Files
wallpaper/wallpaperd.c

248 lines
6.4 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/un.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <time.h>
#include <signal.h>
#include <dirent.h>
#include <sys/stat.h>
int initServerSockServer() {
int server_fd = socket(AF_UNIX, SOCK_STREAM, 0);
struct sockaddr_un addr = {0};
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, "/tmp/my_wallpaper.sock");
unlink(addr.sun_path);
if (server_fd < 0) perror("socket");
if (bind(server_fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) perror("bind");
if (listen(server_fd, 5) < 0) perror("listen");
return server_fd;
}
int last_pid = -1;
void setBackgroundImage(char* path){
printf("changing wallpaper to %s", path);
int pid = fork();
if(pid < 0){
perror("fork error");
return;
}
if(pid == 0) {
// child
char *args[] = {"/usr/bin/swaybg", "-m", "fit", "-i", path, "-c", "#000000", NULL};
execvp("swaybg", args);
}
if(last_pid > 0){
usleep(250000);
printf("INFO: killing %d", last_pid);
kill(last_pid, SIGTERM);
}
last_pid = pid;
}
int image_index = 0;
void runBgSwapNext(char** images, size_t count){
image_index++;
setBackgroundImage(images[image_index%count]);
}
void runBgSwapPrevious(char** images, size_t count){
image_index--;
if(image_index < 0) image_index = 0;
setBackgroundImage(images[image_index%count]);
}
int isImageFile(const char* filename) {
const char* validExtensions[] = { ".jpg", ".jpeg", ".png", ".gif", ".bmp", ".tiff" };
size_t numExtensions = sizeof(validExtensions) / sizeof(validExtensions[0]);
for (size_t i = 0; i < numExtensions; i++) {
if (strstr(filename, validExtensions[i])) {
return 1;
}
}
return 0;
}
#define INITIAL_SIZE 10
void collectImages(const char* path, char*** images, size_t* count) {
DIR* dir = opendir(path);
if (dir == NULL) {
perror("opendir failed");
return;
}
struct dirent* entry;
while ((entry = readdir(dir)) != NULL) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
continue;
}
char fullPath[1024];
snprintf(fullPath, sizeof(fullPath), "%s/%s", path, entry->d_name);
if (entry->d_type == DT_DIR) {
collectImages(fullPath, images, count);
} else if (isImageFile(entry->d_name)) {
if (*count % INITIAL_SIZE == 0) {
*images = realloc(*images, (*count + INITIAL_SIZE) * sizeof(char*));
}
(*images)[*count] = malloc(strlen(fullPath) + 1);
strcpy((*images)[*count], fullPath);
(*count)++;
}
}
closedir(dir);
}
void freeImages(char** images, size_t count) {
for (size_t i = 0; i < count; i++) {
free(images[i]);
}
free(images);
}
void shuffleImages(char** images, size_t count) {
srand(time(NULL)); // Seed for random number generation
for (size_t i = 0; i < count; i++) {
size_t j = rand() % count;
// Swap images[i] and images[j]
char* temp = images[i];
images[i] = images[j];
images[j] = temp;
}
}
int paused_wallpaper = 0;
int static_wallpaper = 0;
char* static_wallpaper_path = NULL;
int timeout_interval = 5;
void handleCommand(char *buff, int n, char** images, size_t image_count){
if(n < 1){
perror("ERROR: command missing");
return;
}
printf("INFO: command accepted %c\n", buff[0]);
switch(buff[0]){
case 't': {
printf("INFO: time changed to %d\n", buff[1]);
timeout_interval = (buff[1] << 8) + buff[2];
} break;
case 'p': {
paused_wallpaper = 1 - paused_wallpaper;
printf("INFO: wallpaper is now %s\n", paused_wallpaper ? "paused" : "unpaused");
} break;
case 'c': {
static_wallpaper = 1 - static_wallpaper;
paused_wallpaper = static_wallpaper;
if(static_wallpaper && static_wallpaper_path){
setBackgroundImage(static_wallpaper_path);
}
printf("INFO: wallpaper is now %s\n", static_wallpaper ? "static" : "dynamic");
} break;
case 'n': {
printf("INFO: wallpaper is now next");
runBgSwapNext(images, image_count);
} break;
case 'b': {
printf("INFO: wallpaper is now next");
runBgSwapPrevious(images, image_count);
} break;
case 'i': {
printf("current wallpaper is: \n%s\n", images[image_index]);
} break;
}
}
int main(int argc, char** argv) {
printf("INFO: daemon started\n");
char** images = NULL;
size_t image_count = 0;
if(argc < 3){
printf("usage: %s dirpath filepath\n", argv[0]);
return 1;
}
struct stat stat_buffer;
if(stat(argv[1], &stat_buffer) != 0){
printf("dirpath is invalid\n");
return 1;
}
if(stat(argv[2], &stat_buffer) != 0){
printf("filepath is invalid\n");
return 1;
}
static_wallpaper_path = argv[2];
collectImages(argv[1], &images, &image_count);
printf("collected %ld suitable images\n", image_count);
shuffleImages(images, image_count);
printf("images shuffled\n");
printf("starting server\n");
int server_fd = initServerSockServer();
setBackgroundImage(images[0]);
while(1){
fd_set fds;
FD_ZERO(&fds);
FD_SET(server_fd, &fds);
struct timeval tv;
tv.tv_sec = timeout_interval; // N seconds
tv.tv_usec = 0;
int ret = select(server_fd + 1, &fds, NULL, NULL, &tv);
if (ret < 0) {
perror("select\n");
break;
}
if (ret == 0) {
if(!paused_wallpaper){
runBgSwapNext(images, image_count);
}
printf("INFO: periodic task\n");
continue;
}
if (FD_ISSET(server_fd, &fds)) {
int client = accept(server_fd, NULL, NULL);
if (client < 0) continue;
printf("INFO: client connected\n");
char buf[256];
int n = read(client, buf, sizeof(buf)-1);
if (n > 0) {
buf[n] = 0;
handleCommand(buf, n, images, image_count);
}
close(client);
printf("INFO: client disconnected\n");
}
}
freeImages(images, image_count);
return 0;
}