From 447455b2fdfc550696d9b06f83e0a348932fa6da Mon Sep 17 00:00:00 2001 From: Remi Akirazar Date: Sun, 30 Nov 2025 03:21:54 -0500 Subject: [PATCH] patch: systray added to dwm --- config.def.h | 5 + dwm | Bin 0 -> 72976 bytes dwm.c | 411 +++++++++++- patches/dwm-systray-20230922-9f88553.diff | 735 ++++++++++++++++++++++ 4 files changed, 1125 insertions(+), 26 deletions(-) create mode 100755 dwm create mode 100644 patches/dwm-systray-20230922-9f88553.diff diff --git a/config.def.h b/config.def.h index d760eeb..a5b1307 100644 --- a/config.def.h +++ b/config.def.h @@ -4,6 +4,11 @@ static const unsigned int borderpx = 2; /* border pixel of windows */ static const unsigned int gappx = 6; /* gaps between windows */ static const unsigned int snap = 32; /* snap pixel */ +static const unsigned int systraypinning = 0; /* 0: sloppy systray follows selected monitor, >0: pin systray to monitor X */ +static const unsigned int systrayonleft = 0; /* 0: systray in the right corner, >0: systray on left of status text */ +static const unsigned int systrayspacing = 2; /* systray spacing */ +static const int systraypinningfailfirst = 1; /* 1: if pinning fails, display systray on the first monitor, False: display systray on the last monitor*/ +static const int showsystray = 1; /* 0 means no systray */ static const int showbar = 1; /* 0 means no bar */ static const int topbar = 1; /* 0 means bottom bar */ static const char *fonts[] = { "JetBrainsMono Nerd Font:size=14" }; diff --git a/dwm b/dwm new file mode 100755 index 0000000000000000000000000000000000000000..145fc7b6f31c7f10ab72ad06cf1d794f7853aff2 GIT binary patch literal 72976 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 literal 0 HcmV?d00001 diff --git a/dwm.c b/dwm.c index 56a9b4f..75461db 100644 --- a/dwm.c +++ b/dwm.c @@ -57,12 +57,27 @@ #define TAGMASK ((1 << LENGTH(tags)) - 1) #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) +#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 */ @@ -142,6 +157,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); @@ -173,6 +194,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); @@ -190,14 +212,17 @@ 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 runautostart(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); @@ -209,6 +234,7 @@ static void setup(void); static void seturgent(Client *c, int urg); static void showhide(Client *c); 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); @@ -226,18 +252,23 @@ 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); static void zoom(const Arg *arg); /* variables */ +static Systray *systray = NULL; static const char autostartblocksh[] = "autostart_blocking.sh"; static const char autostartsh[] = "autostart.sh"; static const char broken[] = "broken"; @@ -264,9 +295,10 @@ 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 running = 1; static Cur *cursor[CurLast]; static Clr **scheme; @@ -448,7 +480,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; @@ -491,6 +523,13 @@ cleanup(void) XUngrabKey(dpy, AnyKey, AnyModifier, root); while (mons) cleanupmon(mons); + + 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++) @@ -522,9 +561,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]) { @@ -577,7 +665,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); @@ -663,6 +751,11 @@ destroynotify(XEvent *e) if ((c = wintoclient(ev->window))) unmanage(c, 1); + else if ((c = wintosystrayicon(ev->window))) { + removesystrayicon(c); + resizebarwin(selmon); + updatesystray(); + } } void @@ -706,7 +799,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; @@ -715,13 +808,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) @@ -742,7 +839,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); @@ -753,7 +850,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 @@ -790,8 +887,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 @@ -877,14 +977,32 @@ 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; } +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 getrootptr(int *x, int *y) { @@ -1025,7 +1143,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); @@ -1112,6 +1231,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)) @@ -1233,6 +1359,17 @@ propertynotify(XEvent *e) Window trans; XPropertyEvent *ev = &e->xproperty; + 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) @@ -1283,6 +1420,19 @@ recttomon(int x, int y, int w, int h) return r; } +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) { @@ -1290,6 +1440,14 @@ resize(Client *c, int x, int y, int w, int h, int interact) resizeclient(c, x, y, w, h); } +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) { @@ -1305,6 +1463,19 @@ resizeclient(Client *c, int x, int y, int w, int h) XSync(dpy, False); } +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 resizemouse(const Arg *arg) { @@ -1528,26 +1699,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; } @@ -1561,7 +1743,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 @@ -1666,6 +1848,10 @@ setup(void) wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False); netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", 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); @@ -1673,6 +1859,9 @@ setup(void) 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); + 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); @@ -1681,6 +1870,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(); @@ -1811,7 +2002,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); } @@ -1907,11 +2109,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, @@ -1922,10 +2131,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); } @@ -2102,6 +2316,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 @@ -2169,6 +2502,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) { @@ -2222,6 +2565,22 @@ xerrorstart(Display *dpy, XErrorEvent *ee) return -1; } +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) { diff --git a/patches/dwm-systray-20230922-9f88553.diff b/patches/dwm-systray-20230922-9f88553.diff new file mode 100644 index 0000000..9356ec1 --- /dev/null +++ b/patches/dwm-systray-20230922-9f88553.diff @@ -0,0 +1,735 @@ +diff --git a/config.def.h b/config.def.h +index 9efa774..fed4fb9 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -3,6 +3,11 @@ + /* appearance */ + static const unsigned int borderpx = 1; /* border pixel of windows */ + static const unsigned int snap = 32; /* snap pixel */ ++static const unsigned int systraypinning = 0; /* 0: sloppy systray follows selected monitor, >0: pin systray to monitor X */ ++static const unsigned int systrayonleft = 0; /* 0: systray in the right corner, >0: systray on left of status text */ ++static const unsigned int systrayspacing = 2; /* systray spacing */ ++static const int systraypinningfailfirst = 1; /* 1: if pinning fails, display systray on the first monitor, False: display systray on the last monitor*/ ++static const int showsystray = 1; /* 0 means no systray */ + static const int showbar = 1; /* 0 means no bar */ + static const int topbar = 1; /* 0 means bottom bar */ + static const char *fonts[] = { "monospace:size=10" }; +diff --git a/dwm.c b/dwm.c +index f1d86b2..f9e7e4a 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -57,12 +57,27 @@ + #define TAGMASK ((1 << LENGTH(tags)) - 1) + #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) + ++#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 */ +@@ -141,6 +156,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); +@@ -172,6 +193,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); +@@ -189,13 +211,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); +@@ -206,6 +231,7 @@ static void setup(void); + static void seturgent(Client *c, int urg); + static void showhide(Client *c); + 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); +@@ -223,18 +249,23 @@ 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); + static void zoom(const Arg *arg); + + /* variables */ ++static Systray *systray = NULL; + static const char broken[] = "broken"; + static char stext[256]; + static int screen; +@@ -257,9 +288,10 @@ 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 running = 1; + static Cur *cursor[CurLast]; + static Clr **scheme; +@@ -441,7 +473,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; +@@ -484,6 +516,13 @@ cleanup(void) + XUngrabKey(dpy, AnyKey, AnyModifier, root); + while (mons) + cleanupmon(mons); ++ ++ 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++) +@@ -515,9 +554,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]) { +@@ -570,7 +658,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); +@@ -655,6 +743,11 @@ destroynotify(XEvent *e) + + if ((c = wintoclient(ev->window))) + unmanage(c, 1); ++ else if ((c = wintosystrayicon(ev->window))) { ++ removesystrayicon(c); ++ resizebarwin(selmon); ++ updatesystray(); ++ } + } + + void +@@ -698,7 +791,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; +@@ -707,13 +800,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) +@@ -734,7 +831,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); +@@ -745,7 +842,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 +@@ -782,8 +879,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 +@@ -869,14 +969,32 @@ 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; + } + ++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 + getrootptr(int *x, int *y) + { +@@ -1017,7 +1135,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); +@@ -1104,6 +1223,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)) +@@ -1225,6 +1351,17 @@ propertynotify(XEvent *e) + Window trans; + XPropertyEvent *ev = &e->xproperty; + ++ 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) +@@ -1275,6 +1412,19 @@ recttomon(int x, int y, int w, int h) + return r; + } + ++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) + { +@@ -1282,6 +1432,14 @@ resize(Client *c, int x, int y, int w, int h, int interact) + resizeclient(c, x, y, w, h); + } + ++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) + { +@@ -1297,6 +1455,19 @@ resizeclient(Client *c, int x, int y, int w, int h) + XSync(dpy, False); + } + ++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 + resizemouse(const Arg *arg) + { +@@ -1443,26 +1614,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; + } +@@ -1476,7 +1658,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 +@@ -1572,6 +1754,10 @@ setup(void) + wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False); + netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", 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); +@@ -1579,6 +1765,9 @@ setup(void) + 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); ++ 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); +@@ -1587,6 +1776,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(); +@@ -1717,7 +1908,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); + } + +@@ -1813,11 +2015,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, +@@ -1828,10 +2037,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); + } +@@ -2008,6 +2222,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 +@@ -2075,6 +2408,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) + { +@@ -2128,6 +2471,22 @@ xerrorstart(Display *dpy, XErrorEvent *ee) + return -1; + } + ++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) + { -- 2.49.1