mirror of
https://github.com/xmonad/xmonad-contrib.git
synced 2025-05-19 11:30:22 -07:00
The documentation for this module was lacking, making it significantly harder to use than the functionality wise very similar X.A.CycleRecentWS—change that.
127 lines
4.3 KiB
Haskell
127 lines
4.3 KiB
Haskell
-----------------------------------------------------------------------------
|
|
-- |
|
|
-- Module : XMonad.Actions.CycleWorkspaceByScreen
|
|
-- Description : Cycle workspaces in a screen-aware fashion.
|
|
-- Copyright : (c) 2017 Ivan Malison
|
|
-- License : BSD3-style (see LICENSE)
|
|
--
|
|
-- Maintainer : IvanMalison@gmail.com
|
|
-- Stability : unstable
|
|
-- Portability : unportable
|
|
--
|
|
-- Cycle through previously viewed workspaces in the order they were viewed most
|
|
-- recently on the screen where cycling is taking place.
|
|
--
|
|
-----------------------------------------------------------------------------
|
|
|
|
module XMonad.Actions.CycleWorkspaceByScreen (
|
|
-- * Usage
|
|
-- $usage
|
|
cycleWorkspaceOnScreen
|
|
, cycleWorkspaceOnCurrentScreen
|
|
, handleKeyEvent
|
|
, repeatableAction
|
|
) where
|
|
|
|
import Data.IORef
|
|
|
|
import Graphics.X11.Xlib.Extras
|
|
|
|
import XMonad
|
|
import XMonad.Prelude
|
|
import XMonad.Hooks.WorkspaceHistory
|
|
import qualified XMonad.StackSet as W
|
|
|
|
-- $usage
|
|
--
|
|
-- To use this module, first import it as well as
|
|
-- "XMonad.Hooks.WorkspaceHistory":
|
|
--
|
|
-- > import XMonad.Hooks.WorkspaceHistory (workspaceHistoryHook)
|
|
-- > import XMonad.Actions.CycleWorkspaceByScreen
|
|
--
|
|
-- Then add 'workspaceHistoryHook' to your @logHook@ like this:
|
|
--
|
|
-- > main :: IO ()
|
|
-- > main = xmonad $ def
|
|
-- > { ...
|
|
-- > , logHook = workspaceHistoryHook >> ...
|
|
-- > }
|
|
--
|
|
-- Finally, define a new keybinding for cycling (seen) workspaces per
|
|
-- screen:
|
|
--
|
|
-- > , ((mod4Mask, xK_slash), cycleWorkspaceOnCurrentScreen [xK_Super_L] xK_slash xK_p)
|
|
|
|
repeatableAction :: [KeySym] -> (EventType -> KeySym -> X ()) -> X ()
|
|
repeatableAction mods pressHandler = do
|
|
XConf {theRoot = root, display = d} <- ask
|
|
let getNextEvent = io $ allocaXEvent $ \p ->
|
|
do
|
|
maskEvent d (keyPressMask .|. keyReleaseMask) p
|
|
KeyEvent {ev_event_type = t, ev_keycode = c} <- getEvent p
|
|
s <- io $ keycodeToKeysym d c 0
|
|
return (t, s)
|
|
handleEvent (t, s)
|
|
| t == keyRelease && s `elem` mods = return ()
|
|
| otherwise = pressHandler t s >> getNextEvent >>= handleEvent
|
|
|
|
io $ grabKeyboard d root False grabModeAsync grabModeAsync currentTime
|
|
getNextEvent >>= handleEvent
|
|
io $ ungrabKeyboard d currentTime
|
|
|
|
handleKeyEvent :: EventType
|
|
-> KeySym
|
|
-> X ()
|
|
-> EventType
|
|
-> KeySym
|
|
-> Maybe (X ())
|
|
handleKeyEvent eventType key action = helper
|
|
where
|
|
helper et k
|
|
| et == eventType && k == key = Just action
|
|
| otherwise = Nothing
|
|
|
|
|
|
runFirst :: [EventType -> KeySym -> Maybe (X ())] -> EventType -> KeySym -> X ()
|
|
runFirst matchers eventType key =
|
|
fromMaybe (return ()) $ join $ find isJust $ map (\fn -> fn eventType key) matchers
|
|
|
|
-- | Like 'XMonad.Actions.CycleRecentWS.cycleRecentWS', but only cycle
|
|
-- through the most recent workspaces on the given screen.
|
|
cycleWorkspaceOnScreen
|
|
:: ScreenId -- ^ The screen to cycle on.
|
|
-> [KeySym] -- ^ A list of modifier keys used when invoking this
|
|
-- action; as soon as one of them is released, the final
|
|
-- switch is made.
|
|
-> KeySym -- ^ Key used to switch to next workspace.
|
|
-> KeySym -- ^ Key used to switch to previous workspace.
|
|
-> X ()
|
|
cycleWorkspaceOnScreen screenId mods nextKey prevKey = workspaceHistoryTransaction $ do
|
|
startingHistory <- workspaceHistoryByScreen
|
|
currentWSIndex <- io $ newIORef 1
|
|
let cycleWorkspaces = fromMaybe [] $ lookup screenId startingHistory
|
|
getAndIncrementWS increment = do
|
|
current <- readIORef currentWSIndex
|
|
modifyIORef
|
|
currentWSIndex
|
|
((`mod` length cycleWorkspaces) . (+ increment))
|
|
return $ cycleWorkspaces !! current
|
|
focusIncrement i = io (getAndIncrementWS i) >>= (windows . W.greedyView)
|
|
|
|
focusIncrement 1 -- Do the first workspace cycle
|
|
repeatableAction mods $
|
|
runFirst
|
|
[ handleKeyEvent keyPress nextKey $ focusIncrement 1
|
|
, handleKeyEvent keyPress prevKey $ focusIncrement (-1)
|
|
]
|
|
return ()
|
|
|
|
-- | Like 'cycleWorkspaceOnScreen', but supply the currently focused
|
|
-- screen as the @screenId@.
|
|
cycleWorkspaceOnCurrentScreen
|
|
:: [KeySym] -> KeySym -> KeySym -> X ()
|
|
cycleWorkspaceOnCurrentScreen mods n p =
|
|
withWindowSet $ \ws ->
|
|
cycleWorkspaceOnScreen (W.screen $ W.current ws) mods n p
|