Xmonad: Spawnon Workspace That Had Focus When Spawn Key Was Pressed

XMonad: SpawnOn workspace that had focus when spawn key was pressed

I found the answer to my own question.

First you must add to your imports:

import XMonad.Actions.SpawnOn

Then under your main function have something like:

main = do
xmonad $ defaultConfig
{
manageHook = myManageHooks <+> manageSpawn <+> manageDocks <+> manageHook defaultConfig
, startupHook = myStartupHook
, ETC.....

The key here was the addition of the manageSpawn in the manageHook line.

Then replace your spawns with spawnHere:

  , ((modMask, xK_w), spawn "chromium")

Becomes:

  , ((modMask, xK_w), spawnHere "chromium")

XMonad spawn programs on startup in specified workspace

The common way is to use startupHook which takes X () action and performs it on each startup.
E.g.

main = xmonad $ defaultConfig
{ startupHook = do
spawnOn "workspace1" "program1"

spawnOn "workspaceN" "programN"
}

Move window to workspace and focus that workspace (shiftAndView) on XMonad WM

Thanks to people from Reddit this problem solved by a few lines of code. (Also @pmf answer works all right)

Here is the solution:

  1. First(best) solution:
^++^ subKeys "Workspaces" (
[ ("M-" ++ i, addName ("Switch to workspace " ++ i) (windows $ W.greedyView wsp)) | (i, wsp) <- zip (map show [1..9]) myWorkspaces]
++ [ ("M-S-" ++ i, addName ("Send to workspace " ++ i) (windows $ W.shift wsp)) | (i, wsp) <- zip (map show [1..9]) myWorkspaces]
)

^++^ subKeys "Window Management" (
[ -- other keys here ]
++ [ ("M-C-" ++ i, addName ("Send and switch to workspace " ++ i) (windows $ W.greedyView wsp . W.shift wsp)) | (i, wsp) <- zip (map show [1..9]) myWorkspaces]
)

  1. Second solution:
shiftAndView :: Int -> X ()
shiftAndView n = windows $ W.greedyView (myWorkspaces !! (n - 1))
. W.shift (myWorkspaces !! (n - 1))

  1. Third solution:
windows $ W.greedyView (myWorkspaces !! 2) . W.shift (myWorkspaces !! 2)

An explanation from RossOgilvie about how first solution works:

We started with a list of entries

[ ("M-1", addName "Switch to workspace 1"    $ (windows $ W.greedyView $ myWorkspaces !! 0))
, ("M-2", addName "Switch to workspace 2" $ (windows $ W.greedyView $ myWorkspaces !! 1))
, etc ]

So we see that each entry is mostly the same, but the number changes and the workspace changes. The idea is first make a list of the numbers and the workspaces, and then second make an entry for each of them. To make the first list we use

zip (map show [1..9]) myWorkspaces
= [("1", wsDo), ("2", wsBo), etc ]

A list comprehension is a lot like a foreach loop in other languages

[ g a | a <- alist ]
= for each a in alist, apply g to a, and make a list from the results.

So the final code we wrote was basically a list comprehension of the form

[ expression for the entry depending on i and wsp | (i,wsp) <- list of numbers and workspaces ]

I hope you see now why this makes the list of entries that we want.


Thanks to RossOgilvie and slinchisl from Reddit :)

How do I keep window in focus when moving it to another monitor?

It's not so clear to me what you really want. I am assuming you'd like to move the current focused windows to other workspace/monitor and keep the focus on that windows. Isn't it?

Looking at the snipet, I am not sure which keybindings you'd like. Let me explain

-- This comprehension list expands as below
[ ( (m .|. modm, key), screenWorkspace sc >>= flip whenJust (windows . f) )
| (key, sc) <- zip [xK_e, xK_w, xK_r] [0..]
, (f, m) <- [(W.view, 0), (W.shift, controlMask)]
]

-- mod + 0 + e moves focus to workspace 0 (but not the focused window)
-- mod + ctrl + e moves focused window to workspace 0 (but doesn't move the focus)
-- mod + 0 + w moves focus to workspace 1 (but not the focused window)
-- etc...
[ ( (0 .|. modm, xK_e), screenWorkspace 0 >>= flip whenJust (windows . W.view) )
, ( (controlMask .|. modm, xK_e), screenWorkspace 0 >>= flip whenJust (windows . W.shift) )
, ( (0 .|. modm, xK_w), screenWorkspace 1 >>= flip whenJust (windows . W.view) )
, ( (controlMask .|. modm, xK_w), screenWorkspace 1 >>= flip whenJust (windows . W.shift) )
, ( (0 .|. modm, xK_r), screenWorkspace 2 >>= flip whenJust (windows . W.view) )
, ( (controlMask .|. modm, xK_r), screenWorkspace 2 >>= flip whenJust (windows . W.shift) )
]

As you can see, you have different keybindigs for moving the focus, and moving the focused window. I guess that you want a single keybind to do both at the same time. And I assume that you want Mod+CTRL+w/e/r to move to other workspace. In that case you need to modify that list by the following

[ ( (controlMask .|. modm, key), screenWorkspace sc >>= flip whenJust (\wid -> windows $ W.view wid . W.shift wid) )
| (key, sc) <- zip [xK_e, xK_w, xK_r] [0..]
]

Since the code above is a little bit cryptic I'd recommend to define an auxiliar function at the top level

moveCurrentWindowsAndFocusIt :: WorkspaceId -> X ()
moveCurrentWindowsAndFocusIt wid = windows $ W.view wid . W.shift wid

-- This is the where your keybindings are
mykeybindings =
...
[ ( (controlMask .|. modm, key), screenWorkspace sc >>= flip whenJust moveCurrentWindowsAndFocusIt )
| (key, sc) <- zip [xK_e, xK_w, xK_r] [0..]
]

XMonad how can I focus on a particular window by name / class name?

module WindowFinder where

import XMonad
import qualified XMonad.StackSet as W
import Control.Monad
import Data.Bool (bool)

findWindows :: String -> X [Window]
findWindows name = do
withWindowSet $ (\ws -> do
forM (W.allWindows ws)
(\w -> do
s <- withDisplay $ \d -> fmap resClass . liftIO $ getClassHint d w
return $ bool [] [w] (s == name) :: X [Window]
) >>= return . join
)

And within a X () context:

        win' <- findWindows "Chromium"
when (length win' > 0)
(windows $ W.focusWindow $ head win')

The above seems to behave in quite a useful manner when there are multiple windows. The behavior seems to be, the first window returned is either the window currently open on the workspace, or the last interacted window of that applicaiton type.



Related Topics



Leave a reply



Submit