summaryrefslogtreecommitdiff
path: root/blog/2023-10-03-sticky-tiling-windows-in-bspwm
diff options
context:
space:
mode:
Diffstat (limited to 'blog/2023-10-03-sticky-tiling-windows-in-bspwm')
-rw-r--r--blog/2023-10-03-sticky-tiling-windows-in-bspwm/index.md93
1 files changed, 93 insertions, 0 deletions
diff --git a/blog/2023-10-03-sticky-tiling-windows-in-bspwm/index.md b/blog/2023-10-03-sticky-tiling-windows-in-bspwm/index.md
new file mode 100644
index 0000000..ab2fbad
--- /dev/null
+++ b/blog/2023-10-03-sticky-tiling-windows-in-bspwm/index.md
@@ -0,0 +1,93 @@
+# sticky tiling windows in bspwm
+
+`bspwm` has a useful `sticky` flag, which keeps the window on whatever the focused desktop
+is, basically like using `node -d` whenever you change desktops.
+for floating windows this works very well, but the situation is more complicated if
+you set the `sticky` flag for a tiled window.
+
+It works, of course, but since the sticky window is moved away from a desktop when it
+stops being focused, it loses its location in the desktop's layout,
+and switching back to that desktop places the sticky tiled window in the location any
+window would be. This is not ideal if you don't want to constantly reconfigure your
+layout after switching to a browser or something similar.
+
+There's actually a draft pull request from 2019 on `bspwm`'s Github that addresses this,
+[#1032](https://github.com/baskerville/bspwm/pull/1032), but patching bspwm to solve this
+problem is quite bothersome if you use a binary package. Plus, `bspwm`'s great advantage
+is how extensible and scriptable it is; there must be a way to solve this problem that way!
+
+There absolutely is, but it took a while for me to figure it out. I spent a few hours on this,
+getting it to *almost* work, but be flawed in a way that made it not worth using.
+But I finally got it working after [emanuele6](https://github.com/emanuele6) helped me
+on IRC (thanks!), and now I use it. So, here it is, `bsp_movedesk`:
+
+ #!/bin/sh
+ # deal with sticky windows when moving workspaces.
+ test -z "$1" && exit
+
+ # path format: desktop/stickywindow: parent
+ bspc query -N -n '.local.leaf.!hidden.sticky' | while read -r wid; do
+ [ "$(bsp_countwindows)" = 1 ] && break
+ dir="$HOME/run/bspsticky/$(bspc query -D -d focused)"
+ mkdir -p "$dir"
+ bspc node "$wid" -i
+ bspc query -N "$wid" -n '@brother.leaf.!window' > "${dir}/${wid}"
+ done
+
+ bspc desktop -f "$1"
+
+ bspc query -N -n '.local.leaf.!hidden.sticky' | while read -r wid; do
+ dir="$HOME/run/bspsticky/$(bspc query -D -d focused)"
+ [ "$(bsp_countwindows)" = 1 ] && break
+ stdir="${dir}/${wid}"
+ if [ -s "$stdir" ]; then
+ rece="$(cat "$stdir")"
+ bspc node "$wid" -n "$rece"
+ rm "$stdir"
+ fi
+ done
+
+ # remove hidden window's receptacles. sucks but better than the alternative
+ while bspc node 'any.local.leaf.!window' -k; do :; done
+
+The script is a wrapper around `desktop -f`, and can be used by replacing instances
+of `bspc desktop -f` with `bsp_movedesk` in your `sxhkd` config.
+
+It works by reading and writing to a special directory
+(on my machine `$HOME/run/bspsticky`, kept inside a ramdisk),
+which contains directories named with a desktop's ID.
+These directories contain files named for a sticky node's ID,
+and contain the ID of a receptacle which the window should be
+moved to if that desktop is focused.
+These receptacles are placed before the focused desktop changes if there
+are multiple windows open (because doing this when the sticky window
+is the only open window is unnecessary.)
+
+This is the `bsp_countwindows` script:
+
+ #!/bin/sh
+ bspc query -N -n '.window.!hidden' -d | wc -l
+
+There are definitely improvements that could be made here,
+but It Works. the end.
+
+---
+
+here's a completely unrelated script, which swaps a window's parent to its sibling,
+in case you want that:
+
+ #!/bin/sh
+ # move focused window to sibling
+ set -e
+
+ # possibly causes a race condition if focused changes during script?
+ focused=$(bspc query -N -n)
+
+ if [ "$1" = "2" ]; then
+ bspc node -f @parent/parent/brother
+ else
+ bspc node -f @parent/brother
+ fi
+ bspc node -i
+ bspc node $focused -n $(bspc query -N -n .local.leaf.!window)
+ bspc node $focused -f