122 Commits
v0.8 ... v0.8.1

Author SHA1 Message Date
Spencer Janssen
b456b87e0e TAG 0.8.1 2009-01-18 22:06:47 +00:00
Spencer Janssen
da2a08ec7e Use spawnOn in my config 2009-01-17 04:10:26 +00:00
Spencer Janssen
c51f64476a Add XMonad.Actions.SpawnOn 2009-01-17 04:04:32 +00:00
Spencer Janssen
d1b2eb4bbb Bump version to 0.8.1 2009-01-16 22:36:07 +00:00
Spencer Janssen
03513bb9b4 Compile without optimizations on x86_64 and GHC 6.10
This is a workaround for http://xmonad.org/bugs/226
2009-01-08 23:16:50 +00:00
Spencer Janssen
0272b8e468 Update all uses of doubleFork/waitForProcess 2009-01-16 21:03:15 +00:00
Spencer Janssen
b1984eef30 Update to my config 2009-01-16 20:45:53 +00:00
Daniel Schoepe
deacde29a0 Adjustments to new userCode function 2009-01-10 22:13:10 +00:00
Brent Yorgey
22ea09d747 X.U.EZConfig: expand documentation 2009-01-16 15:31:43 +00:00
Brent Yorgey
2786791ff5 add a bit of documentation to HintedTile 2009-01-14 06:51:26 +00:00
johanngiwer
021298cb34 ManageHelpers: add isDialog 2009-01-08 23:25:05 +00:00
portnov84
f885e942e9 CenteredMaster
centerMaster layout modifier places master window at top of other, at center of screen. Other windows are managed by base layout.
topRightMaster is similar, but places master window at top right corner.
2009-01-11 13:45:13 +00:00
gwern0
b5d77062b9 XMonad.Util.XSelection: update maintainer information 2009-01-10 21:30:00 +00:00
Brent Yorgey
bcec549103 X.U.XSelection: get rid of warning about missing newline, add Haddock link 2009-01-02 19:43:57 +00:00
loupgaroublond
d889c531d0 adds haddock documentation for transformPromptSelection
also renames the function per mailing list recommendation
2009-01-02 19:09:54 +00:00
loupgaroublond
44b9610906 adds a weird function to XSelection
This enables you to pass a function of (String -> String) to a selection function to modify the string before executing it.  This way, you can input your own escape routines to make it shell command line safe, and/or do other fancier things.
2008-12-22 02:07:30 +00:00
xmonad
f3617e75c5 ThreeColumnsMiddle 2009-01-02 09:10:19 +00:00
rupa
56850074df fix-fromJust-errors
bogner wrote all this stuff and i just tested it.

I had:

myLogHook = ewmhDesktopLogHookCustom ScratchpadFilterOutWorkspace >> updatePointer Nearest

Everytime I invoked or hid Scratchpad, it would leave a 'Maybe.fromJust: Nothing' line in .xsession-errors, and updatePointer would stop working.
2008-12-24 04:55:09 +00:00
Dominik Bruhn
3ac1205411 Prompt: Change Filemode to 600 for history-file (fixes bug 244) 2008-12-18 00:16:01 +00:00
Roman Cheplyaka
ed240c6972 X.L.Monitor: changes in message passing
- transform mbName (Maybe String) to name (String)
- slghtly change semantics of messages, document it
2008-12-26 22:08:51 +00:00
Roman Cheplyaka
d44ca42551 X.L.Monitor: change interface
- remove add*Monitor
- add manageMonitor, monitor template
2008-12-26 21:31:18 +00:00
Roman Cheplyaka
fc581c9e4a X.U.WindowProperties: propertyToQuery+docs 2008-12-25 08:07:02 +00:00
Roman Cheplyaka
c5af703cb8 X.L.Monitor: docs 2008-12-25 07:39:04 +00:00
gwern0
42692986e6 hlintify XUtils, XSelection, Search, WindowGo 2008-12-20 15:33:02 +00:00
Norbert Zeh
88e524f480 fix focus issue for XMonad.Actions.Warp.banishScreen
This patch ensures that the focus (or in fact the whose windowset)
does not change as a result of a banishScreen.  The way this is implemented
will become problematic if xmonad ever goes multithreaded.
2008-12-12 20:35:32 +00:00
Norbert Zeh
4c7ebafcfe addition of XMonad.Actions.Warp.banishScreen
This works on top of warpToScreen and, thus, suffers from the same issue:
focus change.
2008-12-12 19:26:21 +00:00
Norbert Zeh
fe253a602c fixed documentation for banish
banish actually warps to the specified corner of the current window, not
the screen.
2008-12-12 19:18:19 +00:00
Norbert Zeh
52379a3736 addition of combined TallGrid layout
Added a module XMonad.Layouts.GridVariants, which defines layouts
Grid and TallGrid.  The former is a customizable version of Grid.  The latter
is a combination of Grid and Tall (see doc of the module).
2008-12-12 18:48:36 +00:00
Justin Bogner
a11a42b2a5 Add FixedColumn, a layout like Tall but based on the resize hints of windows 2008-12-13 07:30:54 +00:00
gwern0
afa80ad2a2 XMonad.Actions.WindowGo: fix a floating-related focus bug
If a floating window was focused, a cross-workspace 'raise' would cause a loop of
shifting windows. Apparently the problem was 'focus' and its mouse-handling. Spencer
suggested that the calls to focus be replaced with 'focusWindow', which resolved it.
2008-12-05 15:07:55 +00:00
gwern0
ef310e1792 Prompt.hs: +greenXPConfig and amberXPConfig 2008-11-19 21:31:22 +00:00
gwern0
8afb72a48e Prompt.hs: increase font size to 12 from niggardly 10 2008-11-19 21:25:23 +00:00
gwern0
a521838fac Prompt.hs: replace magic numbers with understandable names 2008-11-19 21:25:02 +00:00
Roman Cheplyaka
8698e58f12 X.L.Monitor: recommend doHideIgnore (docs) 2008-12-15 19:07:10 +00:00
Roman Cheplyaka
99f04b7504 X.L.Monitor: docs 2008-12-15 18:44:23 +00:00
Roman Cheplyaka
f365c082ba X.L.Monitor: export Monitor datatype 2008-12-15 18:43:18 +00:00
Roman Cheplyaka
601c3c06db X.H.ManageHelpers: add doHideIgnore 2008-12-15 18:27:58 +00:00
Spencer Janssen
9d0f34852c Add KDE 4 config, thanks to Shirakawasuna on IRC 2008-12-11 07:11:41 +00:00
Spencer Janssen
293b8152aa I use the deleteConsecutive history filter 2008-10-25 07:04:38 +00:00
Braden Shepherdson
1d78c1fd60 Remove XMonad.Config.PlainConfig, it has been turned into the separate xmonad-light project. 2008-12-03 16:15:34 +00:00
gwern0
96786e0abd XMonad.Prompt: swap up and down per bug #243 2008-12-03 01:33:23 +00:00
Aleksandar Dimitrov
78a9495c03 Fix boolean operator precedence in GridSelect keybindings
The vim-like hjkl keys were ORed to the key event AND arrow keys.
2008-12-01 12:09:28 +00:00
sean.escriva
0462f00f42 GridSelect.hs: navigate grid with h,j,k,l as well as arrow keys 2008-11-22 08:47:25 +00:00
Roman Cheplyaka
3b4473f121 Export setOpacity from FadeInactive. Document how to make monitor transparent (X.L.Monitor) 2008-11-17 15:30:27 +00:00
Roman Cheplyaka
6962d8f216 Monitor: use broadcastMessage instead of sendMessage; this solves several issues 2008-11-17 13:39:57 +00:00
Roman Cheplyaka
0a935aff63 FadeInactive: fade all inactive windows (including focused windows on visible screens) 2008-11-17 13:01:15 +00:00
Roman Cheplyaka
642cbdcad6 Monitor: documented one more issue 2008-11-17 11:38:07 +00:00
Roman Cheplyaka
1a6c11e8e6 Monitor: improved the docs 2008-11-17 07:37:09 +00:00
Roman Cheplyaka
8cc3556448 added XMonad.Layout.Monitor 2008-11-15 10:47:35 +00:00
Roman Cheplyaka
d043dfbaf9 WindowProperties: added allWithProperty 2008-11-15 10:45:25 +00:00
Roman Cheplyaka
565dd89ebe ManageHelpers: added doSideFloat (generalization of doCenterFloat) 2008-11-14 11:30:15 +00:00
Dominik Bruhn
20119ffa7a GridSelect: Export default_colorizer 2008-11-12 14:00:05 +00:00
Dominik Bruhn
7337ce50c2 Simplify code for restriction-calculation and remove compiletime warnings 2008-11-12 13:46:30 +00:00
Clemens Fruhwirth
cbc978936e Simplify handle/eventLoop, introduce findInWindowMap, partial updates for key movements (less flickering)
* handle/eventLoop carried the display and the drawing window as
  parameters. The display is available from the embedded X monad, the
  drawing windows was added.

* updateWindows now takes a list of windows to
  update. updateAllWindows updates all windows.

* only the windows that are modified by key movements are redrawn
  now. This means less flickering.
2008-11-11 10:04:05 +00:00
Roman Cheplyaka
80618c53c1 GridSelect: force cursor stay in visible area 2008-11-11 06:33:48 +00:00
Roman Cheplyaka
4908cc5efb GridSelect: fix infiniteness problem with diamondRestrict 2008-11-11 05:53:50 +00:00
Roman Cheplyaka
a5ffb70fc6 GridSelect: remove tabs 2008-11-11 05:36:47 +00:00
Roman Cheplyaka
dcde384f1a Exported shrinkWhile from Decoration to use in GridSelect 2008-11-10 19:15:34 +00:00
Roman Cheplyaka
e3503bc3f2 GridSelect: added link to a screenshot 2008-11-10 19:06:17 +00:00
Roman Cheplyaka
1415787fa3 GridSelect: various improvements
Added documentation
Restricted export list for the sake of haddock
Added functions:
  withSelectedWindow
  bringSelected (by Clemens Fruhwirth)
  goToSelected (by Dominik Bruhn)
