392 Commits
v0.9 ... v0.11

Author SHA1 Message Date
Adam Vogt
6072d9c599 bump cabal-version to satsify hackage 2013-01-01 01:41:59 +00:00
Adam Vogt
277412af44 bump version to 0.11 2012-12-31 10:42:52 +00:00
Adam Vogt
0030802e46 Add more metadata to cabal file 2012-12-31 18:45:13 +00:00
Adam Vogt
f211874340 X.A.Workscreen make the whole module description show up for haddock 2012-12-31 02:46:00 +00:00
Adam Vogt
32548e056f Note that an alternative to XMonad.Actions.ShowText is X.U.Dzen 2012-12-31 02:30:42 +00:00
Dmitri Iouchtchenko
2c6f1c22b2 Add X.A.DynamicWorkspaces.renameWorkspaceByName. 2012-12-27 06:35:31 +00:00
Adam Vogt
b8a22c4dee Change type of X.A.ShowText.handleTimerEvent so example code typechecks. 2012-12-26 01:38:41 +00:00
Adam Vogt
42443e3df2 Describe arguments for X.A.ShowText.flashText 2012-12-26 01:37:25 +00:00
pastorelli.mario
9e0eb7f770 Add XMonad.Actions.ShowText 2012-12-25 20:26:35 +00:00
Adam Vogt
895c47fb4e Record polachok's fix for issue 507 2012-12-16 18:27:24 +00:00
c.lopez
cc98355700 Removes unused function spawnWithActions and redundant imports in XMonad.Actions.Launcher 2012-12-15 22:37:14 +00:00
Adam Vogt
205e7133ac A.Launcher markup identifiers for haddock links 2012-12-15 16:59:14 +00:00
Adam Vogt
9caedf2fff Address warnings from Debug modules
The warnings were related to ghc-7.6 removing Prelude.catch
(triggering warnings regarding the import hiding it), as well
as defaulting of some numeric types.
2012-12-15 16:55:25 +00:00
c.lopez
265df96ab8 Removes LocateMode and LocateRegexMode from XMonad.Actions.Launcher 2012-12-14 21:12:30 +00:00
allbery.b
8d1ad8b280 debug-hooks
Hooks to print diagnostic information to stderr (usually .xsession-errors)
to help debug complex issues involving the StackSet and received events.
2012-08-13 22:38:21 +00:00
Adam Vogt
de84dfef0d Remove trailing whitespace. 2012-11-09 01:41:56 +00:00
Adam Vogt
3fa51ed656 Use Control.Exception.catch explitly to avoid warnings
The base that comes with ghc-7.6.1 no longer includes Prelude.catch;
so these modules were changed so that there is no warning for

import Prelude hiding (catch)

At the same time these changes should be compatible with older GHCs,
since the catch being has never been the one in the Prelude.
2012-11-09 01:35:06 +00:00
Adam Vogt
a9911d2168 Add missing type signatures.
For whatever reason, some patches applied were missing these signatures.
While haddock has been able to include inferred signatures for a while,
including type signatures makes it easier to see if and when types have
been changed.
2012-11-09 01:27:52 +00:00
Adam Vogt
1716ffd9d0 Rename variables "state" to avoid warnings about shadowing
XMonad core re-exports Control.Monad.State, which includes
a function "state" if you happen to use mtl-2. Since there's
a chance xmonad still works with mtl-1 avoid imports like:

import XMonad hiding (state)
2012-11-09 01:23:16 +00:00
Adam Vogt
e776260133 Rename variable in L.Minimize to avoid shadowing.
This "state" is new with a newer mtl.
2012-11-09 00:34:10 +00:00
Adam Vogt
53c2e7833c Gut H.ICCCMFocus: issue 177 has been merged in core.
Keep the module for now: the LG3D bit might still be useful
and there's no need to break configs unnecessarily.
2012-11-08 22:57:16 +00:00
pastorelli.mario
fbb9eb36f9 ewmh-eventhook-custom
Add ewmhDesktopsEventHookCustom, a generalized version of ewmhDesktopsEventHook that takes a sort function as argument. This sort function should be the same used by the LogHook.
2012-08-16 15:30:32 +00:00
daedalusinfinity
4da5da430e Added smart spacing to the spacing module
Added smart spacing to the spacing module, which adds spacing to all windows,
except to windows on singleton workspaces.
2012-09-23 03:45:27 +00:00
c.lopez
0af63a4767 Improves haddock documentation 2012-08-26 09:17:16 +00:00
c.lopez
7245766c6d Improve comments, add an error throw that shouldn't happen 2012-08-26 08:54:26 +00:00
c.lopez
cd6feb81e2 fix a bug when ncompletions = nrows 2012-08-26 08:31:37 +00:00
c.lopez
8f9fa05c0f Fixes typos in Actions.Launcher haddock documentation 2012-08-11 11:25:02 +00:00
c.lopez
b5f9a61dbe Correctly get the autocompletion item when alwaysHighlight in XMonad.Prompt is True 2012-08-11 10:48:05 +00:00
c.lopez
96ab91fcfa Removes warnings, adds a browser value for LauncherConfig in haddock comments 2012-06-28 11:45:33 +00:00
c.lopez
3c74148a2f Changes on XPrompt:
* Adds mkPromptWithModes, creates a prompt given a list of modes (list of XPType).

    * Adds Setting `alwaysHighlight` to defaultXPConfig. When set to true, autocompletion always highlight the first result if it is not highlighted.
    
Adds module XMonad.Actions.Launcher. This module allows to combine and switch between instances of XPrompt. It includes a default set of modes which require the programs `hoogle`, `locate` and `calc` to be installed to work properly.
2012-06-28 10:17:49 +00:00
Daniel Wagner
9d34e848d9 accept more windows as docks 2012-08-23 12:41:53 +00:00
longpoke
a7c2c023fb strip newlines from dmenu's returns to be compatible with the newest version of dmenu 2012-07-23 21:28:07 +00:00
kedals0
814fda056b A workscreen permits to display a set of workspaces on several
screens. In xinerama mode, when a workscreen is viewed, workspaces
associated to all screens are visible.

The first workspace of a workscreen is displayed on first screen,
second on second screen, etc. Workspace position can be easily
changed. If the current workscreen is called again, workspaces are
shifted.

This also permits to see all workspaces of a workscreen even if just
one screen is present, and to move windows from workspace to workscreen.
2012-07-06 09:33:08 +00:00
Daniel Wagner
2a6709ff5c refer to the new name 'handleEventHook' instead of the old name 'eventHook' in X.L.Fullscreen documentation 2012-06-18 18:10:03 +00:00
gopsychonauts
3ffc956b93 UrgencyHooks made available as Window -> X () functions
Adds an UrgencyHook instance for the type Window -> X (), allowing any such
functions to be used directly as UrgencyHooks. The Show and Read constraints
were removed from the UrgencyHook class in order to permit this; these
constraints were required only in a historical implementation of the module,
which used a layout modifier.

All existing configurations using UrgencyHooks should remain fully functional.
New configs may make use of this modification by declaring their UrgencyHook as
a simple Window -> X () function.
2012-05-04 06:23:39 +00:00
Brent Yorgey
e705eba1e0 updates to XMonad.Prompt re: word-oriented commands
+ change killWord and moveWord to have emacs-like behavior: first move
    past/kill consecutive whitespace, then move past/kill consecutive
    non-whitespace.

  + create variants killWord' and moveWord' which take a predicate
    specifying non-word characters.

  + create variants defaultXPKeymap' and emacsLikeXPKeymap' which take
    the same sort of predicate, which is applied to all keybindings with
    word-oriented commands.
2012-05-10 17:43:17 +00:00
Jesper Reenberg
2f2a217b85 Added isUnfocusedOnCurrentWS and fadeInactiveCurrentWSLogHook for better support of fading/opacity on multi monitor setups 2012-03-29 14:18:18 +00:00
Jesper Reenberg
6f996bb21f Fixed X.A.GridSelect to be consistent in the way it (now) sorts the shown
elements when modifying the searchString.

The implemented ordering sorts based on how "deep the needle is in the
haystack", meaning that searching for "st" in the elements "Install" and "Study"
will order them as "Study" and "Install". Previously there was no ordering and
when using GridSelect to select workspaces, the ordering was not consistent, as
the list of workspaces (if not modified manually) is ordered by last used. In
this case either "Study" or "Install" would come first depending on which
workspace was last visited.
2012-05-01 18:04:15 +00:00
Julia Jomantaite
3a740c4d5a Use getXMonadDir to get the default xmonad directory. 2012-05-01 12:14:27 +00:00
Adam Vogt
f09a61f5f5 Minor haddock formatting for X.L.OnHost and X.A.DynamicWorkspaceOrder 2012-04-28 19:45:52 +00:00
Adam Vogt
1a735f04e3 Remove trailing whitespace. 2012-04-28 19:40:48 +00:00
Carlos Lopez-Camey
d2739b1683 Add emacs-like keys to browse history in XMonad.Prompt 2012-04-21 11:07:37 +00:00
Carlos Lopez-Camey
9ecc76e087 Adds an emacs-like Keymap in XMonad.Prompt 2012-04-21 01:23:35 +00:00
jakob
7b21732ead add 'withNthWorkspace' to DynamicWorkspaceOrder.
Note this is very similar to the function of the same name exported by
DynamicWorkspaces.  Ultimately it would probably be cleaner to
generalize the one in DynamicWorkspaces to accept an arbitrary
workspace sort as a parameter; this is left as an exercise for future
hackers.
2012-04-07 18:46:40 +00:00
allbery.b
c691988bbf XMonad.Layout.OnHost allows host-specific modifications to a layout, which
is otherwise very difficult to do.  Similarly to X.L.PerWorkspace, it provides
onHost, onHosts, modHost, and modHosts layout modifiers.  It attempts to do
smart hostname comparison, such that short names will be matched with short
names and FQDNs with FQDNs.

This module currently requires that $HOST be set in the environment.
You can use System.Posix.Env.setEnv to do so in xmonad.hs if need be.
(Properly, this should be done via the network library, but I'm trying to
avoid adding that dependency.)  An alternative would be to shell out to
get the name, but that has considerable portability hurdles.
2012-03-20 03:09:12 +00:00
Adam Vogt
40d8c01894 Bump version to 0.10.1
Raising the X11 dependency while keeping the xmonad version the same leads to
problems where cabal install uses the dependency versions following hackage,
not what is installed.
2012-03-20 00:53:11 +00:00
Jens Petersen
328293a0a8 narrower BorderResize rectangles placed within border edges
Change the border resize rectangles to be narrower and only extend
  inside the window not outside.  Most window managers just seem to use
  the border decoration area for starting resizes which is often just 1 pixel
  wide but as a compromise the width is now 2 pixels (before it was 10!).
  The rectangles are now placed symmetrically within the border and window.
  This seems to work ok with PositionStoreFloat for the Bluetile config.
2012-03-14 06:47:03 +00:00
Ben Boeckel
434aec1038 add-dynamic-bars-module
This adds the X.H.DynamicBars module. It allows per-screen status bars to be
easily managed and dynamically handles the number of screens changing.
2012-03-16 00:22:04 +00:00
Daniel Wagner
69d2e0a873 bump X11 dependency so that noModMask is available 2012-03-16 00:03:02 +00:00
gwern0
9454dd5d7f Paste.hs: rm noModMask, shifted definition to X11 binding (see previous email) 2011-12-03 20:30:38 +00:00
Jens Petersen
60713064e7 GroupNavigation: fix import typo in usage 2012-03-12 10:33:49 +00:00
Jens Petersen
98b0e8e4c1 add sendToEmptyWorkspace to FindEmptyWorkspace
sendToEmptyWorkspace is like tagToEmptyWorkspace except
it does not change workspace after moving the window.
2012-03-12 10:23:31 +00:00
Jens Petersen
d2a076b1e7 xmonad-contrib.cabal: simplify xmonad dependency to >=0.10 && < 0.11
Unless there is a particular reason for listing the lower and upper bounds
separately then this seems simpler and cleaner.
2012-03-12 10:18:00 +00:00
crodjer
e2bb57bd63 ShowWName: Increase horizontal padding for flash
Currently the flash window width leaves a very small amount of padding. This
patch adds some extra horizontal width, governed by text width and length.
2012-03-05 16:45:17 +00:00
Ben Boeckel
d5e7d6217f persist-togglehook-options
Save the state of ToggleHook options over a restart.
2012-03-11 05:01:43 +00:00
Rohan Jain
4feb4fb058 ShowWName flash window background color
While calling paintAndWrite for flash window, the background color from config
should also be passed on as window background in addition to as text background
color. Otherwise the window color gets set to the default black which shows up
when text cannot span whole of the window.

This issue becomes visible when the font size is considerably large or even in
small size with truetype fonts.
2012-03-06 06:52:24 +00:00
crodjer
3f39d34994 ShowWName: Fix flash location by screen rectangle
In case of using this hook with multiple monitors, the Tag flash was not
following the screen's coordinates. This patch shifts the new window created for
flash according to the Rectangle defined by the screen.
2012-03-05 16:12:40 +00:00
crodjer
7789f18ce9 Fix typo in tabbed layout link for font utils docs 2012-02-29 07:00:22 +00:00
Steffen Schuldenzucker
807d356743 L.WorkspaceDir: cleanup redundant {definitions,imports} 2012-02-29 11:21:24 +00:00
Steffen Schuldenzucker
c012b3408d fix L.WorkspaceDir special char handling: remove "echo -n" processing 2012-02-27 12:20:04 +00:00
allbery.b
f6a050e5a3 Add BorderUrgencyHook to XMonad.Hooks.UrgencyHook
BorderUrgencyHook is a new UrgencyHook usable with withUrgencyHook or
withUrgencyHookC; it allows an urgent window to be given a different
border color.  This may not always work as intended, since UrgencyHook
likes to assume that a window being visible is sufficient to disable
urgency notification; but with suppressWhen = Never it may work well
enough.

There is a report that if a new window is created at the wrong time,
the wrong window may be marked urgent somehow.  I seem to once again
be revealing bugs in underlying packages, although a quick examination
of X.H.UrgencyHook doesn't seem to show any way for the wrong window
to be selected.
2012-02-25 08:26:16 +00:00
nicolas.dudebout
92e8f5ebef Adding use case for namedScratchpad. 2012-01-22 23:58:43 +00:00
gwern0
dd591587f6 Actions.WindowGo: typo fix - trim 's' per cub.uanic https://code.google.com/p/xmonad/issues/detail?id=491 2012-01-16 22:42:44 +00:00
gwern0
219b4dd8fb XMonad.Actions.PhysicalScreens: fix typo spotted by Chris Pick <haskell@chrispick.com> 2012-01-15 22:30:13 +00:00
Daniel Wagner
b944b1129c roll back previous incorrect fix 2012-01-11 21:41:33 +00:00
gwern0
08d432bde6 Extending: fix http://code.google.com/p/xmonad/issues/detail?id=490 2012-01-11 21:19:07 +00:00
Daniel Wagner
04d6cbc5f0 another documentation patch: XMonadContrib.UpdatePointer -> XMonad.Actions.UpdatePointer 2012-01-11 21:12:26 +00:00
Daniel Wagner
9cafb7c2af documentation patch, fixes issue 490 2012-01-11 21:08:32 +00:00
Adam Vogt
272c333f75 X.H.EwmhDesktops note that fullscreenEventHook is not included in ewmh
Just a documentation fix (nomeata's suggestion at issue 339).
2012-01-02 21:14:04 +00:00
Adam Vogt
aa96dd6e03 X.H.EwmhDesktops haddock formatting. 2012-01-02 21:12:03 +00:00
Norbert Zeh
59bfe97f63 X.A.Navigation2D
This is a new module to support directional navigation across multiple screens.
As such it is related to X.A.WindowNavigation and X.L.WindowNavigation, but it
is more general.  For a detailed discussion of the differences, see
http://www.cs.dal.ca/~nzeh/xmonad/Navigation2D.pdf.
2011-12-08 20:58:42 +00:00
Daniel Wagner
64efea4d0a documentation patch: mention PostfixOperators 2011-12-10 23:48:20 +00:00
Adam Vogt
a1a578010c P.Shell documentation and add missing unsafePrompt export
Haddock (version 2.9.2 at least) does not attach documentation to any of a b or
c when given:

    -- | documentation
    a,b,c :: X
2011-12-07 16:39:51 +00:00
gwern0
9209e96234 Paste: 3 more escaped characters from alistra 2011-11-29 16:03:35 +00:00
Daniel Wagner
c809ae6f5f unfuck X.U.Paste 2011-11-29 03:23:31 +00:00
gwern0
9b369949ff XMonad.Util.Paste: +alistra's patch for fixing his pasting of things like email address (@) 2011-11-28 21:56:48 +00:00
gwern0
9e69773d98 XMonad.Util.Paste: rm myself from maintainer field; I don't know how to fix any of it even if I wanted 2011-11-28 21:30:01 +00:00
gwern0
2f0ac73313 XMonad.Prompt.Shell: improve 'env' documentation to cover goodgrue's problem 2011-11-27 23:15:07 +00:00
Erik de Castro Lopo
95290ed278 Fix spelling 'prefered' -> 'preferred'. 2011-11-25 01:02:29 +00:00
Adam Vogt
a551d1367c Restore TrackFloating behavior to an earlier version.
Thanks for liskni_si for pressing the matter: without this change it is very
broken, with the patch it is still not perfect but still useful.
2011-11-20 04:55:38 +00:00
Adam Vogt
cb795c8c75 Explicitly list test files in .cabal
In the future, require Cabal >= 1.6 to be able to just write tests/*.hs
2011-11-18 23:25:11 +00:00
Adam Vogt
d4c7c51616 Export types to improve haddock links. 2011-11-18 19:06:42 +00:00
nzeh
c4f3e94377 Better control over GridVariants geometry
Added new messages the layout understands to allow changing the grid aspect
ratio and setting the fraction of the master to a given value rather than
changing it relative to the current value.
2011-09-07 13:33:04 +00:00
Norbert Zeh
2e91cde115 Support for scratchpad applications with multiple windows
I recently found that I use xpad to add sticky notes to my desktop.  I wanted
to be able to show/hide these in the same fashion as regular scratchpads.  This
patch adds a function that allows to do this while reusing most of the existing
NamedScratchpad code.
2011-04-06 14:02:13 +00:00
Norbert Zeh
e09cfba7dd Additional messages for SplitGrid layout
This patch introduces two new message SetMasterRows and SetMasterCols for the
X.GridVariants.SplitGrid layout, which set the number of rows/columns in the
master grid to the given value.  This is useful when setting the number of rows
and/or columns non-incrementally using an interface such as GridSelect.
2009-12-15 19:21:42 +00:00
Adam Vogt
001b38c7ab Be consistent with core utf8-string usage.
Now that spawn assumes executeFile takes a String containing utf8 codepoints
(and takes an actual String as input) adjust Prompt.Shell to avoid double
encoding. U.Run functions are updated to be consistent with spawn.
2011-11-18 18:47:45 +00:00
Adam Vogt
067ccb950e Export types to reduce haddock warnings. 2010-10-23 19:57:55 +00:00
Daniel Wagner
0226b8cb4f documentation patch: note the drawbacks of X.U.Dmenu 2011-11-15 02:27:26 +00:00
Daniel Wagner
68d49ad3aa get ready for GHC 7.4: Num a no longer implies (Eq a, Show a) 2011-11-15 02:26:50 +00:00
Adam Vogt
d3ef59256b Correct completions of utf8-named file in X.P.Shell 2011-11-11 21:56:55 +00:00
Wirt Wolff
1fb2696710 Expose X.L.Groups.Helpers and Groups.Wmii in xmonad-contrib.cabal
They provide many useful exports and are linked from X.L.Groups so promote
them from other-modules or missing status.
2011-11-04 05:37:03 +00:00
Audun Skaugen
71bb40156a Small bugfix to XMonad.Layout.Fullscreen
Fixed a small bug in the layout modifers where 
windows entering fullscreen were not refreshed.

Also fixed some funny whitespace characters.
2011-10-23 10:29:40 +00:00
Daniel Wagner
189f489e03 documentation patch: add a bit more context to the code snippets in X.L.IndependentScreens 2011-10-11 20:46:19 +00:00
Adam Vogt
c00dd7b51b U.EZConfig allow removing more than one mouse binding. 2011-09-23 12:39:07 +00:00
Norbert Zeh
41d23c1749 Remove X.A.GroupNavigation.currentWindow
This function does the same as X.StackSet.peek and all its uses have been
replaced with X.StackSet.peek.
2011-09-20 08:39:22 +00:00
Adam Vogt
7f70beaf4f Fix typo in NoBorders example code. 2011-08-14 19:53:14 +00:00
Daniel Schoepe
f27e89a2ff Add XF86TouchpadToggle to the list of multimedia keys in X.U.EZConfig 2011-09-17 15:14:19 +00:00
Daniel Wagner
61e991afaa documentation patch to XMonad.Doc.Extending 2011-09-16 20:28:45 +00:00
Brent Yorgey
9e5a712929 fix warnings in X.U.EZConfig 2011-09-08 13:32:46 +00:00
Wirt Wolff
f4fc9fe503 X.A.CycleWS Refactor and add toggleWS' that excludes listed tags 2011-09-07 23:27:30 +00:00
Wirt Wolff
23c2896c6f X.A.FlexibleManipulate: Set expected fixities for Pnt math operators
Restores broken mouseWindow discrete linear and resize to 0.9.1 behavior
2011-09-04 22:12:47 +00:00
Daniel Wagner
2443a962a0 GHC 7 compat
* true error: more modules export foldl/foldl'/foldr, so explicitly use the Data.Foldable one
* -Werror error: transition from Control.OldException to Control.Exception, assuming everything was IOException
2011-07-31 17:08:50 +00:00
Adam Vogt
1364a00c84 Correct H.DynamicLog.dynamicLogXinerama comment. Wuzzeb's patch at issue 466.
Slight changes to the patch to 1. work with haddock, and 2. remove ppOutput
which distracts from the formatting and is covered elsewhere.
2011-07-14 23:17:41 +00:00
Ben Boeckel
a9d1ce1efc ungrab-keyboard-before-action
If an action that requires the keyboard to be grabbed (e.g., launching dmenu),
it is a race when submapping the action as to whether the action will have
access to the keyboard or not. To fix this, the keyboard should be ungrabbed
before executing the action.
2011-05-15 21:03:12 +00:00
Ben Boeckel
9f65044be5 add-movenext-moveprev-bindings
Adds default bindings to GridSelect for the moveNext and movePrev motions.
2011-05-15 19:33:26 +00:00
Tomas Janousek
82dff7f91d X.L.LayoutHints: refresh only if hints are not satisfied 2011-06-15 15:03:33 +00:00
Adam Vogt
758094e4c7 L.Spacing use imported fi 2011-06-12 19:23:39 +00:00
Adam Vogt
4ea488d906 Use a phantom type instead of undefined in L.LayoutBuilderP
This better expresses the idea that the argument to alwaysTrue is just there to
select an instance. Another option could be to do use a fundep, which seems to
be compatible with the two instances so far.

class Predicate p w | p -> w
2011-06-09 05:18:58 +00:00
Adam Vogt
6ec8898a54 Add more L.LayoutBuilderP documentation 2011-06-09 05:09:22 +00:00
Adam Vogt
2ba8788b8e Correct L.LayoutBuilderP module name in haddock. 2011-06-09 04:39:40 +00:00
Ilya Portnov
b2f260e9ea Cleanup in X.L.LayoutBuilderP.
Remove unused datatype declaration and export usefull typeclass.
2011-05-14 13:22:32 +00:00
Adam Vogt
334344b804 Extend script for generating the code which runs tests
Now the number of runs each can be set, and the failures and successes are
summarized in the same way as the core Properties.hs. There is some duplicated
code which could be avoided by modifying Properties.hs.
2011-06-09 04:07:22 +00:00
Adam Vogt
dea9cdea5e Move tests from ManageDocks to tests/
The change to use a newtype for RectC is kind of ugly, but this way instances
are less likely to conflict in the tests.
2011-06-09 04:02:20 +00:00
Adam Vogt
ff41d7dc68 Export X.A.CycleWS.screenBy (issue 439) 2011-06-07 00:20:53 +00:00
Tomas Janousek
d752141be1 X.H.FloatNext: export X.H.ToggleHook.runLogHook
Otherwise the user has to import XMonad.Hooks.ToggleHook as well, which he
didn't have to in earlier versions.
2011-05-28 19:17:00 +00:00
Adam Vogt
cc162bba44 Documentation fix (issue 445)
Daniel's change which broke -Wall (adding an import for haddock only) was
somehow removed. Instead we can just modify the sample code to add the import.
2011-05-27 03:35:21 +00:00
Adam Vogt
c438c17e4d X.A.AppendFile documentation fix.
Forgotten > means haddock complained (and generated incorrect output).
More controversially I reworded a sentence and use do notation.
2011-05-27 03:28:54 +00:00
Ben Boeckel
4377e75bcc add-willhook-function
Adds a function that hooks into whether the hook will be triggered on the next
request.
2011-05-15 19:17:18 +00:00
Ben Boeckel
f4dd8973b1 use-map-in-toggle-hook
Use "Data.Map String (Bool, Bool)" instead of "[(String, (Bool, Bool))]" in
X.H.ToggleHook.
2011-05-15 19:14:18 +00:00
Ilya Portnov
af9e1863eb Extend GridSelect navigation
Add moveNext and movePrev, which move selection to next/previous item.
2011-05-15 15:42:46 +00:00
Ilya Portnov
fa6ce67fba Generalize X.L.AutoMaster modifier
Enable it to work not only with Windows, but with any (Eq) type.
2011-05-14 13:25:49 +00:00
Mats Rauhala
a4da8cd41b Aesthetics on Flexiblemanipulate
Based on Adam Vogts recommendation on the mailing list. I had to give explicit
type signatures to get rid of warnings, but nearly verbatim to his version.
2011-05-06 09:44:31 +00:00
Ilya Portnov
d9c9e0c10e Add new layout combinator: LayoutBuilderP.
LayoutBuilderP is similar to LayoutBuilder (and is based on it), but LayoutBuilderP places windows matching given X.U.WindowProperties.Property (or any other predicate) into one rectangle, instead of fixed number of windows.
2011-05-11 15:40:10 +00:00
Mats Rauhala
2ab79a7c35 Compile with ghc7 2011-05-04 19:24:55 +00:00
Mats Rauhala
8056bb5c2c Action search autocomplete based on whole line
The previous version autocompleted based on words, but when searching from web
sites, it makes more sense to autocomplete based on the entire search.
2011-05-04 21:52:01 +00:00
Daniel Wagner
29cad0672e documentation: tell where to find a few auxiliary functions that might be useful in conjunction with X.A.DynamicWorkspaces 2011-04-15 22:48:46 +00:00
Brandon S Allbery KF8NH
08c4c09fc5 Typo in window-properties.sh
Somewhere between my creating the original version of this script and
adding it to the tree, a backslash got lost.  It appears to have been
lost in the version I put on the wiki, so I suspect a copy-paste
problem at that point.
2011-04-13 05:30:02 +00:00
Brandon S Allbery KF8NH
85d6b79ab9 XMonad.Hooks.FadeWindows: A generalized window fading hook 2011-02-26 00:24:36 +00:00
Brandon S Allbery KF8NH
4bcf636259 Script to simplify getting ManageHook information from a window 2011-02-24 02:49:37 +00:00
Brandon S Allbery KF8NH
864732dbdc XMonad/Hooks/DebugKeyEvents - debug helper to see what keys xmonad sees 2011-02-24 02:36:13 +00:00
Brandon S Allbery KF8NH
521ef9e01d Prevent non-default XUtils windows from being composited 2011-02-24 00:32:24 +00:00
gwern0
8fb4c1e734 XMonad.Hooks.FloatNext: issue #406, make FloatNext use ToggleHook 2011-04-12 01:52:17 +00:00
gwern0
9b4e43e20f issue #406: ben boeckel <mathstuf@gmail.com> +XMonad.Hooks.ToggleHook 2011-04-12 01:51:27 +00:00
Adam Vogt
786613198b Fix xinerama workspace swapping with A.CopyWindow.killAllOtherCopies
Spotted by arlinius in #xmonad, and this only shows up for xinerama setups.
Using an algorithm that scales better with number of workspaces would probably
be shorter too (visiting them in turn, rather than doing random access), but
probably not worth the effort.
2011-03-01 03:37:36 +00:00
gwern0
1844c80978 XMonad.Util.Run: resolve issue #441
See <http://code.google.com/p/xmonad/issues/detail?id=441>

> I have run into programs that fail when run by safeSpawn but succeed with spawn.
> I tracked it down in one (python) and it seems to be due to uninstallSignalHandlers.
> When run by safeSpawn, the program reports errors from wait.

dylan did not supply a patch and his version doesn't match the declared type signature;
since I don't want to break every `safeSpawn` user, I tossed a `>> return ()` in to make
the type right, although I'm troubled at removing the exception functions.
2011-04-11 16:37:40 +00:00
gwern0
7c4358d2d6 AppendFile: additional example of usage 2011-01-26 20:10:18 +00:00
Adam Vogt
ed12889c2c Fix A.Gridselect image links (thanks dobblego) 2011-01-19 23:01:13 +00:00
Adam Vogt
9d3e169fb0 Bump version to 0.10 to help keep the correct contrib/core versions together. 2011-01-15 18:05:53 +00:00
Adam Vogt
0377a9e335 H.ICCCMFocus had atom_WM_TAKE_FOCUS incorrectly removed
It is possible that this atom should be defined in the X11 library, but fix the
build of contrib for now. In any case, this would have to wait for a change and
release of the X11 binding.

rolling back:

Wed Jan  5 22:38:39 EST 2011  Adam Vogt <vogt.adam@gmail.com>
  * Remove accidental atom_WM_TAKE_FOCUS from H.ICCCMFocus
  
  The XMonad module exports this already

    M ./XMonad/Hooks/ICCCMFocus.hs -7 +1
2011-01-06 19:20:52 +00:00
Adam Vogt
fe9fb9c62d Remove accidental atom_WM_TAKE_FOCUS from H.ICCCMFocus
The XMonad module exports this already
2011-01-06 03:38:39 +00:00
haskell
37fc674790 Java swing application focus patch 2011-01-05 03:25:35 +00:00
Brent Yorgey
bbd9761130 fix X.L.Gaps documentation, thanks to Carl Mueller for the report 2010-12-23 01:07:44 +00:00
Adam Vogt
a976d33038 Fix A.OnScreen example code typo 2010-12-12 16:18:50 +00:00
Brent Yorgey
1c50b1aa9a fix up funny unicode whitespace in Fullscreen 2010-12-12 14:22:41 +00:00
Audun Skaugen
02a3b820c9 Add X.L.Fullscreen 2010-11-16 22:16:11 +00:00
quesel
3813d625b6 Close the display correctly after counting the number of screens
This patch adds support for calling countScreens in arbitrary places. Prior to
this patch one would end up with an open display for each call of the
countScreens function with would eventually mess up X. This patch ensures that
the display that is no longer needed is closed after the operation and thus
using the function without side effects.
2010-11-16 08:14:49 +00:00
Adam Vogt
67db59bf73 Compatibility with mtl-1 and mtl-2 2010-11-15 23:26:54 +00:00
Adam Vogt
52d3aa1500 Rename state in A.Gridselect to avoid name shadowing (mtl-2) 2010-11-15 23:22:22 +00:00
Clemens Fruhwirth
cbb20fb3a8 Substring search support for X.A.GridSelect. As keymaps get more complicated to support different styles, the gs_navigate element is fundamentially changed. 2010-11-02 21:12:13 +00:00
Clemens Fruhwirth
e544e09cbb Make substring search case insensitive 2010-10-16 21:29:04 +00:00
Clemens Fruhwirth
3a886e0844 Introduce grayoutAllElements in X.A.GridSelect 2010-10-16 21:25:59 +00:00
Clemens Fruhwirth
27fc66bb2c Add substring filter to td_elementmap 2010-10-16 18:36:44 +00:00
Clemens Fruhwirth
3a35fe3f3d Refactor for ad-hoc element and position matching turning td_elementmap into a function using the new td_availSlot and td_elements fields 2010-10-16 18:35:54 +00:00
Clemens Fruhwirth
06bb702240 Remove nub from diamondLayer in X.A.GridSelect 2010-10-16 18:31:32 +00:00
Clemens Fruhwirth
3cee73fe02 Convert access of td_elementmap from field styled to function call styled in X.A.GridSelect 2010-10-16 16:47:57 +00:00
Clemens Fruhwirth
ffe08858ab Make use of field names when constructing TwoDState in X.A.GridSelect 2010-10-16 16:41:51 +00:00
Adam Vogt
96d2982c60 Pointfree and -XRank2Types don't mix in X.L.Groups.Helpers
It used to work with ghc-6.12 (and earlier?), but ghc-7RC2 type inference
doesn't work with . instead of it's definition.
2010-11-13 02:28:39 +00:00
Adam Vogt
f9d2a6bd7f Restrict dependencies, since mtl-2 is incompatible
A couple removed constructors need to be replaced by the lowercase versions
(ex. State = StateT Identity now). But it isn't clear that mtl-1 should be
dropped.
2010-11-13 02:22:04 +00:00
Adam Vogt
b1ff22411d X.L.TrackFloating docs and help nested layouts
Now TrackFloating remembers focus for the given layout when the other window is
also tiled, but not fed to the given layout: this helps with X.L.IM, among
others.
2010-10-30 17:56:15 +00:00
Norbert Zeh
a73a61302c X.L.Maximize: Make layout forget maximized window when it is closed
The X.L.Maximize layout modifier does not track whether the window it stores as
maximized does still exist.  The X server reuses window IDs.  As a result, I
was able to reproduce the following behaviour (e.g., by opening and closing
xpdf windows): Create a window, maximize it, close it without restoring it to
its normal state.  Open a new window with the same window ID (e.g., an xpdf
window after just closing an xpdf window).  The new window will open maximized,
which is not what one would expect.  This patch addresses this problem,
removing the ID of the maximized window from the layout when the maximized
window is closed.
2010-10-29 22:15:51 +00:00
Adam Vogt
81d338952d Fix bug in L.TrackFloating
Addresses the comment that:

If the focus goes from the floating layer to tiling by deleting a floating
window, it's again the master window that gets focus, not the remembered
window.
2010-10-30 00:06:20 +00:00
Daniel Schoepe
d7005d529a Add X.L.Groups.Helpers to other-modules
Not listing aforementioned module can cause build failures in libaries
that depend on xmonad-contrib.
2010-10-24 19:18:50 +00:00
mathstuf
88380dc1da windowbringer-menu-choice
Add functions to allow users to use a menu other than dmenu and pass arguments
to the menu.
2010-09-05 01:35:22 +00:00
Adam Vogt
25889f2d0c Add X.L.TrackFloating for tiled-floating focus issues (#4) 2010-10-16 16:55:36 +00:00
Daniel Wagner
eec8dc9dcb minor documentation fixes 2010-10-07 01:19:57 +00:00
Daniel Schoepe
3a405285b0 Minor documentation fixes in X.U.ExtensibleState 2010-10-04 12:05:09 +00:00
Adam Vogt
8fa66c829d Clarify the note on -XRank2Types in L.Groups 2010-10-02 02:08:41 +00:00
quentin.moser
44a1889345 Mention X.L.Groups.ModifySpec's rank-2 type in the doc 2010-01-17 11:56:01 +00:00
moserq
4339b7ac00 Orphan my modules 2010-10-01 10:43:00 +00:00
moserq
021245b5fa Split X.L.Groups.Examples
X.L.G.Examples : rowOfColumns and tiled tabs layouts
X.L.G.Helpers : helper actions
X.L.G.Wmii : wmii layout
2010-10-01 10:41:42 +00:00
moserq
ea10cbbbd8 X.L.G.Examples: improve the tabs of tiledTabs 2010-01-20 10:32:40 +00:00
moserq
0b4c57d769 X.L.G.Examples: improve the tabs of wmiiLike 2010-01-20 10:17:46 +00:00
quentin.moser
e3af1c3dfc X.L.Groups: Always keep one group, even if empty. 2010-01-18 02:15:26 +00:00
quentin.moser
8e298ca8b8 Do not duplicate layouts in X.L.Groups
I liked the idea, but it completey messes up Decoration layouts.
2010-01-17 11:47:08 +00:00
Adam Vogt
85973b0550 Add missing module re-export (issue 366) 2010-09-30 00:20:46 +00:00
Tomas Janousek
f8be680472 X.H.ManageDocks: event hook to refresh on new docks 2010-07-06 18:58:34 +00:00
quesel
5fb228cfac This patch adds support for multiple master windows to X.L.Master 2010-05-18 06:05:57 +00:00
Tomas Janousek
adbb52d4f2 X.L.LayoutHints: event hook to refresh on hints change 2010-07-06 18:59:25 +00:00
Adam Vogt
2e30d259b8 Remove last excess definition of `fi' (fromIntegral) 2010-09-13 23:38:50 +00:00
Adam Vogt
d5a5522187 Explain fields added for "XMonad.Layout.ImageButtonDecoration" 2010-09-13 23:27:20 +00:00
Adam Vogt
6458e60812 Adjust X.C.Desktop documentation content.
Correct errors regarding a description of `mappend' for X

Use <+> more often since that's `consistent', and there is no difference since
it's the same as >> when all arguments have the same type (which they do...
otherwise people aren't just combining valid values for that field of the
config).
2010-08-03 14:11:17 +00:00
Jan Vornberger
82147d137c Minimize: Replaced calls to 'sendMessage' (BW.focusDown) and 'windows' with alternative methods
Calling these functions during message handling results in the loss of layout state.
This fixes a number of bugs related to the combination of X.L.Minimize with a decoration.
2010-07-27 22:48:41 +00:00
Jan Vornberger
980a22434b CurrentWorkspaceOnTop: proper reimplementation of XMonad.Operation
Fixes bugs in combination with stateful layouts and floating windows
2010-07-27 19:41:54 +00:00
Justin Bogner
fd99373c39 A hook to handle minimize/restore window manager hints.
XMonad.Hooks.Minimize handles both minimize and restore
messages. Handling restore messages was already done in
RestoreMinimized, which this module intends to replace.
2010-06-16 05:11:24 +00:00
gwern0
bac3e0d658 WindowGo: bulk up 'runOrRaise' doc to point to 'raiseMaybe' for shell scripting 2010-07-12 04:56:32 +00:00
gwern0
9f6bb1a26e WindowGo: fmt & sp 2010-07-12 04:29:15 +00:00
Adam Vogt
129af43738 Note that Simplest works well with BoringWindows 2010-06-22 03:08:50 +00:00
gwern0
3f8e0109cc XMonad.Util.Run: improve linking and rearrange docs 2010-06-20 17:52:15 +00:00
gwern0
eed47b3f81 XMonad.Util.Run: correct broken example 2010-06-20 17:51:58 +00:00
gwern0
7dd1384884 XMonad.Util.Run: fix unicode char 2010-06-20 17:51:40 +00:00
gwern0
f23f8e0bf7 XSelection.hs: update docs w/r/t unicode
see http://code.google.com/p/xmonad/issues/detail?id=348
2010-06-15 00:09:02 +00:00
Khudyakov Alexey
e708caf2ac encode string of bytes not list of chars 2010-06-13 11:33:41 +00:00
gwern0
c6178cacd2 GroupNavigation.hs: clean up imports 2010-06-08 20:38:32 +00:00
gwern0
6472683476 remove decodeInput/encodeOutput
see http://code.google.com/p/xmonad/issues/detail?id=348
they are just synonyms for 2 utf8-string functions, and don't really help
2010-06-14 23:23:00 +00:00
gwern0
955dd48153 Developing: be good to mention hlint in a hacking guide 2010-05-06 16:05:35 +00:00
Norbert Zeh
9300140701 Fix bug in history maintenance of X.A.GroupNavigation
When the focused window was closed without a new window receiving focus, the
closed window was not removed from the history database, making for example
"nextMatch History (return True)" misbehave.  This patch fixes this.
2010-06-04 08:14:31 +00:00
Jan Vornberger
af24766a83 PositionStoreHook: take decoration into account 2010-06-02 22:30:15 +00:00
Jan Vornberger
12cc1dc53e PositionStoreHook: take docks into account 2010-06-02 21:50:48 +00:00
Nicolas Pouillard
316e26fd0c TopicSpace: +reverseLastFocusedTopics 2010-05-20 07:28:44 +00:00
Nicolas Pouillard
c1a3a1c19d TopicSpace: improve the lastFocusedTopic handling
Now the list of last topics is internally kept but
only visually truncated.
2009-12-20 21:28:13 +00:00
Norbert Zeh
142eac2eb3 X.A.GroupNavigation with containers < 0.3.0.0 compatibility
This patch replaces the use of Seq.filter and Seq.breakl with two
functions flt and brkl that do the same.  This is necessary to
keep compatibility with containers < 0.3.0.0 because Seq.filter and
Seq.breakl were introduced only in containers 0.3.0.0.
2010-05-14 22:21:53 +00:00
Norbert Zeh
d01bb24022 New module XMonad.Actions.GroupNavigation
This module adds two related facilities.  The first one allows cycling through
the windows in a window group.  A group is defined as the set of windows for
which a given Boolean Query returns True.  The second one keeps track of the
history of focused windows and allows returning to the most recently focused
window in a given window group before the currently focused window.
2010-05-10 08:14:12 +00:00
Daniel Schoepe
2ee34742ca Add a way to update the modifier in X.L.LayoutModifier
This patch adds the possibility to update the state of a layout modifier when
modifying the underlying layout before it is run(i.e. using modifyLayout). 
The modified state is also passed to the subsequent call of redoLayout, whose 
return takes precedence if both functions return modified states of the layout 
modifier.
2009-08-22 21:39:58 +00:00
Adam Vogt
b21208dad7 Remove trailing whitespace in A.KeyRemap 2010-05-03 15:32:58 +00:00
stettberger
99e5a4393f Adding XMonad.Actions.KeyRemap for mapping single keys
With KeyRemap it is possible to emit different keys to client windows, when 
pressing some key. For example having dvorak layout for typing, but us for 
keybindings.
2010-05-02 15:23:22 +00:00
Adam Vogt
ad5277a189 Move Util.Font to .hs, and enable -XCPP
As the CPP pass was the only feature being used in Font.hsc (no other FFI)
it's better to avoid hsc2hs, if only to make the purpose of the module
clearer from the filename.
2010-04-29 14:07:44 +00:00
Adam Vogt
d310cf5f69 A.Search: Remove unnecessary `do' 2010-04-29 13:47:49 +00:00
Khudyakov Alexey
f7d8eb3fdd Fix escaping of URI 2010-04-23 20:47:07 +00:00
Adam Vogt
ceb24fb8b4 Prompt: handle case of historySize=0 better. 2010-04-21 18:30:06 +00:00
Adam Vogt
36bcb743d6 Rearrange tests. See test/genMain.hs for instructions. 2010-04-19 01:49:46 +00:00
Adam Vogt
c3c06a4567 Use CPP to add to exports for Selective tests (L.LimitWindows) 2010-04-19 01:43:44 +00:00
Adam Vogt
78f13d2acd Use imported `fi' alias for fromIntegral more often.
Also moves `fi' into U.Image to avoid cyclic imports,
though XUtils sill exports that definition.
2010-04-16 21:29:39 +00:00
Adam Vogt
d511ffd01a Note that mouseResizableTileMirrored may be removed. 2010-04-16 16:11:18 +00:00
Adam Vogt
4950c69dbd Structure L.MouseResizableTile documentation. 2010-04-16 16:06:41 +00:00
Tomas Janousek
7129622eb9 X.L.MouseResizableTile: make everything configurable 2010-04-15 21:46:09 +00:00
Tomas Janousek
1e847cb65a X.L.MouseResizableTile: configurable gaps (dragger size and position)
(with the option of putting the draggers over window borders with no gaps at
all)
2010-04-15 21:38:13 +00:00
Adam Vogt
2853dc65c8 Remove unnecessary imports. 2010-04-16 16:02:39 +00:00
gwern0
ddd9674b14 update module imports 2010-04-14 21:19:47 +00:00
Adam Vogt
9372aac28e tests/test_XPrompt can build now. 2010-04-14 20:46:12 +00:00
Adam Vogt
2477f81f73 prettier haddock markup for L.NoBorders 2010-04-05 18:40:20 +00:00
Jan Vornberger
c37cbbadf5 ImageButtonDecoration: new image for menu button 2010-04-02 17:49:10 +00:00
trupill
e125c84616 image_buttons
* Added a XMonad.Util.Image module to manipulate simple images
  and show them into an X drawable
* Added the possibility of using image buttons instead of plain
  text buttons into the title bar
* Added a XMonad.Layout.ImageButtonDecoration as an example of
  how to use the image buttons
2010-03-31 09:38:08 +00:00
Jan Vornberger
4e8285dcbe WindowMenu: own colorizer that works better with Bluetile's new theme 2010-04-02 18:41:19 +00:00
Anders Engstrom
96f3456b96 X.L.Named deprecate and implement using X.L.Renamed
nameTail behaves slightly different if there are whitespace before the first word or the name contains tabs or other such whitespace. But I expect few users are affected since the only usecase where nameTail is actually needed is to remove automatically added prefixes. These prefixes will be removed as they should by the new implementation.
2010-04-01 21:24:03 +00:00
Anders Engstrom
5b045e458d X.L.Minimize remove redundant imports 2010-04-01 20:44:00 +00:00
Adam Vogt
5e274b254e Correct module header. 2010-03-30 18:10:29 +00:00
trupill
b6c5550334 minimize_ewmh 2010-03-30 18:36:16 +00:00
Adam Vogt
086c8c209c Use more monoid instances to clean up U.WorkspaceCompare 2010-02-22 15:17:10 +00:00
Adam Vogt
6215d71600 Note that Groups has redundancies and the interface may change.
Refer to:
http://www.haskell.org/pipermail/xmonad/2010-January/009585.html
2010-03-30 17:59:45 +00:00
Tomas Janousek
f093c11a27 X.H.UrgencyHook: performance fix
cleanupUrgents would update the Map in extensible state 2-times the number of
visible windows, resulting in excessive memory usage and garbage collection.
This seems to make it behave correctly.
2010-03-30 14:13:41 +00:00
quentin.moser
97e68c1bc8 Update my e-mail address 2010-01-17 01:11:09 +00:00
quentin.moser
dd1a8ff05d New module: X.L.Groups.Examples
Utility functions and examples using X.L.Groups.
2010-01-17 01:02:36 +00:00
quentin.moser
10e1e1d4c1 New module: X.L.Groups
The mother of all layout combinators.
2010-01-17 00:53:01 +00:00
quentin.moser
38f1a07042 New module: X.L.ZoomRow
Row layout with individually resizable elements.
2010-01-17 00:39:39 +00:00
quentin.moser
317afc33af New module: X.L.Renamed 2010-01-17 00:26:12 +00:00
quentin.moser
6aeca44187 New module: X.U.Stack
Utility functions for working with Maybe Stacks, including:
  - useful conversions to and from lists
  - insertUp/Down, swapUp/Down, focusUp/Down, etc
  - maps, filters and folds
2010-01-17 00:21:04 +00:00
Daniel Wagner
8705542d1d bugfix: removeKeys should remove all keys in the provided list 2010-03-27 19:25:41 +00:00
Jurgen Doser
208d920b6b fixed argument order to isPrefixOf in a couple of places in X.A.Search
In some places, ((!>), prefixAware, and one place in the documentation),
isPrefixOf was used with wrong argument order.  In particular, this made
combining search engines not work as advertised, for example, the predefined
search engine "multi".
2010-03-16 12:20:10 +00:00
Brent Yorgey
5485ba57ac X.P.Ssh: add entries from .ssh/config to ssh prompt completion 2009-12-29 17:13:46 +00:00
Tomas Janousek
21526d1532 X.H.DynamicLog: let the user of xmonadPropLog choose property name 2010-03-19 21:46:31 +00:00
gwern0
520b9ccf6e Replace.hs: rm trailing whitespace 2010-03-14 21:01:09 +00:00
gwern0
e28cd8cd6e Workspace.hs: rm trailing whitespace 2010-03-14 21:01:01 +00:00
gwern0
98a320cbb5 Layout.hs: rm trailing whitespace 2010-03-14 21:00:54 +00:00
gwern0
3b258409db Directory.hs: rm trailing whitespace 2010-03-14 21:00:47 +00:00
gwern0
cf0c3194de MessageControl: rm trailing whitespace 2010-03-14 21:00:38 +00:00
gwern0
796b775d5c LimitWindows.hs: rm trailing whitespace 2010-03-14 21:00:30 +00:00
gwern0
0d3293ce52 LayoutCombinators.hs: rm trailing whitespace 2010-03-14 21:00:21 +00:00
gwern0
ce5f81fe16 DecorationAddons.hs: rm trailing whitespace 2010-03-14 21:00:12 +00:00
gwern0
b267617eee Column.hs: rm whitespace 2010-03-14 21:00:01 +00:00
gwern0
c3796a9cb1 DynamicWorkspaces.hs: rm whitespace 2010-03-14 20:59:51 +00:00
Max Rabkin
ee38a0328b Fix bugs with nested drawers in X.L.Drawer
There were two bugs:
1. The layout modifier assumed the rect's x was zero.
2. The layout modifier assumed that the stackset's focus actually had focus.
2010-03-10 17:01:59 +00:00
Adam Vogt
8cc604c4ad Correct L.Drawer haddock markup and re-export required module. 2010-03-08 22:52:58 +00:00
Max Rabkin
8f58fb4c2f Added X.L.Drawer
X.L.Drawer provides a layout modifier for retracting windows which roll down
(like the Quake console) when they gain focus.
2010-03-08 21:27:52 +00:00
Anders Engstrom
0c9619e5cd X.U.WorkspaceCompare xinerama compare with physical order
Like the old xinerama workspace comparison, but order by physical location just like X.A.PhysicalScreens. Useful if using xinerama sort for statusbar together with physicalscreens.
2010-03-08 11:54:02 +00:00
Anders Engstrom
5e6c03c2ca X.U.Dmenu helpers to run dmenu with arguments 2010-03-08 11:50:22 +00:00
Anders Engstrom
abebe3085c X.L.LayoutScreens split current screen
This patch will allow the user to split the currently focused screen instead of all screens together. This is usefull for multiscreen users who have functioning xinerama, but wish to split one of the screens.
2010-03-08 11:43:18 +00:00
Anders Engstrom
649bb08374 X.A.PhysicalScreens cleaning and allow cycling
Remove redundant import to supress warning, did some refactoring to use xmonad internal things to find screens instead of using X11-stuff. Also added ability to cycle between screens in physical order.
2010-03-08 11:37:04 +00:00
Adam Vogt
16fce733c0 Use imported 'fi' in H.ScreenCorners 2010-02-22 15:06:33 +00:00
Nils Schweinsberg
c8cd7df334 X.H.ScreenCorners typos 2010-02-22 11:51:42 +00:00
Nils Schweinsberg
c057c24f70 X.H.ScreenCorners rewritten to use InputOnly windows instead of waiting for MotionEvents on the root window 2010-02-22 11:24:59 +00:00
Nils Schweinsberg
4a138012ba [patch] X.H.ScreenCorners: move the mouse cursor to avoid loops 2010-02-21 23:15:50 +00:00
Daniel Schoepe
aa34798b99 Prevent possible pattern match failure in X.A.UpdateFocus 2010-02-21 23:47:35 +00:00
Nils Schweinsberg
9fdd63bd8b New extension: XMonad.Hooks.ScreenCorners 2010-02-21 23:02:59 +00:00
daniel
bd47cc5d3e documentation for marshallPP 2010-02-15 00:07:31 +00:00
Daniel Wagner
e44bab10e7 DynamicLog support for IndependentScreens 2010-01-04 05:42:51 +00:00
Daniel Wagner
0909472d54 minor style changes 2009-12-28 17:30:16 +00:00
gwern0
38228517eb XMonad.Prompt: remove white border from greenXPConfig 2010-02-11 16:36:41 +00:00
Daniel Schoepe
de9a2e8adb Fixed reversed history searching direction in X.P.history(Up|Down)Matching 2010-02-08 16:29:01 +00:00
Adam Vogt
52a2eba7e6 Compatibility for rename of XMonad.numlockMask 2010-01-24 20:19:55 +00:00
Adam Vogt
aa8290b60d Use extensible-exceptions to allow base-3 or base-4 2010-01-24 20:33:24 +00:00
Brent Yorgey
b435a6a519 suppress some warnings under ghc 6.12.1 and clean up redundant imports to get rid of some others. 2010-01-12 17:25:07 +00:00
Daniel Schoepe
96792aa4ab Corrected documentation in X.Prompt 2010-02-01 20:45:22 +00:00
Daniel Schoepe
59667f39ab Use Stack instead of list in X.Prompt.history*Matching 2010-02-01 20:28:39 +00:00
Jan Vornberger
9b76a85c74 BluetileConfig: Fullscreen tweaks and border color change 2010-01-31 23:33:47 +00:00
Wirt Wolff
57c00ea498 A.CycleWindows replace partial rotUp and rotDown with safer versions
Rather than throw exceptions, handle null and singleton lists, i.e.
f [] gives [] and f [x] gives [x].
2010-01-23 23:19:12 +00:00
Adam Vogt
a9f2b82337 Use <+> instead of explicit M.union to merge keybindings in X.C.* 2010-01-24 20:21:36 +00:00
Adam Vogt
0b4d34fa7e Fix incorrect import suggestion in L.Tabbed (issue 362) 2010-01-21 18:25:01 +00:00
Adam Vogt
685cc6931f Swap window ordering in L.Accordion (closes Issue 358). Thanks rsaarelm.
This change keeps windows in the same ordering when focus is changed.
2010-01-21 15:43:44 +00:00
Jens Petersen
7b0fd3ba3a use restart to restart xmonad (no longer bluetile) 2010-01-16 10:59:35 +00:00
Tomas Janousek
0ce76fd152 X.L.Decoration: avoid flicker by not showing decowins without rectangles
These would be hidden by updateDecos immediately after being shown. This
caused flicker with simpleTabbed and only one window on a workspace.
2010-01-16 11:20:54 +00:00
Daniel Schoepe
c0d5c4a278 Add a way to cycle only through matching history entries in X.Prompt
This patch adds a way go up through X.Prompt's history using
only those entries that start with the current input, similar
to zsh's `history-search-backward'.
2010-01-13 23:30:36 +00:00
Adam Vogt
882ddc25f4 Style changes in L.Minimize 2010-01-04 14:44:48 +00:00
konstantin.sobolev
6c452e066e minimize_floating
Adds floating windows support to X.L.Minimize
2009-12-30 07:01:05 +00:00
Adam Vogt
6fc1530fe9 Use more imported cursor constants. 2009-12-30 22:09:27 +00:00
Brent Yorgey
1eb50b2028 import new contrib module, X.A.DynamicWorkspaceOrder 2009-12-30 19:23:50 +00:00
Brent Yorgey
f25c348669 X.A.CycleWS: export generalized 'doTo' function for performing an action on a workspace relative to the current one 2009-12-30 19:19:53 +00:00
Brent Yorgey
2c4e5f5d53 new contrib module, X.A.DynamicWorkspaceGroups, for managing groups of workspaces on multi-head setups 2009-12-29 16:57:02 +00:00
Brent Yorgey
d384a98ccb new contrib module from Tomas Janousek, X.A.WorkspaceNames 2009-12-29 16:39:15 +00:00
Tim Horton
4e2e0ef0ba X.P.Shell, filter empty string from PATH
doesDirectoryExist returns True if given an empty string using ghc <= 6.10.4.
This causes getDirectoryContents to raise an exception and X.P.Shell does not
render. This is only an issue if you have an empty string in your PATH.

Using ghc == 6.12.1, doesDirectoryExist returns False given an empty string, so
this should not be an issue in the future.
2009-12-24 03:32:17 +00:00
Brent Yorgey
997fdef24b small tweak to battery logger 2009-12-27 08:56:41 +00:00
Adam Vogt
2f0e880ccd Use imported xC_bottom_right_corner in A.MouseResize 2009-12-27 23:37:05 +00:00
Tomas Janousek
311994f9ef X.A.MouseResize: assign an appropriate cursor for the resizing inpuwin 2009-12-27 21:21:40 +00:00
Spencer Janssen
12c791d02f Fix the createSession bug in spawnPipe
Both the new XMonad.Core.xfork function and spawnPipe call createSession, calling
this function twice results in an error.
2009-12-27 00:35:01 +00:00
Jan Vornberger
adb7144a98 Let the core know about MouseResizableTile's draggers, so they are stacked correctly 2009-12-23 14:54:28 +00:00
Spencer Janssen
e8c0f39fd5 Update all uses of forkProcess to xfork 2009-12-23 06:45:58 +00:00
Jan Vornberger
98fe292e9f Make X.L.Minimize explicitly mark minimized windows as boring 2009-12-22 21:45:29 +00:00
intrigeri
d32efe75e4 Actions/Search: added openstreetmap 2009-12-22 11:45:45 +00:00
Mike Lundy
efbcf16cee Add a search predicate option to XMonad.Prompt 2009-12-21 02:54:08 +00:00
Adam Vogt
05ed62a455 In D.Extending note how <+> can be used with keybindings. 2009-12-20 19:07:39 +00:00
Tomas Janousek
16181ce6e7 Fix MultiToggle crashes with decorated layouts
The problem was that certain layouts keep their "world" state in their value,
which was thrown away and forgotten after ReleaseResources during toggle.

In particular, decorated layouts store some X11 handles in them and
allocate/deallocate it as appropriate. If any modification to their state is
ignored, they may try to deallocate already deallocated memory, which results
in a crash somewhere inside Xlib.

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

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

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

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

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

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

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

View File

@@ -0,0 +1,83 @@
----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.BluetileCommands
-- Copyright : (c) Jan Vornberger 2009
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : jan.vornberger@informatik.uni-oldenburg.de
-- Stability : unstable
-- Portability : not portable
--
-- This is a list of selected commands that can be made available using
-- "XMonad.Hooks.ServerMode" to allow external programs to control
-- the window manager. Bluetile (<http://projects.haskell.org/bluetile/>)
-- uses this to enable its dock application to do things like changing
-- workspaces and layouts.
--
-----------------------------------------------------------------------------
module XMonad.Actions.BluetileCommands (
-- * Usage
-- $usage
bluetileCommands
) where
import XMonad
import qualified XMonad.StackSet as W
import XMonad.Layout.LayoutCombinators
import System.Exit
-- $usage
--
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
--
-- > import XMonad.Hooks.ServerMode
-- > import XMonad.Actions.BluetileCommands
--
-- Then edit your @handleEventHook@:
--
-- > main = xmonad defaultConfig { handleEventHook = serverModeEventHook' bluetileCommands }
--
-- See the documentation of "XMonad.Hooks.ServerMode" for details on
-- how to actually invoke the commands from external programs.
workspaceCommands :: Int -> X [(String, X ())]
workspaceCommands sid = asks (workspaces . config) >>= \spaces -> return
[(("greedyView" ++ show i),
activateScreen sid >> windows (W.greedyView i))
| i <- spaces ]
layoutCommands :: Int -> [(String, X ())]
layoutCommands sid = [ ("layout floating" , activateScreen sid >>
sendMessage (JumpToLayout "Floating"))
, ("layout tiled1" , activateScreen sid >>
sendMessage (JumpToLayout "Tiled1"))
, ("layout tiled2" , activateScreen sid >>
sendMessage (JumpToLayout "Tiled2"))
, ("layout fullscreen" , activateScreen sid >>
sendMessage (JumpToLayout "Fullscreen"))
]
masterAreaCommands :: Int -> [(String, X ())]
masterAreaCommands sid = [ ("increase master n", activateScreen sid >>
sendMessage (IncMasterN 1))
, ("decrease master n", activateScreen sid >>
sendMessage (IncMasterN (-1)))
]
quitCommands :: [(String, X ())]
quitCommands = [ ("quit bluetile", io (exitWith ExitSuccess))
, ("quit bluetile and start metacity", restart "metacity" False)
]
bluetileCommands :: X [(String, X ())]
bluetileCommands = do
let restartCommand = [ ("restart bluetile", restart "bluetile" True) ]
wscmds0 <- workspaceCommands 0
wscmds1 <- workspaceCommands 1
return $ restartCommand
++ wscmds0 ++ layoutCommands 0 ++ masterAreaCommands 0 ++ quitCommands
++ wscmds1 ++ layoutCommands 1 ++ masterAreaCommands 1 ++ quitCommands
activateScreen :: Int -> X ()
activateScreen sid = screenWorkspace (S sid) >>= flip whenJust (windows . W.view)

View File

@@ -26,7 +26,6 @@ module XMonad.Actions.CopyWindow (
import XMonad
import Control.Arrow ((&&&))
import Control.Monad
import qualified Data.List as L
import XMonad.Actions.WindowGo
@@ -146,7 +145,9 @@ killAllOtherCopies = do ss <- gets windowset
delFromAllButCurrent w ss = foldr ($) 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
delWinFromWorkspace w wid = viewing wid $ W.modify Nothing (W.filter (/= w))
viewing wis f ss = W.view (W.currentTag ss) $ f $ W.view wis ss
-- | A list of hidden workspaces containing a copy of the focused window.
wsContainingCopies :: X [WorkspaceId]

View File

@@ -46,6 +46,7 @@ module XMonad.Actions.CycleWS (
-- * Toggling the previous workspace
-- $toggling
, toggleWS
, toggleWS'
, toggleOrView
-- * Moving between screens (xinerama)
@@ -65,6 +66,7 @@ module XMonad.Actions.CycleWS (
, shiftTo
, moveTo
, doTo
-- * The mother-combinator
@@ -72,6 +74,8 @@ module XMonad.Actions.CycleWS (
, toggleOrDoSkip
, skipTags
, screenBy
) where
import Control.Monad ( unless )
@@ -147,9 +151,16 @@ shiftToPrev = shiftBy (-1)
-- | Toggle to the workspace displayed previously.
toggleWS :: X ()
toggleWS = do
hs <- gets (hidden . windowset)
unless (null hs) (windows . view . tag $ head hs)
toggleWS = toggleWS' []
-- | Toggle to the previous workspace while excluding some workspaces.
--
-- > -- Ignore the scratchpad workspace while toggling:
-- > ("M-b", toggleWS' ["NSP"])
toggleWS' :: [WorkspaceId] -> X ()
toggleWS' skips = do
hs' <- cleanHiddens skips
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
@@ -159,9 +170,8 @@ toggleWS = do
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:
-- | Allows ignoring listed workspace tags (such as scratchpad's \"NSP\"), and
-- running other actions such as view, shift, etc. For example:
--
-- > import qualified XMonad.StackSet as W
-- > import XMonad.Actions.CycleWS
@@ -174,9 +184,9 @@ toggleOrView = toggleOrDoSkip [] 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)
hs' <- cleanHiddens skips
cur <- gets (currentTag . windowset)
if toWS == cur
then unless (null hs') (windows . f . tag $ head hs')
else windows (f toWS)
@@ -185,6 +195,9 @@ toggleOrDoSkip skips f toWS = do
skipTags :: (Eq i) => [Workspace i l a] -> [i] -> [Workspace i l a]
skipTags wss ids = filter ((`notElem` ids) . tag) wss
cleanHiddens :: [WorkspaceId] -> X [WindowSpace]
cleanHiddens skips = gets $ (flip skipTags) skips . hidden . windowset
switchWorkspace :: Int -> X ()
switchWorkspace d = wsBy d >>= windows . greedyView
@@ -218,6 +231,10 @@ data WSType = EmptyWS -- ^ cycle through empty workspaces
| HiddenWS -- ^ cycle through non-visible workspaces
| HiddenNonEmptyWS -- ^ cycle through non-empty non-visible workspaces
| AnyWS -- ^ cycle through all workspaces
| WSTagGroup Char
-- ^ cycle through workspaces in the same group, the
-- group name is all characters up to the first
-- separator character or the end of the tag
| WSIs (X (WindowSpace -> Bool))
-- ^ cycle through workspaces satisfying
-- an arbitrary predicate
@@ -232,17 +249,25 @@ wsTypeToPred HiddenNonEmptyWS = do ne <- wsTypeToPred NonEmptyWS
hi <- wsTypeToPred HiddenWS
return (\w -> hi w && ne w)
wsTypeToPred AnyWS = return (const True)
wsTypeToPred (WSTagGroup sep) = do cur <- (groupName.workspace.current) `fmap` gets windowset
return $ (cur ==).groupName
where groupName = takeWhile (/=sep).tag
wsTypeToPred (WSIs p) = p
-- | View the next workspace in the given direction that satisfies
-- the given condition.
moveTo :: Direction1D -> WSType -> X ()
moveTo dir t = findWorkspace getSortByIndex dir t 1 >>= windows . greedyView
moveTo dir t = doTo dir t getSortByIndex (windows . greedyView)
-- | Move the currently focused window to the next workspace in the
-- given direction that satisfies the given condition.
shiftTo :: Direction1D -> WSType -> X ()
shiftTo dir t = findWorkspace getSortByIndex dir t 1 >>= windows . shift
shiftTo dir t = doTo dir t getSortByIndex (windows . shift)
-- | Using the given sort, find the next workspace in the given
-- direction of the given type, and perform the given action on it.
doTo :: Direction1D -> WSType -> X WorkspaceSort -> (WorkspaceId -> X ()) -> X ()
doTo dir t srt act = findWorkspace srt dir t 1 >>= act
-- | Given a function @s@ to sort workspaces, a direction @dir@, a
-- predicate @p@ on workspaces, and an integer @n@, find the tag of
@@ -300,6 +325,17 @@ switchScreen d = do s <- screenBy d
Nothing -> return ()
Just ws -> windows (view ws)
{- | Get the 'ScreenId' /d/ places over. Example usage is a variation of the
the default screen keybindings:
> -- mod-{w,e}, Switch to previous/next Xinerama screen
> -- mod-shift-{w,e}, Move client to previous/next Xinerama screen
> --
> [((m .|. modm, key), sc >>= screenWorkspace >>= flip whenJust (windows . f))
> | (key, sc) <- zip [xK_w, xK_e] [(screenBy (-1)),(screenBy 1)]
> , (f, m) <- [(W.view, 0), (W.shift, shiftMask)]]
-}
screenBy :: Int -> X (ScreenId)
screenBy d = do ws <- gets windowset
--let ss = sortBy screen (screens ws)

View File

@@ -226,8 +226,10 @@ rotUnfocused' f (W.Stack t ls rs) = W.Stack t (reverse revls') rs' -- otherwis
(revls',rs') = splitAt (length ls) (f $ master:revls ++ rs)
-- $generic
-- Generic list rotations
-- Generic list rotations such that @rotUp [1..4]@ is equivalent to
-- @[2,3,4,1]@ and @rotDown [1..4]@ to @[4,1,2,3]@. They both are
-- @id@ for null or singleton lists.
rotUp :: [a] -> [a]
rotUp l = tail l ++ [head l]
rotUp l = drop 1 l ++ take 1 l
rotDown :: [a] -> [a]
rotDown l = last l : init l
rotDown = reverse . rotUp . reverse

View File

@@ -0,0 +1,139 @@
{-# LANGUAGE DeriveDataTypeable #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.DynamicWorkspaceGroups
-- Copyright : (c) Brent Yorgey 2009
-- License : BSD-style (see LICENSE)
--
-- Maintainer : <byorgey@gmail.com>
-- Stability : experimental
-- Portability : unportable
--
-- Dynamically manage \"workspace groups\", sets of workspaces being
-- used together for some common task or purpose, to allow switching
-- between workspace groups in a single action. Note that this only
-- makes sense for multi-head setups.
--
-----------------------------------------------------------------------------
module XMonad.Actions.DynamicWorkspaceGroups
( -- * Usage
-- $usage
WSGroupId
, addWSGroup
, addCurrentWSGroup
, forgetWSGroup
, viewWSGroup
, promptWSGroupView
, promptWSGroupAdd
, promptWSGroupForget
, WSGPrompt
) where
import Data.List (find)
import Control.Arrow ((&&&))
import qualified Data.Map as M
import XMonad
import qualified XMonad.StackSet as W
import XMonad.Prompt
import qualified XMonad.Util.ExtensibleState as XS
-- $usage
-- You can use this module by importing it into your ~\/.xmonad\/xmonad.hs file:
--
-- > import XMonad.Actions.DynamicWorkspaceGroups
--
-- Then add keybindings like the following (this example uses
-- "XMonad.Util.EZConfig"-style keybindings, but this is not necessary):
--
-- > , ("M-y n", promptWSGroupAdd myXPConfig "Name this group: ")
-- > , ("M-y g", promptWSGroupView myXPConfig "Go to group: ")
-- > , ("M-y d", promptWSGroupForget myXPConfig "Forget group: ")
--
type WSGroup = [(ScreenId,WorkspaceId)]
type WSGroupId = String
data WSGroupStorage = WSG { unWSG :: M.Map WSGroupId WSGroup }
deriving (Typeable, Read, Show)
withWSG :: (M.Map WSGroupId WSGroup -> M.Map WSGroupId WSGroup) -> WSGroupStorage -> WSGroupStorage
withWSG f = WSG . f . unWSG
instance ExtensionClass WSGroupStorage where
initialValue = WSG $ M.empty
extensionType = PersistentExtension
-- | Add a new workspace group with the given name.
addWSGroup :: WSGroupId -> [WorkspaceId] -> X ()
addWSGroup name wids = withWindowSet $ \w -> do
let wss = map ((W.tag . W.workspace) &&& W.screen) $ W.screens w
wmap = mapM (strength . (flip lookup wss &&& id)) wids
case wmap of
Just ps -> XS.modify . withWSG . M.insert name $ ps
Nothing -> return ()
where strength (ma, b) = ma >>= \a -> return (a,b)
-- | Give a name to the current workspace group.
addCurrentWSGroup :: WSGroupId -> X ()
addCurrentWSGroup name = withWindowSet $ \w ->
addWSGroup name $ map (W.tag . W.workspace) (W.current w : W.visible w)
-- | Delete the named workspace group from the list of workspace
-- groups. Note that this has no effect on the workspaces involved;
-- it simply forgets the given name.
forgetWSGroup :: WSGroupId -> X ()
forgetWSGroup = XS.modify . withWSG . M.delete
-- | View the workspace group with the given name.
viewWSGroup :: WSGroupId -> X ()
viewWSGroup name = do
WSG m <- XS.get
case M.lookup name m of
Just grp -> mapM_ (uncurry viewWS) grp
Nothing -> return ()
-- | View the given workspace on the given screen.
viewWS :: ScreenId -> WorkspaceId -> X ()
viewWS sid wid = do
mw <- findScreenWS sid
case mw of
Just w -> do
windows $ W.view w
windows $ W.greedyView wid
Nothing -> return ()
-- | Find the workspace which is currently on the given screen.
findScreenWS :: ScreenId -> X (Maybe WorkspaceId)
findScreenWS sid = withWindowSet $
return . fmap (W.tag . W.workspace) . find ((==sid) . W.screen) . W.screens
data WSGPrompt = WSGPrompt String
instance XPrompt WSGPrompt where
showXPrompt (WSGPrompt s) = s
-- | Prompt for a workspace group to view.
promptWSGroupView :: XPConfig -> String -> X ()
promptWSGroupView xp s = do
gs <- fmap (M.keys . unWSG) XS.get
mkXPrompt (WSGPrompt s) xp (mkComplFunFromList' gs) viewWSGroup
-- | Prompt for a name for the current workspace group.
promptWSGroupAdd :: XPConfig -> String -> X ()
promptWSGroupAdd xp s =
mkXPrompt (WSGPrompt s) xp (const $ return []) addCurrentWSGroup
-- | Prompt for a workspace group to forget.
promptWSGroupForget :: XPConfig -> String -> X ()
promptWSGroupForget xp s = do
gs <- fmap (M.keys . unWSG) XS.get
mkXPrompt (WSGPrompt s) xp (mkComplFunFromList' gs) forgetWSGroup

View File

@@ -0,0 +1,178 @@
{-# LANGUAGE DeriveDataTypeable #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.DynamicWorkspaceOrder
-- Copyright : (c) Brent Yorgey 2009
-- License : BSD-style (see LICENSE)
--
-- Maintainer : <byorgey@gmail.com>
-- Stability : experimental
-- Portability : unportable
--
-- Remember a dynamically updateable ordering on workspaces, together
-- with tools for using this ordering with "XMonad.Actions.CycleWS"
-- and "XMonad.Hooks.DynamicLog".
--
-----------------------------------------------------------------------------
module XMonad.Actions.DynamicWorkspaceOrder
( -- * Usage
-- $usage
getWsCompareByOrder
, getSortByOrder
, swapWith
, moveTo
, moveToGreedy
, shiftTo
, withNthWorkspace
) where
import XMonad
import qualified XMonad.StackSet as W
import qualified XMonad.Util.ExtensibleState as XS
import XMonad.Util.WorkspaceCompare (WorkspaceCompare, WorkspaceSort, mkWsSort)
import XMonad.Actions.CycleWS (findWorkspace, WSType(..), Direction1D(..), doTo)
import qualified Data.Map as M
import qualified Data.Set as S
import Data.Maybe (fromJust, fromMaybe)
import Data.Ord (comparing)
-- $usage
-- You can use this module by importing it into your ~\/.xmonad\/xmonad.hs file:
--
-- > import qualified XMonad.Actions.DynamicWorkspaceOrder as DO
--
-- Then add keybindings to swap the order of workspaces (these
-- examples use "XMonad.Util.EZConfig" emacs-style keybindings):
--
-- > , ("M-C-<R>", DO.swapWith Next NonEmptyWS)
-- > , ("M-C-<L>", DO.swapWith Prev NonEmptyWS)
--
-- See "XMonad.Actions.CycleWS" for information on the possible
-- arguments to 'swapWith'.
--
-- However, by itself this will do nothing; 'swapWith' does not change
-- the actual workspaces in any way. It simply keeps track of an
-- auxiliary ordering on workspaces. Anything which cares about the
-- order of workspaces must be updated to use the auxiliary ordering.
--
-- To change the order in which workspaces are displayed by
-- "XMonad.Hooks.DynamicLog", use 'getSortByOrder' in your
-- 'XMonad.Hooks.DynamicLog.ppSort' field, for example:
--
-- > ... dynamicLogWithPP $ byorgeyPP {
-- > ...
-- > , ppSort = DO.getSortByOrder
-- > ...
-- > }
--
-- To use workspace cycling commands like those from
-- "XMonad.Actions.CycleWS", use the versions of 'moveTo',
-- 'moveToGreedy', and 'shiftTo' exported by this module. For example:
--
-- > , ("M-S-<R>", DO.shiftTo Next HiddenNonEmptyWS)
-- > , ("M-S-<L>", DO.shiftTo Prev HiddenNonEmptyWS)
-- > , ("M-<R>", DO.moveTo Next HiddenNonEmptyWS)
-- > , ("M-<L>", DO.moveTo Prev HiddenNonEmptyWS)
--
-- For slight variations on these, use the source for examples and
-- tweak as desired.
-- | Extensible state storage for the workspace order.
data WSOrderStorage = WSO { unWSO :: Maybe (M.Map WorkspaceId Int) }
deriving (Typeable, Read, Show)
instance ExtensionClass WSOrderStorage where
initialValue = WSO Nothing
extensionType = PersistentExtension
-- | Lift a Map function to a function on WSOrderStorage.
withWSO :: (M.Map WorkspaceId Int -> M.Map WorkspaceId Int)
-> (WSOrderStorage -> WSOrderStorage)
withWSO f = WSO . fmap f . unWSO
-- | Update the ordering storage: initialize if it doesn't yet exist;
-- add newly created workspaces at the end as necessary.
updateOrder :: X ()
updateOrder = do
WSO mm <- XS.get
case mm of
Nothing -> do
-- initialize using ordering of workspaces from the user's config
ws <- asks (workspaces . config)
XS.put . WSO . Just . M.fromList $ zip ws [0..]
Just m -> do
-- check for new workspaces and add them at the end
curWs <- gets (S.fromList . map W.tag . W.workspaces . windowset)
let mappedWs = M.keysSet m
newWs = curWs `S.difference` mappedWs
nextIndex = 1 + maximum (-1 : M.elems m)
newWsIxs = zip (S.toAscList newWs) [nextIndex..]
XS.modify . withWSO . M.union . M.fromList $ newWsIxs
-- | A comparison function which orders workspaces according to the
-- stored dynamic ordering.
getWsCompareByOrder :: X WorkspaceCompare
getWsCompareByOrder = do
updateOrder
-- after the call to updateOrder we are guaranteed that the dynamic
-- workspace order is initialized and contains all existing
-- workspaces.
WSO (Just m) <- XS.get
return $ comparing (fromMaybe 1000 . flip M.lookup m)
-- | Sort workspaces according to the stored dynamic ordering.
getSortByOrder :: X WorkspaceSort
getSortByOrder = mkWsSort getWsCompareByOrder
-- | Swap the current workspace with another workspace in the stored
-- dynamic order.
swapWith :: Direction1D -> WSType -> X ()
swapWith dir which = findWorkspace getSortByOrder dir which 1 >>= swapWithCurrent
-- | Swap the given workspace with the current one.
swapWithCurrent :: WorkspaceId -> X ()
swapWithCurrent w = do
cur <- gets (W.currentTag . windowset)
swapOrder w cur
-- | Swap the two given workspaces in the dynamic order.
swapOrder :: WorkspaceId -> WorkspaceId -> X ()
swapOrder w1 w2 = do
io $ print (w1,w2)
WSO (Just m) <- XS.get
let [i1,i2] = map (fromJust . flip M.lookup m) [w1,w2]
XS.modify (withWSO (M.insert w1 i2 . M.insert w2 i1))
windows id -- force a status bar update
-- | View the next workspace of the given type in the given direction,
-- where \"next\" is determined using the dynamic workspace order.
moveTo :: Direction1D -> WSType -> X ()
moveTo dir t = doTo dir t getSortByOrder (windows . W.view)
-- | Same as 'moveTo', but using 'greedyView' instead of 'view'.
moveToGreedy :: Direction1D -> WSType -> X ()
moveToGreedy dir t = doTo dir t getSortByOrder (windows . W.greedyView)
-- | Shift the currently focused window to the next workspace of the
-- given type in the given direction, using the dynamic workspace order.
shiftTo :: Direction1D -> WSType -> X ()
shiftTo dir t = doTo dir t getSortByOrder (windows . W.shift)
-- | Do something with the nth workspace in the dynamic order. The
-- callback is given the workspace's tag as well as the 'WindowSet'
-- of the workspace itself.
withNthWorkspace :: (String -> WindowSet -> WindowSet) -> Int -> X ()
withNthWorkspace job wnum = do
sort <- getSortByOrder
ws <- gets (map W.tag . sort . W.workspaces . windowset)
case drop wnum ws of
(w:_) -> windows $ job w
[] -> return ()

View File

@@ -8,31 +8,39 @@
-- Stability : unstable
-- Portability : unportable
--
-- Provides bindings to add and delete workspaces. Note that you may only
-- delete a workspace that is already empty.
-- Provides bindings to add and delete workspaces.
--
-----------------------------------------------------------------------------
module XMonad.Actions.DynamicWorkspaces (
-- * Usage
-- $usage
addWorkspace, removeWorkspace,
addWorkspace, addWorkspacePrompt,
removeWorkspace,
removeEmptyWorkspace,
removeEmptyWorkspaceAfter,
removeEmptyWorkspaceAfterExcept,
addHiddenWorkspace,
withWorkspace,
selectWorkspace, renameWorkspace,
renameWorkspaceByName,
toNthWorkspace, withNthWorkspace
) where
import XMonad hiding (workspaces)
import XMonad.StackSet hiding (filter, modify, delete)
import XMonad.Prompt.Workspace
import XMonad.Prompt ( XPConfig, mkXPrompt, XPrompt(..) )
import XMonad.Prompt.Workspace ( Wor(Wor), workspacePrompt )
import XMonad.Prompt ( XPConfig, mkXPrompt )
import XMonad.Util.WorkspaceCompare ( getSortByIndex )
import Data.List (find)
import Data.Maybe (isNothing)
import Control.Monad (when)
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@ file:
--
-- > import XMonad.Actions.DynamicWorkspaces
-- > import XMonad.Actions.CopyWindow(copy)
--
-- Then add keybindings like the following:
--
@@ -50,14 +58,10 @@ import XMonad.Util.WorkspaceCompare ( getSortByIndex )
-- > 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".
-- "XMonad.Doc.Extending#Editing_key_bindings". See also the documentation for
-- "XMonad.Actions.CopyWindow", 'windows', 'shift', and 'defaultXPConfig'.
data Wor = Wor String
instance XPrompt Wor where
showXPrompt (Wor x) = x
mkCompl :: [String] -> String -> IO [String]
mkCompl l s = return $ filter (\x -> take (length s) x == s) l
@@ -70,11 +74,13 @@ withWorkspace c job = do ws <- gets (workspaces . windowset)
mkXPrompt (Wor "") c (mkCompl ts) job'
renameWorkspace :: XPConfig -> X ()
renameWorkspace conf = workspacePrompt conf $ \w ->
windows $ \s -> let sett wk = wk { tag = w }
setscr scr = scr { workspace = sett $ workspace scr }
sets q = q { current = setscr $ current q }
in sets $ removeWorkspace' w s
renameWorkspace conf = workspacePrompt conf renameWorkspaceByName
renameWorkspaceByName :: String -> X ()
renameWorkspaceByName w = windows $ \s -> let sett wk = wk { tag = w }
setscr scr = scr { workspace = sett $ workspace scr }
sets q = q { current = setscr $ current q }
in sets $ removeWorkspace' w s
toNthWorkspace :: (String -> X ()) -> Int -> X ()
toNthWorkspace job wnum = do sort <- getSortByIndex
@@ -97,25 +103,68 @@ selectWorkspace conf = workspacePrompt conf $ \w ->
then windows $ greedyView w
else addWorkspace w
-- | Add a new workspace with the given name.
-- | Add a new workspace with the given name, or do nothing if a
-- workspace with the given name already exists; then switch to the
-- newly created workspace.
addWorkspace :: String -> X ()
addWorkspace newtag = addHiddenWorkspace newtag >> windows (greedyView newtag)
-- | Prompt for the name of a new workspace, add it if it does not
-- already exist, and switch to it.
addWorkspacePrompt :: XPConfig -> X ()
addWorkspacePrompt conf = mkXPrompt (Wor "New workspace name: ") conf (const (return [])) addWorkspace
-- | Add a new hidden workspace with the given name.
-- | Add a new hidden workspace with the given name, or do nothing if
-- a workspace with the given name already exists.
addHiddenWorkspace :: String -> X ()
addHiddenWorkspace newtag = do l <- asks (layoutHook . config)
windows (addHiddenWorkspace' newtag l)
addHiddenWorkspace newtag =
whenX (gets (not . tagMember newtag . windowset)) $ do
l <- asks (layoutHook . config)
windows (addHiddenWorkspace' newtag l)
-- | Remove the current workspace if it contains no windows.
removeEmptyWorkspace :: X ()
removeEmptyWorkspace = gets (currentTag . windowset) >>= removeEmptyWorkspaceByTag
-- | Remove the current workspace.
removeWorkspace :: X ()
removeWorkspace = do s <- gets windowset
case s of
StackSet { current = Screen { workspace = torem }
, hidden = (w:_) }
-> do windows $ view (tag w)
windows (removeWorkspace' (tag torem))
_ -> return ()
removeWorkspace = gets (currentTag . windowset) >>= removeWorkspaceByTag
-- | Remove workspace with specific tag if it contains no windows. Only works
-- on the current or the last workspace.
removeEmptyWorkspaceByTag :: String -> X ()
removeEmptyWorkspaceByTag t = whenX (isEmpty t) $ removeWorkspaceByTag t
-- | Remove workspace with specific tag. Only works on the current or the last workspace.
removeWorkspaceByTag :: String -> X ()
removeWorkspaceByTag torem = do
s <- gets windowset
case s of
StackSet { current = Screen { workspace = cur }, hidden = (w:_) } -> do
when (torem==tag cur) $ windows $ view $ tag w
windows $ removeWorkspace' torem
_ -> return ()
-- | Remove the current workspace after an operation if it is empty and hidden.
-- Can be used to remove a workspace if it is empty when leaving it. The
-- operation may only change workspace once, otherwise the workspace will not
-- be removed.
removeEmptyWorkspaceAfter :: X () -> X ()
removeEmptyWorkspaceAfter = removeEmptyWorkspaceAfterExcept []
-- | Like 'removeEmptyWorkspaceAfter' but use a list of sticky workspaces,
-- whose entries will never be removed.
removeEmptyWorkspaceAfterExcept :: [String] -> X () -> X ()
removeEmptyWorkspaceAfterExcept sticky f = do
before <- gets (currentTag . windowset)
f
after <- gets (currentTag . windowset)
when (before/=after && before `notElem` sticky) $ removeEmptyWorkspaceByTag before
isEmpty :: String -> X Bool
isEmpty t = do wsl <- gets $ workspaces . windowset
let mws = find (\ws -> tag ws == t) wsl
return $ maybe True (isNothing . stack) mws
addHiddenWorkspace' :: i -> l -> StackSet i l a sid sd -> StackSet i l a sid sd
addHiddenWorkspace' newtag l s@(StackSet { hidden = ws }) = s { hidden = Workspace newtag l Nothing:ws }

View File

@@ -15,7 +15,7 @@
module XMonad.Actions.FindEmptyWorkspace (
-- * Usage
-- $usage
viewEmptyWorkspace, tagToEmptyWorkspace
viewEmptyWorkspace, tagToEmptyWorkspace, sendToEmptyWorkspace
) where
import Data.List
@@ -65,3 +65,8 @@ viewEmptyWorkspace = withEmptyWorkspace (windows . view)
-- all workspaces are in use.
tagToEmptyWorkspace :: X ()
tagToEmptyWorkspace = withEmptyWorkspace $ \w -> windows $ view w . shift w
-- | Send current window to an empty workspace. Do nothing if
-- all workspaces are in use.
sendToEmptyWorkspace :: X ()
sendToEmptyWorkspace = withEmptyWorkspace $ \w -> windows $ shift w

View File

@@ -23,6 +23,8 @@ module XMonad.Actions.FlexibleManipulate (
) where
import XMonad
import qualified Prelude as P
import Prelude (($), (.), fst, snd, uncurry, const, id, Ord(..), Monad(..), fromIntegral, Double, Integer, map, round, otherwise)
-- $usage
-- First, add this import to your @~\/.xmonad\/xmonad.hs@:
@@ -84,7 +86,7 @@ mouseWindow f w = whenX (isClient w) $ withDisplay $ \d -> do
let uv = (pointer - wpos) / wsize
fc = mapP f uv
mul = mapP (\x -> 2 - 2 * abs(x - 0.5)) fc --Fudge factors: interpolation between 1 when on edge, 2 in middle
mul = mapP (\x -> 2 P.- 2 P.* P.abs(x P.- 0.5)) fc --Fudge factors: interpolation between 1 when on edge, 2 in middle
atl = ((1, 1) - fc) * mul
abr = fc * mul
mouseDrag (\ex ey -> io $ do
@@ -121,14 +123,13 @@ zipP f (ax,ay) (bx,by) = (f ax bx, f ay by)
minP :: Ord a => (a,a) -> (a,a) -> (a,a)
minP = zipP min
instance Num Pnt where
(+) = zipP (+)
(-) = zipP (-)
(*) = zipP (*)
abs = mapP abs
signum = mapP signum
fromInteger = const undefined
infixl 6 +, -
infixl 7 *, /
(+), (-), (*) :: (P.Num a) => (a,a) -> (a,a) -> (a,a)
(+) = zipP (P.+)
(-) = zipP (P.-)
(*) = zipP (P.*)
(/) :: (P.Fractional a) => (a,a) -> (a,a) -> (a,a)
(/) = zipP (P./)
instance Fractional Pnt where
fromRational = const undefined
recip = mapP recip

View File

@@ -20,6 +20,7 @@ module XMonad.Actions.FlexibleResize (
) where
import XMonad
import XMonad.Util.XUtils (fi)
import Foreign.C.Types
-- $usage
@@ -76,6 +77,3 @@ mouseResizeEdgeWindow edge w = whenX (isClient w) $ withDisplay $ \d -> do
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

@@ -17,7 +17,9 @@ module XMonad.Actions.FloatKeys (
keysMoveWindow,
keysMoveWindowTo,
keysResizeWindow,
keysAbsResizeWindow) where
keysAbsResizeWindow,
P, G,
) where
import XMonad

View File

@@ -28,7 +28,6 @@ module XMonad.Actions.GridSelect (
-- * Configuration
GSConfig(..),
defaultGSConfig,
NavigateMap,
TwoDPosition,
buildDefaultGSConfig,
@@ -38,6 +37,7 @@ module XMonad.Actions.GridSelect (
withSelectedWindow,
bringSelected,
goToSelected,
gridselectWorkspace,
spawnSelected,
runSelectedAction,
@@ -45,13 +45,36 @@ module XMonad.Actions.GridSelect (
HasColorizer(defaultColorizer),
fromClassName,
stringColorizer,
colorRangeFromClassName
colorRangeFromClassName,
-- * Navigation Mode assembly
TwoD,
makeXEventhandler,
shadowWithKeymap,
-- * Built-in Navigation Mode
defaultNavigation,
substringSearch,
navNSearch,
-- * Navigation Components
setPos,
move,
moveNext, movePrev,
select,
cancel,
transformSearchString,
-- * Screenshots
-- $screenshots
-- * Types
TwoDState,
) where
import Data.Maybe
import Data.Bits
import Data.Char
import Data.Ord (comparing)
import Control.Applicative
import Control.Monad.State
import Control.Arrow
@@ -92,13 +115,13 @@ import Data.Word (Word8)
-- > {-# LANGUAGE NoMonomorphismRestriction #-}
-- > import XMonad
-- > ...
-- > gsconfig1 = defaultGSConfig { gs_cellheight = 30, gs_cellWidth = 100 }
-- > gsconfig1 = defaultGSConfig { gs_cellheight = 30, gs_cellwidth = 100 }
--
-- An example where 'buildDefaultGSConfig' is used instead of 'defaultGSConfig'
-- in order to specify a custom colorizer is @gsconfig2@ (found in
-- "XMonad.Actions.GridSelect#Colorizers"):
--
-- > gsconfig2 colorizer = (buildDefaultGSConfig colorizer) { gs_cellheight = 30, gs_cellWidth = 100 }
-- > gsconfig2 colorizer = (buildDefaultGSConfig colorizer) { gs_cellheight = 30, gs_cellwidth = 100 }
--
-- > -- | A green monochrome colorizer based on window class
-- > greenColorizer = colorRangeFromClassName
@@ -117,45 +140,48 @@ import Data.Word (Word8)
-- $keybindings
--
-- Adding more keybindings for gridselect to listen to is similar:
-- You can build you own navigation mode and submodes by combining the
-- exported action ingredients and assembling them using 'makeXEventhandler' and 'shadowWithKeymap'.
--
-- At the top of your config:
-- > myNavigation :: TwoD a (Maybe a)
-- > myNavigation = makeXEventhandler $ shadowWithKeymap navKeyMap navDefaultHandler
-- > where navKeyMap = M.fromList [
-- > ((0,xK_Escape), cancel)
-- > ,((0,xK_Return), select)
-- > ,((0,xK_slash) , substringSearch myNavigation)
-- > ,((0,xK_Left) , move (-1,0) >> myNavigation)
-- > ,((0,xK_h) , move (-1,0) >> myNavigation)
-- > ,((0,xK_Right) , move (1,0) >> myNavigation)
-- > ,((0,xK_l) , move (1,0) >> myNavigation)
-- > ,((0,xK_Down) , move (0,1) >> myNavigation)
-- > ,((0,xK_j) , move (0,1) >> myNavigation)
-- > ,((0,xK_Up) , move (0,-1) >> myNavigation)
-- > ,((0,xK_y) , move (-1,-1) >> myNavigation)
-- > ,((0,xK_i) , move (1,-1) >> myNavigation)
-- > ,((0,xK_n) , move (-1,1) >> myNavigation)
-- > ,((0,xK_m) , move (1,-1) >> myNavigation)
-- > ,((0,xK_space) , setPos (0,0) >> myNavigation)
-- > ]
-- > -- The navigation handler ignores unknown key symbols
-- > navDefaultHandler = const myNavigation
--
-- > {-# LANGAUGE NoMonomorphismRestriction #-}
-- > import XMonad
-- > import qualified Data.Map as M
--
-- Then define @gsconfig3@ which may be used in exactly the same manner as @gsconfig1@:
-- You can 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
-- > ]
-- > , gs_navigate = myNavigation
-- > }
-- > 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>>
-- <<http://haskell.org/wikiupload/a/a9/Xmonad-gridselect-workspace.png>>
--
-- Selecting a window by title:
--
-- <<http://haskell.org/sitewiki/images/3/35/Xmonad-gridselect-window-aavogt.png>>
-- <<http://haskell.org/wikiupload/3/35/Xmonad-gridselect-window-aavogt.png>>
data GSConfig a = GSConfig {
gs_cellheight :: Integer,
@@ -163,7 +189,7 @@ data GSConfig a = GSConfig {
gs_cellpadding :: Integer,
gs_colorizer :: a -> Bool -> X (String, String),
gs_font :: String,
gs_navigate :: NavigateMap,
gs_navigate :: TwoD a (Maybe a),
gs_originFractX :: Double,
gs_originFractY :: Double
}
@@ -193,21 +219,56 @@ instance HasColorizer a where
defaultGSConfig :: HasColorizer a => GSConfig a
defaultGSConfig = buildDefaultGSConfig defaultColorizer
type NavigateMap = M.Map (KeyMask,KeySym) (TwoDPosition -> TwoDPosition)
type TwoDPosition = (Integer, Integer)
type TwoDElementMap a = [(TwoDPosition,(String,a))]
data TwoDState a = TwoDState { td_curpos :: TwoDPosition
, td_elementmap :: TwoDElementMap a
, td_availSlots :: [TwoDPosition]
, td_elements :: [(String,a)]
, td_gsconfig :: GSConfig a
, td_font :: XMonadFont
, td_paneX :: Integer
, td_paneY :: Integer
, td_drawingWin :: Window
, td_searchString :: String
}
td_elementmap :: TwoDState a -> [(TwoDPosition,(String,a))]
td_elementmap s = zipWith (,) positions sortedElements
where
TwoDState {td_availSlots = positions,
td_searchString = searchString} = s
-- Filter out any elements that don't contain the searchString (case insensitive)
filteredElements = L.filter ((searchString `isInfixOfI`) . fst) (td_elements s)
-- Sorts the elementmap
sortedElements = orderElementmap searchString filteredElements
-- Case Insensitive version of isInfixOf
needle `isInfixOfI` haystack = (upper needle) `isInfixOf` (upper haystack)
upper = map toUpper
-- | We enforce an ordering such that we will always get the same result. If the
-- elements position changes from call to call of gridselect, then the shown
-- positions will also change when you search for the same string. This is
-- especially the case when using gridselect for showing and switching between
-- workspaces, as workspaces are usually shown in order of last visited. The
-- chosen ordering is "how deep in the haystack the needle is" (number of
-- characters from the beginning of the string and the needle).
orderElementmap :: String -> [(String,a)] -> [(String,a)]
orderElementmap searchString elements = if not $ null searchString then sortedElements else elements
where
upper = map toUpper
-- Calculates a (score, element) tuple where the score is the depth of the (case insensitive) needle.
calcScore element = ( length $ takeWhile (not . isPrefixOf (upper searchString)) (tails . upper . fst $ element)
, element)
-- Use the score and then the string as the parameters for comparing, making
-- it consistent even when two strings that score the same, as it will then be
-- sorted by the strings, making it consistent.
compareScore = comparing (\(score, (str,_)) -> (score, str))
sortedElements = map snd . sortBy compareScore $ map calcScore elements
newtype TwoD a b = TwoD { unTwoD :: StateT (TwoDState a) X b }
deriving (Monad,Functor,MonadState (TwoDState a))
@@ -221,14 +282,16 @@ 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
diamondLayer n = let ul = [ (x,n-x) | x <- [0..n] ]
in nub $ ul ++ (map (negate *** id) ul) ++
(map (negate *** negate) ul) ++
(map (id *** negate) ul)
diamondLayer :: (Enum a, Num a, Eq a) => a -> [(a, a)]
diamondLayer 0 = [(0,0)]
diamondLayer n =
-- tr = top right
-- r = ur ++ 90 degree clock-wise rotation of ur
let tr = [ (x,n-x) | x <- [0..n-1] ]
r = tr ++ (map (\(x,y) -> (y,-x)) tr)
in r ++ (map (negate *** negate) r)
diamond :: (Enum a, Num a) => [(a, a)]
diamond :: (Enum a, Num a, Eq a) => [(a, a)]
diamond = concatMap diamondLayer [0..]
diamondRestrict :: Integer -> Integer -> Integer -> Integer -> [(Integer, Integer)]
@@ -237,9 +300,6 @@ diamondRestrict x y originX originY =
map (\(x', y') -> (x' + fromInteger originX, y' + fromInteger originY)) .
take 1000 $ diamond
tupadd :: (Num t1, Num t) => (t, t1) -> (t, t1) -> (t, t1)
tupadd (a,b) (c,d) = (a+c,b+d)
findInElementMap :: (Eq a) => a -> [(a, b)] -> Maybe (a, b)
findInElementMap pos = find ((== pos) . fst)
@@ -268,11 +328,23 @@ drawWinBox win font (fg,bg) ch cw text x y cp =
updateAllElements :: TwoD a ()
updateAllElements =
do
TwoDState { td_elementmap = els } <- get
updateElements els
s <- get
updateElements (td_elementmap s)
grayoutAllElements :: TwoD a ()
grayoutAllElements =
do
s <- get
updateElementsWithColorizer grayOnly (td_elementmap s)
where grayOnly _ _ = return ("#808080", "#808080")
updateElements :: TwoDElementMap a -> TwoD a ()
updateElements elementmap = do
s <- get
updateElementsWithColorizer (gs_colorizer (td_gsconfig s)) elementmap
updateElementsWithColorizer :: (a -> Bool -> X (String, String)) -> TwoDElementMap a -> TwoD a ()
updateElementsWithColorizer colorizer elementmap = do
TwoDState { td_curpos = curpos,
td_drawingWin = win,
td_gsconfig = gsconfig,
@@ -284,7 +356,7 @@ updateElements elementmap = do
paneX' = div (paneX-cellwidth) 2
paneY' = div (paneY-cellheight) 2
updateElement (pos@(x,y),(text, element)) = liftX $ do
colors <- gs_colorizer gsconfig element (pos == curpos)
colors <- colorizer element (pos == curpos)
drawWinBox win font
colors
cellheight
@@ -295,52 +367,180 @@ updateElements elementmap = do
(gs_cellpadding gsconfig)
mapM_ updateElement elementmap
eventLoop :: TwoD a (Maybe a)
eventLoop = do
(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
else return (Nothing, "")
return (ks,s,ev)
handle (fromMaybe xK_VoidSymbol keysym,string) event
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_Return = do
(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 elmap = td_elementmap state
oldPos = td_curpos state
newPos = diff oldPos
newSelectedEl = findInElementMap newPos elmap
when (isJust newSelectedEl) $ do
put state { td_curpos = newPos }
updateElements (catMaybes [(findInElementMap oldPos elmap), newSelectedEl])
eventLoop
handle _ (ButtonEvent { ev_event_type = t, ev_x = x, ev_y = y })
stdHandle :: Event -> TwoD a (Maybe a) -> TwoD a (Maybe a)
stdHandle (ButtonEvent { ev_event_type = t, ev_x = x, ev_y = y }) contEventloop
| t == buttonRelease = do
(TwoDState { td_elementmap = elmap, td_paneX = px, td_paneY = py,
td_gsconfig = (GSConfig ch cw _ _ _ _ _ _) }) <- get
s @ TwoDState { 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
case lookup (gridX,gridY) (td_elementmap s) of
Just (_,el) -> return (Just el)
Nothing -> eventLoop
| otherwise = eventLoop
Nothing -> contEventloop
| otherwise = contEventloop
handle _ (ExposeEvent { }) = updateAllElements >> eventLoop
stdHandle (ExposeEvent { }) contEventloop = updateAllElements >> contEventloop
stdHandle _ contEventloop = contEventloop
-- | Embeds a key handler into the X event handler that dispatches key
-- events to the key handler, while non-key event go to the standard
-- handler.
makeXEventhandler :: ((KeySym, String, KeyMask) -> TwoD a (Maybe a)) -> TwoD a (Maybe a)
makeXEventhandler keyhandler = fix $ \me -> join $ liftX $ withDisplay $ \d -> liftIO $ allocaXEvent $ \e -> do
maskEvent d (exposureMask .|. keyPressMask .|. buttonReleaseMask) e
ev <- getEvent e
if ev_event_type ev == keyPress
then do
(ks,s) <- lookupString $ asKeyEvent e
return $ do
mask <- liftX $ cleanMask (ev_state ev)
keyhandler (fromMaybe xK_VoidSymbol ks, s, mask)
else
return $ stdHandle ev me
-- | When the map contains (KeySym,KeyMask) tuple for the given event,
-- the associated action in the map associated shadows the default key
-- handler
shadowWithKeymap :: M.Map (KeyMask, KeySym) a -> ((KeySym, String, KeyMask) -> a) -> (KeySym, String, KeyMask) -> a
shadowWithKeymap keymap dflt keyEvent@(ks,_,m') = fromMaybe (dflt keyEvent) (M.lookup (m',ks) keymap)
-- Helper functions to use for key handler functions
-- | Closes gridselect returning the element under the cursor
select :: TwoD a (Maybe a)
select = do
s <- get
return $ fmap (snd . snd) $ findInElementMap (td_curpos s) (td_elementmap s)
-- | Closes gridselect returning no element.
cancel :: TwoD a (Maybe a)
cancel = return Nothing
-- | Sets the absolute position of the cursor.
setPos :: (Integer, Integer) -> TwoD a ()
setPos newPos = do
s <- get
let elmap = td_elementmap s
newSelectedEl = findInElementMap newPos (td_elementmap s)
oldPos = td_curpos s
when (isJust newSelectedEl && newPos /= oldPos) $ do
put s { td_curpos = newPos }
updateElements (catMaybes [(findInElementMap oldPos elmap), newSelectedEl])
-- | Moves the cursor by the offsets specified
move :: (Integer, Integer) -> TwoD a ()
move (dx,dy) = do
s <- get
let (x,y) = td_curpos s
newPos = (x+dx,y+dy)
setPos newPos
moveNext :: TwoD a ()
moveNext = do
position <- gets td_curpos
elems <- gets td_elementmap
let n = length elems
m = case findIndex (\p -> fst p == position) elems of
Nothing -> Nothing
Just k | k == n-1 -> Just 0
| otherwise -> Just (k+1)
whenJust m $ \i ->
setPos (fst $ elems !! i)
movePrev :: TwoD a ()
movePrev = do
position <- gets td_curpos
elems <- gets td_elementmap
let n = length elems
m = case findIndex (\p -> fst p == position) elems of
Nothing -> Nothing
Just 0 -> Just (n-1)
Just k -> Just (k-1)
whenJust m $ \i ->
setPos (fst $ elems !! i)
-- | Apply a transformation function the current search string
transformSearchString :: (String -> String) -> TwoD a ()
transformSearchString f = do
s <- get
let oldSearchString = td_searchString s
newSearchString = f oldSearchString
when (newSearchString /= oldSearchString) $ do
-- FIXME: grayoutAllElements + updateAllElements paint some fields twice causing flickering
-- we would need a much smarter update strategy to fix that
when (length newSearchString > length oldSearchString) grayoutAllElements
-- FIXME curpos might end up outside new bounds
put s { td_searchString = newSearchString }
updateAllElements
-- | By default gridselect used the defaultNavigation action, which
-- binds left,right,up,down and vi-style h,l,j,k navigation. Return
-- quits gridselect, returning the selected element, while Escape
-- cancels the selection. Slash enters the substring search mode. In
-- substring search mode, every string-associated keystroke is
-- added to a search string, which narrows down the object
-- selection. Substring search mode comes back to regular navigation
-- via Return, while Escape cancels the search. If you want that
-- navigation style, add 'defaultNavigation' as 'gs_navigate' to your
-- 'GSConfig' object. This is done by 'buildDefaultGSConfig' automatically.
defaultNavigation :: TwoD a (Maybe a)
defaultNavigation = makeXEventhandler $ shadowWithKeymap navKeyMap navDefaultHandler
where navKeyMap = M.fromList [
((0,xK_Escape) , cancel)
,((0,xK_Return) , select)
,((0,xK_slash) , substringSearch defaultNavigation)
,((0,xK_Left) , move (-1,0) >> defaultNavigation)
,((0,xK_h) , move (-1,0) >> defaultNavigation)
,((0,xK_Right) , move (1,0) >> defaultNavigation)
,((0,xK_l) , move (1,0) >> defaultNavigation)
,((0,xK_Down) , move (0,1) >> defaultNavigation)
,((0,xK_j) , move (0,1) >> defaultNavigation)
,((0,xK_Up) , move (0,-1) >> defaultNavigation)
,((0,xK_k) , move (0,-1) >> defaultNavigation)
,((0,xK_Tab) , moveNext >> defaultNavigation)
,((0,xK_n) , moveNext >> defaultNavigation)
,((shiftMask,xK_Tab), movePrev >> defaultNavigation)
,((0,xK_p) , movePrev >> defaultNavigation)
]
-- The navigation handler ignores unknown key symbols, therefore we const
navDefaultHandler = const defaultNavigation
-- | This navigation style combines navigation and search into one mode at the cost of losing vi style
-- navigation. With this style, there is no substring search submode,
-- but every typed character is added to the substring search.
navNSearch :: TwoD a (Maybe a)
navNSearch = makeXEventhandler $ shadowWithKeymap navNSearchKeyMap navNSearchDefaultHandler
where navNSearchKeyMap = M.fromList [
((0,xK_Escape) , cancel)
,((0,xK_Return) , select)
,((0,xK_Left) , move (-1,0) >> navNSearch)
,((0,xK_Right) , move (1,0) >> navNSearch)
,((0,xK_Down) , move (0,1) >> navNSearch)
,((0,xK_Up) , move (0,-1) >> navNSearch)
,((0,xK_Tab) , moveNext >> navNSearch)
,((shiftMask,xK_Tab), movePrev >> navNSearch)
,((0,xK_BackSpace), transformSearchString (\s -> if (s == "") then "" else init s) >> navNSearch)
]
-- The navigation handler ignores unknown key symbols, therefore we const
navNSearchDefaultHandler (_,s,_) = do
transformSearchString (++ s)
navNSearch
-- | Navigation submode used for substring search. It returns to the
-- first argument navigation style when the user hits Return.
substringSearch :: TwoD a (Maybe a) -> TwoD a (Maybe a)
substringSearch returnNavigation = fix $ \me ->
let searchKeyMap = M.fromList [
((0,xK_Escape) , transformSearchString (const "") >> returnNavigation)
,((0,xK_Return) , returnNavigation)
,((0,xK_BackSpace), transformSearchString (\s -> if (s == "") then "" else init s) >> me)
]
searchDefaultHandler (_,s,_) = do
transformSearchString (++ s)
me
in makeXEventhandler $ shadowWithKeymap searchKeyMap searchDefaultHandler
handle _ _ = eventLoop
-- FIXME probably move that into Utils?
-- Conversion scheme as in http://en.wikipedia.org/wiki/HSV_color_space
@@ -418,7 +618,8 @@ stringToRatio s = let gen = mkStdGen $ sum $ map fromEnum s
-- | Brings up a 2D grid of elements in the center of the screen, and one can
-- select an element with cursors keys. The selected element is returned.
gridselect :: GSConfig a -> [(String,a)] -> X (Maybe a)
gridselect gsconfig elmap =
gridselect _ [] = return Nothing
gridselect gsconfig elements =
withDisplay $ \dpy -> do
rootw <- asks theRoot
s <- gets $ screenRect . W.screenDetail . W.current . windowset
@@ -438,16 +639,16 @@ gridselect gsconfig elmap =
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)
evalTwoD (updateAllElements >> (gs_navigate gsconfig)) TwoDState { td_curpos = (head coords),
td_availSlots = coords,
td_elements = elements,
td_gsconfig = gsconfig,
td_font = font,
td_paneX = screenWidth,
td_paneY = screenHeight,
td_drawingWin = win,
td_searchString = "" }
else
return Nothing
liftIO $ do
@@ -484,19 +685,7 @@ decorateName' w = do
-- | 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))
]
buildDefaultGSConfig col = GSConfig 50 130 10 col "xft:Sans-8" defaultNavigation (1/2) (1/2)
borderColor :: String
borderColor = "white"
@@ -523,3 +712,15 @@ runSelectedAction conf actions = do
case selectedActionM of
Just selectedAction -> selectedAction
Nothing -> return ()
-- | Select a workspace and view it using the given function
-- (normally 'W.view' or 'W.greedyView')
--
-- Another option is to shift the current window to the selected workspace:
--
-- > gridselectWorkspace (\ws -> W.greedyView ws . W.shift ws)
gridselectWorkspace :: GSConfig WorkspaceId ->
(WorkspaceId -> WindowSet -> WindowSet) -> X ()
gridselectWorkspace conf viewFunc = withWindowSet $ \ws -> do
let wss = map W.tag $ W.hidden ws ++ map W.workspace (W.current ws : W.visible ws)
gridselect conf (zip wss wss) >>= flip whenJust (windows . viewFunc)

View File

@@ -0,0 +1,218 @@
{-# LANGUAGE DeriveDataTypeable #-}
----------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.GroupNavigation
-- Copyright : (c) nzeh@cs.dal.ca
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : nzeh@cs.dal.ca
-- Stability : unstable
-- Portability : unportable
--
-- Provides methods for cycling through groups of windows across
-- workspaces, ignoring windows that do not belong to this group. A
-- group consists of all windows matching a user-provided boolean
-- query.
--
-- Also provides a method for jumping back to the most recently used
-- window in any given group.
--
----------------------------------------------------------------------
module XMonad.Actions.GroupNavigation ( -- * Usage
-- $usage
Direction (..)
, nextMatch
, nextMatchOrDo
, nextMatchWithThis
, historyHook
) where
import Control.Monad.Reader
import Data.Foldable as Fold
import Data.Map as Map
import Data.Sequence as Seq
import Data.Set as Set
import Graphics.X11.Types
import Prelude hiding (concatMap, drop, elem, filter, null, reverse)
import XMonad.Core
import XMonad.ManageHook
import XMonad.Operations (windows, withFocused)
import qualified XMonad.StackSet as SS
import qualified XMonad.Util.ExtensibleState as XS
{- $usage
Import the module into your @~\/.xmonad\/xmonad.hs@:
> import XMonad.Actions.GroupNavigation
To support cycling forward and backward through all xterm windows, add
something like this to your keybindings:
> , ((modm , xK_t), nextMatch Forward (className =? "XTerm"))
> , ((modm .|. shiftMask, xK_t), nextMatch Backward (className =? "XTerm"))
These key combinations do nothing if there is no xterm window open.
If you rather want to open a new xterm window if there is no open
xterm window, use 'nextMatchOrDo' instead:
> , ((modm , xK_t), nextMatchOrDo Forward (className =? "XTerm") (spawn "xterm"))
> , ((modm .|. shiftMask, xK_t), nextMatchOrDo Backward (className =? "XTerm") (spawn "xterm"))
You can use 'nextMatchWithThis' with an arbitrary query to cycle
through all windows for which this query returns the same value as the
current window. For example, to cycle through all windows in the same
window class as the current window use:
> , ((modm , xK_f), nextMatchWithThis Forward className)
> , ((modm , xK_b), nextMatchWithThis Backward className)
Finally, you can define keybindings to jump to the most recent window
matching a certain Boolean query. To do this, you need to add
'historyHook' to your logHook:
> main = xmonad $ defaultConfig { logHook = historyHook }
Then the following keybindings, for example, allow you to return to
the most recent xterm or emacs window or to simply to the most recent
window:
> , ((modm .|. controlMask, xK_e), nextMatch History (className =? "Emacs"))
> , ((modm .|. controlMask, xK_t), nextMatch History (className =? "XTerm"))
> , ((modm , xK_BackSpace), nextMatch History (return True))
Again, you can use 'nextMatchOrDo' instead of 'nextMatch' if you want
to execute an action if no window matching the query exists. -}
--- Basic cyclic navigation based on queries -------------------------
-- | The direction in which to look for the next match
data Direction = Forward -- ^ Forward from current window or workspace
| Backward -- ^ Backward from current window or workspace
| History -- ^ Backward in history
-- | Focuses the next window for which the given query produces the
-- same result as the currently focused window. Does nothing if there
-- is no focused window (i.e., the current workspace is empty).
nextMatchWithThis :: Eq a => Direction -> Query a -> X ()
nextMatchWithThis dir qry = withFocused $ \win -> do
prop <- runQuery qry win
nextMatch dir (qry =? prop)
-- | Focuses the next window that matches the given boolean query.
-- Does nothing if there is no such window. This is the same as
-- 'nextMatchOrDo' with alternate action @return ()@.
nextMatch :: Direction -> Query Bool -> X ()
nextMatch dir qry = nextMatchOrDo dir qry (return ())
-- | Focuses the next window that matches the given boolean query. If
-- there is no such window, perform the given action instead.
nextMatchOrDo :: Direction -> Query Bool -> X () -> X ()
nextMatchOrDo dir qry act = orderedWindowList dir
>>= focusNextMatchOrDo qry act
-- Produces the action to perform depending on whether there's a
-- matching window
focusNextMatchOrDo :: Query Bool -> X () -> Seq Window -> X ()
focusNextMatchOrDo qry act = findM (runQuery qry)
>=> maybe act (windows . SS.focusWindow)
-- Returns the list of windows ordered by workspace as specified in
-- ~/.xmonad/xmonad.hs
orderedWindowList :: Direction -> X (Seq Window)
orderedWindowList History = liftM (\(HistoryDB w ws) -> maybe ws (ws |>) w) XS.get
orderedWindowList dir = withWindowSet $ \ss -> do
wsids <- asks (Seq.fromList . workspaces . config)
let wspcs = orderedWorkspaceList ss wsids
wins = dirfun dir
$ Fold.foldl' (><) Seq.empty
$ fmap (Seq.fromList . SS.integrate' . SS.stack) wspcs
cur = SS.peek ss
return $ maybe wins (rotfun wins) cur
where
dirfun Backward = Seq.reverse
dirfun _ = id
rotfun wins x = rotate $ rotateTo (== x) wins
-- Returns the ordered workspace list as specified in ~/.xmonad/xmonad.hs
orderedWorkspaceList :: WindowSet -> Seq String -> Seq WindowSpace
orderedWorkspaceList ss wsids = rotateTo isCurWS wspcs'
where
wspcs = SS.workspaces ss
wspcsMap = Fold.foldl' (\m ws -> Map.insert (SS.tag ws) ws m) Map.empty wspcs
wspcs' = fmap (\wsid -> wspcsMap ! wsid) wsids
isCurWS ws = SS.tag ws == SS.tag (SS.workspace $ SS.current ss)
--- History navigation, requires a layout modifier -------------------
-- The state extension that holds the history information
data HistoryDB = HistoryDB (Maybe Window) -- currently focused window
(Seq Window) -- previously focused windows
deriving (Read, Show, Typeable)
instance ExtensionClass HistoryDB where
initialValue = HistoryDB Nothing Seq.empty
extensionType = PersistentExtension
-- | Action that needs to be executed as a logHook to maintain the
-- focus history of all windows as the WindowSet changes.
historyHook :: X ()
historyHook = XS.get >>= updateHistory >>= XS.put
-- Updates the history in response to a WindowSet change
updateHistory :: HistoryDB -> X HistoryDB
updateHistory (HistoryDB oldcur oldhist) = withWindowSet $ \ss -> do
let newcur = SS.peek ss
wins = Set.fromList $ SS.allWindows ss
newhist = flt (flip Set.member wins) (ins oldcur oldhist)
return $ HistoryDB newcur (del newcur newhist)
where
ins x xs = maybe xs (<| xs) x
del x xs = maybe xs (\x' -> flt (/= x') xs) x
--- Two replacements for Seq.filter and Seq.breakl available only in
--- containers-0.3.0.0, which only ships with ghc 6.12. Once we
--- decide to no longer support ghc < 6.12, these should be replaced
--- with Seq.filter and Seq.breakl.
flt :: (a -> Bool) -> Seq a -> Seq a
flt p = Fold.foldl (\xs x -> if p x then xs |> x else xs) Seq.empty
brkl :: (a -> Bool) -> Seq a -> (Seq a, Seq a)
brkl p xs = flip Seq.splitAt xs
$ snd
$ Fold.foldr (\x (i, j) -> if p x then (i-1, i-1) else (i-1, j)) (l, l) xs
where
l = Seq.length xs
--- Some sequence helpers --------------------------------------------
-- Rotates the sequence by one position
rotate :: Seq a -> Seq a
rotate xs = rotate' (viewl xs)
where
rotate' EmptyL = Seq.empty
rotate' (x' :< xs') = xs' |> x'
-- Rotates the sequence until an element matching the given condition
-- is at the beginning of the sequence.
rotateTo :: (a -> Bool) -> Seq a -> Seq a
rotateTo cond xs = let (lxs, rxs) = brkl cond xs in rxs >< lxs
--- A monadic find ---------------------------------------------------
-- Applies the given action to every sequence element in turn until
-- the first element is found for which the action returns true. The
-- remaining elements in the sequence are ignored.
findM :: Monad m => (a -> m Bool) -> Seq a -> m (Maybe a)
findM cond xs = findM' cond (viewl xs)
where
findM' _ EmptyL = return Nothing
findM' qry (x' :< xs') = do
isMatch <- qry x'
if isMatch
then return (Just x')
else findM qry xs'

156
XMonad/Actions/KeyRemap.hs Normal file
View File

@@ -0,0 +1,156 @@
{-# LANGUAGE DeriveDataTypeable #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.KeyRemap
-- Copyright : (c) Christian Dietrich
-- License : BSD-style (as xmonad)
--
-- Maintainer : stettberger@dokucde.de
-- Stability : unstable
-- Portability : unportable
--
-- Remap Keybinding on the fly, e.g having Dvorak char, but everything with Control/Shift
-- is left us Layout
--
-----------------------------------------------------------------------------
module XMonad.Actions.KeyRemap (
-- * Usage
-- $usage
setKeyRemap,
buildKeyRemapBindings,
setDefaultKeyRemap,
KeymapTable (KeymapTable),
emptyKeyRemap,
dvorakProgrammerKeyRemap
) where
import XMonad
import XMonad.Util.Paste
import Data.List
import qualified XMonad.Util.ExtensibleState as XS
import Control.Monad
data KeymapTable = KeymapTable [((KeyMask, KeySym), (KeyMask, KeySym))] deriving (Typeable, Show)
instance ExtensionClass KeymapTable where
initialValue = KeymapTable []
-- $usage
-- Provides the possibility to remap parts of the keymap to generate different keys
--
-- * E.g You want to type Programmers Dvorak, but your keybindings should be the normal us layout
-- after all
--
-- First, you must add all possible keybindings for all layout you want to use:
--
-- > keys = myKeys ++ buildKeyRemapBindings [dvorakProgrammerKeyRemap,emptyKeyRemap]
--
-- Then you must add setDefaultKeyRemap to your startup hook (e.g. you want to set the
-- empty keyremap (no remapping is done) as default after startup):
--
-- > myStartupHook :: X()
-- > myStartupHook = do
-- > setWMName "LG3D"
-- > setDefaultKeyRemap emptyKeyRemap [dvorakProgrammerKeyRemap, emptyKeyRemap]
--
-- Then you add keybindings for changing keyboard layouts;
--
-- > , ((0 , xK_F1 ), setKeyRemap emptyKeyRemap)
-- > , ((0 , xK_F2 ), setKeyRemap dvorakProgrammerKeyRemap)
--
-- When defining your own keymappings, please be aware of:
--
-- * If you want to emulate a key that is shifted on us you must emulate that keypress:
--
-- > KeymapTable [((0, xK_a), (shiftMask, xK_5))] -- would bind 'a' to '%'
-- > KeymapTable [((shiftMask, xK_a), (0, xK_5))] -- would bind 'A' to '5'
--
-- * the dvorakProgrammerKeyRemap uses the original us layout as lookuptable to generate
-- the KeymapTable
--
-- * KeySym and (ord Char) are incompatible, therefore the magic numbers in dvorakProgrammerKeyRemap
-- are nessesary
doKeyRemap :: KeyMask -> KeySym -> X()
doKeyRemap mask sym = do
table <- XS.get
let (insertMask, insertSym) = extractKeyMapping table mask sym
sendKey insertMask insertSym
-- | Using this in the keybindings to set the actual Key Translation table
setKeyRemap :: KeymapTable -> X()
setKeyRemap table = do
let KeymapTable newtable = table
KeymapTable oldtable <- XS.get
XConf { display = dpy, theRoot = rootw } <- ask
let grab kc m = io $ grabKey dpy kc m rootw True grabModeAsync grabModeAsync
let ungrab kc m = io $ ungrabKey dpy kc m rootw
forM_ oldtable $ \((mask, sym), _) -> do
kc <- io $ keysymToKeycode dpy sym
-- "If the specified KeySym is not defined for any KeyCode,
-- XKeysymToKeycode() returns zero."
when (kc /= 0) $ ungrab kc mask
forM_ newtable $ \((mask, sym), _) -> do
kc <- io $ keysymToKeycode dpy sym
-- "If the specified KeySym is not defined for any KeyCode,
-- XKeysymToKeycode() returns zero."
when (kc /= 0) $ grab kc mask
XS.put table
-- | Adding this to your startupHook, to select your default Key Translation table.
-- You also must give it all the KeymapTables you are willing to use
setDefaultKeyRemap :: KeymapTable -> [KeymapTable] -> X()
setDefaultKeyRemap dflt keyremaps = do
XS.put (KeymapTable mappings)
setKeyRemap dflt
where
mappings = nub (keyremaps >>= \(KeymapTable table) -> table)
extractKeyMapping :: KeymapTable -> KeyMask -> KeySym -> (KeyMask, KeySym)
extractKeyMapping (KeymapTable table) mask sym =
insertKey filtered
where filtered = filter (\((m, s),_) -> m == mask && s == sym) table
insertKey [] = (mask, sym)
insertKey ((_, to):_) = to
-- | Append the output of this function to your keybindings with ++
buildKeyRemapBindings :: [KeymapTable] -> [((KeyMask, KeySym), X ())]
buildKeyRemapBindings keyremaps =
[((mask, sym), doKeyRemap mask sym) | (mask, sym) <- bindings]
where mappings = concat (map (\(KeymapTable table) -> table) keyremaps)
bindings = nub (map (\binding -> fst binding) mappings)
-- Here come the Keymappings
-- | The empty KeymapTable, does no translation
emptyKeyRemap :: KeymapTable
emptyKeyRemap = KeymapTable []
-- | The dvorak Programmers keymap, translates from us keybindings to dvorak programmers
dvorakProgrammerKeyRemap :: KeymapTable
dvorakProgrammerKeyRemap =
KeymapTable [((charToMask maskFrom, from), (charToMask maskTo, to)) |
(maskFrom, from, maskTo, to) <- (zip4 layoutUsShift layoutUsKey layoutDvorakShift layoutDvorakKey)]
where
layoutUs = map (fromIntegral . fromEnum) "`1234567890-=qwertyuiop[]\\asdfghjkl;'zxcvbnm,./~!@#$%^&*()_+QWERTYUIOP{}|ASDFGHJKL:\"ZXCVBNM<>?" :: [KeySym]
layoutUsKey = map (fromIntegral . fromEnum) "`1234567890-=qwertyuiop[]\\asdfghjkl;'zxcvbnm,./`1234567890-=qwertyuiop[]\\asdfghjkl;'zxcvbnm,./" :: [KeySym]
layoutUsShift = "0000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111"
layoutDvorak = map (fromIntegral . fromEnum) "$&[{}(=*)+]!#;,.pyfgcrl/@\\aoeuidhtns-'qjkxbmwvz~%7531902468`:<>PYFGCRL?^|AOEUIDHTNS_\"QJKXBMWVZ" :: [KeySym]
layoutDvorakShift = map getShift layoutDvorak
layoutDvorakKey = map getKey layoutDvorak
getKey char = let Just index = elemIndex char layoutUs
in layoutUsKey !! index
getShift char = let Just index = elemIndex char layoutUs
in layoutUsShift !! index
charToMask char = if [char] == "0" then 0 else shiftMask

123
XMonad/Actions/Launcher.hs Normal file
View File

@@ -0,0 +1,123 @@
{- |
Module : XMonad.Actions.Launcher
Copyright : (C) 2012 Carlos López-Camey
License : None; public domain
Maintainer : <c.lopez@kmels.net>
Stability : unstable
A set of prompts for XMonad
-}
module XMonad.Actions.Launcher(
-- * Description and use
-- $description
defaultLauncherModes
, ExtensionActions
, LauncherConfig(..)
, launcherPrompt
) where
import Data.List (find, findIndex, isPrefixOf, tails)
import qualified Data.Map as M
import Data.Maybe (isJust)
import XMonad hiding (config)
import XMonad.Prompt
import XMonad.Util.Run
{- $description
This module exemplifies usage of `XMonad.Prompt.mkXPromptWithModes`. It includes two modes:
* Hoogle mode: Search for functions using hoogle, choosing a function leads you to documentation in Haddock.
* Calc: Uses the program calc to do calculations.
To test it, modify your local .xmonad:
> import XMonad.Prompt(defaultXPConfig)
> import XMonad.Actions.Launcher
> ((modm .|. controlMask, xK_l), launcherPrompt defaultXPConfig $ defaultLauncherModes launcherConfig)
A LauncherConfig contains settings for the default modes, modify them accordingly.
> launcherConfig = LauncherConfig { pathToHoogle = "/home/YOU/.cabal/bin/hoogle" , browser = "firefox"}
Restart xmonad. Press Ctrl + Your_Modkey + L and the first prompt should pop up.
If you used 'defaultXPConfig', you can change mode with 'xK_grave'. If you are using your own 'XPConfig', define the value for 'changeModeKey'.
-}
data HoogleMode = HMode FilePath String --path to hoogle and browser
data CalculatorMode = CalcMode
data LauncherConfig = LauncherConfig {
browser :: String
, pathToHoogle :: String
}
type ExtensionActions = M.Map String (String -> X())
-- | Uses the command `calc` to compute arithmetic expressions
instance XPrompt CalculatorMode where
showXPrompt CalcMode = "calc %s> "
commandToComplete CalcMode = id --send the whole string to `calc`
completionFunction CalcMode = \s -> if (length s == 0) then return [] else do
fmap lines $ runProcessWithInput "calc" [s] ""
modeAction CalcMode _ _ = return () -- do nothing; this might copy the result to the clipboard
-- | Uses the program `hoogle` to search for functions
instance XPrompt HoogleMode where
showXPrompt _ = "hoogle %s> "
commandToComplete _ = id
completionFunction (HMode pathToHoogleBin' _) = \s -> completionFunctionWith pathToHoogleBin' ["--count","8",s]
-- This action calls hoogle again to find the URL corresponding to the autocompleted item
modeAction (HMode pathToHoogleBin'' browser') query result = do
completionsWithLink <- liftIO $ completionFunctionWith pathToHoogleBin'' ["--count","5","--link",query]
let link = do
s <- find (isJust . \complStr -> findSeqIndex complStr result) completionsWithLink
i <- findSeqIndex s "http://"
return $ drop i s
case link of
Just l -> spawn $ browser' ++ " " ++ l
_ -> return ()
where
-- | Receives a sublist and a list. It returns the index where the sublist appears in the list.
findSeqIndex :: (Eq a) => [a] -> [a] -> Maybe Int
findSeqIndex xs xss = findIndex (isPrefixOf xss) $ tails xs
-- | Creates an autocompletion function for a programm given the program's name and a list of args to send to the command.
completionFunctionWith :: String -> [String] -> IO [String]
completionFunctionWith cmd args = do fmap lines $ runProcessWithInput cmd args ""
-- | Creates a prompt with the given modes
launcherPrompt :: XPConfig -> [XPMode] -> X()
launcherPrompt config modes = mkXPromptWithModes modes config
-- | Create a list of modes based on :
-- a list of extensions mapped to actions
-- the path to hoogle
defaultLauncherModes :: LauncherConfig -> [XPMode]
defaultLauncherModes cnf = let
ph = pathToHoogle cnf
in [ hoogleMode ph $ browser cnf
, calcMode]
hoogleMode :: FilePath -> String -> XPMode
hoogleMode pathToHoogleBin browser' = XPT $ HMode pathToHoogleBin browser'
calcMode :: XPMode
calcMode = XPT CalcMode
{-
-- ideas for XMonad.Prompt running on mode XPMultipleModes
* Switch to mode by name of the prompt, 1. ':' at an empty(?) buffer, 2. autocomplete name in buffer should happen, 3. switch to mode with enter (cancel switch with C-g)
* Support for actions of type String -> X a
-- ideas for this module
* Hoogle mode: add a setting in the action to either go to documentation or to the source code (needs hoogle change?)
* Hoogle mode: add setting to query hoogle at haskell.org instead (with &mode=json)
-}

View File

@@ -1,10 +1,10 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.MessageFeedback
-- Copyright : (c) Quentin Moser <quentin.moser@unifr.ch>
-- Copyright : (c) Quentin Moser <moserq@gmail.com>
-- License : BSD3
--
-- Maintainer : None
-- Maintainer : orphaned
-- Stability : unstable
-- Portability : unportable
--

View File

@@ -23,12 +23,8 @@ module XMonad.Actions.MouseResize
, MouseResize (..)
) where
import Control.Monad
import Data.Maybe
import XMonad
import XMonad.Layout.Decoration
import XMonad.Layout.LayoutModifier
import XMonad.Layout.WindowArranger
import XMonad.Util.XUtils
@@ -114,6 +110,11 @@ createInputWindow ((w,r),mr) = do
Just tr -> withDisplay $ \d -> do
tw <- mkInputWindow d tr
io $ selectInput d tw (exposureMask .|. buttonPressMask)
cursor <- io $ createFontCursor d xC_bottom_right_corner
io $ defineCursor d tw cursor
io $ freeCursor d cursor
showWindow tw
return ((w,r), Just tw)
Nothing -> return ((w,r), Nothing)

View File

@@ -0,0 +1,778 @@
{-# LANGUAGE DeriveDataTypeable, MultiParamTypeClasses, PatternGuards, RankNTypes, TypeSynonymInstances #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Layout.Navigation2D
-- Copyright : (c) 2011 Norbert Zeh <nzeh@cs.dal.ca>
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : Norbert Zeh <nzeh@cs.dal.ca>
-- Stability : unstable
-- Portability : unportable
--
-- Navigation2D is an xmonad extension that allows easy directional
-- navigation of windows and screens (in a multi-monitor setup).
-----------------------------------------------------------------------------
module XMonad.Actions.Navigation2D ( -- * Usage
-- $usage
-- * Finer points
-- $finer_points
-- * Alternative directional navigation modules
-- $alternatives
-- * Incompatibilities
-- $incompatibilities
-- * Detailed technical discussion
-- $technical
-- * Exported functions and types
-- #Exports#
withNavigation2DConfig
, Navigation2DConfig(..)
, defaultNavigation2DConfig
, Navigation2D
, lineNavigation
, centerNavigation
, fullScreenRect
, singleWindowRect
, switchLayer
, windowGo
, windowSwap
, windowToScreen
, screenGo
, screenSwap
, Direction2D(..)
) where
import Control.Applicative
import qualified Data.List as L
import qualified Data.Map as M
import Data.Maybe
import XMonad hiding (Screen)
import qualified XMonad.StackSet as W
import qualified XMonad.Util.ExtensibleState as XS
import XMonad.Util.Types
-- $usage
-- #Usage#
-- Navigation2D provides directional navigation (go left, right, up, down) for
-- windows and screens. It treats floating and tiled windows as two separate
-- layers and provides mechanisms to navigate within each layer and to switch
-- between layers. Navigation2D provides two different navigation strategies
-- (see <#Technical_Discussion> for details): /Line navigation/ feels rather
-- natural but may make it impossible to navigate to a given window from the
-- current window, particularly in the floating layer. /Center navigation/
-- feels less natural in certain situations but ensures that all windows can be
-- reached without the need to involve the mouse. Navigation2D allows different
-- navigation strategies to be used in the two layers and allows customization
-- of the navigation strategy for the tiled layer based on the layout currently
-- in effect.
--
-- You can use this module with (a subset of) the following in your @~\/.xmonad\/xmonad.hs@:
--
-- > import XMonad.Actions.Navigation2D
--
-- Then edit your keybindings:
--
-- > -- Switch between layers
-- > , ((modm, xK_space), switchLayers)
-- >
-- > -- Directional navigation of windows
-- > , ((modm, xK_Right), windowGo R False)
-- > , ((modm, xK_Left ), windowGo L False)
-- > , ((modm, xK_Up ), windowGo U False)
-- > , ((modm, xK_Down ), windowGo D False)
-- >
-- > -- Swap adjacent windows
-- > , ((modm .|. controlMask, xK_Right), windowSwap R False)
-- > , ((modm .|. controlMask, xK_Left ), windowSwap L False)
-- > , ((modm .|. controlMask, xK_Up ), windowSwap U False)
-- > , ((modm .|. controlMask, xK_Down ), windowSwap D False)
-- >
-- > -- Directional navigation of screens
-- > , ((modm, xK_r ), screenGo R False)
-- > , ((modm, xK_l ), screenGo L False)
-- > , ((modm, xK_u ), screenGo U False)
-- > , ((modm, xK_d ), screenGo D False)
-- >
-- > -- Swap workspaces on adjacent screens
-- > , ((modm .|. controlMask, xK_r ), screenSwap R False)
-- > , ((modm .|. controlMask, xK_l ), screenSwap L False)
-- > , ((modm .|. controlMask, xK_u ), screenSwap U False)
-- > , ((modm .|. controlMask, xK_d ), screenSwap D False)
-- >
-- > -- Send window to adjacent screen
-- > , ((modm .|. mod1Mask, xK_r ), windowToScreen R False)
-- > , ((modm .|. mod1Mask, xK_l ), windowToScreen L False)
-- > , ((modm .|. mod1Mask, xK_u ), windowToScreen U False)
-- > , ((modm .|. mod1Mask, xK_d ), windowToScreen D False)
--
-- and add the configuration of the module to your main function:
--
-- > main = xmonad $ withNavigation2DConfig defaultNavigation2DConfig
-- > $ defaultConfig
--
-- For detailed instruction on editing the key binding see:
--
-- "XMonad.Doc.Extending#Editing_key_bindings".
-- $finer_points
-- #Finer_Points#
-- The above should get you started. Here are some finer points:
--
-- Navigation2D has the ability to wrap around at screen edges. For example, if
-- you navigated to the rightmost window on the rightmost screen and you
-- continued to go right, this would get you to the leftmost window on the
-- leftmost screen. This feature may be useful for switching between screens
-- that are far apart but may be confusing at least to novice users. Therefore,
-- it is disabled in the above example (e.g., navigation beyond the rightmost
-- window on the rightmost screen is not possible and trying to do so will
-- simply not do anything.) If you want this feature, change all the 'False'
-- values in the above example to 'True'. You could also decide you want
-- wrapping only for a subset of the operations and no wrapping for others.
--
-- By default, all layouts use the 'defaultTiledNavigation' strategy specified
-- in the 'Navigation2DConfig' (by default, line navigation is used). To
-- override this behaviour for some layouts, add a pair (\"layout name\",
-- navigation strategy) to the 'layoutNavigation' list in the
-- 'Navigation2DConfig', where \"layout name\" is the string reported by the
-- layout's description method (normally what is shown as the layout name in
-- your status bar). For example, all navigation strategies normally allow only
-- navigation between mapped windows. The first step to overcome this, for
-- example, for the Full layout, is to switch to center navigation for the Full
-- layout:
--
-- > myNavigation2DConfig = defaultNavigation2DConfig { layoutNavigation = [("Full", centerNavigation)] }
-- >
-- > main = xmonad $ withNavigation2DConfig myNavigation2DConfig
-- > $ defaultConfig
--
-- The navigation between windows is based on their screen rectangles, which are
-- available /and meaningful/ only for mapped windows. Thus, as already said,
-- the default is to allow navigation only between mapped windows. However,
-- there are layouts that do not keep all windows mapped. One example is the
-- Full layout, which unmaps all windows except the one that has the focus,
-- thereby preventing navigation to any other window in the layout. To make
-- navigation to unmapped windows possible, unmapped windows need to be assigned
-- rectangles to pretend they are mapped, and a natural way to do this for the
-- Full layout is to pretend all windows occupy the full screen and are stacked
-- on top of each other so that only the frontmost one is visible. This can be
-- done as follows:
--
-- > myNavigation2DConfig = defaultNavigation2DConfig { layoutNavigation = [("Full", centerNavigation)]
-- > , unmappedWindowRect = [("Full", singleWindowRect)]
-- > }
-- >
-- > main = xmonad $ withNavigation2DConfig myNavigation2DConfig
-- > $ defaultConfig
--
-- With this setup, Left/Up navigation behaves like standard
-- 'XMonad.StackSet.focusUp' and Right/Down navigation behaves like
-- 'XMonad.StackSet.focusDown', thus allowing navigation between windows in the
-- layout.
--
-- In general, each entry in the 'unmappedWindowRect' association list is a pair
-- (\"layout description\", function), where the function computes a rectangle
-- for each unmapped window from the screen it is on and the window ID.
-- Currently, Navigation2D provides only two functions of this type:
-- 'singleWindowRect' and 'fullScreenRect'.
--
-- With per-layout navigation strategies, if different layouts are in effect on
-- different screens in a multi-monitor setup, and different navigation
-- strategies are defined for these active layouts, the most general of these
-- navigation strategies is used across all screens (because Navigation2D does
-- not distinguish between windows on different workspaces), where center
-- navigation is more general than line navigation, as discussed formally under
-- <#Technical_Discussion>.
-- $alternatives
-- #Alternatives#
--
-- There exist two alternatives to Navigation2D:
-- "XMonad.Actions.WindowNavigation" and "XMonad.Layout.WindowNavigation".
-- X.L.WindowNavigation has the advantage of colouring windows to indicate the
-- window that would receive the focus in each navigation direction, but it does
-- not support navigation across multiple monitors, does not support directional
-- navigation of floating windows, and has a very unintuitive definition of
-- which window receives the focus next in each direction. X.A.WindowNavigation
-- does support navigation across multiple monitors but does not provide window
-- colouring while retaining the unintuitive navigational semantics of
-- X.L.WindowNavigation. This makes it very difficult to predict which window
-- receives the focus next. Neither X.A.WindowNavigation nor
-- X.L.WindowNavigation supports directional navigation of screens.
-- $technical
-- #Technical_Discussion#
-- An in-depth discussion of the navigational strategies implemented in
-- Navigation2D, including formal proofs of their properties, can be found
-- at <http://www.cs.dal.ca/~nzeh/xmonad/Navigation2D.pdf>.
-- $incompatibilities
-- #Incompatibilities#
-- Currently Navigation2D is known not to play nicely with tabbed layouts, but
-- it should work well with any other tiled layout. My hope is to address the
-- incompatibility with tabbed layouts in a future version. The navigation to
-- unmapped windows, for example in a Full layout, by assigning rectangles to
-- unmapped windows is more a workaround than a clean solution. Figuring out
-- how to deal with tabbed layouts may also lead to a more general and cleaner
-- solution to query the layout for a window's rectangle that may make this
-- workaround unnecessary. At that point, the 'unmappedWindowRect' field of the
-- 'Navigation2DConfig' will disappear.
-- | A rectangle paired with an object
type Rect a = (a, Rectangle)
-- | A shorthand for window-rectangle pairs. Reduces typing.
type WinRect = Rect Window
-- | A shorthand for workspace-rectangle pairs. Reduces typing.
type WSRect = Rect WorkspaceId
----------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------
-- --
-- PUBLIC INTERFACE --
-- --
----------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------
-- | Encapsulates the navigation strategy
data Navigation2D = N Generality (forall a . Eq a => Direction2D -> Rect a -> [Rect a] -> Maybe a)
runNav :: forall a . Eq a => Navigation2D -> (Direction2D -> Rect a -> [Rect a] -> Maybe a)
runNav (N _ nav) = nav
-- | Score that indicates how general a navigation strategy is
type Generality = Int
instance Eq Navigation2D where
(N x _) == (N y _) = x == y
instance Ord Navigation2D where
(N x _) <= (N y _) = x <= y
-- | Line navigation. To illustrate this navigation strategy, consider
-- navigating to the left from the current window. In this case, we draw a
-- horizontal line through the center of the current window and consider all
-- windows that intersect this horizontal line and whose right boundaries are to
-- the left of the left boundary of the current window. From among these
-- windows, we choose the one with the rightmost right boundary.
lineNavigation :: Navigation2D
lineNavigation = N 1 doLineNavigation
-- | Center navigation. Again, consider navigating to the left. Then we
-- consider the cone bounded by the two rays shot at 45-degree angles in
-- north-west and south-west direction from the center of the current window. A
-- window is a candidate to receive the focus if its center lies in this cone.
-- We choose the window whose center has minimum L1-distance from the current
-- window center. The tie breaking strategy for windows with the same distance
-- is a bit complicated (see <#Technical_Discussion>) but ensures that all
-- windows can be reached and that windows with the same center are traversed in
-- their order in the window stack, that is, in the order
-- 'XMonad.StackSet.focusUp' and 'XMonad.StackSet.focusDown' would traverse
-- them.
centerNavigation :: Navigation2D
centerNavigation = N 2 doCenterNavigation
-- | Stores the configuration of directional navigation
data Navigation2DConfig = Navigation2DConfig
{ defaultTiledNavigation :: Navigation2D -- ^ default navigation strategy for the tiled layer
, floatNavigation :: Navigation2D -- ^ navigation strategy for the float layer
, screenNavigation :: Navigation2D -- ^ strategy for navigation between screens
, layoutNavigation :: [(String, Navigation2D)] -- ^ association list of customized navigation strategies
-- for different layouts in the tiled layer. Each pair
-- is of the form (\"layout description\", navigation
-- strategy). If there is no pair in this list whose first
-- component is the name of the current layout, the
-- 'defaultTiledNavigation' strategy is used.
, unmappedWindowRect :: [(String, Screen -> Window -> X (Maybe Rectangle))]
-- ^ list associating functions to calculate rectangles
-- for unmapped windows with layouts to which they are
-- to be applied. Each pair in this list is of
-- the form (\"layout description\", function), where the
-- function calculates a rectangle for a given unmapped
-- window from the screen it is on and its window ID.
-- See <#Finer_Points> for how to use this.
} deriving Typeable
-- | Shorthand for the tedious screen type
type Screen = W.Screen WorkspaceId (Layout Window) Window ScreenId ScreenDetail
-- So we can store the configuration in extensible state
instance ExtensionClass Navigation2DConfig where
initialValue = defaultNavigation2DConfig
-- | Modifies the xmonad configuration to store the Navigation2D configuration
withNavigation2DConfig :: Navigation2DConfig -> XConfig a -> XConfig a
withNavigation2DConfig conf2d xconf = xconf { startupHook = startupHook xconf
>> XS.put conf2d
}
-- | Default navigation configuration. It uses line navigation for the tiled
-- layer and for navigation between screens, and center navigation for the float
-- layer. No custom navigation strategies or rectangles for unmapped windows are
-- defined for individual layouts.
defaultNavigation2DConfig :: Navigation2DConfig
defaultNavigation2DConfig = Navigation2DConfig { defaultTiledNavigation = lineNavigation
, floatNavigation = centerNavigation
, screenNavigation = lineNavigation
, layoutNavigation = []
, unmappedWindowRect = []
}
-- | Switches focus to the closest window in the other layer (floating if the
-- current window is tiled, tiled if the current window is floating). Closest
-- means that the L1-distance between the centers of the windows is minimized.
switchLayer :: X ()
switchLayer = actOnLayer otherLayer
( \ _ cur wins -> windows
$ doFocusClosestWindow cur wins
)
( \ _ cur wins -> windows
$ doFocusClosestWindow cur wins
)
( \ _ _ _ -> return () )
False
-- | Moves the focus to the next window in the given direction and in the same
-- layer as the current window. The second argument indicates whether
-- navigation should wrap around (e.g., from the left edge of the leftmost
-- screen to the right edge of the rightmost screen).
windowGo :: Direction2D -> Bool -> X ()
windowGo dir wrap = actOnLayer thisLayer
( \ conf cur wins -> windows
$ doTiledNavigation conf dir W.focusWindow cur wins
)
( \ conf cur wins -> windows
$ doFloatNavigation conf dir W.focusWindow cur wins
)
( \ conf cur wspcs -> windows
$ doScreenNavigation conf dir W.view cur wspcs
)
wrap
-- | Swaps the current window with the next window in the given direction and in
-- the same layer as the current window. (In the floating layer, all that
-- changes for the two windows is their stacking order if they're on the same
-- screen. If they're on different screens, each window is moved to the other
-- window's screen but retains its position and size relative to the screen.)
-- The second argument indicates wrapping (see 'windowGo').
windowSwap :: Direction2D -> Bool -> X ()
windowSwap dir wrap = actOnLayer thisLayer
( \ conf cur wins -> windows
$ doTiledNavigation conf dir swap cur wins
)
( \ conf cur wins -> windows
$ doFloatNavigation conf dir swap cur wins
)
( \ _ _ _ -> return () )
wrap
-- | Moves the current window to the next screen in the given direction. The
-- second argument indicates wrapping (see 'windowGo').
windowToScreen :: Direction2D -> Bool -> X ()
windowToScreen dir wrap = actOnScreens ( \ conf cur wspcs -> windows
$ doScreenNavigation conf dir W.shift cur wspcs
)
wrap
-- | Moves the focus to the next screen in the given direction. The second
-- argument indicates wrapping (see 'windowGo').
screenGo :: Direction2D -> Bool -> X ()
screenGo dir wrap = actOnScreens ( \ conf cur wspcs -> windows
$ doScreenNavigation conf dir W.view cur wspcs
)
wrap
-- | Swaps the workspace on the current screen with the workspace on the screen
-- in the given direction. The second argument indicates wrapping (see
-- 'windowGo').
screenSwap :: Direction2D -> Bool -> X ()
screenSwap dir wrap = actOnScreens ( \ conf cur wspcs -> windows
$ doScreenNavigation conf dir W.greedyView cur wspcs
)
wrap
-- | Maps each window to a fullscreen rect. This may not be the same rectangle the
-- window maps to under the Full layout or a similar layout if the layout
-- respects statusbar struts. In such cases, it may be better to use
-- 'singleWindowRect'.
fullScreenRect :: Screen -> Window -> X (Maybe Rectangle)
fullScreenRect scr _ = return (Just . screenRect . W.screenDetail $ scr)
-- | Maps each window to the rectangle it would receive if it was the only
-- window in the layout. Useful, for example, for determining the default
-- rectangle for unmapped windows in a Full layout that respects statusbar
-- struts.
singleWindowRect :: Screen -> Window -> X (Maybe Rectangle)
singleWindowRect scr win = listToMaybe
. map snd
. fst
<$> runLayout ((W.workspace scr) { W.stack = W.differentiate [win] })
(screenRect . W.screenDetail $ scr)
----------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------
-- --
-- PRIVATE X ACTIONS --
-- --
----------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------
-- | Acts on the appropriate layer using the given action functions
actOnLayer :: ([WinRect] -> [WinRect] -> [WinRect]) -- ^ Chooses which layer to operate on, relative
-- to the current window (same or other layer)
-> (Navigation2DConfig -> WinRect -> [WinRect] -> X ()) -- ^ The action for the tiled layer
-> (Navigation2DConfig -> WinRect -> [WinRect] -> X ()) -- ^ The action for the float layer
-> (Navigation2DConfig -> WSRect -> [WSRect] -> X ()) -- ^ The action if the current workspace is empty
-> Bool -- ^ Should navigation wrap around screen edges?
-> X ()
actOnLayer choice tiledact floatact wsact wrap = withWindowSet $ \winset -> do
conf <- XS.get
(floating, tiled) <- navigableWindows conf wrap winset
let cur = W.peek winset
case cur of
Nothing -> actOnScreens wsact wrap
Just w | Just rect <- L.lookup w tiled -> tiledact conf (w, rect) (choice tiled floating)
| Just rect <- L.lookup w floating -> floatact conf (w, rect) (choice floating tiled)
| otherwise -> return ()
-- | Returns the list of windows on the currently visible workspaces
navigableWindows :: Navigation2DConfig -> Bool -> WindowSet -> X ([WinRect], [WinRect])
navigableWindows conf wrap winset = L.partition (\(win, _) -> M.member win (W.floating winset))
. addWrapping winset wrap
. catMaybes
. concat
<$>
( mapM ( \scr -> mapM (maybeWinRect scr)
$ W.integrate'
$ W.stack
$ W.workspace scr
)
. sortedScreens
) winset
where
maybeWinRect scr win = do
winrect <- windowRect win
rect <- case winrect of
Just _ -> return winrect
Nothing -> maybe (return Nothing)
(\f -> f scr win)
(L.lookup (description . W.layout . W.workspace $ scr) (unmappedWindowRect conf))
return ((,) win <$> rect)
-- | Returns the current rectangle of the given window, Nothing if the window isn't mapped
windowRect :: Window -> X (Maybe Rectangle)
windowRect win = withDisplay $ \dpy -> do
mp <- isMapped win
if mp then do (_, x, y, w, h, bw, _) <- io $ getGeometry dpy win
return $ Just $ Rectangle x y (w + 2 * bw) (h + 2 * bw)
`catchX` return Nothing
else return Nothing
-- | Acts on the screens using the given action function
actOnScreens :: (Navigation2DConfig -> WSRect -> [WSRect] -> X ())
-> Bool -- ^ Should wrapping be used?
-> X ()
actOnScreens act wrap = withWindowSet $ \winset -> do
conf <- XS.get
let wsrects = visibleWorkspaces winset wrap
cur = W.tag . W.workspace . W.current $ winset
rect = fromJust $ L.lookup cur wsrects
act conf (cur, rect) wsrects
-- | Determines whether a given window is mapped
isMapped :: Window -> X Bool
isMapped win = withDisplay
$ \dpy -> io
$ (waIsUnmapped /=)
. wa_map_state
<$> getWindowAttributes dpy win
----------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------
-- --
-- PRIVATE PURE FUNCTIONS --
-- --
----------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------
-- | Finds the window closest to the given window and focuses it. Ties are
-- broken by choosing the first window in the window stack among the tied
-- windows. (The stack order is the one produced by integrate'ing each visible
-- workspace's window stack and concatenating these lists for all visible
-- workspaces.)
doFocusClosestWindow :: WinRect
-> [WinRect]
-> (WindowSet -> WindowSet)
doFocusClosestWindow (cur, rect) winrects
| null winctrs = id
| otherwise = W.focusWindow . fst $ L.foldl1' closer winctrs
where
ctr = centerOf rect
winctrs = filter ((cur /=) . fst)
$ map (\(w, r) -> (w, centerOf r)) winrects
closer wc1@(_, c1) wc2@(_, c2) | lDist ctr c1 > lDist ctr c2 = wc2
| otherwise = wc1
-- | Implements navigation for the tiled layer
doTiledNavigation :: Navigation2DConfig
-> Direction2D
-> (Window -> WindowSet -> WindowSet)
-> WinRect
-> [WinRect]
-> (WindowSet -> WindowSet)
doTiledNavigation conf dir act cur winrects winset
| Just win <- runNav nav dir cur winrects = act win winset
| otherwise = winset
where
layouts = map (description . W.layout . W.workspace)
$ W.screens winset
nav = maximum
$ map ( fromMaybe (defaultTiledNavigation conf)
. flip L.lookup (layoutNavigation conf)
)
$ layouts
-- | Implements navigation for the float layer
doFloatNavigation :: Navigation2DConfig
-> Direction2D
-> (Window -> WindowSet -> WindowSet)
-> WinRect
-> [WinRect]
-> (WindowSet -> WindowSet)
doFloatNavigation conf dir act cur winrects
| Just win <- runNav nav dir cur winrects = act win
| otherwise = id
where
nav = floatNavigation conf
-- | Implements navigation between screens
doScreenNavigation :: Navigation2DConfig
-> Direction2D
-> (WorkspaceId -> WindowSet -> WindowSet)
-> WSRect
-> [WSRect]
-> (WindowSet -> WindowSet)
doScreenNavigation conf dir act cur wsrects
| Just ws <- runNav nav dir cur wsrects = act ws
| otherwise = id
where
nav = screenNavigation conf
-- | Implements line navigation. For layouts without overlapping windows, there
-- is no need to break ties between equidistant windows. When windows do
-- overlap, even the best tie breaking rule cannot make line navigation feel
-- natural. Thus, we fairly arbtitrarily break ties by preferring the window
-- that comes first in the window stack. (The stack order is the one produced
-- by integrate'ing each visible workspace's window stack and concatenating
-- these lists for all visible workspaces.)
doLineNavigation :: Eq a => Direction2D -> Rect a -> [Rect a] -> Maybe a
doLineNavigation dir (cur, rect) winrects
| null winrects' = Nothing
| otherwise = Just . fst $ L.foldl1' closer winrects'
where
-- The current window's center
ctr@(xc, yc) = centerOf rect
-- The list of windows that are candidates to receive focus.
winrects' = filter dirFilter
$ filter ((cur /=) . fst)
$ winrects
-- Decides whether a given window matches the criteria to be a candidate to
-- receive the focus.
dirFilter (_, r) = (dir == L && leftOf r rect && intersectsY yc r)
|| (dir == R && leftOf rect r && intersectsY yc r)
|| (dir == U && above r rect && intersectsX xc r)
|| (dir == D && above rect r && intersectsX xc r)
-- Decide whether r1 is left of/above r2.
leftOf r1 r2 = rect_x r1 + fi (rect_width r1) <= rect_x r2
above r1 r2 = rect_y r1 + fi (rect_height r1) <= rect_y r2
-- Check whether r's x-/y-range contains the given x-/y-coordinate.
intersectsX x r = rect_x r <= x && rect_x r + fi (rect_width r) >= x
intersectsY y r = rect_y r <= y && rect_y r + fi (rect_height r) >= y
-- Decides whether r1 is closer to the current window's center than r2
closer wr1@(_, r1) wr2@(_, r2) | dist ctr r1 > dist ctr r2 = wr2
| otherwise = wr1
-- Returns the distance of r from the point (x, y)
dist (x, y) r | dir == L = x - rect_x r - fi (rect_width r)
| dir == R = rect_x r - x
| dir == U = y - rect_y r - fi (rect_height r)
| otherwise = rect_y r - y
-- | Implements center navigation
doCenterNavigation :: Eq a => Direction2D -> Rect a -> [Rect a] -> Maybe a
doCenterNavigation dir (cur, rect) winrects
| ((w, _):_) <- onCtr' = Just w
| otherwise = closestOffCtr
where
-- The center of the current window
(xc, yc) = centerOf rect
-- All the windows with their center points relative to the current
-- center rotated so the right cone becomes the relevant cone.
-- The windows are ordered in the order they should be preferred
-- when they are otherwise tied.
winctrs = map (\(w, r) -> (w, dirTransform . centerOf $ r))
$ stackTransform
$ winrects
-- Give preference to windows later in the stack for going left or up and to
-- windows earlier in the stack for going right or down. (The stack order
-- is the one produced by integrate'ing each visible workspace's window
-- stack and concatenating these lists for all visible workspaces.)
stackTransform | dir == L || dir == U = reverse
| otherwise = id
-- Transform a point into a difference to the current window center and
-- rotate it so that the relevant cone becomes the right cone.
dirTransform (x, y) | dir == R = ( x - xc , y - yc )
| dir == L = (-(x - xc), -(y - yc))
| dir == D = ( y - yc , x - xc )
| otherwise = (-(y - yc), -(x - xc))
-- Partition the points into points that coincide with the center
-- and points that do not.
(onCtr, offCtr) = L.partition (\(_, (x, y)) -> x == 0 && y == 0) winctrs
-- All the points that coincide with the current center and succeed it
-- in the (appropriately ordered) window stack.
onCtr' = L.tail $ L.dropWhile ((cur /=) . fst) onCtr
-- tail should be safe here because cur should be in onCtr
-- All the points that do not coincide with the current center and which
-- lie in the (rotated) right cone.
offCtr' = L.filter (\(_, (x, y)) -> x > 0 && y < x && y >= -x) offCtr
-- The off-center point closest to the center and
-- closest to the bottom ray of the cone. Nothing if no off-center
-- point is in the cone
closestOffCtr = if null offCtr' then Nothing
else Just $ fst $ L.foldl1' closest offCtr'
closest wp@(_, p@(_, yp)) wq@(_, q@(_, yq))
| lDist (0, 0) q < lDist (0, 0) p = wq -- q is closer than p
| lDist (0, 0) p < lDist (0, 0) q = wp -- q is farther away than p
| yq < yp = wq -- q is closer to the bottom ray than p
| otherwise = wp -- q is farther away from the bottom ray than p
-- or it has the same distance but comes later
-- in the window stack
-- | Swaps the current window with the window given as argument
swap :: Window -> WindowSet -> WindowSet
swap win winset = W.focusWindow cur
$ L.foldl' (flip W.focusWindow) newwinset newfocused
where
-- The current window
cur = fromJust $ W.peek winset
-- All screens
scrs = W.screens winset
-- All visible workspaces
visws = map W.workspace scrs
-- The focused windows of the visible workspaces
focused = mapMaybe (\ws -> W.focus <$> W.stack ws) visws
-- The window lists of the visible workspaces
wins = map (W.integrate' . W.stack) visws
-- Update focused windows and window lists to reflect swap of windows.
newfocused = map swapWins focused
newwins = map (map swapWins) wins
-- Replaces the current window with the argument window and vice versa.
swapWins x | x == cur = win
| x == win = cur
| otherwise = x
-- Reconstruct the workspaces' window stacks to reflect the swap.
newvisws = zipWith (\ws wns -> ws { W.stack = W.differentiate wns }) visws newwins
newscrs = zipWith (\scr ws -> scr { W.workspace = ws }) scrs newvisws
newwinset = winset { W.current = head newscrs
, W.visible = tail newscrs
}
-- | Calculates the center of a rectangle
centerOf :: Rectangle -> (Position, Position)
centerOf r = (rect_x r + fi (rect_width r) `div` 2, rect_y r + fi (rect_height r) `div` 2)
-- | Shorthand for integer conversions
fi :: (Integral a, Num b) => a -> b
fi = fromIntegral
-- | Functions to choose the subset of windows to operate on
thisLayer, otherLayer :: a -> a -> a
thisLayer = curry fst
otherLayer = curry snd
-- | Returns the list of visible workspaces and their screen rects
visibleWorkspaces :: WindowSet -> Bool -> [WSRect]
visibleWorkspaces winset wrap = addWrapping winset wrap
$ map ( \scr -> ( W.tag . W.workspace $ scr
, screenRect . W.screenDetail $ scr
)
)
$ sortedScreens winset
-- | Creates five copies of each (window/workspace, rect) pair in the input: the
-- original and four offset one desktop size (desktop = collection of all
-- screens) to the left, to the right, up, and down. Wrap-around at desktop
-- edges is implemented by navigating into these displaced copies.
addWrapping :: WindowSet -- ^ The window set, used to get the desktop size
-> Bool -- ^ Should wrapping be used? Do nothing if not.
-> [Rect a] -- ^ Input set of (window/workspace, rect) pairs
-> [Rect a]
addWrapping _ False wrects = wrects
addWrapping winset True wrects = [ (w, r { rect_x = rect_x r + fi x
, rect_y = rect_y r + fi y
}
)
| (w, r) <- wrects
, (x, y) <- [(0, 0), (-xoff, 0), (xoff, 0), (0, -yoff), (0, yoff)]
]
where
(xoff, yoff) = wrapOffsets winset
-- | Calculates the offsets for window/screen coordinates for the duplication
-- of windows/workspaces that implements wrap-around.
wrapOffsets :: WindowSet -> (Integer, Integer)
wrapOffsets winset = (max_x - min_x, max_y - min_y)
where
min_x = fi $ minimum $ map rect_x rects
min_y = fi $ minimum $ map rect_y rects
max_x = fi $ maximum $ map (\r -> rect_x r + (fi $ rect_width r)) rects
max_y = fi $ maximum $ map (\r -> rect_y r + (fi $ rect_height r)) rects
rects = map snd $ visibleWorkspaces winset False
-- | Returns the list of screens sorted primarily by their centers'
-- x-coordinates and secondarily by their y-coordinates.
sortedScreens :: WindowSet -> [Screen]
sortedScreens winset = L.sortBy cmp
$ W.screens winset
where
cmp s1 s2 | x1 < x2 = LT
| x1 > x2 = GT
| y1 < x2 = LT
| y1 > y2 = GT
| otherwise = EQ
where
(x1, y1) = centerOf (screenRect . W.screenDetail $ s1)
(x2, y2) = centerOf (screenRect . W.screenDetail $ s2)
-- | Calculates the L1-distance between two points.
lDist :: (Position, Position) -> (Position, Position) -> Int
lDist (x1, y1) (x2, y2) = abs (fi $ x1 - x2) + abs (fi $ y1 - y2)

View File

@@ -15,17 +15,137 @@
module XMonad.Actions.OnScreen (
-- * Usage
-- $usage
onScreen
onScreen
, onScreen'
, Focus(..)
, viewOnScreen
, greedyViewOnScreen
, onlyOnScreen
, toggleOnScreen
, toggleGreedyOnScreen
) where
import XMonad.StackSet
import Control.Monad(guard)
import Data.List
import Data.Maybe(fromMaybe)
import Data.Function(on)
import XMonad
import XMonad.StackSet hiding (new)
import Control.Monad (guard)
-- import Control.Monad.State.Class (gets)
import Data.Maybe (fromMaybe)
-- | Focus data definitions
data Focus = FocusNew -- ^ always focus the new screen
| FocusCurrent -- ^ always keep the focus on the current screen
| FocusTag WorkspaceId -- ^ always focus tag i on the new stack
| FocusTagVisible WorkspaceId -- ^ focus tag i only if workspace with tag i is visible on the old stack
-- | Run any function that modifies the stack on a given screen. This function
-- will also need to know which Screen to focus after the function has been
-- run.
onScreen :: (WindowSet -> WindowSet) -- ^ function to run
-> Focus -- ^ what to do with the focus
-> ScreenId -- ^ screen id
-> WindowSet -- ^ current stack
-> WindowSet
onScreen f foc sc st = fromMaybe st $ do
ws <- lookupWorkspace sc st
let fStack = f $ view ws st
return $ setFocus foc st fStack
-- set focus for new stack
setFocus :: Focus
-> WindowSet -- ^ old stack
-> WindowSet -- ^ new stack
-> WindowSet
setFocus FocusNew _ new = new
setFocus FocusCurrent old new =
case lookupWorkspace (screen $ current old) new of
Nothing -> new
Just i -> view i new
setFocus (FocusTag i) _ new = view i new
setFocus (FocusTagVisible i) old new =
if i `elem` map (tag . workspace) (visible old)
then setFocus (FocusTag i) old new
else setFocus FocusCurrent old new
-- | A variation of @onScreen@ which will take any @X ()@ function and run it
-- on the given screen.
-- Warning: This function will change focus even if the function it's supposed
-- to run doesn't succeed.
onScreen' :: X () -- ^ X function to run
-> Focus -- ^ focus
-> ScreenId -- ^ screen id
-> X ()
onScreen' x foc sc = do
st <- gets windowset
case lookupWorkspace sc st of
Nothing -> return ()
Just ws -> do
windows $ view ws
x
windows $ setFocus foc st
-- | Switch to workspace @i@ on screen @sc@. If @i@ is visible use @view@ to
-- switch focus to the workspace @i@.
viewOnScreen :: ScreenId -- ^ screen id
-> WorkspaceId -- ^ index of the workspace
-> WindowSet -- ^ current stack
-> WindowSet
viewOnScreen sid i =
onScreen (view i) (FocusTag i) sid
-- | Switch to workspace @i@ on screen @sc@. If @i@ is visible use @greedyView@
-- to switch the current workspace with workspace @i@.
greedyViewOnScreen :: ScreenId -- ^ screen id
-> WorkspaceId -- ^ index of the workspace
-> WindowSet -- ^ current stack
-> WindowSet
greedyViewOnScreen sid i =
onScreen (greedyView i) (FocusTagVisible i) sid
-- | Switch to workspace @i@ on screen @sc@. If @i@ is visible do nothing.
onlyOnScreen :: ScreenId -- ^ screen id
-> WorkspaceId -- ^ index of the workspace
-> WindowSet -- ^ current stack
-> WindowSet
onlyOnScreen sid i =
onScreen (view i) FocusCurrent sid
-- | @toggleOrView@ as in "XMonad.Actions.CycleWS" for @onScreen@ with view
toggleOnScreen :: ScreenId -- ^ screen id
-> WorkspaceId -- ^ index of the workspace
-> WindowSet -- ^ current stack
-> WindowSet
toggleOnScreen sid i =
onScreen (toggleOrView' view i) FocusCurrent sid
-- | @toggleOrView@ from "XMonad.Actions.CycleWS" for @onScreen@ with greedyView
toggleGreedyOnScreen :: ScreenId -- ^ screen id
-> WorkspaceId -- ^ index of the workspace
-> WindowSet -- ^ current stack
-> WindowSet
toggleGreedyOnScreen sid i =
onScreen (toggleOrView' greedyView i) FocusCurrent sid
-- a \"pure\" version of X.A.CycleWS.toggleOrDoSkip
toggleOrView' :: (WorkspaceId -> WindowSet -> WindowSet) -- ^ function to run
-> WorkspaceId -- ^ tag to look for
-> WindowSet -- ^ current stackset
-> WindowSet
toggleOrView' f i st = fromMaybe (f i st) $ do
let st' = hidden st
-- make sure we actually have to do something
guard $ i == (tag . workspace $ current st)
guard $ not (null st')
-- finally, toggle!
return $ f (tag . head $ st') st
-- $usage
--
@@ -60,56 +180,9 @@ import Data.Function(on)
--
-- A more basic version inside the default keybindings would be:
--
-- > , ((modm .|. controlMask, xK_1) windows (viewOnScreen 0 "1"))
-- > , ((modm .|. controlMask, xK_1), windows (viewOnScreen 0 "1"))
--
-- where 0 is the first screen and "1" the workspace with the tag "1".
-- where 0 is the first screen and \"1\" the workspace with the tag \"1\".
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
-- | Switch to the (hidden) workspace with index 'i' on the screen 'sc'.
-- A default function (for example 'view' or 'greedyView') will be run if 'sc' is
-- the current screen, no valid screen id or workspace 'i' is already visible.
onScreen :: (Eq sid, Eq i)
=> (i -> StackSet i l a sid sd -> StackSet i l a sid sd) -- ^ default action
-> sid -- ^ screen id
-> i -- ^ index of the workspace
-> StackSet i l a sid sd -- ^ current stack
-> StackSet i l a sid sd
onScreen defFunc sc i st = fromMaybe (defFunc i st) $ do
-- on unfocused current screen
guard $ screen (current st) /= sc
x <- find ((i==) . tag ) (hidden st)
s <- find ((sc==) . screen) (screens st)
o <- find ((sc==) . screen) (visible st)
let newScreen = s { workspace = x }
return st { visible = newScreen : deleteBy ((==) `on` screen) newScreen (visible st)
, hidden = workspace o : deleteBy ((==) `on` tag) x (hidden st)
}
-- | Switch to workspace 'i' on screen 'sc'. If 'i' is visible use 'greedyView'
-- to switch the current workspace with workspace 'i'.
greedyViewOnScreen :: (Eq sid, Eq i)
=> sid -- ^ screen id
-> i -- ^ index of the workspace
-> StackSet i l a sid sd -- ^ current stack
-> StackSet i l a sid sd
greedyViewOnScreen = onScreen greedyView
-- | Switch to workspace 'i' on screen 'sc'. If 'i' is visible use 'view' to
-- switch focus to the workspace 'i'.
viewOnScreen :: (Eq sid, Eq i)
=> sid -- ^ screen id
-> i -- ^ index of the workspace
-> StackSet i l a sid sd -- ^ current stack
-> StackSet i l a sid sd
viewOnScreen = onScreen view
-- | Switch to workspace 'i' on screen 'sc'. If 'i' is visible do nothing.
onlyOnScreen :: (Eq sid, Eq i)
=> sid -- ^ screen id
-> i -- ^ index of the workspace
-> StackSet i l a sid sd -- ^ current stack
-> StackSet i l a sid sd
onlyOnScreen = onScreen doNothing
where doNothing _ st = st

View File

@@ -21,7 +21,6 @@ module XMonad.Actions.PerWorkspaceKeys (
import XMonad
import XMonad.StackSet as S
import Data.List (find)
-- $usage
--
@@ -42,9 +41,9 @@ chooseAction f = withWindowSet (f . S.currentTag)
-- If it isn't listed, then run default action (marked with empty string, \"\"), or do nothing if default isn't supplied.
bindOn :: [(String, X())] -> X()
bindOn bindings = chooseAction chooser where
chooser ws = case find ((ws==).fst) bindings of
Just (_, action) -> action
Nothing -> case find ((""==).fst) bindings of
Just (_, action) -> action
chooser ws = case lookup ws bindings of
Just action -> action
Nothing -> case lookup "" bindings of
Just action -> action
Nothing -> return ()

View File

@@ -19,15 +19,14 @@ module XMonad.Actions.PhysicalScreens (
, getScreen
, viewScreen
, sendToScreen
, onNextNeighbour
, onPrevNeighbour
) 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.List (sortBy,findIndex)
import Data.Function (on)
{- $usage
@@ -42,7 +41,12 @@ and then left-to-right.
Example usage in your @~\/.xmonad\/xmonad.hs@ file:
> import XMonad.Actions.PhysicalSCreens
> import XMonad.Actions.PhysicalScreens
> , ((modMask, xK_a), onPrevNeighbour W.view)
> , ((modMask, xK_o), onNextNeighbour W.view)
> , ((modMask .|. shiftMask, xK_a), onPrevNeighbour W.shift)
> , ((modMask .|. shiftMask, xK_o), onNextNeighbour W.shift)
> --
> -- mod-{w,e,r}, Switch to physical/Xinerama screens 1, 2, or 3
@@ -61,12 +65,12 @@ 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
getScreen (P i) = do w <- gets windowset
let screens = W.current w : W.visible w
if i<0 || i >= length screens
then return Nothing
else let ss = sortBy (cmpScreen `on` (screenRect . W.screenDetail)) screens
in return $ Just $ W.screen $ ss !! i
-- | Switch to a given physical screen
viewScreen :: PhysicalScreen -> X ()
@@ -85,4 +89,26 @@ sendToScreen p = do i <- getScreen p
-- | 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)
cmpScreen (Rectangle x1 y1 _ _) (Rectangle x2 y2 _ _) = compare (y1,x1) (y2,x2)
-- | Get ScreenId for neighbours of the current screen based on position offset.
getNeighbour :: Int -> X ScreenId
getNeighbour d = do w <- gets windowset
let ss = map W.screen $ sortBy (cmpScreen `on` (screenRect . W.screenDetail)) $ W.current w : W.visible w
curPos = maybe 0 id $ findIndex (== W.screen (W.current w)) ss
pos = (curPos + d) `mod` length ss
return $ ss !! pos
neighbourWindows :: Int -> (WorkspaceId -> WindowSet -> WindowSet) -> X ()
neighbourWindows d f = do s <- getNeighbour d
w <- screenWorkspace s
whenJust w $ windows . f
-- | Apply operation on a WindowSet with the WorkspaceId of the next screen in the physical order as parameter.
onNextNeighbour :: (WorkspaceId -> WindowSet -> WindowSet) -> X ()
onNextNeighbour = neighbourWindows 1
-- | Apply operation on a WindowSet with the WorkspaceId of the previous screen in the physical order as parameter.
onPrevNeighbour :: (WorkspaceId -> WindowSet -> WindowSet) -> X ()
onPrevNeighbour = neighbourWindows (-1)

View File

@@ -110,7 +110,7 @@ plane ::
(WorkspaceId -> WindowSet -> WindowSet) -> Lines -> Limits -> Direction ->
X ()
plane function numberLines_ limits direction = do
state <- get
st <- get
xconf <- ask
numberLines <-
@@ -205,7 +205,7 @@ plane function numberLines_ limits direction = do
preColumns = div areas numberLines
mCurrentWS :: Maybe Int
mCurrentWS = elemIndex (currentTag $ windowset state) areaNames
mCurrentWS = elemIndex (currentTag $ windowset st) areaNames
areas :: Int
areas = length areaNames

View File

@@ -44,26 +44,32 @@ module XMonad.Actions.Search ( -- * Usage
lucky,
maps,
mathworld,
openstreetmap,
scholar,
thesaurus,
wayback,
wikipedia,
wiktionary,
youtube,
multi
multi,
-- * Use case: searching with a submap
-- $tip
-- * Types
Browser, Site, Query, Name, Search
) where
import Data.Char (chr, ord, isAlpha, isMark, isDigit)
import Codec.Binary.UTF8.String (encode)
import Data.Char (isAlphaNum, isAscii)
import Data.List (isPrefixOf)
import Numeric (showIntAtBase)
import Text.Printf
import XMonad (X(), MonadIO, liftIO)
import XMonad.Prompt (XPrompt(showXPrompt), mkXPrompt, XPConfig(), historyCompletionP)
import XMonad.Prompt (XPrompt(showXPrompt, nextCompletion, commandToComplete), mkXPrompt, XPConfig(), historyCompletionP, getNextCompletion)
import XMonad.Prompt.Shell (getBrowser)
import XMonad.Util.Run (safeSpawn)
import XMonad.Util.XSelection (getSelection)
{- $usage
This module is intended to allow easy access to databases on the
@@ -120,6 +126,8 @@ import XMonad.Util.XSelection (getSelection)
* 'mathworld' -- Wolfram MathWorld search.
* 'openstreetmap' -- OpenStreetMap free wiki world map.
* 'scholar' -- Google scholar academic search.
* 'thesaurus' -- thesaurus.reference.com search.
@@ -194,31 +202,18 @@ Happy searching! -}
data Search = Search Name
instance XPrompt Search where
showXPrompt (Search name)= "Search [" ++ name ++ "]: "
nextCompletion _ = getNextCompletion
commandToComplete _ c = c
-- | Escape the search string so search engines understand it.
-- Note that everything is escaped; we could be smarter and use 'isAllowedInURI'
-- but then that'd be hard enough to copy-and-paste we'd need to depend on @network@.
-- | Escape the search string so search engines understand it. Only
-- digits and ASCII letters are not encoded. All non ASCII characters
-- which are encoded as UTF8
escape :: String -> String
escape = escapeURIString (\c -> isAlpha c || isDigit c || isMark c)
where -- Copied from Network.URI.
escapeURIString ::
(Char -> Bool) -- a predicate which returns 'False' if should escape
-> String -- the string to process
-> String -- the resulting URI string
escapeURIString = concatMap . escapeURIChar
escapeURIChar :: (Char->Bool) -> Char -> String
escapeURIChar p c
| p c = [c]
| otherwise = '%' : myShowHex (ord c) ""
where
myShowHex :: Int -> ShowS
myShowHex n r = case showIntAtBase 16 toChrHex n r of
[] -> "00"
[ch] -> ['0',ch]
cs -> cs
toChrHex d
| d < 10 = chr (ord '0' + fromIntegral d)
| otherwise = chr (ord 'A' + fromIntegral (d - 10))
escape = concatMap escapeURIChar
escapeURIChar :: Char -> String
escapeURIChar c | isAscii c && isAlphaNum c = [c]
| otherwise = concatMap (printf "%%%02X") $ encode [c]
type Browser = FilePath
type Query = String
@@ -258,8 +253,8 @@ searchEngine name site = searchEngineF name (\s -> site ++ (escape s))
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
> searchFunc s | "wiki:" `isPrefixOf` s = "http://en.wikipedia.org/wiki/" ++ (escape $ tail $ snd $ break (==':') s)
> | "http://" `isPrefixOf` s = s
> | otherwise = (use google) s
> myNewEngine = searchEngineF "mymulti" searchFunc
@@ -276,36 +271,34 @@ searchEngineF = SearchEngine
-- The engines.
amazon, alpha, codesearch, deb, debbts, debpts, dictionary, google, hackage, hoogle,
images, imdb, isohunt, lucky, maps, mathworld, scholar, thesaurus, wayback, wikipedia, wiktionary,
images, imdb, isohunt, lucky, maps, mathworld, openstreetmap, 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 "dict" "http://dictionary.reference.com/browse/"
google = searchEngine "google" "http://www.google.com/search?num=100&q="
hackage = searchEngine "hackage" "http://hackage.haskell.org/package/"
hoogle = searchEngine "hoogle" "http://www.haskell.org/hoogle/?q="
images = searchEngine "images" "http://images.google.fr/images?q="
imdb = searchEngine "imdb" "http://www.imdb.com/Find?select=all&for="
isohunt = searchEngine "isohunt" "http://isohunt.com/torrents/?ihq="
lucky = searchEngine "lucky" "http://www.google.com/search?btnI&q="
maps = searchEngine "maps" "http://maps.google.com/maps?q="
mathworld = searchEngine "mathworld" "http://mathworld.wolfram.com/search/?query="
scholar = searchEngine "scholar" "http://scholar.google.com/scholar?q="
thesaurus = searchEngine "thesaurus" "http://thesaurus.reference.com/search?q="
wikipedia = searchEngine "wiki" "https://secure.wikimedia.org/wikipedia/en/wiki/Special:Search?go=Go&search="
wiktionary = searchEngine "wikt" "http://en.wiktionary.org/wiki/Special:Search?go=Go&search="
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/"
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 "dict" "http://dictionary.reference.com/browse/"
google = searchEngine "google" "http://www.google.com/search?num=100&q="
hackage = searchEngine "hackage" "http://hackage.haskell.org/package/"
hoogle = searchEngine "hoogle" "http://www.haskell.org/hoogle/?q="
images = searchEngine "images" "http://images.google.fr/images?q="
imdb = searchEngine "imdb" "http://www.imdb.com/find?s=all&q="
isohunt = searchEngine "isohunt" "http://isohunt.com/torrents/?ihq="
lucky = searchEngine "lucky" "http://www.google.com/search?btnI&q="
maps = searchEngine "maps" "http://maps.google.com/maps?q="
mathworld = searchEngine "mathworld" "http://mathworld.wolfram.com/search/?query="
openstreetmap = searchEngine "openstreetmap" "http://gazetteer.openstreetmap.org/namefinder/?find="
scholar = searchEngine "scholar" "http://scholar.google.com/scholar?q="
thesaurus = searchEngine "thesaurus" "http://thesaurus.reference.com/search?q="
wikipedia = searchEngine "wiki" "http://en.wikipedia.org/wiki/Special:Search?go=Go&search="
wiktionary = searchEngine "wikt" "http://en.wiktionary.org/wiki/Special:Search?go=Go&search="
youtube = searchEngine "youtube" "http://www.youtube.com/results?search_type=search_videos&search_query="
wayback = searchEngineF "wayback" ("http://web.archive.org/web/*/"++)
multi :: SearchEngine
multi = namedEngine "multi" $ foldr1 (!>) [amazon, alpha, codesearch, deb, debbts, debpts, dictionary, google, hackage, hoogle, images, imdb, isohunt, lucky, maps, mathworld, scholar, thesaurus, wayback, wikipedia, wiktionary, (prefixAware google)]
multi = namedEngine "multi" $ foldr1 (!>) [amazon, alpha, codesearch, deb, debbts, debpts, dictionary, google, hackage, hoogle, images, imdb, isohunt, lucky, maps, mathworld, openstreetmap, 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
@@ -334,14 +327,14 @@ removeColonPrefix s = if ':' `elem` s then drop 1 $ dropWhile (':' /=) s else s
\"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)
(SearchEngine name1 site1) !> (SearchEngine name2 site2) = searchEngineF (name1 ++ "/" ++ name2) (\s -> if (name1++":") `isPrefixOf` s 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)
prefixAware (SearchEngine name site) = SearchEngine name (\s -> if (name++":") `isPrefixOf` s then site $ removeColonPrefix s else site s)
{- | Changes search engine's name -}
namedEngine :: Name -> SearchEngine -> SearchEngine

116
XMonad/Actions/ShowText.hs Normal file
View File

@@ -0,0 +1,116 @@
{-# LANGUAGE DeriveDataTypeable #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.ShowText
-- Copyright : (c) Mario Pastorelli (2012)
-- License : BSD-style (see xmonad/LICENSE)
--
-- Maintainer : pastorelli.mario@gmail.com
-- Stability : unstable
-- Portability : unportable
--
-- ShowText displays text for sometime on the screen similar to "XMonad.Util.Dzen"
-- which offers more features (currently)
-----------------------------------------------------------------------------
module XMonad.Actions.ShowText
( -- * Usage
-- $usage
defaultSTConfig
, handleTimerEvent
, flashText
, ShowTextConfig(..)
) where
import Control.Monad (when)
import Data.Map (Map,empty,insert,lookup)
import Data.Monoid (mempty, All)
import Prelude hiding (lookup)
import XMonad
import XMonad.StackSet (current,screen)
import XMonad.Util.Font (Align(AlignCenter)
, initXMF
, releaseXMF
, textExtentsXMF
, textWidthXMF)
import XMonad.Util.Timer (startTimer)
import XMonad.Util.XUtils (createNewWindow
, deleteWindow
, fi
, showWindow
, paintAndWrite)
import qualified XMonad.Util.ExtensibleState as ES
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
--
-- > import XMonad.Actions.ShowText
--
-- Then add the event hook handler:
--
-- > xmonad { handleEventHook = myHandleEventHooks <+> handleTimerEvent }
--
-- You can then use flashText in your keybindings:
--
-- > ((modMask, xK_Right), flashText defaultSTConfig 1 "->" >> nextWS)
--
-- | ShowText contains the map with timers as keys and created windows as values
newtype ShowText = ShowText (Map Atom Window)
deriving (Read,Show,Typeable)
instance ExtensionClass ShowText where
initialValue = ShowText empty
-- | Utility to modify a ShowText
modShowText :: (Map Atom Window -> Map Atom Window) -> ShowText -> ShowText
modShowText f (ShowText m) = ShowText $ f m
data ShowTextConfig =
STC { st_font :: String -- ^ Font name
, st_bg :: String -- ^ Background color
, st_fg :: String -- ^ Foreground color
}
defaultSTConfig :: ShowTextConfig
defaultSTConfig =
STC { st_font = "-misc-fixed-*-*-*-*-20-*-*-*-*-*-*-*"
, st_bg = "black"
, st_fg = "white"
}
-- | Handles timer events that notify when a window should be removed
handleTimerEvent :: Event -> X All
handleTimerEvent (ClientMessageEvent _ _ _ dis _ mtyp d) = do
(ShowText m) <- ES.get :: X ShowText
a <- io $ internAtom dis "XMONAD_TIMER" False
when (mtyp == a && length d >= 1)
(whenJust (lookup (fromIntegral $ d !! 0) m) deleteWindow)
mempty
handleTimerEvent _ = mempty
-- | Shows a window in the center of the screen with the given text
flashText :: ShowTextConfig
-> Rational -- ^ number of seconds
-> String -- ^ text to display
-> X ()
flashText c i s = do
f <- initXMF (st_font c)
d <- asks display
sc <- gets $ fi . screen . current . windowset
width <- textWidthXMF d f s
(as,ds) <- textExtentsXMF f s
let hight = as + ds
ht = displayHeight d sc
wh = displayWidth d sc
y = (fi ht - hight + 2) `div` 2
x = (fi wh - width + 2) `div` 2
w <- createNewWindow (Rectangle (fi x) (fi y) (fi width) (fi hight))
Nothing "" True
showWindow w
paintAndWrite w f (fi width) (fi hight) 0 (st_bg c) ""
(st_fg c) (st_bg c) [AlignCenter] [s]
releaseXMF f
io $ sync d False
t <- startTimer i
ES.modify $ modShowText (insert (fromIntegral t) w)

View File

@@ -1,3 +1,4 @@
{-# LANGUAGE DeriveDataTypeable #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.SpawnOn
@@ -18,7 +19,6 @@ module XMonad.Actions.SpawnOn (
-- * Usage
-- $usage
Spawner,
mkSpawner,
manageSpawn,
spawnHere,
spawnOn,
@@ -28,7 +28,6 @@ module XMonad.Actions.SpawnOn (
) where
import Data.List (isInfixOf)
import Data.IORef
import System.Posix.Types (ProcessID)
import XMonad
@@ -37,6 +36,7 @@ import qualified XMonad.StackSet as W
import XMonad.Hooks.ManageHelpers
import XMonad.Prompt
import XMonad.Prompt.Shell
import qualified XMonad.Util.ExtensibleState as XS
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
@@ -44,17 +44,16 @@ import XMonad.Prompt.Shell
-- > import XMonad.Actions.SpawnOn
--
-- > main = do
-- > sp <- mkSpawner
-- > xmonad defaultConfig {
-- > ...
-- > manageHook = manageSpawn sp <+> manageHook defaultConfig
-- > manageHook = manageSpawn <+> manageHook defaultConfig
-- > ...
-- > }
--
-- To ensure that application appears on a workspace it was launched at, add keybindings like:
--
-- > , ((mod1Mask,xK_o), spawnHere sp "urxvt")
-- > , ((mod1Mask,xK_s), shellPromptHere sp defaultXPConfig)
-- > , ((mod1Mask,xK_o), spawnHere "urxvt")
-- > , ((mod1Mask,xK_s), shellPromptHere defaultXPConfig)
--
-- The module can also be used to apply other manage hooks to the window of
-- the spawned application(e.g. float or resize it).
@@ -62,26 +61,29 @@ import XMonad.Prompt.Shell
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
newtype Spawner = Spawner {pidsRef :: IORef [(ProcessID, ManageHook)]}
newtype Spawner = Spawner {pidsRef :: [(ProcessID, ManageHook)]} deriving Typeable
instance ExtensionClass Spawner where
initialValue = Spawner []
maxPids :: Int
maxPids = 5
-- | Create 'Spawner' which then has to be passed to other functions.
mkSpawner :: (Functor m, MonadIO m) => m Spawner
mkSpawner = io . fmap Spawner $ newIORef []
-- | Get the current Spawner or create one if it doesn't exist.
modifySpawner :: ([(ProcessID, ManageHook)] -> [(ProcessID, ManageHook)]) -> X ()
modifySpawner f = XS.modify (Spawner . f . pidsRef)
-- | Provides a manage hook to react on process spawned with
-- 'spawnOn', 'spawnHere' etc.
manageSpawn :: Spawner -> ManageHook
manageSpawn sp = do
pids <- io . readIORef $ pidsRef sp
manageSpawn :: ManageHook
manageSpawn = do
Spawner pids <- liftX XS.get
mp <- pid
case flip lookup pids =<< mp of
Nothing -> doF id
Nothing -> idHook
Just mh -> do
whenJust mp $ \p ->
io . modifyIORef (pidsRef sp) $ filter ((/= p) . fst)
liftX . modifySpawner $ filter ((/= p) . fst)
mh
mkPrompt :: (String -> X ()) -> XPConfig -> X ()
@@ -91,32 +93,31 @@ mkPrompt cb c = do
-- | Replacement for Shell prompt ("XMonad.Prompt.Shell") which launches
-- application on current workspace.
shellPromptHere :: Spawner -> XPConfig -> X ()
shellPromptHere sp = mkPrompt (spawnHere sp)
shellPromptHere :: XPConfig -> X ()
shellPromptHere = mkPrompt spawnHere
-- | Replacement for Shell prompt ("XMonad.Prompt.Shell") which launches
-- application on given workspace.
shellPromptOn :: Spawner -> WorkspaceId -> XPConfig -> X ()
shellPromptOn sp ws = mkPrompt (spawnOn sp ws)
shellPromptOn :: WorkspaceId -> XPConfig -> X ()
shellPromptOn ws = mkPrompt (spawnOn ws)
-- | Replacement for 'spawn' which launches
-- application on current workspace.
spawnHere :: Spawner -> String -> X ()
spawnHere sp cmd = withWindowSet $ \ws -> spawnOn sp (W.currentTag ws) cmd
spawnHere :: String -> X ()
spawnHere cmd = withWindowSet $ \ws -> spawnOn (W.currentTag ws) cmd
-- | Replacement for 'spawn' which launches
-- application on given workspace.
spawnOn :: Spawner -> WorkspaceId -> String -> X ()
spawnOn sp ws cmd = spawnAndDo sp (doShift ws) cmd
spawnOn :: WorkspaceId -> String -> X ()
spawnOn ws cmd = spawnAndDo (doShift ws) cmd
-- | Spawn an application and apply the manage hook when it opens.
spawnAndDo :: Spawner -> ManageHook -> String -> X ()
spawnAndDo sp mh cmd = do
spawnAndDo :: ManageHook -> String -> X ()
spawnAndDo mh cmd = do
p <- spawnPID $ mangle cmd
io $ modifyIORef (pidsRef sp) (take maxPids . ((p,mh) :))
modifySpawner $ (take maxPids . ((p,mh) :))
where
-- TODO this is silly, search for a better solution
mangle xs | any (`elem` metaChars) xs || "exec" `isInfixOf` xs = xs
| otherwise = "exec " ++ xs
metaChars = "&|;"

View File

@@ -76,6 +76,7 @@ submapDefault def keys = do
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
maybe def id (M.lookup (m', s) keys)

View File

@@ -25,7 +25,6 @@ module XMonad.Actions.SwapWorkspaces (
import XMonad (windows, X())
import XMonad.StackSet
import XMonad.Actions.CycleWS
import XMonad.Util.Types
import XMonad.Util.WorkspaceCompare

View File

@@ -22,17 +22,22 @@ module XMonad.Actions.TagWindows (
focusDownTagged, focusDownTaggedGlobal,
shiftHere, shiftToScreen,
tagPrompt,
tagDelPrompt
tagDelPrompt,
TagPrompt,
) where
import Data.List (nub,concat,sortBy)
import Data.List (nub,sortBy)
import Control.Monad
import Control.Exception as E
import XMonad.StackSet hiding (filter)
import XMonad.Prompt
import XMonad hiding (workspaces)
econst :: Monad m => a -> IOException -> m a
econst = const . return
-- $usage
--
-- To use window tags, import this module into your @~\/.xmonad\/xmonad.hs@:
@@ -76,10 +81,10 @@ setTag s w = withDisplay $ \d ->
-- reads from the \"_XMONAD_TAGS\" window property
getTags :: Window -> X [String]
getTags w = withDisplay $ \d ->
io $ catch (internAtom d "_XMONAD_TAGS" False >>=
io $ E.catch (internAtom d "_XMONAD_TAGS" False >>=
getTextProperty d w >>=
wcTextPropertyToTextList d)
(\_ -> return [[]])
(econst [[]])
>>= return . words . unwords
-- | check a window for the given tag

View File

@@ -1,3 +1,4 @@
{-# LANGUAGE DeriveDataTypeable #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.TopicSpace
@@ -21,8 +22,10 @@ module XMonad.Actions.TopicSpace
Topic
, Dir
, TopicConfig(..)
, defaultTopicConfig
, getLastFocusedTopics
, setLastFocusedTopic
, reverseLastFocusedTopics
, pprWindowSet
, topicActionWithPrompt
, topicAction
@@ -39,13 +42,12 @@ where
import XMonad
import Data.List
import Data.Maybe (fromMaybe, isNothing, listToMaybe)
import Data.Maybe (fromMaybe, isNothing, listToMaybe, fromJust)
import Data.Ord
import qualified Data.Map as M
import Control.Monad ((=<<),liftM2,when,unless,replicateM_)
import Control.Monad (liftM2,when,unless,replicateM_)
import System.IO
import XMonad.Operations
import qualified XMonad.StackSet as W
import XMonad.Prompt
@@ -56,7 +58,7 @@ import XMonad.Hooks.DynamicLog (PP(..))
import qualified XMonad.Hooks.DynamicLog as DL
import XMonad.Util.Run (spawnPipe)
import XMonad.Util.StringProp(getStringListProp,setStringListProp)
import qualified XMonad.Util.ExtensibleState as XS
-- $overview
-- This module allows to organize your workspaces on a precise topic basis. So
@@ -74,129 +76,108 @@ import XMonad.Util.StringProp(getStringListProp,setStringListProp)
-- $usage
-- Here is an example of configuration using TopicSpace:
--
-- @
-- -- The list of all topics/workspaces of your xmonad configuration.
-- -- The order is important, new topics must be inserted
-- -- at the end of the list if you want hot-restarting
-- -- to work.
-- myTopics :: [Topic]
-- myTopics =
-- [ \"dashboard\" -- the first one
-- , \"admin\", \"build\", \"cleaning\", \"conf\", \"darcs\", \"haskell\", \"irc\"
-- , \"mail\", \"movie\", \"music\", \"talk\", \"text\", \"tools\", \"web\", \"xmonad\"
-- , \"yi\", \"documents\", \"twitter\", \"pdf\"
-- ]
-- @
--
-- @
-- myTopicConfig :: TopicConfig
-- myTopicConfig = TopicConfig
-- { topicDirs = M.fromList $
-- [ (\"conf\", \"w\/conf\")
-- , (\"dashboard\", \"Desktop\")
-- , (\"yi\", \"w\/dev-haskell\/yi\")
-- , (\"darcs\", \"w\/dev-haskell\/darcs\")
-- , (\"haskell\", \"w\/dev-haskell\")
-- , (\"xmonad\", \"w\/dev-haskell\/xmonad\")
-- , (\"tools\", \"w\/tools\")
-- , (\"movie\", \"Movies\")
-- , (\"talk\", \"w\/talks\")
-- , (\"music\", \"Music\")
-- , (\"documents\", \"w\/documents\")
-- , (\"pdf\", \"w\/documents\")
-- ]
-- , defaultTopicAction = const $ spawnShell >*> 3
-- , defaultTopic = \"dashboard\"
-- , maxTopicHistory = 10
-- , topicActions = M.fromList $
-- [ (\"conf\", spawnShell >> spawnShellIn \"wd\/ertai\/private\")
-- , (\"darcs\", spawnShell >*> 3)
-- , (\"yi\", spawnShell >*> 3)
-- , (\"haskell\", spawnShell >*> 2 >>
-- spawnShellIn \"wd\/dev-haskell\/ghc\")
-- , (\"xmonad\", spawnShellIn \"wd\/x11-wm\/xmonad\" >>
-- spawnShellIn \"wd\/x11-wm\/xmonad\/contrib\" >>
-- spawnShellIn \"wd\/x11-wm\/xmonad\/utils\" >>
-- spawnShellIn \".xmonad\" >>
-- spawnShellIn \".xmonad\")
-- , (\"mail\", mailAction)
-- , (\"irc\", ssh somewhere)
-- , (\"admin\", ssh somewhere >>
-- ssh nowhere)
-- , (\"dashboard\", spawnShell)
-- , (\"twitter\", spawnShell)
-- , (\"web\", spawn browserCmd)
-- , (\"movie\", spawnShell)
-- , (\"documents\", spawnShell >*> 2 >>
-- spawnShellIn \"Documents\" >*> 2)
-- , (\"pdf\", spawn pdfViewerCmd)
-- ]
-- }
-- @
--
-- @
-- -- extend your keybindings
-- myKeys conf\@XConfig{modMask=modm} =
-- [ ((modm , xK_n ), spawnShell) -- %! Launch terminal
-- , ((modm , xK_a ), currentTopicAction myTopicConfig)
-- , ((modm , xK_g ), promptedGoto)
-- , ((modm .|. shiftMask, xK_g ), promptedShift)
-- ...
-- ]
-- ++
-- [ ((modm, k), switchNthLastFocused myTopicConfig i)
-- | (i, k) <- zip [1..] workspaceKeys]
-- @
--
-- @
-- spawnShell :: X ()
-- spawnShell = currentTopicDir myTopicConfig >>= spawnShellIn
-- @
--
-- @
-- spawnShellIn :: Dir -> X ()
-- spawnShellIn dir = spawn $ \"urxvt '(cd ''\" ++ dir ++ \"'' && \" ++ myShell ++ \" )'\"
-- @
--
-- @
-- goto :: Topic -> X ()
-- goto = switchTopic myTopicConfig
-- @
--
-- @
-- promptedGoto :: X ()
-- promptedGoto = workspacePrompt myXPConfig goto
-- @
--
-- @
-- promptedShift :: X ()
-- promptedShift = workspacePrompt myXPConfig $ windows . W.shift
-- @
--
-- @
-- myConfig = do
-- checkTopicConfig myTopics myTopicConfig
-- myLogHook <- makeMyLogHook
-- return $ defaultConfig
-- { borderWidth = 1 -- Width of the window border in pixels.
-- , workspaces = myTopics
-- , layoutHook = myModifiers myLayout
-- , manageHook = myManageHook
-- , logHook = myLogHook
-- , handleEventHook = myHandleEventHook
-- , terminal = myTerminal -- The preferred terminal program.
-- , normalBorderColor = \"#3f3c6d\"
-- , focusedBorderColor = \"#4f66ff\"
-- , XMonad.modMask = mod1Mask
-- , keys = myKeys
-- , mouseBindings = myMouseBindings
-- }
-- @
--
-- @
-- main :: IO ()
-- main = xmonad =<< myConfig
-- @
-- > -- The list of all topics/workspaces of your xmonad configuration.
-- > -- The order is important, new topics must be inserted
-- > -- at the end of the list if you want hot-restarting
-- > -- to work.
-- > myTopics :: [Topic]
-- > myTopics =
-- > [ "dashboard" -- the first one
-- > , "admin", "build", "cleaning", "conf", "darcs", "haskell", "irc"
-- > , "mail", "movie", "music", "talk", "text", "tools", "web", "xmonad"
-- > , "yi", "documents", "twitter", "pdf"
-- > ]
-- >
-- > myTopicConfig :: TopicConfig
-- > myTopicConfig = defaultTopicConfig
-- > { topicDirs = M.fromList $
-- > [ ("conf", "w/conf")
-- > , ("dashboard", "Desktop")
-- > , ("yi", "w/dev-haskell/yi")
-- > , ("darcs", "w/dev-haskell/darcs")
-- > , ("haskell", "w/dev-haskell")
-- > , ("xmonad", "w/dev-haskell/xmonad")
-- > , ("tools", "w/tools")
-- > , ("movie", "Movies")
-- > , ("talk", "w/talks")
-- > , ("music", "Music")
-- > , ("documents", "w/documents")
-- > , ("pdf", "w/documents")
-- > ]
-- > , defaultTopicAction = const $ spawnShell >*> 3
-- > , defaultTopic = "dashboard"
-- > , topicActions = M.fromList $
-- > [ ("conf", spawnShell >> spawnShellIn "wd/ertai/private")
-- > , ("darcs", spawnShell >*> 3)
-- > , ("yi", spawnShell >*> 3)
-- > , ("haskell", spawnShell >*> 2 >>
-- > spawnShellIn "wd/dev-haskell/ghc")
-- > , ("xmonad", spawnShellIn "wd/x11-wm/xmonad" >>
-- > spawnShellIn "wd/x11-wm/xmonad/contrib" >>
-- > spawnShellIn "wd/x11-wm/xmonad/utils" >>
-- > spawnShellIn ".xmonad" >>
-- > spawnShellIn ".xmonad")
-- > , ("mail", mailAction)
-- > , ("irc", ssh somewhere)
-- > , ("admin", ssh somewhere >>
-- > ssh nowhere)
-- > , ("dashboard", spawnShell)
-- > , ("twitter", spawnShell)
-- > , ("web", spawn browserCmd)
-- > , ("movie", spawnShell)
-- > , ("documents", spawnShell >*> 2 >>
-- > spawnShellIn "Documents" >*> 2)
-- > , ("pdf", spawn pdfViewerCmd)
-- > ]
-- > }
-- >
-- > -- extend your keybindings
-- > myKeys conf@XConfig{modMask=modm} =
-- > [ ((modm , xK_n ), spawnShell) -- %! Launch terminal
-- > , ((modm , xK_a ), currentTopicAction myTopicConfig)
-- > , ((modm , xK_g ), promptedGoto)
-- > , ((modm .|. shiftMask, xK_g ), promptedShift)
-- > {- more keys ... -}
-- > ]
-- > ++
-- > [ ((modm, k), switchNthLastFocused myTopicConfig i)
-- > | (i, k) <- zip [1..] workspaceKeys]
-- >
-- > spawnShell :: X ()
-- > spawnShell = currentTopicDir myTopicConfig >>= spawnShellIn
-- >
-- > spawnShellIn :: Dir -> X ()
-- > spawnShellIn dir = spawn $ "urxvt '(cd ''" ++ dir ++ "'' && " ++ myShell ++ " )'"
-- >
-- > goto :: Topic -> X ()
-- > goto = switchTopic myTopicConfig
-- >
-- > promptedGoto :: X ()
-- > promptedGoto = workspacePrompt myXPConfig goto
-- >
-- > promptedShift :: X ()
-- > promptedShift = workspacePrompt myXPConfig $ windows . W.shift
-- >
-- > myConfig = do
-- > checkTopicConfig myTopics myTopicConfig
-- > myLogHook <- makeMyLogHook
-- > return $ defaultConfig
-- > { borderWidth = 1 -- Width of the window border in pixels.
-- > , workspaces = myTopics
-- > , layoutHook = myModifiers myLayout
-- > , manageHook = myManageHook
-- > , logHook = myLogHook
-- > , handleEventHook = myHandleEventHook
-- > , terminal = myTerminal -- The preferred terminal program.
-- > , normalBorderColor = "#3f3c6d"
-- > , focusedBorderColor = "#4f66ff"
-- > , XMonad.modMask = mod1Mask
-- > , keys = myKeys
-- > , mouseBindings = myMouseBindings
-- > }
-- >
-- > main :: IO ()
-- > main = xmonad =<< myConfig
-- | An alias for @flip replicateM_@
(>*>) :: Monad m => m a -> Int -> m ()
@@ -225,19 +206,37 @@ data TopicConfig = TopicConfig { topicDirs :: M.Map Topic Dir
-- numeric keypad.
}
defaultTopicConfig :: TopicConfig
defaultTopicConfig = TopicConfig { topicDirs = M.empty
, topicActions = M.empty
, defaultTopicAction = const (ask >>= spawn . terminal . config)
, defaultTopic = "1"
, maxTopicHistory = 10
}
newtype PrevTopics = PrevTopics { getPrevTopics :: [String] } deriving (Read,Show,Typeable)
instance ExtensionClass PrevTopics where
initialValue = PrevTopics []
extensionType = PersistentExtension
-- | Returns the list of last focused workspaces the empty list otherwise.
-- This function rely on a reserved property namely _XMONAD_LAST_FOCUSED_WORKSPACES.
getLastFocusedTopics :: X [String]
getLastFocusedTopics = asks display >>= flip getStringListProp "_XMONAD_LAST_FOCUSED_WORKSPACES"
getLastFocusedTopics = XS.gets getPrevTopics
-- | Given a 'TopicConfig', the last focused topic, and a predicate that will
-- select topics that one want to keep, this function will set the property
-- of last focused topics.
setLastFocusedTopic :: TopicConfig -> Topic -> (Topic -> Bool) -> X ()
setLastFocusedTopic tg w predicate = do
disp <- asks display
setStringListProp disp "_XMONAD_LAST_FOCUSED_WORKSPACES"
. take (maxTopicHistory tg) . nub . (w:) . filter predicate =<< getLastFocusedTopics
setLastFocusedTopic :: Topic -> (Topic -> Bool) -> X ()
setLastFocusedTopic w predicate =
XS.modify $ PrevTopics
. seqList . nub . (w:) . filter predicate
. getPrevTopics
where seqList xs = length xs `seq` xs
-- | Reverse the list of "last focused topics"
reverseLastFocusedTopics :: X ()
reverseLastFocusedTopics =
XS.modify $ PrevTopics . reverse . getPrevTopics
-- | This function is a variant of 'DL.pprWindowSet' which takes a topic configuration
-- and a pretty-printing record 'PP'. It will show the list of topics sorted historically
@@ -248,13 +247,13 @@ pprWindowSet tg pp = do
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)
setLastFocusedTopic (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
let depth topic = fromJust $ elemIndex topic (lastWs ++ [topic])
add_depth proj topic = proj pp . (((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)
sortWindows = take maxDepth . sortBy (comparing $ depth . W.tag)
return $ DL.pprWindowSet sortWindows urgents pp' winset
-- | Given a prompt configuration and a topic configuration, triggers the action associated with
@@ -278,7 +277,7 @@ switchTopic tg topic = do
when (null wins) $ topicAction tg topic
-- | Switch to the Nth last focused topic or failback to the 'defaultTopic'.
switchNthLastFocused ::TopicConfig -> Int -> X ()
switchNthLastFocused :: TopicConfig -> Int -> X ()
switchNthLastFocused tg depth = do
lastWs <- getLastFocusedTopics
switchTopic tg $ (lastWs ++ repeat (defaultTopic tg)) !! depth

View File

@@ -21,7 +21,6 @@ module XMonad.Actions.UpdateFocus (
import XMonad
import qualified XMonad.StackSet as W
import Graphics.X11.Xlib.Extras
import Control.Monad (when)
import Data.Monoid
@@ -45,10 +44,10 @@ 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
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
when (foc /= Just w) $ focus w
return (All True)
focusOnMouseMove _ = return (All True)

View File

@@ -24,6 +24,7 @@ module XMonad.Actions.UpdatePointer
where
import XMonad
import XMonad.Util.XUtils (fi)
import Control.Monad
import XMonad.StackSet (member, peek, screenDetail, current)
import Data.Maybe
@@ -91,8 +92,10 @@ updatePointer p = do
where fraction x y = floor (x * fromIntegral y)
windowAttributesToRectangle :: WindowAttributes -> Rectangle
windowAttributesToRectangle wa = Rectangle (fi (wa_x wa)) (fi (wa_y wa))
(fi (wa_width wa)) (fi (wa_height wa))
windowAttributesToRectangle wa = Rectangle (fi (wa_x wa))
(fi (wa_y wa))
(fi (wa_width wa + 2 * wa_border_width wa))
(fi (wa_height wa + 2 * wa_border_width wa))
moveWithin :: Ord a => a -> a -> a -> a
moveWithin now lower upper =
if now < lower
@@ -100,6 +103,3 @@ moveWithin now lower upper =
else if now > upper
then upper
else now
fi :: (Num b, Integral a) => a -> b
fi = fromIntegral

View File

@@ -22,7 +22,6 @@ module XMonad.Actions.Warp (
warpToWindow
) where
import Data.Ratio
import Data.List
import XMonad
import XMonad.StackSet as W

View File

@@ -17,7 +17,9 @@
module XMonad.Actions.WindowBringer (
-- * Usage
-- $usage
gotoMenu, gotoMenu', bringMenu, windowMap,
gotoMenu, gotoMenu', gotoMenuArgs, gotoMenuArgs',
bringMenu, bringMenu', bringMenuArgs, bringMenuArgs',
windowMap,
bringWindow
) where
@@ -27,7 +29,7 @@ import qualified Data.Map as M
import qualified XMonad.StackSet as W
import XMonad
import qualified XMonad as X
import XMonad.Util.Dmenu (menuMap)
import XMonad.Util.Dmenu (menuMapArgs)
import XMonad.Util.NamedWindows (getName)
-- $usage
@@ -44,19 +46,54 @@ import XMonad.Util.NamedWindows (getName)
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
-- | Default menu command
defaultCmd :: String
defaultCmd = "dmenu"
-- | Pops open a dmenu with window titles. Choose one, and you will be
-- taken to the corresponding workspace.
gotoMenu :: X ()
gotoMenu = actionMenu W.focusWindow
gotoMenu = gotoMenuArgs []
-- | Pops open a dmenu with window titles. Choose one, and you will be
-- taken to the corresponding workspace. This version takes a list of
-- arguments to pass to dmenu.
gotoMenuArgs :: [String] -> X ()
gotoMenuArgs menuArgs = gotoMenuArgs' defaultCmd menuArgs
-- | Pops open an application with window titles given over stdin. Choose one,
-- and you will be taken to the corresponding workspace.
gotoMenu' :: String -> X ()
gotoMenu' menuCmd = actionMenu' menuCmd W.focusWindow
gotoMenu' menuCmd = gotoMenuArgs' menuCmd []
-- | Pops open an application with window titles given over stdin. Choose one,
-- and you will be taken to the corresponding workspace. This version takes a
-- list of arguments to pass to dmenu.
gotoMenuArgs' :: String -> [String] -> X ()
gotoMenuArgs' menuCmd menuArgs = actionMenu menuCmd menuArgs W.focusWindow
-- | Pops open a dmenu with window titles. Choose one, and it will be
-- dragged, kicking and screaming, into your current workspace.
bringMenu :: X ()
bringMenu = actionMenu bringWindow
bringMenu = bringMenuArgs []
-- | Pops open a dmenu with window titles. Choose one, and it will be
-- dragged, kicking and screaming, into your current workspace. This version
-- takes a list of arguments to pass to dmenu.
bringMenuArgs :: [String] -> X ()
bringMenuArgs menuArgs = bringMenuArgs' defaultCmd menuArgs
-- | Pops open an application with window titles given over stdin. Choose one,
-- and it will be dragged, kicking and screaming, into your current
-- workspace.
bringMenu' :: String -> X ()
bringMenu' menuCmd = bringMenuArgs' menuCmd []
-- | Pops open an application with window titles given over stdin. Choose one,
-- and it will be dragged, kicking and screaming, into your current
-- workspace. This version allows arguments to the chooser to be specified.
bringMenuArgs' :: String -> [String] -> X ()
bringMenuArgs' menuCmd menuArgs = actionMenu menuCmd menuArgs bringWindow
-- | Brings the specified window into the current workspace.
bringWindow :: Window -> X.WindowSet -> X.WindowSet
@@ -64,14 +101,11 @@ bringWindow w ws = W.shiftWin (W.currentTag ws) w ws
-- | Calls dmenuMap to grab the appropriate Window, and hands it off to action
-- if found.
actionMenu :: (Window -> X.WindowSet -> X.WindowSet) -> X()
actionMenu action = actionMenu' "dmenu" action
actionMenu' :: String -> (Window -> X.WindowSet -> X.WindowSet) -> X()
actionMenu' menuCmd action = windowMap >>= menuMapFunction >>= flip X.whenJust (windows . action)
actionMenu :: String -> [String] -> (Window -> X.WindowSet -> X.WindowSet) -> X ()
actionMenu menuCmd menuArgs action = windowMap >>= menuMapFunction >>= flip X.whenJust (windows . action)
where
menuMapFunction :: M.Map String a -> X (Maybe a)
menuMapFunction selectionMap = menuMap menuCmd selectionMap
menuMapFunction selectionMap = menuMapArgs menuCmd menuArgs selectionMap
-- | A map from window names to Windows.
windowMap :: X (M.Map String Window)

View File

@@ -58,8 +58,9 @@ and define appropriate key bindings:
(Note that Firefox v3 and up have a class-name of \"Firefox\" and \"Navigator\";
lower versions use other classnames such as \"Firefox-bin\". Either choose the
appropriate one, or cover your bases by using instead something like
@(className =? \"Firefox\" <||> className =? \"Firefox-bin\")@.)
appropriate one, or cover your bases by using instead something like:
> (className =? "Firefox" <||> className =? "Firefox-bin")
For detailed instructions on editing your key bindings, see
"XMonad.Doc.Extending#Editing_key_bindings". -}
@@ -79,8 +80,11 @@ ifWindows qry f el = withWindowSet $ \wins -> do
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.
{- | '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.
Note that this does not go through the shell. If you wish to run an arbitrary IO action
(such as 'spawn', which will run its String argument through the shell), then you will want to use
'raiseMaybe' directly. -}
runOrRaise :: String -> Query Bool -> X ()
runOrRaise = raiseMaybe . safeSpawnProg
@@ -110,7 +114,7 @@ raise = raiseMaybe $ return ()
Mutt which you just did for Firefox - but Mutt runs inside a terminal window?
No problem: you search for a terminal window calling itself \"mutt\", and if
there isn't you run a terminal with a command to run Mutt! Here's an example
(borrowing 'runInTerm' from "XMonad.Utils.Run"):
(borrowing 'runInTerm' from "XMonad.Util.Run"):
> , ((modm, xK_m), raiseMaybe (runInTerm "-title mutt" "mutt") (title =? "mutt"))
-}
@@ -159,11 +163,11 @@ raiseEditor = raiseVar getEditor
{- | If the window is found the window is focused and the third argument is called
otherwise, the first argument is called
See 'raiseMaster' for an example. -}
raiseAndDo :: X () -> Query Bool -> (Window -> X ())-> X ()
raiseAndDo :: X () -> Query Bool -> (Window -> X ()) -> X ()
raiseAndDo f qry after = ifWindow qry (afterRaise `mappend` raiseHook) f
where afterRaise = ask >>= (>> idHook) . liftX . after
{- | If a window matching the second arugment is found, the window is focused and the third argument is called;
{- | If a window matching the second argument 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 . safeSpawnProg
@@ -171,14 +175,14 @@ runOrRaiseAndDo = raiseAndDo . safeSpawnProg
{- | if the window is found the window is focused and set to master
otherwise, the first argument is called.
> raiseMaster (runInTerm \"-title ghci\" \"zsh -c \'ghci\'\") (title =? \"ghci\") -}
> raiseMaster (runInTerm "-title ghci" "zsh -c 'ghci'") (title =? "ghci") -}
raiseMaster :: X () -> Query Bool -> X ()
raiseMaster raisef thatUserQuery = raiseAndDo raisef thatUserQuery (\_ -> windows W.swapMaster)
{- | If the window is found the window is focused and set to master
otherwise, action is run.
> runOrRaiseMaster \"firefox\" (className =? \"Firefox\"))
> runOrRaiseMaster "firefox" (className =? "Firefox"))
-}
runOrRaiseMaster :: String -> Query Bool -> X ()
runOrRaiseMaster run query = runOrRaiseAndDo run query (\_ -> windows W.swapMaster)

View File

@@ -41,6 +41,14 @@ import XMonad.Util.XUtils (fi)
--
-- > , ((modm, xK_o ), windowMenu)
colorizer :: a -> Bool -> X (String, String)
colorizer _ isFg = do
fBC <- asks (focusedBorderColor . config)
nBC <- asks (normalBorderColor . config)
return $ if isFg
then (fBC, nBC)
else (nBC, fBC)
windowMenu :: X ()
windowMenu = withFocused $ \w -> do
tags <- asks (workspaces . config)
@@ -48,13 +56,13 @@ windowMenu = withFocused $ \w -> do
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
gsConfig = (buildDefaultGSConfig colorizer)
{ gs_originFractX = originFractX
, gs_originFractY = originFractY }
actions = [ ("Cancel menu", return ())
, ("Close" , kill)
, ("Maximize" , sendMessage $ maximizeRestore w)
, ("Minimize" , sendMessage $ MinimizeWin w)
, ("Minimize" , minimizeWindow w)
] ++
[ ("Move to " ++ tag, windows $ W.shift tag)
| tag <- tags ]

View File

@@ -36,7 +36,7 @@ module XMonad.Actions.WindowNavigation (
withWindowNavigationKeys,
WNAction(..),
go, swap,
Direction2D(..)
Direction2D(..), WNState,
) where
import XMonad
@@ -52,7 +52,6 @@ import qualified Data.Map as M
import Data.Maybe (catMaybes, fromMaybe, listToMaybe)
import Data.Ord (comparing)
import qualified Data.Set as S
import Graphics.X11.Xlib
-- $usage
--

View File

@@ -18,8 +18,6 @@ module XMonad.Actions.WithAll (
import Data.Foldable hiding (foldr)
import XMonad
import XMonad.Core
import XMonad.Operations
import XMonad.StackSet
-- $usage

View File

@@ -0,0 +1,109 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.Workscreen
-- Copyright : (c) 2012 kedals0
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : Dal <kedasl0@gmail.com>
-- Stability : unstable
-- Portability: unportable
--
-- A workscreen permits to display a set of workspaces on several
-- screens. In xinerama mode, when a workscreen is viewed, workspaces
-- associated to all screens are visible.
--
-- The first workspace of a workscreen is displayed on first screen,
-- second on second screen, etc. Workspace position can be easily
-- changed. If the current workscreen is called again, workspaces are
-- shifted.
--
-- This also permits to see all workspaces of a workscreen even if just
-- one screen is present, and to move windows from workspace to workscreen.
-----------------------------------------------------------------------------
{-# LANGUAGE DeriveDataTypeable #-}
module XMonad.Actions.Workscreen (
-- * Usage
-- $usage
configWorkscreen
,viewWorkscreen
,Workscreen(..)
,shiftToWorkscreen
,fromWorkspace
,expandWorkspace
) where
import XMonad hiding (workspaces)
import qualified XMonad.StackSet as W
import qualified XMonad.Util.ExtensibleState as XS
import XMonad.Actions.OnScreen
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
--
-- > import XMonad.Actions.Workscreen
-- > myWorkspaces = let myOldWorkspaces = ["adm","work","mail"]
-- > in Workscreen.expandWorkspace 2 myOldWorkspaces
-- > myStartupHook = do Workscreen.configWorkscreen (Workscreen.fromWorkspace 2 myWorkspaces)
-- > return ()
--
-- Then, replace normal workspace view and shift keybinding:
--
-- > [((m .|. modm, k), f i)
-- > | (i, k) <- zip [0..] [1..12]
-- > , (f, m) <- [(Workscreen.viewWorkscreen, 0), (Workscreen.shiftToWorkscreen, shiftMask)]]
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
data Workscreen = Workscreen{workscreenId::Int,workspaces::[WorkspaceId]} deriving (Show,Typeable)
type WorkscreenId=Int
data WorkscreenStorage = WorkscreenStorage WorkscreenId [Workscreen] deriving (Show,Typeable)
instance ExtensionClass WorkscreenStorage where
initialValue = WorkscreenStorage 0 []
-- | Helper to group workspaces. Multiply workspace by screens number.
expandWorkspace :: Int -> [WorkspaceId] -> [WorkspaceId]
expandWorkspace nscr ws = concat $ map expandId ws
where expandId wsId = let t = wsId ++ "_"
in map ((++) t . show ) [1..nscr]
-- | Create workscreen list from workspace list. Group workspaces to
-- packets of screens number size.
fromWorkspace :: Int -> [WorkspaceId] -> [Workscreen]
fromWorkspace n ws = map (\(a,b) -> Workscreen a b) $ zip [0..] (fromWorkspace' n ws)
fromWorkspace' :: Int -> [WorkspaceId] -> [[WorkspaceId]]
fromWorkspace' _ [] = []
fromWorkspace' n ws = take n ws : fromWorkspace' n (drop n ws)
-- | Initial configuration of workscreens
configWorkscreen :: [Workscreen] -> X ()
configWorkscreen wscrn = XS.put (WorkscreenStorage 0 wscrn)
-- | View workscreen of index @WorkscreenId@. If current workscreen is asked
-- workscreen, workscreen's workspaces are shifted.
viewWorkscreen :: WorkscreenId -> X ()
viewWorkscreen wscrId = do (WorkscreenStorage c a) <- XS.get
let wscr = if wscrId == c
then Workscreen wscrId $ shiftWs (workspaces $ a !! wscrId)
else a !! wscrId
(x,_:ys) = splitAt wscrId a
newWorkscreenStorage = WorkscreenStorage wscrId (x ++ [wscr] ++ ys)
windows (viewWorkscreen' wscr)
XS.put newWorkscreenStorage
viewWorkscreen' :: Workscreen -> WindowSet -> WindowSet
viewWorkscreen' (Workscreen _ ws) = \s -> foldl wsToSc' s (zip [0..] ws)
where wsToSc' s (scr,wsId) = greedyViewOnScreen scr wsId s
shiftWs :: [WorkspaceId] -> [WorkspaceId]
shiftWs a = drop 1 a ++ take 1 a
-- | Shift a window on the first workspace of workscreen
-- @WorkscreenId@.
shiftToWorkscreen :: WorkscreenId -> X ()
shiftToWorkscreen wscrId = do (WorkscreenStorage _ a) <- XS.get
let ws = head . workspaces $ a !! wscrId
windows $ W.shift ws

View File

@@ -32,10 +32,13 @@ module XMonad.Actions.WorkspaceCursors
-- * Functions to pass to 'modifyLayer'
,focusNth'
,noWrapUp,noWrapDown
,noWrapUp,noWrapDown,
-- * Todo
-- $todo
-- * Types
Cursors,
) where
import qualified XMonad.StackSet as W

View File

@@ -0,0 +1,152 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.WorkspaceNames
-- Copyright : (c) Tomas Janousek <tomi@nomi.cz>
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : Tomas Janousek <tomi@nomi.cz>
-- Stability : experimental
-- Portability : unportable
--
-- Provides bindings to rename workspaces, show these names in DynamicLog and
-- swap workspaces along with their names. These names survive restart.
-- Together with "XMonad.Layout.WorkspaceDir" this provides for a fully
-- dynamic topic space workflow.
--
-----------------------------------------------------------------------------
{-# LANGUAGE DeriveDataTypeable #-}
module XMonad.Actions.WorkspaceNames (
-- * Usage
-- $usage
-- * Workspace naming
renameWorkspace,
workspaceNamesPP,
getWorkspaceNames,
setWorkspaceName,
setCurrentWorkspaceName,
-- * Workspace swapping
swapTo,
swapTo',
swapWithCurrent,
) where
import XMonad
import qualified XMonad.StackSet as W
import qualified XMonad.Util.ExtensibleState as XS
import XMonad.Actions.CycleWS (findWorkspace, WSType(..), Direction1D(..))
import qualified XMonad.Actions.SwapWorkspaces as Swap
import XMonad.Hooks.DynamicLog (PP(..))
import XMonad.Prompt (mkXPrompt, XPConfig)
import XMonad.Prompt.Workspace (Wor(Wor))
import XMonad.Util.WorkspaceCompare (getSortByIndex)
import qualified Data.Map as M
import Data.Maybe (fromMaybe)
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@ file:
--
-- > import XMonad.Actions.WorkspaceNames
--
-- Then add keybindings like the following:
--
-- > , ((modm .|. shiftMask, xK_r ), renameWorkspace defaultXPConfig)
--
-- and apply workspaceNamesPP to your DynamicLog pretty-printer:
--
-- > myLogHook =
-- > workspaceNamesPP xmobarPP >>= dynamicLogString >>= xmonadPropLog
--
-- We also provide a modification of "XMonad.Actions.SwapWorkspaces"\'s
-- functionality, which may be used this way:
--
-- > , ((modMask .|. shiftMask, xK_Left ), swapTo Prev)
-- > , ((modMask .|. shiftMask, xK_Right ), swapTo Next)
--
-- > [((modm .|. controlMask, k), swapWithCurrent i)
-- > | (i, k) <- zip workspaces [xK_1 ..]]
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
-- | Workspace names container.
newtype WorkspaceNames = WorkspaceNames (M.Map WorkspaceId String)
deriving (Typeable, Read, Show)
instance ExtensionClass WorkspaceNames where
initialValue = WorkspaceNames M.empty
extensionType = PersistentExtension
-- | Returns a function that maps workspace tag @\"t\"@ to @\"t:name\"@ for
-- workspaces with a name, and to @\"t\"@ otherwise.
getWorkspaceNames :: X (WorkspaceId -> String)
getWorkspaceNames = do
WorkspaceNames m <- XS.get
return $ \wks -> case M.lookup wks m of
Nothing -> wks
Just s -> wks ++ ":" ++ s
-- | Sets the name of a workspace. Empty string makes the workspace unnamed
-- again.
setWorkspaceName :: WorkspaceId -> String -> X ()
setWorkspaceName w name = do
WorkspaceNames m <- XS.get
XS.put $ WorkspaceNames $ if null name then M.delete w m else M.insert w name m
refresh
-- | Sets the name of the current workspace. See 'setWorkspaceName'.
setCurrentWorkspaceName :: String -> X ()
setCurrentWorkspaceName name = do
current <- gets (W.currentTag . windowset)
setWorkspaceName current name
-- | Prompt for a new name for the current workspace and set it.
renameWorkspace :: XPConfig -> X ()
renameWorkspace conf = do
mkXPrompt pr conf (const (return [])) setCurrentWorkspaceName
where pr = Wor "Workspace name: "
-- | Modify "XMonad.Hooks.DynamicLog"\'s pretty-printing format to show
-- workspace names as well.
workspaceNamesPP :: PP -> X PP
workspaceNamesPP pp = do
names <- getWorkspaceNames
return $
pp {
ppCurrent = ppCurrent pp . names,
ppVisible = ppVisible pp . names,
ppHidden = ppHidden pp . names,
ppHiddenNoWindows = ppHiddenNoWindows pp . names,
ppUrgent = ppUrgent pp . names
}
-- | See 'XMonad.Actions.SwapWorkspaces.swapTo'. This is the same with names.
swapTo :: Direction1D -> X ()
swapTo dir = swapTo' dir AnyWS
-- | Swap with the previous or next workspace of the given type.
swapTo' :: Direction1D -> WSType -> X ()
swapTo' dir which = findWorkspace getSortByIndex dir which 1 >>= swapWithCurrent
-- | See 'XMonad.Actions.SwapWorkspaces.swapWithCurrent'. This is almost the
-- same with names.
swapWithCurrent :: WorkspaceId -> X ()
swapWithCurrent t = do
current <- gets (W.currentTag . windowset)
swapNames t current
windows $ Swap.swapWorkspaces t current
-- | Swap names of the two workspaces.
swapNames :: WorkspaceId -> WorkspaceId -> X ()
swapNames w1 w2 = do
WorkspaceNames m <- XS.get
let getname w = fromMaybe "" $ M.lookup w m
set w name m' = if null name then M.delete w m' else M.insert w name m'
XS.put $ WorkspaceNames $ set w1 (getname w2) $ set w2 (getname w1) $ m

View File

@@ -1,4 +1,5 @@
{-# OPTIONS_GHC -fglasgow-exts -fno-warn-missing-signatures #-}
{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Config.Arossato

View File

@@ -38,7 +38,7 @@ import qualified Data.Map as M
-- > import qualified Data.Map as M
-- > main = xmonad someConfig { keys = \c -> azertyKeys c `M.union` keys someConfig c }
azertyConfig = defaultConfig { keys = \c -> azertyKeys c `M.union` keys defaultConfig c }
azertyConfig = defaultConfig { keys = azertyKeys <+> keys defaultConfig }
azertyKeys conf@(XConfig {modMask = modm}) = M.fromList $
[((modm, xK_semicolon), sendMessage (IncMasterN (-1)))]

217
XMonad/Config/Bluetile.hs Normal file
View File

@@ -0,0 +1,217 @@
{-# OPTIONS -fno-warn-missing-signatures #-}
----------------------------------------------------------------------------
-- |
-- Module : XMonad.Config.Bluetile
-- Copyright : (c) Jan Vornberger 2009
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : jan.vornberger@informatik.uni-oldenburg.de
-- Stability : unstable
-- Portability : not portable
--
-- This is the default configuration of Bluetile
-- (<http://projects.haskell.org/bluetile/>). If you
-- are migrating from Bluetile to xmonad or want to create
-- a similar setup, then this will give you pretty much
-- the same thing, except for Bluetile's helper applications
-- such as the dock.
--
-----------------------------------------------------------------------------
module XMonad.Config.Bluetile (
-- * Usage
-- $usage
bluetileConfig
) where
import XMonad hiding ( (|||) )
import XMonad.Layout.BorderResize
import XMonad.Layout.BoringWindows
import XMonad.Layout.ButtonDecoration
import XMonad.Layout.Decoration
import XMonad.Layout.DecorationAddons
import XMonad.Layout.DraggingVisualizer
import XMonad.Layout.LayoutCombinators
import XMonad.Layout.Maximize
import XMonad.Layout.Minimize
import XMonad.Layout.MouseResizableTile
import XMonad.Layout.Named
import XMonad.Layout.NoBorders
import XMonad.Layout.PositionStoreFloat
import XMonad.Layout.WindowSwitcherDecoration
import XMonad.Actions.BluetileCommands
import XMonad.Actions.CycleWS
import XMonad.Actions.WindowMenu
import XMonad.Hooks.CurrentWorkspaceOnTop
import XMonad.Hooks.EwmhDesktops
import XMonad.Hooks.ManageDocks
import XMonad.Hooks.ManageHelpers
import XMonad.Hooks.PositionStoreHooks
import XMonad.Hooks.Minimize
import XMonad.Hooks.ServerMode
import XMonad.Hooks.WorkspaceByPos
import XMonad.Config.Gnome
import qualified XMonad.StackSet as W
import qualified Data.Map as M
import System.Exit
import Data.Monoid
import Control.Monad(when)
-- $usage
-- To use this module, start with the following @~\/.xmonad\/xmonad.hs@:
--
-- > import XMonad
-- > import XMonad.Config.Bluetile
-- > import XMonad.Util.Replace
-- >
-- > main = replace >> xmonad bluetileConfig
--
-- The invocation of 'replace' will replace a currently running
-- window manager. This is the default behaviour of Bluetile as well.
-- See "XMonad.Util.Replace" for more information.
bluetileWorkspaces :: [String]
bluetileWorkspaces = ["1","2","3","4","5","6","7","8","9","0"]
bluetileKeys :: XConfig Layout -> M.Map (KeyMask, KeySym) (X ())
bluetileKeys conf@(XConfig {XMonad.modMask = modMask'}) = M.fromList $
-- launching and killing programs
[ ((modMask' , xK_Return), spawn $ XMonad.terminal conf) -- %! Launch terminal
, ((modMask', xK_p ), gnomeRun) -- %! Launch Gnome "Run application" dialog
, ((modMask' .|. shiftMask, xK_c ), kill) -- %! Close the focused window
, ((modMask', xK_F5 ), refresh) -- %! Resize viewed windows to the correct size
, ((modMask' .|. shiftMask, xK_F5 ), setLayout $ XMonad.layoutHook conf) -- %! Reset the layouts on the current workspace to default
, ((modMask', xK_o ), windowMenu)
-- move focus up or down the window stack
, ((modMask', xK_Tab ), focusDown) -- %! Move focus to the next window
, ((modMask' .|. shiftMask, xK_Tab ), focusUp) -- %! Move focus to the previous window
, ((modMask', xK_j ), focusDown) -- %! Move focus to the next window
, ((modMask', xK_k ), focusUp) -- %! Move focus to the previous window
, ((modMask', xK_space ), focusMaster) -- %! Move focus to the master window
-- modifying the window order
, ((modMask' .|. shiftMask, xK_space ), windows W.swapMaster) -- %! Swap the focused window and the master window
, ((modMask' .|. shiftMask, xK_j ), windows W.swapDown ) -- %! Swap the focused window with the next window
, ((modMask' .|. shiftMask, xK_k ), windows W.swapUp ) -- %! Swap the focused window with the previous window
-- resizing the master/slave ratio
, ((modMask', xK_h ), sendMessage Shrink) -- %! Shrink the master area
, ((modMask', xK_l ), sendMessage Expand) -- %! Expand the master area
, ((modMask', xK_u ), sendMessage ShrinkSlave) -- %! Shrink a slave area
, ((modMask', xK_i ), sendMessage ExpandSlave) -- %! Expand a slave area
-- floating layer support
, ((modMask', xK_t ), withFocused $ windows . W.sink) -- %! Push window back into tiling
, ((modMask' .|. shiftMask, xK_t ), withFocused $ float ) -- %! Float window
-- increase or decrease number of windows in the master area
, ((modMask' , xK_comma ), sendMessage (IncMasterN 1)) -- %! Increment the number of windows in the master area
, ((modMask' , xK_period), sendMessage (IncMasterN (-1))) -- %! Deincrement the number of windows in the master area
-- quit, or restart
, ((modMask' .|. shiftMask, xK_q ), io (exitWith ExitSuccess)) -- %! Quit
, ((modMask' , xK_q ), restart "xmonad" True) -- %! Restart
-- Metacity-like workspace switching
, ((mod1Mask .|. controlMask, xK_Left), prevWS)
, ((mod1Mask .|. controlMask, xK_Right), nextWS)
, ((mod1Mask .|. controlMask .|. shiftMask, xK_Left), shiftToPrev >> prevWS)
, ((mod1Mask .|. controlMask .|. shiftMask, xK_Right), shiftToNext >> nextWS)
-- more Metacity keys
, ((mod1Mask , xK_F2), gnomeRun)
, ((mod1Mask , xK_F4), kill)
-- Switching to layouts
, ((modMask' , xK_a), sendMessage $ JumpToLayout "Floating")
, ((modMask' , xK_s), sendMessage $ JumpToLayout "Tiled1")
, ((modMask' , xK_d), sendMessage $ JumpToLayout "Tiled2")
, ((modMask' , xK_f), sendMessage $ JumpToLayout "Fullscreen")
-- Maximizing
, ((modMask' , xK_z), withFocused (sendMessage . maximizeRestore))
-- Minimizing
, ((modMask', xK_m ), withFocused minimizeWindow)
, ((modMask' .|. shiftMask, xK_m ), sendMessage RestoreNextMinimizedWin)
]
++
-- mod-[1..9] ++ [0] %! Switch to workspace N
-- mod-shift-[1..9] ++ [0] %! Move client to workspace N
[((m .|. modMask', k), windows $ f i)
| (i, k) <- zip (XMonad.workspaces conf) ([xK_1 .. xK_9] ++ [xK_0])
, (f, m) <- [(W.greedyView, 0), (W.shift, shiftMask)]]
++
-- mod-{w,e,r} %! Switch to physical/Xinerama screens 1, 2, or 3
-- mod-shift-{w,e,r} %! Move client to screen 1, 2, or 3
[((m .|. modMask', key), screenWorkspace sc >>= flip whenJust (windows . f))
| (key, sc) <- zip [xK_w, xK_e, xK_r] [0..]
, (f, m) <- [(W.view, 0), (W.shift, shiftMask)]]
bluetileMouseBindings :: XConfig Layout -> M.Map (KeyMask, Button) (Window -> X ())
bluetileMouseBindings (XConfig {XMonad.modMask = modMask'}) = M.fromList $
-- mod-button1 %! Move a floated window by dragging
[ ((modMask', button1), (\w -> isFloating w >>= \isF -> when (isF) $
focus w >> mouseMoveWindow w >> windows W.shiftMaster))
-- mod-button2 %! Switch to next and first layout
, ((modMask', button2), (\_ -> sendMessage NextLayout))
, ((modMask' .|. shiftMask, button2), (\_ -> sendMessage $ JumpToLayout "Floating"))
-- mod-button3 %! Resize a floated window by dragging
, ((modMask', button3), (\w -> isFloating w >>= \isF -> when (isF) $
focus w >> mouseResizeWindow w >> windows W.shiftMaster))
]
isFloating :: Window -> X (Bool)
isFloating w = do
ws <- gets windowset
return $ M.member w (W.floating ws)
bluetileManageHook :: ManageHook
bluetileManageHook = composeAll
[ workspaceByPos, positionStoreManageHook (Just defaultThemeWithButtons)
, className =? "MPlayer" --> doFloat
, isFullscreen --> doFullFloat
, manageDocks]
bluetileLayoutHook = avoidStruts $ minimize $ boringWindows $ (
named "Floating" floating |||
named "Tiled1" tiled1 |||
named "Tiled2" tiled2 |||
named "Fullscreen" fullscreen
)
where
floating = floatingDeco $ maximize $ borderResize $ positionStoreFloat
tiled1 = tilingDeco $ maximize $ mouseResizableTileMirrored
tiled2 = tilingDeco $ maximize $ mouseResizableTile
fullscreen = tilingDeco $ maximize $ smartBorders Full
tilingDeco l = windowSwitcherDecorationWithButtons shrinkText defaultThemeWithButtons (draggingVisualizer l)
floatingDeco l = buttonDeco shrinkText defaultThemeWithButtons l
bluetileConfig =
defaultConfig
{ modMask = mod4Mask, -- logo key
manageHook = bluetileManageHook,
layoutHook = bluetileLayoutHook,
logHook = currentWorkspaceOnTop >> ewmhDesktopsLogHook,
handleEventHook = ewmhDesktopsEventHook
`mappend` fullscreenEventHook
`mappend` minimizeEventHook
`mappend` serverModeEventHook' bluetileCommands
`mappend` positionStoreEventHook,
workspaces = bluetileWorkspaces,
keys = bluetileKeys,
mouseBindings = bluetileMouseBindings,
focusFollowsMouse = False,
focusedBorderColor = "#000000",
terminal = "gnome-terminal"
}

View File

@@ -54,7 +54,6 @@ module XMonad.Config.Desktop (
) where
import XMonad
import XMonad.Config (defaultConfig)
import XMonad.Hooks.ManageDocks
import XMonad.Hooks.EwmhDesktops
import XMonad.Util.Cursor
@@ -89,7 +88,7 @@ import qualified Data.Map as M
-- $customizing
-- To customize a desktop config, modify its fields as is illustrated with
-- @defaultConfig@ in the \"Extending xmonad\" section of "XMonad.Doc.Extending".
-- @defaultConfig@ in "XMonad.Doc.Extending#Extending xmonad".
-- $layouts
-- See also "XMonad.Util.EZConfig" for more options for modifying key bindings.
@@ -127,7 +126,7 @@ import qualified Data.Map as M
-- To add to the logHook while still sending workspace and window information
-- to DE apps use something like:
--
-- > , logHook = myLogHook >> logHook desktopConfig
-- > , logHook = myLogHook <+> logHook desktopConfig
--
-- Or for more elaborate logHooks you can use @do@:
--
@@ -139,25 +138,23 @@ import qualified Data.Map as M
-- $eventHook
-- To customize xmonad's event handling while still having it respond
-- to EWMH events from pagers, task bars, etc. add to your imports:
-- to EWMH events from pagers, task bars:
--
-- > import Data.Monoid
-- > , handleEventHook = myEventHooks <+> handleEventHook desktopConfig
--
-- 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@)
-- or 'mconcat' if you write a list event of event hooks
--
-- > , handleEventHook = mconcat
-- > [ myMouseHandler
-- > , myMessageHandler
-- > , handleEventHook desktopConfig ]
--
-- Note that the event hooks are run left to right (in contrast to
-- 'ManageHook'S which are right to left)
-- $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
-- time xmonad starts or restarts, use '<+>' to combine actions as in the
-- logHook example, or something like:
--
-- > , startupHook = do
@@ -170,7 +167,7 @@ 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 }
, keys = desktopKeys <+> keys defaultConfig }
desktopKeys (XConfig {modMask = modm}) = M.fromList $
[ ((modm, xK_b), sendMessage ToggleStruts) ]

View File

@@ -1,4 +1,5 @@
{-# OPTIONS_GHC -fno-warn-missing-signatures -fglasgow-exts -fno-warn-orphans #-}
{-# LANGUAGE PatternGuards #-}
{-# OPTIONS_GHC -fno-warn-missing-signatures -fno-warn-orphans #-}
-----------------------------------------------------------------------------
-- |
-- Copyright : (c) Spencer Janssen 2007
@@ -10,7 +11,6 @@ module XMonad.Config.Droundy ( config, mytab ) where
import XMonad hiding (keys, config, (|||))
import qualified XMonad (keys)
import XMonad.Config ( defaultConfig )
import qualified XMonad.StackSet as W
import qualified Data.Map as M

View File

@@ -41,7 +41,7 @@ import System.Environment (getEnvironment)
gnomeConfig = desktopConfig
{ terminal = "gnome-terminal"
, keys = \c -> gnomeKeys c `M.union` keys desktopConfig c
, keys = gnomeKeys <+> keys desktopConfig
, startupHook = gnomeRegister >> startupHook desktopConfig }
gnomeKeys (XConfig {modMask = modm}) = M.fromList $

View File

@@ -40,11 +40,11 @@ import qualified Data.Map as M
kdeConfig = desktopConfig
{ terminal = "konsole"
, keys = \c -> kdeKeys c `M.union` keys desktopConfig c }
, keys = kdeKeys <+> keys desktopConfig }
kde4Config = desktopConfig
{ terminal = "konsole"
, keys = \c -> kde4Keys c `M.union` keys desktopConfig c }
, keys = kde4Keys <+> keys desktopConfig }
kdeKeys (XConfig {modMask = modm}) = M.fromList $
[ ((modm, xK_p), spawn "dcop kdesktop default popupExecuteCommand")

View File

@@ -1,60 +1,64 @@
{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
module XMonad.Config.Sjanssen (sjanssenConfig, sjanssenConfigXmobar) where
module XMonad.Config.Sjanssen (sjanssenConfig) where
import XMonad hiding (Tall(..))
import qualified XMonad.StackSet as W
import XMonad.Actions.CopyWindow
import XMonad.Layout.Tabbed
import XMonad.Layout.HintedTile
import XMonad.Config (defaultConfig)
import XMonad.Layout.NoBorders
import XMonad.Hooks.DynamicLog hiding (xmobar)
import XMonad.Hooks.DynamicLog
import XMonad.Hooks.ManageDocks
import XMonad.Hooks.ManageHelpers (isFullscreen, doFullFloat)
import XMonad.Hooks.EwmhDesktops
import XMonad.Prompt
import XMonad.Actions.SpawnOn
import XMonad.Util.SpawnOnce
import XMonad.Layout.LayoutScreens
import XMonad.Layout.TwoPane
import qualified Data.Map as M
sjanssenConfigXmobar = statusBar "exec xmobar" sjanssenPP strutkey =<< sjanssenConfig
where
strutkey (XConfig {modMask = modm}) = (modm, xK_b)
sjanssenConfig = do
sp <- mkSpawner
return . ewmh $ defaultConfig
sjanssenConfig =
ewmh $ defaultConfig
{ terminal = "exec urxvt"
, workspaces = ["irc", "web"] ++ map show [3 .. 9 :: Int]
, mouseBindings = \(XConfig {modMask = modm}) -> M.fromList $
[ ((modm, button1), (\w -> focus w >> mouseMoveWindow w))
, ((modm, button2), (\w -> focus w >> windows W.swapMaster))
, ((modm.|. shiftMask, button1), (\w -> focus w >> mouseResizeWindow w)) ]
, keys = \c -> mykeys sp c `M.union` keys defaultConfig c
, keys = \c -> mykeys c `M.union` keys defaultConfig c
, logHook = dynamicLogString sjanssenPP >>= xmonadPropLog
, layoutHook = modifiers layouts
, manageHook = composeAll [className =? x --> doShift w
| (x, w) <- [ ("Firefox", "web")
, ("Ktorrent", "7")
, ("Amarokapp", "7")]]
<+> manageHook defaultConfig <+> manageDocks <+> manageSpawn sp
<+> manageHook defaultConfig <+> manageDocks <+> manageSpawn
<+> (isFullscreen --> doFullFloat)
, startupHook = mapM_ spawnOnce spawns
}
where
tiled = HintedTile 1 0.03 0.5 TopLeft
layouts = (tiled Tall ||| (tiled Wide ||| Full)) ||| tabbed shrinkText myTheme
modifiers = smartBorders
modifiers = avoidStruts . smartBorders
mykeys sp (XConfig {modMask = modm}) = M.fromList $
[((modm, xK_p ), shellPromptHere sp myPromptConfig)
,((modm .|. shiftMask, xK_Return), spawnHere sp =<< asks (terminal . config))
spawns = [ "xmobar"
, "xset -b", "xset s off", "xset dpms 0 600 1200"
, "nitrogen --set-tiled wallpaper/wallpaper.jpg"
, "trayer --transparent true --expand true --align right "
++ "--edge bottom --widthtype request" ]
mykeys (XConfig {modMask = modm}) = M.fromList $
[((modm, xK_p ), shellPromptHere myPromptConfig)
,((modm .|. shiftMask, xK_Return), spawnHere =<< asks (terminal . config))
,((modm .|. shiftMask, xK_c ), kill1)
,((modm .|. shiftMask .|. controlMask, xK_c ), kill)
,((modm .|. shiftMask, xK_0 ), windows $ copyToAll)
,((modm, xK_z ), layoutScreens 2 $ TwoPane 0.5 0.5)
,((modm .|. shiftMask, xK_z ), rescreen)
, ((modm , xK_b ), sendMessage ToggleStruts)
]
myFont = "xft:Bitstream Vera Sans Mono:pixelsize=10"

View File

@@ -36,7 +36,7 @@ import qualified Data.Map as M
xfceConfig = desktopConfig
{ terminal = "Terminal"
, keys = \c -> xfceKeys c `M.union` keys desktopConfig c }
, keys = xfceKeys <+> keys desktopConfig }
xfceKeys (XConfig {modMask = modm}) = M.fromList $
[ ((modm, xK_p), spawn "xfrun4")

View File

@@ -256,6 +256,9 @@ xmonad contributed extensions.
* Code should be compilable with "ghc-options: -Wall -Werror" set in the
xmonad-contrib.cabal file. There should be no warnings.
* Code should be free of any warnings or errors from the Hlint tool; use your
best judgement on some warnings like eta-reduction or bracket removal, though.
* Partial functions should be avoided: the window manager should not
crash, so never call 'error' or 'undefined'.

View File

@@ -175,7 +175,7 @@ edit your key bindings.
* "XMonad.Actions.FloatKeys":
Move and resize floating windows.
* "XMonad.Layout.FloatSnap":
* "XMonad.Actions.FloatSnap":
Move and resize floating windows using other windows and the edge of the
screen as guidelines.
@@ -257,7 +257,7 @@ edit your key bindings.
* "XMonad.Actions.UpdateFocus":
Updates the focus on mouse move in unfocused windows.
* "XMonadContrib.UpdatePointer":
* "XMonad.Actions.UpdatePointer":
Causes the pointer to follow whichever window focus changes to.
* "XMonad.Actions.Warp":
@@ -382,13 +382,17 @@ Here is a list of the modules found in @XMonad.Hooks@:
* "XMonad.Hooks.ManageHelpers": provide helper functions to be used
in @manageHook@.
* "XMonad.Hooks.Minimize":
Handles window manager hints to minimize and restore windows. Use
this with XMonad.Layout.Minimize.
* "XMonad.Hooks.Place":
Automatic placement of floating windows.
* "XMonad.Hooks.RestoreMinimized":
Lets you restore minimized windows (see "XMonad.Layout.Minimize")
by selecting them on a taskbar (listens for _NET_ACTIVE_WINDOW
and WM_CHANGE_STATE).
(Deprecated: Use XMonad.Hooks.Minimize) Lets you restore minimized
windows (see "XMonad.Layout.Minimize") by selecting them on a
taskbar (listens for _NET_ACTIVE_WINDOW and WM_CHANGE_STATE).
* "XMonad.Hooks.Script":
Provides a simple interface for running a ~\/.xmonad\/hooks script with the
@@ -932,16 +936,18 @@ example, you could write:
and provide an appropriate definition of @myKeys@, such as:
> myKeys conf@(XConfig {XMonad.modMask = modm}) =
> myKeys conf@(XConfig {XMonad.modMask = modm}) = M.fromList
> [ ((modm, xK_F12), xmonadPrompt defaultXPConfig)
> , ((modm, xK_F3 ), shellPrompt defaultXPConfig)
> ]
This particular definition also requires importing "XMonad.Prompt",
"XMonad.Prompt.Shell", and "XMonad.Prompt.XMonad":
"XMonad.Prompt.Shell", "XMonad.Prompt.XMonad", and "Data.Map":
> import XMonadPrompt
> import ... -- and so on
> import qualified Data.Map as M
> import XMonad.Prompt
> import XMonad.Prompt.Shell
> import XMonad.Prompt.XMonad
For a list of the names of particular keys (such as xK_F12, and so
on), see
@@ -977,7 +983,7 @@ module, before starting we must first import this modules:
For instance, if you have defined some additional key bindings like
these:
> myKeys conf@(XConfig {XMonad.modMask = modm}) =
> myKeys conf@(XConfig {XMonad.modMask = modm}) = M.fromList
> [ ((modm, xK_F12), xmonadPrompt defaultXPConfig)
> , ((modm, xK_F3 ), shellPrompt defaultXPConfig)
> ]
@@ -985,13 +991,19 @@ these:
then you can create a new key bindings map by joining the default one
with yours:
> newKeys x = M.union (keys defaultConfig x) (M.fromList (myKeys x))
> newKeys x = myKeys x `M.union` keys defaultConfig x
Finally, you can use @newKeys@ in the 'XMonad.Core.XConfig.keys' field
of the configuration:
> main = xmonad $ defaultConfig { keys = newKeys }
Alternatively, the '<+>' operator can be used which in this usage does exactly
the same as the explicit usage of 'M.union' and propagation of the config
argument, thanks to appropriate instances in "Data.Monoid".
> main = xmonad $ defaultConfig { keys = myKeys <+> keys defaultConfig }
All together, your @~\/.xmonad\/xmonad.hs@ would now look like this:
@@ -1006,11 +1018,9 @@ All together, your @~\/.xmonad\/xmonad.hs@ would now look like this:
> import XMonad.Prompt.XMonad
>
> main :: IO ()
> main = xmonad $ defaultConfig { keys = newKeys }
> main = xmonad $ defaultConfig { keys = myKeys <+> keys defaultConfig }
>
> newKeys x = M.union (keys defaultConfig x) (M.fromList (myKeys x))
>
> myKeys conf@(XConfig {XMonad.modMask = modm}) =
> myKeys conf@(XConfig {XMonad.modMask = modm}) = M.fromList
> [ ((modm, xK_F12), xmonadPrompt defaultXPConfig)
> , ((modm, xK_F3 ), shellPrompt defaultXPConfig)
> ]
@@ -1034,10 +1044,10 @@ For example, suppose you want to get rid of @mod-q@ and @mod-shift-q@
to define @newKeys@ as a 'Data.Map.difference' between the default
map and the map of the key bindings you want to remove. Like so:
> newKeys x = M.difference (keys defaultConfig x) (M.fromList $ keysToRemove x)
> newKeys x = keys defaultConfig x `M.difference` keysToRemove x
>
> keysToRemove :: XConfig Layout -> [((KeyMask, KeySym),X ())]
> keysToRemove x =
> keysToRemove :: XConfig Layout -> M.Map (KeyMask, KeySym) (X ())
> keysToRemove x = M.fromList
> [ ((modm , xK_q ), return ())
> , ((modm .|. shiftMask, xK_q ), return ())
> ]
@@ -1164,7 +1174,7 @@ Suppose we want a list with the 'XMonad.Layout.Full',
Then we create the combination of layouts we need:
> mylayoutHook = Full ||| tabbed shrinkText defaultTConf ||| Accordion
> mylayoutHook = Full ||| tabbed shrinkText defaultTheme ||| Accordion
Now, all we need to do is change the 'XMonad.Core.layoutHook'
@@ -1178,11 +1188,11 @@ example, suppose we want to use the
'XMonad.Layout.NoBorders.noBorders' layout modifier, from the
"XMonad.Layout.NoBorders" module (which must be imported):
> mylayoutHook = noBorders (Full ||| tabbed shrinkText defaultTConf ||| Accordion)
> mylayoutHook = noBorders (Full ||| tabbed shrinkText defaultTheme ||| Accordion)
If we want only the tabbed layout without borders, then we may write:
> mylayoutHook = Full ||| noBorders (tabbed shrinkText defaultTConf) ||| Accordion
> mylayoutHook = Full ||| noBorders (tabbed shrinkText defaultTheme) ||| Accordion
Our @~\/.xmonad\/xmonad.hs@ will now look like this:
@@ -1192,7 +1202,7 @@ Our @~\/.xmonad\/xmonad.hs@ will now look like this:
> import XMonad.Layout.Accordion
> import XMonad.Layout.NoBorders
>
> mylayoutHook = Full ||| noBorders (tabbed shrinkText defaultTConf) ||| Accordion
> mylayoutHook = Full ||| noBorders (tabbed shrinkText defaultTheme) ||| Accordion
>
> main = xmonad $ defaultConfig { layoutHook = mylayoutHook }

View File

@@ -0,0 +1,69 @@
{-# LANGUAGE DeriveDataTypeable #-}
----------------------------------------------------------------------------
-- |
-- Module : XMonad.Hooks.CurrentWorkspaceOnTop
-- Copyright : (c) Jan Vornberger 2009
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : jan.vornberger@informatik.uni-oldenburg.de
-- Stability : unstable
-- Portability : not portable
--
-- Ensures that the windows of the current workspace are always in front
-- of windows that are located on other visible screens. This becomes important
-- if you use decoration and drag windows from one screen to another. Using this
-- module, the dragged window will always be in front of other windows.
--
-----------------------------------------------------------------------------
module XMonad.Hooks.CurrentWorkspaceOnTop (
-- * Usage
-- $usage
currentWorkspaceOnTop
) where
import XMonad
import qualified XMonad.StackSet as S
import qualified XMonad.Util.ExtensibleState as XS
import Control.Monad(when)
import qualified Data.Map as M
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
--
-- > import XMonad.Hooks.CurrentWorkspaceOnTop
-- >
-- > main = xmonad $ defaultConfig {
-- > ...
-- > logHook = currentWorkspaceOnTop
-- > ...
-- > }
--
data CWOTState = CWOTS String deriving Typeable
instance ExtensionClass CWOTState where
initialValue = CWOTS ""
currentWorkspaceOnTop :: X ()
currentWorkspaceOnTop = withDisplay $ \d -> do
ws <- gets windowset
(CWOTS lastTag) <- XS.get
let curTag = S.tag . S.workspace . S.current $ ws
when (curTag /= lastTag) $ do
-- the following is more or less a reimplementation of what's happening in "XMonad.Operation"
let s = S.current ws
wsp = S.workspace s
viewrect = screenRect $ S.screenDetail s
tmpStack = (S.stack wsp) >>= S.filter (`M.notMember` S.floating ws)
(rs, ml') <- runLayout wsp { S.stack = tmpStack } viewrect
updateLayout curTag ml'
let this = S.view curTag ws
fltWins = filter (flip M.member (S.floating ws)) $ S.index this
wins = fltWins ++ (map fst rs) -- order: first all floating windows, then the order the layout returned
-- end of reimplementation
when (not . null $ wins) $ do
io $ raiseWindow d (head wins) -- raise first window of current workspace to the very top,
io $ restackWindows d wins -- then use restackWindows to let all other windows from the workspace follow
XS.put(CWOTS curTag)

1254
XMonad/Hooks/DebugEvents.hs Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,107 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Hooks.DebugKeyEvents
-- Copyright : (c) 2011 Brandon S Allbery <allbery.b@gmail.com>
-- License : BSD
--
-- Maintainer : Brandon S Allbery <allbery.b@gmail.com>
-- Stability : unstable
-- Portability : unportable
--
-- A debugging module to track key events, useful when you can't tell whether
-- xmonad is processing some or all key events.
-----------------------------------------------------------------------------
module XMonad.Hooks.DebugKeyEvents (-- * Usage
-- $usage
debugKeyEvents
) where
import XMonad.Core
import XMonad.Operations (cleanMask)
import Graphics.X11.Xlib
import Graphics.X11.Xlib.Extras
import Control.Monad.State (gets)
import Data.Bits
import Data.List (intercalate)
import Data.Monoid
import Numeric (showHex)
import System.IO (hPutStrLn
,stderr)
-- $usage
-- Add this to your handleEventHook to print received key events to the
-- log (the console if you use @startx@/@xinit@, otherwise usually
-- @~/.xsession-errors@).
--
-- > , handleEventHook = debugKeyEvents
--
-- If you already have a handleEventHook then you should append it:
--
-- > , handleEventHook = ... <+> debugKeyEvents
--
-- Logged key events look like:
--
-- @keycode 53 sym 120 (0x78, "x") mask 0x0 () clean 0x0 ()@
--
-- The @mask@ and @clean@ indicate the modifiers pressed along with
-- the key; @mask@ is raw, and @clean@ is what @xmonad@ sees after
-- sanitizing it (removing @numberLockMask@, etc.)
--
-- For more detailed instructions on editing the logHook see:
--
-- "XMonad.Doc.Extending#The_log_hook_and_external_status_bars"
-- | Print key events to stderr for debugging
debugKeyEvents :: Event -> X All
debugKeyEvents (KeyEvent {ev_event_type = t, ev_state = m, ev_keycode = code})
| t == keyPress =
withDisplay $ \dpy -> do
sym <- io $ keycodeToKeysym dpy code 0
msk <- cleanMask m
nl <- gets numberlockMask
io $ hPutStrLn stderr $ intercalate " " ["keycode"
,show code
,"sym"
,show sym
," ("
,hex sym
," \""
,keysymToString sym
,"\") mask"
,hex m
,"(" ++ vmask nl m ++ ")"
,"clean"
,hex msk
,"(" ++ vmask nl msk ++ ")"
]
return (All True)
debugKeyEvents _ = return (All True)
-- | Convenient showHex variant
hex :: (Integral n, Show n) => n -> String
hex v = "0x" ++ showHex v ""
-- | Convert a modifier mask into a useful string
vmask :: KeyMask -> KeyMask -> String
vmask numLockMask msk = intercalate " " $
reverse $
fst $
foldr vmask' ([],msk) masks
where
masks = map (\m -> (m,show m)) [0..toEnum (bitSize msk - 1)] ++
[(numLockMask,"num" )
,( lockMask,"lock" )
,(controlMask,"ctrl" )
,( shiftMask,"shift")
,( mod5Mask,"mod5" )
,( mod4Mask,"mod4" )
,( mod3Mask,"mod3" )
,( mod2Mask,"mod2" )
,( mod1Mask,"mod1" )
]
vmask' _ a@( _,0) = a
vmask' (m,s) (ss,v) | v .&. m == m = (s:ss,v .&. complement m)
vmask' _ r = r

View File

@@ -0,0 +1,93 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Hooks.DebugStack
-- Copyright : (c) Brandon S Allbery KF8NH, 2012
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : allbery.b@gmail.com
-- Stability : unstable
-- Portability : not portable
--
-- Dump the state of the 'StackSet'. A @logHook@ and @handleEventHook@ are
-- also provided.
--
-----------------------------------------------------------------------------
module XMonad.Hooks.DebugStack (debugStack
,debugStackString
,debugStackLogHook
,debugStackEventHook
) where
import XMonad.Core
import qualified XMonad.StackSet as W
import XMonad.Util.DebugWindow
import Graphics.X11.Types (Window)
import Graphics.X11.Xlib.Extras (Event)
import Control.Monad (foldM)
import Data.Map (toList)
import Data.Monoid (All(..))
-- | Print the state of the current window stack to @stderr@, which for most
-- installations goes to @~/.xsession-errors@. "XMonad.Util.DebugWindow"
-- is used to display the individual windows.
debugStack :: X ()
debugStack = debugStackString >>= trace
-- | The above packaged as a 'logHook'. (Currently this is identical.)
debugStackLogHook :: X ()
debugStackLogHook = debugStack
-- | The above packaged as a 'handleEventHook'. You almost certainly do not
-- want to use this unconditionally, as it will cause massive amounts of
-- output and possibly slow @xmonad@ down severely.
debugStackEventHook :: Event -> X All
debugStackEventHook _ = debugStack >> return (All True)
-- | Dump the state of the current 'StackSet' as a multiline 'String'.
-- @
-- stack [ mm
-- ,(*) ww
-- , ww
-- ]
-- float { ww
-- , ww
-- }
-- @
--
-- One thing I'm not sure of is where the zipper is when focus is on a
-- floating window.
debugStackString :: X String
debugStackString = withWindowSet $ \ws -> do
s <- emit "stack" ("[","]") (W.peek ws) $ W.index ws
f <- emit "float" ("{","}") (W.peek ws) $ map fst $ toList $ W.floating ws
return $ s ++ f
where
emit :: String -> (String,String) -> Maybe Window -> [Window] -> X String
emit title (lb,rb) _ [] = return $ title ++ " " ++ lb ++ rb ++ "]\n"
emit title (lb,rb) focused ws = do
(_,_,_,_,ss) <- foldM emit' (title,lb,rb,focused,"") ws
return $ ss ++
replicate (length title + 1) ' ' ++
rb ++
"\n"
emit' :: (String,String,String,Maybe Window,String)
-> Window
-> X (String,String,String,Maybe Window,String)
emit' (t,l,r,f,a) w = do
w' <- emit'' f w
return (replicate (length t) ' '
,',' : replicate (length l - 1) ' '
,r
,f
,a ++ t ++ " " ++ l ++ w' ++ "\n"
)
emit'' :: Maybe Window -> Window -> X String
emit'' focus win =
let fi f = if win == f then "(*) " else " "
in (maybe " " fi focus ++) `fmap` debugWindow win

136
XMonad/Hooks/DynamicBars.hs Normal file
View File

@@ -0,0 +1,136 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Hooks.DynamicBars
-- Copyright : (c) Ben Boeckel 2012
-- License : BSD-style (as xmonad)
--
-- Maintainer : mathstuf@gmail.com
-- Stability : unstable
-- Portability : unportable
--
-- Manage per-screen status bars.
--
-----------------------------------------------------------------------------
module XMonad.Hooks.DynamicBars (
-- * Usage
-- $usage
DynamicStatusBar
, DynamicStatusBarCleanup
, dynStatusBarStartup
, dynStatusBarEventHook
, multiPP
) where
import Prelude
import Control.Concurrent.MVar
import Control.Monad
import Control.Monad.Trans (lift)
import Control.Monad.Writer (WriterT, execWriterT, tell)
import Data.Maybe
import Data.Monoid
import Data.Traversable (traverse)
import Graphics.X11.Xinerama
import Graphics.X11.Xlib
import Graphics.X11.Xlib.Extras
import Graphics.X11.Xrandr
import System.IO
import System.IO.Unsafe
import XMonad
import qualified XMonad.StackSet as W
import XMonad.Hooks.DynamicLog
-- $usage
-- Provides a few helper functions to manage per-screen status bars while
-- dynamically responding to screen changes. A startup action, event hook, and
-- a way to separate PP styles based on the screen's focus are provided:
--
-- * The 'dynStatusBarStartup' hook which initializes the status bars.
--
-- * The 'dynStatusBarEventHook' hook which respawns status bars when the
-- number of screens changes.
--
-- * The 'multiPP' function which allows for different output based on whether
-- the screen for the status bar has focus.
--
-- The hooks take a 'DynamicStatusBar' function which is given the id of the
-- screen to start up and returns the 'Handle' to the pipe to write to. The
-- 'DynamicStatusBarCleanup' argument should tear down previous instances. It
-- is called when the number of screens changes and on startup.
--
data DynStatusBarInfo = DynStatusBarInfo
{ dsbInfoScreens :: [ScreenId]
, dsbInfoHandles :: [Handle]
}
type DynamicStatusBar = ScreenId -> IO Handle
type DynamicStatusBarCleanup = IO ()
-- Global state
statusBarInfo :: MVar DynStatusBarInfo
statusBarInfo = unsafePerformIO $ newMVar (DynStatusBarInfo [] [])
dynStatusBarStartup :: DynamicStatusBar -> DynamicStatusBarCleanup -> X ()
dynStatusBarStartup sb cleanup = liftIO $ do
dpy <- openDisplay ""
xrrSelectInput dpy (defaultRootWindow dpy) rrScreenChangeNotifyMask
closeDisplay dpy
updateStatusBars sb cleanup
dynStatusBarEventHook :: DynamicStatusBar -> DynamicStatusBarCleanup -> Event -> X All
dynStatusBarEventHook sb cleanup (RRScreenChangeNotifyEvent {}) = liftIO (updateStatusBars sb cleanup) >> return (All True)
dynStatusBarEventHook _ _ _ = return (All True)
updateStatusBars :: DynamicStatusBar -> DynamicStatusBarCleanup -> IO ()
updateStatusBars sb cleanup = liftIO $ do
dsbInfo <- takeMVar statusBarInfo
screens <- getScreens
if (screens /= (dsbInfoScreens dsbInfo))
then do
mapM hClose (dsbInfoHandles dsbInfo)
cleanup
newHandles <- mapM sb screens
putMVar statusBarInfo (DynStatusBarInfo screens newHandles)
else putMVar statusBarInfo dsbInfo
-----------------------------------------------------------------------------
-- The following code is from adamvo's xmonad.hs file.
-- http://www.haskell.org/haskellwiki/Xmonad/Config_archive/adamvo%27s_xmonad.hs
multiPP :: PP -- ^ The PP to use if the screen is focused
-> PP -- ^ The PP to use otherwise
-> X ()
multiPP focusPP unfocusPP = do
dsbInfo <- liftIO $ readMVar statusBarInfo
multiPP' dynamicLogString focusPP unfocusPP (dsbInfoHandles dsbInfo)
multiPP' :: (PP -> X String) -> PP -> PP -> [Handle] -> X ()
multiPP' dynlStr focusPP unfocusPP handles = do
st <- get
let pickPP :: WorkspaceId -> WriterT (Last XState) X String
pickPP ws = do
let isFoc = (ws ==) . W.tag . W.workspace . W.current $ windowset st
put st{ windowset = W.view ws $ windowset st }
out <- lift $ dynlStr $ if isFoc then focusPP else unfocusPP
when isFoc $ get >>= tell . Last . Just
return out
traverse put . getLast
=<< execWriterT . (io . zipWithM_ hPutStrLn handles <=< mapM pickPP) . catMaybes
=<< mapM screenWorkspace (zipWith const [0 .. ] handles)
return ()
getScreens :: IO [ScreenId]
getScreens = do
screens <- do
dpy <- openDisplay ""
rects <- getScreenInfo dpy
closeDisplay dpy
return rects
let ids = zip [0 .. ] screens
return $ map fst ids

View File

@@ -1,3 +1,4 @@
{-# LANGUAGE DeriveDataTypeable #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Hooks.DynamicHooks
@@ -15,20 +16,18 @@
module XMonad.Hooks.DynamicHooks (
-- * Usage
-- $usage
initDynamicHooks
,dynamicMasterHook
dynamicMasterHook
,addDynamicHook
,updateDynamicHook
,oneShotHook
) where
import XMonad
import System.IO
import qualified XMonad.Util.ExtensibleState as XS
import Data.List
import Data.Maybe (listToMaybe)
import Data.Monoid
import Data.IORef
-- $usage
-- Provides two new kinds of 'ManageHooks' that can be defined at runtime.
@@ -40,68 +39,46 @@ import Data.IORef
-- Note that you will lose all dynamically defined 'ManageHook's when you @mod+q@!
-- If you want them to last, you should create them as normal in your @xmonad.hs@.
--
-- First, you must execute 'initDynamicHooks' from 'main' in your @xmonad.hs@:
-- To use this module, add 'dynamicMasterHook' to your 'manageHook':
--
-- > dynHooksRef <- initDynamicHooks
-- > xmonad { manageHook = myManageHook <+> dynamicMasterHook }
--
-- and then pass this value to the other functions in this module.
-- You can then use the supplied functions in your keybindings:
--
-- You also need to add the base 'ManageHook':
--
-- > xmonad { manageHook = myManageHook <+> dynamicMasterHook dynHooksRef }
--
-- You must include this @dynHooksRef@ value when using the functions in this
-- module:
--
-- > xmonad { keys = myKeys `Data.Map.union` Data.Map.fromList
-- > [((modm, xK_i), oneShotHook dynHooksRef
-- > "FFlaunchHook" (className =? "firefox") (doShift "3")
-- > >> spawn "firefox")
-- > ,((modm, xK_u), addDynamicHook dynHooksRef
-- > (className =? "example" --> doFloat))
-- > ,((modm, xK_y), updatePermanentHook dynHooksRef
-- > (const idHook))) ] -- resets the permanent hook.
-- > ((modMask,xK_a), oneShotHook (className =? "example") doFloat)
--
data DynamicHooks = DynamicHooks
{ transients :: [(Query Bool, ManageHook)]
, permanent :: ManageHook }
deriving Typeable
instance ExtensionClass DynamicHooks where
initialValue = DynamicHooks [] idHook
-- | Creates the 'IORef' that stores the dynamically created 'ManageHook's.
initDynamicHooks :: IO (IORef DynamicHooks)
initDynamicHooks = newIORef (DynamicHooks { transients = [],
permanent = idHook })
-- this hook is always executed, and the IORef's contents checked.
-- this hook is always executed, and the contents of the stored hooks checked.
-- note that transient hooks are run second, therefore taking precedence
-- over permanent ones on matters such as which workspace to shift to.
-- doFloat and doIgnore are idempotent.
-- | Master 'ManageHook' that must be in your @xmonad.hs@ 'ManageHook'.
dynamicMasterHook :: IORef DynamicHooks -> ManageHook
dynamicMasterHook ref = return True -->
(ask >>= \w -> liftX (do
dh <- io $ readIORef ref
dynamicMasterHook :: ManageHook
dynamicMasterHook = (ask >>= \w -> liftX (do
dh <- XS.get
(Endo f) <- runQuery (permanent dh) w
ts <- mapM (\(q,a) -> runQuery q w >>= \x -> return (x,(q, a))) (transients dh)
let (ts',nts) = partition fst ts
gs <- mapM (flip runQuery w . snd . snd) ts'
let (Endo g) = maybe (Endo id) id $ listToMaybe gs
io $ writeIORef ref $ dh { transients = map snd nts }
XS.put $ dh { transients = map snd nts }
return $ Endo $ f . g
))
-- | Appends the given 'ManageHook' to the permanent dynamic 'ManageHook'.
addDynamicHook :: IORef DynamicHooks -> ManageHook -> X ()
addDynamicHook ref m = updateDynamicHook ref (<+> m)
addDynamicHook :: ManageHook -> X ()
addDynamicHook m = updateDynamicHook (<+> m)
-- | Modifies the permanent 'ManageHook' with an arbitrary function.
updateDynamicHook :: IORef DynamicHooks -> (ManageHook -> ManageHook) -> X ()
updateDynamicHook ref f =
io $ modifyIORef ref $ \dh -> dh { permanent = f (permanent dh) }
updateDynamicHook :: (ManageHook -> ManageHook) -> X ()
updateDynamicHook f = XS.modify $ \dh -> dh { permanent = f (permanent dh) }
-- | Creates a one-shot 'ManageHook'. Note that you have to specify the two
-- parts of the 'ManageHook' separately. Where you would usually write:
@@ -112,11 +89,5 @@ updateDynamicHook ref f =
--
-- > oneShotHook dynHooksRef (className =? "example) doFloat
--
oneShotHook :: IORef DynamicHooks -> Query Bool -> ManageHook -> X ()
oneShotHook ref q a =
io $ modifyIORef ref
$ \dh -> dh { transients = (q,a):(transients dh) }
oneShotHook :: Query Bool -> ManageHook -> X ()
oneShotHook q a = XS.modify $ \dh -> dh { transients = (q,a):(transients dh) }

View File

@@ -29,6 +29,9 @@ module XMonad.Hooks.DynamicLog (
dynamicLog,
dynamicLogXinerama,
xmonadPropLog',
xmonadPropLog,
-- * Build your own formatter
dynamicLogWithPP,
dynamicLogString,
@@ -51,24 +54,26 @@ module XMonad.Hooks.DynamicLog (
) where
--
-- Useful imports
--
import XMonad
import Control.Monad
import Data.Char ( isSpace )
import Codec.Binary.UTF8.String (encodeString)
import Control.Monad (liftM2)
import Data.Char ( isSpace, ord )
import Data.List (intersperse, isPrefixOf, sortBy)
import Data.Maybe ( isJust, catMaybes )
import Data.List
import qualified Data.Map as M
import Data.Ord ( comparing )
import qualified Data.Map as M
import qualified XMonad.StackSet as S
import System.IO
import Foreign.C (CChar)
import XMonad
import XMonad.Util.WorkspaceCompare
import XMonad.Util.NamedWindows
import XMonad.Util.Run
import XMonad.Layout.LayoutModifier
import XMonad.Util.Font
import XMonad.Hooks.UrgencyHook
import XMonad.Hooks.ManageDocks
@@ -81,7 +86,9 @@ import XMonad.Hooks.ManageDocks
-- If you just want a quick-and-dirty status bar with zero effort, try
-- the 'xmobar' or 'dzen' functions:
--
-- > main = xmonad =<< xmobar conf
-- > main = xmonad =<< xmobar myConfig
-- >
-- > myConfig = defaultConfig { ... }
--
-- There is also 'statusBar' if you'd like to use another status bar, or would
-- like to use different formatting options. The 'xmobar', 'dzen', and
@@ -144,7 +151,9 @@ import XMonad.Hooks.ManageDocks
-- | Run xmonad with a dzen status bar set to some nice defaults.
--
-- > main = xmonad =<< dzen conf
-- > main = xmonad =<< dzen myConfig
-- >
-- > myConfig = defaultConfig { ... }
--
-- The intent is that the above config file should provide a nice
-- status bar with minimal effort.
@@ -167,7 +176,9 @@ dzen conf = statusBar ("dzen2 " ++ flags) dzenPP toggleStrutsKey conf
-- | Run xmonad with a xmobar status bar set to some nice defaults.
--
-- > main = xmonad =<< xmobar conf
-- > main = xmonad =<< xmobar myConfig
-- >
-- > myConfig = defaultConfig { ... }
--
-- This works pretty much the same as 'dzen' function above.
--
@@ -198,6 +209,24 @@ statusBar cmd pp k conf = do
where
keys' = (`M.singleton` sendMessage ToggleStruts) . k
-- | Write a string to a property on the root window. This property is of
-- type UTF8_STRING. The string must have been processed by encodeString
-- (dynamicLogString does this).
xmonadPropLog' :: String -> String -> X ()
xmonadPropLog' prop msg = do
d <- asks display
r <- asks theRoot
xlog <- getAtom prop
ustring <- getAtom "UTF8_STRING"
io $ changeProperty8 d r xlog ustring propModeReplace (encodeCChar msg)
where
encodeCChar :: String -> [CChar]
encodeCChar = map (fromIntegral . ord)
-- | Write a string to the _XMONAD_LOG property on the root window.
xmonadPropLog :: String -> X ()
xmonadPropLog = xmonadPropLog' "_XMONAD_LOG"
-- |
-- Helper function which provides ToggleStruts keybinding
--
@@ -245,9 +274,9 @@ dynamicLogString pp = do
wt <- maybe (return "") (fmap show . getName) . S.peek $ winset
-- run extra loggers, ignoring any that generate errors.
extras <- sequence $ map (flip catchX (return Nothing)) $ ppExtras pp
extras <- mapM (flip catchX (return Nothing)) $ ppExtras pp
return $ encodeOutput . sepBy (ppSep pp) . ppOrder pp $
return $ encodeString . sepBy (ppSep pp) . ppOrder pp $
[ ws
, ppLayout pp ld
, ppTitle pp wt
@@ -264,9 +293,9 @@ pprWindowSet sort' urgents pp s = sepBy (ppWsSep pp) . map fmt . sort' $
visibles = map (S.tag . S.workspace) (S.visible s)
fmt w = printer pp (S.tag w)
where printer | S.tag w == this = ppCurrent
where printer | any (\x -> maybe False (== S.tag w) (S.findTag x s)) urgents = ppUrgent
| S.tag w == this = ppCurrent
| S.tag w `elem` visibles = ppVisible
| any (\x -> maybe False (== S.tag w) (S.findTag x s)) urgents = \ppC -> ppUrgent ppC . ppHidden ppC
| isJust (S.stack w) = ppHidden
| otherwise = ppHiddenNoWindows
@@ -278,10 +307,15 @@ pprWindowSet sort' urgents pp s = sepBy (ppWsSep pp) . map fmt . sort' $
-- where 1, 9, and 3 are the workspaces on screens 1, 2 and 3, respectively,
-- and 2 and 7 are non-visible, non-empty workspaces.
--
-- Unfortunately, at the present time, the current layout and window title
-- are not shown, and there is no way to incorporate the xinerama
-- workspace format shown above with 'dynamicLogWithPP'. Hopefully this
-- will change soon.
-- At the present time, the current layout and window title
-- are not shown. The xinerama workspace format shown above can be (mostly) replicated
-- using 'dynamicLogWithPP' by setting 'ppSort' to /getSortByXineramaRule/ from
-- "XMonad.Util.WorkspaceCompare". For example,
--
-- > defaultPP { ppCurrent = dzenColor "red" "#efebe7"
-- > , ppVisible = wrap "[" "]"
-- > , ppSort = getSortByXineramaRule
-- > }
dynamicLogXinerama :: X ()
dynamicLogXinerama = withWindowSet $ io . putStrLn . pprWindowSetXinerama
@@ -312,7 +346,7 @@ trim = f . f
-- | Limit a string to a certain length, adding "..." if truncated.
shorten :: Int -> String -> String
shorten n xs | length xs < n = xs
| otherwise = (take (n - length end) xs) ++ end
| otherwise = take (n - length end) xs ++ end
where
end = "..."
@@ -339,11 +373,7 @@ dzenColor fg bg = wrap (fg1++bg1) (fg2++bg2)
dzenEscape :: String -> String
dzenEscape = concatMap (\x -> if x == '^' then "^^" else [x])
-- | Strip dzen formatting or commands. Useful to remove ppHidden
-- formatting in ppUrgent field. For example:
--
-- > , ppHidden = dzenColor "gray20" "" . wrap "(" ")"
-- > , ppUrgent = dzenColor "dark orange" "" . dzenStrip
-- | Strip dzen formatting or commands.
dzenStrip :: String -> String
dzenStrip = strip [] where
strip keep x
@@ -364,11 +394,7 @@ xmobarColor fg bg = wrap t "</fc>"
-- ??? add an xmobarEscape function?
-- | Strip xmobar markup. Useful to remove ppHidden color from ppUrgent
-- field. For example:
--
-- > , ppHidden = xmobarColor "gray20" "" . wrap "<" ">"
-- > , ppUrgent = xmobarColor "dark orange" "" . xmobarStrip
-- | Strip xmobar markup.
xmobarStrip :: String -> String
xmobarStrip = strip [] where
strip keep x
@@ -394,8 +420,6 @@ data PP = PP { ppCurrent :: WorkspaceId -> String
-- ^ how to print tags of empty hidden workspaces
, ppUrgent :: WorkspaceId -> String
-- ^ format to be applied to tags of urgent workspaces.
-- NOTE that 'ppUrgent' is applied /in addition to/
-- 'ppHidden'!
, ppSep :: String
-- ^ separator to use between different log sections
-- (window name, layout, workspaces)
@@ -451,32 +475,31 @@ defaultPP = PP { ppCurrent = wrap "[" "]"
, ppExtras = []
}
-- | Settings to emulate dwm's statusbar, dzen only. Uses dzenStrip in
-- ppUrgent.
-- | Settings to emulate dwm's statusbar, dzen only.
dzenPP :: PP
dzenPP = defaultPP { ppCurrent = dzenColor "white" "#2b4f98" . pad
, ppVisible = dzenColor "black" "#999999" . pad
, ppHidden = dzenColor "black" "#cccccc" . pad
, ppHiddenNoWindows = const ""
, ppUrgent = dzenColor "red" "yellow" . dzenStrip
, ppWsSep = ""
, ppSep = ""
, ppLayout = dzenColor "black" "#cccccc" .
(\ x -> case x of
"TilePrime Horizontal" -> " TTT "
"TilePrime Vertical" -> " []= "
"Hinted Full" -> " [ ] "
_ -> pad x
)
, ppTitle = ("^bg(#324c80) " ++) . dzenEscape
}
, ppVisible = dzenColor "black" "#999999" . pad
, ppHidden = dzenColor "black" "#cccccc" . pad
, ppHiddenNoWindows = const ""
, ppUrgent = dzenColor "red" "yellow" . pad
, ppWsSep = ""
, ppSep = ""
, ppLayout = dzenColor "black" "#cccccc" .
(\ x -> pad $ case x of
"TilePrime Horizontal" -> "TTT"
"TilePrime Vertical" -> "[]="
"Hinted Full" -> "[ ]"
_ -> x
)
, ppTitle = ("^bg(#324c80) " ++) . dzenEscape
}
-- | Some nice xmobar defaults.
xmobarPP :: PP
xmobarPP = defaultPP { ppCurrent = xmobarColor "yellow" "" . wrap "[" "]"
, ppTitle = xmobarColor "green" "" . shorten 40
, ppVisible = wrap "(" ")"
, ppUrgent = xmobarColor "red" "yellow"
, ppUrgent = xmobarColor "red" "yellow"
}
-- | The options that sjanssen likes to use with xmobar, as an
@@ -492,7 +515,7 @@ byorgeyPP :: PP
byorgeyPP = defaultPP { ppHiddenNoWindows = showNamedWorkspaces
, ppHidden = dzenColor "black" "#a8a3f7" . pad
, ppCurrent = dzenColor "yellow" "#a8a3f7" . pad
, ppUrgent = dzenColor "red" "yellow"
, ppUrgent = dzenColor "red" "yellow" . pad
, ppSep = " | "
, ppWsSep = ""
, ppTitle = shorten 70
@@ -501,4 +524,3 @@ byorgeyPP = defaultPP { ppHiddenNoWindows = showNamedWorkspaces
where showNamedWorkspaces wsId = if any (`elem` wsId) ['a'..'z']
then pad wsId
else ""

View File

@@ -19,7 +19,9 @@ module XMonad.Hooks.EwmhDesktops (
ewmhDesktopsStartup,
ewmhDesktopsLogHook,
ewmhDesktopsLogHookCustom,
ewmhDesktopsEventHook
ewmhDesktopsEventHook,
ewmhDesktopsEventHookCustom,
fullscreenEventHook
) where
import Codec.Binary.UTF8.String (encode)
@@ -32,7 +34,9 @@ import Control.Monad
import qualified XMonad.StackSet as W
import XMonad.Hooks.SetWMName
import XMonad.Util.XUtils (fi)
import XMonad.Util.WorkspaceCompare
import XMonad.Util.WindowProperties (getProp32)
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
@@ -40,9 +44,10 @@ import XMonad.Util.WorkspaceCompare
-- > import XMonad
-- > import XMonad.Hooks.EwmhDesktops
-- >
-- > main = xmonad $ ewmh defaultConfig
-- > main = xmonad $ ewmh defaultConfig{ handleEventHook =
-- > handleEventHook defaultConfig <+> fullscreenEventHook }
--
-- You may also be interested in 'avoidStruts' from XMonad.Hooks.ManageDocks.
-- You may also be interested in 'avoidStruts' from "XMonad.Hooks.ManageDocks".
-- | Add EWMH functionality to the given config. See above for an example.
@@ -113,18 +118,23 @@ ewmhDesktopsLogHookCustom f = withWindowSet $ \s -> do
-- * _NET_WM_DESKTOP (move windows to other desktops)
--
-- * _NET_ACTIVE_WINDOW (activate another window, changing workspace if needed)
--
ewmhDesktopsEventHook :: Event -> X All
ewmhDesktopsEventHook e = handle e >> return (All True)
ewmhDesktopsEventHook = ewmhDesktopsEventHookCustom id
handle :: Event -> X ()
handle ClientMessageEvent {
-- |
-- Generalized version of ewmhDesktopsEventHook that allows an arbitrary
-- user-specified function to transform the workspace list (post-sorting)
ewmhDesktopsEventHookCustom :: ([WindowSpace] -> [WindowSpace]) -> Event -> X All
ewmhDesktopsEventHookCustom f e = handle f e >> return (All True)
handle :: ([WindowSpace] -> [WindowSpace]) -> Event -> X ()
handle f (ClientMessageEvent {
ev_window = w,
ev_message_type = mt,
ev_data = d
} = withWindowSet $ \s -> do
}) = withWindowSet $ \s -> do
sort' <- getSortByIndex
let ws = sort' $ W.workspaces s
let ws = f $ sort' $ W.workspaces s
a_cd <- getAtom "_NET_CURRENT_DESKTOP"
a_d <- getAtom "_NET_WM_DESKTOP"
@@ -132,14 +142,14 @@ handle ClientMessageEvent {
a_cw <- getAtom "_NET_CLOSE_WINDOW"
a_ignore <- mapM getAtom ["XMONAD_TIMER"]
if mt == a_cd then do
let n = fromIntegral (head d)
if 0 <= n && n < length ws then
windows $ W.view (W.tag (ws !! n))
let n = head d
if 0 <= n && fi n < length ws then
windows $ W.view (W.tag (ws !! fi n))
else trace $ "Bad _NET_CURRENT_DESKTOP with data[0]="++show n
else if mt == a_d then do
let n = fromIntegral (head d)
if 0 <= n && n < length ws then
windows $ W.shiftWin (W.tag (ws !! n)) w
let n = head d
if 0 <= n && fi n < length ws then
windows $ W.shiftWin (W.tag (ws !! fi n)) w
else trace $ "Bad _NET_DESKTOP with data[0]="++show n
else if mt == a_aw then do
windows $ W.focusWindow w
@@ -151,8 +161,40 @@ handle ClientMessageEvent {
-- The Message is unknown to us, but that is ok, not all are meant
-- to be handled by the window manager
return ()
handle _ = return ()
handle _ _ = return ()
-- |
-- An event hook to handle applications that wish to fullscreen using the
-- _NET_WM_STATE protocol. This includes users of the gtk_window_fullscreen()
-- function, such as Totem, Evince and OpenOffice.org.
--
-- Note this is not included in 'ewmh'.
fullscreenEventHook :: Event -> X All
fullscreenEventHook (ClientMessageEvent _ _ _ dpy win typ (action:dats)) = do
wmstate <- getAtom "_NET_WM_STATE"
fullsc <- getAtom "_NET_WM_STATE_FULLSCREEN"
wstate <- fromMaybe [] `fmap` getProp32 wmstate win
let isFull = fromIntegral fullsc `elem` wstate
-- Constants for the _NET_WM_STATE protocol:
remove = 0
add = 1
toggle = 2
ptype = 4 -- The atom property type for changeProperty
chWstate f = io $ changeProperty32 dpy win wmstate ptype propModeReplace (f wstate)
when (typ == wmstate && fi fullsc `elem` dats) $ do
when (action == add || (action == toggle && not isFull)) $ do
chWstate (fi fullsc:)
windows $ W.float win $ W.RationalRect 0 0 1 1
when (action == remove || (action == toggle && isFull)) $ do
chWstate $ delete (fi fullsc)
windows $ W.sink win
return $ All True
fullscreenEventHook _ = return $ All True
setNumberOfDesktops :: (Integral a) => a -> X ()
setNumberOfDesktops n = withDisplay $ \dpy -> do

View File

@@ -17,10 +17,12 @@ module XMonad.Hooks.FadeInactive (
-- $usage
setOpacity,
isUnfocused,
isUnfocusedOnCurrentWS,
fadeIn,
fadeOut,
fadeIf,
fadeInactiveLogHook,
fadeInactiveCurrentWSLogHook,
fadeOutLogHook
) where
@@ -44,7 +46,7 @@ import Control.Monad
-- you will need to have xcompmgr <http://freedesktop.org/wiki/Software/xapps>
-- or something similar for this to do anything
--
-- For more detailed instructions on editing the layoutHook see:
-- For more detailed instructions on editing the logHook see:
--
-- "XMonad.Doc.Extending#The_log_hook_and_external_status_bars"
--
@@ -58,18 +60,18 @@ rationalToOpacity perc
| perc < 0 || perc > 1 = round perc -- to maintain backwards-compatability
| otherwise = round $ perc * 0xffffffff
-- | sets the opacity of a window
-- | 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 [rationalToOpacity t]
-- | fades a window out by setting the opacity
-- | 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 = fadeOut 1
@@ -78,15 +80,34 @@ fadeIn = fadeOut 1
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
-- | 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.
-- | Set the opacity of inactive windows, on the current workspace, to the
-- specified amount. This is specifically usefull in a multi monitor setup. See
-- 'isUnfocusedOnCurrentWS'.
fadeInactiveCurrentWSLogHook :: Rational -> X ()
fadeInactiveCurrentWSLogHook = fadeOutLogHook . fadeIf isUnfocusedOnCurrentWS
-- | 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.
-- | Returns True if the window doesn't have the focus, and the window is on the
-- current workspace. This is specifically handy in a multi monitor setup
-- (xinerama) where multiple workspaces are visible. Using this, non-focused
-- workspaces are are not faded out making it easier to look and read the
-- content on them.
isUnfocusedOnCurrentWS :: Query Bool
isUnfocusedOnCurrentWS = do
w <- ask
ws <- liftX $ gets windowset
let thisWS = w `elem` W.index ws
unfocused = maybe True (w /=) $ W.peek ws
return $ thisWS && unfocused
-- | 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) ++

221
XMonad/Hooks/FadeWindows.hs Normal file
View File

@@ -0,0 +1,221 @@
{-# LANGUAGE FlexibleInstances, TypeSynonymInstances #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Hooks.FadeWindows
-- Copyright : Brandon S Allbery KF8NH <allbery.b@gmail.com>
-- License : BSD
--
-- Maintainer : Brandon S Allbery KF8NH
-- Stability : unstable
-- Portability : unportable
--
-- A more flexible and general compositing interface than FadeInactive.
-- Windows can be selected and opacity specified by means of FadeHooks,
-- which are very similar to ManageHooks and use the same machinery.
--
-----------------------------------------------------------------------------
module XMonad.Hooks.FadeWindows (-- * Usage
-- $usage
-- * The 'logHook' for window fading
fadeWindowsLogHook
-- * The 'FadeHook'
,FadeHook
,Opacity
,idFadeHook
-- * Predefined 'FadeHook's
,opaque
,solid
,transparent
,invisible
,transparency
,translucence
,fadeBy
,opacity
,fadeTo
-- * 'handleEventHook' for mapped/unmapped windows
,fadeWindowsEventHook
-- * 'doF' for simple hooks
,doS
-- * Useful 'Query's for 'FadeHook's
,isFloating
,isUnfocused
) where
import XMonad.Core
import XMonad.ManageHook (liftX)
import qualified XMonad.StackSet as W
import XMonad.Hooks.FadeInactive (setOpacity
,isUnfocused
)
import Control.Monad (forM_)
import Control.Monad.Reader (ask
,asks)
import Control.Monad.State (gets)
import qualified Data.Map as M
import Data.Monoid
import Graphics.X11.Xlib.Extras (Event(..))
-- $usage
-- To use this module, make sure your @xmonad@ core supports generalized
-- 'ManageHook's (check the type of 'idHook'; if it's @ManageHook@ then
-- your @xmonad@ is too old) and then add @fadeWindowsLogHook@ to your
-- 'logHook' and @fadeWindowsEventHook@ to your 'handleEventHook':
--
-- > , logHook = fadeWindowsLogHook myFadeHook
-- > , handleEventHook = fadeWindowsEventHook
-- > {- ... -}
-- >
-- > myFadeHook = composeAll [isUnfocused --> transparency 0.2
-- > , opaque
-- > ]
--
-- The above is like FadeInactive with a fade value of 0.2.
--
-- FadeHooks do not accumulate; instead, they compose from right to
-- left like 'ManageHook's, so the above example @myFadeHook@ will
-- render unfocused windows at 4/5 opacity and the focused window
-- as opaque. The 'opaque' hook above is optional, by the way, as any
-- unmatched window will be opaque by default.
--
-- This module is best used with "XMonad.Hooks.MoreManageHelpers", which
-- exports a number of Queries that can be used in either @ManageHook@
-- or @FadeHook@.
--
-- Note that you need a compositing manager such as @xcompmgr@,
-- @dcompmgr@, or @cairo-compmgr@ for window fading to work. If you
-- aren't running a compositing manager, the opacity will be recorded
-- but won't take effect until a compositing manager is started.
--
-- For more detailed instructions on editing the 'logHook' see:
--
-- "XMonad.Doc.Extending#The_log_hook_and_external_status_bars"
--
-- For more detailed instructions on editing the 'handleEventHook',
-- see:
--
-- "XMonad.Doc.Extending#Editing_the_event_hook"
-- (which sadly doesnt exist at the time of writing...)
--
-- /WARNING:/ This module is very good at triggering bugs in
-- compositing managers. Symptoms range from windows not being
-- repainted until the compositing manager is restarted or the
-- window is unmapped and remapped, to the machine becoming sluggish
-- until the compositing manager is restarted (at which point a
-- popup/dialog will suddenly appear; apparently it's getting into
-- a tight loop trying to fade the popup in). I find it useful to
-- have a key binding to restart the compositing manager; for example,
--
-- main = xmonad $ defaultConfig {
-- {- ... -}
-- }
-- `additionalKeysP`
-- [("M-S-4",spawn "killall xcompmgr; sleep 1; xcompmgr -cCfF &")]
-- {- ... -}
-- ]
--
-- (See "XMonad.Util.EZConfig" for 'additionalKeysP'.)
-- a window opacity to be carried in a Query. OEmpty is sort of a hack
-- to make it obay the monoid laws
data Opacity = Opacity Rational | OEmpty
instance Monoid Opacity where
mempty = OEmpty
r `mappend` OEmpty = r
_ `mappend` r = r
-- | A FadeHook is similar to a ManageHook, but records window opacity.
type FadeHook = Query Opacity
-- | Render a window fully opaque.
opaque :: FadeHook
opaque = doS (Opacity 1)
-- | Render a window fully transparent.
transparent :: FadeHook
transparent = doS (Opacity 0)
-- | Specify a window's transparency.
transparency :: Rational -- ^ The window's transparency as a fraction.
-- @transparency 1@ is the same as 'transparent',
-- whereas @transparency 0@ is the same as 'opaque'.
-> FadeHook
transparency = doS . Opacity . (1-) . clampRatio
-- | Specify a window's opacity; this is the inverse of 'transparency'.
opacity :: Rational -- ^ The opacity of a window as a fraction.
-- @opacity 1@ is the same as 'opaque',
-- whereas @opacity 0@ is the same as 'transparent'.
-> FadeHook
opacity = doS . Opacity . clampRatio
fadeTo, translucence, fadeBy :: Rational -> FadeHook
-- ^ An alias for 'transparency'.
fadeTo = transparency
-- ^ An alias for 'transparency'.
translucence = transparency
-- ^ An alias for 'transparency'.
fadeBy = opacity
invisible, solid :: FadeHook
-- ^ An alias for 'transparent'.
invisible = transparent
-- ^ An alias for 'opaque'.
solid = opaque
-- | Like 'doF', but usable with 'ManageHook'-like hooks that
-- aren't 'Query' wrapped around transforming functions ('Endo').
doS :: Monoid m => m -> Query m
doS = return
-- | The identity 'FadeHook', which renders windows 'opaque'.
idFadeHook :: FadeHook
idFadeHook = opaque
-- | A Query to determine if a window is floating.
isFloating :: Query Bool
isFloating = ask >>= \w -> liftX . gets $ M.member w . W.floating . windowset
-- boring windows can't be seen outside of a layout, so we watch messages with
-- a dummy LayoutModifier and stow them in a persistent bucket. this is not
-- entirely reliable given that boringAuto still isn't observable; we just hope
-- those aren't visible and won;t be affected anyway
-- @@@ punted for now, will be a separate module. it's still slimy, though
-- | A 'logHook' to fade windows under control of a 'FadeHook', which is
-- similar to but not identical to 'ManageHook'.
fadeWindowsLogHook :: FadeHook -> X ()
fadeWindowsLogHook h = 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 $ \w -> do
o <- userCodeDef (Opacity 1) (runQuery h w)
setOpacity w $ case o of
OEmpty -> 0.93
Opacity r -> r
-- | A 'handleEventHook' to handle fading and unfading of newly mapped
-- or unmapped windows; this avoids problems with layouts such as
-- "XMonad.Layout.Full" or "XMonad.Layout.Tabbed". This hook may
-- also be useful with "XMonad.Hooks.FadeInactive".
fadeWindowsEventHook :: Event -> X All
fadeWindowsEventHook (MapNotifyEvent {}) =
-- we need to run the fadeWindowsLogHook. only one way...
asks config >>= logHook >> return (All True)
fadeWindowsEventHook _ = return (All True)
-- A utility to clamp opacity fractions to the range (0,1)
clampRatio :: Rational -> Rational
clampRatio r | r >= 0 && r <= 1 = r
| r < 0 = 0
| otherwise = 1

View File

@@ -1,10 +1,11 @@
{-# LANGUAGE DeriveDataTypeable #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Hooks.FloatNext
-- Copyright : Quentin Moser <quentin.moser@unifr.ch>
-- Copyright : Quentin Moser <moserq@gmail.com>
-- License : BSD-style (see LICENSE)
--
-- Maintainer : Quentin Moser <quentin.moser@unifr.ch>
-- Maintainer : orphaned
-- Stability : unstable
-- Portability : unportable
--
@@ -35,40 +36,11 @@ module XMonad.Hooks.FloatNext ( -- * Usage
, willFloatAllNewPP
, runLogHook ) where
import Prelude hiding (all)
import XMonad
import XMonad.Hooks.ToggleHook
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)
hookName :: String
hookName = "__float"
-- $usage
-- This module provides actions (that can be set as keybindings)
@@ -93,40 +65,34 @@ floatModeMVar = unsafePerformIO $ newMVar (False, False)
--
-- > , ((modm, xK_r), toggleFloatAllNew)
-- | This 'ManageHook' will selectively float windows as set
-- by 'floatNext' and 'floatAllNew'.
floatNextHook :: ManageHook
floatNextHook = do (next, all) <- io $ takeMVar floatModeMVar
io $ putMVar floatModeMVar (False, all)
if next || all then doFloat else idHook
floatNextHook = toggleHook hookName doFloat
-- | @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
floatNext = hookNext hookName
toggleFloatNext :: X ()
toggleFloatNext = _toggle first
toggleFloatNext = toggleHookNext hookName
-- | @floatAllNew True@ arranges for new windows to be
-- sent to the floating layer, @floatAllNew False@ cancels it
floatAllNew :: Bool -> X ()
floatAllNew = _set second
floatAllNew = hookAllNew hookName
toggleFloatAllNew :: X ()
toggleFloatAllNew = _toggle second
toggleFloatAllNew = toggleHookAllNew hookName
-- | Whether the next window will be set floating
willFloatNext :: X Bool
willFloatNext = _get fst
willFloatNext = willHookNext hookName
-- | Whether new windows will be set floating
willFloatAllNew :: X Bool
willFloatAllNew = _get snd
willFloatAllNew = willHookAllNew hookName
-- $pp
-- The following functions are used to display the current
@@ -148,10 +114,7 @@ willFloatAllNew = _get snd
-- pass them 'id'.
willFloatNextPP :: (String -> String) -> X (Maybe String)
willFloatNextPP = _pp fst "Next"
willFloatNextPP = willHookNextPP hookName
willFloatAllNewPP :: (String -> String) -> X (Maybe String)
willFloatAllNewPP = _pp snd "All"
runLogHook :: X ()
runLogHook = join $ asks $ logHook . config
willFloatAllNewPP = willHookAllNewPP hookName

View File

@@ -0,0 +1,42 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Hooks.ICCCMFocus
-- License : BSD
--
-- Maintainer : Tony Morris <haskell@tmorris.net>
--
-- Implemented in your @logHook@, Java swing applications will not misbehave
-- when it comes to taking and losing focus.
--
-- This has been done by taking the patch in <http://code.google.com/p/xmonad/issues/detail?id=177> and refactoring it so that it can be included in @~\/.xmonad\/xmonad.hs@.
--
-- @
-- conf' =
-- conf {
-- logHook = takeTopFocus
-- }
-- @
-----------------------------------------------------------------------------
module XMonad.Hooks.ICCCMFocus
{-# DEPRECATED "XMonad.Hooks.ICCCMFocus: xmonad>0.10 core merged issue 177" #-}
(
atom_WM_TAKE_FOCUS
, takeFocusX
, takeTopFocus
) where
import XMonad
import XMonad.Hooks.SetWMName
import qualified XMonad.StackSet as W
takeFocusX ::
Window
-> X ()
takeFocusX _w = return ()
-- | The value to add to your log hook configuration.
takeTopFocus ::
X ()
takeTopFocus =
(withWindowSet $ maybe (setFocusX =<< asks theRoot) takeFocusX . W.peek) >> setWMName "LG3D"

View File

@@ -46,7 +46,7 @@ data Focus = Newer | Older
insertPosition :: Position -> Focus -> ManageHook
insertPosition pos foc = Endo . g <$> ask
where
g w = viewingWs w (updateFocus w . ins w . W.delete w)
g w = viewingWs w (updateFocus w . ins w . W.delete' w)
ins w = (\f ws -> fromMaybe id (W.focusWindow <$> W.peek ws) $ f ws) $
case pos of
Master -> W.insertUp w . W.focusMaster

View File

@@ -1,5 +1,4 @@
{-# LANGUAGE PatternGuards, FlexibleInstances, MultiParamTypeClasses #-}
{-# OPTIONS -fglasgow-exts #-}
{-# LANGUAGE DeriveDataTypeable, PatternGuards, FlexibleInstances, MultiParamTypeClasses, CPP #-}
-- deriving Typeable for ghc-6.6 compatibility, which is retained in the core
-----------------------------------------------------------------------------
-- |
@@ -18,10 +17,17 @@ module XMonad.Hooks.ManageDocks (
-- * Usage
-- $usage
manageDocks, checkDock, AvoidStruts, avoidStruts, avoidStrutsOn,
docksEventHook,
ToggleStruts(..),
SetStruts(..),
module XMonad.Util.Types,
#ifdef TESTING
r2c,
c2r,
RectC(..),
#endif
-- for XMonad.Actions.FloatSnap
calcGap
) where
@@ -30,10 +36,11 @@ module XMonad.Hooks.ManageDocks (
-----------------------------------------------------------------------------
import XMonad
import Foreign.C.Types (CLong)
import Control.Monad
import XMonad.Layout.LayoutModifier
import XMonad.Util.Types
import XMonad.Util.WindowProperties (getProp32s)
import XMonad.Util.XUtils (fi)
import Data.Monoid (All(..))
import qualified Data.Set as S
@@ -56,6 +63,11 @@ import qualified Data.Set as S
-- > layoutHook = avoidStruts (tall ||| mirror tall ||| ...)
-- > where tall = Tall 1 (3/100) (1/2)
--
-- The third component is an event hook that causes new docks to appear
-- immediately, instead of waiting for the next focus change.
--
-- > handleEventHook = ... <+> docksEventHook
--
-- 'AvoidStruts' also supports toggling the dock gaps; add a keybinding
-- similar to:
--
@@ -99,8 +111,16 @@ checkDock = ask >>= \w -> liftX $ do
desk <- getAtom "_NET_WM_WINDOW_TYPE_DESKTOP"
mbr <- getProp32s "_NET_WM_WINDOW_TYPE" w
case mbr of
Just [r] -> return $ elem (fromIntegral r) [dock, desk]
_ -> return False
Just rs -> return $ any (`elem` [dock,desk]) (map fromIntegral rs)
_ -> return False
-- | Whenever a new dock appears, refresh the layout immediately to avoid the
-- new dock.
docksEventHook :: Event -> X All
docksEventHook (MapNotifyEvent {ev_window = w}) = do
whenX ((not `fmap` (isClient w)) <&&> runQuery checkDock w) refresh
return (All True)
docksEventHook _ = return (All True)
-- | Gets the STRUT config, if present, in xmonad gap order
getStrut :: Window -> X [Strut]
@@ -210,41 +230,34 @@ type Strut = (Direction2D, CLong, CLong, CLong)
-- | (Initial x pixel, initial y pixel,
-- final x pixel, final y pixel).
type RectC = (CLong, CLong, CLong, CLong)
fi :: (Integral a, Num b) => a -> b
fi = fromIntegral
newtype RectC = RectC (CLong, CLong, CLong, CLong) deriving (Eq,Show)
-- | Invertible conversion.
r2c :: Rectangle -> RectC
r2c (Rectangle x y w h) = (fi x, fi y, fi x + fi w - 1, fi y + fi h - 1)
r2c (Rectangle x y w h) = RectC (fi x, fi y, fi x + fi w - 1, fi y + fi h - 1)
-- | Invertible conversion.
c2r :: RectC -> Rectangle
c2r (x1, y1, x2, y2) = Rectangle (fi x1) (fi y1) (fi $ x2 - x1 + 1) (fi $ y2 - y1 + 1)
c2r (RectC (x1, y1, x2, y2)) = Rectangle (fi x1) (fi y1) (fi $ x2 - x1 + 1) (fi $ y2 - y1 + 1)
-- TODO: Add these QuickCheck properties to the test suite, along with
-- suitable Arbitrary instances.
-- prop_r2c_c2r :: RectC -> Bool
-- prop_r2c_c2r r = r2c (c2r r) == r
-- prop_c2r_r2c :: Rectangle -> Bool
-- prop_c2r_r2c r = c2r (r2c r) == r
reduce :: RectC -> Strut -> RectC -> RectC
reduce (sx0, sy0, sx1, sy1) (s, n, l, h) (x0, y0, x1, y1) = case s of
L | p (y0, y1) -> (mx x0 sx0 , y0 , x1 , y1 )
R | p (y0, y1) -> (x0 , y0 , mn x1 sx1, y1 )
U | p (x0, x1) -> (x0 , mx y0 sy0, x1 , y1 )
D | p (x0, x1) -> (x0 , y0 , x1 , mn y1 sy1)
_ -> (x0 , y0 , x1 , y1 )
reduce (RectC (sx0, sy0, sx1, sy1)) (s, n, l, h) (RectC (x0, y0, x1, y1)) =
RectC $ case s of
L | p (y0, y1) && qh x1 -> (mx x0 sx0, y0 , x1 , y1 )
R | p (y0, y1) && qv sx1 x0 -> (x0 , y0 , mn x1 sx1, y1 )
U | p (x0, x1) && qh y1 -> (x0 , mx y0 sy0, x1 , y1 )
D | p (x0, x1) && qv sy1 y0 -> (x0 , y0 , x1 , mn y1 sy1)
_ -> (x0 , y0 , x1 , y1 )
where
mx a b = max a (b + n)
mn a b = min a (b - n)
p r = r `overlaps` (l, h)
-- Filter out struts that cover the entire rectangle:
qh d1 = n <= d1
qv sd1 d0 = sd1 - n >= d0
-- | Do the two ranges overlap?
--

View File

@@ -28,6 +28,7 @@ module XMonad.Hooks.ManageHelpers (
Side(..),
composeOne,
(-?>), (/=?), (<==?), (</=?), (-->>), (-?>>),
currentWs,
isInProperty,
isKDETrayWindow,
isFullscreen,
@@ -44,7 +45,8 @@ module XMonad.Hooks.ManageHelpers (
doSideFloat,
doFloatAt,
doFloatDep,
doHideIgnore
doHideIgnore,
Match,
) where
import XMonad
@@ -56,7 +58,7 @@ import Data.Monoid
import System.Posix (ProcessID)
-- | Denotes a side of a screen. @S@ stands for South, @NE@ for Northwest
-- | Denotes a side of a screen. @S@ stands for South, @NE@ for Northeast
-- etc. @C@ stands for Center.
data Side = SC | NC | CE | CW | SE | SW | NE | NW | C
deriving (Read, Show, Eq)
@@ -118,6 +120,10 @@ p -?>> f = do
Match b m <- p
if b then fmap Just (f m) else return Nothing
-- | Return the current workspace
currentWs :: Query WorkspaceId
currentWs = liftX (withWindowSet $ return . W.currentTag)
-- | A predicate to check whether a window is a KDE system tray icon.
isKDETrayWindow :: Query Bool
isKDETrayWindow = ask >>= \w -> liftX $ do

53
XMonad/Hooks/Minimize.hs Normal file
View File

@@ -0,0 +1,53 @@
----------------------------------------------------------------------------
-- |
-- Module : XMonad.Hooks.Minimize
-- Copyright : (c) Justin Bogner 2010
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : Justin Bogner <mail@justinbogner.com>
-- Stability : unstable
-- Portability : not portable
--
-- Handles window manager hints to minimize and restore windows. Use
-- this with XMonad.Layout.Minimize.
--
-----------------------------------------------------------------------------
module XMonad.Hooks.Minimize
( -- * Usage
-- $usage
minimizeEventHook
) 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.Minimize
-- > import XMonad.Layout.Minimize
-- >
-- > myHandleEventHook = minimizeEventHook
-- > myLayout = minimize (Tall 1 (3/100) (1/2)) ||| Full ||| etc..
-- > main = xmonad defaultConfig { layoutHook = myLayout
-- > , handleEventHook = myHandleEventHook }
minimizeEventHook :: Event -> X All
minimizeEventHook (ClientMessageEvent {ev_window = w,
ev_message_type = mt,
ev_data = dt}) = do
a_aw <- getAtom "_NET_ACTIVE_WINDOW"
a_cs <- getAtom "WM_CHANGE_STATE"
when (mt == a_aw) $ sendMessage (RestoreMinimizedWin w)
when (mt == a_cs) $ do
let message = fromIntegral . head $ dt
when (message == normalState) $ sendMessage (RestoreMinimizedWin w)
when (message == iconicState) $ minimizeWindow w
return (All True)
minimizeEventHook _ = return (All True)

View File

@@ -1,10 +1,10 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Hooks.Place
-- Copyright : Quentin Moser <quentin.moser@unifr.ch>
-- Copyright : Quentin Moser <moserq@gmail.com>
-- License : BSD-style (see LICENSE)
--
-- Maintainer : Quentin Moser <quentin.moser@unifr.ch>
-- Maintainer : orphaned
-- Stability : unstable
-- Portability : unportable
--
@@ -38,11 +38,12 @@ import qualified XMonad.StackSet as S
import XMonad.Layout.WindowArranger
import XMonad.Actions.FloatKeys
import XMonad.Util.XUtils
import qualified Data.Map as M
import Data.Ratio ((%))
import Data.List (sortBy, minimumBy, partition)
import Data.Maybe (maybe, fromMaybe, catMaybes)
import Data.Maybe (fromMaybe, catMaybes)
import Data.Monoid (Endo(..))
import Control.Monad (guard, join)
import Control.Monad.Trans (lift)
@@ -262,8 +263,6 @@ checkBounds (Rectangle x1 y1 w1 h1) (Rectangle x2 y2 w2 h2)
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)

View File

@@ -0,0 +1,106 @@
----------------------------------------------------------------------------
-- |
-- Module : XMonad.Hooks.PositionStoreHooks
-- Copyright : (c) Jan Vornberger 2009
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : jan.vornberger@informatik.uni-oldenburg.de
-- Stability : unstable
-- Portability : not portable
--
-- This module contains two hooks for the
-- PositionStore (see "XMonad.Util.PositionStore") - a ManageHook and
-- an EventHook.
--
-- The ManageHook can be used to fill the PositionStore with position and size
-- information about new windows. The advantage of using this hook is, that the
-- information is recorded independent of the currently active layout. So the
-- floating shape of the window can later be restored even if it was opened in a
-- tiled layout initially.
--
-- For windows, that do not request a particular position, a random position will
-- be assigned. This prevents windows from piling up exactly on top of each other.
--
-- The EventHook makes sure that windows are deleted from the PositionStore
-- when they are closed.
--
-----------------------------------------------------------------------------
module XMonad.Hooks.PositionStoreHooks (
-- * Usage
-- $usage
positionStoreManageHook,
positionStoreEventHook
) where
import XMonad
import qualified XMonad.StackSet as W
import XMonad.Util.PositionStore
import XMonad.Hooks.ManageDocks
import XMonad.Layout.Decoration
import System.Random(randomRIO)
import Control.Applicative((<$>))
import Control.Monad(when)
import Data.Maybe
import Data.Monoid
import qualified Data.Set as S
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
--
-- > import XMonad.Hooks.PositionStoreHooks
--
-- and adding 'positionStoreManageHook' to your 'ManageHook' as well
-- as 'positionStoreEventHook' to your event hooks. To be accurate
-- about window sizes, the module needs to know if any decoration is in effect.
-- This is specified with the first argument: Supply 'Nothing' for no decoration,
-- otherwise use 'Just defaultTheme' or similar to inform the module about the
-- decoration theme used.
--
-- > myManageHook = positionStoreManageHook Nothing <+> manageHook defaultConfig
-- > myHandleEventHook = positionStoreEventHook
-- >
-- > main = xmonad defaultConfig { manageHook = myManageHook
-- > , handleEventHook = myHandleEventHook
-- > }
--
positionStoreManageHook :: Maybe Theme -> ManageHook
positionStoreManageHook mDecoTheme = ask >>= liftX . positionStoreInit mDecoTheme >> idHook
positionStoreInit :: Maybe Theme -> Window -> X ()
positionStoreInit mDecoTheme w = withDisplay $ \d -> do
let decoH = maybe 0 decoHeight mDecoTheme -- take decoration into account, which - in its current
-- form - makes windows smaller to make room for it
wa <- io $ getWindowAttributes d w
ws <- gets windowset
arbitraryOffsetX <- randomIntOffset
arbitraryOffsetY <- randomIntOffset
if (wa_x wa == 0) && (wa_y wa == 0)
then do
let sr@(Rectangle srX srY _ _) = screenRect . W.screenDetail . W.current $ ws
modifyPosStore (\ps -> posStoreInsert ps w
(Rectangle (srX + fi arbitraryOffsetX)
(srY + fi arbitraryOffsetY)
(fi $ wa_width wa)
(decoH + fi (wa_height wa))) sr )
else do
sc <- fromMaybe (W.current ws) <$> pointScreen (fi $ wa_x wa) (fi $ wa_y wa)
let sr = screenRect . W.screenDetail $ sc
sr' <- fmap ($ sr) (calcGap $ S.fromList [minBound .. maxBound]) -- take docks into account, accepting
-- a somewhat unfortunate inter-dependency
-- with 'XMonad.Hooks.ManageDocks'
modifyPosStore (\ps -> posStoreInsert ps w
(Rectangle (fi $ wa_x wa) (fi (wa_y wa) - fi decoH)
(fi $ wa_width wa) (decoH + fi (wa_height wa))) sr' )
where
randomIntOffset :: X (Int)
randomIntOffset = io $ randomRIO (42, 242)
positionStoreEventHook :: Event -> X All
positionStoreEventHook (DestroyWindowEvent {ev_window = w, ev_event_type = et}) = do
when (et == destroyNotify) $ do
modifyPosStore (\ps -> posStoreRemove ps w)
return (All True)
positionStoreEventHook _ = return (All True)

View File

@@ -8,9 +8,9 @@
-- 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).
-- (Deprecated: Use XMonad.Hooks.Minimize) Lets you restore minimized
-- windows (see "XMonad.Layout.Minimize") by selecting them on a
-- taskbar (listens for _NET_ACTIVE_WINDOW and WM_CHANGE_STATE).
--
-----------------------------------------------------------------------------

View File

@@ -0,0 +1,170 @@
{-# LANGUAGE DeriveDataTypeable #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Hooks.ScreenCorners
-- Copyright : (c) 2009 Nils Schweinsberg
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : Nils Schweinsberg <mail@n-sch.de>
-- Stability : unstable
-- Portability : unportable
--
-- Run @X ()@ actions by touching the edge of your screen with your mouse.
--
-----------------------------------------------------------------------------
module XMonad.Hooks.ScreenCorners
(
-- * Usage
-- $usage
-- * Adding screen corners
ScreenCorner (..)
, addScreenCorner
, addScreenCorners
-- * Event hook
, screenCornerEventHook
) where
import Data.Monoid
import Data.List (find)
import XMonad
import XMonad.Util.XUtils (fi)
import qualified Data.Map as M
import qualified XMonad.Util.ExtensibleState as XS
data ScreenCorner = SCUpperLeft
| SCUpperRight
| SCLowerLeft
| SCLowerRight
deriving (Eq, Ord, Show)
--------------------------------------------------------------------------------
-- ExtensibleState modifications
--------------------------------------------------------------------------------
newtype ScreenCornerState = ScreenCornerState (M.Map Window (ScreenCorner, X ()))
deriving Typeable
instance ExtensionClass ScreenCornerState where
initialValue = ScreenCornerState M.empty
-- | Add one single @X ()@ action to a screen corner
addScreenCorner :: ScreenCorner -> X () -> X ()
addScreenCorner corner xF = do
ScreenCornerState m <- XS.get
(win,xFunc) <- case find (\(_,(sc,_)) -> sc == corner) (M.toList m) of
Just (w, (_,xF')) -> return (w, xF' >> xF) -- chain X actions
Nothing -> flip (,) xF `fmap` createWindowAt corner
XS.modify $ \(ScreenCornerState m') -> ScreenCornerState $ M.insert win (corner,xFunc) m'
-- | Add a list of @(ScreenCorner, X ())@ tuples
addScreenCorners :: [ (ScreenCorner, X ()) ] -> X ()
addScreenCorners = mapM_ (\(corner, xF) -> addScreenCorner corner xF)
--------------------------------------------------------------------------------
-- Xlib functions
--------------------------------------------------------------------------------
-- "Translate" a ScreenCorner to real (x,y) Positions
createWindowAt :: ScreenCorner -> X Window
createWindowAt SCUpperLeft = createWindowAt' 0 0
createWindowAt SCUpperRight = withDisplay $ \dpy ->
let w = displayWidth dpy (defaultScreen dpy) - 1
in createWindowAt' (fi w) 0
createWindowAt SCLowerLeft = withDisplay $ \dpy ->
let h = displayHeight dpy (defaultScreen dpy) - 1
in createWindowAt' 0 (fi h)
createWindowAt SCLowerRight = withDisplay $ \dpy ->
let w = displayWidth dpy (defaultScreen dpy) - 1
h = displayHeight dpy (defaultScreen dpy) - 1
in createWindowAt' (fi w) (fi h)
-- Create a new X window at a (x,y) Position
createWindowAt' :: Position -> Position -> X Window
createWindowAt' x y = withDisplay $ \dpy -> io $ do
rootw <- rootWindow dpy (defaultScreen dpy)
let
visual = defaultVisualOfScreen $ defaultScreenOfDisplay dpy
attrmask = cWOverrideRedirect
w <- allocaSetWindowAttributes $ \attributes -> do
set_override_redirect attributes True
createWindow dpy -- display
rootw -- parent window
x -- x
y -- y
1 -- width
1 -- height
0 -- border width
0 -- depth
inputOnly -- class
visual -- visual
attrmask -- valuemask
attributes -- attributes
-- we only need mouse entry events
selectInput dpy w enterWindowMask
mapWindow dpy w
sync dpy False
return w
--------------------------------------------------------------------------------
-- Event hook
--------------------------------------------------------------------------------
-- | Handle screen corner events
screenCornerEventHook :: Event -> X All
screenCornerEventHook CrossingEvent { ev_window = win } = do
ScreenCornerState m <- XS.get
case M.lookup win m of
Just (_, xF) -> xF
Nothing -> return ()
return (All True)
screenCornerEventHook _ = return (All True)
--------------------------------------------------------------------------------
-- $usage
--
-- This extension adds KDE-like screen corners to XMonad. By moving your cursor
-- into one of your screen corners you can trigger an @X ()@ action, for
-- example @"XMonad.Actions.GridSelect".goToSelected@ or
-- @"XMonad.Actions.CycleWS".nextWS@ etc.
--
-- To use it, import it on top of your @xmonad.hs@:
--
-- > import XMonad.Hooks.ScreenCorners
--
-- Then add your screen corners in our startup hook:
--
-- > myStartupHook = do
-- > ...
-- > addScreenCorner SCUpperRight (goToSelected defaultGSConfig { gs_cellwidth = 200})
-- > addScreenCorners [ (SCLowerRight, nextWS)
-- > , (SCLowerLeft, prevWS)
-- > ]
--
-- And finally wait for screen corner events in your event hook:
--
-- > myEventHook e = do
-- > ...
-- > screenCornerEventHook e

View File

@@ -26,9 +26,6 @@ module XMonad.Hooks.Script (
--
import XMonad
import Control.Monad.Trans
import System.Directory
-- $usage
--
-- This module allows you to run a centrally located script with the text
@@ -48,7 +45,7 @@ import System.Directory
-- | Execute a named script hook
execScriptHook :: MonadIO m => String -> m ()
execScriptHook hook = io $ do
home <- getHomeDirectory
let script = home ++ "/.xmonad/hooks "
execScriptHook hook = do
xmonadDir <- getXMonadDir
let script = xmonadDir ++ "/hooks "
spawn (script ++ hook)

View File

@@ -64,7 +64,6 @@ module XMonad.Hooks.ServerMode
) where
import Control.Monad (when)
import Data.List
import Data.Monoid
import System.IO

170
XMonad/Hooks/ToggleHook.hs Normal file
View File

@@ -0,0 +1,170 @@
{-# LANGUAGE DeriveDataTypeable #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Hooks.ToggleHook
-- Copyright : Ben Boeckel <mathstuf@gmail.com>
-- License : BSD-style (see LICENSE)
--
-- Maintainer : Ben Boeckel <mathstuf@gmail.com>
-- Stability : unstable
-- Portability : unportable
--
-- Hook and keybindings for toggling hook behavior.
-----------------------------------------------------------------------------
module XMonad.Hooks.ToggleHook ( -- * Usage
-- $usage
-- * The hook
toggleHook
, toggleHook'
-- * Actions
, hookNext
, toggleHookNext
, hookAllNew
, toggleHookAllNew
-- * Queries
, willHook
, willHookNext
, willHookAllNew
-- * 'DynamicLog' utilities
-- $pp
, willHookNextPP
, willHookAllNewPP
, runLogHook ) where
import Prelude hiding (all)
import XMonad
import qualified XMonad.Util.ExtensibleState as XS
import Control.Monad (join,guard)
import Control.Applicative ((<$>))
import Control.Arrow (first, second)
import Data.Map
{- Helper functions -}
_set :: String -> ((a -> a) -> (Bool, Bool) -> (Bool, Bool)) -> a -> X ()
_set n f b = modify' n (f $ const b)
_toggle :: String -> ((Bool -> Bool) -> (Bool, Bool) -> (Bool, Bool)) -> X ()
_toggle n f = modify' n (f not)
_get :: String -> ((Bool, Bool) -> a) -> X a
_get n f = XS.gets $ f . (findWithDefault (False, False) n . hooks)
_pp :: String -> ((Bool, Bool) -> Bool) -> String -> (String -> String) -> X (Maybe String)
_pp n f s st = (\b -> guard b >> Just (st s)) <$> _get n f
{- The current state is kept here -}
data HookState = HookState { hooks :: Map String (Bool, Bool) } deriving (Typeable, Read, Show)
instance ExtensionClass HookState where
initialValue = HookState empty
extensionType = PersistentExtension
modify' :: String -> ((Bool, Bool) -> (Bool, Bool)) -> X ()
modify' n f = XS.modify (HookState . setter . hooks)
where
setter m = insert n (f (findWithDefault (False, False) n m)) m
-- $usage
-- This module provides actions (that can be set as keybindings)
-- to be able to cause hooks to be occur on a conditional basis.
--
-- You can use it by including the following in your @~\/.xmonad\/xmonad.hs@:
--
-- > import XMonad.Hooks.ToggleHook
--
-- and adding 'toggleHook name hook' to your 'ManageHook' where @name@ is the
-- name of the hook and @hook@ is the hook to execute based on the state.
--
-- > myManageHook = toggleHook "float" doFloat <+> manageHook defaultConfig
--
-- Additionally, toggleHook' is provided to toggle between two hooks (rather
-- than on/off).
--
-- > myManageHook = toggleHook' "oldfocus" (const id) W.focusWindow <+> manageHook defaultConfig
--
-- The 'hookNext' and 'toggleHookNext' functions can be used in key
-- bindings to set whether the hook is applied or not.
--
-- > , ((modm, xK_e), toggleHookNext "float")
--
-- 'hookAllNew' and 'toggleHookAllNew' are similar but float all
-- spawned windows until disabled again.
--
-- > , ((modm, xK_r), toggleHookAllNew "float")
-- | This 'ManageHook' will selectively apply a hook as set
-- by 'hookNext' and 'hookAllNew'.
toggleHook :: String -> ManageHook -> ManageHook
toggleHook n h = toggleHook' n h idHook
toggleHook' :: String -> ManageHook -> ManageHook -> ManageHook
toggleHook' n th fh = do m <- liftX $ XS.gets hooks
(next, all) <- return $ findWithDefault (False, False) n m
liftX $ XS.put $ HookState $ insert n (False, all) m
if next || all then th else fh
-- | @hookNext name True@ arranges for the next spawned window to
-- have the hook @name@ applied, @hookNext name False@ cancels it.
hookNext :: String -> Bool -> X ()
hookNext n = _set n first
toggleHookNext :: String -> X ()
toggleHookNext n = _toggle n first
-- | @hookAllNew name True@ arranges for new windows to
-- have the hook @name@ applied, @hookAllNew name False@ cancels it
hookAllNew :: String -> Bool -> X ()
hookAllNew n = _set n second
toggleHookAllNew :: String -> X ()
toggleHookAllNew n = _toggle n second
-- | Query what will happen at the next ManageHook call for the hook @name@.
willHook :: String -> X Bool
willHook n = willHookNext n <||> willHookAllNew n
-- | Whether the next window will trigger the hook @name@.
willHookNext :: String -> X Bool
willHookNext n = _get n fst
-- | Whether new windows will trigger the hook @name@.
willHookAllNew :: String -> X Bool
willHookAllNew n = _get n snd
-- $pp
-- The following functions are used to display the current
-- state of 'hookNext' and 'hookAllNew' in your
-- 'XMonad.Hooks.DynamicLog.dynamicLogWithPP'.
-- 'willHookNextPP' and 'willHookAllNewPP' 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 'hookNext'/... will be visible
-- immediately:
--
-- > , ((modm, xK_e), toggleHookNext "float" >> runLogHook)
--
-- The @String -> String@ parameters to 'willHookNextPP' and
-- 'willHookAllNewPP' will be applied to their output, you
-- can use them to set the text color, etc., or you can just
-- pass them 'id'.
willHookNextPP :: String -> (String -> String) -> X (Maybe String)
willHookNextPP n = _pp n fst "Next"
willHookAllNewPP :: String -> (String -> String) -> X (Maybe String)
willHookAllNewPP n = _pp n snd "All"
runLogHook :: X ()
runLogHook = join $ asks $ logHook . config

View File

@@ -1,4 +1,5 @@
{-# LANGUAGE FlexibleContexts, MultiParamTypeClasses, TypeSynonymInstances, PatternGuards #-}
{-# LANGUAGE FlexibleContexts, MultiParamTypeClasses, TypeSynonymInstances, PatternGuards, DeriveDataTypeable,
FlexibleInstances #-}
-----------------------------------------------------------------------------
-- |
@@ -58,30 +59,33 @@ module XMonad.Hooks.UrgencyHook (
dzenUrgencyHook,
DzenUrgencyHook(..),
NoUrgencyHook(..),
BorderUrgencyHook(..),
FocusHook(..),
minutes, seconds,
-- * Stuff for developers:
readUrgents, withUrgents,
StdoutUrgencyHook(..),
SpawnUrgencyHook(..),
UrgencyHook(urgencyHook)
UrgencyHook(urgencyHook),
Interval,
borderUrgencyHook, focusHook, spawnUrgencyHook, stdoutUrgencyHook
) where
import XMonad
import qualified XMonad.StackSet as W
import XMonad.Util.Dzen (dzenWithArgs, seconds)
import qualified XMonad.Util.ExtensibleState as XS
import XMonad.Util.NamedWindows (getName)
import XMonad.Util.Timer (TimerId, startTimer, handleTimer)
import Control.Applicative ((<$>))
import Control.Monad (when)
import Data.Bits (testBit)
import Data.IORef
import Data.List (delete)
import Data.List (delete, (\\))
import Data.Maybe (listToMaybe, maybeToList)
import qualified Data.Set as S
import Foreign (unsafePerformIO)
import System.IO (hPutStrLn, stderr)
-- $usage
--
@@ -195,7 +199,7 @@ import Foreign (unsafePerformIO)
-- hopefully you know where to find it.
-- | This is the method to enable an urgency hook. It uses the default
-- 'urgencyConfig' to control behavior. To change this, use 'withUrgencyHook'
-- 'urgencyConfig' to control behavior. To change this, use 'withUrgencyHookC'
-- instead.
withUrgencyHook :: (LayoutClass l Window, UrgencyHook h) =>
h -> XConfig l -> XConfig l
@@ -213,6 +217,15 @@ withUrgencyHookC hook urgConf conf = conf {
logHook = cleanupUrgents (suppressWhen urgConf) >> logHook conf
}
data Urgents = Urgents { fromUrgents :: [Window] } deriving (Read,Show,Typeable)
onUrgents :: ([Window] -> [Window]) -> Urgents -> Urgents
onUrgents f = Urgents . f . fromUrgents
instance ExtensionClass Urgents where
initialValue = Urgents []
extensionType = PersistentExtension
-- | Global configuration, applied to all types of 'UrgencyHook'. See
-- 'urgencyConfig' for the defaults.
data UrgencyConfig = UrgencyConfig
@@ -262,25 +275,18 @@ focusUrgent = withUrgents $ flip whenJust (windows . W.focusWindow) . listToMayb
clearUrgents :: X ()
clearUrgents = adjustUrgents (const []) >> adjustReminders (const [])
-- | Stores the global set of all urgent windows, across workspaces. Not exported -- use
-- 'readUrgents' or 'withUrgents' instead.
{-# NOINLINE urgents #-}
urgents :: IORef [Window]
urgents = unsafePerformIO (newIORef [])
-- (Hey, I don't like it any more than you do.)
-- | X action that returns a list of currently urgent windows. You might use
-- it, or 'withUrgents', in your custom logHook, to display the workspaces that
-- contain urgent windows.
readUrgents :: X [Window]
readUrgents = io $ readIORef urgents
readUrgents = XS.gets fromUrgents
-- | An HOF version of 'readUrgents', for those who prefer that sort of thing.
withUrgents :: ([Window] -> X a) -> X a
withUrgents f = readUrgents >>= f
adjustUrgents :: ([Window] -> [Window]) -> X ()
adjustUrgents f = io $ modifyIORef urgents f
adjustUrgents = XS.modify . onUrgents
type Interval = Rational
@@ -290,18 +296,19 @@ data Reminder = Reminder { timer :: TimerId
, window :: Window
, interval :: Interval
, remaining :: Maybe Int
} deriving Eq
} deriving (Show,Read,Eq,Typeable)
instance ExtensionClass [Reminder] where
initialValue = []
extensionType = PersistentExtension
-- | Stores the list of urgency reminders.
{-# NOINLINE reminders #-}
reminders :: IORef [Reminder]
reminders = unsafePerformIO (newIORef [])
readReminders :: X [Reminder]
readReminders = io $ readIORef reminders
readReminders = XS.get
adjustReminders :: ([Reminder] -> [Reminder]) -> X ()
adjustReminders f = io $ modifyIORef reminders f
adjustReminders = XS.modify
clearUrgency :: Window -> X ()
clearUrgency w = adjustUrgents (delete w) >> adjustReminders (filter $ (w /=) . window)
@@ -332,7 +339,7 @@ handleEvent wuh event =
callUrgencyHook wuh w
else
clearUrgency w
userCodeDef () =<< asks (logHook . config) -- call *after* IORef has been modified
userCodeDef () =<< asks (logHook . config)
DestroyWindowEvent {ev_window = w} ->
clearUrgency w
_ ->
@@ -369,7 +376,9 @@ shouldSuppress :: SuppressWhen -> Window -> X Bool
shouldSuppress sw w = elem w <$> suppressibleWindows sw
cleanupUrgents :: SuppressWhen -> X ()
cleanupUrgents sw = mapM_ clearUrgency =<< suppressibleWindows sw
cleanupUrgents sw = do
sw' <- suppressibleWindows sw
adjustUrgents (\\ sw') >> adjustReminders (filter $ ((`notElem` sw') . window))
suppressibleWindows :: SuppressWhen -> X [Window]
suppressibleWindows Visible = gets $ S.toList . mapped
@@ -382,9 +391,12 @@ suppressibleWindows Never = return []
-- | The class definition, and some pre-defined instances.
class (Read h, Show h) => UrgencyHook h where
class UrgencyHook h where
urgencyHook :: h -> Window -> X ()
instance UrgencyHook (Window -> X ()) where
urgencyHook = id
data NoUrgencyHook = NoUrgencyHook deriving (Read, Show)
instance UrgencyHook NoUrgencyHook where
@@ -412,11 +424,40 @@ instance UrgencyHook DzenUrgencyHook where
> withUrgencyHook FocusHook $ myconfig { ...
-}
focusHook :: Window -> X ()
focusHook = urgencyHook FocusHook
data FocusHook = FocusHook deriving (Read, Show)
instance UrgencyHook FocusHook where
urgencyHook _ _ = focusUrgent
-- | A hook that sets the border color of an urgent window. The color
-- will remain until the next time the window gains or loses focus, at
-- which point the standard border color from the XConfig will be applied.
-- You may want to use suppressWhen = Never with this:
--
-- > withUrgencyHookC BorderUrgencyHook { urgencyBorderColor = "#ff0000" } urgencyConfig { suppressWhen = Never } ...
--
-- (This should be @urgentBorderColor@ but that breaks "XMonad.Layout.Decoration".
-- @borderColor@ breaks anyone using 'XPConfig' from "XMonad.Prompt". We need to
-- think a bit more about namespacing issues, maybe.)
borderUrgencyHook :: String -> Window -> X ()
borderUrgencyHook = urgencyHook . BorderUrgencyHook
data BorderUrgencyHook = BorderUrgencyHook { urgencyBorderColor :: !String }
deriving (Read, Show)
instance UrgencyHook BorderUrgencyHook where
urgencyHook BorderUrgencyHook { urgencyBorderColor = cs } w =
withDisplay $ \dpy -> io $ do
c' <- initColor dpy cs
case c' of
Just c -> setWindowBorder dpy w c
_ -> hPutStrLn stderr $ concat ["Warning: bad urgentBorderColor "
,show cs
," in BorderUrgencyHook"
]
-- | Flashes when a window requests your attention and you can't see it.
-- Defaults to a duration of five seconds, and no extra args to dzen.
-- See 'DzenUrgencyHook'.
@@ -426,12 +467,16 @@ dzenUrgencyHook = DzenUrgencyHook { duration = seconds 5, args = [] }
-- | Spawn a commandline thing, appending the window id to the prefix string
-- you provide. (Make sure to add a space if you need it.) Do your crazy
-- xcompmgr thing.
spawnUrgencyHook :: String -> Window -> X ()
spawnUrgencyHook = urgencyHook . SpawnUrgencyHook
newtype SpawnUrgencyHook = SpawnUrgencyHook String deriving (Read, Show)
instance UrgencyHook SpawnUrgencyHook where
urgencyHook (SpawnUrgencyHook prefix) w = spawn $ prefix ++ show w
-- | For debugging purposes, really.
stdoutUrgencyHook :: Window -> X ()
stdoutUrgencyHook = urgencyHook StdoutUrgencyHook
data StdoutUrgencyHook = StdoutUrgencyHook deriving (Read, Show)
instance UrgencyHook StdoutUrgencyHook where

View File

@@ -1,3 +1,4 @@
{-# LANGUAGE ScopedTypeVariables #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Hooks.XPropManage
@@ -17,14 +18,13 @@ module XMonad.Hooks.XPropManage (
xPropManageHook, XPropMatch, pmX, pmP
) where
import Control.Exception as E
import Data.Char (chr)
import Data.List (concat)
import Data.Monoid (mconcat, Endo(..))
import Control.Monad.Trans (lift)
import XMonad
import XMonad.ManageHook ((-->))
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
@@ -75,7 +75,7 @@ xPropManageHook tms = mconcat $ map propToHook tms
getProp :: Display -> Window -> Atom -> X ([String])
getProp d w p = do
prop <- io $ catch (getTextProperty d w p >>= wcTextPropertyToTextList d) (\_ -> return [[]])
prop <- io $ E.catch (getTextProperty d w p >>= wcTextPropertyToTextList d) (\(_ :: IOException) -> return [[]])
let filt q | q == wM_COMMAND = concat . map splitAtNull
| otherwise = id
return (filt p prop)

View File

@@ -42,7 +42,7 @@ data Accordion a = Accordion deriving ( Read, Show )
instance LayoutClass Accordion Window where
pureLayout _ sc ws = zip ups tops ++ [(W.focus ws, mainPane)] ++ zip dns bottoms
where
ups = W.up ws
ups = reverse $ W.up ws
dns = W.down ws
(top, allButTop) = splitVerticallyBy (1%8 :: Ratio Int) sc
(center, bottom) = splitVerticallyBy (6%7 :: Ratio Int) allButTop

View File

@@ -18,7 +18,7 @@
module XMonad.Layout.AutoMaster (
-- * Usage
-- $usage
autoMaster
autoMaster, AutoMaster
) where
import Control.Monad
@@ -48,7 +48,7 @@ import XMonad.Layout.LayoutModifier
data AutoMaster a = AutoMaster Int Float Float
deriving (Read,Show)
instance LayoutModifier AutoMaster Window where
instance (Eq w) => LayoutModifier AutoMaster w where
modifyLayout (AutoMaster k bias _) = autoLayout k bias
pureMess = autoMess
@@ -61,12 +61,12 @@ autoMess (AutoMaster k bias delta) m = msum [fmap resize (fromMessage m),
resize Shrink = AutoMaster k (max (-0.4) $ bias-delta) delta
-- | Main layout function
autoLayout :: (LayoutClass l Window) =>
autoLayout :: (Eq w, LayoutClass l w) =>
Int ->
Float ->
W.Workspace WorkspaceId (l Window) Window
W.Workspace WorkspaceId (l w) w
-> Rectangle
-> X ([(Window, Rectangle)], Maybe (l Window))
-> X ([(w, Rectangle)], Maybe (l w))
autoLayout k bias wksp rect = do
let stack = W.stack wksp
let ws = W.integrate' stack

View File

@@ -12,8 +12,10 @@
-- This layout modifier will allow to resize windows by dragging their
-- borders with the mouse. However, it only works in layouts or modified
-- layouts that react to the 'SetGeometry' message.
-- "XMonad.Layout.WindowArranger" can be used to create such a setup.
-- BorderResize is probably most useful in floating layouts.
-- "XMonad.Layout.WindowArranger" can be used to create such a setup,
-- but it is probably must useful in a floating layout such as
-- "XMonad.Layout.PositionStoreFloat" with which it has been mainly tested.
-- See the documentation of PositionStoreFloat for a typical usage example.
--
-----------------------------------------------------------------------------
@@ -22,15 +24,15 @@ module XMonad.Layout.BorderResize
-- $usage
borderResize
, BorderResize (..)
, RectWithBorders, BorderInfo,
) 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((<$>))
import Control.Monad(when)
import qualified Data.Map as M
-- $usage
-- You can use this module with the following in your
@@ -41,89 +43,139 @@ import Control.Applicative((<$>))
-- > main = xmonad defaultConfig { layoutHook = myLayout }
--
data BorderInfo = RightSideBorder Window Rectangle
| LeftSideBorder Window Rectangle
| TopSideBorder Window Rectangle
| BottomSideBorder Window Rectangle
type BorderBlueprint = (Rectangle, Glyph, BorderType)
data BorderType = RightSideBorder
| LeftSideBorder
| TopSideBorder
| BottomSideBorder
deriving (Show, Read, Eq)
type BorderWithRect = (Rectangle, Rectangle, Glyph, BorderInfo)
type BorderWithWin = (Window, BorderInfo)
data BorderInfo = BI { bWin :: Window,
bRect :: Rectangle,
bType :: BorderType
} deriving (Show, Read)
data BorderResize a = BR [BorderWithWin] deriving (Show, Read)
type RectWithBorders = (Rectangle, [BorderInfo])
data BorderResize a = BR (M.Map Window RectWithBorders) 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
brBorderSize = 2
borderResize :: l a -> ModifiedLayout BorderResize l a
borderResize = ModifiedLayout (BR [])
borderResize = ModifiedLayout (BR M.empty)
instance LayoutModifier BorderResize Window where
redoLayout _ _ Nothing wrs = return (wrs, Nothing)
redoLayout (BR borders) _ _ wrs = do
let preparedBorders = for wrs $ \wr -> (wr, prepareBorders wr)
mapM_ deleteBorder borders
newBorders <- forM preparedBorders $ \(wr, (b1, b2, b3, b4)) ->
first (++[wr]) . unzip <$> mapM createBorder [b1,b2,b3,b4]
let wrs' = concat $ map fst newBorders
newBordersSerialized = concat $ map snd newBorders
return (wrs', Just $ BR newBordersSerialized)
redoLayout (BR wrsLastTime) _ _ wrs = do
let correctOrder = map fst wrs
wrsCurrent = M.fromList wrs
wrsGone = M.difference wrsLastTime wrsCurrent
wrsAppeared = M.difference wrsCurrent wrsLastTime
wrsStillThere = M.intersectionWith testIfUnchanged wrsLastTime wrsCurrent
handleGone wrsGone
wrsCreated <- handleAppeared wrsAppeared
let wrsChanged = handleStillThere wrsStillThere
wrsThisTime = M.union wrsChanged wrsCreated
return (compileWrs wrsThisTime correctOrder, Just $ BR wrsThisTime)
-- What we return is the original wrs with the new border
-- windows inserted at the correct positions - this way, the core
-- will restack the borders correctly.
-- We also return information about our borders, so that we
-- can handle events that they receive and destroy them when
-- they are no longer needed.
where
testIfUnchanged entry@(rLastTime, _) rCurrent =
if rLastTime == rCurrent
then (Nothing, entry)
else (Just rCurrent, entry)
handleMess (BR borders) m
| Just e <- fromMessage m :: Maybe Event = handleResize borders e >> return Nothing
handleMess (BR wrsLastTime) m
| Just e <- fromMessage m :: Maybe Event =
handleResize (createBorderLookupTable wrsLastTime) e >> return Nothing
| Just _ <- fromMessage m :: Maybe LayoutMessages =
mapM_ deleteBorder borders >> return (Just $ BR [])
handleGone wrsLastTime >> return (Just $ BR M.empty)
handleMess _ _ = return Nothing
prepareBorders :: (Window, Rectangle) -> (BorderWithRect, BorderWithRect, BorderWithRect, BorderWithRect)
prepareBorders (w, r@(Rectangle x y wh ht)) =
((r, (Rectangle (x + fi wh - brBorderOffset) y brBorderSize ht) , brCursorRightSide , RightSideBorder w r),
(r, (Rectangle (x - brBorderOffset) y brBorderSize ht) , brCursorLeftSide , LeftSideBorder w r),
(r, (Rectangle x (y - brBorderOffset) wh brBorderSize) , brCursorTopSide , TopSideBorder w r),
(r, (Rectangle x (y + fi ht - brBorderOffset) wh brBorderSize) , brCursorBottomSide , BottomSideBorder w r)
)
compileWrs :: M.Map Window RectWithBorders -> [Window] -> [(Window, Rectangle)]
compileWrs wrsThisTime correctOrder = let wrs = reorder (M.toList wrsThisTime) correctOrder
in concat $ map compileWr wrs
handleResize :: [BorderWithWin] -> Event -> X ()
compileWr :: (Window, RectWithBorders) -> [(Window, Rectangle)]
compileWr (w, (r, borderInfos)) =
let borderWrs = for borderInfos $ \bi -> (bWin bi, bRect bi)
in borderWrs ++ [(w, r)]
handleGone :: M.Map Window RectWithBorders -> X ()
handleGone wrsGone = mapM_ deleteWindow borderWins
where
borderWins = map bWin . concat . map snd . M.elems $ wrsGone
handleAppeared :: M.Map Window Rectangle -> X (M.Map Window RectWithBorders)
handleAppeared wrsAppeared = do
let wrs = M.toList wrsAppeared
wrsCreated <- mapM handleSingleAppeared wrs
return $ M.fromList wrsCreated
handleSingleAppeared :: (Window, Rectangle) -> X (Window, RectWithBorders)
handleSingleAppeared (w, r) = do
let borderBlueprints = prepareBorders r
borderInfos <- mapM createBorder borderBlueprints
return (w, (r, borderInfos))
handleStillThere :: M.Map Window (Maybe Rectangle, RectWithBorders) -> M.Map Window RectWithBorders
handleStillThere wrsStillThere = M.map handleSingleStillThere wrsStillThere
handleSingleStillThere :: (Maybe Rectangle, RectWithBorders) -> RectWithBorders
handleSingleStillThere (Nothing, entry) = entry
handleSingleStillThere (Just rCurrent, (_, borderInfos)) = (rCurrent, updatedBorderInfos)
where
changedBorderBlueprints = prepareBorders rCurrent
updatedBorderInfos = map updateBorderInfo . zip borderInfos $ changedBorderBlueprints
-- assuming that the four borders are always in the same order
updateBorderInfo :: (BorderInfo, BorderBlueprint) -> BorderInfo
updateBorderInfo (borderInfo, (r, _, _)) = borderInfo { bRect = r }
createBorderLookupTable :: M.Map Window RectWithBorders -> [(Window, (BorderType, Window, Rectangle))]
createBorderLookupTable wrsLastTime = concat $ map processSingleEntry $ M.toList wrsLastTime
where
processSingleEntry :: (Window, RectWithBorders) -> [(Window, (BorderType, Window, Rectangle))]
processSingleEntry (w, (r, borderInfos)) = for borderInfos $ \bi -> (bWin bi, (bType bi, w, r))
prepareBorders :: Rectangle -> [BorderBlueprint]
prepareBorders (Rectangle x y wh ht) =
[((Rectangle (x + fi wh - fi brBorderSize) y brBorderSize ht), xC_right_side , RightSideBorder),
((Rectangle x y brBorderSize ht) , xC_left_side , LeftSideBorder),
((Rectangle x y wh brBorderSize) , xC_top_side , TopSideBorder),
((Rectangle x (y + fi ht - fi brBorderSize) wh brBorderSize), xC_bottom_side, BottomSideBorder)
]
handleResize :: [(Window, (BorderType, Window, Rectangle))] -> Event -> X ()
handleResize borders ButtonEvent { ev_window = ew, ev_event_type = et }
| et == buttonPress, Just edge <- lookup ew borders =
case edge of
RightSideBorder hostWin (Rectangle hx hy _ hht) ->
(RightSideBorder, hostWin, (Rectangle hx hy _ hht)) ->
mouseDrag (\x _ -> do
let nwh = max 1 $ fi (x - hx)
rect = Rectangle hx hy nwh hht
focus hostWin
when (x - hx > 0) $ sendMessage (SetGeometry rect)) (focus hostWin)
LeftSideBorder hostWin (Rectangle hx hy hwh hht) ->
(LeftSideBorder, hostWin, (Rectangle hx hy hwh hht)) ->
mouseDrag (\x _ -> do
let nx = max 0 $ min (hx + fi hwh) $ x
nwh = max 1 $ hwh + fi (hx - x)
rect = Rectangle nx hy nwh hht
focus hostWin
when (x < hx + fi hwh) $ sendMessage (SetGeometry rect)) (focus hostWin)
TopSideBorder hostWin (Rectangle hx hy hwh hht) ->
(TopSideBorder, hostWin, (Rectangle hx hy hwh hht)) ->
mouseDrag (\_ y -> do
let ny = max 0 $ min (hy + fi hht) $ y
nht = max 1 $ hht + fi (hy - y)
rect = Rectangle hx ny hwh nht
focus hostWin
when (y < hy + fi hht) $ sendMessage (SetGeometry rect)) (focus hostWin)
BottomSideBorder hostWin (Rectangle hx hy hwh _) ->
(BottomSideBorder, hostWin, (Rectangle hx hy hwh _)) ->
mouseDrag (\_ y -> do
let nht = max 1 $ fi (y - hy)
rect = Rectangle hx hy hwh nht
@@ -131,13 +183,10 @@ handleResize borders ButtonEvent { ev_window = ew, ev_event_type = et }
when (y - hy > 0) $ sendMessage (SetGeometry rect)) (focus hostWin)
handleResize _ _ = return ()
createBorder :: BorderWithRect -> X (((Window, Rectangle), BorderWithWin))
createBorder (_, borderRect, borderCursor, borderInfo) = do
createBorder :: BorderBlueprint -> X (BorderInfo)
createBorder (borderRect, borderCursor, borderType) = do
borderWin <- createInputWindow borderCursor borderRect
return ((borderWin, borderRect), (borderWin, borderInfo))
deleteBorder :: BorderWithWin -> X ()
deleteBorder (borderWin, _) = deleteWindow borderWin
return BI { bWin = borderWin, bRect = borderRect, bType = borderType }
createInputWindow :: Glyph -> Rectangle -> X Window
createInputWindow cursorGlyph r = withDisplay $ \d -> do
@@ -162,3 +211,13 @@ mkInputWindow d (Rectangle x y w h) = do
for :: [a] -> (a -> b) -> [b]
for = flip map
reorder :: (Eq a) => [(a, b)] -> [a] -> [(a, b)]
reorder wrs order =
let ordered = concat $ map (pickElem wrs) order
rest = filter (\(w, _) -> not (w `elem` order)) wrs
in ordered ++ rest
where
pickElem list e = case (lookup e list) of
Just result -> [(e, result)]
Nothing -> []

View File

@@ -6,7 +6,7 @@
-- Copyright : (c) 2008 David Roundy <droundy@darcs.net>
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : none
-- Maintainer : Adam Vogt <vogt.adam@gmail.com>
-- Stability : unstable
-- Portability : unportable
--
@@ -24,6 +24,10 @@ module XMonad.Layout.BoringWindows (
UpdateBoring(UpdateBoring),
BoringMessage(Replace,Merge),
BoringWindows()
-- * Tips
-- ** variant of 'Full'
-- $simplest
) where
import XMonad.Layout.LayoutModifier(ModifiedLayout(..),
@@ -31,10 +35,8 @@ import XMonad.Layout.LayoutModifier(ModifiedLayout(..),
import XMonad(Typeable, LayoutClass, Message, X, fromMessage,
sendMessage, windows, withFocused, Window)
import Control.Applicative((<$>))
import Control.Monad(Monad(return, (>>)))
import Data.List((\\), union)
import Data.Maybe(Maybe(..), maybe, fromMaybe, listToMaybe,
maybeToList)
import Data.Maybe(fromMaybe, listToMaybe, maybeToList)
import qualified Data.Map as M
import qualified XMonad.StackSet as W
@@ -136,3 +138,12 @@ instance LayoutModifier BoringWindows Window where
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
{- $simplest
An alternative to 'Full' is "XMonad.Layout.Simplest". Less windows are
ignored by 'focusUp' and 'focusDown'. This may be helpful when you want windows
to be uninteresting by some other layout modifier (ex.
"XMonad.Layout.Minimize")
-}

View File

@@ -0,0 +1,56 @@
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}
----------------------------------------------------------------------------
-- |
-- Module : XMonad.Layout.ButtonDecoration
-- Copyright : (c) Jan Vornberger 2009
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : jan.vornberger@informatik.uni-oldenburg.de
-- Stability : unstable
-- Portability : not portable
--
-- A decoration that includes small buttons on both ends which invoke
-- various actions when clicked on: Show a window menu (see
-- "XMonad.Actions.WindowMenu"), minimize, maximize or close the window.
--
-- Note: For maximizing and minimizing to actually work, you will need
-- to integrate "XMonad.Layout.Maximize" and "XMonad.Layout.Minimize" into your
-- setup. See the documentation of those modules for more information.
--
-----------------------------------------------------------------------------
module XMonad.Layout.ButtonDecoration
( -- * Usage:
-- $usage
buttonDeco,
ButtonDecoration,
) where
import XMonad
import XMonad.Layout.Decoration
import XMonad.Layout.DecorationAddons
-- $usage
-- You can use this module with the following in your
-- @~\/.xmonad\/xmonad.hs@:
--
-- > import XMonad.Layout.DecorationAddons
-- > import XMonad.Layout.ButtonDecoration
--
-- Then edit your @layoutHook@ by adding the ButtonDecoration to
-- your layout:
--
-- > myL = buttonDeco shrinkText defaultThemeWithButtons (layoutHook defaultConfig)
-- > main = xmonad defaultConfig { layoutHook = myL }
--
buttonDeco :: (Eq a, Shrinker s) => s -> Theme
-> l a -> ModifiedLayout (Decoration ButtonDecoration s) l a
buttonDeco s c = decoration s c $ NFD True
data ButtonDecoration a = NFD Bool deriving (Show, Read)
instance Eq a => DecorationStyle ButtonDecoration a where
describeDeco _ = "ButtonDeco"
decorationCatchClicksHook _ mainw dFL dFR = titleBarButtonHandler mainw dFL dFR
decorationAfterDraggingHook _ (mainw, _) decoWin = focus mainw >> handleScreenCrossing mainw decoWin >> return ()

View File

@@ -21,7 +21,8 @@ module XMonad.Layout.CenteredMaster (
-- $usage
centerMaster,
topRightMaster
topRightMaster,
CenteredMaster, TopRightMaster,
) where
import XMonad

View File

@@ -61,9 +61,9 @@ columnLayout (Column q) rect stack = zip ws rects
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
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

@@ -27,7 +27,7 @@ import Data.List ( delete, intersect, (\\) )
import Data.Maybe ( isJust )
import Control.Monad
import XMonad hiding (focus)
import XMonad.StackSet ( integrate, Workspace (..), Stack(..) )
import XMonad.StackSet ( Workspace (..), Stack(..) )
import XMonad.Layout.WindowNavigation
import XMonad.Util.WindowProperties
import qualified XMonad.StackSet as W

View File

@@ -2,7 +2,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Layout.Decoration
-- Copyright : (c) 2007 Andrea Rossato
-- Copyright : (c) 2007 Andrea Rossato, 2009 Jan Vornberger
-- License : BSD-style (see xmonad/LICENSE)
--
-- Maintainer : andrea.rossato@unibz.it
@@ -27,11 +27,13 @@ module XMonad.Layout.Decoration
, isInStack, isVisible, isInvisible, isWithin, fi
, findWindowByDecoration
, module XMonad.Layout.LayoutModifier
, DecorationState, OrigWin
) where
import Control.Monad (when)
import Data.Maybe
import Data.List
import Foreign.C.Types(CInt)
import XMonad
import qualified XMonad.StackSet as W
@@ -42,6 +44,7 @@ import XMonad.Util.NamedWindows (getName)
import XMonad.Util.Invisible
import XMonad.Util.XUtils
import XMonad.Util.Font
import XMonad.Util.Image
-- $usage
-- This module is intended for layout developers, who want to decorate
@@ -65,18 +68,22 @@ decoration s t ds = ModifiedLayout (Decoration (I Nothing) s t ds)
--
-- For a collection of 'Theme's see "XMonad.Util.Themes"
data Theme =
Theme { activeColor :: String -- ^ Color of the active window
, inactiveColor :: String -- ^ Color of the inactive window
, urgentColor :: String -- ^ Color of the urgent window
, activeBorderColor :: String -- ^ Color of the border of the active window
, inactiveBorderColor :: String -- ^ Color of the border of the inactive window
, urgentBorderColor :: String -- ^ Color of the border of the urgent window
, activeTextColor :: String -- ^ Color of the text of the active window
, inactiveTextColor :: String -- ^ Color of the text of the inactive window
, urgentTextColor :: String -- ^ Color of the text of the urgent window
, fontName :: String -- ^ Font name
, decoWidth :: Dimension -- ^ Maximum width of the decorations (if supported by the 'DecorationStyle')
, decoHeight :: Dimension -- ^ Height of the decorations
Theme { activeColor :: String -- ^ Color of the active window
, inactiveColor :: String -- ^ Color of the inactive window
, urgentColor :: String -- ^ Color of the urgent window
, activeBorderColor :: String -- ^ Color of the border of the active window
, inactiveBorderColor :: String -- ^ Color of the border of the inactive window
, urgentBorderColor :: String -- ^ Color of the border of the urgent window
, activeTextColor :: String -- ^ Color of the text of the active window
, inactiveTextColor :: String -- ^ Color of the text of the inactive window
, urgentTextColor :: String -- ^ Color of the text of the urgent window
, fontName :: String -- ^ Font name
, decoWidth :: Dimension -- ^ Maximum width of the decorations (if supported by the 'DecorationStyle')
, decoHeight :: Dimension -- ^ Height of the decorations
, windowTitleAddons :: [(String, Align)] -- ^ Extra text to appear in a window's title bar.
-- Refer to for a use "XMonad.Layout.ImageButtonDecoration"
, windowTitleIcons :: [([[Bool]], Placement)] -- ^ Extra icons to appear in a window's title bar.
-- Inner @[Bool]@ is a row in a icon bitmap.
} deriving (Show, Read)
-- | The default xmonad 'Theme'.
@@ -94,6 +101,8 @@ defaultTheme =
, fontName = "-misc-fixed-*-*-*-*-10-*-*-*-*-*-*-*"
, decoWidth = 200
, decoHeight = 20
, windowTitleAddons = []
, windowTitleIcons = []
}
-- | A 'Decoration' layout modifier will handle 'SetTheme', a message
@@ -136,30 +145,36 @@ class (Read (ds a), Show (ds a), Eq a) => DecorationStyle ds a where
shrink :: ds a -> Rectangle -> Rectangle -> Rectangle
shrink _ (Rectangle _ _ _ dh) (Rectangle x y w h) = Rectangle x (y + fi dh) w (h - dh)
-- | The decoration event hook, where the
-- 'decorationMouseFocusHook' and 'decorationMouseDragHook' are
-- called. If you reimplement it those methods will not be
-- called.
-- | The decoration event hook
decorationEventHook :: ds a -> DecorationState -> Event -> X ()
decorationEventHook ds s e = do decorationMouseFocusHook ds s e
decorationMouseDragHook ds s e
decorationEventHook ds s e = handleMouseFocusDrag ds s e
-- | This method is called when the user clicks the pointer over
-- the decoration.
decorationMouseFocusHook :: ds a -> DecorationState -> Event -> X ()
decorationMouseFocusHook _ s e = handleMouseFocusDrag False s e
-- | A hook that can be used to catch the cases when the user
-- clicks on the decoration. If you return True here, the click event
-- will be considered as dealt with and no further processing will take place.
decorationCatchClicksHook :: ds a
-> Window
-> Int -- ^ distance from the left where the click happened on the decoration
-> Int -- ^ distance from the right where the click happened on the decoration
-> X Bool
decorationCatchClicksHook _ _ _ _ = return False
-- | This method is called when the user starts grabbing the
-- decoration.
decorationMouseDragHook :: ds a -> DecorationState -> Event -> X ()
decorationMouseDragHook _ s e = handleMouseFocusDrag True s e
-- | This hook is called while a window is dragged using the decoration.
-- The hook can be overwritten if a different way of handling the dragging
-- is required.
decorationWhileDraggingHook :: ds a -> CInt -> CInt -> (Window, Rectangle) -> Position -> Position -> X ()
decorationWhileDraggingHook _ ex ey (mainw, r) x y = handleDraggingInProgress ex ey (mainw, r) x y
-- | This hoook is called after a window has been dragged using the decoration.
decorationAfterDraggingHook :: ds a -> (Window, Rectangle) -> Window -> X ()
decorationAfterDraggingHook _ds (mainw, _r) _decoWin = focus mainw
-- | The pure version of the main method, 'decorate'.
pureDecoration :: ds a -> Dimension -> Dimension -> Rectangle
-> W.Stack a -> [(a,Rectangle)] -> (a,Rectangle) -> Maybe Rectangle
pureDecoration _ _ ht _ s _ (w,Rectangle x y wh _) = if isInStack s w
then Just $ Rectangle x y wh ht
else Nothing
pureDecoration _ _ ht _ s _ (w,Rectangle x y wh ht') = if isInStack s w && (ht < ht')
then Just $ Rectangle x y wh ht
else Nothing
-- | Given the theme's decoration width and height, the screen
-- rectangle, the windows stack, the list of windows and
@@ -283,22 +298,30 @@ handleEvent _ _ _ _ = return ()
-- | Mouse focus and mouse drag are handled by the same function, this
-- way we can start dragging unfocused windows too.
handleMouseFocusDrag :: Bool -> DecorationState -> Event -> X ()
handleMouseFocusDrag b (DS dwrs _) ButtonEvent { ev_window = ew
, ev_event_type = et
, ev_x_root = ex
, ev_y_root = ey }
handleMouseFocusDrag :: (DecorationStyle ds a) => ds a -> DecorationState -> Event -> X ()
handleMouseFocusDrag ds (DS dwrs _) ButtonEvent { ev_window = ew
, ev_event_type = et
, ev_x_root = ex
, ev_y_root = ey }
| et == buttonPress
, Just ((mainw,r),_) <- lookFor ew dwrs = do
focus mainw
when b $ mouseDrag (\x y -> do
let rect = Rectangle (x - (fi ex - rect_x r))
(y - (fi ey - rect_y r))
(rect_width r)
(rect_height r)
sendMessage (SetGeometry rect)) (return ())
, Just ((mainw,r), (_, decoRectM)) <- lookFor ew dwrs = do
let Just (Rectangle dx _ dwh _) = decoRectM
distFromLeft = ex - fi dx
distFromRight = fi dwh - (ex - fi dx)
dealtWith <- decorationCatchClicksHook ds mainw (fi distFromLeft) (fi distFromRight)
when (not dealtWith) $ do
mouseDrag (\x y -> focus mainw >> decorationWhileDraggingHook ds ex ey (mainw, r) x y)
(decorationAfterDraggingHook ds (mainw, r) ew)
handleMouseFocusDrag _ _ _ = return ()
handleDraggingInProgress :: CInt -> CInt -> (Window, Rectangle) -> Position -> Position -> X ()
handleDraggingInProgress ex ey (_, r) x y = do
let rect = Rectangle (x - (fi ex - rect_x r))
(y - (fi ey - rect_y r))
(rect_width r)
(rect_height r)
sendMessage $ SetGeometry rect
-- | Given a window and the state, if a matching decoration is in the
-- state return it with its ('Maybe') 'Rectangle'.
lookFor :: Window -> [(OrigWin,DecoWin)] -> Maybe (OrigWin,(Window,Maybe Rectangle))
@@ -345,7 +368,7 @@ createDecoWindow t r = let mask = Just (exposureMask .|. buttonPressMask) in
createNewWindow r mask (inactiveColor t) True
showDecos :: [DecoWin] -> X ()
showDecos = showWindows . catMaybes . map fst
showDecos = showWindows . catMaybes . map fst . filter (isJust . snd)
hideDecos :: [DecoWin] -> X ()
hideDecos = hideWindows . catMaybes . map fst
@@ -374,7 +397,11 @@ updateDeco sh t fs ((w,_),(Just dw,Just (Rectangle _ _ wh ht))) = do
let s = shrinkIt sh
name <- shrinkWhile s (\n -> do size <- io $ textWidthXMF dpy fs n
return $ size > fromIntegral wh - fromIntegral (ht `div` 2)) (show nw)
paintAndWrite dw fs wh ht 1 bc borderc tc bc AlignCenter name
let als = AlignCenter : map snd (windowTitleAddons t)
strs = name : map fst (windowTitleAddons t)
i_als = map snd (windowTitleIcons t)
icons = map fst (windowTitleIcons t)
paintTextAndIcons dw fs wh ht 1 bc borderc tc bc als strs i_als icons
updateDeco _ _ _ (_,(Just w,Nothing)) = hideWindow w
updateDeco _ _ _ _ = return ()

View File

@@ -0,0 +1,123 @@
----------------------------------------------------------------------------
-- |
-- Module : XMonad.Layout.DecorationAddons
-- Copyright : (c) Jan Vornberger 2009
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : jan.vornberger@informatik.uni-oldenburg.de
-- Stability : unstable
-- Portability : not portable
--
-- Various stuff that can be added to the decoration. Most of it
-- is intended to be used by other modules. See
-- "XMonad.Layout.ButtonDecoration" for a module that makes use of this.
--
-----------------------------------------------------------------------------
module XMonad.Layout.DecorationAddons (
titleBarButtonHandler
,defaultThemeWithButtons
,handleScreenCrossing
) where
import XMonad
import qualified XMonad.StackSet as W
import XMonad.Layout.Decoration
import XMonad.Actions.WindowMenu
import XMonad.Layout.Minimize
import XMonad.Layout.Maximize
import XMonad.Hooks.ManageDocks
import XMonad.Util.Font
import XMonad.Util.PositionStore
import Control.Applicative((<$>))
import Data.Maybe
import qualified Data.Set as S
minimizeButtonOffset :: Int
minimizeButtonOffset = 48
maximizeButtonOffset :: Int
maximizeButtonOffset = 25
closeButtonOffset :: Int
closeButtonOffset = 10
buttonSize :: Int
buttonSize = 10
-- | A function intended to be plugged into the 'decorationCatchClicksHook' of a decoration.
-- It will intercept clicks on the buttons of the decoration and invoke the associated action.
-- To actually see the buttons, you will need to use a theme that includes them.
-- See 'defaultThemeWithButtons' below.
titleBarButtonHandler :: Window -> Int -> Int -> X Bool
titleBarButtonHandler mainw distFromLeft distFromRight = do
let action = if (fi distFromLeft <= 3 * buttonSize)
then focus mainw >> windowMenu >> return True
else if (fi distFromRight >= closeButtonOffset &&
fi distFromRight <= closeButtonOffset + buttonSize)
then focus mainw >> kill >> return True
else if (fi distFromRight >= maximizeButtonOffset &&
fi distFromRight <= maximizeButtonOffset + (2 * buttonSize))
then focus mainw >> sendMessage (maximizeRestore mainw) >> return True
else if (fi distFromRight >= minimizeButtonOffset &&
fi distFromRight <= minimizeButtonOffset + buttonSize)
then focus mainw >> minimizeWindow mainw >> return True
else return False
action
-- | Intended to be used together with 'titleBarButtonHandler'. See above.
defaultThemeWithButtons :: Theme
defaultThemeWithButtons = defaultTheme {
windowTitleAddons = [ (" (M)", AlignLeft)
, ("_" , AlignRightOffset minimizeButtonOffset)
, ("[]" , AlignRightOffset maximizeButtonOffset)
, ("X" , AlignRightOffset closeButtonOffset)
]
}
-- | A function intended to be plugged into the 'decorationAfterDraggingHook' of a decoration.
-- It will check if the window has been dragged onto another screen and shift it there.
-- The PositionStore is also updated accordingly, as this is designed to be used together
-- with "XMonad.Layout.PositionStoreFloat".
handleScreenCrossing :: Window -> Window -> X Bool
handleScreenCrossing w decoWin = withDisplay $ \d -> do
root <- asks theRoot
(_, _, _, px, py, _, _, _) <- io $ queryPointer d root
ws <- gets windowset
sc <- fromMaybe (W.current ws) <$> pointScreen (fi px) (fi py)
maybeWksp <- screenWorkspace $ W.screen sc
let targetWksp = maybeWksp >>= \wksp ->
W.findTag w ws >>= \currentWksp ->
if (currentWksp /= wksp)
then Just wksp
else Nothing
case targetWksp of
Just wksp -> do
-- find out window under cursor on target workspace
-- apparently we have to switch to the workspace first
-- to make this work, which unforunately introduces some flicker
windows $ \ws' -> W.view wksp ws'
(_, _, selWin, _, _, _, _, _) <- io $ queryPointer d root
-- adjust PositionStore
let oldScreenRect = screenRect . W.screenDetail $ W.current ws
newScreenRect = screenRect . W.screenDetail $ sc
{-- somewhat ugly hack to get proper ScreenRect,
creates unwanted inter-dependencies
TODO: get ScreenRects in a proper way --}
oldScreenRect' <- fmap ($ oldScreenRect) (calcGap $ S.fromList [minBound .. maxBound])
newScreenRect' <- fmap ($ newScreenRect) (calcGap $ S.fromList [minBound .. maxBound])
wa <- io $ getWindowAttributes d decoWin
modifyPosStore (\ps ->
posStoreMove ps w (fi $ wa_x wa) (fi $ wa_y wa)
oldScreenRect' newScreenRect')
-- set focus correctly so the window will be inserted
-- at the correct position on the target workspace
-- and then shift the window
windows $ \ws' -> W.shiftWin wksp w . W.focusWindow selWin $ ws'
-- return True to signal that screen crossing has taken place
return True
Nothing -> return False

View File

@@ -94,7 +94,6 @@ import XMonad.Layout.TabBarDecoration
import XMonad.Layout.Accordion
import XMonad.Layout.Circle
import XMonad.Layout.ResizeScreen
import XMonad.Layout.WindowArranger
import XMonad.Layout.SimpleFloat

View File

@@ -21,7 +21,6 @@ module XMonad.Layout.Dishes (
Dishes (..)
) where
import Data.List
import XMonad
import XMonad.StackSet (integrate)
import Control.Monad (ap)

View File

@@ -0,0 +1,49 @@
{-# LANGUAGE DeriveDataTypeable, TypeSynonymInstances, MultiParamTypeClasses, FlexibleContexts #-}
----------------------------------------------------------------------------
-- |
-- Module : XMonad.Layout.DraggingVisualizer
-- Copyright : (c) Jan Vornberger 2009
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : jan.vornberger@informatik.uni-oldenburg.de
-- Stability : unstable
-- Portability : not portable
--
-- A helper module to visualize the process of dragging a window by
-- making it follow the mouse cursor. See "XMonad.Layout.WindowSwitcherDecoration"
-- for a module that makes use of this.
--
-----------------------------------------------------------------------------
module XMonad.Layout.DraggingVisualizer
( draggingVisualizer,
DraggingVisualizerMsg (..),
DraggingVisualizer,
) where
import XMonad
import XMonad.Layout.LayoutModifier
data DraggingVisualizer a = DraggingVisualizer (Maybe (Window, Rectangle)) deriving ( Read, Show )
draggingVisualizer :: LayoutClass l Window => l Window -> ModifiedLayout DraggingVisualizer l Window
draggingVisualizer = ModifiedLayout $ DraggingVisualizer Nothing
data DraggingVisualizerMsg = DraggingWindow Window Rectangle
| DraggingStopped
deriving ( Typeable, Eq )
instance Message DraggingVisualizerMsg
instance LayoutModifier DraggingVisualizer Window where
modifierDescription (DraggingVisualizer _) = "DraggingVisualizer"
pureModifier (DraggingVisualizer (Just dragged@(draggedWin, _))) _ _ wrs =
if draggedWin `elem` (map fst wrs)
then (dragged : rest, Nothing)
else (wrs, Just $ DraggingVisualizer Nothing)
where
rest = filter (\(w, _) -> w /= draggedWin) wrs
pureModifier _ _ _ wrs = (wrs, Nothing)
pureMess (DraggingVisualizer _) m = case fromMessage m of
Just (DraggingWindow w rect) -> Just $ DraggingVisualizer $ Just (w, rect)
Just (DraggingStopped) -> Just $ DraggingVisualizer Nothing
_ -> Nothing

131
XMonad/Layout/Drawer.hs Normal file
View File

@@ -0,0 +1,131 @@
{-# LANGUAGE MultiParamTypeClasses, TypeSynonymInstances, FlexibleInstances, FlexibleContexts #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Layout.Drawer
-- Copyright : (c) 2009 Max Rabkin
-- License : BSD-style (see xmonad/LICENSE)
--
-- Maintainer : max.rabkin@gmail.com
-- Stability : unstable
-- Portability : unportable
--
-- A layout modifier that puts some windows in a "drawer" which retracts and
-- expands depending on whether any window in it has focus.
--
-- Useful for music players, tool palettes, etc.
--
-----------------------------------------------------------------------------
module XMonad.Layout.Drawer
( -- * Usage
-- $usage
-- * Drawers
simpleDrawer
, drawer
-- * Placing drawers
-- The drawer can be placed on any side of the screen with these functions
, onLeft, onTop, onRight, onBottom
, module XMonad.Util.WindowProperties
, Drawer, Reflected
) where
import XMonad
import XMonad.Layout.LayoutModifier
import XMonad.Util.WindowProperties
import XMonad.StackSet as S
import XMonad.Layout.Reflect
-- $usage
-- To use this module, add the following import to @~\/.xmonad\/xmonad.hs@:
--
-- > import XMonad.Layout.Drawer
--
-- > myLayout = drawer `onTop` (Tall 1 0.03 0.5) ||| Full ||| RandomOtherLayout...
-- > where
-- > drawer = simpleDrawer 0.01 0.3 (ClassName "Rhythmbox" `Or` ClassName "Xchat")
-- >
-- > main = xmonad defaultConfig { layoutHook = myLayout }
--
-- This will place the Rhythmbox and Xchat windows in at the top of the screen
-- only when using the 'Tall' layout. See "XMonad.Util.WindowProperties" for
-- more information on selecting windows.
data Drawer l a = Drawer Rational Rational Property (l a)
deriving (Read, Show)
-- | filter : filterM :: partition : partitionM
partitionM :: Monad m => (a -> m Bool) -> [a] -> m ([a], [a])
partitionM _ [] = return ([], [])
partitionM f (x:xs) = do
b <- f x
(ys, zs) <- partitionM f xs
return $ if b
then (x:ys, zs)
else (ys, x:zs)
instance (LayoutClass l Window, Read (l Window)) => LayoutModifier (Drawer l) Window where
modifyLayout (Drawer rs rb p l) ws rect =
case stack ws of
Nothing -> runLayout ws rect
Just stk@(Stack { up=up_, down=down_, S.focus=w }) -> do
(upD, upM) <- partitionM (hasProperty p) up_
(downD, downM) <- partitionM (hasProperty p) down_
b <- hasProperty p w
focusedWindow <- gets (fmap S.focus . stack . workspace . current . windowset)
let rectD = if b && Just w == focusedWindow then rectB else rectS
let (stackD, stackM) = if b
then ( Just $ stk { up=upD, down=downD }
, mkStack upM downM )
else ( mkStack upD downD
, Just $ stk { up=upM, down=downM } )
(winsD, _) <- runLayout (ws { layout=l, stack=stackD }) rectD
(winsM, u') <- runLayout (ws { stack=stackM }) rectM
return (winsD ++ winsM, u')
where
mkStack [] [] = Nothing
mkStack xs (y:ys) = Just (Stack { up=xs, S.focus=y, down=ys })
mkStack (x:xs) ys = Just (Stack { up=xs, S.focus=x, down=ys })
rectB = rect { rect_width=round $ fromIntegral (rect_width rect) * rb }
rectS = rectB { rect_x=rect_x rectB - (round $ (rb - rs) * fromIntegral (rect_width rect)) }
rectM = rect { rect_x=rect_x rect + round (fromIntegral (rect_width rect) * rs)
, rect_width=rect_width rect - round (fromIntegral (rect_width rect) * rs) }
type Reflected l = ModifiedLayout Reflect l
-- | Construct a drawer with a simple layout of the windows inside
simpleDrawer :: Rational -- ^ The portion of the screen taken up by the drawer when closed
-> Rational -- ^ The portion of the screen taken up by the drawer when open
-> Property -- ^ Which windows to put in the drawer
-> Drawer Tall a
simpleDrawer rs rb p = Drawer rs rb p vertical
where
vertical = Tall 0 0 0
-- Export a synonym for the constructor as a Haddock workaround
-- | Construct a drawer with an arbitrary layout for windows inside
drawer :: Rational -- ^ The portion of the screen taken up by the drawer when closed
-> Rational -- ^ The portion of the screen taken up by the drawer when open
-> Property -- ^ Which windows to put in the drawer
-> (l a) -- ^ The layout of windows in the drawer
-> Drawer l a
drawer = Drawer
onLeft :: Drawer l a -> l' a -> ModifiedLayout (Drawer l) l' a
onLeft = ModifiedLayout
onRight :: Drawer l a -> l' a -> Reflected (ModifiedLayout (Drawer l) (Reflected l')) a
onRight d = reflectHoriz . onLeft d . reflectHoriz
onTop :: Drawer l a -> l' a -> Mirror (ModifiedLayout (Drawer l) (Mirror l')) a
onTop d = Mirror . onLeft d . Mirror
onBottom :: Drawer l a -> l' a -> Reflected (Mirror (ModifiedLayout (Drawer l) (Mirror (Reflected l')))) a
onBottom d = reflectVert . onTop d . reflectVert

227
XMonad/Layout/Fullscreen.hs Normal file
View File

@@ -0,0 +1,227 @@
{-# LANGUAGE DeriveDataTypeable, MultiParamTypeClasses, FlexibleInstances, TypeSynonymInstances #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Layout.Decoration
-- Copyright : (c) 2010 Audun Skaugen
-- License : BSD-style (see xmonad/LICENSE)
--
-- Maintainer : audunskaugen@gmail.com
-- Stability : unstable
-- Portability : unportable
--
-- Hooks for sending messages about fullscreen windows to layouts, and
-- a few example layout modifier that implement fullscreen windows.
-----------------------------------------------------------------------------
module XMonad.Layout.Fullscreen
( -- * Usage:
-- $usage
fullscreenFull
,fullscreenFocus
,fullscreenFullRect
,fullscreenFocusRect
,fullscreenFloat
,fullscreenFloatRect
,fullscreenEventHook
,fullscreenManageHook
,fullscreenManageHookWith
,FullscreenMessage(..)
-- * Types for reference
,FullscreenFloat, FullscreenFocus, FullscreenFull
) where
import XMonad
import XMonad.Layout.LayoutModifier
import XMonad.Util.WindowProperties
import XMonad.Hooks.ManageHelpers (isFullscreen)
import qualified XMonad.StackSet as W
import Data.List
import Data.Maybe
import Data.Monoid
import qualified Data.Map as M
import Control.Monad
import Control.Arrow (second)
-- $usage
-- Provides a ManageHook and an EventHook that sends layout messages
-- with information about fullscreening windows. This allows layouts
-- to make their own decisions about what they should to with a
-- window that requests fullscreen.
--
-- The module also includes a few layout modifiers as an illustration
-- of how such layouts should behave.
--
-- To use this module, add 'fullscreenEventHook' and 'fullscreenManageHook'
-- to your config, i.e.
--
-- > xmonad defaultconfig { handleEventHook = fullscreenEventHook,
-- > manageHook = fullscreenManageHook,
-- > layoutHook = myLayouts }
--
-- Now you can use layouts that respect fullscreen, for example the
-- provided 'fullscreenFull':
--
-- > myLayouts = fullscreenFull someLayout
--
-- | Messages that control the fullscreen state of the window.
-- AddFullscreen and RemoveFullscreen are sent to all layouts
-- when a window wants or no longer wants to be fullscreen.
-- FullscreenChanged is sent to the current layout after one
-- of the above have been sent.
data FullscreenMessage = AddFullscreen Window
| RemoveFullscreen Window
| FullscreenChanged
deriving (Typeable)
instance Message FullscreenMessage
data FullscreenFull a = FullscreenFull W.RationalRect [a]
deriving (Read, Show)
data FullscreenFocus a = FullscreenFocus W.RationalRect [a]
deriving (Read, Show)
data FullscreenFloat a = FullscreenFloat W.RationalRect (M.Map a (W.RationalRect, Bool))
deriving (Read, Show)
instance LayoutModifier FullscreenFull Window where
pureMess ff@(FullscreenFull frect fulls) m = case fromMessage m of
Just (AddFullscreen win) -> Just $ FullscreenFull frect $ nub $ win:fulls
Just (RemoveFullscreen win) -> Just $ FullscreenFull frect $ delete win $ fulls
Just FullscreenChanged -> Just ff
_ -> Nothing
pureModifier (FullscreenFull frect fulls) rect _ list =
(map (flip (,) rect') visfulls ++ rest, Nothing)
where visfulls = intersect fulls $ map fst list
rest = filter (flip notElem visfulls . fst) list
rect' = scaleRationalRect rect frect
instance LayoutModifier FullscreenFocus Window where
pureMess ff@(FullscreenFocus frect fulls) m = case fromMessage m of
Just (AddFullscreen win) -> Just $ FullscreenFocus frect $ nub $ win:fulls
Just (RemoveFullscreen win) -> Just $ FullscreenFocus frect $ delete win $ fulls
Just FullscreenChanged -> Just ff
_ -> Nothing
pureModifier (FullscreenFocus frect fulls) rect (Just (W.Stack {W.focus = f})) list
| f `elem` fulls = ((f, rect') : rest, Nothing)
| otherwise = (list, Nothing)
where rest = filter ((/= f) . fst) list
rect' = scaleRationalRect rect frect
pureModifier _ _ Nothing list = (list, Nothing)
instance LayoutModifier FullscreenFloat Window where
handleMess (FullscreenFloat frect fulls) m = case fromMessage m of
Just (AddFullscreen win) -> do
mrect <- (M.lookup win . W.floating) `fmap` gets windowset
return $ case mrect of
Just rect -> Just $ FullscreenFloat frect $ M.insert win (rect,True) fulls
Nothing -> Nothing
Just (RemoveFullscreen win) ->
return $ Just $ FullscreenFloat frect $ M.adjust (second $ const False) win fulls
-- Modify the floating member of the stack set directly; this is the hackish part.
Just FullscreenChanged -> do
st <- get
let ws = windowset st
flt = W.floating ws
flt' = M.intersectionWith doFull fulls flt
put st {windowset = ws {W.floating = M.union flt' flt}}
return $ Just $ FullscreenFloat frect $ M.filter snd fulls
where doFull (_, True) _ = frect
doFull (rect, False) _ = rect
Nothing -> return Nothing
-- | Layout modifier that makes fullscreened window fill the
-- entire screen.
fullscreenFull :: LayoutClass l a =>
l a -> ModifiedLayout FullscreenFull l a
fullscreenFull = fullscreenFullRect $ W.RationalRect 0 0 1 1
-- | As above, but the fullscreened window will fill the
-- specified rectangle instead of the entire screen.
fullscreenFullRect :: LayoutClass l a =>
W.RationalRect -> l a -> ModifiedLayout FullscreenFull l a
fullscreenFullRect r = ModifiedLayout $ FullscreenFull r []
-- | Layout modifier that makes the fullscreened window fill
-- the entire screen only if it is currently focused.
fullscreenFocus :: LayoutClass l a =>
l a -> ModifiedLayout FullscreenFocus l a
fullscreenFocus = fullscreenFocusRect $ W.RationalRect 0 0 1 1
-- | As above, but the fullscreened window will fill the
-- specified rectangle instead of the entire screen.
fullscreenFocusRect :: LayoutClass l a =>
W.RationalRect -> l a -> ModifiedLayout FullscreenFocus l a
fullscreenFocusRect r = ModifiedLayout $ FullscreenFocus r []
-- | Hackish layout modifier that makes floating fullscreened
-- windows fill the entire screen.
fullscreenFloat :: LayoutClass l a =>
l a -> ModifiedLayout FullscreenFloat l a
fullscreenFloat = fullscreenFloatRect $ W.RationalRect 0 0 1 1
-- | As above, but the fullscreened window will fill the
-- specified rectangle instead of the entire screen.
fullscreenFloatRect :: LayoutClass l a =>
W.RationalRect -> l a -> ModifiedLayout FullscreenFloat l a
fullscreenFloatRect r = ModifiedLayout $ FullscreenFloat r M.empty
-- | The event hook required for the layout modifiers to work
fullscreenEventHook :: Event -> X All
fullscreenEventHook (ClientMessageEvent _ _ _ dpy win typ (action:dats)) = do
wmstate <- getAtom "_NET_WM_STATE"
fullsc <- getAtom "_NET_WM_STATE_FULLSCREEN"
wstate <- fromMaybe [] `fmap` getProp32 wmstate win
let fi :: (Integral i, Num n) => i -> n
fi = fromIntegral
isFull = fi fullsc `elem` wstate
remove = 0
add = 1
toggle = 2
ptype = 4
chWState f = io $ changeProperty32 dpy win wmstate ptype propModeReplace (f wstate)
when (typ == wmstate && fi fullsc `elem` dats) $ do
when (action == add || (action == toggle && not isFull)) $ do
chWState (fi fullsc:)
broadcastMessage $ AddFullscreen win
sendMessage FullscreenChanged
when (action == remove || (action == toggle && isFull)) $ do
chWState $ delete (fi fullsc)
broadcastMessage $ RemoveFullscreen win
sendMessage FullscreenChanged
return $ All True
fullscreenEventHook (DestroyWindowEvent {ev_window = w}) = do
-- When a window is destroyed, the layouts should remove that window
-- from their states.
broadcastMessage $ RemoveFullscreen w
cw <- (W.workspace . W.current) `fmap` gets windowset
sendMessageWithNoRefresh FullscreenChanged cw
return $ All True
fullscreenEventHook _ = return $ All True
-- | Manage hook that sets the fullscreen property for
-- windows that are initially fullscreen
fullscreenManageHook :: ManageHook
fullscreenManageHook = fullscreenManageHook' isFullscreen
-- | A version of fullscreenManageHook that lets you specify
-- your own query to decide whether a window should be fullscreen.
fullscreenManageHookWith :: Query Bool -> ManageHook
fullscreenManageHookWith h = fullscreenManageHook' $ isFullscreen <||> h
fullscreenManageHook' :: Query Bool -> ManageHook
fullscreenManageHook' isFull = isFull --> do
w <- ask
liftX $ do
broadcastMessage $ AddFullscreen w
cw <- (W.workspace . W.current) `fmap` gets windowset
sendMessageWithNoRefresh FullscreenChanged cw
idHook

View File

@@ -28,7 +28,7 @@
module XMonad.Layout.Gaps (
-- * Usage
-- $usage
Direction2D(..),
Direction2D(..), Gaps,
GapSpec, gaps, GapMessage(..)
) where
@@ -38,6 +38,7 @@ import Graphics.X11 (Rectangle(..))
import XMonad.Layout.LayoutModifier
import XMonad.Util.Types (Direction2D(..))
import XMonad.Util.XUtils (fi)
import Data.List (delete)
@@ -56,8 +57,8 @@ import Data.List (delete)
--
-- > , ((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
-- > , ((modm .|. controlMask, xK_w), sendMessage $ IncGap 5 R) -- increment the right-hand gap
-- > , ((modm .|. controlMask, xK_q), sendMessage $ DecGap 5 R) -- 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
@@ -133,9 +134,6 @@ toggleGap conf cur d | d `elem` cur = delete d cur
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
fi = fromIntegral
-- | Add togglable manual gaps to a layout.
gaps :: GapSpec -- ^ The gaps to allow, paired with their initial sizes.
-> l a -- ^ The layout to modify.

View File

@@ -19,7 +19,8 @@
module XMonad.Layout.GridVariants ( -- * Usage
-- $usage
ChangeMasterGeom(..)
ChangeMasterGridGeom(..)
, ChangeGridGeom(..)
, Grid(..)
, TallGrid(..)
, SplitGrid(..)
@@ -68,9 +69,24 @@ instance LayoutClass Grid a where
nwins = length wins
rects = arrangeAspectGrid rect nwins aspect
pureMessage layout msg = fmap (changeGridAspect layout) (fromMessage msg)
description _ = "Grid"
-- | SplitGrid layout. Parameters are
changeGridAspect :: Grid a -> ChangeGridGeom -> Grid a
changeGridAspect (Grid _) (SetGridAspect aspect) = Grid aspect
changeGridAspect (Grid aspect) (ChangeGridAspect delta) =
Grid (max 0.00001 (aspect + delta))
-- |Geometry change messages understood by Grid and SplitGrid
data ChangeGridGeom
= SetGridAspect !Rational
| ChangeGridAspect !Rational
deriving Typeable
instance Message ChangeGridGeom
-- |SplitGrid layout. Parameters are
--
-- - side where the master is
-- - number of master rows
@@ -81,8 +97,8 @@ instance LayoutClass Grid a where
data SplitGrid a = SplitGrid Orientation !Int !Int !Rational !Rational !Rational
deriving (Read, Show)
-- | Type to specify the side of the screen that holds
-- the master area of a SplitGrid.
-- |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)
@@ -95,18 +111,23 @@ instance LayoutClass SplitGrid a where
rects = arrangeSplitGrid rect o nwins mrows mcols mfrac saspect
pureMessage layout msg =
msum [ fmap (resizeMaster layout) (fromMessage msg)
, fmap (changeMasterGrid layout) (fromMessage msg) ]
msum [ fmap (resizeMaster layout) (fromMessage msg)
, fmap (changeMasterGrid layout) (fromMessage msg)
, fmap (changeSlaveGridAspect layout) (fromMessage msg)
]
description _ = "SplitGrid"
-- |The geometry change message understood by the master grid
data ChangeMasterGeom
= IncMasterRows !Int -- ^Change the number of master rows
| IncMasterCols !Int -- ^Change the number of master columns
data ChangeMasterGridGeom
= IncMasterRows !Int -- ^Change the number of master rows
| IncMasterCols !Int -- ^Change the number of master columns
| SetMasterRows !Int -- ^Set the number of master rows to absolute value
| SetMasterCols !Int -- ^Set the number of master columns to absolute value
| SetMasterFraction !Rational -- ^Set the fraction of the screen used by the master grid
deriving Typeable
instance Message ChangeMasterGeom
instance Message ChangeMasterGridGeom
arrangeSplitGrid :: Rectangle -> Orientation -> Int -> Int -> Int -> Rational -> Rational -> [Rectangle]
arrangeSplitGrid rect@(Rectangle rx ry rw rh) o nwins mrows mcols mfrac saspect
@@ -183,11 +204,23 @@ resizeMaster (SplitGrid o mrows mcols mfrac saspect delta) Shrink =
resizeMaster (SplitGrid o mrows mcols mfrac saspect delta) Expand =
SplitGrid o mrows mcols (min 1 (mfrac + delta)) saspect delta
changeMasterGrid :: SplitGrid a -> ChangeMasterGeom -> SplitGrid a
changeMasterGrid :: SplitGrid a -> ChangeMasterGridGeom -> 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
changeMasterGrid (SplitGrid o _ mcols mfrac saspect delta) (SetMasterRows mrows) =
SplitGrid o (max 0 mrows) mcols mfrac saspect delta
changeMasterGrid (SplitGrid o mrows _ mfrac saspect delta) (SetMasterCols mcols) =
SplitGrid o mrows (max 0 mcols) mfrac saspect delta
changeMasterGrid (SplitGrid o mrows mcols _ saspect delta) (SetMasterFraction mfrac) =
SplitGrid o mrows mcols mfrac saspect delta
changeSlaveGridAspect :: SplitGrid a -> ChangeGridGeom -> SplitGrid a
changeSlaveGridAspect (SplitGrid o mrows mcols mfrac _ delta) (SetGridAspect saspect) =
SplitGrid o mrows mcols mfrac saspect delta
changeSlaveGridAspect (SplitGrid o mrows mcols mfrac saspect delta) (ChangeGridAspect sdelta) =
SplitGrid o mrows mcols mfrac (max 0.00001 (saspect + sdelta)) delta
-- | TallGrid layout. Parameters are
--

510
XMonad/Layout/Groups.hs Normal file
View File

@@ -0,0 +1,510 @@
{-# OPTIONS_GHC -fno-warn-name-shadowing -fno-warn-unused-binds #-}
{-# LANGUAGE StandaloneDeriving, FlexibleContexts, DeriveDataTypeable
, UndecidableInstances, FlexibleInstances, MultiParamTypeClasses
, PatternGuards, Rank2Types, TypeSynonymInstances #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Layout.Groups
-- Copyright : Quentin Moser <moserq@gmail.com>
-- License : BSD-style (see LICENSE)
--
-- Maintainer : orphaned
-- Stability : unstable
-- Portability : unportable
--
-- Two-level layout with windows split in individual layout groups,
-- themselves managed by a user-provided layout.
--
-----------------------------------------------------------------------------
module XMonad.Layout.Groups ( -- * Usage
-- $usage
-- * Creation
group
-- * Messages
, GroupsMessage(..)
, ModifySpec
-- ** Useful 'ModifySpec's
, swapUp
, swapDown
, swapMaster
, focusUp
, focusDown
, focusMaster
, swapGroupUp
, swapGroupDown
, swapGroupMaster
, focusGroupUp
, focusGroupDown
, focusGroupMaster
, moveToGroupUp
, moveToGroupDown
, moveToNewGroupUp
, moveToNewGroupDown
, splitGroup
-- * Types
, Groups
, Group(..)
, onZipper
, onLayout
, WithID
, sameID
) where
import XMonad
import qualified XMonad.StackSet as W
import XMonad.Util.Stack
import Data.Maybe (isJust, isNothing, fromMaybe, catMaybes, fromJust)
import Data.List ((\\))
import Control.Arrow ((>>>))
import Control.Applicative ((<$>))
import Control.Monad (forM)
-- $usage
-- This module provides a layout combinator that allows you
-- to manage your windows in independent groups. You can provide
-- both the layout with which to arrange the windows inside each
-- group, and the layout with which the groups themselves will
-- be arranged on the screen.
--
-- The "XMonad.Layout.Groups.Examples" and "XMonad.Layout.Groups.Wmii"
-- modules contain examples of layouts that can be defined with this
-- combinator. They're also the recommended starting point
-- if you are a beginner and looking for something you can use easily.
--
-- One thing to note is that 'Groups'-based layout have their own
-- notion of the order of windows, which is completely separate
-- from XMonad's. For this reason, operations like 'XMonad.StackSet.SwapUp'
-- will have no visible effect, and those like 'XMonad.StackSet.focusUp'
-- will focus the windows in an unpredictable order. For a better way of
-- rearranging windows and moving focus in such a layout, see the
-- example 'ModifySpec's (to be passed to the 'Modify' message) provided
-- by this module.
--
-- If you use both 'Groups'-based and other layouts, The "XMonad.Layout.Groups.Helpers"
-- module provides actions that can work correctly with both, defined using
-- functions from "XMonad.Actions.MessageFeedback".
-- | Create a 'Groups' layout.
--
-- Note that the second parameter (the layout for arranging the
-- groups) is not used on 'Windows', but on 'Group's. For this
-- reason, you can only use layouts that don't specifically
-- need to manage 'Window's. This is obvious, when you think
-- about it.
group :: l Window -> l2 (Group l Window) -> Groups l l2 Window
group l l2 = Groups l l2 startingGroups (U 1 0)
where startingGroups = fromJust $ singletonZ $ G (ID (U 0 0) l) emptyZ
-- * Stuff with unique keys
data Uniq = U Integer Integer
deriving (Eq, Show, Read)
-- | From a seed, generate an infinite list of keys and a new
-- seed. All keys generated with this method will be different
-- provided you don't use 'gen' again with a key from the list.
-- (if you need to do that, see 'split' instead)
gen :: Uniq -> (Uniq, [Uniq])
gen (U i1 i2) = (U (i1+1) i2, zipWith U (repeat i1) [i2..])
-- | Split an infinite list into two. I ended up not
-- needing this, but let's keep it just in case.
-- split :: [a] -> ([a], [a])
-- split as = snd $ foldr step (True, ([], [])) as
-- where step a (True, (as1, as2)) = (False, (a:as1, as2))
-- step a (False, (as1, as2)) = (True, (as1, a:as2))
-- | Add a unique identity to a layout so we can
-- follow it around.
data WithID l a = ID { getID :: Uniq
, unID :: (l a)}
deriving (Show, Read)
-- | Compare the ids of two 'WithID' values
sameID :: WithID l a -> WithID l a -> Bool
sameID (ID id1 _) (ID id2 _) = id1 == id2
instance Eq (WithID l a) where
ID id1 _ == ID id2 _ = id1 == id2
instance LayoutClass l a => LayoutClass (WithID l) a where
runLayout ws@W.Workspace { W.layout = ID id l } r
= do (placements, ml') <- flip runLayout r
ws { W.layout = l}
return (placements, ID id <$> ml')
handleMessage (ID id l) sm = do ml' <- handleMessage l sm
return $ ID id <$> ml'
description (ID _ l) = description l
-- * The 'Groups' layout
-- ** Datatypes
-- | A group of windows and its layout algorithm.
data Group l a = G { gLayout :: WithID l a
, gZipper :: Zipper a }
deriving (Show, Read, Eq)
onLayout :: (WithID l a -> WithID l a) -> Group l a -> Group l a
onLayout f g = g { gLayout = f $ gLayout g }
onZipper :: (Zipper a -> Zipper a) -> Group l a -> Group l a
onZipper f g = g { gZipper = f $ gZipper g }
-- | The type of our layouts.
data Groups l l2 a = Groups { -- | The starting layout for new groups
baseLayout :: l a
-- | The layout for placing each group on the screen
, partitioner :: l2 (Group l a)
-- | The window groups
, groups :: W.Stack (Group l a)
-- | A seed for generating unique ids
, seed :: Uniq
}
deriving instance (Show a, Show (l a), Show (l2 (Group l a))) => Show (Groups l l2 a)
deriving instance (Read a, Read (l a), Read (l2 (Group l a))) => Read (Groups l l2 a)
-- | Messages accepted by 'Groups'-based layouts.
-- All other messages are forwarded to the layout of the currently
-- focused subgroup (as if they had been wrapped in 'ToFocused').
data GroupsMessage = ToEnclosing SomeMessage -- ^ Send a message to the enclosing layout
-- (the one that places the groups themselves)
| ToGroup Int SomeMessage -- ^ Send a message to the layout for nth group
-- (starting at 0)
| ToFocused SomeMessage -- ^ Send a message to the layout for the focused
-- group
| ToAll SomeMessage -- ^ Send a message to all the sub-layouts
| Refocus -- ^ Refocus the window which should be focused according
-- to the layout.
| Modify ModifySpec -- ^ Modify the ordering\/grouping\/focusing
-- of windows according to a 'ModifySpec'
deriving Typeable
instance Show GroupsMessage where
show (ToEnclosing _) = "ToEnclosing {...}"
show (ToGroup i _) = "ToGroup "++show i++" {...}"
show (ToFocused _) = "ToFocused {...}"
show (ToAll _) = "ToAll {...}"
show Refocus = "Refocus"
show (Modify _) = "Modify {...}"
instance Message GroupsMessage
modifyGroups :: (Zipper (Group l a) -> Zipper (Group l a))
-> Groups l l2 a -> Groups l l2 a
modifyGroups f g = let (seed', id:_) = gen (seed g)
defaultGroups = fromJust $ singletonZ $ G (ID id $ baseLayout g) emptyZ
in g { groups = fromMaybe defaultGroups . f . Just $ groups g
, seed = seed' }
-- ** Readaptation
-- | Adapt our groups to a new stack.
-- This algorithm handles window additions and deletions correctly,
-- ignores changes in window ordering, and tries to react to any
-- other stack changes as gracefully as possible.
readapt :: Eq a => Zipper a -> Groups l l2 a -> Groups l l2 a
readapt z g = let mf = getFocusZ z
(seed', id:_) = gen $ seed g
g' = g { seed = seed' }
in flip modifyGroups g' $ mapZ_ (onZipper $ removeDeleted z)
>>> filterKeepLast (isJust . gZipper)
>>> findNewWindows (W.integrate' z)
>>> addWindows (ID id $ baseLayout g)
>>> focusGroup mf
>>> onFocusedZ (onZipper $ focusWindow mf)
where filterKeepLast _ Nothing = Nothing
filterKeepLast f z@(Just s) = maybe (singletonZ $ W.focus s) Just
$ filterZ_ f z
-- | Remove the windows from a group which are no longer present in
-- the stack.
removeDeleted :: Eq a => Zipper a -> Zipper a -> Zipper a
removeDeleted z = filterZ_ (flip elemZ z)
-- | Identify the windows not already in a group.
findNewWindows :: Eq a => [a] -> Zipper (Group l a)
-> (Zipper (Group l a), [a])
findNewWindows as gs = (gs, foldrZ_ removePresent as gs)
where removePresent g as' = filter (not . flip elemZ (gZipper g)) as'
-- | Add windows to the focused group. If you need to create one,
-- use the given layout and an id from the given list.
addWindows :: WithID l a -> (Zipper (Group l a), [a]) -> Zipper (Group l a)
addWindows l (Nothing, as) = singletonZ $ G l (W.differentiate as)
addWindows _ (z, as) = onFocusedZ (onZipper add) z
where add z = foldl (flip insertUpZ) z as
-- | Focus the group containing the given window
focusGroup :: Eq a => Maybe a -> Zipper (Group l a) -> Zipper (Group l a)
focusGroup Nothing = id
focusGroup (Just a) = fromTags . map (tagBy $ elemZ a . gZipper) . W.integrate'
-- | Focus the given window
focusWindow :: Eq a => Maybe a -> Zipper a -> Zipper a
focusWindow Nothing = id
focusWindow (Just a) = fromTags . map (tagBy (==a)) . W.integrate'
-- * Interface
-- ** Layout instance
instance (LayoutClass l Window, LayoutClass l2 (Group l Window))
=> LayoutClass (Groups l l2) Window where
description (Groups _ p gs _) = s1++" by "++s2
where s1 = description $ gLayout $ W.focus gs
s2 = description p
runLayout ws@(W.Workspace _ _l z) r = let l = readapt z _l in
do (areas, mpart') <- runLayout ws { W.layout = partitioner l
, W.stack = Just $ groups l } r
results <- forM areas $ \(g, r') -> runLayout ws { W.layout = gLayout g
, W.stack = gZipper g } r'
let hidden = map gLayout (W.integrate $ groups l) \\ map (gLayout . fst) areas
hidden' <- mapM (flip handleMessage $ SomeMessage Hide) hidden
let placements = concatMap fst results
newL = justMakeNew l mpart' (map snd results ++ hidden')
return $ (placements, newL)
handleMessage l@(Groups _ p _ _) sm | Just (ToEnclosing sm') <- fromMessage sm
= do mp' <- handleMessage p sm'
return $ maybeMakeNew l mp' []
handleMessage l@(Groups _ p gs _) sm | Just (ToAll sm') <- fromMessage sm
= do mp' <- handleMessage p sm'
mg's <- mapZM_ (handle sm') $ Just gs
return $ maybeMakeNew l mp' $ W.integrate' mg's
where handle sm (G l _) = handleMessage l sm
handleMessage l sm | Just a <- fromMessage sm
= let _rightType = a == Hide -- Is there a better-looking way
-- of doing this?
in handleMessage l $ SomeMessage $ ToAll sm
handleMessage l@(Groups _ _ z _) sm = case fromMessage sm of
Just (ToFocused sm') -> do mg's <- W.integrate' <$> handleOnFocused sm' z
return $ maybeMakeNew l Nothing mg's
Just (ToGroup i sm') -> do mg's <- handleOnIndex i sm' z
return $ maybeMakeNew l Nothing mg's
Just (Modify spec) -> case applySpec spec l of
Just l' -> refocus l' >> return (Just l')
Nothing -> return $ Just l
Just Refocus -> refocus l >> return (Just l)
Just _ -> return Nothing
Nothing -> handleMessage l $ SomeMessage (ToFocused sm)
where handleOnFocused sm z = mapZM step $ Just z
where step True (G l _) = handleMessage l sm
step False _ = return Nothing
handleOnIndex i sm z = mapM step $ zip [0..] $ W.integrate z
where step (j, (G l _)) | i == j = handleMessage l sm
step _ = return Nothing
justMakeNew :: Groups l l2 a -> Maybe (l2 (Group l a)) -> [Maybe (WithID l a)]
-> Maybe (Groups l l2 a)
justMakeNew g mpart' ml's = Just g { partitioner = fromMaybe (partitioner g) mpart'
, groups = combine (groups g) ml's }
where combine z ml's = let table = map (\(ID id a) -> (id, a)) $ catMaybes ml's
in flip mapS_ z $ \(G (ID id l) ws) -> case lookup id table of
Nothing -> G (ID id l) ws
Just l' -> G (ID id l') ws
mapS_ f = fromJust . mapZ_ f . Just
maybeMakeNew :: Groups l l2 a -> Maybe (l2 (Group l a)) -> [Maybe (WithID l a)]
-> Maybe (Groups l l2 a)
maybeMakeNew _ Nothing ml's | all isNothing ml's = Nothing
maybeMakeNew g mpart' ml's = justMakeNew g mpart' ml's
refocus :: Groups l l2 Window -> X ()
refocus g = case getFocusZ $ gZipper $ W.focus $ groups g
of Just w -> focus w
Nothing -> return ()
-- ** ModifySpec type
-- | Type of functions describing modifications to a 'Groups' layout. They
-- are transformations on 'Zipper's of groups.
--
-- Things you shouldn't do:
--
-- * Forge new windows (they will be ignored)
--
-- * Duplicate windows (whatever happens is your problem)
--
-- * Remove windows (they will be added again)
--
-- * Duplicate layouts (only one will be kept, the rest will
-- get the base layout)
--
-- Note that 'ModifySpec' is a rank-2 type (indicating that 'ModifySpec's must
-- be polymorphic in the layout type), so if you define functions taking
-- 'ModifySpec's as arguments, or returning them, you'll need to write a type
-- signature and add @{-# LANGUAGE Rank2Types #-}@ at the beginning
type ModifySpec = forall l. WithID l Window
-> Zipper (Group l Window)
-> Zipper (Group l Window)
-- | Apply a ModifySpec.
applySpec :: ModifySpec -> Groups l l2 Window -> Maybe (Groups l l2 Window)
applySpec f g = let (seed', id:ids) = gen $ seed g
g' = flip modifyGroups g $ f (ID id $ baseLayout g)
>>> toTags
>>> foldr reID ((ids, []), [])
>>> snd
>>> fromTags
in case groups g == groups g' of
True -> Nothing
False -> Just g' { seed = seed' }
where reID eg ((id:ids, seen), egs)
= let myID = getID $ gLayout $ fromE eg
in case elem myID seen of
False -> ((id:ids, myID:seen), eg:egs)
True -> ((ids, seen), mapE_ (setID id) eg:egs)
where setID id (G (ID _ _) z) = G (ID id $ baseLayout g) z
reID _ (([], _), _) = undefined -- The list of ids is infinite
-- ** Misc. ModifySpecs
-- | helper
onFocused :: (Zipper Window -> Zipper Window) -> ModifySpec
onFocused f _ gs = onFocusedZ (onZipper f) gs
-- | Swap the focused window with the previous one.
swapUp :: ModifySpec
swapUp = onFocused swapUpZ
-- | Swap the focused window with the next one.
swapDown :: ModifySpec
swapDown = onFocused swapDownZ
-- | Swap the focused window with the (group's) master
-- window.
swapMaster :: ModifySpec
swapMaster = onFocused swapMasterZ
-- | Swap the focused group with the previous one.
swapGroupUp :: ModifySpec
swapGroupUp _ = swapUpZ
-- | Swap the focused group with the next one.
swapGroupDown :: ModifySpec
swapGroupDown _ = swapDownZ
-- | Swap the focused group with the master group.
swapGroupMaster :: ModifySpec
swapGroupMaster _ = swapMasterZ
-- | Move focus to the previous window in the group.
focusUp :: ModifySpec
focusUp = onFocused focusUpZ
-- | Move focus to the next window in the group.
focusDown :: ModifySpec
focusDown = onFocused focusDownZ
-- | Move focus to the group's master window.
focusMaster :: ModifySpec
focusMaster = onFocused focusMasterZ
-- | Move focus to the previous group.
focusGroupUp :: ModifySpec
focusGroupUp _ = focusUpZ
-- | Move focus to the next group.
focusGroupDown :: ModifySpec
focusGroupDown _ = focusDownZ
-- | Move focus to the master group.
focusGroupMaster :: ModifySpec
focusGroupMaster _ = focusMasterZ
-- | helper
_removeFocused :: W.Stack a -> (a, Zipper a)
_removeFocused (W.Stack f (u:up) down) = (f, Just $ W.Stack u up down)
_removeFocused (W.Stack f [] (d:down)) = (f, Just $ W.Stack d [] down)
_removeFocused (W.Stack f [] []) = (f, Nothing)
-- helper
_moveToNewGroup :: WithID l Window -> W.Stack (Group l Window)
-> (Group l Window -> Zipper (Group l Window)
-> Zipper (Group l Window))
-> Zipper (Group l Window)
_moveToNewGroup l0 s insertX | G l (Just f) <- W.focus s
= let (w, f') = _removeFocused f
s' = s { W.focus = G l f' }
in insertX (G l0 $ singletonZ w) $ Just s'
_moveToNewGroup _ s _ = Just s
-- | Move the focused window to a new group before the current one.
moveToNewGroupUp :: ModifySpec
moveToNewGroupUp _ Nothing = Nothing
moveToNewGroupUp l0 (Just s) = _moveToNewGroup l0 s insertUpZ
-- | Move the focused window to a new group after the current one.
moveToNewGroupDown :: ModifySpec
moveToNewGroupDown _ Nothing = Nothing
moveToNewGroupDown l0 (Just s) = _moveToNewGroup l0 s insertDownZ
-- | Move the focused window to the previous group.
-- If 'True', when in the first group, wrap around to the last one.
-- If 'False', create a new group before it.
moveToGroupUp :: Bool -> ModifySpec
moveToGroupUp _ _ Nothing = Nothing
moveToGroupUp False l0 (Just s) = if null (W.up s) then moveToNewGroupUp l0 (Just s)
else moveToGroupUp True l0 (Just s)
moveToGroupUp True _ (Just s@(W.Stack _ [] [])) = Just s
moveToGroupUp True _ (Just s@(W.Stack (G l (Just f)) _ _))
= let (w, f') = _removeFocused f
in onFocusedZ (onZipper $ insertUpZ w) $ focusUpZ $ Just s { W.focus = G l f' }
moveToGroupUp True _ gs = gs
-- | Move the focused window to the next group.
-- If 'True', when in the last group, wrap around to the first one.
-- If 'False', create a new group after it.
moveToGroupDown :: Bool -> ModifySpec
moveToGroupDown _ _ Nothing = Nothing
moveToGroupDown False l0 (Just s) = if null (W.down s) then moveToNewGroupDown l0 (Just s)
else moveToGroupDown True l0 (Just s)
moveToGroupDown True _ (Just s@(W.Stack _ [] [])) = Just s
moveToGroupDown True _ (Just s@(W.Stack (G l (Just f)) _ _))
= let (w, f') = _removeFocused f
in onFocusedZ (onZipper $ insertUpZ w) $ focusDownZ $ Just s { W.focus = G l f' }
moveToGroupDown True _ gs = gs
-- | Split the focused group into two at the position of the focused window (below it,
-- unless it's the last window - in that case, above it).
splitGroup :: ModifySpec
splitGroup _ Nothing = Nothing
splitGroup l0 z@(Just s) | G l (Just ws) <- W.focus s
= case ws of
W.Stack _ [] [] -> z
W.Stack f (u:up) [] -> let g1 = G l $ Just $ W.Stack f [] []
g2 = G l0 $ Just $ W.Stack u up []
in insertDownZ g1 $ onFocusedZ (const g2) z
W.Stack f up (d:down) -> let g1 = G l $ Just $ W.Stack f up []
g2 = G l0 $ Just $ W.Stack d [] down
in insertUpZ g1 $ onFocusedZ (const g2) z
splitGroup _ _ = Nothing

View File

@@ -0,0 +1,240 @@
{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
{-# LANGUAGE MultiParamTypeClasses, Rank2Types #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Layout.Groups.Examples
-- Copyright : Quentin Moser <moserq@gmail.com>
-- License : BSD-style (see LICENSE)
--
-- Maintainer : orphaned
-- Stability : unstable
-- Portability : unportable
--
-- Example layouts for "XMonad.Layout.Groups".
--
-----------------------------------------------------------------------------
module XMonad.Layout.Groups.Examples ( -- * Usage
-- $usage
-- * Example: Row of columns
-- $example1
rowOfColumns
, zoomColumnIn
, zoomColumnOut
, zoomColumnReset
, toggleColumnFull
, zoomWindowIn
, zoomWindowOut
, zoomWindowReset
, toggleWindowFull
-- * Example: Tiled tab groups
-- $example2
, tallTabs
, mirrorTallTabs
, fullTabs
, TiledTabsConfig(..)
, defaultTiledTabsConfig
, increaseNMasterGroups
, decreaseNMasterGroups
, shrinkMasterGroups
, expandMasterGroups
, nextOuterLayout
-- * Useful re-exports and utils
, module XMonad.Layout.Groups.Helpers
, shrinkText
, defaultTheme
, GroupEQ(..)
, zoomRowG
) where
import XMonad hiding ((|||))
import qualified XMonad.Layout.Groups as G
import XMonad.Layout.Groups.Helpers
import XMonad.Layout.ZoomRow
import XMonad.Layout.Tabbed
import XMonad.Layout.Named
import XMonad.Layout.Renamed
import XMonad.Layout.LayoutCombinators
import XMonad.Layout.Decoration
import XMonad.Layout.Simplest
-- $usage
-- This module contains example 'G.Groups'-based layouts.
-- You can either import this module directly, or look at its source
-- for ideas of how "XMonad.Layout.Groups" may be used.
--
-- You can use the contents of this module by adding
--
-- > import XMonad.Layout.Groups.Examples
--
-- to the top of your @.\/.xmonad\/xmonad.hs@.
--
-- For more information on using any of the layouts, jump directly
-- to its \"Example\" section.
--
-- Whichever layout you choose to use, you will probably want to be
-- able to move focus and windows between groups in a consistent
-- manner. For this, you should take a look at the functions from
-- the "XMonad.Layout.Groups.Helpers" module, which are all
-- re-exported by this module.
--
-- For more information on how to extend your layour hook and key bindings, see
-- "XMonad.Doc.Extending".
-- * Helper: ZoomRow of Group elements
-- | Compare two 'Group's by comparing the ids of their layouts.
data GroupEQ a = GroupEQ
deriving (Show, Read)
instance Eq a => EQF GroupEQ (G.Group l a) where
eq _ (G.G l1 _) (G.G l2 _) = G.sameID l1 l2
zoomRowG :: (Eq a, Show a, Read a, Show (l a), Read (l a))
=> ZoomRow GroupEQ (G.Group l a)
zoomRowG = zoomRowWith GroupEQ
-- * Example 1: Row of columns
-- $example1
-- A layout that arranges windows in a row of columns. It uses 'ZoomRow's for
-- both, allowing you to:
--
-- * Freely change the proportion of the screen width allocated to each column
--
-- * Freely change the proportion of a column's heigth allocated to each of its windows
--
-- * Set a column to occupy the whole screen space whenever it has focus
--
-- * Set a window to occupy its whole column whenever it has focus
--
-- to use this layout, add 'rowOfColumns' to your layout hook, for example:
--
-- > myLayout = rowOfColumns
--
-- To be able to change the sizes of columns and windows, you can create key bindings
-- for the relevant actions:
--
-- > ((modMask, xK_minus), zoomWindowOut)
--
-- and so on.
rowOfColumns = G.group column zoomRowG
where column = renamed [CutWordsLeft 2, PrependWords "ZoomColumn"] $ Mirror zoomRow
-- | Increase the width of the focused column
zoomColumnIn :: X ()
zoomColumnIn = sendMessage $ G.ToEnclosing $ SomeMessage $ zoomIn
-- | Decrease the width of the focused column
zoomColumnOut :: X ()
zoomColumnOut = sendMessage $ G.ToEnclosing $ SomeMessage $ zoomOut
-- | Reset the width of the focused column
zoomColumnReset :: X ()
zoomColumnReset = sendMessage $ G.ToEnclosing $ SomeMessage $ zoomReset
-- | Toggle whether the currently focused column should
-- take up all available space whenever it has focus
toggleColumnFull :: X ()
toggleColumnFull = sendMessage $ G.ToEnclosing $ SomeMessage $ ZoomFullToggle
-- | Increase the heigth of the focused window
zoomWindowIn :: X ()
zoomWindowIn = sendMessage zoomIn
-- | Decrease the height of the focused window
zoomWindowOut :: X ()
zoomWindowOut = sendMessage zoomOut
-- | Reset the height of the focused window
zoomWindowReset :: X ()
zoomWindowReset = sendMessage zoomReset
-- | Toggle whether the currently focused window should
-- take up the whole column whenever it has focus
toggleWindowFull :: X ()
toggleWindowFull = sendMessage ZoomFullToggle
-- * Example 2: Tabbed groups in a Tall/Full layout.
-- $example2
-- A layout which arranges windows into tabbed groups, and the groups
-- themselves according to XMonad's default algorithm
-- (@'Tall' ||| 'Mirror' 'Tall' ||| 'Full'@). As their names
-- indicate, 'tallTabs' starts as 'Tall', 'mirrorTallTabs' starts
-- as 'Mirror' 'Tall' and 'fullTabs' starts as 'Full', but in any
-- case you can freely switch between the three afterwards.
--
-- You can use any of these three layouts by including it in your layout hook.
-- You will need to provide it with a 'TiledTabsConfig' containing the size
-- parameters for 'Tall' and 'Mirror' 'Tall', and the shrinker and decoration theme
-- for the tabs. If you're happy with defaults, you can use 'defaultTiledTabsConfig':
--
-- > myLayout = tallTabs defaultTiledTabsConfig
--
-- To be able to increase\/decrease the number of master groups and shrink\/expand
-- the master area, you can create key bindings for the relevant actions:
--
-- > ((modMask, xK_h), shrinkMasterGroups)
--
-- and so on.
-- | Configuration data for the "tiled tab groups" layout
data TiledTabsConfig s = TTC { vNMaster :: Int
, vRatio :: Rational
, vIncrement :: Rational
, hNMaster :: Int
, hRatio :: Rational
, hIncrement :: Rational
, tabsShrinker :: s
, tabsTheme :: Theme }
defaultTiledTabsConfig :: TiledTabsConfig DefaultShrinker
defaultTiledTabsConfig = TTC 1 0.5 (3/100) 1 0.5 (3/100) shrinkText defaultTheme
fullTabs c = _tab c $ G.group _tabs $ Full ||| _vert c ||| _horiz c
tallTabs c = _tab c $ G.group _tabs $ _vert c ||| _horiz c ||| Full
mirrorTallTabs c = _tab c $ G.group _tabs $ _horiz c ||| Full ||| _vert c
_tabs = named "Tabs" Simplest
_tab c l = renamed [CutWordsLeft 1] $ addTabs (tabsShrinker c) (tabsTheme c) l
_vert c = named "Vertical" $ Tall (vNMaster c) (vIncrement c) (vRatio c)
_horiz c = named "Horizontal" $ Mirror $ Tall (hNMaster c) (hIncrement c) (hRatio c)
-- | Increase the number of master groups by one
increaseNMasterGroups :: X ()
increaseNMasterGroups = sendMessage $ G.ToEnclosing $ SomeMessage $ IncMasterN 1
-- | Decrease the number of master groups by one
decreaseNMasterGroups :: X ()
decreaseNMasterGroups = sendMessage $ G.ToEnclosing $ SomeMessage $ IncMasterN (-1)
-- | Shrink the master area
shrinkMasterGroups :: X ()
shrinkMasterGroups = sendMessage $ G.ToEnclosing $ SomeMessage $ Shrink
-- | Expand the master area
expandMasterGroups :: X ()
expandMasterGroups = sendMessage $ G.ToEnclosing $ SomeMessage $ Expand
-- | Rotate the available outer layout algorithms
nextOuterLayout :: X ()
nextOuterLayout = sendMessage $ G.ToEnclosing $ SomeMessage $ NextLayout

View File

@@ -0,0 +1,232 @@
{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
{-# LANGUAGE MultiParamTypeClasses, Rank2Types #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Layout.Groups.Helpers
-- Copyright : Quentin Moser <moserq@gmail.com>
-- License : BSD-style (see LICENSE)
--
-- Maintainer : orphaned
-- Stability : stable
-- Portability : unportable
--
-- Utility functions for "XMonad.Layout.Groups".
--
-----------------------------------------------------------------------------
module XMonad.Layout.Groups.Helpers ( -- * Usage
-- $usage
-- ** Layout-generic actions
swapUp
, swapDown
, swapMaster
, focusUp
, focusDown
, focusMaster
, toggleFocusFloat
-- ** 'G.Groups'-secific actions
, swapGroupUp
, swapGroupDown
, swapGroupMaster
, focusGroupUp
, focusGroupDown
, focusGroupMaster
, moveToGroupUp
, moveToGroupDown
, moveToNewGroupUp
, moveToNewGroupDown
, splitGroup ) where
import XMonad hiding ((|||))
import qualified XMonad.StackSet as W
import qualified XMonad.Layout.Groups as G
import XMonad.Actions.MessageFeedback
import Control.Monad (unless)
import qualified Data.Map as M
-- $usage
--
-- This module provides helpers functions for use with "XMonad.Layout.Groups"-based
-- layouts. You can use its contents by adding
--
-- > import XMonad.Layout.Groups.Helpers
--
-- to the top of your @.\/.xmonad\/xmonad.hs@.
--
-- "XMonad.Layout.Groups"-based layouts do not have the same notion
-- of window ordering as the rest of XMonad. For this reason, the usual
-- ways of reordering windows and moving focus do not work with them.
-- "XMonad.Layout.Groups" provides 'Message's that can be used to obtain
-- the right effect.
--
-- But what if you want to use both 'G.Groups' and other layouts?
-- This module provides actions that try to send 'G.GroupsMessage's, and
-- fall back to the classic way if the current layout doesn't hande them.
-- They are in the section called \"Layout-generic actions\".
--
-- The sections \"Groups-specific actions\" contains actions that don't make
-- sense for non-'G.Groups'-based layouts. These are simply wrappers around
-- the equivalent 'G.GroupsMessage's, but are included so you don't have to
-- write @sendMessage $ Modify $ ...@ everytime.
--
-- This module exports many operations with the same names as
-- 'G.ModifySpec's from "XMonad.Layout.Groups", so if you want
-- to import both, we suggest to import "XMonad.Layout.Groups"
-- qualified:
--
-- > import qualified XMonad.Layout.Groups as G
--
-- For more information on how to extend your layour hook and key bindings, see
-- "XMonad.Doc.Extending".
-- ** Layout-generic actions
-- #Layout-generic actions#
alt :: G.ModifySpec -> (WindowSet -> WindowSet) -> X ()
alt f g = alt2 (G.Modify f) $ windows g
alt2 :: G.GroupsMessage -> X () -> X ()
alt2 m x = do b <- send m
unless b x
-- | Swap the focused window with the previous one
swapUp :: X ()
swapUp = alt G.swapUp W.swapUp
-- | Swap the focused window with the next one
swapDown :: X ()
swapDown = alt G.swapDown W.swapDown
-- | Swap the focused window with the master window
swapMaster :: X ()
swapMaster = alt G.swapMaster W.swapMaster
-- | If the focused window is floating, focus the next floating
-- window. otherwise, focus the next non-floating one.
focusUp :: X ()
focusUp = ifFloat focusFloatUp focusNonFloatUp
-- | If the focused window is floating, focus the next floating
-- window. otherwise, focus the next non-floating one.
focusDown :: X ()
focusDown = ifFloat focusFloatDown focusNonFloatDown
-- | Move focus to the master window
focusMaster :: X ()
focusMaster = alt G.focusMaster W.shiftMaster
-- | Move focus between the floating and non-floating layers
toggleFocusFloat :: X ()
toggleFocusFloat = ifFloat focusNonFloat focusFloatUp
-- *** Floating layer helpers
getFloats :: X [Window]
getFloats = gets $ M.keys . W.floating . windowset
getWindows :: X [Window]
getWindows = gets $ W.integrate' . W.stack . W.workspace . W.current . windowset
ifFloat :: X () -> X () -> X ()
ifFloat x1 x2 = withFocused $ \w -> do floats <- getFloats
if elem w floats then x1 else x2
focusNonFloat :: X ()
focusNonFloat = alt2 G.Refocus helper
where helper = withFocused $ \w -> do
ws <- getWindows
floats <- getFloats
let (before, after) = span (/=w) ws
case filter (flip notElem floats) $ after ++ before of
[] -> return ()
w':_ -> focus w'
focusHelper :: (Bool -> Bool) -- ^ if you want to focus a floating window, 'id'.
-- if you want a non-floating one, 'not'.
-> ([Window] -> [Window]) -- ^ if you want the next window, 'id'.
-- if you want the previous one, 'reverse'.
-> X ()
focusHelper f g = withFocused $ \w -> do
ws <- getWindows
let (before, _:after) = span (/=w) ws
let toFocus = g $ after ++ before
floats <- getFloats
case filter (f . flip elem floats) toFocus of
[] -> return ()
w':_ -> focus w'
focusNonFloatUp :: X ()
focusNonFloatUp = alt2 (G.Modify G.focusUp) $ focusHelper not reverse
focusNonFloatDown :: X ()
focusNonFloatDown = alt2 (G.Modify G.focusDown) $ focusHelper not id
focusFloatUp :: X ()
focusFloatUp = focusHelper id reverse
focusFloatDown :: X ()
focusFloatDown = focusHelper id id
-- ** Groups-specific actions
wrap :: G.ModifySpec -> X ()
wrap = sendMessage . G.Modify
-- | Swap the focused group with the previous one
swapGroupUp :: X ()
swapGroupUp = wrap G.swapGroupUp
-- | Swap the focused group with the next one
swapGroupDown :: X ()
swapGroupDown = wrap G.swapGroupDown
-- | Swap the focused group with the master group
swapGroupMaster :: X ()
swapGroupMaster = wrap G.swapGroupMaster
-- | Move the focus to the previous group
focusGroupUp :: X ()
focusGroupUp = wrap G.focusGroupUp
-- | Move the focus to the next group
focusGroupDown :: X ()
focusGroupDown = wrap G.focusGroupDown
-- | Move the focus to the master group
focusGroupMaster :: X ()
focusGroupMaster = wrap G.focusGroupMaster
-- | Move the focused window to the previous group. The 'Bool' argument
-- determines what will be done if the focused window is in the very first
-- group: Wrap back to the end ('True'), or create a new group before
-- it ('False').
moveToGroupUp :: Bool -> X ()
moveToGroupUp b = wrap (G.moveToGroupUp b)
-- | Move the focused window to the next group. The 'Bool' argument
-- determines what will be done if the focused window is in the very last
-- group: Wrap back to the beginning ('True'), or create a new group after
-- it ('False').
moveToGroupDown :: Bool -> X ()
moveToGroupDown b = wrap (G.moveToGroupDown b)
-- | Move the focused window to a new group before the current one
moveToNewGroupUp :: X ()
moveToNewGroupUp = wrap G.moveToNewGroupUp
-- | Move the focused window to a new group after the current one
moveToNewGroupDown :: X ()
moveToNewGroupDown = wrap G.moveToNewGroupDown
-- | Split the focused group in two at the position of the focused
-- window.
splitGroup :: X ()
splitGroup = wrap G.splitGroup

View File

@@ -0,0 +1,133 @@
{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
{-# LANGUAGE MultiParamTypeClasses, Rank2Types #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Layout.Groups.Wmii
-- Copyright : Quentin Moser <moserq@gmail.com>
-- License : BSD-style (see LICENSE)
--
-- Maintainer : orphaned
-- Stability : stable
-- Portability : unportable
--
-- A wmii-like layout algorithm.
--
-----------------------------------------------------------------------------
module XMonad.Layout.Groups.Wmii ( -- * Usage
-- $usage
wmii
, zoomGroupIn
, zoomGroupOut
, zoomGroupReset
, toggleGroupFull
, groupToNextLayout
, groupToFullLayout
, groupToTabbedLayout
, groupToVerticalLayout
-- * Useful re-exports
, shrinkText
, defaultTheme
, module XMonad.Layout.Groups.Helpers ) where
import XMonad hiding ((|||))
import qualified XMonad.Layout.Groups as G
import XMonad.Layout.Groups.Examples
import XMonad.Layout.Groups.Helpers
import XMonad.Layout.Tabbed
import XMonad.Layout.Named
import XMonad.Layout.Renamed
import XMonad.Layout.LayoutCombinators
import XMonad.Layout.MessageControl
import XMonad.Layout.Simplest
-- $usage
-- This module provides a layout inspired by the one used by the wmii
-- (<http://wmii.suckless.org>) window manager.
-- Windows are arranged into groups in a horizontal row, and each group can lay out
-- its windows
--
-- * by maximizing the focused one
--
-- * by tabbing them (wmii uses a stacked layout, but I'm too lazy to write it)
--
-- * by arranging them in a column.
--
-- As the groups are arranged in a 'ZoomRow', the relative width of each group can be
-- increased or decreased at will. Groups can also be set to use the whole screen
-- whenever they have focus.
--
-- You can use the contents of this module by adding
--
-- > import XMonad.Layout.Groups.Wmii
--
-- to the top of your @.\/.xmonad\/xmonad.hs@, and adding 'wmii'
-- (with a 'Shrinker' and decoration 'Theme' as
-- parameters) to your layout hook, for example:
--
-- > myLayout = wmii shrinkText defaultTheme
--
-- To be able to zoom in and out of groups, change their inner layout, etc.,
-- create key bindings for the relevant actions:
--
-- > ((modMask, xK_f), toggleGroupFull)
--
-- and so on.
--
-- For more information on how to extend your layout hook and key bindings, see
-- "XMonad.Doc.Extending".
--
-- Finally, you will probably want to be able to move focus and windows
-- between groups in a consistent fashion. For this, you should take a look
-- at the "XMonad.Layout.Groups.Helpers" module, whose contents are re-exported
-- by this module.
-- | A layout inspired by wmii
wmii s t = G.group innerLayout zoomRowG
where column = named "Column" $ Tall 0 (3/100) (1/2)
tabs = named "Tabs" $ Simplest
innerLayout = renamed [CutWordsLeft 3]
$ addTabs s t
$ ignore NextLayout
$ ignore (JumpToLayout "") $ unEscape
$ column ||| tabs ||| Full
-- | Increase the width of the focused group
zoomGroupIn :: X ()
zoomGroupIn = zoomColumnIn
-- | Decrease the size of the focused group
zoomGroupOut :: X ()
zoomGroupOut = zoomColumnOut
-- | Reset the size of the focused group to the default
zoomGroupReset :: X ()
zoomGroupReset = zoomColumnReset
-- | Toggle whether the currently focused group should be maximized
-- whenever it has focus.
toggleGroupFull :: X ()
toggleGroupFull = toggleGroupFull
-- | Rotate the layouts in the focused group.
groupToNextLayout :: X ()
groupToNextLayout = sendMessage $ escape NextLayout
-- | Switch the focused group to the \"maximized\" layout.
groupToFullLayout :: X ()
groupToFullLayout = sendMessage $ escape $ JumpToLayout "Full"
-- | Switch the focused group to the \"tabbed\" layout.
groupToTabbedLayout :: X ()
groupToTabbedLayout = sendMessage $ escape $ JumpToLayout "Tabs"
-- | Switch the focused group to the \"column\" layout.
groupToVerticalLayout :: X ()
groupToVerticalLayout = sendMessage $ escape $ JumpToLayout "Column"

View File

@@ -65,7 +65,7 @@ instance LayoutClass Grid Window where
doLayout (GridRatio d m) r w = flip (,) Nothing . arrange d m r (integrate w)
replicateS :: Int -> (a -> (b, a)) -> a -> ([b], a)
replicateS n = runState . replicateM n . State
replicateS n f = runState . replicateM n $ do (a,s) <- gets f; put s; return a
doColumn :: Dimension -> Dimension -> Dimension -> [(D -> D)] -> [D]
doColumn width height k adjs =

View File

@@ -25,12 +25,11 @@ module XMonad.Layout.IM (
-- * TODO
-- $todo
Property(..), IM(..), withIM, gridIM,
AddRoster,
) where
import XMonad
import qualified XMonad.StackSet as S
import Data.List
import XMonad.Layout (splitHorizontallyBy)
import XMonad.Layout.Grid
import XMonad.Layout.LayoutModifier
import XMonad.Util.WindowProperties

View File

@@ -0,0 +1,183 @@
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}
----------------------------------------------------------------------------
-- |
-- Module : XMonad.Layout.ImageButtonDecoration
-- Copyright : (c) Jan Vornberger 2009
-- Alejandro Serrano 2010
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : trupill@gmail.com
-- Stability : unstable
-- Portability : not portable
--
-- A decoration that includes small image buttons on both ends which invoke
-- various actions when clicked on: Show a window menu (see
-- "XMonad.Actions.WindowMenu"), minimize, maximize or close the window.
--
-- Note: For maximizing and minimizing to actually work, you will need
-- to integrate "XMonad.Layout.Maximize" and "XMonad.Layout.Minimize" into your
-- setup. See the documentation of those modules for more information.
--
-----------------------------------------------------------------------------
-- This module is mostly derived from "XMonad.Layout.DecorationAddons"
-- and "XMonad.Layout.ButtonDecoration"
module XMonad.Layout.ImageButtonDecoration
( -- * Usage:
-- $usage
imageButtonDeco
, defaultThemeWithImageButtons
, imageTitleBarButtonHandler
, ImageButtonDecoration
) where
import XMonad
import XMonad.Layout.Decoration
import XMonad.Layout.DecorationAddons
import XMonad.Util.Image
import XMonad.Actions.WindowMenu
import XMonad.Layout.Minimize
import XMonad.Layout.Maximize
-- $usage
-- You can use this module with the following in your
-- @~\/.xmonad\/xmonad.hs@:
--
-- > import XMonad.Layout.ImageButtonDecoration
--
-- Then edit your @layoutHook@ by adding the ImageButtonDecoration to
-- your layout:
--
-- > myL = imageButtonDeco shrinkText defaultThemeWithImageButtons (layoutHook defaultConfig)
-- > main = xmonad defaultConfig { layoutHook = myL }
--
-- The buttons' dimension and placements
buttonSize :: Int
buttonSize = 10
menuButtonOffset :: Int
menuButtonOffset = 4
minimizeButtonOffset :: Int
minimizeButtonOffset = 32
maximizeButtonOffset :: Int
maximizeButtonOffset = 18
closeButtonOffset :: Int
closeButtonOffset = 4
-- The images in a 0-1 scale to make
-- it easier to visualize
convertToBool' :: [Int] -> [Bool]
convertToBool' = map (\x -> x == 1)
convertToBool :: [[Int]] -> [[Bool]]
convertToBool = map convertToBool'
menuButton' :: [[Int]]
menuButton' = [[1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1],
[1,1,0,0,0,0,0,0,1,1],
[1,1,0,0,0,0,0,0,1,1],
[1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1]]
menuButton :: [[Bool]]
menuButton = convertToBool menuButton'
miniButton' :: [[Int]]
miniButton' = [[0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0],
[1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1]]
miniButton :: [[Bool]]
miniButton = convertToBool miniButton'
maxiButton' :: [[Int]]
maxiButton' = [[1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1],
[1,1,0,0,0,0,0,0,1,1],
[1,1,0,0,0,0,0,0,1,1],
[1,1,0,0,0,0,0,0,1,1],
[1,1,0,0,0,0,0,0,1,1],
[1,1,0,0,0,0,0,0,1,1],
[1,1,0,0,0,0,0,0,1,1],
[1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1]]
maxiButton :: [[Bool]]
maxiButton = convertToBool maxiButton'
closeButton' :: [[Int]]
closeButton' = [[1,1,0,0,0,0,0,0,1,1],
[1,1,1,0,0,0,0,1,1,1],
[0,1,1,1,0,0,1,1,1,0],
[0,0,1,1,1,1,1,1,0,0],
[0,0,0,1,1,1,1,0,0,0],
[0,0,0,1,1,1,1,0,0,0],
[0,0,1,1,1,1,1,1,0,0],
[0,1,1,1,0,0,1,1,1,0],
[1,1,1,0,0,0,0,1,1,1],
[1,1,0,0,0,0,0,0,1,1]]
closeButton :: [[Bool]]
closeButton = convertToBool closeButton'
-- | A function intended to be plugged into the 'decorationCatchClicksHook' of a decoration.
-- It will intercept clicks on the buttons of the decoration and invoke the associated action.
-- To actually see the buttons, you will need to use a theme that includes them.
-- See 'defaultThemeWithImageButtons' below.
imageTitleBarButtonHandler :: Window -> Int -> Int -> X Bool
imageTitleBarButtonHandler mainw distFromLeft distFromRight = do
let action = if (fi distFromLeft >= menuButtonOffset &&
fi distFromLeft <= menuButtonOffset + buttonSize)
then focus mainw >> windowMenu >> return True
else if (fi distFromRight >= closeButtonOffset &&
fi distFromRight <= closeButtonOffset + buttonSize)
then focus mainw >> kill >> return True
else if (fi distFromRight >= maximizeButtonOffset &&
fi distFromRight <= maximizeButtonOffset + buttonSize)
then focus mainw >> sendMessage (maximizeRestore mainw) >> return True
else if (fi distFromRight >= minimizeButtonOffset &&
fi distFromRight <= minimizeButtonOffset + buttonSize)
then focus mainw >> minimizeWindow mainw >> return True
else return False
action
defaultThemeWithImageButtons :: Theme
defaultThemeWithImageButtons = defaultTheme {
windowTitleIcons = [ (menuButton, CenterLeft 3),
(closeButton, CenterRight 3),
(maxiButton, CenterRight 18),
(miniButton, CenterRight 33) ]
}
imageButtonDeco :: (Eq a, Shrinker s) => s -> Theme
-> l a -> ModifiedLayout (Decoration ImageButtonDecoration s) l a
imageButtonDeco s c = decoration s c $ NFD True
data ImageButtonDecoration a = NFD Bool deriving (Show, Read)
instance Eq a => DecorationStyle ImageButtonDecoration a where
describeDeco _ = "ImageButtonDeco"
decorationCatchClicksHook _ mainw dFL dFR = imageTitleBarButtonHandler mainw dFL dFR
decorationAfterDraggingHook _ (mainw, _) decoWin = focus mainw >> handleScreenCrossing mainw decoWin >> return ()

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