From 8899078b00b21d5b36328eaabf208c3a5a2ba4df Mon Sep 17 00:00:00 2001 From: oogeek Date: Thu, 1 Apr 2021 00:49:58 +0800 Subject: [PATCH] X.L.IndependentScreens: Add workspacesOn, withScreen, fix marshallPP always sorting lexically - Added `workspacesOn` for filtering workspaces on the current screen. - Added `withScreen` to specify names for a given single screen. - Added new aliases `PhysicalWindowSpace` and `VirtualWindowSpace` for a `WindowSpace` for easier to read function signatures. - Fixed a bug where `marshallPP` always sorted workspace names lexically. Fixes: https://github.com/xmonad/xmonad-contrib/issues/420 --- CHANGES.md | 16 ++++++ XMonad/Actions/CopyWindow.hs | 2 +- XMonad/Config/Dmwit.hs | 2 +- XMonad/Layout/IndependentScreens.hs | 84 +++++++++++++++++++++-------- 4 files changed, 80 insertions(+), 24 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 675e80f8..4fd76aab 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -609,6 +609,22 @@ - The decoration window now sets a `WM_CLASS` property. This allows other applications, like compositors, to properly match on it. + * `XMonad.Layout.IndependentScreens` + + - Fixed a bug where `marshallPP` always sorted workspace names + lexically. This changes the default behaviour of `marshallPP`—the + given `ppSort` now operates in the _physical_ workspace names. + The documentation of `marshallSort` contains an example of how to + get the old behaviour, where `ppSort` operates in virtual names, + back. + + - Added `workspacesOn` for filtering workspaces on the current screen. + + - Added `withScreen` to specify names for a given single screen. + + - Added new aliases `PhysicalWindowSpace` and `VirtualWindowSpace` + for a `WindowSpace` for easier to read function signatures. + ## 0.16 ### Breaking Changes diff --git a/XMonad/Actions/CopyWindow.hs b/XMonad/Actions/CopyWindow.hs index f3d28ea0..055abc12 100644 --- a/XMonad/Actions/CopyWindow.hs +++ b/XMonad/Actions/CopyWindow.hs @@ -18,7 +18,7 @@ module XMonad.Actions.CopyWindow ( -- * Usage -- $usage copy, copyToAll, copyWindow, runOrCopy - , killAllOtherCopies, kill1 + , killAllOtherCopies, kill1, taggedWindows, copiesOfOn -- * Highlight workspaces containing copies in logHook -- $logHook , wsContainingCopies diff --git a/XMonad/Config/Dmwit.hs b/XMonad/Config/Dmwit.hs index 36886dd5..d5f4bd90 100644 --- a/XMonad/Config/Dmwit.hs +++ b/XMonad/Config/Dmwit.hs @@ -25,7 +25,7 @@ import XMonad.Hooks.DynamicLog import XMonad.Hooks.ManageDocks import XMonad.Hooks.ManageHelpers import XMonad.Layout.Grid -import XMonad.Layout.IndependentScreens +import XMonad.Layout.IndependentScreens hiding (withScreen) import XMonad.Layout.Magnifier import XMonad.Layout.NoBorders import XMonad.Prelude diff --git a/XMonad/Layout/IndependentScreens.hs b/XMonad/Layout/IndependentScreens.hs index 71ac9ce4..635cb722 100644 --- a/XMonad/Layout/IndependentScreens.hs +++ b/XMonad/Layout/IndependentScreens.hs @@ -17,15 +17,18 @@ module XMonad.Layout.IndependentScreens ( -- * Usage -- $usage VirtualWorkspace, PhysicalWorkspace, + VirtualWindowSpace, PhysicalWindowSpace, workspaces', - withScreens, onCurrentScreen, + withScreen, withScreens, + onCurrentScreen, marshallPP, whenCurrentOn, countScreens, + workspacesOn, -- * Converting between virtual and physical workspaces -- $converting marshall, unmarshall, unmarshallS, unmarshallW, - marshallWindowSpace, unmarshallWindowSpace, marshallSort + marshallWindowSpace, unmarshallWindowSpace, marshallSort, ) where -- for the screen stuff @@ -33,7 +36,7 @@ import Control.Arrow ((***)) import Graphics.X11.Xinerama import XMonad import XMonad.Prelude -import XMonad.StackSet hiding (filter, workspaces) +import qualified XMonad.StackSet as W import XMonad.Hooks.DynamicLog -- $usage @@ -78,6 +81,11 @@ import XMonad.Hooks.DynamicLog type VirtualWorkspace = WorkspaceId type PhysicalWorkspace = WorkspaceId +-- | A 'WindowSpace' whose tags are 'PhysicalWorkspace's. +type PhysicalWindowSpace = WindowSpace +-- | A 'WindowSpace' whose tags are 'VirtualWorkspace's. +type VirtualWindowSpace = WindowSpace + -- $converting -- You shouldn't need to use the functions below very much. They are used -- internally. However, in some cases, they may be useful, and so are exported @@ -100,13 +108,20 @@ unmarshallW = snd . unmarshall workspaces' :: XConfig l -> [VirtualWorkspace] workspaces' = nub . map unmarshallW . workspaces +-- | Specify workspace names for each screen +withScreen :: ScreenId -- ^ The screen to make workspaces for + -> [VirtualWorkspace] -- ^ The desired virtual workspace names + -> [PhysicalWorkspace] -- ^ A list of all internal physical workspace names +withScreen n vws = [marshall n pws | pws <- vws] + +-- | Make all workspaces across the monitors bear the same names withScreens :: ScreenId -- ^ The number of screens to make workspaces for -> [VirtualWorkspace] -- ^ The desired virtual workspace names -> [PhysicalWorkspace] -- ^ A list of all internal physical workspace names -withScreens n vws = [marshall sc pws | pws <- vws, sc <- [0..n-1]] +withScreens n vws = concatMap (`withScreen` vws) [0..n-1] onCurrentScreen :: (VirtualWorkspace -> WindowSet -> a) -> (PhysicalWorkspace -> WindowSet -> a) -onCurrentScreen f vws = screen . current >>= f . flip marshall vws +onCurrentScreen f vws = W.screen . W.current >>= f . flip marshall vws -- | In case you don't know statically how many screens there will be, you can call this in main before starting xmonad. For example, part of my config reads -- @@ -121,20 +136,25 @@ onCurrentScreen f vws = screen . current >>= f . flip marshall vws countScreens :: (MonadIO m, Integral i) => m i countScreens = fmap genericLength . liftIO $ openDisplay "" >>= liftA2 (<*) getScreenInfo closeDisplay --- | This turns a naive pretty-printer into one that is aware of the --- independent screens. That is, you can write your pretty printer to behave --- the way you want on virtual workspaces; this function will convert that --- pretty-printer into one that first filters out physical workspaces on other --- screens, then converts all the physical workspaces on this screen to their --- virtual names. +-- | This turns a pretty-printer into one that is aware of the independent screens. The +-- converted pretty-printer first filters out physical workspaces on other screens, then +-- converts all the physical workspaces on this screen to their virtual names. +-- Note that 'ppSort' still operates on physical (marshalled) workspace names, +-- otherwise functions from "XMonad.Util.WorkspaceCompare" wouldn't work. +-- If you need to sort on virtual names, see 'marshallSort'. -- --- For example, if you have handles @hLeft@ and @hRight@ for bars on the left and right screens, respectively, and @pp@ is a pretty-printer function that takes a handle, you could write +-- For example, if you have have two bars on the left and right screens, respectively, and @pp@ is +-- a pretty-printer, you could apply 'marshallPP' when creating a @StatusBarConfig@ from "XMonad.Hooks.StatusBar". +-- +-- A sample config looks like this: +-- +-- > mySBL = statusBarProp "xmobar" $ pure (marshallPP (S 0) pp) +-- > mySBR = statusBarProp "xmobar" $ pure (marshallPP (S 1) pp) +-- > main = xmonad $ withEasySB (mySBL <> mySBR) defToggleStrutsKey def -- --- > logHook = let log screen handle = dynamicLogWithPP . marshallPP screen . pp $ handle --- > in log 0 hLeft >> log 1 hRight marshallPP :: ScreenId -> PP -> PP marshallPP s pp = pp { ppRename = ppRename pp . unmarshallW - , ppSort = fmap (marshallSort s) (ppSort pp) } + , ppSort = (. workspacesOn s) <$> ppSort pp } -- | Take a pretty-printer and turn it into one that only runs when the current -- workspace is one associated with the given screen. The way this works is a @@ -161,7 +181,7 @@ whenCurrentOn s pp = pp { ppSort = do sortWs <- ppSort pp return $ \xs -> case xs of - x:_ | unmarshallS (tag x) == s -> sortWs xs + x:_ | unmarshallS (W.tag x) == s -> sortWs xs _ -> [] , ppOrder = \i@(wss:_) -> case wss of "" -> ["\0"] -- we got passed no workspaces; this is the signal from ppSort that this is a boring case @@ -171,11 +191,31 @@ whenCurrentOn s pp = pp _ -> ppOutput pp out } --- | If @vSort@ is a function that sorts 'WindowSpace's with virtual names, then @marshallSort s vSort@ is a function which sorts 'WindowSpace's with physical names in an analogous way -- but keeps only the spaces on screen @s@. -marshallSort :: ScreenId -> ([WindowSpace] -> [WindowSpace]) -> ([WindowSpace] -> [WindowSpace]) +-- | Filter workspaces that are on current screen. +workspacesOn :: ScreenId -> [PhysicalWindowSpace] -> [PhysicalWindowSpace] +workspacesOn s = filter (\ws -> unmarshallS (W.tag ws) == s) + +-- | @vSort@ is a function that sorts 'VirtualWindowSpace's with virtual names. +-- @marshallSort s vSort@ is a function which sorts 'PhysicalWindowSpace's with virtual names, +-- but keeps only the 'WindowSpace'\'s on screen @s@. +-- +-- NOTE: @vSort@ operating on virtual names comes with some caveats, see +-- for +-- more information. You can use 'marshallSort' like in the following example: +-- +-- === __Example__ +-- +-- > pp' :: ScreenId -> PP -> PP +-- > pp' s pp = (marshallPP s pp) { ppSort = fmap (marshallSort s) (ppSort pp) } +-- > +-- > mySBL = statusBarProp "xmobar" $ pure (pp' (S 0) pp) +-- > mySBR = statusBarProp "xmobar" $ pure (pp' (S 1) pp) +-- > main = xmonad $ withEasySB (mySBL <> mySBR) defToggleStrutsKey def +-- +-- In this way, you have a custom virtual names sort on top of 'marshallPP'. +marshallSort :: ScreenId -> ([VirtualWindowSpace] -> [VirtualWindowSpace]) -> ([PhysicalWindowSpace] -> [PhysicalWindowSpace]) marshallSort s vSort = pScreens . vSort . vScreens where - onScreen ws = unmarshallS (tag ws) == s - vScreens = map unmarshallWindowSpace . filter onScreen + vScreens = map unmarshallWindowSpace . workspacesOn s pScreens = map (marshallWindowSpace s) -- | Convert the tag of the 'WindowSpace' from a 'VirtualWorkspace' to a 'PhysicalWorkspace'. @@ -183,5 +223,5 @@ marshallWindowSpace :: ScreenId -> WindowSpace -> WindowSpace -- | Convert the tag of the 'WindowSpace' from a 'PhysicalWorkspace' to a 'VirtualWorkspace'. unmarshallWindowSpace :: WindowSpace -> WindowSpace -marshallWindowSpace s ws = ws { tag = marshall s (tag ws) } -unmarshallWindowSpace ws = ws { tag = unmarshallW (tag ws) } +marshallWindowSpace s ws = ws { W.tag = marshall s (W.tag ws) } +unmarshallWindowSpace ws = ws { W.tag = unmarshallW (W.tag ws) }