tabbed-icon-20200905-2da4e96.diff (9398B)
1 diff --git a/Makefile b/Makefile 2 index 1b95d15..e571818 100644 3 --- a/Makefile 4 +++ b/Makefile 5 @@ -37,7 +37,7 @@ dist: clean 6 @echo creating dist tarball 7 @mkdir -p tabbed-${VERSION} 8 @cp -R LICENSE Makefile README config.def.h config.mk \ 9 - tabbed.1 arg.h ${SRC} tabbed-${VERSION} 10 + tabbed.1 arg.h icon.h ${SRC} tabbed-${VERSION} 11 @tar -cf tabbed-${VERSION}.tar tabbed-${VERSION} 12 @gzip tabbed-${VERSION}.tar 13 @rm -rf tabbed-${VERSION} 14 diff --git a/TODO b/TODO 15 index 8e1986d..dbcb930 100644 16 --- a/TODO 17 +++ b/TODO 18 @@ -1,4 +1,3 @@ 19 # TODO 20 * add some way to detach windows 21 * add some way to attach windows 22 - 23 diff --git a/icon.h b/icon.h 24 new file mode 100644 25 index 0000000..e2ef631 26 --- /dev/null 27 +++ b/icon.h 28 @@ -0,0 +1,41 @@ 29 +/* GIMP RGBA C-Source image dump (icon.c) */ 30 + 31 +#define ICON_WIDTH (16) 32 +#define ICON_HEIGHT (16) 33 +#define ICON_BYTES_PER_PIXEL (4) /* 2:RGB16, 3:RGB, 4:RGBA */ 34 +#define ICON_COMMENT \ 35 + "GIMP -> Export -> C-Source -> Prefixed name = ICON, Use macros, Save alpha" 36 +#define ICON_PIXEL_DATA ((unsigned char*) ICON_pixel_data) 37 +static const unsigned char ICON_pixel_data[16 * 16 * 4 + 1] = 38 +("\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" 39 + "\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" 40 + "\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" 41 + "\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" 42 + "\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" 43 + "\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" 44 + "\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" 45 + "\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" 46 + "\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" 47 + "\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" 48 + "\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" 49 + "\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" 50 + "\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" 51 + "\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" 52 + "\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" 53 + "\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" 54 + "\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" 55 + "\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" 56 + "\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" 57 + "\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" 58 + "\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" 59 + "\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" 60 + "\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" 61 + "\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" 62 + "\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" 63 + "\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" 64 + "\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" 65 + "\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" 66 + "\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" 67 + "\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" 68 + "\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" 69 + "\000\000\000\000\000\000\000\000\377\000\000\000\377"); 70 diff --git a/tabbed.c b/tabbed.c 71 index eafe28a..ec6212e 100644 72 --- a/tabbed.c 73 +++ b/tabbed.c 74 @@ -18,6 +18,7 @@ 75 #include <X11/Xft/Xft.h> 76 77 #include "arg.h" 78 +#include "icon.h" 79 80 /* XEMBED messages */ 81 #define XEMBED_EMBEDDED_NOTIFY 0 82 @@ -49,7 +50,7 @@ 83 84 enum { ColFG, ColBG, ColLast }; /* color */ 85 enum { WMProtocols, WMDelete, WMName, WMState, WMFullscreen, 86 - XEmbed, WMSelectTab, WMLast }; /* default atoms */ 87 + XEmbed, WMSelectTab, WMIcon, WMLast }; /* default atoms */ 88 89 typedef union { 90 int i; 91 @@ -135,6 +136,7 @@ static void updatenumlockmask(void); 92 static void updatetitle(int c); 93 static int xerror(Display *dpy, XErrorEvent *ee); 94 static void xsettitle(Window w, const char *str); 95 +static void xseticon(void); 96 97 /* variables */ 98 static int screen; 99 @@ -169,6 +171,7 @@ static char winid[64]; 100 static char **cmd; 101 static char *wmname = "tabbed"; 102 static const char *geometry; 103 +static unsigned long icon[ICON_WIDTH * ICON_HEIGHT + 2]; 104 105 char *argv0; 106 107 @@ -455,6 +458,8 @@ focus(int c) 108 n += snprintf(&buf[n], sizeof(buf) - n, " %s", cmd[i]); 109 110 xsettitle(win, buf); 111 + XChangeProperty(dpy, win, wmatom[WMIcon], XA_CARDINAL, 32, 112 + PropModeReplace, (unsigned char *) icon, ICON_WIDTH * ICON_HEIGHT + 2); 113 XRaiseWindow(dpy, win); 114 115 return; 116 @@ -474,6 +479,7 @@ focus(int c) 117 lastsel = sel; 118 sel = c; 119 } 120 + xseticon(); 121 122 if (clients[c]->urgent && (wmh = XGetWMHints(dpy, clients[c]->win))) { 123 wmh->flags &= ~XUrgencyHint; 124 @@ -868,9 +874,13 @@ propertynotify(const XEvent *e) 125 } 126 } 127 XFree(wmh); 128 + if (c == sel) 129 + xseticon(); 130 } else if (ev->state != PropertyDelete && ev->atom == XA_WM_NAME && 131 (c = getclient(ev->window)) > -1) { 132 updatetitle(c); 133 + } else if (ev->atom == wmatom[WMIcon] && (c = getclient(ev->window)) > -1 && c == sel) { 134 + xseticon(); 135 } 136 } 137 138 @@ -995,6 +1005,7 @@ setup(void) 139 wmatom[WMSelectTab] = XInternAtom(dpy, "_TABBED_SELECT_TAB", False); 140 wmatom[WMState] = XInternAtom(dpy, "_NET_WM_STATE", False); 141 wmatom[XEmbed] = XInternAtom(dpy, "_XEMBED", False); 142 + wmatom[WMIcon] = XInternAtom(dpy, "_NET_WM_ICON", False); 143 144 /* init appearance */ 145 wx = 0; 146 @@ -1074,6 +1085,17 @@ setup(void) 147 snprintf(winid, sizeof(winid), "%lu", win); 148 setenv("XEMBED", winid, 1); 149 150 + /* change icon from RGBA to ARGB */ 151 + icon[0] = ICON_WIDTH; 152 + icon[1] = ICON_HEIGHT; 153 + for (int i = 0; i < ICON_WIDTH * ICON_HEIGHT; ++i) { 154 + icon[i + 2] = 155 + ICON_PIXEL_DATA[i * 4 + 3] << 24 | 156 + ICON_PIXEL_DATA[i * 4 + 0] << 0 | 157 + ICON_PIXEL_DATA[i * 4 + 1] << 8 | 158 + ICON_PIXEL_DATA[i * 4 + 2] << 16 ; 159 + } 160 + 161 nextfocus = foreground; 162 focus(-1); 163 } 164 @@ -1265,6 +1287,46 @@ xsettitle(Window w, const char *str) 165 } 166 } 167 168 +void 169 +xseticon(void) 170 +{ 171 + Atom ret_type; 172 + XWMHints *wmh, *cwmh; 173 + int ret_format; 174 + unsigned long ret_nitems, ret_nleft; 175 + long offset = 0L; 176 + unsigned char *data; 177 + 178 + wmh = XGetWMHints(dpy, win); 179 + wmh->flags &= ~(IconPixmapHint | IconMaskHint); 180 + wmh->icon_pixmap = wmh->icon_mask = None; 181 + 182 + 183 + if (XGetWindowProperty(dpy, clients[sel]->win, wmatom[WMIcon], offset, LONG_MAX, False, 184 + XA_CARDINAL, &ret_type, &ret_format, &ret_nitems, 185 + &ret_nleft, &data) == Success && 186 + ret_type == XA_CARDINAL && ret_format == 32) 187 + { 188 + XChangeProperty(dpy, win, wmatom[WMIcon], XA_CARDINAL, 32, 189 + PropModeReplace, data, ret_nitems); 190 + } else if ((cwmh = XGetWMHints(dpy, clients[sel]->win)) && cwmh->flags & IconPixmapHint) { 191 + XDeleteProperty(dpy, win, wmatom[WMIcon]); 192 + wmh->flags |= IconPixmapHint; 193 + wmh->icon_pixmap = cwmh->icon_pixmap; 194 + if (cwmh->flags & IconMaskHint) { 195 + wmh->flags |= IconMaskHint; 196 + wmh->icon_mask = cwmh->icon_mask; 197 + } 198 + XFree(cwmh); 199 + } else { 200 + XChangeProperty(dpy, win, wmatom[WMIcon], XA_CARDINAL, 32, 201 + PropModeReplace, (unsigned char *) icon, ICON_WIDTH * ICON_HEIGHT + 2); 202 + } 203 + XSetWMHints(dpy, win, wmh); 204 + XFree(wmh); 205 + XFree(data); 206 +} 207 + 208 void 209 usage(void) 210 {