Skip to content

Commit

Permalink
X.H.Focus: Adapt docs to the new activation interface
Browse files Browse the repository at this point in the history
Fixes: #396
Related: #192
Related: #128
  • Loading branch information
liskin committed Oct 20, 2021
1 parent 79b130b commit 860f80a
Showing 1 changed file with 48 additions and 59 deletions.
107 changes: 48 additions & 59 deletions XMonad/Hooks/Focus.hs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@

-- |
-- Module: XMonad.Hooks.Focus
-- Description: Provide additional information about a new window.
-- Description: Extends ManageHook EDSL to work on focused windows and current workspace.
-- Copyright: sgf-dma, 2016
-- Maintainer: [email protected]
--
-- Extends "XMonad.ManageHook" EDSL to work on focused windows and current
-- workspace.
--

module XMonad.Hooks.Focus
(
Expand Down Expand Up @@ -95,8 +98,8 @@ import XMonad.Hooks.ManageHelpers (currentWs)
--
-- I may use one of predefined configurations.
--
-- 1. Default window activation behavior is to switch to workspace with
-- activated window and switch focus to it:
-- 1. The default window activation behavior (switch to workspace with
-- activated window and switch focus to it) expressed using this module:
--
-- > import XMonad
-- >
Expand All @@ -105,44 +108,42 @@ import XMonad.Hooks.ManageHelpers (currentWs)
-- >
-- > main :: IO ()
-- > main = do
-- > let mh :: ManageHook
-- > mh = activateSwitchWs
-- > xcf = ewmh $ def
-- > { modMask = mod4Mask
-- > , logHook = activateLogHook mh <+> logHook def
-- > }
-- > let ah :: ManageHook
-- > ah = activateSwitchWs
-- > xcf = setEwmhActivateHook ah
-- > . ewmh $ def{ modMask = mod4Mask }
-- > xmonad xcf
--
-- 2. Or i may move activated window to current workspace and switch focus to
-- it:
--
-- > let mh :: ManageHook
-- > mh = activateOnCurrentWs
-- > let ah :: ManageHook
-- > ah = activateOnCurrentWs
--
-- 3. Or move activated window to current workspace, but keep focus unchanged:
--
-- > let mh :: ManageHook
-- > mh = activateOnCurrentKeepFocus
-- > let ah :: ManageHook
-- > ah = activateOnCurrentKeepFocus
--
-- 4. I may use regular 'ManageHook' combinators for filtering, which windows
-- may activate. E.g. activate all windows, except firefox:
--
-- > let mh :: ManageHook
-- > mh = not <$> (className =? "Firefox" <||> className =? "Firefox-esr" <||> className =? "Iceweasel")
-- > let ah :: ManageHook
-- > ah = not <$> (className =? "Firefox" <||> className =? "Firefox-esr" <||> className =? "Iceweasel")
-- > --> activateSwitchWs
--
-- 5. Or even use 'FocusHook' combinators. E.g. activate all windows, unless
-- xterm is focused on /current/ workspace:
--
-- > let mh :: ManageHook
-- > mh = manageFocus (not <$> focusedCur (className =? "XTerm")
-- > let ah :: ManageHook
-- > ah = manageFocus (not <$> focusedCur (className =? "XTerm")
-- > --> liftQuery activateSwitchWs)
--
-- or activate all windows, unless focused window on the workspace,
-- /where activated window is/, is not a xterm:
--
-- > let mh :: ManageHook
-- > mh = manageFocus (not <$> focused (className =? "XTerm")
-- > let ah :: ManageHook
-- > ah = manageFocus (not <$> focused (className =? "XTerm")
-- > --> liftQuery activateSwitchWs)
--
-- == Defining FocusHook.
Expand Down Expand Up @@ -197,11 +198,11 @@ import XMonad.Hooks.ManageHelpers (currentWs)
-- > main = do
-- > let newFh :: ManageHook
-- > newFh = manageFocus newFocusHook
-- > acFh :: X ()
-- > acFh = activateLogHook (manageFocus activateFocusHook)
-- > xcf = ewmh $ def
-- > acFh :: ManageHook
-- > acFh = manageFocus activateFocusHook
-- > xcf = setEwmhActivateHook acFh
-- > . ewmh $ def
-- > { manageHook = newFh <+> manageHook def
-- > , logHook = acFh <+> logHook def
-- > , modMask = mod4Mask
-- > }
-- > `additionalKeys` [((mod4Mask, xK_v), toggleLock)]
Expand All @@ -214,30 +215,23 @@ import XMonad.Hooks.ManageHelpers (currentWs)
-- - I need 'XMonad.Hooks.EwmhDesktops' module for enabling window
-- activation.
-- - 'FocusHook' in 'manageHook' will be called /only/ for new windows.
-- - 'FocusHook' in 'logHook' will be called /only/ for activated windows.
-- - 'FocusHook' in 'setEwmhActivateHook' will be called /only/ for activated windows.
--
-- Alternatively, i may construct a single 'FocusHook' for both new and
-- activated windows and then just add it to both 'manageHook' and 'logHook':
--
-- > let fh :: ManageHook
-- > fh = manageFocus $ (composeOne
-- > [ liftQuery activated -?> activateFocusHook
-- > , Just <$> newFocusHook
-- > ])
-- > xcf = ewmh $ def
-- > { manageHook = fh <+> manageHook def
-- > , logHook = activateLogHook fh <+> logHook def
-- activated windows and then just add it to both 'manageHook' and 'setEwmhActivateHook':
--
-- > let fh :: Bool -> ManageHook
-- > fh activated = manageFocus $ composeOne
-- > [ pure activated -?> activateFocusHook
-- > , pure True -?> newFocusHook
-- > ]
-- > xcf = setEwmhActivateHook (fh True)
-- > . ewmh $ def
-- > { manageHook = fh False <+> manageHook def
-- > , modMask = mod4Mask
-- > }
-- > `additionalKeys` [((mod4Mask, xK_v), toggleLock)]
--
-- Note:
-- - Predicate 'activated' will be 'True' for activated window.
-- - The order, when constructing final 'FocusHook': 'FocusHook' without
-- 'activated' predicate will match to activated windows too, thus i should
-- place it after one with 'activated' (so the latter will have a chance to
-- handle activated window first).
--
-- And more technical notes:
--
-- - 'FocusHook' will run /many/ times, so it usually should not keep state
Expand All @@ -264,11 +258,6 @@ import XMonad.Hooks.ManageHelpers (currentWs)
--
-- now @FH2@ will see window shift made by @FH1@.
--
-- Also, note, that if several 'activateLogHook'-s are sequenced, only
-- /first/ one (leftmost) will run. Thus, to make above working,
-- 'mappend' all 'ManageHook'-s first, and then run by /single/
-- 'activateLogHook' (see next example).
--
-- Another interesting example is moving all activated windows to current
-- workspace by default, and applying 'FocusHook' after:
--
Expand All @@ -281,14 +270,14 @@ import XMonad.Hooks.ManageHelpers (currentWs)
-- >
-- > main :: IO ()
-- > main = do
-- > let fh :: ManageHook
-- > fh = manageFocus $ (composeOne
-- > [ liftQuery activated -?> (newOnCur --> keepFocus)
-- > , Just <$> newFocusHook
-- > ])
-- > xcf = ewmh $ def
-- > { manageHook = fh <+> manageHook def
-- > , logHook = activateLogHook (fh <+> activateOnCurrentWs) <+> logHook def
-- > let fh :: Bool -> ManageHook
-- > fh activated = manageFocus $ composeOne
-- > [ pure activated -?> (newOnCur --> keepFocus)
-- > , pure True -?> newFocusHook
-- > ]
-- > xcf = setEwmhActivateHook (fh True <+> activateOnCurrentWs)
-- > . ewmh $ def
-- > { manageHook = fh False <+> manageHook def
-- > , modMask = mod4Mask
-- > }
-- > `additionalKeys` [((mod4Mask, xK_v), toggleLock)]
Expand Down Expand Up @@ -319,11 +308,10 @@ import XMonad.Hooks.ManageHelpers (currentWs)
--
-- - i keep focus, when activated window appears on current workspace, in
-- this example.
-- - when @liftQuery activated -?> (newOnCur --> keepFocus)@ runs, activated
-- - when @pure activated -?> (newOnCur --> keepFocus)@ runs, activated
-- window will be /already/ on current workspace, thus, if i do not want to
-- move some activated windows, i should filter them out before applying
-- @activateOnCurrentWs@ 'FocusHook'.
-- - i 'mappend' all 'ManageHook'-s and run 'activateLogHook' only once.


-- FocusQuery.
Expand Down Expand Up @@ -552,21 +540,22 @@ when' b mx
-- $examples

-- | Default EWMH window activation behavior: switch to workspace with
-- activated window and switch focus to it.
-- activated window and switch focus to it. Not to be used in a 'manageHook'.
activateSwitchWs :: ManageHook
activateSwitchWs = manageFocus (switchWorkspace <+> switchFocus)

-- | Move activated window to current workspace.
-- | Move activated window to current workspace. Not to be used in a 'manageHook'.
activateOnCurrent' :: ManageHook
activateOnCurrent' = currentWs >>= unlessFocusLock . doShift

-- | Move activated window to current workspace and switch focus to it. Note,
-- that i need to explicitly call 'switchFocus' here, because otherwise, when
-- activated window is /already/ on current workspace, focus won't be
-- switched.
-- switched. Not to be used in a 'manageHook'.
activateOnCurrentWs :: ManageHook
activateOnCurrentWs = manageFocus (newOnCur --> switchFocus) <+> activateOnCurrent'

-- | Move activated window to current workspace, but keep focus unchanged.
-- Not to be used in a 'manageHook'.
activateOnCurrentKeepFocus :: ManageHook
activateOnCurrentKeepFocus = manageFocus (newOnCur --> keepFocus) <+> activateOnCurrent'

0 comments on commit 860f80a

Please sign in to comment.