]> git.draconx.ca Git - rrace.git/blob - src/ewmhicon.c
Implement window icons.
[rrace.git] / src / ewmhicon.c
1 /*
2  * _NET_WM_ICON helpers for slide puzzle game
3  * Copyright © 2022 Nick Bowler
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
17  */
18
19 #include <config.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23
24 #include <X11/Intrinsic.h>
25 #include <X11/Xatom.h>
26 #include "motif.h"
27
28 static unsigned long scale16to8(unsigned x)
29 {
30         return x*0xfful / 0xffff;
31 }
32
33 static unsigned long wm_pixel(const XColor *c)
34 {
35         return 0xff000000
36              | scale16to8(c->red) << 16
37              | scale16to8(c->green) << 8
38              | scale16to8(c->blue);
39 }
40
41 /*
42  * The 16x16 icon is drawn with 1px shadow, 6x6 tiles, with 1 pixel cropped off
43  * all the edge tiles
44  */
45 void ewmh_tile16(unsigned long *icon, const XColor *c, int tile_x, int tile_y)
46 {
47         int out_x, out_y, out_w, x, y;
48         unsigned long row[6];
49
50         out_x = tile_x * 11 / 2;
51         out_y = tile_y * 11 / 2;
52         out_w = (5 + (tile_x == 1)) * sizeof row[0];
53
54         for (y = 0+(tile_y == 0); y < 6-(tile_y == 2); y++) {
55                 for (x = 0+(tile_x == 0); x < 6-(tile_x==2); x++) {
56                         if (x == 0 || y == 0)
57                                 row[x] = wm_pixel(&c[COLOUR_LIGHT]);
58                         else if (x == 5 || y == 5)
59                                 row[x] = wm_pixel(&c[COLOUR_DARK]);
60                         else
61                                 row[x] = wm_pixel(&c[COLOUR_PRIMARY]);
62                 }
63                 memcpy(&icon[16 * out_y++ + out_x], &row[tile_x == 0], out_w);
64         }
65 }
66
67 /*
68  * The 24x24 icon is drawn with 1px shadow and 8x8 tiles.
69  */
70 void ewmh_tile24(unsigned long *icon, const XColor *c, int tile_x, int tile_y)
71 {
72         int out_x, out_y, x, y;
73         unsigned long row[8];
74
75         out_x = tile_x * 8;
76         out_y = tile_y * 8;
77
78         for (y = 0; y < 8; y++) {
79                 for (x = 0; x < 8; x++) {
80                         if (x == 0 || y == 0)
81                                 row[x] = wm_pixel(&c[COLOUR_LIGHT]);
82                         else if (x == 7 || y == 7)
83                                 row[x] = wm_pixel(&c[COLOUR_DARK]);
84                         else
85                                 row[x] = wm_pixel(&c[COLOUR_PRIMARY]);
86                 }
87                 memcpy(&icon[24 * out_y++ + out_x], row, sizeof row);
88         }
89 }
90
91 /*
92  * The 32x32 icon is drawn with 1px shadow with slightly uneven tiles on
93  * an 11-10-11 pixel grid.
94  */
95 void ewmh_tile32(unsigned long *icon, const XColor *c, int tile_x, int tile_y)
96 {
97         int out_x, out_y, out_w, out_h, x, y;
98         unsigned long row[11];
99
100         out_x = 10*tile_x + (tile_x > 0);
101         out_y = 10*tile_y + (tile_y > 0);
102         out_w = 10 + (tile_x != 1);
103         out_h = 10 + (tile_y != 1);
104
105         for (y = 0; y < out_h; y++) {
106                 for (x = 0; x < out_w; x++) {
107                         if (x == 0 || y == 0)
108                                 row[x] = wm_pixel(&c[COLOUR_LIGHT]);
109                         else if (x == out_w-1 || y == out_h-1)
110                                 row[x] = wm_pixel(&c[COLOUR_DARK]);
111                         else
112                                 row[x] = wm_pixel(&c[COLOUR_PRIMARY]);
113                 }
114                 memcpy(&icon[32 * out_y++ + out_x], row, out_w * sizeof row[0]);
115         }
116 }
117
118 /*
119  * The 48x48 icon is drawn with 2px shadow and 16x16 tiles.
120  */
121 void ewmh_tile48(unsigned long *icon, const XColor *c, int tile_x, int tile_y)
122 {
123         int out_x, out_y, x, y;
124         unsigned long row[16];
125
126         out_x = tile_x * 16;
127         out_y = tile_y * 16;
128
129         for (y = 0; y < 16; y++) {
130                 for (x = 0; x < 16; x++) {
131                         if (x == 0 || y == 0)
132                                 row[x] = wm_pixel(&c[COLOUR_LIGHT]);
133                         else if (x == 15 || y == 15)
134                                 row[x] = wm_pixel(&c[COLOUR_DARK]);
135                         else if (x == 1 || y == 1)
136                                 row[x] = wm_pixel(&c[COLOUR_LIGHT]);
137                         else if (x == 14 || y == 14)
138                                 row[x] = wm_pixel(&c[COLOUR_DARK]);
139                         else
140                                 row[x] = wm_pixel(&c[COLOUR_PRIMARY]);
141                 }
142                 memcpy(&icon[48 * out_y++ + out_x], row, sizeof row);
143         }
144 }
145
146 int ewmh_probe_wm_icon(Widget shell)
147 {
148         Display *display = XtDisplay(shell);
149         Screen *screen = XtScreen(shell);
150         Window root = RootWindowOfScreen(screen);
151         Atom net_supported, net_wm_icon, type;
152
153         unsigned long offset = 0, i, nitems, bytes_after, *props;
154         unsigned char *prop_return;
155         int format;
156
157         net_wm_icon = XInternAtom(display, "_NET_WM_ICON", FALSE);
158         net_supported = XInternAtom(display, "_NET_SUPPORTED", FALSE);
159         do {
160                 XGetWindowProperty(display, root, net_supported, offset, 10,
161                                             FALSE, XA_ATOM, &type,
162                                             &format, &nitems, &bytes_after,
163                                             &prop_return);
164
165                 if (format != 32 || type != XA_ATOM)
166                         break;
167                 offset += nitems;
168
169                 props = (void *)prop_return;
170                 for (i = 0; i < nitems; i++) {
171                         if (props[i] == net_wm_icon) {
172                                 return 1;
173                         }
174                 }
175         } while (nitems > 0 && bytes_after > 0);
176
177         return 0;
178 }
179
180 void *ewmh_icon_alloc(unsigned long **sizes)
181 {
182         unsigned long *buf;
183
184         buf = calloc(sizeof *buf, EWMH_ICON_NELEM);
185         if (buf) {
186                 sizes[ICON_16x16] = buf;
187                 *sizes[ICON_16x16]++ = 16;
188                 *sizes[ICON_16x16]++ = 16;
189
190                 sizes[ICON_24x24] = sizes[ICON_16x16] + 16*16;
191                 *sizes[ICON_24x24]++ = 24;
192                 *sizes[ICON_24x24]++ = 24;
193
194                 sizes[ICON_32x32] = sizes[ICON_24x24] + 24*24;
195                 *sizes[ICON_32x32]++ = 32;
196                 *sizes[ICON_32x32]++ = 32;
197
198                 sizes[ICON_48x48] = sizes[ICON_32x32] + 32*32;
199                 *sizes[ICON_48x48]++ = 48;
200                 *sizes[ICON_48x48]++ = 48;
201         }
202
203         return buf;
204 }