packages feed

xmonad-contrib 0.17.1 → 0.18.0

raw patch · 272 files changed

+6190/−2254 lines, 272 filesdep ~bytestringdep ~containersdep ~mtl

Dependency ranges changed: bytestring, containers, mtl, xmonad

Files

CHANGES.md view
@@ -1,11 +1,320 @@ # Change Log / Release Notes -## 0.17.1 (September 3, 2021)+## 0.18.0 (February 3, 2024)  ### Breaking Changes +  * Deprecated `XMonad.Layout.Cross` due to bitrot; refer to+    `XMonad.Layout.Circle` and `XMonad.Layout.ThreeColumns` for+    alternatives.++  * Deprecated the `XMonad.Layout.StateFull` module and+    `XMonad.Layout.TrackFloating.(t|T)rackFloating` in favour of+    `XMonad.Layout.FocusTracking`.++  * Dropped support for GHC 8.4.++  * `XMonad.Util.ExclusiveScratchpads`++    - Deprecated the module in favour of the (new) exclusive scratchpad+      functionality of `XMonad.Util.NamedScratchpad`.++  * `XMonad.Actions.CycleWorkspaceByScreen`++    - The type of `repeatableAction` has changed, and it's deprecated in+      favour of `X.A.Repeatable.repeatable`.++  * `XMonad.Hooks.DynamicProperty`++    - Deprecated the module in favour of the more aptly named+      `XMonad.Hooks.OnPropertyChange`.++  * `XMonad.Util.Scratchpad`:++    - Deprecated the module; use `XMonad.Util.NamedScratchpad` instead.++  * `XMonad.Actions.Navigation2D`++    - Removed deprecated function `hybridNavigation`.++  * `XMonad.Layout.Spacing`++    - Removed deprecated functions `SpacingWithEdge`, `SmartSpacing`,+      `SmartSpacingWithEdge`, `ModifySpacing`, `setSpacing`, and+      `incSpacing`.++  * `XMonad.Actions.MessageFeedback`++    - Removed deprecated functions `send`, `sendSM`, `sendSM_`,+      `tryInOrder`, `tryInOrder_`, `tryMessage`, and `tryMessage_`.++  * `XMonad.Prompt.Window`++    - Removed deprecated functions `windowPromptGoto`,+      `windowPromptBring`, and `windowPromptBringCopy`.++  * `XMonad.Hooks.ICCCMFocus`++    - Removed deprecated module.  This was merged into xmonad.++  * `XMonad.Layout.LayoutBuilderP`++    - Removed deprecated module; use `XMonad.Layout.LayoutBuilder`+      instead.++  * `XMonad.Hooks.RestoreMinimized`++    - Removed deprecated module; use `XMonad.Hooks.Minimize` instead.++  * `XMonad.Layout.Named`++    - Deprecated the entire module, use `XMonad.Layout.Renamed` (which newly+      provides `named` for convenience) instead.++  * `XMonad.Actions.SinkAll`++    - Deprecated the entire module, use `XMonad.Actions.WithAll`+      instead.++  * `XMonad.Layout.Circle`:++    - Deprecated the entire module, use the `circle` function from+      `XMonad.Layout.CircleEx` instead.++  * `XMonad.Hooks.EwmhDesktops`++    - `_NET_CLIENT_LIST_STACKING` puts windows in the current workspace at the+      top in bottom-to-top order, followed by visible workspaces, followed by+      invisible workspaces.  Within visible and invisible groups, workspaces are+      ordered lexicographically, as before.  Currently focused window will+      always be the topmost, meaning the last in the list.++  * `XMonad.Util.NamedScratchpad`++    - Added `nsSingleScratchpadPerWorkspace`—a logHook to allow only one+      active scratchpad per workspace.+   * `XMonad.Util.EZConfig` +    - The function `readKeySequence` now returns a non-empty list if it+      succeeded.++  * Deprecate `XMonad.Util.Ungrab`; it was moved to `XMonad.Operations`+    in core.++### New Modules++  * `XMonad.Layout.CenterMainFluid`+    - A three column layout with main column in the center and two stack+      column surrounding it. Master window will be on center column and+      spaces on the sides are reserved.++  * `XMonad.Layout.FocusTracking`.++    - Replaces `X.L.StateFull` and half of `X.L.TrackFloating`.++  * `XMonad.Actions.MostRecentlyUsed`++    - Tab through windows by recency of use. Based on the Alt+Tab behaviour+      common outside of xmonad.++  * `XMonad.Util.History`++    - Track history in *O(log n)* time. Provides `History`, a variation on a+      LIFO stack with a uniqueness property. In order to achieve the desired+      asymptotics, the data type is implemented as an ordered Map.++  * `XMonad.Actions.Repeatable`++    - Actions you'd like to repeat. Factors out the shared logic of+      `X.A.CycleRecentWS`, `X.A.CycleWorkspaceByScreen` and `X.A.CycleWindows`.++  * `XMonad.Hooks.OnPropertyChange`:++    - A new module replicating the functionality of+      `XMonad.Hooks.DynamicProperty`, but with more discoverable names.++  * `XMonad.Actions.ToggleFullFloat`:++    - Fullscreen (float) a window while remembering its original state.+      There's both an action to be bound to a key, and hooks that plug into+      `XMonad.Hooks.EwmhDesktops`.++  * `XMonad.Layout.CircleEx`:++    - A new window layout, similar to X.L.Circle, but with more+      possibilities for customisation.++  * `XMonad.Layout.DecorationEx`:++    - A new, more extensible, mechanism for window decorations, and some+      standard types of decorations, including usual bar on top of window,+      tabbed decorations and dwm-like decorations.++### Bug Fixes and Minor Changes++  * `XMonad.Layout.Magnifier`++    - Added `magnifyxy` to allow for different magnification in the+      horizontal and vertical directions. Added `magnifierxy`,+      `magnifierxy'`, `magnifierxyOff`, and `magnifierxyOff'` as+      particular combinators.++  * `XMonad.Util.Loggers`++    - Added `logClassname`, `logClassnames`, `logClassnames'`,+      `logClassnameOnScreen`, `logClassnamesOnScreen`, `logClassnamesOnScreen'`,+      and `ClassnamesFormat`. These are all equivalents of their `Title`+      counterparts, allowing logging the window classname instead.++  * `XMonad.Hooks.StatusBar.PP`++    - `dynamicLogString` now forces its result and produces an error string if+      it throws an exception. Use `dynamicLogString'` if for some reason you+      need the old behavior.++  * `XMonad.Util.EZConfig`++    - Added `remapKeysP`, which remaps keybindings from one binding to+      another.++    - Made `additionalKeys{,P}`, `removeKeys{,P}`, `remapKeysP`, and+      `{additional,remove}MouseBindings` `infixl 4` so they can more easily+      be concatenated with `(++)`.++  * `XMonad.Util.NamedScratchpad`++    - Added `addExclusives`, `resetFocusedNSP`, `setNoexclusive`,+      `resizeNoexclusive`, and `floatMoveNoexclusive` in order to augment+      named scratchpads with the exclusive scratchpad functionality of+      `XMonad.Util.ExclusiveScratchpads`.++  * `XMonad.Layout.BorderResize`++    - Added `borderResizeNear` as a variant of `borderResize` that can+      control how many pixels near a border resizing still works.++  * `XMonad.Util.Run`++    - It is now ensured that all arguments of `execute` and `eval` are+      quoted.  Likewise, `executeNoQuote` is added as a version of+      `execute` that does not do that.++    - Added `findFile` as a shorthand to call `find-file`.++    - Added `list` and `saveExcursion` to the list of Emacs commands.++    - Added `toList` to easily lift a `String` to an `X Input`.++    - Added `>&&>` and `>||>` to glue together different inputs.++  * `XMonad.Util.Parser`++    - Added the `gather`, `count`, `between`, `option`, `optionally`,+      `skipMany`, `skipMany1`, `chainr`, `chainr1`, `chainl`, `chainl1`,+      and `manyTill` functions, in order to achieve feature parity with+      `Text.ParserCombinators.ReadP`.++  * `XMonad.Actions.FloatKeys`++    - Added `directionMoveWindow` and `directionMoveWindow` as more+      alternatives to the existing functions.++  * `XMonad.Hooks.InsertPosition`++    - Added `setupInsertPosition` as a combinator alternative to+      `insertPosition`.++  * `XMonad.Actions.Navigation2D`++    - Added `sideNavigation` as a fallback to the default tiling strategy,+      in case `lineNavigation` can't find a window.  This benefits+      especially users who use `XMonad.Layout.Spacing`.++  * `XMonad.Prompt.OrgMode`++    - Added `orgPromptRefile` and `orgPromptRefileTo` for interactive+      and targeted refiling of the entered note into some existing tree+      of headings, respectively.++    - Allowed the time specification in `HHMM` format.++  * `XMonad.Actions.Search`++    - Added `aur`, `flora`, `ncatlab`, `protondb`, `rosettacode`, `sourcehut`,+      `steam`, `voidpgks_x86_64`, `voidpgks_x86_64_musl`, `arXiv`,+      `clojureDocs`, `cratesIo`, `rustStd`, `noogle`, `nixos`, `homeManager`,+      and `zbmath` search engines.++  * `XMonad.Layout.ResizableThreeColumns`++    - Fixed an issue where the bottom right window would not respond to+      `MirrorShrink` and `MirrorExpand` messages.++  * `XMonad.Hooks.EwmhDesktops`++    - Added `disableEwmhManageDesktopViewport` to avoid setting the+      `_NET_DESKTOP_VIEWPORT` property, as it can lead to issues with+      some status bars (see this+      [polybar issue](https://github.com/polybar/polybar/issues/2603)).++    - Added `setEwmhFullscreenHooks` to override the default fullfloat/sink+      behaviour of `_NET_WM_STATE_FULLSCREEN` requests. See also+      `XMonad.Actions.ToggleFullFloat` for a float-restoring implementation of+      fullscreening.++    - Added `ewmhDesktops(Maybe)ManageHook` that places windows in their+      preferred workspaces. This is useful when restoring a browser session+      after a restart.++  * `XMonad.Hooks.StatusBar`++    - Added `startAllStatusBars` to start the configured status bars.++  * `XMonad.Util.NamedActions`++    - Changed `addDescrKeys` and `addDescrKeys'` to not discard the+      keybindings in the current config.++  * `XMonad.Prompt`++    - The `emacsLikeXPKeymap` and `vimLikeXPKeymap` keymaps now treat+      `C-m` the same as `Return`.++    - Added `prevCompletionKey` to `XPConfig`, facilitating the ability+      to cycle through the completions backwards. This is bound to+      `S-<TAB>` by default.++    - The `vimLikeXPKeymap` now accepts the prompt upon pressing enter+      in normal mode.++  * `XMonad.Actions.Prefix`++    - Added `orIfPrefixed`, a combinator to decide upon an action based+      on whether any prefix argument was given.++  * `XMonad.Actions.WorkspaceNames`++    - Enabled prompt completion (from history) in `renameWorkspace`.++  * `XMonad.Prompt.Pass`++    - Added `passOTPTypePrompt` to type out one-time-passwords via+      `xdotool`.++  * `XMonad.Util.Stack`++    - Added `zipperFocusedAtFirstOf` to differentiate two lists into a+      zipper.++### Other changes++## 0.17.1 (September 3, 2022)++### Breaking Changes++  * `XMonad.Util.EZConfig`+     - The functions `parseKey`, `parseKeyCombo`, and `parseKeySequence`       now return a `Parser` (from `XMonad.Util.Parser`) instead of a       `ReadP`.@@ -15,7 +324,7 @@     - Deprecated all of these modules.  The user-specific configuration       modules may still be found [on the website]. - * `XMonad.Util.NamedScratchpad`+  * `XMonad.Util.NamedScratchpad`      - Scratchpads are now only based on the argument given to       `namedScratchpadManageHook`; all other scratchpad arguments are,@@ -79,7 +388,7 @@     A module for adding a keybinding to repeat the last action, similar     to Vim's `.` or Emacs's `dot-mode`. - * `XMonad.Util.Grab`+  * `XMonad.Util.Grab`      Utilities for making grabbing and ungrabbing keys more convenient. 
README.md view
@@ -6,9 +6,9 @@   <a href="https://github.com/xmonad/xmonad-contrib/blob/readme/LICENSE"><img alt="License" src="https://img.shields.io/github/license/xmonad/xmonad-contrib"></a>   <a href="https://haskell.org/"><img alt="Made in Haskell" src="https://img.shields.io/badge/Made%20in-Haskell-%235e5086?logo=haskell"></a>   <br>-  <a href="https://github.com/xmonad/xmonad-contrib/actions/workflows/stack.yml"><img alt="Stack" src="https://img.shields.io/github/workflow/status/xmonad/xmonad-contrib/Stack?label=Stack&logo=githubactions&logoColor=white"></a>-  <a href="https://github.com/xmonad/xmonad-contrib/actions/workflows/haskell-ci.yml"><img alt="Cabal" src="https://img.shields.io/github/workflow/status/xmonad/xmonad-contrib/Haskell-CI?label=Cabal&logo=githubactions&logoColor=white"></a>-  <a href="https://github.com/xmonad/xmonad-contrib/actions/workflows/nix.yml"><img alt="Nix" src="https://img.shields.io/github/workflow/status/xmonad/xmonad-contrib/Nix?label=Nix&logo=githubactions&logoColor=white"></a>+  <a href="https://github.com/xmonad/xmonad-contrib/actions/workflows/stack.yml"><img alt="Stack" src="https://img.shields.io/github/actions/workflow/status/xmonad/xmonad-contrib/stack.yml?label=Stack&logo=githubactions&logoColor=white"></a>+  <a href="https://github.com/xmonad/xmonad-contrib/actions/workflows/haskell-ci.yml"><img alt="Cabal" src="https://img.shields.io/github/actions/workflow/status/xmonad/xmonad-contrib/haskell-ci.yml?label=Cabal&logo=githubactions&logoColor=white"></a>+  <a href="https://github.com/xmonad/xmonad-contrib/actions/workflows/nix.yml"><img alt="Nix" src="https://img.shields.io/github/actions/workflow/status/xmonad/xmonad-contrib/nix.yml?label=Nix&logo=githubactions&logoColor=white"></a>   <br>   <a href="https://github.com/sponsors/xmonad"><img alt="GitHub Sponsors" src="https://img.shields.io/github/sponsors/xmonad?label=GitHub%20Sponsors&logo=githubsponsors"></a>   <a href="https://opencollective.com/xmonad"><img alt="Open Collective" src="https://img.shields.io/opencollective/all/xmonad?label=Open%20Collective&logo=opencollective"></a>
XMonad/Actions/AfterDrag.hs view
@@ -24,7 +24,7 @@ import Data.Time (NominalDiffTime, diffUTCTime, getCurrentTime)  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- >    import XMonad.Actions.AfterDrag --
XMonad/Actions/BluetileCommands.hs view
@@ -29,7 +29,7 @@  -- $usage ----- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- >    import XMonad.Hooks.ServerMode -- >    import XMonad.Actions.BluetileCommands
XMonad/Actions/Commands.hs view
@@ -37,7 +37,7 @@  -- $usage ----- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- >    import XMonad.Actions.Commands --@@ -57,7 +57,7 @@ -- bindings!) -- -- For detailed instructions on editing your key bindings, see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  -- | Create a 'Data.Map.Map' from @String@s to xmonad actions from a --   list of pairs.
XMonad/Actions/ConstrainedResize.hs view
@@ -26,7 +26,7 @@  -- $usage ----- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import qualified XMonad.Actions.ConstrainedResize as Sqr --
XMonad/Actions/CopyWindow.hs view
@@ -37,7 +37,7 @@  -- $usage ----- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@ file:+-- You can use this module with the following in your @xmonad.hs@ file: -- -- > import XMonad.Actions.CopyWindow --@@ -77,7 +77,7 @@ -- >  , ((modm .|. shiftMask, xK_v ),  killAllOtherCopies) -- @@ Toggle window state back -- -- For detailed instructions on editing your key bindings, see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  -- $logHook --
XMonad/Actions/CycleRecentWS.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE PatternGuards #-}+{-# LANGUAGE MultiWayIf #-} ----------------------------------------------------------------------------- -- | -- Module      :  XMonad.Actions.CycleRecentWS@@ -35,21 +36,25 @@ #endif ) where +import XMonad.Actions.Repeatable (repeatableSt)+ import XMonad hiding (workspaces)-import XMonad.StackSet hiding (filter)+import XMonad.Prelude (void, when)+import XMonad.StackSet hiding (filter, modify)  import Control.Arrow ((&&&)) import Data.Function (on)+import Control.Monad.State (lift)  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@ file:+-- You can use this module with the following in your @xmonad.hs@ file: -- -- > import XMonad.Actions.CycleRecentWS -- > -- >   , ((modm, xK_Tab), cycleRecentWS [xK_Alt_L] xK_Tab xK_grave) -- -- For detailed instructions on editing your key bindings, see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  -- | Cycle through most recent workspaces with repeated presses of a key, while --   a modifier key is held down. The recency of workspaces previewed while browsing@@ -111,25 +116,15 @@                 -> X () cycleWindowSets genOptions mods keyNext keyPrev = do   (options, unView') <- gets $ (genOptions &&& unView) . windowset-  XConf {theRoot = root, display = d} <- ask-  let event = allocaXEvent $ \p -> do-                maskEvent d (keyPressMask .|. keyReleaseMask) p-                KeyEvent {ev_event_type = t, ev_keycode = c} <- getEvent p-                s <- keycodeToKeysym d c 0-                return (t, s)-  let setOption n = do windows $ view (options `cycref` n) . unView'-                       (t, s) <- io event-                       case () of-                         () | t == keyPress   && s == keyNext  -> setOption (n+1)-                            | t == keyPress   && s == keyPrev  -> setOption (n-1)-                            | t == keyRelease && s `elem` mods -> return ()-                            | otherwise                        -> setOption n-  io $ grabKeyboard d root False grabModeAsync grabModeAsync currentTime-  setOption 0-  io $ ungrabKeyboard d currentTime- where-  cycref :: [a] -> Int -> a-  cycref l i = l !! (i `mod` length l)+  let+    preview = do+      i <- get+      lift $ windows (view (options !! (i `mod` n)) . unView')+      where n = length options+  void . repeatableSt (-1) mods keyNext $ \t s -> when (t == keyPress) $ if+    | s == keyNext -> modify succ >> preview+    | s == keyPrev -> modify pred >> preview+    | otherwise    -> pure ()  -- | Given an old and a new 'WindowSet', which is __exactly__ one -- 'view' away from the old one, restore the workspace order of the
XMonad/Actions/CycleSelectedLayouts.hs view
@@ -23,7 +23,7 @@ import qualified XMonad.StackSet as S  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad -- > import XMonad.Actions.CycleSelectedLayouts@@ -39,8 +39,9 @@ -- | If the current layout is in the list, cycle to the next layout. Otherwise, --   apply the first layout from list. cycleThroughLayouts :: [String] -> X ()-cycleThroughLayouts lst = do+cycleThroughLayouts []         = pure ()+cycleThroughLayouts lst@(x: _) = do     winset <- gets windowset     let ld = description . S.layout . S.workspace . S.current $ winset-    let newld = fromMaybe (head lst) (cycleToNext lst ld)+    let newld = fromMaybe x (cycleToNext lst ld)     sendMessage $ JumpToLayout newld
XMonad/Actions/CycleWS.hs view
@@ -92,7 +92,7 @@ import XMonad.Util.WorkspaceCompare  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@ file:+-- You can use this module with the following in your @xmonad.hs@ file: -- -- > import XMonad.Actions.CycleWS -- >@@ -122,7 +122,7 @@ -- >            windows . view $ t                                         ) -- -- For detailed instructions on editing your key bindings, see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>. -- -- When using the toggle functions, in order to ensure that the workspace -- to which you switch is the previously viewed workspace, use the
XMonad/Actions/CycleWindows.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE ViewPatterns, MultiWayIf #-}  -------------------------------------------------------------------------------- -- |@@ -50,7 +50,6 @@         -- $pointer          -- * Generic list rotations-        -- $generic         rotUp, rotDown ) where @@ -59,11 +58,13 @@ import qualified XMonad.StackSet as W import qualified Data.List.NonEmpty as NE import XMonad.Actions.RotSlaves+import XMonad.Actions.Repeatable (repeatableSt)  import Control.Arrow (second)+import Control.Monad.Trans (lift)  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@ file:+-- You can use this module with the following in your @xmonad.hs@ file: -- -- > import XMonad.Actions.CycleWindows -- >    -- config@@ -79,7 +80,7 @@ -- -- Also, if you use focus follows mouse, you will want to read the section -- on updating the mouse pointer below.  For detailed instructions on--- editing your key bindings, see "XMonad.Doc.Extending#Editing_key_bindings".+-- editing your key bindings, see <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>. {- $pointer With FocusFollowsMouse == True, the focus is updated after binding actions, possibly focusing a window you didn't intend to focus. Most@@ -139,27 +140,19 @@                                     -> KeySym    -- ^ Key used to select a \"previous\" stack.                                     -> X () cycleStacks' filteredPerms mods keyNext keyPrev = do-    XConf {theRoot = root, display = d} <- ask-    stacks <- gets $ maybe [] filteredPerms . W.stack . W.workspace . W.current . windowset--    let evt = allocaXEvent $-                  \p -> do maskEvent d (keyPressMask .|. keyReleaseMask) p-                           KeyEvent {ev_event_type = t, ev_keycode = c} <- getEvent p-                           s <- keycodeToKeysym d c 0-                           return (t, s)-        choose n (t, s)-              | t == keyPress   && s == keyNext  = io evt >>= choose (n+1)-              | t == keyPress   && s == keyPrev  = io evt >>= choose (n-1)-              | t == keyPress   && s `elem` [xK_0..xK_9] = io evt >>= choose (numKeyToN s)-              | t == keyRelease && s `elem` mods = return ()-              | otherwise                        = doStack n >> io evt >>= choose n-        doStack n = windows . W.modify' . const $ stacks `cycref` n--    io $ grabKeyboard d root False grabModeAsync grabModeAsync currentTime-    io evt >>= choose 1-    io $ ungrabKeyboard d currentTime-  where cycref l i = l !! (i `mod` length l) -- modify' ensures l is never [], but must also be finite-        numKeyToN = subtract 48 . read . show+  stacks <- gets $ maybe [] filteredPerms+                 . W.stack . W.workspace . W.current . windowset+  let+    preview = do+      i <- get+      lift . windows . W.modify' . const $ stacks !! (i `mod` n)+      where n = length stacks+  void $ repeatableSt 0 mods keyNext $ \t s -> if+    | t == keyPress && s == keyNext          -> modify succ+    | t == keyPress && s == keyPrev          -> modify pred+    | t == keyPress && s `elem` [xK_0..xK_9] -> put (numKeyToN s)+    | otherwise                              -> preview+  where numKeyToN = subtract 48 . read . show  -- | Given a stack element and a stack, shift or insert the element (window) --   at the currently focused position.@@ -229,12 +222,3 @@ rotUnfocused' f   (W.Stack t ls rs) = W.Stack t (reverse revls') rs' -- otherwise     where  (master :| revls) = NE.reverse (let l:ll = ls in l :| ll)            (revls',rs') = splitAt (length ls) (f $ master:revls ++ rs)---- $generic--- Generic list rotations such that @rotUp [1..4]@ is equivalent to--- @[2,3,4,1]@ and @rotDown [1..4]@ to @[4,1,2,3]@. They both are--- @id@ for null or singleton lists.-rotUp :: [a] -> [a]-rotUp   l = drop 1 l ++ take 1 l-rotDown :: [a] -> [a]-rotDown = reverse . rotUp . reverse
XMonad/Actions/CycleWorkspaceByScreen.hs view
@@ -25,11 +25,10 @@  import           Data.IORef -import           Graphics.X11.Xlib.Extras- import           XMonad import           XMonad.Prelude import           XMonad.Hooks.WorkspaceHistory+import           XMonad.Actions.Repeatable (repeatable) import qualified XMonad.StackSet as W  -- $usage@@ -53,22 +52,9 @@ -- -- > , ((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+{-# DEPRECATED repeatableAction "Use XMonad.Actions.Repeatable.repeatable" #-}+repeatableAction :: [KeySym] -> KeySym -> (EventType -> KeySym -> X ()) -> X ()+repeatableAction = repeatable  handleKeyEvent :: EventType                -> KeySym@@ -109,8 +95,7 @@         return $ cycleWorkspaces !! current       focusIncrement i = io (getAndIncrementWS i) >>= (windows . W.greedyView) -  focusIncrement 1 -- Do the first workspace cycle-  repeatableAction mods $+  repeatable mods nextKey $     runFirst       [ handleKeyEvent keyPress nextKey $ focusIncrement 1       , handleKeyEvent keyPress prevKey $ focusIncrement (-1)
XMonad/Actions/DeManage.hs view
@@ -39,7 +39,7 @@ import XMonad  -- $usage--- To use demanage, add this import to your @~\/.xmonad\/xmonad.hs@:+-- To use demanage, add this import to your @xmonad.hs@: -- -- >     import XMonad.Actions.DeManage --@@ -48,7 +48,7 @@ -- > , ((modm,               xK_d     ), withFocused demanage) -- -- For detailed instructions on editing your key bindings, see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  -- | Stop managing the currently focused window. demanage :: Window -> X ()
XMonad/Actions/DwmPromote.hs view
@@ -31,7 +31,7 @@  -- $usage ----- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- >    import XMonad.Actions.DwmPromote --@@ -40,7 +40,7 @@ -- >   , ((modm,               xK_Return), dwmpromote) -- -- For detailed instructions on editing your key bindings, see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  -- | Swap the focused window with the master window. If focus is in --   the master, swap it with the next window in the stack. Focus
XMonad/Actions/DynamicProjects.hs view
@@ -113,7 +113,7 @@ -- >  , ((modm, xK_slash), shiftToProjectPrompt def) -- -- For detailed instructions on editing your key bindings, see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  -------------------------------------------------------------------------------- type ProjectName  = String
XMonad/Actions/DynamicWorkspaceGroups.hs view
@@ -51,7 +51,7 @@ import XMonad.Actions.TopicSpace  -- $usage--- You can use this module by importing it into your ~\/.xmonad\/xmonad.hs file:+-- You can use this module by importing it into your @xmonad.hs@ file: -- -- > import XMonad.Actions.DynamicWorkspaceGroups --
XMonad/Actions/DynamicWorkspaceOrder.hs view
@@ -49,7 +49,7 @@ import Data.Ord (comparing)  -- $usage--- You can use this module by importing it into your ~\/.xmonad\/xmonad.hs file:+-- You can use this module by importing it into your @xmonad.hs@ file: -- -- > import qualified XMonad.Actions.DynamicWorkspaceOrder as DO --
XMonad/Actions/DynamicWorkspaces.hs view
@@ -44,7 +44,7 @@ import qualified XMonad.Util.ExtensibleState as XS  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@ file:+-- You can use this module with the following in your @xmonad.hs@ file: -- -- > import XMonad.Actions.DynamicWorkspaces -- > import XMonad.Actions.CopyWindow(copy)@@ -75,7 +75,7 @@ -- >    zip (zip (repeat (modm .|. controlMask)) [xK_1..xK_9]) (map (setWorkspaceIndex) [1..]) -- -- For detailed instructions on editing your key bindings, see--- "XMonad.Doc.Extending#Editing_key_bindings". See also the documentation for+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>. See also the documentation for -- "XMonad.Actions.CopyWindow", 'windows', 'shift', and 'XPConfig'.  type WorkspaceTag = String
XMonad/Actions/EasyMotion.hs view
@@ -51,7 +51,7 @@ -- $usage -- -- You can use this module's basic functionality with the following in your--- @~\/.xmonad\/xmonad.hs@:+-- @xmonad.hs@: -- -- >    import XMonad.Actions.EasyMotion (selectWindow) --@@ -387,5 +387,5 @@       _   -> handleKeyboard dpy drawFn cancel (trim fg) (clear bg) >>= retryBackspace    where     (fg, bg) = partition ((== Just keySym) . listToMaybe . chord) selected-    trim = map (\o -> o { chord = tail $ chord o })+    trim = map (\o -> o { chord = drop 1 $ chord o })     clear = map (\o -> o { chord = [] })
XMonad/Actions/FindEmptyWorkspace.hs view
@@ -25,7 +25,7 @@  -- $usage ----- To use, import this module into your @~\/.xmonad\/xmonad.hs@:+-- To use, import this module into your @xmonad.hs@: -- -- >   import XMonad.Actions.FindEmptyWorkspace --@@ -38,7 +38,7 @@ -- will tag the current window to an empty workspace and view it. -- -- For detailed instructions on editing your key bindings, see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  -- | Find the first hidden empty workspace in a StackSet. Returns -- Nothing if all workspaces are in use. Function searches currently
XMonad/Actions/FlexibleManipulate.hs view
@@ -29,7 +29,7 @@ import Prelude (Double, Integer, Ord (..), const, fromIntegral, fst, id, otherwise, round, snd, uncurry, ($))  -- $usage--- First, add this import to your @~\/.xmonad\/xmonad.hs@:+-- First, add this import to your @xmonad.hs@: -- -- > import qualified XMonad.Actions.FlexibleManipulate as Flex --
XMonad/Actions/FlexibleResize.hs view
@@ -25,7 +25,7 @@ import Foreign.C.Types  -- $usage--- To use, first import this module into your @~\/.xmonad\/xmonad.hs@ file:+-- To use, first import this module into your @xmonad.hs@ file: -- -- > import qualified XMonad.Actions.FlexibleResize as Flex --
XMonad/Actions/FloatKeys.hs view
@@ -19,14 +19,18 @@                 keysMoveWindowTo,                 keysResizeWindow,                 keysAbsResizeWindow,+                directionMoveWindow,+                directionResizeWindow,+                Direction2D(..),                 P, G, ChangeDim                 ) where  import XMonad import XMonad.Prelude (fi)+import XMonad.Util.Types  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- >    import XMonad.Actions.FloatKeys --@@ -38,8 +42,36 @@ -- >  , ((modm .|. shiftMask, xK_s     ), withFocused (keysAbsResizeWindow (10,10) (1024,752))) -- >  , ((modm,               xK_a     ), withFocused (keysMoveWindowTo (512,384) (1%2,1%2))) --+-- Using "XMonad.Util.EZConfig" syntax, we can easily build keybindings+-- where @M-\<arrow-keys\>@ moves the currently focused window and+-- @M-S-\<arrow-keys\>@ resizes it using 'directionMoveWindow' and+-- 'directionResizeWindow':+--+-- > [ ("M-" <> m <> k, withFocused $ f i)+-- > | (i, k) <- zip [U, D, R, L] ["<Up>", "<Down>", "<Right>", "<Left>"]+-- > , (f, m) <- [(directionMoveWindow 10, ""), (directionResizeWindow 10, "S-")]+-- > ]+-- -- For detailed instructions on editing your key bindings, see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.++-- | @directionMoveWindow delta dir win@ moves the window @win@ by+--   @delta@ pixels in direction @dir@.+directionMoveWindow :: Int -> Direction2D -> Window -> X ()+directionMoveWindow delta dir win = case dir of+  U -> keysMoveWindow (0, -delta) win+  D -> keysMoveWindow (0, delta)  win+  R -> keysMoveWindow (delta, 0)  win+  L -> keysMoveWindow (-delta, 0) win++-- | @directionResizeWindow delta dir win@ resizes the window @win@ by+--   @delta@ pixels in direction @dir@.+directionResizeWindow :: Int -> Direction2D -> Window -> X ()+directionResizeWindow delta dir win = case dir of+  U -> keysResizeWindow (0, -delta) (0, 0) win+  D -> keysResizeWindow (0, delta)  (0, 0) win+  R -> keysResizeWindow (delta, 0)  (0, 0) win+  L -> keysResizeWindow (-delta, 0) (0, 0) win  -- | @keysMoveWindow (dx, dy)@ moves the window by @dx@ pixels to the --   right and @dy@ pixels down.
XMonad/Actions/FloatSnap.hs view
@@ -37,7 +37,7 @@ import XMonad.Actions.AfterDrag  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- >    import XMonad.Actions.FloatSnap --@@ -53,7 +53,7 @@ -- >        , ((modm .|. shiftMask, xK_Down),  withFocused $ snapGrow D Nothing) -- -- For detailed instructions on editing your key bindings, see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>. -- -- And possibly add appropriate mouse bindings, for example: --
XMonad/Actions/FocusNth.hs view
@@ -25,7 +25,7 @@ import XMonad.StackSet  -- $usage--- Add the import to your @~\/.xmonad\/xmonad.hs@:+-- Add the import to your @xmonad.hs@: -- -- > import XMonad.Actions.FocusNth --@@ -36,7 +36,7 @@ -- >     | (i, k) <- zip [0 .. 8] [xK_1 ..]] -- -- For detailed instructions on editing your key bindings, see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  -- | Give focus to the nth window of the current workspace. focusNth :: Int -> X ()
XMonad/Actions/GridSelect.hs view
@@ -97,10 +97,11 @@ import Text.Printf import System.Random (mkStdGen, randomR) import Data.Word (Word8)+import qualified Data.List.NonEmpty as NE  -- $usage ----- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- >    import XMonad.Actions.GridSelect --@@ -142,8 +143,8 @@ -- -- Then you can bind to: ----- >     ,((modm, xK_g), goToSelected  $ gsconfig2 myWinColorizer)--- >     ,((modm, xK_p), spawnSelected $ spawnSelected defaultColorizer)+-- >     ,((modm, xK_g), goToSelected $ gsconfig2 myWinColorizer)+-- >     ,((modm, xK_p), spawnSelected (gsconfig2 defaultColorizer) ["xterm","gvim"])  -- $keybindings --@@ -302,14 +303,14 @@       r  = tr ++ map (\(x,y) -> (y,-x)) tr   in r ++ map (negate *** negate) r -diamond :: (Enum a, Num a, Eq a) => [(a, a)]-diamond = concatMap diamondLayer [0..]+diamond :: (Enum a, Num a, Eq a) => Stream (a, a)+diamond = fromList $ concatMap diamondLayer [0..]  diamondRestrict :: Integer -> Integer -> Integer -> Integer -> [(Integer, Integer)] diamondRestrict x y originX originY =   L.filter (\(x',y') -> abs x' <= x && abs y' <= y) .   map (\(x', y') -> (x' + fromInteger originX, y' + fromInteger originY)) .-  take 1000 $ diamond+  takeS 1000 $ diamond  findInElementMap :: (Eq a) => a -> [(a, b)] -> Maybe (a, b) findInElementMap pos = find ((== pos) . fst)@@ -658,7 +659,7 @@                                 originPosX = floor $ (gs_originFractX gsconfig - (1/2)) * 2 * fromIntegral restrictX                                 originPosY = floor $ (gs_originFractY gsconfig - (1/2)) * 2 * fromIntegral restrictY                                 coords = diamondRestrict restrictX restrictY originPosX originPosY-                                s = TwoDState { td_curpos = head coords,+                                s = TwoDState { td_curpos = NE.head (notEmpty coords),                                                 td_availSlots = coords,                                                 td_elements = elements,                                                 td_gsconfig = gsconfig,
XMonad/Actions/GroupNavigation.hs view
@@ -33,8 +33,8 @@                                       , isOnAnyVisibleWS                                       ) where -import Control.Monad.Reader-import Control.Monad.State+import Control.Monad.Reader (ask, asks)+import Control.Monad.State (gets) import Control.DeepSeq import Data.Map ((!)) import qualified Data.Map as Map@@ -47,13 +47,13 @@ import XMonad.Core import XMonad.ManageHook import XMonad.Operations (windows, withFocused)-import XMonad.Prelude (elem, foldl')+import XMonad.Prelude (elem, foldl', (>=>)) import qualified XMonad.StackSet as SS import qualified XMonad.Util.ExtensibleState as XS  {- $usage -Import the module into your @~\/.xmonad\/xmonad.hs@:+Import the module into your @xmonad.hs@:  > import XMonad.Actions.GroupNavigation @@ -129,7 +129,7 @@                              >=> maybe act (windows . SS.focusWindow)  -- Returns the list of windows ordered by workspace as specified in--- ~/.xmonad/xmonad.hs+-- @xmonad.hs@. orderedWindowList :: Direction -> X (Seq Window) orderedWindowList History = fmap (\(HistoryDB w ws) -> maybe ws (ws |>) w) XS.get orderedWindowList dir     = withWindowSet $ \ss -> do@@ -145,7 +145,7 @@     dirfun _        = id     rotfun wins x   = rotate $ rotateTo (== x) wins --- Returns the ordered workspace list as specified in ~/.xmonad/xmonad.hs+-- Returns the ordered workspace list as specified in @xmonad.hs@. orderedWorkspaceList :: WindowSet -> Seq String -> Seq WindowSpace orderedWorkspaceList ss wsids = rotateTo isCurWS wspcs'     where
XMonad/Actions/LinkWorkspaces.hs view
@@ -36,7 +36,7 @@     ( insert, delete, Map, lookup, empty, filter )  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@ file:+-- You can use this module with the following in your @xmonad.hs@ file: -- -- > import XMonad.Actions.LinkWorkspaces --@@ -58,7 +58,7 @@ -- >       , (i, k) <- zip (XMonad.workspaces conf) [xK_1 .. xK_9]] -- -- For detailed instructions on editing your key bindings, see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  data MessageConfig = MessageConfig {  messageFunction :: ScreenId -> [Char] -> [Char] -> [Char] -> X()                     , foreground :: [Char]
XMonad/Actions/MessageFeedback.hs view
@@ -42,24 +42,18 @@        -- ** Aliases     , sm--      -- * Backwards Compatibility-      -- $backwardsCompatibility-    , send, sendSM, sendSM_-    , tryInOrder, tryInOrder_-    , tryMessage, tryMessage_     ) where  import XMonad               ( Window ) import XMonad.Core          ( X(), Message, SomeMessage(..), LayoutClass(..), windowset, catchX, WorkspaceId, Layout, whenJust ) import XMonad.Operations    ( updateLayout, windowBracket, modifyWindowSet )-import XMonad.Prelude       ( isJust, liftA2, void )+import XMonad.Prelude import XMonad.StackSet      ( Workspace, current, workspace, layout, tag )  import Control.Monad.State  ( gets )  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Actions.MessageFeedback --@@ -230,46 +224,3 @@ -- | Convenience shorthand for 'SomeMessage'. sm :: Message a => a -> SomeMessage sm = SomeMessage------------------------------------------------------------------------------------- Backwards Compatibility:----------------------------------------------------------------------------------{-# DEPRECATED send "Use sendMessageB instead." #-}-{-# DEPRECATED sendSM "Use sendSomeMessageB instead." #-}-{-# DEPRECATED sendSM_ "Use sendSomeMessage instead." #-}-{-# DEPRECATED tryInOrder "Use tryInOrderWithNoRefreshToCurrentB instead." #-}-{-# DEPRECATED tryInOrder_ "Use tryInOrderWithNoRefreshToCurrent instead." #-}-{-# DEPRECATED tryMessage "Use tryMessageWithNoRefreshToCurrentB instead." #-}-{-# DEPRECATED tryMessage_ "Use tryMessageWithNoRefreshToCurrent instead." #-}---- $backwardsCompatibility--- The following functions exist solely for compatibility with pre-0.14--- releases.---- | See 'sendMessageWithNoRefreshToCurrentB'.-send :: Message a => a -> X Bool-send = sendMessageWithNoRefreshToCurrentB---- | See 'sendSomeMessageWithNoRefreshToCurrentB'.-sendSM :: SomeMessage -> X Bool-sendSM = sendSomeMessageWithNoRefreshToCurrentB---- | See 'sendSomeMessageWithNoRefreshToCurrent'.-sendSM_ :: SomeMessage -> X ()-sendSM_ = sendSomeMessageWithNoRefreshToCurrent---- | See 'tryInOrderWithNoRefreshToCurrentB'.-tryInOrder :: [SomeMessage] -> X Bool-tryInOrder = tryInOrderWithNoRefreshToCurrentB---- | See 'tryInOrderWithNoRefreshToCurrent'.-tryInOrder_ :: [SomeMessage] -> X ()-tryInOrder_ = tryInOrderWithNoRefreshToCurrent---- | See 'tryMessageWithNoRefreshToCurrentB'.-tryMessage :: (Message a, Message b) => a -> b -> X Bool-tryMessage = tryMessageWithNoRefreshToCurrentB---- | See 'tryMessageWithNoRefreshToCurrent'.-tryMessage_ :: (Message a, Message b) => a -> b -> X ()-tryMessage_ = tryMessageWithNoRefreshToCurrent
XMonad/Actions/Minimize.hs view
@@ -12,7 +12,7 @@ -- Adds actions for minimizing and maximizing windows -- -- This module should be used with "XMonad.Layout.Minimize". Add 'minimize' to your--- layout modifiers as described in "XMonad.Layout.Minimized" and use actions from+-- layout modifiers as described in "XMonad.Layout.Minimize" and use actions from -- this module -- -- Possible keybindings:
+ XMonad/Actions/MostRecentlyUsed.hs view
@@ -0,0 +1,205 @@+{-# LANGUAGE NamedFieldPuns, GeneralizedNewtypeDeriving #-}++-----------------------------------------------------------------------------+-- |+-- Module      :  XMonad.Actions.MostRecentlyUsed+-- Description :  Tab through windows by recency of use.+-- Copyright   :  (c) 2022 L. S. Leary+-- License     :  BSD3-style (see LICENSE)+--+-- Maintainer  :  @LSLeary (on github)+-- Stability   :  unstable+-- Portability :  unportable+--+-- Based on the Alt+Tab behaviour common outside of xmonad.+--+-----------------------------------------------------------------------------++-- --< Imports & Exports >-- {{{++module XMonad.Actions.MostRecentlyUsed (++  -- * Usage+  -- $usage++  -- * Interface+  configureMRU,+  mostRecentlyUsed,+  withMostRecentlyUsed,+  Location(..),++  ) where++-- base+import Data.List.NonEmpty (nonEmpty)+import Data.IORef (newIORef, readIORef, writeIORef, modifyIORef)+import Control.Monad.IO.Class (MonadIO)++-- mtl+import Control.Monad.Trans (lift)+import Control.Monad.State (get, put, gets)++-- containers+import qualified Data.Map.Strict as M++-- xmonad+import XMonad+  ( Window, KeySym, keyPress, io+  , Event (DestroyWindowEvent, UnmapEvent, ev_send_event, ev_window)+  )+import XMonad.Core+  ( X, XConfig(..), windowset, WorkspaceId, ScreenId+  , ExtensionClass(..), StateExtension(..)+  , waitingUnmap+  )+import XMonad.Operations (screenWorkspace)+import qualified XMonad.StackSet as W++-- xmonad-contrib+import qualified XMonad.Util.ExtensibleConf  as XC+import qualified XMonad.Util.ExtensibleState as XS+import XMonad.Util.PureX+  (handlingRefresh, curScreenId, curTag, greedyView, view, peek, focusWindow)+import XMonad.Util.History (History, origin, event, erase, ledger)+import XMonad.Actions.Repeatable (repeatableSt)+import XMonad.Prelude++-- }}}++-- --< Core Data Types: WindowHistory & Location >-- {{{++data WindowHistory = WinHist+  { busy :: !Bool+  , hist :: !(History Window Location)+  } deriving (Show, Read)++instance ExtensionClass WindowHistory where+  initialValue = WinHist+    { busy = False+    , hist = origin+    }+  extensionType = PersistentExtension++data Location = Location+  { workspace :: !WorkspaceId+  , screen    :: !ScreenId+  } deriving (Show, Read, Eq, Ord)++-- }}}++-- --< Interface >-- {{{++-- $usage+--+-- 'configureMRU' must be applied to your config in order for 'mostRecentlyUsed'+-- to work.+--+-- > main :: IO ()+-- > main = xmonad . configureMRU . ... $ def+-- >   { ...+-- >   }+--+-- Once that's done, it can be used normally in keybinds:+--+-- > , ((mod1Mask, xK_Tab), mostRecentlyUsed [xK_Alt_L, xK_Alt_R] xK_Tab)+--+-- N.B.: This example assumes that 'mod1Mask' corresponds to alt, which is not+-- always the case, depending on how your system is configured.++-- | Configure xmonad to support 'mostRecentlyUsed'.+configureMRU :: XConfig l -> XConfig l+configureMRU = XC.once f (MRU ()) where+  f cnf = cnf+    { logHook         = logHook         cnf <> logWinHist+    , handleEventHook = handleEventHook cnf <> winHistEH+    }+newtype MRU = MRU () deriving Semigroup++-- | An action to browse through the history of focused windows, taking+--   another step back with each tap of the key.+mostRecentlyUsed+  :: [KeySym] -- ^ The 'KeySym's corresponding to the modifier to which the+              --   action is bound.+  -> KeySym   -- ^ The 'KeySym' corresponding to the key to which the action+              --   is bound.+  -> X ()+mostRecentlyUsed mods key = do+  (toUndo, undo) <- undoer+  let undoably curThing withThing thing = curThing >>= \cur ->+        when (cur /= thing) $ withThing thing >> toUndo (withThing cur)+  withMostRecentlyUsed mods key $ \win Location{workspace,screen} ->+    handlingRefresh $ do+      undo+      undoably curScreenId viewScreen screen+      undoably curTag      greedyView workspace+      mi <- gets (W.findTag win . windowset)+      for_ mi $ \i -> do+        undoably curTag greedyView i+        mfw <- peek+        for_ mfw $ \fw -> do+          undoably (pure fw) focusWindow win+  where+    undoer :: (MonadIO m, Monoid a) => m (m a -> m (), m a)+    undoer = do+      ref <- io . newIORef $ pure mempty+      let toUndo = io . modifyIORef ref . liftA2 (<>)+          undo   = join (io $ readIORef ref)+                <* io (writeIORef ref $ pure mempty)+      pure (toUndo, undo)+    viewScreen :: ScreenId -> X Any+    viewScreen scr = screenWorkspace scr >>= foldMap view++-- | A version of 'mostRecentlyUsed' that allows you to customise exactly what+--   is done with each window you tab through (the default being to visit its+--   previous 'Location' and give it focus).+withMostRecentlyUsed+  :: [KeySym]                     -- ^ The 'KeySym's corresponding to the+                                  --   modifier to which the action is bound.+  -> KeySym                       -- ^ The 'KeySym' corresponding to the key to+                                  --   which the action is bound.+  -> (Window -> Location -> X ()) -- ^ The function applied to each window.+  -> X ()+withMostRecentlyUsed mods tab preview = do+  wh@WinHist{busy,hist} <- XS.get+  unless busy $ do+    XS.put wh{ busy = True }++    for_ (nonEmpty $ ledger hist) $ \ne -> do+      mfw <- gets (W.peek . windowset)+      let iSt = case cycleS ne of+            (w, _) :~ s | mfw == Just w -> s+            s                           -> s+      repeatableSt iSt mods tab $ \t s ->+        when (t == keyPress && s == tab) (pop >>= lift . uncurry preview)++    XS.modify $ \ws@WinHist{} -> ws{ busy = False }+    logWinHist+  where+    pop = do+      h :~ t <- get+      put t $> h++-- }}}++-- --< Raw Config >-- {{{++logWinHist :: X ()+logWinHist = do+  wh@WinHist{busy,hist} <- XS.get+  unless busy $ do+    cs <- gets (W.current . windowset)+    let cws = W.workspace cs+    for_ (W.stack cws) $ \st -> do+      let location = Location{ workspace = W.tag cws, screen = W.screen cs }+      XS.put wh{ hist = event (W.focus st) location hist }++winHistEH :: Event -> X All+winHistEH ev = All True <$ case ev of+  UnmapEvent{ ev_send_event = synth, ev_window = w } -> do+    e <- gets (fromMaybe 0 . M.lookup w . waitingUnmap)+    when (synth || e == 0) (collect w)+  DestroyWindowEvent{                ev_window = w } -> collect w+  _                                                  -> pure ()+  where collect w = XS.modify $ \wh@WinHist{hist} -> wh{ hist = erase w hist }++-- }}}
XMonad/Actions/MouseGestures.hs view
@@ -32,7 +32,7 @@  -- $usage ----- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Actions.MouseGestures -- > import qualified XMonad.StackSet as W
XMonad/Actions/MouseResize.hs view
@@ -37,7 +37,7 @@ -- "XMonad.Layout.SimpleFloat" or "XMonad.Layout.DecorationMadness". -- -- You can use this module with the following in your--- @~\/.xmonad\/xmonad.hs@:+-- @xmonad.hs@: -- -- > import XMonad.Actions.MouseResize -- > import XMonad.Layout.WindowArranger@@ -50,9 +50,9 @@ -- -- > main = xmonad def { layoutHook = myLayout } ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook".  mouseResize :: l a -> ModifiedLayout MouseResize l a mouseResize = ModifiedLayout (MR [])
XMonad/Actions/Navigation2D.hs view
@@ -46,7 +46,6 @@                                    , sideNavigation                                    , sideNavigationWithBias                                    , hybridOf-                                   , hybridNavigation                                    , fullScreenRect                                    , singleWindowRect                                    , switchLayer@@ -67,6 +66,7 @@ import qualified XMonad.Util.ExtensibleState as XS import XMonad.Util.EZConfig (additionalKeys, additionalKeysP) import XMonad.Util.Types+import qualified Data.List.NonEmpty as NE  -- $usage -- #Usage#@@ -85,7 +85,7 @@ -- layers and allows customization of the navigation strategy for the tiled -- layer based on the layout currently in effect. ----- You can use this module with (a subset of) the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with (a subset of) the following in your @xmonad.hs@: -- -- > import XMonad.Actions.Navigation2D --@@ -98,8 +98,16 @@ -- >                              False -- >               $ def ----- Alternatively, you can use navigation2DP:+-- /NOTE/: the @def@ argument to 'navigation2D' contains the strategy+-- that decides which windows actually get selected.  While the default+-- behaviour tries to keep them into account, if you use modules that+-- influence tiling in some way, like "XMonad.Layout.Spacing" or+-- "XMonad.Layout.Gaps", you should think about using a different+-- strategy, if you find the default behaviour to be unnatural.  Check+-- out the [finer points](#g:Finer_Points) below for more information. --+-- Alternatively to 'navigation2D', you can use 'navigation2DP':+-- -- > main = xmonad $ navigation2DP def -- >                               ("<Up>", "<Left>", "<Down>", "<Right>") -- >                               [("M-",   windowGo  ),@@ -108,7 +116,7 @@ -- >               $ def -- -- That's it. If instead you'd like more control, you can combine--- withNavigation2DConfig and additionalNav2DKeys or additionalNav2DKeysP:+-- 'withNavigation2DConfig' and 'additionalNav2DKeys' or 'additionalNav2DKeysP': -- -- > main = xmonad $ withNavigation2DConfig def -- >               $ additionalNav2DKeys (xK_Up, xK_Left, xK_Down, xK_Right)@@ -162,7 +170,7 @@ -- -- For detailed instruction on editing the key binding see: ----- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  -- $finer_points -- #Finer_Points#@@ -179,9 +187,19 @@ -- values in the above example to 'True'.  You could also decide you want -- wrapping only for a subset of the operations and no wrapping for others. ----- By default, all layouts use the 'defaultTiledNavigation' strategy specified--- in the 'Navigation2DConfig' (by default, line navigation is used).  To--- override this behaviour for some layouts, add a pair (\"layout name\",+-- By default, all layouts use the 'defaultTiledNavigation' strategy+-- specified in the 'Navigation2DConfig' (by default, line navigation is+-- used).  Many more navigation strategies are available; some may feel+-- more natural, depending on the layout and user:+--+--   * 'lineNavigation'+--   * 'centerNavigation'+--   * 'sideNavigation'+--   * 'sideNavigationWithBias'+--+-- There is also the ability to combine two strategies with 'hybridOf'.+--+-- To override the default behaviour for some layouts, add a pair (\"layout name\", -- navigation strategy) to the 'layoutNavigation' list in the -- 'Navigation2DConfig', where \"layout name\" is the string reported by the -- layout's description method (normally what is shown as the layout name in@@ -327,7 +345,7 @@ -- and push it to the right until it intersects with at least one other window. -- Of those windows, one with a point that is the closest to the centre of the -- line (+1) is selected. This is probably the most intuitive strategy for the--- tiled layer when using XMonad.Layout.Spacing.+-- tiled layer when using "XMonad.Layout.Spacing". sideNavigation :: Navigation2D sideNavigation = N 1 (doSideNavigationWithBias 1) @@ -359,10 +377,6 @@   where     applyToBoth f g a b c = f a b c <|> g a b c -{-# DEPRECATED hybridNavigation "Use hybridOf with lineNavigation and centerNavigation as arguments." #-}-hybridNavigation :: Navigation2D-hybridNavigation = hybridOf lineNavigation centerNavigation- -- | Stores the configuration of directional navigation. The 'Default' instance -- uses line navigation for the tiled layer and for navigation between screens, -- and center navigation for the float layer.  No custom navigation strategies@@ -451,7 +465,7 @@                                             }  instance Default Navigation2DConfig where-    def                   = Navigation2DConfig { defaultTiledNavigation = lineNavigation+    def                   = Navigation2DConfig { defaultTiledNavigation = hybridOf lineNavigation sideNavigation                                                , floatNavigation        = centerNavigation                                                , screenNavigation       = lineNavigation                                                , layoutNavigation       = []@@ -770,8 +784,7 @@      -- All the points that coincide with the current center and succeed it     -- in the (appropriately ordered) window stack.-    onCtr' = L.tail $ L.dropWhile ((cur /=) . fst) onCtr-             -- tail should be safe here because cur should be in onCtr+    onCtr' = L.drop 1 $ L.dropWhile ((cur /=) . fst) onCtr      -- All the points that do not coincide with the current center and which     -- lie in the (rotated) right cone.@@ -871,8 +884,8 @@     -- Reconstruct the workspaces' window stacks to reflect the swap.     newvisws  = zipWith (\ws wns -> ws { W.stack = W.differentiate wns }) visws newwins     newscrs   = zipWith (\scr ws -> scr { W.workspace = ws }) scrs newvisws-    newwinset = winset { W.current = head newscrs-                       , W.visible = tail newscrs+    newwinset = winset { W.current = NE.head (notEmpty newscrs) -- Always at least one screen.+                       , W.visible = drop 1 newscrs                        }  -- | Calculates the center of a rectangle
XMonad/Actions/OnScreen.hs view
@@ -27,7 +27,7 @@     ) where  import XMonad-import XMonad.Prelude (fromMaybe, guard)+import XMonad.Prelude (fromMaybe, guard, empty) import XMonad.StackSet hiding (new)  @@ -140,16 +140,15 @@     let st' = hidden st     -- make sure we actually have to do something     guard $ i == (tag . workspace $ current st)-    guard $ not (null st')-    -- finally, toggle!-    return $ f (tag . head $ st') st-+    case st' of+      []      -> empty+      (h : _) -> return $ f (tag h) st  -- finally, toggle!  -- $usage -- -- This module provides an easy way to control, what you see on other screens in -- xinerama mode without having to focus them. Put this into your--- @~\/.xmonad\/xmonad.hs@:+-- @xmonad.hs@: -- -- > import XMonad.Actions.OnScreen --@@ -183,4 +182,4 @@ -- where 0 is the first screen and \"1\" the workspace with the tag \"1\". -- -- For detailed instructions on editing your key bindings, see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.
XMonad/Actions/PerLayoutKeys.hs view
@@ -25,14 +25,14 @@  -- $usage ----- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- >  import XMonad.Actions.PerLayoutKeys -- -- >   ,((0, xK_F2), bindByLayout [("Tall", spawn "rxvt"), ("Mirror Tall", spawn "xeyes"), ("", spawn "xmessage hello")]) -- -- For detailed instructions on editing your key bindings, see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  -- | Uses supplied function to decide which action to run depending on current layout name. chooseActionByLayout :: (String->X()) -> X()
XMonad/Actions/PerWindowKeys.hs view
@@ -24,7 +24,7 @@  -- $usage ----- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- >  import XMonad.Actions.PerWindowKeys --@@ -41,7 +41,7 @@ -- doThisIfTheOthersFail)]@. -- -- For detailed instructions on editing your key bindings, see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  -- | Run an action if a Query holds true. Doesn't stop at the first one that -- does, however, and could potentially run all actions.
XMonad/Actions/PerWorkspaceKeys.hs view
@@ -25,14 +25,14 @@  -- $usage ----- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- >  import XMonad.Actions.PerWorkspaceKeys -- -- >   ,((0, xK_F2), bindOn [("1", spawn "rxvt"), ("2", spawn "xeyes"), ("", spawn "xmessage hello")]) -- -- For detailed instructions on editing your key bindings, see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  -- | Uses supplied function to decide which action to run depending on current workspace name. chooseAction :: (String->X()) -> X()
XMonad/Actions/PhysicalScreens.hs view
@@ -46,7 +46,7 @@ The default ScreenComparator orders screens by the upper-left-most corner, from top-to-bottom and then left-to-right. -Example usage in your @~\/.xmonad\/xmonad.hs@ file:+Example usage in your @xmonad.hs@ file:  > import XMonad.Actions.PhysicalScreens > import Data.Default@@ -65,7 +65,7 @@ >     , (f, mask) <- [(viewScreen def, 0), (sendToScreen def, shiftMask)]]  For detailed instructions on editing your key bindings, see-"XMonad.Doc.Extending#Editing_key_bindings".+<https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  -}  -- | The type of the index of a screen by location@@ -75,7 +75,7 @@ getScreenIdAndRectangle screen = (W.screen screen, rect) where   rect = screenRect $ W.screenDetail screen --- | Translate a physical screen index to a "ScreenId"+-- | Translate a physical screen index to a 'ScreenId' getScreen:: ScreenComparator -> PhysicalScreen -> X (Maybe ScreenId) getScreen (ScreenComparator cmpScreen) (P i) = do w <- gets windowset                                                   let screens = W.current w : W.visible w
XMonad/Actions/Plane.hs view
@@ -41,13 +41,13 @@  import Data.Map (Map, fromList) -import XMonad.Prelude+import XMonad.Prelude hiding (fromList) import XMonad import XMonad.StackSet hiding (workspaces) import XMonad.Util.Run  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@ file:+-- You can use this module with the following in your @xmonad.hs@ file: -- -- > import XMonad.Actions.Plane -- > import Data.Map (union)@@ -59,7 +59,7 @@ -- > myNewKeys (XConfig {modMask = modm}) = planeKeys modm (Lines 3) Finite -- -- For detailed instructions on editing your key bindings, see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  -- | Direction to go in the plane. data Direction =  ToLeft | ToUp | ToRight | ToDown deriving Enum
XMonad/Actions/Prefix.hs view
@@ -29,6 +29,7 @@        , withPrefixArgument        , isPrefixRaw        , isPrefixNumeric+       , orIfPrefixed        , ppFormatPrefix        ) where @@ -40,11 +41,13 @@ import XMonad.Util.Paste (sendKey) import XMonad.Actions.Submap (submapDefaultWithKey) import XMonad.Util.EZConfig (readKeySequence)+import qualified Data.List.NonEmpty as NE+import Data.List.NonEmpty ((<|))  {- $usage  This module implements Emacs-style prefix argument.  The argument-comes in two flavours, "Raw" and "Numeric".+comes in two flavours, 'Raw' and 'Numeric'.  To initiate the "prefix mode" you hit the prefix keybinding (default C-u).  This sets the Raw argument value to 1.  Repeatedly hitting this@@ -72,7 +75,7 @@  >    ((modm, xK_a), withPrefixArgument addMaybeClean) -Hitting MOD-a will add the <file> to the playlist while C-u MOD-a will+Hitting MOD-a will add the @\<file\>@ to the playlist while C-u MOD-a will clear the playlist and then add the file.  You can of course use an anonymous action, like so:@@ -128,11 +131,11 @@                   -> XConfig l                   -> XConfig l usePrefixArgument prefix conf =-  conf{ keys = M.insert binding (handlePrefixArg [binding]) . keys conf }+  conf{ keys = M.insert binding (handlePrefixArg (binding :| [])) . keys conf }  where   binding = case readKeySequence conf prefix of-    Just [key] -> key-    _          -> (controlMask, xK_u)+    Just (key :| []) -> key+    _                -> (controlMask, xK_u)  -- | Set Prefix up with default prefix key (C-u). useDefaultPrefixArgument :: LayoutClass l Window@@ -140,7 +143,7 @@                          -> XConfig l useDefaultPrefixArgument = usePrefixArgument "C-u" -handlePrefixArg :: [(KeyMask, KeySym)] -> X ()+handlePrefixArg :: NonEmpty (KeyMask, KeySym) -> X () handlePrefixArg events = do   ks <- asks keyActions   logger <- asks (logHook . config)@@ -161,19 +164,19 @@               Raw _ -> XS.put $ Numeric x               Numeric a -> XS.put $ Numeric $ a * 10 + x               None -> return () -- should never happen-            handlePrefixArg (key:events)+            handlePrefixArg (key <| events)           else do             prefix <- XS.get             mapM_ (uncurry sendKey) $ case prefix of-              Raw a -> replicate a (head events) ++ [key]-              _ -> reverse (key:events)+              Raw a -> replicate a (NE.head events) ++ [key]+              _ -> reverse (key : toList events)         keyToNum = (xK_0, 0) : zip [xK_1 .. xK_9] [1..9]  -- | Turn a prefix-aware X action into an X-action. -- -- First, fetch the current prefix, then pass it as argument to the -- original function.  You should use this to "run" your commands.-withPrefixArgument :: (PrefixArgument -> X ()) -> X ()+withPrefixArgument :: (PrefixArgument -> X a) -> X a withPrefixArgument = (>>=) XS.get  -- | Test if 'PrefixArgument' is 'Raw' or not.@@ -185,6 +188,13 @@ isPrefixNumeric :: PrefixArgument -> Bool isPrefixNumeric (Numeric _) = True isPrefixNumeric _ = False++-- | Execute the first action, unless any prefix argument is given,+-- in which case the second action is chosen instead.+--+-- > action1 `orIfPrefixed` action2+orIfPrefixed :: X a -> X a -> X a+orIfPrefixed xa xb = withPrefixArgument $ bool xa xb . isPrefixRaw  -- | Format the prefix using the Emacs convetion for use in a -- statusbar, like xmobar.
XMonad/Actions/Promote.hs view
@@ -28,7 +28,7 @@  -- $usage ----- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- >    import XMonad.Actions.Promote --@@ -37,7 +37,7 @@ -- >   , ((modm,               xK_Return), promote) -- -- For detailed instructions on editing your key bindings, see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  -- | Move the focused window to the master pane. All other windows --   retain their order. If focus is in the master, swap it with the
+ XMonad/Actions/Repeatable.hs view
@@ -0,0 +1,89 @@+-----------------------------------------------------------------------------+-- |+-- Module      :  XMonad.Actions.Repeatable+-- Description :  Actions you'd like to repeat.+-- Copyright   :  (c) 2022 L. S. Leary+-- License     :  BSD3-style (see LICENSE)+--+-- Maintainer  :  @LSLeary (on github)+-- Stability   :  unstable+-- Portability :  unportable+--+-- This module factors out the shared logic of "XMonad.Actions.CycleRecentWS",+-- "XMonad.Actions.CycleWorkspaceByScreen", "XMonad.Actions.CycleWindows" and+-- "XMonad.Actions.MostRecentlyUsed".+--+-- See the source of these modules for usage examples.+--+-----------------------------------------------------------------------------++module XMonad.Actions.Repeatable+  ( repeatable+  , repeatableSt+  , repeatableM+  ) where++-- mtl+import Control.Monad.State (StateT(..))++-- X11+import Graphics.X11.Xlib.Extras++-- xmonad+import XMonad+++-- | An action that temporarily usurps and responds to key press/release events,+--   concluding when one of the modifier keys is released.+repeatable+  :: [KeySym]                      -- ^ The list of 'KeySym's under the+                                   --   modifiers used to invoke the action.+  -> KeySym                        -- ^ The keypress that invokes the action.+  -> (EventType -> KeySym -> X ()) -- ^ The keypress handler.+  -> X ()+repeatable = repeatableM id++-- | A more general variant of 'repeatable' with a stateful handler,+--   accumulating a monoidal return value throughout the events.+repeatableSt+  :: Monoid a+  => s                                     -- ^ Initial state.+  -> [KeySym]                              -- ^ The list of 'KeySym's under the+                                           --   modifiers used to invoke the+                                           --   action.+  -> KeySym                                -- ^ The keypress that invokes the+                                           --   action.+  -> (EventType -> KeySym -> StateT s X a) -- ^ The keypress handler.+  -> X (a, s)+repeatableSt iSt = repeatableM $ \m -> runStateT m iSt++-- | A more general variant of 'repeatable' with an arbitrary monadic handler,+--   accumulating a monoidal return value throughout the events.+repeatableM+  :: (MonadIO m, Monoid a)+  => (m a -> X b)                 -- ^ How to run the monad in 'X'.+  -> [KeySym]                     -- ^ The list of 'KeySym's under the+                                  --   modifiers used to invoke the action.+  -> KeySym                       -- ^ The keypress that invokes the action.+  -> (EventType -> KeySym -> m a) -- ^ The keypress handler.+  -> X b+repeatableM run mods key pressHandler = do+  XConf{ theRoot = root, display = d } <- ask+  run (repeatableRaw d root mods key pressHandler)++repeatableRaw+  :: (MonadIO m, Monoid a)+  => Display -> Window+  -> [KeySym] -> KeySym -> (EventType -> KeySym -> m a) -> m a+repeatableRaw d root mods key pressHandler = do+  io (grabKeyboard d root False grabModeAsync grabModeAsync currentTime)+  handleEvent (keyPress, key) <* io (ungrabKeyboard d currentTime)+  where+    getNextEvent = io $ allocaXEvent $ \p -> do+      maskEvent d (keyPressMask .|. keyReleaseMask) p+      KeyEvent{ ev_event_type = t, ev_keycode = c } <- getEvent p+      s <- keycodeToKeysym d c 0+      return (t, s)+    handleEvent (t, s)+      | t == keyRelease && s `elem` mods = pure mempty+      | otherwise = (<>) <$> pressHandler t s <*> (getNextEvent >>= handleEvent)
XMonad/Actions/RotSlaves.hs view
@@ -17,7 +17,11 @@ module XMonad.Actions.RotSlaves (         -- $usage         rotSlaves', rotSlavesUp, rotSlavesDown,-        rotAll', rotAllUp, rotAllDown+        rotAll', rotAllUp, rotAllDown,++        -- * Generic list rotations+        -- $generic+        rotUp, rotDown         ) where  import XMonad@@ -39,13 +43,13 @@ -- TwoPane layout (see "XMonad.Layout.TwoPane"). -- -- For detailed instructions on editing your key bindings, see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  -- | Rotate the windows in the current stack, excluding the first one --   (master). rotSlavesUp,rotSlavesDown :: X ()-rotSlavesUp   = windows $ modify' (rotSlaves' (\l -> tail l++[head l]))-rotSlavesDown = windows $ modify' (rotSlaves' (\l -> last l : init l))+rotSlavesUp   = windows $ modify' (rotSlaves' rotUp)+rotSlavesDown = windows $ modify' (rotSlaves' rotDown)  -- | The actual rotation, as a pure function on the window stack. rotSlaves' :: ([a] -> [a]) -> Stack a -> Stack a@@ -57,10 +61,19 @@  -- | Rotate all the windows in the current stack. rotAllUp,rotAllDown :: X ()-rotAllUp   = windows $ modify' (rotAll' (\l -> tail l++[head l]))-rotAllDown = windows $ modify' (rotAll' (\l -> last l : init l))+rotAllUp   = windows $ modify' (rotAll' rotUp)+rotAllDown = windows $ modify' (rotAll' rotDown)  -- | The actual rotation, as a pure function on the window stack. rotAll' :: ([a] -> [a]) -> Stack a -> Stack a rotAll' f s = Stack r (reverse revls) rs     where (revls, notEmpty -> r :| rs) = splitAt (length (up s)) (f (integrate s))++-- $generic+-- Generic list rotations such that @rotUp [1..4]@ is equivalent to+-- @[2,3,4,1]@ and @rotDown [1..4]@ to @[4,1,2,3]@. They both are+-- @id@ for null or singleton lists.+rotUp :: [a] -> [a]+rotUp   l = drop 1 l ++ take 1 l+rotDown :: [a] -> [a]+rotDown = reverse . rotUp . reverse
XMonad/Actions/RotateSome.hs view
@@ -35,7 +35,7 @@ import XMonad.Util.Stack (reverseS)  {- $usage-You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+You can use this module with the following in your @xmonad.hs@:  > import XMonad.Actions.RotateSome 
XMonad/Actions/Search.hs view
@@ -31,33 +31,50 @@                                  prefixAware,                                  namedEngine, -                                 amazon,                                  alpha,+                                 amazon,+                                 arXiv,+                                 aur,+                                 clojureDocs,                                  codesearch,+                                 cratesIo,                                  deb,                                  debbts,                                  debpts,                                  dictionary,+                                 duckduckgo,                                  ebay,+                                 flora,                                  github,                                  google,                                  hackage,+                                 homeManager,                                  hoogle,                                  images,                                  imdb,                                  lucky,                                  maps,                                  mathworld,+                                 ncatlab,+                                 nixos,+                                 noogle,                                  openstreetmap,+                                 protondb,+                                 rosettacode,+                                 rustStd,                                  scholar,+                                 sourcehut,                                  stackage,+                                 steam,                                  thesaurus,+                                 vocabulary,+                                 voidpgks_x86_64,+                                 voidpgks_x86_64_musl,                                  wayback,                                  wikipedia,                                  wiktionary,                                  youtube,-                                 vocabulary,-                                 duckduckgo,+                                 zbmath,                                  multi,                                   -- * Use case: searching with a submap                                   -- $tip@@ -102,12 +119,20 @@     The currently available search engines are: +* 'alpha' -- Wolfram|Alpha query.+ * 'amazon' -- Amazon keyword search. -* 'alpha' -- Wolfram|Alpha query.+* 'arXiv' -- Open-access preprint archive. +* 'aur' -- Arch User Repository.++* 'clojureDocs' -- Documentation and examples repository for Clojure.+ * 'codesearch' -- Google Labs Code Search search. +* 'cratesIo' -- Rust crate registry.+ * 'deb'    -- Debian package search.  * 'debbts' -- Debian Bug Tracking System.@@ -116,17 +141,21 @@  * 'dictionary' -- dictionary.reference.com search. +* 'duckduckgo' -- DuckDuckGo search engine.+ * 'ebay' -- Ebay keyword search. +* 'flora' -- Prettier Haskell package database.+ * 'github' -- GitHub keyword search.  * 'google' -- basic Google search.  * 'hackage' -- Hackage, the Haskell package database. -* 'hoogle' -- Hoogle, the Haskell libraries API search engine.+* 'homeManager' -- Search Nix's home-manager's options. -* 'stackage' -- Stackage, An alternative Haskell libraries API search engine.+* 'hoogle' -- Hoogle, the Haskell libraries API search engine.  * 'images' -- Google images. @@ -138,21 +167,45 @@  * 'mathworld' -- Wolfram MathWorld search. +* 'ncatlab' -- Higer Algebra, Homotopy and Category Theory Wiki.++* 'nixos' -- Search NixOS packages and options.++* 'noogle' -- 'hoogle'-like Nix API search engine.+ * 'openstreetmap' -- OpenStreetMap free wiki world map. +* 'protondb' -- Steam Proton Game Database.++* 'rosettacode' -- Programming chrestomathy wiki.++* 'rustStd' -- Rust standard library documentation.+ * 'scholar' -- Google scholar academic search. +* 'sourcehut' -- Sourcehut projects search.++* 'stackage' -- Stackage, An alternative Haskell libraries API search engine.++* 'steam' -- Steam games search.+ * 'thesaurus' -- thesaurus.com search. +* 'vocabulary' -- Dictionary search.++* 'voidpgks_x86_64' -- Void Linux packages search for @x86_64@.++* 'voidpgks_x86_64_musl' -- Void Linux packages search for @x86_64-musl@.+ * 'wayback' -- the Wayback Machine.  * 'wikipedia' -- basic Wikipedia search. -* 'youtube' -- Youtube video search.+* 'wiktionary' -- Wiktionary search. -* 'vocabulary' -- Dictionary search+* 'youtube' -- Youtube video search. -* 'duckduckgo' -- DuckDuckGo search engine.+* 'zbmath' -- Open alternative to MathSciNet.  * 'multi' -- Search based on the prefix. \"amazon:Potter\" will use amazon, etc. With no prefix searches google. @@ -269,7 +322,7 @@    inside of a URL instead of in the end) you can use the alternative 'searchEngineF' function.  > searchFunc :: String -> String-> searchFunc s | "wiki:"    `isPrefixOf` s = "https://en.wikipedia.org/wiki/" ++ (escape $ tail $ snd $ break (==':') s)+> searchFunc s | "wiki:"    `isPrefixOf` s = "https://en.wikipedia.org/wiki/" ++ (escape $ drop 1 $ snd $ break (==':') s) >              | "https://" `isPrefixOf` s = s >              | otherwise                 = (use google) s > myNewEngine = searchEngineF "mymulti" searchFunc@@ -286,39 +339,57 @@ searchEngineF = SearchEngine  -- The engines.-amazon, alpha, codesearch, deb, debbts, debpts, dictionary, ebay, github, google, hackage, hoogle,-  images, imdb, lucky, maps, mathworld, openstreetmap, scholar, stackage, thesaurus, vocabulary, wayback, wikipedia, wiktionary,-  youtube, duckduckgo :: SearchEngine-amazon        = searchEngine "amazon"        "https://www.amazon.com/s/ref=nb_sb_noss_2?url=search-alias%3Daps&field-keywords="+alpha, amazon, arXiv, aur, clojureDocs, codesearch, cratesIo, deb, debbts, debpts, dictionary, duckduckgo, ebay, flora,+  github, google, hackage, homeManager, hoogle, images, imdb, lucky, maps, mathworld, ncatlab, nixos, noogle, openstreetmap, protondb, +  rosettacode, rustStd, scholar, sourcehut, stackage, steam, thesaurus, vocabulary, voidpgks_x86_64, voidpgks_x86_64_musl, wayback, +  wikipedia, wiktionary, youtube, zbmath :: SearchEngine alpha         = searchEngine "alpha"         "https://www.wolframalpha.com/input/?i="+amazon        = searchEngine "amazon"        "https://www.amazon.com/s/ref=nb_sb_noss_2?url=search-alias%3Daps&field-keywords="+arXiv         = searchEngineF "arXiv"        (\s -> "https://arxiv.org/search/?query=" <> s <> "&searchtype=all")+aur           = searchEngine "aur"           "https://aur.archlinux.org/packages?&K="+clojureDocs   = searchEngine "clojureDocs"   "https://clojuredocs.org/search?q=" codesearch    = searchEngine "codesearch"    "https://developers.google.com/s/results/code-search?q="+cratesIo      = searchEngine  "cratesIo"     "https://crates.io/search?q=" deb           = searchEngine "deb"           "https://packages.debian.org/" debbts        = searchEngine "debbts"        "https://bugs.debian.org/" debpts        = searchEngine "debpts"        "https://packages.qa.debian.org/" dictionary    = searchEngine "dict"          "https://dictionary.reference.com/browse/"+duckduckgo    = searchEngine "duckduckgo"    "https://duckduckgo.com/?t=lm&q=" ebay          = searchEngine "ebay"          "https://www.ebay.com/sch/i.html?_nkw="+flora         = searchEngine "flora"         "https://flora.pm/search?q=" github        = searchEngine "github"        "https://github.com/search?q=" google        = searchEngine "google"        "https://www.google.com/search?q=" hackage       = searchEngine "hackage"       "https://hackage.haskell.org/package/"+homeManager   = searchEngine "homeManager"   "https://mipmip.github.io/home-manager-option-search/?query=" hoogle        = searchEngine "hoogle"        "https://hoogle.haskell.org/?hoogle=" images        = searchEngine "images"        "https://images.google.fr/images?q=" imdb          = searchEngine "imdb"          "https://www.imdb.com/find?s=all&q=" lucky         = searchEngine "lucky"         "https://www.google.com/search?btnI&q=" maps          = searchEngine "maps"          "https://maps.google.com/maps?q=" mathworld     = searchEngine "mathworld"     "https://mathworld.wolfram.com/search/?query="+ncatlab       = searchEngine "ncatlab"       "https://ncatlab.org/nlab/search?query="+nixos         = searchEngine "nixos"         "https://search.nixos.org/packages?channel=unstable&from=0&size=200&sort=relevance&type=packages&query="+noogle        = searchEngineF "noogle"       (\s -> "https://noogle.dev/?search=" <> s <> "&page=1&to=any&from=any") openstreetmap = searchEngine "openstreetmap" "https://www.openstreetmap.org/search?query="+protondb      = searchEngine "protondb"      "https://www.protondb.com/search?q="+rosettacode   = searchEngine "rosettacode"   "https://rosettacode.org/w/index.php?search="+rustStd       = searchEngine "rustStd"       "https://doc.rust-lang.org/std/index.html?search=" scholar       = searchEngine "scholar"       "https://scholar.google.com/scholar?q="+sourcehut     = searchEngine "sourcehut"     "https://sr.ht/projects?search=" stackage      = searchEngine "stackage"      "https://www.stackage.org/lts/hoogle?q="+steam         = searchEngine "steam"         "https://store.steampowered.com/search/?term=" thesaurus     = searchEngine "thesaurus"     "https://thesaurus.com/browse/"+vocabulary    = searchEngine "vocabulary"    "https://www.vocabulary.com/search?q="+voidpgks_x86_64      = searchEngine "voidpackages" "https://voidlinux.org/packages/?arch=x86_64&q="+voidpgks_x86_64_musl = searchEngine "voidpackages" "https://voidlinux.org/packages/?arch=x86_64-musl&q="+wayback       = searchEngineF "wayback"      ("https://web.archive.org/web/*/"++) wikipedia     = searchEngine "wiki"          "https://en.wikipedia.org/wiki/Special:Search?go=Go&search=" wiktionary    = searchEngine "wikt"          "https://en.wiktionary.org/wiki/Special:Search?go=Go&search=" youtube       = searchEngine "youtube"       "https://www.youtube.com/results?search_type=search_videos&search_query="-wayback       = searchEngineF "wayback"      ("https://web.archive.org/web/*/"++)-vocabulary    = searchEngine "vocabulary"    "https://www.vocabulary.com/search?q="-duckduckgo    = searchEngine "duckduckgo"    "https://duckduckgo.com/?t=lm&q="+zbmath        = searchEngine "zbmath"        "https://zbmath.org/?q="  multi :: SearchEngine-multi = namedEngine "multi" $ foldr1 (!>) [amazon, alpha, codesearch, deb, debbts, debpts, dictionary, ebay, github, google, hackage, hoogle, images, imdb, lucky, maps, mathworld, openstreetmap, scholar, thesaurus, wayback, wikipedia, wiktionary, duckduckgo, prefixAware google]+multi = namedEngine "multi" $ foldr1 (!>) [alpha, amazon, aur, codesearch, deb, debbts, debpts, dictionary, duckduckgo, ebay, flora, github, hackage, hoogle, images, imdb, lucky, maps, mathworld, ncatlab, openstreetmap, protondb, rosettacode, scholar, sourcehut, stackage, steam, thesaurus, vocabulary, voidpgks_x86_64, voidpgks_x86_64_musl, wayback, wikipedia, wiktionary, youtube, prefixAware google]  {- | This function wraps up a search engine and creates a new one, which works    like the argument, but goes directly to a URL if one is given rather than
XMonad/Actions/ShowText.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE CPP #-}+{-# LANGUAGE MultiWayIf #-} ----------------------------------------------------------------------------- -- | -- Module      :  XMonad.Actions.ShowText@@ -26,7 +27,7 @@ import Data.Map (Map,empty,insert,lookup) import Prelude hiding (lookup) import XMonad-import XMonad.Prelude (All, fi, when)+import XMonad.Prelude (All, fi, listToMaybe) import XMonad.StackSet (current,screen) import XMonad.Util.Font (Align(AlignCenter)                        , initXMF@@ -41,7 +42,7 @@ import qualified XMonad.Util.ExtensibleState as ES  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Actions.ShowText --@@ -87,8 +88,9 @@ handleTimerEvent (ClientMessageEvent _ _ _ dis _ mtyp d) = do     (ShowText m) <- ES.get :: X ShowText     a <- io $ internAtom dis "XMONAD_TIMER" False-    when (mtyp == a && not (null d))-         (whenJust (lookup (fromIntegral $ head d) m) deleteWindow)+    if | mtyp == a, Just dh <- listToMaybe d ->+           whenJust (lookup (fromIntegral dh) m) deleteWindow+       | otherwise -> pure ()     mempty handleTimerEvent _ = mempty 
XMonad/Actions/Sift.hs view
@@ -28,7 +28,7 @@ import XMonad.Util.Stack (reverseS)  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Actions.Sift --
XMonad/Actions/SimpleDate.hs view
@@ -24,7 +24,7 @@ import XMonad.Util.Run  -- $usage--- To use, import this module into @~\/.xmonad\/xmonad.hs@:+-- To use, import this module into @xmonad.hs@: -- -- >     import XMonad.Actions.SimpleDate --@@ -35,7 +35,7 @@ -- In this example, a popup date menu will now be bound to @mod-d@. -- -- For detailed instructions on editing your key bindings, see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  date :: X () date = unsafeSpawn "(date; sleep 10) | dzen2"
XMonad/Actions/SinkAll.hs view
@@ -13,7 +13,7 @@ -- 'sinkAll' function for backwards compatibility. ----------------------------------------------------------------------------- -module XMonad.Actions.SinkAll (+module XMonad.Actions.SinkAll {-# DEPRECATED "Use XMonad.Actions.WithAll instead" #-} (     -- * Usage     -- $usage @@ -23,7 +23,7 @@  -- $usage ----- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Actions.SinkAll --@@ -32,4 +32,4 @@ -- >   , ((modm .|. shiftMask, xK_t), sinkAll) -- -- For detailed instructions on editing your key bindings, see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.
XMonad/Actions/SpawnOn.hs view
@@ -43,7 +43,7 @@ import XMonad.Util.Process (getPPIDChain)  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- >    import XMonad.Actions.SpawnOn --@@ -63,7 +63,7 @@ -- the spawned application(e.g. float or resize it). -- -- For detailed instructions on editing your key bindings, see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  newtype Spawner = Spawner {pidsRef :: [(ProcessID, ManageHook)]} 
XMonad/Actions/Submap.hs view
@@ -32,10 +32,7 @@  {- $usage ----First, import this module into your @~\/.xmonad\/xmonad.hs@:+First, import this module into your @xmonad.hs@:  > import XMonad.Actions.Submap @@ -56,7 +53,7 @@ modifier.  For detailed instructions on editing your key bindings, see-"XMonad.Doc.Extending#Editing_key_bindings".+<https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  -} @@ -76,17 +73,17 @@ -- > -- > gotoLayout :: [(String, X ())]   -- for use with EZConfig -- > gotoLayout =  -- assumes you have a layout named "Tall" and one named "Full".--- >   ["M-l", visualSubmap def $ Map.fromList $ map (\(k, s, a) -> ((0, k), (s, a)))--- >             [ (xK_t, "Tall", switchToLayout "Tall")     -- "M-l t" switches to "Tall"--- >             , (xK_r, "Full", switchToLayout "Full")     -- "M-l r" switches to "full"--- >             ]]+-- >   [("M-l", visualSubmap def $ Map.fromList $ map (\(k, s, a) -> ((0, k), (s, a)))+-- >              [ (xK_t, "Tall", switchToLayout "Tall")     -- "M-l t" switches to "Tall"+-- >              , (xK_r, "Full", switchToLayout "Full")     -- "M-l r" switches to "full"+-- >              ])] -- -- One could alternatively also write @gotoLayout@ as ----- > gotoLayout = ["M-l", visualSubmap def $ Map.fromList $--- >                        [ ((0, xK_t), subName "Tall" $ switchToLayout "Tall")--- >                        , ((0, xK_r), subName "Full" $ switchToLayout "Full")--- >                        ]]+-- > gotoLayout = [("M-l", visualSubmap def $ Map.fromList $+-- >                         [ ((0, xK_t), subName "Tall" $ switchToLayout "Tall")+-- >                         , ((0, xK_r), subName "Full" $ switchToLayout "Full")+-- >                         ])] visualSubmap :: WindowConfig -- ^ The config for the spawned window.              -> M.Map (KeyMask, KeySym) (String, X ())                              -- ^ A map @keybinding -> (description, action)@.
XMonad/Actions/SwapPromote.hs view
@@ -63,6 +63,7 @@ import qualified Data.Map                       as M import qualified Data.Set                       as S import           Control.Arrow+import qualified Data.List.NonEmpty             as NE   -- $usage@@ -99,7 +100,7 @@ -- So far floating windows have been treated no differently than tiled windows -- even though their positions are independent of the stack. Often, yanking -- floating windows in and out of the workspace will obliterate the stack--- history - particularly frustrating with 'XMonad.Util.Scratchpad' since it is+-- history - particularly frustrating with "XMonad.Util.Scratchpad" since it is -- toggled so frequenty and always replaces the master window. That's why the -- swap functions accept a boolean argument; when @True@ non-focused floating -- windows will be ignored.@@ -240,8 +241,8 @@                 (r,s2) = stackSplit s1 fl' :: ([(Int,Window)],W.Stack Window)                 (b,s3) = swapFunction pm s2                 s4 = stackMerge s3 r-                mh = let w = head . W.integrate $ s3-                     in  const $ w : delete w ch+                mh = let w = NE.head . notEmpty . W.integrate $ s3+                     in const $ w : delete w ch             in (b,Just s4,mh)         (x,y,z) = maybe (False,Nothing,id) swapApply' st     -- Any floating master windows will be added to the history when 'windows'
XMonad/Actions/SwapWorkspaces.hs view
@@ -30,7 +30,7 @@   -- $usage--- Add this import to your @~\/.xmonad\/xmonad.hs@:+-- Add this import to your @xmonad.hs@: -- -- > import XMonad.Actions.SwapWorkspaces --@@ -44,7 +44,7 @@ -- will swap workspaces 1 and 5. -- -- For detailed instructions on editing your key bindings, see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  -- | Swaps the currently focused workspace with the given workspace tag, via --   @swapWorkspaces@.
XMonad/Actions/TagWindows.hs view
@@ -39,7 +39,7 @@  -- $usage ----- To use window tags, import this module into your @~\/.xmonad\/xmonad.hs@:+-- To use window tags, import this module into your @xmonad.hs@: -- -- > import XMonad.Actions.TagWindows -- > import XMonad.Prompt    -- to use tagPrompt@@ -64,7 +64,7 @@ --       the tags \"a\" and \"b\" but not \"a b\". -- -- For detailed instructions on editing your key bindings, see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  -- | set multiple tags for a window at once (overriding any previous tags) setTags :: [String] -> Window -> X ()@@ -133,11 +133,6 @@ focusTagged' :: (WindowSet -> [Window]) -> String -> X () focusTagged' wl t = gets windowset >>= findM (hasTag t) . wl >>=     maybe (return ()) (windows . focusWindow)--findM :: (Monad m) => (a -> m Bool) -> [a] -> m (Maybe a)-findM _ []      = return Nothing-findM p (x:xs)  = do b <- p x-                     if b then return (Just x) else findM p xs  -- | apply a pure function to windows with a tag withTaggedP, withTaggedGlobalP :: String -> (Window -> WindowSet -> WindowSet) -> X ()
XMonad/Actions/TiledWindowDragging.hs view
@@ -27,7 +27,7 @@ import           XMonad.Layout.DraggingVisualizer  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Actions.TiledWindowDragging -- > import XMonad.Layout.DraggingVisualizer
+ XMonad/Actions/ToggleFullFloat.hs view
@@ -0,0 +1,122 @@+-- |+-- Module      :  XMonad.Actions.ToggleFullFloat+-- Description :  Fullscreen (float) a window while remembering its original state.+-- Copyright   :  (c) 2022 Tomáš Janoušek <tomi@nomi.cz>+-- License     :  BSD3+-- Maintainer  :  Tomáš Janoušek <tomi@nomi.cz>+--+module XMonad.Actions.ToggleFullFloat (+    -- * Usage+    -- $usage+    toggleFullFloatEwmhFullscreen,+    toggleFullFloat,+    fullFloat,+    unFullFloat,+    gcToggleFullFloat,+    ) where++import qualified Data.Map.Strict as M++import XMonad+import XMonad.Prelude+import XMonad.Hooks.EwmhDesktops (setEwmhFullscreenHooks)+import XMonad.Hooks.ManageHelpers+import qualified XMonad.StackSet as W+import qualified XMonad.Util.ExtensibleState as XS++-- ---------------------------------------------------------------------+-- $usage+--+-- The main use-case is to make 'ewmhFullscreen' (re)store the size and+-- position of floating windows instead of just unconditionally sinking them+-- into the floating layer. To enable this, you'll need this in your+-- @xmonad.hs@:+--+-- > import XMonad+-- > import XMonad.Actions.ToggleFullFloat+-- > import XMonad.Hooks.EwmhDesktops+-- >+-- > main = xmonad $ … . toggleFullFloatEwmhFullscreen . ewmhFullscreen . ewmh . … $ def{…}+--+-- Additionally, this "smart" fullscreening can be bound to a key and invoked+-- manually whenever one needs a larger window temporarily:+--+-- >   , ((modMask .|. shiftMask, xK_t), withFocused toggleFullFloat)++newtype ToggleFullFloat = ToggleFullFloat{ fromToggleFullFloat :: M.Map Window (Maybe W.RationalRect) }+    deriving (Show, Read)++instance ExtensionClass ToggleFullFloat where+    extensionType = PersistentExtension+    initialValue = ToggleFullFloat mempty++-- | Full-float a window, remembering its state (tiled/floating and+-- position/size).+fullFloat :: Window -> X ()+fullFloat = windows . appEndo <=< runQuery doFullFloatSave++-- | Restore window to its remembered state.+unFullFloat :: Window -> X ()+unFullFloat = windows . appEndo <=< runQuery doFullFloatRestore++-- | Full-float a window, if it's not already full-floating. Otherwise,+-- restore its original state.+toggleFullFloat :: Window -> X ()+toggleFullFloat w = ifM (isFullFloat w) (unFullFloat w) (fullFloat w)++isFullFloat :: Window -> X Bool+isFullFloat w = gets $ (Just fullRect ==) . M.lookup w . W.floating . windowset+  where+    fullRect = W.RationalRect 0 0 1 1++doFullFloatSave :: ManageHook+doFullFloatSave = do+    w <- ask+    liftX $ do+        f <- gets $ M.lookup w . W.floating . windowset+        -- @M.insertWith const@ = don't overwrite stored original state+        XS.modify' $ ToggleFullFloat . M.insertWith const w f . fromToggleFullFloat+    doFullFloat++doFullFloatRestore :: ManageHook+doFullFloatRestore = do+    w <- ask+    mf <- liftX $ do+        mf <- XS.gets $ M.lookup w . fromToggleFullFloat+        XS.modify' $ ToggleFullFloat . M.delete w . fromToggleFullFloat+        pure mf+    doF $ case mf of+        Just (Just f) -> W.float w f  -- was floating before+        Just Nothing -> W.sink w      -- was tiled before+        Nothing -> W.sink w           -- fallback when not found in ToggleFullFloat++-- | Install ToggleFullFloat garbage collection hooks.+--+-- Note: This is included in 'toggleFullFloatEwmhFullscreen', only needed if+-- using the 'toggleFullFloat' separately from the EWMH hook.+gcToggleFullFloat :: XConfig a -> XConfig a+gcToggleFullFloat c = c { startupHook     = startupHook c <> gcToggleFullFloatStartupHook+                        , handleEventHook = handleEventHook c <> gcToggleFullFloatEventHook }++-- | ToggleFullFloat garbage collection: drop windows when they're destroyed.+gcToggleFullFloatEventHook :: Event -> X All+gcToggleFullFloatEventHook DestroyWindowEvent{ev_window = w} = do+    XS.modify' $ ToggleFullFloat . M.delete w . fromToggleFullFloat+    mempty+gcToggleFullFloatEventHook _ = mempty++-- | ToggleFullFloat garbage collection: restrict to existing windows at+-- startup.+gcToggleFullFloatStartupHook :: X ()+gcToggleFullFloatStartupHook = withWindowSet $ \ws ->+    XS.modify' $ ToggleFullFloat . M.filterWithKey (\w _ -> w `W.member` ws) . fromToggleFullFloat++-- | Hook this module into 'XMonad.Hooks.EwmhDesktops.ewmhFullscreen'. This+-- makes windows restore their original state (size and position if floating)+-- instead of unconditionally sinking into the tiling layer.+--+-- ('gcToggleFullFloat' is included here.)+toggleFullFloatEwmhFullscreen :: XConfig a -> XConfig a+toggleFullFloatEwmhFullscreen =+    setEwmhFullscreenHooks doFullFloatSave doFullFloatRestore .+    gcToggleFullFloat
XMonad/Actions/TopicSpace.hs view
@@ -103,9 +103,12 @@ -- display your topics in an historical way using a custom `pprWindowSet' -- function. You can also easily switch to recent topics using this history -- of last focused topics.+--+-- A blog post highlighting some features of this module can be found+-- <https://tony-zorman.com/posts/topic-space/2022-09-11-topic-spaces.html here>.  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import qualified Data.Map.Strict as M -- > import qualified XMonad.StackSet as W
XMonad/Actions/UpdateFocus.hs view
@@ -27,7 +27,7 @@  -- $usage -- To make the focus update on mouse movement within an unfocused window, add the--- following to your @~\/.xmonad\/xmonad.hs@:+-- following to your @xmonad.hs@: -- -- > import XMonad.Actions.UpdateFocus -- > xmonad $ def {
XMonad/Actions/UpdatePointer.hs view
@@ -31,7 +31,7 @@ import Control.Arrow ((&&&), (***))  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad -- > import XMonad.Actions.UpdatePointer
XMonad/Actions/Warp.hs view
@@ -28,7 +28,7 @@ import XMonad.StackSet as W  {- $usage-You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+You can use this module with the following in your @xmonad.hs@:  > import XMonad.Actions.Warp @@ -45,7 +45,7 @@ -}  -- For detailed instructions on editing your key bindings, see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.   data Corner = UpperLeft | UpperRight | LowerLeft | LowerRight
XMonad/Actions/WindowBringer.hs view
@@ -36,7 +36,7 @@  -- $usage ----- Import the module into your @~\/.xmonad\/xmonad.hs@:+-- Import the module into your @xmonad.hs@: -- -- > import XMonad.Actions.WindowBringer --@@ -46,7 +46,7 @@ -- > , ((modm .|. shiftMask, xK_b     ), bringMenu) -- -- For detailed instructions on editing your key bindings, see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  data WindowBringerConfig = WindowBringerConfig     { menuCommand :: String -- ^ The shell command that will handle window selection
XMonad/Actions/WindowGo.hs view
@@ -48,9 +48,11 @@ import XMonad.Prompt.Shell (getBrowser, getEditor) import qualified XMonad.StackSet as W (peek, swapMaster, focusWindow, workspaces, StackSet, Workspace, integrate', tag, stack) import XMonad.Util.Run (safeSpawnProg)+import qualified Data.List.NonEmpty as NE+ {- $usage -Import the module into your @~\/.xmonad\/xmonad.hs@:+Import the module into your @xmonad.hs@:  > import XMonad.Actions.WindowGo @@ -66,7 +68,8 @@ > (className =? "Firefox" <||> className =? "Firefox-bin")  For detailed instructions on editing your key bindings, see-"XMonad.Doc.Extending#Editing_key_bindings". -}+<https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.+-}  -- | Get the list of workspaces sorted by their tag workspacesSorted :: Ord i => W.StackSet i l a s sd -> [W.Workspace i l a]@@ -89,7 +92,10 @@ -- | The same as ifWindows, but applies a ManageHook to the first match -- instead and discards the other matches ifWindow :: Query Bool -> ManageHook -> X () -> X ()-ifWindow qry mh = ifWindows qry (windows . appEndo <=< runQuery mh . head)+ifWindow qry mh = ifWindows qry (windows . appEndo <=< runQuery mh . NE.head . notEmpty)+-- ifWindows guarantees that the list given to the function is+-- non-empty. This should really use Data.List.NonEmpty, but, alas,+-- that would be a breaking change.  {- | 'action' is an executable to be run via 'safeSpawnProg' (of "XMonad.Util.Run") if the Window cannot be found.    Presumably this executable is the same one that you were looking for.@@ -164,7 +170,8 @@         let (notEmpty -> _ :| (notEmpty -> y :| _)) = dropWhile (/=w) $ cycle ws             -- cannot fail to match         in windows $ focusFn y-    _ -> windows . focusFn . head $ ws+    _ -> windows . focusFn . NE.head . notEmpty $ ws+         -- ws is non-empty by ifWindows's definition.  -- | Given a function which gets us a String, we try to raise a window with that classname, --   or we then interpret that String as a executable name.
XMonad/Actions/WindowMenu.hs view
@@ -34,7 +34,7 @@  -- $usage ----- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- >    import XMonad.Actions.WindowMenu --
XMonad/Actions/WithAll.hs view
@@ -24,7 +24,7 @@  -- $usage ----- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Actions.WithAll --@@ -33,7 +33,7 @@ --     , ((modm .|. shiftMask, xK_t), sinkAll) -- -- For detailed instructions on editing your key bindings, see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  -- | Un-float all floating windows on the current workspace. sinkAll :: X ()
XMonad/Actions/Workscreen.hs view
@@ -43,7 +43,7 @@ import XMonad.Actions.OnScreen  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Actions.Workscreen -- > myWorkspaces = let myOldWorkspaces = ["adm","work","mail"]@@ -58,7 +58,7 @@ -- >      , (f, m) <- [(Workscreen.viewWorkscreen, 0), (Workscreen.shiftToWorkscreen, shiftMask)]] -- -- For detailed instructions on editing your key bindings, see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.   data Workscreen = Workscreen{workscreenId::Int,workspaces::[WorkspaceId]} deriving (Show)@@ -109,5 +109,6 @@ -- @WorkscreenId@. shiftToWorkscreen :: WorkscreenId -> X () shiftToWorkscreen wscrId = do (WorkscreenStorage _ a) <- XS.get-                              let ws = head . workspaces $ a !! wscrId-                              windows $ W.shift ws+                              case workspaces (a !! wscrId) of+                                []      -> pure ()+                                (w : _) -> windows $ W.shift w
XMonad/Actions/WorkspaceCursors.hs view
@@ -50,7 +50,7 @@ import XMonad(Message, WorkspaceId, X, XState(windowset),               fromMessage, sendMessage, windows, gets) import XMonad.Util.Stack (reverseS)-import XMonad.Prelude (find, fromJust, guard, liftA2, toList, when, (<=<))+import XMonad.Prelude  -- $usage --@@ -95,10 +95,10 @@  -- | makeCursors requires a nonempty string, and each sublist must be nonempty makeCursors ::  [[String]] -> Cursors String-makeCursors [] = error "Workspace Cursors cannot be empty"-makeCursors a = concat . reverse <$> foldl addDim x xs-    where x = end $ map return $ head a-          xs = map (map return) $ tail a+makeCursors []       = error "Workspace Cursors cannot be empty"+makeCursors (a : as) = concat . reverse <$> foldl addDim x xs+    where x = end $ map return a+          xs = map (map return) as           -- this could probably be simplified, but this true:           -- toList . makeCursors == map (concat . reverse) . sequence . reverse . map (map (:[]))           -- the strange order is used because it makes the regular M-1..9
XMonad/Actions/WorkspaceNames.hs view
@@ -51,14 +51,14 @@ import qualified XMonad.Actions.SwapWorkspaces as Swap import XMonad.Hooks.StatusBar.PP (PP(..)) import XMonad.Hooks.EwmhDesktops (addEwmhWorkspaceRename)-import XMonad.Prompt (mkXPrompt, XPConfig)+import XMonad.Prompt (mkXPrompt, XPConfig, historyCompletionP) import XMonad.Prompt.Workspace (Wor(Wor)) import XMonad.Util.WorkspaceCompare (getSortByIndex)  import qualified Data.Map as M  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@ file:+-- You can use this module with the following in your @xmonad.hs@ file: -- -- > import XMonad.Actions.WorkspaceNames --@@ -88,7 +88,7 @@ -- >     | (i, k) <- zip workspaces [xK_1 ..]] -- -- For detailed instructions on editing your key bindings, see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.   @@ -137,9 +137,11 @@  -- | Prompt for a new name for the current workspace and set it. renameWorkspace :: XPConfig -> X ()-renameWorkspace conf =-    mkXPrompt pr conf (const (return [])) setCurrentWorkspaceName-    where pr = Wor "Workspace name: "+renameWorkspace conf = do+    completion <- historyCompletionP (prompt ==)+    mkXPrompt (Wor prompt) conf completion setCurrentWorkspaceName+  where+    prompt = "Workspace name: "  -- | See 'XMonad.Actions.SwapWorkspaces.swapTo'. This is the same with names. swapTo :: Direction1D -> X ()
XMonad/Config/Arossato.hs view
@@ -47,7 +47,7 @@  -- $usage -- The simplest way to use this configuration module is to use an--- @~\/.xmonad\/xmonad.hs@ like this:+-- @xmonad.hs@ like this: -- -- > module Main (main) where -- >@@ -64,7 +64,7 @@ -- -- You can use this module also as a starting point for writing your -- own configuration module from scratch. Save it as your--- @~\/.xmonad\/xmonad.hs@ and:+-- @xmonad.hs@ and: -- -- 1. Change the module name from --
XMonad/Config/Azerty.hs view
@@ -27,7 +27,7 @@ import qualified Data.Map as M  -- $usage--- To use this module, start with the following @~\/.xmonad\/xmonad.hs@:+-- To use this module, start with the following @xmonad.hs@: -- -- > import XMonad -- > import XMonad.Config.Azerty
XMonad/Config/Bepo.hs view
@@ -26,7 +26,7 @@ import qualified Data.Map as M  -- $usage--- To use this module, start with the following @~\/.xmonad\/xmonad.hs@:+-- To use this module, start with the following @xmonad.hs@: -- -- > import XMonad -- > import XMonad.Config.Bepo
XMonad/Config/Bluetile.hs view
@@ -29,7 +29,7 @@ import XMonad  import XMonad.Layout.BorderResize-import XMonad.Layout.BoringWindows+import XMonad.Layout.BoringWindows hiding (Replace) import XMonad.Layout.ButtonDecoration import XMonad.Layout.Decoration import XMonad.Layout.DecorationAddons@@ -37,7 +37,7 @@ import XMonad.Layout.Maximize import XMonad.Layout.Minimize import XMonad.Layout.MouseResizableTile-import XMonad.Layout.Named+import XMonad.Layout.Renamed import XMonad.Layout.NoBorders import XMonad.Layout.PositionStoreFloat import XMonad.Layout.WindowSwitcherDecoration@@ -65,7 +65,7 @@ import XMonad.Prelude(when)  -- $usage--- To use this module, start with the following @~\/.xmonad\/xmonad.hs@:+-- To use this module, start with the following @xmonad.hs@: -- -- > import XMonad -- > import XMonad.Config.Bluetile@@ -183,10 +183,10 @@                 , isFullscreen --> doFullFloat]  bluetileLayoutHook = avoidStruts $ minimize $ boringWindows $-                        named "Floating" floating |||-                        named "Tiled1" tiled1 |||-                        named "Tiled2" tiled2 |||-                        named "Fullscreen" fullscreen+                        renamed [Replace "Floating"] floating |||+                        renamed [Replace "Tiled1"] tiled1 |||+                        renamed [Replace "Tiled2"] tiled2 |||+                        renamed [Replace "Fullscreen"] fullscreen         where             floating = floatingDeco $ maximize $ borderResize positionStoreFloat             tiled1 = tilingDeco $ maximize mouseResizableTileMirrored
XMonad/Config/Desktop.hs view
@@ -24,7 +24,7 @@     -- specification. Extra xmonad settings unique to specific DE's are     -- added by overriding or modifying @desktopConfig@ fields in the     -- same way that the default configuration is customized in-    -- @~\/.xmonad/xmonad.hs@.+    -- @xmonad.hs@.     --     -- For more information about EWMH see:     --@@ -72,7 +72,7 @@ -- <http://haskell.org/haskellwiki/Xmonad> -- -- To configure xmonad for use with a DE or with DE tools like panels--- and pagers, in place of @def@ in your @~\/.xmonad/xmonad.hs@,+-- and pagers, in place of @def@ in your @xmonad.hs@, -- use @desktopConfig@ or one of the other desktop configs from the -- @XMonad.Config@ namespace. The following setup and customization examples -- work the same way for the other desktop configs as for @desktopConfig@.@@ -91,7 +91,7 @@  -- $customizing -- To customize a desktop config, modify its fields as is illustrated with--- the default configuration @def@ in "XMonad.Doc.Extending#Extending xmonad".+-- the default configuration @def@ in <https://xmonad.org/TUTORIAL.html the tutorial>.  -- $layouts -- See also "XMonad.Util.EZConfig" for more options for modifying key bindings.
XMonad/Config/Dmwit.hs view
@@ -34,7 +34,7 @@ import XMonad.Layout.IndependentScreens hiding (withScreen) import XMonad.Layout.Magnifier import XMonad.Layout.NoBorders-import XMonad.Prelude+import XMonad.Prelude hiding (fromList) import XMonad.Util.Dzen hiding (x, y) import XMonad.Util.SpawnOnce -- }}}
XMonad/Config/Droundy.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE PatternGuards #-}+{-# LANGUAGE TupleSections #-} {-# OPTIONS_GHC -fno-warn-missing-signatures -fno-warn-orphans #-} ----------------------------------------------------------------------------- -- |@@ -20,7 +21,7 @@ import XMonad.Layout.Tabbed ( tabbed,                               shrinkText, Shrinker, shrinkIt, CustomShrink(CustomShrink) ) import XMonad.Layout.Combo ( combineTwo )-import XMonad.Layout.Named ( named )+import XMonad.Layout.Renamed ( Rename(Replace), renamed ) import XMonad.Layout.LayoutCombinators import XMonad.Layout.Square ( Square(Square) ) import XMonad.Layout.WindowNavigation ( Navigate(Move,Swap,Go), Direction2D(U,D,R,L),@@ -114,9 +115,9 @@     ]      ++-    zip (zip (repeat $ modMask x) [xK_F1..xK_F12]) (map (withNthWorkspace W.greedyView) [0..])+    zip (map (modMask x,) [xK_F1..xK_F12]) (map (withNthWorkspace W.greedyView) [0..])     ++-    zip (zip (repeat (modMask x .|. shiftMask)) [xK_F1..xK_F12]) (map (withNthWorkspace copy) [0..])+    zip (map (modMask x .|. shiftMask,) [xK_F1..xK_F12]) (map (withNthWorkspace copy) [0..])  config = docks $ ewmh def          { borderWidth = 1 -- Width of the window border in pixels.@@ -124,10 +125,10 @@          , layoutHook = showWName $ workspaceDir "~" $                         boringWindows $ smartBorders $ windowNavigation $                         maximizeVertical $ toggleLayouts Full $ avoidStruts $-                        named "tabbed" mytab |||-                        named "xclock" (mytab ****//* combineTwo Square mytab mytab) |||-                        named "three" (mytab **//* mytab *//* combineTwo Square mytab mytab) |||-                        named "widescreen" ((mytab *||* mytab)+                        renamed [Replace "tabbed"] mytab |||+                        renamed [Replace "xclock"] (mytab ****//* combineTwo Square mytab mytab) |||+                        renamed [Replace "three"] (mytab **//* mytab *//* combineTwo Square mytab mytab) |||+                        renamed [Replace "widescreen"] ((mytab *||* mytab)                                                 ****//* combineTwo Square mytab mytab) --   |||                         --mosaic 0.25 0.5          , terminal = "xterm" -- The preferred terminal program.
XMonad/Config/Gnome.hs view
@@ -32,7 +32,7 @@ import System.Environment (getEnvironment)  -- $usage--- To use this module, start with the following @~\/.xmonad\/xmonad.hs@:+-- To use this module, start with the following @xmonad.hs@: -- -- > import XMonad -- > import XMonad.Config.Gnome
XMonad/Config/Kde.hs view
@@ -28,7 +28,7 @@ import qualified Data.Map as M  -- $usage--- To use this module, start with the following @~\/.xmonad\/xmonad.hs@:+-- To use this module, start with the following @xmonad.hs@: -- -- > import XMonad -- > import XMonad.Config.Kde
XMonad/Config/Mate.hs view
@@ -1,5 +1,7 @@ {-# OPTIONS_GHC -fno-warn-missing-signatures #-}-+-- TODO: Remove when we depend on a version of xmonad that has unGrab.+{-# OPTIONS_GHC -Wno-deprecations  #-}+{-# OPTIONS_GHC -Wno-dodgy-imports #-} ----------------------------------------------------------------------------- -- | -- Module       : XMonad.Config.Mate@@ -28,18 +30,17 @@     desktopLayoutModifiers     ) where -import XMonad-import XMonad.Config.Desktop-import XMonad.Util.Run (safeSpawn)-import XMonad.Util.Ungrab-import XMonad.Prelude (toUpper)-+import System.Environment (getEnvironment) import qualified Data.Map as M -import System.Environment (getEnvironment)+import XMonad hiding (unGrab)+import XMonad.Config.Desktop+import XMonad.Prelude (toUpper)+import XMonad.Util.Run (safeSpawn)+import XMonad.Util.Ungrab (unGrab)  -- $usage--- To use this module, start with the following @~\/.xmonad\/xmonad.hs@:+-- To use this module, start with the following @xmonad.hs@: -- -- > import XMonad -- > import XMonad.Config.Mate
XMonad/Config/Prime.hs view
@@ -126,7 +126,7 @@ import XMonad.Util.EZConfig (additionalKeysP, additionalMouseBindings, checkKeymap, removeKeysP, removeMouseBindings)  -- $start_here--- To start with, create a @~\/.xmonad\/xmonad.hs@ that looks like this:+-- To start with, create a @xmonad.hs@ that looks like this: -- -- > {-# LANGUAGE RebindableSyntax #-} -- > import XMonad.Config.Prime@@ -388,7 +388,7 @@   MouseBindings { mRemove = r } =- sadBindings = return . r sadBindings  -- | Mouse button bindings to an 'X' actions on a window. Default: see @`man--- xmonad`@. To make mod-<scrollwheel> switch workspaces:+-- xmonad`@. To make @mod-\<scrollwheel\>@ switch workspaces: -- -- > import XMonad.Actions.CycleWS (nextWS, prevWS) -- > ...
XMonad/Config/Xfce.hs view
@@ -27,7 +27,7 @@ import qualified Data.Map as M  -- $usage--- To use this module, start with the following @~\/.xmonad\/xmonad.hs@:+-- To use this module, start with the following @xmonad.hs@: -- -- > import XMonad -- > import XMonad.Config.Xfce
XMonad/Doc/Configuring.hs view
@@ -14,7 +14,9 @@ -- <https://xmonad.org/TUTORIAL.html xmonad website>. -- -- For more detailed instructions on extending xmonad with the--- xmonad-contrib library, see "XMonad.Doc.Extending".+-- xmonad-contrib library, see+-- <https://xmonad.org/TUTORIAL.html the tutorial>+-- and "XMonad.Doc.Extending". -- ----------------------------------------------------------------------------- 
XMonad/Doc/Developing.hs view
@@ -86,7 +86,7 @@  Basically, xmonad and the xmonad-contrib libraries let users write their own window manager in just a few lines of code. While-@~\/.xmonad\/xmonad.hs@ at first seems to be simply a configuration+@xmonad.hs@ at first seems to be simply a configuration file, it is actually a complete Haskell program which uses the xmonad and xmonad-contrib libraries to create a custom window manager. @@ -106,13 +106,13 @@ xmonad installs a binary, @xmonad@, which must be executed by the Xsession starting script. This binary, whose code can be read in @Main.hs@ of the xmonad source tree, will use 'XMonad.Core.recompile'-to run @ghc@ in order to build a binary from @~\/.xmonad\/xmonad.hs@.+to run @ghc@ in order to build a binary from @xmonad.hs@. If this compilation process fails, for any reason, a default @main@ entry point will be used, which calls the 'XMonad.Main.xmonad' function with a default configuration.  Thus, the real @main@ entry point, the one that even the users' custom-window manager application in @~\/.xmonad\/xmonad.hs@ must call, is+window manager application in @xmonad.hs@ must call, is the 'XMonad.Main.xmonad' function. This function takes a configuration as its only argument, whose type ('XMonad.Core.XConfig') is defined in "XMonad.Core".
XMonad/Doc/Extending.hs view
@@ -71,20 +71,15 @@     -- *** Removing key bindings     -- $keyDel -    -- *** Adding and removing key bindings-    -- $keyAddDel-     -- ** Editing mouse bindings     -- $mouse -    -- ** Editing the layout hook+    -- ** Editing the layout hook #LayoutHook#     -- $layoutHook -    -- ** Editing the manage hook+    -- ** Editing the manage hook #ManageHook#     -- $manageHook -    -- ** The log hook and external status bars-    -- $logHook     ) where  --------------------------------------------------------------------------------@@ -108,8 +103,8 @@ the documentation and just click on its name to view its Haddock documentation; each module should come with extensive documentation. If you find a module that could be better documented, or has incorrect-documentation, please report it as a bug-(<https://github.com/xmonad/xmonad-contrib/issues>)!+documentation, please+<https://github.com/xmonad/xmonad-contrib/issues report it as a bug>!  First and foremost, xmonad defines its own prelude for commonly used functions, as well as re-exports from @base@.@@ -137,33 +132,31 @@ In the @XMonad.Actions@ namespace you can find modules exporting various functions that are usually intended to be bound to key combinations or mouse actions, in order to provide functionality-beyond the standard keybindings provided by xmonad.+beyond the standard keybindings offered by xmonad.  -}  {- $hooks  In the @XMonad.Hooks@ namespace you can find modules exporting-hooks. Hooks are actions that xmonad performs when certain events-occur. The three most important hooks are:+hooks—actions that xmonad performs when certain events occur.+The three most important hooks are:  * 'XMonad.Core.manageHook': this hook is called when a new window that   xmonad must take care of is created. This is a very powerful hook,   since it lets us examine the new window's properties and act   accordingly. For instance, we can configure xmonad to put windows   belonging to a given application in the float layer, not to manage-  dock applications, or open them in a given workspace. See-  "XMonad.Doc.Extending#Editing_the_manage_hook" for more information-  on customizing 'XMonad.Core.manageHook'.+  dock applications, or open them in a given workspace. See [Editing the+  manage hook](#g:Editing_the_manage_hook) for more information on+  customizing 'XMonad.Core.manageHook'.  * 'XMonad.Core.logHook': this hook is called when the stack of windows-  managed by xmonad has been changed; for example, this is invoked at-  the end of the 'XMonad.Operations.windows' function. For instance-  "XMonad.Hooks.DynamicLog" will produce a string (whose format can be-  configured) to be printed to the standard output. This can be used-  to display some information about the xmonad state in a status bar.-  See "XMonad.Doc.Extending#The_log_hook_and_external_status_bars" for-  more information.+  managed by xmonad changes; for example, this is invoked at the end of+  the 'XMonad.Operations.windows' function. A big application for this+  is to display some information about xmonad in a status bar. The aptly+  named "XMonad.Hooks.StatusBar" will produce a string (whose format can+  be configured) to be written, for example, to an X11 property.  * 'XMonad.Core.handleEventHook': this hook is called on all events handled   by xmonad, thus it is extremely powerful. See "Graphics.X11.Xlib.Extras"@@ -187,13 +180,13 @@ "XMonad.Layout.LayoutModifier".  For more information on using those modules for customizing your-'XMonad.Core.layoutHook' see "XMonad.Doc.Extending#Editing_the_layout_hook".+'XMonad.Core.layoutHook' see [Editing the layout hook](#g:LayoutHook).  -}  {- $prompts -In the @XMonad.Prompt@ name space you can find modules providing+In the @XMonad.Prompt@ namespace you can find modules providing graphical prompts for getting user input and using it to perform various actions. @@ -206,7 +199,7 @@  In the @XMonad.Util@ namespace you can find modules exporting various utility functions that are used by the other modules of the-xmonad-contrib library.+@xmonad-contrib@ library.  There are also utilities for helping in configuring xmonad or using external utilities.@@ -222,7 +215,7 @@ {- $extending #Extending_xmonad# -Since the @xmonad.hs@ file is just another Haskell module, you may+Since the @xmonad.hs@ file is just another Haskell program, you may import and use any Haskell code or libraries you wish, such as extensions from the xmonad-contrib library, or other code you write yourself.@@ -388,83 +381,74 @@ {- $keyDel #Removing_key_bindings# -Removing key bindings requires modifying the 'Data.Map.Strict.Map' which-stores the key bindings.  This can be done with 'Data.Map.difference' or-with 'Data.Map.Strict.delete'.+As we've learned, XMonad stores keybindings inside of a+'Data.Map.Strict.Map', which means that removing keybindings requires+modifying it.  This can be done with 'Data.Map.difference' or with+'Data.Map.Strict.delete'. -For example, suppose you want to get rid of @mod-q@ and @mod-shift-q@-(you just want to leave xmonad running forever). To do this you need to-define @newKeys@ as a 'Data.Map.Strict.difference' between the default-map and the map of the key bindings you want to remove.  Like so:+For example, suppose you want to entirely rid yourself of @"M-q"@ and+@"M-s-q"@ (you just want to leave xmonad running forever).  To do this+with bare @xmonad@, you need to define @newKeys@ as a+'Data.Map.Strict.difference' between the default map and the map of the+key bindings you want to remove.  Like so: ->    newKeys x = keys def x `M.difference` keysToRemove x+> newKeys :: XConfig l -> Map (KeyMask, KeySym) (X ())+> newKeys x = keys def x `M.difference` keysToRemove x >->    keysToRemove :: XConfig Layout ->    M.Map (KeyMask, KeySym) (X ())->    keysToRemove x = M.fromList->             [ ((modm              , xK_q ), return ())->             , ((modm .|. shiftMask, xK_q ), return ())->             ]+> keysToRemove :: XConfig l -> Map (KeyMask, KeySym) (X ())+> keysToRemove x = M.fromList+>          [ ((modm              , xK_q ), return ())+>          , ((modm .|. shiftMask, xK_q ), return ())+>          ]  As you can see, it doesn't matter what actions we associate with the-keys listed in @keysToRemove@, so we just use @return ()@ (the-\"null\" action).+keys listed in @keysToRemove@, so we just use @return ()@ (the \"null\"+action).  Since @newKeys@ contains all of the default keys, you can+simply pass it to 'XMonad.Core.XConfig' as your map of keybindings: -It is also possible to simply define a list of keys we want to unbind-and then use 'Data.Map.Strict.delete' to remove them. In that case we-would write something like:+> main :: IO ()+> main = xmonad $ def { keys = newKeys } ->    newKeys x = foldr M.delete (keys def x) (keysToRemove x)->->    keysToRemove :: XConfig Layout -> [(KeyMask, KeySym)]->    keysToRemove x =->             [ (modm              , xK_q )->             , (modm .|. shiftMask, xK_q )->             ]+However, having to manually type @return ()@ every time seems like a+drag, doesn't it?  And this approach isn't at all compatible with adding+custom keybindings via 'XMonad.Util.EZConfig.additionalKeysP'!  Well,+good thing "XMonad.Util.EZConfig" also sports+'XMonad.Util.EZConfig.removeKeysP'.  You can use it as you would expect. -Another even simpler possibility is the use of some of the utilities-provided by the xmonad-contrib library. Look, for instance, at-'XMonad.Util.EZConfig.removeKeys'.+> main :: IO ()+> main = xmonad $ def+>   { … }+>  `removeKeysP` ["M-q", "M-S-q"] --}+Can you guess how 'XMonad.Util.EZConfig.removeKeysP' works?  It's almost+the same code we wrote above, just accepting a list of keybindings.  Try+to see if you can come up with an implementation of -{- $keyAddDel-#Adding_and_removing_key_bindings#+> removeKeysP :: XConfig l -> [String] -> XConfig l -Adding and removing key bindings requires simply combining the steps-for removing and adding.  Here is an example from-"XMonad.Config.Arossato":+If you're done, just click on @# Source@ when viewing the+'XMonad.Util.EZConfig.removeKeysP' documentation (did you know that+Haddock lets you do that for every function?) and compare. ->    defKeys    = keys def->    delKeys x  = foldr M.delete           (defKeys x) (toRemove x)->    newKeys x  = foldr (uncurry M.insert) (delKeys x) (toAdd    x)->    -- remove some of the default key bindings->    toRemove XConfig{modMask = modm} =->        [ (modm              , xK_j     )->        , (modm              , xK_k     )->        , (modm              , xK_p     )->        , (modm .|. shiftMask, xK_p     )->        , (modm .|. shiftMask, xK_q     )->        , (modm              , xK_q     )->        ] ++->        -- I want modm .|. shiftMask 1-9 to be free!->        [(shiftMask .|. modm, k) | k <- [xK_1 .. xK_9]]->    -- These are my personal key bindings->    toAdd XConfig{modMask = modm} =->        [ ((modm              , xK_F12   ), xmonadPrompt def )->        , ((modm              , xK_F3    ), shellPrompt  def )->        ] ++->        -- Use modm .|. shiftMask .|. controlMask 1-9 instead->        [( (m .|. modm, k), windows $ f i)->         | (i, k) <- zip (workspaces x) [xK_1 .. xK_9]->        ,  (f, m) <- [(W.greedyView, 0), (W.shift, shiftMask .|. controlMask)]->        ]+By the way, one can conveniently combine+'XMonad.Util.EZConfig.additionalKeysP' and+'XMonad.Util.EZConfig.removeKeysP' by just intuitively chaining them: -You can achieve the same result using the "XMonad.Util.CustomKeys"-module; take a look at the 'XMonad.Util.CustomKeys.customKeys'-function in particular.+> main :: IO ()+> main = xmonad $ def+>   { … }+>  `additionalKeysP myKeys+>  `removeKeysP`    ["M-q", "M-S-q"] -NOTE: modm is defined as the modMask you defined (or left as the default) in-your config.+If you don't use the @P@ alternatives of EZConfig, there is also an+aptly named 'XMonad.Util.EZConfig.removeKeys'.  Again, can you try to+come up with an implementation yourself that has the correct signature?++> removeKeys :: XConfig a -> [(KeyMask, KeySym)] -> XConfig a++In addition to 'Data.Map.Strict.delete', you will probably need to use+'foldr'.+ -}  {- $mouse@@ -506,8 +490,7 @@ The problem is that the layout subsystem is implemented with an advanced feature of the Haskell programming language: type classes. This allows us to very easily write new layouts, combine or modify-existing layouts, create layouts with internal state, etc. See-"XMonad.Doc.Extending#The_LayoutClass" for more information. This+existing layouts, create layouts with internal state, etc. This means that we cannot simply have a list of layouts: a list requires every member to belong to the same type! @@ -517,7 +500,7 @@ Suppose we want a list with the 'XMonad.Layout.Full', 'XMonad.Layout.Tabbed.tabbed' and 'XMonad.Layout.Accordion.Accordion' layouts. First we import, in our-@~\/.xmonad\/xmonad.hs@, all the needed modules:+@xmonad.hs@, all the needed modules:  >    import XMonad >@@ -546,7 +529,7 @@  >    mylayoutHook = Full ||| noBorders (tabbed shrinkText def) ||| Accordion -Our @~\/.xmonad\/xmonad.hs@ will now look like this:+Our @xmonad.hs@ will now look like this:  >    import XMonad >@@ -709,44 +692,5 @@  For additional rules and actions you can use in your manageHook, check out the contrib module "XMonad.Hooks.ManageHelpers".---}--{- $logHook-#The_log_hook_and_external_status_bars#--When the stack of the windows managed by xmonad changes for any-reason, xmonad will call 'XMonad.Core.logHook', which can be used to-output some information about the internal state of xmonad, such as the-layout that is presently in use, the workspace we are in, the focused-window's title, and so on.--Extracting information about the internal xmonad state can be somewhat-difficult if you are not familiar with the source code. Therefore,-it's usually easiest to use a module that has been designed-specifically for logging some of the most interesting information-about the internal state of xmonad: "XMonad.Hooks.DynamicLog".  This-module can be used with an external status bar to print the produced-logs in a convenient way; the most commonly used status bars are dzen-and xmobar. The module "XMonad.Hooks.StatusBar" offers another interface-to interact with status bars, that might be more convenient to use.--By default the 'XMonad.Core.logHook' doesn't produce anything. To-enable it you need first to import "XMonad.Hooks.DynamicLog":-->    import XMonad.Hooks.DynamicLog--Then you just need to update the 'XMonad.Core.logHook' field of the-'XMonad.Core.XConfig' record with one of the provided functions. For-example:-->    main = xmonad def { logHook = dynamicLog }--More interesting configurations are also possible; see the-"XMonad.Hooks.DynamicLog" module for more possibilities.--You may now enjoy your extended xmonad experience.--Have fun!  -}
XMonad/Hooks/CurrentWorkspaceOnTop.hs view
@@ -22,14 +22,15 @@     currentWorkspaceOnTop     ) where +import qualified Data.List.NonEmpty as NE (nonEmpty)+import qualified Data.Map as M import XMonad+import XMonad.Prelude (NonEmpty ((:|)), when) import qualified XMonad.StackSet as S import qualified XMonad.Util.ExtensibleState as XS-import XMonad.Prelude (unless, when)-import qualified Data.Map as M  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Hooks.CurrentWorkspaceOnTop -- >@@ -63,7 +64,9 @@             wins = fltWins ++ map fst rs  -- order: first all floating windows, then the order the layout returned         -- end of reimplementation -        unless (null wins) $ do-            io $ raiseWindow d (head wins)  -- raise first window of current workspace to the very top,-            io $ restackWindows d wins      -- then use restackWindows to let all other windows from the workspace follow+        case NE.nonEmpty wins of+            Nothing         -> pure ()+            Just (w :| ws') -> do+                io $ raiseWindow d w            -- raise first window of current workspace to the very top,+                io $ restackWindows d (w : ws') -- then use restackWindows to let all other windows from the workspace follow         XS.put(CWOTS curTag)
XMonad/Hooks/DebugEvents.hs view
@@ -37,12 +37,13 @@ import           Control.Monad.State import           Control.Monad.Reader import           Codec.Binary.UTF8.String-import           Foreign+import           Foreign                                     hiding (void) import           Foreign.C.Types import           Numeric                                     (showHex) import           System.Exit import           System.IO import           System.Process+import           GHC.Stack                                   (HasCallStack, prettyCallStack, callStack)  -- | Event hook to dump all received events.  You should probably not use this --   unconditionally; it will produce massive amounts of output.@@ -203,7 +204,7 @@  -- | Helper to emit tagged event information. say     :: String -> String -> X ()-say l s =  trace $ l ++ ' ':s+say l s =  XMonad.trace $ l ++ ' ':s  -- | Deconstuct a list of 'CInt's into raw bytes splitCInt    :: [CInt] -> IO Raw@@ -240,7 +241,7 @@                         }  newtype Decoder a = Decoder (ReaderT Decode (StateT DecodeState X) a)-#ifndef __HADDOCK__+     deriving (Functor              ,Applicative              ,Monad@@ -249,12 +250,12 @@              ,MonadState  DecodeState              ,MonadReader Decode              )-#endif + -- | Retrive, parse, and dump a window property.  As all the high-level property --   interfaces lose information necessary to decode properties correctly, we --   work at the lowest level available.-dumpProperty          :: Atom -> String -> Window -> Int -> X String+dumpProperty          :: HasCallStack => Atom -> String -> Window -> Int -> X String dumpProperty a n w i  =  do   prop <- withDisplay $ \d ->     io     $@@ -279,7 +280,7 @@     case rc of       0 -> do         fmt <- fromIntegral <$> peek fmtp-        vs' <-                     peek vsp+        vs' <-                  peek vsp         sz  <- fromIntegral <$> peek szp         case () of           () | fmt == none     -> xFree vs' >> return (Left   "(property deleted)"   )@@ -303,7 +304,8 @@  -- @@@ am I better off passing in the Decode and DecodeState? -- | Parse and dump a property (or a 'ClientMessage').-dumpProperty'                             :: Window -- source window+dumpProperty'                             :: HasCallStack+                                          => Window -- source window                                           -> Atom   -- property id                                           -> String -- property name                                           -> Atom   -- property type@@ -334,11 +336,11 @@   (_,ds') <- runDecode dec ds $ dumpProp a n   let fin = length (value ds')       len = length vs-      lost = if ack == 0 then "" else "and " ++ show ack ++ " lost bytes"+      lost = if ack == 0 then "" else " and " ++ show ack ++ " lost bytes"       unk = case () of               () | fin == len -> "undecodeable "                  | fin == 0   -> "."-                 | otherwise  -> "and remainder (" ++ show (len - fin) ++ '/':show len ++ ")"+                 | otherwise  -> " and remainder (" ++ show (len - fin) ++ '/':show len ++ ")"   (_,ds'') <- if fin == 0               then return (True,ds')               else runDecode dec' (withJoint' unk ds' ) $ dumpArray dump8@@ -349,7 +351,7 @@  -- | A simplified version of 'dumpProperty\'', to format random values from --   events.-quickFormat     :: (Storable i, Integral i) => [i] -> Decoder Bool -> X String+quickFormat     :: (HasCallStack, Storable i, Integral i) => [i] -> Decoder Bool -> X String quickFormat v f =  do   let vl = length v   vs <- io $@@ -382,7 +384,7 @@ -- | The top level property decoder, for a wide variety of standard ICCCM and --   EWMH window properties.  We pass part of the 'ReaderT' as arguments for --   pattern matching.-dumpProp                                              :: Atom -> String -> Decoder Bool+dumpProp                                              :: HasCallStack => Atom -> String -> Decoder Bool  dumpProp _ "CLIPBOARD"                                =  dumpSelection dumpProp _ "_NET_SUPPORTED"                           =  dumpArray dumpAtom@@ -426,10 +428,13 @@ dumpProp _ "_NET_WM_VISIBLE_NAME"                     =  dumpUTF dumpProp _ "_NET_WM_ICON_NAME"                        =  dumpUTF dumpProp _ "_NET_WM_VISIBLE_ICON_NAME"                =  dumpUTF-dumpProp _ "_NET_WM_DESKTOP"                          =  dumpExcept [(0xFFFFFFFF,"all")]-                                                                    dump32+-- @@@ the property is CARDINAL; the message is _NET_WM_DESKTOP of 5 dump32s+--     [desktop/all, source indication, 3 zeroes]+-- dumpProp _ "_NET_WM_DESKTOP"                          =  dumpExcept [(0xFFFFFFFF,"all")]+--                                                                     dump32+dumpProp _ "_NET_WM_DESKTOP"                          =  dumpSetDesktop dumpProp _ "_NET_WM_WINDOW_TYPE"                      =  dumpArray dumpAtom-dumpProp _ "_NET_WM_STATE"                            =  dumpArray dumpAtom+dumpProp _ "_NET_WM_STATE"                            =  dumpNWState dumpProp _ "_NET_WM_ALLOWED_ACTIONS"                  =  dumpArray dumpAtom dumpProp _ "_NET_WM_STRUT"                            =  dumpList [("left gap"  ,dump32)                                                                   ,("right gap" ,dump32)@@ -467,6 +472,12 @@                                                                   ] dumpProp _ "_NET_WM_SYNC_REQUEST_COUNTER"             =  dumpExcept [(0,"illegal value 0")]                                                                     dump64+dumpProp _ "_NET_WM_OPAQUE_REGION"                    =  dumpArray $ dumpList [("x",dump32)+                                                                              ,("y",dump32)+                                                                              ,("w",dump32)+                                                                              ,("h",dump32)+                                                                              ]+dumpProp _ "_NET_WM_BYPASS_COMPOSITOR"                =  dumpEnum cpState dumpProp _ "_NET_STARTUP_ID"                          =  dumpUTF dumpProp _ "WM_PROTOCOLS"                             =  dumpArray dumpAtom dumpProp _ "WM_COLORMAP_WINDOWS"                      =  dumpArray dumpWindow@@ -521,8 +532,8 @@                                                                              ]                                                                    )                                                                   ]-             | a == wM_NORMAL_HINTS                   =  (...)-             | a == wM_ZOOM_HINTS                     =  (...) -- same as previous+             | a == wM_NORMAL_HINTS                   =  dumpSizeHints+             | a == wM_ZOOM_HINTS                     =  dumpSizeHints              | a == rGB_DEFAULT_MAP                   =  (...) -- XStandardColormap              | a == rGB_BEST_MAP                      =  (...) -- "              | a == rGB_RED_MAP                       =  (...) -- "@@ -567,12 +578,12 @@ withIndent w =  local (\r -> r {indent = indent r + w})  -- dump an array of items.  this dumps the entire property-dumpArray      :: Decoder Bool -> Decoder Bool+dumpArray      :: HasCallStack => Decoder Bool -> Decoder Bool dumpArray item =  do   withIndent 1 $ append "[" >> withJoint "" (dumpArray' item "")  -- step through values as an array, ending on parse error or end of list-dumpArray'          :: Decoder Bool -> String -> Decoder Bool+dumpArray'          :: HasCallStack => Decoder Bool -> String -> Decoder Bool dumpArray' item pfx =  do   vs <- gets value   if null vs@@ -582,12 +593,12 @@ -- keep parsing until a parse step fails -- @@@ which points out that all my uses of @whenX (return ...)@ are actually 'when', --     which suggests that 'whenX' is *also* the same function... yep.  ISAGN-whenD     :: Monad m => m Bool -> m Bool -> m Bool+whenD     :: (HasCallStack, Monad m) => m Bool -> m Bool -> m Bool whenD p f =  p >>= \b -> if b then f else return False  -- verify a decoder parameter, else call error reporter -- once again, it's more general than I originally wrote-guardR                  :: (MonadReader r m, Eq v)+guardR                  :: (HasCallStack, MonadReader r m, Eq v)                         => (r -> v)                -- value selector                         -> v                       -- expected value                         -> (v -> v -> m a)         -- error reporter@@ -598,43 +609,47 @@   if v == val then good else err v val  -- this is kinda dumb-fi       :: Bool -> a -> a -> a+fi       :: HasCallStack => Bool -> a -> a -> a fi p n y =  if p then y else n -- flip (if' p), if that existed  -- verify we have the expected word size-guardSize      :: Int -> Decoder Bool -> Decoder Bool+guardSize      :: HasCallStack => Int -> Decoder Bool -> Decoder Bool -- see XSync documentation for this insanity-guardSize 64 =  guardR width 32 propSizeErr . guardSize' 8         propShortErr-guardSize  w =  guardR width  w propSizeErr . guardSize' (bytes w) propShortErr+guardSize 64 =  guardR width 32 propSizeErr . guardSize' 8         (propShortErr' 1)+guardSize  w =  guardR width  w propSizeErr . guardSize' (bytes w) (propShortErr' 2) -guardSize'       :: Int -> Decoder a -> Decoder a -> Decoder a-guardSize' l n y =  gets value >>= \vs -> fi (length vs >= l) n y+guardSize'       :: HasCallStack => Int -> Decoder a -> Decoder a -> Decoder a+guardSize' l n y =  gets value >>= \vs -> fi (length vs >= bytes l) n y +-- @guardSize@ doesn't work with empty arrays+guardSize''       :: HasCallStack => Int -> Decoder a -> Decoder a -> Decoder a+guardSize'' l n y =  gets value >>= \vs -> fi (null vs || length vs >= bytes l) n y+ -- verify we have the expected property type-guardType    :: Atom -> Decoder Bool -> Decoder Bool+guardType    :: HasCallStack => Atom -> Decoder Bool -> Decoder Bool guardType  t =  guardR pType t propTypeErr  -- dump a structure as a named tuple-dumpList       :: [(String,Decoder Bool)] -> Decoder Bool+dumpList       :: HasCallStack => [(String,Decoder Bool)] -> Decoder Bool dumpList proto =  do   a <- asks pType   dumpList'' (maxBound :: CULong) (map (\(s,d) -> (s,d,a)) proto) "("  -- same but elements have their own distinct types-dumpList'       :: [(String,Decoder Bool,Atom)] -> Decoder Bool+dumpList'       :: HasCallStack => [(String,Decoder Bool,Atom)] -> Decoder Bool dumpList' proto =  dumpList'' (maxBound :: CULong) proto "("  -- same but only dump elements identified by provided mask-dumpListByMask     :: CULong -> [(String,Decoder Bool)] -> Decoder Bool+dumpListByMask     :: HasCallStack => CULong -> [(String,Decoder Bool)] -> Decoder Bool dumpListByMask m p =  do   a <- asks pType   dumpList'' m (map (\(s,d) -> (s,d,a)) p) "("  -- and the previous two combined-dumpListByMask'     :: CULong -> [(String,Decoder Bool,Atom)] -> Decoder Bool+dumpListByMask'     :: HasCallStack => CULong -> [(String,Decoder Bool,Atom)] -> Decoder Bool dumpListByMask' m p =  dumpList'' m p "(" -dumpList''                    :: CULong -> [(String,Decoder Bool,Atom)] -> String -> Decoder Bool+dumpList''                    :: HasCallStack => CULong -> [(String,Decoder Bool,Atom)] -> String -> Decoder Bool dumpList'' _ []           _   =  append ")" >> return True dumpList'' 0 _            _   =  append ")" >> return True dumpList'' m ((l,p,t):ps) sep = do@@ -659,22 +674,20 @@  -- do the getTextProperty dance, the hard way. -- @@@ @COMPOUND_TEXT@ not supported yet.-dumpString :: Decoder Bool+dumpString :: HasCallStack => Decoder Bool dumpString =  do   fmt <- asks pType   [cOMPOUND_TEXT,uTF8_STRING] <- inX $ mapM getAtom ["COMPOUND_TEXT","UTF8_STRING"]   case () of-    () | fmt == cOMPOUND_TEXT -> guardSize 16 (...)-       | fmt == sTRING        -> guardSize  8 $ do+    () | fmt == cOMPOUND_TEXT -> guardSize'' 16 (propShortErr' 3) ( ... )+       | fmt == sTRING        -> guardSize''  8 (propShortErr' 4) $ do                                    vs <- gets value                                    modify (\r -> r {value = []})                                    let ss = flip unfoldr (map twiddle vs) $                                             \s -> if null s                                                   then Nothing                                                   else let (w,s'') = break (== '\NUL') s-                                                           s'      = if null s''-                                                                     then s''-                                                                     else tail s''+                                                           s'      = drop 1 s''                                                         in Just (w,s')                                    case ss of                                      [s] -> append $ show s@@ -688,7 +701,7 @@                                  failure . ("unrecognized string type " ++)  -- show who owns a selection-dumpSelection :: Decoder Bool+dumpSelection :: HasCallStack => Decoder Bool dumpSelection =  do   -- system selections contain a window ID; others are random   -- note that the window ID will be the same as the owner, so@@ -702,14 +715,14 @@       append $ "owned by " ++ w  -- for now, not querying Xkb-dumpXKlInds :: Decoder Bool+dumpXKlInds :: HasCallStack => Decoder Bool dumpXKlInds =  guardType iNTEGER $ do                  n <- fmap fromIntegral <$> getInt' 32                  case n of-                   Nothing -> propShortErr+                   Nothing -> propShortErr' 5                    Just is -> append $ "indicators " ++ unwords (dumpInds is 1 1 [])   where-    dumpInds                               :: Word32 -> Word32 -> Int -> [String] -> [String]+    dumpInds                               :: HasCallStack => Word32 -> Word32 -> Int -> [String] -> [String]     dumpInds n bt c bs | n == 0 && c == 1 =  ["none"]                        | n == 0           =  bs                        | n .&. bt /= 0    =  dumpInds (n .&. complement bt)@@ -722,9 +735,20 @@                                                       bs  -- decode an Atom-dumpAtom :: Decoder Bool-dumpAtom =-  guardType aTOM $ do++dumpAtom :: HasCallStack => Decoder Bool+dumpAtom = dumpAtom'' aTOM++{-+dumpAtom' :: HasCallStack => String -> Decoder Bool+dumpAtom' t' = do+  t <- inX $ getAtom t'+  dumpAtom'' t+-}++dumpAtom'' :: HasCallStack => Atom -> Decoder Bool+dumpAtom'' t =+  guardType t $ do   a <- getInt' 32   case a of     Nothing -> return False@@ -732,15 +756,16 @@            an <- inX $ atomName $ fromIntegral a'            append an -dumpWindow :: Decoder Bool+dumpWindow :: HasCallStack => Decoder Bool dumpWindow =  guardSize 32 $ guardType wINDOW $ do                 w <- getInt' 32                 case w of                   Nothing -> return False+                  Just 0  -> append "none"                   Just w' -> inX (debugWindow (fromIntegral w')) >>= append  -- a bit of a hack; as a Property it's a wINDOW, as a ClientMessage it's a list-dumpActiveWindow :: Decoder Bool+dumpActiveWindow :: HasCallStack => Decoder Bool dumpActiveWindow =  guardSize 32 $ do                       t <- asks pType                       nAW <- inX $ getAtom "_NET_ACTIVE_WINDOW"@@ -754,49 +779,87 @@                                      t' <- inX $ atomName t                                      failure $ concat ["(bad type "                                                       ,t'-                                                      ,"; expected WINDOW or _NET_ACTIVE_WINDOW"+                                                      ,"; expected WINDOW or _NET_ACTIVE_WINDOW)"                                                       ]++-- likewise but for _NET_WM_DESKTOP+dumpSetDesktop :: HasCallStack => Decoder Bool+dumpSetDesktop =  guardSize 32 $ do+                    t <- asks pType+                    nWD <- inX $ getAtom "_NET_WM_DESKTOP"+                    case () of+                      () | t == cARDINAL -> dumpExcept [(0xFFFFFFFF,"all")]+                                                       dump32+                         | t == nWD      -> dumpList' [("desktop",dumpExcept [(0xFFFFFFFF,"all")]+                                                                             dump32              ,cARDINAL)+                                                      ,("source" ,dumpEnum awSource              ,cARDINAL)+                                                      ]+                      _                -> do+                                     t' <- inX $ atomName t+                                     failure $ concat ["(bad type "+                                                      ,t'+                                                      ,"; expected CARDINAL or _NET_WM_DESKTOP)"+                                                      ]++-- and again for _NET_WM_STATE+dumpNWState :: HasCallStack => Decoder Bool+dumpNWState =  guardSize'' 32 propShortErr $ do+                    t <- asks pType+                    nWS <- inX $ getAtom "_NET_WM_STATE"+                    case () of+                      () | t == aTOM -> dumpArray dumpAtom+                         | t == nWS  -> dumpList' [("action",dumpEnum nwAction,cARDINAL)+                                                  ,("atom1" ,dumpAtom         ,aTOM)+                                                  ,("atom2" ,dumpAtom         ,aTOM)+                                                  ]+                      _                -> do+                                     t' <- inX $ atomName t+                                     failure $ concat ["(bad type "+                                                      ,t'+                                                      ,"; expected ATOM or _NET_WM_STATE)"+                                                      ]+ -- dump a generic CARDINAL value-dumpInt   :: Int -> Decoder Bool+dumpInt   :: HasCallStack => Int -> Decoder Bool dumpInt w =  guardSize w $ guardType cARDINAL $ getInt w show  -- INTEGER is the signed version of CARDINAL-dumpInteger   :: Int -> Decoder Bool+dumpInteger   :: HasCallStack => Int -> Decoder Bool dumpInteger w =  guardSize w $ guardType iNTEGER $ getInt w (show . signed w)  -- reinterpret an unsigned as a signed-signed     :: Int -> Integer -> Integer+signed     :: HasCallStack => Int -> Integer -> Integer signed w i =  bit (w + 1) - i  -- and wrappers to keep the parse list in bounds-dump64 :: Decoder Bool+dump64 :: HasCallStack => Decoder Bool dump64 =  dumpInt 64 -dump32 :: Decoder Bool+dump32 :: HasCallStack => Decoder Bool dump32 =  dumpInt 32  {- not used in standard properties-dump16 :: Decoder Bool+dump16 :: HasCallStack => Decoder Bool dump16 =  dumpInt 16 -} -dump8 :: Decoder Bool+dump8 :: HasCallStack => Decoder Bool dump8 =  dumpInt 8  -- I am assuming for the moment that this is a single string. -- This might be false; consider the way the STRING properties -- handle lists.-dumpUTF :: Decoder Bool+dumpUTF :: HasCallStack => Decoder Bool dumpUTF =  do   uTF8_STRING <- inX $ getAtom "UTF8_STRING"-  guardType uTF8_STRING $ guardSize 8 $ do+  guardType uTF8_STRING $ guardSize'' 8 propShortErr $ do     s <- gets value     modify (\r -> r {value = []})     append . show . decode . map fromIntegral $ s     return True  -- dump an enumerated value using a translation table-dumpEnum'        :: [String] -> Atom -> Decoder Bool+dumpEnum'        :: HasCallStack => [String] -> Atom -> Decoder Bool dumpEnum' ss fmt =  guardType fmt $                     getInt 32     $                     \r -> case () of@@ -805,11 +868,12 @@                                | otherwise             -> genericIndex ss r  -- we do not, unlike @xev@, try to ascii-art pixmaps.-dumpPixmap :: Decoder Bool+dumpPixmap :: HasCallStack => Decoder Bool dumpPixmap =  guardType pIXMAP $ do                 p' <- getInt' 32                 case p' of                   Nothing -> return False+                  Just 0  -> append "none"                   Just p  -> do                     append $ "pixmap " ++ showHex p ""                     g' <- inX $ withDisplay $ \d -> io $@@ -833,46 +897,80 @@                                      ,")"                                      ] -dumpOLAttrs :: Decoder Bool+dumpOLAttrs :: HasCallStack => Decoder Bool dumpOLAttrs = do   pt <- inX $ getAtom "_OL_WIN_ATTR"   guardType pt $ do     msk <- getInt' 32     case msk of-      Nothing   -> propShortErr+      Nothing   -> propShortErr' 7       Just msk' -> dumpListByMask (fromIntegral msk') [("window type" ,dumpAtom     )                                                       ,("menu"        ,dump32       ) -- @@@ unk                                                       ,("pushpin"     ,dumpEnum bool)                                                       ,("limited menu",dump32       ) -- @@@ unk                                                       ] -dumpMwmHints :: Decoder Bool+dumpMwmHints :: HasCallStack => Decoder Bool dumpMwmHints =  do   ta <- asks property   guardType ta $ do     msk <- getInt' 32     case msk of-      Nothing   -> propShortErr-      Just msk' -> dumpListByMask (fromIntegral msk') [("functions"  ,dumpBits mwmFuncs    )-                                                      ,("decorations",dumpBits mwmDecos    )-                                                      ,("input mode" ,dumpEnum mwmInputMode)-                                                      ,("status"     ,dumpBits mwmState    )-                                                      ]+      Nothing   -> propShortErr' 8+      Just msk' -> dumpListByMask' (fromIntegral msk') [("functions"  ,dumpBits mwmFuncs    ,cARDINAL)+                                                       ,("decorations",dumpBits mwmDecos    ,cARDINAL)+                                                       ,("input mode" ,dumpEnum mwmInputMode,cARDINAL) -- @@@ s/b iNTEGER?+                                                       ,("status"     ,dumpBits mwmState    ,cARDINAL)+                                                       ] -dumpMwmInfo :: Decoder Bool+dumpMwmInfo :: HasCallStack => Decoder Bool dumpMwmInfo =  do   ta <- asks property   guardType ta $ dumpList' [("flags" ,dumpBits mwmHints,cARDINAL)                            ,("window",dumpWindow       ,wINDOW  )                            ] +dumpSizeHints :: HasCallStack => Decoder Bool+dumpSizeHints =  do+  guardType wM_SIZE_HINTS $ do+    -- flags, 4 unused CARD32s, fields as specified by flags+    msk <- fmap fromIntegral <$> getInt' 32+    eat (4 * 4) >> pure False+    case msk of+      Nothing   -> propShortErr' 9+      Just msk' -> dumpListByMask' msk' [("min size"    ,dumpSize  ,cARDINAL)+                                        ,("max size"    ,dumpSize  ,cARDINAL)+                                        ,("increment"   ,dumpSize  ,cARDINAL)+                                        ,("aspect ratio",dumpAspect,cARDINAL)+                                        ,("base size"   ,dumpSize  ,cARDINAL)+                                        ,("gravity"     ,dumpGrav  ,cARDINAL)+                                        ]++dumpSize :: HasCallStack => Decoder Bool+dumpSize =  append "(" >> dump32 >> append "," >> dump32 >> append ")"++dumpAspect :: HasCallStack => Decoder Bool+dumpAspect =  do+  -- have to do this manually since it doesn't really fit+  append "min = "+  dump32+  append "/"+  dump32+  append ", max = "+  dump32+  append "/"+  dump32++dumpGrav :: HasCallStack => Decoder Bool+dumpGrav =  dumpEnum wmGravity+ -- the most common case-dumpEnum    :: [String] -> Decoder Bool+dumpEnum    :: HasCallStack => [String] -> Decoder Bool dumpEnum ss =  dumpEnum' ss cARDINAL  -- implement exceptional cases atop a normal dumper -- @@@ there's gotta be a better way-dumpExcept           :: [(Integer,String)] -> Decoder Bool -> Decoder Bool+dumpExcept           :: HasCallStack => [(Integer,String)] -> Decoder Bool -> Decoder Bool dumpExcept xs item = do   -- this horror brought to you by reparsing to get the right value for our use   sp <- get@@ -887,7 +985,8 @@     -- and after all that, we can process the exception list     dumpExcept' xs that v -dumpExcept'                                      :: [(Integer,String)]+dumpExcept'                                      :: HasCallStack+                                                 => [(Integer,String)]                                                  -> DecodeState                                                  -> Integer                                                  -> Decoder Bool@@ -897,7 +996,7 @@  -- use @ps@ to get process information. -- @@@@ assumes a POSIX @ps@, not a BSDish one.-dumpPid :: Decoder Bool+dumpPid :: HasCallStack => Decoder Bool dumpPid =  guardType cARDINAL $ do              n <- getInt' 32              case n of@@ -915,17 +1014,17 @@                                            then "pid " ++ pid                                            else prc !! 1 -dumpTime :: Decoder Bool+dumpTime :: HasCallStack => Decoder Bool dumpTime =  append "server event # " >> dump32 -dumpState :: Decoder Bool+dumpState :: HasCallStack => Decoder Bool dumpState =  do   wM_STATE <- inX $ getAtom "WM_STATE"   guardType wM_STATE $ dumpList' [("state"      ,dumpEnum wmState,cARDINAL)                                  ,("icon window",dumpWindow      ,wINDOW  )                                  ] -dumpMotifDragReceiver :: Decoder Bool+dumpMotifDragReceiver :: HasCallStack => Decoder Bool dumpMotifDragReceiver =  do   ta <- inX $ getAtom "_MOTIF_DRAG_RECEIVER_INFO"   guardType ta $ dumpList' [("endian"    ,dumpMotifEndian,cARDINAL)@@ -933,11 +1032,11 @@                            ,("style"     ,dumpMDropStyle ,cARDINAL) -- @@@ dummy                            ] -dumpMDropStyle :: Decoder Bool+dumpMDropStyle :: HasCallStack => Decoder Bool dumpMDropStyle =  do   d <- getInt' 8   pad 1 $ case d of-            Nothing             -> propShortErr+            Nothing             -> propShortErr' 9             Just ps | ps == 0   -> pad 12 $ append "none"                     | ps == 1   -> pad 12 $ append "drop only"                     | ps == 2   ->          append "prefer preregister " >> dumpMDPrereg@@ -947,7 +1046,7 @@                     | ps == 6   -> pad 12 $ append "prefer receiver"                     | otherwise -> failure $ "unknown drop style " ++ show ps -dumpMDPrereg :: Decoder Bool+dumpMDPrereg :: HasCallStack => Decoder Bool dumpMDPrereg =  do   -- this is a bit ugly; we pretend to be extending the above dumpList'   append ","@@ -957,7 +1056,7 @@   append "drop sites = "   dsc' <- getInt' 16   case dsc' of-    Nothing  -> propShortErr+    Nothing  -> propShortErr' 10     Just dsc -> do       withIndent 13 $ append (show dsc)       pad 2 $ do@@ -969,7 +1068,7 @@ dumpMDBlocks   :: Int -> Decoder Bool dumpMDBlocks _ =  propSimple "(drop site info)" -- @@@ maybe later if needed -dumpMotifEndian :: Decoder Bool+dumpMotifEndian :: HasCallStack => Decoder Bool dumpMotifEndian =  guardType cARDINAL $ guardSize 8 $ do   c <- map twiddle <$> eat 1   case c of@@ -977,14 +1076,14 @@     ['B'] -> append "big"     _     -> failure "bad endian flag" -pad     :: Int -> Decoder Bool -> Decoder Bool+pad     :: HasCallStack => Int -> Decoder Bool -> Decoder Bool pad n p =  do   vs <- gets value   if length vs < n-    then propShortErr+    then propShortErr' 11     else modify (\r -> r {value = drop n vs}) >> p -dumpPercent :: Decoder Bool+dumpPercent :: HasCallStack => Decoder Bool dumpPercent =  guardType cARDINAL $ do                  n <- getInt' 32                  case n of@@ -994,7 +1093,7 @@                            pct :: Double                         in append $ show (round pct :: Integer) ++ "%" -dumpWmHints :: Decoder Bool+dumpWmHints :: HasCallStack => Decoder Bool dumpWmHints =   guardType wM_HINTS $ do   msk <- getInt' 32@@ -1011,7 +1110,7 @@                                  ,("window_group" ,dumpWindow      ,wINDOW  )                                  ] -dumpBits    :: [String] -> Decoder Bool+dumpBits    :: HasCallStack => [String] -> Decoder Bool dumpBits bs =  guardType cARDINAL $ do                  n <- getInt' 32                  case n of@@ -1069,6 +1168,9 @@             ,"pager/task list"             ] +cpState :: [String]+cpState =  ["no preference","disable compositing","force compositing"]+ {- eventually... wmHintsFlags :: [String] wmHintsFlags =  ["Input"@@ -1112,6 +1214,12 @@ wmState :: [String] wmState =  ["Withdrawn","Normal","Zoomed (obsolete)","Iconified","Inactive"] +nwAction :: [String]+nwAction =  ["Clear", "Set", "Toggle"]++wmGravity :: [String]+wmGravity =  ["forget/unmap","NW","N","NE","W","C","E","SW","S","SE","static"]+ nwmEnum                  :: Maybe String                          -> [String]                          -> [String]@@ -1121,7 +1229,7 @@ -- and the lowest level coercions --  -- parse and return an integral value-getInt'    :: Int -> Decoder (Maybe Integer)+getInt'    :: HasCallStack => Int -> Decoder (Maybe Integer) -- see XSync documentation for this insanity getInt' 64 =  guardR width 32 (\a e -> propSizeErr a e >> return Nothing) $               guardSize' 8 (propShortErr >> return Nothing) $ do@@ -1129,7 +1237,7 @@                 hi <- inhale 32                 return $ Just $ lo + hi * (fromIntegral (maxBound :: Word32) + 1) getInt' w  =  guardR width w  (\a e -> propSizeErr a e >> return Nothing) $-              guardSize' (bytes w) (propShortErr >> return Nothing)       $+              guardSize' (bytes w) (propShortErr' 13 >> return Nothing)       $               Just <$> inhale w  -- parse an integral value and feed it to a show-er of some kind@@ -1171,8 +1279,8 @@ append =  append' True  -- and the same but for errors-failure :: String -> Decoder Bool-failure =  append' False+failure :: HasCallStack => String -> Decoder Bool+failure =  append' False . (++ prettyCallStack callStack)  -- common appender append'     :: Bool -> String -> Decoder Bool@@ -1186,8 +1294,12 @@ propSimple s =  modify (\r -> r {value = []}) >> append s  -- report various errors-propShortErr :: Decoder Bool+propShortErr :: HasCallStack => Decoder Bool propShortErr =  failure "(property ended prematurely)"++-- debug version+propShortErr'   :: HasCallStack => Int -> Decoder Bool+propShortErr' n =  failure $ "(short prop " ++ show n ++ ")"  propSizeErr     :: Int -> Int -> Decoder Bool propSizeErr e a =  failure $ "(bad bit width " ++
XMonad/Hooks/DebugKeyEvents.hs view
@@ -51,9 +51,8 @@ -- the key; @mask@ is raw, and @clean@ is what @xmonad@ sees after -- sanitizing it (removing @numberLockMask@, etc.) ----- For more detailed instructions on editing the logHook see:------ "XMonad.Doc.Extending#The_log_hook_and_external_status_bars"+-- For more detailed instructions on editing the logHook see+-- <https://xmonad.org/TUTORIAL.html#make-xmonad-and-xmobar-talk-to-each-other the tutorial>.  -- | Print key events to stderr for debugging debugKeyEvents :: Event -> X All
XMonad/Hooks/DynamicLog.hs view
@@ -76,7 +76,7 @@ import XMonad.Hooks.StatusBar  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad -- > import XMonad.Hooks.DynamicLog
XMonad/Hooks/DynamicProperty.hs view
@@ -1,113 +1,24 @@------------------------------------------------------------------------------ -- | -- Module      :  XMonad.Hooks.DynamicProperty -- Description :  Apply a ManageHook to an already-mapped window. -- Copyright   :  (c) Brandon S Allbery, 2015 -- License     :  BSD3-style (see LICENSE)--- -- Maintainer  :  allbery.b@gmail.com--- Stability   :  unstable--- Portability :  not portable ----- Module to apply a ManageHook to an already-mapped window when a property--- changes. This would commonly be used to match browser windows by title,--- since the final title will only be set after (a) the window is mapped,--- (b) its document has been loaded, (c) all load-time scripts have run.--- (Don't blame browsers for this; it's inherent in HTML and the DOM. And--- changing title dynamically is explicitly permitted by ICCCM and EWMH;--- you don't really want to have your editor window umapped/remapped to--- show the current document and modified state in the titlebar, do you?)------ This is a handleEventHook that triggers on a PropertyChange event. It--- currently ignores properties being removed, in part because you can't--- do anything useful in a ManageHook involving nonexistence of a property.------ This module could also be useful for Electron applications like Spotify--- which sets its WM_CLASS too late for window manager to map it properly.-----------------------------------------------------------------------------------module XMonad.Hooks.DynamicProperty ( -- * Usage-                                      -- $usage--                                      -- * Documentation-                                      dynamicPropertyChange+module XMonad.Hooks.DynamicProperty {-# DEPRECATED "Use \"XMonad.Hooks.OnPropertyChange\" instead." #-}+                                    ( module XMonad.Hooks.OnPropertyChange+                                    , dynamicPropertyChange                                     , dynamicTitle                                     ) where  import XMonad+import XMonad.Hooks.OnPropertyChange import XMonad.Prelude --- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:------ > import XMonad.Hooks.DynamicProperty------ Enable it by including in you handleEventHook definition:------ >  main = xmonad $ def--- >      { ...--- >      , handleEventHook = dynamicPropertyChange "WM_NAME" (title =? "Spotify" --> doShift "5"))--- >      , ...--- >      }------ Or you could create a dynamicManageHook as below:------ > myDynamicManageHook :: ManageHook--- > myDynamicManageHook =--- >  composeAll--- >    [ className =? "Spotify" --> doShift (myWorkspaces !! 4),--- >      title =? "maybe_special_terminal" <||> title =? "special_terminal" --> doCenterFloat,--- >      className =? "dynamicApp" <&&> title =? "dynamic_app" --> doCenterFloat--- >    ]------ And then use it in your handleEventHookDefinition:------ >  main = xmonad $ def--- >      { ...--- >      , handleEventHook = dynamicPropertyChange "WM_NAME" myDynamicManageHook <> handleEventHook baseConfig--- >      , ...--- >      }------- |--- Run a 'ManageHook' when a specific property is changed on a window. Note--- that this will run on any window which changes the property, so you should--- be very specific in your 'ManageHook' matching (lots of windows change--- their titles on the fly!):------ > dynamicPropertyChange "WM_NAME" (className =? "Iceweasel" <&&> title =? "whatever" --> doShift "2")------ Note that the fixity of (-->) won't allow it to be mixed with ($), so you--- can't use the obvious $ shorthand.------ > dynamicPropertyChange "WM_NAME" $ title =? "Foo" --> doFloat -- won't work!------ Consider instead phrasing it like any--- other 'ManageHook':------ >  main = xmonad $ def--- >      { ...--- >      , handleEventHook = dynamicPropertyChange "WM_NAME" myDynHook <> handleEventHook baseConfig--- >      , ...--- >      }--- >--- >    myDynHook = composeAll [...]---+-- | 'dynamicPropertyChange' = 'onXPropertyChange' dynamicPropertyChange :: String -> ManageHook -> Event -> X All-dynamicPropertyChange prop hook PropertyEvent { ev_window = w, ev_atom = a, ev_propstate = ps } = do-  pa <- getAtom prop-  when (ps == propertyNewValue && a == pa) $ do-    g <- appEndo <$> userCodeDef (Endo id) (runQuery hook w)-    windows g-  return mempty -- so anything else also processes it-dynamicPropertyChange _ _ _ = return mempty+dynamicPropertyChange = onXPropertyChange --- | A shorthand for the most common case, dynamic titles+-- | 'dynamicTitle' = 'onTitleChange' dynamicTitle :: ManageHook -> Event -> X All--- strictly, this should also check _NET_WM_NAME. practically, both will--- change and each gets its own PropertyEvent, so we'd need to record that--- we saw the event for that window and ignore the second one. Instead, just--- trust that nobody sets only _NET_WM_NAME. (I'm sure this will prove false,--- since there's always someone who can't bother being compliant.)-dynamicTitle = dynamicPropertyChange "WM_NAME"+dynamicTitle = onTitleChange
XMonad/Hooks/EwmhDesktops.hs view
@@ -24,6 +24,8 @@     -- $usage     ewmh,     ewmhFullscreen,+    ewmhDesktopsManageHook,+    ewmhDesktopsMaybeManageHook,      -- * Customization     -- $customization@@ -40,6 +42,14 @@     -- $customActivate     setEwmhActivateHook, +    -- ** Fullscreen+    -- $customFullscreen+    setEwmhFullscreenHooks,++    -- ** @_NET_DESKTOP_VIEWPORT@+    -- $customManageDesktopViewport+    disableEwmhManageDesktopViewport,+     -- * Standalone hooks (deprecated)     ewmhDesktopsStartup,     ewmhDesktopsLogHook,@@ -66,7 +76,7 @@ import qualified XMonad.Util.ExtensibleState as XS  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad -- > import XMonad.Hooks.EwmhDesktops@@ -102,6 +112,10 @@             -- ^ configurable workspace rename (see 'XMonad.Hooks.StatusBar.PP.ppRename')         , activateHook :: ManageHook             -- ^ configurable handling of window activation requests+        , fullscreenHooks :: (ManageHook, ManageHook)+            -- ^ configurable handling of fullscreen state requests+        , manageDesktopViewport :: Bool+            -- ^ manage @_NET_DESKTOP_VIEWPORT@?         }  instance Default EwmhDesktopsConfig where@@ -109,6 +123,8 @@         { workspaceSort = getSortByIndex         , workspaceRename = pure pure         , activateHook = doFocus+        , fullscreenHooks = (doFullFloat, doSink)+        , manageDesktopViewport = True         }  @@ -229,6 +245,45 @@ setEwmhActivateHook h = XC.modifyDef $ \c -> c{ activateHook = h }  +-- $customFullscreen+-- When a client sends a @_NET_WM_STATE@ request to add\/remove\/toggle the+-- @_NET_WM_STATE_FULLSCREEN@ state, 'ewmhFullscreen' uses a pair of hooks to+-- make the window fullscreen and revert its state. The default hooks are+-- stateless: windows are fullscreened by turning them into fullscreen floats,+-- and reverted by sinking them into the tiling layer. This behaviour can be+-- configured by supplying a pair of 'ManageHook's to 'setEwmhFullscreenHooks'.+--+-- See "XMonad.Actions.ToggleFullFloat" for a pair of hooks that store the+-- original state of floating windows.++-- | Set (replace) the hooks invoked when clients ask to add/remove the+-- $_NET_WM_STATE_FULLSCREEN@ state. The defaults are 'doFullFloat' and+-- 'doSink'.+setEwmhFullscreenHooks :: ManageHook -> ManageHook -> XConfig l -> XConfig l+setEwmhFullscreenHooks f uf = XC.modifyDef $ \c -> c{ fullscreenHooks = (f, uf) }+++-- $customManageDesktopViewport+-- Setting @_NET_DESKTOP_VIEWPORT@ is typically desired but can lead to a+-- confusing workspace list in polybar, where this information is used to+-- re-group the workspaces by monitor. See+-- <https://github.com/polybar/polybar/issues/2603 polybar#2603>.+--+-- To avoid this, you can use:+--+-- > main = xmonad $ … . disableEwmhManageDesktopViewport . ewmh . … $ def{…}+--+-- Note that if you apply this configuration in an already running environment,+-- the property may remain at its previous value. It can be removed by running:+--+-- > xprop -root -remove _NET_DESKTOP_VIEWPORT+--+-- Which should immediately fix your bar.+--+disableEwmhManageDesktopViewport :: XConfig l -> XConfig l+disableEwmhManageDesktopViewport = XC.modifyDef $ \c -> c{ manageDesktopViewport = False }++ -- | Initializes EwmhDesktops and advertises EWMH support to the X server. {-# DEPRECATED ewmhDesktopsStartup "Use ewmh instead." #-} ewmhDesktopsStartup :: X ()@@ -303,7 +358,7 @@ whenChanged = whenX . XS.modified . const  ewmhDesktopsLogHook' :: EwmhDesktopsConfig -> X ()-ewmhDesktopsLogHook' EwmhDesktopsConfig{workspaceSort, workspaceRename} = withWindowSet $ \s -> do+ewmhDesktopsLogHook' EwmhDesktopsConfig{workspaceSort, workspaceRename, manageDesktopViewport} = withWindowSet $ \s -> do     sort' <- workspaceSort     let ws = sort' $ W.workspaces s @@ -320,10 +375,33 @@     let clientList = nub . concatMap (W.integrate' . W.stack) $ ws     whenChanged (ClientList clientList) $ setClientList clientList -    -- Set stacking client list which should have bottom-to-top-    -- stacking order, i.e. focused window should be last-    let clientListStacking = nub . concatMap (maybe [] (\(W.Stack x l r) -> reverse l ++ r ++ [x]) . W.stack) $ ws-    whenChanged (ClientListStacking clientListStacking) $ setClientListStacking clientListStacking+    -- @ws@ is sorted in the "workspace order", which, by default, is+    -- the lexicographical sorting on @WorkspaceId@.+    -- @_NET_CLIENT_LIST_STACKING@ is expected to be in the "bottom-to-top+    -- stacking order".  It is unclear what that would mean for windows on+    -- invisible workspaces, but it seems reasonable to assume that windows on+    -- the current workspace should be "at the top".  With the focused window to+    -- be the top most, meaning the last.+    --+    -- There has been a number of discussions on the order of windows within a+    -- workspace.  See:+    --+    --   https://github.com/xmonad/xmonad-contrib/issues/567+    --   https://github.com/xmonad/xmonad-contrib/pull/568+    --   https://github.com/xmonad/xmonad-contrib/pull/772+    let clientListStacking =+          let wsInFocusOrder = W.hidden s+                               ++ (map W.workspace . W.visible) s+                               ++ [W.workspace $ W.current s]+              stackWindows (W.Stack cur up down) = reverse up ++ down ++ [cur]+              workspaceWindows = maybe [] stackWindows . W.stack+              -- In case a window is a member of multiple workspaces, we keep+              -- only the last occurrence in the list.  One that is closer to+              -- the top in the focus order.+              uniqueKeepLast = reverse . nub . reverse+           in uniqueKeepLast $ concatMap workspaceWindows wsInFocusOrder+    whenChanged (ClientListStacking clientListStacking) $+      setClientListStacking clientListStacking      -- Set current desktop number     let current = W.currentTag s `elemIndex` map W.tag ws@@ -342,9 +420,10 @@     whenChanged (ActiveWindow activeWindow') $ setActiveWindow activeWindow'      -- Set desktop Viewport-    let visibleScreens = W.current s : W.visible s-        currentTags    = map (W.tag . W.workspace) visibleScreens-    whenChanged (MonitorTags currentTags) $ mkViewPorts s (map W.tag ws)+    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)  -- | Create the viewports from the current 'WindowSet' and a list of -- already sorted workspace IDs.@@ -404,6 +483,31 @@         mempty ewmhDesktopsEventHook' _ _ = mempty +-- | A 'ManageHook' that shifts windows to the workspace they want to be in.+-- Useful for restoring browser windows to where they were before restart.+--+-- To only use this for browsers (which might be a good idea, as many apps try+-- to restore their window to their original position, but it's rarely+-- desirable outside of security updates of multi-window apps like a browser),+-- use this:+--+-- > stringProperty "WM_WINDOW_ROLE" =? "browser" --> ewmhDesktopsManageHook+ewmhDesktopsManageHook :: ManageHook+ewmhDesktopsManageHook = maybeToDefinite ewmhDesktopsMaybeManageHook++-- | 'ewmhDesktopsManageHook' as a 'MaybeManageHook' for use with+-- 'composeOne'. Returns 'Nothing' if the window didn't indicate any desktop+-- preference, otherwise 'Just' (even if the preferred desktop was out of+-- bounds).+ewmhDesktopsMaybeManageHook :: MaybeManageHook+ewmhDesktopsMaybeManageHook = desktop >>= traverse doShiftI+  where+    doShiftI :: Int -> ManageHook+    doShiftI d = do+        sort' <- liftX . XC.withDef $ \EwmhDesktopsConfig{workspaceSort} -> workspaceSort+        ws <- liftX . gets $ map W.tag . sort' . W.workspaces . windowset+        maybe idHook doShift $ ws !? d+ -- | Add EWMH fullscreen functionality to the given config. ewmhFullscreen :: XConfig a -> XConfig a ewmhFullscreen c = c { startupHook     = startupHook c <> fullscreenStartup@@ -421,7 +525,12 @@ -- Note this is not included in 'ewmh'. {-# DEPRECATED fullscreenEventHook "Use ewmhFullscreen instead." #-} fullscreenEventHook :: Event -> X All-fullscreenEventHook (ClientMessageEvent _ _ _ dpy win typ (action:dats)) = do+fullscreenEventHook = XC.withDef . fullscreenEventHook'++fullscreenEventHook' :: Event -> EwmhDesktopsConfig -> X All+fullscreenEventHook'+    ClientMessageEvent{ev_event_display = dpy, ev_window = win, ev_message_type = typ, ev_data = action:dats}+    EwmhDesktopsConfig{fullscreenHooks = (fullscreenHook, unFullscreenHook)} = do   managed <- isClient win   wmstate <- getAtom "_NET_WM_STATE"   fullsc <- getAtom "_NET_WM_STATE_FULLSCREEN"@@ -436,16 +545,16 @@       chWstate f = io $ changeProperty32 dpy win wmstate aTOM propModeReplace (f wstate)    when (managed && typ == wmstate && fi fullsc `elem` dats) $ do-    when (action == add || (action == toggle && not isFull)) $ do+    when (not isFull && (action == add || action == toggle)) $ do       chWstate (fi fullsc:)-      windows $ W.float win $ W.RationalRect 0 0 1 1-    when (action == remove || (action == toggle && isFull)) $ do+      windows . appEndo =<< runQuery fullscreenHook win+    when (isFull && (action == remove || action == toggle)) $ do       chWstate $ delete (fi fullsc)-      windows $ W.sink win+      windows . appEndo =<< runQuery unFullscreenHook win    return $ All True -fullscreenEventHook _ = return $ All True+fullscreenEventHook' _ _ = return $ All True  setNumberOfDesktops :: (Integral a) => a -> X () setNumberOfDesktops n = withDisplay $ \dpy -> do@@ -511,6 +620,7 @@                          ,"_NET_ACTIVE_WINDOW"                          ,"_NET_WM_DESKTOP"                          ,"_NET_WM_STRUT"+                         ,"_NET_WM_STRUT_PARTIAL"                          ,"_NET_DESKTOP_VIEWPORT"                          ]     io $ changeProperty32 dpy r a aTOM propModeReplace (fmap fromIntegral supp)
XMonad/Hooks/FadeInactive.hs view
@@ -32,7 +32,7 @@ import qualified XMonad.StackSet as W  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad -- > import XMonad.Hooks.FadeInactive@@ -47,13 +47,12 @@ -- you will need to have xcompmgr <http://freedesktop.org/wiki/Software/xapps> -- or something similar for this to do anything ----- For more detailed instructions on editing the logHook see:------ "XMonad.Doc.Extending#The_log_hook_and_external_status_bars"------ For more detailed instructions on editing the layoutHook see:+-- For more detailed instructions on editing the logHook see+-- <https://xmonad.org/TUTORIAL.html#make-xmonad-and-xmobar-talk-to-each-other the tutorial>. ----- "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook".  -- | Converts a percentage to the format required for _NET_WM_WINDOW_OPACITY rationalToOpacity :: Integral a => Rational -> a
XMonad/Hooks/FadeWindows.hs view
@@ -96,7 +96,7 @@ -- -- at the top of @myFadeHook@. ----- This module is best used with "XMonad.Hooks.MoreManageHelpers", which+-- This module is best used with "XMonad.Hooks.ManageHelpers", which -- exports a number of Queries that can be used in either @ManageHook@ -- or @FadeHook@. --@@ -105,9 +105,8 @@ -- aren't running a compositing manager, the opacity will be recorded -- but won't take effect until a compositing manager is started. ----- For more detailed instructions on editing the 'logHook' see:------ "XMonad.Doc.Extending#The_log_hook_and_external_status_bars"+-- For more detailed instructions on editing the 'logHook' see+-- <https://xmonad.org/TUTORIAL.html#make-xmonad-and-xmobar-talk-to-each-other the tutorial>. -- -- For more detailed instructions on editing the 'handleEventHook', -- see:@@ -217,7 +216,7 @@  -- | A 'handleEventHook' to handle fading and unfading of newly mapped --   or unmapped windows; this avoids problems with layouts such as---   "XMonad.Layout.Full" or "XMonad.Layout.Tabbed".  This hook may+--   'XMonad.Layout.Full' or "XMonad.Layout.Tabbed".  This hook may --   also be useful with "XMonad.Hooks.FadeInactive". fadeWindowsEventHook                     :: Event -> X All fadeWindowsEventHook MapNotifyEvent{} =
XMonad/Hooks/FloatNext.hs view
@@ -47,7 +47,7 @@ -- to automatically send the next spawned window(s) to the floating -- layer. ----- You can use it by including the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use it by including the following in your @xmonad.hs@: -- -- > import XMonad.Hooks.FloatNext --
XMonad/Hooks/Focus.hs view
@@ -1,6 +1,8 @@-{-# LANGUAGE FlexibleContexts       #-}-{-# LANGUAGE MultiParamTypeClasses  #-}-{-# OPTIONS_HADDOCK show-extensions #-}+{-# LANGUAGE DerivingVia                #-}+{-# LANGUAGE FlexibleContexts           #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MultiParamTypeClasses      #-}+{-# OPTIONS_HADDOCK show-extensions     #-}  -- | -- Module:      XMonad.Hooks.Focus@@ -212,7 +214,7 @@ -- --  - /mod4Mask+v/ key toggles focus lock (when enabled, neither focus nor --  workspace won't be switched).---  - I need 'XMonad.Hooks.EwmhDesktops' module for enabling window+--  - I need "XMonad.Hooks.EwmhDesktops" module for enabling window --  activation. --  - 'FocusHook' in 'manageHook' will be called /only/ for new windows. --  - 'FocusHook' in 'setEwmhActivateHook' will be called /only/ for activated windows.@@ -355,28 +357,13 @@ -- | Monad on top of 'Query' providing additional information about new -- window. newtype FocusQuery a = FocusQuery (ReaderT Focus Query a)-instance Functor FocusQuery where-    fmap f (FocusQuery x) = FocusQuery (fmap f x)-instance Applicative FocusQuery where-    pure x                              = FocusQuery (pure x)-    (FocusQuery f) <*> (FocusQuery mx)  = FocusQuery (f <*> mx)-instance Monad FocusQuery where-    (FocusQuery mx) >>= f   = FocusQuery $ mx >>= \x ->-                              let FocusQuery y = f x in y-instance MonadReader Focus FocusQuery where-    ask                     = FocusQuery ask-    local f (FocusQuery mx) = FocusQuery (local f mx)-instance MonadIO FocusQuery where-    liftIO mx       = FocusQuery (liftIO mx)-instance Semigroup a => Semigroup (FocusQuery a) where-    (<>)            = liftM2 (<>)-instance Monoid a => Monoid (FocusQuery a) where-    mempty          = return mempty+  deriving newtype (Functor, Applicative, Monad, MonadReader Focus, MonadIO)+  deriving (Semigroup, Monoid) via Ap FocusQuery a  runFocusQuery :: FocusQuery a -> Focus -> Query a runFocusQuery (FocusQuery m)    = runReaderT m -type FocusHook      = FocusQuery (Endo WindowSet)+type FocusHook = FocusQuery (Endo WindowSet)   -- Lifting into 'FocusQuery'.
− XMonad/Hooks/ICCCMFocus.hs
@@ -1,42 +0,0 @@--------------------------------------------------------------------------------- |--- Module       : XMonad.Hooks.ICCCMFocus--- Description  : Deprecated.--- License      : BSD------ Maintainer   : Tony Morris <haskell@tmorris.net>------ Implemented in your @logHook@, Java swing applications will not misbehave--- when it comes to taking and losing focus.------ This has been done by taking the patch in <http://code.google.com/p/xmonad/issues/detail?id=177> and refactoring it so that it can be included in @~\/.xmonad\/xmonad.hs@.------ @---    conf' =---      conf {---        logHook = takeTopFocus---      }--- @-------------------------------------------------------------------------------module XMonad.Hooks.ICCCMFocus-{-# DEPRECATED "XMonad.Hooks.ICCCMFocus: xmonad>0.10 core merged issue 177" #-}-(-  atom_WM_TAKE_FOCUS-, takeFocusX-, takeTopFocus-) where--import XMonad-import XMonad.Hooks.SetWMName-import qualified XMonad.StackSet as W--takeFocusX ::-  Window-  -> X ()-takeFocusX _w = return ()---- | The value to add to your log hook configuration.-takeTopFocus ::-  X ()-takeTopFocus =-  withWindowSet (maybe (setFocusX =<< asks theRoot) takeFocusX . W.peek) >> setWMName "LG3D"
XMonad/Hooks/InsertPosition.hs view
@@ -17,21 +17,30 @@ module XMonad.Hooks.InsertPosition (     -- * Usage     -- $usage-    insertPosition+    setupInsertPosition, insertPosition     ,Focus(..), Position(..)     ) where -import XMonad(ManageHook, MonadReader(ask))+import XMonad (ManageHook, MonadReader (ask), XConfig (manageHook)) import XMonad.Prelude (Endo (Endo), find) import qualified XMonad.StackSet as W  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module by importing it in your @xmonad.hs@: -- -- > import XMonad.Hooks.InsertPosition+--+-- You then just have to add 'setupInsertPosition' to your @main@ function:+--+-- > main = xmonad $ … $ setupInsertPosition Master Newer $ def { … }+--+-- Alternatively (i.e., you should /not/ do this if you already have set+-- up the above combinator), you can also directly insert+-- 'insertPosition' into your manageHook:+-- -- > xmonad def { manageHook = insertPosition Master Newer <> myManageHook } ----- You should you put the manageHooks that use 'doShift' to take effect+-- NOTE: You should you put the manageHooks that use 'doShift' to take effect -- /before/ 'insertPosition', so that the window order will be consistent. -- Because ManageHooks compose from right to left (like function composition -- '.'), this means that 'insertPosition' should be the leftmost ManageHook.@@ -39,6 +48,11 @@ data Position = Master | End | Above | Below data Focus = Newer | Older +-- | A combinator for setting up 'insertPosition'.+setupInsertPosition :: Position -> Focus -> XConfig a -> XConfig a+setupInsertPosition pos foc cfg =+  cfg{ manageHook = insertPosition pos foc <> manageHook cfg }+ -- | insertPosition. A manage hook for placing new windows. XMonad's default is -- the same as using: @insertPosition Above Newer@. insertPosition :: Position -> Focus -> ManageHook@@ -68,5 +82,7 @@ insertDown w = W.swapDown . W.insertUp w  focusLast' ::  W.Stack a -> W.Stack a-focusLast' st = let ws = W.integrate st-    in W.Stack (last ws) (tail $ reverse ws) []+focusLast' st =+  case reverse (W.integrate st) of+    []       -> st+    (l : ws) -> W.Stack l ws []
XMonad/Hooks/ManageDebug.hs view
@@ -1,7 +1,7 @@ ----------------------------------------------------------------------------- -- | -- Module      :  XMonad.Hooks.ManageDebug--- Description :  A manageHook and associated logHook for debugging "ManageHooks".+-- Description :  A manageHook and associated logHook for debugging ManageHooks. -- Copyright   :  (c) Brandon S Allbery KF8NH, 2014 -- License     :  BSD3-style (see LICENSE) --@@ -12,7 +12,7 @@ -- A @manageHook@ and associated @logHook@ for debugging 'ManageHook's. -- Simplest usage: wrap your xmonad config in the @debugManageHook@ combinator. -- Or use @debugManageHookOn@ for a triggerable version, specifying the--- triggering key sequence in 'XMonad.Util.EZConfig' syntax. Or use the+-- triggering key sequence in "XMonad.Util.EZConfig" syntax. Or use the -- individual hooks in whatever way you see fit. -- -----------------------------------------------------------------------------@@ -47,7 +47,7 @@                         }  -- | A combinator to add triggerable 'ManageHook' debugging in a single operation.---   Specify a key sequence as a string in 'XMonad.Util.EZConfig' syntax; press+--   Specify a key sequence as a string in "XMonad.Util.EZConfig" syntax; press --   this key before opening the window to get just that logged. debugManageHookOn :: String -> XConfig l -> XConfig l debugManageHookOn key cf = cf {logHook    = manageDebugLogHook <> logHook    cf
XMonad/Hooks/ManageDocks.hs view
@@ -49,7 +49,7 @@ import qualified XMonad.StackSet as W  -- $usage--- To use this module, add the following import to @~\/.xmonad\/xmonad.hs@:+-- To use this module, add the following import to @xmonad.hs@: -- -- > import XMonad.Hooks.ManageDocks --@@ -83,7 +83,7 @@ -- > layoutHook = avoidStrutsOn [U,L] (tall ||| mirror tall ||| ...) -- -- For detailed instructions on editing your key bindings, see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>. --  -- | Add docks functionality to the given config.  See above for an example.
XMonad/Hooks/ManageHelpers.hs view
@@ -52,6 +52,7 @@     isMinimized,     isDialog,     pid,+    desktop,     transientTo,     maybeToDefinite,     MaybeManageHook,@@ -199,6 +200,15 @@ -- See <https://specifications.freedesktop.org/wm-spec/wm-spec-1.5.html#idm45623487788432>. pid :: Query (Maybe ProcessID) pid = ask >>= \w -> liftX $ getProp32s "_NET_WM_PID" w <&> \case+    Just [x] -> Just (fromIntegral x)+    _        -> Nothing++-- | This function returns 'Just' the @_NET_WM_DESKTOP@ property for a+-- particular window if set, 'Nothing' otherwise.+--+-- See <https://specifications.freedesktop.org/wm-spec/wm-spec-1.5.html#idm46181547492704>.+desktop :: Query (Maybe Int)+desktop = ask >>= \w -> liftX $ getProp32s "_NET_WM_DESKTOP" w <&> \case     Just [x] -> Just (fromIntegral x)     _        -> Nothing 
XMonad/Hooks/Minimize.hs view
@@ -25,7 +25,7 @@ import XMonad.Prelude  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Hooks.Minimize -- > import XMonad.Layout.Minimize@@ -43,10 +43,12 @@     a_cs <- getAtom "WM_CHANGE_STATE"      when (mt == a_aw) $ maximizeWindow w-    when (mt == a_cs) $ do-      let message = fromIntegral . head $ dt-      when (message == normalState) $ maximizeWindow w-      when (message == iconicState) $ minimizeWindow w+    when (mt == a_cs) $ case listToMaybe dt of+      Nothing  -> pure ()+      Just dth -> do+        let message = fromIntegral dth+        when (message == normalState) $ maximizeWindow w+        when (message == iconicState) $ minimizeWindow w      return (All True) minimizeEventHook _ = return (All True)
XMonad/Hooks/Modal.hs view
@@ -117,7 +117,7 @@ -- --   - @[(String, X ())]@, or -----   - @XConfig Layout -> M.Map (ButtonMask, KeySym) (X ())@).+--   - @XConfig Layout -> M.Map (ButtonMask, KeySym) (X ())@. -- -- The former—accessible via 'mkKeysEz'—is how specifying keys work with -- "XMonad.Util.EZConfig", while the latter is more geared towards how@@ -135,21 +135,17 @@  -- --< Types >-- {{{ --- | Internally, we represent keys as the usual function type:--- @XConfig Layout -> M.Map (ButtonMask, KeySym) (X ())@.-type Keys = XConfig Layout -> M.Map (ButtonMask, KeySym) (X ())---- | From a list of 'XMonad.Util.EZConfig'-style bindings, generate a+-- | From a list of "XMonad.Util.EZConfig"-style bindings, generate a -- key representation. -- -- >>> mkKeysEz [("h", xmessage "Hello, world!")]-mkKeysEz :: [(String, X ())] -> Keys+mkKeysEz :: [(String, X ())] -> (XConfig Layout -> M.Map (ButtonMask, KeySym) (X ())) mkKeysEz = flip mkKeymap  -- | The mode type. Use 'mode' or 'modeWithExit' to create modes. data Mode = Mode   { label     :: !String-  , boundKeys :: !Keys+  , boundKeys :: !(XConfig Layout -> M.Map (ButtonMask, KeySym) (X ()))   }  -- | Newtype for the extensible config.@@ -213,14 +209,14 @@  -- | Create a 'Mode' from the given binding to 'exitMode', label and -- keybindings.-modeWithExit :: String -> String -> Keys -> Mode+modeWithExit :: String -> String -> (XConfig Layout -> M.Map (KeyMask, KeySym) (X ())) -> Mode modeWithExit exitKey mlabel keys = Mode mlabel $ \cnf ->   let exit = fromMaybe (0, xK_Escape) $ runParser (parseKeyCombo cnf) exitKey    in M.insert exit exitMode (keys cnf)  -- | Create a 'Mode' from the given label and keybindings. Sets the -- @escape@ key to 'exitMode'.-mode :: String -> Keys -> Mode+mode :: String -> (XConfig Layout -> M.Map (KeyMask, KeySym) (X ())) -> Mode mode = modeWithExit "<Escape>"  -- | Set the current 'Mode' based on its label.
+ XMonad/Hooks/OnPropertyChange.hs view
@@ -0,0 +1,119 @@+-----------------------------------------------------------------------------+-- |+-- Module      :  XMonad.Hooks.OnPropertyChange+-- Description :  Apply a manageHook on a property (e.g., @WM_CLASS@) change+-- Copyright   :  (c) Brandon S Allbery, 2015+-- License     :  BSD3-style (see LICENSE)+--+-- Maintainer  :  allbery.b@gmail.com+-- Stability   :  unstable+-- Portability :  not portable+--+-- Module to apply a ManageHook to an already-mapped window when a property+-- changes. This would commonly be used to match browser windows by title,+-- since the final title will only be set after (a) the window is mapped,+-- (b) its document has been loaded, (c) all load-time scripts have run.+-- (Don't blame browsers for this; it's inherent in HTML and the DOM. And+-- changing title dynamically is explicitly permitted by ICCCM and EWMH;+-- you don't really want to have your editor window umapped/remapped to+-- show the current document and modified state in the titlebar, do you?)+--+-- This is a handleEventHook that triggers on a PropertyChange event. It+-- currently ignores properties being removed, in part because you can't+-- do anything useful in a ManageHook involving nonexistence of a property.+--+-- This module could also be useful for Electron applications like Spotify+-- which sets its WM_CLASS too late for window manager to map it properly.+--+-----------------------------------------------------------------------------++module XMonad.Hooks.OnPropertyChange (+  -- * Usage+  -- $usage+  onXPropertyChange,+  onTitleChange,+  onClassChange,+) where++import XMonad+import XMonad.Prelude++-- $usage+-- You can use this module with the following in your @xmonad.hs@:+--+-- > import XMonad.Hooks.DynamicProperty+--+-- Enable it by including in you handleEventHook definition:+--+-- >  main = xmonad $ def+-- >      { ...+-- >      , handleEventHook = onXPropertyChange "WM_NAME" (title =? "Spotify" --> doShift "5"))+-- >      , ...+-- >      }+--+-- Or you could create a dynamicManageHook as below:+--+-- > myDynamicManageHook :: ManageHook+-- > myDynamicManageHook =+-- >  composeAll+-- >    [ className =? "Spotify" --> doShift (myWorkspaces !! 4),+-- >      title =? "maybe_special_terminal" <||> title =? "special_terminal" --> doCenterFloat,+-- >      className =? "dynamicApp" <&&> title =? "dynamic_app" --> doCenterFloat+-- >    ]+--+-- And then use it in your handleEventHookDefinition:+--+-- >  main = xmonad $ def+-- >      { ...+-- >      , handleEventHook = onXPropertyChange "WM_NAME" myDynamicManageHook+-- >      , ...+-- >      }+--++-- |+-- Run a 'ManageHook' when a specific property is changed on a window. Note+-- that this will run on any window which changes the property, so you should+-- be very specific in your 'ManageHook' matching (lots of windows change+-- their titles on the fly!):+--+-- > onXPropertyChange "WM_NAME" (className =? "Iceweasel" <&&> title =? "whatever" --> doShift "2")+--+-- Note that the fixity of (-->) won't allow it to be mixed with ($), so you+-- can't use the obvious $ shorthand.+--+-- > onXPropertyChange "WM_NAME" $ title =? "Foo" --> doFloat -- won't work!+--+-- Consider instead phrasing it like any+-- other 'ManageHook':+--+-- >  main = xmonad $ def+-- >      { ...+-- >      , handleEventHook = onXPropertyChange "WM_NAME" myDynHook+-- >      , ...+-- >      }+-- >+-- >    myDynHook = composeAll [...]+--+onXPropertyChange :: String -> ManageHook -> Event -> X All+onXPropertyChange prop hook PropertyEvent { ev_window = w, ev_atom = a, ev_propstate = ps } = do+  pa <- getAtom prop+  when (ps == propertyNewValue && a == pa) $ do+    g <- appEndo <$> userCodeDef (Endo id) (runQuery hook w)+    windows g+  return mempty -- so anything else also processes it+onXPropertyChange _ _ _ = return mempty++-- | A shorthand for dynamic titles; i.e., applications changing their+-- @WM_NAME@ property.+onTitleChange :: ManageHook -> Event -> X All+-- strictly, this should also check _NET_WM_NAME. practically, both will+-- change and each gets its own PropertyEvent, so we'd need to record that+-- we saw the event for that window and ignore the second one. Instead, just+-- trust that nobody sets only _NET_WM_NAME. (I'm sure this will prove false,+-- since there's always someone who can't bother being compliant.)+onTitleChange = onXPropertyChange "WM_NAME"++-- | A shorthand for dynamic resource and class names; i.e.,+-- applications changing their @WM_CLASS@ property.+onClassChange :: ManageHook -> Event -> X All+onClassChange = onXPropertyChange "WM_CLASS"
XMonad/Hooks/Place.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE TupleSections #-} ----------------------------------------------------------------------------- -- | -- Module      :  XMonad.Hooks.Place@@ -50,7 +51,7 @@ -- floating windows at appropriate positions on the screen, as well -- as an 'X' action to manually trigger repositioning. ----- You can use this module by including the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module by including the following in your @xmonad.hs@: -- -- > import XMonad.Hooks.Place --@@ -185,21 +186,22 @@                         -- spawned. Each of them also needs an associated screen                         -- rectangle; for hidden workspaces, we use the current                         -- workspace's screen.-                      let infos = filter ((window `elem`) . stackContents . S.stack . fst)+                      let infos = find ((window `elem`) . stackContents . S.stack . fst)                                      $ [screenInfo $ S.current theWS]                                         ++ map screenInfo (S.visible theWS)-                                        ++ zip (S.hidden theWS) (repeat currentRect)--                      guard(not $ null infos)+                                        ++ map (, currentRect) (S.hidden theWS) -                      let (workspace, screen) = head infos-                          rs = mapMaybe (`M.lookup` allRs)-                               $ organizeClients workspace window floats-                          r' = purePlaceWindow p screen rs pointer r-                          newRect = r2rr screen r'-                          newFloats = M.insert window newRect (S.floating theWS)+                      case infos of+                        Nothing   -> empty+                        Just info -> do+                          let (workspace, screen) = info+                              rs = mapMaybe (`M.lookup` allRs)+                                   $ organizeClients workspace window floats+                              r' = purePlaceWindow p screen rs pointer r+                              newRect = r2rr screen r'+                              newFloats = M.insert window newRect (S.floating theWS) -                      return $ theWS { S.floating = newFloats }+                          return $ theWS { S.floating = newFloats }   placeWindow :: Placement -> Window
XMonad/Hooks/PositionStoreHooks.hs view
@@ -45,7 +45,7 @@ import qualified Data.Set as S  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Hooks.PositionStoreHooks --
XMonad/Hooks/Rescreen.hs view
@@ -32,7 +32,7 @@ -- ('XMonad.Hooks.StatusBar.dynamicSBs' uses this module internally), as well -- as to actually invoke xrandr or autorandr when an output is (dis)connected. ----- To use this, include the following in your @~\/.xmonad\/xmonad.hs@:+-- To use this, include the following in your @xmonad.hs@: -- -- > import XMonad.Hooks.Rescreen --
− XMonad/Hooks/RestoreMinimized.hs
@@ -1,42 +0,0 @@--------------------------------------------------------------------------------- |--- Module      :  XMonad.Hooks.RestoreMinimized--- Description :  Deprecated: Use XMonad.Hooks.Minimize.--- Copyright   :  (c) Jan Vornberger 2009--- License     :  BSD3-style (see LICENSE)------ Maintainer  :  jan.vornberger@informatik.uni-oldenburg.de--- Stability   :  unstable--- Portability :  not portable------ (Deprecated: Use XMonad.Hooks.Minimize) Lets you restore minimized--- windows (see "XMonad.Layout.Minimize") by selecting them on a--- taskbar (listens for _NET_ACTIVE_WINDOW and WM_CHANGE_STATE).-----------------------------------------------------------------------------------module XMonad.Hooks.RestoreMinimized-    {-# DEPRECATED "Use XMonad.Hooks.Minimize instead, this module has no effect" #-}-    ( -- * Usage-      -- $usage-      RestoreMinimized (..)-    , restoreMinimizedEventHook-    ) where--import XMonad.Prelude--import XMonad---- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:------ > import XMonad.Hooks.RestoreMinimized--- >--- > myHandleEventHook = restoreMinimizedEventHook--- >--- > main = xmonad def { handleEventHook = myHandleEventHook }--data RestoreMinimized = RestoreMinimized deriving ( Show, Read )--restoreMinimizedEventHook :: Event -> X All-restoreMinimizedEventHook _ = return (All True)
XMonad/Hooks/ServerMode.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE MultiWayIf #-} ----------------------------------------------------------------------------- -- | -- Module      :  XMonad.Hooks.ServerMode@@ -35,7 +36,7 @@  -- $usage -- You can use this module with the following in your--- @~\/.xmonad\/xmonad.hs@:+-- @xmonad.hs@: -- -- > import XMonad.Hooks.ServerMode --@@ -89,13 +90,14 @@ -- serverModeEventHookF :: String -> (String -> X ()) -> Event -> X All serverModeEventHookF key func ClientMessageEvent {ev_message_type = mt, ev_data = dt} = do-        d <- asks display-        atm <- io $ internAtom d key False-        when (mt == atm && dt /= []) $ do-         let atom = fromIntegral (head dt)+  d <- asks display+  atm <- io $ internAtom d key False+  if | mt == atm, Just dth <- listToMaybe dt -> do+         let atom = fromIntegral dth          cmd <- io $ getAtomName d atom          case cmd of-              Just command -> func command-              Nothing -> io $ hPutStrLn stderr ("Couldn't retrieve atom " ++ show atom)-        return (All True)+           Just command -> func command+           Nothing -> io $ hPutStrLn stderr ("Couldn't retrieve atom " ++ show atom)+     | otherwise -> pure ()+  return (All True) serverModeEventHookF _ _ _ = return (All True)
XMonad/Hooks/SetWMName.hs view
@@ -12,10 +12,10 @@ -- Sets the WM name to a given string, so that it could be detected using -- _NET_SUPPORTING_WM_CHECK protocol. ----- May be useful for making Java GUI programs work, just set WM name to "LG3D"+-- May be useful for making Java GUI programs work, just set WM name to \"LG3D\" -- and use Java 1.6u1 (1.6.0_01-ea-b03 works for me) or later. ----- To your @~\/.xmonad\/xmonad.hs@ file, add the following line:+-- To your @xmonad.hs@ file, add the following line: -- -- > import XMonad.Hooks.SetWMName --@@ -33,7 +33,7 @@ -- fails miserably by guessing absolutely bogus values. -- -- For detailed instructions on editing your hooks, see--- "XMonad.Doc.Extending#4".+-- <https://xmonad.org/TUTORIAL.html the tutorial> and "XMonad.Doc.Extending". -----------------------------------------------------------------------------  module XMonad.Hooks.SetWMName (
XMonad/Hooks/ShowWName.hs view
@@ -9,7 +9,7 @@ -- Maintainer  :  Tony Zorman <soliditsallgood@mailbox.org> -- -- Flash the names of workspaces name when switching to them.  This is a--- reimplementation of 'XMonad.Layout.ShowWName' as a logHook.+-- reimplementation of "XMonad.Layout.ShowWName" as a logHook. -----------------------------------------------------------------------------  module XMonad.Hooks.ShowWName (@@ -33,7 +33,7 @@ {- $usage  You can use this module with the following in your-@~\/.xmonad\/xmonad.hs@:+@xmonad.hs@:  > import XMonad.Hooks.ShowWName >
XMonad/Hooks/StatusBar.hs view
@@ -56,6 +56,7 @@   spawnStatusBar,   killStatusBar,   killAllStatusBars,+  startAllStatusBars,   ) where  import Control.Exception (SomeException, try)@@ -81,7 +82,7 @@ import qualified XMonad.StackSet as W  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad -- > import XMonad.Hooks.StatusBar@@ -564,3 +565,9 @@ killAllStatusBars :: X () killAllStatusBars =   XS.gets (M.elems . getPIDs) >>= io . traverse_ killPid >> XS.put (StatusBarPIDs mempty)++-- | Start all status bars. Note that you do not need this in your startup hook.+-- This can be bound to a keybinding for example to be used in tandem with+-- `killAllStatusBars`.+startAllStatusBars :: X ()+startAllStatusBars = XS.get >>= traverse_ (sbStartupHook . snd) . getASBs
XMonad/Hooks/StatusBar/PP.hs view
@@ -32,6 +32,7 @@     -- * Build your own formatter     PP(..), def,     dynamicLogString,+    dynamicLogString',     dynamicLogWithPP,      -- * Predicates and formatters@@ -55,6 +56,8 @@     ) where  import Control.Monad.Reader+import Control.DeepSeq+import qualified Data.List.NonEmpty as NE  import XMonad import XMonad.Prelude@@ -181,8 +184,15 @@ --   allow for further processing, or use in some application other than --   a status bar. dynamicLogString :: PP -> X String-dynamicLogString pp = do+dynamicLogString pp = userCodeDef "_|_" (dynamicLogString' pp) +-- | The guts of 'dynamicLogString'. Forces the result, so it may throw+--   an exception (most commonly because 'ppOrder' is non-total). Use+--   'dynamicLogString' for a version that catches the exception and+--   produces an error string.+dynamicLogString' :: PP -> X String+dynamicLogString' pp = do+     winset <- gets windowset     urgents <- readUrgents     sort' <- ppSort pp@@ -199,7 +209,7 @@     -- window title     wt <- maybe (pure "") (fmap show . getName) . S.peek $ winset -    return $ sepBy (ppSep pp) . ppOrder pp $+    return $! force $ sepBy (ppSep pp) . ppOrder pp $                         [ ws                         , ppLayout pp ld                         , ppTitle  pp $ ppTitleSanitize pp wt@@ -392,7 +402,7 @@     strip keep x       | null x              = keep       | "^^" `isPrefixOf` x = strip (keep ++ "^") (drop 2 x)-      | '^' == head x       = strip keep (drop 1 . dropWhile (/= ')') $ x)+      | "^"  `isPrefixOf` x = strip keep (drop 1 . dropWhile (/= ')') $ x)       | otherwise           = let (good,x') = span (/= '^') x                               in strip (keep ++ good) x' @@ -448,17 +458,21 @@ xmobarRaw "" = "" xmobarRaw s  = concat ["<raw=", show $ length s, ":", s, "/>"] --- | Strip xmobar markup, specifically the <fc>, <icon> and <action> tags and--- the matching tags like </fc>.+-- | Strip xmobar markup, specifically the \<fc\>, \<icon\> and \<action\> tags+-- and the matching tags like \</fc\>. xmobarStrip :: String -> String xmobarStrip = converge (xmobarStripTags ["fc","icon","action"])  converge :: (Eq a) => (a -> a) -> a -> a-converge f a = let xs = iterate f a-    in fst $ head $ dropWhile (uncurry (/=)) $ zip xs $ tail xs+converge f a+  = fst . NE.head . notEmpty -- If this function terminates, we will find a match.+  . dropWhile (uncurry (/=))+  . zip xs+  $ drop 1 xs+ where xs = iterate f a  xmobarStripTags :: [String] -- ^ tags-        -> String -> String -- ^ with all <tag>...</tag> removed+        -> String -> String -- ^ with all \<tag\>...\</tag\> removed xmobarStripTags tags = strip [] where     strip keep [] = keep     strip keep x
XMonad/Hooks/StatusBar/WorkspaceScreen.hs view
@@ -34,7 +34,7 @@ import qualified XMonad.StackSet               as W  {- $usage- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+ You can use this module with the following in your @xmonad.hs@:   > import XMonad  > import XMonad.Hooks.StatusBar
XMonad/Hooks/ToggleHook.hs view
@@ -77,7 +77,7 @@ -- This module provides actions (that can be set as keybindings) -- to be able to cause hooks to be occur on a conditional basis. ----- You can use it by including the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use it by including the following in your @xmonad.hs@: -- -- > import XMonad.Hooks.ToggleHook --
XMonad/Hooks/UrgencyHook.hs view
@@ -242,8 +242,8 @@ -- -- The interval arguments are in seconds. See the 'minutes' helper. data RemindWhen = Dont                    -- ^ triggering once is enough-                | Repeatedly Int Interval -- ^ repeat <arg1> times every <arg2> seconds-                | Every Interval          -- ^ repeat every <arg1> until the urgency hint is cleared+                | Repeatedly Int Interval -- ^ repeat \<arg1\> times every \<arg2\> seconds+                | Every Interval          -- ^ repeat every \<arg1\> until the urgency hint is cleared                 deriving (Read, Show)  -- | A prettified way of multiplying by 60. Use like: @(5 `minutes`)@.
XMonad/Hooks/WallpaperSetter.hs view
@@ -140,7 +140,7 @@   direxists <- doesDirectoryExist $ wallpaperBaseDir conf </> dir   if direxists     then do files <- getDirectoryContents $ wallpaperBaseDir conf </> dir-            let files' = filter ((/='.').head) files+            let files' = filter (not . ("." `isPrefixOf`)) files             file <- pickFrom files'             return $ Just $ wallpaperBaseDir conf </> dir </> file     else return Nothing
XMonad/Hooks/WindowSwallowing.hs view
@@ -54,7 +54,7 @@ import           System.Posix.Types             ( ProcessID )  -- $usage--- You can use this module by including  the following in your @~\/.xmonad/xmonad.hs@:+-- You can use this module by including  the following in your @xmonad.hs@: -- -- > import XMonad.Hooks.WindowSwallowing --@@ -62,11 +62,11 @@ -- -- > myHandleEventHook = swallowEventHook (className =? "Alacritty" <||> className =? "Termite") (return True) ----- The variant 'swallowEventHookSub' can be used if a layout from "XMonad.Layouts.SubLayouts" is used;+-- The variant 'swallowEventHookSub' can be used if a layout from "XMonad.Layout.SubLayouts" is used; -- instead of swallowing the window it will merge the child window with the parent. (this does not work with floating windows) -- -- For more information on editing your handleEventHook and key bindings,--- see "XMonad.Doc.Extending".+-- see <https://xmonad.org/TUTORIAL.html the tutorial> and "XMonad.Doc.Extending".  -- | Run @action@ iff both parent- and child queries match and the child -- is a child by PID.@@ -98,7 +98,7 @@       return ()  -- | handleEventHook that will merge child windows via--- "XMonad.Layouts.SubLayouts" when they are opened from another window.+-- "XMonad.Layout.SubLayouts" when they are opened from another window. swallowEventHookSub   :: Query Bool -- ^ query the parent window has to match for window swallowing to occur.                 --   Set this to @return True@ to run swallowing for every parent.
XMonad/Hooks/WorkspaceByPos.hs view
@@ -26,10 +26,11 @@ import XMonad.Prelude import qualified XMonad.StackSet as W -import Control.Monad.Except (lift, runExceptT, throwError)+import Control.Monad.Except (runExceptT, throwError)+import Control.Monad.Trans (lift)  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Hooks.WorkspaceByPos -- >
XMonad/Hooks/WorkspaceHistory.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE DerivingVia #-} ----------------------------------------------------------------------------- -- | -- Module      :  XMonad.Hooks.WorkspaceHistory@@ -33,12 +34,12 @@ import Prelude import XMonad import XMonad.StackSet hiding (delete, filter, new)-import XMonad.Prelude (delete, find, foldl', groupBy, nub, sortBy)+import XMonad.Prelude (delete, find, foldl', groupBy, nub, sortBy, listToMaybe) import qualified XMonad.Util.ExtensibleState as XS  -- $usage -- To record the order in which you view workspaces, you can use this--- module with the following in your @~\/.xmonad\/xmonad.hs@:+-- module with the following in your @xmonad.hs@: -- -- > import XMonad.Hooks.WorkspaceHistory (workspaceHistoryHook) --@@ -63,14 +64,9 @@ newtype WorkspaceHistory = WorkspaceHistory   { history :: [(ScreenId, WorkspaceId)] -- ^ Workspace Screens in                                          -- reverse-chronological order.-  } deriving (Read, Show)---- @ScreenId@ is not an instance of NFData, but is a newtype on @Int@. @seq@--- is enough for forcing it. This requires us to provide an instance.-instance NFData WorkspaceHistory where-  rnf (WorkspaceHistory hist) =-    let go = liftRnf2 rwhnf rwhnf-    in liftRnf go hist+  }+  deriving (Read, Show)+  deriving NFData via [(Int, WorkspaceId)]  instance ExtensionClass WorkspaceHistory where     initialValue = WorkspaceHistory []@@ -94,7 +90,7 @@  workspaceHistoryByScreen :: X [(ScreenId, [WorkspaceId])] workspaceHistoryByScreen =-  map (\wss -> (fst $ head wss, map snd wss)) .+  map (\wss -> (maybe 0 fst (listToMaybe wss), map snd wss)) .   groupBy (\a b -> fst a == fst b) .   sortBy (\a b -> compare (fst a) $ fst b)<$>   workspaceHistoryWithScreen
XMonad/Hooks/XPropManage.hs view
@@ -26,7 +26,7 @@ import XMonad.Prelude (Endo (..), chr)  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Hooks.XPropManage -- > import qualified XMonad.StackSet as W
XMonad/Layout/Accordion.hs view
@@ -25,7 +25,7 @@ import Data.Ratio  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Layout.Accordion --@@ -34,9 +34,9 @@ -- > myLayout = Accordion ||| Full ||| etc.. -- > main = xmonad def { layoutHook = myLayout } ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook".  data Accordion a = Accordion deriving ( Read, Show ) 
XMonad/Layout/AvoidFloats.hs view
@@ -35,7 +35,7 @@ import qualified Data.Set as S  -- $usage--- You can use this module with the following in your ~\/.xmonad\/xmonad.hs file:+-- You can use this module with the following in your @xmonad.hs@ file: -- -- > import XMonad.Layout.AvoidFloats --@@ -44,8 +44,9 @@ -- -- > layoutHook = ... ||| avoidFloats Full ||| ... ----- For more detailed instructions on editing the layoutHook see:--- "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook". -- -- Then add appropriate key bindings, for example: --@@ -54,7 +55,7 @@ -- > ,((modm .|. shiftMask .|. controlMask, xK_b), sendMessage (AvoidFloatSet False) >> sendMessage AvoidFloatClearItems) -- -- For detailed instructions on editing your key bindings, see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>. -- -- Note that this module is incompatible with an old way of configuring -- "XMonad.Actions.FloatSnap". If you are having problems, please update your
XMonad/Layout/BinaryColumn.hs view
@@ -14,7 +14,7 @@ -- Each window is half the height of the previous, -- except for the last pair of windows. ----- Note: Originally based on 'XMonad.Layout.Column' with changes:+-- Note: Originally based on "XMonad.Layout.Column" with changes: -- -- * Adding/removing windows doesn't resize all other windows. -- (last window pair exception).
XMonad/Layout/BinarySpacePartition.hs view
@@ -52,7 +52,7 @@ import Data.Ratio ((%))  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Layout.BinarySpacePartition --
XMonad/Layout/BorderResize.hs view
@@ -24,6 +24,7 @@     ( -- * Usage       -- $usage       borderResize+    , borderResizeNear     , BorderResize (..)     , RectWithBorders, BorderInfo,     ) where@@ -37,7 +38,7 @@  -- $usage -- You can use this module with the following in your--- @~\/.xmonad\/xmonad.hs@:+-- @xmonad.hs@: -- -- > import XMonad.Layout.BorderResize -- > myLayout = borderResize (... layout setup that reacts to SetGeometry ...)@@ -58,27 +59,34 @@  type RectWithBorders = (Rectangle, [BorderInfo]) -newtype BorderResize a = BR (M.Map Window RectWithBorders) deriving (Show, Read)--brBorderSize :: Dimension-brBorderSize = 2+data BorderResize a = BR+  { brBorderSize  :: !Dimension+  -- ^ Still resize when this number of pixels around the border.+  , brWrsLastTime :: !(M.Map Window RectWithBorders)+  }+  deriving (Show, Read)  borderResize :: l a -> ModifiedLayout BorderResize l a-borderResize = ModifiedLayout (BR M.empty)+borderResize = borderResizeNear 2 +-- | Like 'borderResize', but takes the number of pixels near the border+-- up to which dragging still resizes a window.+borderResizeNear :: Dimension -> l a -> ModifiedLayout BorderResize l a+borderResizeNear borderSize = ModifiedLayout (BR borderSize M.empty)+ instance LayoutModifier BorderResize Window where     redoLayout _       _ Nothing  wrs = return (wrs, Nothing)-    redoLayout (BR wrsLastTime) _ _ wrs = do+    redoLayout (BR borderSize wrsLastTime) _ _ wrs = do             let correctOrder = map fst wrs                 wrsCurrent = M.fromList wrs                 wrsGone = M.difference wrsLastTime wrsCurrent                 wrsAppeared = M.difference wrsCurrent wrsLastTime                 wrsStillThere = M.intersectionWith testIfUnchanged wrsLastTime wrsCurrent             handleGone wrsGone-            wrsCreated <- handleAppeared wrsAppeared-            let wrsChanged = handleStillThere wrsStillThere+            wrsCreated <- handleAppeared borderSize wrsAppeared+            let wrsChanged = handleStillThere borderSize wrsStillThere                 wrsThisTime = M.union wrsChanged wrsCreated-            return (compileWrs wrsThisTime correctOrder, Just $ BR wrsThisTime)+            return (compileWrs wrsThisTime correctOrder, Just $ BR borderSize wrsThisTime)             -- What we return is the original wrs with the new border             -- windows inserted at the correct positions - this way, the core             -- will restack the borders correctly.@@ -91,11 +99,11 @@                     then (Nothing, entry)                     else (Just rCurrent, entry) -    handleMess (BR wrsLastTime) m+    handleMess (BR borderSize wrsLastTime) m         | Just e <- fromMessage m :: Maybe Event =             handleResize (createBorderLookupTable wrsLastTime) e >> return Nothing         | Just _ <- fromMessage m :: Maybe LayoutMessages =-            handleGone wrsLastTime >> return (Just $ BR M.empty)+            handleGone wrsLastTime >> return (Just $ BR borderSize M.empty)     handleMess _ _ = return Nothing  compileWrs :: M.Map Window RectWithBorders -> [Window] -> [(Window, Rectangle)]@@ -112,26 +120,26 @@     where         borderWins = map bWin . concatMap snd . M.elems $ wrsGone -handleAppeared :: M.Map Window Rectangle -> X (M.Map Window RectWithBorders)-handleAppeared wrsAppeared = do+handleAppeared :: Dimension -> M.Map Window Rectangle -> X (M.Map Window RectWithBorders)+handleAppeared borderSize wrsAppeared = do     let wrs = M.toList wrsAppeared-    wrsCreated <- mapM handleSingleAppeared wrs+    wrsCreated <- mapM (handleSingleAppeared borderSize) wrs     return $ M.fromList wrsCreated -handleSingleAppeared :: (Window, Rectangle) -> X (Window, RectWithBorders)-handleSingleAppeared (w, r) = do-    let borderBlueprints = prepareBorders r+handleSingleAppeared :: Dimension ->(Window, Rectangle) -> X (Window, RectWithBorders)+handleSingleAppeared borderSize (w, r) = do+    let borderBlueprints = prepareBorders borderSize r     borderInfos <- mapM createBorder borderBlueprints     return (w, (r, borderInfos)) -handleStillThere :: M.Map Window (Maybe Rectangle, RectWithBorders) -> M.Map Window RectWithBorders-handleStillThere = M.map handleSingleStillThere+handleStillThere :: Dimension -> M.Map Window (Maybe Rectangle, RectWithBorders) -> M.Map Window RectWithBorders+handleStillThere borderSize = M.map (handleSingleStillThere borderSize) -handleSingleStillThere :: (Maybe Rectangle, RectWithBorders) -> RectWithBorders-handleSingleStillThere (Nothing, entry) = entry-handleSingleStillThere (Just rCurrent, (_, borderInfos)) = (rCurrent, updatedBorderInfos)+handleSingleStillThere :: Dimension -> (Maybe Rectangle, RectWithBorders) -> RectWithBorders+handleSingleStillThere _            (Nothing, entry)                  = entry+handleSingleStillThere borderSize (Just rCurrent, (_, borderInfos)) = (rCurrent, updatedBorderInfos)     where-        changedBorderBlueprints = prepareBorders rCurrent+        changedBorderBlueprints = prepareBorders borderSize rCurrent         updatedBorderInfos = zipWith (curry updateBorderInfo) borderInfos changedBorderBlueprints           -- assuming that the four borders are always in the same order @@ -144,12 +152,12 @@         processSingleEntry :: (Window, RectWithBorders) -> [(Window, (BorderType, Window, Rectangle))]         processSingleEntry (w, (r, borderInfos)) = for borderInfos $ \bi -> (bWin bi, (bType bi, w, r)) -prepareBorders :: Rectangle -> [BorderBlueprint]-prepareBorders (Rectangle x y wh ht) =-    [(Rectangle (x + fi wh - fi brBorderSize) y brBorderSize ht, xC_right_side , RightSideBorder),-     (Rectangle x y brBorderSize ht                            , xC_left_side  , LeftSideBorder),-     (Rectangle x y wh brBorderSize                            , xC_top_side   , TopSideBorder),-     (Rectangle x (y + fi ht - fi brBorderSize) wh brBorderSize, xC_bottom_side, BottomSideBorder)+prepareBorders :: Dimension -> Rectangle -> [BorderBlueprint]+prepareBorders borderSize (Rectangle x y wh ht) =+    [(Rectangle (x + fi wh - fi borderSize) y borderSize ht, xC_right_side , RightSideBorder),+     (Rectangle x y borderSize ht                          , xC_left_side  , LeftSideBorder),+     (Rectangle x y wh borderSize                          , xC_top_side   , TopSideBorder),+     (Rectangle x (y + fi ht - fi borderSize) wh borderSize, xC_bottom_side, BottomSideBorder)     ]  handleResize :: [(Window, (BorderType, Window, Rectangle))] -> Event -> X ()
XMonad/Layout/BoringWindows.hs view
@@ -45,7 +45,7 @@  -- $usage -- You can use this module with the following in your--- @~\/.xmonad\/xmonad.hs@:+-- @xmonad.hs@: -- -- > import XMonad.Layout.BoringWindows --@@ -60,9 +60,9 @@ -- > , ((modm, xK_k), focusDown) -- > , ((modm, xK_m), focusMaster) ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook".   data BoringMessage = FocusUp | FocusDown | FocusMaster | IsBoring Window | ClearBoring@@ -93,7 +93,7 @@ siftDown = sendMessage UpdateBoring >> sendMessage SiftDown  -- | Mark current focused window boring for all layouts.--- This is useful in combination with the 'XMonad.Actions.CopyWindow' module.+-- This is useful in combination with the "XMonad.Actions.CopyWindow" module. markBoringEverywhere :: X () markBoringEverywhere = withFocused (broadcastMessage . IsBoring) 
XMonad/Layout/ButtonDecoration.hs view
@@ -33,7 +33,7 @@  -- $usage -- You can use this module with the following in your--- @~\/.xmonad\/xmonad.hs@:+-- @xmonad.hs@: -- -- > import XMonad.Layout.DecorationAddons -- > import XMonad.Layout.ButtonDecoration
+ XMonad/Layout/CenterMainFluid.hs view
@@ -0,0 +1,98 @@+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}++-----------------------------------------------------------------------------+-- |+-- Module      :  XMonad.Layout.CenterMainFluid+-- Description :  Three column layout with master in center and unoccupied spaces reserved.+-- Copyright   :  (c) 2023 Mahdi Seyedan+-- License     :  BSD-style (see xmonad/LICENSE)+--+-- Maintainer  :  Mahdi Seyedan. <mahdisn78@gmail.com>+-- Stability   :  unstable+-- Portability :  unportable+--+-- A three column layout with main column in the center and+-- two stack columns surrounding it. There will be always+-- a pane in the center column and unoccupied spaces on the+-- sides are reserved.+-- It's best suited for ultrawide montiors, where a single+-- stretched window might be annoying.+-----------------------------------------------------------------------------++module XMonad.Layout.CenterMainFluid+  ( -- * Usage+    -- $usage+    CenterMainFluid (..)+  ) where++import XMonad+import qualified XMonad.StackSet as W+import Control.Monad (msum)++-- $usage+-- You can use this module by adding following in your @xmonad.hs@:+--+-- > import XMonad.Layout.CenterMainFluid+--+-- Then edit your @layoutHook@ by adding the CenterMainFluid layout:+--+-- > myLayoutHook = CenterMainFluid 1 (3/100) (70/100) ||| ...+-- > main = xmonad def { layoutHook = myLayout }+--+-- The first argument specifies how many windows initially appear in the center+-- column. The second argument specifies the amount to resize while resizing+-- and the third argument specifies the initial size of the center column.+--+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook".+++-- | Arguments are nmaster, delta, fraction. Supports 'Shrink', 'Expand' and+-- 'IncMasterN'+data CenterMainFluid a = CenterMainFluid+  { cmfNMaster :: !Int             -- ^ The default number of windows in the center pane (default: 1)+  , cmfRatioIncrement :: !Rational -- ^ Percent of screen to increment by when resizing panes (default: 3/100)+  , cmfRatio :: !Rational          -- ^ Default proportion of screen occupied by the center pane (default: 70/100)+  }+  deriving (Show,Read)++instance LayoutClass CenterMainFluid a where++    pureLayout (CenterMainFluid nmaster _ frac) r s+        | frac == 0 = drop nmaster layout+        | frac == 1 = take nmaster layout+        | otherwise = layout+      where layout = zip ws rs+            ws = W.integrate s+            rs = tile3 frac r nmaster (length ws)++    pureMessage (CenterMainFluid nmaster delta frac) m =+            msum [fmap resize     (fromMessage m)+                 ,fmap incmastern (fromMessage m)]++      where resize Shrink             = CenterMainFluid nmaster delta (max 0 $ frac-delta)+            resize Expand             = CenterMainFluid nmaster delta (min 1 $ frac+delta)+            incmastern (IncMasterN d) = CenterMainFluid (max 0 (nmaster+d)) delta frac++    description _ = "CenterMainFluid"++tile3 :: Rational -> Rectangle -> Int -> Int -> [Rectangle]+tile3 f r nmaster n+  | nmaster <= 0 || n <= nmaster = splitVertically n middleR+  | otherwise = masters ++ rights ++ lefts+      where (leftR, middleR, rightR) = split3HorizontallyBy f r+            (halfN, remaining) = (n - nmaster) `divMod` 2+            masters = splitVertically nmaster middleR+            lefts = splitVertically halfN leftR+            rights = splitVertically (halfN + remaining) rightR++-- | Divide the screen into three rectangles, using a rational to specify the ratio of center one+split3HorizontallyBy :: RealFrac r => r -> Rectangle -> (Rectangle, Rectangle, Rectangle)+split3HorizontallyBy f (Rectangle sx sy sw sh) =+  ( Rectangle sx sy sidew sh+  , Rectangle (sx + fromIntegral sidew) sy middlew sh+  , Rectangle (sx + fromIntegral sidew + fromIntegral middlew) sy sidew sh+  )+  where middlew = floor $ fromIntegral sw * f+        sidew = (sw - fromIntegral middlew) `div` 2
XMonad/Layout/CenteredIfSingle.hs view
@@ -30,7 +30,7 @@ import XMonad.Prelude (fi)  -- $usage--- You can use this module by including  the following in your @~\/.xmonad/xmonad.hs@:+-- You can use this module by including  the following in your @xmonad.hs@: -- -- > import XMonad.Layout.CenteredIfSingle --@@ -38,7 +38,9 @@ -- -- > myLayoutHook = centeredIfSingle 0.7 0.8 Grid ||| ... ----- For more information on configuring your layouts see "XMonad.Doc.Extending".+-- For more information on configuring your layouts see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>+-- and "XMonad.Doc.Extending".   -- | Layout Modifier that places a window in the center of the screen,
XMonad/Layout/CenteredMaster.hs view
@@ -80,11 +80,9 @@ applyPosition pos wksp rect = do   let stack = W.stack wksp   let ws = W.integrate' stack-  if null ws then-     runLayout wksp rect-     else do-       let firstW = head ws-       let other  = tail ws+  case ws of+    []               -> runLayout wksp rect+    (firstW : other) -> do        let filtStack = stack >>= W.filter (firstW /=)        wrs <- runLayout (wksp {W.stack = filtStack}) rect        return $ first ((firstW, place pos other rect) :) wrs
XMonad/Layout/Circle.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}+{-# LANGUAGE PatternSynonyms #-}  ----------------------------------------------------------------------------- -- |@@ -15,18 +16,17 @@ -- ----------------------------------------------------------------------------- -module XMonad.Layout.Circle (-                             -- * Usage-                             -- $usage-                             Circle (..)-                            ) where -- actually it's an ellipse+module XMonad.Layout.Circle {-# DEPRECATED "Use XMonad.Layout.CircleEx instead" #-}+  ( -- * Usage+    -- $usage+    pattern Circle+  ) where -- actually it's an ellipse -import XMonad.Prelude-import XMonad-import XMonad.StackSet (integrate, peek)+import GHC.Real (Ratio(..))+import XMonad.Layout.CircleEx  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Layout.Circle --@@ -35,41 +35,10 @@ -- > myLayout = Circle ||| Full ||| etc.. -- > main = xmonad def { layoutHook = myLayout } ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"--data Circle a = Circle deriving ( Read, Show )--instance LayoutClass Circle Window where-    doLayout Circle r s = do layout <- raiseFocus $ circleLayout r $ integrate s-                             return (layout, Nothing)--circleLayout :: Rectangle -> [a] -> [(a, Rectangle)]-circleLayout _ []     = []-circleLayout r (w:ws) = master : rest-    where master = (w, center r)-          rest   = zip ws $ map (satellite r) [0, pi * 2 / fromIntegral (length ws) ..]--raiseFocus :: [(Window, Rectangle)] -> X [(Window, Rectangle)]-raiseFocus xs = do focused <- withWindowSet (return . peek)-                   return $ case find ((== focused) . Just . fst) xs of-                              Just x  -> x : delete x xs-                              Nothing -> xs+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook". -center :: Rectangle -> Rectangle-center (Rectangle sx sy sw sh) = Rectangle x y w h-    where s = sqrt 2 :: Double-          w = round (fromIntegral sw / s)-          h = round (fromIntegral sh / s)-          x = sx + fromIntegral (sw - w) `div` 2-          y = sy + fromIntegral (sh - h) `div` 2+pattern Circle :: CircleEx a+pattern Circle = CircleEx 1 (70 :% 99) (2 :% 5) 1 0 -satellite :: Rectangle -> Double -> Rectangle-satellite (Rectangle sx sy sw sh) a = Rectangle (sx + round (rx + rx * cos a))-                                                (sy + round (ry + ry * sin a))-                                                w h-    where rx = fromIntegral (sw - w) / 2-          ry = fromIntegral (sh - h) / 2-          w = sw * 10 `div` 25-          h = sh * 10 `div` 25
+ XMonad/Layout/CircleEx.hs view
@@ -0,0 +1,189 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE InstanceSigs #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE RecordWildCards #-}+-----------------------------------------------------------------------------+-- |+-- Module      :  XMonad.Layout.CircleEx+-- Description :  An elliptical, overlapping layout—extended version.+-- Copyright   :  (c) Peter De Wachter, Ilya V. Portnov+-- License     :  BSD-style (see LICENSE)+--+-- Maintainer  :  Ilya V. Portnov <portnov84@rambler.ru>+-- Stability   :  unstable+-- Portability :  unportable+--+-- Circle is an elliptical, overlapping layout. Original code by Peter De Wachter,+-- extended by Ilya Porntov.+-----------------------------------------------------------------------------++module XMonad.Layout.CircleEx (+    -- * Usage+    -- $usage+    CircleEx (..), circle, circleEx,+    CircleExMsg (..)+  )+  where++import Data.Ratio++import XMonad+import XMonad.StackSet (Stack)+import XMonad.Prelude+import qualified XMonad.StackSet as W++-- $usage+--+-- The layout puts the first N windows (called master) into the center of+-- screen. All others (called secondary, or stack) are organized in a circle+-- (well, ellipse). When opening a new secondary window, its size will be+-- slightly smaller than that of its predecessor (this is configurable). If+-- the number of master windows is set to zero, all windows will be arranged+-- in a circle. If there is more than one master window, they will be stacked+-- in the center on top of each other. The size of each additional master+-- window will again be slightly smaller than that of the former.+--+-- Since a picture says more than a thousand words, you see one+-- <https://github.com/xmonad/xmonad-contrib/assets/50166980/90ef1273-5201-4380-8b94-9e62d3c98e1c here>.+--+-- You can use this module with the following in your @xmonad.hs@:+--+-- > import XMonad.Layout.CircleEx+--+-- Then edit your @layoutHook@ by adding the 'CircleEx' layout:+--+-- > myCircle = circleEx {cDelta = -3*pi/4}+-- > myLayout = myCircle ||| Full ||| etc..+-- > main = xmonad def { layoutHook = myLayout }+--+-- This layout understands standard messages:+--+-- * 'IncMasterN': increase or decrease the number of master windows.+-- * 'Shrink' and 'Expand': change the size of master windows.+--+-- More layout-specific messages are also supported, see 'CircleExMsg' below.+--+-- For more detailed instructions on editing the layoutHook see:+-- "XMonad.Doc.Extending#Editing_the_layout_hook"++-- | The layout data type. It is recommended to not use the 'CircleEx' data+-- constructor directly, and instead rely on record update syntax; for+-- example: @circleEx {cMasterRatio = 4%5}@. In this way you can avoid nasty+-- surprises if one day additional fields are added to @CircleEx@.+data CircleEx a = CircleEx+    { cNMaster :: !Int          -- ^ Number of master windows. Default value is 1.+    , cMasterRatio :: !Rational -- ^ Size of master window in relation to screen size.+                                --   Default value is @4%5@.+    , cStackRatio :: !Rational  -- ^ Size of first secondary window in relation to screen size.+                                --   Default value is @3%5@.+    , cMultiplier :: !Rational  -- ^ Coefficient used to calculate the sizes of subsequent secondary+                                --   windows. The size of the next window is calculated as the+                                --   size of the previous one multiplied by this value.+                                --   This value is also used to scale master windows, in case+                                --   there is more than one.+                                --   Default value is @5%6@. Set this to 1 if you want all secondary+                                --   windows to have the same size.+    , cDelta :: !Double         -- ^ Angle of rotation of the whole circle layout. Usual values+                                --   are from 0 to 2π, although it will work outside+                                --   this range as well. Default value of 0 means that the first+                                --   secondary window will be placed at the right side of screen.+    } deriving (Eq, Show, Read)++-- | Circle layout with default settings:+--+-- * Number of master windows is set to 1+-- * @cMasterRatio@ is set to @70/99@, which is nearly @1/sqrt(2)@+-- * @cStackRatio@ is set to @2/5@+-- * @cMultiplier@ is set to 1, which means all secondary windows+--   will have the same size+--+-- This can be used as a drop-in replacement for "XMonad.Layout.Circle".+circle :: CircleEx a+circle = CircleEx 1 (70%99) (2%5) 1 0++-- | Another variant of default settings for circle layout:+--+-- * Number of master windows is set to 1+-- * @cMasterRatio@ is set to @4/5@+-- * @cStackRatio@ is set to @3/5@+-- * @cMultiplier@ is set to @5/6@+--+circleEx :: CircleEx a+circleEx = CircleEx 1 (4%5) (3%5) (5%6) 0++-- | Specific messages understood by CircleEx layout.+data CircleExMsg+  = Rotate !Double            -- ^ Rotate secondary windows by specific angle+  | IncStackRatio !Rational   -- ^ Increase (or decrease, with negative value) sizes of secondary windows+  | IncMultiplier !Rational   -- ^ Increase 'cMultiplier'.+  deriving (Eq, Show, Typeable)++instance Message CircleExMsg++instance LayoutClass CircleEx Window where+  doLayout :: CircleEx Window -> Rectangle -> Stack Window -> X ([(Window, Rectangle)], Maybe (CircleEx Window))+  doLayout layout rect stack = do+    result <- raiseFocus $ circleLayout layout rect $ W.integrate stack+    return (result, Nothing)++  pureMessage :: CircleEx Window -> SomeMessage -> Maybe (CircleEx Window)+  pureMessage layout m =+      msum [changeMasterN <$> fromMessage m,+            resize <$> fromMessage m,+            specific <$> fromMessage m]+    where+      deltaSize = 11 % 10++      resize :: Resize -> CircleEx a+      resize Shrink = layout {cMasterRatio = max 0.1 $ min 1.0 $ cMasterRatio layout / deltaSize}+      resize Expand = layout {cMasterRatio = max 0.1 $ min 1.0 $ cMasterRatio layout * deltaSize}++      changeMasterN :: IncMasterN -> CircleEx a+      changeMasterN (IncMasterN d) = layout {cNMaster = max 0 (cNMaster layout + d)}++      specific :: CircleExMsg -> CircleEx a+      specific (Rotate delta) = layout {cDelta = delta + cDelta layout}+      specific (IncStackRatio delta) = layout {cStackRatio = max 0.1 $ min 2.0 $ delta + cStackRatio layout}+      specific (IncMultiplier delta) = layout {cMultiplier = max 0.1 $ min 2.0 $ delta + cMultiplier layout}++circleLayout :: CircleEx a -> Rectangle -> [a] -> [(a, Rectangle)]+circleLayout _ _ [] = []+circleLayout (CircleEx {..}) rectangle wins =+    master (take cNMaster wins) ++ rest (drop cNMaster wins)+  where+    master :: [a] -> [(a, Rectangle)]+    master ws = zip ws $ map (placeCenter cMasterRatio cMultiplier rectangle)+                           [cNMaster-1, cNMaster-2 .. 0]+    rest :: [a] -> [(a, Rectangle)]+    rest ws = zip ws $ zipWith (placeSatellite cStackRatio cMultiplier rectangle)+                        (map (+ cDelta) [0, pi*2 / fromIntegral (length ws) ..])+                        [0 ..]+++raiseFocus :: [(Window, Rectangle)] -> X [(Window, Rectangle)]+raiseFocus wrs = do+  focused <- withWindowSet (return . W.peek)+  return $ case find ((== focused) . Just . fst) wrs of+             Just x  -> x : delete x wrs+             Nothing -> wrs++placeCenter :: Rational -> Rational -> Rectangle -> Int -> Rectangle+placeCenter ratio multiplier (Rectangle x y width height) n = Rectangle x' y' width' height'+  where+    m = ratio * multiplier ^ n+    width' = round (m * fromIntegral width)+    height' = round (m * fromIntegral height)+    x' = x + fromIntegral (width - width') `div` 2+    y' = y + fromIntegral (height - height') `div` 2++placeSatellite :: Rational -> Rational -> Rectangle -> Double -> Int -> Rectangle+placeSatellite ratio multiplier (Rectangle x y width height) alpha n =+    Rectangle x' y' width' height'+  where+    m = ratio * multiplier ^ n+    x' = x + round (rx + rx * cos alpha)+    y' = y + round (ry + ry * sin alpha)+    rx = fromIntegral (width - width') / 2+    ry = fromIntegral (height - height') / 2+    width' = round (fromIntegral width * m)+    height' = round (fromIntegral height * m)
XMonad/Layout/Combo.hs view
@@ -1,5 +1,8 @@-{-# LANGUAGE FlexibleContexts, FlexibleInstances, MultiParamTypeClasses,-             UndecidableInstances, PatternGuards #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE PatternGuards #-}+{-# LANGUAGE UndecidableInstances #-}  ----------------------------------------------------------------------------- -- |@@ -24,13 +27,13 @@                            ) where  import XMonad hiding (focus)-import XMonad.Prelude (delete, fromMaybe, intersect, isJust, (\\))-import XMonad.StackSet ( integrate', Workspace (..), Stack(..) )-import XMonad.Layout.WindowNavigation ( MoveWindowToWindow(..) )-import qualified XMonad.StackSet as W ( differentiate )+import XMonad.Layout.WindowNavigation (MoveWindowToWindow (..))+import XMonad.Prelude (delete, fromMaybe, intersect, isJust, (\\), listToMaybe)+import XMonad.StackSet (Stack (..), Workspace (..), integrate')+import XMonad.Util.Stack (zipperFocusedAtFirstOf)  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Layout.Combo --@@ -40,9 +43,9 @@ -- -- to your layouts. ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook". -- -- combineTwo is a new simple layout combinator. It allows the -- combination of two layouts using a third to split the screen@@ -57,7 +60,7 @@ -- >    , ((modm .|. controlMask .|. shiftMask, xK_Down ), sendMessage $ Move D) -- -- For detailed instruction on editing the key binding see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>. -- -- These bindings will move a window into the sublayout that is -- up\/down\/left\/right of its current position.  Note that there is some@@ -88,14 +91,14 @@                                          handleMessage super (SomeMessage ReleaseResources)                                return ([(w,rinput)], Just $ C2 [w] [w] super' l1' l2')               arrange origws =-                  do let w2' = case origws `intersect` w2 of [] -> [head origws]+                  do let w2' = case origws `intersect` w2 of [] -> take 1 origws                                                              [x] -> [x]                                                              x -> case origws \\ x of                                                                   [] -> init x                                                                   _ -> x                          superstack = Stack { focus=(), up=[], down=[()] }-                         s1 = differentiate f' (origws \\ w2')-                         s2 = differentiate f' w2'+                         s1 = zipperFocusedAtFirstOf f' (origws \\ w2')+                         s2 = zipperFocusedAtFirstOf f' w2'                          f' = case s of (Just s') -> focus s':delete (focus s') f                                         Nothing -> f                      ([((),r1),((),r2)], msuper') <- runLayout (Workspace "" super (Just superstack)) rinput@@ -121,20 +124,12 @@                          msuper' <- broadcastPrivate m [super]                          if isJust msuper' || isJust ml1' || isJust ml2'                             then return $ Just $ C2 f ws2-                                                 (maybe super head msuper')-                                                 (maybe l1 head ml1')-                                                 (maybe l2 head ml2')+                                                 (fromMaybe super (listToMaybe =<< msuper'))+                                                 (fromMaybe l1    (listToMaybe =<< ml1'))+                                                 (fromMaybe l2    (listToMaybe =<< ml2'))                             else return Nothing     description (C2 _ _ super l1 l2) = "combining "++ description l1 ++" and "++                                        description l2 ++" with "++ description super---differentiate :: Eq q => [q] -> [q] -> Maybe (Stack q)-differentiate (z:zs) xs | z `elem` xs = Just $ Stack { focus=z-                                                     , up = reverse $ takeWhile (/=z) xs-                                                     , down = tail $ dropWhile (/=z) xs }-                        | otherwise = differentiate zs xs-differentiate [] xs = W.differentiate xs  broadcastPrivate :: LayoutClass l b => SomeMessage -> [l b] -> X (Maybe [l b]) broadcastPrivate a ol = do nml <- mapM f ol
XMonad/Layout/ComboP.hs view
@@ -25,15 +25,16 @@                              Property(..)                             ) where -import XMonad.Prelude import XMonad hiding (focus)-import XMonad.StackSet ( Workspace (..), Stack(..) ) import XMonad.Layout.WindowNavigation-import XMonad.Util.WindowProperties+import XMonad.Prelude+import XMonad.StackSet ( Workspace (..), Stack(..) ) import qualified XMonad.StackSet as W+import XMonad.Util.Stack (zipperFocusedAtFirstOf)+import XMonad.Util.WindowProperties  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Layout.ComboP --@@ -44,9 +45,9 @@ -- to your layouts. This way all windows with class = \"Firefox\" will always go -- to the left pane, all others - to the right. ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook". -- -- 'combineTwoP' is a simple layout combinator based on 'combineTwo' from Combo, with -- addition of a 'Property' which tells where to put new windows. Windows mathing@@ -64,7 +65,7 @@ -- >    , ((modm .|. controlMask .|. shiftMask, xK_s    ), sendMessage $ SwapWindow) -- -- For detailed instruction on editing the key binding see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  data SwapWindow =  SwapWindow        -- ^ Swap window between panes                  | SwapWindowN Int   -- ^ Swap window between panes in the N-th nested ComboP. @SwapWindowN 0@ equals to SwapWindow@@ -99,10 +100,10 @@             f' = focus s:delete (focus s) f  -- list of focused windows, contains 2 elements at most         in do             matching <- hasProperty prop `filterM` new  -- new windows matching predecate-            let w1' = w1c ++ matching                     -- updated first pane windows-                w2' = w2c ++ (new \\ matching)            -- updated second pane windows-                s1 = differentiate f' w1'                 -- first pane stack-                s2 = differentiate f' w2'                 -- second pane stack+            let w1' = w1c ++ matching                   -- updated first pane windows+                w2' = w2c ++ (new \\ matching)          -- updated second pane windows+                s1 = zipperFocusedAtFirstOf f' w1'      -- first pane stack+                s2 = zipperFocusedAtFirstOf f' w2'      -- second pane stack             ([((),r1),((),r2)], msuper') <- runLayout (Workspace "" super superstack) rinput             (wrs1, ml1') <- runLayout (Workspace "" l1 s1) r1             (wrs2, ml2') <- runLayout (Workspace "" l2 s2) r2@@ -176,16 +177,5 @@     send st = if W.focus st `elem` w                 then handleMessage l m                 else return Nothing---- code from CombineTwo--- given two sets of zs and xs takes the first z from zs that also belongs to xs--- and turns xs into a stack with z being current element. Acts as--- StackSet.differentiate if zs and xs don't intersect-differentiate :: Eq q => [q] -> [q] -> Maybe (Stack q)-differentiate (z:zs) xs | z `elem` xs = Just $ Stack { focus=z-                                                     , up = reverse $ takeWhile (/=z) xs-                                                     , down = tail $ dropWhile (/=z) xs }-                        | otherwise = differentiate zs xs-differentiate [] xs = W.differentiate xs  -- vim:ts=4:shiftwidth=4:softtabstop=4:expandtab:foldlevel=20:
XMonad/Layout/Cross.hs view
@@ -12,7 +12,7 @@ -- -- A Cross Layout with the main window in the center. ---module XMonad.Layout.Cross(+module XMonad.Layout.Cross {-# DEPRECATED "Use XMonad.Layout.Circle or XMonad.Layout.ThreeColumn.ThreeColMid instead" #-} (                           -- * Usage                           -- $usage                           simpleCross@@ -23,7 +23,7 @@ import XMonad.Prelude( msum )  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Layout.Cross --
XMonad/Layout/Decoration.hs view
@@ -1,8 +1,9 @@+{-# LANGUAGE CPP                   #-} {-# LANGUAGE FlexibleContexts      #-} {-# LANGUAGE FlexibleInstances     #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE PatternGuards         #-}-{-# LANGUAGE CPP                   #-}+{-# LANGUAGE TupleSections         #-} ----------------------------------------------------------------------------- -- | -- Module      :  XMonad.Layout.Decoration@@ -241,7 +242,7 @@                                     toDel = todel d dwrs                                     toAdd = toadd a wrs                                 deleteDecos (map snd toDel)-                                let ndwrs = zip toAdd $ repeat (Nothing,Nothing)+                                let ndwrs = map (, (Nothing,Nothing)) toAdd                                 ndecos <- resync (ndwrs ++ del_dwrs d dwrs) wrs                                 processState (s {decos = ndecos }) @@ -399,7 +400,11 @@ -- structure and the needed 'Rectangle's updateDeco :: Shrinker s => s -> Theme -> XMonadFont -> (OrigWin,DecoWin) -> X () updateDeco sh t fs ((w,_),(Just dw,Just (Rectangle _ _ wh ht))) = do-  nw  <- getName w+  -- xmonad-contrib #809+  -- qutebrowser will happily shovel a 389K multiline string into @_NET_WM_NAME@+  -- and the 'defaultShrinker' (a) doesn't handle multiline strings well (b) is+  -- quadratic due to using 'init'+  nw  <- fmap (take 2048 . takeWhile (/= '\n') . show) (getName w)   ur  <- readUrgents   dpy <- asks display   let focusColor win ic ac uc = maybe ic (\focusw -> case () of@@ -413,7 +418,7 @@                  (urgentColor   t, urgentBorderColor   t, urgentBorderWidth   t, urgentTextColor   t)   let s = shrinkIt sh   name <- shrinkWhile s (\n -> do size <- io $ textWidthXMF dpy fs n-                                  return $ size > fromIntegral wh - fromIntegral (ht `div` 2)) (show nw)+                                  return $ size > fromIntegral wh - fromIntegral (ht `div` 2)) nw   let als = AlignCenter : map snd (windowTitleAddons t)       strs = name : map fst (windowTitleAddons t)       i_als = map snd (windowTitleIcons t)
+ XMonad/Layout/DecorationEx.hs view
@@ -0,0 +1,106 @@++-----------------------------------------------------------------------------+-- |+-- Module      :  XMonad.Layout.DecorationEx+-- Description :  Advanced window decorations module for XMonad+-- Copyright   :  (c) 2007 Andrea Rossato, 2009 Jan Vornberger, 2023 Ilya Portnov+-- License     :  BSD-style (see xmonad/LICENSE)+--+-- Maintainer  :  portnov84@rambler.ru+-- Stability   :  unstable+-- Portability :  unportable+--+-- This set of modules contains a set of type classes and their implementations+-- which define a flexible and extensible mechanism of window decorations.+--+-- <<https://github.com/xmonad/xmonad-contrib/assets/50166980/ccc20e1b-6762-48d9-8195-579f77a98396>>+-- Click <https://github.com/xmonad/xmonad-contrib/assets/50166980/64847a85-33c4-4b5f-8ec8-df73d3e4d58d here>+-- for a larger version.+--+-- Within this mechanism, there are the following entities which define+-- how decorations will look and work:+--+-- * Main object is @DecorationEx@ layout modifier. It is from where everything+--   starts. It creates, shows and hides decoration windows (rectangles) when+--   needed. It is parameterized with decoration geometry, decoration engine and+--   theme. It calls these components to do their parts of the work.+-- * @DecorationGeometry@ defines where decoration rectangles should be placed.+--   For example, standard horizontal bar above each window; or tab bar.+-- * @DecorationEngine@ defines how decorations look and how they react on clicks.+--   Different implementations of the decoration engine can use different APIs+--   to draw decorations. Within this package, there is one implementation +--   (@TextDecoration@), which uses plain Xlib calls, and displays decoration+--   widgets with text fragments, like @[X]@ or @[_]@. Other engines can, for+--   example, use the Cairo library to draw nice gradients and image-based widgets.+-- * A Decoration widget is an element placed on a window decoration. It defines how+--   it looks and how it responds to clicks. Examples include usual window +--   buttons (minimize, maximize, close), window icon, window title.+-- * A Decoration theme defines colors and fonts for the decoration engine. It also+--   contains a list of decoration widgets and says where to place them (at the+--   left, at the right or in the center).+-- +-- This mechanism makes major use of parameterized data types and type families,+-- in order to make it possible to define different types of decorations, and+-- easily combine different aspects of decorations. For example, each decoration+-- engine can be combined with each decoration geometry.+-----------------------------------------------------------------------------++module XMonad.Layout.DecorationEx (+  -- * Usage:+  -- $usage++  -- * Standard decoration settings+  decorationEx,+  textDecoration, textTabbed, dwmStyleDeco,+  -- * Decoration-related types+  TextDecoration (..), DefaultGeometry (..),+  TabbedGeometry (..), DwmGeometry (..),+  DecorationEx,+  -- * Theme types+  BoxBorders (..), BorderColors,+  SimpleStyle (..), GenericTheme (..),+  ThemeEx,+  -- * Widget types+  StandardCommand (..), GenericWidget (..),+  StandardWidget,+  -- * Utility functions for themes+  themeEx, borderColor, shadowBorder,+  -- * Convinience re-exports+  Shrinker (..), shrinkText,+  -- * Standard widgets+  titleW, toggleStickyW, minimizeW,+  maximizeW, closeW, dwmpromoteW,+  moveToNextGroupW, moveToPrevGroupW+  ) where++import XMonad.Layout.Decoration+import XMonad.Layout.DecorationEx.Common+import XMonad.Layout.DecorationEx.Widgets+import XMonad.Layout.DecorationEx.Geometry+import XMonad.Layout.DecorationEx.LayoutModifier+import XMonad.Layout.DecorationEx.TextEngine+import XMonad.Layout.DecorationEx.TabbedGeometry+import XMonad.Layout.DecorationEx.DwmGeometry++-- $usage+--+-- You can use this module with the following in your+-- @xmonad.hs@:+--+-- > import XMonad.Layout.DecorationEx+-- Then edit your @layoutHook@ by adding the DwmStyle decoration to+-- your layout:+--+-- > myTheme = ThemeEx {...}+-- > myL = textDecoration shrinkText myTheme (layoutHook def)+-- > main = xmonad def { layoutHook = myL }+--+-- For more detailed instructions on editing the layoutHook see:+--+-- "XMonad.Doc.Extending#Editing_the_layout_hook"+--+-- This module exports only some definitions from it's submodules,+-- most likely to be used from user configurations. To define+-- your own decoration types you will likely have to import specific+-- submodules.+
+ XMonad/Layout/DecorationEx/Common.hs view
@@ -0,0 +1,272 @@+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE UndecidableInstances #-}++-----------------------------------------------------------------------------+-- |+-- Module      :  XMonad.Layout.DecorationEx.Common+-- Description :  Declaration of types used by DecorationEx module,+--                and commonly used utility functions.+-- Copyright   :  (c) 2007 Andrea Rossato, 2009 Jan Vornberger, 2023 Ilya Portnov+-- License     :  BSD-style (see xmonad/LICENSE)+--+-- Maintainer  :  portnov84@rambler.ru+-- Stability   :  unstable+-- Portability :  unportable+--+-- This module exposes a number of types which are used by other sub-modules+-- of "XMonad.Layout.DecorationEx" module.+-----------------------------------------------------------------------------++module XMonad.Layout.DecorationEx.Common (+    -- * Common types+    WindowDecoration (..)+  , WindowCommand (..)+  , DecorationWidget (..)+  , WidgetPlace (..)+  , WidgetLayout (..)+  , HasWidgets (..)+  , ClickHandler (..)+  , ThemeAttributes (..)+  , XPaintingContext+  , BoxBorders (..)+  , BorderColors+  , ThemeStyleType (..)+  , SimpleStyle (..)+  , GenericTheme (..)+  , ThemeEx +  -- * Utilities+  , widgetLayout+  , windowStyleType+  , genericWindowStyle+  , themeEx+  , borderColor+  , shadowBorder+  ) where++import qualified Data.Map as M+import Data.Bits (testBit)++import XMonad+import qualified XMonad.StackSet as W+import XMonad.Hooks.UrgencyHook+import qualified XMonad.Layout.Decoration as D++-- | Information about decoration of one window+data WindowDecoration = WindowDecoration {+    wdOrigWindow :: !Window         -- ^ Original window (one being decorated)+  , wdOrigWinRect :: !Rectangle     -- ^ Rectangle of original window+  , wdDecoWindow :: !(Maybe Window) -- ^ Decoration window, or Nothing if this window should not be decorated+  , wdDecoRect :: !(Maybe Rectangle) -- ^ Rectangle for decoration window+  , wdWidgets :: ![WidgetPlace]      -- ^ Places for widgets+  }++-- | Type class for window commands (such as maximize or close window)+class (Read cmd, Show cmd) => WindowCommand cmd where+  -- | Execute the command+  executeWindowCommand :: cmd -> Window -> X Bool++  -- | Is the command currently in `checked' state. +  -- For example, for 'sticky' command, check if the+  -- window is currently sticky.+  isCommandChecked :: cmd -> Window -> X Bool++-- | Type class for decoration widgets+class (WindowCommand (WidgetCommand widget), Read widget, Show widget)+  => DecorationWidget widget where+  -- | Type of window commands which this type of widgets can execute+  type WidgetCommand widget++  -- | Get window command which is associated with this widget.+  widgetCommand :: widget -> Int -> WidgetCommand widget++  -- | Check if the widget is shrinkable, i.e. if it's width+  -- can be reduced if there is not enough place in the decoration.+  isShrinkable :: widget -> Bool++-- | Layout of widgets+data WidgetLayout a = WidgetLayout {+    wlLeft :: ![a]     -- ^ Widgets that should be aligned to the left side of decoration+  , wlCenter :: ![a]   -- ^ Widgets that should be in the center of decoration+  , wlRight :: ![a]    -- ^ Widgets taht should be aligned to the right side of decoration+  }++-- | Data type describing where the decoration widget (e.g. window button)+-- should be placed.+-- All coordinates are relative to decoration rectangle.+data WidgetPlace = WidgetPlace {+    wpTextYPosition :: !Position -- ^ Y position of text base line+                                 -- (for widgets like window title or text-based buttons)+  , wpRectangle :: !Rectangle    -- ^ Rectangle where to place the widget+  }+  deriving (Show)++-- | Generic data type which is used to+-- describe characteristics of rectangle borders.+data BoxBorders a = BoxBorders {+    bxTop :: !a+  , bxRight :: !a+  , bxBottom :: !a+  , bxLeft :: !a+  } deriving (Eq, Read, Show)++-- | Convinience data type describing colors of decoration rectangle borders.+type BorderColors = BoxBorders String++-- | Data type describing look of window decoration+-- in particular state (active or inactive)+data SimpleStyle = SimpleStyle {+    sBgColor :: !String                 -- ^ Decoration background color+  , sTextColor :: !String               -- ^ Text (foreground) color+  , sTextBgColor :: !String             -- ^ Text background color+  , sDecoBorderWidth :: !Dimension      -- ^ Width of border of decoration rectangle. Set to 0 to disable the border.+  , sDecorationBorders :: !BorderColors -- ^ Colors of borders of decoration rectangle.+  }+  deriving (Show, Read)++-- | Type class for themes, which claims that+-- the theme contains the list of widgets and their alignments.+class HasWidgets theme widget where+  themeWidgets :: theme widget -> WidgetLayout widget++-- | Type class for themes, which claims that+-- the theme can describe how the decoration should respond+-- to clicks on decoration itself (between widgets).+class ClickHandler theme widget where+  -- | This is called when the user clicks on the decoration rectangle+  -- (not on one of widgets).+  onDecorationClick :: theme widget+                    -> Int                          -- ^ Mouse button number+                    -> Maybe (WidgetCommand widget)++  -- | Determine if it is possible to drag window by it's decoration+  -- with mouse button.+  isDraggingEnabled :: theme widget+                    -> Int          -- ^ Mouse button number+                    -> Bool++-- | Type class for themes, which claims that the theme+-- is responsible for determining looks of decoration.+class (Read theme, Show theme) => ThemeAttributes theme where+  -- | Type which describes looks of decoration in one+  -- of window states (active, inactive, urgent, etc).+  type Style theme++  -- | Select style based on window state.+  selectWindowStyle :: theme -> Window -> X (Style theme)++  -- | Define padding between decoration rectangle and widgets.+  widgetsPadding :: theme -> BoxBorders Dimension+  +  -- | Initial background color of decoration rectangle.+  -- When decoration widget is created, it is initially filled+  -- with this color.+  defaultBgColor :: theme -> String++  -- | Font name defined in the theme.+  themeFontName :: theme -> String++-- | Generic Theme data type. This is used+-- by @TextEngine@ and can be used by other relatively+-- simple decoration engines.+data GenericTheme style widget = GenericTheme {+    exActive :: !style                                  -- ^ Decoration style for active (focused) windows+  , exInactive :: !style                                -- ^ Decoration style for inactive (unfocused) windows+  , exUrgent :: !style                                  -- ^ Decoration style for urgent windows+  , exPadding :: !(BoxBorders Dimension)                -- ^ Padding between decoration rectangle and widgets+  , exFontName :: !String                               -- ^ Font name+  , exOnDecoClick :: !(M.Map Int (WidgetCommand widget)) -- ^ Correspondence between mouse button number and window command.+  , exDragWindowButtons :: ![Int]                       -- ^ For which mouse buttons dragging is enabled+  , exWidgetsLeft :: ![widget]                          -- ^ Widgets that should appear at the left of decoration rectangle (listed left to right)+  , exWidgetsCenter :: ![widget]                        -- ^ Widgets that should appear in the center of decoration rectangle (listed left to right)+  , exWidgetsRight :: ![widget]                         -- ^ Widgets that should appear at the right of decoration rectangle (listed left to right)+  }++deriving instance (Show widget, Show (WidgetCommand widget), Show style) => Show (GenericTheme style widget)+deriving instance (Read widget, Read (WidgetCommand widget), Read style) => Read (GenericTheme style widget)++-- | Convience type for themes used by @TextDecoration@.+type ThemeEx widget = GenericTheme SimpleStyle widget++instance HasWidgets (GenericTheme style) widget where+  themeWidgets theme = WidgetLayout (exWidgetsLeft theme) (exWidgetsCenter theme) (exWidgetsRight theme)++-- | Supported states of windows (on which looks of decorations can depend).+data ThemeStyleType = ActiveWindow | UrgentWindow | InactiveWindow+  deriving (Eq, Show, Read)++-- | Utility function to convert WidgetLayout to plain list of widgets.+widgetLayout :: WidgetLayout widget -> [widget]+widgetLayout ws = wlLeft ws ++ wlCenter ws ++ wlRight ws++-- | Painting context for decoration engines based on plain X11 calls.+type XPaintingContext = (Display, Pixmap, GC)++instance (Show widget, Read widget, Read (WidgetCommand widget), Show (WidgetCommand widget))+        => ThemeAttributes (ThemeEx widget) where+  type Style (ThemeEx widget) = SimpleStyle+  selectWindowStyle theme w = genericWindowStyle w theme+  defaultBgColor t = sBgColor $ exInactive t+  widgetsPadding = exPadding+  themeFontName = exFontName++instance ClickHandler (GenericTheme SimpleStyle) widget where+  onDecorationClick theme button = M.lookup button (exOnDecoClick theme)+  isDraggingEnabled theme button = button `elem` exDragWindowButtons theme++-- | Generic utility function to select style from @GenericTheme@+-- based on current state of the window.+genericWindowStyle :: Window -> GenericTheme style widget -> X style+genericWindowStyle win theme = do+  styleType <- windowStyleType win+  return $ case styleType of+             ActiveWindow -> exActive theme+             InactiveWindow -> exInactive theme+             UrgentWindow -> exUrgent theme++-- | Detect type of style to be used from current state of the window.+windowStyleType :: Window -> X ThemeStyleType+windowStyleType win = do+  mbFocused <- W.peek <$> gets windowset+  isWmStateUrgent <- (win `elem`) <$> readUrgents+  isUrgencyBitSet <- withDisplay $ \dpy -> do+                       hints <- io $ getWMHints dpy win+                       return $ wmh_flags hints `testBit` urgencyHintBit+  if isWmStateUrgent || isUrgencyBitSet+    then return UrgentWindow+    else return $+      case mbFocused of+        Nothing -> InactiveWindow+        Just focused+          | focused == win -> ActiveWindow+          | otherwise -> InactiveWindow++-- | Convert Theme type from "XMonad.Layout.Decoration" to +-- theme type used by "XMonad.Layout.DecorationEx.TextEngine".+themeEx :: Default (WidgetCommand widget) => D.Theme -> ThemeEx widget+themeEx t =+    GenericTheme {+          exActive = SimpleStyle (D.activeColor t) (D.activeTextColor t) (D.activeColor t) (D.activeBorderWidth t) (borderColor $ D.activeColor t)+        , exInactive = SimpleStyle (D.inactiveColor t) (D.inactiveTextColor t) (D.inactiveColor t) (D.inactiveBorderWidth t) (borderColor $ D.inactiveColor t)+        , exUrgent = SimpleStyle (D.urgentColor t) (D.urgentTextColor t) (D.urgentColor t) (D.urgentBorderWidth t) (borderColor $ D.urgentColor t)+        , exPadding = BoxBorders 0 4 0 4+        , exFontName = D.fontName t+        , exOnDecoClick = M.fromList [(1, def)]+        , exDragWindowButtons = [1]+        , exWidgetsLeft = []+        , exWidgetsCenter = []+        , exWidgetsRight = []+      }++instance Default (WidgetCommand widget) => Default (ThemeEx widget) where+  def = themeEx (def :: D.Theme)++borderColor :: String -> BorderColors+borderColor c = BoxBorders c c c c++shadowBorder :: String -> String -> BorderColors+shadowBorder highlight shadow = BoxBorders highlight shadow shadow highlight+
+ XMonad/Layout/DecorationEx/DwmGeometry.hs view
@@ -0,0 +1,106 @@+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE RecordWildCards #-}++-----------------------------------------------------------------------------+-- |+-- Module      :  XMonad.Layout.DecorationEx.DwmGeometry+-- Description :  DWM-style window decoration geometry+-- Copyright   :  (c) 2007 Andrea Rossato, 2023 Ilya Portnov+-- License     :  BSD-style (see xmonad/LICENSE)+--+-- Maintainer  :  portnov84@rambler.ru+-- Stability   :  unstable+-- Portability :  unportable+--+-- This defines window decorations which are shown as a bar of fixed width+-- on top of window.+-----------------------------------------------------------------------------++module XMonad.Layout.DecorationEx.DwmGeometry (+    -- * Usage:+    -- $usage+    DwmGeometry (..),+    dwmStyleDeco, dwmStyleDecoEx+  ) where ++import XMonad+import XMonad.Prelude+import qualified XMonad.StackSet as W+import XMonad.Layout.LayoutModifier+import qualified XMonad.Layout.Decoration as D++import XMonad.Layout.DecorationEx.LayoutModifier+import XMonad.Layout.DecorationEx.Common+import XMonad.Layout.DecorationEx.Geometry+import XMonad.Layout.DecorationEx.Widgets+import XMonad.Layout.DecorationEx.TextEngine++-- $usage+-- You can use this module with the following in your+-- @xmonad.hs@:+--+-- > import XMonad.Layout.DecorationEx.DwmStyle+-- Then edit your @layoutHook@ by adding the DwmStyle decoration to+-- your layout:+--+-- > myL = dwmStyleDeco shrinkText (layoutHook def)+-- > main = xmonad def { layoutHook = myL }+--+-- For more detailed instructions on editing the layoutHook see:+--+-- "XMonad.Doc.Extending#Editing_the_layout_hook"++-- | Decoration geometry data type+data DwmGeometry a = DwmGeometry {+      dwmShowForFocused :: !Bool         -- ^ Whether to show decorations on focused windows+    , dwmHorizontalPosition :: !Rational -- ^ Horizontal position of decoration rectangle.+                                         -- 0 means place it at left corner, 1 - place it at+                                         -- right corner, @1%2@ - place it at center.+    , dwmDecoHeight :: !Dimension        -- ^ Height of decoration rectangle+    , dwmDecoWidth :: !Dimension         -- ^ Width of decoration rectangle+  }+  deriving (Show, Read)++instance Default (DwmGeometry a) where+  def = DwmGeometry False 1 20 200++instance DecorationGeometry DwmGeometry Window where+  describeGeometry _ = "DwmStyle"++  pureDecoration (DwmGeometry {..}) _ stack _ (w, Rectangle x y windowWidth _) =+    let width = min windowWidth dwmDecoWidth+        halfWidth = width `div` 2+        minCenterX = x + fi halfWidth+        maxCenterX = x + fi windowWidth - fromIntegral halfWidth+        centerX = round ((1 - dwmHorizontalPosition)*fi minCenterX + dwmHorizontalPosition*fi maxCenterX) :: Position+        decoX = centerX - fi halfWidth+        focusedWindow = W.focus stack+        isFocused = focusedWindow == w+    in  if (not dwmShowForFocused && isFocused) || not (D.isInStack stack w)+          then Nothing+          else Just $ Rectangle decoX y width dwmDecoHeight++  shrinkWindow _ _ windowRect = windowRect++-- | Add a decoration to window layout. Widgets are indicated with text fragments using TextDecoration;+-- decoration placement can be adjusted.+dwmStyleDecoEx :: D.Shrinker shrinker    +             => shrinker               -- ^ Strings shrinker, for example @shrinkText@+             -> DwmGeometry Window+             -> ThemeEx StandardWidget -- ^ Decoration theme (font, colors, widgets, etc)+             -> l Window               -- ^ Layout to be decorated+             -> ModifiedLayout (DecorationEx TextDecoration StandardWidget DwmGeometry shrinker) l Window+dwmStyleDecoEx shrinker geom theme = decorationEx shrinker theme TextDecoration geom++-- | Add a decoration to window layout. Widgets are indicated with text fragments using TextDecoration;+-- decoration placement is similar to DWM.+dwmStyleDeco :: D.Shrinker shrinker    +             => shrinker               -- ^ Strings shrinker, for example @shrinkText@+             -> ThemeEx StandardWidget -- ^ Decoration theme (font, colors, widgets, etc)+             -> l Window               -- ^ Layout to be decorated+             -> ModifiedLayout (DecorationEx TextDecoration StandardWidget DwmGeometry shrinker) l Window+dwmStyleDeco shrinker = dwmStyleDecoEx shrinker def+
+ XMonad/Layout/DecorationEx/Engine.hs view
@@ -0,0 +1,511 @@+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, ViewPatterns #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE DefaultSignatures #-}++-----------------------------------------------------------------------------+-- |+-- Module      :  XMonad.Layout.DecorationEx.Engine+-- Description :  Type class and its default implementation for window decoration engines.+-- Copyright   :  (c) 2007 Andrea Rossato, 2009 Jan Vornberger, 2023 Ilya Portnov+-- License     :  BSD-style (see xmonad/LICENSE)+--+-- Maintainer  :  portnov84@rambler.ru+-- Stability   :  unstable+-- Portability :  unportable+--+-- This module defines @DecorationEngine@ type class, and default implementation for it.+-----------------------------------------------------------------------------++module XMonad.Layout.DecorationEx.Engine (+    -- * DecorationEngine class+    DecorationEngine (..),+    -- * Auxiliary data types+    DrawData (..), +    DecorationLayoutState (..),+    -- * Re-exports from X.L.Decoration+    Shrinker (..), shrinkText,+    -- * Utility functions+    mkDrawData,+    paintDecorationSimple+  ) where++import Control.Monad+import Data.Kind+import Foreign.C.Types (CInt)++import XMonad+import XMonad.Prelude+import qualified XMonad.StackSet as W+import XMonad.Layout.Decoration (Shrinker (..), shrinkWhile, shrinkText)+import XMonad.Layout.DraggingVisualizer (DraggingVisualizerMsg (..))+import XMonad.Layout.DecorationAddons (handleScreenCrossing)+import XMonad.Util.Font+import XMonad.Util.NamedWindows (getName)++import XMonad.Layout.DecorationEx.Common++-- | Auxiliary type for data which are passed from+-- decoration layout modifier to decoration engine.+data DrawData engine widget = DrawData {+    ddEngineState :: !(DecorationEngineState engine)     -- ^ Decoration engine state+  , ddStyle :: !(Style (Theme engine widget))  -- ^ Graphics style of the decoration. This defines colors, fonts etc+                                                        -- which are to be used for this particular window in it's current state.+  , ddOrigWindow :: !Window                             -- ^ Original window to be decorated+  , ddWindowTitle :: !String                            -- ^ Original window title (not shrinked yet)+  , ddDecoRect :: !Rectangle                            -- ^ Decoration rectangle+  , ddWidgets :: !(WidgetLayout widget)         -- ^ Widgets to be placed on decoration+  , ddWidgetPlaces :: !(WidgetLayout WidgetPlace)       -- ^ Places where widgets must be shown+  }++-- | State of decoration engine+data DecorationLayoutState engine = DecorationLayoutState {+    dsStyleState :: !(DecorationEngineState engine) -- ^ Engine-specific state+  , dsDecorations :: ![WindowDecoration]            -- ^ Mapping between decoration windows and original windows+  }++-- | Decoration engines type class.+-- Decoration engine is responsible for drawing something inside decoration rectangle.+-- It is also responsible for handling X11 events (such as clicks) which happen+-- within decoration rectangle.+-- Decoration rectangles are defined by DecorationGeometry implementation.+class (Read (engine widget a), Show (engine widget a),+       Eq a,+       DecorationWidget widget,+       HasWidgets (Theme engine) widget,+       ClickHandler (Theme engine) widget,+       ThemeAttributes (Theme engine widget))+    => DecorationEngine engine widget a where++    -- | Type of themes used by decoration engine.+    -- This type must be parameterized over a widget type,+    -- because a theme will contain a list of widgets.+    type Theme engine :: Type -> Type           +                                          +    -- | Type of data used by engine as a context during painting;+    -- for plain X11-based implementation this is Display, Pixmap+    -- and GC.+    type DecorationPaintingContext engine + +    -- | Type of state used by the decoration engine.+    -- This can contain some resources that should be initialized+    -- and released at time, such as X11 fonts.+    type DecorationEngineState engine     ++    -- | Give a name to decoration engine.+    describeEngine :: engine widget a -> String++    -- | Initialize state of the engine.+    initializeState :: engine widget a       -- ^ Decoration engine instance+                    -> geom a                -- ^ Decoration geometry instance+                    -> Theme engine widget   -- ^ Theme to be used+                    -> X (DecorationEngineState engine)++    -- | Release resources held in engine state.+    releaseStateResources :: engine widget a              -- ^ Decoration engine instance+                          -> DecorationEngineState engine -- ^ Engine state+                          -> X ()++    -- | Calculate place which will be occupied by one widget.+    -- NB: X coordinate of the returned rectangle will be ignored, because+    -- the rectangle will be moved to the right or to the left for proper alignment+    -- of widgets.+    calcWidgetPlace :: engine widget a         -- ^ Decoration engine instance+                    -> DrawData engine widget  -- ^ Information about window and decoration+                    -> widget                  -- ^ Widget to be placed+                    -> X WidgetPlace++    -- | Place widgets along the decoration bar.+    placeWidgets :: Shrinker shrinker+                 => engine widget a              -- ^ Decoration engine instance+                 -> Theme engine widget          -- ^ Theme to be used+                 -> shrinker                     -- ^ Strings shrinker+                 -> DecorationEngineState engine -- ^ Current state of the engine+                 -> Rectangle                    -- ^ Decoration rectangle+                 -> Window                       -- ^ Original window to be decorated+                 -> WidgetLayout widget          -- ^ Widgets layout+                 -> X (WidgetLayout WidgetPlace)+    placeWidgets engine theme _ decoStyle decoRect window wlayout = do+        let leftWidgets = wlLeft wlayout+            rightWidgets = wlRight wlayout+            centerWidgets = wlCenter wlayout++        dd <- mkDrawData engine theme decoStyle window decoRect+        let paddedDecoRect = pad (widgetsPadding theme) (ddDecoRect dd)+            paddedDd = dd {ddDecoRect = paddedDecoRect}+        rightRects <- alignRight engine paddedDd rightWidgets+        leftRects <- alignLeft engine paddedDd leftWidgets+        let wantedLeftWidgetsWidth = sum $ map (rect_width . wpRectangle) leftRects+            wantedRightWidgetsWidth = sum $ map (rect_width . wpRectangle) rightRects+            hasShrinkableOnLeft = any isShrinkable leftWidgets+            hasShrinkableOnRight = any isShrinkable rightWidgets+            decoWidth = rect_width decoRect+            (leftWidgetsWidth, rightWidgetsWidth)+              | hasShrinkableOnLeft = +                  (min (decoWidth - wantedRightWidgetsWidth) wantedLeftWidgetsWidth,+                      wantedRightWidgetsWidth)+              | hasShrinkableOnRight =+                  (wantedLeftWidgetsWidth,+                      min (decoWidth - wantedLeftWidgetsWidth) wantedRightWidgetsWidth)+              | otherwise = (wantedLeftWidgetsWidth, wantedRightWidgetsWidth)+            ddForCenter = paddedDd {ddDecoRect = padCenter leftWidgetsWidth rightWidgetsWidth paddedDecoRect}+        centerRects <- alignCenter engine ddForCenter centerWidgets+        let shrinkedLeftRects = packLeft (rect_x paddedDecoRect) $ shrinkPlaces leftWidgetsWidth $ zip leftRects (map isShrinkable leftWidgets)+            shrinkedRightRects = packRight (rect_width paddedDecoRect) $ shrinkPlaces rightWidgetsWidth $ zip rightRects (map isShrinkable rightWidgets)+        return $ WidgetLayout shrinkedLeftRects centerRects shrinkedRightRects+      where+        shrinkPlaces targetWidth ps =+          let nShrinkable = length (filter snd ps)+              totalUnshrinkedWidth = sum $ map (rect_width . wpRectangle . fst) $ filter (not . snd) ps+              shrinkedWidth = (targetWidth - totalUnshrinkedWidth) `div` fi nShrinkable++              resetX place = place {wpRectangle = (wpRectangle place) {rect_x = 0}}++              adjust (place, True) = resetX $ place {wpRectangle = (wpRectangle place) {rect_width = shrinkedWidth}}+              adjust (place, False) = resetX place+          in  map adjust ps++        pad p (Rectangle _ _ w h) =+          Rectangle (fi (bxLeft p)) (fi (bxTop p))+                    (w - bxLeft p - bxRight p)+                    (h - bxTop p - bxBottom p)+      +        padCenter left right (Rectangle x y w h) =+          Rectangle (x + fi left) y+                    (w - left - right) h++    -- | Shrink window title so that it would fit in decoration.+    getShrinkedWindowName :: Shrinker shrinker+                          => engine widget a              -- ^ Decoration engine instance+                          -> shrinker                     -- ^ Strings shrinker+                          -> DecorationEngineState engine -- ^ State of decoration engine+                          -> String                       -- ^ Original window title+                          -> Dimension                    -- ^ Width of rectangle in which the title should fit+                          -> Dimension                    -- ^ Height of rectangle in which the title should fit+                          -> X String++    default getShrinkedWindowName :: (Shrinker shrinker, DecorationEngineState engine ~ XMonadFont)+                                  => engine widget a -> shrinker -> DecorationEngineState engine -> String -> Dimension -> Dimension -> X String+    getShrinkedWindowName _ shrinker font name wh _ = do+      let s = shrinkIt shrinker+      dpy <- asks display+      shrinkWhile s (\n -> do size <- io $ textWidthXMF dpy font n+                              return $ size > fromIntegral wh) name++    -- | Mask of X11 events on which the decoration engine should do something.+    -- @exposureMask@ should be included here so that decoration engine could+    -- repaint decorations when they are shown on screen.+    -- @buttonPressMask@ should be included so that decoration engine could+    -- response to mouse clicks.+    -- Other events can be added to custom implementations of DecorationEngine.+    decorationXEventMask :: engine widget a -> EventMask+    decorationXEventMask _ = exposureMask .|. buttonPressMask++    -- | List of X11 window property atoms of original (client) windows,+    -- change of which should trigger repainting of decoration.+    -- For example, if @WM_NAME@ changes it means that we have to redraw+    -- window title.+    propsToRepaintDecoration :: engine widget a -> X [Atom]+    propsToRepaintDecoration _ =+      mapM getAtom ["WM_NAME", "_NET_WM_NAME", "WM_STATE", "WM_HINTS"]++    -- | Generic event handler, which recieves X11 events on decoration+    -- window.+    -- Default implementation handles mouse clicks and drags.+    decorationEventHookEx :: Shrinker shrinker+                          => engine widget a+                          -> Theme engine widget+                          -> DecorationLayoutState engine+                          -> shrinker+                          -> Event+                          -> X ()+    decorationEventHookEx = handleMouseFocusDrag++    -- | Event handler for clicks on decoration window.+    -- This is called from default implementation of "decorationEventHookEx".+    -- This should return True, if the click was handled (something happened+    -- because of that click). If this returns False, the click can be considered+    -- as a beginning of mouse drag.+    handleDecorationClick :: engine widget a      -- ^ Decoration engine instance+                          -> Theme engine widget  -- ^ Decoration theme+                          -> Rectangle            -- ^ Decoration rectangle+                          -> [Rectangle]          -- ^ Rectangles where widgets are placed+                          -> Window               -- ^ Original (client) window+                          -> Int                  -- ^ Mouse click X coordinate+                          -> Int                  -- ^ Mouse click Y coordinate+                          -> Int                  -- ^ Mouse button number+                          -> X Bool+    handleDecorationClick = decorationHandler++    -- | Event handler which is called during mouse dragging.+    -- This is called from default implementation of "decorationEventHookEx".+    decorationWhileDraggingHook :: engine widget a      -- ^ Decoration engine instance+                                -> CInt                 -- ^ Event X coordinate+                                -> CInt                 -- ^ Event Y coordinate+                                -> (Window, Rectangle)  -- ^ Original window and it's rectangle+                                -> Position             -- ^ X coordinate of new pointer position during dragging+                                -> Position             -- ^ Y coordinate of new pointer position during dragging+                                -> X ()+    decorationWhileDraggingHook _ = handleDraggingInProgress++    -- | This hoook is called after a window has been dragged using the decoration.+    -- This is called from default implementation of "decorationEventHookEx".+    decorationAfterDraggingHook :: engine widget a     -- ^ Decoration engine instance+                                -> (Window, Rectangle) -- ^ Original window and its rectangle+                                -> Window              -- ^ Decoration window+                                -> X ()+    decorationAfterDraggingHook _ds (w, _r) decoWin = do+      focus w+      hasCrossed <- handleScreenCrossing w decoWin+      unless hasCrossed $ do+        sendMessage DraggingStopped+        performWindowSwitching w++    -- | Draw everything required on the decoration window.+    -- This method should draw background (flat or gradient or whatever),+    -- borders, and call @paintWidget@ method to draw window widgets+    -- (buttons and title).+    paintDecoration :: Shrinker shrinker+                    => engine widget a         -- ^ Decoration engine instance+                    -> a                       -- ^ Decoration window+                    -> Dimension               -- ^ Decoration window width+                    -> Dimension               -- ^ Decoration window height+                    -> shrinker                -- ^ Strings shrinker instance+                    -> DrawData engine widget  -- ^ Details about what to draw+                    -> Bool                    -- ^ True when this method is called during Expose event+                    -> X ()++    -- | Paint one widget on the decoration window.+    paintWidget :: Shrinker shrinker+                => engine widget a                  -- ^ Decoration engine instance+                -> DecorationPaintingContext engine -- ^ Decoration painting context+                -> WidgetPlace                      -- ^ Place (rectangle) where the widget should be drawn+                -> shrinker                         -- ^ Strings shrinker instance+                -> DrawData engine widget           -- ^ Details about window decoration+                -> widget                           -- ^ Widget to be drawn+                -> Bool                             -- ^ True when this method is called during Expose event+                -> X ()++handleDraggingInProgress :: CInt -> CInt -> (Window, Rectangle) -> Position -> Position -> X ()+handleDraggingInProgress ex ey (mainw, r) x y = do+    let rect = Rectangle (x - (fi ex - rect_x r))+                         (y - (fi ey - rect_y r))+                         (rect_width  r)+                         (rect_height r)+    sendMessage $ DraggingWindow mainw rect++performWindowSwitching :: Window -> X ()+performWindowSwitching win =+    withDisplay $ \d -> do+       root <- asks theRoot+       (_, _, selWin, _, _, _, _, _) <- io $ queryPointer d root+       ws <- gets windowset+       let allWindows = W.index ws+       -- do a little double check to be sure+       when ((win `elem` allWindows) && (selWin `elem` allWindows)) $ do+                let allWindowsSwitched = map (switchEntries win selWin) allWindows+                let (ls, notEmpty -> t :| rs) = break (win ==) allWindowsSwitched+                let newStack = W.Stack t (reverse ls) rs+                windows $ W.modify' $ const newStack+    where+        switchEntries a b x+            | x == a    = b+            | x == b    = a+            | otherwise = x++ignoreX :: WidgetPlace -> WidgetPlace+ignoreX place = place {wpRectangle = (wpRectangle place) {rect_x = 0}}++alignLeft :: forall engine widget a. DecorationEngine engine widget a => engine widget a -> DrawData engine widget -> [widget] -> X [WidgetPlace]+alignLeft engine dd widgets = do+    places <- mapM (calcWidgetPlace engine dd) widgets+    return $ packLeft (rect_x $ ddDecoRect dd) $ map ignoreX places++packLeft :: Position -> [WidgetPlace] -> [WidgetPlace]+packLeft _ [] = []+packLeft x0 (place : places) =+  let rect = wpRectangle place+      x' = x0 + rect_x rect+      rect' = rect {rect_x = x'}+      place' = place {wpRectangle = rect'}+  in  place' : packLeft (x' + fi (rect_width rect)) places++alignRight :: forall engine widget a. DecorationEngine engine widget a => engine widget a -> DrawData engine widget -> [widget] -> X [WidgetPlace]+alignRight engine dd widgets = do+    places <- mapM (calcWidgetPlace engine dd) widgets+    return $ packRight (rect_width $ ddDecoRect dd) $ map ignoreX places++packRight :: Dimension -> [WidgetPlace] -> [WidgetPlace]+packRight x0 places = reverse $ go x0 places+  where+    go _ [] = []+    go x (place : rest) = +      let rect = wpRectangle place+          x' = x - rect_width rect+          rect' = rect {rect_x = fi x'}+          place' = place {wpRectangle = rect'}+      in  place' : go x' rest++alignCenter :: forall engine widget a. DecorationEngine engine widget a => engine widget a -> DrawData engine widget -> [widget] -> X [WidgetPlace]+alignCenter engine dd widgets = do+    places <- alignLeft engine dd widgets+    let totalWidth = sum $ map (rect_width . wpRectangle) places+        availableWidth = fi (rect_width (ddDecoRect dd)) :: Position+        x0 = max 0 $ (availableWidth - fi totalWidth) `div` 2+        places' = map (shift x0) places+    return $ pack (fi availableWidth) places'+  where+    shift x0 place =+      let rect = wpRectangle place+          rect' = rect {rect_x = rect_x rect + fi x0}+      in  place {wpRectangle = rect'}+    +    pack _ [] = []+    pack available (place : places) =+      let rect = wpRectangle place+          placeWidth = rect_width rect+          widthToUse = min available placeWidth+          remaining = available - widthToUse+          rect' = rect {rect_width = widthToUse}+          place' = place {wpRectangle = rect'}+      in  place' : pack remaining places++-- | Build an instance of 'DrawData' type.+mkDrawData :: (DecorationEngine engine widget a, ThemeAttributes (Theme engine widget), HasWidgets (Theme engine) widget)+           => engine widget a+           -> Theme engine widget            -- ^ Decoration theme+           -> DecorationEngineState engine   -- ^ State of decoration engine+           -> Window                         -- ^ Original window (to be decorated)+           -> Rectangle                      -- ^ Decoration rectangle+           -> X (DrawData engine widget)+mkDrawData _ theme decoState origWindow decoRect = do+    -- xmonad-contrib #809+    -- qutebrowser will happily shovel a 389K multiline string into @_NET_WM_NAME@+    -- and the 'defaultShrinker' (a) doesn't handle multiline strings well (b) is+    -- quadratic due to using 'init'+    name  <- fmap (take 2048 . takeWhile (/= '\n') . show) (getName origWindow)+    style <- selectWindowStyle theme origWindow+    return $ DrawData {+                   ddEngineState = decoState,+                   ddStyle = style,+                   ddOrigWindow = origWindow,+                   ddWindowTitle = name,+                   ddDecoRect = decoRect,+                   ddWidgets = themeWidgets theme,+                   ddWidgetPlaces = WidgetLayout [] [] []+                  }++-- | Mouse focus and mouse drag are handled by the same function, this+-- way we can start dragging unfocused windows too.+handleMouseFocusDrag :: (DecorationEngine engine widget a, Shrinker shrinker) => engine widget a -> Theme engine widget -> DecorationLayoutState engine -> shrinker -> Event -> X ()+handleMouseFocusDrag ds theme (DecorationLayoutState {dsDecorations}) _ (ButtonEvent {ev_window, ev_x_root, ev_y_root, ev_event_type, ev_button})+    | ev_event_type == buttonPress+    , Just (WindowDecoration {..}) <- findDecoDataByDecoWindow ev_window dsDecorations = do+        let decoRect@(Rectangle dx dy _ _) = fromJust wdDecoRect+            x = fi $ ev_x_root - fi dx+            y = fi $ ev_y_root - fi dy+            button = fi ev_button+        dealtWith <- handleDecorationClick ds theme decoRect (map wpRectangle wdWidgets) wdOrigWindow x y button+        unless dealtWith $ when (isDraggingEnabled theme button) $+            mouseDrag (\dragX dragY -> focus wdOrigWindow >> decorationWhileDraggingHook ds ev_x_root ev_y_root (wdOrigWindow, wdOrigWinRect) dragX dragY)+                      (decorationAfterDraggingHook ds (wdOrigWindow, wdOrigWinRect) ev_window)+handleMouseFocusDrag _ _ _ _ _ = return ()++-- | Given a window and the state, if a matching decoration is in the+-- state return it with its ('Maybe') 'Rectangle'.+findDecoDataByDecoWindow :: Window -> [WindowDecoration] -> Maybe WindowDecoration+findDecoDataByDecoWindow decoWin = find (\dd -> wdDecoWindow dd == Just decoWin)++decorationHandler :: forall engine widget a.+                     (DecorationEngine engine widget a,+                      ClickHandler (Theme engine) widget)+                  => engine widget a+                  -> Theme engine widget+                  -> Rectangle+                  -> [Rectangle]+                  -> Window+                  -> Int+                  -> Int+                  -> Int+                  -> X Bool+decorationHandler _ theme _ widgetPlaces window x y button = do+    widgetDone <- go $ zip (widgetLayout $ themeWidgets theme) widgetPlaces+    if widgetDone+      then return True+      else case onDecorationClick theme button of+             Just cmd -> do+               executeWindowCommand cmd window+             Nothing -> return False+  where+    go :: [(widget, Rectangle)] -> X Bool+    go [] = return False+    go ((w, rect) : rest) = do+      if pointWithin (fi x) (fi y) rect+        then do+          executeWindowCommand (widgetCommand w button) window+        else go rest++-- | Simple implementation of @paintDecoration@ method.+-- This is used by @TextEngine@ and can be re-used by other decoration+-- engines.+paintDecorationSimple :: forall engine shrinker widget.+                          (DecorationEngine engine widget Window,+                           DecorationPaintingContext engine ~ XPaintingContext,+                           Shrinker shrinker,+                           Style (Theme engine widget) ~ SimpleStyle)+                       => engine widget Window+                       -> Window+                       -> Dimension+                       -> Dimension+                       -> shrinker+                       -> DrawData engine widget+                       -> Bool+                       -> X ()+paintDecorationSimple deco win windowWidth windowHeight shrinker dd isExpose = do+    dpy <- asks display+    let widgets = widgetLayout $ ddWidgets dd+        style = ddStyle dd+    pixmap  <- io $ createPixmap dpy win windowWidth windowHeight (defaultDepthOfScreen $ defaultScreenOfDisplay dpy)+    gc <- io $ createGC dpy pixmap+    -- draw+    io $ setGraphicsExposures dpy gc False+    bgColor <- stringToPixel dpy (sBgColor style)+    -- we start with the border+    let borderWidth = sDecoBorderWidth style+        borderColors = sDecorationBorders style+    when (borderWidth > 0) $ do+      drawLineWith dpy pixmap gc 0 0 windowWidth borderWidth (bxTop borderColors)+      drawLineWith dpy pixmap gc 0 0 borderWidth windowHeight (bxLeft borderColors)+      drawLineWith dpy pixmap gc 0 (fi (windowHeight - borderWidth)) windowWidth borderWidth (bxBottom borderColors)+      drawLineWith dpy pixmap gc (fi (windowWidth - borderWidth)) 0 borderWidth windowHeight (bxRight borderColors)++    -- and now again+    io $ setForeground dpy gc bgColor+    io $ fillRectangle dpy pixmap gc (fi borderWidth) (fi borderWidth) (windowWidth - (borderWidth * 2)) (windowHeight - (borderWidth * 2))++    -- paint strings+    forM_ (zip widgets $ widgetLayout $ ddWidgetPlaces dd) $ \(widget, place) ->+        paintWidget deco (dpy, pixmap, gc) place shrinker dd widget isExpose++    -- debug+    -- black <- stringToPixel dpy "black"+    -- io $ setForeground dpy gc black+    -- forM_ (ddWidgetPlaces dd) $ \(WidgetPlace {wpRectangle = Rectangle x y w h}) ->+    --   io $ drawRectangle dpy pixmap gc x y w h++    -- copy the pixmap over the window+    io $ copyArea      dpy pixmap win gc 0 0 windowWidth windowHeight 0 0+    -- free the pixmap and GC+    io $ freePixmap    dpy pixmap+    io $ freeGC        dpy gc+  where+    drawLineWith dpy pixmap gc x y w h colorName = do+      color <- stringToPixel dpy colorName+      io $ setForeground dpy gc color+      io $ fillRectangle dpy pixmap gc x y w h+
+ XMonad/Layout/DecorationEx/Geometry.hs view
@@ -0,0 +1,87 @@+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE UndecidableInstances #-}++-----------------------------------------------------------------------------+-- |+-- Module      :  XMonad.Layout.DecorationEx.Geometry+-- Description :  Type class which is responsible for defining the placement+--                of window decorations+-- Copyright   :  (c) 2007 Andrea Rossato, 2009 Jan Vornberger, 2023 Ilya Portnov+-- License     :  BSD-style (see xmonad/LICENSE)+--+-- Maintainer  :  portnov84@rambler.ru+-- Stability   :  unstable+-- Portability :  unportable+--+-- This module defines @DecorationGeometry@ type class, and default implementation for it.+-----------------------------------------------------------------------------++module XMonad.Layout.DecorationEx.Geometry (+    DecorationGeometry (..),+    DefaultGeometry (..)+  ) where++import XMonad+import XMonad.Prelude+import qualified XMonad.StackSet as W+import qualified XMonad.Layout.Decoration as D++-- | Decoration geometry class.+-- Decoration geometry is responsible for placement of window decorations: whether+-- they should be on the top of the window or on the bottom, should they go for +-- full window width or only be of certain width, etc.+-- This does not know what will be drawn inside decorations.+class (Read (geom a), Show (geom a),+       Eq a)+    => DecorationGeometry geom a where++    -- | Give a name to decoration geometry implementation.+    describeGeometry :: geom a -> String++    -- | Reduce original window size to make space for decoration, if necessary.+    shrinkWindow :: geom a -> Rectangle -> Rectangle -> Rectangle+    shrinkWindow _ (Rectangle _ _ _ dh) (Rectangle x y w h) = Rectangle x (y + fi dh) w (h - dh)++    -- | The pure version of the main method, 'decorate'.+    -- The method should return a rectangle where to place window decoration,+    -- or 'Nothing' if this window is not to be decorated.+    pureDecoration :: geom a          -- ^ Decoration geometry instance+                   -> Rectangle       -- ^ Screen rectangle+                   -> W.Stack a       -- ^ Current stack of windows being displayed+                   -> [(a,Rectangle)] -- ^ Set of all windows with their corresponding rectangle+                   -> (a,Rectangle)   -- ^ Window being decorated and its rectangle+                   -> Maybe Rectangle++    -- | The method should return a rectangle where to place window decoration,+    -- or 'Nothing' if this window is not to be decorated.+    decorateWindow :: geom a           -- ^ Decoration geometry instance+                   -> Rectangle        -- ^ Screen rectangle+                   -> W.Stack a        -- ^ Current stack of windows being displayed+                   -> [(a, Rectangle)] -- ^ Set of all windows with their corresponding rectangle+                   -> (a, Rectangle)   -- ^ Window being decorated and its rectangle+                   -> X (Maybe Rectangle)+    decorateWindow geom r s wrs wr = return $ pureDecoration geom r s wrs wr++-- | Data type for default implementation of 'DecorationGeometry'.+-- This defines simple decorations: a horizontal bar at the top of each window,+-- running for full width of the window.+newtype DefaultGeometry a = DefaultGeometry {+    gDecorationHeight :: Dimension+  }+  deriving (Read, Show)++instance Eq a => DecorationGeometry DefaultGeometry a where+  describeGeometry _ = "Default"++  pureDecoration (DefaultGeometry {..}) _ s _ (w, Rectangle x y windowWidth windowHeight) =+      if D.isInStack s w && (gDecorationHeight < windowHeight)+        then Just $ Rectangle x y windowWidth gDecorationHeight+        else Nothing++instance Default (DefaultGeometry a) where+  def = DefaultGeometry 20+
+ XMonad/Layout/DecorationEx/LayoutModifier.hs view
@@ -0,0 +1,322 @@+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE UndecidableInstances #-}++-----------------------------------------------------------------------------+-- |+-- Module      :  XMonad.Layout.DecorationEx.LayoutModifier+-- Description :  Layout modifier which adds decorations to windows.+-- Copyright   :  (c) 2007 Andrea Rossato, 2009 Jan Vornberger, 2023 Ilya Portnov+-- License     :  BSD-style (see xmonad/LICENSE)+--+-- Maintainer  :  portnov84@rambler.ru+-- Stability   :  unstable+-- Portability :  unportable+--+-- Layout modifier, which is responsible for creation of decoration rectangles+-- (windows), updating and removing them when needed. It is parameterized by+-- @DecorationGeometry@, which says where decorations should be placed, and by+-- @DecorationEngine@, which says how decorations should look.+-----------------------------------------------------------------------------++module XMonad.Layout.DecorationEx.LayoutModifier (+    -- * Usage+    --+    -- $usage+    decorationEx,+    DecorationEx+  ) where++import XMonad+import XMonad.Prelude+import qualified XMonad.StackSet as W+import XMonad.Layout.LayoutModifier+import XMonad.Layout.WindowArranger (diff, listFromList)+import XMonad.Util.Invisible+import XMonad.Util.XUtils hiding (paintTextAndIcons)++import XMonad.Layout.DecorationEx.Common+import XMonad.Layout.DecorationEx.Engine+import XMonad.Layout.DecorationEx.Geometry++-- $usage+--+-- This module exports @decorationEx@ function, which is a generic function for+-- adding decorations to your layouts. It can be used to use different+-- decoration geometries and engines in any combination.+-- For most used combinations, there are convenience functions in+-- "XMonad.Layout.DecorationEx.TextEngine", "XMonad.Layout.DecorationEx.TabbedGeometry",+-- and "XMonad.Layout.DecorationEx.DwmGeometry".+--+-- You can use this module with the following in your+-- @xmonad.hs@:+--+-- > import XMonad.Layout.DecorationEx.LayoutModifier+-- Then edit your @layoutHook@ by adding the DwmStyle decoration to+-- your layout:+--+-- > myL = decorationEx shrinkText myTheme myEngine myGeometry (layoutHook def)+-- >         where+-- >           myGeometry = DefaultGeometry -- or another geometry type+-- >           myEngine = TextDecoration    -- or another decoration engine+-- >           myTheme = GenericTheme {...} -- theme type should correspond to selected engine type+-- >+-- > main = xmonad def { layoutHook = myL }+--+-- For more detailed instructions on editing the layoutHook see:+--+-- "XMonad.Doc.Extending#Editing_the_layout_hook"+++-- | The 'DecorationEx' 'LayoutModifier'. This data type is an instance+-- of the 'LayoutModifier' class. This data type will be passed,+-- together with a layout, to the 'ModifiedLayout' type constructor+-- to modify the layout by adding decorations according to a+-- 'DecorationEngine'.+data DecorationEx engine widget geom shrinker a =+    DecorationEx (Invisible Maybe (DecorationLayoutState engine)) shrinker (Theme engine widget) (engine widget a) (geom a)++deriving instance (Show (Theme engine widget), Show shrinker, Show (engine widget a), Show (geom a)) => Show (DecorationEx engine widget geom shrinker a)+deriving instance (Read (Theme engine widget), Read shrinker, Read (engine widget a), Read (geom a)) => Read (DecorationEx engine widget geom shrinker a)++-- | The long 'LayoutModifier' instance for the 'DecorationEx' type.+--+-- In 'redoLayout' we check the state: if there is no state we+-- initialize it.+--+-- The state is @diff@ed against the list of windows produced by the+-- underlying layout: removed windows get deleted and new ones+-- decorated by 'createDecos', which will call 'decorate' to decide if+-- a window must be given a 'Rectangle', in which case a decoration+-- window will be created.+--+-- After that we resync the updated state with the windows' list and+-- then we process the resynced stated (as we do with a new state).+--+-- First we map the decoration windows, we update each decoration to+-- reflect any decorated window's change, and we insert, in the list+-- of windows and rectangles returned by the underlying layout, the+-- decoration for each window. This way xmonad will restack the+-- decorations and their windows accordingly. At the end we remove+-- invisible\/stacked windows.+--+-- Message handling is quite simple: when needed we release the state+-- component of the 'DecorationEx' 'LayoutModifier'. Otherwise we call+-- 'handleEvent', which will call the appropriate 'DecorationEngine'+-- methods to perform its tasks.+instance (DecorationEngine engine widget Window, DecorationGeometry geom Window, Shrinker shrinker) => LayoutModifier (DecorationEx engine widget geom shrinker) Window where+    redoLayout (DecorationEx (I (Just decoState)) shrinker theme engine geom) _ Nothing _ = do+        releaseResources engine decoState+        return ([], Just $ DecorationEx (I Nothing) shrinker theme engine geom)+    redoLayout _ _ Nothing _  = return ([], Nothing)++    redoLayout (DecorationEx invState shrinker theme engine geom) screenRect (Just stack) srcPairs+        | I Nothing  <- invState = initState theme engine geom shrinker screenRect stack srcPairs >>= processState+        | I (Just s) <- invState = do+            let decorations  = dsDecorations s+                (d,a) = curry diff (getOrigWindows decorations) srcWindows+                toDel = todel d decorations+                toAdd = toadd a srcPairs+            deleteDecos toDel+            let decosToBeAdded = [WindowDecoration win rect Nothing Nothing [] | (win, rect) <- toAdd]+            newDecorations <- resync (dsStyleState s) (decosToBeAdded ++ del_dwrs d decorations) srcPairs+            processState (s {dsDecorations = newDecorations})++        where+          srcWindows = map fst srcPairs++          getOrigWindows :: [WindowDecoration] -> [Window]+          getOrigWindows = map wdOrigWindow++          del_dwrs :: [Window] -> [WindowDecoration] -> [WindowDecoration]+          del_dwrs = listFromList wdOrigWindow notElem++          findDecoWindow :: Int -> [WindowDecoration] -> Maybe Window+          findDecoWindow i d = wdDecoWindow $ d !! i++          todel :: [Window] -> [WindowDecoration] -> [WindowDecoration]+          todel d = filter (\dd -> wdOrigWindow dd `elem` d)++          toadd :: [Window] -> [(Window, Rectangle)] -> [(Window, Rectangle)]+          toadd a = filter (\p -> fst p `elem` a)++          createDecoWindowIfNeeded :: Maybe Window -> Maybe Rectangle -> X (Maybe Window)+          createDecoWindowIfNeeded mbDecoWindow mbDecoRect =+            case (mbDecoWindow, mbDecoRect) of+              (Nothing, Just decoRect) -> do+                decoWindow <- createDecoWindow engine theme decoRect+                return $ Just decoWindow+              _ -> return mbDecoWindow++          resync :: DecorationEngineState engine -> [WindowDecoration] -> [(Window,Rectangle)] -> X [WindowDecoration]+          resync _ _ [] = return []+          resync decoState dd ((window,rect):xs) =+            case  window `elemIndex` getOrigWindows dd of+              Just i  -> do+                mbDecoRect <- decorateWindow geom screenRect stack srcPairs (window,rect)+                widgetPlaces <- case mbDecoRect of+                                  Nothing -> return $ WidgetLayout [] [] []+                                  Just decoRect -> placeWidgets engine theme shrinker decoState decoRect window (themeWidgets theme)+                mbDecoWindow  <- createDecoWindowIfNeeded (findDecoWindow i dd) mbDecoRect+                let newDd = WindowDecoration window rect mbDecoWindow mbDecoRect (widgetLayout widgetPlaces)+                restDd <- resync decoState dd xs+                return $ newDd : restDd+              Nothing -> resync decoState dd xs++          -- We drop any windows that are *precisely* stacked underneath+          -- another window: these must be intended to be tabbed!+          removeTabbed :: [Rectangle] -> [(Window, Rectangle)] -> [(Window, Rectangle)]+          removeTabbed _ [] = []+          removeTabbed rs ((w,r):xs)+              | r `elem` rs = removeTabbed rs xs+              | otherwise   = (w,r) : removeTabbed (r:rs) xs++          insertDwr :: WindowDecoration -> [(Window, Rectangle)] -> [(Window, Rectangle)]+          insertDwr dd wrs =+            case (wdDecoWindow dd, wdDecoRect dd) of+              (Just decoWindow, Just decoRect) -> (decoWindow, decoRect) : (wdOrigWindow dd, shrinkWindow geom decoRect (wdOrigWinRect dd)) : wrs+              _ -> (wdOrigWindow dd, wdOrigWinRect dd) : wrs++          dwrs_to_wrs :: [WindowDecoration] -> [(Window, Rectangle)]+          dwrs_to_wrs = removeTabbed [] . foldr insertDwr []++          processState :: DecorationLayoutState engine -> X ([(Window, Rectangle)], Maybe (DecorationEx engine widget geom shrinker Window))+          processState st = do+            let decorations = dsDecorations st+            showDecos decorations+            updateDecos engine shrinker theme (dsStyleState st) decorations+            return (dwrs_to_wrs decorations, Just (DecorationEx (I (Just (st {dsDecorations = decorations}))) shrinker theme engine geom))++    handleMess (DecorationEx (I (Just st)) shrinker theme engine geom) m+        | Just Hide <- fromMessage m = do+            hideDecos $ dsDecorations st+            return Nothing+--         | Just (SetTheme nt) <- fromMessage m = do+--             releaseResources engine st+--             let t' = themeEx nt+--             return $ Just $ DecorationEx (I Nothing) shrinker t' engine+        | Just ReleaseResources <- fromMessage m = do+            releaseResources engine st+            return $ Just $ DecorationEx (I Nothing) shrinker theme  engine geom+        | Just e <- fromMessage m = do+            decorationEventHookEx engine theme st shrinker e+            handleEvent engine shrinker theme st e+            return Nothing+    handleMess _ _ = return Nothing++    modifierDescription (DecorationEx _ _ _ engine geom) = describeEngine engine ++ describeGeometry geom++-- | By default 'DecorationEx' handles 'PropertyEvent' and 'ExposeEvent'+-- only.+handleEvent :: (Shrinker shrinker, DecorationEngine engine widget Window) => engine widget Window -> shrinker -> Theme engine widget -> DecorationLayoutState engine -> Event -> X ()+handleEvent engine shrinker theme (DecorationLayoutState {..}) e+    | PropertyEvent {ev_window = w, ev_atom = atom} <- e+    , Just i <- w `elemIndex` map wdOrigWindow dsDecorations = do+        supportedAtoms <- propsToRepaintDecoration engine+        when (atom `elem` supportedAtoms) $ do+          -- io $ putStrLn $ "property event on " ++ show w -- ++ ": " ++ fromMaybe "<?>" atomName+          updateDeco engine shrinker theme dsStyleState (dsDecorations !! i) False+    | ExposeEvent   {ev_window = w} <- e+    , Just i <- w `elemIndex` mapMaybe wdDecoWindow dsDecorations = do+        -- io $ putStrLn $ "expose event on " ++ show w+        updateDeco engine shrinker theme dsStyleState (dsDecorations !! i) True+handleEvent _ _ _ _ _ = return ()++-- | Initialize the 'DecorationState' by initializing the font+-- structure and by creating the needed decorations.+initState :: (DecorationEngine engine widget Window, DecorationGeometry geom Window, Shrinker shrinker)+          => Theme engine widget+          -> engine widget Window+          -> geom Window+          -> shrinker+          -> Rectangle+          -> W.Stack Window+          -> [(Window,Rectangle)] -> X (DecorationLayoutState engine)+initState theme engine geom shrinker screenRect stack wrs = do+  styleState <- initializeState engine geom theme+  decorations <- createDecos theme engine geom shrinker styleState screenRect stack wrs wrs+  return $ DecorationLayoutState styleState decorations++-- | Delete windows stored in the state and release the font structure.+releaseResources :: DecorationEngine engine widget Window => engine widget Window -> DecorationLayoutState engine -> X ()+releaseResources engine st = do+  deleteDecos (dsDecorations st)+  releaseStateResources engine (dsStyleState st)++-- | Create the decoration windows of a list of windows and their+-- rectangles, by calling the 'decorate' method of the+-- 'DecorationStyle' received.+createDecos :: (DecorationEngine engine widget Window, DecorationGeometry geom Window, Shrinker shrinker)+            => Theme engine widget+            -> engine widget Window+            -> geom Window+            -> shrinker+            -> DecorationEngineState engine+            -> Rectangle+            -> W.Stack Window+            -> [(Window,Rectangle)] -> [(Window,Rectangle)] -> X [WindowDecoration]+createDecos theme engine geom shrinker decoState screenRect stack wrs ((w,r):xs) = do+  mbDecoRect <- decorateWindow geom screenRect stack wrs (w,r)+  case mbDecoRect of+    Just decoRect -> do+      decoWindow <- createDecoWindow engine theme decoRect+      widgetPlaces <- placeWidgets engine theme shrinker decoState decoRect w (themeWidgets theme)+      restDd <- createDecos theme engine geom shrinker decoState screenRect stack wrs xs+      let newDd = WindowDecoration w r (Just decoWindow) (Just decoRect) $ widgetLayout widgetPlaces+      return $ newDd : restDd+    Nothing -> do+      restDd <- createDecos theme engine geom shrinker decoState screenRect stack wrs xs+      let newDd = WindowDecoration w r Nothing Nothing []+      return $ newDd : restDd+createDecos _ _ _ _ _ _ _ _ [] = return []++createDecoWindow :: (DecorationEngine engine widget Window) => engine widget Window -> Theme engine widget -> Rectangle -> X Window+createDecoWindow engine theme rect = do+  let mask = Just $ decorationXEventMask engine+  w <- createNewWindow rect mask (defaultBgColor theme) True+  d <- asks display+  io $ setClassHint d w (ClassHint "xmonad-decoration" "xmonad")+  return w++showDecos :: [WindowDecoration] -> X ()+showDecos dd =+  showWindows $ mapMaybe wdDecoWindow $ filter (isJust . wdDecoRect) dd++hideDecos :: [WindowDecoration] -> X ()+hideDecos = hideWindows . mapMaybe wdDecoWindow++deleteDecos :: [WindowDecoration] -> X ()+deleteDecos = deleteWindows . mapMaybe wdDecoWindow++updateDecos :: (Shrinker shrinker, DecorationEngine engine widget Window)+            => engine widget Window -> shrinker -> Theme engine widget -> DecorationEngineState engine -> [WindowDecoration] -> X ()+updateDecos engine shrinker theme decoState = mapM_ (\wd -> updateDeco engine shrinker theme decoState wd False)++-- | Update a decoration window given a shrinker, a theme, the font+-- structure and the needed 'Rectangle's+updateDeco :: (Shrinker shrinker, DecorationEngine engine widget Window) => engine widget Window -> shrinker -> Theme engine widget -> DecorationEngineState engine -> WindowDecoration -> Bool -> X ()+updateDeco engine shrinker theme decoState wd isExpose =+  case (wdDecoWindow wd, wdDecoRect wd) of+    (Just decoWindow, Just decoRect@(Rectangle _ _ wh ht)) -> do+      let origWin = wdOrigWindow wd+      drawData <- mkDrawData engine theme decoState origWin decoRect+      widgetPlaces <- placeWidgets engine theme shrinker decoState decoRect (wdOrigWindow wd) (themeWidgets theme)+      -- io $ print widgetPlaces+      paintDecoration engine decoWindow wh ht shrinker (drawData {ddWidgetPlaces = widgetPlaces}) isExpose+    (Just decoWindow, Nothing) -> hideWindow decoWindow+    _ -> return ()++-- | Apply a DecorationEx modifier to an underlying layout+decorationEx :: (DecorationEngine engine widget a, DecorationGeometry geom a, Shrinker shrinker)+             => shrinker             -- ^ Strings shrinker, for example @shrinkText@+             -> Theme engine widget  -- ^ Decoration theme+             -> engine widget a      -- ^ Decoration engine instance+             -> geom a               -- ^ Decoration geometry instance+             -> l a                  -- ^ Underlying layout to be decorated+             -> ModifiedLayout (DecorationEx engine widget geom shrinker) l a+decorationEx shrinker theme engine geom = ModifiedLayout (DecorationEx (I Nothing) shrinker theme engine geom)+
+ XMonad/Layout/DecorationEx/TabbedGeometry.hs view
@@ -0,0 +1,169 @@+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE RecordWildCards #-}++-----------------------------------------------------------------------------+-- |+-- Module      :  XMonad.Layout.DecorationEx.TabbedGeometry+-- Description :  Tab-based window decoration geometry+-- Copyright   :  (c) 2007 Andrea Rossato, 2023 Ilya Portnov+-- License     :  BSD-style (see xmonad/LICENSE)+--+-- Maintainer  :  portnov84@rambler.ru+-- Stability   :  unstable+-- Portability :  unportable+--+-- This module defines window decoration geometry based on tabs.+-- The tabs can follow horizontally and be placed above or below windows;+-- in such case, tabs can occupy full width of the window or be aligned to+-- left or right. Or tabs can go vertically near left or right side of+-- the window.+-----------------------------------------------------------------------------++module XMonad.Layout.DecorationEx.TabbedGeometry (+    textTabbed,+    TabbedGeometry (..),+    HorizontalTabPlacement (..),+    VerticalTabPlacement (..),+    HorizontalTabWidth (..),+    HorizontalTabsAlignment (..),+    SingleTabMode (..)+  ) where ++import XMonad+import qualified XMonad.StackSet as W+import XMonad.Prelude+import XMonad.Layout.Decoration (ModifiedLayout, Shrinker (..))++import XMonad.Layout.DecorationEx.LayoutModifier+import XMonad.Layout.DecorationEx.Common+import XMonad.Layout.DecorationEx.Geometry+import XMonad.Layout.DecorationEx.Widgets+import XMonad.Layout.DecorationEx.TextEngine++-- | Placement of tabs when they go horizontally:+-- should they be placed above or below the window.+data HorizontalTabPlacement = Top | Bottom+  deriving (Eq, Read, Show)++-- | Placement of tabs when they go vertically:+-- should they appear at left or at right side of the window.+data VerticalTabPlacement = TabsAtLeft | TabsAtRight+  deriving (Eq, Read, Show)++-- | Width of tabs when they go horizontally.+data HorizontalTabWidth =+      AutoWidth             -- ^ Define the width automatically by evenly dividing windows' width+    | FixedWidth !Dimension -- ^ Use fixed width of the tab+  deriving (Eq, Read, Show)++-- | Alignment of tabs when they go horizontally.+data HorizontalTabsAlignment = AlignTabsLeft | AlignTabsCenter | AlignTabsRight+  deriving (Eq, Read, Show)++-- | What to do if there is only one tab.+data SingleTabMode = ShowTab | HideTab+  deriving (Eq, Read, Show)++data TabbedGeometry a =+      HorizontalTabs {+          showIfSingleWindow :: !SingleTabMode      -- ^ What to do if there is only one tab+        , hTabPlacement :: !HorizontalTabPlacement  -- ^ Where to place horizontal tabs+        , hTabAlignment :: !HorizontalTabsAlignment -- ^ How to align horizontal tabs (makes sense with fixed width of tabs).+        , hTabWidth :: !HorizontalTabWidth          -- ^ Width of horizontal tabs+        , hTabHeight :: !Dimension                  -- ^ Height of horizontal tabs+      }+    | VerticalTabs {+          showIfSingleWindow :: !SingleTabMode      -- ^ What to do if there is only one tab+        , vTabPlacement :: !VerticalTabPlacement    -- ^ Where to place vertical tabs+        , vTabWidth :: !Dimension                   -- ^ Width of vertical tabs+        , vTabHeight :: !Dimension                  -- ^ Height of vertical tabs+      }+  deriving (Show, Read)++instance Default (TabbedGeometry a) where+  def = HorizontalTabs ShowTab Top AlignTabsLeft AutoWidth 20 ++instance DecorationGeometry TabbedGeometry Window where++  describeGeometry _ = "Tabbed"++  pureDecoration tabs _ stack wrs (window, windowRect) =+    let Rectangle windowX windowY windowWidth windowHeight = windowRect+        -- windows that are mapped onto the same rectangle as current one are considered to+        -- be in one tabs group+        tabbedWindows = filter (`elem` map fst (filter ((==windowRect) . snd) wrs)) (W.integrate stack)+        mbWindowIndex = window `elemIndex` tabbedWindows+        numWindows = length tabbedWindows+    in  if numWindows > 1 || (showIfSingleWindow tabs == ShowTab && numWindows > 0)+          then+            case tabs of+              HorizontalTabs {..} ->+                  Just $ case hTabPlacement of+                            Top    -> Rectangle decoX windowY effectiveTabWidth hTabHeight+                            Bottom -> Rectangle decoX (windowY + fi (windowHeight - hTabHeight)) effectiveTabWidth hTabHeight+                where+                  decoX = maybe windowX tabX mbWindowIndex++                  -- If there are too many windows or configured tab width+                  -- is too big, then we have to switch to 'auto' mode.+                  hTabWidth' =+                    case hTabWidth of+                      AutoWidth -> AutoWidth+                      FixedWidth tabWidth+                        | tabWidth * fi numWindows > windowWidth -> AutoWidth+                        | otherwise -> FixedWidth tabWidth++                  effectiveTabWidth =+                    case hTabWidth' of+                      AutoWidth -> fi $ maybe windowX (\i -> tabX (i+1) - tabX i) mbWindowIndex+                      FixedWidth tabWidth -> tabWidth++                  allTabsWidth =+                    case hTabWidth' of+                      AutoWidth -> fi windowWidth+                      FixedWidth _ -> fi $ min windowWidth $ effectiveTabWidth * max 1 (fi numWindows)++                  tabsStartX =+                    case hTabAlignment of+                      AlignTabsLeft -> windowX+                      AlignTabsRight -> windowX + fi windowWidth - allTabsWidth+                      AlignTabsCenter -> windowX + (fi windowWidth - allTabsWidth) `div` 2++                  -- X coordinate of i'th window in horizontal tabs layout+                  tabX i = tabsStartX ++                        case hTabWidth' of+                          AutoWidth -> fi ((windowWidth * fi i) `div` max 1 (fi numWindows))+                          FixedWidth _ -> fi effectiveTabWidth * fi i++              VerticalTabs {..} ->+                  Just $ case vTabPlacement of+                            TabsAtLeft  -> fixHeightTab windowX+                            TabsAtRight -> fixHeightTab (windowX + fi (windowWidth - vTabWidth))+                where+                  fixHeightLoc i = windowY + fi vTabHeight * fi i+                  fixHeightTab x = Rectangle x+                        (maybe windowY fixHeightLoc mbWindowIndex) vTabWidth vTabHeight+          else Nothing++  shrinkWindow tabs (Rectangle _ _ dw dh) (Rectangle x y w h) =+    case tabs of+      HorizontalTabs {..} ->+        case hTabPlacement of+            Top -> Rectangle x (y + fi dh) w (h - dh)+            Bottom -> Rectangle x y w (h - dh)+      VerticalTabs {..} ->+        case vTabPlacement of+            TabsAtLeft  -> Rectangle (x + fi dw) y (w - dw) h+            TabsAtRight -> Rectangle x y (w - dw) h++-- | Add tabbed decorations (with default settings) with text-based widgets to a layout.+textTabbed :: (Shrinker shrinker)+           => shrinker               -- ^ Strings shrinker, e.g. @shrinkText@+           -> ThemeEx StandardWidget -- ^ Decoration theme+           -> l Window               -- ^ Layout to be decorated+           -> ModifiedLayout (DecorationEx TextDecoration StandardWidget TabbedGeometry shrinker) l Window+textTabbed shrinker theme = decorationEx shrinker theme TextDecoration def+
+ XMonad/Layout/DecorationEx/TextEngine.hs view
@@ -0,0 +1,116 @@+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UndecidableInstances #-}++-----------------------------------------------------------------------------+-- |+-- Module      :  XMonad.Layout.DecorationEx.TextEngine+-- Description :  Text-based window decoration engine+-- Copyright   :  (c) 2007 Andrea Rossato, 2009 Jan Vornberger, 2023 Ilya Portnov+-- License     :  BSD-style (see xmonad/LICENSE)+--+-- Maintainer  :  portnov84@rambler.ru+-- Stability   :  unstable+-- Portability :  unportable+--+-- Window decoration engine, that uses text fragments (like @"[X]"@) to indicate+-- widgets (window buttons).+-----------------------------------------------------------------------------++module XMonad.Layout.DecorationEx.TextEngine (+    textDecoration,+    TextDecoration (..)+  ) where ++import XMonad+import XMonad.Prelude+import XMonad.Layout.LayoutModifier+import XMonad.Util.Font++import XMonad.Layout.DecorationEx.LayoutModifier+import XMonad.Layout.DecorationEx.Common+import XMonad.Layout.DecorationEx.Engine+import XMonad.Layout.DecorationEx.Geometry+import XMonad.Layout.DecorationEx.Widgets++-- | Decoration engine data type+data TextDecoration widget a = TextDecoration+  deriving (Show, Read)++instance (TextWidget widget, ClickHandler (GenericTheme SimpleStyle) widget)+  => DecorationEngine TextDecoration widget Window where+  type Theme TextDecoration = GenericTheme SimpleStyle+  type DecorationPaintingContext TextDecoration = XPaintingContext+  type DecorationEngineState TextDecoration = XMonadFont++  describeEngine _ = "TextDecoration"++  calcWidgetPlace = calcTextWidgetPlace++  paintWidget = paintTextWidget++  paintDecoration = paintDecorationSimple++  initializeState _ _ theme = initXMF (themeFontName theme)+  releaseStateResources _ = releaseXMF++-- | Implementation of @paintWidget@ for decoration engines based on @TextDecoration@.+paintTextWidget :: (TextWidget widget,+                    Style (Theme engine widget) ~ SimpleStyle,+                    DecorationPaintingContext engine ~ XPaintingContext,+                    DecorationEngineState engine ~ XMonadFont,+                    Shrinker shrinker,+                    DecorationEngine engine widget Window)+                => engine widget Window+                -> DecorationPaintingContext engine+                -> WidgetPlace+                -> shrinker+                -> DrawData engine widget+                -> widget+                -> Bool+                -> X ()+paintTextWidget engine (dpy, pixmap, gc) place shrinker dd widget _ = do+    let style = ddStyle dd+        rect = wpRectangle place+        x = rect_x rect+        y = wpTextYPosition place+    str <- widgetString dd widget+    str' <- if isShrinkable widget+              then getShrinkedWindowName engine shrinker (ddEngineState dd) str (rect_width rect) (rect_height rect)+              else return str+    printStringXMF dpy pixmap (ddEngineState dd) gc (sTextColor style) (sTextBgColor style) x y str'++-- | Implementation of @calcWidgetPlace@ for decoration engines based on @TextDecoration@.+calcTextWidgetPlace :: (TextWidget widget,+                        DecorationEngineState engine ~ XMonadFont,+                        DecorationEngine engine widget Window)+                    => engine widget Window+                    -> DrawData engine widget+                    -> widget+                    -> X WidgetPlace+calcTextWidgetPlace _ dd widget = do+    str <- widgetString dd widget+    let h = rect_height (ddDecoRect dd)+        font = ddEngineState dd+    withDisplay $ \dpy -> do+      width <- fi <$> textWidthXMF dpy (ddEngineState dd) str+      (a, d) <- textExtentsXMF font str+      let height = a + d+          y = fi $ (h - fi height) `div` 2+          y0 = y + fi a+          rect = Rectangle 0 y width (fi height)+      return $ WidgetPlace y0 rect++-- | Add decoration to existing layout. Widgets are indicated by text fragments, like @"[+]"@.+-- Geometry is simple: a horizontal panel at the top of each window, going for the full width+-- of the window.+textDecoration :: (Shrinker shrinker)+               => shrinker                -- ^ String shrinker, for example @shrinkText@+               -> Theme TextDecoration StandardWidget  -- ^ Decoration theme (font, colors, widgets, etc)+               -> l Window                -- ^ Layout to be decorated+             -> ModifiedLayout (DecorationEx TextDecoration StandardWidget DefaultGeometry shrinker) l Window+textDecoration shrinker theme = decorationEx shrinker theme TextDecoration def+
+ XMonad/Layout/DecorationEx/Widgets.hs view
@@ -0,0 +1,208 @@+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-}+-----------------------------------------------------------------------------+-- |+-- Module      :  XMonad.Layout.DecorationEx.Widgets+-- Description :  Definitions for decoration widgets (window buttons etc)+-- Copyright   :  2023 Ilya Portnov+-- License     :  BSD-style (see xmonad/LICENSE)+--+-- Maintainer  :  portnov84@rambler.ru+-- Stability   :  unstable+-- Portability :  unportable+--+-- This module contains data types and utilities to deal with decoration+-- widgets. A widget is anything that is displayed on window decoration,+-- and, optionally, can react on clicks. Examples of widgets are usual+-- window buttons (minimize, maximize, close), window icon and window title.+-----------------------------------------------------------------------------++module XMonad.Layout.DecorationEx.Widgets (+    -- * Data types+    StandardCommand (..),+    TextWidget (..),+    GenericWidget (..),+    StandardWidget,+    -- * Utility functions+    isWidgetChecked,+    -- * Presets for standard widgets+    titleW, toggleStickyW, minimizeW,+    maximizeW, closeW, dwmpromoteW,+    moveToNextGroupW,moveToPrevGroupW+  ) where ++import XMonad+import qualified XMonad.StackSet as W+import XMonad.Actions.DwmPromote+import qualified XMonad.Actions.CopyWindow as CW+import qualified XMonad.Layout.Groups.Examples as Ex+import XMonad.Layout.Maximize+import XMonad.Actions.Minimize+import XMonad.Actions.WindowMenu++import XMonad.Layout.DecorationEx.Common+import XMonad.Layout.DecorationEx.Engine++-- | Standard window commands.+--+-- One can extend this list by simply doing+--+-- > data MyWindowCommand =+-- >     Std StandardCommand+-- >   | SomeFancyCommand+--+-- > instance WindowCommand MyWindowCommand where ...+--+-- > type MyWidget = GenericWidget MyWindowCommand+--+data StandardCommand =+      FocusWindow      -- ^ Focus the window+    | FocusUp          -- ^ Move focus to previous window+    | FocusDown        -- ^ Move focus to following window+    | MoveToNextGroup  -- ^ Move the window to the next group (see "XMonad.Layout.Groups")+    | MoveToPrevGroup  -- ^ Move the window to the previous group+    | DwmPromote       -- ^ Execute @dwmpromote@ (see "XMonad.Actions.DwmPromote")+    | ToggleSticky     -- ^ Make window sticky or unstick it (see "XMonad.Actions.CopyWindow")+    | ToggleMaximize   -- ^ Maximize or restore window (see "XMonad.Layout.Maximize")+    | Minimize         -- ^ Minimize window (see "XMonad.Actions.Minimize")+    | CloseWindow      -- ^ Close the window+    | GridWindowMenu   -- ^ Show window menu via "XMonad.Actions.GridSelect" (see "XMonad.Actions.WindowMenu")+  deriving (Eq, Show, Read)++instance Default StandardCommand where+  def = FocusWindow++instance WindowCommand StandardCommand where+  executeWindowCommand FocusWindow w = do+    focus w+    return False+  executeWindowCommand FocusUp _ = do+    windows W.focusUp+    withFocused maximizeWindowAndFocus+    return True+  executeWindowCommand FocusDown _ = do+    windows W.focusDown+    withFocused maximizeWindowAndFocus+    return True+  executeWindowCommand MoveToNextGroup w = do+    focus w+    Ex.moveToGroupDown False+    return True+  executeWindowCommand MoveToPrevGroup w = do+    focus w+    Ex.moveToGroupUp False+    return True+  executeWindowCommand CloseWindow w = do+    killWindow w+    return True+  executeWindowCommand DwmPromote w = do+    focus w+    dwmpromote+    return True+  executeWindowCommand ToggleSticky w = do+    focus w+    copies <- CW.wsContainingCopies+    if null copies+      then windows CW.copyToAll+      else CW.killAllOtherCopies+    return True+  executeWindowCommand ToggleMaximize w = do+    sendMessage $ maximizeRestore w+    focus w+    return True+  executeWindowCommand Minimize w = do+    minimizeWindow w+    return True+  executeWindowCommand GridWindowMenu w = do+    focus w+    windowMenu+    return True++  isCommandChecked FocusWindow _ = return False+  isCommandChecked DwmPromote w = do+      withWindowSet $ \ws -> return $ Just w == master ws+    where+      master ws =+        case W.integrate' $ W.stack $ W.workspace $ W.current ws of+          [] -> Nothing+          (x:_) -> Just x+  isCommandChecked ToggleSticky w = do+    ws <- gets windowset+    let copies = CW.copiesOfOn (Just w) (CW.taggedWindows $ W.hidden ws)+    return $ not $ null copies+  isCommandChecked _ _ = return False++-- | Generic data type for decoration widgets.+data GenericWidget cmd =+      TitleWidget                      -- ^ Window title (just text label)+    | WindowIcon { swCommand :: !cmd } -- ^ Window icon with some associated command+    -- | Other widgets+    | GenericWidget {+        swCheckedText :: !String       -- ^ Text for checked widget state+      , swUncheckedText :: !String     -- ^ Text for unchecked widget state+      , swCommand :: !cmd              -- ^ Window command+    }+    deriving (Show, Read)++-- | Generic widget type specialized for 'StandardCommand'+type StandardWidget = GenericWidget StandardCommand++instance (Default cmd, Read cmd, Show cmd, WindowCommand cmd) => DecorationWidget (GenericWidget cmd) where++  type WidgetCommand (GenericWidget cmd) = cmd++  widgetCommand TitleWidget _ = def+  widgetCommand w 1 = swCommand w+  widgetCommand _ _ = def++  isShrinkable TitleWidget = True+  isShrinkable _ = False++-- | Check if the widget should be displayed in `checked' state.+isWidgetChecked :: DecorationWidget widget => widget -> Window -> X Bool+isWidgetChecked wdt = isCommandChecked (widgetCommand wdt 1)++-- | Type class for widgets that can be displayed as+-- text fragments by 'TextDecoration' engine.+class DecorationWidget widget => TextWidget widget where+  widgetString :: DrawData engine widget -> widget -> X String++instance TextWidget StandardWidget where+    widgetString dd TitleWidget = return $ ddWindowTitle dd+    widgetString _ (WindowIcon {}) = return "[*]"+    widgetString dd w = do+      checked <- isWidgetChecked w (ddOrigWindow dd)+      if checked+        then return $ swCheckedText w+        else return $ swUncheckedText w++-- | Widget for window title+titleW :: StandardWidget+titleW = TitleWidget++-- | Widget for ToggleSticky command.+toggleStickyW :: StandardWidget+toggleStickyW = GenericWidget "[S]" "[s]" ToggleSticky++-- | Widget for Minimize command+minimizeW :: StandardWidget+minimizeW = GenericWidget "" "[_]" Minimize++-- | Widget for ToggleMaximize command+maximizeW :: StandardWidget+maximizeW = GenericWidget "" "[O]" ToggleMaximize++-- | Widget for CloseWindow command+closeW :: StandardWidget+closeW = GenericWidget "" "[X]" CloseWindow++dwmpromoteW :: StandardWidget+dwmpromoteW = GenericWidget "[M]" "[m]" DwmPromote++moveToNextGroupW :: StandardWidget+moveToNextGroupW = GenericWidget "" "[>]" MoveToNextGroup++moveToPrevGroupW :: StandardWidget+moveToPrevGroupW = GenericWidget "" "[<]" MoveToPrevGroup+
XMonad/Layout/DecorationMadness.hs view
@@ -17,7 +17,7 @@     ( -- * Usage       -- $usage -      -- * Decorated layouts based on Circle+      -- * Decorated layouts based on CircleEx       -- $circle       circleSimpleDefault     , circleDefault@@ -94,13 +94,13 @@ import XMonad.Layout.TabBarDecoration  import XMonad.Layout.Accordion-import XMonad.Layout.Circle+import XMonad.Layout.CircleEx import XMonad.Layout.WindowArranger import XMonad.Layout.SimpleFloat  -- $usage -- You can use this module with the following in your--- @~\/.xmonad\/xmonad.hs@:+-- @xmonad.hs@: -- -- > import XMonad.Layout.DecorationMadness --@@ -108,9 +108,9 @@ -- -- > main = xmonad def { layoutHook = someMadLayout } ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook". -- -- You can also edit the default theme: --@@ -132,39 +132,39 @@ -- "XMonad.Util.Themes"  -- $circle--- Here you will find 'Circle' based decorated layouts.+-- Here you will find 'CircleEx' based decorated layouts. --- | A 'Circle' layout with the xmonad default decoration, default+-- | A 'CircleEx' layout with the xmonad default decoration, default -- theme and default shrinker. -- -- Here you can find a screen shot: -- -- <http://code.haskell.org/~arossato/xmonadShots/circleSimpleDefault.png>-circleSimpleDefault :: ModifiedLayout (Decoration DefaultDecoration DefaultShrinker) Circle Window-circleSimpleDefault = decoration shrinkText def DefaultDecoration Circle+circleSimpleDefault :: ModifiedLayout (Decoration DefaultDecoration DefaultShrinker) CircleEx Window+circleSimpleDefault = decoration shrinkText def DefaultDecoration circle  -- | Similar to 'circleSimpleDefault' but with the possibility of -- setting a custom shrinker and a custom theme. circleDefault :: Shrinker s => s -> Theme-              -> ModifiedLayout (Decoration DefaultDecoration s) Circle Window-circleDefault s t = decoration s t DefaultDecoration Circle+              -> ModifiedLayout (Decoration DefaultDecoration s) CircleEx Window+circleDefault s t = decoration s t DefaultDecoration circle --- | A 'Circle' layout with the xmonad simple decoration, default+-- | A 'CircleEx' layout with the xmonad simple decoration, default -- theme and default shrinker. -- -- Here you can find a screen shot: -- -- <http://code.haskell.org/~arossato/xmonadShots/circleSimpleDeco.png>-circleSimpleDeco :: ModifiedLayout (Decoration SimpleDecoration DefaultShrinker) Circle Window-circleSimpleDeco = decoration shrinkText def (Simple True) Circle+circleSimpleDeco :: ModifiedLayout (Decoration SimpleDecoration DefaultShrinker) CircleEx Window+circleSimpleDeco = decoration shrinkText def (Simple True) circle  -- | Similar to 'circleSimpleDece' but with the possibility of -- setting a custom shrinker and a custom theme. circleDeco :: Shrinker s => s -> Theme-           -> ModifiedLayout (Decoration SimpleDecoration s) Circle Window-circleDeco s t = decoration s t (Simple True) Circle+           -> ModifiedLayout (Decoration SimpleDecoration s) CircleEx Window+circleDeco s t = decoration s t (Simple True) circle --- | A 'Circle' layout with the xmonad default decoration, default+-- | A 'CircleEx' layout with the xmonad default decoration, default -- theme and default shrinker, but with the possibility of moving -- windows with the mouse, and resize\/move them with the keyboard. --@@ -172,17 +172,17 @@ -- -- <http://code.haskell.org/~arossato/xmonadShots/circleSimpleDefaultResizable.png> circleSimpleDefaultResizable :: ModifiedLayout (Decoration DefaultDecoration DefaultShrinker)-                                (ModifiedLayout MouseResize (ModifiedLayout WindowArranger Circle)) Window-circleSimpleDefaultResizable = decoration shrinkText def DefaultDecoration (mouseResize $ windowArrange Circle)+                                (ModifiedLayout MouseResize (ModifiedLayout WindowArranger CircleEx)) Window+circleSimpleDefaultResizable = decoration shrinkText def DefaultDecoration (mouseResize $ windowArrange circle)  -- | Similar to 'circleSimpleDefaultResizable' but with the -- possibility of setting a custom shrinker and a custom theme. circleDefaultResizable :: Shrinker s => s -> Theme                        -> ModifiedLayout (Decoration DefaultDecoration s)-                          (ModifiedLayout MouseResize (ModifiedLayout WindowArranger Circle)) Window-circleDefaultResizable s t = decoration s t DefaultDecoration (mouseResize $ windowArrange Circle)+                          (ModifiedLayout MouseResize (ModifiedLayout WindowArranger CircleEx)) Window+circleDefaultResizable s t = decoration s t DefaultDecoration (mouseResize $ windowArrange circle) --- | A 'Circle' layout with the xmonad simple decoration, default+-- | A 'CircleEx' layout with the xmonad simple decoration, default -- theme and default shrinker, but with the possibility of moving -- windows with the mouse, and resize\/move them with the keyboard. --@@ -190,45 +190,45 @@ -- -- <http://code.haskell.org/~arossato/xmonadShots/circleSimpleDecoResizable.png> circleSimpleDecoResizable :: ModifiedLayout (Decoration SimpleDecoration DefaultShrinker)-                             (ModifiedLayout MouseResize (ModifiedLayout WindowArranger Circle)) Window-circleSimpleDecoResizable = decoration shrinkText def (Simple True) (mouseResize $ windowArrange Circle)+                             (ModifiedLayout MouseResize (ModifiedLayout WindowArranger CircleEx)) Window+circleSimpleDecoResizable = decoration shrinkText def (Simple True) (mouseResize $ windowArrange circle)  -- | Similar to 'circleSimpleDecoResizable' but with the -- possibility of setting a custom shrinker and a custom theme. circleDecoResizable :: Shrinker s => s -> Theme                     -> ModifiedLayout (Decoration SimpleDecoration s)-                       (ModifiedLayout MouseResize (ModifiedLayout WindowArranger Circle)) Window-circleDecoResizable s t = decoration s t (Simple True) (mouseResize $ windowArrange Circle)+                       (ModifiedLayout MouseResize (ModifiedLayout WindowArranger CircleEx)) Window+circleDecoResizable s t = decoration s t (Simple True) (mouseResize $ windowArrange circle) --- | A 'Circle' layout with the xmonad DwmStyle decoration, default+-- | A 'CircleEx' layout with the xmonad DwmStyle decoration, default -- theme and default shrinker. -- -- Here you can find a screen shot: -- -- <http://code.haskell.org/~arossato/xmonadShots/circleSimpleDwmStyle.png>-circleSimpleDwmStyle :: ModifiedLayout (Decoration DwmStyle DefaultShrinker) Circle Window-circleSimpleDwmStyle = decoration shrinkText def Dwm Circle+circleSimpleDwmStyle :: ModifiedLayout (Decoration DwmStyle DefaultShrinker) CircleEx Window+circleSimpleDwmStyle = decoration shrinkText def Dwm circle  -- | Similar to 'circleSimpleDwmStyle' but with the -- possibility of setting a custom shrinker and a custom theme. circleDwmStyle :: Shrinker s => s -> Theme-               -> ModifiedLayout (Decoration DwmStyle s) Circle Window-circleDwmStyle s t = decoration s t Dwm Circle+               -> ModifiedLayout (Decoration DwmStyle s) CircleEx Window+circleDwmStyle s t = decoration s t Dwm circle --- | A 'Circle' layout with the xmonad tabbed decoration, default+-- | A 'CircleEx' layout with the xmonad tabbed decoration, default -- theme and default shrinker. -- -- Here you can find a screen shot: -- -- <http://code.haskell.org/~arossato/xmonadShots/circleSimpleTabbed.png>-circleSimpleTabbed :: ModifiedLayout (Decoration TabBarDecoration DefaultShrinker) (ModifiedLayout ResizeScreen Circle) Window-circleSimpleTabbed = simpleTabBar Circle+circleSimpleTabbed :: ModifiedLayout (Decoration TabBarDecoration DefaultShrinker) (ModifiedLayout ResizeScreen CircleEx) Window+circleSimpleTabbed = simpleTabBar circle  -- | Similar to 'circleSimpleTabbed' but with the -- possibility of setting a custom shrinker and a custom theme. circleTabbed :: Shrinker s => s -> Theme-             -> ModifiedLayout (Decoration TabBarDecoration s) (ModifiedLayout ResizeScreen Circle) Window-circleTabbed s t = tabBar s t Top (resizeVertical (fi $ decoHeight t) Circle)+             -> ModifiedLayout (Decoration TabBarDecoration s) (ModifiedLayout ResizeScreen CircleEx) Window+circleTabbed s t = tabBar s t Top (resizeVertical (fi $ decoHeight t) circle)   -- $accordion
XMonad/Layout/Dishes.hs view
@@ -27,7 +27,7 @@ import XMonad.Prelude (ap)  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Layout.Dishes --@@ -36,9 +36,9 @@ -- > myLayout = Dishes 2 (1/6) ||| Full ||| etc.. -- > main = xmonad def { layoutHook = myLayout } ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook".  data Dishes a = Dishes Int Rational deriving (Show, Read) instance LayoutClass Dishes a where
XMonad/Layout/DragPane.hs view
@@ -35,7 +35,7 @@ import XMonad.Util.XUtils  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Layout.DragPane --@@ -44,9 +44,9 @@ -- > myLayout = dragPane Horizontal 0.1 0.5 ||| Full ||| etc.. -- > main = xmonad def { layoutHook = myLayout } ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook".  halfHandleWidth :: Integral a => a halfHandleWidth = 1
XMonad/Layout/Drawer.hs view
@@ -41,7 +41,7 @@ import XMonad.Layout.Reflect  -- $usage--- To use this module, add the following import to @~\/.xmonad\/xmonad.hs@:+-- To use this module, add the following import to @xmonad.hs@: -- -- > import XMonad.Layout.Drawer --
XMonad/Layout/Dwindle.hs view
@@ -68,9 +68,9 @@ -- 1.1, is the factor by which the third parameter increases or decreases in -- response to Expand or Shrink messages. ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook".  -- | Layouts with geometrically decreasing window sizes.  'Spiral' and 'Dwindle' -- split the screen into a rectangle for the first window and a rectangle for@@ -159,8 +159,8 @@         nwins   = length wins         sizes   = take nwins $ unfoldr (\r -> Just (r * ratio, r * ratio)) 1         totals' = 0 : zipWith (+) sizes totals'-        totals  = tail totals'-        splits  = zip (tail sizes) totals+        totals  = drop 1 totals'+        splits  = zip (drop 1 sizes) totals         ratios  = reverse $ map (uncurry (/)) splits         rects   = genRects rect ratios         genRects r []     = [r]
XMonad/Layout/DwmStyle.hs view
@@ -30,7 +30,7 @@  -- $usage -- You can use this module with the following in your--- @~\/.xmonad\/xmonad.hs@:+-- @xmonad.hs@: -- -- > import XMonad.Layout.DwmStyle --@@ -40,9 +40,9 @@ -- > myL = dwmStyle shrinkText def (layoutHook def) -- > main = xmonad def { layoutHook = myL } ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook". -- -- You can also edit the default configuration options. --
XMonad/Layout/FixedAspectRatio.hs view
@@ -38,7 +38,7 @@ import           XMonad.Layout.LayoutHints  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Layout.FixedAspectRatio -- Then add it to your layout:@@ -53,8 +53,8 @@ -- depending on the size hints (for example for programs like mpv), -- see "XMonad.Layout.LayoutHints" ----- See "XMonad.Doc.Extending#Editing_the_layout_hook" for more info on--- the 'layoutHook'.+-- See <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook" for more info on the 'layoutHook'. -- -- You also want to add keybindings to set and clear the aspect ratio: --@@ -73,7 +73,7 @@ -- -- >  , ((modMask .|. shiftMask, xK_c), withFocused (sendMessage . ResetRatio) >> kill) ----- See "XMonad.Doc.Extending#Editing_key_bindings" for more info+-- See <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> for more info -- on customizing the keybindings. -- -- This layout also comes with a 'ManageHook' 'doFixAspect' to@@ -84,7 +84,8 @@ -- >   ... -- > ] ----- Check "XMonad.Doc.Extending#Editing_the_manage_hook" for more information on+-- Check <https://xmonad.org/TUTORIAL.html#final-touches the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_manage_hook" for more information on -- customizing the manage hook.  -- | Similar to 'layoutHintsWithReplacement', but relies on the user to
XMonad/Layout/FixedColumn.hs view
@@ -28,7 +28,7 @@ import qualified XMonad.StackSet as W  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Layout.FixedColumn --@@ -37,9 +37,9 @@ -- > myLayout = FixedColumn 1 20 80 10 ||| Full ||| etc.. -- > main = xmonad def { layoutHook = myLayout } ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook".  -- | A tiling mode based on preserving a nice fixed width --   window. Supports 'Shrink', 'Expand' and 'IncMasterN'.
+ XMonad/Layout/FocusTracking.hs view
@@ -0,0 +1,85 @@+{-# LANGUAGE MultiParamTypeClasses, TypeSynonymInstances #-}+{- |++Module      :  XMonad.Layout.FocusTracking+Description :  Track focus in the tiled layer.+Copyright   :  (c) 2010 & 2013 Adam Vogt+                   2011 Willem Vanlint+                   2018 & 2022 L.S.Leary+License     :  BSD-style (see xmonad/LICENSE)++Maintainer  :  @LSLeary (on github)+Stability   :  unstable+Portability :  unportable++FocusTracking simply holds onto the last true focus it was given and continues+to use it as the focus for the transformed layout until it sees another. It can+be used to improve the behaviour of a child layout that has not been given the+focused window, or equivalently, that of the layout itself when a float has+focus.++Relevant issues:++  * <http://code.google.com/p/xmonad/issues/detail?id=4>+  * <http://code.google.com/p/xmonad/issues/detail?id=306>++--------------------------------------------------------------------------------+-}+module XMonad.Layout.FocusTracking+    ( -- * Usage+      -- $usage+      FocusTracking(..)+    , focusTracking+    ) where++import XMonad.Prelude+import XMonad+import XMonad.Layout.LayoutModifier+import XMonad.Util.Stack (findZ)+import qualified XMonad.StackSet as W++-- $usage+--+-- To use the module, first import it:+--+-- > import XMonad.Layout.FocusTracking+--+-- Then, a focus-dependent layout can be made to fall back on the last focus it+-- saw, for example:+--+-- > main = xmonad def+-- >  { layoutHook = someParentLayoutWith aChild (focusTracking anotherChild)+-- >  , ...+-- >  }+--+-- Or in a simpler case:+--+-- > main = xmonad def+-- >  { layoutHook = myTiledLayout ||| focusTracking Full+-- >  , ...+-- >  }+--++-- | A 'LayoutModifier' that remembers the last focus it saw.+newtype FocusTracking a = FocusTracking (Maybe Window)+    deriving (Read, Show)++instance LayoutModifier FocusTracking Window where+    modifyLayoutWithUpdate (FocusTracking mw) ws@W.Workspace{ W.stack = ms } r+      = do+        xCur <- gets (W.peek . W.view (W.tag ws) . windowset)+        let isF = xCur /= (W.focus <$> ms)+            -- use the remembered focus point when true focus differs from+            -- what this (sub)layout is given, which happens e.g. when true+            -- focus is in floating layer or when another sublayout has focus+            newStack | isF = (mw >>= \w -> findZ (w==) ms) <|> ms+                     | otherwise = ms+            newState | isF = mw+                     | otherwise = xCur+        ran <- runLayout ws{ W.stack = newStack } r+        return (ran, guard (newState /= mw) $> FocusTracking newState)++-- | Transform a layout into one that remembers and uses the last focus it saw.+focusTracking ::  l a -> ModifiedLayout FocusTracking l a+focusTracking = ModifiedLayout (FocusTracking Nothing)+
XMonad/Layout/Gaps.hs view
@@ -44,7 +44,7 @@ import XMonad.Util.Types (Direction2D(..))  -- $usage--- You can use this module by importing it into your @~\/.xmonad\/xmonad.hs@ file:+-- You can use this module by importing it into your @xmonad.hs@ file: -- -- > import XMonad.Layout.Gaps --
XMonad/Layout/Grid.hs view
@@ -25,7 +25,7 @@ import XMonad.StackSet  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Layout.Grid --@@ -40,9 +40,9 @@ -- -- > myLayout = GridRatio (4/3) ||| etc. ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook".  data Grid a = Grid | GridRatio Double deriving (Read, Show) @@ -61,7 +61,7 @@     mincs = max 1 $ nwins `div` ncols     extrs = nwins - ncols * mincs     chop :: Int -> Dimension -> [(Position, Dimension)]-    chop n m = ((0, m - k * fromIntegral (pred n)) :) . map (, k) . tail . reverse . take n . tail . iterate (subtract k') $ m'+    chop n m = ((0, m - k * fromIntegral (pred n)) :) . map (, k) . drop 1 . reverse . take n . drop 1 . iterate (subtract k') $ m'         where         k :: Dimension         k = m `div` fromIntegral n
XMonad/Layout/Groups.hs view
@@ -105,8 +105,8 @@ -- seed. All keys generated with this method will be different -- provided you don't use 'gen' again with a key from the list. -- (if you need to do that, see 'split' instead)-gen :: Uniq -> (Uniq, [Uniq])-gen (U i1 i2) = (U (i1+1) i2, map (U i1) [i2..])+gen :: Uniq -> (Uniq, Stream Uniq)+gen (U i1 i2) = (U (i1+1) i2, fmap (U i1) (fromList [i2..]))  -- | Split an infinite list into two. I ended up not -- needing this, but let's keep it just in case.@@ -197,16 +197,16 @@  modifyGroups :: (Zipper (Group l a) -> Zipper (Group l a))              -> Groups l l2 a -> Groups l l2 a-modifyGroups f g = let (seed', ids) = gen (seed g)-                       defaultGroups = fromJust $ singletonZ $ G (ID (head ids) $ baseLayout g) emptyZ+modifyGroups f g = let (seed', ident :~ _) = gen (seed g)+                       defaultGroups = fromJust $ singletonZ $ G (ID ident $ baseLayout g) emptyZ                    in g { groups = fromMaybe defaultGroups . f . Just $ groups g                         , seed = seed' }  modifyGroupsX :: (Zipper (Group l a) -> X (Zipper (Group l a)))               -> Groups l l2 a -> X (Groups l l2 a) modifyGroupsX f g = do-  let (seed', ids) = gen (seed g)-      defaultGroups = fromJust $ singletonZ $ G (ID (head ids) $ baseLayout g) emptyZ+  let (seed', ident :~ _) = gen (seed g)+      defaultGroups = fromJust $ singletonZ $ G (ID ident $ baseLayout g) emptyZ   g' <- f . Just $ groups g   return g { groups = fromMaybe defaultGroups g', seed = seed' } @@ -218,12 +218,12 @@ -- other stack changes as gracefully as possible. readapt :: Eq a => Zipper a -> Groups l l2 a -> Groups l l2 a readapt z g = let mf = getFocusZ z-                  (seed', ids) = gen $ seed g+                  (seed', ident :~ _) = gen $ seed g                   g' = g { seed = seed' }               in flip modifyGroups g' $ mapZ_ (onZipper $ removeDeleted z)                                         >>> filterKeepLast (isJust . gZipper)                                         >>> findNewWindows (W.integrate' z)-                                        >>> addWindows (ID (head ids) $ baseLayout g)+                                        >>> addWindows (ID ident $ baseLayout g)                                         >>> focusGroup mf                                         >>> onFocusedZ (onZipper $ focusWindow mf)     where filterKeepLast _ Nothing = Nothing@@ -379,10 +379,10 @@ -- | Apply a ModifySpec. applySpec :: ModifySpec -> Groups l l2 Window -> Maybe (Groups l l2 Window) applySpec f g =-    let (seed', ids) =  gen $ seed g-        g' = flip modifyGroups g $ f (ID (head ids) $ baseLayout g)+    let (seed', ident :~ ids) =  gen $ seed g -- gen generates an infinite list+        g' = flip modifyGroups g $ f (ID ident $ baseLayout g)                                    >>> toTags-                                   >>> foldr (reID g) ((tail ids, []), [])+                                   >>> foldr (reID g) ((ids, []), [])                                    >>> snd                                    >>> fromTags     in if groups g == groups g'@@ -391,10 +391,10 @@  applySpecX :: ModifySpecX -> Groups l l2 Window -> X (Maybe (Groups l l2 Window)) applySpecX f g = do-    let (seed', ids) = gen $ seed g-    g' <- flip modifyGroupsX g $ f (ID (head ids) $ baseLayout g)+    let (seed', ident :~ ids) = gen $ seed g -- gen generates an infinite list+    g' <- flip modifyGroupsX g $ f (ID ident $ baseLayout g)                                 >>> fmap toTags-                                >>> fmap (foldr (reID g) ((tail ids, []), []))+                                >>> fmap (foldr (reID g) ((ids, []), []))                                 >>> fmap snd                                 >>> fmap fromTags     return $ if groups g == groups g'@@ -403,14 +403,13 @@  reID :: Groups l l2 Window      -> Either (Group l Window) (Group l Window)-     -> (([Uniq], [Uniq]), [Either (Group l Window) (Group l Window)])-     -> (([Uniq], [Uniq]), [Either (Group l Window) (Group l Window)])-reID _ _ (([], _), _) = undefined -- The list of ids is infinite-reID g eg ((id:ids, seen), egs) = if myID `elem` seen-                                  then ((ids, seen), mapE_ (setID id) eg:egs)-                                  else ((id:ids, myID:seen), eg:egs)-    where myID = getID $ gLayout $ fromE eg-          setID id (G (ID _ _) z) = G (ID id $ baseLayout g) z+     -> ((Stream Uniq, [Uniq]), [Either (Group l Window) (Group l Window)])+     -> ((Stream Uniq, [Uniq]), [Either (Group l Window) (Group l Window)])+reID g eg ((ident :~ ids, seen), egs)+    | myID `elem` seen = ((ids, seen), mapE_ (setID ident) eg:egs)+    | otherwise = ((ident :~ ids, myID:seen), eg:egs)+  where myID = getID $ gLayout $ fromE eg+        setID id (G (ID _ _) z) = G (ID id $ baseLayout g) z  -- ** Misc. ModifySpecs 
XMonad/Layout/Groups/Examples.hs view
@@ -1,5 +1,8 @@ {-# OPTIONS_GHC -fno-warn-missing-signatures #-}-{-# LANGUAGE MultiParamTypeClasses, Rank2Types, TypeFamilies #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}  ----------------------------------------------------------------------------- -- |@@ -59,7 +62,6 @@  import XMonad.Layout.ZoomRow import XMonad.Layout.Tabbed-import XMonad.Layout.Named import XMonad.Layout.Renamed import XMonad.Layout.Decoration import XMonad.Layout.Simplest@@ -74,7 +76,7 @@ -- -- > import XMonad.Layout.Groups.Examples ----- to the top of your @.\/.xmonad\/xmonad.hs@.+-- to the top of your @xmonad.hs@. -- -- For more information on using any of the layouts, jump directly --   to its \"Example\" section.@@ -85,8 +87,8 @@ --   the "XMonad.Layout.Groups.Helpers" module, which are all --   re-exported by this module. ----- For more information on how to extend your layour hook and key bindings, see---   "XMonad.Doc.Extending".+-- For more information on how to extend your layoutHook and key bindings, see+-- <https://xmonad.org/TUTORIAL.html the tutorial> and "XMonad.Doc.Extending".   -- * Helper: ZoomRow of Group elements@@ -209,13 +211,13 @@  mirrorTallTabs c = _tab c $ G.group _tabs $ _horiz c ||| Full ||| _vert c -_tabs = named "Tabs" Simplest+_tabs = renamed [Replace "Tabs"] Simplest  _tab c l = renamed [CutWordsLeft 1] $ addTabs (tabsShrinker c) (tabsTheme c) l -_vert c = named "Vertical" $ Tall (vNMaster c) (vIncrement c) (vRatio c)+_vert c = renamed [Replace "Vertical"] $ Tall (vNMaster c) (vIncrement c) (vRatio c) -_horiz c = named "Horizontal" $ Mirror $ Tall (hNMaster c) (hIncrement c) (hRatio c)+_horiz c = renamed [Replace "Horizontal"] $ Mirror $ Tall (hNMaster c) (hIncrement c) (hRatio c)  -- | Increase the number of master groups by one increaseNMasterGroups :: X ()
XMonad/Layout/Groups/Helpers.hs view
@@ -58,7 +58,7 @@ -- -- > import XMonad.Layout.Groups.Helpers ----- to the top of your @.\/.xmonad\/xmonad.hs@.+-- to the top of your @xmonad.hs@. -- -- "XMonad.Layout.Groups"-based layouts do not have the same notion -- of window ordering as the rest of XMonad. For this reason, the usual@@ -83,8 +83,8 @@ -- -- > import qualified XMonad.Layout.Groups as G ----- For more information on how to extend your layour hook and key bindings, see--- "XMonad.Doc.Extending".+-- For more information on how to extend your layoutHook and key bindings, see+-- <https://xmonad.org/TUTORIAL.html the tutorial> and "XMonad.Doc.Extending".  -- ** Layout-generic actions -- #Layout-generic actions#@@ -155,7 +155,7 @@             -> X () focusHelper f g = withFocused $ \w -> do                  ws <- getWindows-                 let (before, tail -> after) = span (/=w) ws+                 let (before, drop 1 -> after) = span (/=w) ws                  let toFocus = g $ after ++ before                  floats <- getFloats                  case filter (f . flip elem floats) toFocus of
XMonad/Layout/Groups/Wmii.hs view
@@ -41,7 +41,6 @@ import XMonad.Layout.Groups.Helpers  import XMonad.Layout.Tabbed-import XMonad.Layout.Named import XMonad.Layout.Renamed import XMonad.Layout.MessageControl import XMonad.Layout.Simplest@@ -67,7 +66,7 @@ -- -- > import XMonad.Layout.Groups.Wmii ----- to the top of your @.\/.xmonad\/xmonad.hs@, and adding 'wmii'+-- to the top of your @xmonad.hs@, and adding 'wmii' -- (with a 'Shrinker' and decoration 'Theme' as -- parameters) to your layout hook, for example: --@@ -80,8 +79,8 @@ -- -- and so on. ----- For more information on how to extend your layout hook and key bindings, see--- "XMonad.Doc.Extending".+-- For more information on how to extend your layoutHook and key bindings, see+-- <https://xmonad.org/TUTORIAL.html the tutorial> and "XMonad.Doc.Extending". -- -- Finally, you will probably want to be able to move focus and windows -- between groups in a consistent fashion. For this, you should take a look@@ -90,8 +89,8 @@  -- | A layout inspired by wmii wmii s t = G.group innerLayout zoomRowG-    where column = named "Column" $ Tall 0 (3/100) (1/2)-          tabs = named "Tabs" Simplest+    where column = renamed [Replace "Column"] $ Tall 0 (3/100) (1/2)+          tabs = renamed [Replace "Tabs"] Simplest           innerLayout = renamed [CutWordsLeft 3]                         $ addTabs s t                         $ ignore NextLayout
XMonad/Layout/Hidden.hs view
@@ -37,7 +37,7 @@  -------------------------------------------------------------------------------- -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Layout.Hidden --@@ -46,9 +46,9 @@ -- > myLayout = hiddenWindows (Tall 1 (3/100) (1/2)) ||| Full ||| etc.. -- > main = xmonad def { layoutHook = myLayout } ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook". -- -- In the key bindings, do something like: --@@ -58,7 +58,7 @@ -- -- For detailed instruction on editing the key bindings see: ----- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  -------------------------------------------------------------------------------- newtype HiddenWindows a = HiddenWindows [Window] deriving (Show, Read)
XMonad/Layout/HintedGrid.hs view
@@ -36,7 +36,7 @@ (.) = fmap  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Layout.HintedGrid --@@ -51,6 +51,7 @@ -- > myLayout = GridRatio (4/3) False ||| etc. -- -- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and -- "XMonad.Doc.Extending#Editing_the_layout_hook".  -- | Automatic mirroring of hinted layouts doesn't work very well, so this
XMonad/Layout/HintedTile.hs view
@@ -27,7 +27,7 @@ import XMonad.Prelude  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Layout.HintedTile --@@ -46,9 +46,9 @@ -- built-in Tall with HintedTile, change @import Xmonad@ to -- @import Xmonad hiding (Tall)@. ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook".  data HintedTile a = HintedTile     { nmaster     :: !Int         -- ^ number of windows in the master pane
XMonad/Layout/IM.hs view
@@ -30,15 +30,16 @@ ) where  import XMonad-import qualified XMonad.StackSet as S import XMonad.Layout.Grid import XMonad.Layout.LayoutModifier+import XMonad.Prelude import XMonad.Util.WindowProperties+import qualified XMonad.StackSet as S  import Control.Arrow (first)  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Layout.IM -- > import Data.Ratio ((%))@@ -55,9 +56,9 @@ -- -- Screenshot: <http://haskell.org/haskellwiki/Image:Xmonad-layout-im.png> ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook".  -- $hints --@@ -109,11 +110,6 @@             wrs <- runLayout (wksp {S.stack = filteredStack}) slaveRect             return (first ((w, masterRect) :) wrs)         Nothing -> runLayout wksp rect---- | Like find, but works with monadic computation instead of pure function.-findM :: Monad m => (a -> m Bool) -> [a] -> m (Maybe a)-findM _ [] = return Nothing-findM f (x:xs) = do { b <- f x; if b then return (Just x) else findM f xs }  -- | This is for compatibility with old configs only and will be removed in future versions! data IM a = IM Rational Property deriving (Read, Show)
XMonad/Layout/ImageButtonDecoration.hs view
@@ -47,7 +47,7 @@  -- $usage -- You can use this module with the following in your--- @~\/.xmonad\/xmonad.hs@:+-- @xmonad.hs@: -- -- > import XMonad.Layout.ImageButtonDecoration --
XMonad/Layout/IndependentScreens.hs view
@@ -42,7 +42,7 @@ import qualified XMonad.StackSet as W  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Layout.IndependentScreens --
XMonad/Layout/LayoutBuilder.hs view
@@ -57,14 +57,16 @@   LayoutN, ) where +import Data.Maybe (maybeToList) import XMonad import XMonad.Prelude (foldM, (<|>), isJust, fromMaybe, isNothing, listToMaybe) import qualified XMonad.StackSet as W+import XMonad.Util.Stack (zipperFocusedAtFirstOf) import XMonad.Util.WindowProperties  -------------------------------------------------------------------------------- -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Layout.LayoutBuilder --@@ -103,9 +105,9 @@ -- -- These examples require "XMonad.Layout.Tabbed". ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook". -- -- You may wish to add the following keybindings: --@@ -114,7 +116,7 @@ -- -- For detailed instruction on editing the key binding see: ----- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  -------------------------------------------------------------------------------- -- $selectWin@@ -452,11 +454,4 @@  -------------------------------------------------------------------------------- differentiate' :: Eq q => Maybe q -> [q] -> Maybe (W.Stack q)-differentiate' _ [] = Nothing-differentiate' Nothing w = W.differentiate w-differentiate' (Just f) w-    | f `elem` w = Just W.Stack { W.focus = f-                                , W.up    = reverse $ takeWhile (/=f) w-                                , W.down  = tail $ dropWhile (/=f) w-                                }-    | otherwise = W.differentiate w+differentiate' = zipperFocusedAtFirstOf . maybeToList
− XMonad/Layout/LayoutBuilderP.hs
@@ -1,208 +0,0 @@-{-# LANGUAGE FlexibleContexts, FlexibleInstances, MultiParamTypeClasses, UndecidableInstances, PatternGuards, ScopedTypeVariables #-}--------------------------------------------------------------------------------- |--- Module      :  XMonad.Layout.LayoutBuilderP--- Description :  (DEPRECATED) An old version of "XMonad.Layout.LayoutBuilderP".--- Copyright   :  (c) 2009 Anders Engstrom <ankaan@gmail.com>, 2011 Ilya Portnov <portnov84@rambler.ru>--- License     :  BSD3-style (see LICENSE)------ Maintainer  :  Ilya Portnov <portnov84@rambler.ru>--- Stability   :  unstable--- Portability :  unportable------ DEPRECATED.  Use 'XMonad.Layout.LayoutBuilder' instead.-----------------------------------------------------------------------------------module XMonad.Layout.LayoutBuilderP {-# DEPRECATED "Use XMonad.Layout.LayoutBuilder instead" #-} (-  LayoutP (..),-  layoutP, layoutAll,-  B.relBox, B.absBox,-  -- * Overloading ways to select windows-  -- $selectWin-  Predicate (..), Proxy(..),-  ) where--import XMonad-import XMonad.Prelude hiding (Const)-import qualified XMonad.StackSet as W-import XMonad.Util.WindowProperties--import qualified XMonad.Layout.LayoutBuilder as B---- $selectWin------ 'Predicate' exists because layouts are required to be serializable, and--- "XMonad.Util.WindowProperties" is not sufficient (for example it does not--- allow using regular expressions).------ compare "XMonad.Util.Invisible"---- | Type class for predicates. This enables us to manage not only Windows,--- but any objects, for which instance Predicate is defined.------ Another instance exists in XMonad.Util.WindowPropertiesRE in xmonad-extras-class Predicate p w where-  alwaysTrue :: Proxy w -> p         -- ^ A predicate that is always True.-  checkPredicate :: p -> w -> X Bool -- ^ Check if given object (window or smth else) matches that predicate---- | Contains no actual data, but is needed to help select the correct instance--- of 'Predicate'-data Proxy a = Proxy---- | Data type for our layout.-data LayoutP p l1 l2 a =-    LayoutP (Maybe a) (Maybe a) p B.SubBox (Maybe B.SubBox) (l1 a) (Maybe (l2 a))-    deriving (Show,Read)---- | Use the specified layout in the described area windows that match given predicate and send the rest of the windows to the next layout in the chain.---   It is possible to supply an alternative area that will then be used instead, if there are no windows to send to the next layout.-{-# DEPRECATED layoutP "Use XMonad.Layout.LayoutBuilder.layoutP instead." #-}-layoutP :: (Read a, Eq a, LayoutClass l1 a, LayoutClass l2 a, LayoutClass l3 a, Predicate p a) =>-       p-    -> B.SubBox                       -- ^ The box to place the windows in-    -> Maybe B.SubBox                 -- ^ Possibly an alternative box that is used when this layout handles all windows that are left-    -> l1 a                         -- ^ The layout to use in the specified area-    -> LayoutP p l2 l3 a              -- ^ Where to send the remaining windows-    -> LayoutP p l1 (LayoutP p l2 l3) a -- ^ The resulting layout-layoutP prop box mbox sub next = LayoutP Nothing Nothing prop box mbox sub (Just next)---- | Use the specified layout in the described area for all remaining windows.-{-# DEPRECATED layoutAll "Use XMonad.Layout.LayoutBuilder.layoutAll instead." #-}-layoutAll :: forall l1 p a. (Read a, Eq a, LayoutClass l1 a, Predicate p a) =>-       B.SubBox             -- ^ The box to place the windows in-    -> l1 a               -- ^ The layout to use in the specified area-    -> LayoutP p l1 Full a  -- ^ The resulting layout-layoutAll box sub =-  let a = alwaysTrue (Proxy :: Proxy a)-  in  LayoutP Nothing Nothing a box Nothing sub Nothing--instance (LayoutClass l1 w, LayoutClass l2 w, Predicate p w, Show w, Read w, Eq w, Typeable w, Show p, Typeable p) =>-    LayoutClass (LayoutP p l1 l2) w where--        -- | Update window locations.-        runLayout (W.Workspace _ (LayoutP subf nextf prop box mbox sub next) s) rect-            = do (subs,nexts,subf',nextf') <- splitStack s prop subf nextf-                 let selBox = if isJust nextf'-                                then box-                                else fromMaybe box mbox--                 (sublist,sub') <- handle sub subs $ calcArea selBox rect--                 (nextlist,next') <- case next of Nothing -> return ([],Nothing)-                                                  Just n -> do (res,l) <- handle n nexts rect-                                                               return (res,Just l)--                 return (sublist++nextlist, Just $ LayoutP subf' nextf' prop box mbox sub' next' )-              where-                  handle l s' r = do (res,ml) <- runLayout (W.Workspace "" l s') r-                                     let l' = fromMaybe l ml-                                     return (res,l')--        -- |  Propagate messages.-        handleMessage l m-            | Just (IncMasterN _) <- fromMessage m = sendFocus l m-            | Just Shrink         <- fromMessage m = sendFocus l m-            | Just Expand         <- fromMessage m = sendFocus l m-            | otherwise = sendBoth l m--        -- |  Descriptive name for layout.-        description (LayoutP _ _ _ _ _ sub (Just next)) = "layoutP "++ description sub ++" "++ description next-        description (LayoutP _ _ _ _ _ sub Nothing)     = "layoutP "++ description sub---sendSub :: (LayoutClass l1 a, LayoutClass l2 a, Read a, Show a, Eq a, Typeable a, Predicate p a)-        => LayoutP p l1 l2 a -> SomeMessage -> X (Maybe (LayoutP p l1 l2 a))-sendSub (LayoutP subf nextf prop box mbox sub next) m =-    do sub' <- handleMessage sub m-       return $ if isJust sub'-                then Just $ LayoutP subf nextf prop box mbox (fromMaybe sub sub') next-                else Nothing--sendBoth :: (LayoutClass l1 a, LayoutClass l2 a, Read a, Show a, Eq a, Typeable a, Predicate p a)-         => LayoutP p l1 l2 a -> SomeMessage -> X (Maybe (LayoutP p l1 l2 a))-sendBoth l@(LayoutP _ _ _ _ _ _ Nothing) m = sendSub l m-sendBoth (LayoutP subf nextf prop box mbox sub (Just next)) m =-    do sub' <- handleMessage sub m-       next' <- handleMessage next m-       return $ if isJust sub' || isJust next'-                then Just $ LayoutP subf nextf prop box mbox (fromMaybe sub sub') (Just $ fromMaybe next next')-                else Nothing--sendNext :: (LayoutClass l1 a, LayoutClass l2 a, Read a, Show a, Eq a, Typeable a, Predicate p a)-         => LayoutP p l1 l2 a -> SomeMessage -> X (Maybe (LayoutP p l1 l2 a))-sendNext (LayoutP _ _ _ _ _ _ Nothing) _ = return Nothing-sendNext (LayoutP subf nextf prop box mbox sub (Just next)) m =-    do next' <- handleMessage next m-       return $ if isJust next'-                then Just $ LayoutP subf nextf prop box mbox sub next'-                else Nothing--sendFocus :: (LayoutClass l1 a, LayoutClass l2 a, Read a, Show a, Eq a, Typeable a, Predicate p a)-          => LayoutP p l1 l2 a -> SomeMessage -> X (Maybe (LayoutP p l1 l2 a))-sendFocus l@(LayoutP subf _ _ _ _ _ _) m = do foc <- isFocus subf-                                              if foc then sendSub l m-                                                     else sendNext l m--isFocus :: (Show a) => Maybe a -> X Bool-isFocus Nothing = return False-isFocus (Just w) = do ms <- W.stack . W.workspace . W.current <$> gets windowset-                      return $ maybe False (\s -> show w == show (W.focus s)) ms----- | Split given list of objects (i.e. windows) using predicate.-splitBy :: (Predicate p w) => p -> [w] -> X ([w], [w])-splitBy prop = foldM step ([], [])-  where-    step (good, bad) w = do-      ok <- checkPredicate prop w-      return $ if ok-                then (w:good, bad)-                else (good,   w:bad)--splitStack :: (Predicate p w, Eq w) => Maybe (W.Stack w) -> p -> Maybe w -> Maybe w -> X (Maybe (W.Stack w),Maybe (W.Stack w),Maybe w,Maybe w)-splitStack Nothing _ _ _ = return (Nothing,Nothing,Nothing,Nothing)-splitStack (Just s) prop subf nextf = do-    let ws = W.integrate s-    (good, other) <- splitBy prop ws-    let subf'  = foc good subf-        nextf' = foc other nextf-    return ( differentiate' subf' good-           , differentiate' nextf' other-           , subf'-           , nextf'-           )-  where-    foc [] _ = Nothing-    foc l f-      | W.focus s `elem` l = Just $ W.focus s-      | maybe False (`elem` l) f = f-      | otherwise = Just $ head l--calcArea :: B.SubBox -> Rectangle -> Rectangle-calcArea (B.SubBox xpos ypos width height) rect = Rectangle (rect_x rect + fromIntegral xpos') (rect_y rect + fromIntegral ypos') width' height'-    where-        xpos' = calc False xpos $ rect_width rect-        ypos' = calc False ypos $ rect_height rect-        width' = calc True width $ rect_width rect - xpos'-        height' = calc True height $ rect_height rect - ypos'--        calc zneg val tot = fromIntegral $ min (fromIntegral tot) $ max 0 $-            case val of B.Rel v -> floor $ v * fromIntegral tot-                        B.Abs v -> if v<0 || (zneg && v==0)-                                 then fromIntegral tot+v-                                 else v--differentiate' :: Eq q => Maybe q -> [q] -> Maybe (W.Stack q)-differentiate' _ [] = Nothing-differentiate' Nothing w = W.differentiate w-differentiate' (Just f) w-    | f `elem` w = Just $ W.Stack { W.focus = f-                                  , W.up    = reverse $ takeWhile (/=f) w-                                  , W.down  = tail $ dropWhile (/=f) w-                                  }-    | otherwise = W.differentiate w--instance Predicate Property Window where-  alwaysTrue _ = Const True-  checkPredicate = hasProperty
XMonad/Layout/LayoutCombinators.hs view
@@ -51,7 +51,7 @@ import XMonad.Layout.DragPane  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Layout.LayoutCombinators --@@ -61,9 +61,9 @@ -- > myLayout = (Tall 1 (3/100) (1/2) *//* Full)  ||| (Tall 1 (3/100) (1/2) ***||** Full) ||| Full ||| etc.. -- > main = xmonad def { layoutHook = myLayout } ----- For more detailed instructions on editing the @layoutHook@ see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the @layoutHook@ see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook". --  -- $combine@@ -80,7 +80,7 @@          */* , **/* , ***/* , ****/* , ***/** , ****/*** , ***/**** , */**** , **/*** , */*** , */**  -- $dpv--- These combinators combine two layouts using "XMonad.DragPane" in+-- These combinators combine two layouts using "XMonad.Layout.DragPane" in -- vertical mode.  (*||*),(**||*),(***||*),(****||*), (***||**),(****||***),@@ -100,7 +100,7 @@ (*||**)     = combineTwo (dragPane Vertical 0.1 (1/3))  -- $dph--- These combinators combine two layouts using "XMonad.DragPane" in+-- These combinators combine two layouts using "XMonad.Layout.DragPane" in -- horizontal mode.  (*//*),(**//*),(***//*),(****//*), (***//**),(****//***),
XMonad/Layout/LayoutHints.hs view
@@ -47,7 +47,7 @@ import qualified Data.Set as Set  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Layout.LayoutHints --@@ -66,9 +66,9 @@ -- -- > myLayout = layoutHintsToCenter (Tall 1 (3/100) (1/2)) ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook". -- -- To make XMonad reflect changes in window hints immediately, add -- 'hintsEventHook' to your 'handleEventHook'.
XMonad/Layout/LayoutModifier.hs view
@@ -73,7 +73,7 @@ -- -- * "XMonad.Layout.Reflect" ----- * "XMonad.Layout.Named"+-- * "XMonad.Layout.Renamed" -- -- * "XMonad.Layout.WindowNavigation" --
XMonad/Layout/LayoutScreens.hs view
@@ -36,7 +36,7 @@ -- email window at all times, a crude mimic of sticky windows). -- -- You can use this module with the following in your--- @~\/.xmonad\/xmonad.hs@ file:+-- @xmonad.hs@ file: -- -- > import XMonad.Layout.LayoutScreens -- > import XMonad.Layout.TwoPane@@ -57,7 +57,7 @@ -- >   , ((modm .|. controlMask .|. shiftMask, xK_space), rescreen) -- -- For detailed instructions on editing your key bindings, see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  -- | Modify all screens. layoutScreens :: LayoutClass l Int => Int -> l Int -> X ()
XMonad/Layout/LimitWindows.hs view
@@ -44,7 +44,7 @@ import qualified XMonad.StackSet as W  -- $usage--- To use this module, add the following import to @~\/.xmonad\/xmonad.hs@:+-- To use this module, add the following import to @xmonad.hs@: -- -- > import XMonad.Layout.LimitWindows --@@ -56,7 +56,7 @@ -- actions. -- -- For detailed instructions on editing your key bindings, see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>. -- -- See also 'XMonad.Layout.BoringWindows.boringAuto' for keybindings that skip -- the hidden windows.@@ -75,7 +75,7 @@ limitWindows n = ModifiedLayout (LimitWindows FirstN n)  -- | Only display @n@ windows around the focused window. This makes sense with--- layouts that arrange windows linearily, like 'XMonad.Layout.Layout.Accordion'.+-- layouts that arrange windows linearily, like "XMonad.Layout.Accordion". limitSlice :: Int -> l a -> ModifiedLayout LimitWindows l a limitSlice n = ModifiedLayout (LimitWindows Slice n) 
XMonad/Layout/MagicFocus.hs view
@@ -34,7 +34,7 @@ import qualified Data.Map as M  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Layout.MagicFocus --@@ -45,9 +45,9 @@ -- > main = xmonad def { layoutHook = myLayout, -- >                     handleEventHook = promoteWarp } ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook".  -- | Create a new layout which automagically puts the focused window --   in the master area.
XMonad/Layout/Magnifier.hs view
@@ -26,12 +26,15 @@        -- * General combinators       magnify,+      magnifyxy,        -- * Magnify Everything       magnifier,       magnifierOff,       magnifiercz,       magnifierczOff,+      magnifierxy,+      magnifierxyOff,       maxMagnifierOff,       maximizeVertical, @@ -39,6 +42,8 @@       magnifier',       magnifiercz',       magnifierczOff',+      magnifierxy',+      magnifierxyOff',        -- * Messages and Types       MagnifyMsg (..),@@ -54,7 +59,7 @@ import XMonad.StackSet  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Layout.Magnifier --@@ -66,19 +71,19 @@ -- -- By default 'magnifier' increases the focused window's size by @1.5@. ----- You can also use @'magnifiercz' 1.2@ to use a custom level of--- magnification.  You can even make the focused window smaller for a--- pop in effect.  There's also the possibility of starting out not--- magnifying anything at all ('magnifierOff'); see below for ways to--- toggle this on while in use.+-- You can also use @'magnifiercz' 1.2@ or @'magnifierxy' 1 1000@ to use+-- a custom level of magnification. You can even make the focused window+-- smaller for a pop in effect. There's also the possibility of starting+-- out not magnifying anything at all ('magnifierOff'); see below for+-- ways to toggle this on while in use. -- -- The most general combinator available is 'magnify'—all of the other -- functions in this module are essentially just creative applications -- of it. ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook". -- -- Magnifier supports some commands, see 'MagnifyMsg'.  To use them add -- something like this to your key bindings:@@ -101,7 +106,7 @@ -- like @Mag.Toggle@, @Mag.magnifier@, and so on. -- -- For detailed instruction on editing the key binding see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  -- | Add magnification capabilities to a certain layout. --@@ -116,9 +121,23 @@                     --   (@True@) or off (@False@)     -> l a          -- ^ Input layout     -> ModifiedLayout Magnifier l a-magnify cz mt start = ModifiedLayout $-    Mag 1 (fromRational cz, fromRational cz) (bool Off On start) mt+magnify cz = magnifyxy cz cz +-- | Like 'magnify', but with the ability to specify different amounts+-- of horizontal and vertical magnification.+--+-- >>> magnifyxy 1.3 1.6 (NoMaster 1) True+magnifyxy+    :: Rational      -- ^ Amount to magnify horizontally+    -> Rational      -- ^ Amount to magnify vertically+    -> MagnifyThis   -- ^ What to magnify+    -> Bool          -- ^ Whether magnification should start out on+                     --   (@True@) or off (@False@)+    -> l a           -- ^ Input layout+    -> ModifiedLayout Magnifier l a+magnifyxy cx cy mt start = ModifiedLayout $+    Mag 1 (fromRational cx, fromRational cy) (bool Off On start) mt+ -- | Increase the size of the window that has focus magnifier :: l a -> ModifiedLayout Magnifier l a magnifier = magnifiercz 1.5@@ -137,6 +156,24 @@ magnifiercz' :: Rational -> l a -> ModifiedLayout Magnifier l a magnifiercz' cz = magnify cz (NoMaster 1) True +-- | Increase the size of the window that has focus by a custom zoom in+-- both directions.+magnifierxy :: Rational -> Rational -> l a -> ModifiedLayout Magnifier l a+magnifierxy cx cy = magnifyxy cx cy (AllWins 1) True++-- | Like 'magnifierxy', but default to @Off@.+magnifierxyOff :: Rational -> Rational -> l a -> ModifiedLayout Magnifier l a+magnifierxyOff cx cy = magnifyxy cx cy (AllWins 1) False++-- | Increase the size of the window that has focus by a custom zoom in+-- both directions, unless it is one of the master windows.+magnifierxy' :: Rational -> Rational -> l a -> ModifiedLayout Magnifier l a+magnifierxy' cx cy = magnifyxy cx cy (NoMaster 1) True++-- | Like 'magnifierxy'', but defaults to @Off@.+magnifierxyOff' :: Rational -> Rational -> l a -> ModifiedLayout Magnifier l a+magnifierxyOff' cx cy = magnifyxy cx cy (NoMaster 1) False+ -- | Magnifier that defaults to Off magnifierOff :: l a -> ModifiedLayout Magnifier l a magnifierOff = magnifierczOff 1.5@@ -154,7 +191,8 @@ magnifierczOff' :: Rational -> l a -> ModifiedLayout Magnifier l a magnifierczOff' cz = magnify cz (NoMaster 1) False --- | A magnifier that greatly magnifies just the vertical direction+-- | A magnifier that greatly magnifies just the vertical direction;+-- defaults to @Off@. maximizeVertical :: l a -> ModifiedLayout Magnifier l a maximizeVertical = ModifiedLayout (Mag 1 (1, 1000) Off (AllWins 1)) 
XMonad/Layout/Master.hs view
@@ -31,7 +31,7 @@ import Control.Arrow (first)  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Layout.Master --@@ -52,6 +52,7 @@ -- Grid manage the right half. -- -- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and -- "XMonad.Doc.Extending#Editing_the_layout_hook". -- -- Like 'XMonad.Layout.Tall', 'withMaster' supports the
XMonad/Layout/Maximize.hs view
@@ -31,7 +31,7 @@ import XMonad.Prelude ( partition )  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Layout.Maximize --@@ -46,9 +46,9 @@ -- > myLayout = maximizeWithPadding 10 (Tall 1 (3/100) (1/2)) ||| Full ||| etc..) -- > main = xmonad def { layoutHook = myLayout } ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook". -- -- In the key-bindings, do something like: --@@ -57,7 +57,7 @@ -- -- For detailed instruction on editing the key binding see: ----- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  data Maximize a = Maximize Dimension (Maybe Window) deriving ( Read, Show ) maximize :: LayoutClass l Window => l Window -> ModifiedLayout Maximize l Window
XMonad/Layout/MessageControl.hs view
@@ -35,7 +35,7 @@ import Control.Arrow (second)  -- $usage--- You can use this module by importing it into your @~\/.xmonad\/xmonad.hs@ file:+-- You can use this module by importing it into your @xmonad.hs@ file: -- -- > import XMonad.Layout.MessageEscape --
XMonad/Layout/Minimize.hs view
@@ -30,7 +30,7 @@ import qualified XMonad.Util.ExtensibleState as XS  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Layout.Minimize --@@ -39,9 +39,9 @@ -- > myLayout = minimize (Tall 1 (3/100) (1/2)) ||| Full ||| etc.. -- > main = xmonad def { layoutHook = myLayout } ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook". -- -- The module is designed to work together with "XMonad.Layout.BoringWindows" so -- that minimized windows will be skipped over when switching the focused window with
XMonad/Layout/Monitor.hs view
@@ -40,7 +40,7 @@ import XMonad.Hooks.FadeInactive (setOpacity)  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Layout.Monitor --
XMonad/Layout/Mosaic.hs view
@@ -1,4 +1,8 @@-{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, PatternGuards #-}+{-# LANGUAGE DeriveFoldable #-}+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE PatternGuards #-} ----------------------------------------------------------------------------- -- | -- Module      :  XMonad.Layout.Mosaic@@ -37,7 +41,7 @@ import Control.Arrow(second, first)  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Layout.Mosaic --@@ -58,9 +62,9 @@ -- --  > , ((modm, xK_r), sendMessage Reset) ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook".  data Aspect     = Taller@@ -179,16 +183,7 @@ normalize x = let s = sum x in map (/s) x  data Tree a = Branch (Tree a) (Tree a) | Leaf a | Empty--instance Foldable Tree where-   foldMap _f Empty = mempty-   foldMap f (Leaf x) = f x-   foldMap f (Branch l r) = foldMap f l `mappend` foldMap f r--instance Functor Tree where-   fmap f (Leaf x) = Leaf $ f x-   fmap f (Branch l r) = Branch (fmap f l) (fmap f r)-   fmap _ Empty = Empty+  deriving (Functor, Show, Foldable)  instance Semigroup (Tree a) where     Empty <> x = x
XMonad/Layout/MosaicAlt.hs view
@@ -38,7 +38,7 @@ import Data.Ratio  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Layout.MosaicAlt -- > import qualified Data.Map as M@@ -48,9 +48,9 @@ -- > myLayout = MosaicAlt M.empty ||| Full ||| etc.. -- > main = xmonad def { layoutHook = myLayout } ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook". -- -- In the key-bindings, do something like: --@@ -63,7 +63,7 @@ -- -- For detailed instruction on editing the key binding see: ----- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  data HandleWindowAlt =     ShrinkWindowAlt Window
XMonad/Layout/MouseResizableTile.hs view
@@ -20,7 +20,7 @@                                     -- $usage                                     mouseResizableTile,                                     mouseResizableTileMirrored,-                                    MRTMessage (ShrinkSlave, ExpandSlave),+                                    MRTMessage (ShrinkSlave, ExpandSlave, SetMasterFraction, SetLeftSlaveFraction, SetRightSlaveFraction),                                      -- * Parameters                                     -- $mrtParameters@@ -41,7 +41,7 @@ import Graphics.X11 as X  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Layout.MouseResizableTile --@@ -53,9 +53,9 @@ -- > main = xmonad def { layoutHook = myLayout } -- ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook". -- -- You may also want to add the following key bindings: --@@ -64,7 +64,7 @@ -- -- For detailed instruction on editing the key binding see: ----- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  -- $mrtParameters -- The following functions are also labels for updating the @data@ (whose
XMonad/Layout/MultiColumns.hs view
@@ -29,7 +29,7 @@ import XMonad.Prelude  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Layout.MultiColumns --@@ -56,9 +56,9 @@ -- columns, the screen is instead split equally among all columns. Therefore, -- if equal size among all columns are desired, set the size to -0.5. ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook".  -- | Layout constructor. multiCol@@ -96,8 +96,8 @@                       ,fmap incmastern (fromMessage m)]             where resize Shrink = l { multiColSize = max (-0.5) $ s-ds }                   resize Expand = l { multiColSize = min 1 $ s+ds }-                  incmastern (IncMasterN x) = l { multiColNWin = take a n ++ [newval] ++ tail r }-                      where newval =  max 0 $ head r + x+                  incmastern (IncMasterN x) = l { multiColNWin = take a n ++ [newval] ++ drop 1 r }+                      where newval = max 0 $ maybe 0 (x +) (listToMaybe r)                             r = drop a n                   n = multiColNWin l                   ds = multiColDeltaSize l
XMonad/Layout/MultiDishes.hs view
@@ -27,7 +27,7 @@ import XMonad.Prelude (ap)  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Layout.MultiDishes --@@ -53,9 +53,9 @@ -- > |_______| -- > |___|___| ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook".  data MultiDishes a = MultiDishes Int Int Rational deriving (Show, Read) instance LayoutClass MultiDishes a where
XMonad/Layout/Named.hs view
@@ -16,7 +16,7 @@ -- ----------------------------------------------------------------------------- -module XMonad.Layout.Named+module XMonad.Layout.Named {-# DEPRECATED "Use XMonad.Layout.Renamed instead" #-}     ( -- * Usage       -- $usage       named,@@ -27,7 +27,7 @@ import XMonad.Layout.Renamed  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Layout.Named --@@ -37,16 +37,12 @@ -- > myLayout = named "real big" Full ||| (nameTail $ named "real big" $ Full) ||| etc.. -- > main = xmonad def { layoutHook = myLayout } ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook". -- -- Note that this module has been deprecated and may be removed in a future -- release, please use "XMonad.Layout.Renamed" instead.---- | (Deprecated) Rename a layout.-named :: String -> l a -> ModifiedLayout Rename l a-named s = renamed [Replace s]  -- | (Deprecated) Remove the first word of the name. nameTail :: l a -> ModifiedLayout Rename l a
XMonad/Layout/NoBorders.hs view
@@ -45,7 +45,7 @@   -- $usage--- You can use this module with the following in your ~\/.xmonad\/xmonad.hs file:+-- You can use this module with the following in your xmonad.hs file: -- -- > import XMonad.Layout.NoBorders --@@ -54,9 +54,9 @@ -- -- > layoutHook = ... ||| noBorders Full ||| ... ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook".  -- todo, use an InvisibleList. data WithBorder a = WithBorder Dimension [a] deriving ( Read, Show )
XMonad/Layout/NoFrillsDecoration.hs view
@@ -31,7 +31,7 @@  -- $usage -- You can use this module with the following in your--- @~\/.xmonad\/xmonad.hs@:+-- @xmonad.hs@: -- -- > import XMonad.Layout.NoFrillsDecoration --
XMonad/Layout/OnHost.hs view
@@ -34,7 +34,7 @@ import           System.Posix.Env                  (getEnv)  -- $usage--- You can use this module by importing it into your ~\/.xmonad\/xmonad.hs file:+-- You can use this module by importing it into your @xmonad.hs@ file: -- -- > import XMonad.Layout.OnHost --
XMonad/Layout/OneBig.hs view
@@ -55,23 +55,25 @@  -- | Main layout function oneBigLayout :: OneBig a -> Rectangle -> W.Stack a -> [(a, Rectangle)]-oneBigLayout (OneBig cx cy) rect stack = [(master,masterRect)]-                                      ++ divideBottom bottomRect bottomWs-                                      ++ divideRight rightRect rightWs-      where ws = W.integrate stack-            n = length ws-            ht (Rectangle _ _ _ hh) = hh-            wd (Rectangle _ _ ww _) = ww-            h' = round (fromIntegral (ht rect)*cy)-            w = wd rect-            m = calcBottomWs n w h'-            master = head ws-            other  = tail ws-            bottomWs = take m other-            rightWs = drop m other-            masterRect = cmaster n m cx cy rect-            bottomRect = cbottom cy rect-            rightRect  = cright cx cy rect+oneBigLayout (OneBig cx cy) rect stack =+  let ws = W.integrate stack+      n  = length ws+   in case ws of+    []               -> []+    (master : other) -> [(master,masterRect)]+                     ++ divideBottom bottomRect bottomWs+                     ++ divideRight rightRect rightWs+     where+      ht (Rectangle _ _ _ hh) = hh+      wd (Rectangle _ _ ww _) = ww+      h' = round (fromIntegral (ht rect)*cy)+      w = wd rect+      m = calcBottomWs n w h'+      bottomWs = take m other+      rightWs = drop m other+      masterRect = cmaster n m cx cy rect+      bottomRect = cbottom cy rect+      rightRect  = cright cx cy rect  -- | Calculate how many windows must be placed at bottom calcBottomWs :: Int -> Dimension -> Dimension -> Int
XMonad/Layout/PerScreen.hs view
@@ -29,7 +29,7 @@ import XMonad.Prelude (fromMaybe)  -- $usage--- You can use this module by importing it into your ~\/.xmonad\/xmonad.hs file:+-- You can use this module by importing it into your @xmonad.hs@ file: -- -- > import XMonad.Layout.PerScreen --
XMonad/Layout/PerWorkspace.hs view
@@ -29,7 +29,7 @@ import XMonad.Prelude (fromMaybe)  -- $usage--- You can use this module by importing it into your ~\/.xmonad\/xmonad.hs file:+-- You can use this module by importing it into your @xmonad.hs@ file: -- -- > import XMonad.Layout.PerWorkspace --
XMonad/Layout/PositionStoreFloat.hs view
@@ -33,7 +33,7 @@ import XMonad.Prelude (fromMaybe, isJust, nub, when)  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Layout.PositionStoreFloat -- > import XMonad.Layout.NoFrillsDecoration
XMonad/Layout/Reflect.hs view
@@ -32,7 +32,7 @@ import XMonad.Layout.MultiToggle  -- $usage--- You can use this module by importing it into your @~\/.xmonad\/xmonad.hs@ file:+-- You can use this module by importing it into your @xmonad.hs@ file: -- -- > import XMonad.Layout.Reflect --
XMonad/Layout/Renamed.hs view
@@ -19,6 +19,7 @@ module XMonad.Layout.Renamed ( -- * Usage                                -- $usage                                renamed+                             , named                              , Rename(..) ) where  import XMonad@@ -29,7 +30,7 @@ -- -- > import XMonad.Layout.Renamed ----- to your @~\/.xmonad\/xmonad.hs@.+-- to your @xmonad.hs@. -- -- You can then use 'renamed' to modify the description of your -- layouts. For example:@@ -39,6 +40,10 @@ -- | Apply a list of 'Rename' values to a layout, from left to right. renamed :: [Rename a] -> l a -> ModifiedLayout Rename l a renamed = ModifiedLayout . Chain++-- | Rename a layout. (Convenience alias for @renamed [Replace s]@.)+named :: String -> l a -> ModifiedLayout Rename l a+named s = renamed [Replace s]  -- | The available renaming operations data Rename a = CutLeft Int -- ^ Remove a number of characters from the left
XMonad/Layout/ResizableThreeColumns.hs view
@@ -13,7 +13,7 @@ -- -- A layout similar to tall but with three columns. With 2560x1600 pixels this -- layout can be used for a huge main window and up to six reasonable sized--- resizable slave windows.+-- resizable stack windows. -----------------------------------------------------------------------------  module XMonad.Layout.ResizableThreeColumns (@@ -31,7 +31,7 @@ import Data.Ratio  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Layout.ResizableThreeColumns --@@ -45,7 +45,7 @@ -- resizing and the third argument specifies the initial size of the columns. -- A positive size designates the fraction of the screen that the main window -- should occupy, but if the size is negative the absolute value designates the--- fraction a slave column should occupy. If both slave columns are visible,+-- fraction a stack column should occupy. If both stack columns are visible, -- they always occupy the same amount of space. -- -- You may also want to add the following key bindings:@@ -53,11 +53,11 @@ -- > , ((modm,               xK_a), sendMessage MirrorShrink) -- > , ((modm,               xK_z), sendMessage MirrorExpand) ----- The ResizableThreeColMid variant places the main window between the slave columns.------ For more detailed instructions on editing the layoutHook see:+-- The ResizableThreeColMid variant places the main window between the stack columns. ----- "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook".   -- | Arguments are nmaster, delta, fraction@@ -99,8 +99,13 @@       mresize s MirrorExpand = mresize' s (negate delta)       mresize' s delt =         let up = length $ W.up s-            total = up + length (W.down s) + 1-            pos = if up == (nmaster-1) || up == (total-1) then up-1 else up+            down = length $ W.down s+            total = up + down + 1+            pos = if up == nmaster - 1           -- upper right+                  || up == total - 1             -- upper left+                  || up `elem` [down, down + 1]  -- lower right+                  then up - 1+                  else up             mfrac' = modifymfrac (mfrac ++ repeat 1) delt pos         in l { threeColSlaves = take total mfrac'}       modifymfrac [] _ _ = []@@ -128,23 +133,23 @@   | n <= nmaster+1 = splitVertically mf nmaster s1                   ++ splitVertically (drop nmaster mf) (n-nmaster) s2   | otherwise = concat [ splitVertically mf nmaster r1-                       , splitVertically (drop nmaster mf) nslave1 r2-                       , splitVertically (drop (nmaster + nslave1) mf) nslave2 r3+                       , splitVertically (drop nmaster mf) nstack1 r2+                       , splitVertically (drop (nmaster + nstack1) mf) nstack2 r3                        ]   where     (r1, r2, r3) = split3HorizontallyBy middle (if f<0 then 1+2*f else f) r     (s1, s2)     = splitHorizontallyBy (if f<0 then 1+f else f) r-    nslave       = n - nmaster-    nslave1      = ceiling (nslave % 2)-    nslave2      = n - nmaster - nslave1+    nstack       = n - nmaster+    nstack1      = ceiling (nstack % 2)+    nstack2      = nstack - nstack1  splitVertically :: RealFrac r => [r] -> Int -> Rectangle -> [Rectangle] splitVertically [] _ r = [r] splitVertically _ n r | n < 2 = [r] splitVertically (f:fx) n (Rectangle sx sy sw sh) =-  let smallh = min sh (floor $ fromIntegral (sh `div` fromIntegral n) * f)+  let smallh = min sh (floor $ fi (sh `div` fi n) * f)   in Rectangle sx sy sw smallh :-       splitVertically fx (n-1) (Rectangle sx (sy+fromIntegral smallh) sw (sh-smallh))+       splitVertically fx (n-1) (Rectangle sx (sy+fi smallh) sw (sh-smallh))  split3HorizontallyBy :: Bool -> Rational -> Rectangle -> (Rectangle, Rectangle, Rectangle) split3HorizontallyBy middle f (Rectangle sx sy sw sh) =
XMonad/Layout/ResizableTile.hs view
@@ -27,7 +27,7 @@ import qualified Data.Map as M  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Layout.ResizableTile --@@ -36,9 +36,9 @@ -- > myLayout =  ResizableTall 1 (3/100) (1/2) [] ||| etc.. -- > main = xmonad def { layoutHook = myLayout } ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook". -- -- You may also want to add the following key bindings: --@@ -47,7 +47,7 @@ -- -- For detailed instruction on editing the key binding see: ----- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  data MirrorResize = MirrorShrink | MirrorExpand instance Message MirrorResize
XMonad/Layout/ResizeScreen.hs view
@@ -11,9 +11,9 @@ -- Portability :  unportable -- -- A layout transformer to have a layout respect a given screen--- geometry. Mostly used with "Decoration" (the Horizontal and the--- Vertical version will react to SetTheme and change their dimension--- accordingly.+-- geometry. Mostly used with "XMonad.Layout.Decoration" (the+-- Horizontal and the Vertical version will react to SetTheme and+-- change their dimension accordingly. -----------------------------------------------------------------------------  module XMonad.Layout.ResizeScreen@@ -31,7 +31,7 @@  -- $usage -- You can use this module by importing it into your--- @~\/.xmonad\/xmonad.hs@ file:+-- @xmonad.hs@ file: -- -- > import XMonad.Layout.ResizeScreen --@@ -39,9 +39,9 @@ -- -- > layoutHook = resizeHorizontal 40 Full ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook".  resizeHorizontal :: Int -> l a -> ModifiedLayout ResizeScreen l a resizeHorizontal i = ModifiedLayout (ResizeScreen L i)
XMonad/Layout/Roledex.hs view
@@ -27,7 +27,7 @@ import Data.Ratio  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Layout.Roledex --@@ -36,9 +36,9 @@ -- > myLayout =  Roledex ||| etc.. -- > main = xmonad def { layoutHook = myLayout } ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook".  -- $screenshot -- <<http://www.timthelion.com/rolodex.png>>
XMonad/Layout/ShowWName.hs view
@@ -35,15 +35,15 @@  -- $usage -- You can use this module with the following in your--- @~\/.xmonad\/xmonad.hs@:+-- @xmonad.hs@: -- -- > import XMonad.Layout.ShowWName -- > myLayout = layoutHook def -- > main = xmonad def { layoutHook = showWName myLayout } ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook".  -- | A layout modifier to show the workspace name when switching showWName :: l a -> ModifiedLayout ShowWName l a
XMonad/Layout/SimpleDecoration.hs view
@@ -32,7 +32,7 @@  -- $usage -- You can use this module with the following in your--- @~\/.xmonad\/xmonad.hs@:+-- @xmonad.hs@: -- -- > import XMonad.Layout.SimpleDecoration --@@ -42,9 +42,9 @@ -- > myL = simpleDeco shrinkText def (layoutHook def) -- > main = xmonad def { layoutHook = myL } ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook". -- -- You can also edit the default configuration options. --
XMonad/Layout/SimpleFloat.hs view
@@ -33,7 +33,7 @@  -- $usage -- You can use this module with the following in your--- @~\/.xmonad\/xmonad.hs@:+-- @xmonad.hs@: -- -- > import XMonad.Layout.SimpleFloat --@@ -42,9 +42,9 @@ -- > myLayout = simpleFloat ||| Full ||| etc.. -- > main = xmonad def { layoutHook = myLayout } ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook".  -- | A simple floating layout where every window is placed according -- to the window's initial attributes.
XMonad/Layout/Simplest.hs view
@@ -1,4 +1,6 @@-{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TupleSections #-} ----------------------------------------------------------------------------- -- | -- Module      :  XMonad.Layout.Simplest@@ -24,7 +26,7 @@  -- $usage -- You can use this module with the following in your--- @~\/.xmonad\/xmonad.hs@:+-- @xmonad.hs@: -- -- > import XMonad.Layout.Simplest --@@ -33,10 +35,10 @@ -- > myLayout = Simplest ||| Full ||| etc.. -- > main = xmonad def { layoutHook = myLayout } ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook".  data Simplest a = Simplest deriving (Show, Read) instance LayoutClass Simplest a where-    pureLayout Simplest rec (S.Stack w l r) = zip (w : reverse l ++ r) (repeat rec)+    pureLayout Simplest rec (S.Stack w l r) = map (, rec) (w : reverse l ++ r)
XMonad/Layout/SimplestFloat.hs view
@@ -28,7 +28,7 @@  -- $usage -- You can use this module with the following in your--- @~\/.xmonad\/xmonad.hs@:+-- @xmonad.hs@: -- -- > import XMonad.Layout.SimplestFloat --@@ -37,9 +37,9 @@ -- > myLayout = simplestFloat ||| Full ||| etc.. -- > main = xmonad def { layoutHook = myLayout } ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook".  -- | A simple floating layout where every window is placed according -- to the window's initial attributes.
XMonad/Layout/SortedLayout.hs view
@@ -33,7 +33,7 @@  -- $usage -- You can use this module with the following in your--- @~\/.xmonad\/xmonad.hs@:+-- @xmonad.hs@: -- -- > import XMonad.Layout.SortedLayout --@@ -42,9 +42,9 @@ -- > myLayout = sorted [ClassName "Firefox", ClassName "URxvt"] Grid -- > main = xmonad def { layoutHook = myLayout } ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook".   -- | Modify a layout using a list of properties to sort its windows.
XMonad/Layout/Spacing.hs view
@@ -41,12 +41,6 @@       -- * Modify Borders     , Border (..)     , borderMap, borderIncrementBy--      -- * Backwards Compatibility-    , SpacingWithEdge-    , SmartSpacing, SmartSpacingWithEdge-    , ModifySpacing (..)-    , setSpacing, incSpacing     ) where  import           XMonad@@ -57,7 +51,7 @@   -- $usage--- You can use this module by importing it into your @~\/.xmonad\/xmonad.hs@+-- You can use this module by importing it into your @xmonad.hs@ -- file: -- -- > import XMonad.Layout.Spacing@@ -220,9 +214,6 @@         = Just $ s { windowBorder = f wb }         | Just (ModifyWindowBorderEnabled f) <- fromMessage m         = Just $ s { windowBorderEnabled = f wbe }-        | Just (ModifySpacing f) <- fromMessage m-        = Just $ let f' = borderMap (fromIntegral . f . fromIntegral)-                 in  s { screenBorder = f' sb, windowBorder = f' wb }         | otherwise         = Nothing @@ -365,26 +356,7 @@ ----------------------------------------------------------------------------- -- Backwards Compatibility: ------------------------------------------------------------------------------{-# DEPRECATED SpacingWithEdge, SmartSpacing, SmartSpacingWithEdge "Use Spacing instead." #-}-{-# DEPRECATED ModifySpacing "Use SpacingModifier instead, perhaps with sendMessages." #-}-{-# DEPRECATED setSpacing "Use setScreenWindowSpacing instead." #-}-{-# DEPRECATED incSpacing "Use incScreenWindowSpacing instead." #-} --- | A type synonym for the 'Spacing' 'LayoutModifier'.-type SpacingWithEdge = Spacing---- | A type synonym for the 'Spacing' 'LayoutModifier'.-type SmartSpacing = Spacing---- | A type synonym for the 'Spacing' 'LayoutModifier'.-type SmartSpacingWithEdge = Spacing---- | Message to dynamically modify (e.g. increase\/decrease\/set) the size of--- the screen spacing and window spacing. See 'SpacingModifier'.-newtype ModifySpacing = ModifySpacing (Int -> Int)--instance Message ModifySpacing- -- | Surround all windows by a certain number of pixels of blank space. See -- 'spacingRaw'. spacing :: Int -> l a -> ModifiedLayout Spacing l a@@ -410,11 +382,3 @@ smartSpacingWithEdge :: Int -> l a -> ModifiedLayout Spacing l a smartSpacingWithEdge i = spacingRaw True (uniformBorder i') True (uniformBorder i') True     where i' = fromIntegral i---- | See 'setScreenWindowSpacing'.-setSpacing :: Int -> X ()-setSpacing = setScreenWindowSpacing . fromIntegral---- | See 'incScreenWindowSpacing'.-incSpacing :: Int -> X ()-incSpacing = incScreenWindowSpacing . fromIntegral
XMonad/Layout/Spiral.hs view
@@ -31,7 +31,7 @@ import XMonad.StackSet ( integrate )  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Layout.Spiral --@@ -40,12 +40,12 @@ -- > myLayout =  spiral (6/7) ||| etc.. -- > main = xmonad def { layoutHook = myLayout } ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook".  fibs :: [Integer]-fibs = 1 : 1 : zipWith (+) fibs (tail fibs)+fibs = 1 : 1 : zipWith (+) fibs (drop 1 fibs)  mkRatios :: [Integer] -> [Rational] mkRatios (x1:x2:xs) = (x1 % x2) : mkRatios (x2:xs)@@ -82,7 +82,7 @@ instance LayoutClass SpiralWithDir a where     pureLayout (SpiralWithDir dir rot scale) sc stack = zip ws rects         where ws = integrate stack-              ratios = blend scale . reverse . take (length ws - 1) . mkRatios $ tail fibs+              ratios = blend scale . reverse . take (length ws - 1) . mkRatios $ drop 1 fibs               rects = divideRects (zip ratios dirs) sc               dirs  = dropWhile (/= dir) $ case rot of                                            CW  -> cycle [East .. North]
XMonad/Layout/Square.hs view
@@ -29,7 +29,7 @@ import XMonad.StackSet ( integrate )  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@ file:+-- You can use this module with the following in your @xmonad.hs@ file: -- -- >   import XMonad.Layout.Square --@@ -41,7 +41,7 @@ -- >         [(tabbed,3),(tabbed,30),(tabbed,1),(tabbed,1)]  -- For detailed instructions on editing your key bindings, see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  data Square a = Square deriving ( Read, Show ) 
XMonad/Layout/StackTile.hs view
@@ -27,7 +27,7 @@ import XMonad.Prelude  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Layout.StackTile --@@ -36,9 +36,9 @@ -- > myLayout =  StackTile 1 (3/100) (1/2) ||| etc.. -- > main = xmonad def { layoutHook = myLayout } ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook". -- data StackTile a = StackTile !Int !Rational !Rational deriving (Show, Read) 
XMonad/Layout/StateFull.hs view
@@ -20,19 +20,18 @@ -- behaviour of a child layout that has not been given the focused window. -------------------------------------------------------------------------------- -module XMonad.Layout.StateFull (+module XMonad.Layout.StateFull {-# DEPRECATED "Use X.L.TrackFloating." #-} (   -- * Usage   -- $Usage   pattern StateFull,   StateFull,-  FocusTracking(..),-  focusTracking+  FocusTracking,+  F.focusTracking ) where -import XMonad hiding ((<&&>))-import XMonad.Prelude (fromMaybe, (<|>))-import qualified XMonad.StackSet as W-import XMonad.Util.Stack (findZ)+import XMonad+import XMonad.Layout.LayoutModifier+import qualified XMonad.Layout.FocusTracking as F  -- $Usage --@@ -50,43 +49,14 @@ -- > main = xmonad def -- >  { layoutHook = someParentLayoutWith aChild (focusTracking anotherChild) } --- | The @FocusTracking@ data type for which the @LayoutClass@ instance is---   provided.-data FocusTracking l a = FocusTracking (Maybe a) (l a)-  deriving (Show, Read)---- | Transform a layout into one that remembers and uses its last focus.-focusTracking :: l a -> FocusTracking l a-focusTracking = FocusTracking Nothing+-- | The @FocusTracking@ type for which the @LayoutClass@ instance is provided.+type FocusTracking = ModifiedLayout F.FocusTracking  -- | A type synonym to match the @StateFull@ pattern synonym. type StateFull = FocusTracking Full  -- | A pattern synonym for the primary use case of the @FocusTracking@ --   transformer; using @Full@.-pattern StateFull :: FocusTracking Full a-pattern StateFull = FocusTracking Nothing Full--instance LayoutClass l Window => LayoutClass (FocusTracking l) Window where--  description (FocusTracking _ child)-    | chDesc == "Full"  = "StateFull"-    | ' ' `elem` chDesc = "FocusTracking (" ++ chDesc ++ ")"-    | otherwise           = "FocusTracking " ++ chDesc-    where chDesc = description child--  runLayout (W.Workspace i (FocusTracking mOldFoc childL) mSt) sr = do--    mRealFoc <- gets (W.peek . windowset)-    let mGivenFoc = W.focus <$> mSt-        passedMSt = if mRealFoc == mGivenFoc then mSt-                    else (mOldFoc >>= \oF -> findZ (==oF) mSt) <|> mSt--    (wrs, mChildL') <- runLayout (W.Workspace i childL passedMSt) sr-    let newFT = if mRealFoc /= mGivenFoc then FocusTracking mOldFoc <$> mChildL'-                else Just $ FocusTracking mGivenFoc (fromMaybe childL mChildL')--    return (wrs, newFT)+pattern StateFull :: StateFull a+pattern StateFull = ModifiedLayout (F.FocusTracking Nothing) Full -  handleMessage (FocusTracking mf childLayout) m =-    (fmap . fmap) (FocusTracking mf) (handleMessage childLayout m)
XMonad/Layout/Stoppable.hs view
@@ -58,7 +58,7 @@ import System.Posix.Signals  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad -- > import XMonad.Layout.Stoppable@@ -75,9 +75,9 @@ -- layoutHook you have to provide manageHook from -- "XMonad.Util.RemoteWindows" module. ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook".  signalWindow :: Signal -> Window -> X () signalWindow s w = do
XMonad/Layout/SubLayouts.hs view
@@ -4,6 +4,7 @@ {-# LANGUAGE ParallelListComp #-} {-# LANGUAGE PatternGuards #-} {-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TupleSections #-} {-# LANGUAGE ViewPatterns #-}  -----------------------------------------------------------------------------@@ -46,8 +47,6 @@     )     where -import XMonad.Layout.Circle () -- so haddock can find the link- import XMonad.Layout.Decoration(Decoration, DefaultShrinker) import XMonad.Layout.LayoutModifier(LayoutModifier(handleMess, modifyLayout,                                     redoLayout),@@ -114,7 +113,7 @@ --  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Layout.SubLayouts -- > import XMonad.Layout.WindowNavigation@@ -163,10 +162,9 @@ --  could not be used in the keybinding instead? It avoids having to explicitly --  pass the conf. ----- For more detailed instructions, see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"--- "XMonad.Doc.Extending#Adding_key_bindings"+-- For more detailed instructions, see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>+-- and "XMonad.Doc.Extending#Editing_the_layout_hook".  -- | The main layout modifier arguments: --@@ -184,11 +182,11 @@ --  [@outerLayout@] The layout that determines the rectangles given to each --  group. -----  Ex. The second group is 'Tall', the third is 'Circle', all others are tabbed---  with:+--  Ex. The second group is 'Tall', the third is 'XMonad.Layout.CircleEx.circle',+--  all others are tabbed with: -- --  > myLayout = addTabs shrinkText def---  >          $ subLayout [0,1,2] (Simplest ||| Tall 1 0.2 0.5 ||| Circle)+--  >          $ subLayout [0,1,2] (Simplest ||| Tall 1 0.2 0.5 ||| circle) --  >          $ Tall 1 0.2 0.5 ||| Full subLayout :: [Int] -> subl a -> l a -> ModifiedLayout (Sublayout subl) l a subLayout nextLayout sl = ModifiedLayout (Sublayout (I []) (nextLayout,sl) [])@@ -348,7 +346,7 @@             return $ Just $ Sublayout (I ((sm,w):ms)) defl sls          | Just (Broadcast sm) <- fromMessage m = do-            ms' <- fmap (zip (repeat sm) . W.integrate') currentStack+            ms' <- fmap (map (sm,) . W.integrate') currentStack             return $ if null ms' then Nothing                 else Just $ Sublayout (I $ ms' ++ ms) defl sls @@ -409,7 +407,7 @@            catchLayoutMess :: LayoutMessages -> X (Maybe (Sublayout l Window))            catchLayoutMess x = do             let m' = x `asTypeOf` (undefined :: LayoutMessages)-            ms' <- zip (repeat $ SomeMessage m') . W.integrate'+            ms' <- map (SomeMessage m',) . W.integrate'                     <$> currentStack             return $ do guard $ not $ null ms'                         Just $ Sublayout (I $ ms' ++ ms) defl sls
XMonad/Layout/TabBarDecoration.hs view
@@ -31,7 +31,7 @@  -- $usage -- You can use this module with the following in your--- @~\/.xmonad\/xmonad.hs@:+-- @xmonad.hs@: -- -- > import XMonad.Layout.TabBarDecoration --@@ -39,9 +39,9 @@ -- -- > main = xmonad def { layoutHook = simpleTabBar $ layoutHook def} ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook". -- -- 'tabBar' will give you the possibility of setting a custom shrinker -- and a custom theme.
XMonad/Layout/Tabbed.hs view
@@ -43,7 +43,7 @@ import XMonad.Util.Types (Direction2D(..))  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Layout.Tabbed --@@ -67,9 +67,9 @@ -- on the workspace.  To have it always shown, use one of the layouts or -- modifiers ending in @Always@. ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook". -- -- You can also edit the default configuration options. --
XMonad/Layout/TallMastersCombo.hs view
@@ -1,5 +1,9 @@ -- {-# LANGUAGE PatternGuards, FlexibleContexts, FlexibleInstances, TypeSynonymInstances, MultiParamTypeClasses #-}-{-# LANGUAGE PatternGuards, FlexibleContexts, FlexibleInstances, MultiParamTypeClasses #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE PatternGuards #-}+ --------------------------------------------------------------------------- -- | -- Module      :  XMonad.Layout.TallMastersCombo@@ -16,7 +20,7 @@ -- a main master, which is the original master window; -- a sub master, the first window of the second pane. -- This combinator can be nested, and has a good support for using--- 'XMonad.Layout.Tabbed' as a sublayout.+-- "XMonad.Layout.Tabbed" as a sublayout. -- ----------------------------------------------------------------------------- @@ -42,16 +46,17 @@ ) where  import XMonad hiding (focus, (|||))-import XMonad.Prelude (delete, find, foldM, fromMaybe, isJust)-import XMonad.StackSet (Workspace(..),integrate',Stack(..))-import qualified XMonad.StackSet as W import qualified XMonad.Layout as LL-import XMonad.Layout.Simplest (Simplest(..)) import XMonad.Layout.Decoration+import XMonad.Layout.Simplest (Simplest (..))+import XMonad.Prelude (delete, find, foldM, fromMaybe, isJust, listToMaybe)+import XMonad.StackSet (Stack (..), Workspace (..), integrate')+import qualified XMonad.StackSet as W+import XMonad.Util.Stack (zipperFocusedAtFirstOf)  --------------------------------------------------------------------------------- -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Layout.TallMastersCombo --@@ -244,14 +249,14 @@                return $ mergeSubLayouts  mlayout1 mlayout2 (TMSCombineTwo f w1 w2 (not vsp) nmaster delta frac layout1 layout2) True     | Just SwapSubMaster <- fromMessage m =         -- first get the submaster window-        let subMaster = if null w2 then Nothing else Just $ head w2+        let subMaster = listToMaybe w2         in case subMaster of             Just mw -> do windows $ W.modify' $ swapWindow mw                           return Nothing             Nothing -> return Nothing     | Just FocusSubMaster <- fromMessage m =         -- first get the submaster window-        let subMaster = if null w2 then Nothing else Just $ head w2+        let subMaster = listToMaybe w2         in case subMaster of             Just mw -> do windows $ W.modify' $ focusWindow mw                           return Nothing@@ -302,19 +307,6 @@               mlayout2 <- handleMessage layout2 m               return $ mergeSubLayouts mlayout1 mlayout2 i False ----- code from CombineTwo--- given two sets of zs and xs takes the first z from zs that also belongs to xs--- and turns xs into a stack with z being current element. Acts as--- StackSet.differentiate if zs and xs don't intersect-differentiate :: Eq q => [q] -> [q] -> Maybe (Stack q)-differentiate (z:zs) xs | z `elem` xs = Just $ Stack { focus=z-                                                     , up = reverse $ takeWhile (/=z) xs-                                                     , down = tail $ dropWhile (/=z) xs }-                        | otherwise = differentiate zs xs-differentiate [] xs = W.differentiate xs- -- | Swap a given window with the focused window. swapWindow :: (Eq a) => a -> Stack a -> Stack a swapWindow w (Stack foc upLst downLst)@@ -388,9 +380,9 @@                        Nothing   -> f         snum = length slst         (slst1, slst2) = splitAt nmaster slst-        s0 = differentiate f' slst-        s1' = differentiate f' slst1-        s2' = differentiate f' slst2+        s0 = zipperFocusedAtFirstOf f' slst+        s1' = zipperFocusedAtFirstOf f' slst1+        s2' = zipperFocusedAtFirstOf f' slst2         (s1,s2,frac') | nmaster == 0    = (Nothing,s0,0)                       | nmaster >= snum = (s0,Nothing,1)                       | otherwise       = (s1',s2',frac)
XMonad/Layout/ThreeColumns.hs view
@@ -32,7 +32,7 @@ import Data.Ratio  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Layout.ThreeColumns --@@ -51,9 +51,9 @@ -- -- The ThreeColMid variant places the main window between the stack columns. ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook".   -- $screenshot
XMonad/Layout/ToggleLayouts.hs view
@@ -25,7 +25,7 @@ import XMonad.StackSet (Workspace (..))  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Layout.ToggleLayouts --@@ -34,9 +34,9 @@ -- > myLayout = toggleLayouts Full (Tall 1 (3/100) (1/2)) ||| etc.. -- > main = xmonad def { layoutHook = myLayout } ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook". -- -- To toggle between layouts add a key binding like --@@ -48,7 +48,7 @@ -- -- For detailed instruction on editing the key binding see: ----- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  data ToggleLayouts lt lf a = ToggleLayouts Bool (lt a) (lf a) deriving (Read,Show) data ToggleLayout = ToggleLayout | Toggle String deriving (Read,Show)
XMonad/Layout/TrackFloating.hs view
@@ -2,7 +2,7 @@ {- |  Module      :  XMonad.Layout.TrackFloating-Description :  Track focus in the tiled layer.+Description :  Let focused tiles track focused floats Copyright   :  (c) 2010 & 2013 Adam Vogt                2011 Willem Vanlint License     :  BSD-style (see xmonad/LICENSE)@@ -11,14 +11,9 @@ Stability   :  unstable Portability :  unportable -Layout modifier that tracks focus in the tiled layer while the floating layer-or another sublayout is in use. This is particularly helpful for tiled layouts-where the focus determines what is visible. It can also be used to improve the-behaviour of a child layout that has not been given the focused window.+Provides layout modifier 'UseTransientFor': when a float has focus and is+@WM_TRANSIENT_FOR@ a tile, run the underlying layout as if that tile had focus. -The relevant bugs are Issue 4 and 306:-<http://code.google.com/p/xmonad/issues/detail?id=4>,-<http://code.google.com/p/xmonad/issues/detail?id=306> -} module XMonad.Layout.TrackFloating     (-- * Usage@@ -37,31 +32,15 @@ import XMonad.Prelude import XMonad import XMonad.Layout.LayoutModifier+import XMonad.Layout.FocusTracking import XMonad.Util.Stack (findZ) import qualified XMonad.StackSet as W  import qualified Data.Traversable as T  -newtype TrackFloating a = TrackFloating (Maybe Window)-    deriving (Read,Show)---instance LayoutModifier TrackFloating Window where-    modifyLayoutWithUpdate (TrackFloating mw) ws@W.Workspace{ W.stack = ms } r-      = do-        xCur <- gets (W.peek . W.view (W.tag ws) . windowset)-        let isF = xCur /= (W.focus <$> ms)-            -- use the remembered focus point when true focus differs from-            -- what this (sub)layout is given, which happens e.g. when true-            -- focus is in floating layer or when another sublayout has focus-            newStack | isF = (mw >>= \w -> findZ (w==) ms) <|> ms-                     | otherwise = ms-            newState | isF = mw-                     | otherwise = xCur-        ran <- runLayout ws{ W.stack = newStack } r-        return (ran, guard (newState /= mw) >> Just (TrackFloating newState))-+{-# DEPRECATED TrackFloating "Use X.L.FocusTracking.FocusTracking." #-}+type TrackFloating = FocusTracking   {- | When focus is on the tiled layer, the underlying layout is run with focus@@ -128,8 +107,9 @@ * the remembered focus hasn't since been killed  -}+{-# DEPRECATED trackFloating "Use X.L.FocusTracking.focusTracking." #-} trackFloating ::  l a -> ModifiedLayout TrackFloating l a-trackFloating = ModifiedLayout (TrackFloating Nothing)+trackFloating = focusTracking  {- $layoutModifier It also corrects focus issues for full-like layouts inside other layout
XMonad/Layout/TwoPane.hs view
@@ -27,7 +27,7 @@ import XMonad.StackSet ( focus, up, down)  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Layout.TwoPane --@@ -36,9 +36,9 @@ -- > myLayout = TwoPane (3/100) (1/2)  ||| Full ||| etc.. -- > main = xmonad def { layoutHook = myLayout } ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook".  data TwoPane a =     TwoPane Rational Rational@@ -56,8 +56,8 @@      handleMessage (TwoPane delta split) x =         return $ case fromMessage x of-                   Just Shrink -> Just (TwoPane delta (split - delta))-                   Just Expand -> Just (TwoPane delta (split + delta))+                   Just Shrink -> Just (TwoPane delta (max 0 (split - delta)))+                   Just Expand -> Just (TwoPane delta (min 1 (split + delta)))                    _           -> Nothing      description _ = "TwoPane"
XMonad/Layout/TwoPanePersistent.hs view
@@ -28,7 +28,7 @@ import XMonad hiding (focus)  -- $usage--- Import the module in @~\/.xmonad\/xmonad.hs@:+-- Import the module in @xmonad.hs@: -- -- > import XMonad.Layout.TwoPanePersistent --@@ -58,8 +58,8 @@    pureMessage (TwoPanePersistent w delta split) x =     case fromMessage x of-      Just Shrink -> Just (TwoPanePersistent w delta (split - delta))-      Just Expand -> Just (TwoPanePersistent w delta (split + delta))+      Just Shrink -> Just (TwoPanePersistent w delta (max 0 (split - delta)))+      Just Expand -> Just (TwoPanePersistent w delta (min 1 (split + delta)))       _ -> Nothing    description _ = "TwoPanePersistent"
XMonad/Layout/VoidBorders.hs view
@@ -35,7 +35,7 @@ import XMonad.StackSet (integrate)  -- $usage--- You can use this module with the following in your ~\/.xmonad/xmonad.hs+-- You can use this module with the following in your @xmonad.hs@ -- file: -- -- > import XMonad.Layout.VoidBorders@@ -46,9 +46,9 @@ -- -- > layoutHook = ... ||| voidBorders Full ||| normalBorders Tall ... ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook".  data VoidBorders a = VoidBorders deriving (Read, Show) 
XMonad/Layout/WindowArranger.hs view
@@ -35,7 +35,7 @@  -- $usage -- You can use this module with the following in your--- @~\/.xmonad\/xmonad.hs@:+-- @xmonad.hs@: -- -- > import XMonad.Layout.WindowArranger -- > myLayout = layoutHook def@@ -45,9 +45,9 @@ -- -- > main = xmonad def { layoutHook = windowArrangeAll myLayout } ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook". -- -- You may also want to define some key binding to move or resize -- windows. These are good defaults:@@ -68,7 +68,7 @@ -- >        , ((modm .|. controlMask .|. shiftMask, xK_Up   ), sendMessage (DecreaseUp    1)) -- -- For detailed instructions on editing your key bindings, see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  -- | A layout modifier to float the windows in a workspace windowArrange :: l a -> ModifiedLayout WindowArranger l a
XMonad/Layout/WindowNavigation.hs view
@@ -35,7 +35,7 @@ import XMonad.Util.XUtils  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Layout.WindowNavigation --@@ -45,9 +45,9 @@ -- > myLayout = windowNavigation (Tall 1 (3/100) (1/2)) ||| Full ||| etc.. -- > main = xmonad def { layoutHook = myLayout } ----- For more detailed instructions on editing the 'layoutHook' see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the 'layoutHook' see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook". -- -- In keybindings: --@@ -62,7 +62,7 @@ -- -- For detailed instruction on editing the key binding see: ----- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.   data MoveWindowToWindow a = MoveWindowToWindow a a deriving ( Read, Show)@@ -75,10 +75,10 @@ -- | Used with 'configurableNavigation' to specify how to show reachable windows' -- borders. You cannot create 'WNConfig' values directly; use 'def' or one of the following -- three functions to create one.--- +-- -- 'def', and 'windowNavigation', uses the focused border color at 40% brightness, as if -- you had specified--- +-- -- > configurableNavigation (navigateBrightness 0.4) data WNConfig =     WNC { brightness    :: Maybe Double -- Indicates a fraction of the focus color.
XMonad/Layout/WindowSwitcherDecoration.hs view
@@ -36,7 +36,7 @@  -- $usage -- You can use this module with the following in your--- @~\/.xmonad\/xmonad.hs@:+-- @xmonad.hs@: -- -- > import XMonad.Layout.WindowSwitcherDecoration -- > import XMonad.Layout.DraggingVisualizer
XMonad/Layout/WorkspaceDir.hs view
@@ -41,7 +41,7 @@ import XMonad.StackSet ( tag, currentTag )  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Layout.WorkspaceDir --@@ -51,9 +51,9 @@ -- > myLayout = workspaceDir "~" (Tall 1 (3/100) (1/2))  ||| Full ||| etc.. -- > main = xmonad def { layoutHook = myLayout } ----- For more detailed instructions on editing the layoutHook see:------ "XMonad.Doc.Extending#Editing_the_layout_hook"+-- For more detailed instructions on editing the layoutHook see+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and+-- "XMonad.Doc.Extending#Editing_the_layout_hook". -- -- WorkspaceDir provides also a prompt. To use it you need to import -- "XMonad.Prompt" and add something like this to your key bindings:@@ -67,7 +67,7 @@ -- -- For detailed instruction on editing the key binding see: ----- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  newtype Chdir = Chdir String instance Message Chdir
XMonad/Layout/ZoomRow.hs view
@@ -49,7 +49,7 @@ -- and decreased, and a window can be set to use the whole available -- space whenever it has focus. ----- You can use this module by including  the following in your @~\/.xmonad/xmonad.hs@:+-- You can use this module by including  the following in your @xmonad.hs@: -- -- > import XMonad.Layout.ZoomRow --@@ -69,8 +69,9 @@ -- >   -- (Un)Maximize the focused window -- > , ((modMask             , xK_f    ), sendMessage ToggleZoomFull) ----- For more information on editing your layout hook and key bindings,--- see "XMonad.Doc.Extending".+-- For more information on editing your layoutHook and key bindings,+-- see <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>+-- and "XMonad.Doc.Extending".  -- * Creation functions 
XMonad/Prelude.hs view
@@ -1,6 +1,9 @@+{-# OPTIONS_GHC -Wno-dodgy-imports #-} {-# LANGUAGE BangPatterns        #-}+{-# LANGUAGE InstanceSigs        #-} {-# LANGUAGE LambdaCase          #-} {-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies        #-} -------------------------------------------------------------------- -- | -- Module      :  XMonad.Prelude@@ -24,6 +27,7 @@     notEmpty,     safeGetWindowAttributes,     mkAbsolutePath,+    findM,      -- * Keys     keyToString,@@ -35,6 +39,14 @@     multimediaKeys,     functionKeys,     WindowScreen,++    -- * Infinite streams+    Stream(..),+    (+~),+    cycleS,+    takeS,+    toList,+    fromList, ) where  import Foreign (alloca, peek)@@ -44,10 +56,10 @@ import Control.Monad       as Exports import Data.Bool           as Exports import Data.Char           as Exports-import Data.Foldable       as Exports+import Data.Foldable       as Exports hiding (toList) import Data.Function       as Exports-import Data.Functor        as Exports-import Data.List           as Exports+import Data.Functor        as Exports hiding (unzip)+import Data.List           as Exports hiding ((!?)) import Data.Maybe          as Exports import Data.Monoid         as Exports import Data.Traversable    as Exports@@ -55,14 +67,15 @@ import qualified Data.Map.Strict as Map  import Control.Arrow ((&&&), first)+import Control.Exception (SomeException, handle) import Data.Bifunctor (bimap) import Data.Bits import Data.List.NonEmpty (NonEmpty ((:|))) import Data.Tuple (swap)+import GHC.Exts (IsList(..)) import GHC.Stack import System.Directory (getHomeDirectory) import System.Environment (getEnv)-import Control.Exception (SomeException, handle) import qualified XMonad.StackSet as W  -- | Short for 'fromIntegral'.@@ -89,6 +102,21 @@ (.:) :: (a -> b) -> (c -> d -> a) -> c -> d -> b (.:) = (.) . (.) +-- | Like 'find', but takes a monadic function instead; retains the+-- short-circuiting behaviour of the non-monadic version.+--+-- For example,+--+-- > findM (\a -> putStr (show a <> " ") >> pure False) [1..10]+--+-- would print "1 2 3 4 5 6 7 8 9 10" and return @Nothing@, while+--+-- > findM (\a -> putStr (show a <> " ") >> pure True) [1..10]+--+-- would print @"1"@ and return @Just 1@.+findM :: Monad m => (a -> m Bool) -> [a] -> m (Maybe a)+findM p = foldr (\x -> ifM (p x) (pure $ Just x)) (pure Nothing)+ -- | 'Data.List.NonEmpty.fromList' with a better error message. Useful to -- silence GHC's Pattern match(es) are non-exhaustive warning in places where -- the programmer knows it's always non-empty, but it's infeasible to express@@ -97,7 +125,7 @@ notEmpty [] = error "unexpected empty list" notEmpty (x:xs) = x :| xs --- | A safe version of 'Graphics.X11.Extras.getWindowAttributes'.+-- | A safe version of 'Graphics.X11.Xlib.Extras.getWindowAttributes'. safeGetWindowAttributes :: Window -> X (Maybe WindowAttributes) safeGetWindowAttributes w = withDisplay $ \dpy -> io . alloca $ \p ->   xGetWindowAttributes dpy w p >>= \case@@ -199,7 +227,7 @@ allSpecialKeys :: [(String, KeySym)] allSpecialKeys = functionKeys <> specialKeys <> multimediaKeys --- | A list pairing function key descriptor strings (e.g. @\"<F2>\"@)+-- | A list pairing function key descriptor strings (e.g. @\"\<F2\>\"@) -- with the associated KeySyms. functionKeys :: [(String, KeySym)] functionKeys = [ ('F' : show n, k)@@ -449,3 +477,36 @@ -- | The specialized 'W.Screen' derived from 'WindowSet'. type WindowScreen -- FIXME move to core     = W.Screen WorkspaceId (Layout Window) Window ScreenId ScreenDetail++-- | An infinite stream type+data Stream a = !a :~ Stream a+infixr 5 :~++instance Functor Stream where+  fmap :: (a -> b) -> Stream a -> Stream b+  fmap f = go+   where go (x :~ xs) = f x :~ go xs++instance IsList (Stream a) where+  type (Item (Stream a)) = a++  fromList :: [a] -> Stream a+  fromList (x : xs) = x :~ fromList xs+  fromList []       = errorWithoutStackTrace "XMonad.Prelude.Stream.fromList: Can't create stream out of finite list."++  toList :: Stream a -> [a]+  toList (x :~ xs) = x : toList xs++-- | Absorb a list into an infinite stream.+(+~) :: [a] -> Stream a -> Stream a+xs +~ s = foldr (:~) s xs+infixr 5 +~++-- | Absorb a non-empty list into an infinite stream.+cycleS :: NonEmpty a -> Stream a+cycleS (x :| xs) = s where s = x :~ xs +~ s++-- | @takeS n stream@ returns the first @n@ elements of @stream@; if @n < 0@,+-- this returns the empty list.+takeS :: Int -> Stream a -> [a]+takeS n = take n . toList
XMonad/Prompt.hs view
@@ -7,6 +7,7 @@ {-# LANGUAGE PatternGuards #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE MultiWayIf #-} ----------------------------------------------------------------------------- -- | -- Module      :  XMonad.Prompt@@ -61,6 +62,7 @@     , defaultColor, modifyColor, setColor     , resetColor, setBorderColor     , modifyPrompter, setPrompter, resetPrompter+    , selectedCompletion, setCurrentCompletions, getCurrentCompletions     , moveWord, moveWord', killWord, killWord'     , changeWord, deleteString     , moveHistory, setSuccess, setDone, setModeDone@@ -98,7 +100,7 @@     ) where  import           XMonad                       hiding (cleanMask, config)-import           XMonad.Prelude               hiding (toList)+import           XMonad.Prelude               hiding (toList, fromList) import qualified XMonad.StackSet              as W import           XMonad.Util.Font import           XMonad.Util.Types@@ -112,11 +114,13 @@ import           Data.Bifunctor               (bimap) import           Data.Bits import           Data.IORef+import qualified Data.List.NonEmpty           as NE import qualified Data.Map                     as M import           Data.Set                     (fromList, toList) import           System.IO import           System.IO.Unsafe             (unsafePerformIO) import           System.Posix.Files+import Data.List.NonEmpty (nonEmpty)  -- $usage -- For usage examples see "XMonad.Prompt.Shell",@@ -183,7 +187,8 @@                                                 -- history entries to remember         , promptKeymap          :: M.Map (KeyMask,KeySym) (XP ())                                                 -- ^ Mapping from key combinations to actions-        , completionKey         :: (KeyMask, KeySym)     -- ^ Key that should trigger completion+        , completionKey         :: (KeyMask, KeySym)     -- ^ Key to trigger forward completion+        , prevCompletionKey     :: (KeyMask, KeySym)     -- ^ Key to trigger backward completion         , changeModeKey         :: KeySym       -- ^ Key to change mode (when the prompt has multiple modes)         , defaultText           :: String       -- ^ The text by default in the prompt line         , autoComplete          :: Maybe Int    -- ^ Just x: if only one completion remains, auto-select it,@@ -285,14 +290,14 @@                 | Bottom                 -- | Prompt will be placed in the center horizontally and                 --   in the certain place of screen vertically. If it's in the upper-                --   part of the screen, completion window will be placed below(like-                --   in 'Top') and otherwise above(like in 'Bottom')+                --   part of the screen, completion window will be placed below (like+                --   in 'Top') and otherwise above (like in 'Bottom')                 | CenteredAt { xpCenterY :: Rational                              -- ^ Rational between 0 and 1, giving                              -- y coordinate of center of the prompt relative to the screen height.                              , xpWidth  :: Rational                              -- ^ Rational between 0 and 1, giving-                             -- width of the prompt relatave to the screen width.+                             -- width of the prompt relative to the screen width.                              }                   deriving (Show,Read) @@ -329,7 +334,8 @@         , borderColor           = border def         , promptBorderWidth     = 1         , promptKeymap          = defaultXPKeymap-        , completionKey         = (0,xK_Tab)+        , completionKey         = (0, xK_Tab)+        , prevCompletionKey     = (shiftMask, xK_Tab)         , changeModeKey         = xK_grave         , position              = Bottom         , height                = 18@@ -439,7 +445,7 @@ setInput :: String -> XP () setInput = modify . setCommand --- | Returns the current input string. Intented for use in custom keymaps+-- | Returns the current input string. Intended for use in custom keymaps -- where 'get' or similar can't be used to retrieve it. getInput :: XP String getInput = gets command@@ -533,11 +539,11 @@ -- The argument supplied to the action to execute is always the current highlighted item, -- that means that this prompt overrides the value `alwaysHighlight` for its configuration to True. mkXPromptWithModes :: [XPType] -> XPConfig -> X ()-mkXPromptWithModes modes conf = do-  let defaultMode = head modes-      modeStack = W.Stack { W.focus = defaultMode -- Current mode+mkXPromptWithModes [] _ = pure ()+mkXPromptWithModes (defaultMode : modes) conf = do+  let modeStack = W.Stack { W.focus = defaultMode -- Current mode                           , W.up = []-                          , W.down = tail modes -- Other modes+                          , W.down = modes -- Other modes                           }       om = XPMultipleModes modeStack   st' <- mkXPromptImplementation (showXPrompt defaultMode) conf { alwaysHighlight = True } om@@ -624,6 +630,10 @@  type KeyStroke = (KeySym, String) +-- | Check whether the given key stroke is a modifier.+isModifier :: KeyStroke -> Bool+isModifier (_, keyString) = null keyString+ -- | Main event "loop". Gives priority to events from the state's event buffer. eventLoop :: (KeyStroke -> Event -> XP ())           -> XP Bool@@ -642,11 +652,11 @@                                 ks <- keycodeToKeysym d (ev_keycode ev) 0                                 return (ks, s, ev)                         else return (noSymbol, "", ev)-        l   -> do-                modify $ \s -> s { eventBuffer = tail l }-                return $ head l+        (l : ls) -> do+                modify $ \s -> s { eventBuffer = ls }+                return l     handle (keysym,keystr) event-    stopAction >>= flip unless (eventLoop handle stopAction)+    stopAction >>= \stop -> unless stop (eventLoop handle stopAction)  -- | Default event loop stop condition. evDefaultStop :: XP Bool@@ -688,34 +698,39 @@ -- | Prompt event handler for the main loop. Dispatches to input, completion -- and mode switching handlers. handleMain :: KeyStroke -> Event -> XP ()-handleMain stroke@(keysym,_) KeyEvent{ev_event_type = t, ev_state = m} = do-    (compKey,modeKey) <- gets $ (completionKey &&& changeModeKey) . config-    keymask <- gets cleanMask <*> pure m-    -- haven't subscribed to keyRelease, so just in case-    when (t == keyPress) $-        if (keymask,keysym) == compKey-           then getCurrentCompletions >>= handleCompletionMain-           else do-                setCurrentCompletions Nothing-                if keysym == modeKey-                   then modify setNextMode >> updateWindows-                   else handleInputMain keymask stroke-handleMain stroke event = handleOther stroke event---- | Prompt input handler for the main loop.-handleInputMain :: KeyMask -> KeyStroke -> XP ()-handleInputMain keymask (keysym,keystr) = do-    keymap <- gets (promptKeymap . config)-    case M.lookup (keymask,keysym) keymap of-        -- 'null keystr' i.e. when only a modifier was pressed+handleMain stroke@(keysym, keystr) = \case+    KeyEvent{ev_event_type = t, ev_state = m} -> do+      (prevCompKey, (compKey, modeKey)) <- gets $+          (prevCompletionKey &&& completionKey &&& changeModeKey) . config+      keymask <- gets cleanMask <*> pure m+      -- haven't subscribed to keyRelease, so just in case+      when (t == keyPress) $ if+          | (keymask, keysym) == compKey ->+               getCurrentCompletions >>= handleCompletionMain Next+          | (keymask, keysym) == prevCompKey ->+               getCurrentCompletions >>= handleCompletionMain Prev+          | otherwise -> do+               keymap <- gets (promptKeymap . config)+               let mbAction = M.lookup (keymask, keysym) keymap+               -- Either run when we can insert a valid character, or the+               -- pressed key has an action associated to it.+               unless (isModifier stroke && isNothing mbAction) $ do+                   setCurrentCompletions Nothing+                   if keysym == modeKey+                      then modify setNextMode >> updateWindows+                      else handleInput keymask mbAction+    event -> handleOther stroke event+  where+    -- Prompt input handler for the main loop.+    handleInput :: KeyMask -> Maybe (XP ()) -> XP ()+    handleInput keymask = \case         Just action -> action >> updateWindows-        Nothing     -> unless (null keystr) $-            when (keymask .&. controlMask == 0) $ do-                insertString $ utf8Decode keystr-                updateWindows-                updateHighlightedCompl-                complete <- tryAutoComplete-                when complete $ setSuccess True >> setDone True+        Nothing     -> when (keymask .&. controlMask == 0) $ do+            insertString $ utf8Decode keystr+            updateWindows+            updateHighlightedCompl+            complete <- tryAutoComplete+            when complete acceptSelection  -- There are two options to store the completion list during the main loop: -- * Use the State monad, with 'Nothing' as the initial state.@@ -725,17 +740,18 @@ -- -- | Prompt completion handler for the main loop. Given 'Nothing', generate the -- current completion list. With the current list, trigger a completion.-handleCompletionMain :: Maybe [String] -> XP ()-handleCompletionMain Nothing   = do-    cs <- getCompletions-    when (length cs > 1) $-        modify $ \s -> s { showComplWin = True }-    setCurrentCompletions $ Just cs-    handleCompletion cs-handleCompletionMain (Just cs) = handleCompletion cs+handleCompletionMain :: Direction1D -> Maybe [String] -> XP ()+handleCompletionMain dir compls = case compls of+   Just cs -> handleCompletion dir cs+   Nothing -> do+       cs <- getCompletions+       when (length cs > 1) $+           modify $ \s -> s { showComplWin = True }+       setCurrentCompletions $ Just cs+       handleCompletion dir cs -handleCompletion :: [String] -> XP ()-handleCompletion cs = do+handleCompletion :: Direction1D -> [String] -> XP ()+handleCompletion dir cs = do     alwaysHlight <- gets $ alwaysHighlight . config     st <- get @@ -775,8 +791,10 @@            | -- We only have one suggestion, so we need to be a little             -- bit smart in order to avoid a loop.-            length cs == 1 =-              if command st == hlCompl then put st else replaceCompletion (head cs)+            Just (ch :| []) <- nonEmpty cs =+              if command st == hlCompl+              then put st+              else replaceCompletion ch              -- The current suggestion matches the command, so advance             -- to the next completion and try again.@@ -790,7 +808,7 @@           | otherwise = replaceCompletion prevCompl          where           hlCompl     :: String       = fromMaybe (command st) $ highlightedItem st l-          complIndex' :: (Int, Int)   = nextComplIndex st+          complIndex' :: (Int, Int)   = computeComplIndex dir st           nextHlCompl :: Maybe String = highlightedItem st{ complIndex = complIndex' } cs            isSuffixOfCmd        :: Bool = hlCompl `isSuffixOf` command st@@ -831,10 +849,10 @@                   -> KeyMask                   -> KeyStroke                   -> XP ()-handleInputSubmap defaultAction keymap keymask (keysym,keystr) =+handleInputSubmap defaultAction keymap keymask stroke@(keysym, _) =     case M.lookup (keymask,keysym) keymap of         Just action -> action >> updateWindows-        Nothing     -> unless (null keystr) $ defaultAction >> updateWindows+        Nothing     -> unless (isModifier stroke) $ defaultAction >> updateWindows  -- | Initiate a prompt input buffer event loop. Input is sent to a buffer and -- bypasses the prompt. The provided function is given the existing buffer and@@ -888,8 +906,8 @@                   -> KeyStroke                   -> Event                   -> XP ()-handleInputBuffer f keymask (keysym,keystr) event =-    unless (null keystr || keymask .&. controlMask /= 0) $ do+handleInputBuffer f keymask stroke@(keysym, keystr) event =+    unless (isModifier stroke || keymask .&. controlMask /= 0) $ do         (evB,inB) <- gets (eventBuffer &&& inputBuffer)         let keystr' = utf8Decode keystr         let (cont,keep) = f inB keystr'@@ -905,18 +923,24 @@ bufferOne :: String -> String -> (Bool,Bool) bufferOne xs x = (null xs && null x,True) --- | Return the @(column, row)@ of the next highlight, or @(0, 0)@ if+-- | Return the @(column, row)@ of the desired highlight, or @(0, 0)@ if -- there is no prompt window or a wrap-around occurs.-nextComplIndex :: XPState -> (Int, Int)-nextComplIndex st = case complWinDim st of+computeComplIndex :: Direction1D -> XPState -> (Int, Int)+computeComplIndex dir st = case complWinDim st of   Nothing -> (0, 0)  -- no window dimensions (just destroyed or not created)   Just ComplWindowDim{ cwCols, cwRows } ->-    let (currentcol, currentrow) = complIndex st-        (colm, rowm) =-          ((currentcol + 1) `mod` length cwCols, (currentrow + 1) `mod` length cwRows)-     in if rowm == currentrow + 1-        then (currentcol, currentrow + 1)  -- We are not in the last row, so go down-        else (colm, rowm)                  -- otherwise advance to the next column+    if rowm == currentrow + direction+    then (currentcol, rowm)  -- We are not in the last row, so advance the row+    else (colm, rowm)        -- otherwise advance to the respective column+   where+    (currentcol, currentrow) = complIndex st+    (colm, rowm) =+      ( (currentcol + direction) `mod` length cwCols+      , (currentrow + direction) `mod` length cwRows+      )+    direction = case dir of+      Next ->  1+      Prev -> -1  tryAutoComplete :: XP Bool tryAutoComplete = do@@ -968,8 +992,8 @@   , (xK_bracketleft, quit)   ] ++   map (first $ (,) 0)-  [ (xK_Return, setSuccess True >> setDone True)-  , (xK_KP_Enter, setSuccess True >> setDone True)+  [ (xK_Return, acceptSelection)+  , (xK_KP_Enter, acceptSelection)   , (xK_BackSpace, deleteString Prev)   , (xK_Delete, deleteString Next)   , (xK_Left, moveCursor Prev)@@ -1009,6 +1033,7 @@   , (xK_g, quit)   , (xK_bracketleft, quit)   , (xK_t, transposeChars)+  , (xK_m, acceptSelection)   ] ++   map (first $ (,) mod1Mask) -- meta key + <key>   [ (xK_BackSpace, killWord' p Prev)@@ -1021,8 +1046,8 @@   ]   ++   map (first $ (,) 0) -- <key>-  [ (xK_Return, setSuccess True >> setDone True)-  , (xK_KP_Enter, setSuccess True >> setDone True)+  [ (xK_Return, acceptSelection)+  , (xK_KP_Enter, acceptSelection)   , (xK_BackSpace, deleteString Prev)   , (xK_Delete, deleteString Next)   , (xK_Left, moveCursor Prev)@@ -1058,9 +1083,12 @@                     -- alternates.                  -> M.Map (KeyMask,KeySym) (XP ()) vimLikeXPKeymap' fromColor promptF pasteFilter notWord = M.fromList $+    map (first $ (,) controlMask) -- control + <key>+    [ (xK_m, acceptSelection)+    ] ++     map (first $ (,) 0)-    [ (xK_Return,       setSuccess True >> setDone True)-    , (xK_KP_Enter,     setSuccess True >> setDone True)+    [ (xK_Return,       acceptSelection)+    , (xK_KP_Enter,     acceptSelection)     , (xK_BackSpace,    deleteString Prev)     , (xK_Delete,       deleteString Next)     , (xK_Left,         moveCursor Prev)@@ -1111,6 +1139,8 @@         , (xK_c,            promptSubmap (setModeDone True) changeVimXPKeymap                                 >> setModeDone True           )+        , (xK_Return,       acceptSelection)+        , (xK_KP_Enter,     acceptSelection)         ] ++         map (first $ (,) shiftMask)         [ (xK_dollar,       endOfLine >> moveCursor Prev)@@ -1166,6 +1196,10 @@  -- KeyPress and State +-- | Accept the current selection and exit.+acceptSelection :: StateT XPState IO ()+acceptSelection = setSuccess True >> setDone True+ -- | Quit. quit :: XP () quit = flushString >> setSuccess False >> setDone True >> setModeDone True@@ -1291,7 +1325,7 @@         c oc oo             | oo >= length oc && d == Prev = take (oo - 1) oc             | oo <  length oc && d == Prev = take (oo - 1) f ++ ss-            | oo <  length oc && d == Next = f ++ tail ss+            | oo <  length oc && d == Next = f ++ drop 1 ss             | otherwise = oc             where (f,ss) = splitAt oo oc @@ -1372,11 +1406,11 @@ -- starting cursor character is not considered, and the cursor is placed over -- the matching character. toHeadChar :: Direction1D -> String -> XP ()-toHeadChar d s = unless (null s) $ do+toHeadChar _ ""      = pure ()+toHeadChar d (c : _) = do     cmd <- gets command     off <- gets offset-    let c = head s-        off' = (if d == Prev then negate . fst else snd)+    let off' = (if d == Prev then negate . fst else snd)              . join (***) (maybe 0 (+1) . elemIndex c)              . (reverse *** drop 1)              $ splitAt off cmd@@ -1440,9 +1474,7 @@ redrawWindows emptyAction compls = do   d <- gets dpy   drawWin-  case compls of-    [] -> emptyAction-    l  -> redrawComplWin l+  maybe emptyAction redrawComplWin (nonEmpty compls)   io $ sync d False  where   -- | Draw the main prompt window.@@ -1461,14 +1493,14 @@     io $ freePixmap dpy pm  -- | Redraw the completion window, if necessary.-redrawComplWin ::  [String] -> XP ()+redrawComplWin ::  NonEmpty String -> XP () redrawComplWin compl = do   XPS{ showComplWin, complWinDim, complWin } <- get   nwi <- getComplWinDim compl   let recreate = do destroyComplWin                     w <- createComplWin nwi                     drawComplWin w compl-  if compl /= [] && showComplWin+  if showComplWin      then io (readIORef complWin) >>= \case             Just w -> case complWinDim of                         Just wi -> if nwi == wi -- complWinDim did not change@@ -1499,7 +1531,7 @@       (preCursor, cursor, postCursor) = if offset >= length com                  then (str, " ","") -- add a space: it will be our cursor ;-)                  else let (a, b) = splitAt offset com-                      in (prt ++ a, [head b], tail b)+                      in (prt ++ a, take 1 b, drop 1 b)    -- vertical and horizontal text alignment   (asc, desc) <- io $ textExtentsXMF fontS str  -- font ascent and descent@@ -1542,7 +1574,7 @@  -- | Given the completions that we would like to show, calculate the -- required dimensions for the completion windows.-getComplWinDim :: [String] -> XP ComplWindowDim+getComplWinDim :: NonEmpty String -> XP ComplWindowDim getComplWinDim compl = do   XPS{ config = cfg, screen = scr, fontS = fs, dpy, winWidth } <- get   let -- Height of a single completion row@@ -1583,7 +1615,7 @@    -- Get font ascent and descent.  Coherence condition: we will print   -- everything using the same font.-  (asc, desc) <- io $ textExtentsXMF fs $ head compl+  (asc, desc) <- io $ textExtentsXMF fs $ NE.head compl   let yp    = fi $ (ht + fi (asc - desc)) `div` 2 -- y position of the first row       yRows = take (fi rows) [yp, yp + fi ht ..]  -- y positions of all rows @@ -1593,7 +1625,7 @@   pure $ ComplWindowDim x y winWidth rowHeight xCols yRows  -- | Draw the completion window.-drawComplWin :: Window -> [String] -> XP ()+drawComplWin :: Window -> NonEmpty String -> XP () drawComplWin w entries = do   XPS{ config, color, dpy, gcon } <- get   let scr = defaultScreenOfDisplay dpy@@ -1616,7 +1648,7 @@   -> GC   -> String         -- ^ Default foreground color   -> String         -- ^ Default background color-  -> [String]       -- ^ Entries to be printed...+  -> NonEmpty String -- ^ Entries to be printed...   -> ComplWindowDim -- ^ ...into a window of this size   -> XP () printComplEntries dpy drw gc fc bc entries ComplWindowDim{ cwCols, cwRows } = do@@ -1638,7 +1670,7 @@  where   -- | Create the completion matrix to be printed.   complMat :: [[String]]-    = chunksOf (length cwRows) (take (length cwCols * length cwRows) entries)+    = chunksOf (length cwRows) (take (length cwCols * length cwRows) (NE.toList entries))    -- | Find the column and row indexes in which a string appears.   -- If the string is not in the matrix, the indices default to @(0, 0)@.@@ -1756,7 +1788,7 @@     | " \\" `isPrefixOf` s2 = (s1 ++ " " ++ s1', s2')     | otherwise = (s1, s2)       where (s1, s2 ) = break isSpace s-            (s1',s2') = breakAtSpace $ tail s2+            (s1',s2') = breakAtSpace $ drop 1 s2  -- | 'historyCompletion' provides a canned completion function much like --   'getShellCompl'; you pass it to mkXPrompt, and it will make completions work@@ -1784,7 +1816,8 @@ -- immediately next to each other. deleteAllDuplicates, deleteConsecutive :: [String] -> [String] deleteAllDuplicates = nub-deleteConsecutive = map head . group+deleteConsecutive = map (NE.head . notEmpty) . group+-- The elements of group will always have at least one element.  newtype HistoryMatches = HistoryMatches (IORef ([String],Maybe (W.Stack String))) 
XMonad/Prompt/AppendFile.hs view
@@ -37,7 +37,7 @@ -- $usage -- -- You can use this module by importing it, along with--- "XMonad.Prompt", into your ~\/.xmonad\/xmonad.hs file:+-- "XMonad.Prompt", into your @xmonad.hs@ file: -- -- > import XMonad.Prompt -- > import XMonad.Prompt.AppendFile@@ -69,7 +69,7 @@ -- the file too. -- -- For detailed instructions on editing your key bindings, see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  newtype AppendFile = AppendFile FilePath 
XMonad/Prompt/DirExec.hs view
@@ -35,7 +35,7 @@ econst = const . return  -- $usage--- 1. In your @~\/.xmonad\/xmonad.hs@:+-- 1. In your @xmonad.hs@: -- -- > import XMonad.Prompt.DirExec --@@ -63,7 +63,7 @@ -- terminal -- -- For detailed instruction on editing the key binding see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  newtype DirExec = DirExec String 
XMonad/Prompt/Email.hs view
@@ -31,7 +31,7 @@ -- $usage -- -- You can use this module by importing it, along with--- "XMonad.Prompt", into your ~\/.xmonad\/xmonad.hs file:+-- "XMonad.Prompt", into your @xmonad.hs@ file: -- -- > import XMonad.Prompt -- > import XMonad.Prompt.Email@@ -50,7 +50,7 @@ -- characters and then hit \'tab\'. -- -- For detailed instructions on editing your key bindings, see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.   -- | Prompt the user for a recipient, subject, and body, and send an
XMonad/Prompt/FuzzyMatch.hs view
@@ -32,21 +32,21 @@ -- subsequence is a valid completion; matching is case insensitive.  This means -- that the sequence of typed characters can be obtained from the completion by -- deleting an appropriate subset of its characters.  Example: "spr" matches--- "FastSPR" but also "SuccinctParallelTrees" because it's a subsequence of the--- latter: "S.......P.r..........".+-- \"FastSPR\" but also \"SuccinctParallelTrees\" because it's a subsequence of+-- the latter: "S.......P.r..........". -- -- While this type of inclusiveness is helpful most of the time, it sometimes -- also produces surprising matches.  'fuzzySort' helps sorting matches by -- relevance, using a simple heuristic for measuring relevance.  The matches are -- sorted primarily by the length of the substring that contains the query -- characters and secondarily the starting position of the match.  So, if the--- search string is "spr" and the matches are "FastSPR", "FasterSPR", and--- "SuccinctParallelTrees", then the order is "FastSPR", "FasterSPR",--- "SuccinctParallelTrees" because both "FastSPR" and "FasterSPR" contain "spr"--- within a substring of length 3 ("SPR") while the shortest substring of--- "SuccinctParallelTrees" that matches "spr" is "SuccinctPar", which has length--- 11.  "FastSPR" is ranked before "FasterSPR" because its match starts at--- position 5 while the match in "FasterSPR" starts at position 7.+-- search string is "spr" and the matches are \"FastSPR\", \"FasterSPR\", and+-- \"SuccinctParallelTrees\", then the order is \"FastSPR\", \"FasterSPR\",+-- \"SuccinctParallelTrees\" because both \"FastSPR\" and \"FasterSPR\" contain+-- "spr" within a substring of length 3 (\"SPR\") while the shortest substring+-- of \"SuccinctParallelTrees\" that matches "spr" is \"SuccinctPar\", which has+-- length 11.  \"FastSPR\" is ranked before \"FasterSPR\" because its match+-- starts at position 5 while the match in \"FasterSPR\" starts at position 7. -- -- To use these functions in an XPrompt, for example, for windowPrompt: --@@ -63,7 +63,7 @@ -- > , ((modm .|. shiftMask, xK_g), windowPrompt myXPConfig Goto allWindows) -- -- For detailed instructions on editing the key bindings, see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  -- | Returns True if the first argument is a subsequence of the second argument, -- that is, it can be obtained from the second sequence by deleting elements.
XMonad/Prompt/Input.hs view
@@ -56,7 +56,7 @@ -- create an autocompleting version, like this: -- -- > firingPrompt' = inputPromptWithCompl def "Fire"--- >                     (mkComplFunFromList employees) ?+ fireEmployee+-- >                     (mkComplFunFromList def employees) ?+ fireEmployee -- -- Now all he has to do is add a keybinding to @firingPrompt@ (or -- @firingPrompt'@), such as@@ -70,7 +70,7 @@ -- invoked. -- -- (For detailed instructions on editing your key bindings, see--- "XMonad.Doc.Extending#Editing_key_bindings".)+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.) -- -- "XMonad.Prompt.Input" is also intended to ease the process of -- developing other modules which require user input. For an example
XMonad/Prompt/Layout.hs view
@@ -26,7 +26,7 @@ import XMonad.StackSet ( workspaces, layout )  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Prompt -- > import XMonad.Prompt.Layout@@ -34,7 +34,7 @@ -- >   , ((modm .|. shiftMask, xK_m     ), layoutPrompt def) -- -- For detailed instruction on editing the key binding see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>. -- -- WARNING: This prompt won't display all possible layouts, because the -- code to enable this was rejected from xmonad core.  It only displays
XMonad/Prompt/Man.hs view
@@ -39,7 +39,7 @@ import qualified Control.Exception as E  -- $usage--- 1. In your @~\/.xmonad\/xmonad.hs@:+-- 1. In your @xmonad.hs@: -- -- > import XMonad.Prompt -- > import XMonad.Prompt.Man@@ -49,7 +49,7 @@ -- >     , ((modm, xK_F1), manPrompt def) -- -- For detailed instruction on editing the key binding see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  data Man = Man @@ -88,7 +88,7 @@  -- | Run a command using shell and return its output. ----- XXX Merge into 'XMonad.Util.Run'?+-- XXX Merge into "XMonad.Util.Run"? -- -- (Ask \"gurus\" whether @evaluate (length ...)@ approach is -- better\/more idiomatic.)
XMonad/Prompt/OrgMode.hs view
@@ -3,8 +3,10 @@ {-# LANGUAGE LambdaCase          #-} {-# LANGUAGE NamedFieldPuns      #-} {-# LANGUAGE OverloadedStrings   #-}+{-# LANGUAGE RecordWildCards     #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE StrictData          #-}+{-# LANGUAGE ViewPatterns        #-} -------------------------------------------------------------------- -- | -- Module      :  XMonad.Prompt.OrgMode@@ -23,8 +25,8 @@ -- -- It can be used to quickly save TODOs, NOTEs, and the like with the -- additional capability to schedule/deadline a task, add a priority,--- and use the system's clipboard (really: the primary selection) as the--- contents of the note.+-- refile to some existing heading, and use the system's clipboard+-- (really: the primary selection) as the contents of the note. -- -- A blog post highlighting some features of this module can be found -- <https://tony-zorman.com/posts/orgmode-prompt/2022-08-27-xmonad-and-org-mode.html here>.@@ -36,6 +38,8 @@      -- * Prompts     orgPrompt,              -- :: XPConfig -> String -> FilePath -> X ()+    orgPromptRefile,        -- :: XPConfig -> [String] -> String -> FilePath -> X ()+    orgPromptRefileTo,      -- :: XPConfig -> String -> String -> FilePath -> X ()     orgPromptPrimary,       -- :: XPConfig -> String -> FilePath -> X ()      -- * Types@@ -56,13 +60,22 @@  import XMonad.Prelude -import XMonad (X, io)-import XMonad.Prompt (XPConfig, XPrompt (showXPrompt), mkXPrompt)+import XMonad (X, io, whenJust)+import XMonad.Prompt (XPConfig, XPrompt (showXPrompt), mkXPromptWithReturn, mkComplFunFromList, ComplFunction) import XMonad.Util.Parser import XMonad.Util.XSelection (getSelection)+import XMonad.Util.Run -import Data.Time (Day (ModifiedJulianDay), NominalDiffTime, UTCTime (utctDay), addUTCTime, defaultTimeLocale, formatTime, fromGregorian, getCurrentTime, iso8601DateFormat, nominalDay, toGregorian)-import System.IO (IOMode (AppendMode), hPutStrLn, withFile)+import Control.DeepSeq (deepseq)+import qualified Data.List.NonEmpty as NE (head)+import Data.Time (Day (ModifiedJulianDay), NominalDiffTime, UTCTime (utctDay), addUTCTime, fromGregorian, getCurrentTime, nominalDay, toGregorian)+#if MIN_VERSION_time(1, 9, 0)+import Data.Time.Format.ISO8601 (iso8601Show)+#else+import Data.Time.Format (defaultTimeLocale, formatTime, iso8601DateFormat)+#endif+import GHC.Natural (Natural)+import System.IO (IOMode (AppendMode, ReadMode), hClose, hGetContents, openFile, withFile)  {- $usage @@ -108,8 +121,8 @@ Monday and you schedule something for Monday, you will actually schedule it for the /next/ Monday (the one in seven days). -The time is specified in the @HH:MM@ format.  The minutes may be-omitted, in which case we assume a full hour is specified.+The time is specified in the @HH:MM@ or @HHMM@ format.  The minutes may+be omitted, in which case we assume a full hour is specified.  A few examples are probably in order.  Suppose we have bound the key above, pressed it, and are now confronted with a prompt:@@ -151,6 +164,20 @@ return to whatever you were doing before.  See the 'orgPromptPrimary' prompt for that. +Finally, 'orgPromptRefile' and 'orgPromptRefileTo' provide support to+automatically+<https://orgmode.org/manual/Refile-and-Copy.html refile>+the generated item under a heading of choice.  For example, binding++> orgPromptRefile def "TODO" "todos.org"++to a key will first pop up an ordinary prompt that works exactly like+'orgPrompt', and then query the user for an already existing heading+(with completions) as provided by the @~/todos.org@ file.  If that+prompt is cancelled, the heading will appear in the org file as normal+(i.e., at the end of the file); otherwise, it gets refiled under the+selected heading.+ -}  {- TODO@@ -173,6 +200,9 @@   , orgFile    :: FilePath   } +mkOrgCfg :: ClipboardSupport -> String -> FilePath -> X OrgMode+mkOrgCfg clp header fp = OrgMode clp header <$> mkAbsolutePath fp+ -- | Whether we should use a clipboard and which one to use. data ClipboardSupport   = PrimarySelection@@ -199,7 +229,7 @@                --   a single @*@   -> FilePath  -- ^ Path to @.org@ file, e.g. @home\/me\/todos.org@   -> X ()-orgPrompt xpc = mkOrgPrompt xpc .: OrgMode NoClpSupport+orgPrompt xpc = (void . mkOrgPrompt xpc =<<) .: mkOrgCfg NoClpSupport  -- | Like 'orgPrompt', but additionally make use of the primary -- selection.  If it is a URL, then use an org-style link@@ -209,12 +239,78 @@ -- The prompt will display a little @+ PS@ in the window -- after the type of note. orgPromptPrimary :: XPConfig -> String -> FilePath -> X ()-orgPromptPrimary xpc = mkOrgPrompt xpc .: OrgMode PrimarySelection+orgPromptPrimary xpc = (void . mkOrgPrompt xpc =<<) .: mkOrgCfg PrimarySelection --- | Create the actual prompt.-mkOrgPrompt :: XPConfig -> OrgMode -> X ()+-- | Internal type in order to generate a nice prompt in+-- 'orgPromptRefile' and 'orgPromptRefileTo'.+data RefilePrompt = Refile+instance XPrompt RefilePrompt where+  showXPrompt :: RefilePrompt -> String+  showXPrompt Refile = "Refile note to: "++-- | Like 'orgPrompt' (which see for the other arguments), but offer to+-- refile the entered note afterwards.+--+-- Note that refiling is done by shelling out to Emacs, hence an @emacs@+-- binary must be in @$PATH@.  One may customise this by following the+-- instructions in "XMonad.Util.Run#g:EDSL"; more specifically, by+-- changing the 'XMonad.Util.Run.emacs' field of+-- 'XMonad.Util.Run.ProcessConfig'.+orgPromptRefile :: XPConfig -> String -> FilePath -> X ()+orgPromptRefile xpc str fp = do+  orgCfg <- mkOrgCfg NoClpSupport str fp++  -- NOTE: Ideally we would just use System.IO.readFile' here+  -- (especially because it also reads everything strictly), but this is+  -- only available starting in base 4.15.x.+  fileContents <- io $ do+    handle   <- openFile (orgFile orgCfg) ReadMode+    contents <- hGetContents handle+    contents <$ (contents `deepseq` hClose handle)++  -- Save the entry as soon as possible.+  notCancelled <- mkOrgPrompt xpc orgCfg+  when notCancelled $+    -- If the user didn't cancel, try to parse the org file and offer to+    -- refile the entry if possible.+    whenJust (runParser pOrgFile fileContents) $ \headings ->+      mkXPromptWithReturn Refile xpc (completeHeadings headings) pure >>= \case+        Nothing     -> pure ()+        Just parent -> refile parent (orgFile orgCfg)+ where+  completeHeadings :: [Heading] -> ComplFunction+  completeHeadings = mkComplFunFromList xpc . map headingText++-- | Like 'orgPromptRefile', but with a fixed heading for refiling; no+-- prompt will appear to query for a target.+--+-- Heading names may omit tags, but generally need to be prefixed by the+-- correct todo keywords; e.g.,+--+-- > orgPromptRefileTo def "PROJECT Work" "TODO" "~/todos.org"+--+-- Will refile the created note @"TODO <text>"@ to the @"PROJECT Work"@+-- heading, even with the actual name is @"PROJECT Work+-- :work:other_tags:"@.  Just entering @"Work"@ will not work, as Emacs+-- doesn't recognise @"PROJECT"@ as an Org keyword by default (i.e. when+-- started in batch-mode).+orgPromptRefileTo+  :: XPConfig+  -> String     -- ^ Heading to refile the entry under.+  -> String+  -> FilePath+  -> X ()+orgPromptRefileTo xpc refileHeading str fp = do+  orgCfg       <- mkOrgCfg NoClpSupport str fp+  notCancelled <- mkOrgPrompt xpc orgCfg+  when notCancelled $ refile refileHeading (orgFile orgCfg)++-- | Create the actual prompt.  Returns 'False' when the input was+-- cancelled by the user (by, for example, pressing @Esc@ or @C-g@) and+-- 'True' otherwise.+mkOrgPrompt :: XPConfig -> OrgMode -> X Bool mkOrgPrompt xpc oc@OrgMode{ todoHeader, orgFile, clpSupport } =-  mkXPrompt oc xpc (const (pure [])) appendNote+  isJust <$> mkXPromptWithReturn oc xpc (const (pure [])) appendNote  where   -- | Parse the user input, create an @org-mode@ note out of that and   -- try to append it to the given file.@@ -228,14 +324,32 @@                then Header sel                else Body   $ "\n " <> sel -    -- Expand path if applicable-    fp <- mkAbsolutePath orgFile--    withFile fp AppendMode . flip hPutStrLn+    withFile orgFile AppendMode . flip hPutStrLn       <=< maybe (pure "") (ppNote clpStr todoHeader) . pInput         $ input  ------------------------------------------------------------------------+-- Refiling++-- | Let Emacs do the refiling, as this seems—and I know how this+-- sounds—more robust than trying to do it ad-hoc in this module.+refile :: String -> FilePath -> X ()+refile (asString -> parent) (asString -> fp) =+  proc $ inEmacs+     >-> asBatch+     >-> eval (progn [ "find-file" <> fp+                     , "end-of-buffer"+                     , "org-refile nil nil"+                         <> list [ parent+                                 , fp+                                 , "nil"+                                 , saveExcursion ["org-find-exact-headline-in-buffer"+                                                    <> parent]+                                 ]+                     , "save-buffer"+                     ])++------------------------------------------------------------------------ -- Time  -- | A 'Time' is a 'Date' with the possibility of having a specified@@ -274,7 +388,11 @@   mconcat ["<", isoDay, " ", take 3 $ show (dayOfWeek day), time, ">"]  where   time   :: String = maybe "" ((' ' :) . show) tod+#if MIN_VERSION_time(1, 9, 0)+  isoDay :: String = iso8601Show day+#else   isoDay :: String = formatTime defaultTimeLocale (iso8601DateFormat Nothing) day+#endif  -- | Pretty print a 'Date' and an optional time to reflect the actual -- date.@@ -375,7 +493,7 @@       otherPrio  -> " [#" <> show otherPrio <> "] "  --------------------------------------------------------------------------- Parsing+-- Note parsing  -- | Parse the given string into a 'Note'. pInput :: String -> Maybe Note@@ -408,29 +526,38 @@    where     go :: String -> Parser String     go consumed = do-      str  <- munch  (/= head ptn)+      str  <- munch  (/= NE.head (notEmpty ptn))       word <- munch1 (/= ' ')       bool go pure (word == ptn) $ consumed <> str <> word  -- | Parse a 'Priority'. pPriority :: Parser Priority-pPriority = pLast (pure NoPriority) $+pPriority = option NoPriority $   " " *> skipSpaces *> choice-    [ "#" *> ("A" <|> "a") $> A-    , "#" *> ("B" <|> "b") $> B-    , "#" *> ("C" <|> "c") $> C+    [ "#" *> foldCase "a" $> A+    , "#" *> foldCase "b" $> B+    , "#" *> foldCase "c" $> C     ]  -- | Try to parse a 'Time'. pTimeOfDay :: Parser (Maybe TimeOfDay)-pTimeOfDay = pLast (pure Nothing) $-  skipSpaces *> choice-    [ Just <$> (TimeOfDay <$> pHour <* string ":" <*> pMinute) -- HH:MM-    , Just <$> (TimeOfDay <$> pHour               <*> pure 0 ) -- HH+pTimeOfDay = option Nothing $+  skipSpaces >> Just <$> choice+    [ TimeOfDay <$> pHour <* ":" <*> pMinute -- HH:MM+    , pHHMM                                  -- HHMM+    , TimeOfDay <$> pHour        <*> pure 0  -- HH     ]  where-  pMinute :: Parser Int = pNumBetween 1 60-  pHour   :: Parser Int = pNumBetween 1 24+  pHHMM :: Parser TimeOfDay+  pHHMM = do+    let getTwo = count 2 (satisfy isDigit)+    hh <- read <$> getTwo+    guard (hh >= 0 && hh <= 23)+    mm <- read <$> getTwo+    guard (mm >= 0 && mm <= 59)+    pure $ TimeOfDay hh mm+  pHour   :: Parser Int = pNumBetween 0 23+  pMinute :: Parser Int = pNumBetween 0 59  -- | Parse a 'Date'. pDate :: Parser Date@@ -470,12 +597,12 @@                ])          <*> optional (skipSpaces *> num >>= \i -> guard (i >= 25) $> i) -  -- | Parse a prefix and drop a potential suffix up to the next (space+  -- Parse a prefix and drop a potential suffix up to the next (space   -- separated) word.  If successful, return @ret@.-  pPrefix :: Parser String -> String -> a -> Parser a-  pPrefix start leftover ret = do-    void start-    l <- munch (/= ' ')+  pPrefix :: String -> String -> a -> Parser a+  pPrefix start (map toLower -> leftover) ret = do+    void (foldCase start)+    l <- map toLower <$> munch (/= ' ')     guard (l `isPrefixOf` leftover)     pure ret @@ -485,8 +612,38 @@   n <- num   n <$ guard (n >= lo && n <= hi) --- | A flipped version of '(<|>)'.  Useful when @p'@ is some complicated--- expression that, for example, consumes spaces and @p@ does not want--- to do that.-pLast :: Parser a -> Parser a -> Parser a-pLast p p' = p' <|> p+-- Parse the given string case insensitively.+foldCase :: String -> Parser String+foldCase = traverse (\c -> char (toLower c) <|> char (toUpper c))++------------------------------------------------------------------------+-- File parsing++data Heading = Heading+  { level       :: Natural+    -- ^ Level of the Org heading; i.e., the number of leading stars.+  , headingText :: String+    -- ^ The heading text without its level.+  }++-- | Naïvely parse an Org file.  At this point, only the headings are+-- parsed into a non-nested list (ignoring parent-child relations); no+-- further analysis is done on the individual lines themselves.+pOrgFile :: Parser [Heading]+pOrgFile = many pHeading++pHeading :: Parser Heading+pHeading = skipSpaces *> do+  level       <- genericLength <$> munch1 (== '*') <* " "+  headingText <- pLine+  void $ many (pLine >>= \line -> guard (isNotHeading line) $> line) -- skip body+  pure Heading{..}++pLine :: Parser String+pLine = munch (/= '\n') <* "\n"++isNotHeading :: String -> Bool+isNotHeading str = case break (/= '*') str of+  ("", _)       -> True+  (_ , ' ' : _) -> False+  _             -> True
XMonad/Prompt/Pass.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE LambdaCase #-} ----------------------------------------------------------------------------- -- | -- Module      :  XMonad.Prompt.Pass@@ -16,13 +17,16 @@ -- completion system provided by "XMonad.Prompt".  Specifically, we -- provide ----- - two functions to lookup passwords in the password-store:+-- - various functions to lookup passwords in the password-store: -----     - 'passPrompt' copies the password directly to the clipboard.+--     + 'passPrompt' copies the password directly to the clipboard. -----     - 'passTypePrompt' uses @xdotool@ to type the password---       directly.+--     + 'passOTPPrompt' copies a one-time-password to the clipboard+--        (this uses <https://github.com/tadfisher/pass-otp pass-otp>). --+--     + 'passTypePrompt' and 'passOTPTypePrompt' work like the above,+--       respectively, but use @xdotool@ to type out the password.+-- -- - 'passGeneratePrompt' generates a password for a given password --   label that the user inputs. --@@ -64,26 +68,30 @@     , passGenerateAndCopyPrompt     , passGenerateAndCopyPrompt' -      -- * Misc+      -- * One-time-passwords     , passOTPPrompt+    , passOTPTypePrompt     ) where  import System.Directory (getHomeDirectory)-import System.FilePath (combine, dropExtension, takeExtension)+import System.FilePath (dropExtension, (</>)) import System.Posix.Env (getEnv)-import XMonad.Core-import XMonad.Prompt ( XPrompt-                     , showXPrompt-                     , commandToComplete-                     , nextCompletion-                     , getNextCompletion-                     , XPConfig-                     , mkXPrompt-                     , searchPredicate)+import XMonad+import XMonad.Prelude+import XMonad.Prompt+  ( XPConfig,+    XPrompt,+    commandToComplete,+    getNextCompletion,+    mkXPrompt,+    nextCompletion,+    searchPredicate,+    showXPrompt,+  ) import XMonad.Util.Run (runProcessWithInput)  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Prompt.Pass --@@ -113,16 +121,14 @@ -- -- For detailed instructions on: ----- - editing your key bindings, see "XMonad.Doc.Extending#Editing_key_bindings".+-- - editing your key bindings, see <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>. -- -- - how to setup the password store, see <http://git.zx2c4.com/password-store/about/> --   or @man 1 pass@. -- -type Predicate = String -> String -> Bool--getPassCompl :: [String] -> Predicate -> String -> IO [String]-getPassCompl compls p s = return $ filter (p s) compls+---------------------------------------------------------------------------------+-- Prompt  type PromptLabel = String @@ -133,28 +139,6 @@   commandToComplete _ c           = c   nextCompletion      _           = getNextCompletion --- | Default password store folder in @$HOME/.password-store@.----passwordStoreFolderDefault :: String -> String-passwordStoreFolderDefault home = combine home ".password-store"---- | Compute the password store's location.--- Use the @$PASSWORD_STORE_DIR@ environment variable to set the password store.--- If empty, return the password store located in user's home.----passwordStoreFolder :: IO String-passwordStoreFolder =-  getEnv "PASSWORD_STORE_DIR" >>= computePasswordStoreDir-  where computePasswordStoreDir Nothing         = fmap passwordStoreFolderDefault getHomeDirectory-        computePasswordStoreDir (Just storeDir) = return storeDir---- | A pass prompt factory.----mkPassPrompt :: PromptLabel -> (String -> X ()) -> XPConfig -> X ()-mkPassPrompt promptLabel passwordFunction xpconfig = do-  passwords <- io (passwordStoreFolder >>= getPasswords)-  mkXPrompt (Pass promptLabel) xpconfig (getPassCompl passwords $ searchPredicate xpconfig) passwordFunction- -- | A prompt to retrieve a password from a given entry. -- passPrompt :: XPConfig -> X ()@@ -171,6 +155,13 @@ passOTPPrompt :: XPConfig -> X () passOTPPrompt = mkPassPrompt "Select OTP" selectOTP +-- | A prompt to retrieve a OTP from a given entry.  Note that you will+-- need to use the <https://github.com/tadfisher/pass-otp pass-otp>+-- extension for this to work.+--+passOTPTypePrompt :: XPConfig -> X ()+passOTPTypePrompt = mkPassPrompt "Select OTP" selectOTPType+ -- | A prompt to generate a password for a given entry. -- This can be used to override an already stored entry. -- (Beware that no confirmation is asked)@@ -219,63 +210,104 @@ passEditPrompt' :: String -> XPConfig -> X () passEditPrompt' s = mkPassPrompt s editPassword +-- | A pass prompt factory.+--+mkPassPrompt :: PromptLabel -> (String -> X ()) -> XPConfig -> X ()+mkPassPrompt promptLabel passwordFunction xpconfig = do+  passwords <- io (passwordStoreFolder >>= getPasswords)+  mkXPrompt (Pass promptLabel)+            xpconfig+            (getPassCompl passwords $ searchPredicate xpconfig)+            passwordFunction+ where+  getPassCompl :: [String] -> (String -> String -> Bool) -> String -> IO [String]+  getPassCompl compls p s = return $ filter (p s) compls++  -- Compute the password store's location. Use the @$PASSWORD_STORE_DIR@+  -- environment variable to set the password store. If empty, return the+  -- password store located in user's home.+  passwordStoreFolder :: IO String+  passwordStoreFolder =+    getEnv "PASSWORD_STORE_DIR" >>= computePasswordStoreDir+   where+    -- Default password store folder in @$HOME/.password-store@.+    computePasswordStoreDir :: Maybe String -> IO String+    computePasswordStoreDir = \case+      Nothing       -> getHomeDirectory <&> (</> ".password-store")+      Just storeDir -> return storeDir++  -- Retrieve the list of passwords from the password store @passwordStoreDir@.+  getPasswords :: FilePath -> IO [String]+  getPasswords passwordStoreDir = do+    files <- runProcessWithInput "find" [+      "-L", -- Traverse symlinks+      passwordStoreDir,+      "-type", "f",+      "-name", "*.gpg",+      "-printf", "%P\n"] []+    return . map dropExtension $ lines files++---------------------------------------------------------------------------------+-- Selecting a password+ -- | Select a password. -- selectPassword :: String -> X ()-selectPassword passLabel = spawn $ "pass --clip \"" ++ escapeQuote passLabel ++ "\""+selectPassword = spawn . pass "--clip" --- | Select an OTP.+-- | Select a one-time-password and copy it to the clipboard. -- selectOTP :: String -> X ()-selectOTP passLabel = spawn $ "pass otp --clip \"" ++ escapeQuote passLabel ++ "\""+selectOTP = spawn . pass "otp --clip" +-- | Select a one-time-password and type it out.+--+selectOTPType :: String -> X ()+selectOTPType = spawn . typeString . pass "otp"+ -- | Generate a 30 characters password for a given entry. -- If the entry already exists, it is updated with a new password. -- generatePassword :: String -> X ()-generatePassword passLabel = spawn $ "pass generate --force \"" ++ escapeQuote passLabel ++ "\" 30"+generatePassword passLabel = spawn $ pass "generate --force" passLabel ++ " 30"  -- | Generate a 30 characters password for a given entry. -- If the entry already exists, it is updated with a new password. -- After generating the password, it is copied to the clipboard. -- generateAndCopyPassword :: String -> X ()-generateAndCopyPassword passLabel = spawn $ "pass generate --force -c \"" ++ escapeQuote passLabel ++ "\" 30"+generateAndCopyPassword passLabel = spawn $ pass "generate --force -c" passLabel ++ " 30"  -- | Remove a password stored for a given entry. -- removePassword :: String -> X ()-removePassword passLabel = spawn $ "pass rm --force \"" ++ escapeQuote passLabel ++ "\""+removePassword = spawn . pass "rm --force"  -- | Edit a password stored for a given entry. -- editPassword :: String -> X ()-editPassword passLabel = spawn $ "pass edit \"" ++ escapeQuote passLabel ++ "\""+editPassword = spawn . pass "edit"  -- | Type a password stored for a given entry using xdotool. -- typePassword :: String -> X ()-typePassword passLabel = spawn $ "pass \"" ++ escapeQuote passLabel-  ++ "\"|head -n1|tr -d '\n'|xdotool type --clearmodifiers --file -"--escapeQuote :: String -> String-escapeQuote = concatMap escape-  where escape :: Char -> String-        escape '"' = "\\\""-        escape x   = [x]+typePassword = spawn . typeString . pass "" --- | Retrieve the list of passwords from the password store 'passwordStoreDir'+-- | Type the given string with @xdotool@. ---getPasswords :: FilePath -> IO [String]-getPasswords passwordStoreDir = do-  files <- runProcessWithInput "find" [-    "-L", -- Traverse symlinks-    passwordStoreDir,-    "-type", "f",-    "-name", "*.gpg",-    "-printf", "%P\n"] []-  return . map removeGpgExtension $ lines files+-- >>> typeString (pass "" "arXiv")+-- "pass  \"arXiv\" | head -n1 | tr -d '\n' | xdotool type --clearmodifiers --file -"+typeString :: String -> String+typeString cmd = cmd ++ " | head -n1 | tr -d '\n' | xdotool type --clearmodifiers --file -" -removeGpgExtension :: String -> String-removeGpgExtension file | takeExtension file == ".gpg" = dropExtension file-                        | otherwise                    = file+-- | Generate a pass prompt.+--+-- >>> pass "otp" "\\n'git'\"hub\""+-- "pass otp \"\\\\n'git'\\\"hub\\\"\""+pass :: String -> String -> String+pass cmd label = concat ["pass ", cmd, " \"", concatMap escape label, "\""]+ where+  escape :: Char -> String+  escape '"'  = "\\\""+  escape '\\' = "\\\\"+  escape x    = [x]
XMonad/Prompt/RunOrRaise.hs view
@@ -22,7 +22,7 @@     ) where  import XMonad hiding (config)-import XMonad.Prelude (isNothing, isSuffixOf, liftA2)+import XMonad.Prelude import XMonad.Prompt import XMonad.Prompt.Shell import XMonad.Actions.WindowGo (runOrRaise)@@ -35,7 +35,7 @@ econst = const . return  {- $usage-1. In your @~\/.xmonad\/xmonad.hs@:+1. In your @xmonad.hs@:  > import XMonad.Prompt > import XMonad.Prompt.RunOrRaise@@ -45,7 +45,8 @@ >   , ((modm .|. controlMask, xK_x), runOrRaisePrompt def)  For detailed instruction on editing the key binding see-"XMonad.Doc.Extending#Editing_key_bindings". -}+<https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.+-}  data RunOrRaisePrompt = RRP instance XPrompt RunOrRaisePrompt where
XMonad/Prompt/Shell.hs view
@@ -52,7 +52,7 @@ econst = const . return  {- $usage-1. In your @~\/.xmonad\/xmonad.hs@:+1. In your @xmonad.hs@:  > import XMonad.Prompt > import XMonad.Prompt.Shell@@ -62,7 +62,8 @@ >   , ((modm .|. controlMask, xK_x), shellPrompt def)  For detailed instruction on editing the key binding see-"XMonad.Doc.Extending#Editing_key_bindings". -}+<https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.+-}  data Shell = Shell type Predicate = String -> String -> Bool@@ -196,7 +197,7 @@     p  <- getEnv "PATH" `E.catch` econst []     let ds = filter (/= "") $ split ':' p     es <- forM ds $ \d -> getDirectoryContents d `E.catch` econst []-    return . uniqSort . filter ((/= '.') . head) . concat $ es+    return . uniqSort . filter (not . ("." `isPrefixOf`)) . concat $ es  split :: Eq a => a -> [a] -> [[a]] split _ [] = []
XMonad/Prompt/Ssh.hs view
@@ -33,7 +33,7 @@ econst = const . return  -- $usage--- 1. In your @~\/.xmonad\/xmonad.hs@:+-- 1. In your @xmonad.hs@: -- -- > import XMonad.Prompt -- > import XMonad.Prompt.Ssh@@ -43,10 +43,10 @@ -- >   , ((modm .|. controlMask, xK_s), sshPrompt def) -- -- Keep in mind, that if you want to use the completion you have to--- disable the "HashKnownHosts" option in your ssh_config+-- disable the \"HashKnownHosts\" option in your ssh_config -- -- For detailed instruction on editing the key binding see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  data Ssh = Ssh 
XMonad/Prompt/Theme.hs view
@@ -29,7 +29,7 @@  -- $usage -- You can use this module with the following in your--- @~\/.xmonad\/xmonad.hs@:+-- @xmonad.hs@: -- -- > import XMonad.Prompt -- > import XMonad.Prompt.Theme@@ -39,7 +39,7 @@ -- >   , ((modm .|. controlMask, xK_t), themePrompt def) -- -- For detailed instruction on editing the key binding see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  data ThemePrompt = ThemePrompt 
XMonad/Prompt/Unicode.hs view
@@ -52,7 +52,7 @@ {- $usage  You can use this module by importing it, along with-"XMonad.Prompt", into your ~\/.xmonad\/xmonad.hs file:+"XMonad.Prompt", into your @xmonad.hs@ file:  > import XMonad.Prompt > import XMonad.Prompt.Unicode@@ -60,6 +60,11 @@ and adding an appropriate keybinding, for example:  >  , ((modm .|. controlMask, xK_u), unicodePrompt "/path/to/unicode-data" def)++A path to a @UnicodeData.txt@ file or equivalent must be provided.  This file+should be available through your package manager; search for @unicode-data@.+If no package is found, one may opt to download this file directly from+[unicode.org](http://www.unicode.org/Public/UNIDATA/UnicodeData.txt).  More flexibility is given by the @mkUnicodePrompt@ function, which takes a command and a list of arguments to pass as its first two arguments. See
XMonad/Prompt/Window.hs view
@@ -26,11 +26,6 @@     allApplications,     wsWindows,     XWindowMap,--    -- * Deprecated-    windowPromptGoto,-    windowPromptBring,-    windowPromptBringCopy,     ) where  import XMonad.Prelude (forM)@@ -49,7 +44,7 @@ -- where you left your XChat. It also offers helpers to build the -- subset of windows which is used for the prompt completion. ----- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Prompt -- > import XMonad.Prompt.Window@@ -70,7 +65,7 @@ -- keystrokes to the selected client. -- -- For detailed instruction on editing the key binding see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  -- Describe actions that can applied  on the selected window data WindowPrompt = Goto | Bring | BringCopy | BringToMaster | WithWindow String (Window ->  X())@@ -111,15 +106,6 @@         bringAction      = winAction bringWindow         bringCopyAction  = winAction bringCopyWindow         bringToMaster    = winAction (\w s -> W.shiftMaster . W.focusWindow w $ bringWindow w s)---- | Deprecated. Use windowPrompt instead.-{-# DEPRECATED windowPromptGoto      "Use windowPrompt instead." #-}-{-# DEPRECATED windowPromptBring     "Use windowPrompt instead." #-}-{-# DEPRECATED windowPromptBringCopy "Use windowPrompt instead." #-}-windowPromptGoto, windowPromptBring, windowPromptBringCopy :: XPConfig -> X ()-windowPromptGoto c = windowPrompt c Goto windowMap-windowPromptBring c = windowPrompt c Bring windowMap-windowPromptBringCopy c = windowPrompt c BringCopy windowMap  -- | A helper to get the map of all windows. allWindows :: XWindowMap
XMonad/Prompt/Workspace.hs view
@@ -28,7 +28,7 @@ import XMonad.Util.WorkspaceCompare ( getSortByIndex )  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Prompt -- > import XMonad.Prompt.Workspace@@ -36,7 +36,7 @@ -- >   , ((modm .|. shiftMask, xK_m     ), workspacePrompt def (windows . W.shift)) -- -- For detailed instruction on editing the key binding see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  newtype Wor = Wor String 
XMonad/Prompt/XMonad.hs view
@@ -28,7 +28,7 @@ import XMonad.Prelude (fromMaybe)  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad.Prompt -- > import XMonad.Prompt.XMonad@@ -38,7 +38,7 @@ -- >   , ((modm .|. controlMask, xK_x), xmonadPrompt def) -- -- For detailed instruction on editing the key binding see--- "XMonad.Doc.Extending#Editing_key_bindings".+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.  newtype XMonad = XMonad String 
XMonad/Prompt/Zsh.hs view
@@ -28,7 +28,7 @@  {- $usage 1. Grab the @capture.zsh@ script to capture zsh completions from <https://github.com/Valodim/zsh-capture-completion>-2. In your @~\/.xmonad\/xmonad.hs@:+2. In your @xmonad.hs@:  > import XMonad.Prompt > import XMonad.Prompt.Zsh@@ -38,7 +38,7 @@ >   , ((modm .|. controlMask, xK_x), zshPrompt def "/path/to/capture.zsh")  For detailed instruction on editing the key binding see-"XMonad.Doc.Extending#Editing_key_bindings". -}+<https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>. -}  data Zsh = Zsh 
XMonad/Util/ActionCycle.hs view
@@ -33,7 +33,7 @@   -- $usage--- You can use this module to implement cycling key-bindings by importing 'XMonad.Util.ActionCycle'+-- You can use this module to implement cycling key-bindings by importing "XMonad.Util.ActionCycle" -- -- > import XMonad.Util.ActionCycle --
XMonad/Util/CustomKeys.hs view
@@ -25,7 +25,7 @@  -- $usage ----- In @~\/.xmonad\/xmonad.hs@ add:+-- In @xmonad.hs@ add: -- -- > import XMonad.Util.CustomKeys --
XMonad/Util/DebugWindow.hs view
@@ -57,9 +57,7 @@                              \s -> if null s                                      then Nothing                                      else let (w'',s'') = break (== '\NUL') s-                                              s'      = if null s''-                                                          then s''-                                                          else tail s''+                                              s'        = drop 1 s''                                           in Just (w'',s')       t <- catchX' (wrap <$> getEWMHTitle  "VISIBLE" w) $            catchX' (wrap <$> getEWMHTitle  ""        w) $@@ -107,8 +105,7 @@ getEWMHTitle       :: String -> Window -> X String getEWMHTitle sub w =  do   a <- getAtom $ "_NET_WM_" ++ (if null sub then "" else '_':sub) ++ "_NAME"-  (Just t) <- withDisplay $ \d -> io $ getWindowProperty32 d a w-  return $ map (toEnum . fromEnum) t+  getDecodedStringProp w a -- should always be UTF8_STRING but rules are made to be broken  getICCCMTitle   :: Window -> X String getICCCMTitle w =  getDecodedStringProp w wM_NAME@@ -116,7 +113,7 @@ getDecodedStringProp     :: Window -> Atom -> X String getDecodedStringProp w a =  do   t@(TextProperty t' _ 8 _) <- withDisplay $ \d -> io $ getTextProperty d w a-  [s] <- catchX' (tryUTF8     t) $+  [s] <- catchX' (tryUTF8     t) $ -- shouldn't happen but some apps do it          catchX' (tryCompound t) $          io ((:[]) <$> peekCString t')   return s@@ -125,7 +122,7 @@ tryUTF8 (TextProperty s enc _ _) =  do   uTF8_STRING <- getAtom "UTF8_STRING"   when (enc /= uTF8_STRING) $ error "String is not UTF8_STRING"-  map decodeString . splitNul <$> io (peekCString s)+  map decodeString . splitNul <$> io (peekCAString s)  tryCompound                            :: TextProperty -> X [String] tryCompound t@(TextProperty _ enc _ _) =  do@@ -203,7 +200,7 @@                                       Just s'' -> s''                                       _        -> '<':show a ++ ">"                             unAtoms as (t ++ (if i then ' ':s else s)) True-    +     simplify       :: String -> Atom -> X String     simplify pfx a =  do                         s' <- io $ getAtomName d a@@ -215,10 +212,10 @@                                        return s      -- note that above it says this checks all of them before simplifying.-    -- I'll do that after I'm confident this works as intended.    +    -- I'll do that after I'm confident this works as intended.     windowState     :: [Atom] -> X String     windowState []  =  return ""     windowState as' =  go as' ";"       where         go []     t = return t-        go (a:as) t = simplify "_NET_WM_STATE_" a >>= \t' -> go as (t ++ ' ':t') +        go (a:as) t = simplify "_NET_WM_STATE_" a >>= \t' -> go as (t ++ ' ':t')
XMonad/Util/EZConfig.hs view
@@ -1,4 +1,6 @@ {-# LANGUAGE CPP #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE ScopedTypeVariables #-} -------------------------------------------------------------------- -- | -- Module      :  XMonad.Util.EZConfig@@ -23,6 +25,7 @@                              -- * Adding or removing keybindings                               additionalKeys, additionalKeysP,+                             remapKeysP,                              removeKeys, removeKeysP,                              additionalMouseBindings, removeMouseBindings, @@ -49,11 +52,13 @@ import XMonad.Util.Parser  import Control.Arrow (first, (&&&))+import qualified Data.List.NonEmpty as NE import qualified Data.Map as M import Data.Ord (comparing)+import Data.List.NonEmpty (nonEmpty)  -- $usage--- To use this module, first import it into your @~\/.xmonad\/xmonad.hs@:+-- To use this module, first import it into your @xmonad.hs@: -- -- > import XMonad.Util.EZConfig --@@ -90,6 +95,7 @@ additionalKeys :: XConfig a -> [((KeyMask, KeySym), X ())] -> XConfig a additionalKeys conf keyList =     conf { keys = M.union (M.fromList keyList) . keys conf }+infixl 4 `additionalKeys`  -- | Like 'additionalKeys', except using short @String@ key --   descriptors like @\"M-m\"@ instead of @(modMask, xK_m)@, as@@ -104,8 +110,44 @@ additionalKeysP :: XConfig l -> [(String, X ())] -> XConfig l additionalKeysP conf keyList =     conf { keys = \cnf -> M.union (mkKeymap cnf keyList) (keys conf cnf) }+infixl 4 `additionalKeysP`  -- |+-- Remap keybindings from one binding to another.  More precisely, the+-- input list contains pairs of the form @(TO, FROM)@, and maps the+-- action bound to @FROM@ to the key @TO@.  For example, the following+-- would bind @"M-m"@ to what's bound to @"M-c"@ (which is to close the+-- focused window, in this case):+--+-- > main :: IO ()+-- > main = xmonad $ def `remapKeysP` [("M-m", "M-c")]+--+-- NOTE: Submaps are not transparent, and thus these keys can't be+-- accessed in this way: more explicitly, the @FROM@ string may **not**+-- be a submap.  However, the @TO@ can be a submap without problems.+-- This means that+--+-- > xmonad $ def `remapKeysP` [("M-m", "M-c a")]+--+-- is illegal (and indeed will just disregard the binding altogether),+-- while+--+-- > xmonad $ def `remapKeysP` [("M-c a", "M-m")]+--+-- is totally fine.+remapKeysP :: XConfig l -> [(String, String)] -> XConfig l+remapKeysP conf keyList =+    conf { keys = \cnf -> mkKeymap cnf (keyList' cnf) <> keys conf cnf }+  where+   keyList' :: XConfig Layout -> [(String, X ())]+   keyList' cnf =+     mapMaybe (traverse (\s -> case readKeySequence cnf s of+                                 Just (ks :| []) -> keys conf cnf M.!? ks+                                 _               -> Nothing))+              keyList+infixl 4 `remapKeysP`++-- | -- Remove standard keybindings you're not using. Example use: -- -- > main = xmonad $ def { terminal = "urxvt" }@@ -113,6 +155,7 @@ removeKeys :: XConfig a -> [(KeyMask, KeySym)] -> XConfig a removeKeys conf keyList =     conf { keys = \cnf -> foldr M.delete (keys conf cnf) keyList }+infixl 4 `removeKeys`  -- | Like 'removeKeys', except using short @String@ key descriptors --   like @\"M-m\"@ instead of @(modMask, xK_m)@, as described in the@@ -123,17 +166,20 @@  removeKeysP :: XConfig l -> [String] -> XConfig l removeKeysP conf keyList =-    conf { keys = \cnf -> keys conf cnf `M.difference` mkKeymap cnf (zip keyList $ repeat (return ())) }+    conf { keys = \cnf -> keys conf cnf `M.difference` mkKeymap cnf (map (, return ()) keyList) }+infixl 4 `removeKeysP`  -- | Like 'additionalKeys', but for mouse bindings. additionalMouseBindings :: XConfig a -> [((ButtonMask, Button), Window -> X ())] -> XConfig a additionalMouseBindings conf mouseBindingsList =     conf { mouseBindings = M.union (M.fromList mouseBindingsList) . mouseBindings conf }+infixl 4 `additionalMouseBindings`  -- | Like 'removeKeys', but for mouse bindings. removeMouseBindings :: XConfig a -> [(ButtonMask, Button)] -> XConfig a removeMouseBindings conf mouseBindingList =     conf { mouseBindings = \cnf -> foldr M.delete (mouseBindings conf cnf) mouseBindingList }+infixl 4 `removeMouseBindings`   --------------------------------------------------------------@@ -383,35 +429,40 @@ -- | Given a list of pairs of parsed key sequences and actions, --   group them into submaps in the appropriate way. -mkNamedSubmaps :: [([(KeyMask, KeySym)], NamedAction)] -> [((KeyMask, KeySym), NamedAction)]+mkNamedSubmaps :: [(NonEmpty (KeyMask, KeySym), NamedAction)] -> [((KeyMask, KeySym), NamedAction)] mkNamedSubmaps = mkSubmaps' submapName -mkSubmaps :: [ ([(KeyMask,KeySym)], X ()) ] -> [((KeyMask, KeySym), X ())]+mkSubmaps :: [ (NonEmpty (KeyMask, KeySym), X ()) ] -> [((KeyMask, KeySym), X ())] mkSubmaps = mkSubmaps' $ submap . M.fromList -mkSubmaps' ::  (Ord a) => ([(a, c)] -> c) -> [([a], c)] -> [(a, c)]+mkSubmaps' :: forall a b. (Ord a) => ([(a, b)] -> b) -> [(NonEmpty a, b)] -> [(a, b)] mkSubmaps' subm binds = map combine gathered-  where gathered = groupBy fstKey-                 . sortBy (comparing fst)-                 $ binds-        combine [([k],act)] = (k,act)-        combine ks = (head . fst . head $ ks,-                      subm . mkSubmaps' subm $ map (first tail) ks)-        fstKey = (==) `on` (head . fst)+  where+   gathered :: [[(NonEmpty a, b)]]+   gathered = groupBy fstKey . sortBy (comparing fst) $ binds +   combine :: [(NonEmpty a, b)] -> (a, b)+   combine [(k :| [], act)] = (k, act)+   combine ks = ( NE.head . fst . NE.head . notEmpty $ ks+                , subm . mkSubmaps' subm $ map (first (notEmpty . NE.drop 1)) ks+                )++   fstKey :: (NonEmpty a, b) -> (NonEmpty a, b) -> Bool+   fstKey = (==) `on` (NE.head . fst)+ -- | Given a configuration record and a list of (key sequence --   description, action) pairs, parse the key sequences into lists of --   @(KeyMask,KeySym)@ pairs.  Key sequences which fail to parse will --   be ignored.-readKeymap :: XConfig l -> [(String, t)] -> [([(KeyMask, KeySym)], t)]+readKeymap :: XConfig l -> [(String, t)] -> [(NonEmpty (KeyMask, KeySym), t)] readKeymap c = mapMaybe (maybeKeys . first (readKeySequence c))   where maybeKeys (Nothing,_) = Nothing         maybeKeys (Just k, act) = Just (k, act)  -- | Parse a sequence of keys, returning Nothing if there is --   a parse failure (no parse, or ambiguous parse).-readKeySequence :: XConfig l -> String -> Maybe [(KeyMask, KeySym)]-readKeySequence c = runParser (parseKeySequence c <* eof)+readKeySequence :: XConfig l -> String -> Maybe (NonEmpty (KeyMask, KeySym))+readKeySequence c = nonEmpty <=< runParser (parseKeySequence c <* eof)  -- | Parse a sequence of key combinations separated by spaces, e.g. --   @\"M-c x C-S-2\"@ (mod+c, x, ctrl+shift+2).@@ -437,7 +488,7 @@                      return $ indexMod (read [n] - 1)     where indexMod = (!!) [mod1Mask,mod2Mask,mod3Mask,mod4Mask,mod5Mask] --- | Parse an unmodified basic key, like @\"x\"@, @\"<F1>\"@, etc.+-- | Parse an unmodified basic key, like @\"x\"@, @\"\<F1\>\"@, etc. parseKey :: Parser KeySym parseKey = parseSpecial <> parseRegular @@ -501,8 +552,8 @@ doKeymapCheck conf km = (bad,dups)   where ks = map ((readKeySequence conf &&& id) . fst) km         bad = nub . map snd . filter (isNothing . fst) $ ks-        dups = map (snd . head)-             . filter ((>1) . length)+        dups = map (snd . NE.head)+             . mapMaybe nonEmpty              . groupBy ((==) `on` fst)              . sortBy (comparing fst)              . map (first fromJust)
XMonad/Util/ExclusiveScratchpads.hs view
@@ -15,7 +15,9 @@ -- ----------------------------------------------------------------------------- -module XMonad.Util.ExclusiveScratchpads (+module XMonad.Util.ExclusiveScratchpads+  {-# DEPRECATED "Use the exclusive scratchpad functionality of \"XMonad.Util.NamedScratchpad\" insead." #-}+  (   -- * Usage   -- $usage   mkXScratchpads,@@ -37,13 +39,14 @@   customFloating   ) where -import XMonad.Prelude (appEndo, filterM, liftA2, (<=<))+import XMonad.Prelude import XMonad import XMonad.Actions.Minimize import XMonad.Actions.TagWindows (addTag,delTag) import XMonad.Hooks.ManageHelpers (doRectFloat,isInProperty)  import qualified XMonad.StackSet as W+import qualified Data.List.NonEmpty as NE  -- $usage --@@ -51,7 +54,7 @@ -- "XMonad.Layout.Minimize", please refer to the documentation of these modules for more -- information on how to configure them. ----- To use this module, put the following in your @~\/.xmonad\/xmonad.hs@:+-- To use this module, put the following in your @xmonad.hs@: -- -- > import XMonad.Utils.ExclusiveScratchpads -- > import XMonad.ManageHook (title,appName)@@ -71,11 +74,12 @@ -- -- > scratchpads = exclusiveSps ++ regularSps ----- Add the hooks to your managehook (see "XMonad.Doc.Extending#Editing_the_manage_hook"), eg.:+-- Add the hooks to your managehook (see "XMonad.Doc.Extending#Editing_the_manage_hook" or+-- <https://xmonad.org/TUTORIAL.html#final-touches the tutorial>); e.g., -- -- > manageHook = myManageHook <> xScratchpadsManageHook scratchpads ----- And finally add some keybindings (see "XMonad.Doc.Extending#Editing_key_bindings"):+-- And finally add some keybindings (see <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>): -- -- > , ((modMask, xK_h), scratchpadAction scratchpads "htop") -- > , ((modMask, xK_c), scratchpadAction scratchpads "xclock")@@ -171,8 +175,8 @@   let ys = filterM (flip runQuery w . query) xs    unlessX (null <$> ys) $ do-    mh <- head . map hook <$> ys  -- ys /= [], so `head` is fine-    n  <- head . map name <$> ys  -- same+    mh <- NE.head . notEmpty . map hook <$> ys  -- ys /= [], so `head` is fine+    n  <- NE.head . notEmpty . map name <$> ys  -- same      (windows . appEndo <=< runQuery mh) w     hideOthers xs n
XMonad/Util/Font.hs view
@@ -123,12 +123,15 @@   if xftPrefix `isPrefixOf` s then      do dpy <- asks display         let fonts = case wordsBy (== ',') (drop (length xftPrefix) s) of-              []       -> "xft:monospace" :| []  -- NE.singleton only in base 4.15+              []       -> fallback :| []  -- NE.singleton only in base 4.15               (x : xs) -> x :| xs-        Xft <$> io (traverse (openFont dpy) fonts)+        fb <- io $ openFont dpy fallback+        fmap Xft . io $ traverse (\f -> E.catch (openFont dpy f) (econst $ pure fb))+                                 fonts   else Utf8 <$> initUtf8Font s  where   xftPrefix = "xft:"+  fallback  = "xft:monospace"   openFont dpy str = xftFontOpen dpy (defaultScreenOfDisplay dpy) str   wordsBy p str = case dropWhile p str of     ""   -> []
+ XMonad/Util/History.hs view
@@ -0,0 +1,128 @@+{-# LANGUAGE NamedFieldPuns, DeriveTraversable #-}++-----------------------------------------------------------------------------+-- |+-- Module      :  XMonad.Util.History+-- Description :  Track history in /O(log n)/ time.+-- Copyright   :  (c) 2022 L. S. Leary+-- License     :  BSD3-style (see LICENSE)+--+-- Maintainer  :  @LSLeary (on github)+-- Stability   :  unstable+-- Portability :  unportable+--+-- Provides 'History', a variation on a LIFO stack with a uniqueness property.+-- In order to achieve the desired asymptotics, the data type is implemented as+-- an ordered Map.+--+-----------------------------------------------------------------------------++module XMonad.Util.History (+  History,+  origin,+  event,+  erase,+  recall,+  ledger,+  transcribe,+  ) where++-- base+import Data.Function (on)+import Text.Read+  ( Read(readPrec, readListPrec), Lexeme(Ident)+  , parens, prec, lexP, step, readListPrecDefault+  )++-- containers+import Data.IntMap (IntMap)+import qualified Data.IntMap.Strict as I+import Data.Map (Map)+import qualified Data.Map.Strict as M+++-- | A history of unique @k@-events with @a@-annotations.+--+--   @History k a@ can be considered a (LIFO) stack of @(k, a)@ values with the+--   property that each @k@ is unique. From this point of view, 'event' pushes+--   and 'ledger' pops/peeks all.+--+--   The naive implementation has /O(n)/ 'event' and 'erase' due to the+--   uniqueness condition, but we can still use it as a denotation:+--+-- > mu :: History k a -> [(k, a)]+--+--   As an opaque data type with strict operations, @History k a@ values are all+--   finite expressions in the core interface: 'origin', 'erase' and 'event'.+--   Hence we define @mu@ by structural induction on these three cases.+--+data History k a = History+  { annals   :: !(IntMap (k, a))+  , recorded :: !(Map k Int)+  } deriving (Functor, Foldable, Traversable)++instance (Eq  k, Eq  a) => Eq  (History k a) where (==)    = (==)    `on` ledger+instance (Ord k, Ord a) => Ord (History k a) where compare = compare `on` ledger++instance (Show k, Show a) => Show (History k a) where+  showsPrec d h+    = showParen (d > app_prec)+    $ showString "transcribe "+    . showsPrec (app_prec+1) (ledger h)+    where app_prec = 10++instance (Read k, Read a, Ord k) => Read (History k a) where+  readPrec = parens . prec app_prec $ do+    Ident "transcribe" <- lexP+    l <- step readPrec+    pure (transcribe l)+    where app_prec = 10+  readListPrec = readListPrecDefault+++-- | /O(1)/. A history of nothing.+--+-- > mu origin := []+--+origin :: History k a+origin = History I.empty M.empty++-- | /O(log n)/. A new event makes history; its predecessor forgotten.+--+-- > mu (event k a h) := (k, a) : mu (erase k h)+--+event :: Ord k => k -> a -> History k a -> History k a+event k a History{annals,recorded} = History+  { annals   = I.insert ik (k, a) . maybe id I.delete mseen $ annals+  , recorded = recorded'+  }+  where+    ik = maybe 0 (\((i, _), _) -> pred i) (I.minViewWithKey annals)+    (mseen, recorded') = M.insertLookupWithKey (\_ x _ -> x) k ik recorded++-- | /O(log n)/. Erase an event from history.+--+-- > mu (erase k h) := filter ((k /=) . fst) (mu h)+--+erase :: Ord k => k -> History k a -> History k a+erase k History{annals,recorded} = History+  { annals   = maybe id I.delete mseen annals+  , recorded = recorded'+  }+  where (mseen, recorded') = M.updateLookupWithKey (\_ _ -> Nothing) k recorded+++-- | /O(log n)/. Recall an event.+recall :: Ord k => k -> History k a -> Maybe a+recall k History{annals,recorded} = do+  ik     <- M.lookup k recorded+  (_, a) <- I.lookup ik annals+  pure a++-- | /O(n)/. Read history, starting with the modern day. @ledger@ is @mu@.+ledger :: History k a -> [(k, a)]+ledger = I.elems . annals++-- | /O(n * log n)/. Transcribe a ledger.+transcribe :: Ord k => [(k, a)] -> History k a+transcribe = foldr (uncurry event) origin
XMonad/Util/Image.hs view
@@ -22,7 +22,8 @@     ) where  import XMonad-import XMonad.Util.Font (stringToPixel,fi)+import XMonad.Prelude+import XMonad.Util.Font (stringToPixel)  -- | Placement of the icon in the title bar data Placement = OffsetLeft Int Int   -- ^ An exact amount of pixels from the upper left corner@@ -42,7 +43,7 @@  -- | Gets the ('width', 'height') of an image imageDims :: [[Bool]] -> (Int, Int)-imageDims img = (length (head img), length img)+imageDims img = (length (fromMaybe [] (listToMaybe img)), length img)  -- | Return the 'x' and 'y' positions inside a 'Rectangle' to start drawing --   the image given its 'Placement'
XMonad/Util/Loggers.hs view
@@ -35,13 +35,16 @@     -- $xmonad     , logCurrent, logLayout     , logTitle, logTitles, logTitles'+    , logClassname, logClassnames, logClassnames'     , logConst, logDefault, (.|)     -- * XMonad: Screen-specific Loggers     -- $xmonad-screen     , logCurrentOnScreen, logLayoutOnScreen-    , logTitleOnScreen, logWhenActive+    , logTitleOnScreen, logClassnameOnScreen, logWhenActive     , logTitlesOnScreen, logTitlesOnScreen'+    , logClassnamesOnScreen, logClassnamesOnScreen'     , TitlesFormat(..)+    , ClassnamesFormat(..)     -- * Formatting Utilities     -- $format     , onLogger@@ -58,7 +61,7 @@ import XMonad.Hooks.StatusBar.PP import XMonad.Hooks.UrgencyHook (readUrgents) import XMonad.Util.Font (Align (..))-import XMonad.Util.NamedWindows (getName)+import XMonad.Util.NamedWindows (getName, getNameWMClass)  import Control.Exception as E import XMonad.Prelude (find, fromMaybe, isPrefixOf, isSuffixOf, WindowScreen)@@ -71,7 +74,7 @@ econst = const . return  -- $usage--- Use this module by importing it into your @~\/.xmonad\/xmonad.hs@:+-- Use this module by importing it into your @xmonad.hs@: -- -- > import XMonad.Util.Loggers --@@ -175,9 +178,13 @@ -- example you can loggerize the number of windows on each workspace, or -- titles on other workspaces, or the id of the previously focused workspace.... +-- | Internal function to get a wrapped title string from a window+fetchWindowTitle :: Window -> X String+fetchWindowTitle = fmap show . getName+ -- | Get the title (name) of the focused window. logTitle :: Logger-logTitle = withWindowSet $ traverse (fmap show . getName) . W.peek+logTitle = logWindowInfoFocusedWindow fetchWindowTitle  -- | Get the titles of all windows on the visible workspace of the given -- screen and format them according to the given functions.@@ -199,41 +206,24 @@   -> (String -> String) -- ^ Formatting for the unfocused window   -> Logger logTitlesOnScreen sid formatFoc formatUnfoc =-  logTitlesOnScreen' sid TitlesFormat{ focusedFormat   = formatFoc-                                     , unfocusedFormat = formatUnfoc-                                     , urgentFormat    = formatUnfoc-                                     }+  logWindowInfoOnScreen fetchWindowTitle sid formatFoc formatUnfoc formatUnfoc  -- | Like 'logTitlesOnScreen' but with support for urgent windows.  To -- be used with "XMonad.Hooks.UrgencyHook". logTitlesOnScreen' :: ScreenId -> TitlesFormat -> Logger logTitlesOnScreen' sid (TitlesFormat formatFoc formatUnfoc formatUrg) =-  (`withScreen` sid) $ \screen -> do-    let focWin = fmap W.focus . W.stack . W.workspace $ screen-    urgWins <- readUrgents-    logTitlesOnScreenWorker screen $ \win name ->-      if | Just win == focWin -> formatFoc   name-         | win `elem` urgWins -> formatUrg   name-         | otherwise          -> formatUnfoc name---- | Internal function for 'logTitlesOnScreen' and 'logTitlesOnScreen''.-logTitlesOnScreenWorker :: WindowScreen -> (Window -> String -> String) -> Logger-logTitlesOnScreenWorker screen logger = do-  let wins = maybe [] W.integrate . W.stack . W.workspace $ screen-  winNames <- traverse (fmap show . getName) wins-  pure . Just . unwords $ zipWith logger wins winNames+  logWindowInfoOnScreen fetchWindowTitle sid formatFoc formatUnfoc formatUrg  -- | Like 'logTitlesOnScreen', but directly use the "focused" screen -- (the one with the currently focused workspace). logTitles :: (String -> String) -> (String -> String) -> Logger-logTitles formatFoc formatUnfoc = do-  sid <- gets $ W.screen . W.current . windowset-  logTitlesOnScreen sid formatFoc formatUnfoc+logTitles formatFoc formatUnfoc =+  logWindowInfoFocusedScreen fetchWindowTitle formatFoc formatUnfoc formatUnfoc  -- | Variant of 'logTitles', but with support for urgent windows. logTitles' :: TitlesFormat -> Logger-logTitles' formatter =-  gets (W.screen . W.current . windowset) >>= (`logTitlesOnScreen'` formatter)+logTitles' (TitlesFormat formatFoc formatUnfoc formatUrg) =+  logWindowInfoFocusedScreen fetchWindowTitle formatFoc formatUnfoc formatUrg  -- | Formatting applied to the titles of certain windows. data TitlesFormat = TitlesFormat@@ -246,11 +236,114 @@ -- 'logTitlesOnScreen''. instance Default TitlesFormat where   def = TitlesFormat-    { focusedFormat   = wrap "[" "]" . xmobarRaw . shorten 30 . xmobarStrip-    , unfocusedFormat =                xmobarRaw . shorten 30 . xmobarStrip-    , urgentFormat    = wrap "!" "!" . xmobarRaw . shorten 30 . xmobarStrip+    { focusedFormat   = xmobarFocusedFormat+    , unfocusedFormat = xmobarWsFormat+    , urgentFormat    = xmobarUrgentFormat     } +-- | Internal function to get a wrapped classname string from a window+fetchWindowClassname :: Window -> X String+fetchWindowClassname = fmap show . getNameWMClass++-- | Get the classname of the focused window.+logClassname :: Logger+logClassname = logWindowInfoFocusedWindow fetchWindowClassname++-- | Get the classnames of all windows on the visible workspace of the given+-- screen and format them according to the given functions.+logClassnamesOnScreen+  :: ScreenId           -- ^ Screen to log the classnames on+  -> (String -> String) -- ^ Formatting for the focused window+  -> (String -> String) -- ^ Formatting for the unfocused window+  -> Logger+logClassnamesOnScreen sid formatFoc formatUnfoc =+  logWindowInfoOnScreen fetchWindowClassname sid formatFoc formatUnfoc formatUnfoc++-- | Like 'logClassnamesOnScreen' but with support for urgent windows.  To+-- be used with "XMonad.Hooks.UrgencyHook".+logClassnamesOnScreen' :: ScreenId -> ClassnamesFormat -> Logger+logClassnamesOnScreen' sid (ClassnamesFormat formatFoc formatUnfoc formatUrg) =+  logWindowInfoOnScreen fetchWindowClassname sid formatFoc formatUnfoc formatUrg++-- | Like 'logClassnamesOnScreen', but directly use the "focused" screen+-- (the one with the currently focused workspace).+logClassnames :: (String -> String) -> (String -> String) -> Logger+logClassnames formatFoc formatUnfoc =+  logWindowInfoFocusedScreen fetchWindowClassname formatFoc formatUnfoc formatUnfoc++-- | Variant of 'logClassnames', but with support for urgent windows.+logClassnames' :: ClassnamesFormat -> Logger+logClassnames' (ClassnamesFormat formatFoc formatUnfoc formatUrg) =+  logWindowInfoFocusedScreen fetchWindowClassname formatFoc formatUnfoc formatUrg++-- | Formatting applied to the classnames of certain windows.+data ClassnamesFormat = ClassnamesFormat+  { focusedFormatClassname   :: String -> String  -- ^ Focused formatting.+  , unfocusedFormatClassname :: String -> String  -- ^ Unfocused formatting.+  , urgentFormatClassname    :: String -> String  -- ^ Formatting when urgent.+  }++-- | How to format these classnames by default when using 'logClassnames'' and+-- 'logClassnamesOnScreen''.+instance Default ClassnamesFormat where+  def = ClassnamesFormat+    { focusedFormatClassname   = xmobarFocusedFormat+    , unfocusedFormatClassname = xmobarWsFormat+    , urgentFormatClassname    = xmobarUrgentFormat+    }++-- | Internal function to get the specified window information for all windows on+-- the visible workspace of the given screen and format them according to the+-- given functions.+logWindowInfoOnScreen+  :: (Window -> X String)+  -> ScreenId+  -> (String -> String)+  -> (String -> String)+  -> (String -> String)+  -> Logger+logWindowInfoOnScreen getWindowInfo sid formatFoc formatUnfoc formatUrg =+  (`withScreen` sid) $ \screen -> do+    let focWin = fmap W.focus . W.stack . W.workspace $ screen+    urgWins <- readUrgents+    logWindowInfoOnScreenWorker getWindowInfo screen $ \win name ->+      if | Just win == focWin -> formatFoc   name+         | win `elem` urgWins -> formatUrg   name+         | otherwise          -> formatUnfoc name++-- | Internal helper function for 'logWindowInfoOnScreen'.+logWindowInfoOnScreenWorker+  :: (Window -> X String)+  -> WindowScreen+  -> (Window -> String -> String)+  -> Logger+logWindowInfoOnScreenWorker getWindowInfo screen logger = do+  let wins = maybe [] W.integrate . W.stack . W.workspace $ screen+  winNames <- traverse getWindowInfo wins+  pure . Just . unwords $ zipWith logger wins winNames++-- | Internal. Like 'logWindowInfoOnScreen', but directly use the "focused" screen+-- (the one with the currently focused workspace).+logWindowInfoFocusedScreen+  :: (Window -> X String)+  -> (String -> String)+  -> (String -> String)+  -> (String -> String)+  -> Logger+logWindowInfoFocusedScreen getWindowInfo formatFoc formatUnfoc formatUrg = do+  sid <- gets $ W.screen . W.current . windowset+  logWindowInfoOnScreen getWindowInfo sid formatFoc formatUnfoc formatUrg++-- | Internal function to get the specified information for the currently focused window+logWindowInfoFocusedWindow :: (Window -> X String) -> Logger+logWindowInfoFocusedWindow getWindowInfo = withWindowSet $ traverse getWindowInfo . W.peek++-- | Internal formatting helpers+xmobarWsFormat, xmobarFocusedFormat, xmobarUrgentFormat :: String -> String+xmobarWsFormat      = xmobarRaw . shorten 30 . xmobarStrip+xmobarFocusedFormat = wrap "[" "]" . xmobarWsFormat+xmobarUrgentFormat  = wrap "!" "!" . xmobarWsFormat+ -- | Get the name of the current layout. logLayout :: Logger logLayout = withWindowSet $ return . Just . ld@@ -297,9 +390,18 @@  -- | Get the title (name) of the focused window, on the given screen. logTitleOnScreen :: ScreenId -> Logger-logTitleOnScreen =+logTitleOnScreen = logWindowInfoFocusedWindowOnScreen fetchWindowTitle++-- | Get the classname of the focused window, on the given screen.+logClassnameOnScreen :: ScreenId -> Logger+logClassnameOnScreen = logWindowInfoFocusedWindowOnScreen fetchWindowClassname++-- | Internal function to get the specified information for the focused window,+-- on the given screen.+logWindowInfoFocusedWindowOnScreen :: (Window -> X String) -> ScreenId -> Logger+logWindowInfoFocusedWindowOnScreen getWindowInfo =   withScreen-    $ traverse (fmap show . getName)+    $ traverse getWindowInfo     . (W.focus <$>)     . W.stack     . W.workspace
XMonad/Util/Loggers/NamedScratchpad.hs view
@@ -9,7 +9,7 @@ -- Stability   :  unstable -- Portability :  unportable ----- 'XMonad.Util.Loggers' for 'XMonad.Util.NamedScratchpad'+-- "XMonad.Util.Loggers" for "XMonad.Util.NamedScratchpad" -- ----------------------------------------------------------------------------- @@ -50,7 +50,7 @@ -- (This is difficult to change; "minimizing" by moving it back to 'NSP' -- is even harder.) -- I hide the 'NamedScratchpad's from the taskbar and use this to track--- them instead (see 'XMonad.Util.NoTaskbar').+-- them instead (see "XMonad.Util.NoTaskbar").  -- The extension data for tracking NSP windows newtype NSPTrack = NSPTrack [Maybe Window]
XMonad/Util/NamedActions.hs view
@@ -205,7 +205,7 @@ addDescrKeys' (k,f) ks conf =     let shk l = f $ [(k,f $ ks l)] ^++^ ks l         keylist l = M.map getAction $ M.fromList $ ks l ^++^ [(k, shk l)]-    in conf { keys = keylist }+     in conf { keys = keylist <> keys conf }  -- | A version of the default keys from the default configuration, but with -- 'NamedAction'  instead of @X ()@
XMonad/Util/NamedScratchpad.hs view
@@ -1,5 +1,6 @@-{-# LANGUAGE InstanceSigs     #-}-{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE InstanceSigs   #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE ViewPatterns   #-} ----------------------------------------------------------------------------- -- | -- Module      :  XMonad.Util.NamedScratchpad@@ -30,37 +31,48 @@   allNamedScratchpadAction,   namedScratchpadManageHook,   nsHideOnFocusLoss,+  nsSingleScratchpadPerWorkspace,    -- * Dynamic Scratchpads   -- $dynamic-scratchpads   dynamicNSPAction,   toggleDynamicNSP, +  -- * Exclusive Scratchpads+  -- $exclusive-scratchpads+  addExclusives,+  -- ** Keyboard related+  resetFocusedNSP,+  -- ** Mouse related+  setNoexclusive,+  resizeNoexclusive,+  floatMoveNoexclusive,+   -- * Deprecations   namedScratchpadFilterOutWorkspace,   namedScratchpadFilterOutWorkspacePP,    ) where -import Data.Coerce (coerce) import Data.Map.Strict (Map, (!?)) import XMonad import XMonad.Actions.DynamicWorkspaces (addHiddenWorkspace) import XMonad.Actions.SpawnOn (spawnHere)+import XMonad.Actions.TagWindows (addTag, delTag) import XMonad.Hooks.ManageHelpers (doRectFloat) import XMonad.Hooks.RefocusLast (withRecentsIn) import XMonad.Hooks.StatusBar.PP (PP, ppSort)-import XMonad.Prelude (filterM, unless, when)+import XMonad.Prelude (appEndo, filterM, findM, foldl', for_, liftA2, unless, void, when, (<=<)) -import qualified Data.Map.Strict    as Map import qualified Data.List.NonEmpty as NE+import qualified Data.Map.Strict    as Map  import qualified XMonad.StackSet             as W import qualified XMonad.Util.ExtensibleState as XS  -- $usage -- Allows to have several floating scratchpads running different applications.--- Bind a key to 'namedScratchpadSpawnAction'.+-- Bind a key to 'namedScratchpadAction'. -- Pressing it will spawn configured application, or bring it to the current -- workspace if it already exists. -- Pressing the key with the application on the current workspace will@@ -101,7 +113,7 @@ -- >  , manageHook = namedScratchpadManageHook scratchpads -- -- For detailed instruction on editing the key binding see--- "XMonad.Doc.Extending#Editing_key_bindings"+-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> -- -- For some applications (like displaying your workspaces in a status bar) it -- is convenient to filter out the @NSP@ workspace when looking at all@@ -111,6 +123,25 @@ -- the list of workspaces from EWMH.  See the documentation of these functions -- for examples. --+-- If you want to explore this module further, scratchpads can come in+-- many forms and flavours:+--+--   + \"Regular\" scratchpads: they can be predefined and+--     summoned/banished with a key press.  These are the scratchpads+--     that you have seen above.+--+--   + [Dynamic scratchpads](#g:dynamic-scratchpads), which allow you to+--     dynamically declare existing windows as scratchpads.  These can+--     be treated as a separate type of scratchpad.+--+--   + [Exclusive](#g:exclusive-scratchpads) scratchpads, which can be+--     seen as a property of already existing scratchpads.  Marking+--     scratchpads as exclusive will not allow them to be shown on the+--     same workspace; the scratchpad being brought up will hide the+--     others.+--+-- See the relevant sections in the documentation for more information.+-- -- Further, there is also a @logHook@ that you can use to hide -- scratchpads when they lose focus; this is functionality akin to what -- some dropdown terminals provide.  See the documentation of@@ -124,23 +155,51 @@                           , hook   :: ManageHook  -- ^ Manage hook called for application window, use it to define the placement. See @nonFloating@, @defaultFloating@ and @customFloating@                           } --- | The NSP state associates a name to an entire scratchpad.-newtype NSPState = NSPState (Map String NamedScratchpad)+-- | The NSP state.+data NSPState = NSPState+  { nspExclusives  :: !(Map String NamedScratchpads)+    -- ^ Associates the name of a scratchpad to some list of scratchpads+    -- that should be mutually exclusive to it.+  , nspScratchpads :: !(Map String NamedScratchpad)+    -- ^ Associates a name to an entire scratchpad.+  }  instance ExtensionClass NSPState where   initialValue :: NSPState-  initialValue = NSPState mempty+  initialValue = NSPState mempty mempty --- | Try to fill the 'NSPState' with the given list of scratchpads.  In--- case the state is already non-empty, don't do anything and return--- that state.  Otherwise, fill the state with the given scratchpads.+-- | Try to:+--+--    (i) Fill the 'nspScratchpads' portion of the 'NSPState' with the+--        given list of scratchpads.  In case that particular map of the+--        state is already non-empty, don't do anything and return that+--        state.+--+--   (ii) Replace possibly dummy scratchpads in @nspExclusives@ with+--        proper values.  For convenience, the user may specify+--        exclusive scratchpads by name in the startup hook.  However,+--        we don't necessarily have all information then to immediately+--        turn these into proper NamedScratchpads.  As such, we thinly+--        wrap the names into an NSP skeleton, to be filled in later.+--        This function, to be executed _before_+--        'someNamedScratchpadAction' is the (latest) point where that+--        happens. fillNSPState :: NamedScratchpads -> X NSPState fillNSPState nsps = do-    nsp@(NSPState xs) <- XS.get-    let nspState = NSPState . Map.fromList $ zip (map name nsps) nsps-    if null xs-        then nspState <$ XS.put nspState-        else pure nsp+    nsp@(NSPState exs scratches) <- XS.get+    if null scratches+      then let nspState = NSPState (fillOut exs) nspScratches+            in nspState <$ XS.put nspState+      else pure nsp+  where+    -- @fillNSPState@ only runs once, so the complexity here is probably+    -- not a big deal.+    nspScratches :: Map String NamedScratchpad+    nspScratches = Map.fromList $ zip (map name nsps) nsps+    fillOut :: Map String [NamedScratchpad] -> Map String [NamedScratchpad]+    fillOut exs = foldl' (\nspMap n -> Map.map (replaceWith n) nspMap) exs nsps+    replaceWith :: NamedScratchpad -> [NamedScratchpad] -> [NamedScratchpad]+    replaceWith n = map (\x -> if name x == name n then n else x)  -- | Manage hook that makes the window non-floating nonFloating :: ManageHook@@ -154,6 +213,11 @@ customFloating :: W.RationalRect -> ManageHook customFloating = doRectFloat +-- | @isNSP win nsps@ checks whether the window @win@ is any scratchpad+-- in @nsps@.+isNSP :: Window -> NamedScratchpads -> X Bool+isNSP w = fmap or . traverse ((`runQuery` w) . query)+ -- | Named scratchpads configuration type NamedScratchpads = [NamedScratchpad] @@ -221,15 +285,58 @@ -- >               -- enable hiding for all of @myScratchpads@ -- >   } nsHideOnFocusLoss :: NamedScratchpads -> X ()-nsHideOnFocusLoss scratches = withWindowSet $ \winSet -> do+nsHideOnFocusLoss scratches =+    nsHideOnCondition $ \ lastFocus _curFoc _ws hideScratch ->+        whenX (isNSP lastFocus scratches) $+            hideScratch lastFocus++-- | A @logHook@ to have only one active scratchpad on a workspace. This can+-- be useful when working with multiple floating scratchpads which would+-- otherwise be stacked. Note that this also requires you to use the+-- 'XMonad.Hooks.RefocusLast.refocusLastLogHook'.+--+-- ==== __Example__+--+-- > import XMonad.Hooks.RefocusLast (refocusLastLogHook)+-- > import XMonad.Util.NamedScratchpad+-- >+-- > main = xmonad $ def+-- >   { logHook = refocusLastLogHook+-- >            >> nsHideOnNewScratchpad myScratchpads+-- >               -- enable hiding for all of @myScratchpads@+-- >   }+nsSingleScratchpadPerWorkspace :: NamedScratchpads -> X ()+nsSingleScratchpadPerWorkspace scratches =+    nsHideOnCondition $ \ _lastFocus curFocus winSet hideScratch -> do+        allScratchesButCurrent <-+            filterM (liftA2 (<||>) (pure . (/= curFocus)) (`isNSP` scratches))+                    (W.index winSet)+        whenX (isNSP curFocus scratches) $+            for_ allScratchesButCurrent hideScratch++-- | Hide scratchpads according to some condition. See 'nsHideOnFocusLoss' and+-- 'nsSingleScratchpadPerWorkspace' for usage examples.+nsHideOnCondition+    :: (  Window           -- Last focus.+       -> Window           -- Current focus.+       -> WindowSet        -- Current windowset.+       -> (Window -> X ()) -- A function to hide the named scratchpad.+       -> X ())+    -> X ()+nsHideOnCondition cond = withWindowSet $ \winSet -> do     let cur = W.currentTag winSet-    withRecentsIn cur () $ \lastFocus _ ->-        when (lastFocus `elem` W.index winSet && cur /= scratchpadWorkspaceTag) $-            whenX (isNS lastFocus) $-                shiftToNSP (W.workspaces winSet) ($ lastFocus)-  where-    isNS :: Window -> X Bool-    isNS w = or <$> traverse ((`runQuery` w) . query) scratches+    withRecentsIn cur () $ \lastFocus curFocus -> do+        let hideScratch :: Window -> X ()+            hideScratch win = shiftToNSP (W.workspaces winSet) ($ win)+            isWorthy =+                -- Check for the window being on the current workspace; if there+                -- is no history (i.e., curFocus ≡ lastFocus), don't do anything+                -- because the potential scratchpad is definitely focused.+                lastFocus `elem` W.index winSet && lastFocus /= curFocus+                -- Don't do anything on the NSP workspace, lest the world explodes.+                && cur /= scratchpadWorkspaceTag+        when isWorthy $+            cond lastFocus curFocus winSet hideScratch  -- | Execute some action on a named scratchpad. --@@ -241,19 +348,23 @@                           -> String                           -> X () someNamedScratchpadAction f runApp _ns scratchpadName = do-    NSPState scratchpadConfig <- fillNSPState _ns  -- See Note [Filling NSPState]-    case scratchpadConfig !? scratchpadName of+    NSPState{ nspScratchpads } <- fillNSPState _ns  -- See Note [Filling NSPState]+    case nspScratchpads !? scratchpadName of         Just conf -> withWindowSet $ \winSet -> do-            let focusedWspWindows = maybe [] W.integrate (W.stack . W.workspace . W.current $ winSet)+            let focusedWspWindows = W.index winSet                 allWindows        = W.allWindows winSet             matchingOnCurrent <- filterM (runQuery (query conf)) focusedWspWindows             matchingOnAll     <- filterM (runQuery (query conf)) allWindows              case NE.nonEmpty matchingOnCurrent of                 -- no matching window on the current workspace -> scratchpad not running or in background-                Nothing -> case NE.nonEmpty matchingOnAll of-                    Nothing   -> runApp conf-                    Just wins -> f (windows . W.shiftWin (W.currentTag winSet)) wins+                Nothing -> do+                    -- summon the scratchpad+                    case NE.nonEmpty matchingOnAll of+                        Nothing   -> runApp conf+                        Just wins -> f (windows . W.shiftWin (W.currentTag winSet)) wins+                    -- check for exclusive scratchpads to hide+                    hideUnwanted (name conf)                  -- matching window running on current workspace -> window should be shifted to scratchpad workspace                 Just wins -> shiftToNSP (W.workspaces winSet) (`f` wins)@@ -284,7 +395,7 @@ namedScratchpadManageHook :: NamedScratchpads -- ^ Named scratchpads configuration                           -> ManageHook namedScratchpadManageHook nsps = do-    ns <- Map.elems . coerce <$> liftX (fillNSPState nsps)+    ns <- Map.elems . nspScratchpads <$> liftX (fillNSPState nsps)     composeAll $ fmap (\c -> query c --> hook c) ns  -- | Shift some windows to the scratchpad workspace according to the@@ -339,11 +450,12 @@  -- | Make a window a dynamic scratchpad addDynamicNSP :: String -> Window -> X ()-addDynamicNSP s w = XS.modify @NSPState . coerce $ Map.insert s (mkDynamicNSP s w)+addDynamicNSP s w = XS.modify $ \(NSPState exs ws) ->+  NSPState exs (Map.insert s (mkDynamicNSP s w) ws)  -- | Make a window stop being a dynamic scratchpad removeDynamicNSP :: String -> X ()-removeDynamicNSP s = XS.modify @NSPState . coerce $ Map.delete @_ @NamedScratchpad s+removeDynamicNSP s = XS.modify $ \(NSPState exs ws) -> NSPState exs (Map.delete s ws)  -- | Toggle the visibility of a dynamic scratchpad. dynamicNSPAction :: String -> X ()@@ -353,12 +465,139 @@ -- a window from being one if it already is. toggleDynamicNSP :: String -> Window -> X () toggleDynamicNSP s w = do-    NSPState nsps <- XS.get-    case nsps !? s of+    NSPState{ nspScratchpads } <- XS.get+    case nspScratchpads !? s of         Nothing  -> addDynamicNSP s w         Just nsp -> ifM (runQuery (query nsp) w)                         (removeDynamicNSP s)                         (addDynamicNSP s w)++-----------------------------------------------------------------------+-- Exclusive scratchpads++-- $exclusive-scratchpads+--+-- Exclusive scratchpads allow you to hide certain scratchpads in+-- relation to others.  There can be multiple groups of pairwise+-- exclusive scratchpads; whenever one such scratchpad gets called, it+-- will hide all other scratchpads on the focused workspace that are in+-- this group.+--+-- For example, having defined "Calc", "Mail", and "Term" scratchpads,+-- you can use 'addExclusives' to make some of them dislike each other:+--+-- > myExclusives = addExclusives+-- >   [ ["Calc", "Mail"]+-- >   , ["Mail", "Term"]+-- >   ]+--+-- You now have to add @myExclusives@ to you startupHook:+--+-- > main :: IO+-- > main = xmonad . … . $ def+-- >   { …+-- >   , startupHook = myStartupHook >> myExclusives+-- >   }+--+-- This will hide the "Mail" scratchpad whenever the "Calc" scratchpad+-- is brought up, and vice-versa.  Likewise, "Mail" and "Term" behave in+-- this way, but "Calc" and "Term" may peacefully coexist.+--+-- If you move a scratchpad it still gets hidden when you fetch a+-- scratchpad of the same family.  To change that behaviour—and make+-- windows not exclusive anymore when they get resized or moved—add+-- these mouse bindings (see+-- "XMonad.Doc.Extending#Editing_mouse_bindings"):+--+-- >     , ((mod4Mask, button1), floatMoveNoexclusive)+-- >     , ((mod4Mask, button3), resizeNoexclusive)+--+-- To reset a moved scratchpad to the original position that you set+-- with its hook, focus is and then call 'resetFocusedNSP'.  For+-- example, if you want to extend @M-\<Return\>@ to reset the placement+-- when a scratchpad is in focus but keep the default behaviour for+-- tiled windows, set these key bindings:+--+-- > , ((modMask, xK_Return), windows W.swapMaster >> resetFocusedNSP)++-- | Make some scratchpads exclusive.+addExclusives :: [[String]] -> X ()+addExclusives exs = do+    NSPState _ ws <- XS.get+    -- Re-initialise `ws' to nothing, so we can react to changes in case+    -- of a restart.  See 'fillNSPState' for more details on filling.+    XS.put (NSPState (foldl' (go []) mempty exs) mempty)+    unless (null ws) $+        void (fillNSPState (Map.elems ws))+  where+    -- Ignoring that this is specialised to NSPs, it works something like+    -- >>> foldl' (go []) mempty [[1, 2], [3, 4], [1, 3]]+    -- fromList [(1, [3, 2]), (2, [1]), (3, [1, 4]), (4, [3])]+    go _  m []       = m+    go ms m (n : ns) = go (n : ms) (Map.insertWith (<>) n (mkNSP (ms <> ns)) m) ns+    mkNSP = map (\n -> NS n mempty (pure False) mempty)++-- | @setNoexclusive w@ makes the window @w@ lose its exclusivity+-- features.+setNoexclusive :: Window -> X ()+setNoexclusive w = do+    NSPState _ ws <- XS.get+    whenX (isNSP w (Map.elems ws)) $+        addTag "_NSP_NOEXCLUSIVE" w++-- | If the focused window is a scratchpad, the scratchpad gets reset to+-- the original placement specified with the hook and becomes exclusive+-- again.+resetFocusedNSP :: X ()+resetFocusedNSP = do+    NSPState _ (Map.elems -> ws) <- XS.get+    withFocused $ \w -> do+        mbWin <- findM ((`runQuery` w) . query) ws+        whenJust mbWin $ \win -> do+            (windows . appEndo <=< runQuery (hook win)) w+            hideUnwanted (name win)+            delTag "_NSP_NOEXCLUSIVE" w++-- | @hideUnwanted nspWindow@ hides all windows that @nspWindow@ does+-- not like; i.e., windows that are in some kind of exclusivity contract+-- with it.+--+-- A consistency assumption for this is that @nspWindow@ must be the+-- currently focused window.  For this to take effect, @nspWindow@ must+-- not have set the @_NSP_NOEXCLUSIVE@ property, neither must any+-- exclusive window we'd like to hide.+hideUnwanted :: String -> X ()+hideUnwanted nspWindow = withWindowSet $ \winSet -> do+    NSPState{ nspExclusives } <- XS.get+    whenJust (nspExclusives !? nspWindow) $ \unwanted ->+        withFocused $ \w -> whenX (runQuery notIgnored w) $ do+            for_ (W.index winSet) $ \win ->+                whenX (runQuery (isUnwanted unwanted) win) $+                    shiftToNSP (W.workspaces winSet) ($ win)+  where+    notIgnored :: Query Bool+    notIgnored = notElem "_NSP_NOEXCLUSIVE" . words <$> stringProperty "_XMONAD_TAGS"++    isUnwanted :: [NamedScratchpad] -> Query Bool+    isUnwanted = (notIgnored <&&>) . foldr (\nsp qs -> qs <||> query nsp) (pure False)++-- | Float and drag the window; make it lose its exclusivity status in+-- the process.+floatMoveNoexclusive :: Window -- ^ Window which should be moved+                     -> X ()+floatMoveNoexclusive = mouseHelper mouseMoveWindow++-- | Resize window and make it lose its exclusivity status in the+-- process.+resizeNoexclusive :: Window -- ^ Window which should be resized+                  -> X ()+resizeNoexclusive = mouseHelper mouseResizeWindow++mouseHelper :: (Window -> X a) -> Window -> X ()+mouseHelper f w = setNoexclusive w+               >> focus w+               >> f w+               >> windows W.shiftMaster  ------------------------------------------------------------------------ -- Deprecations
XMonad/Util/Parser.hs view
@@ -5,6 +5,7 @@ {-# LANGUAGE ScopedTypeVariables        #-} {-# LANGUAGE TypeApplications           #-} {-# LANGUAGE TypeFamilies               #-}+{-# LANGUAGE TypeOperators              #-} -------------------------------------------------------------------- -- | -- Module      : XMonad.Util.Parser@@ -36,6 +37,7 @@   runParser,    -- * Primitive Parsers+  pfail,   eof,   num,   char,@@ -43,10 +45,17 @@   skipSpaces,   get,   look,+  gather,    -- * Combining Parsers   satisfy,   choice,+  count,+  between,+  option,+  optionally,+  skipMany,+  skipMany1,   many1,   sepBy,   sepBy1,@@ -54,7 +63,11 @@   endBy1,   munch,   munch1,-  pfail+  chainr,+  chainr1,+  chainl,+  chainl1,+  manyTill, ) where  import XMonad.Prelude@@ -85,7 +98,7 @@ > pLongerSequence = ReadP.char '<' *> ReadP.string "f" <* ReadP.char '>' > pCombination = pLangle ReadP.+++ pLongerSequence -Parsing the string @"<f>"@ will return+Parsing the string @"\<f\>"@ will return  >>> ReadP.readP_to_S pCombination "<f>" [("<","f>"),("f","")]@@ -123,18 +136,22 @@   -- produces any result at all, then right parser is not used.   (<>) :: Parser a -> Parser a -> Parser a   (<>) = coerce ((<++) @a)+  {-# INLINE (<>) #-}  instance Monoid (Parser a) where   -- | A parser that always fails.   mempty :: Parser a   mempty = Parser empty+  {-# INLINE mempty #-}  instance Alternative Parser where   empty :: Parser a   empty = mempty+  {-# INLINE empty #-}    (<|>) :: Parser a -> Parser a -> Parser a   (<|>) = (<>)+  {-# INLINE (<|>) #-}  -- | When @-XOverloadedStrings@ is on, treat a string @s@ as the parser -- @'string' s@, when appropriate.  This allows one to write things like@@ -142,89 +159,199 @@ instance a ~ String => IsString (Parser a) where   fromString :: String -> Parser a   fromString = string+  {-# INLINE fromString #-}  -- | Run a parser on a given string. runParser :: Parser a -> String -> Maybe a runParser (Parser p) = fmap fst . listToMaybe . ReadP.readP_to_S p+{-# INLINE runParser #-}  -- | Always fails pfail :: Parser a pfail = empty+{-# INLINE pfail #-}  -- | Consume and return the next character.  Fails if there is no input -- left. get :: Parser Char get = coerce ReadP.get+{-# INLINE get #-}  -- | Look-ahead: return the part of the input that is left, without -- consuming it. look :: Parser String look = coerce ReadP.look+{-# INLINE look #-} +-- | Transform a parser into one that does the same, but in addition+-- returns the exact characters read.+--+-- >>> runParser (         string "* " $> True) "* hi"+-- Just True+-- >>> runParser (gather $ string "* " $> True) "* hi"+-- Just ("* ",True)+gather :: forall a. Parser a -> Parser (String, a)+gather = coerce (ReadP.gather @a)+{-# INLINE gather #-}+ -- | Succeeds if and only if we are at the end of input. eof :: Parser () eof = coerce ReadP.eof+{-# INLINE eof #-} --- | Parse an integral number number.+-- | Parse an integral number. num :: (Read a, Integral a) => Parser a num = read <$> munch1 isDigit-{-# SPECIALISE num :: Parser Word    #-}-{-# SPECIALISE num :: Parser Int     #-}-{-# SPECIALISE num :: Parser Integer #-}+{-# INLINE num #-}  -- | Parse and return the specified character. char :: Char -> Parser Char char = coerce ReadP.char+{-# INLINE char #-}  -- | Parse and return the specified string. string :: String -> Parser String string = coerce ReadP.string+{-# INLINE string #-}  -- | Skip all whitespace. skipSpaces :: Parser () skipSpaces = coerce ReadP.skipSpaces+{-# INLINE skipSpaces #-}  -- | Consume and return the next character if it satisfies the specified -- predicate. satisfy :: (Char -> Bool) -> Parser Char satisfy = coerce ReadP.satisfy+{-# INLINE satisfy #-}  -- | Combine all parsers in the given list in a left-biased way. choice :: [Parser a] -> Parser a choice = foldl' (<>) mempty+{-# INLINE choice #-} +-- | @count n p@ parses @n@ occurrences of @p@ in sequence and returns a+-- list of results.+count :: Int -> Parser a -> Parser [a]+count = replicateM+{-# INLINE count #-}++-- | @between open close p@ parses @open@, followed by @p@ and finally+-- @close@.  Only the value of @p@ is returned.+between :: Parser open -> Parser close -> Parser a -> Parser a+between open close p = open *> p <* close+{-# INLINE between #-}++-- | @option def p@ will try to parse @p@ and, if it fails, simply+-- return @def@ without consuming any input.+option :: a -> Parser a -> Parser a+option def p = p <|> pure def+{-# INLINE option #-}++-- | @optionally p@ optionally parses @p@ and always returns @()@.+optionally :: Parser a -> Parser ()+optionally p = void p <|> pure ()+{-# INLINE optionally #-}++-- | Like 'many', but discard the result.+skipMany :: Parser a -> Parser ()+skipMany = void . many+{-# INLINE skipMany #-}++-- | Like 'many1', but discard the result.+skipMany1 :: Parser a -> Parser ()+skipMany1 p = p *> skipMany p+{-# INLINE skipMany1 #-}+ -- | Parse the first zero or more characters satisfying the predicate. -- Always succeeds; returns an empty string if the predicate returns -- @False@ on the first character of input. munch :: (Char -> Bool) -> Parser String munch = coerce ReadP.munch+{-# INLINE munch #-}  -- | Parse the first one or more characters satisfying the predicate. -- Fails if none, else succeeds exactly once having consumed all the -- characters. munch1 :: (Char -> Bool) -> Parser String munch1 = coerce ReadP.munch1+{-# INLINE munch1 #-}  -- | @endBy p sep@ parses zero or more occurrences of @p@, separated and -- ended by @sep@. endBy :: Parser a -> Parser sep -> Parser [a] endBy p sep = many (p <* sep)+{-# INLINE endBy #-}  -- | @endBy p sep@ parses one or more occurrences of @p@, separated and -- ended by @sep@. endBy1 :: Parser a -> Parser sep -> Parser [a] endBy1 p sep = many1 (p <* sep)+{-# INLINE endBy1 #-}  -- | Parse one or more occurrences of the given parser. many1 :: Parser a -> Parser [a]-many1 p = liftA2 (:) p (many p)+many1 = some+{-# INLINE many1 #-}  -- | @sepBy p sep@ parses zero or more occurrences of @p@, separated by -- @sep@.  Returns a list of values returned by @p@. sepBy :: Parser a -> Parser sep -> Parser [a] sepBy p sep = sepBy1 p sep <> pure []+{-# INLINE sepBy #-}  -- | @sepBy1 p sep@ parses one or more occurrences of @p@, separated by -- @sep@.  Returns a list of values returned by @p@. sepBy1 :: Parser a -> Parser sep -> Parser [a] sepBy1 p sep = liftA2 (:) p (many (sep *> p))+{-# INLINE sepBy1 #-}++-- | @chainr p op x@ parses zero or more occurrences of @p@, separated+-- by @op@.  Returns a value produced by a /right/ associative+-- application of all functions returned by @op@.  If there are no+-- occurrences of @p@, @x@ is returned.+chainr :: Parser a -> Parser (a -> a -> a) -> a -> Parser a+chainr p op x = option x (chainr1 p op)+{-# INLINE chainr #-}++-- | Like 'chainr', but parses one or more occurrences of @p@.+chainr1 :: forall a. Parser a -> Parser (a -> a -> a) -> Parser a+chainr1 p op = scan+ where+  scan :: Parser a+  scan = p >>= rest++  rest :: a -> Parser a+  rest x = option x $ do f <- op+                         f x <$> scan+{-# INLINE chainr1 #-}++-- | @chainl p op x@ parses zero or more occurrences of @p@, separated+-- by @op@.  Returns a value produced by a /left/ associative+-- application of all functions returned by @op@.  If there are no+-- occurrences of @p@, @x@ is returned.+chainl :: Parser a -> Parser (a -> a -> a) -> a -> Parser a+chainl p op x = option x (chainl1 p op)+{-# INLINE chainl #-}++-- | Like 'chainl', but parses one or more occurrences of @p@.+chainl1 :: forall a. Parser a -> Parser (a -> a -> a) -> Parser a+chainl1 p op = scan+ where+  scan :: Parser a+  scan = p >>= rest++  rest :: a -> Parser a+  rest x = option x $ do f <- op+                         y <- p+                         rest (f x y)+{-# INLINE chainl1 #-}++-- | @manyTill p end@ parses zero or more occurrences of @p@, until+-- @end@ succeeds.  Returns a list of values returned by @p@.+manyTill :: forall a end. Parser a -> Parser end -> Parser [a]+manyTill p end = scan+ where+  scan :: Parser [a]+  scan = end $> [] <|> liftA2 (:) p scan+{-# INLINE manyTill #-}
XMonad/Util/Paste.hs view
@@ -35,7 +35,7 @@  {- $usage -Import this module into your xmonad.hs as usual:+Import this module into your @xmonad.hs@ as usual:  > import XMonad.Util.Paste 
XMonad/Util/PureX.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE GeneralizedNewtypeDeriving, FlexibleContexts #-}+{-# LANGUAGE DerivingVia, GeneralizedNewtypeDeriving, FlexibleContexts #-}  ----------------------------------------------------------------------------- -- |@@ -53,7 +53,7 @@  -- xmonad import XMonad-import XMonad.Prelude (Any (..), liftA2, WindowScreen)+import XMonad.Prelude import qualified XMonad.StackSet as W import qualified XMonad.Actions.FocusNth @@ -110,12 +110,7 @@ -- | The @PureX@ newtype over @ReaderT XConf (State XState) a@. newtype PureX a = PureX (ReaderT XConf (State XState) a)   deriving (Functor, Applicative, Monad, MonadReader XConf, MonadState XState)--instance Semigroup a => Semigroup (PureX a) where-  (<>) = liftA2 (<>)--instance Monoid a => Monoid (PureX a) where-  mempty  = return mempty+  deriving (Semigroup, Monoid) via Ap PureX a  -- | The @XLike@ typeclass over monads reading @XConf@ values and tracking --   @XState@ state.
XMonad/Util/RemoteWindows.hs view
@@ -44,7 +44,7 @@ import System.Posix.Env  -- $usage--- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+-- You can use this module with the following in your @xmonad.hs@: -- -- > import XMonad -- > import XMonad.Util.RemoteWindows
XMonad/Util/Run.hs view
@@ -49,6 +49,7 @@   spawnExternalProcess,   proc,   getInput,+  toInput,    -- ** Programs   inEditor,@@ -59,9 +60,12 @@   -- ** General Combinators   (>->),   (>-$),+  (>&&>),+  (>||>),   inWorkingDir,-  execute,   eval,+  execute,+  executeNoQuote,   setXClass,   asString, @@ -75,6 +79,9 @@   require,   progn,   quote,+  findFile,+  list,+  saveExcursion,    -- * Re-exports   hPutStr,@@ -107,9 +114,7 @@   - For an example usage of 'runInTerm' see "XMonad.Prompt.Ssh".    - For an example usage of 'runProcessWithInput' see-    "XMonad.Prompt.DirectoryPrompt", "XMonad.Util.Dmenu",-    "XMonad.Prompt.ShellPrompt", "XMonad.Actions.WmiiActions", or-    "XMonad.Prompt.WorkspaceDir".+    "XMonad.Util.Dmenu", or "XMonad.Prompt.Shell".    - For an example usage of 'runProcessWithInputAndWait' see     "XMonad.Util.Dzen".@@ -300,6 +305,10 @@  which would be quite bothersome to type indeed! +A blog post going into some more detail and also explaining how to+integrate this new language with the "XMonad.Util.NamedScratchpad"+module is available+<https://tony-zorman.com/posts/2022-05-25-calling-emacs-from-xmonad.html here>. -}  -----------------------------------------------------------------------@@ -354,10 +363,32 @@ (>-$) xi xs = xi >-> fmap mkDList xs infixr 3 >-$ +-- | @a >&&> b@ glues the different inputs @a@ and @b@ by means of @&&@.+-- For example,+--+-- @+-- pure "do something" >&&> pure "do another thing"+-- @+--+-- would result in @do something && do another thing@ being executed by a+-- shell.+(>&&>) :: X Input -> X Input -> X Input+a >&&> b = a <> toInput " && " <> b+infixr 2 >&&>++-- | Like '(>&&>)', but with @||@.+(>||>) :: X Input -> X Input -> X Input+a >||> b = a <> toInput " || " <> b+infixr 2 >||>+ -- | Spawn a completed input. proc :: X Input -> X () proc xi = spawn =<< getInput xi +-- | Create an effectful 'Input' from a 'String'.+toInput :: String -> X Input+toInput = pure . mkDList+ -- | Get the completed input string. getInput :: X Input -> X String getInput xi = xi <&> ($ "")@@ -373,13 +404,20 @@ -- | Execute the argument.  Current /thing/ must support a @-e@ option. -- For programs such as Emacs, 'eval' may be the safer option; while -- @emacsclient@ supports @-e@, the @emacs@ executable itself does not.+--+-- Note that this function always wraps its argument in single quotes;+-- see 'executeNoQuote' for an alternative. execute :: String -> X Input-execute this = pure ((" -e " <> this) <>)+execute this = pure ((" -e " <> tryQuote this) <>) +-- | Like 'execute', but doesn't wrap its argument in single quotes.+executeNoQuote :: String -> X Input+executeNoQuote this = pure ((" -e " <> this) <>)+ -- | Eval(uate) the argument.  Current /thing/ must support a @--eval@ -- option. eval :: String -> X Input-eval this = pure ((" --eval " <> this) <>)+eval this = pure ((" --eval " <> tryQuote this) <>)  -- | Use 'emacs'. inEmacs :: X Input@@ -413,6 +451,9 @@ termInDir :: X Input termInDir = inTerm >-> inWorkingDir +-----------------------------------------------------------------------+-- Emacs+ -- | Transform the given input into an elisp function; i.e., surround it -- with parentheses. --@@ -428,14 +469,14 @@ asString :: String -> String asString s = " \"" <> s <> "\" " --- | Wrap the given commands in a @progn@ and also escape it by wrapping--- it inside single quotes.  The given commands need not be wrapped in--- parentheses, this will be done by the function.  For example:+-- | Wrap the given commands in a @progn@.  The given commands need not+-- be wrapped in parentheses (but can); this will be done by the+-- function.  For example: -- -- >>> progn [require "this-lib", "function-from-this-lib arg", "(other-function arg2)"]--- " '( progn (require (quote this-lib)) (function-from-this-lib arg) (other-function arg2) )' "+-- "(progn (require (quote this-lib)) (function-from-this-lib arg) (other-function arg2))" progn :: [String] -> String-progn cmds = elispFun $ "progn " <> unwords (map inParens cmds)+progn = inParens . ("progn " <>) . unwords . map inParens  -- | Require a package. --@@ -451,6 +492,27 @@ quote :: String -> String quote = inParens . ("quote " <>) +-- | Call @find-file@.+--+-- >>> findFile "/path/to/file"+-- "(find-file \"/path/to/file\" )"+findFile :: String -> String+findFile = inParens . ("find-file" <>) . asString++-- | Make a list of the given inputs.+--+-- >>> list ["foo", "bar", "baz", "qux"]+-- "(list foo bar baz qux)"+list :: [String] -> String+list = inParens . ("list " <>) . unwords++-- | Like 'progn', but with @save-excursion@.+--+-- >>> saveExcursion [require "this-lib", "function-from-this-lib arg", "(other-function arg2)"]+-- "(save-excursion (require (quote this-lib)) (function-from-this-lib arg) (other-function arg2))"+saveExcursion :: [String] -> String+saveExcursion = inParens . ("save-excursion " <>) . unwords . map inParens+ ----------------------------------------------------------------------- -- Batch mode @@ -493,3 +555,8 @@ inParens s = case s of   '(' : _ -> s   _       -> "(" <> s <> ")"++tryQuote :: String -> String+tryQuote s = case dropWhile (== ' ') s of+  '\'' : _ -> s+  _        -> "'" <> s <> "'"
XMonad/Util/Scratchpad.hs view
@@ -13,7 +13,7 @@ -- ----------------------------------------------------------------------------- -module XMonad.Util.Scratchpad (+module XMonad.Util.Scratchpad {-# DEPRECATED "Use XMonad.Util.NamedScratchpad instead" #-} (   -- * Usage   -- $usage   scratchpadSpawnAction
XMonad/Util/SpawnNamedPipe.hs view
@@ -9,7 +9,7 @@ -- Stability   :  unstable -- Portability :  not portable ----- A module for spawning a pipe whose "Handle" lives in the Xmonad state.+-- A module for spawning a pipe whose 'Handle' lives in the Xmonad state. -- ----------------------------------------------------------------------------- @@ -55,10 +55,10 @@ instance ExtensionClass NamedPipes where     initialValue = NamedPipes Map.empty --- | When 'spawnNamedPipe' is executed with a command "String" and a name--- "String" respectively.  The command string is spawned with 'spawnPipe' (as--- long as the name chosen hasn't been used already) and the "Handle" returned--- is saved in Xmonad's state associated with the name "String".+-- | When 'spawnNamedPipe' is executed with a command 'String' and a name+-- 'String' respectively.  The command string is spawned with 'spawnPipe' (as+-- long as the name chosen hasn't been used already) and the 'Handle' returned+-- is saved in Xmonad's state associated with the name 'String'. spawnNamedPipe :: String -> String -> X () spawnNamedPipe cmd name = do   b <- XS.gets (Map.member name . pipeMap)@@ -66,7 +66,7 @@     h <- spawnPipe cmd     XS.modify (NamedPipes . Map.insert name h . pipeMap) --- | Attempts to retrieve a "Handle" to a pipe previously stored in Xmonad's+-- | Attempts to retrieve a 'Handle' to a pipe previously stored in Xmonad's -- state associated with the given string via a call to 'spawnNamedPipe'. If the -- given string doesn't exist in the map stored in Xmonad's state Nothing is -- returned.
XMonad/Util/SpawnOnce.hs view
@@ -11,7 +11,7 @@ -- -- A module for spawning a command once, and only once.  Useful to start -- status bars and make session settings inside startupHook. See also--- 'XMonad.Util.SessionStart' for a different and more flexible way to+-- "XMonad.Util.SessionStart" for a different and more flexible way to -- run commands only on first startup. -- -----------------------------------------------------------------------------@@ -53,7 +53,7 @@  -- $spawnon -- These functions combine 'spawnOnce' with their relatives in--- 'XMonad.Actions.SpawnOn'. You must add 'manageSpawn' to your+-- "XMonad.Actions.SpawnOn". You must add 'manageSpawn' to your -- @manageHook@ for them to work, as with @SpawnOn@.  -- | Like 'spawnOnce' but launches the application on the given workspace.
XMonad/Util/Stack.hs view
@@ -27,6 +27,7 @@                          , toIndex                          , fromTags                          , toTags+                         , zipperFocusedAtFirstOf                             -- * 'Zipper' manipulation functions                            -- ** Insertion, movement@@ -123,6 +124,18 @@ toTags (Just s) = map Left (reverse . W.up $ s) ++ [Right . W.focus $ s]                   ++ map Left (W.down s) +-- | @differentiate zs xs@ takes the first @z@ from @z2 that also belongs to+-- @xs@ and turns @xs@ into a stack with @z@ being the current element. Acts+-- as 'XMonad.StackSet.differentiate' if @zs@ and @xs@ don't intersect.+zipperFocusedAtFirstOf :: Eq q => [q] -> [q] -> Zipper q+zipperFocusedAtFirstOf []       xs = W.differentiate xs+zipperFocusedAtFirstOf (z : zs) xs+  | z `elem` xs = Just $+        W.Stack { W.focus = z+                , W.up    = reverse $ takeWhile (/= z) xs+                , W.down  = drop 1  $ dropWhile (/= z) xs+                }+  | otherwise = zipperFocusedAtFirstOf zs xs  -- * Zipper functions @@ -162,20 +175,20 @@ focusUpZ Nothing = Nothing focusUpZ (Just s) | u:up <- W.up s = Just $ W.Stack u up (W.focus s:W.down s) focusUpZ (Just s) | null $ W.down s = Just s-focusUpZ (Just (W.Stack f _ down)) = Just $ W.Stack (last down) (tail (reverse down) ++ [f]) []+focusUpZ (Just (W.Stack f _ down)) = Just $ W.Stack (last down) (drop 1 (reverse down) ++ [f]) []  -- | Move the focus to the next element focusDownZ :: Zipper a -> Zipper a focusDownZ Nothing = Nothing focusDownZ (Just s) | d:down <- W.down s = Just $ W.Stack d (W.focus s:W.up s) down focusDownZ (Just s) | null $ W.up s = Just s-focusDownZ (Just (W.Stack f up _)) = Just $ W.Stack (last up) [] (tail (reverse up) ++ [f])+focusDownZ (Just (W.Stack f up _)) = Just $ W.Stack (last up) [] (drop 1 (reverse up) ++ [f])  -- | Move the focus to the first element focusMasterZ :: Zipper a -> Zipper a focusMasterZ Nothing = Nothing focusMasterZ (Just (W.Stack f up down)) | not $ null up-    = Just $ W.Stack (last up) [] (tail (reverse up) ++ [f] ++ down)+    = Just $ W.Stack (last up) [] (drop 1 (reverse up) ++ [f] ++ down) focusMasterZ (Just s) = Just s  -- | Refocus a @Stack a@ on an element satisfying the predicate, or fail to
XMonad/Util/Timer.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE MultiWayIf #-} ----------------------------------------------------------------------------- -- | -- Module      :  XMonad.Util.Timer@@ -20,13 +21,14 @@     , TimerId     ) where -import XMonad import Control.Concurrent import Data.Unique+import XMonad+import XMonad.Prelude (listToMaybe)  -- $usage -- This module can be used to setup a timer to handle deferred events.--- See 'XMonad.Layout.ShowWName' for an usage example.+-- See "XMonad.Layout.ShowWName" for an usage example.  type TimerId = Int @@ -53,7 +55,6 @@ handleTimer ti ClientMessageEvent{ev_message_type = mt, ev_data = dt} action = do   d <- asks display   a <- io $ internAtom d "XMONAD_TIMER" False-  if mt == a && dt /= [] && fromIntegral (head dt) == ti-     then action-     else return Nothing+  if | mt == a, Just dth <- listToMaybe dt, fromIntegral dth == ti -> action+     | otherwise -> return Nothing handleTimer _ _ _ = return Nothing
XMonad/Util/Ungrab.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} ----------------------------------------------------------------------------- -- | -- Module      :  XMonad.Util.Ungrab@@ -13,12 +14,15 @@ -- ----------------------------------------------------------------------------- -module XMonad.Util.Ungrab+module XMonad.Util.Ungrab {-# DEPRECATED "Use XMonad.Operations.unGrab instead" #-}     ( -- * Usage:       -- $usage       unGrab     ) where +#if MIN_VERSION_xmonad(0, 17, 9)+import XMonad.Operations (unGrab)+#else import Graphics.X11.Xlib (sync) import Graphics.X11.Xlib.Extras (currentTime) import Graphics.X11.Xlib.Misc (ungrabKeyboard, ungrabPointer)@@ -43,3 +47,4 @@ -- | Release xmonad's keyboard grab, so other grabbers can do their thing. unGrab :: X () unGrab = withDisplay $ \d -> io (ungrabKeyboard d currentTime >> ungrabPointer d currentTime >> sync d False)+#endif
XMonad/Util/WindowProperties.hs view
@@ -46,7 +46,7 @@               | Or  Property Property               | Not Property               | Const Bool-              | Tagged String -- ^ Tagged via 'XMonad.Actions.TagWindows'+              | Tagged String -- ^ Tagged via "XMonad.Actions.TagWindows"               deriving (Read, Show) infixr 9 `And` infixr 8 `Or`
XMonad/Util/WindowState.hs view
@@ -33,22 +33,22 @@ -- -- This module have advantage over "XMonad.Actions.TagWindows" in that it -- hides from you implementation details and provides simple type-safe--- interface.  Main datatype is "StateQuery", which is simple wrapper around--- "Query", which is instance of MonadState, with 'put' and 'get' are--- functions to acess data, stored in "Window".+-- interface.  Main datatype is 'StateQuery', which is simple wrapper around+-- 'Query', which is instance of MonadState, with 'put' and 'get' are+-- functions to acess data, stored in 'Window'. -- -- To save some data in window you probably want to do following: -- > (runStateQuery  (put $ Just value)  win) :: X () -- To retrive it, you can use -- > (runStateQuery get win) :: X (Maybe YourValueType)--- "Query" can be promoted to "StateQuery" simply by constructor,+-- 'Query' can be promoted to 'StateQuery' simply by constructor, -- and reverse is 'getQuery'. -- -- For example, I use it to have all X applications @russian@ or @dvorak@ -- layout, but emacs have only @us@, to not screw keybindings. Use your -- imagination! --- | Wrapper around "Query" with phanom type @s@, representing state, saved in+-- | Wrapper around 'Query' with phantom type @s@, representing state, saved in -- window. newtype StateQuery s a = StateQuery {       getQuery :: Query a@@ -57,11 +57,11 @@ packIntoQuery :: (Window -> X a) -> Query a packIntoQuery = Query . ReaderT --- | Apply "StateQuery" to "Window".+-- | Apply 'StateQuery' to 'Window'. runStateQuery :: StateQuery s a -> Window ->  X a runStateQuery = runQuery . getQuery --- | Lifted to "Query" version of 'catchX'+-- | Lifted to 'Query' version of 'catchX' catchQuery :: Query a -> Query (Maybe a) catchQuery q = packIntoQuery $ \win -> userCode $ runQuery q win 
tests/OrgMode.hs view
@@ -150,6 +150,7 @@     hourGen :: Gen String     hourGen = oneof       [ pure " " <<>> (pad <$> hourInt) <<>> pure ":" <<>> (pad <$> minuteInt)+      , pure " " <<>> (pad <$> hourInt) <<>>               (pad <$> minuteInt)       , pure ""       ]      where
tests/Selective.hs view
@@ -34,14 +34,14 @@ prop_select_increasing :: Selection l -> Stack Int -> Bool prop_select_increasing sel (stk :: Stack Int) =     let res = integrate $ select sel stk-     in and . zipWith (<) res $ tail res+     in and . zipWith (<) res $ drop 1 res  -- selection has the form [0..l] ++ [m..n] -- relies on the Arbitrary instance for Stack Int generating stacks like [0..k] prop_select_two_consec :: Selection l -> Stack Int -> Bool prop_select_two_consec sel (stk :: Stack Int) =     let wins = integrate $ select sel stk-     in (length . filter not . zipWith ((==) . (+1)) wins $ tail wins) <= 1+     in (length . filter not . zipWith ((==) . (+1)) wins $ drop 1 wins) <= 1  -- update preserves invariants on selections prop_update_nm :: Selection l -> Stack Int -> Bool
xmonad-contrib.cabal view
@@ -1,5 +1,5 @@ name:               xmonad-contrib-version:            0.17.1+version:            0.18.0 -- ^ also update cpp-options: -DXMONAD_CONTRIB_VERSION_*  homepage:           https://xmonad.org/@@ -38,7 +38,7 @@ build-type:         Simple bug-reports:        https://github.com/xmonad/xmonad-contrib/issues -tested-with:        GHC == 8.4.4 || == 8.6.5 || == 8.8.4 || == 8.10.7 || == 9.0.2 || == 9.2.2+tested-with:        GHC == 8.6.5 || == 8.8.4 || == 8.10.7 || == 9.0.2 || == 9.2.8 || == 9.4.8 || == 9.6.4 || == 9.8.1  source-repository head   type:     git@@ -55,8 +55,8 @@  library     build-depends: base >= 4.11 && < 5,-                   bytestring >= 0.10 && < 0.12,-                   containers >= 0.5 && < 0.7,+                   bytestring >= 0.10 && < 0.13,+                   containers >= 0.5 && < 0.8,                    directory,                    filepath,                    time >= 1.8 && < 1.13,@@ -65,21 +65,21 @@                    mtl >= 1 && < 3,                    unix,                    X11 >= 1.10 && < 1.11,-                   xmonad >= 0.16.99999 && < 0.18,+                   xmonad >= 0.16.99999 && < 0.19,                    utf8-string,                    deepseq     default-language: Haskell2010      cpp-options:   -DXMONAD_CONTRIB_VERSION_MAJOR=0-                   -DXMONAD_CONTRIB_VERSION_MINOR=17-                   -DXMONAD_CONTRIB_VERSION_PATCH=1+                   -DXMONAD_CONTRIB_VERSION_MINOR=18+                   -DXMONAD_CONTRIB_VERSION_PATCH=0     ghc-options:   -Wall -Wno-unused-do-bind      if flag(pedantic)        ghc-options: -Werror -Wwarn=deprecations -Wwarn=dodgy-imports      -- Keep this in sync with the oldest version in 'tested-with'-    if impl(ghc > 8.4.4)+    if impl(ghc > 8.6.5)        -- don't treat unused-imports warning as errors, they may be necessary        -- for compatibility with older versions of base (or other deps)        ghc-options: -Wwarn=unused-imports@@ -118,6 +118,7 @@                         XMonad.Actions.LinkWorkspaces                         XMonad.Actions.MessageFeedback                         XMonad.Actions.Minimize+                        XMonad.Actions.MostRecentlyUsed                         XMonad.Actions.MouseGestures                         XMonad.Actions.MouseResize                         XMonad.Actions.Navigation2D@@ -132,6 +133,7 @@                         XMonad.Actions.Promote                         XMonad.Actions.RandomBackground                         XMonad.Actions.RepeatAction+                        XMonad.Actions.Repeatable                         XMonad.Actions.RotSlaves                         XMonad.Actions.RotateSome                         XMonad.Actions.Search@@ -145,6 +147,7 @@                         XMonad.Actions.SwapWorkspaces                         XMonad.Actions.TagWindows                         XMonad.Actions.TiledWindowDragging+                        XMonad.Actions.ToggleFullFloat                         XMonad.Actions.TopicSpace                         XMonad.Actions.TreeSelect                         XMonad.Actions.UpdateFocus@@ -190,18 +193,17 @@                         XMonad.Hooks.FadeWindows                         XMonad.Hooks.FloatNext                         XMonad.Hooks.Focus-                        XMonad.Hooks.ICCCMFocus                         XMonad.Hooks.InsertPosition                         XMonad.Hooks.ManageDebug                         XMonad.Hooks.ManageDocks                         XMonad.Hooks.ManageHelpers                         XMonad.Hooks.Minimize                         XMonad.Hooks.Modal+                        XMonad.Hooks.OnPropertyChange                         XMonad.Hooks.Place                         XMonad.Hooks.PositionStoreHooks                         XMonad.Hooks.RefocusLast                         XMonad.Hooks.Rescreen-                        XMonad.Hooks.RestoreMinimized                         XMonad.Hooks.ScreenCorners                         XMonad.Hooks.Script                         XMonad.Hooks.ServerMode@@ -226,14 +228,25 @@                         XMonad.Layout.BorderResize                         XMonad.Layout.BoringWindows                         XMonad.Layout.ButtonDecoration+                        XMonad.Layout.CenterMainFluid                         XMonad.Layout.CenteredIfSingle                         XMonad.Layout.CenteredMaster                         XMonad.Layout.Circle+                        XMonad.Layout.CircleEx                         XMonad.Layout.Column                         XMonad.Layout.Combo                         XMonad.Layout.ComboP                         XMonad.Layout.Cross                         XMonad.Layout.Decoration+                        XMonad.Layout.DecorationEx+                        XMonad.Layout.DecorationEx.Common+                        XMonad.Layout.DecorationEx.Engine+                        XMonad.Layout.DecorationEx.Geometry+                        XMonad.Layout.DecorationEx.Widgets+                        XMonad.Layout.DecorationEx.LayoutModifier+                        XMonad.Layout.DecorationEx.TextEngine+                        XMonad.Layout.DecorationEx.DwmGeometry+                        XMonad.Layout.DecorationEx.TabbedGeometry                         XMonad.Layout.DecorationAddons                         XMonad.Layout.DecorationMadness                         XMonad.Layout.Dishes@@ -244,6 +257,7 @@                         XMonad.Layout.DwmStyle                         XMonad.Layout.FixedAspectRatio                         XMonad.Layout.FixedColumn+                        XMonad.Layout.FocusTracking                         XMonad.Layout.Fullscreen                         XMonad.Layout.Gaps                         XMonad.Layout.Grid@@ -260,7 +274,6 @@                         XMonad.Layout.ImageButtonDecoration                         XMonad.Layout.IndependentScreens                         XMonad.Layout.LayoutBuilder-                        XMonad.Layout.LayoutBuilderP                         XMonad.Layout.LayoutCombinators                         XMonad.Layout.LayoutHints                         XMonad.Layout.LayoutModifier@@ -362,6 +375,7 @@                         XMonad.Util.Font                         XMonad.Util.Grab                         XMonad.Util.Hacks+                        XMonad.Util.History                         XMonad.Util.Image                         XMonad.Util.Invisible                         XMonad.Util.Loggers@@ -417,6 +431,7 @@                   XMonad.Actions.FocusNth                   XMonad.Actions.GridSelect                   XMonad.Actions.PhysicalScreens+                  XMonad.Actions.Repeatable                   XMonad.Actions.RotateSome                   XMonad.Actions.Submap                   XMonad.Actions.SwapWorkspaces@@ -462,7 +477,7 @@   build-depends: base                , QuickCheck >= 2                , X11 >= 1.10 && < 1.11-               , bytestring >= 0.10 && < 0.12+               , bytestring >= 0.10 && < 0.13                , containers                , directory                , time >= 1.8 && < 1.13@@ -473,7 +488,7 @@                , unix                , utf8-string                , deepseq-               , xmonad >= 0.16.9999 && < 0.18+               , xmonad >= 0.16.9999 && < 0.19   cpp-options: -DTESTING   ghc-options: -Wall -Wno-unused-do-bind   default-language: Haskell2010@@ -482,7 +497,10 @@      ghc-options: -Werror -Wwarn=deprecations -Wwarn=dodgy-imports    -- Keep this in sync with the oldest version in 'tested-with'-  if impl(ghc > 8.4.4)+  if impl(ghc > 8.6.5)      -- don't treat unused-imports warning as errors, they may be necessary      -- for compatibility with older versions of base (or other deps)      ghc-options: -Wwarn=unused-imports++  if impl(ghc > 9.8)+    ghc-options:   -Wno-x-partial