Adding dwm patch for systray. - dotfiles - These are my dotfiles. There are many like it, but these are mine.
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
       ---
 (DIR) commit 3d5e193eadca503c9e6d6a5f03ae91f674e1985a
 (DIR) parent 0af9eacb1337a96136452b728bd04700cebb72b9
 (HTM) Author: Jay Scott <me@jay.scot>
       Date:   Sat, 28 Oct 2023 09:06:01 +0100
       
       Adding dwm patch for systray.
       
       Diffstat:
         M bashrc                              |       3 +++
         M bin/dwmstatus.sh                    |      13 +++++++------
         D bin/fet.sh                          |     281 -------------------------------
         M suckless/dwm/Makefile               |       8 +++++++-
         M suckless/dwm/config.h               |       6 ++++++
         A suckless/dwm/patches/01-dwm-systra… |     746 +++++++++++++++++++++++++++++++
       
       6 files changed, 769 insertions(+), 288 deletions(-)
       ---
 (DIR) diff --git a/bashrc b/bashrc
       @@ -42,6 +42,9 @@ alias rm='rm -i'
        # random alias
        alias weather='curl wttr.in/?1QF'
        alias ls='ls --color=auto'
       +alias voff='mullvad lockdown-mode set off; mullvad disconnect'
       +alias von='mullvad lockdown-mode set on; mullvad connect'
       +alias vcheck='curl https://am.i.mullvad.net/connected'
        
        # git alias
        alias ga='git add -A'
 (DIR) diff --git a/bin/dwmstatus.sh b/bin/dwmstatus.sh
       @@ -1,17 +1,18 @@
        #!/bin/sh
        
       -maildir="$HOME/mail/jay/Inbox/new/"
       -
        while true; do
        
                localtime=$(date +"%T")
                vol=$(pactl list sinks | tr ' ' '\n' | grep -m1 '%')
       +        vstatus=$(mullvad status)
        
       -        #mailcount="$(find "$maildir" -type f | wc -l)"
       -        #rsscount=$(newsboat -x print-unread | awk '{print $1}')
       +        if [ "$vstatus" != "Disconnected" ]; then
       +                vstatus="On"
       +        else
       +                vstatus="Off"
       +        fi
        
       -        #xsetroot -name " RSS: $rsscount | MAIL: $mailcount | VOL: $vol | $localtime"
       -        xsetroot -name " VOL: $vol | $localtime"
       +        xsetroot -name " VPN: $vstatus | VOL: $vol | $localtime | "
        
                sleep 10
        done
 (DIR) diff --git a/bin/fet.sh b/bin/fet.sh
       @@ -1,281 +0,0 @@
       -#!/bin/sh
       -#
       -#    fet.sh
       -#  a fetch in pure POSIX shell
       -#
       -
       -# supress errors
       -exec 2>/dev/null
       -set --
       -eq() { # equals  |  [ a = b ] with globbing
       -        case $1 in
       -        $2) ;;
       -        *) return 1 ;;
       -        esac
       -}
       -
       -## DE
       -wm=$XDG_CURRENT_DESKTOP
       -[ "$wm" ] || wm=$DESKTOP_SESSION
       -
       -## Distro
       -# freedesktop.org/software/systemd/man/os-release.html
       -# a common file that has variables about the distro
       -for os in /etc/os-release /usr/lib/os-release; do
       -        # some POSIX shells exit when trying to source a file that doesn't exist
       -        [ -f $os ] && . $os && break
       -done
       -
       -if [ -e /proc/$$/comm ]; then
       -        ## Terminal
       -        while [ ! "$term" ]; do
       -                # loop over lines in /proc/pid/status until it reaches PPid
       -                # then save that to a variable and exit the file
       -                while read -r line; do
       -                        eq "$line" 'PPid*' && ppid=${line##*:?} && break
       -                done <"/proc/${ppid:-$PPID}/status"
       -
       -                # Make sure not to do an infinite loop
       -                [ "$pppid" = "$ppid" ] && break
       -                pppid=$ppid
       -
       -                # get name of binary
       -                read -r name <"/proc/$ppid/comm"
       -
       -                case $name in
       -                *sh | "${0##*/}") ;;                     # skip shells
       -                *[Ll]ogin* | *init | *systemd*) break ;; # exit when the top is reached
       -                # anything else can be assumed to be the terminal
       -                # this has the side affect of catching tmux, but tmux
       -                # detaches from the terminal and therefore ignoring that
       -                # will just make the init the term
       -                *) term=$name ;;
       -                esac
       -        done
       -
       -        ## WM/DE
       -        [ "$wm" ] ||
       -                # loop over all processes and check the binary name
       -                for i in /proc/*/comm; do
       -                        read -r c <"$i"
       -                        case $c in
       -                        *bar* | *rc) ;;
       -                        awesome | xmonad* | qtile | sway | i3 | [bfo]*box | *wm*)
       -                                wm=${c%%-*}
       -                                break
       -                                ;;
       -                        esac
       -                done
       -
       -        ## Memory
       -        # loop over lines in /proc/meminfo until it reaches MemTotal,
       -        # then convert the amount (second word) from KB to MB
       -        while read -r line; do
       -                eq "$line" 'MemTotal*' && set -- $line && break
       -        done </proc/meminfo
       -        mem="$(($2 / 1000))MB"
       -
       -        ## Processor
       -        while read -r line; do
       -                case $line in
       -                vendor_id*) vendor="${line##*: } " ;;
       -                model\ name*)
       -                        cpu=${line##*: }
       -                        break
       -                        ;;
       -                esac
       -        done </proc/cpuinfo
       -
       -        ## Uptime
       -        # the simple math is shamefully stolen from aosync
       -        IFS=. read -r uptime _ </proc/uptime
       -        d=$((uptime / 60 / 60 / 24))
       -        up=$(printf %02d:%02d $((uptime / 60 / 60 % 24)) $((uptime / 60 % 60)))
       -        [ "$d" -gt 0 ] && up="${d}d $up"
       -
       -        ## Kernel
       -        read -r _ _ version _ </proc/version
       -        kernel=${version%%-*}
       -        eq "$version" '*Microsoft*' && ID="fake $ID"
       -
       -        ## Motherboard // laptop
       -        read -r model </sys/devices/virtual/dmi/id/product_name
       -        # invalid model handling
       -        case $model in
       -        # alternate file with slightly different info
       -        # on my laptop it has the device model (instead of 'hp notebook')
       -        # on my desktop it has the extended motherboard model
       -        'System '* | 'Default '* | 'To Be Filled'*)
       -                read -r model </sys/devices/virtual/dmi/id/board_name
       -                ;;
       -        esac
       -
       -        ## Packages
       -        # clean environment, then make every file in the dir an argument,
       -        # then save the argument count to $pkgs
       -        set --
       -        # kiss, arch, debian, void, gentoo
       -        for i in '/var/db/kiss/installed/*' '/var/lib/pacman/local/[0-9a-z]*' \
       -                '/var/lib/dpkg/info/*.list' '/var/db/xbps/.*' '/var/db/pkg/*/*'; do
       -                set -- $i
       -                [ $# -gt 1 ] && pkgs=$# && break
       -        done
       -
       -        read -r host </proc/sys/kernel/hostname
       -elif [ -f /var/run/dmesg.boot ]; then
       -        # Both OpenBSD and FreeBSD use this file, however they're formatted differently
       -        read -r bsd </var/run/dmesg.boot
       -        case $bsd in
       -        Open*)
       -                ## OpenBSD cpu/mem/name
       -                while read -r line; do
       -                        case $line in
       -                        'real mem'*)
       -                                # use the pre-formatted value which is in brackets
       -                                mem=${line##*\(}
       -                                mem=${mem%\)*}
       -                                ;;
       -                        # set $cpu to everything before a comma and after the field name
       -                        cpu0:*)
       -                                cpu=${line#cpu0: }
       -                                # Remove excess info after the actual CPU name
       -                                cpu=${cpu%%,*}
       -                                # Set the CPU Manufacturer to the first word of the cpu
       -                                # variable [separated by '(' or ' ']
       -                                vendor=${cpu%%[\( ]*}
       -                                # We got all the info we want, stop reading
       -                                break
       -                                ;;
       -                        # First 2 words in the file are OpenBSD <version>
       -                        *) [ "$ID" ] || {
       -                                set -- $line
       -                                ID="$1 $2"
       -                        } ;;
       -                        esac
       -                done </var/run/dmesg.boot
       -                [ -d /var/db/pkg ] && set -- /var/db/pkg/* && pkgs=$#
       -                read -r host </etc/myname
       -                host=${host%.*}
       -                ;;
       -        # Everything else, assume FreeBSD (first line is ---<<BOOT>> or something)
       -        *)
       -                # shellcheck source=/dev/null
       -                . /etc/rc.conf
       -                # shut shellcheck up without disabling the warning
       -                host=${hostname:-}
       -
       -                while read -r line; do
       -                        case $line in
       -                        # os version
       -                        FreeBSD*)
       -                                # If the OS is already set, no need to set it again
       -                                [ "$ID" ] && continue
       -                                ID=${line%%-R*}
       -                                ;;
       -
       -                        CPU:*)
       -                                cpu=${cpu#CPU: }
       -                                # Remove excess info from after the actual CPU name
       -                                cpu=${line%\(*}
       -                                ;;
       -                        *Origin=*)
       -                                # CPU Manufacturer
       -                                vendor=${line#*Origin=\"}
       -                                vendor="${vendor%%\"*} "
       -                                ;;
       -
       -                        'real memory'*)
       -                                # Get the pre-formatted amount which is inside brackets
       -                                mem=${line##*\(}
       -                                mem=${mem%\)*}
       -                                # This appears to be the final thing we need from the file,
       -                                # no need to read it more.
       -                                break
       -                                ;;
       -                        esac
       -                done </var/run/dmesg.boot
       -                ;;
       -        esac
       -elif
       -        v=/System/Library/CoreServices/SystemVersion.plist
       -        [ -f "$v" ]
       -then
       -        ## Macos
       -        # make sure this variable is empty as to not break the following loop
       -        temp=
       -        while read -r line; do
       -                case $line in
       -                # set a variable so the script knows it's on the correct line
       -                # (the line after this one is the important one)
       -                *ProductVersion*) temp=. ;;
       -                *)
       -                        # check if the script is reading the derired line, if not
       -                        # don't do anything
       -                        [ "$temp" ] || continue
       -                        # Remove everything before and including the first '>'
       -                        ID=${line#*>}
       -                        # Remove the other side of the XML tag, and insert the actual OS name
       -                        ID="MacOS ${ID%<*}"
       -                        # We got the info we want, end the loop.
       -                        break
       -                        ;;
       -                esac
       -        done <"$v"
       -fi
       -
       -eq "$0" '*fetish' && printf 'Step on me daddy\n' && exit
       -
       -# help i dont know if it's a capital consistently
       -eq "$wm" '*[Gg][Nn][Oo][Mm][Ee]*' && wm='foot DE'
       -
       -## GTK
       -while read -r line; do
       -        eq "$line" 'gtk-theme*' && gtk=${line##*=} && break
       -done <"${XDG_CONFIG_HOME:=$HOME/.config}/gtk-3.0/settings.ini"
       -
       -# Shorten $cpu and $vendor
       -# this is so messy due to so many inconsistencies in the model names
       -vendor=${vendor##*Authentic}
       -vendor=${vendor##*Genuine}
       -cpu=${cpu##*) }
       -cpu=${cpu%% @*}
       -cpu=${cpu%% CPU}
       -cpu=${cpu##CPU }
       -cpu=${cpu##*AMD }
       -cpu=${cpu%% with*}
       -cpu=${cpu% *-Core*}
       -
       -col() {
       -        printf '  '
       -        for i in 1 2 3 4 5 6; do
       -                printf '\033[9%sm%s' "$i" "${colourblocks:-▅▅}"
       -        done
       -        printf '\033[0m\n'
       -}
       -
       -print() {
       -        [ "$2" ] && printf '\033[9%sm%6s\033[0m%b%s\n' \
       -                "${accent:-4}" "$1" "${separator:- ~ }" "$2"
       -}
       -
       -# default value
       -: "${info:=n user os sh wm up gtk cpu mem host kern pkgs term col n}"
       -
       -for i in $info; do
       -        case $i in
       -        n) echo ;;
       -        os) print os "$ID" ;;
       -        sh) print sh "${SHELL##*/}" ;;
       -        wm) print wm "${wm##*/}" ;;
       -        up) print up "$up" ;;
       -        gtk) print gtk "${gtk# }" ;;
       -        cpu) print cpu "$vendor$cpu" ;;
       -        mem) print mem "$mem" ;;
       -        host) print host "$model" ;;
       -        kern) print kern "$kernel" ;;
       -        pkgs) print pkgs "$pkgs" ;;
       -        term) print term "$term" ;;
       -        user) printf '%7s@%s\n' "$USER" "$host" ;;
       -        col) col ;;
       -        esac
       -done
 (DIR) diff --git a/suckless/dwm/Makefile b/suckless/dwm/Makefile
       @@ -1,6 +1,7 @@
        REPOSITORY = http://git.suckless.org/dwm
        SRC_DIR = src
        PINNED_REVISION = HEAD
       +PATCH_DIR = patches
        
        all: $(SRC_DIR)
        
       @@ -11,7 +12,7 @@ clean: reset
                        git clean -f; \
                fi
        
       -$(SRC_DIR): clone reset
       +$(SRC_DIR): clone reset patch
                @cp config.h $@
                @cd $@ && $(MAKE) -s
        
       @@ -20,6 +21,11 @@ reset:
                        cd $(SRC_DIR) && git reset --hard $(PINNED_REVISION); \
                fi
        
       +patch: $(PATCH_DIR)/*
       +        @for file in $^ ; do \
       +                patch -d "${SRC_DIR}" < $${file}; \
       +        done
       +
        clone:
                @if ! test -d $(SRC_DIR); then \
                        git clone $(REPOSITORY) $(SRC_DIR); \
 (DIR) diff --git a/suckless/dwm/config.h b/suckless/dwm/config.h
       @@ -6,6 +6,12 @@ static const unsigned int snap      = 32;
        static const int lockfullscreen            = 1;
        static const int showbar            = 1;
        static const int topbar             = 1;
       +static const unsigned int systraypinning = 0;
       +static const unsigned int systrayonleft = 0;
       +static const unsigned int systrayspacing = 2;
       +static const int systraypinningfailfirst = 1;
       +static const int showsystray        = 1;
       +
        static const char *fonts[]          = { "Hack:size=10" };
        static const char dmenufont[]       = "Hack:size=10";
        static const char col_gray1[]       = "#222222";
 (DIR) diff --git a/suckless/dwm/patches/01-dwm-systray-6.4.diff b/suckless/dwm/patches/01-dwm-systray-6.4.diff
       @@ -0,0 +1,746 @@
       +diff --git a/config.def.h b/config.def.h
       +index 9efa774..750529d 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" };
       +@@ -101,8 +106,8 @@ static const Key keys[] = {
       + /* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */
       + static const Button buttons[] = {
       +         /* click                event mask      button          function        argument */
       +-        { ClkLtSymbol,          0,              Button1,        setlayout,      {0} },
       +-        { ClkLtSymbol,          0,              Button3,        setlayout,      {.v = &layouts[2]} },
       ++        { ClkTagBar,            MODKEY,         Button1,        tag,            {0} },
       ++        { ClkTagBar,            MODKEY,         Button3,        toggletag,      {0} },
       +         { ClkWinTitle,          0,              Button2,        zoom,           {0} },
       +         { ClkStatusText,        0,              Button2,        spawn,          {.v = termcmd } },
       +         { ClkClientWin,         MODKEY,         Button1,        movemouse,      {0} },
       +diff --git a/dwm.c b/dwm.c
       +index 03baf42..4611a03 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);
       +@@ -207,6 +232,7 @@ static void seturgent(Client *c, int urg);
       + static void showhide(Client *c);
       + static void sigchld(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);
       +@@ -224,18 +250,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;
       +@@ -258,9 +289,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;
       +@@ -442,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;
       +@@ -485,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++)
       +@@ -516,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]) {
       +@@ -571,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);
       +@@ -656,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
       +@@ -699,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;
       +@@ -708,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 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)
       +@@ -735,7 +832,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);
       +@@ -746,7 +843,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
       +@@ -783,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
       +@@ -870,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)
       + {
       +@@ -1018,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);
       +@@ -1105,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))
       +@@ -1226,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)
       +@@ -1276,6 +1413,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)
       + {
       +@@ -1283,6 +1433,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)
       + {
       +@@ -1298,6 +1456,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)
       + {
       +@@ -1444,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;
       + }
       +@@ -1477,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
       +@@ -1566,6 +1748,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);
       +@@ -1573,6 +1759,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);
       +@@ -1581,6 +1770,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();
       +@@ -1711,7 +1902,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);
       + }
       + 
       +@@ -1807,11 +2009,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,
       +@@ -1822,10 +2031,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);
       +         }
       +@@ -2002,6 +2216,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
       +@@ -2069,6 +2402,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)
       + {
       +@@ -2122,6 +2465,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)
       + {