diff options
Diffstat (limited to 'dwm.c')
| -rw-r--r-- | dwm.c | 421 | 
1 files changed, 390 insertions, 31 deletions
| @@ -79,12 +79,27 @@                                    } \                                  } +#define SYSTEM_TRAY_REQUEST_DOCK    0 +/* XEMBED messages */ +#define XEMBED_EMBEDDED_NOTIFY      0 +#define XEMBED_WINDOW_ACTIVATE      1 +#define XEMBED_FOCUS_IN             4 +#define XEMBED_MODALITY_ON         10 +#define XEMBED_MAPPED              (1 << 0) +#define XEMBED_WINDOW_ACTIVATE      1 +#define XEMBED_WINDOW_DEACTIVATE    2 +#define VERSION_MAJOR               0 +#define VERSION_MINOR               0 +#define XEMBED_EMBEDDED_VERSION (VERSION_MAJOR << 16) | VERSION_MINOR +  /* enums */  enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */  enum { SchemeNorm, SchemeSel }; /* color schemes */  enum { NetSupported, NetWMName, NetWMState, NetWMCheck, +       NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation, NetSystemTrayOrientationHorz,         NetWMFullscreen, NetActiveWindow, NetWMWindowType,         NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ +enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */  enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */  enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,         ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ @@ -168,6 +183,12 @@ typedef struct {  	int monitor;  } Rule; +typedef struct Systray   Systray; +struct Systray { +	Window win; +	Client *icons; +}; +  /* function declarations */  static void applyrules(Client *c);  static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact); @@ -200,6 +221,7 @@ static void focusstack(const Arg *arg);  static Atom getatomprop(Client *c, Atom prop);  static int getrootptr(int *x, int *y);  static long getstate(Window w); +static unsigned int getsystraywidth();  static int gettextprop(Window w, Atom atom, char *text, unsigned int size);  static void grabbuttons(Client *c, int focused);  static void grabkeys(void); @@ -218,13 +240,16 @@ static void pop(Client *c);  static void propertynotify(XEvent *e);  static void quit(const Arg *arg);  static Monitor *recttomon(int x, int y, int w, int h); +static void removesystrayicon(Client *i);  static void resize(Client *c, int x, int y, int w, int h, int interact); +static void resizebarwin(Monitor *m);  static void resizeclient(Client *c, int x, int y, int w, int h);  static void resizemouse(const Arg *arg); +static void resizerequest(XEvent *e);  static void restack(Monitor *m);  static void run(void);  static void scan(void); -static int sendevent(Client *c, Atom proto); +static int sendevent(Window w, Atom proto, int m, long d0, long d1, long d2, long d3, long d4);  static void sendmon(Client *c, Monitor *m);  static void setclientstate(Client *c, long state);  static void setfocus(Client *c); @@ -239,6 +264,7 @@ static void sigchld(int unused);  static void sighup(int unused);  static void sigterm(int unused);  static void spawn(const Arg *arg); +static Monitor *systraytomon(Monitor *m);  static void tag(const Arg *arg);  static void tagmon(const Arg *arg);  static void tile(Monitor *m); @@ -256,12 +282,16 @@ static int updategeom(void);  static void updatenumlockmask(void);  static void updatesizehints(Client *c);  static void updatestatus(void); +static void updatesystray(void); +static void updatesystrayicongeom(Client *i, int w, int h); +static void updatesystrayiconstate(Client *i, XPropertyEvent *ev);  static void updatetitle(Client *c);  static void updatewindowtype(Client *c);  static void updatewmhints(Client *c);  static void view(const Arg *arg);  static Client *wintoclient(Window w);  static Monitor *wintomon(Window w); +static Client *wintosystrayicon(Window w);  static int xerror(Display *dpy, XErrorEvent *ee);  static int xerrordummy(Display *dpy, XErrorEvent *ee);  static int xerrorstart(Display *dpy, XErrorEvent *ee); @@ -275,6 +305,7 @@ static Client *termforwin(const Client *c);  static pid_t winpid(Window w);  /* variables */ +static Systray *systray = NULL;  static const char broken[] = "broken";  static char stext[256];  static int screen; @@ -297,9 +328,11 @@ static void (*handler[LASTEvent]) (XEvent *) = {  	[MapRequest] = maprequest,  	[MotionNotify] = motionnotify,  	[PropertyNotify] = propertynotify, +        [ResizeRequest] = resizerequest,  	[UnmapNotify] = unmapnotify  };  static Atom wmatom[WMLast], netatom[NetLast]; +static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast];  static int restart = 0;  static int running = 1;  static Cur *cursor[CurLast]; @@ -542,7 +575,7 @@ buttonpress(XEvent *e)  			arg.ui = 1 << i;  		} else if (ev->x < x + TEXTW(selmon->ltsymbol))  			click = ClkLtSymbol; -		else if (ev->x > selmon->ww - (int)TEXTW(stext)) +		else if (ev->x > selmon->ww - (int)TEXTW(stext) - getsystraywidth())  			click = ClkStatusText;  		else  			click = ClkWinTitle; @@ -585,7 +618,14 @@ cleanup(void)  	XUngrabKey(dpy, AnyKey, AnyModifier, root);  	while (mons)  		cleanupmon(mons); -	for (i = 0; i < CurLast; i++) + +	if (showsystray) { +		XUnmapWindow(dpy, systray->win); +		XDestroyWindow(dpy, systray->win); +		free(systray); +	} + +    for (i = 0; i < CurLast; i++)  		drw_cur_free(drw, cursor[i]);  	for (i = 0; i < LENGTH(colors); i++)  		free(scheme[i]); @@ -616,9 +656,58 @@ cleanupmon(Monitor *mon)  void  clientmessage(XEvent *e)  { +	XWindowAttributes wa; +	XSetWindowAttributes swa;  	XClientMessageEvent *cme = &e->xclient;  	Client *c = wintoclient(cme->window); +	if (showsystray && cme->window == systray->win && cme->message_type == netatom[NetSystemTrayOP]) { +		/* add systray icons */ +		if (cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) { +			if (!(c = (Client *)calloc(1, sizeof(Client)))) +				die("fatal: could not malloc() %u bytes\n", sizeof(Client)); +			if (!(c->win = cme->data.l[2])) { +				free(c); +				return; +			} +			c->mon = selmon; +			c->next = systray->icons; +			systray->icons = c; +			if (!XGetWindowAttributes(dpy, c->win, &wa)) { +				/* use sane defaults */ +				wa.width = bh; +				wa.height = bh; +				wa.border_width = 0; +			} +			c->x = c->oldx = c->y = c->oldy = 0; +			c->w = c->oldw = wa.width; +			c->h = c->oldh = wa.height; +			c->oldbw = wa.border_width; +			c->bw = 0; +			c->isfloating = True; +			/* reuse tags field as mapped status */ +			c->tags = 1; +			updatesizehints(c); +			updatesystrayicongeom(c, wa.width, wa.height); +			XAddToSaveSet(dpy, c->win); +			XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask); +			XReparentWindow(dpy, c->win, systray->win, 0, 0); +			/* use parents background color */ +			swa.background_pixel  = scheme[SchemeNorm][ColBg].pixel; +			XChangeWindowAttributes(dpy, c->win, CWBackPixel, &swa); +			sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0 , systray->win, XEMBED_EMBEDDED_VERSION); +			/* FIXME not sure if I have to send these events, too */ +			sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_FOCUS_IN, 0 , systray->win, XEMBED_EMBEDDED_VERSION); +			sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0 , systray->win, XEMBED_EMBEDDED_VERSION); +			sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_MODALITY_ON, 0 , systray->win, XEMBED_EMBEDDED_VERSION); +			XSync(dpy, False); +			resizebarwin(selmon); +			updatesystray(); +			setclientstate(c, NormalState); +		} +		return; +	} +  	if (!c)  		return;  	if (cme->message_type == netatom[NetWMState]) { @@ -671,7 +760,7 @@ configurenotify(XEvent *e)  				for (c = m->clients; c; c = c->next)  					if (c->isfullscreen)  						resizeclient(c, m->mx, m->my, m->mw, m->mh); -				XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh); +				resizebarwin(m);  			}  			focus(NULL);  			arrange(NULL); @@ -757,7 +846,11 @@ destroynotify(XEvent *e)  	if ((c = wintoclient(ev->window)))  		unmanage(c, 1); - +	else if ((c = wintosystrayicon(ev->window))) { +		removesystrayicon(c); +		resizebarwin(selmon); +		updatesystray(); +	}  	else if ((c = swallowingclient(ev->window)))  		unmanage(c->swallowing, 1);  } @@ -803,7 +896,7 @@ dirtomon(int dir)  void  drawbar(Monitor *m)  { -	int x, w, tw = 0; +	int x, w, tw = 0, stw = 0;  	int boxs = drw->fonts->h / 9;  	int boxw = drw->fonts->h / 6 + 2;  	unsigned int i, occ = 0, urg = 0; @@ -812,13 +905,17 @@ drawbar(Monitor *m)  	if (!m->showbar)  		return; +	if(showsystray && m == systraytomon(m) && !systrayonleft) +		stw = getsystraywidth(); +  	/* draw status first so it can be overdrawn by tags later */  	if (m == selmon) { /* status is only drawn on selected monitor */  		drw_setscheme(drw, scheme[SchemeNorm]); -		tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */ -		drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0); +		tw = TEXTW(stext) - lrpad / 2 + 2; /* 2px extra right padding */ +		drw_text(drw, m->ww - tw - stw, 0, tw, bh, lrpad / 2 - 2, stext, 0);  	} +	resizebarwin(m);  	for (c = m->clients; c; c = c->next) {  		occ |= c->tags;  		if (c->isurgent) @@ -839,7 +936,7 @@ drawbar(Monitor *m)  	drw_setscheme(drw, scheme[SchemeNorm]);  	x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); -	if ((w = m->ww - tw - x) > bh) { +	if ((w = m->ww - tw - stw - x) > bh) {  		if (m->sel) {  			drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]);  			drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0); @@ -850,7 +947,7 @@ drawbar(Monitor *m)  			drw_rect(drw, x, 0, w, bh, 1, 1);  		}  	} -	drw_map(drw, m->barwin, 0, 0, m->ww, bh); +	drw_map(drw, m->barwin, 0, 0, m->ww - stw, bh);  }  void @@ -887,8 +984,11 @@ expose(XEvent *e)  	Monitor *m;  	XExposeEvent *ev = &e->xexpose; -	if (ev->count == 0 && (m = wintomon(ev->window))) +	if (ev->count == 0 && (m = wintomon(ev->window))) {  		drawbar(m); +		if (m == selmon) +			updatesystray(); +	}  }  void @@ -974,9 +1074,17 @@ getatomprop(Client *c, Atom prop)  	unsigned char *p = NULL;  	Atom da, atom = None; -	if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM, +	/* FIXME getatomprop should return the number of items and a pointer to +	 * the stored data instead of this workaround */ +	Atom req = XA_ATOM; +	if (prop == xatom[XembedInfo]) +		req = xatom[XembedInfo]; + +	if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, req,  		&da, &di, &dl, &dl, &p) == Success && p) {  		atom = *(Atom *)p; +		if (da == xatom[XembedInfo] && dl == 2) +			atom = ((Atom *)p)[1];  		XFree(p);  	}  	return atom; @@ -1010,6 +1118,16 @@ getstate(Window w)  	return result;  } +unsigned int +getsystraywidth() +{ +	unsigned int w = 0; +	Client *i; +	if(showsystray) +		for(i = systray->icons; i; w += i->w + systrayspacing, i = i->next) ; +	return w ? w + systrayspacing : 1; +} +  int  gettextprop(Window w, Atom atom, char *text, unsigned int size)  { @@ -1112,7 +1230,8 @@ killclient(const Arg *arg)  {  	if (!selmon->sel)  		return; -	if (!sendevent(selmon->sel, wmatom[WMDelete])) { + +	if (!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0 , 0, 0)) {  		XGrabServer(dpy);  		XSetErrorHandler(xerrordummy);  		XSetCloseDownMode(dpy, DestroyAll); @@ -1245,6 +1364,13 @@ maprequest(XEvent *e)  	static XWindowAttributes wa;  	XMapRequestEvent *ev = &e->xmaprequest; +	Client *i; +	if ((i = wintosystrayicon(ev->window))) { +		sendevent(i->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0, systray->win, XEMBED_EMBEDDED_VERSION); +		resizebarwin(selmon); +		updatesystray(); +	} +  	if (!XGetWindowAttributes(dpy, ev->window, &wa) || wa.override_redirect)  		return;  	if (!wintoclient(ev->window)) @@ -1366,7 +1492,18 @@ propertynotify(XEvent *e)  	Window trans;  	XPropertyEvent *ev = &e->xproperty; -	if ((ev->window == root) && (ev->atom == XA_WM_NAME)) +	if ((c = wintosystrayicon(ev->window))) { +		if (ev->atom == XA_WM_NORMAL_HINTS) { +			updatesizehints(c); +			updatesystrayicongeom(c, c->w, c->h); +		} +		else +			updatesystrayiconstate(c, ev); +		resizebarwin(selmon); +		updatesystray(); +	} + +    if ((ev->window == root) && (ev->atom == XA_WM_NAME))  		updatestatus();  	else if (ev->state == PropertyDelete)  		return; /* ignore */ @@ -1418,6 +1555,19 @@ recttomon(int x, int y, int w, int h)  }  void +removesystrayicon(Client *i) +{ +	Client **ii; + +	if (!showsystray || !i) +		return; +	for (ii = &systray->icons; *ii && *ii != i; ii = &(*ii)->next); +	if (ii) +		*ii = i->next; +	free(i); +} + +void  resize(Client *c, int x, int y, int w, int h, int interact)  {  	if (applysizehints(c, &x, &y, &w, &h, interact)) @@ -1425,6 +1575,14 @@ resize(Client *c, int x, int y, int w, int h, int interact)  }  void +resizebarwin(Monitor *m) { +	unsigned int w = m->ww; +	if (showsystray && m == systraytomon(m) && !systrayonleft) +		w -= getsystraywidth(); +	XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, w, bh); +} + +void  resizeclient(Client *c, int x, int y, int w, int h)  {  	XWindowChanges wc; @@ -1497,6 +1655,19 @@ resizemouse(const Arg *arg)  }  void +resizerequest(XEvent *e) +{ +	XResizeRequestEvent *ev = &e->xresizerequest; +	Client *i; + +	if ((i = wintosystrayicon(ev->window))) { +		updatesystrayicongeom(i, ev->width, ev->height); +		resizebarwin(selmon); +		updatesystray(); +	} +} + +void  restack(Monitor *m)  {  	Client *c; @@ -1585,26 +1756,37 @@ setclientstate(Client *c, long state)  }  int -sendevent(Client *c, Atom proto) +sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, long d3, long d4)  {  	int n; -	Atom *protocols; +	Atom *protocols, mt;  	int exists = 0;  	XEvent ev; -	if (XGetWMProtocols(dpy, c->win, &protocols, &n)) { -		while (!exists && n--) -			exists = protocols[n] == proto; -		XFree(protocols); +	if (proto == wmatom[WMTakeFocus] || proto == wmatom[WMDelete]) { +		mt = wmatom[WMProtocols]; +		if (XGetWMProtocols(dpy, w, &protocols, &n)) { +			while (!exists && n--) +				exists = protocols[n] == proto; +			XFree(protocols); +		}  	} +	else { +		exists = True; +		mt = proto; +    } +  	if (exists) {  		ev.type = ClientMessage; -		ev.xclient.window = c->win; -		ev.xclient.message_type = wmatom[WMProtocols]; +		ev.xclient.window = w; +		ev.xclient.message_type = mt;  		ev.xclient.format = 32; -		ev.xclient.data.l[0] = proto; -		ev.xclient.data.l[1] = CurrentTime; -		XSendEvent(dpy, c->win, False, NoEventMask, &ev); +		ev.xclient.data.l[0] = d0; +		ev.xclient.data.l[1] = d1; +		ev.xclient.data.l[2] = d2; +		ev.xclient.data.l[3] = d3; +		ev.xclient.data.l[4] = d4; +		XSendEvent(dpy, w, False, mask, &ev);  	}  	return exists;  } @@ -1618,7 +1800,7 @@ setfocus(Client *c)  			XA_WINDOW, 32, PropModeReplace,  			(unsigned char *) &(c->win), 1);  	} -	sendevent(c, wmatom[WMTakeFocus]); +	sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0);  }  void @@ -1719,15 +1901,22 @@ setup(void)  	wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False);  	wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False);  	netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); -	netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); -	netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False); +   netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); +	netatom[NetSystemTray] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_S0", False); +	netatom[NetSystemTrayOP] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE", False); +	netatom[NetSystemTrayOrientation] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION", False); +	netatom[NetSystemTrayOrientationHorz] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION_HORZ", False); +    netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);  	netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False);  	netatom[NetWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False);  	netatom[NetWMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);  	netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);  	netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);  	netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False); -	/* init cursors */ +	xatom[Manager] = XInternAtom(dpy, "MANAGER", False); +	xatom[Xembed] = XInternAtom(dpy, "_XEMBED", False); +	xatom[XembedInfo] = XInternAtom(dpy, "_XEMBED_INFO", False); +    /* init cursors */  	cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr);  	cursor[CurResize] = drw_cur_create(drw, XC_sizing);  	cursor[CurMove] = drw_cur_create(drw, XC_fleur); @@ -1735,6 +1924,8 @@ setup(void)  	scheme = ecalloc(LENGTH(colors), sizeof(Clr *));  	for (i = 0; i < LENGTH(colors); i++)  		scheme[i] = drw_scm_create(drw, colors[i], 3); +	/* init system tray */ +	updatesystray();  	/* init bars */  	updatebars();  	updatestatus(); @@ -1875,7 +2066,18 @@ togglebar(const Arg *arg)  {  	selmon->showbar = !selmon->showbar;  	updatebarpos(selmon); -	XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); +	resizebarwin(selmon); +	if (showsystray) { +		XWindowChanges wc; +		if (!selmon->showbar) +			wc.y = -bh; +		else if (selmon->showbar) { +			wc.y = 0; +			if (!selmon->topbar) +				wc.y = selmon->mh - bh; +		} +		XConfigureWindow(dpy, systray->win, CWY, &wc); +	}  	arrange(selmon);  } @@ -1988,11 +2190,18 @@ unmapnotify(XEvent *e)  		else  			unmanage(c, 0);  	} +	else if ((c = wintosystrayicon(ev->window))) { +		/* KLUDGE! sometimes icons occasionally unmap their windows, but do +		 * _not_ destroy them. We map those windows back */ +		XMapRaised(dpy, c->win); +		updatesystray(); +	}  }  void  updatebars(void)  { +	unsigned int w;  	Monitor *m;  	XSetWindowAttributes wa = {  		.override_redirect = True, @@ -2003,10 +2212,15 @@ updatebars(void)  	for (m = mons; m; m = m->next) {  		if (m->barwin)  			continue; -		m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen), +		w = m->ww; +		if (showsystray && m == systraytomon(m)) +			w -= getsystraywidth(); +		m->barwin = XCreateWindow(dpy, root, m->wx, m->by, w, bh, 0, DefaultDepth(dpy, screen),  				CopyFromParent, DefaultVisual(dpy, screen),  				CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);  		XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor); +		if (showsystray && m == systraytomon(m)) +			XMapRaised(dpy, systray->win);  		XMapRaised(dpy, m->barwin);  		XSetClassHint(dpy, m->barwin, &ch);  	} @@ -2183,6 +2397,125 @@ updatestatus(void)  	if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext)))  		strcpy(stext, "dwm-"VERSION);  	drawbar(selmon); +	updatesystray(); +} + + +void +updatesystrayicongeom(Client *i, int w, int h) +{ +	if (i) { +		i->h = bh; +		if (w == h) +			i->w = bh; +		else if (h == bh) +			i->w = w; +		else +			i->w = (int) ((float)bh * ((float)w / (float)h)); +		applysizehints(i, &(i->x), &(i->y), &(i->w), &(i->h), False); +		/* force icons into the systray dimensions if they don't want to */ +		if (i->h > bh) { +			if (i->w == i->h) +				i->w = bh; +			else +				i->w = (int) ((float)bh * ((float)i->w / (float)i->h)); +			i->h = bh; +		} +	} +} + +void +updatesystrayiconstate(Client *i, XPropertyEvent *ev) +{ +	long flags; +	int code = 0; + +	if (!showsystray || !i || ev->atom != xatom[XembedInfo] || +			!(flags = getatomprop(i, xatom[XembedInfo]))) +		return; + +	if (flags & XEMBED_MAPPED && !i->tags) { +		i->tags = 1; +		code = XEMBED_WINDOW_ACTIVATE; +		XMapRaised(dpy, i->win); +		setclientstate(i, NormalState); +	} +	else if (!(flags & XEMBED_MAPPED) && i->tags) { +		i->tags = 0; +		code = XEMBED_WINDOW_DEACTIVATE; +		XUnmapWindow(dpy, i->win); +		setclientstate(i, WithdrawnState); +	} +	else +		return; +	sendevent(i->win, xatom[Xembed], StructureNotifyMask, CurrentTime, code, 0, +			systray->win, XEMBED_EMBEDDED_VERSION); +} + +void +updatesystray(void) +{ +	XSetWindowAttributes wa; +	XWindowChanges wc; +	Client *i; +	Monitor *m = systraytomon(NULL); +	unsigned int x = m->mx + m->mw; +	unsigned int sw = TEXTW(stext) - lrpad + systrayspacing; +	unsigned int w = 1; + +	if (!showsystray) +		return; +	if (systrayonleft) +		x -= sw + lrpad / 2; +	if (!systray) { +		/* init systray */ +		if (!(systray = (Systray *)calloc(1, sizeof(Systray)))) +			die("fatal: could not malloc() %u bytes\n", sizeof(Systray)); +		systray->win = XCreateSimpleWindow(dpy, root, x, m->by, w, bh, 0, 0, scheme[SchemeSel][ColBg].pixel); +		wa.event_mask        = ButtonPressMask | ExposureMask; +		wa.override_redirect = True; +		wa.background_pixel  = scheme[SchemeNorm][ColBg].pixel; +		XSelectInput(dpy, systray->win, SubstructureNotifyMask); +		XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32, +				PropModeReplace, (unsigned char *)&netatom[NetSystemTrayOrientationHorz], 1); +		XChangeWindowAttributes(dpy, systray->win, CWEventMask|CWOverrideRedirect|CWBackPixel, &wa); +		XMapRaised(dpy, systray->win); +		XSetSelectionOwner(dpy, netatom[NetSystemTray], systray->win, CurrentTime); +		if (XGetSelectionOwner(dpy, netatom[NetSystemTray]) == systray->win) { +			sendevent(root, xatom[Manager], StructureNotifyMask, CurrentTime, netatom[NetSystemTray], systray->win, 0, 0); +			XSync(dpy, False); +		} +		else { +			fprintf(stderr, "dwm: unable to obtain system tray.\n"); +			free(systray); +			systray = NULL; +			return; +		} +	} +	for (w = 0, i = systray->icons; i; i = i->next) { +		/* make sure the background color stays the same */ +		wa.background_pixel  = scheme[SchemeNorm][ColBg].pixel; +		XChangeWindowAttributes(dpy, i->win, CWBackPixel, &wa); +		XMapRaised(dpy, i->win); +		w += systrayspacing; +		i->x = w; +		XMoveResizeWindow(dpy, i->win, i->x, 0, i->w, i->h); +		w += i->w; +		if (i->mon != m) +			i->mon = m; +	} +	w = w ? w + systrayspacing : 1; +	x -= w; +	XMoveResizeWindow(dpy, systray->win, x, m->by, w, bh); +	wc.x = x; wc.y = m->by; wc.width = w; wc.height = bh; +	wc.stack_mode = Above; wc.sibling = m->barwin; +	XConfigureWindow(dpy, systray->win, CWX|CWY|CWWidth|CWHeight|CWSibling|CWStackMode, &wc); +	XMapWindow(dpy, systray->win); +	XMapSubwindows(dpy, systray->win); +	/* redraw background */ +	XSetForeground(dpy, drw->gc, scheme[SchemeNorm][ColBg].pixel); +	XFillRectangle(dpy, systray->win, drw->gc, 0, 0, w, bh); +	XSync(dpy, False);  }  void @@ -2380,6 +2713,16 @@ wintoclient(Window w)  	return NULL;  } +Client * +wintosystrayicon(Window w) { +	Client *i = NULL; + +	if (!showsystray || !w) +		return i; +	for (i = systray->icons; i && i->win != w; i = i->next) ; +	return i; +} +  Monitor *  wintomon(Window w)  { @@ -2444,6 +2787,22 @@ xrdb(const Arg *arg)    arrange(NULL);  } +Monitor * +systraytomon(Monitor *m) { +	Monitor *t; +	int i, n; +	if(!systraypinning) { +		if(!m) +			return selmon; +		return m == selmon ? m : NULL; +	} +	for(n = 1, t = mons; t && t->next; n++, t = t->next) ; +	for(i = 1, t = mons; t && t->next && i < systraypinning; i++, t = t->next) ; +	if(systraypinningfailfirst && n < systraypinning) +		return mons; +	return t; +} +  void  zoom(const Arg *arg)  { | 
