[dwm][patches][systray] add patch with barpadding support - sites - public wiki contents of suckless.org
 (HTM) git clone git://git.suckless.org/sites
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
 (DIR) commit 8206a952238a89090a96bb7851e647e69774ce04
 (DIR) parent 475493d4c12b2271e94aa7faa6a0483b2e5248ce
 (HTM) Author: Markus Hanetzok <markus@hanetzok.net>
       Date:   Tue, 18 Nov 2025 16:48:43 +0100
       
       [dwm][patches][systray] add patch with barpadding support
       
       added a patch that can be applied on top of the most recent barpadding
       patch to combine barpadding + systray
       
       Diffstat:
         A dwm.suckless.org/patches/systray/d… |     786 +++++++++++++++++++++++++++++++
         M dwm.suckless.org/patches/systray/i… |       6 ++++++
       
       2 files changed, 792 insertions(+), 0 deletions(-)
       ---
 (DIR) diff --git a/dwm.suckless.org/patches/systray/dwm-systray-6.6.diff b/dwm.suckless.org/patches/systray/dwm-systray-6.6.diff
       @@ -0,0 +1,786 @@
       +diff '--color=auto' -up dwm-6.6/config.def.h systray-dwm-6.6/config.def.h
       +--- dwm-6.6/config.def.h        2025-08-09 15:00:55.740267680 +0200
       ++++ systray-dwm-6.6/config.def.h        2025-11-18 16:26:31.581907543 +0100
       +@@ -3,8 +3,15 @@
       + /* 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 int vertpad            = 10;       /* vertical padding of bar */
       ++static const int sidepad            = 10;       /* horizontal padding of bar */
       + static const char *fonts[]          = { "monospace:size=10" };
       + static const char dmenufont[]       = "monospace:size=10";
       + static const char col_gray1[]       = "#222222";
       +diff '--color=auto' -up dwm-6.6/dwm.c systray-dwm-6.6/dwm.c
       +--- dwm-6.6/dwm.c        2025-08-09 15:00:55.740267680 +0200
       ++++ systray-dwm-6.6/dwm.c        2025-11-18 16:35:53.062929489 +0100
       +@@ -56,12 +56,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 */
       +@@ -140,6 +155,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);
       +@@ -171,6 +192,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);
       +@@ -188,13 +210,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);
       +@@ -205,6 +230,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);
       +@@ -222,24 +248,31 @@ 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;
       + static int sw, sh;           /* X display screen geometry width, height */
       + static int bh;               /* bar height */
       + static int lrpad;            /* sum of left and right padding for text */
       ++static int vp;               /* vertical padding for bar */
       ++static int sp;               /* side padding for bar */
       + static int (*xerrorxlib)(Display *, XErrorEvent *);
       + static unsigned int numlockmask = 0;
       + static void (*handler[LASTEvent]) (XEvent *) = {
       +@@ -256,9 +289,10 @@ static void (*handler[LASTEvent]) (XEven
       +         [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;
       +@@ -440,7 +474,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;
       +@@ -483,6 +517,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++)
       +@@ -514,9 +555,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]) {
       +@@ -569,7 +659,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);
       +@@ -654,6 +744,11 @@ destroynotify(XEvent *e)
       + 
       +         if ((c = wintoclient(ev->window)))
       +                 unmanage(c, 1);
       ++        else if ((c = wintosystrayicon(ev->window))) {
       ++                removesystrayicon(c);
       ++                resizebarwin(selmon);
       ++                updatesystray();
       ++        }
       + }
       + 
       + void
       +@@ -697,7 +792,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;
       +@@ -706,13 +801,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 right padding */
       ++                drw_text(drw, m->ww - tw - stw - 2 * sp, 0, tw, bh, lrpad / 2 - 2, stext, 0);
       +         }
       + 
       ++        resizebarwin(m);
       +         for (c = m->clients; c; c = c->next) {
       +                 occ |= c->tags;
       +                 if (c->isurgent)
       +@@ -733,18 +832,18 @@ 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);
       ++                        drw_text(drw, x, 0, w - 2 * sp, bh, lrpad / 2, m->sel->name, 0);
       +                         if (m->sel->isfloating)
       +                                 drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0);
       +                 } else {
       +                         drw_setscheme(drw, scheme[SchemeNorm]);
       +-                        drw_rect(drw, x, 0, w, bh, 1, 1);
       ++                        drw_rect(drw, x, 0, w - 2 * sp, 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
       +@@ -781,8 +880,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
       +@@ -868,14 +970,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)
       + {
       +@@ -1016,7 +1136,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);
       +@@ -1103,6 +1224,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))
       +@@ -1224,6 +1352,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 +1414,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))
       +@@ -1282,6 +1434,14 @@ resize(Client *c, int x, int y, int w, i
       + }
       + 
       + void
       ++resizebarwin(Monitor *m) {
       ++        unsigned int w = m->ww;
       ++        if (showsystray && m == systraytomon(m) && !systrayonleft)
       ++                w -= getsystraywidth();
       ++        XMoveResizeWindow(dpy, m->barwin, m->wx + sp, m->by + vp, w - 2 * sp, bh);
       ++}
       ++
       ++void
       + resizeclient(Client *c, int x, int y, int w, int h)
       + {
       +         XWindowChanges wc;
       +@@ -1297,6 +1457,19 @@ resizeclient(Client *c, int x, int y, in
       + }
       + 
       + 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)
       + {
       +         int ocx, ocy, nw, nh;
       +@@ -1442,26 +1615,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;
       + }
       +@@ -1475,7 +1659,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
       +@@ -1563,6 +1747,9 @@ setup(void)
       +         lrpad = drw->fonts->h;
       +         bh = drw->fonts->h + 2;
       +         updategeom();
       ++        sp = sidepad;
       ++        vp = (topbar == 1) ? vertpad : - vertpad;
       ++
       +         /* init atoms */
       +         utf8string = XInternAtom(dpy, "UTF8_STRING", False);
       +         wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
       +@@ -1571,6 +1758,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);
       +@@ -1578,6 +1769,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);
       +@@ -1586,9 +1780,12 @@ 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();
       ++        updatebarpos(selmon);
       +         /* supporting window for NetWMCheck */
       +         wmcheckwin = XCreateSimpleWindow(dpy, root, 0, 0, 1, 1, 0, 0, 0);
       +         XChangeProperty(dpy, wmcheckwin, netatom[NetWMCheck], XA_WINDOW, 32,
       +@@ -1716,7 +1913,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);
       + }
       + 
       +@@ -1812,11 +2020,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,
       +@@ -1827,10 +2042,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 + sp, m->by + vp, w - 2 * sp, 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);
       +         }
       +@@ -1842,11 +2062,11 @@ updatebarpos(Monitor *m)
       +         m->wy = m->my;
       +         m->wh = m->mh;
       +         if (m->showbar) {
       +-                m->wh -= bh;
       +-                m->by = m->topbar ? m->wy : m->wy + m->wh;
       +-                m->wy = m->topbar ? m->wy + bh : m->wy;
       ++                m->wh = m->wh - vertpad - bh;
       ++                m->by = m->topbar ? m->wy : m->wy + m->wh + vertpad;
       ++                m->wy = m->topbar ? m->wy + bh + vp : m->wy;
       +         } else
       +-                m->by = -bh;
       ++                m->by = -bh - vp;
       + }
       + 
       + void
       +@@ -2007,6 +2227,126 @@ 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 - vp;
       ++        unsigned int y = m->by + sp;
       ++        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, y, 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, y - sp, 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, y, w, bh);
       ++        wc.x = x; wc.y = y; 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
       +@@ -2074,6 +2414,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)
       + {
       +@@ -2127,6 +2477,22 @@ xerrorstart(Display *dpy, XErrorEvent *e
       +         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)
       + {
       +@@ -2162,3 +2528,4 @@ main(int argc, char *argv[])
       +         XCloseDisplay(dpy);
       +         return EXIT_SUCCESS;
       + }
       ++
 (DIR) diff --git a/dwm.suckless.org/patches/systray/index.md b/dwm.suckless.org/patches/systray/index.md
       @@ -21,6 +21,11 @@ Download
        * [dwm-git-20130119-systray.diff](dwm-git-20130119-systray.diff) (19946b)
        * [dwm-systray-6.0.diff](dwm-systray-6.0.diff) (19788b) (20130119)
        
       +If you'd like to combine [barpadding](../barpadding/) and the systray patch,
       +you can apply the following patch on top of dwm-barpadding-6.6.diff
       +
       +* [dwm-systray-6.6.diff](dwm-systray-6.6.diff) (28K) (20251118)
       +
        Author
        ------
        * Jan Christoph Ebersbach <jceb@e-jc.de>
       @@ -30,3 +35,4 @@ Author
        * Igor Gevka (cb3f58a (6.2), 20200216)
        * Michel Boaventura <michel.boaventura@protonmail.com> (f09418b)
        * Hritik Vijay <hr1t1k@protonmail.com> (20210418)
       +* Markus Hanetzok (20251118)