mirror of
https://github.com/xmonad/xmonad-contrib.git
synced 2025-07-27 10:11:52 -07:00
Compare commits
91 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
2659a12049 | ||
|
3533a5d3f3 | ||
|
d8baf188db | ||
|
8dcb699db3 | ||
|
4440974718 | ||
|
7629022c72 | ||
|
9a209f6d55 | ||
|
9a6494fae2 | ||
|
f7c34eef31 | ||
|
dec7167bc8 | ||
|
80f70d284d | ||
|
c7a64a99ce | ||
|
73502fbbdf | ||
|
10fbf85a2a | ||
|
e0024ec9c8 | ||
|
670d3160c4 | ||
|
4026d40730 | ||
|
e76c654211 | ||
|
1e7cd73544 | ||
|
06b3767cae | ||
|
1125e9102e | ||
|
396ae4e77c | ||
|
7124346ebe | ||
|
6283298a85 | ||
|
c1a711dba0 | ||
|
9a4559d2fa | ||
|
9b0a2649b6 | ||
|
8454e5d6b3 | ||
|
35c5c1eaf0 | ||
|
a0dde418ad | ||
|
4fbd0c5b3f | ||
|
926c5ec9d2 | ||
|
69453d212a | ||
|
0917d4f5d4 | ||
|
0bf616d2fb | ||
|
4f2feafd04 | ||
|
e153c6d406 | ||
|
0b1beb1d2b | ||
|
54c138c4f0 | ||
|
35ea95dc88 | ||
|
6bcefb308b | ||
|
c6e80350e2 | ||
|
24b112c452 | ||
|
c698a58fe6 | ||
|
f6723df7d8 | ||
|
0c835744c2 | ||
|
7e0186ef4e | ||
|
9e28c1ce37 | ||
|
7b3466d9a9 | ||
|
bf55da2bad | ||
|
53571aad1e | ||
|
838c878fa2 | ||
|
feae6b11e5 | ||
|
0cca07363d | ||
|
4c6f940a1d | ||
|
44cf0f02c3 | ||
|
64c9db6bab | ||
|
e11534fa56 | ||
|
662eeb7e5f | ||
|
da6155ebac | ||
|
edb48ee66c | ||
|
a5431b3f85 | ||
|
cdf37639e4 | ||
|
9997b18970 | ||
|
ef14aa07ba | ||
|
f20b54067c | ||
|
1a4c17e35e | ||
|
71f87d5804 | ||
|
0d5de727c3 | ||
|
697d9e21b7 | ||
|
2949cbeef4 | ||
|
8925732d5f | ||
|
ecc2f0d5ec | ||
|
0853c1ce21 | ||
|
b95f4daab7 | ||
|
e75a72d63f | ||
|
7064ac5ec9 | ||
|
d4798cf7ae | ||
|
5954f61988 | ||
|
67ab9fb6ad | ||
|
38306b1deb | ||
|
aba20ccf60 | ||
|
647c7e9b61 | ||
|
2033064db1 | ||
|
dd80c23f56 | ||
|
fb9a8cfef8 | ||
|
02012aeedd | ||
|
ef79fa7c10 | ||
|
2a73b577c2 | ||
|
0155164015 | ||
|
5375240f08 |
@@ -88,8 +88,8 @@ defaultCommands = do
|
||||
, ("expand" , sendMessage Expand )
|
||||
, ("next-layout" , sendMessage NextLayout )
|
||||
, ("default-layout" , asks (layoutHook . config) >>= setLayout )
|
||||
, ("restart-wm" , sr >> restart Nothing True )
|
||||
, ("restart-wm-no-resume", sr >> restart Nothing False )
|
||||
, ("restart-wm" , sr >> restart "xmonad" True )
|
||||
, ("restart-wm-no-resume", sr >> restart "xmonad" False )
|
||||
, ("xterm" , spawn =<< asks (terminal . config) )
|
||||
, ("run" , spawn "exe=`dmenu_path | dmenu -b` && exec $exe" )
|
||||
, ("kill" , kill )
|
||||
|
@@ -16,9 +16,9 @@
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
module XMonad.Actions.ConstrainedResize (
|
||||
-- * Usage
|
||||
-- $usage
|
||||
XMonad.Actions.ConstrainedResize.mouseResizeWindow
|
||||
-- * Usage
|
||||
-- $usage
|
||||
XMonad.Actions.ConstrainedResize.mouseResizeWindow
|
||||
) where
|
||||
|
||||
import XMonad
|
||||
|
@@ -1,4 +1,4 @@
|
||||
{-# OPTIONS_GHC -fglasgow-exts #-}
|
||||
{-# LANGUAGE PatternGuards #-}
|
||||
-----------------------------------------------------------------------------
|
||||
-- |
|
||||
-- Module : XMonad.Actions.CopyWindow
|
||||
|
@@ -10,7 +10,7 @@
|
||||
-- Portability : unportable
|
||||
--
|
||||
-- Provides bindings to cycle forward or backward through the list
|
||||
-- of workspaces, and to move windows there.
|
||||
-- of workspaces, and to move windows there, and to cycle between the screens.
|
||||
--
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
@@ -22,31 +22,38 @@ module XMonad.Actions.CycleWS (
|
||||
shiftToNext,
|
||||
shiftToPrev,
|
||||
toggleWS,
|
||||
nextScreen,
|
||||
prevScreen,
|
||||
shiftNextScreen,
|
||||
shiftPrevScreen
|
||||
) where
|
||||
|
||||
import Data.List ( sortBy, findIndex )
|
||||
import Data.List ( findIndex )
|
||||
import Data.Maybe ( fromMaybe )
|
||||
import Data.Ord ( comparing )
|
||||
|
||||
import XMonad hiding (workspaces)
|
||||
import qualified XMonad (workspaces)
|
||||
import XMonad.StackSet hiding (filter)
|
||||
import XMonad.Util.WorkspaceCompare
|
||||
|
||||
-- $usage
|
||||
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@ file:
|
||||
--
|
||||
-- > import XMonad.Actions.CycleWS
|
||||
--
|
||||
-- > , ((modMask x, xK_Right), nextWS)
|
||||
-- > , ((modMask x, xK_Left), prevWS)
|
||||
-- > , ((modMask x .|. shiftMask, xK_Right), shiftToNext)
|
||||
-- > , ((modMask x .|. shiftMask, xK_Left), shiftToPrev)
|
||||
-- > , ((modMask x, xK_Down), nextWS)
|
||||
-- > , ((modMask x, xK_Up), prevWS)
|
||||
-- > , ((modMask x .|. shiftMask, xK_Down), shiftToNext)
|
||||
-- > , ((modMask x .|. shiftMask, xK_Up), shiftToPrev)
|
||||
-- > , ((modMask x, xK_Right), nextScreen)
|
||||
-- > , ((modMask x, xK_Left), prevScreen)
|
||||
-- > , ((modMask x .|. shiftMask, xK_Right), shiftNextScreen)
|
||||
-- > , ((modMask x .|. shiftMask, xK_Left), shiftPrevScreen)
|
||||
-- > , ((modMask x, xK_t), toggleWS)
|
||||
--
|
||||
-- If you want to follow the moved window, you can use both actions:
|
||||
--
|
||||
-- > , ((modMask x .|. shiftMask, xK_Right), shiftToNext >> nextWS)
|
||||
-- > , ((modMask x .|. shiftMask, xK_Left), shiftToPrev >> prevWS)
|
||||
-- > , ((modMask x .|. shiftMask, xK_Down), shiftToNext >> nextWS)
|
||||
-- > , ((modMask x .|. shiftMask, xK_Up), shiftToPrev >> prevWS)
|
||||
--
|
||||
-- For detailed instructions on editing your key bindings, see
|
||||
-- "XMonad.Doc.Extending#Editing_key_bindings".
|
||||
@@ -81,14 +88,47 @@ shiftBy d = wsBy d >>= windows . shift
|
||||
wsBy :: Int -> X (WorkspaceId)
|
||||
wsBy d = do
|
||||
ws <- gets windowset
|
||||
spaces <- asks (XMonad.workspaces . config)
|
||||
let orderedWs = sortBy (comparing (wsIndex spaces)) (workspaces ws)
|
||||
sort' <- getSortByTag
|
||||
let orderedWs = sort' (workspaces ws)
|
||||
let now = fromMaybe 0 $ findWsIndex (workspace (current ws)) orderedWs
|
||||
let next = orderedWs !! ((now + d) `mod` length orderedWs)
|
||||
return $ tag next
|
||||
|
||||
wsIndex :: [WorkspaceId] -> WindowSpace -> Maybe Int
|
||||
wsIndex spaces ws = findIndex (== tag ws) spaces
|
||||
|
||||
findWsIndex :: WindowSpace -> [WindowSpace] -> Maybe Int
|
||||
findWsIndex ws wss = findIndex ((== tag ws) . tag) wss
|
||||
|
||||
-- | View next screen
|
||||
nextScreen :: X ()
|
||||
nextScreen = switchScreen 1
|
||||
|
||||
-- | View prev screen
|
||||
prevScreen :: X ()
|
||||
prevScreen = switchScreen (-1)
|
||||
|
||||
switchScreen :: Int -> X ()
|
||||
switchScreen d = do s <- screenBy d
|
||||
mws <- screenWorkspace s
|
||||
case mws of
|
||||
Nothing -> return ()
|
||||
Just ws -> windows (view ws)
|
||||
|
||||
screenBy :: Int -> X (ScreenId)
|
||||
screenBy d = do ws <- gets windowset
|
||||
--let ss = sortBy screen (screens ws)
|
||||
let now = screen (current ws)
|
||||
return $ (now + fromIntegral d) `mod` fromIntegral (length (screens ws))
|
||||
|
||||
-- | Move focused window to workspace on next screen
|
||||
shiftNextScreen :: X ()
|
||||
shiftNextScreen = shiftScreenBy 1
|
||||
|
||||
-- | Move focused window to workspace on prev screen
|
||||
shiftPrevScreen :: X ()
|
||||
shiftPrevScreen = shiftScreenBy (-1)
|
||||
|
||||
shiftScreenBy :: Int -> X ()
|
||||
shiftScreenBy d = do s <- screenBy d
|
||||
mws <- screenWorkspace s
|
||||
case mws of
|
||||
Nothing -> return ()
|
||||
Just ws -> windows (shift ws)
|
||||
|
@@ -17,9 +17,9 @@
|
||||
-- Based on the FlexibleResize code by Lukas Mai (mauke).
|
||||
|
||||
module XMonad.Actions.FlexibleManipulate (
|
||||
-- * Usage
|
||||
-- $usage
|
||||
mouseWindow, discrete, linear, resize, position
|
||||
-- * Usage
|
||||
-- $usage
|
||||
mouseWindow, discrete, linear, resize, position
|
||||
) where
|
||||
|
||||
import XMonad
|
||||
|
@@ -13,9 +13,9 @@
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
module XMonad.Actions.FlexibleResize (
|
||||
-- * Usage
|
||||
-- $usage
|
||||
XMonad.Actions.FlexibleResize.mouseResizeWindow
|
||||
-- * Usage
|
||||
-- $usage
|
||||
XMonad.Actions.FlexibleResize.mouseResizeWindow
|
||||
) where
|
||||
|
||||
import XMonad
|
||||
|
@@ -38,12 +38,13 @@ focusNth :: Int -> X ()
|
||||
focusNth = windows . modify' . focusNth'
|
||||
|
||||
focusNth' :: Int -> Stack a -> Stack a
|
||||
focusNth' n s@(Stack _ ls rs) | (n < 0) || (n > length(ls) + length(rs)) = s
|
||||
| otherwise = listToStack n (integrate s)
|
||||
focusNth' n s@(Stack _ ls rs) | (n < 0) || (n > length(ls) + length(rs)) = s
|
||||
| otherwise = listToStack n (integrate s)
|
||||
|
||||
listToStack :: Int -> [a] -> Stack a
|
||||
listToStack n l = Stack t ls rs
|
||||
where (t:rs) = drop n l
|
||||
ls = reverse (take n l)
|
||||
where
|
||||
(t:rs) = drop n l
|
||||
ls = reverse (take n l)
|
||||
|
||||
|
||||
|
@@ -15,7 +15,7 @@
|
||||
module XMonad.Actions.MouseGestures (
|
||||
-- * Usage
|
||||
-- $usage
|
||||
Direction(..),
|
||||
Direction(..),
|
||||
mouseGesture
|
||||
) where
|
||||
|
||||
|
33
XMonad/Actions/NoBorders.hs
Normal file
33
XMonad/Actions/NoBorders.hs
Normal file
@@ -0,0 +1,33 @@
|
||||
-----------------------------------------------------------------------------
|
||||
-- |
|
||||
-- Module : XMonad.Actions.NoBorders
|
||||
-- Copyright : (c) Lukas Mai
|
||||
-- License : BSD3-style (see LICENSE)
|
||||
--
|
||||
-- Maintainer : Lukas Mai <l.mai@web.de>
|
||||
-- Stability : unstable
|
||||
-- Portability : unportable
|
||||
--
|
||||
-- This module provides helper functions for dealing with window borders.
|
||||
--
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
module XMonad.Actions.NoBorders (
|
||||
toggleBorder
|
||||
) where
|
||||
|
||||
import XMonad
|
||||
|
||||
-- | Toggle the border of the currently focused window. To use it, add a
|
||||
-- keybinding like so:
|
||||
--
|
||||
-- > , ((modMask x, xK_g ), withFocused toggleBorder)
|
||||
--
|
||||
toggleBorder :: Window -> X ()
|
||||
toggleBorder w = do
|
||||
bw <- asks (borderWidth . config)
|
||||
withDisplay $ \d -> io $ do
|
||||
cw <- wa_border_width `fmap` getWindowAttributes d w
|
||||
if cw == 0
|
||||
then setWindowBorderWidth d w bw
|
||||
else setWindowBorderWidth d w 0
|
@@ -12,10 +12,10 @@
|
||||
-- place.
|
||||
-----------------------------------------------------------------------------
|
||||
module XMonad.Actions.RotSlaves (
|
||||
-- $usage
|
||||
rotSlaves', rotSlavesUp, rotSlavesDown,
|
||||
rotAll', rotAllUp, rotAllDown
|
||||
) where
|
||||
-- $usage
|
||||
rotSlaves', rotSlavesUp, rotSlavesDown,
|
||||
rotAll', rotAllUp, rotAllDown
|
||||
) where
|
||||
|
||||
import XMonad.StackSet
|
||||
import XMonad
|
||||
|
138
XMonad/Actions/Search.hs
Normal file
138
XMonad/Actions/Search.hs
Normal file
@@ -0,0 +1,138 @@
|
||||
{- |
|
||||
Module : XMonad.Actions.Search
|
||||
Copyright : (C) 2007 Gwern Branwen
|
||||
License : None; public domain
|
||||
|
||||
Maintainer : <gwern0@gmail.com>
|
||||
Stability : unstable
|
||||
Portability : unportable
|
||||
|
||||
A module for easily running Internet searches on web sites through XMonad.
|
||||
Modeled after the handy Surfraw CLI search tools
|
||||
<https://secure.wikimedia.org/wikipedia/en/wiki/Surfraw>.
|
||||
|
||||
Additional sites welcomed.
|
||||
-}
|
||||
module XMonad.Actions.Search ( -- * Usage
|
||||
-- $usage
|
||||
search,
|
||||
simpleEngine,
|
||||
promptSearch,
|
||||
selectSearch,
|
||||
|
||||
amazon,
|
||||
google,
|
||||
imdb,
|
||||
wayback,
|
||||
wikipedia,
|
||||
hoogle
|
||||
) where
|
||||
|
||||
import Data.Char (chr, ord, isAlpha, isMark, isDigit)
|
||||
import Numeric (showIntAtBase)
|
||||
import XMonad (X(), MonadIO)
|
||||
import XMonad.Prompt (XPrompt(showXPrompt), mkXPrompt, XPConfig())
|
||||
import XMonad.Prompt.Shell (getShellCompl)
|
||||
import XMonad.Util.Run (safeSpawn)
|
||||
import XMonad.Util.XSelection (getSelection)
|
||||
|
||||
{- $usage
|
||||
|
||||
This module is intended to allow easy access to databases on the Internet
|
||||
through XMonad's interface. The idea is that one wants to run a search but the
|
||||
query string and the browser to use must come from somewhere. There are two
|
||||
places the query string can come from - the user can type it into a prompt
|
||||
which pops up, or the query could be available already in the X Windows
|
||||
copy\/paste buffer (perhaps you just highlighted the string of interest).
|
||||
|
||||
Thus, there are two main functions: 'promptSearch', and 'selectSearch'
|
||||
(implemented using the more primitive 'search'). To each of these is passed an
|
||||
engine function; this is a function that knows how to search a particular
|
||||
site.
|
||||
|
||||
For example, the 'google' function knows how to search Google, and so on. You pass
|
||||
promptSearch and selectSearch the engine you want, the browser you want, and
|
||||
anything special they might need; this whole line is then bound to a key of
|
||||
you choosing in your xmonad.hs. For specific examples, see each function.
|
||||
This module is easily extended to new sites by using 'simpleEngine'.
|
||||
-}
|
||||
|
||||
-- A customized prompt.
|
||||
data Search = Search
|
||||
instance XPrompt Search where
|
||||
showXPrompt Search = "Search: "
|
||||
|
||||
-- | Escape the search string so search engines understand it.
|
||||
-- Note that everything is escaped; we could be smarter and use 'isAllowedInURI'
|
||||
-- but then that'd be hard enough to copy-and-paste we'd need to depend on 'network'.
|
||||
escape :: String -> String
|
||||
escape = escapeURIString (\c -> isAlpha c || isDigit c || isMark c)
|
||||
where -- Copied from Network.URI.
|
||||
escapeURIString ::
|
||||
(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
|
||||
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
|
||||
[] -> "00"
|
||||
[ch] -> ['0',ch]
|
||||
cs -> cs
|
||||
toChrHex d
|
||||
| d < 10 = chr (ord '0' + fromIntegral d)
|
||||
| otherwise = chr (ord 'A' + fromIntegral (d - 10))
|
||||
|
||||
type Browser = FilePath
|
||||
type SearchEngine = String -> String
|
||||
|
||||
search :: MonadIO m => Browser -> SearchEngine -> String -> m ()
|
||||
search browser site query = safeSpawn browser $ site 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 simpleEngine
|
||||
without needing to modify Search.hs:
|
||||
|
||||
> newEngine = simpleEngine "http://site.com/search="
|
||||
|
||||
The important thing is that the site has a interface which accepts the query
|
||||
string as part of the URL. Alas, the exact URL to feed simpleEngine varies
|
||||
from site to site, often considerably. 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. -}
|
||||
simpleEngine :: String -> SearchEngine
|
||||
simpleEngine site query = site ++ escape query
|
||||
|
||||
-- The engines
|
||||
amazon, google, hoogle, imdb, wayback, wikipedia :: SearchEngine
|
||||
amazon = simpleEngine "http://www.amazon.com/exec/obidos/external-search?index=all&keyword="
|
||||
google = simpleEngine "http://www.google.com/search?num=100&q="
|
||||
hoogle = simpleEngine "http://www.haskell.org/hoogle/?q="
|
||||
imdb = simpleEngine "http://www.imdb.com/Find?select=all&for="
|
||||
wikipedia = simpleEngine "https://secure.wikimedia.org/wikipedia/en/wiki/Special:Search?go=Go&search="
|
||||
wayback = simpleEngine "http://web.archive.org/"
|
||||
{- This doesn't seem to work, but nevertheless, it seems to be the official
|
||||
method at <http://web.archive.org/collections/web/advanced.html> to get the
|
||||
latest backup. -}
|
||||
|
||||
{- | Like 'search', but in this case, the string is not specified but grabbed
|
||||
from the user's response to a prompt. Example:
|
||||
|
||||
> , ((modm, xK_g ), promptSearch greenXPConfig "firefox" google)
|
||||
|
||||
-}
|
||||
promptSearch :: XPConfig -> Browser -> SearchEngine -> X ()
|
||||
promptSearch config browser site = mkXPrompt Search config (getShellCompl []) $ search browser site
|
||||
|
||||
{- | Like search, but for use with the X selection; it grabs the selection,
|
||||
passes it to a given searchEngine and opens it in the given browser. Example:
|
||||
|
||||
> , ((modm .|. shiftMask, xK_g ), selectSearch "firefox" google)
|
||||
|
||||
-}
|
||||
selectSearch :: MonadIO m => Browser -> SearchEngine -> m ()
|
||||
selectSearch browser searchEngine = search browser searchEngine =<< getSelection
|
@@ -1,6 +1,6 @@
|
||||
-----------------------------------------------------------------------------
|
||||
-- |
|
||||
-- Module : Xmonad.Actions.SinkAll
|
||||
-- Module : XMonad.Actions.SinkAll
|
||||
-- License : BSD3-style (see LICENSE)
|
||||
-- Stability : unstable
|
||||
-- Portability : unportable
|
||||
|
@@ -39,6 +39,14 @@ then add appropriate keybindings to warp the pointer; for example:
|
||||
> | (key, sc) <- zip [xK_w, xK_e, xK_r] [0..]]
|
||||
|
||||
Note that warping to a particular screen may change the focus.
|
||||
|
||||
'warpToScreen' and 'warpToWindow' can be used in a variety of
|
||||
ways. Suppose you wanted to emulate Ratpoison's \'banish\' command,
|
||||
which moves the mouse pointer to a corner; you could define:
|
||||
|
||||
> banish :: X ()
|
||||
> banish = warpToWindow 1 1 -- lower left
|
||||
|
||||
-}
|
||||
|
||||
-- For detailed instructions on editing your key bindings, see
|
||||
|
@@ -41,8 +41,8 @@ import XMonad.Actions.CopyWindow
|
||||
import XMonad.Actions.DynamicWorkspaces
|
||||
import XMonad.Actions.RotView
|
||||
|
||||
--import XMonad.Hooks.ManageDocks
|
||||
--import XMonad.Hooks.UrgencyHook
|
||||
import XMonad.Hooks.ManageDocks
|
||||
import XMonad.Hooks.UrgencyHook
|
||||
|
||||
myXPConfig :: XPConfig
|
||||
myXPConfig = defaultXPConfig {font="-*-lucida-medium-r-*-*-14-*-*-*-*-*-*-*"
|
||||
@@ -77,7 +77,7 @@ keys x = M.fromList $
|
||||
|
||||
-- quit, or restart
|
||||
, ((modMask x .|. shiftMask, xK_Escape), io (exitWith ExitSuccess)) -- %! Quit xmonad
|
||||
, ((modMask x , xK_Escape), broadcastMessage ReleaseResources >> restart (Just "xmonad") True) -- %! Restart xmonad
|
||||
, ((modMask x , xK_Escape), restart "xmonad" True) -- %! Restart xmonad
|
||||
|
||||
, ((modMask x .|. shiftMask, xK_z ),
|
||||
layoutScreens 1 (fixedLayout [Rectangle 0 0 1024 768]))
|
||||
@@ -127,13 +127,15 @@ keys x = M.fromList $
|
||||
zip (zip (repeat (modMask x .|. shiftMask)) [xK_F1..xK_F12]) (map (withNthWorkspace copy) [0..])
|
||||
|
||||
config = -- withUrgencyHook FocusUrgencyHook $
|
||||
withUrgencyHook NoUrgencyHook $
|
||||
defaultConfig
|
||||
{ borderWidth = 1 -- Width of the window border in pixels.
|
||||
, XMonad.workspaces = ["1:mutt","2:iceweasel"]
|
||||
, layoutHook = workspaceDir "~" $ windowNavigation $
|
||||
toggleLayouts (noBorders Full) $ -- avoidStruts $
|
||||
toggleLayouts (noBorders Full) $ avoidStruts $
|
||||
Named "tabbed" (noBorders mytab) |||
|
||||
Named "xclock" (mytab ****//* combineTwo Square mytab mytab) |||
|
||||
Named "three" (mytab **//* mytab *//* combineTwo Square mytab mytab) |||
|
||||
Named "widescreen" ((mytab *||* mytab)
|
||||
****//* combineTwo Square mytab mytab) -- |||
|
||||
--mosaic 0.25 0.5
|
||||
|
@@ -20,7 +20,7 @@ import System.IO (hPutStrLn)
|
||||
sjanssenConfig = do
|
||||
xmobar <- spawnPipe "xmobar"
|
||||
return $ defaultConfig
|
||||
{ terminal = "urxvt"
|
||||
{ terminal = "urxvtc"
|
||||
, workspaces = ["irc", "web"] ++ map show [3 .. 7 :: Int] ++ ["mail", "im"]
|
||||
, logHook = dynamicLogWithPP $ sjanssenPP { ppOutput = hPutStrLn xmobar }
|
||||
, modMask = mod4Mask
|
||||
|
@@ -178,7 +178,7 @@ a (possibly empty) 'XMonad.StackSet.stack' of windows.
|
||||
"XMonad.StackSet" (which should usually be imported qualified, to
|
||||
avoid name clashes with Prelude functions such as 'Prelude.delete' and
|
||||
'Prelude.filter') provides many pure functions to manipulate the
|
||||
'XMonad.StackSet.StackSet'. These functions are most commonlyq used as
|
||||
'XMonad.StackSet.StackSet'. These functions are most commonly used as
|
||||
an argument to 'XMonad.Operations.windows', which takes a pure
|
||||
function to manipulate the 'XMonad.Core.WindowSet' and does all the
|
||||
needed operations to refresh the screen and save the modified
|
||||
@@ -246,7 +246,7 @@ xmonad contributed extensions.
|
||||
* Comment every top level function (particularly exported funtions), and
|
||||
provide a type signature.
|
||||
|
||||
* Use Haddock syntax in the comments.
|
||||
* Use Haddock syntax in the comments (see below).
|
||||
|
||||
* Follow the coding style of the other modules.
|
||||
|
||||
@@ -260,6 +260,31 @@ xmonad contributed extensions.
|
||||
* Any pure function added to the core should have QuickCheck properties
|
||||
precisely defining its behaviour.
|
||||
|
||||
For examples of Haddock documentation syntax, have a look at other
|
||||
extensions. Important points are:
|
||||
|
||||
* Every exported function (or even better, every function) should have
|
||||
a Haddock comment explaining what it does.
|
||||
|
||||
* Literal chunks of code can be written in comments using
|
||||
\"birdtrack\" notation (a greater-than symbol at the beginning of
|
||||
each line). Be sure to leave a blank line before and after each
|
||||
birdtrack-quoted section.
|
||||
|
||||
* Link to functions by surrounding the names in single quotes, modules
|
||||
in double quotes.
|
||||
|
||||
* Literal quote marks and slashes should be escaped with a backslash.
|
||||
|
||||
To generate and view the Haddock documentation for your extension, run
|
||||
|
||||
> runhaskell Setup haddock
|
||||
|
||||
and then point your browser to @\/path\/to\/XMonadContrib\/dist\/doc\/html\/xmonad-contrib\/index.html@.
|
||||
|
||||
For more information, see the Haddock documentation:
|
||||
<http://www.haskell.org/haddock/haddock-html-0.8/index.html>.
|
||||
|
||||
-}
|
||||
|
||||
{- $license
|
||||
|
@@ -152,6 +152,9 @@ edit your key bindings.
|
||||
|
||||
* "XMonad.Actions.RotView": cycle through non-empty workspaces.
|
||||
|
||||
* "XMonad.Actions.Search": provide helpful functions for easily
|
||||
running web searchs.
|
||||
|
||||
* "XMonad.Actions.SimpleDate": display the date in a popup menu.
|
||||
|
||||
* "XMonad.Actions.SinkAll": sink all floating windows.
|
||||
@@ -226,6 +229,9 @@ Here is a list of the modules found in @XMonad.Hooks@:
|
||||
|
||||
* "XMonad.Hooks.ManageDocks": handle DOCK and STRUT windows appropriately.
|
||||
|
||||
* "XMonad.Hooks.ManageHelpers": provide helper functions to be used
|
||||
in @manageHook@.
|
||||
|
||||
* "XMonad.Hooks.SetWMName": set the WM name. Useful when e.g. running
|
||||
Java GUI programs.
|
||||
|
||||
@@ -307,6 +313,8 @@ For more information on using those modules for customizing your
|
||||
* "XMonad.Layout.Roledex": a \"completely pointless layout which acts
|
||||
like Microsoft's Flip 3D\".
|
||||
|
||||
* "XMonad.Layout.ShowWName": Show the name of the current workspace when switching.
|
||||
|
||||
* "XMonad.Layout.Spiral": Fibonacci spiral layout.
|
||||
|
||||
* "XMonad.Layout.Square": split the screen into a square area plus the rest.
|
||||
|
@@ -10,17 +10,18 @@
|
||||
--
|
||||
-- DynamicLog
|
||||
--
|
||||
-- Log events in:
|
||||
-- By default, log events in:
|
||||
--
|
||||
-- > 1 2 [3] 4 8
|
||||
--
|
||||
-- format. Suitable to pipe into dzen.
|
||||
-- format, although the format is highly customizable.
|
||||
-- Suitable to pipe into dzen or xmobar.
|
||||
--
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
module XMonad.Hooks.DynamicLog (
|
||||
-- * Usage
|
||||
-- $usage
|
||||
-- $usage
|
||||
dynamicLog,
|
||||
dynamicLogDzen,
|
||||
dynamicLogXmobar,
|
||||
@@ -37,7 +38,7 @@ module XMonad.Hooks.DynamicLog (
|
||||
makeSimpleDzenConfig
|
||||
) where
|
||||
|
||||
--
|
||||
--
|
||||
-- Useful imports
|
||||
--
|
||||
import XMonad
|
||||
@@ -45,12 +46,13 @@ import Data.Maybe ( isJust )
|
||||
import Data.List
|
||||
import Data.Ord ( comparing )
|
||||
import qualified XMonad.StackSet as S
|
||||
import Data.Monoid
|
||||
import System.IO
|
||||
import XMonad.Util.WorkspaceCompare
|
||||
import XMonad.Util.NamedWindows
|
||||
import XMonad.Util.Run
|
||||
import XMonad.Hooks.UrgencyHook
|
||||
|
||||
-- $usage
|
||||
-- $usage
|
||||
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
|
||||
--
|
||||
-- > import XMonad
|
||||
@@ -67,9 +69,9 @@ makeSimpleDzenConfig = do
|
||||
, logHook = dynamicLogWithPP dzenPP
|
||||
{ ppOutput = hPutStrLn h } }
|
||||
|
||||
-- |
|
||||
-- |
|
||||
--
|
||||
-- Run xmonad with a dzen status bar set to some nice defaults. Output
|
||||
-- Run xmonad with a dzen status bar set to some nice defaults. Output
|
||||
-- is taken from the dynamicLogWithPP hook.
|
||||
--
|
||||
-- > main = dzen xmonad
|
||||
@@ -104,13 +106,15 @@ dynamicLog = dynamicLogWithPP defaultPP
|
||||
-- A log function that uses the 'PP' hooks to customize output.
|
||||
dynamicLogWithPP :: PP -> X ()
|
||||
dynamicLogWithPP pp = do
|
||||
spaces <- asks (workspaces . config)
|
||||
winset <- gets windowset
|
||||
urgents <- readUrgents
|
||||
sort' <- getSortByTag
|
||||
-- layout description
|
||||
ld <- withWindowSet $ return . description . S.layout . S.workspace . S.current
|
||||
let ld = description . S.layout . S.workspace . S.current $ winset
|
||||
-- workspace list
|
||||
ws <- withWindowSet $ return . pprWindowSet spaces pp
|
||||
let ws = pprWindowSet sort' urgents pp winset
|
||||
-- window title
|
||||
wt <- withWindowSet $ maybe (return "") (fmap show . getName) . S.peek
|
||||
wt <- maybe (return "") (fmap show . getName) . S.peek $ winset
|
||||
|
||||
io . ppOutput pp . sepBy (ppSep pp) . ppOrder pp $
|
||||
[ ws
|
||||
@@ -124,27 +128,18 @@ dynamicLogWithPP pp = do
|
||||
dynamicLogDzen :: X ()
|
||||
dynamicLogDzen = dynamicLogWithPP dzenPP
|
||||
|
||||
|
||||
pprWindowSet :: [String] -> PP -> WindowSet -> String
|
||||
pprWindowSet spaces pp s = sepBy (ppWsSep pp) $ map fmt $ sortBy cmp
|
||||
(map S.workspace (S.current s : S.visible s) ++ S.hidden s)
|
||||
where f Nothing Nothing = EQ
|
||||
f (Just _) Nothing = LT
|
||||
f Nothing (Just _) = GT
|
||||
f (Just x) (Just y) = compare x y
|
||||
|
||||
wsIndex = flip elemIndex spaces . S.tag
|
||||
|
||||
cmp a b = f (wsIndex a) (wsIndex b) `mappend` compare (S.tag a) (S.tag b)
|
||||
|
||||
this = S.tag (S.workspace (S.current s))
|
||||
pprWindowSet :: ([WindowSpace] -> [WindowSpace]) -> [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))
|
||||
visibles = map (S.tag . S.workspace) (S.visible s)
|
||||
|
||||
fmt w = printer pp (S.tag w)
|
||||
where printer | S.tag w == this = ppCurrent
|
||||
| S.tag w `elem` visibles = ppVisible
|
||||
| isJust (S.stack w) = ppHidden
|
||||
| otherwise = ppHiddenNoWindows
|
||||
where printer | S.tag w == this = ppCurrent
|
||||
| S.tag w `elem` visibles = ppVisible
|
||||
| any (\x -> maybe False (== S.tag w) (S.findTag x s)) urgents = \ppC -> ppUrgent ppC . ppHidden ppC
|
||||
| isJust (S.stack w) = ppHidden
|
||||
| otherwise = ppHiddenNoWindows
|
||||
|
||||
-- |
|
||||
-- Workspace logger with a format designed for Xinerama:
|
||||
@@ -198,7 +193,8 @@ xmobarColor fg bg = wrap t "</fc>"
|
||||
-- | The 'PP' type allows the user to customize various behaviors of
|
||||
-- dynamicLogPP
|
||||
data PP = PP { ppCurrent, ppVisible
|
||||
, ppHidden, ppHiddenNoWindows :: WorkspaceId -> String
|
||||
, ppHidden, ppHiddenNoWindows
|
||||
, ppUrgent :: WorkspaceId -> String
|
||||
, ppSep, ppWsSep :: String
|
||||
, ppTitle :: String -> String
|
||||
, ppLayout :: String -> String
|
||||
@@ -212,6 +208,7 @@ defaultPP = PP { ppCurrent = wrap "[" "]"
|
||||
, ppVisible = wrap "<" ">"
|
||||
, ppHidden = id
|
||||
, ppHiddenNoWindows = const ""
|
||||
, ppUrgent = id
|
||||
, ppSep = " : "
|
||||
, ppWsSep = " "
|
||||
, ppTitle = shorten 80
|
||||
@@ -226,6 +223,7 @@ dzenPP = defaultPP { ppCurrent = dzenColor "white" "#2b4f98" . pad
|
||||
, ppVisible = dzenColor "black" "#999999" . pad
|
||||
, ppHidden = dzenColor "black" "#cccccc" . pad
|
||||
, ppHiddenNoWindows = const ""
|
||||
, ppUrgent = dzenColor "red" "yellow"
|
||||
, ppWsSep = ""
|
||||
, ppSep = ""
|
||||
, ppLayout = dzenColor "black" "#cccccc" .
|
||||
@@ -247,7 +245,7 @@ sjanssenPP = defaultPP { ppCurrent = xmobarColor "white" "#ff000000"
|
||||
|
||||
-- | These are good defaults to be used with the xmobar status bar
|
||||
dynamicLogXmobar :: X ()
|
||||
dynamicLogXmobar =
|
||||
dynamicLogXmobar =
|
||||
dynamicLogWithPP defaultPP { ppCurrent = xmobarColor "yellow" "" . wrap "[" "]"
|
||||
, ppTitle = xmobarColor "green" "" . shorten 40
|
||||
, ppVisible = wrap "(" ")"
|
||||
|
@@ -17,15 +17,15 @@ module XMonad.Hooks.EwmhDesktops (
|
||||
ewmhDesktopsLogHook
|
||||
) where
|
||||
|
||||
import Data.List (elemIndex, sortBy)
|
||||
import Data.Ord (comparing)
|
||||
import Data.Maybe (fromMaybe)
|
||||
import Data.List
|
||||
import Data.Maybe
|
||||
|
||||
import XMonad
|
||||
import Control.Monad
|
||||
import qualified XMonad.StackSet as W
|
||||
|
||||
import XMonad.Hooks.SetWMName
|
||||
import XMonad.Util.WorkspaceCompare
|
||||
|
||||
-- $usage
|
||||
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
|
||||
@@ -48,9 +48,8 @@ import XMonad.Hooks.SetWMName
|
||||
-- of the current state of workspaces and windows.
|
||||
ewmhDesktopsLogHook :: X ()
|
||||
ewmhDesktopsLogHook = withWindowSet $ \s -> do
|
||||
-- Bad hack because xmonad forgets the original order of things, it seems
|
||||
-- see http://code.google.com/p/xmonad/issues/detail?id=53
|
||||
let ws = sortBy (comparing W.tag) $ W.workspaces s
|
||||
sort' <- getSortByTag
|
||||
let ws = sort' $ W.workspaces s
|
||||
let wins = W.allWindows s
|
||||
|
||||
setSupported
|
||||
@@ -62,18 +61,26 @@ ewmhDesktopsLogHook = withWindowSet $ \s -> do
|
||||
setDesktopNames (map W.tag ws)
|
||||
|
||||
-- Current desktop
|
||||
fromMaybe (return ()) $ do
|
||||
n <- W.lookupWorkspace 0 s
|
||||
i <- elemIndex n $ map W.tag ws
|
||||
return $ setCurrentDesktop i
|
||||
let curr = fromJust $ elemIndex (W.tag (W.workspace (W.current s))) $ map W.tag ws
|
||||
|
||||
setCurrentDesktop curr
|
||||
|
||||
setClientList wins
|
||||
|
||||
-- Per window Desktop
|
||||
forM (zip ws [(0::Int)..]) $ \(w, wn) ->
|
||||
forM (W.integrate' (W.stack w)) $ \win -> do
|
||||
-- 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
|
||||
|
||||
setActiveWindow
|
||||
|
||||
return ()
|
||||
|
||||
|
||||
@@ -98,7 +105,7 @@ setDesktopNames names = withDisplay $ \dpy -> do
|
||||
a <- getAtom "_NET_DESKTOP_NAMES"
|
||||
c <- getAtom "UTF8_STRING"
|
||||
let names' = map (fromIntegral.fromEnum) $
|
||||
concatMap (("Workspace "++) . (++['\0'])) names
|
||||
concatMap (++['\0']) names
|
||||
io $ changeProperty8 dpy r a c propModeReplace names'
|
||||
|
||||
setClientList :: [Window] -> X ()
|
||||
@@ -122,9 +129,23 @@ setSupported = withDisplay $ \dpy -> do
|
||||
r <- asks theRoot
|
||||
a <- getAtom "_NET_SUPPORTED"
|
||||
c <- getAtom "ATOM"
|
||||
supp <- mapM getAtom ["_NET_WM_STATE_HIDDEN"]
|
||||
supp <- mapM getAtom ["_NET_WM_STATE_HIDDEN"
|
||||
,"_NET_NUMBER_OF_DESKTOPS"
|
||||
,"_NET_CLIENT_LIST"
|
||||
,"_NET_CURRENT_DESKTOP"
|
||||
,"_NET_DESKTOP_NAMES"
|
||||
,"_NET_ACTIVE_WINDOW"
|
||||
,"_NET_WM_DESKTOP"
|
||||
,"_NET_WM_STRUT"
|
||||
]
|
||||
io $ changeProperty32 dpy r a c propModeReplace (fmap fromIntegral supp)
|
||||
|
||||
setWMName "xmonad"
|
||||
|
||||
|
||||
setActiveWindow :: X ()
|
||||
setActiveWindow = withWindowSet $ \s -> withDisplay $ \dpy -> do
|
||||
let w = fromMaybe 0 (W.peek s)
|
||||
r <- asks theRoot
|
||||
a <- getAtom "_NET_ACTIVE_WINDOW"
|
||||
c <- getAtom "WINDOW"
|
||||
io $ changeProperty32 dpy r a c propModeReplace [fromIntegral w]
|
||||
|
@@ -24,7 +24,9 @@ module XMonad.Hooks.ManageDocks (
|
||||
-----------------------------------------------------------------------------
|
||||
import XMonad
|
||||
import Foreign.C.Types (CLong)
|
||||
import Data.Maybe (catMaybes)
|
||||
-- import Data.Maybe (catMaybes, fromMaybe)
|
||||
import Control.Monad
|
||||
|
||||
-- $usage
|
||||
-- To use this module, add the following import to @~\/.xmonad\/xmonad.hs@:
|
||||
--
|
||||
@@ -40,12 +42,15 @@ import Data.Maybe (catMaybes)
|
||||
-- so-called "gap" support. First, you must add it to your list of layouts:
|
||||
--
|
||||
-- > layoutHook = avoidStruts (tall ||| mirror tall ||| ...)
|
||||
-- > where tall = Tall 1 (3/100) (1/2)
|
||||
--
|
||||
-- 'AvoidStruts' also supports toggling the dock gap, add a keybinding similar
|
||||
-- to:
|
||||
--
|
||||
-- > ,((modMask, xK_b ), sendMessage ToggleStruts)
|
||||
-- > ,((modMask x, xK_b ), sendMessage ToggleStruts)
|
||||
--
|
||||
-- For detailed instructions on editing your key bindings, see
|
||||
-- "XMonad.Doc.Extending#Editing_key_bindings".
|
||||
|
||||
-- |
|
||||
-- Detects if the given window is of type DOCK and if so, reveals it, but does
|
||||
@@ -54,29 +59,35 @@ manageDocks :: ManageHook
|
||||
manageDocks = checkDock --> doIgnore
|
||||
|
||||
-- |
|
||||
-- Checks if a window is a DOCK window
|
||||
-- Checks if a window is a DOCK or DESKTOP window
|
||||
checkDock :: Query Bool
|
||||
checkDock = ask >>= \w -> liftX $ do
|
||||
a <- getAtom "_NET_WM_WINDOW_TYPE"
|
||||
d <- getAtom "_NET_WM_WINDOW_TYPE_DOCK"
|
||||
dock <- getAtom "_NET_WM_WINDOW_TYPE_DOCK"
|
||||
desk <- getAtom "_NET_WM_WINDOW_TYPE_DESKTOP"
|
||||
mbr <- getProp a w
|
||||
case mbr of
|
||||
Just [r] -> return (fromIntegral r == d)
|
||||
Just [r] -> return $ elem (fromIntegral r) [dock, desk]
|
||||
_ -> return False
|
||||
|
||||
-- |
|
||||
-- Gets the STRUT config, if present, in xmonad gap order
|
||||
getStrut :: Window -> X (Maybe (Int, Int, Int, Int))
|
||||
getStrut :: Window -> X [Strut]
|
||||
getStrut w = do
|
||||
a <- getAtom "_NET_WM_STRUT"
|
||||
mbr <- getProp a w
|
||||
case mbr of
|
||||
Just [l,r,t,b] -> return (Just (
|
||||
fromIntegral t,
|
||||
fromIntegral b,
|
||||
fromIntegral l,
|
||||
fromIntegral r))
|
||||
_ -> return Nothing
|
||||
spa <- getAtom "_NET_WM_STRUT_PARTIAL"
|
||||
sa <- getAtom "_NET_WM_STRUT"
|
||||
msp <- getProp spa w
|
||||
case msp of
|
||||
Just sp -> return $ parseStrutPartial sp
|
||||
Nothing -> fmap (maybe [] parseStrut) $ getProp sa w
|
||||
where
|
||||
parseStrut xs@[_, _, _, _] = parseStrutPartial . take 12 $ xs ++ cycle [minBound, maxBound]
|
||||
parseStrut _ = []
|
||||
|
||||
parseStrutPartial [l, r, t, b, ly1, ly2, ry1, ry2, tx1, tx2, bx1, bx2]
|
||||
= filter (\(_, n, _, _) -> n /= 0)
|
||||
[(L, l, ly1, ly2), (R, r, ry1, ry2), (T, t, tx1, tx2), (B, b, bx1, bx2)]
|
||||
parseStrutPartial _ = []
|
||||
|
||||
-- |
|
||||
-- Helper to read a property
|
||||
@@ -86,48 +97,28 @@ getProp a w = withDisplay $ \dpy -> io $ getWindowProperty32 dpy a w
|
||||
-- |
|
||||
-- Goes through the list of windows and find the gap so that all STRUT
|
||||
-- settings are satisfied.
|
||||
calcGap :: X Rectangle
|
||||
calcGap :: X (Rectangle -> Rectangle)
|
||||
calcGap = withDisplay $ \dpy -> do
|
||||
rootw <- asks theRoot
|
||||
-- We don't keep track of dock like windows, so we find all of them here
|
||||
(_,_,wins) <- io $ queryTree dpy rootw
|
||||
struts <- catMaybes `fmap` mapM getStrut wins
|
||||
struts <- concat `fmap` mapM getStrut wins
|
||||
|
||||
-- we grab the window attributes of the root window rather than checking
|
||||
-- the width of the screen because xlib caches this info and it tends to
|
||||
-- be incorrect after RAndR
|
||||
wa <- io $ getWindowAttributes dpy rootw
|
||||
return $ reduceScreen (foldl max4 (0,0,0,0) struts)
|
||||
$ Rectangle (fi $ wa_x wa) (fi $ wa_y wa) (fi $ wa_width wa) (fi $ wa_height wa)
|
||||
|
||||
-- |
|
||||
-- Piecewise maximum of a 4-tuple of Ints
|
||||
max4 :: (Int, Int, Int, Int) -> (Int, Int, Int, Int) -> (Int, Int, Int, Int)
|
||||
max4 (a1,a2,a3,a4) (b1,b2,b3,b4) = (max a1 b1, max a2 b2, max a3 b3, max a4 b4)
|
||||
let screen = r2c $ Rectangle (fi $ wa_x wa) (fi $ wa_y wa) (fi $ wa_width wa) (fi $ wa_height wa)
|
||||
return $ \r -> c2r $ foldr (reduce screen) (r2c r) struts
|
||||
|
||||
fi :: (Integral a, Num b) => a -> b
|
||||
fi = fromIntegral
|
||||
|
||||
-- | Given strut values and the screen rectangle, compute a reduced screen
|
||||
-- rectangle.
|
||||
reduceScreen :: (Int, Int, Int, Int) -> Rectangle -> Rectangle
|
||||
reduceScreen (t, b, l, r) (Rectangle rx ry rw rh)
|
||||
= Rectangle (rx + fi l) (ry + fi t) (rw - fi r) (rh - fi b)
|
||||
r2c :: Rectangle -> RectC
|
||||
r2c (Rectangle x y w h) = (fi x, fi y, fi x + fi w, fi y + fi h)
|
||||
|
||||
r2c :: Rectangle -> (Position, Position, Position, Position)
|
||||
r2c (Rectangle x y w h) = (x, y, x + fi w, y + fi h)
|
||||
|
||||
c2r :: (Position, Position, Position, Position) -> Rectangle
|
||||
c2r (x1, y1, x2, y2) = Rectangle x1 y1 (fi $ x2 - x1) (fi $ y2 - y1)
|
||||
|
||||
-- | Given a bounding rectangle 's' and another rectangle 'r', compute a
|
||||
-- rectangle 'r' that fits inside 's'.
|
||||
fitRect :: Rectangle -> Rectangle -> Rectangle
|
||||
fitRect s r
|
||||
= c2r (max sx1 rx1, max sy1 ry1, min sx2 rx2, min sy2 ry2)
|
||||
where
|
||||
(sx1, sy1, sx2, sy2) = r2c s
|
||||
(rx1, ry1, rx2, ry2) = r2c r
|
||||
c2r :: RectC -> Rectangle
|
||||
c2r (x1, y1, x2, y2) = Rectangle (fi x1) (fi y1) (fi $ x2 - x1) (fi $ y2 - y1)
|
||||
|
||||
-- | Adjust layout automagically.
|
||||
avoidStruts :: LayoutClass l a => l a -> AvoidStruts l a
|
||||
@@ -140,7 +131,7 @@ instance Message ToggleStruts
|
||||
|
||||
instance LayoutClass l a => LayoutClass (AvoidStruts l) a where
|
||||
doLayout (AvoidStruts True lo) r s =
|
||||
do rect <- fmap (flip fitRect r) calcGap
|
||||
do rect <- fmap ($ r) calcGap
|
||||
(wrs,mlo') <- doLayout lo rect s
|
||||
return (wrs, AvoidStruts True `fmap` mlo')
|
||||
doLayout (AvoidStruts False lo) r s = do (wrs,mlo') <- doLayout lo r s
|
||||
@@ -150,3 +141,22 @@ instance LayoutClass l a => LayoutClass (AvoidStruts l) a where
|
||||
| otherwise = do ml' <- handleMessage l m
|
||||
return (AvoidStruts b `fmap` ml')
|
||||
description (AvoidStruts _ l) = description l
|
||||
|
||||
data Side = L | R | T | B
|
||||
|
||||
type Strut = (Side, CLong, CLong, CLong)
|
||||
|
||||
type RectC = (CLong, CLong, CLong, CLong)
|
||||
|
||||
reduce :: RectC -> Strut -> RectC -> RectC
|
||||
reduce (sx0, sy0, sx1, sy1) (s, n, l, h) (x0, y0, x1, y1) = case s of
|
||||
L | p (y0, y1) -> (mx x0 sx0 , y0 , x1 , y1 )
|
||||
R | p (y0, y1) -> (x0 , y0 , mn x1 sx1, y1 )
|
||||
T | p (x0, x1) -> (x0 , mx y0 sy0, x1 , y1 )
|
||||
B | p (x0, x1) -> (x0 , y0 , x1 , mn y1 sy1)
|
||||
_ -> (x0 , y0 , x1 , y1 )
|
||||
where
|
||||
mx a b = max a (b + n)
|
||||
mn a b = min a (b - n)
|
||||
inRange (a, b) c = c > a && c < b
|
||||
p (a, b) = inRange (a, b) l || inRange (a, b) h || inRange (a, b) l || inRange (l, h) b
|
||||
|
130
XMonad/Hooks/ManageHelpers.hs
Normal file
130
XMonad/Hooks/ManageHelpers.hs
Normal file
@@ -0,0 +1,130 @@
|
||||
-----------------------------------------------------------------------------
|
||||
-- |
|
||||
-- Module : XMonad.Hooks.ManageHelpers
|
||||
-- Copyright : (c) Lukas Mai
|
||||
-- License : BSD
|
||||
--
|
||||
-- Maintainer : Lukas Mai <l.mai@web.de>
|
||||
-- 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 =
|
||||
-- > xmonad defaultConfig{
|
||||
-- > ...
|
||||
-- > manageHook = composeOne [
|
||||
-- > isKDETrayWindow -?> doIgnore,
|
||||
-- > transience,
|
||||
-- > resource =? "stalonetray" -?> doIgnore
|
||||
-- > ],
|
||||
-- > ...
|
||||
-- > }
|
||||
|
||||
module XMonad.Hooks.ManageHelpers (
|
||||
composeOne,
|
||||
(-?>), (/=?), (<==?), (</=?), (-->>), (-?>>),
|
||||
isKDETrayWindow,
|
||||
transientTo,
|
||||
maybeToDefinite,
|
||||
MaybeManageHook,
|
||||
transience,
|
||||
transience'
|
||||
) where
|
||||
|
||||
import XMonad
|
||||
import qualified XMonad.StackSet as W
|
||||
|
||||
import Data.Maybe
|
||||
import Data.Monoid
|
||||
|
||||
-- | 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
|
||||
-- This is analogous to group types in regular expressions
|
||||
-- TODO create a better API for aggregating multiple Matches logically
|
||||
data Match a = Match Bool a
|
||||
|
||||
-- | An alternative 'ManageHook' composer. Unlike 'composeAll' it stops as soon as
|
||||
-- a candidate returns a 'Just' value, effectively running only the first match
|
||||
-- (whereas 'composeAll' continues and executes all matching rules).
|
||||
composeOne :: [MaybeManageHook] -> ManageHook
|
||||
composeOne = foldr try idHook
|
||||
where
|
||||
try q z = do
|
||||
x <- q
|
||||
case x of
|
||||
Just h -> return h
|
||||
Nothing -> z
|
||||
|
||||
infixr 0 -?>, -->>, -?>>
|
||||
|
||||
-- | q \/=? x. if the result of q equals x, return False
|
||||
(/=?) :: Eq a => Query a -> a -> Query Bool
|
||||
q /=? x = fmap (/= x) q
|
||||
|
||||
-- | q <==? x. if the result of q equals x, return True grouped with q
|
||||
(<==?) :: Eq a => Query a -> a -> Query (Match a)
|
||||
q <==? x = fmap (`eq` x) q
|
||||
where eq q' x' = Match (q' == x') q'
|
||||
|
||||
-- | q <\/=? x. if the result of q notequals x, return True grouped with q
|
||||
(</=?) :: Eq a => Query a -> a -> Query (Match a)
|
||||
q </=? x = fmap (`neq` x) q
|
||||
where neq q' x' = Match (q' /= x') q'
|
||||
|
||||
-- | A helper operator for use in 'composeOne'. It takes a condition and an action;
|
||||
-- if the condition fails, it returns 'Nothing' from the 'Query' so 'composeOne' will
|
||||
-- go on and try the next rule.
|
||||
(-?>) :: Query Bool -> ManageHook -> MaybeManageHook
|
||||
p -?> f = do
|
||||
x <- p
|
||||
if x then fmap Just f else return Nothing
|
||||
|
||||
-- | A helper operator for use in 'composeAll'. It takes a condition and a function taking a grouped datum to action. If 'p' is true, it executes the resulting action.
|
||||
(-->>) :: Query (Match a) -> (a -> ManageHook) -> ManageHook
|
||||
p -->> f = do Match b m <- p
|
||||
if b then (f m) else mempty
|
||||
|
||||
-- | A helper operator for use in 'composeOne'. It takes a condition and a function taking a groupdatum to action. If 'p' is true, it executes the resulting action. If it fails, it returns 'Nothing' from the 'Query' so 'composeOne' will go on and try the next rule.
|
||||
(-?>>) :: Query (Match a) -> (a -> ManageHook) -> MaybeManageHook
|
||||
p -?>> f = do Match b m <- p
|
||||
if b then fmap Just (f m) else return Nothing
|
||||
|
||||
-- | A predicate to check whether a window is a KDE system tray icon.
|
||||
isKDETrayWindow :: Query Bool
|
||||
isKDETrayWindow = ask >>= \w -> liftX $ do
|
||||
dpy <- asks display
|
||||
kde_tray <- getAtom "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR"
|
||||
r <- io $ getWindowProperty32 dpy kde_tray w
|
||||
return $ case r of
|
||||
Just [_] -> True
|
||||
_ -> False
|
||||
|
||||
-- | 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'.
|
||||
transientTo :: Query (Maybe Window)
|
||||
transientTo = do w <- ask
|
||||
d <- (liftX . asks) display
|
||||
liftIO $ getTransientForHint d w
|
||||
|
||||
-- | A convenience 'MaybeManageHook' that will check to see if a window
|
||||
-- is transient, and then move it to it's parent.
|
||||
transience :: MaybeManageHook
|
||||
transience = transientTo </=? Nothing
|
||||
-?>> move
|
||||
where move :: Maybe Window -> ManageHook
|
||||
move mw = maybe idHook (doF . move') mw
|
||||
where move' :: Window -> (WindowSet -> WindowSet)
|
||||
move' w = \s -> maybe s (`W.shift` s) (W.findTag w s)
|
||||
|
||||
-- | 'transience' set to a 'ManageHook'
|
||||
transience' :: ManageHook
|
||||
transience' = maybeToDefinite transience
|
||||
|
||||
-- | converts 'MaybeManageHook's to 'ManageHook's
|
||||
maybeToDefinite :: MaybeManageHook -> ManageHook
|
||||
maybeToDefinite = fmap (fromMaybe mempty)
|
@@ -107,7 +107,7 @@ doLay mirror (DragPane mw ty delta split) r s = do
|
||||
mirror $ Rectangle x y (w-halfHandleWidth) h
|
||||
right = case right' of
|
||||
Rectangle x y w h ->
|
||||
mirror $ Rectangle (x+halfHandleWidth) y (w-halfHandleWidth) h
|
||||
mirror $ Rectangle (x+halfHandleWidth) y (w-halfHandleWidth) h
|
||||
handr = case left' of
|
||||
Rectangle x y w h ->
|
||||
mirror $ Rectangle (x + fromIntegral w - halfHandleWidth) y (2*halfHandleWidth) h
|
||||
@@ -131,6 +131,6 @@ doLay mirror (DragPane mw ty delta split) r s = do
|
||||
newDragWin :: Rectangle -> X Window
|
||||
newDragWin r = do
|
||||
let mask = Just $ exposureMask .|. buttonPressMask
|
||||
w <- createNewWindow r mask handleColor
|
||||
w <- createNewWindow r mask handleColor False
|
||||
showWindow w
|
||||
return w
|
||||
|
@@ -17,7 +17,7 @@
|
||||
module XMonad.Layout.Grid (
|
||||
-- * Usage
|
||||
-- $usage
|
||||
Grid(..)
|
||||
Grid(..)
|
||||
) where
|
||||
|
||||
import XMonad
|
||||
|
@@ -30,14 +30,16 @@ import qualified XMonad.StackSet as W
|
||||
-- screen and long for greater flexibility (e.g. being able to see your
|
||||
-- email window at all times, a crude mimic of sticky windows).
|
||||
--
|
||||
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@ file:
|
||||
-- You can use this module with the following in your
|
||||
-- @~\/.xmonad\/xmonad.hs@ file:
|
||||
--
|
||||
-- > import XMonad.Layout.LayoutScreens
|
||||
-- > import XMonad.Layout.TwoPane
|
||||
--
|
||||
-- Then add some keybindings; for example:
|
||||
--
|
||||
-- > , ((modMask .|. shiftMask, xK_space), layoutScreens 2 (TwoPane 0.5 0.5))
|
||||
-- > , ((controlMask .|. modMask .|. shiftMask, xK_space), rescreen)
|
||||
-- > , ((modMask x .|. shiftMask, xK_space), layoutScreens 2 (TwoPane 0.5 0.5))
|
||||
-- > , ((modMask x .|. controlMask .|. shiftMask, xK_space), rescreen)
|
||||
--
|
||||
-- Another example use would be to handle a scenario where xrandr didn't
|
||||
-- work properly (e.g. a VNC X server in my case) and you want to be able
|
||||
@@ -45,9 +47,9 @@ import qualified XMonad.StackSet as W
|
||||
--
|
||||
-- > import XMonad.Layout.LayoutScreens
|
||||
--
|
||||
-- > , ((modMask .|. shiftMask, xK_space),
|
||||
-- > , ((modMask x .|. shiftMask, xK_space),
|
||||
-- > layoutScreens 1 (fixedLayout [Rectangle 0 0 1024 768]))
|
||||
-- > , ((controlMask .|. modMask .|. shiftMask, xK_space), rescreen)
|
||||
-- > , ((modMask x .|. controlMask .|. shiftMask, xK_space), rescreen)
|
||||
--
|
||||
-- For detailed instructions on editing your key bindings, see
|
||||
-- "XMonad.Doc.Extending#Editing_key_bindings".
|
||||
|
@@ -22,6 +22,8 @@ module XMonad.Layout.Magnifier
|
||||
-- $usage
|
||||
magnifier,
|
||||
magnifier',
|
||||
magnifiercz,
|
||||
magnifiercz',
|
||||
MagnifyMsg (..)
|
||||
) where
|
||||
|
||||
@@ -34,12 +36,24 @@ import XMonad.Layout.LayoutModifier
|
||||
--
|
||||
-- > import XMonad.Layout.Magnifier
|
||||
--
|
||||
-- Then edit your @layoutHook@ by adding the Magnifier layout modifier
|
||||
-- Then edit your @layoutHook@ by adding the 'magnifier' layout modifier
|
||||
-- to some layout:
|
||||
--
|
||||
-- > myLayouts = magnifier (Tall 1 (3/100) (1/2)) ||| Full ||| etc..
|
||||
-- > main = xmonad defaultConfig { layoutHook = myLayouts }
|
||||
--
|
||||
-- By default magnifier increases the focused window's size by 1.5.
|
||||
-- You can also use:
|
||||
--
|
||||
-- > magnifiercz (12%10)
|
||||
--
|
||||
-- to use a custom level of magnification. You can even make the focused
|
||||
-- window smaller for a pop in effect. Keep in mind, you must
|
||||
--
|
||||
-- > import Data.Ratio
|
||||
--
|
||||
-- in order to use rationals (such as @12%10@) in your config.
|
||||
--
|
||||
-- For more detailed instructions on editing the layoutHook see:
|
||||
--
|
||||
-- "XMonad.Doc.Extending#Editing_the_layout_hook"
|
||||
@@ -59,11 +73,20 @@ import XMonad.Layout.LayoutModifier
|
||||
magnifier :: l a -> ModifiedLayout Magnifier l a
|
||||
magnifier = ModifiedLayout (Mag 1.5 On All)
|
||||
|
||||
-- | Change the size of the window that has focus by a custom zoom
|
||||
magnifiercz :: Rational -> l a -> ModifiedLayout Magnifier l a
|
||||
magnifiercz cz = ModifiedLayout (Mag ((fromRational cz)*1.0::Double) On All)
|
||||
|
||||
-- | Increase the size of the window that has focus, unless if it is the
|
||||
-- master window.
|
||||
magnifier' :: l a -> ModifiedLayout Magnifier l a
|
||||
magnifier' = ModifiedLayout (Mag 1.5 On NoMaster)
|
||||
|
||||
-- | Increase the size of the window that has focus by a custom zoom,
|
||||
-- unless if it is the master window.
|
||||
magnifiercz' :: Rational -> l a -> ModifiedLayout Magnifier l a
|
||||
magnifiercz' cz = ModifiedLayout (Mag ((fromRational cz)*1.0::Double) On NoMaster)
|
||||
|
||||
data MagnifyMsg = MagnifyMore | MagnifyLess | ToggleOn | ToggleOff deriving ( Typeable )
|
||||
instance Message MagnifyMsg
|
||||
|
||||
|
@@ -23,6 +23,7 @@ module XMonad.Layout.MultiToggle (
|
||||
Toggle(..),
|
||||
(??),
|
||||
EOT(..),
|
||||
single,
|
||||
mkToggle
|
||||
) where
|
||||
|
||||
@@ -39,7 +40,7 @@ import Data.Maybe
|
||||
-- group of radio buttons.
|
||||
--
|
||||
-- A side effect of this meta-layout is that layout transformers no longer
|
||||
-- receive any messages; any message not handled by SwitchTrans itself will
|
||||
-- receive any messages; any message not handled by MultiToggle itself will
|
||||
-- undo the current layout transformer, pass the message on to the base
|
||||
-- layout, then reapply the transformer.
|
||||
--
|
||||
@@ -63,7 +64,7 @@ import Data.Maybe
|
||||
--
|
||||
-- After changing this to
|
||||
--
|
||||
-- > layout = mkToggle (MIRROR ?? EOT) (tiled ||| Full)
|
||||
-- > layout = mkToggle (single MIRROR) (tiled ||| Full)
|
||||
--
|
||||
-- you can now dynamically apply the 'XMonad.Layout.Mirror' transformation:
|
||||
--
|
||||
@@ -81,7 +82,7 @@ import Data.Maybe
|
||||
-- > data NOBORDERS = NOBORDERS deriving (Read, Show, Eq, Typeable)
|
||||
-- > instance Transformer NOBORDERS Window where
|
||||
-- > transform _ x k = k (noBorders x)
|
||||
-- >
|
||||
-- >
|
||||
-- > data FULL = FULL deriving (Read, Show, Eq, Typeable)
|
||||
-- > instance Transformer FULL Window where
|
||||
-- > transform _ x k = k Full
|
||||
@@ -90,7 +91,7 @@ import Data.Maybe
|
||||
-- layout = id
|
||||
-- . 'XMonad.Layout.NoBorders.smartBorders'
|
||||
-- . mkToggle (NOBORDERS ?? FULL ?? EOT)
|
||||
-- . mkToggle (MIRROR ?? EOT)
|
||||
-- . mkToggle (single MIRROR)
|
||||
-- $ tiled ||| 'XMonad.Layout.Grid.Grid' ||| 'XMonad.Layout.Circle.Circle'
|
||||
-- @
|
||||
--
|
||||
@@ -164,6 +165,10 @@ infixr 0 ??
|
||||
(??) :: (HList b w) => a -> b -> HCons a b
|
||||
(??) = HCons
|
||||
|
||||
-- | Construct a singleton transformer table.
|
||||
single :: a -> HCons a EOT
|
||||
single = (?? EOT)
|
||||
|
||||
class HList c a where
|
||||
find :: (Transformer t a) => c -> t -> Maybe Int
|
||||
resolve :: c -> Int -> b -> (forall t. (Transformer t a) => t -> b) -> b
|
||||
@@ -189,7 +194,7 @@ acceptChange :: (LayoutClass l' a) => MultiToggle ts l a -> ((l' a -> MultiToggl
|
||||
acceptChange mt f = fmap (f (\x -> mt{ currLayout = EL x }))
|
||||
|
||||
instance (Typeable a, Show ts, HList ts a, LayoutClass l a) => LayoutClass (MultiToggle ts l) a where
|
||||
description _ = "MultiToggle"
|
||||
description mt = currLayout mt `unEL` \l -> description l
|
||||
|
||||
pureLayout mt r s = currLayout mt `unEL` \l -> pureLayout l r s
|
||||
|
||||
|
@@ -12,6 +12,13 @@
|
||||
--
|
||||
-- Configure layouts on a per-workspace basis. NOTE that this module
|
||||
-- does not (yet) work in conjunction with multiple screens! =(
|
||||
--
|
||||
-- Note also that when using PerWorkspace, on initial startup workspaces
|
||||
-- may not respond to messages properly until a window has been opened.
|
||||
-- This is due to a limitation inherent in the way PerWorkspace is
|
||||
-- implemented: it cannot decide which layout to use until actually
|
||||
-- required to lay out some windows (which does not happen until a window
|
||||
-- is opened).
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
module XMonad.Layout.PerWorkspace (
|
||||
|
119
XMonad/Layout/Reflect.hs
Normal file
119
XMonad/Layout/Reflect.hs
Normal file
@@ -0,0 +1,119 @@
|
||||
{-# OPTIONS_GHC -fglasgow-exts #-}
|
||||
|
||||
-- for now, use -fglasgow-exts for compatibility with ghc 6.6, which chokes
|
||||
-- on some of the LANGUAGE pragmas below
|
||||
{- LANGUAGE FlexibleInstances, MultiParamTypeClasses, DeriveDataTypeable, TypeSynonymInstances -}
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- |
|
||||
-- Module : XMonad.Layout.Reflect
|
||||
-- Copyright : (c) Brent Yorgey
|
||||
-- License : BSD-style (see LICENSE)
|
||||
--
|
||||
-- Maintainer : <byorgey@gmail.com>
|
||||
-- Stability : unstable
|
||||
-- Portability : unportable
|
||||
--
|
||||
-- Reflect a layout horizontally or vertically.
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
module XMonad.Layout.Reflect (
|
||||
-- * Usage
|
||||
-- $usage
|
||||
|
||||
reflectHoriz, reflectVert,
|
||||
REFLECTX(..), REFLECTY(..)
|
||||
|
||||
) where
|
||||
|
||||
import XMonad.Core
|
||||
import Graphics.X11 (Rectangle(..), Window)
|
||||
import Control.Arrow ((***), second)
|
||||
import Control.Applicative ((<$>))
|
||||
|
||||
import XMonad.Layout.MultiToggle
|
||||
|
||||
-- $usage
|
||||
-- You can use this module by importing it into your @~\/.xmonad\/xmonad.hs@ file:
|
||||
--
|
||||
-- > import XMonad.Layout.Reflect
|
||||
--
|
||||
-- and modifying your layoutHook as follows (for example):
|
||||
--
|
||||
-- > layoutHook = reflectHoriz $ Tall 1 (3/100) (1/2) -- put master pane on the right
|
||||
--
|
||||
-- 'reflectHoriz' and 'reflectVert' can be applied to any sort of
|
||||
-- layout (including Mirrored layouts) and will simply flip the
|
||||
-- physical layout of the windows vertically or horizontally.
|
||||
--
|
||||
-- "XMonad.Layout.MultiToggle" transformers are also provided for
|
||||
-- toggling layouts between reflected\/non-reflected with a keybinding.
|
||||
-- To use this feature, you will also need to import the MultiToggle
|
||||
-- module:
|
||||
--
|
||||
-- > import XMonad.Layout.MultiToggle
|
||||
--
|
||||
-- Next, add one or more toggles to your layout. For example, to allow
|
||||
-- separate toggling of both vertical and horizontal reflection:
|
||||
--
|
||||
-- > layoutHook = mkToggle (REFLECTX ?? EOT) $
|
||||
-- > mkToggle (REFLECTY ?? EOT) $
|
||||
-- > (tiled ||| Mirror tiled ||| ...) -- whatever layouts you use
|
||||
--
|
||||
-- Finally, add some keybindings to do the toggling, for example:
|
||||
--
|
||||
-- > , ((modMask x .|. controlMask, xK_x), sendMessage $ Toggle REFLECTX)
|
||||
-- > , ((modMask x .|. controlMask, xK_y), sendMessage $ Toggle REFLECTY)
|
||||
--
|
||||
|
||||
-- | Apply a horizontal reflection (left \<--\> right) to a
|
||||
-- layout.
|
||||
reflectHoriz :: (LayoutClass l a) => (l a) -> Reflect l a
|
||||
reflectHoriz = Reflect Horiz
|
||||
|
||||
-- | Apply a vertical reflection (top \<--\> bottom) to a
|
||||
-- layout.
|
||||
reflectVert :: (LayoutClass l a) => (l a) -> Reflect l a
|
||||
reflectVert = Reflect Vert
|
||||
|
||||
data ReflectDir = Horiz | Vert
|
||||
deriving (Read, Show)
|
||||
|
||||
-- | Given an axis of reflection and the enclosing rectangle which
|
||||
-- contains all the laid out windows, transform a rectangle
|
||||
-- representing a window into its flipped counterpart.
|
||||
reflectRect :: ReflectDir -> Rectangle -> Rectangle -> Rectangle
|
||||
reflectRect Horiz (Rectangle sx _ sw _) (Rectangle rx ry rw rh) =
|
||||
Rectangle (2*sx + fi sw - rx - fi rw) ry rw rh
|
||||
reflectRect Vert (Rectangle _ sy _ sh) (Rectangle rx ry rw rh) =
|
||||
Rectangle rx (2*sy + fi sh - ry - fi rh) rw rh
|
||||
|
||||
fi :: (Integral a, Num b) => a -> b
|
||||
fi = fromIntegral
|
||||
|
||||
|
||||
data Reflect l a = Reflect ReflectDir (l a) deriving (Show, Read)
|
||||
|
||||
instance LayoutClass l a => LayoutClass (Reflect l) a where
|
||||
|
||||
-- do layout l, then reflect all the generated Rectangles.
|
||||
doLayout (Reflect d l) r s = (map (second (reflectRect d r)) *** fmap (Reflect d))
|
||||
<$> doLayout l r s
|
||||
|
||||
-- pass messages on to the underlying layout
|
||||
handleMessage (Reflect d l) = fmap (fmap (Reflect d)) . handleMessage l
|
||||
|
||||
description (Reflect d l) = "Reflect" ++ xy ++ " " ++ description l
|
||||
where xy = case d of { Horiz -> "X" ; Vert -> "Y" }
|
||||
|
||||
|
||||
-------- instances for MultiToggle ------------------
|
||||
|
||||
data REFLECTX = REFLECTX deriving (Read, Show, Eq, Typeable)
|
||||
data REFLECTY = REFLECTY deriving (Read, Show, Eq, Typeable)
|
||||
|
||||
instance Transformer REFLECTX Window where
|
||||
transform REFLECTX x k = k (reflectHoriz x)
|
||||
|
||||
instance Transformer REFLECTY Window where
|
||||
transform REFLECTY x k = k (reflectVert x)
|
@@ -24,6 +24,8 @@ module XMonad.Layout.ResizableTile (
|
||||
import XMonad hiding (splitVertically, splitHorizontallyBy)
|
||||
import qualified XMonad.StackSet as W
|
||||
import Control.Monad
|
||||
import qualified Data.Map as M
|
||||
import Data.List ((\\))
|
||||
|
||||
-- $usage
|
||||
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
|
||||
@@ -58,12 +60,16 @@ instance LayoutClass ResizableTall a where
|
||||
ap zip (tile frac (mfrac ++ repeat 1) r nmaster . length) . W.integrate
|
||||
handleMessage (ResizableTall nmaster delta frac mfrac) m =
|
||||
do ms <- (W.stack . W.workspace . W.current) `fmap` gets windowset
|
||||
case ms of
|
||||
Nothing -> return Nothing
|
||||
Just s -> return $ msum [fmap resize (fromMessage m)
|
||||
,fmap (\x -> mresize x s) (fromMessage m)
|
||||
,fmap incmastern (fromMessage m)]
|
||||
where resize Shrink = ResizableTall nmaster delta (max 0 $ frac-delta) mfrac
|
||||
fs <- (M.keys . W.floating) `fmap` gets windowset
|
||||
return $ ms >>= unfloat fs >>= handleMesg
|
||||
where handleMesg s = msum [fmap resize (fromMessage m)
|
||||
,fmap (\x -> mresize x s) (fromMessage m)
|
||||
,fmap incmastern (fromMessage m)]
|
||||
unfloat fs s = if W.focus s `elem` fs
|
||||
then Nothing
|
||||
else Just (s { W.up = (W.up s) \\ fs
|
||||
, W.down = (W.down s) \\ fs })
|
||||
resize Shrink = ResizableTall nmaster delta (max 0 $ frac-delta) mfrac
|
||||
resize Expand = ResizableTall nmaster delta (min 1 $ frac+delta) mfrac
|
||||
mresize MirrorShrink s = mresize' s delta
|
||||
mresize MirrorExpand s = mresize' s (0-delta)
|
||||
|
104
XMonad/Layout/ShowWName.hs
Normal file
104
XMonad/Layout/ShowWName.hs
Normal file
@@ -0,0 +1,104 @@
|
||||
{-# LANGUAGE PatternGuards, TypeSynonymInstances, MultiParamTypeClasses #-}
|
||||
-----------------------------------------------------------------------------
|
||||
-- |
|
||||
-- Module : XMonad.Layout.ShowWName
|
||||
-- Copyright : (c) Andrea Rossato 2007
|
||||
-- License : BSD-style (see xmonad/LICENSE)
|
||||
--
|
||||
-- Maintainer : andrea.rossato@unibz.it
|
||||
-- Stability : unstable
|
||||
-- Portability : unportable
|
||||
--
|
||||
-- This is a layout modifier that will show the workspace name
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
module XMonad.Layout.ShowWName
|
||||
( -- * Usage
|
||||
-- $usage
|
||||
showWName
|
||||
, showWName'
|
||||
, defaultSWNConfig
|
||||
, SWNConfig(..)
|
||||
) where
|
||||
|
||||
import XMonad
|
||||
import qualified XMonad.StackSet as S
|
||||
import XMonad.Layout.LayoutModifier
|
||||
import XMonad.Util.Font
|
||||
import XMonad.Util.Timer
|
||||
import XMonad.Util.XUtils
|
||||
|
||||
-- $usage
|
||||
-- You can use this module with the following in your
|
||||
-- @~\/.xmonad\/xmonad.hs@:
|
||||
--
|
||||
-- > import XMonad.Layout.ShowWName
|
||||
-- > myLayout = layoutHook defaultConfig
|
||||
-- > main = xmonad defaultConfig { layoutHook = showWName myLayout }
|
||||
--
|
||||
-- For more detailed instructions on editing the layoutHook see:
|
||||
--
|
||||
-- "XMonad.Doc.Extending#Editing_the_layout_hook"
|
||||
|
||||
-- | A layout modifier to show the workspace name when switching
|
||||
showWName :: l a -> ModifiedLayout ShowWName l a
|
||||
showWName = ModifiedLayout (SWN True defaultSWNConfig Nothing)
|
||||
|
||||
-- | A layout modifier to show the workspace name when switching. It
|
||||
-- is possible to provide a costum configuration.
|
||||
showWName' :: SWNConfig -> l a -> ModifiedLayout ShowWName l a
|
||||
showWName' c = ModifiedLayout (SWN True c Nothing)
|
||||
|
||||
type ShowWNState = Maybe (TimerId, Window)
|
||||
data ShowWName a = SWN Bool SWNConfig ShowWNState deriving (Read, Show)
|
||||
|
||||
data SWNConfig =
|
||||
SWNC { swn_font :: String -- ^ Font name
|
||||
, swn_bgcolor :: String -- ^ Backgorund color
|
||||
, swn_color :: String -- ^ String color
|
||||
, swn_fade :: Rational -- ^ Time in seconds of the name visibility
|
||||
} deriving (Read, Show)
|
||||
|
||||
defaultSWNConfig :: SWNConfig
|
||||
defaultSWNConfig =
|
||||
SWNC { swn_font = "-misc-fixed-*-*-*-*-20-*-*-*-*-*-*-*"
|
||||
, swn_bgcolor = "black"
|
||||
, swn_color = "white"
|
||||
, swn_fade = 1
|
||||
}
|
||||
|
||||
instance LayoutModifier ShowWName Window where
|
||||
redoLayout (SWN True c (Just (_,w))) r _ wrs = deleteWindow w >> flashName c r wrs
|
||||
redoLayout (SWN True c Nothing ) r _ wrs = flashName c r wrs
|
||||
redoLayout (SWN False _ _ ) _ _ wrs = return (wrs, Nothing)
|
||||
|
||||
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
|
||||
return . Just $ SWN True c Nothing
|
||||
|
||||
handleMess (SWN _ c s) m
|
||||
| Just Hide <- fromMessage m = return . Just $ SWN True c s
|
||||
| otherwise = return 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)
|
||||
f <- initXMF (swn_font c)
|
||||
width <- textWidthXMF d f n
|
||||
(_,as,ds,_) <- textExtentsXMF f n
|
||||
let hight = as + ds
|
||||
y = (fi ht - hight + 2) `div` 2
|
||||
x = (fi wh - width + 2) `div` 2
|
||||
w <- createNewWindow (Rectangle (fi x) (fi y) (fi width) (fi hight)) Nothing "" True
|
||||
showWindow w
|
||||
paintAndWrite w f (fi width) (fi hight) 0 "" "" (swn_color c) (swn_bgcolor c) AlignCenter n
|
||||
releaseXMF f
|
||||
io $ sync d False
|
||||
i <- startTimer (swn_fade c)
|
||||
return (wrs, Just $ SWN False c $ Just (i,w))
|
||||
|
||||
-- | Short-hand for 'fromIntegral'
|
||||
fi :: (Integral a, Num b) => a -> b
|
||||
fi = fromIntegral
|
@@ -33,6 +33,8 @@ import XMonad.Util.Invisible
|
||||
import XMonad.Util.XUtils
|
||||
import XMonad.Util.Font
|
||||
|
||||
import XMonad.Hooks.UrgencyHook
|
||||
|
||||
-- $usage
|
||||
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
|
||||
--
|
||||
@@ -62,10 +64,13 @@ tabbed s t = Tabbed (I Nothing) s t
|
||||
data TConf =
|
||||
TConf { activeColor :: String
|
||||
, inactiveColor :: String
|
||||
, urgentColor :: String
|
||||
, activeBorderColor :: String
|
||||
, inactiveTextColor :: String
|
||||
, inactiveBorderColor :: String
|
||||
, urgentBorderColor :: String
|
||||
, activeTextColor :: String
|
||||
, inactiveTextColor :: String
|
||||
, urgentTextColor :: String
|
||||
, fontName :: String
|
||||
, tabSize :: Int
|
||||
} deriving (Show, Read)
|
||||
@@ -74,10 +79,13 @@ defaultTConf :: TConf
|
||||
defaultTConf =
|
||||
TConf { activeColor = "#999999"
|
||||
, inactiveColor = "#666666"
|
||||
, urgentColor = "#FFFF00"
|
||||
, activeBorderColor = "#FFFFFF"
|
||||
, inactiveBorderColor = "#BBBBBB"
|
||||
, urgentBorderColor = "##00FF00"
|
||||
, activeTextColor = "#FFFFFF"
|
||||
, inactiveTextColor = "#BFBFBF"
|
||||
, urgentTextColor = "#FF0000"
|
||||
, fontName = "-misc-fixed-*-*-*-*-10-*-*-*-*-*-*-*"
|
||||
, tabSize = 20
|
||||
}
|
||||
@@ -86,7 +94,7 @@ data TabState =
|
||||
TabState { tabsWindows :: [(Window,Window)]
|
||||
, scr :: Rectangle
|
||||
, font :: XMonadFont
|
||||
}
|
||||
}
|
||||
|
||||
data Tabbed s a =
|
||||
Tabbed (Invisible Maybe TabState) s TConf
|
||||
@@ -128,8 +136,8 @@ handleMess _ _ = return Nothing
|
||||
|
||||
handleEvent :: Shrinker s => s -> TConf -> TabState -> Event -> X ()
|
||||
-- button press
|
||||
handleEvent ishr conf (TabState {tabsWindows = tws, scr = screen, font = fs})
|
||||
(ButtonEvent {ev_window = thisw, ev_subwindow = thisbw, ev_event_type = t})
|
||||
handleEvent ishr conf (TabState {tabsWindows = tws, scr = screen, font = fs})
|
||||
(ButtonEvent {ev_window = thisw, ev_subwindow = thisbw, ev_event_type = t })
|
||||
| t == buttonPress, tl <- map fst tws, thisw `elem` tl || thisbw `elem` tl = do
|
||||
case lookup thisw tws of
|
||||
Just x -> do focus x
|
||||
@@ -174,7 +182,7 @@ createTabs c (Rectangle x y wh ht) owl@(ow:ows) = do
|
||||
height = fromIntegral $ tabSize c
|
||||
mask = Just (exposureMask .|. buttonPressMask)
|
||||
d <- asks display
|
||||
w <- createNewWindow (Rectangle x y wid height) mask (inactiveColor c)
|
||||
w <- createNewWindow (Rectangle x y wid height) mask (inactiveColor c) True
|
||||
io $ restackWindows d $ w : [ow]
|
||||
ws <- createTabs c (Rectangle (x + fromIntegral wid) y (wh - wid) ht) ows
|
||||
return (w:ws)
|
||||
@@ -182,18 +190,22 @@ createTabs c (Rectangle x y wh ht) owl@(ow:ows) = do
|
||||
updateTab :: Shrinker s => s -> TConf -> XMonadFont -> Dimension -> (Window,Window) -> X ()
|
||||
updateTab ishr c fs wh (tabw,ow) = do
|
||||
nw <- getName ow
|
||||
ur <- readUrgents
|
||||
let ht = fromIntegral $ tabSize c :: Dimension
|
||||
focusColor win ic ac = (maybe ic (\focusw -> if focusw == win
|
||||
then ac else ic) . W.peek)
|
||||
`fmap` gets windowset
|
||||
focusColor win ic ac uc = (maybe ic (\focusw -> case () of
|
||||
_ | focusw == win -> ac
|
||||
| win `elem` ur -> uc
|
||||
| otherwise -> ic) . W.peek)
|
||||
`fmap` gets windowset
|
||||
(bc',borderc',tc') <- focusColor ow
|
||||
(inactiveColor c, inactiveBorderColor c, inactiveTextColor c)
|
||||
(activeColor c, activeBorderColor c, activeTextColor c)
|
||||
(urgentColor c, urgentBorderColor c, urgentTextColor c)
|
||||
dpy <- asks display
|
||||
let s = shrinkIt ishr
|
||||
name <- shrinkWhile s (\n -> do
|
||||
size <- io $ textWidthXMF dpy fs n
|
||||
return $ size > fromIntegral wh - fromIntegral (ht `div` 2)) (show nw)
|
||||
size <- io $ textWidthXMF dpy fs n
|
||||
return $ size > fromIntegral wh - fromIntegral (ht `div` 2)) (show nw)
|
||||
paintAndWrite tabw fs wh ht 1 bc' borderc' tc' bc' AlignCenter name
|
||||
|
||||
shrink :: TConf -> Rectangle -> Rectangle
|
||||
@@ -205,10 +217,10 @@ shrinkWhile sh p x = sw $ sh x
|
||||
where sw [n] = return n
|
||||
sw [] = return ""
|
||||
sw (n:ns) = do
|
||||
cond <- p n
|
||||
if cond
|
||||
then sw ns
|
||||
else return n
|
||||
cond <- p n
|
||||
if cond
|
||||
then sw ns
|
||||
else return n
|
||||
|
||||
data CustomShrink = CustomShrink
|
||||
instance Show CustomShrink where show _ = ""
|
||||
|
@@ -96,6 +96,7 @@ data XPConfig =
|
||||
, position :: XPPosition -- ^ Position: 'Top' or 'Bottom'
|
||||
, height :: Dimension -- ^ Window height
|
||||
, historySize :: Int -- ^ The number of history entries to be saved
|
||||
, defaultText :: String -- ^ The text by default in the prompt line
|
||||
} deriving (Show, Read)
|
||||
|
||||
data XPType = forall p . XPrompt p => XPT p
|
||||
@@ -135,6 +136,7 @@ defaultXPConfig =
|
||||
, position = Bottom
|
||||
, height = 18
|
||||
, historySize = 256
|
||||
, defaultText = []
|
||||
}
|
||||
|
||||
type ComplFunction = String -> IO [String]
|
||||
@@ -142,7 +144,21 @@ type ComplFunction = String -> IO [String]
|
||||
initState :: XPrompt p => Display -> Window -> Window -> Rectangle -> ComplFunction
|
||||
-> GC -> XMonadFont -> p -> [History] -> XPConfig -> XPState
|
||||
initState d rw w s compl gc fonts pt h c =
|
||||
XPS d rw w s Nothing Nothing compl gc fonts (XPT pt) "" 0 h c
|
||||
XPS { dpy = d
|
||||
, rootw = rw
|
||||
, win = w
|
||||
, screen = s
|
||||
, complWin = Nothing
|
||||
, complWinDim = Nothing
|
||||
, completionFunction = compl
|
||||
, gcon = gc
|
||||
, fontS = fonts
|
||||
, xptype = XPT pt
|
||||
, command = defaultText c
|
||||
, offset = length (defaultText c)
|
||||
, history = h
|
||||
, config = c
|
||||
}
|
||||
|
||||
-- | Same as 'mkXPrompt', except that the action function can have
|
||||
-- type @String -> X a@, for any @a@, and the final action returned
|
||||
@@ -281,6 +297,8 @@ keyPressHandle mask (ks,_)
|
||||
| ks == xK_a -> startOfLine >> go
|
||||
| ks == xK_e -> endOfLine >> go
|
||||
| ks == xK_y -> pasteString >> go
|
||||
| ks == xK_Right -> moveWord Next >> go
|
||||
| ks == xK_Left -> moveWord Prev >> go
|
||||
| ks == xK_Delete -> killWord Next >> go
|
||||
| ks == xK_BackSpace -> killWord Prev >> go
|
||||
| ks == xK_g || ks == xK_c -> quit
|
||||
@@ -380,6 +398,21 @@ moveCursor d =
|
||||
modify $ \s -> s { offset = o (offset s) (command s)}
|
||||
where o oo c = if d == Prev then max 0 (oo - 1) else min (length c) (oo + 1)
|
||||
|
||||
-- | move the cursor one word
|
||||
moveWord :: Direction -> XP ()
|
||||
moveWord d = do
|
||||
c <- gets command
|
||||
o <- gets offset
|
||||
let (f,ss) = splitAt o c
|
||||
lenToS = length . fst . break isSpace
|
||||
ln p s = case p s of
|
||||
' ':x -> 1 + lenToS x
|
||||
x -> lenToS x
|
||||
newoff = case d of
|
||||
Prev -> o - (ln reverse f )
|
||||
_ -> o + (ln id ss)
|
||||
modify $ \s -> s { offset = newoff }
|
||||
|
||||
moveHistory :: Direction -> XP ()
|
||||
moveHistory d = do
|
||||
h <- getHistory
|
||||
@@ -454,7 +487,7 @@ printPrompt drw = do
|
||||
ht = height c
|
||||
fsl <- io $ textWidthXMF (dpy st) fs f
|
||||
psl <- io $ textWidthXMF (dpy st) fs p
|
||||
(_,asc,desc,_) <- io $ textExtentsXMF (dpy st) fs str
|
||||
(_,asc,desc,_) <- io $ textExtentsXMF fs str
|
||||
let y = fi $ ((ht - fi (asc + desc)) `div` 2) + fi asc
|
||||
x = (asc + desc) `div` 2
|
||||
|
||||
@@ -521,7 +554,7 @@ getComplWinDim compl = do
|
||||
(x,y) = case position c of
|
||||
Top -> (0,ht)
|
||||
Bottom -> (0, (0 + rem_height - actual_height))
|
||||
(_,asc,desc,_) <- io $ textExtentsXMF (dpy st) fs $ head compl
|
||||
(_,asc,desc,_) <- io $ textExtentsXMF fs $ head compl
|
||||
let yp = fi $ (ht + fi (asc - desc)) `div` 2
|
||||
xp = (asc + desc) `div` 2
|
||||
yy = map fi . take (fi actual_rows) $ [yp,(yp + ht)..]
|
||||
@@ -613,7 +646,7 @@ getHistory = do
|
||||
readHistory :: IO ([History],Handle)
|
||||
readHistory = do
|
||||
home <- getEnv "HOME"
|
||||
let path = home ++ "/.xmonad_history"
|
||||
let path = home ++ "/.xmonad/history"
|
||||
f <- fileExist path
|
||||
if f then do h <- openFile path ReadMode
|
||||
str <- hGetContents h
|
||||
@@ -627,7 +660,7 @@ readHistory = do
|
||||
writeHistory :: [History] -> IO ()
|
||||
writeHistory hist = do
|
||||
home <- getEnv "HOME"
|
||||
let path = home ++ "/.xmonad_history"
|
||||
let path = home ++ "/.xmonad/history"
|
||||
catch (writeFile path (show hist)) (\_ -> do putStrLn "error in writing"; return ())
|
||||
|
||||
-- $xutils
|
||||
|
@@ -13,8 +13,6 @@
|
||||
--
|
||||
-- * narrow completions by section number, if the one is specified
|
||||
-- (like @\/etc\/bash_completion@ does)
|
||||
--
|
||||
-- * write QuickCheck properties
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
module XMonad.Prompt.Man (
|
||||
@@ -58,33 +56,36 @@ instance XPrompt Man where
|
||||
|
||||
-- | Query for manual page to be displayed.
|
||||
manPrompt :: XPConfig -> X ()
|
||||
manPrompt c = mkXPrompt Man c manCompl $ runInTerm . (++) "man "
|
||||
manPrompt c = do
|
||||
mans <- io getMans
|
||||
mkXPrompt Man c (manCompl mans) $ runInTerm . (++) "man "
|
||||
|
||||
manCompl :: String -> IO [String]
|
||||
manCompl str | '/' `elem` str = do
|
||||
-- XXX It may be better to use readline instead of bash's compgen...
|
||||
lines `fmap` getCommandOutput ("bash -c 'compgen -A file " ++ str ++ "'")
|
||||
| otherwise = do
|
||||
mp <- getCommandOutput "manpath -g 2>/dev/null" `E.catch` \_ -> return []
|
||||
getMans :: IO [String]
|
||||
getMans = do
|
||||
paths <- getCommandOutput "manpath -g 2>/dev/null" `E.catch` \_ -> return []
|
||||
let sects = ["man" ++ show n | n <- [1..9 :: Int]]
|
||||
dirs = [d ++ "/" ++ s | d <- split ':' mp, s <- sects]
|
||||
stripExt = reverse . drop 1 . dropWhile (/= '.') . reverse
|
||||
dirs = [d ++ "/" ++ s | d <- split ':' paths, s <- sects]
|
||||
mans <- forM dirs $ \d -> do
|
||||
exists <- doesDirectoryExist d
|
||||
if exists
|
||||
then map (stripExt . stripSuffixes [".gz", ".bz2"]) `fmap`
|
||||
getDirectoryContents d
|
||||
else return []
|
||||
mkComplFunFromList (uniqSort $ concat mans) str
|
||||
return $ uniqSort $ concat mans
|
||||
|
||||
manCompl :: [String] -> String -> IO [String]
|
||||
manCompl mans s | s == "" || last s == ' ' = return []
|
||||
| otherwise = do
|
||||
-- XXX readline instead of bash's compgen?
|
||||
f <- lines `fmap` getCommandOutput ("bash -c 'compgen -A file " ++ s ++ "'")
|
||||
mkComplFunFromList (f ++ mans) s
|
||||
|
||||
-- | Run a command using shell and return its output.
|
||||
--
|
||||
-- XXX merge with 'XMonad.Util.Run.runProcessWithInput'?
|
||||
-- XXX Merge into 'XMonad.Util.Run'?
|
||||
--
|
||||
-- * update documentation of the latter (there is no 'Maybe' in result)
|
||||
--
|
||||
-- * ask \"gurus\" whether @evaluate (length ...)@ approach is
|
||||
-- better\/more idiomatic
|
||||
-- (Ask \"gurus\" whether @evaluate (length ...)@ approach is
|
||||
-- better\/more idiomatic.)
|
||||
getCommandOutput :: String -> IO String
|
||||
getCommandOutput s = do
|
||||
(pin, pout, perr, ph) <- runInteractiveCommand s
|
||||
@@ -95,6 +96,9 @@ getCommandOutput s = do
|
||||
waitForProcess ph
|
||||
return output
|
||||
|
||||
stripExt :: String -> String
|
||||
stripExt = reverse . drop 1 . dropWhile (/= '.') . reverse
|
||||
|
||||
stripSuffixes :: Eq a => [[a]] -> [a] -> [a]
|
||||
stripSuffixes sufs fn =
|
||||
head . catMaybes $ map (flip rstrip fn) sufs ++ [Just fn]
|
||||
|
@@ -89,20 +89,12 @@ getCommands :: IO [String]
|
||||
getCommands = do
|
||||
p <- getEnv "PATH" `catch` const (return [])
|
||||
let ds = split ':' p
|
||||
fp d f = d ++ "/" ++ f
|
||||
es <- forM ds $ \d -> do
|
||||
exists <- doesDirectoryExist d
|
||||
if exists
|
||||
then getDirectoryContents d >>= filterM (isExecutable . fp d)
|
||||
then getDirectoryContents d
|
||||
else return []
|
||||
return . uniqSort . concat $ es
|
||||
|
||||
isExecutable :: FilePath ->IO Bool
|
||||
isExecutable f = do
|
||||
fe <- doesFileExist f
|
||||
if fe
|
||||
then fmap executable $ getPermissions f
|
||||
else return False
|
||||
return . uniqSort . filter ((/= '.') . head) . concat $ es
|
||||
|
||||
split :: Eq a => a -> [a] -> [[a]]
|
||||
split _ [] = []
|
||||
|
@@ -12,8 +12,12 @@
|
||||
--
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
module XMonad.Util.Dzen (dzen, dzenWithArgs, dzenScreen,
|
||||
seconds) where
|
||||
module XMonad.Util.Dzen (
|
||||
dzen,
|
||||
dzenWithArgs,
|
||||
dzenScreen,
|
||||
seconds
|
||||
) where
|
||||
|
||||
import XMonad
|
||||
import XMonad.Util.Run (runProcessWithInputAndWait, seconds)
|
||||
|
@@ -102,10 +102,10 @@ textWidthXMF dpy (Xft xftdraw) s = liftIO $ do
|
||||
return $ xglyphinfo_width gi
|
||||
#endif
|
||||
|
||||
textExtentsXMF :: MonadIO m => Display -> XMonadFont -> String -> m (FontDirection,Int32,Int32,CharStruct)
|
||||
textExtentsXMF _ (Core fs) s = return $ textExtents fs s
|
||||
textExtentsXMF :: MonadIO m => XMonadFont -> String -> m (FontDirection,Int32,Int32,CharStruct)
|
||||
textExtentsXMF (Core fs) s = return $ textExtents fs s
|
||||
#ifdef XFT
|
||||
textExtentsXMF _ (Xft xftfont) _ = liftIO $ do
|
||||
textExtentsXMF (Xft xftfont) _ = liftIO $ do
|
||||
ascent <- xftfont_ascent xftfont
|
||||
descent <- xftfont_descent xftfont
|
||||
return (error "Font direction touched", fi ascent, fi descent, error "Font overall size touched")
|
||||
@@ -120,7 +120,7 @@ stringPosition :: XMonadFont -> Rectangle -> Align -> String -> X (Position,Posi
|
||||
stringPosition fs (Rectangle _ _ w h) al s = do
|
||||
dpy <- asks display
|
||||
width <- io $ textWidthXMF dpy fs s
|
||||
(_,a,d,_) <- io $ textExtentsXMF dpy fs s
|
||||
(_,a,d,_) <- io $ textExtentsXMF fs s
|
||||
let y = fi $ ((h - fi (a + d)) `div` 2) + fi a;
|
||||
x = case al of
|
||||
AlignCenter -> fi (w `div` 2) - fi (width `div` 2)
|
||||
|
@@ -29,11 +29,9 @@ module XMonad.Util.Run (
|
||||
) where
|
||||
|
||||
import System.Posix.IO
|
||||
import System.Posix.Process (createSession, forkProcess, executeFile,
|
||||
getProcessStatus)
|
||||
import System.Posix.Process (executeFile)
|
||||
import Control.Concurrent (threadDelay)
|
||||
import Control.Exception (try)
|
||||
import System.Exit (ExitCode(ExitSuccess), exitWith)
|
||||
import System.IO
|
||||
import System.Process (runInteractiveProcess, waitForProcess)
|
||||
import XMonad
|
||||
@@ -50,7 +48,7 @@ import Control.Monad
|
||||
-- For an example usage of 'runProcessWithInputAndWait' see
|
||||
-- "XMonad.Util.Dzen"
|
||||
|
||||
-- | Returns Just output if the command succeeded, and Nothing if it didn't.
|
||||
-- | Return output if the command succeeded, otherwise return @()@.
|
||||
-- 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
|
||||
@@ -67,22 +65,16 @@ runProcessWithInput cmd args input = do
|
||||
-- | Wait is in us
|
||||
runProcessWithInputAndWait :: FilePath -> [String] -> String -> Int -> IO ()
|
||||
runProcessWithInputAndWait cmd args input timeout = do
|
||||
pid <- forkProcess $ do
|
||||
forkProcess $ do -- double fork it over to init
|
||||
createSession
|
||||
(pin, pout, perr, ph) <- runInteractiveProcess cmd args Nothing Nothing
|
||||
hPutStr pin input
|
||||
hFlush pin
|
||||
threadDelay timeout
|
||||
hClose pin
|
||||
hClose pout
|
||||
hClose perr
|
||||
waitForProcess ph
|
||||
return ()
|
||||
exitWith ExitSuccess
|
||||
return ()
|
||||
getProcessStatus True False pid
|
||||
return ()
|
||||
doubleFork $ do
|
||||
(pin, pout, perr, ph) <- runInteractiveProcess cmd args Nothing Nothing
|
||||
hPutStr pin input
|
||||
hFlush pin
|
||||
threadDelay timeout
|
||||
hClose pin
|
||||
hClose pout
|
||||
hClose perr
|
||||
waitForProcess ph
|
||||
return ()
|
||||
|
||||
-- | Multiplies by ONE MILLION, for use with
|
||||
-- 'runProcessWithInputAndWait'.
|
||||
@@ -104,16 +96,16 @@ seconds = fromEnum . (* 1000000)
|
||||
-- unsafeSpawn is an alias for XMonad's 'spawn', to remind one that use
|
||||
-- of it can be, well, unsafe.
|
||||
-- Examples:
|
||||
--
|
||||
--
|
||||
-- > , ((modMask, xK_Print), unsafeSpawn "import -window root png:$HOME/xwd-$(date +%s)$$.png")
|
||||
-- > , ((modMask, xK_d ), safeSpawn "firefox" "")
|
||||
--
|
||||
--
|
||||
-- Note that the unsafeSpawn example must be unsafe and not safe because
|
||||
-- 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 (forkProcess $ executeFile prog True [arg] Nothing) >> return ())
|
||||
safeSpawn prog arg = liftIO (try (doubleFork $ executeFile prog True [arg] Nothing) >> return ())
|
||||
|
||||
unsafeSpawn :: MonadIO m => String -> m ()
|
||||
unsafeSpawn = spawn
|
||||
@@ -134,11 +126,7 @@ spawnPipe x = do
|
||||
setFdOption wr CloseOnExec True
|
||||
h <- fdToHandle wr
|
||||
hSetBuffering h LineBuffering
|
||||
pid <- forkProcess $ do
|
||||
forkProcess $ do
|
||||
dupTo rd stdInput
|
||||
createSession
|
||||
executeFile "/bin/sh" False ["-c", x] Nothing
|
||||
exitWith ExitSuccess
|
||||
getProcessStatus True False pid
|
||||
doubleFork $ do
|
||||
dupTo rd stdInput
|
||||
executeFile "/bin/sh" False ["-c", x] Nothing
|
||||
return h
|
||||
|
59
XMonad/Util/Timer.hs
Normal file
59
XMonad/Util/Timer.hs
Normal file
@@ -0,0 +1,59 @@
|
||||
-----------------------------------------------------------------------------
|
||||
-- |
|
||||
-- Module : XMonad.Util.Timer
|
||||
-- Copyright : (c) Andrea Rossato and David Roundy 2007
|
||||
-- License : BSD-style (see xmonad/LICENSE)
|
||||
--
|
||||
-- Maintainer : andrea.rossato@unibz.it
|
||||
-- Stability : unstable
|
||||
-- Portability : unportable
|
||||
--
|
||||
-- A module for setting up timers
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
module XMonad.Util.Timer
|
||||
( -- * Usage
|
||||
-- $usage
|
||||
startTimer
|
||||
, handleTimer
|
||||
, TimerId
|
||||
) where
|
||||
|
||||
import XMonad
|
||||
import Control.Applicative
|
||||
import Control.Concurrent
|
||||
import Data.Unique
|
||||
|
||||
-- $usage
|
||||
-- This module can be used to setup a timer to handle deferred events.
|
||||
-- See 'XMonad.Layout.ShowWName' for an usage example.
|
||||
|
||||
type TimerId = Int
|
||||
|
||||
-- | Start a timer, which will send a ClientMessageEvent after some
|
||||
-- time (in seconds).
|
||||
startTimer :: Rational -> X TimerId
|
||||
startTimer s = io $ do
|
||||
u <- hashUnique <$> newUnique
|
||||
doubleFork $ do
|
||||
d <- openDisplay ""
|
||||
rw <- rootWindow d $ defaultScreen d
|
||||
threadDelay (fromEnum $ s * 1000000)
|
||||
a <- internAtom d "XMONAD_TIMER" False
|
||||
allocaXEvent $ \e -> do
|
||||
setEventType e clientMessage
|
||||
setClientMessageEvent e rw a 32 (fromIntegral u) currentTime
|
||||
sendEvent d rw False structureNotifyMask e
|
||||
sync d False
|
||||
return u
|
||||
|
||||
-- | Given a 'TimerId' and an 'Event', run an action when the 'Event'
|
||||
-- has been sent by the timer specified by the 'TimerId'
|
||||
handleTimer :: TimerId -> Event -> X (Maybe a) -> X (Maybe a)
|
||||
handleTimer ti (ClientMessageEvent {ev_message_type = mt, ev_data = dt}) action = do
|
||||
d <- asks display
|
||||
a <- io $ internAtom d "XMONAD_TIMER" False
|
||||
if mt == a && dt /= [] && fromIntegral (head dt) == ti
|
||||
then action
|
||||
else return Nothing
|
||||
handleTimer _ _ _ = return Nothing
|
41
XMonad/Util/WorkspaceCompare.hs
Normal file
41
XMonad/Util/WorkspaceCompare.hs
Normal file
@@ -0,0 +1,41 @@
|
||||
-----------------------------------------------------------------------------
|
||||
-- |
|
||||
-- Module : XMonad.Util.WorkspaceCompare
|
||||
-- Copyright : (c) Spencer Janssen <sjanssen@cse.unl.edu>
|
||||
-- License : BSD3-style (see LICENSE)
|
||||
--
|
||||
-- Maintainer : Spencer Janssen <sjanssen@cse.unl.edu>
|
||||
-- Stability : unstable
|
||||
-- Portability : unportable
|
||||
--
|
||||
|
||||
module XMonad.Util.WorkspaceCompare ( getWsIndex, getWsCompare, getSortByTag ) where
|
||||
|
||||
import XMonad
|
||||
import qualified XMonad.StackSet as S
|
||||
import Data.List
|
||||
import Data.Monoid
|
||||
|
||||
-- | Lookup the index of a workspace id in the user's config, return Nothing
|
||||
-- if that workspace does not exist in the config.
|
||||
getWsIndex :: X (WorkspaceId -> Maybe Int)
|
||||
getWsIndex = do
|
||||
spaces <- asks (workspaces . config)
|
||||
return $ flip elemIndex spaces
|
||||
|
||||
-- | A comparison function for WorkspaceId
|
||||
getWsCompare :: X (WorkspaceId -> WorkspaceId -> Ordering)
|
||||
getWsCompare = do
|
||||
wsIndex <- getWsIndex
|
||||
return $ \a b -> f (wsIndex a) (wsIndex b) `mappend` compare a b
|
||||
where
|
||||
f Nothing Nothing = EQ
|
||||
f (Just _) Nothing = LT
|
||||
f Nothing (Just _) = GT
|
||||
f (Just x) (Just y) = compare x y
|
||||
|
||||
-- | Sort several workspaces according to the order in getWsCompare
|
||||
getSortByTag :: X ([WindowSpace] -> [WindowSpace])
|
||||
getSortByTag = do
|
||||
cmp <- getWsCompare
|
||||
return $ sortBy (\a b -> cmp (S.tag a) (S.tag b))
|
@@ -57,8 +57,8 @@ import XMonad.Util.Run (safeSpawn, unsafeSpawn)
|
||||
|
||||
-- | Returns a String corresponding to the current mouse selection in X; if there is none, an empty string is returned. Note that this is
|
||||
-- really only reliable for ASCII text and currently escapes or otherwise mangles more complex UTF-8 characters.
|
||||
getSelection :: IO String
|
||||
getSelection = do
|
||||
getSelection :: MonadIO m => m String
|
||||
getSelection = io $ do
|
||||
dpy <- openDisplay ""
|
||||
let dflt = defaultScreen dpy
|
||||
rootw <- rootWindow dpy dflt
|
||||
@@ -80,8 +80,8 @@ getSelection = do
|
||||
else destroyWindow dpy win >> return ""
|
||||
|
||||
-- | Set the current X Selection to a given String.
|
||||
putSelection :: String -> IO ()
|
||||
putSelection text = do
|
||||
putSelection :: MonadIO m => String -> m ()
|
||||
putSelection text = io $ do
|
||||
dpy <- openDisplay ""
|
||||
let dflt = defaultScreen dpy
|
||||
rootw <- rootWindow dpy dflt
|
||||
|
@@ -3,7 +3,7 @@
|
||||
-- Module : XMonad.Util.XUtils
|
||||
-- Copyright : (c) 2007 Andrea Rossato
|
||||
-- License : BSD-style (see xmonad/LICENSE)
|
||||
--
|
||||
--
|
||||
-- Maintainer : andrea.rossato@unibz.it
|
||||
-- Stability : unstable
|
||||
-- Portability : unportable
|
||||
@@ -12,7 +12,7 @@
|
||||
--
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
module XMonad.Util.XUtils (
|
||||
module XMonad.Util.XUtils (
|
||||
-- * Usage:
|
||||
-- $usage
|
||||
averagePixels
|
||||
@@ -22,7 +22,7 @@ module XMonad.Util.XUtils (
|
||||
, deleteWindow
|
||||
, paintWindow
|
||||
, paintAndWrite
|
||||
, stringToPixel
|
||||
, stringToPixel
|
||||
) where
|
||||
|
||||
|
||||
@@ -44,15 +44,16 @@ averagePixels p1 p2 f =
|
||||
let mn x1 x2 = round (fromIntegral x1 * f + fromIntegral x2 * (1-f))
|
||||
Color p _ _ _ _ <- io $ allocColor d cm (Color 0 (mn r1 r2) (mn g1 g2) (mn b1 b2) 0)
|
||||
return p
|
||||
|
||||
-- | Create a simple window given a rectangle. If Nothing is given
|
||||
-- only the exposureMask will be set, otherwise the Just value.
|
||||
-- Use 'showWindow' to map and hideWindow to unmap.
|
||||
createNewWindow :: Rectangle -> Maybe EventMask -> String -> X Window
|
||||
createNewWindow (Rectangle x y w h) m col = do
|
||||
createNewWindow :: Rectangle -> Maybe EventMask -> String -> Bool -> X Window
|
||||
createNewWindow (Rectangle x y w h) m col o = do
|
||||
d <- asks display
|
||||
rw <- asks theRoot
|
||||
c <- stringToPixel d col
|
||||
win <- io $ createSimpleWindow d rw x y w h 0 c c
|
||||
c <- stringToPixel d col
|
||||
win <- io $ mkWindow d (defaultScreenOfDisplay d) rw x y w h c o
|
||||
case m of
|
||||
Just em -> io $ selectInput d win em
|
||||
Nothing -> io $ selectInput d win exposureMask
|
||||
@@ -77,9 +78,9 @@ deleteWindow w = do
|
||||
io $ destroyWindow d w
|
||||
|
||||
-- | Fill a window with a rectangle and a border
|
||||
paintWindow :: Window -- ^ The window where to draw
|
||||
paintWindow :: Window -- ^ The window where to draw
|
||||
-> Dimension -- ^ Window width
|
||||
-> Dimension -- ^ Window height
|
||||
-> Dimension -- ^ Window height
|
||||
-> Dimension -- ^ Border width
|
||||
-> String -- ^ Window background color
|
||||
-> String -- ^ Border color
|
||||
@@ -88,10 +89,10 @@ paintWindow w wh ht bw c bc =
|
||||
paintWindow' w (Rectangle 0 0 wh ht) bw c bc Nothing
|
||||
|
||||
-- | Fill a window with a rectangle and a border, and write a string at given position
|
||||
paintAndWrite :: Window -- ^ The window where to draw
|
||||
paintAndWrite :: Window -- ^ The window where to draw
|
||||
-> XMonadFont -- ^ XMonad Font for drawing
|
||||
-> Dimension -- ^ Window width
|
||||
-> Dimension -- ^ Window height
|
||||
-> Dimension -- ^ Window height
|
||||
-> Dimension -- ^ Border width
|
||||
-> String -- ^ Window background color
|
||||
-> String -- ^ Border color
|
||||
@@ -130,6 +131,21 @@ paintWindow' win (Rectangle x y wh ht) bw color b_color str = do
|
||||
io $ freePixmap d p
|
||||
io $ freeGC d gc
|
||||
|
||||
-- | Creates a window with the possibility of setting some attributes.
|
||||
-- Not exported.
|
||||
mkWindow :: Display -> Screen -> Window -> Position
|
||||
-> Position -> Dimension -> Dimension -> Pixel -> Bool -> IO Window
|
||||
mkWindow d s rw x y w h p o = do
|
||||
let visual = defaultVisualOfScreen s
|
||||
attrmask = cWOverrideRedirect .|. cWBackPixel .|. cWBorderPixel
|
||||
allocaSetWindowAttributes $
|
||||
\attributes -> do
|
||||
set_override_redirect attributes o
|
||||
set_border_pixel attributes p
|
||||
set_background_pixel attributes p
|
||||
createWindow d rw x y w h 0 (defaultDepthOfScreen s)
|
||||
inputOutput visual attrmask attributes
|
||||
|
||||
-- | Short-hand for 'fromIntegral'
|
||||
fi :: (Integral a, Num b) => a -> b
|
||||
fi = fromIntegral
|
||||
|
@@ -1,5 +1,5 @@
|
||||
name: xmonad-contrib
|
||||
version: 0.5
|
||||
version: 0.6
|
||||
homepage: http://xmonad.org/
|
||||
synopsis: Third party extensions for xmonad
|
||||
description:
|
||||
@@ -33,6 +33,10 @@ flag small_base
|
||||
flag use_xft
|
||||
description: Use Xft to render text
|
||||
|
||||
flag testing
|
||||
description: Testing mode
|
||||
default: False
|
||||
|
||||
library
|
||||
if flag(small_base)
|
||||
build-depends: base >= 3, containers, directory, process, random
|
||||
@@ -43,8 +47,12 @@ library
|
||||
build-depends: X11-xft >= 0.2
|
||||
cpp-options: -DXFT
|
||||
|
||||
build-depends: mtl, unix, X11>=1.4.0, xmonad==0.5
|
||||
ghc-options: -Wall -Werror
|
||||
build-depends: mtl, unix, X11>=1.4.1, xmonad==0.6
|
||||
ghc-options: -Wall
|
||||
|
||||
if flag(testing)
|
||||
ghc-options: -Werror
|
||||
|
||||
exposed-modules: XMonad.Doc
|
||||
XMonad.Doc.Configuring
|
||||
XMonad.Doc.Extending
|
||||
@@ -62,8 +70,10 @@ library
|
||||
XMonad.Actions.FloatKeys
|
||||
XMonad.Actions.FocusNth
|
||||
XMonad.Actions.MouseGestures
|
||||
XMonad.Actions.NoBorders
|
||||
XMonad.Actions.RotSlaves
|
||||
XMonad.Actions.RotView
|
||||
XMonad.Actions.Search
|
||||
XMonad.Actions.SimpleDate
|
||||
XMonad.Actions.SinkAll
|
||||
XMonad.Actions.Submap
|
||||
@@ -79,6 +89,7 @@ library
|
||||
XMonad.Hooks.DynamicLog
|
||||
XMonad.Hooks.EwmhDesktops
|
||||
XMonad.Hooks.ManageDocks
|
||||
XMonad.Hooks.ManageHelpers
|
||||
XMonad.Hooks.SetWMName
|
||||
XMonad.Hooks.UrgencyHook
|
||||
XMonad.Hooks.XPropManage
|
||||
@@ -102,10 +113,12 @@ library
|
||||
XMonad.Layout.Named
|
||||
XMonad.Layout.NoBorders
|
||||
XMonad.Layout.PerWorkspace
|
||||
XMonad.Layout.Reflect
|
||||
XMonad.Layout.ResizableTile
|
||||
XMonad.Layout.Roledex
|
||||
XMonad.Layout.Spiral
|
||||
XMonad.Layout.Square
|
||||
XMonad.Layout.ShowWName
|
||||
XMonad.Layout.Tabbed
|
||||
XMonad.Layout.ThreeColumns
|
||||
XMonad.Layout.ToggleLayouts
|
||||
@@ -133,5 +146,7 @@ library
|
||||
XMonad.Util.Invisible
|
||||
XMonad.Util.NamedWindows
|
||||
XMonad.Util.Run
|
||||
XMonad.Util.Timer
|
||||
XMonad.Util.WorkspaceCompare
|
||||
XMonad.Util.XSelection
|
||||
XMonad.Util.XUtils
|
||||
|
Reference in New Issue
Block a user