313 Commits
v0.8.1 ... v0.9

Author SHA1 Message Date
Spencer Janssen
6f6e9692c2 Bump version to 0.9 2009-10-26 00:48:50 +00:00
Wirt Wolff
beda65a760 README Update to point to wiki changelog, prettify 2009-10-24 20:35:50 +00:00
Wirt Wolff
79ab1d5de1 Doc namespace minor updates
Most signifigant changes are use unversioned links to external html,
fix a couple of key binding examples, and double quotes that should
have been single.
2009-10-23 18:49:05 +00:00
Wirt Wolff
06a1322366 Docs: use myLayout like template rather than plural
Despite myLayouts currently being more popular in examples, make
them all myLayout as in man/xmonad.hs to avoid mixing them in the
same module as was done a few places, leading to confusion for some users.
2009-10-23 04:26:51 +00:00
Spencer Janssen
5417286d6a Use 'ewmh' in relevant configs 2009-10-23 03:50:43 +00:00
Spencer Janssen
4832f0fc7d Add ewmh function to set all EWMH settings in one step 2009-10-23 03:46:30 +00:00
Adam Vogt
74a03cd8fb Refer to modm as the current modMask
This makes the config suggestions consistent with the current template.
2009-10-22 04:11:26 +00:00
Daniel Schoepe
9f16a427e6 Resolve conflicts between Justin Bogner's C.Desktop patch and latest head. 2009-10-22 11:58:49 +00:00
Justin Bogner
fc1da0d701 Move EWMH support initialization to a startupHook
Set EWMH support atoms and the window manager name in a startup hook,
rather than in the log hook: the log hook occurs far too frequently
for it to make sense to set constants with it.
2009-10-11 05:35:38 +00:00
Wirt Wolff
6e91396fa5 C.Desktop fix bad escaping and typo 2009-10-22 10:01:56 +00:00
Wirt Wolff
0e713d57c1 C.Desktop doc explaining common desktop config customizations
To close http://code.google.com/p/xmonad/issues/detail?id=174
2009-10-22 04:27:48 +00:00
Daniel Schoepe
8f8e650537 Clean keymask in GridSelect(solves issue 318) 2009-10-21 22:34:04 +00:00
Adam Vogt
00bae8bafa Share one StdGen between RGB channels in A.RandomBackground 2009-10-20 16:59:24 +00:00
Adam Vogt
be635001de Document A.RandomBackground 2009-10-20 16:52:05 +00:00
Adam Vogt
3513c8386b Bump X11 dependency to 1.4.6.1, to access cursor definitions. 2009-10-20 16:19:14 +00:00
Wirt Wolff
6d4ad7f431 C.Gnome combine with instead of replace Desktop startupHook
Now that C.Desktop sets startupHook do both rather than only
gnomeRegister.
2009-10-20 09:20:10 +00:00
Adam Vogt
4abbb620a4 Remove H.SetCursor: U.Cursor is preferred 2009-10-19 23:57:22 +00:00
Adam Vogt
37a0dba16e Add some haddock formatting in U.Cursor 2009-10-19 23:30:36 +00:00
Andres Salomon
bcab2509d3 XMonadContrib: set the default cursor to left_ptr for the Desktop config 2009-09-15 16:57:53 +00:00
Andres Salomon
9ac6c9a24d XMonadContrib: add a utility module to set the default cursor
This adds XMonad.Util.Cursor, which defines a function that allows setting
the default mouse cursor.  This can be useful for (for example) gnomeConfig,
to ensure that the root cursor is changed from X_cursor to left_ptr.
2009-09-15 16:56:04 +00:00
Adam Vogt
45db2ebfbe More docs formatting in A.GridSelect 2009-10-16 20:31:32 +00:00
Adam Vogt
721cda38cc In A.GridSelect correct haddocks 2009-10-16 17:11:59 +00:00
Adam Vogt
f655307a1c Describe parameters to subLayouts more 2009-10-16 16:49:37 +00:00
Adam Vogt
8d4c0a5e13 Refer to modMask as modm in L.SubLayouts sample keybinds 2009-10-16 16:47:37 +00:00
Adam Vogt
f61ac3a174 Format L.SubLayout TODO 2009-10-16 15:58:37 +00:00
Adam Vogt
f28f32f7ed Add more links in L.SubLayout documentation 2009-10-16 15:55:18 +00:00
Adam Vogt
0e2aef4deb Link a screenshot in L.SubLayouts from the haskellwiki 2009-10-16 15:05:39 +00:00
Jan Vornberger
41a53e7d15 Added focusMaster to BoringWindows 2009-10-15 23:35:18 +00:00
Adam Vogt
ca29a33f56 Remove NamedFieldPuns from L.LimitWindows
This is more ugly, but otherwise we have lots of trouble for ghc-6.8
compatibility (due to the recomended flag having changed)
2009-10-15 01:01:23 +00:00
Max Rabkin
d330dcae24 added prop_select_two_consec to test_Selective.hs 2009-10-01 15:58:53 +00:00
Adam Vogt
6ef8fd353d Note L.Minimize in L.LimitWindows haddocks. 2009-10-14 20:53:26 +00:00
Max Rabkin
2b31698e15 Move limitSelect into L.LimitWindows 2009-10-14 20:22:13 +00:00
Max Rabkin
79eb2582c4 added haddocks for L.Selective 2009-10-02 11:27:20 +00:00
Max Rabkin
70e968c354 Support IncMasterN in Selective 2009-09-29 17:33:46 +00:00
Max Rabkin
adc029566e removed commented-out code 2009-09-29 16:35:09 +00:00
Max Rabkin
cd43a200bf Test that update preserves invariants of Selection 2009-09-29 16:31:39 +00:00
Max Rabkin
f0e835ebe2 move updateSel from test_Selective into Selective 2009-09-29 16:04:20 +00:00
Max Rabkin
831168d701 Add "Selective" layout modifier 2009-09-29 16:02:07 +00:00
Daniel Schoepe
064f117018 Filter extra modifier bits some layouts set in XMonad.Prompt 2009-10-12 13:28:14 +00:00
Adam Vogt
1edc2752c7 Cleanup L.BorderResize 2009-10-12 05:55:32 +00:00
Jan Vornberger
06998efa45 Layout modifier to resize windows by dragging their borders with the mouse 2009-10-11 22:22:14 +00:00
Adam Vogt
ec87f7d62d Add U.Replace which implements a --replace behavior. 2009-10-12 05:23:06 +00:00
Adam Vogt
5e0a65ea63 Update D.Extending module lists with help of a script (also added) 2009-10-12 04:49:18 +00:00
Adam Vogt
bf36bb785a Correct erroneous haddock link in U.XSelection 2009-10-12 04:31:33 +00:00
Adam Vogt
4b67243cac Make L.Mosaic explicit imports compatible with haskell-src-exts 2009-10-12 04:28:59 +00:00
Adam Vogt
a08fd578ee Put screenshots inline for L.ThreeColumns and L.Roledex 2009-10-12 04:26:51 +00:00
Adam Vogt
3e0be7dd1b Use LANGUAGE pragma instead of -fglasgow-exts in L.Minimize 2009-10-12 04:24:57 +00:00
Adam Vogt
f983084b63 Add a description to L.LayoutScreens 2009-10-12 04:22:31 +00:00
Adam Vogt
dc07d902d9 Add Portability and Stability boilerplate for a couple modules.
Needed for automating the generation of the Doc.Extending module summaries.
2009-10-12 04:10:55 +00:00
Adam Vogt
e0a5d16e40 Correct hyperlink in A.DeManage 2009-10-12 04:03:40 +00:00
Jan Vornberger
97537c8ad3 NoFrillsDecoration - most basic version of decoration for windows 2009-10-11 22:05:12 +00:00
Adam Vogt
a8677c001a Split A.TopicSpace documentation into sections 2009-10-12 00:47:30 +00:00
Adam Vogt
19b55d74a7 Use hyperlinks in WorkspaceCursors documentation. 2009-10-08 03:20:47 +00:00
Adam Vogt
9ba60f1952 Minor haddock formatting correction in L.Tabbed 2009-10-08 02:48:39 +00:00
Adam Vogt
eb10d679e6 Hyperlink the reference to ResizableTile in MouseResizableTile 2009-10-05 17:53:03 +00:00
Adam Vogt
f0925b5a28 Finish a sentence in H.ManageDocks haddocks. 2009-10-05 16:53:12 +00:00
Adam Vogt
63b6d7c225 Add a SetStruts message to H.ManageDocks.
This patch also uses Data.Set instead of [] for the AvoidStruts
constructor to simplify the SetStruts implementation.
2009-10-05 16:42:21 +00:00
Adam Vogt
1ef2eb63b9 Derive Enum for U.Types.Direction2D 2009-10-05 16:31:32 +00:00
Adam Vogt
e9a432298c Rearrange the GSCONFIG class in A.Gridselect 2009-10-05 02:32:27 +00:00
Adam Vogt
4509a8b696 Add a GSCONFIG class to overload defaultGSConfig.
This uses -XOverlappingInstances to provide a fallback instance which uses the
focusedBorderColor and normalBorderColor, but that part is optional.

User's configs should use -XNoMonomorphismRestriction if they want to avoid
writing a type signature for myGSConfig.

Also, type variables become ambiguous in expressions like:

> myGSConfig = defaultGSConfig { gs_navigate = neiu `M.union` gs_navigate defaultGSConfig }
>     where neiu = M.map (\(x,y) (a,b) -> (x+a,y+b)) $ M.fromList
>             [((0,xK_n),(-1,0)) ,((0,xK_e),(0,1)) ,((0,xK_i),(1,0)) ,((0,xK_u),(0,-1))]

But that can be resolved with the appropriate (`asTypeOf`myGSConfig) applied to
the second defaultGSConfig, or the use of some other method for modifying
existing fields.
2009-10-03 19:38:04 +00:00
Adam Vogt
fb7539d74b Add a screenshots section in the A.GridSelect haddocks 2009-10-04 16:08:16 +00:00
Jan Vornberger
ed43c38519 Fixed guard in WorkspaceByPos - condition got switched during transformation 2009-10-04 08:52:32 +00:00
Wirt Wolff
697f387a39 A.CycleWindows update docs, use lib fn second instead of custom lambda 2009-09-26 15:47:00 +00:00
Adam Vogt
0bb00440dc Group functions in GridSelect haddock, add an inline screenshot. 2009-10-03 18:19:27 +00:00
sean.escriva
097d7367bb minor hlint cleanup of Prompt and XMonad.Prompt.* sub-modules 2009-09-28 20:44:43 +00:00
mail
104cc6ba25 New module : X.H.SetCursor
Idea from Andres Salomon
(http://www.haskell.org/pipermail/xmonad/2009-September/008553.html).
2009-09-15 10:13:27 +00:00
Adam Vogt
f6fa7e509f Hyperlink modules named in WindowMenu, RestoreMinimized, and Minimize 2009-10-03 15:13:25 +00:00
Jan Vornberger
563266f3a5 Mention X.L.Maximize and X.L.Minimize in WindowMenu documentation 2009-10-03 11:13:30 +00:00
Adam Vogt
df9655c662 Small style change in L.SimplestFloat 2009-10-02 00:15:52 +00:00
Adam Vogt
27a7bcbd6e Use U.XUtils.fi to make WindowMenu clearer 2009-10-01 22:57:36 +00:00
Jan Vornberger
77f52bc84d Extended GridSelect
1) Added another convenience wrapper that allows to select an X() action
   from a given list.
2) Implemented the option to change the position of the selection diamond.
(Re-recorded from Bluetile repo, rebased to current darcs)
2009-09-30 15:27:41 +00:00
Jan Vornberger
832d435dee WindowMenu based on GridSelect that displays actions for the focused window (re-recorded from Bluetile repo). 2009-09-30 15:53:43 +00:00
Daniel Schoepe
066db410b0 Use default handler in XMonad.Prompt.eventLoop 2009-10-01 18:04:02 +00:00
Adam Vogt
66b8ad46d0 Remove redundant parentheses from L.MouseResizableTile 2009-09-30 21:21:10 +00:00
Adam Vogt
bf2fc75035 Use ErrorT instead of nested case for H.WorkspaceByPos 2009-09-30 20:49:14 +00:00
Adam Vogt
e6158615cb Note that ManageDocks is preferred to A.DeManage 2009-09-30 20:44:43 +00:00
Adam Vogt
cce2c7c839 Factor out redundancy in L.MouseResizableTile.handleResize 2009-09-30 20:41:51 +00:00
Jan Vornberger
41b58ed499 In a multi-head setup, move windows with a non-zero position upon creation to the right workspace.
Useful in a dual-head setup: Looks at the requested geometry of
new windows and moves them to the workspace of the non-focused
screen if necessary.
2009-09-30 12:33:41 +00:00
Adam Vogt
3bc9c11d97 Use LANGUAGE instead of -fglasgow-exts in L.MouseResizableTile 2009-09-30 20:04:43 +00:00
Adam Vogt
8aa3450f83 Remove redundant ($) in A.Commands 2009-09-30 20:03:11 +00:00
Adam Vogt
2d193a4304 Fix haddock parse error in MouseResizableTile 2009-09-30 20:01:43 +00:00
Jan Vornberger
5d949197b2 A ResizableTile-like layout that can be resized using the mouse.
All separations between windows can be dragged to modify the layout.
Keyboard commands can also be used to achieve the same effect.
2009-09-30 12:11:05 +00:00
Jan Vornberger
2b9b770e12 Replaced more stuff in X.L.Maximize with pure versions 2009-05-16 23:35:57 +00:00
Jan Vornberger
b5b9a3dc67 Expanded on X.L.Maximize functionality
1. Move maximized window into the background when it's not focused.
2. Changed semantics so that maximizing a different window will
   automatically restore the currently maximized window and maximize the
   new one (previously this had to be done in two seperate steps).
2009-05-03 00:10:52 +00:00
Jan Vornberger
5aa7d3635e EventHook to restore minimized windows from taskbar (re-recorded from Bluetile repo) 2009-09-28 23:15:49 +00:00
Jan Vornberger
218b041fa9 LayoutModifier to minimize windows (re-recorded from Bluetile repo) 2009-09-28 23:13:20 +00:00
Daniel Schoepe
2bebf54795 Correctly check completionKey field in XMonad.Prompt 2009-09-28 09:32:15 +00:00
Daniel Schoepe
bc00f63b79 Fix for issue 315 2009-09-28 09:19:46 +00:00
Daniel Schoepe
02eed22659 Only use search history for completion in X.A.Search 2009-09-20 22:14:55 +00:00
Daniel Schoepe
2733268980 Fix regression in XMonad.Prompt's completion 2009-09-20 20:57:11 +00:00
Daniel Schoepe
eac4b6a8d2 Clean keymask before use in XMonad.Prompt 2009-09-20 20:12:29 +00:00
Daniel Schoepe
d783e96352 Export moveCursor in XMonad.Prompt 2009-09-20 19:25:13 +00:00
Wirt Wolff
f98c0c83a1 U.EZConfig: Correct additionalKeysP M2-M5 values
Was 8,9,10,11,12 rather than needed 8,16,32,64,128
2009-09-06 07:05:03 +00:00
Daniel Schoepe
e2113acd35 Factor out direction types and put them in X.U.Types
This patch factors out commonly used direction types like
data Direction = Prev | Next
and moves them to X.U.Types.
2009-09-19 19:17:17 +00:00
Daniel Schoepe
33046439d6 Add function to disable focusFollowsMouse conditionally
This patch adds an event hook to have the focus follow the mouse only
if a given condition is true.
2009-08-29 21:29:16 +00:00
Daniel Schoepe
e8e6cfcc3a Make the keymap of XMonad.Prompt customizable
This patch allows the user to change the keymap XMonad.Prompt and
related modules use to be customized using the XPConfig structure.
2009-09-10 16:08:28 +00:00
Spencer Janssen
857bf537b5 Run gnomeRegister from startupHook 2009-09-18 02:34:10 +00:00
Adam Vogt
832ea65e75 Use U.Run.safeSpawn in C.Gnome 2009-09-17 23:39:53 +00:00
Adam Vogt
c4cae4839d Add gnomeRegister to C.Gnome.
Credit to Joachim Breitner here:
http://www.haskell.org/pipermail/xmonad/2009-May/007984.html
2009-09-17 23:21:50 +00:00
Adam Vogt
cbd978c3b5 Remove excess broadcastMessage ReleaseResources from A.Commands
XMonad.Operations.restart tells the layouts to release resources.  There's no
sense in duplicating it in contrib code anymore.
2009-09-04 01:02:59 +00:00
Adam Vogt
a9cb7bf67a Mark modules last-modified in 2007 as stable
http://www.haskell.org/pipermail/xmonad/2009-July/008328.html
2009-09-04 00:51:47 +00:00
Spencer Janssen
63e5b222b8 Minor changes to my config 2009-09-01 02:48:02 +00:00
Adam Vogt
c91f54b2fb Return True in X.H.FadeInactive.isUnfocused if current workspace is empty. (dschoepe) 2009-08-28 21:45:37 +00:00
Jan Vornberger
e80f1df518 Actually execute the correct command when giving user-defined commands to ServerMode 2009-08-25 23:38:28 +00:00
Adam Vogt
afecca6561 Preserve backwards compatibility with H.ServerMode 2009-08-25 22:03:48 +00:00
Daniel Schoepe
28e0adcde7 Let the user decide which commands to use in X.H.ServerMode 2009-08-25 10:16:30 +00:00
Daniel Schoepe
9a207f0512 Improve/correct documentation in X.A.TagWindows 2009-08-23 13:12:29 +00:00
Clemens Fruhwirth
491e21b3b9 Replace nextEvent with maskEvent to prevent GridSelect from swallowing unrelated events (such as map/unmap) 2009-08-09 13:10:55 +00:00
Daniel Schoepe
0ec25c9fee Better default for ppUrgent in xmobarPP
Most users would expect workspaces with urgent windows to be highlighted in
xmobar when they set up an UrgencyHook. Hence, doing this by default in xmobarPP
makes sense. (dzenPP does the same)
2009-08-22 18:34:16 +00:00
Daniel Schoepe
8b6135f868 Add backwards compatability in X.H.FadeInactive 2009-08-21 22:56:46 +00:00
Daniel Schoepe
8fe80758a8 More flexible interface for X.H.FadeInactive
This patch allows setting the opacity on a per-window basis and lets the
user specify it as a percentage instead of an Integer between 0 and 2^32-1.
2009-08-21 20:39:36 +00:00
Wirt Wolff
cc2fb2c10d U.Scratchpad: doc add disable-factory flag to gnome-terminal example
Few systems have --disable-factory on by default, but it's needed to
set custom resource string.
http://code.google.com/p/xmonad/issues/detail?id=308
2009-08-18 19:25:03 +00:00
Wirt Wolff
5daaf583b7 A.CycleWS: add toggleOrView fns, fix doc, prevent head exception 2009-08-17 21:55:49 +00:00
Adam Vogt
8be4946bcd Add -fwarn-tabs to ghc-options for the regular build 2009-08-14 02:21:08 +00:00
Daniel Schoepe
15acd55553 Don't use tabs in EwmhDesktops 2009-08-13 20:01:19 +00:00
Joachim Breitner
4f375b20bf Do not warn about unknown ClientMessageEvents
Not all client messages are are meant to be handled by the wndow manager, so do
not complain when one is unknown.
2009-08-12 22:29:17 +00:00
konstantin.sobolev
cb9ab874ce ScratchpadRewrite
Scratchpad reimplementation in terms of NamedScratchpad. No interface changes.
2009-04-28 20:01:36 +00:00
konstantin.sobolev
be2bbc9202 NS_Placement
Added ability to specify scratchpad manage hooks, mostly for defining window placement in a more flexible manner
2009-04-28 19:27:31 +00:00
Anders Engstrom
3bce490813 ThreeColMid - Swap slave window positions
This patch will swap the positions of the two slave windows and this will result in a more intuitive window order. When using focusDown beginning in the master pane we will move in the following graphical order 2->3->1->2->3 instead of 2->1->3->2->1. This is backwards from what is expected.

The small drawback is that increasing from 2 to 3 windows (and therefore also columns) will behave in a less intuitive way. The window in the right column will jump to the left of the screen.

I think that it is a good idea to make this change since I rely a lot on the window order but people using WindowNavigation may be of a different opinion.

An alternative is to add an option to select in what way to behave, but that could be overkill... I leave it up to discussion and devs to decide.
2009-05-03 19:50:26 +00:00
Brent Yorgey
d13551a49c fix UrgencyHook docs (\a -> \\a in Haddock) 2009-08-09 18:40:16 +00:00
gwern0
d38696bcd5 XMonad.Actions.Search: removeColonPrefix shouldn't throw an exception if no :! 2009-08-08 00:22:24 +00:00
gwern0
bf398ff356 XMonad.Actions.Search: clean up hasPrefix - dupe of Data.List.isPrefixOf 2009-08-08 00:21:20 +00:00
gwern0
41a63a5743 XMonad.Actions.Search: +wikt 2009-08-08 00:06:22 +00:00
quentin.moser
a4d5d7ff9b NoWrap export patch for use with X.L.MessageControl 2009-01-28 00:47:26 +00:00
quentin.moser
aca86af08a new XMonad.Layout.MessageControl module 2009-01-28 01:39:17 +00:00
Adam Vogt
d13dc2ff48 U.NamedActions: align the descriptions for each section, refactor its integration with EZConfig 2009-07-26 03:20:03 +00:00
Adam Vogt
b89dc9da44 U.NamedActions support subtitles bound to (0,0) unreachable normally 2009-05-25 00:29:15 +00:00
Adam Vogt
a3ba5f1503 Add U.NamedActions: present a list of keybindings including submaps 2009-05-04 02:40:17 +00:00
Adam Vogt
f22c4624a3 Revert to old behavior where unmatched keys do not exit the eventloop for A.GridSelect 2009-07-27 01:23:02 +00:00
Adam Vogt
b09827c2bc Share more mkAdjust calls L.LayoutHints in the LayoutHintsToCenter modifier 2009-07-26 06:18:02 +00:00
Adam Vogt
218595881f Make direction keybindings configurable in A.GridSelect 2009-07-26 02:04:38 +00:00
Anders Engstrom
f1ce4e5876 LayoutBuilder - make an example more sane 2009-05-13 15:57:32 +00:00
Khudyakov Alexey
c884dbb74b Clean Xkb masks in X.A.Submap
Xkb adds its own mask and prevent Submap keybindings from normal
functioning when alternate layout is used. This patch cleans
these masks.
2009-06-23 16:46:53 +00:00
Adam Vogt
fdaeaa18de Fix defaulting warning with A.RandomBackground 2009-07-16 23:49:55 +00:00
Juraj Hercek
4e3a4a2c8b Addition of Machine window property.
This patch adds WM_CLIENT_MACHINE property to window properties.
I can be used to distinguish windows run from different machines.
2009-07-15 10:50:53 +00:00
David Roundy
dd1dc7f2bc remove myself as maintainer from code I don't maintain. 2009-07-16 15:34:09 +00:00
wirtwolff
8addbabe49 X.A.CopyWindow: add wsContainingCopies, doc cleanup
Use wsContainingCopies in a logHook to highlight hidden workspaces
with copies of the focused window. (refactored from original by aavogt)
2009-07-03 01:15:24 +00:00
Daniel Schoepe
b805a6fa42 Add ability to copy the entered string in X.Prompt 2009-07-09 10:07:03 +00:00
Adam Vogt
2a73df7a45 Correct license for L.CenteredMaster
Context for why I've recorded the patch:
	aavogt | portnov: did you get the message about your XMonad.Layout.CenteredMaster licence being not compatible with the licence of contrib?
	portnov | aavogt: yep.  Could you change that yourself? I allow this to be distributed as bsd3. Making so small patch and sending it will get to much time :)
	portnov | *so
	aavogt | I can change it, its more about whether you would allow the change to be made                                                                       
	aavogt | but I guess this clears it up                                                                                                                       
	portnov | i allow.
2009-07-08 05:16:16 +00:00
Adam Vogt
5cd48cac7c Remove trailing whitespace from many modules 2009-07-05 20:12:05 +00:00
Adam Vogt
d65e40f09d Clarify documentation the Migrate message added to L.SubLayouts 2009-07-05 18:00:14 +00:00
Adam Vogt
f0c0f4d5c3 Reduce a bit of recently introduced duplication in L.SubLayouts 2009-07-05 17:51:45 +00:00
Adam Vogt
f8a4dd9503 Add Migrate message to L.SubLayouts, for better support of moving windows between groups 2009-07-05 17:49:34 +00:00
Adam Vogt
1f13242164 L.SubLayouts: also run the layout being modified in a restricted environment
This way, correct behavior can be expected if the layout runs ex. 'withWindowset
W.peek', instead of looking at its arguments.
2009-07-05 17:41:56 +00:00
Adam Vogt
48e74031f9 L.SubLayouts fix bug where previously run layouts would not get messages 2009-07-05 17:35:04 +00:00
Adam Vogt
99788c8780 Simplify A.WorkspaceCursors use of layout for state, add documentation 2009-07-05 05:06:29 +00:00
Adam Vogt
96a63b1dfa Add A.WorkspaceCursors, a generalization of Plane to arbitrary dimensions
This is implemented as a layoutModifier, since that way the workspace
arrangment is preserved between restarts.
2009-07-02 04:26:09 +00:00
Adam Vogt
9c3b472470 Refactor A.OnScreen to use Maybe Monad 2009-07-03 02:15:07 +00:00
mail
7e6fed9bf0 Added XMonad.Actions.OnScreen 2009-07-02 10:16:21 +00:00
Daniel Schoepe
02671904e1 Remove code duplication in X.A.CopyWindow 2009-07-02 10:49:33 +00:00
sean.escriva
7aafd381d3 Cleanup code duplication in X.P.Layout and X.P.Workspace 2009-07-01 21:56:40 +00:00
Brent Yorgey
a6c4f7659a X.A.Search: use the new canonical package URL for hackage search 2009-06-29 19:24:55 +00:00
Brent Yorgey
141c3cba96 X.H.ManageHelpers: add two new helper functions, doFloatDep and doFloatAt 2009-06-05 03:01:13 +00:00
Adam Vogt
1e1f2c6770 Keep track of whether messages should be given to new sublayouts in L.SubLayouts 2009-06-28 06:06:08 +00:00
Adam Vogt
1893d67d09 Run sublayouts in L.Sublayouts in a restricted state 2009-06-28 06:03:33 +00:00
Adam Vogt
a0ae1e8bba A.RandomBackground: Parameterize randomBg by a RandomColor data 2009-06-29 00:41:47 +00:00
Adam Vogt
32debd47e8 Add A.RandomBackground, actions to start terminals with a random -bg option 2009-06-27 20:27:55 +00:00
Adam Vogt
54f030faf8 Replace most -fglasgow-exts with specific LANGUAGE pragmas 2009-06-26 02:54:57 +00:00
portnov84
8362a5b81b Column_layout.dpatch
This module defines layot named Column. It places all windows in one
column. Windows heights are calculated from equation: H1/H2 = H2/H3 = ... = q,
where `q' is given (thus, windows heights forms a geometric progression). With
Shrink/Expand messages one can change the `q' value.
2009-06-05 18:45:15 +00:00
Brent Yorgey
6bd66b885a X.A.Search: add Google "I'm feeling lucky" search 2009-06-25 17:37:51 +00:00
Daniel Schoepe
dce0b17420 Add ifWindow and ifWindows and simplify WindowGo
This patch adds ifWindow and ifWindows as helper functions to
X.A.WindowGo and removes some boilerplate by rewriting other functions
in terms of those. Also some minor simplifications.
2009-06-24 23:17:11 +00:00
Adam Vogt
0cb6ac2910 Use -fwarn-tabs for test, remove tabs 2009-06-24 04:38:31 +00:00
Adam Vogt
2d84da7fdd From A.Topicspace split functions for storing strings with root to U.StringProp
These functions will be used to send strings for execution by command line, in
xmonad-eval
2009-06-23 05:25:37 +00:00
Adam Vogt
9847e0da5e Correct A.TopicSpace sample config 2009-06-23 00:39:37 +00:00
Adam Vogt
0f15f2fa7e Add shiftNthLastFocused to A.TopicSpace 2009-06-23 00:26:45 +00:00
Daniel Schoepe
5733601ad3 Generalize Actions.SpawnOn
Actions.SpawnOn can now be used to execute arbitrary manage hooks on
the windows spawned by a command(e.g. start a terminal of specific size
or floated).
2009-06-22 18:38:25 +00:00
gwern0
10c984ce44 update callers of safeSpawn 2009-06-22 20:14:23 +00:00
gwern0
65b8c39fe7 XMonad.Util.Run: improve definition so this can be used with emacs 2009-06-22 20:14:01 +00:00
gwern0
04f440d804 XMonad.Actions.WindowGo: switch to safeSpawn, since everyone just passes a prog name (no shell scripting) 2009-06-22 19:32:55 +00:00
gwern0
d4d17e6576 XMonad.Util.Run: +convenience function for safeSpawn which drops args to the prog 2009-06-22 19:30:18 +00:00
gwern0
e582ae5a4e XMonad.Actions.WindowGo: improve haddocks 2009-06-22 19:28:31 +00:00
Adam Vogt
41d8b2b22a Fix window ordering bug in L.LimitWindows 2009-06-22 00:43:09 +00:00
Adam Vogt
708b8a7d96 L.LimitWindows add usage information, functions to modify the limit 2009-06-22 00:01:15 +00:00
Dmitry Astapov
f541602f0b Expand Tabbed documentation to describe mouse clicks processing 2009-06-21 21:19:47 +00:00
Dmitry Astapov
be2be3f2f6 Close tabs by middle click on tab decoration
I'd better do it in xmonad.hs, but I can't decide what to expose from
Tabbed.hs to make it happed. Suggestions on how to make mouse click
handling hook a part of the Tabbed creation interface are very welcome
- my attempts turned out to be ugly in extreme.
2009-06-21 19:52:25 +00:00
Dmitry Astapov
54dc0ac732 Provide means to find original window by its decoration.
In order to enable user to write custom `decorationMouseFocusHook' and
`decorationMouseDragHook' hooks we need to provide him with means to
lookup original window by its decoration.

Module Decoration has internal function `lookFor' for exactly the same
purpose. I exported it under a slightly different name and without
exposing internals of DecorationState.
2009-06-21 19:46:52 +00:00
Adam Vogt
d823d9e68c Add L.LimitWindows layout modifier 2009-06-19 05:27:31 +00:00
Daniel Schoepe
1b521f0064 Remove Hooks.EventHook
The Hooks.EventHook module is superseded by handleEventHook from core and should no longer be needed.
2009-06-18 10:43:18 +00:00
Adam Vogt
00c3775a06 use 'take 1' instead of custom truncHead function in L.WindowNavigation 2009-06-18 01:01:18 +00:00
Adam Vogt
cc84480c99 Correct many typos in the documentation, consistent US spellingg 2009-06-18 00:37:29 +00:00
Joachim Breitner
6d0b082eb7 minor typo in ./XMonad/Layout/StackTile.hs 2009-06-17 21:03:45 +00:00
Brent Yorgey
67cdbb0ba8 X.L.ResizableTile: make sure windows aren't resized to a height larger than the screen (fixes #298) 2009-06-04 12:35:09 +00:00
Roman Cheplyaka
fc984af98d X.A.PhysicalScreens: fix typo 2009-06-02 17:21:48 +00:00
Roman Cheplyaka
9b7125f965 X.L.AutoMaster: fix warning 2009-06-02 17:17:54 +00:00
Ilya Portnov
85913caf2e AutoMaster.dpatch
Provides layout modifier AutoMaster. It separates screen in two parts -
master and slave. Size of slave area automatically changes depending on
number of slave windows.
2009-04-26 15:54:01 +00:00
Anders Engstrom
aa435aa5c8 UpdatePointer - Don't warp while dragging with mouse 2009-05-30 18:57:52 +00:00
Anders Engstrom
72e2c5d0b4 FlexibleResize - Resize from edge, don't move adjust at opposite edge
When resizing other corners than bottom-right, instead of adjusting to even columns/rows on the opposite side to it the same way as if resizing was made from the bottom right.

Also add the possibility to add an area in the middle of an edge where only that edge is resized, not the closest corner.
2009-05-30 18:54:37 +00:00
Khudyakov Alexey
eddd655b49 Remove USE_UTF8 defines.
They are not needed any more since utf8-string is mandatory dependence.
2009-04-19 13:09:09 +00:00
Anders Engstrom
c5b5db500b FloatSnap - calculate gaps instead of snapping against unmanaged windows
This patch will remove snapping against unmanaged windows, but instead calculate a new rectangle with all gaps (computed by ManageDocks) removed. This new rectangle is used to snap against. (Both the inside and outside of the rectangle.)

This will remedy the issue of snapping against multiple layers of the same window, additionally there will be no snap-points between windows on the same side. So if you are running two dzen side by side with half the screen each. You will not automatically have a snap-point in the middle.

Naturally, this patch will change which function is exported from ManageDocks.
2009-05-26 22:29:42 +00:00
Adam Vogt
f6479ee0a8 Fix L.Mosaic bug where stored [Rational] was not extended 2009-05-25 03:07:34 +00:00
Brent Yorgey
451ced82d9 X.A.Search: add Wolfram|Alpha search 2009-05-25 01:04:19 +00:00
Adam Vogt
3f3aff573a Remove L.ThreeColumnsMiddle compatiblity module
Signed off here too:
http://www.haskell.org/pipermail/xmonad/2009-May/007883.html
2009-05-25 00:32:45 +00:00
Adam Vogt
49bb2655ff A.FloatSnap snap to unmanaged docks too 2009-05-25 00:18:34 +00:00
Anders Engstrom
6703453f26 LayoutBuilder fix maintainer 2009-05-24 20:59:57 +00:00
Anders Engstrom
1fd4489ae6 FloatSnap fix maintainer 2009-05-24 20:58:54 +00:00
Anders Engstrom
bc425079f2 X.A.FloatSnap - More configuration for magic resize, adaption for mouse bindings and some minor fixes 2009-05-24 20:11:43 +00:00
Anders Engstrom
bd7e2004a0 X.A.FloatSnap - Assisted move/resize of windows
TODO: Try to snap against unmanaged windows such as dzen/xmobar.
2009-05-23 23:52:30 +00:00
Adam Vogt
160d961951 Simplyify L.Mosaic interface, and support resizing specific windows
The order previously was not as documented, which prevented resizing specific
windows.

The Mosaic constructor is hidden in favour of mosaic :: Rational -> [Rational] -> Mosaic a

Expand and Shrink messages are added, requiring another argument.

Remove useless demonstration of SlopeMod message since resizing the focused
window is better.
2009-05-24 19:38:10 +00:00
Adam Vogt
75cf2c1e30 L.ResizableTile document ResizableTall parameters with records 2009-05-19 02:42:58 +00:00
Adam Vogt
50c22cc05b L.LayoutHints, add layoutHintsToCentre
layoutHintsToCentre attempts to apply hints in a way that eliminates gaps
between windows. The excess space ends up on all edges.
2009-05-19 01:38:06 +00:00
Adam Vogt
9d27bdb17d Remove excess whitespace from L.LayoutHints 2009-05-19 01:33:50 +00:00
Brent Yorgey
2eb98c1437 new layout module X.L.Spacing, put blank space around each window 2009-05-14 21:55:52 +00:00
Anders Engstrom
a3f931262b X.L.LayoutBuilder doc fix and cleaning 2009-05-09 19:52:54 +00:00
Anders Engstrom
af22761a10 X.L.LayoutBuilder custom layouts
A layout combinator that sends a specified number of windows to one rectangle and the rest to another.
2009-05-09 17:46:27 +00:00
Anders Engstrom
823ea115ae submapDefault fix key leakage 2009-04-26 17:10:02 +00:00
Adam Vogt
ea61ad0f47 Fix typo in L.Mosaic hints 2009-05-08 20:29:37 +00:00
wirtwolff
071257d475 U.Loggers: add maildirNew, other loggers, and logger formatting utilities
Rework of the Logger portions of patches originally from seanmce33@gmail.com
to apply without conflicts, plus several formatting utilities for use with
X (Maybe String) aka Loggers.
2009-04-12 04:13:56 +00:00
Anders Engstrom
a5e11a14b6 ThreeCol - Update docs to match reality 2009-05-03 19:07:55 +00:00
Adam Vogt
99e839228e Remove some excess whitespace in XMonad.AppLauncher 2009-05-03 18:34:16 +00:00
Adam Vogt
cc0e18af8a Export ThreeColMid from L.ThreeColumnsMiddle
The configs that import it should continue to work with this module, though the
type of the ThreeColMid constructor is now ThreeCol (previously ThreeColMid).
2009-04-25 16:17:10 +00:00
Adam Vogt
7410b9826c ThreeColumns support middle column, with more backwards compatiblity 2009-04-14 06:18:19 +00:00
Anders Engstrom
71139c1fb3 X.L.ThreeColumnsMiddle merged into X.L.ThreeColumns with some new features 2009-04-11 11:36:36 +00:00
Anders Engstrom
561855133c nameTail - Remove the first word of a layout description 2009-05-03 10:59:50 +00:00
Adam Vogt
4a8c4b74ac Add H.InsertPosition: add new windows to different positions in a workspace 2009-05-03 02:03:03 +00:00
Adam Vogt
552b4f91ab Add changeMaster function to L.Mosaic 2009-05-01 23:31:36 +00:00
Adam Vogt
89c2ecb448 Optimizer bug does not affect 6.10.2 (issue 226) 2009-04-30 03:48:23 +00:00
Adam Vogt
06a997aaf9 Remove -XScopedTypeVariables requirement with L.SubLayouts
This should keep the code -Wall clean on ghc-6.8 in addition to ghc-6.10
2009-04-28 22:27:49 +00:00
Adam Vogt
115cd5af95 Add SubLayouts: a layout combinator for nesting layouts. 2009-04-23 01:31:35 +00:00
Adam Vogt
0dd1cf1ea8 Document and extend BoringWindows to support multiple sources of boring.
The Replace and Merge messages are added to support layouts sending a list of
windows that should be skipped over. The sources are tagged by a string key, so
it is possible though unlikely for different sources of boring windows to
interfere with eachother.
2009-04-06 04:13:01 +00:00
Adam Vogt
24b39a40cb Add Apply message to L.WindowNavigation 2009-03-03 06:57:01 +00:00
Nicolas Pouillard
b60cdb60f0 X.A.TopicSpace: remove the allTopics lists from the configuration. 2009-04-23 17:29:39 +00:00
perlkat
cc7d2140b7 added colour themes
These themes are colour themes only; they use the default font settings.
I thought the existing themes were rather dull, so these give more bright
(but tasteful) colours; shades of peacock feathers, shades of autumn.
2009-02-27 06:53:15 +00:00
sean.escriva
e780b6f81e Prompt.hs: setSuccess True also on Keypad Enter 2009-04-09 16:26:09 +00:00
Daniel Schoepe
5ce50a3cc0 Update focus on mouse moves within inactive windows
This patch adds functionality to update the focus on moves in unfocused windows, which would make sense if one wanted the focus to follow the mouse.
Currently this only happens when the mouse enters/leaves a window. 
This patch should fix issue #205.
2009-04-07 19:18:19 +00:00
Adam Vogt
6bcbd5b871 Add promoteWarp event to L.MagicFocus
This event enables A.UpdatePointer behavior without causing infinite loops in
combination with magicFocus
2009-03-22 22:14:56 +00:00
Adam Vogt
761b884555 Add TowardsCentre option to UpdatePointer
This option is like Nearest, but it places the pointer a configurable
percentage towards the centre of the window, instead of right at the edge.
2009-03-22 21:58:11 +00:00
Adam Vogt
3ad7661897 Remove excess whitespace in A.UpdatePointer 2009-03-22 21:55:53 +00:00
Anders Engstrom
6d205dda20 Combo fix ReleaseResources when no windows are available, new fix 2009-02-24 17:20:18 +00:00
portnov84
e0ca57557b OneBig_resize.dpatch
Add Shrink/Expand messages handling for OneBig layout.
2009-02-21 14:23:00 +00:00
portnov84
1c0d227c44 OneBig_layout.dpatch
Add the OneBig layout, which places one (master) window at top left corner of
screen (width and height of master window are parameters of layout), and other
(slave) windows at bottom and at right of master, trying to give equal space
for each slave window.
2009-02-20 17:26:34 +00:00
Khudyakov Alexey
32b1e5bdfa Properly encode destop names before sending them to X server in XMonad.Hooks.EwmhDesktops 2009-02-20 18:41:37 +00:00
Khudyakov Alexey
13d8b17f97 Make utf8-string regular dependency
The reason for this is that EWMH specification require 
utf8 encoded strings.
2009-02-20 18:33:18 +00:00
Daniel Schoepe
6686d32f56 Update haddock description for Actions.GridSelect 2009-04-22 17:25:10 +00:00
sean.escriva
3184fd00c7 X.H.DynamicLog: provides trim, inverse of pad 2009-04-09 16:35:13 +00:00
Daniel Schoepe
e431c38c5e Mouse support for GridSelect
GridSelect now allows selecting an element by a click with the left mouse button.
2009-04-09 22:33:02 +00:00
Daniel Schoepe
156917209e Generalize GridSelect to arbitrary elements
This patch generalizes Actions.GridSelect to work for arbitrary (String,a)-lists. The changes break configurations that used `gridSelect' directly, which is now named gridSelectWindow. As an example for uses of the GridSelect-UI, I included a function to spawn an application from a list of commands(`spawnSelected').
2009-04-09 15:57:04 +00:00
quentin.moser
34147551ce Improve composability of X.H.Place, drop simple(st)Float support 2009-04-15 18:45:50 +00:00
quentin.moser
e772528912 Fixed X.H.Place.position 2009-04-09 08:49:46 +00:00
quentin.moser
43edb3a151 Module for automatic placement of floating windows 2009-04-08 08:09:53 +00:00
quentin.moser
1b82ccd21f X.H.FloatNext: new module, float the next spawned window(s) 2009-04-15 18:19:07 +00:00
konstantin.sobolev
af526ae23e ComboP 2009-04-15 01:43:27 +00:00
Nicolas Pouillard
0234f94be3 New module: XMonad.Actions.TopicSpace 2009-04-19 08:52:39 +00:00
konstantin.sobolev
5ad49783f2 NamedScratchpad 2009-04-19 04:55:42 +00:00
Adam Vogt
4cac1c6ebd More configurability for Layout.NoBorders (typeclass method)
This method uses a typeclass to pass a function to the layoutmodifier. It is
flexible, but a bit indirect and perhaps the flexibility is not required.
2009-03-25 05:02:06 +00:00
nelhage
93ed1c6019 Add XMonad.Actions.PhysicalScreens
Add an XMonad.Actions.PhysicalScreens contrib module that allows
addressing of screens by physical ordering, rather than the arbitrary
ScreenID.
2009-03-21 00:13:20 +00:00
Joachim Breitner
521bb48ad9 pointWithin has moved to the core 2008-10-08 15:42:45 +00:00
Joachim Breitner
15df01705f UpdatePointer even to empty workspaces
This makes UpdatePointer more Xinerama-compatible: If the user switches to a
screen with an empty workspace, the pointer is moved to that workspace, which I
think is expected behavoiur.
2008-10-07 08:00:41 +00:00
Norbert Zeh
ac8c6ab633 More predictable aspect ratio in GridVariants.Grid
The old version fairly arbitrarily decided to prefer windows that are too
high over those that are too wide.  The new version chooses the number of
columns so that all windows on the screen are as close as possible to the
desired aspect ratio.  As a side effect, the layout changes much more
predictably under addition and removal of clients.
2009-03-11 01:36:17 +00:00
Ismael Carnales
e8d80d552c X.L.Master: fix number of windows 2009-03-01 05:15:09 +00:00
wirtwolff
15217548ab U.EZConfig: add xK_Print <Print> to special keys
Many setups are expecting xK_Print rather than
xK_Sys_Req, so make it available in additionalKeysP.
2009-03-02 23:07:41 +00:00
Daniel Schoepe
fb7a2d4ae3 More flexibility for H.FadeInactive 2009-03-09 16:00:20 +00:00
Valery V. Vorotyntsev
75a3e2e290 Prompt.Shell: escape ampersand
Ampersand (&) is a special character and should be escaped.
2009-03-12 09:13:14 +00:00
Adam Vogt
a2846292bf Cleanup X.L.Mosaic, without breaking it 2009-02-19 02:24:17 +00:00
Adam Vogt
92aa7079ea X.L.Mosaic: prevent users from causing non-termination with negative elements 2009-02-10 02:27:27 +00:00
Adam Vogt
aa7dce7085 better Layout.NoBorders.smartBorders behavior on xinerama
Now smartBorders shows borders when you have multiple screens with one window
each. In the case where only one window is visible, no borders are drawn.
2009-03-14 17:00:58 +00:00
wirtwolff
ac60c04cb4 H.DynamicLog: revised dzenStrip and xmobarStrip functions
Reconcile darcswatch patch with pushed version of dzenStrip.
2009-03-14 04:15:17 +00:00
Braden Shepherdson
2a9c77aa71 X.H.DynamicLog: Add dzenStrip to remove formatting, for use in dzenPP's ppUrgent.
This function was written by Wirt Wolff. This change should allow UrgencyHook
to work out of the box with dzen and dzenPP, rather than the colours being
overridden so even though UrgencyHook is working, it doesn't change colours.
2009-03-14 03:28:18 +00:00
Roman Cheplyaka
98030cb415 X.H.ManageHelpers: export isInProperty 2009-03-08 20:11:12 +00:00
wirtwolff
1b682cbceb L.Cross: clarify documentation
Amend-record earlier patch to work with byorgey's fix,
this one is just the documentation typo fixes and 
clarifications.
2009-02-22 04:22:20 +00:00
daniel
edcba03217 documentation for IndependentScreens 2009-02-21 23:59:59 +00:00
daniel
04a5f4392e eliminate a haddock warning in BoringWindows 2009-02-21 23:58:36 +00:00
daniel
db4f731f4e merge IndependentScreens 2009-02-21 23:21:42 +00:00
daniel
57a62ce871 add IndependentScreens to xmonad-contrib.cabal 2009-02-21 23:16:32 +00:00
daniel
cf07f9caca add type information for IndependentScreens 2009-02-21 23:15:25 +00:00
Brent Yorgey
efc2f1160f add some boilerplate comments at the top of IndependentScreens 2009-02-21 23:08:50 +00:00
daniel
ffe5f0cf6f IndependentScreens, v0.0 2009-02-21 22:52:29 +00:00
wirtwolff
d6d03e84af U.Run: remove waitForProcess to close Issue 268
http://code.google.com/p/xmonad/issues/detail?id=268
Submitting with some trepidation, since I've nearly no
understanding of process handling. Should be ok, no 
warnings by sjanssen when asking about it in hpaste or
earlier email, and tested locally by spawning excessive
numbers of dzens: did not leave zombies or raise exceptions.
2009-02-20 21:41:53 +00:00
Brent Yorgey
ed1d90d322 change Cross data declaration into a record so that Haddock will parse the per-argument comments 2009-02-21 22:47:42 +00:00
Ismael Carnales
3285ac8bb4 X.L.Master: turn it to a Layout modifier and update the code 2009-02-13 02:04:53 +00:00
Spencer Janssen
27bbeff92c Use doShift in my config 2009-02-19 04:20:40 +00:00
Spencer Janssen
35c5e80c32 SpawnOn: use doShift. This resolves problems where SpawnOn would shift the wrong window 2009-02-19 04:18:56 +00:00
Spencer Janssen
a4f4c5bd39 SpawnOn: delete seen pids 2009-02-13 01:30:11 +00:00
Roman Cheplyaka
bbb0e97e61 X.U.Loggers: handle possible EOF (reported by dyfrgi) 2009-02-16 21:38:42 +00:00
wirtwolff
c1c5b8d08e U.Scratchpad: add general spawn action to close issue 249
Adds scratchpadSpawnActionCustom where user specifies how to set
resource to "scratchpad". This allows use of gnome-terminal, etc.
Add detail to RationalRectangle documentation; strip trailing spaces.
2009-02-14 00:36:42 +00:00
Spencer Janssen
cd86241cc9 SpawnOn: add 'exec' to shell strings where possible 2009-02-12 23:46:08 +00:00
'Luis Cabellos
6037b0db21 Add Cross Layout 2009-02-09 17:48:02 +00:00
Daniel Schoepe
7e1db48875 Fix an undefined in EwmhDesktops 2009-02-09 15:23:08 +00:00
Roman Cheplyaka
509e345947 X.U.WindowProperties: docs (description and sections) 2009-02-08 23:14:22 +00:00
Ismael Carnales
12939b6c1d X.U.WindowProperties: Add getProp32 and getProp32s, helpers to get properties from windows 2009-02-05 01:30:31 +00:00
Adam Vogt
aa1581b3d0 cleanup and make X.L.Mosaic behavior more intuitive wrt. areas 2009-02-08 22:16:29 +00:00
Joachim Breitner
b66d1aae33 minor typo in XMonad/Util/EZConfig.hs 2009-02-08 19:22:24 +00:00
Khudyakov Alexey
07793c1bc3 Multimedia keys support for EZConfig 2009-02-07 17:33:30 +00:00
wirtwolff
bd3c36d62e +A.CycleWindows: bindings to cycle windows in new ways
Provides binding actions and customizable pure stack operations
to cycle through a list of permutations of the stack (recent),
cycle nth into focus, cycle through focus excluding a neighbor,
cycle unfocused, shift a window halfway around the stack.
Esp. for Full, two or three pane layouts, but useful for any
layout with many windows.
2009-02-07 17:06:22 +00:00
gwern0
f80d3eb250 XMonad.Actions.CopyWindow: fmt & qualify stackset import 2009-02-06 17:18:33 +00:00
lan3ny
af08bec754 XMonad.Actions.CopyWindow runOrCopy 2008-06-02 20:57:42 +00:00
Ismael Carnales
9fc46d0dfd ManageHelpers: reduce duplicated code in predicates 2009-02-04 02:18:47 +00:00
Roman Cheplyaka
c1b9f308d9 Remove X.U.SpawnOnWorkspace (superseded by X.A.SpawnOn) 2009-02-04 10:36:35 +00:00
Roman Cheplyaka
fbb9605d76 X.A.SpawnOn: add docs
Add more documentation, including documentation from
X.U.SpawnOnWorkspace by Daniel Schoepe.
2009-02-04 10:24:24 +00:00
Spencer Janssen
54122382ed Remove silliness from XMonad.Doc.Configuring 2009-02-04 05:56:26 +00:00
Daniel Schoepe
9a7dcbbabb Adjustments to use the new event hook feature instead of Hooks.EventHook 2009-02-03 16:00:46 +00:00
quentin.moser
4700b44c2c Easier Colorizers for X.A.GridSelect 2009-01-28 00:17:02 +00:00
Roman Cheplyaka
b88f22fc36 X.A.SpawOn: fix usage doc 2009-02-02 10:20:42 +00:00
Norbert Zeh
d4a0bbbe2c Added GridVariants.SplitGrid
GridVariants.TallGrid behaved weird when transformed using Mirror
or Reflect.  The new layout SplitGrid does away with the need for
such transformations by taking a parameter to specify horizontal
or vertical splits.
2009-01-29 15:21:46 +00:00
Ismael Carnales
31110d1b45 FixedColumn: added missing nmaster to the usage doc 2009-01-30 19:52:39 +00:00
gwern0
3c0f793e4a XMonad.Actions.Search: fix whitespace & tabs 2009-01-29 02:52:46 +00:00
Michal Trybus
794f70fb04 xmonad-action-search-intelligent-searchengines
Changed the XMonad.Action.Search to use a function instead of String to prepare the search URL.Added a few useful functions used to connect many search engines together and do intelligent prefixed searches (more doc in haddock)The API has not changed with the only exception of search function, which now accepts a function instead of String.
2009-01-28 10:19:38 +00:00
quentin.moser
cfbee439a1 XMonad.Prompt autocompletion fix 2009-01-27 18:41:45 +00:00
Brent Yorgey
869a3d4a1e X.A.SinkAll: re-add accidentally deleted usage documentation 2009-01-27 22:25:33 +00:00
Brent Yorgey
d1e2991ccf move XMonad.Actions.SinkAll functionality to more general XMonad.Actions.WithAll, and re-export sinkAll from X.A.SinkAll for backwards compatibility 2009-01-27 22:23:55 +00:00
loupgaroublond
3022e3c937 adds generic 'all windows on current workspace' functionality 2008-12-21 22:48:50 +00:00
quentin.moser
01e0a42c17 placement patch to XMonad.Layout.LayoutHints 2009-01-26 19:59:50 +00:00
quentin.moser
eed05efeab XMonad.Actions.MessageFeedback module 2009-01-26 18:10:59 +00:00
Anders Engstrom
b39dfa1917 submapDefault
Add support for a default action to take when the entered key does not match any entry.
2009-01-18 15:29:33 +00:00
Roman Cheplyaka
b3822c6faa X.A.CycleWS: convert tabs to spaces (closes #266) 2009-01-27 18:56:04 +00:00
Adam Vogt
9826ade99e Mosaic picks the middle aspect layout, unless overriden 2009-01-26 03:24:21 +00:00
Adam Vogt
f22c6aa144 Mosaic: stop preventing access to the widest layouts 2009-01-25 04:52:56 +00:00
Adam Vogt
b7872f77f7 X.L.Mosaic add documentation, update interface and aspect ratio behavior 2009-01-25 04:12:29 +00:00
Spencer Janssen
c1f1f27da0 Use currentTag, thanks asgaroth 2009-01-25 21:33:31 +00:00
Daniel Schoepe
70e9b9b2d6 Support for spawning most applications on a specific workspace 2009-01-25 19:10:45 +00:00
Roman Cheplyaka
22a7c39107 X.L.Mosaic: haddock fix 2009-01-24 23:59:08 +00:00
Adam Vogt
5c849c1fc6 A mosaic layout based on MosaicAlt
The position of a window in the stack determines its position and layout. And
the overall tendency to make wide or tall windows can be changed, though not
all of the options presented by MosaicAlt can be reached, the layout changes
with each aspect ratio message.
2009-01-24 02:20:58 +00:00
Spencer Janssen
e78cad6f90 uninstallSignalHandlers in spawnPipe 2009-01-22 00:27:45 +00:00
Spencer Janssen
69a75d863e Create a new session for spawnPiped processes 2009-01-22 00:04:41 +00:00
169 changed files with 10037 additions and 1962 deletions

84
README
View File

@@ -1,21 +1,78 @@
3rd party xmonad extensions and contributions.
xmonad-contrib : third party extensions to the xmonad window manager
Build and install through Cabal as for other Haskell packages:
http://xmonad.org
runhaskell Setup configure --user --prefix=$HOME
runhaskell Setup build
runhaskell Setup install --user
You need the ghc compiler and xmonad window manager installed in
order to use these extensions.
(You may want to remove the --user flag when installing as root.)
For installation and configuration instructions, please see the
xmonad website, the documents included with the xmonad source
distribution, and online haddock documentation:
scripts/ contains further external programs useful with xmonad.
http://www.xmonad.org/xmonad-docs
Haskell code contributed to this repo should live under the
appropriate subdivision of the 'XMonad.' namespace (currently includes
Actions, Config, Hooks, Layout, Prompt, and Util). For example, to use
the Mosaic layout, one would import:
------------------------------------------------------------------------
XMonad.Layout.Mosaic
Changelogs
For a list of changes since the 0.8.x releases, see:
http://www.haskell.org/haskellwiki/Xmonad/Notable_changes_since_0.8
------------------------------------------------------------------------
Updates to XMonadContrib-0.9 that may Require Changes to ~/.xmonad/xmonad.hs
Please see the Changelogs and xmonad-contrib haddock documentation
links for further details regarding the following changes.
* XMonad.Hooks.EwmhDesktops no longer uses layoutHook, the
ewmhDesktopsLayout modifier has been removed from xmonad-contrib. It
uses logHook, handleEventHook, and startupHook instead and provides
a convenient function 'ewmh' to add EWMH support to a defaultConfig.
* Most DynamicLog users can continue with configs unchanged, but users
of the quickbar functions 'xmobar' or 'dzen' will need to change
xmonad.hs: their types have changed to allow easier composition with
other XConfig modifiers. The 'dynamicLogDzen' and 'dynamicLogXmobar'
functions have been removed.
* WindowGo or safeSpawn users may need to change command lines due to
safeSpawn changes.
* People explicitly referencing the "SP" scratchpad workspace should
change it to "NSP" which is also used by the new Util.NamedScratchpad.
* (Optional) People who explicitly use swapMaster in key or mouse
bindings should change it to shiftMaster. It's the current default
used where swapMaster had been used previously. It works better than
swapMaster when using floating and tiled windows together on the
same workspace.
------------------------------------------------------------------------
Getting or updating XMonadContrib
latest release: http://hackage.haskell.org/cgi-bin/hackage-scripts/package/xmonad-contrib
darcs version: darcs get http://code.haskell.org/XMonadContrib
(To use darcs xmonad-contrib you must also use the darcs version
of xmonad.)
------------------------------------------------------------------------
Contributing
Haskell code contributed to this repo should live under the
appropriate subdivision of the 'XMonad.' namespace (currently
includes Actions, Config, Hooks, Layout, Prompt, and Util). For
example, to use the Grid layout, one would import:
XMonad.Layout.Grid
For further details, see the documentation for the
XMonad.Doc.Developing module and http://xmonad.org website.
------------------------------------------------------------------------
@@ -23,6 +80,3 @@ Code submitted to the contrib repo is licensed under the same license as
xmonad itself, with copyright held by the authors.
------------------------------------------------------------------------
Documentation for the extensions and configuration system is available
in Haddock form in the XMonad.Doc module and submodules.

View File

@@ -41,7 +41,7 @@ import Data.Maybe
--
-- Then add a keybinding to the runCommand action:
--
-- > , ((modMask x .|. controlMask, xK_y), commands >>= runCommand)
-- > , ((modm .|. controlMask, xK_y), commands >>= runCommand)
--
-- and define the list of commands you want to use:
--
@@ -82,23 +82,22 @@ defaultCommands = do
wscmds <- workspaceCommands
return $ wscmds ++ screenCommands ++ otherCommands
where
sr = broadcastMessage ReleaseResources
otherCommands =
[ ("shrink" , sendMessage Shrink )
, ("expand" , sendMessage Expand )
, ("next-layout" , sendMessage NextLayout )
, ("default-layout" , asks (layoutHook . config) >>= setLayout )
, ("restart-wm" , sr >> restart "xmonad" True )
, ("restart-wm-no-resume", sr >> restart "xmonad" False )
, ("restart-wm" , restart "xmonad" True )
, ("restart-wm-no-resume", restart "xmonad" False )
, ("xterm" , spawn =<< asks (terminal . config) )
, ("run" , spawn "exe=`dmenu_path | dmenu -b` && exec $exe" )
, ("kill" , kill )
, ("refresh" , refresh )
, ("focus-up" , windows $ focusUp )
, ("focus-down" , windows $ focusDown )
, ("swap-up" , windows $ swapUp )
, ("swap-down" , windows $ swapDown )
, ("swap-master" , windows $ swapMaster )
, ("focus-up" , windows focusUp )
, ("focus-down" , windows focusDown )
, ("swap-up" , windows swapUp )
, ("swap-down" , windows swapDown )
, ("swap-master" , windows swapMaster )
, ("sink" , withFocused $ windows . sink )
, ("quit-wm" , io $ exitWith ExitSuccess )
]

View File

@@ -5,7 +5,7 @@
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : <dougal@dougalstanton.net>
-- Stability : unstable
-- Stability : stable
-- Portability : unportable
--
-- Lets you constrain the aspect ratio of a floating
@@ -31,8 +31,8 @@ import XMonad
--
-- Then add something like the following to your mouse bindings:
--
-- > , ((modMask x, button3), (\w -> focus w >> Sqr.mouseResizeWindow w False))
-- > , ((modMask x .|. shiftMask, button3), (\w -> focus w >> Sqr.mouseResizeWindow w True ))
-- > , ((modm, button3), (\w -> focus w >> Sqr.mouseResizeWindow w False))
-- > , ((modm .|. shiftMask, button3), (\w -> focus w >> Sqr.mouseResizeWindow w True ))
--
-- The line without the shiftMask replaces the standard mouse resize
-- function call, so it's not completely necessary but seems neater

View File

@@ -2,14 +2,14 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.CopyWindow
-- Copyright : (c) David Roundy <droundy@darcs.net>, Ivan Veselov <veselov@gmail.com>
-- Copyright : (c) David Roundy <droundy@darcs.net>, Ivan Veselov <veselov@gmail.com>, Lanny Ripple <lan3ny@gmail.com>
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : ???
-- Stability : unstable
-- Portability : unportable
--
-- Provides a binding to duplicate a window on multiple workspaces,
-- Provides bindings to duplicate a window on multiple workspaces,
-- providing dwm-like tagging functionality.
--
-----------------------------------------------------------------------------
@@ -17,13 +17,20 @@
module XMonad.Actions.CopyWindow (
-- * Usage
-- $usage
copy, copyToAll, copyWindow, killAllOtherCopies, kill1
copy, copyToAll, copyWindow, runOrCopy
, killAllOtherCopies, kill1
-- * Highlight workspaces containing copies in logHook
-- $logHook
, wsContainingCopies
) where
import Prelude hiding (filter)
import XMonad
import Control.Arrow ((&&&))
import Control.Monad
import qualified Data.List as L
import XMonad hiding (modify, workspaces)
import XMonad.StackSet
import XMonad.Actions.WindowGo
import qualified XMonad.StackSet as W
-- $usage
--
@@ -36,7 +43,7 @@ import XMonad.StackSet
-- > -- mod-[1..9] @@ Switch to workspace N
-- > -- mod-shift-[1..9] @@ Move client to workspace N
-- > -- mod-control-shift-[1..9] @@ Copy client to workspace N
-- > [((m .|. modMask x, k), windows $ f i)
-- > [((m .|. modm, k), windows $ f i)
-- > | (i, k) <- zip (workspaces x) [xK_1 ..]
-- > , (f, m) <- [(W.view, 0), (W.shift, shiftMask), (copy, shiftMask .|. controlMask)]]
--
@@ -48,7 +55,12 @@ import XMonad.StackSet
-- You may also wish to redefine the binding to kill a window so it only
-- removes it from the current workspace, if it's present elsewhere:
--
-- > , ((modMask x .|. shiftMask, xK_c ), kill1) -- @@ Close the focused window
-- > , ((modm .|. shiftMask, xK_c ), kill1) -- @@ Close the focused window
--
-- Instead of copying a window from one workspace to another maybe you don't
-- want to have to remember where you placed it. For that consider:
--
-- > , ((modm, xK_b ), runOrCopy "firefox" (className =? "Firefox")) -- @@ run or copy firefox
--
-- Another possibility which this extension provides is 'making window
-- always visible' (i.e. always on current workspace), similar to corresponding
@@ -58,59 +70,95 @@ import XMonad.StackSet
--
-- Here is the example of keybindings which provide these actions:
--
-- > , ((modMask x, xK_v )", windows copyToAll) -- @@ Make focused window always visible
-- > , ((modMask x .|. shiftMask, xK_v ), killAllOtherCopies) -- @@ Toggle window state back
-- > , ((modm, xK_v ), windows copyToAll) -- @@ Make focused window always visible
-- > , ((modm .|. shiftMask, xK_v ), killAllOtherCopies) -- @@ Toggle window state back
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
-- | copy. Copy the focussed window to a new workspace.
copy :: (Eq s, Eq i, Eq a) => i -> StackSet i l a s sd -> StackSet i l a s sd
copy n s | Just w <- peek s = copyWindow w n s
-- $logHook
-- To distinguish workspaces containing copies of the focused window use
-- something like:
--
-- > sampleLogHook h = do
-- > copies <- wsContainingCopies
-- > let check ws | ws `elem` copies = pad . xmobarColor "red" "black" $ ws
-- > | otherwise = pad ws
-- > dynamicLogWithPP myPP {ppHidden = check, ppOutput = hPutStrLn h}
-- >
-- > main = do
-- > h <- spawnPipe "xmobar"
-- > xmonad defaultConfig { logHook = sampleLogHook h }
-- | Copy the focused window to a workspace.
copy :: (Eq s, Eq i, Eq a) => i -> W.StackSet i l a s sd -> W.StackSet i l a s sd
copy n s | Just w <- W.peek s = copyWindow w n s
| otherwise = s
-- | copyToAll. Copy the focused window to all of workspaces.
copyToAll :: (Eq s, Eq i, Eq a) => StackSet i l a s sd -> StackSet i l a s sd
copyToAll s = foldr copy s $ map tag (workspaces s)
-- | Copy the focused window to all workspaces.
copyToAll :: (Eq s, Eq i, Eq a) => W.StackSet i l a s sd -> W.StackSet i l a s sd
copyToAll s = foldr copy s $ map W.tag (W.workspaces s)
-- | copyWindow. Copy a window to a new workspace
copyWindow :: (Eq a, Eq i, Eq s) => a -> i -> StackSet i l a s sd -> StackSet i l a s sd
-- | Copy an arbitrary window to a workspace.
copyWindow :: (Eq a, Eq i, Eq s) => a -> i -> W.StackSet i l a s sd -> W.StackSet i l a s sd
copyWindow w n = copy'
where copy' s = if n `tagMember` s
then view (currentTag s) $ insertUp' w $ view n s
where copy' s = if n `W.tagMember` s
then W.view (W.currentTag s) $ insertUp' w $ W.view n s
else s
insertUp' a s = modify (Just $ Stack a [] [])
(\(Stack t l r) -> if a `elem` t:l++r
then Just $ Stack t l r
else Just $ Stack a (L.delete a l) (L.delete a (t:r))) s
insertUp' a s = W.modify (Just $ W.Stack a [] [])
(\(W.Stack t l r) -> if a `elem` t:l++r
then Just $ W.Stack t l r
else Just $ W.Stack a (L.delete a l) (L.delete a (t:r))) s
-- | runOrCopy will run the provided shell command unless it can
-- find a specified window in which case it will copy the window to
-- the current workspace. Similar to (i.e., stolen from) "XMonad.Actions.WindowGo".
runOrCopy :: String -> Query Bool -> X ()
runOrCopy = copyMaybe . spawn
-- | Copy a window if it exists, run the first argument otherwise.
copyMaybe :: X () -> Query Bool -> X ()
copyMaybe f qry = ifWindow qry copyWin f
where copyWin = ask >>= \w -> doF (\ws -> copyWindow w (W.currentTag ws) ws)
-- | Remove the focused window from this workspace. If it's present in no
-- other workspace, then kill it instead. If we do kill it, we'll get a
-- delete notify back from X.
--
-- There are two ways to delete a window. Either just kill it, or if it
-- supports the delete protocol, send a delete event (e.g. firefox)
--
-- supports the delete protocol, send a delete event (e.g. firefox).
kill1 :: X ()
kill1 = do ss <- gets windowset
whenJust (peek ss) $ \w -> if member w $ delete'' w ss
whenJust (W.peek ss) $ \w -> if W.member w $ delete'' w ss
then windows $ delete'' w
else kill
where delete'' w = modify Nothing (filter (/= w))
where delete'' w = W.modify Nothing (W.filter (/= w))
-- | Kill all other copies of focused window (if they're present)
-- 'All other' means here 'copies, which are not on current workspace'
--
-- Consider calling this function after copyToAll
--
-- | Kill all other copies of focused window (if they're present).
-- 'All other' means here 'copies which are not on the current workspace'.
killAllOtherCopies :: X ()
killAllOtherCopies = do ss <- gets windowset
whenJust (peek ss) $ \w -> windows $
view (currentTag ss) .
whenJust (W.peek ss) $ \w -> windows $
W.view (W.currentTag ss) .
delFromAllButCurrent w
where
delFromAllButCurrent w ss = foldr ($) ss $
map (delWinFromWorkspace w . tag) $
hidden ss ++ map workspace (visible ss)
delWinFromWorkspace w wid ss = modify Nothing (filter (/= w)) $ view wid ss
map (delWinFromWorkspace w . W.tag) $
W.hidden ss ++ map W.workspace (W.visible ss)
delWinFromWorkspace w wid = W.modify Nothing (W.filter (/= w)) . W.view wid
-- | A list of hidden workspaces containing a copy of the focused window.
wsContainingCopies :: X [WorkspaceId]
wsContainingCopies = do
ws <- gets windowset
return $ copiesOfOn (W.peek ws) (taggedWindows $ W.hidden ws)
-- | Get a list of tuples (tag, [Window]) for each workspace.
taggedWindows :: [W.Workspace i l a] -> [(i, [a])]
taggedWindows = map $ W.tag &&& W.integrate' . W.stack
-- | Get tags with copies of the focused window (if present.)
copiesOfOn :: (Eq a) => Maybe a -> [(i, [a])] -> [i]
copiesOfOn foc tw = maybe [] hasCopyOf foc
where hasCopyOf f = map fst $ filter ((f `elem` ) . snd) tw

View File

@@ -30,7 +30,7 @@ import XMonad.StackSet
--
-- > import XMonad.Actions.CycleRecentWS
-- >
-- > , ((modMask x, xK_Tab), cycleRecentWS [xK_Alt_L] xK_Tab xK_grave)
-- > , ((modm, xK_Tab), cycleRecentWS [xK_Alt_L] xK_Tab xK_grave)
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".

View File

@@ -25,12 +25,12 @@ import qualified XMonad.StackSet as S
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
--
--
-- > import XMonad hiding ((|||))
-- > import XMonad.Layout.LayoutCombinators ((|||))
-- > import XMonad.Actions.CycleSelectedLayouts
--
-- > , ((modMask x, xK_t ), cycleThroughLayouts ["Tall", "Mirror Tall"])
-- > , ((modm, xK_t ), cycleThroughLayouts ["Tall", "Mirror Tall"])
--
-- Make sure you are using NewSelect from XMonad.Layout.LayoutCombinators,
-- rather than the Select defined in xmonad core.

View File

@@ -42,7 +42,11 @@ module XMonad.Actions.CycleWS (
, prevWS
, shiftToNext
, shiftToPrev
-- * Toggling the previous workspace
-- $toggling
, toggleWS
, toggleOrView
-- * Moving between screens (xinerama)
@@ -56,7 +60,7 @@ module XMonad.Actions.CycleWS (
-- * Moving between workspaces, take two!
-- $taketwo
, WSDirection(..)
, Direction1D(..)
, WSType(..)
, shiftTo
@@ -65,14 +69,18 @@ module XMonad.Actions.CycleWS (
-- * The mother-combinator
, findWorkspace
, toggleOrDoSkip
, skipTags
) where
import Control.Monad ( unless )
import Data.List ( findIndex )
import Data.Maybe ( isNothing, isJust )
import XMonad hiding (workspaces)
import XMonad.StackSet hiding (filter)
import XMonad.Util.Types
import XMonad.Util.WorkspaceCompare
-- $usage
@@ -82,27 +90,27 @@ import XMonad.Util.WorkspaceCompare
-- >
-- > -- a basic CycleWS setup
-- >
-- > , ((modMask x, xK_Down), nextWS)
-- > , ((modMask x, xK_Up), prevWS)
-- > , ((modMask x .|. shiftMask, xK_Down), shiftToNext)
-- > , ((modMask x .|. shiftMask, xK_Up), shiftToPrev)
-- > , ((modMask x, xK_Right), nextScreen)
-- > , ((modMask x, xK_Left), prevScreen)
-- > , ((modMask x .|. shiftMask, xK_Right), shiftNextScreen)
-- > , ((modMask x .|. shiftMask, xK_Left), shiftPrevScreen)
-- > , ((modMask x, xK_z), toggleWS)
-- > , ((modm, xK_Down), nextWS)
-- > , ((modm, xK_Up), prevWS)
-- > , ((modm .|. shiftMask, xK_Down), shiftToNext)
-- > , ((modm .|. shiftMask, xK_Up), shiftToPrev)
-- > , ((modm, xK_Right), nextScreen)
-- > , ((modm, xK_Left), prevScreen)
-- > , ((modm .|. shiftMask, xK_Right), shiftNextScreen)
-- > , ((modm .|. shiftMask, xK_Left), shiftPrevScreen)
-- > , ((modm, xK_z), toggleWS)
--
-- If you want to follow the moved window, you can use both actions:
--
-- > , ((modMask x .|. shiftMask, xK_Down), shiftToNext >> nextWS)
-- > , ((modMask x .|. shiftMask, xK_Up), shiftToPrev >> prevWS)
-- > , ((modm .|. shiftMask, xK_Down), shiftToNext >> nextWS)
-- > , ((modm .|. shiftMask, xK_Up), shiftToPrev >> prevWS)
--
-- You can also get fancier with 'moveTo', 'shiftTo', and 'findWorkspace'.
-- For example:
--
-- > , ((modMask x , xK_f), moveTo Next EmptyWS) -- find a free workspace
-- > , ((modMask x .|. controlMask, xK_Right), -- a crazy keybinding!
-- > do t <- findWorkspace getXineramaWsCompare Next NonEmptyWS 2
-- > , ((modm , xK_f), moveTo Next EmptyWS) -- find a free workspace
-- > , ((modm .|. controlMask, xK_Right), -- a crazy keybinding!
-- > do t <- findWorkspace getSortByXineramaRule Next NonEmptyWS 2
-- > windows . view $ t )
--
-- For detailed instructions on editing your key bindings, see
@@ -135,9 +143,47 @@ shiftToNext = shiftBy 1
shiftToPrev :: X ()
shiftToPrev = shiftBy (-1)
-- $toggling
-- | Toggle to the workspace displayed previously.
toggleWS :: X ()
toggleWS = windows $ view =<< tag . head . hidden
toggleWS = do
hs <- gets (hidden . windowset)
unless (null hs) (windows . view . tag $ head hs)
-- | 'XMonad.StackSet.greedyView' a workspace, or if already there, view
-- the previously displayed workspace ala weechat. Change @greedyView@ to
-- @toggleOrView@ in your workspace bindings as in the 'XMonad.StackSet.view'
-- faq at <http://haskell.org/haskellwiki/Xmonad/Frequently_asked_questions>.
-- For more flexibility see 'toggleOrDoSkip'.
toggleOrView :: WorkspaceId -> X ()
toggleOrView = toggleOrDoSkip [] greedyView
-- | Allows ignoring listed workspace tags (such as scratchpad's \"NSP\") while
-- finding the previously displayed workspace, or choice of different actions,
-- like view, shift, etc. For example:
--
-- > import qualified XMonad.StackSet as W
-- > import XMonad.Actions.CycleWS
-- >
-- > -- toggleOrView for people who prefer view to greedyView
-- > toggleOrView' = toggleOrDoSkip [] W.view
-- >
-- > -- toggleOrView ignoring scratchpad and named scratchpad workspace
-- > toggleOrViewNoSP = toggleOrDoSkip ["NSP"] W.greedyView
toggleOrDoSkip :: [WorkspaceId] -> (WorkspaceId -> WindowSet -> WindowSet)
-> WorkspaceId -> X ()
toggleOrDoSkip skips f toWS = do
ws <- gets windowset
let hs' = hidden ws `skipTags` skips
if toWS == (tag . workspace $ current ws)
then unless (null hs') (windows . f . tag $ head hs')
else windows (f toWS)
-- | List difference ('\\') for workspaces and tags. Removes workspaces
-- matching listed tags from the given workspace list.
skipTags :: (Eq i) => [Workspace i l a] -> [i] -> [Workspace i l a]
skipTags wss ids = filter ((`notElem` ids) . tag) wss
switchWorkspace :: Int -> X ()
switchWorkspace d = wsBy d >>= windows . greedyView
@@ -166,13 +212,10 @@ the letter 'p' in its name. =)
-}
-- | Direction to cycle through the sort order.
data WSDirection = Next | Prev
-- | What type of workspaces should be included in the cycle?
data WSType = EmptyWS -- ^ cycle through empty workspaces
| NonEmptyWS -- ^ cycle through non-empty workspaces
| HiddenWS -- ^ cycle through non-visible workspaces
| HiddenWS -- ^ cycle through non-visible workspaces
| HiddenNonEmptyWS -- ^ cycle through non-empty non-visible workspaces
| AnyWS -- ^ cycle through all workspaces
| WSIs (X (WindowSpace -> Bool))
@@ -186,19 +229,19 @@ wsTypeToPred NonEmptyWS = return (isJust . stack)
wsTypeToPred HiddenWS = do hs <- gets (map tag . hidden . windowset)
return (\w -> tag w `elem` hs)
wsTypeToPred HiddenNonEmptyWS = do ne <- wsTypeToPred NonEmptyWS
hi <- wsTypeToPred HiddenWS
hi <- wsTypeToPred HiddenWS
return (\w -> hi w && ne w)
wsTypeToPred AnyWS = return (const True)
wsTypeToPred (WSIs p) = p
-- | View the next workspace in the given direction that satisfies
-- the given condition.
moveTo :: WSDirection -> WSType -> X ()
moveTo :: Direction1D -> WSType -> X ()
moveTo dir t = findWorkspace getSortByIndex dir t 1 >>= windows . greedyView
-- | Move the currently focused window to the next workspace in the
-- given direction that satisfies the given condition.
shiftTo :: WSDirection -> WSType -> X ()
shiftTo :: Direction1D -> WSType -> X ()
shiftTo dir t = findWorkspace getSortByIndex dir t 1 >>= windows . shift
-- | Given a function @s@ to sort workspaces, a direction @dir@, a
@@ -214,7 +257,7 @@ shiftTo dir t = findWorkspace getSortByIndex dir t 1 >>= windows . shift
-- that 'moveTo' and 'shiftTo' are implemented by applying @(>>=
-- (windows . greedyView))@ and @(>>= (windows . shift))@, respectively,
-- to the output of 'findWorkspace'.
findWorkspace :: X WorkspaceSort -> WSDirection -> WSType -> Int -> X WorkspaceId
findWorkspace :: X WorkspaceSort -> Direction1D -> WSType -> Int -> X WorkspaceId
findWorkspace s dir t n = findWorkspaceGen s (wsTypeToPred t) (maybeNegate dir n)
where
maybeNegate Next d = d
@@ -229,7 +272,7 @@ findWorkspaceGen sortX wsPredX d = do
let cur = workspace (current ws)
sorted = sort (workspaces ws)
pivoted = let (a,b) = span ((/= (tag cur)) . tag) sorted in b ++ a
ws' = filter wsPred $ pivoted
ws' = filter wsPred pivoted
mCurIx = findWsIndex cur ws'
d' = if d > 0 then d - 1 else d
next = if null ws'

View File

@@ -0,0 +1,233 @@
--------------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.CycleWindows
-- Copyright : (c) Wirt Wolff <wirtwolff@gmail.com>
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : Wirt Wolff <wirtwolff@gmail.com>
-- Stability : unstable
-- Portability : unportable
--
-- Provides bindings to cycle windows up or down on the current workspace
-- stack while maintaining focus in place.
--
-- Bindings are available to:
--
-- * Cycle nearby or nth windows into the focused frame
--
-- * Cycle a window halfway around the stack
--
-- * Cycle windows through the focused position.
--
-- * Cycle unfocused windows.
--
-- These bindings are especially useful with layouts that hide some of
-- the windows in the stack, such as Full, "XMonad.Layout.TwoPane" or
-- when using "XMonad.Layout.LimitWindows" to only show three or four
-- panes. See also "XMonad.Actions.RotSlaves" for related actions.
-----------------------------------------------------------------------------
module XMonad.Actions.CycleWindows (
-- * Usage
-- $usage
-- * Cycling nearby or nth window into current frame
-- $cycle
cycleRecentWindows,
cycleStacks',
-- * Cycling half the stack to get rid of a boring window
-- $opposite
rotOpposite', rotOpposite,
-- * Cycling windows through the current frame
-- $focused
rotFocused', rotFocusedUp, rotFocusedDown, shiftToFocus',
-- * Cycling windows through other frames
-- $unfocused
rotUnfocused', rotUnfocusedUp, rotUnfocusedDown,
-- * Updating the mouse pointer
-- $pointer
-- * Generic list rotations
-- $generic
rotUp, rotDown
) where
import XMonad
import qualified XMonad.StackSet as W
import XMonad.Actions.RotSlaves
import Control.Arrow (second)
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@ file:
--
-- > import XMonad.Actions.CycleWindows
-- > -- config
-- > -- other key bindings with x here your config
-- >
-- > -- make sure mod matches keysym
-- > , ((mod4Mask, xK_s), cycleRecentWindows [xK_Super_L] xK_s xK_w)
-- > , ((modm, xK_z), rotOpposite)
-- > , ((modm , xK_i), rotUnfocusedUp)
-- > , ((modm , xK_u), rotUnfocusedDown)
-- > , ((modm .|. controlMask, xK_i), rotFocusedUp)
-- > , ((modm .|. controlMask, xK_u), rotFocusedDown)
--
-- Also, if you use focus follows mouse, you will want to read the section
-- on updating the mouse pointer below. For detailed instructions on
-- editing your key bindings, see "XMonad.Doc.Extending#Editing_key_bindings".
{- $pointer
With FocusFollowsMouse == True, the focus is updated after binding
actions, possibly focusing a window you didn't intend to focus. Most
people using TwoPane probably already have a logHook causing the mouse
to follow focus. (See "XMonad.Actions.UpdatePointer", or "XMonad.Actions.Warp")
If you want this built into the key binding instead, use the appropriate
action from one of those modules to also have your bindings move the pointer
to the point of your choice on the current window:
> import XMonad.Actions.UpdatePointer -- or Actions.Warp
and either
> -- modify the window rotation bindings
> , ((modm .|. controlMask, xK_i ), rotFocusedUp
> >> updatePointer (Relative 1 1))
> , ((modm .|. controlMask, xK_u ), rotFocusedDown
> >> updatePointer (Relative 1 1))
>
> -- or add to xmonad's logHook
> , logHook = dynamicLogWithPP xmobarPP
> >> updatePointer Nearest -- or your preference
-}
-- $cycle
-- Cycle windows into focus from below or above the focused pane by pressing
-- a key while one or more modifier keys is held down. The window order isn't
-- changed until a modifier is released, leaving the previously focused window
-- just below the new one, (or above if the window just above is chosen.) For
-- best results use the same modifier + key combination as the one used to invoke
-- the \"bring from below\" action. Also, once cycling, pressing a number key n
-- will focus the nth window, with 0 being the one originally focused.
cycleRecentWindows :: [KeySym] -- ^ A list of modifier keys used when invoking this action.
-- As soon as one of them is released, the final switch is made.
-> KeySym -- ^ Key used to shift windows from below the current choice into the current frame.
-> KeySym -- ^ Key used to shift windows from above the current choice into the current frame.
-- If it's the same as the first key, it is effectively ignored.
-> X ()
cycleRecentWindows = cycleStacks' stacks where
stacks s = map (shiftToFocus' `flip` s) (wins s)
wins (W.Stack t l r) = t : r ++ reverse l
-- | Cycle through a /finite/ list of window stacks with repeated presses
-- of a key while a modifier key is held down. For best results use the same
-- mod key + key combination as the one used to invoke the \"bring from below\"
-- action. You could use cycleStacks' with a different stack permutations
-- function to, for example, cycle from one below to one above to two below,
-- etc. instead of in order. You are responsible for having it generate a
-- finite list, though, or xmonad may hang seeking its length.
cycleStacks' :: (W.Stack Window -> [W.Stack Window]) -- ^ A function to a finite list of permutations of a given stack.
-> [KeySym] -- ^ A list of modifier keys used to invoke 'cycleStacks''.
-- As soon as any is released, we're no longer cycling on the [Stack Window]
-> KeySym -- ^ Key used to select a \"next\" stack.
-> KeySym -- ^ Key used to select a \"previous\" stack.
-> X ()
cycleStacks' filteredPerms mods keyNext keyPrev = do
XConf {theRoot = root, display = d} <- ask
stacks <- gets $ maybe [] filteredPerms . W.stack . W.workspace . W.current . windowset
let evt = allocaXEvent $
\p -> do maskEvent d (keyPressMask .|. keyReleaseMask) p
KeyEvent {ev_event_type = t, ev_keycode = c} <- getEvent p
s <- keycodeToKeysym d c 0
return (t, s)
choose n (t, s)
| t == keyPress && s == keyNext = io evt >>= choose (n+1)
| t == keyPress && s == keyPrev = io evt >>= choose (n-1)
| t == keyPress && s `elem` [xK_0..xK_9] = io evt >>= choose (numKeyToN s)
| t == keyRelease && s `elem` mods = return ()
| otherwise = doStack n >> io evt >>= choose n
doStack n = windows . W.modify' . const $ stacks `cycref` n
io $ grabKeyboard d root False grabModeAsync grabModeAsync currentTime
io evt >>= choose 1
io $ ungrabKeyboard d currentTime
where cycref l i = l !! (i `mod` length l) -- modify' ensures l is never [], but must also be finite
numKeyToN = subtract 48 . read . show
-- | Given a stack element and a stack, shift or insert the element (window)
-- at the currently focused position.
shiftToFocus' :: (Eq a, Show a, Read a) => a -> W.Stack a -> W.Stack a
shiftToFocus' w s@(W.Stack _ ls _) = W.Stack w (reverse revls') rs'
where (revls', rs') = splitAt (length ls) . filter (/= w) $ W.integrate s
-- $opposite
-- Shifts the focused window as far as possible from the current focus,
-- i.e. halfway around the stack. Windows above the focus up to the \"opposite\"
-- position remain in place, while those above the insertion shift toward
-- the current focus. This is useful for people who use lots of windows in Full,
-- TwoPane, etc., to get rid of boring windows while cycling and swapping
-- near the focus.
rotOpposite :: X()
rotOpposite = windows $ W.modify' rotOpposite'
-- | The opposite rotation on a Stack.
rotOpposite' :: W.Stack a -> W.Stack a
rotOpposite' (W.Stack t l r) = W.Stack t' l' r'
where rrvl = r ++ reverse l
part = (length rrvl + 1) `div` 2
(l',t':r') = second reverse . splitAt (length l) $
reverse (take part rrvl ++ t : drop part rrvl)
-- $focused
-- Most people will want the @rotAllUp@ or @rotAllDown@ actions from
-- "XMonad.Actions.RotSlaves" to cycle all windows in the stack.
--
-- The following actions keep the \"next\" window stable, which is
-- mostly useful in two window layouts, or when you have a log viewer or
-- buffer window you want to keep next to the cycled window.
-- | Rotate windows through the focused frame, excluding the \"next\" window.
-- With, e.g. TwoPane, this allows cycling windows through either the
-- master or slave pane, without changing the other frame. When the master
-- is focused, the window below is skipped, when a non-master window is
-- focused, the master is skipped.
rotFocusedUp :: X ()
rotFocusedUp = windows . W.modify' $ rotFocused' rotUp
rotFocusedDown :: X ()
rotFocusedDown = windows . W.modify' $ rotFocused' rotDown
-- | The focused rotation on a stack.
rotFocused' :: ([a] -> [a]) -> W.Stack a -> W.Stack a
rotFocused' _ s@(W.Stack _ [] []) = s
rotFocused' f (W.Stack t [] (r:rs)) = W.Stack t' [] (r:rs') -- Master has focus
where (t':rs') = f (t:rs)
rotFocused' f s@(W.Stack _ _ _) = rotSlaves' f s -- otherwise
-- $unfocused
-- Rotate windows through the unfocused frames. This is similar to
-- @rotSlaves@, from "XMonad.Actions.RotSlaves", but excludes the current
-- frame rather than master.
rotUnfocusedUp :: X ()
rotUnfocusedUp = windows . W.modify' $ rotUnfocused' rotUp
rotUnfocusedDown :: X ()
rotUnfocusedDown = windows . W.modify' $ rotUnfocused' rotDown
-- | The unfocused rotation on a stack.
rotUnfocused' :: ([a] -> [a]) -> W.Stack a -> W.Stack a
rotUnfocused' _ s@(W.Stack _ [] []) = s
rotUnfocused' f s@(W.Stack _ [] _ ) = rotSlaves' f s -- Master has focus
rotUnfocused' f (W.Stack t ls rs) = W.Stack t (reverse revls') rs' -- otherwise
where (master:revls) = reverse ls
(revls',rs') = splitAt (length ls) (f $ master:revls ++ rs)
-- $generic
-- Generic list rotations
rotUp :: [a] -> [a]
rotUp l = tail l ++ [head l]
rotDown :: [a] -> [a]
rotDown l = last l : init l

View File

@@ -5,12 +5,13 @@
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : Spencer Janssen <spencerjanssen@gmail.com>
-- Stability : unstable
-- Stability : stable
-- Portability : unportable
--
-- This module provides a method to cease management of a window
-- without unmapping it. This is especially useful for applications
-- like kicker and gnome-panel.
-- like kicker and gnome-panel. See also "XMonad.Hooks.ManageDocks" for
-- more a more automated solution.
--
-- To make a panel display correctly with xmonad:
--
@@ -43,7 +44,7 @@ import XMonad
--
-- And add a keybinding, such as:
--
-- > , ((modMask x, xK_d ), withFocused demanage)
-- > , ((modm, xK_d ), withFocused demanage)
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".

View File

@@ -5,7 +5,7 @@
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : arcatan@kapsi.fi
-- Stability : unstable
-- Stability : stable
-- Portability : unportable
--
-- Dwm-like swap function for xmonad.
@@ -33,7 +33,7 @@ import XMonad.StackSet
--
-- then add a keybinding or substitute 'dwmpromote' in place of promote:
--
-- > , ((modMask x, xK_Return), dwmpromote)
-- > , ((modm, xK_Return), dwmpromote)
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".

View File

@@ -36,18 +36,18 @@ import XMonad.Util.WorkspaceCompare ( getSortByIndex )
--
-- Then add keybindings like the following:
--
-- > , ((modMask x .|. shiftMask, xK_BackSpace), removeWorkspace)
-- > , ((modMask x .|. shiftMask, xK_v ), selectWorkspace defaultXPConfig)
-- > , ((modMask x, xK_m ), withWorkspace defaultXPConfig (windows . W.shift))
-- > , ((modMask x .|. shiftMask, xK_m ), withWorkspace defaultXPConfig (windows . copy))
-- > , ((modMask x .|. shiftMask, xK_r ), renameWorkspace defaultXPConfig)
-- > , ((modm .|. shiftMask, xK_BackSpace), removeWorkspace)
-- > , ((modm .|. shiftMask, xK_v ), selectWorkspace defaultXPConfig)
-- > , ((modm, xK_m ), withWorkspace defaultXPConfig (windows . W.shift))
-- > , ((modm .|. shiftMask, xK_m ), withWorkspace defaultXPConfig (windows . copy))
-- > , ((modm .|. shiftMask, xK_r ), renameWorkspace defaultXPConfig)
--
-- > -- mod-[1..9] %! Switch to workspace N
-- > -- mod-shift-[1..9] %! Move client to workspace N
-- > ++
-- > zip (zip (repeat (modMask x)) [xK_1..xK_9]) (map (withNthWorkspace W.greedyView) [0..])
-- > zip (zip (repeat (modm)) [xK_1..xK_9]) (map (withNthWorkspace W.greedyView) [0..])
-- > ++
-- > zip (zip (repeat (modMask x .|. shiftMask)) [xK_1..xK_9]) (map (withNthWorkspace W.shift) [0..])
-- > zip (zip (repeat (modm .|. shiftMask)) [xK_1..xK_9]) (map (withNthWorkspace W.shift) [0..])
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".

View File

@@ -5,7 +5,7 @@
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : arcatan@kapsi.fi
-- Stability : unstable
-- Stability : stable
-- Portability : unportable
--
-- Find an empty workspace.
@@ -32,8 +32,8 @@ import XMonad.StackSet
--
-- and add the desired keybindings, for example:
--
-- > , ((modMask x, xK_m ), viewEmptyWorkspace)
-- > , ((modMask x .|. shiftMask, xK_m ), tagToEmptyWorkspace)
-- > , ((modm, xK_m ), viewEmptyWorkspace)
-- > , ((modm .|. shiftMask, xK_m ), tagToEmptyWorkspace)
--
-- Now you can jump to an empty workspace with @mod-m@. @Mod-shift-m@
-- will tag the current window to an empty workspace and view it.

View File

@@ -7,7 +7,7 @@
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : <mgsloan@gmail.com>
-- Stability : unstable
-- Stability : stable
-- Portability : unportable
--
-- Move and resize floating windows without warping the mouse.
@@ -31,7 +31,7 @@ import XMonad
--
-- Now set up the desired mouse binding, for example:
--
-- > , ((modMask x, button1), (\w -> focus w >> Flex.mouseWindow Flex.linear w))
-- > , ((modm, button1), (\w -> focus w >> Flex.mouseWindow Flex.linear w))
--
-- * Flex.'linear' indicates that positions between the edges and the
-- middle indicate a combination scale\/position.

View File

@@ -15,7 +15,8 @@
module XMonad.Actions.FlexibleResize (
-- * Usage
-- $usage
XMonad.Actions.FlexibleResize.mouseResizeWindow
XMonad.Actions.FlexibleResize.mouseResizeWindow,
XMonad.Actions.FlexibleResize.mouseResizeEdgeWindow
) where
import XMonad
@@ -28,40 +29,53 @@ import Foreign.C.Types
--
-- Then add an appropriate mouse binding:
--
-- > , ((modMask x, button3), (\w -> focus w >> Flex.mouseResizeWindow w))
-- > , ((modm, button3), (\w -> focus w >> Flex.mouseResizeWindow w))
--
-- For detailed instructions on editing your mouse bindings, see
-- "XMonad.Doc.Extending#Editing_mouse_bindings".
-- | Resize a floating window from whichever corner the mouse is
-- closest to.
mouseResizeWindow :: Window -> X ()
mouseResizeWindow w = whenX (isClient w) $ withDisplay $ \d -> do
mouseResizeWindow
:: Window -- ^ The window to resize.
-> X ()
mouseResizeWindow = mouseResizeEdgeWindow 0
-- | Resize a floating window from whichever corner or edge the mouse is
-- closest to.
mouseResizeEdgeWindow
:: Rational -- ^ The size of the area where only one edge is resized.
-> Window -- ^ The window to resize.
-> X ()
mouseResizeEdgeWindow edge w = whenX (isClient w) $ withDisplay $ \d -> do
io $ raiseWindow d w
wa <- io $ getWindowAttributes d w
sh <- io $ getWMNormalHints d w
(_, _, _, _, _, ix, iy, _) <- io $ queryPointer d w
let
[pos_x, pos_y, width, height] = map (fromIntegral . ($ wa)) [wa_x, wa_y, wa_width, wa_height]
west = firstHalf ix width
north = firstHalf iy height
[pos_x, pos_y, width, height] = map (fi . ($ wa)) [wa_x, wa_y, wa_width, wa_height]
west = findPos ix width
north = findPos iy height
(cx, fx, gx) = mkSel west width pos_x
(cy, fy, gy) = mkSel north height pos_y
io $ warpPointer d none w 0 0 0 0 cx cy
mouseDrag (\ex ey -> do
wa' <- io $ getWindowAttributes d w
let [px, py] = map (fromIntegral . ($ wa')) [wa_x, wa_y]
io $ moveResizeWindow d w (fx px (fromIntegral ex))
(fy py (fromIntegral ey))
`uncurry` applySizeHintsContents sh (gx $ fromIntegral ex, gy $ fromIntegral ey))
mouseDrag (\ex ey -> do let (nw,nh) = applySizeHintsContents sh (gx ex, gy ey)
io $ moveResizeWindow d w (fx nw) (fy nh) nw nh)
(float w)
where
firstHalf :: CInt -> Position -> Bool
firstHalf a b = fromIntegral a * 2 <= b
cfst = curry fst
csnd = curry snd
mkSel :: Bool -> Position -> Position -> (Position, a -> a -> a, CInt -> Position)
mkSel b k p =
if b
then (0, csnd, ((k + p) -) . fromIntegral)
else (k, cfst, subtract p . fromIntegral)
findPos :: CInt -> Position -> Maybe Bool
findPos m s = if p < 0.5 - edge/2
then Just True
else if p < 0.5 + edge/2
then Nothing
else Just False
where p = fi m / fi s
mkSel :: Maybe Bool -> Position -> Position -> (Position, Dimension -> Position, Position -> Dimension)
mkSel b k p = case b of
Just True -> (0, (fi k + fi p -).fi, (fi k + fi p -).fi)
Nothing -> (k `div` 2, const p, const $ fi k)
Just False -> (k, const p, subtract (fi p) . fi)
fi :: (Num b, Integral a) => a -> b
fi = fromIntegral

View File

@@ -5,7 +5,7 @@
-- License : BSD
--
-- Maintainer : Karsten Schoelzel <kuser@gmx.de>
-- Stability : unstable
-- Stability : stable
-- Portability : unportable
--
-- Move and resize floating windows.
@@ -28,11 +28,11 @@ import XMonad
--
-- Then add appropriate key bindings, for example:
--
-- > , ((modMask x, xK_d ), withFocused (keysResizeWindow (-10,-10) (1,1)))
-- > , ((modMask x, xK_s ), withFocused (keysResizeWindow (10,10) (1,1)))
-- > , ((modMask x .|. shiftMask, xK_d ), withFocused (keysAbsResizeWindow (-10,-10) (1024,752)))
-- > , ((modMask x .|. shiftMask, xK_s ), withFocused (keysAbsResizeWindow (10,10) (1024,752)))
-- > , ((modMask x, xK_a ), withFocused (keysMoveWindowTo (512,384) (1%2,1%2)))
-- > , ((modm, xK_d ), withFocused (keysResizeWindow (-10,-10) (1,1)))
-- > , ((modm, xK_s ), withFocused (keysResizeWindow (10,10) (1,1)))
-- > , ((modm .|. shiftMask, xK_d ), withFocused (keysAbsResizeWindow (-10,-10) (1024,752)))
-- > , ((modm .|. shiftMask, xK_s ), withFocused (keysAbsResizeWindow (10,10) (1024,752)))
-- > , ((modm, xK_a ), withFocused (keysMoveWindowTo (512,384) (1%2,1%2)))
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".

328
XMonad/Actions/FloatSnap.hs Normal file
View File

@@ -0,0 +1,328 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Layout.FloatSnap
-- Copyright : (c) 2009 Anders Engstrom <ankaan@gmail.com>
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : Anders Engstrom <ankaan@gmail.com>
-- Stability : unstable
-- Portability : unportable
--
-- Move and resize floating windows using other windows and the edge of the
-- screen as guidelines.
-----------------------------------------------------------------------------
module XMonad.Actions.FloatSnap (
-- * Usage
-- $usage
Direction2D(..),
snapMove,
snapGrow,
snapShrink,
snapMagicMove,
snapMagicResize,
snapMagicMouseResize) where
import XMonad
import Control.Applicative((<$>))
import Data.List (sort)
import Data.Maybe (listToMaybe,fromJust,isNothing)
import qualified XMonad.StackSet as W
import XMonad.Hooks.ManageDocks (calcGap)
import XMonad.Util.Types (Direction2D(..))
import qualified Data.Set as S
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
--
-- > import XMonad.Actions.FloatSnap
--
-- Then add appropriate key bindings, for example:
--
-- > , ((modm, xK_Left), withFocused $ snapMove L Nothing)
-- > , ((modm, xK_Right), withFocused $ snapMove R Nothing)
-- > , ((modm, xK_Up), withFocused $ snapMove U Nothing)
-- > , ((modm, xK_Down), withFocused $ snapMove D Nothing)
-- > , ((modm .|. shiftMask, xK_Left), withFocused $ snapShrink R Nothing)
-- > , ((modm .|. shiftMask, xK_Right), withFocused $ snapGrow R Nothing)
-- > , ((modm .|. shiftMask, xK_Up), withFocused $ snapShrink D Nothing)
-- > , ((modm .|. shiftMask, xK_Down), withFocused $ snapGrow D Nothing)
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
--
-- And possibly add an appropriate mouse binding, for example:
--
-- > , ((modm, button1), (\w -> focus w >> mouseMoveWindow w >> snapMagicMove (Just 50) (Just 50) w))
-- > , ((modm .|. shiftMask, button1), (\w -> focus w >> mouseMoveWindow w >> snapMagicResize [L,R,U,D] (Just 50) (Just 50) w))
-- > , ((modm, button3), (\w -> focus w >> mouseResizeWindow w >> snapMagicResize [R,D] (Just 50) (Just 50) w))
--
-- For detailed instructions on editing your mouse bindings, see
-- "XMonad.Doc.Extending#Editing_mouse_bindings".
--
-- Using these mouse bindings, it will not snap while moving, but allow you to click the window once after it has been moved or resized to snap it into place.
-- Note that the order in which the commands are applied in the mouse bindings are important.
--
-- Interesting values for the distance to look for window in the orthogonal axis are Nothing (to snap against every window), Just 0 (to only snap
-- against windows that we should collide with geometrically while moving) and Just 1 (to also snap against windows we brush against).
--
-- For 'snapMagicMove', 'snapMagicResize' and 'snapMagicMouseResize', try instead setting it to the same as the maximum snapping distance.
--
-- When a value is specified it can be geometrically conceived as adding a border with the specified width around the window and then checking which
-- windows it should collide with.
-- | Resize the window by each edge independently to snap against the closest part of other windows or the edge of the screen. Use the location of the
-- mouse over the window to decide which edges to snap. In corners, the two adjoining edges will be snapped, along the middle of an edge only that edge
-- will be snapped. In the center of the window all edges will snap. Intended to be used together with "XMonad.Actions.FlexibleResize" or
-- "XMonad.Actions.FlexibleManipulate".
snapMagicMouseResize
:: Rational -- ^ How big the middle snap area of each axis should be.
-> Maybe Int -- ^ The distance in the orthogonal axis to look for windows to snap against. Use Nothing to snap against every window.
-> Maybe Int -- ^ The maximum distance to snap. Use Nothing to not impose any boundary.
-> Window -- ^ The window to move and resize.
-> X ()
snapMagicMouseResize middle collidedist snapdist w = whenX (isClient w) $ withDisplay $ \d -> do
wa <- io $ getWindowAttributes d w
(_, _, _, px, py, _, _, _) <- io $ queryPointer d w
let x = (fromIntegral px - wx wa)/(ww wa)
y = (fromIntegral py - wy wa)/(wh wa)
ml = if x <= (0.5 - middle/2) then [L] else []
mr = if x > (0.5 + middle/2) then [R] else []
mu = if y <= (0.5 - middle/2) then [U] else []
md = if y > (0.5 + middle/2) then [D] else []
mdir = ml++mr++mu++md
dir = if mdir == []
then [L,R,U,D]
else mdir
snapMagicResize dir collidedist snapdist w
where
wx = fromIntegral.wa_x
wy = fromIntegral.wa_y
ww = fromIntegral.wa_width
wh = fromIntegral.wa_height
-- | Resize the window by each edge independently to snap against the closest part of other windows or the edge of the screen.
snapMagicResize
:: [Direction2D] -- ^ The edges to snap.
-> Maybe Int -- ^ The distance in the orthogonal axis to look for windows to snap against. Use Nothing to snap against every window.
-> Maybe Int -- ^ The maximum distance to snap. Use Nothing to not impose any boundary.
-> Window -- ^ The window to move and resize.
-> X ()
snapMagicResize dir collidedist snapdist w = whenX (isClient w) $ withDisplay $ \d -> do
io $ raiseWindow d w
wa <- io $ getWindowAttributes d w
(xbegin,xend) <- handleAxis True d wa
(ybegin,yend) <- handleAxis False d wa
let xbegin' = if L `elem` dir then xbegin else (wx wa)
xend' = if R `elem` dir then xend else (wx wa + ww wa)
ybegin' = if U `elem` dir then ybegin else (wy wa)
yend' = if D `elem` dir then yend else (wy wa + wh wa)
io $ moveWindow d w (fromIntegral $ xbegin') (fromIntegral $ ybegin')
io $ resizeWindow d w (fromIntegral $ xend' - xbegin') (fromIntegral $ yend' - ybegin')
float w
where
wx = fromIntegral.wa_x
wy = fromIntegral.wa_y
ww = fromIntegral.wa_width
wh = fromIntegral.wa_height
handleAxis horiz d wa = do
((mbl,mbr,bs),(mfl,mfr,fs)) <- getSnap horiz collidedist d w
let begin = if bs
then wpos wa
else case (mbl,mbr) of
(Just bl,Just br) -> if wpos wa - bl < br - wpos wa then bl else br
(Just bl,Nothing) -> bl
(Nothing,Just br) -> br
(Nothing,Nothing) -> wpos wa
end = if fs
then wpos wa + wdim wa
else case (if mfl==(Just begin) then Nothing else mfl,mfr) of
(Just fl,Just fr) -> if wpos wa + wdim wa - fl < fr - wpos wa - wdim wa then fl else fr
(Just fl,Nothing) -> fl
(Nothing,Just fr) -> fr
(Nothing,Nothing) -> wpos wa + wdim wa
begin' = if isNothing snapdist || abs (begin - wpos wa) <= fromJust snapdist then begin else (wpos wa)
end' = if isNothing snapdist || abs (end - wpos wa - wdim wa) <= fromJust snapdist then end else (wpos wa + wdim wa)
return (begin',end')
where
(wpos, wdim, _, _) = constructors horiz
-- | Move a window by both axises in any direction to snap against the closest part of other windows or the edge of the screen.
snapMagicMove
:: Maybe Int -- ^ The distance in the orthogonal axis to look for windows to snap against. Use Nothing to snap against every window.
-> Maybe Int -- ^ The maximum distance to snap. Use Nothing to not impose any boundary.
-> Window -- ^ The window to move.
-> X ()
snapMagicMove collidedist snapdist w = whenX (isClient w) $ withDisplay $ \d -> do
io $ raiseWindow d w
wa <- io $ getWindowAttributes d w
nx <- handleAxis True d wa
ny <- handleAxis False d wa
io $ moveWindow d w (fromIntegral nx) (fromIntegral ny)
float w
where
handleAxis horiz d wa = do
((mbl,mbr,bs),(mfl,mfr,fs)) <- getSnap horiz collidedist d w
return $ if bs || fs
then wpos wa
else let b = case (mbl,mbr) of
(Just bl,Just br) -> if wpos wa - bl < br - wpos wa then bl else br
(Just bl,Nothing) -> bl
(Nothing,Just br) -> br
(Nothing,Nothing) -> wpos wa
f = case (mfl,mfr) of
(Just fl,Just fr) -> if wpos wa + wdim wa - fl < fr - wpos wa - wdim wa then fl else fr
(Just fl,Nothing) -> fl
(Nothing,Just fr) -> fr
(Nothing,Nothing) -> wpos wa
newpos = if abs (b - wpos wa) <= abs (f - wpos wa - wdim wa) then b else (f - wdim wa)
in if isNothing snapdist || abs (newpos - wpos wa) <= fromJust snapdist then newpos else (wpos wa)
where
(wpos, wdim, _, _) = constructors horiz
-- | Move a window in the specified direction until it snaps against another window or the edge of the screen.
snapMove
:: Direction2D -- ^ What direction to move the window in.
-> Maybe Int -- ^ The distance in the orthogonal axis to look for windows to snap against. Use Nothing to snap against every window.
-> Window -- ^ The window to move.
-> X ()
snapMove L = doSnapMove True True
snapMove R = doSnapMove True False
snapMove U = doSnapMove False True
snapMove D = doSnapMove False False
doSnapMove :: Bool -> Bool -> Maybe Int -> Window -> X ()
doSnapMove horiz rev collidedist w = whenX (isClient w) $ withDisplay $ \d -> do
io $ raiseWindow d w
wa <- io $ getWindowAttributes d w
((bl,br,_),(fl,fr,_)) <- getSnap horiz collidedist d w
let (mb,mf) = if rev then (bl,fl)
else (br,fr)
newpos = fromIntegral $ case (mb,mf) of
(Just b,Nothing) -> b
(Nothing,Just f) -> f - wdim wa
(Just b,Just f) -> if rev /= (b < f - wdim wa)
then b
else f - wdim wa
_ -> wpos wa
if horiz then io $ moveWindow d w newpos (fromIntegral $ wa_y wa)
else io $ moveWindow d w (fromIntegral $ wa_x wa) newpos
float w
where
(wpos, wdim, _, _) = constructors horiz
-- | Grow the specified edge of a window until it snaps against another window or the edge of the screen.
snapGrow
:: Direction2D -- ^ What edge of the window to grow.
-> Maybe Int -- ^ The distance in the orthogonal axis to look for windows to snap against. Use Nothing to snap against every window.
-> Window -- ^ The window to grow.
-> X ()
snapGrow = snapResize True
-- | Shrink the specified edge of a window until it snaps against another window or the edge of the screen.
snapShrink
:: Direction2D -- ^ What edge of the window to shrink.
-> Maybe Int -- ^ The distance in the orthogonal axis to look for windows to snap against. Use Nothing to snap against every window.
-> Window -- ^ The window to shrink.
-> X ()
snapShrink = snapResize False
snapResize :: Bool -> Direction2D -> Maybe Int -> Window -> X ()
snapResize grow dir collidedist w = whenX (isClient w) $ withDisplay $ \d -> do
io $ raiseWindow d w
wa <- io $ getWindowAttributes d w
mr <- case dir of
L -> do ((mg,ms,_),(_,_,_)) <- getSnap True collidedist d w
return $ case (if grow then mg else ms) of
Just v -> Just (v, wy wa, ww wa + wx wa - v, wh wa)
_ -> Nothing
R -> do ((_,_,_),(ms,mg,_)) <- getSnap True collidedist d w
return $ case (if grow then mg else ms) of
Just v -> Just (wx wa, wy wa, v - wx wa, wh wa)
_ -> Nothing
U -> do ((mg,ms,_),(_,_,_)) <- getSnap False collidedist d w
return $ case (if grow then mg else ms) of
Just v -> Just (wx wa, v, ww wa, wh wa + wy wa - v)
_ -> Nothing
D -> do ((_,_,_),(ms,mg,_)) <- getSnap False collidedist d w
return $ case (if grow then mg else ms) of
Just v -> Just (wx wa, wy wa, ww wa, v - wy wa)
_ -> Nothing
case mr of
Nothing -> return ()
Just (nx,ny,nw,nh) -> if nw>0 && nh>0 then do io $ moveWindow d w (fromIntegral nx) (fromIntegral ny)
io $ resizeWindow d w (fromIntegral nw) (fromIntegral nh)
else return ()
float w
where
wx = fromIntegral.wa_x
wy = fromIntegral.wa_y
ww = fromIntegral.wa_width
wh = fromIntegral.wa_height
getSnap :: Bool -> Maybe Int -> Display -> Window -> X ((Maybe Int,Maybe Int,Bool),(Maybe Int,Maybe Int,Bool))
getSnap horiz collidedist d w = do
wa <- io $ getWindowAttributes d w
screen <- W.current <$> gets windowset
let sr = screenRect $ W.screenDetail screen
wl = W.integrate' . W.stack $ W.workspace screen
gr <- fmap ($sr) $ calcGap $ S.fromList [minBound .. maxBound]
wla <- filter (collides wa) `fmap` (io $ mapM (getWindowAttributes d) $ filter (/=w) wl)
return ( neighbours (back wa sr gr wla) (wpos wa)
, neighbours (front wa sr gr wla) (wpos wa + wdim wa)
)
where
wborder = fromIntegral.wa_border_width
(wpos, wdim, rpos, rdim) = constructors horiz
(refwpos, refwdim, _, _) = constructors $ not horiz
back wa sr gr wla = dropWhile (< rpos sr) $
takeWhile (< rpos sr + rdim sr) $
sort $ (rpos sr):(rpos gr):(rpos gr + rdim gr):
foldr (\a as -> (wpos a):(wpos a + wdim a + wborder a + wborder wa):as) [] wla
front wa sr gr wla = dropWhile (<= rpos sr) $
takeWhile (<= rpos sr + rdim sr) $
sort $ (rpos gr - 2*wborder wa):(rpos gr + rdim gr - 2*wborder wa):(rpos sr + rdim sr - 2*wborder wa):
foldr (\a as -> (wpos a - wborder a - wborder wa):(wpos a + wdim a):as) [] wla
neighbours l v = ( listToMaybe $ reverse $ takeWhile (< v) l
, listToMaybe $ dropWhile (<= v) l
, v `elem` l
)
collides wa oa = case collidedist of
Nothing -> True
Just dist -> ( refwpos oa - wborder oa < refwpos wa + refwdim wa + wborder wa + dist
&& refwpos wa - wborder wa - dist < refwpos oa + refwdim oa + wborder oa )
constructors :: Bool -> (WindowAttributes -> Int, WindowAttributes -> Int, Rectangle -> Int, Rectangle -> Int)
constructors True = ( fromIntegral.wa_x
, fromIntegral.wa_width
, fromIntegral.rect_x
, fromIntegral.rect_width
)
constructors False = ( fromIntegral.wa_y
, fromIntegral.wa_height
, fromIntegral.rect_y
, fromIntegral.rect_height
)

View File

@@ -5,7 +5,7 @@
-- License : BSD
--
-- Maintainer : Karsten Schoelzel <kuser@gmx.de>
-- Stability : unstable
-- Stability : stable
-- Portability : unportable
--
-- Focus the nth window of the current workspace.
@@ -14,7 +14,7 @@
module XMonad.Actions.FocusNth (
-- * Usage
-- $usage
focusNth) where
focusNth,focusNth') where
import XMonad.StackSet
import XMonad
@@ -27,7 +27,7 @@ import XMonad
-- Then add appropriate keybindings, for example:
--
-- > -- mod4-[1..9] @@ Switch to window N
-- > ++ [((modMask x, k), focusNth i)
-- > ++ [((modm, k), focusNth i)
-- > | (i, k) <- zip [0 .. 8] [xK_1 ..]]
--
-- For detailed instructions on editing your key bindings, see

View File

@@ -1,3 +1,4 @@
{-# LANGUAGE ScopedTypeVariables, GeneralizedNewtypeDeriving, TypeSynonymInstances, FlexibleInstances, OverlappingInstances #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.GridSelect
@@ -8,28 +9,55 @@
-- Stability : unstable
-- Portability : unportable
--
-- GridSelect displays a 2D grid of windows to navigate with cursor
-- keys and to select with return.
-- GridSelect displays items(e.g. the opened windows) in a 2D grid and lets
-- the user select from it with the cursor/hjkl keys or the mouse.
--
-----------------------------------------------------------------------------
module XMonad.Actions.GridSelect (
-- * Usage
-- $usage
-- ** Customizing
-- *** Using a common GSConfig
-- $commonGSConfig
-- *** Custom keybindings
-- $keybindings
-- * Configuration
GSConfig(..),
defaultGSConfig,
NavigateMap,
TwoDPosition,
buildDefaultGSConfig,
-- * Variations on 'gridselect'
gridselect,
gridselectWindow,
withSelectedWindow,
bringSelected,
goToSelected,
default_colorizer
spawnSelected,
runSelectedAction,
-- * Colorizers
HasColorizer(defaultColorizer),
fromClassName,
stringColorizer,
colorRangeFromClassName
-- * Screenshots
-- $screenshots
) where
import Data.Maybe
import Data.Bits
import Control.Applicative
import Control.Monad.State
import Control.Arrow
import Data.List as L
import XMonad
import qualified Data.Map as M
import XMonad hiding (liftX)
import XMonad.Util.Font
import XMonad.Prompt (mkUnmanagedWindow)
import XMonad.StackSet as W
@@ -37,6 +65,8 @@ import XMonad.Layout.Decoration
import XMonad.Util.NamedWindows
import XMonad.Actions.WindowBringer (bringWindow)
import Text.Printf
import System.Random (mkStdGen, genRange, next)
import Data.Word (Word8)
-- $usage
--
@@ -46,33 +76,150 @@ import Text.Printf
--
-- Then add a keybinding, e.g.
--
-- > , ((modMask x, xK_g), goToSelected defaultGSConfig)
-- > , ((modm, xK_g), goToSelected defaultGSConfig)
--
-- Screenshot: <http://clemens.endorphin.org/gridselect.png>
-- This module also supports displaying arbitrary information in a grid and letting
-- the user select from it. E.g. to spawn an application from a given list, you
-- can use the following:
--
-- > , ((modm, xK_s), spawnSelected defaultGSConfig ["xterm","gmplayer","gvim"])
data GSConfig = GSConfig {
-- $commonGSConfig
--
-- It is possible to bind a @gsconfig@ at top-level in your configuration. Like so:
--
-- > -- the top of your config
-- > {-# LANGUAGE NoMonomorphismRestriction #-}
-- > import XMonad
-- > ...
-- > 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 }
--
-- > -- | A green monochrome colorizer based on window class
-- > greenColorizer = colorRangeFromClassName
-- > black -- lowest inactive bg
-- > (0x70,0xFF,0x70) -- highest inactive bg
-- > black -- active bg
-- > white -- inactive fg
-- > white -- active fg
-- > where black = minBound
-- > white = maxBound
--
-- Then you can bind to:
--
-- > ,((modm, xK_g), goToSelected $ gsconfig2 myWinColorizer)
-- > ,((modm, xK_p), spawnSelected $ spawnSelected defaultColorizer)
-- $keybindings
--
-- Adding more keybindings for gridselect to listen to is similar:
--
-- At the top of your config:
--
-- > {-# LANGAUGE NoMonomorphismRestriction #-}
-- > import XMonad
-- > import qualified Data.Map as M
--
-- Then define @gsconfig3@ which may be used in exactly the same manner as @gsconfig1@:
--
-- > gsconfig3 = defaultGSConfig
-- > { gs_cellheight = 30
-- > , gs_cellwidth = 100
-- > , gs_navigate = M.unions
-- > [reset
-- > ,nethackKeys
-- > ,gs_navigate -- get the default navigation bindings
-- > $ defaultGSConfig `asTypeOf` gsconfig3 -- needed to fix an ambiguous type variable
-- > ]
-- > }
-- > where addPair (a,b) (x,y) = (a+x,b+y)
-- > nethackKeys = M.map addPair $ M.fromList
-- > [((0,xK_y),(-1,-1))
-- > ,((0,xK_i),(1,-1))
-- > ,((0,xK_n),(-1,1))
-- > ,((0,xK_m),(1,1))
-- > ]
-- > -- jump back to the center with the spacebar, regardless of the current position.
-- > reset = M.singleton (0,xK_space) (const (0,0))
-- $screenshots
--
-- Selecting a workspace:
--
-- <<http://haskell.org/sitewiki/images/a/a9/Xmonad-gridselect-workspace.png>>
--
-- Selecting a window by title:
--
-- <<http://haskell.org/sitewiki/images/3/35/Xmonad-gridselect-window-aavogt.png>>
data GSConfig a = GSConfig {
gs_cellheight :: Integer,
gs_cellwidth :: Integer,
gs_cellpadding :: Integer,
gs_colorizer :: Window -> Bool -> X (String, String),
gs_font :: String
gs_colorizer :: a -> Bool -> X (String, String),
gs_font :: String,
gs_navigate :: NavigateMap,
gs_originFractX :: Double,
gs_originFractY :: Double
}
-- | That is 'fromClassName' if you are selecting a 'Window', or
-- 'defaultColorizer' if you are selecting a 'String'. The catch-all instance
-- @HasColorizer a@ uses the 'focusedBorderColor' and 'normalBorderColor'
-- colors.
class HasColorizer a where
defaultColorizer :: a -> Bool -> X (String, String)
instance HasColorizer Window where
defaultColorizer = fromClassName
instance HasColorizer String where
defaultColorizer = stringColorizer
instance HasColorizer a where
defaultColorizer _ isFg =
let getColor = if isFg then focusedBorderColor else normalBorderColor
in asks $ flip (,) "black" . getColor . config
-- | A basic configuration for 'gridselect', with the colorizer chosen based on the type.
--
-- If you want to replace the 'gs_colorizer' field, use 'buildDefaultGSConfig'
-- instead, to avoid ambiguous type variables.
defaultGSConfig :: HasColorizer a => GSConfig a
defaultGSConfig = buildDefaultGSConfig defaultColorizer
type NavigateMap = M.Map (KeyMask,KeySym) (TwoDPosition -> TwoDPosition)
type TwoDPosition = (Integer, Integer)
type TwoDWindowMap = [(TwoDPosition,(String,Window))]
type TwoDElementMap a = [(TwoDPosition,(String,a))]
data TwoDState = TwoDState { td_curpos :: TwoDPosition,
td_windowmap :: [(TwoDPosition,(String,Window))],
td_gsconfig :: GSConfig,
td_font :: XMonadFont,
td_paneX :: Integer,
td_paneY :: Integer,
td_drawingWin :: Window
}
data TwoDState a = TwoDState { td_curpos :: TwoDPosition
, td_elementmap :: TwoDElementMap a
, td_gsconfig :: GSConfig a
, td_font :: XMonadFont
, td_paneX :: Integer
, td_paneY :: Integer
, td_drawingWin :: Window
}
newtype TwoD a b = TwoD { unTwoD :: StateT (TwoDState a) X b }
deriving (Monad,Functor,MonadState (TwoDState a))
type TwoD a = StateT TwoDState X a
instance Applicative (TwoD a) where
(<*>) = ap
pure = return
liftX :: X a1 -> TwoD a a1
liftX = TwoD . lift
evalTwoD :: TwoD a1 a -> TwoDState a1 -> X a
evalTwoD m s = flip evalStateT s $ unTwoD m
diamondLayer :: (Enum b', Num b') => b' -> [(b', b')]
-- FIXME remove nub
@@ -84,15 +231,17 @@ diamondLayer n = let ul = [ (x,n-x) | x <- [0..n] ]
diamond :: (Enum a, Num a) => [(a, a)]
diamond = concatMap diamondLayer [0..]
diamondRestrict :: (Enum t, Num t, Ord t) => t -> t -> [(t, t)]
diamondRestrict x y = L.filter (\(x',y') -> abs x' <= x && abs y' <= y) .
L.takeWhile (\(x',y') -> abs x' + abs y' <= x+y) $ diamond
diamondRestrict :: Integer -> Integer -> Integer -> Integer -> [(Integer, Integer)]
diamondRestrict x y originX originY =
L.filter (\(x',y') -> abs x' <= x && abs y' <= y) .
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)
findInWindowMap :: (Eq a) => a -> [(a, b)] -> Maybe (a, b)
findInWindowMap pos = find ((== pos) . fst)
findInElementMap :: (Eq a) => a -> [(a, b)] -> Maybe (a, b)
findInElementMap pos = find ((== pos) . fst)
drawWinBox :: Window -> XMonadFont -> (String, String) -> Integer -> Integer -> String -> Integer -> Integer -> Integer -> X ()
drawWinBox win font (fg,bg) ch cw text x y cp =
@@ -116,14 +265,14 @@ drawWinBox win font (fg,bg) ch cw text x y cp =
liftIO $ freeGC dpy gc
liftIO $ freeGC dpy bordergc
updateAllWindows :: TwoD ()
updateAllWindows =
updateAllElements :: TwoD a ()
updateAllElements =
do
TwoDState { td_windowmap = wins } <- get
updateWindows wins
TwoDState { td_elementmap = els } <- get
updateElements els
updateWindows :: TwoDWindowMap -> TwoD ()
updateWindows windowmap = do
updateElements :: TwoDElementMap a -> TwoD a ()
updateElements elementmap = do
TwoDState { td_curpos = curpos,
td_drawingWin = win,
td_gsconfig = gsconfig,
@@ -134,8 +283,8 @@ updateWindows windowmap = do
cellheight = gs_cellheight gsconfig
paneX' = div (paneX-cellwidth) 2
paneY' = div (paneY-cellheight) 2
updateWindow (pos@(x,y),(text, clientwindow)) = lift $ do
colors <- (gs_colorizer gsconfig) clientwindow (pos == curpos)
updateElement (pos@(x,y),(text, element)) = liftX $ do
colors <- gs_colorizer gsconfig element (pos == curpos)
drawWinBox win font
colors
cellheight
@@ -144,13 +293,12 @@ updateWindows windowmap = do
(paneX'+x*cellwidth)
(paneY'+y*cellheight)
(gs_cellpadding gsconfig)
mapM updateWindow windowmap
return ()
mapM_ updateElement elementmap
eventLoop :: TwoD (Maybe Window)
eventLoop :: TwoD a (Maybe a)
eventLoop = do
(keysym,string,event) <- lift $ withDisplay $ \d -> liftIO $ allocaXEvent $ \e -> do
nextEvent d e
(keysym,string,event) <- liftX $ withDisplay $ \d -> liftIO $ allocaXEvent $ \e -> do
maskEvent d (exposureMask .|. keyPressMask .|. buttonReleaseMask) e
ev <- getEvent e
(ks,s) <- if ev_event_type ev == keyPress
then lookupString $ asKeyEvent e
@@ -158,35 +306,41 @@ eventLoop = do
return (ks,s,ev)
handle (fromMaybe xK_VoidSymbol keysym,string) event
handle :: (KeySym, String)
-> Event
-> StateT TwoDState X (Maybe Window)
handle (ks,_) (KeyEvent {ev_event_type = t})
handle :: (KeySym, t) -> Event -> TwoD a (Maybe a)
handle (ks,_) (KeyEvent {ev_event_type = t, ev_state = m })
| t == keyPress && ks == xK_Escape = return Nothing
| t == keyPress && (ks == xK_Left || ks == xK_h) = diffAndRefresh (-1,0)
| t == keyPress && (ks == xK_Right || ks == xK_l) = diffAndRefresh (1,0)
| t == keyPress && (ks == xK_Down || ks == xK_j) = diffAndRefresh (0,1)
| t == keyPress && (ks == xK_Up || ks == xK_k) = diffAndRefresh (0,-1)
| t == keyPress && ks == xK_Return = do
(TwoDState { td_curpos = pos, td_windowmap = winmap }) <- get
return $ fmap (snd . snd) $ findInWindowMap pos winmap
(TwoDState { td_curpos = pos, td_elementmap = elmap }) <- get
return $ fmap (snd . snd) $ findInElementMap pos elmap
| t == keyPress = do
m' <- liftX (cleanMask m)
keymap <- gets (gs_navigate . td_gsconfig)
maybe eventLoop diffAndRefresh . M.lookup (m',ks) $ keymap
where diffAndRefresh diff = do
state <- get
let windowmap = td_windowmap state
let elmap = td_elementmap state
oldPos = td_curpos state
newPos = oldPos `tupadd` diff
newSelectedWin = findInWindowMap newPos windowmap
when (isJust newSelectedWin) $ do
newPos = diff oldPos
newSelectedEl = findInElementMap newPos elmap
when (isJust newSelectedEl) $ do
put state { td_curpos = newPos }
updateWindows (catMaybes [(findInWindowMap oldPos windowmap), newSelectedWin])
updateElements (catMaybes [(findInElementMap oldPos elmap), newSelectedEl])
eventLoop
handle _ (ExposeEvent { }) = do
updateAllWindows
eventLoop
handle _ (ButtonEvent { ev_event_type = t, ev_x = x, ev_y = y })
| t == buttonRelease = do
(TwoDState { td_elementmap = elmap, td_paneX = px, td_paneY = py,
td_gsconfig = (GSConfig ch cw _ _ _ _ _ _) }) <- get
let gridX = (fi x - (px - cw) `div` 2) `div` cw
gridY = (fi y - (py - ch) `div` 2) `div` ch
case lookup (gridX,gridY) elmap of
Just (_,el) -> return (Just el)
Nothing -> eventLoop
| otherwise = eventLoop
handle _ _ = do
eventLoop
handle _ (ExposeEvent { }) = updateAllElements >> eventLoop
handle _ _ = eventLoop
-- FIXME probably move that into Utils?
-- Conversion scheme as in http://en.wikipedia.org/wiki/HSV_color_space
@@ -206,52 +360,94 @@ hsv2rgb (h,s,v) =
5 -> (v,p,q)
_ -> error "The world is ending. x mod a >= a."
default_colorizer :: Window -> Bool -> X (String, String)
default_colorizer w active = do
classname <- runQuery className w
let seed x = toInteger (sum $ map ((*x).fromEnum) classname) :: Integer
-- | Default colorizer for Strings
stringColorizer :: String -> Bool -> X (String, String)
stringColorizer s active =
let seed x = toInteger (sum $ map ((*x).fromEnum) s) :: Integer
(r,g,b) = hsv2rgb ((seed 83) `mod` 360,
(fromInteger ((seed 191) `mod` 1000))/2500+0.4,
(fromInteger ((seed 121) `mod` 1000))/2500+0.4)
if active
then return ("#faff69", "black")
else return ("#" ++ concat (map (twodigitHex.(round :: Double -> Integer).(*256)) [r, g, b] ), "white")
where
twodigitHex :: Integer -> String
twodigitHex a = printf "%02x" a
in if active
then return ("#faff69", "black")
else return ("#" ++ concat (map (twodigitHex.(round :: Double -> Word8).(*256)) [r, g, b] ), "white")
-- | Brings up a 2D grid of windows in the center of the screen, and one can
-- select a window with cursors keys. The selected window is returned.
gridselect :: GSConfig -> X (Maybe Window)
gridselect gsconfig =
-- | Colorize a window depending on it's className.
fromClassName :: Window -> Bool -> X (String, String)
fromClassName w active = runQuery className w >>= flip defaultColorizer active
twodigitHex :: Word8 -> String
twodigitHex a = printf "%02x" a
-- | A colorizer that picks a color inside a range,
-- and depending on the window's class.
colorRangeFromClassName :: (Word8, Word8, Word8) -- ^ Beginning of the color range
-> (Word8, Word8, Word8) -- ^ End of the color range
-> (Word8, Word8, Word8) -- ^ Background of the active window
-> (Word8, Word8, Word8) -- ^ Inactive text color
-> (Word8, Word8, Word8) -- ^ Active text color
-> Window -> Bool -> X (String, String)
colorRangeFromClassName startC endC activeC inactiveT activeT w active =
do classname <- runQuery className w
if active
then return (rgbToHex activeC, rgbToHex activeT)
else return (rgbToHex $ mix startC endC
$ stringToRatio classname, rgbToHex inactiveT)
where rgbToHex :: (Word8, Word8, Word8) -> String
rgbToHex (r, g, b) = '#':twodigitHex r
++twodigitHex g++twodigitHex b
-- | Creates a mix of two colors according to a ratio
-- (1 -> first color, 0 -> second color).
mix :: (Word8, Word8, Word8) -> (Word8, Word8, Word8)
-> Double -> (Word8, Word8, Word8)
mix (r1, g1, b1) (r2, g2, b2) r = (mix' r1 r2, mix' g1 g2, mix' b1 b2)
where mix' a b = truncate $ (fi a * r) + (fi b * (1 - r))
-- | Generates a Double from a string, trying to
-- achieve a random distribution.
-- We create a random seed from the sum of all characters
-- in the string, and use it to generate a ratio between 0 and 1
stringToRatio :: String -> Double
stringToRatio "" = 0
stringToRatio s = let gen = mkStdGen $ sum $ map fromEnum s
range = (\(a, b) -> b - a) $ genRange gen
randomInt = foldr1 combine $ replicate 20 next
combine f1 f2 g = let (_, g') = f1 g in f2 g'
in fi (fst $ randomInt gen) / fi range
-- | 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 gsconfig elmap =
withDisplay $ \dpy -> do
rootw <- liftIO $ rootWindow dpy (defaultScreen dpy)
rootw <- asks theRoot
s <- gets $ screenRect . W.screenDetail . W.current . windowset
windowList <- windowMap
win <- liftIO $ mkUnmanagedWindow dpy (defaultScreenOfDisplay dpy) rootw
(rect_x s) (rect_y s) (rect_width s) (rect_height s)
liftIO $ mapWindow dpy win
liftIO $ selectInput dpy win (exposureMask .|. keyPressMask)
liftIO $ selectInput dpy win (exposureMask .|. keyPressMask .|. buttonReleaseMask)
status <- io $ grabKeyboard dpy win True grabModeAsync grabModeAsync currentTime
io $ grabButton dpy button1 anyModifier win True buttonReleaseMask grabModeAsync grabModeAsync none none
font <- initXMF (gs_font gsconfig)
let screenWidth = toInteger $ rect_width s;
screenHeight = toInteger $ rect_height s;
selectedWindow <- if (status == grabSuccess) then
do
let restriction :: Integer -> (GSConfig -> Integer) -> Double
restriction ss cs = ((fromInteger ss)/(fromInteger $ cs gsconfig)-1)/2
selectedElement <- if (status == grabSuccess) then do
let restriction ss cs = (fromInteger ss/fromInteger (cs gsconfig)-1)/2 :: Double
restrictX = floor $ restriction screenWidth gs_cellwidth
restrictY = floor $ restriction screenHeight gs_cellheight
winmap = zipWith (,) (diamondRestrict restrictX restrictY) windowList
selectedWindow <- evalStateT (do updateAllWindows; eventLoop)
(TwoDState (0,0)
winmap
gsconfig
font
screenWidth
screenHeight
win)
return selectedWindow
originPosX = floor $ ((gs_originFractX gsconfig) - (1/2)) * 2 * fromIntegral restrictX
originPosY = floor $ ((gs_originFractY gsconfig) - (1/2)) * 2 * fromIntegral restrictY
coords = diamondRestrict restrictX restrictY originPosX originPosY
elmap' = zip coords elmap
evalTwoD (updateAllElements >> eventLoop)
(TwoDState (head coords)
elmap'
gsconfig
font
screenWidth
screenHeight
win)
else
return Nothing
liftIO $ do
@@ -259,19 +455,22 @@ gridselect gsconfig =
destroyWindow dpy win
sync dpy False
releaseXMF font
return selectedWindow
return selectedElement
-- | Like `gridSelect' but with the current windows and their titles as elements
gridselectWindow :: GSConfig Window -> X (Maybe Window)
gridselectWindow gsconf = windowMap >>= gridselect gsconf
-- | Brings up a 2D grid of windows in the center of the screen, and one can
-- select a window with cursors keys. The selected window is then passed to
-- a callback function.
withSelectedWindow :: (Window -> X ()) -> GSConfig -> X ()
withSelectedWindow :: (Window -> X ()) -> GSConfig Window -> X ()
withSelectedWindow callback conf = do
mbWindow <- gridselect conf
mbWindow <- gridselectWindow conf
case mbWindow of
Just w -> callback w
Nothing -> return ()
windowMap :: X [(String,Window)]
windowMap = do
ws <- gets windowset
@@ -283,20 +482,44 @@ decorateName' :: Window -> X String
decorateName' w = do
fmap show $ getName w
defaultGSConfig :: GSConfig
defaultGSConfig = GSConfig 50 130 10 default_colorizer "xft:Sans-8"
-- | Builds a default gs config from a colorizer function.
buildDefaultGSConfig :: (a -> Bool -> X (String,String)) -> GSConfig a
buildDefaultGSConfig col = GSConfig 50 130 10 col "xft:Sans-8" defaultGSNav (1/2) (1/2)
defaultGSNav :: NavigateMap
defaultGSNav = M.map tupadd $ M.fromList
[((0,xK_Left) ,(-1,0))
,((0,xK_h) ,(-1,0))
,((0,xK_Right),(1,0))
,((0,xK_l) ,(1,0))
,((0,xK_Down) ,(0,1))
,((0,xK_j) ,(0,1))
,((0,xK_Up) ,(0,-1))
,((0,xK_k) ,(0,-1))
]
borderColor :: String
borderColor = "white"
-- | Brings selected window to the current workspace.
bringSelected :: GSConfig -> X ()
bringSelected :: GSConfig Window -> X ()
bringSelected = withSelectedWindow $ \w -> do
windows (bringWindow w)
XMonad.focus w
windows W.shiftMaster
-- | Switches to selected window's workspace and focuses that window.
goToSelected :: GSConfig -> X ()
goToSelected :: GSConfig Window -> X ()
goToSelected = withSelectedWindow $ windows . W.focusWindow
-- | Select an application to spawn from a given list
spawnSelected :: GSConfig String -> [String] -> X ()
spawnSelected conf lst = gridselect conf (zip lst lst) >>= flip whenJust spawn
-- | Select an action and run it in the X monad
runSelectedAction :: GSConfig (X ()) -> [(String, X ())] -> X ()
runSelectedAction conf actions = do
selectedActionM <- gridselect conf actions
case selectedActionM of
Just selectedAction -> selectedAction
Nothing -> return ()

View File

@@ -0,0 +1,99 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.MessageFeedback
-- Copyright : (c) Quentin Moser <quentin.moser@unifr.ch>
-- License : BSD3
--
-- Maintainer : None
-- Stability : unstable
-- Portability : unportable
--
-- Alternative to 'XMonad.Operations.sendMessage' that provides knowledge
-- of whether the message was handled, and utility functions based on
-- this facility.
-----------------------------------------------------------------------------
module XMonad.Actions.MessageFeedback (
-- * Usage
-- $usage
send
, tryMessage
, tryMessage_
, tryInOrder
, tryInOrder_
, sm
, sendSM
, sendSM_
) where
import XMonad.Core ( X (), Message, SomeMessage(..), LayoutClass(..), windowset, catchX )
import XMonad.StackSet ( current, workspace, layout, tag )
import XMonad.Operations ( updateLayout )
import Control.Monad.State ( gets )
import Data.Maybe ( isJust )
import Control.Applicative ((<$>))
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
--
-- > import XMonad.Actions.MessageFeedback
--
-- You can then use this module's functions wherever an action is expected.
--
-- Note that most functions in this module have a return type of @X Bool@
-- whereas configuration options will expect a @X ()@ action.
-- For example, the key binding
--
-- > -- Shrink the master area of a tiled layout, or move the focused window
-- > -- to the left in a WindowArranger-based layout
-- > ((modKey, xK_Left), tryMessage Shrink (MoveLeft 50))
--
-- is mis-typed. For this reason, this module provides alternatives (ending with
-- an underscore, e.g. tryMessage_) that discard their result and return an @X ()@.
-- For example, to correct the previous example:
--
-- > ((modKey, xK_Left), tryMessage_ Shrink (MoveLeft 50))
--
-- | Behaves like 'XMonad.Operations.sendMessage', but returns True of the
-- message was handled by the layout, False otherwise.
send :: Message a => a -> X Bool
send = sendSM . sm
-- | Sends the first message, and if it was not handled, sends the second.
-- Returns True if either message was handled, False otherwise.
tryMessage :: (Message a, Message b) => a -> b -> X Bool
tryMessage m1 m2 = do b <- send m1
if b then return True else send m2
tryMessage_ :: (Message a, Message b) => a -> b -> X ()
tryMessage_ m1 m2 = tryMessage m1 m2 >> return ()
-- | Tries sending every message of the list in order until one of them
-- is handled. Returns True if one of the messages was handled, False otherwise.
tryInOrder :: [SomeMessage] -> X Bool
tryInOrder [] = return False
tryInOrder (m:ms) = do b <- sendSM m
if b then return True else tryInOrder ms
tryInOrder_ :: [SomeMessage] -> X ()
tryInOrder_ ms = tryInOrder ms >> return ()
-- | Convenience shorthand for 'XMonad.Core.SomeMessage'.
sm :: Message a => a -> SomeMessage
sm = SomeMessage
sendSM :: SomeMessage -> X Bool
sendSM m = do w <- workspace . current <$> gets windowset
ml' <- handleMessage (layout w) m `catchX` return Nothing
updateLayout (tag w) ml'
return $ isJust ml'
sendSM_ :: SomeMessage -> X ()
sendSM_ m = sendSM m >> return ()

View File

@@ -15,14 +15,14 @@
module XMonad.Actions.MouseGestures (
-- * Usage
-- $usage
Direction(..),
Direction2D(..),
mouseGestureH,
mouseGesture,
mkCollect
) where
import XMonad
import XMonad.Hooks.ManageDocks (Direction(..))
import XMonad.Util.Types (Direction2D(..))
import Data.IORef
import qualified Data.Map as M
@@ -39,7 +39,7 @@ import Control.Monad
--
-- then add an appropriate mouse binding:
--
-- > , ((modMask x .|. shiftMask, button3), mouseGesture gestures)
-- > , ((modm .|. shiftMask, button3), mouseGesture gestures)
--
-- where @gestures@ is a 'Data.Map.Map' from gestures to actions on
-- windows, for example:
@@ -64,10 +64,10 @@ delta (ax, ay) (bx, by) = max (d ax bx) (d ay by)
where
d a b = abs (a - b)
dir :: Pos -> Pos -> Direction
dir :: Pos -> Pos -> Direction2D
dir (ax, ay) (bx, by) = trans . (/ pi) $ atan2 (fromIntegral $ ay - by) (fromIntegral $ bx - ax)
where
trans :: Double -> Direction
trans :: Double -> Direction2D
trans x
| rg (-3/4) (-1/4) x = D
| rg (-1/4) (1/4) x = R
@@ -75,7 +75,7 @@ dir (ax, ay) (bx, by) = trans . (/ pi) $ atan2 (fromIntegral $ ay - by) (fromInt
| otherwise = L
rg a z x = a <= x && x < z
gauge :: (Direction -> X ()) -> Pos -> IORef (Maybe (Direction, Pos)) -> Position -> Position -> X ()
gauge :: (Direction2D -> X ()) -> Pos -> IORef (Maybe (Direction2D, Pos)) -> Position -> Position -> X ()
gauge hook op st nx ny = do
let np = (nx, ny)
stx <- io $ readIORef st
@@ -96,7 +96,7 @@ gauge hook op st nx ny = do
-- | @'mouseGestureH' moveHook endHook@ is a mouse button
-- event handler. It collects mouse movements, calling @moveHook@ for each
-- update; when the button is released, it calls @endHook@.
mouseGestureH :: (Direction -> X ()) -> X () -> X ()
mouseGestureH :: (Direction2D -> X ()) -> X () -> X ()
mouseGestureH moveHook endHook = do
dpy <- asks display
root <- asks theRoot
@@ -108,7 +108,7 @@ mouseGestureH moveHook endHook = do
-- | A utility function on top of 'mouseGestureH'. It uses a 'Data.Map.Map' to
-- look up the mouse gesture, then executes the corresponding action (if any).
mouseGesture :: Map [Direction] (Window -> X ()) -> Window -> X ()
mouseGesture :: Map [Direction2D] (Window -> X ()) -> Window -> X ()
mouseGesture tbl win = do
(mov, end) <- mkCollect
mouseGestureH (\d -> mov d >> return ()) $ end >>= \gest ->
@@ -121,7 +121,7 @@ mouseGesture tbl win = do
-- collect mouse movements (and return the current gesture as a list); the end
-- hook will return a list of the completed gesture, which you can access with
-- 'Control.Monad.>>='.
mkCollect :: (MonadIO m, MonadIO m') => m (Direction -> m' [Direction], m' [Direction])
mkCollect :: (MonadIO m, MonadIO m') => m (Direction2D -> m' [Direction2D], m' [Direction2D])
mkCollect = liftIO $ do
acc <- newIORef []
let

View File

@@ -47,11 +47,11 @@ import XMonad.Util.XUtils
--
-- Then edit your @layoutHook@ by modifying a given layout:
--
-- > myLayouts = mouseResize $ windowArrange $ layoutHook defaultConfig
-- > myLayout = mouseResize $ windowArrange $ layoutHook defaultConfig
--
-- and then:
--
-- > main = xmonad defaultConfig { layoutHook = myLayouts }
-- > main = xmonad defaultConfig { layoutHook = myLayout }
--
-- For more detailed instructions on editing the layoutHook see:
--

View File

@@ -5,7 +5,7 @@
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : Lukas Mai <l.mai@web.de>
-- Stability : unstable
-- Stability : stable
-- Portability : unportable
--
-- This module provides helper functions for dealing with window borders.
@@ -21,7 +21,7 @@ import XMonad
-- | Toggle the border of the currently focused window. To use it, add a
-- keybinding like so:
--
-- > , ((modMask x, xK_g ), withFocused toggleBorder)
-- > , ((modm, xK_g ), withFocused toggleBorder)
--
toggleBorder :: Window -> X ()
toggleBorder w = do

115
XMonad/Actions/OnScreen.hs Normal file
View File

@@ -0,0 +1,115 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.OnScreen
-- Copyright : (c) 2009 Nils Schweinsberg
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : Nils Schweinsberg <mail@n-sch.de>
-- Stability : unstable
-- Portability : unportable
--
-- Control workspaces on different screens (in xinerama mode).
--
-----------------------------------------------------------------------------
module XMonad.Actions.OnScreen (
-- * Usage
-- $usage
onScreen
, viewOnScreen
, greedyViewOnScreen
, onlyOnScreen
) where
import XMonad.StackSet
import Control.Monad(guard)
import Data.List
import Data.Maybe(fromMaybe)
import Data.Function(on)
-- $usage
--
-- This module provides an easy way to control, what you see on other screens in
-- xinerama mode without having to focus them. Put this into your
-- @~\/.xmonad\/xmonad.hs@:
--
-- > import XMonad.Actions.OnScreen
--
-- Then add the appropriate keybindings, for example replace your current keys
-- to switch the workspaces with this at the bottom of your keybindings:
--
-- > ++
-- > [ ((m .|. modm, k), windows (f i))
-- > | (i, k) <- zip (workspaces conf) ([xK_1 .. xK_9] ++ [xK_0])
-- > , (f, m) <- [ (viewOnScreen 0, 0)
-- > , (viewOnScreen 1, controlMask)
-- > , (greedyView, controlMask .|. shiftMask) ]
-- > ]
--
-- This will provide you with the following keybindings:
--
-- * modkey + 1-0:
-- Switch to workspace 1-0 on screen 0
--
-- * modkey + control + 1-0:
-- Switch to workspace 1-0 on screen 1
--
-- * modkey + control + shift + 1-0:
-- Default greedyView behaviour
--
--
-- A more basic version inside the default keybindings would be:
--
-- > , ((modm .|. controlMask, xK_1) windows (viewOnScreen 0 "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

@@ -0,0 +1,88 @@
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.PhysicalScreens
-- Copyright : (c) Nelson Elhage <nelhage@mit.edu>
-- License : BSD
--
-- Maintainer : Nelson Elhage <nelhage@mit.edu>
-- Stability : unstable
-- Portability : unportable
--
-- Manipulate screens ordered by physical location instead of ID
-----------------------------------------------------------------------------
module XMonad.Actions.PhysicalScreens (
-- * Usage
-- $usage
PhysicalScreen(..)
, getScreen
, viewScreen
, sendToScreen
) where
import XMonad
import qualified XMonad.StackSet as W
import qualified Graphics.X11.Xlib as X
import Graphics.X11.Xinerama
import Data.List (sortBy)
import Data.Function (on)
{- $usage
This module allows you name Xinerama screens from XMonad using their
physical location relative to each other (as reported by Xinerama),
rather than their @ScreenID@ s, which are arbitrarily determined by
your X server and graphics hardware.
Screens are ordered by the upper-left-most corner, from top-to-bottom
and then left-to-right.
Example usage in your @~\/.xmonad\/xmonad.hs@ file:
> import XMonad.Actions.PhysicalSCreens
> --
> -- 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
> --
> [((modm .|. mask, key), f sc)
> | (key, sc) <- zip [xK_w, xK_e, xK_r] [0..]
> , (f, mask) <- [(viewScreen, 0), (sendToScreen, shiftMask)]]
For detailed instructions on editing your key bindings, see
"XMonad.Doc.Extending#Editing_key_bindings".
-}
-- | The type of the index of a screen by location
newtype PhysicalScreen = P Int deriving (Eq,Ord,Show,Read,Enum,Num,Integral,Real)
-- | Translate a physical screen index to a "ScreenId"
getScreen :: PhysicalScreen -> X (Maybe ScreenId)
getScreen (P i) = withDisplay $ \dpy -> do
screens <- io $ getScreenInfo dpy
if i >= length screens
then return Nothing
else let ss = sortBy (cmpScreen `on` fst) $ zip screens [0..]
in return $ Just $ snd $ ss !! i
-- | Switch to a given physical screen
viewScreen :: PhysicalScreen -> X ()
viewScreen p = do i <- getScreen p
whenJust i $ \s -> do
w <- screenWorkspace s
whenJust w $ windows . W.view
-- | Send the active window to a given physical screen
sendToScreen :: PhysicalScreen -> X ()
sendToScreen p = do i <- getScreen p
whenJust i $ \s -> do
w <- screenWorkspace s
whenJust w $ windows . W.shift
-- | Compare two screens by their top-left corners, ordering
-- | top-to-bottom and then left-to-right.
cmpScreen :: Rectangle -> Rectangle -> Ordering
cmpScreen (Rectangle x1 y1 _ _) (Rectangle x2 y2 _ _) = compare (y1,x1) (y2,x2)

View File

@@ -78,9 +78,9 @@ data Limits
-- divisor, the last line will have the remaining workspaces.
data Lines
= GConf -- ^ Use @gconftool-2@ to find out the number of lines.
| Lines Int -- ^ Specify the number of lines explicity.
| Lines Int -- ^ Specify the number of lines explicitly.
-- | This is the way most people would like to use this module. It ataches the
-- | This is the way most people would like to use this module. It attaches the
-- 'KeyMask' passed as a parameter with 'xK_Left', 'xK_Up', 'xK_Right' and
-- 'xK_Down', associating it with 'planeMove' to the corresponding 'Direction'.
-- It also associates these bindings with 'shiftMask' to 'planeShift'.

View File

@@ -33,7 +33,7 @@ import XMonad.StackSet
--
-- then add a keybinding or substitute 'promote' in place of swapMaster:
--
-- > , ((modMask x, xK_Return), promote)
-- > , ((modm, xK_Return), promote)
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".

View File

@@ -0,0 +1,72 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.RandomBackground
-- Copyright : (c) 2009 Anze Slosar
-- translation to Haskell by Adam Vogt
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : <vogt.adam@gmail.com>
-- Stability : unstable
-- Portability : unportable
--
-- An action to start terminals with a random background color
--
-----------------------------------------------------------------------------
module XMonad.Actions.RandomBackground (
-- * Usage
-- $usage
randomBg',
randomBg,
RandomColor(HSV,RGB)
) where
import XMonad(X, XConf(config), XConfig(terminal), io, spawn,
MonadIO, asks)
import System.Random
import Control.Monad(liftM)
import Numeric(showHex)
-- $usage
--
-- Add to your keybindings something like:
--
-- > ,((modm .|. shiftMask, xK_Return), randomBg $ HSV 0xff 0x20
-- | RandomColor fixes constraints when generating random colors. All
-- parameters should be in the range 0 -- 0xff
data RandomColor = RGB { _colorMin :: Int
, _colorMax :: Int
} -- ^ specify the minimum and maximum lowest values for each color channel.
| HSV { _colorSaturation :: Double
, _colorValue :: Double
} -- ^ specify the saturation and value, leaving the hue random.
toHex :: [Int] -> String
toHex = ("'#"++) . (++"'") . concatMap (ensure 2 . ($ "") . showHex)
where ensure x = reverse . take x . (++repeat '0') . reverse
randPermutation :: (RandomGen g) => [a] -> g -> [a]
randPermutation xs g = swap $ zip (randoms g) xs
where
swap ((True,x):(c,y):ys) = y:swap ((c,x):ys)
swap ((False,x):ys) = x:swap ys
swap x = map snd x
-- | @randomBg'@ produces a random hex number in the form @'#xxyyzz'@
randomBg' :: (MonadIO m) => RandomColor -> m String
randomBg' (RGB l h) = io $ liftM (toHex . take 3 . randomRs (l,h)) newStdGen
randomBg' (HSV s v) = io $ do
g <- newStdGen
let x = (^(2::Int)) $ fst $ randomR (0,sqrt $ pi / 3) g
return $ toHex $ map round $ randPermutation [v,(v-s)*x + s,s] g
-- | @randomBg@ starts a terminal with the background color taken from 'randomBg''
--
-- This depends on the your 'terminal' configuration field accepting an
-- argument like @-bg '#ff0023'@
randomBg :: RandomColor -> X ()
randomBg x = do
t <- asks (terminal . config)
c <- randomBg' x
spawn $ t ++ " -bg " ++ c

View File

@@ -5,7 +5,7 @@
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : Hans Philipp Annen <haphi@gmx.net>
-- Stability : unstable
-- Stability : stable
-- Portability : unportable
--
-- Rotate all windows except the master window and keep the focus in
@@ -28,7 +28,7 @@ import XMonad
--
-- and add whatever keybindings you would like, for example:
--
-- > , ((modMask x .|. shiftMask, xK_Tab ), rotSlavesUp)
-- > , ((modm .|. shiftMask, xK_Tab ), rotSlavesUp)
--
-- This operation will rotate all windows except the master window,
-- while the focus stays where it is. It is useful together with the

View File

@@ -10,45 +10,56 @@
Modeled after the handy Surfraw CLI search tools at <https://secure.wikimedia.org/wikipedia/en/wiki/Surfraw>.
Additional sites welcomed. -}
module XMonad.Actions.Search ( -- * Usage
-- $usage
search,
SearchEngine(..),
searchEngine,
promptSearch,
promptSearchBrowser,
selectSearch,
selectSearchBrowser,
amazon,
codesearch,
deb,
debbts,
debpts,
dictionary,
google,
hackage,
hoogle,
images,
imdb,
isohunt,
maps,
mathworld,
scholar,
thesaurus,
wayback,
wikipedia,
youtube
module XMonad.Actions.Search ( -- * Usage
-- $usage
search,
SearchEngine(..),
searchEngine,
searchEngineF,
promptSearch,
promptSearchBrowser,
selectSearch,
selectSearchBrowser,
isPrefixOf,
escape,
use,
intelligent,
(!>),
prefixAware,
namedEngine,
amazon,
alpha,
codesearch,
deb,
debbts,
debpts,
dictionary,
google,
hackage,
hoogle,
images,
imdb,
isohunt,
lucky,
maps,
mathworld,
scholar,
thesaurus,
wayback,
wikipedia,
wiktionary,
youtube,
multi
-- * Use case: searching with a submap
-- $tip
) where
import Data.Char (chr, ord, isAlpha, isMark, isDigit)
import Data.List (isPrefixOf)
import Numeric (showIntAtBase)
import XMonad (X(), MonadIO, liftIO)
import XMonad.Prompt (XPrompt(showXPrompt), mkXPrompt, XPConfig(), historyCompletion)
import XMonad.Prompt (XPrompt(showXPrompt), mkXPrompt, XPConfig(), historyCompletionP)
import XMonad.Prompt.Shell (getBrowser)
import XMonad.Util.Run (safeSpawn)
import XMonad.Util.XSelection (getSelection)
@@ -79,13 +90,15 @@ import XMonad.Util.XSelection (getSelection)
* 'amazon' -- Amazon keyword search.
* 'alpha' -- Wolfram|Alpha query.
* 'codesearch' -- Google Labs Code Search search.
* 'deb' -- Debian package search.
* 'debbts' -- Debian Bug Tracking System.
* 'debpts -- Debian Package Tracking System.
* 'debpts' -- Debian Package Tracking System.
* 'dictionary' -- dictionary.reference.com search.
@@ -101,6 +114,8 @@ import XMonad.Util.XSelection (getSelection)
* 'isohunt' -- isoHunt search.
* 'lucky' -- Google "I'm feeling lucky" search.
* 'maps' -- Google maps.
* 'mathworld' -- Wolfram MathWorld search.
@@ -115,6 +130,8 @@ import XMonad.Util.XSelection (getSelection)
* 'youtube' -- Youtube video search.
* 'multi' -- Search based on the prefix. \"amazon:Potter\" will use amazon, etc. With no prefix searches google.
Feel free to add more! -}
{- $tip
@@ -153,7 +170,7 @@ Or in combination with XMonad.Util.EZConfig:
>
> ...
>
> searchList :: [([Char], S.SearchEngine)]
> searchList :: [(String, S.SearchEngine)]
> searchList = [ ("g", S.google)
> , ("h", S.hoohle)
> , ("w", S.wikipedia)
@@ -205,14 +222,21 @@ escape = escapeURIString (\c -> isAlpha c || isDigit c || isMark c)
type Browser = FilePath
type Query = String
type Site = String
type Site = String -> String
type Name = String
data SearchEngine = SearchEngine Name Site
-- | Given a browser, a search engine, and a search term, perform the
-- | Given an already defined search engine, extracts its transformation
-- function, making it easy to create compound search engines.
-- For an instance you can use @use google@ to get a function which
-- makes the same transformation as the google search engine would.
use :: SearchEngine -> Site
use (SearchEngine _ engine) = engine
-- | Given a browser, a search engine's transformation function, and a search term, perform the
-- requested search in the browser.
search :: Browser -> Site -> Query -> X ()
search browser site query = safeSpawn browser $ site ++ escape query
search browser site query = safeSpawn browser [site query]
{- | Given a base URL, create the 'SearchEngine' that escapes the query and
appends it to the base. You can easily define a new engine locally using
@@ -222,45 +246,113 @@ search browser site query = safeSpawn browser $ site ++ escape query
The important thing is that the site has a interface which accepts the escaped query
string as part of the URL. Alas, the exact URL to feed searchEngine varies
from site to site, often considerably, so there's no general way to cover this.
from site to site, often considerably, so there\'s no general way to cover this.
Generally, examining the resultant URL of a search will allow you to reverse-engineer
it if you can't find the necessary URL already described in other projects such as Surfraw. -}
searchEngine :: Name -> Site -> SearchEngine
searchEngine = SearchEngine
searchEngine :: Name -> String -> SearchEngine
searchEngine name site = searchEngineF name (\s -> site ++ (escape s))
{- | If your search engine is more complex than this (you may want to identify
the kind of input and make the search URL dependent on the input or put the query
inside of a URL instead of in the end) you can use the alternative 'searchEngineF' function.
> searchFunc :: String -> String
> searchFunc s | s `isPrefixOf` "wiki:" = "http://en.wikipedia.org/wiki/" ++ (escape $ tail $ snd $ break (==':') s)
> | s `isPrefixOf` "http://" = s
> | otherwise = (use google) s
> myNewEngine = searchEngineF "mymulti" searchFunc
@searchFunc@ here searches for a word in wikipedia if it has a prefix
of \"wiki:\" (you can use the 'escape' function to escape any forbidden characters), opens an address
directly if it starts with \"http:\/\/\" and otherwise uses the provided google search engine.
You can use other engines inside of your own through the 'use' function as shown above to make
complex searches.
The user input will be automatically escaped in search engines created with 'searchEngine',
'searchEngineF', however, completely depends on the transformation function passed to it. -}
searchEngineF :: Name -> Site -> SearchEngine
searchEngineF = SearchEngine
-- The engines.
amazon, codesearch, deb, debbts, debpts, dictionary, google, hackage, hoogle, images,
imdb, isohunt, maps, mathworld, scholar, thesaurus, wayback, wikipedia,
amazon, alpha, codesearch, deb, debbts, debpts, dictionary, google, hackage, hoogle,
images, imdb, isohunt, lucky, maps, mathworld, scholar, thesaurus, wayback, wikipedia, wiktionary,
youtube :: SearchEngine
amazon = searchEngine "amazon" "http://www.amazon.com/exec/obidos/external-search?index=all&keyword="
alpha = searchEngine "alpha" "http://www.wolframalpha.com/input/?i="
codesearch = searchEngine "codesearch" "http://www.google.com/codesearch?q="
deb = searchEngine "deb" "http://packages.debian.org/"
debbts = searchEngine "debbts" "http://bugs.debian.org/"
debpts = searchEngine "debpts" "http://packages.qa.debian.org/"
dictionary = searchEngine "dictionary" "http://dictionary.reference.com/browse/"
dictionary = searchEngine "dict" "http://dictionary.reference.com/browse/"
google = searchEngine "google" "http://www.google.com/search?num=100&q="
hackage = searchEngine "hackage" "http://hackage.haskell.org/cgi-bin/hackage-scripts/package/"
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="
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 "wikipedia" "https://secure.wikimedia.org/wikipedia/en/wiki/Special:Search?go=Go&search="
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="
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/"
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)]
{- | This function wraps up a search engine and creates a new one, which works
like the argument, but goes directly to a URL if one is given rather than
searching.
> myIntelligentGoogleEngine = intelligent google
Now if you search for http:\/\/xmonad.org it will directly open in your browser-}
intelligent :: SearchEngine -> SearchEngine
intelligent (SearchEngine name site) = searchEngineF name (\s -> if (fst $ break (==':') s) `elem` ["http", "https", "ftp"] then s else (site s))
-- | > removeColonPrefix "foo://bar" ~> "//bar"
-- > removeColonPrefix "foo//bar" ~> "foo//bar"
removeColonPrefix :: String -> String
removeColonPrefix s = if ':' `elem` s then drop 1 $ dropWhile (':' /=) s else s
{- | Connects a few search engines into one. If the search engines\' names are
\"s1\", \"s2\" and \"s3\", then the resulting engine will use s1 if the query
is @s1:word@, s2 if you type @s2:word@ and s3 in all other cases.
Example:
> multiEngine = intelligent (wikipedia !> mathworld !> (prefixAware google))
Now if you type \"wiki:Haskell\" it will search for \"Haskell\" in Wikipedia,
\"mathworld:integral\" will search mathworld, and everything else will fall back to
google. The use of intelligent will make sure that URLs are opened directly. -}
(!>) :: SearchEngine -> SearchEngine -> SearchEngine
(SearchEngine name1 site1) !> (SearchEngine name2 site2) = searchEngineF (name1 ++ "/" ++ name2) (\s -> if s `isPrefixOf` (name1++":") then site1 (removeColonPrefix s) else site2 s)
{- | Makes a search engine prefix-aware. Especially useful together with '!>'.
It will automatically remove the prefix from a query so that you don\'t end
up searching for google:xmonad if google is your fallback engine and you
explicitly add the prefix. -}
prefixAware :: SearchEngine -> SearchEngine
prefixAware (SearchEngine name site) = SearchEngine name (\s -> if s `isPrefixOf` (name++":") then site $ removeColonPrefix s else site s)
{- | Changes search engine's name -}
namedEngine :: Name -> SearchEngine -> SearchEngine
namedEngine name (SearchEngine _ site) = searchEngineF name site
{- | Like 'search', but for use with the output from a Prompt; it grabs the
Prompt's result, passes it to a given searchEngine and opens it in a given
browser. -}
promptSearchBrowser :: XPConfig -> Browser -> SearchEngine -> X ()
promptSearchBrowser config browser (SearchEngine name site) = mkXPrompt (Search name) config historyCompletion $ search browser site
promptSearchBrowser config browser (SearchEngine name site) =
mkXPrompt (Search name) config (historyCompletionP ("Search [" `isPrefixOf`)) $ search browser site
{- | Like 'search', but in this case, the string is not specified but grabbed
from the user's response to a prompt. Example:

View File

@@ -29,7 +29,7 @@ import XMonad.Util.Run
--
-- and add a keybinding, for example:
--
-- > , ((modMask x, xK_d ), date)
-- > , ((modm, xK_d ), date)
--
-- In this example, a popup date menu will now be bound to @mod-d@.
--

View File

@@ -5,17 +5,20 @@
-- Stability : unstable
-- Portability : unportable
--
-- Provides a simple binding that pushes all floating windows on the current
-- workspace back into tiling.
-- Provides a simple binding that pushes all floating windows on the
-- current workspace back into tiling. Note that the functionality of
-- this module has been folded into the more general
-- "XMonad.Actions.WithAll"; this module simply re-exports the
-- 'sinkAll' function for backwards compatibility.
-----------------------------------------------------------------------------
module XMonad.Actions.SinkAll (
-- * Usage
-- $usage
sinkAll) where
import XMonad
import XMonad.StackSet
import XMonad.Actions.WithAll (sinkAll)
-- $usage
--
@@ -25,16 +28,7 @@ import XMonad.StackSet
--
-- then add a keybinding; for example:
--
-- , ((modMask x .|. shiftMask, xK_t), sinkAll)
-- > , ((modm .|. shiftMask, xK_t), sinkAll)
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
-- | Un-float all floating windows on the current workspace.
sinkAll :: X ()
sinkAll = withAll sink
-- | Apply a function to all windows on current workspace.
withAll :: (Window -> WindowSet -> WindowSet) -> X ()
withAll f = windows $ \ws -> let all' = integrate' . stack . workspace . current $ ws
in foldr f ws all'

View File

@@ -8,28 +8,26 @@
-- Stability : unstable
-- Portability : unportable
--
-- This module provides helper functions to be used in @manageHook@. Here's
-- how you might use this:
-- Provides a way to modify a window spawned by a command(e.g shift it to the workspace
-- it was launched on) by using the _NET_WM_PID property that most windows set on creation.
-- Hence this module won't work on applications that don't set this property.
--
-- > import XMonad.Hooks.ManageHelpers
-- > main = do
-- > sp <- mkSpawner
-- > xmonad defaultConfig {
-- > ...
-- > manageHook = spawnHook sp <+> manageHook defaultConfig
-- > ...
-- > }
-----------------------------------------------------------------------------
module XMonad.Actions.SpawnOn (
-- * Usage
-- $usage
Spawner,
mkSpawner,
manageSpawn,
spawnHere,
spawnOn,
spawnAndDo,
shellPromptHere,
shellPromptOn
) where
import Data.List (isInfixOf)
import Data.IORef
import System.Posix.Types (ProcessID)
@@ -40,38 +38,85 @@ import XMonad.Hooks.ManageHelpers
import XMonad.Prompt
import XMonad.Prompt.Shell
newtype Spawner = Spawner {pidsRef :: IORef [(ProcessID, WorkspaceId)]}
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
--
-- > import XMonad.Actions.SpawnOn
--
-- > main = do
-- > sp <- mkSpawner
-- > xmonad defaultConfig {
-- > ...
-- > manageHook = manageSpawn sp <+> 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)
--
-- The module can also be used to apply other manage hooks to the window of
-- the spawned application(e.g. float or resize it).
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
newtype Spawner = Spawner {pidsRef :: IORef [(ProcessID, ManageHook)]}
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 []
-- | Provides a manage hook to react on process spawned with
-- 'spawnOn', 'spawnHere' etc.
manageSpawn :: Spawner -> ManageHook
manageSpawn sp = do
pids <- io . readIORef $ pidsRef sp
mp <- pid
case flip lookup pids =<< mp of
Just w -> doF (W.shift w)
Nothing -> doF id
Just mh -> do
whenJust mp $ \p ->
io . modifyIORef (pidsRef sp) $ filter ((/= p) . fst)
mh
mkPrompt :: (String -> X ()) -> XPConfig -> X ()
mkPrompt cb c = do
cmds <- io $ getCommands
mkXPrompt Shell c (getShellCompl cmds) cb
-- | Replacement for Shell prompt ("XMonad.Prompt.Shell") which launches
-- application on current workspace.
shellPromptHere :: Spawner -> XPConfig -> X ()
shellPromptHere sp = mkPrompt (spawnHere sp)
-- | 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)
-- | Replacement for 'spawn' which launches
-- application on current workspace.
spawnHere :: Spawner -> String -> X ()
spawnHere sp cmd = withWindowSet $ \ws -> spawnOn sp (currTag ws) cmd
where currTag = W.tag . W.workspace . W.current
spawnHere sp cmd = withWindowSet $ \ws -> spawnOn sp (W.currentTag ws) cmd
-- | Replacement for 'spawn' which launches
-- application on given workspace.
spawnOn :: Spawner -> WorkspaceId -> String -> X ()
spawnOn sp ws cmd = do
p <- spawnPID cmd
io $ modifyIORef (pidsRef sp) (take maxPids . ((p, ws) :))
spawnOn sp ws cmd = spawnAndDo sp (doShift ws) cmd
-- | Spawn an application and apply the manage hook when it opens.
spawnAndDo :: Spawner -> ManageHook -> String -> X ()
spawnAndDo sp mh cmd = do
p <- spawnPID $ mangle cmd
io $ modifyIORef (pidsRef sp) (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

@@ -15,9 +15,10 @@
module XMonad.Actions.Submap (
-- * Usage
-- $usage
submap
submap,
submapDefault
) where
import Data.Bits
import XMonad hiding (keys)
import qualified Data.Map as M
import Control.Monad.Fix (fix)
@@ -33,7 +34,7 @@ First, import this module into your @~\/.xmonad\/xmonad.hs@:
Allows you to create a sub-mapping of keys. Example:
> , ((modMask x, xK_a), submap . M.fromList $
> , ((modm, xK_a), submap . M.fromList $
> [ ((0, xK_n), spawn "mpc next")
> , ((0, xK_p), spawn "mpc prev")
> , ((0, xK_z), spawn "mpc random")
@@ -57,7 +58,11 @@ For detailed instructions on editing your key bindings, see
-- corresponding action, or does nothing if the key is not found in
-- the map.
submap :: M.Map (KeyMask, KeySym) (X ()) -> X ()
submap keys = do
submap keys = submapDefault (return ()) keys
-- | Like 'submap', but executes a default action if the key did not match.
submapDefault :: X () -> M.Map (KeyMask, KeySym) (X ()) -> X ()
submapDefault def keys = do
XConf { theRoot = root, display = d } <- ask
io $ grabKeyboard d root False grabModeAsync grabModeAsync currentTime
@@ -69,8 +74,8 @@ submap keys = do
if isModifierKey keysym
then nextkey
else return (m, keysym)
-- Remove num lock mask and Xkb group state bits
m' <- cleanMask $ m .&. ((1 `shiftL` 12) - 1)
maybe def id (M.lookup (m', s) keys)
io $ ungrabKeyboard d currentTime
m' <- cleanMask m
whenJust (M.lookup (m', s) keys) id

View File

@@ -19,12 +19,13 @@ module XMonad.Actions.SwapWorkspaces (
swapWithCurrent,
swapTo,
swapWorkspaces,
WSDirection(..)
Direction1D(..)
) where
import XMonad (windows, X())
import XMonad.StackSet
import XMonad.Actions.CycleWS
import XMonad.Util.Types
import XMonad.Util.WorkspaceCompare
@@ -36,7 +37,7 @@ import XMonad.Util.WorkspaceCompare
-- Then throw something like this in your keys definition:
--
-- > ++
-- > [((modMask x .|. controlMask, k), windows $ swapWithCurrent i)
-- > [((modm .|. controlMask, k), windows $ swapWithCurrent i)
-- > | (i, k) <- zip workspaces [xK_1 ..]]
--
-- After installing this update, if you're on workspace 1, hitting mod-ctrl-5
@@ -52,7 +53,7 @@ swapWithCurrent t s = swapWorkspaces t (currentTag s) s
-- | Say @swapTo Next@ or @swapTo Prev@ to move your current workspace.
-- This is an @X ()@ so can be hooked up to your keybindings directly.
swapTo :: WSDirection -> X ()
swapTo :: Direction1D -> X ()
swapTo dir = findWorkspace getSortByIndex dir AnyWS 1 >>= windows . swapWithCurrent
-- | Takes two workspace tags and an existing XMonad.StackSet and returns a new

View File

@@ -42,16 +42,16 @@ import XMonad hiding (workspaces)
--
-- and add keybindings such as the following:
--
-- > , ((modMask x, xK_f ), withFocused (addTag "abc"))
-- > , ((modMask x .|. controlMask, xK_f ), withFocused (delTag "abc"))
-- > , ((modMask x .|. shiftMask, xK_f ), withTaggedGlobal "abc" sink)
-- > , ((modMask x, xK_d ), withTaggedP "abc" (shiftWin "2"))
-- > , ((modMask x .|. shiftMask, xK_d ), withTaggedGlobalP "abc" shiftHere)
-- > , ((modMask x .|. controlMask, xK_d ), focusUpTaggedGlobal "abc")
-- > , ((modMask x, xK_g ), tagPrompt defaultXPConfig (\s -> withFocused (addTag s)))
-- > , ((modMask x .|. controlMask, xK_g ), tagDelPrompt defaultXPConfig)
-- > , ((modMask x .|. shiftMask, xK_g ), tagPrompt defaultXPConfig (\s -> withTaggedGlobal s float))
-- > , ((modWinMask, xK_g ), tagPrompt defaultXPConfig (\s -> withTaggedP s (shiftWin "2")))
-- > , ((modm, xK_f ), withFocused (addTag "abc"))
-- > , ((modm .|. controlMask, xK_f ), withFocused (delTag "abc"))
-- > , ((modm .|. shiftMask, xK_f ), withTaggedGlobalP "abc" W.sink)
-- > , ((modm, xK_d ), withTaggedP "abc" (W.shiftWin "2"))
-- > , ((modm .|. shiftMask, xK_d ), withTaggedGlobalP "abc" shiftHere)
-- > , ((modm .|. controlMask, xK_d ), focusUpTaggedGlobal "abc")
-- > , ((modm, xK_g ), tagPrompt defaultXPConfig (\s -> withFocused (addTag s)))
-- > , ((modm .|. controlMask, xK_g ), tagDelPrompt defaultXPConfig)
-- > , ((modm .|. shiftMask, xK_g ), tagPrompt defaultXPConfig (\s -> withTaggedGlobal s float))
-- > , ((modWinMask, xK_g ), tagPrompt defaultXPConfig (\s -> withTaggedP s (W.shiftWin "2")))
-- > , ((modWinMask .|. shiftMask, xK_g ), tagPrompt defaultXPConfig (\s -> withTaggedGlobalP s shiftHere))
-- > , ((modWinMask .|. controlMask, xK_g ), tagPrompt defaultXPConfig (\s -> focusUpTaggedGlobal s))
--

View File

@@ -0,0 +1,317 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.TopicSpace
-- Copyright : (c) Nicolas Pouillard
-- License : BSD-style (see LICENSE)
--
-- Maintainer : Nicolas Pouillard <nicolas.pouillard@gmail.com>
-- Stability : unstable
-- Portability : unportable
--
-- Turns your workspaces into a more topic oriented system.
-----------------------------------------------------------------------------
module XMonad.Actions.TopicSpace
(
-- * Overview
-- $overview
-- * Usage
-- $usage
Topic
, Dir
, TopicConfig(..)
, getLastFocusedTopics
, setLastFocusedTopic
, pprWindowSet
, topicActionWithPrompt
, topicAction
, currentTopicAction
, switchTopic
, switchNthLastFocused
, shiftNthLastFocused
, currentTopicDir
, checkTopicConfig
, (>*>)
)
where
import XMonad
import Data.List
import Data.Maybe (fromMaybe, isNothing, listToMaybe)
import Data.Ord
import qualified Data.Map as M
import Control.Monad ((=<<),liftM2,when,unless,replicateM_)
import System.IO
import XMonad.Operations
import qualified XMonad.StackSet as W
import XMonad.Prompt
import XMonad.Prompt.Workspace
import XMonad.Hooks.UrgencyHook
import XMonad.Hooks.DynamicLog (PP(..))
import qualified XMonad.Hooks.DynamicLog as DL
import XMonad.Util.Run (spawnPipe)
import XMonad.Util.StringProp(getStringListProp,setStringListProp)
-- $overview
-- This module allows to organize your workspaces on a precise topic basis. So
-- instead of having a workspace called `work' you can setup one workspace per
-- task. Here we call these workspaces, topics. The great thing with
-- topics is that one can attach a directory that makes sense to each
-- particular topic. One can also attach an action which will be triggered
-- when switching to a topic that does not have any windows in it. So you can
-- attach your mail client to the mail topic, some terminals in the right
-- directory to the xmonad topic... This package also provides a nice way to
-- display your topics in an historical way using a custom `pprWindowSet'
-- function. You can also easily switch to recent topics using this history
-- of last focused topics.
-- $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
-- @
-- | An alias for @flip replicateM_@
(>*>) :: Monad m => m a -> Int -> m ()
(>*>) = flip replicateM_
infix >*>
-- | 'Topic' is just an alias for 'WorkspaceId'
type Topic = WorkspaceId
-- | 'Dir' is just an alias for 'FilePath' but should points to a directory.
type Dir = FilePath
-- | Here is the topic space configuration area.
data TopicConfig = TopicConfig { topicDirs :: M.Map Topic Dir
-- ^ This mapping associate a directory to each topic.
, topicActions :: M.Map Topic (X ())
-- ^ This mapping associate an action to trigger when
-- switching to a given topic which workspace is empty.
, defaultTopicAction :: Topic -> X ()
-- ^ This is the default topic action.
, defaultTopic :: Topic
-- ^ This is the default topic.
, maxTopicHistory :: Int
-- ^ This setups the maximum depth of topic history, usually
-- 10 is a good default since we can bind all of them using
-- numeric keypad.
}
-- | 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"
-- | 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
-- | 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
-- and highlighting topics with urgent windows.
pprWindowSet :: TopicConfig -> PP -> X String
pprWindowSet tg pp = do
winset <- gets windowset
urgents <- readUrgents
let empty_workspaces = map W.tag $ filter (isNothing . W.stack) $ W.workspaces winset
maxDepth = maxTopicHistory tg
setLastFocusedTopic tg (W.tag . W.workspace . W.current $ winset)
(`notElem` empty_workspaces)
lastWs <- getLastFocusedTopics
let depth topic = elemIndex topic lastWs
add_depth proj topic = proj pp $ maybe topic (((topic++":")++) . show) $ depth topic
pp' = pp { ppHidden = add_depth ppHidden, ppVisible = add_depth ppVisible }
sortWindows = take (maxDepth - 1) . sortBy (comparing $ fromMaybe maxDepth . depth . W.tag)
return $ DL.pprWindowSet sortWindows urgents pp' winset
-- | Given a prompt configuration and a topic configuration, triggers the action associated with
-- the topic given in prompt.
topicActionWithPrompt :: XPConfig -> TopicConfig -> X ()
topicActionWithPrompt xp tg = workspacePrompt xp (liftM2 (>>) (switchTopic tg) (topicAction tg))
-- | Given a configuration and a topic, triggers the action associated with the given topic.
topicAction :: TopicConfig -> Topic -> X ()
topicAction tg topic = fromMaybe (defaultTopicAction tg topic) $ M.lookup topic $ topicActions tg
-- | Trigger the action associated with the current topic.
currentTopicAction :: TopicConfig -> X ()
currentTopicAction tg = topicAction tg =<< gets (W.tag . W.workspace . W.current . windowset)
-- | Switch to the given topic.
switchTopic :: TopicConfig -> Topic -> X ()
switchTopic tg topic = do
windows $ W.greedyView topic
wins <- gets (W.integrate' . W.stack . W.workspace . W.current . windowset)
when (null wins) $ topicAction tg topic
-- | Switch to the Nth last focused topic or failback to the 'defaultTopic'.
switchNthLastFocused ::TopicConfig -> Int -> X ()
switchNthLastFocused tg depth = do
lastWs <- getLastFocusedTopics
switchTopic tg $ (lastWs ++ repeat (defaultTopic tg)) !! depth
-- | Shift the focused window to the Nth last focused topic, or fallback to doing nothing.
shiftNthLastFocused :: Int -> X ()
shiftNthLastFocused n = do
ws <- fmap (listToMaybe . drop n) getLastFocusedTopics
whenJust ws $ windows . W.shift
-- | Returns the directory associated with current topic returns the empty string otherwise.
currentTopicDir :: TopicConfig -> X String
currentTopicDir tg = do
topic <- gets (W.tag . W.workspace . W.current . windowset)
return . fromMaybe "" . M.lookup topic $ topicDirs tg
-- | Check the given topic configuration for duplicates topics or undefined topics.
checkTopicConfig :: [Topic] -> TopicConfig -> IO ()
checkTopicConfig tags tg = do
-- tags <- gets $ map W.tag . workspaces . windowset
let
seenTopics = nub $ sort $ M.keys (topicDirs tg) ++ M.keys (topicActions tg)
dups = tags \\ nub tags
diffTopic = seenTopics \\ sort tags
check lst msg = unless (null lst) $ xmessage $ msg ++ " (tags): " ++ show lst
check diffTopic "Seen but missing topics/workspaces"
check dups "Duplicate topics/workspaces"
-- | Display the given message using the @xmessage@ program.
xmessage :: String -> IO ()
xmessage s = do
h <- spawnPipe "xmessage -file -"
hPutStr h s
hClose h

View File

@@ -0,0 +1,61 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.UpdateFocus
-- Copyright : (c) Daniel Schoepe
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : Daniel Schoepe <asgaroth_@gmx.de>
-- Stability : unstable
-- Portability : unportable
--
-- Updates the focus on mouse move in unfocused windows.
--
-----------------------------------------------------------------------------
module XMonad.Actions.UpdateFocus (
-- * Usage
-- $usage
focusOnMouseMove,
adjustEventInput
) where
import XMonad
import qualified XMonad.StackSet as W
import Graphics.X11.Xlib.Extras
import Control.Monad (when)
import Data.Monoid
-- $usage
-- To make the focus update on mouse movement within an unfocused window, add the
-- following to your @~\/.xmonad\/xmonad.hs@:
--
-- > import XMonad.Actions.UpdateFocus
-- > xmonad $ defaultConfig {
-- > ..
-- > startupHook = adjustEventInput
-- > handleEventHook = focusOnMouseMove
-- > ..
-- > }
--
-- This module is probably only useful when focusFollowsMouse is set to True(default).
-- | Changes the focus if the mouse is moved within an unfocused window.
focusOnMouseMove :: Event -> X All
focusOnMouseMove (MotionEvent { ev_x = x, ev_y = y, ev_window = root }) = do
-- check only every 15 px to avoid excessive calls to translateCoordinates
when (x `mod` 15 == 0 || y `mod` 15 == 0) $ do
dpy <- asks display
Just foc <- withWindowSet $ return . W.peek
-- get the window under the pointer:
(_,_,_,w) <- io $ translateCoordinates dpy root root (fromIntegral x) (fromIntegral y)
when (foc /= w) $ focus w
return (All True)
focusOnMouseMove _ = return (All True)
-- | Adjusts the event mask to pick up pointer movements.
adjustEventInput :: X ()
adjustEventInput = withDisplay $ \dpy -> do
rootw <- asks theRoot
io $ selectInput dpy rootw $ substructureRedirectMask .|. substructureNotifyMask
.|. enterWindowMask .|. leaveWindowMask .|. structureNotifyMask
.|. buttonPressMask .|. pointerMotionMask

View File

@@ -3,7 +3,7 @@
-- Module : XMonadContrib.UpdatePointer
-- Copyright : (c) Robert Marlow <robreim@bobturf.org>
-- License : BSD3-style (see LICENSE)
--
--
-- Maintainer : Robert Marlow <robreim@bobturf.org>
-- Stability : stable
-- Portability : portable
@@ -14,7 +14,7 @@
--
-----------------------------------------------------------------------------
module XMonad.Actions.UpdatePointer
module XMonad.Actions.UpdatePointer
(
-- * Usage
-- $usage
@@ -25,7 +25,8 @@ module XMonad.Actions.UpdatePointer
import XMonad
import Control.Monad
import XMonad.StackSet (member)
import XMonad.StackSet (member, peek, screenDetail, current)
import Data.Maybe
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
@@ -34,9 +35,9 @@ import XMonad.StackSet (member)
-- > import XMonad.Actions.UpdatePointer
--
-- Enable it by including it in your logHook definition. Eg:
--
--
-- > logHook = updatePointer Nearest
--
--
-- which will move the pointer to the nearest point of a newly focused window, or
--
-- > logHook = updatePointer (Relative 0.5 0.5)
@@ -50,43 +51,55 @@ import XMonad.StackSet (member)
--
-- which moves the pointer to the bottom-right corner of the focused window.
data PointerPosition = Nearest | Relative Rational Rational
data PointerPosition = Nearest | Relative Rational Rational | TowardsCentre Rational Rational
deriving (Read,Show)
-- | Update the pointer's location to the currently focused
-- window unless it's already there, or unless the user was changing
-- window or empty screen unless it's already there, or unless the user was changing
-- focus with the mouse
updatePointer :: PointerPosition -> X ()
updatePointer p = withFocused $ \w -> do
updatePointer p = do
ws <- gets windowset
dpy <- asks display
rect <- case peek ws of
Nothing -> return $ (screenRect . screenDetail .current) ws
Just w -> windowAttributesToRectangle `fmap` io (getWindowAttributes dpy w)
root <- asks theRoot
mouseIsMoving <- asks mouseFocused
wa <- io $ getWindowAttributes dpy w
(_sameRoot,_,currentWindow,rootx,rooty,_,_,_) <- io $ queryPointer dpy root
unless (pointWithinRegion rootx rooty (wa_x wa) (wa_y wa) (wa_width wa) (wa_height wa)
drag <- gets dragging
unless (pointWithin (fi rootx) (fi rooty) rect
|| mouseIsMoving
|| not (currentWindow `member` ws)) $
|| isJust drag
|| not (currentWindow `member` ws || currentWindow == none)) $
case p of
Nearest -> do
let x = moveWithin rootx (wa_x wa) ((wa_x wa) + (wa_width wa))
let y = moveWithin rooty (wa_y wa) ((wa_y wa) + (wa_height wa))
io $ warpPointer dpy none root 0 0 0 0 (fromIntegral x) (fromIntegral y)
let x = moveWithin (fi rootx) (rect_x rect) (fi (rect_x rect) + fi (rect_width rect))
y = moveWithin (fi rooty) (rect_y rect) (fi (rect_y rect) + fi (rect_height rect))
io $ warpPointer dpy none root 0 0 0 0 x y
TowardsCentre xfrc yfrc -> do
let cx = fi (rect_width rect) / 2 + fi (rect_x rect)
cy = fi (rect_height rect) / 2 + fi (rect_y rect)
x,y,cx,cy :: Rational
x = moveWithin (fi rootx) (fi $ rect_x rect) (fi (rect_x rect) + fi (rect_width rect))
y = moveWithin (fi rooty) (fi $ rect_y rect) (fi (rect_y rect) + fi (rect_height rect))
io $ warpPointer dpy none root 0 0 0 0 (round $ x + xfrc*(cx-x)) (round $ y + yfrc*(cy-y))
Relative h v ->
io $ warpPointer dpy none w 0 0 0 0
(fraction h (wa_width wa)) (fraction v (wa_height wa))
io $ warpPointer dpy none root 0 0 0 0
(rect_x rect + fraction h (rect_width rect))
(rect_y rect + fraction v (rect_height rect))
where fraction x y = floor (x * fromIntegral y)
moveWithin :: Integral a => a -> a -> a -> a
moveWithin current lower upper =
if current < lower
windowAttributesToRectangle :: WindowAttributes -> Rectangle
windowAttributesToRectangle wa = Rectangle (fi (wa_x wa)) (fi (wa_y wa))
(fi (wa_width wa)) (fi (wa_height wa))
moveWithin :: Ord a => a -> a -> a -> a
moveWithin now lower upper =
if now < lower
then lower
else if current > upper
else if now > upper
then upper
else current
else now
-- Test that a point resides within a region.
-- This belongs somewhere more generally accessible than this module.
pointWithinRegion :: Integral a => a -> a -> a -> a -> a -> a -> Bool
pointWithinRegion px py rx ry rw rh =
within px rx (rx + rw) && within py ry (ry + rh)
where within x left right = x >= left && x <= right
fi :: (Num b, Integral a) => a -> b
fi = fromIntegral

View File

@@ -34,11 +34,11 @@ You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
then add appropriate keybindings to warp the pointer; for example:
> , ((modMask x, xK_z ), warpToWindow (1%2) (1%2)) -- @@ Move pointer to currently focused window
> , ((modm, xK_z ), warpToWindow (1%2) (1%2)) -- @@ Move pointer to currently focused window
>
>-- mod-ctrl-{w,e,r} @@ Move mouse pointer to screen 1, 2, or 3
>
> [((modMask x .|. controlMask, key), warpToScreen sc (1%2) (1%2))
> [((modm .|. controlMask, key), warpToScreen sc (1%2) (1%2))
> | (key, sc) <- zip [xK_w, xK_e, xK_r] [0..]]
Note that warping to a particular screen may change the focus.

View File

@@ -5,7 +5,7 @@
-- License : BSD-style (see LICENSE)
--
-- Maintainer : Devin Mullins <me@twifkak.com>
-- Stability : unstable
-- Stability : stable
-- Portability : unportable
--
-- dmenu operations to bring windows to you, and bring you to windows.
@@ -15,11 +15,11 @@
-----------------------------------------------------------------------------
module XMonad.Actions.WindowBringer (
-- * Usage
-- $usage
gotoMenu, gotoMenu', bringMenu, windowMap,
bringWindow
) where
-- * Usage
-- $usage
gotoMenu, gotoMenu', bringMenu, windowMap,
bringWindow
) where
import Data.Char (toLower)
import qualified Data.Map as M
@@ -38,8 +38,8 @@ import XMonad.Util.NamedWindows (getName)
--
-- and define appropriate key bindings:
--
-- > , ((modMask x .|. shiftMask, xK_g ), gotoMenu)
-- > , ((modMask x .|. shiftMask, xK_b ), bringMenu)
-- > , ((modm .|. shiftMask, xK_g ), gotoMenu)
-- > , ((modm .|. shiftMask, xK_b ), bringMenu)
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".

View File

@@ -28,18 +28,23 @@ module XMonad.Actions.WindowGo (
runOrRaiseMaster,
raiseAndDo,
raiseMaster,
ifWindows,
ifWindow,
raiseHook,
module XMonad.ManageHook
) where
import Control.Monad (filterM)
import Control.Monad
import Data.Char (toLower)
import XMonad (Query(), X(), withWindowSet, spawn, runQuery, liftIO)
import Data.Monoid
import XMonad (Query(), X(), ManageHook, withWindowSet, runQuery, liftIO, ask)
import Graphics.X11 (Window)
import XMonad.ManageHook
import XMonad.Operations (windows)
import XMonad.Prompt.Shell (getBrowser, getEditor)
import qualified XMonad.StackSet as W (allWindows, peek, swapMaster, focusWindow)
import XMonad.Util.Run (safeSpawnProg)
{- $usage
Import the module into your @~\/.xmonad\/xmonad.hs@:
@@ -48,8 +53,8 @@ Import the module into your @~\/.xmonad\/xmonad.hs@:
and define appropriate key bindings:
> , ((modMask x .|. shiftMask, xK_g), raise (className =? "Firefox"))
> , ((modMask x .|. shiftMask, xK_b), runOrRaise "firefox" (className =? "Firefox"))
> , ((modm .|. shiftMask, xK_g), raise (className =? "Firefox"))
> , ((modm .|. shiftMask, xK_b), runOrRaise "firefox" (className =? "Firefox"))
(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
@@ -59,20 +64,35 @@ appropriate one, or cover your bases by using instead something like
For detailed instructions on editing your key bindings, see
"XMonad.Doc.Extending#Editing_key_bindings". -}
-- | 'action' is an executable to be run via 'spawn' (of "XMonad.Core") if the Window cannot be found.
-- | If windows that satisfy the query exist, apply the supplied
-- function to them, otherwise run the action given as
-- second parameter.
ifWindows :: Query Bool -> ([Window] -> X ()) -> X () -> X ()
ifWindows qry f el = withWindowSet $ \wins -> do
matches <- filterM (runQuery qry) $ W.allWindows wins
case matches of
[] -> el
ws -> f ws
-- | The same as ifWindows, but applies a ManageHook to the first match
-- instead and discards the other matches
ifWindow :: Query Bool -> ManageHook -> X () -> X ()
ifWindow qry mh = ifWindows qry (windows . appEndo <=< runQuery mh . head)
-- | 'action' is an executable to be run via 'safeSpawnProg' (of "XMonad.Util.Run") if the Window cannot be found.
-- Presumably this executable is the same one that you were looking for.
runOrRaise :: String -> Query Bool -> X ()
runOrRaise = raiseMaybe . spawn
runOrRaise = raiseMaybe . safeSpawnProg
-- | See 'raiseMaybe'. If the Window can't be found, quietly give up and do nothing.
raise :: Query Bool -> X ()
raise = raiseMaybe $ return ()
{- | 'raiseMaybe' queries all Windows based on a boolean provided by the
user. Currently, there are three such useful booleans defined in
"XMonad.ManageHook": title, resource, className. Each one tests based pretty
user. Currently, there are 3 such useful booleans defined in
"XMonad.ManageHook": 'title', 'resource', 'className'. Each one tests based pretty
much as you would think. ManageHook also defines several operators, the most
useful of which is (=?). So a useful test might be finding a Window whose
useful of which is (=?). So a useful test might be finding a @Window@ whose
class is Firefox. Firefox 3 declares the class \"Firefox\", so you'd want to
pass in a boolean like @(className =? \"Firefox\")@.
@@ -95,15 +115,15 @@ raise = raiseMaybe $ return ()
> , ((modm, xK_m), raiseMaybe (runInTerm "-title mutt" "mutt") (title =? "mutt"))
-}
raiseMaybe :: X () -> Query Bool -> X ()
raiseMaybe f thatUserQuery = withWindowSet $ \s -> do
maybeResult <- filterM (runQuery thatUserQuery) (W.allWindows s)
case maybeResult of
[] -> f
(x:_) -> windows $ W.focusWindow x
raiseMaybe f qry = ifWindow qry raiseHook f
-- | A manage hook that raises the window.
raiseHook :: ManageHook
raiseHook = ask >>= doF . W.focusWindow
-- | See 'runOrRaise' and 'raiseNextMaybe'. Version that allows cycling through matches.
runOrRaiseNext :: String -> Query Bool -> X ()
runOrRaiseNext = raiseNextMaybe . spawn
runOrRaiseNext = raiseNextMaybe . safeSpawnProg
-- | See 'raise' and 'raiseNextMaybe'. Version that allows cycling through matches.
raiseNext :: Query Bool -> X ()
@@ -115,18 +135,14 @@ raiseNext = raiseNextMaybe $ return ()
query the next matching window is raised. If no matches are found
the function f is executed.
-}
raiseNextMaybe :: X () -> Query Bool -> X ()
raiseNextMaybe f thatUserQuery = withWindowSet $ \s -> do
ws <- filterM (runQuery thatUserQuery) (W.allWindows s)
case ws of
[] -> f
(x:_) -> let go (Just w) | (w `elem` ws) = next w $ cycle ws
go _ = windows $ W.focusWindow x
in go $ W.peek s
where
next w (x:y:_) | x==w = windows $ W.focusWindow y
next w (_:xs) = next w xs
next _ _ = error "raiseNextMaybe: empty list"
raiseNextMaybe f qry = flip (ifWindows qry) f $ \ws -> do
foc <- withWindowSet $ return . W.peek
case foc of
Just w | w `elem` ws -> let (_:y:_) = dropWhile (/=w) $ cycle ws -- cannot fail to match
in windows $ W.focusWindow y
_ -> windows . W.focusWindow . head $ ws
-- | Given a function which gets us a String, we try to raise a window with that classname,
-- or we then interpret that String as a executable name.
@@ -135,38 +151,34 @@ raiseVar getvar = liftIO getvar >>= \var -> runOrRaise var (fmap (map toLower) c
{- | 'raiseBrowser' and 'raiseEditor' grab $BROWSER and $EDITOR respectively and they either
take you to the specified program's window, or they try to run it. This is most useful
if your variables are simple and look like 'firefox' or 'emacs'. -}
if your variables are simple and look like \"firefox\" or \"emacs\". -}
raiseBrowser, raiseEditor :: X ()
raiseBrowser = raiseVar getBrowser
raiseEditor = raiseVar getEditor
{- | if the window is found the window is focused and the third argument is called
{- | If the window is found the window is focused and the third argument is called
otherwise, the first argument is called
See 'raiseMaster' for an example -}
See 'raiseMaster' for an example. -}
raiseAndDo :: X () -> Query Bool -> (Window -> X ())-> X ()
raiseAndDo raisef thatUserQuery afterRaise = withWindowSet $ \s -> do
maybeResult <- filterM (runQuery thatUserQuery) (W.allWindows s)
case maybeResult of
[] -> raisef
(x:_) -> do windows $ W.focusWindow x
afterRaise x
raiseAndDo f qry after = ifWindow qry (afterRaise `mappend` raiseHook) f
where afterRaise = ask >>= (>> idHook) . liftX . after
{- | if the window is found the window is focused and the third argument is called
otherwise, raisef is called -}
{- | If a window matching the second arugment is found, the window is focused and the third argument is called;
otherwise, the first argument is called. -}
runOrRaiseAndDo :: String -> Query Bool -> (Window -> X ()) -> X ()
runOrRaiseAndDo = raiseAndDo . spawn
runOrRaiseAndDo = raiseAndDo . safeSpawnProg
{- | if the window is found the window is focused and set to master
otherwise, the first argument is called
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
{- | 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

@@ -0,0 +1,71 @@
----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.WindowMenu
-- Copyright : (c) Jan Vornberger 2009
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : jan.vornberger@informatik.uni-oldenburg.de
-- Stability : unstable
-- Portability : not portable
--
-- Uses "XMonad.Actions.GridSelect" to display a number of actions related to
-- window management in the center of the focused window. Actions include: Closing,
-- maximizing, minimizing and shifting the window to another workspace.
--
-- 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.Actions.WindowMenu (
-- * Usage
-- $usage
windowMenu
) where
import XMonad
import qualified XMonad.StackSet as W
import XMonad.Actions.GridSelect
import XMonad.Layout.Maximize
import XMonad.Layout.Minimize
import XMonad.Util.XUtils (fi)
-- $usage
--
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
--
-- > import XMonad.Actions.WindowMenu
--
-- Then add a keybinding, e.g.
--
-- > , ((modm, xK_o ), windowMenu)
windowMenu :: X ()
windowMenu = withFocused $ \w -> do
tags <- asks (workspaces . config)
Rectangle x y wh ht <- getSize w
Rectangle sx sy swh sht <- gets $ screenRect . W.screenDetail . W.current . windowset
let originFractX = (fi x - fi sx + fi wh / 2) / fi swh
originFractY = (fi y - fi sy + fi ht / 2) / fi sht
gsConfig = defaultGSConfig
{ gs_originFractX = originFractX
, gs_originFractY = originFractY }
actions = [ ("Cancel menu", return ())
, ("Close" , kill)
, ("Maximize" , sendMessage $ maximizeRestore w)
, ("Minimize" , sendMessage $ MinimizeWin w)
] ++
[ ("Move to " ++ tag, windows $ W.shift tag)
| tag <- tags ]
runSelectedAction gsConfig actions
getSize :: Window -> X (Rectangle)
getSize w = do
d <- asks display
wa <- io $ getWindowAttributes d w
let x = fi $ wa_x wa
y = fi $ wa_y wa
wh = fi $ wa_width wa
ht = fi $ wa_height wa
return (Rectangle x y wh ht)

View File

@@ -5,6 +5,8 @@
-- Devin Mullins <me@twifkak.com>
-- Maintainer : Devin Mullins <me@twifkak.com>
-- License : BSD3-style (see LICENSE)
-- Stability : unstable
-- Portability : unportable
--
-- This is a rewrite of "XMonad.Layout.WindowNavigation". WindowNavigation
-- lets you assign keys to move up\/down\/left\/right, based on actual cartesian
@@ -34,11 +36,11 @@ module XMonad.Actions.WindowNavigation (
withWindowNavigationKeys,
WNAction(..),
go, swap,
Direction(..)
Direction2D(..)
) where
import XMonad
import XMonad.Hooks.ManageDocks (Direction(..))
import XMonad.Util.Types (Direction2D(..))
import qualified XMonad.StackSet as W
import Control.Applicative ((<$>))
@@ -84,15 +86,15 @@ import Graphics.X11.Xlib
-- - manageHook to draw window decos?
withWindowNavigation :: (KeySym, KeySym, KeySym, KeySym) -> XConfig l -> IO (XConfig l)
withWindowNavigation (u,l,d,r) conf =
withWindowNavigationKeys [ ((modMask conf , u), WNGo U),
((modMask conf , l), WNGo L),
((modMask conf , d), WNGo D),
((modMask conf , r), WNGo R),
((modMask conf .|. shiftMask, u), WNSwap U),
((modMask conf .|. shiftMask, l), WNSwap L),
((modMask conf .|. shiftMask, d), WNSwap D),
((modMask conf .|. shiftMask, r), WNSwap R) ]
withWindowNavigation (u,l,d,r) conf@XConfig{modMask=modm} =
withWindowNavigationKeys [ ((modm , u), WNGo U),
((modm , l), WNGo L),
((modm , d), WNGo D),
((modm , r), WNGo R),
((modm .|. shiftMask, u), WNSwap U),
((modm .|. shiftMask, l), WNSwap L),
((modm .|. shiftMask, d), WNSwap D),
((modm .|. shiftMask, r), WNSwap R) ]
conf
withWindowNavigationKeys :: [((KeyMask, KeySym), WNAction)] -> XConfig l -> IO (XConfig l)
@@ -104,7 +106,7 @@ withWindowNavigationKeys wnKeys conf = do
where fromWNAction posRef (WNGo dir) = go posRef dir
fromWNAction posRef (WNSwap dir) = swap posRef dir
data WNAction = WNGo Direction | WNSwap Direction
data WNAction = WNGo Direction2D | WNSwap Direction2D
type WNState = Map WorkspaceId Point
@@ -113,10 +115,10 @@ type WNState = Map WorkspaceId Point
-- 2. get target windowrect
-- 3. focus window
-- 4. set new position
go :: IORef WNState -> Direction -> X ()
go :: IORef WNState -> Direction2D -> X ()
go = withTargetWindow W.focusWindow
swap :: IORef WNState -> Direction -> X ()
swap :: IORef WNState -> Direction2D -> X ()
swap = withTargetWindow swapWithFocused
where swapWithFocused targetWin winSet =
case W.peek winSet of
@@ -128,7 +130,7 @@ swap = withTargetWindow swapWithFocused
mapWindows'' f (W.Stack focused up down) = W.Stack (f focused) (map f up) (map f down)
swapWin win1 win2 win = if win == win1 then win2 else if win == win2 then win1 else win
withTargetWindow :: (Window -> WindowSet -> WindowSet) -> IORef WNState -> Direction -> X ()
withTargetWindow :: (Window -> WindowSet -> WindowSet) -> IORef WNState -> Direction2D -> X ()
withTargetWindow adj posRef dir = fromCurrentPoint posRef $ \win pos -> do
targets <- filter ((/= win) . fst) <$> navigableTargets pos dir
whenJust (listToMaybe targets) $ \(targetWin, targetRect) -> do
@@ -175,12 +177,12 @@ Point x y `inside` Rectangle rx ry rw rh =
midPoint :: Position -> Dimension -> Position
midPoint pos dim = pos + fromIntegral dim `div` 2
navigableTargets :: Point -> Direction -> X [(Window, Rectangle)]
navigableTargets :: Point -> Direction2D -> X [(Window, Rectangle)]
navigableTargets point dir = navigable dir point <$> windowRects
-- Filters and sorts the windows in terms of what is closest from the Point in
-- the Direction.
navigable :: Direction -> Point -> [(Window, Rectangle)] -> [(Window, Rectangle)]
-- the Direction2D.
navigable :: Direction2D -> Point -> [(Window, Rectangle)] -> [(Window, Rectangle)]
navigable d pt = sortby d . filter (inr d pt . snd)
-- Produces a list of normal-state windows, on any screen. Rectangles are
@@ -197,7 +199,7 @@ windowRect win = withDisplay $ \dpy -> do
-- Modified from droundy's implementation of WindowNavigation:
inr :: Direction -> Point -> Rectangle -> Bool
inr :: Direction2D -> Point -> Rectangle -> Bool
inr D (Point px py) (Rectangle rx ry w h) = px >= rx && px < rx + fromIntegral w &&
py < ry + fromIntegral h
inr U (Point px py) (Rectangle rx ry w _) = px >= rx && px < rx + fromIntegral w &&
@@ -207,7 +209,7 @@ inr R (Point px py) (Rectangle rx ry _ h) = px < rx &&
inr L (Point px py) (Rectangle rx ry w h) = px > rx + fromIntegral w &&
py >= ry && py < ry + fromIntegral h
sortby :: Direction -> [(a,Rectangle)] -> [(a,Rectangle)]
sortby :: Direction2D -> [(a,Rectangle)] -> [(a,Rectangle)]
sortby D = sortBy $ comparing (rect_y . snd)
sortby R = sortBy $ comparing (rect_x . snd)
sortby U = reverse . sortby D

54
XMonad/Actions/WithAll.hs Normal file
View File

@@ -0,0 +1,54 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.WithAll
-- License : BSD3-style (see LICENSE)
-- Stability : unstable
-- Portability : unportable
--
-- Provides functions for performing a given action on all windows of
-- the current workspace.
-----------------------------------------------------------------------------
module XMonad.Actions.WithAll (
-- * Usage
-- $usage
sinkAll, withAll,
withAll', killAll) where
import Data.Foldable hiding (foldr)
import XMonad
import XMonad.Core
import XMonad.Operations
import XMonad.StackSet
-- $usage
--
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
--
-- > import XMonad.Actions.WithAll
--
-- then add a keybinding; for example:
--
-- , ((modm .|. shiftMask, xK_t), sinkAll)
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
-- | Un-float all floating windows on the current workspace.
sinkAll :: X ()
sinkAll = withAll' sink
-- | Apply a function to all windows on the current workspace.
withAll' :: (Window -> WindowSet -> WindowSet) -> X ()
withAll' f = windows $ \ws -> let all' = integrate' . stack . workspace . current $ ws
in foldr f ws all'
-- | Execute an 'X' action for each window on the current workspace.
withAll :: (Window -> X ()) -> X()
withAll f = withWindowSet $ \ws -> let all' = integrate' . stack . workspace . current $ ws
in forM_ all' f
-- | Kill all the windows on the current workspace.
killAll :: X()
killAll = withAll killWindow

View File

@@ -0,0 +1,219 @@
{-# LANGUAGE DeriveDataTypeable, FlexibleInstances, MultiParamTypeClasses #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.WorkspaceCursors
-- Copyright : (c) 2009 Adam Vogt <vogt.adam@gmail.com>
-- License : BSD
--
-- Maintainer : Adam Vogt
-- Stability : unstable
-- Portability : unportable
--
-- Like "XMonad.Actions.Plane" for an arbitrary number of dimensions.
-----------------------------------------------------------------------------
module XMonad.Actions.WorkspaceCursors
(
-- * Usage
-- $usage
focusDepth
,makeCursors
,toList
,workspaceCursors
,WorkspaceCursors
,getFocus
-- * Modifying the focus
,modifyLayer
,modifyLayer'
,shiftModifyLayer,shiftLayer
-- * Functions to pass to 'modifyLayer'
,focusNth'
,noWrapUp,noWrapDown
-- * Todo
-- $todo
) where
import qualified XMonad.StackSet as W
import XMonad.Actions.FocusNth(focusNth')
import XMonad.Layout.LayoutModifier(ModifiedLayout(..),
LayoutModifier(handleMess, redoLayout))
import XMonad(Typeable, Message, WorkspaceId, X, XState(windowset),
fromMessage, sendMessage, windows, gets)
import Control.Monad((<=<), guard, liftM, liftM2, when)
import Control.Applicative((<$>))
import Data.Foldable(Foldable(foldMap), toList)
import Data.Maybe(fromJust, listToMaybe)
import Data.Monoid(Monoid(mappend, mconcat))
import Data.Traversable(sequenceA)
-- $usage
--
-- Here is an example config:
--
-- > import XMonad
-- > import XMonad.Actions.WorkspaceCursors
-- > import XMonad.Hooks.DynamicLog
-- > import XMonad.Util.EZConfig
-- > import qualified XMonad.StackSet as W
-- >
-- > main = do
-- > x <- xmobar conf
-- > xmonad x
-- >
-- > conf = additionalKeysP defaultConfig
-- > { layoutHook = workspaceCursors myCursors $ layoutHook defaultConfig
-- > , workspaces = toList myCursors } $
-- > [("M-"++shift++control++[k], f direction depth)
-- > | (f,shift) <- zip [modifyLayer,shiftModifyLayer] ["","S-"]
-- > , (direction,control) <- zip [W.focusUp',W.focusDown'] ["C-",""]
-- > , (depth,k) <- zip (reverse [1..focusDepth myCursors]) "asdf"]
-- > ++ moreKeybindings
-- >
-- > moreKeybindings = []
-- >
-- > myCursors = makeCursors $ map (map (\x -> [x])) [ "1234", "abc", "xyz"]
-- > -- myCursors = makeCursors [["wsA","wsB","wsC"],["-alpha-","-beta-","-gamma-"],["x","y"]]
-- $todo
--
-- * Find and document how to raise the allowable length of arguments:
-- restoring xmonad's state results in: @xmonad: executeFile: resource
-- exhausted (Argument list too long)@ when you specify more than about 50
-- workspaces. Or change it such that workspaces are created when you try to
-- view it.
--
-- * Function for pretty printing for DynamicLog that groups workspaces by
-- common prefixes
--
-- * Examples of adding workspaces to the cursors, having them appear multiple
-- times for being able to show jumping to some n'th multiple workspace
-- | makeCursors requires a nonempty string, and each sublist must be nonempty
makeCursors :: [[String]] -> Cursors String
makeCursors [] = error "Workspace Cursors cannot be empty"
makeCursors a = concat . reverse <$> foldl addDim x xs
where x = end $ map return $ head a
xs = map (map return) $ tail a
-- this could probably be simplified, but this true:
-- toList . makeCursors == map (concat . reverse) . sequence . reverse . map (map (:[]))
-- the strange order is used because it makes the regular M-1..9
-- bindings change the prefixes first
addDim :: (Monoid a) => Cursors a -> [a] -> Cursors a
addDim prev prefixes = Cons . fromJust . W.differentiate
$ map ((<$> prev) . mappend) prefixes
end :: [a] -> Cursors a
end = Cons . fromJust . W.differentiate . map End
data Cursors a
= Cons (W.Stack (Cursors a))
| End a deriving (Eq,Show,Read,Typeable)
instance Foldable Cursors where
foldMap f (End x) = f x
foldMap f (Cons (W.Stack x y z)) = foldMap f x `mappend` mconcat (map (foldMap f) $ reverse y ++ z)
instance Functor Cursors where
fmap f (End a) = End $ f a
fmap f (Cons (W.Stack x y z)) = Cons $ W.Stack (fmap f x) (fmap (fmap f) y) (fmap (fmap f) z)
changeFocus :: (Cursors t -> Bool) -> Cursors t -> [Cursors t]
changeFocus p (Cons x) = do
choose <- chFocus p x
foc <- changeFocus p $ W.focus choose
return . Cons $ choose { W.focus = foc }
changeFocus p x = guard (p x) >> return x
chFocus :: (a -> Bool) -> W.Stack a -> [W.Stack a]
chFocus p st = filter (p . W.focus) $ zipWith const (iterate W.focusDown' st) (W.integrate st)
getFocus :: Cursors b -> b
getFocus (Cons x) = getFocus $ W.focus x
getFocus (End x) = x
-- This could be made more efficient, if the fact that the suffixes are grouped
focusTo :: (Eq t) => t -> Cursors t -> Maybe (Cursors t)
focusTo x = listToMaybe . filter ((x==) . getFocus) . changeFocus (const True)
-- | non-wrapping version of 'W.focusUp''
noWrapUp :: W.Stack t -> W.Stack t
noWrapUp (W.Stack t (l:ls) rs) = W.Stack l ls (t:rs)
noWrapUp x@(W.Stack _ [] _ ) = x
-- | non-wrapping version of 'W.focusDown''
noWrapDown :: W.Stack t -> W.Stack t
noWrapDown = reverseStack . noWrapUp . reverseStack
where reverseStack (W.Stack t ls rs) = W.Stack t rs ls
focusDepth :: Cursors t -> Int
focusDepth (Cons x) = 1 + focusDepth (W.focus x)
focusDepth (End _) = 0
descend :: Monad m =>(W.Stack (Cursors a) -> m (W.Stack (Cursors a)))-> Int-> Cursors a-> m (Cursors a)
descend f 1 (Cons x) = Cons `liftM` f x
descend f n (Cons x) | n > 1 = liftM Cons $ descend f (pred n) `onFocus` x
descend _ _ x = return x
onFocus :: (Monad m) => (a1 -> m a1) -> W.Stack a1 -> m (W.Stack a1)
onFocus f st = (\x -> st { W.focus = x}) `liftM` f (W.focus st)
-- | @modifyLayer@ is used to change the focus at a given depth
modifyLayer :: (W.Stack (Cursors String) -> W.Stack (Cursors String)) -> Int -> X ()
modifyLayer f depth = modifyCursors (descend (return . f) depth)
-- | @shiftModifyLayer@ is the same as 'modifyLayer', but also shifts the
-- currently focused window to the new workspace
shiftModifyLayer :: (W.Stack (Cursors String) -> W.Stack (Cursors WorkspaceId))-> Int-> X ()
shiftModifyLayer f = modifyLayer' $ \st -> do
let st' = f st
windows $ W.shift $ getFocus (Cons st')
return st'
-- | @shiftLayer@ is the same as 'shiftModifyLayer', but the focus remains on
-- the current workspace.
shiftLayer :: (W.Stack (Cursors String) -> W.Stack (Cursors WorkspaceId))-> Int-> X ()
shiftLayer f = modifyLayer' $ \st -> do
windows $ W.shift $ getFocus $ Cons $ f st
return st
-- | example usages are 'shiftLayer' and 'shiftModifyLayer'
modifyLayer' :: (W.Stack (Cursors String) -> X (W.Stack (Cursors String))) -> Int -> X ()
modifyLayer' f depth = modifyCursors (descend f depth)
modifyCursors :: (Cursors String -> X (Cursors String)) -> X ()
modifyCursors = sendMessage . ChangeCursors . (liftM2 (>>) updateXMD return <=<)
data WorkspaceCursors a = WorkspaceCursors (Cursors String)
deriving (Typeable,Read,Show)
-- | The state is stored in the 'WorkspaceCursors' layout modifier. Put this as
-- your outermost modifier, unless you want different cursors at different
-- times (using "XMonad.Layout.MultiToggle")
workspaceCursors :: Cursors String -> l a -> ModifiedLayout WorkspaceCursors l a
workspaceCursors = ModifiedLayout . WorkspaceCursors
data ChangeCursors = ChangeCursors { unWrap :: Cursors String -> X (Cursors String) }
deriving (Typeable)
instance Message ChangeCursors
updateXMD :: Cursors WorkspaceId -> X ()
updateXMD cs = do
changed <- gets $ (getFocus cs /=) . W.currentTag . windowset
when changed $ windows $ W.greedyView $ getFocus cs
instance LayoutModifier WorkspaceCursors a where
redoLayout (WorkspaceCursors cs) _ _ arrs = do
cws <- gets $ W.currentTag . windowset
return (arrs,WorkspaceCursors <$> focusTo cws cs)
handleMess (WorkspaceCursors cs) m =
sequenceA $ fmap WorkspaceCursors . ($ cs) . unWrap <$> fromMessage m

View File

@@ -90,8 +90,7 @@ arossatoConfig = do
map show [7 .. 9 :: Int]
, logHook = myDynLog xmobar -- REMOVE this line if you do not have xmobar installed!
, manageHook = newManageHook
, layoutHook = eventHook ServerMode $
avoidStruts $
, layoutHook = avoidStruts $
decorated |||
noBorders mytabs |||
otherLays
@@ -99,6 +98,7 @@ arossatoConfig = do
, normalBorderColor = "white"
, focusedBorderColor = "black"
, keys = newKeys
, handleEventHook = serverModeEventHook
, focusFollowsMouse = False
}
where

View File

@@ -7,6 +7,8 @@
-- License : BSD
--
-- Maintainer : Devin Mullins <me@twifkak.com>
-- Stability : stable
-- Portability : unportable
--
-- This module fixes some of the keybindings for the francophone among you who
-- use an AZERTY keyboard layout. Config stolen from TeXitoi's config on the

View File

@@ -7,29 +7,173 @@
-- License : BSD
--
-- Maintainer : Spencer Janssen <spencerjanssen@gmail.com>
-- Stability : unstable
-- Portability : unportable
--
-- This module provides a config suitable for use with a desktop
-- environment such as KDE or GNOME.
-----------------------------------------------------------------------------
module XMonad.Config.Desktop (
-- | Several basic integration settings are common to all of xmonad's
-- desktop integration configurations. The specific desktop environment
-- (DE) modules like "XMonad.Config.Gnome" use this module's
-- @desktopConfig@ to set up basic communication between xmonad and
-- the DE via a subset of the Extended Window Manager Hints (EWMH)
-- specification. Extra xmonad settings unique to specific DE's are
-- added by overriding or modifying @desktopConfig@ fields in the
-- same way that @defaultConfig@ is customized in @~\/.xmonad/xmonad.hs@.
--
-- For more information about EWMH see:
--
-- <http://standards.freedesktop.org/wm-spec/wm-spec-latest.html>
--
-- See also: "XMonad.Hooks.EwmhDesktops", "XMonad.Hooks.ManageDocks",
-- "XMonad.Util.EZConfig".
-- * Usage
-- $usage
desktopConfig,
-- * Customizing a desktop config
-- $customizing
-- ** Modifying layouts, manageHook, or key bindings
-- $layouts
desktopLayoutModifiers
-- ** Modifying the logHook
-- $logHook
-- ** Modifying the handleEventHook
-- $eventHook
-- ** Modifying the startupHook
-- $startupHook
) where
import XMonad
import XMonad.Config (defaultConfig)
import XMonad.Hooks.ManageDocks
import XMonad.Hooks.EwmhDesktops
import XMonad.Util.Cursor
import qualified Data.Map as M
desktopConfig = defaultConfig
{ logHook = ewmhDesktopsLogHook
, layoutHook = desktopLayoutModifiers $ layoutHook defaultConfig
, manageHook = manageHook defaultConfig <+> manageDocks
, keys = \c -> desktopKeys c `M.union` keys defaultConfig c }
-- $usage
-- While this document describes how to configure xmonad, you also need
-- to set up your Desktop Environment (DE) and display manager to use
-- xmonad as its window manager. For DE and distro specific tips on
-- how to do so, see the xmonad wiki:
--
-- <http://haskell.org/haskellwiki/Xmonad>
--
-- To configure xmonad for use with a DE or with DE tools like panels
-- and pagers, in place of @defaultConfig@ in your @~\/.xmonad/xmonad.hs@,
-- use @desktopConfig@ or one of the other desktop configs from the
-- @XMonad.Config@ namespace. The following setup and customization examples
-- work the same way for the other desktop configs as for @desktopConfig@.
-- If you are using a specific DE config, import its module instead, and
-- use its config in place of @desktopConfig@ in the following examples.
--
-- > import XMonad
-- > import XMonad.Config.Desktop
-- >
-- > main = xmonad desktopConfig
--
-- @desktopConfig@ is an 'XConfig' that configures xmonad to
-- ignore and leave room for dock type windows like panels and trays, adds
-- the default key binding to toggle panel visibility, and activates basic
-- EWMH support. It also sets a prettier root window mouse pointer.
-- $customizing
-- To customize a desktop config, modify its fields as is illustrated with
-- @defaultConfig@ in the \"Extending xmonad\" section of "XMonad.Doc.Extending".
-- $layouts
-- See also "XMonad.Util.EZConfig" for more options for modifying key bindings.
-- To add to layouts, manageHook or key bindings use something like the following
-- to combine your modifications with the desktop config settings:
--
-- > import XMonad
-- > import XMonad.Config.Desktop
-- > import XMonad.Layout.Tabbed
-- > import XMonad.Util.EZConfig (additionalKeys)
-- >
-- > main =
-- > xmonad $ desktopConfig {
-- > -- add manage hooks while still ignoring panels and using default manageHooks
-- > manageHook = myManageHook <+> manageHook desktopConfig
-- >
-- > -- add a fullscreen tabbed layout that does not avoid covering
-- > -- up desktop panels before the desktop layouts
-- > , layoutHook = simpleTabbed ||| layoutHook desktopConfig
-- > }
-- > -- add a screenshot key to the default desktop bindings
-- > `additionalKeys` [ ((mod4Mask, xK_F8), spawn "scrot") ]
--
-- To replace the desktop layouts with your own choices, but still
-- allow toggling panel visibility, use 'desktopLayoutModifiers' to
-- modify your layouts:
--
-- > , layoutHook = desktopLayoutModifiers $ simpleTabbed ||| Tall 1 0.03 0.5
--
-- @desktopLayoutModifiers@ modifies a layout to avoid covering docks, panels,
-- etc. that set the @_NET_WM_STRUT_PARTIAL@ property.
-- See also "XMonad.Hooks.ManageDocks".
-- $logHook
-- To add to the logHook while still sending workspace and window information
-- to DE apps use something like:
--
-- > , logHook = myLogHook >> logHook desktopConfig
--
-- Or for more elaborate logHooks you can use @do@:
--
-- > , logHook = do
-- > dynamicLogWithPP xmobarPP
-- > updatePointer (Relative 0.9 0.9)
-- > logHook desktopConfig
--
-- $eventHook
-- To customize xmonad's event handling while still having it respond
-- to EWMH events from pagers, task bars, etc. add to your imports:
--
-- > import Data.Monoid
--
-- and use 'Data.Monoid.mappend' to combine event hooks (right to left application like @\<+\>@)
--
-- > , handleEventHook = mappend myEventHooks (handleEventHook desktopConfig)
--
-- or 'Data.Monoid.mconcat' (like @composeAll@)
--
-- > , handleEventHook = mconcat
-- > [ myMouseHandler
-- > , myMessageHandler
-- > , handleEventHook desktopConfig ]
--
-- $startupHook
-- To run the desktop startupHook, plus add further actions to be run each
-- time xmonad starts or restarts, use '>>' to combine actions as in the
-- logHook example, or something like:
--
-- > , startupHook = do
-- > startupHook desktopConfig
-- > spawn "xmonad-restart.sh"
-- > adjustEventInput
--
desktopConfig = ewmh defaultConfig
{ startupHook = setDefaultCursor xC_left_ptr
, layoutHook = desktopLayoutModifiers $ layoutHook defaultConfig
, manageHook = manageHook defaultConfig <+> manageDocks
, keys = \c -> desktopKeys c `M.union` keys defaultConfig c }
desktopKeys (XConfig {modMask = modm}) = M.fromList $
[ ((modm, xK_b), sendMessage ToggleStruts) ]
desktopLayoutModifiers layout = avoidStruts $ ewmhDesktopsLayout layout
desktopLayoutModifiers layout = avoidStruts layout

View File

@@ -22,7 +22,7 @@ import XMonad.Layout.Combo ( combineTwo )
import XMonad.Layout.Named ( named )
import XMonad.Layout.LayoutCombinators
import XMonad.Layout.Square ( Square(Square) )
import XMonad.Layout.WindowNavigation ( Navigate(Move,Swap,Go), Direction(U,D,R,L),
import XMonad.Layout.WindowNavigation ( Navigate(Move,Swap,Go), Direction2D(U,D,R,L),
windowNavigation )
import XMonad.Layout.BoringWindows ( boringWindows, markBoring, clearBoring,
focusUp, focusDown )
@@ -40,11 +40,10 @@ import XMonad.Actions.CopyWindow ( kill1, copy )
import XMonad.Actions.DynamicWorkspaces ( withNthWorkspace, withWorkspace,
selectWorkspace, renameWorkspace, removeWorkspace )
import XMonad.Actions.CycleWS ( moveTo, WSType( HiddenNonEmptyWS ),
WSDirection( Prev, Next) )
Direction1D( Prev, Next) )
import XMonad.Hooks.ManageDocks ( avoidStruts, manageDocks )
import XMonad.Hooks.EwmhDesktops ( ewmhDesktopsLogHook,
ewmhDesktopsLayout )
import XMonad.Hooks.EwmhDesktops ( ewmh )
myXPConfig :: XPConfig
myXPConfig = defaultXPConfig {font="-*-lucida-medium-r-*-*-14-*-*-*-*-*-*-*"
@@ -95,7 +94,7 @@ keys x = M.fromList $
, ((modMask x .|. controlMask .|. shiftMask, xK_Left), sendMessage $ Move L)
, ((modMask x .|. controlMask .|. shiftMask, xK_Up), sendMessage $ Move U)
, ((modMask x .|. controlMask .|. shiftMask, xK_Down), sendMessage $ Move D)
, ((0, xK_F2 ), spawn "gnome-terminal") -- %! Launch gnome-terminal
, ((0, xK_F3 ), shellPrompt myXPConfig) -- %! Launch program
, ((0, xK_F11 ), spawn "ksnapshot") -- %! Take snapshot
@@ -112,16 +111,16 @@ keys x = M.fromList $
, ((modMask x, xK_space), sendMessage Toggle)
]
++
zip (zip (repeat $ modMask x) [xK_F1..xK_F12]) (map (withNthWorkspace W.greedyView) [0..])
++
zip (zip (repeat (modMask x .|. shiftMask)) [xK_F1..xK_F12]) (map (withNthWorkspace copy) [0..])
config = defaultConfig
config = ewmh defaultConfig
{ borderWidth = 1 -- Width of the window border in pixels.
, XMonad.workspaces = ["mutt","iceweasel"]
, layoutHook = ewmhDesktopsLayout $ showWName $ workspaceDir "~" $
, layoutHook = showWName $ workspaceDir "~" $
boringWindows $ smartBorders $ windowNavigation $
maximizeVertical $ toggleLayouts Full $ avoidStruts $
named "tabbed" mytab |||
@@ -131,7 +130,6 @@ config = defaultConfig
****//* combineTwo Square mytab mytab) -- |||
--mosaic 0.25 0.5
, manageHook = manageHook defaultConfig <+> manageDocks -- add panel-handling
, logHook = ewmhDesktopsLogHook -- actually, no logging here, just other stuff
, terminal = "xterm" -- The preferred terminal program.
, normalBorderColor = "#222222" -- Border color for unfocused windows.
, focusedBorderColor = "#00ff00" -- Border color for focused windows.
@@ -142,12 +140,12 @@ config = defaultConfig
mytab = tabbed CustomShrink defaultTheme
instance Shrinker CustomShrink where
shrinkIt shr s | Just s' <- dropFromHead " " s = shrinkIt shr s'
shrinkIt shr s | Just s' <- dropFromTail " " s = shrinkIt shr s'
shrinkIt shr s | Just s' <- dropFromTail "- Iceweasel" s = shrinkIt shr s'
shrinkIt shr s | Just s' <- dropFromTail "- KPDF" s = shrinkIt shr s'
shrinkIt shr s | Just s' <- dropFromHead "file://" s = shrinkIt shr s'
shrinkIt shr s | Just s' <- dropFromHead "http://" s = shrinkIt shr s'
shrinkIt shr s | Just s' <- dropFromHead " " s = shrinkIt shr s'
shrinkIt shr s | Just s' <- dropFromTail " " s = shrinkIt shr s'
shrinkIt shr s | Just s' <- dropFromTail "- Iceweasel" s = shrinkIt shr s'
shrinkIt shr s | Just s' <- dropFromTail "- KPDF" s = shrinkIt shr s'
shrinkIt shr s | Just s' <- dropFromHead "file://" s = shrinkIt shr s'
shrinkIt shr s | Just s' <- dropFromHead "http://" s = shrinkIt shr s'
shrinkIt _ s | n > 9 = s : map cut [2..(halfn-3)] ++ shrinkIt shrinkText s
where n = length s
halfn = n `div` 2

View File

@@ -7,6 +7,8 @@
-- License : BSD
--
-- Maintainer : Spencer Janssen <spencerjanssen@gmail.com>
-- Stability : unstable
-- Portability : unportable
--
-- This module provides a config suitable for use with the GNOME desktop
-- environment.
@@ -15,14 +17,18 @@ module XMonad.Config.Gnome (
-- * Usage
-- $usage
gnomeConfig,
gnomeRun
gnomeRun,
gnomeRegister
) where
import XMonad
import XMonad.Config.Desktop
import XMonad.Util.Run (safeSpawn)
import qualified Data.Map as M
import System.Environment (getEnvironment)
-- $usage
-- To use this module, start with the following @~\/.xmonad\/xmonad.hs@:
--
@@ -30,11 +36,13 @@ import qualified Data.Map as M
-- > import XMonad.Config.Gnome
-- >
-- > main = xmonad gnomeConfig
--
--
-- For examples of how to further customize @gnomeConfig@ see "XMonad.Config.Desktop".
gnomeConfig = desktopConfig
{ terminal = "gnome-terminal"
, keys = \c -> gnomeKeys c `M.union` keys desktopConfig c }
, keys = \c -> gnomeKeys c `M.union` keys desktopConfig c
, startupHook = gnomeRegister >> startupHook desktopConfig }
gnomeKeys (XConfig {modMask = modm}) = M.fromList $
[ ((modm, xK_p), gnomeRun)
@@ -53,3 +61,22 @@ gnomeRun = withDisplay $ \dpy -> do
setClientMessageEvent e rw gnome_panel 32 panel_run 0
sendEvent dpy rw False structureNotifyMask e
sync dpy False
-- | Register xmonad with gnome. 'dbus-send' must be in the $PATH with which
-- xmonad is started.
--
-- This action reduces a delay on startup only only if you have configured
-- gnome-session>=2.26: to start xmonad with a command as such:
--
-- > gconftool-2 -s /desktop/gnome/session/required_components/windowmanager xmonad --type string
gnomeRegister :: MonadIO m => m ()
gnomeRegister = io $ do
x <- lookup "DESKTOP_AUTOSTART_ID" `fmap` getEnvironment
whenJust x $ \sessionId -> safeSpawn "dbus-send"
["--session"
,"--print-reply=string"
,"--dest=org.gnome.SessionManager"
,"/org/gnome/SessionManager"
,"org.gnome.SessionManager.RegisterClient"
,"string:xmonad"
,"string:"++sessionId]

View File

@@ -7,6 +7,8 @@
-- License : BSD
--
-- Maintainer : Spencer Janssen <spencerjanssen@gmail.com>
-- Stability : unstable
-- Portability : unportable
--
-- This module provides a config suitable for use with the KDE desktop
-- environment.
@@ -32,7 +34,9 @@ import qualified Data.Map as M
-- > main = xmonad kdeConfig
--
-- For KDE 4, replace 'kdeConfig' with 'kde4Config'
--
--
-- For examples of how to further customize @kdeConfig@ see "XMonad.Config.Desktop".
kdeConfig = desktopConfig
{ terminal = "konsole"

View File

@@ -38,7 +38,7 @@ layout = fromSetGet (\x c -> c { layoutHook = x }) layoutHook
terminal = fromSetGet (\x c -> c { X.terminal = x }) X.terminal
keys = fromSetGet (\x c -> c { X.keys = x }) X.keys
set :: Accessor (XConfig LayoutList) a -> a -> Config ()
set :: Accessor (XConfig LayoutList) a -> a -> Config ()
set r x = tell (mkW $ r ^= x)
add r x = tell (mkW (r ^: mappend x))

View File

@@ -10,6 +10,7 @@ import XMonad.Config (defaultConfig)
import XMonad.Layout.NoBorders
import XMonad.Hooks.DynamicLog hiding (xmobar)
import XMonad.Hooks.ManageDocks
import XMonad.Hooks.ManageHelpers (isFullscreen, doFullFloat)
import XMonad.Hooks.EwmhDesktops
import XMonad.Prompt
import XMonad.Actions.SpawnOn
@@ -19,38 +20,39 @@ import XMonad.Layout.TwoPane
import qualified Data.Map as M
sjanssenConfigXmobar = statusBar "xmobar" sjanssenPP strutkey =<< sjanssenConfig
sjanssenConfigXmobar = statusBar "exec xmobar" sjanssenPP strutkey =<< sjanssenConfig
where
strutkey (XConfig {modMask = modm}) = (modm, xK_b)
sjanssenConfig = do
sp <- mkSpawner
return $ defaultConfig
{ terminal = "urxvtc"
return . 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
, layoutHook = modifiers layouts
, logHook = ewmhDesktopsLogHook
, manageHook = composeAll [className =? x --> doF (W.shift w)
, 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 sp
<+> (isFullscreen --> doFullFloat)
}
where
tiled = HintedTile 1 0.03 0.5 TopLeft
layouts = (tiled Tall ||| (tiled Wide ||| Full)) ||| tabbed shrinkText myTheme
modifiers = smartBorders
mykeys sp (XConfig {modMask = modm, workspaces = ws}) = M.fromList $
mykeys sp (XConfig {modMask = modm}) = M.fromList $
[((modm, xK_p ), shellPromptHere sp myPromptConfig)
,((modm .|. shiftMask, xK_Return), spawnHere sp =<< asks (terminal . config))
,((modm .|. shiftMask, xK_c ), kill1)
,((modm .|. shiftMask .|. controlMask, xK_c ), kill)
,((modm .|. shiftMask, xK_0 ), windows $ \w -> foldr copy w ws)
,((modm .|. shiftMask, xK_0 ), windows $ copyToAll)
,((modm, xK_z ), layoutScreens 2 $ TwoPane 0.5 0.5)
,((modm .|. shiftMask, xK_z ), rescreen)
]

View File

@@ -6,7 +6,9 @@
-- Copyright : (c) Ivan Miljenovic <Ivan.Miljenovic@gmail.com>
-- License : BSD
--
-- Maintainer : Ivan Miljenovic <Ivan.Miljenovic@gmail.com>
-- Maintainer : none
-- Stability : unstable
-- Portability : unportable
--
-- This module provides a config suitable for use with the Xfce desktop
-- environment.
@@ -29,7 +31,8 @@ import qualified Data.Map as M
-- > import XMonad.Config.Xfce
-- >
-- > main = xmonad xfceConfig
--
--
-- For examples of how to further customize @xfceConfig@ see "XMonad.Config.Desktop".
xfceConfig = desktopConfig
{ terminal = "Terminal"

View File

@@ -49,16 +49,25 @@ if it does exist, xmonad will use whatever settings you specify. Note
that this file can contain arbitrary Haskell code, which means that
you have quite a lot of flexibility in configuring xmonad.
NOTE for users of previous versions (< 0.5) of xmonad: this is a major
change in the way xmonad is configured. Prior to version 0.5,
configuring xmonad required editing an xmonad source file called
Config.hs, recompiling xmonad, and then restarting. From version 0.5
onwards, however, you should NOT edit this file. All you have to do
is edit xmonad.hs and restart with @mod-q@; xmonad does the
recompiling itself. The format of the configuration file has also
changed; it is now simpler and much shorter, only requiring you to
list those settings which are different from the defaults.
HISTORICAL NOTE regarding upgrading from versions (< 0.5) of xmonad
or using old documentation:
xmonad-0.5 delivered a major change in the way xmonad is configured. Prior
to version 0.5, configuring xmonad required editing a source file called
Config.hs, manually recompiling xmonad, and then restarting. From
version 0.5 onwards, however, you should NOT edit this file or manually
compile with ghc --make. All you have to do is edit xmonad.hs and restart
with @mod-q@; xmonad does the recompiling itself. The format of the
configuration file also changed with version 0.5; enabling simpler and
much shorter xmonad.hs files that only require listing those settings which
are different from the defaults.
While the complicated template.hs (man/xmonad.hs) files listing all default
settings are still provided for reference, once you wish to make substantial
changes to your configuration, the template.hs style configuration is not
recommended. It is fine to use top-level definitions to organize your
xmonad.hs, but wherever possible it is better to leave out settings that
simply duplicate defaults.
-}
{- $example
@@ -90,8 +99,8 @@ describe values that differ from the defaults.
As an alternative, you can copy the template @xmonad.hs@ file (found
either in the @man@ directory, if you have the xmonad source, or on
the xmonad wiki at
@http:\/\/haskell.org\/haskellwiki\/Xmonad\/Config_archive\/Template_xmonad.hs@)
the xmonad wiki config archive at
<http://haskell.org/haskellwiki/Xmonad/Config_archive>)
into your @~\/.xmonad\/@ directory. This template file contains all
the default settings spelled out, and you should be able to simply
change the ones you would like to change.
@@ -106,18 +115,14 @@ be found in "XMonad.Core".
#Checking_whether_your_xmonad.hs_is_correct#
After changing your configuration, it is a good idea to check that it
is syntactically and type correct. You can do this easily by loading
your configuration file in the Haskell interpreter:
is syntactically and type correct. You can do this easily by using an xmonad
flag:
> $ ghci ~/.xmonad/xmonad.hs
> GHCi, version 6.8.2: http://www.haskell.org/ghc/ :? for help
> Loading package base ... linking ... done.
> Ok, modules loaded: Main.
>
> Prelude Main> :t main
> main :: IO ()
> $ xmonad --recompile
> $
Ok, looks good.
If there is no output, your xmonad.hs has no errors. If there are errors, they
will be printed to the console. Patch them up and try again.
Note, however, that if you skip this step and try restarting xmonad
with errors in your xmonad.hs, it's not the end of the world; xmonad
@@ -139,15 +144,8 @@ all your windows, layouts, etc. intact. (If you change anything
related to your layouts, you may need to hit @mod-shift-space@ after
restarting to see the changes take effect.) If something goes wrong,
the previous (default) settings will be used. Note this requires that
GHC and xmonad are in your @$PATH@. If GHC isn't in your path, you can
still compile @xmonad.hs@ yourself:
> $ cd ~/.xmonad
> $ /path/to/ghc --make xmonad.hs
> $ ls
> xmonad xmonad.hi xmonad.hs xmonad.o
When you hit @mod-q@, this newly compiled xmonad will be used.
GHC and xmonad are in the @$PATH@ in the environment from which xmonad
is started.
-}

File diff suppressed because it is too large Load Diff

View File

@@ -53,20 +53,20 @@ import Data.IORef
-- You must include this @dynHooksRef@ value when using the functions in this
-- module:
--
-- > xmonad { keys = myKeys `Data.Map.union` Data.Map.fromList
-- > [((modMask conf, xK_i), oneShotHook dynHooksRef
-- > "FFlaunchHook" (className =? "firefox") (doShift "3")
-- > xmonad { keys = myKeys `Data.Map.union` Data.Map.fromList
-- > [((modm, xK_i), oneShotHook dynHooksRef
-- > "FFlaunchHook" (className =? "firefox") (doShift "3")
-- > >> spawn "firefox")
-- > ,((modMask conf, xK_u), addDynamicHook dynHooksRef
-- > ,((modm, xK_u), addDynamicHook dynHooksRef
-- > (className =? "example" --> doFloat))
-- > ,((modMask conf, xK_y), updatePermanentHook dynHooksRef
-- > ,((modm, xK_y), updatePermanentHook dynHooksRef
-- > (const idHook))) ] -- resets the permanent hook.
--
data DynamicHooks = DynamicHooks
{ transients :: [(Query Bool, ManageHook)]
, permanent :: ManageHook }
-- | Creates the 'IORef' that stores the dynamically created 'ManageHook's.
initDynamicHooks :: IO (IORef DynamicHooks)
@@ -80,7 +80,7 @@ initDynamicHooks = newIORef (DynamicHooks { transients = [],
-- doFloat and doIgnore are idempotent.
-- | Master 'ManageHook' that must be in your @xmonad.hs@ 'ManageHook'.
dynamicMasterHook :: IORef DynamicHooks -> ManageHook
dynamicMasterHook ref = return True -->
dynamicMasterHook ref = return True -->
(ask >>= \w -> liftX (do
dh <- io $ readIORef ref
(Endo f) <- runQuery (permanent dh) w
@@ -99,7 +99,7 @@ addDynamicHook ref m = updateDynamicHook ref (<+> m)
-- | Modifies the permanent 'ManageHook' with an arbitrary function.
updateDynamicHook :: IORef DynamicHooks -> (ManageHook -> ManageHook) -> X ()
updateDynamicHook ref f =
updateDynamicHook ref f =
io $ modifyIORef ref $ \dh -> dh { permanent = f (permanent dh) }
@@ -108,10 +108,10 @@ updateDynamicHook ref f =
--
-- > className =? "example" --> doFloat
--
-- you must call 'oneShotHook' as
-- you must call 'oneShotHook' as
--
-- > oneShotHook dynHooksRef (className =? "example) doFloat
--
--
oneShotHook :: IORef DynamicHooks -> Query Bool -> ManageHook -> X ()
oneShotHook ref q a =
io $ modifyIORef ref

View File

@@ -38,8 +38,9 @@ module XMonad.Hooks.DynamicLog (
dzenPP, xmobarPP, sjanssenPP, byorgeyPP,
-- * Formatting utilities
wrap, pad, shorten,
xmobarColor, dzenColor, dzenEscape,
wrap, pad, trim, shorten,
xmobarColor, xmobarStrip,
dzenColor, dzenEscape, dzenStrip,
-- * Internal formatting functions
pprWindowSet,
@@ -55,6 +56,7 @@ module XMonad.Hooks.DynamicLog (
--
import XMonad
import Control.Monad
import Data.Char ( isSpace )
import Data.Maybe ( isJust, catMaybes )
import Data.List
import qualified Data.Map as M
@@ -302,6 +304,11 @@ wrap l r m = l ++ m ++ r
pad :: String -> String
pad = wrap " " " "
-- | Trim leading and trailing whitespace from a string.
trim :: String -> String
trim = f . f
where f = reverse . dropWhile isSpace
-- | Limit a string to a certain length, adding "..." if truncated.
shorten :: Int -> String -> String
shorten n xs | length xs < n = xs
@@ -332,6 +339,20 @@ 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
dzenStrip :: String -> String
dzenStrip = strip [] where
strip keep x
| null x = keep
| "^^" `isPrefixOf` x = strip (keep ++ "^") (drop 2 x)
| '^' == head x = strip keep (drop 1 . dropWhile (/= ')') $ x)
| otherwise = let (good,x') = span (/= '^') x
in strip (keep ++ good) x'
-- | Use xmobar escape codes to output a string with given foreground
-- and background colors.
xmobarColor :: String -- ^ foreground color: a color name, or #rrggbb format
@@ -343,6 +364,21 @@ 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
xmobarStrip :: String -> String
xmobarStrip = strip [] where
strip keep x
| null x = keep
| "<fc=" `isPrefixOf` x = strip keep (drop 1 . dropWhile (/= '>') $ x)
| "</fc>" `isPrefixOf` x = strip keep (drop 5 x)
| '<' == head x = strip (keep ++ "<") (tail x)
| otherwise = let (good,x') = span (/= '<') x
in strip (keep ++ good) x'
-- | The 'PP' type allows the user to customize the formatting of
-- status information.
data PP = PP { ppCurrent :: WorkspaceId -> String
@@ -415,13 +451,14 @@ defaultPP = PP { ppCurrent = wrap "[" "]"
, ppExtras = []
}
-- | Settings to emulate dwm's statusbar, dzen only.
-- | Settings to emulate dwm's statusbar, dzen only. Uses dzenStrip in
-- ppUrgent.
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"
, ppUrgent = dzenColor "red" "yellow" . dzenStrip
, ppWsSep = ""
, ppSep = ""
, ppLayout = dzenColor "black" "#cccccc" .
@@ -439,6 +476,7 @@ xmobarPP :: PP
xmobarPP = defaultPP { ppCurrent = xmobarColor "yellow" "" . wrap "[" "]"
, ppTitle = xmobarColor "green" "" . shorten 40
, ppVisible = wrap "(" ")"
, ppUrgent = xmobarColor "red" "yellow"
}
-- | The options that sjanssen likes to use with xmobar, as an

View File

@@ -1,107 +0,0 @@
{-# OPTIONS_GHC -fglasgow-exts #-} -- for deriving Typeable
{-# LANGUAGE FlexibleContexts, FlexibleInstances, MultiParamTypeClasses, PatternGuards #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Hooks.EventHook
-- Copyright : (c) 2007 Andrea Rossato
-- License : BSD-style (see xmonad/LICENSE)
--
-- Maintainer : andrea.rossato@unibz.it
-- Stability : unstable
-- Portability : unportable
--
-- A layout modifier that implements an event hook at the layout level.
--
-- Since it operates at the 'Workspace' level, it will install itself
-- on the first current 'Workspace' and will broadcast a 'Message' to
-- all other 'Workspace's not to handle events.
-----------------------------------------------------------------------------
module XMonad.Hooks.EventHook
( -- * Usage
-- $usage
-- * Writing a hook
-- $hook
EventHook (..)
, eventHook
, HandleEvent
) where
import Data.Maybe
import XMonad
import XMonad.StackSet (Workspace (..), currentTag)
-- $usage
-- You can use this module with the following in your
-- @~\/.xmonad\/xmonad.hs@:
--
-- > import XMonad.Hooks.EventHook
--
-- Then edit your @layoutHook@ by adding the 'eventHook':
--
-- > layoutHook = eventHook EventHookExample $ avoidStruts $ simpleTabbed ||| Full ||| etc..
--
-- and then:
--
-- > main = xmonad defaultConfig { layoutHook = myLayouts }
--
-- For more detailed instructions on editing the layoutHook see:
--
-- "XMonad.Doc.Extending#Editing_the_layout_hook"
-- $hook
-- Writing a hook is very simple.
--
-- This is a basic example to log all events:
--
-- > data EventHookExample = EventHookExample deriving ( Show, Read )
-- > instance EventHook EventHookExample where
-- > handleEvent _ e = io $ hPutStrLn stderr . show $ e --return ()
--
-- This is an 'EventHook' to log mouse button events:
--
-- > data EventHookButton = EventHookButton deriving ( Show, Read )
-- > instance EventHook EventHookButton where
-- > handleEvent _ (ButtonEvent {ev_window = w}) = do
-- > io $ hPutStrLn stderr $ "This is a button event on window " ++ (show w)
-- > handleEvent _ _ = return ()
--
-- Obviously you can compose event hooks:
--
-- > layoutHook = eventHook EventHookButton $ eventHook EventHookExample $ avoidStruts $ simpleTabbed ||| Full ||| etc..
eventHook :: EventHook eh => eh -> l a -> (HandleEvent eh l) a
eventHook = HandleEvent Nothing True
class (Read eh, Show eh) => EventHook eh where
handleEvent :: eh -> Event -> X ()
handleEvent _ _ = return ()
data HandleEvent eh l a = HandleEvent (Maybe WorkspaceId) Bool eh (l a) deriving ( Show, Read )
data EventHandleMsg = HandlerOff deriving ( Typeable )
instance Message EventHandleMsg
instance (EventHook eh, LayoutClass l a) => LayoutClass (HandleEvent eh l) a where
runLayout (Workspace i (HandleEvent Nothing True eh l) ms) r = do
broadcastMessage HandlerOff
iws <- gets (currentTag . windowset)
(wrs, ml) <- runLayout (Workspace i l ms) r
return (wrs, Just $ HandleEvent (Just iws) True eh (fromMaybe l ml))
runLayout (Workspace i (HandleEvent mi b eh l) ms) r = do
(wrs, ml) <- runLayout (Workspace i l ms) r
return (wrs, Just $ HandleEvent mi b eh (fromMaybe l ml))
handleMessage (HandleEvent i True eh l) m
| Just HandlerOff <- fromMessage m = return . Just $ HandleEvent i False eh l
| Just e <- fromMessage m = handleMessage l (SomeMessage e) >>= \ml ->
handleEvent eh e >>
maybe (return Nothing) (\l' -> return . Just $ HandleEvent i True eh l') ml
handleMessage (HandleEvent i b eh l) m = handleMessage l m >>=
maybe (return Nothing) (\l' -> return . Just $ HandleEvent i b eh l')
description (HandleEvent _ _ _ l) = description l

View File

@@ -15,14 +15,17 @@
module XMonad.Hooks.EwmhDesktops (
-- * Usage
-- $usage
EwmhDesktopsHook,
ewmh,
ewmhDesktopsStartup,
ewmhDesktopsLogHook,
ewmhDesktopsLogHookCustom,
ewmhDesktopsLayout
ewmhDesktopsEventHook
) where
import Codec.Binary.UTF8.String (encode)
import Data.List
import Data.Maybe
import Data.Monoid
import XMonad
import Control.Monad
@@ -30,7 +33,6 @@ import qualified XMonad.StackSet as W
import XMonad.Hooks.SetWMName
import XMonad.Util.WorkspaceCompare
import XMonad.Hooks.EventHook
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
@@ -38,34 +40,29 @@ import XMonad.Hooks.EventHook
-- > import XMonad
-- > import XMonad.Hooks.EwmhDesktops
-- >
-- > myLogHook :: X ()
-- > myLogHook = ewmhDesktopsLogHook
-- >
-- > myLayoutHook = ewmhDesktopsLayout $ avoidStruts $ layoutHook defaultConfig
-- >
-- > main = xmonad defaultConfig { layoutHook = myLayouts, logHook = myLogHook }
-- > main = xmonad $ ewmh defaultConfig
--
-- 'avoidStruts' is used to automatically leave space for dock programs, and
-- can be found in 'XMonad.Hooks.ManageDocks'.
--
-- For more detailed instructions on editing the layoutHook see:
--
-- "XMonad.Doc.Extending#The_log_hook_and_external_status_bars"
--
-- For more detailed instructions on editing the layoutHook see:
--
-- "XMonad.Doc.Extending#Editing_the_layout_hook"
-- You may also be interested in 'avoidStruts' from XMonad.Hooks.ManageDocks.
-- | Add EWMH functionality to the given config. See above for an example.
ewmh :: XConfig a -> XConfig a
ewmh c = c { startupHook = startupHook c +++ ewmhDesktopsStartup
, handleEventHook = handleEventHook c +++ ewmhDesktopsEventHook
, logHook = logHook c +++ ewmhDesktopsLogHook }
where x +++ y = mappend x y
-- |
-- Initializes EwmhDesktops and advertises EWMH support to the X
-- server
ewmhDesktopsStartup :: X ()
ewmhDesktopsStartup = setSupported
-- |
-- Notifies pagers and window lists, such as those in the gnome-panel
-- of the current state of workspaces and windows.
ewmhDesktopsLogHook :: X ()
ewmhDesktopsLogHook = ewmhDesktopsLogHookCustom id
-- |
-- Generalized version of ewmhDesktopsLogHook that allows an arbitrary
-- user-specified function to transform the workspace list (post-sorting)
@@ -74,8 +71,6 @@ ewmhDesktopsLogHookCustom f = withWindowSet $ \s -> do
sort' <- getSortByIndex
let ws = f $ sort' $ W.workspaces s
setSupported
-- Number of Workspaces
setNumberOfDesktops (length ws)
@@ -100,7 +95,7 @@ ewmhDesktopsLogHookCustom f = withWindowSet $ \s -> do
setWindowDesktop win curr
forM_ (W.hidden s) $ \w ->
case elemIndex (W.tag w) (map W.tag ws) of
case elemIndex (W.tag w) (map W.tag ws) of
Nothing -> return ()
Just wn -> forM_ (W.integrate' (W.stack w)) $ \win -> do
setWindowDesktop win wn
@@ -119,13 +114,8 @@ ewmhDesktopsLogHookCustom f = withWindowSet $ \s -> do
--
-- * _NET_ACTIVE_WINDOW (activate another window, changing workspace if needed)
--
ewmhDesktopsLayout :: layout a -> HandleEvent EwmhDesktopsHook layout a
ewmhDesktopsLayout = eventHook EwmhDesktopsHook
data EwmhDesktopsHook = EwmhDesktopsHook deriving ( Show, Read )
instance EventHook EwmhDesktopsHook where
handleEvent _ e@ClientMessageEvent {} = do handle e
handleEvent _ _ = return ()
ewmhDesktopsEventHook :: Event -> X All
ewmhDesktopsEventHook e = handle e >> return (All True)
handle :: Event -> X ()
handle ClientMessageEvent {
@@ -156,9 +146,12 @@ handle ClientMessageEvent {
else if mt == a_cw then do
killWindow w
else if mt `elem` a_ignore then do
return ()
else trace $ "Unknown ClientMessageEvent " ++ show mt
handle _ = undefined -- does not happen, as otherwise ewmhDesktopsHook would not match
return ()
else do
-- The Message is unknown to us, but that is ok, not all are meant
-- to be handled by the window manager
return ()
handle _ = return ()
setNumberOfDesktops :: (Integral a) => a -> X ()
@@ -181,8 +174,7 @@ setDesktopNames names = withDisplay $ \dpy -> do
r <- asks theRoot
a <- getAtom "_NET_DESKTOP_NAMES"
c <- getAtom "UTF8_STRING"
let names' = map (fromIntegral.fromEnum) $
concatMap (++['\0']) names
let names' = map fromIntegral $ concatMap ((++[0]) . encode) names
io $ changeProperty8 dpy r a c propModeReplace names'
setClientList :: [Window] -> X ()

View File

@@ -16,12 +16,17 @@ module XMonad.Hooks.FadeInactive (
-- * Usage
-- $usage
setOpacity,
fadeInactiveLogHook
isUnfocused,
fadeIn,
fadeOut,
fadeIf,
fadeInactiveLogHook,
fadeOutLogHook
) where
import XMonad
import qualified XMonad.StackSet as W
import Control.Monad (forM_)
import Control.Monad
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
@@ -31,11 +36,11 @@ import Control.Monad (forM_)
-- >
-- > myLogHook :: X ()
-- > myLogHook = fadeInactiveLogHook fadeAmount
-- > where fadeAmount = 0xdddddddd
-- > where fadeAmount = 0.8
-- >
-- > main = xmonad defaultConfig { logHook = myLogHook }
--
-- fadeAmount can be any integer
-- fadeAmount can be any rational between 0 and 1.
-- you will need to have xcompmgr <http://freedesktop.org/wiki/Software/xapps>
-- or something similar for this to do anything
--
@@ -47,31 +52,43 @@ import Control.Monad (forM_)
--
-- "XMonad.Doc.Extending#Editing_the_layout_hook"
-- |
-- sets the opacity of a window
setOpacity :: Window -> Integer -> X ()
-- | Converts a percentage to the format required for _NET_WM_WINDOW_OPACITY
rationalToOpacity :: Integral a => Rational -> a
rationalToOpacity perc
| perc < 0 || perc > 1 = round perc -- to maintain backwards-compatability
| otherwise = round $ perc * 0xffffffff
-- | sets the opacity of a window
setOpacity :: Window -> Rational -> X ()
setOpacity w t = withDisplay $ \dpy -> do
a <- getAtom "_NET_WM_WINDOW_OPACITY"
c <- getAtom "CARDINAL"
io $ changeProperty32 dpy w a c propModeReplace [fromIntegral t]
io $ changeProperty32 dpy w a c propModeReplace [rationalToOpacity t]
-- |
-- fades a window out by setting the opacity
fadeOut :: Integer -> Window -> X ()
fadeOut amt = flip setOpacity amt
-- | fades a window out by setting the opacity
fadeOut :: Rational -> Window -> X ()
fadeOut = flip setOpacity
-- |
-- makes a window completely opaque
-- | makes a window completely opaque
fadeIn :: Window -> X ()
fadeIn = flip setOpacity 0xffffffff
fadeIn = fadeOut 1
-- |
-- lowers the opacity of inactive windows to the specified amount
fadeInactiveLogHook :: Integer -> X ()
fadeInactiveLogHook amt = withWindowSet $ \s ->
forM_ (visibleWins s) (fadeOut amt) >>
withFocused fadeIn
where
visibleWins s = (maybe [] unfocused . W.stack . W.workspace) (W.current s) ++
concatMap (W.integrate' . W.stack . W.workspace) (W.visible s)
unfocused (W.Stack _ l r) = l ++ r
-- | Fades a window by the specified amount if it satisfies the first query, otherwise
-- makes it opaque.
fadeIf :: Query Bool -> Rational -> Query Rational
fadeIf qry amt = qry >>= \b -> return $ if b then amt else 1
-- | sets the opacity of inactive windows to the specified amount
fadeInactiveLogHook :: Rational -> X ()
fadeInactiveLogHook = fadeOutLogHook . fadeIf isUnfocused
-- | returns True if the window doesn't have the focus.
isUnfocused :: Query Bool
isUnfocused = ask >>= \w -> liftX . gets $ maybe True (w /=) . W.peek . windowset
-- | fades out every window by the amount returned by the query.
fadeOutLogHook :: Query Rational -> X ()
fadeOutLogHook qry = withWindowSet $ \s -> do
let visibleWins = (W.integrate' . W.stack . W.workspace . W.current $ s) ++
concatMap (W.integrate' . W.stack . W.workspace) (W.visible s)
forM_ visibleWins $ liftM2 (=<<) setOpacity (runQuery qry)

157
XMonad/Hooks/FloatNext.hs Normal file
View File

@@ -0,0 +1,157 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Hooks.FloatNext
-- Copyright : Quentin Moser <quentin.moser@unifr.ch>
-- License : BSD-style (see LICENSE)
--
-- Maintainer : Quentin Moser <quentin.moser@unifr.ch>
-- Stability : unstable
-- Portability : unportable
--
-- Hook and keybindings for automatically sending the next
-- spawned window(s) to the floating layer.
--
-----------------------------------------------------------------------------
module XMonad.Hooks.FloatNext ( -- * Usage
-- $usage
-- * The hook
floatNextHook
-- * Actions
, floatNext
, toggleFloatNext
, floatAllNew
, toggleFloatAllNew
-- * Queries
, willFloatNext
, willFloatAllNew
-- * 'DynamicLog' utilities
-- $pp
, willFloatNextPP
, willFloatAllNewPP
, runLogHook ) where
import Prelude hiding (all)
import XMonad
import Control.Monad (join)
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)
_toggle :: ((Bool -> Bool) -> (Bool, Bool) -> (Bool, Bool)) -> X ()
_toggle f = io $ modifyMVar2 floatModeMVar (f not)
_get :: ((Bool, Bool) -> a) -> X a
_get f = io $ f <$> readMVar floatModeMVar
_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
{- The current state is kept here -}
floatModeMVar :: MVar (Bool, Bool)
floatModeMVar = unsafePerformIO $ newMVar (False, False)
-- $usage
-- This module provides actions (that can be set as keybindings)
-- to automatically send the next spawned window(s) to the floating
-- layer.
--
-- You can use it by including the following in your @~\/.xmonad\/xmonad.hs@:
--
-- > import XMonad.Hooks.FloatNext
--
-- and adding 'floatNextHook' to your 'ManageHook':
--
-- > myManageHook = floatNextHook <+> manageHook defaultConfig
--
-- The 'floatNext' and 'toggleFloatNext' functions can be used in key
-- bindings to float the next spawned window:
--
-- > , ((modm, xK_e), toggleFloatNext)
--
-- 'floatAllNew' and 'toggleFloatAllNew' are similar but float all
-- spawned windows until disabled again.
--
-- > , ((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)
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 ()
floatNext = _set first
toggleFloatNext :: X ()
toggleFloatNext = _toggle first
-- | @floatAllNew True@ arranges for new windows to be
-- sent to the floating layer, @floatAllNew False@ cancels it
floatAllNew :: Bool -> X ()
floatAllNew = _set second
toggleFloatAllNew :: X ()
toggleFloatAllNew = _toggle second
-- | Whether the next window will be set floating
willFloatNext :: X Bool
willFloatNext = _get fst
-- | Whether new windows will be set floating
willFloatAllNew :: X Bool
willFloatAllNew = _get snd
-- $pp
-- The following functions are used to display the current
-- state of 'floatNext' and 'floatAllNew' in your
-- 'XMonad.Hooks.DynamicLog.dynamicLogWithPP'.
-- 'willFloatNextPP' and 'willFloatAllNewPP' should be added
-- to the 'XMonad.Hooks.DynamicLog.ppExtras' field of your
-- 'XMonad.Hooks.DynamicLog.PP'.
--
-- Use 'runLogHook' to refresh the output of your 'logHook', so
-- that the effects of a 'floatNext'/... will be visible
-- immediately:
--
-- > , ((modm, xK_e), toggleFloatNext >> runLogHook)
--
-- The @String -> String@ parameters to 'willFloatNextPP' and
-- 'willFloatAllNewPP' will be applied to their output, you
-- can use them to set the text color, etc., or you can just
-- pass them 'id'.
willFloatNextPP :: (String -> String) -> X (Maybe String)
willFloatNextPP = _pp fst "Next"
willFloatAllNewPP :: (String -> String) -> X (Maybe String)
willFloatAllNewPP = _pp snd "All"
runLogHook :: X ()
runLogHook = join $ asks $ logHook . config

View File

@@ -0,0 +1,74 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Hooks.InsertPosition
-- Copyright : (c) 2009 Adam Vogt
-- License : BSD-style (see xmonad/LICENSE)
--
-- Maintainer : vogt.adam@gmail.com
-- Stability : unstable
-- Portability : portable
--
-- Configure where new windows should be added and which window should be
-- focused.
--
-----------------------------------------------------------------------------
module XMonad.Hooks.InsertPosition (
-- * Usage
-- $usage
insertPosition
,Focus(..), Position(..)
) where
import XMonad(ManageHook, MonadReader(ask))
import qualified XMonad.StackSet as W
import Control.Applicative((<$>))
import Data.Maybe(fromMaybe)
import Data.List(find)
import Data.Monoid(Endo(Endo))
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
--
-- > import XMonad.Hooks.InsertPosition
-- > xmonad defaultConfig { manageHook = insertPosition Master Newer <+> myManageHook }
--
-- You should you put the manageHooks that use 'doShift' to take effect
-- /before/ 'insertPosition', so that the window order will be consistent.
-- Because ManageHooks compose from right to left (like function composition
-- '.'), this means that 'insertPosition' should be the leftmost ManageHook.
data Position = Master | End | Above | Below
data Focus = Newer | Older
-- | insertPosition. A manage hook for placing new windows. XMonad's default is
-- the same as using: @insertPosition Above Newer@.
insertPosition :: Position -> Focus -> ManageHook
insertPosition pos foc = Endo . g <$> ask
where
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
End -> insertDown w . W.modify' focusLast'
Above -> W.insertUp w
Below -> insertDown w
updateFocus =
case foc of
Older -> const id
Newer -> W.focusWindow
-- | Modify the StackSet when the workspace containing w is focused
viewingWs :: (Eq a, Eq s, Eq i, Show i) =>a-> (W.StackSet i l a s sd -> W.StackSet i l a s sd)-> W.StackSet i l a s sd-> W.StackSet i l a s sd
viewingWs w f = do
i <- W.tag . W.workspace . W.current
ws <- find (elem w . W.integrate' . W.stack) . W.workspaces
maybe id (fmap (W.view i . f) . W.view . W.tag) ws
-- | 'insertDown' and 'focusLast' belong in XMonad.StackSet?
insertDown :: (Eq a) => a -> W.StackSet i l a s sd -> W.StackSet i l a s sd
insertDown w = W.swapDown . W.insertUp w
focusLast' :: W.Stack a -> W.Stack a
focusLast' st = let ws = W.integrate st
in W.Stack (last ws) (tail $ reverse ws) []

View File

@@ -1,6 +1,6 @@
{-# LANGUAGE PatternGuards, FlexibleInstances, MultiParamTypeClasses #-}
{-# OPTIONS -fglasgow-exts #-}
-- deriving Typeable
-- deriving Typeable for ghc-6.6 compatibility, which is retained in the core
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Hooks.ManageDocks
@@ -18,7 +18,12 @@ module XMonad.Hooks.ManageDocks (
-- * Usage
-- $usage
manageDocks, checkDock, AvoidStruts, avoidStruts, avoidStrutsOn,
ToggleStruts(..), Direction(..)
ToggleStruts(..),
SetStruts(..),
module XMonad.Util.Types,
-- for XMonad.Actions.FloatSnap
calcGap
) where
@@ -27,8 +32,10 @@ import XMonad
import Foreign.C.Types (CLong)
import Control.Monad
import XMonad.Layout.LayoutModifier
import XMonad.Util.Types
import XMonad.Util.WindowProperties (getProp32s)
import Data.List (delete)
import qualified Data.Set as S
-- $usage
-- To use this module, add the following import to @~\/.xmonad\/xmonad.hs@:
@@ -52,12 +59,12 @@ import Data.List (delete)
-- 'AvoidStruts' also supports toggling the dock gaps; add a keybinding
-- similar to:
--
-- > ,((modMask x, xK_b ), sendMessage ToggleStruts)
-- > ,((modm, xK_b ), sendMessage ToggleStruts)
--
-- If you have multiple docks, you can toggle their gaps individually.
-- For example, to toggle only the top gap:
--
-- > ,((modMask x .|. controlMask, xK_t), sendMessage $ ToggleStrut U)
-- > ,((modm .|. controlMask, xK_t), sendMessage $ ToggleStrut U)
--
-- Similarly, you can use 'D', 'L', and 'R' to individually toggle
-- gaps on the bottom, left, or right.
@@ -79,18 +86,6 @@ import Data.List (delete)
-- "XMonad.Doc.Extending#Editing_key_bindings".
--
-- | An enumeration of the four cardinal directions\/sides of the
-- screen.
--
-- Ideally this would go in its own separate module in Util,
-- but ManageDocks is angling for inclusion into the xmonad core,
-- so keep the dependencies to a minimum.
data Direction = U -- ^ Up\/top
| D -- ^ Down\/bottom
| R -- ^ Right
| L -- ^ Left
deriving ( Read, Show, Eq, Ord, Enum, Bounded )
-- | Detects if the given window is of type DOCK and if so, reveals
-- it, but does not manage it. If the window has the STRUT property
-- set, adjust the gap accordingly.
@@ -100,10 +95,9 @@ manageDocks = checkDock --> doIgnore
-- | Checks if a window is a DOCK or DESKTOP window
checkDock :: Query Bool
checkDock = ask >>= \w -> liftX $ do
a <- getAtom "_NET_WM_WINDOW_TYPE"
dock <- getAtom "_NET_WM_WINDOW_TYPE_DOCK"
desk <- getAtom "_NET_WM_WINDOW_TYPE_DESKTOP"
mbr <- getProp a w
mbr <- getProp32s "_NET_WM_WINDOW_TYPE" w
case mbr of
Just [r] -> return $ elem (fromIntegral r) [dock, desk]
_ -> return False
@@ -111,12 +105,10 @@ checkDock = ask >>= \w -> liftX $ do
-- | Gets the STRUT config, if present, in xmonad gap order
getStrut :: Window -> X [Strut]
getStrut w = do
spa <- getAtom "_NET_WM_STRUT_PARTIAL"
sa <- getAtom "_NET_WM_STRUT"
msp <- getProp spa w
msp <- getProp32s "_NET_WM_STRUT_PARTIAL" w
case msp of
Just sp -> return $ parseStrutPartial sp
Nothing -> fmap (maybe [] parseStrut) $ getProp sa w
Nothing -> fmap (maybe [] parseStrut) $ getProp32s "_NET_WM_STRUT" w
where
parseStrut xs@[_, _, _, _] = parseStrutPartial . take 12 $ xs ++ cycle [minBound, maxBound]
parseStrut _ = []
@@ -126,13 +118,9 @@ getStrut w = do
[(L, l, ly1, ly2), (R, r, ry1, ry2), (U, t, tx1, tx2), (D, b, bx1, bx2)]
parseStrutPartial _ = []
-- | Helper to read a property
getProp :: Atom -> Window -> X (Maybe [CLong])
getProp a w = withDisplay $ \dpy -> io $ getWindowProperty32 dpy a w
-- | Goes through the list of windows and find the gap so that all
-- STRUT settings are satisfied.
calcGap :: [Direction] -> X (Rectangle -> Rectangle)
calcGap :: S.Set Direction2D -> X (Rectangle -> Rectangle)
calcGap ss = withDisplay $ \dpy -> do
rootw <- asks theRoot
-- We don't keep track of dock like windows, so we find all of them here
@@ -145,7 +133,7 @@ calcGap ss = withDisplay $ \dpy -> do
wa <- io $ getWindowAttributes dpy rootw
let screen = r2c $ Rectangle (fi $ wa_x wa) (fi $ wa_y wa) (fi $ wa_width wa) (fi $ wa_height wa)
return $ \r -> c2r $ foldr (reduce screen) (r2c r) struts
where careAbout (s,_,_,_) = s `elem` ss
where careAbout (s,_,_,_) = s `S.member` ss
-- | Adjust layout automagically: don't cover up any docks, status
-- bars, etc.
@@ -156,39 +144,68 @@ avoidStruts = avoidStrutsOn [U,D,L,R]
-- etc. on the indicated sides of the screen. Valid sides are U
-- (top), D (bottom), R (right), or L (left).
avoidStrutsOn :: LayoutClass l a =>
[Direction]
[Direction2D]
-> l a
-> ModifiedLayout AvoidStruts l a
avoidStrutsOn ss = ModifiedLayout (AvoidStruts ss)
avoidStrutsOn ss = ModifiedLayout $ AvoidStruts $ S.fromList ss
data AvoidStruts a = AvoidStruts [Direction] deriving ( Read, Show )
data AvoidStruts a = AvoidStruts (S.Set Direction2D) deriving ( Read, Show )
-- | Message type which can be sent to an 'AvoidStruts' layout
-- modifier to alter its behavior.
data ToggleStruts = ToggleStruts
| ToggleStrut Direction
| ToggleStrut Direction2D
deriving (Read,Show,Typeable)
instance Message ToggleStruts
-- | SetStruts is a message constructor used to set or unset specific struts,
-- regardless of whether or not the struts were originally set. Here are some
-- example bindings:
--
-- Show all gaps:
--
-- > ,((modm .|. shiftMask ,xK_b),sendMessage $ SetStruts [minBound .. maxBound] [])
--
-- Hide all gaps:
--
-- > ,((modm .|. controlMask,xK_b),sendMessage $ SetStruts [] [minBound .. maxBound])
--
-- Show only upper and left gaps:
--
-- > ,((modm .|. controlMask .|. shiftMask,xK_b),sendMessage $ SetStruts [U,L] [minBound .. maxBound])
--
-- Hide the bottom keeping whatever the other values were:
--
-- > ,((modm .|. controlMask .|. shiftMask,xK_g),sendMessage $ SetStruts [] [D])
data SetStruts = SetStruts { addedStruts :: [Direction2D]
, removedStruts :: [Direction2D] -- ^ These are removed from the currently set struts before 'addedStruts' are added.
}
deriving (Read,Show,Typeable)
instance Message SetStruts
instance LayoutModifier AvoidStruts a where
modifyLayout (AvoidStruts ss) w r = do
nr <- fmap ($ r) (calcGap ss)
runLayout w nr
handleMess (AvoidStruts ss) m
| Just ToggleStruts <- fromMessage m = return $ Just $ AvoidStruts (toggleAll ss)
| Just (ToggleStrut s) <- fromMessage m = return $ Just $ AvoidStruts (toggleOne s ss)
| otherwise = return Nothing
where toggleAll [] = [U,D,L,R]
toggleAll _ = []
toggleOne x xs | x `elem` xs = delete x xs
| otherwise = x : xs
pureMess (AvoidStruts ss) m
| Just ToggleStruts <- fromMessage m = Just $ AvoidStruts (toggleAll ss)
| Just (ToggleStrut s) <- fromMessage m = Just $ AvoidStruts (toggleOne s ss)
| Just (SetStruts n k) <- fromMessage m
, let newSS = S.fromList n `S.union` (ss S.\\ S.fromList k)
, newSS /= ss = Just $ AvoidStruts newSS
| otherwise = Nothing
where toggleAll x | S.null x = S.fromList [minBound .. maxBound]
| otherwise = S.empty
toggleOne x xs | x `S.member` xs = S.delete x xs
| otherwise = x `S.insert` xs
-- | (Direction, height\/width, initial pixel, final pixel).
type Strut = (Direction, CLong, CLong, CLong)
type Strut = (Direction2D, CLong, CLong, CLong)
-- | (Initial x pixel, initial y pixel,
-- final x pixel, final y pixel).

View File

@@ -28,6 +28,7 @@ module XMonad.Hooks.ManageHelpers (
Side(..),
composeOne,
(-?>), (/=?), (<==?), (</=?), (-->>), (-?>>),
isInProperty,
isKDETrayWindow,
isFullscreen,
isDialog,
@@ -41,11 +42,14 @@ module XMonad.Hooks.ManageHelpers (
doFullFloat,
doCenterFloat,
doSideFloat,
doFloatAt,
doFloatDep,
doHideIgnore
) where
import XMonad
import qualified XMonad.StackSet as W
import XMonad.Util.WindowProperties (getProp32s)
import Data.Maybe
import Data.Monoid
@@ -117,41 +121,32 @@ p -?>> f = do
-- | A predicate to check whether a window is a KDE system tray icon.
isKDETrayWindow :: Query Bool
isKDETrayWindow = ask >>= \w -> liftX $ do
dpy <- asks display
kde_tray <- getAtom "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR"
r <- io $ getWindowProperty32 dpy kde_tray w
r <- getProp32s "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR" w
return $ case r of
Just [_] -> True
_ -> False
-- | Helper to check if a window property contains certain value.
isInProperty :: String -> String -> Query Bool
isInProperty p v = ask >>= \w -> liftX $ do
va <- getAtom v
r <- getProp32s p w
return $ case r of
Just xs -> fromIntegral va `elem` xs
_ -> False
-- | A predicate to check whether a window wants to fill the whole screen.
-- See also 'doFullFloat'.
isFullscreen :: Query Bool
isFullscreen = ask >>= \w -> liftX $ do
dpy <- asks display
state <- getAtom "_NET_WM_STATE"
full <- getAtom "_NET_WM_STATE_FULLSCREEN"
r <- io $ getWindowProperty32 dpy state w
return $ case r of
Just xs -> fromIntegral full `elem` xs
_ -> False
isFullscreen = isInProperty "_NET_WM_STATE" "_NET_WM_STATE_FULLSCREEN"
-- | A predicate to check whether a window is a dialog.
isDialog :: Query Bool
isDialog = ask >>= \w -> liftX $ do
dpy <- asks display
w_type <- getAtom "_NET_WM_WINDOW_TYPE"
w_dialog <- getAtom "_NET_WM_WINDOW_TYPE_DIALOG"
r <- io $ getWindowProperty32 dpy w_type w
return $ case r of
Just xs -> fromIntegral w_dialog `elem` xs
_ -> False
isDialog = isInProperty "_NET_WM_WINDOW_TYPE" "_NET_WM_WINDOW_TYPE_DIALOG"
pid :: Query (Maybe ProcessID)
pid = ask >>= \w -> liftX $ do
dpy <- asks display
a <- getAtom "_NET_WM_PID"
p <- io $ getWindowProperty32 dpy a w
p <- getProp32s "_NET_WM_PID" w
return $ case p of
Just [x] -> Just (fromIntegral x)
_ -> Nothing
@@ -192,19 +187,31 @@ doRectFloat r = ask >>= \w -> doF (W.float w r)
doFullFloat :: ManageHook
doFullFloat = doRectFloat $ W.RationalRect 0 0 1 1
-- | Floats a new window using a rectangle computed as a function of
-- the rectangle that it would have used by default.
doFloatDep :: (W.RationalRect -> W.RationalRect) -> ManageHook
doFloatDep move = ask >>= \w -> doF . W.float w . move . snd =<< liftX (floatLocation w)
-- | Floats a new window with its original size, and its top left
-- corner at a specific point on the screen (both coordinates should
-- be in the range 0 to 1).
doFloatAt :: Rational -> Rational -> ManageHook
doFloatAt x y = doFloatDep move
where
move (W.RationalRect _ _ w h) = W.RationalRect x y w h
-- | Floats a new window with its original size on the specified side of a
-- screen
doSideFloat :: Side -> ManageHook
doSideFloat side = ask >>= \w -> doF . W.float w . move . snd =<< liftX (floatLocation w)
where
doSideFloat side = doFloatDep move
where
move (W.RationalRect _ _ w h) = W.RationalRect cx cy w h
where
cx = if side `elem` [SC,C ,NC] then (1-w)/2
else if side `elem` [SW,CW,NW] then 0
else {- side `elem` [SE,CE,NE] -} 1-w
cy = if side `elem` [CE,C ,CW] then (1-h)/2
else if side `elem` [NE,NC,NW] then 0
else {- side `elem` [SE,SC,SW] -} 1-h
where cx = if side `elem` [SC,C ,NC] then (1-w)/2
else if side `elem` [SW,CW,NW] then 0
else {- side `elem` [SE,CE,NE] -} 1-w
cy = if side `elem` [CE,C ,CW] then (1-h)/2
else if side `elem` [NE,NC,NW] then 0
else {- side `elem` [SE,SC,SW] -} 1-h
-- | Floats a new window with its original size, but centered.
doCenterFloat :: ManageHook

460
XMonad/Hooks/Place.hs Normal file
View File

@@ -0,0 +1,460 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Hooks.Place
-- Copyright : Quentin Moser <quentin.moser@unifr.ch>
-- License : BSD-style (see LICENSE)
--
-- Maintainer : Quentin Moser <quentin.moser@unifr.ch>
-- Stability : unstable
-- Portability : unportable
--
-- Automatic placement of floating windows.
--
-----------------------------------------------------------------------------
module XMonad.Hooks.Place ( -- * Usage
-- $usage
-- * Placement actions
placeFocused
, placeHook
-- * Placement policies
-- $placements
, Placement
, smart
, simpleSmart
, fixed
, underMouse
, inBounds
, withGaps
-- * Others
, purePlaceWindow ) where
import XMonad
import qualified XMonad.StackSet as S
import XMonad.Layout.WindowArranger
import XMonad.Actions.FloatKeys
import qualified Data.Map as M
import Data.Ratio ((%))
import Data.List (sortBy, minimumBy, partition)
import Data.Maybe (maybe, fromMaybe, catMaybes)
import Data.Monoid (Endo(..))
import Control.Monad (guard, join)
import Control.Monad.Trans (lift)
-- $usage
-- This module provides a 'ManageHook' that automatically places
-- floating windows at appropriate positions on the screen, as well
-- as an 'X' action to manually trigger repositioning.
--
-- You can use this module by including the following in your @~\/.xmonad\/xmonad.hs@:
--
-- > import XMonad.Hooks.Place
--
-- and adding 'placeHook' to your 'manageHook', for example:
--
-- > main = xmonad $ defaultConfig { manageHook = placeHook simpleSmart
-- > <+> manageHook defaultConfig }
--
-- Note that 'placeHook' should be applied after most other hooks, especially hooks
-- such as 'doFloat' and 'doShift'. Since hooks combined with '<+>' are applied from
-- right to left, this means that 'placeHook' should be the /first/ hook in your chain.
--
-- You can also define a key to manually trigger repositioning with 'placeFocused' by
-- adding the following to your keys definition:
--
-- > , ((modm, xK_w), placeFocused simpleSmart)
--
-- Both 'placeHook' and 'placeFocused' take a 'Placement' parameter, which specifies
-- the placement policy to use (smart, under the mouse, fixed position, etc.). See
-- 'Placement' for a list of available policies.
{- Placement policies -}
-- $placements
-- Placement policies determine how windows will be placed by 'placeFocused' and 'placeHook'.
--
-- A few examples:
--
-- * Basic smart placement
--
-- > myPlacement = simpleSmart
--
-- * Under the mouse (pointer at the top-left corner), but constrained
-- inside of the screen area
--
-- > myPlacement = inBounds (underMouse (0, 0))
--
-- * Smart placement with a preference for putting windows near
-- the center of the screen, and with 16px gaps at the top and bottom
-- of the screen where no window will be placed
--
-- > myPlacement = withGaps (16,0,16,0) (smart (0.5,0.5))
-- | The type of placement policies
data Placement = Smart (Rational, Rational)
| Fixed (Rational, Rational)
| UnderMouse (Rational, Rational)
| Bounds (Dimension, Dimension, Dimension, Dimension) Placement
deriving (Show, Read, Eq)
-- | Try to place windows with as little overlap as possible
smart :: (Rational, Rational) -- ^ Where the window should be placed inside
-- the available area. See 'fixed'.
-> Placement
smart = Smart
simpleSmart :: Placement
simpleSmart = inBounds $ smart (0,0)
-- | Place windows at a fixed position
fixed :: (Rational, Rational) -- ^ Where windows should go.
--
-- * (0,0) -> top left of the screen
--
-- * (1,0) -> top right of the screen
--
-- * etc
-> Placement
fixed = Fixed
-- | Place windows under the mouse
underMouse :: (Rational, Rational) -- ^ Where the pointer should be relative to
-- the window's frame; see 'fixed'.
-> Placement
underMouse = UnderMouse
-- | Apply the given placement policy, constraining the
-- placed windows inside the screen boundaries.
inBounds :: Placement -> Placement
inBounds = Bounds (0,0,0,0)
-- | Same as 'inBounds', but allows specifying gaps along the screen's edges
withGaps :: (Dimension, Dimension, Dimension, Dimension)
-- ^ top, right, bottom and left gaps
-> Placement -> Placement
withGaps = Bounds
{- Placement functions -}
-- | Repositions the focused window according to a placement policy. Works for
-- both \"real\" floating windows and windows in a 'WindowArranger'-based
-- layout.
placeFocused :: Placement -> X ()
placeFocused p = withFocused $ \window -> do
info <- gets $ screenInfo . S.current . windowset
floats <- gets $ M.keys . S.floating . windowset
r'@(Rectangle x' y' _ _) <- placeWindow p window info floats
-- use X.A.FloatKeys if the window is floating, send
-- a WindowArranger message otherwise.
case elem window floats of
True -> keysMoveWindowTo (x', y') (0, 0) window
False -> sendMessage $ SetGeometry r'
-- | Hook to automatically place windows when they are created.
placeHook :: Placement -> ManageHook
placeHook p = do window <- ask
r <- Query $ lift $ getWindowRectangle window
allRs <- Query $ lift $ getAllRectangles
pointer <- Query $ lift $ getPointer window
return $ Endo $ \theWS -> fromMaybe theWS $
do let currentRect = screenRect $ S.screenDetail $ S.current theWS
floats = M.keys $ S.floating theWS
guard(window `elem` floats )
-- Look for the workspace(s) on which the window is to be
-- spawned. Each of them also needs an associated screen
-- rectangle; for hidden workspaces, we use the current
-- workspace's screen.
let infos = filter ((window `elem`) . stackContents . S.stack . fst)
$ [screenInfo $ S.current theWS]
++ (map screenInfo $ S.visible theWS)
++ zip (S.hidden theWS) (repeat currentRect)
guard(not $ null infos)
let (workspace, screen) = head infos
rs = catMaybes $ map (flip M.lookup allRs)
$ organizeClients workspace window floats
r' = purePlaceWindow p screen rs pointer r
newRect = r2rr screen r'
newFloats = M.insert window newRect (S.floating theWS)
return $ theWS { S.floating = newFloats }
placeWindow :: Placement -> Window
-> (S.Workspace WorkspaceId (Layout Window) Window, Rectangle)
-- ^ The workspace with reference to which the window should be placed,
-- and the screen's geometry.
-> [Window]
-- ^ The list of floating windows.
-> X Rectangle
placeWindow p window (ws, s) floats
= do (r, rs, pointer) <- getNecessaryData window ws floats
return $ purePlaceWindow p s rs pointer r
-- | Compute the new position of a window according to a placement policy.
purePlaceWindow :: Placement -- ^ The placement strategy
-> Rectangle -- ^ The screen
-> [Rectangle] -- ^ The other visible windows
-> (Position, Position) -- ^ The pointer's position.
-> Rectangle -- ^ The window to be placed
-> Rectangle
purePlaceWindow (Bounds (t,r,b,l) p') (Rectangle sx sy sw sh) rs p w
= let s' = (Rectangle (sx + fi l) (sy + fi t) (sw - l - r) (sh - t - b))
in checkBounds s' $ purePlaceWindow p' s' rs p w
purePlaceWindow (Fixed ratios) s _ _ w = placeRatio ratios s w
purePlaceWindow (UnderMouse (rx, ry)) _ _ (px, py) (Rectangle _ _ w h)
= Rectangle (px - truncate (rx * fi w)) (py - truncate (ry * fi h)) w h
purePlaceWindow (Smart ratios) s rs _ w
= placeSmart ratios s rs (rect_width w) (rect_height w)
-- | Helper: Places a Rectangle at a fixed position indicated by two Rationals
-- inside another,
placeRatio :: (Rational, Rational) -> Rectangle -> Rectangle -> Rectangle
placeRatio (rx, ry) (Rectangle x1 y1 w1 h1) (Rectangle _ _ w2 h2)
= Rectangle (scale rx x1 (x1 + fi w1 - fi w2))
(scale ry y1 (y1 + fi h1 - fi h2))
w2 h2
-- | Helper: Ensures its second parameter is contained inside the first
-- by possibly moving it.
checkBounds :: Rectangle -> Rectangle -> Rectangle
checkBounds (Rectangle x1 y1 w1 h1) (Rectangle x2 y2 w2 h2)
= Rectangle (max x1 (min (x1 + fi w1 - fi w2) x2))
(max y1 (min (y1 + fi h1 - fi h2) y2))
w2 h2
{- Utilities -}
scale :: (RealFrac a, Integral b) => a -> b -> b -> b
scale r n1 n2 = truncate $ r * fi n2 + (1 - r) * fi n1
fi :: (Integral a, Num b) => a -> b
fi = fromIntegral
r2rr :: Rectangle -> Rectangle -> S.RationalRect
r2rr (Rectangle x0 y0 w0 h0) (Rectangle x y w h)
= S.RationalRect ((fi x-fi x0) % fi w0)
((fi y-fi y0) % fi h0)
(fi w % fi w0)
(fi h % fi h0)
{- Querying stuff -}
stackContents :: Maybe (S.Stack w) -> [w]
stackContents = maybe [] S.integrate
screenInfo :: S.Screen i l a sid ScreenDetail -> (S.Workspace i l a, Rectangle)
screenInfo (S.Screen { S.workspace = ws, S.screenDetail = (SD s)}) = (ws, s)
getWindowRectangle :: Window -> X Rectangle
getWindowRectangle window
= do d <- asks display
(_, x, y, w, h, _, _) <- io $ getGeometry d window
-- We can't use the border width returned by
-- getGeometry because it will be 0 if the
-- window isn't mapped yet.
b <- asks $ borderWidth . config
return $ Rectangle x y (w + 2*b) (h + 2*b)
getAllRectangles :: X (M.Map Window Rectangle)
getAllRectangles = do ws <- gets windowset
let allWindows = join $ map (stackContents . S.stack)
$ (S.workspace . S.current) ws
: (map S.workspace . S.visible) ws
++ S.hidden ws
allRects <- mapM getWindowRectangle allWindows
return $ M.fromList $ zip allWindows allRects
organizeClients :: S.Workspace a b Window -> Window -> [Window] -> [Window]
organizeClients ws w floats
= let (floatCs, layoutCs) = partition (`elem` floats) $ filter (/= w)
$ stackContents $ S.stack ws
in reverse layoutCs ++ reverse floatCs
-- About the ordering: the smart algorithm will overlap windows
-- starting ith the head of the list. So:
-- - we put the non-floating windows first since they'll
-- probably be below the floating ones,
-- - we reverse the lists, since the newer/more important
-- windows are usually near the head.
getPointer :: Window -> X (Position, Position)
getPointer window = do d <- asks display
(_,_,_,x,y,_,_,_) <- io $ queryPointer d window
return (fi x,fi y)
-- | Return values are, in order: window's rectangle,
-- other windows' rectangles and pointer's coordinates.
getNecessaryData :: Window
-> S.Workspace WorkspaceId (Layout Window) Window
-> [Window]
-> X (Rectangle, [Rectangle], (Position, Position))
getNecessaryData window ws floats
= do r <- getWindowRectangle window
rs <- return (organizeClients ws window floats)
>>= mapM getWindowRectangle
pointer <- getPointer window
return (r, rs, pointer)
{- Smart placement algorithm -}
-- | Alternate representation for rectangles.
data SmartRectangle a = SR
{ sr_x0, sr_y0 :: a -- ^ Top left coordinates, inclusive
, sr_x1, sr_y1 :: a -- ^ Bottom right coorsinates, exclusive
} deriving (Show, Eq)
r2sr :: Rectangle -> SmartRectangle Position
r2sr (Rectangle x y w h) = SR x y (x + fi w) (y + fi h)
sr2r :: SmartRectangle Position -> Rectangle
sr2r (SR x0 y0 x1 y1) = Rectangle x0 y0 (fi $ x1 - x0) (fi $ y1 - y0)
width :: Num a => SmartRectangle a -> a
width r = sr_x1 r - sr_x0 r
height :: Num a => SmartRectangle a -> a
height r = sr_y1 r - sr_y0 r
isEmpty :: Real a => SmartRectangle a -> Bool
isEmpty r = (width r <= 0) || (height r <= 0)
contains :: Real a => SmartRectangle a -> SmartRectangle a -> Bool
contains r1 r2 = sr_x0 r1 <= sr_x0 r2
&& sr_y0 r1 <= sr_y0 r2
&& sr_x1 r1 >= sr_x1 r2
&& sr_y1 r1 >= sr_y1 r2
-- | Main placement function
placeSmart :: (Rational, Rational) -- ^ point of the screen where windows
-- should be placed first, if possible.
-> Rectangle -- ^ screen
-> [Rectangle] -- ^ other clients
-> Dimension -- ^ width
-> Dimension -- ^ height
-> Rectangle
placeSmart (rx, ry) s@(Rectangle sx sy sw sh) rs w h
= let free = map sr2r $ findSpace (r2sr s) (map r2sr rs) (fi w) (fi h)
in position free (scale rx sx (sx + fi sw - fi w))
(scale ry sy (sy + fi sh - fi h))
w h
-- | Second part of the algorithm:
-- Chooses the best position in which to place a window,
-- according to a list of free areas and an ideal position for
-- the top-left corner.
-- We can't use semi-open surfaces for this, so we go back to
-- X11 Rectangles/Positions/etc instead.
position :: [Rectangle] -- ^ Free areas
-> Position -> Position -- ^ Ideal coordinates
-> Dimension -> Dimension -- ^ Width and height of the window
-> Rectangle
position rs x y w h = minimumBy distanceOrder $ map closest rs
where distanceOrder r1 r2
= compare (distance (rect_x r1,rect_y r1) (x,y) :: Dimension)
(distance (rect_x r2,rect_y r2) (x,y) :: Dimension)
distance (x1,y1) (x2,y2) = truncate $ (sqrt :: Double -> Double)
$ fi $ (x1 - x2)^(2::Int)
+ (y1 - y2)^(2::Int)
closest r = checkBounds r (Rectangle x y w h)
-- | First part of the algorithm:
-- Tries to find an area in which to place a new
-- rectangle so that it overlaps as little as possible with
-- other rectangles already present. The first rectangles in
-- the list will be overlapped first.
findSpace :: Real a =>
SmartRectangle a -- ^ The total available area
-> [SmartRectangle a] -- ^ The parts already in use
-> a -- ^ Width of the rectangle to place
-> a -- ^ Height of the rectangle to place
-> [SmartRectangle a]
findSpace total [] _ _ = [total]
findSpace total rs@(_:rs') w h
= case filter largeEnough $ cleanup $ subtractRects total rs of
[] -> findSpace total rs' w h
as -> as
where largeEnough r = width r >= w && height r >= h
-- | Subtracts smaller rectangles from a total rectangle
-- , returning a list of remaining rectangular areas.
subtractRects :: Real a => SmartRectangle a
-> [SmartRectangle a] -> [SmartRectangle a]
subtractRects total [] = [total]
subtractRects total (r:rs)
= do total' <- subtractRects total rs
filter (not . isEmpty)
[ total' {sr_y1 = min (sr_y1 total') (sr_y0 r)} -- Above
, total' {sr_x0 = max (sr_x0 total') (sr_x1 r)} -- Right
, total' {sr_y0 = max (sr_y0 total') (sr_y1 r)} -- Below
, total' {sr_x1 = min (sr_x1 total') (sr_x0 r)} -- Left
]
-- | "Nubs" a list of rectangles, dropping all those that are
-- already contained in another rectangle of the list.
cleanup :: Real a => [SmartRectangle a] -> [SmartRectangle a]
cleanup rs = foldr dropIfContained [] $ sortBy sizeOrder rs
sizeOrder :: Real a => SmartRectangle a -> SmartRectangle a -> Ordering
sizeOrder r1 r2 | w1 < w2 = LT
| w1 == w2 && h1 < h2 = LT
| w1 == w2 && h1 == h2 = EQ
| otherwise = GT
where w1 = width r1
w2 = width r2
h1 = height r1
h2 = height r2
dropIfContained :: Real a => SmartRectangle a
-> [SmartRectangle a] -> [SmartRectangle a]
dropIfContained r rs = if any (`contains` r) rs
then rs
else r:rs

View File

@@ -0,0 +1,49 @@
----------------------------------------------------------------------------
-- |
-- Module : XMonad.Hooks.RestoreMinimized
-- Copyright : (c) Jan Vornberger 2009
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : jan.vornberger@informatik.uni-oldenburg.de
-- Stability : unstable
-- Portability : not portable
--
-- Lets you restore minimized windows (see "XMonad.Layout.Minimize")
-- by selecting them on a taskbar (listens for _NET_ACTIVE_WINDOW
-- and WM_CHANGE_STATE).
--
-----------------------------------------------------------------------------
module XMonad.Hooks.RestoreMinimized
( -- * Usage
-- $usage
RestoreMinimized (..)
, restoreMinimizedEventHook
) where
import Data.Monoid
import Control.Monad(when)
import XMonad
import XMonad.Layout.Minimize
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
--
-- > import XMonad.Hooks.RestoreMinimized
-- >
-- > myHandleEventHook = restoreMinimizedEventHook
-- >
-- > main = xmonad defaultConfig { handleEventHook = myHandleEventHook }
data RestoreMinimized = RestoreMinimized deriving ( Show, Read )
restoreMinimizedEventHook :: Event -> X All
restoreMinimizedEventHook (ClientMessageEvent {ev_window = w,
ev_message_type = mt}) = do
a_aw <- getAtom "_NET_ACTIVE_WINDOW"
a_cs <- getAtom "WM_CHANGE_STATE"
when (mt == a_aw || mt == a_cs) $ do
sendMessage (RestoreMinimizedWin w)
return (All True)
restoreMinimizedEventHook _ = return (All True)

View File

@@ -43,7 +43,7 @@ import System.Directory
-- > ...
-- > }
--
-- Now, everytime the startup hook runs, the command
-- Now, every time the startup hook runs, the command
-- @~\/.xmonad\/hooks startup@ will also.
-- | Execute a named script hook

View File

@@ -59,45 +59,48 @@ module XMonad.Hooks.ServerMode
( -- * Usage
-- $usage
ServerMode (..)
, eventHook
, serverModeEventHook
, serverModeEventHook'
) where
import Control.Monad (when)
import Data.List
import Data.Monoid
import System.IO
import XMonad
import XMonad.Actions.Commands
import XMonad.Hooks.EventHook
-- $usage
-- You can use this module with the following in your
-- @~\/.xmonad\/xmonad.hs@:
--
-- > import XMonad.Hooks.ServerMode
-- > import XMonad.Actions.Commands
--
-- Then edit your @layoutHook@ by adding the 'eventHook':
-- Then edit your @handleEventHook@ by adding the 'serverModeEventHook':
--
-- > layoutHook = eventHook ServerMode $ avoidStruts $ simpleTabbed ||| Full ||| etc..
-- > main = xmonad defaultConfig { handleEventHook = serverModeEventHook }
--
-- and then:
--
-- > main = xmonad defaultConfig { layoutHook = myLayouts }
--
-- For more detailed instructions on editing the layoutHook see:
--
-- "XMonad.Doc.Extending#Editing_the_layout_hook"
data ServerMode = ServerMode deriving ( Show, Read )
instance EventHook ServerMode where
handleEvent _ (ClientMessageEvent {ev_message_type = mt, ev_data = dt}) = do
-- | Executes a command of the list when receiving its index via a special ClientMessageEvent
-- (indexing starts at 1)
serverModeEventHook :: Event -> X All
serverModeEventHook = serverModeEventHook' defaultCommands
-- | serverModeEventHook' additionally takes an action to generate the list of
-- commands.
serverModeEventHook' :: X [(String,X ())] -> Event -> X All
serverModeEventHook' cmdAction (ClientMessageEvent {ev_message_type = mt, ev_data = dt}) = do
d <- asks display
a <- io $ internAtom d "XMONAD_COMMAND" False
when (mt == a && dt /= []) $ do
cl <- defaultCommands
cl <- cmdAction
let listOfCommands = map (uncurry (++)) . zip (map show ([1..] :: [Int])) . map ((++) " - " . fst)
case lookup (fromIntegral (head dt) :: Int) (zip [1..] cl) of
Just (c,_) -> runCommand' c
Nothing -> mapM_ (io . hPutStrLn stderr) . listOfCommands $ cl
handleEvent _ _ = return ()
Just (_,action) -> action
Nothing -> mapM_ (io . hPutStrLn stderr) . listOfCommands $ cl
return (All True)
serverModeEventHook' _ _ = return (All True)

View File

@@ -70,7 +70,6 @@ module XMonad.Hooks.UrgencyHook (
import XMonad
import qualified XMonad.StackSet as W
import XMonad.Hooks.EventHook
import XMonad.Util.Dzen (dzenWithArgs, seconds)
import XMonad.Util.NamedWindows (getName)
import XMonad.Util.Timer (TimerId, startTimer, handleTimer)
@@ -139,7 +138,7 @@ import Foreign (unsafePerformIO)
-- two parts:
--
-- * The console app must send a ^G (bell). In bash, a helpful trick is
-- @sleep 1; echo -e \'\a\'@.
-- @sleep 1; echo -e \'\\a\'@.
--
-- * The terminal must convert the bell into UrgencyHint.
--
@@ -199,7 +198,7 @@ import Foreign (unsafePerformIO)
-- 'urgencyConfig' to control behavior. To change this, use 'withUrgencyHook'
-- instead.
withUrgencyHook :: (LayoutClass l Window, UrgencyHook h) =>
h -> XConfig l -> XConfig (HandleEvent (WithUrgencyHook h) l)
h -> XConfig l -> XConfig l
withUrgencyHook hook conf = withUrgencyHookC hook urgencyConfig conf
-- | This lets you modify the defaults set in 'urgencyConfig'. An example:
@@ -208,9 +207,9 @@ withUrgencyHook hook conf = withUrgencyHookC hook urgencyConfig conf
--
-- (Don't type the @...@, you dolt.) See 'UrgencyConfig' for details on configuration.
withUrgencyHookC :: (LayoutClass l Window, UrgencyHook h) =>
h -> UrgencyConfig -> XConfig l -> XConfig (HandleEvent (WithUrgencyHook h) l)
h -> UrgencyConfig -> XConfig l -> XConfig l
withUrgencyHookC hook urgConf conf = conf {
layoutHook = eventHook (WithUrgencyHook hook urgConf) $ layoutHook conf,
handleEventHook = \e -> handleEvent (WithUrgencyHook hook urgConf) e >> handleEventHook conf e,
logHook = cleanupUrgents (suppressWhen urgConf) >> logHook conf
}
@@ -252,14 +251,14 @@ urgencyConfig = UrgencyConfig { suppressWhen = Visible, remindWhen = Dont }
-- | Focuses the most recently urgent window. Good for what ails ya -- I mean, your keybindings.
-- Example keybinding:
--
-- > , ((modMask , xK_BackSpace), focusUrgent)
-- > , ((modm , xK_BackSpace), focusUrgent)
focusUrgent :: X ()
focusUrgent = withUrgents $ flip whenJust (windows . W.focusWindow) . listToMaybe
-- | Just makes the urgents go away.
-- Example keybinding:
--
-- > , ((modMask .|. shiftMask, xK_BackSpace), clearUrgents)
-- > , ((modm .|. shiftMask, xK_BackSpace), clearUrgents)
clearUrgents :: X ()
clearUrgents = adjustUrgents (const []) >> adjustReminders (const [])
@@ -322,9 +321,10 @@ data WithUrgencyHook h = WithUrgencyHook h UrgencyConfig
-- ourselves, allowing us to clear urgency when a window is visible, and not to
-- set urgency if a window is visible. If you have a better idea, please, let us
-- know!
instance UrgencyHook h => EventHook (WithUrgencyHook h) where
handleEvent wuh event = case event of
PropertyEvent { ev_event_type = t, ev_atom = a, ev_window = w } -> do
handleEvent :: UrgencyHook h => WithUrgencyHook h -> Event -> X ()
handleEvent wuh event =
case event of
PropertyEvent { ev_event_type = t, ev_atom = a, ev_window = w } -> do
when (t == propertyNotify && a == wM_HINTS) $ withDisplay $ \dpy -> do
WMHints { wmh_flags = flags } <- io $ getWMHints dpy w
if (testBit flags urgencyHintBit) then do
@@ -333,9 +333,9 @@ instance UrgencyHook h => EventHook (WithUrgencyHook h) where
else
clearUrgency w
userCodeDef () =<< asks (logHook . config) -- call *after* IORef has been modified
DestroyWindowEvent {ev_window = w} ->
DestroyWindowEvent {ev_window = w} ->
clearUrgency w
_ ->
_ ->
mapM_ handleReminder =<< readReminders
where handleReminder reminder = handleTimer (timer reminder) event $ reminderHook wuh reminder

View File

@@ -0,0 +1,54 @@
----------------------------------------------------------------------------
-- |
-- Module : XMonad.Hooks.WorkspaceByPos
-- Copyright : (c) Jan Vornberger 2009
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : jan.vornberger@informatik.uni-oldenburg.de
-- Stability : unstable
-- Portability : not portable
--
-- Useful in a dual-head setup: Looks at the requested geometry of
-- new windows and moves them to the workspace of the non-focused
-- screen if necessary.
--
-----------------------------------------------------------------------------
module XMonad.Hooks.WorkspaceByPos (
-- * Usage
-- $usage
workspaceByPos
) where
import XMonad
import qualified XMonad.StackSet as W
import XMonad.Util.XUtils (fi)
import Data.Maybe
import Control.Applicative((<$>))
import Control.Monad.Error ((<=<),guard,lift,runErrorT,throwError)
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
--
-- > import XMonad.Hooks.WorkspaceByPos
-- >
-- > myManageHook = workspaceByPos <+> manageHook defaultConfig
-- >
-- > main = xmonad defaultConfig { manageHook = myManageHook }
workspaceByPos :: ManageHook
workspaceByPos = (maybe idHook doShift <=< liftX . needsMoving) =<< ask
needsMoving :: Window -> X (Maybe WorkspaceId)
needsMoving w = withDisplay $ \d -> do
-- only relocate windows with non-zero position
wa <- io $ getWindowAttributes d w
fmap (const Nothing `either` Just) . runErrorT $ do
guard $ wa_x wa /= 0 || wa_y wa /= 0
ws <- gets windowset
sc <- lift $ fromMaybe (W.current ws)
<$> pointScreen (fi $ wa_x wa) (fi $ wa_y wa)
Just wkspc <- lift $ screenWorkspace (W.screen sc)
guard $ W.currentTag ws /= wkspc
return wkspc `asTypeOf` throwError ""

View File

@@ -34,7 +34,7 @@ import XMonad.ManageHook ((-->))
-- > import XMonad.Actions.TagWindows
-- > import Data.List
--
-- > manageHook = xPropManageHook xPropMatches
-- > manageHook = xPropManageHook xPropMatches
-- >
-- > xPropMatches :: [XPropMatch]
-- > xPropMatches = [ ([ (wM_CLASS, any ("gimp"==))], (\w -> float w >> return (W.shift "2")))
@@ -71,7 +71,7 @@ xPropManageHook tms = mconcat $ map propToHook tms
where
propToHook (ms, f) = fmap and (mapM mkQuery ms) --> mkHook f
mkQuery (a, tf) = fmap tf (getQuery a)
mkHook func = ask >>= Query . lift . fmap Endo . func
mkHook func = ask >>= Query . lift . fmap Endo . func
getProp :: Display -> Window -> Atom -> X ([String])
getProp d w p = do

View File

@@ -7,7 +7,7 @@
-- License : BSD
--
-- Maintainer : glasser@mit.edu
-- Stability : unstable
-- Stability : stable
-- Portability : unportable
--
-- LayoutClass that puts non-focused windows in ribbons at the top and bottom
@@ -30,8 +30,8 @@ import Data.Ratio
--
-- Then edit your @layoutHook@ by adding the Accordion layout:
--
-- > myLayouts = Accordion ||| Full ||| etc..
-- > main = xmonad defaultConfig { layoutHook = myLayouts }
-- > myLayout = Accordion ||| Full ||| etc..
-- > main = xmonad defaultConfig { layoutHook = myLayout }
--
-- For more detailed instructions on editing the layoutHook see:
--

123
XMonad/Layout/AutoMaster.hs Normal file
View File

@@ -0,0 +1,123 @@
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, TypeSynonymInstances, FlexibleContexts #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Layout.AutoMaster
-- Copyright : (c) 2009 Ilya Portnov
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : Ilya Portnov <portnov84@rambler.ru>
-- Stability : unstable
-- Portability : unportable
--
-- Provides layout modifier AutoMaster. It separates screen in two parts -
-- master and slave. Size of slave area automatically changes depending on
-- number of slave windows.
--
-----------------------------------------------------------------------------
module XMonad.Layout.AutoMaster (
-- * Usage
-- $usage
autoMaster
) where
import Control.Monad
import XMonad
import qualified XMonad.StackSet as W
import XMonad.Layout.LayoutModifier
-- $usage
-- This module defines layout modifier named autoMaster. It separates
-- screen in two parts - master and slave. Master windows are arranged
-- in one row, in slave area underlying layout is run. Size of slave area
-- automatically increases when number of slave windows is increasing.
--
-- You can use this module by adding folowing in your @xmonad.hs@:
--
-- > import XMonad.Layout.AutoMaster
--
-- Then add layouts to your layoutHook:
--
-- > myLayoutHook = autoMaster 1 (1/100) Grid ||| ...
--
-- In this example, master area by default contains 1 window (you can
-- change this number in runtime with usual IncMasterN message), changing
-- slave area size with 1/100 on each Shrink/Expand message.
-- | Data type for layout modifier
data AutoMaster a = AutoMaster Int Float Float
deriving (Read,Show)
instance LayoutModifier AutoMaster Window where
modifyLayout (AutoMaster k bias _) = autoLayout k bias
pureMess = autoMess
-- | Handle Shrink/Expand and IncMasterN messages
autoMess :: AutoMaster a -> SomeMessage -> Maybe (AutoMaster a)
autoMess (AutoMaster k bias delta) m = msum [fmap resize (fromMessage m),
fmap incmastern (fromMessage m)]
where incmastern (IncMasterN d) = AutoMaster (max 1 (k+d)) bias delta
resize Expand = AutoMaster k (min ( 0.4) $ bias+delta) delta
resize Shrink = AutoMaster k (max (-0.4) $ bias-delta) delta
-- | Main layout function
autoLayout :: (LayoutClass l Window) =>
Int ->
Float ->
W.Workspace WorkspaceId (l Window) Window
-> Rectangle
-> X ([(Window, Rectangle)], Maybe (l Window))
autoLayout k bias wksp rect = do
let stack = W.stack wksp
let ws = W.integrate' stack
let n = length ws
if null ws then
runLayout wksp rect
else do
if (n<=k) then
return ((divideRow rect ws),Nothing)
else do
let master = take k ws
let filtStack = stack >>= W.filter (\w -> not (w `elem` master))
wrs <- runLayout (wksp {W.stack = filtStack}) (slaveRect rect n bias)
return ((divideRow (masterRect rect n bias) master) ++ (fst wrs),
snd wrs)
-- | Calculates height of master area, depending on number of windows.
masterHeight :: Int -> Float -> Float
masterHeight n bias = (calcHeight n) + bias
where calcHeight :: Int -> Float
calcHeight 1 = 1.0
calcHeight m = if (m<9) then (43/45) - (fromIntegral m)*(7/90) else (1/3)
-- | Rectangle for master area
masterRect :: Rectangle -> Int -> Float -> Rectangle
masterRect (Rectangle sx sy sw sh) n bias = Rectangle sx sy sw h
where h = round $ (fromIntegral sh)*(masterHeight n bias)
-- | Rectangle for slave area
slaveRect :: Rectangle -> Int -> Float -> Rectangle
slaveRect (Rectangle sx sy sw sh) n bias = Rectangle sx (sy+mh) sw h
where mh = round $ (fromIntegral sh)*(masterHeight n bias)
h = round $ (fromIntegral sh)*(1-masterHeight n bias)
-- | Divide rectangle between windows
divideRow :: Rectangle -> [a] -> [(a, Rectangle)]
divideRow (Rectangle x y w h) ws = zip ws rects
where n = length ws
oneW = fromIntegral w `div` n
oneRect = Rectangle x y (fromIntegral oneW) h
rects = take n $ iterate (shiftR (fromIntegral oneW)) oneRect
-- | Shift rectangle right
shiftR :: Position -> Rectangle -> Rectangle
shiftR s (Rectangle x y w h) = Rectangle (x+s) y w h
-- | User interface function
autoMaster :: LayoutClass l a =>
Int -> -- Number of master windows
Float -> -- Step for which to increment/decrement master area size with Shrink/Expand
l a ->
ModifiedLayout AutoMaster l a
autoMaster nmaster delta = ModifiedLayout (AutoMaster nmaster 0 delta)

View File

@@ -0,0 +1,164 @@
{-# LANGUAGE TypeSynonymInstances, MultiParamTypeClasses, PatternGuards #-}
----------------------------------------------------------------------------
-- |
-- Module : XMonad.Layout.BorderResize
-- Copyright : (c) Jan Vornberger 2009
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : jan.vornberger@informatik.uni-oldenburg.de
-- Stability : unstable
-- Portability : not portable
--
-- 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.
--
-----------------------------------------------------------------------------
module XMonad.Layout.BorderResize
( -- * Usage
-- $usage
borderResize
, BorderResize (..)
) where
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((<$>))
-- $usage
-- You can use this module with the following in your
-- @~\/.xmonad\/xmonad.hs@:
--
-- > import XMonad.Layout.BorderResize
-- > myLayout = borderResize (... layout setup that reacts to SetGeometry ...)
-- > 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)
data BorderResize a = BR [BorderWithWin] deriving (Show, Read)
brBorderOffset :: Position
brBorderOffset = 5
brBorderSize :: Dimension
brBorderSize = 10
brCursorRightSide :: Glyph
brCursorRightSide = 96
brCursorLeftSide :: Glyph
brCursorLeftSide = 70
brCursorTopSide :: Glyph
brCursorTopSide = 138
brCursorBottomSide :: Glyph
brCursorBottomSide = 16
borderResize :: l a -> ModifiedLayout BorderResize l a
borderResize = ModifiedLayout (BR [])
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)
-- 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.
handleMess (BR borders) m
| Just e <- fromMessage m :: Maybe Event = handleResize borders e >> return Nothing
| Just _ <- fromMessage m :: Maybe LayoutMessages =
mapM_ deleteBorder borders >> return (Just $ BR [])
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)
)
handleResize :: [BorderWithWin] -> 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) ->
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) ->
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) ->
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 _) ->
mouseDrag (\_ y -> do
let nht = max 1 $ fi (y - hy)
rect = Rectangle hx hy hwh nht
focus hostWin
when (y - hy > 0) $ sendMessage (SetGeometry rect)) (focus hostWin)
handleResize _ _ = return ()
createBorder :: BorderWithRect -> X (((Window, Rectangle), BorderWithWin))
createBorder (_, borderRect, borderCursor, borderInfo) = do
borderWin <- createInputWindow borderCursor borderRect
return ((borderWin, borderRect), (borderWin, borderInfo))
deleteBorder :: BorderWithWin -> X ()
deleteBorder (borderWin, _) = deleteWindow borderWin
createInputWindow :: Glyph -> Rectangle -> X Window
createInputWindow cursorGlyph r = withDisplay $ \d -> do
win <- mkInputWindow d r
io $ selectInput d win (exposureMask .|. buttonPressMask)
cursor <- io $ createFontCursor d cursorGlyph
io $ defineCursor d win cursor
io $ freeCursor d cursor
showWindow win
return win
mkInputWindow :: Display -> Rectangle -> X Window
mkInputWindow d (Rectangle x y w h) = do
rw <- asks theRoot
let screen = defaultScreenOfDisplay d
visual = defaultVisualOfScreen screen
attrmask = cWOverrideRedirect
io $ allocaSetWindowAttributes $
\attributes -> do
set_override_redirect attributes True
createWindow d rw x y w h 0 0 inputOnly visual attrmask attributes
for :: [a] -> (a -> b) -> [b]
for = flip map

View File

@@ -1,5 +1,5 @@
{-# OPTIONS_GHC -fglasgow-exts #-} -- For deriving Data/Typeable
{-# LANGUAGE TypeSynonymInstances, MultiParamTypeClasses, DeriveDataTypeable #-}
{-# LANGUAGE PatternGuards, FlexibleContexts, FlexibleInstances #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Layout.BoringWindows
@@ -17,51 +17,122 @@
module XMonad.Layout.BoringWindows (
-- * Usage
-- $usage
boringWindows,
boringWindows, boringAuto,
markBoring, clearBoring,
focusUp, focusDown
focusUp, focusDown, focusMaster,
UpdateBoring(UpdateBoring),
BoringMessage(Replace,Merge),
BoringWindows()
) where
import XMonad hiding (Point)
import XMonad.Layout.LayoutModifier(ModifiedLayout(..),
LayoutModifier(handleMessOrMaybeModifyIt, redoLayout))
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 qualified Data.Map as M
import qualified XMonad.StackSet as W
import XMonad.Layout.LayoutModifier
import XMonad.Util.Invisible
data BoringMessage = FocusUp | FocusDown | IsBoring Window | ClearBoring
deriving ( Read, Show, Typeable )
-- $usage
-- You can use this module with the following in your
-- @~\/.xmonad\/xmonad.hs@:
--
-- > import XMonad.Layout.BoringWindows
--
-- Then edit your @layoutHook@ by adding the layout modifier:
--
-- > myLayout = boringWindows (Full ||| etc..)
-- > main = xmonad defaultConfig { layoutHook = myLayout }
--
-- Then to your keybindings, add:
--
-- > , ((modm, xK_j), focusUp)
-- > , ((modm, xK_k), focusDown)
-- > , ((modm, xK_m), focusMaster)
--
-- For more detailed instructions on editing the layoutHook see:
--
-- "XMonad.Doc.Extending#Editing_the_layout_hook"
data BoringMessage = FocusUp | FocusDown | FocusMaster | IsBoring Window | ClearBoring
| Replace String [Window]
| Merge String [Window]
deriving ( Read, Show, Typeable )
instance Message BoringMessage
markBoring, clearBoring, focusUp, focusDown :: X ()
-- | UpdateBoring is sent before attempting to view another boring window, so
-- that layouts have a chance to mark boring windows.
data UpdateBoring = UpdateBoring
deriving (Typeable)
instance Message UpdateBoring
markBoring, clearBoring, focusUp, focusDown, focusMaster :: X ()
markBoring = withFocused (sendMessage . IsBoring)
clearBoring = sendMessage ClearBoring
focusUp = sendMessage FocusUp
focusDown = sendMessage FocusDown
focusUp = sendMessage UpdateBoring >> sendMessage FocusUp
focusDown = sendMessage UpdateBoring >> sendMessage FocusDown
focusMaster = sendMessage UpdateBoring >> sendMessage FocusMaster
data BoringWindows a = BoringWindows (Invisible [] a) deriving ( Show, Read, Typeable )
data BoringWindows a = BoringWindows
{ namedBoring :: M.Map String [a] -- ^ store borings with a specific source
, chosenBoring :: [a] -- ^ user-chosen borings
, hiddenBoring :: Maybe [a] -- ^ maybe mark hidden windows
} deriving (Show,Read,Typeable)
boringWindows :: (LayoutClass l a, Eq a) => l a -> ModifiedLayout BoringWindows l a
boringWindows = ModifiedLayout (BoringWindows (I []))
boringWindows = ModifiedLayout (BoringWindows M.empty [] Nothing)
-- | Mark windows that are not given rectangles as boring
boringAuto :: (LayoutClass l a, Eq a) => l a -> ModifiedLayout BoringWindows l a
boringAuto = ModifiedLayout (BoringWindows M.empty [] (Just []))
instance LayoutModifier BoringWindows Window where
handleMessOrMaybeModifyIt (BoringWindows (I bs)) m
| Just (IsBoring b) <- fromMessage m = return $ Just $ Left $ BoringWindows (I (b:bs))
| Just ClearBoring <- fromMessage m = return $ Just $ Left $ BoringWindows (I [])
| Just FocusUp <- fromMessage m = do windows $ W.modify' $ focusUp'
return Nothing
| Just FocusDown <- fromMessage m =
do windows $ W.modify' (reverseStack . focusUp' . reverseStack)
redoLayout (b@BoringWindows { hiddenBoring = bs }) _r mst arrs = do
let bs' = W.integrate' mst \\ map fst arrs
return (arrs, Just $ b { hiddenBoring = const bs' <$> bs } )
handleMessOrMaybeModifyIt bst@(BoringWindows nbs cbs lbs) m
| Just (Replace k ws) <- fromMessage m
, maybe True (ws/=) (M.lookup k nbs) =
let nnb = if null ws then M.delete k nbs
else M.insert k ws nbs
in rjl bst { namedBoring = nnb }
| Just (Merge k ws) <- fromMessage m
, maybe True (not . null . (ws \\)) (M.lookup k nbs) =
rjl bst { namedBoring = M.insertWith union k ws nbs }
| Just (IsBoring w) <- fromMessage m , w `notElem` cbs =
rjl bst { chosenBoring = w:cbs }
| Just ClearBoring <- fromMessage m, not (null cbs) =
rjl bst { namedBoring = M.empty, chosenBoring = []}
| Just FocusUp <- fromMessage m =
do windows $ W.modify' $ skipBoring W.focusUp'
return Nothing
where focusUp' (W.Stack t ls rs)
| (a,l:ls') <- skipBoring ls = W.Stack l ls' (a++t:rs)
| otherwise = case skipBoring (reverse (t:rs)++ls) of
(a,x:xs) -> W.Stack x xs a
_ -> W.Stack t ls rs
skipBoring [] = ([],[])
skipBoring (x:xs) | x `elem` bs = case skipBoring xs of
(a,b) -> (x:a,b)
| otherwise = ([],x:xs)
| Just FocusDown <- fromMessage m =
do windows $ W.modify' $ skipBoring W.focusDown'
return Nothing
| Just FocusMaster <- fromMessage m =
do windows $ W.modify'
$ skipBoring W.focusDown' -- wiggle focus to make sure
. skipBoring W.focusUp' -- no boring window gets the focus
. focusMaster'
return Nothing
where skipBoring f st = fromMaybe st $ listToMaybe
$ filter ((`notElem` W.focus st:bs) . W.focus)
$ take (length $ W.integrate st)
$ iterate f st
bs = concat $ cbs:maybeToList lbs ++ M.elems nbs
rjl = return . Just . Left
handleMessOrMaybeModifyIt _ _ = return Nothing
-- | reverse a stack: up becomes down and down becomes up.
reverseStack :: W.Stack a -> W.Stack a
reverseStack (W.Stack t ls rs) = W.Stack t rs ls
-- | Variant of 'focusMaster' that works on a
-- 'Stack' rather than an entire 'StackSet'.
focusMaster' :: W.Stack a -> W.Stack a
focusMaster' c@(W.Stack _ [] _) = c
focusMaster' (W.Stack t ls rs) = W.Stack x [] (xs ++ t : rs) where (x:xs) = reverse ls

View File

@@ -3,15 +3,15 @@
-- |
-- Module : XMonad.Layout.CenteredMaster
-- Copyright : (c) 2009 Ilya Portnov
-- License : GNU GPL v3 or any later
-- License : BSD-style (see xmonad/LICENSE)
--
-- Maintainer : Ilya Portnov <portnov84@rambler.ru>
-- Stability : unstable
-- Portability : unportable
--
-- Two layout modifiers. centerMaster places master window at center,
-- on top of all other windows, which are managed by base layout.
-- topRightMaster is similar, but places master window in top right corner
-- Two layout modifiers. centerMaster places master window at center,
-- on top of all other windows, which are managed by base layout.
-- topRightMaster is similar, but places master window in top right corner
-- instead of center.
--
-----------------------------------------------------------------------------
@@ -30,22 +30,22 @@ import qualified XMonad.StackSet as W
-- $usage
-- This module defines two new layout modifiers: centerMaster and topRightMaster.
-- centerMaster places master window at center of screen, on top of others.
-- centerMaster places master window at center of screen, on top of others.
-- All other windows in background are managed by base layout.
-- topRightMaster is like centerMaster, but places master window in top right corner instead of center.
--
--
-- Yo can use this module by adding folowing in your @xmonad.hs@:
--
-- > import XMonad.Layout.CenteredMaster
--
--
-- Then add layouts to your layoutHook:
--
--
-- > myLayoutHook = centerMaster Grid ||| ...
-- | Function that decides where master window should be placed
type Positioner = Rectangle -> Rectangle
-- | Data type for LayoutModifier
-- | Data type for LayoutModifier
data CenteredMaster a = CenteredMaster deriving (Read,Show)
instance LayoutModifier CenteredMaster Window where
@@ -56,12 +56,12 @@ data TopRightMaster a = TopRightMaster deriving (Read,Show)
instance LayoutModifier TopRightMaster Window where
modifyLayout TopRightMaster = applyPosition (topRight (3/7) (1/2))
-- | Modifier that puts master window in center, other windows in background
-- | Modifier that puts master window in center, other windows in background
-- are managed by given layout
centerMaster :: LayoutClass l a => l a -> ModifiedLayout CenteredMaster l a
centerMaster = ModifiedLayout CenteredMaster
-- | Modifier that puts master window in top right corner, other windows in background
-- | Modifier that puts master window in top right corner, other windows in background
-- are managed by given layout
topRightMaster :: LayoutClass l a => l a -> ModifiedLayout TopRightMaster l a
topRightMaster = ModifiedLayout TopRightMaster

View File

@@ -31,8 +31,8 @@ import XMonad.StackSet (integrate, peek)
--
-- Then edit your @layoutHook@ by adding the Circle layout:
--
-- > myLayouts = Circle ||| Full ||| etc..
-- > main = xmonad defaultConfig { layoutHook = myLayouts }
-- > myLayout = Circle ||| Full ||| etc..
-- > main = xmonad defaultConfig { layoutHook = myLayout }
--
-- For more detailed instructions on editing the layoutHook see:
--

71
XMonad/Layout/Column.hs Normal file
View File

@@ -0,0 +1,71 @@
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, TypeSynonymInstances #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Layout.Column
-- Copyright : (c) 2009 Ilya Portnov
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : Ilya Portnov <portnov84@rambler.ru>
-- Stability : unstable
-- Portability : unportable
--
-- Provides Column layout that places all windows in one column. Windows
-- heights are calculated from equation: H1/H2 = H2/H3 = ... = q, where q is
-- given. With Shrink/Expand messages you can change the q value.
--
-----------------------------------------------------------------------------
module XMonad.Layout.Column (
-- * Usage
-- $usage
Column (..)
) where
import XMonad
import qualified XMonad.StackSet as W
-- $usage
-- This module defines layot named Column. It places all windows in one
-- column. Windows heights are calculated from equation: H1/H2 = H2/H3 = ... =
-- q, where `q' is given (thus, windows heights are members of geometric
-- progression). With Shrink/Expand messages one can change the `q' value.
--
-- You can use this module by adding folowing in your @xmonad.hs@:
--
-- > import XMonad.Layout.Column
--
-- Then add layouts to your layoutHook:
--
-- > myLayoutHook = Column 1.6 ||| ...
--
-- In this example, each next window will have height 1.6 times less then
-- previous window.
data Column a = Column Float deriving (Read,Show)
instance LayoutClass Column a where
pureLayout = columnLayout
pureMessage = columnMessage
columnMessage :: Column a -> SomeMessage -> Maybe (Column a)
columnMessage (Column q) m = fmap resize (fromMessage m)
where resize Shrink = Column (q-0.1)
resize Expand = Column (q+0.1)
columnLayout :: Column a -> Rectangle -> W.Stack a -> [(a,Rectangle)]
columnLayout (Column q) rect stack = zip ws rects
where ws = W.integrate stack
n = length ws
heights = map (xn n rect q) [1..n]
ys = [fromIntegral $ sum $ take k heights | k <- [0..n-1]]
rects = map (mkRect rect) $ zip heights ys
mkRect :: Rectangle -> (Dimension,Position) -> Rectangle
mkRect (Rectangle xs ys ws _) (h,y) = Rectangle xs (ys+fromIntegral y) ws h
xn :: Int -> Rectangle -> Float -> Int -> Dimension
xn n (Rectangle _ _ _ h) q k = if q==1 then
h `div` (fromIntegral n)
else
round ((fromIntegral h)*q^(n-k)*(1-q)/(1-q^n))

View File

@@ -25,7 +25,7 @@ module XMonad.Layout.Combo (
import Data.List ( delete, intersect, (\\) )
import Data.Maybe ( isJust )
import XMonad hiding (focus)
import XMonad.StackSet ( integrate, Workspace (..), Stack(..) )
import XMonad.StackSet ( integrate', Workspace (..), Stack(..) )
import XMonad.Layout.WindowNavigation ( MoveWindowToWindow(..) )
import qualified XMonad.StackSet as W ( differentiate )
@@ -51,10 +51,10 @@ import qualified XMonad.StackSet as W ( differentiate )
-- each sublayout. To do this, use "XMonad.Layout.WindowNavigation",
-- and add the following key bindings (or something similar):
--
-- > , ((modMask x .|. controlMask .|. shiftMask, xK_Right), sendMessage $ Move R)
-- > , ((modMask x .|. controlMask .|. shiftMask, xK_Left ), sendMessage $ Move L)
-- > , ((modMask x .|. controlMask .|. shiftMask, xK_Up ), sendMessage $ Move U)
-- > , ((modMask x .|. controlMask .|. shiftMask, xK_Down ), sendMessage $ Move D)
-- > , ((modm .|. controlMask .|. shiftMask, xK_Right), sendMessage $ Move R)
-- > , ((modm .|. controlMask .|. shiftMask, xK_Left ), sendMessage $ Move L)
-- > , ((modm .|. controlMask .|. shiftMask, xK_Up ), sendMessage $ Move U)
-- > , ((modm .|. controlMask .|. shiftMask, xK_Down ), sendMessage $ Move D)
--
-- For detailed instruction on editing the key binding see
-- "XMonad.Doc.Extending#Editing_key_bindings".
@@ -76,7 +76,7 @@ combineTwo = C2 [] []
instance (LayoutClass l (), LayoutClass l1 a, LayoutClass l2 a, Read a, Show a, Eq a, Typeable a)
=> LayoutClass (CombineTwo (l ()) l1 l2) a where
doLayout (C2 f w2 super l1 l2) rinput s = arrange (integrate s)
runLayout (Workspace _ (C2 f w2 super l1 l2) s) rinput = arrange (integrate' s)
where arrange [] = do l1' <- maybe l1 id `fmap` handleMessage l1 (SomeMessage ReleaseResources)
l2' <- maybe l2 id `fmap` handleMessage l2 (SomeMessage ReleaseResources)
super' <- maybe super id `fmap`
@@ -93,12 +93,11 @@ instance (LayoutClass l (), LayoutClass l1 a, LayoutClass l2 a, Read a, Show a,
x -> case origws \\ x of
[] -> init x
_ -> x
superstack = if focus s `elem` w2'
then Stack { focus=(), up=[], down=[()] }
else Stack { focus=(), up=[], down=[()] }
superstack = Stack { focus=(), up=[], down=[()] }
s1 = differentiate f' (origws \\ w2')
s2 = differentiate f' w2'
f' = focus s:delete (focus s) f
f' = case s of (Just s') -> focus s':delete (focus s') f
Nothing -> f
([((),r1),((),r2)], msuper') <- runLayout (Workspace "" super (Just superstack)) rinput
(wrs1, ml1') <- runLayout (Workspace "" l1 s1) r1
(wrs2, ml2') <- runLayout (Workspace "" l2 s2) r2

180
XMonad/Layout/ComboP.hs Normal file
View File

@@ -0,0 +1,180 @@
{-# LANGUAGE TypeSynonymInstances, DeriveDataTypeable, MultiParamTypeClasses, FlexibleContexts, FlexibleInstances, PatternGuards #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Layout.ComboP
-- Copyright : (c) Konstantin Sobolev <konstantin.sobolev@gmail.com>
-- License : BSD-style (see LICENSE)
--
-- Maintainer : Konstantin Sobolev <konstantin.sobolev@gmail.com>
-- Stability : unstable
-- Portability : unportable
--
-- A layout that combines multiple layouts and allows to specify where to put
-- new windows.
--
-----------------------------------------------------------------------------
module XMonad.Layout.ComboP (
-- * Usage
-- $usage
combineTwoP,
CombineTwoP,
SwapWindow(..),
Property(..)
) where
import Data.List ( delete, intersect, (\\) )
import Data.Maybe ( isJust )
import Control.Monad
import XMonad hiding (focus)
import XMonad.StackSet ( integrate, Workspace (..), Stack(..) )
import XMonad.Layout.WindowNavigation
import XMonad.Util.WindowProperties
import qualified XMonad.StackSet as W
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
--
-- > import XMonad.Layout.ComboP
--
-- and add something like
--
-- > combineTwoP (TwoPane 0.03 0.5) (tabbed shrinkText defaultTConf) (tabbed shrinkText defaultTConf) (ClassName "Firefox")
--
-- to your layouts. This way all windows with class = \"Firefox\" will always go
-- to the left pane, all others - to the right.
--
-- For more detailed instructions on editing the layoutHook see:
--
-- "XMonad.Doc.Extending#Editing_the_layout_hook"
--
-- 'combineTwoP' is a simple layout combinator based on 'combineTwo' from Combo, with
-- addition of a 'Property' which tells where to put new windows. Windows mathing
-- the property will go into the first part, all others will go into the second
-- part. It supports @Move@ messages as 'combineTwo' does, but it also introduces
-- 'SwapWindow' message which sends focused window to the other part. It is
-- required because @Move@ commands don't work when one of the parts is empty.
-- To use it, import \"XMonad.Layout.WindowNavigation\", and add the following key
-- bindings (or something similar):
--
-- > , ((modm .|. controlMask .|. shiftMask, xK_Right), sendMessage $ Move R)
-- > , ((modm .|. controlMask .|. shiftMask, xK_Left ), sendMessage $ Move L)
-- > , ((modm .|. controlMask .|. shiftMask, xK_Up ), sendMessage $ Move U)
-- > , ((modm .|. controlMask .|. shiftMask, xK_Down ), sendMessage $ Move D)
-- > , ((modm .|. controlMask .|. shiftMask, xK_s ), sendMessage $ SwapWindow)
--
-- For detailed instruction on editing the key binding see
-- "XMonad.Doc.Extending#Editing_key_bindings".
data SwapWindow = SwapWindow -- ^ Swap window between panes
| SwapWindowN Int -- ^ Swap window between panes in the N-th nested ComboP. @SwapWindowN 0@ equals to SwapWindow
deriving (Read, Show, Typeable)
instance Message SwapWindow
data CombineTwoP l l1 l2 a = C2P [a] [a] [a] l (l1 a) (l2 a) Property
deriving (Read, Show)
combineTwoP :: (LayoutClass super(), LayoutClass l1 Window, LayoutClass l2 Window) =>
super () -> l1 Window -> l2 Window -> Property -> CombineTwoP (super ()) l1 l2 Window
combineTwoP = C2P [] [] []
instance (LayoutClass l (), LayoutClass l1 Window, LayoutClass l2 Window) =>
LayoutClass (CombineTwoP (l ()) l1 l2) Window where
doLayout (C2P f w1 w2 super l1 l2 prop) rinput s =
let origws = W.integrate s -- passed in windows
w1c = origws `intersect` w1 -- current windows in the first pane
w2c = origws `intersect` w2 -- current windows in the second pane
new = origws \\ (w1c ++ w2c) -- new windows
superstack = Just Stack { focus=(), up=[], down=[()] }
f' = focus s:delete (focus s) f -- list of focused windows, contains 2 elements at most
in do
matching <- (hasProperty prop) `filterM` new -- new windows matching predecate
let w1' = w1c ++ matching -- updated first pane windows
w2' = w2c ++ (new \\ matching) -- updated second pane windows
s1 = differentiate f' w1' -- first pane stack
s2 = differentiate f' w2' -- second pane stack
([((),r1),((),r2)], msuper') <- runLayout (Workspace "" super superstack) rinput
(wrs1, ml1') <- runLayout (Workspace "" l1 s1) r1
(wrs2, ml2') <- runLayout (Workspace "" l2 s2) r2
return (wrs1++wrs2, Just $ C2P f' w1' w2' (maybe super id msuper')
(maybe l1 id ml1') (maybe l2 id ml2') prop)
handleMessage us@(C2P f ws1 ws2 super l1 l2 prop) m
| Just SwapWindow <- fromMessage m = swap us
| Just (SwapWindowN 0) <- fromMessage m = swap us
| Just (SwapWindowN n) <- fromMessage m = forwardToFocused us $ SomeMessage $ SwapWindowN $ n-1
| Just (MoveWindowToWindow w1 w2) <- fromMessage m,
w1 `elem` ws1,
w2 `elem` ws2 = return $ Just $ C2P f (delete w1 ws1) (w1:ws2) super l1 l2 prop
| Just (MoveWindowToWindow w1 w2) <- fromMessage m,
w1 `elem` ws2,
w2 `elem` ws1 = return $ Just $ C2P f (w1:ws1) (delete w1 ws2) super l1 l2 prop
| otherwise = do ml1' <- handleMessage l1 m
ml2' <- handleMessage l2 m
msuper' <- handleMessage super m
if isJust msuper' || isJust ml1' || isJust ml2'
then return $ Just $ C2P f ws1 ws2
(maybe super id msuper')
(maybe l1 id ml1')
(maybe l2 id ml2') prop
else return Nothing
description (C2P _ _ _ super l1 l2 prop) = "combining " ++ description l1 ++ " and "++
description l2 ++ " with " ++ description super ++ " using "++ (show prop)
-- send focused window to the other pane. Does nothing if we don't
-- own the focused window
swap :: (LayoutClass s a, LayoutClass l1 Window, LayoutClass l2 Window) =>
CombineTwoP (s a) l1 l2 Window -> X (Maybe (CombineTwoP (s a) l1 l2 Window))
swap (C2P f ws1 ws2 super l1 l2 prop) = do
mst <- gets (W.stack . W.workspace . W.current . windowset)
let (ws1', ws2') = case mst of
Nothing -> (ws1, ws2)
Just st -> if foc `elem` ws1
then (foc `delete` ws1, foc:ws2)
else if foc `elem` ws2
then (foc:ws1, foc `delete` ws2)
else (ws1, ws2)
where foc = W.focus st
if (ws1,ws2) == (ws1',ws2')
then return Nothing
else return $ Just $ C2P f ws1' ws2' super l1 l2 prop
-- forwards the message to the sublayout which contains the focused window
forwardToFocused :: (LayoutClass l1 Window, LayoutClass l2 Window, LayoutClass s a) =>
CombineTwoP (s a) l1 l2 Window -> SomeMessage -> X (Maybe (CombineTwoP (s a) l1 l2 Window))
forwardToFocused (C2P f ws1 ws2 super l1 l2 prop) m = do
ml1 <- forwardIfFocused l1 ws1 m
ml2 <- forwardIfFocused l2 ws2 m
ms <- if isJust ml1 || isJust ml2
then return Nothing
else handleMessage super m
if isJust ml1 || isJust ml2 || isJust ms
then return $ Just $ C2P f ws1 ws2 (maybe super id ms) (maybe l1 id ml1) (maybe l2 id ml2) prop
else return Nothing
-- forwards message m to layout l if focused window is among w
forwardIfFocused :: (LayoutClass l Window) => l Window -> [Window] -> SomeMessage -> X (Maybe (l Window))
forwardIfFocused l w m = do
mst <- gets (W.stack . W.workspace . W.current . windowset)
maybe (return Nothing) send mst where
send st = if (W.focus st) `elem` w
then handleMessage l m
else return Nothing
-- code from CombineTwo
-- given two sets of zs and xs takes the first z from zs that also belongs to xs
-- and turns xs into a stack with z being current element. Acts as
-- StackSet.differentiate if zs and xs don't intersect
differentiate :: Eq q => [q] -> [q] -> Maybe (Stack q)
differentiate (z:zs) xs | z `elem` xs = Just $ Stack { focus=z
, up = reverse $ takeWhile (/=z) xs
, down = tail $ dropWhile (/=z) xs }
| otherwise = differentiate zs xs
differentiate [] xs = W.differentiate xs
-- vim:ts=4:shiftwidth=4:softtabstop=4:expandtab:foldlevel=20:

112
XMonad/Layout/Cross.hs Normal file
View File

@@ -0,0 +1,112 @@
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}
-- |
-- Module : XMonad.Layout.Cross
-- Copyright : (c) Luis Cabellos <zhen.sydow@gmail.com>
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : Luis Cabellos <zhen.sydow@gmail.com>
-- Stability : stable
-- Portability : portable
--
-- A Cross Layout with the main window in the center.
--
module XMonad.Layout.Cross(
-- * Usage
-- $usage
simpleCross
, Cross(..) ) where
import XMonad( Dimension, Rectangle(..), LayoutClass(..), Resize(..), fromMessage )
import XMonad.StackSet( focus, up, down )
import Control.Monad( msum )
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
--
-- > import XMonad.Layout.Cross
--
-- Then edit your @layoutHook@ by adding one of the Cross layouts:
--
-- > myLayout = simpleCross ||| etc..
-- > main = xmonad defaultConfig { layoutHook = myLayout }
--
-- apply a factor to a Rectangle Dimension
(<%>) :: Dimension -> Rational -> Dimension
d <%> f = floor $ f * (fromIntegral d)
-- | The Cross Layout draws the focused window in the center of the screen
-- and part of the other windows on the sides. The 'Shrink' and 'Expand'
-- messages increment the size of the main window.
--
-- The focus keybindings change the center window, while other windows
-- cycle through the side positions. With the Cross layout only four
-- windows are shown around the focused window, two ups and two downs,
-- no matter how many are in the current stack. I.e. focus down cycles the
-- window below focused into the center; focus up cycles the window above.
data Cross a = Cross {
crossProp :: !Rational, -- ^ Proportion of screen occupied by the main window.
crossInc :: !Rational -- ^ Percent of main window to increment by when resizing.
}
deriving( Show, Read )
-- | A simple Cross Layout. It places the focused window in the center.
-- The proportion of the screen used by the main window is 4\/5.
simpleCross :: Cross a
simpleCross = Cross (4/5) (1/100)
instance LayoutClass Cross a where
pureLayout (Cross f _) r s = [(focus s, mainRect r f)] ++
(zip winCycle (upRects r f)) ++
(zip (reverse winCycle) (downRects r f))
where winCycle = (up s) ++ (reverse (down s))
pureMessage (Cross f d) m = msum [fmap resize (fromMessage m)]
where resize Shrink = Cross (max (1/100) $ f - d) d
resize Expand = Cross (min 1 $ f + d) d
description _ = "Cross"
-- get the Rectangle for the focused window
mainRect :: Rectangle -> Rational -> Rectangle
mainRect (Rectangle rx ry rw rh) f = Rectangle
(rx + (fromIntegral (rw <%> invf)))
(ry + (fromIntegral (rh <%> invf)))
(rw <%> f) (rh <%> f)
where invf = (1/2) * (1-f)
-- get the rectangles for the up windows
upRects :: Rectangle -> Rational -> [Rectangle]
upRects r f = [topRectangle r nf, rightRectangle r nf]
where nf = f * (8/10)
-- get the rectangles for the down windows
downRects :: Rectangle -> Rational -> [Rectangle]
downRects r f = [bottomRectangle r nf, leftRectangle r nf]
where nf = f * (8/10)
topRectangle :: Rectangle -> Rational -> Rectangle
topRectangle (Rectangle rx ry rw rh) f = Rectangle
(rx + (fromIntegral (rw <%> ((1-f)*(1/2)))))
ry
(rw <%> f) (rh <%> ((1-f)*(1/2)))
rightRectangle :: Rectangle -> Rational -> Rectangle
rightRectangle (Rectangle rx ry rw rh) f = Rectangle
(rx + (fromIntegral (rw - (rw <%> (1/2)))))
(ry + (fromIntegral (rh <%> ((1-f)*(1/2)))))
(rw <%> (1/2)) (rh <%> f)
bottomRectangle :: Rectangle -> Rational -> Rectangle
bottomRectangle (Rectangle rx ry rw rh) f = Rectangle
(rx + (fromIntegral (rw <%> ((1-f)*(1/2)))))
(ry + (fromIntegral (rh - (rh <%> ((1-f)*(1/2))))))
(rw <%> f) (rh <%> ((1-f)*(1/2)))
leftRectangle :: Rectangle -> Rational -> Rectangle
leftRectangle (Rectangle rx ry rw rh) f = Rectangle
rx
(ry + (fromIntegral (rh <%> ((1-f)*(1/2)))))
(rw <%> (1/2)) (rh <%> f)

View File

@@ -1,5 +1,4 @@
{-# OPTIONS_GHC -fglasgow-exts #-} -- for deriving Typeable
{-# LANGUAGE FlexibleContexts, FlexibleInstances, MultiParamTypeClasses, PatternGuards, TypeSynonymInstances #-}
{-# LANGUAGE DeriveDataTypeable, FlexibleContexts, FlexibleInstances, MultiParamTypeClasses, PatternGuards, TypeSynonymInstances #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Layout.Decoration
@@ -26,6 +25,7 @@ module XMonad.Layout.Decoration
, Shrinker (..), DefaultShrinker
, shrinkText, CustomShrink ( CustomShrink ), shrinkWhile
, isInStack, isVisible, isInvisible, isWithin, fi
, findWindowByDecoration
, module XMonad.Layout.LayoutModifier
) where
@@ -307,6 +307,9 @@ lookFor w ((wr,(Just dw,dr)):dwrs) | w == dw = Just (wr,(dw,dr))
lookFor w ((_, (Nothing, _)):dwrs) = lookFor w dwrs
lookFor _ [] = Nothing
findWindowByDecoration :: Window -> DecorationState -> Maybe (OrigWin,(Window,Maybe Rectangle))
findWindowByDecoration w ds = lookFor w (decos ds)
-- | Initialize the 'DecorationState' by initializing the font
-- structure and by creating the needed decorations.
initState :: DecorationStyle ds Window => Theme -> ds Window -> Rectangle

View File

@@ -127,8 +127,8 @@ import XMonad.Layout.SimpleFloat
-- up the key bindings, please read the documentation of
-- "XMonad.Layout.WindowArranger"
--
-- The deafult theme can be dynamically change with the xmonad theme
-- selector. See "XMonad.Prompt.Theme". For more themse, look at
-- The default theme can be dynamically change with the xmonad theme
-- selector. See "XMonad.Prompt.Theme". For more themes, look at
-- "XMonad.Util.Themes"
-- $circle
@@ -541,12 +541,12 @@ mirrorTallTabbed s t = tabBar s t Top (resizeVertical (fi $ decoHeight t) mirror
--
-- <http://code.haskell.org/~arossato/xmonadShots/floatSimpleSimple.png>
floatSimpleSimple :: (Show a, Eq a) => ModifiedLayout (Decoration SimpleDecoration DefaultShrinker)
(ModifiedLayout MouseResize (ModifiedLayout WindowArranger SimpleFloat)) a
(ModifiedLayout MouseResize (ModifiedLayout WindowArranger SimpleFloat)) a
floatSimpleSimple = simpleFloat
floatSimple :: (Show a, Eq a, Shrinker s) => s -> Theme ->
ModifiedLayout (Decoration SimpleDecoration s)
(ModifiedLayout MouseResize (ModifiedLayout WindowArranger SimpleFloat)) a
(ModifiedLayout MouseResize (ModifiedLayout WindowArranger SimpleFloat)) a
floatSimple = simpleFloat'
-- | This version is decorated with the 'DefaultDecoration' style.
@@ -555,14 +555,14 @@ floatSimple = simpleFloat'
--
-- <http://code.haskell.org/~arossato/xmonadShots/floatSimpleDefault.png>
floatSimpleDefault :: (Show a, Eq a) => ModifiedLayout (Decoration DefaultDecoration DefaultShrinker)
(ModifiedLayout MouseResize (ModifiedLayout WindowArranger SimpleFloat)) a
(ModifiedLayout MouseResize (ModifiedLayout WindowArranger SimpleFloat)) a
floatSimpleDefault = decoration shrinkText defaultTheme DefaultDecoration (mouseResize $ windowArrangeAll $ SF 20)
-- | Same as 'floatSimpleDefault', but with the possibility of setting a
-- custom shrinker and a custom theme.
floatDefault :: (Show a, Eq a, Shrinker s) => s -> Theme ->
ModifiedLayout (Decoration DefaultDecoration s)
(ModifiedLayout MouseResize (ModifiedLayout WindowArranger SimpleFloat)) a
(ModifiedLayout MouseResize (ModifiedLayout WindowArranger SimpleFloat)) a
floatDefault s t = decoration s t DefaultDecoration (mouseResize $ windowArrangeAll $ SF (decoHeight t))
-- | This version is decorated with the 'DwmStyle'. Note that this is
@@ -572,14 +572,14 @@ floatDefault s t = decoration s t DefaultDecoration (mouseResize $ windowArrange
--
-- <http://code.haskell.org/~arossato/xmonadShots/floatSimpleDwmStyle.png>
floatSimpleDwmStyle :: (Show a, Eq a) => ModifiedLayout (Decoration DwmStyle DefaultShrinker)
(ModifiedLayout MouseResize (ModifiedLayout WindowArranger SimpleFloat)) a
(ModifiedLayout MouseResize (ModifiedLayout WindowArranger SimpleFloat)) a
floatSimpleDwmStyle = decoration shrinkText defaultTheme Dwm (mouseResize $ windowArrangeAll $ SF 20)
-- | Same as 'floatSimpleDwmStyle', but with the possibility of setting a
-- custom shrinker and a custom theme.
floatDwmStyle :: (Show a, Eq a, Shrinker s) => s -> Theme ->
ModifiedLayout (Decoration DwmStyle s)
(ModifiedLayout MouseResize (ModifiedLayout WindowArranger SimpleFloat)) a
(ModifiedLayout MouseResize (ModifiedLayout WindowArranger SimpleFloat)) a
floatDwmStyle s t = decoration s t Dwm (mouseResize $ windowArrangeAll $ SF (decoHeight t))
-- | This version is decorated with the 'TabbedDecoration' style.
@@ -589,12 +589,12 @@ floatDwmStyle s t = decoration s t Dwm (mouseResize $ windowArrangeAll $ SF (dec
--
-- <http://code.haskell.org/~arossato/xmonadShots/floatSimpleTabbed.png>
floatSimpleTabbed :: (Show a, Eq a) => ModifiedLayout (Decoration TabBarDecoration DefaultShrinker)
(ModifiedLayout MouseResize (ModifiedLayout WindowArranger SimpleFloat)) a
(ModifiedLayout MouseResize (ModifiedLayout WindowArranger SimpleFloat)) a
floatSimpleTabbed = tabBar shrinkText defaultTheme Top (mouseResize $ windowArrangeAll $ SF 20)
-- | Same as 'floatSimpleTabbed', but with the possibility of setting a
-- custom shrinker and a custom theme.
floatTabbed :: (Show a, Eq a, Shrinker s) => s -> Theme ->
ModifiedLayout (Decoration TabBarDecoration s)
(ModifiedLayout MouseResize (ModifiedLayout WindowArranger SimpleFloat)) a
(ModifiedLayout MouseResize (ModifiedLayout WindowArranger SimpleFloat)) a
floatTabbed s t = tabBar s t Top (mouseResize $ windowArrangeAll $ SF (decoHeight t))

View File

@@ -33,8 +33,8 @@ import Control.Monad (ap)
--
-- Then edit your @layoutHook@ by adding the Dishes layout:
--
-- > myLayouts = Dishes 2 (1/6) ||| Full ||| etc..
-- > main = xmonad defaultConfig { layoutHook = myLayouts }
-- > myLayout = Dishes 2 (1/6) ||| Full ||| etc..
-- > main = xmonad defaultConfig { layoutHook = myLayout }
--
-- For more detailed instructions on editing the layoutHook see:
--

View File

@@ -1,5 +1,4 @@
{-# OPTIONS_GHC -fglasgow-exts #-} -- For deriving Data/Typeable
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, PatternGuards, TypeSynonymInstances #-}
{-# LANGUAGE DeriveDataTypeable, FlexibleInstances, MultiParamTypeClasses, PatternGuards, TypeSynonymInstances #-}
-----------------------------------------------------------------------------
-- |
@@ -8,7 +7,7 @@
-- David Roundy <droundy@darcs.net>,
-- Andrea Rossato <andrea.rossato@unibz.it>
-- License : BSD3-style (see LICENSE)
--
--
-- Maintainer : Andrea Rossato <andrea.rossato@unibz.it>
-- Stability : unstable
-- Portability : unportable
@@ -30,7 +29,7 @@ module XMonad.Layout.DragPane (
import XMonad
import Data.Unique
import qualified XMonad.StackSet as W
import qualified XMonad.StackSet as W
import XMonad.Util.Invisible
import XMonad.Util.XUtils
@@ -41,8 +40,8 @@ import XMonad.Util.XUtils
--
-- Then edit your @layoutHook@ by adding the DragPane layout:
--
-- > myLayouts = dragPane Horizontal 0.1 0.5 ||| Full ||| etc..
-- > main = xmonad defaultConfig { layoutHook = myLayouts }
-- > myLayout = dragPane Horizontal 0.1 0.5 ||| Full ||| etc..
-- > main = xmonad defaultConfig { layoutHook = myLayout }
--
-- For more detailed instructions on editing the layoutHook see:
--
@@ -57,8 +56,8 @@ handleColor = "#000000"
dragPane :: DragType -> Double -> Double -> DragPane a
dragPane t x y = DragPane (I Nothing) t x y
data DragPane a =
DragPane (Invisible Maybe (Window,Rectangle,Int)) DragType Double Double
data DragPane a =
DragPane (Invisible Maybe (Window,Rectangle,Int)) DragType Double Double
deriving ( Show, Read )
data DragType = Horizontal | Vertical deriving ( Show, Read )
@@ -87,7 +86,7 @@ handleMess d@(DragPane mb@(I (Just (win,_,ident))) ty delta split) x
handleMess _ _ = return Nothing
handleEvent :: DragPane a -> Event -> X ()
handleEvent (DragPane (I (Just (win,r,ident))) ty _ _)
handleEvent (DragPane (I (Just (win,r,ident))) ty _ _)
(ButtonEvent {ev_window = thisw, ev_subwindow = thisbw, ev_event_type = t })
| t == buttonPress && thisw == win || thisbw == win = do
mouseDrag (\ex ey -> do
@@ -115,12 +114,12 @@ doLay mirror (DragPane mw ty delta split) r s = do
[] -> case W.down s of
(next:_) -> [(W.focus s,left),(next,right)]
[] -> [(W.focus s, r)]
if length wrs > 1
if length wrs > 1
then case mw of
I (Just (w,_,ident)) -> do
I (Just (w,_,ident)) -> do
w' <- deleteWindow w >> newDragWin handr
return (wrs, Just $ DragPane (I $ Just (w',r',ident)) ty delta split)
I Nothing -> do
I Nothing -> do
w <- newDragWin handr
i <- io $ newUnique
return (wrs, Just $ DragPane (I $ Just (w,r',hashUnique i)) ty delta split)

View File

@@ -42,8 +42,8 @@ import XMonad.StackSet as W
--
-- Then edit your @layoutHook@ by adding the FixedColumn layout:
--
-- > myLayouts = FixedColumn 20 80 10 ||| Full ||| etc..
-- > main = xmonad defaultConfig { layoutHook = myLayouts }
-- > myLayout = FixedColumn 1 20 80 10 ||| Full ||| etc..
-- > main = xmonad defaultConfig { layoutHook = myLayout }
--
-- For more detailed instructions on editing the layoutHook see:
--

View File

@@ -1,8 +1,4 @@
{-# OPTIONS_GHC -fglasgow-exts #-}
-- for now, use -fglasgow-exts for compatibility with ghc 6.6, which chokes
-- on some of the LANGUAGE pragmas below
{- LANGUAGE FlexibleInstances, MultiParamTypeClasses, DeriveDataTypeable, TypeSynonymInstances -}
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, DeriveDataTypeable, TypeSynonymInstances, PatternGuards #-}
-----------------------------------------------------------------------------
-- |
@@ -32,7 +28,7 @@
module XMonad.Layout.Gaps (
-- * Usage
-- $usage
Direction(..),
Direction2D(..),
GapSpec, gaps, GapMessage(..)
) where
@@ -40,8 +36,8 @@ module XMonad.Layout.Gaps (
import XMonad.Core
import Graphics.X11 (Rectangle(..))
import XMonad.Hooks.ManageDocks (Direction(..))
import XMonad.Layout.LayoutModifier
import XMonad.Util.Types (Direction2D(..))
import Data.List (delete)
@@ -58,10 +54,10 @@ import Data.List (delete)
-- You can additionally add some keybindings to toggle or modify the gaps,
-- for example:
--
-- > , ((modMask x .|. controlMask, xK_g), sendMessage $ ToggleGaps) -- toggle all gaps
-- > , ((modMask x .|. controlMask, xK_t), sendMessage $ ToggleGap U) -- toggle the top gap
-- > , ((modMask x .|. controlMask, xK_w), sendMessage $ IncGap R 5) -- increment the right-hand gap
-- > , ((modMask x .|. controlMask, xK_q), sendMessage $ DecGap R 5) -- decrement the right-hand gap
-- > , ((modm .|. controlMask, xK_g), sendMessage $ ToggleGaps) -- toggle all gaps
-- > , ((modm .|. controlMask, xK_t), sendMessage $ ToggleGap U) -- toggle the top gap
-- > , ((modm .|. controlMask, xK_w), sendMessage $ IncGap R 5) -- increment the right-hand gap
-- > , ((modm .|. controlMask, xK_q), sendMessage $ DecGap R 5) -- decrement the right-hand gap
--
-- If you want complete control over all gaps, you could include
-- something like this in your keybindings, assuming in this case you
@@ -83,19 +79,19 @@ import Data.List (delete)
-- | A manual gap configuration. Each side of the screen on which a
-- gap is enabled is paired with a size in pixels.
type GapSpec = [(Direction,Int)]
type GapSpec = [(Direction2D,Int)]
-- | The gap state. The first component is the configuration (which
-- gaps are allowed, and their current size), the second is the gaps
-- which are currently active.
data Gaps a = Gaps GapSpec [Direction]
data Gaps a = Gaps GapSpec [Direction2D]
deriving (Show, Read)
-- | Messages which can be sent to a gap modifier.
data GapMessage = ToggleGaps -- ^ Toggle all gaps.
| ToggleGap !Direction -- ^ Toggle a single gap.
| IncGap !Int !Direction -- ^ Increase a gap by a certain number of pixels.
| DecGap !Int !Direction -- ^ Decrease a gap.
| ToggleGap !Direction2D -- ^ Toggle a single gap.
| IncGap !Int !Direction2D -- ^ Increase a gap by a certain number of pixels.
| DecGap !Int !Direction2D -- ^ Decrease a gap.
deriving (Typeable)
instance Message GapMessage
@@ -125,16 +121,16 @@ applyGaps gs r = foldr applyGap r (activeGaps gs)
activeGaps :: Gaps a -> GapSpec
activeGaps (Gaps conf cur) = filter ((`elem` cur) . fst) conf
toggleGaps :: GapSpec -> [Direction] -> [Direction]
toggleGaps :: GapSpec -> [Direction2D] -> [Direction2D]
toggleGaps conf [] = map fst conf
toggleGaps _ _ = []
toggleGap :: GapSpec -> [Direction] -> Direction -> [Direction]
toggleGap :: GapSpec -> [Direction2D] -> Direction2D -> [Direction2D]
toggleGap conf cur d | d `elem` cur = delete d cur
| d `elem` (map fst conf) = d:cur
| otherwise = cur
incGap :: GapSpec -> Direction -> Int -> GapSpec
incGap :: GapSpec -> Direction2D -> Int -> GapSpec
incGap gs d i = map (\(dir,j) -> if dir == d then (dir,max (j+i) 0) else (dir,j)) gs
fi :: (Num b, Integral a) => a -> b

View File

@@ -30,14 +30,14 @@ import XMonad.StackSet
--
-- Then edit your @layoutHook@ by adding the Grid layout:
--
-- > myLayouts = Grid ||| Full ||| etc..
-- > main = xmonad defaultConfig { layoutHook = myLayouts }
-- > myLayout = Grid ||| Full ||| etc..
-- > main = xmonad defaultConfig { layoutHook = myLayout }
--
-- You can also specify an aspect ratio for Grid to strive for with the
-- GridRatio constructor. For example, if you want Grid to try to make a grid
-- four windows wide and three windows tall, you could use
--
-- > myLayouts = GridRatio (4/3) ||| etc.
-- > myLayout = GridRatio (4/3) ||| etc.
--
-- For more detailed instructions on editing the layoutHook see:
--

View File

@@ -22,6 +22,8 @@ module XMonad.Layout.GridVariants ( -- * Usage
ChangeMasterGeom(..)
, Grid(..)
, TallGrid(..)
, SplitGrid(..)
, Orientation(..)
) where
import Control.Monad
@@ -31,7 +33,7 @@ import qualified XMonad.StackSet as W
-- $usage
-- This module can be used as follows:
--
-- > import XMonad.Layout.Master
-- > import XMonad.Layout.GridVariants
--
-- Then add something like this to your layouts:
--
@@ -39,20 +41,20 @@ import qualified XMonad.StackSet as W
--
-- for a 16:10 aspect ratio grid, or
--
-- > TallGrid 2 3 (2/3) (16/10) (5/100)
-- > SplitGrid L 2 3 (2/3) (16/10) (5/100)
--
-- for a layout with a 2x3 master grid that uses 2/3 of the screen,
-- and a 16:10 aspect ratio slave grid. The last parameter is again
-- the percentage by which the split between master and slave area
-- changes in response to Expand/Shrink messages.
-- and a 16:10 aspect ratio slave grid to its right. The last
-- parameter is again the percentage by which the split between master
-- and slave area changes in response to Expand/Shrink messages.
--
-- To be able to change the geometry of the master grid, add something
-- like this to your keybindings:
--
-- > ((modMask .|. shiftMask, xK_equal), sendMessage $ IncMasterCols 1),
-- > ((modMask .|. shiftMask, xK_minus), sendMessage $ IncMasterCols (-1)),
-- > ((modMask .|. ctrlMask, xK_equal), sendMessage $ IncMasterRows 1),
-- > ((modMask .|. ctrlMask, xK_minus), sendMessage $ IncMasterRows (-1))
-- > ((modm .|. shiftMask, xK_equal), sendMessage $ IncMasterCols 1),
-- > ((modm .|. shiftMask, xK_minus), sendMessage $ IncMasterCols (-1)),
-- > ((modm .|. controlMask, xK_equal), sendMessage $ IncMasterRows 1),
-- > ((modm .|. controlMask, xK_minus), sendMessage $ IncMasterRows (-1))
-- | Grid layout. The parameter is the desired x:y aspect ratio of windows
data Grid a = Grid !Rational
@@ -68,29 +70,35 @@ instance LayoutClass Grid a where
description _ = "Grid"
-- | TallGrid layout. Parameters are
-- | SplitGrid layout. Parameters are
--
-- - side where the master is
-- - number of master rows
-- - number of master columns
-- - portion of screen used for master grid
-- - x:y aspect ratio of slave windows
-- - increment for resize messages
data TallGrid a = TallGrid !Int !Int !Rational !Rational !Rational
deriving (Read, Show)
data SplitGrid a = SplitGrid Orientation !Int !Int !Rational !Rational !Rational
deriving (Read, Show)
instance LayoutClass TallGrid a where
-- | Type to specify the side of the screen that holds
-- the master area of a SplitGrid.
data Orientation = T | B | L | R
deriving (Eq, Read, Show)
pureLayout (TallGrid mrows mcols mfrac saspect _) rect st = zip wins rects
instance LayoutClass SplitGrid a where
pureLayout (SplitGrid o mrows mcols mfrac saspect _) rect st = zip wins rects
where
wins = W.integrate st
nwins = length wins
rects = arrangeTallGrid rect nwins mrows mcols mfrac saspect
rects = arrangeSplitGrid rect o nwins mrows mcols mfrac saspect
pureMessage layout msg =
msum [ fmap (resizeMaster layout) (fromMessage msg)
, fmap (changeMasterGrid layout) (fromMessage msg) ]
description _ = "TallGrid"
description _ = "SplitGrid"
-- |The geometry change message understood by the master grid
data ChangeMasterGeom
@@ -100,19 +108,25 @@ data ChangeMasterGeom
instance Message ChangeMasterGeom
arrangeTallGrid :: Rectangle -> Int -> Int -> Int -> Rational -> Rational -> [Rectangle]
arrangeTallGrid rect@(Rectangle rx ry rw rh) nwins mrows mcols mfrac saspect
arrangeSplitGrid :: Rectangle -> Orientation -> Int -> Int -> Int -> Rational -> Rational -> [Rectangle]
arrangeSplitGrid rect@(Rectangle rx ry rw rh) o nwins mrows mcols mfrac saspect
| nwins <= mwins = arrangeMasterGrid rect nwins mcols
| mwins == 0 = arrangeAspectGrid rect nwins saspect
| otherwise = (arrangeMasterGrid mrect mwins mcols) ++
(arrangeAspectGrid srect swins saspect)
where
mwins = mrows * mcols
swins = nwins - mwins
mrect = Rectangle rx ry rw mh
srect = Rectangle rx (fromIntegral ry + fromIntegral mh) rw sh
mh = ceiling (fromIntegral rh * mfrac)
sh = rh - mh
mwins = mrows * mcols
swins = nwins - mwins
mrect = Rectangle mx my mw mh
srect = Rectangle sx sy sw sh
(mh, sh, mw, sw) = if o `elem` [T, B] then
(ceiling (fromIntegral rh * mfrac), rh - mh, rw, rw)
else
(rh, rh, ceiling (fromIntegral rw * mfrac), rw - mw)
mx = fromIntegral rx + if o == R then fromIntegral sw else 0
my = fromIntegral ry + if o == B then fromIntegral sh else 0
sx = fromIntegral rx + if o == L then fromIntegral mw else 0
sy = fromIntegral ry + if o == T then fromIntegral mh else 0
arrangeMasterGrid :: Rectangle -> Int -> Int -> [Rectangle]
arrangeMasterGrid rect nwins mcols = arrangeGrid rect nwins (min nwins mcols)
@@ -121,8 +135,18 @@ arrangeAspectGrid :: Rectangle -> Int -> Rational -> [Rectangle]
arrangeAspectGrid rect@(Rectangle _ _ rw rh) nwins aspect =
arrangeGrid rect nwins (min nwins ncols)
where
ncols = ceiling $ sqrt $ ( fromRational
( (fromIntegral rw * fromIntegral nwins) / (fromIntegral rh * aspect) ) :: Double)
scr_a = fromIntegral rw / fromIntegral rh
fcols = sqrt ( fromRational $ scr_a * fromIntegral nwins / aspect ) :: Double
cols1 = floor fcols :: Int
cols2 = ceiling fcols :: Int
rows1 = ceiling ( fromIntegral nwins / fromIntegral cols1 :: Rational ) :: Int
rows2 = floor ( fromIntegral nwins / fromIntegral cols2 :: Rational ) :: Int
a1 = scr_a * fromIntegral rows1 / fromIntegral cols1
a2 = scr_a * fromIntegral rows2 / fromIntegral cols2
ncols | cols1 == 0 = cols2
| rows2 == 0 = cols1
| a1 / aspect < aspect / a2 = cols1
| otherwise = cols2
arrangeGrid :: Rectangle -> Int -> Int -> [Rectangle]
arrangeGrid (Rectangle rx ry rw rh) nwins ncols =
@@ -153,14 +177,48 @@ splitEvenly n parts = [ sz-off | (sz,off) <- zip sizes offsets]
sizes = [i*size | i <- [1..parts]]
offsets = (take (fromIntegral extra) [1..]) ++ [extra,extra..]
resizeMaster :: TallGrid a -> Resize -> TallGrid a
resizeMaster (TallGrid mrows mcols mfrac saspect delta) Shrink =
TallGrid mrows mcols (max 0 (mfrac - delta)) saspect delta
resizeMaster (TallGrid mrows mcols mfrac saspect delta) Expand =
TallGrid mrows mcols (min 1 (mfrac + delta)) saspect delta
resizeMaster :: SplitGrid a -> Resize -> SplitGrid a
resizeMaster (SplitGrid o mrows mcols mfrac saspect delta) Shrink =
SplitGrid o mrows mcols (max 0 (mfrac - delta)) saspect delta
resizeMaster (SplitGrid o mrows mcols mfrac saspect delta) Expand =
SplitGrid o mrows mcols (min 1 (mfrac + delta)) saspect delta
changeMasterGrid :: TallGrid a -> ChangeMasterGeom -> TallGrid a
changeMasterGrid (TallGrid mrows mcols mfrac saspect delta) (IncMasterRows d) =
TallGrid (max 0 (mrows + d)) mcols mfrac saspect delta
changeMasterGrid (TallGrid mrows mcols mfrac saspect delta) (IncMasterCols d) =
TallGrid mrows (max 0 (mcols + d)) mfrac saspect delta
changeMasterGrid :: SplitGrid a -> ChangeMasterGeom -> SplitGrid a
changeMasterGrid (SplitGrid o mrows mcols mfrac saspect delta) (IncMasterRows d) =
SplitGrid o (max 0 (mrows + d)) mcols mfrac saspect delta
changeMasterGrid (SplitGrid o mrows mcols mfrac saspect delta) (IncMasterCols d) =
SplitGrid o mrows (max 0 (mcols + d)) mfrac saspect delta
-- | TallGrid layout. Parameters are
--
-- - number of master rows
-- - number of master columns
-- - portion of screen used for master grid
-- - x:y aspect ratio of slave windows
-- - increment for resize messages
--
-- This exists mostly because it was introduced in an earlier version.
-- It's a fairly thin wrapper around "SplitGrid L".
data TallGrid a = TallGrid !Int !Int !Rational !Rational !Rational
deriving (Read, Show)
instance LayoutClass TallGrid a where
pureLayout (TallGrid mrows mcols mfrac saspect _) rect st = zip wins rects
where
wins = W.integrate st
nwins = length wins
rects = arrangeSplitGrid rect L nwins mrows mcols mfrac saspect
pureMessage layout msg =
msum [ fmap ((tallGridAdapter resizeMaster) layout) (fromMessage msg)
, fmap ((tallGridAdapter changeMasterGrid) layout) (fromMessage msg) ]
description _ = "TallGrid"
tallGridAdapter :: (SplitGrid a -> b -> SplitGrid a) -> TallGrid a -> b -> TallGrid a
tallGridAdapter f (TallGrid mrows mcols mfrac saspect delta) msg =
TallGrid mrows' mcols' mfrac' saspect' delta'
where
SplitGrid _ mrows' mcols' mfrac' saspect' delta' =
f (SplitGrid L mrows mcols mfrac saspect delta) msg

View File

@@ -41,13 +41,13 @@ infixr 9 .
--
-- Then edit your @layoutHook@ by adding the 'Grid' layout:
--
-- > myLayouts = Grid False ||| Full ||| etc..
-- > main = xmonad defaultConfig { layoutHook = myLayouts }
-- > myLayout = Grid False ||| Full ||| etc..
-- > main = xmonad defaultConfig { layoutHook = myLayout }
--
-- You can also specify an aspect ratio for Grid to strive for with the
-- GridRatio constructor:
--
-- > myLayouts = GridRatio (4/3) False ||| etc.
-- > myLayout = GridRatio (4/3) False ||| etc.
--
-- For more detailed instructions on editing the layoutHook see
-- "XMonad.Doc.Extending#Editing_the_layout_hook".

View File

@@ -10,7 +10,7 @@
-- Stability : unstable
-- Portability : unportable
--
-- Layout modfier suitable for workspace with multi-windowed instant messanger
-- Layout modfier suitable for workspace with multi-windowed instant messenger
-- (like Psi or Tkabber).
--
-----------------------------------------------------------------------------
@@ -45,8 +45,8 @@ import XMonad.Util.WindowProperties
-- for managing your chat windows (Grid in this example, another useful choice
-- to consider is Tabbed layout).
--
-- > myLayouts = withIM (1%7) (ClassName "Tkabber") Grid ||| Full ||| etc..
-- > main = xmonad defaultConfig { layoutHook = myLayouts }
-- > myLayout = withIM (1%7) (ClassName "Tkabber") Grid ||| Full ||| etc..
-- > main = xmonad defaultConfig { layoutHook = myLayout }
--
-- Here @1%7@ is the part of the screen which your roster will occupy,
-- @ClassName \"Tkabber\"@ tells xmonad which window is actually your roster.

View File

@@ -0,0 +1,104 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Layout.IndependentScreens
-- Copyright : (c) 2009 Daniel Wagner
-- License : BSD3
--
-- Maintainer : <daniel@wagner-home.com>
-- Stability : unstable
-- Portability : unportable
--
-- Utility functions for simulating independent sets of workspaces on
-- each screen (like dwm's workspace model), using internal tags to
-- distinguish workspaces associated with each screen.
-----------------------------------------------------------------------------
module XMonad.Layout.IndependentScreens (
-- * Usage
-- $usage
VirtualWorkspace, PhysicalWorkspace,
workspaces',
withScreens, onCurrentScreen,
countScreens,
marshall, unmarshall
) where
-- for the screen stuff
import Control.Arrow hiding ((|||))
import Control.Monad
import Control.Monad.Instances
import Data.List
import Graphics.X11.Xinerama
import XMonad
import XMonad.StackSet hiding (workspaces)
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
--
-- > import XMonad.Layout.IndependentScreens
--
-- You can define your workspaces by calling @withScreens@:
--
-- > myConfig = defaultConfig { workspaces = withScreens 2 ["web", "email", "irc"] }
--
-- This will create \"physical\" workspaces with distinct internal names for
-- each (screen, virtual workspace) pair.
--
-- Then edit any keybindings that use the list of workspaces or refer
-- to specific workspace names. In the default configuration, only
-- the keybindings for changing workspace do this:
--
-- > [((m .|. modm, k), windows $ f i)
-- > | (i, k) <- zip (XMonad.workspaces conf) [xK_1 .. xK_9]
-- > , (f, m) <- [(W.greedyView, 0), (W.shift, shiftMask)]]
--
-- This should change to
--
-- > [((m .|. modm, k), windows $ onCurrentScreen f i)
-- > | (i, k) <- zip (workspaces' conf) [xK_1 .. xK_9]
-- > , (f, m) <- [(W.greedyView, 0), (W.shift, shiftMask)]]
--
-- In particular, the analogue of @XMonad.workspaces@ is
-- @workspaces'@, and you can use @onCurrentScreen@ to convert functions
-- of virtual workspaces to functions of physical workspaces, which work
-- by marshalling the virtual workspace name and the currently focused
-- screen into a physical workspace name.
type VirtualWorkspace = WorkspaceId
type PhysicalWorkspace = WorkspaceId
marshall :: ScreenId -> VirtualWorkspace -> PhysicalWorkspace
marshall (S sc) vws = show sc ++ '_':vws
unmarshall :: PhysicalWorkspace -> (ScreenId, VirtualWorkspace)
unmarshall = ((S . read) *** drop 1) . break (=='_')
-- ^ You shouldn't need to use @marshall@ and @unmarshall@ very much.
-- They simply convert between the physical and virtual worlds. For
-- example, you might want to use them as part of a status bar
-- configuration. The function @snd . unmarshall@ would discard the
-- screen information from an otherwise unsightly workspace name.
workspaces' :: XConfig l -> [VirtualWorkspace]
workspaces' = nub . map (snd . unmarshall) . workspaces
withScreens :: ScreenId -- ^ The number of screens to make workspaces for
-> [VirtualWorkspace] -- ^ The desired virtual workspace names
-> [PhysicalWorkspace] -- ^ A list of all internal physical workspace names
withScreens n vws = [marshall sc pws | pws <- vws, sc <- [0..n-1]]
onCurrentScreen :: (VirtualWorkspace -> WindowSet -> a) -> (PhysicalWorkspace -> WindowSet -> a)
onCurrentScreen f vws = screen . current >>= f . flip marshall vws
-- | In case you don't know statically how many screens there will be, you can call this in main before starting xmonad. For example, part of my config reads
--
-- > main = do
-- > nScreens <- countScreens
-- > xmonad $ defaultConfig {
-- > ...
-- > workspaces = withScreens nScreens (workspaces defaultConfig),
-- > ...
-- > }
--
countScreens :: (MonadIO m, Integral i) => m i
countScreens = liftM genericLength . liftIO $ openDisplay "" >>= getScreenInfo

View File

@@ -0,0 +1,277 @@
{-# LANGUAGE FlexibleContexts, FlexibleInstances, MultiParamTypeClasses, UndecidableInstances, PatternGuards, DeriveDataTypeable #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Layout.LayoutBuilder
-- Copyright : (c) 2009 Anders Engstrom <ankaan@gmail.com>
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : Anders Engstrom <ankaan@gmail.com>
-- Stability : unstable
-- Portability : unportable
--
-- A layout combinator that sends a specified number of windows to one rectangle
-- and the rest to another.
--
-----------------------------------------------------------------------------
module XMonad.Layout.LayoutBuilder (
-- * Usage
-- $usage
layoutN,
layoutR,
layoutAll,
IncLayoutN (..),
SubMeasure (..),
SubBox (..),
absBox,
relBox
) where
import XMonad
import XMonad.Layout
import qualified XMonad.StackSet as W
import Graphics.X11.Xlib
import Data.Maybe (isJust)
import Control.Monad
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
--
-- > import XMonad.Layout.LayoutBuilder
--
-- Then edit your @layoutHook@ by adding something like:
--
-- > myLayout = ( (layoutN 1 (relBox 0 0 0.5 1) (Just $ relBox 0 0 1 1) $ simpleTabbed)
-- > $ (layoutAll (relBox 0.5 0 1 1) $ simpleTabbed)
-- > ) |||
-- > ( (layoutN 1 (relBox (1/3) 0 (1/2) 1) (Just $ relBox 0 0 1 1) $ Tall 0 0.01 0.5)
-- > $ (layoutR 0.1 0.5 (relBox (2/3) 0 1 1) Nothing $ Tall 0 0.01 0.5)
-- > $ (layoutAll (relBox 0 0 (1/3) 1) $ Tall 0 0.01 0.5)
-- > ) |||
-- > ( (layoutN 1 (absBox (-512-200) 0 512 0) (Just $ relBox 0 0 1 1) $ simpleTabbed)
-- > $ (layoutN 1 (absBox (-200) 0 0 0) Nothing $ simpleTabbed)
-- > $ (layoutAll (absBox 0 0 (-512-200) 0) $ simpleTabbed)
-- > ) ||| Full ||| etc...
-- > main = xmonad defaultConfig { layoutHook = myLayout }
--
-- This will produce a layout similar to DragPane, but with the possibility to have multiple windows in the left half
-- and tabs that show the available windows. It will also produce a layout similar to ThreeColMid and a special layout
-- created for use with a 80 columns wide Emacs window, its sidebar and a tabbed area for all other windows.
--
-- This module can be used to create many different custom layouts, but there are limitations. The primary limitation
-- can be observed in the second and third example when there are only two columns with windows in them. The leftmost
-- area is left blank. These blank areas can be avoided by placing the rectangles appropriately.
--
-- These examples require "XMonad.Layout.Tabbed".
--
-- For more detailed instructions on editing the layoutHook see:
--
-- "XMonad.Doc.Extending#Editing_the_layout_hook"
--
-- You may wish to add the following keybindings:
--
-- > , ((modm .|. shiftMask, xK_h ), sendMessage $ IncLayoutN (-1))
-- > , ((modm .|. shiftMask, xK_l ), sendMessage $ IncLayoutN 1)
--
-- For detailed instruction on editing the key binding see:
--
-- "XMonad.Doc.Extending#Editing_key_bindings".
type WindowNum = Either Int (Rational,Rational)
-- | Use one layout in the specified area for a number of windows and possibly let another layout handle the rest.
data LayoutN l1 l2 a =
LayoutN (Maybe a) (Maybe a) WindowNum SubBox (Maybe SubBox) (l1 a) (Maybe (l2 a))
deriving (Show,Read)
-- | Use the specified layout in the described area for N windows and send the rest of the windows to the next layout in the chain.
-- It is possible to supply an alternative area that will then be used instead, if there are no windows to send to the next layout.
layoutN :: (Read a, Eq a, LayoutClass l1 a, LayoutClass l2 a, LayoutClass l3 a) =>
Int -- ^ The number of windows to handle
-> SubBox -- ^ The box to place the windows in
-> Maybe SubBox -- ^ Possibly an alternative box that is used when this layout handles all windows that are left
-> l1 a -- ^ The layout to use in the specified area
-> LayoutN l2 l3 a -- ^ Where to send the remaining windows
-> LayoutN l1 (LayoutN l2 l3) a -- ^ The resulting layout
layoutN num box mbox sub next = LayoutN Nothing Nothing (Left num) box mbox sub (Just next)
-- | As layoutN, but the number of windows is given relative to the total number of windows remaining to be handled. The first
-- argument is how much to change the ratio when using IncLayoutN, and the second is the initial ratio.
layoutR :: (Read a, Eq a, LayoutClass l1 a, LayoutClass l2 a, LayoutClass l3 a) =>
Rational -- ^ How much to change the ratio with each IncLayoutN
-> Rational -- ^ The ratio of the remaining windows to handle
-> SubBox -- ^ The box to place the windows in
-> Maybe SubBox -- ^ Possibly an alternative box that is used when this layout handles all windows that are left
-> l1 a -- ^ The layout to use in the specified area
-> LayoutN l2 l3 a -- ^ Where to send the remaining windows
-> LayoutN l1 (LayoutN l2 l3) a -- ^ The resulting layout
layoutR numdiff num box mbox sub next = LayoutN Nothing Nothing (Right (numdiff,num)) box mbox sub (Just next)
-- | Use the specified layout in the described area for all remaining windows.
layoutAll :: (Read a, Eq a, LayoutClass l1 a) =>
SubBox -- ^ The box to place the windows in
-> l1 a -- ^ The layout to use in the specified area
-> LayoutN l1 Full a -- ^ The resulting layout
layoutAll box sub = LayoutN Nothing Nothing (Right (0,1)) box Nothing sub Nothing
-- | Change the number of windows handled by the focused layout.
data IncLayoutN = IncLayoutN Int deriving Typeable
instance Message IncLayoutN
-- | The absolute or relative measures used to describe the area a layout should be placed in. For negative absolute values
-- the total remaining space will be added. For sizes, the remaining space will also be added for zeroes. Relative values
-- are applied on the remaining space after the top-left corner of the box have been removed.
data SubMeasure = Abs Int | Rel Rational deriving (Show,Read)
-- | A box to place a layout in. The stored values are xpos, ypos, width and height.
data SubBox = SubBox SubMeasure SubMeasure SubMeasure SubMeasure deriving (Show,Read)
-- | Create a box with only absolute measurements. If the values are negative, the total remaining space will be added. For
-- sizes it will also be added for zeroes.
absBox :: Int -- ^ Absolute X-Position
-> Int -- ^ Absolute Y-Position
-> Int -- ^ Absolute width
-> Int -- ^ Absolute height
-> SubBox -- ^ The resulting 'SubBox' describing the area
absBox x y w h = SubBox (Abs x) (Abs y) (Abs w) (Abs h)
-- | Create a box with only relative measurements.
relBox :: Rational -- ^ Relative X-Position with respect to the surrounding area
-> Rational -- ^ Relative Y-Position with respect to the surrounding area
-> Rational -- ^ Relative width with respect to the remaining width
-> Rational -- ^ Relative height with respect to the remaining height
-> SubBox -- ^ The resulting 'SubBox' describing the area
relBox x y w h = SubBox (Rel x) (Rel y) (Rel w) (Rel h)
instance (LayoutClass l1 a, LayoutClass l2 a, Read a, Show a, Eq a, Typeable a) =>
LayoutClass (LayoutN l1 l2) a where
-- | Update window locations.
runLayout (W.Workspace _ (LayoutN subf nextf num box mbox sub next) s) rect
= do let (subs,nexts,subf',nextf') = splitStack s num subf nextf
selBox = if isJust nextf'
then box
else maybe box id mbox
(sublist,sub') <- handle sub subs $ calcArea selBox rect
(nextlist,next') <- case next of Nothing -> return ([],Nothing)
Just n -> do (res,l) <- handle n nexts rect
return (res,Just l)
return (sublist++nextlist, Just $ LayoutN subf' nextf' num box mbox sub' next' )
where
handle l s' r = do (res,ml) <- runLayout (W.Workspace "" l s') r
l' <- return $ maybe l id ml
return (res,l')
-- | Propagate messages.
handleMessage l m
| Just (IncLayoutN _) <- fromMessage m = windowNum l m
| Just (IncMasterN _) <- fromMessage m = sendFocus l m
| Just (Shrink) <- fromMessage m = sendFocus l m
| Just (Expand) <- fromMessage m = sendFocus l m
| otherwise = sendBoth l m
-- | Descriptive name for layout.
description (LayoutN _ _ _ _ _ sub Nothing) = "layoutAll "++ description sub
description (LayoutN _ _ (Left _) _ _ sub (Just next)) = "layoutN "++ description sub ++" "++ description next
description (LayoutN _ _ (Right _) _ _ sub (Just next)) = "layoutR "++ description sub ++" "++ description next
windowNum :: (LayoutClass l1 a, LayoutClass l2 a, Read a, Show a, Eq a, Typeable a) => LayoutN l1 l2 a -> SomeMessage -> X (Maybe (LayoutN l1 l2 a))
windowNum l@(LayoutN subf nextf num box mbox subl nextl) m | (Just (IncLayoutN n)) <- fromMessage m =
do foc <- isFocus subf
if foc then do let newnum = case num of
(Left oldnum) -> Left $ max 1 $ oldnum + n
(Right (diff,oldnum)) -> Right (diff, min 1 $ max 0 $ oldnum + (fromIntegral n)*diff)
return $ Just $ LayoutN subf nextf newnum box mbox subl nextl
else sendNext l m
windowNum l m = sendNext l m
sendSub :: (LayoutClass l1 a, LayoutClass l2 a, Read a, Show a, Eq a, Typeable a) => LayoutN l1 l2 a -> SomeMessage -> X (Maybe (LayoutN l1 l2 a))
sendSub (LayoutN subf nextf num box mbox sub next) m =
do sub' <- handleMessage sub m
return $ if isJust sub'
then Just $ LayoutN subf nextf num box mbox (maybe sub id sub') next
else Nothing
sendBoth :: (LayoutClass l1 a, LayoutClass l2 a, Read a, Show a, Eq a, Typeable a) => LayoutN l1 l2 a -> SomeMessage -> X (Maybe (LayoutN l1 l2 a))
sendBoth l@(LayoutN _ _ _ _ _ _ Nothing) m = sendSub l m
sendBoth (LayoutN subf nextf num box mbox sub (Just next)) m =
do sub' <- handleMessage sub m
next' <- handleMessage next m
return $ if isJust sub' || isJust next'
then Just $ LayoutN subf nextf num box mbox (maybe sub id sub') (Just $ maybe next id next')
else Nothing
sendNext :: (LayoutClass l1 a, LayoutClass l2 a, Read a, Show a, Eq a, Typeable a) => LayoutN l1 l2 a -> SomeMessage -> X (Maybe (LayoutN l1 l2 a))
sendNext (LayoutN _ _ _ _ _ _ Nothing) _ = return Nothing
sendNext (LayoutN subf nextf num box mbox sub (Just next)) m =
do next' <- handleMessage next m
return $ if isJust next'
then Just $ LayoutN subf nextf num box mbox sub next'
else Nothing
sendFocus :: (LayoutClass l1 a, LayoutClass l2 a, Read a, Show a, Eq a, Typeable a) => LayoutN l1 l2 a -> SomeMessage -> X (Maybe (LayoutN l1 l2 a))
sendFocus l@(LayoutN subf _ _ _ _ _ _) m = do foc <- isFocus subf
if foc then sendSub l m
else sendNext l m
isFocus :: (Show a) => Maybe a -> X Bool
isFocus Nothing = return False
isFocus (Just w) = do ms <- (W.stack . W.workspace . W.current) `fmap` gets windowset
return $ maybe False (\s -> show w == (show $ W.focus s)) ms
calcNum :: Int -> WindowNum -> Int
calcNum tot num = max 1 $ case num of Left i -> i
Right (_,r) -> ceiling $ r * fromIntegral tot
splitStack :: Eq a => Maybe (W.Stack a) -> WindowNum -> Maybe a -> Maybe a -> (Maybe (W.Stack a),Maybe (W.Stack a),Maybe a,Maybe a)
splitStack Nothing _ _ _ = (Nothing,Nothing,Nothing,Nothing)
splitStack (Just s) num subf nextf = ( differentiate' subf' subl
, differentiate' nextf' nextl
, subf'
, nextf'
)
where
ws = W.integrate s
n = calcNum (length ws) num
subl = take n ws
nextl = drop n ws
subf' = foc subl subf
nextf' = foc nextl nextf
foc [] _ = Nothing
foc l f = if W.focus s `elem` l
then Just $ W.focus s
else if maybe False (`elem` l) f
then f
else Just $ head l
calcArea :: SubBox -> Rectangle -> Rectangle
calcArea (SubBox xpos ypos width height) rect = Rectangle (rect_x rect + fromIntegral xpos') (rect_y rect + fromIntegral ypos') width' height'
where
xpos' = calc False xpos $ rect_width rect
ypos' = calc False ypos $ rect_height rect
width' = calc True width $ rect_width rect - xpos'
height' = calc True height $ rect_height rect - ypos'
calc zneg val tot = fromIntegral $ min (fromIntegral tot) $ max 0 $
case val of Rel v -> floor $ v * fromIntegral tot
Abs v -> if v<0 || (zneg && v==0)
then (fromIntegral tot)+v
else v
differentiate' :: Eq q => Maybe q -> [q] -> Maybe (W.Stack q)
differentiate' _ [] = Nothing
differentiate' Nothing w = W.differentiate w
differentiate' (Just f) w
| f `elem` w = Just $ W.Stack { W.focus = f
, W.up = reverse $ takeWhile (/=f) w
, W.down = tail $ dropWhile (/=f) w
}
| otherwise = W.differentiate w

View File

@@ -1,5 +1,4 @@
{-# OPTIONS_GHC -fglasgow-exts #-} -- For deriving Data/Typeable
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, PatternGuards #-}
{-# LANGUAGE DeriveDataTypeable, FlexibleInstances, MultiParamTypeClasses, PatternGuards #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Layout.LayoutCombinators
@@ -47,7 +46,7 @@ module XMonad.Layout.LayoutCombinators
-- * New layout choice combinator and 'JumpToLayout'
-- $jtl
, (|||)
, JumpToLayout(JumpToLayout)
, JumpToLayout(..)
) where
import Data.Maybe ( isJust, isNothing )
@@ -65,8 +64,8 @@ import XMonad.Layout.DragPane
-- Then edit your @layoutHook@ to use the new layout combinators. For
-- example:
--
-- > myLayouts = (Tall 1 (3/100) (1/2) *//* Full) ||| (Tall 1 (3/100) (1/2) ***||** Full) ||| Full ||| etc..
-- > main = xmonad defaultConfig { layoutHook = myLayouts }
-- > myLayout = (Tall 1 (3/100) (1/2) *//* Full) ||| (Tall 1 (3/100) (1/2) ***||** Full) ||| Full ||| etc..
-- > main = xmonad defaultConfig { layoutHook = myLayout }
--
-- For more detailed instructions on editing the @layoutHook@ see:
--
@@ -79,7 +78,7 @@ import XMonad.Layout.DragPane
--
-- Then bind some keys to a 'JumpToLayout' message:
--
-- > , ((modMask x .|. controlMask, xK_f), sendMessage $ JumpToLayout "Full") -- jump directly to the Full layout
-- > , ((modm .|. controlMask, xK_f), sendMessage $ JumpToLayout "Full") -- jump directly to the Full layout
--
-- See below for more detailed documentation.
@@ -214,12 +213,12 @@ infixr 5 |||
data NewSelect l1 l2 a = NewSelect Bool (l1 a) (l2 a) deriving ( Read, Show )
data NoWrap = NextLayoutNoWrap | Wrap deriving ( Read, Show, Typeable )
instance Message NoWrap
-- | A message to jump to a particular layout, specified by its
-- description string.
data JumpToLayout = JumpToLayout String deriving ( Read, Show, Typeable )
-- |
data JumpToLayout = JumpToLayout String -- ^ A message to jump to a particular layout
-- , specified by its description string..
| NextLayoutNoWrap
| Wrap
deriving ( Read, Show, Typeable )
instance Message JumpToLayout
instance (LayoutClass l1 a, LayoutClass l2 a) => LayoutClass (NewSelect l1 l2) a where

View File

@@ -1,5 +1,5 @@
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, TypeSynonymInstances #-}
{-# LANGUAGE ParallelListComp, PatternGuards #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Layout.LayoutHints
@@ -8,7 +8,7 @@
--
-- Maintainer : none
-- Stability : unstable
-- Portability : portable
-- Portability : unportable
--
-- Make layouts respect size hints.
-----------------------------------------------------------------------------
@@ -17,41 +17,221 @@ module XMonad.Layout.LayoutHints
( -- * usage
-- $usage
layoutHints
, layoutHintsWithPlacement
, layoutHintsToCenter
, LayoutHints
) where
) where
import XMonad hiding ( trace )
import XMonad.Layout.LayoutModifier
import XMonad.Layout.Decoration ( isInStack )
import XMonad(LayoutClass(runLayout), mkAdjust, Window,
Dimension, Position, Rectangle(Rectangle),D)
import qualified XMonad.StackSet as W
import XMonad.Layout.Decoration(isInStack)
import XMonad.Layout.LayoutModifier(ModifiedLayout(..),
LayoutModifier(modifyLayout, redoLayout, modifierDescription))
import XMonad.Util.Types(Direction2D(..))
import Control.Applicative((<$>))
import Control.Arrow(Arrow((***), first, second))
import Control.Monad(Monad(return), mapM, join)
import Data.Function(on)
import Data.List(sortBy)
import Data.Set (Set)
import qualified Data.Set as Set
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
--
-- > import XMonad.Layout.LayoutHints
--
-- Then edit your @layoutHook@ by adding the LayoutHints layout modifier
-- Then edit your @layoutHook@ by adding the 'layoutHints' layout modifier
-- to some layout:
--
-- > myLayouts = layoutHints (Tall 1 (3/100) (1/2)) ||| Full ||| etc..
-- > main = xmonad defaultConfig { layoutHook = myLayouts }
-- > myLayout = layoutHints (Tall 1 (3/100) (1/2)) ||| Full ||| etc..
-- > main = xmonad defaultConfig { layoutHook = myLayout }
--
-- Or, to center the adapted window in its available area:
--
-- > myLayout = layoutHintsWithPlacement (0.5, 0.5) (Tall 1 (3/100) (1/2))
-- > ||| Full ||| etc..
--
-- Or, to make a reasonable attempt to eliminate gaps between windows:
--
-- > myLayout = layoutHintsToCenter (Tall 1 (3/100) (1/2))
--
-- For more detailed instructions on editing the layoutHook see:
--
-- "XMonad.Doc.Extending#Editing_the_layout_hook"
layoutHints :: (LayoutClass l a) => l a -> ModifiedLayout LayoutHints l a
layoutHints = ModifiedLayout LayoutHints
layoutHints = ModifiedLayout (LayoutHints (0, 0))
data LayoutHints a = LayoutHints deriving (Read, Show)
-- | @layoutHintsWithPlacement (rx, ry) layout@ will adapt the sizes of a layout's
-- windows according to their size hints, and position them inside their
-- originally assigned area according to the @rx@ and @ry@ parameters.
-- (0, 0) places the window at the top left, (1, 0) at the top right, (0.5, 0.5)
-- at the center, etc.
layoutHintsWithPlacement :: (LayoutClass l a) => (Double, Double)
-> l a -> ModifiedLayout LayoutHints l a
layoutHintsWithPlacement rs = ModifiedLayout (LayoutHints rs)
-- | @layoutHintsToCenter layout@ applies hints, sliding the window to the
-- center of the screen and expanding its neighbors to fill the gaps. Windows
-- are never expanded in a way that increases overlap.
--
-- @layoutHintsToCenter@ only makes one pass at resizing the neighbors of
-- hinted windows, so with some layouts (ex. the arrangement with two 'Mirror'
-- 'Tall' stacked vertically), @layoutHintsToCenter@ may leave some gaps.
-- Simple layouts like 'Tall' are unaffected.
layoutHintsToCenter :: (LayoutClass l a) => l a -> ModifiedLayout LayoutHintsToCenter l a
layoutHintsToCenter = ModifiedLayout LayoutHintsToCenter
data LayoutHints a = LayoutHints (Double, Double)
deriving (Read, Show)
instance LayoutModifier LayoutHints Window where
modifierDescription _ = "Hinted"
redoLayout _ _ Nothing xs = return (xs, Nothing)
redoLayout _ _ (Just s) xs = do
xs' <- mapM applyHint xs
return (xs', Nothing)
redoLayout (LayoutHints al) _ (Just s) xs
= do xs' <- mapM (\x@(_, r) -> second (placeRectangle al r) <$> applyHint x) xs
return (xs', Nothing)
where
applyHint (w,r@(Rectangle a b c d)) = do
adj <- mkAdjust w
let (c',d') = adj (c,d)
return (w, if isInStack s w then Rectangle a b c' d' else r)
-- | @placeRectangle (rx, ry) r0 r@ will return a new rectangle with the same dimensions
-- as @r@, but positioned inside of @r0@ as specified by the (rx, ry) parameters (see
-- 'layoutHintsWithPlacement').
placeRectangle :: RealFrac r => (r, r) -> Rectangle -> Rectangle -> Rectangle
placeRectangle (rx, ry) (Rectangle x0 y0 w h) (Rectangle _ _ dx dy)
= Rectangle (align x0 dx w rx) (align y0 dy h ry) dx dy
where align :: RealFrac r => Position -> Dimension -> Dimension -> r -> Position
align z0 dz d r = z0 + truncate (fromIntegral (d - dz) * r)
fitting :: [Rectangle] -> Int
fitting rects = sum $ do
r <- rects
return $ length $ filter (touching r) rects
applyOrder :: Rectangle -> [((Window, Rectangle),t)] -> [[((Window, Rectangle),t)]]
applyOrder root wrs = do
-- perhaps it would just be better to take all permutations, or apply the
-- resizing multiple times
f <- [maximum, minimum, sum, sum . map sq]
return $ sortBy (compare `on` (f . distance)) wrs
where distFC = uncurry ((+) `on` sq) . pairWise (-) (center root)
distance = map distFC . corners . snd . fst
pairWise f (a,b) (c,d) = (f a c, f b d)
sq = join (*)
data LayoutHintsToCenter a = LayoutHintsToCenter deriving (Read, Show)
instance LayoutModifier LayoutHintsToCenter Window where
modifyLayout _ ws@(W.Workspace _ _ Nothing) r = runLayout ws r
modifyLayout _ ws@(W.Workspace _ _ (Just st)) r = do
(arrs,ol) <- runLayout ws r
flip (,) ol
. head . reverse . sortBy (compare `on` (fitting . map snd))
. map (applyHints st r) . applyOrder r
<$> mapM (\x -> fmap ((,) x) $ mkAdjust (fst x)) arrs
-- apply hints to first, grow adjacent windows
applyHints :: W.Stack Window -> Rectangle -> [((Window, Rectangle),(D -> D))] -> [(Window, Rectangle)]
applyHints _ _ [] = []
applyHints s root (((w,lrect@(Rectangle a b c d)),adj):xs) =
let (c',d') = adj (c,d)
redr = placeRectangle (centerPlacement root lrect :: (Double,Double)) lrect
$ if isInStack s w then Rectangle a b c' d' else lrect
ds = (fromIntegral c - fromIntegral c',fromIntegral d - fromIntegral d')
growOther' r = growOther ds lrect (freeDirs root lrect) r
mapSnd f = map (first $ second f)
next = applyHints s root $ mapSnd growOther' xs
in (w,redr):next
growOther :: (Position, Position) -> Rectangle -> Set Direction2D -> Rectangle -> Rectangle
growOther ds lrect fds r
| dirs <- flipDir <$> Set.toList (Set.intersection adj fds)
, not $ any (uncurry opposite) $ cross dirs =
foldr (flip grow ds) r dirs
| otherwise = r
where
adj = adjacent lrect r
cross xs = [ (a,b) | a <- xs, b <- xs ]
flipDir :: Direction2D -> Direction2D
flipDir d = case d of { L -> R; U -> D; R -> L; D -> U }
opposite :: Direction2D -> Direction2D -> Bool
opposite x y = flipDir x == y
-- | Leave the opposite edges where they were
grow :: Direction2D -> (Position,Position) -> Rectangle -> Rectangle
grow L (px,_ ) (Rectangle x y w h) = Rectangle (x-px) y (w+fromIntegral px) h
grow U (_ ,py) (Rectangle x y w h) = Rectangle x (y-py) w (h+fromIntegral py)
grow R (px,_ ) (Rectangle x y w h) = Rectangle x y (w+fromIntegral px) h
grow D (_ ,py) (Rectangle x y w h) = Rectangle x y w (h+fromIntegral py)
comparingEdges :: ([Position] -> [Position] -> Bool) -> Rectangle -> Rectangle -> Set Direction2D
comparingEdges surrounds r1 r2 = Set.fromList $ map fst $ filter snd [ (\k -> (dir,k)) $
any and [[dir `elem` [R,L], allEq [a,c,w,y], [b,d] `surrounds` [x,z]]
,[dir `elem` [U,D], allEq [b,d,x,z], [a,c] `surrounds` [w,y]]]
| ((a,b),(c,d)) <- edge $ corners r1
| ((w,x),(y,z)) <- edge $ delay 2 $ corners r2
| dir <- [U,R,D,L]]
where edge (x:xs) = zip (x:xs) (xs ++ [x])
edge [] = []
delay n xs = drop n xs ++ take n xs
allEq = all (uncurry (==)) . edge
-- | in what direction is the second window from the first that can expand if the
-- first is shrunk, assuming that the root window is fully covered:
-- one direction for a common edge
-- two directions for a common corner
adjacent :: Rectangle -> Rectangle -> Set Direction2D
adjacent = comparingEdges (all . onClosedInterval)
-- | True whenever two edges touch. not (Set.null $ adjacent x y) ==> touching x y
touching :: Rectangle -> Rectangle -> Bool
touching a b = not . Set.null $ comparingEdges c a b
where c x y = any (onClosedInterval x) y || any (onClosedInterval y) x
onClosedInterval :: Ord a => [a] -> a -> Bool
onClosedInterval bds x = minimum bds <= x && maximum bds >= x
-- | starting top left going clockwise
corners :: Rectangle -> [(Position, Position)]
corners (Rectangle x y w h) = [(x,y)
,(x+fromIntegral w, y)
,(x+fromIntegral w, y+fromIntegral h)
,(x, y+fromIntegral h)]
center :: Rectangle -> (Position, Position)
center (Rectangle x y w h) = (avg x w, avg y h)
where avg a b = a + fromIntegral b `div` 2
centerPlacement :: RealFrac r => Rectangle -> Rectangle -> (r, r)
centerPlacement = centerPlacement' clamp
where clamp n = case signum n of
0 -> 0.5
1 -> 1
_ -> 0
freeDirs :: Rectangle -> Rectangle -> Set Direction2D
freeDirs root = Set.fromList . uncurry (++) . (lr *** ud)
. centerPlacement' signum root
where
lr 1 = [L]
lr (-1) = [R]
lr _ = [L,R]
ud 1 = [U]
ud (-1) = [D]
ud _ = [U,D]
centerPlacement' :: (Position -> r) -> Rectangle -> Rectangle -> (r, r)
centerPlacement' cf root assigned
= (cf $ cx - cwx, cf $ cy - cwy)
where (cx,cy) = center root
(cwx,cwy) = center assigned

View File

@@ -1,5 +1,4 @@
{-# OPTIONS_GHC -fglasgow-exts #-} -- For deriving Data/Typeable
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, PatternGuards #-}
{-# LANGUAGE DeriveDataTypeable, FlexibleInstances, MultiParamTypeClasses, PatternGuards #-}
-----------------------------------------------------------------------------
-- |

View File

@@ -10,6 +10,7 @@
-- Stability : unstable
-- Portability : unportable
--
-- Divide a single screen into multiple screens.
-----------------------------------------------------------------------------
module XMonad.Layout.LayoutScreens (
@@ -38,8 +39,8 @@ import qualified XMonad.StackSet as W
--
-- Then add some keybindings; for example:
--
-- > , ((modMask x .|. shiftMask, xK_space), layoutScreens 2 (TwoPane 0.5 0.5))
-- > , ((modMask x .|. controlMask .|. shiftMask, xK_space), rescreen)
-- > , ((modm .|. shiftMask, xK_space), layoutScreens 2 (TwoPane 0.5 0.5))
-- > , ((modm .|. controlMask .|. shiftMask, xK_space), rescreen)
--
-- Another example use would be to handle a scenario where xrandr didn't
-- work properly (e.g. a VNC X server in my case) and you want to be able
@@ -47,9 +48,9 @@ import qualified XMonad.StackSet as W
--
-- > import XMonad.Layout.LayoutScreens
--
-- > , ((modMask x .|. shiftMask, xK_space),
-- > , ((modm .|. shiftMask, xK_space),
-- > layoutScreens 1 (fixedLayout [Rectangle 0 0 1024 768]))
-- > , ((modMask x .|. controlMask .|. shiftMask, xK_space), rescreen)
-- > , ((modm .|. controlMask .|. shiftMask, xK_space), rescreen)
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".

View File

@@ -0,0 +1,160 @@
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, DeriveDataTypeable, PatternGuards #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Layout.LimitWindows
-- Copyright : (c) 2009 Adam Vogt
-- (c) 2009 Max Rabkin -- wrote limitSelect
-- License : BSD-style (see xmonad/LICENSE)
--
-- Maintainer : vogt.adam@gmail.com
-- Stability : unstable
-- Portability : unportable
--
-- A layout modifier that limits the number of windows that can be shown.
-- See "XMonad.Layout.Minimize" for manually setting hidden windows.
--
-----------------------------------------------------------------------------
module XMonad.Layout.LimitWindows (
-- * Usage
-- $usage
-- * Layout Modifiers
limitWindows,limitSlice,limitSelect,
-- * Change the number of windows
increaseLimit,decreaseLimit,setLimit
) where
import XMonad.Layout.LayoutModifier
import XMonad
import qualified XMonad.StackSet as W
import XMonad.Layout (IncMasterN (..))
import Control.Monad((<=<),guard)
import Control.Applicative((<$>))
import Data.Maybe(fromJust)
-- $usage
-- To use this module, add the following import to @~\/.xmonad\/xmonad.hs@:
--
-- > import XMonad.Layout.LimitWindows
--
-- > myLayout = limitWindows 6 $ Tall 1 0.03 0.5 ||| Full ||| RandomOtherLayout...
-- > main = xmonad defaultConfig { layoutHook = myLayout }
--
-- You may also be interested in dynamically changing the number dynamically,
-- by binding keys to the 'increaseLimit', 'decreaseLimit', or 'setLimit'
-- actions.
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
--
-- See also 'XMonad.Layout.BoringWindows.boringAuto' for keybindings that skip
-- the hidden windows.
increaseLimit :: X ()
increaseLimit = sendMessage $ LimitChange succ
decreaseLimit :: X ()
decreaseLimit = sendMessage . LimitChange $ max 1 . pred
setLimit :: Int -> X ()
setLimit tgt = sendMessage . LimitChange $ const tgt
-- | Only display the first @n@ windows.
limitWindows :: Int -> l a -> ModifiedLayout LimitWindows l a
limitWindows n = ModifiedLayout (LimitWindows FirstN n)
-- | Only display @n@ windows around the focused window. This makes sense with
-- layouts that arrange windows linearily, like 'XMonad.Layout.Layout.Accordion'.
limitSlice :: Int -> l a -> ModifiedLayout LimitWindows l a
limitSlice n = ModifiedLayout (LimitWindows Slice n)
-- | Only display the first @m@ windows and @r@ others.
-- The @IncMasterN@ message will change @m@, as well as passing it onto the
-- underlying layout.
limitSelect :: Int -> Int -> l a -> ModifiedLayout Selection l a
limitSelect m r = ModifiedLayout Sel{ nMaster=m, start=m, nRest=r }
data LimitWindows a = LimitWindows SliceStyle Int deriving (Read,Show)
data SliceStyle = FirstN | Slice deriving (Read,Show)
data LimitChange = LimitChange { unLC :: (Int -> Int) } deriving (Typeable)
instance Message LimitChange
instance LayoutModifier LimitWindows a where
pureMess (LimitWindows s n) =
fmap (LimitWindows s) . pos <=< (`app` n) . unLC <=< fromMessage
where pos x = guard (x>=1) >> return x
app f x = guard (f x /= x) >> return (f x)
modifyLayout (LimitWindows style n) ws r =
runLayout ws { W.stack = f n <$> W.stack ws } r
where f = case style of
FirstN -> firstN
Slice -> slice
firstN :: Int -> W.Stack a -> W.Stack a
firstN n st = upfocus $ fromJust $ W.differentiate $ take (max 1 n) $ W.integrate st
where upfocus = foldr (.) id $ replicate (length (W.up st)) W.focusDown'
-- | A non-wrapping, fixed-size slice of a stack around the focused element
slice :: Int -> W.Stack t -> W.Stack t
slice n (W.Stack f u d) =
W.Stack f (take (nu + unusedD) u)
(take (nd + unusedU) d)
where unusedD = max 0 $ nd - length d
unusedU = max 0 $ nu - length u
nd = div (n - 1) 2
nu = uncurry (+) $ divMod (n - 1) 2
data Selection a = Sel { nMaster :: Int, start :: Int, nRest :: Int }
deriving (Read, Show, Eq)
instance LayoutModifier Selection a where
modifyLayout s w r =
runLayout (w { W.stack = updateAndSelect s <$> W.stack w }) r
pureModifier sel _ stk wins = (wins, update sel <$> stk)
pureMess sel m
| Just f <- unLC <$> fromMessage m =
Just $ sel { nRest = max 0 (f (nMaster sel + nRest sel) - nMaster sel) }
| Just (IncMasterN n) <- fromMessage m =
Just $ sel { nMaster = max 0 (nMaster sel + n) }
| otherwise =
Nothing
select :: Selection l -> W.Stack a -> W.Stack a
select s stk
| lups < nMaster s
= stk { W.down=take (nMaster s - lups - 1) downs ++
(take (nRest s) . drop (start s - lups - 1) $ downs) }
| otherwise
= stk { W.up=reverse (take (nMaster s) ups ++ drop (start s) ups),
W.down=take ((nRest s) - (lups - start s) - 1) downs }
where
downs = W.down stk
ups = reverse $ W.up stk
lups = length ups
updateStart :: Selection l -> W.Stack a -> Int
updateStart s stk
| lups < nMaster s -- the focussed window is in the master pane
= start s `min` (lups + ldown - (nRest s) + 1) `max` nMaster s
| otherwise
= start s `min` lups
`max` (lups - (nRest s) + 1)
`min` (lups + ldown - (nRest s) + 1)
`max` nMaster s
where
lups = length $ W.up stk
ldown = length $ W.down stk
update :: Selection l -> W.Stack a -> Selection a
update sel stk = sel { start=updateStart sel stk }
updateAndSelect :: Selection l -> W.Stack a -> W.Stack a
updateAndSelect sel stk = select (update sel stk) stk

View File

@@ -16,13 +16,21 @@
module XMonad.Layout.MagicFocus
(-- * Usage
-- $usage
magicFocus
magicFocus,
promoteWarp,
promoteWarp',
followOnlyIf,
disableFollowOnWS
) where
import XMonad
import XMonad.StackSet
import qualified XMonad.StackSet as W
import XMonad.Layout.LayoutModifier
import XMonad.Actions.UpdatePointer(updatePointer, PointerPosition(TowardsCentre))
import Data.Monoid(All(..))
import qualified Data.Map as M
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
--
@@ -31,8 +39,9 @@ import XMonad.Layout.LayoutModifier
-- Then edit your @layoutHook@ by adding the magicFocus layout
-- modifier:
--
-- > myLayouts = magicFocus (Tall 1 (3/100) (1/2)) ||| Full ||| etc..
-- > main = xmonad defaultConfig { layoutHook = myLayouts }
-- > myLayout = magicFocus (Tall 1 (3/100) (1/2)) ||| Full ||| etc..
-- > main = xmonad defaultConfig { layoutHook = myLayout,
-- > handleEventHook = promoteWarp }
--
-- For more detailed instructions on editing the layoutHook see:
--
@@ -46,10 +55,53 @@ magicFocus = ModifiedLayout MagicFocus
data MagicFocus a = MagicFocus deriving (Show, Read)
instance LayoutModifier MagicFocus Window where
modifyLayout MagicFocus (Workspace i l s) r =
modifyLayout MagicFocus (W.Workspace i l s) r =
withWindowSet $ \wset ->
runLayout (Workspace i l (s >>= \st -> Just $ swap st (peek wset))) r
runLayout (W.Workspace i l (s >>= \st -> Just $ swap st (W.peek wset))) r
swap :: (Eq a) => Stack a -> Maybe a -> Stack a
swap (Stack f u d) focused | Just f == focused = Stack f [] (reverse u ++ d)
| otherwise = Stack f u d
swap :: (Eq a) => W.Stack a -> Maybe a -> W.Stack a
swap (W.Stack f u d) focused
| Just f == focused = W.Stack f [] (reverse u ++ d)
| otherwise = W.Stack f u d
-- | An eventHook that overrides the normal focusFollowsMouse. When the mouse
-- it moved to another window, that window is replaced as the master, and the
-- mouse is warped to inside the new master.
--
-- It prevents infinite loops when focusFollowsMouse is true (the default), and
-- MagicFocus is in use when changing focus with the mouse.
--
-- This eventHook does nothing when there are floating windows on the current
-- workspace.
promoteWarp :: Event -> X All
promoteWarp = promoteWarp' (TowardsCentre 0.15 0.15)
-- | promoteWarp' allows you to specify an arbitrary PointerPosition to apply
-- when the mouse enters another window.
promoteWarp' :: PointerPosition -> Event -> X All
promoteWarp' pos e@(CrossingEvent {ev_window = w, ev_event_type = t})
| t == enterNotify && ev_mode e == notifyNormal = do
ws <- gets windowset
let foc = W.peek ws
st = W.integrate' . W.stack . W.workspace $ W.current ws
wsFloats = M.filterWithKey (\k _ -> k `elem` st) $ W.floating ws
if Just w /= foc && M.null wsFloats then do
windows (W.swapMaster . W.focusWindow w)
updatePointer pos
return $ All False
else return $ All True
promoteWarp' _ _ = return $ All True
-- | Another event hook to override the focusFollowsMouse and make the pointer
-- only follow if a given condition is satisfied. This could be used to disable
-- focusFollowsMouse only for given workspaces or layouts.
-- Beware that your focusFollowsMouse setting is ignored if you use this event hook.
followOnlyIf :: X Bool -> Event -> X All
followOnlyIf cond e@(CrossingEvent {ev_window = w, ev_event_type = t})
| t == enterNotify && ev_mode e == notifyNormal
= whenX cond (focus w) >> return (All False)
followOnlyIf _ _ = return $ All True
-- | Disables focusFollow on the given workspaces:
disableFollowOnWS :: [WorkspaceId] -> X Bool
disableFollowOnWS wses = (`notElem` wses) `fmap` gets (W.currentTag . windowset)

Some files were not shown because too many files have changed in this diff Show More