2008-11-10 18:46:44 +00:00
Clemens Fruhwirth
de64bf60b4 Initial version of GridSelect.hs with a lot room for improvement/cleanups 2008-11-07 11:51:14 +00:00
sean.escriva
7749dc92d5 documentation: XMonad.Util.Search.hs, add EZConfig keybindings example 2008-11-06 17:17:07 +00:00
Don Stewart
9d2a5d4acc typo 2008-11-04 04:30:44 +00:00
Don Stewart
b6164c6ddc place an upper bound on the version of base we support 2008-11-04 03:58:57 +00:00
Don Stewart
c40d8c2f3d explicit import list for things in the process library 2008-11-04 03:53:19 +00:00
Don Stewart
b6c951a30c Work around ghc 6.10 bug #2738 2008-11-04 03:48:19 +00:00
deadguysfrom
2520104b1e windowPromptBringCopy 2008-10-23 17:30:19 +00:00
Travis B. Hartwell
b849ccb29e generic menu and window bringer 2008-10-27 00:55:23 +00:00
gwern0
1e30ffe2c6 Search.hs: +hackage search, courtesy of byorgey 2008-10-31 21:49:37 +00:00
gwern0
f0259987b1 Prompt.hs rename deleteConsecutiveDuplicates
That name is really unwieldy and long.
2008-10-08 20:51:31 +00:00
gwern0
c27eb22b39 Prompt.hs: have historyCompletion filter dupes
Specifically, it calls deleteConsecutiveDuplicates on the end product. uniqSort reverses order in an unfortunate way, so we don't use that.
The use-case is when a user has added the same input many times - as it stands, if the history records 30 'top's or whatever, the completion will show 30 'top' entries! This fixes that.
2008-10-08 20:47:10 +00:00
gwern0
a0ac6331df Prompt.hs: tweak haddocks 2008-10-08 20:46:49 +00:00
gwern0
806c1f4b5f Prompt.hs: mv uniqSort to next to its confreres, and mention the trade-off 2008-10-08 19:26:45 +00:00
Joachim Breitner
a4cbf496e7 Do not consider XMONAD_TIMER unknown 2008-10-08 19:56:43 +00:00
Joachim Breitner
6d17e66bb3 Kill window without focusing it first
This patch requires the patch "add killWindow function" in xmonad.
Before this patch, people would experience “workspace flicker” when closing
a window via EWMH that is not on the current workspace, for example when
quitting pidgin via the panel icon.
2008-10-05 00:25:33 +00:00
daniel
a2cf9d4d97 let MagnifyLess actually magnify less 2008-10-15 15:39:11 +00:00
intrigeri
9d409b6b3d Actions.Search: add a few search engines
Add Debian {package, bug, tracking system} search engines, as well as Google
Images and isohunt.
2008-10-08 10:40:33 +00:00
Joachim Breitner
5f361b02af Implement HiddenNonEmptyWS with HiddenWS and NonEmptyWS
(Just to reduce code duplication)
2008-10-06 21:10:27 +00:00
Joachim Breitner
5514c2ddca Add straightforward HiddenWS to WSType
With NonEmptyWS and HiddenNonEmptyWS present, HiddenWS is obviously missing.
2008-10-06 21:05:48 +00:00
Joachim Breitner
2480ba1f02 Merge emptyLayoutMod into redoLayout
This removes the emptyLayoutMod method from the LayoutModifier class, and
change the Stack parameter to redoLayout to a Maybe Stack one. It also changes
all affected code. This should should be a refactoring without any change in
program behaviour.
2008-10-05 19:02:20 +00:00
Joachim Breitner
2102a565fd SmartBorders even for empty layouts
Fixes: http://code.google.com/p/xmonad/issues/detail?id=223
2008-10-05 18:44:26 +00:00
gwern0
2051b80b25 Paste.hs: improve haddocks 2008-09-27 15:01:58 +00:00
gwern0
e8edf860f7 Paste.hs: fix haddock 2008-09-27 14:52:38 +00:00
daniel
95c8fa2d1d minor explanatory comment 2008-10-03 01:59:19 +00:00
Lukas Mai
a667fa5720 XMonad.Layout.HintedGrid: add GridRatio (--no-test because of haddock breakage) 2008-09-30 14:17:15 +00:00
Lukas Mai
31fd3135cf XMonad.Util.Font: UTF8 -> USE_UTF8 2008-09-30 14:00:56 +00:00
gwern0
300d9cf2b7 Paste.hs: implement noModMask suggestion 2008-09-26 23:20:56 +00:00
daniel
b663075990 fix a divide by zero error in Grid 2008-09-26 20:41:48 +00:00
gwern0
b0c3dcc192 -DUTF8 flag with -DUSE_UTF8 2008-09-21 15:40:14 +00:00
gwern0
07e9192f6f XSelection.hs: use CPP to compile against utf8-string 2008-09-20 15:16:15 +00:00
Devin Mullins
205032840b add XMonad.Config.Azerty 2008-09-24 04:49:46 +00:00
Devin Mullins
ae57d452be flip GridRatio to match convention (x/y) 2008-09-22 03:33:54 +00:00
daniel
bf51c0f64c let Grid have a configurable aspect ratio goal 2008-09-22 01:09:50 +00:00
gwern0
8971328f06 Paste.hs: +warning about ASCII limitations 2008-09-21 15:50:38 +00:00
gwern0
38a21daefe Paste.hs: shorten comment lines to under 80 columns per sjanssen 2008-09-21 15:49:50 +00:00
Spencer Janssen
9476610ee0 Forgot to enable historyFilter :( 2008-09-21 09:42:54 +00:00
Spencer Janssen
2d5b9475b9 Prompt: add configurable history filters 2008-09-21 09:34:53 +00:00
Spencer Janssen
005f4ef7fb Update my config to use 'statusBar' 2008-09-21 06:35:13 +00:00
Spencer Janssen
1c1205daed Rename pasteKey functions to sendKey 2008-09-21 06:20:16 +00:00
Spencer Janssen
505cbb2430 DynamicLog: doc fixes 2008-09-21 06:13:14 +00:00
Spencer Janssen
2477985387 Move XMonad.Util.XPaste to XMonad.Util.Paste 2008-09-21 06:09:47 +00:00
Spencer Janssen
8d670902e5 Depend on X11 >= 1.4.3 2008-09-21 05:54:56 +00:00
Spencer Janssen
c75b058c5b statusBar now supplies the action to toggle struts 2008-09-18 01:38:58 +00:00
Devin Mullins
f3b6b2707a cleanup - use currentTag 2008-09-21 01:11:59 +00:00
gwern0
bd2b5379ab XPaste.hs: improve author info 2008-09-20 15:23:42 +00:00
gwern0
4ae4a7ec07 +XMonad.Util.XPaste: a module for pasting strings to windows 2008-09-20 15:21:06 +00:00
Devin Mullins
9dd5fff540 UrgencyHook bug fix: cleanupUrgents should clean up reminders, too 2008-09-20 06:21:17 +00:00
Spencer Janssen
026fdf71be Sketch of XMonad.Config.Monad 2008-09-17 08:18:38 +00:00
seanmce33
10be813bd7 raiseMaster 2008-09-12 18:48:30 +00:00
Daniel Neri
63a0177187 Add missing space between dzen command and flags 2008-09-15 13:10:09 +00:00
Spencer Janssen
2d1ccbe643 Big DynamicLog refactor. Added statusBar, improved compositionality for dzen and xmobar
Compatibility notes:
    - dzen type change
    - xmobar type change
    - dynamicLogDzen removed
    - dynamicLogXmobar removed
2008-09-13 20:59:31 +00:00
Spencer Janssen
03caedc589 Take maintainership of XMonad.Prompt 2008-09-11 23:04:42 +00:00
Spencer Janssen
e677bb3cc1 Overhaul Prompt to use a zipper for history navigation. Fixes issue #216 2008-09-11 22:59:40 +00:00
Spencer Janssen
644b85ab36 Use the new completion on tab setting 2008-09-11 08:59:40 +00:00
Joachim Breitner
587078d456 Only start to show the completion window with more than one match 2008-09-08 11:01:29 +00:00
Joachim Breitner
25033caf6e XPrompt: Add showCompletionOnTab option
This patch partially implements
http://code.google.com/p/xmonad/issues/detail?id=215
It adds a XPConfig option that, if enabled, hides the completion window
until the user presses Tab once. Default behaviour is preserved.
TODO: If Tab causes a unique completion, continue to hide the completion
window.
2008-09-08 10:57:58 +00:00
Marco Túlio Gontijo e Silva
a908ff760b XMonad.Actions.Plane.planeKeys: function to make easier to configure 2008-07-14 15:36:01 +00:00
Marco Túlio Gontijo e Silva
07a5355edc XMonad.Actions.Plane: removed unneeded hiding 2008-07-14 15:26:31 +00:00
Marco Túlio Gontijo e Silva
289b994646 Improvements in documentation 2008-07-09 00:24:25 +00:00
Spencer Janssen
297e626fc7 Fix haddock typos in XMonad.Config.{Desktop,Gnome,Kde} 2008-09-11 04:08:08 +00:00
Devin Mullins
c3d5c09e84 add clearUrgents for your keys 2008-09-09 05:54:25 +00:00
Devin Mullins
27efc7a626 add reminder functionality to UrgencyHook
I'm considering rewriting remindWhen and suppressWhen as UrgencyHookModifiers, so to speak. Bleh.
2008-08-24 20:05:48 +00:00
63 changed files with 1990 additions and 1004 deletions

View File

@@ -77,7 +77,7 @@ copyToAll s = foldr copy s $ map tag (workspaces s)
copyWindow :: (Eq a, Eq i, Eq s) => a -> i -> StackSet i l a s sd -> StackSet i l a s sd
copyWindow w n = copy'
where copy' s = if n `tagMember` s
then view (tag (workspace (current s))) $ insertUp' w $ view n s
then view (currentTag s) $ insertUp' w $ view n s
else s
insertUp' a s = modify (Just $ Stack a [] [])
(\(Stack t l r) -> if a `elem` t:l++r
@@ -107,7 +107,7 @@ kill1 = do ss <- gets windowset
killAllOtherCopies :: X ()
killAllOtherCopies = do ss <- gets windowset
whenJust (peek ss) $ \w -> windows $
view (tag (workspace (current ss))) .
view (currentTag ss) .
delFromAllButCurrent w
where
delFromAllButCurrent w ss = foldr ($) ss $

View File

@@ -172,6 +172,7 @@ data WSDirection = Next | Prev
-- | What type of workspaces should be included in the cycle?
data WSType = EmptyWS -- ^ cycle through empty workspaces
| NonEmptyWS -- ^ cycle through non-empty workspaces
| HiddenWS -- ^ cycle through non-visible workspaces
| HiddenNonEmptyWS -- ^ cycle through non-empty non-visible workspaces
| AnyWS -- ^ cycle through all workspaces
| WSIs (X (WindowSpace -> Bool))
@@ -182,8 +183,11 @@ data WSType = EmptyWS -- ^ cycle through empty workspaces
wsTypeToPred :: WSType -> X (WindowSpace -> Bool)
wsTypeToPred EmptyWS = return (isNothing . stack)
wsTypeToPred NonEmptyWS = return (isJust . stack)
wsTypeToPred HiddenNonEmptyWS = do hs <- gets (map tag . hidden . windowset)
return (\w -> isJust (stack w) && tag w `elem` hs)
wsTypeToPred HiddenWS = do hs <- gets (map tag . hidden . windowset)
return (\w -> tag w `elem` hs)
wsTypeToPred HiddenNonEmptyWS = do ne <- wsTypeToPred NonEmptyWS
hi <- wsTypeToPred HiddenWS
return (\w -> hi w && ne w)
wsTypeToPred AnyWS = return (const True)
wsTypeToPred (WSIs p) = p
@@ -217,7 +221,7 @@ findWorkspace s dir t n = findWorkspaceGen s (wsTypeToPred t) (maybeNegate dir n
maybeNegate Prev d = (-d)
findWorkspaceGen :: X WorkspaceSort -> X (WindowSpace -> Bool) -> Int -> X WorkspaceId
findWorkspaceGen _ _ 0 = (tag . workspace . current) `fmap` gets windowset
findWorkspaceGen _ _ 0 = gets (currentTag . windowset)
findWorkspaceGen sortX wsPredX d = do
wsPred <- wsPredX
sort <- sortX

View File

@@ -0,0 +1,302 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.GridSelect
-- Copyright : Clemens Fruhwirth <clemens@endorphin.org>
-- License : BSD-style (see LICENSE)
--
-- Maintainer : Clemens Fruhwirth <clemens@endorphin.org>
-- Stability : unstable
-- Portability : unportable
--
-- GridSelect displays a 2D grid of windows to navigate with cursor
-- keys and to select with return.
--
-----------------------------------------------------------------------------
module XMonad.Actions.GridSelect (
-- * Usage
-- $usage
GSConfig(..),
defaultGSConfig,
gridselect,
withSelectedWindow,
bringSelected,
goToSelected,
default_colorizer
) where
import Data.Maybe
import Data.Bits
import Control.Monad.State
import Control.Arrow
import Data.List as L
import XMonad
import XMonad.Util.Font
import XMonad.Prompt (mkUnmanagedWindow)
import XMonad.StackSet as W
import XMonad.Layout.Decoration
import XMonad.Util.NamedWindows
import XMonad.Actions.WindowBringer (bringWindow)
import Text.Printf
-- $usage
--
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
--
-- > import XMonad.Actions.GridSelect
--
-- Then add a keybinding, e.g.
--
-- > , ((modMask x, xK_g), goToSelected defaultGSConfig)
--
-- Screenshot: <http://clemens.endorphin.org/gridselect.png>
data GSConfig = GSConfig {
gs_cellheight :: Integer,
gs_cellwidth :: Integer,
gs_cellpadding :: Integer,
gs_colorizer :: Window -> Bool -> X (String, String),
gs_font :: String
}
type TwoDPosition = (Integer, Integer)
type TwoDWindowMap = [(TwoDPosition,(String,Window))]
data TwoDState = TwoDState { td_curpos :: TwoDPosition,
td_windowmap :: [(TwoDPosition,(String,Window))],
td_gsconfig :: GSConfig,
td_font :: XMonadFont,
td_paneX :: Integer,
td_paneY :: Integer,
td_drawingWin :: Window
}
type TwoD a = StateT TwoDState X a
diamondLayer :: (Enum b', Num b') => b' -> [(b', b')]
-- FIXME remove nub
diamondLayer n = let ul = [ (x,n-x) | x <- [0..n] ]
in nub $ ul ++ (map (negate *** id) ul) ++
(map (negate *** negate) ul) ++
(map (id *** negate) ul)
diamond :: (Enum a, Num a) => [(a, a)]
diamond = concatMap diamondLayer [0..]
diamondRestrict :: (Enum t, Num t, Ord t) => t -> t -> [(t, t)]
diamondRestrict x y = L.filter (\(x',y') -> abs x' <= x && abs y' <= y) .
L.takeWhile (\(x',y') -> abs x' + abs y' <= x+y) $ diamond
tupadd :: (Num t1, Num t) => (t, t1) -> (t, t1) -> (t, t1)
tupadd (a,b) (c,d) = (a+c,b+d)
findInWindowMap :: (Eq a) => a -> [(a, b)] -> Maybe (a, b)
findInWindowMap pos = find ((== pos) . fst)
drawWinBox :: Window -> XMonadFont -> (String, String) -> Integer -> Integer -> String -> Integer -> Integer -> Integer -> X ()
drawWinBox win font (fg,bg) ch cw text x y cp =
withDisplay $ \dpy -> do
gc <- liftIO $ createGC dpy win
bordergc <- liftIO $ createGC dpy win
liftIO $ do
Just fgcolor <- initColor dpy fg
Just bgcolor <- initColor dpy bg
Just bordercolor <- initColor dpy borderColor
setForeground dpy gc fgcolor
setBackground dpy gc bgcolor
setForeground dpy bordergc bordercolor
fillRectangle dpy win gc (fromInteger x) (fromInteger y) (fromInteger cw) (fromInteger ch)
drawRectangle dpy win bordergc (fromInteger x) (fromInteger y) (fromInteger cw) (fromInteger ch)
stext <- shrinkWhile (shrinkIt shrinkText)
(\n -> do size <- liftIO $ textWidthXMF dpy font n
return $ size > (fromInteger (cw-(2*cp))))
text
printStringXMF dpy win font gc bg fg (fromInteger (x+cp)) (fromInteger (y+(div ch 2))) stext
liftIO $ freeGC dpy gc
liftIO $ freeGC dpy bordergc
updateAllWindows :: TwoD ()
updateAllWindows =
do
TwoDState { td_windowmap = wins } <- get
updateWindows wins
updateWindows :: TwoDWindowMap -> TwoD ()
updateWindows windowmap = do
TwoDState { td_curpos = curpos,
td_drawingWin = win,
td_gsconfig = gsconfig,
td_font = font,
td_paneX = paneX,
td_paneY = paneY} <- get
let cellwidth = gs_cellwidth gsconfig
cellheight = gs_cellheight gsconfig
paneX' = div (paneX-cellwidth) 2
paneY' = div (paneY-cellheight) 2
updateWindow (pos@(x,y),(text, clientwindow)) = lift $ do
colors <- (gs_colorizer gsconfig) clientwindow (pos == curpos)
drawWinBox win font
colors
cellheight
cellwidth
text
(paneX'+x*cellwidth)
(paneY'+y*cellheight)
(gs_cellpadding gsconfig)
mapM updateWindow windowmap
return ()
eventLoop :: TwoD (Maybe Window)
eventLoop = do
(keysym,string,event) <- lift $ withDisplay $ \d -> liftIO $ allocaXEvent $ \e -> do
nextEvent d e
ev <- getEvent e
(ks,s) <- if ev_event_type ev == keyPress
then lookupString $ asKeyEvent e
else return (Nothing, "")
return (ks,s,ev)
handle (fromMaybe xK_VoidSymbol keysym,string) event
handle :: (KeySym, String)
-> Event
-> StateT TwoDState X (Maybe Window)
handle (ks,_) (KeyEvent {ev_event_type = t})
| t == keyPress && ks == xK_Escape = return Nothing
| t == keyPress && (ks == xK_Left || ks == xK_h) = diffAndRefresh (-1,0)
| t == keyPress && (ks == xK_Right || ks == xK_l) = diffAndRefresh (1,0)
| t == keyPress && (ks == xK_Down || ks == xK_j) = diffAndRefresh (0,1)
| t == keyPress && (ks == xK_Up || ks == xK_k) = diffAndRefresh (0,-1)
| t == keyPress && ks == xK_Return = do
(TwoDState { td_curpos = pos, td_windowmap = winmap }) <- get
return $ fmap (snd . snd) $ findInWindowMap pos winmap
where diffAndRefresh diff = do
state <- get
let windowmap = td_windowmap state
oldPos = td_curpos state
newPos = oldPos `tupadd` diff
newSelectedWin = findInWindowMap newPos windowmap
when (isJust newSelectedWin) $ do
put state { td_curpos = newPos }
updateWindows (catMaybes [(findInWindowMap oldPos windowmap), newSelectedWin])
eventLoop
handle _ (ExposeEvent { }) = do
updateAllWindows
eventLoop
handle _ _ = do
eventLoop
-- FIXME probably move that into Utils?
-- Conversion scheme as in http://en.wikipedia.org/wiki/HSV_color_space
hsv2rgb :: Fractional a => (Integer,a,a) -> (a,a,a)
hsv2rgb (h,s,v) =
let hi = (div h 60) `mod` 6 :: Integer
f = (((fromInteger h)/60) - (fromInteger hi)) :: Fractional a => a
q = v * (1-f)
p = v * (1-s)
t = v * (1-(1-f)*s)
in case hi of
0 -> (v,t,p)
1 -> (q,v,p)
2 -> (p,v,t)
3 -> (p,q,v)
4 -> (t,p,v)
5 -> (v,p,q)
_ -> error "The world is ending. x mod a >= a."
default_colorizer :: Window -> Bool -> X (String, String)
default_colorizer w active = do
classname <- runQuery className w
let seed x = toInteger (sum $ map ((*x).fromEnum) classname) :: Integer
(r,g,b) = hsv2rgb ((seed 83) `mod` 360,
(fromInteger ((seed 191) `mod` 1000))/2500+0.4,
(fromInteger ((seed 121) `mod` 1000))/2500+0.4)
if active
then return ("#faff69", "black")
else return ("#" ++ concat (map (twodigitHex.(round :: Double -> Integer).(*256)) [r, g, b] ), "white")
where
twodigitHex :: Integer -> String
twodigitHex a = printf "%02x" a
-- | Brings up a 2D grid of windows in the center of the screen, and one can
-- select a window with cursors keys. The selected window is returned.
gridselect :: GSConfig -> X (Maybe Window)
gridselect gsconfig =
withDisplay $ \dpy -> do
rootw <- liftIO $ rootWindow dpy (defaultScreen dpy)
s <- gets $ screenRect . W.screenDetail . W.current . windowset
windowList <- windowMap
win <- liftIO $ mkUnmanagedWindow dpy (defaultScreenOfDisplay dpy) rootw
(rect_x s) (rect_y s) (rect_width s) (rect_height s)
liftIO $ mapWindow dpy win
liftIO $ selectInput dpy win (exposureMask .|. keyPressMask)
status <- io $ grabKeyboard dpy win True grabModeAsync grabModeAsync currentTime
font <- initXMF (gs_font gsconfig)
let screenWidth = toInteger $ rect_width s;
screenHeight = toInteger $ rect_height s;
selectedWindow <- if (status == grabSuccess) then
do
let restriction :: Integer -> (GSConfig -> Integer) -> Double
restriction ss cs = ((fromInteger ss)/(fromInteger $ cs gsconfig)-1)/2
restrictX = floor $ restriction screenWidth gs_cellwidth
restrictY = floor $ restriction screenHeight gs_cellheight
winmap = zipWith (,) (diamondRestrict restrictX restrictY) windowList
selectedWindow <- evalStateT (do updateAllWindows; eventLoop)
(TwoDState (0,0)
winmap
gsconfig
font
screenWidth
screenHeight
win)
return selectedWindow
else
return Nothing
liftIO $ do
unmapWindow dpy win
destroyWindow dpy win
sync dpy False
releaseXMF font
return selectedWindow
-- | Brings up a 2D grid of windows in the center of the screen, and one can
-- select a window with cursors keys. The selected window is then passed to
-- a callback function.
withSelectedWindow :: (Window -> X ()) -> GSConfig -> X ()
withSelectedWindow callback conf = do
mbWindow <- gridselect conf
case mbWindow of
Just w -> callback w
Nothing -> return ()
windowMap :: X [(String,Window)]
windowMap = do
ws <- gets windowset
wins <- mapM keyValuePair (W.allWindows ws)
return wins
where keyValuePair w = flip (,) w `fmap` decorateName' w
decorateName' :: Window -> X String
decorateName' w = do
fmap show $ getName w
defaultGSConfig :: GSConfig
defaultGSConfig = GSConfig 50 130 10 default_colorizer "xft:Sans-8"
borderColor :: String
borderColor = "white"
-- | Brings selected window to the current workspace.
bringSelected :: GSConfig -> X ()
bringSelected = withSelectedWindow $ \w -> do
windows (bringWindow w)
XMonad.focus w
windows W.shiftMaster
-- | Switches to selected window's workspace and focuses that window.
goToSelected :: GSConfig -> X ()
goToSelected = withSelectedWindow $ windows . W.focusWindow

View File

@@ -65,7 +65,8 @@ instance Show (MouseResize a) where show _ = ""
instance Read (MouseResize a) where readsPrec _ s = [(MR [], s)]
instance LayoutModifier MouseResize Window where
redoLayout (MR st) _ s wrs
redoLayout _ _ Nothing wrs = return (wrs, Nothing)
redoLayout (MR st) _ (Just s) wrs
| [] <- st = initState >>= \nst -> return (wrs, Just $ MR nst)
| otherwise = processState >>= \nst -> return (wrs, Just $ MR nst)
where

View File

@@ -36,7 +36,7 @@ import Data.List (find)
-- | Uses supplied function to decide which action to run depending on current workspace name.
chooseAction :: (String->X()) -> X()
chooseAction f = withWindowSet (f . S.tag . S.workspace . S.current)
chooseAction f = withWindowSet (f . S.currentTag)
-- | If current workspace is listed, run appropriate action (only the first match counts!)
-- If it isn't listed, then run default action (marked with empty string, \"\"), or do nothing if default isn't supplied.

View File

@@ -29,6 +29,9 @@ module XMonad.Actions.Plane
, Limits (..)
, Lines (..)
-- * Key bindings
, planeKeys
-- * Navigating through workspaces
, planeShift
, planeMove
@@ -36,7 +39,8 @@ module XMonad.Actions.Plane
where
import Control.Monad
import Data.List hiding (union)
import Data.List
import Data.Map hiding (split)
import Data.Maybe
import XMonad
@@ -52,12 +56,7 @@ import XMonad.Util.Run
-- >
-- > myKeys conf = union (keys defaultConfig conf) $ myNewKeys conf
-- >
-- > myNewkeys (XConfig {modMask = m}) =
-- > fromList
-- > [ ((keyMask .|. m, keySym), function (Lines 3) Finite direction)
-- > | (keySym, direction) <- zip [xK_Left .. xK_Down] $ enumFrom ToLeft
-- > , (keyMask, function) <- [(0, planeMove), (shiftMask, planeShift)]
-- > ]
-- > myNewkeys (XConfig {modMask = modm}) = planeKeys modm (Lines 3) Finite
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
@@ -65,13 +64,12 @@ import XMonad.Util.Run
-- | Direction to go in the plane.
data Direction = ToLeft | ToUp | ToRight | ToDown deriving Enum
-- | Defines whether it's a finite or a circular organization of workspaces.
-- | Defines the behaviour when you're trying to move out of the limits.
data Limits
= Finite -- ^ When you're at a edge of the plane, there's no way to move
-- to the next region.
| Circular -- ^ If you try to move, you'll get to the other edge, on the
-- other side.
| Linear -- ^ The plan comes as a row.
= Finite -- ^ Ignore the function call, and keep in the same workspace.
| Circular -- ^ Get on the other side, like in the Snake game.
| Linear -- ^ The plan comes as a row, so it goes to the next or prev if
-- the workspaces were numbered.
deriving Eq
-- | The number of lines in which the workspaces will be arranged. It's
@@ -82,26 +80,22 @@ data Lines
= GConf -- ^ Use @gconftool-2@ to find out the number of lines.
| Lines Int -- ^ Specify the number of lines explicity.
-- $navigating
--
-- There're two parameters that must be provided to navigate, and it's a good
-- idea to use them with the same values in each keybinding.
--
-- The first is the number of lines in which the workspaces are going to be
-- organized. It's possible to use a number of lines that is not a divisor
-- of the number of workspaces, but the results are better when using a
-- divisor. If it's not a divisor, the last line will have the remaining
-- workspaces.
--
-- The other one is 'Limits'.
-- | This is the way most people would like to use this module. It ataches the
-- 'KeyMask' passed as a parameter with 'xK_Left', 'xK_Up', 'xK_Right' and
-- 'xK_Down', associating it with 'planeMove' to the corresponding 'Direction'.
-- It also associates these bindings with 'shiftMask' to 'planeShift'.
planeKeys :: KeyMask -> Lines -> Limits -> Map (KeyMask, KeySym) (X ())
planeKeys modm ln limits =
fromList $
[ ((keyMask, keySym), function ln limits direction)
| (keySym, direction) <- zip [xK_Left .. xK_Down] $ enumFrom ToLeft
, (keyMask, function) <- [(modm, planeMove), (shiftMask .|. modm, planeShift)]
]
-- | Shift a window to the next workspace in 'Direction'. Note that this will
-- also move to the next workspace.
planeShift
:: Lines
-> Limits
-> Direction
-> X ()
-- also move to the next workspace. It's a good idea to use the same 'Lines'
-- and 'Limits' for all the bindings.
planeShift :: Lines -> Limits -> Direction -> X ()
planeShift = plane shift'
shift' ::

View File

@@ -22,10 +22,16 @@ module XMonad.Actions.Search ( -- * Usage
amazon,
codesearch,
deb,
debbts,
debpts,
dictionary,
google,
hackage,
hoogle,
images,
imdb,
isohunt,
maps,
mathworld,
scholar,
@@ -75,14 +81,26 @@ import XMonad.Util.XSelection (getSelection)
* 'codesearch' -- Google Labs Code Search search.
* 'deb' -- Debian package search.
* 'debbts' -- Debian Bug Tracking System.
* 'debpts -- Debian Package Tracking System.
* 'dictionary' -- dictionary.reference.com search.
* 'google' -- basic Google search.
* 'hoogle' -- Hoogle, the Haskell libraries search engine.
* 'hackage' -- Hackage, the Haskell package database.
* 'hoogle' -- Hoogle, the Haskell libraries API search engine.
* 'images' -- Google images.
* 'imdb' -- the Internet Movie Database.
* 'isohunt' -- isoHunt search.
* 'maps' -- Google maps.
* 'mathworld' -- Wolfram MathWorld search.
@@ -125,6 +143,22 @@ Then add the following to your key bindings:
> , ((0, xK_w), method S.wikipedia)
> ]
Or in combination with XMonad.Util.EZConfig:
> ...
> ] -- end of regular keybindings
> -- Search commands
> ++ [("M-s " ++ k, S.promptSearch P.defaultXPConfig f) | (k,f) <- searchList ]
> ++ [("M-S-s " ++ k, S.selectSearch f) | (k,f) <- searchList ]
>
> ...
>
> searchList :: [([Char], S.SearchEngine)]
> searchList = [ ("g", S.google)
> , ("h", S.hoohle)
> , ("w", S.wikipedia)
> ]
Make sure to set firefox to open new pages in a new window instead of
in a new tab: @Firefox -> Edit -> Preferences -> Tabs -> New pages
should be opened in...@
@@ -154,14 +188,14 @@ escape = escapeURIString (\c -> isAlpha c || isDigit c || isMark c)
(Char -> Bool) -- a predicate which returns 'False' if should escape
-> String -- the string to process
-> String -- the resulting URI string
escapeURIString p s = concatMap (escapeURIChar p) s
escapeURIString = concatMap . escapeURIChar
escapeURIChar :: (Char->Bool) -> Char -> String
escapeURIChar p c
| p c = [c]
| otherwise = '%' : myShowHex (ord c) ""
where
myShowHex :: Int -> ShowS
myShowHex n r = case showIntAtBase 16 (toChrHex) n r of
myShowHex n r = case showIntAtBase 16 toChrHex n r of
[] -> "00"
[ch] -> ['0',ch]
cs -> cs
@@ -178,7 +212,7 @@ data SearchEngine = SearchEngine Name Site
-- | Given a browser, a search engine, and a search term, perform the
-- requested search in the browser.
search :: Browser -> Site -> Query -> X ()
search browser site query = safeSpawn browser (site ++ (escape query))
search browser site query = safeSpawn browser $ site ++ escape query
{- | Given a base URL, create the 'SearchEngine' that escapes the query and
appends it to the base. You can easily define a new engine locally using
@@ -193,17 +227,24 @@ search browser site query = safeSpawn browser (site ++ (escape query))
Generally, examining the resultant URL of a search will allow you to reverse-engineer
it if you can't find the necessary URL already described in other projects such as Surfraw. -}
searchEngine :: Name -> Site -> SearchEngine
searchEngine name site = SearchEngine name site
searchEngine = SearchEngine
-- The engines.
amazon, codesearch, dictionary, google, hoogle, imdb, maps, mathworld,
scholar, thesaurus, wayback, wikipedia, youtube :: SearchEngine
amazon, codesearch, deb, debbts, debpts, dictionary, google, hackage, hoogle, images,
imdb, isohunt, maps, mathworld, scholar, thesaurus, wayback, wikipedia,
youtube :: SearchEngine
amazon = searchEngine "amazon" "http://www.amazon.com/exec/obidos/external-search?index=all&keyword="
codesearch = searchEngine "codesearch" "http://www.google.com/codesearch?q="
deb = searchEngine "deb" "http://packages.debian.org/"
debbts = searchEngine "debbts" "http://bugs.debian.org/"
debpts = searchEngine "debpts" "http://packages.qa.debian.org/"
dictionary = searchEngine "dictionary" "http://dictionary.reference.com/browse/"
google = searchEngine "google" "http://www.google.com/search?num=100&q="
hackage = searchEngine "hackage" "http://hackage.haskell.org/cgi-bin/hackage-scripts/package/"
hoogle = searchEngine "hoogle" "http://www.haskell.org/hoogle/?q="
images = searchEngine "images" "http://images.google.fr/images?q="
imdb = searchEngine "imdb" "http://www.imdb.com/Find?select=all&for="
isohunt = searchEngine "isohunt" "http://isohunt.com/torrents/?ihq="
maps = searchEngine "maps" "http://maps.google.com/maps?q="
mathworld = searchEngine "mathworld" "http://mathworld.wolfram.com/search/?query="
scholar = searchEngine "scholar" "http://scholar.google.com/scholar?q="
@@ -219,7 +260,7 @@ wayback = searchEngine "wayback" "http://web.archive.org/"
Prompt's result, passes it to a given searchEngine and opens it in a given
browser. -}
promptSearchBrowser :: XPConfig -> Browser -> SearchEngine -> X ()
promptSearchBrowser config browser (SearchEngine name site) = mkXPrompt (Search name) config (historyCompletion) $ search browser site
promptSearchBrowser config browser (SearchEngine name site) = mkXPrompt (Search name) config historyCompletion $ search browser site
{- | Like 'search', but in this case, the string is not specified but grabbed
from the user's response to a prompt. Example:

77
XMonad/Actions/SpawnOn.hs Normal file
View File

@@ -0,0 +1,77 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.SpawnOn
-- Copyright : (c) Spencer Janssen
-- License : BSD
--
-- Maintainer : Spencer Janssen <spencerjanssen@gmail.com>
-- Stability : unstable
-- Portability : unportable
--
-- This module provides helper functions to be used in @manageHook@. Here's
-- how you might use this:
--
-- > import XMonad.Hooks.ManageHelpers
-- > main = do
-- > sp <- mkSpawner
-- > xmonad defaultConfig {
-- > ...
-- > manageHook = spawnHook sp <+> manageHook defaultConfig
-- > ...
-- > }
module XMonad.Actions.SpawnOn (
Spawner,
mkSpawner,
manageSpawn,
spawnHere,
spawnOn,
shellPromptHere,
shellPromptOn
) where
import Data.IORef
import System.Posix.Types (ProcessID)
import XMonad
import qualified XMonad.StackSet as W
import XMonad.Hooks.ManageHelpers
import XMonad.Prompt
import XMonad.Prompt.Shell
newtype Spawner = Spawner {pidsRef :: IORef [(ProcessID, WorkspaceId)]}
maxPids :: Int
maxPids = 5
mkSpawner :: (Functor m, MonadIO m) => m Spawner
mkSpawner = io . fmap Spawner $ newIORef []
manageSpawn :: Spawner -> ManageHook
manageSpawn sp = do
pids <- io . readIORef $ pidsRef sp
mp <- pid
case flip lookup pids =<< mp of
Just w -> doF (W.shift w)
Nothing -> doF id
mkPrompt :: (String -> X ()) -> XPConfig -> X ()
mkPrompt cb c = do
cmds <- io $ getCommands
mkXPrompt Shell c (getShellCompl cmds) cb
shellPromptHere :: Spawner -> XPConfig -> X ()
shellPromptHere sp = mkPrompt (spawnHere sp)
shellPromptOn :: Spawner -> WorkspaceId -> XPConfig -> X ()
shellPromptOn sp ws = mkPrompt (spawnOn sp ws)
spawnHere :: Spawner -> String -> X ()
spawnHere sp cmd = withWindowSet $ \ws -> spawnOn sp (currTag ws) cmd
where currTag = W.tag . W.workspace . W.current
spawnOn :: Spawner -> WorkspaceId -> String -> X ()
spawnOn sp ws cmd = do
p <- spawnPID cmd
io $ modifyIORef (pidsRef sp) (take maxPids . ((p, ws) :))

View File

@@ -48,7 +48,7 @@ import XMonad.Util.WorkspaceCompare
-- | Swaps the currently focused workspace with the given workspace tag, via
-- @swapWorkspaces@.
swapWithCurrent :: Eq i => i -> StackSet i l a s sd -> StackSet i l a s sd
swapWithCurrent t s = swapWorkspaces t (tag $ workspace $ current s) s
swapWithCurrent t s = swapWorkspaces t (currentTag s) s
-- | Say @swapTo Next@ or @swapTo Prev@ to move your current workspace.
-- This is an @X ()@ so can be hooked up to your keybindings directly.

View File

@@ -120,7 +120,7 @@ wsToList ws = crs ++ cls
wsToListGlobal :: (Ord i) => StackSet i l a s sd -> [a]
wsToListGlobal ws = concat ([crs] ++ rws ++ lws ++ [cls])
where
curtag = tag . workspace . current $ ws
curtag = currentTag ws
(crs, cls) = (cms down, cms (reverse . up))
cms f = maybe [] f (stack . workspace . current $ ws)
(lws, rws) = (mws (<), mws (>))
@@ -149,8 +149,7 @@ withTagged t f = withTagged' t (mapM_ f)
withTaggedGlobal t f = withTaggedGlobal' t (mapM_ f)
withTagged' :: String -> ([Window] -> X ()) -> X ()
withTagged' t m = gets windowset >>=
filterM (hasTag t) . integrate' . stack . workspace . current >>= m
withTagged' t m = gets windowset >>= filterM (hasTag t) . index >>= m
withTaggedGlobal' :: String -> ([Window] -> X ()) -> X ()
withTaggedGlobal' t m = gets windowset >>=
@@ -160,7 +159,7 @@ withFocusedP :: (Window -> WindowSet -> WindowSet) -> X ()
withFocusedP f = withFocused $ windows . f
shiftHere :: (Ord a, Eq s, Eq i) => a -> StackSet i l a s sd -> StackSet i l a s sd
shiftHere w s = shiftWin (tag . workspace . current $ s) w s
shiftHere w s = shiftWin (currentTag s) w s
shiftToScreen :: (Ord a, Eq s, Eq i) => s -> a -> StackSet i l a s sd -> StackSet i l a s sd
shiftToScreen sid w s = case filter (\m -> sid /= screen m) ((current s):(visible s)) of

View File

@@ -16,6 +16,7 @@ module XMonad.Actions.Warp (
-- * Usage
-- $usage
banish,
banishScreen,
Corner(..),
warpToScreen,
warpToWindow
@@ -49,7 +50,7 @@ Note that warping to a particular screen may change the focus.
data Corner = UpperLeft | UpperRight | LowerLeft | LowerRight
{- | Move the mouse cursor to a corner of the screen. Useful for
{- | Move the mouse cursor to a corner of the focused window. Useful for
uncluttering things.
Internally, this uses numerical parameters. We parametrize on the 'Corner'
@@ -64,7 +65,22 @@ banish direction = case direction of
LowerRight -> warpToWindow 1 1
LowerLeft -> warpToWindow 0 1
UpperLeft -> warpToWindow 0 0
UpperRight -> warpToWindow 1 0
UpperRight -> warpToWindow 1 0
{- | Same as 'banish' but moves the mouse to the corner of the
currently focused screen -}
banishScreen :: Corner -> X ()
banishScreen direction = case direction of
LowerRight -> warpToCurrentScreen 1 1
LowerLeft -> warpToCurrentScreen 0 1
UpperLeft -> warpToCurrentScreen 0 0
UpperRight -> warpToCurrentScreen 1 0
where
warpToCurrentScreen h v =
do ws <- gets windowset
warpToScreen (W.screen $ current ws) h v
windows (const ws)
fraction :: (Integral a, Integral b) => Rational -> a -> b
fraction f x = floor (f * fromIntegral x)

View File

@@ -15,11 +15,11 @@
-----------------------------------------------------------------------------
module XMonad.Actions.WindowBringer (
-- * Usage
-- $usage
gotoMenu, bringMenu, windowMap,
bringWindow
) where
-- * Usage
-- $usage
gotoMenu, gotoMenu', bringMenu, windowMap,
bringWindow
) where
import Data.Char (toLower)
import qualified Data.Map as M
@@ -27,7 +27,7 @@ import qualified Data.Map as M
import qualified XMonad.StackSet as W
import XMonad
import qualified XMonad as X
import XMonad.Util.Dmenu (dmenuMap)
import XMonad.Util.Dmenu (menuMap)
import XMonad.Util.NamedWindows (getName)
-- $usage
@@ -50,6 +50,9 @@ import XMonad.Util.NamedWindows (getName)
gotoMenu :: X ()
gotoMenu = actionMenu W.focusWindow
gotoMenu' :: String -> X ()
gotoMenu' menuCmd = actionMenu' menuCmd W.focusWindow
-- | Pops open a dmenu with window titles. Choose one, and it will be
-- dragged, kicking and screaming, into your current workspace.
bringMenu :: X ()
@@ -57,12 +60,18 @@ bringMenu = actionMenu bringWindow
-- | Brings the specified window into the current workspace.
bringWindow :: Window -> X.WindowSet -> X.WindowSet
bringWindow w ws = W.shiftWin (W.tag . W.workspace . W.current $ ws) w ws
bringWindow w ws = W.shiftWin (W.currentTag ws) w ws
-- | Calls dmenuMap to grab the appropriate Window, and hands it off to action
-- if found.
actionMenu :: (Window -> X.WindowSet -> X.WindowSet) -> X()
actionMenu action = windowMap >>= dmenuMap >>= flip X.whenJust (windows . action)
actionMenu action = actionMenu' "dmenu" action
actionMenu' :: String -> (Window -> X.WindowSet -> X.WindowSet) -> X()
actionMenu' menuCmd action = windowMap >>= menuMapFunction >>= flip X.whenJust (windows . action)
where
menuMapFunction :: M.Map String a -> X (Maybe a)
menuMapFunction selectionMap = menuMap menuCmd selectionMap
-- | A map from window names to Windows.
windowMap :: X (M.Map String Window)

View File

@@ -24,17 +24,22 @@ module XMonad.Actions.WindowGo (
raiseBrowser,
raiseEditor,
runOrRaiseAndDo,
runOrRaiseMaster,
raiseAndDo,
raiseMaster,
module XMonad.ManageHook
) where
import Control.Monad (filterM)
import Data.Char (toLower)
import XMonad (Query(), X(), withWindowSet, spawn, runQuery, liftIO, focus)
import XMonad (Query(), X(), withWindowSet, spawn, runQuery, liftIO)
import Graphics.X11 (Window)
import XMonad.ManageHook
import XMonad.Operations (windows)
import XMonad.Prompt.Shell (getBrowser, getEditor)
import qualified XMonad.StackSet as W (allWindows, peek)
import qualified XMonad.StackSet as W (allWindows, peek, swapMaster, focusWindow)
{- $usage
Import the module into your @~\/.xmonad\/xmonad.hs@:
@@ -57,7 +62,7 @@ For detailed instructions on editing your key bindings, see
-- | 'action' is an executable to be run via 'spawn' (of "XMonad.Core") if the Window cannot be found.
-- Presumably this executable is the same one that you were looking for.
runOrRaise :: String -> Query Bool -> X ()
runOrRaise action = raiseMaybe $ spawn action
runOrRaise = raiseMaybe . spawn
-- | See 'raiseMaybe'. If the Window can't be found, quietly give up and do nothing.
raise :: Query Bool -> X ()
@@ -94,11 +99,11 @@ raiseMaybe f thatUserQuery = withWindowSet $ \s -> do
maybeResult <- filterM (runQuery thatUserQuery) (W.allWindows s)
case maybeResult of
[] -> f
(x:_) -> focus x
(x:_) -> windows $ W.focusWindow x
-- | See 'runOrRaise' and 'raiseNextMaybe'. Version that allows cycling through matches.
runOrRaiseNext :: String -> Query Bool -> X ()
runOrRaiseNext action = raiseNextMaybe $ spawn action
runOrRaiseNext = raiseNextMaybe . spawn
-- | See 'raise' and 'raiseNextMaybe'. Version that allows cycling through matches.
raiseNext :: Query Bool -> X ()
@@ -116,10 +121,10 @@ raiseNextMaybe f thatUserQuery = withWindowSet $ \s -> do
case ws of
[] -> f
(x:_) -> let go (Just w) | (w `elem` ws) = next w $ cycle ws
go _ = focus x
go _ = windows $ W.focusWindow x
in go $ W.peek s
where
next w (x:y:_) | x==w = focus y
next w (x:y:_) | x==w = windows $ W.focusWindow y
next w (_:xs) = next w xs
next _ _ = error "raiseNextMaybe: empty list"
@@ -134,3 +139,34 @@ raiseVar getvar = liftIO getvar >>= \var -> runOrRaise var (fmap (map toLower) c
raiseBrowser, raiseEditor :: X ()
raiseBrowser = raiseVar getBrowser
raiseEditor = raiseVar getEditor
{- | if the window is found the window is focused and the third argument is called
otherwise, the first argument is called
See 'raiseMaster' for an example -}
raiseAndDo :: X () -> Query Bool -> (Window -> X ())-> X ()
raiseAndDo raisef thatUserQuery afterRaise = withWindowSet $ \s -> do
maybeResult <- filterM (runQuery thatUserQuery) (W.allWindows s)
case maybeResult of
[] -> raisef
(x:_) -> do windows $ W.focusWindow x
afterRaise x
{- | if the window is found the window is focused and the third argument is called
otherwise, raisef is called -}
runOrRaiseAndDo :: String -> Query Bool -> (Window -> X ()) -> X ()
runOrRaiseAndDo = raiseAndDo . spawn
{- | if the window is found the window is focused and set to master
otherwise, the first argument is called
raiseMaster (runInTerm \"-title ghci\" \"zsh -c \'ghci\'\") (title =? \"ghci\") -}
raiseMaster :: X () -> Query Bool -> X ()
raiseMaster raisef thatUserQuery = raiseAndDo raisef thatUserQuery (\_ -> windows W.swapMaster)
{- | if the window is found the window is focused and set to master
otherwise, action is run
runOrRaiseMaster \"firefox\" (className =? \"Firefox\"))
-}
runOrRaiseMaster :: String -> Query Bool -> X ()
runOrRaiseMaster run query = runOrRaiseAndDo run query (\_ -> windows W.swapMaster)

View File

@@ -153,7 +153,7 @@ currentPosition posRef = do
currentWindow <- gets (W.peek . windowset)
currentRect <- maybe (Rectangle 0 0 0 0) snd <$> windowRect (fromMaybe root currentWindow)
wsid <- gets (W.tag . W.workspace . W.current . windowset)
wsid <- gets (W.currentTag . windowset)
mp <- M.lookup wsid <$> io (readIORef posRef)
return $ maybe (middleOf currentRect) (`inside` currentRect) mp
@@ -162,7 +162,7 @@ currentPosition posRef = do
setPosition :: IORef WNState -> Point -> Rectangle -> X ()
setPosition posRef oldPos newRect = do
wsid <- gets (W.tag . W.workspace . W.current . windowset)
wsid <- gets (W.currentTag . windowset)
io $ modifyIORef posRef $ M.insert wsid (oldPos `inside` newRect)
inside :: Point -> Rectangle -> Point

46
XMonad/Config/Azerty.hs Normal file
View File

@@ -0,0 +1,46 @@
{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Config.Azerty
-- Copyright : (c) Devin Mullins <me@twifkak.com>
-- License : BSD
--
-- Maintainer : Devin Mullins <me@twifkak.com>
--
-- This module fixes some of the keybindings for the francophone among you who
-- use an AZERTY keyboard layout. Config stolen from TeXitoi's config on the
-- wiki.
module XMonad.Config.Azerty (
-- * Usage
-- $usage
azertyConfig, azertyKeys
) 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.Azerty
-- >
-- > main = xmonad azertyConfig
--
-- If you prefer, an azertyKeys function is provided which you can use as so:
--
-- > import qualified Data.Map as M
-- > main = xmonad someConfig { keys = \c -> azertyKeys c `M.union` keys someConfig c }
azertyConfig = defaultConfig { keys = \c -> azertyKeys c `M.union` keys defaultConfig c }
azertyKeys conf@(XConfig {modMask = modm}) = M.fromList $
[((modm, xK_semicolon), sendMessage (IncMasterN (-1)))]
++
[((m .|. modm, k), windows $ f i)
| (i, k) <- zip (workspaces conf) [0x26,0xe9,0x22,0x27,0x28,0x2d,0xe8,0x5f,0xe7,0xe0],
(f, m) <- [(W.greedyView, 0), (W.shift, shiftMask)]]

View File

@@ -12,8 +12,6 @@
-- environment such as KDE or GNOME.
module XMonad.Config.Desktop (
-- * Usage
-- -- $usage
desktopConfig,
desktopLayoutModifiers
) where

View File

@@ -176,7 +176,7 @@ instance UrgencyHook FocusUrgencyHook Window where
s { windowset = until ((Just w ==) . W.peek)
W.focusUp $ windowset s }
| otherwise =
let t = W.tag $ W.workspace $ W.current $ windowset s
let t = W.currentTag $ windowset s
in s { windowset = until ((Just w ==) . W.peek)
W.focusUp $ copyWindow w t $ windowset s }
has _ Nothing = False

View File

@@ -13,7 +13,7 @@
module XMonad.Config.Gnome (
-- * Usage
-- -- $usage
-- $usage
gnomeConfig,
gnomeRun
) where

View File

@@ -13,8 +13,9 @@
module XMonad.Config.Kde (
-- * Usage
-- -- $usage
kdeConfig
-- $usage
kdeConfig,
kde4Config
) where
import XMonad
@@ -29,13 +30,24 @@ import qualified Data.Map as M
-- > import XMonad.Config.Kde
-- >
-- > main = xmonad kdeConfig
--
-- For KDE 4, replace 'kdeConfig' with 'kde4Config'
--
kdeConfig = desktopConfig
{ terminal = "konsole"
, keys = \c -> kdeKeys c `M.union` keys desktopConfig c }
kde4Config = desktopConfig
{ terminal = "konsole"
, keys = \c -> kde4Keys c `M.union` keys desktopConfig c }
kdeKeys (XConfig {modMask = modm}) = M.fromList $
[ ((modm, xK_p), spawn "dcop kdesktop default popupExecuteCommand")
, ((modm .|. shiftMask, xK_q), spawn "dcop kdesktop default logout")
]
kde4Keys (XConfig {modMask = modm}) = M.fromList $
[ ((modm, xK_p), spawn "krunner")
, ((modm .|. shiftMask, xK_q), spawn "dbus-send --print-reply --dest=org.kde.ksmserver /KSMServer org.kde.KSMServerInterface.logout int32:1 int32:0 int32:1")
]

49
XMonad/Config/Monad.hs Normal file
View File

@@ -0,0 +1,49 @@
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-- experimental, not expected to work
{- our goal:
config = do
add layout Full
set terminal "urxvt"
add keys [blah blah blah]
-}
{-
ideas:
composability!
"only once" features like avoidStruts, ewmhDesktops
-}
module XMonad.Config.Monad where
import XMonad hiding (terminal, keys)
import qualified XMonad as X
import Control.Monad.Writer
import Data.Monoid
import Data.Accessor
import Data.Accessor.Basic hiding (set)
-- Ugly! To fix this we'll need to change the kind of XConfig.
newtype LayoutList a = LL [Layout a] deriving Monoid
type W = Dual (Endo (XConfig LayoutList))
mkW = Dual . Endo
newtype Config a = C (WriterT W IO a)
deriving (Functor, Monad, MonadWriter W)
-- references:
layout = fromSetGet (\x c -> c { layoutHook = x }) layoutHook
terminal = fromSetGet (\x c -> c { X.terminal = x }) X.terminal
keys = fromSetGet (\x c -> c { X.keys = x }) X.keys
set :: Accessor (XConfig LayoutList) a -> a -> Config ()
set r x = tell (mkW $ r ^= x)
add r x = tell (mkW (r ^: mappend x))
--
example :: Config ()
example = do
add layout $ LL [Layout $ Full] -- make this better
set terminal "urxvt"

View File

@@ -1,528 +0,0 @@
{-# LANGUAGE
FlexibleInstances,
FlexibleContexts,
MultiParamTypeClasses,
ExistentialQuantification
#-}
-------------------------------------------------------------------------
-- |
-- Module : XMonad.Config.PlainConfig
-- Copyright : Braden Shepherdson <Braden.Shepherdson@gmail.com>
-- License : BSD3
--
-- Maintainer : Braden Shepherdson <Braden.Shepherdson@gmail.com>
--
-- Proof-of-concept (but usable) plain-text configuration file
-- parser, for use instead of xmonad.hs. Does not require recompilation,
-- allowing xmonad to be free of the GHC dependency.
--
-------------------------------------------------------------------------
module XMonad.Config.PlainConfig
(
-- * Introduction
-- $usage
-- * Supported Layouts
-- $layouts
-- * Support Key Bindings
-- $keys
-- * Other Notes
-- $notes
-- * Example Config File
-- $example
plainConfig ,readConfig, checkConfig
)
where
import XMonad
import System.Exit
import qualified XMonad.StackSet as W
import qualified Data.Map as M
import Data.List
import Data.Maybe (isJust,fromJust)
import Data.Char (isSpace)
--import Control.Monad
import Control.Monad.Error
import Control.Monad.Identity
import Control.Arrow ((&&&))
import Text.ParserCombinators.ReadP
import System.IO
import Control.Exception (bracket)
import XMonad.Util.EZConfig (mkKeymap)
-- $usage
-- The @xmonad.hs@ file is very minimal when used with PlainConfig.
-- It typically contains only the following:
--
-- > module Main where
-- > import XMonad
-- > import XMonad.Config.PlainConfig (plainConfig)
-- > main = plainConfig
--
-- The 'plainConfig' function parses @~\/.xmonad\/xmonad.conf@,
-- the format of which is described below.
-- $layouts
-- Only 'Tall', 'Wide' and 'Full' are supported at present.
-- $keys
--
-- Key bindings are specified as a pair of an arbitrary EZConfig and
-- one of the following:
--
-- @ Name Haskell equivalent Default binding(s)@
--
-- * @spawn \<cmd\> spawn \"\<cmd\>\" none@
--
-- * @kill kill M-S-c@
--
-- * @nextLayout sendMessage NextLayout M-\<Space\>@
--
-- * @refresh refresh M-S-\<Space\>@
--
-- * @focusDown windows W.focusDown M-\<Tab\>, M-j@
--
-- * @focusUp windows W.focusUp M-k@
--
-- * @focusMaster windows W.focusMaster M-m@
--
-- * @swapDown windows W.swapDown M-S-j@
--
-- * @swapUp windows W.swapUp M-S-k@
--
-- * @swapMaster windows W.swapMaster M-\<Return\>@
--
-- * @shrink sendMessage Shrink M-h@
--
-- * @expand sendMessage Expand M-l@
--
-- * @sink withFocused $ windows . W.sink M-t@
--
-- * @incMaster sendMessage (IncMasterN 1) M-,@
--
-- * @decMaster sendMessage (IncMasterN (-1)) M-.@
--
-- * @quit io $ exitWith ExitSuccess M-S-q@
--
-- * @restart broadcastMessageReleaseResources >> restart \"xmonad\" True M-q@
--
-- $notes
-- Submaps are allowed.
-- These settings override the defaults. Changes made here will be used over
-- the default bindings for those keys.
-- $example
-- An example @~\/.xmonad\/xmonad.conf@ file follows:
--
-- @modMask = 3@
--
-- @numlockMask = 2@
--
-- @borderWidth = 1@
--
-- @normalBorderColor = #dddddd@
--
-- @focusedBorderColor = #00ff00@
--
-- @terminal=urxvt@
--
-- @workspaces=[\"1: IRC\",\"2: Web\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\"]@
--
-- @focusFollowsMouse=True@
--
-- @layouts=[\"Tall\",\"Full\",\"Wide\"]@
--
-- @key=(\"M-x t\", \"spawn xmessage Test\")@
--
-- @manageHook=(ClassName \"MPlayer\" , \"float\" )@
--
-- @manageHook=(ClassName \"Gimp\" , \"float\" )@
--
-- @manageHook=(Resource \"desktop_window\", \"ignore\" )@
--
-- @manageHook=(Resource \"kdesktop\" , \"ignore\" )@
--
-- @manageHook=(Resource \"gnome-panel\" , \"ignore\" )@
--
----------------------------------------------------------------
------ Several functions for parsing the key-value file. -------
----------------------------------------------------------------
parseKVBy :: Char -> ReadP (String,String)
parseKVBy sep = do
skipSpaces
k <- munch1 (\x -> x /= ' ' && x /= sep)
skipSpaces
char kvSep
skipSpaces
v <- munch1 (\x -> x /= ' ') --or EOS
return (k,v)
parseKVVBy :: Char -> ReadP (String,String)
parseKVVBy sep = do
skipSpaces
k <- munch1 (\x -> x /= ' ' && x /= sep)
skipSpaces
char kvSep
skipSpaces
v <- munch1 (const True) -- until EOS
return (k,v)
kvSep :: Char
kvSep = '='
parseKV, parseKVV :: ReadP (String,String)
parseKV = parseKVBy kvSep
parseKVV = parseKVVBy kvSep
readKV :: String -> Integer -> RC (String,String)
readKV s ln = case readP_to_S parseKV s of
[((k,v),"")] -> return (k,v) --single, correct parse
[] -> throwError [(ln,"No parse")]
_ -> do
case readP_to_S parseKVV s of
[((k,v),"")] -> return (k,v) --single, correct parse
[] -> throwError [(ln,"No parse")]
xs -> throwError [(ln,"Ambiguous parse: "
++ show xs)]
isComment :: String -> Bool
isComment = not . null . readP_to_S parseComment
where parseComment = skipSpaces >> char '#' >> return ()
-- null means failed parse, so _not_ a comment.
isBlank :: String -> Bool
isBlank = null . filter (not . isSpace)
type RC = ErrorT [(Integer,String)] Identity
instance Error [(Integer,String)] where
noMsg = [(-1, "Unknown error.")]
strMsg s = [(-1, s)]
parseFile :: [String] -> RC (XConfig Layout)
parseFile ss = parseLines baseConfig theLines
where theLines = filter (not . liftM2 (||) isComment isBlank . snd)
$ zip [1..] ss
parseLines :: XConfig Layout -> [(Integer,String)] -> RC (XConfig Layout)
parseLines = foldM parse
parse :: XConfig Layout -> (Integer, String) -> RC (XConfig Layout)
parse xc (ln,s) = do
(k,v) <- readKV s ln
case M.lookup k commands of
Nothing -> throwError [(ln,"Unknown command: "++k)]
Just f -> f v ln xc
----------------------------------------------------------------
-- Now the semantic parts, that convert from the relevant --
-- key-value entries to values in an XConfig --
----------------------------------------------------------------
type Command = String -> Integer -> XConfig Layout -> RC (XConfig Layout)
commands :: M.Map String Command
commands = M.fromList $
[("modMask" , cmd_modMask )
,("numlockMask" , cmd_numlockMask )
,("normalBorderColor" , cmd_normalBorderColor )
,("focusedBorderColor" , cmd_focusedBorderColor)
,("terminal" , cmd_terminal )
,("workspaces" , cmd_workspaces )
,("focusFollowsMouse" , cmd_focusFollowsMouse )
,("layouts" , cmd_layouts )
,("key" , cmd_key )
,("manageHook" , cmd_manageHook )
,("borderWidth" , cmd_borderWidth )
]
-- | Behind-the-scenes helper for both 'cmd_modMask' and 'cmd_numlockMask'.
genericModKey :: (KeyMask -> XConfig Layout) -> Command
genericModKey f s ln _ = do
x <- rcRead s ln :: RC Integer
case lookup x (zip [1..] [mod1Mask,mod2Mask,mod3Mask,mod4Mask,mod5Mask]) of
Just y -> return $ f y
Nothing -> throwError [(ln,"Invalid mod key number: "++ show x)]
-- | Reads the mod key modifier number.
cmd_modMask :: Command
cmd_modMask s ln xc = genericModKey (\k -> xc{modMask = k}) s ln xc
-- | Reads the numlock key modifier number.
cmd_numlockMask :: Command
cmd_numlockMask s ln xc = genericModKey (\k -> xc{numlockMask = k}) s ln xc
-- | Reads the border width.
cmd_borderWidth :: Command
cmd_borderWidth s ln xc = do
w <- rcRead s ln
return $ xc { borderWidth = w }
-- | Reads the colors but just keeps them as RRGGBB Strings.
cmd_normalBorderColor, cmd_focusedBorderColor :: Command
cmd_normalBorderColor s _ xc = return $ xc{ normalBorderColor = s }
cmd_focusedBorderColor s _ xc = return $ xc{ focusedBorderColor = s }
-- | Reads the terminal. It is just a String, no parsing.
cmd_terminal :: Command
cmd_terminal s _ xc = return $ xc{ terminal = s }
-- | Reads the workspace tag list. This is given as a Haskell [String].
cmd_workspaces :: Command
cmd_workspaces s ln xc = rcRead s ln >>= \x -> return xc{ workspaces = x }
-- | Reads the focusFollowsMouse, as a Haskell Bool.
cmd_focusFollowsMouse :: Command
cmd_focusFollowsMouse s ln xc = rcRead s ln >>=
\x -> return xc{focusFollowsMouse = x}
-- | The list known layouts, mapped by name.
-- An easy location for improvement is to add more contrib layouts here.
layouts :: M.Map String (Layout Window)
layouts = M.fromList
[("Tall", Layout (Tall 1 (3/100) (1/2)))
,("Wide", Layout (Mirror (Tall 1 (3/100) (1/2))))
,("Full", Layout Full)
]
-- | Expects a [String], the strings being layout names. Quotes required.
-- Draws from the `layouts' list above.
cmd_layouts :: Command
cmd_layouts s ln xc = do
xs <- rcRead s ln -- read the list of strings
let ls = map (id &&& (flip M.lookup) layouts) xs
when (null ls) $ throwError [(ln,"Empty layout list")]
case filter (not . isJust . snd) ls of
[] -> return $ xc{ layoutHook = foldr1
(\(Layout l) (Layout r) ->
Layout (l ||| r)) (map (fromJust . snd) ls)
}
ys -> throwError $ map (\(x,_) -> (ln, "Unknown layout: "++ x)) ys
-- | A Map from names to key binding actions.
key_actions :: M.Map String (X ())
key_actions = M.fromList
[("kill" , kill )
,("nextLayout" , sendMessage NextLayout )
--,("prevLayout" , sendMessage PrevLayout )
--,("resetLayout" , setLayout $ XMonad.layoutHook conf)
,("refresh" , refresh )
,("focusDown" , windows W.focusDown )
,("focusUp" , windows W.focusUp )
,("focusMaster" , windows W.focusMaster )
,("swapMaster" , windows W.swapMaster )
,("swapDown" , windows W.swapDown )
,("swapUp" , windows W.swapUp )
,("shrink" , sendMessage Shrink )
,("expand" , sendMessage Expand )
,("sink" , withFocused $ windows . W.sink)
,("incMaster" , sendMessage (IncMasterN 1))
,("decMaster" , sendMessage (IncMasterN (-1)))
,("quit" , io $ exitWith ExitSuccess)
,("restart" , broadcastMessage ReleaseResources
>> restart "xmonad" True)
]
-- | Expects keys as described in the preamble, as
-- (\"EZConfig key name\", \"action name\"),
-- eg. (\"M-S-t\", \"spawn thunderbird\")
-- One key per "key=" line.
cmd_key :: Command
cmd_key s ln xc = do
(k,v) <- rcRead s ln
if "spawn " `isPrefixOf` v
then return $ xc {
keys = \c -> M.union (mkKeymap c
[(k, spawn (drop 6 v))]
) ((keys xc) c)
}
else do
case M.lookup v key_actions of
Nothing -> throwError [(ln, "Unknown key action \"" ++ v ++ "\"")]
Just ac -> return $
xc { keys = \c -> M.union (mkKeymap c [(k, ac)])
((keys xc) c)
}
-- | Map of names to actions for 'ManageHook's.
manageHook_actions :: M.Map String ManageHook
manageHook_actions = M.fromList
[("float" , doFloat )
,("ignore" , doIgnore )
]
-- | Parses 'ManageHook's in the form given in the preamble.
-- eg. (ClassName \"MPlayer\", \"float\")
cmd_manageHook :: Command
cmd_manageHook s ln xc = do
(k,v) <- rcRead s ln
let q = parseQuery k
if "toWorkspace " `isPrefixOf` v
then return $ xc { manageHook = manageHook xc <+>
(q --> doShift (drop 12 v))
}
else case M.lookup v manageHook_actions of
Nothing -> throwError [(ln, "Unknown ManageHook action \""
++ v ++ "\"")]
Just ac -> return $ xc { manageHook = manageHook xc <+> (q --> ac) }
-- | Core of the ManageHook expression parser.
-- Taken from Roman Cheplyaka's WindowProperties
parseQuery :: Property -> Query Bool
parseQuery (Title s) = title =? s
parseQuery (ClassName s) = className =? s
parseQuery (Resource s) = resource =? s
parseQuery (And p q) = parseQuery p <&&> parseQuery q
parseQuery (Or p q) = parseQuery p <&&> parseQuery q
parseQuery (Not p) = not `fmap` parseQuery p
parseQuery (Const b) = return b
-- | Property constructors are quite self-explaining.
-- Taken from Roman Cheplyaka's WindowProperties
data Property = Title String
| ClassName String
| Resource String
| And Property Property
| Or Property Property
| Not Property
| Const Bool
deriving (Read, Show)
-- | A wrapping of the read function into the RC monad.
rcRead :: (Read a) => String -> Integer -> RC a
rcRead s ln = case reads s of
[(x,"")] -> return x
_ -> throwError [(ln, "Failed to parse value")]
-- | The standard Config.hs 'defaultConfig', with the layout wrapped.
baseConfig :: XConfig Layout
baseConfig = defaultConfig{ layoutHook = Layout (layoutHook defaultConfig) }
-- | Core function that attempts to parse @~\/.xmonad\/xmonad.conf@
readConfig :: IO (Maybe (XConfig Layout))
readConfig = do
dir <- getXMonadDir
cs <- bracket (openFile (dir++"/xmonad.conf") ReadMode)
(\h -> hClose h) -- vv force the lazy IO
(\h -> (lines `fmap` hGetContents h) >>= \ss ->
length ss `seq` return ss)
let xce = runIdentity $ runErrorT $ parseFile cs
case xce of
Left es -> mapM_ (\(ln,e) ->
putStrLn $ "readConfig error: line "++show ln++
": "++ e) es
>> return Nothing
Right xc -> return $ Just xc
-- | Attempts to run readConfig, and checks if it failed.
checkConfig :: IO Bool
checkConfig = isJust `fmap` readConfig
{- REMOVED: It was for debugging, and causes an 'orphaned instances'
warning to boot.
-- | Reads in the config, and then prints the resulting XConfig
dumpConfig :: IO ()
dumpConfig = readConfig >>= print
instance Show (XConfig Layout) where
show x = "XConfig { "
++ "normalBorderColor = "++ normalBorderColor x ++", "
++ "focusedBorderColor = "++ focusedBorderColor x++", "
++ "terminal = "++ terminal x ++", "
++ "workspaces = "++ show (workspaces x) ++", "
++ "numlockMask = "++ show (numlockMask x) ++", "
++ "modMask = "++ show (modMask x) ++", "
++ "borderWidth = "++ show (borderWidth x) ++", "
++ "focusFollowsMouse = "++ show (focusFollowsMouse x) ++", "
++ "layouts = "++ show (layoutHook x) ++" }"
-}
-- | Handles the unwrapping of the Layout. Intended for use as
-- @main = plainConfig@
plainConfig :: IO ()
plainConfig = do
conf <- readConfig
case conf of
(Just xc@XConfig{layoutHook= (Layout l)}) ->
xmonad (xc{ layoutHook = l })
Nothing ->
spawn $ "xmessage Failed to read xmonad.conf. See xmonad.errors."

View File

@@ -1,5 +1,5 @@
{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
module XMonad.Config.Sjanssen (sjanssenConfig) where
module XMonad.Config.Sjanssen (sjanssenConfig, sjanssenConfigXmobar) where
import XMonad hiding (Tall(..))
import qualified XMonad.StackSet as W
@@ -10,41 +10,49 @@ import XMonad.Config (defaultConfig)
import XMonad.Layout.NoBorders
import XMonad.Hooks.DynamicLog hiding (xmobar)
import XMonad.Hooks.ManageDocks
import XMonad.Hooks.EwmhDesktops
import XMonad.Prompt
import XMonad.Prompt.Shell
import XMonad.Util.Run (spawnPipe)
import XMonad.Actions.SpawnOn
import XMonad.Layout.LayoutScreens
import XMonad.Layout.TwoPane
import qualified Data.Map as M
import System.IO (hPutStrLn)
sjanssenConfigXmobar = statusBar "xmobar" sjanssenPP strutkey =<< sjanssenConfig
where
strutkey (XConfig {modMask = modm}) = (modm, xK_b)
sjanssenConfig = do
xmobar <- spawnPipe "xmobar"
sp <- mkSpawner
return $ defaultConfig
{ terminal = "urxvtc"
, workspaces = ["irc", "web"] ++ map show [3 .. 9 :: Int]
, logHook = dynamicLogWithPP $ sjanssenPP { ppOutput = hPutStrLn xmobar }
, 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 sp c `M.union` keys defaultConfig c
, layoutHook = modifiers layouts
, logHook = ewmhDesktopsLogHook
, manageHook = composeAll [className =? x --> doF (W.shift w)
| (x, w) <- [ ("Firefox", "web")
, ("Ktorrent", "7")]]
<+> manageHook defaultConfig <+> manageDocks
, ("Ktorrent", "7")
, ("Amarokapp", "7")]]
<+> manageHook defaultConfig <+> manageDocks <+> manageSpawn sp
}
where
tiled = HintedTile 1 0.03 0.5 TopLeft
layouts = (tiled Tall ||| (tiled Wide ||| Full)) ||| tabbed shrinkText myTheme
modifiers = avoidStruts . smartBorders
modifiers = smartBorders
mykeys (XConfig {modMask = modm, workspaces = ws}) = M.fromList $
[((modm, xK_p ), shellPrompt myPromptConfig)
mykeys sp (XConfig {modMask = modm, workspaces = ws}) = M.fromList $
[((modm, xK_p ), shellPromptHere sp myPromptConfig)
,((modm .|. shiftMask, xK_c ), kill1)
,((modm .|. shiftMask .|. controlMask, xK_c ), kill)
,((modm .|. shiftMask, xK_0 ), windows $ \w -> foldr copy w ws)
,((modm, xK_b ), sendMessage ToggleStruts)
,((modm, xK_z ), layoutScreens 2 $ TwoPane 0.5 0.5)
,((modm .|. shiftMask, xK_z ), rescreen)
]
myFont = "xft:Bitstream Vera Sans Mono:pixelsize=10"
@@ -52,4 +60,6 @@ sjanssenConfig = do
myPromptConfig = defaultXPConfig
{ position = Top
, font = myFont
, showCompletionOnTab = True
, historyFilter = deleteConsecutive
, promptBorderWidth = 0 }

View File

@@ -13,7 +13,7 @@
module XMonad.Config.Xfce (
-- * Usage
-- -- $usage
-- $usage
xfceConfig
) where

View File

@@ -490,6 +490,9 @@ A non complete list with a brief description:
workspaces in various ways, used by several other modules which need
to sort workspaces (e.g. "XMonad.Hooks.DynamicLog").
* "XMonad.Util.Paste" provides utilities for pasting or sending keys and
strings to windows;
* "XMonad.Util.XSelection" provide utilities for using the mouse
selection;

View File

@@ -1,3 +1,5 @@
{-# LANGUAGE FlexibleContexts #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Hooks.DynamicLog
@@ -23,15 +25,17 @@ module XMonad.Hooks.DynamicLog (
-- * Drop-in loggers
dzen,
xmobar,
statusBar,
dynamicLog,
dynamicLogDzen,
dynamicLogXmobar,
dynamicLogXinerama,
-- * Build your own formatter
dynamicLogWithPP,
dynamicLogString,
PP(..), defaultPP, dzenPP, xmobarPP, sjanssenPP, byorgeyPP,
PP(..), defaultPP,
-- * Example formatters
dzenPP, xmobarPP, sjanssenPP, byorgeyPP,
-- * Formatting utilities
wrap, pad, shorten,
@@ -50,6 +54,7 @@ module XMonad.Hooks.DynamicLog (
-- Useful imports
--
import XMonad
import Control.Monad
import Data.Maybe ( isJust, catMaybes )
import Data.List
import qualified Data.Map as M
@@ -72,21 +77,17 @@ import XMonad.Hooks.ManageDocks
-- > import XMonad.Hooks.DynamicLog
--
-- If you just want a quick-and-dirty status bar with zero effort, try
-- the 'dzen' function, which sets up a dzen status bar with a default
-- format:
-- the 'xmobar' or 'dzen' functions:
--
-- > main = dzen xmonad
-- > main = xmonad =<< xmobar conf
--
-- or, to use this with your own custom xmonad configuration,
-- 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
-- 'statusBar' functions are preferred over the other options listed below, as
-- they take care of all the necessary plumbing -- no shell scripting required!
--
-- > main = dzen $ \conf -> xmonad $ conf { <your customizations> }
--
-- Also you can use 'xmobar' function instead of 'dzen' in the examples above,
-- if you have xmobar installed.
--
-- Alternatively, you can choose among several default status bar
-- formats ('dynamicLog', 'dynamicLogDzen', 'dynamicLogXmobar', or
-- 'dynamicLogXinerama') by simply setting your logHook to the
-- Alternatively, you can choose among several default status bar formats
-- ('dynamicLog' or 'dynamicLogXinerama') by simply setting your logHook to the
-- appropriate function, for instance:
--
-- > main = xmonad $ defaultConfig {
@@ -139,69 +140,67 @@ import XMonad.Hooks.ManageDocks
------------------------------------------------------------------------
-- | Run xmonad with a dzen status bar set to some nice defaults. Output
-- is taken from the dynamicLogWithPP hook.
-- | Run xmonad with a dzen status bar set to some nice defaults.
--
-- > main = dzen xmonad
-- > main = xmonad =<< dzen conf
--
-- The intent is that the above config file should provide a nice
-- status bar with minimal effort. If you want to customize your xmonad
-- configuration while using this, you'll have to do something like
--
-- > main = dzen $ \conf -> xmonad $ conf { <your customized settings...> }
-- status bar with minimal effort.
--
-- If you wish to customize the status bar format at all, you'll have to
-- use something like 'dynamicLogWithPP' instead.
-- use the 'statusBar' function instead.
--
-- The binding uses the XMonad.Hooks.ManageDocks module to automatically
-- handle screen placement for dzen, and enables 'mod-b' for toggling
-- the menu bar.
--
dzen ::
(XConfig
(ModifiedLayout AvoidStruts
(Choose Tall (Choose (Mirror Tall) Full))) -> IO t) -> IO t
dzen f = do
h <- spawnPipe ("dzen2" ++ " " ++ flags)
f $ defaultConfig
{ logHook = dynamicLogWithPP dzenPP
{ ppOutput = hPutStrLn h }
,layoutHook = avoidStrutsOn [U] (layoutHook defaultConfig)
,keys = \c -> toggleStrutsKey c `M.union` keys defaultConfig c
,manageHook = manageHook defaultConfig <+> manageDocks
}
dzen :: LayoutClass l Window
=> XConfig l -> IO (XConfig (ModifiedLayout AvoidStruts l))
dzen conf = statusBar ("dzen2 " ++ flags) dzenPP toggleStrutsKey conf
where
fg = "'#a8a3f7'" -- n.b quoting
bg = "'#3f3c6d'"
flags = "-e 'onstart=lower' -w 400 -ta l -fg " ++ fg ++ " -bg " ++ bg
-- | Run xmonad with a xmobar status bar set to some nice defaults. Output
-- is taken from the dynamicLogWithPP hook.
-- | Run xmonad with a xmobar status bar set to some nice defaults.
--
-- > main = xmobar xmonad
-- > main = xmonad =<< xmobar conf
--
-- This works pretty much the same as 'dzen' function above
-- This works pretty much the same as 'dzen' function above.
--
xmobar ::
(XConfig
(ModifiedLayout AvoidStruts
(Choose Tall (Choose (Mirror Tall) Full))) -> IO t) -> IO t
xmobar f = do
h <- spawnPipe "xmobar"
f $ defaultConfig
{ logHook = dynamicLogWithPP xmobarPP { ppOutput = hPutStrLn h }
, layoutHook = avoidStruts $ layoutHook defaultConfig
, keys = \c -> toggleStrutsKey c `M.union` keys defaultConfig c
, manageHook = manageHook defaultConfig <+> manageDocks
}
xmobar :: LayoutClass l Window
=> XConfig l -> IO (XConfig (ModifiedLayout AvoidStruts l))
xmobar conf = statusBar "xmobar" xmobarPP toggleStrutsKey conf
-- | Modifies the given base configuration to launch the given status bar,
-- send status information to that bar, and allocate space on the screen edges
-- for the bar.
statusBar :: LayoutClass l Window
=> String -- ^ the command line to launch the status bar
-> PP -- ^ the pretty printing options
-> (XConfig Layout -> (KeyMask, KeySym))
-- ^ the desired key binding to toggle bar visibility
-> XConfig l -- ^ the base config
-> IO (XConfig (ModifiedLayout AvoidStruts l))
statusBar cmd pp k conf = do
h <- spawnPipe cmd
return $ conf
{ layoutHook = avoidStruts (layoutHook conf)
, logHook = do
logHook conf
dynamicLogWithPP pp { ppOutput = hPutStrLn h }
, manageHook = manageHook conf <+> manageDocks
, keys = liftM2 M.union keys' (keys conf)
}
where
keys' = (`M.singleton` sendMessage ToggleStruts) . k
-- |
-- Helper function which provides ToggleStruts keybinding
--
toggleStrutsKey :: XConfig t -> M.Map (KeyMask, KeySym) (X ())
toggleStrutsKey XConfig{modMask = modm} = M.fromList
[ ((modm, xK_b ), sendMessage ToggleStruts) ]
toggleStrutsKey :: XConfig t -> (KeyMask, KeySym)
toggleStrutsKey XConfig{modMask = modm} = (modm, xK_b )
------------------------------------------------------------------------
@@ -218,16 +217,6 @@ toggleStrutsKey XConfig{modMask = modm} = M.fromList
dynamicLog :: X ()
dynamicLog = dynamicLogWithPP defaultPP
-- | An example log hook that emulates dwm's status bar, using colour
-- codes printed to dzen. Requires dzen. Workspaces, xinerama,
-- layouts and the window title are handled.
dynamicLogDzen :: X ()
dynamicLogDzen = dynamicLogWithPP dzenPP
-- | These are good defaults to be used with the xmobar status bar.
dynamicLogXmobar :: X ()
dynamicLogXmobar = dynamicLogWithPP xmobarPP
-- | Format the current status using the supplied pretty-printing format,
-- and write it to stdout.
dynamicLogWithPP :: PP -> X ()
@@ -269,7 +258,7 @@ dynamicLogString pp = do
pprWindowSet :: WorkspaceSort -> [Window] -> PP -> WindowSet -> String
pprWindowSet sort' urgents pp s = sepBy (ppWsSep pp) . map fmt . sort' $
map S.workspace (S.current s : S.visible s) ++ S.hidden s
where this = S.tag (S.workspace (S.current s))
where this = S.currentTag s
visibles = map (S.tag . S.workspace) (S.visible s)
fmt w = printer pp (S.tag w)

View File

@@ -29,11 +29,10 @@ module XMonad.Hooks.EventHook
, HandleEvent
) where
import Control.Applicative ((<$>))
import Data.Maybe
import XMonad
import XMonad.StackSet (StackSet (..), Screen (..), Workspace (..))
import XMonad.StackSet (Workspace (..), currentTag)
-- $usage
-- You can use this module with the following in your
@@ -89,7 +88,7 @@ instance Message EventHandleMsg
instance (EventHook eh, LayoutClass l a) => LayoutClass (HandleEvent eh l) a where
runLayout (Workspace i (HandleEvent Nothing True eh l) ms) r = do
broadcastMessage HandlerOff
iws <- (tag . workspace . current) <$> gets windowset
iws <- gets (currentTag . windowset)
(wrs, ml) <- runLayout (Workspace i l ms) r
return (wrs, Just $ HandleEvent (Just iws) True eh (fromMaybe l ml))

View File

@@ -82,26 +82,28 @@ ewmhDesktopsLogHookCustom f = withWindowSet $ \s -> do
-- Names thereof
setDesktopNames (map W.tag ws)
-- Current desktop
let curr = fromJust $ elemIndex (W.tag (W.workspace (W.current s))) $ map W.tag ws
setCurrentDesktop curr
-- all windows, with focused windows last
let wins = nub . concatMap (maybe [] (\(W.Stack x l r)-> reverse l ++ r ++ [x]) . W.stack) $ ws
setClientList wins
-- Per window Desktop
-- To make gnome-panel accept our xinerama stuff, we display
-- all visible windows on the current desktop.
forM_ (W.current s : W.visible s) $ \x ->
forM_ (W.integrate' (W.stack (W.workspace x))) $ \win -> do
setWindowDesktop win curr
-- Current desktop
case (elemIndex (W.currentTag s) $ map W.tag ws) of
Nothing -> return ()
Just curr -> do
setCurrentDesktop curr
-- Per window Desktop
-- To make gnome-panel accept our xinerama stuff, we display
-- all visible windows on the current desktop.
forM_ (W.current s : W.visible s) $ \x ->
forM_ (W.integrate' (W.stack (W.workspace x))) $ \win -> do
setWindowDesktop win curr
forM_ (W.hidden s) $ \w ->
let wn = fromJust $ elemIndex (W.tag w) (map W.tag ws) in
forM_ (W.integrate' (W.stack w)) $ \win -> do
setWindowDesktop win wn
case elemIndex (W.tag w) (map W.tag ws) of
Nothing -> return ()
Just wn -> forM_ (W.integrate' (W.stack w)) $ \win -> do
setWindowDesktop win wn
setActiveWindow
@@ -138,6 +140,7 @@ handle ClientMessageEvent {
a_d <- getAtom "_NET_WM_DESKTOP"
a_aw <- getAtom "_NET_ACTIVE_WINDOW"
a_cw <- getAtom "_NET_CLOSE_WINDOW"
a_ignore <- mapM getAtom ["XMONAD_TIMER"]
if mt == a_cd then do
let n = fromIntegral (head d)
if 0 <= n && n < length ws then
@@ -151,8 +154,9 @@ handle ClientMessageEvent {
else if mt == a_aw then do
windows $ W.focusWindow w
else if mt == a_cw then do
windows $ W.focusWindow w
kill
killWindow w
else if mt `elem` a_ignore then do
return ()
else trace $ "Unknown ClientMessageEvent " ++ show mt
handle _ = undefined -- does not happen, as otherwise ewmhDesktopsHook would not match

View File

@@ -15,6 +15,7 @@
module XMonad.Hooks.FadeInactive (
-- * Usage
-- $usage
setOpacity,
fadeInactiveLogHook
) where
@@ -68,8 +69,9 @@ fadeIn = flip setOpacity 0xffffffff
-- lowers the opacity of inactive windows to the specified amount
fadeInactiveLogHook :: Integer -> X ()
fadeInactiveLogHook amt = withWindowSet $ \s ->
forM_ (concatMap visibleWins $ W.current s : W.visible s) (fadeOut amt) >>
forM_ (visibleWins s) (fadeOut amt) >>
withFocused fadeIn
where
visibleWins = maybe [] unfocused . W.stack . W.workspace
visibleWins s = (maybe [] unfocused . W.stack . W.workspace) (W.current s) ++
concatMap (W.integrate' . W.stack . W.workspace) (W.visible s)
unfocused (W.Stack _ l r) = l ++ r

View File

@@ -25,10 +25,13 @@
-- > }
module XMonad.Hooks.ManageHelpers (
Side(..),
composeOne,
(-?>), (/=?), (<==?), (</=?), (-->>), (-?>>),
isKDETrayWindow,
isFullscreen,
isDialog,
pid,
transientTo,
maybeToDefinite,
MaybeManageHook,
@@ -36,7 +39,9 @@ module XMonad.Hooks.ManageHelpers (
transience',
doRectFloat,
doFullFloat,
doCenterFloat
doCenterFloat,
doSideFloat,
doHideIgnore
) where
import XMonad
@@ -45,6 +50,13 @@ import qualified XMonad.StackSet as W
import Data.Maybe
import Data.Monoid
import System.Posix (ProcessID)
-- | Denotes a side of a screen. @S@ stands for South, @NE@ for Northwest
-- etc. @C@ stands for Center.
data Side = SC | NC | CE | CW | SE | SW | NE | NW | C
deriving (Read, Show, Eq)
-- | A ManageHook that may or may not have been executed; the outcome is embedded in the Maybe
type MaybeManageHook = Query (Maybe (Endo WindowSet))
-- | A grouping type, which can hold the outcome of a predicate Query.
@@ -124,6 +136,26 @@ isFullscreen = ask >>= \w -> liftX $ do
Just xs -> fromIntegral full `elem` xs
_ -> False
-- | A predicate to check whether a window is a dialog.
isDialog :: Query Bool
isDialog = ask >>= \w -> liftX $ do
dpy <- asks display
w_type <- getAtom "_NET_WM_WINDOW_TYPE"
w_dialog <- getAtom "_NET_WM_WINDOW_TYPE_DIALOG"
r <- io $ getWindowProperty32 dpy w_type w
return $ case r of
Just xs -> fromIntegral w_dialog `elem` xs
_ -> False
pid :: Query (Maybe ProcessID)
pid = ask >>= \w -> liftX $ do
dpy <- asks display
a <- getAtom "_NET_WM_PID"
p <- io $ getWindowProperty32 dpy a w
return $ case p of
Just [x] -> Just (fromIntegral x)
_ -> Nothing
-- | A predicate to check whether a window is Transient.
-- It holds the result which might be the window it is transient to
-- or it might be 'Nothing'.
@@ -160,8 +192,24 @@ doRectFloat r = ask >>= \w -> doF (W.float w r)
doFullFloat :: ManageHook
doFullFloat = doRectFloat $ W.RationalRect 0 0 1 1
-- | Floats a new window with its original size on the specified side of a
-- screen
doSideFloat :: Side -> ManageHook
doSideFloat side = ask >>= \w -> doF . W.float w . move . snd =<< liftX (floatLocation w)
where
move (W.RationalRect _ _ w h) = W.RationalRect cx cy w h
where
cx = if side `elem` [SC,C ,NC] then (1-w)/2
else if side `elem` [SW,CW,NW] then 0
else {- side `elem` [SE,CE,NE] -} 1-w
cy = if side `elem` [CE,C ,CW] then (1-h)/2
else if side `elem` [NE,NC,NW] then 0
else {- side `elem` [SE,SC,SW] -} 1-h
-- | Floats a new window with its original size, but centered.
doCenterFloat :: ManageHook
doCenterFloat = ask >>= \w -> doF . W.float w . center . snd =<< liftX (floatLocation w)
where
center (W.RationalRect _ _ w h) = W.RationalRect ((1-w)/2) ((1-h)/2) w h
doCenterFloat = doSideFloat C
-- | Hides window and ignores it.
doHideIgnore :: ManageHook
doHideIgnore = ask >>= \w -> liftX (hide w) >> doF (W.delete w)

View File

@@ -53,12 +53,13 @@ module XMonad.Hooks.UrgencyHook (
-- * Stuff for your config file:
withUrgencyHook, withUrgencyHookC,
UrgencyConfig(..), urgencyConfig,
SuppressWhen(..),
focusUrgent,
SuppressWhen(..), RemindWhen(..),
focusUrgent, clearUrgents,
dzenUrgencyHook,
DzenUrgencyHook(..), seconds,
DzenUrgencyHook(..),
NoUrgencyHook(..),
FocusHook(..),
minutes, seconds,
-- * Stuff for developers:
readUrgents, withUrgents,
StdoutUrgencyHook(..),
@@ -72,12 +73,13 @@ import qualified XMonad.StackSet as W
import XMonad.Hooks.EventHook
import XMonad.Util.Dzen (dzenWithArgs, seconds)
import XMonad.Util.NamedWindows (getName)
import XMonad.Util.Timer (TimerId, startTimer, handleTimer)
import Control.Applicative ((<$>))
import Control.Monad (when)
import Data.Bits (testBit)
import Data.IORef
import Data.List ((\\), delete)
import Data.List (delete)
import Data.Maybe (listToMaybe, maybeToList)
import qualified Data.Set as S
import Foreign (unsafePerformIO)
@@ -193,19 +195,18 @@ import Foreign (unsafePerformIO)
-- Hopefully you already read the section on how to configure xmonad. If not,
-- hopefully you know where to find it.
-- | This is the method to enable an urgency hook. It suppresses urgency status
-- for windows that are currently visible. If you'd like to change that behavior,
-- use 'withUrgencyHookC'.
-- | This is the method to enable an urgency hook. It uses the default
-- 'urgencyConfig' to control behavior. To change this, use 'withUrgencyHook'
-- instead.
withUrgencyHook :: (LayoutClass l Window, UrgencyHook h) =>
h -> XConfig l -> XConfig (HandleEvent (WithUrgencyHook h) l)
withUrgencyHook hook conf = withUrgencyHookC hook urgencyConfig conf
-- | If you'd like to configure *when* to trigger the urgency hook, call this
-- function with a custom 'UrgencyConfig'. Or, by example:
-- | This lets you modify the defaults set in 'urgencyConfig'. An example:
--
-- > withUrgencyHookC dzenUrgencyHook { ... } urgencyConfig { suppressWhen = Focused }
--
-- (Don't type the @...@, you dolt.) See documentation on your options at 'SuppressWhen'.
-- (Don't type the @...@, you dolt.) See 'UrgencyConfig' for details on configuration.
withUrgencyHookC :: (LayoutClass l Window, UrgencyHook h) =>
h -> UrgencyConfig -> XConfig l -> XConfig (HandleEvent (WithUrgencyHook h) l)
withUrgencyHookC hook urgConf conf = conf {
@@ -213,16 +214,13 @@ withUrgencyHookC hook urgConf conf = conf {
logHook = cleanupUrgents (suppressWhen urgConf) >> logHook conf
}
-- | Global configuration, applicable to all types of 'UrgencyHook'.
-- | Global configuration, applied to all types of 'UrgencyHook'. See
-- 'urgencyConfig' for the defaults.
data UrgencyConfig = UrgencyConfig
{ suppressWhen :: SuppressWhen -- ^ see 'SuppressWhen' for options
{ suppressWhen :: SuppressWhen -- ^ when to trigger the urgency hook
, remindWhen :: RemindWhen -- ^ when to re-trigger the urgency hook
} deriving (Read, Show)
-- | The default 'UrgencyConfig'. Use a variation of this in your config just
-- as you use a variation of defaultConfig for your xmonad definition.
urgencyConfig :: UrgencyConfig
urgencyConfig = UrgencyConfig { suppressWhen = Visible }
-- | A set of choices as to /when/ you should (or rather, shouldn't) be notified of an urgent window.
-- The default is 'Visible'. Prefix each of the following with \"don't bug me when\":
data SuppressWhen = Visible -- ^ the window is currently visible
@@ -231,6 +229,26 @@ data SuppressWhen = Visible -- ^ the window is currently visible
| Never -- ^ ... aww, heck, go ahead and bug me, just in case.
deriving (Read, Show)
-- | A set of choices as to when you want to be re-notified of an urgent
-- window. Perhaps you focused on something and you miss the dzen popup bar. Or
-- you're AFK. Or you feel the need to be more distracted. I don't care.
--
-- The interval arguments are in seconds. See the 'minutes' helper.
data RemindWhen = Dont -- ^ triggering once is enough
| Repeatedly Int Interval -- ^ repeat <arg1> times every <arg2> seconds
| Every Interval -- ^ repeat every <arg1> until the urgency hint is cleared
deriving (Read, Show)
-- | A prettified way of multiplying by 60. Use like: @(5 `minutes`)@.
minutes :: Rational -> Rational
minutes secs = secs * 60
-- | 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.
urgencyConfig :: UrgencyConfig
urgencyConfig = UrgencyConfig { suppressWhen = Visible, remindWhen = Dont }
-- | Focuses the most recently urgent window. Good for what ails ya -- I mean, your keybindings.
-- Example keybinding:
--
@@ -238,6 +256,13 @@ data SuppressWhen = Visible -- ^ the window is currently visible
focusUrgent :: X ()
focusUrgent = withUrgents $ flip whenJust (windows . W.focusWindow) . listToMaybe
-- | Just makes the urgents go away.
-- Example keybinding:
--
-- > , ((modMask .|. shiftMask, xK_BackSpace), clearUrgents)
clearUrgents :: X ()
clearUrgents = adjustUrgents (const []) >> adjustReminders (const [])
-- | Stores the global set of all urgent windows, across workspaces. Not exported -- use
-- 'readUrgents' or 'withUrgents' instead.
{-# NOINLINE urgents #-}
@@ -255,7 +280,35 @@ readUrgents = io $ readIORef urgents
withUrgents :: ([Window] -> X a) -> X a
withUrgents f = readUrgents >>= f
data WithUrgencyHook h = WithUrgencyHook h UrgencyConfig deriving (Read, Show)
adjustUrgents :: ([Window] -> [Window]) -> X ()
adjustUrgents f = io $ modifyIORef urgents f
type Interval = Rational
-- | An urgency reminder, as reified for 'RemindWhen'.
-- The last value is the countdown number, for 'Repeatedly'.
data Reminder = Reminder { timer :: TimerId
, window :: Window
, interval :: Interval
, remaining :: Maybe Int
} deriving Eq
-- | Stores the list of urgency reminders.
{-# NOINLINE reminders #-}
reminders :: IORef [Reminder]
reminders = unsafePerformIO (newIORef [])
readReminders :: X [Reminder]
readReminders = io $ readIORef reminders
adjustReminders :: ([Reminder] -> [Reminder]) -> X ()
adjustReminders f = io $ modifyIORef reminders f
clearUrgency :: Window -> X ()
clearUrgency w = adjustUrgents (delete w) >> adjustReminders (filter $ (w /=) . window)
data WithUrgencyHook h = WithUrgencyHook h UrgencyConfig
deriving (Read, Show)
-- The Non-ICCCM Manifesto:
-- Note: Some non-standard choices have been made in this implementation to
@@ -270,41 +323,53 @@ data WithUrgencyHook h = WithUrgencyHook h UrgencyConfig deriving (Read, Show)
-- set urgency if a window is visible. If you have a better idea, please, let us
-- know!
instance UrgencyHook h => EventHook (WithUrgencyHook h) where
handleEvent wuh event =
case event of
handleEvent wuh event = case event of
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
-- Add to list of urgents.
adjustUrgents (\ws -> if elem w ws then ws else w : ws)
-- Call the urgencyHook.
callUrgencyHook wuh w
else do
-- Remove from list of urgents.
adjustUrgents (delete w)
-- Call logHook after IORef has been modified.
userCode =<< asks (logHook . config)
DestroyWindowEvent {ev_window = w} -> do
adjustUrgents (delete w)
else
clearUrgency w
userCodeDef () =<< asks (logHook . config) -- call *after* IORef has been modified
DestroyWindowEvent {ev_window = w} ->
clearUrgency w
_ ->
return ()
adjustUrgents :: ([Window] -> [Window]) -> X ()
adjustUrgents f = io $ modifyIORef urgents f
mapM_ handleReminder =<< readReminders
where handleReminder reminder = handleTimer (timer reminder) event $ reminderHook wuh reminder
callUrgencyHook :: UrgencyHook h => WithUrgencyHook h -> Window -> X ()
callUrgencyHook (WithUrgencyHook hook UrgencyConfig { suppressWhen = sw }) w =
whenX (not <$> shouldSuppress sw w)
(userCode $ urgencyHook hook w)
callUrgencyHook (WithUrgencyHook hook UrgencyConfig { suppressWhen = sw, remindWhen = rw }) w =
whenX (not <$> shouldSuppress sw w) $ do
userCodeDef () $ urgencyHook hook w
case rw of
Repeatedly times int -> addReminder w int $ Just times
Every int -> addReminder w int Nothing
Dont -> return ()
addReminder :: Window -> Rational -> Maybe Int -> X ()
addReminder w int times = do
timerId <- startTimer int
let reminder = Reminder timerId w int times
adjustReminders (\rs -> if w `elem` map window rs then rs else reminder : rs)
reminderHook :: UrgencyHook h => WithUrgencyHook h -> Reminder -> X (Maybe a)
reminderHook (WithUrgencyHook hook _) reminder = do
case remaining reminder of
Just x | x > 0 -> remind $ Just (x - 1)
Just _ -> adjustReminders $ delete reminder
Nothing -> remind Nothing
return Nothing
where remind remaining' = do userCode $ urgencyHook hook (window reminder)
adjustReminders $ delete reminder
addReminder (window reminder) (interval reminder) remaining'
shouldSuppress :: SuppressWhen -> Window -> X Bool
shouldSuppress sw w = elem w <$> suppressibleWindows sw
cleanupUrgents :: SuppressWhen -> X ()
cleanupUrgents sw = do
suppressibles <- suppressibleWindows sw
adjustUrgents (\\ suppressibles)
cleanupUrgents sw = mapM_ clearUrgency =<< suppressibleWindows sw
suppressibleWindows :: SuppressWhen -> X [Window]
suppressibleWindows Visible = gets $ S.toList . mapped
@@ -356,7 +421,7 @@ instance UrgencyHook FocusHook where
-- Defaults to a duration of five seconds, and no extra args to dzen.
-- See 'DzenUrgencyHook'.
dzenUrgencyHook :: DzenUrgencyHook
dzenUrgencyHook = DzenUrgencyHook { duration = (5 `seconds`), args = [] }
dzenUrgencyHook = DzenUrgencyHook { duration = seconds 5, args = [] }
-- | Spawn a commandline thing, appending the window id to the prefix string
-- you provide. (Make sure to add a space if you need it.) Do your crazy

View File

@@ -0,0 +1,110 @@
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, TypeSynonymInstances #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Layout.CenteredMaster
-- Copyright : (c) 2009 Ilya Portnov
-- License : GNU GPL v3 or any later
--
-- Maintainer : Ilya Portnov <portnov84@rambler.ru>
-- Stability : unstable
-- Portability : unportable
--
-- Two layout modifiers. centerMaster places master window at center,
-- on top of all other windows, which are managed by base layout.
-- topRightMaster is similar, but places master window in top right corner
-- instead of center.
--
-----------------------------------------------------------------------------
module XMonad.Layout.CenteredMaster (
-- * Usage
-- $usage
centerMaster,
topRightMaster
) where
import XMonad
import XMonad.Layout.LayoutModifier
import qualified XMonad.StackSet as W
-- $usage
-- This module defines two new layout modifiers: centerMaster and topRightMaster.
-- centerMaster places master window at center of screen, on top of others.
-- All other windows in background are managed by base layout.
-- topRightMaster is like centerMaster, but places master window in top right corner instead of center.
--
-- Yo can use this module by adding folowing in your @xmonad.hs@:
--
-- > import XMonad.Layout.CenteredMaster
--
-- Then add layouts to your layoutHook:
--
-- > myLayoutHook = centerMaster Grid ||| ...
-- | Function that decides where master window should be placed
type Positioner = Rectangle -> Rectangle
-- | Data type for LayoutModifier
data CenteredMaster a = CenteredMaster deriving (Read,Show)
instance LayoutModifier CenteredMaster Window where
modifyLayout CenteredMaster = applyPosition (center (5/7) (5/7))
data TopRightMaster a = TopRightMaster deriving (Read,Show)
instance LayoutModifier TopRightMaster Window where
modifyLayout TopRightMaster = applyPosition (topRight (3/7) (1/2))
-- | Modifier that puts master window in center, other windows in background
-- are managed by given layout
centerMaster :: LayoutClass l a => l a -> ModifiedLayout CenteredMaster l a
centerMaster = ModifiedLayout CenteredMaster
-- | Modifier that puts master window in top right corner, other windows in background
-- are managed by given layout
topRightMaster :: LayoutClass l a => l a -> ModifiedLayout TopRightMaster l a
topRightMaster = ModifiedLayout TopRightMaster
-- | Internal function, doing main job
applyPosition :: (LayoutClass l a, Eq a) =>
Positioner
-> W.Workspace WorkspaceId (l a) a
-> Rectangle
-> X ([(a, Rectangle)], Maybe (l a))
applyPosition pos wksp rect = do
let stack = W.stack wksp
let ws = W.integrate' $ stack
if null ws then
runLayout wksp rect
else do
let first = head ws
let other = tail ws
let filtStack = stack >>= W.filter (first /=)
wrs <- runLayout (wksp {W.stack = filtStack}) rect
return ((first, place pos other rect) : fst wrs, snd wrs)
-- | Place master window (it's Rectangle is given), using the given Positioner.
-- If second argument is empty (that is, there is only one window on workspace),
-- place that window fullscreen.
place :: Positioner -> [a] -> Rectangle -> Rectangle
place _ [] rect = rect
place pos _ rect = pos rect
-- | Function that calculates Rectangle at top right corner of given Rectangle
topRight :: Float -> Float -> Rectangle -> Rectangle
topRight rx ry (Rectangle sx sy sw sh) = Rectangle x sy w h
where w = round (fromIntegral sw * rx)
h = round (fromIntegral sh * ry)
x = sx + fromIntegral (sw-w)
-- | Function that calculates Rectangle at center of given Rectangle.
center :: Float -> Float -> Rectangle -> Rectangle
center rx ry (Rectangle sx sy sw sh) = Rectangle x y w h
where w = round (fromIntegral sw * rx)
h = round (fromIntegral sh * ry)
x = sx + fromIntegral (sw-w) `div` 2
y = sy + fromIntegral (sh-h) `div` 2

View File

@@ -24,7 +24,7 @@ module XMonad.Layout.Decoration
, DecorationStyle (..)
, DefaultDecoration (..)
, Shrinker (..), DefaultShrinker
, shrinkText, CustomShrink ( CustomShrink )
, shrinkText, CustomShrink ( CustomShrink ), shrinkWhile
, isInStack, isVisible, isInvisible, isWithin, fi
, module XMonad.Layout.LayoutModifier
) where
@@ -201,7 +201,12 @@ instance Eq a => DecorationStyle DefaultDecoration a
-- 'handleEvent', which will call the appropriate 'DecorationStyle'
-- methods to perform its tasks.
instance (DecorationStyle ds Window, Shrinker s) => LayoutModifier (Decoration ds s) Window where
redoLayout (Decoration st sh t ds) sc stack wrs
redoLayout (Decoration (I (Just s)) sh t ds) _ Nothing _ = do
releaseResources s
return ([], Just $ Decoration (I Nothing) sh t ds)
redoLayout _ _ Nothing _ = return ([], Nothing)
redoLayout (Decoration st sh t ds) sc (Just stack) wrs
| I Nothing <- st = initState t ds sc stack wrs >>= processState
| I (Just s) <- st = do let dwrs = decos s
(d,a) = curry diff (get_ws dwrs) ws
@@ -264,11 +269,6 @@ instance (DecorationStyle ds Window, Shrinker s) => LayoutModifier (Decoration d
return $ Just $ Decoration (I Nothing) sh t ds
handleMess _ _ = return Nothing
emptyLayoutMod (Decoration (I (Just s)) sh t ds) _ _ = do
releaseResources s
return ([], Just $ Decoration (I Nothing) sh t ds)
emptyLayoutMod _ _ _ = return ([], Nothing)
modifierDescription (Decoration _ _ _ ds) = describeDeco ds
-- | By default 'Decoration' handles 'PropertyEvent' and 'ExposeEvent'

View File

@@ -0,0 +1,91 @@
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, TypeSynonymInstances #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Layout.FixedColumn
-- Copyright : (c) 2008 Justin Bogner <mail@justinbogner.com>
-- License : BSD3-style (as xmonad)
--
-- Maintainer : Justin Bogner <mail@justinbogner.com>
-- Stability : unstable
-- Portability : unportable
--
-- A layout much like Tall, but using a multiple of a window's minimum
-- resize amount instead of a percentage of screen to decide where to
-- split. This is useful when you usually leave a text editor or
-- terminal in the master pane and like it to be 80 columns wide.
--
-----------------------------------------------------------------------------
module XMonad.Layout.FixedColumn (
-- * Usage
-- $usage
FixedColumn(..)
) where
import Control.Monad (msum)
import Data.Maybe (fromMaybe)
import Graphics.X11.Xlib (Window, rect_width)
import Graphics.X11.Xlib.Extras ( getWMNormalHints
, getWindowAttributes
, sh_base_size
, sh_resize_inc
, wa_border_width)
import XMonad.Core (X, LayoutClass(..), fromMessage, io, withDisplay)
import XMonad.Layout (Resize(..), IncMasterN(..), tile)
import XMonad.StackSet as W
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
--
-- > import XMonad.Layout.FixedColumn
--
-- Then edit your @layoutHook@ by adding the FixedColumn layout:
--
-- > myLayouts = FixedColumn 20 80 10 ||| Full ||| etc..
-- > main = xmonad defaultConfig { layoutHook = myLayouts }
--
-- For more detailed instructions on editing the layoutHook see:
--
-- "XMonad.Doc.Extending#Editing_the_layout_hook"
-- | A tiling mode based on preserving a nice fixed width
-- window. Supports 'Shrink', 'Expand' and 'IncMasterN'.
data FixedColumn a = FixedColumn !Int -- Number of windows in the master pane
!Int -- Number to increment by when resizing
!Int -- Default width of master pane
!Int -- Column width for normal windows
deriving (Read, Show)
instance LayoutClass FixedColumn Window where
doLayout (FixedColumn nmaster _ ncol fallback) r s = do
fws <- mapM (widthCols fallback ncol) ws
let frac = maximum (take nmaster fws) // rect_width r
rs = tile frac r nmaster (length ws)
return $ (zip ws rs, Nothing)
where ws = W.integrate s
x // y = fromIntegral x / fromIntegral y
pureMessage (FixedColumn nmaster delta ncol fallback) m =
msum [fmap resize (fromMessage m)
,fmap incmastern (fromMessage m)]
where resize Shrink
= FixedColumn nmaster delta (max 0 $ ncol - delta) fallback
resize Expand
= FixedColumn nmaster delta (ncol + delta) fallback
incmastern (IncMasterN d)
= FixedColumn (max 0 (nmaster+d)) delta ncol fallback
description _ = "FixedColumn"
-- | Determine the width of @w@ given that we would like it to be @n@
-- columns wide, using @inc@ as a resize increment for windows that
-- don't have one
widthCols :: Int -> Int -> Window -> X Int
widthCols inc n w = withDisplay $ \d -> io $ do
sh <- getWMNormalHints d w
bw <- fmap (fromIntegral . wa_border_width) $ getWindowAttributes d w
let widthHint f = f sh >>= return . fromIntegral . fst
oneCol = fromMaybe inc $ widthHint sh_resize_inc
base = fromMaybe 0 $ widthHint sh_base_size
return $ 2 * bw + base + n * oneCol

View File

@@ -17,7 +17,7 @@
module XMonad.Layout.Grid (
-- * Usage
-- $usage
Grid(..), arrange
Grid(..), arrange, defaultRatio
) where
import XMonad
@@ -33,21 +33,31 @@ import XMonad.StackSet
-- > myLayouts = Grid ||| Full ||| etc..
-- > main = xmonad defaultConfig { layoutHook = myLayouts }
--
-- 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
-- four windows wide and three windows tall, you could use
--
-- > myLayouts = GridRatio (4/3) ||| etc.
--
-- For more detailed instructions on editing the layoutHook see:
--
-- "XMonad.Doc.Extending#Editing_the_layout_hook"
data Grid a = Grid deriving (Read, Show)
data Grid a = Grid | GridRatio Double deriving (Read, Show)
defaultRatio :: Double
defaultRatio = 16/9
instance LayoutClass Grid a where
pureLayout Grid r s = arrange r (integrate s)
pureLayout Grid r = pureLayout (GridRatio defaultRatio) r
pureLayout (GridRatio d) r = arrange d r . integrate
arrange :: Rectangle -> [a] -> [(a, Rectangle)]
arrange (Rectangle rx ry rw rh) st = zip st rectangles
arrange :: Double -> Rectangle -> [a] -> [(a, Rectangle)]
arrange aspectRatio (Rectangle rx ry rw rh) st = zip st rectangles
where
nwins = length st
ncols = max 1 . round . sqrt $ fromIntegral nwins * 9 * fromIntegral rw / (16 * fromIntegral rh :: Double)
mincs = nwins `div` ncols
ncols = max 1 . round . sqrt $ fromIntegral nwins * fromIntegral rw / (fromIntegral rh * aspectRatio)
mincs = max 1 $ nwins `div` ncols
extrs = nwins - ncols * mincs
chop :: Int -> Dimension -> [(Position, Dimension)]
chop n m = ((0, m - k * fromIntegral (pred n)) :) . map (flip (,) k) . tail . reverse . take n . tail . iterate (subtract k') $ m'

View File

@@ -0,0 +1,166 @@
{-# LANGUAGE DeriveDataTypeable, FlexibleInstances, MultiParamTypeClasses #-}
----------------------------------------------------------------------
-- |
-- Module : XMonad.Layout.GridVariants
-- Copyright : (c) Norbert Zeh
-- License : BSD-style (see LICENSE)
--
-- Maintainer : nzeh@cs.dal.ca
-- Stability : unstable
-- Portability : unportable
--
-- Two layouts: one is a variant of the Grid layout that allows the
-- desired aspect ratio of windows to be specified. The other is like
-- Tall but places a grid with fixed number of rows and columns in the
-- master area and uses an aspect-ratio-specified layout for the
-- slaves.
----------------------------------------------------------------------
module XMonad.Layout.GridVariants ( -- * Usage
-- $usage
ChangeMasterGeom(..)
, Grid(..)
, TallGrid(..)
) where
import Control.Monad
import XMonad
import qualified XMonad.StackSet as W
-- $usage
-- This module can be used as follows:
--
-- > import XMonad.Layout.Master
--
-- Then add something like this to your layouts:
--
-- > Grid (16/10)
--
-- for a 16:10 aspect ratio grid, or
--
-- > TallGrid 2 3 (2/3) (16/10) (5/100)
--
-- for a layout with a 2x3 master grid that uses 2/3 of the screen,
-- and a 16:10 aspect ratio slave grid. The last parameter is again
-- the percentage by which the split between master and slave area
-- changes in response to Expand/Shrink messages.
--
-- To be able to change the geometry of the master grid, add something
-- like this to your keybindings:
--
-- > ((modMask .|. shiftMask, xK_equal), sendMessage $ IncMasterCols 1),
-- > ((modMask .|. shiftMask, xK_minus), sendMessage $ IncMasterCols (-1)),
-- > ((modMask .|. ctrlMask, xK_equal), sendMessage $ IncMasterRows 1),
-- > ((modMask .|. ctrlMask, xK_minus), sendMessage $ IncMasterRows (-1))
-- | Grid layout. The parameter is the desired x:y aspect ratio of windows
data Grid a = Grid !Rational
deriving (Read, Show)
instance LayoutClass Grid a where
pureLayout (Grid aspect) rect st = zip wins rects
where
wins = W.integrate st
nwins = length wins
rects = arrangeAspectGrid rect nwins aspect
description _ = "Grid"
-- | TallGrid layout. Parameters are
--
-- - number of master rows
-- - number of master columns
-- - portion of screen used for master grid
-- - x:y aspect ratio of slave windows
-- - increment for resize messages
data TallGrid a = TallGrid !Int !Int !Rational !Rational !Rational
deriving (Read, Show)
instance LayoutClass TallGrid a where
pureLayout (TallGrid mrows mcols mfrac saspect _) rect st = zip wins rects
where
wins = W.integrate st
nwins = length wins
rects = arrangeTallGrid rect nwins mrows mcols mfrac saspect
pureMessage layout msg =
msum [ fmap (resizeMaster layout) (fromMessage msg)
, fmap (changeMasterGrid layout) (fromMessage msg) ]
description _ = "TallGrid"
-- |The geometry change message understood by the master grid
data ChangeMasterGeom
= IncMasterRows !Int -- ^Change the number of master rows
| IncMasterCols !Int -- ^Change the number of master columns
deriving Typeable
instance Message ChangeMasterGeom
arrangeTallGrid :: Rectangle -> Int -> Int -> Int -> Rational -> Rational -> [Rectangle]
arrangeTallGrid rect@(Rectangle rx ry rw rh) nwins mrows mcols mfrac saspect
| nwins <= mwins = arrangeMasterGrid rect nwins mcols
| mwins == 0 = arrangeAspectGrid rect nwins saspect
| otherwise = (arrangeMasterGrid mrect mwins mcols) ++
(arrangeAspectGrid srect swins saspect)
where
mwins = mrows * mcols
swins = nwins - mwins
mrect = Rectangle rx ry rw mh
srect = Rectangle rx (fromIntegral ry + fromIntegral mh) rw sh
mh = ceiling (fromIntegral rh * mfrac)
sh = rh - mh
arrangeMasterGrid :: Rectangle -> Int -> Int -> [Rectangle]
arrangeMasterGrid rect nwins mcols = arrangeGrid rect nwins (min nwins mcols)
arrangeAspectGrid :: Rectangle -> Int -> Rational -> [Rectangle]
arrangeAspectGrid rect@(Rectangle _ _ rw rh) nwins aspect =
arrangeGrid rect nwins (min nwins ncols)
where
ncols = ceiling $ sqrt $ ( fromRational
( (fromIntegral rw * fromIntegral nwins) / (fromIntegral rh * aspect) ) :: Double)
arrangeGrid :: Rectangle -> Int -> Int -> [Rectangle]
arrangeGrid (Rectangle rx ry rw rh) nwins ncols =
[Rectangle (fromIntegral x + rx) (fromIntegral y + ry) (fromIntegral w) (fromIntegral h)
| (x, y, w, h) <- rects]
where
nrows_in_cols = listDifference $ splitEvenly nwins ncols
x_slabs = splitIntoSlabs (fromIntegral rw) ncols
y_slabs = [splitIntoSlabs (fromIntegral rh) nrows | nrows <- nrows_in_cols]
rects_in_cols = [[(x, y, w, h) | (y, h) <- lst]
| ((x, w), lst) <- zip x_slabs y_slabs]
rects = foldr (++) [] rects_in_cols
splitIntoSlabs :: Int -> Int -> [(Int, Int)]
splitIntoSlabs width nslabs = zip (0:xs) widths
where
xs = splitEvenly width nslabs
widths = listDifference xs
listDifference :: [Int] -> [Int]
listDifference lst = [cur-pre | (cur,pre) <- zip lst (0:lst)]
splitEvenly :: Int -> Int -> [Int]
splitEvenly n parts = [ sz-off | (sz,off) <- zip sizes offsets]
where
size = ceiling ( (fromIntegral n / fromIntegral parts) :: Double )
extra = size*parts - n
sizes = [i*size | i <- [1..parts]]
offsets = (take (fromIntegral extra) [1..]) ++ [extra,extra..]
resizeMaster :: TallGrid a -> Resize -> TallGrid a
resizeMaster (TallGrid mrows mcols mfrac saspect delta) Shrink =
TallGrid mrows mcols (max 0 (mfrac - delta)) saspect delta
resizeMaster (TallGrid mrows mcols mfrac saspect delta) Expand =
TallGrid mrows mcols (min 1 (mfrac + delta)) saspect delta
changeMasterGrid :: TallGrid a -> ChangeMasterGeom -> TallGrid a
changeMasterGrid (TallGrid mrows mcols mfrac saspect delta) (IncMasterRows d) =
TallGrid (max 0 (mrows + d)) mcols mfrac saspect delta
changeMasterGrid (TallGrid mrows mcols mfrac saspect delta) (IncMasterCols d) =
TallGrid mrows (max 0 (mcols + d)) mfrac saspect delta

View File

@@ -18,7 +18,7 @@
module XMonad.Layout.HintedGrid (
-- * Usage
-- $usage
Grid(..), arrange
Grid(..), arrange, defaultRatio
) where
import Prelude hiding ((.))
@@ -44,16 +44,25 @@ infixr 9 .
-- > myLayouts = Grid False ||| Full ||| etc..
-- > main = xmonad defaultConfig { layoutHook = myLayouts }
--
-- You can also specify an aspect ratio for Grid to strive for with the
-- GridRatio constructor:
--
-- > myLayouts = GridRatio (4/3) False ||| etc.
--
-- For more detailed instructions on editing the layoutHook see
-- "XMonad.Doc.Extending#Editing_the_layout_hook".
-- | Automatic mirroring of hinted layouts doesn't work very well, so this
-- 'Grid' comes with built-in mirroring. @Grid False@ is the normal layout,
-- @Grid True@ is the mirrored variant (rotated by 90 degrees).
data Grid a = Grid Bool deriving (Read, Show)
data Grid a = Grid Bool | GridRatio Double Bool deriving (Read, Show)
defaultRatio :: Double
defaultRatio = 16/9
instance LayoutClass Grid Window where
doLayout (Grid m) r w = flip (,) Nothing . arrange m r (integrate w)
doLayout (Grid m) r w = doLayout (GridRatio defaultRatio m) r w
doLayout (GridRatio d m) r w = flip (,) Nothing . arrange d m r (integrate w)
replicateS :: Int -> (a -> (b, a)) -> a -> ([b], a)
replicateS n = runState . replicateM n . State
@@ -92,12 +101,12 @@ doRect height = doR
zipWith3 (\x y (w, h) -> Rectangle (fromIntegral x) (fromIntegral y) w h) xs ys c' ++ doR width' (n - 1) cs
-- | The internal function for computing the grid layout.
arrange :: Bool -> Rectangle -> [Window] -> X [(Window, Rectangle)]
arrange mirror (Rectangle rx ry rw rh) wins = do
arrange :: Double -> Bool -> Rectangle -> [Window] -> X [(Window, Rectangle)]
arrange aspectRatio mirror (Rectangle rx ry rw rh) wins = do
proto <- mapM mkAdjust wins
let
adjs = map (\f -> twist . f . twist) proto
rs = arrange' (twist (rw, rh)) adjs
rs = arrange' aspectRatio (twist (rw, rh)) adjs
rs' = map (\(Rectangle x y w h) -> uncurry (uncurry Rectangle (twist (x, y))) (twist (w, h))) rs
return . zip wins . map (\r -> r{ rect_x = rect_x r + rx, rect_y = rect_y r + ry }) $ rs'
where
@@ -105,11 +114,11 @@ arrange mirror (Rectangle rx ry rw rh) wins = do
| mirror = \(a, b) -> (b, a)
| otherwise = id
arrange' :: D -> [D -> D] -> [Rectangle]
arrange' (rw, rh) adjs = reverse $ doRect rh rw (fromIntegral ncolumns) (ecols ++ cols)
arrange' :: Double -> D -> [D -> D] -> [Rectangle]
arrange' aspectRatio (rw, rh) adjs = reverse $ doRect rh rw (fromIntegral ncolumns) (ecols ++ cols)
where
nwindows = length adjs
ncolumns = max 1 . round . sqrt $ fromIntegral nwindows * 9 * fromIntegral rw / (16 * fromIntegral rh :: Double)
ncolumns = max 1 . round . sqrt $ fromIntegral nwindows * fromIntegral rw / (fromIntegral rh * aspectRatio)
nrows = nwindows `div` ncolumns
nextras = nwindows - ncolumns * nrows
(ecols, adjs') = replicateS nextras (splitAt (nrows + 1)) $ reverse adjs

View File

@@ -50,11 +50,12 @@ import Control.Monad
-- "XMonad.Doc.Extending#Editing_the_layout_hook"
data HintedTile a = HintedTile
{ nmaster :: !Int
, delta, frac :: !Rational
{ nmaster :: !Int -- ^ number of windows in the master pane
, delta :: !Rational -- ^ how much to change when resizing
, frac :: !Rational -- ^ ratio between master/nonmaster panes
, alignment :: !Alignment -- ^ Where to place windows that are smaller
-- than their preordained rectangles.
, orientation :: !Orientation
, orientation :: !Orientation -- ^ Tall or Wide (mirrored) layout?
} deriving ( Show, Read )
data Orientation

View File

@@ -122,6 +122,6 @@ instance LayoutClass IM Window where
let (masterRect, slaveRect) = splitHorizontallyBy r rect
master <- findM (hasProperty prop) ws
let positions = case master of
Just w -> (w, masterRect) : arrange slaveRect (filter (w /=) ws)
Nothing -> arrange rect ws
Just w -> (w, masterRect) : arrange defaultRatio slaveRect (filter (w /=) ws)
Nothing -> arrange defaultRatio rect ws
return (positions, Nothing)

View File

@@ -46,7 +46,8 @@ data LayoutHints a = LayoutHints deriving (Read, Show)
instance LayoutModifier LayoutHints Window where
modifierDescription _ = "Hinted"
redoLayout _ _ s xs = do
redoLayout _ _ Nothing xs = return (xs, Nothing)
redoLayout _ _ (Just s) xs = do
xs' <- mapM applyHint xs
return (xs', Nothing)
where

View File

@@ -164,18 +164,17 @@ class (Show (m a), Read (m a)) => LayoutModifier m a where
-- consider implementing 'hook' and 'pureModifier' instead of
-- 'redoLayout'.
--
-- If you also need to perform some action when 'runLayout' is
-- called on an empty workspace, see 'emptyLayoutMod'.
-- On empty workspaces, the Stack is Nothing.
--
-- The default implementation of 'redoLayout' calls 'hook' and
-- then 'pureModifier'.
redoLayout :: m a -- ^ the layout modifier
-> Rectangle -- ^ screen rectangle
-> Stack a -- ^ current window stack
redoLayout :: m a -- ^ the layout modifier
-> Rectangle -- ^ screen rectangle
-> Maybe (Stack a) -- ^ current window stack
-> [(a, Rectangle)] -- ^ (window,rectangle) pairs returned
-- by the underlying layout
-> X ([(a, Rectangle)], Maybe (m a))
redoLayout m r s wrs = do hook m; return $ pureModifier m r s wrs
redoLayout m r ms wrs = do hook m; return $ pureModifier m r ms wrs
-- | 'pureModifier' allows you to intercept a call to 'runLayout'
-- /after/ it is called on the underlying layout, in order to
@@ -184,33 +183,14 @@ class (Show (m a), Read (m a)) => LayoutModifier m a where
--
-- The default implementation of 'pureModifier' returns the
-- window rectangles unmodified.
pureModifier :: m a -- ^ the layout modifier
-> Rectangle -- ^ screen rectangle
-> Stack a -- ^ current window stack
pureModifier :: m a -- ^ the layout modifier
-> Rectangle -- ^ screen rectangle
-> Maybe (Stack a) -- ^ current window stack
-> [(a, Rectangle)] -- ^ (window, rectangle) pairs returned
-- by the underlying layout
-> ([(a, Rectangle)], Maybe (m a))
pureModifier _ _ _ wrs = (wrs, Nothing)
-- | 'emptyLayoutMod' allows you to intercept a call to
-- 'runLayout' on an empty workspace, /after/ it is called on
-- the underlying layout, in order to perform some effect in the
-- X monad, possibly return a new layout modifier, and\/or
-- modify the results of 'runLayout' before returning them.
--
-- If you don't need access to the X monad, then tough luck.
-- There isn't a pure version of 'emptyLayoutMod'.
--
-- The default implementation of 'emptyLayoutMod' ignores its
-- arguments and returns an empty list of window\/rectangle
-- pairings.
--
-- /NOTE/: 'emptyLayoutMod' will likely be combined with
-- 'redoLayout' soon!
emptyLayoutMod :: m a -> Rectangle -> [(a, Rectangle)]
-> X ([(a, Rectangle)], Maybe (m a))
emptyLayoutMod _ _ _ = return ([], Nothing)
-- | 'hook' is called by the default implementation of
-- 'redoLayout', and as such represents an X action which is to
-- be run each time 'runLayout' is called on the underlying
@@ -256,9 +236,7 @@ class (Show (m a), Read (m a)) => LayoutModifier m a where
instance (LayoutModifier m a, LayoutClass l a) => LayoutClass (ModifiedLayout m l) a where
runLayout (Workspace i (ModifiedLayout m l) ms) r =
do (ws, ml') <- modifyLayout m (Workspace i l ms) r
(ws', mm') <- case ms of
Just s -> redoLayout m r s ws
Nothing -> emptyLayoutMod m r ws
(ws', mm') <- redoLayout m r ms ws
let ml'' = case mm' of
Just m' -> Just $ (ModifiedLayout m') $ maybe l id ml'
Nothing -> ModifiedLayout m `fmap` ml'

View File

@@ -114,14 +114,13 @@ data Toggle = On | Off deriving (Read, Show)
data MagnifyMaster = All | NoMaster deriving (Read, Show)
instance LayoutModifier Magnifier Window where
redoLayout (Mag z On All ) = applyMagnifier z
redoLayout (Mag z On NoMaster) = unlessMaster $ applyMagnifier z
redoLayout _ = nothing
where nothing _ _ wrs = return (wrs, Nothing)
redoLayout (Mag z On All ) r (Just s) wrs = applyMagnifier z r s wrs
redoLayout (Mag z On NoMaster) r (Just s) wrs = unlessMaster (applyMagnifier z) r s wrs
redoLayout _ _ _ wrs = return (wrs, Nothing)
handleMess (Mag z On t) m
| Just MagnifyMore <- fromMessage m = return . Just $ (Mag (z `addto` 0.1) On t)
| Just MagnifyLess <- fromMessage m = return . Just $ (Mag (z `addto` 0.1) On t)
| Just MagnifyMore <- fromMessage m = return . Just $ (Mag (z `addto` 0.1 ) On t)
| Just MagnifyLess <- fromMessage m = return . Just $ (Mag (z `addto` (-0.1)) On t)
| Just ToggleOff <- fromMessage m = return . Just $ (Mag (z ) Off t)
| Just Toggle <- fromMessage m = return . Just $ (Mag (z ) Off t)
where addto (x,y) i = (x+i,y+i)

172
XMonad/Layout/Monitor.hs Normal file
View File

@@ -0,0 +1,172 @@
{-# LANGUAGE TypeSynonymInstances, MultiParamTypeClasses, DeriveDataTypeable, PatternGuards #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Layout.Monitor
-- Copyright : (c) Roman Cheplyaka
-- License : BSD-style (see LICENSE)
--
-- Maintainer : Roman Cheplyaka <roma@ro-che.info>
-- Stability : unstable
-- Portability : unportable
--
-- Layout modfier for displaying some window (monitor) above other windows
--
-----------------------------------------------------------------------------
module XMonad.Layout.Monitor (
-- * Usage
-- $usage
-- * Hints and issues
-- $hints
Monitor(..),
monitor,
Property(..),
MonitorMessage(..),
doHideIgnore,
manageMonitor
-- * TODO
-- $todo
) where
import XMonad
import XMonad.Layout.LayoutModifier
import XMonad.Util.WindowProperties
import XMonad.Hooks.ManageHelpers (doHideIgnore)
import XMonad.Hooks.FadeInactive (setOpacity)
import Control.Monad
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
--
-- > import XMonad.Layout.Monitor
--
-- Define 'Monitor' record. 'monitor' can be used as a template. At least 'prop'
-- and 'rect' should be set here. Also consider setting 'persistent' to True.
--
-- Minimal example:
--
-- > myMonitor = monitor
-- > { prop = ClassName "SomeClass"
-- > , rect = Rectangle 0 0 40 20 -- rectangle 40x20 in upper left corner
-- > }
--
-- More interesting example:
--
-- > clock = monitor {
-- > -- Cairo-clock creates 2 windows with the same classname, thus also using title
-- > prop = ClassName "Cairo-clock" `And` Title "MacSlow's Cairo-Clock"
-- > -- rectangle 150x150 in lower right corner, assuming 1280x800 resolution
-- > , rect = Rectangle (1280-150) (800-150) 150 150
-- > -- avoid flickering
-- > , persistent = True
-- > -- make the window transparent
-- > , opacity = 0xAAAAAAAA
-- > -- hide on start
-- > , visible = False
-- > -- assign it a name to be able to toggle it independently of others
-- > , name = "clock"
-- > }
--
-- Add ManageHook to de-manage monitor windows and apply opacity settings.
--
-- > manageHook = myManageHook <+> manageMonitor clock
--
-- Apply layout modifier.
--
-- > myLayouts = ModifiedLayout clock $ tall ||| Full ||| ...
--
-- After that, if there exists a window with specified properties, it will be
-- displayed on top of all /tiled/ (not floated) windows on specified
-- position.
--
-- It's also useful to add some keybinding to toggle monitor visibility:
--
-- > , ((mod1Mask, xK_u ), broadcastMessage ToggleMonitor >> refresh)
--
-- Screenshot: <http://www.haskell.org/haskellwiki/Image:Xmonad-clock.png>
data Monitor a = Monitor
{ prop :: Property -- ^ property which uniquely identifies monitor window
, rect :: Rectangle -- ^ specifies where to put monitor
, visible :: Bool -- ^ is it visible by default?
, name :: String -- ^ name of monitor (useful when we have many of them)
, persistent :: Bool -- ^ is it shown on all layouts?
, opacity :: Integer -- ^ opacity level
} deriving (Read, Show)
-- | Template for 'Monitor' record. At least 'prop' and 'rect' should be
-- redefined. Default settings: 'visible' is 'True', 'persistent' is 'False'.
monitor :: Monitor a
monitor = Monitor
{ prop = Const False
, rect = Rectangle 0 0 0 0
, visible = True
, name = ""
, persistent = False
, opacity = 0xFFFFFFFF
}
-- | Messages without names affect all monitors. Messages with names affect only
-- monitors whose names match.
data MonitorMessage = ToggleMonitor | ShowMonitor | HideMonitor
| ToggleMonitorNamed String
| ShowMonitorNamed String
| HideMonitorNamed String
deriving (Read,Show,Eq,Typeable)
instance Message MonitorMessage
withMonitor :: Property -> a -> (Window -> X a) -> X a
withMonitor p a fn = do
monitorWindows <- allWithProperty p
case monitorWindows of
[] -> return a
w:_ -> fn w
instance LayoutModifier Monitor Window where
redoLayout mon _ _ rects = withMonitor (prop mon) (rects, Nothing) $ \w ->
if visible mon
then do tileWindow w (rect mon)
reveal w
return ((w,rect mon):rects, Nothing)
else do hide w
return (rects, Nothing)
handleMess mon mess
| Just ToggleMonitor <- fromMessage mess = return $ Just $ mon { visible = not $ visible mon }
| Just (ToggleMonitorNamed n) <- fromMessage mess = return $
if name mon == n then Just $ mon { visible = not $ visible mon } else Nothing
| Just ShowMonitor <- fromMessage mess = return $ Just $ mon { visible = True }
| Just (ShowMonitorNamed n) <- fromMessage mess = return $
if name mon == n then Just $ mon { visible = True } else Nothing
| Just HideMonitor <- fromMessage mess = return $ Just $ mon { visible = False }
| Just (HideMonitorNamed n) <- fromMessage mess = return $
if name mon == n then Just $ mon { visible = False } else Nothing
| Just Hide <- fromMessage mess = do unless (persistent mon) $ withMonitor (prop mon) () hide; return Nothing
| otherwise = return Nothing
-- | ManageHook which demanages monitor window and applies opacity settings.
manageMonitor :: Monitor a -> ManageHook
manageMonitor mon = propertyToQuery (prop mon) --> do
w <- ask
liftX $ setOpacity w $ opacity mon
if persistent mon then doIgnore else doHideIgnore
-- $hints
-- - This module assumes that there is only one window satisfying property exists.
--
-- - If your monitor is available on /all/ layouts, set
-- 'persistent' to 'True' to avoid unnecessary
-- flickering. You can still toggle monitor with a keybinding.
--
-- - You can use several monitors with nested modifiers. Give them names
--- to be able to toggle them independently.
--
-- - You can display monitor only on specific workspaces with
-- "XMonad.Layout.PerWorkspace".
-- $todo
-- - make Monitor remember the window it manages
--
-- - specify position relative to the screen

View File

@@ -75,9 +75,9 @@ data SmartBorder a = SmartBorder [a] deriving (Read, Show)
instance LayoutModifier SmartBorder Window where
unhook (SmartBorder s) = asks (borderWidth . config) >>= setBorders s
redoLayout (SmartBorder s) _ st wrs = do
redoLayout (SmartBorder s) _ mst wrs = do
wset <- gets windowset
let managedwindows = W.integrate st
let managedwindows = W.integrate' mst
screens = filter (nonzerorect . screenRect . W.screenDetail) . W.screens $ wset
ws = tiled ++ floating
tiled = case filter (`elem` managedwindows) $ map fst wrs of

View File

@@ -70,8 +70,6 @@ defaultSWNConfig =
instance LayoutModifier ShowWName a where
redoLayout sn r _ wrs = doShow sn r wrs
emptyLayoutMod sn r wrs = doShow sn r wrs
handleMess (SWN _ c (Just (i,w))) m
| Just e <- fromMessage m = handleTimer i e (deleteWindow w >> return Nothing)
| Just Hide <- fromMessage m = do deleteWindow w
@@ -89,7 +87,7 @@ doShow (SWN False _ _ ) _ wrs = return (wrs, Nothing)
flashName :: SWNConfig -> Rectangle -> [(a, Rectangle)] -> X ([(a, Rectangle)], Maybe (ShowWName a))
flashName c (Rectangle _ _ wh ht) wrs = do
d <- asks display
n <- withWindowSet (return . S.tag . S.workspace . S.current)
n <- withWindowSet (return . S.currentTag)
f <- initXMF (swn_font c)
width <- textWidthXMF d f n
(as,ds) <- textExtentsXMF f n

View File

@@ -0,0 +1,92 @@
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Layout.ThreeColumnsMiddle
-- Copyright : (c) Carsten Otto <xmonad@c-otto.de>,
-- based on ThreeColumns (c) Kai Grossjohann <kai@emptydomain.de>
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : ?
-- Stability : unstable
-- Portability : unportable
--
-- A layout similar to tall but with three columns, where the main window is
-- in the middle. With 2560x1600 pixels this layout can be used for a huge
-- main window and up to six reasonable sized slave windows.
--
-- > Screenshot: http://server.c-otto.de/xmonad/ThreeColumnsMiddle.png
--
-----------------------------------------------------------------------------
module XMonad.Layout.ThreeColumnsMiddle (
-- * Usage
-- $usage
ThreeColMid(..)
) where
import XMonad
import qualified XMonad.StackSet as W
import Data.Ratio
import Control.Monad
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
--
-- > import XMonad.Layout.ThreeColumnsMiddle
--
-- Then edit your @layoutHook@ by adding the ThreeColMid layout:
--
-- > myLayouts = ThreeColMid 1 (3/100) (1/2) ||| etc..
-- > main = xmonad defaultConfig { layoutHook = myLayouts }
--
-- The first argument specifies how many windows appear in the main window.
-- The second argument specifies how much the main window size changes when resizing.
-- The third argument specifies the initial size of the main window as a fraction of
-- total screen size.
--
-- For more detailed instructions on editing the layoutHook see:
--
-- "XMonad.Doc.Extending#Editing_the_layout_hook"
data ThreeColMid a = ThreeColMid !Int !Rational !Rational deriving (Show,Read)
instance LayoutClass ThreeColMid a where
doLayout (ThreeColMid nmaster _ frac) r =
return . (\x->(x,Nothing)) .
ap zip (tile3 frac r nmaster . length) . W.integrate
handleMessage (ThreeColMid nmaster delta frac) m =
return $ msum [fmap resize (fromMessage m)
,fmap incmastern (fromMessage m)]
where resize Shrink = ThreeColMid nmaster delta (max 0 $ frac-delta)
resize Expand = ThreeColMid nmaster delta (min 1 $ frac+delta)
incmastern (IncMasterN d) = ThreeColMid (max 0 (nmaster+d)) delta frac
description _ = "ThreeColMid"
-- | tile3. Compute window positions using 3 panes
tile3 :: Rational -> Rectangle -> Int -> Int -> [Rectangle]
tile3 f r nmaster n
-- split horizontally, if there are very few windows (only the main screen is used)
| n <= nmaster || nmaster == 0 = splitHorizontally n r
-- one window more than the master window can hold (the additional window is shown right of the main screen)
| n == nmaster+1 = splitVertically nmaster s1 ++ splitVertically (n-nmaster) s2
-- many windows (the main windows are shown in the center, all other windows are shown left and right of it)
| otherwise = splitVertically nmaster r1 ++ splitVertically nleft r2 ++ splitVertically nright r3
where (r1, r2, r3) = split3HorizontallyBy f r
(s1, s2) = splitHorizontallyBy f r
nslave = (n - nmaster)
nleft = ceiling (nslave % 2)
nright = (n - nmaster - nleft)
split3HorizontallyBy :: Rational -> Rectangle -> (Rectangle, Rectangle, Rectangle)
split3HorizontallyBy f (Rectangle sx sy sw sh) =
( Rectangle (sx + fromIntegral leftw) sy midw sh
, Rectangle sx sy leftw sh
, Rectangle (sx + fromIntegral leftw + fromIntegral midw) sy rightw sh )
where midw = ceiling $ fromIntegral sw * f
leftw = ceiling ( (sw - midw) % 2 )
rightw = sw - leftw - midw

View File

@@ -109,9 +109,9 @@ type ArrangeAll = Bool
data WindowArranger a = WA Bool ArrangeAll [ArrangedWindow a] deriving (Read, Show)
instance (Show a, Read a, Eq a) => LayoutModifier WindowArranger a where
pureModifier (WA True b []) _ _ wrs = arrangeWindows b wrs
pureModifier (WA True b []) _ (Just _) wrs = arrangeWindows b wrs
pureModifier (WA True b awrs) _ (S.Stack w _ _) wrs = curry process wrs awrs
pureModifier (WA True b awrs) _ (Just (S.Stack w _ _)) wrs = curry process wrs awrs
where
wins = map fst *** map awrWin
update (a,r) = mkNewAWRs b a *** removeAWRs r >>> uncurry (++)

View File

@@ -106,7 +106,7 @@ configurableNavigation :: LayoutClass l a => WNConfig -> l a -> ModifiedLayout W
configurableNavigation conf = ModifiedLayout (WindowNavigation conf (I Nothing))
instance LayoutModifier WindowNavigation Window where
redoLayout (WindowNavigation conf (I state)) rscr s origwrs =
redoLayout (WindowNavigation conf (I state)) rscr (Just s) origwrs =
do XConf { normalBorder = nbc, focusedBorder = fbc, display = dpy } <- ask
[uc,dc,lc,rc] <-
case brightness conf of
@@ -136,6 +136,7 @@ instance LayoutModifier WindowNavigation Window where
mapM_ (sc nbc) (wothers \\ map fst wnavigable)
mapM_ (\(win,c) -> sc c win) wnavigablec
return (origwrs, Just $ WindowNavigation conf $ I $ Just $ NS pt wnavigable)
redoLayout _ _ _ origwrs = return (origwrs, Nothing)
handleMessOrMaybeModifyIt (WindowNavigation conf (I (Just (NS pt wrs)))) m
| Just (Go d) <- fromMessage m =

View File

@@ -37,7 +37,7 @@ import XMonad.Util.Run ( runProcessWithInput )
import XMonad.Prompt ( XPConfig )
import XMonad.Prompt.Directory ( directoryPrompt )
import XMonad.Layout.LayoutModifier
import XMonad.StackSet ( tag, current, workspace )
import XMonad.StackSet ( tag, currentTag )
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
@@ -69,7 +69,7 @@ instance Message Chdir
data WorkspaceDir a = WorkspaceDir String deriving ( Read, Show )
instance LayoutModifier WorkspaceDir Window where
modifyLayout (WorkspaceDir d) w r = do tc <- gets (tag.workspace.current.windowset)
modifyLayout (WorkspaceDir d) w r = do tc <- gets (currentTag.windowset)
when (tc == tag w) $ scd d
runLayout w r
handleMess (WorkspaceDir _) m

View File

@@ -5,7 +5,7 @@
-- Copyright : (C) 2007 Andrea Rossato
-- License : BSD3
--
-- Maintainer : andrea.rossato@unibz.it
-- Maintainer : Spencer Janssen <spencerjanssen@gmail.com>
-- Stability : unstable
-- Portability : unportable
--
@@ -18,7 +18,9 @@ module XMonad.Prompt
-- $usage
mkXPrompt
, mkXPromptWithReturn
, amberXPConfig
, defaultXPConfig
, greenXPConfig
, XPType (..)
, XPPosition (..)
, XPConfig (..)
@@ -44,8 +46,13 @@ module XMonad.Prompt
, decodeInput
, encodeOutput
, historyCompletion
-- * History filters
, deleteAllDuplicates
, deleteConsecutive
) where
import Prelude hiding (catch)
import XMonad hiding (config, io)
import qualified XMonad.StackSet as W
import XMonad.Util.Font
@@ -61,9 +68,13 @@ import Data.Bits ((.&.))
import Data.Maybe
import Data.List
import Data.Set (fromList, toList)
import System.Environment (getEnv)
import System.Directory
import System.IO
import System.Posix.Files
import Control.Exception hiding (handle)
import qualified Data.Map as Map
import Data.Map (Map)
-- $usage
-- For usage examples see "XMonad.Prompt.Shell",
@@ -83,13 +94,14 @@ data XPState =
, complWin :: Maybe Window
, complWinDim :: Maybe ComplWindowDim
, completionFunction :: String -> IO [String]
, showComplWin :: Bool
, gcon :: !GC
, fontS :: !XMonadFont
, xptype :: !XPType
, command :: String
, commandHistory :: W.Stack String
, offset :: !Int
, history :: [History]
, config :: XPConfig
, successful :: Bool
}
data XPConfig =
@@ -103,10 +115,14 @@ data XPConfig =
, position :: XPPosition -- ^ Position: 'Top' or 'Bottom'
, height :: !Dimension -- ^ Window height
, historySize :: !Int -- ^ The number of history entries to be saved
, historyFilter :: [String] -> [String]
-- ^ a filter to determine which
-- history entries to remember
, defaultText :: String -- ^ The text by default in the prompt line
, autoComplete :: Maybe Int -- ^ Just x: if only one completion remains, auto-select it,
, showCompletionOnTab :: Bool -- ^ Only show list of completions when Tab was pressed
-- and delay by x microseconds
} deriving (Show, Read)
}
data XPType = forall p . XPrompt p => XPT p
@@ -161,26 +177,29 @@ data XPPosition = Top
| Bottom
deriving (Show,Read)
defaultXPConfig :: XPConfig
amberXPConfig, defaultXPConfig, greenXPConfig :: XPConfig
defaultXPConfig =
XPC { font = "-misc-fixed-*-*-*-*-10-*-*-*-*-*-*-*"
, bgColor = "#333333"
, fgColor = "#FFFFFF"
, fgHLight = "#000000"
, bgHLight = "#BBBBBB"
, borderColor = "#FFFFFF"
XPC { font = "-misc-fixed-*-*-*-*-12-*-*-*-*-*-*-*"
, bgColor = "grey22"
, fgColor = "grey80"
, fgHLight = "black"
, bgHLight = "grey"
, borderColor = "white"
, promptBorderWidth = 1
, position = Bottom
, height = 18
, historySize = 256
, historyFilter = id
, defaultText = []
, autoComplete = Nothing
}
, showCompletionOnTab = False }
greenXPConfig = defaultXPConfig { fgColor = "green", bgColor = "black" }
amberXPConfig = defaultXPConfig { fgColor = "#ca8f2d", bgColor = "black", fgHLight = "#eaaf4c" }
type ComplFunction = String -> IO [String]
initState :: XPrompt p => Display -> Window -> Window -> Rectangle -> ComplFunction
-> GC -> XMonadFont -> p -> [History] -> XPConfig -> XPState
-> GC -> XMonadFont -> p -> [String] -> XPConfig -> XPState
initState d rw w s compl gc fonts pt h c =
XPS { dpy = d
, rootw = rw
@@ -189,15 +208,25 @@ initState d rw w s compl gc fonts pt h c =
, complWin = Nothing
, complWinDim = Nothing
, completionFunction = compl
, showComplWin = not (showCompletionOnTab c)
, gcon = gc
, fontS = fonts
, xptype = XPT pt
, command = defaultText c
, commandHistory = W.Stack { W.focus = defaultText c
, W.up = []
, W.down = h }
, offset = length (defaultText c)
, history = h
, config = c
, successful = False
}
-- this would be much easier with functional references
command :: XPState -> String
command = W.focus . commandHistory
setCommand :: String -> XPState -> XPState
setCommand xs s = s { commandHistory = (commandHistory s) { W.focus = xs }}
-- | Same as 'mkXPrompt', except that the action function can have
-- type @String -> X a@, for any @a@, and the final action returned
-- by 'mkXPromptWithReturn' will have type @X (Maybe a)@. @Nothing@
@@ -210,25 +239,26 @@ mkXPromptWithReturn t conf compl action = do
let d = display c
rw = theRoot c
s <- gets $ screenRect . W.screenDetail . W.current . windowset
hist <- liftIO $ readHistory
w <- liftIO $ createWin d rw conf s
liftIO $ selectInput d w $ exposureMask .|. keyPressMask
gc <- liftIO $ createGC d w
liftIO $ setGraphicsExposures d gc False
(hist,h) <- liftIO $ readHistory
fs <- initXMF (font conf)
let st = initState d rw w s compl gc fs (XPT t) hist conf
let hs = fromMaybe [] $ Map.lookup (showXPrompt t) hist
st = initState d rw w s compl gc fs (XPT t) hs conf
st' <- liftIO $ execStateT runXP st
releaseXMF fs
liftIO $ freeGC d gc
liftIO $ hClose h
if (command st' /= "")
if successful st'
then do
let htw = take (historySize conf) (history st')
liftIO $ writeHistory htw
liftIO $ writeHistory $ Map.insertWith
(\xs ys -> take (historySize conf)
. historyFilter conf $ xs ++ ys)
(showXPrompt t) [command st'] hist
Just <$> action (command st')
else
return Nothing
else return Nothing
-- | Creates a prompt given:
--
@@ -277,6 +307,7 @@ handle :: KeyStroke -> Event -> XP ()
handle k@(ks,_) e@(KeyEvent {ev_event_type = t})
| t == keyPress && ks == xK_Tab = do
c <- getCompletions
if length c > 1 then modify $ \s -> s { showComplWin = True } else return ()
completionHandle c k e
handle ks (KeyEvent {ev_event_type = t, ev_state = m})
| t == keyPress = keyPressHandle m ks
@@ -292,7 +323,7 @@ completionHandle c (ks,_) (KeyEvent {ev_event_type = t})
| t == keyPress && ks == xK_Tab = do
st <- get
let updateState l = do let new_command = nextCompletion (xptype st) (command st) l
modify $ \s -> s { command = new_command, offset = length new_command }
modify $ \s -> setCommand new_command $ s { offset = length new_command }
updateWins l = do redrawWindows l
eventLoop (completionHandle l)
case c of
@@ -319,11 +350,10 @@ tryAutoComplete = do
where runCompleted cmd delay = do
st <- get
let new_command = nextCompletion (xptype st) (command st) [cmd]
modify $ \s -> s { command = "autocompleting..." }
modify $ setCommand "autocompleting..."
updateWindows
io $ threadDelay delay
modify $ \s -> s { command = new_command }
historyPush
modify $ setCommand new_command
return True
-- KeyPresses
@@ -348,19 +378,20 @@ keyPressHandle mask (ks,_)
| ks == xK_w -> killWord Prev >> go
| ks == xK_g || ks == xK_c -> quit
| otherwise -> eventLoop handle -- unhandled control sequence
| ks == xK_Return = historyPush >> return ()
| ks == xK_Return = setSuccess True
| ks == xK_BackSpace = deleteString Prev >> go
| ks == xK_Delete = deleteString Next >> go
| ks == xK_Left = moveCursor Prev >> go
| ks == xK_Right = moveCursor Next >> go
| ks == xK_Up = moveHistory Prev >> go
| ks == xK_Down = moveHistory Next >> go
| ks == xK_Home = startOfLine >> go
| ks == xK_End = endOfLine >> go
| ks == xK_Down = moveHistory W.focusUp' >> go
| ks == xK_Up = moveHistory W.focusDown' >> go
| ks == xK_Escape = quit
where
go = updateWindows >> eventLoop handle
quit = flushString >> return () -- quit and discard everything
quit = flushString >> setSuccess False -- quit and discard everything
setSuccess b = modify $ \s -> s { successful = b }
-- insert a character
keyPressHandle _ (_,s)
| s == "" = eventLoop handle
@@ -374,18 +405,18 @@ keyPressHandle _ (_,s)
-- | Kill the portion of the command before the cursor
killBefore :: XP ()
killBefore =
modify $ \s -> s { command = drop (offset s) (command s)
, offset = 0 }
modify $ \s -> setCommand (drop (offset s) (command s)) $ s { offset = 0 }
-- | Kill the portion of the command including and after the cursor
killAfter :: XP ()
killAfter =
modify $ \s -> s { command = take (offset s) (command s) }
modify $ \s -> setCommand (take (offset s) (command s)) s
-- | Kill the next\/previous word
killWord :: Direction -> XP ()
killWord d = do
XPS { command = c, offset = o } <- get
o <- gets offset
c <- gets command
let (f,ss) = splitAt o c
delNextWord w =
case w of
@@ -396,7 +427,7 @@ killWord d = do
case d of
Next -> (f ++ delNextWord ss, o)
Prev -> (delPrevWord f ++ ss, length $ delPrevWord f) -- laziness!!
modify $ \s -> s { command = ncom, offset = noff}
modify $ \s -> setCommand ncom $ s { offset = noff}
-- | Put the cursor at the end of line
endOfLine :: XP ()
@@ -411,12 +442,12 @@ startOfLine =
-- | Flush the command string and reset the offset
flushString :: XP ()
flushString = do
modify $ \s -> s { command = "", offset = 0}
modify $ \s -> setCommand "" $ s { offset = 0}
-- | Insert a character at the cursor position
insertString :: String -> XP ()
insertString str =
modify $ \s -> s { command = c (command s) (offset s), offset = o (offset s)}
modify $ \s -> setCommand (c (command s) (offset s)) $ s { offset = o (offset s)}
where o oo = oo + length str
c oc oo | oo >= length oc = oc ++ str
| otherwise = f ++ str ++ ss
@@ -429,7 +460,7 @@ pasteString = join $ io $ liftM insertString $ getSelection
-- | Remove a character at the cursor position
deleteString :: Direction -> XP ()
deleteString d =
modify $ \s -> s { command = c (command s) (offset s), offset = o (offset s)}
modify $ \s -> setCommand (c (command s) (offset s)) $ s { offset = o (offset s)}
where o oo = if d == Prev then max 0 (oo - 1) else oo
c oc oo
| oo >= length oc && d == Prev = take (oo - 1) oc
@@ -459,17 +490,10 @@ moveWord d = do
Next -> o + (ln id ss)
modify $ \s -> s { offset = newoff }
moveHistory :: Direction -> XP ()
moveHistory d = do
h <- getHistory
c <- gets command
let str = if h /= [] then head h else c
let nc = case elemIndex c h of
Just i -> case d of
Prev -> h !! (if (i + 1) > (length h - 1) then 0 else i + 1)
Next -> h !! (max (i - 1) 0)
Nothing -> str
modify $ \s -> s { command = nc, offset = length nc}
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 }
-- X Stuff
@@ -636,7 +660,7 @@ redrawComplWin compl = do
let recreate = do destroyComplWin
w <- createComplWin nwi
drawComplWin w compl
if (compl /= [] )
if (compl /= [] && showComplWin st)
then case complWin st of
Just w -> case complWinDim st of
Just wi -> if nwi == wi -- complWinDim did not change
@@ -673,41 +697,28 @@ printComplString d drw gc fc bc x y s = do
-- History
data History =
H { prompt :: String
, command_history :: String
} deriving (Show, Read, Eq)
type History = Map String [String]
historyPush :: XP ()
historyPush = do
c <- gets command
when (c /= []) $ modify (\s -> s { history = nub $ H (showXPrompt (xptype s)) c : history s })
emptyHistory :: History
emptyHistory = Map.empty
getHistory :: XP [String]
getHistory = do
hist <- gets history
pt <- gets xptype
return $ map command_history . filter (\h -> prompt h == showXPrompt pt) $ hist
getHistoryFile :: IO FilePath
getHistoryFile = fmap (++ "/history") $ getAppUserDataDirectory "xmonad"
readHistory :: IO ([History],Handle)
readHistory = do
home <- getEnv "HOME"
let path = home ++ "/.xmonad/history"
f <- fileExist path
if f then do h <- openFile path ReadMode
str <- hGetContents h
case (reads str) of
[(hist,_)] -> return (hist,h)
[] -> return ([],h)
_ -> return ([],h)
else do h <- openFile path WriteMode
return ([],h)
readHistory :: IO History
readHistory = catch readHist (const (return emptyHistory))
where
readHist = do
path <- getHistoryFile
xs <- bracket (openFile path ReadMode) hClose hGetLine
readIO xs
writeHistory :: [History] -> IO ()
writeHistory :: History -> IO ()
writeHistory hist = do
home <- getEnv "HOME"
let path = home ++ "/.xmonad/history"
catch (writeFile path (show hist)) (\_ -> do putStrLn "error in writing"; return ())
path <- getHistoryFile
catch (writeFile path (show hist)) $ const $ hPutStrLn stderr "error in writing"
setFileMode path mode
where mode = ownerReadMode .|. ownerWriteMode
-- $xutils
@@ -802,18 +813,21 @@ breakAtSpace s
where (s1, s2 ) = break isSpace s
(s1',s2') = breakAtSpace $ tail s2
-- | Sort a list and remove duplicates.
-- | 'historyCompletion' provides a canned completion function much like
-- 'getShellCompl'; you pass it to mkXPrompt, and it will make completions work
-- from the query history stored in ~\/.xmonad\/history.
historyCompletion :: ComplFunction
historyCompletion x = fmap (deleteConsecutive . filter (isInfixOf x) . Map.fold (++) []) readHistory
-- | Sort a list and remove duplicates. Like 'deleteAllDuplicates', but trades off
-- laziness and stability for efficiency.
uniqSort :: Ord a => [a] -> [a]
uniqSort = toList . fromList
-- | 'historyCompletion' provides a canned completion function much like
-- getShellCompl; you pass it to mkXPrompt, and it will make completions work
-- from the query history stored in ~/.xmonad/history.
historyCompletion :: ComplFunction
historyCompletion = \x -> liftM (filter $ isInfixOf x) readHistoryIO
-- We need to define this locally because there is no function with the type "XP a -> IO a", and
-- 'getHistory' is uselessly of the type "XP [String]".
readHistoryIO :: IO [String]
readHistoryIO = do (hist,_) <- readHistory
return $ map command_history hist
-- | Functions to be used with the 'historyFilter' setting.
-- 'deleteAllDuplicates' will remove all duplicate entries.
-- 'deleteConsecutive' will only remove duplicate elements
-- immediately next to each other.
deleteAllDuplicates, deleteConsecutive :: [String] -> [String]
deleteAllDuplicates = nub
deleteConsecutive = map head . group

View File

@@ -88,12 +88,12 @@ manCompl mans s | s == "" || last s == ' ' = return []
-- better\/more idiomatic.)
getCommandOutput :: String -> IO String
getCommandOutput s = do
(pin, pout, perr, ph) <- runInteractiveCommand s
-- we can ignore the process handle because we ignor SIGCHLD
(pin, pout, perr, _) <- runInteractiveCommand s
hClose pin
output <- hGetContents pout
E.evaluate (length output)
hClose perr
waitForProcess ph
return output
stripExt :: String -> String

View File

@@ -15,7 +15,8 @@
module XMonad.Prompt.Shell
( -- * Usage
-- $usage
shellPrompt
Shell (..)
, shellPrompt
, getCommands
, getBrowser
, getEditor
@@ -141,4 +142,4 @@ getBrowser = env "BROWSER" "firefox"
-- | Like 'getBrowser', but should be of a text editor. This gets the $EDITOR variable, defaulting to \"emacs\".
getEditor :: IO String
getEditor = env "EDITOR" "emacs"
getEditor = env "EDITOR" "emacs"

View File

@@ -19,7 +19,8 @@ module XMonad.Prompt.Window
-- * Usage
-- $usage
windowPromptGoto,
windowPromptBring
windowPromptBring,
windowPromptBringCopy
) where
import qualified Data.Map as M
@@ -28,6 +29,7 @@ import Data.List
import qualified XMonad.StackSet as W
import XMonad
import XMonad.Prompt
import XMonad.Actions.CopyWindow
import XMonad.Actions.WindowBringer
-- $usage
@@ -57,16 +59,18 @@ import XMonad.Actions.WindowBringer
-- For detailed instruction on editing the key binding see
-- "XMonad.Doc.Extending#Editing_key_bindings".
data WindowPrompt = Goto | Bring
data WindowPrompt = Goto | Bring | BringCopy
instance XPrompt WindowPrompt where
showXPrompt Goto = "Go to window: "
showXPrompt Bring = "Bring me here: "
showXPrompt Bring = "Bring window: "
showXPrompt BringCopy = "Bring a copy: "
commandToComplete _ c = c
nextCompletion _ = getNextCompletion
windowPromptGoto, windowPromptBring :: XPConfig -> X ()
windowPromptGoto, windowPromptBring, windowPromptBringCopy :: XPConfig -> X ()
windowPromptGoto c = doPrompt Goto c
windowPromptBring c = doPrompt Bring c
windowPromptBringCopy c = doPrompt BringCopy c
-- | Pops open a prompt with window titles. Choose one, and you will be
-- taken to the corresponding workspace.
@@ -75,6 +79,7 @@ doPrompt t c = do
a <- case t of
Goto -> fmap gotoAction windowMap
Bring -> fmap bringAction windowMap
BringCopy -> fmap bringCopyAction windowMap
wm <- windowMap
mkXPrompt t c (compList wm) a
@@ -82,5 +87,11 @@ doPrompt t c = do
winAction a m = flip whenJust (windows . a) . flip M.lookup m
gotoAction = winAction W.focusWindow
bringAction = winAction bringWindow
bringCopyAction = winAction bringCopyWindow
compList m s = return . filter (isPrefixOf s) . map fst . M.toList $ m
-- | Brings a copy of the specified window into the current workspace.
bringCopyWindow :: Window -> WindowSet -> WindowSet
bringCopyWindow w ws = copyWindow w (W.currentTag $ ws) ws

View File

@@ -15,10 +15,10 @@
-----------------------------------------------------------------------------
module XMonad.Util.Dmenu (
-- * Usage
-- $usage
dmenu, dmenuXinerama, dmenuMap
) where
-- * Usage
-- $usage
dmenu, dmenuXinerama, dmenuMap, menu, menuMap
) where
import XMonad
import qualified XMonad.StackSet as W
@@ -40,9 +40,17 @@ dmenuXinerama opts = do
io $ runProcessWithInput "dmenu" ["-xs", show (curscreen+1)] (unlines opts)
dmenu :: [String] -> X String
dmenu opts = io $ runProcessWithInput "dmenu" [] (unlines opts)
dmenu opts = menu "dmenu" opts
menu :: String -> [String] -> X String
menu menuCmd opts = io $ runProcessWithInput menuCmd [] (unlines opts)
menuMap :: String -> M.Map String a -> X (Maybe a)
menuMap menuCmd selectionMap = do
selection <- menuFunction (M.keys selectionMap)
return $ M.lookup selection selectionMap
where
menuFunction = menu menuCmd
dmenuMap :: M.Map String a -> X (Maybe a)
dmenuMap selectionMap = do
selection <- dmenu (M.keys selectionMap)
return $ M.lookup selection selectionMap
dmenuMap selectionMap = menuMap "dmenu" selectionMap

View File

@@ -134,11 +134,16 @@ removeMouseBindings conf mouseBindingList =
-- the key sequence descriptions contained in the Strings. The key
-- sequence descriptions are \"emacs-style\": @M-@, @C-@, @S-@, and
-- @M\#-@ denote mod, control, shift, and mod1-mod5 (where @\#@ is
-- replaced by the appropriate number) respectively; some special
-- keys can be specified by enclosing their name in angle brackets.
-- replaced by the appropriate number) respectively. Note that if
-- you want to make a keybinding using \'alt\' even though you use a
-- different key (like the \'windows\' key) for \'mod\', you can use
-- something like @\"M1-x\"@ for alt+x (check the output of @xmodmap@
-- to see which mod key \'alt\' is bound to). Some special keys can
-- also be specified by enclosing their name in angle brackets.
--
-- For example, @\"M-C-x\"@ denotes mod+ctrl+x; @\"S-\<Escape\>\"@ denotes
-- shift-escape.
-- For example, @\"M-C-x\"@ denotes mod+ctrl+x; @\"S-\<Escape\>\"@
-- denotes shift-escape; @\"M1-C-\<Delete\>\"@ denotes alt+ctrl+delete
-- (assuming alt is bound to mod1, which is common).
--
-- Sequences of keys can also be specified by separating the key
-- descriptions with spaces. For example, @\"M-x y \<Down\>\"@ denotes the
@@ -159,7 +164,10 @@ removeMouseBindings conf mouseBindingList =
-- create a keymap and add it to your config.
--
-- Here is a complete list of supported special keys. Note that a few
-- keys, such as the arrow keys, have synonyms:
-- keys, such as the arrow keys, have synonyms. If there are other
-- special keys you would like to see supported, feel free to submit a
-- patch, or ask on the xmonad mailing list; adding special keys is
-- quite simple.
--
-- > <Backspace>
-- > <Tab>

View File

@@ -43,7 +43,7 @@ import Graphics.X11.Xft
import Graphics.X11.Xrender
#endif
#if defined XFT || defined UTF8
#if defined XFT || defined USE_UTF8
import Codec.Binary.UTF8.String (encodeString, decodeString)
#endif
@@ -103,7 +103,7 @@ initXMF s =
return (Xft xftdraw)
else
#endif
#ifdef UTF8
#ifdef USE_UTF8
fmap Utf8 $ initUtf8Font s
#else
fmap Core $ initCoreFont s
@@ -195,14 +195,14 @@ printStringXMF dpy drw fs@(Xft font) gc fc bc x y s = do
#endif
decodeInput :: String -> String
#if defined XFT || defined UTF8
#if defined XFT || defined USE_UTF8
decodeInput = decodeString
#else
decodeInput = id
#endif
encodeOutput :: String -> String
#if defined XFT || defined UTF8
#if defined XFT || defined USE_UTF8
encodeOutput = encodeString
#else
encodeOutput = id

View File

@@ -30,7 +30,7 @@ import XMonad.Core
import System.Time
import System.IO
import System.Process
import System.Process (runInteractiveCommand)
import System.Locale
-- $usage
@@ -82,7 +82,7 @@ battery = logCmd "/usr/bin/acpi | sed -r 's/.*?: (.*%).*/\\1/; s/discharging, ([
-- | Create a 'Logger' from an arbitrary shell command.
logCmd :: String -> Logger
logCmd c = io $ do (_, out, _, proc) <- runInteractiveCommand c
logCmd c = io $ do (_, out, _, _) <- runInteractiveCommand c
output <- hGetLine out
waitForProcess proc
-- no need to waitForProcess, we ignore SIGCHLD
return $ Just output

94
XMonad/Util/Paste.hs Normal file
View File

@@ -0,0 +1,94 @@
{- |
Module : XMonad.Util.Paste
Copyright : (C) 2008 Jérémy Bobbio, gwern
License : BSD3
Maintainer : gwern <gwern0@gmail.com>
Stability : unstable
Portability : unportable
A module for sending key presses to windows. This modules provides generalized
and specialized functions for this task.
-}
module XMonad.Util.Paste ( -- * Usage
-- $usage
pasteSelection,
pasteString,
pasteChar,
sendKey,
sendKeyWindow,
noModMask
)
where
import XMonad (io, theRoot, withDisplay, X ())
import Graphics.X11
import Graphics.X11.Xlib.Extras (none, setEventType, setKeyEvent)
import Control.Monad.Reader (asks)
import XMonad.Operations (withFocused)
import Data.Char (isUpper)
import Graphics.X11.Xlib.Misc (stringToKeysym)
import XMonad.Util.XSelection (getSelection)
{- $usage
Import this module into your xmonad.hs as usual:
> import XMonad.Util.Paste
And use the functions. They all return 'X' (), and so are appropriate
for use as keybindings. Example:
> , ((m, xK_d), pasteString "foo bar") ]
Don't expect too much of the functions; they probably don't work on complex
texts.
-}
-- | Paste the current X mouse selection. Note that this uses 'getSelection' from
-- "XMonad.Util.XSelection" and so is heir to its flaws.
pasteSelection :: X ()
pasteSelection = getSelection >>= pasteString
-- | Send a string to the window which is currently focused. This function correctly
-- handles capitalization.
pasteString :: String -> X ()
pasteString = mapM_ (\x -> if isUpper x then pasteChar shiftMask x else pasteChar noModMask x)
{- | Send a character to the current window. This is more low-level.
Remember that you must handle the case of capitalization appropriately.
That is, from the window's perspective:
> pasteChar mod2Mask 'F' ~> "f"
You would want to do something like:
> pasteChar shiftMask 'F'
Note that this function makes use of 'stringToKeysym', and so will probably
have trouble with any 'Char' outside ASCII.
-}
pasteChar :: KeyMask -> Char -> X ()
pasteChar m c = sendKey m $ stringToKeysym [c]
sendKey :: KeyMask -> KeySym -> X ()
sendKey = (withFocused .) . sendKeyWindow
-- | The primitive. Allows you to send any combination of 'KeyMask' and 'KeySym' to any 'Window' you specify.
sendKeyWindow :: KeyMask -> KeySym -> Window -> X ()
sendKeyWindow mods key w = withDisplay $ \d -> do
rootw <- asks theRoot
keycode <- io $ keysymToKeycode d key
io $ allocaXEvent $ \ev -> do
setEventType ev keyPress
setKeyEvent ev w rootw none mods keycode True
sendEvent d w True keyPressMask ev
setEventType ev keyRelease
sendEvent d w True keyReleaseMask ev
-- | A null 'KeyMask'. Used when you don't want a character or string shifted, control'd, or what.
--
-- TODO: This really should be a function in the X11 binding. When noModMask shows up there, remove.
noModMask :: KeyMask
noModMask = 0

View File

@@ -31,7 +31,7 @@ module XMonad.Util.Run (
) where
import System.Posix.IO
import System.Posix.Process (executeFile)
import System.Posix.Process (executeFile, forkProcess)
import Control.Concurrent (threadDelay)
import Control.Exception (try)
import System.IO
@@ -54,20 +54,20 @@ import Control.Monad
-- This corresponds to dmenu's notion of exit code 1 for a cancelled invocation.
runProcessWithInput :: FilePath -> [String] -> String -> IO String
runProcessWithInput cmd args input = do
(pin, pout, perr, ph) <- runInteractiveProcess cmd args Nothing Nothing
(pin, pout, perr, _) <- runInteractiveProcess cmd args Nothing Nothing
hPutStr pin input
hClose pin
output <- hGetContents pout
when (output == output) $ return ()
hClose pout
hClose perr
waitForProcess ph
-- no need to waitForProcess, we ignore SIGCHLD
return output
-- | Wait is in µs (microseconds)
runProcessWithInputAndWait :: FilePath -> [String] -> String -> Int -> IO ()
runProcessWithInputAndWait cmd args input timeout = do
doubleFork $ do
forkProcess $ do
(pin, pout, perr, ph) <- runInteractiveProcess cmd args Nothing Nothing
hPutStr pin input
hFlush pin
@@ -77,6 +77,7 @@ runProcessWithInputAndWait cmd args input timeout = do
hClose perr
waitForProcess ph
return ()
return ()
-- | Multiplies by ONE MILLION, for functions that take microseconds.
--
@@ -106,7 +107,7 @@ it makes use of shell interpretation by relying on @$HOME@ and
interpolation, whereas the safeSpawn example can be safe because
Firefox doesn't need any arguments if it is just being started. -}
safeSpawn :: MonadIO m => FilePath -> String -> m ()
safeSpawn prog arg = liftIO (try (doubleFork $ executeFile prog True [arg] Nothing) >> return ())
safeSpawn prog arg = liftIO (try (forkProcess $ executeFile prog True [arg] Nothing) >> return ())
unsafeSpawn :: MonadIO m => String -> m ()
unsafeSpawn = spawn
@@ -128,7 +129,7 @@ spawnPipe x = do
setFdOption wr CloseOnExec True
h <- fdToHandle wr
hSetBuffering h LineBuffering
doubleFork $ do
forkProcess $ do
dupTo rd stdInput
executeFile "/bin/sh" False ["-c", x] Nothing
return h

View File

@@ -23,6 +23,7 @@ import XMonad
import Control.Applicative
import Control.Concurrent
import Data.Unique
import System.Posix.Process (forkProcess)
-- $usage
-- This module can be used to setup a timer to handle deferred events.
@@ -35,7 +36,7 @@ type TimerId = Int
startTimer :: Rational -> X TimerId
startTimer s = io $ do
u <- hashUnique <$> newUnique
doubleFork $ do
forkProcess $ do
d <- openDisplay ""
rw <- rootWindow d $ defaultScreen d
threadDelay (fromEnum $ s * 1000000)

View File

@@ -14,10 +14,12 @@
module XMonad.Util.WindowProperties (
-- * Usage
-- $usage
Property(..), hasProperty, focusedHasProperty)
Property(..), hasProperty, focusedHasProperty, allWithProperty,
propertyToQuery)
where
import XMonad
import qualified XMonad.StackSet as W
import Control.Monad
-- $usage
-- This module allows to specify window properties, such as title, classname or
@@ -59,3 +61,20 @@ focusedHasProperty p = do
Just s -> hasProperty p $ W.focus s
Nothing -> return False
-- | Find all existing windows with specified property
allWithProperty :: Property -> X [Window]
allWithProperty prop = withDisplay $ \dpy -> do
rootw <- asks theRoot
(_,_,wins) <- io $ queryTree dpy rootw
hasProperty prop `filterM` wins
-- | Convert property to 'Query' 'Bool' (see "XMonad.ManageHook")
propertyToQuery :: Property -> Query Bool
propertyToQuery (Title s) = title =? s
propertyToQuery (Resource s) = resource =? s
propertyToQuery (ClassName s) = className =? s
propertyToQuery (Role s) = stringProperty "WM_WINDOW_ROLE" =? s
propertyToQuery (And p1 p2) = propertyToQuery p1 <&&> propertyToQuery p2
propertyToQuery (Or p1 p2) = propertyToQuery p1 <||> propertyToQuery p2
propertyToQuery (Not p) = not `fmap` propertyToQuery p
propertyToQuery (Const b) = return b

View File

@@ -1,10 +1,10 @@
{-# LANGUAGE CPP #-}
{- |
Module : XMonad.Util.XSelection
Copyright : (C) 2007 Andrea Rossato, Matthew Sackman
License : BSD3
Maintainer : Andrea Rossato <andrea.rossato@unibz.it>,
Matthew Sackman <matthew@wellquite.org>
Maintainer : Gwern Branwen <gwern0@gmail.com>
Stability : unstable
Portability : unportable
@@ -19,18 +19,62 @@ module XMonad.Util.XSelection ( -- * Usage
getSelection,
promptSelection,
safePromptSelection,
transformPromptSelection,
transformSafePromptSelection,
putSelection) where
import Control.Concurrent (forkIO)
import Control.Exception as E (catch)
import Control.Monad(Monad (return, (>>)), Functor(..), liftM, join)
import Data.Bits (shiftL, (.&.), (.|.))
import Data.Char (chr, ord)
import Data.Char (ord)
import Data.Maybe (fromMaybe)
import Data.Word (Word8)
import XMonad
import XMonad.Util.Run (safeSpawn, unsafeSpawn)
#ifdef USE_UTF8
import Codec.Binary.UTF8.String (decode)
#else
import Data.Bits (shiftL, (.&.), (.|.))
import Data.Char (chr)
import Data.Word (Word8)
{- | Decode a UTF8 string packed into a list of Word8 values, directly to
String; does not deal with CChar, hence you will want the counter-intuitive @map fromIntegral@
UTF-8 decoding for internal use in getSelection.
This code is copied from Eric Mertens's "utf-string" library <http://code.haskell.org/utf8-string/>
(as of version 0.1),\which is BSD-3 licensed like this module.
It'd be better to just @import Codec.Binary.UTF8.String (decode)@, but then users of this would need to install it; XMonad has enough
dependencies already. -}
decode :: [Word8] -> String
decode [] = ""
decode (c:cs)
| c < 0x80 = chr (fromEnum c) : decode cs
| c < 0xc0 = replacement_character : decode cs
| c < 0xe0 = multi_byte 1 0x1f 0x80
| c < 0xf0 = multi_byte 2 0xf 0x800
| c < 0xf8 = multi_byte 3 0x7 0x10000
| c < 0xfc = multi_byte 4 0x3 0x200000
| c < 0xfe = multi_byte 5 0x1 0x4000000
| otherwise = replacement_character : decode cs
where
replacement_character :: Char
replacement_character = '\xfffd'
multi_byte :: Int -> Word8 -> Int -> [Char]
multi_byte i mask overlong = aux i cs (fromEnum (c .&. mask))
where
aux 0 rs acc
| overlong <= acc && acc <= 0x10ffff &&
(acc < 0xd800 || 0xdfff < acc) &&
(acc < 0xfffe || 0xffff < acc) = chr acc : decode rs
| otherwise = replacement_character : decode rs
aux n (r:rs) acc
| r .&. 0xc0 == 0x80 = aux (n-1) rs
$ shiftL acc 6 .|. fromEnum (r .&. 0x3f)
aux _ rs _ = replacement_character : decode rs
#endif
{- $usage
Add @import XMonad.Util.XSelection@ to the top of Config.hs
Then make use of getSelection or promptSelection as needed; if
@@ -127,42 +171,12 @@ shell using 'safeSpawn' from "XMonad.Util.Run"; see its documentation for more
details on the advantages and disadvantages of using safeSpawn. -}
promptSelection, safePromptSelection, unsafePromptSelection :: String -> X ()
promptSelection = unsafePromptSelection
safePromptSelection app = join $ io $ liftM (safeSpawn app) (getSelection)
safePromptSelection app = join $ io $ liftM (safeSpawn app) getSelection
unsafePromptSelection app = join $ io $ liftM unsafeSpawn $ fmap (\x -> app ++ " " ++ x) getSelection
{- | Decode a UTF8 string packed into a list of Word8 values, directly to
String; does not deal with CChar, hence you will want the counter-intuitive @map fromIntegral@
UTF-8 decoding for internal use in getSelection.
This code is copied from Eric Mertens's "utf-string" library <http://code.haskell.org/utf8-string/>
(as of version 0.1),\which is BSD-3 licensed like this module.
It'd be better to just @import Codec.Binary.UTF8.String (decode)@, but then users of this would need to install it; XMonad has enough
dependencies already. -}
decode :: [Word8] -> String
decode [ ] = ""
decode (c:cs)
| c < 0x80 = chr (fromEnum c) : decode cs
| c < 0xc0 = replacement_character : decode cs
| c < 0xe0 = multi_byte 1 0x1f 0x80
| c < 0xf0 = multi_byte 2 0xf 0x800
| c < 0xf8 = multi_byte 3 0x7 0x10000
| c < 0xfc = multi_byte 4 0x3 0x200000
| c < 0xfe = multi_byte 5 0x1 0x4000000
| otherwise = replacement_character : decode cs
where
replacement_character :: Char
replacement_character = '\xfffd'
multi_byte :: Int -> Word8 -> Int -> [Char]
multi_byte i mask overlong = aux i cs (fromEnum (c .&. mask))
where
aux 0 rs acc
| overlong <= acc && acc <= 0x10ffff &&
(acc < 0xd800 || 0xdfff < acc) &&
(acc < 0xfffe || 0xffff < acc) = chr acc : decode rs
| otherwise = replacement_character : decode rs
aux n (r:rs) acc
| r .&. 0xc0 == 0x80 = aux (n-1) rs
$ shiftL acc 6 .|. fromEnum (r .&. 0x3f)
aux _ rs _ = replacement_character : decode rs
{- | A wrapper around 'promptSelection' and its safe variant. They take two parameters, the first is a function that transforms strings, and the second is the application to run. The transformer essentially transforms the selection in X.
One example is to wrap code, such as a command line action copied out of the browser to be run as '"sudo" ++ cmd' or '"su - -c \"" ++ cmd ++ "\"".
-}
transformPromptSelection, transformSafePromptSelection :: (String -> String) -> String -> X ()
transformPromptSelection f app = join $ io $ liftM (safeSpawn app) (fmap f getSelection)
transformSafePromptSelection f app = join $ io $ liftM unsafeSpawn $ fmap (\x -> app ++ " " ++ x) (fmap f getSelection)

View File

@@ -137,7 +137,7 @@ paintWindow' win (Rectangle x y wh ht) bw color b_color str = do
io $ fillRectangle d p gc 0 0 wh ht
-- and now again
io $ setForeground d gc color'
io $ fillRectangle d p gc (fi bw) (fi bw) ((wh - (bw * 2))) (ht - (bw * 2))
io $ fillRectangle d p gc (fi bw) (fi bw) (wh - (bw * 2)) (ht - (bw * 2))
when (isJust str) $ do
let (xmf,fc,bc,s) = fromJust str
printStringXMF d p xmf gc fc bc x y s

View File

@@ -1,5 +1,5 @@
name: xmonad-contrib
version: 0.8
version: 0.8.1
homepage: http://xmonad.org/
synopsis: Third party extensions for xmonad
description:
@@ -43,7 +43,7 @@ flag testing
library
if flag(small_base)
build-depends: base >= 3, containers, directory, process, random, old-time, old-locale
build-depends: base >= 3 && < 4, containers, directory, process, random, old-time, old-locale
else
build-depends: base < 3
@@ -55,14 +55,17 @@ library
if flag(with_utf8)
build-depends: utf8-string
extensions: ForeignFunctionInterface
cpp-options: -DUTF8
cpp-options: -DUSE_UTF8
build-depends: mtl, unix, X11>=1.4.1, xmonad>=0.8, xmonad<0.9
build-depends: mtl, unix, X11>=1.4.3, xmonad>=0.8, xmonad<0.9
ghc-options: -Wall
if flag(testing)
ghc-options: -Werror
if impl (ghc >= 6.10.1) && arch (x86_64)
ghc-options: -O0
exposed-modules: XMonad.Doc
XMonad.Doc.Configuring
XMonad.Doc.Extending
@@ -81,6 +84,7 @@ library
XMonad.Actions.FlexibleResize
XMonad.Actions.FloatKeys
XMonad.Actions.FocusNth
XMonad.Actions.GridSelect
XMonad.Actions.MouseGestures
XMonad.Actions.MouseResize
XMonad.Actions.NoBorders
@@ -91,6 +95,7 @@ library
XMonad.Actions.Search
XMonad.Actions.SimpleDate
XMonad.Actions.SinkAll
XMonad.Actions.SpawnOn
XMonad.Actions.Submap
XMonad.Actions.SwapWorkspaces
XMonad.Actions.TagWindows
@@ -100,11 +105,11 @@ library
XMonad.Actions.WindowGo
XMonad.Actions.WindowBringer
XMonad.Config.Arossato
XMonad.Config.Azerty
XMonad.Config.Desktop
XMonad.Config.Droundy
XMonad.Config.Gnome
XMonad.Config.Kde
XMonad.Config.PlainConfig
XMonad.Config.Sjanssen
XMonad.Config.Xfce
XMonad.Hooks.DynamicHooks
@@ -121,6 +126,7 @@ library
XMonad.Hooks.XPropManage
XMonad.Layout.Accordion
XMonad.Layout.BoringWindows
XMonad.Layout.CenteredMaster
XMonad.Layout.Circle
XMonad.Layout.Combo
XMonad.Layout.Decoration
@@ -128,8 +134,10 @@ library
XMonad.Layout.Dishes
XMonad.Layout.DragPane
XMonad.Layout.DwmStyle
XMonad.Layout.FixedColumn
XMonad.Layout.Gaps
XMonad.Layout.Grid
XMonad.Layout.GridVariants
XMonad.Layout.HintedGrid
XMonad.Layout.HintedTile
XMonad.Layout.IM
@@ -141,6 +149,7 @@ library
XMonad.Layout.Magnifier
XMonad.Layout.Master
XMonad.Layout.Maximize
XMonad.Layout.Monitor
XMonad.Layout.MosaicAlt
XMonad.Layout.MultiToggle
XMonad.Layout.MultiToggle.Instances
@@ -161,6 +170,7 @@ library
XMonad.Layout.Tabbed
XMonad.Layout.TabBarDecoration
XMonad.Layout.ThreeColumns
XMonad.Layout.ThreeColumnsMiddle
XMonad.Layout.ToggleLayouts
XMonad.Layout.TwoPane
XMonad.Layout.WindowArranger
@@ -197,5 +207,6 @@ library
XMonad.Util.Timer
XMonad.Util.WindowProperties
XMonad.Util.WorkspaceCompare
XMonad.Util.Paste
XMonad.Util.XSelection
XMonad.Util.XUtils