bspwm framed

thursday, 15 january 2015

bspwm, by definition, implementing a binary space partitioning scheme does not manage frames per se like other tiling window managers such as herbstluftwm.

While there is a lot of merit in the dynamic gaps described here which grow the windows towards the edge of the screen (monitor) while shrinking the window_gap as windows are added to the desktop, I find I prefer that the windows stay bounded within a fixed margin (a la frame) around the desktop as the window_gap is dynamically adjusted – there is less visual jitter to my eyes if the outer edges remain fixed maintaining a static desktop border. It’s purely a cosmetic preference which the luxury of a 30” monitor affords.

Two window desktop

Five window desktop, resized window_gap

So the rules I wanted to apply are..

  • maintain a fixed default margin around the monitor desktop
  • the right_padding is dependent on whether the Conky panel is visible or is the default monitor margin
  • dynamically adjust the inner window_gap as windows are added or removed from the desktop, maintaining the default monitor margin
  • with the Conky panel visible, full screen mode fits within the margins (pseudo frame) of the desktop
  • with the Conky panel hidden, full screen mode fills the entire screen

Additional niceties thrown in are..

  • allow toggling dynamic window gaps which, if off, sets the window_gap to 1 pixel (just my preference over a zero value)
  • remember whether dynamic window gaps are on or off, between bspwm sessions (persistence)

desktop margin

in pixels is set with a simple script that allows various parts of this bspwm configuration to access. As a script, it allows real-time adjustments of the value to fine tune the window_gap and margin control of the desktop. The value is the outer margin or container for the windows and the window_gap for two windows..

#!/bin/sh echo 90

conky padding

the conky_padding script is modified to accommodate the new monitor padding requirements in monocle mode..

#!/bin/sh maximum_width=$(grep 'maximum_width' ~/.conkyrc | cut -d' ' -f2) border_margin=$(grep 'border_outer_margin' ~/.conkyrc | cut -d' ' -f2) function shadow() { if pidof compton >/dev/null; then R=$(grep ‘shadow-radius’ ~/.compton.conf | sed ‘s/.([0-9]);/\1/’) X=$(grep ‘shadow-offset-x’ ~/.compton.conf | sed ‘s/.([0-9]);/\1/’) echo $(( $R ** 2 - $X ** 2 + 2 )) else echo 0 fi } function tiled() { D=$(bspc query –tree –monitor DVI-1 | grep ‘T - *’ | awk ‘{ print $1; }’) G=$(bspc config –desktop $D window_gap) echo $(( $maximum_width + $border_margin * 2 - $G + 2 + $(shadow) )) } function monocle() { echo $(( $maximum_width + $border_margin * 2 + $(shadow) )) } function desktop() { if [[ $(bspc query –monitors –monitor focused) = DVI-0 ]]; then bspc query –tree –monitor last | grep $’^\t[0-9].*’ | sed ‘s/\t([0-9]) .*/\1/’ else bspc query –desktops –desktop focused fi } if xdotool search --onlyvisible --classname 'Conky'; then if bspc query –tree –monitor DVI-1 | grep -q ‘ M - *’; then P=$(desktop_margin) bspc config -m DVI-1 top_padding $P bspc config -m DVI-1 left_padding $P bspc config -m DVI-1 bottom_padding $P bspc config -m DVI-1 right_padding $(monocle) else bspc config -m DVI-1 right_padding $(tiled) fi else if bspc query –tree –monitor DVI-1 | grep -q ‘ M - *’; then bspc config -m DVI-1 top_padding 0 bspc config -m DVI-1 left_padding 0 bspc config -m DVI-1 bottom_padding 0 bspc config -m DVI-1 right_padding 0 else bspc config -m DVI-1 right_padding $(( $(desktop_margin) - $(bspc config –desktop $(desktop) window_gap) )) fi fi

The shadow function is just an attempt at calculating a shadow width compensation value for the window_gap – which somewhat superfluous (over kill) given the desktop margin can be set to any desirable value.

Five window desktop, no conky

