248 lines
6.4 KiB
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;
|
|
}
|