89 Commits
v0.9 ... v0.9.1

Author SHA1 Message Date
Spencer Janssen
103d633e41 TAG 0.9.1 2009-12-16 23:36:51 +00:00
Spencer Janssen
d7cac6d70c Bump version to 0.9.1 2009-12-16 23:26:34 +00:00
Spencer Janssen
e806fe9bc8 Match X11 dependencies with xmonad's 2009-12-16 01:26:30 +00:00
Spencer Janssen
d451c277f6 Safer X11 version dependency 2009-12-16 00:59:16 +00:00
Spencer Janssen
cdae01dfdb Update Prompt for numlockMask changes 2009-11-03 22:26:21 +00:00
Tomas Janousek
5c2aa04175 X.L.MouseResizableTile: change description for mirrored variant
The description for mirrored MouseResizableTile is now "Mirror
MouseResizableTile", to follow the standard of other layouts that can be
mirrored using the Mirror modifier.
2009-12-11 12:42:18 +00:00
Tomas Janousek
1d6a171dd2 X.A.GridSelect: documentation typo fix
spotted by Justin on IRC
2009-12-11 18:25:15 +00:00
Adam Vogt
e8cfb696ad A.GridSelect shouldn't grab keys if there are no choices.
Thanks thermal2008 in #xmonad for bringing up the corner case when gridselect
is run with an empty list of choices.
2009-12-10 18:30:38 +00:00
Nils Schweinsberg
9464b32395 onScreen' variation for X () functions 2009-12-09 00:37:17 +00:00
Jan Vornberger
f46873fdab Added Bluetile's config 2009-12-09 15:03:09 +00:00
Jan Vornberger
c729dac32e BluetileCommands - a list of commands that Bluetile uses to communicate with its dock 2009-12-08 23:44:31 +00:00
Adam Vogt
84a8e42ac0 Use lookup instead of find in A.PerWorkspaceKeys 2009-11-29 03:26:50 +00:00
Nils Schweinsberg
de3cafec0d Change of X.A.OnScreen, more simple and predictable behaviour of onScreen, new functions: toggle(Greedy)OnScreen 2009-12-07 15:50:50 +00:00
Jan Vornberger
bfb5fc7384 Module to ensure that a dragged window always stays in front of all other windows 2009-11-29 00:45:06 +00:00
Jan Vornberger
b2fa3f3e80 Decoration that allows to switch the position of windows by dragging them onto each other. 2009-11-29 00:34:31 +00:00
Jan Vornberger
2ca7de8b08 A decoration with small buttons and a supporting module 2009-11-29 00:24:16 +00:00
gwern0
8fa0319e89 XMonad.Actions.Search: finally fixed the internet archive search plugin 2009-12-05 03:34:35 +00:00
gwern0
8e8962909b XMonad.Actions.Search: in retrospect, a bit silly to make everyone go through SSL 2009-12-05 03:33:18 +00:00
Tim Horton
1dc74c3879 Prompt.hs: Corrected quit keybindings 2009-12-03 05:00:41 +00:00
Jan Vornberger
bcb204731f Extended decoration module with more hooks and consolidated some existing ones 2009-11-28 23:43:10 +00:00
Jan Vornberger
c92b8b3e9e Extended decoration theme to contain extra static text that always appears in the title bar 2009-10-24 21:39:28 +00:00
Jan Vornberger
be4feb98d6 Extended paintAndWrite to allow for multiple strings to be written into the rectangle 2009-10-24 20:51:11 +00:00
Jan Vornberger
c38912b991 Added the alignment option 'AlignRightOffset' 2009-10-24 20:45:13 +00:00
Jan Vornberger
79e7a8210a Prevent windows from being decorated that are too small to contain decoration. 2009-06-27 09:43:16 +00:00
Tomas Janousek
02063ff97e X.L.MouseResizableTile: keep draggers on the bottom of the window stack. 2009-11-26 17:34:13 +00:00
Jan Vornberger
c198812fb6 Implemented smarter system of managing borders for BorderResize 2009-11-22 23:36:51 +00:00
Tomas Janousek
e2c5fa876a X.H.DynamicLog: fix xmonadPropLog double-encoding of UTF-8
dynamicLogString utf-8 encodes its output, xmonadPropLog shouldn't do that
again.
2009-11-21 00:48:29 +00:00
Brent Yorgey
70d5cedcc5 X.H.DynamicLog: make documentation for 'dzen' and 'xmobar' slightly more clear 2009-11-21 17:07:39 +00:00
Tomas Janousek
82a0d30f31 X.H.ManageDocks: ignore struts that cover an entire screen on that screen
Imagine a screen layout like this:

  11111111
  11111111
  11111111
   222222    <--- xmobar here
   222222
   222222

