    -----------------------------------------------------------------------------
    -- |
    -- 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           XMonad
    import           XMonad.Prelude
    import           XMonad.Hooks.WorkspaceHistory
    import           XMonad.Actions.Repeatable (repeatable)
    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)

    {-# DEPRECATED repeatableAction "Use XMonad.Actions.Repeatable.repeatable" #-}
    repeatableAction :: [KeySym] -> KeySym -> (EventType -> KeySym -> X ()) -> X ()
    repeatableAction :: [KeySym] -> KeySym -> (EventType -> KeySym -> X ()) -> X ()
    repeatableAction = [KeySym] -> KeySym -> (EventType -> KeySym -> X ()) -> X ()
    repeatable

    handleKeyEvent :: EventType
                   -> KeySym
                   -> X ()
                   -> EventType
                   -> KeySym
                   -> Maybe (X ())
    handleKeyEvent :: EventType -> KeySym -> X () -> EventType -> KeySym -> Maybe (X ())
    handleKeyEvent EventType
    eventType KeySym
    key X ()
    action = EventType -> KeySym -> Maybe (X ())
    helper
      where
      helper :: EventType -> KeySym -> Maybe (X ())
    helper EventType
    et KeySym
    k
        | EventType
    et EventType -> EventType -> Bool
    forall a. Eq a => a -> a -> Bool
    == EventType
    eventType Bool -> Bool -> Bool
    && KeySym
    k KeySym -> KeySym -> Bool
    forall a. Eq a => a -> a -> Bool
    == KeySym
    key = X () -> Maybe (X ())
    forall a. a -> Maybe a
    Just X ()
    action
        | Bool
    otherwise = Maybe (X ())
    forall a. Maybe a
    Nothing

    runFirst :: [EventType -> KeySym -> Maybe (X ())] -> EventType -> KeySym -> X ()
    runFirst :: [EventType -> KeySym -> Maybe (X ())]
    -> EventType -> KeySym -> X ()
    runFirst [EventType -> KeySym -> Maybe (X ())]
    matchers EventType
    eventType KeySym
    key =
      X () -> Maybe (X ()) -> X ()
    forall a. a -> Maybe a -> a
    fromMaybe (() -> X ()
    forall a. a -> X a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()) (Maybe (X ()) -> X ()) -> Maybe (X ()) -> X ()
    forall a b. (a -> b) -> a -> b
    $ Maybe (Maybe (X ())) -> Maybe (X ())
    forall (m :: * -> *) a. Monad m => m (m a) -> m a
    join (Maybe (Maybe (X ())) -> Maybe (X ()))
    -> Maybe (Maybe (X ())) -> Maybe (X ())
    forall a b. (a -> b) -> a -> b
    $ (Maybe (X ()) -> Bool) -> [Maybe (X ())] -> Maybe (Maybe (X ()))
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
    find Maybe (X ()) -> Bool
    forall a. Maybe a -> Bool
    isJust ([Maybe (X ())] -> Maybe (Maybe (X ())))
    -> [Maybe (X ())] -> Maybe (Maybe (X ()))
    forall a b. (a -> b) -> a -> b
    $ ((EventType -> KeySym -> Maybe (X ())) -> Maybe (X ()))
    -> [EventType -> KeySym -> Maybe (X ())] -> [Maybe (X ())]
    forall a b. (a -> b) -> [a] -> [b]
    map (\EventType -> KeySym -> Maybe (X ())
    fn -> EventType -> KeySym -> Maybe (X ())
    fn EventType
    eventType KeySym
    key) [EventType -> KeySym -> Maybe (X ())]
    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 -> [KeySym] -> KeySym -> KeySym -> X ()
    cycleWorkspaceOnScreen ScreenId
    screenId [KeySym]
    mods KeySym
    nextKey KeySym
    prevKey = X () -> X ()
    workspaceHistoryTransaction (X () -> X ()) -> X () -> X ()
    forall a b. (a -> b) -> a -> b
    $ do
      startingHistory <- X [(ScreenId, [WorkspaceId])]
    workspaceHistoryByScreen
      currentWSIndex <- io $ newIORef 1
      let cycleWorkspaces = [WorkspaceId] -> Maybe [WorkspaceId] -> [WorkspaceId]
    forall a. a -> Maybe a -> a
    fromMaybe [] (Maybe [WorkspaceId] -> [WorkspaceId])
    -> Maybe [WorkspaceId] -> [WorkspaceId]
    forall a b. (a -> b) -> a -> b
    $ ScreenId -> [(ScreenId, [WorkspaceId])] -> Maybe [WorkspaceId]
    forall a b. Eq a => a -> [(a, b)] -> Maybe b
    lookup ScreenId
    screenId [(ScreenId, [WorkspaceId])]
    startingHistory
          getAndIncrementWS Int
    increment = do
            current <- IORef Int -> IO Int
    forall a. IORef a -> IO a
    readIORef IORef Int
    currentWSIndex
            modifyIORef
              currentWSIndex
              ((`mod` length cycleWorkspaces) . (+ increment))
            return $ cycleWorkspaces !! current
          focusIncrement Int
    i = IO WorkspaceId -> X WorkspaceId
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    io (Int -> IO WorkspaceId
    getAndIncrementWS Int
    i) X WorkspaceId -> (WorkspaceId -> X ()) -> X ()
    forall a b. X a -> (a -> X b) -> X b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= ((WindowSet -> WindowSet) -> X ()
    windows ((WindowSet -> WindowSet) -> X ())
    -> (WorkspaceId -> WindowSet -> WindowSet) -> WorkspaceId -> X ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . WorkspaceId -> WindowSet -> WindowSet
    forall s i l a sd.
    (Eq s, Eq i) =>
    i -> StackSet i l a s sd -> StackSet i l a s sd
    W.greedyView)

      repeatable mods nextKey $
        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 :: [KeySym] -> KeySym -> KeySym -> X ()
    cycleWorkspaceOnCurrentScreen [KeySym]
    mods KeySym
    n KeySym
    p =
      (WindowSet -> X ()) -> X ()
    forall a. (WindowSet -> X a) -> X a
    withWindowSet ((WindowSet -> X ()) -> X ()) -> (WindowSet -> X ()) -> X ()
    forall a b. (a -> b) -> a -> b
    $ \WindowSet
    ws ->
        ScreenId -> [KeySym] -> KeySym -> KeySym -> X ()
    cycleWorkspaceOnScreen (Screen WorkspaceId (Layout KeySym) KeySym ScreenId ScreenDetail
    -> ScreenId
    forall i l a sid sd. Screen i l a sid sd -> sid
    W.screen (Screen WorkspaceId (Layout KeySym) KeySym ScreenId ScreenDetail
     -> ScreenId)
    -> Screen WorkspaceId (Layout KeySym) KeySym ScreenId ScreenDetail
    -> ScreenId
    forall a b. (a -> b) -> a -> b
    $ WindowSet
    -> Screen WorkspaceId (Layout KeySym) KeySym ScreenId ScreenDetail
    forall i l a sid sd. StackSet i l a sid sd -> Screen i l a sid sd
    W.current WindowSet
    ws) [KeySym]
    mods KeySym
    n KeySym
    p