| 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) | |
| + { |