#include #include #include #include #include #include #include #include #include #include #include struct color { int r; int g; int b; }; void init_random(void) { srand(time(0)); } int rand_range(int u, int l) { return (rand() % (u - l + 1)) + l; } void exec_with_stdout(char *file, char *args[], char *buf, int length) { int pfds[2]; pipe(pfds); int status = fork(); if(status == 0) { close(1); dup(pfds[1]); close(pfds[0]); execvp(file, args); } else { if(!buf) return; /* don't read anything */ int readin = read(pfds[0], buf, length - 1); buf[readin] = '\0'; } } void imagemagick(char *filename, char *buffer, int size) { char *execargs[] = { "convert", filename, "-resize", "25%", "-colors", "16", "-unique-colors", "-quiet", "txt:-", NULL }; char *name = "convert"; exec_with_stdout(name, execargs, buffer, size); } struct color *get_raw_colors(char *image) { char buf[2048]; imagemagick(image, (char *)&buf, 2048); int hcount = 0; char cbuf[3][3]; static struct color colors[16]; for(int i = 0; (unsigned int)i < sizeof buf; i++) { if(buf[i] == '#') { hcount++; /* we have to ignore a comment, that's why there's a special case */ if(hcount >= 2 && hcount - 2 < 16 && (unsigned int)(i + 6) < sizeof buf) { memcpy((char *)&cbuf[0], buf + i + 1, 2); memcpy((char *)&cbuf[1], buf + i + 3, 2); memcpy((char *)&cbuf[2], buf + i + 5, 2); cbuf[0][2] = '\0'; cbuf[1][2] = '\0'; cbuf[2][2] = '\0'; colors[hcount - 2].r = (int)strtol((char *)&cbuf[0], NULL, 16); colors[hcount - 2].g = (int)strtol((char *)&cbuf[1], NULL, 16); colors[hcount - 2].b = (int)strtol((char *)&cbuf[2], NULL, 16); } } } return (struct color *)&colors; } void blend_color(struct color *a, struct color *b, struct color *c) { c->r = (int)(0.5 * a->r + 0.5 * b->r); c->g = (int)(0.5 * a->g + 0.5 * b->g); c->b = (int)(0.5 * a->b + 0.5 * b->b); } void darken_color(struct color *a, struct color *b, double percentage) { b->r = (int)(a->r * (1 - percentage)); b->g = (int)(a->g * (1 - percentage)); b->b = (int)(a->b * (1 - percentage)); } void adjust_colors(struct color *colors) { /* #eeeeee */ struct color e = {238, 238, 238}; /* if top digit != 0 */ if(colors[0].r > 15) darken_color(&colors[0], &colors[0], 0.40); blend_color(&colors[7], &e, &colors[7]); darken_color(&colors[7], &colors[8], 0.30); blend_color(&colors[15], &e, &colors[15]); } int check_colors(struct color *colors) { int j = 0; for(int i = 0; i < 16; i++) { if(colors[i].r + colors[i].g + colors[i].b == 0) j++; } if(j > 0) return 0; return 1; } struct color *get_colors(char *filename) { /* check for permission */ if(access(filename, F_OK | R_OK) != 0) { errno = ENOENT; return NULL; } struct color *col = get_raw_colors(filename); adjust_colors(col); return col; } /* generalized function , * used by get_conf_file and get_wal_dir */ char *get_file_gen(char *initvar, char *backvar, char *postfix, char *file) { static char buffer[256]; int extension = 0; char *path = getenv(initvar); if(!path) { path = getenv(backvar); extension = 1; } if(!path) { fprintf(stderr, "error: both initvar and backvar are undefined.\n"); exit(1); } snprintf(buffer, 256, "%s%s/%s", path, extension ? postfix : "", file); return buffer; } char *get_conf_file(char *file) { return get_file_gen("XDG_CONFIG_HOME", "HOME", "/.config/cwal", file); } /* pass NULL to get the base dir name, not specific file */ char *get_wal_dir(char *file) { if(!file) file = ""; return get_file_gen("XDG_DATA_HOME", "HOME", "/.local/share/wallpapers", file); } char *select_random_rel(void) { DIR *dir = opendir(get_wal_dir(NULL)); struct dirent *file; /* probably should move hardcoded constants somewhere that makes sense */ static char names[50][256]; int i = 0, random; init_random(); while(file = readdir(dir)) { if(i == 50) break; if(file->d_type != DT_REG) continue; memcpy(&names[i], file->d_name, 256); i++; } random = rand_range(i - 1, 0); return names[random]; } void print_color(struct color *color) { printf("#%02x%02x%02x\n", color->r, color->g, color->b); } void run_handler(struct color *colors, char *wal) { char chars[16][8]; char *argv[19]; for(int i = 0; i < 16; i++) { snprintf(&chars[i], 8, "#%02x%02x%02x", colors[i].r, colors[i].g, colors[i].b); } for(int i = 0; i < 16; i++) { argv[i + 1] = &chars[i]; } argv[17] = wal; argv[18] = NULL; char *conf = get_conf_file("handler"); argv[0] = "handler"; if(access(conf, F_OK | R_OK | X_OK) != 0) { printf("couldn't find %s!\n", conf); return; } exec_with_stdout(conf, argv, NULL, 0); } struct settings { int h:1; /* running hooks or not */ int r:1; /* pick a random wallpaper */ } settings = { .h = 1, .r = 1, }; char *select_random_file(void) { char *file = select_random_rel(); static char ret[256]; file = get_wal_dir(file); memcpy(&ret, file, 256); return ret; } int main(void) { char *file = select_random_file(); struct color *colors = get_colors(file); printf("%i\n", check_colors(colors)); for(int i = 0; i < 16; i++) { print_color(&colors[i]); } run_handler(colors, file); get_conf_file("hello"); return 0; }