/*
* 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
#include
#include "ewmhicon.h"
#include "icon.h"
#include "colour.h"
#include "help.h"
static const char *progname = "ewmhicon";
static const char sopts[] = "c:VH";
static const struct option lopts[] = {
{ "colourseq", 1, NULL, 'c' },
{ "version", 0, NULL, 'V' },
{ "help", 0, NULL, 'H' },
{ 0 }
};
#define S8TO16(x) ((x) * 0xfffful / 0xff)
#define RGB8(r, g, b) { \
0xff000000 | (r << 16) | (g << 8) | b, \
S8TO16(r), S8TO16(g), S8TO16(b) }
#define COLOUR_SYS_EWMHICON(r, g, b) \
RGB8(0x ## r ## ul, 0x ## g ## ul, 0x ## b ## ul)
#undef COLOUR_SYSTEM
#define COLOUR_SYSTEM EWMHICON
#define COLOURTAB_(n) { n ## _PRIMARY, n ## _DARK, n ## _LIGHT }
#define COLOURTAB(n) COLOURTAB_(COLOUR ## n)
static const XColor colours[7][3] = {
{
{ 0xffff0000, 0xffff },
{ 0xff00ff00, 0, 0xffff },
{ 0xff0000ff, 0, 0, 0xffff }
},
COLOURTAB(0), COLOURTAB(1), COLOURTAB(2),
COLOURTAB(3), COLOURTAB(4), COLOURTAB(5)
};
static void print_usage(FILE *f)
{
fprintf(f, "Usage: %s size\n", progname);
if (f != stdout)
fprintf(f, "Try %s --help for more information.\n", progname);
}
static void print_help(void)
{
const struct option *opt;
print_usage(stdout);
putchar('\n');
puts("Options:");
for (opt = lopts; opt->name; opt++) {
if (help_print_optstring(opt, "ARG", 20))
putchar('\n');
}
putchar('\n');
printf("Report bugs to <%s>.\n", PACKAGE_BUGREPORT);
}
static void print_version(void)
{
printf("ewmhicon (%s) %s\n", PACKAGE, PACKAGE_VERSION);
printf("Copyright (C) 2022 Nick Bowler\n");
puts("License GPLv3+: GNU GPL version 3 or any later version");
puts("This is free software: you are free to change and redistribute it.");
puts("There is NO WARRANTY, to the extent permitted by law.");
}
static void
print_xpm(const char *colourseq, unsigned long size, unsigned long *icon_buf)
{
const char colourchars[21] = ".%+"",Rr""-Oo""'Yy"":Gg"";Bb"" Ww";
unsigned w = size & 0xffff, h = (size >> 16) & 0xffff;
unsigned x, y, i, j, n;
n = 7;
for (i = 0; i < 7; i++)
n -= !strchr(colourseq, '0'+i);
puts("/* XPM */");
puts("static char *icon[] = {");
printf("\"%u %u %u 1\",\n", w, h, 3*n);
for (i = 0; i < 7; i++) {
if (!strchr(colourseq, '0'+i))
continue;
for (j = 0; j < 3; j++) {
printf("\"%c c #%.6lx\",\n", colourchars[3*i+j],
colours[i][j].pixel & 0xffffff);
}
}
for (y = 0; y < h; y++) {
putchar('"');
for (x = 0; x < w; x++) {
unsigned long val = icon_buf[y*h+x];
int c = '#';
for (i = 0; i < sizeof colourchars; i++) {
if (colours[i/3][i%3].pixel == val) {
c = colourchars[i];
break;
}
}
putchar(c);
}
printf("\"%.*s\n", y+1 0xffff)
goto err_range;
if (!c) {
h = w;
} else {
n = strspn(size_spec += n+1, "0123456789");
if (size_spec[n])
goto err_invalid;
h = strtoul(size_spec, NULL, 10);
if (h > 0xffff)
goto err_range;
}
return (h << 16) | w;
err_range:
fprintf(stderr, "%s: %s: %s\n", progname, size_spec, strerror(ERANGE));
return 0;
err_invalid:
fprintf(stderr, "%s: %s: %s\n", progname, size_spec,
"invalid size specification");
return 0;
}
static unsigned long *find_icon(unsigned long size, unsigned long *ewmhicon)
{
unsigned long w = size & 0xffff, h = (size >> 16) & 0xffff;
unsigned long i;
if (!size)
return NULL;
for (i = 0; i < EWMH_ICON_NELEM-2;) {
unsigned long icon_w = ewmhicon[i];
unsigned long icon_h = ewmhicon[i+1];
if (w == icon_w && h == icon_h) {
i += 2;
break;
}
assert(icon_w < ULONG_MAX / icon_h);
assert(i < ULONG_MAX - icon_w*icon_h);
i += 2 + icon_w*icon_h;
}
if (i < EWMH_ICON_NELEM)
return &ewmhicon[i];
fprintf(stderr, "%s: error: no %lux%lu icon found\n", progname, w, h);
return NULL;
}
int main(int argc, char **argv)
{
unsigned long *ewmhicon, *icon, size, buf[9];
char colourseq[10] = "000000000";
int opt;
if (argc > 0)
progname = argv[0];
while ((opt = getopt_long(argc, argv, sopts, lopts, 0)) != -1) {
switch (opt) {
case 'c':
if (decode_colourseq(colourseq, optarg) != 0)
return EXIT_FAILURE;
break;
case 'H':
print_help();
return EXIT_SUCCESS;
case 'V':
print_version();
return EXIT_SUCCESS;
default:
print_usage(stderr);
return EXIT_FAILURE;
}
}
if (argc != optind+1) {
printf("%s: error: size not specified\n", progname);
print_usage(stderr);
return EXIT_FAILURE;
}
size = decode_size(argv[optind]);
if (!size)
return EXIT_FAILURE;
ewmhicon = ewmh_icon_generate(expand_seq(buf, colourseq), colours[0]);
if (!ewmhicon) {
fprintf(stderr, "%s: failed to allocate memory\n", progname);
return EXIT_FAILURE;
}
icon = find_icon(size, ewmhicon);
if (!icon)
return EXIT_FAILURE;
print_xpm(colourseq, size, icon);
free(ewmhicon);
return 0;
}