X-Git-Url: http://git.draconx.ca/gitweb/rrace.git/blobdiff_plain/c871e6fab6382d4a46ec0c410386041a8aadef65..935b93502aeb0c39892a127ac8cb1380652fd61b:/t/ewmhicon.c diff --git a/t/ewmhicon.c b/t/ewmhicon.c index fd92e32..d7c6aea 100644 --- a/t/ewmhicon.c +++ b/t/ewmhicon.c @@ -23,37 +23,46 @@ #include #include #include +#include +#include #include #include #include "ewmhicon.h" +#include "icon.h" #include "colour.h" #include "help.h" +enum { + SOPT_MAX = UCHAR_MAX, + LOPT_W32VGA, + LOPT_MAX +}; + static const char *progname = "ewmhicon"; static const char sopts[] = "c:VH"; static const struct option lopts[] = { { "colourseq", 1, NULL, 'c' }, + { "w32vga", 0, NULL, LOPT_W32VGA }, { "version", 0, NULL, 'V' }, { "help", 0, NULL, 'H' }, { 0 } }; -#define PASTE(a, b) a ## b -#define INDIR(a) a - #define S8TO16(x) ((x) * 0xfffful / 0xff) -#define RGB8_(r, g, b) { \ - 0xff000000 | (r << 16) | (g << 8) | b, \ - S8TO16(r), S8TO16(g), S8TO16(b) } +#define RGB8(r, g, b) { \ + 0xff000000 | (r << 16) | (g << 8) | b, \ + S8TO16(r), S8TO16(g), S8TO16(b) } -#define RGB8(r, g, b) RGB8_(0x ## r ## ul, 0x ## g ## ul, 0x ## b ## ul) +#define COLOUR_SYS_XCOLOR(r, g, b) \ + RGB8(0x ## r ## ul, 0x ## g ## ul, 0x ## b ## ul) -#define COLOURTAB(n) { \ - INDIR(RGB8 PASTE(COLOUR ## n, _PRIMARY_RGB_)), \ - INDIR(RGB8 PASTE(COLOUR ## n, _DARK_RGB_)), \ - INDIR(RGB8 PASTE(COLOUR ## n, _LIGHT_RGB_)) } +#undef COLOUR_SYSTEM +#define COLOUR_SYSTEM XCOLOR + +#define COLOURTAB_(n) { n ## _PRIMARY, n ## _DARK, n ## _LIGHT } +#define COLOURTAB(n) COLOURTAB_(COLOUR ## n) static const XColor colours[7][3] = { { @@ -97,52 +106,159 @@ static void print_version(void) puts("There is NO WARRANTY, to the extent permitted by law."); } -static const char sizes[][6] = { - "16x16", "24x24", "32x32", "48x48" -}; -static int to_size_enum(const char *arg) -{ - char buf[8]; - unsigned i; +#define COLOUR_SYS_HEX(r, g, b) 0x ## r ## g ## b ## ul - if (!strchr(arg, 'x')) { - sprintf(buf, "%.3sx%.3s", arg, arg); - arg = buf; - } - - for (i = 0; i < sizeof sizes / sizeof sizes[0]; i++) { - if (!strcmp(arg, sizes[i])) - return i; - } +#undef COLOUR_SYSTEM +#define COLOUR_SYSTEM HEX - return -1; +/* + * Returns true iff this pixel is an "edge" -- that is, either there + * is no pixel to the right or below or those pixels are a different + * colour. + */ +static int is_edge(unsigned x, unsigned y, unsigned w, unsigned h, + unsigned long *p, unsigned long colour) +{ + return y+1 >= h || x+1 >= w + || (p[1] & 0xffffff) != colour + || (p[w] & 0xffffff) != colour; } -static void gen_icon(int size, const char *colourseq) +static void print_xpm_w32vga(unsigned long size, unsigned long *icon_buf) { - void (*tilefunc)(unsigned long *, const XColor *, int, int); - static unsigned long icon_buf[48*48]; - const char colourchars[21] = ".%+"",Rr""-Oo""'Yy"":Gg"";Bb"" Ww"; - unsigned i, j, x, y, w, h, n; + unsigned w = size & 0xffff, h = (size >> 16) & 0xffff; + unsigned x, y, i, j, n; + + const char colourchars[16] = "#rgybmc-+RGYBMC "; + unsigned long palette[16] = { + 0x000000, 0x800000, 0x008000, 0x808000, + 0x000080, 0x800080, 0x008080, 0xc0c0c0, + 0x808080, 0xff0000, 0x00ff00, 0xffff00, + 0x0000ff, 0xff00ff, 0x00ffff, 0xffffff + }; + + unsigned long prev_colour = 0; + unsigned used_colours, v; + + size = (unsigned long) w * h; + for (i = 0; i < size; i++) { + unsigned long *p = &icon_buf[i]; + char *c; + + x = i%w, y=i/w; + + switch (*p & 0xffffff) { + /* red */ + case COLOUR0_PRIMARY: + *p = y&1 ? ( x&1 ? 'r' : 'm' ) : ( x&1 ? 'y' : 'r' ); + break; + case COLOUR0_LIGHT: + *p = (x^y)&1 ? '+' : 'r'; + break; + case COLOUR0_DARK: + *p = 'r'; + break; + /* orange */ + case COLOUR1_PRIMARY: + *p = y&1 ? 'y' : x&1 ? '+' : 'R'; + break; + case COLOUR1_LIGHT: + *p = (x^y)&1 ? '+' : 'y'; + break; + case COLOUR1_DARK: + *p = (x^y)&1 ? 'r' : 'y'; + break; + /* yellow */ + case COLOUR2_PRIMARY: + *p = (x^y)&1 ? '+' : 'Y'; + break; + case COLOUR2_LIGHT: + *p = (x^y)&1 ? '-' : 'Y'; + break; + case COLOUR2_DARK: + *p = (x^y)&1 ? '+' : 'Y'; + if (is_edge(x, y, w, h, p, COLOUR2_DARK)) + *p = (x^y)&1 ? '+' : 'y'; + break; + /* green */ + case COLOUR3_PRIMARY: + *p = y&1 ? 'g' : x&1 ? '+' : 'g'; + break; + case COLOUR3_LIGHT: + *p = (x^y)&1 ? '+' : 'g'; + break; + case COLOUR3_DARK: + *p = 'g'; + if (is_edge(x, y, w, h, p, COLOUR3_DARK)) + *p = (x^y)&1 ? '#' : 'g'; + break; + /* blue */ + case COLOUR4_PRIMARY: + *p = (x^y)&1 ? 'b' : 'c'; + break; + case COLOUR4_LIGHT: + *p = 'c'; + if (is_edge(x, y, w, h, p, COLOUR4_LIGHT)) + *p = (x^y)&1 ? 'b' : 'c'; + break; + case COLOUR4_DARK: + *p = 'b'; + if (is_edge(x, y, w, h, p, COLOUR4_DARK)) + *p = (x^y)&1 ? '#' : 'b'; + break; + /* white */ + case COLOUR5_PRIMARY: + *p = (x^y)&1 ? '-' : ' '; + break; + case COLOUR5_LIGHT: + *p = ' '; + break; + case COLOUR5_DARK: + *p = (x^y)&1 ? '+' : ' '; + break; + /* dummy */ + case 0xff0000: *p = 'R'; break; + case 0x00ff00: *p = 'G'; break; + case 0x0000ff: *p = 'B'; break; + } - 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); + c = strchr(colourchars, *p); + assert(c && c - colourchars < 16); + used_colours |= 1u << (c-colourchars); } - for (i = 0; i < 9; i++) { - const XColor *c; + for (n = 0, v = used_colours; v; n++) + v &= v-1; - assert(colourseq[i] >= '0' && colourseq[i] <= '6'); - c = colours[colourseq[i]-'0']; + puts("/* XPM */"); + puts("static char *icon[] = {"); + printf("\"%u %u %u 1\",\n", w, h, n); + for (i = 0; i < sizeof colourchars; i++) { + if (!(used_colours & (1u << i))) + continue; + + printf("\"%c c #%.6lx\",\n", colourchars[i], palette[i]); + } - tilefunc(icon_buf, c, i%3, i/3); + for (y = 0; y < h; y++) { + putchar('"'); + for (x = 0; x < w; x++) { + putchar(icon_buf[y*h+x]); + } + printf("\"%.*s\n", y+1> 16) & 0xffff; + unsigned x, y, i, j, n; + n = 7; for (i = 0; i < 7; i++) n -= !strchr(colourseq, '0'+i); @@ -177,10 +293,10 @@ static void gen_icon(int size, const char *colourseq) } printf("\"%.*s\n", y+1 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; + } + + 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 (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; + } + + if (i < EWMH_ICON_NELEM) + return &ewmhicon[i]; + + fprintf(stderr, "%s: error: no %lux%lu icon found\n", progname, w, h); + return NULL; +} + int main(int argc, char **argv) { - char colourseq[9] = "000000000"; - int opt, size; + unsigned long *ewmhicon, *icon, size, buf[9]; + char colourseq[10] = "000000000"; + int w32vga = 0; + int opt; if (argc > 0) progname = argv[0]; @@ -223,6 +424,9 @@ int main(int argc, char **argv) if (decode_colourseq(colourseq, optarg) != 0) return EXIT_FAILURE; break; + case LOPT_W32VGA: + w32vga = 1; + break; case 'H': print_help(); return EXIT_SUCCESS; @@ -241,13 +445,26 @@ int main(int argc, char **argv) return EXIT_FAILURE; } - size = to_size_enum(argv[optind]); - if (size < 0) { - printf("%s: error: invalid size %s\n", progname, argv[optind]); - print_usage(stderr); + 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; } - gen_icon(size, colourseq); + icon = find_icon(size, ewmhicon); + if (!icon) + return EXIT_FAILURE; + + if (w32vga) { + print_xpm_w32vga(size, icon); + } else { + print_xpm(colourseq, size, icon); + } + + free(ewmhicon); return 0; }