/* * _NET_WM_ICON helpers for slide puzzle game * 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 * 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 #if !X_DISPLAY_MISSING # include # include #endif #include "ewmhicon.h" #include "colour.h" #include "icon.h" enum { ICON_16x16, ICON_24x24, ICON_32x32, ICON_48x48, ICON_MAX }; static unsigned long scale16to8(uint_least32_t x) { return x*0xff / 0xffff; } static unsigned long wm_pixel(const XColor *c) { 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) { unsigned char *index = icon; unsigned long *argb = icon; unsigned i; area--; for (i = 0; i <= area; i++) { argb[area-i] = (map + index[area-i])->pixel; } } void *ewmh_icon_generate(const unsigned long *seq, const XColor *map) { static const unsigned char dims[ICON_MAX] = { 16, 24, 32, 48 }; unsigned long *work, *ret; unsigned i, j, fullsize, size; work = ret = malloc(sizeof *work * EWMH_ICON_NELEM); if (!work) return NULL; for (i = fullsize = 0; i < ICON_MAX; i++) { work += fullsize; size = dims[i]; *work++ = size; *work++ = size; for (j = 0; j < 9; j++) { unsigned x = j%3, y = j/3; switch (i) { case 0: icon_tile16((void *)work, seq[j], x, y); break; case 1: icon_tile24((void *)work, seq[j], x, y); break; case 2: icon_tile32((void *)work, seq[j], x, y); break; case 3: icon_tile48((void *)work, seq[j], x, y); break; } } fullsize = size*size; do_remap(work, fullsize, map); } return ret; } #if !X_DISPLAY_MISSING /* * EWMH-supporting window managers that handle _NET_WM_ICON add this atom to * the _NET_SUPPORTED list on the root window. Look for that and return 1 * if it is found, or 0 otherwise. */ 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", 0); net_supported = XInternAtom(display, "_NET_SUPPORTED", 0); do { XGetWindowProperty(display, root, net_supported, offset, 10, 0, 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) { XFree(props); return 1; } } XFree(props); } while (nitems > 0 && bytes_after > 0); return 0; } #endif