../notes
source

window tags

Thoughts after 5 years

Published 2025-08-14, last edit 2025-08-18

I used to be a multi-screen maximalist. Everyone knows the more monitors you have the more powerful you are, right? I ran a triple-head setup turned in various ways, and it came with it’s own challenges for my wm management and window wants. One day I saw someone talking about their single monitor workflow and they said it helped them focus. After some reflection I came to the conclusion they were right - even if I’m referencing docs, having windows side by side rather than splatted helps me hone in on what matters. I would have to be a little more intentional with what is on the single screen in front of me instead of just splatting things into whatever space is available.

And so (initially as an experiment) I went from 3 mid monitors to one really nice monitor. Many edge cases left my dotfiles. I didn’t have to worry about lemonbar’s -g flag behaving oddly anymore. When the border of the monitor is the edge of the total display, you don’t have to worry about pseudo-borders for things like window movement scripts. All in all it was a great success! The result was a calmer, more focused desktop experience.

Around 2020 I saw a talk about the hikari wayland compositor and it mentioned taking great inspo from cwm, a window group wm in the openbsd world. I did some further digging and thought that window groups might be a fine thing to have, and it might stack further into the single-monitor feels described above - after all, you go from N virtual desktops to just 1, with tags for summoning or dismissing things at will. Thus the latter half of 2020 saw a lot of tag/group experiments for me, jamming the concept into bspwm with a script, currently called btags. bspc can hide windows by toggling a hidden flag on them - After ~6 months of messing with the concept, things largely stabilized, though I did come back to tweak the flow once or twice in the 5 years since.

So.. What worked? What didn’t?

∗ ∗ ∗

Overview:#

  • I have 4 tags
  • Tags have their own associated border color
  • Toggling a tag just means flipping the hidden flag with bspc
  • I still tile my windows, am not interested in a floating experience

Ideas that worked#

The hole, and dismissal#

The 4th tag is my “hole” tag. It’s where I banish windows I don’t want to see, but still keep them open - things like a torrent client, spare emacs window, or steam. After a few years, I realized I needed a “dismiss” notion in all this. Something to say “idc where this window goes, but not here”. Adding it made my experience much smoother pretty much right away.

Standard roles for tags#

My tags uses are pretty much always:

tag use name
1 emacs/code code
2 qutebrowser net
3 misc: chat, osrs, a document misc
4 the hole hole

This means that I can always hit Alt+1 to see/cycle through emacs windows, or 2 for browsing. This predictability is extremely nice, I can always go to either without thinking much about it. Summon chat for a second to type something and then dismiss it? donezo.

Subscription#

Subscribing to bspwm events allows me to automatically assign tags to windows based on their WM_CLASS, or inherit the value from the currently focused tag. This means I don’t have to assign window tags often, things go where they should (ready to be summoned without thought)

Showing how I get the info to make those decisions:

bspc subscribe node_add | while read -r event m d i wid; do
    current_class=$(xprop WM_CLASS -id $wid)
    current_name=$(xprop WM_NAME -id $wid)
    last_class=$(xprop WM_CLASS -id $(bspc query -N last -n))
    # ...
done

Window border colors from tag#

Using distinct colors, I can tell assigned tags at a glance (drawn with chwbn):

btags.png

From the top left clockwise: net, code, code, hole

# tag, visible, border color, wids
$ btags state-plain
code    true    e9a4d1  0x01ACB110 0x01AD21ED
net     true    7bcc7b  0x01E00013
chat    false   98bde1
hole    true    b9b9b9  0x01AE254F
none    true    000000  0x0340003B

Fishing#

I have a script called find_class that finds and shows a WM_CLASS, unhiding it if it is hidden - it does not touch the tag toggle state, which allows me to view a window in a hidden tag. Thus, I can summon steam from the hole without conjuring all the other windows I’ve thrown in there, and it returns on the next action that triggers a tag render.

Ideas that didn’t pan out#

Multiple tags per window#

I thought it would be neat to allow multiple tags/groups per window, but in practice this got messy super fast. Much easier to manage a single tag allowed per window, and then do tag juggling higher level commands.

Status lines#

I gave btags an option to match the output format of bspc subscribe initially, thinking it would be nice to plug and play into existing status bar helpers, but ultimately ended up implementing a more plain status reporter and using it in my panel

$ btags state
: WMDP-0:Fa:Ob:Fc:ohole:fd:LT:TT:G
$ btags state-plain
a       true    e9a4d1
b       true    7bcc7b  0x01A25F85 0x01E00013 0x01E00013 0x01A219FF
c       true    98bde1
hole    false   b9b9b9  0x0340003B 0x01A042CE
none    true    000000

Resize-averse applications#

In bspwm, showing/hiding a tiled node means re-inserting it into the tree, which can result in many resize events in nearby windows. Some programs (terminals, emacs, most websites) take this in stride, but occasionally you run into programs that don’t. The runelite runescape client was causing my entire wm to freeze when being resized so often for the show/hide action.

What might a return to virtual desktops look like for me?#

I’m writing this post because occasionally I feel like I should scrape this whole notion and return to a more traditional setup. Let’s think about it:

  • I’d miss the “summon browser” key via tag focus - would probably make it a search-for-browser instead?
  • The “hole” concept can still exist in an nth desktop, along with a dismissal notion
  • cycling between current window class could be a thing
  • I could get rid of btags and tag state most likely, simplify border handling (would only have to worry about one focused window, no multi-color drawing)
  • Would be a feeling of “going to” windows rather than summoning/dismissing them in one space
    • benefit: could leave some workspace in-progress with an idea alone for awhile and pick it right back up
  • Is it possible to have summon/dismiss notions with keybinds for desktop flicking and not have it be keybind hell? right now these things are conflated because it’s done via tags, so I don’t have to think about it, which is very nice.
  • Flicking through window class is more limited than a tagging notion because you get to tag windows in an adhoc fashion. Is there some world where I mix tags and desktops? I would want a way to show details of the current tab group next to the desktop status - perhaps in the panel.
  • One thing that would be missing/have to implement if I wanted it: per desktop layouts