2 * Test app for _NET_WM_ICON formatting.
3 * Copyright © 2022 Nick Bowler
5 * Use a fake colour scheme to generate an icon of the chosen size (16x16,
6 * 24x24, 32x32 or 48x48) and display the pixels as characters.
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
36 static const char *progname = "ewmhicon";
37 static const char sopts[] = "c:VH";
38 static const struct option lopts[] = {
39 { "colourseq", 1, NULL, 'c' },
40 { "version", 0, NULL, 'V' },
41 { "help", 0, NULL, 'H' },
45 #define S8TO16(x) ((x) * 0xfffful / 0xff)
47 #define RGB8(r, g, b) { \
48 0xff000000 | (r << 16) | (g << 8) | b, \
49 S8TO16(r), S8TO16(g), S8TO16(b) }
51 #define COLOUR_SYS_EWMHICON(r, g, b) \
52 RGB8(0x ## r ## ul, 0x ## g ## ul, 0x ## b ## ul)
55 #define COLOUR_SYSTEM EWMHICON
57 #define COLOURTAB_(n) { n ## _PRIMARY, n ## _DARK, n ## _LIGHT }
58 #define COLOURTAB(n) COLOURTAB_(COLOUR ## n)
60 static const XColor colours[7][3] = {
62 { 0xffff0000, 0xffff },
63 { 0xff00ff00, 0, 0xffff },
64 { 0xff0000ff, 0, 0, 0xffff }
66 COLOURTAB(0), COLOURTAB(1), COLOURTAB(2),
67 COLOURTAB(3), COLOURTAB(4), COLOURTAB(5)
70 static void print_usage(FILE *f)
72 fprintf(f, "Usage: %s size\n", progname);
74 fprintf(f, "Try %s --help for more information.\n", progname);
77 static void print_help(void)
79 const struct option *opt;
84 for (opt = lopts; opt->name; opt++) {
85 if (help_print_optstring(opt, "ARG", 20))
90 printf("Report bugs to <%s>.\n", PACKAGE_BUGREPORT);
93 static void print_version(void)
95 printf("ewmhicon (%s) %s\n", PACKAGE, PACKAGE_VERSION);
96 printf("Copyright (C) 2022 Nick Bowler\n");
97 puts("License GPLv3+: GNU GPL version 3 or any later version");
98 puts("This is free software: you are free to change and redistribute it.");
99 puts("There is NO WARRANTY, to the extent permitted by law.");
103 print_xpm(const char *colourseq, unsigned long size, unsigned long *icon_buf)
105 const char colourchars[21] = ".%+"",Rr""-Oo""'Yy"":Gg"";Bb"" Ww";
106 unsigned w = size & 0xffff, h = (size >> 16) & 0xffff;
107 unsigned x, y, i, j, n;
110 for (i = 0; i < 7; i++)
111 n -= !strchr(colourseq, '0'+i);
114 puts("static char *icon[] = {");
115 printf("\"%u %u %u 1\",\n", w, h, 3*n);
116 for (i = 0; i < 7; i++) {
117 if (!strchr(colourseq, '0'+i))
120 for (j = 0; j < 3; j++) {
121 printf("\"%c c #%.6lx\",\n", colourchars[3*i+j],
122 colours[i][j].pixel & 0xffffff);
126 for (y = 0; y < h; y++) {
128 for (x = 0; x < w; x++) {
129 unsigned long val = icon_buf[y*h+x];
132 for (i = 0; i < sizeof colourchars; i++) {
133 if (colours[i/3][i%3].pixel == val) {
141 printf("\"%.*s\n", y+1<h, ",");
146 static int decode_colourseq(char *out, const char *arg)
150 for (i = 0; i < 9; i++) {
153 case 'R': case 'r': out[i] = '1'; break;
154 case 'O': case 'o': out[i] = '2'; break;
155 case 'Y': case 'y': out[i] = '3'; break;
156 case 'G': case 'g': out[i] = '4'; break;
157 case 'B': case 'b': out[i] = '5'; break;
158 case 'W': case 'w': out[i] = '6'; break;
159 case '1': case '2': case '3': case '4': case '5': case '6':
160 case '0': out[i] = arg[i]; break;
167 fprintf(stderr, "%s: error: invalid colour sequence '%s'\n",
175 /* Convert the user sequence into a list of colour index specifiers */
176 static unsigned long *expand_seq(unsigned long *out, const char *seq)
180 for (i = 0; i < 9; i++) {
181 out[i] = 0x30303 * (seq[i]-'0') + 0x20100;
187 static unsigned long decode_size(char *size_spec)
193 n = strspn(size_spec, "0123456789");
194 switch (size_spec[n]) {
197 case 0: case 'x': case 'X':
202 w = strtoul(size_spec, NULL, 10);
210 n = strspn(size_spec += n+1, "0123456789");
214 h = strtoul(size_spec, NULL, 10);
219 return (h << 16) | w;
221 fprintf(stderr, "%s: %s: %s\n", progname, size_spec, strerror(ERANGE));
224 fprintf(stderr, "%s: %s: %s\n", progname, size_spec,
225 "invalid size specification");
229 static unsigned long *find_icon(unsigned long size, unsigned long *ewmhicon)
231 unsigned long w = size & 0xffff, h = (size >> 16) & 0xffff;
237 for (i = 0; i < EWMH_ICON_NELEM-2;) {
238 unsigned long icon_w = ewmhicon[i];
239 unsigned long icon_h = ewmhicon[i+1];
241 if (w == icon_w && h == icon_h) {
246 assert(icon_w < ULONG_MAX / icon_h);
247 assert(i < ULONG_MAX - icon_w*icon_h);
248 i += 2 + icon_w*icon_h;
251 if (i < EWMH_ICON_NELEM)
254 fprintf(stderr, "%s: error: no %lux%lu icon found\n", progname, w, h);
258 int main(int argc, char **argv)
260 unsigned long *ewmhicon, *icon, size, buf[9];
261 char colourseq[10] = "000000000";
267 while ((opt = getopt_long(argc, argv, sopts, lopts, 0)) != -1) {
270 if (decode_colourseq(colourseq, optarg) != 0)
285 if (argc != optind+1) {
286 printf("%s: error: size not specified\n", progname);
291 size = decode_size(argv[optind]);
295 ewmhicon = ewmh_icon_generate(expand_seq(buf, colourseq), colours[0]);
297 fprintf(stderr, "%s: failed to allocate memory\n", progname);
301 icon = find_icon(size, ewmhicon);
305 print_xpm(colourseq, size, icon);