Introduction
Introduction Statistics Contact Development Disclaimer Help
Adding dwm patch for systray. - dotfiles - These are my dotfiles. There are man…
Log
Files
Refs
README
---
commit 3d5e193eadca503c9e6d6a5f03ae91f674e1985a
parent 0af9eacb1337a96136452b728bd04700cebb72b9
Author: Jay Scott <[email protected]>
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(-)
---
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'
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 | $loc…
- xsetroot -name " VOL: $vol | $localtime"
+ xsetroot -name " VPN: $vstatus | VOL: $vol | $localtime | "
sleep 10
done
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 exi…
- [ -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 i…
- # 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 | *w…
- 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/*/*…
- 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 di…
- 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 brac…
- mem=${line##*\(}
- mem=${mem%\)*}
- ;;
- # set $cpu to everything before a comma and after the …
- cpu0:*)
- cpu=${line#cpu0: }
- # Remove excess info after the actual CPU name
- cpu=${cpu%%,*}
- # Set the CPU Manufacturer to the first word o…
- # 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 someth…
- *)
- # 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 …
- [ "$ID" ] && continue
- ID=${line%%-R*}
- ;;
-
- CPU:*)
- cpu=${cpu#CPU: }
- # Remove excess info from after the actual CPU…
- cpu=${line%\(*}
- ;;
- *Origin=*)
- # CPU Manufacturer
- vendor=${line#*Origin=\"}
- vendor="${vendor%%\"*} "
- ;;
-
- 'real memory'*)
- # Get the pre-formatted amount which is inside…
- mem=${line##*\(}
- mem=${mem%\)*}
- # This appears to be the final thing we need f…
- # 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 …
- # 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…
- 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
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); \
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";
diff --git a/suckless/dwm/patches/01-dwm-systray-6.4.diff b/suckless/dwm/patche…
@@ -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 …
++static const unsigned int systrayonleft = 0; /* 0: systray in the right co…
++static const unsigned int systrayspacing = 2; /* systray spacing */
++static const int systraypinningfailfirst = 1; /* 1: if pinning fails, displ…
++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, ClkClient…
+ static const Button buttons[] = {
+ /* click event mask button function …
+- { ClkLtSymbol, 0, Button1, setlayout, …
+- { ClkLtSymbol, 0, Button3, setlayout, …
++ { ClkTagBar, MODKEY, Button1, tag, …
++ { ClkTagBar, MODKEY, Button3, toggletag, …
+ { ClkWinTitle, 0, Button2, zoom, …
+ { ClkStatusText, 0, Button2, spawn, …
+ { ClkClientWin, MODKEY, Button1, movemouse, …
+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, NetSystemTra…
+ NetWMFullscreen, NetActiveWindow, NetWMWindowType,
+ NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
++enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */
+ enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atom…
+ 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 inte…
+@@ -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, …
+ 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) - getsystrayw…
+ 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 =…
++ /* 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", s…
++ 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 | Prope…
++ XReparentWindow(dpy, c->win, systray->win, 0, 0);
++ /* use parents background color */
++ swa.background_pixel = scheme[SchemeNorm][ColBg].pix…
++ XChangeWindowAttributes(dpy, c->win, CWBackPixel, &sw…
++ sendevent(c->win, netatom[Xembed], StructureNotifyMas…
++ /* FIXME not sure if I have to send these events, too…
++ sendevent(c->win, netatom[Xembed], StructureNotifyMas…
++ sendevent(c->win, netatom[Xembed], StructureNotifyMas…
++ sendevent(c->win, netatom[Xembed], StructureNotifyMas…
++ 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,…
+- XMoveResizeWindow(dpy, m->barwin, m->wx, m->b…
++ 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, ste…
+ }
+
++ 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 : S…
+ 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_…
++ /* FIXME getatomprop should return the number of items and a pointer …
++ * 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-…
++ 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, wmato…
+ 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, Curre…
++ resizebarwin(selmon);
++ updatesystray();
++ }
++
+ if (!XGetWindowAttributes(dpy, ev->window, &wa) || wa.override_redire…
+ 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 inter…
+ 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,…
+ {
+ 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[WMTakeFocu…
+ }
+
+ void
+@@ -1566,6 +1748,10 @@ setup(void)
+ wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False);
+ netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", Fal…
+ netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
++ netatom[NetSystemTray] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_S0", Fals…
++ netatom[NetSystemTrayOP] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE"…
++ netatom[NetSystemTrayOrientation] = XInternAtom(dpy, "_NET_SYSTEM_TRA…
++ netatom[NetSystemTrayOrientationHorz] = XInternAtom(dpy, "_NET_SYSTEM…
+ netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
+ netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False);
+ netatom[NetWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", Fa…
+@@ -1573,6 +1759,9 @@ setup(void)
+ netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", Fa…
+ netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYP…
+ 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…
++ 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, …
++ * _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,…
++ w = m->ww;
++ if (showsystray && m == systraytomon(m))
++ w -= getsystraywidth();
++ m->barwin = XCreateWindow(dpy, root, m->wx, m->by, w, bh, 0, …
+ CopyFromParent, DefaultVisual(dpy, screen),
+ CWOverrideRedirect|CWBackPixmap|CWEventMask, …
+ 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…
++ if (i->h > bh) {
++ if (i->w == i->h)
++ i->w = bh;
++ else
++ i->w = (int) ((float)bh * ((float)i->w / (flo…
++ 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, co…
++ 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(Sy…
++ systray->win = XCreateSimpleWindow(dpy, root, x, m->by, w, bh…
++ 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[NetSystemTrayOrien…
++ PropModeReplace, (unsigned char *)&netatom[Ne…
++ XChangeWindowAttributes(dpy, systray->win, CWEventMask|CWOver…
++ XMapRaised(dpy, systray->win);
++ XSetSelectionOwner(dpy, netatom[NetSystemTray], systray->win,…
++ if (XGetSelectionOwner(dpy, netatom[NetSystemTray]) == systra…
++ sendevent(root, xatom[Manager], StructureNotifyMask, …
++ 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|CWSiblin…
++ 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->…
++ if(systraypinningfailfirst && n < systraypinning)
++ return mons;
++ return t;
++}
++
+ void
+ zoom(const Arg *arg)
+ {
You are viewing proxied material from jay.scot. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.