When placing xmobar as indicated, the partial strut property indicates that an
entire height of screen 1 is covered by the strut, as well as a few lines at
the top of screen 2. The original code would create a screen rectangle of
negative height and wreak havoc. This patch causes such strut to be ignored on
the screen it covers entirely, resulting in the desired behaviour of a small
strut at the top of screen 2.

Please note that this semantics of _NET_WM_STRUT and _NET_WM_STRUT_PARTIAL is
different to what is in wm-spec. The "correct" thing to do would be to discard
the covered portion of screen 1 leaving two narrow areas at the sides, but
this new behaviour is probably more desirable in many cases, at least for
xmonad/xmobar users.

The correct solution of having separate _NET_WM_STRUT_PARTIAL for each
Xinerama screen was mentioned in wm-spec maillist in 2007, but has never
really been proposed, discussed and included in wm-spec. Hence this "hack".
2009-11-19 14:50:43 +00:00
Adam Vogt
46fca2c6c9 Use imported 'fi' in PositionStoreHooks 2009-11-19 10:31:12 +00:00
Daniel Schoepe
30a78d51e3 Changed interface of X.U.ExtensibleState
Changed the interface of X.U.ExtensibleState to resemble that of
Control.Monad.State and modified the modules that use it accordingly.
2009-11-16 17:10:13 +00:00
Jan Vornberger
b881934a02 PositionStoreFloat - a floating layout with support hooks 2009-11-15 18:48:33 +00:00
Jan Vornberger
6a8e6af48f PositionStore utility to store information about position and size of a window 2009-11-08 19:57:35 +00:00
Anders Engstrom
addb6a99e1 X.H.Urgencyhook fix minor doc bug 2009-11-15 13:11:21 +00:00
Anders Engstrom
5d341e8e99 X.H.DynamicLog fix minor indentation oddness 2009-11-15 13:07:07 +00:00
Anders Engstrom
5463e04b94 X.A.CycleWS cycle by tag group
Allow grouping of workspaces, so that a user can cycle through those in the same group. Grouping is done by using a special character in the tag.
2009-11-15 13:02:17 +00:00
Adam Vogt
b4acd87c7a Use less short names in X.Prompt 2009-11-15 02:56:47 +00:00
Adam Vogt
aa6f4882a4 Use io instead of liftIO in Prompt 2009-11-15 02:53:01 +00:00
Adam Vogt
ff11ae70a0 'io' and 'fi' are defined outside of Prompt 2009-11-15 02:40:01 +00:00
Adam Vogt
9cdcb7185f Use zipWithM_ instead of recursion in Prompt.printComplList 2009-11-15 02:34:51 +00:00
Adam Vogt
4f97bc02ce Minor style changes in DynamicWorkspaces 2009-11-15 02:27:51 +00:00
Anders Engstrom
b3329397c0 X.A.DynamicWorkspaces fix doc and add behaviour
Before this patch the documentation claims that it won't do anything on non-empty workspaces when it actually does. This patch fixes the documentation to reflect the actual behaviour, but also adds the behaviour promised by the documentation in other functions. It does not break configs. In addition it also provides functions to help removing empty workspaces when leaving them.
2009-11-13 23:39:03 +00:00
daniel
cb684763ce rework XMonad.Util.Dzen 2009-11-14 05:15:09 +00:00
daniel
db37e18098 generalize IO actions to MonadIO m => m actions
This should not cause any working configs to stop working, because IO is an instance of MonadIO, and because complete configs will pin down the type of the call to IO.  Note that XMonad.Config.Arossato is not a complete config, and so it needed some tweaks; with a main function, this should not be a problem.
2009-11-14 02:36:16 +00:00
daniel
7c363c82d3 fix documentation to match implementation 2009-11-14 02:13:28 +00:00
Adam Vogt
65d1309cf1 Bypass more of stringToKeysym in U.Paste 2009-11-14 22:37:26 +00:00
Adam Vogt
14f0f6129d Don't erase floating information with H.InsertPosition (Issue 334) 2009-11-13 16:14:02 +00:00
Adam Vogt
8cda47f19f Rename gridselectViewWorkspace to gridselectWorkspace, add another example.
The name should be more general to suggest uses other than just viewing other
workspaces.
2009-11-12 21:14:35 +00:00
Brent Yorgey
fdec915dda X.A.DynamicWorkspaces: fix addWorkspace and friends so they never add another copy of an existing workspace 2009-11-12 20:13:51 +00:00
Adam Vogt
eba5720d30 Trim whitespace in H.FloatNext 2009-11-11 02:27:02 +00:00
Adam Vogt
d606f998bd Use ExtensibleState in H.FloatNext 2009-11-11 02:25:13 +00:00
Adam Vogt
3102a69287 Make a haddock link direct in C.Desktop. 2009-11-11 01:38:10 +00:00
Adam Vogt
8dcd818586 Change A.TopicSpace haddocks to use block quotes. 2009-11-11 01:32:41 +00:00
Adam Vogt
60ae62e4e3 Add defaultTopicConfig, to allow adding more fields to TopicSpace later. 2009-11-11 01:29:15 +00:00
Spencer Janssen
3b82b8755e X.A.WindowGo: fix haddock markup 2009-11-11 00:32:56 +00:00
Daniel Schoepe
e14dcd9aa6 Minor style corrections in X.U.SpawnOnce 2009-11-09 20:15:43 +00:00
Daniel Schoepe
da094a635d Add gridselectViewWorkspace in X.A.GridSelect 2009-11-09 15:58:15 +00:00
`Henrique Abreu
77f916fa26 minor-doc-fix-in-ManageHelpers 2009-11-04 17:27:27 +00:00
Daniel Schoepe
5f4b9e8a19 Set buffering to LineBuffering in scripts/xmonadpropread.hs
(Required for the script to work properly with tools like dzen)
2009-11-08 20:41:06 +00:00
Spencer Janssen
a3fb5f5df1 X.U.ExtensibleState: style 2009-11-08 18:28:58 +00:00
Brent Yorgey
0efee8b0cb X.A.DynamicWorkspaces: new 'addWorkspacePrompt' method 2009-11-08 17:05:03 +00:00
Adam Vogt
71abbe457a Remove defaulting when using NoMonomorphismRestriction in H.EwmhDesktops 2009-11-07 19:52:55 +00:00
Adam Vogt
9cd4fccdc2 Update A.TopicSpace to use extensible state. No config changes required. 2009-11-07 19:45:02 +00:00
Adam Vogt
920bf15e04 Inline tupadd function in A.GridSelect 2009-11-01 19:03:12 +00:00
Spencer Janssen
54acce050f Alphabetize exposed-modules 2009-11-07 17:49:46 +00:00
Spencer Janssen
328fae1468 Use X.U.SpawnOnce in my config 2009-11-07 17:46:15 +00:00
Spencer Janssen
df7ac47317 Add XMonad.Util.SpawnOnce 2009-11-07 17:38:20 +00:00
Daniel Schoepe
86f6b327ae Store deserialized data after reading in X.U.ExtensibleState 2009-11-07 10:38:32 +00:00
Daniel Schoepe
8ec090cfbf Fixed conflict between X.U.ExtensibleState and X.C.Sjanssen 2009-11-07 10:36:19 +00:00
Daniel Schoepe
fa476549c2 Use X.U.ExtensibleState instead of IORefs
This patch changes SpawnOn, DynamicHooks and UrgencyHooks to
use X.U.ExtensibleState instead of IORefs. This simplifies the
usage of those modules thus also breaking current configs.
2009-11-06 11:56:01 +00:00
Daniel Schoepe
f71fdefdc7 Add X.U.ExtensibleState 2009-11-06 11:53:36 +00:00
Spencer Janssen
97a36b49a5 My config uses xmonadPropLog now 2009-11-07 00:52:30 +00:00
Spencer Janssen
1a8bdd4320 Add xmonadpropread script 2009-11-07 00:48:58 +00:00
Spencer Janssen
3f6787be4f Add experimental xmonadPropLog function 2009-11-07 00:46:24 +00:00
gwern0
2edac2fc13 XMonad.Actions.Search: imdb search URL tweak for bug #33 2009-11-03 22:23:30 +00:00
Adam Vogt
9f66ef9975 Clean imports for L.BoringWindows 2009-11-03 14:06:49 +00:00
Adam Vogt
4769530d9f I maintain L.BoringWindows 2009-11-03 14:05:09 +00:00
Tomas Janousek
bfdfb2297e fix window rectangle calculation in X.A.UpdatePointer 2009-10-26 15:49:18 +00:00
Adam Vogt
9180666302 Implement hasProperty in terms of runQuery in U.WindowProperties
This addresses issue 302 for unicode titles by actually using the complicated
XMonad.ManageHook.title code, instead of reimplementing it with stringProperty
(which doesn't appear to handle unicode).
2009-10-31 15:49:45 +00:00
Daniel Schoepe
9159b17cc8 Add functions to access the current input in X.Prompt 2009-10-30 23:50:33 +00:00
Spencer Janssen
41deac6194 Remove putSelection, fixes #317 2009-10-30 22:43:54 +00:00
Adam Vogt
a64d55f618 Fix typo in H.FadeInactive documentation 2009-10-29 16:57:36 +00:00
Anders Engstrom
b1ac0b5030 X.L.MultiCol constructor 0 NWin bugfig
Fix bug where the constructor did not accept catch-all columns. Also some minor cleaning.
2009-10-29 10:56:33 +00:00
Ismael Carnales
ccd71d4a15 X.H.ManageHelpers: added currentWs that returns the current workspace 2009-10-28 19:35:19 +00:00
Anders Engstrom
6e84273e03 X.L.MultiColumns bugfix and formating
Fix bug where a column list of insufficient length could be used to find the column of the window. Also fix formating to conform better with standards.
2009-10-27 13:17:41 +00:00
Anders Engstrom
3fd77f5386 X.L.MultiColumns NWin shrinkning fix
Fixed a bug where the list containing the number of windows in each column was allowed the shrink if a column was unused.
2009-10-27 00:59:32 +00:00
Anders Engstrom
95bada8d02 New Layout X.L.MultiColumns
New layout inspired the realization that I was switching between Mirror Tall and Mirror ThreeCol depending on how many windows there were on the workspace. This layout will make those changes automatically.
2009-10-24 17:51:55 +00:00
mail
0b9b98c06b Changing behaviour of ppUrgent with X.H.DynamicLog
Currently, the ppUrgent method is an addition to the ppHidden method.
This doesn't make any sense since it is in fact possible to get urgent
windows on the current and visible screens. So I've raised the ppUrgent
printer to be above ppCurrent/ppVisible and dropped its dependency on
ppHidden.

In addition to that this makes it a lot more easier to define a more
custom ppUrgent printer, since you don't have to "undo" the ppHidden
printer anymore. This also basicly removes the need for dzenStrip,
although I just changed the description.

-- McManiaC / Nils
2009-09-10 01:04:11 +00:00
Tomas Janousek
cdb1e6ef71 fix X.U.Run.spawnPipe fd leak 2009-10-25 21:02:46 +00:00
56 changed files with 2266 additions and 663 deletions

View 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)

View File

@@ -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

View File

@@ -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 }

View File

@@ -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)

View File

@@ -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

View File

@@ -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 ()

View File

@@ -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)]

View File

@@ -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 = "&|;"

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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
View 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"
}

View File

@@ -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.

View File

@@ -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"

View 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)

View File

@@ -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) }

View File

@@ -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

View File

@@ -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

View File

@@ -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"
--

View File

@@ -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

View File

@@ -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

View File

@@ -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?
--

View File

@@ -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

View 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)

View File

@@ -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
_ ->

View File

@@ -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 -> []

View File

@@ -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

View 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 ()

View File

@@ -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 ()

View 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

View 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

View File

@@ -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 ()

View 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

View 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 -> []

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View 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

View File

@@ -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 _ [] = []

View File

@@ -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 ()

View File

@@ -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

View File

@@ -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

View File

@@ -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

View 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)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View 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

View File

@@ -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
View 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)

View File

@@ -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

View File

@@ -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\"@;

View File

@@ -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
View 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

View File

@@ -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