baskerville / bspwm

A tiling window manager based on binary space partitioning
BSD 2-Clause "Simplified" License
7.73k stars 414 forks source link

Issue with `bspc subscribe --fifo` #1390

Closed andrew-grechkin closed 2 years ago

andrew-grechkin commented 2 years ago

Subscribing to events in FIFO is convenient if it's necessary to process them.

I'm trying to understand the events format and doing the simple test:

$ bspc subscribe --fifo
/run/user/1027/bspwm_fifo.rCRMZ1

$ cat /run/user/1027/bspwm_fifo.rCRMZ1
WMeDP-1:f1:f2:f3:f4:f5:f6:f7:f8:f9:O0:LT:TT:G
WMeDP-1:f1:f2:f3:f4:f5:f6:f7:f8:f9:O0:LT:TT:G
WMeDP-1:f1:f2:f3:f4:f5:f6:f7:f8:f9:O0:LT:TT:G
WMeDP-1:f1:f2:f3:f4:f5:f6:f7:f8:f9:O0:LT:TT:G
WMeDP-1:f1:f2:f3:f4:f5:f6:f7:f8:f9:O0:LT:TT:G
WMeDP-1:f1:f2:f3:f4:f5:f6:f7:f8:f9:O0:LT:TT:G
WMeDP-1:f1:f2:f3:f4:f5:f6:f7:f8:f9:O0:LT:TT:G
WMeDP-1:f1:f2:f3:f4:f5:f6:f7:f8:f9:O0:LT:TT:G
WMeDP-1:f1:f2:f3:f4:f5:f6:f7:f8:f9:O0:LT:TT:G
WMeDP-1:f1:o2:f3:f4:f5:f6:f7:f8:f9:O0:LT:TT:G

I see the events are sent but all of them are equal. Doesn't matter what i'm doing: adding node, removing or just focus. Is there anything I'm doing wrong or subscribe --fifo has issues?

emanuele6 commented 2 years ago

Subscribing to events in FIFO is convenient if it's necessary to process them.

Not really...

Most times, you can just pipe the output of bspc subscribe to your program:

#!/bin/sh --
bspc subscribe report | some_program
# or
#bspc subsribe node_add | some_program
# or...

You would only need to use --fifo if you need a named pipe because you need to pass that pipe to a program as an argument; e.g.:

#!/bin/sh --
some_program --events-from-file "$(bspc subscribe --fifo node_add)"

Or if you need to pass multiple of these pipes to a scripts, or if you need to pass these pipes to a script that needs stdin for something else:

#!/bin/sh --
my_script \
  --bspwm-pipe "$(bspc subscribe --fifo report)" \
  --some-other-pipe /path/to/some/pipe
#!/bin/sh --
cd -- ~/pix || exit

find . -type f -name '*.png' '!' -path '*
*' | my_script "$(bspc subscribe --fifo desktop_focus)"

This is quite a niche use case.

But even in this case, I would suggest to use something like this instead to create the named pipe:

#!/bin/sh --
bspwmpipepath=/tmp/my_script_tmppipe
clockpipepath=/tmp/my_script_tmppipe
trap 'rm -f -- "$bspwmpipepath" "$clockpipepath"' EXIT
mkfifo -- "$bspwmpipepath" "$clockpipepath" || exit

bspc subscribe report > "$bspwmpipepath" &
clock -s > "$clockpipepath" &
my_script --bspwm-pipe "$bspwmpipepath" --clock-pipe "$clockpipepath"

If you have bash, you can simply use process substitution:

#!/bin/bash --
my_script --bspwm-pipe <(bspc subscribe report) --clock-pipe <(clock -s)

bspc subscribe --fifo may be nice so you don't have to create a named pipe yourself with mkfifo that you will then have to delete.

But in bash with <(), you don't have to worry about that since bash will delete the named pipe automatically, that is if an actual named pipe is created at all since, on linux at least, bash will just use linux's procfs's named pipes.

bspc subscribe --fifo is quite terrible since bspwm will hang until the named pipe at the path it outputted is not opened for reading; any mouse click will not be handled, all your bspc commands (so also your sxhkd hotkeys that use bspc commands) will just hang, &c until the pipe is finally opened by some process and they will be handled and executed at once.

