From 4bfbc859f834599f8047443f14ad6a99006acaf4 Mon Sep 17 00:00:00 2001 From: Jarcode Date: Wed, 4 Sep 2019 15:36:25 -0700 Subject: [PATCH] add icon support for glava window --- glava-config/window.lua | 6 +-- glava/render.c | 9 +++-- glava/xwin.c | 79 +++++++++++++++++++++++++++++++++++++++- glava/xwin.h | 1 + resources/glava.bmp | Bin 0 -> 1162 bytes resources/glava.ico | Bin 318 -> 0 bytes 6 files changed, 88 insertions(+), 7 deletions(-) create mode 100644 resources/glava.bmp delete mode 100644 resources/glava.ico diff --git a/glava-config/window.lua b/glava-config/window.lua index 81e74f1..d0ca1ee 100644 --- a/glava-config/window.lua +++ b/glava-config/window.lua @@ -350,10 +350,10 @@ return function() model:remove(iter) end end - + function window:on_destroy() os.exit(0) end - + window:show_all() - window:set_icon_from_file(glava.resource_path .. "glava.ico") + window:set_icon_from_file(glava.resource_path .. "glava.bmp") Gtk.main() end diff --git a/glava/render.c b/glava/render.c index 34502da..8024ef6 100644 --- a/glava/render.c +++ b/glava/render.c @@ -1354,9 +1354,10 @@ struct glava_renderer* rd_new(const char** paths, const char* entry, glava_abort(); } - gl->w = gl->wcb->create_and_bind(wintitle, "GLava", xwintype, (const char**) xwinstates, xwinstates_sz, - gl->geometry[2], gl->geometry[3], gl->geometry[0], gl->geometry[1], - context_version_major, context_version_minor, gl->clickthrough, test_mode); + gl->w = gl->wcb->create_and_bind( + wintitle, "GLava", xwintype, (const char**) xwinstates, xwinstates_sz, + gl->geometry[2], gl->geometry[3], gl->geometry[0], gl->geometry[1], + context_version_major, context_version_minor, gl->clickthrough, test_mode); if (!gl->w) abort(); for (size_t t = 0; t < xwinstates_sz; ++t) @@ -1366,6 +1367,8 @@ struct glava_renderer* rd_new(const char** paths, const char* entry, if (xwinstates) free(xwinstates); if (wintitle && wintitle != wintitle_default) free(wintitle); + xwin_assign_icon_bmp(gl->wcb, gl->w, GLAVA_RESOURCE_PATH "/glava.bmp"); + glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_CLAMP); glDisable(GL_CULL_FACE); diff --git a/glava/xwin.c b/glava/xwin.c index 1b7bcd7..c56fbdb 100644 --- a/glava/xwin.c +++ b/glava/xwin.c @@ -7,11 +7,15 @@ #include #include #include - #include +#include +#include #include #include +#include +#include +#include #include #include @@ -25,6 +29,79 @@ #include "render.h" #include "xwin.h" +/* BMP Image header */ +struct __attribute__((packed)) bmp_header { + uint16_t header; + uint32_t size; + uint16_t reserved0, reserved1; + uint32_t offset; + /* BITMAPINFOHEADER */ + uint32_t header_size, width, height; + uint16_t planes, bits_per_pixel; + uint32_t compression, image_size, hres, vres, colors, colors_used; +}; + +#define BMP_HEADER_MAGIC 0x4D42 +#define BMP_BITFIELDS 3 + +void xwin_assign_icon_bmp(struct gl_wcb* wcb, void* impl, const char* path) { + int fd = open(path, O_RDONLY); + if (fd == -1) { + fprintf(stderr, "failed to load icon '%s': %s\n", path, strerror(errno)); + return; + } + Display* d = wcb->get_x11_display(); + Window w = wcb->get_x11_window(impl); + struct stat st; + fstat(fd, &st); + const struct bmp_header* header = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (header->header != BMP_HEADER_MAGIC) { + fprintf(stderr, "failed to load icon '%s': invalid BMP header.\n", path); + close(fd); + return; + } + if (header->bits_per_pixel != 32) { + fprintf(stderr, "failed to load icon '%s': wrong bit depth (%d).\n", + path, (int) header->bits_per_pixel); + close(fd); + return; + } + if (header->planes != 1 || header->compression != BMP_BITFIELDS) { + fprintf(stderr, "failed to load icon '%s': invalid BMP format, requires RGBA bitfields.\n", path); + close(fd); + return; + } + + /* Obtain image data pointer from offset */ + const char* data = (const char*) (((const uint8_t*) header) + header->offset); + + /* Assign icon using the older WMHints. Most window managers don't actually use this. */ + XWMHints hints = {}; + hints.flags = IconPixmapHint; + hints.icon_pixmap = XCreateBitmapFromData(d, w, data, header->width, header->height); + XSetWMHints(d, w, &hints); + + /* To assign the icon property we need to convert the image data to `unsigned long`, which + can be 64-bits and padded depending on the architecture. Additionally we need to flip the + Y-axis due to how BMP data is stored. */ + size_t sz = header->width * header->height; + size_t asz = sz + 2; + unsigned long* off = malloc(asz * sizeof(unsigned long)); + for (size_t x = 0; x < header->width; ++x) { + for (size_t y = 0; y < header->height; ++y) { + off[x + (((header->height - 1) - y) * header->height) + 2] + = ((const uint32_t*) data)[x + (y * header->height)]; + } + } + /* The first two elements represent the icon dimensions */ + off[0] = header->width; + off[1] = header->height; + XChangeProperty(d, w, XInternAtom(d, "_NET_WM_ICON", true), + XA_CARDINAL, 32, PropModeReplace, (const unsigned char*) off, asz); + free(off); + close(fd); +}; + /* Note: currently unused */ Window* __attribute__ ((unused)) xwin_get_desktop_layer(struct gl_wcb* wcb) { static Window desktop; diff --git a/glava/xwin.h b/glava/xwin.h index ddce088..5bc0048 100644 --- a/glava/xwin.h +++ b/glava/xwin.h @@ -6,6 +6,7 @@ typedef unsigned long int Window; +void xwin_assign_icon_bmp(struct gl_wcb* wcb, void* impl, const char* path); bool xwin_should_render(struct gl_wcb* wcb, void* impl); void xwin_wait_for_wm(void); bool xwin_settype(struct gl_wcb* wcb, void* impl, const char* type); diff --git a/resources/glava.bmp b/resources/glava.bmp new file mode 100644 index 0000000000000000000000000000000000000000..873286a4e713109e90b9be648f70a81865eb5d3f GIT binary patch literal 1162 zcmZ?r?P6g7gDwUJh8hM21_3B$WKdvW2Fb86FevLmFo+Am{}~t{2*myGTu}?=>cJwI$ZieYCyOF8h;@5=olmq(+^^UFtQpDpOAi# a8e~1lY>*s2{m5#uu|fJ_7@PcX5d#2+d^Z39 literal 0 HcmV?d00001 diff --git a/resources/glava.ico b/resources/glava.ico deleted file mode 100644 index f27a3b07e59144bfa0766915c72d3b2d6206cb59..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 318 zcmZQzU}Ruq5D*YxU}Run&|qX>5My9q&|qL-5MW?nP+$PbvoPQSCMG5fdpa8!8XER6 z>{;Bv&@g8YL(iTDh7Eff7#jA>W@y;92bWf`_)I7Oa~K#Hm{>U2S=pEw@zD$*c?J%4 zPBsQcCQc4^P6kd!CQb%+&Y3eA88~NxXoi_H!8FKp22K!(1ONXIvl$ERz`!8j!oVO< S!@wX@!@%&T9)dx7U>E?to;zOv