From 3e5824a590c77c31e2393d461ef0b895766a3287 Mon Sep 17 00:00:00 2001 From: Daniele Fucini Date: Sat, 24 Oct 2026 20:27:52 +0200 Subject: [PATCH] Keep the games workspace on the HDMI screen Wine games lose the mouse when their window moves between screens. safeView replaces greedyView for mod-N, xmobar clicks and mpv so workspace 3 always opens on screen 0 and is never swapped away; safeRescreen keeps a hidden workspace 3 off the laptop screen when screens change. --- .config/xmonad/xmonad.hs | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/.config/xmonad/xmonad.hs b/.config/xmonad/xmonad.hs index c739d6a..f84a330 100644 --- a/.config/xmonad/xmonad.hs +++ b/.config/xmonad/xmonad.hs @@ -4,6 +4,7 @@ import Data.Monoid import Graphics.X11.ExtraTypes.XF86 import Control.Monad (forM_, liftM2, when) import XMonad +import XMonad.Actions.OnScreen (greedyViewOnScreen) import XMonad.Actions.PhysicalScreens import XMonad.Hooks.EwmhDesktops import XMonad.Hooks.ManageDocks @@ -34,10 +35,10 @@ main :: IO () main = xmonad . ewmhFullscreen - . setEwmhSwitchDesktopHook W.greedyView + . setEwmhSwitchDesktopHook safeView . ewmh . docks - . addAfterRescreenHook restartStatusBars + . rescreenHook def {afterRescreenHook = restartStatusBars, rescreenWorkspacesHook = Last (Just safeRescreen)} . addRandrChangeHook (spawn myScreenHotplug) $ myConfig @@ -145,6 +146,32 @@ myConfig = | (key, sc) <- zip [xK_w, xK_e] [0 ..], (f, mask) <- [(viewScreen def, 0), (sendToScreen def, shiftMask)] ] + ++ [((myModMask, key), windows $ safeView ws) | (ws, key) <- zip myWorkspaces [xK_1 .. xK_9]] + +-- greedyView that keeps wsGames on screen 0 (HDMI): Wine games lose the mouse when moved between screens +safeView :: WorkspaceId -> WindowSet -> WindowSet +safeView i ws + | i == wsGames = greedyViewOnScreen 0 i ws + | W.currentTag ws == wsGames && i `elem` map (W.tag . W.workspace) (W.visible ws) = W.view i ws + | otherwise = W.greedyView i ws + +-- xmonad's rescreen, except that a hidden wsGames is never put on a secondary screen +safeRescreen :: X () +safeRescreen = do + screens <- withDisplay getCleanedScreenInfo + case screens of + [] -> return () + xinesc : xinescs -> + windows $ \ws -> + let notGames = (/= wsGames) . W.tag + pool = map W.workspace (W.visible ws) ++ filter notGames (W.hidden ws) + (xs, _) = splitAt (length xinescs) pool + shown = map W.tag (W.workspace (W.current ws) : xs) + in ws + { W.current = W.Screen (W.workspace (W.current ws)) 0 (SD xinesc), + W.visible = zipWith3 W.Screen xs [1 ..] (map SD xinescs), + W.hidden = filter ((`notElem` shown) . W.tag) (map W.workspace (W.visible ws) ++ W.hidden ws) + } -- Workspaces myWorkspaces :: [String] @@ -291,7 +318,7 @@ myManageHook = isFullscreen --> doFullFloat ] <+> namedScratchpadManageHook myScratchpads - where viewShift = doF . liftM2 (.) W.greedyView W.shift + where viewShift = doF . liftM2 (.) safeView W.shift -- Handle event hook myHandleEventHook :: Event -> X All