xmonad-contrib 0.11.4 → 0.12
raw patch · 178 files changed
+6378/−1023 lines, 178 filesdep +filepathdep ~basedep ~containersdep ~xmonadnew-uploader
Dependencies added: filepath
Dependency ranges changed: base, containers, xmonad
Files
- CHANGES.md +212/−0
- README +0/−82
- README.md +40/−0
- XMonad/Actions/AfterDrag.hs +71/−0
- XMonad/Actions/BluetileCommands.hs +1/−1
- XMonad/Actions/CopyWindow.hs +1/−1
- XMonad/Actions/CycleWS.hs +18/−9
- XMonad/Actions/DynamicProjects.hs +311/−0
- XMonad/Actions/DynamicWorkspaceGroups.hs +10/−2
- XMonad/Actions/DynamicWorkspaces.hs +49/−20
- XMonad/Actions/FloatSnap.hs +18/−8
- XMonad/Actions/GridSelect.hs +99/−33
- XMonad/Actions/GroupNavigation.hs +1/−1
- XMonad/Actions/Launcher.hs +3/−3
- XMonad/Actions/LinkWorkspaces.hs +169/−0
- XMonad/Actions/MouseResize.hs +2/−2
- XMonad/Actions/Navigation2D.hs +111/−21
- XMonad/Actions/Plane.hs +4/−3
- XMonad/Actions/Search.hs +28/−14
- XMonad/Actions/ShowText.hs +9/−4
- XMonad/Actions/SpawnOn.hs +15/−10
- XMonad/Actions/Submap.hs +2/−2
- XMonad/Actions/TagWindows.hs +6/−6
- XMonad/Actions/TopicSpace.hs +9/−4
- XMonad/Actions/UpdateFocus.hs +1/−1
- XMonad/Actions/UpdatePointer.hs +39/−40
- XMonad/Actions/WindowNavigation.hs +1/−1
- XMonad/Actions/WorkspaceCursors.hs +2/−2
- XMonad/Actions/WorkspaceNames.hs +20/−1
- XMonad/Config/Arossato.hs +9/−10
- XMonad/Config/Azerty.hs +1/−1
- XMonad/Config/Bepo.hs +47/−0
- XMonad/Config/Bluetile.hs +2/−2
- XMonad/Config/Desktop.hs +8/−7
- XMonad/Config/Dmwit.hs +323/−0
- XMonad/Config/Droundy.hs +7/−7
- XMonad/Config/Gnome.hs +1/−1
- XMonad/Config/Mate.hs +87/−0
- XMonad/Config/Prime.hs +689/−0
- XMonad/Config/Sjanssen.hs +5/−5
- XMonad/Config/dmwit.xmobarrc +10/−0
- XMonad/Doc.hs +2/−2
- XMonad/Doc/Configuring.hs +1/−1
- XMonad/Doc/Extending.hs +29/−29
- XMonad/Hooks/CurrentWorkspaceOnTop.hs +1/−1
- XMonad/Hooks/DebugEvents.hs +8/−1
- XMonad/Hooks/DebugKeyEvents.hs +6/−1
- XMonad/Hooks/DebugStack.hs +64/−47
- XMonad/Hooks/DynamicBars.hs +23/−25
- XMonad/Hooks/DynamicLog.hs +40/−30
- XMonad/Hooks/DynamicProperty.hs +71/−0
- XMonad/Hooks/EwmhDesktops.hs +4/−3
- XMonad/Hooks/FadeInactive.hs +1/−1
- XMonad/Hooks/FadeWindows.hs +1/−1
- XMonad/Hooks/FloatNext.hs +1/−1
- XMonad/Hooks/InsertPosition.hs +1/−1
- XMonad/Hooks/ManageDebug.hs +100/−0
- XMonad/Hooks/ManageDocks.hs +45/−15
- XMonad/Hooks/ManageHelpers.hs +1/−1
- XMonad/Hooks/Minimize.hs +3/−3
- XMonad/Hooks/Place.hs +2/−2
- XMonad/Hooks/PositionStoreHooks.hs +5/−5
- XMonad/Hooks/RestoreMinimized.hs +1/−1
- XMonad/Hooks/ScreenCorners.hs +30/−2
- XMonad/Hooks/Script.hs +1/−1
- XMonad/Hooks/ServerMode.hs +112/−44
- XMonad/Hooks/ToggleHook.hs +2/−2
- XMonad/Hooks/UrgencyHook.hs +76/−13
- XMonad/Hooks/WallpaperSetter.hs +223/−0
- XMonad/Hooks/WorkspaceByPos.hs +2/−2
- XMonad/Hooks/WorkspaceHistory.hs +74/−0
- XMonad/Layout/Accordion.hs +1/−1
- XMonad/Layout/AvoidFloats.hs +239/−0
- XMonad/Layout/BinarySpacePartition.hs +793/−0
- XMonad/Layout/BorderResize.hs +1/−1
- XMonad/Layout/BoringWindows.hs +1/−1
- XMonad/Layout/ButtonDecoration.hs +2/−2
- XMonad/Layout/Circle.hs +1/−1
- XMonad/Layout/Cross.hs +1/−1
- XMonad/Layout/Decoration.hs +8/−4
- XMonad/Layout/DecorationAddons.hs +1/−1
- XMonad/Layout/DecorationMadness.hs +26/−26
- XMonad/Layout/Dishes.hs +1/−1
- XMonad/Layout/DragPane.hs +1/−1
- XMonad/Layout/Drawer.hs +1/−1
- XMonad/Layout/Dwindle.hs +210/−0
- XMonad/Layout/DwmStyle.hs +9/−10
- XMonad/Layout/FixedColumn.hs +1/−1
- XMonad/Layout/Fullscreen.hs +21/−6
- XMonad/Layout/Gaps.hs +6/−1
- XMonad/Layout/Grid.hs +1/−1
- XMonad/Layout/Groups/Examples.hs +9/−4
- XMonad/Layout/Groups/Helpers.hs +1/−1
- XMonad/Layout/Groups/Wmii.hs +2/−1
- XMonad/Layout/Hidden.hs +133/−0
- XMonad/Layout/HintedGrid.hs +1/−1
- XMonad/Layout/HintedTile.hs +1/−1
- XMonad/Layout/IM.hs +1/−1
- XMonad/Layout/IfMax.hs +76/−0
- XMonad/Layout/ImageButtonDecoration.hs +3/−3
- XMonad/Layout/IndependentScreens.hs +45/−5
- XMonad/Layout/LayoutBuilder.hs +33/−14
- XMonad/Layout/LayoutCombinators.hs +1/−1
- XMonad/Layout/LayoutHints.hs +3/−3
- XMonad/Layout/LimitWindows.hs +1/−1
- XMonad/Layout/MagicFocus.hs +10/−10
- XMonad/Layout/Magnifier.hs +1/−1
- XMonad/Layout/Master.hs +25/−5
- XMonad/Layout/Maximize.hs +27/−13
- XMonad/Layout/Minimize.hs +1/−1
- XMonad/Layout/Monitor.hs +1/−1
- XMonad/Layout/Mosaic.hs +1/−1
- XMonad/Layout/MosaicAlt.hs +1/−1
- XMonad/Layout/MouseResizableTile.hs +1/−1
- XMonad/Layout/MultiColumns.hs +2/−2
- XMonad/Layout/MultiToggle.hs +1/−1
- XMonad/Layout/Named.hs +1/−1
- XMonad/Layout/NoFrillsDecoration.hs +2/−2
- XMonad/Layout/PerScreen.hs +74/−0
- XMonad/Layout/PerWorkspace.hs +13/−14
- XMonad/Layout/PositionStoreFloat.hs +2/−2
- XMonad/Layout/ResizableTile.hs +1/−1
- XMonad/Layout/Roledex.hs +1/−1
- XMonad/Layout/ShowWName.hs +10/−6
- XMonad/Layout/SimpleDecoration.hs +6/−5
- XMonad/Layout/SimpleFloat.hs +2/−2
- XMonad/Layout/Simplest.hs +1/−1
- XMonad/Layout/SimplestFloat.hs +1/−1
- XMonad/Layout/Spacing.hs +62/−2
- XMonad/Layout/Spiral.hs +1/−1
- XMonad/Layout/StackTile.hs +1/−1
- XMonad/Layout/Stoppable.hs +127/−0
- XMonad/Layout/SubLayouts.hs +6/−5
- XMonad/Layout/TabBarDecoration.hs +3/−3
- XMonad/Layout/Tabbed.hs +85/−32
- XMonad/Layout/ThreeColumns.hs +1/−1
- XMonad/Layout/ToggleLayouts.hs +1/−1
- XMonad/Layout/TrackFloating.hs +68/−6
- XMonad/Layout/TwoPane.hs +1/−1
- XMonad/Layout/WindowArranger.hs +3/−3
- XMonad/Layout/WindowNavigation.hs +9/−6
- XMonad/Layout/WindowSwitcherDecoration.hs +6/−6
- XMonad/Layout/WorkspaceDir.hs +2/−2
- XMonad/Prompt.hs +28/−15
- XMonad/Prompt/AppLauncher.hs +4/−4
- XMonad/Prompt/AppendFile.hs +2/−2
- XMonad/Prompt/ConfirmPrompt.hs +51/−0
- XMonad/Prompt/DirExec.hs +3/−3
- XMonad/Prompt/Directory.hs +1/−1
- XMonad/Prompt/Email.hs +1/−1
- XMonad/Prompt/Input.hs +2/−2
- XMonad/Prompt/Layout.hs +1/−1
- XMonad/Prompt/Man.hs +8/−4
- XMonad/Prompt/Pass.hs +152/−0
- XMonad/Prompt/RunOrRaise.hs +2/−2
- XMonad/Prompt/Shell.hs +23/−19
- XMonad/Prompt/Ssh.hs +10/−3
- XMonad/Prompt/Theme.hs +2/−2
- XMonad/Prompt/Window.hs +3/−3
- XMonad/Prompt/Workspace.hs +1/−1
- XMonad/Prompt/XMonad.hs +1/−1
- XMonad/Util/CustomKeys.hs +4/−4
- XMonad/Util/DebugWindow.hs +46/−12
- XMonad/Util/EZConfig.hs +8/−6
- XMonad/Util/ExtensibleState.hs +1/−1
- XMonad/Util/Invisible.hs +3/−1
- XMonad/Util/Loggers.hs +2/−2
- XMonad/Util/NamedActions.hs +7/−3
- XMonad/Util/NamedScratchpad.hs +1/−1
- XMonad/Util/RemoteWindows.hs +90/−0
- XMonad/Util/Replace.hs +2/−2
- XMonad/Util/Run.hs +1/−1
- XMonad/Util/SpawnNamedPipe.hs +76/−0
- XMonad/Util/Themes.hs +116/−117
- XMonad/Util/WindowState.hs +91/−0
- XMonad/Util/WorkspaceCompare.hs +9/−1
- XMonad/Util/XSelection.hs +10/−4
- xmonad-contrib.cabal +49/−26
+ CHANGES.md view
@@ -0,0 +1,212 @@+# Change Log / Release Notes++## 0.12 (December 14, 2015)++### Breaking Changes++ * `XMonad.Actions.UpdatePointer.updatePointer` arguments were+ changed. This allows including aspects of both of the+ `TowardsCentre` and `Relative` methods. To keep the same behavior,+ replace the entry in the left column with the entry on the right:++ | < 0.12 | >= 0.12 |+ |-------------------------------------|----------------------------------|+ | `updatePointer Nearest` | `updatePointer (0.5, 0.5) (1,1)` |+ | `updatePointer (Relative x y)` | `updatePointer (x,y) (1,1)` |+ | `updatePointer (TowardsCentre x y)` | `updatePointer (0.5,0.5) (x,y)` |++### New Modules++ * `XMonad.Actions.AfterDrag`++ Perform an action after the current mouse drag is completed.++ * `XMonad.Actions.DynamicProjects`++ Imbues workspaces with additional features so they can be treated+ as individual project areas.++ * `XMonad.Actions.LinkWorkspaces`++ Provides bindings to add and delete links between workspaces. It+ is aimed at providing useful links between workspaces in a+ multihead setup. Linked workspaces are viewed at the same time.++ * `XMonad.Config.Bepo`++ This module fixes some of the keybindings for the francophone+ among you who use a BEPO keyboard layout. Based on+ `XMonad.Config.Azerty`++ * `XMonad.Config.Dmwit`++ Daniel Wagner's configuration.++ * `XMonad.Config.Mate`++ This module provides a config suitable for use with the MATE+ desktop environment.++ * `XMonad.Config.Prime`++ A draft of a brand new config syntax for xmonad.++ * `XMonad.Hooks.DynamicProperty`++ 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.++ * `XMonad.Hooks.ManageDebug`++ 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 individual hooks in whatever way you see fit.++ * `XMonad.Hooks.WallpaperSetter`++ Log hook which changes the wallpapers depending on visible+ workspaces.++ * `XMonad.Hooks.WorkspaceHistory`++ Keeps track of workspace viewing order.++ * `XMonad.Layout.AvoidFloats`++ Find a maximum empty rectangle around floating windows and use+ that area to display non-floating windows.++ * `XMonad.Layout.BinarySpacePartition`++ Layout where new windows will split the focused window in half,+ based off of BSPWM.++ * `XMonad.Layout.Dwindle`++ Three layouts: The first, `Spiral`, is a reimplementation of+ `XMonad.Layout.Spiral.spiral` with, at least to me, more intuitive+ semantics. The second, `Dwindle`, is inspired by a similar layout+ in awesome and produces the same sequence of decreasing window+ sizes as Spiral but pushes the smallest windows into a screen+ corner rather than the centre. The third, `Squeeze` arranges all+ windows in one row or in one column, with geometrically decreasing+ sizes.++ * `XMonad.Layout.Hidden`++ Similar to `XMonad.Layout.Minimize` but completely removes windows+ from the window set so `XMonad.Layout.BoringWindows` isn't+ necessary. Perfect companion to `XMonad.Layout.BinarySpacePartition`+ since it can be used to move windows to another part of the BSP tree.++ * `XMonad.Layout.IfMax`++ Provides `IfMax` layout, which will run one layout if there are+ maximum `N` windows on workspace, and another layout, when number+ of windows is greater than `N`.++ * `XMonad.Layout.PerScreen`++ Configure layouts based on the width of your screen; use your+ favorite multi-column layout for wide screens and a full-screen+ layout for small ones.++ * `XMonad.Layout.Stoppable`++ This module implements a special kind of layout modifier, which when+ applied to a layout, causes xmonad to stop all non-visible processes.+ In a way, this is a sledge-hammer for applications that drain power.+ For example, given a web browser on a stoppable workspace, once the+ workspace is hidden the web browser will be stopped.++ * `XMonad.Prompt.ConfirmPrompt`++ A module for setting up simple confirmation prompts for+ keybindings.++ * `XMonad.Prompt.Pass`++ This module provides 3 `XMonad.Prompt`s to ease passwords+ manipulation (generate, read, remove) via [pass][].++ * `XMonad.Util.RemoteWindows`++ This module implements a proper way of finding out whether the+ window is remote or local.++ * `XMonad.Util.SpawnNamedPipe`++ A module for spawning a pipe whose `Handle` lives in the xmonad state.++ * `XMonad.Util.WindowState`++ Functions for saving per-window data.++### Miscellaneous Changes++ * Fix issue #9: `XMonad.Prompt.Shell` `searchPredicate` is ignored,+ defaults to `isPrefixOf`++ * Fix moveHistory when alwaysHighlight is enabled++ * `XMonad.Actions.DynamicWorkspaceGroups` now exports `addRawWSGroup`++ * Side tabs were added to the tabbed layout++ * `XMonad/Layout/IndependentScreens` now exports `marshallSort`++ * `XMonad/Hooks/UrgencyHook` now exports `clearUrgency`++ * Exceptions are now caught when finding commands on `PATH` in `Prompt.Shell`++ * Switched to `Data.Default` wherever possible++ * `XMonad.Layout.IndependentScreens` now exports `whenCurrentOn`++ * `XMonad.Util.NamedActions` now exports `addDescrKeys'`++ * EWMH `DEMANDS_ATTENTION` support added to `UrgencyHook`++ * New `useTransientFor` modifier in `XMonad.Layout.TrackFloating`++ * Added the ability to remove arbitrary workspaces++## 0.9 (October 26, 2009)++### Updates that Require Changes in `xmonad.hs`++ * `XMonad.Hooks.EwmhDesktops` no longer uses `layoutHook`, the+ `ewmhDesktopsLayout` modifier has been removed from+ xmonad-contrib. It uses `logHook`, `handleEventHook`, and+ `startupHook` instead and provides a convenient function `ewmh` to+ add EWMH support to a `defaultConfig`.++ * Most `DynamicLog` users can continue with configs unchanged, but+ users of the quickbar functions `xmobar` or `dzen` will need to+ change `xmonad.hs`: their types have changed to allow easier+ composition with other `XConfig` modifiers. The `dynamicLogDzen`+ and `dynamicLogXmobar` functions have been removed.++ * `WindowGo` or `safeSpawn` users may need to change command lines+ due to `safeSpawn` changes.++ * People explicitly referencing the "SP" scratchpad workspace should+ change it to "NSP" which is also used by the new+ `Util.NamedScratchpad` module.++ * (Optional) People who explicitly use `swapMaster` in key or mouse+ bindings should change it to `shiftMaster`. It's the current+ default used where `swapMaster` had been used previously. It works+ better than `swapMaster` when using floating and tiled windows+ together on the same workspace.++## See Also++<https://wiki.haskell.org/Xmonad/Notable_changes_since_0.8>++[pass]: http://www.passwordstore.org/
− README
@@ -1,82 +0,0 @@- xmonad-contrib : third party extensions to the xmonad window manager-- http://xmonad.org-- You need the ghc compiler and xmonad window manager installed in- order to use these extensions.-- For installation and configuration instructions, please see the- xmonad website, the documents included with the xmonad source- distribution, and online haddock documentation:-- http://www.xmonad.org/xmonad-docs----------------------------------------------------------------------------Changelogs-- For a list of changes since the 0.8.x releases, see:--http://www.haskell.org/haskellwiki/Xmonad/Notable_changes_since_0.8----------------------------------------------------------------------------Updates to XMonadContrib-0.9 that may Require Changes to ~/.xmonad/xmonad.hs-- Please see the Changelogs and xmonad-contrib haddock documentation- links for further details regarding the following changes.-- * XMonad.Hooks.EwmhDesktops no longer uses layoutHook, the- ewmhDesktopsLayout modifier has been removed from xmonad-contrib. It- uses logHook, handleEventHook, and startupHook instead and provides- a convenient function 'ewmh' to add EWMH support to a defaultConfig.-- * Most DynamicLog users can continue with configs unchanged, but users- of the quickbar functions 'xmobar' or 'dzen' will need to change- xmonad.hs: their types have changed to allow easier composition with- other XConfig modifiers. The 'dynamicLogDzen' and 'dynamicLogXmobar'- functions have been removed.-- * WindowGo or safeSpawn users may need to change command lines due to- safeSpawn changes.-- * People explicitly referencing the "SP" scratchpad workspace should- change it to "NSP" which is also used by the new Util.NamedScratchpad.-- * (Optional) People who explicitly use swapMaster in key or mouse- bindings should change it to shiftMaster. It's the current default- used where swapMaster had been used previously. It works better than- swapMaster when using floating and tiled windows together on the- same workspace.----------------------------------------------------------------------------Getting or updating XMonadContrib-- latest release: http://hackage.haskell.org/cgi-bin/hackage-scripts/package/xmonad-contrib-- darcs version: darcs get http://code.haskell.org/XMonadContrib-- (To use darcs xmonad-contrib you must also use the darcs version- of xmonad.)----------------------------------------------------------------------------Contributing-- Haskell code contributed to this repo should live under the- appropriate subdivision of the 'XMonad.' namespace (currently- includes Actions, Config, Hooks, Layout, Prompt, and Util). For- example, to use the Grid layout, one would import:-- XMonad.Layout.Grid-- For further details, see the documentation for the- XMonad.Doc.Developing module and http://xmonad.org website.----------------------------------------------------------------------------Code submitted to the contrib repo is licensed under the same license as-xmonad itself, with copyright held by the authors.--------------------------------------------------------------------------
+ README.md view
@@ -0,0 +1,40 @@+# xmonad-contrib: Third Party Extensions to the xmonad Window Manager++You need the ghc compiler and xmonad window manager installed in+order to use these extensions.++For installation and configuration instructions, please see the+[xmonad website] [xmonad], the documents included with the+[xmonad source distribution] [xmonad-git], and the+[online haddock documentation] [xmonad-docs].++## Getting or Updating XMonadContrib++ * Latest release: <https://hackage.haskell.org/package/xmonad-contrib>++ * Git version: <https://github.com/xmonad/xmonad-contrib>++(To use git xmonad-contrib you must also use the+[git version of xmonad] [xmonad-git].)++## Contributing++Haskell code contributed to this repo should live under the+appropriate subdivision of the `XMonad` namespace (currently includes+`Actions`, `Config`, `Hooks`, `Layout`, `Prompt`, and `Util`). For+example, to use the Grid layout, one would import:++ XMonad.Layout.Grid++For further details, see the [documentation] [developing] for the+`XMonad.Doc.Developing` module and the [xmonad website] [xmonad].++## License++Code submitted to the contrib repo is licensed under the same license as+xmonad itself, with copyright held by the authors.++[xmonad]: http://xmonad.org+[xmonad-git]: https://github.com/xmonad/xmonad+[xmonad-docs]: http://www.xmonad.org/xmonad-docs+[developing]: http://xmonad.org/xmonad-docs/xmonad-contrib/XMonad-Doc-Developing.html
+ XMonad/Actions/AfterDrag.hs view
@@ -0,0 +1,71 @@+-----------------------------------------------------------------------------+-- |+-- Module : XMonad.Actions.AfterDrag+-- Copyright : (c) 2014 Anders Engstrom <ankaan@gmail.com>+-- License : BSD3-style (see LICENSE)+--+-- Maintainer : Anders Engstrom <ankaan@gmail.com>+-- Stability : unstable+-- Portability : unportable+--+-- Perform an action after the current mouse drag is completed.+-----------------------------------------------------------------------------++module XMonad.Actions.AfterDrag (+ -- * Usage+ -- $usage+ afterDrag,+ ifClick,+ ifClick') where++import XMonad+import System.Time++-- $usage+-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+--+-- > import XMonad.Actions.AfterDrag+--+-- Then add appropriate mouse bindings, for example:+--+-- > , ((modm, button3), (\w -> focus w >> mouseResizeWindow w >> ifClick (windows $ W.float w $ W.RationalRect 0 0 1 1)))+--+-- This will allow you to resize windows as usual, but if you instead of+-- draging click the mouse button the window will be automatically resized to+-- fill the whole screen.+--+-- For detailed instructions on editing your mouse bindings, see+-- "XMonad.Doc.Extending#Editing_mouse_bindings".+--+-- More practical examples are available in "XMonad.Actions.FloatSnap".++-- | Schedule a task to take place after the current dragging is completed.+afterDrag+ :: X () -- ^ The task to schedule.+ -> X ()+afterDrag task = do drag <- gets dragging+ case drag of+ Nothing -> return () -- Not dragging+ Just (motion, cleanup) -> modify $ \s -> s { dragging = Just(motion, cleanup >> task) }++-- | Take an action if the current dragging can be considered a click,+-- supposing the drag just started before this function is called.+-- A drag is considered a click if it is completed within 300 ms.+ifClick+ :: X () -- ^ The action to take if the dragging turned out to be a click.+ -> X () +ifClick action = ifClick' 300 action (return ())++-- | Take an action if the current dragging is completed within a certain time (in milliseconds.)+ifClick'+ :: Int -- ^ Maximum time of dragging for it to be considered a click (in milliseconds.)+ -> X () -- ^ The action to take if the dragging turned out to be a click.+ -> X () -- ^ The action to take if the dragging turned out to not be a click.+ -> X () +ifClick' ms click drag = do+ start <- io $ getClockTime+ afterDrag $ do + stop <- io $ getClockTime+ if diffClockTimes stop start <= noTimeDiff { tdPicosec = fromIntegral ms * 10^(9 :: Integer) }+ then click+ else drag
XMonad/Actions/BluetileCommands.hs view
@@ -36,7 +36,7 @@ -- -- Then edit your @handleEventHook@: ----- > main = xmonad defaultConfig { handleEventHook = serverModeEventHook' bluetileCommands }+-- > main = xmonad def { handleEventHook = serverModeEventHook' bluetileCommands } -- -- See the documentation of "XMonad.Hooks.ServerMode" for details on -- how to actually invoke the commands from external programs.
XMonad/Actions/CopyWindow.hs view
@@ -87,7 +87,7 @@ -- > -- > main = do -- > h <- spawnPipe "xmobar"--- > xmonad defaultConfig { logHook = sampleLogHook h }+-- > xmonad def { logHook = sampleLogHook h } -- | Copy the focused window to a workspace. copy :: (Eq s, Eq i, Eq a) => i -> W.StackSet i l a s sd -> W.StackSet i l a s sd
XMonad/Actions/CycleWS.hs view
@@ -78,11 +78,11 @@ ) where -import Control.Monad ( unless )-import Data.List ( findIndex )+import Data.List ( find, findIndex ) import Data.Maybe ( isNothing, isJust ) import XMonad hiding (workspaces)+import qualified XMonad.Hooks.WorkspaceHistory as WH import XMonad.StackSet hiding (filter) import XMonad.Util.Types import XMonad.Util.WorkspaceCompare@@ -119,6 +119,10 @@ -- -- For detailed instructions on editing your key bindings, see -- "XMonad.Doc.Extending#Editing_key_bindings".+--+-- When using the toggle functions, in order to ensure that the workspace+-- to which you switch is the previously viewed workspace, use the+-- 'logHook' in "XMonad.Hooks.WorkspaceHistory". {- $moving @@ -158,9 +162,7 @@ -- > -- Ignore the scratchpad workspace while toggling: -- > ("M-b", toggleWS' ["NSP"]) toggleWS' :: [WorkspaceId] -> X ()-toggleWS' skips = do- hs' <- cleanHiddens skips- unless (null hs') (windows . view . tag $ head hs')+toggleWS' skips = lastViewedHiddenExcept skips >>= flip whenJust (windows . view) -- | 'XMonad.StackSet.greedyView' a workspace, or if already there, view -- the previously displayed workspace ala weechat. Change @greedyView@ to@@ -184,10 +186,9 @@ toggleOrDoSkip :: [WorkspaceId] -> (WorkspaceId -> WindowSet -> WindowSet) -> WorkspaceId -> X () toggleOrDoSkip skips f toWS = do- hs' <- cleanHiddens skips cur <- gets (currentTag . windowset) if toWS == cur- then unless (null hs') (windows . f . tag $ head hs')+ then lastViewedHiddenExcept skips >>= flip whenJust (windows . f) else windows (f toWS) -- | List difference ('\\') for workspaces and tags. Removes workspaces@@ -195,8 +196,16 @@ skipTags :: (Eq i) => [Workspace i l a] -> [i] -> [Workspace i l a] skipTags wss ids = filter ((`notElem` ids) . tag) wss -cleanHiddens :: [WorkspaceId] -> X [WindowSpace]-cleanHiddens skips = gets $ (flip skipTags) skips . hidden . windowset+-- | Ignoring the skips, find the best candidate for the last viewed hidden+-- workspace.+lastViewedHiddenExcept :: [WorkspaceId] -> X (Maybe WorkspaceId)+lastViewedHiddenExcept skips = do+ hs <- gets $ map tag . flip skipTags skips . hidden . windowset+ vs <- WH.workspaceHistory+ return $ choose hs (find (`elem` hs) vs)+ where choose [] _ = Nothing+ choose (h:_) Nothing = Just h+ choose _ vh@(Just _) = vh switchWorkspace :: Int -> X () switchWorkspace d = wsBy d >>= windows . greedyView
+ XMonad/Actions/DynamicProjects.hs view
@@ -0,0 +1,311 @@+{-# LANGUAGE DeriveDataTypeable #-}++--------------------------------------------------------------------------------+-- |+-- Module : XMonad.Actions.DynamicProjects+-- Copyright : (c) Peter J. Jones+-- License : BSD3-style (see LICENSE)+--+-- Maintainer : Peter Jones <pjones@devalot.com>+-- Stability : unstable+-- Portability : not portable+--+-- Imbues workspaces with additional features so they can be treated+-- as individual project areas.+--------------------------------------------------------------------------------+module XMonad.Actions.DynamicProjects+ ( -- * Overview+ -- $overview++ -- * Usage+ -- $usage++ -- * Types+ Project (..)+ , ProjectName++ -- * Hooks+ , dynamicProjects++ -- * Bindings+ , switchProjectPrompt+ , shiftToProjectPrompt+ , renameProjectPrompt++ -- * Helper Functions+ , switchProject+ , shiftToProject+ , lookupProject+ , currentProject+ , activateProject+ ) where++--------------------------------------------------------------------------------+import Control.Applicative ((<|>))+import Control.Monad (when, unless)+import Data.List (sort, union, stripPrefix)+import Data.Map.Strict (Map)+import qualified Data.Map.Strict as Map+import Data.Maybe (fromMaybe, isNothing)+import Data.Monoid ((<>))+import System.Directory (setCurrentDirectory, getHomeDirectory)+import XMonad+import XMonad.Actions.DynamicWorkspaces+import XMonad.Prompt+import XMonad.Prompt.Directory (directoryPrompt)+import XMonad.Prompt.Workspace (Wor(..))+import qualified XMonad.StackSet as W+import qualified XMonad.Util.ExtensibleState as XS++--------------------------------------------------------------------------------+-- $overview+-- Inspired by @TopicSpace@, @DynamicWorkspaces@, and @WorkspaceDir@,+-- @DynamicProjects@ treats workspaces as projects while maintaining+-- compatibility with all existing workspace-related functionality in+-- XMonad.+--+-- Instead of using generic workspace names such as @3@ or @work@,+-- @DynamicProjects@ allows you to dedicate workspaces to specific+-- projects and then switch between projects easily.+--+-- A project is made up of a name, working directory, and a start-up+-- hook. When you switch to a workspace, @DynamicProjects@ changes+-- the working directory to the one configured for the matching+-- project. If the workspace doesn't have any windows, the project's+-- start-up hook is executed. This allows you to launch applications+-- or further configure the workspace/project.+--+-- When using the @switchProjectPrompt@ function, workspaces are+-- created as needed. This means you can create new project spaces+-- (and therefore workspaces) on the fly. (These dynamic projects are+-- not preserved across restarts.)+--+-- Additionally, frequently used projects can be configured statically+-- in your XMonad configuration. Doing so allows you to configure the+-- per-project start-up hook.++--------------------------------------------------------------------------------+-- $usage+-- To use @DynamicProjects@ you need to add it to your XMonad+-- configuration and then configure some optional key bindings.+--+-- > import XMonad.Actions.DynamicProjects+--+-- Start by defining some projects:+--+-- > projects :: [Project]+-- > projects =+-- > [ Project { projectName = "scratch"+-- > , projectDirectory = "~/"+-- > , projectStartHook = Nothing+-- > }+-- >+-- > , Project { projectName = "browser"+-- > , projectDirectory = "~/download"+-- > , projectStartHook = Just $ do spawn "conkeror"+-- > spawn "chromium"+-- > }+-- > ]+--+-- Then inject @DynamicProjects@ into your XMonad configuration:+--+-- > main = xmonad $ dynamicProjects projects def+--+-- And finally, configure some optional key bindings:+--+-- > , ((modm, xK_space), switchProjectPrompt)+-- > , ((modm, xK_slash), shiftToProjectPrompt)+--+-- For detailed instructions on editing your key bindings, see+-- "XMonad.Doc.Extending#Editing_key_bindings".++--------------------------------------------------------------------------------+type ProjectName = String+type ProjectTable = Map ProjectName Project++--------------------------------------------------------------------------------+-- | Details about a workspace that represents a project.+data Project = Project+ { projectName :: !ProjectName -- ^ Workspace name.+ , projectDirectory :: !FilePath -- ^ Working directory.+ , projectStartHook :: !(Maybe (X ())) -- ^ Optional start-up hook.+ } deriving Typeable++--------------------------------------------------------------------------------+-- | Internal project state.+data ProjectState = ProjectState+ { projects :: !ProjectTable+ , previousProject :: !(Maybe WorkspaceId)+ } deriving Typeable++--------------------------------------------------------------------------------+instance ExtensionClass ProjectState where+ initialValue = ProjectState Map.empty Nothing++--------------------------------------------------------------------------------+-- | Add dynamic projects support to the given config.+dynamicProjects :: [Project] -> XConfig a -> XConfig a+dynamicProjects ps c =+ c { startupHook = startupHook c <> dynamicProjectsStartupHook ps+ , logHook = logHook c <> dynamicProjectsLogHook+ }++--------------------------------------------------------------------------------+-- | Log hook for tracking workspace changes.+dynamicProjectsLogHook :: X ()+dynamicProjectsLogHook = do+ name <- gets (W.tag . W.workspace . W.current . windowset)+ state <- XS.get++ unless (Just name == previousProject state) $ do+ XS.put (state {previousProject = Just name})+ activateProject . fromMaybe (defProject name) $+ Map.lookup name (projects state)++--------------------------------------------------------------------------------+-- | Start-up hook for recording configured projects.+dynamicProjectsStartupHook :: [Project] -> X ()+dynamicProjectsStartupHook ps = XS.modify go+ where+ go :: ProjectState -> ProjectState+ go s = s {projects = update $ projects s}++ update :: ProjectTable -> ProjectTable+ update = Map.union (Map.fromList $ map entry ps)++ entry :: Project -> (ProjectName, Project)+ entry p = (projectName p, addDefaultHook p)++ -- Force the hook to be a @Just@ so that it doesn't automatically+ -- get deleted when switching away from a workspace with no+ -- windows.+ addDefaultHook :: Project -> Project+ addDefaultHook p = p { projectStartHook = projectStartHook p <|>+ Just (return ())+ }++--------------------------------------------------------------------------------+-- | Find a project based on its name.+lookupProject :: ProjectName -> X (Maybe Project)+lookupProject name = Map.lookup name `fmap` XS.gets projects++--------------------------------------------------------------------------------+-- | Fetch the current project (the one being used for the currently+-- active workspace).+currentProject :: X Project+currentProject = do+ name <- gets (W.tag . W.workspace . W.current . windowset)+ proj <- lookupProject name+ return $ fromMaybe (defProject name) proj++--------------------------------------------------------------------------------+-- | Switch to the given project.+switchProject :: Project -> X ()+switchProject p = do+ oldws <- gets (W.workspace . W.current . windowset)+ oldp <- currentProject++ let name = W.tag oldws+ ws = W.integrate' (W.stack oldws)++ -- If the project we are switching away from has no windows, and+ -- it's a dynamic project, remove it from the configuration.+ when (null ws && isNothing (projectStartHook oldp)) $+ XS.modify (\s -> s {projects = Map.delete name $ projects s})++ appendWorkspace (projectName p)++--------------------------------------------------------------------------------+-- | Prompt for a project name and then switch to it. Automatically+-- creates a project if a new name is returned from the prompt.+switchProjectPrompt :: XPConfig -> X ()+switchProjectPrompt c = projectPrompt c switch+ where+ switch :: ProjectTable -> ProjectName -> X ()+ switch ps name = case Map.lookup name ps of+ Just p -> switchProject p+ Nothing | null name -> return ()+ | otherwise -> directoryPrompt dirC "Project Dir: " (mkProject name)++ dirC :: XPConfig+ dirC = c { alwaysHighlight = False } -- Fix broken tab completion.++ mkProject :: ProjectName -> FilePath -> X ()+ mkProject name dir = do+ let p = Project name dir Nothing+ XS.modify $ \s -> s {projects = Map.insert name p $ projects s}+ switchProject p++--------------------------------------------------------------------------------+-- | Shift the currently focused window to the given project.+shiftToProject :: Project -> X ()+shiftToProject p = do+ addHiddenWorkspace (projectName p)+ windows (W.shift $ projectName p)++--------------------------------------------------------------------------------+-- | Prompts for a project name and then shifts the currently focused+-- window to that project.+shiftToProjectPrompt :: XPConfig -> X ()+shiftToProjectPrompt c = projectPrompt c go+ where+ go :: ProjectTable -> ProjectName -> X ()+ go ps name = shiftToProject . fromMaybe (defProject name) $+ Map.lookup name ps++--------------------------------------------------------------------------------+-- | Prompt for a project name.+projectPrompt :: XPConfig -> (ProjectTable -> ProjectName -> X ()) -> X ()+projectPrompt c f = do+ ws <- map W.tag `fmap` gets (W.workspaces . windowset)+ ps <- XS.gets projects++ let names = sort (Map.keys ps `union` ws)+ label = "Switch or Create Project: "++ mkXPrompt (Wor label) c (mkComplFunFromList' names) (f ps)++--------------------------------------------------------------------------------+-- | Rename the current project.+renameProjectPrompt :: XPConfig -> X ()+renameProjectPrompt c = mkXPrompt (Wor "New Project Name: ") c (return . (:[])) go+ where+ go :: String -> X ()+ go name = do+ p <- currentProject+ ps <- XS.gets projects+ renameWorkspaceByName name++ let p' = fromMaybe (p { projectName = name }) $ Map.lookup name ps+ ps' = Map.insert name p' $ Map.delete (projectName p) ps++ XS.modify $ \s -> s {projects = ps'}+ activateProject p'++--------------------------------------------------------------------------------+-- | Activate a project by updating the working directory and+-- possibly running its start-up hook. This function is automatically+-- invoked when the workspace changes.+activateProject :: Project -> X ()+activateProject p = do+ ws <- gets (W.integrate' . W.stack . W.workspace . W.current . windowset)+ home <- io getHomeDirectory++ -- Change to the project's directory.+ catchIO (setCurrentDirectory $ expandHome home $ projectDirectory p)++ -- Possibly run the project's startup hook.+ when (null ws) $ fromMaybe (return ()) (projectStartHook p)++ where++ -- Replace an initial @~@ character with the home directory.+ expandHome :: FilePath -> FilePath -> FilePath+ expandHome home dir = case stripPrefix "~" dir of+ Nothing -> dir+ Just xs -> home ++ xs++--------------------------------------------------------------------------------+-- | Default project.+defProject :: ProjectName -> Project+defProject name = Project name "~/" Nothing
XMonad/Actions/DynamicWorkspaceGroups.hs view
@@ -23,6 +23,7 @@ WSGroupId + , addRawWSGroup , addWSGroup , addCurrentWSGroup , forgetWSGroup@@ -72,20 +73,27 @@ initialValue = WSG $ M.empty extensionType = PersistentExtension +-- | Add a new workspace group of the given name, mapping to an+-- explicitly specified association between screen IDs and workspace+-- names. This function could be useful for, say, creating some+-- standard workspace groups in your startup hook.+addRawWSGroup :: WSGroupId -> [(ScreenId, WorkspaceId)] -> X ()+addRawWSGroup name = XS.modify . withWSG . M.insert name+ -- | Add a new workspace group with the given name. addWSGroup :: WSGroupId -> [WorkspaceId] -> X () addWSGroup name wids = withWindowSet $ \w -> do let wss = map ((W.tag . W.workspace) &&& W.screen) $ W.screens w wmap = mapM (strength . (flip lookup wss &&& id)) wids case wmap of- Just ps -> XS.modify . withWSG . M.insert name $ ps+ Just ps -> addRawWSGroup name ps Nothing -> return () where strength (ma, b) = ma >>= \a -> return (a,b) -- | Give a name to the current workspace group. addCurrentWSGroup :: WSGroupId -> X () addCurrentWSGroup name = withWindowSet $ \w ->- addWSGroup name $ map (W.tag . W.workspace) (W.current w : W.visible w)+ addWSGroup name $ map (W.tag . W.workspace) (reverse $ W.current w : W.visible w) -- | Delete the named workspace group from the list of workspace -- groups. Note that this has no effect on the workspaces involved;
XMonad/Actions/DynamicWorkspaces.hs view
@@ -16,11 +16,14 @@ -- * Usage -- $usage addWorkspace, addWorkspacePrompt,+ appendWorkspace, appendWorkspacePrompt,+ addWorkspaceAt, removeWorkspace,+ removeWorkspaceByTag, removeEmptyWorkspace, removeEmptyWorkspaceAfter, removeEmptyWorkspaceAfterExcept,- addHiddenWorkspace,+ addHiddenWorkspace, addHiddenWorkspaceAt, withWorkspace, selectWorkspace, renameWorkspace, renameWorkspaceByName,@@ -45,10 +48,10 @@ -- Then add keybindings like the following: -- -- > , ((modm .|. shiftMask, xK_BackSpace), removeWorkspace)--- > , ((modm .|. shiftMask, xK_v ), selectWorkspace defaultXPConfig)--- > , ((modm, xK_m ), withWorkspace defaultXPConfig (windows . W.shift))--- > , ((modm .|. shiftMask, xK_m ), withWorkspace defaultXPConfig (windows . copy))--- > , ((modm .|. shiftMask, xK_r ), renameWorkspace defaultXPConfig)+-- > , ((modm .|. shiftMask, xK_v ), selectWorkspace def)+-- > , ((modm, xK_m ), withWorkspace def (windows . W.shift))+-- > , ((modm .|. shiftMask, xK_m ), withWorkspace def (windows . copy))+-- > , ((modm .|. shiftMask, xK_r ), renameWorkspace def) -- -- > -- mod-[1..9] %! Switch to workspace N -- > -- mod-shift-[1..9] %! Move client to workspace N@@ -59,9 +62,10 @@ -- -- For detailed instructions on editing your key bindings, see -- "XMonad.Doc.Extending#Editing_key_bindings". See also the documentation for--- "XMonad.Actions.CopyWindow", 'windows', 'shift', and 'defaultXPConfig'.+-- "XMonad.Actions.CopyWindow", 'windows', 'shift', and 'XPConfig'. + mkCompl :: [String] -> String -> IO [String] mkCompl l s = return $ filter (\x -> take (length s) x == s) l @@ -107,21 +111,42 @@ -- workspace with the given name already exists; then switch to the -- newly created workspace. addWorkspace :: String -> X ()-addWorkspace newtag = addHiddenWorkspace newtag >> windows (greedyView newtag)+addWorkspace = addWorkspaceAt (:) +-- | Same as addWorkspace, but adds the workspace to the end of the list of workspaces+appendWorkspace :: String -> X()+appendWorkspace = addWorkspaceAt (flip (++) . return)++-- | Adds a new workspace with the given name to the current list of workspaces.+-- This function allows the user to pass a function that inserts an element+-- into a list at an arbitrary spot.+addWorkspaceAt :: (WindowSpace -> [WindowSpace] -> [WindowSpace]) -> String -> X ()+addWorkspaceAt add newtag = addHiddenWorkspaceAt add newtag >> windows (greedyView newtag)+ -- | Prompt for the name of a new workspace, add it if it does not -- already exist, and switch to it. addWorkspacePrompt :: XPConfig -> X () addWorkspacePrompt conf = mkXPrompt (Wor "New workspace name: ") conf (const (return [])) addWorkspace +-- | Prompt for the name of a new workspace, appending it to the end of the list of workspaces +-- if it does not already exist, and switch to it.+appendWorkspacePrompt :: XPConfig -> X ()+appendWorkspacePrompt conf = mkXPrompt (Wor "New workspace name: ") conf (const (return [])) appendWorkspace+ -- | Add a new hidden workspace with the given name, or do nothing if--- a workspace with the given name already exists.-addHiddenWorkspace :: String -> X ()-addHiddenWorkspace newtag =+-- a workspace with the given name already exists. Takes a function to insert+-- the workspace at an arbitrary spot in the list.+addHiddenWorkspaceAt :: (WindowSpace -> [WindowSpace] -> [WindowSpace]) -> String -> X ()+addHiddenWorkspaceAt add newtag = whenX (gets (not . tagMember newtag . windowset)) $ do l <- asks (layoutHook . config)- windows (addHiddenWorkspace' newtag l)+ windows (addHiddenWorkspace' add newtag l) +-- | Add a new hidden workspace with the given name, or do nothing if+-- a workspace with the given name already exists.+addHiddenWorkspace :: String -> X ()+addHiddenWorkspace = addHiddenWorkspaceAt (:)+ -- | Remove the current workspace if it contains no windows. removeEmptyWorkspace :: X () removeEmptyWorkspace = gets (currentTag . windowset) >>= removeEmptyWorkspaceByTag@@ -130,12 +155,11 @@ removeWorkspace :: X () removeWorkspace = gets (currentTag . windowset) >>= removeWorkspaceByTag --- | Remove workspace with specific tag if it contains no windows. Only works--- on the current or the last workspace.+-- | Remove workspace with specific tag if it contains no windows. removeEmptyWorkspaceByTag :: String -> X () removeEmptyWorkspaceByTag t = whenX (isEmpty t) $ removeWorkspaceByTag t --- | Remove workspace with specific tag. Only works on the current or the last workspace.+-- | Remove workspace with specific tag. removeWorkspaceByTag :: String -> X () removeWorkspaceByTag torem = do s <- gets windowset@@ -166,16 +190,21 @@ let mws = find (\ws -> tag ws == t) wsl return $ maybe True (isNothing . stack) mws -addHiddenWorkspace' :: i -> l -> StackSet i l a sid sd -> StackSet i l a sid sd-addHiddenWorkspace' newtag l s@(StackSet { hidden = ws }) = s { hidden = Workspace newtag l Nothing:ws }+addHiddenWorkspace' :: (Workspace i l a -> [Workspace i l a] -> [Workspace i l a]) -> i -> l -> StackSet i l a sid sd -> StackSet i l a sid sd+addHiddenWorkspace' add newtag l s@(StackSet { hidden = ws }) = s { hidden = add (Workspace newtag l Nothing) ws } +-- | Remove the hidden workspace with the given tag from the StackSet, if+-- it exists. All the windows in that workspace are moved to the current+-- workspace. removeWorkspace' :: (Eq i) => i -> StackSet i l a sid sd -> StackSet i l a sid sd removeWorkspace' torem s@(StackSet { current = scr@(Screen { workspace = wc })- , hidden = (w:ws) })- | tag w == torem = s { current = scr { workspace = wc { stack = meld (stack w) (stack wc) } }- , hidden = ws }+ , hidden = hs })+ = let (xs, ys) = break ((== torem) . tag) hs+ in removeWorkspace'' xs ys where meld Nothing Nothing = Nothing meld x Nothing = x meld Nothing x = x meld (Just x) (Just y) = differentiate (integrate x ++ integrate y)-removeWorkspace' _ s = s+ removeWorkspace'' xs (y:ys) = s { current = scr { workspace = wc { stack = meld (stack y) (stack wc) } }+ , hidden = xs ++ ys }+ removeWorkspace'' _ _ = s
XMonad/Actions/FloatSnap.hs view
@@ -21,18 +21,21 @@ snapShrink, snapMagicMove, snapMagicResize,- snapMagicMouseResize) where+ snapMagicMouseResize,+ afterDrag,+ ifClick,+ ifClick') where import XMonad import Control.Applicative((<$>)) import Data.List (sort) import Data.Maybe (listToMaybe,fromJust,isNothing) import qualified XMonad.StackSet as W+import qualified Data.Set as S import XMonad.Hooks.ManageDocks (calcGap) import XMonad.Util.Types (Direction2D(..))--import qualified Data.Set as S+import XMonad.Actions.AfterDrag -- $usage -- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:@@ -53,17 +56,24 @@ -- For detailed instructions on editing your key bindings, see -- "XMonad.Doc.Extending#Editing_key_bindings". ----- And possibly add an appropriate mouse binding, for example:+-- And possibly add appropriate mouse bindings, for example: ----- > , ((modm, button1), (\w -> focus w >> mouseMoveWindow w >> snapMagicMove (Just 50) (Just 50) w))--- > , ((modm .|. shiftMask, button1), (\w -> focus w >> mouseMoveWindow w >> snapMagicResize [L,R,U,D] (Just 50) (Just 50) w))--- > , ((modm, button3), (\w -> focus w >> mouseResizeWindow w >> snapMagicResize [R,D] (Just 50) (Just 50) w))+-- > , ((modm, button1), (\w -> focus w >> mouseMoveWindow w >> ifClick (snapMagicMove (Just 50) (Just 50) w)))+-- > , ((modm .|. shiftMask, button1), (\w -> focus w >> mouseMoveWindow w >> ifClick (snapMagicResize [L,R,U,D] (Just 50) (Just 50) w)))+-- > , ((modm, button3), (\w -> focus w >> mouseResizeWindow w >> ifClick (snapMagicResize [R,D] (Just 50) (Just 50) w))) -- -- For detailed instructions on editing your mouse bindings, see -- "XMonad.Doc.Extending#Editing_mouse_bindings". -- -- Using these mouse bindings, it will not snap while moving, but allow you to click the window once after it has been moved or resized to snap it into place.--- Note that the order in which the commands are applied in the mouse bindings are important.+-- Note that the order in which the commands are applied in the mouse bindings are important. Snapping can also be used together with other window resizing+-- functions, such as those from "XMonad.Actions.FlexibleResize"+--+-- An alternative set of mouse bindings that will always snap after the drag is:+--+-- > , ((modm, button1), (\w -> focus w >> mouseMoveWindow w >> afterDrag (snapMagicMove (Just 50) (Just 50) w)))+-- > , ((modm .|. shiftMask, button1), (\w -> focus w >> mouseMoveWindow w >> afterDrag (snapMagicResize [L,R,U,D] (Just 50) (Just 50) w)))+-- > , ((modm, button3), (\w -> focus w >> mouseResizeWindow w >> afterDrag (snapMagicResize [R,D] (Just 50) (Just 50) w))) -- -- Interesting values for the distance to look for window in the orthogonal axis are Nothing (to snap against every window), Just 0 (to only snap -- against windows that we should collide with geometrically while moving) and Just 1 (to also snap against windows we brush against).
XMonad/Actions/GridSelect.hs view
@@ -27,6 +27,7 @@ -- * Configuration GSConfig(..),+ def, defaultGSConfig, TwoDPosition, buildDefaultGSConfig,@@ -38,6 +39,7 @@ bringSelected, goToSelected, gridselectWorkspace,+ gridselectWorkspace', spawnSelected, runSelectedAction, @@ -65,6 +67,12 @@ cancel, transformSearchString, + -- * Rearrangers+ -- $rearrangers+ Rearranger,+ noRearranger,+ searchStringRearrangerGenerator,+ -- * Screenshots -- $screenshots @@ -167,7 +175,7 @@ -- -- You can then define @gsconfig3@ which may be used in exactly the same manner as @gsconfig1@: ----- > gsconfig3 = defaultGSConfig+-- > gsconfig3 = def -- > { gs_cellheight = 30 -- > , gs_cellwidth = 100 -- > , gs_navigate = myNavigation@@ -183,6 +191,11 @@ -- -- <<http://haskell.org/wikiupload/3/35/Xmonad-gridselect-window-aavogt.png>> +-- | The 'Default' instance gives a basic configuration for 'gridselect', with+-- the colorizer chosen based on the type.+--+-- If you want to replace the 'gs_colorizer' field, use 'buildDefaultGSConfig'+-- instead of 'def' to avoid ambiguous type variables. data GSConfig a = GSConfig { gs_cellheight :: Integer, gs_cellwidth :: Integer,@@ -190,6 +203,7 @@ gs_colorizer :: a -> Bool -> X (String, String), gs_font :: String, gs_navigate :: TwoD a (Maybe a),+ gs_rearranger :: Rearranger a, gs_originFractX :: Double, gs_originFractY :: Double }@@ -212,12 +226,12 @@ let getColor = if isFg then focusedBorderColor else normalBorderColor in asks $ flip (,) "black" . getColor . config --- | A basic configuration for 'gridselect', with the colorizer chosen based on the type.------ If you want to replace the 'gs_colorizer' field, use 'buildDefaultGSConfig'--- instead, to avoid ambiguous type variables.+instance HasColorizer a => Default (GSConfig a) where+ def = buildDefaultGSConfig defaultColorizer++{-# DEPRECATED defaultGSConfig "Use def (from Data.Default, and re-exported from XMonad.Actions.GridSelect) instead." #-} defaultGSConfig :: HasColorizer a => GSConfig a-defaultGSConfig = buildDefaultGSConfig defaultColorizer+defaultGSConfig = def type TwoDPosition = (Integer, Integer) @@ -232,13 +246,18 @@ , td_paneY :: Integer , td_drawingWin :: Window , td_searchString :: String+ , td_elementmap :: TwoDElementMap a } -td_elementmap :: TwoDState a -> [(TwoDPosition,(String,a))]-td_elementmap s = zipWith (,) positions sortedElements+generateElementmap :: TwoDState a -> X (TwoDElementMap a)+generateElementmap s = do+ rearrangedElements <- rearranger searchString sortedElements+ return $ zip positions rearrangedElements where TwoDState {td_availSlots = positions,+ td_gsconfig = gsconfig, td_searchString = searchString} = s+ GSConfig {gs_rearranger = rearranger} = gsconfig -- Filter out any elements that don't contain the searchString (case insensitive) filteredElements = L.filter ((searchString `isInfixOfI`) . fst) (td_elements s) -- Sorts the elementmap@@ -331,11 +350,11 @@ s <- get updateElements (td_elementmap s) -grayoutAllElements :: TwoD a ()-grayoutAllElements =+grayoutElements :: Int -> TwoD a ()+grayoutElements skip = do s <- get- updateElementsWithColorizer grayOnly (td_elementmap s)+ updateElementsWithColorizer grayOnly $ drop skip (td_elementmap s) where grayOnly _ _ = return ("#808080", "#808080") updateElements :: TwoDElementMap a -> TwoD a ()@@ -371,7 +390,7 @@ stdHandle (ButtonEvent { ev_event_type = t, ev_x = x, ev_y = y }) contEventloop | t == buttonRelease = do s @ TwoDState { td_paneX = px, td_paneY = py,- td_gsconfig = (GSConfig ch cw _ _ _ _ _ _) } <- get+ td_gsconfig = (GSConfig ch cw _ _ _ _ _ _ _) } <- get let gridX = (fi x - (px - cw) `div` 2) `div` cw gridY = (fi y - (py - ch) `div` 2) `div` ch case lookup (gridX,gridY) (td_elementmap s) of@@ -467,11 +486,17 @@ let oldSearchString = td_searchString s newSearchString = f oldSearchString when (newSearchString /= oldSearchString) $ do- -- FIXME: grayoutAllElements + updateAllElements paint some fields twice causing flickering- -- we would need a much smarter update strategy to fix that- when (length newSearchString > length oldSearchString) grayoutAllElements -- FIXME curpos might end up outside new bounds- put s { td_searchString = newSearchString }+ let s' = s { td_searchString = newSearchString }+ m <- liftX $ generateElementmap s'+ let s'' = s' { td_elementmap = m }+ oldLen = length $ td_elementmap s+ newLen = length $ td_elementmap s''+ -- All the elements in the previous element map should be+ -- grayed out, except for those which will be covered by+ -- elements in the new element map.+ when (newLen < oldLen) $ grayoutElements newLen+ put s'' updateAllElements -- | By default gridselect used the defaultNavigation action, which@@ -622,16 +647,16 @@ gridselect gsconfig elements = withDisplay $ \dpy -> do rootw <- asks theRoot- s <- gets $ screenRect . W.screenDetail . W.current . windowset+ scr <- gets $ screenRect . W.screenDetail . W.current . windowset win <- liftIO $ mkUnmanagedWindow dpy (defaultScreenOfDisplay dpy) rootw- (rect_x s) (rect_y s) (rect_width s) (rect_height s)+ (rect_x scr) (rect_y scr) (rect_width scr) (rect_height scr) liftIO $ mapWindow dpy win liftIO $ selectInput dpy win (exposureMask .|. keyPressMask .|. buttonReleaseMask) status <- io $ grabKeyboard dpy win True grabModeAsync grabModeAsync currentTime io $ grabButton dpy button1 anyModifier win True buttonReleaseMask grabModeAsync grabModeAsync none none font <- initXMF (gs_font gsconfig)- let screenWidth = toInteger $ rect_width s;- screenHeight = toInteger $ rect_height s;+ let screenWidth = toInteger $ rect_width scr+ screenHeight = toInteger $ rect_height scr selectedElement <- if (status == grabSuccess) then do let restriction ss cs = (fromInteger ss/fromInteger (cs gsconfig)-1)/2 :: Double restrictX = floor $ restriction screenWidth gs_cellwidth@@ -639,16 +664,19 @@ 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-- evalTwoD (updateAllElements >> (gs_navigate gsconfig)) TwoDState { td_curpos = (head coords),- td_availSlots = coords,- td_elements = elements,- td_gsconfig = gsconfig,- td_font = font,- td_paneX = screenWidth,- td_paneY = screenHeight,- td_drawingWin = win,- td_searchString = "" }+ s = TwoDState { td_curpos = (head coords),+ td_availSlots = coords,+ td_elements = elements,+ td_gsconfig = gsconfig,+ td_font = font,+ td_paneX = screenWidth,+ td_paneY = screenHeight,+ td_drawingWin = win,+ td_searchString = "",+ td_elementmap = [] }+ m <- generateElementmap s+ evalTwoD (updateAllElements >> (gs_navigate gsconfig))+ (s { td_elementmap = m }) else return Nothing liftIO $ do@@ -685,7 +713,7 @@ -- | Builds a default gs config from a colorizer function. buildDefaultGSConfig :: (a -> Bool -> X (String,String)) -> GSConfig a-buildDefaultGSConfig col = GSConfig 50 130 10 col "xft:Sans-8" defaultNavigation (1/2) (1/2)+buildDefaultGSConfig col = GSConfig 50 130 10 col "xft:Sans-8" defaultNavigation noRearranger (1/2) (1/2) borderColor :: String borderColor = "white"@@ -721,6 +749,44 @@ -- > gridselectWorkspace (\ws -> W.greedyView ws . W.shift ws) gridselectWorkspace :: GSConfig WorkspaceId -> (WorkspaceId -> WindowSet -> WindowSet) -> X ()-gridselectWorkspace conf viewFunc = withWindowSet $ \ws -> do+gridselectWorkspace conf viewFunc = gridselectWorkspace' conf (windows . viewFunc)++-- | Select a workspace and run an arbitrary action on it.+gridselectWorkspace' :: GSConfig WorkspaceId -> (WorkspaceId -> X ()) -> X ()+gridselectWorkspace' conf func = withWindowSet $ \ws -> do let wss = map W.tag $ W.hidden ws ++ map W.workspace (W.current ws : W.visible ws)- gridselect conf (zip wss wss) >>= flip whenJust (windows . viewFunc)+ gridselect conf (zip wss wss) >>= flip whenJust func++-- $rearrangers+--+-- Rearrangers allow for arbitrary post-filter rearranging of the grid+-- elements.+--+-- For example, to be able to switch to a new dynamic workspace by typing+-- in its name, you can use the following keybinding action:+--+-- > import XMonad.Actions.DynamicWorkspaces (addWorkspace)+-- >+-- > gridselectWorkspace' defaultGSConfig+-- > { gs_navigate = navNSearch+-- > , gs_rearranger = searchStringRearrangerGenerator id+-- > }+-- > addWorkspace++-- | A function taking the search string and a list of elements, and+-- returning a potentially rearranged list of elements.+type Rearranger a = String -> [(String, a)] -> X [(String, a)]++-- | A rearranger that leaves the elements unmodified.+noRearranger :: Rearranger a+noRearranger _ = return++-- | A generator for rearrangers that append a single element based on the+-- search string, if doing so would not be redundant (empty string or value+-- already present).+searchStringRearrangerGenerator :: (String -> a) -> Rearranger a+searchStringRearrangerGenerator f =+ let r "" xs = return $ xs+ r s xs | s `elem` map fst xs = return $ xs+ | otherwise = return $ xs ++ [(s, f s)]+ in r
@@ -73,7 +73,7 @@ matching a certain Boolean query. To do this, you need to add 'historyHook' to your logHook: -> main = xmonad $ defaultConfig { logHook = historyHook }+> main = xmonad $ def { logHook = historyHook } Then the following keybindings, for example, allow you to return to the most recent xterm or emacs window or to simply to the most recent
XMonad/Actions/Launcher.hs view
@@ -34,10 +34,10 @@ To test it, modify your local .xmonad: - > import XMonad.Prompt(defaultXPConfig)+ > import XMonad.Prompt(def) > import XMonad.Actions.Launcher - > ((modm .|. controlMask, xK_l), launcherPrompt defaultXPConfig $ defaultLauncherModes launcherConfig)+ > ((modm .|. controlMask, xK_l), launcherPrompt def $ defaultLauncherModes launcherConfig) A LauncherConfig contains settings for the default modes, modify them accordingly. @@ -45,7 +45,7 @@ Restart xmonad. Press Ctrl + Your_Modkey + L and the first prompt should pop up. - If you used 'defaultXPConfig', you can change mode with 'xK_grave'. If you are using your own 'XPConfig', define the value for 'changeModeKey'.+ If you used the default 'XPConfig', you can change mode with 'xK_grave'. If you are using your own 'XPConfig', define the value for 'changeModeKey'. -} data HoogleMode = HMode FilePath String --path to hoogle and browser
+ XMonad/Actions/LinkWorkspaces.hs view
@@ -0,0 +1,169 @@+-----------------------------------------------------------------------------+-- |+-- Module : XMonad.Actions.LinkWorkspaces+-- Copyright : (c) Jan-David Quesel <quesel@gmail.org>+-- License : BSD3-style (see LICENSE)+--+-- Maintainer : none+-- Stability : unstable+-- Portability : unportable+--+-- Provides bindings to add and delete links between workspaces. It is aimed+-- at providing useful links between workspaces in a multihead setup. Linked+-- workspaces are view at the same time.+--+-----------------------------------------------------------------------------++{-# LANGUAGE DeriveDataTypeable #-}+module XMonad.Actions.LinkWorkspaces (+ -- * Usage+ -- $usage+ switchWS,+ removeAllMatchings,+ unMatch,+ toggleLinkWorkspaces,+ defaultMessageConf,+ MessageConfig(..)+ ) where++import XMonad+import qualified XMonad.StackSet as W+import XMonad.Layout.IndependentScreens(countScreens)+import qualified XMonad.Util.ExtensibleState as XS (get, put)+import XMonad.Actions.OnScreen(Focus(FocusCurrent), onScreen')+import qualified Data.Map as M+ ( insert, delete, Map, lookup, empty, filter )++-- $usage+-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@ file:+--+-- > import XMonad.Actions.LinkWorkspaces+--+-- and add a function to print messages like+--+-- > message_command (S screen) = " dzen2 -p 1 -w 300 -xs " ++ show (screen + 1)+-- > message_color_func c1 c2 msg = dzenColor c1 c2 msg+-- > message screen c1 c2 msg = spawn $ "echo '" ++ (message_color_func c1 c2 msg) ++ "' | " ++ message_command screen+--+-- alternatively you can use the noMessages function as the argument+--+-- Then add keybindings like the following:+--+-- > ,((modm, xK_p), toggleLinkWorkspaces message)+-- > ,((modm .|. shiftMask, xK_p), removeAllMatchings message)+--+-- > [ ((modm .|. m, k), a i)+-- > | (a, m) <- [(switchWS (\y -> windows $ view y) message, 0),(switchWS (\x -> windows $ shift x . view x) message, shiftMask)]+-- > , (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".++data MessageConfig = MessageConfig { messageFunction :: (ScreenId -> [Char] -> [Char] -> [Char] -> X())+ , foreground :: [Char]+ , alertedForeground :: [Char]+ , background :: [Char]+ }++defaultMessageConf :: MessageConfig+defaultMessageConf = MessageConfig { messageFunction = noMessageFn+ , background = "#000000"+ , alertedForeground = "#ff7701"+ , foreground = "#00ff00" }++noMessageFn :: ScreenId -> [Char] -> [Char] -> [Char] -> X()+noMessageFn _ _ _ _ = return () :: X ()++-- | Stuff for linking workspaces+data WorkspaceMap = WorkspaceMap (M.Map WorkspaceId WorkspaceId) deriving (Read, Show, Typeable)+instance ExtensionClass WorkspaceMap + where initialValue = WorkspaceMap M.empty+ extensionType = PersistentExtension++switchWS :: (WorkspaceId -> X ()) -> MessageConfig -> WorkspaceId -> X ()+switchWS f m ws = switchWS' f m ws Nothing++-- | Switch to the given workspace in a non greedy way, stop if we reached the first screen+-- | we already did switching on+switchWS' :: (WorkspaceId -> X ()) -> MessageConfig -> WorkspaceId -> (Maybe ScreenId) -> X ()+switchWS' switchFn message workspace stopAtScreen = do+ ws <- gets windowset+ nScreens <- countScreens+ let now = W.screen (W.current ws)+ let next = ((now + 1) `mod` nScreens)+ switchFn workspace+ case stopAtScreen of+ Nothing -> sTM now next (Just now)+ Just sId -> if sId == next then return () else sTM now next (Just sId)+ where sTM = switchToMatching (switchWS' switchFn message) message workspace++-- | Switch to the workspace that matches the current one, executing switches for that workspace as well.+-- | The function switchWorkspaceNonGreedy' will take of stopping if we reached the first workspace again.+switchToMatching :: (WorkspaceId -> (Maybe ScreenId) -> X ()) -> MessageConfig -> WorkspaceId -> ScreenId + -> ScreenId -> (Maybe ScreenId) -> X ()+switchToMatching f message t now next stopAtScreen = do+ WorkspaceMap matchings <- XS.get :: X WorkspaceMap+ case (M.lookup t matchings) of+ Nothing -> return () :: X()+ Just newWorkspace -> do+ onScreen' (f newWorkspace stopAtScreen) FocusCurrent next + messageFunction message now (foreground message) (background message) ("Switching to: " ++ (t ++ " and " ++ newWorkspace))++-- | Insert a mapping between t1 and t2 or remove it was already present+toggleMatching :: MessageConfig -> WorkspaceId -> WorkspaceId -> X ()+toggleMatching message t1 t2 = do+ WorkspaceMap matchings <- XS.get :: X WorkspaceMap+ case (M.lookup t1 matchings) of+ Nothing -> setMatching message t1 t2 matchings+ Just t -> if t == t2 then removeMatching' message t1 t2 matchings else setMatching message t1 t2 matchings+ return ()++-- | Insert a mapping between t1 and t2 and display a message+setMatching :: MessageConfig -> WorkspaceId -> WorkspaceId -> M.Map WorkspaceId WorkspaceId -> X ()+setMatching message t1 t2 matchings = do+ ws <- gets windowset+ let now = W.screen (W.current ws)+ XS.put $ WorkspaceMap $ M.insert t1 t2 matchings+ messageFunction message now (foreground message) (background message) ("Linked: " ++ (t1 ++ " " ++ t2))++-- currently this function is called manually this means that if workspaces+-- were deleted, some links stay in the RAM even though they are not used+-- anymore... because of the small amount of memory used for those there is no+-- special cleanup so far+removeMatching' :: MessageConfig -> WorkspaceId -> WorkspaceId -> M.Map WorkspaceId WorkspaceId -> X ()+removeMatching' message t1 t2 matchings = do+ ws <- gets windowset+ let now = W.screen (W.current ws)+ XS.put $ WorkspaceMap $ M.delete t1 matchings+ messageFunction message now (alertedForeground message) (background message) ("Unlinked: " ++ t1 ++ " " ++ t2)++-- | Remove all maps between workspaces+removeAllMatchings :: MessageConfig -> X ()+removeAllMatchings message = do+ ws <- gets windowset+ let now = W.screen (W.current ws)+ XS.put $ WorkspaceMap $ M.empty+ messageFunction message now (alertedForeground message) (background message) "All links removed!"++-- | remove all matching regarding a given workspace+unMatch :: WorkspaceId -> X ()+unMatch workspace = do+ WorkspaceMap matchings <- XS.get :: X WorkspaceMap+ XS.put $ WorkspaceMap $ M.delete workspace (M.filter (/= workspace) matchings)++-- | Toggle the currently displayed workspaces as matching. Starting from the one with focus+-- | a linked list of workspaces is created that will later be iterated by switchToMatching.+toggleLinkWorkspaces :: MessageConfig -> X ()+toggleLinkWorkspaces message = withWindowSet $ \ws -> toggleLinkWorkspaces' (W.screen (W.current ws)) message++toggleLinkWorkspaces' :: ScreenId -> MessageConfig -> X ()+toggleLinkWorkspaces' first message = do+ ws <- gets windowset+ nScreens <- countScreens+ let now = W.screen (W.current ws)+ let next = (now + 1) `mod` nScreens+ if next == first then return () else do -- this is also the case if there is only one screen+ case (W.lookupWorkspace next ws) of+ Nothing -> return ()+ Just name -> toggleMatching message (W.currentTag ws) (name)+ onScreen' (toggleLinkWorkspaces' first message) FocusCurrent next
XMonad/Actions/MouseResize.hs view
@@ -43,11 +43,11 @@ -- -- Then edit your @layoutHook@ by modifying a given layout: ----- > myLayout = mouseResize $ windowArrange $ layoutHook defaultConfig+-- > myLayout = mouseResize $ windowArrange $ layoutHook def -- -- and then: ----- > main = xmonad defaultConfig { layoutHook = myLayout }+-- > main = xmonad def { layoutHook = myLayout } -- -- For more detailed instructions on editing the layoutHook see: --
@@ -32,8 +32,13 @@ -- * Exported functions and types -- #Exports# - withNavigation2DConfig+ navigation2D+ , navigation2DP+ , additionalNav2DKeys+ , additionalNav2DKeysP+ , withNavigation2DConfig , Navigation2DConfig(..)+ , def , defaultNavigation2DConfig , Navigation2D , lineNavigation@@ -56,6 +61,7 @@ import XMonad hiding (Screen) import qualified XMonad.StackSet as W import qualified XMonad.Util.ExtensibleState as XS+import XMonad.Util.EZConfig (additionalKeys, additionalKeysP) import XMonad.Util.Types -- $usage@@ -77,10 +83,46 @@ -- -- > import XMonad.Actions.Navigation2D ----- Then edit your keybindings:+-- Then add the configuration of the module to your main function: --+-- > main = xmonad $ navigation2D def+-- > (xK_Up, xK_Left, xK_Down, xK_Right)+-- > [(mod4Mask, windowGo ),+-- > (mod4Mask .|. shiftMask, windowSwap)]+-- > False+-- > $ def+--+-- Alternatively, you can use navigation2DP:+--+-- > main = xmonad $ navigation2D def+-- > ("<Up>", "<Left>", "<Down>", "<Right>")+-- > [("M-", windowGo ),+-- > ("M-S-", windowSwap)]+-- > False+-- > $ def+--+-- That's it. If instead you'd like more control, you can combine+-- withNavigation2DConfig and additionalNav2DKeys or additionalNav2DKeysP:+--+-- > main = xmonad $ withNavigation2DConfig def+-- > $ additionalNav2DKeys (xK_Up, xK_Left, xK_Down, xK_Right)+-- > [(mod4Mask, windowGo ),+-- > (mod4Mask .|. shiftMask, windowSwap)]+-- > False+-- > $ additionalNav2DKeys (xK_u, xK_l, xK_d, xK_r)+-- > [(mod4Mask, screenGo ),+-- > (mod4Mask .|. shiftMask, screenSwap)]+-- > False+-- > $ def+--+-- Or you can add the configuration of the module to your main function:+--+-- > main = xmonad $ withNavigation2DConfig def $ def+--+-- And specify your keybindings normally:+-- -- > -- Switch between layers--- > , ((modm, xK_space), switchLayers)+-- > , ((modm, xK_space), switchLayer) -- > -- > -- Directional navigation of windows -- > , ((modm, xK_Right), windowGo R False)@@ -112,11 +154,6 @@ -- > , ((modm .|. mod1Mask, xK_u ), windowToScreen U False) -- > , ((modm .|. mod1Mask, xK_d ), windowToScreen D False) ----- and add the configuration of the module to your main function:------ > main = xmonad $ withNavigation2DConfig defaultNavigation2DConfig--- > $ defaultConfig--- -- For detailed instruction on editing the key binding see: -- -- "XMonad.Doc.Extending#Editing_key_bindings".@@ -147,10 +184,10 @@ -- example, for the Full layout, is to switch to center navigation for the Full -- layout: ----- > myNavigation2DConfig = defaultNavigation2DConfig { layoutNavigation = [("Full", centerNavigation)] }+-- > myNavigation2DConfig = def { layoutNavigation = [("Full", centerNavigation)] } -- > -- > main = xmonad $ withNavigation2DConfig myNavigation2DConfig--- > $ defaultConfig+-- > $ def -- -- The navigation between windows is based on their screen rectangles, which are -- available /and meaningful/ only for mapped windows. Thus, as already said,@@ -164,12 +201,12 @@ -- on top of each other so that only the frontmost one is visible. This can be -- done as follows: ----- > myNavigation2DConfig = defaultNavigation2DConfig { layoutNavigation = [("Full", centerNavigation)]--- > , unmappedWindowRect = [("Full", singleWindowRect)]--- > }+-- > myNavigation2DConfig = def { layoutNavigation = [("Full", centerNavigation)]+-- > , unmappedWindowRect = [("Full", singleWindowRect)]+-- > } -- > -- > main = xmonad $ withNavigation2DConfig myNavigation2DConfig--- > $ defaultConfig+-- > $ def -- -- With this setup, Left/Up navigation behaves like standard -- 'XMonad.StackSet.focusUp' and Right/Down navigation behaves like@@ -279,7 +316,10 @@ centerNavigation :: Navigation2D centerNavigation = N 2 doCenterNavigation --- | Stores the configuration of directional navigation+-- | 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+-- or rectangles for unmapped windows are defined for individual layouts. data Navigation2DConfig = Navigation2DConfig { defaultTiledNavigation :: Navigation2D -- ^ default navigation strategy for the tiled layer , floatNavigation :: Navigation2D -- ^ navigation strategy for the float layer@@ -303,9 +343,59 @@ -- | Shorthand for the tedious screen type type Screen = W.Screen WorkspaceId (Layout Window) Window ScreenId ScreenDetail +-- | Convenience function for enabling Navigation2D with typical keybindings.+-- Takes a Navigation2DConfig, an (up, left, down, right) tuple, a mapping from+-- modifier key to action, and a bool to indicate if wrapping should occur, and+-- returns a function from XConfig to XConfig.+-- Example:+--+-- > navigation2D def (xK_w, xK_a, xK_s, xK_d) [(mod4Mask, windowGo), (mod4Mask .|. shiftMask, windowSwap)] False myConfig+navigation2D :: Navigation2DConfig -> (KeySym, KeySym, KeySym, KeySym) -> [(ButtonMask, Direction2D -> Bool -> X ())] ->+ Bool -> XConfig l -> XConfig l+navigation2D navConfig (u, l, d, r) modifiers wrap xconfig =+ additionalNav2DKeys (u, l, d, r) modifiers wrap $+ withNavigation2DConfig navConfig xconfig++-- | Convenience function for enabling Navigation2D with typical keybindings,+-- using the syntax defined in 'XMonad.Util.EZConfig.mkKeymap'. Takes a+-- Navigation2DConfig, an (up, left, down, right) tuple, a mapping from key+-- prefix to action, and a bool to indicate if wrapping should occur, and+-- returns a function from XConfig to XConfig. Example:+--+-- > navigation2DP def ("w", "a", "s", "d") [("M-", windowGo), ("M-S-", windowSwap)] False myConfig+navigation2DP :: Navigation2DConfig -> (String, String, String, String) -> [(String, Direction2D -> Bool -> X ())] ->+ Bool -> XConfig l -> XConfig l+navigation2DP navConfig (u, l, d, r) modifiers wrap xconfig =+ additionalNav2DKeysP (u, l, d, r) modifiers wrap $+ withNavigation2DConfig navConfig xconfig++-- | Convenience function for adding keybindings. Takes an (up, left, down,+-- right) tuple, a mapping from key prefix to action, and a bool to indicate if+-- wrapping should occur, and returns a function from XConfig to XConfig.+-- Example:+--+-- > additionalNav2DKeys (xK_w, xK_a, xK_s, xK_d) [(mod4Mask, windowGo), (mod4Mask .|. shiftMask, windowSwap)] False myConfig+additionalNav2DKeys :: (KeySym, KeySym, KeySym, KeySym) -> [(ButtonMask, Direction2D -> Bool -> X ())] ->+ Bool -> XConfig l -> XConfig l+additionalNav2DKeys (u, l, d, r) modifiers wrap =+ flip additionalKeys [((modif, k), func dir wrap) | (modif, func) <- modifiers, (k, dir) <- dirKeys]+ where dirKeys = [(u, U), (l, L), (d, D), (r, R)]++-- | Convenience function for adding keybindings, using the syntax defined in+-- 'XMonad.Util.EZConfig.mkKeymap'. Takes an (up, left, down, right) tuple, a+-- mapping from key prefix to action, and a bool to indicate if wrapping should+-- occur, and returns a function from XConfig to XConfig. Example:+--+-- > additionalNav2DKeysP def ("w", "a", "s", "d") [("M-", windowGo), ("M-S-", windowSwap)] False myConfig+additionalNav2DKeysP :: (String, String, String, String) -> [(String, Direction2D -> Bool -> X ())] ->+ Bool -> XConfig l -> XConfig l+additionalNav2DKeysP (u, l, d, r) modifiers wrap =+ flip additionalKeysP [(modif ++ k, func dir wrap) | (modif, func) <- modifiers, (k, dir) <- dirKeys]+ where dirKeys = [(u, U), (l, L), (d, D), (r, R)]+ -- So we can store the configuration in extensible state instance ExtensionClass Navigation2DConfig where- initialValue = defaultNavigation2DConfig+ initialValue = def -- | Modifies the xmonad configuration to store the Navigation2D configuration withNavigation2DConfig :: Navigation2DConfig -> XConfig a -> XConfig a@@ -313,12 +403,12 @@ >> XS.put conf2d } --- | Default navigation configuration. It uses line navigation for the tiled--- layer and for navigation between screens, and center navigation for the float--- layer. No custom navigation strategies or rectangles for unmapped windows are--- defined for individual layouts.+{-# DEPRECATED defaultNavigation2DConfig "Use def (from Data.Default, and re-exported from XMonad.Actions.Navigation2D) instead." #-} defaultNavigation2DConfig :: Navigation2DConfig-defaultNavigation2DConfig = Navigation2DConfig { defaultTiledNavigation = lineNavigation+defaultNavigation2DConfig = def++instance Default Navigation2DConfig where+ def = Navigation2DConfig { defaultTiledNavigation = lineNavigation , floatNavigation = centerNavigation , screenNavigation = lineNavigation , layoutNavigation = []
XMonad/Actions/Plane.hs view
@@ -51,12 +51,13 @@ -- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@ file: -- -- > import XMonad.Actions.Plane+-- > import Data.Map (union) -- >--- > main = xmonad defaultConfig {keys = myKeys}+-- > main = xmonad def {keys = myKeys} -- >--- > myKeys conf = union (keys defaultConfig conf) $ myNewKeys conf+-- > myKeys conf = union (keys def conf) $ myNewKeys conf -- >--- > myNewkeys (XConfig {modMask = modm}) = planeKeys modm (Lines 3) Finite+-- > myNewKeys (XConfig {modMask = modm}) = planeKeys modm (Lines 3) Finite -- -- For detailed instructions on editing your key bindings, see -- "XMonad.Doc.Extending#Editing_key_bindings".
XMonad/Actions/Search.hs view
@@ -46,11 +46,14 @@ mathworld, openstreetmap, scholar,+ stackage, thesaurus, wayback, wikipedia, wiktionary, youtube,+ vocabulary,+ duckduckgo, multi, -- * Use case: searching with a submap -- $tip@@ -59,15 +62,17 @@ Browser, Site, Query, Name, Search ) where -import Codec.Binary.UTF8.String (encode)-import Data.Char (isAlphaNum, isAscii)-import Data.List (isPrefixOf)-import Text.Printf-import XMonad (X(), MonadIO, liftIO)-import XMonad.Prompt (XPrompt(showXPrompt, nextCompletion, commandToComplete), mkXPrompt, XPConfig(), historyCompletionP, getNextCompletion)-import XMonad.Prompt.Shell (getBrowser)-import XMonad.Util.Run (safeSpawn)-import XMonad.Util.XSelection (getSelection)+import Codec.Binary.UTF8.String (encode)+import Data.Char (isAlphaNum, isAscii)+import Data.List (isPrefixOf)+import Text.Printf+import XMonad (X (), liftIO)+import XMonad.Prompt (XPConfig (), XPrompt (showXPrompt, nextCompletion, commandToComplete),+ getNextCompletion,+ historyCompletionP, mkXPrompt)+import XMonad.Prompt.Shell (getBrowser)+import XMonad.Util.Run (safeSpawn)+import XMonad.Util.XSelection (getSelection) {- $usage@@ -114,6 +119,8 @@ * 'hoogle' -- Hoogle, the Haskell libraries API search engine. +* 'stackage' -- Stackage, An alternative Haskell libraries API search engine.+ * 'images' -- Google images. * 'imdb' -- the Internet Movie Database.@@ -138,6 +145,10 @@ * 'youtube' -- Youtube video search. +* 'vocabulary' -- Dictionary search++* 'duckduckgo' -- DuckDuckGo search engine.+ * 'multi' -- Search based on the prefix. \"amazon:Potter\" will use amazon, etc. With no prefix searches google. Feel free to add more! -}@@ -157,7 +168,7 @@ > ... > -- Search commands-> , ((modm, xK_s), SM.submap $ searchEngineMap $ S.promptSearch P.defaultXPConfig)+> , ((modm, xK_s), SM.submap $ searchEngineMap $ S.promptSearch P.def) > , ((modm .|. shiftMask, xK_s), SM.submap $ searchEngineMap $ S.selectSearch) > > ...@@ -173,7 +184,7 @@ > ... > ] -- end of regular keybindings > -- Search commands-> ++ [("M-s " ++ k, S.promptSearch P.defaultXPConfig f) | (k,f) <- searchList ]+> ++ [("M-s " ++ k, S.promptSearch P.def f) | (k,f) <- searchList ] > ++ [("M-S-s " ++ k, S.selectSearch f) | (k,f) <- searchList ] > > ...@@ -271,8 +282,8 @@ -- The engines. amazon, alpha, codesearch, deb, debbts, debpts, dictionary, google, hackage, hoogle,- images, imdb, isohunt, lucky, maps, mathworld, openstreetmap, scholar, thesaurus, wayback, wikipedia, wiktionary,- youtube :: SearchEngine+ images, imdb, isohunt, lucky, maps, mathworld, openstreetmap, scholar, stackage, thesaurus, vocabulary, wayback, wikipedia, wiktionary,+ youtube, duckduckgo :: SearchEngine amazon = searchEngine "amazon" "http://www.amazon.com/exec/obidos/external-search?index=all&keyword=" alpha = searchEngine "alpha" "http://www.wolframalpha.com/input/?i=" codesearch = searchEngine "codesearch" "http://www.google.com/codesearch?q="@@ -291,14 +302,17 @@ mathworld = searchEngine "mathworld" "http://mathworld.wolfram.com/search/?query=" openstreetmap = searchEngine "openstreetmap" "http://gazetteer.openstreetmap.org/namefinder/?find=" scholar = searchEngine "scholar" "http://scholar.google.com/scholar?q="+stackage = searchEngine "stackage" "www.stackage.org/lts/hoogle?q=" thesaurus = searchEngine "thesaurus" "http://thesaurus.reference.com/search?q=" wikipedia = searchEngine "wiki" "http://en.wikipedia.org/wiki/Special:Search?go=Go&search=" wiktionary = searchEngine "wikt" "http://en.wiktionary.org/wiki/Special:Search?go=Go&search=" youtube = searchEngine "youtube" "http://www.youtube.com/results?search_type=search_videos&search_query=" wayback = searchEngineF "wayback" ("http://web.archive.org/web/*/"++)+vocabulary = searchEngine "vocabulary" "http://www.vocabulary.com/search?q="+duckduckgo = searchEngine "duckduckgo" "https://duckduckgo.com/?t=lm&q=" multi :: SearchEngine-multi = namedEngine "multi" $ foldr1 (!>) [amazon, alpha, codesearch, deb, debbts, debpts, dictionary, google, hackage, hoogle, images, imdb, isohunt, lucky, maps, mathworld, openstreetmap, scholar, thesaurus, wayback, wikipedia, wiktionary, (prefixAware google)]+multi = namedEngine "multi" $ foldr1 (!>) [amazon, alpha, codesearch, deb, debbts, debpts, dictionary, google, hackage, hoogle, images, imdb, isohunt, lucky, maps, mathworld, openstreetmap, scholar, thesaurus, wayback, wikipedia, wiktionary, duckduckgo, (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
@@ -16,7 +16,8 @@ module XMonad.Actions.ShowText ( -- * Usage -- $usage- defaultSTConfig+ def+ , defaultSTConfig , handleTimerEvent , flashText , ShowTextConfig(..)@@ -52,7 +53,7 @@ -- -- You can then use flashText in your keybindings: ----- > ((modMask, xK_Right), flashText defaultSTConfig 1 "->" >> nextWS)+-- > ((modMask, xK_Right), flashText def 1 "->" >> nextWS) -- -- | ShowText contains the map with timers as keys and created windows as values@@ -72,12 +73,16 @@ , st_fg :: String -- ^ Foreground color } -defaultSTConfig :: ShowTextConfig-defaultSTConfig =+instance Default ShowTextConfig where+ def = STC { st_font = "-misc-fixed-*-*-*-*-20-*-*-*-*-*-*-*" , st_bg = "black" , st_fg = "white" }++{-# DEPRECATED defaultSTConfig "Use def (from Data.Default, and re-exported by XMonad.Actions.ShowText) instead." #-}+defaultSTConfig :: ShowTextConfig+defaultSTConfig = def -- | Handles timer events that notify when a window should be removed handleTimerEvent :: Event -> X All
XMonad/Actions/SpawnOn.hs view
@@ -20,6 +20,7 @@ -- $usage Spawner, manageSpawn,+ manageSpawnWithGC, spawnHere, spawnOn, spawnAndDo,@@ -44,16 +45,16 @@ -- > import XMonad.Actions.SpawnOn -- -- > main = do--- > xmonad defaultConfig {+-- > xmonad def { -- > ...--- > manageHook = manageSpawn <+> manageHook defaultConfig+-- > manageHook = manageSpawn <+> manageHook def -- > ... -- > } -- -- To ensure that application appears on a workspace it was launched at, add keybindings like: -- -- > , ((mod1Mask,xK_o), spawnHere "urxvt")--- > , ((mod1Mask,xK_s), shellPromptHere defaultXPConfig)+-- > , ((mod1Mask,xK_s), shellPromptHere def) -- -- The module can also be used to apply other manage hooks to the window of -- the spawned application(e.g. float or resize it).@@ -66,8 +67,6 @@ instance ExtensionClass Spawner where initialValue = Spawner [] -maxPids :: Int-maxPids = 5 -- | Get the current Spawner or create one if it doesn't exist. modifySpawner :: ([(ProcessID, ManageHook)] -> [(ProcessID, ManageHook)]) -> X ()@@ -76,20 +75,26 @@ -- | Provides a manage hook to react on process spawned with -- 'spawnOn', 'spawnHere' etc. manageSpawn :: ManageHook-manageSpawn = do+manageSpawn = manageSpawnWithGC (return . take 20)++manageSpawnWithGC :: ([(ProcessID, ManageHook)] -> X [(ProcessID, ManageHook)])+ -- ^ function to stop accumulation of entries for windows that never set @_NET_WM_PID@+ -> ManageHook+manageSpawnWithGC garbageCollect = do Spawner pids <- liftX XS.get mp <- pid case flip lookup pids =<< mp of Nothing -> idHook Just mh -> do- whenJust mp $ \p ->- liftX . modifySpawner $ filter ((/= p) . fst)+ whenJust mp $ \p -> liftX $ do+ ps <- XS.gets pidsRef+ XS.put . Spawner =<< garbageCollect (filter ((/= p) . fst) ps) mh mkPrompt :: (String -> X ()) -> XPConfig -> X () mkPrompt cb c = do cmds <- io $ getCommands- mkXPrompt Shell c (getShellCompl cmds) cb+ mkXPrompt Shell c (getShellCompl cmds $ searchPredicate c) cb -- | Replacement for Shell prompt ("XMonad.Prompt.Shell") which launches -- application on current workspace.@@ -115,7 +120,7 @@ spawnAndDo :: ManageHook -> String -> X () spawnAndDo mh cmd = do p <- spawnPID $ mangle cmd- modifySpawner $ (take maxPids . ((p,mh) :))+ modifySpawner $ ((p,mh) :) where -- TODO this is silly, search for a better solution mangle xs | any (`elem` metaChars) xs || "exec" `isInfixOf` xs = xs
XMonad/Actions/Submap.hs view
@@ -62,7 +62,7 @@ -- | Like 'submap', but executes a default action if the key did not match. submapDefault :: X () -> M.Map (KeyMask, KeySym) (X ()) -> X ()-submapDefault def keys = do+submapDefault defAction keys = do XConf { theRoot = root, display = d } <- ask io $ grabKeyboard d root False grabModeAsync grabModeAsync currentTime@@ -79,4 +79,4 @@ io $ ungrabKeyboard d currentTime - maybe def id (M.lookup (m', s) keys)+ maybe defAction id (M.lookup (m', s) keys)
XMonad/Actions/TagWindows.hs view
@@ -53,12 +53,12 @@ -- > , ((modm, xK_d ), withTaggedP "abc" (W.shiftWin "2")) -- > , ((modm .|. shiftMask, xK_d ), withTaggedGlobalP "abc" shiftHere) -- > , ((modm .|. controlMask, xK_d ), focusUpTaggedGlobal "abc")--- > , ((modm, xK_g ), tagPrompt defaultXPConfig (\s -> withFocused (addTag s)))--- > , ((modm .|. controlMask, xK_g ), tagDelPrompt defaultXPConfig)--- > , ((modm .|. shiftMask, xK_g ), tagPrompt defaultXPConfig (\s -> withTaggedGlobal s float))--- > , ((modWinMask, xK_g ), tagPrompt defaultXPConfig (\s -> withTaggedP s (W.shiftWin "2")))--- > , ((modWinMask .|. shiftMask, xK_g ), tagPrompt defaultXPConfig (\s -> withTaggedGlobalP s shiftHere))--- > , ((modWinMask .|. controlMask, xK_g ), tagPrompt defaultXPConfig (\s -> focusUpTaggedGlobal s))+-- > , ((modm, xK_g ), tagPrompt def (\s -> withFocused (addTag s)))+-- > , ((modm .|. controlMask, xK_g ), tagDelPrompt def)+-- > , ((modm .|. shiftMask, xK_g ), tagPrompt def (\s -> withTaggedGlobal s float))+-- > , ((modWinMask, xK_g ), tagPrompt def (\s -> withTaggedP s (W.shiftWin "2")))+-- > , ((modWinMask .|. shiftMask, xK_g ), tagPrompt def (\s -> withTaggedGlobalP s shiftHere))+-- > , ((modWinMask .|. controlMask, xK_g ), tagPrompt def (\s -> focusUpTaggedGlobal s)) -- -- NOTE: Tags are saved as space separated strings and split with -- 'unwords'. Thus if you add a tag \"a b\" the window will have
XMonad/Actions/TopicSpace.hs view
@@ -22,6 +22,7 @@ Topic , Dir , TopicConfig(..)+ , def , defaultTopicConfig , getLastFocusedTopics , setLastFocusedTopic@@ -89,7 +90,7 @@ -- > ] -- > -- > myTopicConfig :: TopicConfig--- > myTopicConfig = defaultTopicConfig+-- > myTopicConfig = def -- > { topicDirs = M.fromList $ -- > [ ("conf", "w/conf") -- > , ("dashboard", "Desktop")@@ -161,7 +162,7 @@ -- > myConfig = do -- > checkTopicConfig myTopics myTopicConfig -- > myLogHook <- makeMyLogHook--- > return $ defaultConfig+-- > return $ def -- > { borderWidth = 1 -- Width of the window border in pixels. -- > , workspaces = myTopics -- > , layoutHook = myModifiers myLayout@@ -206,13 +207,17 @@ -- numeric keypad. } -defaultTopicConfig :: TopicConfig-defaultTopicConfig = TopicConfig { topicDirs = M.empty+instance Default TopicConfig where+ def = TopicConfig { topicDirs = M.empty , topicActions = M.empty , defaultTopicAction = const (ask >>= spawn . terminal . config) , defaultTopic = "1" , maxTopicHistory = 10 }++{-# DEPRECATED defaultTopicConfig "Use def (from Data.Default, and re-exported by XMonad.Actions.TopicSpace) instead." #-}+defaultTopicConfig :: TopicConfig+defaultTopicConfig = def newtype PrevTopics = PrevTopics { getPrevTopics :: [String] } deriving (Read,Show,Typeable) instance ExtensionClass PrevTopics where
XMonad/Actions/UpdateFocus.hs view
@@ -29,7 +29,7 @@ -- following to your @~\/.xmonad\/xmonad.hs@: -- -- > import XMonad.Actions.UpdateFocus--- > xmonad $ defaultConfig {+-- > xmonad $ def { -- > .. -- > startupHook = adjustEventInput -- > handleEventHook = focusOnMouseMove
XMonad/Actions/UpdatePointer.hs view
@@ -19,12 +19,12 @@ -- * Usage -- $usage updatePointer- , PointerPosition (..) ) where import XMonad import XMonad.Util.XUtils (fi)+import Control.Arrow import Control.Monad import XMonad.StackSet (member, peek, screenDetail, current) import Data.Maybe@@ -35,31 +35,32 @@ -- > import XMonad -- > import XMonad.Actions.UpdatePointer ----- Enable it by including it in your logHook definition. Eg:------ > logHook = updatePointer Nearest+-- Enable it by including it in your logHook definition, e.g.: ----- which will move the pointer to the nearest point of a newly focused window, or+-- > logHook = updatePointer (0.5, 0.5) (1, 1) ----- > logHook = updatePointer (Relative 0.5 0.5)+-- which will move the pointer to the nearest point of a newly focused+-- window. The first argument establishes a reference point within the+-- newly-focused window, while the second argument linearly interpolates+-- between said reference point and the edges of the newly-focused window to+-- obtain a bounding box for the pointer. ----- which will move the pointer to the center of a newly focused window.+-- > logHook = updatePointer (0.5, 0.5) (0, 0) -- exact centre of window+-- > logHook = updatePointer (0.25, 0.25) (0.25, 0.25) -- near the top-left+-- > logHook = updatePointer (0.5, 0.5) (1.1, 1.1) -- within 110% of the edge -- -- To use this with an existing logHook, use >> : -- -- > logHook = dynamicLog--- > >> updatePointer (Relative 1 1)+-- > >> updatePointer (1, 1) (0, 0) -- -- which moves the pointer to the bottom-right corner of the focused window. -data PointerPosition = Nearest | Relative Rational Rational | TowardsCentre Rational Rational- deriving (Read,Show)- -- | Update the pointer's location to the currently focused -- window or empty screen unless it's already there, or unless the user was changing -- focus with the mouse-updatePointer :: PointerPosition -> X ()-updatePointer p = do+updatePointer :: (Rational, Rational) -> (Rational, Rational) -> X ()+updatePointer refPos ratio = do ws <- gets windowset dpy <- asks display rect <- case peek ws of@@ -67,39 +68,37 @@ Just w -> windowAttributesToRectangle `fmap` io (getWindowAttributes dpy w) root <- asks theRoot mouseIsMoving <- asks mouseFocused- (_sameRoot,_,currentWindow,rootx,rooty,_,_,_) <- io $ queryPointer dpy root+ (_sameRoot,_,currentWindow,rootX,rootY,_,_,_) <- io $ queryPointer dpy root drag <- gets dragging- unless (pointWithin (fi rootx) (fi rooty) rect+ unless (pointWithin (fi rootX) (fi rootY) rect || mouseIsMoving || isJust drag- || not (currentWindow `member` ws || currentWindow == none)) $- case p of- Nearest -> do- let x = moveWithin (fi rootx) (rect_x rect) (fi (rect_x rect) + fi (rect_width rect))- y = moveWithin (fi rooty) (rect_y rect) (fi (rect_y rect) + fi (rect_height rect))- io $ warpPointer dpy none root 0 0 0 0 x y- TowardsCentre xfrc yfrc -> do- let cx = fi (rect_width rect) / 2 + fi (rect_x rect)- cy = fi (rect_height rect) / 2 + fi (rect_y rect)- x,y,cx,cy :: Rational- x = moveWithin (fi rootx) (fi $ rect_x rect) (fi (rect_x rect) + fi (rect_width rect))- y = moveWithin (fi rooty) (fi $ rect_y rect) (fi (rect_y rect) + fi (rect_height rect))- io $ warpPointer dpy none root 0 0 0 0 (round $ x + xfrc*(cx-x)) (round $ y + yfrc*(cy-y))- Relative h v ->- io $ warpPointer dpy none root 0 0 0 0- (rect_x rect + fraction h (rect_width rect))- (rect_y rect + fraction v (rect_height rect))- where fraction x y = floor (x * fromIntegral y)+ || not (currentWindow `member` ws || currentWindow == none)) $ let+ -- focused rectangle+ (rectX, rectY) = (rect_x &&& rect_y) rect+ (rectW, rectH) = (fi . rect_width &&& fi . rect_height) rect+ -- reference position, with (0,0) and (1,1) being top-left and bottom-right+ refX = lerp (fst refPos) rectX (rectX + rectW)+ refY = lerp (snd refPos) rectY (rectY + rectH)+ -- final pointer bounds, lerped *outwards* from reference position+ boundsX = join (***) (lerp (fst ratio) refX) (rectX, rectX + rectW)+ boundsY = join (***) (lerp (snd ratio) refY) (rectY, rectY + rectH)+ -- ideally we ought to move the pointer in a straight line towards the+ -- reference point until it is within the above bounds, but…+ in io $ warpPointer dpy none root 0 0 0 0+ (round . clip boundsX $ fi rootX)+ (round . clip boundsY $ fi rootY) windowAttributesToRectangle :: WindowAttributes -> Rectangle windowAttributesToRectangle wa = Rectangle (fi (wa_x wa)) (fi (wa_y wa)) (fi (wa_width wa + 2 * wa_border_width wa)) (fi (wa_height wa + 2 * wa_border_width wa))-moveWithin :: Ord a => a -> a -> a -> a-moveWithin now lower upper =- if now < lower- then lower- else if now > upper- then upper- else now++lerp :: (RealFrac r, Real a, Real b) => r -> a -> b -> r+lerp r a b = (1 - r) * realToFrac a + r * realToFrac b++clip :: Ord a => (a, a) -> a -> a+clip (lower, upper) x = if x < lower then lower+ else if x > upper then upper else x+
@@ -62,7 +62,7 @@ -- -- > main = do -- > config <- withWindowNavigation (xK_w, xK_a, xK_s, xK_d)--- > $ defaultConfig { ... }+-- > $ def { ... } -- > xmonad config -- -- Here, we pass in the keys for navigation in counter-clockwise order from up.
XMonad/Actions/WorkspaceCursors.hs view
@@ -69,8 +69,8 @@ -- > x <- xmobar conf -- > xmonad x -- >--- > conf = additionalKeysP defaultConfig--- > { layoutHook = workspaceCursors myCursors $ layoutHook defaultConfig+-- > conf = additionalKeysP def+-- > { layoutHook = workspaceCursors myCursors $ layoutHook def -- > , workspaces = toList myCursors } $ -- > [("M-"++shift++control++[k], f direction depth) -- > | (f,shift) <- zip [modifyLayer,shiftModifyLayer] ["","S-"]
XMonad/Actions/WorkspaceNames.hs view
@@ -32,6 +32,9 @@ swapTo, swapTo', swapWithCurrent,++ -- * Workspace prompt+ workspaceNamePrompt ) where import XMonad@@ -47,6 +50,7 @@ import qualified Data.Map as M import Data.Maybe (fromMaybe)+import Data.List (isInfixOf) -- $usage -- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@ file:@@ -55,7 +59,7 @@ -- -- Then add keybindings like the following: ----- > , ((modm .|. shiftMask, xK_r ), renameWorkspace defaultXPConfig)+-- > , ((modm .|. shiftMask, xK_r ), renameWorkspace def) -- -- and apply workspaceNamesPP to your DynamicLog pretty-printer: --@@ -150,3 +154,18 @@ let getname w = fromMaybe "" $ M.lookup w m set w name m' = if null name then M.delete w m' else M.insert w name m' XS.put $ WorkspaceNames $ set w1 (getname w2) $ set w2 (getname w1) $ m++-- | Same behavior than 'XMonad.Prompt.Workspace.workspacePrompt' excepted it acts on the workspace name provided by this module.+workspaceNamePrompt :: XPConfig -> (String -> X ()) -> X ()+workspaceNamePrompt conf job = do+ myWorkspaces <- gets $ map W.tag . W.workspaces . windowset+ myWorkspacesName <- getWorkspaceNames >>= \f -> return $ map f myWorkspaces+ let pairs = zip myWorkspacesName myWorkspaces+ mkXPrompt (Wor "Select workspace: ") conf+ (contains myWorkspacesName)+ (job . toWsId pairs)+ where toWsId pairs name = case lookup name pairs of+ Nothing -> ""+ Just i -> i+ contains completions input =+ return $ filter (Data.List.isInfixOf input) completions
XMonad/Config/Arossato.hs view
@@ -36,7 +36,6 @@ import XMonad.Layout.SimpleFloat import XMonad.Layout.Tabbed import XMonad.Layout.WindowArranger-import XMonad.Prompt import XMonad.Prompt.Shell import XMonad.Prompt.Ssh import XMonad.Prompt.Theme@@ -86,7 +85,7 @@ arossatoConfig = do xmobar <- spawnPipe "xmobar" -- REMOVE this line if you do not have xmobar installed!- return $ defaultConfig+ return $ def { workspaces = ["home","var","dev","mail","web","doc"] ++ map show [7 .. 9 :: Int] , logHook = myDynLog xmobar -- REMOVE this line if you do not have xmobar installed!@@ -120,7 +119,7 @@ newManageHook = myManageHook -- xmobar- myDynLog h = dynamicLogWithPP defaultPP+ myDynLog h = dynamicLogWithPP def { ppCurrent = xmobarColor "yellow" "" . wrap "[" "]" , ppTitle = xmobarColor "green" "" . shorten 40 , ppVisible = wrap "(" ")"@@ -128,7 +127,7 @@ } -- key bindings stuff- defKeys = keys defaultConfig+ 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@@ -144,12 +143,12 @@ [(shiftMask .|. modMask x, k) | k <- [xK_1 .. xK_9]] -- These are my personal key bindings toAdd x =- [ ((modMask x , xK_F12 ), xmonadPrompt defaultXPConfig )- , ((modMask x , xK_F3 ), shellPrompt defaultXPConfig )- , ((modMask x , xK_F4 ), sshPrompt defaultXPConfig )- , ((modMask x , xK_F5 ), themePrompt defaultXPConfig )- , ((modMask x , xK_F6 ), windowPromptGoto defaultXPConfig )- , ((modMask x , xK_F7 ), windowPromptBring defaultXPConfig )+ [ ((modMask x , xK_F12 ), xmonadPrompt def )+ , ((modMask x , xK_F3 ), shellPrompt def )+ , ((modMask x , xK_F4 ), sshPrompt def )+ , ((modMask x , xK_F5 ), themePrompt def )+ , ((modMask x , xK_F6 ), windowPromptGoto def )+ , ((modMask x , xK_F7 ), windowPromptBring def ) , ((modMask x , xK_comma ), prevWS ) , ((modMask x , xK_period), nextWS ) , ((modMask x , xK_Right ), windows W.focusDown )
XMonad/Config/Azerty.hs view
@@ -38,7 +38,7 @@ -- > import qualified Data.Map as M -- > main = xmonad someConfig { keys = \c -> azertyKeys c `M.union` keys someConfig c } -azertyConfig = defaultConfig { keys = azertyKeys <+> keys defaultConfig }+azertyConfig = def { keys = azertyKeys <+> keys def } azertyKeys conf@(XConfig {modMask = modm}) = M.fromList $ [((modm, xK_semicolon), sendMessage (IncMasterN (-1)))]
+ XMonad/Config/Bepo.hs view
@@ -0,0 +1,47 @@+{-# OPTIONS_GHC -fno-warn-missing-signatures #-}++-----------------------------------------------------------------------------+-- |+-- Module : XMonad.Config.Bepo+-- Copyright : (c) Yorick Laupa <yo.eight@gmail.com>+-- License : BSD+--+-- Maintainer : Yorick Laupa <yo.eight@gmail.com>+-- Stability : stable+-- Portability : unportable+--+-- This module fixes some of the keybindings for the francophone among you who+-- use a BEPO keyboard layout. Based on XMonad.Config.Azerty++module XMonad.Config.Bepo (+ -- * Usage+ -- $usage+ bepoConfig, bepoKeys+ ) where++import XMonad+import qualified XMonad.StackSet as W++import qualified Data.Map as M++-- $usage+-- To use this module, start with the following @~\/.xmonad\/xmonad.hs@:+--+-- > import XMonad+-- > import XMonad.Config.Bepo+-- >+-- > main = xmonad bepoConfig+--+-- If you prefer, an bepoKeys function is provided which you can use as so:+--+-- > import qualified Data.Map as M+-- > main = xmonad someConfig { keys = \c -> bepoKeys c `M.union` keys someConfig c }++bepoConfig = def { keys = bepoKeys <+> keys def }++bepoKeys conf@(XConfig { modMask = modm }) = M.fromList $+ [((modm, xK_semicolon), sendMessage (IncMasterN (-1)))]+ +++ [((m .|. modm, k), windows $ f i)+ | (i, k) <- zip (workspaces conf) [0x22,0xab,0xbb,0x28,0x29,0x40,0x2b,0x2d,0x2f,0x2a],+ (f, m) <- [(W.greedyView, 0), (W.shift, shiftMask)]]
XMonad/Config/Bluetile.hs view
@@ -1,5 +1,5 @@-{-# OPTIONS -fno-warn-missing-signatures #-} {-# LANGUAGE FlexibleContexts #-}+{-# OPTIONS -fno-warn-missing-signatures #-} ---------------------------------------------------------------------------- -- | -- Module : XMonad.Config.Bluetile@@ -199,7 +199,7 @@ floatingDeco l = buttonDeco shrinkText defaultThemeWithButtons l bluetileConfig =- defaultConfig+ def { modMask = mod4Mask, -- logo key manageHook = bluetileManageHook, layoutHook = bluetileLayoutHook,
XMonad/Config/Desktop.hs view
@@ -22,7 +22,8 @@ -- the DE via a subset of the Extended Window Manager Hints (EWMH) -- specification. Extra xmonad settings unique to specific DE's are -- added by overriding or modifying @desktopConfig@ fields in the- -- same way that @defaultConfig@ is customized in @~\/.xmonad/xmonad.hs@.+ -- same way that the default configuration is customized in+ -- @~\/.xmonad/xmonad.hs@. -- -- For more information about EWMH see: --@@ -69,7 +70,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 @defaultConfig@ in your @~\/.xmonad/xmonad.hs@,+-- and pagers, in place of @def@ in your @~\/.xmonad/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@.@@ -88,7 +89,7 @@ -- $customizing -- To customize a desktop config, modify its fields as is illustrated with--- @defaultConfig@ in "XMonad.Doc.Extending#Extending xmonad".+-- the default configuration @def@ in "XMonad.Doc.Extending#Extending xmonad". -- $layouts -- See also "XMonad.Util.EZConfig" for more options for modifying key bindings.@@ -163,11 +164,11 @@ -- > adjustEventInput -- -desktopConfig = ewmh defaultConfig+desktopConfig = ewmh def { startupHook = setDefaultCursor xC_left_ptr- , layoutHook = desktopLayoutModifiers $ layoutHook defaultConfig- , manageHook = manageHook defaultConfig <+> manageDocks- , keys = desktopKeys <+> keys defaultConfig }+ , layoutHook = desktopLayoutModifiers $ layoutHook def+ , manageHook = manageHook def <+> manageDocks+ , keys = desktopKeys <+> keys def } desktopKeys (XConfig {modMask = modm}) = M.fromList $ [ ((modm, xK_b), sendMessage ToggleStruts) ]
+ XMonad/Config/Dmwit.hs view
@@ -0,0 +1,323 @@+-- boilerplate {{{+{-# LANGUAGE ExistentialQuantification, NoMonomorphismRestriction, TypeSynonymInstances #-}+{-# OPTIONS_GHC -fno-warn-missing-signatures -fno-warn-type-defaults #-}+module XMonad.Config.Dmwit where++-- system imports+import Control.Applicative+import Control.Monad+import Control.Monad.Trans+import Data.Char+import Data.List+import Data.Map (Map, fromList)+import Data.Ratio+import Data.Word+import GHC.Real+import System.Environment+import System.Exit+import System.IO+import System.Process++-- xmonad core+import XMonad+import XMonad.StackSet hiding (workspaces)++-- xmonad contrib+import XMonad.Actions.SpawnOn+import XMonad.Actions.Warp+import XMonad.Hooks.DynamicLog+import XMonad.Hooks.ManageDocks+import XMonad.Hooks.ManageHelpers+import XMonad.Layout.Grid+import XMonad.Layout.IndependentScreens+import XMonad.Layout.Magnifier+import XMonad.Layout.NoBorders+import XMonad.Util.Dzen hiding (x, y)+import XMonad.Util.SpawnOnce+-- }}}+-- volume {{{+outputOf :: String -> IO String+outputOf s = do+ uninstallSignalHandlers+ (hIn, hOut, hErr, p) <- runInteractiveCommand s+ mapM_ hClose [hIn, hErr]+ hGetContents hOut <* waitForProcess p <* installSignalHandlers++geomMean :: Floating a => [a] -> a+geomMean xs = product xs ** (recip . fromIntegral . length $ xs)++arithMean :: Floating a => [a] -> a+arithMean xs = sum xs / fromIntegral (length xs)++namedNumbers n s = do+ l <- lines s+ guard (sentinel `isPrefixOf` l)+ return (drop (length sentinel) l)+ where sentinel = n ++ " #"++-- Data.List.Split.splitOn ":", but without involving an extra dependency+splitColon xs = case break (==':') xs of+ (a, ':':b) -> a : splitColon b+ (a, _) -> [a]++parse s = arithMean $ do+ l <- lines s+ guard ("\tVolume: " `isPrefixOf` l)+ part <- splitColon l+ (n,'%':_) <- reads part+ return n++modVolume :: String -> Integer -> IO Double+modVolume kind n = do+ is <- namedNumbers parseKind <$> outputOf listCommand+ forM_ is (outputOf . setCommand)+ parse <$> outputOf listCommand+ where+ sign | n > 0 = "+" | otherwise = "-"+ ctlKind = map (\c -> if c == ' ' then '-' else c) kind+ parseKind = unwords . map (\(c:cs) -> toUpper c : cs) . words $ kind+ setCommand i = "pactl set-" ++ ctlKind ++ "-volume " ++ i ++ " -- " ++ sign ++ show (abs n) ++ "%"+ listCommand = "pactl list " ++ ctlKind ++ "s"+-- }}}+-- convenient actions {{{+centerMouse = warpToWindow (1/2) (1/2)+statusBarMouse = warpToScreen 0 (5/1600) (5/1200)+withScreen s f = screenWorkspace s >>= flip whenJust (windows . f)++makeLauncher yargs run exec close = concat+ ["exe=`yeganesh ", yargs, "` && ", run, " ", exec, "$exe", close]+launcher = makeLauncher "" "eval" "\"exec " "\""+termLauncher = makeLauncher "-p withterm" "exec urxvt -e" "" ""+viewShift i = view i . shift i+floatAll = composeAll . map (\s -> className =? s --> doFloat)+sinkFocus = peek >>= maybe id sink+showMod k n = liftIO (modVolume k n) >>= volumeDzen . show . round+volumeDzen = dzenConfig $ onCurr (center 170 66) >=> font "-*-helvetica-*-r-*-*-64-*-*-*-*-*-*-*,-*-terminus-*-*-*-*-64-*-*-*-*-*-*-*"+-- }}}+altMask = mod1Mask+bright = "#80c0ff"+dark = "#13294e"+-- manage hooks for mplayer {{{+fullscreen43on169 = expand $ RationalRect 0 (-1/6) 1 (4/3) where+ expand (RationalRect x y w h) = RationalRect (x - bwx) (y - bwy) (w + 2 * bwx) (h + 2 * bwy)+ bwx = 2 / 1920 -- borderwidth+ bwy = 2 / 1080++fullscreenMPlayer = className =? "MPlayer" --> do+ dpy <- liftX $ asks display+ win <- ask+ hints <- liftIO $ getWMNormalHints dpy win+ case fmap (approx . fst) (sh_aspect hints) of+ Just ( 4 :% 3) -> viewFullOn 0 "5" win+ Just (16 :% 9) -> viewFullOn 1 "5" win+ _ -> doFloat+ where+ fi = fromIntegral :: Dimension -> Double+ approx (n, d) = approxRational (fi n / fi d) (1/100)++operationOn f s n w = do+ let ws = marshall s n+ currws <- liftX $ screenWorkspace s+ doF $ view ws . maybe id view currws . shiftWin ws w . f w++viewFullOn = operationOn sink+centerWineOn = operationOn (`XMonad.StackSet.float` RationalRect (79/960) (-1/540) (401/480) (271/270))+-- }}}+-- debugging {{{+class Show a => PPrint a where+ pprint :: Int -> a -> String+ pprint _ = show++data PPrintable = forall a. PPrint a => P a+instance Show PPrintable where show (P x) = show x+instance PPrint PPrintable where pprint n (P x) = pprint n x++record :: String -> Int -> [(String, PPrintable)] -> String+record s n xs = preamble ++ intercalate newline fields ++ postlude where+ indentation = '\n' : replicate n '\t'+ preamble = s ++ " {" ++ indentation+ postlude = indentation ++ "}"+ newline = ',' : indentation+ fields = map (\(name, value) -> name ++ " = " ++ pprint (n+1) value) xs++instance PPrint a => PPrint (Maybe a) where+ pprint n (Just x) = "Just (" ++ pprint n x ++ ")"+ pprint _ x = show x++instance PPrint a => PPrint [a] where+ pprint _ [] = "[]"+ pprint n xs = preamble ++ intercalate newline allLines ++ postlude where+ indentation = '\n' : replicate n '\t'+ preamble = "[" ++ indentation+ allLines = map (pprint (n+1)) xs+ newline = ',' : indentation+ postlude = indentation ++ "]"++instance PPrint Rectangle where+ pprint n x = record "Rectangle" n [+ ("rect_x", P (rect_x x)),+ ("rect_y", P (rect_y x)),+ ("rect_width", P (rect_width x)),+ ("rect_height", P (rect_height x))+ ]++instance PPrint a => PPrint (Stack a) where+ pprint n x = record "Stack" n [+ ("focus", P (XMonad.StackSet.focus x)),+ ("up", P (up x)),+ ("down", P (down x))+ ]++instance (PPrint i, PPrint l, PPrint a) => PPrint (Workspace i l a) where+ pprint n x = record "Workspace" n [+ ("tag", P (tag x)),+ ("layout", P (layout x)),+ ("stack", P (stack x))+ ]++instance PPrint ScreenDetail where+ pprint n x = record "SD" n [("screenRect", P (screenRect x))]++instance (PPrint i, PPrint l, PPrint a, PPrint sid, PPrint sd) => PPrint (XMonad.StackSet.Screen i l a sid sd) where+ pprint n x = record "Screen" n [+ ("workspace", P (workspace x)),+ ("screen", P (screen x)),+ ("screenDetail", P (screenDetail x))+ ]++instance (PPrint i, PPrint l, PPrint a, PPrint sid, PPrint sd) => PPrint (StackSet i l a sid sd) where+ pprint n x = record "StackSet" n [+ ("current", P (current x)),+ ("visible", P (visible x)),+ ("hidden", P (hidden x)),+ ("floating", P (floating x))+ ]++instance PPrint (Layout a)+instance PPrint Int+instance PPrint XMonad.Screen+instance PPrint Integer+instance PPrint Position+instance PPrint Dimension+instance PPrint Char+instance PPrint Word64+instance PPrint ScreenId+instance (Show a, Show b) => PPrint (Map a b)+-- }}}+-- main {{{+dmwitConfig nScreens = def {+ borderWidth = 2,+ workspaces = withScreens nScreens (map show [1..5]),+ terminal = "urxvt",+ normalBorderColor = dark,+ focusedBorderColor = bright,+ modMask = mod4Mask,+ keys = keyBindings,+ layoutHook = magnifierOff $ avoidStruts (GridRatio 0.9) ||| noBorders Full,+ manageHook = (title =? "CGoban: Main Window" --> doF sinkFocus)+ <+> (className =? "Wine" <&&> (appName =? "hl2.exe" <||> appName =? "portal2.exe") --> ask >>= viewFullOn {-centerWineOn-} 1 "5")+ <+> (className =? "VirtualBox" --> ask >>= viewFullOn 1 "5")+ <+> (isFullscreen --> doFullFloat) -- TF2 matches the "isFullscreen" criteria, so its manage hook should appear after (e.g., to the left of a <+> compared to) this one+ <+> (appName =? "huludesktop" --> doRectFloat fullscreen43on169)+ <+> fullscreenMPlayer+ <+> floatAll ["Gimp", "Wine"]+ <+> manageDocks+ <+> manageSpawn,+ logHook = allPPs nScreens,+ startupHook = refresh+ >> mapM_ (spawnOnce . xmobarCommand) [0 .. nScreens-1]+ }++main = countScreens >>= xmonad . dmwitConfig+-- }}}+-- keybindings {{{+keyBindings conf = let m = modMask conf in fromList . anyMask $ [+ ((m , xK_BackSpace ), spawnHere "urxvt"),+ ((m , xK_p ), spawnHere launcher),+ ((m .|. shiftMask , xK_p ), spawnHere termLauncher),+ ((m .|. shiftMask , xK_c ), kill),+ ((m , xK_q ), restart "xmonad" True),+ ((m .|. shiftMask , xK_q ), io (exitWith ExitSuccess)),+ ((m , xK_grave ), sendMessage NextLayout),+ ((m .|. shiftMask , xK_grave ), setLayout $ layoutHook conf),+ ((m , xK_o ), sendMessage Toggle),+ ((m , xK_x ), withFocused (windows . sink)),+ ((m , xK_Home ), windows focusUp),+ ((m .|. shiftMask , xK_Home ), windows swapUp),+ ((m , xK_End ), windows focusDown),+ ((m .|. shiftMask , xK_End ), windows swapDown),+ ((m , xK_a ), windows focusMaster),+ ((m .|. shiftMask , xK_a ), windows swapMaster),+ ((m , xK_Control_L ), withScreen 0 view),+ ((m .|. shiftMask , xK_Control_L ), withScreen 0 viewShift),+ ((m , xK_Alt_L ), withScreen 1 view),+ ((m .|. shiftMask , xK_Alt_L ), withScreen 1 viewShift),+ ((m , xK_u ), centerMouse),+ ((m .|. shiftMask , xK_u ), statusBarMouse),+ ((m , xK_s ), spawnHere "chromium --password-store=gnome"),+ ((m , xK_n ), spawnHere "gvim todo"),+ ((m , xK_t ), spawnHere "mpc toggle"),+ ((m , xK_h ), spawnHere "urxvt -e alsamixer"),+ ((m , xK_d ), spawnHere "wyvern"),+ ((m , xK_l ), spawnHere "urxvt -e sup"),+ ((m , xK_r ), spawnHere "urxvt -e ncmpcpp"),+ ((m , xK_c ), spawnHere "urxvt -e ghci"),+ ((m , xK_g ), spawnHere "slock" >> spawnHere "xscreensaver-command -lock"),+ ((m , xK_f ), spawnHere "gvim ~/.xmonad/xmonad.hs"),+ (( noModMask , xK_F8 ), showMod "sink input" (-4)),+ (( noModMask , xK_F9 ), showMod "sink input" 4 ),+ (( shiftMask , xK_F8 ), showMod "sink" (-4)),+ (( shiftMask , xK_F9 ), showMod "sink" 4 ),+ (( noModMask , xK_Super_L ), return ()) -- make VirtualBox ignore stray hits of the Windows key+ ] ++ [+ ((m .|. e , key ), windows (onCurrentScreen f ws))+ | (key, ws) <- zip [xK_1..xK_9] (workspaces' conf)+ , (e, f) <- [(0, view), (shiftMask, viewShift)]+ ]++atSchool school home = do+ host <- liftIO (getEnv "HOST")+ return $ case host of+ "sorghum" -> home+ "buckwheat" -> home+ _ -> school++anyMask xs = do+ ((mask, key), action) <- xs+ extraMask <- [0, controlMask, altMask, controlMask .|. altMask]+ return ((mask .|. extraMask, key), action)+-- }}}+-- logHook {{{+pipeName n s = "/home/dmwit/.xmonad/pipe-" ++ n ++ "-" ++ show s++xmobarCommand (S s) = unwords ["xmobar",+ "-x", show s,+ "-t", template s,+ "-C", pipeReader+ ]+ where+ template 0 = "}%focus%{%workspaces%"+ template _ = "%date%}%focus%{%workspaces%"+ pipeReader = "'[\+ \Run PipeReader \"" ++ pipeName "focus" s ++ "\" \"focus\",\+ \Run PipeReader \"" ++ pipeName "workspaces" s ++ "\" \"workspaces\"\+ \]'"++allPPs nScreens = sequence_ [dynamicLogWithPP (pp s) | s <- [0..nScreens-1], pp <- [ppFocus, ppWorkspaces]]+color c = xmobarColor c ""++ppFocus s@(S s_) = whenCurrentOn s def {+ ppOrder = \(_:_:windowTitle:_) -> [windowTitle],+ ppOutput = appendFile (pipeName "focus" s_) . (++ "\n")+ }++ppWorkspaces s@(S s_) = marshallPP s def {+ ppCurrent = color "white",+ ppVisible = color "white",+ ppHiddenNoWindows = color dark,+ ppUrgent = color "red",+ ppSep = "",+ ppOrder = \(wss:_layout:_title:_) -> [wss],+ ppOutput = appendFile (pipeName "workspaces" s_) . (++"\n")+ }+-- }}}
XMonad/Config/Droundy.hs view
@@ -16,7 +16,7 @@ import qualified Data.Map as M import System.Exit ( exitWith, ExitCode(ExitSuccess) ) -import XMonad.Layout.Tabbed ( tabbed, defaultTheme,+import XMonad.Layout.Tabbed ( tabbed, shrinkText, Shrinker, shrinkIt, CustomShrink(CustomShrink) ) import XMonad.Layout.Combo ( combineTwo ) import XMonad.Layout.Named ( named )@@ -32,7 +32,7 @@ import XMonad.Layout.ShowWName ( showWName ) import XMonad.Layout.Magnifier ( maximizeVertical, MagnifyMsg(Toggle) ) -import XMonad.Prompt ( defaultXPConfig, font, height, XPConfig )+import XMonad.Prompt ( font, height, XPConfig ) import XMonad.Prompt.Layout ( layoutPrompt ) import XMonad.Prompt.Shell ( shellPrompt ) @@ -46,8 +46,8 @@ import XMonad.Hooks.EwmhDesktops ( ewmh ) myXPConfig :: XPConfig-myXPConfig = defaultXPConfig {font="-*-lucida-medium-r-*-*-14-*-*-*-*-*-*-*"- ,height=22}+myXPConfig = def {font="-*-lucida-medium-r-*-*-14-*-*-*-*-*-*-*"+ ,height=22} ------------------------------------------------------------------------@@ -117,7 +117,7 @@ ++ zip (zip (repeat (modMask x .|. shiftMask)) [xK_F1..xK_F12]) (map (withNthWorkspace copy) [0..]) -config = ewmh defaultConfig+config = ewmh def { borderWidth = 1 -- Width of the window border in pixels. , XMonad.workspaces = ["mutt","iceweasel"] , layoutHook = showWName $ workspaceDir "~" $@@ -129,7 +129,7 @@ named "widescreen" ((mytab *||* mytab) ****//* combineTwo Square mytab mytab) -- ||| --mosaic 0.25 0.5- , manageHook = manageHook defaultConfig <+> manageDocks -- add panel-handling+ , manageHook = manageHook def <+> manageDocks -- add panel-handling , terminal = "xterm" -- The preferred terminal program. , normalBorderColor = "#222222" -- Border color for unfocused windows. , focusedBorderColor = "#00ff00" -- Border color for focused windows.@@ -137,7 +137,7 @@ , XMonad.keys = keys } -mytab = tabbed CustomShrink defaultTheme+mytab = tabbed CustomShrink def instance Shrinker CustomShrink where shrinkIt shr s | Just s' <- dropFromHead " " s = shrinkIt shr s'
XMonad/Config/Gnome.hs view
@@ -74,7 +74,7 @@ x <- lookup "DESKTOP_AUTOSTART_ID" `fmap` getEnvironment whenJust x $ \sessionId -> safeSpawn "dbus-send" ["--session"- ,"--print-reply=string"+ ,"--print-reply=literal" ,"--dest=org.gnome.SessionManager" ,"/org/gnome/SessionManager" ,"org.gnome.SessionManager.RegisterClient"
+ XMonad/Config/Mate.hs view
@@ -0,0 +1,87 @@+{-# OPTIONS_GHC -fno-warn-missing-signatures #-}++-----------------------------------------------------------------------------+-- |+-- Module : XMonad.Config.Mate+-- Copyright : (c) Brandon S Allbery KF8NH, 2014+-- License : BSD+--+-- Maintainer : allbery.b@gmail.com+-- Stability : unstable+-- Portability : unportable+--+-- This module provides a config suitable for use with the MATE desktop+-- environment.+--+-----------------------------------------------------------------------------++module XMonad.Config.Mate (+ -- * Usage+ -- $usage+ mateConfig,+ mateRun,+ mateRegister+ ) where++import XMonad+import XMonad.Config.Desktop+import XMonad.Util.Run (safeSpawn)++import qualified Data.Map as M++import System.Environment (getEnvironment)++-- $usage+-- To use this module, start with the following @~\/.xmonad\/xmonad.hs@:+--+-- > import XMonad+-- > import XMonad.Config.Mate+-- >+-- > main = xmonad mateConfig+--+-- For examples of how to further customize @mateConfig@ see "XMonad.Config.Desktop".++mateConfig = desktopConfig+ { terminal = "mate-terminal"+ , keys = mateKeys <+> keys desktopConfig+ , startupHook = mateRegister >> startupHook desktopConfig }++mateKeys (XConfig {modMask = modm}) = M.fromList $+ [ ((modm, xK_p), mateRun)+ , ((modm .|. shiftMask, xK_q), spawn "mate-session-save --logout-dialog") ]++-- | Launch the "Run Application" dialog. mate-panel must be running for this+-- to work.+mateRun :: X ()+mateRun = withDisplay $ \dpy -> do+ rw <- asks theRoot+ mate_panel <- getAtom "_MATE_PANEL_ACTION"+ panel_run <- getAtom "_MATE_PANEL_ACTION_RUN_DIALOG"++ io $ allocaXEvent $ \e -> do+ setEventType e clientMessage+ setClientMessageEvent e rw mate_panel 32 panel_run 0+ sendEvent dpy rw False structureNotifyMask e+ sync dpy False++-- | Register xmonad with mate. 'dbus-send' must be in the $PATH with which+-- xmonad is started.+--+-- This action reduces a delay on startup only if you have configured+-- mate-session to start xmonad with a command such as (check local+-- documentation):+--+-- > dconf write /org/mate/desktop/session/required_components/windowmanager "'xmonad'"+--+-- (the extra quotes are required by dconf)+mateRegister :: MonadIO m => m ()+mateRegister = io $ do+ x <- lookup "DESKTOP_AUTOSTART_ID" `fmap` getEnvironment+ whenJust x $ \sessionId -> safeSpawn "dbus-send"+ ["--session"+ ,"--print-reply=literal"+ ,"--dest=org.mate.SessionManager"+ ,"/org/mate/SessionManager"+ ,"org.mate.SessionManager.RegisterClient"+ ,"string:xmonad"+ ,"string:"++sessionId]
+ XMonad/Config/Prime.hs view
@@ -0,0 +1,689 @@+{-# LANGUAGE FlexibleContexts, FlexibleInstances, FunctionalDependencies, KindSignatures, MultiParamTypeClasses, UndecidableInstances #-}++-----------------------------------------------------------------------------+-- |+-- Module : XMonad.Config.Prime+-- Copyright : Devin Mullins <devin.mullins@gmail.com>+-- License : BSD-style (see LICENSE)+--+-- Maintainer : Devin Mullins <devin.mullins@gmail.com>+-- Stability : unstable+-- Portability : unportable+--+-- This is a draft of a brand new config syntax for xmonad. It aims to be:+--+-- * easier to copy/paste snippets from the docs+--+-- * easier to get the gist for what's going on, for you imperative programmers+--+-- It's brand new, so it's pretty much guaranteed to break or change syntax.+-- But what's the worst that could happen? Xmonad crashes and logs you out?+-- It probably won't do that. Give it a try.+--+-----------------------------------------------------------------------------++module XMonad.Config.Prime (+-- Note: The identifiers here are listed in the order that makes the most sense+-- for a user, while the definitions below are listed in the order that makes+-- the most sense for a developer.++-- * Start here+-- $start_here+xmonad,+nothing,+-- * Attributes you can set+-- $settables+normalBorderColor,+focusedBorderColor,+terminal,+modMask,+borderWidth,+focusFollowsMouse,+clickJustFocuses,+SettableClass(..),+UpdateableClass(..),++-- * Attributes you can add to+-- $summables+manageHook,+handleEventHook,+workspaces,+logHook,+startupHook,+clientMask,+rootMask,+SummableClass(..),++-- * Attributes you can add to or remove from+-- $removables+keys,+mouseBindings,+RemovableClass(..),++-- * Modifying the list of workspaces+-- $workspaces+withWorkspaces,+wsNames,+wsKeys,+wsActions,+wsSetName,++-- * Modifying the screen keybindings+-- $screens+withScreens,+sKeys,+sActions,+onScreens,++-- * Modifying the layoutHook+-- $layout+addLayout,+resetLayout,+modifyLayout,++-- * Updating the XConfig en masse+-- $update+startWith,+apply,+applyIO,++-- * The rest of the world+-- | Everything you know and love from the core "XMonad" module is available+-- for use in your config file, too.+module XMonad,+-- | (Almost) everything you know and love from the Haskell "Prelude" is+-- available for use in your config file. Note that '>>' has been overriden, so+-- if you want to create do-blocks for normal monads, you'll need some let+-- statements or a separate module. (See the Troubleshooting section.)+module Prelude,++-- * Core+-- | These are the building blocks on which the config language is built.+-- Regular people shouldn't need to know about these.+Prime,+Arr,+(>>),+ifThenElse,++-- * Example config+-- $example++-- * Troubleshooting+-- $troubleshooting+) where++import Prelude hiding ((>>), mod)+import qualified Prelude as P ((>>=), (>>))++import Data.Monoid (All)++import XMonad hiding (xmonad, XConfig(..))+import XMonad (XConfig(XConfig))+import qualified XMonad.StackSet as W+import qualified XMonad as X (xmonad, XConfig(..))++import XMonad.Util.EZConfig (additionalKeysP, additionalMouseBindings, checkKeymap, removeKeysP, removeMouseBindings)++-- $start_here+-- To start with, create a @~\/.xmonad\/xmonad.hs@ that looks like this:+--+-- > {-# LANGUAGE RebindableSyntax #-}+-- > import XMonad.Config.Prime+-- >+-- > -- Imports go here.+-- >+-- > main = xmonad $ do+-- > nothing+-- > -- Configs go here.+--+-- This will give you a default xmonad install, with room to grow. The lines+-- starting with double dashes are comments. You may delete them. Note that+-- Haskell is a bit precise about indentation. Make sure all the statements in+-- your do-block start at the same column, and make sure that any multi-line+-- statements are formatted with a hanging indent. (For an example, see the+-- 'keys =+' statement in the /Example config/ section, below.)+--+-- After changing your config file, restart xmonad with mod-q (where, by+-- default, "mod" == "alt").++--+-- The Prime "Monad"+--++-- | A Prime is a function that transforms an XConfig. It's not a monad, but we+-- turn on RebindableSyntax so we can abuse the pretty do notation.+type Prime l l' = Arr (XConfig l) (XConfig l')++-- | An Arr is a generalization of Prime. Don't reference the type, if you can+-- avoid it. It might go away in the future.+type Arr x y = x -> IO y++-- | Composes two Arrs using 'Prelude.>>=' from "Prelude".+(>>) :: Arr x y -> Arr y z -> Arr x z+(>>) x y c = (P.>>=) (x c) y++-- | Because of RebindableSyntax, this is necessary to enable you to use+-- if-then-else expressions. No need to call it directly.+ifThenElse :: Bool -> a -> a -> a+ifThenElse True a _ = a+ifThenElse False _ b = b++-- | This is the xmonad main function. It passes 'XMonad.Config.def' (the+-- default 'XConfig') into your do-block, takes the modified config out of your+-- do-block, and then runs xmonad.+--+-- The do-block is a 'Prime'. Advanced readers can skip right to that+-- definition.++xmonad :: (Default a, Read (l Window), LayoutClass l Window) =>+ (a -> IO (XConfig l)) -> IO ()+xmonad prime = (P.>>=) (prime def) X.xmonad++-- | This doesn't modify the config in any way. It's just here for your initial+-- config because Haskell doesn't allow empty do-blocks. Feel free to delete it+-- once you've added other stuff.+nothing :: Prime l l+nothing = return++-- $settables+-- These are a bunch of attributes that you can set. Syntax looks like this:+--+-- > terminal =: "urxvt"+--+-- Strings are double quoted, Dimensions are unquoted integers, booleans are+-- 'True' or 'False' (case-sensitive), and 'modMask' is usually 'mod1Mask' or+-- 'mod4Mask'.++class UpdateableClass s x y | s -> x y where+ -- | This lets you apply a function to an attribute (i.e. read, modify, write).+ (=.) :: s c -> (x -> y) -> Arr c c++class SettableClass s x y | s -> x y where+ -- | This lets you modify an attribute.+ (=:) :: s c -> y -> Arr c c++-- Undecideable instance. But it's nice to leave open the possibility to write+-- fields you can't read (e.g. `wmName =: ...`).+instance UpdateableClass s x y => SettableClass s x y where+ s =: y = s =. const y++data Settable x c = Settable (c -> x) -- getter+ (x -> c -> c) -- setter++instance UpdateableClass (Settable x) x x where+ (Settable g s =. f) c = return $ s (f $ g c) c++-- | Non-focused windows border color. Default: @\"#dddddd\"@+normalBorderColor :: Settable String (XConfig l)+normalBorderColor = Settable X.normalBorderColor (\x c -> c { X.normalBorderColor = x })++-- | Focused windows border color. Default: @\"#ff0000\"@+focusedBorderColor :: Settable String (XConfig l)+focusedBorderColor = Settable X.focusedBorderColor (\x c -> c { X.focusedBorderColor = x })++-- | The preferred terminal application. Default: @\"xterm\"@+terminal :: Settable String (XConfig l)+terminal = Settable X.terminal (\x c -> c { X.terminal = x })++-- | The mod modifier, as used by key bindings. Default: @mod1Mask@ (which is+-- probably alt on your computer).+modMask :: Settable KeyMask (XConfig l)+modMask = Settable X.modMask (\x c -> c { X.modMask = x })++-- | The border width (in pixels). Default: @1@+borderWidth :: Settable Dimension (XConfig l)+borderWidth = Settable X.borderWidth (\x c -> c { X.borderWidth = x })++-- | Whether window focus follows the mouse cursor on move, or requires a mouse+-- click. (Mouse? What's that?) Default: @True@+focusFollowsMouse :: Settable Bool (XConfig l)+focusFollowsMouse = Settable X.focusFollowsMouse (\x c -> c { X.focusFollowsMouse = x })++-- | If True, a mouse click on an inactive window focuses it, but the click is+-- not passed to the window. If False, the click is also passed to the window.+-- Default @True@+clickJustFocuses :: Settable Bool (XConfig l)+clickJustFocuses = Settable X.clickJustFocuses (\x c -> c { X.clickJustFocuses = x })++-- $summables+-- In addition to being able to set these attributes, they have a special+-- syntax for being able to add to them. The operator is @=+@ (the plus comes+-- /after/ the equals), but each attribute has a different syntax for what+-- comes after the operator.++class SummableClass s y | s -> y where+ -- | This lets you add to an attribute.+ (=+) :: s c -> y -> Arr c c+ infix 0 =+++data Summable x y c = Summable (c -> x) -- getter+ (x -> c -> c) -- setter+ (x -> y -> x) -- accumulator++instance UpdateableClass (Summable x y) x x where+ (Summable g s _ =. f) c = return $ s (f $ g c) c++instance SummableClass (Summable x y) y where+ (Summable g s a =+ y) c = return $ s (g c `a` y) c++-- | The action to run when a new window is opened. Default:+--+-- > manageHook =: composeAll [className =? "MPlayer" --> doFloat, className =? "Gimp" --> doFloat]+--+-- To add more rules to this list, you can say, for instance:+--+-- > import XMonad.StackSet+-- > ...+-- > manageHook =+ (className =? "Emacs" --> doF kill)+-- > manageHook =+ (className =? "Vim" --> doF shiftMaster)+--+-- Note that operator precedence mandates the parentheses here.+manageHook :: Summable ManageHook ManageHook (XConfig l)+manageHook = Summable X.manageHook (\x c -> c { X.manageHook = x }) (<+>)++-- | Custom X event handler. Return @All True@ if the default handler should+-- also be run afterwards. Default does nothing. To add an event handler:+--+-- > import XMonad.Hooks.ServerMode+-- > ...+-- > handleEventHook =+ serverModeEventHook+handleEventHook :: Summable (Event -> X All) (Event -> X All) (XConfig l)+handleEventHook = Summable X.handleEventHook (\x c -> c { X.handleEventHook = x }) (<+>)++-- | List of workspaces' names. Default: @map show [1 .. 9 :: Int]@. Adding+-- appends to the end:+--+-- > workspaces =+ ["0"]+--+-- This is useless unless you also create keybindings for this.+workspaces :: Summable [String] [String] (XConfig l)+workspaces = Summable X.workspaces (\x c -> c { X.workspaces = x }) (++)++-- | The action to perform when the windows set is changed. This happens+-- whenever focus change, a window is moved, etc. @logHook =+@ takes an @X ()@+-- and appends it via '(>>)'. For instance:+--+-- > import XMonad.Hooks.ICCCMFocus+-- > ...+-- > logHook =+ takeTopFocus+--+-- Note that if your expression is parametrically typed (e.g. of type+-- @MonadIO m => m ()@), you'll need to explicitly annotate it, like so:+--+-- > logHook =+ (io $ putStrLn "Hello, world!" :: X ())+logHook :: Summable (X ()) (X ()) (XConfig l)+logHook = Summable X.logHook (\x c -> c { X.logHook = x }) (P.>>)++-- | The action to perform on startup. @startupHook =+@ takes an @X ()@ and+-- appends it via '(>>)'. For instance:+--+-- > import XMonad.Hooks.SetWMName+-- > ...+-- > startupHook =+ setWMName "LG3D"+--+-- Note that if your expression is parametrically typed (e.g. of type+-- @MonadIO m => m ()@), you'll need to explicitly annotate it, as documented+-- in 'logHook'.+startupHook :: Summable (X ()) (X ()) (XConfig l)+startupHook = Summable X.startupHook (\x c -> c { X.startupHook = x }) (P.>>)++-- | The client events that xmonad is interested in. This is useful in+-- combination with handleEventHook. Default: @structureNotifyMask .|.+-- enterWindowMask .|. propertyChangeMask@+--+-- > clientMask =+ keyPressMask .|. keyReleaseMask+clientMask :: Summable EventMask EventMask (XConfig l)+clientMask = Summable X.clientMask (\x c -> c { X.clientMask = x }) (.|.)++-- | The root events that xmonad is interested in. This is useful in+-- combination with handleEventHook. Default: @substructureRedirectMask .|.+-- substructureNotifyMask .|. enterWindowMask .|. leaveWindowMask .|.+-- structureNotifyMask .|. buttonPressMask@+rootMask :: Summable EventMask EventMask (XConfig l)+rootMask = Summable X.rootMask (\x c -> c { X.rootMask = x }) (.|.)++-- $removables+-- The following support the the @=+@ for adding items and the @=-@ operator+-- for removing items.++class RemovableClass r y | r -> y where+ -- | This lets you remove from an attribute.+ (=-) :: r c -> y -> Arr c c+ infix 0 =-++data Keys c = Keys { kAdd :: [(String, X ())] -> c -> c,+ kRemove :: [String] -> c -> c }++instance SummableClass Keys [(String, X ())] where+ Keys { kAdd = a } =+ newKeys = return . a newKeys++instance RemovableClass Keys [String] where+ Keys { kRemove = r } =- sadKeys = return . r sadKeys++-- | Key bindings to 'X' actions. Default: see @`man xmonad`@. 'keys'+-- takes a list of keybindings specified emacs-style, as documented in+-- 'XMonad.Util.EZConfig.mkKeyMap'. For example, to change the "kill window"+-- key:+--+-- > keys =- ["M-S-c"]+-- > keys =+ [("M-M1-x", kill)]+keys :: Keys (XConfig l)+keys = Keys {+ -- Note that since checkKeymap happens on newKeys, it doesn't check for+ -- duplicates between repeated applications. Probably OK. (Especially since+ -- overriding defaults is a common behavior.) Also note that there's no+ -- reference cycle here. Yay!+ kAdd = \newKeys c -> (c `additionalKeysP` newKeys) { X.startupHook = (P.>>) (X.startupHook c) (checkKeymap c newKeys) },+ kRemove = flip removeKeysP+}++data MouseBindings c = MouseBindings { mAdd :: [((ButtonMask, Button), Window -> X ())] -> c -> c,+ mRemove :: [(ButtonMask, Button)] -> c -> c }++instance SummableClass MouseBindings [((ButtonMask, Button), Window -> X ())] where+ MouseBindings { mAdd = a } =+ newBindings = return . a newBindings++instance RemovableClass MouseBindings [(ButtonMask, Button)] where+ 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:+--+-- > import XMonad.Actions.CycleWS (nextWS, prevWS)+-- > ...+-- > mouseBindings =+ [((mod4Mask, button4), const prevWS),+-- > ((mod4Mask, button5), const nextWS)]+--+-- Note that you need to specify the numbered mod-mask e.g. 'mod4Mask' instead+-- of just 'modMask'.+mouseBindings :: MouseBindings (XConfig l)+mouseBindings = MouseBindings {+ mAdd = flip additionalMouseBindings,+ mRemove = flip removeMouseBindings+}++-- $workspaces+-- Workspaces can be configured through 'workspaces', but then the 'keys' need+-- to be set, and this can be a bit laborious. 'withWorkspaces' provides a+-- convenient mechanism for common workspace updates.++-- | Configure workspaces through a Prime-like interface. Example:+--+-- > withWorkspaces $ do+-- > wsKeys =+ ["0"]+-- > wsActions =+ [("M-M1-", windows . swapWithCurrent)]+-- > wsSetName 1 "mail"+--+-- This will set 'workspaces' and add the necessary keybindings to 'keys'. Note+-- that it won't remove old keybindings; it's just not that clever.+withWorkspaces :: Arr WorkspaceConfig WorkspaceConfig -> Prime l l+withWorkspaces wsarr xconf = (P.>>=) (wsarr def) $ \wsconf -> wsprime wsconf xconf+ where wsprime :: WorkspaceConfig -> Prime l l+ wsprime wsconf =+ (workspaces =: allNames) >>+ (keys =+ [(mod ++ key, action name) | (name, key) <- zip allNames (wsKeys_ wsconf),+ (mod, action) <- wsActions_ wsconf])+ where allNames = zipWith chooseName (wsNames_ wsconf) (wsKeys_ wsconf)+ chooseName name keyspec = if not (null name) then name else keyspec++data WorkspaceConfig = WorkspaceConfig {+ wsNames_ :: [String],+ wsKeys_ :: [String],+ wsActions_ :: [(String, String -> X ())]+}++instance Default WorkspaceConfig where+ def = WorkspaceConfig {+ wsNames_ = repeat "",+ wsKeys_ = map (:[]) ['1'..'9'], -- The hungry monkey eats dots and turns them into numbers.+ wsActions_ = [("M-", windows . W.greedyView),+ ("M-S-", windows . W.shift)]+ }++-- | The list of workspace names, like 'workspaces' but with two differences:+--+-- 1. If any entry is the empty string, it'll be replaced with the+-- corresponding entry in 'wsKeys'.+-- 2. The list is truncated to the size of 'wsKeys'.+--+-- The default value is @'repeat' ""@.+--+-- If you'd like to create workspaces without associated keyspecs, you can do+-- that afterwards, outside the 'withWorkspaces' block, with @'workspaces' =+@.+wsNames :: Settable [String] WorkspaceConfig+wsNames = Settable wsNames_ (\x c -> c { wsNames_ = x })++-- | The list of workspace keys. These are combined with the modifiers in+-- 'wsActions' to form the keybindings for navigating to workspaces. Default:+-- @["1","2",...,"9"]@.+wsKeys :: Summable [String] [String] WorkspaceConfig+wsKeys = Summable wsKeys_ (\x c -> c { wsKeys_ = x }) (++)++-- | Mapping from key prefix to command. Its type is @[(String, String ->+-- X())]@. The key prefix may be a modifier such as @\"M-\"@, or a submap+-- prefix such as @\"M-a \"@, or both, as in @\"M-a M-\"@. The command is a+-- function that takes a workspace name and returns an @X ()@. 'withWorkspaces'+-- creates keybindings for the cartesian product of 'wsKeys' and 'wsActions'.+--+-- Default:+--+-- > [("M-", windows . W.greedyView),+-- > ("M-S-", windows . W.shift)]+wsActions :: Summable [(String, String -> X ())] [(String, String -> X ())] WorkspaceConfig+wsActions = Summable wsActions_ (\x c -> c { wsActions_ = x }) (++)++-- | A convenience for just modifying one entry in 'wsNames', in case you only+-- want a few named workspaces. Example:+--+-- > wsSetName 1 "mail"+-- > wsSetName 2 "web"+wsSetName :: Int -> String -> Arr WorkspaceConfig WorkspaceConfig+wsSetName index newName = wsNames =. (map maybeSet . zip [0..])+ where maybeSet (i, oldName) | i == (index - 1) = newName+ | otherwise = oldName++-- $screens+-- 'withScreens' provides a convenient mechanism to set keybindings for moving+-- between screens, much like 'withWorkspaces'.++-- | Configure screen keys through a Prime-like interface:+--+-- > withScreens $ do+-- > sKeys =: ["e", "r"]+--+-- This will add the necessary keybindings to 'keys'. Note that it won't remove+-- old keybindings; it's just not that clever.+withScreens :: Arr ScreenConfig ScreenConfig -> Prime l l+withScreens sarr xconf = (P.>>=) (sarr def) $ \sconf -> sprime sconf xconf+ where sprime :: ScreenConfig -> Prime l l+ sprime sconf =+ (keys =+ [(mod ++ key, action sid) | (sid, key) <- zip [0..] (sKeys_ sconf),+ (mod, action) <- sActions_ sconf])++data ScreenConfig = ScreenConfig {+ sKeys_ :: [String],+ sActions_ :: [(String, ScreenId -> X ())]+}++instance Default ScreenConfig where+ def = ScreenConfig {+ sKeys_ = ["w", "e", "r"],+ sActions_ = [("M-", windows . onScreens W.view),+ ("M-S-", windows . onScreens W.shift)]+ }+++-- | The list of screen keys. These are combined with the modifiers in+-- 'sActions' to form the keybindings for navigating to workspaces. Default:+-- @["w","e","r"]@.+sKeys :: Summable [String] [String] ScreenConfig+sKeys = Summable sKeys_ (\x c -> c { sKeys_ = x }) (++)++-- | Mapping from key prefix to command. Its type is @[(String, ScreenId ->+-- X())]@. Works the same as 'wsActions' except for a different function type.+--+-- Default:+--+-- > [("M-", windows . onScreens W.view),+-- > ("M-S-", windows . onScreens W.shift)]+sActions :: Summable [(String, ScreenId -> X ())] [(String, ScreenId -> X ())] ScreenConfig+sActions = Summable sActions_ (\x c -> c { sActions_ = x }) (++)++-- | Converts a stackset transformer parameterized on the workspace type into one+-- parameterized on the screen type. For example, you can use @onScreens W.view+-- 0@ to navigate to the workspace on the 0th screen. If the screen id is not+-- recognized, the returned transformer acts as an identity function.+onScreens :: Eq s => (i -> W.StackSet i l a s sd -> W.StackSet i l a s sd) ->+ s -> W.StackSet i l a s sd -> W.StackSet i l a s sd+onScreens f sc ws = maybe id f (W.lookupWorkspace sc ws) ws++-- $layout+-- Layouts are special. You can't modify them using the @=:@ or @=.@ operator.+-- You need to use the following functions.++-- | Add a layout to the list of layouts choosable with mod-space. For instance:+--+-- > import XMonad.Layout.Tabbed+-- > ...+-- > addLayout simpleTabbed+addLayout :: (LayoutClass l Window, LayoutClass r Window) => r Window -> Prime l (Choose l r)+addLayout r c = return c { X.layoutHook = X.layoutHook c ||| r }++-- | Reset the layoutHook from scratch. For instance, to get rid of the wide+-- layout:+--+-- > resetLayout $ Tall 1 (3/100) (1/2) ||| Full+--+-- (The dollar is like an auto-closing parenthesis, so all the stuff to the+-- right of it is treated like an argument to resetLayout.)+resetLayout :: (LayoutClass r Window) => r Window -> Prime l r+resetLayout r c = return c { X.layoutHook = r }++-- | Modify your 'layoutHook' with some wrapper function. You probably want to call+-- this after you're done calling 'addLayout'. Example:+--+-- > import XMonad.Layout.NoBorders+-- > ...+-- > modifyLayout smartBorders+modifyLayout :: (LayoutClass r Window) => (l Window -> r Window) -> Prime l r+modifyLayout f c = return c { X.layoutHook = f $ X.layoutHook c }++-- $update+-- Finally, there are a few contrib modules that bundle multiple attribute+-- updates together. There are three types: 1) wholesale replacements for the+-- default config, 2) pure functions on the config, and 3) IO actions on the+-- config. The syntax for each is different. Examples:+--+-- 1) To start with a 'XMonad.Config.Gnome.gnomeConfig' instead of the default,+-- we use 'startWith':+--+-- > import XMonad.Config.Gnome+-- > ...+-- > startWith gnomeConfig+--+-- 2) 'XMonad.Hooks.UrgencyHook.withUrgencyHook' is a pure function, so we need+-- to use 'apply':+--+-- > import XMonad.Hooks.UrgencyHook+-- > ...+-- > apply $ withUrgencyHook dzenUrgencyHook+--+-- 3) 'XMonad.Hooks.DynamicLog.xmobar' returns an @IO (XConfig l)@, so we need+-- to use 'applyIO':+--+-- > import XMonad.Hooks.DynamicLog+-- > ...+-- > applyIO xmobar++-- | Replace the current 'XConfig' with the given one. If you use this, you+-- probably want it to be the first line of your config.+startWith :: XConfig l' -> Prime l l'+startWith = const . return++-- | Turns a pure function on 'XConfig' into a 'Prime'.+apply :: (XConfig l -> XConfig l') -> Prime l l'+apply f = return . f++-- | Turns an IO function on 'XConfig' into a 'Prime'.+applyIO :: (XConfig l -> IO (XConfig l')) -> Prime l l'+applyIO = id -- This is here in case we want to change the Prime type later.++-- $example+-- As an example, I've included below a subset of my current config. Note that+-- my import statements specify individual identifiers in parentheticals.+-- That's optional. The default is to import the entire module. I just find it+-- helpful to remind me where things came from.+--+-- > {-# LANGUAGE RebindableSyntax #-}+-- > import XMonad.Config.Prime+-- >+-- > import XMonad.Actions.CycleWS (prevWS, nextWS)+-- > import XMonad.Actions.SwapWorkspaces (swapWithCurrent)+-- > import XMonad.Actions.WindowNavigation (withWindowNavigation)+-- > import XMonad.Layout.Fullscreen (fullscreenSupport)+-- > import XMonad.Layout.NoBorders (smartBorders)+-- > import XMonad.Layout.Tabbed (simpleTabbed)+-- >+-- > main = xmonad $ do+-- > modMask =: mod4Mask+-- > normalBorderColor =: "#222222"+-- > terminal =: "urxvt"+-- > focusFollowsMouse =: False+-- > resetLayout $ Tall 1 (3/100) (1/2) ||| simpleTabbed+-- > modifyLayout smartBorders+-- > apply fullscreenSupport+-- > applyIO $ withWindowNavigation (xK_w, xK_a, xK_s, xK_d)+-- > withWorkspaces $ do+-- > wsKeys =+ ["0"]+-- > wsActions =+ [("M-M1-", windows . swapWithCurrent)]+-- > keys =+ [+-- > ("M-,", sendMessage $ IncMasterN (-1)),+-- > ("M-.", sendMessage $ IncMasterN 1),+-- > ("M-M1-d", spawn "date | dzen2 -fg '#eeeeee' -p 2"),+-- > ("C-S-q", return ()),+-- > ("<XF86AudioLowerVolume>", spawn "amixer set Master 5%-"),+-- > ("<XF86AudioRaiseVolume>", spawn "amixer set Master 5%+"),+-- > ("M-M1-x", kill),+-- > ("M-i", prevWS),+-- > ("M-o", nextWS)+-- > ]++-- $troubleshooting+-- === Only the last line of my config seems to take effect. What gives?+-- You're missing the @{-\# LANGUAGE RebindableSyntax \#-}@ line at the top.+--+-- === How do I do use normal monads like 'X' or 'IO'?+-- Here are a couple of ways:+--+-- > import qualified Prelude as P+-- > ...+-- > test1, test2 :: X ()+-- > test1 = spawn "echo Hi" P.>> spawn "echo Bye"+-- > test2 = do spawn "echo Hi"+-- > spawn "echo Bye"+-- > where (>>) = (P.>>)+--+-- === How do I use the old keyboard syntax?+-- You can use 'apply' and supply your own Haskell function. For instance:+--+-- > apply $ flip additionalKeys $ [((mod1Mask, xK_z), spawn "date | dzen2 -fg '#eeeeee' -p 2")]+--+-- === How do I run a command before xmonad starts (like 'spawnPipe')?+-- If you're using it for a status bar, see if 'XMonad.Hooks.DynamicLog.dzen'+-- or 'XMonad.Hooks.DynamicLog.xmobar' does what you want. If so, you can apply+-- it with 'applyIO'.+--+-- If not, you can write your own @XConfig l -> IO (XConfig l)@ and apply it+-- with 'applyIO'. When writing this function, see the above tip about using+-- normal monads.+--+-- Alternatively, you could do something like this this:+--+-- > import qualified Prelude as P (>>)+-- >+-- > main =+-- > openFile ".xmonad.log" AppendMode >>= \log ->+-- > hSetBuffering log LineBuffering P.>>+-- > (xmonad $ do+-- > nothing -- Prime config here.+-- > )
XMonad/Config/Sjanssen.hs view
@@ -21,21 +21,21 @@ import qualified Data.Map as M sjanssenConfig =- ewmh $ defaultConfig+ ewmh $ def { terminal = "exec urxvt" , workspaces = ["irc", "web"] ++ map show [3 .. 9 :: Int] , mouseBindings = \(XConfig {modMask = modm}) -> M.fromList $ [ ((modm, button1), (\w -> focus w >> mouseMoveWindow w)) , ((modm, button2), (\w -> focus w >> windows W.swapMaster)) , ((modm.|. shiftMask, button1), (\w -> focus w >> mouseResizeWindow w)) ]- , keys = \c -> mykeys c `M.union` keys defaultConfig c+ , keys = \c -> mykeys c `M.union` keys def c , logHook = dynamicLogString sjanssenPP >>= xmonadPropLog , layoutHook = modifiers layouts , manageHook = composeAll [className =? x --> doShift w | (x, w) <- [ ("Firefox", "web") , ("Ktorrent", "7") , ("Amarokapp", "7")]]- <+> manageHook defaultConfig <+> manageDocks <+> manageSpawn+ <+> manageHook def <+> manageDocks <+> manageSpawn <+> (isFullscreen --> doFullFloat) , startupHook = mapM_ spawnOnce spawns }@@ -62,8 +62,8 @@ ] myFont = "xft:Bitstream Vera Sans Mono:pixelsize=10"- myTheme = defaultTheme { fontName = myFont }- myPromptConfig = defaultXPConfig+ myTheme = def { fontName = myFont }+ myPromptConfig = def { position = Top , font = myFont , showCompletionOnTab = True
+ XMonad/Config/dmwit.xmobarrc view
@@ -0,0 +1,10 @@+Config {+ font = "xft:Monospace:pixelsize=14,-*-*-*-r-*-*-16-*-*-*-*-*-*-*",+ bgColor = "#000040",+ fgColor = "#80c0ff",+ position = TopSize C 100 26,+ lowerOnStart = True,+ commands = [ Run Com "date" ["+%H:%M"] "" 30 ],+ sepChar = "%",+ alignSep = "}{"+}
XMonad/Doc.hs view
@@ -49,9 +49,9 @@ xmonad is a tiling window manager for X. The xmonad-contrib library collects third party tiling algorithms, hooks, configurations, scripts, and other extensions to xmonad. The source for this library-is available from <http://code.haskell.org/XMonadContrib> via darcs:+is available from <https://github.com/xmonad/xmonad-contrib> via git: -> darcs get http://code.haskell.org/XMonadContrib+> git clone https://github.com/xmonad/xmonad-contrib.git Each stable release of xmonad is accompanied by a stable release of the contrib library, which you should use if (and only if) you're
XMonad/Doc/Configuring.hs view
@@ -84,7 +84,7 @@ > > import XMonad >-> main = xmonad $ defaultConfig+> main = xmonad $ def > { borderWidth = 2 > , terminal = "urxvt" > , normalBorderColor = "#cccccc"
XMonad/Doc/Extending.hs view
@@ -102,7 +102,7 @@ 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-(<http://code.google.com/p/xmonad/issues/list>)!+(<https://github.com/xmonad/xmonad/issues>)! -} @@ -932,13 +932,13 @@ > import XMonad >-> main = xmonad $ defaultConfig { keys = myKeys }+> main = xmonad $ def { keys = myKeys } and provide an appropriate definition of @myKeys@, such as: > myKeys conf@(XConfig {XMonad.modMask = modm}) = M.fromList-> [ ((modm, xK_F12), xmonadPrompt defaultXPConfig)-> , ((modm, xK_F3 ), shellPrompt defaultXPConfig)+> [ ((modm, xK_F12), xmonadPrompt def)+> , ((modm, xK_F3 ), shellPrompt def) > ] This particular definition also requires importing "XMonad.Prompt",@@ -984,25 +984,25 @@ these: > myKeys conf@(XConfig {XMonad.modMask = modm}) = M.fromList-> [ ((modm, xK_F12), xmonadPrompt defaultXPConfig)-> , ((modm, xK_F3 ), shellPrompt defaultXPConfig)+> [ ((modm, xK_F12), xmonadPrompt def)+> , ((modm, xK_F3 ), shellPrompt def) > ] then you can create a new key bindings map by joining the default one with yours: -> newKeys x = myKeys x `M.union` keys defaultConfig x+> newKeys x = myKeys x `M.union` keys def x Finally, you can use @newKeys@ in the 'XMonad.Core.XConfig.keys' field of the configuration: -> main = xmonad $ defaultConfig { keys = newKeys }+> main = xmonad $ def { keys = newKeys } Alternatively, the '<+>' operator can be used which in this usage does exactly the same as the explicit usage of 'M.union' and propagation of the config argument, thanks to appropriate instances in "Data.Monoid". -> main = xmonad $ defaultConfig { keys = myKeys <+> keys defaultConfig }+> main = xmonad $ def { keys = myKeys <+> keys def } All together, your @~\/.xmonad\/xmonad.hs@ would now look like this: @@ -1018,11 +1018,11 @@ > import XMonad.Prompt.XMonad > > main :: IO ()-> main = xmonad $ defaultConfig { keys = myKeys <+> keys defaultConfig }+> main = xmonad $ def { keys = myKeys <+> keys def } > > myKeys conf@(XConfig {XMonad.modMask = modm}) = M.fromList-> [ ((modm, xK_F12), xmonadPrompt defaultXPConfig)-> , ((modm, xK_F3 ), shellPrompt defaultXPConfig)+> [ ((modm, xK_F12), xmonadPrompt def)+> , ((modm, xK_F3 ), shellPrompt def) > ] There are much simpler ways to accomplish this, however, if you are@@ -1044,7 +1044,7 @@ to define @newKeys@ as a 'Data.Map.difference' between the default map and the map of the key bindings you want to remove. Like so: -> newKeys x = keys defaultConfig x `M.difference` keysToRemove x+> newKeys x = keys def x `M.difference` keysToRemove x > > keysToRemove :: XConfig Layout -> M.Map (KeyMask, KeySym) (X ()) > keysToRemove x = M.fromList@@ -1060,7 +1060,7 @@ and then use 'Data.Map.delete' to remove them. In that case we would write something like: -> newKeys x = foldr M.delete (keys defaultConfig x) (keysToRemove x)+> newKeys x = foldr M.delete (keys def x) (keysToRemove x) > > keysToRemove :: XConfig Layout -> [(KeyMask, KeySym)] > keysToRemove x =@@ -1081,7 +1081,7 @@ for removing and adding. Here is an example from "XMonad.Config.Arossato": -> defKeys = keys defaultConfig+> 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@@ -1097,8 +1097,8 @@ > [(shiftMask .|. modm, k) | k <- [xK_1 .. xK_9]] > -- These are my personal key bindings > toAdd XConfig{modMask = modm} =-> [ ((modm , xK_F12 ), xmonadPrompt defaultXPConfig )-> , ((modm , xK_F3 ), shellPrompt defaultXPConfig )+> [ ((modm , xK_F12 ), xmonadPrompt def )+> , ((modm , xK_F3 ), shellPrompt def ) > ] ++ > -- Use modm .|. shiftMask .|. controlMask 1-9 instead > [( (m .|. modm, k), windows $ f i)@@ -1125,9 +1125,9 @@ > > myMouse x = [ (0, button4), (\w -> focus w >> kill) ] >-> newMouse x = M.union (mouseBindings defaultConfig x) (M.fromList (myMouse x))+> newMouse x = M.union (mouseBindings def x) (M.fromList (myMouse x)) >-> main = xmonad $ defaultConfig { ..., mouseBindings = newMouse, ... }+> main = xmonad $ def { ..., mouseBindings = newMouse, ... } Overriding or deleting mouse bindings works similarly. You can also configure mouse bindings much more easily using the@@ -1174,13 +1174,13 @@ Then we create the combination of layouts we need: -> mylayoutHook = Full ||| tabbed shrinkText defaultTheme ||| Accordion+> mylayoutHook = Full ||| tabbed shrinkText def ||| Accordion Now, all we need to do is change the 'XMonad.Core.layoutHook' field of the 'XMonad.Core.XConfig' record, like so: -> main = xmonad $ defaultConfig { layoutHook = mylayoutHook }+> main = xmonad $ def { layoutHook = mylayoutHook } Thanks to the new combinator, we can apply a layout modifier to a whole combination of layouts, instead of applying it to each one. For@@ -1188,11 +1188,11 @@ 'XMonad.Layout.NoBorders.noBorders' layout modifier, from the "XMonad.Layout.NoBorders" module (which must be imported): -> mylayoutHook = noBorders (Full ||| tabbed shrinkText defaultTheme ||| Accordion)+> mylayoutHook = noBorders (Full ||| tabbed shrinkText def ||| Accordion) If we want only the tabbed layout without borders, then we may write: -> mylayoutHook = Full ||| noBorders (tabbed shrinkText defaultTheme) ||| Accordion+> mylayoutHook = Full ||| noBorders (tabbed shrinkText def) ||| Accordion Our @~\/.xmonad\/xmonad.hs@ will now look like this: @@ -1202,9 +1202,9 @@ > import XMonad.Layout.Accordion > import XMonad.Layout.NoBorders >-> mylayoutHook = Full ||| noBorders (tabbed shrinkText defaultTheme) ||| Accordion+> mylayoutHook = Full ||| noBorders (tabbed shrinkText def) ||| Accordion >-> main = xmonad $ defaultConfig { layoutHook = mylayoutHook }+> main = xmonad $ def { layoutHook = mylayoutHook } That's it! @@ -1256,7 +1256,7 @@ > , resource =? "win" --> doF (W.shift "doc") -- xpdf > , resource =? "firefox-bin" --> doF (W.shift "web") > ]-> newManageHook = myManageHook <+> manageHook defaultConfig+> newManageHook = myManageHook <+> manageHook def Again we use 'XMonad.ManageHook.composeAll' to compose a list of@@ -1318,14 +1318,14 @@ We can now use the 'XMonad.ManageHook.<+>' combinator to add our 'XMonad.Config.manageHook' to the default one: -> newManageHook = myManageHook <+> manageHook defaultConfig+> newManageHook = myManageHook <+> manageHook def (Of course, if we wanted to completely replace the default 'XMonad.Config.manageHook', this step would not be necessary.) Now, all we need to do is change the 'XMonad.Core.manageHook' field of the 'XMonad.Core.XConfig' record, like so: -> main = xmonad defaultConfig { ..., manageHook = newManageHook, ... }+> main = xmonad def { ..., manageHook = newManageHook, ... } And we are done. @@ -1387,7 +1387,7 @@ 'XMonad.Core.XConfig' record with one of the provided functions. For example: -> main = xmonad defaultConfig { logHook = dynamicLog }+> main = xmonad def { logHook = dynamicLog } More interesting configurations are also possible; see the "XMonad.Hooks.DynamicLog" module for more possibilities.
XMonad/Hooks/CurrentWorkspaceOnTop.hs view
@@ -33,7 +33,7 @@ -- -- > import XMonad.Hooks.CurrentWorkspaceOnTop -- >--- > main = xmonad $ defaultConfig {+-- > main = xmonad $ def { -- > ... -- > logHook = currentWorkspaceOnTop -- > ...
XMonad/Hooks/DebugEvents.hs view
@@ -47,6 +47,7 @@ import System.Exit import System.IO import System.Process+import Control.Applicative -- | Event hook to dump all received events. You should probably not use this -- unconditionally; it will produce massive amounts of output.@@ -224,6 +225,12 @@ ,("WM_SAVE_YOURSELF" ,("STRING" , 8,0)) ] +#if __GLASGOW_HASKELL__ < 707+finiteBitSize :: Bits a => a -> Int+finiteBitSize x = bitSize x+#endif++ -- | Convert a modifier mask into a useful string vmask :: KeyMask -> KeyMask -> String vmask numLockMask msk = unwords $@@ -231,7 +238,7 @@ fst $ foldr vmask' ([],msk) masks where- masks = map (\m -> (m,show m)) [0..toEnum (bitSize msk - 1)] +++ masks = map (\m -> (m,show m)) [0..toEnum (finiteBitSize msk - 1)] ++ [(numLockMask,"num" ) ,( lockMask,"lock" ) ,(controlMask,"ctrl" )
XMonad/Hooks/DebugKeyEvents.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} ----------------------------------------------------------------------------- -- | -- Module : XMonad.Hooks.DebugKeyEvents@@ -91,7 +92,11 @@ fst $ foldr vmask' ([],msk) masks where- masks = map (\m -> (m,show m)) [0..toEnum (bitSize msk - 1)] ++++#if __GLASGOW_HASKELL__ < 707+ finiteBitSize x = bitSize x+#endif+ masks = map (\m -> (m,show m)) [0..toEnum (finiteBitSize msk - 1)] ++ [(numLockMask,"num" ) ,( lockMask,"lock" ) ,(controlMask,"ctrl" )
XMonad/Hooks/DebugStack.hs view
@@ -1,26 +1,30 @@ ----------------------------------------------------------------------------- -- | -- Module : XMonad.Hooks.DebugStack--- Copyright : (c) Brandon S Allbery KF8NH, 2012+-- Copyright : (c) Brandon S Allbery KF8NH, 2014 -- License : BSD3-style (see LICENSE) -- -- Maintainer : allbery.b@gmail.com -- Stability : unstable -- Portability : not portable ----- Dump the state of the 'StackSet'. A @logHook@ and @handleEventHook@ are+-- Dump the state of the 'StackSet'. A @logHook@ and @handleEventHook@ are -- also provided. -- ----------------------------------------------------------------------------- module XMonad.Hooks.DebugStack (debugStack+ ,debugStackFull ,debugStackString+ ,debugStackFullString ,debugStackLogHook+ ,debugStackFullLogHook ,debugStackEventHook+ ,debugStackFullEventHook ) where import XMonad.Core-import qualified XMonad.StackSet as W+import qualified XMonad.StackSet as W import XMonad.Util.DebugWindow @@ -28,66 +32,79 @@ import Graphics.X11.Xlib.Extras (Event) import Control.Monad (foldM)-import Data.Map (toList)+import Data.Map (member) import Data.Monoid (All(..))+import Data.List (intercalate) --- | Print the state of the current window stack to @stderr@, which for most--- installations goes to @~/.xsession-errors@. "XMonad.Util.DebugWindow"--- is used to display the individual windows.+-- | Print the state of the current window stack for the current workspace to+-- @stderr@, which for most installations goes to @~/.xsession-errors@.+-- "XMonad.Util.DebugWindow" is used to display the individual windows. debugStack :: X () debugStack = debugStackString >>= trace --- | The above packaged as a 'logHook'. (Currently this is identical.)+-- | Print the state of the current window stack for all workspaces to+-- @stderr@, which for most installations goes to @~/.xsession-errors@.+-- "XMonad.Util.DebugWindow" is used to display the individual windows.+debugStackFull :: X ()+debugStackFull = debugStackFullString >>= trace++-- | 'debugStack' packaged as a 'logHook'. (Currently this is identical.) debugStackLogHook :: X () debugStackLogHook = debugStack --- | The above packaged as a 'handleEventHook'. You almost certainly do not+-- | 'debugStackFull packaged as a 'logHook'. (Currently this is identical.)+debugStackFullLogHook :: X ()+debugStackFullLogHook = debugStackFull++-- | 'debugStack' packaged as a 'handleEventHook'. You almost certainly do not -- want to use this unconditionally, as it will cause massive amounts of -- output and possibly slow @xmonad@ down severely. debugStackEventHook :: Event -> X All debugStackEventHook _ = debugStack >> return (All True) --- | Dump the state of the current 'StackSet' as a multiline 'String'.+-- | 'debugStackFull' packaged as a 'handleEventHook'. You almost certainly do+-- not want to use this unconditionally, as it will cause massive amounts of+-- output and possibly slow @xmonad@ down severely.++debugStackFullEventHook :: Event -> X All+debugStackFullEventHook _ = debugStackFull >> return (All True)++-- | Dump the state of the current workspace in the 'StackSet' as a multiline 'String'.+debugStackString :: X String+debugStackString = withWindowSet $ debugStackWs . W.workspace . W.current++-- | Dump the state of all workspaces in the 'StackSet' as a multiline 'String'.+-- @@@ this is in stackset order, which is roughly lru-ish+debugStackFullString :: X String+debugStackFullString = withWindowSet $ fmap (intercalate "\n") . mapM debugStackWs . W.workspaces++-- | Dump the state of a workspace in the current 'StackSet' as a multiline 'String'. -- @--- stack [ mm--- ,(*) ww--- , ww--- ]--- float { ww--- , ww--- }+-- Workspace "foo::+-- mm+-- * ww+-- ^ww -- @------ One thing I'm not sure of is where the zipper is when focus is on a--- floating window.-debugStackString :: X String-debugStackString = withWindowSet $ \ws -> do- s <- emit "stack" ("[","]") (W.peek ws) $ W.index ws- f <- emit "float" ("{","}") (W.peek ws) $ map fst $ toList $ W.floating ws- return $ s ++ f+-- * indicates the focused window, ^ indicates a floating window+debugStackWs :: W.Workspace String (Layout Window) Window -> X String+debugStackWs w = withWindowSet $ \ws -> do+ let cur = if wt == W.currentTag ws then " (current)" else ""+ wt = W.tag w+ s <- emit ws $ W.integrate' . W.stack $ w+ return $ intercalate "\n" $ ("Workspace " ++ show wt ++ cur):s where- emit :: String -> (String,String) -> Maybe Window -> [Window] -> X String- emit title (lb,rb) _ [] = return $ title ++ " " ++ lb ++ rb ++ "]\n"- emit title (lb,rb) focused ws = do- (_,_,_,_,ss) <- foldM emit' (title,lb,rb,focused,"") ws- return $ ss ++- replicate (length title + 1) ' ' ++- rb ++- "\n"+ emit :: WindowSet -> [Window] -> X [String]+ emit _ [] = return [" -empty workspace-"]+ emit ww ws = do+ (_,ss) <- foldM emit' (ww,[]) ws+ return ss - emit' :: (String,String,String,Maybe Window,String)+ emit' :: (WindowSet,[String]) -> Window- -> X (String,String,String,Maybe Window,String)- emit' (t,l,r,f,a) w = do- w' <- emit'' f w- return (replicate (length t) ' '- ,',' : replicate (length l - 1) ' '- ,r- ,f- ,a ++ t ++ " " ++ l ++ w' ++ "\n"- )- emit'' :: Maybe Window -> Window -> X String- emit'' focus win =- let fi f = if win == f then "(*) " else " "- in (maybe " " fi focus ++) `fmap` debugWindow win+ -> X (WindowSet,[String])+ emit' (ws,a) w' = do+ let focus = if Just w' == W.peek ws then '*' else ' '+ float = if w' `member` W.floating ws then '^' else ' '+ s <- debugWindow w'+ return (ws,(focus:float:s):a)
XMonad/Hooks/DynamicBars.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE DeriveDataTypeable #-} ----------------------------------------------------------------------------- -- | -- Module : XMonad.Hooks.DynamicBars@@ -24,7 +25,6 @@ import Prelude -import Control.Concurrent.MVar import Control.Monad import Control.Monad.Trans (lift) import Control.Monad.Writer (WriterT, execWriterT, tell)@@ -39,11 +39,11 @@ import Graphics.X11.Xrandr import System.IO-import System.IO.Unsafe import XMonad import qualified XMonad.StackSet as W import XMonad.Hooks.DynamicLog+import qualified XMonad.Util.ExtensibleState as XS -- $usage -- Provides a few helper functions to manage per-screen status bars while@@ -67,37 +67,35 @@ data DynStatusBarInfo = DynStatusBarInfo { dsbInfoScreens :: [ScreenId] , dsbInfoHandles :: [Handle]- }+ } deriving (Typeable) +instance ExtensionClass DynStatusBarInfo where+ initialValue = DynStatusBarInfo [] []+ type DynamicStatusBar = ScreenId -> IO Handle type DynamicStatusBarCleanup = IO () --- Global state-statusBarInfo :: MVar DynStatusBarInfo-statusBarInfo = unsafePerformIO $ newMVar (DynStatusBarInfo [] [])- dynStatusBarStartup :: DynamicStatusBar -> DynamicStatusBarCleanup -> X ()-dynStatusBarStartup sb cleanup = liftIO $ do- dpy <- openDisplay ""- xrrSelectInput dpy (defaultRootWindow dpy) rrScreenChangeNotifyMask- closeDisplay dpy+dynStatusBarStartup sb cleanup = do+ dpy <- asks display+ root <- asks theRoot+ io $ xrrSelectInput dpy root rrScreenChangeNotifyMask updateStatusBars sb cleanup dynStatusBarEventHook :: DynamicStatusBar -> DynamicStatusBarCleanup -> Event -> X All-dynStatusBarEventHook sb cleanup (RRScreenChangeNotifyEvent {}) = liftIO (updateStatusBars sb cleanup) >> return (All True)+dynStatusBarEventHook sb cleanup (RRScreenChangeNotifyEvent {}) = updateStatusBars sb cleanup >> return (All True) dynStatusBarEventHook _ _ _ = return (All True) -updateStatusBars :: DynamicStatusBar -> DynamicStatusBarCleanup -> IO ()-updateStatusBars sb cleanup = liftIO $ do- dsbInfo <- takeMVar statusBarInfo+updateStatusBars :: DynamicStatusBar -> DynamicStatusBarCleanup -> X ()+updateStatusBars sb cleanup = do+ dsbInfo <- XS.get screens <- getScreens- if (screens /= (dsbInfoScreens dsbInfo))- then do- mapM hClose (dsbInfoHandles dsbInfo)- cleanup- newHandles <- mapM sb screens- putMVar statusBarInfo (DynStatusBarInfo screens newHandles)- else putMVar statusBarInfo dsbInfo+ when (screens /= dsbInfoScreens dsbInfo) $ do+ newHandles <- liftIO $ do+ hClose `mapM_` dsbInfoHandles dsbInfo+ cleanup+ mapM sb screens+ XS.put $ DynStatusBarInfo screens newHandles ----------------------------------------------------------------------------- -- The following code is from adamvo's xmonad.hs file.@@ -107,7 +105,7 @@ -> PP -- ^ The PP to use otherwise -> X () multiPP focusPP unfocusPP = do- dsbInfo <- liftIO $ readMVar statusBarInfo+ dsbInfo <- XS.get multiPP' dynamicLogString focusPP unfocusPP (dsbInfoHandles dsbInfo) multiPP' :: (PP -> X String) -> PP -> PP -> [Handle] -> X ()@@ -125,8 +123,8 @@ =<< mapM screenWorkspace (zipWith const [0 .. ] handles) return () -getScreens :: IO [ScreenId]-getScreens = do+getScreens :: MonadIO m => m [ScreenId]+getScreens = liftIO $ do screens <- do dpy <- openDisplay "" rects <- getScreenInfo dpy
XMonad/Hooks/DynamicLog.hs view
@@ -35,7 +35,7 @@ -- * Build your own formatter dynamicLogWithPP, dynamicLogString,- PP(..), defaultPP,+ PP(..), defaultPP, def, -- * Example formatters dzenPP, xmobarPP, sjanssenPP, byorgeyPP,@@ -43,6 +43,7 @@ -- * Formatting utilities wrap, pad, trim, shorten, xmobarColor, xmobarStrip,+ xmobarStripTags, dzenColor, dzenEscape, dzenStrip, -- * Internal formatting functions@@ -88,7 +89,7 @@ -- -- > main = xmonad =<< xmobar myConfig -- >--- > myConfig = defaultConfig { ... }+-- > myConfig = def { ... } -- -- There is also 'statusBar' if you'd like to use another status bar, or would -- like to use different formatting options. The 'xmobar', 'dzen', and@@ -99,7 +100,7 @@ -- ('dynamicLog' or 'dynamicLogXinerama') by simply setting your logHook to the -- appropriate function, for instance: ----- > main = xmonad $ defaultConfig {+-- > main = xmonad $ def { -- > ... -- > logHook = dynamicLog -- > ...@@ -124,9 +125,9 @@ -- > -- > main = do -- > h <- spawnPipe "xmobar -options -foo -bar"--- > xmonad $ defaultConfig {+-- > xmonad $ def { -- > ...--- > logHook = dynamicLogWithPP $ defaultPP { ppOutput = hPutStrLn h }+-- > logHook = dynamicLogWithPP $ def { ppOutput = hPutStrLn h } -- -- If you use @spawnPipe@, be sure to redefine the 'ppOutput' field of -- your pretty-printer as in the example above; by default the status@@ -153,7 +154,7 @@ -- -- > main = xmonad =<< dzen myConfig -- >--- > myConfig = defaultConfig { ... }+-- > myConfig = def { ... } -- -- The intent is that the above config file should provide a nice -- status bar with minimal effort.@@ -178,7 +179,7 @@ -- -- > main = xmonad =<< xmobar myConfig -- >--- > myConfig = defaultConfig { ... }+-- > myConfig = def { ... } -- -- This works pretty much the same as 'dzen' function above. --@@ -246,7 +247,7 @@ -- To customize the output format, see 'dynamicLogWithPP'. -- dynamicLog :: X ()-dynamicLog = dynamicLogWithPP defaultPP+dynamicLog = dynamicLogWithPP def -- | Format the current status using the supplied pretty-printing format, -- and write it to stdout.@@ -312,10 +313,10 @@ -- using 'dynamicLogWithPP' by setting 'ppSort' to /getSortByXineramaRule/ from -- "XMonad.Util.WorkspaceCompare". For example, ----- > defaultPP { ppCurrent = dzenColor "red" "#efebe7"--- > , ppVisible = wrap "[" "]"--- > , ppSort = getSortByXineramaRule--- > }+-- > def { ppCurrent = dzenColor "red" "#efebe7"+-- > , ppVisible = wrap "[" "]"+-- > , ppSort = getSortByXineramaRule+-- > } dynamicLogXinerama :: X () dynamicLogXinerama = withWindowSet $ io . putStrLn . pprWindowSetXinerama @@ -394,10 +395,15 @@ -- ??? add an xmobarEscape function? --- | Strip xmobar markup.+-- | Strip xmobar markup, specifically the <fc>, <icon> and <action> tags and+-- the matching tags like </fc>. xmobarStrip :: String -> String-xmobarStrip = xmobarStripTags ["fc","icon","action"] where+xmobarStrip = converge (xmobarStripTags ["fc","icon","action"]) where +converge :: (Eq a) => (a -> a) -> a -> a+converge f a = let xs = iterate f a+ in fst $ head $ dropWhile (uncurry (/=)) $ zip xs $ tail xs+ xmobarStripTags :: [String] -- ^ tags -> String -> String -- ^ with all <tag>...</tag> removed xmobarStripTags tags = strip [] where@@ -473,8 +479,12 @@ } -- | The default pretty printing options, as seen in 'dynamicLog'.+{-# DEPRECATED defaultPP "Use def (from Data.Default, and re-exported by XMonad.Hooks.DynamicLog) instead." #-} defaultPP :: PP-defaultPP = PP { ppCurrent = wrap "[" "]"+defaultPP = def++instance Default PP where+ def = PP { ppCurrent = wrap "[" "]" , ppVisible = wrap "<" ">" , ppHidden = id , ppHiddenNoWindows = const ""@@ -492,7 +502,7 @@ -- | Settings to emulate dwm's statusbar, dzen only. dzenPP :: PP-dzenPP = defaultPP { ppCurrent = dzenColor "white" "#2b4f98" . pad+dzenPP = def { ppCurrent = dzenColor "white" "#2b4f98" . pad , ppVisible = dzenColor "black" "#999999" . pad , ppHidden = dzenColor "black" "#cccccc" . pad , ppHiddenNoWindows = const ""@@ -511,7 +521,7 @@ -- | Some nice xmobar defaults. xmobarPP :: PP-xmobarPP = defaultPP { ppCurrent = xmobarColor "yellow" "" . wrap "[" "]"+xmobarPP = def { ppCurrent = xmobarColor "yellow" "" . wrap "[" "]" , ppTitle = xmobarColor "green" "" . shorten 40 , ppVisible = wrap "(" ")" , ppUrgent = xmobarColor "red" "yellow"@@ -519,23 +529,23 @@ -- | The options that sjanssen likes to use with xmobar, as an -- example. Note the use of 'xmobarColor' and the record update on--- 'defaultPP'.+-- 'def'. sjanssenPP :: PP-sjanssenPP = defaultPP { ppCurrent = xmobarColor "white" "black"- , ppTitle = xmobarColor "#00ee00" "" . shorten 120- }+sjanssenPP = def { ppCurrent = xmobarColor "white" "black"+ , ppTitle = xmobarColor "#00ee00" "" . shorten 120+ } -- | The options that byorgey likes to use with dzen, as another example. byorgeyPP :: PP-byorgeyPP = defaultPP { ppHiddenNoWindows = showNamedWorkspaces- , ppHidden = dzenColor "black" "#a8a3f7" . pad- , ppCurrent = dzenColor "yellow" "#a8a3f7" . pad- , ppUrgent = dzenColor "red" "yellow" . pad- , ppSep = " | "- , ppWsSep = ""- , ppTitle = shorten 70- , ppOrder = reverse- }+byorgeyPP = def { ppHiddenNoWindows = showNamedWorkspaces+ , ppHidden = dzenColor "black" "#a8a3f7" . pad+ , ppCurrent = dzenColor "yellow" "#a8a3f7" . pad+ , ppUrgent = dzenColor "red" "yellow" . pad+ , ppSep = " | "+ , ppWsSep = ""+ , ppTitle = shorten 70+ , ppOrder = reverse+ } where showNamedWorkspaces wsId = if any (`elem` wsId) ['a'..'z'] then pad wsId else ""
+ XMonad/Hooks/DynamicProperty.hs view
@@ -0,0 +1,71 @@+-----------------------------------------------------------------------------+-- |+-- Module : XMonad.Hooks.DynamicProperty+-- 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.+--+-----------------------------------------------------------------------------++module XMonad.Hooks.DynamicProperty where++import XMonad+import Data.Monoid+import Control.Applicative+import Control.Monad (when)++-- |+-- 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 'MansgeHook' 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':+--+-- > , handleEventHook = dynamicPropertyChange "WM_NAME" myDynHook <+> handleEventHook baseConfig+-- > +-- > {- ... -}+-- > +-- > myDynHook = composeAll [...]+--+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 (All False) -- so anything else also processes it+dynamicPropertyChange _ _ _ = return (All False)++-- | A shorthand for the most common case, dynamic titles+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"
XMonad/Hooks/EwmhDesktops.hs view
@@ -44,8 +44,8 @@ -- > import XMonad -- > import XMonad.Hooks.EwmhDesktops -- >--- > main = xmonad $ ewmh defaultConfig{ handleEventHook =--- > handleEventHook defaultConfig <+> fullscreenEventHook }+-- > main = xmonad $ ewmh def{ handleEventHook =+-- > handleEventHook def <+> fullscreenEventHook } -- -- You may also be interested in 'avoidStruts' from "XMonad.Hooks.ManageDocks". @@ -55,7 +55,8 @@ ewmh c = c { startupHook = startupHook c +++ ewmhDesktopsStartup , handleEventHook = handleEventHook c +++ ewmhDesktopsEventHook , logHook = logHook c +++ ewmhDesktopsLogHook }- where x +++ y = mappend x y+ -- @@@ will fix this correctly later with the rewrite+ where x +++ y = mappend y x -- | -- Initializes EwmhDesktops and advertises EWMH support to the X
XMonad/Hooks/FadeInactive.hs view
@@ -40,7 +40,7 @@ -- > myLogHook = fadeInactiveLogHook fadeAmount -- > where fadeAmount = 0.8 -- >--- > main = xmonad defaultConfig { logHook = myLogHook }+-- > main = xmonad def { logHook = myLogHook } -- -- fadeAmount can be any rational between 0 and 1. -- you will need to have xcompmgr <http://freedesktop.org/wiki/Software/xapps>
XMonad/Hooks/FadeWindows.hs view
@@ -115,7 +115,7 @@ -- a tight loop trying to fade the popup in). I find it useful to -- have a key binding to restart the compositing manager; for example, ----- main = xmonad $ defaultConfig {+-- main = xmonad $ def { -- {- ... -} -- } -- `additionalKeysP`
XMonad/Hooks/FloatNext.hs view
@@ -53,7 +53,7 @@ -- -- and adding 'floatNextHook' to your 'ManageHook': ----- > myManageHook = floatNextHook <+> manageHook defaultConfig+-- > myManageHook = floatNextHook <+> manageHook def -- -- The 'floatNext' and 'toggleFloatNext' functions can be used in key -- bindings to float the next spawned window:
XMonad/Hooks/InsertPosition.hs view
@@ -31,7 +31,7 @@ -- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@: -- -- > import XMonad.Hooks.InsertPosition--- > xmonad defaultConfig { manageHook = insertPosition Master Newer <+> myManageHook }+-- > xmonad def { manageHook = insertPosition Master Newer <+> myManageHook } -- -- You should you put the manageHooks that use 'doShift' to take effect -- /before/ 'insertPosition', so that the window order will be consistent.
+ XMonad/Hooks/ManageDebug.hs view
@@ -0,0 +1,100 @@+{-# LANGUAGE DeriveDataTypeable #-}++-----------------------------------------------------------------------------+-- |+-- Module : XMonad.Hooks.ManageDebug+-- Copyright : (c) Brandon S Allbery KF8NH, 2014+-- License : BSD3-style (see LICENSE)+--+-- Maintainer : allbery.b@gmail.com+-- Stability : unstable+-- Portability : not portable+--+-- 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+-- individual hooks in whatever way you see fit.+--+-----------------------------------------------------------------------------+--+--++module XMonad.Hooks.ManageDebug (debugManageHook+ ,debugManageHookOn+ ,manageDebug+ ,maybeManageDebug+ ,manageDebugLogHook+ ,debugNextManagedWindow+ ) where++import XMonad+import XMonad.Hooks.DebugStack+import XMonad.Util.DebugWindow+import XMonad.Util.EZConfig+import qualified XMonad.Util.ExtensibleState as XS+import Control.Monad (when)++-- persistent state for manageHook debugging to trigger logHook debugging+data ManageStackDebug = MSD (Bool,Bool) deriving Typeable+instance ExtensionClass ManageStackDebug where+ initialValue = MSD (False,False)++-- | A combinator to add full 'ManageHook' debugging in a single operation.+debugManageHook :: XConfig l -> XConfig l+debugManageHook cf = cf {logHook = manageDebugLogHook <+> logHook cf+ ,manageHook = manageDebug <+> manageHook cf+ }++-- | A combinator to add triggerable 'ManageHook' debugging in a single operation.+-- 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+ ,manageHook = maybeManageDebug <+> manageHook cf+ }+ `additionalKeysP`+ [(key,debugNextManagedWindow)]++-- | Place this at the start of a 'ManageHook', or possibly other places for a+-- more limited view. It will show the current 'StackSet' state and the new+-- window, and set a flag so that @manageDebugLogHook@ will display the+-- final 'StackSet' state.+--+-- Note that the initial state shows only the current workspace; the final+-- one shows all workspaces, since your 'ManageHook' might use e.g. 'doShift',+manageDebug :: ManageHook+manageDebug = do+ w <- ask+ liftX $ do+ trace "== manageHook; current stack =="+ debugStackString >>= trace+ ws <- debugWindow w+ trace $ "new:\n " ++ ws+ XS.modify $ \(MSD (_,key)) -> MSD (True,key)+ idHook++-- | @manageDebug@ only if the user requested it with @debugNextManagedWindow@.+maybeManageDebug :: ManageHook+maybeManageDebug = do+ go <- liftX $ do+ MSD (log_,go') <- XS.get+ XS.put $ MSD (log_,False)+ return go'+ if go then manageDebug else idHook++-- | If @manageDebug@ has set the debug-stack flag, show the stack.+manageDebugLogHook :: X ()+manageDebugLogHook = do+ MSD (go,key) <- XS.get+ when go $ do+ trace "== manageHook; final stack =="+ debugStackFullString >>= trace+ XS.put $ MSD (False,key)+ idHook++-- | Request that the next window to be managed be @manageDebug@-ed. This can+-- be used anywhere an X action can, such as key bindings, mouse bindings+-- (presumably with 'const'), 'startupHook', etc.+debugNextManagedWindow :: X ()+debugNextManagedWindow = XS.modify $ \(MSD (log_,_)) -> MSD (log_,True)
XMonad/Hooks/ManageDocks.hs view
@@ -1,5 +1,4 @@ {-# LANGUAGE DeriveDataTypeable, PatternGuards, FlexibleInstances, MultiParamTypeClasses, CPP #-}--- deriving Typeable for ghc-6.6 compatibility, which is retained in the core ----------------------------------------------------------------------------- -- | -- Module : XMonad.Hooks.ManageDocks@@ -40,7 +39,7 @@ import XMonad.Util.Types import XMonad.Util.WindowProperties (getProp32s) import XMonad.Util.XUtils (fi)-import Data.Monoid (All(..))+import Data.Monoid (All(..), mempty) import qualified Data.Set as S @@ -99,10 +98,12 @@ -- -- | Detects if the given window is of type DOCK and if so, reveals--- it, but does not manage it. If the window has the STRUT property--- set, adjust the gap accordingly.+-- it, but does not manage it. manageDocks :: ManageHook-manageDocks = checkDock --> doIgnore+manageDocks = checkDock --> (doIgnore <+> clearGapCache)+ where clearGapCache = do+ liftX (broadcastMessage ClearGapCache)+ mempty -- | Checks if a window is a DOCK or DESKTOP window checkDock :: Query Bool@@ -118,7 +119,9 @@ -- new dock. docksEventHook :: Event -> X All docksEventHook (MapNotifyEvent {ev_window = w}) = do- whenX ((not `fmap` (isClient w)) <&&> runQuery checkDock w) refresh+ whenX ((not `fmap` (isClient w)) <&&> runQuery checkDock w) $ do+ broadcastMessage ClearGapCache+ refresh return (All True) docksEventHook _ = return (All True) @@ -167,9 +170,12 @@ [Direction2D] -> l a -> ModifiedLayout AvoidStruts l a-avoidStrutsOn ss = ModifiedLayout $ AvoidStruts $ S.fromList ss+avoidStrutsOn ss = ModifiedLayout $ AvoidStruts (S.fromList ss) Nothing -data AvoidStruts a = AvoidStruts (S.Set Direction2D) deriving ( Read, Show )+data AvoidStruts a = AvoidStruts {+ avoidStrutsDirection :: S.Set Direction2D,+ avoidStrutsRectCache :: Maybe (S.Set Direction2D, Rectangle, Rectangle )+} deriving ( Read, Show ) -- | Message type which can be sent to an 'AvoidStruts' layout -- modifier to alter its behavior.@@ -179,6 +185,13 @@ instance Message ToggleStruts ++-- | message sent to ensure that caching the gaps won't give a wrong result+-- because a new dock has been added+data ClearGapCache = ClearGapCache+ deriving (Read,Show,Typeable)+instance Message ClearGapCache+ -- | SetStruts is a message constructor used to set or unset specific struts, -- regardless of whether or not the struts were originally set. Here are some -- example bindings:@@ -206,21 +219,38 @@ instance Message SetStruts instance LayoutModifier AvoidStruts a where- modifyLayout (AvoidStruts ss) w r = do- nr <- fmap ($ r) (calcGap ss)- runLayout w nr+ modifyLayoutWithUpdate as@(AvoidStruts ss cache) w r = do+ nr <- case cache of+ Just (ss', r', nr) | ss' == ss, r' == r -> return nr+ _ -> do+ nr <- fmap ($ r) (calcGap ss)+ setWorkarea nr+ return nr+ arranged <- runLayout w nr+ let newCache = Just (ss, r, nr)+ return (arranged, if newCache == cache+ then Nothing+ else Just as{ avoidStrutsRectCache = newCache } ) - pureMess (AvoidStruts ss) m- | Just ToggleStruts <- fromMessage m = Just $ AvoidStruts (toggleAll ss)- | Just (ToggleStrut s) <- fromMessage m = Just $ AvoidStruts (toggleOne s ss)+ pureMess as@(AvoidStruts { avoidStrutsDirection = ss }) m+ | Just ToggleStruts <- fromMessage m = Just $ as { avoidStrutsDirection = toggleAll ss }+ | Just (ToggleStrut s) <- fromMessage m = Just $ as { avoidStrutsDirection = toggleOne s ss } | Just (SetStruts n k) <- fromMessage m , let newSS = S.fromList n `S.union` (ss S.\\ S.fromList k)- , newSS /= ss = Just $ AvoidStruts newSS+ , newSS /= ss = Just $ as { avoidStrutsDirection = newSS }+ | Just ClearGapCache <- fromMessage m = Just $ as { avoidStrutsRectCache = Nothing } | otherwise = Nothing where toggleAll x | S.null x = S.fromList [minBound .. maxBound] | otherwise = S.empty toggleOne x xs | x `S.member` xs = S.delete x xs | otherwise = x `S.insert` xs++setWorkarea :: Rectangle -> X ()+setWorkarea (Rectangle x y w h) = withDisplay $ \dpy -> do+ a <- getAtom "_NET_WORKAREA"+ c <- getAtom "CARDINAL"+ r <- asks theRoot+ io $ changeProperty32 dpy r a c propModeReplace [fi x, fi y, fi w, fi h] -- | (Direction, height\/width, initial pixel, final pixel).
XMonad/Hooks/ManageHelpers.hs view
@@ -13,7 +13,7 @@ -- -- > import XMonad.Hooks.ManageHelpers -- > main =--- > xmonad defaultConfig{+-- > xmonad def{ -- > ... -- > manageHook = composeOne [ -- > isKDETrayWindow -?> doIgnore,
XMonad/Hooks/Minimize.hs view
@@ -9,7 +9,7 @@ -- Portability : not portable -- -- Handles window manager hints to minimize and restore windows. Use--- this with XMonad.Layout.Minimize.+-- this with "XMonad.Layout.Minimize". -- ----------------------------------------------------------------------------- @@ -33,8 +33,8 @@ -- > -- > myHandleEventHook = minimizeEventHook -- > myLayout = minimize (Tall 1 (3/100) (1/2)) ||| Full ||| etc..--- > main = xmonad defaultConfig { layoutHook = myLayout--- > , handleEventHook = myHandleEventHook }+-- > main = xmonad def { layoutHook = myLayout+-- > , handleEventHook = myHandleEventHook } minimizeEventHook :: Event -> X All minimizeEventHook (ClientMessageEvent {ev_window = w,
XMonad/Hooks/Place.hs view
@@ -59,8 +59,8 @@ -- -- and adding 'placeHook' to your 'manageHook', for example: ----- > main = xmonad $ defaultConfig { manageHook = placeHook simpleSmart--- > <+> manageHook defaultConfig }+-- > main = xmonad $ def { manageHook = placeHook simpleSmart+-- > <+> manageHook def } -- -- Note that 'placeHook' should be applied after most other hooks, especially hooks -- such as 'doFloat' and 'doShift'. Since hooks combined with '<+>' are applied from
XMonad/Hooks/PositionStoreHooks.hs view
@@ -55,15 +55,15 @@ -- as 'positionStoreEventHook' to your event hooks. To be accurate -- about window sizes, the module needs to know if any decoration is in effect. -- This is specified with the first argument: Supply 'Nothing' for no decoration,--- otherwise use 'Just defaultTheme' or similar to inform the module about the+-- otherwise use 'Just def' or similar to inform the module about the -- decoration theme used. ----- > myManageHook = positionStoreManageHook Nothing <+> manageHook defaultConfig+-- > myManageHook = positionStoreManageHook Nothing <+> manageHook def -- > myHandleEventHook = positionStoreEventHook -- >--- > main = xmonad defaultConfig { manageHook = myManageHook--- > , handleEventHook = myHandleEventHook--- > }+-- > main = xmonad def { manageHook = myManageHook+-- > , handleEventHook = myHandleEventHook+-- > } -- positionStoreManageHook :: Maybe Theme -> ManageHook
XMonad/Hooks/RestoreMinimized.hs view
@@ -34,7 +34,7 @@ -- > -- > myHandleEventHook = restoreMinimizedEventHook -- >--- > main = xmonad defaultConfig { handleEventHook = myHandleEventHook }+-- > main = xmonad def { handleEventHook = myHandleEventHook } data RestoreMinimized = RestoreMinimized deriving ( Show, Read )
XMonad/Hooks/ScreenCorners.hs view
@@ -1,8 +1,8 @@-{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveDataTypeable, FlexibleInstances, MultiParamTypeClasses #-} ----------------------------------------------------------------------------- -- | -- Module : XMonad.Hooks.ScreenCorners--- Copyright : (c) 2009 Nils Schweinsberg+-- Copyright : (c) 2009 Nils Schweinsberg, 2015 Evgeny Kurnevsky -- License : BSD3-style (see LICENSE) -- -- Maintainer : Nils Schweinsberg <mail@n-sch.de>@@ -25,12 +25,16 @@ -- * Event hook , screenCornerEventHook++ -- * Layout hook+ , screenCornerLayoutHook ) where import Data.Monoid import Data.List (find) import XMonad import XMonad.Util.XUtils (fi)+import XMonad.Layout.LayoutModifier import qualified Data.Map as M import qualified XMonad.Util.ExtensibleState as XS@@ -143,6 +147,23 @@ --------------------------------------------------------------------------------+-- Layout hook+--------------------------------------------------------------------------------++data ScreenCornerLayout a = ScreenCornerLayout+ deriving ( Read, Show )++instance LayoutModifier ScreenCornerLayout a where+ hook ScreenCornerLayout = withDisplay $ \dpy -> do+ ScreenCornerState m <- XS.get+ io $ mapM_ (raiseWindow dpy) $ M.keys m+ unhook = hook++screenCornerLayoutHook :: l a -> ModifiedLayout ScreenCornerLayout l a+screenCornerLayoutHook = ModifiedLayout ScreenCornerLayout+++-------------------------------------------------------------------------------- -- $usage -- -- This extension adds KDE-like screen corners to XMonad. By moving your cursor@@ -162,6 +183,13 @@ -- > addScreenCorners [ (SCLowerRight, nextWS) -- > , (SCLowerLeft, prevWS) -- > ]+--+-- Then add layout hook:+-- > myLayout = screenCornerLayoutHook $ tiled ||| Mirror tiled ||| Full where+-- > tiled = Tall nmaster delta ratio+-- > nmaster = 1+-- > ratio = 1 / 2+-- > delta = 3 / 100 -- -- And finally wait for screen corner events in your event hook: --
XMonad/Hooks/Script.hs view
@@ -34,7 +34,7 @@ -- For example, if you wanted to run the hook "startup" in your script every -- time your startup hook ran, you could modify your xmonad config as such: ----- > main = xmonad $ defaultConfig {+-- > main = xmonad $ def { -- > ... -- > startupHook = execScriptHook "startup" -- > ...
XMonad/Hooks/ServerMode.hs view
@@ -1,69 +1,104 @@ ----------------------------------------------------------------------------- -- | -- Module : XMonad.Hooks.ServerMode--- Copyright : (c) Andrea Rossato and David Roundy 2007+-- Copyright : (c) Peter Olson 2013 and Andrea Rossato and David Roundy 2007 -- License : BSD-style (see xmonad/LICENSE) ----- Maintainer : andrea.rossato@unibz.it+-- Maintainer : polson2@hawk.iit.edu -- Stability : unstable -- Portability : unportable -- -- This is an 'EventHook' that will receive commands from an external--- client.+-- client. Also consider "XMonad.Hooks.EwmhDesktops" together with+-- @wmctrl@. -- -- This is the example of a client: -- -- > import Graphics.X11.Xlib -- > import Graphics.X11.Xlib.Extras -- > import System.Environment+-- > import System.IO -- > import Data.Char--- >--- > usage :: String -> String--- > usage n = "Usage: " ++ n ++ " command number\nSend a command number to a running instance of XMonad"--- >+-- > -- > main :: IO ()--- > main = do--- > args <- getArgs--- > pn <- getProgName--- > let com = case args of--- > [] -> error $ usage pn--- > w -> (w !! 0)--- > sendCommand com--- >--- > sendCommand :: String -> IO ()--- > sendCommand s = do+-- > main = parse True "XMONAD_COMMAND" =<< getArgs+-- > +-- > parse :: Bool -> String -> [String] -> IO ()+-- > parse input addr args = case args of+-- > ["--"] | input -> repl addr+-- > | otherwise -> return ()+-- > ("--":xs) -> sendAll addr xs+-- > ("-a":a:xs) -> parse input a xs+-- > ("-h":_) -> showHelp+-- > ("--help":_) -> showHelp+-- > ("-?":_) -> showHelp+-- > (a@('-':_):_) -> hPutStrLn stderr ("Unknown option " ++ a)+-- > +-- > (x:xs) -> sendCommand addr x >> parse False addr xs+-- > [] | input -> repl addr+-- > | otherwise -> return ()+-- > +-- > +-- > repl :: String -> IO ()+-- > repl addr = do e <- isEOF+-- > case e of+-- > True -> return ()+-- > False -> do l <- getLine+-- > sendCommand addr l+-- > repl addr+-- > +-- > sendAll :: String -> [String] -> IO ()+-- > sendAll addr ss = foldr (\a b -> sendCommand addr a >> b) (return ()) ss+-- > +-- > sendCommand :: String -> String -> IO ()+-- > sendCommand addr s = do -- > d <- openDisplay "" -- > rw <- rootWindow d $ defaultScreen d--- > a <- internAtom d "XMONAD_COMMAND" False+-- > a <- internAtom d addr False+-- > m <- internAtom d s False -- > allocaXEvent $ \e -> do -- > setEventType e clientMessage--- > setClientMessageEvent e rw a 32 (fromIntegral (read s)) currentTime+-- > setClientMessageEvent e rw a 32 m currentTime -- > sendEvent d rw False structureNotifyMask e -- > sync d False+-- > +-- > showHelp :: IO ()+-- > showHelp = do pn <- getProgName+-- > putStrLn ("Send commands to a running instance of xmonad. xmonad.hs must be configured with XMonad.Hooks.ServerMode to work.\n-a atomname can be used at any point in the command line arguments to change which atom it is sending on.\nIf sent with no arguments or only -a atom arguments, it will read commands from stdin.\nEx:\n" ++ pn ++ " cmd1 cmd2\n" ++ pn ++ " -a XMONAD_COMMAND cmd1 cmd2 cmd3 -a XMONAD_PRINT hello world\n" ++ pn ++ " -a XMONAD_PRINT # will read data from stdin.\nThe atom defaults to XMONAD_COMMAND.") ----- compile with: @ghc --make sendCommand.hs@ --+-- compile with: @ghc --make xmonadctl.hs@+-- -- run with ----- > sendCommand command number+-- > xmonadctl command ----- For instance:+-- or with ----- > sendCommand 0+-- > $ xmonadctl+-- > command1+-- > command2+-- > .+-- > .+-- > .+-- > ^D ----- will ask to xmonad to print the list of command numbers in--- stderr (so you can read it in @~\/.xsession-errors@).+-- Usage will change depending on which event hook(s) you use. More examples are shown below.+-- ----------------------------------------------------------------------------- module XMonad.Hooks.ServerMode ( -- * Usage -- $usage- ServerMode (..)- , serverModeEventHook+ serverModeEventHook , serverModeEventHook'+ , serverModeEventHookCmd+ , serverModeEventHookCmd'+ , serverModeEventHookF ) where import Control.Monad (when)+import Data.Maybe import Data.Monoid import System.IO @@ -75,31 +110,64 @@ -- @~\/.xmonad\/xmonad.hs@: -- -- > import XMonad.Hooks.ServerMode--- > import XMonad.Actions.Commands ----- Then edit your @handleEventHook@ by adding the 'serverModeEventHook':------ > main = xmonad defaultConfig { handleEventHook = serverModeEventHook }-----data ServerMode = ServerMode deriving ( Show, Read )+-- Then edit your @handleEventHook@ by adding the appropriate event hook from below -- | Executes a command of the list when receiving its index via a special ClientMessageEvent--- (indexing starts at 1)+-- (indexing starts at 1). Sending index 0 will ask xmonad to print the list of command numbers+-- in stderr (so that you can read it in @~\/.xsession-errors@). Uses "XMonad.Actions.Commands#defaultCommands" as the default.+--+-- > main = xmonad def { handleEventHook = serverModeEventHook }+-- +-- > xmonadctl 0 # tells xmonad to output command list+-- > xmonadctl 1 # tells xmonad to switch to workspace 1+-- serverModeEventHook :: Event -> X All serverModeEventHook = serverModeEventHook' defaultCommands -- | serverModeEventHook' additionally takes an action to generate the list of -- commands. serverModeEventHook' :: X [(String,X ())] -> Event -> X All-serverModeEventHook' cmdAction (ClientMessageEvent {ev_message_type = mt, ev_data = dt}) = do+serverModeEventHook' cmdAction ev = serverModeEventHookF "XMONAD_COMMAND" (sequence_ . map helper . words) ev+ where helper cmd = do cl <- cmdAction+ case lookup cmd (zip (map show [1 :: Integer ..]) cl) of+ Just (_,action) -> action+ Nothing -> mapM_ (io . hPutStrLn stderr) . listOfCommands $ cl+ listOfCommands cl = map (uncurry (++)) $ zip (map show ([1..] :: [Int])) $ map ((++) " - " . fst) cl+++-- | Executes a command of the list when receiving its name via a special ClientMessageEvent.+-- Uses "XMonad.Actions.Commands#defaultCommands" as the default.+--+-- > main = xmonad def { handleEventHook = serverModeEventHookCmd }+--+-- > xmonadctl run # Tells xmonad to generate a run prompt+--+serverModeEventHookCmd :: Event -> X All+serverModeEventHookCmd = serverModeEventHookCmd' defaultCommands++-- | Additionally takes an action to generate the list of commands+serverModeEventHookCmd' :: X [(String,X ())] -> Event -> X All+serverModeEventHookCmd' cmdAction ev = serverModeEventHookF "XMONAD_COMMAND" (sequence_ . map helper . words) ev+ where helper cmd = do cl <- cmdAction+ fromMaybe (io $ hPutStrLn stderr ("Couldn't find command " ++ cmd)) (lookup cmd cl)++-- | Listens for an atom, then executes a callback function whenever it hears it.+-- A trivial example that prints everything supplied to it on xmonad's standard out:+--+-- > main = xmonad def { handleEventHook = serverModeEventHookF "XMONAD_PRINT" (io . putStrLn) }+--+-- > xmonadctl -a XMONAD_PRINT "hello world"+--+serverModeEventHookF :: String -> (String -> X ()) -> Event -> X All+serverModeEventHookF key func (ClientMessageEvent {ev_message_type = mt, ev_data = dt}) = do d <- asks display- a <- io $ internAtom d "XMONAD_COMMAND" False- when (mt == a && dt /= []) $ do- cl <- cmdAction- let listOfCommands = map (uncurry (++)) . zip (map show ([1..] :: [Int])) . map ((++) " - " . fst)- case lookup (fromIntegral (head dt) :: Int) (zip [1..] cl) of- Just (_,action) -> action- Nothing -> mapM_ (io . hPutStrLn stderr) . listOfCommands $ cl+ atm <- io $ internAtom d key False+ when (mt == atm && dt /= []) $ do+ let atom = fromIntegral $ toInteger $ foldr1 (\a b -> a + (b*2^(32::Int))) dt+ 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)-serverModeEventHook' _ _ = return (All True)+serverModeEventHookF _ _ _ = return (All True)
XMonad/Hooks/ToggleHook.hs view
@@ -85,12 +85,12 @@ -- and adding 'toggleHook name hook' to your 'ManageHook' where @name@ is the -- name of the hook and @hook@ is the hook to execute based on the state. ----- > myManageHook = toggleHook "float" doFloat <+> manageHook defaultConfig+-- > myManageHook = toggleHook "float" doFloat <+> manageHook def -- -- Additionally, toggleHook' is provided to toggle between two hooks (rather -- than on/off). ----- > myManageHook = toggleHook' "oldfocus" (const id) W.focusWindow <+> manageHook defaultConfig+-- > myManageHook = toggleHook' "oldfocus" (const id) W.focusWindow <+> manageHook def -- -- The 'hookNext' and 'toggleHookNext' functions can be used in key -- bindings to set whether the hook is applied or not.
XMonad/Hooks/UrgencyHook.hs view
@@ -61,6 +61,7 @@ NoUrgencyHook(..), BorderUrgencyHook(..), FocusHook(..),+ filterUrgencyHook, minutes, seconds, -- * Stuff for developers: readUrgents, withUrgents,@@ -78,14 +79,16 @@ import qualified XMonad.Util.ExtensibleState as XS import XMonad.Util.NamedWindows (getName) import XMonad.Util.Timer (TimerId, startTimer, handleTimer)+import XMonad.Util.WindowProperties (getProp32) import Control.Applicative ((<$>)) import Control.Monad (when) import Data.Bits (testBit) import Data.List (delete, (\\))-import Data.Maybe (listToMaybe, maybeToList)+import Data.Maybe (listToMaybe, maybeToList, fromMaybe) import qualified Data.Set as S import System.IO (hPutStrLn, stderr)+import Foreign.C.Types (CLong) -- $usage --@@ -104,7 +107,7 @@ -- 'withUrgencyHook'. For example: -- -- > main = xmonad $ withUrgencyHook dzenUrgencyHook { args = ["-bg", "darkgreen", "-xs", "1"] }--- > $ defaultConfig+-- > $ def -- -- This will pop up a dzen bar for five seconds telling you you've got an -- urgent window.@@ -116,7 +119,7 @@ -- extra popup, install NoUrgencyHook, as so: -- -- > main = xmonad $ withUrgencyHook NoUrgencyHook--- > $ defaultConfig+-- > $ def -- -- Now, your "XMonad.Hooks.DynamicLog" must be set up to display the urgent -- windows. If you're using the 'dzen' or 'dzenPP' functions from that module,@@ -257,7 +260,7 @@ -- | The default 'UrgencyConfig'. suppressWhen = Visible, remindWhen = Dont. -- Use a variation of this in your config just as you use a variation of--- defaultConfig for your xmonad definition.+-- 'def' for your xmonad definition. urgencyConfig :: UrgencyConfig urgencyConfig = UrgencyConfig { suppressWhen = Visible, remindWhen = Dont } @@ -310,12 +313,34 @@ adjustReminders :: ([Reminder] -> [Reminder]) -> X () adjustReminders = XS.modify -clearUrgency :: Window -> X ()-clearUrgency w = adjustUrgents (delete w) >> adjustReminders (filter $ (w /=) . window) data WithUrgencyHook h = WithUrgencyHook h UrgencyConfig deriving (Read, Show) +-- | Change the _NET_WM_STATE property by applying a function to the list of atoms.+changeNetWMState :: Display -> Window -> ([CLong] -> [CLong]) -> X ()+changeNetWMState dpy w f = do+ wmstate <- getAtom "_NET_WM_STATE"+ wstate <- fromMaybe [] `fmap` getProp32 wmstate w+ let ptype = 4 -- atom property type for changeProperty+ io $ changeProperty32 dpy w wmstate ptype propModeReplace (f wstate)+ return ()++-- | Add an atom to the _NET_WM_STATE property.+addNetWMState :: Display -> Window -> Atom -> X ()+addNetWMState dpy w atom = changeNetWMState dpy w $ ((fromIntegral atom):)++-- | Remove an atom from the _NET_WM_STATE property.+removeNetWMState :: Display -> Window -> Atom -> X ()+removeNetWMState dpy w atom = changeNetWMState dpy w $ delete (fromIntegral atom)++-- | Get the _NET_WM_STATE propertly as a [CLong]+getNetWMState :: Window -> X [CLong]+getNetWMState w = do+ a_wmstate <- getAtom "_NET_WM_STATE"+ fromMaybe [] `fmap` getProp32 a_wmstate w+ + -- The Non-ICCCM Manifesto: -- Note: Some non-standard choices have been made in this implementation to -- account for the fact that things are different in a tiling window manager:@@ -331,20 +356,40 @@ handleEvent :: UrgencyHook h => WithUrgencyHook h -> Event -> X () handleEvent wuh event = case event of+ -- WM_HINTS urgency flag PropertyEvent { ev_event_type = t, ev_atom = a, ev_window = w } -> do when (t == propertyNotify && a == wM_HINTS) $ withDisplay $ \dpy -> do WMHints { wmh_flags = flags } <- io $ getWMHints dpy w- if (testBit flags urgencyHintBit) then do- adjustUrgents (\ws -> if elem w ws then ws else w : ws)- callUrgencyHook wuh w- else- clearUrgency w- userCodeDef () =<< asks (logHook . config)+ if (testBit flags urgencyHintBit) then markUrgent w else markNotUrgent w+ -- Window destroyed DestroyWindowEvent {ev_window = w} ->- clearUrgency w+ markNotUrgent w+ -- _NET_WM_STATE_DEMANDS_ATTENTION requested by client+ ClientMessageEvent {ev_event_display = dpy, ev_window = w, ev_message_type = t, ev_data = action:atoms} -> do+ a_wmstate <- getAtom "_NET_WM_STATE"+ a_da <- getAtom "_NET_WM_STATE_DEMANDS_ATTENTION"+ wstate <- getNetWMState w+ let demandsAttention = fromIntegral a_da `elem` wstate+ remove = 0+ add = 1+ toggle = 2+ when (t == a_wmstate && fromIntegral a_da `elem` atoms) $ do+ when (action == add || (action == toggle && not demandsAttention)) $ do+ markUrgent w+ addNetWMState dpy w a_da+ when (action == remove || (action == toggle && demandsAttention)) $ do+ markNotUrgent w+ removeNetWMState dpy w a_da _ -> mapM_ handleReminder =<< readReminders where handleReminder reminder = handleTimer (timer reminder) event $ reminderHook wuh reminder+ markUrgent w = do+ adjustUrgents (\ws -> if elem w ws then ws else w : ws)+ callUrgencyHook wuh w+ userCodeDef () =<< asks (logHook . config)+ markNotUrgent w = do+ adjustUrgents (delete w) >> adjustReminders (filter $ (w /=) . window)+ userCodeDef () =<< asks (logHook . config) callUrgencyHook :: UrgencyHook h => WithUrgencyHook h -> Window -> X () callUrgencyHook (WithUrgencyHook hook UrgencyConfig { suppressWhen = sw, remindWhen = rw }) w =@@ -378,6 +423,9 @@ cleanupUrgents :: SuppressWhen -> X () cleanupUrgents sw = do sw' <- suppressibleWindows sw+ a_da <- getAtom "_NET_WM_STATE_DEMANDS_ATTENTION"+ dpy <- withDisplay (\dpy -> return dpy)+ mapM_ (\w -> removeNetWMState dpy w a_da) sw' adjustUrgents (\\ sw') >> adjustReminders (filter $ ((`notElem` sw') . window)) suppressibleWindows :: SuppressWhen -> X [Window]@@ -481,3 +529,18 @@ instance UrgencyHook StdoutUrgencyHook where urgencyHook _ w = io $ putStrLn $ "Urgent: " ++ show w++-- | urgencyhook such that windows on certain workspaces+-- never get urgency set.+--+-- Useful for scratchpad workspaces perhaps:+--+-- > main = xmonad (withUrgencyHook (filterUrgencyHook ["NSP", "SP"]) defaultConfig)+filterUrgencyHook :: [WorkspaceId] -> Window -> X ()+filterUrgencyHook skips w = do+ ws <- gets windowset+ case W.findTag w ws of+ Just tag -> when (tag `elem` skips)+ $ adjustUrgents (delete w)+ _ -> return ()+
+ XMonad/Hooks/WallpaperSetter.hs view
@@ -0,0 +1,223 @@+{-# LANGUAGE DeriveDataTypeable #-}+-----------------------------------+-- |+-- Module : XMonad.Hooks.WallpaperSetter+-- Copyright : (c) Anton Pirogov, 2014+-- License : BSD3+--+-- Maintainer : Anton Pirogov <anton.pirogov@gmail.com>+-- Stability : unstable+-- Portability : unportable+--+-- Log hook which changes the wallpapers depending on visible workspaces.+-----------------------------------+module XMonad.Hooks.WallpaperSetter (+ -- * Usage+ -- $usage+ wallpaperSetter+, WallpaperConf(..)+, Wallpaper(..)+, WallpaperList(..)+, defWallpaperConf+, defWPNames+ -- *TODO+ -- $todo+) where+import XMonad+import qualified XMonad.StackSet as S+import qualified XMonad.Util.ExtensibleState as XS++import System.IO+import System.Process+import System.Directory (getHomeDirectory, doesFileExist, doesDirectoryExist, getDirectoryContents)+import System.FilePath ((</>))+import System.Random (randomRIO)++import qualified Data.Map as M+import Data.List (intersperse, sortBy)+import Data.Char (isAlphaNum)+import Data.Ord (comparing)++import Control.Monad+import Control.Applicative+import Data.Maybe+import Data.Monoid++-- $usage+-- This module requires imagemagick and feh to be installed, as these are utilized+-- for the required image transformations and the actual setting of the wallpaper.+--+-- This was especially tested with multi-head setups - if you have two monitors and swap+-- the workspaces, the wallpapers will be swapped too, scaled accordingly and rotated if necessary+-- (e.g. if you are using your monitor rotated but only have wide wallpapers).+--+-- Add a log hook like this:+--+-- > myWorkspaces = ["1:main","2:misc","3","4"]+-- > ...+-- > main = xmonad $ defaultConfig {+-- > logHook = wallpaperSetter defWallpaperConf {+-- > wallpapers = defWPNames myWorkspaces+-- > <> WallpaperList [("1:main",WallpaperDir "1")]+-- > }+-- > }+-- > ...++-- $todo+-- * implement a kind of image cache like in wallpaperd to remove or at least reduce the lag+--+-- * find out how to merge multiple images from stdin to one (-> for caching all pictures in memory)++-- | internal. to use XMonad state for memory in-between log-hook calls and remember PID of old external call+data WCState = WCState (Maybe [WorkspaceId]) (Maybe ProcessHandle) deriving Typeable+instance ExtensionClass WCState where+ initialValue = WCState Nothing Nothing++-- | Represents a wallpaper+data Wallpaper = WallpaperFix FilePath -- ^ Single, fixed wallpaper+ | WallpaperDir FilePath -- ^ Random wallpaper from this subdirectory+ deriving (Eq, Show, Read)++newtype WallpaperList = WallpaperList [(WorkspaceId, Wallpaper)]+ deriving (Show,Read)++instance Monoid WallpaperList where+ mempty = WallpaperList []+ mappend (WallpaperList w1) (WallpaperList w2) =+ WallpaperList $ M.toList $ (M.fromList w2) `M.union` (M.fromList w1)++-- | Complete wallpaper configuration passed to the hook+data WallpaperConf = WallpaperConf {+ wallpaperBaseDir :: FilePath -- ^ Where the wallpapers reside (if empty, will look in \~\/.wallpapers/)+ , wallpapers :: WallpaperList -- ^ List of the wallpaper associations for workspaces+ } deriving (Show, Read)++-- | default configuration. looks in \~\/.wallpapers/ for WORKSPACEID.jpg+defWallpaperConf :: WallpaperConf+defWallpaperConf = WallpaperConf "" $ WallpaperList []++instance Default WallpaperConf where+ def = defWallpaperConf++-- |returns the default association list (maps name to name.jpg, non-alphanumeric characters are omitted)+defWPNames :: [WorkspaceId] -> WallpaperList+defWPNames xs = WallpaperList $ map (\x -> (x,WallpaperFix (filter isAlphaNum x++".jpg"))) xs++-- | Add this to your log hook with the workspace configuration as argument.+wallpaperSetter :: WallpaperConf -> X ()+wallpaperSetter wpconf = do+ WCState oldws h <- XS.get+ visws <- getVisibleWorkspaces+ when (Just visws /= oldws) $ do++ wpconf' <- completeWPConf wpconf+ wspicpaths <- getPicPathsAndWSRects wpconf'++ -- terminate old call if any to prevent unnecessary CPU overload when switching WS too fast+ case h of+ Nothing -> return ()+ Just pid -> liftIO $ terminateProcess pid++ handle <- applyWallpaper wspicpaths+ XS.put $ WCState (Just visws) $ Just handle++-- Helper functions+-------------------++-- | Picks a random element from a list+pickFrom :: [a] -> IO a+pickFrom list = do+ i <- randomRIO (0,length list - 1)+ return $ list !! i++-- | get absolute picture path of the given wallpaper picture+-- or select a random one if it is a directory+getPicPath :: WallpaperConf -> Wallpaper -> IO (Maybe FilePath)+getPicPath conf (WallpaperDir dir) = do+ direxists <- doesDirectoryExist $ wallpaperBaseDir conf </> dir+ if direxists+ then do files <- getDirectoryContents $ wallpaperBaseDir conf </> dir+ let files' = filter ((/='.').head) files+ file <- pickFrom files'+ return $ Just $ wallpaperBaseDir conf </> dir </> file+ else return Nothing+getPicPath conf (WallpaperFix file) = do+ exist <- doesFileExist path+ return $ if exist then Just path else Nothing+ where path = wallpaperBaseDir conf </> file++-- | Take a path to a picture, return (width, height) if the path is a valid picture+-- (requires imagemagick tool identify to be installed)+getPicRes :: FilePath -> IO (Maybe (Int,Int))+getPicRes picpath = do+ (_, Just outh,_,_pid) <- createProcess $ (proc "identify" ["-format", "%w %h", picpath]) { std_out = CreatePipe }+ output <- hGetContents outh+ return $ case map reads (words output) of+ -- mapM Text.Read.readMaybe is better but only in ghc>=7.6+ [[(w,"")],[(h,"")]] -> Just (w,h)+ _ -> Nothing+++-- |complete unset fields to default values (wallpaper directory = ~/.wallpapers,+-- expects a file "NAME.jpg" for each workspace named NAME)+completeWPConf :: WallpaperConf -> X WallpaperConf+completeWPConf (WallpaperConf dir (WallpaperList ws)) = do+ home <- liftIO getHomeDirectory+ winset <- gets windowset+ let tags = map S.tag $ S.workspaces winset+ dir' = if null dir then home </> ".wallpapers" else dir+ ws' = if null ws then defWPNames tags else WallpaperList ws+ return (WallpaperConf dir' ws')++getVisibleWorkspaces :: X [WorkspaceId]+getVisibleWorkspaces = do+ winset <- gets windowset+ return $ map (S.tag . S.workspace) . sortBy (comparing S.screen) $ S.current winset : S.visible winset++getPicPathsAndWSRects :: WallpaperConf -> X [(Rectangle, FilePath)]+getPicPathsAndWSRects wpconf = do+ winset <- gets windowset+ paths <- liftIO getPicPaths+ visws <- getVisibleWorkspaces+ let visscr = S.current winset : S.visible winset+ visrects = M.fromList $ map (\x -> ((S.tag . S.workspace) x, S.screenDetail x)) visscr+ hasPicAndIsVisible (n, mp) = n `elem` visws && (isJust mp)+ getRect tag = screenRect $ fromJust $ M.lookup tag visrects+ foundpaths = map (\(n,Just p)->(getRect n,p)) $ filter hasPicAndIsVisible paths+ return foundpaths+ where getPicPaths = mapM (\(x,y) -> getPicPath wpconf y+ >>= \p -> return (x,p)) wl+ WallpaperList wl = wallpapers wpconf++-- | Gets a list of geometry rectangles and filenames, builds and sets wallpaper+applyWallpaper :: [(Rectangle, FilePath)] -> X ProcessHandle+applyWallpaper parts = do+ winset <- gets windowset+ let (vx,vy) = getVScreenDim winset+ layers <- liftIO $ mapM layerCommand parts+ let basepart ="convert -size "++show vx++"x"++show vy++" xc:black "+ endpart =" jpg:- | feh --no-xinerama --bg-tile --no-fehbg -"+ cmd = basepart ++ (concat $ intersperse " " layers) ++ endpart+ liftIO $ runCommand cmd+++getVScreenDim :: S.StackSet i l a sid ScreenDetail -> (Integer, Integer)+getVScreenDim = foldr maxXY (0,0) . map (screenRect . S.screenDetail) . S.screens+ where maxXY (Rectangle x y w h) (mx,my) = ( fromIntegral ((fromIntegral x)+w) `max` mx+ , fromIntegral ((fromIntegral y)+h) `max` my )++needsRotation :: Rectangle -> (Int,Int) -> Bool+needsRotation rect (px,py) = let wratio, pratio :: Double+ wratio = (fromIntegral $ rect_width rect) / (fromIntegral $ rect_height rect)+ pratio = fromIntegral px / fromIntegral py+ in wratio > 1 && pratio < 1 || wratio < 1 && pratio > 1++layerCommand :: (Rectangle, FilePath) -> IO String+layerCommand (rect, path) = do+ res <- getPicRes path+ return $ case needsRotation rect <$> res of+ Nothing -> ""+ Just rotate ->+ " \\( '"++path++"' "++(if rotate then "-rotate 90 " else "")+ ++ " -scale "++(show$rect_width rect)++"x"++(show$rect_height rect)++"! \\)"+ ++ " -geometry +"++(show$rect_x rect)++"+"++(show$rect_y rect)++" -composite "
XMonad/Hooks/WorkspaceByPos.hs view
@@ -33,9 +33,9 @@ -- -- > import XMonad.Hooks.WorkspaceByPos -- >--- > myManageHook = workspaceByPos <+> manageHook defaultConfig+-- > myManageHook = workspaceByPos <+> manageHook def -- >--- > main = xmonad defaultConfig { manageHook = myManageHook }+-- > main = xmonad def { manageHook = myManageHook } workspaceByPos :: ManageHook workspaceByPos = (maybe idHook doShift <=< liftX . needsMoving) =<< ask
+ XMonad/Hooks/WorkspaceHistory.hs view
@@ -0,0 +1,74 @@+{-# LANGUAGE DeriveDataTypeable #-}++-----------------------------------------------------------------------------+-- |+-- Module : XMonad.Hooks.WorkspaceHistory+-- Copyright : (c) 2013 Dmitri Iouchtchenko+-- License : BSD3-style (see LICENSE)+--+-- Maintainer : Dmitri Iouchtchenko <johnnyspoon@gmail.com>+-- Stability : unstable+-- Portability : unportable+--+-- Keeps track of workspace viewing order.+--+-----------------------------------------------------------------------------++module XMonad.Hooks.WorkspaceHistory+ ( -- * Usage+ -- $usage++ -- * Hooking+ workspaceHistoryHook++ -- * Querying+ , workspaceHistory++ ) where++import XMonad+import XMonad.StackSet (currentTag)+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@:+--+-- > import XMonad.Hooks.WorkspaceHistory (workspaceHistoryHook)+--+-- Then add the hook to your 'logHook':+--+-- > main = xmonad $ def+-- > { ...+-- > , logHook = ... >> workspaceHistoryHook >> ...+-- > , ...+-- > }+--+-- To make use of the collected data, a query function is provided.++data WorkspaceHistory =+ WorkspaceHistory { history :: [WorkspaceId] -- ^ Workspaces in reverse-chronological order.+ }+ deriving (Typeable, Read, Show)++instance ExtensionClass WorkspaceHistory where+ initialValue = WorkspaceHistory []+ extensionType = PersistentExtension++-- | A 'logHook' that keeps track of the order in which workspaces have+-- been viewed.+workspaceHistoryHook :: X ()+workspaceHistoryHook = gets (currentTag . windowset) >>= (XS.modify . makeFirst)++-- | A list of workspace tags in the order they have been viewed, with the+-- most recent first. No duplicates are present, but not all workspaces are+-- guaranteed to appear, and there may be workspaces that no longer exist.+workspaceHistory :: X [WorkspaceId]+workspaceHistory = XS.gets history+++-- | Cons the 'WorkspaceId' onto the 'WorkspaceHistory' if it is not+-- already there, or move it to the front if it is.+makeFirst :: WorkspaceId -> WorkspaceHistory -> WorkspaceHistory+makeFirst w v = let (xs, ys) = break (w ==) $ history v+ in v { history = w : (xs ++ drop 1 ys) }
XMonad/Layout/Accordion.hs view
@@ -31,7 +31,7 @@ -- Then edit your @layoutHook@ by adding the Accordion layout: -- -- > myLayout = Accordion ||| Full ||| etc..--- > main = xmonad defaultConfig { layoutHook = myLayout }+-- > main = xmonad def { layoutHook = myLayout } -- -- For more detailed instructions on editing the layoutHook see: --
+ XMonad/Layout/AvoidFloats.hs view
@@ -0,0 +1,239 @@+{-# LANGUAGE PatternGuards, FlexibleContexts, FlexibleInstances, MultiParamTypeClasses, TypeSynonymInstances, ParallelListComp, DeriveDataTypeable #-}++-----------------------------------------------------------------------------+-- |+-- Module : XMonad.Layout.AvoidFloats+-- Copyright : (c) 2014 Anders Engstrom <ankaan@gmail.com>+-- License : BSD3-style (see LICENSE)+--+-- Maintainer : (c) Anders Engstrom <ankaan@gmail.com>+-- Stability : unstable+-- Portability : unportable+--+-- Find a maximum empty rectangle around floating windows and use that area+-- to display non-floating windows.+--+-----------------------------------------------------------------------------++module XMonad.Layout.AvoidFloats (+ -- * Usage+ -- $usage+ avoidFloats,+ avoidFloats',+ AvoidFloatMsg(..),+ AvoidFloatItemMsg(..),+ ) where++import XMonad+import XMonad.Layout.LayoutModifier+import qualified XMonad.StackSet as W++import Data.List+import Data.Ord+import Data.Maybe+import qualified Data.Map as M+import qualified Data.Set as S++-- $usage+-- You can use this module with the following in your ~\/.xmonad\/xmonad.hs file:+--+-- > import XMonad.Layout.AvoidFloats+--+-- and modify the layouts to call avoidFloats on the layouts where you want the+-- non-floating windows to not be behind floating windows.+--+-- > layoutHook = ... ||| avoidFloats Full ||| ...+--+-- For more detailed instructions on editing the layoutHook see:+-- "XMonad.Doc.Extending#Editing_the_layout_hook"+--+-- Then add appropriate key bindings, for example:+--+-- > ,((modm .|. shiftMask, xK_b), sendMessage AvoidFloatToggle)+-- > ,((modm .|. controlMask, xK_b), withFocused $ sendMessage . AvoidFloatToggleItem)+-- > ,((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".+--+-- Note that this module is incompatible with an old way of configuring+-- "XMonad.Actions.FloatSnap". If you are having problems, please update your+-- configuration.++-- | Avoid floating windows unless the resulting area for windows would be too small.+-- In that case, use the whole screen as if this layout modifier wasn't there.+-- No windows are avoided by default, they need to be added using signals.+avoidFloats+ :: l a -- ^ Layout to modify.+ -> ModifiedLayout AvoidFloats l a+avoidFloats = avoidFloats' 100 100 False++-- | Avoid floating windows unless the resulting area for windows would be too small.+-- In that case, use the whole screen as if this layout modifier wasn't there.+avoidFloats'+ :: Int -- ^ Minimum width of the area used for non-floating windows.+ -> Int -- ^ Minimum height of the area used for non-floating windows.+ -> Bool -- ^ If floating windows should be avoided by default.+ -> l a -- ^ Layout to modify.+ -> ModifiedLayout AvoidFloats l a+avoidFloats' w h act = ModifiedLayout (AvoidFloats Nothing S.empty w h act)++data AvoidFloats a = AvoidFloats+ { cache :: Maybe ((M.Map a W.RationalRect, Rectangle), Rectangle)+ , chosen :: S.Set a+ , minw :: Int+ , minh :: Int+ , avoidAll :: Bool+ } deriving (Read, Show)++-- | Change the state of the whole avoid float layout modifier.+data AvoidFloatMsg+ = AvoidFloatToggle -- ^ Toggle between avoiding all or only selected.+ | AvoidFloatSet Bool -- ^ Set if all all floating windows should be avoided.+ | AvoidFloatClearItems -- ^ Clear the set of windows to specifically avoid.+ deriving (Typeable)+++-- | Change the state of the avoid float layout modifier conserning a specific window.+data AvoidFloatItemMsg a+ = AvoidFloatAddItem a -- ^ Add a window to always avoid.+ | AvoidFloatRemoveItem a -- ^ Stop always avoiding selected window.+ | AvoidFloatToggleItem a -- ^ Toggle between always avoiding selected window.+ deriving (Typeable)++instance Message AvoidFloatMsg+instance Typeable a => Message (AvoidFloatItemMsg a)++instance LayoutModifier AvoidFloats Window where+ modifyLayoutWithUpdate lm w r = withDisplay $ \d -> do+ floating <- gets $ W.floating . windowset+ case cache lm of+ Just (key, mer) | key == (floating,r) -> flip (,) Nothing `fmap` runLayout w mer+ _ -> do rs <- io $ map toRect `fmap` mapM (getWindowAttributes d) (filter shouldAvoid $ M.keys floating)+ let mer = maximumBy (comparing area) $ filter bigEnough $ maxEmptyRectangles r rs+ flip (,) (Just $ pruneWindows $ lm { cache = Just ((floating,r),mer) }) `fmap` runLayout w mer+ where+ toRect :: WindowAttributes -> Rectangle+ toRect wa = let b = fi $ wa_border_width wa+ in Rectangle (fi $ wa_x wa) (fi $ wa_y wa) (fi $ wa_width wa + 2*b) (fi $ wa_height wa + 2*b)+ + bigEnough :: Rectangle -> Bool+ bigEnough rect = rect_width rect >= fi (minw lm) && rect_height rect >= fi (minh lm)++ shouldAvoid a = avoidAll lm || a `S.member` chosen lm++ pureMess lm m+ | Just (AvoidFloatToggle) <- fromMessage m = Just $ lm { avoidAll = not (avoidAll lm), cache = Nothing }+ | Just (AvoidFloatSet s) <- fromMessage m, s /= avoidAll lm = Just $ lm { avoidAll = s, cache = Nothing }+ | Just (AvoidFloatClearItems) <- fromMessage m = Just $ lm { chosen = S.empty, cache = Nothing }+ | Just (AvoidFloatAddItem a) <- fromMessage m, a `S.notMember` chosen lm = Just $ lm { chosen = S.insert a (chosen lm), cache = Nothing }+ | Just (AvoidFloatRemoveItem a) <- fromMessage m, a `S.member` chosen lm = Just $ lm { chosen = S.delete a (chosen lm), cache = Nothing }+ | Just (AvoidFloatToggleItem a) <- fromMessage m = let op = if a `S.member` chosen lm then S.delete else S.insert+ in Just $ lm { chosen = op a (chosen lm), cache = Nothing }+ | otherwise = Nothing++pruneWindows :: AvoidFloats Window -> AvoidFloats Window+pruneWindows lm = case cache lm of+ Nothing -> lm+ Just ((floating,_),_) -> lm { chosen = S.filter (flip M.member floating) (chosen lm) }++-- | Find all maximum empty rectangles (MERs) that are axis aligned. This is+-- done in O(n^2) time using a modified version of the algoprithm MERAlg 1+-- described in \"On the maximum empty rectangle problem\" by A. Naamad, D.T.+-- Lee and W.-L HSU. Published in Discrete Applied Mathematics 8 (1984.)+maxEmptyRectangles :: Rectangle -> [Rectangle] -> [Rectangle]+maxEmptyRectangles br rectangles = filter (\a -> area a > 0) $ upAndDownEdge ++ noneOrUpEdge ++ downEdge+ where+ upAndDownEdge = findGaps br rectangles+ noneOrUpEdge = concat $ map (everyLower br bottoms) bottoms+ downEdge = concat $ map maybeToList $ map (bottomEdge br bottoms) bottoms+ bottoms = sortBy (comparing bottom) $ splitContainers rectangles++everyLower :: Rectangle -> [Rectangle] -> Rectangle -> [Rectangle]+everyLower br bottoms r = let (rs, boundLeft, boundRight, boundRects) = foldr (everyUpper r) ([], left br, right br, reverse bottoms) bottoms+ (boundLeft', boundRight', _) = shrinkBounds boundLeft boundRight boundRects r (top br)+ in mkRect boundLeft' boundRight' (top br) (top r) ?: rs++everyUpper+ :: Rectangle -- ^ The current rectangle where the top edge is used.+ -> Rectangle -- ^ The current rectangle where the bottom edge is used.+ -> ([Rectangle],Int,Int,[Rectangle]) -- ^ List of MERs found so far, left bound, right bound and list of rectangles used for bounds.+ -> ([Rectangle],Int,Int,[Rectangle])+everyUpper lower upper (rs, boundLeft, boundRight, boundRects) = (r?:rs, boundLeft', boundRight', boundRects')+ where+ r = mkRect boundLeft' boundRight' (bottom upper) (top lower)+ (boundLeft', boundRight', boundRects') = shrinkBounds boundLeft boundRight boundRects lower (bottom upper)++shrinkBounds :: Int -> Int -> [Rectangle] -> Rectangle -> Int -> (Int, Int, [Rectangle])+shrinkBounds boundLeft boundRight boundRects lower upperLimit = (boundLeft', boundRight', boundRects')+ where+ (shrinkers, boundRects') = span (\a -> bottom a > upperLimit) boundRects+ (boundLeft', boundRight') = foldr (shrinkBounds' lower) (boundLeft, boundRight) $ filter (\a -> top a < top lower) shrinkers++shrinkBounds' :: Rectangle -> Rectangle -> (Int, Int) -> (Int, Int)+shrinkBounds' mr r (boundLeft, boundRight)+ | right r < right mr = (max boundLeft $ right r, boundRight)+ | left r > left mr = (boundLeft, min boundRight $ left r)+ | otherwise = (right r, left r) -- r is horizontally covering all of mr; make sure the area of this rectangle will always be 0.++bottomEdge :: Rectangle -> [Rectangle] -> Rectangle -> Maybe Rectangle+bottomEdge br bottoms r = let rs = filter (\a -> bottom r < bottom a && top a < bottom br) bottoms+ boundLeft = maximum $ left br : (filter (< right r) $ map right rs)+ boundRight = minimum $ right br : (filter (> left r) $ map left rs)+ in if any (\a -> left a <= left r && right r <= right a) rs+ then Nothing+ else mkRect boundLeft boundRight (bottom r) (bottom br)++-- | Split rectangles that horizontally fully contains another rectangle+-- without sharing either the left or right side.+splitContainers :: [Rectangle] -> [Rectangle]+splitContainers rects = splitContainers' [] $ sortBy (comparing rect_width) rects+ where+ splitContainers' :: [Rectangle] -> [Rectangle] -> [Rectangle]+ splitContainers' res [] = res+ splitContainers' res (r:rs) = splitContainers' (r:res) $ concat $ map (doSplit r) rs++ doSplit :: Rectangle -> Rectangle -> [Rectangle]+ doSplit guide r+ | left guide <= left r || right r <= right guide = [r]+ | otherwise = let w0 = fi (rect_x guide - rect_x r) + (rect_width guide `div` 2)+ w1 = rect_width r - w0+ in [ Rectangle (rect_x r) (rect_y r) w0 (rect_height r)+ , Rectangle (rect_x r + fi w0) (rect_y r) w1 (rect_height r)+ ]++-- | Find all horizontal gaps that are left empty from top to bottom of screen.+findGaps+ :: Rectangle -- ^ Bounding rectangle.+ -> [Rectangle] -- ^ List of all rectangles that can cover areas in the bounding rectangle.+ -> [Rectangle]+findGaps br rs = let (gaps,end) = foldr findGaps' ([], left br) $ sortBy (flip $ comparing left) $ filter inBounds rs+ lastgap = mkRect end (right br) (top br) (bottom br)+ in lastgap?:gaps+ where+ findGaps' :: Rectangle -> ([Rectangle], Int) -> ([Rectangle], Int)+ findGaps' r (gaps, end) = let gap = mkRect end (left r) (top br) (bottom br)+ in (gap?:gaps, max end (right r))++ inBounds :: Rectangle -> Bool+ inBounds r = left r < right br && left br < right r++fi :: (Integral a, Num b) => a -> b+fi x = fromIntegral x++(?:) :: Maybe a -> [a] -> [a]+Just x ?: xs = x:xs+_ ?: xs = xs++left, right, top, bottom, area :: Rectangle -> Int+left r = fi (rect_x r)+right r = fi (rect_x r) + fi (rect_width r)+top r = fi (rect_y r)+bottom r = fi (rect_y r) + fi (rect_height r)+area r = fi (rect_width r * rect_height r)++mkRect :: Int -> Int -> Int -> Int -> Maybe Rectangle+mkRect l r t b = let rect = Rectangle (fi l) (fi t) (fi $ max 0 $ r-l) (fi $ max 0 $ b-t)+ in if area rect > 0+ then Just rect+ else Nothing
+ XMonad/Layout/BinarySpacePartition.hs view
@@ -0,0 +1,793 @@+{-# LANGUAGE PatternGuards #-}+{-# LANGUAGE DoAndIfThenElse #-}+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, DeriveDataTypeable #-}+-----------------------------------------------------------------------------+-- |+-- Module : XMonad.Layout.BinarySpacePartition+-- Copyright : (c) 2013 Ben Weitzman <benweitzman@gmail.com>+-- 2015 Anton Pirogov <anton.pirogov@gmail.com>+-- License : BSD3-style (see LICENSE)+--+-- Maintainer : Ben Weitzman <benweitzman@gmail.com>+-- Stability : unstable+-- Portability : unportable+--+-- Layout where new windows will split the focused window in half, based off of BSPWM+--+-----------------------------------------------------------------------------++module XMonad.Layout.BinarySpacePartition (+ -- * Usage+ -- $usage+ emptyBSP+ , Rotate(..)+ , Swap(..)+ , ResizeDirectional(..)+ , TreeRotate(..)+ , TreeBalance(..)+ , FocusParent(..)+ , SelectMoveNode(..)+ , Direction2D(..)+ ) where++import XMonad+import qualified XMonad.StackSet as W+import XMonad.Util.Stack hiding (Zipper)+import XMonad.Util.Types++-- for mouse resizing+import XMonad.Layout.WindowArranger (WindowArrangerMsg(SetGeometry))+-- for "focus parent" node border+import XMonad.Util.XUtils++import qualified Data.Map as M+import qualified Data.Set as S+import Data.List ((\\), elemIndex, foldl')+import Data.Maybe (fromMaybe, isNothing, isJust, mapMaybe, catMaybes)+import Control.Applicative+import Control.Monad+import Data.Ratio ((%))++-- $usage+-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+--+-- > import XMonad.Layout.BinarySpacePartition+--+-- Then add the layout, using the default BSP (BinarySpacePartition)+--+-- > myLayout = emptyBSP ||| etc ..+--+-- It may be a good idea to use "XMonad.Actions.Navigation2D" to move between the windows.+--+-- This layout responds to SetGeometry and is compatible with e.g. "XMonad.Actions.MouseResize"+-- or "XMonad.Layout.BorderResize". You should probably try both to decide which is better for you,+-- if you want to be able to resize the splits with the mouse.+--+-- If you don't want to use the mouse, add the following key bindings to resize the splits with the keyboard:+--+-- > , ((modm .|. altMask, xK_l ), sendMessage $ ExpandTowards R)+-- > , ((modm .|. altMask, xK_h ), sendMessage $ ExpandTowards L)+-- > , ((modm .|. altMask, xK_j ), sendMessage $ ExpandTowards D)+-- > , ((modm .|. altMask, xK_k ), sendMessage $ ExpandTowards U)+-- > , ((modm .|. altMask .|. ctrlMask , xK_l ), sendMessage $ ShrinkFrom R)+-- > , ((modm .|. altMask .|. ctrlMask , xK_h ), sendMessage $ ShrinkFrom L)+-- > , ((modm .|. altMask .|. ctrlMask , xK_j ), sendMessage $ ShrinkFrom D)+-- > , ((modm .|. altMask .|. ctrlMask , xK_k ), sendMessage $ ShrinkFrom U)+-- > , ((modm, xK_r ), sendMessage Rotate)+-- > , ((modm, xK_s ), sendMessage Swap)+-- > , ((modm, xK_n ), sendMessage FocusParent)+-- > , ((modm .|. ctrlMask, xK_n ), sendMessage SelectNode)+-- > , ((modm .|. shiftMask, xK_n ), sendMessage MoveNode)+--+-- Here's an alternative key mapping, this time using additionalKeysP,+-- arrow keys, and slightly different behavior when resizing windows+--+-- > , ("M-M1-<Left>", sendMessage $ ExpandTowards L)+-- > , ("M-M1-<Right>", sendMessage $ ShrinkFrom L)+-- > , ("M-M1-<Up>", sendMessage $ ExpandTowards U)+-- > , ("M-M1-<Down>", sendMessage $ ShrinkFrom U)+-- > , ("M-M1-C-<Left>", sendMessage $ ShrinkFrom R)+-- > , ("M-M1-C-<Right>", sendMessage $ ExpandTowards R)+-- > , ("M-M1-C-<Up>", sendMessage $ ShrinkFrom D)+-- > , ("M-M1-C-<Down>", sendMessage $ ExpandTowards D)+-- > , ("M-s", sendMessage $ BSP.Swap)+-- > , ("M-M1-s", sendMessage $ Rotate) ]+--+-- If you have many windows open and the layout begins to look too hard to manage, you can 'Balance'+-- the layout, so that the current splittings are discarded and windows are tiled freshly in a way that+-- the split depth is minimized. You can combine this with 'Equalize', which does not change your tree,+-- but tunes the split ratios in a way that each window gets the same amount of space:+--+-- > , ((myModMask, xK_a), sendMessage Balance)+-- > , ((myModMask .|. shiftMask, xK_a), sendMessage Equalize)+--++-- |Message for rotating the binary tree around the parent node of the window to the left or right+data TreeRotate = RotateL | RotateR deriving Typeable+instance Message TreeRotate++-- |Message to balance the tree in some way (Balance retiles the windows, Equalize changes ratios)+data TreeBalance = Balance | Equalize deriving Typeable+instance Message TreeBalance++-- |Message for resizing one of the cells in the BSP+data ResizeDirectional = ExpandTowards Direction2D | ShrinkFrom Direction2D | MoveSplit Direction2D deriving Typeable+instance Message ResizeDirectional++-- |Message for rotating a split (horizontal/vertical) in the BSP+data Rotate = Rotate deriving Typeable+instance Message Rotate++-- |Message for swapping the left child of a split with the right child of split+data Swap = Swap deriving Typeable+instance Message Swap++-- |Message to cyclically select the parent node instead of the leaf+data FocusParent = FocusParent deriving Typeable+instance Message FocusParent++-- |Message to move nodes inside the tree+data SelectMoveNode = SelectNode | MoveNode deriving Typeable+instance Message SelectMoveNode++data Axis = Horizontal | Vertical deriving (Show, Read, Eq)++oppositeDirection :: Direction2D -> Direction2D+oppositeDirection U = D+oppositeDirection D = U+oppositeDirection L = R+oppositeDirection R = L++oppositeAxis :: Axis -> Axis+oppositeAxis Vertical = Horizontal+oppositeAxis Horizontal = Vertical++toAxis :: Direction2D -> Axis+toAxis U = Horizontal+toAxis D = Horizontal+toAxis L = Vertical+toAxis R = Vertical++split :: Axis -> Rational -> Rectangle -> (Rectangle, Rectangle)+split Horizontal r (Rectangle sx sy sw sh) = (r1, r2) where+ r1 = Rectangle sx sy sw sh'+ r2 = Rectangle sx (sy + fromIntegral sh') sw (sh - sh')+ sh' = floor $ fromIntegral sh * r+split Vertical r (Rectangle sx sy sw sh) = (r1, r2) where+ r1 = Rectangle sx sy sw' sh+ r2 = Rectangle (sx + fromIntegral sw') sy (sw - sw') sh+ sw' = floor $ fromIntegral sw * r++data Split = Split { axis :: Axis+ , ratio :: Rational+ } deriving (Show, Read, Eq)++oppositeSplit :: Split -> Split+oppositeSplit (Split d r) = Split (oppositeAxis d) r++increaseRatio :: Split -> Rational -> Split+increaseRatio (Split d r) delta = Split d (min 0.9 (max 0.1 (r + delta)))++resizeDiff :: Rational+resizeDiff = 0.05+++data Tree a = Leaf Int | Node { value :: a+ , left :: Tree a+ , right :: Tree a+ } deriving (Show, Read, Eq)++numLeaves :: Tree a -> Int+numLeaves (Leaf _) = 1+numLeaves (Node _ l r) = numLeaves l + numLeaves r++-- right or left rotation of a (sub)tree, no effect if rotation not possible+rotTree :: Direction2D -> Tree a -> Tree a+rotTree _ (Leaf n) = Leaf n+rotTree R n@(Node _ (Leaf _) _) = n+rotTree L n@(Node _ _ (Leaf _)) = n+rotTree R (Node sp (Node sp2 l2 r2) r) = Node sp2 l2 (Node sp r2 r)+rotTree L (Node sp l (Node sp2 l2 r2)) = Node sp2 (Node sp l l2) r2+rotTree _ t = t+++data Crumb a = LeftCrumb a (Tree a) | RightCrumb a (Tree a) deriving (Show, Read, Eq)++swapCrumb :: Crumb a -> Crumb a+swapCrumb (LeftCrumb s t) = RightCrumb s t+swapCrumb (RightCrumb s t) = LeftCrumb s t++parentVal :: Crumb a -> a+parentVal (LeftCrumb s _) = s+parentVal (RightCrumb s _) = s++modifyParentVal :: (a -> a) -> Crumb a -> Crumb a+modifyParentVal f (LeftCrumb s t) = LeftCrumb (f s) t+modifyParentVal f (RightCrumb s t) = RightCrumb (f s) t++type Zipper a = (Tree a, [Crumb a])++toZipper :: Tree a -> Zipper a+toZipper t = (t, [])++goLeft :: Zipper a -> Maybe (Zipper a)+goLeft (Leaf _, _) = Nothing+goLeft (Node x l r, bs) = Just (l, LeftCrumb x r:bs)++goRight :: Zipper a -> Maybe (Zipper a)+goRight (Leaf _, _) = Nothing+goRight (Node x l r, bs) = Just (r, RightCrumb x l:bs)++goUp :: Zipper a -> Maybe (Zipper a)+goUp (_, []) = Nothing+goUp (t, LeftCrumb x r:cs) = Just (Node x t r, cs)+goUp (t, RightCrumb x l:cs) = Just (Node x l t, cs)++goSibling :: Zipper a -> Maybe (Zipper a)+goSibling (_, []) = Nothing+goSibling z@(_, LeftCrumb _ _:_) = Just z >>= goUp >>= goRight+goSibling z@(_, RightCrumb _ _:_) = Just z >>= goUp >>= goLeft++top :: Zipper a -> Zipper a+top z = case goUp z of+ Nothing -> z+ Just z' -> top z'++toTree :: Zipper a -> Tree a+toTree = fst . top++goToNthLeaf :: Int -> Zipper a -> Maybe (Zipper a)+goToNthLeaf _ z@(Leaf _, _) = Just z+goToNthLeaf n z@(t, _) =+ if numLeaves (left t) > n+ then do z' <- goLeft z+ goToNthLeaf n z'+ else do z' <- goRight z+ goToNthLeaf (n - (numLeaves . left $ t)) z'++toggleSplits :: Tree Split -> Tree Split+toggleSplits (Leaf l) = Leaf l+toggleSplits (Node s l r) = Node (oppositeSplit s) (toggleSplits l) (toggleSplits r)++splitCurrent :: Zipper Split -> Maybe (Zipper Split)+splitCurrent (Leaf _, []) = Just (Node (Split Vertical 0.5) (Leaf 0) (Leaf 0), [])+splitCurrent (Leaf _, crumb:cs) = Just (Node (Split (oppositeAxis . axis . parentVal $ crumb) 0.5) (Leaf 0) (Leaf 0), crumb:cs)+splitCurrent (n, []) = Just (Node (Split Vertical 0.5) (Leaf 0) (toggleSplits n), [])+splitCurrent (n, crumb:cs) = Just (Node (Split (oppositeAxis . axis . parentVal $ crumb) 0.5) (Leaf 0) (toggleSplits n), crumb:cs)++removeCurrent :: Zipper a -> Maybe (Zipper a)+removeCurrent (Leaf _, LeftCrumb _ r:cs) = Just (r, cs)+removeCurrent (Leaf _, RightCrumb _ l:cs) = Just (l, cs)+removeCurrent (Leaf _, []) = Nothing+removeCurrent (Node _ (Leaf _) r@(Node _ _ _), cs) = Just (r, cs)+removeCurrent (Node _ l@(Node _ _ _) (Leaf _), cs) = Just (l, cs)+removeCurrent (Node _ (Leaf _) (Leaf _), cs) = Just (Leaf 0, cs)+removeCurrent z@(Node _ _ _, _) = goLeft z >>= removeCurrent++rotateCurrent :: Zipper Split -> Maybe (Zipper Split)+rotateCurrent l@(_, []) = Just l+rotateCurrent (n, c:cs) = Just (n, modifyParentVal oppositeSplit c:cs)++swapCurrent :: Zipper a -> Maybe (Zipper a)+swapCurrent l@(_, []) = Just l+swapCurrent (n, c:cs) = Just (n, swapCrumb c:cs)++isAllTheWay :: Direction2D -> Zipper Split -> Bool+isAllTheWay _ (_, []) = True+isAllTheWay R (_, LeftCrumb s _:_)+ | axis s == Vertical = False+isAllTheWay L (_, RightCrumb s _:_)+ | axis s == Vertical = False+isAllTheWay D (_, LeftCrumb s _:_)+ | axis s == Horizontal = False+isAllTheWay U (_, RightCrumb s _:_)+ | axis s == Horizontal = False+isAllTheWay dir z = fromMaybe False $ goUp z >>= Just . isAllTheWay dir++expandTreeTowards :: Direction2D -> Zipper Split -> Maybe (Zipper Split)+expandTreeTowards _ z@(_, []) = Just z+expandTreeTowards dir z+ | isAllTheWay dir z = shrinkTreeFrom (oppositeDirection dir) z+expandTreeTowards R (t, LeftCrumb s r:cs)+ | axis s == Vertical = Just (t, LeftCrumb (increaseRatio s resizeDiff) r:cs)+expandTreeTowards L (t, RightCrumb s l:cs)+ | axis s == Vertical = Just (t, RightCrumb (increaseRatio s (-resizeDiff)) l:cs)+expandTreeTowards D (t, LeftCrumb s r:cs)+ | axis s == Horizontal = Just (t, LeftCrumb (increaseRatio s resizeDiff) r:cs)+expandTreeTowards U (t, RightCrumb s l:cs)+ | axis s == Horizontal = Just (t, RightCrumb (increaseRatio s (-resizeDiff)) l:cs)+expandTreeTowards dir z = goUp z >>= expandTreeTowards dir++shrinkTreeFrom :: Direction2D -> Zipper Split -> Maybe (Zipper Split)+shrinkTreeFrom _ z@(_, []) = Just z+shrinkTreeFrom R z@(_, LeftCrumb s _:_)+ | axis s == Vertical = Just z >>= goSibling >>= expandTreeTowards L+shrinkTreeFrom L z@(_, RightCrumb s _:_)+ | axis s == Vertical = Just z >>= goSibling >>= expandTreeTowards R+shrinkTreeFrom D z@(_, LeftCrumb s _:_)+ | axis s == Horizontal = Just z >>= goSibling >>= expandTreeTowards U+shrinkTreeFrom U z@(_, RightCrumb s _:_)+ | axis s == Horizontal = Just z >>= goSibling >>= expandTreeTowards D+shrinkTreeFrom dir z = goUp z >>= shrinkTreeFrom dir++-- Direction2D refers to which direction the divider should move.+autoSizeTree :: Direction2D -> Zipper Split -> Maybe (Zipper Split)+autoSizeTree _ z@(_, []) = Just z+autoSizeTree d z =+ Just z >>= getSplit (toAxis d) >>= resizeTree d++-- resizing once found the correct split. YOU MUST FIND THE RIGHT SPLIT FIRST.+resizeTree :: Direction2D -> Zipper Split -> Maybe (Zipper Split)+resizeTree _ z@(_, []) = Just z+resizeTree R z@(_, LeftCrumb _ _:_) =+ Just z >>= expandTreeTowards R+resizeTree L z@(_, LeftCrumb _ _:_) =+ Just z >>= shrinkTreeFrom R+resizeTree U z@(_, LeftCrumb _ _:_) =+ Just z >>= shrinkTreeFrom D+resizeTree D z@(_, LeftCrumb _ _:_) =+ Just z >>= expandTreeTowards D+resizeTree R z@(_, RightCrumb _ _:_) =+ Just z >>= shrinkTreeFrom L+resizeTree L z@(_, RightCrumb _ _:_) =+ Just z >>= expandTreeTowards L+resizeTree U z@(_, RightCrumb _ _:_) =+ Just z >>= expandTreeTowards U+resizeTree D z@(_, RightCrumb _ _:_) =+ Just z >>= shrinkTreeFrom U++getSplit :: Axis -> Zipper Split -> Maybe (Zipper Split)+getSplit _ (_, []) = Nothing+getSplit d z =+ do let fs = findSplit d z+ if isNothing fs+ then findClosest d z+ else fs++findClosest :: Axis -> Zipper Split -> Maybe (Zipper Split)+findClosest _ z@(_, []) = Just z+findClosest d z@(_, LeftCrumb s _:_)+ | axis s == d = Just z+findClosest d z@(_, RightCrumb s _:_)+ | axis s == d = Just z+findClosest d z = goUp z >>= findClosest d++findSplit :: Axis -> Zipper Split -> Maybe (Zipper Split)+findSplit _ (_, []) = Nothing+findSplit d z@(_, LeftCrumb s _:_)+ | axis s == d = Just z+findSplit d z = goUp z >>= findSplit d++resizeSplit :: Direction2D -> (Rational,Rational) -> Zipper Split -> Maybe (Zipper Split)+resizeSplit _ _ z@(_, []) = Just z+resizeSplit dir (xsc,ysc) z = case goToBorder dir z of+ Nothing -> Just z+ Just (t, crumb) -> Just $ case dir of+ R -> (t{value=sp{ratio=scaleRatio (ratio sp) xsc}}, crumb)+ D -> (t{value=sp{ratio=scaleRatio (ratio sp) ysc}}, crumb)+ L -> (t{value=sp{ratio=1-scaleRatio (1-ratio sp) xsc}}, crumb)+ U -> (t{value=sp{ratio=1-scaleRatio (1-ratio sp) ysc}}, crumb)+ where sp = value t+ scaleRatio r fac = min 0.9 $ max 0.1 $ r*fac++-- starting from a leaf, go to node representing a border of the according window+goToBorder :: Direction2D -> Zipper Split -> Maybe (Zipper Split)+goToBorder L z@(_, RightCrumb (Split Vertical _) _:_) = goUp z+goToBorder L z = goUp z >>= goToBorder L+goToBorder R z@(_, LeftCrumb (Split Vertical _) _:_) = goUp z+goToBorder R z = goUp z >>= goToBorder R+goToBorder U z@(_, RightCrumb (Split Horizontal _) _:_) = goUp z+goToBorder U z = goUp z >>= goToBorder U+goToBorder D z@(_, LeftCrumb (Split Horizontal _) _:_) = goUp z+goToBorder D z = goUp z >>= goToBorder D++-- takes a list of indices and numerates the leaves of a given tree+numerate :: [Int] -> Tree a -> Tree a+numerate ns t = snd $ num ns t+ where num (n:nns) (Leaf _) = (nns, Leaf n)+ num [] (Leaf _) = ([], Leaf 0)+ num n (Node s l r) = (n'', Node s nl nr)+ where (n', nl) = num n l+ (n'', nr) = num n' r++-- return values of leaves from left to right as list+flatten :: Tree a -> [Int]+flatten (Leaf n) = [n]+flatten (Node _ l r) = flatten l++flatten r++-- adjust ratios to make window areas equal+equalize :: Zipper Split -> Maybe (Zipper Split)+equalize (t, cs) = Just (eql t, cs)+ where eql (Leaf n) = Leaf n+ eql n@(Node s l r) = Node s{ratio=fromIntegral (numLeaves l) % fromIntegral (numLeaves n)}+ (eql l) (eql r)++-- generate a symmetrical balanced tree for n leaves from given tree, preserving leaf labels+balancedTree :: Zipper Split -> Maybe (Zipper Split)+balancedTree (t, cs) = Just (numerate (flatten t) $ balanced (numLeaves t), cs)+ where balanced 1 = Leaf 0+ balanced 2 = Node (Split Horizontal 0.5) (Leaf 0) (Leaf 0)+ balanced m = Node (Split Horizontal 0.5) (balanced (m`div`2)) (balanced (m-m`div`2))++-- attempt to rotate splits optimally in order choose more quad-like rects+optimizeOrientation :: Rectangle -> Zipper Split -> Maybe (Zipper Split)+optimizeOrientation rct (t, cs) = Just (opt t rct, cs)+ where opt (Leaf v) _ = Leaf v+ opt (Node sp l r) rect = Node sp' (opt l lrect) (opt r rrect)+ where (Rectangle _ _ w1 h1,Rectangle _ _ w2 h2) = split (axis sp) (ratio sp) rect+ (Rectangle _ _ w3 h3,Rectangle _ _ w4 h4) = split (axis $ oppositeSplit sp) (ratio sp) rect+ f w h = if w > h then w'/h' else h'/w' where (w',h') = (fromIntegral w :: Double, fromIntegral h :: Double)+ wratio = min (f w1 h1) (f w2 h2)+ wratio' = min (f w3 h3) (f w4 h4)+ sp' = if wratio<wratio' then sp else oppositeSplit sp+ (lrect, rrect) = split (axis sp') (ratio sp') rect+++-- initially focused leaf, path from root to selected node, window ids of borders highlighting the selection+data NodeRef = NodeRef { refLeaf :: Int, refPath :: [Direction2D], refWins :: [Window] } deriving (Show,Read,Eq)+noRef = NodeRef (-1) [] []++goToNode :: NodeRef -> Zipper a -> Maybe (Zipper a)+goToNode (NodeRef _ dirs _) z = foldM gofun z dirs+ where gofun z' L = goLeft z'+ gofun z' R = goRight z'+ gofun _ _ = Nothing++toNodeRef :: Int -> Maybe (Zipper Split) -> NodeRef+toNodeRef _ Nothing = noRef+toNodeRef l (Just (_, cs)) = NodeRef l (reverse $ map crumbToDir cs) []+ where crumbToDir (LeftCrumb _ _) = L+ crumbToDir (RightCrumb _ _) = R++-- returns the leaf a noderef is leading to, if any+nodeRefToLeaf :: NodeRef -> Maybe (Zipper a) -> Maybe Int+nodeRefToLeaf n (Just z) = case goToNode n z of+ Just (Leaf l, _) -> Just l+ Just (Node _ _ _, _) -> Nothing+ Nothing -> Nothing+nodeRefToLeaf _ Nothing = Nothing++leafToNodeRef :: Int -> BinarySpacePartition a -> NodeRef+leafToNodeRef l b = toNodeRef l (makeZipper b >>= goToNthLeaf l)++data BinarySpacePartition a = BinarySpacePartition { getOldRects :: [(Window,Rectangle)]+ , getFocusedNode :: NodeRef+ , getSelectedNode :: NodeRef+ , getTree :: Maybe (Tree Split) } deriving (Show, Read,Eq)++-- | an empty BinarySpacePartition to use as a default for adding windows to.+emptyBSP :: BinarySpacePartition a+emptyBSP = BinarySpacePartition [] noRef noRef Nothing++makeBSP :: Tree Split -> BinarySpacePartition a+makeBSP = BinarySpacePartition [] noRef noRef . Just++makeZipper :: BinarySpacePartition a -> Maybe (Zipper Split)+makeZipper (BinarySpacePartition _ _ _ Nothing) = Nothing+makeZipper (BinarySpacePartition _ _ _ (Just t)) = Just . toZipper $ t++size :: BinarySpacePartition a -> Int+size = maybe 0 numLeaves . getTree++zipperToBinarySpacePartition :: Maybe (Zipper Split) -> BinarySpacePartition b+zipperToBinarySpacePartition Nothing = emptyBSP+zipperToBinarySpacePartition (Just z) = BinarySpacePartition [] noRef noRef . Just . toTree . top $ z++rectangles :: BinarySpacePartition a -> Rectangle -> [Rectangle]+rectangles (BinarySpacePartition _ _ _ Nothing) _ = []+rectangles (BinarySpacePartition _ _ _ (Just (Leaf _))) rootRect = [rootRect]+rectangles (BinarySpacePartition _ _ _ (Just node)) rootRect =+ rectangles (makeBSP . left $ node) leftBox +++ rectangles (makeBSP . right $ node) rightBox+ where (leftBox, rightBox) = split (axis info) (ratio info) rootRect+ info = value node++getNodeRect :: BinarySpacePartition a -> Rectangle -> NodeRef -> Rectangle+getNodeRect b r n = fromMaybe (Rectangle 0 0 1 1) (makeZipper b >>= goToNode n >>= getRect [])+ where getRect ls (_, []) = Just $ foldl (\r' (s,f) -> f $ split' s r') r ls+ getRect ls z@(_, LeftCrumb s _:_) = goUp z >>= getRect ((s,fst):ls)+ getRect ls z@(_, RightCrumb s _:_) = goUp z >>= getRect ((s,snd):ls)+ split' s = split (axis s) (ratio s)++doToNth :: (Zipper Split -> Maybe (Zipper Split)) -> BinarySpacePartition a -> BinarySpacePartition a+doToNth f b = b{getTree=getTree $ zipperToBinarySpacePartition $ makeZipper b >>= goToNode (getFocusedNode b) >>= f}++splitNth :: BinarySpacePartition a -> BinarySpacePartition a+splitNth (BinarySpacePartition _ _ _ Nothing) = makeBSP (Leaf 0)+splitNth b = doToNth splitCurrent b++removeNth :: BinarySpacePartition a -> BinarySpacePartition a+removeNth (BinarySpacePartition _ _ _ Nothing) = emptyBSP+removeNth (BinarySpacePartition _ _ _ (Just (Leaf _))) = emptyBSP+removeNth b = doToNth removeCurrent b++rotateNth :: BinarySpacePartition a -> BinarySpacePartition a+rotateNth (BinarySpacePartition _ _ _ Nothing) = emptyBSP+rotateNth b@(BinarySpacePartition _ _ _ (Just (Leaf _))) = b+rotateNth b = doToNth rotateCurrent b++swapNth :: BinarySpacePartition a -> BinarySpacePartition a+swapNth (BinarySpacePartition _ _ _ Nothing) = emptyBSP+swapNth b@(BinarySpacePartition _ _ _ (Just (Leaf _))) = b+swapNth b = doToNth swapCurrent b++growNthTowards :: Direction2D -> BinarySpacePartition a -> BinarySpacePartition a+growNthTowards _ (BinarySpacePartition _ _ _ Nothing) = emptyBSP+growNthTowards _ b@(BinarySpacePartition _ _ _ (Just (Leaf _))) = b+growNthTowards dir b = doToNth (expandTreeTowards dir) b++shrinkNthFrom :: Direction2D -> BinarySpacePartition a -> BinarySpacePartition a+shrinkNthFrom _ (BinarySpacePartition _ _ _ Nothing)= emptyBSP+shrinkNthFrom _ b@(BinarySpacePartition _ _ _ (Just (Leaf _))) = b+shrinkNthFrom dir b = doToNth (shrinkTreeFrom dir) b++autoSizeNth :: Direction2D -> BinarySpacePartition a -> BinarySpacePartition a+autoSizeNth _ (BinarySpacePartition _ _ _ Nothing) = emptyBSP+autoSizeNth _ b@(BinarySpacePartition _ _ _ (Just (Leaf _))) = b+autoSizeNth dir b = doToNth (autoSizeTree dir) b++resizeSplitNth :: Direction2D -> (Rational,Rational) -> BinarySpacePartition a -> BinarySpacePartition a+resizeSplitNth _ _ (BinarySpacePartition _ _ _ Nothing) = emptyBSP+resizeSplitNth _ _ b@(BinarySpacePartition _ _ _ (Just (Leaf _))) = b+resizeSplitNth dir sc b = doToNth (resizeSplit dir sc) b++-- rotate tree left or right around parent of nth leaf+rotateTreeNth :: Direction2D -> BinarySpacePartition a -> BinarySpacePartition a+rotateTreeNth _ (BinarySpacePartition _ _ _ Nothing) = emptyBSP+rotateTreeNth U b = b+rotateTreeNth D b = b+rotateTreeNth dir b@(BinarySpacePartition _ _ _ (Just _)) =+ doToNth (\t -> case goUp t of+ Nothing -> Just t+ Just (t', c) -> Just (rotTree dir t', c)) b++equalizeNth :: BinarySpacePartition a -> BinarySpacePartition a+equalizeNth (BinarySpacePartition _ _ _ Nothing) = emptyBSP+equalizeNth b@(BinarySpacePartition _ _ _ (Just (Leaf _))) = b+equalizeNth b = doToNth equalize b++rebalanceNth :: BinarySpacePartition a -> Rectangle -> BinarySpacePartition a+rebalanceNth (BinarySpacePartition _ _ _ Nothing) _ = emptyBSP+rebalanceNth b@(BinarySpacePartition _ _ _ (Just (Leaf _))) _ = b+rebalanceNth b r = doToNth (balancedTree >=> optimizeOrientation r) b++flattenLeaves :: BinarySpacePartition a -> [Int]+flattenLeaves (BinarySpacePartition _ _ _ Nothing) = []+flattenLeaves (BinarySpacePartition _ _ _ (Just t)) = flatten t++-- we do this before an action to look afterwards which leaves moved where+numerateLeaves :: BinarySpacePartition a -> BinarySpacePartition a+numerateLeaves b@(BinarySpacePartition _ _ _ Nothing) = b+numerateLeaves b@(BinarySpacePartition _ _ _ (Just t)) = b{getTree=Just $ numerate ns t}+ where ns = [0..(numLeaves t-1)]++-- if there is a selected and focused node and the focused is not a part of selected,+-- move selected node to be a child of focused node+moveNode :: BinarySpacePartition a -> BinarySpacePartition a+moveNode b@(BinarySpacePartition _ (NodeRef (-1) _ _) _ _) = b+moveNode b@(BinarySpacePartition _ _ (NodeRef (-1) _ _) _) = b+moveNode b@(BinarySpacePartition _ _ _ Nothing) = b+moveNode b@(BinarySpacePartition _ f s (Just ot)) =+ case makeZipper b >>= goToNode s of+ Just (n, LeftCrumb _ t:cs) -> b{getTree=Just $ insert n $ top (t, cs)}+ Just (n, RightCrumb _ t:cs) -> b{getTree=Just $ insert n $ top (t, cs)}+ _ -> b+ where insert t z = case goToNode f z of+ Nothing -> ot --return original tree (abort)+ Just (n, c:cs) -> toTree (Node (Split (oppositeAxis . axis . parentVal $ c) 0.5) t n, c:cs)+ Just (n, []) -> toTree (Node (Split Vertical 0.5) t n, [])++------------------------------------------++-- returns index of focused window or 0 for empty stack+index :: W.Stack a -> Int+index s = case toIndex (Just s) of+ (_, Nothing) -> 0+ (_, Just int) -> int++--move windows to new positions according to tree transformations, keeping focus on originally focused window+--CAREFUL here! introduce a bug here and have fun debugging as your windows start to disappear or explode+adjustStack :: Maybe (W.Stack Window) --original stack+ -> Maybe (W.Stack Window) --stack without floating windows+ -> [Window] --just floating windows of this WS+ -> Maybe (BinarySpacePartition Window) -- Tree with numbered leaves telling what to move where+ -> Maybe (W.Stack Window) --resulting stack+adjustStack orig Nothing _ _ = orig --no new stack -> no changes+adjustStack orig _ _ Nothing = orig --empty tree -> no changes+adjustStack orig s fw (Just b) =+ if length ls<length ws then orig --less leaves than non-floating windows -> tree incomplete, no changes+ else fromIndex ws' fid'+ where ws' = mapMaybe (`M.lookup` wsmap) ls ++ fw+ fid' = fromMaybe 0 $ elemIndex focused ws'+ wsmap = M.fromList $ zip [0..] ws -- map: old index in list -> window+ ls = flattenLeaves b -- get new index ordering from tree+ (ws,fid) = toIndex s+ focused = ws !! fromMaybe 0 fid++--replace the window stack of the managed workspace with our modified stack+replaceStack :: Maybe (W.Stack Window) -> X ()+replaceStack s = do+ st <- get+ let wset = windowset st+ cur = W.current wset+ wsp = W.workspace cur+ put st{windowset=wset{W.current=cur{W.workspace=wsp{W.stack=s}}}}++replaceFloating :: M.Map Window W.RationalRect -> X ()+replaceFloating wsm = do+ st <- get+ let wset = windowset st+ put st{windowset=wset{W.floating=wsm}}++-- some helpers to filter windows+--+getFloating :: X [Window]+getFloating = (M.keys . W.floating) <$> gets windowset -- all floating windows++getStackSet :: X (Maybe (W.Stack Window))+getStackSet = (W.stack . W.workspace . W.current) <$> gets windowset -- windows on this WS (with floating)++getScreenRect :: X Rectangle+getScreenRect = (screenRect . W.screenDetail . W.current) <$> gets windowset++withoutFloating :: [Window] -> Maybe (W.Stack Window) -> Maybe (W.Stack Window)+withoutFloating fs = maybe Nothing (unfloat fs)++-- ignore messages if current focus is on floating window, otherwise return stack without floating+unfloat :: [Window] -> W.Stack Window -> Maybe (W.Stack Window)+unfloat fs s = if W.focus s `elem` fs+ then Nothing+ else Just $ s{W.up = W.up s \\ fs, W.down = W.down s \\ fs}++instance LayoutClass BinarySpacePartition Window where+ doLayout b r s = do+ let b' = layout b+ b'' <- updateNodeRef b' (size b/=size b') r+ let rs = rectangles b'' r+ wrs = zip ws rs+ return (wrs, Just b''{getOldRects=wrs})+ where+ ws = W.integrate s+ l = length ws+ layout bsp+ | l == sz = bsp+ | l > sz = layout $ splitNth bsp+ | otherwise = layout $ removeNth bsp+ where sz = size bsp++ handleMessage b_orig m+ | Just msg@(SetGeometry _) <- fromMessage m = handleResize b msg+ | Just FocusParent <- fromMessage m = do+ let n = getFocusedNode b+ let n' = toNodeRef (refLeaf n) (makeZipper b >>= goToNode n >>= goUp)+ return $ Just b{getFocusedNode=n'{refWins=refWins n}}+ | Just SelectNode <- fromMessage m = do+ let n = getFocusedNode b+ let s = getSelectedNode b+ removeBorder $ refWins s+ let s' = if refLeaf n == refLeaf s && refPath n == refPath s+ then noRef else n{refWins=[]}+ return $ Just b{getSelectedNode=s'}+ | otherwise = do+ ws <- getStackSet+ fs <- getFloating+ r <- getScreenRect+ -- removeBorder $ refWins $ getSelectedNode b+ let lws = withoutFloating fs ws -- tiled windows on WS+ lfs = maybe [] W.integrate ws \\ maybe [] W.integrate lws -- untiled windows on WS+ b' = handleMesg r -- transform tree (concerns only tiled windows)+ ws' = adjustStack ws lws lfs b' -- apply transformation to window stack, reintegrate floating wins+ replaceStack ws'+ return b'+ where handleMesg r = msum [ fmap resize (fromMessage m)+ , fmap rotate (fromMessage m)+ , fmap swap (fromMessage m)+ , fmap rotateTr (fromMessage m)+ , fmap (balanceTr r) (fromMessage m)+ , fmap move (fromMessage m)+ ]+ resize (ExpandTowards dir) = growNthTowards dir b+ resize (ShrinkFrom dir) = shrinkNthFrom dir b+ resize (MoveSplit dir) = autoSizeNth dir b+ rotate Rotate = resetFoc $ rotateNth b+ swap Swap = resetFoc $ swapNth b+ rotateTr RotateL = resetFoc $ rotateTreeNth L b+ rotateTr RotateR = resetFoc $ rotateTreeNth R b+ balanceTr _ Equalize = resetFoc $ equalizeNth b+ balanceTr r Balance = resetFoc $ rebalanceNth b r+ move MoveNode = resetFoc $ moveNode b+ move SelectNode = b --should not happen here, is done above, as we need X monad++ b = numerateLeaves b_orig+ resetFoc bsp = bsp{getFocusedNode=(getFocusedNode bsp){refLeaf=(-1)}+ ,getSelectedNode=(getSelectedNode bsp){refLeaf=(-1)}}++ description _ = "BSP"++-- React to SetGeometry message to work with BorderResize/MouseResize+handleResize :: BinarySpacePartition Window -> WindowArrangerMsg -> X (Maybe (BinarySpacePartition Window))+handleResize b (SetGeometry newrect@(Rectangle _ _ w h)) = do+ ws <- getStackSet+ fs <- getFloating+ case W.focus <$> ws of+ Nothing -> return Nothing+ Just win -> do+ (_,_,_,_,_,mx,my,_) <- withDisplay (\d -> io $ queryPointer d win)+ let oldrect@(Rectangle _ _ ow oh) = fromMaybe (Rectangle 0 0 0 0) $ lookup win $ getOldRects b+ let (xsc,ysc) = (fi w % fi ow, fi h % fi oh)+ (xsc',ysc') = (rough xsc, rough ysc)+ dirs = changedDirs oldrect newrect (fi mx,fi my)+ n = elemIndex win $ maybe [] W.integrate $ withoutFloating fs ws+ -- unless (isNothing dir) $ debug $+ -- show (fi x-fi ox,fi y-fi oy) ++ show (fi w-fi ow,fi h-fi oh)+ -- ++ show dir ++ " " ++ show win ++ " " ++ show (mx,my)+ return $ case n of+ Just _ -> Just $ foldl' (\b' d -> resizeSplitNth d (xsc',ysc') b') b dirs+ Nothing -> Nothing --focused window is floating -> ignore+ where rough v = min 1.5 $ max 0.75 v -- extreme scale factors are forbidden+handleResize _ _ = return Nothing++-- find out which borders have been pulled. We need the old and new rects and the mouse coordinates+changedDirs :: Rectangle -> Rectangle -> (Int,Int) -> [Direction2D]+changedDirs (Rectangle _ _ ow oh) (Rectangle _ _ w h) (mx,my) = catMaybes [lr, ud]+ where lr = if ow==w then Nothing+ else Just (if (fi mx :: Double) > (fi ow :: Double)/2 then R else L)+ ud = if oh==h then Nothing+ else Just (if (fi my :: Double) > (fi oh :: Double)/2 then D else U)++-- node focus border helpers+----------------------------+updateNodeRef :: BinarySpacePartition Window -> Bool -> Rectangle -> X (BinarySpacePartition Window)+updateNodeRef b force r = do+ let n = getFocusedNode b+ let s = getSelectedNode b+ removeBorder (refWins n++refWins s)+ l <- getCurrFocused+ b' <- if refLeaf n /= l || refLeaf n == (-1) || force+ then return b{getFocusedNode=leafToNodeRef l b}+ else return b+ b'' <- if force then return b'{getSelectedNode=noRef} else return b'+ renderBorders r b''+ where getCurrFocused = maybe 0 index <$> (withoutFloating <$> getFloating <*> getStackSet)++-- create border around focused node if necessary+renderBorders :: Rectangle -> BinarySpacePartition a -> X (BinarySpacePartition a)+renderBorders r b = do+ let l = nodeRefToLeaf (getFocusedNode b) $ makeZipper b+ wssel <- if refLeaf (getSelectedNode b)/=(-1)+ then createBorder (getNodeRect b r (getSelectedNode b)) $ Just "#00ff00"+ else return []+ let b' = b{getSelectedNode=(getSelectedNode b){refWins=wssel}}+ if refLeaf (getFocusedNode b')==(-1) || isJust l || size b'<2 then return b'+ else do+ ws' <- createBorder (getNodeRect b' r (getFocusedNode b')) Nothing+ return b'{getFocusedNode=(getFocusedNode b'){refWins=ws'}}++-- create a window for each border line, show, add into stack and set floating+createBorder :: Rectangle -> Maybe String -> X [Window]+createBorder (Rectangle wx wy ww wh) c = do+ bw <- asks (borderWidth.config)+ bc <- case c of+ Nothing -> asks (focusedBorderColor.config)+ Just s -> return s+ let rects = [ Rectangle wx wy ww (fi bw)+ , Rectangle wx wy (fi bw) wh+ , Rectangle wx (wy+fi wh-fi bw) ww (fi bw)+ , Rectangle (wx+fi ww-fi bw) wy (fi bw) wh+ ]+ ws <- mapM (\r -> createNewWindow r Nothing bc False) rects+ showWindows ws+ maybe Nothing (\s -> Just s{W.down=W.down s ++ ws}) <$> getStackSet >>= replaceStack+ M.union (M.fromList $ zip ws $ map toRR rects) . W.floating . windowset <$> get >>= replaceFloating+ modify (\s -> s{mapped=mapped s `S.union` S.fromList ws})+ -- show <$> mapM isClient ws >>= debug+ return ws+ where toRR (Rectangle x y w h) = W.RationalRect (fi x) (fi y) (fi w) (fi h)++-- remove border line windows from stack + floating, kill+removeBorder :: [Window] -> X ()+removeBorder ws = do+ modify (\s -> s{mapped = mapped s `S.difference` S.fromList ws})+ flip (foldl (flip M.delete)) ws . W.floating . windowset <$> get >>= replaceFloating+ maybe Nothing (\s -> Just s{W.down=W.down s \\ ws}) <$> getStackSet >>= replaceStack+ deleteWindows ws
XMonad/Layout/BorderResize.hs view
@@ -40,7 +40,7 @@ -- -- > import XMonad.Layout.BorderResize -- > myLayout = borderResize (... layout setup that reacts to SetGeometry ...)--- > main = xmonad defaultConfig { layoutHook = myLayout }+-- > main = xmonad def { layoutHook = myLayout } -- type BorderBlueprint = (Rectangle, Glyph, BorderType)
XMonad/Layout/BoringWindows.hs view
@@ -49,7 +49,7 @@ -- Then edit your @layoutHook@ by adding the layout modifier: -- -- > myLayout = boringWindows (Full ||| etc..)--- > main = xmonad defaultConfig { layoutHook = myLayout }+-- > main = xmonad def { layoutHook = myLayout } -- -- Then to your keybindings, add: --
XMonad/Layout/ButtonDecoration.hs view
@@ -40,8 +40,8 @@ -- Then edit your @layoutHook@ by adding the ButtonDecoration to -- your layout: ----- > myL = buttonDeco shrinkText defaultThemeWithButtons (layoutHook defaultConfig)--- > main = xmonad defaultConfig { layoutHook = myL }+-- > myL = buttonDeco shrinkText defaultThemeWithButtons (layoutHook def)+-- > main = xmonad def { layoutHook = myL } -- buttonDeco :: (Eq a, Shrinker s) => s -> Theme
XMonad/Layout/Circle.hs view
@@ -32,7 +32,7 @@ -- Then edit your @layoutHook@ by adding the Circle layout: -- -- > myLayout = Circle ||| Full ||| etc..--- > main = xmonad defaultConfig { layoutHook = myLayout }+-- > main = xmonad def { layoutHook = myLayout } -- -- For more detailed instructions on editing the layoutHook see: --
XMonad/Layout/Cross.hs view
@@ -29,7 +29,7 @@ -- Then edit your @layoutHook@ by adding one of the Cross layouts: -- -- > myLayout = simpleCross ||| etc..--- > main = xmonad defaultConfig { layoutHook = myLayout }+-- > main = xmonad def { layoutHook = myLayout } -- -- apply a factor to a Rectangle Dimension
XMonad/Layout/Decoration.hs view
@@ -17,7 +17,7 @@ ( -- * Usage: -- $usage decoration- , Theme (..), defaultTheme+ , Theme (..), defaultTheme, def , Decoration , DecorationMsg (..) , DecorationStyle (..)@@ -86,9 +86,8 @@ -- Inner @[Bool]@ is a row in a icon bitmap. } deriving (Show, Read) --- | The default xmonad 'Theme'.-defaultTheme :: Theme-defaultTheme =+instance Default Theme where+ def = Theme { activeColor = "#999999" , inactiveColor = "#666666" , urgentColor = "#FFFF00"@@ -104,6 +103,11 @@ , windowTitleAddons = [] , windowTitleIcons = [] }++{-# DEPRECATED defaultTheme "Use def (from Data.Default, and re-exported by XMonad.Layout.Decoration) instead." #-}+-- | The default xmonad 'Theme'.+defaultTheme :: Theme+defaultTheme = def -- | A 'Decoration' layout modifier will handle 'SetTheme', a message -- to dynamically change the decoration 'Theme'.
XMonad/Layout/DecorationAddons.hs view
@@ -68,7 +68,7 @@ -- | Intended to be used together with 'titleBarButtonHandler'. See above. defaultThemeWithButtons :: Theme-defaultThemeWithButtons = defaultTheme {+defaultThemeWithButtons = def { windowTitleAddons = [ (" (M)", AlignLeft) , ("_" , AlignRightOffset minimizeButtonOffset) , ("[]" , AlignRightOffset maximizeButtonOffset)
XMonad/Layout/DecorationMadness.hs view
@@ -82,7 +82,7 @@ , floatDwmStyle , floatSimpleTabbed , floatTabbed- , defaultTheme, shrinkText+ , def, defaultTheme, shrinkText ) where import XMonad@@ -105,7 +105,7 @@ -- -- Then edit your @layoutHook@ by adding the layout you want: ----- > main = xmonad defaultConfig { layoutHook = someMadLayout }+-- > main = xmonad def { layoutHook = someMadLayout } -- -- For more detailed instructions on editing the layoutHook see: --@@ -113,7 +113,7 @@ -- -- You can also edit the default theme: ----- > myTheme = defaultTheme { inactiveBorderColor = "#FF0000"+-- > myTheme = def { inactiveBorderColor = "#FF0000" -- > , activeTextColor = "#00FF00" } -- -- and@@ -140,7 +140,7 @@ -- -- <http://code.haskell.org/~arossato/xmonadShots/circleSimpleDefault.png> circleSimpleDefault :: ModifiedLayout (Decoration DefaultDecoration DefaultShrinker) Circle Window-circleSimpleDefault = decoration shrinkText defaultTheme DefaultDecoration Circle+circleSimpleDefault = decoration shrinkText def DefaultDecoration Circle -- | Similar to 'circleSimpleDefault' but with the possibility of -- setting a custom shrinker and a custom theme.@@ -155,7 +155,7 @@ -- -- <http://code.haskell.org/~arossato/xmonadShots/circleSimpleDeco.png> circleSimpleDeco :: ModifiedLayout (Decoration SimpleDecoration DefaultShrinker) Circle Window-circleSimpleDeco = decoration shrinkText defaultTheme (Simple True) Circle+circleSimpleDeco = decoration shrinkText def (Simple True) Circle -- | Similar to 'circleSimpleDece' but with the possibility of -- setting a custom shrinker and a custom theme.@@ -172,7 +172,7 @@ -- <http://code.haskell.org/~arossato/xmonadShots/circleSimpleDefaultResizable.png> circleSimpleDefaultResizable :: ModifiedLayout (Decoration DefaultDecoration DefaultShrinker) (ModifiedLayout MouseResize (ModifiedLayout WindowArranger Circle)) Window-circleSimpleDefaultResizable = decoration shrinkText defaultTheme DefaultDecoration (mouseResize $ windowArrange Circle)+circleSimpleDefaultResizable = decoration shrinkText def DefaultDecoration (mouseResize $ windowArrange Circle) -- | Similar to 'circleSimpleDefaultResizable' but with the -- possibility of setting a custom shrinker and a custom theme.@@ -190,7 +190,7 @@ -- <http://code.haskell.org/~arossato/xmonadShots/circleSimpleDecoResizable.png> circleSimpleDecoResizable :: ModifiedLayout (Decoration SimpleDecoration DefaultShrinker) (ModifiedLayout MouseResize (ModifiedLayout WindowArranger Circle)) Window-circleSimpleDecoResizable = decoration shrinkText defaultTheme (Simple True) (mouseResize $ windowArrange Circle)+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.@@ -206,7 +206,7 @@ -- -- <http://code.haskell.org/~arossato/xmonadShots/circleSimpleDwmStyle.png> circleSimpleDwmStyle :: ModifiedLayout (Decoration DwmStyle DefaultShrinker) Circle Window-circleSimpleDwmStyle = decoration shrinkText defaultTheme Dwm Circle+circleSimpleDwmStyle = decoration shrinkText def Dwm Circle -- | Similar to 'circleSimpleDwmStyle' but with the -- possibility of setting a custom shrinker and a custom theme.@@ -241,7 +241,7 @@ -- -- <http://code.haskell.org/~arossato/xmonadShots/accordionSimpleDefault.png> accordionSimpleDefault :: ModifiedLayout (Decoration DefaultDecoration DefaultShrinker) Accordion Window-accordionSimpleDefault = decoration shrinkText defaultTheme DefaultDecoration Accordion+accordionSimpleDefault = decoration shrinkText def DefaultDecoration Accordion -- | Similar to 'accordionSimpleDefault' but with the possibility of -- setting a custom shrinker and a custom theme.@@ -256,7 +256,7 @@ -- -- <http://code.haskell.org/~arossato/xmonadShots/accordionSimpleDeco.png> accordionSimpleDeco :: ModifiedLayout (Decoration SimpleDecoration DefaultShrinker) Accordion Window-accordionSimpleDeco = decoration shrinkText defaultTheme (Simple True) Accordion+accordionSimpleDeco = decoration shrinkText def (Simple True) Accordion -- | Similar to 'accordionSimpleDece' but with the possibility of -- setting a custom shrinker and a custom theme.@@ -269,7 +269,7 @@ -- windows with the mouse, and resize\/move them with the keyboard. accordionSimpleDefaultResizable :: ModifiedLayout (Decoration DefaultDecoration DefaultShrinker) (ModifiedLayout MouseResize (ModifiedLayout WindowArranger Accordion)) Window-accordionSimpleDefaultResizable = decoration shrinkText defaultTheme DefaultDecoration (mouseResize $ windowArrange Accordion)+accordionSimpleDefaultResizable = decoration shrinkText def DefaultDecoration (mouseResize $ windowArrange Accordion) -- | Similar to 'accordionSimpleDefaultResizable' but with the -- possibility of setting a custom shrinker and a custom theme.@@ -283,7 +283,7 @@ -- windows with the mouse, and resize\/move them with the keyboard. accordionSimpleDecoResizable :: ModifiedLayout (Decoration SimpleDecoration DefaultShrinker) (ModifiedLayout MouseResize (ModifiedLayout WindowArranger Accordion)) Window-accordionSimpleDecoResizable = decoration shrinkText defaultTheme (Simple True) (mouseResize $ windowArrange Accordion)+accordionSimpleDecoResizable = decoration shrinkText def (Simple True) (mouseResize $ windowArrange Accordion) -- | Similar to 'accordionSimpleDecoResizable' but with the -- possibility of setting a custom shrinker and a custom theme.@@ -299,7 +299,7 @@ -- -- <http://code.haskell.org/~arossato/xmonadShots/accordionSimpleDwmStyle.png> accordionSimpleDwmStyle :: ModifiedLayout (Decoration DwmStyle DefaultShrinker) Accordion Window-accordionSimpleDwmStyle = decoration shrinkText defaultTheme Dwm Accordion+accordionSimpleDwmStyle = decoration shrinkText def Dwm Accordion -- | Similar to 'accordionSimpleDwmStyle' but with the -- possibility of setting a custom shrinker and a custom theme.@@ -337,7 +337,7 @@ -- -- <http://code.haskell.org/~arossato/xmonadShots/tallSimpleDefault.png> tallSimpleDefault :: ModifiedLayout (Decoration DefaultDecoration DefaultShrinker) Tall Window-tallSimpleDefault = decoration shrinkText defaultTheme DefaultDecoration tall+tallSimpleDefault = decoration shrinkText def DefaultDecoration tall -- | Similar to 'tallSimpleDefault' but with the possibility of -- setting a custom shrinker and a custom theme.@@ -352,7 +352,7 @@ -- -- <http://code.haskell.org/~arossato/xmonadShots/tallSimpleDeco.png> tallSimpleDeco :: ModifiedLayout (Decoration SimpleDecoration DefaultShrinker) Tall Window-tallSimpleDeco = decoration shrinkText defaultTheme (Simple True) tall+tallSimpleDeco = decoration shrinkText def (Simple True) tall -- | Similar to 'tallSimpleDece' but with the possibility of -- setting a custom shrinker and a custom theme.@@ -369,7 +369,7 @@ -- <http://code.haskell.org/~arossato/xmonadShots/tallSimpleDefaultResizable.png> tallSimpleDefaultResizable :: ModifiedLayout (Decoration DefaultDecoration DefaultShrinker) (ModifiedLayout MouseResize (ModifiedLayout WindowArranger Tall)) Window-tallSimpleDefaultResizable = decoration shrinkText defaultTheme DefaultDecoration (mouseResize $ windowArrange tall)+tallSimpleDefaultResizable = decoration shrinkText def DefaultDecoration (mouseResize $ windowArrange tall) -- | Similar to 'tallSimpleDefaultResizable' but with the -- possibility of setting a custom shrinker and a custom theme.@@ -387,7 +387,7 @@ -- <http://code.haskell.org/~arossato/xmonadShots/tallSimpleDecoResizable.png> tallSimpleDecoResizable :: ModifiedLayout (Decoration SimpleDecoration DefaultShrinker) (ModifiedLayout MouseResize (ModifiedLayout WindowArranger Tall)) Window-tallSimpleDecoResizable = decoration shrinkText defaultTheme (Simple True) (mouseResize $ windowArrange tall)+tallSimpleDecoResizable = decoration shrinkText def (Simple True) (mouseResize $ windowArrange tall) -- | Similar to 'tallSimpleDecoResizable' but with the -- possibility of setting a custom shrinker and a custom theme.@@ -403,7 +403,7 @@ -- -- <http://code.haskell.org/~arossato/xmonadShots/tallSimpleDwmStyle.png> tallSimpleDwmStyle :: ModifiedLayout (Decoration DwmStyle DefaultShrinker) Tall Window-tallSimpleDwmStyle = decoration shrinkText defaultTheme Dwm tall+tallSimpleDwmStyle = decoration shrinkText def Dwm tall -- | Similar to 'tallSimpleDwmStyle' but with the -- possibility of setting a custom shrinker and a custom theme.@@ -440,7 +440,7 @@ -- -- <http://code.haskell.org/~arossato/xmonadShots/mirrorTallSimpleDefault.png> mirrorTallSimpleDefault :: ModifiedLayout (Decoration DefaultDecoration DefaultShrinker) (Mirror Tall) Window-mirrorTallSimpleDefault = decoration shrinkText defaultTheme DefaultDecoration mirrorTall+mirrorTallSimpleDefault = decoration shrinkText def DefaultDecoration mirrorTall -- | Similar to 'mirrorTallSimpleDefault' but with the possibility of -- setting a custom shrinker and a custom theme.@@ -455,7 +455,7 @@ -- -- <http://code.haskell.org/~arossato/xmonadShots/mirrorTallSimpleDeco.png> mirrorTallSimpleDeco :: ModifiedLayout (Decoration SimpleDecoration DefaultShrinker) (Mirror Tall) Window-mirrorTallSimpleDeco = decoration shrinkText defaultTheme (Simple True) mirrorTall+mirrorTallSimpleDeco = decoration shrinkText def (Simple True) mirrorTall -- | Similar to 'mirrorTallSimpleDece' but with the possibility of -- setting a custom shrinker and a custom theme.@@ -472,7 +472,7 @@ -- <http://code.haskell.org/~arossato/xmonadShots/mirrorTallSimpleDefaultResizable.png> mirrorTallSimpleDefaultResizable :: ModifiedLayout (Decoration DefaultDecoration DefaultShrinker) (ModifiedLayout MouseResize (ModifiedLayout WindowArranger (Mirror Tall))) Window-mirrorTallSimpleDefaultResizable = decoration shrinkText defaultTheme DefaultDecoration (mouseResize $ windowArrange mirrorTall)+mirrorTallSimpleDefaultResizable = decoration shrinkText def DefaultDecoration (mouseResize $ windowArrange mirrorTall) -- | Similar to 'mirrorTallSimpleDefaultResizable' but with the -- possibility of setting a custom shrinker and a custom theme.@@ -490,7 +490,7 @@ -- <http://code.haskell.org/~arossato/xmonadShots/mirrorTallSimpleDecoResizable.png> mirrorTallSimpleDecoResizable :: ModifiedLayout (Decoration SimpleDecoration DefaultShrinker) (ModifiedLayout MouseResize (ModifiedLayout WindowArranger (Mirror Tall))) Window-mirrorTallSimpleDecoResizable = decoration shrinkText defaultTheme (Simple True) (mouseResize $ windowArrange mirrorTall)+mirrorTallSimpleDecoResizable = decoration shrinkText def (Simple True) (mouseResize $ windowArrange mirrorTall) -- | Similar to 'mirrorTallSimpleDecoResizable' but with the -- possibility of setting a custom shrinker and a custom theme.@@ -506,7 +506,7 @@ -- -- <http://code.haskell.org/~arossato/xmonadShots/mirrorTallSimpleDwmStyle.png> mirrorTallSimpleDwmStyle :: ModifiedLayout (Decoration DwmStyle DefaultShrinker) (Mirror Tall) Window-mirrorTallSimpleDwmStyle = decoration shrinkText defaultTheme Dwm mirrorTall+mirrorTallSimpleDwmStyle = decoration shrinkText def Dwm mirrorTall -- | Similar to 'mirrorTallSimpleDwmStyle' but with the -- possibility of setting a custom shrinker and a custom theme.@@ -555,7 +555,7 @@ -- <http://code.haskell.org/~arossato/xmonadShots/floatSimpleDefault.png> floatSimpleDefault :: (Show a, Eq a) => ModifiedLayout (Decoration DefaultDecoration DefaultShrinker) (ModifiedLayout MouseResize (ModifiedLayout WindowArranger SimpleFloat)) a-floatSimpleDefault = decoration shrinkText defaultTheme DefaultDecoration (mouseResize $ windowArrangeAll $ SF 20)+floatSimpleDefault = decoration shrinkText def DefaultDecoration (mouseResize $ windowArrangeAll $ SF 20) -- | Same as 'floatSimpleDefault', but with the possibility of setting a -- custom shrinker and a custom theme.@@ -572,7 +572,7 @@ -- <http://code.haskell.org/~arossato/xmonadShots/floatSimpleDwmStyle.png> floatSimpleDwmStyle :: (Show a, Eq a) => ModifiedLayout (Decoration DwmStyle DefaultShrinker) (ModifiedLayout MouseResize (ModifiedLayout WindowArranger SimpleFloat)) a-floatSimpleDwmStyle = decoration shrinkText defaultTheme Dwm (mouseResize $ windowArrangeAll $ SF 20)+floatSimpleDwmStyle = decoration shrinkText def Dwm (mouseResize $ windowArrangeAll $ SF 20) -- | Same as 'floatSimpleDwmStyle', but with the possibility of setting a -- custom shrinker and a custom theme.@@ -589,7 +589,7 @@ -- <http://code.haskell.org/~arossato/xmonadShots/floatSimpleTabbed.png> floatSimpleTabbed :: (Show a, Eq a) => ModifiedLayout (Decoration TabBarDecoration DefaultShrinker) (ModifiedLayout MouseResize (ModifiedLayout WindowArranger SimpleFloat)) a-floatSimpleTabbed = tabBar shrinkText defaultTheme Top (mouseResize $ windowArrangeAll $ SF 20)+floatSimpleTabbed = tabBar shrinkText def Top (mouseResize $ windowArrangeAll $ SF 20) -- | Same as 'floatSimpleTabbed', but with the possibility of setting a -- custom shrinker and a custom theme.
XMonad/Layout/Dishes.hs view
@@ -33,7 +33,7 @@ -- Then edit your @layoutHook@ by adding the Dishes layout: -- -- > myLayout = Dishes 2 (1/6) ||| Full ||| etc..--- > main = xmonad defaultConfig { layoutHook = myLayout }+-- > main = xmonad def { layoutHook = myLayout } -- -- For more detailed instructions on editing the layoutHook see: --
XMonad/Layout/DragPane.hs view
@@ -41,7 +41,7 @@ -- Then edit your @layoutHook@ by adding the DragPane layout: -- -- > myLayout = dragPane Horizontal 0.1 0.5 ||| Full ||| etc..--- > main = xmonad defaultConfig { layoutHook = myLayout }+-- > main = xmonad def { layoutHook = myLayout } -- -- For more detailed instructions on editing the layoutHook see: --
XMonad/Layout/Drawer.hs view
@@ -48,7 +48,7 @@ -- > where -- > drawer = simpleDrawer 0.01 0.3 (ClassName "Rhythmbox" `Or` ClassName "Xchat") -- >--- > main = xmonad defaultConfig { layoutHook = myLayout }+-- > main = xmonad def { layoutHook = myLayout } -- -- This will place the Rhythmbox and Xchat windows in at the top of the screen -- only when using the 'Tall' layout. See "XMonad.Util.WindowProperties" for
+ XMonad/Layout/Dwindle.hs view
@@ -0,0 +1,210 @@+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}++-----------------------------------------------------------------------------+-- |+-- Module : XMonad.Layout.Dwindle+-- Copyright : (c) Norbert Zeh <norbert.zeh@gmail.com>+-- License : BSD3+--+-- Maintainer : Norbert Zeh <norbert.zeh@gmail.com>+-- Stability : experimental+-- Portability : portable+--+-- Three layouts: The first, 'Spiral', is a reimplementation of+-- 'XMonad.Layout.Spiral.spiral' with, at least to me, more intuitive semantics.+-- The second, 'Dwindle', is inspired by a similar layout in awesome and+-- produces the same sequence of decreasing window sizes as Spiral but pushes+-- the smallest windows into a screen corner rather than the centre. The third,+-- 'Squeeze' arranges all windows in one row or in one column, with+-- geometrically decreasing sizes.+--+-----------------------------------------------------------------------------++module XMonad.Layout.Dwindle ( -- * Usage+ -- $usage+ Dwindle(..)+ , Direction2D(..)+ , Chirality(..)+ ) where++import Data.List ( unfoldr )+import XMonad+import XMonad.StackSet ( integrate, Stack )+import XMonad.Util.Types ( Direction2D(..) )++-- $usage+-- This module can be used as follows:+--+-- > import XMonad.Layout.Dwindle+--+-- Then add something like this to your layouts:+--+-- > Dwindle R CW 1.5 1.1+--+-- or+--+-- > Spiral L CW 1.5 1.1+--+-- or+--+-- ^ Squeeze D 1.5 1.1+--+-- The first produces a layout that places the second window to the right of+-- the first, the third below the second, the fourth to the right of the third,+-- and so on. The first window is 1.5 times as wide as the second one, the+-- second is 1.5 times as tall as the third one, and so on. Thus, the further+-- down the window stack a window is, the smaller it is and the more it is+-- pushed into the bottom-right corner.+--+-- The second produces a layout with the same window sizes but places the second+-- window to the left of the first one, the third above the second one, the+-- fourth to the right of the third one, and so on.+--+-- The third produces a layout that stacks windows vertically top-down with each+-- window being 1.5 times as tall as the next.+--+-- In all three cases, the fourth (third, in the case of 'Squeeze') parameter,+-- 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"++-- | Layouts with geometrically decreasing window sizes. 'Spiral' and 'Dwindle'+-- split the screen into a rectangle for the first window and a rectangle for+-- the remaining windows, which is split recursively to lay out these windows.+-- Both layouts alternate between horizontal and vertical splits.+--+-- In each recursive step, the split 'Direction2D' determines the placement of the+-- remaining windows relative to the current window: to the left, to the right,+-- above or below. The split direction of the first split is determined by the+-- first layout parameter. The split direction of the second step is rotated 90+-- degrees relative to the first split direction according to the second layout+-- parameter of type 'Chirality'. So, if the first split is 'R' and the second+-- layout parameter is 'CW', then the second split is 'D'.+--+-- For the 'Spiral' layout, the same 'Chirality' is used for computing the split+-- direction of each step from the split direction of the previous step. For+-- example, parameters 'R' and 'CW' produces the direction sequence 'R', 'D',+-- 'L', 'U', 'R', 'D', 'L', 'U', ...+--+-- For the 'Dwindle' layout, the 'Chirality' alternates between 'CW' and 'CCW' in+-- each step. For example, parameters 'U' and 'CCW' produce the direction+-- sequence 'U', 'L', 'U', 'L', ... because 'L' is the 'CCW' rotation of 'U' and+-- 'U' is the 'CW' rotation of 'L'.+--+-- In each split, the current rectangle is split so that the ratio between the+-- size of the rectangle allocated to the current window and the size of the+-- rectangle allocated to the remaining windows is the third layout parameter.+-- This ratio can be altered using 'Expand' and 'Shrink' messages. The former+-- multiplies the ratio by the fourth layout parameter. The latter divides the+-- ratio by this parameter.+--+-- 'Squeeze' does not alternate between horizontal and vertical splits and+-- simply splits in the direction given as its first argument.+--+-- Parameters for both 'Dwindle' and 'Spiral':+--+-- * First split direction+--+-- * First split chirality+--+-- * Size ratio between rectangle allocated to current window and rectangle +-- allocated to remaining windows+--+-- * Factor by which the size ratio is changed in response to 'Expand' or 'Shrink'+-- messages+--+-- The parameters for 'Squeeze' are the same, except that there is no 'Chirality'+-- parameter.+data Dwindle a = Dwindle !Direction2D !Chirality !Rational !Rational+ | Spiral !Direction2D !Chirality !Rational !Rational+ | Squeeze !Direction2D !Rational !Rational+ deriving (Read, Show)++-- | Rotation between consecutive split directions+data Chirality = CW | CCW+ deriving (Read, Show)++instance LayoutClass Dwindle a where+ pureLayout (Dwindle dir rot ratio _) = dwindle alternate dir rot ratio+ pureLayout (Spiral dir rot ratio _) = dwindle rotate dir rot ratio+ pureLayout (Squeeze dir ratio _) = squeeze dir ratio+ pureMessage (Dwindle dir rot ratio delta) =+ fmap (\ratio' -> Dwindle dir rot ratio' delta) . changeRatio ratio delta+ pureMessage (Spiral dir rot ratio delta) =+ fmap (\ratio' -> Spiral dir rot ratio' delta) . changeRatio ratio delta+ pureMessage (Squeeze dir ratio delta) =+ fmap (\ratio' -> Squeeze dir ratio' delta) . changeRatio ratio delta++changeRatio :: Rational -> Rational -> SomeMessage -> Maybe Rational+changeRatio ratio delta = fmap f . fromMessage+ where f Expand = ratio * delta+ f Shrink = ratio / delta++dwindle :: AxesGenerator -> Direction2D -> Chirality -> Rational -> Rectangle -> Stack a -> + [(a, Rectangle)]+dwindle trans dir rot ratio rect st = unfoldr genRects (integrate st, rect, dirAxes dir, rot)+ where genRects ([], _, _, _) = Nothing+ genRects ([w], r, a, rt) = Just ((w, r), ([], r, a, rt))+ genRects ((w:ws), r, a, rt) = Just ((w, r'), (ws, r'', a', rt'))+ where (r', r'') = splitRect r ratio a+ (a', rt') = trans a rt++squeeze :: Direction2D -> Rational -> Rectangle -> Stack a -> [(a, Rectangle)]+squeeze dir ratio rect st = zip wins rects+ where wins = integrate st+ 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+ ratios = reverse $ map (\(l, r) -> l / r) splits+ rects = genRects rect ratios+ genRects r [] = [r]+ genRects r (x:xs) = r' : genRects r'' xs+ where (r', r'') = splitRect r x (dirAxes dir)++splitRect :: Rectangle -> Rational -> Axes -> (Rectangle, Rectangle)+splitRect (Rectangle x y w h) ratio (ax, ay) = (Rectangle x' y' w' h', Rectangle x'' y'' w'' h'')+ where portion = ratio / (ratio + 1)+ w1 = (round $ fi w * portion) :: Int+ w2 = fi w - w1+ h1 = (round $ fi h * portion) :: Int+ h2 = fi h - h1+ x' = x + fi (negate ax * (1 - ax) * w2 `div` 2)+ y' = y + fi (negate ay * (1 - ay) * h2 `div` 2)+ w' = fi $ w1 + (1 - abs ax) * w2+ h' = fi $ h1 + (1 - abs ay) * h2+ x'' = x + fi (ax * (1 + ax) * w1 `div` 2)+ y'' = y + fi (ay * (1 + ay) * h1 `div` 2)+ w'' = fi $ w2 + (1 - abs ax) * w1+ h'' = fi $ h2 + (1 - abs ay) * h1+ fi :: (Num b, Integral a) => a -> b+ fi = fromIntegral++type Axes = (Int, Int)+type AxesGenerator = Axes -> Chirality -> (Axes, Chirality)++dirAxes :: Direction2D -> Axes+dirAxes L = (-1, 0)+dirAxes R = ( 1, 0)+dirAxes U = ( 0, -1)+dirAxes D = ( 0, 1)++alternate :: AxesGenerator+alternate = chDir alt++rotate :: AxesGenerator+rotate = chDir id++chDir :: (Chirality -> Chirality) -> AxesGenerator+chDir f (x, y) r = (a' r, r')+ where a' CW = (-y, x)+ a' CCW = ( y, -x)+ r' = f r++alt :: Chirality -> Chirality+alt CW = CCW+alt CCW = CW
XMonad/Layout/DwmStyle.hs view
@@ -17,6 +17,7 @@ -- $usage dwmStyle , Theme (..)+ , def , defaultTheme , DwmStyle (..) , shrinkText, CustomShrink(CustomShrink)@@ -36,8 +37,8 @@ -- Then edit your @layoutHook@ by adding the DwmStyle decoration to -- your layout: ----- > myL = dwmStyle shrinkText defaultTheme (layoutHook defaultConfig)--- > main = xmonad defaultConfig { layoutHook = myL }+-- > myL = dwmStyle shrinkText def (layoutHook def)+-- > main = xmonad def { layoutHook = myL } -- -- For more detailed instructions on editing the layoutHook see: --@@ -45,23 +46,21 @@ -- -- You can also edit the default configuration options. ----- > myDWConfig = defaultTheme { inactiveBorderColor = "red"--- > , inactiveTextColor = "red"}+-- > myDWConfig = def { inactiveBorderColor = "red"+-- > , inactiveTextColor = "red"} -- -- and ----- > myL = dwmStyle shrinkText myDWConfig (layoutHook defaultConfig)+-- > myL = dwmStyle shrinkText myDWConfig (layoutHook def) -- -- A complete xmonad.hs file for this would therefore be: -- -- > import XMonad -- > import XMonad.Layout.DwmStyle -- >--- > main = xmonad defaultConfig {--- > layoutHook =--- > dwmStyle shrinkText defaultTheme--- > (layoutHook defaultConfig)--- > }+-- > main = xmonad def {+-- > layoutHook = dwmStyle shrinkText def (layoutHook def)+-- > } --
XMonad/Layout/FixedColumn.hs view
@@ -43,7 +43,7 @@ -- Then edit your @layoutHook@ by adding the FixedColumn layout: -- -- > myLayout = FixedColumn 1 20 80 10 ||| Full ||| etc..--- > main = xmonad defaultConfig { layoutHook = myLayout }+-- > main = xmonad def { layoutHook = myLayout } -- -- For more detailed instructions on editing the layoutHook see: --
XMonad/Layout/Fullscreen.hs view
@@ -1,7 +1,7 @@-{-# LANGUAGE DeriveDataTypeable, MultiParamTypeClasses, FlexibleInstances, TypeSynonymInstances #-}+{-# LANGUAGE DeriveDataTypeable, FlexibleContexts, MultiParamTypeClasses, FlexibleInstances, TypeSynonymInstances #-} ----------------------------------------------------------------------------- -- |--- Module : XMonad.Layout.Decoration+-- Module : XMonad.Layout.Fullscreen -- Copyright : (c) 2010 Audun Skaugen -- License : BSD-style (see xmonad/LICENSE) --@@ -15,7 +15,8 @@ module XMonad.Layout.Fullscreen ( -- * Usage: -- $usage- fullscreenFull+ fullscreenSupport+ ,fullscreenFull ,fullscreenFocus ,fullscreenFullRect ,fullscreenFocusRect@@ -53,15 +54,29 @@ -- To use this module, add 'fullscreenEventHook' and 'fullscreenManageHook' -- to your config, i.e. ----- > xmonad defaultconfig { handleEventHook = fullscreenEventHook,--- > manageHook = fullscreenManageHook,--- > layoutHook = myLayouts }+-- > xmonad def { handleEventHook = fullscreenEventHook,+-- > manageHook = fullscreenManageHook,+-- > layoutHook = myLayouts } -- -- Now you can use layouts that respect fullscreen, for example the -- provided 'fullscreenFull': -- -- > myLayouts = fullscreenFull someLayout --++-- | Modifies your config to apply basic fullscreen support -- fullscreen+-- windows when they request it. Example usage:+--+-- > main = xmonad+-- > $ fullscreenSupport+-- > $ defaultConfig { ... }+fullscreenSupport :: LayoutClass l Window =>+ XConfig l -> XConfig (ModifiedLayout FullscreenFull l)+fullscreenSupport c = c {+ layoutHook = fullscreenFull $ layoutHook c,+ handleEventHook = handleEventHook c <+> fullscreenEventHook,+ manageHook = manageHook c <+> fullscreenManageHook+ } -- | Messages that control the fullscreen state of the window. -- AddFullscreen and RemoveFullscreen are sent to all layouts
XMonad/Layout/Gaps.hs view
@@ -29,7 +29,7 @@ -- * Usage -- $usage Direction2D(..), Gaps,- GapSpec, gaps, GapMessage(..)+ GapSpec, gaps, gaps', GapMessage(..) ) where @@ -140,3 +140,8 @@ -> ModifiedLayout Gaps l a gaps g = ModifiedLayout (Gaps g (map fst g)) +-- | Add togglable manual gaps to a layout, explicitly specifying the initial states.+gaps' :: [((Direction2D,Int),Bool)] -- ^ The gaps to allow and their initial states.+ -> l a -- ^ The layout to modify.+ -> ModifiedLayout Gaps l a+gaps' g = ModifiedLayout (Gaps (map fst g) [d | ((d,_),v) <- g, v])
XMonad/Layout/Grid.hs view
@@ -31,7 +31,7 @@ -- Then edit your @layoutHook@ by adding the Grid layout: -- -- > myLayout = Grid ||| Full ||| etc..--- > main = xmonad defaultConfig { layoutHook = myLayout }+-- > main = xmonad def { layoutHook = myLayout } -- -- You can also specify an aspect ratio for Grid to strive for with the -- GridRatio constructor. For example, if you want Grid to try to make a grid
XMonad/Layout/Groups/Examples.hs view
@@ -1,5 +1,5 @@ {-# OPTIONS_GHC -fno-warn-missing-signatures #-}-{-# LANGUAGE MultiParamTypeClasses, Rank2Types #-}+{-# LANGUAGE MultiParamTypeClasses, Rank2Types, TypeFamilies #-} ----------------------------------------------------------------------------- -- |@@ -36,6 +36,7 @@ , mirrorTallTabs , fullTabs , TiledTabsConfig(..)+ , def , defaultTiledTabsConfig , increaseNMasterGroups , decreaseNMasterGroups@@ -180,9 +181,9 @@ -- You can use any of these three layouts by including it in your layout hook. -- You will need to provide it with a 'TiledTabsConfig' containing the size -- parameters for 'Tall' and 'Mirror' 'Tall', and the shrinker and decoration theme--- for the tabs. If you're happy with defaults, you can use 'defaultTiledTabsConfig':+-- for the tabs. If you're happy with defaults, you can use 'def': ----- > myLayout = tallTabs defaultTiledTabsConfig+-- > myLayout = tallTabs def -- -- To be able to increase\/decrease the number of master groups and shrink\/expand -- the master area, you can create key bindings for the relevant actions:@@ -201,8 +202,12 @@ , tabsShrinker :: s , tabsTheme :: Theme } +instance s ~ DefaultShrinker => Default (TiledTabsConfig s) where+ def = TTC 1 0.5 (3/100) 1 0.5 (3/100) shrinkText def++{-# DEPRECATED defaultTiledTabsConfig "Use def (from Data.Default, and re-exported by XMonad.Layout.Groups) instead." #-} defaultTiledTabsConfig :: TiledTabsConfig DefaultShrinker-defaultTiledTabsConfig = TTC 1 0.5 (3/100) 1 0.5 (3/100) shrinkText defaultTheme+defaultTiledTabsConfig = def fullTabs c = _tab c $ G.group _tabs $ Full ||| _vert c ||| _horiz c
XMonad/Layout/Groups/Helpers.hs view
@@ -1,5 +1,5 @@ {-# OPTIONS_GHC -fno-warn-missing-signatures #-}-{-# LANGUAGE MultiParamTypeClasses, Rank2Types #-}+{-# LANGUAGE MultiParamTypeClasses, Rank2Types, ImpredicativeTypes #-} ----------------------------------------------------------------------------- -- |
XMonad/Layout/Groups/Wmii.hs view
@@ -30,6 +30,7 @@ -- * Useful re-exports , shrinkText+ , def , defaultTheme , module XMonad.Layout.Groups.Helpers ) where @@ -71,7 +72,7 @@ -- (with a 'Shrinker' and decoration 'Theme' as -- parameters) to your layout hook, for example: ----- > myLayout = wmii shrinkText defaultTheme+-- > myLayout = wmii shrinkText def -- -- To be able to zoom in and out of groups, change their inner layout, etc., -- create key bindings for the relevant actions:
+ XMonad/Layout/Hidden.hs view
@@ -0,0 +1,133 @@+{-# LANGUAGE DeriveDataTypeable, FlexibleContexts, MultiParamTypeClasses, TypeSynonymInstances, PatternGuards #-}++----------------------------------------------------------------------------+-- |+-- Module : XMonad.Layout.Hidden+-- Copyright : (c) Peter Jones 2015+-- License : BSD3-style (see LICENSE)+--+-- Maintainer : pjones@devalot.com+-- Stability : unstable+-- Portability : not portable+--+-- Similar to "XMonad.Layout.Minimize" but completely removes windows+-- from the window set so "XMonad.Layout.BoringWindows" isn't+-- necessary. Perfect companion to+-- "XMonad.Layout.BinarySpacePartition" since it can be used to move+-- windows to another part of the BSP tree.+--+-----------------------------------------------------------------------------+module XMonad.Layout.Hidden+ ( -- * Usage+ -- $usage+ HiddenMsg (..)+ , hiddenWindows+ , hideWindow+ , popOldestHiddenWindow+ , popNewestHiddenWindow+ ) where++--------------------------------------------------------------------------------+import XMonad+import XMonad.Layout.LayoutModifier+import qualified XMonad.StackSet as W++--------------------------------------------------------------------------------+-- $usage+-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+--+-- > import XMonad.Layout.Hidden+--+-- Then edit your @layoutHook@ by adding the @HiddenWindows@ layout modifier:+--+-- > 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"+--+-- In the key bindings, do something like:+--+-- > , ((modMask, xK_backslash), withFocused hideWindow)+-- > , ((modMask .|. shiftMask, xK_backslash), popOldestHiddenWindow)+-- > ...+--+-- For detailed instruction on editing the key bindings see:+--+-- "XMonad.Doc.Extending#Editing_key_bindings".++--------------------------------------------------------------------------------+data HiddenWindows a = HiddenWindows [Window] deriving (Show, Read)++--------------------------------------------------------------------------------+-- | Messages for the @HiddenWindows@ layout modifier.+data HiddenMsg = HideWindow Window -- ^ Hide a window.+ | PopNewestHiddenWindow -- ^ Restore window (FILO).+ | PopOldestHiddenWindow -- ^ Restore window (FIFO).+ deriving (Typeable, Eq)++instance Message HiddenMsg++--------------------------------------------------------------------------------+instance LayoutModifier HiddenWindows Window where+ handleMess h@(HiddenWindows hidden) mess+ | Just (HideWindow win) <- fromMessage mess = hideWindowMsg h win+ | Just (PopNewestHiddenWindow) <- fromMessage mess = popNewestMsg h+ | Just (PopOldestHiddenWindow) <- fromMessage mess = popOldestMsg h+ | Just ReleaseResources <- fromMessage mess = doUnhook+ | otherwise = return Nothing+ where doUnhook = do mapM_ restoreWindow hidden+ return Nothing++ modifierDescription _ = "Hidden"++--------------------------------------------------------------------------------+-- | Apply the @HiddenWindows@ layout modifier.+hiddenWindows :: LayoutClass l Window => l Window -> ModifiedLayout HiddenWindows l Window+hiddenWindows = ModifiedLayout $ HiddenWindows []++--------------------------------------------------------------------------------+-- | Remove the given window from the current layout. It is placed in+-- list of hidden windows so it can be restored later.+hideWindow :: Window -> X ()+hideWindow = sendMessage . HideWindow++--------------------------------------------------------------------------------+-- | Restore a previously hidden window. Using this function will+-- treat the list of hidden windows as a FIFO queue. That is, the+-- first window hidden will be restored.+popOldestHiddenWindow :: X ()+popOldestHiddenWindow = sendMessage PopOldestHiddenWindow++--------------------------------------------------------------------------------+-- | Restore a previously hidden window. Using this function will+-- treat the list of hidden windows as a FILO queue. That is, the+-- most recently hidden window will be restored.+popNewestHiddenWindow :: X ()+popNewestHiddenWindow = sendMessage PopNewestHiddenWindow++--------------------------------------------------------------------------------+hideWindowMsg :: HiddenWindows a -> Window -> X (Maybe (HiddenWindows a))+hideWindowMsg (HiddenWindows hidden) win = do+ windows (W.delete' win)+ return . Just . HiddenWindows $ hidden ++ [win]++--------------------------------------------------------------------------------+popNewestMsg :: HiddenWindows a -> X (Maybe (HiddenWindows a))+popNewestMsg (HiddenWindows []) = return Nothing+popNewestMsg (HiddenWindows hidden) = do+ let (win, rest) = (last hidden, init hidden)+ restoreWindow win+ return . Just . HiddenWindows $ rest++--------------------------------------------------------------------------------+popOldestMsg :: HiddenWindows a -> X (Maybe (HiddenWindows a))+popOldestMsg (HiddenWindows []) = return Nothing+popOldestMsg (HiddenWindows (win:rest)) = do+ restoreWindow win+ return . Just . HiddenWindows $ rest++--------------------------------------------------------------------------------+restoreWindow :: Window -> X ()+restoreWindow = windows . W.insertUp
XMonad/Layout/HintedGrid.hs view
@@ -42,7 +42,7 @@ -- Then edit your @layoutHook@ by adding the 'Grid' layout: -- -- > myLayout = Grid False ||| Full ||| etc..--- > main = xmonad defaultConfig { layoutHook = myLayout }+-- > main = xmonad def { layoutHook = myLayout } -- -- You can also specify an aspect ratio for Grid to strive for with the -- GridRatio constructor:
XMonad/Layout/HintedTile.hs view
@@ -38,7 +38,7 @@ -- > nmaster = 1 -- > ratio = 1/2 -- > delta = 3/100--- > main = xmonad defaultConfig { layoutHook = myLayout }+-- > main = xmonad def { layoutHook = myLayout } -- -- Because both Xmonad and Xmonad.Layout.HintedTile define Tall, -- you need to disambiguate Tall. If you are replacing the
XMonad/Layout/IM.hs view
@@ -45,7 +45,7 @@ -- to consider is Tabbed layout). -- -- > myLayout = withIM (1%7) (ClassName "Tkabber") Grid ||| Full ||| etc..--- > main = xmonad defaultConfig { layoutHook = myLayout }+-- > main = xmonad def { layoutHook = myLayout } -- -- Here @1%7@ is the part of the screen which your roster will occupy, -- @ClassName \"Tkabber\"@ tells xmonad which window is actually your roster.
+ XMonad/Layout/IfMax.hs view
@@ -0,0 +1,76 @@+-----------------------------------------------------------------------------+-- |+-- Module : XMonad.Layout.IfMax+-- Copyright : (c) 2013 Ilya Portnov+-- License : BSD3-style (see LICENSE)+--+-- Maintainer : Ilya Portnov <portnov84@rambler.ru>+-- Stability : unstable+-- Portability : unportable+--+-- Provides IfMax layout, which will run one layout if there are maximum N +-- windows on workspace, and another layout, when number of windows is greater+-- than N.+--+-----------------------------------------------------------------------------++{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}++module XMonad.Layout.IfMax+ ( -- * Usage+ -- $usage+ IfMax (..)+ , ifMax+ ) where++import Data.Maybe++import XMonad+import qualified XMonad.StackSet as W++-- $usage+-- IfMax layout will run one layout if number of windows on workspace is as +-- maximum N, and else will run another layout.+--+-- You can use this module by adding folowing in your @xmonad.hs@:+--+-- > import XMonad.Layout.IfMax+--+-- Then add layouts to your layoutHook:+--+-- > myLayoutHook = IfMax 2 Full (Tall ...) ||| ...+--+-- In this example, if there are 1 or 2 windows, Full layout will be used;+-- otherwise, Tall layout will be used.+--++data IfMax l1 l2 w = IfMax Int (l1 w) (l2 w)+ deriving (Read, Show)++instance (LayoutClass l1 a, LayoutClass l2 a) => LayoutClass (IfMax l1 l2) a where++ runLayout (W.Workspace _ (IfMax n l1 l2) s) rect = arrange (W.integrate' s)+ where+ arrange [] = do l1' <- maybe l1 id `fmap` handleMessage l1 (SomeMessage ReleaseResources)+ l2' <- maybe l2 id `fmap` handleMessage l2 (SomeMessage ReleaseResources)+ return ([], Just $ IfMax n l1' l2')+ arrange ws | length ws <= n = do+ (wrs, ml1') <- runLayout (W.Workspace "" l1 s) rect+ let l1' = fromMaybe l1 ml1'+ return (wrs, Just $ IfMax n l1' l2)+ | otherwise = do+ (wrs, ml2') <- runLayout (W.Workspace "" l2 s) rect+ let l2' = fromMaybe l2 ml2'+ return (wrs, Just $ IfMax n l1 l2')++ description (IfMax n l1 l2) = "If number of windows is <= " ++ show n ++ ", then " +++ description l1 ++ ", else " ++ description l2++-- | Layout itself+ifMax :: (LayoutClass l1 w, LayoutClass l2 w)+ => Int -- ^ Maximum number of windows for the first layout+ -> l1 w -- ^ First layout+ -> l2 w -- ^ Second layout+ -> IfMax l1 l2 w+ifMax n l1 l2 = IfMax n l1 l2+
XMonad/Layout/ImageButtonDecoration.hs view
@@ -50,8 +50,8 @@ -- Then edit your @layoutHook@ by adding the ImageButtonDecoration to -- your layout: ----- > myL = imageButtonDeco shrinkText defaultThemeWithImageButtons (layoutHook defaultConfig)--- > main = xmonad defaultConfig { layoutHook = myL }+-- > myL = imageButtonDeco shrinkText defaultThemeWithImageButtons (layoutHook def)+-- > main = xmonad def { layoutHook = myL } -- -- The buttons' dimension and placements@@ -164,7 +164,7 @@ action defaultThemeWithImageButtons :: Theme-defaultThemeWithImageButtons = defaultTheme {+defaultThemeWithImageButtons = def { windowTitleIcons = [ (menuButton, CenterLeft 3), (closeButton, CenterRight 3), (maxiButton, CenterRight 18),
XMonad/Layout/IndependentScreens.hs view
@@ -20,18 +20,19 @@ workspaces', withScreens, onCurrentScreen, marshallPP,+ whenCurrentOn, countScreens, -- * Converting between virtual and physical workspaces -- $converting marshall, unmarshall, unmarshallS, unmarshallW,- marshallWindowSpace, unmarshallWindowSpace+ marshallWindowSpace, unmarshallWindowSpace, marshallSort ) where -- for the screen stuff import Control.Applicative((<*), liftA2) import Control.Arrow hiding ((|||)) import Control.Monad-import Data.List+import Data.List (nub, genericLength) import Graphics.X11.Xinerama import XMonad import XMonad.StackSet hiding (filter, workspaces)@@ -44,7 +45,7 @@ -- -- You can define your workspaces by calling @withScreens@: ----- > myConfig = defaultConfig { workspaces = withScreens 2 ["web", "email", "irc"] }+-- > myConfig = def { workspaces = withScreens 2 ["web", "email", "irc"] } -- -- This will create \"physical\" workspaces with distinct internal names for -- each (screen, virtual workspace) pair.@@ -72,6 +73,9 @@ -- of virtual workspaces to functions of physical workspaces, which work -- by marshalling the virtual workspace name and the currently focused -- screen into a physical workspace name.+--+-- A complete example abusing many of the functions below is available in the+-- "XMonad.Config.Dmwit" module. type VirtualWorkspace = WorkspaceId type PhysicalWorkspace = WorkspaceId@@ -110,9 +114,9 @@ -- -- > main = do -- > nScreens <- countScreens--- > xmonad $ defaultConfig {+-- > xmonad $ def { -- > ...--- > workspaces = withScreens nScreens (workspaces defaultConfig),+-- > workspaces = withScreens nScreens (workspaces def), -- > ... -- > } --@@ -140,6 +144,42 @@ ppSort = fmap (marshallSort s) (ppSort pp) } +-- | Take a pretty-printer and turn it into one that only runs when the current+-- workspace is one associated with the given screen. The way this works is a+-- bit hacky, so beware: the 'ppOutput' field of the input will not be invoked+-- if either of the following conditions is met:+--+-- 1. The 'ppSort' of the input returns an empty list (when not given one).+--+-- 2. The 'ppOrder' of the input returns the exact string @\"\\0\"@.+--+-- For example, you can use this to create a pipe which tracks the title of the+-- window currently focused on a given screen (even if the screen is not+-- current) by doing something like this:+--+-- > ppFocus s = whenCurrentOn s def+-- > { ppOrder = \(_:_:title:_) -> [title]+-- > , ppOutput = appendFile ("focus" ++ show s) . (++ "\n")+-- > }+--+-- Sequence a few of these pretty-printers to get a log hook that keeps each+-- screen's title up-to-date.+whenCurrentOn :: ScreenId -> PP -> PP+whenCurrentOn s pp = pp+ { ppSort = do+ sort <- ppSort pp+ return $ \xs -> case xs of+ x:_ | unmarshallS (tag x) == s -> sort xs+ _ -> []+ , ppOrder = \i@(wss:_) -> case wss of+ "" -> ["\0"] -- we got passed no workspaces; this is the signal from ppSort that this is a boring case+ _ -> ppOrder pp i+ , ppOutput = \out -> case out of+ "\0" -> return () -- we got passed the signal from ppOrder that this is a boring case+ _ -> ppOutput pp out+ }++-- | If @vSort@ is a function that sorts 'WindowSpace's with virtual names, then @marshallSort s vSort@ is a function which sorts 'WindowSpace's with physical names in an analogous way -- but keeps only the spaces on screen @s@. marshallSort :: ScreenId -> ([WindowSpace] -> [WindowSpace]) -> ([WindowSpace] -> [WindowSpace]) marshallSort s vSort = pScreens . vSort . vScreens where onScreen ws = unmarshallS (tag ws) == s
XMonad/Layout/LayoutBuilder.hs view
@@ -10,7 +10,11 @@ -- Portability : unportable -- -- A layout combinator that sends a specified number of windows to one rectangle--- and the rest to another.+-- and the rest to another. Each of these rectangles are given a layout that+-- is used within them. This can be chained to provide an arbitrary number of+-- rectangles. The layout combinator allows overlapping rectangles, but such+-- layouts does not work well together with hinting+-- ("XMonad.Layout.LayoutHints", "XMonad.Layout.HintedGrid" etc.) -- ----------------------------------------------------------------------------- @@ -30,7 +34,7 @@ import XMonad import qualified XMonad.StackSet as W-import Data.Maybe (isJust)+import Data.Maybe (isJust,isNothing,listToMaybe) -- $usage -- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:@@ -49,13 +53,23 @@ -- > ( (layoutN 1 (absBox (-512-200) 0 512 0) (Just $ relBox 0 0 1 1) $ simpleTabbed) -- > $ (layoutN 1 (absBox (-200) 0 0 0) Nothing $ simpleTabbed) -- > $ (layoutAll (absBox 0 0 (-512-200) 0) $ simpleTabbed)+-- > ) |||+-- > ( (layoutN 1 (absBox 10 0 0 (-10)) Nothing $ Tall 0 0.01 0.5)+-- > $ (layoutN 1 (absBox 0 0 200 0) Nothing $ Tall 0 0.01 0.5)+-- > $ (layoutAll (absBox 10 10 0 0) $ Tall 2 0.01 0.5) -- > ) ||| Full ||| etc...--- > main = xmonad defaultConfig { layoutHook = myLayout }+-- > main = xmonad def { layoutHook = myLayout } -- -- This will produce a layout similar to DragPane, but with the possibility to have multiple windows in the left half -- and tabs that show the available windows. It will also produce a layout similar to ThreeColMid and a special layout -- created for use with a 80 columns wide Emacs window, its sidebar and a tabbed area for all other windows. --+-- The final layout is for applications that use a toolbar in a separate window, shown on a low resolution screen. It has+-- a master area that cover almost the whole screen. It leaves 10 px to the left and 10 px at the bottom. To the left+-- the toolbar is located and can be accessed by focusing this area. It is actually 200 px wide, but usually below the+-- other windows. Similarly all other windows are tiled, but behind the master window and can be accessed by moving the+-- mouse to the bottom of the screen. Everything can also be accessed by the standard focus changing key bindings.+-- -- This module can be used to create many different custom layouts, but there are limitations. The primary limitation -- can be observed in the second and third example when there are only two columns with windows in them. The leftmost -- area is left blank. These blank areas can be avoided by placing the rectangles appropriately.@@ -154,17 +168,24 @@ then box else maybe box id mbox - (sublist,sub') <- handle sub subs $ calcArea selBox rect+ (sublist,sub',schange) <- 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)+ (nextlist,next',nchange) <- case next of Nothing -> return ([], Nothing, False)+ Just n -> do (res, l, ch) <- handle n nexts rect+ return (res, Just l, ch) - return (sublist++nextlist, Just $ LayoutN subf' nextf' num box mbox sub' next' )+ let newlist = if (length $ maybe [] W.up s) < (length $ W.integrate' subs)+ then sublist++nextlist+ else nextlist++sublist+ newstate = if subf' /= subf || nextf' /= nextf || schange || nchange+ then Just $ LayoutN subf' nextf' num box mbox sub' next'+ else Nothing++ return (newlist, newstate) where handle l s' r = do (res,ml) <- runLayout (W.Workspace "" l s') r l' <- return $ maybe l id ml- return (res,l')+ return (res, l', isNothing ml) -- | Propagate messages. handleMessage l m@@ -244,11 +265,9 @@ subf' = foc subl subf nextf' = foc nextl nextf foc [] _ = Nothing- foc l f = if W.focus s `elem` l- then Just $ W.focus s- else if maybe False (`elem` l) f- then f- else Just $ head l+ foc l f | W.focus s `elem` l = Just $ W.focus s+ | maybe False (`elem` l) f = f+ | otherwise = listToMaybe l calcArea :: SubBox -> Rectangle -> Rectangle calcArea (SubBox xpos ypos width height) rect = Rectangle (rect_x rect + fromIntegral xpos') (rect_y rect + fromIntegral ypos') width' height'
XMonad/Layout/LayoutCombinators.hs view
@@ -68,7 +68,7 @@ -- example: -- -- > myLayout = (Tall 1 (3/100) (1/2) *//* Full) ||| (Tall 1 (3/100) (1/2) ***||** Full) ||| Full ||| etc..--- > main = xmonad defaultConfig { layoutHook = myLayout }+-- > main = xmonad def { layoutHook = myLayout } -- -- For more detailed instructions on editing the @layoutHook@ see: --
XMonad/Layout/LayoutHints.hs view
@@ -54,7 +54,7 @@ -- to some layout: -- -- > myLayout = layoutHints (Tall 1 (3/100) (1/2)) ||| Full ||| etc..--- > main = xmonad defaultConfig { layoutHook = myLayout }+-- > main = xmonad def { layoutHook = myLayout } -- -- Or, to center the adapted window in its available area: --@@ -74,8 +74,8 @@ -- -- > myHandleEventHook = hintsEventHook <+> ... -- >--- > main = xmonad defaultConfig { handleEventHook = myHandleEventHook--- > , ... }+-- > main = xmonad def { handleEventHook = myHandleEventHook+-- > , ... } layoutHints :: (LayoutClass l a) => l a -> ModifiedLayout LayoutHints l a layoutHints = ModifiedLayout (LayoutHints (0, 0))
XMonad/Layout/LimitWindows.hs view
@@ -47,7 +47,7 @@ -- > import XMonad.Layout.LimitWindows -- -- > myLayout = limitWindows 6 $ Tall 1 0.03 0.5 ||| Full ||| RandomOtherLayout...--- > main = xmonad defaultConfig { layoutHook = myLayout }+-- > main = xmonad def { layoutHook = myLayout } -- -- You may also be interested in dynamically changing the number dynamically, -- by binding keys to the 'increaseLimit', 'decreaseLimit', or 'setLimit'
XMonad/Layout/MagicFocus.hs view
@@ -28,7 +28,7 @@ import qualified XMonad.StackSet as W import XMonad.Layout.LayoutModifier -import XMonad.Actions.UpdatePointer(updatePointer, PointerPosition(TowardsCentre))+import XMonad.Actions.UpdatePointer (updatePointer) import Data.Monoid(All(..)) import qualified Data.Map as M @@ -41,8 +41,8 @@ -- modifier: -- -- > myLayout = magicFocus (Tall 1 (3/100) (1/2)) ||| Full ||| etc..--- > main = xmonad defaultConfig { layoutHook = myLayout,--- > handleEventHook = promoteWarp }+-- > main = xmonad def { layoutHook = myLayout,+-- > handleEventHook = promoteWarp } -- -- For more detailed instructions on editing the layoutHook see: --@@ -75,12 +75,12 @@ -- This eventHook does nothing when there are floating windows on the current -- workspace. promoteWarp :: Event -> X All-promoteWarp = promoteWarp' (TowardsCentre 0.15 0.15)+promoteWarp = promoteWarp' (0.5, 0.5) (0.85, 0.85) --- | promoteWarp' allows you to specify an arbitrary PointerPosition to apply--- when the mouse enters another window.-promoteWarp' :: PointerPosition -> Event -> X All-promoteWarp' pos e@(CrossingEvent {ev_window = w, ev_event_type = t})+-- | promoteWarp' allows you to specify an arbitrary pair of arguments to+-- pass to 'updatePointer' when the mouse enters another window.+promoteWarp' :: (Rational, Rational) -> (Rational, Rational) -> Event -> X All+promoteWarp' refPos ratio e@(CrossingEvent {ev_window = w, ev_event_type = t}) | t == enterNotify && ev_mode e == notifyNormal = do ws <- gets windowset let foc = W.peek ws@@ -88,10 +88,10 @@ wsFloats = M.filterWithKey (\k _ -> k `elem` st) $ W.floating ws if Just w /= foc && M.null wsFloats then do windows (W.swapMaster . W.focusWindow w)- updatePointer pos+ updatePointer refPos ratio return $ All False else return $ All True-promoteWarp' _ _ = return $ All True+promoteWarp' _ _ _ = return $ All True -- | Another event hook to override the focusFollowsMouse and make the pointer -- only follow if a given condition is satisfied. This could be used to disable
XMonad/Layout/Magnifier.hs view
@@ -44,7 +44,7 @@ -- to some layout: -- -- > myLayout = magnifier (Tall 1 (3/100) (1/2)) ||| Full ||| etc..--- > main = xmonad defaultConfig { layoutHook = myLayout }+-- > main = xmonad def { layoutHook = myLayout } -- -- By default magnifier increases the focused window's size by 1.5. -- You can also use:
XMonad/Layout/Master.hs view
@@ -18,6 +18,7 @@ -- $usage mastered,+ fixMastered, multimastered, AddMaster, ) where@@ -25,6 +26,7 @@ import XMonad import qualified XMonad.StackSet as S import XMonad.Layout.LayoutModifier+import Control.Monad -- $usage -- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:@@ -36,6 +38,10 @@ -- -- > mastered (1/100) (1/2) $ Grid --+-- Or if you prefer to have a master with fixed width:+--+-- > fixMastered (1/100) (1/2) $ Grid+-- -- Or if you want multiple (here two) master windows from the beginning: -- -- > multimastered 2 (1/100) (1/2) $ Grid@@ -53,7 +59,6 @@ -- layout data AddMaster a = AddMaster Int Rational Rational deriving (Show, Read) --- | Modifier which converts given layout to a mastered one multimastered :: (LayoutClass l a) => Int -- ^ @k@, number of master windows -> Rational -- ^ @delta@, the ratio of the screen to resize by@@ -70,7 +75,7 @@ mastered delta frac = multimastered 1 delta frac instance LayoutModifier AddMaster Window where- modifyLayout (AddMaster k delta frac) = applyMaster k delta frac+ modifyLayout (AddMaster k delta frac) = applyMaster False k delta frac modifierDescription _ = "Mastered" pureMess (AddMaster k delta frac) m@@ -80,19 +85,34 @@ pureMess _ _ = Nothing +data FixMaster a = FixMaster (AddMaster a) deriving (Show, Read)++instance LayoutModifier FixMaster Window where+ modifyLayout (FixMaster (AddMaster k d f)) = applyMaster True k d f+ modifierDescription (FixMaster a) = "Fix" ++ modifierDescription a+ pureMess (FixMaster a) m = liftM FixMaster (pureMess a m)++fixMastered :: (LayoutClass l a) =>+ Rational -- ^ @delta@, the ratio of the screen to resize by+ -> Rational -- ^ @frac@, what portion of the screen to use for the master window+ -> l a -- ^ the layout to be modified+ -> ModifiedLayout FixMaster l a+fixMastered delta frac = ModifiedLayout . FixMaster $ AddMaster 1 delta frac+ -- | Internal function for adding a master window and let the modified -- layout handle the rest of the windows applyMaster :: (LayoutClass l Window) =>- Int+ Bool+ -> Int -> Rational -> Rational -> S.Workspace WorkspaceId (l Window) Window -> Rectangle -> X ([(Window, Rectangle)], Maybe (l Window))-applyMaster k _ frac wksp rect = do+applyMaster f k _ frac wksp rect = do let st= S.stack wksp let ws = S.integrate' $ st- let n = length ws+ let n = length ws + fromEnum f if n > 1 then do if(n<=k) then return ((divideCol rect ws), Nothing)
XMonad/Layout/Maximize.hs view
@@ -19,6 +19,7 @@ -- * Usage -- $usage maximize,+ maximizeWithPadding, maximizeRestore, Maximize, MaximizeRestore, ) where@@ -35,9 +36,15 @@ -- -- Then edit your @layoutHook@ by adding the Maximize layout modifier: ----- > myLayout = maximize (Tall 1 (3/100) (1/2)) ||| Full ||| etc..--- > main = xmonad defaultConfig { layoutHook = myLayout }+-- > myLayout = maximize (Tall 1 (3/100) (1/2)) ||| Full ||| etc..)+-- > main = xmonad def { layoutHook = myLayout } --+-- Or, if you want to control the amount of padding placed around the+-- maximized window:+--+-- > 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"@@ -51,36 +58,43 @@ -- -- "XMonad.Doc.Extending#Editing_key_bindings". -data Maximize a = Maximize (Maybe Window) deriving ( Read, Show )+data Maximize a = Maximize Dimension (Maybe Window) deriving ( Read, Show ) maximize :: LayoutClass l Window => l Window -> ModifiedLayout Maximize l Window-maximize = ModifiedLayout $ Maximize Nothing+maximize = ModifiedLayout $ Maximize 25 Nothing +-- | Like 'maximize', but allows you to specify the amount of padding+-- placed around the maximized window.+maximizeWithPadding :: LayoutClass l Window => Dimension -> l Window -> ModifiedLayout Maximize l Window+maximizeWithPadding padding = ModifiedLayout $ Maximize padding Nothing+ data MaximizeRestore = MaximizeRestore Window deriving ( Typeable, Eq ) instance Message MaximizeRestore maximizeRestore :: Window -> MaximizeRestore maximizeRestore = MaximizeRestore instance LayoutModifier Maximize Window where- modifierDescription (Maximize _) = "Maximize"- pureModifier (Maximize (Just target)) rect (Just (S.Stack focused _ _)) wrs =+ modifierDescription (Maximize _ _) = "Maximize"+ pureModifier (Maximize padding (Just target)) rect (Just (S.Stack focused _ _)) wrs = if focused == target then (maxed ++ rest, Nothing) else (rest ++ maxed, lay) where (toMax, rest) = partition (\(w, _) -> w == target) wrs maxed = map (\(w, _) -> (w, maxRect)) toMax- maxRect = Rectangle (rect_x rect + 25) (rect_y rect + 25)- (rect_width rect - 50) (rect_height rect - 50)- lay | null maxed = Just (Maximize Nothing)+ maxRect = Rectangle (rect_x rect + fromIntegral padding)+ (rect_y rect + fromIntegral padding)+ (rect_width rect - padding * 2)+ (rect_height rect - padding * 2)+ lay | null maxed = Just (Maximize padding Nothing) | otherwise = Nothing pureModifier _ _ _ wrs = (wrs, Nothing) - pureMess (Maximize mw) m = case fromMessage m of+ pureMess (Maximize padding mw) m = case fromMessage m of Just (MaximizeRestore w) -> case mw of Just w' -> if (w == w')- then Just $ Maximize Nothing -- restore window- else Just $ Maximize $ Just w -- maximize different window- Nothing -> Just $ Maximize $ Just w -- maximize window+ then Just $ Maximize padding Nothing -- restore window+ else Just $ Maximize padding $ Just w -- maximize different window+ Nothing -> Just $ Maximize padding $ Just w -- maximize window _ -> Nothing -- vim: sw=4:et
XMonad/Layout/Minimize.hs view
@@ -41,7 +41,7 @@ -- Then edit your @layoutHook@ by adding the Minimize layout modifier: -- -- > myLayout = minimize (Tall 1 (3/100) (1/2)) ||| Full ||| etc..--- > main = xmonad defaultConfig { layoutHook = myLayout }+-- > main = xmonad def { layoutHook = myLayout } -- -- For more detailed instructions on editing the layoutHook see: --
XMonad/Layout/Monitor.hs view
@@ -10,7 +10,7 @@ -- Stability : unstable -- Portability : unportable ----- Layout modfier for displaying some window (monitor) above other windows+-- Layout modifier for displaying some window (monitor) above other windows. -- ----------------------------------------------------------------------------- module XMonad.Layout.Monitor (
XMonad/Layout/Mosaic.hs view
@@ -49,7 +49,7 @@ -- Then edit your @layoutHook@ by adding the Mosaic layout: -- -- > myLayout = mosaic 2 [3,2] ||| Full ||| etc..--- > main = xmonad $ defaultConfig { layoutHook = myLayout }+-- > main = xmonad $ def { layoutHook = myLayout } -- -- Unfortunately, infinite lists break serialization, so don't use them. And if -- the list is too short, it is extended with @++ repeat 1@, which covers the
XMonad/Layout/MosaicAlt.hs view
@@ -45,7 +45,7 @@ -- Then edit your @layoutHook@ by adding the MosaicAlt layout: -- -- > myLayout = MosaicAlt M.empty ||| Full ||| etc..--- > main = xmonad defaultConfig { layoutHook = myLayout }+-- > main = xmonad def { layoutHook = myLayout } -- -- For more detailed instructions on editing the layoutHook see: --
XMonad/Layout/MouseResizableTile.hs view
@@ -48,7 +48,7 @@ -- will not work correctly here because of the use of the mouse.) -- -- > myLayout = mouseResizableTile ||| etc..--- > main = xmonad defaultConfig { layoutHook = myLayout }+-- > main = xmonad def { layoutHook = myLayout } -- -- -- For more detailed instructions on editing the layoutHook see:
XMonad/Layout/MultiColumns.hs view
@@ -35,12 +35,12 @@ -- Then edit your @layoutHook@ by adding the multiCol layout: -- -- > myLayouts = multiCol [1] 4 0.01 0.5 ||| etc..--- > main = xmonad defaultConfig { layoutHook = myLayouts }+-- > main = xmonad def { layoutHook = myLayouts } -- -- Or alternatively: -- -- > myLayouts = Mirror (multiCol [1] 2 0.01 (-0.25)) ||| etc..--- > main = xmonad defaultConfig { layoutHook = myLayouts }+-- > main = xmonad def { layoutHook = myLayouts } -- -- The maximum number of windows in a column can be controlled using the -- IncMasterN messages and the column containing the focused window will be
XMonad/Layout/MultiToggle.hs view
@@ -99,7 +99,7 @@ transform :: (LayoutClass l a) => t -> l a -> (forall l'. (LayoutClass l' a) => l' a -> (l' a -> l a) -> b) -> b -data (LayoutClass l a) => EL l a = forall l'. (LayoutClass l' a) => EL (l' a) (l' a -> l a)+data EL l a = forall l'. (LayoutClass l' a) => EL (l' a) (l' a -> l a) unEL :: (LayoutClass l a) => EL l a -> (forall l'. (LayoutClass l' a) => l' a -> b) -> b unEL (EL x _) k = k x
XMonad/Layout/Named.hs view
@@ -34,7 +34,7 @@ -- to some layout: -- -- > myLayout = named "real big" Full ||| (nameTail $ named "real big" $ Full) ||| etc..--- > main = xmonad defaultConfig { layoutHook = myLayout }+-- > main = xmonad def { layoutHook = myLayout } -- -- For more detailed instructions on editing the layoutHook see: --
XMonad/Layout/NoFrillsDecoration.hs view
@@ -37,8 +37,8 @@ -- Then edit your @layoutHook@ by adding the NoFrillsDecoration to -- your layout: ----- > myL = noFrillsDeco shrinkText defaultTheme (layoutHook defaultConfig)--- > main = xmonad defaultConfig { layoutHook = myL }+-- > myL = noFrillsDeco shrinkText def (layoutHook def)+-- > main = xmonad def { layoutHook = myL } -- -- | Add very simple decorations to windows of a layout.
+ XMonad/Layout/PerScreen.hs view
@@ -0,0 +1,74 @@+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}++-----------------------------------------------------------------------------+-- |+-- Module : XMonad.Layout.PerScreen+-- Copyright : (c) Edward Z. Yang+-- License : BSD-style (see LICENSE)+--+-- Maintainer : <ezyang@cs.stanford.edu>+-- Stability : unstable+-- Portability : unportable+--+-- Configure layouts based on the width of your screen; use your+-- favorite multi-column layout for wide screens and a full-screen+-- layout for small ones.+-----------------------------------------------------------------------------++module XMonad.Layout.PerScreen+ ( -- * Usage+ -- $usage+ PerScreen,+ ifWider+ ) where++import XMonad+import qualified XMonad.StackSet as W++import Data.Maybe (fromMaybe)++-- $usage+-- You can use this module by importing it into your ~\/.xmonad\/xmonad.hs file:+--+-- > import XMonad.Layout.PerScreen+--+-- and modifying your layoutHook as follows (for example):+--+-- > layoutHook = ifWider 1280 (Tall 1 (3/100) (1/2) ||| Full) Full+--+-- Replace any of the layouts with any arbitrarily complicated layout.+-- ifWider can also be used inside other layout combinators.++ifWider :: (LayoutClass l1 a, LayoutClass l2 a)+ => Dimension -- ^ target screen width+ -> (l1 a) -- ^ layout to use when the screen is wide enough+ -> (l2 a) -- ^ layout to use otherwise+ -> PerScreen l1 l2 a+ifWider w = PerScreen w False++data PerScreen l1 l2 a = PerScreen Dimension Bool (l1 a) (l2 a) deriving (Read, Show)++-- | Construct new PerScreen values with possibly modified layouts.+mkNewPerScreenT :: PerScreen l1 l2 a -> Maybe (l1 a) ->+ PerScreen l1 l2 a+mkNewPerScreenT (PerScreen w _ lt lf) mlt' =+ (\lt' -> PerScreen w True lt' lf) $ fromMaybe lt mlt'++mkNewPerScreenF :: PerScreen l1 l2 a -> Maybe (l2 a) ->+ PerScreen l1 l2 a+mkNewPerScreenF (PerScreen w _ lt lf) mlf' =+ (\lf' -> PerScreen w False lt lf') $ fromMaybe lf mlf'++instance (LayoutClass l1 a, LayoutClass l2 a, Show a) => LayoutClass (PerScreen l1 l2) a where+ runLayout (W.Workspace i p@(PerScreen w _ lt lf) ms) r+ | rect_width r > w = do (wrs, mlt') <- runLayout (W.Workspace i lt ms) r+ return (wrs, Just $ mkNewPerScreenT p mlt')+ | otherwise = do (wrs, mlt') <- runLayout (W.Workspace i lf ms) r+ return (wrs, Just $ mkNewPerScreenF p mlt')++ handleMessage (PerScreen w bool lt lf) m+ | bool = handleMessage lt m >>= maybe (return Nothing) (\nt -> return . Just $ PerScreen w bool nt lf)+ | otherwise = handleMessage lf m >>= maybe (return Nothing) (\nf -> return . Just $ PerScreen w bool lt nf)++ description (PerScreen _ True l1 _) = description l1+ description (PerScreen _ _ _ l2) = description l2
XMonad/Layout/PerWorkspace.hs view
@@ -25,8 +25,6 @@ import XMonad import qualified XMonad.StackSet as W -import XMonad.Layout.LayoutModifier- import Data.Maybe (fromMaybe) -- $usage@@ -44,7 +42,8 @@ -- Note that @l1@, @l2@, and @l3@ can be arbitrarily complicated -- layouts, e.g. @(Full ||| smartBorders $ tabbed shrinkText -- defaultTConf ||| ...)@, and @m1@ can be any layout modifier, i.e. a--- function of type @(l a -> ModifiedLayout lm l a)@.+-- function of type @(l a -> ModifiedLayout lm l a)@. (In fact, @m1@ can be any+-- function @(LayoutClass l a, LayoutClass l' a) => l a -> l' a@.) -- -- In another scenario, suppose you wanted to have layouts A, B, and C -- available on all workspaces, except that on workspace foo you want@@ -69,25 +68,25 @@ -> (l1 a) -- ^ layout to use on matched workspaces -> (l2 a) -- ^ layout to use everywhere else -> PerWorkspace l1 l2 a-onWorkspaces wsIds l1 l2 = PerWorkspace wsIds False l1 l2+onWorkspaces wsIds = modWorkspaces wsIds . const -- | Specify a layout modifier to apply to a particular workspace; layouts -- on all other workspaces will remain unmodified.-modWorkspace :: (LayoutClass l a)- => WorkspaceId -- ^ tag of the workspace to match- -> (l a -> ModifiedLayout lm l a) -- ^ the modifier to apply on the matching workspace- -> l a -- ^ the base layout- -> PerWorkspace (ModifiedLayout lm l) l a+modWorkspace :: (LayoutClass l1 a, LayoutClass l2 a)+ => WorkspaceId -- ^ tag of the workspace to match+ -> (l2 a -> l1 a) -- ^ the modifier to apply on the matching workspace+ -> l2 a -- ^ the base layout+ -> PerWorkspace l1 l2 a modWorkspace wsId = modWorkspaces [wsId] -- | Specify a layout modifier to apply to a particular set of -- workspaces; layouts on all other workspaces will remain -- unmodified.-modWorkspaces :: (LayoutClass l a)- => [WorkspaceId] -- ^ tags of the workspaces to match- -> (l a -> ModifiedLayout lm l a) -- ^ the modifier to apply on the matching workspaces- -> l a -- ^ the base layout- -> PerWorkspace (ModifiedLayout lm l) l a+modWorkspaces :: (LayoutClass l1 a, LayoutClass l2 a)+ => [WorkspaceId] -- ^ tags of the workspaces to match+ -> (l2 a -> l1 a) -- ^ the modifier to apply on the matching workspaces+ -> l2 a -- ^ the base layout+ -> PerWorkspace l1 l2 a modWorkspaces wsIds f l = PerWorkspace wsIds False (f l) l -- | Structure for representing a workspace-specific layout along with
XMonad/Layout/PositionStoreFloat.hs view
@@ -45,8 +45,8 @@ -- BorderResize: -- -- > myLayouts = floatingDeco $ borderResize $ positionStoreFloat ||| etc..--- > where floatingDeco l = noFrillsDeco shrinkText defaultTheme l--- > main = xmonad defaultConfig { layoutHook = myLayouts }+-- > where floatingDeco l = noFrillsDeco shrinkText def l+-- > main = xmonad def { layoutHook = myLayouts } -- -- See the documentation of "XMonad.Hooks.PositionStoreHooks" on how -- to add the support hooks.
XMonad/Layout/ResizableTile.hs view
@@ -34,7 +34,7 @@ -- Then edit your @layoutHook@ by adding the ResizableTile layout: -- -- > myLayout = ResizableTall 1 (3/100) (1/2) [] ||| etc..--- > main = xmonad defaultConfig { layoutHook = myLayout }+-- > main = xmonad def { layoutHook = myLayout } -- -- For more detailed instructions on editing the layoutHook see: --
XMonad/Layout/Roledex.hs view
@@ -33,7 +33,7 @@ -- Then edit your @layoutHook@ by adding the Roledex layout: -- -- > myLayout = Roledex ||| etc..--- > main = xmonad defaultConfig { layoutHook = myLayout }+-- > main = xmonad def { layoutHook = myLayout } -- -- For more detailed instructions on editing the layoutHook see: --
XMonad/Layout/ShowWName.hs view
@@ -17,6 +17,7 @@ -- $usage showWName , showWName'+ , def , defaultSWNConfig , SWNConfig(..) , ShowWName@@ -34,8 +35,8 @@ -- @~\/.xmonad\/xmonad.hs@: -- -- > import XMonad.Layout.ShowWName--- > myLayout = layoutHook defaultConfig--- > main = xmonad defaultConfig { layoutHook = showWName myLayout }+-- > myLayout = layoutHook def+-- > main = xmonad def { layoutHook = showWName myLayout } -- -- For more detailed instructions on editing the layoutHook see: --@@ -43,7 +44,7 @@ -- | A layout modifier to show the workspace name when switching showWName :: l a -> ModifiedLayout ShowWName l a-showWName = ModifiedLayout (SWN True defaultSWNConfig Nothing)+showWName = ModifiedLayout (SWN True def Nothing) -- | A layout modifier to show the workspace name when switching. It -- is possible to provide a custom configuration.@@ -60,14 +61,18 @@ , swn_fade :: Rational -- ^ Time in seconds of the name visibility } deriving (Read, Show) -defaultSWNConfig :: SWNConfig-defaultSWNConfig =+instance Default SWNConfig where+ def = SWNC { swn_font = "-misc-fixed-*-*-*-*-20-*-*-*-*-*-*-*" , swn_bgcolor = "black" , swn_color = "white" , swn_fade = 1 } +{-# DEPRECATED defaultSWNConfig "Use def (from Data.Default, and re-exported from XMonad.Layout.ShowWName) instead." #-}+defaultSWNConfig :: SWNConfig+defaultSWNConfig = def+ instance LayoutModifier ShowWName a where redoLayout sn r _ wrs = doShow sn r wrs @@ -99,6 +104,5 @@ showWindow w paintAndWrite w f (fi width) (fi hight) 0 (swn_bgcolor c) "" (swn_color c) (swn_bgcolor c) [AlignCenter] [n] releaseXMF f- io $ sync d False i <- startTimer (swn_fade c) return (wrs, Just $ SWN False c $ Just (i,w))
XMonad/Layout/SimpleDecoration.hs view
@@ -20,6 +20,7 @@ -- $usage simpleDeco , Theme (..)+ , def , defaultTheme , SimpleDecoration (..) , shrinkText, CustomShrink(CustomShrink)@@ -38,8 +39,8 @@ -- Then edit your @layoutHook@ by adding the SimpleDecoration decoration to -- your layout: ----- > myL = simpleDeco shrinkText defaultTheme (layoutHook defaultConfig)--- > main = xmonad defaultConfig { layoutHook = myL }+-- > myL = simpleDeco shrinkText def (layoutHook def)+-- > main = xmonad def { layoutHook = myL } -- -- For more detailed instructions on editing the layoutHook see: --@@ -47,12 +48,12 @@ -- -- You can also edit the default configuration options. ----- > mySDConfig = defaultTheme { inactiveBorderColor = "red"--- > , inactiveTextColor = "red"}+-- > mySDConfig = def { inactiveBorderColor = "red"+-- > , inactiveTextColor = "red"} -- -- and ----- > myL = dwmStyle shrinkText mySDConfig (layoutHook defaultTheme)+-- > myL = dwmStyle shrinkText mySDConfig (layoutHook def) -- | Add simple decorations to windows of a layout. simpleDeco :: (Eq a, Shrinker s) => s -> Theme
XMonad/Layout/SimpleFloat.hs view
@@ -39,7 +39,7 @@ -- Then edit your @layoutHook@ by adding the SimpleFloat layout: -- -- > myLayout = simpleFloat ||| Full ||| etc..--- > main = xmonad defaultConfig { layoutHook = myLayout }+-- > main = xmonad def { layoutHook = myLayout } -- -- For more detailed instructions on editing the layoutHook see: --@@ -51,7 +51,7 @@ -- This version is decorated with the 'SimpleDecoration' style. simpleFloat :: Eq a => ModifiedLayout (Decoration SimpleDecoration DefaultShrinker) (ModifiedLayout MouseResize (ModifiedLayout WindowArranger SimpleFloat)) a-simpleFloat = decoration shrinkText defaultTheme (Simple False) (mouseResize $ windowArrangeAll $ SF 20)+simpleFloat = decoration shrinkText def (Simple False) (mouseResize $ windowArrangeAll $ SF 20) -- | Same as 'simpleFloat', but with the possibility of setting a -- custom shrinker and a custom theme.
XMonad/Layout/Simplest.hs view
@@ -30,7 +30,7 @@ -- Then edit your @layoutHook@ by adding the Simplest layout: -- -- > myLayout = Simplest ||| Full ||| etc..--- > main = xmonad defaultConfig { layoutHook = myLayout }+-- > main = xmonad def { layoutHook = myLayout } -- -- For more detailed instructions on editing the layoutHook see: --
XMonad/Layout/SimplestFloat.hs view
@@ -34,7 +34,7 @@ -- Then edit your @layoutHook@ by adding the SimplestFloat layout: -- -- > myLayout = simplestFloat ||| Full ||| etc..--- > main = xmonad defaultConfig { layoutHook = myLayout }+-- > main = xmonad def { layoutHook = myLayout } -- -- For more detailed instructions on editing the layoutHook see: --
XMonad/Layout/Spacing.hs view
@@ -1,4 +1,5 @@-{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, DeriveDataTypeable #-}+{-# LANGUAGE PatternGuards #-} ----------------------------------------------------------------------------- -- |@@ -18,12 +19,17 @@ -- $usage spacing, Spacing,+ spacingWithEdge, SpacingWithEdge, smartSpacing, SmartSpacing,-+ smartSpacingWithEdge, SmartSpacingWithEdge,+ ModifySpacing(..), setSpacing, incSpacing ) where import Graphics.X11 (Rectangle(..)) import Control.Arrow (second)+import XMonad.Operations (sendMessage)+import XMonad.Core (X,runLayout,Message,fromMessage,Typeable)+import XMonad.StackSet (up, down, Workspace(..)) import XMonad.Util.Font (fi) import XMonad.Layout.LayoutModifier@@ -45,12 +51,47 @@ data Spacing a = Spacing Int deriving (Show, Read) +-- | Message to dynamically modify (e.g. increase/decrease/set) the size of the window spacing+data ModifySpacing = ModifySpacing (Int -> Int) deriving (Typeable)+instance Message ModifySpacing++-- | Set spacing to given amount+setSpacing :: Int -> X ()+setSpacing n = sendMessage $ ModifySpacing $ const n++-- | Increase spacing by given amount+incSpacing :: Int -> X ()+incSpacing n = sendMessage $ ModifySpacing $ (+n)+ instance LayoutModifier Spacing a where pureModifier (Spacing p) _ _ wrs = (map (second $ shrinkRect p) wrs, Nothing) + pureMess (Spacing px) m+ | Just (ModifySpacing f) <- fromMessage m = Just $ Spacing $ max 0 $ f px+ | otherwise = Nothing+ modifierDescription (Spacing p) = "Spacing " ++ show p +-- | Surround all windows by a certain number of pixels of blank space, and+-- additionally adds the same amount of spacing around the edge of the screen.+spacingWithEdge :: Int -> l a -> ModifiedLayout SpacingWithEdge l a+spacingWithEdge p = ModifiedLayout (SpacingWithEdge p)++data SpacingWithEdge a = SpacingWithEdge Int deriving (Show, Read)++instance LayoutModifier SpacingWithEdge a where++ pureModifier (SpacingWithEdge p) _ _ wrs = (map (second $ shrinkRect p) wrs, Nothing)++ pureMess (SpacingWithEdge px) m+ | Just (ModifySpacing f) <- fromMessage m = Just $ SpacingWithEdge $ max 0 $ f px+ | otherwise = Nothing++ modifyLayout (SpacingWithEdge p) w r = runLayout w (shrinkRect p r)++ modifierDescription (SpacingWithEdge p) = "SpacingWithEdge " ++ show p+ shrinkRect :: Int -> Rectangle -> Rectangle shrinkRect p (Rectangle x y w h) = Rectangle (x+fi p) (y+fi p) (w-2*fi p) (h-2*fi p) @@ -67,3 +108,22 @@ pureModifier (SmartSpacing p) _ _ wrs = (map (second $ shrinkRect p) wrs, Nothing) modifierDescription (SmartSpacing p) = "SmartSpacing " ++ show p++-- | Surrounds all windows with blank space, and adds the same amount of spacing+-- around the edge of the screen, except when the window is the only visible+-- window on the current workspace.+smartSpacingWithEdge :: Int -> l a -> ModifiedLayout SmartSpacingWithEdge l a+smartSpacingWithEdge p = ModifiedLayout (SmartSpacingWithEdge p)++data SmartSpacingWithEdge a = SmartSpacingWithEdge Int deriving (Show, Read)++instance LayoutModifier SmartSpacingWithEdge a where++ pureModifier _ _ _ [x] = ([x], Nothing)+ pureModifier (SmartSpacingWithEdge p) _ _ wrs = (map (second $ shrinkRect p) wrs, Nothing)++ modifyLayout (SmartSpacingWithEdge p) w r+ | maybe False (\s -> null (up s) && null (down s)) (stack w) = runLayout w r+ | otherwise = runLayout w (shrinkRect p r)++ modifierDescription (SmartSpacingWithEdge p) = "SmartSpacingWithEdge " ++ show p
XMonad/Layout/Spiral.hs view
@@ -37,7 +37,7 @@ -- Then edit your @layoutHook@ by adding the Spiral layout: -- -- > myLayout = spiral (6/7) ||| etc..--- > main = xmonad defaultConfig { layoutHook = myLayout }+-- > main = xmonad def { layoutHook = myLayout } -- -- For more detailed instructions on editing the layoutHook see: --
XMonad/Layout/StackTile.hs view
@@ -33,7 +33,7 @@ -- Then edit your @layoutHook@ by adding the StackTile layout: -- -- > myLayout = StackTile 1 (3/100) (1/2) ||| etc..--- > main = xmonad defaultConfig { layoutHook = myLayout }+-- > main = xmonad def { layoutHook = myLayout } -- -- For more detailed instructions on editing the layoutHook see: --
+ XMonad/Layout/Stoppable.hs view
@@ -0,0 +1,127 @@+{-# LANGUAGE MultiParamTypeClasses, TypeSynonymInstances #-}+{-# LANGUAGE PatternGuards #-}+-----------------------------------------------------------------------------+-- |+-- Module : XMonad.Layout.Stoppable+-- Copyright : (c) Anton Vorontsov <anton@enomsg.org> 2014+-- License : BSD-style (as xmonad)+--+-- Maintainer : Anton Vorontsov <anton@enomsg.org>+-- Stability : unstable+-- Portability : unportable+--+-- This module implements a special kind of layout modifier, which when+-- applied to a layout, causes xmonad to stop all non-visible processes.+-- In a way, this is a sledge-hammer for applications that drain power.+-- For example, given a web browser on a stoppable workspace, once the+-- workspace is hidden the web browser will be stopped.+--+-- Note that the stopped application won't be able to communicate with X11+-- clipboard. For this, the module actually stops applications after a+-- certain delay, giving a chance for a user to complete copy-paste+-- sequence. By default, the delay equals to 15 seconds, it is+-- configurable via 'Stoppable' constructor.+--+-- The stoppable modifier prepends a mark (by default equals to+-- \"Stoppable\") to the layout description (alternatively, you can choose+-- your own mark and use it with 'Stoppable' constructor). The stoppable+-- layout (identified by a mark) spans to multiple workspaces, letting you+-- to create groups of stoppable workspaces that only stop processes when+-- none of the workspaces are visible, and conversely, unfreezing all+-- processes even if one of the stoppable workspaces are visible.+--+-- To stop the process we use signals, which works for most cases. For+-- processes that tinker with signal handling (debuggers), another+-- (Linux-centric) approach may be used. See+-- <https://www.kernel.org/doc/Documentation/cgroups/freezer-subsystem.txt>+--+-----------------------------------------------------------------------------++module XMonad.Layout.Stoppable+ ( -- $usage+ Stoppable(..)+ , stoppable+ ) where++import XMonad+import XMonad.Actions.WithAll+import XMonad.Util.WindowProperties+import XMonad.Util.RemoteWindows+import XMonad.Util.Timer+import XMonad.StackSet hiding (filter)+import XMonad.Layout.LayoutModifier+import System.Posix.Signals+import Data.Maybe+import Control.Monad++-- $usage+-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+--+-- > import XMonad+-- > import XMonad.Layout.Stoppable+-- >+-- > main = xmonad def+-- > { layoutHook = layoutHook def ||| stoppable (layoutHook def) }+--+-- Note that the module has to distinguish between local and remote+-- proccesses, which means that it needs to know the hostname, so it looks+-- for environment variables (e.g. HOST).+--+-- Environment variables will work for most cases, but won't work if the+-- hostname changes. To cover dynamic hostnames case, in addition to+-- 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"++signalWindow :: Signal -> Window -> X ()+signalWindow s w = do+ pid <- getProp32s "_NET_WM_PID" w+ io $ (signalProcess s . fromIntegral) `mapM_` fromMaybe [] pid++signalLocalWindow :: Signal -> Window -> X ()+signalLocalWindow s w = isLocalWindow w >>= flip when (signalWindow s w)++withAllOn :: (a -> X ()) -> Workspace i l a -> X ()+withAllOn f wspc = f `mapM_` integrate' (stack wspc)++withAllFiltered :: (Workspace i l a -> Bool)+ -> [Workspace i l a]+ -> (a -> X ()) -> X ()+withAllFiltered p wspcs f = withAllOn f `mapM_` filter p wspcs++sigStoppableWorkspacesHook :: String -> X ()+sigStoppableWorkspacesHook k = do+ ws <- gets windowset+ withAllFiltered isStoppable (hidden ws) (signalLocalWindow sigSTOP)+ where+ isStoppable ws = k `elem` words (description $ layout ws)++-- | Data type for ModifiedLayout. The constructor lets you to specify a+-- custom mark/description modifier and a delay. You can also use+-- 'stoppable' helper function.+data Stoppable a = Stoppable+ { mark :: String+ , delay :: Rational+ , timer :: Maybe TimerId+ } deriving (Show,Read)++instance LayoutModifier Stoppable Window where+ modifierDescription = mark++ hook _ = withAll $ signalLocalWindow sigCONT++ handleMess (Stoppable m _ (Just tid)) msg+ | Just ev <- fromMessage msg = handleTimer tid ev run+ where run = sigStoppableWorkspacesHook m >> return Nothing+ handleMess (Stoppable m d _) msg+ | Just Hide <- fromMessage msg =+ (Just . Stoppable m d . Just) `liftM` startTimer d+ | otherwise = return Nothing++-- | Convert a layout to a stoppable layout using the default mark+-- (\"Stoppable\") and a delay of 15 seconds.+stoppable :: l a -> ModifiedLayout Stoppable l a+stoppable = ModifiedLayout (Stoppable "Stoppable" 15 Nothing)
XMonad/Layout/SubLayouts.hs view
@@ -45,12 +45,12 @@ redoLayout), ModifiedLayout(..)) import XMonad.Layout.Simplest(Simplest(..))-import XMonad.Layout.Tabbed(defaultTheme, shrinkText,+import XMonad.Layout.Tabbed(shrinkText, TabbedDecoration, addTabs) import XMonad.Layout.WindowNavigation(Navigate(Apply)) import XMonad.Util.Invisible(Invisible(..)) import XMonad.Util.Types(Direction2D(..))-import XMonad+import XMonad hiding (def) import Control.Applicative((<$>),(<*)) import Control.Arrow(Arrow(second, (&&&))) import Control.Monad(MonadPlus(mplus), foldM, guard, when, join)@@ -59,6 +59,7 @@ import Data.Maybe(isNothing, fromMaybe, listToMaybe, mapMaybe) import Data.Traversable(sequenceA) +import qualified XMonad as X import qualified XMonad.Layout.BoringWindows as B import qualified XMonad.StackSet as W import qualified Data.Map as M@@ -123,7 +124,7 @@ -- -- > myLayout = windowNavigation $ subTabbed $ boringWindows $ -- > Tall 1 (3/100) (1/2) ||| etc..--- > main = xmonad defaultConfig { layoutHook = myLayout }+-- > main = xmonad def { layoutHook = myLayout } -- -- "XMonad.Layout.WindowNavigation" is used to specify which windows to merge, -- and it is not integrated into the modifier because it can be configured, and@@ -182,7 +183,7 @@ -- Ex. The second group is 'Tall', the third is 'Circle', all others are tabbed -- with: ----- > myLayout = addTabs shrinkText defaultTheme+-- > myLayout = addTabs shrinkText def -- > $ 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@@ -192,7 +193,7 @@ subTabbed :: (Eq a, LayoutModifier (Sublayout Simplest) a, LayoutClass l a) => l a -> ModifiedLayout (Decoration TabbedDecoration DefaultShrinker) (ModifiedLayout (Sublayout Simplest) l) a-subTabbed x = addTabs shrinkText defaultTheme $ subLayout [] Simplest x+subTabbed x = addTabs shrinkText X.def $ subLayout [] Simplest x -- | @defaultSublMap@ is an attempt to create a set of keybindings like the -- defaults ones but to be used as a 'submap' for sending messages to the
XMonad/Layout/TabBarDecoration.hs view
@@ -16,7 +16,7 @@ ( -- * Usage -- $usage simpleTabBar, tabBar- , defaultTheme, shrinkText+ , def, defaultTheme, shrinkText , TabBarDecoration (..), XPPosition (..) , module XMonad.Layout.ResizeScreen ) where@@ -36,7 +36,7 @@ -- -- Then edit your @layoutHook@ by adding the layout you want: ----- > main = xmonad defaultConfig { layoutHook = simpleTabBar $ layoutHook defaultConfig}+-- > main = xmonad def { layoutHook = simpleTabBar $ layoutHook def} -- -- For more detailed instructions on editing the layoutHook see: --@@ -53,7 +53,7 @@ -- | layout, with the default theme and the default shrinker. simpleTabBar :: Eq a => l a -> ModifiedLayout (Decoration TabBarDecoration DefaultShrinker) (ModifiedLayout ResizeScreen l) a-simpleTabBar = decoration shrinkText defaultTheme (TabBar Top) . resizeVertical 20+simpleTabBar = decoration shrinkText def (TabBar Top) . resizeVertical 20 -- | Same of 'simpleTabBar', but with the possibility of setting a -- custom shrinker, a custom theme and the position: 'Top' or
XMonad/Layout/Tabbed.hs view
@@ -20,13 +20,18 @@ simpleTabbed, tabbed, addTabs , simpleTabbedAlways, tabbedAlways, addTabsAlways , simpleTabbedBottom, tabbedBottom, addTabsBottom+ , simpleTabbedLeft, tabbedLeft, addTabsLeft+ , simpleTabbedRight, tabbedRight, addTabsRight , simpleTabbedBottomAlways, tabbedBottomAlways, addTabsBottomAlways+ , simpleTabbedLeftAlways, tabbedLeftAlways, addTabsLeftAlways+ , simpleTabbedRightAlways, tabbedRightAlways, addTabsRightAlways , Theme (..)+ , def , defaultTheme , TabbedDecoration (..) , shrinkText, CustomShrink(CustomShrink) , Shrinker(..)- , TabbarShown, TabbarLocation+ , TabbarShown, Direction2D(..) ) where import Data.List@@ -35,6 +40,7 @@ import qualified XMonad.StackSet as S import XMonad.Layout.Decoration import XMonad.Layout.Simplest ( Simplest(Simplest) )+import XMonad.Util.Types (Direction2D(..)) -- $usage -- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:@@ -47,11 +53,11 @@ -- -- or, if you want a specific theme for you tabbed layout: ----- > myLayout = tabbed shrinkText defaultTheme ||| Full ||| etc..+-- > myLayout = tabbed shrinkText def ||| Full ||| etc.. -- -- and then: ----- > main = xmonad defaultConfig { layoutHook = myLayout }+-- > main = xmonad def { layoutHook = myLayout } -- -- This layout has hardcoded behaviour for mouse clicks on tab decorations: -- Left click on the tab switches focus to that window.@@ -67,8 +73,8 @@ -- -- You can also edit the default configuration options. ----- > myTabConfig = defaultTheme { inactiveBorderColor = "#FF0000"--- > , activeTextColor = "#00FF00"}+-- > myTabConfig = def { inactiveBorderColor = "#FF0000"+-- > , activeTextColor = "#00FF00"} -- -- and --@@ -82,21 +88,33 @@ -- -- > import XMonad -- > import XMonad.Layout.Tabbed--- > main = xmonad defaultConfig { layoutHook = simpleTabbed }+-- > main = xmonad def { layoutHook = simpleTabbed } simpleTabbed :: ModifiedLayout (Decoration TabbedDecoration DefaultShrinker) Simplest Window-simpleTabbed = tabbed shrinkText defaultTheme+simpleTabbed = tabbed shrinkText def simpleTabbedAlways :: ModifiedLayout (Decoration TabbedDecoration DefaultShrinker) Simplest Window-simpleTabbedAlways = tabbedAlways shrinkText defaultTheme+simpleTabbedAlways = tabbedAlways shrinkText def -- | A bottom-tabbed layout with the default xmonad Theme. simpleTabbedBottom :: ModifiedLayout (Decoration TabbedDecoration DefaultShrinker) Simplest Window-simpleTabbedBottom = tabbedBottom shrinkText defaultTheme+simpleTabbedBottom = tabbedBottom shrinkText def -- | A bottom-tabbed layout with the default xmonad Theme. simpleTabbedBottomAlways :: ModifiedLayout (Decoration TabbedDecoration DefaultShrinker) Simplest Window-simpleTabbedBottomAlways = tabbedBottomAlways shrinkText defaultTheme+simpleTabbedBottomAlways = tabbedBottomAlways shrinkText def +-- | A side-tabbed layout with the default xmonad Theme.+simpleTabbedLeft, simpleTabbedRight :: ModifiedLayout (Decoration TabbedDecoration DefaultShrinker) + Simplest Window+simpleTabbedLeft = tabbedLeft shrinkText def+simpleTabbedRight = tabbedRight shrinkText def++-- | A side-tabbed layout with the default xmonad Theme.+simpleTabbedLeftAlways, simpleTabbedRightAlways :: ModifiedLayout (Decoration TabbedDecoration DefaultShrinker) + Simplest Window+simpleTabbedLeftAlways = tabbedLeftAlways shrinkText def+simpleTabbedRightAlways = tabbedRightAlways shrinkText def+ -- | A layout decorated with tabs and the possibility to set a custom -- shrinker and theme. tabbed :: (Eq a, Shrinker s) => s -> Theme@@ -117,68 +135,103 @@ -> ModifiedLayout (Decoration TabbedDecoration s) Simplest a tabbedBottomAlways s c = addTabsBottomAlways s c Simplest +-- | A layout decorated with tabs and the possibility to set a custom+-- shrinker and theme.+tabbedLeft, tabbedRight :: (Eq a, Shrinker s) => s -> Theme+ -> ModifiedLayout (Decoration TabbedDecoration s) Simplest a+tabbedLeft s c = addTabsLeft s c Simplest+tabbedRight s c = addTabsRight s c Simplest++-- | A layout decorated with tabs and the possibility to set a custom+-- shrinker and theme.+tabbedLeftAlways, tabbedRightAlways :: (Eq a, Shrinker s) => s -> Theme+ -> ModifiedLayout (Decoration TabbedDecoration s) Simplest a+tabbedLeftAlways s c = addTabsLeftAlways s c Simplest+tabbedRightAlways s c = addTabsRightAlways s c Simplest+ -- Layout Modifiers -- | A layout modifier that uses the provided shrinker and theme to add tabs to any layout. addTabs :: (Eq a, LayoutClass l a, Shrinker s) => s -> Theme -> l a -> ModifiedLayout (Decoration TabbedDecoration s) l a-addTabs = createTabs WhenPlural Top+addTabs = createTabs WhenPlural U addTabsAlways :: (Eq a, LayoutClass l a, Shrinker s) => s -> Theme -> l a -> ModifiedLayout (Decoration TabbedDecoration s) l a-addTabsAlways = createTabs Always Top+addTabsAlways = createTabs Always U -- | A layout modifier that uses the provided shrinker and theme to add tabs to the bottom of any layout. addTabsBottom :: (Eq a, LayoutClass l a, Shrinker s) => s -> Theme -> l a -> ModifiedLayout (Decoration TabbedDecoration s) l a-addTabsBottom = createTabs WhenPlural Bottom+addTabsBottom = createTabs WhenPlural D addTabsBottomAlways :: (Eq a, LayoutClass l a, Shrinker s) => s -> Theme -> l a -> ModifiedLayout (Decoration TabbedDecoration s) l a-addTabsBottomAlways = createTabs Always Bottom+addTabsBottomAlways = createTabs Always D +-- | A layout modifier that uses the provided shrinker and theme to add tabs to the side of any layout.+addTabsRight, addTabsLeft :: (Eq a, LayoutClass l a, Shrinker s) => s -> Theme -> l a+ -> ModifiedLayout (Decoration TabbedDecoration s) l a+addTabsRight = createTabs WhenPlural R+addTabsLeft = createTabs WhenPlural L +addTabsRightAlways, addTabsLeftAlways :: (Eq a, LayoutClass l a, Shrinker s) => s -> Theme -> l a+ -> ModifiedLayout (Decoration TabbedDecoration s) l a+addTabsRightAlways = createTabs Always R+addTabsLeftAlways = createTabs Always L+ -- Tab creation abstractions. Internal use only. -- Create tabbar when required at the given location with the given -- shrinker and theme to the supplied layout.-createTabs ::(Eq a, LayoutClass l a, Shrinker s) => TabbarShown -> TabbarLocation -> s+createTabs ::(Eq a, LayoutClass l a, Shrinker s) => TabbarShown -> Direction2D -> s -> Theme -> l a -> ModifiedLayout (Decoration TabbedDecoration s) l a-createTabs sh loc tx th l = decoration tx th (Tabbed loc sh) l -data TabbarLocation = Top | Bottom deriving (Read,Show)+createTabs sh loc tx th l = decoration tx th (Tabbed loc sh) l data TabbarShown = Always | WhenPlural deriving (Read, Show, Eq) -data TabbedDecoration a = Tabbed TabbarLocation TabbarShown deriving (Read, Show)+data TabbedDecoration a = Tabbed Direction2D TabbarShown deriving (Read, Show) instance Eq a => DecorationStyle TabbedDecoration a where- describeDeco (Tabbed Top _ ) = "Tabbed"- describeDeco (Tabbed Bottom _ ) = "Tabbed Bottom"+ describeDeco (Tabbed U _ ) = "Tabbed"+ describeDeco (Tabbed D _ ) = "Tabbed Bottom"+ describeDeco (Tabbed L _ ) = "Tabbed Left"+ describeDeco (Tabbed R _ ) = "Tabbed Right" decorationEventHook _ ds ButtonEvent { ev_window = ew , ev_event_type = et , ev_button = eb } | et == buttonPress- , Just ((w,_),_) <-findWindowByDecoration ew ds =+ , Just ((w,_),_) <- findWindowByDecoration ew ds = if eb == button2 then killWindow w else focus w decorationEventHook _ _ _ = return () - pureDecoration (Tabbed lc sh) _ ht _ s wrs (w,r@(Rectangle x y wh hh))+ pureDecoration (Tabbed lc sh) wt ht _ s wrs (w,r@(Rectangle x y wh hh)) = if ((sh == Always && numWindows > 0) || numWindows > 1) then Just $ case lc of- Top -> upperTab- Bottom -> lowerTab+ U -> upperTab+ D -> lowerTab+ L -> leftTab+ R -> rightTab else Nothing where ws = filter (`elem` map fst (filter ((==r) . snd) wrs)) (S.integrate s)- loc i = x + fi ((wh * fi i) `div` max 1 (fi $ length ws))- wid = fi $ maybe x (\i -> loc (i+1) - loc i) $ w `elemIndex` ws- nx = maybe x loc $ w `elemIndex` ws- upperTab = Rectangle nx y wid (fi ht)- lowerTab = Rectangle nx (y+fi(hh-ht)) wid (fi ht)+ loc k h i = k + fi ((h * fi i) `div` max 1 (fi $ length ws))+ esize k h = fi $ maybe k (\i -> loc k h (i+1) - loc k h i) $ w `elemIndex` ws+ wid = esize x wh+ hid = esize y hh+ n k h = maybe k (loc k h) $ w `elemIndex` ws+ nx = n x wh+ ny = n y hh+ upperTab = Rectangle nx y wid (fi ht)+ lowerTab = Rectangle nx (y + fi (hh - ht)) wid (fi ht)+ leftTab = Rectangle x ny (fi wt) hid+ rightTab = Rectangle (x + fi (wh - wt)) ny (fi wt) hid numWindows = length ws- shrink (Tabbed loc _ ) (Rectangle _ _ _ dh) (Rectangle x y w h)+ shrink (Tabbed loc _ ) (Rectangle _ _ dw dh) (Rectangle x y w h) = case loc of- Top -> Rectangle x (y + fi dh) w (h - dh)- Bottom -> Rectangle x y w (h - dh)+ U -> Rectangle x (y + fi dh) w (h - dh)+ D -> Rectangle x y w (h - dh)+ L -> Rectangle (x + fi dw) y (w - dw) h+ R -> Rectangle x y (w - dw) h
XMonad/Layout/ThreeColumns.hs view
@@ -39,7 +39,7 @@ -- Then edit your @layoutHook@ by adding the ThreeCol layout: -- -- > myLayout = ThreeCol 1 (3/100) (1/2) ||| ThreeColMid 1 (3/100) (1/2) ||| etc..--- > main = xmonad defaultConfig { layoutHook = myLayout }+-- > main = xmonad def { layoutHook = myLayout } -- -- The first argument specifies how many windows initially appear in the main -- window. The second argument argument specifies the amount to resize while
XMonad/Layout/ToggleLayouts.hs view
@@ -30,7 +30,7 @@ -- Then edit your @layoutHook@ by adding the ToggleLayouts layout: -- -- > myLayout = toggleLayouts Full (Tall 1 (3/100) (1/2)) ||| etc..--- > main = xmonad defaultConfig { layoutHook = myLayout }+-- > main = xmonad def { layoutHook = myLayout } -- -- For more detailed instructions on editing the layoutHook see: --
XMonad/Layout/TrackFloating.hs view
@@ -2,7 +2,8 @@ {- | Module : XMonad.Layout.TrackFloating-Copyright : (c) 2010 Adam Vogt+Copyright : (c) 2010 & 2013 Adam Vogt+ 2011 Willem Vanlint License : BSD-style (see xmonad/LICENSE) Maintainer : vogt.adam@gmail.com@@ -13,8 +14,9 @@ is in use. This is particularly helpful for tiled layouts where the focus determines what is visible. -The relevant bug is Issue 4-<http://code.google.com/p/xmonad/issues/detail?id=4>.+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@@ -23,7 +25,11 @@ -- ** For other layout modifiers -- $layoutModifier trackFloating,+ useTransientFor,++ -- ** Exported types TrackFloating,+ UseTransientFor, ) where import Control.Monad@@ -37,7 +43,9 @@ import XMonad.Layout.LayoutModifier import qualified XMonad.StackSet as W +import qualified Data.Traversable as T + data TrackFloating a = TrackFloating { _wasFloating :: Bool, _tiledFocus :: Maybe Window }@@ -75,15 +83,69 @@ in guard (n /= os) >> Just n) ++{- | When focus is on the tiled layer, the underlying layout is run with focus+on the window named by the WM_TRANSIENT_FOR property on the floating window.+-}+useTransientFor :: l a -> ModifiedLayout UseTransientFor l a+useTransientFor x = ModifiedLayout UseTransientFor x++data UseTransientFor a = UseTransientFor deriving (Read,Show,Eq)++instance LayoutModifier UseTransientFor Window where+ modifyLayout _ ws@(W.Workspace{ W.stack = ms }) r = do+ m <- gets (W.peek . windowset)+ d <- asks display+ parent <- fmap join $ T.traverse (io . getTransientForHint d) m++ s0 <- get+ whenJust parent $ \p -> put s0{ windowset = W.focusWindow p (windowset s0) }+ result <- runLayout ws{ W.stack = fromMaybe ms (liftM2 focusWin ms parent) } r++ m' <- gets (W.peek . windowset)++ when (m' == parent) $+ -- layout changed the windowset, so don't clobber it+ whenJust m $ \p -> put s0{ windowset = W.focusWindow p (windowset s0) }++ return result++++focusWin :: Eq a => W.Stack a -> a -> Maybe (W.Stack a)+focusWin st@(W.Stack f u d) w+ | w `elem` u || w `elem` d = Just . head . filter ((==w) . W.focus)+ $ iterate (if w `elem` u then W.focusUp'+ else W.focusDown') st+ | w == f = Just st+ | otherwise = Nothing+++ {- $usage Apply to your layout in a config like: -> main = xmonad (defaultConfig{-> layoutHook = trackFloating-> (noBorders Full ||| Tall 1 0.3 0.5),+> main = xmonad (def{+> layoutHook = trackFloating (useTransientFor+> (noBorders Full ||| Tall 1 0.3 0.5)), > ... > })+++'useTransientFor' and 'trackFloating' can be enabled independently. For+example when the floating window sets @WM_TRANSIENT_FOR@, such as libreoffice's+file->preferences window, @optionA@ will have the last-focused window magnified+while @optionB@ will result magnify the window that opened the preferences+window regardless of which tiled window was focused before.++> import XMonad.Layout.Magnifier+> import XMonad.Layout.TrackFloating+>+> underlyingLayout = magnifier (Tall 1 0.3 0.5)+>+> optionA = trackFloating underlyingLayout+> optionB = trackFloating (useTransientFor underlyingLayout) -}
XMonad/Layout/TwoPane.hs view
@@ -33,7 +33,7 @@ -- Then edit your @layoutHook@ by adding the TwoPane layout: -- -- > myLayout = TwoPane (3/100) (1/2) ||| Full ||| etc..--- > main = xmonad defaultConfig { layoutHook = myLayout }+-- > main = xmonad def { layoutHook = myLayout } -- -- For more detailed instructions on editing the layoutHook see: --
XMonad/Layout/WindowArranger.hs view
@@ -38,12 +38,12 @@ -- @~\/.xmonad\/xmonad.hs@: -- -- > import XMonad.Layout.WindowArranger--- > myLayout = layoutHook defaultConfig--- > main = xmonad defaultConfig { layoutHook = windowArrange myLayout }+-- > myLayout = layoutHook def+-- > main = xmonad def { layoutHook = windowArrange myLayout } -- -- or ----- > main = xmonad defaultConfig { layoutHook = windowArrangeAll myLayout }+-- > main = xmonad def { layoutHook = windowArrangeAll myLayout } -- -- For more detailed instructions on editing the layoutHook see: --
@@ -21,7 +21,7 @@ Navigate(..), Direction2D(..), MoveWindowToWindow(..), navigateColor, navigateBrightness,- noNavigateBorders, defaultWNConfig,+ noNavigateBorders, defaultWNConfig, def, WNConfig, WindowNavigation, ) where @@ -42,7 +42,7 @@ -- to some layout: -- -- > myLayout = windowNavigation (Tall 1 (3/100) (1/2)) ||| Full ||| etc..--- > main = xmonad defaultConfig { layoutHook = myLayout }+-- > main = xmonad def { layoutHook = myLayout } -- -- For more detailed instructions on editing the layoutHook see: --@@ -82,24 +82,27 @@ noNavigateBorders :: WNConfig noNavigateBorders =- defaultWNConfig {brightness = Just 0}+ def {brightness = Just 0} navigateColor :: String -> WNConfig navigateColor c = WNC Nothing c c c c navigateBrightness :: Double -> WNConfig-navigateBrightness f = defaultWNConfig { brightness = Just $ max 0 $ min 1 f }+navigateBrightness f = def { brightness = Just $ max 0 $ min 1 f } +instance Default WNConfig where def = WNC (Just 0.4) "#0000FF" "#00FFFF" "#FF0000" "#FF00FF"++{-# DEPRECATED defaultWNConfig "Use def (from Data.Default, and re-exported by XMonad.Layout.WindowNavigation) instead." #-} defaultWNConfig :: WNConfig-defaultWNConfig = WNC (Just 0.4) "#0000FF" "#00FFFF" "#FF0000" "#FF00FF"+defaultWNConfig = def data NavigationState a = NS Point [(a,Rectangle)] data WindowNavigation a = WindowNavigation WNConfig (Invisible Maybe (NavigationState a)) deriving ( Read, Show ) windowNavigation :: LayoutClass l a => l a -> ModifiedLayout WindowNavigation l a-windowNavigation = ModifiedLayout (WindowNavigation defaultWNConfig (I Nothing))+windowNavigation = ModifiedLayout (WindowNavigation def (I Nothing)) configurableNavigation :: LayoutClass l a => WNConfig -> l a -> ModifiedLayout WindowNavigation l a configurableNavigation conf = ModifiedLayout (WindowNavigation conf (I Nothing))
XMonad/Layout/WindowSwitcherDecoration.hs view
@@ -43,8 +43,8 @@ -- Then edit your @layoutHook@ by adding the WindowSwitcherDecoration to -- your layout: ----- > myL = windowSwitcherDecoration shrinkText defaultTheme (draggingVisualizer $ layoutHook defaultConfig)--- > main = xmonad defaultConfig { layoutHook = myL }+-- > myL = windowSwitcherDecoration shrinkText def (draggingVisualizer $ layoutHook def)+-- > main = xmonad def { layoutHook = myL } -- -- There is also a version of the decoration that contains buttons like -- "XMonad.Layout.ButtonDecoration". To use that version, you will need to@@ -53,8 +53,8 @@ -- -- > import XMonad.Layout.DecorationAddons -- >--- > myL = windowSwitcherDecorationWithButtons shrinkText defaultThemeWithButtons (draggingVisualizer $ layoutHook defaultConfig)--- > main = xmonad defaultConfig { layoutHook = myL }+-- > myL = windowSwitcherDecorationWithButtons shrinkText defaultThemeWithButtons (draggingVisualizer $ layoutHook def)+-- > main = xmonad def { layoutHook = myL } -- -- Additionaly, there is a version of the decoration that contains image buttons like -- "XMonad.Layout.ImageButtonDecoration". To use that version, you will need to@@ -63,8 +63,8 @@ -- -- > import XMonad.Layout.ImageButtonDecoration -- >--- > myL = windowSwitcherDecorationWithImageButtons shrinkText defaultThemeWithImageButtons (draggingVisualizer $ layoutHook defaultConfig)--- > main = xmonad defaultConfig { layoutHook = myL }+-- > myL = windowSwitcherDecorationWithImageButtons shrinkText defaultThemeWithImageButtons (draggingVisualizer $ layoutHook def)+-- > main = xmonad def { layoutHook = myL } -- windowSwitcherDecoration :: (Eq a, Shrinker s) => s -> Theme
XMonad/Layout/WorkspaceDir.hs view
@@ -47,7 +47,7 @@ -- to some layout: -- -- > myLayout = workspaceDir "~" (Tall 1 (3/100) (1/2)) ||| Full ||| etc..--- > main = xmonad defaultConfig { layoutHook = myLayout }+-- > main = xmonad def { layoutHook = myLayout } -- -- For more detailed instructions on editing the layoutHook see: --@@ -56,7 +56,7 @@ -- WorkspaceDir provides also a prompt. To use it you need to import -- "XMonad.Prompt" and add something like this to your key bindings: ----- > , ((modm .|. shiftMask, xK_x ), changeDir defaultXPConfig)+-- > , ((modm .|. shiftMask, xK_x ), changeDir def) -- -- For detailed instruction on editing the key binding see: --
XMonad/Prompt.hs view
@@ -1,8 +1,9 @@-{-# LANGUAGE ExistentialQuantification, FlexibleContexts #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ExistentialQuantification #-} ----------------------------------------------------------------------------- -- | -- Module : XMonad.Prompt--- Copyright : (C) 2007 Andrea Rossato+-- Copyright : (C) 2007 Andrea Rossato, 2015 Evgeny Kurnevsky -- License : BSD3 -- -- Maintainer : Spencer Janssen <spencerjanssen@gmail.com>@@ -19,6 +20,7 @@ mkXPrompt , mkXPromptWithReturn , mkXPromptWithModes+ , def , amberXPConfig , defaultXPConfig , greenXPConfig@@ -134,6 +136,8 @@ , position :: XPPosition -- ^ Position: 'Top' or 'Bottom' , alwaysHighlight :: !Bool -- ^ Always highlight an item, overriden to True with multiple modes. This implies having *one* column of autocompletions only. , height :: !Dimension -- ^ Window height+ , maxComplRows :: Maybe Dimension+ -- ^ Just x: maximum number of rows to show in completion window , historySize :: !Int -- ^ The number of history entries to be saved , historyFilter :: [String] -> [String] -- ^ a filter to determine which@@ -193,7 +197,6 @@ -- | This method is used to generate the string to be passed to -- the completion function.- -- This function is not used when in multiple modes (because alwaysHighlight in XPConfig is True) commandToComplete :: t -> String -> String commandToComplete _ = getLastWord @@ -229,7 +232,8 @@ amberXPConfig, defaultXPConfig, greenXPConfig :: XPConfig -defaultXPConfig =+instance Default XPConfig where+ def = XPC { font = "-misc-fixed-*-*-*-*-12-*-*-*-*-*-*-*" , bgColor = "grey22" , fgColor = "grey80"@@ -242,6 +246,7 @@ , changeModeKey = xK_grave , position = Bottom , height = 18+ , maxComplRows = Nothing , historySize = 256 , historyFilter = id , defaultText = []@@ -250,8 +255,10 @@ , searchPredicate = isPrefixOf , alwaysHighlight = False }-greenXPConfig = defaultXPConfig { fgColor = "green", bgColor = "black", promptBorderWidth = 0 }-amberXPConfig = defaultXPConfig { fgColor = "#ca8f2d", bgColor = "black", fgHLight = "#eaaf4c" }+{-# DEPRECATED defaultXPConfig "Use def (from Data.Default, and re-exported from XMonad.Prompt) instead." #-}+defaultXPConfig = def+greenXPConfig = def { fgColor = "green", bgColor = "black", promptBorderWidth = 0 }+amberXPConfig = def { fgColor = "#ca8f2d", bgColor = "black", fgHLight = "#eaaf4c" } initState :: Display -> Window -> Window -> Rectangle -> XPOperationMode -> GC -> XMonadFont -> [String] -> XPConfig -> KeyMask -> XPState@@ -367,7 +374,7 @@ --When it is false, it is handled depending on the prompt buffer's value let selectedCompletion = case alwaysHighlight (config st') of False -> command st'- True -> fromMaybe "" $ highlightedCompl st'+ True -> fromMaybe (command st') $ highlightedCompl st' Just <$> action selectedCompletion else return Nothing @@ -375,8 +382,7 @@ -- -- * a prompt type, instance of the 'XPrompt' class. ----- * a prompt configuration ('defaultXPConfig' can be used as a--- starting point)+-- * a prompt configuration ('def' can be used as a starting point) -- -- * a completion function ('mkComplFunFromList' can be used to -- create a completions function given a list of possible completions)@@ -795,9 +801,13 @@ modify $ \s -> s { offset = newoff } moveHistory :: (W.Stack String -> W.Stack String) -> XP ()-moveHistory f = modify $ \s -> let ch = f $ commandHistory s- in s { commandHistory = ch- , offset = length $ W.focus ch }+moveHistory f = do+ modify $ \s -> let ch = f $ commandHistory s+ in s { commandHistory = ch+ , offset = length $ W.focus ch+ , complIndex = (0,0) }+ updateWindows+ updateHighlightedCompl updateHighlightedCompl :: XP () updateHighlightedCompl = do@@ -934,7 +944,10 @@ rem_height = rect_height scr - ht (rows,r) = length compl `divMod` fi columns needed_rows = max 1 (rows + if r == 0 then 0 else 1)- actual_max_number_of_rows = rem_height `div` ht+ limit_max_number = case maxComplRows c of+ Nothing -> id+ Just m -> min m+ actual_max_number_of_rows = limit_max_number $ rem_height `div` ht actual_rows = min actual_max_number_of_rows (fi needed_rows) actual_height = actual_rows * ht (x,y) = case position c of@@ -1187,10 +1200,10 @@ -- > .. -- > ((modMask,xK_p), shellPrompt . myPrompt =<< initMatches) -- > ..--- > myPrompt ref = defaultPrompt+-- > myPrompt ref = def -- > { promptKeymap = M.union [((0,xK_Up), historyUpMatching ref) -- > ,((0,xK_Down), historyDownMatching ref)]--- > (promptKeymap defaultPrompt)+-- > (promptKeymap def) -- > , .. } -- historyUpMatching, historyDownMatching :: HistoryMatches -> XP ()
XMonad/Prompt/AppLauncher.hs view
@@ -25,7 +25,7 @@ import XMonad (X(),MonadIO) import XMonad.Core (spawn)-import XMonad.Prompt (XPrompt(showXPrompt), mkXPrompt, XPConfig())+import XMonad.Prompt (XPrompt(showXPrompt), mkXPrompt, XPConfig(searchPredicate)) import XMonad.Prompt.Shell (getShellCompl) {- $usage@@ -50,8 +50,8 @@ Then you can add the bindings to the applications. > ...-> , ((modm, xK_g), AL.launchApp defaultXPConfig "gimp" )-> , ((modm, xK_g), AL.launchApp defaultXPConfig "evince" )+> , ((modm, xK_g), AL.launchApp def "gimp" )+> , ((modm, xK_g), AL.launchApp def "evince" ) > ... -}@@ -72,4 +72,4 @@ {- | Get the user's response to a prompt an launch an application using the input as command parameters of the application.-} launchApp :: XPConfig -> Application -> X ()-launchApp config app = mkXPrompt (AppPrompt app) config (getShellCompl []) $ launch app+launchApp config app = mkXPrompt (AppPrompt app) config (getShellCompl [] $ searchPredicate config) $ launch app
XMonad/Prompt/AppendFile.hs view
@@ -42,7 +42,7 @@ -- -- and adding an appropriate keybinding, for example: ----- > , ((modm .|. controlMask, xK_n), appendFilePrompt defaultXPConfig "/home/me/NOTES")+-- > , ((modm .|. controlMask, xK_n), appendFilePrompt def "/home/me/NOTES") -- -- Additional notes can be added via regular Haskell or XMonad functions; for -- example, to preface notes with the time they were made, one could write a@@ -50,7 +50,7 @@ -- -- > , ((modm .|. controlMask, xK_n), do -- > spawn ("date>>"++"/home/me/NOTES")--- > appendFilePrompt defaultXPConfig "/home/me/NOTES"+-- > appendFilePrompt def "/home/me/NOTES" -- > ) -- -- (Put the spawn on the line after the prompt to append the time instead.)
+ XMonad/Prompt/ConfirmPrompt.hs view
@@ -0,0 +1,51 @@+-----------------------------------------------------------------------------+-- |+-- Module : XMonad.Prompt.ConfirmPrompt+-- Copyright : (C) 2015 Antoine Beaupré+-- License : BSD3+--+-- Maintainer : Antoine Beaupré <anarcat@debian.org>+-- Stability : unstable+-- Portability : unportable+--+-- A module for setting up simple confirmation prompts for keybindings.+--+-----------------------------------------------------------------------------+module XMonad.Prompt.ConfirmPrompt (confirmPrompt+ -- * Usage+ -- $usage+ , module XMonad.Prompt+ -- * Use case: confirming exit+ -- $tip+ , EnterPrompt+ ) where++import XMonad (X)+import XMonad.Prompt (XPConfig, XPrompt, showXPrompt, mkXPrompt, mkComplFunFromList)++{- $usage++This module makes it easy to add a confirmation prompt for specific+actions. Instead of just running the action, a simple confirmation+prompt will be created using 'XMonad.Prompt' primitives. The action+will then run normally if the user confirms.+-}++{- $tip+This should be used something like this:++> ...+> , ((modm , xK_l), confirmPrompt defaultXPConfig "exit" $ io (exitWith ExitSuccess))+> ...+-}++{- | Customized 'XPrompt' prompt that will ask to confirm the given string -}+data EnterPrompt = EnterPrompt String+instance XPrompt EnterPrompt where+ showXPrompt (EnterPrompt n) = "Confirm " ++ n ++ " (esc/ENTER)"++{- | Prompt the user to confirm a given action. We offer no completion+ and simply ask to confirm (ENTER) or cancel (ESCAPE). The actual key+ handling is done by mkXPrompt.-}+confirmPrompt :: XPConfig -> String -> X() -> X()+confirmPrompt config app func = mkXPrompt (EnterPrompt app) config (mkComplFunFromList []) $ const func
XMonad/Prompt/DirExec.hs view
@@ -41,17 +41,17 @@ -- -- 2. In your keybindings add something like: ----- > , ("M-C-x", dirExecPrompt defaultXPConfig spawn "/home/joe/.scipts")+-- > , ("M-C-x", dirExecPrompt def spawn "/home/joe/.scipts") -- -- or ----- > , ("M-C-x", dirExecPromptNamed defaultXPConfig spawn+-- > , ("M-C-x", dirExecPromptNamed def spawn -- > "/home/joe/.scripts" "My Scripts: ") -- -- or add this after your default bindings: -- -- > ++--- > [ ("M-x " ++ key, dirExecPrompt defaultXPConfig fn "/home/joe/.scripts")+-- > [ ("M-x " ++ key, dirExecPrompt def fn "/home/joe/.scripts") -- > | (key, fn) <- [ ("x", spawn), ("M-x", runInTerm "-hold") ] -- > ] -- > ++
XMonad/Prompt/Directory.hs view
@@ -36,7 +36,7 @@ getDirCompl :: String -> IO [String] getDirCompl s = (filter notboring . lines) `fmap`- runProcessWithInput "/bin/bash" [] ("compgen -A directory " ++ s ++ "\n")+ runProcessWithInput "bash" [] ("compgen -A directory " ++ s ++ "\n") notboring :: String -> Bool notboring ('.':'.':_) = True
XMonad/Prompt/Email.hs view
@@ -36,7 +36,7 @@ -- -- and adding an appropriate keybinding, for example: ----- > , ((modm .|. controlMask, xK_e), emailPrompt defaultXPConfig addresses)+-- > , ((modm .|. controlMask, xK_e), emailPrompt def addresses) -- -- where @addresses@ is a list of email addresses that should -- autocomplete, for example:
XMonad/Prompt/Input.hs view
@@ -49,12 +49,12 @@ -- @fireEmployee@ action, like so: -- -- > firingPrompt :: X ()--- > firingPrompt = inputPrompt defaultXPConfig \"Fire\" ?+ fireEmployee+-- > firingPrompt = inputPrompt defaultXPConfig "Fire" ?+ fireEmployee -- -- If @employees@ contains a list of all his employees, he could also -- create an autocompleting version, like this: ----- > firingPrompt' = inputPromptWithCompl defaultXPConfig \"Fire\"+-- > firingPrompt' = inputPromptWithCompl defaultXPConfig "Fire" -- > (mkComplFunFromList employees) ?+ fireEmployee -- -- Now all he has to do is add a keybinding to @firingPrompt@ (or
XMonad/Prompt/Layout.hs view
@@ -31,7 +31,7 @@ -- > import XMonad.Prompt -- > import XMonad.Prompt.Layout ----- > , ((modm .|. shiftMask, xK_m ), layoutPrompt defaultXPConfig)+-- > , ((modm .|. shiftMask, xK_m ), layoutPrompt def) -- -- For detailed instruction on editing the key binding see -- "XMonad.Doc.Extending#Editing_key_bindings".
XMonad/Prompt/Man.hs view
@@ -46,7 +46,7 @@ -- -- 2. In your keybindings add something like: ----- > , ((modm, xK_F1), manPrompt defaultXPConfig)+-- > , ((modm, xK_F1), manPrompt def) -- -- For detailed instruction on editing the key binding see -- "XMonad.Doc.Extending#Editing_key_bindings".@@ -64,11 +64,15 @@ getMans :: IO [String] getMans = do- paths <- getCommandOutput "manpath -g 2>/dev/null" `E.catch`- \(E.SomeException _) -> return []+ paths <- do+ let getout cmd = getCommandOutput cmd `E.catch` \E.SomeException{} -> return ""+ -- one of these combinations should give some output+ p1 <- getout "manpath -g 2>/dev/null"+ p2 <- getout "manpath 2>/dev/null"+ return $ intercalate ":" $ lines $ p1 ++ p2 let sects = ["man" ++ show n | n <- [1..9 :: Int]] dirs = [d ++ "/" ++ s | d <- split ':' paths, s <- sects]- mans <- forM dirs $ \d -> do+ mans <- forM (nub dirs) $ \d -> do exists <- doesDirectoryExist d if exists then map (stripExt . stripSuffixes [".gz", ".bz2"]) `fmap`
+ XMonad/Prompt/Pass.hs view
@@ -0,0 +1,152 @@+-----------------------------------------------------------------------------+-- |+-- Module : XMonad.Prompt.Pass+-- Copyright : (c) 2014 Igor Babuschkin, Antoine R. Dumont+-- License : BSD3-style (see LICENSE)+--+-- Maintainer : Antoine R. Dumont <eniotna.t@gmail.com>+-- Stability : unstable+-- Portability : unportable+--+-- This module provides 3 <XMonad.Prompt> to ease passwords manipulation (generate, read, remove):+--+-- - one to lookup passwords in the password-storage.+--+-- - one to generate a password for a given password label that the user inputs.+--+-- - one to delete a stored password for a given password label that the user inputs.+--+-- All those prompts benefit from the completion system provided by the module <XMonad.Prompt>.+--+-- The password store is setuped through an environment variable PASSWORD_STORE_DIR.+-- If this is set, use the content of the variable.+-- Otherwise, the password store is located on user's home @$HOME\/.password-store@.+--+--+-- Source:+--+-- - The password storage implementation is <http://git.zx2c4.com/password-store the password-store cli>.+--+-- - Inspired from <http://babushk.in/posts/combining-xmonad-and-pass.html>+--+-----------------------------------------------------------------------------++module XMonad.Prompt.Pass (+ -- * Usages+ -- $usages+ passPrompt+ , passGeneratePrompt+ , passRemovePrompt+ ) where++import Control.Monad (liftM)+import XMonad.Core+import XMonad.Prompt ( XPrompt+ , showXPrompt+ , commandToComplete+ , nextCompletion+ , getNextCompletion+ , XPConfig+ , mkXPrompt+ , mkComplFunFromList)+import System.Directory (getHomeDirectory)+import System.FilePath (takeExtension, dropExtension, combine)+import System.Posix.Env (getEnv)+import XMonad.Util.Run (runProcessWithInput)++-- $usages+-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+--+-- > import XMonad.Prompt.Pass+--+-- Then add a keybinding for 'passPrompt', 'passGeneratePrompt' or 'passRemovePrompt':+--+-- > , ((modMask x , xK_p) , passPrompt xpconfig)+-- > , ((modMask x .|. controlMask, xK_p) , passGeneratePrompt xpconfig)+-- > , ((modMask x .|. controlMask .|. shiftMask, xK_p), passRemovePrompt xpconfig)+--+-- For detailed instructions on:+--+-- - editing your key bindings, see "XMonad.Doc.Extending#Editing_key_bindings".+--+-- - how to setup the password storage, see <http://git.zx2c4.com/password-store/about/>+--++type PromptLabel = String++data Pass = Pass PromptLabel++instance XPrompt Pass where+ showXPrompt (Pass prompt) = prompt ++ ": "+ 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 = liftM 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 (mkComplFunFromList passwords) passwordFunction++-- | A prompt to retrieve a password from a given entry.+--+passPrompt :: XPConfig -> X ()+passPrompt = mkPassPrompt "Select password" selectPassword++-- | 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)+--+passGeneratePrompt :: XPConfig -> X ()+passGeneratePrompt = mkPassPrompt "Generate password" generatePassword++-- | A prompt to remove a password for a given entry.+-- (Beware that no confirmation is asked)+--+passRemovePrompt :: XPConfig -> X ()+passRemovePrompt = mkPassPrompt "Remove password" removePassword++-- | Select a password.+--+selectPassword :: String -> X ()+selectPassword passLabel = spawn $ "pass --clip " ++ passLabel++-- | 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 " ++ passLabel ++ " 30"++-- | Remove a password stored for a given entry.+--+removePassword :: String -> X ()+removePassword passLabel = spawn $ "pass rm --force " ++ passLabel++-- | Retrieve the list of passwords from the password storage 'passwordStoreDir+getPasswords :: FilePath -> IO [String]+getPasswords passwordStoreDir = do+ files <- runProcessWithInput "find" [+ passwordStoreDir,+ "-type", "f",+ "-name", "*.gpg",+ "-printf", "%P\n"] []+ return $ map removeGpgExtension $ lines files++removeGpgExtension :: String -> String+removeGpgExtension file | takeExtension file == ".gpg" = dropExtension file+ | otherwise = file
XMonad/Prompt/RunOrRaise.hs view
@@ -41,7 +41,7 @@ 2. In your keybindings add something like: -> , ((modm .|. controlMask, xK_x), runOrRaisePrompt defaultXPConfig)+> , ((modm .|. controlMask, xK_x), runOrRaisePrompt def) For detailed instruction on editing the key binding see "XMonad.Doc.Extending#Editing_key_bindings". -}@@ -52,7 +52,7 @@ runOrRaisePrompt :: XPConfig -> X () runOrRaisePrompt c = do cmds <- io getCommands- mkXPrompt RRP c (getShellCompl cmds) open+ mkXPrompt RRP c (getShellCompl cmds $ searchPredicate c) open open :: String -> X () open path = io (isNormalFile path) >>= \b -> if b
XMonad/Prompt/Shell.hs view
@@ -32,8 +32,9 @@ import Codec.Binary.UTF8.String (encodeString) import Control.Exception as E import Control.Monad (forM)-import Data.List (isPrefixOf)-import System.Directory (doesDirectoryExist, getDirectoryContents)+import Data.Char (toLower)+import Data.List (isPrefixOf, sortBy)+import System.Directory (getDirectoryContents) import System.Environment (getEnv) import System.Posix.Files (getFileStatus, isDirectory) @@ -52,12 +53,13 @@ 2. In your keybindings add something like: -> , ((modm .|. controlMask, xK_x), shellPrompt defaultXPConfig)+> , ((modm .|. controlMask, xK_x), shellPrompt def) For detailed instruction on editing the key binding see "XMonad.Doc.Extending#Editing_key_bindings". -} data Shell = Shell+type Predicate = String -> String -> Bool instance XPrompt Shell where showXPrompt Shell = "Run: "@@ -66,11 +68,11 @@ shellPrompt :: XPConfig -> X () shellPrompt c = do cmds <- io getCommands- mkXPrompt Shell c (getShellCompl cmds) spawn+ mkXPrompt Shell c (getShellCompl cmds $ searchPredicate c) spawn {- $spawns See safe and unsafeSpawn in "XMonad.Util.Run".- prompt is an alias for safePrompt;+ prompt is an alias for unsafePrompt; safePrompt and unsafePrompt work on the same principles, but will use XPrompt to interactively query the user for input; the appearance is set by passing an XPConfig as the second argument. The first argument@@ -87,14 +89,14 @@ prompt, unsafePrompt, safePrompt :: FilePath -> XPConfig -> X () prompt = unsafePrompt-safePrompt c config = mkXPrompt Shell config (getShellCompl [c]) run+safePrompt c config = mkXPrompt Shell config (getShellCompl [c] $ searchPredicate config) run where run = safeSpawn c . return-unsafePrompt c config = mkXPrompt Shell config (getShellCompl [c]) run+unsafePrompt c config = mkXPrompt Shell config (getShellCompl [c] $ searchPredicate config) run where run a = unsafeSpawn $ c ++ " " ++ a -getShellCompl :: [String] -> String -> IO [String]-getShellCompl cmds s | s == "" || last s == ' ' = return []- | otherwise = do+getShellCompl :: [String] -> Predicate -> String -> IO [String]+getShellCompl cmds p s | s == "" || last s == ' ' = return []+ | otherwise = do f <- fmap lines $ runProcessWithInput "bash" [] ("compgen -A file -- " ++ s ++ "\n") files <- case f of@@ -102,21 +104,23 @@ if isDirectory fs then return [x ++ "/"] else return [x] _ -> return f- return . uniqSort $ files ++ commandCompletionFunction cmds s+ return . sortBy typedFirst . uniqSort $ files ++ commandCompletionFunction cmds p s+ where+ typedFirst x y+ | x `startsWith` s && not (y `startsWith` s) = LT+ | y `startsWith` s && not (x `startsWith` s) = GT+ | otherwise = x `compare` y+ startsWith str ps = isPrefixOf (map toLower ps) (map toLower str) -commandCompletionFunction :: [String] -> String -> [String]-commandCompletionFunction cmds str | '/' `elem` str = []- | otherwise = filter (isPrefixOf str) cmds+commandCompletionFunction :: [String] -> Predicate -> String -> [String]+commandCompletionFunction cmds p str | '/' `elem` str = []+ | otherwise = filter (p str) cmds getCommands :: IO [String] getCommands = do p <- getEnv "PATH" `E.catch` econst [] let ds = filter (/= "") $ split ':' p- es <- forM ds $ \d -> do- exists <- doesDirectoryExist d- if exists- then getDirectoryContents d- else return []+ es <- forM ds $ \d -> getDirectoryContents d `E.catch` econst [] return . uniqSort . filter ((/= '.') . head) . concat $ es split :: Eq a => a -> [a] -> [[a]]
XMonad/Prompt/Ssh.hs view
@@ -29,6 +29,7 @@ import Control.Monad import Data.Maybe+import Data.List(elemIndex) econst :: Monad m => a -> IOException -> m a econst = const . return@@ -41,7 +42,7 @@ -- -- 2. In your keybindings add something like: ----- > , ((modm .|. controlMask, xK_s), sshPrompt defaultXPConfig)+-- > , ((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@@ -53,8 +54,11 @@ instance XPrompt Ssh where showXPrompt Ssh = "SSH to: "- commandToComplete _ c = c- nextCompletion _ = getNextCompletion+ commandToComplete _ c = maybe c (\(_u,h) -> h) (parseHost c)+ nextCompletion _t c l = maybe next (\(u,_h) -> u ++ "@" ++ next) hostPared+ where + hostPared = parseHost c+ next = getNextCompletion (maybe c (\(_u,h) -> h) hostPared) l sshPrompt :: XPConfig -> X () sshPrompt c = do@@ -135,3 +139,6 @@ ']':':':x -> x _ -> "22" getWithPort str = str++parseHost :: String -> Maybe (String, String)+parseHost a = elemIndex '@' a >>= (\c-> Just ( (take c a), (drop (c+1) a) ) )
XMonad/Prompt/Theme.hs view
@@ -35,7 +35,7 @@ -- -- in your keybindings add: ----- > , ((modm .|. controlMask, xK_t), themePrompt defaultXPConfig)+-- > , ((modm .|. controlMask, xK_t), themePrompt def) -- -- For detailed instruction on editing the key binding see -- "XMonad.Doc.Extending#Editing_key_bindings".@@ -49,7 +49,7 @@ themePrompt :: XPConfig -> X () themePrompt c = mkXPrompt ThemePrompt c (mkComplFunFromList' . map ppThemeInfo $ listOfThemes) changeTheme- where changeTheme t = sendMessage . SetTheme . fromMaybe defaultTheme $ M.lookup t mapOfThemes+ where changeTheme t = sendMessage . SetTheme . fromMaybe def $ M.lookup t mapOfThemes mapOfThemes :: M.Map String Theme mapOfThemes = M.fromList . uncurry zip . (map ppThemeInfo &&& map theme) $ listOfThemes
XMonad/Prompt/Window.hs view
@@ -44,13 +44,13 @@ -- -- and in the keys definition: ----- > , ((modm .|. shiftMask, xK_g ), windowPromptGoto defaultXPConfig)--- > , ((modm .|. shiftMask, xK_b ), windowPromptBring defaultXPConfig)+-- > , ((modm .|. shiftMask, xK_g ), windowPromptGoto def)+-- > , ((modm .|. shiftMask, xK_b ), windowPromptBring def) -- -- The autoComplete option is a handy complement here: -- -- > , ((modm .|. shiftMask, xK_g ), windowPromptGoto--- > defaultXPConfig { autoComplete = Just 500000 } )+-- > def { autoComplete = Just 500000 } ) -- -- The \'500000\' is the number of microseconds to pause before sending you to -- your new window. This is useful so that you don't accidentally send some
XMonad/Prompt/Workspace.hs view
@@ -32,7 +32,7 @@ -- > import XMonad.Prompt -- > import XMonad.Prompt.Workspace ----- > , ((modm .|. shiftMask, xK_m ), workspacePrompt defaultXPConfig (windows . W.shift))+-- > , ((modm .|. shiftMask, xK_m ), workspacePrompt def (windows . W.shift)) -- -- For detailed instruction on editing the key binding see -- "XMonad.Doc.Extending#Editing_key_bindings".
XMonad/Prompt/XMonad.hs view
@@ -33,7 +33,7 @@ -- -- in your keybindings add: ----- > , ((modm .|. controlMask, xK_x), xmonadPrompt defaultXPConfig)+-- > , ((modm .|. controlMask, xK_x), xmonadPrompt def) -- -- For detailed instruction on editing the key binding see -- "XMonad.Doc.Extending#Editing_key_bindings".
XMonad/Util/CustomKeys.hs view
@@ -31,7 +31,7 @@ -- -- 2. Set key bindings with 'customKeys': ----- > main = xmonad defaultConfig { keys = customKeys delkeys inskeys }+-- > main = xmonad def { keys = customKeys delkeys inskeys } -- > where -- > delkeys :: XConfig l -> [(KeyMask, KeySym)] -- > delkeys XConfig {modMask = modm} =@@ -53,17 +53,17 @@ -- > import System.Exit -- > import qualified Data.Map as M -- >--- > main = xmonad defaultConfig {+-- > main = xmonad def { -- > keys = \_ -> M.fromList [ -- > -- Let me out of here! I want my KDE back! Help! Help! -- > ( (0, xK_Escape), io (exitWith ExitSuccess) ) ] } --- | Customize 'XMonad.Config.defaultConfig' -- delete needless+-- | Customize 'XMonad.Config.def' -- delete needless -- shortcuts and insert those you will use. customKeys :: (XConfig Layout -> [(KeyMask, KeySym)]) -- ^ shortcuts to delete -> (XConfig Layout -> [((KeyMask, KeySym), X ())]) -- ^ key bindings to insert -> XConfig Layout -> M.Map (KeyMask, KeySym) (X ())-customKeys = customKeysFrom defaultConfig+customKeys = customKeysFrom def -- | General variant of 'customKeys': customize key bindings of -- third-party configuration.
XMonad/Util/DebugWindow.hs view
@@ -1,14 +1,14 @@ ----------------------------------------------------------------------------- -- | -- Module : XMonad.Util.DebugWindow--- Copyright : (c) Brandon S Allbery KF8NH, 2012+-- Copyright : (c) Brandon S Allbery KF8NH, 2014 -- License : BSD3-style (see LICENSE) -- -- Maintainer : allbery.b@gmail.com -- Stability : unstable -- Portability : not portable ----- Module to dump window information for diagnostic/debugging purposes. See +-- Module to dump window information for diagnostic/debugging purposes. See -- "XMonad.Hooks.DebugEvents" and "XMonad.Hooks.DebugStack" for practical uses. -- -----------------------------------------------------------------------------@@ -20,7 +20,7 @@ import XMonad import Codec.Binary.UTF8.String (decodeString)-import Control.Exception.Extensible as E+import Control.Exception.Extensible as E import Control.Monad (when) import Data.List (unfoldr ,intercalate@@ -34,7 +34,7 @@ -- and its title if available. Also indicate override_redirect with an -- exclamation mark, and wrap in brackets if it is unmapped or withdrawn. debugWindow :: Window -> X String-debugWindow 0 = return "None"+debugWindow 0 = return "-no window-" debugWindow w = do let wx = pad 8 '0' $ showHex w "" w' <- withDisplay $ \d -> io (safeGetWindowAttributes d w)@@ -59,23 +59,36 @@ catchX' (wrap `fmap` getEWMHTitle "" w) $ catchX' (wrap `fmap` getICCCMTitle w) $ return ""+ h' <- getMachine w+ let h = if null h' then "" else '@':h'+ -- if it has WM_COMMAND use it, else use the appName+ -- NB. modern stuff often does not set WM_COMMAND since it's only ICCCM required and not some+ -- horrible gnome/freedesktop session manager thing like Wayland intended. How helpful of them.+ p' <- withDisplay $ \d -> safeGetCommand d w+ let p = if null p' then "" else wrap $ intercalate " " p'+ nWP <- getAtom "_NET_WM_PID"+ pid' <- withDisplay $ \d -> io $ getWindowProperty32 d nWP w+ let pid = case pid' of+ Just [pid''] -> '(':show pid'' ++ ")"+ _ -> ""+ let cmd = p ++ pid ++ h let (lb,rb) = case () of () | m == waIsViewable -> ("","") | otherwise -> ("[","]") o' = if o then "!" else "" return $ concat [lb ,o'- ,"window " ,wx ,t- ," ("+ ," " ,show wid- ,',':show ht- ,')':if bw == 0 then "" else '+':show bw- ,"@("+ ,'x':show ht+ ,if bw == 0 then "" else '+':show bw+ ,"@" ,show x ,',':show y- ,')':if null c then "" else ' ':c+ ,if null c then "" else ' ':c+ ,if null cmd then "" else ' ':cmd ,rb ] @@ -86,8 +99,11 @@ return $ map (toEnum . fromEnum) t getICCCMTitle :: Window -> X String-getICCCMTitle w = do- t@(TextProperty t' _ 8 _) <- withDisplay $ \d -> io $ getTextProperty d w wM_NAME+getICCCMTitle w = getDecodedStringProp w wM_NAME++getDecodedStringProp :: Window -> Atom -> X String+getDecodedStringProp w a = do+ t@(TextProperty t' _ 8 _) <- withDisplay $ \d -> io $ getTextProperty d w a [s] <- catchX' (tryUTF8 t) $ catchX' (tryCompound t) $ io ((:[]) `fmap` peekCString t')@@ -138,3 +154,21 @@ case s of 0 -> return Nothing _ -> Just `fmap` peek p++-- and so is getCommand+safeGetCommand :: Display -> Window -> X [String]+safeGetCommand d w = do+ wC <- getAtom "WM_COMMAND"+ p <- io $ getWindowProperty8 d wC w+ case p of+ Nothing -> return []+ Just cs' -> do+ let cs = map (toEnum . fromEnum) cs'+ go (a,(s,"\NUL")) = (s:a,("",""))+ go (a,(s,'\NUL':ss)) = go (s:a,go' ss)+ go r = r -- ???+ go' = break (== '\NUL')+ in return $ reverse $ fst $ go ([],go' cs)++getMachine :: Window -> X String+getMachine w = catchX' (getAtom "WM_CLIENT_MACHINE" >>= getDecodedStringProp w) (return "")
XMonad/Util/EZConfig.hs view
@@ -7,7 +7,7 @@ -- -- Maintainer : Devin Mullins <me@twifkak.com> ----- Useful helper functions for amending the defaultConfig, and for+-- Useful helper functions for amending the default configuration, and for -- parsing keybindings specified in a special (emacs-like) format. -- -- (See also "XMonad.Util.CustomKeys" in xmonad-contrib.)@@ -69,7 +69,7 @@ -- | -- Add or override keybindings from the existing set. Example use: ----- > main = xmonad $ defaultConfig { terminal = "urxvt" }+-- > main = xmonad $ def { terminal = "urxvt" } -- > `additionalKeys` -- > [ ((mod1Mask, xK_m ), spawn "echo 'Hi, mom!' | dzen2 -p 4") -- > , ((mod1Mask, xK_BackSpace), withFocused hide) -- N.B. this is an absurd thing to do@@ -88,7 +88,7 @@ -- descriptors like @\"M-m\"@ instead of @(modMask, xK_m)@, as -- described in the documentation for 'mkKeymap'. For example: ----- > main = xmonad $ defaultConfig { terminal = "urxvt" }+-- > main = xmonad $ def { terminal = "urxvt" } -- > `additionalKeysP` -- > [ ("M-m", spawn "echo 'Hi, mom!' | dzen2 -p 4") -- > , ("M-<Backspace>", withFocused hide) -- N.B. this is an absurd thing to do@@ -101,7 +101,7 @@ -- | -- Remove standard keybindings you're not using. Example use: ----- > main = xmonad $ defaultConfig { terminal = "urxvt" }+-- > main = xmonad $ def { terminal = "urxvt" } -- > `removeKeys` [(mod1Mask .|. shiftMask, n) | n <- [xK_1 .. xK_9]] removeKeys :: XConfig a -> [(ButtonMask, KeySym)] -> XConfig a removeKeys conf keyList =@@ -111,7 +111,7 @@ -- like @\"M-m\"@ instead of @(modMask, xK_m)@, as described in the -- documentation for 'mkKeymap'. For example: ----- > main = xmonad $ defaultConfig { terminal = "urxvt" }+-- > main = xmonad $ def { terminal = "urxvt" } -- > `removeKeysP` ["M-S-" ++ [n] | n <- ['1'..'9']] removeKeysP :: XConfig l -> [String] -> XConfig l@@ -346,6 +346,7 @@ -- > <XF86Pictures> -- > <XF86Music> -- > <XF86TouchpadToggle>+-- > <XF86AudioMicMute> -- > <XF86_Switch_VT_1>-<XF86_Switch_VT_12> -- > <XF86_Ungrab> -- > <XF86_ClearGrab>@@ -652,6 +653,7 @@ , "XF86Pictures" , "XF86Music" , "XF86TouchpadToggle"+ , "XF86AudioMicMute" , "XF86_Switch_VT_1" , "XF86_Switch_VT_2" , "XF86_Switch_VT_3"@@ -682,7 +684,7 @@ -- > main = xmonad $ myConfig -- > -- > myKeymap = [("S-M-c", kill), ...]--- > myConfig = defaultConfig {+-- > myConfig = def { -- > ... -- > keys = \c -> mkKeymap c myKeymap -- > startupHook = return () >> checkKeymap myConfig myKeymap
XMonad/Util/ExtensibleState.hs view
@@ -23,7 +23,7 @@ , gets ) where -import Data.Typeable (typeOf,Typeable,cast)+import Data.Typeable (typeOf,cast) import qualified Data.Map as M import XMonad.Core import qualified Control.Monad.State as State
XMonad/Util/Invisible.hs view
@@ -22,13 +22,15 @@ , fromIMaybe ) where +import Control.Applicative+ -- $usage -- A wrapper data type to store layout state that shouldn't be persisted across -- restarts. A common wrapped type to use is @Maybe a@. -- Invisible derives trivial definitions for Read and Show, so the wrapped data -- type need not do so. -newtype Invisible m a = I (m a) deriving (Monad, Functor, Applicative)+newtype Invisible m a = I (m a) deriving (Monad, Applicative, Functor) instance (Functor m, Monad m) => Read (Invisible m a) where readsPrec _ s = [(fail "Read Invisible", s)]
XMonad/Util/Loggers.hs view
@@ -77,7 +77,7 @@ -- For example: -- -- > -- display load averages and a pithy quote along with xmonad status.--- > , logHook = dynamicLogWithPP $ defaultPP {+-- > , logHook = dynamicLogWithPP $ def { -- > ppExtras = [ padL loadAvg, logCmd "fortune -n 40 -s" ] -- > } -- > -- gives something like " 3.27 3.52 3.26 Drive defensively. Buy a tank."@@ -193,7 +193,7 @@ -- use instead of \'.\' or \'$\' in hard to read formatting lines. -- For example: ----- > myLogHook = dynamicLogWithPP defaultPP {+-- > myLogHook = dynamicLogWithPP def { -- > -- skipped -- > , ppExtras = [lLoad, lTitle, logSp 3, wrapL "[" "]" $ date "%a %d %b"] -- > , ppOrder = \(ws,l,_,xs) -> [l,ws] ++ xs
XMonad/Util/NamedActions.hs view
@@ -12,6 +12,9 @@ -- -- A wrapper for keybinding configuration that can list the available -- keybindings.+--+-- Note that xmonad>=0.11 has by default a list of the default keybindings+-- bound to @M-S-/@ or @M-?@. -------------------------------------------------------------------- module XMonad.Util.NamedActions (@@ -21,6 +24,7 @@ spawn', submapName, addDescrKeys,+ addDescrKeys', xMessage, showKmSimple,@@ -63,7 +67,7 @@ -- > import XMonad.Util.EZConfig -- > -- > main = xmonad $ addDescrKeys ((mod4Mask, xK_F1), xMessage) myKeys--- > defaultConfig { modMask = mod4Mask }+-- > def { modMask = mod4Mask } -- > -- > myKeys c = (subtitle "Custom Keys":) $ mkNamedKeymap c $ -- > [("M-x a", addName "useless message" $ spawn "xmessage foo"),@@ -187,7 +191,7 @@ smartSpace xs = ' ':xs _test :: String-_test = unlines $ showKm $ defaultKeysDescr XMonad.defaultConfig { XMonad.layoutHook = XMonad.Layout $ XMonad.layoutHook XMonad.defaultConfig }+_test = unlines $ showKm $ defaultKeysDescr XMonad.def { XMonad.layoutHook = XMonad.Layout $ XMonad.layoutHook XMonad.def } showKm :: [((KeyMask, KeySym), NamedAction)] -> [String] showKm keybindings = padding $ do@@ -223,7 +227,7 @@ keylist l = M.map getAction $ M.fromList $ ks l ^++^ [(k, shk l)] in conf { keys = keylist } --- | A version of the default keys from 'XMonad.Config.defaultConfig', but with+-- | A version of the default keys from the default configuration, but with -- 'NamedAction' instead of @X ()@ defaultKeysDescr :: XConfig Layout -> [((KeyMask, KeySym), NamedAction)] defaultKeysDescr conf@(XConfig {XMonad.modMask = modm}) =
XMonad/Util/NamedScratchpad.hs view
@@ -166,7 +166,7 @@ -- -- A simple use could be: ----- > logHook = dynamicLogWithPP . namedScratchpadFilterOutWorkspace $ defaultPP+-- > logHook = dynamicLogWithPP . namedScratchpadFilterOutWorkspace $ def -- -- Here is another example, when using "XMonad.Layout.IndependentScreens". -- If you have handles @hLeft@ and @hRight@ for bars on the left and right screens, respectively, and @pp@ is a pretty-printer function that takes a handle, you could write
+ XMonad/Util/RemoteWindows.hs view
@@ -0,0 +1,90 @@+-----------------------------------------------------------------------------+-- |+-- Module : XMonad.Util.RemoteWindows+-- Copyright : (c) Anton Vorontsov <anton@enomsg.org> 2014+-- License : BSD-style (as xmonad)+--+-- Maintainer : Anton Vorontsov <anton@enomsg.org>+-- Stability : unstable+-- Portability : unportable+--+-- This module implements a proper way of finding out whether the window+-- is remote or local.+--+-- Just checking for a hostname and WM_CLIENT_MACHINE being equal is often+-- not enough because the hostname is a changing subject (without any+-- established notification mechanisms), and thus WM_CLIENT_MACHINE and+-- the hostname can diverge even for a local window.+--+-- This module solves the problem. As soon as there is a new window+-- created, we check the hostname and WM_CLIENT_MACHINE, and then we cache+-- the result into the XMONAD_REMOTE property.+--+-- Notice that XMonad itself does not know anything about hostnames, nor+-- does it have any dependency on Network.* modules. For this module it is+-- not a problem: you can provide a mean to get the hostname through your+-- config file (see usage). Or, if you don't like the hassle of handling+-- dynamic hostnames (suppose your hostname never changes), it is also+-- fine: this module will fallback to using environment variables.+--+-----------------------------------------------------------------------------++module XMonad.Util.RemoteWindows+ ( -- $usage+ isLocalWindow+ , manageRemote+ , manageRemoteG+ ) where++import XMonad+import XMonad.Util.WindowProperties+import Data.Monoid+import Data.Maybe+import Control.Monad+import System.Posix.Env++-- $usage+-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:+--+-- > import XMonad+-- > import XMonad.Util.RemoteWindows+-- > import Network.BSD+-- >+-- > main = xmonad def+-- > { manageHook = manageRemote =<< io getHostName }++guessHostName :: IO String+guessHostName = pickOneMaybe `liftM` (getEnv `mapM` vars)+ where+ pickOneMaybe = last . (mzero:) . take 1 . catMaybes+ vars = ["XAUTHLOCALHOSTNAME","HOST","HOSTNAME"]++setRemoteProp :: Window -> String -> X ()+setRemoteProp w host = do+ d <- asks display+ p <- getAtom "XMONAD_REMOTE"+ t <- getAtom "CARDINAL"+ v <- hasProperty (Machine host) w+ io $ changeProperty32 d w p t propModeReplace+ [fromIntegral . fromEnum $ not v]++-- | Given a window, tell if it is a local or a remote process. Normally,+-- it checks XMONAD_REMOTE property. If it does not exist (i.e. the+-- manageRemote hook was not deployed in user's config), it falls back to+-- checking environment variables and assuming that hostname never+-- changes.+isLocalWindow :: Window -> X Bool+isLocalWindow w = getProp32s "XMONAD_REMOTE" w >>= \p -> case p of+ Just [y] -> return $ y == 0+ _ -> io guessHostName >>= \host -> hasProperty (Machine host) w++-- | Use this hook to let XMonad properly track remote/local windows. For+-- example, @manageHook = manageRemote =<< io getHostName@.+manageRemote :: String -> ManageHook+manageRemote host = ask >>= \w -> liftX (setRemoteProp w host) >> return mempty++-- | Use this hook if you want to manage XMONAD_REMOTE properties, but+-- don't want to use an external getHostName in your config. That way you+-- are retreating to environment variables.+manageRemoteG :: ManageHook+manageRemoteG = manageRemote =<< io guessHostName
XMonad/Util/Replace.hs view
@@ -40,7 +40,7 @@ -- > import XMonad.Util.Replace -- > main = do -- > replace--- > xmonad $ defaultConfig { .... }+-- > xmonad $ def { .... } -- -- $shortcomings@@ -61,7 +61,7 @@ -- > main = do -- > args <- getArgs -- > when ("--replace" `elem` args) replace--- > xmonad $ defaultConfig { .... }+-- > xmonad $ def { .... } -- -- -- Note that your @~\/.xmonad/xmonad-$arch-$os@ binary is not run with the same
XMonad/Util/Run.hs view
@@ -134,7 +134,7 @@ unsafeSpawn :: MonadIO m => String -> m () unsafeSpawn = spawn --- | Open a terminal emulator. The terminal emulator is specified in @defaultConfig@ as xterm by default. It is then+-- | Open a terminal emulator. The terminal emulator is specified in the default configuration as xterm by default. It is then -- asked to pass the shell a command with certain options. This is unsafe in the sense of 'unsafeSpawn' unsafeRunInTerm, runInTerm :: String -> String -> X () unsafeRunInTerm options command = asks (terminal . config) >>= \t -> unsafeSpawn $ t ++ " " ++ options ++ " -e " ++ command
+ XMonad/Util/SpawnNamedPipe.hs view
@@ -0,0 +1,76 @@+{-# LANGUAGE DeriveDataTypeable #-}++-----------------------------------------------------------------------------+-- |+-- Module : XMonad.Util.SpawnNamedPipe+-- Copyright : (c) Christian Wills 2014 +-- License : BSD3-style (see LICENSE)+--+-- Maintainer : cwills.dev@gmail.com+-- Stability : unstable+-- Portability : not portable+--+-- A module for spawning a pipe whose "Handle" lives in the Xmonad state.+--+-----------------------------------------------------------------------------++module XMonad.Util.SpawnNamedPipe (+ -- * Usage+ -- $usage+ spawnNamedPipe+ , getNamedPipe+ ) where++import XMonad+import XMonad.Util.Run+import System.IO+import qualified XMonad.Util.ExtensibleState as XS+import Control.Monad+import qualified Data.Map as Map++-- $usage+-- This module makes it possible to spawn a pipe to Dzen2 in the startupHook+-- and write to it from inside the logHook without the need for global+-- variables.+--+-- > import XMonad.Util.SpawnNamedPipe+-- > import Data.Maybe+-- > +-- > -- StartupHook+-- > startupHook' = spawnNamedPipe "dzen2" "dzenPipe" +-- > +-- > -- LogHook+-- > logHook' = do+-- > mh <- getNamedPipeHandle "dzenPipe" +-- > dynamicLogWithPP $ defaultPP {+-- > ppOutput = maybe (\s -> return ()) (hPutStrLn) mh}+-- >+-- > -- Main+-- > main = xmonad $ defaultConfig {+-- > startupHook = startupHook'+-- > , logHook = logHook'}+--++data NamedPipes = NamedPipes { pipeMap :: Map.Map String Handle }+ deriving (Show, Typeable)++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". +spawnNamedPipe :: String -> String -> X ()+spawnNamedPipe cmd name = do+ b <- XS.gets (Map.member name . pipeMap) + unless b $ do+ h <- spawnPipe cmd + XS.modify (NamedPipes . Map.insert name h . pipeMap) ++-- | 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. +getNamedPipe :: String -> X (Maybe Handle)+getNamedPipe name = XS.gets (Map.lookup name . pipeMap)
XMonad/Util/Themes.hs view
@@ -45,8 +45,7 @@ -- do not apply to xmonad as a whole.) -- -- If you want to use one of them with one of your decorated layouts,--- you need to substitute defaultTheme with, for instance, (theme--- smallClean).+-- you need to substitute def with, for instance, (theme smallClean). -- -- Here is an example: --@@ -56,7 +55,7 @@ -- > -- > myLayout = tabbed shrinkText (theme smallClean) -- >--- > main = xmonad defaultConfig {layoutHook = myLayout}+-- > main = xmonad def {layoutHook = myLayout} -- -- If you have a theme you would like to share, adding it to this -- module is very easy.@@ -80,7 +79,7 @@ } newTheme :: ThemeInfo-newTheme = TI "" "" "" defaultTheme+newTheme = TI "" "" "" def ppThemeInfo :: ThemeInfo -> String ppThemeInfo t = themeName t <> themeDescription t <> "by" <> themeAuthor t@@ -112,7 +111,7 @@ newTheme { themeName = "xmonadTheme" , themeAuthor = "David Roundy" , themeDescription = "The default xmonad theme"- , theme = defaultTheme+ , theme = def } -- | Small decorations with a Ion3 remembrance, by Andrea Rossato.@@ -121,14 +120,14 @@ newTheme { themeName = "smallClean" , themeAuthor = "Andrea Rossato" , themeDescription = "Small decorations with a Ion3 remembrance"- , theme = defaultTheme { activeColor = "#8a999e"- , inactiveColor = "#545d75"- , activeBorderColor = "white"- , inactiveBorderColor = "grey"- , activeTextColor = "white"- , inactiveTextColor = "grey"- , decoHeight = 14- }+ , theme = def { activeColor = "#8a999e"+ , inactiveColor = "#545d75"+ , activeBorderColor = "white"+ , inactiveBorderColor = "grey"+ , activeTextColor = "white"+ , inactiveTextColor = "grey"+ , decoHeight = 14+ } } -- | Don's preferred colors - from DynamicLog...;)@@ -137,14 +136,14 @@ newTheme { themeName = "donaldTheme" , themeAuthor = "Andrea Rossato" , themeDescription = "Don's preferred colors - from DynamicLog...;)"- , theme = defaultTheme { activeColor = "#2b4f98"- , inactiveColor = "#cccccc"- , activeBorderColor = "#2b4f98"- , inactiveBorderColor = "#cccccc"- , activeTextColor = "white"- , inactiveTextColor = "black"- , decoHeight = 16- }+ , theme = def { activeColor = "#2b4f98"+ , inactiveColor = "#cccccc"+ , activeBorderColor = "#2b4f98"+ , inactiveBorderColor = "#cccccc"+ , activeTextColor = "white"+ , inactiveTextColor = "black"+ , decoHeight = 16+ } } -- | Ffrom Robert Manea's prompt theme.@@ -153,15 +152,15 @@ newTheme { themeName = "robertTheme" , themeAuthor = "Andrea Rossato" , themeDescription = "From Robert Manea's prompt theme"- , theme = defaultTheme { activeColor = "#aecf96"- , inactiveColor = "#111111"- , activeBorderColor = "#aecf96"- , inactiveBorderColor = "#111111"- , activeTextColor = "black"- , inactiveTextColor = "#d5d3a7"- , fontName = "-*-profont-*-*-*-*-11-*-*-*-*-*-iso8859"- , decoHeight = 16- }+ , theme = def { activeColor = "#aecf96"+ , inactiveColor = "#111111"+ , activeBorderColor = "#aecf96"+ , inactiveBorderColor = "#111111"+ , activeTextColor = "black"+ , inactiveTextColor = "#d5d3a7"+ , fontName = "-*-profont-*-*-*-*-11-*-*-*-*-*-iso8859"+ , decoHeight = 16+ } } -- | deifl\'s Theme, by deifl.@@ -170,15 +169,15 @@ newTheme { themeName = "deiflTheme" , themeAuthor = "deifl" , themeDescription = "deifl's Theme"- , theme = defaultTheme { inactiveBorderColor = "#708090"- , activeBorderColor = "#5f9ea0"- , activeColor = "#000000"- , inactiveColor = "#333333"- , inactiveTextColor = "#888888"- , activeTextColor = "#87cefa"- , fontName = "-xos4-terminus-*-*-*-*-12-*-*-*-*-*-*-*"- , decoHeight = 15- }+ , theme = def { inactiveBorderColor = "#708090"+ , activeBorderColor = "#5f9ea0"+ , activeColor = "#000000"+ , inactiveColor = "#333333"+ , inactiveTextColor = "#888888"+ , activeTextColor = "#87cefa"+ , fontName = "-xos4-terminus-*-*-*-*-12-*-*-*-*-*-*-*"+ , decoHeight = 15+ } } -- | oxymor00n\'s theme, by Tom Rauchenwald.@@ -187,19 +186,19 @@ newTheme { themeName = "oxymor00nTheme" , themeAuthor = "Tom Rauchenwald" , themeDescription = "oxymor00n's theme"- , theme = defaultTheme { inactiveBorderColor = "#000"- , activeBorderColor = "aquamarine3"- , activeColor = "aquamarine3"- , inactiveColor = "DarkSlateGray4"- , inactiveTextColor = "#222"- , activeTextColor = "#222"- -- This font can be found in the package ttf-alee- -- on debian-systems- , fontName = "-*-Bandal-*-*-*-*-12-*-*-*-*-*-*-*"- , decoHeight = 15- , urgentColor = "#000"- , urgentTextColor = "#63b8ff"- }+ , theme = def { inactiveBorderColor = "#000"+ , activeBorderColor = "aquamarine3"+ , activeColor = "aquamarine3"+ , inactiveColor = "DarkSlateGray4"+ , inactiveTextColor = "#222"+ , activeTextColor = "#222"+ -- This font can be found in the package ttf-alee+ -- on debian-systems+ , fontName = "-*-Bandal-*-*-*-*-12-*-*-*-*-*-*-*"+ , decoHeight = 15+ , urgentColor = "#000"+ , urgentTextColor = "#63b8ff"+ } } wfarrTheme :: ThemeInfo@@ -207,15 +206,15 @@ newTheme { themeName = "wfarrTheme" , themeAuthor = "Will Farrington" , themeDescription = "A nice blue/black theme."- , theme = defaultTheme { activeColor = "#4c7899"- , inactiveColor = "#333333"- , activeBorderColor = "#285577"- , inactiveBorderColor = "#222222"- , activeTextColor = "#ffffff"- , inactiveTextColor = "#888888"- , fontName = "-*-fixed-medium-r-*--10-*-*-*-*-*-iso8859-1"- , decoHeight = 12- }+ , theme = def { activeColor = "#4c7899"+ , inactiveColor = "#333333"+ , activeBorderColor = "#285577"+ , inactiveBorderColor = "#222222"+ , activeTextColor = "#ffffff"+ , inactiveTextColor = "#888888"+ , fontName = "-*-fixed-medium-r-*--10-*-*-*-*-*-iso8859-1"+ , decoHeight = 12+ } } -- | Forest colours, by Kathryn Andersen@@ -224,13 +223,13 @@ newTheme { themeName = "kavonForestTheme" , themeAuthor = "Kathryn Andersen" , themeDescription = "Forest colours"- , theme = defaultTheme { activeColor = "#115422"- , activeBorderColor = "#1a8033"- , activeTextColor = "white"- , inactiveColor = "#543211"- , inactiveBorderColor = "#804c19"- , inactiveTextColor = "#ffcc33"- }+ , theme = def { activeColor = "#115422"+ , activeBorderColor = "#1a8033"+ , activeTextColor = "white"+ , inactiveColor = "#543211"+ , inactiveBorderColor = "#804c19"+ , inactiveTextColor = "#ffcc33"+ } } -- | Lake (blue/green) colours, by Kathryn Andersen@@ -239,13 +238,13 @@ newTheme { themeName = "kavonLakeTheme" , themeAuthor = "Kathryn Andersen" , themeDescription = "Lake (blue/green) colours"- , theme = defaultTheme { activeColor = "#001166"- , activeBorderColor = "#1f3999"- , activeTextColor = "white"- , inactiveColor = "#09592a"- , inactiveBorderColor = "#198044"- , inactiveTextColor = "#73e6a3"- }+ , theme = def { activeColor = "#001166"+ , activeBorderColor = "#1f3999"+ , activeTextColor = "white"+ , inactiveColor = "#09592a"+ , inactiveBorderColor = "#198044"+ , inactiveTextColor = "#73e6a3"+ } } -- | Peacock colours, by Kathryn Andersen@@ -254,13 +253,13 @@ newTheme { themeName = "kavonPeacockTheme" , themeAuthor = "Kathryn Andersen" , themeDescription = "Peacock colours"- , theme = defaultTheme { activeColor = "#190f4c"- , activeBorderColor = "#2b1980"- , activeTextColor = "white"- , inactiveColor = "#225173"- , inactiveBorderColor = "#2a638c"- , inactiveTextColor = "#8fb2cc"- }+ , theme = def { activeColor = "#190f4c"+ , activeBorderColor = "#2b1980"+ , activeTextColor = "white"+ , inactiveColor = "#225173"+ , inactiveBorderColor = "#2a638c"+ , inactiveTextColor = "#8fb2cc"+ } } -- | Violet-Green colours, by Kathryn Andersen@@ -269,13 +268,13 @@ newTheme { themeName = "kavonVioGreenTheme" , themeAuthor = "Kathryn Andersen" , themeDescription = "Violet-Green colours"- , theme = defaultTheme { activeColor = "#37174c"- , activeBorderColor = "#333399"- , activeTextColor = "white"- , inactiveColor = "#174c17"- , inactiveBorderColor = "#336633"- , inactiveTextColor = "#aaccaa"- }+ , theme = def { activeColor = "#37174c"+ , activeBorderColor = "#333399"+ , activeTextColor = "white"+ , inactiveColor = "#174c17"+ , inactiveBorderColor = "#336633"+ , inactiveTextColor = "#aaccaa"+ } } -- | Blue colours, by Kathryn Andersen@@ -284,13 +283,13 @@ newTheme { themeName = "kavonBluesTheme" , themeAuthor = "Kathryn Andersen" , themeDescription = "Blue colours"- , theme = defaultTheme { activeColor = "#000066"- , activeBorderColor = "#111199"- , activeTextColor = "white"- , inactiveColor = "#9999ee"- , inactiveBorderColor = "#6666cc"- , inactiveTextColor = "black"- }+ , theme = def { activeColor = "#000066"+ , activeBorderColor = "#111199"+ , activeTextColor = "white"+ , inactiveColor = "#9999ee"+ , inactiveBorderColor = "#6666cc"+ , inactiveTextColor = "black"+ } } -- | Christmas colours, by Kathryn Andersen@@ -299,13 +298,13 @@ newTheme { themeName = "kavonChristmasTheme" , themeAuthor = "Kathryn Andersen" , themeDescription = "Christmas (green + red) colours"- , theme = defaultTheme { activeColor = "#660000"- , activeBorderColor = "#990000"- , activeTextColor = "white"- , inactiveColor = "#006600"- , inactiveBorderColor = "#003300"- , inactiveTextColor = "#99bb99"- }+ , theme = def { activeColor = "#660000"+ , activeBorderColor = "#990000"+ , activeTextColor = "white"+ , inactiveColor = "#006600"+ , inactiveBorderColor = "#003300"+ , inactiveTextColor = "#99bb99"+ } } -- | Autumn colours, by Kathryn Andersen@@ -314,13 +313,13 @@ newTheme { themeName = "kavonAutumnTheme" , themeAuthor = "Kathryn Andersen" , themeDescription = "Autumn (brown + red) colours"- , theme = defaultTheme { activeColor = "#660000"- , activeBorderColor = "#990000"- , activeTextColor = "white"- , inactiveColor = "#542d11"- , inactiveBorderColor = "#804d1A"- , inactiveTextColor = "#ffcc33"- }+ , theme = def { activeColor = "#660000"+ , activeBorderColor = "#990000"+ , activeTextColor = "white"+ , inactiveColor = "#542d11"+ , inactiveBorderColor = "#804d1A"+ , inactiveTextColor = "#ffcc33"+ } } -- | Fire colours, by Kathryn Andersen@@ -329,12 +328,12 @@ newTheme { themeName = "kavonFireTheme" , themeAuthor = "Kathryn Andersen" , themeDescription = "Fire (orange + red) colours"- , theme = defaultTheme { activeColor = "#660000"- , activeBorderColor = "#990000"- , activeTextColor = "white"- , inactiveColor = "#ff8000"- , inactiveBorderColor = "#d9b162"- , inactiveTextColor = "black"- }+ , theme = def { activeColor = "#660000"+ , activeBorderColor = "#990000"+ , activeTextColor = "white"+ , inactiveColor = "#ff8000"+ , inactiveBorderColor = "#d9b162"+ , inactiveTextColor = "black"+ } }
+ XMonad/Util/WindowState.hs view
@@ -0,0 +1,91 @@+{-#+ LANGUAGE ScopedTypeVariables, GeneralizedNewtypeDeriving,+ FlexibleInstances, MultiParamTypeClasses,+ FlexibleContexts -- ghc-6.12 only+ #-}+-----------------------------------------------------------------------------+-- |+-- Module : XMonad.Util.WindowState+-- Copyright : (c) Dmitry Bogatov <KAction@gnu.org>+-- License : BSD+--+-- Maintainer : Dmitry Bogatov <KAction@gnu.org>+-- Stability : unstable+-- Portability : unportable+--+-- Functions for saving per-window data.+-----------------------------------------------------------------------------++module XMonad.Util.WindowState ( -- * Usage+ -- $usage+ get,+ put,+ StateQuery(..),+ runStateQuery,+ catchQuery ) where+import XMonad hiding (get, put, modify)+import Control.Monad.Reader(ReaderT(..))+import Control.Monad.State.Class+import Data.Typeable (typeOf)+import Control.Applicative((<$>), Applicative)+-- $usage+--+-- This module allow to store state data with some 'Window'.+-- It is implemented with XProperties, so resources will be freed when+-- 'Window' is destoyed.+--+-- 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".+--+-- 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,+-- 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+-- window.+newtype StateQuery s a = StateQuery {+ getQuery :: Query a+ } deriving (Monad, MonadIO, Applicative, Functor)++packIntoQuery :: (Window -> X a) -> Query a+packIntoQuery = Query . ReaderT++-- | Apply "StateQuery" to "Window".+runStateQuery :: StateQuery s a -> Window -> X a+runStateQuery = runQuery . getQuery++-- | Lifted to "Query" version of 'catchX'+catchQuery :: Query a -> Query (Maybe a)+catchQuery q = packIntoQuery $ \win -> userCode $ runQuery q win++-- | Instance of MonadState for StateQuery.+instance (Show s, Read s, Typeable s) => MonadState (Maybe s) (StateQuery s) where+ get = StateQuery $ read' <$> get' undefined where+ get' :: (Maybe s) -> Query String+ get' x = stringProperty (typePropertyName x)+ read' :: (Read s) => String -> Maybe s+ read' "" = Nothing+ read' s = Just $ read s+ put = StateQuery . packIntoQuery <$> setWindowProperty' where+ setWindowProperty' val = setWindowProperty prop strValue where+ prop = typePropertyName val+ strValue = maybe "" show val++typePropertyName :: (Typeable a) => a -> String+typePropertyName x = "_XMONAD_WINSTATE__" ++ show (typeOf x)++type PropertyName = String+setWindowProperty :: PropertyName -> String -> Window -> X ()+setWindowProperty prop val win = withDisplay $ \d -> io $+ internAtom d prop False >>=+ setTextProperty d win val
XMonad/Util/WorkspaceCompare.hs view
@@ -40,12 +40,20 @@ spaces <- asks (workspaces . config) return $ flip elemIndex spaces +-- | Compare Maybe's differently, so Nothing (i.e. workspaces without indexes)+-- come last in the order+indexCompare :: Maybe Int -> Maybe Int -> Ordering+indexCompare Nothing Nothing = EQ+indexCompare Nothing (Just _) = GT+indexCompare (Just _) Nothing = LT+indexCompare a b = compare a b+ -- | A comparison function for WorkspaceId, based on the index of the -- tags in the user's config. getWsCompare :: X WorkspaceCompare getWsCompare = do wsIndex <- getWsIndex- return $ mconcat [compare `on` wsIndex, compare]+ return $ mconcat [indexCompare `on` wsIndex, compare] -- | A simple comparison function that orders workspaces -- lexicographically by tag.
XMonad/Util/XSelection.hs view
@@ -46,6 +46,10 @@ -- | Returns a String corresponding to the current mouse selection in X; -- if there is none, an empty string is returned.+--+-- WARNING: this function is fundamentally implemented incorrectly and may, among other possible failure modes,+-- deadlock or crash. For details, see <http://code.google.com/p/xmonad/issues/detail?id=573>.+-- (These errors are generally very rare in practice, but still exist.) getSelection :: MonadIO m => m String getSelection = io $ do dpy <- openDisplay ""@@ -63,10 +67,12 @@ allocaXEvent $ \e -> do nextEvent dpy e ev <- getEvent e- if ev_event_type ev == selectionNotify- then do res <- getWindowProperty8 dpy clp win- return $ decode . map fromIntegral . fromMaybe [] $ res- else destroyWindow dpy win >> return ""+ result <- if ev_event_type ev == selectionNotify+ then do res <- getWindowProperty8 dpy clp win+ return $ decode . map fromIntegral . fromMaybe [] $ res+ else destroyWindow dpy win >> return ""+ closeDisplay dpy+ return result {- | A wrapper around 'getSelection'. Makes it convenient to run a program with the current selection as an argument. This is convenient for handling URLs, in particular. For example, in your Config.hs you could bind a key to
xmonad-contrib.cabal view
@@ -1,5 +1,5 @@ name: xmonad-contrib-version: 0.11.4+version: 0.12 homepage: http://xmonad.org/ synopsis: Third party extensions for xmonad description:@@ -21,7 +21,7 @@ license-file: LICENSE author: Spencer Janssen & others maintainer: xmonad@haskell.org-extra-source-files: README scripts/generate-configs scripts/run-xmonad.sh+extra-source-files: README.md CHANGES.md scripts/generate-configs scripts/run-xmonad.sh scripts/window-properties.sh scripts/xinitrc scripts/xmonad-acpi.c scripts/xmonad-clock.c@@ -30,52 +30,52 @@ tests/Selective.hs tests/SwapWorkspaces.hs tests/XPrompt.hs+ XMonad/Config/dmwit.xmobarrc cabal-version: >= 1.6 build-type: Simple-bug-reports: http://code.google.com/p/xmonad/issues/list+bug-reports: https://github.com/xmonad/xmonad-contrib/issues -tested-with: GHC == 7.8.2, GHC==7.6.2, GHC==7.4.1, GHC==7.2.1, GHC==7.0.4+tested-with:+ GHC==7.6.3,+ GHC==7.8.4,+ GHC==7.10.2 source-repository head- type: darcs- location: http://code.haskell.org/XMonadContrib+ type: git+ location: https://github.com/xmonad/xmonad-contrib -flag small_base- description: Choose the new smaller, split-up base package.- flag use_xft description: Use Xft to render text flag testing description: Testing mode+ manual: True default: False library- if flag(small_base)- build-depends: base >= 3 && < 5,- containers,- directory,- extensible-exceptions,- old-locale,- old-time,- process,- random- else- build-depends: base < 3+ build-depends: base >= 3 && < 5,+ containers,+ directory,+ extensible-exceptions,+ filepath,+ old-locale,+ old-time,+ process,+ random,+ mtl >= 1 && < 3,+ unix,+ X11>=1.6.1 && < 1.7,+ xmonad>=0.12 && < 0.13,+ utf8-string if flag(use_xft)- build-depends: X11-xft >= 0.2, utf8-string- extensions: ForeignFunctionInterface+ build-depends: X11-xft >= 0.2 cpp-options: -DXFT - build-depends: mtl >= 1 && < 3, unix, X11 >= 1.6.1 && < 1.7, xmonad >= 0.11 && < 0.12, utf8-string- if true ghc-options: -fwarn-tabs -Wall - extensions: ForeignFunctionInterface- if flag(testing) ghc-options: -fwarn-tabs -Werror @@ -89,6 +89,7 @@ XMonad.Doc.Configuring XMonad.Doc.Extending XMonad.Doc.Developing+ XMonad.Actions.AfterDrag XMonad.Actions.BluetileCommands XMonad.Actions.Commands XMonad.Actions.ConstrainedResize@@ -102,6 +103,7 @@ XMonad.Actions.DynamicWorkspaces XMonad.Actions.DynamicWorkspaceGroups XMonad.Actions.DynamicWorkspaceOrder+ XMonad.Actions.DynamicProjects XMonad.Actions.FindEmptyWorkspace XMonad.Actions.FlexibleManipulate XMonad.Actions.FlexibleResize@@ -111,6 +113,7 @@ XMonad.Actions.GridSelect XMonad.Actions.GroupNavigation XMonad.Actions.Launcher+ XMonad.Actions.LinkWorkspaces XMonad.Actions.MessageFeedback XMonad.Actions.MouseGestures XMonad.Actions.MouseResize@@ -147,10 +150,14 @@ XMonad.Config.Arossato XMonad.Config.Azerty XMonad.Config.Bluetile+ XMonad.Config.Bepo XMonad.Config.Desktop+ XMonad.Config.Dmwit XMonad.Config.Droundy XMonad.Config.Gnome XMonad.Config.Kde+ XMonad.Config.Mate+ XMonad.Config.Prime XMonad.Config.Sjanssen XMonad.Config.Xfce XMonad.Hooks.CurrentWorkspaceOnTop@@ -159,6 +166,7 @@ XMonad.Hooks.DynamicBars XMonad.Hooks.DynamicHooks XMonad.Hooks.DynamicLog+ XMonad.Hooks.DynamicProperty XMonad.Hooks.DebugStack XMonad.Hooks.EwmhDesktops XMonad.Hooks.FadeInactive@@ -166,6 +174,7 @@ XMonad.Hooks.FloatNext XMonad.Hooks.ICCCMFocus XMonad.Hooks.InsertPosition+ XMonad.Hooks.ManageDebug XMonad.Hooks.ManageDocks XMonad.Hooks.ManageHelpers XMonad.Hooks.Minimize@@ -178,10 +187,14 @@ XMonad.Hooks.SetWMName XMonad.Hooks.ToggleHook XMonad.Hooks.UrgencyHook+ XMonad.Hooks.WallpaperSetter XMonad.Hooks.WorkspaceByPos+ XMonad.Hooks.WorkspaceHistory XMonad.Hooks.XPropManage XMonad.Layout.Accordion XMonad.Layout.AutoMaster+ XMonad.Layout.AvoidFloats+ XMonad.Layout.BinarySpacePartition XMonad.Layout.BorderResize XMonad.Layout.BoringWindows XMonad.Layout.ButtonDecoration@@ -198,6 +211,7 @@ XMonad.Layout.DraggingVisualizer XMonad.Layout.DragPane XMonad.Layout.Drawer+ XMonad.Layout.Dwindle XMonad.Layout.DwmStyle XMonad.Layout.FixedColumn XMonad.Layout.Fullscreen@@ -208,8 +222,10 @@ XMonad.Layout.Groups.Examples XMonad.Layout.Groups.Helpers XMonad.Layout.Groups.Wmii+ XMonad.Layout.Hidden XMonad.Layout.HintedGrid XMonad.Layout.HintedTile+ XMonad.Layout.IfMax XMonad.Layout.IM XMonad.Layout.ImageButtonDecoration XMonad.Layout.IndependentScreens@@ -238,6 +254,7 @@ XMonad.Layout.NoFrillsDecoration XMonad.Layout.OnHost XMonad.Layout.OneBig+ XMonad.Layout.PerScreen XMonad.Layout.PerWorkspace XMonad.Layout.PositionStoreFloat XMonad.Layout.Reflect@@ -254,6 +271,7 @@ XMonad.Layout.Spiral XMonad.Layout.Square XMonad.Layout.StackTile+ XMonad.Layout.Stoppable XMonad.Layout.SubLayouts XMonad.Layout.TabBarDecoration XMonad.Layout.Tabbed@@ -269,12 +287,14 @@ XMonad.Prompt XMonad.Prompt.AppendFile XMonad.Prompt.AppLauncher+ XMonad.Prompt.ConfirmPrompt XMonad.Prompt.Directory XMonad.Prompt.DirExec XMonad.Prompt.Email XMonad.Prompt.Input XMonad.Prompt.Layout XMonad.Prompt.Man+ XMonad.Prompt.Pass XMonad.Prompt.RunOrRaise XMonad.Prompt.Shell XMonad.Prompt.Ssh@@ -298,16 +318,19 @@ XMonad.Util.NamedWindows XMonad.Util.Paste XMonad.Util.PositionStore+ XMonad.Util.RemoteWindows XMonad.Util.Replace XMonad.Util.Run XMonad.Util.Scratchpad XMonad.Util.SpawnOnce+ XMonad.Util.SpawnNamedPipe XMonad.Util.Stack XMonad.Util.StringProp XMonad.Util.Themes XMonad.Util.Timer XMonad.Util.Types XMonad.Util.WindowProperties+ XMonad.Util.WindowState XMonad.Util.WorkspaceCompare XMonad.Util.XSelection XMonad.Util.XUtils