#include #include #include #include #include #include #include #include #include #include #include #include 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; }