mirror of
https://github.com/xmonad/xmonad-contrib.git
synced 2025-07-26 17:51:51 -07:00
Compare commits
89 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
103d633e41 | ||
|
d7cac6d70c | ||
|
e806fe9bc8 | ||
|
d451c277f6 | ||
|
cdae01dfdb | ||
|
5c2aa04175 | ||
|
1d6a171dd2 | ||
|
e8cfb696ad | ||
|
9464b32395 | ||
|
f46873fdab | ||
|
c729dac32e | ||
|
84a8e42ac0 | ||
|
de3cafec0d | ||
|
bfb5fc7384 | ||
|
b2fa3f3e80 | ||
|
2ca7de8b08 | ||
|
8fa0319e89 | ||
|
8e8962909b | ||
|
1dc74c3879 | ||
|
bcb204731f | ||
|
c92b8b3e9e | ||
|
be4feb98d6 | ||
|
c38912b991 | ||
|
79e7a8210a | ||
|
02063ff97e | ||
|
c198812fb6 | ||
|
e2c5fa876a | ||
|
70d5cedcc5 | ||
|
82a0d30f31 | ||
|
46fca2c6c9 | ||
|
30a78d51e3 | ||
|
b881934a02 | ||
|
6a8e6af48f | ||
|
addb6a99e1 | ||
|
5d341e8e99 | ||
|
5463e04b94 | ||
|
b4acd87c7a | ||
|
aa6f4882a4 | ||
|
ff11ae70a0 | ||
|
9cdcb7185f | ||
|
4f97bc02ce | ||
|
b3329397c0 | ||
|
cb684763ce | ||
|
db37e18098 | ||
|
7c363c82d3 | ||
|
65d1309cf1 | ||
|
14f0f6129d | ||
|
8cda47f19f | ||
|
fdec915dda | ||
|
eba5720d30 | ||
|
d606f998bd | ||
|
3102a69287 | ||
|
8dcd818586 | ||
|
60ae62e4e3 | ||
|
3b82b8755e | ||
|
e14dcd9aa6 | ||
|
da094a635d | ||
|
77f916fa26 | ||
|
5f4b9e8a19 | ||
|
a3fb5f5df1 | ||
|
0efee8b0cb | ||
|
71abbe457a | ||
|
9cd4fccdc2 | ||
|
920bf15e04 | ||
|
54acce050f | ||
|
328fae1468 | ||
|
df7ac47317 | ||
|
86f6b327ae | ||
|
8ec090cfbf | ||
|
fa476549c2 | ||
|
f71fdefdc7 | ||
|
97a36b49a5 | ||
|
1a8bdd4320 | ||
|
3f6787be4f | ||
|
2edac2fc13 | ||
|
9f66ef9975 | ||
|
4769530d9f | ||
|
bfdfb2297e | ||
|
9180666302 | ||
|
9159b17cc8 | ||
|
41deac6194 | ||
|
a64d55f618 | ||
|
b1ac0b5030 | ||
|
ccd71d4a15 | ||
|
6e84273e03 | ||
|
3fd77f5386 | ||
|
95bada8d02 | ||
|
0b9b98c06b | ||
|
cdb1e6ef71 |
83
XMonad/Actions/BluetileCommands.hs
Normal file
83
XMonad/Actions/BluetileCommands.hs
Normal file
@@ -0,0 +1,83 @@
|
||||
----------------------------------------------------------------------------
|
||||
-- |
|
||||
-- Module : XMonad.Actions.BluetileCommands
|
||||
-- Copyright : (c) Jan Vornberger 2009
|
||||
-- License : BSD3-style (see LICENSE)
|
||||
--
|
||||
-- Maintainer : jan.vornberger@informatik.uni-oldenburg.de
|
||||
-- Stability : unstable
|
||||
-- Portability : not portable
|
||||
--
|
||||
-- This is a list of selected commands that can be made available using
|
||||
-- "XMonad.Hooks.ServerMode" to allow external programs to control
|
||||
-- the window manager. Bluetile (<http://projects.haskell.org/bluetile/>)
|
||||
-- uses this to enable its dock application to do things like changing
|
||||
-- workspaces and layouts.
|
||||
--
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
module XMonad.Actions.BluetileCommands (
|
||||
-- * Usage
|
||||
-- $usage
|
||||
bluetileCommands
|
||||
) where
|
||||
|
||||
import XMonad
|
||||
import qualified XMonad.StackSet as W
|
||||
import XMonad.Layout.LayoutCombinators
|
||||
import System.Exit
|
||||
|
||||
-- $usage
|
||||
--
|
||||
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
|
||||
--
|
||||
-- > import XMonad.Hooks.ServerMode
|
||||
-- > import XMonad.Actions.BluetileCommands
|
||||
--
|
||||
-- Then edit your @handleEventHook@:
|
||||
--
|
||||
-- > main = xmonad defaultConfig { handleEventHook = serverModeEventHook' bluetileCommands }
|
||||
--
|
||||
-- See the documentation of "XMonad.Hooks.ServerMode" for details on
|
||||
-- how to actually invoke the commands from external programs.
|
||||
|
||||
workspaceCommands :: Int -> X [(String, X ())]
|
||||
workspaceCommands sid = asks (workspaces . config) >>= \spaces -> return
|
||||
[(("greedyView" ++ show i),
|
||||
activateScreen sid >> windows (W.greedyView i))
|
||||
| i <- spaces ]
|
||||
|
||||
layoutCommands :: Int -> [(String, X ())]
|
||||
layoutCommands sid = [ ("layout floating" , activateScreen sid >>
|
||||
sendMessage (JumpToLayout "Floating"))
|
||||
, ("layout tiled1" , activateScreen sid >>
|
||||
sendMessage (JumpToLayout "Tiled1"))
|
||||
, ("layout tiled2" , activateScreen sid >>
|
||||
sendMessage (JumpToLayout "Tiled2"))
|
||||
, ("layout fullscreen" , activateScreen sid >>
|
||||
sendMessage (JumpToLayout "Fullscreen"))
|
||||
]
|
||||
|
||||
masterAreaCommands :: Int -> [(String, X ())]
|
||||
masterAreaCommands sid = [ ("increase master n", activateScreen sid >>
|
||||
sendMessage (IncMasterN 1))
|
||||
, ("decrease master n", activateScreen sid >>
|
||||
sendMessage (IncMasterN (-1)))
|
||||
]
|
||||
|
||||
quitCommands :: [(String, X ())]
|
||||
quitCommands = [ ("quit bluetile", io (exitWith ExitSuccess))
|
||||
, ("quit bluetile and start metacity", restart "metacity" False)
|
||||
]
|
||||
|
||||
bluetileCommands :: X [(String, X ())]
|
||||
bluetileCommands = do
|
||||
let restartCommand = [ ("restart bluetile", restart "bluetile" True) ]
|
||||
wscmds0 <- workspaceCommands 0
|
||||
wscmds1 <- workspaceCommands 1
|
||||
return $ restartCommand
|
||||
++ wscmds0 ++ layoutCommands 0 ++ masterAreaCommands 0 ++ quitCommands
|
||||
++ wscmds1 ++ layoutCommands 1 ++ masterAreaCommands 1 ++ quitCommands
|
||||
|
||||
activateScreen :: Int -> X ()
|
||||
activateScreen sid = screenWorkspace (S sid) >>= flip whenJust (windows . W.view)
|
@@ -218,6 +218,10 @@ data WSType = EmptyWS -- ^ cycle through empty workspaces
|
||||
| HiddenWS -- ^ cycle through non-visible workspaces
|
||||
| HiddenNonEmptyWS -- ^ cycle through non-empty non-visible workspaces
|
||||
| AnyWS -- ^ cycle through all workspaces
|
||||
| WSTagGroup Char
|
||||
-- ^ cycle through workspaces in the same group, the
|
||||
-- group name is all characters up to the first
|
||||
-- separator character or the end of the tag
|
||||
| WSIs (X (WindowSpace -> Bool))
|
||||
-- ^ cycle through workspaces satisfying
|
||||
-- an arbitrary predicate
|
||||
@@ -232,6 +236,9 @@ wsTypeToPred HiddenNonEmptyWS = do ne <- wsTypeToPred NonEmptyWS
|
||||
hi <- wsTypeToPred HiddenWS
|
||||
return (\w -> hi w && ne w)
|
||||
wsTypeToPred AnyWS = return (const True)
|
||||
wsTypeToPred (WSTagGroup sep) = do cur <- (groupName.workspace.current) `fmap` gets windowset
|
||||
return $ (cur ==).groupName
|
||||
where groupName = takeWhile (/=sep).tag
|
||||
wsTypeToPred (WSIs p) = p
|
||||
|
||||
-- | View the next workspace in the given direction that satisfies
|
||||
|
@@ -8,15 +8,18 @@
|
||||
-- Stability : unstable
|
||||
-- Portability : unportable
|
||||
--
|
||||
-- Provides bindings to add and delete workspaces. Note that you may only
|
||||
-- delete a workspace that is already empty.
|
||||
-- Provides bindings to add and delete workspaces.
|
||||
--
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
module XMonad.Actions.DynamicWorkspaces (
|
||||
-- * Usage
|
||||
-- $usage
|
||||
addWorkspace, removeWorkspace,
|
||||
addWorkspace, addWorkspacePrompt,
|
||||
removeWorkspace,
|
||||
removeEmptyWorkspace,
|
||||
removeEmptyWorkspaceAfter,
|
||||
removeEmptyWorkspaceAfterExcept,
|
||||
addHiddenWorkspace,
|
||||
withWorkspace,
|
||||
selectWorkspace, renameWorkspace,
|
||||
@@ -28,6 +31,9 @@ import XMonad.StackSet hiding (filter, modify, delete)
|
||||
import XMonad.Prompt.Workspace
|
||||
import XMonad.Prompt ( XPConfig, mkXPrompt, XPrompt(..) )
|
||||
import XMonad.Util.WorkspaceCompare ( getSortByIndex )
|
||||
import Data.List (find)
|
||||
import Data.Maybe (isNothing)
|
||||
import Control.Monad (when)
|
||||
|
||||
-- $usage
|
||||
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@ file:
|
||||
@@ -97,25 +103,68 @@ selectWorkspace conf = workspacePrompt conf $ \w ->
|
||||
then windows $ greedyView w
|
||||
else addWorkspace w
|
||||
|
||||
-- | Add a new workspace with the given name.
|
||||
-- | Add a new workspace with the given name, or do nothing if a
|
||||
-- workspace with the given name already exists; then switch to the
|
||||
-- newly created workspace.
|
||||
addWorkspace :: String -> X ()
|
||||
addWorkspace newtag = addHiddenWorkspace newtag >> windows (greedyView newtag)
|
||||
|
||||
-- | Prompt for the name of a new workspace, add it if it does not
|
||||
-- already exist, and switch to it.
|
||||
addWorkspacePrompt :: XPConfig -> X ()
|
||||
addWorkspacePrompt conf = mkXPrompt (Wor "New workspace name: ") conf (const (return [])) addWorkspace
|
||||
|
||||
-- | Add a new hidden workspace with the given name.
|
||||
-- | Add a new hidden workspace with the given name, or do nothing if
|
||||
-- a workspace with the given name already exists.
|
||||
addHiddenWorkspace :: String -> X ()
|
||||
addHiddenWorkspace newtag = do l <- asks (layoutHook . config)
|
||||
windows (addHiddenWorkspace' newtag l)
|
||||
addHiddenWorkspace newtag =
|
||||
whenX (gets (not . tagMember newtag . windowset)) $ do
|
||||
l <- asks (layoutHook . config)
|
||||
windows (addHiddenWorkspace' newtag l)
|
||||
|
||||
-- | Remove the current workspace if it contains no windows.
|
||||
removeEmptyWorkspace :: X ()
|
||||
removeEmptyWorkspace = gets (currentTag . windowset) >>= removeEmptyWorkspaceByTag
|
||||
|
||||
-- | Remove the current workspace.
|
||||
removeWorkspace :: X ()
|
||||
removeWorkspace = do s <- gets windowset
|
||||
case s of
|
||||
StackSet { current = Screen { workspace = torem }
|
||||
, hidden = (w:_) }
|
||||
-> do windows $ view (tag w)
|
||||
windows (removeWorkspace' (tag torem))
|
||||
_ -> return ()
|
||||
removeWorkspace = gets (currentTag . windowset) >>= removeWorkspaceByTag
|
||||
|
||||
-- | Remove workspace with specific tag if it contains no windows. Only works
|
||||
-- on the current or the last workspace.
|
||||
removeEmptyWorkspaceByTag :: String -> X ()
|
||||
removeEmptyWorkspaceByTag t = whenX (isEmpty t) $ removeWorkspaceByTag t
|
||||
|
||||
-- | Remove workspace with specific tag. Only works on the current or the last workspace.
|
||||
removeWorkspaceByTag :: String -> X ()
|
||||
removeWorkspaceByTag torem = do
|
||||
s <- gets windowset
|
||||
case s of
|
||||
StackSet { current = Screen { workspace = cur }, hidden = (w:_) } -> do
|
||||
when (torem==tag cur) $ windows $ view $ tag w
|
||||
windows $ removeWorkspace' torem
|
||||
_ -> return ()
|
||||
|
||||
-- | Remove the current workspace after an operation if it is empty and hidden.
|
||||
-- Can be used to remove a workspace if it is empty when leaving it. The
|
||||
-- operation may only change workspace once, otherwise the workspace will not
|
||||
-- be removed.
|
||||
removeEmptyWorkspaceAfter :: X () -> X ()
|
||||
removeEmptyWorkspaceAfter = removeEmptyWorkspaceAfterExcept []
|
||||
|
||||
-- | Like 'removeEmptyWorkspaceAfter' but use a list of sticky workspaces,
|
||||
-- whose entries will never be removed.
|
||||
removeEmptyWorkspaceAfterExcept :: [String] -> X () -> X ()
|
||||
removeEmptyWorkspaceAfterExcept sticky f = do
|
||||
before <- gets (currentTag . windowset)
|
||||
f
|
||||
after <- gets (currentTag . windowset)
|
||||
when (before/=after && before `notElem` sticky) $ removeEmptyWorkspaceByTag before
|
||||
|
||||
isEmpty :: String -> X Bool
|
||||
isEmpty t = do wsl <- gets $ workspaces . windowset
|
||||
let mws = find (\ws -> tag ws == t) wsl
|
||||
return $ maybe True (isNothing . stack) mws
|
||||
|
||||
addHiddenWorkspace' :: i -> l -> StackSet i l a sid sd -> StackSet i l a sid sd
|
||||
addHiddenWorkspace' newtag l s@(StackSet { hidden = ws }) = s { hidden = Workspace newtag l Nothing:ws }
|
||||
|
@@ -38,6 +38,7 @@ module XMonad.Actions.GridSelect (
|
||||
withSelectedWindow,
|
||||
bringSelected,
|
||||
goToSelected,
|
||||
gridselectWorkspace,
|
||||
spawnSelected,
|
||||
runSelectedAction,
|
||||
|
||||
@@ -92,13 +93,13 @@ import Data.Word (Word8)
|
||||
-- > {-# LANGUAGE NoMonomorphismRestriction #-}
|
||||
-- > import XMonad
|
||||
-- > ...
|
||||
-- > gsconfig1 = defaultGSConfig { gs_cellheight = 30, gs_cellWidth = 100 }
|
||||
-- > gsconfig1 = defaultGSConfig { gs_cellheight = 30, gs_cellwidth = 100 }
|
||||
--
|
||||
-- An example where 'buildDefaultGSConfig' is used instead of 'defaultGSConfig'
|
||||
-- in order to specify a custom colorizer is @gsconfig2@ (found in
|
||||
-- "XMonad.Actions.GridSelect#Colorizers"):
|
||||
--
|
||||
-- > gsconfig2 colorizer = (buildDefaultGSConfig colorizer) { gs_cellheight = 30, gs_cellWidth = 100 }
|
||||
-- > gsconfig2 colorizer = (buildDefaultGSConfig colorizer) { gs_cellheight = 30, gs_cellwidth = 100 }
|
||||
--
|
||||
-- > -- | A green monochrome colorizer based on window class
|
||||
-- > greenColorizer = colorRangeFromClassName
|
||||
@@ -237,9 +238,6 @@ diamondRestrict x y originX originY =
|
||||
map (\(x', y') -> (x' + fromInteger originX, y' + fromInteger originY)) .
|
||||
take 1000 $ diamond
|
||||
|
||||
tupadd :: (Num t1, Num t) => (t, t1) -> (t, t1) -> (t, t1)
|
||||
tupadd (a,b) (c,d) = (a+c,b+d)
|
||||
|
||||
findInElementMap :: (Eq a) => a -> [(a, b)] -> Maybe (a, b)
|
||||
findInElementMap pos = find ((== pos) . fst)
|
||||
|
||||
@@ -418,6 +416,7 @@ stringToRatio s = let gen = mkStdGen $ sum $ map fromEnum s
|
||||
-- | Brings up a 2D grid of elements in the center of the screen, and one can
|
||||
-- select an element with cursors keys. The selected element is returned.
|
||||
gridselect :: GSConfig a -> [(String,a)] -> X (Maybe a)
|
||||
gridselect _ [] = return Nothing
|
||||
gridselect gsconfig elmap =
|
||||
withDisplay $ \dpy -> do
|
||||
rootw <- asks theRoot
|
||||
@@ -487,7 +486,7 @@ buildDefaultGSConfig :: (a -> Bool -> X (String,String)) -> GSConfig a
|
||||
buildDefaultGSConfig col = GSConfig 50 130 10 col "xft:Sans-8" defaultGSNav (1/2) (1/2)
|
||||
|
||||
defaultGSNav :: NavigateMap
|
||||
defaultGSNav = M.map tupadd $ M.fromList
|
||||
defaultGSNav = M.map (\(x,y) (a,b) -> (x+a,y+b)) $ M.fromList
|
||||
[((0,xK_Left) ,(-1,0))
|
||||
,((0,xK_h) ,(-1,0))
|
||||
,((0,xK_Right),(1,0))
|
||||
@@ -523,3 +522,15 @@ runSelectedAction conf actions = do
|
||||
case selectedActionM of
|
||||
Just selectedAction -> selectedAction
|
||||
Nothing -> return ()
|
||||
|
||||
-- | Select a workspace and view it using the given function
|
||||
-- (normally 'W.view' or 'W.greedyView')
|
||||
--
|
||||
-- Another option is to shift the current window to the selected workspace:
|
||||
--
|
||||
-- > gridselectWorkspace (\ws -> W.greedyView ws . W.shift ws)
|
||||
gridselectWorkspace :: GSConfig WorkspaceId ->
|
||||
(WorkspaceId -> WindowSet -> WindowSet) -> X ()
|
||||
gridselectWorkspace conf viewFunc = withWindowSet $ \ws -> do
|
||||
let wss = map W.tag $ W.hidden ws ++ map W.workspace (W.current ws : W.visible ws)
|
||||
gridselect conf (zip wss wss) >>= flip whenJust (windows . viewFunc)
|
@@ -15,17 +15,138 @@
|
||||
module XMonad.Actions.OnScreen (
|
||||
-- * Usage
|
||||
-- $usage
|
||||
onScreen
|
||||
onScreen
|
||||
, onScreen'
|
||||
, Focus(..)
|
||||
, viewOnScreen
|
||||
, greedyViewOnScreen
|
||||
, onlyOnScreen
|
||||
, toggleOnScreen
|
||||
, toggleGreedyOnScreen
|
||||
) where
|
||||
|
||||
import XMonad.StackSet
|
||||
import Control.Monad(guard)
|
||||
import Data.List
|
||||
import Data.Maybe(fromMaybe)
|
||||
import Data.Function(on)
|
||||
import XMonad
|
||||
import XMonad.Core
|
||||
import XMonad.StackSet hiding (new)
|
||||
|
||||
import Control.Monad (guard)
|
||||
-- import Control.Monad.State.Class (gets)
|
||||
import Data.Maybe (fromMaybe)
|
||||
|
||||
|
||||
-- | Focus data definitions
|
||||
data Focus = FocusNew -- ^ always focus the new screen
|
||||
| FocusCurrent -- ^ always keep the focus on the current screen
|
||||
| FocusTag WorkspaceId -- ^ always focus tag i on the new stack
|
||||
| FocusTagVisible WorkspaceId -- ^ focus tag i only if workspace with tag i is visible on the old stack
|
||||
|
||||
|
||||
-- | Run any function that modifies the stack on a given screen. This function
|
||||
-- will also need to know which Screen to focus after the function has been
|
||||
-- run.
|
||||
onScreen :: (WindowSet -> WindowSet) -- ^ function to run
|
||||
-> Focus -- ^ what to do with the focus
|
||||
-> ScreenId -- ^ screen id
|
||||
-> WindowSet -- ^ current stack
|
||||
-> WindowSet
|
||||
onScreen f foc sc st = fromMaybe st $ do
|
||||
ws <- lookupWorkspace sc st
|
||||
|
||||
let fStack = f $ view ws st
|
||||
|
||||
return $ setFocus foc st fStack
|
||||
|
||||
|
||||
-- set focus for new stack
|
||||
setFocus :: Focus
|
||||
-> WindowSet -- ^ old stack
|
||||
-> WindowSet -- ^ new stack
|
||||
-> WindowSet
|
||||
setFocus FocusNew _ new = new
|
||||
setFocus FocusCurrent old new =
|
||||
case lookupWorkspace (screen $ current old) new of
|
||||
Nothing -> new
|
||||
Just i -> view i new
|
||||
setFocus (FocusTag i) _ new = view i new
|
||||
setFocus (FocusTagVisible i) old new =
|
||||
if i `elem` map (tag . workspace) (visible old)
|
||||
then setFocus (FocusTag i) old new
|
||||
else setFocus FocusCurrent old new
|
||||
|
||||
-- | A variation of @onScreen@ which will take any @X ()@ function and run it
|
||||
-- on the given screen.
|
||||
-- Warning: This function will change focus even if the function it's supposed
|
||||
-- to run doesn't succeed.
|
||||
onScreen' :: X () -- ^ X function to run
|
||||
-> Focus -- ^ focus
|
||||
-> ScreenId -- ^ screen id
|
||||
-> X ()
|
||||
onScreen' x foc sc = do
|
||||
st <- gets windowset
|
||||
case lookupWorkspace sc st of
|
||||
Nothing -> return ()
|
||||
Just ws -> do
|
||||
windows $ view ws
|
||||
x
|
||||
windows $ setFocus foc st
|
||||
|
||||
|
||||
-- | Switch to workspace @i@ on screen @sc@. If @i@ is visible use @view@ to
|
||||
-- switch focus to the workspace @i@.
|
||||
viewOnScreen :: ScreenId -- ^ screen id
|
||||
-> WorkspaceId -- ^ index of the workspace
|
||||
-> WindowSet -- ^ current stack
|
||||
-> WindowSet
|
||||
viewOnScreen sid i =
|
||||
onScreen (view i) (FocusTag i) sid
|
||||
|
||||
-- | Switch to workspace @i@ on screen @sc@. If @i@ is visible use @greedyView@
|
||||
-- to switch the current workspace with workspace @i@.
|
||||
greedyViewOnScreen :: ScreenId -- ^ screen id
|
||||
-> WorkspaceId -- ^ index of the workspace
|
||||
-> WindowSet -- ^ current stack
|
||||
-> WindowSet
|
||||
greedyViewOnScreen sid i =
|
||||
onScreen (greedyView i) (FocusTagVisible i) sid
|
||||
|
||||
-- | Switch to workspace @i@ on screen @sc@. If @i@ is visible do nothing.
|
||||
onlyOnScreen :: ScreenId -- ^ screen id
|
||||
-> WorkspaceId -- ^ index of the workspace
|
||||
-> WindowSet -- ^ current stack
|
||||
-> WindowSet
|
||||
onlyOnScreen sid i =
|
||||
onScreen (view i) FocusCurrent sid
|
||||
|
||||
-- | @toggleOrView@ as in "XMonad.Actions.CycleWS" for @onScreen@ with view
|
||||
toggleOnScreen :: ScreenId -- ^ screen id
|
||||
-> WorkspaceId -- ^ index of the workspace
|
||||
-> WindowSet -- ^ current stack
|
||||
-> WindowSet
|
||||
toggleOnScreen sid i =
|
||||
onScreen (toggleOrView' view i) FocusCurrent sid
|
||||
|
||||
-- | @toggleOrView@ from "XMonad.Actions.CycleWS" for @onScreen@ with greedyView
|
||||
toggleGreedyOnScreen :: ScreenId -- ^ screen id
|
||||
-> WorkspaceId -- ^ index of the workspace
|
||||
-> WindowSet -- ^ current stack
|
||||
-> WindowSet
|
||||
toggleGreedyOnScreen sid i =
|
||||
onScreen (toggleOrView' greedyView i) FocusCurrent sid
|
||||
|
||||
|
||||
-- a \"pure\" version of X.A.CycleWS.toggleOrDoSkip
|
||||
toggleOrView' :: (WorkspaceId -> WindowSet -> WindowSet) -- ^ function to run
|
||||
-> WorkspaceId -- ^ tag to look for
|
||||
-> WindowSet -- ^ current stackset
|
||||
-> WindowSet
|
||||
toggleOrView' f i st = fromMaybe (f i st) $ do
|
||||
let st' = hidden st
|
||||
-- make sure we actually have to do something
|
||||
guard $ i == (tag . workspace $ current st)
|
||||
guard $ not (null st')
|
||||
-- finally, toggle!
|
||||
return $ f (tag . head $ st') st
|
||||
|
||||
|
||||
-- $usage
|
||||
--
|
||||
@@ -62,54 +183,7 @@ import Data.Function(on)
|
||||
--
|
||||
-- > , ((modm .|. controlMask, xK_1) windows (viewOnScreen 0 "1"))
|
||||
--
|
||||
-- where 0 is the first screen and "1" the workspace with the tag "1".
|
||||
-- where 0 is the first screen and \"1\" the workspace with the tag \"1\".
|
||||
--
|
||||
-- For detailed instructions on editing your key bindings, see
|
||||
-- "XMonad.Doc.Extending#Editing_key_bindings".
|
||||
|
||||
-- | Switch to the (hidden) workspace with index 'i' on the screen 'sc'.
|
||||
-- A default function (for example 'view' or 'greedyView') will be run if 'sc' is
|
||||
-- the current screen, no valid screen id or workspace 'i' is already visible.
|
||||
onScreen :: (Eq sid, Eq i)
|
||||
=> (i -> StackSet i l a sid sd -> StackSet i l a sid sd) -- ^ default action
|
||||
-> sid -- ^ screen id
|
||||
-> i -- ^ index of the workspace
|
||||
-> StackSet i l a sid sd -- ^ current stack
|
||||
-> StackSet i l a sid sd
|
||||
onScreen defFunc sc i st = fromMaybe (defFunc i st) $ do
|
||||
-- on unfocused current screen
|
||||
guard $ screen (current st) /= sc
|
||||
x <- find ((i==) . tag ) (hidden st)
|
||||
s <- find ((sc==) . screen) (screens st)
|
||||
o <- find ((sc==) . screen) (visible st)
|
||||
let newScreen = s { workspace = x }
|
||||
return st { visible = newScreen : deleteBy ((==) `on` screen) newScreen (visible st)
|
||||
, hidden = workspace o : deleteBy ((==) `on` tag) x (hidden st)
|
||||
}
|
||||
|
||||
-- | Switch to workspace 'i' on screen 'sc'. If 'i' is visible use 'greedyView'
|
||||
-- to switch the current workspace with workspace 'i'.
|
||||
greedyViewOnScreen :: (Eq sid, Eq i)
|
||||
=> sid -- ^ screen id
|
||||
-> i -- ^ index of the workspace
|
||||
-> StackSet i l a sid sd -- ^ current stack
|
||||
-> StackSet i l a sid sd
|
||||
greedyViewOnScreen = onScreen greedyView
|
||||
|
||||
-- | Switch to workspace 'i' on screen 'sc'. If 'i' is visible use 'view' to
|
||||
-- switch focus to the workspace 'i'.
|
||||
viewOnScreen :: (Eq sid, Eq i)
|
||||
=> sid -- ^ screen id
|
||||
-> i -- ^ index of the workspace
|
||||
-> StackSet i l a sid sd -- ^ current stack
|
||||
-> StackSet i l a sid sd
|
||||
viewOnScreen = onScreen view
|
||||
|
||||
-- | Switch to workspace 'i' on screen 'sc'. If 'i' is visible do nothing.
|
||||
onlyOnScreen :: (Eq sid, Eq i)
|
||||
=> sid -- ^ screen id
|
||||
-> i -- ^ index of the workspace
|
||||
-> StackSet i l a sid sd -- ^ current stack
|
||||
-> StackSet i l a sid sd
|
||||
onlyOnScreen = onScreen doNothing
|
||||
where doNothing _ st = st
|
||||
|
@@ -21,7 +21,6 @@ module XMonad.Actions.PerWorkspaceKeys (
|
||||
|
||||
import XMonad
|
||||
import XMonad.StackSet as S
|
||||
import Data.List (find)
|
||||
|
||||
-- $usage
|
||||
--
|
||||
@@ -42,9 +41,9 @@ chooseAction f = withWindowSet (f . S.currentTag)
|
||||
-- If it isn't listed, then run default action (marked with empty string, \"\"), or do nothing if default isn't supplied.
|
||||
bindOn :: [(String, X())] -> X()
|
||||
bindOn bindings = chooseAction chooser where
|
||||
chooser ws = case find ((ws==).fst) bindings of
|
||||
Just (_, action) -> action
|
||||
Nothing -> case find ((""==).fst) bindings of
|
||||
Just (_, action) -> action
|
||||
chooser ws = case lookup ws bindings of
|
||||
Just action -> action
|
||||
Nothing -> case lookup "" bindings of
|
||||
Just action -> action
|
||||
Nothing -> return ()
|
||||
|
||||
|
@@ -289,20 +289,17 @@ google = searchEngine "google" "http://www.google.com/search?num=100&q="
|
||||
hackage = searchEngine "hackage" "http://hackage.haskell.org/package/"
|
||||
hoogle = searchEngine "hoogle" "http://www.haskell.org/hoogle/?q="
|
||||
images = searchEngine "images" "http://images.google.fr/images?q="
|
||||
imdb = searchEngine "imdb" "http://www.imdb.com/Find?select=all&for="
|
||||
imdb = searchEngine "imdb" "http://www.imdb.com/find?s=all&q="
|
||||
isohunt = searchEngine "isohunt" "http://isohunt.com/torrents/?ihq="
|
||||
lucky = searchEngine "lucky" "http://www.google.com/search?btnI&q="
|
||||
maps = searchEngine "maps" "http://maps.google.com/maps?q="
|
||||
mathworld = searchEngine "mathworld" "http://mathworld.wolfram.com/search/?query="
|
||||
scholar = searchEngine "scholar" "http://scholar.google.com/scholar?q="
|
||||
thesaurus = searchEngine "thesaurus" "http://thesaurus.reference.com/search?q="
|
||||
wikipedia = searchEngine "wiki" "https://secure.wikimedia.org/wikipedia/en/wiki/Special:Search?go=Go&search="
|
||||
wiktionary = searchEngine "wikt" "http://en.wiktionary.org/wiki/Special:Search?go=Go&search="
|
||||
wikipedia = searchEngine "wiki" "http://en.wikipedia.org/wiki/Special:Search?go=Go&search="
|
||||
wiktionary = searchEngine "wikt" "http://en.wiktionary.org/wiki/Special:Search?go=Go&search="
|
||||
youtube = searchEngine "youtube" "http://www.youtube.com/results?search_type=search_videos&search_query="
|
||||
{- 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. -}
|
||||
wayback = searchEngine "wayback" "http://web.archive.org/"
|
||||
wayback = searchEngineF "wayback" ("http://web.archive.org/web/*/"++)
|
||||
|
||||
multi :: SearchEngine
|
||||
multi = namedEngine "multi" $ foldr1 (!>) [amazon, alpha, codesearch, deb, debbts, debpts, dictionary, google, hackage, hoogle, images, imdb, isohunt, lucky, maps, mathworld, scholar, thesaurus, wayback, wikipedia, wiktionary, (prefixAware google)]
|
||||
|
@@ -1,3 +1,4 @@
|
||||
{-# LANGUAGE DeriveDataTypeable #-}
|
||||
-----------------------------------------------------------------------------
|
||||
-- |
|
||||
-- Module : XMonad.Actions.SpawnOn
|
||||
@@ -18,7 +19,6 @@ module XMonad.Actions.SpawnOn (
|
||||
-- * Usage
|
||||
-- $usage
|
||||
Spawner,
|
||||
mkSpawner,
|
||||
manageSpawn,
|
||||
spawnHere,
|
||||
spawnOn,
|
||||
@@ -28,7 +28,6 @@ module XMonad.Actions.SpawnOn (
|
||||
) where
|
||||
|
||||
import Data.List (isInfixOf)
|
||||
import Data.IORef
|
||||
import System.Posix.Types (ProcessID)
|
||||
|
||||
import XMonad
|
||||
@@ -37,6 +36,7 @@ import qualified XMonad.StackSet as W
|
||||
import XMonad.Hooks.ManageHelpers
|
||||
import XMonad.Prompt
|
||||
import XMonad.Prompt.Shell
|
||||
import qualified XMonad.Util.ExtensibleState as XS
|
||||
|
||||
-- $usage
|
||||
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
|
||||
@@ -44,17 +44,16 @@ import XMonad.Prompt.Shell
|
||||
-- > import XMonad.Actions.SpawnOn
|
||||
--
|
||||
-- > main = do
|
||||
-- > sp <- mkSpawner
|
||||
-- > xmonad defaultConfig {
|
||||
-- > ...
|
||||
-- > manageHook = manageSpawn sp <+> manageHook defaultConfig
|
||||
-- > manageHook = manageSpawn <+> manageHook defaultConfig
|
||||
-- > ...
|
||||
-- > }
|
||||
--
|
||||
-- To ensure that application appears on a workspace it was launched at, add keybindings like:
|
||||
--
|
||||
-- > , ((mod1Mask,xK_o), spawnHere sp "urxvt")
|
||||
-- > , ((mod1Mask,xK_s), shellPromptHere sp defaultXPConfig)
|
||||
-- > , ((mod1Mask,xK_o), spawnHere "urxvt")
|
||||
-- > , ((mod1Mask,xK_s), shellPromptHere defaultXPConfig)
|
||||
--
|
||||
-- The module can also be used to apply other manage hooks to the window of
|
||||
-- the spawned application(e.g. float or resize it).
|
||||
@@ -62,26 +61,29 @@ import XMonad.Prompt.Shell
|
||||
-- For detailed instructions on editing your key bindings, see
|
||||
-- "XMonad.Doc.Extending#Editing_key_bindings".
|
||||
|
||||
newtype Spawner = Spawner {pidsRef :: IORef [(ProcessID, ManageHook)]}
|
||||
newtype Spawner = Spawner {pidsRef :: [(ProcessID, ManageHook)]} deriving Typeable
|
||||
|
||||
instance ExtensionClass Spawner where
|
||||
initialValue = Spawner []
|
||||
|
||||
maxPids :: Int
|
||||
maxPids = 5
|
||||
|
||||
-- | Create 'Spawner' which then has to be passed to other functions.
|
||||
mkSpawner :: (Functor m, MonadIO m) => m Spawner
|
||||
mkSpawner = io . fmap Spawner $ newIORef []
|
||||
-- | Get the current Spawner or create one if it doesn't exist.
|
||||
modifySpawner :: ([(ProcessID, ManageHook)] -> [(ProcessID, ManageHook)]) -> X ()
|
||||
modifySpawner f = XS.modify (Spawner . f . pidsRef)
|
||||
|
||||
-- | Provides a manage hook to react on process spawned with
|
||||
-- 'spawnOn', 'spawnHere' etc.
|
||||
manageSpawn :: Spawner -> ManageHook
|
||||
manageSpawn sp = do
|
||||
pids <- io . readIORef $ pidsRef sp
|
||||
manageSpawn :: ManageHook
|
||||
manageSpawn = do
|
||||
Spawner pids <- liftX XS.get
|
||||
mp <- pid
|
||||
case flip lookup pids =<< mp of
|
||||
Nothing -> doF id
|
||||
Nothing -> idHook
|
||||
Just mh -> do
|
||||
whenJust mp $ \p ->
|
||||
io . modifyIORef (pidsRef sp) $ filter ((/= p) . fst)
|
||||
liftX . modifySpawner $ filter ((/= p) . fst)
|
||||
mh
|
||||
|
||||
mkPrompt :: (String -> X ()) -> XPConfig -> X ()
|
||||
@@ -91,32 +93,31 @@ mkPrompt cb c = do
|
||||
|
||||
-- | Replacement for Shell prompt ("XMonad.Prompt.Shell") which launches
|
||||
-- application on current workspace.
|
||||
shellPromptHere :: Spawner -> XPConfig -> X ()
|
||||
shellPromptHere sp = mkPrompt (spawnHere sp)
|
||||
shellPromptHere :: XPConfig -> X ()
|
||||
shellPromptHere = mkPrompt spawnHere
|
||||
|
||||
-- | Replacement for Shell prompt ("XMonad.Prompt.Shell") which launches
|
||||
-- application on given workspace.
|
||||
shellPromptOn :: Spawner -> WorkspaceId -> XPConfig -> X ()
|
||||
shellPromptOn sp ws = mkPrompt (spawnOn sp ws)
|
||||
shellPromptOn :: WorkspaceId -> XPConfig -> X ()
|
||||
shellPromptOn ws = mkPrompt (spawnOn ws)
|
||||
|
||||
-- | Replacement for 'spawn' which launches
|
||||
-- application on current workspace.
|
||||
spawnHere :: Spawner -> String -> X ()
|
||||
spawnHere sp cmd = withWindowSet $ \ws -> spawnOn sp (W.currentTag ws) cmd
|
||||
spawnHere :: String -> X ()
|
||||
spawnHere cmd = withWindowSet $ \ws -> spawnOn (W.currentTag ws) cmd
|
||||
|
||||
-- | Replacement for 'spawn' which launches
|
||||
-- application on given workspace.
|
||||
spawnOn :: Spawner -> WorkspaceId -> String -> X ()
|
||||
spawnOn sp ws cmd = spawnAndDo sp (doShift ws) cmd
|
||||
spawnOn :: WorkspaceId -> String -> X ()
|
||||
spawnOn ws cmd = spawnAndDo (doShift ws) cmd
|
||||
|
||||
-- | Spawn an application and apply the manage hook when it opens.
|
||||
spawnAndDo :: Spawner -> ManageHook -> String -> X ()
|
||||
spawnAndDo sp mh cmd = do
|
||||
spawnAndDo :: ManageHook -> String -> X ()
|
||||
spawnAndDo mh cmd = do
|
||||
p <- spawnPID $ mangle cmd
|
||||
io $ modifyIORef (pidsRef sp) (take maxPids . ((p,mh) :))
|
||||
modifySpawner $ (take maxPids . ((p,mh) :))
|
||||
where
|
||||
-- TODO this is silly, search for a better solution
|
||||
mangle xs | any (`elem` metaChars) xs || "exec" `isInfixOf` xs = xs
|
||||
| otherwise = "exec " ++ xs
|
||||
metaChars = "&|;"
|
||||
|
||||
|
@@ -1,3 +1,4 @@
|
||||
{-# LANGUAGE DeriveDataTypeable #-}
|
||||
-----------------------------------------------------------------------------
|
||||
-- |
|
||||
-- Module : XMonad.Actions.TopicSpace
|
||||
@@ -21,6 +22,7 @@ module XMonad.Actions.TopicSpace
|
||||
Topic
|
||||
, Dir
|
||||
, TopicConfig(..)
|
||||
, defaultTopicConfig
|
||||
, getLastFocusedTopics
|
||||
, setLastFocusedTopic
|
||||
, pprWindowSet
|
||||
@@ -56,7 +58,7 @@ import XMonad.Hooks.DynamicLog (PP(..))
|
||||
import qualified XMonad.Hooks.DynamicLog as DL
|
||||
|
||||
import XMonad.Util.Run (spawnPipe)
|
||||
import XMonad.Util.StringProp(getStringListProp,setStringListProp)
|
||||
import qualified XMonad.Util.ExtensibleState as XS
|
||||
|
||||
-- $overview
|
||||
-- This module allows to organize your workspaces on a precise topic basis. So
|
||||
@@ -74,129 +76,108 @@ import XMonad.Util.StringProp(getStringListProp,setStringListProp)
|
||||
-- $usage
|
||||
-- Here is an example of configuration using TopicSpace:
|
||||
--
|
||||
-- @
|
||||
-- -- The list of all topics/workspaces of your xmonad configuration.
|
||||
-- -- The order is important, new topics must be inserted
|
||||
-- -- at the end of the list if you want hot-restarting
|
||||
-- -- to work.
|
||||
-- myTopics :: [Topic]
|
||||
-- myTopics =
|
||||
-- [ \"dashboard\" -- the first one
|
||||
-- , \"admin\", \"build\", \"cleaning\", \"conf\", \"darcs\", \"haskell\", \"irc\"
|
||||
-- , \"mail\", \"movie\", \"music\", \"talk\", \"text\", \"tools\", \"web\", \"xmonad\"
|
||||
-- , \"yi\", \"documents\", \"twitter\", \"pdf\"
|
||||
-- ]
|
||||
-- @
|
||||
--
|
||||
-- @
|
||||
-- myTopicConfig :: TopicConfig
|
||||
-- myTopicConfig = TopicConfig
|
||||
-- { topicDirs = M.fromList $
|
||||
-- [ (\"conf\", \"w\/conf\")
|
||||
-- , (\"dashboard\", \"Desktop\")
|
||||
-- , (\"yi\", \"w\/dev-haskell\/yi\")
|
||||
-- , (\"darcs\", \"w\/dev-haskell\/darcs\")
|
||||
-- , (\"haskell\", \"w\/dev-haskell\")
|
||||
-- , (\"xmonad\", \"w\/dev-haskell\/xmonad\")
|
||||
-- , (\"tools\", \"w\/tools\")
|
||||
-- , (\"movie\", \"Movies\")
|
||||
-- , (\"talk\", \"w\/talks\")
|
||||
-- , (\"music\", \"Music\")
|
||||
-- , (\"documents\", \"w\/documents\")
|
||||
-- , (\"pdf\", \"w\/documents\")
|
||||
-- ]
|
||||
-- , defaultTopicAction = const $ spawnShell >*> 3
|
||||
-- , defaultTopic = \"dashboard\"
|
||||
-- , maxTopicHistory = 10
|
||||
-- , topicActions = M.fromList $
|
||||
-- [ (\"conf\", spawnShell >> spawnShellIn \"wd\/ertai\/private\")
|
||||
-- , (\"darcs\", spawnShell >*> 3)
|
||||
-- , (\"yi\", spawnShell >*> 3)
|
||||
-- , (\"haskell\", spawnShell >*> 2 >>
|
||||
-- spawnShellIn \"wd\/dev-haskell\/ghc\")
|
||||
-- , (\"xmonad\", spawnShellIn \"wd\/x11-wm\/xmonad\" >>
|
||||
-- spawnShellIn \"wd\/x11-wm\/xmonad\/contrib\" >>
|
||||
-- spawnShellIn \"wd\/x11-wm\/xmonad\/utils\" >>
|
||||
-- spawnShellIn \".xmonad\" >>
|
||||
-- spawnShellIn \".xmonad\")
|
||||
-- , (\"mail\", mailAction)
|
||||
-- , (\"irc\", ssh somewhere)
|
||||
-- , (\"admin\", ssh somewhere >>
|
||||
-- ssh nowhere)
|
||||
-- , (\"dashboard\", spawnShell)
|
||||
-- , (\"twitter\", spawnShell)
|
||||
-- , (\"web\", spawn browserCmd)
|
||||
-- , (\"movie\", spawnShell)
|
||||
-- , (\"documents\", spawnShell >*> 2 >>
|
||||
-- spawnShellIn \"Documents\" >*> 2)
|
||||
-- , (\"pdf\", spawn pdfViewerCmd)
|
||||
-- ]
|
||||
-- }
|
||||
-- @
|
||||
--
|
||||
-- @
|
||||
-- -- extend your keybindings
|
||||
-- myKeys conf\@XConfig{modMask=modm} =
|
||||
-- [ ((modm , xK_n ), spawnShell) -- %! Launch terminal
|
||||
-- , ((modm , xK_a ), currentTopicAction myTopicConfig)
|
||||
-- , ((modm , xK_g ), promptedGoto)
|
||||
-- , ((modm .|. shiftMask, xK_g ), promptedShift)
|
||||
-- ...
|
||||
-- ]
|
||||
-- ++
|
||||
-- [ ((modm, k), switchNthLastFocused myTopicConfig i)
|
||||
-- | (i, k) <- zip [1..] workspaceKeys]
|
||||
-- @
|
||||
--
|
||||
-- @
|
||||
-- spawnShell :: X ()
|
||||
-- spawnShell = currentTopicDir myTopicConfig >>= spawnShellIn
|
||||
-- @
|
||||
--
|
||||
-- @
|
||||
-- spawnShellIn :: Dir -> X ()
|
||||
-- spawnShellIn dir = spawn $ \"urxvt '(cd ''\" ++ dir ++ \"'' && \" ++ myShell ++ \" )'\"
|
||||
-- @
|
||||
--
|
||||
-- @
|
||||
-- goto :: Topic -> X ()
|
||||
-- goto = switchTopic myTopicConfig
|
||||
-- @
|
||||
--
|
||||
-- @
|
||||
-- promptedGoto :: X ()
|
||||
-- promptedGoto = workspacePrompt myXPConfig goto
|
||||
-- @
|
||||
--
|
||||
-- @
|
||||
-- promptedShift :: X ()
|
||||
-- promptedShift = workspacePrompt myXPConfig $ windows . W.shift
|
||||
-- @
|
||||
--
|
||||
-- @
|
||||
-- myConfig = do
|
||||
-- checkTopicConfig myTopics myTopicConfig
|
||||
-- myLogHook <- makeMyLogHook
|
||||
-- return $ defaultConfig
|
||||
-- { borderWidth = 1 -- Width of the window border in pixels.
|
||||
-- , workspaces = myTopics
|
||||
-- , layoutHook = myModifiers myLayout
|
||||
-- , manageHook = myManageHook
|
||||
-- , logHook = myLogHook
|
||||
-- , handleEventHook = myHandleEventHook
|
||||
-- , terminal = myTerminal -- The preferred terminal program.
|
||||
-- , normalBorderColor = \"#3f3c6d\"
|
||||
-- , focusedBorderColor = \"#4f66ff\"
|
||||
-- , XMonad.modMask = mod1Mask
|
||||
-- , keys = myKeys
|
||||
-- , mouseBindings = myMouseBindings
|
||||
-- }
|
||||
-- @
|
||||
--
|
||||
-- @
|
||||
-- main :: IO ()
|
||||
-- main = xmonad =<< myConfig
|
||||
-- @
|
||||
-- > -- The list of all topics/workspaces of your xmonad configuration.
|
||||
-- > -- The order is important, new topics must be inserted
|
||||
-- > -- at the end of the list if you want hot-restarting
|
||||
-- > -- to work.
|
||||
-- > myTopics :: [Topic]
|
||||
-- > myTopics =
|
||||
-- > [ "dashboard" -- the first one
|
||||
-- > , "admin", "build", "cleaning", "conf", "darcs", "haskell", "irc"
|
||||
-- > , "mail", "movie", "music", "talk", "text", "tools", "web", "xmonad"
|
||||
-- > , "yi", "documents", "twitter", "pdf"
|
||||
-- > ]
|
||||
-- >
|
||||
-- > myTopicConfig :: TopicConfig
|
||||
-- > myTopicConfig = defaultTopicConfig
|
||||
-- > { topicDirs = M.fromList $
|
||||
-- > [ ("conf", "w/conf")
|
||||
-- > , ("dashboard", "Desktop")
|
||||
-- > , ("yi", "w/dev-haskell/yi")
|
||||
-- > , ("darcs", "w/dev-haskell/darcs")
|
||||
-- > , ("haskell", "w/dev-haskell")
|
||||
-- > , ("xmonad", "w/dev-haskell/xmonad")
|
||||
-- > , ("tools", "w/tools")
|
||||
-- > , ("movie", "Movies")
|
||||
-- > , ("talk", "w/talks")
|
||||
-- > , ("music", "Music")
|
||||
-- > , ("documents", "w/documents")
|
||||
-- > , ("pdf", "w/documents")
|
||||
-- > ]
|
||||
-- > , defaultTopicAction = const $ spawnShell >*> 3
|
||||
-- > , defaultTopic = "dashboard"
|
||||
-- > , topicActions = M.fromList $
|
||||
-- > [ ("conf", spawnShell >> spawnShellIn "wd/ertai/private")
|
||||
-- > , ("darcs", spawnShell >*> 3)
|
||||
-- > , ("yi", spawnShell >*> 3)
|
||||
-- > , ("haskell", spawnShell >*> 2 >>
|
||||
-- > spawnShellIn "wd/dev-haskell/ghc")
|
||||
-- > , ("xmonad", spawnShellIn "wd/x11-wm/xmonad" >>
|
||||
-- > spawnShellIn "wd/x11-wm/xmonad/contrib" >>
|
||||
-- > spawnShellIn "wd/x11-wm/xmonad/utils" >>
|
||||
-- > spawnShellIn ".xmonad" >>
|
||||
-- > spawnShellIn ".xmonad")
|
||||
-- > , ("mail", mailAction)
|
||||
-- > , ("irc", ssh somewhere)
|
||||
-- > , ("admin", ssh somewhere >>
|
||||
-- > ssh nowhere)
|
||||
-- > , ("dashboard", spawnShell)
|
||||
-- > , ("twitter", spawnShell)
|
||||
-- > , ("web", spawn browserCmd)
|
||||
-- > , ("movie", spawnShell)
|
||||
-- > , ("documents", spawnShell >*> 2 >>
|
||||
-- > spawnShellIn "Documents" >*> 2)
|
||||
-- > , ("pdf", spawn pdfViewerCmd)
|
||||
-- > ]
|
||||
-- > }
|
||||
-- >
|
||||
-- > -- extend your keybindings
|
||||
-- > myKeys conf@XConfig{modMask=modm} =
|
||||
-- > [ ((modm , xK_n ), spawnShell) -- %! Launch terminal
|
||||
-- > , ((modm , xK_a ), currentTopicAction myTopicConfig)
|
||||
-- > , ((modm , xK_g ), promptedGoto)
|
||||
-- > , ((modm .|. shiftMask, xK_g ), promptedShift)
|
||||
-- > {- more keys ... -}
|
||||
-- > ]
|
||||
-- > ++
|
||||
-- > [ ((modm, k), switchNthLastFocused myTopicConfig i)
|
||||
-- > | (i, k) <- zip [1..] workspaceKeys]
|
||||
-- >
|
||||
-- > spawnShell :: X ()
|
||||
-- > spawnShell = currentTopicDir myTopicConfig >>= spawnShellIn
|
||||
-- >
|
||||
-- > spawnShellIn :: Dir -> X ()
|
||||
-- > spawnShellIn dir = spawn $ "urxvt '(cd ''" ++ dir ++ "'' && " ++ myShell ++ " )'"
|
||||
-- >
|
||||
-- > goto :: Topic -> X ()
|
||||
-- > goto = switchTopic myTopicConfig
|
||||
-- >
|
||||
-- > promptedGoto :: X ()
|
||||
-- > promptedGoto = workspacePrompt myXPConfig goto
|
||||
-- >
|
||||
-- > promptedShift :: X ()
|
||||
-- > promptedShift = workspacePrompt myXPConfig $ windows . W.shift
|
||||
-- >
|
||||
-- > myConfig = do
|
||||
-- > checkTopicConfig myTopics myTopicConfig
|
||||
-- > myLogHook <- makeMyLogHook
|
||||
-- > return $ defaultConfig
|
||||
-- > { borderWidth = 1 -- Width of the window border in pixels.
|
||||
-- > , workspaces = myTopics
|
||||
-- > , layoutHook = myModifiers myLayout
|
||||
-- > , manageHook = myManageHook
|
||||
-- > , logHook = myLogHook
|
||||
-- > , handleEventHook = myHandleEventHook
|
||||
-- > , terminal = myTerminal -- The preferred terminal program.
|
||||
-- > , normalBorderColor = "#3f3c6d"
|
||||
-- > , focusedBorderColor = "#4f66ff"
|
||||
-- > , XMonad.modMask = mod1Mask
|
||||
-- > , keys = myKeys
|
||||
-- > , mouseBindings = myMouseBindings
|
||||
-- > }
|
||||
-- >
|
||||
-- > main :: IO ()
|
||||
-- > main = xmonad =<< myConfig
|
||||
|
||||
-- | An alias for @flip replicateM_@
|
||||
(>*>) :: Monad m => m a -> Int -> m ()
|
||||
@@ -225,19 +206,31 @@ data TopicConfig = TopicConfig { topicDirs :: M.Map Topic Dir
|
||||
-- numeric keypad.
|
||||
}
|
||||
|
||||
defaultTopicConfig :: TopicConfig
|
||||
defaultTopicConfig = TopicConfig { topicDirs = M.empty
|
||||
, topicActions = M.empty
|
||||
, defaultTopicAction = const (ask >>= spawn . terminal . config)
|
||||
, defaultTopic = "1"
|
||||
, maxTopicHistory = 10
|
||||
}
|
||||
|
||||
newtype PrevTopics = PrevTopics { getPrevTopics :: [String] } deriving (Read,Show,Typeable)
|
||||
instance ExtensionClass PrevTopics where
|
||||
initialValue = PrevTopics []
|
||||
extensionType = PersistentExtension
|
||||
|
||||
-- | Returns the list of last focused workspaces the empty list otherwise.
|
||||
-- This function rely on a reserved property namely _XMONAD_LAST_FOCUSED_WORKSPACES.
|
||||
getLastFocusedTopics :: X [String]
|
||||
getLastFocusedTopics = asks display >>= flip getStringListProp "_XMONAD_LAST_FOCUSED_WORKSPACES"
|
||||
getLastFocusedTopics = XS.gets getPrevTopics
|
||||
|
||||
-- | Given a 'TopicConfig', the last focused topic, and a predicate that will
|
||||
-- select topics that one want to keep, this function will set the property
|
||||
-- of last focused topics.
|
||||
setLastFocusedTopic :: TopicConfig -> Topic -> (Topic -> Bool) -> X ()
|
||||
setLastFocusedTopic tg w predicate = do
|
||||
disp <- asks display
|
||||
setStringListProp disp "_XMONAD_LAST_FOCUSED_WORKSPACES"
|
||||
. take (maxTopicHistory tg) . nub . (w:) . filter predicate =<< getLastFocusedTopics
|
||||
setLastFocusedTopic tg w predicate =
|
||||
XS.modify $ PrevTopics
|
||||
. take (maxTopicHistory tg) . nub . (w:) . filter predicate
|
||||
. getPrevTopics
|
||||
|
||||
-- | This function is a variant of 'DL.pprWindowSet' which takes a topic configuration
|
||||
-- and a pretty-printing record 'PP'. It will show the list of topics sorted historically
|
||||
|
@@ -91,8 +91,10 @@ updatePointer p = do
|
||||
where fraction x y = floor (x * fromIntegral y)
|
||||
|
||||
windowAttributesToRectangle :: WindowAttributes -> Rectangle
|
||||
windowAttributesToRectangle wa = Rectangle (fi (wa_x wa)) (fi (wa_y wa))
|
||||
(fi (wa_width wa)) (fi (wa_height wa))
|
||||
windowAttributesToRectangle wa = Rectangle (fi (wa_x wa))
|
||||
(fi (wa_y wa))
|
||||
(fi (wa_width wa + 2 * wa_border_width wa))
|
||||
(fi (wa_height wa + 2 * wa_border_width wa))
|
||||
moveWithin :: Ord a => a -> a -> a -> a
|
||||
moveWithin now lower upper =
|
||||
if now < lower
|
||||
|
@@ -58,8 +58,9 @@ and define appropriate key bindings:
|
||||
|
||||
(Note that Firefox v3 and up have a class-name of \"Firefox\" and \"Navigator\";
|
||||
lower versions use other classnames such as \"Firefox-bin\". Either choose the
|
||||
appropriate one, or cover your bases by using instead something like
|
||||
@(className =? \"Firefox\" <||> className =? \"Firefox-bin\")@.)
|
||||
appropriate one, or cover your bases by using instead something like:
|
||||
|
||||
> (className =? "Firefox" <||> className =? "Firefox-bin")
|
||||
|
||||
For detailed instructions on editing your key bindings, see
|
||||
"XMonad.Doc.Extending#Editing_key_bindings". -}
|
||||
@@ -171,14 +172,14 @@ runOrRaiseAndDo = raiseAndDo . safeSpawnProg
|
||||
{- | if the window is found the window is focused and set to master
|
||||
otherwise, the first argument is called.
|
||||
|
||||
> raiseMaster (runInTerm \"-title ghci\" \"zsh -c \'ghci\'\") (title =? \"ghci\") -}
|
||||
> raiseMaster (runInTerm "-title ghci" "zsh -c 'ghci'") (title =? "ghci") -}
|
||||
raiseMaster :: X () -> Query Bool -> X ()
|
||||
raiseMaster raisef thatUserQuery = raiseAndDo raisef thatUserQuery (\_ -> windows W.swapMaster)
|
||||
|
||||
{- | If the window is found the window is focused and set to master
|
||||
otherwise, action is run.
|
||||
|
||||
> runOrRaiseMaster \"firefox\" (className =? \"Firefox\"))
|
||||
> runOrRaiseMaster "firefox" (className =? "Firefox"))
|
||||
-}
|
||||
runOrRaiseMaster :: String -> Query Bool -> X ()
|
||||
runOrRaiseMaster run query = runOrRaiseAndDo run query (\_ -> windows W.swapMaster)
|
||||
|
@@ -1,4 +1,5 @@
|
||||
{-# OPTIONS_GHC -fglasgow-exts -fno-warn-missing-signatures #-}
|
||||
{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
|
||||
{-# LANGUAGE NoMonomorphismRestriction #-}
|
||||
-----------------------------------------------------------------------------
|
||||
-- |
|
||||
-- Module : XMonad.Config.Arossato
|
||||
|
215
XMonad/Config/Bluetile.hs
Normal file
215
XMonad/Config/Bluetile.hs
Normal file
@@ -0,0 +1,215 @@
|
||||
{-# OPTIONS -fno-warn-missing-signatures #-}
|
||||
----------------------------------------------------------------------------
|
||||
-- |
|
||||
-- Module : XMonad.Config.Bluetile
|
||||
-- Copyright : (c) Jan Vornberger 2009
|
||||
-- License : BSD3-style (see LICENSE)
|
||||
--
|
||||
-- Maintainer : jan.vornberger@informatik.uni-oldenburg.de
|
||||
-- Stability : unstable
|
||||
-- Portability : not portable
|
||||
--
|
||||
-- This is the default configuration of Bluetile
|
||||
-- (<http://projects.haskell.org/bluetile/>). If you
|
||||
-- are migrating from Bluetile to xmonad or want to create
|
||||
-- a similar setup, then this will give you pretty much
|
||||
-- the same thing, except for Bluetile's helper applications
|
||||
-- such as the dock.
|
||||
--
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
module XMonad.Config.Bluetile (
|
||||
-- * Usage
|
||||
-- $usage
|
||||
bluetileConfig
|
||||
) where
|
||||
|
||||
import XMonad hiding ( (|||) )
|
||||
|
||||
import XMonad.Layout hiding ( (|||) )
|
||||
import XMonad.Layout.BorderResize
|
||||
import XMonad.Layout.BoringWindows
|
||||
import XMonad.Layout.ButtonDecoration
|
||||
import XMonad.Layout.Decoration
|
||||
import XMonad.Layout.DecorationAddons
|
||||
import XMonad.Layout.DraggingVisualizer
|
||||
import XMonad.Layout.LayoutCombinators
|
||||
import XMonad.Layout.Maximize
|
||||
import XMonad.Layout.Minimize
|
||||
import XMonad.Layout.MouseResizableTile
|
||||
import XMonad.Layout.Named
|
||||
import XMonad.Layout.NoBorders
|
||||
import XMonad.Layout.PositionStoreFloat
|
||||
import XMonad.Layout.WindowSwitcherDecoration
|
||||
|
||||
import XMonad.Actions.BluetileCommands
|
||||
import XMonad.Actions.CycleWS
|
||||
import XMonad.Actions.WindowMenu
|
||||
|
||||
import XMonad.Hooks.CurrentWorkspaceOnTop
|
||||
import XMonad.Hooks.EwmhDesktops
|
||||
import XMonad.Hooks.ManageDocks
|
||||
import XMonad.Hooks.PositionStoreHooks
|
||||
import XMonad.Hooks.RestoreMinimized
|
||||
import XMonad.Hooks.ServerMode
|
||||
import XMonad.Hooks.WorkspaceByPos
|
||||
|
||||
import XMonad.Config.Gnome
|
||||
|
||||
import qualified XMonad.StackSet as W
|
||||
import qualified Data.Map as M
|
||||
|
||||
import System.Exit
|
||||
import Data.Monoid
|
||||
import Control.Monad(when)
|
||||
|
||||
-- $usage
|
||||
-- To use this module, start with the following @~\/.xmonad\/xmonad.hs@:
|
||||
--
|
||||
-- > import XMonad
|
||||
-- > import XMonad.Config.Bluetile
|
||||
-- > import XMonad.Util.Replace
|
||||
-- >
|
||||
-- > main = replace >> xmonad bluetileConfig
|
||||
--
|
||||
-- The invocation of 'replace' will replace a currently running
|
||||
-- window manager. This is the default behaviour of Bluetile as well.
|
||||
-- See "XMonad.Util.Replace" for more information.
|
||||
|
||||
bluetileWorkspaces :: [String]
|
||||
bluetileWorkspaces = ["1","2","3","4","5","6","7","8","9","0"]
|
||||
|
||||
bluetileKeys :: XConfig Layout -> M.Map (KeyMask, KeySym) (X ())
|
||||
bluetileKeys conf@(XConfig {XMonad.modMask = modMask'}) = M.fromList $
|
||||
-- launching and killing programs
|
||||
[ ((modMask' , xK_Return), spawn $ XMonad.terminal conf) -- %! Launch terminal
|
||||
, ((modMask', xK_p ), gnomeRun) -- %! Launch Gnome "Run application" dialog
|
||||
, ((modMask' .|. shiftMask, xK_c ), kill) -- %! Close the focused window
|
||||
|
||||
, ((modMask', xK_F5 ), refresh) -- %! Resize viewed windows to the correct size
|
||||
, ((modMask' .|. shiftMask, xK_F5 ), setLayout $ XMonad.layoutHook conf) -- %! Reset the layouts on the current workspace to default
|
||||
|
||||
, ((modMask', xK_o ), windowMenu)
|
||||
|
||||
-- move focus up or down the window stack
|
||||
, ((modMask', xK_Tab ), focusDown) -- %! Move focus to the next window
|
||||
, ((modMask' .|. shiftMask, xK_Tab ), focusUp) -- %! Move focus to the previous window
|
||||
, ((modMask', xK_j ), focusDown) -- %! Move focus to the next window
|
||||
, ((modMask', xK_k ), focusUp) -- %! Move focus to the previous window
|
||||
, ((modMask', xK_space ), focusMaster) -- %! Move focus to the master window
|
||||
|
||||
-- modifying the window order
|
||||
, ((modMask' .|. shiftMask, xK_space ), windows W.swapMaster) -- %! Swap the focused window and the master window
|
||||
, ((modMask' .|. shiftMask, xK_j ), windows W.swapDown ) -- %! Swap the focused window with the next window
|
||||
, ((modMask' .|. shiftMask, xK_k ), windows W.swapUp ) -- %! Swap the focused window with the previous window
|
||||
|
||||
-- resizing the master/slave ratio
|
||||
, ((modMask', xK_h ), sendMessage Shrink) -- %! Shrink the master area
|
||||
, ((modMask', xK_l ), sendMessage Expand) -- %! Expand the master area
|
||||
, ((modMask', xK_u ), sendMessage ShrinkSlave) -- %! Shrink a slave area
|
||||
, ((modMask', xK_i ), sendMessage ExpandSlave) -- %! Expand a slave area
|
||||
|
||||
-- floating layer support
|
||||
, ((modMask', xK_t ), withFocused $ windows . W.sink) -- %! Push window back into tiling
|
||||
, ((modMask' .|. shiftMask, xK_t ), withFocused $ float ) -- %! Float window
|
||||
|
||||
-- increase or decrease number of windows in the master area
|
||||
, ((modMask' , xK_comma ), sendMessage (IncMasterN 1)) -- %! Increment the number of windows in the master area
|
||||
, ((modMask' , xK_period), sendMessage (IncMasterN (-1))) -- %! Deincrement the number of windows in the master area
|
||||
|
||||
-- quit, or restart
|
||||
, ((modMask' .|. shiftMask, xK_q ), io (exitWith ExitSuccess)) -- %! Quit bluetile
|
||||
, ((modMask' , xK_q ), spawn "bluetile --restart") -- %! Restart bluetile
|
||||
|
||||
-- Metacity-like workspace switching
|
||||
, ((mod1Mask .|. controlMask, xK_Left), prevWS)
|
||||
, ((mod1Mask .|. controlMask, xK_Right), nextWS)
|
||||
, ((mod1Mask .|. controlMask .|. shiftMask, xK_Left), shiftToPrev >> prevWS)
|
||||
, ((mod1Mask .|. controlMask .|. shiftMask, xK_Right), shiftToNext >> nextWS)
|
||||
|
||||
-- more Metacity keys
|
||||
, ((mod1Mask , xK_F2), gnomeRun)
|
||||
, ((mod1Mask , xK_F4), kill)
|
||||
|
||||
-- Switching to layouts
|
||||
, ((modMask' , xK_a), sendMessage $ JumpToLayout "Floating")
|
||||
, ((modMask' , xK_s), sendMessage $ JumpToLayout "Tiled1")
|
||||
, ((modMask' , xK_d), sendMessage $ JumpToLayout "Tiled2")
|
||||
, ((modMask' , xK_f), sendMessage $ JumpToLayout "Fullscreen")
|
||||
|
||||
-- Maximizing
|
||||
, ((modMask' , xK_z), withFocused (sendMessage . maximizeRestore))
|
||||
|
||||
-- Minimizing
|
||||
, ((modMask', xK_m ), withFocused (\f -> sendMessage (MinimizeWin f)))
|
||||
, ((modMask' .|. shiftMask, xK_m ), sendMessage RestoreNextMinimizedWin)
|
||||
]
|
||||
++
|
||||
-- mod-[1..9] ++ [0] %! Switch to workspace N
|
||||
-- mod-shift-[1..9] ++ [0] %! Move client to workspace N
|
||||
[((m .|. modMask', k), windows $ f i)
|
||||
| (i, k) <- zip (XMonad.workspaces conf) ([xK_1 .. xK_9] ++ [xK_0])
|
||||
, (f, m) <- [(W.greedyView, 0), (W.shift, shiftMask)]]
|
||||
++
|
||||
-- mod-{w,e,r} %! Switch to physical/Xinerama screens 1, 2, or 3
|
||||
-- mod-shift-{w,e,r} %! Move client to screen 1, 2, or 3
|
||||
[((m .|. modMask', key), screenWorkspace sc >>= flip whenJust (windows . f))
|
||||
| (key, sc) <- zip [xK_w, xK_e, xK_r] [0..]
|
||||
, (f, m) <- [(W.view, 0), (W.shift, shiftMask)]]
|
||||
|
||||
bluetileMouseBindings :: XConfig Layout -> M.Map (KeyMask, Button) (Window -> X ())
|
||||
bluetileMouseBindings (XConfig {XMonad.modMask = modMask'}) = M.fromList $
|
||||
-- mod-button1 %! Move a floated window by dragging
|
||||
[ ((modMask', button1), (\w -> isFloating w >>= \isF -> when (isF) $
|
||||
focus w >> mouseMoveWindow w >> windows W.shiftMaster))
|
||||
-- mod-button2 %! Switch to next and first layout
|
||||
, ((modMask', button2), (\_ -> sendMessage NextLayout))
|
||||
, ((modMask' .|. shiftMask, button2), (\_ -> sendMessage $ JumpToLayout "Floating"))
|
||||
-- mod-button3 %! Resize a floated window by dragging
|
||||
, ((modMask', button3), (\w -> isFloating w >>= \isF -> when (isF) $
|
||||
focus w >> mouseResizeWindow w >> windows W.shiftMaster))
|
||||
]
|
||||
|
||||
isFloating :: Window -> X (Bool)
|
||||
isFloating w = do
|
||||
ws <- gets windowset
|
||||
return $ M.member w (W.floating ws)
|
||||
|
||||
bluetileManageHook :: ManageHook
|
||||
bluetileManageHook = composeAll
|
||||
[ workspaceByPos, positionStoreManageHook
|
||||
, className =? "MPlayer" --> doFloat
|
||||
, manageDocks]
|
||||
|
||||
bluetileLayoutHook = avoidStruts $ boringAuto $ minimize $ (
|
||||
named "Floating" floating |||
|
||||
named "Tiled1" tiled1 |||
|
||||
named "Tiled2" tiled2 |||
|
||||
named "Fullscreen" fullscreen
|
||||
)
|
||||
where
|
||||
floating = floatingDeco $ maximize $ borderResize $ positionStoreFloat
|
||||
tiled1 = tilingDeco $ maximize $ mouseResizableTileMirrored
|
||||
tiled2 = tilingDeco $ maximize $ mouseResizableTile
|
||||
fullscreen = tilingDeco $ maximize $ smartBorders Full
|
||||
|
||||
tilingDeco l = windowSwitcherDecorationWithButtons shrinkText defaultThemeWithButtons (draggingVisualizer l)
|
||||
floatingDeco l = buttonDeco shrinkText defaultThemeWithButtons l
|
||||
|
||||
bluetileConfig =
|
||||
defaultConfig
|
||||
{ modMask = mod4Mask, -- logo key
|
||||
manageHook = bluetileManageHook,
|
||||
layoutHook = bluetileLayoutHook,
|
||||
logHook = currentWorkspaceOnTop >> ewmhDesktopsLogHook,
|
||||
handleEventHook = ewmhDesktopsEventHook
|
||||
`mappend` restoreMinimizedEventHook
|
||||
`mappend` serverModeEventHook' bluetileCommands
|
||||
`mappend` positionStoreEventHook,
|
||||
workspaces = bluetileWorkspaces,
|
||||
keys = bluetileKeys,
|
||||
mouseBindings = bluetileMouseBindings,
|
||||
focusFollowsMouse = False,
|
||||
focusedBorderColor = "#ff5500",
|
||||
terminal = "gnome-terminal"
|
||||
}
|
@@ -89,7 +89,7 @@ import qualified Data.Map as M
|
||||
|
||||
-- $customizing
|
||||
-- To customize a desktop config, modify its fields as is illustrated with
|
||||
-- @defaultConfig@ in the \"Extending xmonad\" section of "XMonad.Doc.Extending".
|
||||
-- @defaultConfig@ in "XMonad.Doc.Extending#Extending xmonad".
|
||||
|
||||
-- $layouts
|
||||
-- See also "XMonad.Util.EZConfig" for more options for modifying key bindings.
|
||||
|
@@ -1,5 +1,5 @@
|
||||
{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
|
||||
module XMonad.Config.Sjanssen (sjanssenConfig, sjanssenConfigXmobar) where
|
||||
module XMonad.Config.Sjanssen (sjanssenConfig) where
|
||||
|
||||
import XMonad hiding (Tall(..))
|
||||
import qualified XMonad.StackSet as W
|
||||
@@ -8,53 +8,58 @@ import XMonad.Layout.Tabbed
|
||||
import XMonad.Layout.HintedTile
|
||||
import XMonad.Config (defaultConfig)
|
||||
import XMonad.Layout.NoBorders
|
||||
import XMonad.Hooks.DynamicLog hiding (xmobar)
|
||||
import XMonad.Hooks.DynamicLog
|
||||
import XMonad.Hooks.ManageDocks
|
||||
import XMonad.Hooks.ManageHelpers (isFullscreen, doFullFloat)
|
||||
import XMonad.Hooks.EwmhDesktops
|
||||
import XMonad.Prompt
|
||||
import XMonad.Actions.SpawnOn
|
||||
import XMonad.Util.SpawnOnce
|
||||
|
||||
import XMonad.Layout.LayoutScreens
|
||||
import XMonad.Layout.TwoPane
|
||||
|
||||
import qualified Data.Map as M
|
||||
|
||||
sjanssenConfigXmobar = statusBar "exec xmobar" sjanssenPP strutkey =<< sjanssenConfig
|
||||
where
|
||||
strutkey (XConfig {modMask = modm}) = (modm, xK_b)
|
||||
|
||||
sjanssenConfig = do
|
||||
sp <- mkSpawner
|
||||
return . ewmh $ defaultConfig
|
||||
sjanssenConfig =
|
||||
ewmh $ defaultConfig
|
||||
{ terminal = "exec urxvt"
|
||||
, workspaces = ["irc", "web"] ++ map show [3 .. 9 :: Int]
|
||||
, mouseBindings = \(XConfig {modMask = modm}) -> M.fromList $
|
||||
[ ((modm, button1), (\w -> focus w >> mouseMoveWindow w))
|
||||
, ((modm, button2), (\w -> focus w >> windows W.swapMaster))
|
||||
, ((modm.|. shiftMask, button1), (\w -> focus w >> mouseResizeWindow w)) ]
|
||||
, keys = \c -> mykeys sp c `M.union` keys defaultConfig c
|
||||
, keys = \c -> mykeys c `M.union` keys defaultConfig c
|
||||
, logHook = dynamicLogString sjanssenPP >>= xmonadPropLog
|
||||
, layoutHook = modifiers layouts
|
||||
, manageHook = composeAll [className =? x --> doShift w
|
||||
| (x, w) <- [ ("Firefox", "web")
|
||||
, ("Ktorrent", "7")
|
||||
, ("Amarokapp", "7")]]
|
||||
<+> manageHook defaultConfig <+> manageDocks <+> manageSpawn sp
|
||||
<+> manageHook defaultConfig <+> manageDocks <+> manageSpawn
|
||||
<+> (isFullscreen --> doFullFloat)
|
||||
, startupHook = mapM_ spawnOnce spawns
|
||||
}
|
||||
where
|
||||
tiled = HintedTile 1 0.03 0.5 TopLeft
|
||||
layouts = (tiled Tall ||| (tiled Wide ||| Full)) ||| tabbed shrinkText myTheme
|
||||
modifiers = smartBorders
|
||||
modifiers = avoidStruts . smartBorders
|
||||
|
||||
mykeys sp (XConfig {modMask = modm}) = M.fromList $
|
||||
[((modm, xK_p ), shellPromptHere sp myPromptConfig)
|
||||
,((modm .|. shiftMask, xK_Return), spawnHere sp =<< asks (terminal . config))
|
||||
spawns = [ "xmobar"
|
||||
, "xset -b", "xset s off", "xset dpms 0 600 1200"
|
||||
, "nitrogen --set-tiled wallpaper/wallpaper.jpg"
|
||||
, "trayer --transparent true --expand true --align right "
|
||||
++ "--edge bottom --widthtype request" ]
|
||||
|
||||
mykeys (XConfig {modMask = modm}) = M.fromList $
|
||||
[((modm, xK_p ), shellPromptHere myPromptConfig)
|
||||
,((modm .|. shiftMask, xK_Return), spawnHere =<< asks (terminal . config))
|
||||
,((modm .|. shiftMask, xK_c ), kill1)
|
||||
,((modm .|. shiftMask .|. controlMask, xK_c ), kill)
|
||||
,((modm .|. shiftMask, xK_0 ), windows $ copyToAll)
|
||||
,((modm, xK_z ), layoutScreens 2 $ TwoPane 0.5 0.5)
|
||||
,((modm .|. shiftMask, xK_z ), rescreen)
|
||||
, ((modm , xK_b ), sendMessage ToggleStruts)
|
||||
]
|
||||
|
||||
myFont = "xft:Bitstream Vera Sans Mono:pixelsize=10"
|
||||
|
62
XMonad/Hooks/CurrentWorkspaceOnTop.hs
Normal file
62
XMonad/Hooks/CurrentWorkspaceOnTop.hs
Normal file
@@ -0,0 +1,62 @@
|
||||
{-# LANGUAGE DeriveDataTypeable #-}
|
||||
----------------------------------------------------------------------------
|
||||
-- |
|
||||
-- Module : XMonad.Hooks.CurrentWorkspaceOnTop
|
||||
-- Copyright : (c) Jan Vornberger 2009
|
||||
-- License : BSD3-style (see LICENSE)
|
||||
--
|
||||
-- Maintainer : jan.vornberger@informatik.uni-oldenburg.de
|
||||
-- Stability : unstable
|
||||
-- Portability : not portable
|
||||
--
|
||||
-- Ensures that the windows of the current workspace are always in front
|
||||
-- of windows that are located on other visible screens. This becomes important
|
||||
-- if you use decoration and drag windows from one screen to another. Using this
|
||||
-- module, the dragged window will always be in front of other windows.
|
||||
--
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
module XMonad.Hooks.CurrentWorkspaceOnTop (
|
||||
-- * Usage
|
||||
-- $usage
|
||||
currentWorkspaceOnTop
|
||||
) where
|
||||
|
||||
import XMonad
|
||||
import qualified XMonad.StackSet as S
|
||||
import qualified XMonad.Util.ExtensibleState as XS
|
||||
import Control.Monad(when)
|
||||
|
||||
-- $usage
|
||||
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
|
||||
--
|
||||
-- > import XMonad.Hooks.CurrentWorkspaceOnTop
|
||||
-- >
|
||||
-- > main = xmonad $ defaultConfig {
|
||||
-- > ...
|
||||
-- > logHook = currentWorkspaceOnTop
|
||||
-- > ...
|
||||
-- > }
|
||||
--
|
||||
|
||||
data CWOTState = CWOTS String deriving Typeable
|
||||
|
||||
instance ExtensionClass CWOTState where
|
||||
initialValue = CWOTS ""
|
||||
|
||||
currentWorkspaceOnTop :: X ()
|
||||
currentWorkspaceOnTop = withDisplay $ \d -> do
|
||||
ws <- gets windowset
|
||||
(CWOTS lastTag) <- XS.get
|
||||
let curTag = S.tag . S.workspace . S.current $ ws
|
||||
when (curTag /= lastTag) $ do
|
||||
let s = S.current ws
|
||||
wsp = S.workspace s
|
||||
viewrect = screenRect $ S.screenDetail s
|
||||
tmpStack = S.stack . S.workspace $ s
|
||||
(rs, _) <- runLayout wsp { S.stack = tmpStack } viewrect
|
||||
let wins = map fst rs
|
||||
when (not . null $ wins) $ do
|
||||
io $ raiseWindow d (head wins) -- raise first window of current workspace to the very top,
|
||||
io $ restackWindows d wins -- then use restackWindows to let all other windows from the workspace follow
|
||||
XS.put(CWOTS curTag)
|
@@ -1,3 +1,4 @@
|
||||
{-# LANGUAGE DeriveDataTypeable #-}
|
||||
-----------------------------------------------------------------------------
|
||||
-- |
|
||||
-- Module : XMonad.Hooks.DynamicHooks
|
||||
@@ -15,20 +16,18 @@
|
||||
module XMonad.Hooks.DynamicHooks (
|
||||
-- * Usage
|
||||
-- $usage
|
||||
initDynamicHooks
|
||||
,dynamicMasterHook
|
||||
dynamicMasterHook
|
||||
,addDynamicHook
|
||||
,updateDynamicHook
|
||||
,oneShotHook
|
||||
) where
|
||||
|
||||
import XMonad
|
||||
import System.IO
|
||||
import qualified XMonad.Util.ExtensibleState as XS
|
||||
|
||||
import Data.List
|
||||
import Data.Maybe (listToMaybe)
|
||||
import Data.Monoid
|
||||
import Data.IORef
|
||||
|
||||
-- $usage
|
||||
-- Provides two new kinds of 'ManageHooks' that can be defined at runtime.
|
||||
@@ -40,68 +39,46 @@ import Data.IORef
|
||||
-- Note that you will lose all dynamically defined 'ManageHook's when you @mod+q@!
|
||||
-- If you want them to last, you should create them as normal in your @xmonad.hs@.
|
||||
--
|
||||
-- First, you must execute 'initDynamicHooks' from 'main' in your @xmonad.hs@:
|
||||
-- To use this module, add 'dynamicMasterHook' to your 'manageHook':
|
||||
--
|
||||
-- > dynHooksRef <- initDynamicHooks
|
||||
-- > xmonad { manageHook = myManageHook <+> dynamicMasterHook }
|
||||
--
|
||||
-- and then pass this value to the other functions in this module.
|
||||
-- You can then use the supplied functions in your keybindings:
|
||||
--
|
||||
-- You also need to add the base 'ManageHook':
|
||||
--
|
||||
-- > xmonad { manageHook = myManageHook <+> dynamicMasterHook dynHooksRef }
|
||||
--
|
||||
-- You must include this @dynHooksRef@ value when using the functions in this
|
||||
-- module:
|
||||
--
|
||||
-- > xmonad { keys = myKeys `Data.Map.union` Data.Map.fromList
|
||||
-- > [((modm, xK_i), oneShotHook dynHooksRef
|
||||
-- > "FFlaunchHook" (className =? "firefox") (doShift "3")
|
||||
-- > >> spawn "firefox")
|
||||
-- > ,((modm, xK_u), addDynamicHook dynHooksRef
|
||||
-- > (className =? "example" --> doFloat))
|
||||
-- > ,((modm, xK_y), updatePermanentHook dynHooksRef
|
||||
-- > (const idHook))) ] -- resets the permanent hook.
|
||||
-- > ((modMask,xK_a), oneShotHook (className =? "example") doFloat)
|
||||
--
|
||||
|
||||
data DynamicHooks = DynamicHooks
|
||||
{ transients :: [(Query Bool, ManageHook)]
|
||||
, permanent :: ManageHook }
|
||||
deriving Typeable
|
||||
|
||||
instance ExtensionClass DynamicHooks where
|
||||
initialValue = DynamicHooks [] idHook
|
||||
|
||||
-- | Creates the 'IORef' that stores the dynamically created 'ManageHook's.
|
||||
initDynamicHooks :: IO (IORef DynamicHooks)
|
||||
initDynamicHooks = newIORef (DynamicHooks { transients = [],
|
||||
permanent = idHook })
|
||||
|
||||
|
||||
-- this hook is always executed, and the IORef's contents checked.
|
||||
-- this hook is always executed, and the contents of the stored hooks checked.
|
||||
-- note that transient hooks are run second, therefore taking precedence
|
||||
-- over permanent ones on matters such as which workspace to shift to.
|
||||
-- doFloat and doIgnore are idempotent.
|
||||
-- | Master 'ManageHook' that must be in your @xmonad.hs@ 'ManageHook'.
|
||||
dynamicMasterHook :: IORef DynamicHooks -> ManageHook
|
||||
dynamicMasterHook ref = return True -->
|
||||
(ask >>= \w -> liftX (do
|
||||
dh <- io $ readIORef ref
|
||||
dynamicMasterHook :: ManageHook
|
||||
dynamicMasterHook = (ask >>= \w -> liftX (do
|
||||
dh <- XS.get
|
||||
(Endo f) <- runQuery (permanent dh) w
|
||||
ts <- mapM (\(q,a) -> runQuery q w >>= \x -> return (x,(q, a))) (transients dh)
|
||||
let (ts',nts) = partition fst ts
|
||||
gs <- mapM (flip runQuery w . snd . snd) ts'
|
||||
let (Endo g) = maybe (Endo id) id $ listToMaybe gs
|
||||
io $ writeIORef ref $ dh { transients = map snd nts }
|
||||
XS.put $ dh { transients = map snd nts }
|
||||
return $ Endo $ f . g
|
||||
))
|
||||
|
||||
-- | Appends the given 'ManageHook' to the permanent dynamic 'ManageHook'.
|
||||
addDynamicHook :: IORef DynamicHooks -> ManageHook -> X ()
|
||||
addDynamicHook ref m = updateDynamicHook ref (<+> m)
|
||||
|
||||
addDynamicHook :: ManageHook -> X ()
|
||||
addDynamicHook m = updateDynamicHook (<+> m)
|
||||
|
||||
-- | Modifies the permanent 'ManageHook' with an arbitrary function.
|
||||
updateDynamicHook :: IORef DynamicHooks -> (ManageHook -> ManageHook) -> X ()
|
||||
updateDynamicHook ref f =
|
||||
io $ modifyIORef ref $ \dh -> dh { permanent = f (permanent dh) }
|
||||
|
||||
updateDynamicHook :: (ManageHook -> ManageHook) -> X ()
|
||||
updateDynamicHook f = XS.modify $ \dh -> dh { permanent = f (permanent dh) }
|
||||
|
||||
-- | Creates a one-shot 'ManageHook'. Note that you have to specify the two
|
||||
-- parts of the 'ManageHook' separately. Where you would usually write:
|
||||
@@ -112,11 +89,5 @@ updateDynamicHook ref f =
|
||||
--
|
||||
-- > oneShotHook dynHooksRef (className =? "example) doFloat
|
||||
--
|
||||
oneShotHook :: IORef DynamicHooks -> Query Bool -> ManageHook -> X ()
|
||||
oneShotHook ref q a =
|
||||
io $ modifyIORef ref
|
||||
$ \dh -> dh { transients = (q,a):(transients dh) }
|
||||
|
||||
|
||||
|
||||
|
||||
oneShotHook :: Query Bool -> ManageHook -> X ()
|
||||
oneShotHook q a = XS.modify $ \dh -> dh { transients = (q,a):(transients dh) }
|
||||
|
@@ -29,6 +29,8 @@ module XMonad.Hooks.DynamicLog (
|
||||
dynamicLog,
|
||||
dynamicLogXinerama,
|
||||
|
||||
xmonadPropLog,
|
||||
|
||||
-- * Build your own formatter
|
||||
dynamicLogWithPP,
|
||||
dynamicLogString,
|
||||
@@ -56,13 +58,16 @@ module XMonad.Hooks.DynamicLog (
|
||||
--
|
||||
import XMonad
|
||||
import Control.Monad
|
||||
import Data.Char ( isSpace )
|
||||
import Data.Char ( isSpace, ord )
|
||||
import Data.Maybe ( isJust, catMaybes )
|
||||
import Data.List
|
||||
import qualified Data.Map as M
|
||||
import Data.Ord ( comparing )
|
||||
import qualified XMonad.StackSet as S
|
||||
import System.IO
|
||||
|
||||
import Foreign.C (CChar)
|
||||
|
||||
import XMonad.Util.WorkspaceCompare
|
||||
import XMonad.Util.NamedWindows
|
||||
import XMonad.Util.Run
|
||||
@@ -81,7 +86,9 @@ import XMonad.Hooks.ManageDocks
|
||||
-- If you just want a quick-and-dirty status bar with zero effort, try
|
||||
-- the 'xmobar' or 'dzen' functions:
|
||||
--
|
||||
-- > main = xmonad =<< xmobar conf
|
||||
-- > main = xmonad =<< xmobar myConfig
|
||||
-- >
|
||||
-- > myConfig = defaultConfig { ... }
|
||||
--
|
||||
-- There is also 'statusBar' if you'd like to use another status bar, or would
|
||||
-- like to use different formatting options. The 'xmobar', 'dzen', and
|
||||
@@ -144,7 +151,9 @@ import XMonad.Hooks.ManageDocks
|
||||
|
||||
-- | Run xmonad with a dzen status bar set to some nice defaults.
|
||||
--
|
||||
-- > main = xmonad =<< dzen conf
|
||||
-- > main = xmonad =<< dzen myConfig
|
||||
-- >
|
||||
-- > myConfig = defaultConfig { ... }
|
||||
--
|
||||
-- The intent is that the above config file should provide a nice
|
||||
-- status bar with minimal effort.
|
||||
@@ -167,7 +176,9 @@ dzen conf = statusBar ("dzen2 " ++ flags) dzenPP toggleStrutsKey conf
|
||||
|
||||
-- | Run xmonad with a xmobar status bar set to some nice defaults.
|
||||
--
|
||||
-- > main = xmonad =<< xmobar conf
|
||||
-- > main = xmonad =<< xmobar myConfig
|
||||
-- >
|
||||
-- > myConfig = defaultConfig { ... }
|
||||
--
|
||||
-- This works pretty much the same as 'dzen' function above.
|
||||
--
|
||||
@@ -198,6 +209,20 @@ statusBar cmd pp k conf = do
|
||||
where
|
||||
keys' = (`M.singleton` sendMessage ToggleStruts) . k
|
||||
|
||||
-- | Write a string to the property _XMONAD_LOG on the root window. This
|
||||
-- property is of type UTF8_STRING. The string must have been processed by
|
||||
-- encodeString (dynamicLogString does this).
|
||||
xmonadPropLog :: String -> X ()
|
||||
xmonadPropLog msg = do
|
||||
d <- asks display
|
||||
r <- asks theRoot
|
||||
xlog <- getAtom "_XMONAD_LOG"
|
||||
ustring <- getAtom "UTF8_STRING"
|
||||
io $ changeProperty8 d r xlog ustring propModeReplace (encodeCChar msg)
|
||||
where
|
||||
encodeCChar :: String -> [CChar]
|
||||
encodeCChar = map (fromIntegral . ord)
|
||||
|
||||
-- |
|
||||
-- Helper function which provides ToggleStruts keybinding
|
||||
--
|
||||
@@ -264,9 +289,9 @@ pprWindowSet sort' urgents pp s = sepBy (ppWsSep pp) . map fmt . sort' $
|
||||
visibles = map (S.tag . S.workspace) (S.visible s)
|
||||
|
||||
fmt w = printer pp (S.tag w)
|
||||
where printer | S.tag w == this = ppCurrent
|
||||
where printer | any (\x -> maybe False (== S.tag w) (S.findTag x s)) urgents = ppUrgent
|
||||
| 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
|
||||
|
||||
@@ -339,11 +364,7 @@ dzenColor fg bg = wrap (fg1++bg1) (fg2++bg2)
|
||||
dzenEscape :: String -> String
|
||||
dzenEscape = concatMap (\x -> if x == '^' then "^^" else [x])
|
||||
|
||||
-- | Strip dzen formatting or commands. Useful to remove ppHidden
|
||||
-- formatting in ppUrgent field. For example:
|
||||
--
|
||||
-- > , ppHidden = dzenColor "gray20" "" . wrap "(" ")"
|
||||
-- > , ppUrgent = dzenColor "dark orange" "" . dzenStrip
|
||||
-- | Strip dzen formatting or commands.
|
||||
dzenStrip :: String -> String
|
||||
dzenStrip = strip [] where
|
||||
strip keep x
|
||||
@@ -364,11 +385,7 @@ xmobarColor fg bg = wrap t "</fc>"
|
||||
|
||||
-- ??? add an xmobarEscape function?
|
||||
|
||||
-- | Strip xmobar markup. Useful to remove ppHidden color from ppUrgent
|
||||
-- field. For example:
|
||||
--
|
||||
-- > , ppHidden = xmobarColor "gray20" "" . wrap "<" ">"
|
||||
-- > , ppUrgent = xmobarColor "dark orange" "" . xmobarStrip
|
||||
-- | Strip xmobar markup.
|
||||
xmobarStrip :: String -> String
|
||||
xmobarStrip = strip [] where
|
||||
strip keep x
|
||||
@@ -394,8 +411,6 @@ data PP = PP { ppCurrent :: WorkspaceId -> String
|
||||
-- ^ how to print tags of empty hidden workspaces
|
||||
, ppUrgent :: WorkspaceId -> String
|
||||
-- ^ format to be applied to tags of urgent workspaces.
|
||||
-- NOTE that 'ppUrgent' is applied /in addition to/
|
||||
-- 'ppHidden'!
|
||||
, ppSep :: String
|
||||
-- ^ separator to use between different log sections
|
||||
-- (window name, layout, workspaces)
|
||||
@@ -451,32 +466,31 @@ defaultPP = PP { ppCurrent = wrap "[" "]"
|
||||
, ppExtras = []
|
||||
}
|
||||
|
||||
-- | Settings to emulate dwm's statusbar, dzen only. Uses dzenStrip in
|
||||
-- ppUrgent.
|
||||
-- | Settings to emulate dwm's statusbar, dzen only.
|
||||
dzenPP :: PP
|
||||
dzenPP = defaultPP { ppCurrent = dzenColor "white" "#2b4f98" . pad
|
||||
, ppVisible = dzenColor "black" "#999999" . pad
|
||||
, ppHidden = dzenColor "black" "#cccccc" . pad
|
||||
, ppHiddenNoWindows = const ""
|
||||
, ppUrgent = dzenColor "red" "yellow" . dzenStrip
|
||||
, ppWsSep = ""
|
||||
, ppSep = ""
|
||||
, ppLayout = dzenColor "black" "#cccccc" .
|
||||
(\ x -> case x of
|
||||
"TilePrime Horizontal" -> " TTT "
|
||||
"TilePrime Vertical" -> " []= "
|
||||
"Hinted Full" -> " [ ] "
|
||||
_ -> pad x
|
||||
)
|
||||
, ppTitle = ("^bg(#324c80) " ++) . dzenEscape
|
||||
}
|
||||
, ppVisible = dzenColor "black" "#999999" . pad
|
||||
, ppHidden = dzenColor "black" "#cccccc" . pad
|
||||
, ppHiddenNoWindows = const ""
|
||||
, ppUrgent = dzenColor "red" "yellow" . pad
|
||||
, ppWsSep = ""
|
||||
, ppSep = ""
|
||||
, ppLayout = dzenColor "black" "#cccccc" .
|
||||
(\ x -> case x of
|
||||
"TilePrime Horizontal" -> " TTT "
|
||||
"TilePrime Vertical" -> " []= "
|
||||
"Hinted Full" -> " [ ] "
|
||||
_ -> pad x
|
||||
)
|
||||
, ppTitle = ("^bg(#324c80) " ++) . dzenEscape
|
||||
}
|
||||
|
||||
-- | Some nice xmobar defaults.
|
||||
xmobarPP :: PP
|
||||
xmobarPP = defaultPP { ppCurrent = xmobarColor "yellow" "" . wrap "[" "]"
|
||||
, ppTitle = xmobarColor "green" "" . shorten 40
|
||||
, ppVisible = wrap "(" ")"
|
||||
, ppUrgent = xmobarColor "red" "yellow"
|
||||
, ppUrgent = xmobarColor "red" "yellow"
|
||||
}
|
||||
|
||||
-- | The options that sjanssen likes to use with xmobar, as an
|
||||
@@ -492,7 +506,7 @@ byorgeyPP :: PP
|
||||
byorgeyPP = defaultPP { ppHiddenNoWindows = showNamedWorkspaces
|
||||
, ppHidden = dzenColor "black" "#a8a3f7" . pad
|
||||
, ppCurrent = dzenColor "yellow" "#a8a3f7" . pad
|
||||
, ppUrgent = dzenColor "red" "yellow"
|
||||
, ppUrgent = dzenColor "red" "yellow" . pad
|
||||
, ppSep = " | "
|
||||
, ppWsSep = ""
|
||||
, ppTitle = shorten 70
|
||||
|
@@ -32,6 +32,7 @@ import Control.Monad
|
||||
import qualified XMonad.StackSet as W
|
||||
|
||||
import XMonad.Hooks.SetWMName
|
||||
import XMonad.Util.XUtils (fi)
|
||||
import XMonad.Util.WorkspaceCompare
|
||||
|
||||
-- $usage
|
||||
@@ -132,14 +133,14 @@ handle ClientMessageEvent {
|
||||
a_cw <- getAtom "_NET_CLOSE_WINDOW"
|
||||
a_ignore <- mapM getAtom ["XMONAD_TIMER"]
|
||||
if mt == a_cd then do
|
||||
let n = fromIntegral (head d)
|
||||
if 0 <= n && n < length ws then
|
||||
windows $ W.view (W.tag (ws !! n))
|
||||
let n = head d
|
||||
if 0 <= n && fi n < length ws then
|
||||
windows $ W.view (W.tag (ws !! fi n))
|
||||
else trace $ "Bad _NET_CURRENT_DESKTOP with data[0]="++show n
|
||||
else if mt == a_d then do
|
||||
let n = fromIntegral (head d)
|
||||
if 0 <= n && n < length ws then
|
||||
windows $ W.shiftWin (W.tag (ws !! n)) w
|
||||
let n = head d
|
||||
if 0 <= n && fi n < length ws then
|
||||
windows $ W.shiftWin (W.tag (ws !! fi n)) w
|
||||
else trace $ "Bad _NET_DESKTOP with data[0]="++show n
|
||||
else if mt == a_aw then do
|
||||
windows $ W.focusWindow w
|
||||
|
@@ -44,7 +44,7 @@ import Control.Monad
|
||||
-- you will need to have xcompmgr <http://freedesktop.org/wiki/Software/xapps>
|
||||
-- or something similar for this to do anything
|
||||
--
|
||||
-- For more detailed instructions on editing the layoutHook see:
|
||||
-- For more detailed instructions on editing the logHook see:
|
||||
--
|
||||
-- "XMonad.Doc.Extending#The_log_hook_and_external_status_bars"
|
||||
--
|
||||
|
@@ -1,3 +1,4 @@
|
||||
{-# LANGUAGE DeriveDataTypeable #-}
|
||||
-----------------------------------------------------------------------------
|
||||
-- |
|
||||
-- Module : XMonad.Hooks.FloatNext
|
||||
@@ -38,37 +39,35 @@ module XMonad.Hooks.FloatNext ( -- * Usage
|
||||
import Prelude hiding (all)
|
||||
|
||||
import XMonad
|
||||
import qualified XMonad.Util.ExtensibleState as XS
|
||||
|
||||
import Control.Monad (join)
|
||||
import Control.Monad (join,guard)
|
||||
import Control.Applicative ((<$>))
|
||||
import Control.Arrow (first, second)
|
||||
import Control.Concurrent.MVar
|
||||
import System.IO.Unsafe (unsafePerformIO)
|
||||
|
||||
|
||||
{- Helper functions -}
|
||||
|
||||
modifyMVar2 :: MVar a -> (a -> a) -> IO ()
|
||||
modifyMVar2 v f = modifyMVar_ v (return . f)
|
||||
|
||||
_set :: ((a -> a) -> (Bool, Bool) -> (Bool, Bool)) -> a -> X ()
|
||||
_set f b = io $ modifyMVar2 floatModeMVar (f $ const b)
|
||||
_set f b = modify' (f $ const b)
|
||||
|
||||
_toggle :: ((Bool -> Bool) -> (Bool, Bool) -> (Bool, Bool)) -> X ()
|
||||
_toggle f = io $ modifyMVar2 floatModeMVar (f not)
|
||||
_toggle f = modify' (f not)
|
||||
|
||||
_get :: ((Bool, Bool) -> a) -> X a
|
||||
_get f = io $ f <$> readMVar floatModeMVar
|
||||
_get f = XS.gets (f . getFloatMode)
|
||||
|
||||
_pp :: ((Bool, Bool) -> Bool) -> String -> (String -> String) -> X (Maybe String)
|
||||
_pp f s st = _get f >>= \b -> if b then return $ Just $ st s else return Nothing
|
||||
|
||||
_pp f s st = (\b -> guard b >> Just (st s)) <$> _get f
|
||||
|
||||
{- The current state is kept here -}
|
||||
|
||||
floatModeMVar :: MVar (Bool, Bool)
|
||||
floatModeMVar = unsafePerformIO $ newMVar (False, False)
|
||||
data FloatMode = FloatMode { getFloatMode :: (Bool,Bool) } deriving (Typeable)
|
||||
|
||||
instance ExtensionClass FloatMode where
|
||||
initialValue = FloatMode (False,False)
|
||||
|
||||
modify' :: ((Bool,Bool) -> (Bool,Bool)) -> X ()
|
||||
modify' f = XS.modify (FloatMode . f . getFloatMode)
|
||||
|
||||
-- $usage
|
||||
-- This module provides actions (that can be set as keybindings)
|
||||
@@ -93,15 +92,13 @@ floatModeMVar = unsafePerformIO $ newMVar (False, False)
|
||||
--
|
||||
-- > , ((modm, xK_r), toggleFloatAllNew)
|
||||
|
||||
|
||||
-- | This 'ManageHook' will selectively float windows as set
|
||||
-- by 'floatNext' and 'floatAllNew'.
|
||||
floatNextHook :: ManageHook
|
||||
floatNextHook = do (next, all) <- io $ takeMVar floatModeMVar
|
||||
io $ putMVar floatModeMVar (False, all)
|
||||
floatNextHook = do (next, all) <- liftX $ XS.gets getFloatMode
|
||||
liftX $ XS.put $ FloatMode (False, all)
|
||||
if next || all then doFloat else idHook
|
||||
|
||||
|
||||
-- | @floatNext True@ arranges for the next spawned window to be
|
||||
-- sent to the floating layer, @floatNext False@ cancels it.
|
||||
floatNext :: Bool -> X ()
|
||||
@@ -118,7 +115,6 @@ floatAllNew = _set second
|
||||
toggleFloatAllNew :: X ()
|
||||
toggleFloatAllNew = _toggle second
|
||||
|
||||
|
||||
-- | Whether the next window will be set floating
|
||||
willFloatNext :: X Bool
|
||||
willFloatNext = _get fst
|
||||
@@ -127,7 +123,6 @@ willFloatNext = _get fst
|
||||
willFloatAllNew :: X Bool
|
||||
willFloatAllNew = _get snd
|
||||
|
||||
|
||||
-- $pp
|
||||
-- The following functions are used to display the current
|
||||
-- state of 'floatNext' and 'floatAllNew' in your
|
||||
@@ -154,4 +149,4 @@ willFloatAllNewPP :: (String -> String) -> X (Maybe String)
|
||||
willFloatAllNewPP = _pp snd "All"
|
||||
|
||||
runLogHook :: X ()
|
||||
runLogHook = join $ asks $ logHook . config
|
||||
runLogHook = join $ asks $ logHook . config
|
||||
|
@@ -46,7 +46,7 @@ data Focus = Newer | Older
|
||||
insertPosition :: Position -> Focus -> ManageHook
|
||||
insertPosition pos foc = Endo . g <$> ask
|
||||
where
|
||||
g w = viewingWs w (updateFocus w . ins w . W.delete w)
|
||||
g w = viewingWs w (updateFocus w . ins w . W.delete' w)
|
||||
ins w = (\f ws -> fromMaybe id (W.focusWindow <$> W.peek ws) $ f ws) $
|
||||
case pos of
|
||||
Master -> W.insertUp w . W.focusMaster
|
||||
|
@@ -236,15 +236,18 @@ c2r (x1, y1, x2, y2) = Rectangle (fi x1) (fi y1) (fi $ x2 - x1 + 1) (fi $ y2 - y
|
||||
|
||||
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 )
|
||||
U | p (x0, x1) -> (x0 , mx y0 sy0, x1 , y1 )
|
||||
D | p (x0, x1) -> (x0 , y0 , x1 , mn y1 sy1)
|
||||
_ -> (x0 , y0 , x1 , y1 )
|
||||
L | p (y0, y1) && qh x1 -> (mx x0 sx0, y0 , x1 , y1 )
|
||||
R | p (y0, y1) && qv sx1 x0 -> (x0 , y0 , mn x1 sx1, y1 )
|
||||
U | p (x0, x1) && qh y1 -> (x0 , mx y0 sy0, x1 , y1 )
|
||||
D | p (x0, x1) && qv sy1 y0 -> (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)
|
||||
p r = r `overlaps` (l, h)
|
||||
-- Filter out struts that cover the entire rectangle:
|
||||
qh d1 = n <= d1
|
||||
qv sd1 d0 = sd1 - n >= d0
|
||||
|
||||
-- | Do the two ranges overlap?
|
||||
--
|
||||
|
@@ -28,6 +28,7 @@ module XMonad.Hooks.ManageHelpers (
|
||||
Side(..),
|
||||
composeOne,
|
||||
(-?>), (/=?), (<==?), (</=?), (-->>), (-?>>),
|
||||
currentWs,
|
||||
isInProperty,
|
||||
isKDETrayWindow,
|
||||
isFullscreen,
|
||||
@@ -56,7 +57,7 @@ import Data.Monoid
|
||||
|
||||
import System.Posix (ProcessID)
|
||||
|
||||
-- | Denotes a side of a screen. @S@ stands for South, @NE@ for Northwest
|
||||
-- | Denotes a side of a screen. @S@ stands for South, @NE@ for Northeast
|
||||
-- etc. @C@ stands for Center.
|
||||
data Side = SC | NC | CE | CW | SE | SW | NE | NW | C
|
||||
deriving (Read, Show, Eq)
|
||||
@@ -118,6 +119,10 @@ p -?>> f = do
|
||||
Match b m <- p
|
||||
if b then fmap Just (f m) else return Nothing
|
||||
|
||||
-- | Return the current workspace
|
||||
currentWs :: Query WorkspaceId
|
||||
currentWs = liftX (withWindowSet $ return . W.currentTag)
|
||||
|
||||
-- | A predicate to check whether a window is a KDE system tray icon.
|
||||
isKDETrayWindow :: Query Bool
|
||||
isKDETrayWindow = ask >>= \w -> liftX $ do
|
||||
|
95
XMonad/Hooks/PositionStoreHooks.hs
Normal file
95
XMonad/Hooks/PositionStoreHooks.hs
Normal file
@@ -0,0 +1,95 @@
|
||||
----------------------------------------------------------------------------
|
||||
-- |
|
||||
-- Module : XMonad.Hooks.PositionStoreHooks
|
||||
-- Copyright : (c) Jan Vornberger 2009
|
||||
-- License : BSD3-style (see LICENSE)
|
||||
--
|
||||
-- Maintainer : jan.vornberger@informatik.uni-oldenburg.de
|
||||
-- Stability : unstable
|
||||
-- Portability : not portable
|
||||
--
|
||||
-- This module contains two hooks for the
|
||||
-- PositionStore (see "XMonad.Util.PositionStore") - a ManageHook and
|
||||
-- an EventHook.
|
||||
--
|
||||
-- The ManageHook can be used to fill the PositionStore with position and size
|
||||
-- information about new windows. The advantage of using this hook is, that the
|
||||
-- information is recorded independent of the currently active layout. So the
|
||||
-- floating shape of the window can later be restored even if it was opened in a
|
||||
-- tiled layout initially.
|
||||
--
|
||||
-- For windows, that do not request a particular position, a random position will
|
||||
-- be assigned. This prevents windows from piling up exactly on top of each other.
|
||||
--
|
||||
-- The EventHook makes sure that windows are deleted from the PositionStore
|
||||
-- when they are closed.
|
||||
--
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
module XMonad.Hooks.PositionStoreHooks (
|
||||
-- * Usage
|
||||
-- $usage
|
||||
positionStoreManageHook,
|
||||
positionStoreEventHook
|
||||
) where
|
||||
|
||||
import XMonad
|
||||
import qualified XMonad.StackSet as W
|
||||
import XMonad.Util.PositionStore
|
||||
import XMonad.Util.XUtils (fi)
|
||||
|
||||
import System.Random(randomRIO)
|
||||
import Control.Applicative((<$>))
|
||||
import Control.Monad(when)
|
||||
import Data.Maybe
|
||||
import Data.Monoid
|
||||
|
||||
-- $usage
|
||||
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
|
||||
--
|
||||
-- > import XMonad.Hooks.PositionStoreHooks
|
||||
--
|
||||
-- and adding 'positionStoreManageHook' to your 'ManageHook' as well
|
||||
-- as 'positionStoreEventHook' to your event hooks:
|
||||
--
|
||||
-- > myManageHook = positionStoreManageHook <+> manageHook defaultConfig
|
||||
-- > myHandleEventHook = positionStoreEventHook
|
||||
-- >
|
||||
-- > main = xmonad defaultConfig { manageHook = myManageHook
|
||||
-- > , handleEventHook = myHandleEventHook
|
||||
-- > }
|
||||
--
|
||||
|
||||
positionStoreManageHook :: ManageHook
|
||||
positionStoreManageHook = ask >>= liftX . positionStoreInit >> idHook
|
||||
|
||||
positionStoreInit :: Window -> X ()
|
||||
positionStoreInit w = withDisplay $ \d -> do
|
||||
wa <- io $ getWindowAttributes d w
|
||||
ws <- gets windowset
|
||||
arbitraryOffsetX <- randomIntOffset
|
||||
arbitraryOffsetY <- randomIntOffset
|
||||
if (wa_x wa == 0) && (wa_y wa == 0)
|
||||
then do
|
||||
let sr@(Rectangle srX srY _ _) = screenRect . W.screenDetail . W.current $ ws
|
||||
modifyPosStore (\ps -> posStoreInsert ps w
|
||||
(Rectangle (srX + fi arbitraryOffsetX)
|
||||
(srY + fi arbitraryOffsetY)
|
||||
(fi $ wa_width wa)
|
||||
(fi $ wa_height wa)) sr )
|
||||
else do
|
||||
sc <- fromMaybe (W.current ws) <$> pointScreen (fi $ wa_x wa) (fi $ wa_y wa)
|
||||
let sr = screenRect . W.screenDetail $ sc
|
||||
modifyPosStore (\ps -> posStoreInsert ps w
|
||||
(Rectangle (fi $ wa_x wa) (fi $ wa_y wa)
|
||||
(fi $ wa_width wa) (fi $ wa_height wa)) sr )
|
||||
where
|
||||
randomIntOffset :: X (Int)
|
||||
randomIntOffset = io $ randomRIO (42, 242)
|
||||
|
||||
positionStoreEventHook :: Event -> X All
|
||||
positionStoreEventHook (DestroyWindowEvent {ev_window = w, ev_event_type = et}) = do
|
||||
when (et == destroyNotify) $ do
|
||||
modifyPosStore (\ps -> posStoreRemove ps w)
|
||||
return (All True)
|
||||
positionStoreEventHook _ = return (All True)
|
@@ -1,4 +1,5 @@
|
||||
{-# LANGUAGE FlexibleContexts, MultiParamTypeClasses, TypeSynonymInstances, PatternGuards #-}
|
||||
{-# LANGUAGE FlexibleContexts, MultiParamTypeClasses, TypeSynonymInstances, PatternGuards, DeriveDataTypeable,
|
||||
FlexibleInstances #-}
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- |
|
||||
@@ -71,17 +72,16 @@ import XMonad
|
||||
import qualified XMonad.StackSet as W
|
||||
|
||||
import XMonad.Util.Dzen (dzenWithArgs, seconds)
|
||||
import qualified XMonad.Util.ExtensibleState as XS
|
||||
import XMonad.Util.NamedWindows (getName)
|
||||
import XMonad.Util.Timer (TimerId, startTimer, handleTimer)
|
||||
|
||||
import Control.Applicative ((<$>))
|
||||
import Control.Monad (when)
|
||||
import Data.Bits (testBit)
|
||||
import Data.IORef
|
||||
import Data.List (delete)
|
||||
import Data.Maybe (listToMaybe, maybeToList)
|
||||
import qualified Data.Set as S
|
||||
import Foreign (unsafePerformIO)
|
||||
|
||||
-- $usage
|
||||
--
|
||||
@@ -195,7 +195,7 @@ import Foreign (unsafePerformIO)
|
||||
-- hopefully you know where to find it.
|
||||
|
||||
-- | This is the method to enable an urgency hook. It uses the default
|
||||
-- 'urgencyConfig' to control behavior. To change this, use 'withUrgencyHook'
|
||||
-- 'urgencyConfig' to control behavior. To change this, use 'withUrgencyHookC'
|
||||
-- instead.
|
||||
withUrgencyHook :: (LayoutClass l Window, UrgencyHook h) =>
|
||||
h -> XConfig l -> XConfig l
|
||||
@@ -213,6 +213,15 @@ withUrgencyHookC hook urgConf conf = conf {
|
||||
logHook = cleanupUrgents (suppressWhen urgConf) >> logHook conf
|
||||
}
|
||||
|
||||
data Urgents = Urgents { fromUrgents :: [Window] } deriving (Read,Show,Typeable)
|
||||
|
||||
onUrgents :: ([Window] -> [Window]) -> Urgents -> Urgents
|
||||
onUrgents f = Urgents . f . fromUrgents
|
||||
|
||||
instance ExtensionClass Urgents where
|
||||
initialValue = Urgents []
|
||||
extensionType = PersistentExtension
|
||||
|
||||
-- | Global configuration, applied to all types of 'UrgencyHook'. See
|
||||
-- 'urgencyConfig' for the defaults.
|
||||
data UrgencyConfig = UrgencyConfig
|
||||
@@ -262,25 +271,18 @@ focusUrgent = withUrgents $ flip whenJust (windows . W.focusWindow) . listToMayb
|
||||
clearUrgents :: X ()
|
||||
clearUrgents = adjustUrgents (const []) >> adjustReminders (const [])
|
||||
|
||||
-- | Stores the global set of all urgent windows, across workspaces. Not exported -- use
|
||||
-- 'readUrgents' or 'withUrgents' instead.
|
||||
{-# NOINLINE urgents #-}
|
||||
urgents :: IORef [Window]
|
||||
urgents = unsafePerformIO (newIORef [])
|
||||
-- (Hey, I don't like it any more than you do.)
|
||||
|
||||
-- | X action that returns a list of currently urgent windows. You might use
|
||||
-- it, or 'withUrgents', in your custom logHook, to display the workspaces that
|
||||
-- contain urgent windows.
|
||||
readUrgents :: X [Window]
|
||||
readUrgents = io $ readIORef urgents
|
||||
readUrgents = XS.gets fromUrgents
|
||||
|
||||
-- | An HOF version of 'readUrgents', for those who prefer that sort of thing.
|
||||
withUrgents :: ([Window] -> X a) -> X a
|
||||
withUrgents f = readUrgents >>= f
|
||||
|
||||
adjustUrgents :: ([Window] -> [Window]) -> X ()
|
||||
adjustUrgents f = io $ modifyIORef urgents f
|
||||
adjustUrgents = XS.modify . onUrgents
|
||||
|
||||
type Interval = Rational
|
||||
|
||||
@@ -290,18 +292,19 @@ data Reminder = Reminder { timer :: TimerId
|
||||
, window :: Window
|
||||
, interval :: Interval
|
||||
, remaining :: Maybe Int
|
||||
} deriving Eq
|
||||
} deriving (Show,Read,Eq,Typeable)
|
||||
|
||||
instance ExtensionClass [Reminder] where
|
||||
initialValue = []
|
||||
extensionType = PersistentExtension
|
||||
|
||||
-- | Stores the list of urgency reminders.
|
||||
{-# NOINLINE reminders #-}
|
||||
reminders :: IORef [Reminder]
|
||||
reminders = unsafePerformIO (newIORef [])
|
||||
|
||||
readReminders :: X [Reminder]
|
||||
readReminders = io $ readIORef reminders
|
||||
readReminders = XS.get
|
||||
|
||||
adjustReminders :: ([Reminder] -> [Reminder]) -> X ()
|
||||
adjustReminders f = io $ modifyIORef reminders f
|
||||
adjustReminders = XS.modify
|
||||
|
||||
clearUrgency :: Window -> X ()
|
||||
clearUrgency w = adjustUrgents (delete w) >> adjustReminders (filter $ (w /=) . window)
|
||||
@@ -332,7 +335,7 @@ handleEvent wuh event =
|
||||
callUrgencyHook wuh w
|
||||
else
|
||||
clearUrgency w
|
||||
userCodeDef () =<< asks (logHook . config) -- call *after* IORef has been modified
|
||||
userCodeDef () =<< asks (logHook . config)
|
||||
DestroyWindowEvent {ev_window = w} ->
|
||||
clearUrgency w
|
||||
_ ->
|
||||
|
@@ -12,8 +12,10 @@
|
||||
-- This layout modifier will allow to resize windows by dragging their
|
||||
-- borders with the mouse. However, it only works in layouts or modified
|
||||
-- layouts that react to the 'SetGeometry' message.
|
||||
-- "XMonad.Layout.WindowArranger" can be used to create such a setup.
|
||||
-- BorderResize is probably most useful in floating layouts.
|
||||
-- "XMonad.Layout.WindowArranger" can be used to create such a setup,
|
||||
-- but it is probably must useful in a floating layout such as
|
||||
-- "XMonad.Layout.PositionStoreFloat" with which it has been mainly tested.
|
||||
-- See the documentation of PositionStoreFloat for a typical usage example.
|
||||
--
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
@@ -28,9 +30,8 @@ import XMonad
|
||||
import XMonad.Layout.Decoration
|
||||
import XMonad.Layout.WindowArranger
|
||||
import XMonad.Util.XUtils
|
||||
import Control.Monad(when,forM)
|
||||
import Control.Arrow(first)
|
||||
import Control.Applicative((<$>))
|
||||
import Control.Monad(when)
|
||||
import qualified Data.Map as M
|
||||
|
||||
-- $usage
|
||||
-- You can use this module with the following in your
|
||||
@@ -41,15 +42,21 @@ import Control.Applicative((<$>))
|
||||
-- > main = xmonad defaultConfig { layoutHook = myLayout }
|
||||
--
|
||||
|
||||
data BorderInfo = RightSideBorder Window Rectangle
|
||||
| LeftSideBorder Window Rectangle
|
||||
| TopSideBorder Window Rectangle
|
||||
| BottomSideBorder Window Rectangle
|
||||
deriving (Show, Read, Eq)
|
||||
type BorderWithRect = (Rectangle, Rectangle, Glyph, BorderInfo)
|
||||
type BorderWithWin = (Window, BorderInfo)
|
||||
type BorderBlueprint = (Rectangle, Glyph, BorderType)
|
||||
|
||||
data BorderResize a = BR [BorderWithWin] deriving (Show, Read)
|
||||
data BorderType = RightSideBorder
|
||||
| LeftSideBorder
|
||||
| TopSideBorder
|
||||
| BottomSideBorder
|
||||
deriving (Show, Read, Eq)
|
||||
data BorderInfo = BI { bWin :: Window,
|
||||
bRect :: Rectangle,
|
||||
bType :: BorderType
|
||||
} deriving (Show, Read)
|
||||
|
||||
type RectWithBorders = (Rectangle, [BorderInfo])
|
||||
|
||||
data BorderResize a = BR (M.Map Window RectWithBorders) deriving (Show, Read)
|
||||
|
||||
brBorderOffset :: Position
|
||||
brBorderOffset = 5
|
||||
@@ -66,64 +73,119 @@ brCursorBottomSide :: Glyph
|
||||
brCursorBottomSide = 16
|
||||
|
||||
borderResize :: l a -> ModifiedLayout BorderResize l a
|
||||
borderResize = ModifiedLayout (BR [])
|
||||
borderResize = ModifiedLayout (BR M.empty)
|
||||
|
||||
instance LayoutModifier BorderResize Window where
|
||||
redoLayout _ _ Nothing wrs = return (wrs, Nothing)
|
||||
redoLayout (BR borders) _ _ wrs = do
|
||||
let preparedBorders = for wrs $ \wr -> (wr, prepareBorders wr)
|
||||
mapM_ deleteBorder borders
|
||||
newBorders <- forM preparedBorders $ \(wr, (b1, b2, b3, b4)) ->
|
||||
first (++[wr]) . unzip <$> mapM createBorder [b1,b2,b3,b4]
|
||||
let wrs' = concat $ map fst newBorders
|
||||
newBordersSerialized = concat $ map snd newBorders
|
||||
return (wrs', Just $ BR newBordersSerialized)
|
||||
redoLayout (BR wrsLastTime) _ _ wrs = do
|
||||
let correctOrder = map fst wrs
|
||||
wrsCurrent = M.fromList wrs
|
||||
wrsGone = M.difference wrsLastTime wrsCurrent
|
||||
wrsAppeared = M.difference wrsCurrent wrsLastTime
|
||||
wrsStillThere = M.intersectionWith testIfUnchanged wrsLastTime wrsCurrent
|
||||
handleGone wrsGone
|
||||
wrsCreated <- handleAppeared wrsAppeared
|
||||
let wrsChanged = handleStillThere wrsStillThere
|
||||
wrsThisTime = M.union wrsChanged wrsCreated
|
||||
return (compileWrs wrsThisTime correctOrder, Just $ BR wrsThisTime)
|
||||
-- What we return is the original wrs with the new border
|
||||
-- windows inserted at the correct positions - this way, the core
|
||||
-- will restack the borders correctly.
|
||||
-- We also return information about our borders, so that we
|
||||
-- can handle events that they receive and destroy them when
|
||||
-- they are no longer needed.
|
||||
where
|
||||
testIfUnchanged entry@(rLastTime, _) rCurrent =
|
||||
if rLastTime == rCurrent
|
||||
then (Nothing, entry)
|
||||
else (Just rCurrent, entry)
|
||||
|
||||
handleMess (BR borders) m
|
||||
| Just e <- fromMessage m :: Maybe Event = handleResize borders e >> return Nothing
|
||||
handleMess (BR wrsLastTime) m
|
||||
| Just e <- fromMessage m :: Maybe Event =
|
||||
handleResize (createBorderLookupTable wrsLastTime) e >> return Nothing
|
||||
| Just _ <- fromMessage m :: Maybe LayoutMessages =
|
||||
mapM_ deleteBorder borders >> return (Just $ BR [])
|
||||
handleGone wrsLastTime >> return (Just $ BR M.empty)
|
||||
handleMess _ _ = return Nothing
|
||||
|
||||
prepareBorders :: (Window, Rectangle) -> (BorderWithRect, BorderWithRect, BorderWithRect, BorderWithRect)
|
||||
prepareBorders (w, r@(Rectangle x y wh ht)) =
|
||||
((r, (Rectangle (x + fi wh - brBorderOffset) y brBorderSize ht) , brCursorRightSide , RightSideBorder w r),
|
||||
(r, (Rectangle (x - brBorderOffset) y brBorderSize ht) , brCursorLeftSide , LeftSideBorder w r),
|
||||
(r, (Rectangle x (y - brBorderOffset) wh brBorderSize) , brCursorTopSide , TopSideBorder w r),
|
||||
(r, (Rectangle x (y + fi ht - brBorderOffset) wh brBorderSize) , brCursorBottomSide , BottomSideBorder w r)
|
||||
)
|
||||
compileWrs :: M.Map Window RectWithBorders -> [Window] -> [(Window, Rectangle)]
|
||||
compileWrs wrsThisTime correctOrder = let wrs = reorder (M.toList wrsThisTime) correctOrder
|
||||
in concat $ map compileWr wrs
|
||||
|
||||
handleResize :: [BorderWithWin] -> Event -> X ()
|
||||
compileWr :: (Window, RectWithBorders) -> [(Window, Rectangle)]
|
||||
compileWr (w, (r, borderInfos)) =
|
||||
let borderWrs = for borderInfos $ \bi -> (bWin bi, bRect bi)
|
||||
in borderWrs ++ [(w, r)]
|
||||
|
||||
handleGone :: M.Map Window RectWithBorders -> X ()
|
||||
handleGone wrsGone = mapM_ deleteWindow borderWins
|
||||
where
|
||||
borderWins = map bWin . concat . map snd . M.elems $ wrsGone
|
||||
|
||||
handleAppeared :: M.Map Window Rectangle -> X (M.Map Window RectWithBorders)
|
||||
handleAppeared wrsAppeared = do
|
||||
let wrs = M.toList wrsAppeared
|
||||
wrsCreated <- mapM handleSingleAppeared wrs
|
||||
return $ M.fromList wrsCreated
|
||||
|
||||
handleSingleAppeared :: (Window, Rectangle) -> X (Window, RectWithBorders)
|
||||
handleSingleAppeared (w, r) = do
|
||||
let borderBlueprints = prepareBorders r
|
||||
borderInfos <- mapM createBorder borderBlueprints
|
||||
return (w, (r, borderInfos))
|
||||
|
||||
handleStillThere :: M.Map Window (Maybe Rectangle, RectWithBorders) -> M.Map Window RectWithBorders
|
||||
handleStillThere wrsStillThere = M.map handleSingleStillThere wrsStillThere
|
||||
|
||||
handleSingleStillThere :: (Maybe Rectangle, RectWithBorders) -> RectWithBorders
|
||||
handleSingleStillThere (Nothing, entry) = entry
|
||||
handleSingleStillThere (Just rCurrent, (_, borderInfos)) = (rCurrent, updatedBorderInfos)
|
||||
where
|
||||
changedBorderBlueprints = prepareBorders rCurrent
|
||||
updatedBorderInfos = map updateBorderInfo . zip borderInfos $ changedBorderBlueprints
|
||||
-- assuming that the four borders are always in the same order
|
||||
|
||||
updateBorderInfo :: (BorderInfo, BorderBlueprint) -> BorderInfo
|
||||
updateBorderInfo (borderInfo, (r, _, _)) = borderInfo { bRect = r }
|
||||
|
||||
createBorderLookupTable :: M.Map Window RectWithBorders -> [(Window, (BorderType, Window, Rectangle))]
|
||||
createBorderLookupTable wrsLastTime = concat $ map processSingleEntry $ M.toList wrsLastTime
|
||||
where
|
||||
processSingleEntry :: (Window, RectWithBorders) -> [(Window, (BorderType, Window, Rectangle))]
|
||||
processSingleEntry (w, (r, borderInfos)) = for borderInfos $ \bi -> (bWin bi, (bType bi, w, r))
|
||||
|
||||
prepareBorders :: Rectangle -> [BorderBlueprint]
|
||||
prepareBorders (Rectangle x y wh ht) =
|
||||
[((Rectangle (x + fi wh - brBorderOffset) y brBorderSize ht), brCursorRightSide , RightSideBorder),
|
||||
((Rectangle (x - brBorderOffset) y brBorderSize ht) , brCursorLeftSide , LeftSideBorder),
|
||||
((Rectangle x (y - brBorderOffset) wh brBorderSize) , brCursorTopSide , TopSideBorder),
|
||||
((Rectangle x (y + fi ht - brBorderOffset) wh brBorderSize), brCursorBottomSide , BottomSideBorder)
|
||||
]
|
||||
|
||||
handleResize :: [(Window, (BorderType, Window, Rectangle))] -> Event -> X ()
|
||||
handleResize borders ButtonEvent { ev_window = ew, ev_event_type = et }
|
||||
| et == buttonPress, Just edge <- lookup ew borders =
|
||||
case edge of
|
||||
RightSideBorder hostWin (Rectangle hx hy _ hht) ->
|
||||
(RightSideBorder, hostWin, (Rectangle hx hy _ hht)) ->
|
||||
mouseDrag (\x _ -> do
|
||||
let nwh = max 1 $ fi (x - hx)
|
||||
rect = Rectangle hx hy nwh hht
|
||||
focus hostWin
|
||||
when (x - hx > 0) $ sendMessage (SetGeometry rect)) (focus hostWin)
|
||||
LeftSideBorder hostWin (Rectangle hx hy hwh hht) ->
|
||||
(LeftSideBorder, hostWin, (Rectangle hx hy hwh hht)) ->
|
||||
mouseDrag (\x _ -> do
|
||||
let nx = max 0 $ min (hx + fi hwh) $ x
|
||||
nwh = max 1 $ hwh + fi (hx - x)
|
||||
rect = Rectangle nx hy nwh hht
|
||||
focus hostWin
|
||||
when (x < hx + fi hwh) $ sendMessage (SetGeometry rect)) (focus hostWin)
|
||||
TopSideBorder hostWin (Rectangle hx hy hwh hht) ->
|
||||
(TopSideBorder, hostWin, (Rectangle hx hy hwh hht)) ->
|
||||
mouseDrag (\_ y -> do
|
||||
let ny = max 0 $ min (hy + fi hht) $ y
|
||||
nht = max 1 $ hht + fi (hy - y)
|
||||
rect = Rectangle hx ny hwh nht
|
||||
focus hostWin
|
||||
when (y < hy + fi hht) $ sendMessage (SetGeometry rect)) (focus hostWin)
|
||||
BottomSideBorder hostWin (Rectangle hx hy hwh _) ->
|
||||
(BottomSideBorder, hostWin, (Rectangle hx hy hwh _)) ->
|
||||
mouseDrag (\_ y -> do
|
||||
let nht = max 1 $ fi (y - hy)
|
||||
rect = Rectangle hx hy hwh nht
|
||||
@@ -131,13 +193,10 @@ handleResize borders ButtonEvent { ev_window = ew, ev_event_type = et }
|
||||
when (y - hy > 0) $ sendMessage (SetGeometry rect)) (focus hostWin)
|
||||
handleResize _ _ = return ()
|
||||
|
||||
createBorder :: BorderWithRect -> X (((Window, Rectangle), BorderWithWin))
|
||||
createBorder (_, borderRect, borderCursor, borderInfo) = do
|
||||
createBorder :: BorderBlueprint -> X (BorderInfo)
|
||||
createBorder (borderRect, borderCursor, borderType) = do
|
||||
borderWin <- createInputWindow borderCursor borderRect
|
||||
return ((borderWin, borderRect), (borderWin, borderInfo))
|
||||
|
||||
deleteBorder :: BorderWithWin -> X ()
|
||||
deleteBorder (borderWin, _) = deleteWindow borderWin
|
||||
return BI { bWin = borderWin, bRect = borderRect, bType = borderType }
|
||||
|
||||
createInputWindow :: Glyph -> Rectangle -> X Window
|
||||
createInputWindow cursorGlyph r = withDisplay $ \d -> do
|
||||
@@ -162,3 +221,13 @@ mkInputWindow d (Rectangle x y w h) = do
|
||||
|
||||
for :: [a] -> (a -> b) -> [b]
|
||||
for = flip map
|
||||
|
||||
reorder :: (Eq a) => [(a, b)] -> [a] -> [(a, b)]
|
||||
reorder wrs order =
|
||||
let ordered = concat $ map (pickElem wrs) order
|
||||
rest = filter (\(w, _) -> not (w `elem` order)) wrs
|
||||
in ordered ++ rest
|
||||
where
|
||||
pickElem list e = case (lookup e list) of
|
||||
Just result -> [(e, result)]
|
||||
Nothing -> []
|
||||
|
@@ -6,7 +6,7 @@
|
||||
-- Copyright : (c) 2008 David Roundy <droundy@darcs.net>
|
||||
-- License : BSD3-style (see LICENSE)
|
||||
--
|
||||
-- Maintainer : none
|
||||
-- Maintainer : Adam Vogt <vogt.adam@gmail.com>
|
||||
-- Stability : unstable
|
||||
-- Portability : unportable
|
||||
--
|
||||
@@ -31,10 +31,8 @@ import XMonad.Layout.LayoutModifier(ModifiedLayout(..),
|
||||
import XMonad(Typeable, LayoutClass, Message, X, fromMessage,
|
||||
sendMessage, windows, withFocused, Window)
|
||||
import Control.Applicative((<$>))
|
||||
import Control.Monad(Monad(return, (>>)))
|
||||
import Data.List((\\), union)
|
||||
import Data.Maybe(Maybe(..), maybe, fromMaybe, listToMaybe,
|
||||
maybeToList)
|
||||
import Data.Maybe(fromMaybe, listToMaybe, maybeToList)
|
||||
import qualified Data.Map as M
|
||||
import qualified XMonad.StackSet as W
|
||||
|
||||
|
55
XMonad/Layout/ButtonDecoration.hs
Normal file
55
XMonad/Layout/ButtonDecoration.hs
Normal file
@@ -0,0 +1,55 @@
|
||||
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}
|
||||
----------------------------------------------------------------------------
|
||||
-- |
|
||||
-- Module : XMonad.Layout.ButtonDecoration
|
||||
-- Copyright : (c) Jan Vornberger 2009
|
||||
-- License : BSD3-style (see LICENSE)
|
||||
--
|
||||
-- Maintainer : jan.vornberger@informatik.uni-oldenburg.de
|
||||
-- Stability : unstable
|
||||
-- Portability : not portable
|
||||
--
|
||||
-- A decoration that includes small buttons on both ends which invoke
|
||||
-- various actions when clicked on: Show a window menu (see
|
||||
-- "XMonad.Actions.WindowMenu"), minimize, maximize or close the window.
|
||||
--
|
||||
-- Note: For maximizing and minimizing to actually work, you will need
|
||||
-- to integrate "XMonad.Layout.Maximize" and "XMonad.Layout.Minimize" into your
|
||||
-- setup. See the documentation of those modules for more information.
|
||||
--
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
module XMonad.Layout.ButtonDecoration
|
||||
( -- * Usage:
|
||||
-- $usage
|
||||
buttonDeco
|
||||
) where
|
||||
|
||||
import XMonad
|
||||
import XMonad.Layout.Decoration
|
||||
import XMonad.Layout.DecorationAddons
|
||||
|
||||
-- $usage
|
||||
-- You can use this module with the following in your
|
||||
-- @~\/.xmonad\/xmonad.hs@:
|
||||
--
|
||||
-- > import XMonad.Layout.DecorationAddons
|
||||
-- > import XMonad.Layout.ButtonDecoration
|
||||
--
|
||||
-- Then edit your @layoutHook@ by adding the ButtonDecoration to
|
||||
-- your layout:
|
||||
--
|
||||
-- > myL = buttonDeco shrinkText defaultThemeWithButtons (layoutHook defaultConfig)
|
||||
-- > main = xmonad defaultConfig { layoutHook = myL }
|
||||
--
|
||||
|
||||
buttonDeco :: (Eq a, Shrinker s) => s -> Theme
|
||||
-> l a -> ModifiedLayout (Decoration ButtonDecoration s) l a
|
||||
buttonDeco s c = decoration s c $ NFD True
|
||||
|
||||
data ButtonDecoration a = NFD Bool deriving (Show, Read)
|
||||
|
||||
instance Eq a => DecorationStyle ButtonDecoration a where
|
||||
describeDeco _ = "ButtonDeco"
|
||||
decorationCatchClicksHook _ mainw dFL dFR = titleBarButtonHandler mainw dFL dFR
|
||||
decorationAfterDraggingHook _ (mainw, _) decoWin = focus mainw >> handleScreenCrossing mainw decoWin >> return ()
|
@@ -2,7 +2,7 @@
|
||||
-----------------------------------------------------------------------------
|
||||
-- |
|
||||
-- Module : XMonad.Layout.Decoration
|
||||
-- Copyright : (c) 2007 Andrea Rossato
|
||||
-- Copyright : (c) 2007 Andrea Rossato, 2009 Jan Vornberger
|
||||
-- License : BSD-style (see xmonad/LICENSE)
|
||||
--
|
||||
-- Maintainer : andrea.rossato@unibz.it
|
||||
@@ -32,6 +32,7 @@ module XMonad.Layout.Decoration
|
||||
import Control.Monad (when)
|
||||
import Data.Maybe
|
||||
import Data.List
|
||||
import Foreign.C.Types(CInt)
|
||||
|
||||
import XMonad
|
||||
import qualified XMonad.StackSet as W
|
||||
@@ -77,6 +78,7 @@ data Theme =
|
||||
, fontName :: String -- ^ Font name
|
||||
, decoWidth :: Dimension -- ^ Maximum width of the decorations (if supported by the 'DecorationStyle')
|
||||
, decoHeight :: Dimension -- ^ Height of the decorations
|
||||
, windowTitleAddons :: [(String, Align)] -- ^ Extra text to appear in a window's title bar
|
||||
} deriving (Show, Read)
|
||||
|
||||
-- | The default xmonad 'Theme'.
|
||||
@@ -94,6 +96,7 @@ defaultTheme =
|
||||
, fontName = "-misc-fixed-*-*-*-*-10-*-*-*-*-*-*-*"
|
||||
, decoWidth = 200
|
||||
, decoHeight = 20
|
||||
, windowTitleAddons = []
|
||||
}
|
||||
|
||||
-- | A 'Decoration' layout modifier will handle 'SetTheme', a message
|
||||
@@ -136,30 +139,36 @@ class (Read (ds a), Show (ds a), Eq a) => DecorationStyle ds a where
|
||||
shrink :: ds a -> Rectangle -> Rectangle -> Rectangle
|
||||
shrink _ (Rectangle _ _ _ dh) (Rectangle x y w h) = Rectangle x (y + fi dh) w (h - dh)
|
||||
|
||||
-- | The decoration event hook, where the
|
||||
-- 'decorationMouseFocusHook' and 'decorationMouseDragHook' are
|
||||
-- called. If you reimplement it those methods will not be
|
||||
-- called.
|
||||
-- | The decoration event hook
|
||||
decorationEventHook :: ds a -> DecorationState -> Event -> X ()
|
||||
decorationEventHook ds s e = do decorationMouseFocusHook ds s e
|
||||
decorationMouseDragHook ds s e
|
||||
decorationEventHook ds s e = handleMouseFocusDrag ds s e
|
||||
|
||||
-- | This method is called when the user clicks the pointer over
|
||||
-- the decoration.
|
||||
decorationMouseFocusHook :: ds a -> DecorationState -> Event -> X ()
|
||||
decorationMouseFocusHook _ s e = handleMouseFocusDrag False s e
|
||||
-- | A hook that can be used to catch the cases when the user
|
||||
-- clicks on the decoration. If you return True here, the click event
|
||||
-- will be considered as dealt with and no further processing will take place.
|
||||
decorationCatchClicksHook :: ds a
|
||||
-> Window
|
||||
-> Int -- ^ distance from the left where the click happened on the decoration
|
||||
-> Int -- ^ distance from the right where the click happened on the decoration
|
||||
-> X Bool
|
||||
decorationCatchClicksHook _ _ _ _ = return False
|
||||
|
||||
-- | This method is called when the user starts grabbing the
|
||||
-- decoration.
|
||||
decorationMouseDragHook :: ds a -> DecorationState -> Event -> X ()
|
||||
decorationMouseDragHook _ s e = handleMouseFocusDrag True s e
|
||||
-- | This hook is called while a window is dragged using the decoration.
|
||||
-- The hook can be overwritten if a different way of handling the dragging
|
||||
-- is required.
|
||||
decorationWhileDraggingHook :: ds a -> CInt -> CInt -> (Window, Rectangle) -> Position -> Position -> X ()
|
||||
decorationWhileDraggingHook _ ex ey (mainw, r) x y = handleDraggingInProgress ex ey (mainw, r) x y
|
||||
|
||||
-- | This hoook is called after a window has been dragged using the decoration.
|
||||
decorationAfterDraggingHook :: ds a -> (Window, Rectangle) -> Window -> X ()
|
||||
decorationAfterDraggingHook _ds (mainw, _r) _decoWin = focus mainw
|
||||
|
||||
-- | The pure version of the main method, 'decorate'.
|
||||
pureDecoration :: ds a -> Dimension -> Dimension -> Rectangle
|
||||
-> W.Stack a -> [(a,Rectangle)] -> (a,Rectangle) -> Maybe Rectangle
|
||||
pureDecoration _ _ ht _ s _ (w,Rectangle x y wh _) = if isInStack s w
|
||||
then Just $ Rectangle x y wh ht
|
||||
else Nothing
|
||||
pureDecoration _ _ ht _ s _ (w,Rectangle x y wh ht') = if isInStack s w && (ht < ht')
|
||||
then Just $ Rectangle x y wh ht
|
||||
else Nothing
|
||||
|
||||
-- | Given the theme's decoration width and height, the screen
|
||||
-- rectangle, the windows stack, the list of windows and
|
||||
@@ -283,22 +292,30 @@ handleEvent _ _ _ _ = return ()
|
||||
|
||||
-- | Mouse focus and mouse drag are handled by the same function, this
|
||||
-- way we can start dragging unfocused windows too.
|
||||
handleMouseFocusDrag :: Bool -> DecorationState -> Event -> X ()
|
||||
handleMouseFocusDrag b (DS dwrs _) ButtonEvent { ev_window = ew
|
||||
, ev_event_type = et
|
||||
, ev_x_root = ex
|
||||
, ev_y_root = ey }
|
||||
handleMouseFocusDrag :: (DecorationStyle ds a) => ds a -> DecorationState -> Event -> X ()
|
||||
handleMouseFocusDrag ds (DS dwrs _) ButtonEvent { ev_window = ew
|
||||
, ev_event_type = et
|
||||
, ev_x_root = ex
|
||||
, ev_y_root = ey }
|
||||
| et == buttonPress
|
||||
, Just ((mainw,r),_) <- lookFor ew dwrs = do
|
||||
focus mainw
|
||||
when b $ mouseDrag (\x y -> do
|
||||
let rect = Rectangle (x - (fi ex - rect_x r))
|
||||
(y - (fi ey - rect_y r))
|
||||
(rect_width r)
|
||||
(rect_height r)
|
||||
sendMessage (SetGeometry rect)) (return ())
|
||||
, Just ((mainw,r), (_, decoRectM)) <- lookFor ew dwrs = do
|
||||
let Just (Rectangle dx _ dwh _) = decoRectM
|
||||
distFromLeft = ex - fi dx
|
||||
distFromRight = fi dwh - (ex - fi dx)
|
||||
dealtWith <- decorationCatchClicksHook ds mainw (fi distFromLeft) (fi distFromRight)
|
||||
when (not dealtWith) $ do
|
||||
mouseDrag (\x y -> focus mainw >> decorationWhileDraggingHook ds ex ey (mainw, r) x y)
|
||||
(decorationAfterDraggingHook ds (mainw, r) ew)
|
||||
handleMouseFocusDrag _ _ _ = return ()
|
||||
|
||||
handleDraggingInProgress :: CInt -> CInt -> (Window, Rectangle) -> Position -> Position -> X ()
|
||||
handleDraggingInProgress ex ey (_, r) x y = do
|
||||
let rect = Rectangle (x - (fi ex - rect_x r))
|
||||
(y - (fi ey - rect_y r))
|
||||
(rect_width r)
|
||||
(rect_height r)
|
||||
sendMessage $ SetGeometry rect
|
||||
|
||||
-- | Given a window and the state, if a matching decoration is in the
|
||||
-- state return it with its ('Maybe') 'Rectangle'.
|
||||
lookFor :: Window -> [(OrigWin,DecoWin)] -> Maybe (OrigWin,(Window,Maybe Rectangle))
|
||||
@@ -374,7 +391,9 @@ updateDeco sh t fs ((w,_),(Just dw,Just (Rectangle _ _ wh ht))) = do
|
||||
let s = shrinkIt sh
|
||||
name <- shrinkWhile s (\n -> do size <- io $ textWidthXMF dpy fs n
|
||||
return $ size > fromIntegral wh - fromIntegral (ht `div` 2)) (show nw)
|
||||
paintAndWrite dw fs wh ht 1 bc borderc tc bc AlignCenter name
|
||||
let als = AlignCenter : map snd (windowTitleAddons t)
|
||||
strs = name : map fst (windowTitleAddons t)
|
||||
paintAndWrite dw fs wh ht 1 bc borderc tc bc als strs
|
||||
updateDeco _ _ _ (_,(Just w,Nothing)) = hideWindow w
|
||||
updateDeco _ _ _ _ = return ()
|
||||
|
||||
|
124
XMonad/Layout/DecorationAddons.hs
Normal file
124
XMonad/Layout/DecorationAddons.hs
Normal file
@@ -0,0 +1,124 @@
|
||||
----------------------------------------------------------------------------
|
||||
-- |
|
||||
-- Module : XMonad.Layout.DecorationAddons
|
||||
-- Copyright : (c) Jan Vornberger 2009
|
||||
-- License : BSD3-style (see LICENSE)
|
||||
--
|
||||
-- Maintainer : jan.vornberger@informatik.uni-oldenburg.de
|
||||
-- Stability : unstable
|
||||
-- Portability : not portable
|
||||
--
|
||||
-- Various stuff that can be added to the decoration. Most of it
|
||||
-- is intended to be used by other modules. See
|
||||
-- "XMonad.Layout.ButtonDecoration" for a module that makes use of this.
|
||||
--
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
module XMonad.Layout.DecorationAddons (
|
||||
titleBarButtonHandler
|
||||
,defaultThemeWithButtons
|
||||
,handleScreenCrossing
|
||||
) where
|
||||
|
||||
import XMonad
|
||||
import qualified XMonad.StackSet as W
|
||||
import XMonad.Layout.Decoration
|
||||
import XMonad.Actions.WindowMenu
|
||||
import XMonad.Layout.Minimize
|
||||
import XMonad.Layout.Maximize
|
||||
import XMonad.Hooks.ManageDocks
|
||||
import XMonad.Util.Font
|
||||
import XMonad.Util.PositionStore
|
||||
import XMonad.Util.XUtils (fi)
|
||||
|
||||
import Control.Applicative((<$>))
|
||||
import Data.Maybe
|
||||
import qualified Data.Set as S
|
||||
|
||||
minimizeButtonOffset :: Int
|
||||
minimizeButtonOffset = 48
|
||||
|
||||
maximizeButtonOffset :: Int
|
||||
maximizeButtonOffset = 25
|
||||
|
||||
closeButtonOffset :: Int
|
||||
closeButtonOffset = 10
|
||||
|
||||
buttonSize :: Int
|
||||
buttonSize = 10
|
||||
|
||||
-- | A function intended to be plugged into the 'decorationCatchClicksHook' of a decoration.
|
||||
-- It will intercept clicks on the buttons of the decoration and invoke the associated action.
|
||||
-- To actually see the buttons, you will need to use a theme that includes them.
|
||||
-- See 'defaultThemeWithButtons' below.
|
||||
titleBarButtonHandler :: Window -> Int -> Int -> X Bool
|
||||
titleBarButtonHandler mainw distFromLeft distFromRight = do
|
||||
let action = if (fi distFromLeft <= 3 * buttonSize)
|
||||
then focus mainw >> windowMenu >> return True
|
||||
else if (fi distFromRight >= closeButtonOffset &&
|
||||
fi distFromRight <= closeButtonOffset + buttonSize)
|
||||
then focus mainw >> kill >> return True
|
||||
else if (fi distFromRight >= maximizeButtonOffset &&
|
||||
fi distFromRight <= maximizeButtonOffset + (2 * buttonSize))
|
||||
then focus mainw >> sendMessage (maximizeRestore mainw) >> return True
|
||||
else if (fi distFromRight >= minimizeButtonOffset &&
|
||||
fi distFromRight <= minimizeButtonOffset + buttonSize)
|
||||
then focus mainw >> sendMessage (MinimizeWin mainw) >> return True
|
||||
else return False
|
||||
action
|
||||
|
||||
-- | Intended to be used together with 'titleBarButtonHandler'. See above.
|
||||
defaultThemeWithButtons :: Theme
|
||||
defaultThemeWithButtons = defaultTheme {
|
||||
windowTitleAddons = [ (" (M)", AlignLeft)
|
||||
, ("_" , AlignRightOffset minimizeButtonOffset)
|
||||
, ("[]" , AlignRightOffset maximizeButtonOffset)
|
||||
, ("X" , AlignRightOffset closeButtonOffset)
|
||||
]
|
||||
}
|
||||
|
||||
-- | A function intended to be plugged into the 'decorationAfterDraggingHook' of a decoration.
|
||||
-- It will check if the window has been dragged onto another screen and shift it there.
|
||||
-- The PositionStore is also updated accordingly, as this is designed to be used together
|
||||
-- with "XMonad.Layout.PositionStoreFloat".
|
||||
handleScreenCrossing :: Window -> Window -> X Bool
|
||||
handleScreenCrossing w decoWin = withDisplay $ \d -> do
|
||||
root <- asks theRoot
|
||||
(_, _, _, px, py, _, _, _) <- io $ queryPointer d root
|
||||
ws <- gets windowset
|
||||
sc <- fromMaybe (W.current ws) <$> pointScreen (fi px) (fi py)
|
||||
maybeWksp <- screenWorkspace $ W.screen sc
|
||||
let targetWksp = maybeWksp >>= \wksp ->
|
||||
W.findTag w ws >>= \currentWksp ->
|
||||
if (currentWksp /= wksp)
|
||||
then Just wksp
|
||||
else Nothing
|
||||
case targetWksp of
|
||||
Just wksp -> do
|
||||
-- find out window under cursor on target workspace
|
||||
-- apparently we have to switch to the workspace first
|
||||
-- to make this work, which unforunately introduces some flicker
|
||||
windows $ \ws' -> W.view wksp ws'
|
||||
(_, _, selWin, _, _, _, _, _) <- io $ queryPointer d root
|
||||
|
||||
-- adjust PositionStore
|
||||
let oldScreenRect = screenRect . W.screenDetail $ W.current ws
|
||||
newScreenRect = screenRect . W.screenDetail $ sc
|
||||
{-- somewhat ugly hack to get proper ScreenRect,
|
||||
creates unwanted inter-dependencies
|
||||
TODO: get ScreenRects in a proper way --}
|
||||
oldScreenRect' <- fmap ($ oldScreenRect) (calcGap $ S.fromList [minBound .. maxBound])
|
||||
newScreenRect' <- fmap ($ newScreenRect) (calcGap $ S.fromList [minBound .. maxBound])
|
||||
wa <- io $ getWindowAttributes d decoWin
|
||||
modifyPosStore (\ps ->
|
||||
posStoreMove ps w (fi $ wa_x wa) (fi $ wa_y wa)
|
||||
oldScreenRect' newScreenRect')
|
||||
|
||||
-- set focus correctly so the window will be inserted
|
||||
-- at the correct position on the target workspace
|
||||
-- and then shift the window
|
||||
windows $ \ws' -> W.shiftWin wksp w . W.focusWindow selWin $ ws'
|
||||
|
||||
-- return True to signal that screen crossing has taken place
|
||||
return True
|
||||
Nothing -> return False
|
48
XMonad/Layout/DraggingVisualizer.hs
Normal file
48
XMonad/Layout/DraggingVisualizer.hs
Normal file
@@ -0,0 +1,48 @@
|
||||
{-# LANGUAGE DeriveDataTypeable, TypeSynonymInstances, MultiParamTypeClasses, FlexibleContexts #-}
|
||||
----------------------------------------------------------------------------
|
||||
-- |
|
||||
-- Module : XMonad.Layout.DraggingVisualizer
|
||||
-- Copyright : (c) Jan Vornberger 2009
|
||||
-- License : BSD3-style (see LICENSE)
|
||||
--
|
||||
-- Maintainer : jan.vornberger@informatik.uni-oldenburg.de
|
||||
-- Stability : unstable
|
||||
-- Portability : not portable
|
||||
--
|
||||
-- A helper module to visualize the process of dragging a window by
|
||||
-- making it follow the mouse cursor. See "XMonad.Layout.WindowSwitcherDecoration"
|
||||
-- for a module that makes use of this.
|
||||
--
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
module XMonad.Layout.DraggingVisualizer
|
||||
( draggingVisualizer,
|
||||
DraggingVisualizerMsg (..)
|
||||
) where
|
||||
|
||||
import XMonad
|
||||
import XMonad.Layout.LayoutModifier
|
||||
|
||||
data DraggingVisualizer a = DraggingVisualizer (Maybe (Window, Rectangle)) deriving ( Read, Show )
|
||||
draggingVisualizer :: LayoutClass l Window => l Window -> ModifiedLayout DraggingVisualizer l Window
|
||||
draggingVisualizer = ModifiedLayout $ DraggingVisualizer Nothing
|
||||
|
||||
data DraggingVisualizerMsg = DraggingWindow Window Rectangle
|
||||
| DraggingStopped
|
||||
deriving ( Typeable, Eq )
|
||||
instance Message DraggingVisualizerMsg
|
||||
|
||||
instance LayoutModifier DraggingVisualizer Window where
|
||||
modifierDescription (DraggingVisualizer _) = "DraggingVisualizer"
|
||||
pureModifier (DraggingVisualizer (Just dragged@(draggedWin, _))) _ _ wrs =
|
||||
if draggedWin `elem` (map fst wrs)
|
||||
then (dragged : rest, Nothing)
|
||||
else (wrs, Just $ DraggingVisualizer Nothing)
|
||||
where
|
||||
rest = filter (\(w, _) -> w /= draggedWin) wrs
|
||||
pureModifier _ _ _ wrs = (wrs, Nothing)
|
||||
|
||||
pureMess (DraggingVisualizer _) m = case fromMessage m of
|
||||
Just (DraggingWindow w rect) -> Just $ DraggingVisualizer $ Just (w, rect)
|
||||
Just (DraggingStopped) -> Just $ DraggingVisualizer Nothing
|
||||
_ -> Nothing
|
@@ -144,7 +144,8 @@ instance LayoutClass MouseResizableTile a where
|
||||
where releaseResources = mapM_ deleteDragger $ draggers state
|
||||
handleMessage _ _ = return Nothing
|
||||
|
||||
description _ = "MouseResizableTile"
|
||||
description state = mirror "MouseResizableTile"
|
||||
where mirror = if isMirrored state then ("Mirror " ++) else id
|
||||
|
||||
adjustForMirror :: Bool -> DraggerWithRect -> DraggerWithRect
|
||||
adjustForMirror False dragger = dragger
|
||||
@@ -229,6 +230,7 @@ splitHorizontallyBy f (Rectangle sx sy sw sh) = ((leftHalf, rightHalf), (dragger
|
||||
createDragger :: Rectangle -> DraggerWithRect -> X DraggerWithWin
|
||||
createDragger sr (draggerRect, draggerCursor, draggerInfo) = do
|
||||
draggerWin <- createInputWindow draggerCursor $ sanitizeRectangle sr draggerRect
|
||||
io . flip lowerWindow draggerWin =<< asks display
|
||||
return (draggerWin, draggerInfo)
|
||||
|
||||
deleteDragger :: DraggerWithWin -> X ()
|
||||
|
145
XMonad/Layout/MultiColumns.hs
Normal file
145
XMonad/Layout/MultiColumns.hs
Normal file
@@ -0,0 +1,145 @@
|
||||
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- |
|
||||
-- Module : XMonad.Layout.MultiColumns
|
||||
-- Copyright : (c) Anders Engstrom <ankaan@gmail.com>
|
||||
-- License : BSD3-style (see LICENSE)
|
||||
--
|
||||
-- Maintainer : Anders Engstrom <ankaan@gmail.com>
|
||||
-- Stability : unstable
|
||||
-- Portability : unportable
|
||||
--
|
||||
-- This layout tiles windows in a growing number of columns. The number of
|
||||
-- windows in each column can be controlled by messages.
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
module XMonad.Layout.MultiColumns (
|
||||
-- * Usage
|
||||
-- $usage
|
||||
|
||||
multiCol
|
||||
) where
|
||||
|
||||
import XMonad
|
||||
import qualified XMonad.StackSet as W
|
||||
|
||||
import Control.Monad
|
||||
|
||||
-- $usage
|
||||
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
|
||||
--
|
||||
-- > import XMonad.Layout.MultiColumns
|
||||
--
|
||||
-- Then edit your @layoutHook@ by adding the multiCol layout:
|
||||
--
|
||||
-- > myLayouts = multiCol [1] 4 0.01 0.5 ||| etc..
|
||||
-- > main = xmonad defaultConfig { layoutHook = myLayouts }
|
||||
--
|
||||
-- Or alternatively:
|
||||
--
|
||||
-- > myLayouts = Mirror (multiCol [1] 2 0.01 (-0.25)) ||| etc..
|
||||
-- > main = xmonad defaultConfig { layoutHook = myLayouts }
|
||||
--
|
||||
-- The maximum number of windows in a column can be controlled using the
|
||||
-- IncMasterN messages and the column containing the focused window will be
|
||||
-- modified. If the value is 0, all remaining windows will be placed in that
|
||||
-- column when all columns before that has been filled.
|
||||
--
|
||||
-- The size can be set to between 1 and -0.5. If the value is positive, the
|
||||
-- master column will be of that size. The rest of the screen is split among
|
||||
-- the other columns. But if the size is negative, it instead indicates the
|
||||
-- size of all non-master columns and the master column will cover the rest of
|
||||
-- the screen. If the master column would become smaller than the other
|
||||
-- columns, the screen is instead split equally among all columns. Therefore,
|
||||
-- if equal size among all columns are desired, set the size to -0.5.
|
||||
--
|
||||
-- For more detailed instructions on editing the layoutHook see:
|
||||
--
|
||||
-- "XMonad.Doc.Extending#Editing_the_layout_hook"
|
||||
|
||||
-- | Layout constructor.
|
||||
multiCol
|
||||
:: [Int] -- ^ Windows in each column, starting with master. Set to 0 to catch the rest.
|
||||
-> Int -- ^ Default value for all following columns.
|
||||
-> Rational -- ^ How much to change size each time.
|
||||
-> Rational -- ^ Initial size of master area, or column area if the size is negative.
|
||||
-> MultiCol a
|
||||
multiCol n defn ds s = MultiCol (map (max 0) n) (max 0 defn) ds s 0
|
||||
|
||||
data MultiCol a = MultiCol
|
||||
{ multiColNWin :: ![Int]
|
||||
, multiColDefWin :: !Int
|
||||
, multiColDeltaSize :: !Rational
|
||||
, multiColSize :: !Rational
|
||||
, multiColActive :: !Int
|
||||
} deriving (Show,Read,Eq)
|
||||
|
||||
instance LayoutClass MultiCol a where
|
||||
doLayout l r s = return (zip w rlist, resl)
|
||||
where rlist = doL (multiColNWin l') (multiColSize l') r wlen
|
||||
w = W.integrate s
|
||||
wlen = length w
|
||||
-- Make sure the list of columns is big enough and update active column
|
||||
nw = multiColNWin l ++ repeat (multiColDefWin l)
|
||||
l' = l { multiColNWin = take (max (length $ multiColNWin l) $ getCol (wlen-1) nw + 1) nw
|
||||
, multiColActive = getCol (length $ W.up s) nw
|
||||
}
|
||||
-- Only return new layout if it has been modified
|
||||
resl = if l'==l
|
||||
then Nothing
|
||||
else Just l'
|
||||
handleMessage l m =
|
||||
return $ msum [fmap resize (fromMessage m)
|
||||
,fmap incmastern (fromMessage m)]
|
||||
where resize Shrink = l { multiColSize = max (-0.5) $ s-ds }
|
||||
resize Expand = l { multiColSize = min 1 $ s+ds }
|
||||
incmastern (IncMasterN x) = l { multiColNWin = take a n ++ [newval] ++ tail r }
|
||||
where newval = max 0 $ head r + x
|
||||
r = drop a n
|
||||
n = multiColNWin l
|
||||
ds = multiColDeltaSize l
|
||||
s = multiColSize l
|
||||
a = multiColActive l
|
||||
description _ = "MultiCol"
|
||||
|
||||
|
||||
-- | Get which column a window is in, starting at 0.
|
||||
getCol :: Int -> [Int] -> Int
|
||||
getCol w (n:ns) = if n<1 || w < n
|
||||
then 0
|
||||
else 1 + getCol (w-n) ns
|
||||
-- Should never occur...
|
||||
getCol _ _ = -1
|
||||
|
||||
doL :: [Int] -> Rational -> Rectangle -> Int -> [Rectangle]
|
||||
doL nwin s r n = rlist
|
||||
where -- Number of columns to tile
|
||||
ncol = getCol (n-1) nwin + 1
|
||||
-- Compute the actual size
|
||||
size = floor $ abs s * fromIntegral (rect_width r)
|
||||
-- Extract all but last column to tile
|
||||
c = take (ncol-1) nwin
|
||||
-- Compute number of windows in last column and add it to the others
|
||||
col = c ++ [n-sum c]
|
||||
-- Compute width of columns
|
||||
width = if s>0
|
||||
then if ncol==1
|
||||
-- Only one window
|
||||
then [fromIntegral $ rect_width r]
|
||||
-- Give the master it's space and split the rest equally for the other columns
|
||||
else size:replicate (ncol-1) ((fromIntegral (rect_width r) - size) `div` (ncol-1))
|
||||
else if fromIntegral ncol * abs s >= 1
|
||||
-- Split equally
|
||||
then replicate ncol $ fromIntegral (rect_width r) `div` ncol
|
||||
-- Let the master cover what is left...
|
||||
else (fromIntegral (rect_width r) - (ncol-1)*size):replicate (ncol-1) size
|
||||
-- Compute the horizontal position of columns
|
||||
xpos = accumEx (fromIntegral $ rect_x r) width
|
||||
-- Exclusive accumulation
|
||||
accumEx a (x:xs) = a:accumEx (a+x) xs
|
||||
accumEx _ _ = []
|
||||
-- Create a rectangle for each column
|
||||
cr = zipWith (\x w -> r { rect_x=fromIntegral x, rect_width=fromIntegral w }) xpos width
|
||||
-- Split the columns into the windows
|
||||
rlist = concat $ zipWith (\num rect -> splitVertically num rect) col cr
|
92
XMonad/Layout/PositionStoreFloat.hs
Normal file
92
XMonad/Layout/PositionStoreFloat.hs
Normal file
@@ -0,0 +1,92 @@
|
||||
{-# LANGUAGE TypeSynonymInstances, MultiParamTypeClasses, PatternGuards #-}
|
||||
----------------------------------------------------------------------------
|
||||
-- |
|
||||
-- Module : XMonad.Layout.PositionStoreFloat
|
||||
-- Copyright : (c) Jan Vornberger 2009
|
||||
-- License : BSD3-style (see LICENSE)
|
||||
--
|
||||
-- Maintainer : jan.vornberger@informatik.uni-oldenburg.de
|
||||
-- Stability : unstable
|
||||
-- Portability : not portable
|
||||
--
|
||||
-- A floating layout which has been designed with a dual-head setup
|
||||
-- in mind. It makes use of "XMonad.Util.PositionStore" as well as
|
||||
-- "XMonad.Hooks.PositionStoreHooks" . Since there is currently no way
|
||||
-- to move or resize windows with the keyboard alone in this layout,
|
||||
-- it is adviced to use it in combination with a decoration such as
|
||||
-- "XMonad.Layout.NoFrillsDecoration" (to move windows) and the
|
||||
-- layout modifier "XMonad.Layout.BorderResize" (to resize windows).
|
||||
--
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
module XMonad.Layout.PositionStoreFloat
|
||||
( -- * Usage
|
||||
-- $usage
|
||||
positionStoreFloat
|
||||
) where
|
||||
|
||||
import XMonad
|
||||
import XMonad.Util.PositionStore
|
||||
import qualified XMonad.StackSet as S
|
||||
import XMonad.Layout.WindowArranger
|
||||
import Control.Monad(when)
|
||||
import Data.Maybe(isJust)
|
||||
import Data.List(nub)
|
||||
|
||||
-- $usage
|
||||
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
|
||||
--
|
||||
-- > import XMonad.Layout.PositionStoreFloat
|
||||
-- > import XMonad.Layout.NoFrillsDecoration
|
||||
-- > import XMonad.Layout.BorderResize
|
||||
--
|
||||
-- Then edit your @layoutHook@ by adding the PositionStoreFloat layout.
|
||||
-- Below is a suggestion which uses the mentioned NoFrillsDecoration and
|
||||
-- BorderResize:
|
||||
--
|
||||
-- > myLayouts = floatingDeco $ borderResize $ positionStoreFloat ||| etc..
|
||||
-- > where floatingDeco l = noFrillsDeco shrinkText defaultTheme l
|
||||
-- > main = xmonad defaultConfig { layoutHook = myLayouts }
|
||||
--
|
||||
-- See the documentation of "XMonad.Hooks.PositionStoreHooks" on how
|
||||
-- to add the support hooks.
|
||||
|
||||
positionStoreFloat :: PositionStoreFloat a
|
||||
positionStoreFloat = PSF (Nothing, [])
|
||||
|
||||
data PositionStoreFloat a = PSF (Maybe Rectangle, [a]) deriving (Show, Read)
|
||||
instance LayoutClass PositionStoreFloat Window where
|
||||
description _ = "PSF"
|
||||
doLayout (PSF (maybeChange, paintOrder)) sr (S.Stack w l r) = do
|
||||
posStore <- getPosStore
|
||||
let wrs = map (\w' -> (w', pSQ posStore w' sr)) (reverse l ++ r)
|
||||
let focused = case maybeChange of
|
||||
Nothing -> (w, pSQ posStore w sr)
|
||||
Just changedRect -> (w, changedRect)
|
||||
let wrs' = focused : wrs
|
||||
let paintOrder' = nub (w : paintOrder)
|
||||
when (isJust maybeChange) $ do
|
||||
updatePositionStore focused sr
|
||||
return (reorder wrs' paintOrder', Just $ PSF (Nothing, paintOrder'))
|
||||
where
|
||||
pSQ posStore w' sr' = case (posStoreQuery posStore w' sr') of
|
||||
Just rect -> rect
|
||||
Nothing -> (Rectangle 50 50 200 200) -- should usually not happen
|
||||
pureMessage (PSF (_, paintOrder)) m
|
||||
| Just (SetGeometry rect) <- fromMessage m =
|
||||
Just $ PSF (Just rect, paintOrder)
|
||||
| otherwise = Nothing
|
||||
|
||||
updatePositionStore :: (Window, Rectangle) -> Rectangle -> X ()
|
||||
updatePositionStore (w, rect) sr = modifyPosStore (\ps ->
|
||||
posStoreInsert ps w rect sr)
|
||||
|
||||
reorder :: (Eq a) => [(a, b)] -> [a] -> [(a, b)]
|
||||
reorder wrs order =
|
||||
let ordered = concat $ map (pickElem wrs) order
|
||||
rest = filter (\(w, _) -> not (w `elem` order)) wrs
|
||||
in ordered ++ rest
|
||||
where
|
||||
pickElem list e = case (lookup e list) of
|
||||
Just result -> [(e, result)]
|
||||
Nothing -> []
|
@@ -96,7 +96,7 @@ flashName c (Rectangle _ _ wh ht) wrs = do
|
||||
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
|
||||
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)
|
||||
|
@@ -66,7 +66,7 @@ data TabBarDecoration a = TabBar XPPosition deriving (Read, Show)
|
||||
instance Eq a => DecorationStyle TabBarDecoration a where
|
||||
describeDeco _ = "TabBar"
|
||||
shrink _ _ r = r
|
||||
decorationMouseDragHook _ _ _ = return ()
|
||||
decorationCatchClicksHook _ mainw _ _ = focus mainw >> return True
|
||||
pureDecoration (TabBar p) _ dht (Rectangle x y wh ht) s _ (w,_) =
|
||||
if isInStack s w then Just $ Rectangle nx ny wid (fi dht) else Nothing
|
||||
where wrs = S.integrate s
|
||||
|
@@ -155,17 +155,16 @@ data TabbedDecoration a = Tabbed TabbarLocation TabbarShown deriving (Read, Show
|
||||
instance Eq a => DecorationStyle TabbedDecoration a where
|
||||
describeDeco (Tabbed Top _ ) = "Tabbed"
|
||||
describeDeco (Tabbed Bottom _ ) = "Tabbed Bottom"
|
||||
decorationMouseFocusHook _ ds ButtonEvent { ev_window = ew
|
||||
, ev_event_type = et
|
||||
, ev_button = eb }
|
||||
decorationEventHook _ ds ButtonEvent { ev_window = ew
|
||||
, ev_event_type = et
|
||||
, ev_button = eb }
|
||||
| et == buttonPress
|
||||
, Just ((w,_),_) <-findWindowByDecoration ew ds =
|
||||
if eb == button2
|
||||
then killWindow w
|
||||
else focus w
|
||||
decorationMouseFocusHook _ _ _ = return ()
|
||||
decorationEventHook _ _ _ = return ()
|
||||
|
||||
decorationMouseDragHook _ _ _ = return ()
|
||||
pureDecoration (Tabbed lc sh) _ ht _ s wrs (w,r@(Rectangle x y wh hh))
|
||||
= if ((sh == Always && numWindows > 0) || numWindows > 1)
|
||||
then Just $ case lc of
|
||||
|
105
XMonad/Layout/WindowSwitcherDecoration.hs
Normal file
105
XMonad/Layout/WindowSwitcherDecoration.hs
Normal file
@@ -0,0 +1,105 @@
|
||||
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}
|
||||
----------------------------------------------------------------------------
|
||||
-- |
|
||||
-- Module : XMonad.Layout.WindowSwitcherDecoration
|
||||
-- Copyright : (c) Jan Vornberger 2009
|
||||
-- License : BSD3-style (see LICENSE)
|
||||
--
|
||||
-- Maintainer : jan.vornberger@informatik.uni-oldenburg.de
|
||||
-- Stability : unstable
|
||||
-- Portability : not portable
|
||||
--
|
||||
-- A decoration that allows to switch the position of windows by dragging
|
||||
-- them onto each other.
|
||||
--
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
module XMonad.Layout.WindowSwitcherDecoration
|
||||
( -- * Usage:
|
||||
-- $usage
|
||||
windowSwitcherDecoration,
|
||||
windowSwitcherDecorationWithButtons
|
||||
) where
|
||||
|
||||
import XMonad
|
||||
import XMonad.Layout.Decoration
|
||||
import XMonad.Layout.DecorationAddons
|
||||
import XMonad.Layout.DraggingVisualizer
|
||||
import qualified XMonad.StackSet as S
|
||||
import Control.Monad
|
||||
import Foreign.C.Types(CInt)
|
||||
|
||||
-- $usage
|
||||
-- You can use this module with the following in your
|
||||
-- @~\/.xmonad\/xmonad.hs@:
|
||||
--
|
||||
-- > import XMonad.Layout.WindowSwitcherDecoration
|
||||
-- > import XMonad.Layout.DraggingVisualizer
|
||||
--
|
||||
-- Then edit your @layoutHook@ by adding the WindowSwitcherDecoration to
|
||||
-- your layout:
|
||||
--
|
||||
-- > myL = windowSwitcherDecoration shrinkText defaultTheme (draggingVisualizer $ layoutHook defaultConfig)
|
||||
-- > main = xmonad defaultConfig { layoutHook = myL }
|
||||
--
|
||||
-- There is also a version of the decoration that contains buttons like
|
||||
-- "XMonad.Layout.ButtonDecoration". To use that version, you will need to
|
||||
-- import "XMonad.Layout.DecorationAddons" as well and modify your @layoutHook@
|
||||
-- in the following way:
|
||||
--
|
||||
-- > import XMonad.Layout.DecorationAddons
|
||||
-- >
|
||||
-- > myL = windowSwitcherDecorationWithButtons shrinkText defaultThemeWithButtons (draggingVisualizer $ layoutHook defaultConfig)
|
||||
-- > main = xmonad defaultConfig { layoutHook = myL }
|
||||
--
|
||||
|
||||
windowSwitcherDecoration :: (Eq a, Shrinker s) => s -> Theme
|
||||
-> l a -> ModifiedLayout (Decoration WindowSwitcherDecoration s) l a
|
||||
windowSwitcherDecoration s c = decoration s c $ WSD False
|
||||
|
||||
windowSwitcherDecorationWithButtons :: (Eq a, Shrinker s) => s -> Theme
|
||||
-> l a -> ModifiedLayout (Decoration WindowSwitcherDecoration s) l a
|
||||
windowSwitcherDecorationWithButtons s c = decoration s c $ WSD True
|
||||
|
||||
data WindowSwitcherDecoration a = WSD Bool deriving (Show, Read)
|
||||
|
||||
instance Eq a => DecorationStyle WindowSwitcherDecoration a where
|
||||
describeDeco _ = "WindowSwitcherDeco"
|
||||
|
||||
decorationCatchClicksHook (WSD withButtons) mainw dFL dFR = if withButtons
|
||||
then titleBarButtonHandler mainw dFL dFR
|
||||
else return False
|
||||
decorationWhileDraggingHook _ ex ey (mainw, r) x y = handleTiledDraggingInProgress ex ey (mainw, r) x y
|
||||
decorationAfterDraggingHook _ (mainw, _) decoWin = do focus mainw
|
||||
hasCrossed <- handleScreenCrossing mainw decoWin
|
||||
unless hasCrossed $ do sendMessage $ DraggingStopped
|
||||
performWindowSwitching mainw
|
||||
|
||||
handleTiledDraggingInProgress :: CInt -> CInt -> (Window, Rectangle) -> Position -> Position -> X ()
|
||||
handleTiledDraggingInProgress ex ey (mainw, r) x y = do
|
||||
let rect = Rectangle (x - (fi ex - rect_x r))
|
||||
(y - (fi ey - rect_y r))
|
||||
(rect_width r)
|
||||
(rect_height r)
|
||||
sendMessage $ DraggingWindow mainw rect
|
||||
|
||||
performWindowSwitching :: Window -> X ()
|
||||
performWindowSwitching win =
|
||||
withDisplay $ \d -> do
|
||||
root <- asks theRoot
|
||||
(_, _, selWin, _, _, _, _, _) <- io $ queryPointer d root
|
||||
ws <- gets windowset
|
||||
let allWindows = S.index ws
|
||||
-- do a little double check to be sure
|
||||
if (win `elem` allWindows) && (selWin `elem` allWindows)
|
||||
then do
|
||||
let allWindowsSwitched = map (switchEntries win selWin) allWindows
|
||||
let (ls, t:rs) = break (win ==) allWindowsSwitched
|
||||
let newStack = S.Stack t (reverse ls) rs
|
||||
windows $ S.modify' $ \_ -> newStack
|
||||
else return ()
|
||||
where
|
||||
switchEntries a b x
|
||||
| x == a = b
|
||||
| x == b = a
|
||||
| otherwise = x
|
102
XMonad/Prompt.hs
102
XMonad/Prompt.hs
@@ -29,7 +29,8 @@ module XMonad.Prompt
|
||||
, defaultXPKeymap
|
||||
, quit
|
||||
, killBefore, killAfter, startOfLine, endOfLine
|
||||
, pasteString, copyString, moveCursor
|
||||
, pasteString, moveCursor
|
||||
, setInput, getInput
|
||||
, moveWord, killWord, deleteString
|
||||
, moveHistory, setSuccess, setDone
|
||||
, Direction1D(..)
|
||||
@@ -62,12 +63,13 @@ module XMonad.Prompt
|
||||
|
||||
import Prelude hiding (catch)
|
||||
|
||||
import XMonad hiding (config, io, numlockMask, cleanMask)
|
||||
import qualified XMonad as X (numlockMask,config)
|
||||
import XMonad hiding (config, numlockMask, cleanMask)
|
||||
import qualified XMonad as X (numlockMask)
|
||||
import qualified XMonad.StackSet as W
|
||||
import XMonad.Util.Font
|
||||
import XMonad.Util.Types
|
||||
import XMonad.Util.XSelection (getSelection, putSelection)
|
||||
import XMonad.Util.XSelection (getSelection)
|
||||
import XMonad.Util.XUtils (fi)
|
||||
|
||||
import Control.Arrow ((&&&),first)
|
||||
import Control.Concurrent (threadDelay)
|
||||
@@ -217,8 +219,8 @@ amberXPConfig = defaultXPConfig { fgColor = "#ca8f2d", bgColor = "black", fgHLig
|
||||
type ComplFunction = String -> IO [String]
|
||||
|
||||
initState :: XPrompt p => Display -> Window -> Window -> Rectangle -> ComplFunction
|
||||
-> GC -> XMonadFont -> p -> [String] -> XPConfig -> XPState
|
||||
initState d rw w s compl gc fonts pt h c =
|
||||
-> GC -> XMonadFont -> p -> [String] -> XPConfig -> KeyMask -> XPState
|
||||
initState d rw w s compl gc fonts pt h c nm =
|
||||
XPS { dpy = d
|
||||
, rootw = rw
|
||||
, win = w
|
||||
@@ -237,7 +239,7 @@ initState d rw w s compl gc fonts pt h c =
|
||||
, config = c
|
||||
, successful = False
|
||||
, done = False
|
||||
, numlockMask = X.numlockMask defaultConfig
|
||||
, numlockMask = nm
|
||||
}
|
||||
|
||||
-- this would be much easier with functional references
|
||||
@@ -247,6 +249,15 @@ command = W.focus . commandHistory
|
||||
setCommand :: String -> XPState -> XPState
|
||||
setCommand xs s = s { commandHistory = (commandHistory s) { W.focus = xs }}
|
||||
|
||||
-- | Sets the input string to the given value.
|
||||
setInput :: String -> XP ()
|
||||
setInput = modify . setCommand
|
||||
|
||||
-- | Returns the current input string. Intented for use in custom keymaps
|
||||
-- where the 'get' or similar can't be used to retrieve it.
|
||||
getInput :: XP String
|
||||
getInput = gets command
|
||||
|
||||
-- | Same as 'mkXPrompt', except that the action function can have
|
||||
-- type @String -> X a@, for any @a@, and the final action returned
|
||||
-- by 'mkXPromptWithReturn' will have type @X (Maybe a)@. @Nothing@
|
||||
@@ -255,27 +266,24 @@ setCommand xs s = s { commandHistory = (commandHistory s) { W.focus = xs }}
|
||||
-- module.
|
||||
mkXPromptWithReturn :: XPrompt p => p -> XPConfig -> ComplFunction -> (String -> X a) -> X (Maybe a)
|
||||
mkXPromptWithReturn t conf compl action = do
|
||||
c <- ask
|
||||
let d = display c
|
||||
rw = theRoot c
|
||||
s <- gets $ screenRect . W.screenDetail . W.current . windowset
|
||||
hist <- liftIO readHistory
|
||||
w <- liftIO $ createWin d rw conf s
|
||||
liftIO $ selectInput d w $ exposureMask .|. keyPressMask
|
||||
gc <- liftIO $ createGC d w
|
||||
liftIO $ setGraphicsExposures d gc False
|
||||
XConf { display = d, theRoot = rw } <- ask
|
||||
s <- gets $ screenRect . W.screenDetail . W.current . windowset
|
||||
hist <- io readHistory
|
||||
w <- io $ createWin d rw conf s
|
||||
io $ selectInput d w $ exposureMask .|. keyPressMask
|
||||
gc <- io $ createGC d w
|
||||
io $ setGraphicsExposures d gc False
|
||||
fs <- initXMF (font conf)
|
||||
numlock <- asks $ X.numlockMask . X.config
|
||||
numlock <- gets $ X.numlockMask
|
||||
let hs = fromMaybe [] $ M.lookup (showXPrompt t) hist
|
||||
st = (initState d rw w s compl gc fs (XPT t) hs conf)
|
||||
{ numlockMask = numlock }
|
||||
st' <- liftIO $ execStateT runXP st
|
||||
st = initState d rw w s compl gc fs (XPT t) hs conf numlock
|
||||
st' <- io $ execStateT runXP st
|
||||
|
||||
releaseXMF fs
|
||||
liftIO $ freeGC d gc
|
||||
io $ freeGC d gc
|
||||
if successful st'
|
||||
then do
|
||||
liftIO $ writeHistory $ M.insertWith
|
||||
io $ writeHistory $ M.insertWith
|
||||
(\xs ys -> take (historySize conf)
|
||||
. historyFilter conf $ xs ++ ys)
|
||||
(showXPrompt t) (historyFilter conf [command st'])
|
||||
@@ -302,8 +310,7 @@ mkXPrompt t conf compl action = mkXPromptWithReturn t conf compl action >> retur
|
||||
|
||||
runXP :: XP ()
|
||||
runXP = do
|
||||
st <- get
|
||||
let (d,w) = (dpy &&& win) st
|
||||
(d,w) <- gets (dpy &&& win)
|
||||
status <- io $ grabKeyboard d w True grabModeAsync grabModeAsync currentTime
|
||||
when (status == grabSuccess) $ do
|
||||
updateWindows
|
||||
@@ -403,13 +410,13 @@ defaultXPKeymap = M.fromList $
|
||||
, (xK_a, startOfLine)
|
||||
, (xK_e, endOfLine)
|
||||
, (xK_y, pasteString)
|
||||
, (xK_c, copyString)
|
||||
, (xK_Right, moveWord Next)
|
||||
, (xK_Left, moveWord Prev)
|
||||
, (xK_Delete, killWord Next)
|
||||
, (xK_BackSpace, killWord Prev)
|
||||
, (xK_w, killWord Prev)
|
||||
, (xK_q, quit)
|
||||
, (xK_g, quit)
|
||||
, (xK_bracketleft, quit)
|
||||
] ++
|
||||
map (first $ (,) 0)
|
||||
[ (xK_Return, setSuccess True >> setDone True)
|
||||
@@ -505,10 +512,6 @@ insertString str =
|
||||
pasteString :: XP ()
|
||||
pasteString = join $ io $ liftM insertString getSelection
|
||||
|
||||
-- | Copy the currently entered string into the X selection.
|
||||
copyString :: XP ()
|
||||
copyString = gets command >>= io . putSelection
|
||||
|
||||
-- | Remove a character at the cursor position
|
||||
deleteString :: Direction1D -> XP ()
|
||||
deleteString d =
|
||||
@@ -724,28 +727,15 @@ redrawComplWin compl = do
|
||||
|
||||
printComplList :: Display -> Drawable -> GC -> String -> String
|
||||
-> [Position] -> [Position] -> [[String]] -> XP ()
|
||||
printComplList _ _ _ _ _ _ _ [] = return ()
|
||||
printComplList _ _ _ _ _ [] _ _ = return ()
|
||||
printComplList d drw gc fc bc (x:xs) y (s:ss) = do
|
||||
printComplColumn d drw gc fc bc x y s
|
||||
printComplList d drw gc fc bc xs y ss
|
||||
|
||||
printComplColumn :: Display -> Drawable -> GC -> String -> String
|
||||
-> Position -> [Position] -> [String] -> XP ()
|
||||
printComplColumn _ _ _ _ _ _ _ [] = return ()
|
||||
printComplColumn _ _ _ _ _ _ [] _ = return ()
|
||||
printComplColumn d drw gc fc bc x (y:yy) (s:ss) = do
|
||||
printComplString d drw gc fc bc x y s
|
||||
printComplColumn d drw gc fc bc x yy ss
|
||||
|
||||
printComplString :: Display -> Drawable -> GC -> String -> String
|
||||
-> Position -> Position -> String -> XP ()
|
||||
printComplString d drw gc fc bc x y s = do
|
||||
st <- get
|
||||
if completionToCommand (xptype st) s == commandToComplete (xptype st) (command st)
|
||||
then printStringXMF d drw (fontS st) gc
|
||||
(fgHLight $ config st) (bgHLight $ config st) x y s
|
||||
else printStringXMF d drw (fontS st) gc fc bc x y s
|
||||
printComplList d drw gc fc bc xs ys sss =
|
||||
zipWithM_ (\x ss ->
|
||||
zipWithM_ (\y s -> do
|
||||
st <- get
|
||||
let (f,b) = if completionToCommand (xptype st) s == commandToComplete (xptype st) (command st)
|
||||
then (fgHLight $ config st,bgHLight $ config st)
|
||||
else (fc,bc)
|
||||
printStringXMF d drw (fontS st) gc f b x y s)
|
||||
ys ss) xs sss
|
||||
|
||||
-- History
|
||||
|
||||
@@ -834,14 +824,6 @@ getNextCompletion c l = l !! idx
|
||||
Just i -> if i >= length l - 1 then 0 else i + 1
|
||||
Nothing -> 0
|
||||
|
||||
-- Lift an IO action into the XP
|
||||
io :: IO a -> XP a
|
||||
io = liftIO
|
||||
|
||||
-- Shorthand for fromIntegral
|
||||
fi :: (Num b, Integral a) => a -> b
|
||||
fi = fromIntegral
|
||||
|
||||
-- | Given a maximum length, splits a list into sublists
|
||||
splitInSubListsAt :: Int -> [a] -> [[a]]
|
||||
splitInSubListsAt _ [] = []
|
||||
|
@@ -59,5 +59,5 @@ emailPrompt c addrs =
|
||||
inputPromptWithCompl c "To" (mkComplFunFromList addrs) ?+ \to ->
|
||||
inputPrompt c "Subject" ?+ \subj ->
|
||||
inputPrompt c "Body" ?+ \body ->
|
||||
io $ runProcessWithInput "mail" ["-s", subj, to] (body ++ "\n")
|
||||
runProcessWithInput "mail" ["-s", subj, to] (body ++ "\n")
|
||||
>> return ()
|
||||
|
@@ -37,13 +37,13 @@ import XMonad.Util.Run
|
||||
dmenuXinerama :: [String] -> X String
|
||||
dmenuXinerama opts = do
|
||||
curscreen <- (fromIntegral . W.screen . W.current) `fmap` gets windowset :: X Int
|
||||
io $ runProcessWithInput "dmenu" ["-xs", show (curscreen+1)] (unlines opts)
|
||||
runProcessWithInput "dmenu" ["-xs", show (curscreen+1)] (unlines opts)
|
||||
|
||||
dmenu :: [String] -> X String
|
||||
dmenu opts = menu "dmenu" opts
|
||||
|
||||
menu :: String -> [String] -> X String
|
||||
menu menuCmd opts = io $ runProcessWithInput menuCmd [] (unlines opts)
|
||||
menu menuCmd opts = runProcessWithInput menuCmd [] (unlines opts)
|
||||
|
||||
menuMap :: String -> M.Map String a -> X (Maybe a)
|
||||
menuMap menuCmd selectionMap = do
|
||||
|
@@ -13,36 +13,169 @@
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
module XMonad.Util.Dzen (
|
||||
-- * Flexible interface
|
||||
dzenConfig,
|
||||
timeout,
|
||||
font,
|
||||
xScreen,
|
||||
vCenter,
|
||||
hCenter,
|
||||
center,
|
||||
onCurr,
|
||||
x,
|
||||
y,
|
||||
addArgs,
|
||||
|
||||
-- * Legacy interface
|
||||
dzen,
|
||||
dzenWithArgs,
|
||||
dzenScreen,
|
||||
seconds
|
||||
dzenWithArgs,
|
||||
|
||||
-- * Miscellaneous
|
||||
seconds,
|
||||
chomp,
|
||||
(>=>)
|
||||
) where
|
||||
|
||||
import Control.Monad
|
||||
import Data.List
|
||||
import XMonad
|
||||
import XMonad.StackSet
|
||||
import XMonad.Util.Run (runProcessWithInputAndWait, seconds)
|
||||
|
||||
type DzenConfig = (Int, [String]) -> X (Int, [String])
|
||||
|
||||
-- | @dzenConfig config s@ will display the string @s@ according to the
|
||||
-- configuration @config@. For example, to display the string @\"foobar\"@ with
|
||||
-- all the default settings, you can simply call
|
||||
--
|
||||
-- > dzenConfig return "foobar"
|
||||
--
|
||||
-- Or, to set a longer timeout, you could use
|
||||
--
|
||||
-- > dzenConfig (timeout 10) "foobar"
|
||||
--
|
||||
-- You can combine configurations with the (>=>) operator. To display
|
||||
-- @\"foobar\"@ for 10 seconds on the first screen, you could use
|
||||
--
|
||||
-- > dzenConfig (timeout 10 >=> xScreen 0) "foobar"
|
||||
--
|
||||
-- As a final example, you could adapt the above to display @\"foobar\"@ for
|
||||
-- 10 seconds on the current screen with
|
||||
--
|
||||
-- > dzenConfig (timeout 10 >=> onCurr xScreen) "foobar"
|
||||
dzenConfig :: DzenConfig -> String -> X ()
|
||||
dzenConfig conf s = do
|
||||
(t, args) <- conf (seconds 3, [])
|
||||
runProcessWithInputAndWait "dzen2" args (chomp s) t
|
||||
|
||||
-- | dzen wants exactly one newline at the end of its input, so this can be
|
||||
-- used for your own invocations of dzen. However, all functions in this
|
||||
-- module will call this for you.
|
||||
chomp :: String -> String
|
||||
chomp = (++"\n") . reverse . dropWhile ('\n' ==) . reverse
|
||||
|
||||
-- | Set the timeout, in seconds. This defaults to 3 seconds if not
|
||||
-- specified.
|
||||
timeout :: Rational -> DzenConfig
|
||||
timeout = timeoutMicro . seconds
|
||||
|
||||
-- | Set the timeout, in microseconds. Mostly here for the legacy
|
||||
-- interface.
|
||||
timeoutMicro :: Int -> DzenConfig
|
||||
timeoutMicro n (_, ss) = return (n, ss)
|
||||
|
||||
-- | Add raw command-line arguments to the configuration. These will be
|
||||
-- passed on verbatim to dzen2. The default includes no arguments.
|
||||
addArgs :: [String] -> DzenConfig
|
||||
addArgs ss (n, ss') = return (n, ss ++ ss')
|
||||
|
||||
-- | Start dzen2 on a particular screen. Only works with versions of dzen
|
||||
-- that support the "-xs" argument.
|
||||
xScreen :: ScreenId -> DzenConfig
|
||||
xScreen sc = addArgs ["-xs", show (fromIntegral sc + 1 :: Int)]
|
||||
|
||||
-- | Take a screen-specific configuration and supply it with the screen ID
|
||||
-- of the currently focused screen, according to xmonad. For example, show
|
||||
-- a 100-pixel wide bar centered within the current screen, you could use
|
||||
--
|
||||
-- > dzenConfig (onCurr (hCenter 100)) "foobar"
|
||||
--
|
||||
-- Of course, you can still combine these with (>=>); for example, to center
|
||||
-- the string @\"foobar\"@ both horizontally and vertically in a 100x14 box
|
||||
-- using the lovely Terminus font, you could use
|
||||
--
|
||||
-- > terminus = "-*-terminus-*-*-*-*-12-*-*-*-*-*-*-*"
|
||||
-- > dzenConfig (onCurr (center 100 14) >=> font terminus) "foobar"
|
||||
onCurr :: (ScreenId -> DzenConfig) -> DzenConfig
|
||||
onCurr f conf = gets (screen . current . windowset) >>= flip f conf
|
||||
|
||||
-- | Put the top of the dzen bar at a particular pixel.
|
||||
x :: Int -> DzenConfig
|
||||
x n = addArgs ["-x", show n]
|
||||
-- | Put the left of the dzen bar at a particular pixel.
|
||||
y :: Int -> DzenConfig
|
||||
y n = addArgs ["-y", show n]
|
||||
|
||||
-- | Specify the font. Check out xfontsel to get the format of the String
|
||||
-- right; if your dzen supports xft, then you can supply that here, too.
|
||||
font :: String -> DzenConfig
|
||||
font fn = addArgs ["-fn", fn]
|
||||
|
||||
-- | @vCenter height sc@ sets the configuration to have the dzen bar appear
|
||||
-- on screen @sc@ with height @height@, vertically centered with respect to
|
||||
-- the actual size of that screen.
|
||||
vCenter :: Int -> ScreenId -> DzenConfig
|
||||
vCenter = center' rect_height "-h" "-y"
|
||||
|
||||
-- | @hCenter width sc@ sets the configuration to have the dzen bar appear
|
||||
-- on screen @sc@ with width @width@, horizontally centered with respect to
|
||||
-- the actual size of that screen.
|
||||
hCenter :: Int -> ScreenId -> DzenConfig
|
||||
hCenter = center' rect_width "-w" "-x"
|
||||
|
||||
-- | @center width height sc@ sets the configuration to have the dzen bar
|
||||
-- appear on screen @sc@ with width @width@ and height @height@, centered
|
||||
-- both horizontally and vertically with respect to the actual size of that
|
||||
-- screen.
|
||||
center :: Int -> Int -> ScreenId -> DzenConfig
|
||||
center width height sc = hCenter width sc >=> vCenter height sc
|
||||
|
||||
-- Center things along a single dimension on a particular screen.
|
||||
center' :: (Rectangle -> Dimension) -> String -> String -> Int -> ScreenId -> DzenConfig
|
||||
center' selector extentName positionName extent sc conf = do
|
||||
rect <- gets (detailFromScreenId sc . windowset)
|
||||
case rect of
|
||||
Nothing -> return conf
|
||||
Just r -> addArgs
|
||||
[extentName , show extent,
|
||||
positionName, show ((fromIntegral (selector r) - extent) `div` 2),
|
||||
"-xs" , show (fromIntegral sc + 1 :: Int)
|
||||
] conf
|
||||
|
||||
-- Get the rectangle outlining a particular screen.
|
||||
detailFromScreenId :: ScreenId -> WindowSet -> Maybe Rectangle
|
||||
detailFromScreenId sc ws = fmap screenRect maybeSD where
|
||||
c = current ws
|
||||
v = visible ws
|
||||
mapping = map (\s -> (screen s, screenDetail s)) (c:v)
|
||||
maybeSD = lookup sc mapping
|
||||
|
||||
-- | @dzen str timeout@ pipes @str@ to dzen2 for @timeout@ microseconds.
|
||||
-- Example usage:
|
||||
--
|
||||
-- > dzen "Hi, mom!" (5 `seconds`)
|
||||
dzen :: String -> Int -> X ()
|
||||
dzen str timeout = dzenWithArgs str [] timeout
|
||||
dzen = flip (dzenConfig . timeoutMicro)
|
||||
|
||||
-- | @dzen str args timeout@ pipes @str@ to dzen2 for @timeout@ seconds, passing @args@ to dzen.
|
||||
-- Example usage:
|
||||
--
|
||||
-- > dzenWithArgs "Hi, dons!" ["-ta", "r"] (5 `seconds`)
|
||||
dzenWithArgs :: String -> [String] -> Int -> X ()
|
||||
dzenWithArgs str args timeout = io $ runProcessWithInputAndWait "dzen2" args (unchomp str) timeout
|
||||
-- dzen seems to require the input to terminate with exactly one newline.
|
||||
where unchomp s@['\n'] = s
|
||||
unchomp [] = ['\n']
|
||||
unchomp (c:cs) = c : unchomp cs
|
||||
dzenWithArgs str args t = dzenConfig (timeoutMicro t >=> addArgs args) str
|
||||
|
||||
-- | @dzenScreen sc str timeout@ pipes @str@ to dzen2 for @timeout@ microseconds, and on screen @sc@.
|
||||
-- Requires dzen to be compiled with Xinerama support.
|
||||
dzenScreen :: ScreenId -> String -> Int -> X()
|
||||
dzenScreen sc str timeout = dzenWithArgs str ["-xs", screen] timeout
|
||||
where screen = toXineramaArg sc
|
||||
toXineramaArg n = show ( ((fromIntegral n)+1)::Int )
|
||||
dzenScreen :: ScreenId -> String -> Int -> X ()
|
||||
dzenScreen sc str t = dzenConfig (timeoutMicro t >=> xScreen sc) str
|
||||
|
@@ -27,7 +27,9 @@ module XMonad.Util.EZConfig (
|
||||
-- * Emacs-style keybinding specifications
|
||||
|
||||
mkKeymap, checkKeymap,
|
||||
mkNamedKeymap
|
||||
mkNamedKeymap,
|
||||
|
||||
parseKey -- used by XMonad.Util.Paste
|
||||
) where
|
||||
|
||||
import XMonad
|
||||
|
116
XMonad/Util/ExtensibleState.hs
Normal file
116
XMonad/Util/ExtensibleState.hs
Normal file
@@ -0,0 +1,116 @@
|
||||
-----------------------------------------------------------------------------
|
||||
-- |
|
||||
-- Module : XMonad.Util.ExtensibleState
|
||||
-- Copyright : (c) Daniel Schoepe 2009
|
||||
-- License : BSD3-style (see LICENSE)
|
||||
--
|
||||
-- Maintainer : daniel.schoepe@gmail.com
|
||||
-- Stability : unstable
|
||||
-- Portability : not portable
|
||||
--
|
||||
-- Module for storing custom mutable state in xmonad.
|
||||
--
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
module XMonad.Util.ExtensibleState (
|
||||
-- * Usage
|
||||
-- $usage
|
||||
put
|
||||
, modify
|
||||
, remove
|
||||
, get
|
||||
, gets
|
||||
) where
|
||||
|
||||
import Data.Typeable (typeOf,Typeable,cast)
|
||||
import qualified Data.Map as M
|
||||
import XMonad.Core
|
||||
import qualified Control.Monad.State as State
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- $usage
|
||||
--
|
||||
-- To utilize this feature in a contrib module create a data type,
|
||||
-- and make it an instance of ExtensionClass. You can then use
|
||||
-- the functions from this module for storing your data:
|
||||
--
|
||||
-- > {-# LANGUAGE DeriveDataTypeable #-}
|
||||
-- > import qualified XMonad.Util.ExtensibleState as XS
|
||||
-- >
|
||||
-- > data ListStorage = ListStorage [Integer] deriving Typeable
|
||||
-- > instance ExtensionClass ListStorage where
|
||||
-- > initialValue = ListStorage []
|
||||
-- >
|
||||
-- > .. XS.put (ListStorage [23,42])
|
||||
--
|
||||
-- To retrieve the stored data call:
|
||||
--
|
||||
-- > .. XS.get
|
||||
--
|
||||
-- If the type can't be infered from the usage of the retrieved data, you
|
||||
-- might need to add an explicit type signature:
|
||||
--
|
||||
-- > .. XS.get :: X ListStorage
|
||||
--
|
||||
-- To make your data persistent between restarts, the data type needs to be
|
||||
-- an instance of Read and Show and the instance declaration has to be changed:
|
||||
--
|
||||
-- > data ListStorage = ListStorage [Integer] deriving (Typeable,Read,Show)
|
||||
-- >
|
||||
-- > instance ExtensionClass ListStorage where
|
||||
-- > initialValue = ListStorage []
|
||||
-- > extensionType = PersistentExtension
|
||||
--
|
||||
-- One should take care that the string representation of the chosen type
|
||||
-- is unique among the stored values, otherwise it will be overwritten.
|
||||
-- Normally these values contain fully qualified module names when deriving Typeable, so
|
||||
-- name collisions should not be a problem in most cases.
|
||||
-- A module should not try to store common datatypes(e.g. a list of Integers)
|
||||
-- without a custom data type as a wrapper to avoid those collisions.
|
||||
--
|
||||
|
||||
-- | Modify the map of state extensions by applying the given function.
|
||||
modifyStateExts :: (M.Map String (Either String StateExtension)
|
||||
-> M.Map String (Either String StateExtension))
|
||||
-> X ()
|
||||
modifyStateExts f = State.modify $ \st -> st { extensibleState = f (extensibleState st) }
|
||||
|
||||
-- | Apply a function to a stored value of the matching type or the initial value if there
|
||||
-- is none.
|
||||
modify :: ExtensionClass a => (a -> a) -> X ()
|
||||
modify f = put . f =<< get
|
||||
|
||||
-- | Add a value to the extensible state field. A previously stored value with the same
|
||||
-- type will be overwritten. (More precisely: A value whose string representation of its type
|
||||
-- is equal to the new one's)
|
||||
put :: ExtensionClass a => a -> X ()
|
||||
put v = modifyStateExts . M.insert (show . typeOf $ v) . Right . extensionType $ v
|
||||
|
||||
-- | Try to retrieve a value of the requested type, return an initial value if there is no such value.
|
||||
get :: ExtensionClass a => X a
|
||||
get = getState' undefined -- `trick' to avoid needing -XScopedTypeVariables
|
||||
where toValue val = maybe initialValue id $ cast val
|
||||
getState' :: ExtensionClass a => a -> X a
|
||||
getState' k = do
|
||||
v <- State.gets $ M.lookup (show . typeOf $ k) . extensibleState
|
||||
case v of
|
||||
Just (Right (StateExtension val)) -> return $ toValue val
|
||||
Just (Right (PersistentExtension val)) -> return $ toValue val
|
||||
Just (Left str) -> case extensionType (undefined `asTypeOf` k) of
|
||||
PersistentExtension x -> do
|
||||
let val = maybe initialValue id $
|
||||
cast =<< safeRead str `asTypeOf` (Just x)
|
||||
put (val `asTypeOf` k)
|
||||
return val
|
||||
_ -> return $ initialValue
|
||||
_ -> return $ initialValue
|
||||
safeRead str = case reads str of
|
||||
[(x,"")] -> Just x
|
||||
_ -> Nothing
|
||||
|
||||
gets :: ExtensionClass a => (a -> b) -> X b
|
||||
gets = flip fmap get
|
||||
|
||||
-- | Remove the value from the extensible state field that has the same type as the supplied argument
|
||||
remove :: ExtensionClass a => a -> X ()
|
||||
remove wit = modifyStateExts $ M.delete (show . typeOf $ wit)
|
@@ -143,7 +143,8 @@ textExtentsXMF (Xft xftfont) _ = io $ do
|
||||
#endif
|
||||
|
||||
-- | String position
|
||||
data Align = AlignCenter | AlignRight | AlignLeft
|
||||
data Align = AlignCenter | AlignRight | AlignLeft | AlignRightOffset Int
|
||||
deriving (Show, Read)
|
||||
|
||||
-- | Return the string x and y 'Position' in a 'Rectangle', given a
|
||||
-- 'FontStruct' and the 'Align'ment
|
||||
@@ -156,6 +157,7 @@ stringPosition dpy fs (Rectangle _ _ w h) al s = do
|
||||
AlignCenter -> fi (w `div` 2) - fi (width `div` 2)
|
||||
AlignLeft -> 1
|
||||
AlignRight -> fi (w - (fi width + 1));
|
||||
AlignRightOffset offset -> fi (w - (fi width + 1)) - fi offset;
|
||||
return (x,y)
|
||||
|
||||
printStringXMF :: (Functor m, MonadIO m) => Display -> Drawable -> XMonadFont -> GC -> String -> String
|
||||
|
@@ -254,7 +254,7 @@ fixedWidthL a str n logger = do
|
||||
case a of
|
||||
AlignCenter -> toL (take n $ padhalf l ++ l ++ cs)
|
||||
AlignRight -> toL (reverse (take n $ reverse l ++ cs))
|
||||
AlignLeft -> toL (take n $ l ++ cs)
|
||||
_ -> toL (take n $ l ++ cs)
|
||||
where
|
||||
toL = return . Just
|
||||
cs = cycle str
|
||||
|
@@ -28,8 +28,11 @@ import Graphics.X11.Xlib.Extras (none, setEventType, setKeyEvent)
|
||||
import Control.Monad.Reader (asks)
|
||||
import XMonad.Operations (withFocused)
|
||||
import Data.Char (isUpper)
|
||||
import Data.Maybe (listToMaybe)
|
||||
import Graphics.X11.Xlib.Misc (stringToKeysym)
|
||||
import XMonad.Util.XSelection (getSelection)
|
||||
import XMonad.Util.EZConfig (parseKey)
|
||||
import Text.ParserCombinators.ReadP (readP_to_S)
|
||||
|
||||
{- $usage
|
||||
|
||||
@@ -70,7 +73,8 @@ pasteString = mapM_ (\x -> if isUpper x then pasteChar shiftMask x else pasteCha
|
||||
have trouble with any 'Char' outside ASCII.
|
||||
-}
|
||||
pasteChar :: KeyMask -> Char -> X ()
|
||||
pasteChar m c = sendKey m $ stringToKeysym [c]
|
||||
pasteChar m c = sendKey m $ maybe (stringToKeysym [c]) fst
|
||||
$ listToMaybe $ readP_to_S parseKey [c]
|
||||
|
||||
sendKey :: KeyMask -> KeySym -> X ()
|
||||
sendKey = (withFocused .) . sendKeyWindow
|
||||
|
80
XMonad/Util/PositionStore.hs
Normal file
80
XMonad/Util/PositionStore.hs
Normal file
@@ -0,0 +1,80 @@
|
||||
{-# LANGUAGE DeriveDataTypeable #-}
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
-- |
|
||||
-- Module : XMonad.Util.PositionStore
|
||||
-- Copyright : (c) Jan Vornberger 2009
|
||||
-- License : BSD3-style (see LICENSE)
|
||||
--
|
||||
-- Maintainer : jan.vornberger@informatik.uni-oldenburg.de
|
||||
-- Stability : unstable
|
||||
-- Portability : not portable
|
||||
--
|
||||
-- A utility module to store information about position and size of a window.
|
||||
-- See "XMonad.Layout.PositionStoreFloat" for a layout that makes use of this.
|
||||
--
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
module XMonad.Util.PositionStore (
|
||||
getPosStore,
|
||||
modifyPosStore,
|
||||
|
||||
posStoreInsert,
|
||||
posStoreMove,
|
||||
posStoreQuery,
|
||||
posStoreRemove
|
||||
) where
|
||||
|
||||
import XMonad
|
||||
import qualified XMonad.Util.ExtensibleState as XS
|
||||
import Graphics.X11.Xlib
|
||||
import Graphics.X11.Types
|
||||
import Data.Typeable
|
||||
import qualified Data.Map as M
|
||||
|
||||
-- Store window positions relative to the upper left screen edge
|
||||
-- and windows sizes as well as positions as fractions of the screen size.
|
||||
-- This way windows can be easily relocated and scaled when switching screens.
|
||||
|
||||
data PositionStore = PS (M.Map Window PosStoreRectangle)
|
||||
deriving (Read,Show,Typeable)
|
||||
data PosStoreRectangle = PSRectangle Double Double Double Double
|
||||
deriving (Read,Show,Typeable)
|
||||
|
||||
instance ExtensionClass PositionStore where
|
||||
initialValue = PS M.empty
|
||||
extensionType = PersistentExtension
|
||||
|
||||
getPosStore :: X (PositionStore)
|
||||
getPosStore = XS.get
|
||||
|
||||
modifyPosStore :: (PositionStore -> PositionStore) -> X ()
|
||||
modifyPosStore = XS.modify
|
||||
|
||||
posStoreInsert :: PositionStore -> Window -> Rectangle -> Rectangle -> PositionStore
|
||||
posStoreInsert (PS posStoreMap) w (Rectangle x y wh ht) (Rectangle srX srY srWh srHt) =
|
||||
let offsetX = x - srX
|
||||
offsetY = y - srY
|
||||
in PS $ M.insert w (PSRectangle (fromIntegral offsetX / fromIntegral srWh)
|
||||
(fromIntegral offsetY / fromIntegral srHt)
|
||||
(fromIntegral wh / fromIntegral srWh)
|
||||
(fromIntegral ht / fromIntegral srHt)) posStoreMap
|
||||
|
||||
posStoreRemove :: PositionStore -> Window -> PositionStore
|
||||
posStoreRemove (PS posStoreMap) w = PS $ M.delete w posStoreMap
|
||||
|
||||
posStoreQuery :: PositionStore -> Window -> Rectangle -> Maybe Rectangle
|
||||
posStoreQuery (PS posStoreMap) w (Rectangle srX srY srWh srHt) = do
|
||||
(PSRectangle x y wh ht) <- M.lookup w posStoreMap
|
||||
let realWh = fromIntegral srWh * wh
|
||||
realHt = fromIntegral srHt * ht
|
||||
realOffsetX = fromIntegral srWh * x
|
||||
realOffsetY = fromIntegral srHt * y
|
||||
return (Rectangle (srX + round realOffsetX) (srY + round realOffsetY)
|
||||
(round realWh) (round realHt))
|
||||
|
||||
posStoreMove :: PositionStore -> Window -> Position -> Position -> Rectangle -> Rectangle -> PositionStore
|
||||
posStoreMove posStore w x y oldSr newSr =
|
||||
case (posStoreQuery posStore w oldSr) of
|
||||
Nothing -> posStore -- not in store, can't move -> do nothing
|
||||
Just (Rectangle _ _ wh ht) -> posStoreInsert posStore w (Rectangle x y wh ht) newSr
|
@@ -51,10 +51,9 @@ import Control.Monad
|
||||
-- For an example usage of 'runProcessWithInputAndWait' see
|
||||
-- "XMonad.Util.Dzen"
|
||||
|
||||
-- | Return output if the command succeeded, otherwise return @()@.
|
||||
-- This corresponds to dmenu's notion of exit code 1 for a canceled invocation.
|
||||
runProcessWithInput :: FilePath -> [String] -> String -> IO String
|
||||
runProcessWithInput cmd args input = do
|
||||
-- | Returns the output.
|
||||
runProcessWithInput :: MonadIO m => FilePath -> [String] -> String -> m String
|
||||
runProcessWithInput cmd args input = io $ do
|
||||
(pin, pout, perr, _) <- runInteractiveProcess cmd args Nothing Nothing
|
||||
hPutStr pin input
|
||||
hClose pin
|
||||
@@ -66,8 +65,8 @@ runProcessWithInput cmd args input = do
|
||||
return output
|
||||
|
||||
-- | Wait is in µs (microseconds)
|
||||
runProcessWithInputAndWait :: FilePath -> [String] -> String -> Int -> IO ()
|
||||
runProcessWithInputAndWait cmd args input timeout = do
|
||||
runProcessWithInputAndWait :: MonadIO m => FilePath -> [String] -> String -> Int -> m ()
|
||||
runProcessWithInputAndWait cmd args input timeout = io $ do
|
||||
forkProcess $ do
|
||||
(pin, pout, perr, _) <- runInteractiveProcess cmd args Nothing Nothing
|
||||
hPutStr pin input
|
||||
@@ -130,8 +129,8 @@ safeRunInTerm :: String -> String -> X ()
|
||||
safeRunInTerm options command = asks (terminal . config) >>= \t -> safeSpawn t [options, " -e " ++ command]
|
||||
|
||||
-- | Launch an external application through the system shell and return a @Handle@ to its standard input.
|
||||
spawnPipe :: String -> IO Handle
|
||||
spawnPipe x = do
|
||||
spawnPipe :: MonadIO m => String -> m Handle
|
||||
spawnPipe x = io $ do
|
||||
(rd, wr) <- createPipe
|
||||
setFdOption wr CloseOnExec True
|
||||
h <- fdToHandle wr
|
||||
@@ -141,4 +140,5 @@ spawnPipe x = do
|
||||
uninstallSignalHandlers
|
||||
dupTo rd stdInput
|
||||
executeFile "/bin/sh" False ["-c", x] Nothing
|
||||
closeFd rd
|
||||
return h
|
||||
|
39
XMonad/Util/SpawnOnce.hs
Normal file
39
XMonad/Util/SpawnOnce.hs
Normal file
@@ -0,0 +1,39 @@
|
||||
{-# LANGUAGE DeriveDataTypeable #-}
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- |
|
||||
-- Module : XMonad.Util.ExtensibleState
|
||||
-- Copyright : (c) Spencer Janssen 2009
|
||||
-- License : BSD3-style (see LICENSE)
|
||||
--
|
||||
-- Maintainer : spencerjanssen@gmail.com
|
||||
-- Stability : unstable
|
||||
-- Portability : not portable
|
||||
--
|
||||
-- A module for spawning a command once, and only once. Useful to start
|
||||
-- status bars and make session settings inside startupHook.
|
||||
--
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
module XMonad.Util.SpawnOnce (spawnOnce) where
|
||||
|
||||
import XMonad
|
||||
import Data.Set as Set
|
||||
import qualified XMonad.Util.ExtensibleState as XS
|
||||
import Control.Monad
|
||||
|
||||
data SpawnOnce = SpawnOnce { unspawnOnce :: (Set String) }
|
||||
deriving (Read, Show, Typeable)
|
||||
|
||||
instance ExtensionClass SpawnOnce where
|
||||
initialValue = SpawnOnce Set.empty
|
||||
extensionType = PersistentExtension
|
||||
|
||||
-- | The first time 'spawnOnce' is executed on a particular command, that
|
||||
-- command is executed. Subsequent invocations for a command do nothing.
|
||||
spawnOnce :: String -> X ()
|
||||
spawnOnce xs = do
|
||||
b <- XS.gets (Set.member xs . unspawnOnce)
|
||||
when (not b) $ do
|
||||
spawn xs
|
||||
XS.modify (SpawnOnce . Set.insert xs . unspawnOnce)
|
@@ -49,15 +49,7 @@ infixr 8 `Or`
|
||||
|
||||
-- | Does given window have this property?
|
||||
hasProperty :: Property -> Window -> X Bool
|
||||
hasProperty (Title s) w = withDisplay $ \d -> fmap (Just s ==) $ io $ fetchName d w
|
||||
hasProperty (Resource s) w = withDisplay $ \d -> fmap ((==) s . resName ) $ io $ getClassHint d w
|
||||
hasProperty (ClassName s) w = withDisplay $ \d -> fmap ((==) s . resClass) $ io $ getClassHint d w
|
||||
hasProperty (Role s) w = withDisplay $ \d -> fmap ((==) (Just s)) $ getStringProperty d w "WM_WINDOW_ROLE"
|
||||
hasProperty (Machine s) w = withDisplay $ \d -> fmap ((==) (Just s)) $ getStringProperty d w "WM_CLIENT_MACHINE"
|
||||
hasProperty (And p1 p2) w = do { r1 <- hasProperty p1 w; r2 <- hasProperty p2 w; return $ r1 && r2 }
|
||||
hasProperty (Or p1 p2) w = do { r1 <- hasProperty p1 w; r2 <- hasProperty p2 w; return $ r1 || r2 }
|
||||
hasProperty (Not p1) w = do { r1 <- hasProperty p1 w; return $ not r1 }
|
||||
hasProperty (Const b) _ = return b
|
||||
hasProperty p w = runQuery (propertyToQuery p) w
|
||||
|
||||
-- | Does the focused window have this property?
|
||||
focusedHasProperty :: Property -> X Bool
|
||||
|
@@ -9,7 +9,7 @@ Stability : unstable
|
||||
Portability : unportable
|
||||
|
||||
A module for accessing and manipulating X Window's mouse selection (the buffer used in copy and pasting).
|
||||
'getSelection' and 'putSelection' are adaptations of Hxsel.hs and Hxput.hs from the XMonad-utils, available:
|
||||
'getSelection' is an adaptation of Hxsel.hs and Hxput.hs from the XMonad-utils, available:
|
||||
|
||||
> $ darcs get <http://gorgias.mine.nu/repos/xmonad-utils>
|
||||
-}
|
||||
@@ -20,13 +20,10 @@ module XMonad.Util.XSelection ( -- * Usage
|
||||
promptSelection,
|
||||
safePromptSelection,
|
||||
transformPromptSelection,
|
||||
transformSafePromptSelection,
|
||||
putSelection) where
|
||||
transformSafePromptSelection) where
|
||||
|
||||
import Control.Concurrent (forkIO)
|
||||
import Control.Exception as E (catch)
|
||||
import Control.Monad(Monad (return, (>>)), Functor(..), liftM, join)
|
||||
import Data.Char (ord)
|
||||
import Data.Maybe (fromMaybe)
|
||||
import XMonad
|
||||
import XMonad.Util.Run (safeSpawn, unsafeSpawn)
|
||||
@@ -81,43 +78,6 @@ getSelection = io $ do
|
||||
return $ decode . map fromIntegral . fromMaybe [] $ res
|
||||
else destroyWindow dpy win >> return ""
|
||||
|
||||
-- | Set the current X Selection to a specified string.
|
||||
putSelection :: MonadIO m => String -> m ()
|
||||
putSelection text = io $ do
|
||||
dpy <- openDisplay ""
|
||||
let dflt = defaultScreen dpy
|
||||
rootw <- rootWindow dpy dflt
|
||||
win <- createSimpleWindow dpy rootw 0 0 1 1 0 0 0
|
||||
p <- internAtom dpy "PRIMARY" True
|
||||
ty <- internAtom dpy "UTF8_STRING" False
|
||||
xSetSelectionOwner dpy p win currentTime
|
||||
winOwn <- xGetSelectionOwner dpy p
|
||||
if winOwn == win
|
||||
then do forkIO ((allocaXEvent $ processEvent dpy ty text) >> destroyWindow dpy win) >> return ()
|
||||
else do putStrLn "Unable to obtain ownership of the selection" >> destroyWindow dpy win
|
||||
return ()
|
||||
where
|
||||
processEvent :: Display -> Atom -> [Char] -> XEventPtr -> IO ()
|
||||
processEvent dpy ty txt e = do
|
||||
nextEvent dpy e
|
||||
ev <- getEvent e
|
||||
if ev_event_type ev == selectionRequest
|
||||
then do print ev
|
||||
allocaXEvent $ \replyPtr -> do
|
||||
changeProperty8 (ev_event_display ev)
|
||||
(ev_requestor ev)
|
||||
(ev_property ev)
|
||||
ty
|
||||
propModeReplace
|
||||
(map (fromIntegral . ord) txt)
|
||||
setSelectionNotify replyPtr (ev_requestor ev) (ev_selection ev)
|
||||
(ev_target ev) (ev_property ev) (ev_time ev)
|
||||
sendEvent dpy (ev_requestor ev) False noEventMask replyPtr
|
||||
sync dpy False
|
||||
else do putStrLn "Unexpected Message Received"
|
||||
print ev
|
||||
processEvent dpy ty text e
|
||||
|
||||
{- | A wrapper around 'getSelection'. Makes it convenient to run a program with the current selection as an argument.
|
||||
This is convenient for handling URLs, in particular. For example, in your Config.hs you could bind a key to
|
||||
@promptSelection \"firefox\"@;
|
||||
|
@@ -103,7 +103,8 @@ paintWindow :: Window -- ^ The window where to draw
|
||||
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
|
||||
-- | Fill a window with a rectangle and a border, and write
|
||||
-- | a number of strings to given positions
|
||||
paintAndWrite :: Window -- ^ The window where to draw
|
||||
-> XMonadFont -- ^ XMonad Font for drawing
|
||||
-> Dimension -- ^ Window width
|
||||
@@ -113,19 +114,20 @@ paintAndWrite :: Window -- ^ The window where to draw
|
||||
-> String -- ^ Border color
|
||||
-> String -- ^ String color
|
||||
-> String -- ^ String background color
|
||||
-> Align -- ^ String 'Align'ment
|
||||
-> String -- ^ String to be printed
|
||||
-> [Align] -- ^ String 'Align'ments
|
||||
-> [String] -- ^ Strings to be printed
|
||||
-> X ()
|
||||
paintAndWrite w fs wh ht bw bc borc ffc fbc al str = do
|
||||
paintAndWrite w fs wh ht bw bc borc ffc fbc als strs = do
|
||||
d <- asks display
|
||||
(x,y) <- stringPosition d fs (Rectangle 0 0 wh ht) al str
|
||||
paintWindow' w (Rectangle x y wh ht) bw bc borc ms
|
||||
where ms = Just (fs,ffc,fbc,str)
|
||||
strPositions <- forM (zip als strs) $ \(al, str) ->
|
||||
stringPosition d fs (Rectangle 0 0 wh ht) al str
|
||||
let ms = Just (fs,ffc,fbc, zip strs strPositions)
|
||||
paintWindow' w (Rectangle 0 0 wh ht) bw bc borc ms
|
||||
|
||||
-- This stuff is not exported
|
||||
|
||||
paintWindow' :: Window -> Rectangle -> Dimension -> String -> String -> Maybe (XMonadFont,String,String,String) -> X ()
|
||||
paintWindow' win (Rectangle x y wh ht) bw color b_color str = do
|
||||
paintWindow' :: Window -> Rectangle -> Dimension -> String -> String -> Maybe (XMonadFont,String,String,[(String, (Position, Position))]) -> X ()
|
||||
paintWindow' win (Rectangle _ _ wh ht) bw color b_color strStuff = do
|
||||
d <- asks display
|
||||
p <- io $ createPixmap d win wh ht (defaultDepthOfScreen $ defaultScreenOfDisplay d)
|
||||
gc <- io $ createGC d p
|
||||
@@ -138,9 +140,10 @@ paintWindow' win (Rectangle x y wh ht) bw color b_color str = do
|
||||
-- and now again
|
||||
io $ setForeground d gc color'
|
||||
io $ fillRectangle d p gc (fi bw) (fi bw) (wh - (bw * 2)) (ht - (bw * 2))
|
||||
when (isJust str) $ do
|
||||
let (xmf,fc,bc,s) = fromJust str
|
||||
printStringXMF d p xmf gc fc bc x y s
|
||||
when (isJust strStuff) $ do
|
||||
let (xmf,fc,bc,strAndPos) = fromJust strStuff
|
||||
forM_ strAndPos $ \(s, (x, y)) ->
|
||||
printStringXMF d p xmf gc fc bc x y s
|
||||
-- copy the pixmap over the window
|
||||
io $ copyArea d p win gc 0 0 wh ht 0 0
|
||||
-- free the pixmap and GC
|
||||
|
34
scripts/xmonadpropread.hs
Normal file
34
scripts/xmonadpropread.hs
Normal file
@@ -0,0 +1,34 @@
|
||||
-- Copyright Spencer Janssen <spencerjanssen@gmail.com>
|
||||
-- BSD3 (see LICENSE)
|
||||
--
|
||||
-- Experimental, will add proper documentation later (famous last words)
|
||||
|
||||
import Control.Monad
|
||||
import Graphics.X11
|
||||
import Graphics.X11.Xlib.Extras
|
||||
import Codec.Binary.UTF8.String as UTF8
|
||||
import Foreign.C (CChar)
|
||||
import System.IO
|
||||
|
||||
main = do
|
||||
hSetBuffering stdout LineBuffering
|
||||
|
||||
d <- openDisplay ""
|
||||
xlog <- internAtom d "_XMONAD_LOG" False
|
||||
|
||||
root <- rootWindow d (defaultScreen d)
|
||||
selectInput d root propertyChangeMask
|
||||
|
||||
allocaXEvent $ \ep -> forever $ do
|
||||
nextEvent d ep
|
||||
e <- getEvent ep
|
||||
case e of
|
||||
PropertyEvent { ev_atom = a } | a == xlog -> do
|
||||
mwp <- getWindowProperty8 d xlog root
|
||||
maybe (return ()) (putStrLn . decodeCChar) mwp
|
||||
_ -> return ()
|
||||
|
||||
return ()
|
||||
|
||||
decodeCChar :: [CChar] -> String
|
||||
decodeCChar = UTF8.decode . map fromIntegral
|
@@ -1,5 +1,5 @@
|
||||
name: xmonad-contrib
|
||||
version: 0.9
|
||||
version: 0.9.1
|
||||
homepage: http://xmonad.org/
|
||||
synopsis: Third party extensions for xmonad
|
||||
description:
|
||||
@@ -49,7 +49,7 @@ library
|
||||
extensions: ForeignFunctionInterface
|
||||
cpp-options: -DXFT
|
||||
|
||||
build-depends: mtl, unix, X11>=1.4.6.1, xmonad>=0.9, xmonad<1, utf8-string
|
||||
build-depends: mtl, unix, X11>=1.5.0.0 && < 1.6, xmonad>=0.9.1, xmonad<0.10, utf8-string
|
||||
ghc-options: -fwarn-tabs -Wall
|
||||
extensions: ForeignFunctionInterface
|
||||
|
||||
@@ -63,6 +63,7 @@ library
|
||||
XMonad.Doc.Configuring
|
||||
XMonad.Doc.Extending
|
||||
XMonad.Doc.Developing
|
||||
XMonad.Actions.BluetileCommands
|
||||
XMonad.Actions.Commands
|
||||
XMonad.Actions.ConstrainedResize
|
||||
XMonad.Actions.CopyWindow
|
||||
@@ -89,8 +90,8 @@ library
|
||||
XMonad.Actions.PhysicalScreens
|
||||
XMonad.Actions.Plane
|
||||
XMonad.Actions.Promote
|
||||
XMonad.Actions.RotSlaves
|
||||
XMonad.Actions.RandomBackground
|
||||
XMonad.Actions.RotSlaves
|
||||
XMonad.Actions.Search
|
||||
XMonad.Actions.SimpleDate
|
||||
XMonad.Actions.SinkAll
|
||||
@@ -99,23 +100,25 @@ library
|
||||
XMonad.Actions.SwapWorkspaces
|
||||
XMonad.Actions.TagWindows
|
||||
XMonad.Actions.TopicSpace
|
||||
XMonad.Actions.UpdatePointer
|
||||
XMonad.Actions.UpdateFocus
|
||||
XMonad.Actions.UpdatePointer
|
||||
XMonad.Actions.Warp
|
||||
XMonad.Actions.WindowBringer
|
||||
XMonad.Actions.WindowGo
|
||||
XMonad.Actions.WindowMenu
|
||||
XMonad.Actions.WindowNavigation
|
||||
XMonad.Actions.WindowGo
|
||||
XMonad.Actions.WindowBringer
|
||||
XMonad.Actions.WithAll
|
||||
XMonad.Actions.WorkspaceCursors
|
||||
XMonad.Config.Arossato
|
||||
XMonad.Config.Azerty
|
||||
XMonad.Config.Bluetile
|
||||
XMonad.Config.Desktop
|
||||
XMonad.Config.Droundy
|
||||
XMonad.Config.Gnome
|
||||
XMonad.Config.Kde
|
||||
XMonad.Config.Sjanssen
|
||||
XMonad.Config.Xfce
|
||||
XMonad.Hooks.CurrentWorkspaceOnTop
|
||||
XMonad.Hooks.DynamicHooks
|
||||
XMonad.Hooks.DynamicLog
|
||||
XMonad.Hooks.EwmhDesktops
|
||||
@@ -125,10 +128,11 @@ library
|
||||
XMonad.Hooks.ManageDocks
|
||||
XMonad.Hooks.ManageHelpers
|
||||
XMonad.Hooks.Place
|
||||
XMonad.Hooks.PositionStoreHooks
|
||||
XMonad.Hooks.RestoreMinimized
|
||||
XMonad.Hooks.Script
|
||||
XMonad.Hooks.SetWMName
|
||||
XMonad.Hooks.ServerMode
|
||||
XMonad.Hooks.SetWMName
|
||||
XMonad.Hooks.UrgencyHook
|
||||
XMonad.Hooks.WorkspaceByPos
|
||||
XMonad.Hooks.XPropManage
|
||||
@@ -136,15 +140,18 @@ library
|
||||
XMonad.Layout.AutoMaster
|
||||
XMonad.Layout.BorderResize
|
||||
XMonad.Layout.BoringWindows
|
||||
XMonad.Layout.ButtonDecoration
|
||||
XMonad.Layout.CenteredMaster
|
||||
XMonad.Layout.Circle
|
||||
XMonad.Layout.Cross
|
||||
XMonad.Layout.Column
|
||||
XMonad.Layout.Combo
|
||||
XMonad.Layout.ComboP
|
||||
XMonad.Layout.Cross
|
||||
XMonad.Layout.Decoration
|
||||
XMonad.Layout.DecorationAddons
|
||||
XMonad.Layout.DecorationMadness
|
||||
XMonad.Layout.Dishes
|
||||
XMonad.Layout.DraggingVisualizer
|
||||
XMonad.Layout.DragPane
|
||||
XMonad.Layout.DwmStyle
|
||||
XMonad.Layout.FixedColumn
|
||||
@@ -171,6 +178,7 @@ library
|
||||
XMonad.Layout.Mosaic
|
||||
XMonad.Layout.MosaicAlt
|
||||
XMonad.Layout.MouseResizableTile
|
||||
XMonad.Layout.MultiColumns
|
||||
XMonad.Layout.MultiToggle
|
||||
XMonad.Layout.MultiToggle.Instances
|
||||
XMonad.Layout.Named
|
||||
@@ -178,37 +186,39 @@ library
|
||||
XMonad.Layout.NoFrillsDecoration
|
||||
XMonad.Layout.OneBig
|
||||
XMonad.Layout.PerWorkspace
|
||||
XMonad.Layout.PositionStoreFloat
|
||||
XMonad.Layout.Reflect
|
||||
XMonad.Layout.ResizableTile
|
||||
XMonad.Layout.ResizeScreen
|
||||
XMonad.Layout.Roledex
|
||||
XMonad.Layout.Simplest
|
||||
XMonad.Layout.ShowWName
|
||||
XMonad.Layout.SimpleDecoration
|
||||
XMonad.Layout.SimpleFloat
|
||||
XMonad.Layout.Simplest
|
||||
XMonad.Layout.SimplestFloat
|
||||
XMonad.Layout.Spacing
|
||||
XMonad.Layout.Spiral
|
||||
XMonad.Layout.Square
|
||||
XMonad.Layout.ShowWName
|
||||
XMonad.Layout.StackTile
|
||||
XMonad.Layout.SubLayouts
|
||||
XMonad.Layout.Tabbed
|
||||
XMonad.Layout.TabBarDecoration
|
||||
XMonad.Layout.Tabbed
|
||||
XMonad.Layout.ThreeColumns
|
||||
XMonad.Layout.ToggleLayouts
|
||||
XMonad.Layout.TwoPane
|
||||
XMonad.Layout.WindowArranger
|
||||
XMonad.Layout.WindowNavigation
|
||||
XMonad.Layout.WindowSwitcherDecoration
|
||||
XMonad.Layout.WorkspaceDir
|
||||
XMonad.Layout.SimplestFloat
|
||||
XMonad.Prompt.Directory
|
||||
XMonad.Prompt
|
||||
XMonad.Prompt.AppendFile
|
||||
XMonad.Prompt.AppLauncher
|
||||
XMonad.Prompt.Input
|
||||
XMonad.Prompt.Directory
|
||||
XMonad.Prompt.DirExec
|
||||
XMonad.Prompt.Email
|
||||
XMonad.Prompt.Input
|
||||
XMonad.Prompt.Layout
|
||||
XMonad.Prompt.Man
|
||||
XMonad.Prompt.DirExec
|
||||
XMonad.Prompt.RunOrRaise
|
||||
XMonad.Prompt.Shell
|
||||
XMonad.Prompt.Ssh
|
||||
@@ -220,6 +230,7 @@ library
|
||||
XMonad.Util.CustomKeys
|
||||
XMonad.Util.Dmenu
|
||||
XMonad.Util.Dzen
|
||||
XMonad.Util.ExtensibleState
|
||||
XMonad.Util.EZConfig
|
||||
XMonad.Util.Font
|
||||
XMonad.Util.Invisible
|
||||
@@ -227,15 +238,17 @@ library
|
||||
XMonad.Util.NamedActions
|
||||
XMonad.Util.NamedScratchpad
|
||||
XMonad.Util.NamedWindows
|
||||
XMonad.Util.StringProp
|
||||
XMonad.Util.Paste
|
||||
XMonad.Util.PositionStore
|
||||
XMonad.Util.Replace
|
||||
XMonad.Util.Run
|
||||
XMonad.Util.Scratchpad
|
||||
XMonad.Util.SpawnOnce
|
||||
XMonad.Util.StringProp
|
||||
XMonad.Util.Themes
|
||||
XMonad.Util.Timer
|
||||
XMonad.Util.Types
|
||||
XMonad.Util.WindowProperties
|
||||
XMonad.Util.WorkspaceCompare
|
||||
XMonad.Util.Paste
|
||||
XMonad.Util.Replace
|
||||
XMonad.Util.XSelection
|
||||
XMonad.Util.XUtils
|
||||
|
Reference in New Issue
Block a user