/*
* _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