sites

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

dwm-status2d-systray-6.4.diff (27308B)


      1 diff --git a/config.def.h b/config.def.h
      2 index 061ad66..a308a7e 100644
      3 --- a/config.def.h
      4 +++ b/config.def.h
      5 @@ -3,6 +3,11 @@
      6  /* appearance */
      7  static const unsigned int borderpx  = 1;        /* border pixel of windows */
      8  static const unsigned int snap      = 32;       /* snap pixel */
      9 +static const unsigned int systraypinning = 0;   /* 0: sloppy systray follows selected monitor, >0: pin systray to monitor X */
     10 +static const unsigned int systrayonleft  = 0;   /* 0: systray in the right corner, >0: systray on left of status text */
     11 +static const unsigned int systrayspacing = 2;   /* systray spacing */
     12 +static const int systraypinningfailfirst = 1;   /* 1: if pinning fails, display systray on the first monitor, False: display systray on the last monitor*/
     13 +static const int showsystray        = 1;        /* 0 means no systray */
     14  static const int showbar            = 1;        /* 0 means no bar */
     15  static const int topbar             = 1;        /* 0 means bottom bar */
     16  static const char *fonts[]          = { "monospace:size=10" };
     17 @@ -112,4 +117,3 @@ static const Button buttons[] = {
     18  	{ ClkTagBar,            MODKEY,         Button1,        tag,            {0} },
     19  	{ ClkTagBar,            MODKEY,         Button3,        toggletag,      {0} },
     20  };
     21 -
     22 diff --git a/dwm.c b/dwm.c
     23 index e5efb6a..79a46f5 100644
     24 --- a/dwm.c
     25 +++ b/dwm.c
     26 @@ -57,12 +57,27 @@
     27  #define TAGMASK                 ((1 << LENGTH(tags)) - 1)
     28  #define TEXTW(X)                (drw_fontset_getwidth(drw, (X)) + lrpad)
     29  
     30 +#define SYSTEM_TRAY_REQUEST_DOCK    0
     31 +/* XEMBED messages */
     32 +#define XEMBED_EMBEDDED_NOTIFY      0
     33 +#define XEMBED_WINDOW_ACTIVATE      1
     34 +#define XEMBED_FOCUS_IN             4
     35 +#define XEMBED_MODALITY_ON         10
     36 +#define XEMBED_MAPPED              (1 << 0)
     37 +#define XEMBED_WINDOW_ACTIVATE      1
     38 +#define XEMBED_WINDOW_DEACTIVATE    2
     39 +#define VERSION_MAJOR               0
     40 +#define VERSION_MINOR               0
     41 +#define XEMBED_EMBEDDED_VERSION (VERSION_MAJOR << 16) | VERSION_MINOR
     42 +
     43  /* enums */
     44  enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
     45  enum { SchemeNorm, SchemeSel }; /* color schemes */
     46  enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
     47 +       NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation, NetSystemTrayOrientationHorz,
     48         NetWMFullscreen, NetActiveWindow, NetWMWindowType,
     49         NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
     50 +enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */
     51  enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
     52  enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
     53         ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
     54 @@ -141,6 +156,12 @@ typedef struct {
     55  	int monitor;
     56  } Rule;
     57  
     58 +typedef struct Systray   Systray;
     59 +struct Systray {
     60 +	Window win;
     61 +	Client *icons;
     62 +};
     63 +
     64  /* function declarations */
     65  static void applyrules(Client *c);
     66  static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact);
     67 @@ -163,6 +184,7 @@ static void detachstack(Client *c);
     68  static Monitor *dirtomon(int dir);
     69  static void drawbar(Monitor *m);
     70  static void drawbars(void);
     71 +static int drawstatusbar(Monitor *m, int bh, char* text);
     72  static void enternotify(XEvent *e);
     73  static void expose(XEvent *e);
     74  static void focus(Client *c);
     75 @@ -172,6 +194,7 @@ static void focusstack(const Arg *arg);
     76  static Atom getatomprop(Client *c, Atom prop);
     77  static int getrootptr(int *x, int *y);
     78  static long getstate(Window w);
     79 +static unsigned int getsystraywidth();
     80  static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
     81  static void grabbuttons(Client *c, int focused);
     82  static void grabkeys(void);
     83 @@ -189,13 +212,16 @@ static void pop(Client *c);
     84  static void propertynotify(XEvent *e);
     85  static void quit(const Arg *arg);
     86  static Monitor *recttomon(int x, int y, int w, int h);
     87 +static void removesystrayicon(Client *i);
     88  static void resize(Client *c, int x, int y, int w, int h, int interact);
     89 +static void resizebarwin(Monitor *m);
     90  static void resizeclient(Client *c, int x, int y, int w, int h);
     91  static void resizemouse(const Arg *arg);
     92 +static void resizerequest(XEvent *e);
     93  static void restack(Monitor *m);
     94  static void run(void);
     95  static void scan(void);
     96 -static int sendevent(Client *c, Atom proto);
     97 +static int sendevent(Window w, Atom proto, int m, long d0, long d1, long d2, long d3, long d4);
     98  static void sendmon(Client *c, Monitor *m);
     99  static void setclientstate(Client *c, long state);
    100  static void setfocus(Client *c);
    101 @@ -207,6 +233,7 @@ static void seturgent(Client *c, int urg);
    102  static void showhide(Client *c);
    103  static void sigchld(int unused);
    104  static void spawn(const Arg *arg);
    105 +static Monitor *systraytomon(Monitor *m);
    106  static void tag(const Arg *arg);
    107  static void tagmon(const Arg *arg);
    108  static void tile(Monitor *m);
    109 @@ -224,20 +251,25 @@ static int updategeom(void);
    110  static void updatenumlockmask(void);
    111  static void updatesizehints(Client *c);
    112  static void updatestatus(void);
    113 +static void updatesystray(void);
    114 +static void updatesystrayicongeom(Client *i, int w, int h);
    115 +static void updatesystrayiconstate(Client *i, XPropertyEvent *ev);
    116  static void updatetitle(Client *c);
    117  static void updatewindowtype(Client *c);
    118  static void updatewmhints(Client *c);
    119  static void view(const Arg *arg);
    120  static Client *wintoclient(Window w);
    121  static Monitor *wintomon(Window w);
    122 +static Client *wintosystrayicon(Window w);
    123  static int xerror(Display *dpy, XErrorEvent *ee);
    124  static int xerrordummy(Display *dpy, XErrorEvent *ee);
    125  static int xerrorstart(Display *dpy, XErrorEvent *ee);
    126  static void zoom(const Arg *arg);
    127  
    128  /* variables */
    129 +static Systray *systray = NULL;
    130  static const char broken[] = "broken";
    131 -static char stext[256];
    132 +static char stext[1024];
    133  static int screen;
    134  static int sw, sh;           /* X display screen geometry width, height */
    135  static int bh;               /* bar height */
    136 @@ -258,9 +290,10 @@ static void (*handler[LASTEvent]) (XEvent *) = {
    137  	[MapRequest] = maprequest,
    138  	[MotionNotify] = motionnotify,
    139  	[PropertyNotify] = propertynotify,
    140 +    [ResizeRequest] = resizerequest,
    141  	[UnmapNotify] = unmapnotify
    142  };
    143 -static Atom wmatom[WMLast], netatom[NetLast];
    144 +static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast];
    145  static int running = 1;
    146  static Cur *cursor[CurLast];
    147  static Clr **scheme;
    148 @@ -442,7 +475,7 @@ buttonpress(XEvent *e)
    149  			arg.ui = 1 << i;
    150  		} else if (ev->x < x + TEXTW(selmon->ltsymbol))
    151  			click = ClkLtSymbol;
    152 -		else if (ev->x > selmon->ww - (int)TEXTW(stext))
    153 +		else if (ev->x > selmon->ww - (int)TEXTW(stext) - getsystraywidth())
    154  			click = ClkStatusText;
    155  		else
    156  			click = ClkWinTitle;
    157 @@ -485,9 +518,16 @@ cleanup(void)
    158  	XUngrabKey(dpy, AnyKey, AnyModifier, root);
    159  	while (mons)
    160  		cleanupmon(mons);
    161 -	for (i = 0; i < CurLast; i++)
    162 +
    163 +	if (showsystray) {
    164 +		XUnmapWindow(dpy, systray->win);
    165 +		XDestroyWindow(dpy, systray->win);
    166 +		free(systray);
    167 +	}
    168 +
    169 +    for (i = 0; i < CurLast; i++)
    170  		drw_cur_free(drw, cursor[i]);
    171 -	for (i = 0; i < LENGTH(colors); i++)
    172 +	for (i = 0; i < LENGTH(colors) + 1; i++)
    173  		free(scheme[i]);
    174  	free(scheme);
    175  	XDestroyWindow(dpy, wmcheckwin);
    176 @@ -516,9 +556,58 @@ cleanupmon(Monitor *mon)
    177  void
    178  clientmessage(XEvent *e)
    179  {
    180 +	XWindowAttributes wa;
    181 +	XSetWindowAttributes swa;
    182  	XClientMessageEvent *cme = &e->xclient;
    183  	Client *c = wintoclient(cme->window);
    184  
    185 +	if (showsystray && cme->window == systray->win && cme->message_type == netatom[NetSystemTrayOP]) {
    186 +		/* add systray icons */
    187 +		if (cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) {
    188 +			if (!(c = (Client *)calloc(1, sizeof(Client))))
    189 +				die("fatal: could not malloc() %u bytes\n", sizeof(Client));
    190 +			if (!(c->win = cme->data.l[2])) {
    191 +				free(c);
    192 +				return;
    193 +			}
    194 +			c->mon = selmon;
    195 +			c->next = systray->icons;
    196 +			systray->icons = c;
    197 +			if (!XGetWindowAttributes(dpy, c->win, &wa)) {
    198 +				/* use sane defaults */
    199 +				wa.width = bh;
    200 +				wa.height = bh;
    201 +				wa.border_width = 0;
    202 +			}
    203 +			c->x = c->oldx = c->y = c->oldy = 0;
    204 +			c->w = c->oldw = wa.width;
    205 +			c->h = c->oldh = wa.height;
    206 +			c->oldbw = wa.border_width;
    207 +			c->bw = 0;
    208 +			c->isfloating = True;
    209 +			/* reuse tags field as mapped status */
    210 +			c->tags = 1;
    211 +			updatesizehints(c);
    212 +			updatesystrayicongeom(c, wa.width, wa.height);
    213 +			XAddToSaveSet(dpy, c->win);
    214 +			XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask);
    215 +			XReparentWindow(dpy, c->win, systray->win, 0, 0);
    216 +			/* use parents background color */
    217 +			swa.background_pixel  = scheme[SchemeNorm][ColBg].pixel;
    218 +			XChangeWindowAttributes(dpy, c->win, CWBackPixel, &swa);
    219 +			sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
    220 +			/* FIXME not sure if I have to send these events, too */
    221 +			sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_FOCUS_IN, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
    222 +			sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
    223 +			sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_MODALITY_ON, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
    224 +			XSync(dpy, False);
    225 +			resizebarwin(selmon);
    226 +			updatesystray();
    227 +			setclientstate(c, NormalState);
    228 +		}
    229 +		return;
    230 +	}
    231 +
    232  	if (!c)
    233  		return;
    234  	if (cme->message_type == netatom[NetWMState]) {
    235 @@ -571,7 +660,7 @@ configurenotify(XEvent *e)
    236  				for (c = m->clients; c; c = c->next)
    237  					if (c->isfullscreen)
    238  						resizeclient(c, m->mx, m->my, m->mw, m->mh);
    239 -				XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
    240 +				resizebarwin(m);
    241  			}
    242  			focus(NULL);
    243  			arrange(NULL);
    244 @@ -656,6 +745,11 @@ destroynotify(XEvent *e)
    245  
    246  	if ((c = wintoclient(ev->window)))
    247  		unmanage(c, 1);
    248 +	else if ((c = wintosystrayicon(ev->window))) {
    249 +		removesystrayicon(c);
    250 +		resizebarwin(selmon);
    251 +		updatesystray();
    252 +	}
    253  }
    254  
    255  void
    256 @@ -696,10 +790,119 @@ dirtomon(int dir)
    257  	return m;
    258  }
    259  
    260 +int
    261 +drawstatusbar(Monitor *m, int bh, char* stext) {
    262 +	int ret, i, w, x, len;
    263 +	short isCode = 0;
    264 +	char *text;
    265 +	char *p;
    266 +
    267 +	len = strlen(stext) + 1 ;
    268 +	if (!(text = (char*) malloc(sizeof(char)*len)))
    269 +		die("malloc");
    270 +	p = text;
    271 +	memcpy(text, stext, len);
    272 +
    273 +	/* compute width of the status text */
    274 +	w = 0;
    275 +	i = -1;
    276 +	while (text[++i]) {
    277 +		if (text[i] == '^') {
    278 +			if (!isCode) {
    279 +				isCode = 1;
    280 +				text[i] = '\0';
    281 +				w += TEXTW(text) - lrpad;
    282 +				text[i] = '^';
    283 +				if (text[++i] == 'f')
    284 +					w += atoi(text + ++i);
    285 +			} else {
    286 +				isCode = 0;
    287 +				text = text + i + 1;
    288 +				i = -1;
    289 +			}
    290 +		}
    291 +	}
    292 +	if (!isCode)
    293 +		w += TEXTW(text) - lrpad;
    294 +	else
    295 +		isCode = 0;
    296 +	text = p;
    297 +
    298 +	w += 2; /* 1px padding on both sides */
    299 +	ret = m->ww - w;
    300 +	x = m->ww - w - getsystraywidth();
    301 +
    302 +	drw_setscheme(drw, scheme[LENGTH(colors)]);
    303 +	drw->scheme[ColFg] = scheme[SchemeNorm][ColFg];
    304 +	drw->scheme[ColBg] = scheme[SchemeNorm][ColBg];
    305 +	drw_rect(drw, x, 0, w, bh, 1, 1);
    306 +	x++;
    307 +
    308 +	/* process status text */
    309 +	i = -1;
    310 +	while (text[++i]) {
    311 +		if (text[i] == '^' && !isCode) {
    312 +			isCode = 1;
    313 +
    314 +			text[i] = '\0';
    315 +			w = TEXTW(text) - lrpad;
    316 +			drw_text(drw, x, 0, w, bh, 0, text, 0);
    317 +
    318 +			x += w;
    319 +
    320 +			/* process code */
    321 +			while (text[++i] != '^') {
    322 +				if (text[i] == 'c') {
    323 +					char buf[8];
    324 +					memcpy(buf, (char*)text+i+1, 7);
    325 +					buf[7] = '\0';
    326 +					drw_clr_create(drw, &drw->scheme[ColFg], buf);
    327 +					i += 7;
    328 +				} else if (text[i] == 'b') {
    329 +					char buf[8];
    330 +					memcpy(buf, (char*)text+i+1, 7);
    331 +					buf[7] = '\0';
    332 +					drw_clr_create(drw, &drw->scheme[ColBg], buf);
    333 +					i += 7;
    334 +				} else if (text[i] == 'd') {
    335 +					drw->scheme[ColFg] = scheme[SchemeNorm][ColFg];
    336 +					drw->scheme[ColBg] = scheme[SchemeNorm][ColBg];
    337 +				} else if (text[i] == 'r') {
    338 +					int rx = atoi(text + ++i);
    339 +					while (text[++i] != ',');
    340 +					int ry = atoi(text + ++i);
    341 +					while (text[++i] != ',');
    342 +					int rw = atoi(text + ++i);
    343 +					while (text[++i] != ',');
    344 +					int rh = atoi(text + ++i);
    345 +
    346 +					drw_rect(drw, rx + x, ry, rw, rh, 1, 0);
    347 +				} else if (text[i] == 'f') {
    348 +					x += atoi(text + ++i);
    349 +				}
    350 +			}
    351 +
    352 +			text = text + i + 1;
    353 +			i=-1;
    354 +			isCode = 0;
    355 +		}
    356 +	}
    357 +
    358 +	if (!isCode) {
    359 +		w = TEXTW(text) - lrpad;
    360 +		drw_text(drw, x, 0, w, bh, 0, text, 0);
    361 +	}
    362 +
    363 +	drw_setscheme(drw, scheme[SchemeNorm]);
    364 +	free(p);
    365 +
    366 +	return ret;
    367 +}
    368 +
    369  void
    370  drawbar(Monitor *m)
    371  {
    372 -	int x, w, tw = 0;
    373 +	int x, w, tw = 0, stw = 0;
    374  	int boxs = drw->fonts->h / 9;
    375  	int boxw = drw->fonts->h / 6 + 2;
    376  	unsigned int i, occ = 0, urg = 0;
    377 @@ -708,13 +911,15 @@ drawbar(Monitor *m)
    378  	if (!m->showbar)
    379  		return;
    380  
    381 +	if(showsystray && m == systraytomon(m) && !systrayonleft)
    382 +		stw = getsystraywidth();
    383 +
    384  	/* draw status first so it can be overdrawn by tags later */
    385  	if (m == selmon) { /* status is only drawn on selected monitor */
    386 -		drw_setscheme(drw, scheme[SchemeNorm]);
    387 -		tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */
    388 -		drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0);
    389 +		tw = m->ww - drawstatusbar(m, bh, stext);
    390  	}
    391  
    392 +	resizebarwin(m);
    393  	for (c = m->clients; c; c = c->next) {
    394  		occ |= c->tags;
    395  		if (c->isurgent)
    396 @@ -735,7 +940,7 @@ drawbar(Monitor *m)
    397  	drw_setscheme(drw, scheme[SchemeNorm]);
    398  	x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0);
    399  
    400 -	if ((w = m->ww - tw - x) > bh) {
    401 +	if ((w = m->ww - tw - stw - x) > bh) {
    402  		if (m->sel) {
    403  			drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]);
    404  			drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0);
    405 @@ -746,7 +951,7 @@ drawbar(Monitor *m)
    406  			drw_rect(drw, x, 0, w, bh, 1, 1);
    407  		}
    408  	}
    409 -	drw_map(drw, m->barwin, 0, 0, m->ww, bh);
    410 +	drw_map(drw, m->barwin, 0, 0, m->ww - stw, bh);
    411  }
    412  
    413  void
    414 @@ -783,8 +988,11 @@ expose(XEvent *e)
    415  	Monitor *m;
    416  	XExposeEvent *ev = &e->xexpose;
    417  
    418 -	if (ev->count == 0 && (m = wintomon(ev->window)))
    419 +	if (ev->count == 0 && (m = wintomon(ev->window))) {
    420  		drawbar(m);
    421 +		if (m == selmon)
    422 +			updatesystray();
    423 +	}
    424  }
    425  
    426  void
    427 @@ -870,9 +1078,17 @@ getatomprop(Client *c, Atom prop)
    428  	unsigned char *p = NULL;
    429  	Atom da, atom = None;
    430  
    431 -	if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM,
    432 +	/* FIXME getatomprop should return the number of items and a pointer to
    433 +	 * the stored data instead of this workaround */
    434 +	Atom req = XA_ATOM;
    435 +	if (prop == xatom[XembedInfo])
    436 +		req = xatom[XembedInfo];
    437 +
    438 +	if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, req,
    439  		&da, &di, &dl, &dl, &p) == Success && p) {
    440  		atom = *(Atom *)p;
    441 +		if (da == xatom[XembedInfo] && dl == 2)
    442 +			atom = ((Atom *)p)[1];
    443  		XFree(p);
    444  	}
    445  	return atom;
    446 @@ -906,6 +1122,16 @@ getstate(Window w)
    447  	return result;
    448  }
    449  
    450 +unsigned int
    451 +getsystraywidth()
    452 +{
    453 +	unsigned int w = 0;
    454 +	Client *i;
    455 +	if(showsystray)
    456 +		for(i = systray->icons; i; w += i->w + systrayspacing, i = i->next) ;
    457 +	return w ? w + systrayspacing : 1;
    458 +}
    459 +
    460  int
    461  gettextprop(Window w, Atom atom, char *text, unsigned int size)
    462  {
    463 @@ -1008,7 +1234,8 @@ killclient(const Arg *arg)
    464  {
    465  	if (!selmon->sel)
    466  		return;
    467 -	if (!sendevent(selmon->sel, wmatom[WMDelete])) {
    468 +
    469 +	if (!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0 , 0, 0)) {
    470  		XGrabServer(dpy);
    471  		XSetErrorHandler(xerrordummy);
    472  		XSetCloseDownMode(dpy, DestroyAll);
    473 @@ -1095,6 +1322,14 @@ maprequest(XEvent *e)
    474  	static XWindowAttributes wa;
    475  	XMapRequestEvent *ev = &e->xmaprequest;
    476  
    477 +	Client *i;
    478 +	if ((i = wintosystrayicon(ev->window))) {
    479 +		sendevent(i->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0, systray->win, XEMBED_EMBEDDED_VERSION);
    480 +		resizebarwin(selmon);
    481 +		updatesystray();
    482 +	}
    483 +
    484 +
    485  	if (!XGetWindowAttributes(dpy, ev->window, &wa) || wa.override_redirect)
    486  		return;
    487  	if (!wintoclient(ev->window))
    488 @@ -1216,7 +1451,18 @@ propertynotify(XEvent *e)
    489  	Window trans;
    490  	XPropertyEvent *ev = &e->xproperty;
    491  
    492 -	if ((ev->window == root) && (ev->atom == XA_WM_NAME))
    493 +	if ((c = wintosystrayicon(ev->window))) {
    494 +		if (ev->atom == XA_WM_NORMAL_HINTS) {
    495 +			updatesizehints(c);
    496 +			updatesystrayicongeom(c, c->w, c->h);
    497 +		}
    498 +		else
    499 +			updatesystrayiconstate(c, ev);
    500 +		resizebarwin(selmon);
    501 +		updatesystray();
    502 +	}
    503 +
    504 +    if ((ev->window == root) && (ev->atom == XA_WM_NAME))
    505  		updatestatus();
    506  	else if (ev->state == PropertyDelete)
    507  		return; /* ignore */
    508 @@ -1266,6 +1512,19 @@ recttomon(int x, int y, int w, int h)
    509  	return r;
    510  }
    511  
    512 +void
    513 +removesystrayicon(Client *i)
    514 +{
    515 +	Client **ii;
    516 +
    517 +	if (!showsystray || !i)
    518 +		return;
    519 +	for (ii = &systray->icons; *ii && *ii != i; ii = &(*ii)->next);
    520 +	if (ii)
    521 +		*ii = i->next;
    522 +	free(i);
    523 +}
    524 +
    525  void
    526  resize(Client *c, int x, int y, int w, int h, int interact)
    527  {
    528 @@ -1273,6 +1532,14 @@ resize(Client *c, int x, int y, int w, int h, int interact)
    529  		resizeclient(c, x, y, w, h);
    530  }
    531  
    532 +void
    533 +resizebarwin(Monitor *m) {
    534 +	unsigned int w = m->ww;
    535 +	if (showsystray && m == systraytomon(m) && !systrayonleft)
    536 +		w -= getsystraywidth();
    537 +	XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, w, bh);
    538 +}
    539 +
    540  void
    541  resizeclient(Client *c, int x, int y, int w, int h)
    542  {
    543 @@ -1345,6 +1612,19 @@ resizemouse(const Arg *arg)
    544  	}
    545  }
    546  
    547 +void
    548 +resizerequest(XEvent *e)
    549 +{
    550 +	XResizeRequestEvent *ev = &e->xresizerequest;
    551 +	Client *i;
    552 +
    553 +	if ((i = wintosystrayicon(ev->window))) {
    554 +		updatesystrayicongeom(i, ev->width, ev->height);
    555 +		resizebarwin(selmon);
    556 +		updatesystray();
    557 +	}
    558 +}
    559 +
    560  void
    561  restack(Monitor *m)
    562  {
    563 @@ -1434,26 +1714,37 @@ setclientstate(Client *c, long state)
    564  }
    565  
    566  int
    567 -sendevent(Client *c, Atom proto)
    568 +sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, long d3, long d4)
    569  {
    570  	int n;
    571 -	Atom *protocols;
    572 +	Atom *protocols, mt;
    573  	int exists = 0;
    574  	XEvent ev;
    575  
    576 -	if (XGetWMProtocols(dpy, c->win, &protocols, &n)) {
    577 -		while (!exists && n--)
    578 -			exists = protocols[n] == proto;
    579 -		XFree(protocols);
    580 +	if (proto == wmatom[WMTakeFocus] || proto == wmatom[WMDelete]) {
    581 +		mt = wmatom[WMProtocols];
    582 +		if (XGetWMProtocols(dpy, w, &protocols, &n)) {
    583 +			while (!exists && n--)
    584 +				exists = protocols[n] == proto;
    585 +			XFree(protocols);
    586 +		}
    587  	}
    588 +	else {
    589 +		exists = True;
    590 +		mt = proto;
    591 +    }
    592 +
    593  	if (exists) {
    594  		ev.type = ClientMessage;
    595 -		ev.xclient.window = c->win;
    596 -		ev.xclient.message_type = wmatom[WMProtocols];
    597 +		ev.xclient.window = w;
    598 +		ev.xclient.message_type = mt;
    599  		ev.xclient.format = 32;
    600 -		ev.xclient.data.l[0] = proto;
    601 -		ev.xclient.data.l[1] = CurrentTime;
    602 -		XSendEvent(dpy, c->win, False, NoEventMask, &ev);
    603 +		ev.xclient.data.l[0] = d0;
    604 +		ev.xclient.data.l[1] = d1;
    605 +		ev.xclient.data.l[2] = d2;
    606 +		ev.xclient.data.l[3] = d3;
    607 +		ev.xclient.data.l[4] = d4;
    608 +		XSendEvent(dpy, w, False, mask, &ev);
    609  	}
    610  	return exists;
    611  }
    612 @@ -1467,7 +1758,7 @@ setfocus(Client *c)
    613  			XA_WINDOW, 32, PropModeReplace,
    614  			(unsigned char *) &(c->win), 1);
    615  	}
    616 -	sendevent(c, wmatom[WMTakeFocus]);
    617 +	sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0);
    618  }
    619  
    620  void
    621 @@ -1555,22 +1846,32 @@ setup(void)
    622  	wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False);
    623  	wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False);
    624  	netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False);
    625 -	netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
    626 -	netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
    627 +   netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
    628 +	netatom[NetSystemTray] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_S0", False);
    629 +	netatom[NetSystemTrayOP] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE", False);
    630 +	netatom[NetSystemTrayOrientation] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION", False);
    631 +	netatom[NetSystemTrayOrientationHorz] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION_HORZ", False);
    632 +    netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
    633  	netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False);
    634  	netatom[NetWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False);
    635  	netatom[NetWMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
    636  	netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
    637  	netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
    638  	netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False);
    639 -	/* init cursors */
    640 +	xatom[Manager] = XInternAtom(dpy, "MANAGER", False);
    641 +	xatom[Xembed] = XInternAtom(dpy, "_XEMBED", False);
    642 +	xatom[XembedInfo] = XInternAtom(dpy, "_XEMBED_INFO", False);
    643 +    /* init cursors */
    644  	cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr);
    645  	cursor[CurResize] = drw_cur_create(drw, XC_sizing);
    646  	cursor[CurMove] = drw_cur_create(drw, XC_fleur);
    647  	/* init appearance */
    648 -	scheme = ecalloc(LENGTH(colors), sizeof(Clr *));
    649 +	scheme = ecalloc(LENGTH(colors) + 1, sizeof(Clr *));
    650 +	scheme[LENGTH(colors)] = drw_scm_create(drw, colors[0], 3);
    651  	for (i = 0; i < LENGTH(colors); i++)
    652  		scheme[i] = drw_scm_create(drw, colors[i], 3);
    653 +	/* init system tray */
    654 +	updatesystray();
    655  	/* init bars */
    656  	updatebars();
    657  	updatestatus();
    658 @@ -1699,7 +2000,18 @@ togglebar(const Arg *arg)
    659  {
    660  	selmon->showbar = !selmon->showbar;
    661  	updatebarpos(selmon);
    662 -	XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
    663 +	resizebarwin(selmon);
    664 +	if (showsystray) {
    665 +		XWindowChanges wc;
    666 +		if (!selmon->showbar)
    667 +			wc.y = -bh;
    668 +		else if (selmon->showbar) {
    669 +			wc.y = 0;
    670 +			if (!selmon->topbar)
    671 +				wc.y = selmon->mh - bh;
    672 +		}
    673 +		XConfigureWindow(dpy, systray->win, CWY, &wc);
    674 +	}
    675  	arrange(selmon);
    676  }
    677  
    678 @@ -1795,11 +2107,18 @@ unmapnotify(XEvent *e)
    679  		else
    680  			unmanage(c, 0);
    681  	}
    682 +	else if ((c = wintosystrayicon(ev->window))) {
    683 +		/* KLUDGE! sometimes icons occasionally unmap their windows, but do
    684 +		 * _not_ destroy them. We map those windows back */
    685 +		XMapRaised(dpy, c->win);
    686 +		updatesystray();
    687 +	}
    688  }
    689  
    690  void
    691  updatebars(void)
    692  {
    693 +	unsigned int w;
    694  	Monitor *m;
    695  	XSetWindowAttributes wa = {
    696  		.override_redirect = True,
    697 @@ -1810,10 +2129,15 @@ updatebars(void)
    698  	for (m = mons; m; m = m->next) {
    699  		if (m->barwin)
    700  			continue;
    701 -		m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen),
    702 +		w = m->ww;
    703 +		if (showsystray && m == systraytomon(m))
    704 +			w -= getsystraywidth();
    705 +		m->barwin = XCreateWindow(dpy, root, m->wx, m->by, w, bh, 0, DefaultDepth(dpy, screen),
    706  				CopyFromParent, DefaultVisual(dpy, screen),
    707  				CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
    708  		XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor);
    709 +		if (showsystray && m == systraytomon(m))
    710 +			XMapRaised(dpy, systray->win);
    711  		XMapRaised(dpy, m->barwin);
    712  		XSetClassHint(dpy, m->barwin, &ch);
    713  	}
    714 @@ -1990,6 +2314,125 @@ updatestatus(void)
    715  	if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext)))
    716  		strcpy(stext, "dwm-"VERSION);
    717  	drawbar(selmon);
    718 +	updatesystray();
    719 +}
    720 +
    721 +
    722 +void
    723 +updatesystrayicongeom(Client *i, int w, int h)
    724 +{
    725 +	if (i) {
    726 +		i->h = bh;
    727 +		if (w == h)
    728 +			i->w = bh;
    729 +		else if (h == bh)
    730 +			i->w = w;
    731 +		else
    732 +			i->w = (int) ((float)bh * ((float)w / (float)h));
    733 +		applysizehints(i, &(i->x), &(i->y), &(i->w), &(i->h), False);
    734 +		/* force icons into the systray dimensions if they don't want to */
    735 +		if (i->h > bh) {
    736 +			if (i->w == i->h)
    737 +				i->w = bh;
    738 +			else
    739 +				i->w = (int) ((float)bh * ((float)i->w / (float)i->h));
    740 +			i->h = bh;
    741 +		}
    742 +	}
    743 +}
    744 +
    745 +void
    746 +updatesystrayiconstate(Client *i, XPropertyEvent *ev)
    747 +{
    748 +	long flags;
    749 +	int code = 0;
    750 +
    751 +	if (!showsystray || !i || ev->atom != xatom[XembedInfo] ||
    752 +			!(flags = getatomprop(i, xatom[XembedInfo])))
    753 +		return;
    754 +
    755 +	if (flags & XEMBED_MAPPED && !i->tags) {
    756 +		i->tags = 1;
    757 +		code = XEMBED_WINDOW_ACTIVATE;
    758 +		XMapRaised(dpy, i->win);
    759 +		setclientstate(i, NormalState);
    760 +	}
    761 +	else if (!(flags & XEMBED_MAPPED) && i->tags) {
    762 +		i->tags = 0;
    763 +		code = XEMBED_WINDOW_DEACTIVATE;
    764 +		XUnmapWindow(dpy, i->win);
    765 +		setclientstate(i, WithdrawnState);
    766 +	}
    767 +	else
    768 +		return;
    769 +	sendevent(i->win, xatom[Xembed], StructureNotifyMask, CurrentTime, code, 0,
    770 +			systray->win, XEMBED_EMBEDDED_VERSION);
    771 +}
    772 +
    773 +void
    774 +updatesystray(void)
    775 +{
    776 +	XSetWindowAttributes wa;
    777 +	XWindowChanges wc;
    778 +	Client *i;
    779 +	Monitor *m = systraytomon(NULL);
    780 +	unsigned int x = m->mx + m->mw;
    781 +	unsigned int sw = TEXTW(stext) - lrpad + systrayspacing;
    782 +	unsigned int w = 1;
    783 +
    784 +	if (!showsystray)
    785 +		return;
    786 +	if (systrayonleft)
    787 +		x -= sw + lrpad / 2;
    788 +	if (!systray) {
    789 +		/* init systray */
    790 +		if (!(systray = (Systray *)calloc(1, sizeof(Systray))))
    791 +			die("fatal: could not malloc() %u bytes\n", sizeof(Systray));
    792 +		systray->win = XCreateSimpleWindow(dpy, root, x, m->by, w, bh, 0, 0, scheme[SchemeSel][ColBg].pixel);
    793 +		wa.event_mask        = ButtonPressMask | ExposureMask;
    794 +		wa.override_redirect = True;
    795 +		wa.background_pixel  = scheme[SchemeNorm][ColBg].pixel;
    796 +		XSelectInput(dpy, systray->win, SubstructureNotifyMask);
    797 +		XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32,
    798 +				PropModeReplace, (unsigned char *)&netatom[NetSystemTrayOrientationHorz], 1);
    799 +		XChangeWindowAttributes(dpy, systray->win, CWEventMask|CWOverrideRedirect|CWBackPixel, &wa);
    800 +		XMapRaised(dpy, systray->win);
    801 +		XSetSelectionOwner(dpy, netatom[NetSystemTray], systray->win, CurrentTime);
    802 +		if (XGetSelectionOwner(dpy, netatom[NetSystemTray]) == systray->win) {
    803 +			sendevent(root, xatom[Manager], StructureNotifyMask, CurrentTime, netatom[NetSystemTray], systray->win, 0, 0);
    804 +			XSync(dpy, False);
    805 +		}
    806 +		else {
    807 +			fprintf(stderr, "dwm: unable to obtain system tray.\n");
    808 +			free(systray);
    809 +			systray = NULL;
    810 +			return;
    811 +		}
    812 +	}
    813 +	for (w = 0, i = systray->icons; i; i = i->next) {
    814 +		/* make sure the background color stays the same */
    815 +		wa.background_pixel  = scheme[SchemeNorm][ColBg].pixel;
    816 +		XChangeWindowAttributes(dpy, i->win, CWBackPixel, &wa);
    817 +		XMapRaised(dpy, i->win);
    818 +		w += systrayspacing;
    819 +		i->x = w;
    820 +		XMoveResizeWindow(dpy, i->win, i->x, 0, i->w, i->h);
    821 +		w += i->w;
    822 +		if (i->mon != m)
    823 +			i->mon = m;
    824 +	}
    825 +	w = w ? w + systrayspacing : 1;
    826 +	x -= w;
    827 +	XMoveResizeWindow(dpy, systray->win, x, m->by, w, bh);
    828 +	wc.x = x; wc.y = m->by; wc.width = w; wc.height = bh;
    829 +	wc.stack_mode = Above; wc.sibling = m->barwin;
    830 +	XConfigureWindow(dpy, systray->win, CWX|CWY|CWWidth|CWHeight|CWSibling|CWStackMode, &wc);
    831 +	XMapWindow(dpy, systray->win);
    832 +	XMapSubwindows(dpy, systray->win);
    833 +	/* redraw background */
    834 +	XSetForeground(dpy, drw->gc, scheme[SchemeNorm][ColBg].pixel);
    835 +	XFillRectangle(dpy, systray->win, drw->gc, 0, 0, w, bh);
    836 +	XSync(dpy, False);
    837  }
    838  
    839  void
    840 @@ -2057,6 +2500,16 @@ wintoclient(Window w)
    841  	return NULL;
    842  }
    843  
    844 +Client *
    845 +wintosystrayicon(Window w) {
    846 +	Client *i = NULL;
    847 +
    848 +	if (!showsystray || !w)
    849 +		return i;
    850 +	for (i = systray->icons; i && i->win != w; i = i->next) ;
    851 +	return i;
    852 +}
    853 +
    854  Monitor *
    855  wintomon(Window w)
    856  {
    857 @@ -2110,6 +2563,22 @@ xerrorstart(Display *dpy, XErrorEvent *ee)
    858  	return -1;
    859  }
    860  
    861 +Monitor *
    862 +systraytomon(Monitor *m) {
    863 +	Monitor *t;
    864 +	int i, n;
    865 +	if(!systraypinning) {
    866 +		if(!m)
    867 +			return selmon;
    868 +		return m == selmon ? m : NULL;
    869 +	}
    870 +	for(n = 1, t = mons; t && t->next; n++, t = t->next) ;
    871 +	for(i = 1, t = mons; t && t->next && i < systraypinning; i++, t = t->next) ;
    872 +	if(systraypinningfailfirst && n < systraypinning)
    873 +		return mons;
    874 +	return t;
    875 +}
    876 +
    877  void
    878  zoom(const Arg *arg)
    879  {