Monday, February 21, 2022

XMonad: giving a window affinity to live on a given workspace

I've been working on a project (http://usfirst.org) that combines vscode with a simulator to run Java locally. One small annoyance is that every time the program runs, the simulator opens a new window on the same desktop, but it's intended to be run full-screen. Since I'm running XMonad, I have to manually window-shift-number to send the simulator off to another workspace. That's the sort of annoyance I run my own window manager to deal with.

So let's deal with it.

First, we have to discriminate the simulator window from others. No major issue there; the xprop command-line tool lets us get details on the window. Just run and click.

> xprop
  WM_STATE(WM_STATE):
        window state: Normal
        icon window: 0x0
  _NET_WM_ICON_NAME(UTF8_STRING) = "Robot Simulation"
  _NET_WM_NAME(UTF8_STRING) = "Robot Simulation"
  WM_LOCALE_NAME(STRING) = "en_US.UTF-8"
  WM_CLIENT_MACHINE(STRING) = "rambler"
  WM_ICON_NAME(STRING) = "Robot Simulation"
  WM_NAME(STRING) = "Robot Simulation"
  XdndAware(ATOM) = BITMAP
  WM_CLASS(STRING) = "Robot Simulation", "Robot Simulation"
  WM_NORMAL_HINTS(WM_SIZE_HINTS):
        program specified location: 0, 0
        window gravity: Static
  WM_HINTS(WM_HINTS):
        Initial state is Normal State.
  _NET_WM_PID(CARDINAL) = 14024
  WM_PROTOCOLS(ATOM): protocols  WM_DELETE_WINDOW, _NET_WM_PING

The relevant detail here is WM_CLASS, which is the window class and appears to be the nice, stable string "Robot Simulation". Great!

XMonad includes manageHook rules that let us hook into the rules for window config. Documentation lives here; there's a lot, but the most relevant ones are that we can get the class of the window (className) and we can direct the window to go to a different workspace (doShift). The stanza is a simple piece of XMonad line noise:

windowAffinities = className =? "Robot Simulation" --> doShift "9"

... then just modify the top of my xmonad declaration to include that logic.

main = do
    xmproc <- spawnPipe "xmobar"

xmonad $ docks defaultConfig
     { manageHook = windowAffinities <+> manageDocks <+> manageHook defaultConfig

(Note: if you want more than one, the composeAll [ hooks ] grouping will do so. Just make sure the brackets [] get on their own lines, or Haskell will complain "parse error (possibly incorrect indentation or mismatched brackets)".

Added that stanza, a quick Windows-Q to reload the XMonad rules, and the next time the simulator opened, it opened on workspace 9. Just a little less typing to do what I mean.

No comments:

Post a Comment