window gap

the window_gap script is modified to maintain a fixed desktop margin or frame for the windows as the window_gap is adjusted for new or removed windows – reducing the monitor padding in tiled mode or simply applying the default desktop margin in monocle mode..

#!/bin/sh mode='linear 20' # mode='binary' function linear() { [[ $M = DVI-1 ]] && factor=$@ || factor=$(dotpitch $@) echo $(( ($margin + $factor) - ($windows - 1) * $factor )) } function binary() { echo $(( ($margin * 2) / (2 ** ($windows -1)) )) } function dotpitch() { echo $@ | awk ‘{ print int($1 * 0.25 / 0.282 + 0.5) }’ } function window_gap() { margin=$(desktop_margin) M=$(bspc query –monitors –desktop focused) [[ $M = DVI-1 ]] || margin=$(dotpitch $margin) windows=$(bspc query –desktop focused –windows | wc -l) G=$($mode) [[ $G -lt 1 || ! -f ~/.config/bspwm/!window_gap ]] && G=1 if bspc query –tree –monitor $M | grep -q ‘ T - *’; then bspc config –desktop focused window_gap $G P=$(( $margin - $G )) [[ $P -lt 0 ]] && P=0 else P=$(desktop_margin) fi [[ $M = DVI-1 ]] || P=$(dotpitch $P) bspc config -m $M top_padding $P bspc config -m $M left_padding $P bspc config -m $M bottom_padding $P [[ $M = DVI-1 ]] || bspc config -m $M right_padding $P conky_padding } case $@ in –daemon) bspc control –subscribe | while read line do window_gap done ;; *) window_gap ;; esac

To enable the dynamic window_gap management, the window_gap script is invoked in daemon mode by the bspwmrc startup. sxkhdrc maps a key to invoke it manually for toggling the dynamic window_gap management on and off using a simple file named “!window_gap” as a state indicator.

A dot pitch adjustment using the dot pitch ratio of the two monitors in this multihead setup is applied to the window_gap and monitor margin of the secondary monitor to maintain visually equal spacing of the windows! This is very anal..

Full screen, with conky

Full screen, no conky

toggle dynamic window gap

switches between no window_gap (which in my configuration sets the window_gap to 1 versus 0) and dynamic window_gap.

alt + g [[ -f ~/.config/bspwm/!window_gap ]] && rm -f ~/.config/bspwm/!window_gap || touch ~/.config/bspwm/!window_gap; window_gap

The side-effect of the persistent !window_gap file is that the last state is available to the bspwm session at startup to set the initial desktops window_gap.

toggle compositing shadows

shadow effects adorning spread out windows via compton, a standalone compositing manager, can be toggled on and off. conky_padding is invoked as it performs a minor (and ridiculous) adjustment to the right_padding to compensate for the shadow effect.

alt + ctrl + super + backslash if pidof compton; then killall compton; rm -f ~/.compton; else touch ~/.compton; compton; while ! pidof compton; do sleep 0.1s; done; fi; conky_padding

Wait for compton to load before testing conky_padding.

session startup

on bspwm startup, note the last window_gap state and fire up the daemon process..

[[ -f ~/.config/bspwm/!window_gap ]] && window_gap=$(desktop_margin) || window_gap=1 bspc config window_gap $window_gap ... window_gap --daemon &

That’s about it for bspwm for me. It fits my workflow and aesthetic. And there is a real elegance to its messaging implementation with sxhkd and being able to control it from the command line any time one wishes.

True frames via herbstluftwm are possibly something that might entice an investigation, especially since, its client/server design utilizing shell scripting is very similar to bspwm. Frames would bring a different window management behaviour and probably more predictable tiling placement (since herbstluftwm is a manual tiling window manager), albeit, at the cost of requiring more scripting to achieve some of the behaviour which comes naturally to bspwm which satisfies my general workflow – utilizing the full range of available desktops with typically no more than four windows in each.

But it could be enlightening to find out when time permits..

»»  bspwm gym

comment ?