sites

public wiki contents of suckless.org
git clone git://git.suckless.org/sites
Log | Files | Refs

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  {