Open jaimet opened 4 years ago
switch your order of operations - wait for the new application to spawn so that the focused node gets split, and then kill it after it is split
I had to solve a similar problem to implement "window swallowing" and there is no good solution AFAIK. @neeasade solution works but you can see how the node gets split before you kill the original which is annoying and ugly (at least for me). A slightly better solution is to substitute the original window with a receptacle hiding the window at the same time. This way you leave a receptacle behind that you can populate with the next application you open. As an example, this script replaces the current window with whatever application you are launching and places the window back after the application is closed:
#!/bin/bash
NODE_CURRENT=$(bspc query -N -n focused)
bspc node $NODE_CURRENT -i --flag hidden=on
bspc rule --add "*" --one-shot focused=on state=locked \
node=$(bspc query -N -d -n '.leaf.!window')
$@ &
WATCH=$(bspc subscribe -c 1 node_add)
NODE_NEW=${WATCH##* }
while read EVENT
do
[ "${EVENT##* }" = "$NODE_NEW" ] && break
done < <(bspc subscribe node_remove)
bspc node $NODE_CURRENT --flag hidden=off --focus
Problems:
All of this could be solved if there was a bspc node <command>
to replace a node with a hidden window directly, a rule to replace a node or a way to have no focused window.
The lack of a better solution to replace an existing window with a new one or a hidden one is worrying since this sounds like basic window manager operations to me. If there is a better solution please let me know.
I think the real solution is to set the parent window of the program you want to open. Some programs support this, for example mpv has a --wid
flag that can be used like this:
mpv --wid=$(bspc query -N -n focused)
Since most programs don't, though, I wrote a daemon that uses the bspc subscribe
mechanism to hide/unhide windows opened and handle preselections. It can be put into bspwmrc and is mostly POSIX compatible.
## window swallowing options
# classes considered a terminal emulator, meaning
# to be hidden when a node is added while focused
terminal="urxvt launcher"
# classes that should never hide a `terminal`
blacklist="xev xclock"
# other combinations of parent/child where the child
# window should "swallow" the parent.
special="qutebrowser/mpv nheko/mpv"
ids=$XDG_RUNTIME_DIR/swallow
get_class() {
xprop -id "$1" | awk -F '"' '/WM_CLASS/{print $4}'
}
save_presel() {
test "$2" = cancel && export last_presel="$1"
}
swallow() {
child_id=$1
parent_id=$(bspc query -N -n last)
this_desktop=$2
term_desktop=$(bspc query -D -n last)
insert_point=$3
if test "$insert_point" = "$last_presel"; then
unset last_presel
return
fi
test "$this_desktop" != "$term_desktop" && return
child_class=$(get_class "$child_id")
echo "$terminal $blacklist" | grep -i "$child_class" && return
parent_class=$(get_class "$parent_id")
! echo "$terminal" | grep -i "$parent_class" && \
! echo "$special" | grep -i "$parent_class/$child_class" && return
echo "$child_id $parent_id" >> "$ids"
bspc node "$parent_id" --flag hidden=on
}
spit() {
child_id=$1
this_desktop=$2
grep "^$child_id" "$ids" || return
parent_id=$(awk "/^$child_id/"'{print $2}' "$ids")
term_desktop=$(bspc query -D -n "$parent_id")
bspc node "$parent_id" --flag hidden=off
test "$term_desktop" != "$this_desktop" && bspc node "$parent_id" -d "$this_desktop"
bspc node "$parent_id" -f
sed -i "/^$child_id/d" "$ids"
}
# bspwm event handler
pgrep bspc && exit
bspc subscribe node_presel node_add node_remove node_flag |
while read -r msg; do
set -- $msg
case "$1" in
node_presel) save_presel "$4" "$5" ;;
node_add) swallow "$5" "$3" "$4";;
node_remove) spit "$4" "$3" ;;
esac
done &
I have several (~10) tiled windows on my desktop, and I no longer need one of these windows. I need start an application which will create a new window. I would like the new window to replace the window that I no longer need.
I have tried to do this "manually" by:
My problem is that after closing the no-longer-needed window, focus passes back to the most-recently-focused window (which I presume is by design) so that my new window appears elsewhere (not where my now-closed-window was).
Is there some clever way of achieving this?
TIA