]> git.draconx.ca Git - rrace.git/commitdiff
Separate EWMH colour conversion from icon generation.
authorNick Bowler <nbowler@draconx.ca>
Fri, 13 Jan 2023 01:55:56 +0000 (20:55 -0500)
committerNick Bowler <nbowler@draconx.ca>
Fri, 13 Jan 2023 01:55:56 +0000 (20:55 -0500)
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.

src/ewmhicon.c
src/ewmhicon.h
src/x11.c
t/ewmhicon.c
tests/gui.at
testsuite.at

index 7e69ec883f5c36317c900abff0a947e03b149d8c..8b731a35d52dece292079b576d5d9f7758c689ee 100644 (file)
@@ -20,6 +20,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <stdint.h>
 
 #if !X_DISPLAY_MISSING
 #  include <X11/Intrinsic.h>
 
 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;
        }
 }
 
index 1f83853ba4e63761f854abf607b42a59478fb309..e12c14ef9eb41459cdb5157c2e4d60989b5eb21d 100644 (file)
@@ -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.
index b4b0a2cd2db82c1a0c96addd291d362841e5e216..dd59fd7e24acadb3f40e3f565273214cc17f4d2f 100644 (file)
--- 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,
index d7c6aea2276a1eb9b2da221707a002b95c32befc..5919363549a3f72bc779ba842f19753ded4cb854 100644 (file)
@@ -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.
 #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);
index 7d470527240a67de4ba34a2e80b381103c337752..92d1723fdaebed19d376a3c9fa984f0763e6fb8d 100644 (file)
@@ -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
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
+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[] = {
index 09efc3a6862c05b1a653698aab5b4e5f5cebb17e..c00be4810a0150ce8fdaaa500e8ff8c50f6fa99c 100644 (file)
@@ -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 <<EOF'; cat "$1.tap"; echo 'EOF'; } >"$1.pl"
-  prove "$1.pl" 2>&1
+  cat "$program.tap"
+  :; { echo 'print <<EOF'; cat "$program.tap"; echo 'EOF'; } >"$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