From 43a709ff25b9973a83327a06a6ecc94b09e7787b Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Mon, 7 Mar 2022 22:47:18 -0500 Subject: [PATCH] Implement window icons. --- Makefile.am | 11 ++- src/ewmhicon.c | 204 +++++++++++++++++++++++++++++++++++++++++++++++ src/motif.c | 9 +++ src/motif.h | 36 +++++++++ src/motifopt.opt | 3 + src/x11.c | 82 +++++++++++++++++-- t/.gitignore | 1 + t/ewmhicon.c | 114 ++++++++++++++++++++++++++ tests/game.at | 15 ++++ tests/gui.at | 162 +++++++++++++++++++++++++++++++++++++ testsuite.at | 1 + 11 files changed, 629 insertions(+), 9 deletions(-) create mode 100644 src/ewmhicon.c create mode 100644 t/ewmhicon.c create mode 100644 tests/gui.at diff --git a/Makefile.am b/Makefile.am index 0ce64bc..e9dd395 100644 --- a/Makefile.am +++ b/Makefile.am @@ -19,7 +19,8 @@ AM_CFLAGS = $(MOTIF_CFLAGS) bin_PROGRAMS = rrace-motif -rrace_motif_SOURCES = src/game.c src/x11.c src/game.h src/motif.h +rrace_motif_SOURCES = src/game.c src/x11.c src/game.h src/motif.h \ + src/ewmhicon.c rrace_motif_LDADD = $(libmotifmain_a_OBJECTS) $(libmotifui_a_OBJECTS) \ $(libglohelp_a_OBJECTS) libgnu.a $(MOTIF_LIBS) $(rrace_motif_OBJECTS): $(gnulib_headers) @@ -64,11 +65,17 @@ $(GUIFILES:.dat=.h): $(DX_BASEDIR)/scripts/gen-tree.awk DISTCLEANFILES += $(GUIFILES:.dat=.h) EXTRA_DIST += $(DX_BASEDIR)/scripts/gen-tree.awk $(GUIFILES) -check_PROGRAMS = t/boardmove t/rng-test +check_PROGRAMS = t/boardmove t/ewmhicon t/rng-test EXTRA_DIST += t/xos256ss.c t_boardmove_LDADD = src/game.$(OBJEXT) libgnu.a $(t_boardmove_OBJECTS): $(gnulib_headers) +t_ewmhicon_LDADD = src/ewmhicon.$(OBJEXT) libgnu.a $(MOTIF_LIBS) +$(t_ewmhicon_OBJECTS): $(gnulib_headers) + +t_rng_test_LDADD = libgnu.a +$(t_rng_test_OBJECTS): $(gnulib_headers) + include $(top_srcdir)/lib/gnulib.mk include $(top_srcdir)/common/snippet/autotest.mk diff --git a/src/ewmhicon.c b/src/ewmhicon.c new file mode 100644 index 0000000..e071cec --- /dev/null +++ b/src/ewmhicon.c @@ -0,0 +1,204 @@ +/* + * _NET_WM_ICON helpers for slide puzzle game + * Copyright © 2022 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 + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include + +#include +#include +#include "motif.h" + +static unsigned long scale16to8(unsigned x) +{ + return x*0xfful / 0xffff; +} + +static unsigned long wm_pixel(const XColor *c) +{ + return 0xff000000 + | scale16to8(c->red) << 16 + | scale16to8(c->green) << 8 + | scale16to8(c->blue); +} + +/* + * The 16x16 icon is drawn with 1px shadow, 6x6 tiles, with 1 pixel cropped off + * all the edge tiles + */ +void ewmh_tile16(unsigned long *icon, const XColor *c, int tile_x, int tile_y) +{ + int out_x, out_y, out_w, x, y; + unsigned long row[6]; + + out_x = tile_x * 11 / 2; + out_y = tile_y * 11 / 2; + out_w = (5 + (tile_x == 1)) * sizeof row[0]; + + for (y = 0+(tile_y == 0); y < 6-(tile_y == 2); y++) { + for (x = 0+(tile_x == 0); x < 6-(tile_x==2); x++) { + if (x == 0 || y == 0) + row[x] = wm_pixel(&c[COLOUR_LIGHT]); + else if (x == 5 || y == 5) + row[x] = wm_pixel(&c[COLOUR_DARK]); + else + row[x] = wm_pixel(&c[COLOUR_PRIMARY]); + } + memcpy(&icon[16 * out_y++ + out_x], &row[tile_x == 0], out_w); + } +} + +/* + * The 24x24 icon is drawn with 1px shadow and 8x8 tiles. + */ +void ewmh_tile24(unsigned long *icon, const XColor *c, int tile_x, int tile_y) +{ + int out_x, out_y, x, y; + unsigned long row[8]; + + out_x = tile_x * 8; + out_y = tile_y * 8; + + for (y = 0; y < 8; y++) { + for (x = 0; x < 8; x++) { + if (x == 0 || y == 0) + row[x] = wm_pixel(&c[COLOUR_LIGHT]); + else if (x == 7 || y == 7) + row[x] = wm_pixel(&c[COLOUR_DARK]); + else + row[x] = wm_pixel(&c[COLOUR_PRIMARY]); + } + memcpy(&icon[24 * out_y++ + out_x], row, sizeof row); + } +} + +/* + * The 32x32 icon is drawn with 1px shadow with slightly uneven tiles on + * an 11-10-11 pixel grid. + */ +void ewmh_tile32(unsigned long *icon, const XColor *c, int tile_x, int tile_y) +{ + int out_x, out_y, out_w, out_h, x, y; + unsigned long row[11]; + + out_x = 10*tile_x + (tile_x > 0); + out_y = 10*tile_y + (tile_y > 0); + out_w = 10 + (tile_x != 1); + out_h = 10 + (tile_y != 1); + + for (y = 0; y < out_h; y++) { + for (x = 0; x < out_w; x++) { + if (x == 0 || y == 0) + row[x] = wm_pixel(&c[COLOUR_LIGHT]); + else if (x == out_w-1 || y == out_h-1) + row[x] = wm_pixel(&c[COLOUR_DARK]); + else + row[x] = wm_pixel(&c[COLOUR_PRIMARY]); + } + memcpy(&icon[32 * out_y++ + out_x], row, out_w * sizeof row[0]); + } +} + +/* + * The 48x48 icon is drawn with 2px shadow and 16x16 tiles. + */ +void ewmh_tile48(unsigned long *icon, const XColor *c, int tile_x, int tile_y) +{ + int out_x, out_y, x, y; + unsigned long row[16]; + + out_x = tile_x * 16; + out_y = tile_y * 16; + + for (y = 0; y < 16; y++) { + for (x = 0; x < 16; x++) { + if (x == 0 || y == 0) + row[x] = wm_pixel(&c[COLOUR_LIGHT]); + else if (x == 15 || y == 15) + row[x] = wm_pixel(&c[COLOUR_DARK]); + else if (x == 1 || y == 1) + row[x] = wm_pixel(&c[COLOUR_LIGHT]); + else if (x == 14 || y == 14) + row[x] = wm_pixel(&c[COLOUR_DARK]); + else + row[x] = wm_pixel(&c[COLOUR_PRIMARY]); + } + memcpy(&icon[48 * out_y++ + out_x], row, sizeof row); + } +} + +int ewmh_probe_wm_icon(Widget shell) +{ + Display *display = XtDisplay(shell); + Screen *screen = XtScreen(shell); + Window root = RootWindowOfScreen(screen); + Atom net_supported, net_wm_icon, type; + + unsigned long offset = 0, i, nitems, bytes_after, *props; + unsigned char *prop_return; + int format; + + net_wm_icon = XInternAtom(display, "_NET_WM_ICON", FALSE); + net_supported = XInternAtom(display, "_NET_SUPPORTED", FALSE); + do { + XGetWindowProperty(display, root, net_supported, offset, 10, + FALSE, XA_ATOM, &type, + &format, &nitems, &bytes_after, + &prop_return); + + if (format != 32 || type != XA_ATOM) + break; + offset += nitems; + + props = (void *)prop_return; + for (i = 0; i < nitems; i++) { + if (props[i] == net_wm_icon) { + return 1; + } + } + } while (nitems > 0 && bytes_after > 0); + + return 0; +} + +void *ewmh_icon_alloc(unsigned long **sizes) +{ + unsigned long *buf; + + buf = calloc(sizeof *buf, EWMH_ICON_NELEM); + if (buf) { + sizes[ICON_16x16] = buf; + *sizes[ICON_16x16]++ = 16; + *sizes[ICON_16x16]++ = 16; + + sizes[ICON_24x24] = sizes[ICON_16x16] + 16*16; + *sizes[ICON_24x24]++ = 24; + *sizes[ICON_24x24]++ = 24; + + sizes[ICON_32x32] = sizes[ICON_24x24] + 24*24; + *sizes[ICON_32x32]++ = 32; + *sizes[ICON_32x32]++ = 32; + + sizes[ICON_48x48] = sizes[ICON_32x32] + 32*32; + *sizes[ICON_48x48]++ = 48; + *sizes[ICON_48x48]++ = 48; + } + + return buf; +} diff --git a/src/motif.c b/src/motif.c index f98b307..52afaae 100644 --- a/src/motif.c +++ b/src/motif.c @@ -135,9 +135,15 @@ static void proc_exit(Widget w, XEvent *e, String *argv, Cardinal *argc) static void proc_new_game(Widget w, XEvent *e, String *argv, Cardinal *argc) { + Widget shell; + + for (shell = w; !XtIsWMShell(shell);) + shell = XtParent(shell); + game_reset(&state.board); x11_redraw_goal(&state); x11_redraw_game(&state); + x11_redraw_icon(&state, shell); } static const XtActionsRec menu_actions[] = { @@ -158,8 +164,11 @@ static XtAppContext app_initialize(int argc, char **argv) ui_initialize(&state, shell); x11_initialize(&state, XtScreen(shell)); game_reset(&state.board); + state.use_ewmh_icons = ewmh_probe_wm_icon(shell); XtRealizeWidget(shell); + x11_redraw_icon(&state, shell); + return app; } diff --git a/src/motif.h b/src/motif.h index 171739d..74893d1 100644 --- a/src/motif.h +++ b/src/motif.h @@ -29,13 +29,49 @@ struct app_state { Widget game, goal; + /* Whether to set _NET_WM_ICON property on WMShell */ + int use_ewmh_icons; + GC tile_gc; + Pixmap icon_pixmap; uint_least32_t tile_colour[TILE_MAX-1][3]; }; void ui_initialize(struct app_state *state, Widget shell); void x11_initialize(struct app_state *state, Screen *screen); +void x11_redraw_icon(struct app_state *state, Widget shell); void x11_redraw_goal(struct app_state *state); void x11_redraw_game(struct app_state *state); +/* + * Helpers for drawing window icons in various sizes. The tileXX functions + * draw one (out of 9) tiles at a particular size using a particular colour + * set. Call for each tile position to draw a complete icon. + */ + +enum { ICON_16x16, ICON_24x24, ICON_32x32, ICON_48x48, ICON_MAX }; +#define EWMH_ICON_NELEM (2+16*16 + 2+24*24 + 2+32*32 + 2+48*48) + +void ewmh_tile16(unsigned long *icon, const XColor *c, int tile_x, int tile_y); +void ewmh_tile24(unsigned long *icon, const XColor *c, int tile_x, int tile_y); +void ewmh_tile32(unsigned long *icon, const XColor *c, int tile_x, int tile_y); +void ewmh_tile48(unsigned long *icon, const XColor *c, int tile_x, int tile_y); + +/* + * Allocate storage for the EWMH _NET_WM_ICON array. The sizes array is + * populated with pointers to the beginning of each icon's pixel data. For + * example, sizes[ICON_24x24] points to the first pixel of the 24x24 image. + * + * The returned value can then be passed to XChangeProperty to set the icon, + * (use EWMH_ICON_NELEM for the number of elements) and must be freed by the + * caller. + */ +void *ewmh_icon_alloc(unsigned long **sizes); + +/* + * Check if the root window indicates support for EWMH icons. Returns 1 if + * supported, or 0 otherwise. + */ +int ewmh_probe_wm_icon(Widget shell); + #endif diff --git a/src/motifopt.opt b/src/motifopt.opt index 9fd8240..b9c0aed 100644 --- a/src/motifopt.opt +++ b/src/motifopt.opt @@ -4,6 +4,9 @@ X server DISPLAY name to use. --geometry=[W][xH][+X[+Y]] Set initial window size (W by H) and/or position (X, Y). +--iconic +Start iconified. + --title=NAME Set window title to NAME. diff --git a/src/x11.c b/src/x11.c index 611223f..95e0cf0 100644 --- a/src/x11.c +++ b/src/x11.c @@ -18,12 +18,18 @@ #include #include +#include #include #include #include +#include +#include #include "motif.h" +/* Size of the traditional icon pixmap (multiple of 3) */ +#define ICON_SIZE 48 + /* TODO user-selectable colours */ static const char * const colours[][3] = { /*primary bottom top */ @@ -61,6 +67,9 @@ void x11_initialize(struct app_state *state, Screen *screen) gcv.line_width = 1; state->tile_gc = XCreateGC(display, root, GCLineWidth, &gcv); + + state->icon_pixmap = XCreatePixmap(display, root, ICON_SIZE, ICON_SIZE, + DefaultDepthOfScreen(screen)); } static void draw_tile(struct app_state *state, Display *display, Drawable d, @@ -94,7 +103,7 @@ static void draw_tile(struct app_state *state, Display *display, Drawable d, XFillRectangle(display, d, state->tile_gc, tx+2, ty+2, tw-4, th-4); } -static void +static int redraw_tile(struct app_state *state, Display *display, Drawable d, uint_fast32_t bit0, uint_fast32_t bit1, uint_fast32_t bit2, int x, int y, Dimension w, Dimension h) @@ -112,24 +121,83 @@ redraw_tile(struct app_state *state, Display *display, Drawable d, } else { draw_tile(state, display, d, tile, x, y, w, h); } + + return tile; +} + +static int +redraw_goal_tile(struct app_state *state, Display *display, Drawable d, + int x, int y, Dimension w, Dimension h) +{ + uint_least16_t *gp = state->board.goal; + + return redraw_tile(state, display, d, gp[0], gp[1], gp[2], x, y, w, h); } void x11_redraw_goal(struct app_state *state) { Display *display = XtDisplay(state->goal); - Window goal = XtWindow(state->goal); + Window window = XtWindow(state->goal); Dimension w, h; int i; XtVaGetValues(state->goal, XmNwidth, &w, XmNheight, &h, (char *)NULL); - w /= 3; h /= 3; + for (i = 0; i < 9; i++) + redraw_goal_tile(state, display, window, i%3, i/3, w/3, h/3); +} + +/* Render the goal area as the window's icon */ +void x11_redraw_icon(struct app_state *state, Widget shell) +{ + Display *display = XtDisplay(shell); + Dimension tilesz = ICON_SIZE/3; + int i, j, tile; + + XColor colours[(TILE_MAX-1)*COLOUR_MAX]; + unsigned long *icons[ICON_MAX]; + void *wm_icon = NULL; + + if (state->use_ewmh_icons && (wm_icon = ewmh_icon_alloc(icons))) { + Colormap cmap = DefaultColormapOfScreen(XtScreen(shell)); + + for (i = 0; i < TILE_MAX-1; i++) { + for (j = 0; j < COLOUR_MAX; j++) { + XColor *c = &colours[i*COLOUR_MAX+j]; + c->pixel = state->tile_colour[i][j]; + } + } + + XQueryColors(display, cmap, colours, i*j); + } for (i = 0; i < 9; i++) { - uint_least16_t *gp = state->board.goal; + tile = redraw_goal_tile(state, display, state->icon_pixmap, + i%3, i/3, tilesz, tilesz); + + if (wm_icon) { + XColor *c = &colours[(tile-1)*COLOUR_MAX]; + ewmh_tile16(icons[ICON_16x16], c, i%3, i/3); + ewmh_tile24(icons[ICON_24x24], c, i%3, i/3); + ewmh_tile32(icons[ICON_32x32], c, i%3, i/3); + ewmh_tile48(icons[ICON_48x48], c, i%3, i/3); + } + } - redraw_tile(state, display, goal, - gp[0], gp[1], gp[2], - i%3, i/3, w, h); + /* + * Clear and reset XmNiconPixmap otherwise it seems dtwm will not + * notice the changed icon. + */ + XtVaSetValues(shell, XmNiconPixmap, None, (char *)NULL); + XtVaSetValues(shell, XmNiconPixmap, state->icon_pixmap, (char *)NULL); + + if (wm_icon) { + Atom net_wm_icon = XInternAtom(display, "_NET_WM_ICON", FALSE); + + XChangeProperty(display, XtWindow(shell), net_wm_icon, + XA_CARDINAL, 32, PropModeReplace, + wm_icon, EWMH_ICON_NELEM); + + free(wm_icon); } } diff --git a/t/.gitignore b/t/.gitignore index 46a482f..8221c29 100644 --- a/t/.gitignore +++ b/t/.gitignore @@ -1,2 +1,3 @@ /boardmove +/ewmhicon /rng-test diff --git a/t/ewmhicon.c b/t/ewmhicon.c new file mode 100644 index 0000000..e088d41 --- /dev/null +++ b/t/ewmhicon.c @@ -0,0 +1,114 @@ +/* + * Test app for _NET_WM_ICON formatting. + * Copyright © 2022 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. + * + * 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 + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include "motif.h" + +static const char *progname = "ewmhicon"; + +static void print_usage(FILE *f) +{ + fprintf(f, "Usage: %s size\n", progname); +} + +static const char sizes[][6] = { + "16x16", "24x24", "32x32", "48x48" +}; + +int to_size_enum(const char *arg) +{ + char buf[8]; + unsigned i; + + 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; + } + + return -1; +} + +static unsigned long icon_buf[48*48]; + +int main(int argc, char **argv) +{ + void (*tilefunc)(unsigned long *, const XColor *, int, int); + XColor c[COLOUR_MAX] = {0}; + int size, x, y, w, h; + + if (argc > 0) + progname = argv[0]; + + if (argc != 2) { + print_usage(stderr); + return EXIT_FAILURE; + } + + size = to_size_enum(argv[1]); + if (size < 0) { + printf("%s: error: invalid size %s\n", progname, argv[1]); + return EXIT_FAILURE; + } + + 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[COLOUR_PRIMARY].red = 0xffff; + c[COLOUR_DARK].green = 0xffff; + c[COLOUR_LIGHT].blue = 0xffff; + + for (x = 0; x < 3; x++) { + for (y = 0; y < 3; y++) { + tilefunc(icon_buf, c, x, y); + } + } + + for (y = 0; y < h; y++) { + for (x = 0; x < w; x++) { + unsigned long val = icon_buf[y*h+x]; + int c = ' '; + + if (val == 0xffff0000) c = '.'; // primary + else if (val == 0xff00ff00) c = '%'; // dark + else if (val == 0xff0000ff) c = '+'; // light + + putchar(c); + } + putchar('\n'); + } + + return 0; +} diff --git a/tests/game.at b/tests/game.at index 9cfc7af..bfd9819 100644 --- a/tests/game.at +++ b/tests/game.at @@ -1,3 +1,18 @@ +# Copyright © 2022 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 +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + AT_SETUP([game_do_move zigzag]) AT_CHECK([boardmove m4_do( diff --git a/tests/gui.at b/tests/gui.at new file mode 100644 index 0000000..95d33fd --- /dev/null +++ b/tests/gui.at @@ -0,0 +1,162 @@ +# Copyright © 2022 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 +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +AT_SETUP([_NET_WM_ICON tiles (16x16)]) + +AT_CHECK([ewmhicon 16x16], [0], [dnl +....%+....%+.... +....%+....%+.... +....%+....%+.... +....%+....%+.... +%%%%%+%%%%%+%%%% +++++++++++++++++ +....%+....%+.... +....%+....%+.... +....%+....%+.... +....%+....%+.... +%%%%%+%%%%%+%%%% +++++++++++++++++ +....%+....%+.... +....%+....%+.... +....%+....%+.... +....%+....%+.... +]) + +AT_CLEANUP + +AT_SETUP([_NET_WM_ICON tiles (24x24)]) + +AT_CHECK([ewmhicon 24x24], [0], [dnl +++++++++++++++++++++++++ ++......%+......%+......% ++......%+......%+......% ++......%+......%+......% ++......%+......%+......% ++......%+......%+......% ++......%+......%+......% ++%%%%%%%+%%%%%%%+%%%%%%% +++++++++++++++++++++++++ ++......%+......%+......% ++......%+......%+......% ++......%+......%+......% ++......%+......%+......% ++......%+......%+......% ++......%+......%+......% ++%%%%%%%+%%%%%%%+%%%%%%% +++++++++++++++++++++++++ ++......%+......%+......% ++......%+......%+......% ++......%+......%+......% ++......%+......%+......% ++......%+......%+......% ++......%+......%+......% ++%%%%%%%+%%%%%%%+%%%%%%% +]) + +AT_CLEANUP + +AT_SETUP([_NET_WM_ICON tiles (32x32)]) + +AT_CHECK([ewmhicon 32x32], [0], [dnl +++++++++++++++++++++++++++++++++ ++.........%+........%+.........% ++.........%+........%+.........% ++.........%+........%+.........% ++.........%+........%+.........% ++.........%+........%+.........% ++.........%+........%+.........% ++.........%+........%+.........% ++.........%+........%+.........% ++.........%+........%+.........% ++%%%%%%%%%%+%%%%%%%%%+%%%%%%%%%% +++++++++++++++++++++++++++++++++ ++.........%+........%+.........% ++.........%+........%+.........% ++.........%+........%+.........% ++.........%+........%+.........% ++.........%+........%+.........% ++.........%+........%+.........% ++.........%+........%+.........% ++.........%+........%+.........% ++%%%%%%%%%%+%%%%%%%%%+%%%%%%%%%% +++++++++++++++++++++++++++++++++ ++.........%+........%+.........% ++.........%+........%+.........% ++.........%+........%+.........% ++.........%+........%+.........% ++.........%+........%+.........% ++.........%+........%+.........% ++.........%+........%+.........% ++.........%+........%+.........% ++.........%+........%+.........% ++%%%%%%%%%%+%%%%%%%%%+%%%%%%%%%% +]) + +AT_CLEANUP + +AT_SETUP([_NET_WM_ICON tiles (48x48)]) + +AT_CHECK([ewmhicon 48x48], [0], [dnl +++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++%+++++++++++++++%+++++++++++++++% +++............%%++............%%++............%% +++............%%++............%%++............%% +++............%%++............%%++............%% +++............%%++............%%++............%% +++............%%++............%%++............%% +++............%%++............%%++............%% +++............%%++............%%++............%% +++............%%++............%%++............%% +++............%%++............%%++............%% +++............%%++............%%++............%% +++............%%++............%%++............%% +++............%%++............%%++............%% +++%%%%%%%%%%%%%%++%%%%%%%%%%%%%%++%%%%%%%%%%%%%% ++%%%%%%%%%%%%%%%+%%%%%%%%%%%%%%%+%%%%%%%%%%%%%%% +++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++%+++++++++++++++%+++++++++++++++% +++............%%++............%%++............%% +++............%%++............%%++............%% +++............%%++............%%++............%% +++............%%++............%%++............%% +++............%%++............%%++............%% +++............%%++............%%++............%% +++............%%++............%%++............%% +++............%%++............%%++............%% +++............%%++............%%++............%% +++............%%++............%%++............%% +++............%%++............%%++............%% +++............%%++............%%++............%% +++%%%%%%%%%%%%%%++%%%%%%%%%%%%%%++%%%%%%%%%%%%%% ++%%%%%%%%%%%%%%%+%%%%%%%%%%%%%%%+%%%%%%%%%%%%%%% +++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++%+++++++++++++++%+++++++++++++++% +++............%%++............%%++............%% +++............%%++............%%++............%% +++............%%++............%%++............%% +++............%%++............%%++............%% +++............%%++............%%++............%% +++............%%++............%%++............%% +++............%%++............%%++............%% +++............%%++............%%++............%% +++............%%++............%%++............%% +++............%%++............%%++............%% +++............%%++............%%++............%% +++............%%++............%%++............%% +++%%%%%%%%%%%%%%++%%%%%%%%%%%%%%++%%%%%%%%%%%%%% ++%%%%%%%%%%%%%%%+%%%%%%%%%%%%%%%+%%%%%%%%%%%%%%% +]) + +AT_CLEANUP diff --git a/testsuite.at b/testsuite.at index 7e8855e..104f782 100644 --- a/testsuite.at +++ b/testsuite.at @@ -17,3 +17,4 @@ AT_INIT AT_COLOR_TESTS m4_include([tests/game.at]) +m4_include([tests/gui.at]) -- 2.43.2