#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)
area--;
for (i = 0; i <= area; i++) {
- argb[area-i] = wm_pixel(map + index[area-i]);
+ argb[area-i] = (map + index[area-i])->pixel;
}
}
/*
* _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
*/
#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.
}
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,
/*
* 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' },
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.");
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)
case LOPT_W32VGA:
w32vga = 1;
break;
+ case LOPT_TEST_CMAP:
+ test_cmap = 1;
+ break;
case 'H':
print_help();
return EXIT_SUCCESS;
}
}
+ if (test_cmap) {
+ return test_ewmh_icon_prepare();
+ }
+
if (argc != optind+1) {
printf("%s: error: size not specified\n", progname);
print_usage(stderr);
-# 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[] = {
AT_CLEANUP
AT_SETUP([_NET_WM_ICON tiles (24x24)])
+AT_KEYWORDS([gui ewmh icon])
AT_CHECK([ewmhicon 24x24], [0], [[/* XPM */
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[] = {
AT_CLEANUP
AT_SETUP([_NET_WM_ICON tiles (48x48)])
+AT_KEYWORDS([gui ewmh icon])
AT_CHECK([ewmhicon 48x48], [0], [[/* XPM */
static char *icon[] = {
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