Search code examples
haskellxmonad

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


I'm using xmonad with 2 monitors and XMonad.Layout.IndependentScreens. It works mostly fine, but one problem I have is that when I move a window to another monitor, it looses focus

The code that is responsible for the placement is here:

     [((m .|. modm, key), screenWorkspace sc >>= flip whenJust (windows . f))
           | (key, sc) <- zip [xK_e, xK_w, xK_r] [0..] -- switched e and w to accomodate my monitor setup
           , (f, m) <- [(W.view, 0), (W.shift, controlMask)]]
  

However, I am very new to Haskell and cannot make any sense of it

How do I modify the code above to achieve what I want?


Solution

  • 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..] 
     ]