You can try by running bspc subscribe --fifo in a terminal and then clicking around, nothing will work, until you run cat /path/to/that/file (you can use the same terminal) and all the clicks will be handled at once (in order).

That is the reason why using $(bspc subscribe --fifo) more than once without opening the file at the path returned by the first one will cause a deadlock; e.g.:

#!/bin/sh --
some_program -- "$(bspc subscribe --fifo report)" "$(bspc subscribe --fifo report)"

The second bspc subscribe --fifo will hang since bspwm can't respond to it, because it is hanging waiting for the named pipe at the path returned by the first bspc subscribe --fifo to be opened, which can't be done by some_program since the shell didn't start it yet, because the second bspc subscribe --fifo is hanging.

Process substitution and bspc subscribe > pipe &; ... pipe don't cause bspwm to hang:

#!/bin/bash --
some_program <(bspc subscribe report) <(bspc subscribe report)
# or
##!/bin/sh --
#trap 'rm -f pipe1 pipe2' EXIT
#mkfifo pipe1 pipe2 || exit
#bspc subscribe report > pipe1 &
#bspc subscribe report > pipe2 &
#some_program pipe1 pipe2

And if you run someprogramyoudontcontrol --pipe "$(bspc subscribe --fifo)" you have to hope that program will open the pipe that soon enough and that it will open it at all instead of printing Invalid option: '--piep' and hiding from you the path that you now have to open to fix bspwm being hung. (you can probably use ls /run/user/"$UID" to figure out what pipe you need to open in this case.)

I suggest to avoid subscribe --fifo (use it only if you actually need to create a direct pipe with bspwm (for some reason?)) since there better options that don't hang bspwm (indirect pipe connected to the output of bspc subscribe that receives data from bspwm through a UNIX socket), and a named pipe is rarely needed anyway as I said at the beginning.


I'm trying to understand the events format and doing the simple test:

You can just read the manual, it is documented quite well there (except for not specifying what T, and M; S, P, L, and M; and T, P, F, =, and @ mean, but you can easily figure those out):

REPORT FORMAT
       Each report event message is composed of items separated by colons.

       Each item has the form <type><value> where <type> is the first
       character of the item.

       M<monitor_name>
           Focused monitor.

       m<monitor_name>
           Unfocused monitor.

       O<desktop_name>
           Occupied focused desktop.

       o<desktop_name>
           Occupied unfocused desktop.

       F<desktop_name>
           Free focused desktop.

       f<desktop_name>
           Free unfocused desktop.

       U<desktop_name>
           Urgent focused desktop.

       u<desktop_name>
           Urgent unfocused desktop.

       L(T|M)
           Layout of the focused desktop of a monitor.

       T(T|P|F|=|@)
           State of the focused node of a focused desktop.

       G(S?P?L?M?)
           Active flags of the focused node of a focused desktop.
  • readable online here

I see the events are sent but all of them are equal. Doesn't matter what i'm doing: adding node, removing or just focus.

As bspc subscribe report is implemented now. bspwm will sending a report string anytime any event happens that could change it (node_focus, desktop_focus, desktop_add, etc.) occurs even if the report string didn't actually change.

All the events that bspwm reports are listed in the manual (readable online here), you can experiment with them by running bspc subscribe all in a terminal (you are not using --fifo so don't worry ;)) and then clicking and moving things around.

As you can tell from the description above quoted from the manual, the string did not change because you were only clicking on other tiled windows with no flags set in the same desktop.

If, for example, you had clicked on a floating window (with no flags set) or changed the state of the focused window to floating, it would have been slightly different:

WMeDP-1:f1:f2:f3:f4:f5:f6:f7:f8:f9:O0:LT:TF:G

Or, if you had focused desktop 2:

# if it is a desktop in tiled layout
WMeDP-1:f1:F2:f3:f4:f5:f6:f7:f8:f9:o0:LT

# if it is a desktop in monocle layout
WMeDP-1:f1:F2:f3:f4:f5:f6:f7:f8:f9:o0:LM
andrew-grechkin commented 2 years ago

thanks a lot @emanuele6 for the explanation now it's clear that subscribe --fifo is not what I have anticipated