From: Nick Bowler Date: Fri, 13 Jan 2023 01:55:56 +0000 (-0500) Subject: Separate EWMH colour conversion from icon generation. X-Git-Url: http://git.draconx.ca/gitweb/rrace.git/commitdiff_plain/b4b5688edd332e17591ca7bc1cdd64c296abe1c5 Separate EWMH colour conversion from icon generation. We don't need to recompute the ARGB colour values for every single pixel, we can do this in advance once for each possible colour. To do this, we alter the behaviour to use the 'pixel' member of the supplied XColor array, and create a new function that can be called beforehand to populate it based on red/green/blue values. Interestingly, the ewmhicon test program was already providing an XColor array with 'pixel' values that are correct for this new behaviour, so it needs no changes, except a new mode is added as a basic sanity check for the new function. --- diff --git a/src/ewmhicon.c b/src/ewmhicon.c index 7e69ec8..8b731a3 100644 --- a/src/ewmhicon.c +++ b/src/ewmhicon.c @@ -20,6 +20,7 @@ #include #include #include +#include #if !X_DISPLAY_MISSING # include @@ -32,17 +33,29 @@ enum { ICON_16x16, ICON_24x24, ICON_32x32, ICON_48x48, ICON_MAX }; -static unsigned long scale16to8(unsigned x) +static unsigned long scale16to8(uint_least32_t x) { - return x*0xfful / 0xffff; + return x*0xff / 0xffff; } static unsigned long wm_pixel(const XColor *c) { - return 0xff000000 - | scale16to8(c->red) << 16 - | scale16to8(c->green) << 8 - | scale16to8(c->blue); + uint_least32_t t = -1; + + t = (t << 8) + scale16to8(c->red); + t = (t << 8) + scale16to8(c->green); + t = (t << 8) + scale16to8(c->blue); + + return t & 0xffffffff; +} + +void ewmh_icon_prepare_cmap(XColor *map, unsigned n) +{ + unsigned i; + + for (i = 0; i < n; i++) { + map[i].pixel = wm_pixel(&map[i]); + } } static void do_remap(void *icon, unsigned area, const XColor *map) @@ -53,7 +66,7 @@ static void do_remap(void *icon, unsigned area, const XColor *map) area--; for (i = 0; i <= area; i++) { - argb[area-i] = wm_pixel(map + index[area-i]); + argb[area-i] = (map + index[area-i])->pixel; } } diff --git a/src/ewmhicon.h b/src/ewmhicon.h index 1f83853..e12c14e 100644 --- a/src/ewmhicon.h +++ b/src/ewmhicon.h @@ -1,6 +1,6 @@ /* * _NET_WM_ICON helpers for slide puzzle game - * Copyright © 2022 Nick Bowler + * Copyright © 2023 Nick Bowler * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -39,13 +39,23 @@ typedef struct { */ #define EWMH_ICON_NELEM (2+16*16 + 2+24*24 + 2+32*32 + 2+48*48) +/* + * For each of the n elements of the array pointed to by map, set the + * 'pixel' member according to its separated red/green/blue components, + * with an alpha value of 255 (opaque). + * + * The resulting colourmap is suitable for use with ewmh_icon_generate. + */ +void ewmh_icon_prepare_cmap(XColor *map, unsigned n); + /* * Generate EWMH icon data based on a sequence of tile colours. Internally, * this calls icon_tile16 and friends to draw each of the icon patterns. * * The sequence specifies the colour of all 9 icon tiles, beginning from the * top left in row-major order. Each value specifies three offsets into - * the provided colour map, encoded in the same manner as icon_tile16 et al. + * the provided colour map, using the 'pixel' members directly as 32-bit + * ARGB colour values. * * Returns a newly-allocated buffer which is suitable for use directly with * XChangeProperty, and should be freed by the caller. diff --git a/src/x11.c b/src/x11.c index b4b0a2c..dd59fd7 100644 --- a/src/x11.c +++ b/src/x11.c @@ -223,6 +223,7 @@ static void set_icon(struct app_state *state, Display *display, } XQueryColors(display, cmap, colours, XtNumber(colours)); + ewmh_icon_prepare_cmap(colours, XtNumber(colours)); wm_icon = ewmh_icon_generate(ewmhseq, colours); if (wm_icon) { XChangeProperty(display, XtWindow(shell), net_wm_icon, diff --git a/t/ewmhicon.c b/t/ewmhicon.c index d7c6aea..5919363 100644 --- a/t/ewmhicon.c +++ b/t/ewmhicon.c @@ -1,6 +1,6 @@ /* * Test app for _NET_WM_ICON formatting. - * Copyright © 2022 Nick Bowler + * Copyright © 2022-2023 Nick Bowler * * Use a fake colour scheme to generate an icon of the chosen size (16x16, * 24x24, 32x32 or 48x48) and display the pixels as characters. @@ -32,16 +32,19 @@ #include "icon.h" #include "colour.h" #include "help.h" +#include "xtra.h" enum { SOPT_MAX = UCHAR_MAX, LOPT_W32VGA, + LOPT_TEST_CMAP, LOPT_MAX }; static const char *progname = "ewmhicon"; static const char sopts[] = "c:VH"; static const struct option lopts[] = { + { "test-cmap", 0, NULL, LOPT_TEST_CMAP }, { "colourseq", 1, NULL, 'c' }, { "w32vga", 0, NULL, LOPT_W32VGA }, { "version", 0, NULL, 'V' }, @@ -100,7 +103,7 @@ static void print_help(void) static void print_version(void) { printf("ewmhicon (%s) %s\n", PACKAGE, PACKAGE_VERSION); - printf("Copyright (C) 2022 Nick Bowler\n"); + printf("Copyright (C) 2023 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."); @@ -408,11 +411,41 @@ static unsigned long *find_icon(unsigned long size, unsigned long *ewmhicon) return NULL; } +static int test_ewmh_icon_prepare(void) +{ + int ret = EXIT_SUCCESS; + unsigned i; + + XColor *template = (void *)colours; + XColor newmap[sizeof colours / sizeof colours[0][0]]; + + printf("1..%d\n", (int)XTRA_ARRAYSIZE(newmap)); + for (i = 0; i < XTRA_ARRAYSIZE(newmap); i++) { + newmap[i] = template[i]; + newmap[i].pixel = 0; + } + + ewmh_icon_prepare_cmap(newmap, XTRA_ARRAYSIZE(newmap)); + for (i = 0; i < XTRA_ARRAYSIZE(newmap); i++) { + XColor *c = &newmap[i]; + + if (c->pixel != template[i].pixel) { + printf("not "); + ret = EXIT_FAILURE; + } + + printf("ok %u (%.4hx, %.4hx, %.4hx) -> %.8lx\n", + i+1, c->red, c->green, c->blue, c->pixel); + } + + return ret; +} + int main(int argc, char **argv) { unsigned long *ewmhicon, *icon, size, buf[9]; char colourseq[10] = "000000000"; - int w32vga = 0; + int w32vga = 0, test_cmap = 0; int opt; if (argc > 0) @@ -427,6 +460,9 @@ int main(int argc, char **argv) case LOPT_W32VGA: w32vga = 1; break; + case LOPT_TEST_CMAP: + test_cmap = 1; + break; case 'H': print_help(); return EXIT_SUCCESS; @@ -439,6 +475,10 @@ int main(int argc, char **argv) } } + if (test_cmap) { + return test_ewmh_icon_prepare(); + } + if (argc != optind+1) { printf("%s: error: size not specified\n", progname); print_usage(stderr); diff --git a/tests/gui.at b/tests/gui.at index 7d47052..92d1723 100644 --- a/tests/gui.at +++ b/tests/gui.at @@ -1,4 +1,4 @@ -# Copyright © 2022 Nick Bowler +# Copyright © 2022-2023 Nick Bowler # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -13,7 +13,11 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +TEST_TAP_SIMPLE([ewmh_icon_prepare_cmap], + [ewmhicon --test-cmap], [], [gui ewmh icon]) + AT_SETUP([_NET_WM_ICON tiles (16x16)]) +AT_KEYWORDS([gui ewmh icon]) AT_CHECK([ewmhicon 16x16], [0], [[/* XPM */ static char *icon[] = { @@ -43,6 +47,7 @@ static char *icon[] = { AT_CLEANUP AT_SETUP([_NET_WM_ICON tiles (24x24)]) +AT_KEYWORDS([gui ewmh icon]) AT_CHECK([ewmhicon 24x24], [0], [[/* XPM */ static char *icon[] = { @@ -80,6 +85,7 @@ static char *icon[] = { AT_CLEANUP AT_SETUP([_NET_WM_ICON tiles (32x32)]) +AT_KEYWORDS([gui ewmh icon]) AT_CHECK([ewmhicon 32x32], [0], [[/* XPM */ static char *icon[] = { @@ -125,6 +131,7 @@ static char *icon[] = { AT_CLEANUP AT_SETUP([_NET_WM_ICON tiles (48x48)]) +AT_KEYWORDS([gui ewmh icon]) AT_CHECK([ewmhicon 48x48], [0], [[/* XPM */ static char *icon[] = { diff --git a/testsuite.at b/testsuite.at index 09efc3a..c00be48 100644 --- a/testsuite.at +++ b/testsuite.at @@ -18,16 +18,18 @@ AT_COLOR_TESTS m4_divert_push([PREPARE_TESTS])dnl test_run_tap () { - "$builddir/t/$1" > "$1.tap" + program=$1; shift + + "$builddir/t/$program" "$@" > "$program.tap" status=$? - cat "$1.tap" - :; { echo 'print <"$1.pl" - prove "$1.pl" 2>&1 + cat "$program.tap" + :; { echo 'print <"$program.pl" + prove "$program.pl" 2>&1 return $status } m4_divert_pop([PREPARE_TESTS]) -m4_define([TEST_TAP], [AT_CHECK([test_run_tap "$1"], [0], [ignore])]) +m4_define([TEST_TAP], [AT_CHECK([test_run_tap $1], [0], [ignore])]) m4_define([TEST_TAP_SIMPLE], [dnl AT_SETUP([$1]) AT_KEYWORDS([$4])dnl