diff --git a/Makefile b/Makefile index 1b95d15..e571818 100644 --- a/Makefile +++ b/Makefile @@ -37,7 +37,7 @@ dist: clean @echo creating dist tarball @mkdir -p tabbed-${VERSION} @cp -R LICENSE Makefile README config.def.h config.mk \ - tabbed.1 arg.h ${SRC} tabbed-${VERSION} + tabbed.1 arg.h icon.h ${SRC} tabbed-${VERSION} @tar -cf tabbed-${VERSION}.tar tabbed-${VERSION} @gzip tabbed-${VERSION}.tar @rm -rf tabbed-${VERSION} diff --git a/TODO b/TODO index 8e1986d..dbcb930 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,3 @@ # TODO * add some way to detach windows * add some way to attach windows - diff --git a/icon.h b/icon.h new file mode 100644 index 0000000..e2ef631 --- /dev/null +++ b/icon.h @@ -0,0 +1,41 @@ +/* GIMP RGBA C-Source image dump (icon.c) */ + +#define ICON_WIDTH (16) +#define ICON_HEIGHT (16) +#define ICON_BYTES_PER_PIXEL (4) /* 2:RGB16, 3:RGB, 4:RGBA */ +#define ICON_COMMENT \ + "GIMP -> Export -> C-Source -> Prefixed name = ICON, Use macros, Save alpha" +#define ICON_PIXEL_DATA ((unsigned char*) ICON_pixel_data) +static const unsigned char ICON_pixel_data[16 * 16 * 4 + 1] = +("\000\000\000\377\000\000\000\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\000\000" + "\000\377\000\000\000\000\000\000\000\000\000\000\000\377\000\000\000\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\000\000\000\377\000\000\000" + "\000\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000" + "\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377" + "\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000" + "\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377" + "\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000" + "\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377" + "\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000" + "\000\377\000\000\000\377\000\000\000\000\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\000\000" + "\000\377\000\000\000\000\000\000\000\000\000\000\000\377\000\000\000\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377" + "\000\000\000\377\000\000\000\000\000\000\000\000\000\000\000\377\000\000\000\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\000\000\000\377\000" + "\000\000\377\000\000\000\000\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377" + "\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000" + "\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377" + "\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000" + "\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377" + "\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000" + "\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\377\000\000\000\377\000\000\000\377\000\000\000\000\000\000\000\377\000\000\000\377\000\000\000\000\000\000\000\001\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\000" + "\000\000\377\000\000\000\000\000\000\000\000\000\000\000\377\000\000\000\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\377\000\000\000\377"); diff --git a/tabbed.c b/tabbed.c index eafe28a..ec6212e 100644 --- a/tabbed.c +++ b/tabbed.c @@ -18,6 +18,7 @@ #include #include "arg.h" +#include "icon.h" /* XEMBED messages */ #define XEMBED_EMBEDDED_NOTIFY 0 @@ -49,7 +50,7 @@ enum { ColFG, ColBG, ColLast }; /* color */ enum { WMProtocols, WMDelete, WMName, WMState, WMFullscreen, - XEmbed, WMSelectTab, WMLast }; /* default atoms */ + XEmbed, WMSelectTab, WMIcon, WMLast }; /* default atoms */ typedef union { int i; @@ -135,6 +136,7 @@ static void updatenumlockmask(void); static void updatetitle(int c); static int xerror(Display *dpy, XErrorEvent *ee); static void xsettitle(Window w, const char *str); +static void xseticon(void); /* variables */ static int screen; @@ -169,6 +171,7 @@ static char winid[64]; static char **cmd; static char *wmname = "tabbed"; static const char *geometry; +static unsigned long icon[ICON_WIDTH * ICON_HEIGHT + 2]; char *argv0; @@ -455,6 +458,8 @@ focus(int c) n += snprintf(&buf[n], sizeof(buf) - n, " %s", cmd[i]); xsettitle(win, buf); + XChangeProperty(dpy, win, wmatom[WMIcon], XA_CARDINAL, 32, + PropModeReplace, (unsigned char *) icon, ICON_WIDTH * ICON_HEIGHT + 2); XRaiseWindow(dpy, win); return; @@ -474,6 +479,7 @@ focus(int c) lastsel = sel; sel = c; } + xseticon(); if (clients[c]->urgent && (wmh = XGetWMHints(dpy, clients[c]->win))) { wmh->flags &= ~XUrgencyHint; @@ -868,9 +874,13 @@ propertynotify(const XEvent *e) } } XFree(wmh); + if (c == sel) + xseticon(); } else if (ev->state != PropertyDelete && ev->atom == XA_WM_NAME && (c = getclient(ev->window)) > -1) { updatetitle(c); + } else if (ev->atom == wmatom[WMIcon] && (c = getclient(ev->window)) > -1 && c == sel) { + xseticon(); } } @@ -995,6 +1005,7 @@ setup(void) wmatom[WMSelectTab] = XInternAtom(dpy, "_TABBED_SELECT_TAB", False); wmatom[WMState] = XInternAtom(dpy, "_NET_WM_STATE", False); wmatom[XEmbed] = XInternAtom(dpy, "_XEMBED", False); + wmatom[WMIcon] = XInternAtom(dpy, "_NET_WM_ICON", False); /* init appearance */ wx = 0; @@ -1074,6 +1085,17 @@ setup(void) snprintf(winid, sizeof(winid), "%lu", win); setenv("XEMBED", winid, 1); + /* change icon from RGBA to ARGB */ + icon[0] = ICON_WIDTH; + icon[1] = ICON_HEIGHT; + for (int i = 0; i < ICON_WIDTH * ICON_HEIGHT; ++i) { + icon[i + 2] = + ICON_PIXEL_DATA[i * 4 + 3] << 24 | + ICON_PIXEL_DATA[i * 4 + 0] << 0 | + ICON_PIXEL_DATA[i * 4 + 1] << 8 | + ICON_PIXEL_DATA[i * 4 + 2] << 16 ; + } + nextfocus = foreground; focus(-1); } @@ -1265,6 +1287,46 @@ xsettitle(Window w, const char *str) } } +void +xseticon(void) +{ + Atom ret_type; + XWMHints *wmh, *cwmh; + int ret_format; + unsigned long ret_nitems, ret_nleft; + long offset = 0L; + unsigned char *data; + + wmh = XGetWMHints(dpy, win); + wmh->flags &= ~(IconPixmapHint | IconMaskHint); + wmh->icon_pixmap = wmh->icon_mask = None; + + + if (XGetWindowProperty(dpy, clients[sel]->win, wmatom[WMIcon], offset, LONG_MAX, False, + XA_CARDINAL, &ret_type, &ret_format, &ret_nitems, + &ret_nleft, &data) == Success && + ret_type == XA_CARDINAL && ret_format == 32) + { + XChangeProperty(dpy, win, wmatom[WMIcon], XA_CARDINAL, 32, + PropModeReplace, data, ret_nitems); + } else if ((cwmh = XGetWMHints(dpy, clients[sel]->win)) && cwmh->flags & IconPixmapHint) { + XDeleteProperty(dpy, win, wmatom[WMIcon]); + wmh->flags |= IconPixmapHint; + wmh->icon_pixmap = cwmh->icon_pixmap; + if (cwmh->flags & IconMaskHint) { + wmh->flags |= IconMaskHint; + wmh->icon_mask = cwmh->icon_mask; + } + XFree(cwmh); + } else { + XChangeProperty(dpy, win, wmatom[WMIcon], XA_CARDINAL, 32, + PropModeReplace, (unsigned char *) icon, ICON_WIDTH * ICON_HEIGHT + 2); + } + XSetWMHints(dpy, win, wmh); + XFree(wmh); + XFree(data); +} + void usage(void) {