haskellwindowx11xmonad

Start applications on specific workspace if not yet started there


In short: when I switch to workspace X, I want some programs to autostart, but only if they're not already started.

This is different from XMonad startup on different workspaces as I don't want to move windows to specific workspaces (like always moving xterm to workspace 2).
This doesn't work for me, either: xmonad spawn on startup in different workspace. I don't want all applications to start immediately as I log in, also this won't autostart e.g. xterm if I close it and switch to workspace 2 again.


Enough about what doesn't work, here is what does work:
(almost)

In my workspace list I hold touples with the workspace name and a list programs to start when I switch there:

myWorkspaces = [ ("VIM", ["gvim"]), ("TERM",[myTerminal ++ " -e tmux"]) ]

-- In my keybindings:
[ ((mod4Mask, key), loadWorkspace workspace cmd)
  | (key, (workspace, cmd)) <- zip [xK_1..] myWorkspaces
]

I defined a function to switch to a workspace and spawn the given programs:

loadWorkspace :: String -> [String] -> X()
loadWorkspace workspace commands =
    do windows $ W.greedyView workspace
       mapM_ spawn filtered_commands
           where filtered_commands :: X [String]
                 filtered_commands = filterM isNotOpen commands

                 isNotOpen :: String -> X Bool
                 isNotOpen command = return True

(For some reason mapM_ requires the second argument to be a String instead of [String]. I want to map spawn over the strings in filtered_commands, any idea why this doesn't work?)

The last missing piece is the isNotOpen function, which should search the classNames of the windows in the current workspace and return whether command is already there.


I find it extremely hard (compared to other languages and technologies) to search for the XMonad way to do things. For this case I could only find how to get the windows in the current WS - https://superuser.com/a/852152/481701. Ok, I think, this gives me a Window object, I can query it for some attributes.

But no. The Window is actually... alias for Word64!!! Ok, I think. Google xmonad get window attributes. Nothing. xmonad get classname from window id. Nothing. xmonad window information. And a dozen other ways to say something similar - no helpful results. All I get is the xmonad homepage, the FAQ, or "Xmonad configuration tips".
I tried these in hayoo!, too, and the closest I could get was "fromClassName - Colorize a window depending on it's className.". Haha.

So, how can I get a window's className (or any other attributes) outside of ManageHook?


Solution

  • You might like dynamic projects or topic spaces as prebaked alternatives. They don't do exactly what you propose, but perhaps one of them is close enough to still be useful, and require less configuration work.

    I want to map spawn over the strings in filtered_commands, any idea why this doesn't work?

    Yep, you need to lift mapM_ to handle a monadic argument (as opposed to a monadic function or return value). Thus:

    filtered_commands >>= mapM_ spawn
    

    Or, since you are already in a do block:

    result_of_filtered_commands <- filtered_commands
    mapM_ spawn result_of_filtered_commands
    

    So, how can I get a window's className (or any other attributes) outside of ManageHook?

    Look at the source of className:

    className = ask >>= (\w -> liftX $ withDisplay $ \d -> fmap resClass $ io $ getClassHint d w)
    

    You can take just the argument to liftX as an X action rather than a Query action. The key function is getClassHint from the X11 package. That package also offers access to other attributes of windows.