diff --git a/CHANGES.md b/CHANGES.md index 3093117f..329dacac 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -44,6 +44,9 @@ - Added a customization option for the action that gets executed when a client sends a **_NET_CURRENT_DESKTOP** request. It is now possible to change it using the `setEwmhSwitchDesktopHook`. + - Added a customization option for mapping hidden workspaces to screens + when setting the **_NET_DESKTOP_VIEWPORT**. This can be done using + the `setEwmhHiddenWorkspaceToScreenMapping`. * `XMonad.Layout.IndependentScreens` @@ -51,6 +54,7 @@ belong to. - Added `doFocus'` hook as an alternative for `doFocus` when using IndependentScreens. + - Added `screenOnMonitor` for getting the active screen for a monitor. * `XMonad.Util.NamedScratchPad` diff --git a/XMonad/Hooks/EwmhDesktops.hs b/XMonad/Hooks/EwmhDesktops.hs index 056c7c43..f7238647 100644 --- a/XMonad/Hooks/EwmhDesktops.hs +++ b/XMonad/Hooks/EwmhDesktops.hs @@ -54,6 +54,9 @@ module XMonad.Hooks.EwmhDesktops ( -- $customManageDesktopViewport disableEwmhManageDesktopViewport, + -- $customHiddenWorkspaceMapper + setEwmhHiddenWorkspaceToScreenMapping, + -- * Standalone hooks (deprecated) ewmhDesktopsStartup, ewmhDesktopsLogHook, @@ -122,6 +125,8 @@ data EwmhDesktopsConfig = -- ^ configurable action for handling _NET_CURRENT_DESKTOP , manageDesktopViewport :: Bool -- ^ manage @_NET_DESKTOP_VIEWPORT@? + , hiddenWorkspaceToScreen :: WindowSet -> WindowSpace -> WindowScreen + -- ^ map hidden workspaces to screens for @_NET_DESKTOP_VIEWPORT@ } instance Default EwmhDesktopsConfig where @@ -132,6 +137,8 @@ instance Default EwmhDesktopsConfig where , fullscreenHooks = (doFullFloat, doSink) , switchDesktopHook = W.view , manageDesktopViewport = True + -- Hidden workspaces are mapped to the current screen by default. + , hiddenWorkspaceToScreen = \winset _ -> W.current winset } @@ -316,6 +323,34 @@ disableEwmhManageDesktopViewport :: XConfig l -> XConfig l disableEwmhManageDesktopViewport = XC.modifyDef $ \c -> c{ manageDesktopViewport = False } +-- $customHiddenWorkspaceMapper +-- +-- Mapping the hidden workspaces to the current screen is a good default behavior, +-- but it makes the assumption that workspaces don't belong to a sepcific screen. +-- If the default behaviour is undesired, for example when using "XMonad.Layout.IndependentScreens", +-- it can be customized. +-- +-- The following example demonstrates a way to configure the mapping when using "XMonad.Layout.IndependentScreens": +-- +-- > import XMonad.Layout.IndependentScreens +-- > +-- > customMapper :: WindowSet -> (WindowSpace -> WindowScreen) +-- > customMapper winset (Workspace wsid _ _) = fromMaybe (W.current winset) maybeMappedScreen +-- > where +-- > screenId = unmarshallS wsid +-- > maybeMappedScreen = screenOnMonitor screenId winset +-- > +-- > +-- > main = xmonad $ ... . setEwmhHiddenWorkspaceToScreenMapping customMapper . ewmh . ... $ def{...} + +-- | Set (replace) the function responsible for mapping the hidden workspaces to screens. +setEwmhHiddenWorkspaceToScreenMapping :: (WindowSet -> (WindowSpace -> WindowScreen)) + -- ^ Function that given the current WindowSet + -- produces a function to maps a (hidden) workspace to a screen. + -> XConfig l -> XConfig l +setEwmhHiddenWorkspaceToScreenMapping mapper = XC.modifyDef $ \c -> c{ hiddenWorkspaceToScreen = mapper } + + -- | Initializes EwmhDesktops and advertises EWMH support to the X server. {-# DEPRECATED ewmhDesktopsStartup "Use ewmh instead." #-} ewmhDesktopsStartup :: X () @@ -390,7 +425,7 @@ whenChanged :: (Eq a, ExtensionClass a) => a -> X () -> X () whenChanged = whenX . XS.modified . const ewmhDesktopsLogHook' :: EwmhDesktopsConfig -> X () -ewmhDesktopsLogHook' EwmhDesktopsConfig{workspaceSort, workspaceRename, manageDesktopViewport} = withWindowSet $ \s -> do +ewmhDesktopsLogHook' EwmhDesktopsConfig{workspaceSort, workspaceRename, manageDesktopViewport, hiddenWorkspaceToScreen} = withWindowSet $ \s -> do sort' <- workspaceSort let ws = sort' $ W.workspaces s @@ -455,18 +490,20 @@ ewmhDesktopsLogHook' EwmhDesktopsConfig{workspaceSort, workspaceRename, manageDe when manageDesktopViewport $ do let visibleScreens = W.current s : W.visible s currentTags = map (W.tag . W.workspace) visibleScreens - whenChanged (MonitorTags currentTags) $ mkViewPorts s (map W.tag ws) + whenChanged (MonitorTags currentTags) $ mkViewPorts s hiddenWorkspaceToScreen (map W.tag ws) -- | Create the viewports from the current 'WindowSet' and a list of -- already sorted workspace IDs. -mkViewPorts :: WindowSet -> [WorkspaceId] -> X () -mkViewPorts winset = setDesktopViewport . concat . mapMaybe (viewPorts M.!?) +mkViewPorts :: WindowSet -> (WindowSet -> WindowSpace -> WindowScreen) -> [WorkspaceId] -> X () +mkViewPorts winset hiddenWorkspaceMapper = setDesktopViewport . concat . mapMaybe (viewPorts M.!?) where foc = W.current winset - -- Hidden workspaces are mapped to the current screen's viewport. viewPorts :: M.Map WorkspaceId [Position] viewPorts = M.fromList $ map mkVisibleViewPort (foc : W.visible winset) - ++ map (mkViewPort foc) (W.hidden winset) + ++ map (uncurry mkViewPort) hiddenWorkspacesWithScreens + + hiddenWorkspacesWithScreens :: [(WindowScreen,WindowSpace)] + hiddenWorkspacesWithScreens = map (\x -> (hiddenWorkspaceMapper winset x, x)) (W.hidden winset) mkViewPort :: WindowScreen -> WindowSpace -> (WorkspaceId, [Position]) mkViewPort scr w = (W.tag w, mkPos scr) diff --git a/XMonad/Layout/IndependentScreens.hs b/XMonad/Layout/IndependentScreens.hs index 62e2de2a..92abf6f0 100644 --- a/XMonad/Layout/IndependentScreens.hs +++ b/XMonad/Layout/IndependentScreens.hs @@ -26,7 +26,7 @@ module XMonad.Layout.IndependentScreens ( marshallPP, whenCurrentOn, countScreens, - workspacesOn, + workspacesOn, screenOnMonitor, workspaceOnScreen, focusWindow', doFocus', focusScreen, focusWorkspace, nthWorkspace, withWspOnScreen, -- * Converting between virtual and physical workspaces -- $converting @@ -148,7 +148,7 @@ withWspOnScreen screenId operation ws = case workspaceOnScreen screenId ws of Just wsp -> operation wsp ws Nothing -> ws --- | Get the workspace that is active on a given screen. +-- | Get the screen that is active on a given monitor. screenOnMonitor :: ScreenId -> WindowSet -> Maybe WindowScreen screenOnMonitor screenId ws = find ((screenId ==) . W.screen) (W.current ws : W.visible ws)