X-Git-Url: https://git.draconx.ca/gitweb/rrace.git/blobdiff_plain/0a46ad3167e6f87e254288080e3ce89402089afb..0638562c931293881c645e7ddba35916d626b4ca:/t/ewmhicon.c diff --git a/t/ewmhicon.c b/t/ewmhicon.c index 88ecfed..6983cf9 100644 --- a/t/ewmhicon.c +++ b/t/ewmhicon.c @@ -23,92 +23,287 @@ #include #include #include +#include +#include #include +#include #include "ewmhicon.h" +#include "icon.h" +#include "colour.h" +#include "help.h" static const char *progname = "ewmhicon"; +static const char sopts[] = "c:VH"; +static const struct option lopts[] = { + { "colourseq", 1, NULL, 'c' }, + { "version", 0, NULL, 'V' }, + { "help", 0, NULL, 'H' }, + { 0 } +}; + +#define S8TO16(x) ((x) * 0xfffful / 0xff) + +#define RGB8(r, g, b) { \ + 0xff000000 | (r << 16) | (g << 8) | b, \ + S8TO16(r), S8TO16(g), S8TO16(b) } + +#define COLOUR_SYS_EWMHICON(r, g, b) \ + RGB8(0x ## r ## ul, 0x ## g ## ul, 0x ## b ## ul) + +#undef COLOUR_SYSTEM +#define COLOUR_SYSTEM EWMHICON + +#define COLOURTAB_(n) { n ## _PRIMARY, n ## _DARK, n ## _LIGHT } +#define COLOURTAB(n) COLOURTAB_(COLOUR ## n) + +static const XColor colours[7][3] = { + { + { 0xffff0000, 0xffff }, + { 0xff00ff00, 0, 0xffff }, + { 0xff0000ff, 0, 0, 0xffff } + }, + COLOURTAB(0), COLOURTAB(1), COLOURTAB(2), + COLOURTAB(3), COLOURTAB(4), COLOURTAB(5) +}; static void print_usage(FILE *f) { fprintf(f, "Usage: %s size\n", progname); + if (f != stdout) + fprintf(f, "Try %s --help for more information.\n", progname); } -static const char sizes[][6] = { - "16x16", "24x24", "32x32", "48x48" -}; - -int to_size_enum(const char *arg) +static void print_help(void) { - char buf[8]; - unsigned i; + const struct option *opt; - if (!strchr(arg, 'x')) { - sprintf(buf, "%.3sx%.3s", arg, arg); - arg = buf; + print_usage(stdout); + putchar('\n'); + puts("Options:"); + for (opt = lopts; opt->name; opt++) { + if (help_print_optstring(opt, "ARG", 20)) + putchar('\n'); } + putchar('\n'); - for (i = 0; i < sizeof sizes / sizeof sizes[0]; i++) { - if (!strcmp(arg, sizes[i])) - return i; - } + printf("Report bugs to <%s>.\n", PACKAGE_BUGREPORT); +} - return -1; +static void print_version(void) +{ + printf("ewmhicon (%s) %s\n", PACKAGE, PACKAGE_VERSION); + printf("Copyright (C) 2022 Nick Bowler\n"); + puts("License GPLv3+: GNU GPL version 3 or any later version"); + puts("This is free software: you are free to change and redistribute it."); + puts("There is NO WARRANTY, to the extent permitted by law."); } -static unsigned long icon_buf[48*48]; +static void +print_xpm(const char *colourseq, unsigned long size, unsigned long *icon_buf) +{ + const char colourchars[21] = ".%+"",Rr""-Oo""'Yy"":Gg"";Bb"" Ww"; + unsigned w = size & 0xffff, h = (size >> 16) & 0xffff; + unsigned x, y, i, j, n; -int main(int argc, char **argv) + n = 7; + for (i = 0; i < 7; i++) + n -= !strchr(colourseq, '0'+i); + + puts("/* XPM */"); + puts("static char *icon[] = {"); + printf("\"%u %u %u 1\",\n", w, h, 3*n); + for (i = 0; i < 7; i++) { + if (!strchr(colourseq, '0'+i)) + continue; + + for (j = 0; j < 3; j++) { + printf("\"%c c #%.6lx\",\n", colourchars[3*i+j], + colours[i][j].pixel & 0xffffff); + } + } + + for (y = 0; y < h; y++) { + putchar('"'); + for (x = 0; x < w; x++) { + unsigned long val = icon_buf[y*h+x]; + int c = '#'; + + for (i = 0; i < sizeof colourchars; i++) { + if (colours[i/3][i%3].pixel == val) { + c = colourchars[i]; + break; + } + } + + putchar(c); + } + printf("\"%.*s\n", y+1 0) - progname = argv[0]; + for (i = 0; i < 9; i++) { + switch (arg[i]) { + case 0: return 0; + case 'R': case 'r': out[i] = '1'; break; + case 'O': case 'o': out[i] = '2'; break; + case 'Y': case 'y': out[i] = '3'; break; + case 'G': case 'g': out[i] = '4'; break; + case 'B': case 'b': out[i] = '5'; break; + case 'W': case 'w': out[i] = '6'; break; + case '1': case '2': case '3': case '4': case '5': case '6': + case '0': out[i] = arg[i]; break; + default: goto err; + } + } - if (argc != 2) { - print_usage(stderr); - return EXIT_FAILURE; + if (arg[i]) { +err: + fprintf(stderr, "%s: error: invalid colour sequence '%s'\n", + progname, arg); + return -1; } - size = to_size_enum(argv[1]); - if (size < 0) { - printf("%s: error: invalid size %s\n", progname, argv[1]); - return EXIT_FAILURE; + return 0; +} + +/* Convert the user sequence into a list of colour index specifiers */ +static unsigned long *expand_seq(unsigned long *out, const char *seq) +{ + int i; + + for (i = 0; i < 9; i++) { + out[i] = 0x30303 * (seq[i]-'0') + 0x20100; + } + + return out; +} + +static unsigned long decode_size(char *size_spec) +{ + unsigned long w, h; + char c = 0; + size_t n; + + n = strspn(size_spec, "0123456789"); + switch (size_spec[n]) { + default: + goto err_invalid; + case 0: case 'x': case 'X': + c = size_spec[n]; + size_spec[n] = 0; } - switch (size) { - case ICON_16x16: tilefunc = ewmh_tile16; w = h = 16; break; - case ICON_24x24: tilefunc = ewmh_tile24; w = h = 24; break; - case ICON_32x32: tilefunc = ewmh_tile32; w = h = 32; break; - case ICON_48x48: tilefunc = ewmh_tile48; w = h = 48; break; - default: assert(0); + w = strtoul(size_spec, NULL, 10); + size_spec[n] = c; + if (w > 0xffff) + goto err_range; + + if (!c) { + h = w; + } else { + n = strspn(size_spec += n+1, "0123456789"); + if (size_spec[n]) + goto err_invalid; + + h = strtoul(size_spec, NULL, 10); + if (h > 0xffff) + goto err_range; } - c[COLOUR_PRIMARY].red = 0xffff; - c[COLOUR_DARK].green = 0xffff; - c[COLOUR_LIGHT].blue = 0xffff; + return (h << 16) | w; +err_range: + fprintf(stderr, "%s: %s: %s\n", progname, size_spec, strerror(ERANGE)); + return 0; +err_invalid: + fprintf(stderr, "%s: %s: %s\n", progname, size_spec, + "invalid size specification"); + return 0; +} + +static unsigned long *find_icon(unsigned long size, unsigned long *ewmhicon) +{ + unsigned long w = size & 0xffff, h = (size >> 16) & 0xffff; + unsigned long i; + + if (!size) + return NULL; - for (x = 0; x < 3; x++) { - for (y = 0; y < 3; y++) { - tilefunc(icon_buf, c, x, y); + for (i = 0; i < EWMH_ICON_NELEM-2;) { + unsigned long icon_w = ewmhicon[i]; + unsigned long icon_h = ewmhicon[i+1]; + + if (w == icon_w && h == icon_h) { + i += 2; + break; } + + assert(icon_w < ULONG_MAX / icon_h); + assert(i < ULONG_MAX - icon_w*icon_h); + i += 2 + icon_w*icon_h; } - for (y = 0; y < h; y++) { - for (x = 0; x < w; x++) { - unsigned long val = icon_buf[y*h+x]; - int c = ' '; + if (i < EWMH_ICON_NELEM) + return &ewmhicon[i]; - if (val == 0xffff0000) c = '.'; // primary - else if (val == 0xff00ff00) c = '%'; // dark - else if (val == 0xff0000ff) c = '+'; // light + fprintf(stderr, "%s: error: no %lux%lu icon found\n", progname, w, h); + return NULL; +} - putchar(c); +int main(int argc, char **argv) +{ + unsigned long *ewmhicon, *icon, size, buf[9]; + char colourseq[10] = "000000000"; + int opt; + + if (argc > 0) + progname = argv[0]; + + while ((opt = getopt_long(argc, argv, sopts, lopts, 0)) != -1) { + switch (opt) { + case 'c': + if (decode_colourseq(colourseq, optarg) != 0) + return EXIT_FAILURE; + break; + case 'H': + print_help(); + return EXIT_SUCCESS; + case 'V': + print_version(); + return EXIT_SUCCESS; + default: + print_usage(stderr); + return EXIT_FAILURE; } - putchar('\n'); } + if (argc != optind+1) { + printf("%s: error: size not specified\n", progname); + print_usage(stderr); + return EXIT_FAILURE; + } + + size = decode_size(argv[optind]); + if (!size) + return EXIT_FAILURE; + + ewmhicon = ewmh_icon_generate(expand_seq(buf, colourseq), colours[0]); + if (!ewmhicon) { + fprintf(stderr, "%s: failed to allocate memory\n", progname); + return EXIT_FAILURE; + } + + icon = find_icon(size, ewmhicon); + if (!icon) + return EXIT_FAILURE; + + print_xpm(colourseq, size, icon); + + free(ewmhicon); return 0; }