1064 Commits
v0.1 ... v0.14

Author SHA1 Message Date
Peter Simons
71cb355948 travis.yml: we can now run "cabal check" successfully 2018-07-30 11:06:02 +02:00
Peter Simons
19069b3d4b xmonad.cabal: drop hard-coded profiling mode
Hackage won't accept the package with that "hack" in place. If you want to
compile with profiling enabled, please configure the build with
--enable-profiling via "cabal" or "stack" or whatever build driver you're
using.
2018-07-30 11:03:53 +02:00
Peter Simons
969fca9406 Merge pull request #157 from xmonad/travis
Travis
2018-07-30 10:44:27 +02:00
Peter Simons
61f00e65f1 Merge pull request #169 from mimi1vx/patch-1
Allow  X11-1.9
2018-07-30 09:43:07 +02:00
Peter Simons
db11089e70 travis.yml: re-generate with latest version of make-travis-yml 2018-07-30 09:36:19 +02:00
Peter Simons
e601a7d16d xmonad.cabal: updated tested-with fields to the latest major release, respectively 2018-07-30 09:33:03 +02:00
Peter Simons
0dd23bddfa Merge branch 'master' into travis. 2018-07-30 09:32:12 +02:00
Peter Simons
55b14d4850 Bump version number to 0.14 for upcoming release. 2018-07-30 09:29:12 +02:00
Ondřej Súkup
9df514b378 Allow X11-1.9 2018-05-15 09:45:36 +02:00
geekosaur
ecf1a0ca0d Merge pull request #163 from aplaice/patch-1
Fix typo Utils -> Util
2018-04-18 18:25:18 -04:00
aplaice
d216e95f97 Fix typo Utils -> Util
This is extremely minor, but it results in haddock incorrectly
hyperlinking XMonad.Utils.ExtensibleState at
https://hackage.haskell.org/package/xmonad-0.13/docs/XMonad-Core.html#v:extensibleState
2018-04-11 23:46:11 +02:00
Brent Yorgey
af3d3818c8 Revert "remove unnecessary profiling flag"
This reverts commit d065038c8a.

Put profiling flag back, and comment out 'cabal check' test in .travis.yml
2018-03-21 22:22:58 -05:00
Brent Yorgey
d065038c8a remove unnecessary profiling flag
It was making cabal check unhappy.
2018-03-21 15:34:27 -05:00
Brent Yorgey
10bc213349 include libxrandr-dev 2018-03-21 15:24:54 -05:00
Brent Yorgey
d22d93b43f try updating travis config 2018-03-21 14:58:54 -05:00
Brent Yorgey
871a80fee7 add GHC 8.4.1 to tested-with 2018-03-21 14:58:38 -05:00
Brent Yorgey
2d59f5157c update GHC version number to 8.4.1 2018-03-21 14:58:25 -05:00
Brent Yorgey
0738262d9e Merge pull request #153 from vmchale/master
update to work with latest GHC
2018-03-21 14:54:30 -05:00
Brent Yorgey
63d6a66133 Merge branch 'master' into master 2018-03-21 14:52:50 -05:00
Brent Yorgey
fe6215d309 Merge pull request #156 from MichielDerhaeg/compat
restored compatability with GHC versions prior to 8.0.1
2018-03-21 14:50:17 -05:00
Michiel Derhaeg
c3cb4ad65f forgot to remote windows specific code 2018-03-18 00:08:03 +01:00
Michiel Derhaeg
126f891d11 restored compatability with GHC versions prior to 8.0.1 2018-03-17 23:23:11 +01:00
Vanessa McHale
d3383ce0f5 make it work w/ xmonad-testing 2018-02-05 18:29:14 -06:00
Vanessa McHale
c96a59fa0d update to work with latest GHC 2018-02-05 17:46:57 -06:00
Peter J. Jones
12a45b4b99 Merge pull request #88 from Javran/master
fix xmonad/xmonad#87
2017-09-13 18:07:04 -07:00
Javran Cheng
462957b2f0 fix xmonad/xmonad#87
switch focus when mouse is entering a workspace
but not moving into a window (w' == 0)

for magic number 0 in w' == 0
see discussion in https://github.com/xmonad/xmonad/pull/88#pullrequestreview-62489502
2017-09-13 19:28:02 -04:00
Peter J. Jones
2e6312776b Merge pull request #111 from YoYoYonnY/origin/patch-1
Safer string quoting for help message
2017-05-31 10:05:03 -07:00
Jonne Ransijn
3897cab7c9 Safer string quoting for help message
Using `show` to quote help string instead of hard-coding it.
Allows for quotes and other characters to be placed inside the help string.
2017-05-09 00:25:48 +02:00
Peter Jones
10b843ad21 Add a section on rebashing and squashing 2017-04-10 16:58:45 -07:00
Peter J. Jones
bc320b69da Merge pull request #91 from pjones/pjones/remove-state-file
Remove the xmonad state file after reading it
2017-04-10 10:47:03 -07:00
Peter Jones
89a8cc88c3 Remove the xmonad state file after reading it
Tries to make sure IO is not lazy so the file is processed before it
is removed from the file system.

Fixes #86 and friends.
2017-03-30 16:19:26 -07:00
Peter Jones
76f4a16258 Add a stack.yaml file for testing and easy Hackage upload 2017-02-10 16:20:01 -07:00
Peter Jones
8f2eb540d7 Update documentation after final release review 2017-02-10 15:48:44 -07:00
Peter Jones
ba2d75b930 Build the man page for 0.13 2017-02-10 15:46:45 -07:00
Peter Jones
acf0652952 Add a release date 2017-02-09 16:25:41 -07:00
Peter Jones
e4d231920c Bump version to 0.13 2017-02-09 16:09:52 -07:00
Peter J. Jones
980828feea Merge pull request #76 from SirBoonami/master
Rare crash fix due to uncaught exception from `getWindowAttributes`
2017-02-09 15:04:41 -07:00
Felix Hirn
2e5ae02059 Updated CHANGES.md 2017-02-09 22:34:26 +01:00
Felix Hirn
50eb1844eb Fixed a crash due to an unhandled getWindowAttributes exception 2017-02-09 22:28:57 +01:00
Peter Jones
f18bda7dc7 Having an executable build script implies force = True' in recompile'
This is slight change to the original implementation.  This version
forces a recompile if XMonad detects a custom build script.  The
previous version took into consideration the time stamps of the source
files.

For a custom build script, the source files may be located in another
location, or there could be dependencies unknown to XMonad.  Better to
just always call the build script and let it work out if something
needs to be built.
2017-02-08 19:48:42 -07:00
Peter Jones
2d8cad02fe Improve function docs for setWindowBorderWithFallback 2017-02-08 16:53:40 -07:00
Peter Jones
2baab28602 When looking for a directory, prefer ~/.xmonad over XDG BDS
This fixes issue #71
2017-02-07 13:28:53 -07:00
Peter J. Jones
ef65f901ce Merge pull request #65 from HebaruSan/focus-race-condition
Don't send focus events for the wrong windows
2017-02-06 17:29:32 -07:00
Peter Jones
f2da028ff9 Add CONTRIBUTING.md and GitHub templates 2017-01-12 12:23:48 -07:00
Brent Yorgey
bad3ce7a5e Merge pull request #62 from pjones/feature/recompile
Support for custom config locations and recompile strategies
2017-01-03 17:56:40 -05:00
Peter Jones
e1c555e3e6 Implement recommendations from Brent's review 2017-01-03 15:46:07 -07:00
Peter Jones
ab20f7df8d Stop using the term XDG unqualified
This change makes it clear that xmonad can use the "XDG Base Directory
Specification" a la the directory package without making any other XDG
claims.
2017-01-03 15:15:26 -07:00
Peter Jones
a70bf6a6a3 Fix another compatibility issue with GHC 7.6.x and 7.8.x 2017-01-03 15:15:26 -07:00
Peter Jones
f58b2399bd Fix compatibility issue with GHC 7.6.x and 7.8.x 2017-01-03 15:15:25 -07:00
Peter Jones
91d23656a3 Fix compile issue when using directory-1.2.3 2017-01-03 15:15:24 -07:00
Peter Jones
d6b6189cc1 Add release notes for changes in this PR 2017-01-03 15:15:23 -07:00
Peter Jones
0248e3c9fa Custom entry point for people using build tools (cabal, stack, etc.)
The xmonadNoArgs function is now exposed as launch.  This allows users
to start xmonad from a custom binary and skip the configuration
complication check. (This is related to issue #62.)

In order to make the new launch function easier to use, resume state
has been removed from the command line and is now stored in a
temporary file.  As a bonus this fixes issue #12.

This commit also includes a method of migrating from older command
line state to the newer state file.  This should allow you have an
older xmonad instance start a newer xmonad and maintain state.
2017-01-03 15:15:22 -07:00
Peter Jones
40fc10b6a5 Allow customization of xmonad directories
Users can specify directory overrides via environment variables.  If
those aren't set, xmonad now prefers XDG directories.  If ~/.xmonad
exists and none of the others do, it will be used instead.

See: xmonad/xmonad#61
2017-01-03 15:15:22 -07:00
Paul Hebble
3a140badf5 Don't send focus events for the wrong windows
Prevents focus switching loop with UpdatePointer.
From https://code.google.com/archive/p/xmonad/issues/200
2016-12-24 21:01:44 -06:00
Brent Yorgey
2b103ede55 Merge pull request #64 from bennofs/fix-63
fix #63: window jumping to origin position when dragging
2016-12-21 13:49:57 -05:00
Benno Fünfstück
4565e2c90e fix #63: window jumping to origin position when dragging
We need to make sure that the StackSet contains the right
position for the window at all times while dragging. Previously,
the window was only placed at a different position. If, for any
reason, a layout refresh happens while the window is being dragged,
then the window will jump back to the old position because the StackSet
still contains the position of the window where it was as the drag started.

This patch fixes that issue by calling float after each mouse movement, which
ensures that the position for the window is updated in the StackSet.

Fixes #63
2016-12-15 18:42:54 +01:00
Peter Jones
285ee2f836 Add build status badge from Travis 2016-12-14 14:46:52 -07:00
Peter J. Jones
7e9c9ccb1f Merge pull request #59 from xmonad/feature/fix-PR9
Fetch border color from the window's colormap
2016-12-14 14:39:08 -07:00
Peter Jones
dc078490d0 Guard most calls to getWindowAttributes since it may throw an exception
This is a continuation of the work done by Adam Sjøgren (@asjo) to
resolve an issue where RGBA windows have transparent borders.  It also
fixes bugs related to windows suddenly disappearing right before
xmonad calls getWindowAttributes.

For more information see xmonad/xmonad#9
2016-12-14 14:18:45 -07:00
Peter Jones
202e239ea4 Refactor xmonad/xmonad#9 and remove explicit exception handling 2016-12-14 14:18:44 -07:00
Peter J. Jones
e159ec36fe Merge pull request #53 from Philonous/rebuild_script
Add support for (re-) building using script
2016-12-13 12:24:41 -07:00
Philipp Balzarek
0b1ccc75ef update CHANGES.md 2016-12-10 11:21:06 +01:00
Philipp Balzarek
b0f9a3d0b9 clean up build-script handling 2016-12-10 11:10:04 +01:00
Philipp Balzarek
75d297a633 Add support for rebuild script
(#46)
2016-12-10 11:10:04 +01:00
Peter J. Jones
5f5e737d9c Merge pull request #57 from xmonad/prof-flag
only turn on -prof -auto-all with profiling flag
2016-12-08 11:00:52 -07:00
geekosaur
a39ed3ee1b Merge pull request #58 from xmonad/manual-testing
cabal: set 'testing' flag to manual
2016-11-15 13:27:18 -05:00
Brent Yorgey
e05a046bca cabal: set 'testing' flag to manual 2016-11-15 05:12:40 -06:00
Brent Yorgey
12ddc800ab only turn on -prof -auto-all with profiling flag 2016-11-09 10:20:51 -06:00
Brent Yorgey
2fab1bb9f5 test GHC 8 on Travis 2016-11-09 10:09:01 -06:00
Brent Yorgey
1b17d1c378 Merge pull request #48 from mschristiansen/tests
Fix failing tests on GHC 8 and reduce warnings.
2016-11-09 11:06:46 -05:00
Mikkel Christiansen
f490ced673 Fix failing tests on GHC 8 and reduce warnings.
Fix test failures on GHC 8 for `abort` and `new_abort` caused by `error`
appending the stack trace to the error message (since base
4.9.0.0)[1]. This fixes #36.

An alternative is to use `errorWithoutStackTrace` (new in base 4.9.0.0),
but this then requires use of CPP for backwards compatibility.

Remove type constraints prompting GHC to warn about redundant
constraints.

Tested with 7.6.3, 7.8.4, 7.10.3, 8.0.1 (all on NixOS).

[1] https://hackage.haskell.org/package/base-4.9.0.0/docs/GHC-Stack.html
2016-11-09 12:03:34 +02:00
Brent Yorgey
0919ecfbde Merge pull request #51 from mgsloan/no-unicode-with-xmessage
Replace unicode characters in ghc error messages
2016-11-08 23:09:30 -05:00
Brent Yorgey
41b7b1341e Merge pull request #33 from dlahoti/patch-1
replace "XXX comment me" with actual (albeit rudimentary) comments in `mouseMoveWindow` and `mouseResizeWindow`
2016-11-08 23:01:07 -05:00
Michael Sloan
0f0aa5e8cb Replace unicode characters in ghc error messages 2016-10-14 17:40:51 -07:00
dlahoti
ad4417c8e0 clicked -> dragged 2016-05-15 10:46:14 -04:00
dlahoti
b0f7643cc5 replace "XXX comment me" with actual comments 2016-05-15 10:32:28 -04:00
Francesco Ariis
8b055621e9 clarify GenerateManpage.hs license 2016-05-12 11:08:37 -05:00
geekosaur
dc6a972bc1 Merge pull request #29 from windo/fix_help
help: correct section for workspace switching
2016-03-18 08:49:31 -04:00
Siim Põder
e4a3eede18 help: correct section for workspace switching 2016-03-18 09:49:15 +00:00
Brent Yorgey
a0ffe7e47d pandoc, etc. should not be a dependency when not building generatemanpage 2015-12-18 14:23:38 -06:00
Brent Yorgey
b00b94fda7 Merge pull request #13 from pjones/release-0.12
Release 0.12
2015-12-18 11:25:07 -06:00
Peter Jones
45a78ba802 Finial tweaks before release 2015-12-14 13:30:55 -07:00
Peter Jones
4c0717e9cc Make it easier to update the man page 2015-12-11 11:19:40 -07:00
Peter Jones
30b4ff5e40 Update development references (darcs, code.google.com, etc.)
* All references to darcs have been updated to git

  * Most Google Code references have been changed to GitHub

  * References to specific issues at code.google.com have been left
    alone

  * Updated the GenerateManpage.hs to work with the latest version of
    pandoc
2015-12-11 11:17:26 -07:00
Peter Jones
b68ebc797a Remove references to development snapshots from darcs 2015-12-11 10:34:31 -07:00
Peter Jones
eb4ef5b23f Update CONFIG instructions: defaultConfig -> def 2015-12-11 10:00:53 -07:00
Peter Jones
73224be21b Bring in entries from https://wiki.haskell.org/Xmonad/Notable_changes_since_0.11 2015-12-09 12:54:14 -07:00
Peter Jones
7e287ec815 Revert a typo that wasn't actually a typo 2015-12-08 16:46:16 -07:00
Peter Jones
60f472faa2 Fix a couple of links (darcs -> git) 2015-12-08 16:28:56 -07:00
Peter Jones
bd72c6e1e2 Add CHANGES.md 2015-12-08 13:50:20 -07:00
Peter Jones
b5402e76d3 Fix some bad formatting 2015-12-08 13:31:54 -07:00
Peter Jones
39dc00b16f Add a file extension to the README file to make GitHub happy 2015-12-08 13:30:11 -07:00
Peter Jones
038f77de5a Reformat the README as proper markdown for GitHub and Hackage 2015-12-08 13:28:08 -07:00
Adam Vogt
59e731ea11 minor update to STYLE and TODO 2015-11-28 16:23:24 -05:00
Brent Yorgey
3ce9dcbbb5 add generated .travis.yml 2015-11-06 14:49:32 -06:00
Brent Yorgey
f25afdab9f .cabal: update tested-with field 2015-11-06 14:49:15 -06:00
brandon s allbery kf8nh
577d5ae968 Add gitignore
Shamelessly ganked from cabal, with obvious project-related files removed.
2015-08-22 13:32:54 -04:00
Josh Holland
29bcd465c2 Bump dependency on utf8-string
The release of utf8-string version 1 just removed some deprecated APIs
that are not used by XMonad.

Fixes #598.
2015-05-05 10:27:18 +00:00
Adam Vogt
307b82a53d Make ~/.xmonad/xmonad-$arch-$os handle args like /usr/bin/xmonad 2015-04-14 18:48:21 +00:00
Adam Vogt
197b0091f8 remove unused FFI pragma 2015-03-27 19:27:59 +00:00
Adam Vogt
69c5dae00d Avoid using instances removed in QuickCheck-2.7
see https://github.com/nick8325/quickcheck/issues/31 for details
2015-03-01 13:50:49 +00:00
Adam Vogt
28c3482411 use setLocale properly
passing in Nothing returns the locale, while Just "" sets the locale according
to environment variables (which is what was being done before).

Thanks to geekosaur & v_v for finding this.
2015-02-27 02:52:28 +00:00
Adam Vogt
73ee008cf6 generate man/xmonad.1 man/xmonad.1.html with a more recent pandoc (1.13) 2014-12-22 00:40:33 +00:00
Adam Vogt
82a1cae123 build with ghc-6.12 again 2014-08-15 03:38:08 +00:00
Adam Vogt
d01b913594 depend on the setlocale package 2014-10-20 14:10:06 +00:00
Adam Vogt
d9e3ebf531 don't encode paths for spawnPID (#348) 2014-10-20 14:04:10 +00:00
Adam Vogt
252c9d5eee stop floating Gimp with the default manageHook
most people have probably moved on to gimp-2.8,
which doesn't really need to be floating
2014-07-04 22:40:25 +00:00
Joey Hess
5f0b1601d5 needs update for mplayer2
xmonad floats mplayer by default. However, Debian has switched to
mplayer2, and so on upgrade, it will stop floating. This can be easily
fixed in the user's config file, but here is a patch that avoids
bothering the user with breakage on upgrade.
2014-07-03 05:43:59 +00:00
Adam Vogt
d60791e3f5 minor formatting of manpage 2014-05-11 17:17:35 +00:00
Adam Vogt
f0054fdde7 update GenerateManpage to pandoc 1.12 2014-05-11 17:14:41 +00:00
Adam Vogt
a9de363b14 make GenerateManpage look in src/ 2014-05-11 17:14:07 +00:00
Daniel Wagner
7eb6ba0126 use only POSIX-standard regexen in GenerateManpage 2014-05-11 15:46:02 +00:00
Adam Vogt
f03d2cdf74 make the check for overflow cleaner 2014-05-07 02:49:30 +00:00
Adam Vogt
16c0cb9a33 make cabal test show a FAIL when at least one test fails 2014-05-03 05:46:29 +00:00
Adam Vogt
fdf3fb2c58 remove unnecessary CPP 2014-05-03 04:48:15 +00:00
Adam Vogt
22d5e7eaa3 add missing files to sdist 2014-05-03 04:47:40 +00:00
Adam Vogt
f837b830fc note -fno-warn-unused-do-bind in STYLE 2014-05-03 04:41:05 +00:00
Adam Vogt
939c0558e6 update README 2014-05-03 04:40:52 +00:00
Adam Vogt
fbd406eb03 add some more forgotten properties 2014-05-03 03:41:44 +00:00
Adam Vogt
ecde376224 make hpc report cover the testsuite too 2014-05-03 03:41:25 +00:00
Adam Vogt
edf3394821 run more tests (and add a couple) 2014-05-03 02:11:03 +00:00
Adam Vogt
20be322b08 put hpc reports in dist/hpc/ 2014-05-02 19:29:07 +00:00
Adam Vogt
f8f53fdff8 add forgotten tests back 2014-05-02 19:28:58 +00:00
Adam Vogt
1da1e2e21e updated hpc 2014-05-02 18:49:04 +00:00
Adam Vogt
4026075bc6 clean up cabal file
We don't support ghc-6.6 anymore, so no need to include this split_base stuff.
2014-05-02 18:07:21 +00:00
Adam Vogt
8863761d66 update testsuite (mostly due Jesper Reenberg)
* use quickcheck2
* run them using cabal's test-suite field
* split up Properties into separate files
2014-05-02 18:01:46 +00:00
Adam Vogt
d67dcd8c4b hack to avoid crash when fewer workspaces than screens (#543) 2014-05-02 17:59:10 +00:00
Adam Vogt
aa84841289 OPTIONS_GHC is the preferred pragma name 2014-05-02 17:57:34 +00:00
Adam Vogt
d10abdcdd0 move library part to src/ 2014-05-02 17:51:59 +00:00
Adam Vogt
3073826dfc avoid warnings from missing Prelude.catch in ghc>=7.6 2014-05-02 05:58:23 +00:00
Adam Vogt
daed0062c6 derive Applicative instance for Query 2014-05-02 05:57:43 +00:00
Adam Vogt
abd737cfb4 Bump version to 0.12
This is to make contrib build failures resulting from by data-default
lead people to do the right thing: update xmonad-core.
2013-07-20 19:21:24 +00:00
Daniel Wagner
e719be4e69 warning police: name userCodeDef's argument defValue instead of def 2013-05-28 16:44:01 +00:00
Daniel Wagner
ec1a20c727 depend on data-default, and deprecate the monomorphic name defaultConfig 2013-05-28 00:35:31 +00:00
Daniel Wagner
8f039ec434 use "modm" instead of "modMask" in the sample config 2013-01-06 17:44:14 +00:00
Daniel Wagner
057fcc5162 define the "help" string in the sample configuration bundled with xmonad 2013-01-06 17:42:54 +00:00
mwlochbaum
8e7634f543 configurableEventMasks 2013-02-05 18:28:58 +00:00
Daniel Wagner
40cb12ce17 Grab all keycodes linked to each keysym, not just one
This patch is based heavily on the one contributed by
svein.ove@aas.no, but updated to avoid causing a conflict and to work
with the newest X11 bindings. The name of the patch (and comment
below) are copied verbatim from his patch.

XKeysymToKeycode only gives the first code bound to a given symbol. To
handle the case where multiple keys are bound to the same symbol,
XKeycodeToKeysym is used instead, searching through all possible
keycodes for each sym.
2013-01-18 22:54:46 +00:00
Adam Vogt
b803fd74a5 Issue 135 use wa_border_width for floating windows (neoraider) 2013-01-15 17:07:15 +00:00
Adam Vogt
d386a230f6 Add flags for call to ghc closing issue 240
The -main-is flag goes back to at least ghc 6.10, and maybe the warning that
this otherwise redundant flag enables (when xmonad.hs isn't a  module Main)
also dates back that far.
2013-01-01 03:50:34 +00:00
Adam Vogt
e87456ab77 bump cabal-version to satisfy hackage 2013-01-01 01:40:56 +00:00
Adam Vogt
cdc22f0849 TAG 0.11 2013-01-01 01:30:31 +00:00
Adam Vogt
70413b2e22 Bump version to 0.11 2012-12-31 18:48:10 +00:00
Adam Vogt
67ffde0dfb Add more metadata to cabal file 2012-12-31 18:46:52 +00:00
Adam Vogt
d904fb1cc4 Update generated manpage (and releaseDate in util/GenerateManpage.hs) 2012-12-31 16:34:03 +00:00
Adam Vogt
4120be8ba0 Copy help binding from XMonad.Config to man/xmonad.hs 2012-12-31 16:33:05 +00:00
Adam Vogt
e015155131 Shorter hyperlinks to hackage in README. 2012-12-31 10:53:58 +00:00
Adam Vogt
4c1536cd18 Add clickJustFocuses option to template configuration. 2012-12-31 10:44:20 +00:00
Adam Vogt
a34a5e979a Add configuration option clickToFocus (issue 225)
To summarize this allows clicks which change the focus to also be passed on to
that window.
2012-01-03 01:39:16 +00:00
conrad.irwin
38faddf9de pass mouse clicks on to focused windows (experimental)
Originally: http://www.haskell.org/pipermail/xmonad/2008-June/005807.html
2011-05-25 04:34:13 +00:00
Adam Vogt
3ab2b28711 HCAR.tex convert line endings. 2012-11-18 19:40:06 +00:00
gwern0
934ff6a562 HCAR.tex: update to Janis's master version per his instructions 2012-11-18 01:03:10 +00:00
Adam Vogt
f8b07d8956 Add generated manpage and html manpage to the repo.
The intention of adding these files to the data-files
is so that they get included in the upload to hackage:
people might like manpage but not have to install pandoc.

It's not really clear that this is the best solution.
2012-11-08 23:11:39 +00:00
Adam Vogt
67d436a4e6 Resolve conflicts Geoff Reedy's window focus hack. 2010-02-22 14:45:12 +00:00
Geoff Reedy
c6fef373dc Give focus to windows that don't set the input hint 2009-10-10 23:19:07 +00:00
Geoff Reedy
2d4f304c0a implement the ICCCM WM_TAKE_FOCUS protocol 2009-06-22 05:19:11 +00:00
Geoff Reedy
1df8ea3d0e track currently processing event 2009-06-22 03:56:49 +00:00
Adam Vogt
490719c035 resolve HCar.tex conflict 2012-11-08 22:35:14 +00:00
gwern0
3cd001e8df HCAR.tex: update with Janis's master version 2012-10-03 19:04:25 +00:00
gwern0
b0dda7b351 HCAR.tex: update per Janis 2012-05-16 21:13:52 +00:00
gwern0
d8495adf0d HCAR.tex: update per Janis 2012-05-13 21:15:22 +00:00
gwern0
06f35a650e Config.hs: implement mod-shift-/ newbie keybinding guide per http://code.google.com/p/xmonad/issues/detail?id=182 2012-01-13 01:04:10 +00:00
gwern0
56f5ecb320 Config.hs: rm commented out keybinding (dead for years) 2012-01-13 00:01:15 +00:00
Adam Vogt
ff674a27e2 Include manual pages in data-files. 2011-12-04 00:11:37 +00:00
Adam Vogt
6c51745122 Correctly identify source files in ~/.lib (David McLean) 2012-04-30 15:42:22 +00:00
Adam Vogt
108c2280ef Address versioning problems related to X11 1.6 release.
Bump version to 0.10.1 since cabal uses hackage dependencies even when the
locally installed package differs.

Allow X11-1.6 dependency.
2012-03-20 00:49:24 +00:00
Adam Vogt
e70b489936 Drop PlainConfig from HCAR.tex: it doesn't exist in contrib.
The code for that moved out to a separate project:
http://braincrater.wordpress.com/2008/08/28/announcing-xmonad-light/
2011-12-11 00:44:05 +00:00
gwern0
450c3a34fe HCAR: update module count, date, versions, maintainer 2011-12-04 02:59:31 +00:00
Adam Vogt
32f416a3c2 Minor updates to supporting files (for 0.10 release). 2011-11-18 23:13:24 +00:00
Adam Vogt
4be3b39cd2 Assume locale is utf8 for spawn.
This adds the utf8-string dependency so that users no longer need to encode
strings they (possibly indirectly) pass to spawn. This is the expected
behavior, since each Char in String should be an actual character.

For systems that do not use utf8 this does not help. Fixing this by using iconv
or similar libraries may be done later.
2011-11-18 18:29:20 +00:00
Adam Vogt
75889ab62e Correct recompile keybinding (issue 126)
Thanks reenberg for pointing out the previous patch incorrectly warns about a
missing xmonad when the config has an error.

Also changed is "type" which as a shell builtin is more likely to exist than
"which".
2011-11-17 04:25:22 +00:00
Adam Vogt
792add376e Warn with xmessage when xmonad cannot be found for recompile (issue 126) 2010-03-30 00:33:10 +00:00
Daniel Wagner
87c50a911f change the default mod+p binding to keep up with changes to dmenu 2011-10-13 16:25:09 +00:00
Daniel Wagner
d16aa9975e recognize the --replace option 2011-08-09 19:52:50 +00:00
Adam Vogt
f34642cbac Break a long line 2011-06-09 04:24:24 +00:00
Jens Petersen
008c3638a5 output error code when xmonad.hs compile fails without any error output
Currently if there is no ghc on the path say for some reason,
xmonad.error is empty.  This patch makes
it output the exitcode code when the compile process fails
without any error output.  (It might be easier just to spawn
a shell to get "ghc: command not found" output for free.)
2011-04-26 06:23:41 +00:00
Adam Vogt
f5c40e9e12 Remove -fglasgow-exts for deriving Data/Typeable needed with ghc-6.6
This gets rid of a warning with ghc-7.0.2, and -XDeriveDataTypeable seems to
have been added with 6.8, which should be far back enough:
http://www.haskell.org/ghc/docs/6.8-latest/html/users_guide/deriving.html#deriving-typeable
2011-06-08 23:04:15 +00:00
Adam Vogt
bd82cc9150 Expose instances to haddock
While haddock may have choked on -XGeneralizedNewtypeDeriving before, this is
no longer the case. Also this doesn't change the results with a recent haddock
(2.9.2)
2011-06-08 22:56:13 +00:00
Adam Vogt
a025912ab7 Haddock formatting for a type (-->) 2011-05-24 01:51:35 +00:00
Brandon S Allbery KF8NH
19c1759b35 Generalize types of ManageHook functions, so they can be reused 2011-02-24 00:30:21 +00:00
gwern0
92acd1eb74 HCAR.tex: update per Janis's final version 2011-05-22 18:37:55 +00:00
gwern0
db9f39d6af HCAR.text: mention 2 features added since last HCAR
Prompted by Janis's usual request for updated HCARs
2011-04-11 16:45:19 +00:00
Adam Vogt
ebcd67efac Correct misleading documentation on Stack (thanks sdrodge)
`Possibly empty' applies only to `Maybe (Stack a)', not `Stack a' described
there, so this is easier to understand.
2011-03-28 00:19:30 +00:00
gwern0
387a253f62 HCAR.tex: apply Janis Voigtlaender's HCAR changes 2010-11-09 20:50:22 +00:00
Adam Vogt
4c83e8e097 Bump version to 0.10
This doesn't mean it's ready for this number release, but at least
contrib/core incompatibilities introduced since 0.9 will be avoided.
2011-01-15 18:07:15 +00:00
Adam Vogt
ae59a5184f Update util/GenerateManpage for pandoc 1.6 2010-12-31 16:31:18 +00:00
Adam Vogt
fa8fe9aca4 Update util/GenerateManpage to be pandoc-1.4 compatible 2010-04-03 18:13:54 +00:00
gwern0
673c3e9ed9 HCAR.tex: update from May
- there were no significant changes to xmonad-core
- description of 2 new modules not mentioned in HCAR
2010-10-12 01:09:15 +00:00
Adam Vogt
6ba45cdb38 Update comments describing `recompile' 2010-04-03 18:11:15 +00:00
Adam Vogt
b995b430bc Note things to update each release. 2010-03-22 15:06:22 +00:00
gwern0
ba482a4611 XMonad.Core: escape slashes, ln module 2010-06-20 17:57:41 +00:00
Tomas Janousek
684907bc77 fix haddock comment being assigned to constructor instead of field 2010-04-15 17:39:36 +00:00
gwern0
ad4136df26 HCAr.tex: update with additions and versions 2010-05-02 20:13:21 +00:00
gwern0
defe0c282e +original HCAR entry 2010-05-02 20:02:52 +00:00
Spencer Janssen
c7bdac1a7e Less refreshing in mouse-2 binding (thanks aavogt) 2010-05-03 15:50:17 +00:00
Daniel Schoepe
17799f131a Replaced custom forever_ by library function 2009-01-14 21:55:56 +00:00
Tomas Janousek
8cd66aa380 reveal: don't insert non-clients into the set of mapped windows
In xmonad-core, this fixes a small bug that caused doIgnored windows to get
into `mapped' and never being removed from there.

In the context of xmonad-contrib, this fixes a tremendous memory leak that
could be triggered by using MouseResizableTile and UrgencyHook at the same
time. MRT would create dummy windows that would get added to `mapped' by the
reveal call in `windows'. As these were not removed (removal from `mapped' is
filtered by `isClient'), they'd stay there forever and due to an inefficiency
in UrgencyHook would eat up all memory sooner or later.
2010-03-27 21:42:43 +00:00
gwern0
32ba0d4a0d loc.hs: hlintify 2010-02-13 23:15:37 +00:00
Spencer Janssen
77b3f62610 Various clean-ups suggested by HLint 2010-02-14 02:57:50 +00:00
Spencer Janssen
f3b07eb5dc Make the --replace docs consistent 2010-02-13 00:26:47 +00:00
Adam Vogt
4372c256ed Add --replace flag with documentation (issue 99). 2009-12-20 18:35:29 +00:00
Adam Vogt
34239a79de Fix compile error when using base-3 (thanks bogner). 2010-02-11 06:39:38 +00:00
Daniel Schoepe
5866db4f0f Broadcast PropertyChange events (needed for layouts with decoration) 2010-01-13 20:40:17 +00:00
Adam Vogt
46d039cde5 Rename numlockMask to numberlockMask to help users of the template config.
Without the change, the errors are like:

>     [ unrelated error messages ]
>     No constructor has all these fields: `numlockMask',
>       `terminal', [every other field set]

With the change:

>     `numlockMask' is not a record selector
>     [ context where numlockMask is named ]
2010-01-18 16:22:56 +00:00
Adam Vogt
dd22717961 Correct warnings with ghc-6.12
Changes include:
  - compatibility with base-4 or 3 (base-2 untested) by using
    extensible-exceptions. This adds an additional dependency for users of
    ghc<6.10)
  - list all dependencies again when -ftesting (change in Cabal-1.8.0.2)
  - remove unnecessary imports
  - suppress -fwarn-unused-do-bind, with appropriate Cabal-1.8 workaround,
    described here:
    http://www.haskell.org/pipermail/xmonad/2010-January/009554.html
2010-01-18 18:15:32 +00:00
Spencer Janssen
0beeb4164b Add xfork: a forkProcess that works around process global state 2009-12-23 06:16:23 +00:00
Spencer Janssen
0b435028ff TAG 0.9.1 2009-12-16 23:36:43 +00:00
Spencer Janssen
84a988da82 extra-source-files for the new manpage 2009-12-16 23:20:05 +00:00
Spencer Janssen
dbd739e41e Bump to 0.9.1 2009-12-16 23:11:10 +00:00
Spencer Janssen
d5d8d551e6 Determine numlockMask automatically, fixes #120 2009-12-16 01:21:40 +00:00
Spencer Janssen
a2ba4d8a6c Update for X11 1.5.0.0 2009-12-16 01:17:00 +00:00
Spencer Janssen
557d3edb7d Safer X11 version dependency 2009-12-16 01:03:30 +00:00
Brent Yorgey
262db2367f man/xmonad.hs: remove reference to deprecated 'dynamicLogDzen' function 2009-11-26 05:39:08 +00:00
Spencer Janssen
eddb445307 A few tweaks to --verbose-version 2009-12-08 04:07:29 +00:00
Adam Vogt
d5aadf2538 Generalize the type of (<+>). It can be used for keybindings too. 2009-12-05 23:36:11 +00:00
gwern0
a16bb44934 Main.hs +--verbose-version flag
This resolves http://code.google.com/p/xmonad/issues/detail?id=320 by adding a
--verbose-version option yielding output like "xmonad 0.9 compiled by ghc 6.10 for linux/i386"
2009-11-28 14:48:40 +00:00
Spencer Janssen
2b854ee47c Swap the order that windows are mapped/unmapped. Addresses #322 2009-11-19 02:54:40 +00:00
Spencer Janssen
02ed1cabdc Add GPL warning to GenerateManpage 2009-11-11 00:01:06 +00:00
Adam Vogt
02693d307c Add a basic header to the html manpage output 2009-10-28 03:30:42 +00:00
Adam Vogt
37dc284460 Use pandoc to convert a markdown manpage tranlation to html and man. 2009-10-28 03:06:39 +00:00
Daniel Schoepe
73e406f4a6 Support for extensible state in contrib modules. 2009-11-06 11:50:50 +00:00
Spencer Janssen
44bc9558d9 Set SIGPIPE to default in forked processes 2009-11-06 22:37:43 +00:00
Spencer Janssen
0eb84e4866 Bump version to 0.9 2009-10-26 00:45:43 +00:00
Adam Vogt
b4bf8de874 Grab the xmonad.cabal version for putting into the manpage 2009-10-24 20:09:20 +00:00
Adam Vogt
17c89e327e Correct formatting in manpage 2009-10-24 20:07:48 +00:00
Don Stewart
da71b6c8ac depend on X11 >= 1.4.6.1, for conformity with XMC 2009-10-24 21:24:09 +00:00
Khudyakov Alexey
2621f3f6a8 Fix for Tall documentation 2009-05-16 10:47:53 +00:00
Daniel Wagner
8ec0bf3290 correct a comment 2009-07-27 03:20:24 +00:00
Spencer Janssen
7e20d0d308 man/xmonad.hs is in data-files, remove it from extra-source-files 2009-10-23 03:14:57 +00:00
Adam Vogt
24d8de93d7 Add the template config as distributed file. 2009-10-22 04:14:02 +00:00
Adam Vogt
2dd6eeba7d Note in manpage that 'exec xmonad' should be used 2009-09-01 04:05:38 +00:00
Adam Vogt
72997cf982 Manual page spelling: maximise -> maximize, utilising -> utilizing 2009-09-01 04:02:17 +00:00
Adam Vogt
7365d7bc11 Describe modular configuration in the manual page 2009-09-01 04:00:46 +00:00
Spencer Janssen
36e20f689c Remove redundant parens 2009-09-18 03:55:47 +00:00
wirtwolff
cde261ed56 man_xmonad.hs: import Data.Monoid for mempty, keybinding edits
Bring mempty into scope. Add commented ToggleStruts binding.
Replace shadowed modMask in keybindings with modm instead.
2009-03-20 02:46:24 +00:00
Adam Vogt
8d8cc8bcd8 Only watch mtime for .hs, .lhs, .hsc for ~/.xmonad/lib
Previously xmonad would force a recompile due to the object files being too
new, so only look at files which may contain haskell code.
2009-05-03 23:54:15 +00:00
Adam Vogt
ccb6ff92f2 Add lib to ghc searchpath with recompilation check 2009-03-21 23:29:07 +00:00
Adam Vogt
e944a6c8d3 Remove tabs from ManageHook.hs 2009-07-10 01:14:24 +00:00
Adam Vogt
eb1e29c8bb Set infix 0 --> to reduce parentheses in ManageHooks
What was previously:
> (appName ?= x <&&> classname ?= y) --> (doFloat <+> doIgnore)

Can now be:
> appName ?= x <&&> classname ?= y --> doFloat <+> doIgnore
2009-07-10 01:13:08 +00:00
Adam Vogt
66e7715ea6 Pester the user with one (not two) xmessages on config errors 2009-03-21 23:37:36 +00:00
Wouter Swierstra
d9d3e40112 Minor bugfix in the creation of new StackSets. 2009-05-03 15:43:21 +00:00
Spencer Janssen
7385793c65 Avoid deadly cycle in man/xmonad.hs 2009-03-19 08:19:18 +00:00
wirtwolff
72885e7e24 X.Config.hs, ./man/xmonad.hs: update Event Hook doc 2009-02-09 18:38:37 +00:00
Spencer Janssen
a931776e54 Use records to document Tall's arguments 2009-02-21 23:06:28 +00:00
Joachim Breitner
61568318d6 Fix possible head []
This seems to be a rare case, but I just got hit by it.
2009-01-06 19:20:26 +00:00
Spencer Janssen
3caa989e20 ManageHook.doShift: use shiftWin instead of shift 2009-02-19 04:14:58 +00:00
Spencer Janssen
09fd11d13b Express shift in terms of shiftWin 2009-02-17 23:53:43 +00:00
Don Stewart
f33681de49 Use standard -fforce-recomp instead of undocumented -no-recomp 2009-02-08 16:55:18 +00:00
Daniel Schoepe
bf8bfc66a5 Support for custom event hooks 2009-02-03 15:55:36 +00:00
Daniel Schoepe
4075e2d9d3 Make X an instance of Typeable 2009-01-28 21:54:06 +00:00
Spencer Janssen
78856e1a6f Add uninstallSignalHandlers, use in spawn 2009-01-22 00:26:43 +00:00
Spencer Janssen
4222dd9ad3 Create a new session for forked processes 2009-01-22 00:04:23 +00:00
Spencer Janssen
34a547ce57 TAG 0.8.1 2009-01-18 08:39:10 +00:00
Spencer Janssen
353e7cd681 Close stdin in spawned processes 2009-01-17 04:00:24 +00:00
Spencer Janssen
72dece0769 Document spawnPID 2009-01-17 03:59:07 +00:00
Spencer Janssen
6e1c5e9b49 Asynchronously recompile/restart xmonad on mod-q 2009-01-17 03:53:00 +00:00
Spencer Janssen
bf8ba79090 Add --restart, a command line flag to cause a running xmonad process to restart 2009-01-17 03:49:59 +00:00
Spencer Janssen
5edfb1d262 Bump version to 0.8.1 2009-01-16 22:36:21 +00:00
Spencer Janssen
0fecae0abc Remove doubleFork, handle SIGCHLD
This is a rather big change.  Rather than make spawned processes become
children of init, we handle them in xmonad.  As a side effect of this change,
we never need to use waitForProcess in any contrib module -- in fact, doing so
will raise an exception.  The main benefit to handling SIGCHLD is that xmonad
can now be started with 'exec', and will correctly clean up after inherited
child processes.
2009-01-16 20:47:42 +00:00
gwern0
26f4f734f9 Main.hs: escape / in Haddocks
This lets haddocks for Main.hs, at least, to build with 2.3.0.
2008-12-07 02:09:15 +00:00
Daniel Schoepe
5e7df396b9 More flexible userCode function 2009-01-10 22:18:52 +00:00
Spencer Janssen
314ba78335 Call logHook as the very last action in windows 2008-12-09 23:37:00 +00:00
Spencer Janssen
7aa78ecc75 Accept inferior crossing events. This patch enables fmouse-focus-follows-screen 2008-12-05 04:51:30 +00:00
Spencer Janssen
ba8e26458e Tile all windows at once 2008-11-18 07:44:47 +00:00
Spencer Janssen
c627e8cc4d Factor rational rect scaling into a separate function 2008-11-18 07:28:49 +00:00
Spencer Janssen
04f894275d Change screen focus by clicking on the root window.
This is a modification of a patch from Joachim Breitner.
2008-11-06 22:40:31 +00:00
Spencer Janssen
edb752136f Fix #192. 2008-10-21 22:00:59 +00:00
Adam Vogt
2b463a632f select base < 4 for building on ghc 6.10 2008-10-13 21:45:09 +00:00
Joachim Breitner
ca122dd2cb add killWindow function
This is required to kill anything that is not focused, without
having to focus it first.
2008-10-05 00:18:04 +00:00
Devin Mullins
77657b65f9 add'l documentation 2008-09-27 23:46:39 +00:00
Spencer Janssen
28c57a837a Regression: ungrab buttons on *non* root windows 2008-10-07 21:43:51 +00:00
Spencer Janssen
afda20b56d Partial fix for #40
Improvements:
 - clicking on the root will change focus to that screen
 - moving the mouse from a window on a screen to an empty screen changes focus
   to that screen
The only remaining issue is that moving the mouse between two empty screens
does not change focus.  In order to solve this, we'd have to select motion events
on the root window, which is potentially expensive.
2008-10-07 21:20:53 +00:00
Spencer Janssen
0cc7b12fd0 Track mouse position via events received 2008-10-07 20:39:53 +00:00
Spencer Janssen
15a78ae715 Fix haddock 2008-10-07 09:46:41 +00:00
Spencer Janssen
18444799e0 Move screen locating code into pointScreen 2008-10-07 09:42:07 +00:00
Spencer Janssen
cc60fa73ad Make pointWithin a top-level binding 2008-10-07 09:02:29 +00:00
gwern0
8881e2ac78 sp README, CONFIG, STYLE, TODO 2008-09-13 02:44:57 +00:00
Spencer Janssen
533031e3d6 Use the same X11 dependency as xmonad-contrib 2008-09-21 06:15:08 +00:00
Spencer Janssen
76d4af15e4 Export focusUp' and focusDown' -- work entirely on stacks 2008-09-11 21:48:03 +00:00
Devin Mullins
74c6dd2721 add W.shiftMaster, fix float/tile-reordering bug 2008-09-11 05:39:09 +00:00
Spencer Janssen
b605fd9fce Spelling. Any bets on how long this has been there? 2008-09-05 19:52:11 +00:00
Spencer Janssen
85202ebd47 Bump version to 0.8 2008-09-05 19:42:25 +00:00
Spencer Janssen
328c660ce7 Remove obsolete comments about darcs X11 2008-09-05 19:49:15 +00:00
Spencer Janssen
b185a439b1 Recommend latest packages rather than specific versions 2008-09-05 19:48:37 +00:00
Spencer Janssen
0016e06984 Also remove -optl from the executable section 2008-08-20 21:00:23 +00:00
Spencer Janssen
339b2d0097 -optl-Wl,-s is not needed with recent Cabal versions 2008-08-20 20:41:02 +00:00
Malebria
5f4d63ba71 Haddock links 2008-06-01 21:25:15 +00:00
Malebria
942572c830 Haddock syntax for enumeration 2008-06-01 20:49:51 +00:00
Spencer Janssen
46ac2ca24b I prefer the spencerjanssen@gmail.com address now 2008-07-14 20:26:50 +00:00
Trevor Elliott
3830d7a571 Raise windows in the floating layer when moving or resizing 2008-05-21 21:50:57 +00:00
Devin Mullins
5b3eaf663a add currentTag convenience function 2008-05-11 22:42:58 +00:00
Spencer Janssen
c93b7c7c3b Make Mirror a newtype 2008-05-08 10:46:40 +00:00
Spencer Janssen
42dee4768e Comments 2008-05-07 01:31:22 +00:00
Spencer Janssen
e847b350ed Break long line 2008-05-07 01:26:08 +00:00
Spencer Janssen
cccbfa21e4 Style 2008-05-07 01:25:19 +00:00
Spencer Janssen
870b3ad282 Simplify 2008-05-07 01:13:09 +00:00
Spencer Janssen
ab30d76578 Overhaul Choose, fixes issue 183 2008-05-06 22:08:09 +00:00
Klaus Weidner
d8d636e573 Remember if focus changes were caused by mouse actions or by key commands
If the user used the mouse to change window focus (moving into or clicking on a
window), this should be handled differently than focus changes due to keyboard
commands. Specifically, it's inappropriate to discard window enter/leave events
while the mouse is moving. This fixes the bug where a fast mouse motion across
multiple windows resulted in the wrong window keeping focus.

It's also helpful information for contrib modules such as UpdatePointer - it's
supposed to move the mouse pointer only in response to keyboard actions, not if
the user was moving the mouse.
2008-05-02 17:56:03 +00:00
Spencer Janssen
ba3987f299 Wibble 2008-05-06 20:38:40 +00:00
Ivan N. Veselov
5a19425e79 Added doShift function for more user-friendly hooks 2008-05-06 18:57:57 +00:00
Don Stewart
28431e18c8 use named colours. fixes startup failure on the XO 2008-05-02 21:01:49 +00:00
Spencer Janssen
43c2d26cdb Set focus *after* revealing windows 2008-04-07 22:25:59 +00:00
Spencer Janssen
c24016882e Reveal windows after moving/resizing them.
This should reduce the number of repaints for newly visible windows.
2008-04-07 22:07:56 +00:00
Spencer Janssen
9dae87c537 Hide newly created but non-visible windows (fixes bug #172) 2008-04-30 01:40:12 +00:00
Don Stewart
b67026dd02 formatting, eta expansion 2008-04-18 18:43:37 +00:00
Lukas Mai
aa58eea6dc XMonad.ManageHook: add 'appName', another name for 'resource' 2008-04-06 01:20:06 +00:00
Lukas Mai
7db13a2a45 XMonad.ManageHook: make 'title' locale-aware; haddock cleanup
The code for 'title' was stolen from getname.patch (bug #44).
2008-04-06 01:13:38 +00:00
Lukas Mai
029e668dbc XMonad.Main: call setlocale on startup 2008-04-06 01:12:34 +00:00
robreim
6f61c83623 floats always use current screen (with less bugs) 2008-04-05 13:50:09 +00:00
Lukas Mai
bcbccbfafc XMonad.Operations: applySizeHint reshuffle
Make applySizeHints take window borders into account. Move old functionality
to applySizeHintsContents. Add new mkAdjust function that generates a custom
autohinter for a window.
2008-04-04 21:56:15 +00:00
Lukas Mai
04c8d62361 XMonad.Layout: documentation cleanup 2008-04-04 21:54:44 +00:00
Spencer Janssen
4890116e49 Remove gaps from the example config 2008-03-29 23:29:59 +00:00
Spencer Janssen
708084dd48 Remove gaps 2008-03-25 09:15:26 +00:00
Spencer Janssen
ef516142b9 Remove -fhpc from ghc-options (annoying hackage workaround) 2008-03-29 20:58:04 +00:00
Spencer Janssen
cb51875da6 Remove version numbers from README 2008-03-29 20:41:58 +00:00
Spencer Janssen
167a6e155b Bump version to 0.7 2008-03-29 19:13:36 +00:00
Don Stewart
2b2774f81d no need to expose --resume to the user 2008-03-28 21:42:19 +00:00
Spencer Janssen
16725dfe0d Rename property to stringProperty 2008-03-25 20:18:14 +00:00
Brent Yorgey
15db3c6f0a ManageHook: add a 'property' Query that can get an arbitrary String property from a window (such as WM_WINDOW_ROLE, for example) 2008-03-25 14:54:14 +00:00
Brent Yorgey
6db444eb1a Main.hs: startupHook should be guarded by userCode 2008-03-25 17:12:41 +00:00
Spencer Janssen
46bc3bbd17 Also print compilation errors to stderr 2008-03-24 22:58:57 +00:00
Don Stewart
d948210935 clean up for style 2008-03-22 21:41:16 +00:00
Andrea Rossato
db08970071 add sendMessageWithNoRefresh and have broadcastMessage use it
This patch:
- moves broadcastMessage and restart from Core to Operations (to avoid
  circular imports);
- in Operations introduces sendMessageWithNoRefresh and move
 updateLayout outside windows.
- broadcastMessage now uses sendMessageWithNoRefresh to obey to this
  rules:
  1. if handleMessage returns Nothing no action is taken;
  2. if handleMessage returns a Just ml *only* the layout field of the
     workspace record will be updated.
2008-02-23 13:07:02 +00:00
Spencer Janssen
4c69a85b3f --recompile now forces recompilation of xmonad.hs 2008-03-24 21:24:53 +00:00
Lukas Mai
ac103b8472 add --help option 2008-01-29 23:52:58 +00:00
Don Stewart
029965e4d4 add mod-shift-tab to the default bindings, from Mathias Stearn 2008-03-23 21:14:21 +00:00
Don Stewart
9fd1d4f9d0 more tests 2008-03-23 00:34:36 +00:00
Don Stewart
dbbd934b0b some tests for the size increment handling in Operations.hs 2008-03-22 23:49:52 +00:00
Don Stewart
750544fda9 more properties for splitting horizontally and vertically 2008-03-22 20:18:35 +00:00
Don Stewart
90eae3fd63 test message handling of Full layout 2008-03-22 19:27:28 +00:00
Don Stewart
d6233d0463 formatting 2008-03-22 19:26:35 +00:00
Don Stewart
5f088f4e99 strict fields on layout messages 2008-03-22 19:22:48 +00:00
Don Stewart
f8a7d8d381 QuickCheck properties to fully specify the Tall layout, and its messages 2008-03-22 04:18:01 +00:00
Don Stewart
f7686746c6 clean up Layout.hs, not entirely happy about the impure layouts. 2008-03-22 04:17:18 +00:00
Don Stewart
04ee55c3ca comments 2008-03-22 04:16:54 +00:00
Don Stewart
50ce362626 add hpc generation script 2008-03-22 04:16:40 +00:00
Don Stewart
209b88f821 add QuickCheck property for Full: it produces one window, it is fullscreen, and it is the current window 2008-03-22 00:20:26 +00:00
Don Stewart
c5cca485df QC for pureLayout. confirm pureLayout . Tall produces no overlaps 2008-03-22 00:12:29 +00:00
Don Stewart
0593a282ca whitespace 2008-03-22 00:12:08 +00:00
Don Stewart
351de8d2b6 reenable quickcheck properties for layouts (no overlap, fullscreen) 2008-03-21 23:40:15 +00:00
Don Stewart
4bd9073937 formatting 2008-03-21 23:09:56 +00:00
Don Stewart
79754fd5d3 Revert float location patch. Not Xinerama safe 2008-03-21 21:41:29 +00:00
Lukas Mai
b14de19e8b XMonad.Core: ignore SIGPIPE, let write calls throw 2008-03-21 17:19:11 +00:00
Brent Yorgey
e97c326ff0 update documentation 2008-03-11 16:07:27 +00:00
Andrea Rossato
bc13b4ba07 Reimplement Mirror with runLayout 2008-02-25 08:32:36 +00:00
Andrea Rossato
5bea59a823 Reimplement Choose with runLayout 2008-02-22 19:31:19 +00:00
Andrea Rossato
669a162cfc runLayout is now a LayoutClass method and takes the Workspace and the screen Rectangle 2008-02-22 17:58:15 +00:00
Don Stewart
310c22694e add property for ensureTags behaviour on hidden workspaces 2008-03-10 18:25:57 +00:00
robreim
1c930ba955 Small linecount fix :) 2008-03-08 02:19:39 +00:00
robreim
797204fe6c Change floats to always use the current screen 2008-03-08 01:58:29 +00:00
Don Stewart
a3ecf5d304 use -fhpc by default when testing. All developers should have 6.8.x 2008-03-07 18:42:23 +00:00
Don Stewart
1a4a4a5000 more general properties for view, greedyView 2008-03-07 18:16:57 +00:00
Don Stewart
a8d3564653 rework failure cases in StackSet.view 2008-03-07 18:16:34 +00:00
Don Stewart
d5955b023c bit more code coverage 2008-03-07 18:09:05 +00:00
Don Stewart
4d9a6c2681 more tests. slightly better test coverage 2008-02-27 18:01:13 +00:00
Don Stewart
87193ff61e test geometry setting 2008-02-27 17:55:54 +00:00
Don Stewart
3303c6e05d incorrect invariant test for greedyView 2008-02-25 18:03:50 +00:00
Brent Yorgey
9d9acba45f Add a startupHook.
The only thing I am not sure about here is at what exact point the 
startupHook should get run.  I picked a place that seems to make sense: 
as late as possible, right before entering the main loop.  That way all
the layouts/workspaces/other state are set up and the startupHook can
manipulate them.
2008-02-04 19:24:45 +00:00
Brent Yorgey
cc2754d82a Core.hs: add an Applicative instance for X 2008-02-04 19:23:48 +00:00
gwern0
cea3492d28 update LOC claim in man page 2008-02-15 21:14:20 +00:00
Don Stewart
14d9a194ff add quickstart instructions 2008-02-12 20:35:02 +00:00
Spencer Janssen
e8d1d028ba Remove non-existent windows on restart 2008-02-07 09:11:40 +00:00
Don Stewart
695860f1fd Lift initColor exceptions into Maybe
We should audit all X11 Haskell lib calls we make for whether
they throw undocumented exceptions, and then banish that.
2008-02-06 19:48:58 +00:00
Don Stewart
261f742404 some things to do 2008-02-06 19:25:33 +00:00
Don Stewart
1de1bcded2 module uses CPP 2008-02-06 19:05:21 +00:00
Spencer Janssen
0c697ebbb4 Rename runManageHook to runQuery 2008-02-04 05:33:36 +00:00
daniel
a626083721 let enter dismiss compile errors 2008-02-03 20:28:52 +00:00
Brent Yorgey
481e42ab72 Core.hs, StackSet.hs: some documentation updates 2008-02-01 19:06:53 +00:00
Andrea Rossato
e751c4b62f Make Mirror implement emptyLayout 2008-01-28 00:18:34 +00:00
"Valery V. Vorotyntsev"
730984fd60 xmonad.cabal: add `build-type' to make Cabal happy 2008-01-31 16:32:13 +00:00
Daniel Neri
ad85e11a4a Get version from the Paths_xmonad module generated by Cabal
No need to bump version in more than one place.
2008-01-29 14:40:37 +00:00
Spencer Janssen
2da09787da Kill stale xmonad 0.1 comments 2008-01-28 21:14:18 +00:00
Spencer Janssen
162a54d992 Point to 0.6 release of contrib 2008-01-28 10:11:15 +00:00
Don Stewart
d00d4ca046 notes on releases 2008-01-28 17:10:12 +00:00
Don Stewart
0dd54885eb bump output of --version 2008-01-28 17:08:40 +00:00
Spencer Janssen
f80d593d57 Generalize the type of catchIO, use it in Main.hs 2008-01-28 05:46:51 +00:00
Andrea Rossato
10be8aaae0 Add emptyLayout to LayoutClass, a method to be called when a workspace is empty 2008-01-24 01:32:07 +00:00
Don Stewart
66f623b656 clarify copyright 2008-01-08 18:56:40 +00:00
Spencer Janssen
b86351f3c3 TAG 0.6 2008-01-27 22:06:33 +00:00
Spencer Janssen
8399e80327 More other-modules 2008-01-27 22:01:52 +00:00
Spencer Janssen
3e3d516092 Update example config 2008-01-27 21:23:31 +00:00
Spencer Janssen
d2ae7310d6 Bump version to 0.6 2008-01-27 20:50:00 +00:00
Austin Seipp
ca3e277d2b Updated ./man/xmonad.1.in to contain new command line parameters 2008-01-22 07:01:53 +00:00
Spencer Janssen
bb2b6c7bf8 Depend on QuickCheck < 2 when building tests 2008-01-22 07:02:25 +00:00
Spencer Janssen
d74814af35 Roll testing into the main executable, use Cabal to build the tests 2008-01-19 09:12:15 +00:00
Spencer Janssen
f9799422f9 Simplify duplicate/cloned screen logic 2008-01-18 03:22:28 +00:00
Joachim Breitner
be5e27038f Put the screen removing stuff in getCleanedScreenInfo 2007-12-31 18:15:56 +00:00
Joachim Breitner
1f4b8cb5f6 Ignore cloned screens
This patch ignores screens that are just clones of existing ones,
or are completely contained in another. Currently only for rescreen, not yet for
xmonad start.
2007-12-31 18:06:28 +00:00
Spencer Janssen
da7ca1c29d -Werror when flag(testing) only 2008-01-18 01:48:27 +00:00
nicolas.pouillard
e095621ab9 Export doubleFork 2008-01-14 20:26:12 +00:00
Lukas Mai
93c55c948e reword comment (previous version didn't make sense to me) 2007-11-22 16:59:25 +00:00
nicolas.pouillard
9ff105340e The recompile function now returns a boolean status instead of (). 2008-01-05 22:55:00 +00:00
Spencer Janssen
5e61b137fb Make focus-follows-mouse configurable 2007-12-29 02:33:01 +00:00
Spencer Janssen
aeef36f74c Strictify all XConfig fields, gives nice error messages when a field is forgotten on construction 2007-12-29 02:19:23 +00:00
Spencer Janssen
673f303646 Spelling 2007-12-29 02:16:28 +00:00
Spencer Janssen
7f3c6823d4 Wibble 2007-12-29 02:15:19 +00:00
Spencer Janssen
79f23d6cec Broadcast button events to all layouts, fix for issue #111 2007-12-27 08:03:56 +00:00
Brent Yorgey
46f5e68cfa Config.hs: too many users seem to be ignoring/missing the polite warning not to modify this file; change it to something a bit less polite/more obvious. 2007-12-20 20:15:49 +00:00
Spencer Janssen
76d2bddaf0 Remove desktop manageHook rules in favor of ManageDocks 2007-12-22 11:37:35 +00:00
Spencer Janssen
f5e55f3a27 Wibble 2007-12-22 04:11:51 +00:00
Spencer Janssen
6c72a03fb1 Add support for several flags:
--version: print xmonad's version
 --recompile: recompile xmonad.hs if it is out of date
 --force-recompile: recompile xmonad.hs unconditionally
2007-12-22 02:05:20 +00:00
Spencer Janssen
31c7734f7b Remove getProgName capability from restart, we don't use it anymore 2007-12-19 21:50:11 +00:00
Spencer Janssen
d1af7d986d Flush pending X calls before restarting 2007-12-19 16:20:29 +00:00
tim.thelion
da167bfc11 Allow for sharing of home directory across architectures. 2007-12-18 06:51:46 +00:00
Spencer Janssen
c46f3ad549 Call 'broadcastMessage ReleaseResources' in restart 2007-12-19 06:57:10 +00:00
Adam Vogt
5b42a58d06 Manpage now describes config in ~/.xmonad/xmonad.hs 2007-12-19 02:39:18 +00:00
Adam Vogt
e8292e0e9d Update manpage to describe greedyView 2007-12-19 02:37:26 +00:00
Spencer Janssen
6cd46e12bb Depend on X11-1.4.1, it has crucial bugfixes 2007-12-15 02:21:00 +00:00
Don Stewart
2441275122 1.4.1 X11 dep 2007-12-14 16:05:58 +00:00
Spencer Janssen
f70ab7964e Set withdrawnState after calling hide 2007-12-12 06:02:50 +00:00
Spencer Janssen
237fdbf037 Remove stale comment 2007-12-11 08:42:36 +00:00
Spencer Janssen
5166ede96b Make windows responsible for setting withdrawn state 2007-12-11 08:01:17 +00:00
Spencer Janssen
56463b2391 Remove stale comment 2007-12-11 07:56:41 +00:00
Spencer Janssen
f427c2b0e9 Clean up stale mapped/waitingUnmap state in handle rather than unmanage.
This is an attempt to fix issue #96.  Thanks to jcreigh for the insights
necessary to fix the bug.
2007-12-11 07:48:10 +00:00
Spencer Janssen
287d364e0d Delete windows from waitingUnmap that aren't waitng for any unmaps 2007-12-11 07:45:06 +00:00
Brent Yorgey
8c31768b79 man/xmonad.hs: add some documentation explaining that 'title' can be used in the manageHook just like 'resource' and 'className'. 2007-12-10 17:33:57 +00:00
Lukas Mai
9ceef229c3 normalize Module headers 2007-12-10 08:53:27 +00:00
Spencer Janssen
40581c9bf8 Add 'testing' mode, this should reduce 'darcs check' time significantly 2007-12-10 00:47:04 +00:00
Spencer Janssen
161ade3593 Use XMonad meta-module in Main.hs 2007-12-10 00:44:56 +00:00
Spencer Janssen
f2461c9e3a Remove references to 0.4 2007-12-09 23:23:36 +00:00
Spencer Janssen
11b37429b1 Bump version to 0.5! 2007-12-09 23:15:39 +00:00
Spencer Janssen
bbf5d0010c Rename xmonad.hs to xmonad-template.hs 2007-12-09 23:14:26 +00:00
Andrea Rossato
2f60ee5680 StackSet: some haddock tuning 2007-12-09 16:15:25 +00:00
Don Stewart
3e2d48d5da add a template xmonad.hs 2007-12-09 22:50:18 +00:00
Spencer Janssen
462422d07a Remove kicker and gnome-panel from the default manageHook, these are better
handled by XMonad.Hooks.ManageDocks.  Also, remove the over-complicated list
comprehensions.
2007-12-09 13:54:08 +00:00
Spencer Janssen
33f28ed2ac XMonad.Layouts -> XMonad.Layout 2007-12-08 08:05:53 +00:00
Andrea Rossato
a29590034a Typos and formatting 2007-11-24 14:32:21 +00:00
Andrea Rossato
f394956e56 Move XMonad.Layouts to XMonad.Layout for uniformity with xmc 2007-11-24 14:30:00 +00:00
Spencer Janssen
039d9e2b96 Hide generalized newtype deriving from Haddock 2007-12-08 01:50:15 +00:00
Spencer Janssen
a73f8ec709 Export XMonad.Layouts from XMonad 2007-12-08 01:49:27 +00:00
Spencer Janssen
1bb18654d6 Export XMonad.Operations from XMonad 2007-12-08 00:06:36 +00:00
Spencer Janssen
fa45d59e95 Export Graphics.X11, Graphics.X11.Xlib.Extras, and various Monad stuff from XMonad 2007-12-07 23:35:35 +00:00
Spencer Janssen
f73f8f38a5 Depend on X11>=1.4.0 2007-12-05 04:59:45 +00:00
Spencer Janssen
28cc666a75 Update extra-source-files 2007-12-05 04:44:21 +00:00
Spencer Janssen
c8f16a85cf Update man location 2007-12-05 04:39:13 +00:00
Lukas Mai
6908189698 make Query a MonadIO 2007-11-28 19:51:26 +00:00
Spencer Janssen
39eccc350c Add ManageHook to the XMonad metamodule 2007-11-27 00:28:40 +00:00
Don Stewart
c8ab301c95 update todos before release 2007-11-25 05:27:20 +00:00
Don Stewart
5e310c0c94 Depend on X11 1.4.0 2007-11-25 03:40:12 +00:00
Lukas Mai
4fa10442ab add getXMonadDir (2nd try) 2007-11-21 18:30:18 +00:00
Spencer Janssen
1ab1d729a0 Add 'and' and 'or' functions to ManageHook. 2007-11-21 10:46:13 +00:00
Don Stewart
c95b8d9160 generalise type of `io' 2007-11-21 05:44:07 +00:00
Spencer Janssen
92b4510d7b Add recompilation forcing, clean up recompile's documentation 2007-11-20 22:36:14 +00:00
Spencer Janssen
6114bb371e recompile does not raise any exceptions 2007-11-20 21:58:35 +00:00
Spencer Janssen
7e2ec3840c -no-recomp because we're doing our own recompilation checking 2007-11-20 21:57:44 +00:00
Don Stewart
6ce125a566 pointfree 2007-11-20 18:40:16 +00:00
Don Stewart
3456086f85 clean up fmap overuse with applicatives. more opportunities remain 2007-11-20 18:17:43 +00:00
Spencer Janssen
3b83895d28 ManageHook is a Monoid 2007-11-19 06:08:20 +00:00
Spencer Janssen
dc6ba6b5ee No more liftM 2007-11-19 03:31:20 +00:00
Spencer Janssen
df5003eb16 Refactor recompile 2007-11-19 03:22:55 +00:00
Spencer Janssen
99dd1a30ba Trailing space 2007-11-19 03:06:58 +00:00
Spencer Janssen
d6c5eb3e80 Generalize recompile to MonadIO 2007-11-19 03:04:36 +00:00
Spencer Janssen
9d9b733994 Factor out doubleFork logic 2007-11-19 03:03:53 +00:00
Don Stewart
ea71fd67e8 handle case of xmonad binary not existing, when checking recompilation 2007-11-19 03:00:57 +00:00
Don Stewart
e9eadd6141 Use executeFile directly, rather than the shell, avoiding sh interepeting 2007-11-19 02:50:15 +00:00
Don Stewart
ddf9e49e49 use 'spawn' rather than runProcess, to report errors asynchronously, avoiding zombies 2007-11-19 02:37:12 +00:00
Don Stewart
81803ffe81 use 'spawn' rather than runProcess, to report errors asynchronously, avoiding zombies 2007-11-19 02:37:12 +00:00
Don Stewart
31ce83d04e Use xmessage to present a failure message to users when the config file cannot be loaded 2007-11-19 02:24:29 +00:00
Don Stewart
c2ae7a8c71 only check xmonad.hs against the xmonad binary, not the .o file (meaning you can remove it if you like) 2007-11-19 01:15:28 +00:00
Don Stewart
45eea722be Do our own recompilation checking: only launch ghc if the xmonad.hs is newer than its .o file 2007-11-19 01:07:59 +00:00
Don Stewart
4bb6371155 reformat export list to fit on the page 2007-11-19 00:39:00 +00:00
Devin Mullins
dfd4d435d8 add support for Mac users and their silly case-insensitive filesystems 2007-11-17 02:48:36 +00:00
Don Stewart
ac41c8fb52 some more tweaks 2007-11-16 18:42:27 +00:00
Don Stewart
223b48ab27 more todos: docs 2007-11-16 18:24:44 +00:00
Don Stewart
107b942414 we need examples for the managehook edsl 2007-11-16 18:23:32 +00:00
Don Stewart
6aee5509de more todos 2007-11-16 18:20:33 +00:00
Don Stewart
ba6d9c8a52 polish readme 2007-11-16 18:19:31 +00:00
Don Stewart
3a995b40c9 more polish for config doc 2007-11-16 18:16:40 +00:00
Don Stewart
656f4551da tweak .cabal synopsis a little 2007-11-16 18:12:45 +00:00
Andrea Rossato
6ae94edbe4 Config: small haddock fix 2007-11-16 11:31:58 +00:00
Andrea Rossato
22ccca29e6 Core: documented XConfig and ScreenDetail 2007-11-16 11:28:26 +00:00
"Valery V. Vorotyntsev"
2302bb3304 CONFIG, TODO: fix typos
CONFIG: delete trailing whitespace
2007-11-15 14:41:51 +00:00
Lukas Mai
b4e0e77911 make default ratios in config nicer to look at 2007-11-12 01:35:51 +00:00
Lukas Mai
dcf53fbaf6 refactor main, add "recompile" to XMonad.Core 2007-11-08 23:09:33 +00:00
Don Stewart
833e37da9c comments, reexport Data.Bits 2007-11-14 18:37:59 +00:00
Don Stewart
cf0c3b9ab6 polish .cabal file. add xmonad@ as the default maintainer 2007-11-14 18:27:16 +00:00
Don Stewart
532a920bce add lots more text on configuration 2007-11-14 18:25:31 +00:00
Don Stewart
0d506daf45 refactor trace. 2007-11-14 03:41:09 +00:00
Devin Mullins
4887c5ac42 clarify comment at top of Config.hs
There appears to be some confusion -- several people have wanted to edit
Config.hs as was done in the past. This comment probably won't stop that, but
it's a start.
2007-11-11 19:13:04 +00:00
David Roundy
3d0c08365d avoid Data.Ratio and % operator in XMonad.Config
I think this'll make Config.hs more friendly as a template for folks
to modify.
2007-11-11 18:37:08 +00:00
Devin Mullins
e4c2a81ca1 remove obviated (and confusing) comments 2007-11-11 05:50:47 +00:00
Spencer Janssen
58fc2bc59e XMonad.Main uses FlexibleContexts 2007-11-11 21:45:28 +00:00
David Roundy
c8473e3ae9 hide existential Layout (mostly) from user API. 2007-11-11 00:30:55 +00:00
Don Stewart
11711e1a46 Depend on X11 1.3.0.20071111 2007-11-11 20:09:32 +00:00
Don Stewart
99fb75eb9b update README some more 2007-11-09 18:12:03 +00:00
Don Stewart
ceb1c51b3f we depend on Cabal 1.2.0 or newer 2007-11-09 15:59:34 +00:00
Spencer Janssen
14b6306ac2 Generalize several functions to MonadIO 2007-11-09 06:42:14 +00:00
Spencer Janssen
b51f6f55a8 Docs for ManageHook 2007-11-09 03:18:10 +00:00
Spencer Janssen
e2ab6e8a27 New ManageHook system 2007-11-09 02:47:22 +00:00
Spencer Janssen
a5200b3862 Generalize the type of whenJust 2007-11-07 06:21:26 +00:00
Don Stewart
f81ec95fa0 maybe False (const True) -> isJust. spotted by shachaf 2007-11-08 00:35:39 +00:00
Don Stewart
39f4fe7a90 typo 2007-11-08 00:02:59 +00:00
Don Stewart
d50d6c909d imports not needed in example now 2007-11-07 03:23:46 +00:00
Don Stewart
dbfd13207d Provide top level XMonad.hs export module 2007-11-07 03:06:17 +00:00
Don Stewart
6eb23670bb point to where defns for config stuff can be found 2007-11-07 02:08:01 +00:00
Spencer Janssen
bbe4a27f65 Fix haddock comment 2007-11-07 03:05:10 +00:00
Lukas Mai
94924123bb fall back to previous ~/.xmonad/xmonad if recompilation fails 2007-11-07 01:53:09 +00:00
Don Stewart
ece268cd1e recommend --user 2007-11-06 22:10:04 +00:00
Don Stewart
dfd8e51136 add CONFIG with details of how to configure 2007-11-05 04:07:41 +00:00
Spencer Janssen
0de10862c2 Run only 50 tests per property, decreases test time by 10 seconds on my system 2007-11-05 06:49:44 +00:00
Spencer Janssen
f7b6a4508f Remove stale comment 2007-11-05 06:37:31 +00:00
Spencer Janssen
00f83ac78a Use Cabal's optimization flags rather than -O 2007-11-05 06:17:59 +00:00
Spencer Janssen
3a902ce613 Build the whole thing in the test hook 2007-11-05 06:16:15 +00:00
Spencer Janssen
5342be0e67 -Werror 2007-11-05 06:03:26 +00:00
Spencer Janssen
88845e5d97 Remove superfluous 'extensions:' field 2007-11-05 03:45:15 +00:00
Spencer Janssen
4732557c12 Use configurations in xmonad.cabal 2007-11-05 03:34:28 +00:00
Don Stewart
a13c11ff52 ~/.xmonad/Main.hs is now ~/.xmonad/xmonad.hs ! 2007-11-05 03:26:55 +00:00
Don Stewart
fcea17f920 makeMain -> xmonad 2007-11-05 03:12:03 +00:00
Don Stewart
a5acef3ad6 -Wall police 2007-11-05 02:22:02 +00:00
Don Stewart
76e960a40c remember to compile the xmonad library also with the usual ghc-optoins 2007-11-05 02:21:27 +00:00
Don Stewart
30af3a8f84 EventLoop -> Core, DefaultConfig -> Config 2007-11-05 02:17:05 +00:00
Don Stewart
c9142952c2 clean up DefaultConfig.hs 2007-11-05 02:11:42 +00:00
Don Stewart
934fb2c368 clean up some weird formatting/overboard strictness annotations 2007-11-05 01:14:00 +00:00
Spencer Janssen
d1c29a40cf Update pragmas for GHC 6.8 compatibility 2007-11-04 21:55:07 +00:00
Spencer Janssen
cd9c592ebc Use the layout and workspaces values from the actual configuration used 2007-11-04 02:03:20 +00:00
Spencer Janssen
131e060533 Float handler out of makeMain, make keys and mouseBindings dependent on XConfig for easy modMask switching 2007-11-02 02:59:24 +00:00
Spencer Janssen
4996b1bc47 We can't rely on the executable name, because it may be 'Main' 2007-11-01 20:50:57 +00:00
Spencer Janssen
4b2366b5ce Get defaultGaps from the current config, not the default one 2007-11-01 20:50:25 +00:00
Spencer Janssen
0590f5da9e exposed-modules 2007-11-01 19:33:31 +00:00
Spencer Janssen
c3c39aae12 Hierarchify 2007-11-01 18:08:46 +00:00
Spencer Janssen
7bc4ab41c7 Main.hs -> DefaultConfig.hs, add new Main.hs with 'buildLaunch' 2007-11-01 17:57:49 +00:00
Spencer Janssen
7dc2d254d1 Layouts.Choose: handle ReleaseResources 2007-11-01 15:23:02 +00:00
Spencer Janssen
528d51e58a Layouts.Choose: send Hide to non-selected layout 2007-11-01 15:11:47 +00:00
Spencer Janssen
9ef3fdcf08 Export mirrorRect 2007-11-01 08:56:31 +00:00
Spencer Janssen
e8d3f674ef Only export main from Main 2007-11-01 08:23:26 +00:00
Spencer Janssen
8a5d2490bb Add readsLayout, remove the existential from XConfig 2007-11-01 08:21:55 +00:00
Spencer Janssen
22aacf9bf6 Delete Main.hs-boot! 2007-11-01 08:00:45 +00:00
Spencer Janssen
b0b43050f4 Remove manageHook from Main.hs-boot 2007-11-01 07:53:08 +00:00
Spencer Janssen
23035e944b Remove workspaces from Main.hs-boot 2007-11-01 07:45:56 +00:00
Spencer Janssen
bf52d34bbf -Wall police 2007-11-01 07:44:11 +00:00
Spencer Janssen
8a8c538c23 Eliminate defaultTerminal 2007-11-01 07:31:47 +00:00
Spencer Janssen
e50927ffc0 Store user configuration in XConf 2007-11-01 07:23:08 +00:00
Spencer Janssen
3789f37f25 This is a massive update, here's what has changed:
* Read is no longer a superclass of Layout
 * All of the core layouts have moved to the new Layouts.hs module
 * Select has been replaced by the new statically typed Choose combinator,
   which is heavily based on David Roundy's NewSelect proposal for
   XMonadContrib.  Consequently:
    - Rather than a list of choosable layouts, we use the ||| combinator to
      combine several layouts into a single switchable layout
    - We've lost the capability to JumpToLayout and PrevLayout.  Both can be
      added with some effort
2007-11-01 06:43:18 +00:00
David Roundy
48ccbc7fb2 cleaner version of main/config inversion. 2007-10-29 18:48:23 +00:00
David Roundy
d679ceb234 make setLayout a bit more inclusive. 2007-10-24 23:12:50 +00:00
David Roundy
7b3c1243b7 make xmonad work with inverted main/config. 2007-10-18 17:00:58 +00:00
David Roundy
97fe14dfd2 sketch of config/main inversion. 2007-10-18 16:42:30 +00:00
Don Stewart
c1e039ba88 more precise X11 version required 2007-10-31 20:32:41 +00:00
Don Stewart
9bd11aeea5 tweaks to todo 2007-10-31 16:46:18 +00:00
Don Stewart
c350caf9b8 HEADS UP: remove X11-extras dependency, depend on X11 >= 1.3.0
The X11-extras library has been merged into the larger X11 library,
so we now drop the dependency on X11-extras, and instead build 
against the new X11 library.

If you apply this patch you must build and install X11-1.3.0 or greater
first,

  http://hackage.haskell.org/cgi-bin/hackage-scripts/package/X11-1.3.0

You can also go ahead and wipe X11-extras from GHC's memory, (for ghci to work
out of the box with the testsuite)

  $ ghc-pkg unregister X11-extras
  $ ghc-pkg unregister --user X11-extras
2007-10-30 22:08:24 +00:00
Spencer Janssen
066da1cd99 New windows start in the iconic state 2007-10-28 06:39:49 +00:00
Don Stewart
cadf81976f add text on using xprop to find client names 2007-10-27 16:30:31 +00:00
Don Stewart
ddd1fa9cae add text reminding people to run mod-shift-space 2007-10-26 22:52:28 +00:00
Brent Yorgey
3bd63adb60 StackSet.hs: (insertUp): remove comments about new window being made master window, since that clearly isn't true. 2007-10-22 21:08:56 +00:00
Brent Yorgey
e384a358b5 Replace 'findIndex' with 'findTag', which more accurately describes what the function does.
I realize this is a big change, but the name 'findIndex' was confusing for me, since I expected it to return some sort of integer.  What it actually does, of course, is return a workspace tag, which might be more general than an index.
Of course, this change breaks several contrib modules; I'll submit a patch to make the change there as well.
2007-10-22 20:41:05 +00:00
Brent Yorgey
8971ab7fae StackSet.hs: (ensureTags): elaborate into a more descriptive comment. 2007-10-22 20:22:12 +00:00
Brent Yorgey
2e8794d0f3 StackSet.hs: remove dead code. 2007-10-22 19:26:36 +00:00
Brent Yorgey
92d58ae0a8 StackSet.hs: (differentiate): 'Texture' doesn't mean anything to me; replace with a more descriptive comment. 2007-10-22 19:13:33 +00:00
Brent Yorgey
33e14e7ba7 StackSet.hs: (new): better comment; 'm' is not an integer, it is a list of screen descriptions. 2007-10-22 18:34:11 +00:00
Brent Yorgey
ec45881d4c StackSet.hs: align some comments 2007-10-22 16:16:01 +00:00
Brent Yorgey
b73ac809ba StackSet.hs: small grammar fix and better flow in comment 2007-10-22 16:08:58 +00:00
Brent Yorgey
d0507c9eb3 StackSet.hs: better comments regarding hidden/visible workspace tracking for Xinerama
I'm not 100% sure that I understand what's going on here, but it seems as though the comment still described an older state of affairs.  I don't see any Map Workspace Screen keeping track of visible workspaces.
2007-10-22 16:02:39 +00:00
Spencer Janssen
fc82a7d412 Add Config.terminal 2007-10-24 10:53:54 +00:00
Don Stewart
cc019f487c explain that you need ghc as well 2007-10-24 03:05:20 +00:00
Spencer Janssen
4c7cf15cdb xmonad, not XMonad 2007-10-23 23:49:00 +00:00
gwern0
350a4d6f6b STYLE: enlarge on existing principles
Comments: the -Wall thing was just trying to say -Wall -Werror should work. The license thing was too narrow - or are my public domain contributions unwelcome because they are not BSD-3? I think comments are most important for exported functions users will use; it isn't so important for helper functions (used only in the module) to be very well-documented, right?
2007-10-23 22:52:25 +00:00
Don Stewart
1ddaffbfba start on style guide 2007-10-23 22:14:22 +00:00
Eric Mertens
0903c76d40 Operations.hs: flip maybe id is fromMaybe 2007-10-18 23:14:18 +00:00
Eric Mertens
156a89b761 Deobfuscate Tall layout 2007-10-18 23:13:29 +00:00
Spencer Janssen
1ea1c05617 setInitialProperties after placing windows 2007-10-19 20:13:10 +00:00
Spencer Janssen
f5ad470815 setInitialProperties after placing windows 2007-10-19 20:13:10 +00:00
Spencer Janssen
1be4bc5d91 Ignore borders in the stored RationalRects of floating windows.
Also, add 'floatWindow' which computes the actual Rectangle for that window,
including border.
2007-10-19 06:39:22 +00:00
Spencer Janssen
0514380d76 Only assign workspace keys up to xK_9. Related to bug #63 2007-10-19 08:37:46 +00:00
Spencer Janssen
18cf8fbb10 Ignore borders in the stored RationalRects of floating windows.
Also, add 'floatWindow' which computes the actual Rectangle for that window,
including border.
2007-10-19 06:39:22 +00:00
Spencer Janssen
eb65473591 I prefer fmap over liftM 2007-10-19 06:31:04 +00:00
Devin Mullins
c734586275 change 0/1/3 to named states, per X11-extras darcs head 2007-10-18 02:16:51 +00:00
David Roundy
74131eb15f remove StackOrNot type synonymn. 2007-10-17 20:14:06 +00:00
Eric Mertens
ac94932345 Operations.hs: make use of notElem and notMember 2007-10-17 17:43:57 +00:00
Spencer Janssen
bec871d254 Bump XMonadContrib version 2007-10-16 21:52:44 +00:00
Spencer Janssen
258f85dd08 Bump X11, X11-extras versions in the README 2007-10-16 21:26:36 +00:00
l.mai
16abab4241 reformat comments 2007-10-16 16:29:20 +00:00
Spencer Janssen
01cf4a5581 Whitespace fixes for Properties.hs 2007-10-15 02:27:57 +00:00
Spencer Janssen
bd6a52e587 Clean up trailing whitespace 2007-10-15 02:23:22 +00:00
Devin Mullins
0938298f29 explain numlockMask 2007-10-14 00:55:25 +00:00
Devin Mullins
5bd96a8e1a whitespace cleanup in Config.hs 2007-10-14 00:53:42 +00:00
Don Stewart
874e6f80f0 bump the version tag to 0.4, we're almost there 2007-10-13 23:27:58 +00:00
Don Stewart
6fecf7c425 document, and use better names, for serialising/existential-dispatch framework 2007-10-13 23:21:50 +00:00
Don Stewart
3a18204adb typo in comment 2007-10-13 23:08:28 +00:00
Don Stewart
2599706141 more todos 2007-10-13 22:52:00 +00:00
Don Stewart
2edc5a92c2 done 2007-10-13 22:35:36 +00:00
Don Stewart
b6d36f3c70 release tasks 2007-10-13 22:33:47 +00:00
Don Stewart
5c9850bf6d some more layout clean ups 2007-10-13 22:23:17 +00:00
Don Stewart
3f3b4251c2 clean up Layout code a little more 2007-10-13 22:10:24 +00:00
Don Stewart
2de6cc7cf1 restore magic markup comments 2007-10-13 21:23:51 +00:00
Don Stewart
3aa746c0db defer to sjanssen's manageHook comment 2007-10-13 21:03:46 +00:00
Don Stewart
48b001f9a2 Heads up: rework the Config.hs file comments, and some variable names. Please manually resync your Config.hs if you're tracking the darcs branch 2007-10-13 21:01:49 +00:00
Don Stewart
775172983b clean up names of layout code 2007-10-13 20:43:00 +00:00
Spencer Janssen
f5bec53b83 Another manageHook example 2007-10-13 20:56:05 +00:00
Spencer Janssen
77e3876d07 Better comment for the default manageHook 2007-10-13 20:33:40 +00:00
Don Stewart
f439e766a4 add can't happen case to silence incomplete patterns in StackSet.hs 2007-10-13 18:55:25 +00:00
Spencer Janssen
c436e63a15 Bump X11-extras dependency 2007-10-12 20:37:21 +00:00
Spencer Janssen
d610407cf8 Respect ExitExceptions, fixes a regression where exitWith had no effect 2007-10-12 15:28:01 +00:00
Spencer Janssen
f7d6f6b6f7 Make runX return XState 2007-10-12 15:15:24 +00:00
David Roundy
6dba9ddeb3 fix potential hole in userCode.
This makes userCode catch errors even when the
user does something like (return undefined).
2007-10-12 15:02:53 +00:00
Andrea Rossato
49f64197b2 Haddox fix 2007-10-12 10:05:51 +00:00
Spencer Janssen
1f625a6c0d Add userCode function for the popular m catchX return () 2007-10-12 01:42:17 +00:00
David Roundy
1eaee82e85 catch exceptions when calling user-written code.
This is a minimal approach that only catches error
in actual user-written code.
2007-10-12 01:33:05 +00:00
David Roundy
07be5998c0 use the right catch in catchX.
Don't ask *me* why the prelude includes a version of
catch that is worse than useless (because it lulls you
into a feeling of safety).
2007-10-12 01:14:50 +00:00
David Roundy
6d7307030a fix one last bug w.r.t. issue 55. 2007-10-12 01:05:09 +00:00
Don Stewart
6c94b3b217 more comments 2007-10-06 15:43:51 +00:00
David Roundy
1a48b527ff one more comment. 2007-10-11 15:44:23 +00:00
David Roundy
75874040cc add comments in XMonad.
This change also removes readLayout as a top level function,
since it's only used once.
2007-10-11 15:29:42 +00:00
Spencer Janssen
e331dd4a82 Nuke old TODOs, add a documentation TODO 2007-10-11 02:21:27 +00:00
Spencer Janssen
3cf5c1f9d4 Set the border color of new windows, nice catch by mauke 2007-10-11 02:16:27 +00:00
Spencer Janssen
4cfe583f63 Bump required X11-extras version to 0.3.1 2007-10-10 16:57:05 +00:00
Spencer Janssen
d348f2ae72 Only adjust floating windows that are actually larger than the screen
Also, fix a typo caught by Xiao-Yong Jin on the mailing list.
2007-10-10 06:26:04 +00:00
Shachaf Ben-Kiki
41063f2e57 Add LANGUAGE pragmas
It seems that GHC 6.6 just enables -fglasgow-exts when it sees any LANGUAGE
pragma, so not all of them were added; this patch adds the rest of them, which
is necessary for xmonad to compile in GHC >=6.7.
2007-10-08 02:11:07 +00:00
Ferenc Wagner
42dde26d4d The empty line isntcomment.
There is a separate filter for that case.
2007-10-06 19:12:31 +00:00
Christian Thiemann
c66ff8335e Add event handler for PropertyNotifyEvent that calls logHook if window title changed 2007-10-06 17:54:58 +00:00
Spencer Janssen
f7ecf70a35 Moving to code.haskell.org 2007-10-06 19:18:43 +00:00
Don Stewart
fd10c198e6 comments need to be given for all top level bindings 2007-10-06 15:41:27 +00:00
Don Stewart
c49b8f567f a bunch of things in XMonad.hs are missing top level comments! 2007-10-06 15:36:08 +00:00
Devin Mullins
1d0191184f add mapWorkspace tests
(just completely duplicated the two mapLayout tests :)
2007-10-06 07:31:29 +00:00
Don Stewart
6c38226553 change email 2007-10-06 10:49:01 +00:00
Don Stewart
5cd9094f58 style on layout class code 2007-10-06 10:46:06 +00:00
Don Stewart
053f1adb7c avoid name class with forever in 6.8 2007-10-06 10:35:30 +00:00
David Roundy
6294e6adf5 add pureMessage. 2007-10-05 14:05:53 +00:00
Don Stewart
1f9e77bd90 polish some syntax 2007-10-06 10:29:18 +00:00
Devin Mullins
8d3b6fa304 oops, need to export 2007-10-06 05:50:59 +00:00
Devin Mullins
6316d4f2ff darcs setpref test
Fix, per that Main extraction I made the other day.
2007-10-06 05:43:33 +00:00
Devin Mullins
a88a0b1b8b (cleanup) extract mapWorkspace out of renameTag 2007-10-06 05:41:04 +00:00
Don Stewart
bab04b71d3 comment out type error'd property 2007-10-06 10:22:25 +00:00
Don Stewart
d83ce46a1e add floating property 2007-10-06 10:06:54 +00:00
Don Stewart
aaaeae54c3 mention C headers 2007-10-06 09:40:06 +00:00
Spencer Janssen
e0bcad162f Comment only 2007-10-05 03:44:45 +00:00
Spencer Janssen
b07e334405 Move grabButtons/Keys into X 2007-10-05 03:41:02 +00:00
Spencer Janssen
c237441003 Make WindowSet serialization robust to layout changes 2007-10-05 00:00:31 +00:00
Spencer Janssen
42b691d515 Add mapLayout 2007-10-04 23:45:37 +00:00
Devin Mullins
65f3f4db8a extract Properties module for re-use by contrib tests
I want to reuse Properties' Arbitrary instance (as well as the T and
NonNegative types) in an upcoming set of SwapWorkspaces QC props.
`module Main where import Main` doesn't work too well. :)

If this patch is accepted, the darcs 'test' pref should be modified to
"-itests tests/Main.hs".
2007-10-04 07:58:52 +00:00
Spencer Janssen
172e046e84 Remove commented code 2007-10-04 20:02:00 +00:00
Spencer Janssen
7dac92057d manageHook: use the curry style, better documentation 2007-10-03 16:24:04 +00:00
Spencer Janssen
8dbf8896c9 Pointfree 2007-10-03 16:16:43 +00:00
Spencer Janssen
f11ce95528 Remove unused import 2007-10-03 16:16:21 +00:00
Spencer Janssen
d57aab25ef Float Gimp too 2007-10-03 16:13:05 +00:00
Spencer Janssen
89645e0999 List possibleLayouts last, because users are less likely to modify it 2007-10-02 21:47:08 +00:00
Spencer Janssen
ab0ebe1050 Docs for defaultLayout and defaultLayouts 2007-10-02 21:45:17 +00:00
David Roundy
8e303a6bea clean up Config a bit. 2007-10-02 20:36:36 +00:00
David Roundy
e70fb29efc some renaming of classes and data types. 2007-09-29 19:13:20 +00:00
Spencer Janssen
2afa8c3a7a Don't manage kdesktop either 2007-10-02 18:24:55 +00:00
Spencer Janssen
ce0d5d376d Refactor, ignore desktop_window too 2007-10-02 17:52:58 +00:00
Spencer Janssen
4bcad8fe60 Automatically float MPlayer windows 2007-10-02 17:47:22 +00:00
Spencer Janssen
da3db68b59 Add rules for gnome-panel and kicker 2007-10-02 17:42:43 +00:00
Spencer Janssen
045ed777a2 Pass window name and class info to manageHook 2007-10-02 17:40:24 +00:00
Spencer Janssen
e8bbba9694 Send ClassHints to manageHook 2007-10-01 17:52:46 +00:00
Spencer Janssen
8b3dc01e53 Operations.windows is responsible for setting initial properties, remove redundant code from Main 2007-10-01 17:06:28 +00:00
Spencer Janssen
8b8433a9e7 First cut at manageHook 2007-10-01 16:46:27 +00:00
Spencer Janssen
acbe7976d7 Add StackSet.allWindows 2007-10-01 16:39:59 +00:00
David Roundy
d05b01431d set border color more judiciously, so layouts can customize this. 2007-09-28 23:53:46 +00:00
Don Stewart
60a40be09e deeper test for differentiate. back to 100% coverage 2007-09-30 07:50:18 +00:00
Don Stewart
2b6a200ad3 properties for tag renaming 2007-09-30 07:46:41 +00:00
Don Stewart
2196ab7469 test lookupWorkspace more deeply 2007-09-30 07:38:22 +00:00
Aaron Denney
ff1918ad20 On change of keyboard mapping, grabKeys from the root window. 2007-09-29 22:47:55 +00:00
Andrea Rossato
5e3317b28e Operation: coding style conformance 2007-09-28 11:27:44 +00:00
Spencer Janssen
306b3c11c3 StackSet uses PatternGuards 2007-09-28 18:25:10 +00:00
David Roundy
5ef7c5f5d0 define defaultLayout in Config.hs. 2007-09-28 02:02:08 +00:00
Don Stewart
16d4ce5706 merge, update test hook 2007-09-29 14:20:41 +00:00
Don Stewart
6640e434bf 100% coverage of alternative branches 2007-09-28 23:57:45 +00:00
Don Stewart
cee31df81d add some more properties for failure cases 2007-09-28 23:32:30 +00:00
Don Stewart
029dd68860 polish 2007-09-28 23:28:39 +00:00
Don Stewart
bd64d169fe comments and formatting only 2007-09-28 22:05:23 +00:00
Spencer Janssen
d0d81db6de Use LANGUAGE pragmas over -fglasgow-exts 2007-09-28 18:14:38 +00:00
David Roundy
f1c1e982a2 merge old workspace tags with new on restart. 2007-09-26 18:33:09 +00:00
Spencer Janssen
60dda50181 SomeLayout: use the description of the wrapped layout 2007-09-28 05:23:44 +00:00
Spencer Janssen
3b64981c78 LayoutSelection: describe the active layout only 2007-09-28 05:18:58 +00:00
David Roundy
a7c4c38ba8 put transients completely on the screen when possible. 2007-09-27 21:10:14 +00:00
Spencer Janssen
34bbbf59c4 setLayout should not call sendMessage, because sendMessage calls windows 2007-09-28 01:15:10 +00:00
Spencer Janssen
4fd7353d8e Add setLayout to the core 2007-09-28 00:22:41 +00:00
Spencer Janssen
7e8de677cb Document otherPossibleLayouts 2007-09-28 00:02:50 +00:00
Spencer Janssen
3a9dc57c69 Minor formatting 2007-09-28 00:00:25 +00:00
Spencer Janssen
5f9222efb4 otherPossibleLayouts is empty by default 2007-09-27 23:58:45 +00:00
Spencer Janssen
d1fdd4a020 Update kind changes in the -class branch 2007-09-27 22:27:30 +00:00
Spencer Janssen
2ab2195782 Refactor floating code in manage 2007-09-27 19:55:34 +00:00
David Roundy
71bce5e525 fix bug where ReleaseResources wasn't getting sent to all layouts. 2007-09-25 21:58:16 +00:00
Spencer Janssen
9c78ba538b Simplify readLayout, comment on surprising behavior 2007-09-25 21:17:08 +00:00
David Roundy
68c72b34e1 fix bug in reading of SomeLayouts. 2007-09-25 20:28:01 +00:00
David Roundy
2caf68ee69 add support for parseable layouts not in the default. 2007-09-25 17:41:34 +00:00
David Roundy
f420ae881d rename modifyLayout to handleMessage. 2007-09-25 18:29:06 +00:00
David Roundy
e062265b38 make it easier to define pure layouts. 2007-09-25 17:05:03 +00:00
David Roundy
9c35abaa46 Make a String description part of each Layout. 2007-09-24 18:57:53 +00:00
Andrea Rossato
ee39e7fdb8 broadcast a ReleaseResources before restarting 2007-09-24 19:39:15 +00:00
Andrea Rossato
e6fb743e5a Added LayoutMessages
This patch adds some more messages to manage layout: Hide is sent to
layouts in that are not visible anymore. ReleaseReasourses is sent
before a restart.
2007-09-24 19:35:13 +00:00
David Roundy
0b11d6666d update screens for new kind of StackSet. 2007-09-24 13:45:45 +00:00
David Roundy
4a7ec374d0 create default modifyLayout that ignores messages. 2007-09-23 11:52:19 +00:00
David Roundy
1c603ebc4b add layout selection back into core xmonad using LayoutSelection.
This is just a reimplementation of LayoutChoice.
2007-09-21 21:21:59 +00:00
David Roundy
3af0ccf73c make layouts preserved over restart 2007-09-21 20:43:16 +00:00
David Roundy
fe397edf4a move Layout into StackSet.
WARNING! This changes the format of StackSet, and
will definitely mess up your xmonad state, requiring
at minimum a restart!
2007-09-20 22:12:48 +00:00
David Roundy
70282f23dc add (unused) Layout to StackSet. 2007-09-20 21:28:43 +00:00
David Roundy
f3f12383f0 remove unneeded Ord constraint. 2007-09-20 21:05:27 +00:00
David Roundy
cb13207644 eliminate a few Eq a constraints in StackSet. 2007-09-20 21:01:43 +00:00
Spencer Janssen
eb1e38405d Pointfree Mirror and SomeLayout instances 2007-09-20 21:10:42 +00:00
Spencer Janssen
d43384cfc7 Use derived Show and Read instances for Mirror 2007-09-20 20:57:11 +00:00
David Roundy
197c834331 define readLayout to create a SomeLayout based on a set of possible layout types. 2007-09-20 18:15:06 +00:00
David Roundy
5f12ca0faa add Read instance to Layout. 2007-09-20 17:45:29 +00:00
David Roundy
b4929576e7 add Show instance to Layout 2007-09-20 16:12:08 +00:00
David Roundy
0e5f8b03e8 eliminate ugly OldLayout. 2007-09-20 15:52:37 +00:00
David Roundy
3f03dcb5c1 move Layout stuff into class (hokey first cut). 2007-09-14 21:59:59 +00:00
Don Stewart
bee79c83e6 add prop for 'differentiate' 2007-09-27 23:19:28 +00:00
Karsten Schoelzel
29a5256c10 document shiftWin 2007-09-27 13:42:05 +00:00
Don Stewart
6cff2dddcf new QC properties: floating a window is reversible, screens includes current screen 2007-09-27 22:04:31 +00:00
Don Stewart
d1ad738f6b Add 3 QC properties for focusMaster: local, idempotent, preserves invariant 2007-09-27 21:44:01 +00:00
Don Stewart
3b6bfbf54c no regents in xmonad license 2007-09-27 21:43:17 +00:00
Don Stewart
f8c0ae5407 note that we use pattern guards in the .cabal file 2007-09-27 21:42:30 +00:00
Don Stewart
f1aa00f96f Add StackSet.focusMaster (mod-m) to move focus to master 2007-09-27 21:39:37 +00:00
Don Stewart
5e943d512c use hPrint instead of hPutStrLn 2007-09-27 21:39:01 +00:00
Spencer Janssen
019315e70c Split float up 2007-09-24 09:06:06 +00:00
Spencer Janssen
bc525b79e3 Use the new StackSet.screens in windows 2007-09-24 09:05:23 +00:00
Spencer Janssen
f67ebbf495 Add StackSet.screens 2007-09-24 09:04:25 +00:00
Don Stewart
3060c36d00 fmt, and tiny comment seeking clarification 2007-09-17 23:46:58 +00:00
Spencer Janssen
c6f346f887 Eliminate Operations.sink too 2007-09-17 21:40:52 +00:00
Spencer Janssen
e87a111a50 Remove Operations functions which have StackSet equivalents, just use 'windows foo' instead 2007-09-17 21:19:53 +00:00
Alex Tarkovsky
3b5ca225f6 Change manpage token @@ to %! to avoid conflicts with Haddock (xmonad) 2007-09-16 23:52:29 +00:00
Spencer Janssen
46ef80ad06 Haddockify delete' comments 2007-09-17 19:41:14 +00:00
Karsten Schoelzel
b72c096bc6 Fix float behaviour, add shiftWin.
First, if float is called with window which is on a hidden workspace,
then the window will remain on that hidden workspace.

Now the focus should change more as expected:
float w = (view current) . (shiftWin ws w)
    where
        current is the current screen/workspace
        shiftWin ws w is: - view the workspace w is on
            - set focus on w
            - shift ws
            - set focus back to window it was on that workspace
                unless w was focused

shiftWin was add to StackSet.hs
2007-09-10 09:03:29 +00:00
Karsten Schoelzel
0842194940 Add delete' for use in shift
Rename delete to delete' so we can clear floating status in delete,
thus removing one special handling. 
At the moment delete' is only used in shift, but is useful for temporarily
removing a window from the stack.
2007-09-10 11:38:35 +00:00
Don Stewart
2b207a28ef update description field of cabal file 2007-09-16 02:30:16 +00:00
Don Stewart
54af88d5f6 pointfree looks nicer here 2007-09-11 05:19:28 +00:00
Spencer Janssen
b6f00e9aab Remove redundant reveal 2007-09-10 21:38:07 +00:00
Alex Tarkovsky
874a4264c3 Add missing insert markers for generate-configs.sh in Config.hs 2007-09-07 12:04:14 +00:00
Karsten Schoelzel
6898a0e583 Move lower boundary check into applySizeHints, because all users of applySizeHints
do this manually.
2007-09-05 19:21:25 +00:00
Ivan Tarasov
f668b6238a export getAtom from XMonad. 2007-08-25 17:41:56 +00:00
Spencer Janssen
bccf8dd5f8 Use show rather than string hacks 2007-09-05 20:28:16 +00:00
David Roundy
41e3b073c8 switch WorkspaceId to String. 2007-08-20 11:36:58 +00:00
Spencer Janssen
82dd5b8119 Alex Tarkovsky's docstring patch updated for conflicts 2007-09-05 19:35:58 +00:00
Don Stewart
1fb52ce2cc tasks done 2007-09-05 00:49:01 +00:00
Spencer Janssen
dede0a2ce9 README: spelling 2007-09-04 19:30:42 +00:00
Spencer Janssen
74441202a0 Bump version to 0.3 2007-09-04 19:28:41 +00:00
Spencer Janssen
bda704297c Add a link to XMonadContrib 2007-09-04 19:27:59 +00:00
Spencer Janssen
2819adfef4 Point to X11-extras-0.3 in the README 2007-09-04 19:26:43 +00:00
Spencer Janssen
8146dd46dd Depend on X11-extras >= 0.3 2007-09-03 21:52:49 +00:00
Spencer Janssen
92a1335cff Add location of X11-extras to README 2007-08-24 16:09:35 +00:00
Spencer Janssen
49cebc6130 Add docstrings for mouse controls 2007-08-24 04:59:39 +00:00
Don Stewart
314b5ee6bd todos 2007-08-22 02:28:15 +00:00
Don Stewart
aaba52043d comment only: example of 2 monitor gaps 2007-08-21 03:25:38 +00:00
David Roundy
6ec342ff75 don't refresh when setting focus to already focussed window. 2007-08-20 15:02:25 +00:00
David Roundy
8a8438a5c2 clear out motion events when processing one motion event.
This is important if the hook is slow (e.g. try adding "float w"
to the window-dragging hook), as it allows xmonad to keep up with
the motion of the mouse.
2007-08-20 00:23:51 +00:00
David Roundy
2716b1ada6 remove unneeded do. 2007-08-13 14:37:21 +00:00
David Roundy
34d8d51a77 make splitHorizontallyBy accept any RealFrac. 2007-08-13 14:37:07 +00:00
Spencer Janssen
ca0d87664b Fix new bug in screen switching 2007-08-16 21:56:29 +00:00
Don Stewart
6a273c2afa -Wall police 2007-08-16 03:31:32 +00:00
Spencer Janssen
6dcd66f16e Comment only 2007-08-15 22:40:31 +00:00
David Roundy
df4c18a181 simplify code in StackSet. 2007-08-14 01:04:22 +00:00
David Roundy
ec0995a3a6 change workspaces to [WorkspaceId] 2007-08-14 00:37:22 +00:00
Spencer Janssen
919774dff8 Operations.windows: minor refactor 2007-08-15 03:15:21 +00:00
Spencer Janssen
447d662d1d Cleanup 2007-08-10 21:39:40 +00:00
David Roundy
fae3cbebb1 move event loop out of mouseDrag. 2007-08-07 20:16:16 +00:00
David Roundy
4c40661047 only display any given window once.
This change goes along with the sticky window work.  It makes xmonad
display each window once and only once, with preference given to the
focussed screen.  It has no effect when there are no duplicate windows,
except to make things less efficient.  We could do better using Data.Set
(or Data.Map) to store the set of windows that are visible.
2007-07-24 14:13:10 +00:00
Spencer Janssen
2f3ccd7ab6 Add greedyView, make it the default action for mod-wer 2007-08-15 02:55:04 +00:00
Spencer Janssen
8bb313ea53 Remove 'Eq' constraint from StackSet.index 2007-08-07 14:43:46 +00:00
Don Stewart
2e7aa7d055 trailing whitespace only 2007-08-05 07:27:16 +00:00
Andrea Rossato
6875437c44 added workspaces to hs-boot (needed by XMonadContrib.Commands and possibly other modules) 2007-07-28 13:17:56 +00:00
Karsten Schoelzel
808894c217 QuickCheck filter preserves order 2007-07-28 18:45:34 +00:00
Karsten Schoelzel
84c6432c82 Bugfix: reordering when filtering out the last window on a workspace
Say you have three windows A B C* on a workspace with * marking the focus.
If you close C or move it to another workspace, the resulting order will be B* A,
thus reordering the other windows, defying the comment of filter.
2007-07-28 13:25:07 +00:00
Spencer Janssen
bf4388e3aa shift: use guards instead of if 2007-07-24 15:23:40 +00:00
Spencer Janssen
cc3527a975 Remove unnecessary Integral constraints 2007-07-24 15:22:57 +00:00
David Roundy
9a2f57552e make delete work when window is in multiple workspaces. 2007-07-24 14:20:45 +00:00
Spencer Janssen
189c2d31f9 Remove redundant 'n >= 0' check from shift. (from David Roundy's 'simplify shift, removing unneeded check.' patch) 2007-07-24 14:59:27 +00:00
Michael G. Sloan
5068bd27f0 Cleanup of shift code 2007-07-22 20:53:37 +00:00
Don Stewart
fc70bed46b use $HOME in examples 2007-07-19 06:33:48 +00:00
Peter De Wachter
d0482810b3 Tweak dmenu binding
Add an "eval", so quotes and environment variables get evaluated
according to sh rules.
2007-07-17 19:07:22 +00:00
Jason Creighton
c146940154 restore focus to currently focused window after "float" (closes #32) 2007-07-10 04:26:31 +00:00
Spencer Janssen
bfd638d818 Operations.screenWorkspace: return Nothing when the screen does not exist 2007-07-07 22:38:42 +00:00
Spencer Janssen
a48ec57cd9 Operations.rescreen: screen indexes start at zero 2007-07-07 22:33:34 +00:00
Spencer Janssen
54c024583f Note and workaround bugs in Operations.float 2007-07-05 19:52:13 +00:00
Spencer Janssen
2efa369dfc refresh after starting 2007-06-30 05:03:46 +00:00
Spencer Janssen
e74e8050d0 UPGRADE X11-Extras! Manage iconified windows 2007-06-30 02:10:26 +00:00
Spencer Janssen
ab830ec227 Move screen details into StackSet 2007-06-29 21:39:17 +00:00
Jason Creighton
bb12b08239 Change a window's workspace when dragging across screens (closes #30) 2007-06-28 02:50:23 +00:00
David Roundy
61d7524bcd support self-modifying layouts. 2007-06-23 20:14:47 +00:00
Don Stewart
d0566a28be comment for (dubious?) integrate' 2007-06-26 05:24:31 +00:00
David Roundy
6f9a060118 broadcast unidentified events.
This change is independent of the doLayout change I just sent in, but fixes
the problem that change introduces in Decoration, by ensuring that all
Layouts get redraw events.  I think this is the correct behavior.
2007-06-23 21:41:25 +00:00
Don Stewart
dbdf0fd5e4 add 2 properties to state where focus goes on delete of focused window 2007-06-26 04:09:07 +00:00
Don Stewart
ce28fc1eb2 fix empty case in 'filter', and note differences in semantics wrt. focus to 'delete' 2007-06-26 03:57:41 +00:00
Don Stewart
977f8328fc clean up 'StackSet.filter' for style 2007-06-26 03:32:02 +00:00
Don Stewart
776886660b minor tweaks, ideas from joachim.fasting@ 2007-06-21 03:36:13 +00:00
Don Stewart
c6da7fc14a only perform mouse events on managed windows. closes #28 2007-06-21 01:17:00 +00:00
Spencer Janssen
e99d7431c8 Update Layout documentation 2007-06-20 15:08:58 +00:00
Spencer Janssen
5dea6605fc -Wall police 2007-06-20 15:08:23 +00:00
Spencer Janssen
6091bfd0fe Stack windows in the order they are returned by doLayout 2007-06-20 15:04:19 +00:00
Don Stewart
d411736ded remove out of date `(Included with GHC)' text in README 2007-06-20 06:04:30 +00:00
David Roundy
e517aedfa1 make Layouts able to layout whatever they like. 2007-06-19 15:08:16 +00:00
Peter De Wachter
b84a9b875b float fixed size windows 2007-06-18 21:46:57 +00:00
Spencer Janssen
33bb745880 Remove all references to 'exec' 2007-06-18 20:15:32 +00:00
Don Stewart
be08dd80ec -Wall police, and turn on -fno-warn-orphans 2007-06-17 05:23:22 +00:00
David Roundy
dbd58faffe make workspace tag not need to be a Num.
This change also removes the barely used 'size' field, and replaces
it with a tagMember predicate.  The idea is to move towards the ability
to make the workspace tag be a String, which by default might be "1".."9",
but could also be customized to be something meaningful to the user.
2007-06-14 14:07:09 +00:00
Spencer Janssen
a2c5aa3612 Fix float stacking 2007-06-14 21:34:12 +00:00
Spencer Janssen
fa2b56c14e Remove 'temporary work around' in 'windows' 2007-06-14 21:14:50 +00:00
Andrea Rossato
7d1a23698f haddock tuning for StackSet.hs
with this patch the documentation of StackSet.hs will have a nice TOC
2007-06-14 06:45:11 +00:00
Jason Creighton
8169445cbd move initColor to Operations and only store the Pixel value of colors
Moving initColor to Operations allows it to be used by extensions.

The Pixel component of the color is the only thing we need, so it's simpler
just to deal with that.
2007-06-13 23:45:01 +00:00
Andrea Rossato
753b42ae65 haddick fine tuning 2007-06-13 18:59:02 +00:00
Spencer Janssen
d1e4699944 Indentation 2007-06-13 04:30:18 +00:00
Jason Creighton
62344287da prevent keyboard focus from getting lost in some cases 2007-06-13 02:53:50 +00:00
David Roundy
8cdcceab48 resolve conflict in Operations. 2007-06-12 17:06:25 +00:00
David Roundy
194a934c37 add catchX to catch exceptions. 2007-06-12 15:42:53 +00:00
David Roundy
5f8202e79e make focus, up and down complete functions.
This is a rerun of my change to make (Stack a) never be empty.  Gives
us more type-safety.
2007-06-12 15:05:55 +00:00
David Roundy
4ffee115e1 add differentiate function to StackSet to go [a] -> Stack a. 2007-06-12 13:28:53 +00:00
Spencer Janssen
00e1038d71 Make 'view' a total function 2007-06-12 14:32:48 +00:00
Don Stewart
7158a58792 fmt 2007-06-12 13:49:38 +00:00
Stefan O'Rear
c0a9636f3b -Wall police 2007-06-12 06:05:46 +00:00
Stefan O'Rear
ff6b48382c Use a more descriptive name for the layout reversal message 2007-06-12 05:58:59 +00:00
Stefan O'Rear
bb9e46df6c Use broadcastMessage in windows and switchLayout, should improve Xinerama for tabbed and make xmonad robust in the presence of state-altering unlayout hooks 2007-06-12 05:55:10 +00:00
Stefan O'Rear
f68a954fc3 Add a broadcastMessage function, which sends to all visible workspaces without refreshing. (+6 loc) 2007-06-12 05:53:39 +00:00
Spencer Janssen
d21e61a315 TODO for scan 2007-06-11 21:42:17 +00:00
Spencer Janssen
4b9bacb1f9 Set withdrawn state after calling windows 2007-06-11 21:33:27 +00:00
Spencer Janssen
9992737e84 Remove obsolete 'layout' function 2007-06-11 20:36:22 +00:00
Spencer Janssen
615a4a1af1 -Wall police 2007-06-11 20:20:07 +00:00
Spencer Janssen
33447129dd Comment only 2007-06-11 19:58:27 +00:00
Spencer Janssen
14971546bb Hide windows that are not supposed to be visible 2007-06-11 19:18:09 +00:00
Spencer Janssen
6f7030f875 -Wall police 2007-06-11 18:57:08 +00:00
Spencer Janssen
4f5c307d6f API CHANGE: Give doLayout a Stack rather than a flattened list 2007-06-11 18:26:29 +00:00
Spencer Janssen
e7b37ca646 -Wall police 2007-06-11 18:01:23 +00:00
Spencer Janssen
5f3e91676a Add StackSet.filter 2007-06-11 16:51:54 +00:00
Spencer Janssen
b3bdbf3588 Use catchIO in 'restart' 2007-06-11 16:11:52 +00:00
Spencer Janssen
00b930b09e Rename safeIO to catchIO 2007-06-11 16:06:08 +00:00
David Roundy
0d17ca9436 add safeIO which catches and logs exceptions. 2007-06-11 15:36:50 +00:00
Spencer Janssen
b668133c08 Ensure windows get at least 1 pixel for width/height 2007-06-11 06:19:30 +00:00
Spencer Janssen
330179ea20 Restrict the master/slave ratio to [0, 1] 2007-06-11 05:32:30 +00:00
Jason Creighton
854d3239cc comment only 2007-06-11 02:02:49 +00:00
David Roundy
c8b6388fb8 a few modifications to event-sending to make Tabbed layout work. 2007-06-10 15:38:36 +00:00
David Roundy
b97e8836e2 send message when "windows" is called. 2007-06-10 01:35:31 +00:00
David Roundy
ab6f210300 implement Spencer's decoration suggestion. 2007-06-10 01:22:37 +00:00
Andrea Rossato
e1885f27e1 haddock compatibility 2007-06-10 12:37:46 +00:00
Don Stewart
6365601c77 Move state logging into Config.hs, via logHook :: X () 2007-06-10 06:19:32 +00:00
Don Stewart
3bfa0930af polish serialisation code (-7 lines) 2007-06-10 04:55:51 +00:00
David Roundy
0d4a7d098f cut incorrect comment. 2007-06-09 17:34:47 +00:00
David Roundy
16c8622fbf doLayout cleanup and commented exception-handling. 2007-06-09 14:50:36 +00:00
Stefan O'Rear
1c3931a0d6 Give refresh sole responsibility for establishing window properties (-3 loc) 2007-06-09 18:58:35 +00:00
Stefan O'Rear
7706f38dc8 Give refresh sole responsibility for establishing window properties (-3 loc) 2007-06-09 18:58:35 +00:00
Don Stewart
0ada17c34a HEADS UP: (logging format change). use a custom pretty printer, for an easier format to parse, than 'show' produces 2007-06-09 13:17:16 +00:00
Don Stewart
a21c4d02f1 Add notes on using X11-extras from darcs 2007-06-09 02:50:45 +00:00
Spencer Janssen
cf9828cbcd Fix unmap handling
According to the ICCCM, clients should send a synthetic unmap event when they
initiate an unmap.  The old code waited for these synthetic unmaps to unmanage
windows.  However, certain 'obsolete' clients do not send synthetic unmaps
(notably xpdf's find dialog).  These windows entered a zombified state: xmonad
does not manage them, yet they are still mapped and raised on screen.

The new algorithm (derived from wmii):
 - track windows that are mapped on screen
 - track the number of expected unmap events for each window, increment every
   time 'hide' is called on a window that is not mapped.
 - decrement the expected unmap counter on each unmap event
 - treat an unmap event as genuine (ie. unmap the window) when:
    - the event is synthetic (per ICCCM)
    - OR there are no expected unmap events for this window
2007-06-06 21:40:06 +00:00
Don Stewart
b257658781 dead import 2007-06-06 02:52:26 +00:00
Jason Creighton
5da458c755 move extraModifiers/cleanMask to Operations.hs
so XMonadContrib can use them
2007-06-06 00:50:56 +00:00
Don Stewart
d7d8c586cb temporary workaround for delete/focus issue in fullscreen mode 2007-06-06 02:49:38 +00:00
Don Stewart
86ea7f7bc0 whitespace 2007-06-06 02:48:57 +00:00
Don Stewart
a2a0670397 simplify code 2007-06-06 00:46:03 +00:00
Don Stewart
02a9e4c589 mention why StackSet needs -fglasgow-exts (for deriving Typeable) 2007-06-05 09:26:59 +00:00
Don Stewart
d4676d93e8 comments only 2007-06-05 09:18:03 +00:00
Don Stewart
0010a23c18 clean size hint code 2007-06-05 09:13:54 +00:00
Don Stewart
7ae7029b50 Enable logging of state changes to stdout 2007-06-05 08:37:35 +00:00
Don Stewart
21e09361a6 remove accidental logging of events 2007-06-05 08:14:52 +00:00
Don Stewart
8f200d408f Fix lost eventNotifyMask bug
When resuming, we were (implicitly) relying on 'scan' to find all
windows, and reset their event masks and WM_STATE. When we moved to
Iconfified hidden workspaces, 'scan' would only find and reset states on 
the current workspace.

The result being that hidden workspace windows no longer received
enterNotify events.

Fix this by traversing the StackSet serialised during a restart, setting
the intial X states for each window, whether visible or hidden.
2007-06-05 04:30:40 +00:00
Don Stewart
d3632eb8fe whitespace only 2007-06-05 00:07:23 +00:00
Spencer Janssen
b22ebceb80 Comment only 2007-06-04 21:19:56 +00:00
Spencer Janssen
ba14f07093 Wibble. 2007-06-04 21:18:16 +00:00
Spencer Janssen
2a6d6d4ed7 -Wall police 2007-06-04 21:15:31 +00:00
Peter De Wachter
68b2859aa2 apply size hints to floating windows 2007-06-04 19:29:43 +00:00
Peter De Wachter
a10f11f623 size hints infrastructure 2007-06-04 19:27:53 +00:00
Spencer Janssen
6a2f9d739d Delete stale comment 2007-06-04 20:46:17 +00:00
Spencer Janssen
4d74099851 Comment only 2007-06-04 20:36:59 +00:00
Spencer Janssen
26b388189e Use 'windows' in 'focus' 2007-06-04 20:16:39 +00:00
l.mai
1c609288dd realign guard 2007-06-04 18:20:45 +00:00
Spencer Janssen
68a63688ad swapUp/Down are also mirrored 2007-06-04 18:35:35 +00:00
Spencer Janssen
6b8e9570c2 Remove redundant cases in swapUp/Down 2007-06-04 18:33:44 +00:00
Spencer Janssen
85e57cfa47 focusUp/Down are the same, in reversed order 2007-06-04 18:31:43 +00:00
Spencer Janssen
89a31eaf52 Simplify focusUp/Down 2007-06-04 18:22:28 +00:00
Spencer Janssen
fc70307325 Integral implies Eq 2007-06-04 18:07:45 +00:00
Spencer Janssen
f9110c999b Comment typo. 2007-06-04 18:05:54 +00:00
Spencer Janssen
795e96d353 Dump state at launch (commented for now) 2007-06-04 16:24:50 +00:00
Spencer Janssen
fec58e8a09 Small clean up 2007-06-04 06:44:18 +00:00
Spencer Janssen
d01623db88 Merge windows and refresh 2007-06-04 06:36:57 +00:00
Spencer Janssen
1912feee50 Use the new integrate function 2007-06-04 06:26:53 +00:00
Spencer Janssen
cad36baa19 Add integrate 2007-06-04 06:25:01 +00:00
Spencer Janssen
77da6e4c72 Delete stale comments 2007-06-04 06:17:19 +00:00
Spencer Janssen
71349314c5 Remove inaccurate warnings about 'hide' 2007-06-04 06:06:11 +00:00
Spencer Janssen
f2eb5ac6bb base >= 2.0 means we can use forM_ 2007-06-04 05:09:14 +00:00
Stefan O'Rear
e4e1724842 Remove no-longer-needed 'dimensions' state (-5 loc) 2007-06-04 04:47:15 +00:00
Stefan O'Rear
cd73165c63 Set WM_STATE, iconify invisible windows (+9 loc)
Note that this breaks compatibility with certain programs described as
"obsolete" in the ICCCM (1994).  See the command above the UnmapEvent handler
for details.
2007-06-04 04:23:43 +00:00
Don Stewart
225a2e89a3 clean up Main.hs slightly 2007-06-04 03:56:37 +00:00
Don Stewart
9b429f4f41 whitespace 2007-06-04 01:55:32 +00:00
Don Stewart
ca896686a1 -Wall 2007-06-04 01:46:30 +00:00
Stefan O'Rear
f06d042b56 do not cache atom values within Xmonad, instead let Xlib worry about caching (a documented feature) 2007-06-04 01:39:38 +00:00
Spencer Janssen
29a32bc146 Honor configure requests from unmanaged windows 2007-06-03 23:47:30 +00:00
Spencer Janssen
27b7cccd3a -Wall police 2007-06-03 21:20:55 +00:00
Stefan O'Rear
b20a9cff7f Correctly handle resize requests (-12 +22)
Xmonad now implements resize requests in a consistent manner.

* If the window is FLOATING, we implement the program's request, and
  correctly update the StackSet; so it will keep the new size.  This
  should work correctly even for non-current windows.

* Otherwise, we ignore the request.  As per ICCCM, we send a fake
  ConfigureNotify containing the new (unchanged) geometry.  This is
  perfectly ICCCM compliant, and if it breaks your client, it's your
  own fault.

This patch requires setConfigureEvent, which is added to X11-extras by
a patch approximately contemporaneous with this one.
2007-06-03 20:31:53 +00:00
Don Stewart
8f3258a348 comments only 2007-06-03 07:15:56 +00:00
Don Stewart
0226ba3441 Polish core layout code. Lifts limitation on nmaster > 1. it may be 0 now 2007-06-03 06:43:06 +00:00
Don Stewart
84f22f7102 heads up: polish config.hs. moves tiling-local values into lexical scope. removes wide' as an explicit mode (it's mirror tall') 2007-06-03 05:47:40 +00:00
Don Stewart
7e9fbf5883 set build-depends base>=2.0 so people can't miss the missing Read instance issue 2007-06-03 03:23:19 +00:00
Chris Mears
7ae4bc8f39 Fix out-of-date comment in Config.hs. 2007-06-02 11:43:12 +00:00
Jason Creighton
a6098f6010 only grab button{1,2,3} for click-to-focus (scrollwheel shouldn't focus) 2007-06-02 05:26:05 +00:00
Jason Creighton
72a50ead89 make mouse bindings configurable 2007-06-02 04:06:47 +00:00
Don Stewart
0be589ae8c commented out implementation state logging. if someone has a client, we can enable this 2007-06-01 08:56:26 +00:00
Jason Creighton
b46a449baf ignore numlock/capslock on mouse bindings 2007-06-01 01:51:37 +00:00
Don Stewart
9669c26fdc now we handle transients properly, and restack windows, refresh from focus is ok 2007-06-01 02:23:29 +00:00
glasser
ddffd109ce Rename withWorkspace to withWindowSet. 2007-06-01 00:13:25 +00:00
Spencer Janssen
68e6643356 Revert accidental change to border color 2007-05-31 14:55:09 +00:00
Don Stewart
7246a9e2d2 comments on why fullscreen tiling doesn't work with `implicit' floating 2007-05-31 09:05:37 +00:00
Don Stewart
777cf28bdf clean up mouse code a bit 2007-05-31 08:53:08 +00:00
Jason Creighton
3cb64d7461 first shot at a floating layer
This is a first attempting at a floating layer:

mod-button1: move window
mod-button2: swapMaster
mod-button3: resize window

mod-t: make floating window tiled again

Moving or resizing a window automatically makes it floating.

Known issues:

Hard to manage stacking order. You can promote a window to move it to the top,
(which you can do with mod-button2) but it should be easier than that.

Moving a window by dragging it to a different Xinerama screen does not move it
to that workspace.

Code is ugly.
2007-05-31 04:47:33 +00:00
Jason Creighton
1d764ecf2e remove LOC cap (but still print count after tests) 2007-05-31 04:34:17 +00:00
Spencer Janssen
5594c71e66 Remove 0.2 TODOs 2007-05-31 00:58:55 +00:00
Spencer Janssen
a3479aa9f5 Bump version to 0.2 2007-05-30 20:25:29 +00:00
Spencer Janssen
b069f84add Minor style change. 2007-05-30 18:10:06 +00:00
nickburlett
fc08bd48b4 log errors on executeFile in restart
I found it difficult to track down a problem in the restart code where xmonad was silently not restarting. This will log the error to stderr, which should show up in .xsession-errors
2007-05-30 17:10:24 +00:00
Spencer Janssen
e83ae8ba62 Depend on X11-extras >= 0.2 2007-05-30 17:36:07 +00:00
Spencer Janssen
67ae8fcd7c Require X11 >= 1.2.1 2007-05-30 17:29:09 +00:00
Don Stewart
f6b14b7123 point out restart is used to propagate changes 2007-05-30 02:10:05 +00:00
Spencer Janssen
fbfbb14658 Really change restart keybinding this time 2007-05-30 06:14:54 +00:00
Spencer Janssen
79a9c58f92 HEADS UP: Change restart keybinding to mod-q 2007-05-30 06:10:44 +00:00
Spencer Janssen
bc2e6b2112 HEADS UP: Change restart keybinding to mod-q 2007-05-30 06:10:44 +00:00
Spencer Janssen
89417a6e25 Fix 'refresh' doc string 2007-05-29 02:04:46 +00:00
Jason Creighton
2be4f5f216 Give link to bugtracker in "BUGS" section of manpage 2007-05-29 01:58:51 +00:00
Don Stewart
c023e9a681 make 'tall' layout the default on startup. more useful for new users 2007-05-29 01:46:11 +00:00
Don Stewart
da63d4a4b7 notes about which dependant packages already come with ghc 2007-05-29 00:57:48 +00:00
Don Stewart
46b04b3fa5 forgot to set focus in 'focus'. this restores the old behaviour 2007-05-28 13:45:47 +00:00
Don Stewart
0b8c9c407e don't refresh on focus events
leads to a race. this will affect how gaps are redrawn when moving to a
new screen with the mouse.
2007-05-28 13:31:27 +00:00
Don Stewart
5818e5a7fc ensure !! won't go out of bounds in modifyGap 2007-05-28 07:06:09 +00:00
Don Stewart
eda3ab2849 mention .xinitrc 2007-05-28 06:12:52 +00:00
Don Stewart
c2318fa67d update readme 2007-05-28 05:14:44 +00:00
Spencer Janssen
f85dac53e4 Add the HTML manpage 2007-05-28 06:31:22 +00:00
Spencer Janssen
39fd73a7f7 Fix manpage generator 2007-05-28 06:26:58 +00:00
Don Stewart
abdbc23551 apply gap to each screen 2007-05-28 04:47:22 +00:00
Don Stewart
cf52e66ec1 move gapcalc.c 2007-05-28 04:04:02 +00:00
Spencer Janssen
f6bac98678 Remove gapcalc.c from the sdist, add generated manpage 2007-05-28 04:06:55 +00:00
Don Stewart
94b64e7035 help man script 2007-05-28 03:38:46 +00:00
Don Stewart
58f180aefb done with gap 2007-05-28 03:35:25 +00:00
Spencer Janssen
257aa4776f Document mod-n 2007-05-28 03:35:36 +00:00
Don Stewart
0cca848c54 be sure to reset the gap list on rescreen 2007-05-28 03:18:35 +00:00
Don Stewart
c613073cb6 support per-screen gap settings. you can have different gaps on individual screens now 2007-05-28 03:15:01 +00:00
Don Stewart
1d2c5ca35a Use (Int,Int,Int,Int) for arbitrary gaps on any side of the screen 2007-05-28 02:51:35 +00:00
Spencer Janssen
b0cfe9b6ab Update extra-source-files 2007-05-27 21:06:57 +00:00
Spencer Janssen
19256758a2 Note the manpage move in xmonad.cabal 2007-05-27 20:58:57 +00:00
Don Stewart
c7655df3cb refactor only 2007-05-27 15:43:53 +00:00
Don Stewart
25616c3b9f comments on alternative gap movement policies 2007-05-27 15:32:11 +00:00
Don Stewart
d16d751207 when focus is called from an event, better refresh too, since it might have switched workspaces (so gap follows screen focus) 2007-05-27 15:19:42 +00:00
Don Stewart
2231879268 only set gap on current physical screen 2007-05-27 15:08:05 +00:00
Don Stewart
5fdbe0711d gap 2007-05-27 15:00:53 +00:00
Don Stewart
7fb1dd96de todo 2007-05-27 14:32:16 +00:00
Don Stewart
77f59efcc6 revert raiseWindow in focus. Leads to some funny races with pop ups. Harmless with status bar support now 2007-05-27 13:45:05 +00:00
Don Stewart
bb4bd97c87 mod-b, toggle on or off the status bar gap 2007-05-27 12:59:28 +00:00
Don Stewart
a64c9f1856 Add new config value, defaultMenuGap, for specifying a gap for a status bar
By default, it is 0 (set in Config.hs), but set this to a pixel count to
get a permanent gap at the top of the screen. You can then at startup
launch dzen, and it will run in this gap, and not be obscured by other
windows.

Perfect for a persistant status bar.
2007-05-27 12:27:02 +00:00
Don Stewart
e5e4b46ffa raiseWindow when settings focus. The focused window should always be raised, I think 2007-05-27 09:41:05 +00:00
Don Stewart
7be0a2103d Be a bit more conservative with -O flags, and GC. Hope to avoid runtime GC bug 2007-05-27 07:44:38 +00:00
Don Stewart
ef5326ccff dead code 2007-05-27 07:26:52 +00:00
Don Stewart
ee2c2c311b refactor code smell in Operation.hs 2007-05-27 07:21:35 +00:00
Don Stewart
fdc6af5faa clean Main.hs slightly 2007-05-27 07:21:06 +00:00
Don Stewart
325329e5d7 todo 2007-05-27 06:37:40 +00:00
Jason Creighton
8cfe050be7 Generate keybindings section in manpage from Config.hs 2007-05-27 06:29:14 +00:00
Don Stewart
d3f56af172 specify --user, spotted by fasta 2007-05-27 01:40:32 +00:00
Don Stewart
60f4f4e5e4 HEADS UP: change key binding for swapLeft/Right and IncMaster
The use of arrow keys for swapLeft/Right clash with firefox's back
button. Use the more intuitive mod-shift-jk for this. (It's a movement
operation, after all).

This clashes with IncMaster, so we use mod+comma and mod+period for
these (i.e. the keys mod < and mod > , to move windows to and from the
master area).

While we're here, replace the use of the terms 'left' and 'right' for
navigation, in comments and identifiers, with 'up' and 'down' instead.
Hence mod-j == focusDown. Far more intuitive for people (dons) who live
in fullscreen mode and have vim movement wired into their central
nervous system.

Principle of least VI surprise: movement down or up means using j and k.
2007-05-26 11:14:53 +00:00
Don Stewart
6346e11ff6 type sig for abort. 2007-05-26 06:14:50 +00:00
Neil Mitchell
a5aa4b1686 Add an abort function, called for deliberate and intentional errors 2007-05-23 23:32:12 +00:00
Neil Mitchell
6f9998ad27 Delete the Catch wrapper, no longer required by the latest version of Catch 2007-05-23 23:29:41 +00:00
Don Stewart
e64e434750 start on TODO list needed for 0.2 to be tagged 2007-05-26 06:07:20 +00:00
glasser
52608185b4 Add a test that the size field of StackSet is correct to QuickCheck invariant. 2007-05-25 16:31:59 +00:00
Spencer Janssen
8d6b914409 Formatting only 2007-05-25 21:44:14 +00:00
Rob
7afc18b0e1 Quickcheck property to check that delete / focus behaviour
See patch "Deleting a window should not affect focus". Checks this property.
2007-05-25 03:54:32 +00:00
Rob
a36bd31973 Fix bug in noDuplicate invariant
ws used by noDuplicates is actually a list of list of elements which 
will pretty rarely raise any flags even if the StackSet actually does
contain duplicates. This patch concatenates ws to ensure the quickcheck
property tests accurately.
2007-05-25 06:08:42 +00:00
Spencer Janssen
d502891ef0 Add a note about already installed packages 2007-05-25 15:31:43 +00:00
Rob
f8caf7f982 Deleting a window should not affect focus
This fixes a bug whereby deleting a window will first move focus to
that window before deleting it without moving focus back afterwards.

The fix generalises the remove inner function to delete a window from
the stack whether it's in focus or not. If the window is in focus,
behaviour remains as it was.
2007-05-25 02:41:18 +00:00
Spencer Janssen
654e64b772 Use --resume by default 2007-05-23 19:14:18 +00:00
bobstopper
bcf305cd1e add swapLeft and swapRight 2007-05-22 05:00:08 +00:00
Spencer Janssen
0df8dffc78 restart: don't preserve old args 2007-05-22 06:03:57 +00:00
Spencer Janssen
865939b660 Wibble 2007-05-22 04:38:44 +00:00
Spencer Janssen
9b52525417 Generalize withDisplay's type 2007-05-22 04:37:58 +00:00
Don Stewart
3202fa0673 refactor using whenX 2007-05-22 04:31:16 +00:00
Spencer Janssen
07a354e5a3 Add preliminary randr support 2007-05-22 04:02:28 +00:00
Neil Mitchell
c4dd126200 Update the Catch checking to the new interface for StackSet 2007-05-22 01:54:22 +00:00
Spencer Janssen
e300df5425 Remove the magic '2' 2007-05-21 23:45:35 +00:00
Spencer Janssen
d074b1bcfd List --resume args first 2007-05-21 23:24:27 +00:00
Spencer Janssen
ff975f6d40 Move special case 'view' code into 'windows'.
This is ugly right now -- I promise to clean it up later.
2007-05-21 21:56:46 +00:00
Spencer Janssen
a9d7b7ef49 Experimental support for a beefier restart. 2007-05-21 19:46:53 +00:00
Spencer Janssen
270d80297f Catch the exception rather than explicitly checking the PATH 2007-05-21 19:19:00 +00:00
Spencer Janssen
3c2ad2509e Put restart in the X monad 2007-05-21 19:07:49 +00:00
Spencer Janssen
90dd7705a8 Show instances for WorkspaceId and ScreenId 2007-05-21 19:07:04 +00:00
Spencer Janssen
127fd0b309 Read instance for StackSet 2007-05-21 18:45:04 +00:00
Spencer Janssen
c8cfc1faca Remove redundant fromIntegrals 2007-05-21 16:51:23 +00:00
Spencer Janssen
daefb508d7 Use Position for dimensions 2007-05-21 16:28:09 +00:00
Spencer Janssen
b59d4d1dc0 Make screen info dynamic: first step to supporting randr 2007-05-21 15:27:59 +00:00
Don Stewart
b1345e037c modify 2007-05-21 11:57:50 +00:00
Don Stewart
ea80d2a71f Move xinerama current/visible/hidden workspace logic into StackSet directly. 2007-05-21 05:52:53 +00:00
Jason Creighton
02073c547b s/workspace/windowset/ 2007-05-21 04:03:30 +00:00
Jason Creighton
5c44fa79fd focusWindow: always view the containing workspace first 2007-05-21 03:55:51 +00:00
Don Stewart
d28d4251e0 explicit export list for StackSet 2007-05-21 02:52:50 +00:00
Don Stewart
d3d058345d comment only 2007-05-20 09:08:46 +00:00
Jason Creighton
b757a526db only hide old workspace on view if the old workspace is not visible (Xinerama) 2007-05-21 03:14:35 +00:00
Spencer Janssen
1c4b0a51d8 Fix mod-j/k bindings 2007-05-21 03:02:53 +00:00
Spencer Janssen
2e5084319a Be explicit about suspicious System.Mem import 2007-05-20 16:57:41 +00:00
Don Stewart
77e46027ed HEADS UP: Rewrite StackSet as a Zipper
In order to give a better account of how focus and master interact, and
how each operation affects focus, we reimplement the StackSet type as a
two level nested 'Zipper'. To quote Oleg:

    A Zipper is essentially an `updateable' and yet pure functional
    cursor into a data structure. Zipper is also a delimited
    continuation reified as a data structure.

That is, we use the Zipper as a cursor which encodes the window which is
in focus. Thus our data structure tracks focus correctly by
construction! We then get simple, obvious semantics for e.g. insert, in
terms of how it affects focus/master. Our transient-messes-with-focus
bug evaporates. 'swap' becomes trivial.

By moving focus directly into the stackset, we can toss some QC
properties about focus handling: it is simply impossible now for focus
to go wrong. As a benefit, we get a dozen new QC properties for free,
governing how master and focus operate.

The encoding of focus in the data type also simplifies the focus
handling in Operations: several operations affecting focus are now
simply wrappers over StackSet.

For the full story, please read the StackSet module, and the QC
properties.

Finally, we save ~40 lines with the simplified logic in Operations.hs

For more info, see the blog post on the implementation,

    http://cgi.cse.unsw.edu.au/~dons/blog/2007/05/17#xmonad_part1b_zipper
2007-05-20 07:00:53 +00:00
Spencer Janssen
f9af744b1e Read is not needed for StackSet 2007-05-16 05:42:33 +00:00
Jason Creighton
4206c4bae9 variable number of windows in master area 2007-05-16 03:14:37 +00:00
Spencer Janssen
810c19d7f2 Use camelCase, please. 2007-05-16 01:44:54 +00:00
David Roundy
3cc55de0f4 beautify tile 2007-05-15 15:40:11 +00:00
David Roundy
21cbab3f06 put doLayout in the X monad. 2007-05-12 21:53:01 +00:00
Spencer Janssen
67fe5ab219 setsid() before exec. Intended to fix issue #7 2007-05-14 04:45:47 +00:00
David Roundy
54ee507cca keep focus stack. 2007-05-10 13:16:37 +00:00
Jason Creighton
378aa87173 bump LOC limit to 550 2007-05-10 03:27:31 +00:00
Spencer Janssen
47ae5e4ea5 Remove broken prop_promoterotate, replace it with prop_promote_raise_id 2007-05-08 21:19:07 +00:00
Spencer Janssen
c4030d45e2 Disable shift_reversible until focus issues are decided. 2007-05-08 21:09:52 +00:00
Spencer Janssen
f5b0df6a73 Disable delete.push until focus issues are decided 2007-05-08 20:49:21 +00:00
Spencer Janssen
c5c958dc2c Remove unsafe fromJust 2007-05-08 16:38:22 +00:00
Neil Mitchell
626d25bb3a Add the initial Catch testing framework for StackSet 2007-05-08 15:46:21 +00:00
Neil Mitchell
97141b9a07 Work around the fact that Yhc gets defaulting a bit wrong 2007-05-08 12:49:49 +00:00
Spencer Janssen
4afb251f41 Make tests typecheck 2007-05-08 15:24:49 +00:00
Spencer Janssen
a846eb18ff Remove unsafe use of head 2007-05-08 15:21:16 +00:00
Spencer Janssen
f03ca10714 Make 'index' return Nothing, rather than error 2007-05-08 15:12:00 +00:00
Spencer Janssen
ba9e15e772 Use 'drop 1' rather than tail, skip equality check. 2007-05-08 15:09:43 +00:00
Spencer Janssen
70fe61971b Redundant parens 2007-05-08 15:04:12 +00:00
Spencer Janssen
1276edc861 StackSet.view: ignore invalid indices 2007-05-08 14:39:51 +00:00
Neil Mitchell
27f1f50071 Change the swap function so its Haskell 98, by using list-comps instead of pattern-guards. 2007-05-08 12:31:58 +00:00
Don Stewart
9f4fd822b6 Arbitrary instance for StackSet must set random focus on each workspace
When focus was separated from the stack order on each workspace, we
forgot to update the Arbitrary instance to set random focus. As spotted
by David R, this then invalidates 4 of our QC properties. In particular,
the property involving where focus goes after a random transient
(annoying behaviour) appeared to be correct, but wasn't, due to
inadequate coverage.

This patch sets focus to a random window on each workspace. As a result,
we now catch the focus/raise/delete issue people have been complaining
about.

Lesson: make sure your QuickCheck generators are doing what you think
they are.
2007-05-08 05:11:26 +00:00
David Roundy
ab27c7d48d make quickcheck tests friendlier to read. 2007-05-05 17:54:15 +00:00
Jason Creighton
ab0f3be0af make Properties.hs exit with failure on test failure 2007-05-05 17:43:57 +00:00
Don Stewart
7a56422491 since we just ignore type errors, no need to derive Show 2007-05-04 09:41:43 +00:00
Don Stewart
0928bb484a Constrain layout messages to be members of a Message class
Using Typeables as the only constraint on layout messages is a bit
scary, as a user can send arbitrary values to layoutMsg, whether they
make sense or not: there's basically no type feedback on the values you
supply to layoutMsg.

Folloing Simon Marlow's dynamically extensible exceptions paper, we use
an existential type, and a Message type class, to constrain valid
arguments to layoutMsg to be valid members of Message.

That is, a user writes some data type for messages their layout
algorithm accepts:

  data MyLayoutEvent = Zoom
                     | Explode
                     | Flaming3DGlassEffect
                     deriving (Typeable)

and they then add this to the set of valid message types:

  instance Message MyLayoutEvent

Done. We also reimplement the dynamic type check while we're here, to
just directly use 'cast', rather than expose a raw fromDynamic/toDyn.

With this, I'm much happier about out dynamically extensible layout
event subsystem.
2007-05-04 08:16:49 +00:00
Spencer Janssen
72e7bed426 Handle empty layout lists 2007-05-04 04:56:44 +00:00
Don Stewart
d0ef78e5c3 refactoring, style, comments on new layout code 2007-05-04 02:36:18 +00:00
Jason Creighton
b5ed587f2e use anyKey constant instead of magic number 2007-05-04 01:50:43 +00:00
Jason Creighton
7a89f431b1 added mirrorLayout to mirror arbitrary layouts 2007-05-04 01:46:53 +00:00
Spencer Janssen
a5e0e2458d Fix layout switching order 2007-05-03 23:56:32 +00:00
Spencer Janssen
9d3d2f8503 More Config.hs bugs 2007-05-03 23:46:07 +00:00
Spencer Janssen
204c90b072 Revert accidental change to Config.hs 2007-05-03 23:31:48 +00:00
Spencer Janssen
bedc069143 Add -fglasgow-exts for pattern guards. Properties.hs doesn't complain anymore 2007-05-03 21:42:21 +00:00
Spencer Janssen
5b7c6c8631 Avoid the unsafe pattern match, in case Config.hs has no layouts 2007-05-03 21:40:07 +00:00
David Roundy
ea1134db26 add support for extensible layouts. 2007-05-03 14:47:50 +00:00
Don Stewart
f0df95da72 comments. and stop tracing events to stderr 2007-05-03 07:58:21 +00:00
Don Stewart
f5e8b2b6a8 -Wall police 2007-05-03 07:49:37 +00:00
Don Stewart
08ce2a5efa elaborate documentation in Config.hs 2007-05-03 07:48:43 +00:00
Spencer Janssen
b63e8c029e Use updated refreshKeyboardMapping. Requires latest X11-extras 2007-05-03 03:20:40 +00:00
Jason Creighton
fa271e00ce run QC tests in addition to LOC test 2007-05-03 00:32:02 +00:00
Spencer Janssen
3416eceb5d Add 'mod-n': refreshes current layout 2007-05-03 00:22:52 +00:00
Spencer Janssen
833d5ae357 Fix tests after StackSet changes 2007-05-02 20:16:22 +00:00
Spencer Janssen
1dff21001c First steps to adding floating layer 2007-05-02 19:59:17 +00:00
Don Stewart
0c569a64e1 update motivational text using xmonad.org 2007-05-02 06:18:59 +00:00
Spencer Janssen
c0266c0cb8 Sort dependencies in installation order 2007-05-01 20:42:49 +00:00
Spencer Janssen
56a4164a90 Recommend X11-extras 0.1 2007-05-01 20:41:21 +00:00
Don Stewart
fdc73b4cb1 elaborate description in .cabal 2007-05-01 03:54:14 +00:00
Don Stewart
121e20d342 use -fasm by default. Much faster 2007-05-01 03:12:20 +00:00
Don Stewart
af7c76d3fe check we never generate invalid stack sets 2007-04-30 06:59:46 +00:00
Spencer Janssen
3586379ecc Make border width configurable 2007-04-30 16:35:15 +00:00
Spencer Janssen
08e514b28f Add Config.hs-boot, remove defaultLayoutDesc from XConf 2007-04-30 16:26:47 +00:00
Spencer Janssen
ecbff364c9 Comment only 2007-04-30 16:16:35 +00:00
Spencer Janssen
1e83de8cde Comment only 2007-04-30 16:15:11 +00:00
Don Stewart
4d9fa8bc98 view n . shift n . view i . shift i) x == x --> shift + view is invertible 2007-04-30 06:29:01 +00:00
Don Stewart
17f70344ec add rotate all and view idempotency tests 2007-04-30 05:57:51 +00:00
Don Stewart
14773f6300 push is idempotent 2007-04-30 05:43:45 +00:00
Don Stewart
89182406a8 add two properties relating to empty window managers 2007-04-30 05:10:16 +00:00
Don Stewart
0d7969be18 new QC property: opening a window only affects the current screen 2007-04-30 05:01:33 +00:00
Spencer Janssen
5d086df912 Add XConf for values that don't change. 2007-04-30 05:47:15 +00:00
Spencer Janssen
5c1982cc35 Control.Arrow is suspicious, add an explicit import 2007-04-30 05:36:23 +00:00
Jason Creighton
bdbca84bcd configurable border colors
This also fixes a bug where xmonad was assuming a 24-bit display, and just
using, eg, 0xff0000 as an index into a colormap without querying the X server
to determine the proper pixel value for "red".
2007-04-30 04:38:59 +00:00
Don Stewart
8097060259 a bit more precise about building non-empty stacksets for one test 2007-04-30 03:57:29 +00:00
Don Stewart
df7d1d95fa remove redundant call to 'delete' in 'shift' 2007-04-30 03:11:51 +00:00
Don Stewart
8265cae8a8 clean 'delete' a little 2007-04-30 02:53:19 +00:00
Don Stewart
a07f0778ad shrink 'swap' 2007-04-30 02:48:13 +00:00
Don Stewart
9fafa995c7 shrink 'rotate' a little 2007-04-30 02:45:25 +00:00
Don Stewart
966da43176 move size into Properties.hs 2007-04-30 02:17:58 +00:00
Don Stewart
a839238483 don't need 'size' operation on StackSet 2007-04-30 01:59:27 +00:00
Don Stewart
5386ab0094 add homepage: field to .cabal file 2007-04-29 04:10:11 +00:00
Don Stewart
d5e73b70ae add fromList to Properties.hs 2007-04-29 03:58:23 +00:00
Don Stewart
9b80a36cf8 move fromList into Properties.hs, -17 loc 2007-04-29 03:58:04 +00:00
Jason Creighton
90b4eb607c avoid grabbing all keys when a keysym is undefined
XKeysymToKeycode() returns zero if the keysym is undefined. Zero also happens
to be the value of AnyKey.
2007-04-28 18:00:46 +00:00
Spencer Janssen
0dd75f9d68 Further refactoring 2007-04-26 21:22:57 +00:00
Spencer Janssen
bd41b81c16 Refactor in Config.hs (no real changes) 2007-04-26 21:14:07 +00:00
Spencer Janssen
c03b53db67 Add the manpage to extra-source-files 2007-04-26 01:41:05 +00:00
David Lazar
4fbb4e23a3 add xmonad manpage 2007-04-26 01:08:12 +00:00
Spencer Janssen
ea94892e1c Remove toList 2007-04-26 00:57:13 +00:00
Jason Creighton
767bc68acf Ignore numlock and capslock in keybindings 2007-04-24 01:33:57 +00:00
Spencer Janssen
70a87063d1 Clear numlock bit 2007-04-24 01:03:52 +00:00
Jason Creighton
2a5be03dd1 force window border to 1px 2007-04-23 05:08:24 +00:00
Don Stewart
50f89990a0 s/creigh// 2007-04-23 02:40:26 +00:00
Don Stewart
5f6ac3573d some other things to do 2007-04-23 02:31:51 +00:00
Spencer Janssen
5475c751ab Start TODOs for 0.2 2007-04-23 02:15:26 +00:00
Don Stewart
47eb93c694 update readme 2007-04-22 09:05:07 +00:00
55 changed files with 6457 additions and 1395 deletions

24
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,24 @@
### Problem Description
Describe the problem you are having, what you expect to happen
instead, and how to reproduce the problem.
### Configuration File
Please include the smallest configuration file that reproduces the
problem you are experiencing:
```haskell
module Main (main) where
import XMonad
main :: IO ()
main = xmonad def
```
### Checklist
- [ ] I've read [CONTRIBUTING.md](https://github.com/xmonad/xmonad/blob/master/CONTRIBUTING.md)
- [ ] I tested my configuration with [xmonad-testing](https://github.com/xmonad/xmonad-testing)

14
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,14 @@
### Description
Include a description for your changes, including the motivation
behind them.
### Checklist
- [ ] I've read [CONTRIBUTING.md](https://github.com/xmonad/xmonad/blob/master/CONTRIBUTING.md)
- [ ] I've confirmed these changes don't belong in xmonad-contrib instead
- [ ] I tested my changes with [xmonad-testing](https://github.com/xmonad/xmonad-testing)
- [ ] I updated the `CHANGES.md` file

26
.gitignore vendored Normal file
View File

@@ -0,0 +1,26 @@
.cabal-sandbox/
cabal.sandbox.config
.hpc/
*.hi
*.o
*.p_hi
*.prof
*.tix
cabal.config
dist
dist-*
# editor temp files
*#
.#*
*~
.*.swp
# TAGS files
TAGS
tags
# stack artifacts
/.stack-work/
/cabal.project.local

118
.travis.yml Normal file
View File

@@ -0,0 +1,118 @@
# This Travis job script has been generated by a script via
#
# runghc make_travis_yml_2.hs '-o' '.travis.yml' 'xmonad.cabal' 'libxrandr-dev'
#
# For more information, see https://github.com/hvr/multi-ghc-travis
#
language: c
sudo: false
git:
submodules: false # whether to recursively clone submodules
cache:
directories:
- $HOME/.cabal/packages
- $HOME/.cabal/store
before_cache:
- rm -fv $HOME/.cabal/packages/hackage.haskell.org/build-reports.log
# remove files that are regenerated by 'cabal update'
- rm -fv $HOME/.cabal/packages/hackage.haskell.org/00-index.*
- rm -fv $HOME/.cabal/packages/hackage.haskell.org/*.json
- rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.cache
- rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.tar
- rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.tar.idx
- rm -rfv $HOME/.cabal/packages/head.hackage
matrix:
include:
- compiler: "ghc-8.4.3"
# env: TEST=--disable-tests BENCH=--disable-benchmarks
addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.4.3,libxrandr-dev], sources: [hvr-ghc]}}
- compiler: "ghc-8.2.2"
# env: TEST=--disable-tests BENCH=--disable-benchmarks
addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.2.2,libxrandr-dev], sources: [hvr-ghc]}}
- compiler: "ghc-8.0.2"
# env: TEST=--disable-tests BENCH=--disable-benchmarks
addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.0.2,libxrandr-dev], sources: [hvr-ghc]}}
- compiler: "ghc-7.10.3"
# env: TEST=--disable-tests BENCH=--disable-benchmarks
addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.10.3,libxrandr-dev], sources: [hvr-ghc]}}
- compiler: "ghc-7.8.4"
# env: TEST=--disable-tests BENCH=--disable-benchmarks
addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.8.4,libxrandr-dev], sources: [hvr-ghc]}}
- compiler: "ghc-7.6.3"
# env: TEST=--disable-tests BENCH=--disable-benchmarks
addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.6.3,libxrandr-dev], sources: [hvr-ghc]}}
before_install:
- HC=${CC}
- HCPKG=${HC/ghc/ghc-pkg}
- unset CC
- ROOTDIR=$(pwd)
- mkdir -p $HOME/.local/bin
- "PATH=/opt/ghc/bin:/opt/ghc-ppa-tools/bin:$HOME/local/bin:$PATH"
- HCNUMVER=$(( $(${HC} --numeric-version|sed -E 's/([0-9]+)\.([0-9]+)\.([0-9]+).*/\1 * 10000 + \2 * 100 + \3/') ))
- echo $HCNUMVER
install:
- cabal --version
- echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]"
- BENCH=${BENCH---enable-benchmarks}
- TEST=${TEST---enable-tests}
- HADDOCK=${HADDOCK-true}
- UNCONSTRAINED=${UNCONSTRAINED-true}
- NOINSTALLEDCONSTRAINTS=${NOINSTALLEDCONSTRAINTS-false}
- GHCHEAD=${GHCHEAD-false}
- travis_retry cabal update -v
- "sed -i.bak 's/^jobs:/-- jobs:/' ${HOME}/.cabal/config"
- rm -fv cabal.project cabal.project.local
- grep -Ev -- '^\s*--' ${HOME}/.cabal/config | grep -Ev '^\s*$'
- "printf 'packages: \".\"\\n' > cabal.project"
- touch cabal.project.local
- "if ! $NOINSTALLEDCONSTRAINTS; then for pkg in $($HCPKG list --simple-output); do echo $pkg | grep -vw -- xmonad | sed 's/^/constraints: /' | sed 's/-[^-]*$/ installed/' >> cabal.project.local; done; fi"
- cat cabal.project || true
- cat cabal.project.local || true
- if [ -f "./configure.ac" ]; then
(cd "." && autoreconf -i);
fi
- rm -f cabal.project.freeze
- cabal new-build -w ${HC} ${TEST} ${BENCH} --project-file="cabal.project" --dep -j2 all
- cabal new-build -w ${HC} --disable-tests --disable-benchmarks --project-file="cabal.project" --dep -j2 all
- rm -rf .ghc.environment.* "."/dist
- DISTDIR=$(mktemp -d /tmp/dist-test.XXXX)
# Here starts the actual work to be performed for the package under test;
# any command which exits with a non-zero exit code causes the build to fail.
script:
# test that source-distributions can be generated
- (cd "." && cabal sdist)
- mv "."/dist/xmonad-*.tar.gz ${DISTDIR}/
- cd ${DISTDIR} || false
- find . -maxdepth 1 -name '*.tar.gz' -exec tar -xvf '{}' \;
- "printf 'packages: xmonad-*/*.cabal\\n' > cabal.project"
- touch cabal.project.local
- "if ! $NOINSTALLEDCONSTRAINTS; then for pkg in $($HCPKG list --simple-output); do echo $pkg | grep -vw -- xmonad | sed 's/^/constraints: /' | sed 's/-[^-]*$/ installed/' >> cabal.project.local; done; fi"
- cat cabal.project || true
- cat cabal.project.local || true
# this builds all libraries and executables (without tests/benchmarks)
- cabal new-build -w ${HC} --disable-tests --disable-benchmarks all
# build & run tests, build benchmarks
- cabal new-build -w ${HC} ${TEST} ${BENCH} all
- if [ "x$TEST" = "x--enable-tests" ]; then cabal new-test -w ${HC} ${TEST} ${BENCH} all; fi
# cabal check
- (cd xmonad-* && cabal check)
# haddock
- rm -rf ./dist-newstyle
- if $HADDOCK; then cabal new-haddock -w ${HC} ${TEST} ${BENCH} all; else echo "Skipping haddock generation";fi
# Build without installed constraints for packages in global-db
- if $UNCONSTRAINED; then rm -f cabal.project.local; echo cabal new-build -w ${HC} --disable-tests --disable-benchmarks all; else echo "Not building without installed constraints"; fi
# REGENDATA ["-o",".travis.yml","xmonad.cabal","libxrandr-dev"]
# EOF

117
CHANGES.md Normal file
View File

@@ -0,0 +1,117 @@
# Change Log / Release Notes
## 0.14 (July 30, 2018)
### Bug Fixes
* The state file that xmonad uses while restarting itself is now
removed after it is processed. This fixes a bug that manifested
in several different ways:
- Names of old workspaces would be resurrected after a restart
- Screen sizes would be wrong after changing monitor configuration (#90)
- `spawnOnce` stopped working (xmonad/xmonad-contrib#155)
- Focus did not follow when moving between workspaces (#87)
- etc.
* Recover old behavior (in 0.12) when `focusFollowsMouse == True`:
the focus follows when the mouse enters another workspace
but not moving into any window.
* Compiles with GHC 8.4.1
* Restored compatability with GHC version prior to 8.0.1 by removing the
dependency on directory version 1.2.3.
## 0.13 (February 10, 2017)
### Breaking Changes
* When restarting xmonad, resume state is no longer passed to the
next process via the command line. Instead, a temporary state
file is created and xmonad's state is serialized to that file.
When upgrading to 0.13 from a previous version, the `--resume`
command line option will automatically migrate to a state file.
This fixes issue #12.
### Enhancements
* You can now control which directory xmonad uses for finding your
configuration file and which one is used for storing the compiled
version of your configuration. In order of preference:
1. New environment variables. If you want to use these ensure
you set the correct environment variable and also create the
directory it references:
- `XMONAD_CONFIG_DIR`
- `XMONAD_CACHE_DIR`
- `XMONAD_DATA_DIR`
2. The `~/.xmonad` directory.
3. XDG Base Directory Specification directories, if they exist:
- `XDG_CONFIG_HOME/xmonad`
- `XDG_CACHE_HOME/xmonad`
- `XDG_DATA_HOME/xmonad`
If none of these directories exist then one will be created using
the following logic: If the relevant environment variable
mentioned in step (1) above is set, the referent directory will be
created and used. Otherwise `~/.xmonad` will be created and used.
This fixes a few issues, notably #7 and #56.
* A custom build script can be used when xmonad is given the
`--recompile` command line option. If an executable named `build`
exists in the xmonad configuration directory it will be called
instead of `ghc`. It takes one argument, the name of the
executable binary it must produce.
This fixes #8. (One of two possible custom build solutions. See
the next entry for another solution.)
* For users who build their xmonad configuration using tools such as
cabal or stack, there is another option for executing xmonad.
Instead of running the `xmonad` executable directly, arrange to
have your login manager run your configuration binary instead.
Then, in your binary, use the new `launch` command instead of
`xmonad`.
This will keep xmonad from using its configuration file
checking/compiling code and directly start the window manager
without `exec`ing any other binary.
See the documentation for the `launch` function in `XMonad.Main`
for more details.
Fixes #8. (Second way to have a custom build environment for
XMonad. See previous entry for another solution.)
## 0.12 (December 14, 2015)
* Compiles with GHC 7.10.2, 7.8.4, and 7.6.3
* Use of [data-default][] allows using `def` where previously you
had to write `defaultConfig`, `defaultXPConfig`, etc.
* The [setlocale][] package is now used instead of a binding shipped
with xmonad proper allowing the use of `Main.hs` instead of
`Main.hsc`
* No longer encodes paths for `spawnPID`
* The default `manageHook` no longer floats Gimp windows
* Doesn't crash when there are fewer workspaces than screens
* `Query` is now an instance of `Applicative`
* Various improvements to the example configuration file
[data-default]: http://hackage.haskell.org/package/data-default
[setlocale]: https://hackage.haskell.org/package/setlocale

82
CONFIG Normal file
View File

@@ -0,0 +1,82 @@
== Configuring xmonad ==
xmonad is configured by creating and editing the file:
~/.xmonad/xmonad.hs
xmonad then uses settings from this file as arguments to the window manager,
on startup. For a complete example of possible settings, see the file:
man/xmonad.hs
Further examples are on the website, wiki and extension documentation.
http://haskell.org/haskellwiki/Xmonad
== A simple example ==
Here is a basic example, which overrides the default border width,
default terminal, and some colours. This text goes in the file
$HOME/.xmonad/xmonad.hs :
import XMonad
main = xmonad $ def
{ borderWidth = 2
, terminal = "urxvt"
, normalBorderColor = "#cccccc"
, focusedBorderColor = "#cd8b00" }
You can find the defaults in the file:
XMonad/Config.hs
== Checking your xmonad.hs is correct ==
Place this text in ~/.xmonad/xmonad.hs, and then check that it is
syntactically and type correct by loading it in the Haskell
interpreter:
$ ghci ~/.xmonad/xmonad.hs
GHCi, version 6.8.1: http://www.haskell.org/ghc/ :? for help
Loading package base ... linking ... done.
Ok, modules loaded: Main.
Prelude Main> :t main
main :: IO ()
Ok, looks good.
== Loading your configuration ==
To have xmonad start using your settings, type 'mod-q'. xmonad will
then load this new file, and run it. If it is unable to, the defaults
are used.
To load successfully, both 'xmonad' and 'ghc' must be in your $PATH
environment variable. If GHC isn't in your path, for some reason, you
can compile the xmonad.hs file yourself:
$ cd ~/.xmonad
$ ghc --make xmonad.hs
$ ls
xmonad xmonad.hi xmonad.hs xmonad.o
When you hit mod-q, this newly compiled xmonad will be used.
== Where are the defaults? ==
The default configuration values are defined in the source file:
XMonad/Config.hs
the XConfig data structure itself is defined in:
XMonad/Core.hs
== Extensions ==
Since the xmonad.hs file is just another Haskell module, you may import
and use any Haskell code or libraries you wish. For example, you can use
things from the xmonad-contrib library, or other code you write
yourself.

141
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,141 @@
# Contributing to xmonad and xmonad-contrib
## Before Creating a GitHub Issue
New issue submissions should adhere to the following guidelines:
* Does your issue have to do with [xmonad][], [xmonad-contrib][], or
maybe even with the [X11][] library?
Please submit your issue to the **correct** GitHub repository.
* To help you figure out which repository to submit your issue to,
and to help us resolve the problem you are having, create the
smallest configuration file you can that reproduces the problem.
You may find that the [xmonad-testing][] repository is helpful in
reproducing the problem with a smaller configuration file.
Once you've done that please include the configuration file with
your GitHub issue.
* If possible, use the [xmonad-testing][] repository to test your
configuration with the bleeding-edge development version of xmonad
and xmonad-contrib. We might have already fixed your problem.
## Contributing Changes/Patches
Have a change to xmonad that you want included in the next release?
Awesome! Here are a few things to keep in mind:
* Review the above section about creating GitHub issues.
* It's always best to talk with the community before making any
nontrivial changes to xmonad. There are a couple of ways you can
chat with us:
- Post a message to the [mailing list][ml].
- Join the `#xmonad` IRC channel on `chat.freenode.org`.
* Continue reading this document!
## Expediting Reviews and Merges
Here are some tips for getting your changes merged into xmonad:
* If your changes can go into [xmonad-contrib][] instead
of [xmonad][], please do so. We rarely accept new features to
xmonad. (Not that we don't accept changes to xmonad, just that we
prefer changes to xmonad-contrib instead.)
* Change the fewest files as possible. If it makes sense, submit a
completely new module to xmonad-contrib.
* Your changes should include relevant entries in the `CHANGES.md`
file. Help us communicate changes to the community.
* Make sure you test your changes using the [xmonad-testing][]
repository. Include a new configuration file that shows off your
changes if possible by creating a PR on that repository as well.
* Make sure you read the section on rebasing and squashing commits
below.
## Rebasing and Squashing Commits
Under no circumstances should you ever merge the master branch into
your feature branch. This makes it nearly impossible to review your
changes and we *will not accept your PR* if you do this.
Instead of merging you should rebase your changes on top of the master
branch. If a core team member asks you to "rebase your changes" this
is what they are talking about.
It's also helpful to squash all of your commits so that your pull
request only contains a single commit. Again, this makes it easier to
review your changes and identify the changes later on in the Git
history.
### How to Rebase Your Changes
The goal of rebasing is to bring recent changes from the master branch
into your feature branch. This often helps resolve conflicts where
you have changed a file that also changed in a recently merged pull
request (i.e. the `CHANGES.md` file). Here is how you do that.
1. Make sure that you have a `git remote` configured for the main
repository. I like to call this remote `upstream`:
$ git remote add upstream https://github.com/xmonad/xmonad-contrib.git
2. Pull from upstream and rewrite your changes on top of master. For
this to work you should not have any modified files in your
working directory. Run these commands from within your feature
branch (the branch you are asking to be merged):
$ git fetch --all
$ git pull --rebase upstream master
3. If the rebase was successful you can now push your feature branch
back to GitHub. You need to force the push since your commits
have been rewritten and have new IDs:
$ git push --force-with-lease
4. Your pull request should now be conflict-free and only contain the
changes that you actually made.
### How to Squash Commits
The goal of squashing commits is to produce a clean Git history where
each pull request contains just one commit.
1. Use `git log` to see how many commits you are including in your
pull request. (If you've already submitted your pull request you
can see this in the GitHub interface.)
2. Rebase all of those commits into a single commit. Assuming you
want to squash the last four (4) commits into a single commit:
$ git rebase -i HEAD~4
3. Git will open your editor and display the commits you are
rebasing with the word "pick" in front of them.
4. Leave the first listed commit as "pick" and change the remaining
commits from "pick" to "squash".
5. Save the file and exit your editor. Git will create a new commit
and open your editor so you can modify the commit message.
6. If everything was successful you can push your changed history
back up to GitHub:
$ git push --force-with-lease
[xmonad]: https://github.com/xmonad/xmonad
[xmonad-contrib]: https://github.com/xmonad/xmonad-contrib
[xmonad-testing]: https://github.com/xmonad/xmonad-testing
[x11]: https://github.com/xmonad/X11
[ml]: https://mail.haskell.org/cgi-bin/mailman/listinfo/xmonad

150
Config.hs
View File

@@ -1,150 +0,0 @@
-----------------------------------------------------------------------------
-- |
-- Module : Config.hs
-- Copyright : (c) Spencer Janssen 2007
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : dons@cse.unsw.edu.au
-- Stability : stable
-- Portability : portable
--
-----------------------------------------------------------------------------
module Config where
--
-- xmonad bindings follow mostly the dwm/wmii conventions:
--
-- key combination action
--
-- mod-shift-return new xterm
-- mod-p launch dmenu
-- mod-shift-p launch gmrun
--
-- mod-space switch tiling mode
--
-- mod-tab raise next window in stack
-- mod-j
-- mod-k
--
-- mod-h decrease the size of the master area
-- mod-l increase the size of the master area
--
-- mod-shift-c kill client
-- mod-shift-q exit window manager
-- mod-shift-ctrl-q restart window manager ('xmonad' must be in $PATH)
--
-- mod-return cycle the current tiling order
--
-- mod-1..9 switch to workspace N
-- mod-shift-1..9 move client to workspace N
--
-- mod-w,e,r switch to physical/Xinerama screen 1, 2 or 3.
--
-- xmonad places each window into a "workspace." Each workspace can have
-- any number of windows, which you can cycle though with mod-j and mod-k.
-- Windows are either displayed full screen, tiled horizontally, or tiled
-- vertically. You can toggle the layout mode with mod-space, which will
-- cycle through the available modes.
--
-- You can switch to workspace N with mod-N. For example, to switch to
-- workspace 5, you would press mod-5. Similarly, you can move the current
-- window to another workspace with mod-shift-N.
--
-- When running with multiple monitors (Xinerama), each screen has exactly
-- 1 workspace visible. When xmonad starts, workspace 1 is on screen 1,
-- workspace 2 is on screen 2, etc. If you switch to a workspace which is
-- currently visible on another screen, xmonad simply switches focus to
-- that screen. If you switch to a workspace which is *not* visible, xmonad
-- replaces the workspace on the *current* screen with the workspace you
-- selected.
--
-- For example, if you have the following configuration:
--
-- Screen 1: Workspace 2
-- Screen 2: Workspace 5 (current workspace)
--
-- and you wanted to view workspace 7 on screen 1, you would press:
--
-- mod-2 (to select workspace 2, and make screen 1 the current screen)
-- mod-7 (to select workspace 7)
--
-- Since switching to the workspace currently visible on a given screen is
-- such a common operation, shortcuts are provided: mod-{w,e,r} switch to
-- the workspace currently visible on screens 1, 2, and 3 respectively.
-- Likewise, shift-mod-{w,e,r} moves the current window to the workspace on
-- that screen. Using these keys, the above example would become mod-w
-- mod-7.
--
import Data.Ratio
import Data.Bits
import qualified Data.Map as M
import System.Exit
import Graphics.X11.Xlib
import XMonad
import Operations
-- The number of workspaces:
workspaces :: Int
workspaces = 9
-- modMask lets you easily change which modkey you use. The default is mod1Mask
-- ("left alt"). You may also consider using mod3Mask ("right alt"), which
-- does not conflict with emacs keybindings. The "windows key" is usually
-- mod4Mask.
modMask :: KeyMask
modMask = mod1Mask
-- How much to change the horizontal/vertical split bar by defalut.
defaultDelta :: Rational
defaultDelta = 3%100
-- The mask for the numlock key. You may need to change this on some systems.
numlockMask :: KeyMask
numlockMask = lockMask
-- What layout to start in, and what the default proportion for the
-- left pane should be in the tiled layout. See LayoutDesc and
-- friends in XMonad.hs for options.
startingLayoutDesc :: LayoutDesc
startingLayoutDesc =
LayoutDesc { layoutType = Full
, tileFraction = 1%2 }
-- The keys list.
keys :: M.Map (KeyMask, KeySym) (X ())
keys = M.fromList $
[ ((modMask .|. shiftMask, xK_Return), spawn "xterm")
, ((modMask, xK_p ), spawn "exe=`dmenu_path | dmenu` && exec $exe")
, ((modMask .|. shiftMask, xK_p ), spawn "gmrun")
, ((modMask, xK_space ), switchLayout)
, ((modMask, xK_Tab ), raise GT)
, ((modMask, xK_j ), raise GT)
, ((modMask, xK_k ), raise LT)
, ((modMask, xK_h ), changeSplit (negate defaultDelta))
, ((modMask, xK_l ), changeSplit defaultDelta)
, ((modMask .|. shiftMask, xK_c ), kill)
, ((modMask .|. shiftMask, xK_q ), io $ exitWith ExitSuccess)
, ((modMask .|. shiftMask .|. controlMask, xK_q ), io restart)
-- Cycle the current tiling order
, ((modMask, xK_Return), promote)
] ++
-- Keybindings to get to each workspace:
[((m .|. modMask, xK_0 + fromIntegral i), f (fromIntegral (pred i))) -- index from 0.
| i <- [1 .. workspaces]
, (f, m) <- [(view, 0), (tag, shiftMask)]]
-- Keybindings to each screen :
-- mod-wer (underneath 123) switches to physical/Xinerama screens 1 2 and 3
++
[((m .|. modMask, key), screenWorkspace sc >>= f)
| (key, sc) <- zip [xK_w, xK_e, xK_r] [0..]
, (f, m) <- [(view, 0), (tag, shiftMask)]]

24
LICENSE
View File

@@ -1,27 +1,31 @@
Copyright (c) Spencer Janssen
Copyright (c) 2007,2008 Spencer Janssen
Copyright (c) 2007,2008 Don Stewart
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the author nor the names of his contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

83
MAINTAINERS.md Normal file
View File

@@ -0,0 +1,83 @@
# XMonad Maintainers
## The XMonad Core Team
* Adam Vogt [GitHub][aavogt]
* Brandon S Allbery [GitHub][geekosaur], IRC: `geekosaur`
* Brent Yorgey [GitHub][byorgey], IRC: `byorgey`
* Daniel Wagner [GitHub][dmwit], IRC: `dmwit`
* David Lazar [GitHub][davidlazar]
* Devin Mullins [GitHub][twifkak]
* Peter J. Jones [GitHub][pjones], [Twitter][twitter:pjones], [OpenPGP Key][pgp:pjones], IRC: `pmade`
## Release Procedures
When the time comes to release another version of XMonad and Contrib...
1. Create a release branch (e.g., `release-0.XX`).
This will allow you to separate the release process from main
development. Changes you make on this branch will be merged back
into `master` as one of the last steps.
2. Update the version number in the `*.cabal` files and verify
dependencies and documentation. This includes the `tested-with:`
field.
3. Use the [packdeps][] tool to ensure you have the dependency
versions correct. If you need to update the version of a
dependency then you should rebuild and retest.
4. Review documentation files and make sure they are accurate:
- `README.md`
- `CHANGES.md`
- and the `example-config.hs` in the `xmonad-testing` repo
5. Generate the manpage:
* `cabal configure` with the `-fgeneratemanpage` flag
* Build the project
* Run the `generatemanpage` tool from the top level of this repo
* Review the man page: `man -l man/xmonad.1`
6. Tag the repository with the release version (e.g., `v0.13`)
7. Build the project tarballs (`cabal sdist`)
8. Upload the packages to Hackage (`cabal upload`)
9. Merge the release branches into `master`
10. Update the website:
* Generate and push haddocks with `xmonad-web/gen-docs.sh`
* Check that `tour.html` and `intro.html` are up to date, and
mention all core bindings
11. Update the topic for the IRC channel (`#xmonad`)
12. Send the `announce-0.XX.txt` file to:
- XMonad mailing list
- Haskell Cafe
[packdeps]: http://hackage.haskell.org/package/packdeps
[aavogt]: https://github.com/orgs/xmonad/people/aavogt
[geekosaur]: https://github.com/orgs/xmonad/people/geekosaur
[byorgey]: https://github.com/orgs/xmonad/people/byorgey
[dmwit]: https://github.com/orgs/xmonad/people/dmwit
[davidlazar]: https://github.com/orgs/xmonad/people/davidlazar
[twifkak]: https://github.com/orgs/xmonad/people/twifkak
[pjones]: https://github.com/orgs/xmonad/people/pjones
[twitter:pjones]: https://twitter.com/contextualdev
[pgp:pjones]: http://pgp.mit.edu/pks/lookup?op=get&search=0x526722D1204284CB

181
Main.hs
View File

@@ -1,6 +1,6 @@
-----------------------------------------------------------------------------
----------------------------------------------------------------------------
-- |
-- Module : Main.hs
-- Module : Main
-- Copyright : (c) Spencer Janssen 2007
-- License : BSD3-style (see LICENSE)
--
@@ -8,182 +8,13 @@
-- Stability : unstable
-- Portability : not portable, uses mtl, X11, posix
--
-- xmonad, a minimalist, tiling window manager for X11
--
-----------------------------------------------------------------------------
--
-- xmonad, a minimal window manager for X11
--
import Data.Bits
import qualified Data.Map as M
import Graphics.X11.Xlib hiding (refreshKeyboardMapping)
import Graphics.X11.Xlib.Extras
import Graphics.X11.Xinerama
import Control.Monad.State
import qualified StackSet as W
module Main (main) where
import XMonad
import Operations
import Config
--
-- The main entry point
--
main :: IO ()
main = do
dpy <- openDisplay ""
let dflt = defaultScreen dpy
rootw <- rootWindow dpy dflt
wmdelt <- internAtom dpy "WM_DELETE_WINDOW" False
wmprot <- internAtom dpy "WM_PROTOCOLS" False
xinesc <- getScreenInfo dpy
let st = XState
{ display = dpy
, xineScreens = xinesc
, theRoot = rootw
, wmdelete = wmdelt
, wmprotocols = wmprot
-- fromIntegral needed for X11 versions that use Int instead of CInt.
, dimensions = (fromIntegral (displayWidth dpy dflt),
fromIntegral (displayHeight dpy dflt))
, workspace = W.empty workspaces (length xinesc)
, defaultLayoutDesc = startingLayoutDesc
, layoutDescs = M.empty
}
xSetErrorHandler -- in C, I'm too lazy to write the binding
-- setup initial X environment
sync dpy False
selectInput dpy rootw $ substructureRedirectMask
.|. substructureNotifyMask
.|. enterWindowMask
.|. leaveWindowMask
grabKeys dpy rootw
sync dpy False
ws <- scan dpy rootw
allocaXEvent $ \e ->
runX st $ do
mapM_ manage ws
forever $ handle =<< xevent dpy e
where
xevent d e = io (nextEvent d e >> getEvent e)
forever a = a >> forever a
-- ---------------------------------------------------------------------
-- IO stuff. Doesn't require any X state
-- Most of these things run only on startup (bar grabkeys)
-- | scan for any initial windows to manage
scan :: Display -> Window -> IO [Window]
scan dpy rootw = do
(_, _, ws) <- queryTree dpy rootw
filterM ok ws
where
ok w = do wa <- getWindowAttributes dpy w
return $ not (wa_override_redirect wa)
&& wa_map_state wa == waIsViewable
-- | Grab the keys back
grabKeys :: Display -> Window -> IO ()
grabKeys dpy rootw = do
ungrabKey dpy '\0' {-AnyKey-} anyModifier rootw
flip mapM_ (M.keys keys) $ \(mask,sym) -> do
kc <- keysymToKeycode dpy sym
mapM_ (grab kc) [mask, mask .|. numlockMask] -- note: no numlock
where
grab kc m = grabKey dpy kc m rootw True grabModeAsync grabModeAsync
-- ---------------------------------------------------------------------
-- Event handler
--
-- | handle. Handle X events
--
-- Events dwm handles that we don't:
--
-- [ButtonPress] = buttonpress,
-- [Expose] = expose,
-- [PropertyNotify] = propertynotify,
--
-- Todo: seperate IO from X monad stuff. We want to be able to test the
-- handler, and client functions, with dummy X interface ops, in QuickCheck
--
-- Will require an abstract interpreter from Event -> X Action, which
-- modifies the internal X state, and then produces an IO action to
-- evaluate.
--
-- XCreateWindowEvent(3X11)
-- Window manager clients normally should ignore this window if the
-- override_redirect member is True.
--
handle :: Event -> X ()
-- run window manager command
handle (KeyEvent {ev_event_type = t, ev_state = m, ev_keycode = code})
| t == keyPress
= withDisplay $ \dpy -> do
s <- io $ keycodeToKeysym dpy code 0
whenJust (M.lookup (m,s) keys) id
-- manage a new window
handle (MapRequestEvent {ev_window = w}) = withDisplay $ \dpy -> do
wa <- io $ getWindowAttributes dpy w -- ignore override windows
when (not (wa_override_redirect wa)) $ manage w
-- window destroyed, unmanage it
handle (DestroyWindowEvent {ev_window = w}) = do b <- isClient w; when b $ unmanage w
-- window gone, unmanage it
handle (UnmapEvent {ev_window = w}) = do b <- isClient w; when b $ unmanage w
-- set keyboard mapping
handle e@(MappingNotifyEvent {ev_window = w}) = do
-- this fromIntegral is only necessary with the old X11 version that uses
-- Int instead of CInt. TODO delete it when there is a new release of X11
let m = (ev_request e, ev_first_keycode e, fromIntegral $ ev_count e)
withDisplay $ \d -> io $ refreshKeyboardMapping d m
when (ev_request e == mappingKeyboard) $ withDisplay $ io . flip grabKeys w
-- click on an unfocussed window
handle (ButtonEvent {ev_window = w, ev_event_type = t})
| t == buttonPress
= safeFocus w
-- entered a normal window
handle e@(CrossingEvent {ev_window = w, ev_event_type = t})
| t == enterNotify && ev_mode e == notifyNormal && ev_detail e /= notifyInferior
= safeFocus w
-- left a window, check if we need to focus root
handle e@(CrossingEvent {ev_event_type = t})
| t == leaveNotify
= do rootw <- gets theRoot
when (ev_window e == rootw && not (ev_same_screen e)) $ setFocus rootw
-- configure a window
handle e@(ConfigureRequestEvent {ev_window = w}) = do
XState { display = dpy, workspace = ws } <- get
when (W.member w ws) $ -- already managed, reconfigure (see client:configure()
trace ("Reconfigure already managed window: " ++ show w)
io $ configureWindow dpy (ev_window e) (ev_value_mask e) $ WindowChanges
{ wc_x = ev_x e
, wc_y = ev_y e
, wc_width = ev_width e
, wc_height = ev_height e
, wc_border_width = ev_border_width e
, wc_sibling = ev_above e
-- this fromIntegral is only necessary with the old X11 version that uses
-- Int instead of CInt. TODO delete it when there is a new release of X11
, wc_stack_mode = fromIntegral $ ev_detail e
}
io $ sync dpy False
handle e = trace (eventName e) -- ignoring
main = xmonad def

View File

@@ -1,282 +0,0 @@
-----------------------------------------------------------------------------
-- |
-- Module : Operations.hs
-- Copyright : (c) Spencer Janssen 2007
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : dons@cse.unsw.edu.au
-- Stability : stable
-- Portability : portable
--
-----------------------------------------------------------------------------
module Operations where
import Data.List
import Data.Maybe
import Data.Bits
import qualified Data.Map as M
import Control.Monad.State
import Control.Arrow
import System.Posix.Process
import System.Environment
import System.Directory
import Graphics.X11.Xlib
import Graphics.X11.Xlib.Extras
import XMonad
import qualified StackSet as W
-- ---------------------------------------------------------------------
-- Managing windows
-- | refresh. Refresh the currently focused window. Resizes to full
-- screen and raises the window.
refresh :: X ()
refresh = do
XState {workspace = ws, xineScreens = xinesc
,display = d ,layoutDescs = fls ,defaultLayoutDesc = dfltfl } <- get
flip mapM_ (M.assocs (W.screen2ws ws)) $ \(scn, n) -> do
let sc = genericIndex xinesc scn -- temporary coercion!
fl = M.findWithDefault dfltfl n fls
mapM_ (\(w, rect) -> io $ moveWindowInside d w rect) $
case layoutType fl of
Full -> fmap (flip (,) sc) $ maybeToList $ W.peekStack n ws
Tall -> tile (tileFraction fl) sc $ W.index n ws
Wide -> vtile (tileFraction fl) sc $ W.index n ws
whenJust (W.peekStack n ws) (io . raiseWindow d)
whenJust (W.peek ws) setFocus
clearEnterEvents
-- | clearEnterEvents. Remove all window entry events from the event queue.
clearEnterEvents :: X ()
clearEnterEvents = do
d <- gets display
io $ sync d False
io $ allocaXEvent $ \p -> fix $ \again -> do
more <- checkMaskEvent d enterWindowMask p
when more again
-- | tile. Compute the positions for windows in horizontal layout
-- mode.
--
tile :: Rational -> Rectangle -> [Window] -> [(Window, Rectangle)]
tile _ _ [] = []
tile _ d [w] = [(w, d)]
tile r (Rectangle sx sy sw sh) (w:s)
= (w, Rectangle sx sy (fromIntegral lw) sh) : zipWith f [sy, sy + rh ..] s
where
lw = floor $ fromIntegral sw * r
rw = sw - fromIntegral lw
rh = fromIntegral sh `div` fromIntegral (length s)
f i a = (a, Rectangle (sx + lw) i rw (fromIntegral rh))
-- | vtile. Tile vertically.
vtile :: Rational -> Rectangle -> [Window] -> [(Window, Rectangle)]
vtile r rect = map (second flipRect) . tile r (flipRect rect)
-- | Flip rectangles around
flipRect :: Rectangle -> Rectangle
flipRect (Rectangle rx ry rw rh) = (Rectangle ry rx rh rw)
-- | switchLayout. Switch to another layout scheme. Switches the
-- current workspace. By convention, a window set as master in Tall mode
-- remains as master in Wide mode. When switching from full screen to a
-- tiling mode, the currently focused window becomes a master. When
-- switching back , the focused window is uppermost.
--
switchLayout :: X ()
switchLayout = layout $ \fl -> fl { layoutType = rotateLayout (layoutType fl) }
-- | changeSplit. Changes the window split.
changeSplit :: Rational -> X ()
changeSplit delta = layout $ \fl ->
fl { tileFraction = min 1 (max 0 (tileFraction fl + delta)) }
-- | layout. Modify the current workspace's layout with a pure
-- function and refresh.
layout :: (LayoutDesc -> LayoutDesc) -> X ()
layout f = do
modify $ \s ->
let fls = layoutDescs s
n = W.current . workspace $ s
fl = M.findWithDefault (defaultLayoutDesc s) n fls
in s { layoutDescs = M.insert n (f fl) fls }
refresh
-- | windows. Modify the current window list with a pure function, and refresh
windows :: (WindowSet -> WindowSet) -> X ()
windows f = do
modify $ \s -> s { workspace = f (workspace s) }
refresh
ws <- gets workspace
trace (show ws) -- log state changes to stderr
-- | hide. Hide a window by moving it offscreen.
hide :: Window -> X ()
hide w = withDisplay $ \d -> do
(sw,sh) <- gets dimensions
io $ moveWindow d w (2*fromIntegral sw) (2*fromIntegral sh)
-- ---------------------------------------------------------------------
-- Window operations
-- | setButtonGrab. Tell whether or not to intercept clicks on a given window
buttonsToGrab :: [Button]
buttonsToGrab = [button1, button2, button3]
setButtonGrab :: Bool -> Window -> X ()
setButtonGrab True w = withDisplay $ \d -> io $
flip mapM_ buttonsToGrab $ \b ->
grabButton d b anyModifier w False
(buttonPressMask .|. buttonReleaseMask)
grabModeAsync grabModeSync none none
setButtonGrab False w = withDisplay $ \d -> io $
flip mapM_ buttonsToGrab $ \b ->
ungrabButton d b anyModifier w
-- | moveWindowInside. Moves and resizes w such that it fits inside the given
-- rectangle, including its border.
moveWindowInside :: Display -> Window -> Rectangle -> IO ()
moveWindowInside d w r = do
bw <- (fromIntegral . wa_border_width) `liftM` getWindowAttributes d w
moveResizeWindow d w (rect_x r) (rect_y r)
(rect_width r - bw*2)
(rect_height r - bw*2)
-- | manage. Add a new window to be managed in the current workspace. Bring it into focus.
-- If the window is already under management, it is just raised.
--
manage :: Window -> X ()
manage w = do
withDisplay $ \d -> io $ do
selectInput d w $ structureNotifyMask .|. enterWindowMask .|. propertyChangeMask
mapWindow d w
windows $ W.push w
-- | unmanage. A window no longer exists, remove it from the window
-- list, on whatever workspace it is.
unmanage :: Window -> X ()
unmanage w = do
windows $ W.delete w
withServerX $ do
setTopFocus
withDisplay $ \d -> io (sync d False)
-- TODO, everything operates on the current display, so wrap it up.
-- | Grab the X server (lock it) from the X monad
withServerX :: X () -> X ()
withServerX f = withDisplay $ \dpy -> do
io $ grabServer dpy
f
io $ ungrabServer dpy
safeFocus :: Window -> X ()
safeFocus w = do ws <- gets workspace
if W.member w ws
then setFocus w
else do b <- isRoot w
when b setTopFocus
-- | Explicitly set the keyboard focus to the given window
setFocus :: Window -> X ()
setFocus w = do
ws <- gets workspace
-- clear mouse button grab and border on other windows
flip mapM_ (W.visibleWorkspaces ws) $ \n -> do
flip mapM_ (W.index n ws) $ \otherw -> do
setButtonGrab True otherw
setBorder otherw 0xdddddd
withDisplay $ \d -> io $ setInputFocus d w revertToPointerRoot 0
setButtonGrab False w
setBorder w 0xff0000 -- make this configurable
-- This does not use 'windows' intentionally. 'windows' calls refresh,
-- which means infinite loops.
modify $ \s -> s { workspace = W.raiseFocus w (workspace s) }
-- | Set the focus to the window on top of the stack, or root
setTopFocus :: X ()
setTopFocus = do
ws <- gets workspace
case W.peek ws of
Just new -> setFocus new
Nothing -> gets theRoot >>= setFocus
-- | Set the border color for a particular window.
setBorder :: Window -> Pixel -> X ()
setBorder w p = withDisplay $ \d -> io $ setWindowBorder d w p
-- | raise. focus to window at offset 'n' in list.
-- The currently focused window is always the head of the list
raise :: Ordering -> X ()
raise = windows . W.rotate
-- | promote. Move the currently focused window into the master frame
promote :: X ()
promote = windows W.promote
-- | Kill the currently focused client
kill :: X ()
kill = withDisplay $ \d -> do
ws <- gets workspace
whenJust (W.peek ws) $ \w -> do
protocols <- io $ getWMProtocols d w
XState {wmdelete = wmdelt, wmprotocols = wmprot} <- get
if wmdelt `elem` protocols
then io $ allocaXEvent $ \ev -> do
setEventType ev clientMessage
setClientMessageEvent ev w wmprot 32 wmdelt 0
sendEvent d w False noEventMask ev
else io (killClient d w) >> return ()
-- | tag. Move a window to a new workspace, 0 indexed.
tag :: WorkspaceId -> X ()
tag n = do
ws <- gets workspace
let m = W.current ws -- :: WorkspaceId
when (n /= m) $
whenJust (W.peek ws) $ \w -> do
hide w
windows $ W.shift n
-- | view. Change the current workspace to workspace at offset n (0 indexed).
view :: WorkspaceId -> X ()
view n = do
ws <- gets workspace
let m = W.current ws
windows $ W.view n
ws' <- gets workspace
-- If the old workspace isn't visible anymore, we have to hide the windows
-- in case we're switching to an empty workspace.
when (m `notElem` (W.visibleWorkspaces ws')) (mapM_ hide (W.index m ws))
clearEnterEvents
setTopFocus
-- | 'screenWorkspace sc' returns the workspace number viewed by 'sc'.
screenWorkspace :: ScreenId -> X WorkspaceId
screenWorkspace sc = fmap (fromMaybe 0 . W.workspace sc) (gets workspace)
-- | True if window is under management by us
isClient :: Window -> X Bool
isClient w = liftM (W.member w) (gets workspace)
-- | Restart xmonad by exec()'ing self. This doesn't save state and xmonad has
-- to be in PATH for this to work.
restart :: IO ()
restart = do
prog <- getProgName
prog_path <- findExecutable prog
case prog_path of
Nothing -> return () -- silently fail
Just p -> do args <- getArgs
executeFile p True args Nothing

42
README
View File

@@ -1,42 +0,0 @@
xmonad : a lightweight X11 window manager.
Motivation:
dwm is great, but we can do better, building a more robust,
more correct window manager in fewer lines of code, using strong
static typing. Enter Haskell.
If the aim of dwm is to fit in under 2000 lines of C, the aim of
xmonad is to fit in under 500 lines of Haskell with similar functionality.
Building:
Get the dependencies
X11 http://hackage.haskell.org/cgi-bin/hackage-scripts/package/X11-1.2
(Unfortunately X11-1.2 does not work correctly on AMD64. The latest
darcs version from http://darcs.haskell.org/packages/X11 does.)
mtl http://hackage.haskell.org/cgi-bin/hackage-scripts/package/mtl-1.0
unix http://hackage.haskell.org/cgi-bin/hackage-scripts/package/unix-2.0 (included with ghc)
X11-extras: darcs get http://darcs.haskell.org/~sjanssen/X11-extras
dmenu 2.{5,6,7} http://www.suckless.org/download/dmenu-2.7.tar.gz
And then build with Cabal:
runhaskell Setup.lhs configure --prefix=/home/dons
runhaskell Setup.lhs build
runhaskell Setup.lhs install
Then add:
exec /home/dons/bin/xmonad
to the last line of your .xsession file
Authors:
Spencer Janssen
Don Stewart

121
README.md Normal file
View File

@@ -0,0 +1,121 @@
# xmonad: A Tiling Window Manager
[![Build Status](https://travis-ci.org/xmonad/xmonad.svg?branch=master)](https://travis-ci.org/xmonad/xmonad)
[xmonad][] is a tiling window manager for X. Windows are arranged
automatically to tile the screen without gaps or overlap, maximising
screen use. Window manager features are accessible from the keyboard:
a mouse is optional. xmonad is written, configured and extensible in
Haskell. Custom layout algorithms, key bindings and other extensions
may be written by the user in config files. Layouts are applied
dynamically, and different layouts may be used on each
workspace. Xinerama is fully supported, allowing windows to be tiled
on several physical screens.
## Quick Start
* From hackage:
cabal update
cabal install xmonad xmonad-contrib
* Alternatively, build from source using the following repositories:
- <https://github.com/xmonad/xmonad>
- <https://github.com/xmonad/xmonad-contrib>
For the full story, read on.
## Building
Building is quite straightforward, and requires a basic Haskell toolchain.
On many systems xmonad is available as a binary package in your
package system (e.g. on Debian or Gentoo). If at all possible, use this
in preference to a source build, as the dependency resolution will be
simpler.
We'll now walk through the complete list of toolchain dependencies.
* GHC: the Glasgow Haskell Compiler
You first need a Haskell compiler. Your distribution's package
system will have binaries of GHC (the Glasgow Haskell Compiler),
the compiler we use, so install that first. If your operating
system's package system doesn't provide a binary version of GHC
and the `cabal-install` tool, you can install both using the
[Haskell Platform][platform].
It shouldn't be necessary to compile GHC from source -- every common
system has a pre-build binary version. However, if you want to
build from source, the following links will be helpful:
- GHC: <http://haskell.org/ghc/>
- Cabal: <http://haskell.org/cabal/download.html>
* X11 libraries:
Since you're building an X application, you'll need the C X11
library headers. On many platforms, these come pre-installed. For
others, such as Debian, you can get them from your package manager:
$ apt-get install libx11-dev libxinerama-dev libxext-dev
## Running xmonad
If you built XMonad using `cabal` then add:
exec $HOME/.cabal/bin/xmonad
to the last line of your `.xsession` or `.xinitrc` file.
## Configuring
See the [CONFIG][] document and the [example configuration file][example-config].
## XMonadContrib
There are many extensions to xmonad available in the XMonadContrib
(xmc) library. Examples include an ion3-like tabbed layout, a
prompt/program launcher, and various other useful modules.
XMonadContrib is available at:
* Latest release: <http://hackage.haskell.org/package/xmonad-contrib>
* Git version: <https://github.com/xmonad/xmonad-contrib>
## Other Useful Programs
A nicer xterm replacement, that supports resizing better:
* urxvt: <http://software.schmorp.de/pkg/rxvt-unicode.html>
For custom status bars:
* xmobar: <http://hackage.haskell.org/package/xmobar>
* taffybar: <https://github.com/travitch/taffybar>
* dzen: <http://gotmor.googlepages.com/dzen>
For a program dispatch menu:
* [XMonad.Prompt.Shell][xmc-prompt-shell]: (from [XMonadContrib][])
* dmenu: <http://www.suckless.org/download/>
* gmrun: (in your package system)
## Authors
* Spencer Janssen
* Don Stewart
* Jason Creighton
[xmonad]: http://xmonad.org
[xmonadcontrib]: https://hackage.haskell.org/package/xmonad-contrib
[xmc-prompt-shell]: https://hackage.haskell.org/package/xmonad-contrib/docs/XMonad-Prompt-Shell.html
[platform]: http://haskell.org/platform/
[example-config]: https://github.com/xmonad/xmonad-testing/blob/master/example-config.hs
[config]: https://github.com/xmonad/xmonad/blob/master/CONFIG

22
STYLE Normal file
View File

@@ -0,0 +1,22 @@
== Coding guidelines for contributing to
== xmonad and the xmonad contributed extensions
* Comment every top level function (particularly exported functions), and
provide a type signature; use Haddock syntax in the comments.
* Follow the coding style of the other modules.
* Code should be compilable with -Wall -Werror -fno-warn-unused-do-bind -fwarn-tabs.
There should be no warnings.
* Partial functions should be avoided: the window manager should not
crash, so do not call `error` or `undefined`
* Use 4 spaces for indenting.
* Any pure function added to the core should have QuickCheck properties
precisely defining its behavior.
* New modules should identify the author, and be submitted under
the same license as xmonad (BSD3 license or freer).

View File

@@ -1,252 +0,0 @@
-----------------------------------------------------------------------------
-- |
-- Module : StackSet
-- Copyright : (c) Don Stewart 2007
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : dons@cse.unsw.edu.au
-- Stability : stable
-- Portability : portable, needs GHC 6.6
--
-----------------------------------------------------------------------------
--
-- The 'StackSet' data type encodes a set of stacks. A given stack in the
-- set is always current. Elements may appear only once in the entire
-- stack set.
--
-- A StackSet provides a nice data structure for window managers with
-- multiple physical screens, and multiple workspaces, where each screen
-- has a stack of windows, and a window may be on only 1 screen at any
-- given time.
--
module StackSet (
StackSet(..), -- abstract
screen, peekStack, index, empty, peek, push, delete, member,
raiseFocus, rotate, promote, shift, view, workspace, fromList,
toList, size, visibleWorkspaces, swap {- helper -}
) where
import Data.Maybe
import qualified Data.List as L (delete,genericLength,elemIndex)
import qualified Data.Map as M
------------------------------------------------------------------------
-- | The StackSet data structure. Multiple screens containing tables of
-- stacks, with a current pointer
data StackSet i j a =
StackSet
{ current :: !i -- ^ the currently visible stack
, screen2ws:: !(M.Map j i) -- ^ screen -> workspace
, ws2screen:: !(M.Map i j) -- ^ workspace -> screen map
, stacks :: !(M.Map i [a]) -- ^ the separate stacks
, focus :: !(M.Map i a) -- ^ the window focused in each stack
, cache :: !(M.Map a i) -- ^ a cache of windows back to their stacks
} deriving Eq
instance (Show i, Show a) => Show (StackSet i j a) where
showsPrec p s r = showsPrec p (show . toList $ s) r
-- The cache is used to check on insertion that we don't already have
-- this window managed on another stack
------------------------------------------------------------------------
-- | /O(n)/. Create a new empty stacks of size 'n', indexed from 0, with 'm'
-- screens. (also indexed from 0) The 0-indexed stack will be current.
empty :: (Integral i, Integral j) => Int -> Int -> StackSet i j a
empty n m = StackSet { current = 0
, screen2ws = wsScrs2Works
, ws2screen = wsWorks2Scrs
, stacks = M.fromList (zip [0..fromIntegral n-1] (repeat []))
, focus = M.empty
, cache = M.empty }
where (scrs,wrks) = unzip $ map (\x -> (fromIntegral x, fromIntegral x)) [0..m-1]
wsScrs2Works = M.fromList (zip scrs wrks)
wsWorks2Scrs = M.fromList (zip wrks scrs)
-- | /O(log w)/. True if x is somewhere in the StackSet
member :: Ord a => a -> StackSet i j a -> Bool
member a w = M.member a (cache w)
-- | /O(log n)/. Looks up the workspace that x is in, if it is in the StackSet
-- lookup :: (Monad m, Ord a) => a -> StackSet i j a -> m i
-- lookup x w = M.lookup x (cache w)
-- | /O(n)/. Number of stacks
size :: StackSet i j a -> Int
size = M.size . stacks
------------------------------------------------------------------------
-- | fromList. Build a new StackSet from a list of list of elements,
-- keeping track of the currently focused workspace, and the total
-- number of workspaces. If there are duplicates in the list, the last
-- occurence wins.
fromList :: (Integral i, Integral j, Ord a) => (i, Int,[[a]]) -> StackSet i j a
fromList (_,_,[]) = error "Cannot build a StackSet from an empty list"
fromList (n,m,xs) | n < 0 || n >= L.genericLength xs
= error $ "Cursor index is out of range: " ++ show (n, length xs)
| m < 1 || m > L.genericLength xs
= error $ "Can't have more screens than workspaces: " ++ show (m, length xs)
fromList (o,m,xs) = view o $ foldr (\(i,ys) s ->
foldr (\a t -> insert a i t) s ys)
(empty (length xs) m) (zip [0..] xs)
-- | toList. Flatten a stackset to a list of lists
toList :: StackSet i j a -> (i,Int,[[a]])
toList x = (current x, M.size $ screen2ws x, map snd $ M.toList (stacks x))
-- | Push. Insert an element onto the top of the current stack.
-- If the element is already in the current stack, it is moved to the top.
-- If the element is managed on another stack, it is removed from that
-- stack first.
push :: (Integral i, Ord a) => a -> StackSet i j a -> StackSet i j a
push k w = insert k (current w) w
-- | /O(log s)/. Extract the element on the top of the current stack. If no such
-- element exists, Nothing is returned.
peek :: Integral i => StackSet i j a -> Maybe a
peek w = peekStack (current w) w
-- | /O(log s)/. Extract the element on the top of the given stack. If no such
-- element exists, Nothing is returned.
peekStack :: Integral i => i -> StackSet i j a -> Maybe a
peekStack i w = M.lookup i (focus w)
-- | /O(log s)/. Index. Extract the stack at workspace 'n'.
-- If the index is invalid, an exception is thrown.
index :: Integral i => i -> StackSet i j a -> [a]
index k w = fromJust (M.lookup k (stacks w))
-- | view. Set the stack specified by the argument as being visible and the
-- current StackSet. If the stack wasn't previously visible, it will become
-- visible on the current screen. If the index is out of range an exception is
-- thrown.
view :: (Integral i, Integral j) => i -> StackSet i j a -> StackSet i j a
-- view n w | n >= 0 && n < fromIntegral (M.size (stacks w)) -- coerce
view n w | M.member n (stacks w)
= if M.member n (ws2screen w) then w { current = n }
else tweak (fromJust $ screen (current w) w)
| otherwise = error $ "view: index out of bounds: " ++ show n
where
tweak sc = w { screen2ws = M.insert sc n (screen2ws w)
, ws2screen = M.insert n sc (M.filter (/=sc) (ws2screen w))
, current = n
}
-- | That screen that workspace 'n' is visible on, if any.
screen :: Integral i => i -> StackSet i j a -> Maybe j
screen n w = M.lookup n (ws2screen w)
-- | The workspace visible on screen 'sc'. Nothing if screen is out of bounds.
workspace :: Integral j => j -> StackSet i j a -> Maybe i
workspace sc w = M.lookup sc (screen2ws w)
-- | A list of the currently visible workspaces.
visibleWorkspaces :: StackSet i j a -> [i]
visibleWorkspaces = M.keys . ws2screen
--
-- | /O(log n)/. rotate. cycle the current window list up or down.
-- Has the effect of rotating focus. In fullscreen mode this will cause
-- a new window to be visible.
--
-- rotate EQ --> [5,6,7,8,1,2,3,4]
-- rotate GT --> [6,7,8,1,2,3,4,5]
-- rotate LT --> [4,5,6,7,8,1,2,3]
--
-- where xs = [5..8] ++ [1..4]
--
rotate :: (Integral i, Eq a) => Ordering -> StackSet i j a -> StackSet i j a
rotate o w = maybe w id $ do
f <- M.lookup (current w) (focus w)
s <- M.lookup (current w) (stacks w)
ea <- case o of
EQ -> Nothing
GT -> elemAfter f s
LT -> elemAfter f (reverse s)
return $ w { focus = M.insert (current w) ea (focus w) }
-- | /O(log n)/. shift. move the client on top of the current stack to
-- the top of stack 'n'. If the stack to move to is not valid, and
-- exception is thrown.
--
shift :: (Integral i, Ord a) => i -> StackSet i j a -> StackSet i j a
shift n w = maybe w (\k -> insert k n (delete k w)) (peek w)
-- | /O(log n)/. Insert an element onto the top of stack 'n'.
-- If the element is already in the stack 'n', it is moved to the top.
-- If the element exists on another stack, it is removed from that stack.
-- If the index is wrong an exception is thrown.
--
insert :: (Integral i, Ord a) => a -> i -> StackSet i j a -> StackSet i j a
insert k n old = new { cache = M.insert k n (cache new)
, stacks = M.adjust (k:) n (stacks new)
, focus = M.insert n k (focus new) }
where new = delete k old
-- | /O(log n)/. Delete an element entirely from from the StackSet.
-- This can be used to ensure that a given element is not managed elsewhere.
-- If the element doesn't exist, the original StackSet is returned unmodified.
delete :: (Integral i, Ord a) => a -> StackSet i j a -> StackSet i j a
delete k w = maybe w tweak (M.lookup k (cache w))
where
tweak i = w { cache = M.delete k (cache w)
, stacks = M.adjust (L.delete k) i (stacks w)
, focus = M.update (\k' -> if k == k' then elemAfter k (stacks w M.! i)
else Just k') i
(focus w)
}
-- | /O(log n)/. If the given window is contained in a workspace, make it the
-- focused window of that workspace, and make that workspace the current one.
raiseFocus :: (Integral i, Integral j, Ord a) => a -> StackSet i j a -> StackSet i j a
raiseFocus k w = case M.lookup k (cache w) of
Nothing -> w
Just i -> (view i w) { focus = M.insert i k (focus w) }
-- | Swap the currently focused window with the master window (the
-- window on top of the stack). Focus moves to the master.
promote :: (Integral i, Ord a) => StackSet i j a -> StackSet i j a
promote w = maybe w id $ do
a <- peek w -- fail if null
let w' = w { stacks = M.adjust (\s -> swap a (head s) s) (current w) (stacks w) }
return $ insert a (current w) w' -- and maintain focus (?)
--
-- | Swap first occurences of 'a' and 'b' in list.
-- If both elements are not in the list, the list is unchanged.
--
-- Given a set as a list (no duplicates)
--
-- > swap a b . swap a b == id
--
swap :: Eq a => a -> a -> [a] -> [a]
swap a b xs
| a == b = xs -- do nothing
| Just ai <- L.elemIndex a xs
, Just bi <- L.elemIndex b xs = insertAt bi a (insertAt ai b xs)
where
insertAt n x ys = as ++ x : tail bs
where (as,bs) = splitAt n ys
swap _ _ xs = xs -- do nothing
--
-- cycling:
-- promote w = w { stacks = M.adjust next (current w) (stacks w) }
-- where next [] = []
-- next xs = last xs : init xs
--
-- | Find the element in the (circular) list after given element.
elemAfter :: Eq a => a -> [a] -> Maybe a
elemAfter w ws = listToMaybe . filter (/= w) . dropWhile (/= w) $ ws ++ ws

29
TODO
View File

@@ -1,29 +0,0 @@
- think about the statusbar/multithreading.
Three shared TVars:
windowTitle :: TVar String
workspace :: TVar Int
statusText :: TVar String
Three threads:
Main thread, handles all of the events that it handles now. When
necessary, it writes to workspace or windowTitle
Status IO thread, the algorithm is something like this:
forever $ do
s <- getLine
atomic (writeTVar statusText s)
Statusbar drawing thread, waits for changes in all three TVars, and
redraws whenever it finds a change.
- Notes on new StackSet:
The actors: screens, workspaces, windows
Invariants:
- There is exactly one screen in focus at any given time.
- A screen views exactly one workspace.
- A workspace is visible on one or zero screens.
- A workspace has zero or more windows.
- A workspace has either one or zero windows in focus. Zero if the
workspace has no windows, one in all other cases.
- A window is a member of only one workspace.

122
XMonad.hs
View File

@@ -1,122 +0,0 @@
{-# OPTIONS -fglasgow-exts #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.hs
-- Copyright : (c) Spencer Janssen 2007
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : sjanssen@cse.unl.edu
-- Stability : unstable
-- Portability : not portable, uses cunning newtype deriving
--
-----------------------------------------------------------------------------
--
-- The X monad, a state monad transformer over IO, for the window
-- manager state, and support routines.
--
module XMonad (
X, WindowSet, WorkspaceId(..), ScreenId(..), XState(..), Layout(..), LayoutDesc(..),
runX, io, withDisplay, isRoot, spawn, trace, whenJust, rotateLayout
) where
import StackSet (StackSet)
import Control.Monad.State
import System.IO
import System.Posix.Process (executeFile, forkProcess, getProcessStatus)
import System.Exit
import Graphics.X11.Xlib
import qualified Data.Map as M
-- | XState, the window manager state.
-- Just the display, width, height and a window list
data XState = XState
{ display :: Display -- ^ the X11 display
, theRoot :: !Window -- ^ the root window
, wmdelete :: !Atom -- ^ window deletion atom
, wmprotocols :: !Atom -- ^ wm protocols atom
, dimensions :: !(Int,Int) -- ^ dimensions of the screen,
-- used for hiding windows
, workspace :: !WindowSet -- ^ workspace list
, xineScreens :: ![Rectangle] -- ^ dimensions of each screen
, defaultLayoutDesc :: !LayoutDesc -- ^ default layout
, layoutDescs :: !(M.Map WorkspaceId LayoutDesc) -- ^ mapping of workspaces
-- to descriptions of their layouts
}
type WindowSet = StackSet WorkspaceId ScreenId Window
-- | Virtual workspace indicies
newtype WorkspaceId = W Int deriving (Eq,Ord,Show,Enum,Num,Integral,Real)
-- | Physical screen indicies
newtype ScreenId = S Int deriving (Eq,Ord,Show,Enum,Num,Integral,Real)
------------------------------------------------------------------------
-- | The X monad, a StateT transformer over IO encapsulating the window
-- manager state
newtype X a = X (StateT XState IO a)
deriving (Functor, Monad, MonadIO, MonadState XState)
-- | Run the X monad, given a chunk of X monad code, and an initial state
-- Return the result, and final state
runX :: XState -> X a -> IO ()
runX st (X a) = runStateT a st >> return ()
-- ---------------------------------------------------------------------
-- Convenient wrappers to state
-- | Run a monad action with the current display settings
withDisplay :: (Display -> X ()) -> X ()
withDisplay f = gets display >>= f
-- | True if the given window is the root window
isRoot :: Window -> X Bool
isRoot w = liftM (w==) (gets theRoot)
------------------------------------------------------------------------
-- Layout handling
-- | The different layout modes
data Layout = Full | Tall | Wide deriving (Enum, Bounded, Eq)
-- | 'rot' for Layout.
rotateLayout :: Layout -> Layout
rotateLayout x = if x == maxBound then minBound else succ x
-- | A full description of a particular workspace's layout parameters.
data LayoutDesc = LayoutDesc { layoutType :: !Layout
, tileFraction :: !Rational
}
-- ---------------------------------------------------------------------
-- Utilities
-- | Lift an IO action into the X monad
io :: IO a -> X a
io = liftIO
{-# INLINE io #-}
-- | spawn. Launch an external application
spawn :: String -> X ()
spawn x = io $ do
pid <- forkProcess $ do
forkProcess (executeFile "/bin/sh" False ["-c", x] Nothing)
exitWith ExitSuccess
return ()
getProcessStatus True False pid
return ()
-- | Run a side effecting action with the current workspace. Like 'when' but
whenJust :: Maybe a -> (a -> X ()) -> X ()
whenJust mg f = maybe (return ()) f mg
-- | A 'trace' for the X monad. Logs a string to stderr. The result may
-- be found in your .xsession-errors file
trace :: String -> X ()
trace msg = io $! do hPutStrLn stderr msg; hFlush stderr

1
cabal.project Normal file
View File

@@ -0,0 +1 @@
packages: ./

71
man/HCAR.tex Normal file
View File

@@ -0,0 +1,71 @@
% xmonad-Gx.tex
\begin{hcarentry}{xmonad}
\label{xmonad}
\report{Gwern Branwen}%11/11
\status{active development}
\makeheader
XMonad is a tiling window manager for X. Windows are arranged
automatically to tile the screen without gaps or overlap, maximizing
screen use. Window manager features are accessible from the keyboard; a
mouse is optional. XMonad is written, configured, and extensible in
Haskell. Custom layout algorithms, key bindings, and other extensions may
be written by the user in config files. Layouts are applied
dynamically, and different layouts may be used on each workspace.
Xinerama is fully supported, allowing windows to be tiled on several
physical screens.
Development since the last report has continued; XMonad founder Don Stewart
has stepped down and Adam Vogt is the new maintainer.
After gestating for 2 years, version 0.10 has been released, with simultaneous
releases of the XMonadContrib library of customizations (which has now grown to
no less than 216 modules encompassing a dizzying array of features) and the
xmonad-extras package of extensions,
Details of changes between releases can be found in the release notes:
\begin{compactitem}
\item \url{http://haskell.org/haskellwiki/Xmonad/Notable_changes_since_0.8}
\item \url{http://haskell.org/haskellwiki/Xmonad/Notable_changes_since_0.9}
% \item \url{http://haskell.org/haskellwiki/Xmonad/Notable_changes_since_0.10}
\item the Darcs repositories have been upgraded to the hashed format
\item XMonad.Config.PlainConfig allows writing configs in a more 'normal' style, and not raw Haskell
\item Supports using local modules in xmonad.hs; for example: to use definitions from \~/.xmonad/lib/XMonad/Stack/MyAdditions.hs
\item xmonad --restart CLI option
\item xmonad --replace CLI option
\item XMonad.Prompt now has customizable keymaps
\item Actions.GridSelect - a GUI menu for selecting windows or workspaces \& substring search on window names
\item Actions.OnScreen
\item Extensions now can have state
\item Actions.SpawnOn - uses state to spawn applications on the workspace the user was originally on,
and not where the user happens to be
\item Markdown manpages and not man/troff
\item XMonad.Layout.ImageButtonDecoration \&\\ XMonad.Util.Image
\item XMonad.Layout.Groups
\item XMonad.Layout.ZoomRow
\item XMonad.Layout.Renamed
\item XMonad.Layout.Drawer
\item XMonad.Layout.FullScreen
\item XMonad.Hooks.ScreenCorners
\item XMonad.Actions.DynamicWorkspaceOrder
\item XMonad.Actions.WorkspaceNames
\item XMonad.Actions.DynamicWorkspaceGroups
\end{compactitem}
Binary packages of XMonad and XMonadContrib are available for all major Linux distributions.
\FurtherReading
\begin{compactitem}
\item Homepage:
\url{http://xmonad.org/}
\item Git source:
\texttt{git clone} \url{https://github.com/xmonad/xmonad.git}
\item IRC channel:
\verb+#xmonad @@ irc.freenode.org+
\item Mailing list:
\email{xmonad@@haskell.org}
\end{compactitem}
\end{hcarentry}

282
man/xmonad.1 Normal file
View File

@@ -0,0 +1,282 @@
.TH xmonad 1 "31 December 2012" xmonad-0.13 "xmonad manual".\" Automatically generated by Pandoc 1.19.2.1
.\"
.TH "" "" "" "" ""
.hy
.SH Name
.PP
xmonad \- a tiling window manager
.SH Description
.PP
\f[I]xmonad\f[] is a minimalist tiling window manager for X, written in
Haskell.
Windows are managed using automatic layout algorithms, which can be
dynamically reconfigured.
At any time windows are arranged so as to maximize the use of screen
real estate.
All features of the window manager are accessible purely from the
keyboard: a mouse is entirely optional.
\f[I]xmonad\f[] is configured in Haskell, and custom layout algorithms
may be implemented by the user in config files.
A principle of \f[I]xmonad\f[] is predictability: the user should know
in advance precisely the window arrangement that will result from any
action.
.PP
By default, \f[I]xmonad\f[] provides three layout algorithms: tall, wide
and fullscreen.
In tall or wide mode, windows are tiled and arranged to prevent overlap
and maximize screen use.
Sets of windows are grouped together on virtual screens, and each screen
retains its own layout, which may be reconfigured dynamically.
Multiple physical monitors are supported via Xinerama, allowing
simultaneous display of a number of screens.
.PP
By utilizing the expressivity of a modern functional language with a
rich static type system, \f[I]xmonad\f[] provides a complete, featureful
window manager in less than 1200 lines of code, with an emphasis on
correctness and robustness.
Internal properties of the window manager are checked using a
combination of static guarantees provided by the type system, and
type\-based automated testing.
A benefit of this is that the code is simple to understand, and easy to
modify.
.SH Usage
.PP
\f[I]xmonad\f[] places each window into a "workspace".
Each workspace can have any number of windows, which you can cycle
though with mod\-j and mod\-k.
Windows are either displayed full screen, tiled horizontally, or tiled
vertically.
You can toggle the layout mode with mod\-space, which will cycle through
the available modes.
.PP
You can switch to workspace N with mod\-N.
For example, to switch to workspace 5, you would press mod\-5.
Similarly, you can move the current window to another workspace with
mod\-shift\-N.
.PP
When running with multiple monitors (Xinerama), each screen has exactly
1 workspace visible.
mod\-{w,e,r} switch the focus between screens, while shift\-mod\-{w,e,r}
move the current window to that screen.
When \f[I]xmonad\f[] starts, workspace 1 is on screen 1, workspace 2 is
on screen 2, etc.
When switching workspaces to one that is already visible, the current
and visible workspaces are swapped.
.SS Flags
.PP
xmonad has several flags which you may pass to the executable.
These flags are:
.TP
.B \-\-recompile
Recompiles your configuration in \f[I]~/.xmonad/xmonad.hs\f[]
.RS
.RE
.TP
.B \-\-restart
Causes the currently running \f[I]xmonad\f[] process to restart
.RS
.RE
.TP
.B \-\-replace
Replace the current window manager with xmonad
.RS
.RE
.TP
.B \-\-version
Display version of \f[I]xmonad\f[]
.RS
.RE
.TP
.B \-\-verbose\-version
Display detailed version of \f[I]xmonad\f[]
.RS
.RE
.SS Default keyboard bindings
.TP
.B mod\-shift\-return
Launch terminal
.RS
.RE
.TP
.B mod\-p
Launch dmenu
.RS
.RE
.TP
.B mod\-shift\-p
Launch gmrun
.RS
.RE
.TP
.B mod\-shift\-c
Close the focused window
.RS
.RE
.TP
.B mod\-space
Rotate through the available layout algorithms
.RS
.RE
.TP
.B mod\-shift\-space
Reset the layouts on the current workspace to default
.RS
.RE
.TP
.B mod\-n
Resize viewed windows to the correct size
.RS
.RE
.TP
.B mod\-tab
Move focus to the next window
.RS
.RE
.TP
.B mod\-shift\-tab
Move focus to the previous window
.RS
.RE
.TP
.B mod\-j
Move focus to the next window
.RS
.RE
.TP
.B mod\-k
Move focus to the previous window
.RS
.RE
.TP
.B mod\-m
Move focus to the master window
.RS
.RE
.TP
.B mod\-return
Swap the focused window and the master window
.RS
.RE
.TP
.B mod\-shift\-j
Swap the focused window with the next window
.RS
.RE
.TP
.B mod\-shift\-k
Swap the focused window with the previous window
.RS
.RE
.TP
.B mod\-h
Shrink the master area
.RS
.RE
.TP
.B mod\-l
Expand the master area
.RS
.RE
.TP
.B mod\-t
Push window back into tiling
.RS
.RE
.TP
.B mod\-comma
Increment the number of windows in the master area
.RS
.RE
.TP
.B mod\-period
Deincrement the number of windows in the master area
.RS
.RE
.TP
.B mod\-shift\-q
Quit xmonad
.RS
.RE
.TP
.B mod\-q
Restart xmonad
.RS
.RE
.TP
.B mod\-shift\-slash
Run xmessage with a summary of the default keybindings (useful for
beginners)
.RS
.RE
.TP
.B mod\-[1..9]
Switch to workspace N
.RS
.RE
.TP
.B mod\-shift\-[1..9]
Move client to workspace N
.RS
.RE
.TP
.B mod\-{w,e,r}
Switch to physical/Xinerama screens 1, 2, or 3
.RS
.RE
.TP
.B mod\-shift\-{w,e,r}
Move client to screen 1, 2, or 3
.RS
.RE
.TP
.B mod\-button1
Set the window to floating mode and move by dragging
.RS
.RE
.TP
.B mod\-button2
Raise the window to the top of the stack
.RS
.RE
.TP
.B mod\-button3
Set the window to floating mode and resize by dragging
.RS
.RE
.SH Examples
.PP
To use xmonad as your window manager add to your \f[I]~/.xinitrc\f[]
file:
.RS
.PP
exec xmonad
.RE
.SH Customization
.PP
xmonad is customized in ~/.xmonad/xmonad.hs, and then restarted with
mod\-q.
.PP
You can find many extensions to the core feature set in the xmonad\-
contrib package, available through your package manager or from
xmonad.org (http://xmonad.org).
.SS Modular Configuration
.PP
As of \f[I]xmonad\-0.9\f[], any additional Haskell modules may be placed
in \f[I]~/.xmonad/lib/\f[] are available in GHC\[aq]s searchpath.
Hierarchical modules are supported: for example, the file
\f[I]~/.xmonad/lib/XMonad/Stack/MyAdditions.hs\f[] could contain:
.IP
.nf
\f[C]
module\ XMonad.Stack.MyAdditions\ (function1)\ where
\ \ function1\ =\ error\ "function1:\ Not\ implemented\ yet!"
\f[]
.fi
.PP
Your xmonad.hs may then import XMonad.Stack.MyAdditions as if that
module was contained within xmonad or xmonad\-contrib.
.SH Bugs
.PP
Probably.
If you find any, please report them to the
bugtracker (https://github.com/xmonad/xmonad/issues)

165
man/xmonad.1.html Normal file
View File

@@ -0,0 +1,165 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-Style-Type" content="text/css" />
<meta name="generator" content="pandoc" />
<title></title>
<style type="text/css">code{white-space: pre;}</style>
</head>
<body>
<h1>xmonad-0.13</h1><p>Section: xmonad manual (1)<br/>Updated: 31 December 2012</p><hr/>
<div id="TOC">
<ul>
<li><a href="#name">Name</a></li>
<li><a href="#description">Description</a></li>
<li><a href="#usage">Usage</a><ul>
<li><a href="#flags">Flags</a></li>
<li><a href="#default-keyboard-bindings">Default keyboard bindings</a></li>
</ul></li>
<li><a href="#examples">Examples</a></li>
<li><a href="#customization">Customization</a><ul>
<li><a href="#modular-configuration">Modular Configuration</a></li>
</ul></li>
<li><a href="#bugs">Bugs</a></li>
</ul>
</div>
<h1 id="name">Name</h1>
<p>xmonad - a tiling window manager</p>
<h1 id="description">Description</h1>
<p><em>xmonad</em> is a minimalist tiling window manager for X, written in Haskell. Windows are managed using automatic layout algorithms, which can be dynamically reconfigured. At any time windows are arranged so as to maximize the use of screen real estate. All features of the window manager are accessible purely from the keyboard: a mouse is entirely optional. <em>xmonad</em> is configured in Haskell, and custom layout algorithms may be implemented by the user in config files. A principle of <em>xmonad</em> is predictability: the user should know in advance precisely the window arrangement that will result from any action.</p>
<p>By default, <em>xmonad</em> provides three layout algorithms: tall, wide and fullscreen. In tall or wide mode, windows are tiled and arranged to prevent overlap and maximize screen use. Sets of windows are grouped together on virtual screens, and each screen retains its own layout, which may be reconfigured dynamically. Multiple physical monitors are supported via Xinerama, allowing simultaneous display of a number of screens.</p>
<p>By utilizing the expressivity of a modern functional language with a rich static type system, <em>xmonad</em> provides a complete, featureful window manager in less than 1200 lines of code, with an emphasis on correctness and robustness. Internal properties of the window manager are checked using a combination of static guarantees provided by the type system, and type-based automated testing. A benefit of this is that the code is simple to understand, and easy to modify.</p>
<h1 id="usage">Usage</h1>
<p><em>xmonad</em> places each window into a &quot;workspace&quot;. Each workspace can have any number of windows, which you can cycle though with mod-j and mod-k. Windows are either displayed full screen, tiled horizontally, or tiled vertically. You can toggle the layout mode with mod-space, which will cycle through the available modes.</p>
<p>You can switch to workspace N with mod-N. For example, to switch to workspace 5, you would press mod-5. Similarly, you can move the current window to another workspace with mod-shift-N.</p>
<p>When running with multiple monitors (Xinerama), each screen has exactly 1 workspace visible. mod-{w,e,r} switch the focus between screens, while shift-mod-{w,e,r} move the current window to that screen. When <em>xmonad</em> starts, workspace 1 is on screen 1, workspace 2 is on screen 2, etc. When switching workspaces to one that is already visible, the current and visible workspaces are swapped.</p>
<h2 id="flags">Flags</h2>
<p>xmonad has several flags which you may pass to the executable. These flags are:</p>
<dl>
<dt>--recompile</dt>
<dd>Recompiles your configuration in <em>~/.xmonad/xmonad.hs</em>
</dd>
<dt>--restart</dt>
<dd>Causes the currently running <em>xmonad</em> process to restart
</dd>
<dt>--replace</dt>
<dd>Replace the current window manager with xmonad
</dd>
<dt>--version</dt>
<dd>Display version of <em>xmonad</em>
</dd>
<dt>--verbose-version</dt>
<dd>Display detailed version of <em>xmonad</em>
</dd>
</dl>
<h2 id="default-keyboard-bindings">Default keyboard bindings</h2>
<dl>
<dt>mod-shift-return</dt>
<dd>Launch terminal
</dd>
<dt>mod-p</dt>
<dd>Launch dmenu
</dd>
<dt>mod-shift-p</dt>
<dd>Launch gmrun
</dd>
<dt>mod-shift-c</dt>
<dd>Close the focused window
</dd>
<dt>mod-space</dt>
<dd>Rotate through the available layout algorithms
</dd>
<dt>mod-shift-space</dt>
<dd>Reset the layouts on the current workspace to default
</dd>
<dt>mod-n</dt>
<dd>Resize viewed windows to the correct size
</dd>
<dt>mod-tab</dt>
<dd>Move focus to the next window
</dd>
<dt>mod-shift-tab</dt>
<dd>Move focus to the previous window
</dd>
<dt>mod-j</dt>
<dd>Move focus to the next window
</dd>
<dt>mod-k</dt>
<dd>Move focus to the previous window
</dd>
<dt>mod-m</dt>
<dd>Move focus to the master window
</dd>
<dt>mod-return</dt>
<dd>Swap the focused window and the master window
</dd>
<dt>mod-shift-j</dt>
<dd>Swap the focused window with the next window
</dd>
<dt>mod-shift-k</dt>
<dd>Swap the focused window with the previous window
</dd>
<dt>mod-h</dt>
<dd>Shrink the master area
</dd>
<dt>mod-l</dt>
<dd>Expand the master area
</dd>
<dt>mod-t</dt>
<dd>Push window back into tiling
</dd>
<dt>mod-comma</dt>
<dd>Increment the number of windows in the master area
</dd>
<dt>mod-period</dt>
<dd>Deincrement the number of windows in the master area
</dd>
<dt>mod-shift-q</dt>
<dd>Quit xmonad
</dd>
<dt>mod-q</dt>
<dd>Restart xmonad
</dd>
<dt>mod-shift-slash</dt>
<dd>Run xmessage with a summary of the default keybindings (useful for beginners)
</dd>
<dt>mod-[1..9]</dt>
<dd>Switch to workspace N
</dd>
<dt>mod-shift-[1..9]</dt>
<dd>Move client to workspace N
</dd>
<dt>mod-{w,e,r}</dt>
<dd>Switch to physical/Xinerama screens 1, 2, or 3
</dd>
<dt>mod-shift-{w,e,r}</dt>
<dd>Move client to screen 1, 2, or 3
</dd>
<dt>mod-button1</dt>
<dd>Set the window to floating mode and move by dragging
</dd>
<dt>mod-button2</dt>
<dd>Raise the window to the top of the stack
</dd>
<dt>mod-button3</dt>
<dd>Set the window to floating mode and resize by dragging
</dd>
</dl>
<h1 id="examples">Examples</h1>
<p>To use xmonad as your window manager add to your <em>~/.xinitrc</em> file:</p>
<blockquote>
<p>exec xmonad</p>
</blockquote>
<h1 id="customization">Customization</h1>
<p>xmonad is customized in ~/.xmonad/xmonad.hs, and then restarted with mod-q.</p>
<p>You can find many extensions to the core feature set in the xmonad- contrib package, available through your package manager or from <a href="http://xmonad.org">xmonad.org</a>.</p>
<h2 id="modular-configuration">Modular Configuration</h2>
<p>As of <em>xmonad-0.9</em>, any additional Haskell modules may be placed in <em>~/.xmonad/lib/</em> are available in GHC's searchpath. Hierarchical modules are supported: for example, the file <em>~/.xmonad/lib/XMonad/Stack/MyAdditions.hs</em> could contain:</p>
<pre class="haskell"><code>module XMonad.Stack.MyAdditions (function1) where
function1 = error &quot;function1: Not implemented yet!&quot;</code></pre>
<p>Your xmonad.hs may then import XMonad.Stack.MyAdditions as if that module was contained within xmonad or xmonad-contrib.</p>
<h1 id="bugs">Bugs</h1>
<p>Probably. If you find any, please report them to the <a href="https://github.com/xmonad/xmonad/issues">bugtracker</a></p>
</body>
</html>

104
man/xmonad.1.markdown Normal file
View File

@@ -0,0 +1,104 @@
#Name
xmonad - a tiling window manager
#Description
_xmonad_ is a minimalist tiling window manager for X, written in Haskell.
Windows are managed using automatic layout algorithms, which can be
dynamically reconfigured. At any time windows are arranged so as to
maximize the use of screen real estate. All features of the window manager
are accessible purely from the keyboard: a mouse is entirely optional.
_xmonad_ is configured in Haskell, and custom layout algorithms may be
implemented by the user in config files. A principle of _xmonad_ is
predictability: the user should know in advance precisely the window
arrangement that will result from any action.
By default, _xmonad_ provides three layout algorithms: tall, wide and
fullscreen. In tall or wide mode, windows are tiled and arranged to prevent
overlap and maximize screen use. Sets of windows are grouped together on
virtual screens, and each screen retains its own layout, which may be
reconfigured dynamically. Multiple physical monitors are supported via
Xinerama, allowing simultaneous display of a number of screens.
By utilizing the expressivity of a modern functional language with a rich
static type system, _xmonad_ provides a complete, featureful window manager
in less than 1200 lines of code, with an emphasis on correctness and
robustness. Internal properties of the window manager are checked using a
combination of static guarantees provided by the type system, and
type-based automated testing. A benefit of this is that the code is simple
to understand, and easy to modify.
#Usage
_xmonad_ places each window into a "workspace". Each workspace can have
any number of windows, which you can cycle though with mod-j and mod-k.
Windows are either displayed full screen, tiled horizontally, or tiled
vertically. You can toggle the layout mode with mod-space, which will cycle
through the available modes.
You can switch to workspace N with mod-N. For example, to switch to
workspace 5, you would press mod-5. Similarly, you can move the current
window to another workspace with mod-shift-N.
When running with multiple monitors (Xinerama), each screen has exactly 1
workspace visible. mod-{w,e,r} switch the focus between screens, while
shift-mod-{w,e,r} move the current window to that screen. When _xmonad_
starts, workspace 1 is on screen 1, workspace 2 is on screen 2, etc. When
switching workspaces to one that is already visible, the current and
visible workspaces are swapped.
##Flags
xmonad has several flags which you may pass to the executable.
These flags are:
--recompile
: Recompiles your configuration in _~/.xmonad/xmonad.hs_
--restart
: Causes the currently running _xmonad_ process to restart
--replace
: Replace the current window manager with xmonad
--version
: Display version of _xmonad_
--verbose-version
: Display detailed version of _xmonad_
##Default keyboard bindings
___KEYBINDINGS___
#Examples
To use xmonad as your window manager add to your _~/.xinitrc_ file:
> exec xmonad
#Customization
xmonad is customized in ~/.xmonad/xmonad.hs, and then restarted
with mod-q.
You can find many extensions to the core feature set in the xmonad-
contrib package, available through your package manager or from
[xmonad.org].
##Modular Configuration
As of _xmonad-0.9_, any additional Haskell modules may be placed in
_~/.xmonad/lib/_ are available in GHC's searchpath. Hierarchical modules
are supported: for example, the file
_~/.xmonad/lib/XMonad/Stack/MyAdditions.hs_ could contain:
```haskell
module XMonad.Stack.MyAdditions (function1) where
function1 = error "function1: Not implemented yet!"
```
Your xmonad.hs may then import XMonad.Stack.MyAdditions as if that
module was contained within xmonad or xmonad-contrib.
#Bugs
Probably. If you find any, please report them to the [bugtracker]
[xmonad.org]: http://xmonad.org
[bugtracker]: https://github.com/xmonad/xmonad/issues

333
man/xmonad.hs Normal file
View File

@@ -0,0 +1,333 @@
--
-- xmonad example config file.
--
-- A template showing all available configuration hooks,
-- and how to override the defaults in your own xmonad.hs conf file.
--
-- Normally, you'd only override those defaults you care about.
--
import XMonad
import Data.Monoid
import System.Exit
import qualified XMonad.StackSet as W
import qualified Data.Map as M
-- The preferred terminal program, which is used in a binding below and by
-- certain contrib modules.
--
myTerminal = "xterm"
-- Whether focus follows the mouse pointer.
myFocusFollowsMouse :: Bool
myFocusFollowsMouse = True
-- Whether clicking on a window to focus also passes the click to the window
myClickJustFocuses :: Bool
myClickJustFocuses = False
-- Width of the window border in pixels.
--
myBorderWidth = 1
-- modMask lets you specify which modkey you want to use. The default
-- is mod1Mask ("left alt"). You may also consider using mod3Mask
-- ("right alt"), which does not conflict with emacs keybindings. The
-- "windows key" is usually mod4Mask.
--
myModMask = mod1Mask
-- The default number of workspaces (virtual screens) and their names.
-- By default we use numeric strings, but any string may be used as a
-- workspace name. The number of workspaces is determined by the length
-- of this list.
--
-- A tagging example:
--
-- > workspaces = ["web", "irc", "code" ] ++ map show [4..9]
--
myWorkspaces = ["1","2","3","4","5","6","7","8","9"]
-- Border colors for unfocused and focused windows, respectively.
--
myNormalBorderColor = "#dddddd"
myFocusedBorderColor = "#ff0000"
------------------------------------------------------------------------
-- Key bindings. Add, modify or remove key bindings here.
--
myKeys conf@(XConfig {XMonad.modMask = modm}) = M.fromList $
-- launch a terminal
[ ((modm .|. shiftMask, xK_Return), spawn $ XMonad.terminal conf)
-- launch dmenu
, ((modm, xK_p ), spawn "dmenu_run")
-- launch gmrun
, ((modm .|. shiftMask, xK_p ), spawn "gmrun")
-- close focused window
, ((modm .|. shiftMask, xK_c ), kill)
-- Rotate through the available layout algorithms
, ((modm, xK_space ), sendMessage NextLayout)
-- Reset the layouts on the current workspace to default
, ((modm .|. shiftMask, xK_space ), setLayout $ XMonad.layoutHook conf)
-- Resize viewed windows to the correct size
, ((modm, xK_n ), refresh)
-- Move focus to the next window
, ((modm, xK_Tab ), windows W.focusDown)
-- Move focus to the next window
, ((modm, xK_j ), windows W.focusDown)
-- Move focus to the previous window
, ((modm, xK_k ), windows W.focusUp )
-- Move focus to the master window
, ((modm, xK_m ), windows W.focusMaster )
-- Swap the focused window and the master window
, ((modm, xK_Return), windows W.swapMaster)
-- Swap the focused window with the next window
, ((modm .|. shiftMask, xK_j ), windows W.swapDown )
-- Swap the focused window with the previous window
, ((modm .|. shiftMask, xK_k ), windows W.swapUp )
-- Shrink the master area
, ((modm, xK_h ), sendMessage Shrink)
-- Expand the master area
, ((modm, xK_l ), sendMessage Expand)
-- Push window back into tiling
, ((modm, xK_t ), withFocused $ windows . W.sink)
-- Increment the number of windows in the master area
, ((modm , xK_comma ), sendMessage (IncMasterN 1))
-- Deincrement the number of windows in the master area
, ((modm , xK_period), sendMessage (IncMasterN (-1)))
-- Toggle the status bar gap
-- Use this binding with avoidStruts from Hooks.ManageDocks.
-- See also the statusBar function from Hooks.DynamicLog.
--
-- , ((modm , xK_b ), sendMessage ToggleStruts)
-- Quit xmonad
, ((modm .|. shiftMask, xK_q ), io (exitWith ExitSuccess))
-- Restart xmonad
, ((modm , xK_q ), spawn "xmonad --recompile; xmonad --restart")
-- Run xmessage with a summary of the default keybindings (useful for beginners)
, ((modm .|. shiftMask, xK_slash ), spawn ("echo \"" ++ help ++ "\" | xmessage -file -"))
]
++
--
-- mod-[1..9], Switch to workspace N
-- mod-shift-[1..9], Move client to workspace N
--
[((m .|. modm, k), windows $ f i)
| (i, k) <- zip (XMonad.workspaces conf) [xK_1 .. xK_9]
, (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 .|. modm, 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)]]
------------------------------------------------------------------------
-- Mouse bindings: default actions bound to mouse events
--
myMouseBindings (XConfig {XMonad.modMask = modm}) = M.fromList $
-- mod-button1, Set the window to floating mode and move by dragging
[ ((modm, button1), (\w -> focus w >> mouseMoveWindow w
>> windows W.shiftMaster))
-- mod-button2, Raise the window to the top of the stack
, ((modm, button2), (\w -> focus w >> windows W.shiftMaster))
-- mod-button3, Set the window to floating mode and resize by dragging
, ((modm, button3), (\w -> focus w >> mouseResizeWindow w
>> windows W.shiftMaster))
-- you may also bind events to the mouse scroll wheel (button4 and button5)
]
------------------------------------------------------------------------
-- Layouts:
-- You can specify and transform your layouts by modifying these values.
-- If you change layout bindings be sure to use 'mod-shift-space' after
-- restarting (with 'mod-q') to reset your layout state to the new
-- defaults, as xmonad preserves your old layout settings by default.
--
-- The available layouts. Note that each layout is separated by |||,
-- which denotes layout choice.
--
myLayout = tiled ||| Mirror tiled ||| Full
where
-- default tiling algorithm partitions the screen into two panes
tiled = Tall nmaster delta ratio
-- The default number of windows in the master pane
nmaster = 1
-- Default proportion of screen occupied by master pane
ratio = 1/2
-- Percent of screen to increment by when resizing panes
delta = 3/100
------------------------------------------------------------------------
-- Window rules:
-- Execute arbitrary actions and WindowSet manipulations when managing
-- a new window. You can use this to, for example, always float a
-- particular program, or have a client always appear on a particular
-- workspace.
--
-- To find the property name associated with a program, use
-- > xprop | grep WM_CLASS
-- and click on the client you're interested in.
--
-- To match on the WM_NAME, you can use 'title' in the same way that
-- 'className' and 'resource' are used below.
--
myManageHook = composeAll
[ className =? "MPlayer" --> doFloat
, className =? "Gimp" --> doFloat
, resource =? "desktop_window" --> doIgnore
, resource =? "kdesktop" --> doIgnore ]
------------------------------------------------------------------------
-- Event handling
-- * EwmhDesktops users should change this to ewmhDesktopsEventHook
--
-- Defines a custom handler function for X Events. The function should
-- return (All True) if the default handler is to be run afterwards. To
-- combine event hooks use mappend or mconcat from Data.Monoid.
--
myEventHook = mempty
------------------------------------------------------------------------
-- Status bars and logging
-- Perform an arbitrary action on each internal state change or X event.
-- See the 'XMonad.Hooks.DynamicLog' extension for examples.
--
myLogHook = return ()
------------------------------------------------------------------------
-- Startup hook
-- Perform an arbitrary action each time xmonad starts or is restarted
-- with mod-q. Used by, e.g., XMonad.Layout.PerWorkspace to initialize
-- per-workspace layout choices.
--
-- By default, do nothing.
myStartupHook = return ()
------------------------------------------------------------------------
-- Now run xmonad with all the defaults we set up.
-- Run xmonad with the settings you specify. No need to modify this.
--
main = xmonad defaults
-- A structure containing your configuration settings, overriding
-- fields in the default config. Any you don't override, will
-- use the defaults defined in xmonad/XMonad/Config.hs
--
-- No need to modify this.
--
defaults = def {
-- simple stuff
terminal = myTerminal,
focusFollowsMouse = myFocusFollowsMouse,
clickJustFocuses = myClickJustFocuses,
borderWidth = myBorderWidth,
modMask = myModMask,
workspaces = myWorkspaces,
normalBorderColor = myNormalBorderColor,
focusedBorderColor = myFocusedBorderColor,
-- key bindings
keys = myKeys,
mouseBindings = myMouseBindings,
-- hooks, layouts
layoutHook = myLayout,
manageHook = myManageHook,
handleEventHook = myEventHook,
logHook = myLogHook,
startupHook = myStartupHook
}
-- | Finally, a copy of the default bindings in simple textual tabular format.
help :: String
help = unlines ["The default modifier key is 'alt'. Default keybindings:",
"",
"-- launching and killing programs",
"mod-Shift-Enter Launch xterminal",
"mod-p Launch dmenu",
"mod-Shift-p Launch gmrun",
"mod-Shift-c Close/kill the focused window",
"mod-Space Rotate through the available layout algorithms",
"mod-Shift-Space Reset the layouts on the current workSpace to default",
"mod-n Resize/refresh viewed windows to the correct size",
"",
"-- move focus up or down the window stack",
"mod-Tab Move focus to the next window",
"mod-Shift-Tab Move focus to the previous window",
"mod-j Move focus to the next window",
"mod-k Move focus to the previous window",
"mod-m Move focus to the master window",
"",
"-- modifying the window order",
"mod-Return Swap the focused window and the master window",
"mod-Shift-j Swap the focused window with the next window",
"mod-Shift-k Swap the focused window with the previous window",
"",
"-- resizing the master/slave ratio",
"mod-h Shrink the master area",
"mod-l Expand the master area",
"",
"-- floating layer support",
"mod-t Push window back into tiling; unfloat and re-tile it",
"",
"-- increase or decrease number of windows in the master area",
"mod-comma (mod-,) Increment the number of windows in the master area",
"mod-period (mod-.) Deincrement the number of windows in the master area",
"",
"-- quit, or restart",
"mod-Shift-q Quit xmonad",
"mod-q Restart xmonad",
"mod-[1..9] Switch to workSpace N",
"",
"-- Workspaces & screens",
"mod-Shift-[1..9] Move client to workspace N",
"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",
"",
"-- Mouse bindings: default actions bound to mouse events",
"mod-button1 Set the window to floating mode and move by dragging",
"mod-button2 Raise the window to the top of the stack",
"mod-button3 Set the window to floating mode and resize by dragging"]

47
src/XMonad.hs Normal file
View File

@@ -0,0 +1,47 @@
--------------------------------------------------------------------
-- |
-- Module : XMonad
-- Copyright : (c) Don Stewart
-- License : BSD3
--
-- Maintainer: Don Stewart <dons@galois.com>
-- Stability : provisional
-- Portability:
--
--------------------------------------------------------------------
--
-- Useful exports for configuration files.
module XMonad (
module XMonad.Main,
module XMonad.Core,
module XMonad.Config,
module XMonad.Layout,
module XMonad.ManageHook,
module XMonad.Operations,
module Graphics.X11,
module Graphics.X11.Xlib.Extras,
(.|.),
MonadState(..), gets, modify,
MonadReader(..), asks,
MonadIO(..)
) where
-- core modules
import XMonad.Main
import XMonad.Core
import XMonad.Config
import XMonad.Layout
import XMonad.ManageHook
import XMonad.Operations
-- import XMonad.StackSet -- conflicts with 'workspaces' defined in XMonad.hs
-- modules needed to get basic configuration working
import Data.Bits
import Graphics.X11 hiding (refreshKeyboardMapping)
import Graphics.X11.Xlib.Extras
import Control.Monad.State
import Control.Monad.Reader

336
src/XMonad/Config.hs Normal file
View File

@@ -0,0 +1,336 @@
{-# OPTIONS_GHC -fno-warn-missing-signatures -fno-warn-orphans #-}
{-# LANGUAGE TypeFamilies #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Config
-- Copyright : (c) Spencer Janssen 2007
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : dons@galois.com
-- Stability : stable
-- Portability : portable
--
-- This module specifies the default configuration values for xmonad.
--
-- DO NOT MODIFY THIS FILE! It won't work. You may configure xmonad
-- by providing your own @~\/.xmonad\/xmonad.hs@ that overrides
-- specific fields in the default config, 'def'. For a starting point, you can
-- copy the @xmonad.hs@ found in the @man@ directory, or look at
-- examples on the xmonad wiki.
--
------------------------------------------------------------------------
module XMonad.Config (defaultConfig, Default(..)) where
--
-- Useful imports
--
import XMonad.Core as XMonad hiding
(workspaces,manageHook,keys,logHook,startupHook,borderWidth,mouseBindings
,layoutHook,modMask,terminal,normalBorderColor,focusedBorderColor,focusFollowsMouse
,handleEventHook,clickJustFocuses,rootMask,clientMask)
import qualified XMonad.Core as XMonad
(workspaces,manageHook,keys,logHook,startupHook,borderWidth,mouseBindings
,layoutHook,modMask,terminal,normalBorderColor,focusedBorderColor,focusFollowsMouse
,handleEventHook,clickJustFocuses,rootMask,clientMask)
import XMonad.Layout
import XMonad.Operations
import XMonad.ManageHook
import qualified XMonad.StackSet as W
import Data.Bits ((.|.))
import Data.Default
import Data.Monoid
import qualified Data.Map as M
import System.Exit
import Graphics.X11.Xlib
import Graphics.X11.Xlib.Extras
-- | The default number of workspaces (virtual screens) and their names.
-- By default we use numeric strings, but any string may be used as a
-- workspace name. The number of workspaces is determined by the length
-- of this list.
--
-- A tagging example:
--
-- > workspaces = ["web", "irc", "code" ] ++ map show [4..9]
--
workspaces :: [WorkspaceId]
workspaces = map show [1 .. 9 :: Int]
-- | modMask lets you specify which modkey you want to use. The default
-- is mod1Mask ("left alt"). You may also consider using mod3Mask
-- ("right alt"), which does not conflict with emacs keybindings. The
-- "windows key" is usually mod4Mask.
--
defaultModMask :: KeyMask
defaultModMask = mod1Mask
-- | Width of the window border in pixels.
--
borderWidth :: Dimension
borderWidth = 1
-- | Border colors for unfocused and focused windows, respectively.
--
normalBorderColor, focusedBorderColor :: String
normalBorderColor = "gray" -- "#dddddd"
focusedBorderColor = "red" -- "#ff0000" don't use hex, not <24 bit safe
------------------------------------------------------------------------
-- Window rules
-- | Execute arbitrary actions and WindowSet manipulations when managing
-- a new window. You can use this to, for example, always float a
-- particular program, or have a client always appear on a particular
-- workspace.
--
-- To find the property name associated with a program, use
-- xprop | grep WM_CLASS
-- and click on the client you're interested in.
--
manageHook :: ManageHook
manageHook = composeAll
[ className =? "MPlayer" --> doFloat
, className =? "mplayer2" --> doFloat ]
------------------------------------------------------------------------
-- Logging
-- | Perform an arbitrary action on each internal state change or X event.
-- Examples include:
--
-- * do nothing
--
-- * log the state to stdout
--
-- See the 'DynamicLog' extension for examples.
--
logHook :: X ()
logHook = return ()
------------------------------------------------------------------------
-- Event handling
-- | Defines a custom handler function for X Events. The function should
-- return (All True) if the default handler is to be run afterwards.
-- To combine event hooks, use mappend or mconcat from Data.Monoid.
handleEventHook :: Event -> X All
handleEventHook _ = return (All True)
-- | Perform an arbitrary action at xmonad startup.
startupHook :: X ()
startupHook = return ()
------------------------------------------------------------------------
-- Extensible layouts
--
-- You can specify and transform your layouts by modifying these values.
-- If you change layout bindings be sure to use 'mod-shift-space' after
-- restarting (with 'mod-q') to reset your layout state to the new
-- defaults, as xmonad preserves your old layout settings by default.
--
-- | The available layouts. Note that each layout is separated by |||, which
-- denotes layout choice.
layout = tiled ||| Mirror tiled ||| Full
where
-- default tiling algorithm partitions the screen into two panes
tiled = Tall nmaster delta ratio
-- The default number of windows in the master pane
nmaster = 1
-- Default proportion of screen occupied by master pane
ratio = 1/2
-- Percent of screen to increment by when resizing panes
delta = 3/100
------------------------------------------------------------------------
-- Event Masks:
-- | The client events that xmonad is interested in
clientMask :: EventMask
clientMask = structureNotifyMask .|. enterWindowMask .|. propertyChangeMask
-- | The root events that xmonad is interested in
rootMask :: EventMask
rootMask = substructureRedirectMask .|. substructureNotifyMask
.|. enterWindowMask .|. leaveWindowMask .|. structureNotifyMask
.|. buttonPressMask
------------------------------------------------------------------------
-- Key bindings:
-- | The preferred terminal program, which is used in a binding below and by
-- certain contrib modules.
terminal :: String
terminal = "xterm"
-- | Whether focus follows the mouse pointer.
focusFollowsMouse :: Bool
focusFollowsMouse = True
-- | Whether a mouse click select the focus or is just passed to the window
clickJustFocuses :: Bool
clickJustFocuses = True
-- | The xmonad key bindings. Add, modify or remove key bindings here.
--
-- (The comment formatting character is used when generating the manpage)
--
keys :: XConfig Layout -> M.Map (KeyMask, KeySym) (X ())
keys conf@(XConfig {XMonad.modMask = modMask}) = M.fromList $
-- launching and killing programs
[ ((modMask .|. shiftMask, xK_Return), spawn $ XMonad.terminal conf) -- %! Launch terminal
, ((modMask, xK_p ), spawn "dmenu_run") -- %! Launch dmenu
, ((modMask .|. shiftMask, xK_p ), spawn "gmrun") -- %! Launch gmrun
, ((modMask .|. shiftMask, xK_c ), kill) -- %! Close the focused window
, ((modMask, xK_space ), sendMessage NextLayout) -- %! Rotate through the available layout algorithms
, ((modMask .|. shiftMask, xK_space ), setLayout $ XMonad.layoutHook conf) -- %! Reset the layouts on the current workspace to default
, ((modMask, xK_n ), refresh) -- %! Resize viewed windows to the correct size
-- move focus up or down the window stack
, ((modMask, xK_Tab ), windows W.focusDown) -- %! Move focus to the next window
, ((modMask .|. shiftMask, xK_Tab ), windows W.focusUp ) -- %! Move focus to the previous window
, ((modMask, xK_j ), windows W.focusDown) -- %! Move focus to the next window
, ((modMask, xK_k ), windows W.focusUp ) -- %! Move focus to the previous window
, ((modMask, xK_m ), windows W.focusMaster ) -- %! Move focus to the master window
-- modifying the window order
, ((modMask, xK_Return), 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
-- floating layer support
, ((modMask, xK_t ), withFocused $ windows . W.sink) -- %! Push window back into tiling
-- 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 xmonad
, ((modMask , xK_q ), spawn "if type xmonad; then xmonad --recompile && xmonad --restart; else xmessage xmonad not in \\$PATH: \"$PATH\"; fi") -- %! Restart xmonad
, ((modMask .|. shiftMask, xK_slash ), helpCommand)
-- repeat the binding for non-American layout keyboards
, ((modMask , xK_question), helpCommand)
]
++
-- mod-[1..9] %! Switch to workspace N
-- mod-shift-[1..9] %! Move client to workspace N
[((m .|. modMask, k), windows $ f i)
| (i, k) <- zip (XMonad.workspaces conf) [xK_1 .. xK_9]
, (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)]]
where
helpCommand :: X ()
helpCommand = spawn ("echo " ++ show help ++ " | xmessage -file -") -- %! Run xmessage with a summary of the default keybindings (useful for beginners)
-- | Mouse bindings: default actions bound to mouse events
mouseBindings :: XConfig Layout -> M.Map (KeyMask, Button) (Window -> X ())
mouseBindings (XConfig {XMonad.modMask = modMask}) = M.fromList
-- mod-button1 %! Set the window to floating mode and move by dragging
[ ((modMask, button1), \w -> focus w >> mouseMoveWindow w
>> windows W.shiftMaster)
-- mod-button2 %! Raise the window to the top of the stack
, ((modMask, button2), windows . (W.shiftMaster .) . W.focusWindow)
-- mod-button3 %! Set the window to floating mode and resize by dragging
, ((modMask, button3), \w -> focus w >> mouseResizeWindow w
>> windows W.shiftMaster)
-- you may also bind events to the mouse scroll wheel (button4 and button5)
]
instance (a ~ Choose Tall (Choose (Mirror Tall) Full)) => Default (XConfig a) where
def = XConfig
{ XMonad.borderWidth = borderWidth
, XMonad.workspaces = workspaces
, XMonad.layoutHook = layout
, XMonad.terminal = terminal
, XMonad.normalBorderColor = normalBorderColor
, XMonad.focusedBorderColor = focusedBorderColor
, XMonad.modMask = defaultModMask
, XMonad.keys = keys
, XMonad.logHook = logHook
, XMonad.startupHook = startupHook
, XMonad.mouseBindings = mouseBindings
, XMonad.manageHook = manageHook
, XMonad.handleEventHook = handleEventHook
, XMonad.focusFollowsMouse = focusFollowsMouse
, XMonad.clickJustFocuses = clickJustFocuses
, XMonad.clientMask = clientMask
, XMonad.rootMask = rootMask
, XMonad.handleExtraArgs = \ xs theConf -> case xs of
[] -> return theConf
_ -> fail ("unrecognized flags:" ++ show xs)
}
-- | The default set of configuration values itself
{-# DEPRECATED defaultConfig "Use def (from Data.Default, and re-exported by XMonad and XMonad.Config) instead." #-}
defaultConfig :: XConfig (Choose Tall (Choose (Mirror Tall) Full))
defaultConfig = def
-- | Finally, a copy of the default bindings in simple textual tabular format.
help :: String
help = unlines ["The default modifier key is 'alt'. Default keybindings:",
"",
"-- launching and killing programs",
"mod-Shift-Enter Launch xterminal",
"mod-p Launch dmenu",
"mod-Shift-p Launch gmrun",
"mod-Shift-c Close/kill the focused window",
"mod-Space Rotate through the available layout algorithms",
"mod-Shift-Space Reset the layouts on the current workSpace to default",
"mod-n Resize/refresh viewed windows to the correct size",
"",
"-- move focus up or down the window stack",
"mod-Tab Move focus to the next window",
"mod-Shift-Tab Move focus to the previous window",
"mod-j Move focus to the next window",
"mod-k Move focus to the previous window",
"mod-m Move focus to the master window",
"",
"-- modifying the window order",
"mod-Return Swap the focused window and the master window",
"mod-Shift-j Swap the focused window with the next window",
"mod-Shift-k Swap the focused window with the previous window",
"",
"-- resizing the master/slave ratio",
"mod-h Shrink the master area",
"mod-l Expand the master area",
"",
"-- floating layer support",
"mod-t Push window back into tiling; unfloat and re-tile it",
"",
"-- increase or decrease number of windows in the master area",
"mod-comma (mod-,) Increment the number of windows in the master area",
"mod-period (mod-.) Deincrement the number of windows in the master area",
"",
"-- quit, or restart",
"mod-Shift-q Quit xmonad",
"mod-q Restart xmonad",
"",
"-- Workspaces & screens",
"mod-[1..9] Switch to workSpace N",
"mod-Shift-[1..9] Move client to workspace N",
"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",
"",
"-- Mouse bindings: default actions bound to mouse events",
"mod-button1 Set the window to floating mode and move by dragging",
"mod-button2 Raise the window to the top of the stack",
"mod-button3 Set the window to floating mode and resize by dragging"]

693
src/XMonad/Core.hs Normal file
View File

@@ -0,0 +1,693 @@
{-# LANGUAGE ExistentialQuantification, FlexibleInstances, GeneralizedNewtypeDeriving,
MultiParamTypeClasses, TypeSynonymInstances, CPP, DeriveDataTypeable #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Core
-- Copyright : (c) Spencer Janssen 2007
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : spencerjanssen@gmail.com
-- Stability : unstable
-- Portability : not portable, uses cunning newtype deriving
--
-- The 'X' monad, a state monad transformer over 'IO', for the window
-- manager state, and support routines.
--
-----------------------------------------------------------------------------
module XMonad.Core (
X, WindowSet, WindowSpace, WorkspaceId,
ScreenId(..), ScreenDetail(..), XState(..),
XConf(..), XConfig(..), LayoutClass(..),
Layout(..), readsLayout, Typeable, Message,
SomeMessage(..), fromMessage, LayoutMessages(..),
StateExtension(..), ExtensionClass(..),
runX, catchX, userCode, userCodeDef, io, catchIO, installSignalHandlers, uninstallSignalHandlers,
withDisplay, withWindowSet, isRoot, runOnWorkspaces,
getAtom, spawn, spawnPID, xfork, recompile, trace, whenJust, whenX,
getXMonadDir, getXMonadCacheDir, getXMonadDataDir, stateFileName,
atom_WM_STATE, atom_WM_PROTOCOLS, atom_WM_DELETE_WINDOW, atom_WM_TAKE_FOCUS, withWindowAttributes,
ManageHook, Query(..), runQuery
) where
import XMonad.StackSet hiding (modify)
import Prelude
import Control.Exception.Extensible (fromException, try, bracket, throw, finally, SomeException(..))
import qualified Control.Exception.Extensible as E
import Control.Applicative
import Control.Monad.State
import Control.Monad.Reader
import Data.Semigroup
import Data.Default
import System.FilePath
import System.IO
import System.Info
import System.Posix.Env (getEnv)
import System.Posix.Process (executeFile, forkProcess, getAnyProcessStatus, createSession)
import System.Posix.Signals
import System.Posix.IO
import System.Posix.Types (ProcessID)
import System.Process
import System.Directory
import System.Exit
import Graphics.X11.Xlib
import Graphics.X11.Xlib.Extras (getWindowAttributes, WindowAttributes, Event)
import Data.Typeable
import Data.List ((\\))
import Data.Maybe (isJust,fromMaybe)
import Data.Monoid hiding ((<>))
import System.Environment (lookupEnv)
import qualified Data.Map as M
import qualified Data.Set as S
-- | XState, the (mutable) window manager state.
data XState = XState
{ windowset :: !WindowSet -- ^ workspace list
, mapped :: !(S.Set Window) -- ^ the Set of mapped windows
, waitingUnmap :: !(M.Map Window Int) -- ^ the number of expected UnmapEvents
, dragging :: !(Maybe (Position -> Position -> X (), X ()))
, numberlockMask :: !KeyMask -- ^ The numlock modifier
, extensibleState :: !(M.Map String (Either String StateExtension))
-- ^ stores custom state information.
--
-- The module "XMonad.Util.ExtensibleState" in xmonad-contrib
-- provides additional information and a simple interface for using this.
}
-- | XConf, the (read-only) window manager configuration.
data XConf = XConf
{ display :: Display -- ^ the X11 display
, config :: !(XConfig Layout) -- ^ initial user configuration
, theRoot :: !Window -- ^ the root window
, normalBorder :: !Pixel -- ^ border color of unfocused windows
, focusedBorder :: !Pixel -- ^ border color of the focused window
, keyActions :: !(M.Map (KeyMask, KeySym) (X ()))
-- ^ a mapping of key presses to actions
, buttonActions :: !(M.Map (KeyMask, Button) (Window -> X ()))
-- ^ a mapping of button presses to actions
, mouseFocused :: !Bool -- ^ was refocus caused by mouse action?
, mousePosition :: !(Maybe (Position, Position))
-- ^ position of the mouse according to
-- the event currently being processed
, currentEvent :: !(Maybe Event)
-- ^ event currently being processed
}
-- todo, better name
data XConfig l = XConfig
{ normalBorderColor :: !String -- ^ Non focused windows border color. Default: \"#dddddd\"
, focusedBorderColor :: !String -- ^ Focused windows border color. Default: \"#ff0000\"
, terminal :: !String -- ^ The preferred terminal application. Default: \"xterm\"
, layoutHook :: !(l Window) -- ^ The available layouts
, manageHook :: !ManageHook -- ^ The action to run when a new window is opened
, handleEventHook :: !(Event -> X All) -- ^ Handle an X event, returns (All True) if the default handler
-- should also be run afterwards. mappend should be used for combining
-- event hooks in most cases.
, workspaces :: ![String] -- ^ The list of workspaces' names
, modMask :: !KeyMask -- ^ the mod modifier
, keys :: !(XConfig Layout -> M.Map (ButtonMask,KeySym) (X ()))
-- ^ The key binding: a map from key presses and actions
, mouseBindings :: !(XConfig Layout -> M.Map (ButtonMask, Button) (Window -> X ()))
-- ^ The mouse bindings
, borderWidth :: !Dimension -- ^ The border width
, logHook :: !(X ()) -- ^ The action to perform when the windows set is changed
, startupHook :: !(X ()) -- ^ The action to perform on startup
, focusFollowsMouse :: !Bool -- ^ Whether window entry events can change focus
, clickJustFocuses :: !Bool -- ^ False to make a click which changes focus to be additionally passed to the window
, clientMask :: !EventMask -- ^ The client events that xmonad is interested in
, rootMask :: !EventMask -- ^ The root events that xmonad is interested in
, handleExtraArgs :: !([String] -> XConfig Layout -> IO (XConfig Layout))
-- ^ Modify the configuration, complain about extra arguments etc. with arguments that are not handled by default
}
type WindowSet = StackSet WorkspaceId (Layout Window) Window ScreenId ScreenDetail
type WindowSpace = Workspace WorkspaceId (Layout Window) Window
-- | Virtual workspace indices
type WorkspaceId = String
-- | Physical screen indices
newtype ScreenId = S Int deriving (Eq,Ord,Show,Read,Enum,Num,Integral,Real)
-- | The 'Rectangle' with screen dimensions
data ScreenDetail = SD { screenRect :: !Rectangle } deriving (Eq,Show, Read)
------------------------------------------------------------------------
-- | The X monad, 'ReaderT' and 'StateT' transformers over 'IO'
-- encapsulating the window manager configuration and state,
-- respectively.
--
-- Dynamic components may be retrieved with 'get', static components
-- with 'ask'. With newtype deriving we get readers and state monads
-- instantiated on 'XConf' and 'XState' automatically.
--
newtype X a = X (ReaderT XConf (StateT XState IO) a)
deriving (Functor, Monad, MonadIO, MonadState XState, MonadReader XConf, Typeable)
instance Applicative X where
pure = return
(<*>) = ap
instance Semigroup a => Semigroup (X a) where
(<>) = liftM2 (<>)
instance (Monoid a) => Monoid (X a) where
mempty = return mempty
mappend = liftM2 mappend
instance Default a => Default (X a) where
def = return def
type ManageHook = Query (Endo WindowSet)
newtype Query a = Query (ReaderT Window X a)
deriving (Functor, Applicative, Monad, MonadReader Window, MonadIO)
runQuery :: Query a -> Window -> X a
runQuery (Query m) w = runReaderT m w
instance Semigroup a => Semigroup (Query a) where
(<>) = liftM2 (<>)
instance Monoid a => Monoid (Query a) where
mempty = return mempty
mappend = liftM2 mappend
instance Default a => Default (Query a) where
def = return def
-- | Run the 'X' monad, given a chunk of 'X' monad code, and an initial state
-- Return the result, and final state
runX :: XConf -> XState -> X a -> IO (a, XState)
runX c st (X a) = runStateT (runReaderT a c) st
-- | Run in the 'X' monad, and in case of exception, and catch it and log it
-- to stderr, and run the error case.
catchX :: X a -> X a -> X a
catchX job errcase = do
st <- get
c <- ask
(a, s') <- io $ runX c st job `E.catch` \e -> case fromException e of
Just x -> throw e `const` (x `asTypeOf` ExitSuccess)
_ -> do hPrint stderr e; runX c st errcase
put s'
return a
-- | Execute the argument, catching all exceptions. Either this function or
-- 'catchX' should be used at all callsites of user customized code.
userCode :: X a -> X (Maybe a)
userCode a = catchX (Just `liftM` a) (return Nothing)
-- | Same as userCode but with a default argument to return instead of using
-- Maybe, provided for convenience.
userCodeDef :: a -> X a -> X a
userCodeDef defValue a = fromMaybe defValue `liftM` userCode a
-- ---------------------------------------------------------------------
-- Convenient wrappers to state
-- | Run a monad action with the current display settings
withDisplay :: (Display -> X a) -> X a
withDisplay f = asks display >>= f
-- | Run a monadic action with the current stack set
withWindowSet :: (WindowSet -> X a) -> X a
withWindowSet f = gets windowset >>= f
-- | Safely access window attributes.
withWindowAttributes :: Display -> Window -> (WindowAttributes -> X ()) -> X ()
withWindowAttributes dpy win f = do
wa <- userCode (io $ getWindowAttributes dpy win)
catchX (whenJust wa f) (return ())
-- | True if the given window is the root window
isRoot :: Window -> X Bool
isRoot w = (w==) <$> asks theRoot
-- | Wrapper for the common case of atom internment
getAtom :: String -> X Atom
getAtom str = withDisplay $ \dpy -> io $ internAtom dpy str False
-- | Common non-predefined atoms
atom_WM_PROTOCOLS, atom_WM_DELETE_WINDOW, atom_WM_STATE, atom_WM_TAKE_FOCUS :: X Atom
atom_WM_PROTOCOLS = getAtom "WM_PROTOCOLS"
atom_WM_DELETE_WINDOW = getAtom "WM_DELETE_WINDOW"
atom_WM_STATE = getAtom "WM_STATE"
atom_WM_TAKE_FOCUS = getAtom "WM_TAKE_FOCUS"
------------------------------------------------------------------------
-- LayoutClass handling. See particular instances in Operations.hs
-- | An existential type that can hold any object that is in 'Read'
-- and 'LayoutClass'.
data Layout a = forall l. (LayoutClass l a, Read (l a)) => Layout (l a)
-- | Using the 'Layout' as a witness, parse existentially wrapped windows
-- from a 'String'.
readsLayout :: Layout a -> String -> [(Layout a, String)]
readsLayout (Layout l) s = [(Layout (asTypeOf x l), rs) | (x, rs) <- reads s]
-- | Every layout must be an instance of 'LayoutClass', which defines
-- the basic layout operations along with a sensible default for each.
--
-- Minimal complete definition:
--
-- * 'runLayout' || (('doLayout' || 'pureLayout') && 'emptyLayout'), and
--
-- * 'handleMessage' || 'pureMessage'
--
-- You should also strongly consider implementing 'description',
-- although it is not required.
--
-- Note that any code which /uses/ 'LayoutClass' methods should only
-- ever call 'runLayout', 'handleMessage', and 'description'! In
-- other words, the only calls to 'doLayout', 'pureMessage', and other
-- such methods should be from the default implementations of
-- 'runLayout', 'handleMessage', and so on. This ensures that the
-- proper methods will be used, regardless of the particular methods
-- that any 'LayoutClass' instance chooses to define.
class Show (layout a) => LayoutClass layout a where
-- | By default, 'runLayout' calls 'doLayout' if there are any
-- windows to be laid out, and 'emptyLayout' otherwise. Most
-- instances of 'LayoutClass' probably do not need to implement
-- 'runLayout'; it is only useful for layouts which wish to make
-- use of more of the 'Workspace' information (for example,
-- "XMonad.Layout.PerWorkspace").
runLayout :: Workspace WorkspaceId (layout a) a
-> Rectangle
-> X ([(a, Rectangle)], Maybe (layout a))
runLayout (Workspace _ l ms) r = maybe (emptyLayout l r) (doLayout l r) ms
-- | Given a 'Rectangle' in which to place the windows, and a 'Stack'
-- of windows, return a list of windows and their corresponding
-- Rectangles. If an element is not given a Rectangle by
-- 'doLayout', then it is not shown on screen. The order of
-- windows in this list should be the desired stacking order.
--
-- Also possibly return a modified layout (by returning @Just
-- newLayout@), if this layout needs to be modified (e.g. if it
-- keeps track of some sort of state). Return @Nothing@ if the
-- layout does not need to be modified.
--
-- Layouts which do not need access to the 'X' monad ('IO', window
-- manager state, or configuration) and do not keep track of their
-- own state should implement 'pureLayout' instead of 'doLayout'.
doLayout :: layout a -> Rectangle -> Stack a
-> X ([(a, Rectangle)], Maybe (layout a))
doLayout l r s = return (pureLayout l r s, Nothing)
-- | This is a pure version of 'doLayout', for cases where we
-- don't need access to the 'X' monad to determine how to lay out
-- the windows, and we don't need to modify the layout itself.
pureLayout :: layout a -> Rectangle -> Stack a -> [(a, Rectangle)]
pureLayout _ r s = [(focus s, r)]
-- | 'emptyLayout' is called when there are no windows.
emptyLayout :: layout a -> Rectangle -> X ([(a, Rectangle)], Maybe (layout a))
emptyLayout _ _ = return ([], Nothing)
-- | 'handleMessage' performs message handling. If
-- 'handleMessage' returns @Nothing@, then the layout did not
-- respond to the message and the screen is not refreshed.
-- Otherwise, 'handleMessage' returns an updated layout and the
-- screen is refreshed.
--
-- Layouts which do not need access to the 'X' monad to decide how
-- to handle messages should implement 'pureMessage' instead of
-- 'handleMessage' (this restricts the risk of error, and makes
-- testing much easier).
handleMessage :: layout a -> SomeMessage -> X (Maybe (layout a))
handleMessage l = return . pureMessage l
-- | Respond to a message by (possibly) changing our layout, but
-- taking no other action. If the layout changes, the screen will
-- be refreshed.
pureMessage :: layout a -> SomeMessage -> Maybe (layout a)
pureMessage _ _ = Nothing
-- | This should be a human-readable string that is used when
-- selecting layouts by name. The default implementation is
-- 'show', which is in some cases a poor default.
description :: layout a -> String
description = show
instance LayoutClass Layout Window where
runLayout (Workspace i (Layout l) ms) r = fmap (fmap Layout) `fmap` runLayout (Workspace i l ms) r
doLayout (Layout l) r s = fmap (fmap Layout) `fmap` doLayout l r s
emptyLayout (Layout l) r = fmap (fmap Layout) `fmap` emptyLayout l r
handleMessage (Layout l) = fmap (fmap Layout) . handleMessage l
description (Layout l) = description l
instance Show (Layout a) where show (Layout l) = show l
-- | Based on ideas in /An Extensible Dynamically-Typed Hierarchy of
-- Exceptions/, Simon Marlow, 2006. Use extensible messages to the
-- 'handleMessage' handler.
--
-- User-extensible messages must be a member of this class.
--
class Typeable a => Message a
-- |
-- A wrapped value of some type in the 'Message' class.
--
data SomeMessage = forall a. Message a => SomeMessage a
-- |
-- And now, unwrap a given, unknown 'Message' type, performing a (dynamic)
-- type check on the result.
--
fromMessage :: Message m => SomeMessage -> Maybe m
fromMessage (SomeMessage m) = cast m
-- X Events are valid Messages.
instance Message Event
-- | 'LayoutMessages' are core messages that all layouts (especially stateful
-- layouts) should consider handling.
data LayoutMessages = Hide -- ^ sent when a layout becomes non-visible
| ReleaseResources -- ^ sent when xmonad is exiting or restarting
deriving (Typeable, Eq)
instance Message LayoutMessages
-- ---------------------------------------------------------------------
-- Extensible state
--
-- | Every module must make the data it wants to store
-- an instance of this class.
--
-- Minimal complete definition: initialValue
class Typeable a => ExtensionClass a where
-- | Defines an initial value for the state extension
initialValue :: a
-- | Specifies whether the state extension should be
-- persistent. Setting this method to 'PersistentExtension'
-- will make the stored data survive restarts, but
-- requires a to be an instance of Read and Show.
--
-- It defaults to 'StateExtension', i.e. no persistence.
extensionType :: a -> StateExtension
extensionType = StateExtension
-- | Existential type to store a state extension.
data StateExtension =
forall a. ExtensionClass a => StateExtension a
-- ^ Non-persistent state extension
| forall a. (Read a, Show a, ExtensionClass a) => PersistentExtension a
-- ^ Persistent extension
-- ---------------------------------------------------------------------
-- | General utilities
--
-- Lift an 'IO' action into the 'X' monad
io :: MonadIO m => IO a -> m a
io = liftIO
-- | Lift an 'IO' action into the 'X' monad. If the action results in an 'IO'
-- exception, log the exception to stderr and continue normal execution.
catchIO :: MonadIO m => IO () -> m ()
catchIO f = io (f `E.catch` \(SomeException e) -> hPrint stderr e >> hFlush stderr)
-- | spawn. Launch an external application. Specifically, it double-forks and
-- runs the 'String' you pass as a command to \/bin\/sh.
--
-- Note this function assumes your locale uses utf8.
spawn :: MonadIO m => String -> m ()
spawn x = spawnPID x >> return ()
-- | Like 'spawn', but returns the 'ProcessID' of the launched application
spawnPID :: MonadIO m => String -> m ProcessID
spawnPID x = xfork $ executeFile "/bin/sh" False ["-c", x] Nothing
-- | A replacement for 'forkProcess' which resets default signal handlers.
xfork :: MonadIO m => IO () -> m ProcessID
xfork x = io . forkProcess . finally nullStdin $ do
uninstallSignalHandlers
createSession
x
where
nullStdin = do
fd <- openFd "/dev/null" ReadOnly Nothing defaultFileFlags
dupTo fd stdInput
closeFd fd
-- | This is basically a map function, running a function in the 'X' monad on
-- each workspace with the output of that function being the modified workspace.
runOnWorkspaces :: (WindowSpace -> X WindowSpace) -> X ()
runOnWorkspaces job = do
ws <- gets windowset
h <- mapM job $ hidden ws
c:v <- mapM (\s -> (\w -> s { workspace = w}) <$> job (workspace s))
$ current ws : visible ws
modify $ \s -> s { windowset = ws { current = c, visible = v, hidden = h } }
-- | Return the path to the xmonad configuration directory. This
-- directory is where user configuration files are stored (e.g, the
-- xmonad.hs file). You may also create a @lib@ subdirectory in the
-- configuration directory and the default recompile command will add
-- it to the GHC include path.
--
-- Several directories are considered. In order of
-- preference:
--
-- 1. The directory specified in the @XMONAD_CONFIG_DIR@ environment variable.
-- 2. The @~\/.xmonad@ directory.
-- 3. The @XDG_CONFIG_HOME/xmonad@ directory.
--
-- The first directory that exists will be used. If none of the
-- directories exist then (1) will be used if it is set, otherwise (2)
-- will be used. Either way, a directory will be created if necessary.
getXMonadDir :: MonadIO m => m String
getXMonadDir =
findFirstDirWithEnv "XMONAD_CONFIG_DIR"
[ getAppUserDataDirectory "xmonad"
, getXDGDirectory XDGConfig "xmonad"
]
-- | Return the path to the xmonad cache directory. This directory is
-- used to store temporary files that can easily be recreated. For
-- example, the XPrompt history file.
--
-- Several directories are considered. In order of preference:
--
-- 1. The directory specified in the @XMONAD_CACHE_DIR@ environment variable.
-- 2. The @~\/.xmonad@ directory.
-- 3. The @XDG_CACHE_HOME/xmonad@ directory.
--
-- The first directory that exists will be used. If none of the
-- directories exist then (1) will be used if it is set, otherwise (2)
-- will be used. Either way, a directory will be created if necessary.
getXMonadCacheDir :: MonadIO m => m String
getXMonadCacheDir =
findFirstDirWithEnv "XMONAD_CACHE_DIR"
[ getAppUserDataDirectory "xmonad"
, getXDGDirectory XDGCache "xmonad"
]
-- | Return the path to the xmonad data directory. This directory is
-- used by XMonad to store data files such as the run-time state file
-- and the configuration binary generated by GHC.
--
-- Several directories are considered. In order of preference:
--
-- 1. The directory specified in the @XMONAD_DATA_DIR@ environment variable.
-- 2. The @~\/.xmonad@ directory.
-- 3. The @XDG_DATA_HOME/xmonad@ directory.
--
-- The first directory that exists will be used. If none of the
-- directories exist then (1) will be used if it is set, otherwise (2)
-- will be used. Either way, a directory will be created if necessary.
getXMonadDataDir :: MonadIO m => m String
getXMonadDataDir =
findFirstDirWithEnv "XMONAD_DATA_DIR"
[ getAppUserDataDirectory "xmonad"
, getXDGDirectory XDGData "xmonad"
]
-- | Helper function that will find the first existing directory and
-- return its path. If none of the directories can be found, create
-- and return the first from the list. If the list is empty this
-- function returns the historical @~\/.xmonad@ directory.
findFirstDirOf :: MonadIO m => [IO FilePath] -> m FilePath
findFirstDirOf [] = findFirstDirOf [getAppUserDataDirectory "xmonad"]
findFirstDirOf possibles = do
found <- go possibles
case found of
Just path -> return path
Nothing -> do
primary <- io (head possibles)
io (createDirectoryIfMissing True primary)
return primary
where
go [] = return Nothing
go (x:xs) = do
dir <- io x
exists <- io (doesDirectoryExist dir)
if exists then return (Just dir) else go xs
-- | Simple wrapper around @findFirstDirOf@ that allows the primary
-- path to be specified by an environment variable.
findFirstDirWithEnv :: MonadIO m => String -> [IO FilePath] -> m FilePath
findFirstDirWithEnv envName paths = do
envPath' <- io (getEnv envName)
case envPath' of
Nothing -> findFirstDirOf paths
Just envPath -> findFirstDirOf (return envPath:paths)
-- | Helper function to retrieve the various XDG directories.
-- This has been based on the implementation shipped with GHC version 8.0.1 or
-- higher. Put here to preserve compatibility with older GHC versions.
getXDGDirectory :: XDGDirectory -> FilePath -> IO FilePath
getXDGDirectory xdgDir suffix =
normalise . (</> suffix) <$>
case xdgDir of
XDGData -> get "XDG_DATA_HOME" ".local/share"
XDGConfig -> get "XDG_CONFIG_HOME" ".config"
XDGCache -> get "XDG_CACHE_HOME" ".cache"
where
get name fallback = do
env <- lookupEnv name
case env of
Nothing -> fallback'
Just path
| isRelative path -> fallback'
| otherwise -> return path
where
fallback' = (</> fallback) <$> getHomeDirectory
data XDGDirectory = XDGData | XDGConfig | XDGCache
-- | Get the name of the file used to store the xmonad window state.
stateFileName :: (Functor m, MonadIO m) => m FilePath
stateFileName = (</> "xmonad.state") <$> getXMonadDataDir
-- | 'recompile force', recompile the xmonad configuration file when
-- any of the following apply:
--
-- * force is 'True'
--
-- * the xmonad executable does not exist
--
-- * the xmonad executable is older than xmonad.hs or any file in
-- the @lib@ directory (under the configuration directory).
--
-- The -i flag is used to restrict recompilation to the xmonad.hs file only,
-- and any files in the aforementioned @lib@ directory.
--
-- Compilation errors (if any) are logged to the @xmonad.errors@ file
-- in the xmonad data directory. If GHC indicates failure with a
-- non-zero exit code, an xmessage displaying that file is spawned.
--
-- 'False' is returned if there are compilation errors.
--
recompile :: MonadIO m => Bool -> m Bool
recompile force = io $ do
cfgdir <- getXMonadDir
datadir <- getXMonadDataDir
let binn = "xmonad-"++arch++"-"++os
bin = datadir </> binn
err = datadir </> "xmonad.errors"
src = cfgdir </> "xmonad.hs"
lib = cfgdir </> "lib"
buildscript = cfgdir </> "build"
libTs <- mapM getModTime . Prelude.filter isSource =<< allFiles lib
srcT <- getModTime src
binT <- getModTime bin
useBuildscript <- do
exists <- doesFileExist buildscript
if exists then isExecutable buildscript else return False
if force || useBuildscript || any (binT <) (srcT : libTs)
then do
-- temporarily disable SIGCHLD ignoring:
uninstallSignalHandlers
status <- bracket (openFile err WriteMode) hClose $ \errHandle ->
waitForProcess =<< if useBuildscript
then compileScript bin cfgdir buildscript errHandle
else compileGHC bin cfgdir errHandle
-- re-enable SIGCHLD:
installSignalHandlers
-- now, if it fails, run xmessage to let the user know:
when (status /= ExitSuccess) $ do
ghcErr <- readFile err
let msg = unlines $
["Error detected while loading xmonad configuration file: " ++ src]
++ lines (if null ghcErr then show status else ghcErr)
++ ["","Please check the file for errors."]
-- nb, the ordering of printing, then forking, is crucial due to
-- lazy evaluation
hPutStrLn stderr msg
forkProcess $ executeFile "xmessage" True ["-default", "okay", replaceUnicode msg] Nothing
return ()
return (status == ExitSuccess)
else return True
where getModTime f = E.catch (Just <$> getModificationTime f) (\(SomeException _) -> return Nothing)
isSource = flip elem [".hs",".lhs",".hsc"] . takeExtension
isExecutable f = E.catch (executable <$> getPermissions f) (\(SomeException _) -> return False)
allFiles t = do
let prep = map (t</>) . Prelude.filter (`notElem` [".",".."])
cs <- prep <$> E.catch (getDirectoryContents t) (\(SomeException _) -> return [])
ds <- filterM doesDirectoryExist cs
concat . ((cs \\ ds):) <$> mapM allFiles ds
-- Replace some of the unicode symbols GHC uses in its output
replaceUnicode = map $ \c -> case c of
'\8226' -> '*' --
'\8216' -> '`' --
'\8217' -> '`' --
_ -> c
compileGHC bin dir errHandle =
runProcess "ghc" ["--make"
, "xmonad.hs"
, "-i"
, "-ilib"
, "-fforce-recomp"
, "-main-is", "main"
, "-v0"
, "-o", bin
] (Just dir) Nothing Nothing Nothing (Just errHandle)
compileScript bin dir script errHandle =
runProcess script [bin] (Just dir) Nothing Nothing Nothing (Just errHandle)
-- | Conditionally run an action, using a @Maybe a@ to decide.
whenJust :: Monad m => Maybe a -> (a -> m ()) -> m ()
whenJust mg f = maybe (return ()) f mg
-- | Conditionally run an action, using a 'X' event to decide
whenX :: X Bool -> X () -> X ()
whenX a f = a >>= \b -> when b f
-- | A 'trace' for the 'X' monad. Logs a string to stderr. The result may
-- be found in your .xsession-errors file
trace :: MonadIO m => String -> m ()
trace = io . hPutStrLn stderr
-- | Ignore SIGPIPE to avoid termination when a pipe is full, and SIGCHLD to
-- avoid zombie processes, and clean up any extant zombie processes.
installSignalHandlers :: MonadIO m => m ()
installSignalHandlers = io $ do
installHandler openEndedPipe Ignore Nothing
installHandler sigCHLD Ignore Nothing
(try :: IO a -> IO (Either SomeException a))
$ fix $ \more -> do
x <- getAnyProcessStatus False False
when (isJust x) more
return ()
uninstallSignalHandlers :: MonadIO m => m ()
uninstallSignalHandlers = io $ do
installHandler openEndedPipe Default Nothing
installHandler sigCHLD Default Nothing
return ()

210
src/XMonad/Layout.hs Normal file
View File

@@ -0,0 +1,210 @@
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, PatternGuards, TypeSynonymInstances, DeriveDataTypeable #-}
-- --------------------------------------------------------------------------
-- |
-- Module : XMonad.Layout
-- Copyright : (c) Spencer Janssen 2007
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : spencerjanssen@gmail.com
-- Stability : unstable
-- Portability : not portable, Typeable deriving, mtl, posix
--
-- The collection of core layouts.
--
-----------------------------------------------------------------------------
module XMonad.Layout (
Full(..), Tall(..), Mirror(..),
Resize(..), IncMasterN(..), Choose, (|||), ChangeLayout(..),
mirrorRect, splitVertically,
splitHorizontally, splitHorizontallyBy, splitVerticallyBy,
tile
) where
import XMonad.Core
import Graphics.X11 (Rectangle(..))
import qualified XMonad.StackSet as W
import Control.Arrow ((***), second)
import Control.Monad
import Data.Maybe (fromMaybe)
------------------------------------------------------------------------
-- | Change the size of the master pane.
data Resize = Shrink | Expand deriving Typeable
-- | Increase the number of clients in the master pane.
data IncMasterN = IncMasterN !Int deriving Typeable
instance Message Resize
instance Message IncMasterN
-- | Simple fullscreen mode. Renders the focused window fullscreen.
data Full a = Full deriving (Show, Read)
instance LayoutClass Full a
-- | The builtin tiling mode of xmonad. Supports 'Shrink', 'Expand' and
-- 'IncMasterN'.
data Tall a = Tall { tallNMaster :: !Int -- ^ The default number of windows in the master pane (default: 1)
, tallRatioIncrement :: !Rational -- ^ Percent of screen to increment by when resizing panes (default: 3/100)
, tallRatio :: !Rational -- ^ Default proportion of screen occupied by master pane (default: 1/2)
}
deriving (Show, Read)
-- TODO should be capped [0..1] ..
-- a nice pure layout, lots of properties for the layout, and its messages, in Properties.hs
instance LayoutClass Tall a where
pureLayout (Tall nmaster _ frac) r s = zip ws rs
where ws = W.integrate s
rs = tile frac r nmaster (length ws)
pureMessage (Tall nmaster delta frac) m =
msum [fmap resize (fromMessage m)
,fmap incmastern (fromMessage m)]
where resize Shrink = Tall nmaster delta (max 0 $ frac-delta)
resize Expand = Tall nmaster delta (min 1 $ frac+delta)
incmastern (IncMasterN d) = Tall (max 0 (nmaster+d)) delta frac
description _ = "Tall"
-- | Compute the positions for windows using the default two-pane tiling
-- algorithm.
--
-- The screen is divided into two panes. All clients are
-- then partioned between these two panes. One pane, the master, by
-- convention has the least number of windows in it.
tile
:: Rational -- ^ @frac@, what proportion of the screen to devote to the master area
-> Rectangle -- ^ @r@, the rectangle representing the screen
-> Int -- ^ @nmaster@, the number of windows in the master pane
-> Int -- ^ @n@, the total number of windows to tile
-> [Rectangle]
tile f r nmaster n = if n <= nmaster || nmaster == 0
then splitVertically n r
else splitVertically nmaster r1 ++ splitVertically (n-nmaster) r2 -- two columns
where (r1,r2) = splitHorizontallyBy f r
--
-- Divide the screen vertically into n subrectangles
--
splitVertically, splitHorizontally :: Int -> Rectangle -> [Rectangle]
splitVertically n r | n < 2 = [r]
splitVertically n (Rectangle sx sy sw sh) = Rectangle sx sy sw smallh :
splitVertically (n-1) (Rectangle sx (sy+fromIntegral smallh) sw (sh-smallh))
where smallh = sh `div` fromIntegral n --hmm, this is a fold or map.
-- Not used in the core, but exported
splitHorizontally n = map mirrorRect . splitVertically n . mirrorRect
-- Divide the screen into two rectangles, using a rational to specify the ratio
splitHorizontallyBy, splitVerticallyBy :: RealFrac r => r -> Rectangle -> (Rectangle, Rectangle)
splitHorizontallyBy f (Rectangle sx sy sw sh) =
( Rectangle sx sy leftw sh
, Rectangle (sx + fromIntegral leftw) sy (sw-fromIntegral leftw) sh)
where leftw = floor $ fromIntegral sw * f
-- Not used in the core, but exported
splitVerticallyBy f = (mirrorRect *** mirrorRect) . splitHorizontallyBy f . mirrorRect
------------------------------------------------------------------------
-- | Mirror a layout, compute its 90 degree rotated form.
newtype Mirror l a = Mirror (l a) deriving (Show, Read)
instance LayoutClass l a => LayoutClass (Mirror l) a where
runLayout (W.Workspace i (Mirror l) ms) r = (map (second mirrorRect) *** fmap Mirror)
`fmap` runLayout (W.Workspace i l ms) (mirrorRect r)
handleMessage (Mirror l) = fmap (fmap Mirror) . handleMessage l
description (Mirror l) = "Mirror "++ description l
-- | Mirror a rectangle.
mirrorRect :: Rectangle -> Rectangle
mirrorRect (Rectangle rx ry rw rh) = Rectangle ry rx rh rw
------------------------------------------------------------------------
-- LayoutClass selection manager
-- Layouts that transition between other layouts
-- | Messages to change the current layout.
data ChangeLayout = FirstLayout | NextLayout deriving (Eq, Show, Typeable)
instance Message ChangeLayout
-- | The layout choice combinator
(|||) :: l a -> r a -> Choose l r a
(|||) = Choose L
infixr 5 |||
-- | A layout that allows users to switch between various layout options.
data Choose l r a = Choose LR (l a) (r a) deriving (Read, Show)
-- | Are we on the left or right sub-layout?
data LR = L | R deriving (Read, Show, Eq)
data NextNoWrap = NextNoWrap deriving (Eq, Show, Typeable)
instance Message NextNoWrap
-- | A small wrapper around handleMessage, as it is tedious to write
-- SomeMessage repeatedly.
handle :: (LayoutClass l a, Message m) => l a -> m -> X (Maybe (l a))
handle l m = handleMessage l (SomeMessage m)
-- | A smart constructor that takes some potential modifications, returns a
-- new structure if any fields have changed, and performs any necessary cleanup
-- on newly non-visible layouts.
choose :: (LayoutClass l a, LayoutClass r a)
=> Choose l r a-> LR -> Maybe (l a) -> Maybe (r a) -> X (Maybe (Choose l r a))
choose (Choose d _ _) d' Nothing Nothing | d == d' = return Nothing
choose (Choose d l r) d' ml mr = f lr
where
(l', r') = (fromMaybe l ml, fromMaybe r mr)
lr = case (d, d') of
(L, R) -> (hide l' , return r')
(R, L) -> (return l', hide r' )
(_, _) -> (return l', return r')
f (x,y) = fmap Just $ liftM2 (Choose d') x y
hide x = fmap (fromMaybe x) $ handle x Hide
instance (LayoutClass l a, LayoutClass r a) => LayoutClass (Choose l r) a where
runLayout (W.Workspace i (Choose L l r) ms) =
fmap (second . fmap $ flip (Choose L) r) . runLayout (W.Workspace i l ms)
runLayout (W.Workspace i (Choose R l r) ms) =
fmap (second . fmap $ Choose R l) . runLayout (W.Workspace i r ms)
description (Choose L l _) = description l
description (Choose R _ r) = description r
handleMessage lr m | Just NextLayout <- fromMessage m = do
mlr' <- handle lr NextNoWrap
maybe (handle lr FirstLayout) (return . Just) mlr'
handleMessage c@(Choose d l r) m | Just NextNoWrap <- fromMessage m =
case d of
L -> do
ml <- handle l NextNoWrap
case ml of
Just _ -> choose c L ml Nothing
Nothing -> choose c R Nothing =<< handle r FirstLayout
R -> choose c R Nothing =<< handle r NextNoWrap
handleMessage c@(Choose _ l _) m | Just FirstLayout <- fromMessage m =
flip (choose c L) Nothing =<< handle l FirstLayout
handleMessage c@(Choose d l r) m | Just ReleaseResources <- fromMessage m =
join $ liftM2 (choose c d) (handle l ReleaseResources) (handle r ReleaseResources)
handleMessage c@(Choose d l r) m = do
ml' <- case d of
L -> handleMessage l m
R -> return Nothing
mr' <- case d of
L -> return Nothing
R -> handleMessage r m
choose c d ml' mr'

518
src/XMonad/Main.hs Normal file
View File

@@ -0,0 +1,518 @@
{-# LANGUAGE MultiParamTypeClasses, FlexibleContexts #-}
----------------------------------------------------------------------------
-- |
-- Module : XMonad.Main
-- Copyright : (c) Spencer Janssen 2007
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : spencerjanssen@gmail.com
-- Stability : unstable
-- Portability : not portable, uses mtl, X11, posix
--
-- xmonad, a minimalist, tiling window manager for X11
--
-----------------------------------------------------------------------------
module XMonad.Main (xmonad, launch) where
import System.Locale.SetLocale
import qualified Control.Exception.Extensible as E
import Data.Bits
import Data.List ((\\))
import Data.Function
import qualified Data.Map as M
import qualified Data.Set as S
import Control.Monad.Reader
import Control.Monad.State
import Data.Maybe (fromMaybe)
import Data.Monoid (getAll)
import Graphics.X11.Xlib hiding (refreshKeyboardMapping)
import Graphics.X11.Xlib.Extras
import XMonad.Core
import qualified XMonad.Config as Default
import XMonad.StackSet (new, floating, member)
import qualified XMonad.StackSet as W
import XMonad.Operations
import System.IO
import System.Directory
import System.Info
import System.Environment
import System.Posix.Process (executeFile)
import System.Exit (exitFailure)
import System.FilePath
import Paths_xmonad (version)
import Data.Version (showVersion)
import Graphics.X11.Xinerama (compiledWithXinerama)
------------------------------------------------------------------------
-- |
-- | The entry point into xmonad. Attempts to compile any custom main
-- for xmonad, and if it doesn't find one, just launches the default.
xmonad :: (LayoutClass l Window, Read (l Window)) => XConfig l -> IO ()
xmonad conf = do
installSignalHandlers -- important to ignore SIGCHLD to avoid zombies
let launch' args = do
catchIO buildLaunch
conf' @ XConfig { layoutHook = Layout l }
<- handleExtraArgs conf args conf{ layoutHook = Layout (layoutHook conf) }
withArgs [] $ launch (conf' { layoutHook = l })
args <- getArgs
case args of
("--resume": ws : xs : args') -> migrateState ws xs >> launch' args'
["--help"] -> usage
["--recompile"] -> recompile True >>= flip unless exitFailure
["--restart"] -> sendRestart
["--version"] -> putStrLn $ unwords shortVersion
["--verbose-version"] -> putStrLn . unwords $ shortVersion ++ longVersion
"--replace" : args' -> sendReplace >> launch' args'
_ -> launch' args
where
shortVersion = ["xmonad", showVersion version]
longVersion = [ "compiled by", compilerName, showVersion compilerVersion
, "for", arch ++ "-" ++ os
, "\nXinerama:", show compiledWithXinerama ]
usage :: IO ()
usage = do
self <- getProgName
putStr . unlines $
concat ["Usage: ", self, " [OPTION]"] :
"Options:" :
" --help Print this message" :
" --version Print the version number" :
" --recompile Recompile your ~/.xmonad/xmonad.hs" :
" --replace Replace the running window manager with xmonad" :
" --restart Request a running xmonad process to restart" :
[]
-- | Build the xmonad configuration file with ghc, then execute it.
-- If there are no errors, this function does not return. An
-- exception is raised in any of these cases:
--
-- * ghc missing
--
-- * both the configuration file and executable are missing
--
-- * xmonad.hs fails to compile
--
-- ** wrong ghc in path (fails to compile)
--
-- ** type error, syntax error, ..
--
-- * Missing XMonad\/XMonadContrib modules due to ghc upgrade
--
buildLaunch :: IO ()
buildLaunch = do
recompile False
dir <- getXMonadDataDir
args <- getArgs
whoami <- getProgName
let compiledConfig = "xmonad-"++arch++"-"++os
unless (whoami == compiledConfig) $
executeFile (dir </> compiledConfig) False args Nothing
sendRestart :: IO ()
sendRestart = do
dpy <- openDisplay ""
rw <- rootWindow dpy $ defaultScreen dpy
xmonad_restart <- internAtom dpy "XMONAD_RESTART" False
allocaXEvent $ \e -> do
setEventType e clientMessage
setClientMessageEvent e rw xmonad_restart 32 0 currentTime
sendEvent dpy rw False structureNotifyMask e
sync dpy False
-- | a wrapper for 'replace'
sendReplace :: IO ()
sendReplace = do
dpy <- openDisplay ""
let dflt = defaultScreen dpy
rootw <- rootWindow dpy dflt
replace dpy dflt rootw
-- | Entry point into xmonad for custom builds.
--
-- This function isn't meant to be called by the typical xmonad user
-- because it:
--
-- * Does not process any command line arguments.
--
-- * Therefore doesn't know how to restart a running xmonad.
--
-- * Does not compile your configuration file since it assumes it's
-- actually running from within your compiled configuration.
--
-- Unless you know what you are doing, you should probably be using
-- the 'xmonad' function instead.
--
-- However, if you are using a custom build environment (such as
-- stack, cabal, make, etc.) you will likely want to call this
-- function instead of 'xmonad'. You probably also want to have a key
-- binding to the 'XMonad.Operations.restart` function that restarts
-- your custom binary with the resume flag set to @True@.
launch :: (LayoutClass l Window, Read (l Window)) => XConfig l -> IO ()
launch initxmc = do
-- setup locale information from environment
setLocale LC_ALL (Just "")
-- ignore SIGPIPE and SIGCHLD
installSignalHandlers
-- First, wrap the layout in an existential, to keep things pretty:
let xmc = initxmc { layoutHook = Layout $ layoutHook initxmc }
dpy <- openDisplay ""
let dflt = defaultScreen dpy
rootw <- rootWindow dpy dflt
-- If another WM is running, a BadAccess error will be returned. The
-- default error handler will write the exception to stderr and exit with
-- an error.
selectInput dpy rootw $ rootMask initxmc
sync dpy False -- sync to ensure all outstanding errors are delivered
-- turn off the default handler in favor of one that ignores all errors
-- (ugly, I know)
xSetErrorHandler -- in C, I'm too lazy to write the binding: dons
xinesc <- getCleanedScreenInfo dpy
nbc <- do v <- initColor dpy $ normalBorderColor xmc
~(Just nbc_) <- initColor dpy $ normalBorderColor Default.def
return (fromMaybe nbc_ v)
fbc <- do v <- initColor dpy $ focusedBorderColor xmc
~(Just fbc_) <- initColor dpy $ focusedBorderColor Default.def
return (fromMaybe fbc_ v)
hSetBuffering stdout NoBuffering
let layout = layoutHook xmc
lreads = readsLayout layout
initialWinset = let padToLen n xs = take (max n (length xs)) $ xs ++ repeat ""
in new layout (padToLen (length xinesc) (workspaces xmc)) $ map SD xinesc
cf = XConf
{ display = dpy
, config = xmc
, theRoot = rootw
, normalBorder = nbc
, focusedBorder = fbc
, keyActions = keys xmc xmc
, buttonActions = mouseBindings xmc xmc
, mouseFocused = False
, mousePosition = Nothing
, currentEvent = Nothing }
st = XState
{ windowset = initialWinset
, numberlockMask = 0
, mapped = S.empty
, waitingUnmap = M.empty
, dragging = Nothing
, extensibleState = M.empty
}
allocaXEvent $ \e ->
runX cf st $ do
-- check for serialized state in a file.
serializedSt <- do
path <- stateFileName
exists <- io (doesFileExist path)
if exists then readStateFile initxmc else return Nothing
-- restore extensibleState if we read it from a file.
let extst = maybe M.empty extensibleState serializedSt
modify (\s -> s {extensibleState = extst})
setNumlockMask
grabKeys
grabButtons
io $ sync dpy False
ws <- io $ scan dpy rootw
-- bootstrap the windowset, Operations.windows will identify all
-- the windows in winset as new and set initial properties for
-- those windows. Remove all windows that are no longer top-level
-- children of the root, they may have disappeared since
-- restarting.
let winset = maybe initialWinset windowset serializedSt
windows . const . foldr W.delete winset $ W.allWindows winset \\ ws
-- manage the as-yet-unmanaged windows
mapM_ manage (ws \\ W.allWindows winset)
userCode $ startupHook initxmc
-- main loop, for all you HOF/recursion fans out there.
forever $ prehandle =<< io (nextEvent dpy e >> getEvent e)
return ()
where
-- if the event gives us the position of the pointer, set mousePosition
prehandle e = let mouse = do guard (ev_event_type e `elem` evs)
return (fromIntegral (ev_x_root e)
,fromIntegral (ev_y_root e))
in local (\c -> c { mousePosition = mouse, currentEvent = Just e }) (handleWithHook e)
evs = [ keyPress, keyRelease, enterNotify, leaveNotify
, buttonPress, buttonRelease]
-- | Runs handleEventHook from the configuration and runs the default handler
-- function if it returned True.
handleWithHook :: Event -> X ()
handleWithHook e = do
evHook <- asks (handleEventHook . config)
whenX (userCodeDef True $ getAll `fmap` evHook e) (handle e)
-- ---------------------------------------------------------------------
-- | Event handler. Map X events onto calls into Operations.hs, which
-- modify our internal model of the window manager state.
--
-- Events dwm handles that we don't:
--
-- [ButtonPress] = buttonpress,
-- [Expose] = expose,
-- [PropertyNotify] = propertynotify,
--
handle :: Event -> X ()
-- run window manager command
handle (KeyEvent {ev_event_type = t, ev_state = m, ev_keycode = code})
| t == keyPress = withDisplay $ \dpy -> do
s <- io $ keycodeToKeysym dpy code 0
mClean <- cleanMask m
ks <- asks keyActions
userCodeDef () $ whenJust (M.lookup (mClean, s) ks) id
-- manage a new window
handle (MapRequestEvent {ev_window = w}) = withDisplay $ \dpy -> do
withWindowAttributes dpy w $ \wa -> do -- ignore override windows
-- need to ignore mapping requests by managed windows not on the current workspace
managed <- isClient w
when (not (wa_override_redirect wa) && not managed) $ manage w
-- window destroyed, unmanage it
-- window gone, unmanage it
handle (DestroyWindowEvent {ev_window = w}) = whenX (isClient w) $ do
unmanage w
modify (\s -> s { mapped = S.delete w (mapped s)
, waitingUnmap = M.delete w (waitingUnmap s)})
-- We track expected unmap events in waitingUnmap. We ignore this event unless
-- it is synthetic or we are not expecting an unmap notification from a window.
handle (UnmapEvent {ev_window = w, ev_send_event = synthetic}) = whenX (isClient w) $ do
e <- gets (fromMaybe 0 . M.lookup w . waitingUnmap)
if (synthetic || e == 0)
then unmanage w
else modify (\s -> s { waitingUnmap = M.update mpred w (waitingUnmap s) })
where mpred 1 = Nothing
mpred n = Just $ pred n
-- set keyboard mapping
handle e@(MappingNotifyEvent {}) = do
io $ refreshKeyboardMapping e
when (ev_request e `elem` [mappingKeyboard, mappingModifier]) $ do
setNumlockMask
grabKeys
-- handle button release, which may finish dragging.
handle e@(ButtonEvent {ev_event_type = t})
| t == buttonRelease = do
drag <- gets dragging
case drag of
-- we're done dragging and have released the mouse:
Just (_,f) -> modify (\s -> s { dragging = Nothing }) >> f
Nothing -> broadcastMessage e
-- handle motionNotify event, which may mean we are dragging.
handle e@(MotionEvent {ev_event_type = _t, ev_x = x, ev_y = y}) = do
drag <- gets dragging
case drag of
Just (d,_) -> d (fromIntegral x) (fromIntegral y) -- we're dragging
Nothing -> broadcastMessage e
-- click on an unfocused window, makes it focused on this workspace
handle e@(ButtonEvent {ev_window = w,ev_event_type = t,ev_button = b })
| t == buttonPress = do
-- If it's the root window, then it's something we
-- grabbed in grabButtons. Otherwise, it's click-to-focus.
dpy <- asks display
isr <- isRoot w
m <- cleanMask $ ev_state e
mact <- asks (M.lookup (m, b) . buttonActions)
case mact of
Just act | isr -> act $ ev_subwindow e
_ -> do
focus w
ctf <- asks (clickJustFocuses . config)
unless ctf $ io (allowEvents dpy replayPointer currentTime)
broadcastMessage e -- Always send button events.
-- entered a normal window: focus it if focusFollowsMouse is set to
-- True in the user's config.
handle e@(CrossingEvent {ev_window = w, ev_event_type = t})
| t == enterNotify && ev_mode e == notifyNormal
= whenX (asks $ focusFollowsMouse . config) $ do
dpy <- asks display
root <- asks theRoot
(_, _, w', _, _, _, _, _) <- io $ queryPointer dpy root
-- when Xlib cannot find a child that contains the pointer,
-- it returns None(0)
when (w' == 0 || w == w') (focus w)
-- left a window, check if we need to focus root
handle e@(CrossingEvent {ev_event_type = t})
| t == leaveNotify
= do rootw <- asks theRoot
when (ev_window e == rootw && not (ev_same_screen e)) $ setFocusX rootw
-- configure a window
handle e@(ConfigureRequestEvent {ev_window = w}) = withDisplay $ \dpy -> do
ws <- gets windowset
bw <- asks (borderWidth . config)
if M.member w (floating ws)
|| not (member w ws)
then do io $ configureWindow dpy w (ev_value_mask e) $ WindowChanges
{ wc_x = ev_x e
, wc_y = ev_y e
, wc_width = ev_width e
, wc_height = ev_height e
, wc_border_width = fromIntegral bw
, wc_sibling = ev_above e
, wc_stack_mode = ev_detail e }
when (member w ws) (float w)
else withWindowAttributes dpy w $ \wa -> io $ allocaXEvent $ \ev -> do
setEventType ev configureNotify
setConfigureEvent ev w w
(wa_x wa) (wa_y wa) (wa_width wa)
(wa_height wa) (ev_border_width e) none (wa_override_redirect wa)
sendEvent dpy w False 0 ev
io $ sync dpy False
-- configuration changes in the root may mean display settings have changed
handle (ConfigureEvent {ev_window = w}) = whenX (isRoot w) rescreen
-- property notify
handle event@(PropertyEvent { ev_event_type = t, ev_atom = a })
| t == propertyNotify && a == wM_NAME = asks (logHook . config) >>= userCodeDef () >>
broadcastMessage event
handle e@ClientMessageEvent { ev_message_type = mt } = do
a <- getAtom "XMONAD_RESTART"
if (mt == a)
then restart "xmonad" True
else broadcastMessage e
handle e = broadcastMessage e -- trace (eventName e) -- ignoring
-- ---------------------------------------------------------------------
-- IO stuff. Doesn't require any X state
-- Most of these things run only on startup (bar grabkeys)
-- | scan for any new windows to manage. If they're already managed,
-- this should be idempotent.
scan :: Display -> Window -> IO [Window]
scan dpy rootw = do
(_, _, ws) <- queryTree dpy rootw
filterM (\w -> ok w `E.catch` skip) ws
-- TODO: scan for windows that are either 'IsViewable' or where WM_STATE ==
-- Iconic
where ok w = do wa <- getWindowAttributes dpy w
a <- internAtom dpy "WM_STATE" False
p <- getWindowProperty32 dpy a w
let ic = case p of
Just (3:_) -> True -- 3 for iconified
_ -> False
return $ not (wa_override_redirect wa)
&& (wa_map_state wa == waIsViewable || ic)
skip :: E.SomeException -> IO Bool
skip _ = return False
setNumlockMask :: X ()
setNumlockMask = do
dpy <- asks display
ms <- io $ getModifierMapping dpy
xs <- sequence [ do
ks <- io $ keycodeToKeysym dpy kc 0
if ks == xK_Num_Lock
then return (setBit 0 (fromIntegral m))
else return (0 :: KeyMask)
| (m, kcs) <- ms, kc <- kcs, kc /= 0]
modify (\s -> s { numberlockMask = foldr (.|.) 0 xs })
-- | Grab the keys back
grabKeys :: X ()
grabKeys = do
XConf { display = dpy, theRoot = rootw } <- ask
let grab kc m = io $ grabKey dpy kc m rootw True grabModeAsync grabModeAsync
(minCode, maxCode) = displayKeycodes dpy
allCodes = [fromIntegral minCode .. fromIntegral maxCode]
io $ ungrabKey dpy anyKey anyModifier rootw
ks <- asks keyActions
-- build a map from keysyms to lists of keysyms (doing what
-- XGetKeyboardMapping would do if the X11 package bound it)
syms <- forM allCodes $ \code -> io (keycodeToKeysym dpy code 0)
let keysymMap = M.fromListWith (++) (zip syms [[code] | code <- allCodes])
keysymToKeycodes sym = M.findWithDefault [] sym keysymMap
forM_ (M.keys ks) $ \(mask,sym) ->
forM_ (keysymToKeycodes sym) $ \kc ->
mapM_ (grab kc . (mask .|.)) =<< extraModifiers
-- | XXX comment me
grabButtons :: X ()
grabButtons = do
XConf { display = dpy, theRoot = rootw } <- ask
let grab button mask = io $ grabButton dpy button mask rootw False buttonPressMask
grabModeAsync grabModeSync none none
io $ ungrabButton dpy anyButton anyModifier rootw
ems <- extraModifiers
ba <- asks buttonActions
mapM_ (\(m,b) -> mapM_ (grab b . (m .|.)) ems) (M.keys $ ba)
-- | @replace@ to signals compliant window managers to exit.
replace :: Display -> ScreenNumber -> Window -> IO ()
replace dpy dflt rootw = do
-- check for other WM
wmSnAtom <- internAtom dpy ("WM_S" ++ show dflt) False
currentWmSnOwner <- xGetSelectionOwner dpy wmSnAtom
when (currentWmSnOwner /= 0) $ do
-- prepare to receive destroyNotify for old WM
selectInput dpy currentWmSnOwner structureNotifyMask
-- create off-screen window
netWmSnOwner <- allocaSetWindowAttributes $ \attributes -> do
set_override_redirect attributes True
set_event_mask attributes propertyChangeMask
let screen = defaultScreenOfDisplay dpy
visual = defaultVisualOfScreen screen
attrmask = cWOverrideRedirect .|. cWEventMask
createWindow dpy rootw (-100) (-100) 1 1 0 copyFromParent copyFromParent visual attrmask attributes
-- try to acquire wmSnAtom, this should signal the old WM to terminate
xSetSelectionOwner dpy wmSnAtom netWmSnOwner currentTime
-- SKIPPED: check if we acquired the selection
-- SKIPPED: send client message indicating that we are now the WM
-- wait for old WM to go away
fix $ \again -> do
evt <- allocaXEvent $ \event -> do
windowEvent dpy currentWmSnOwner structureNotifyMask event
get_EventType event
when (evt /= destroyNotify) again

119
src/XMonad/ManageHook.hs Normal file
View File

@@ -0,0 +1,119 @@
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.ManageHook
-- Copyright : (c) Spencer Janssen 2007
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : spencerjanssen@gmail.com
-- Stability : unstable
-- Portability : not portable, uses cunning newtype deriving
--
-- An EDSL for ManageHooks
--
-----------------------------------------------------------------------------
-- XXX examples required
module XMonad.ManageHook where
import XMonad.Core
import Graphics.X11.Xlib.Extras
import Graphics.X11.Xlib (Display, Window, internAtom, wM_NAME)
import Control.Exception.Extensible (bracket, SomeException(..))
import qualified Control.Exception.Extensible as E
import Control.Monad.Reader
import Data.Maybe
import Data.Monoid
import qualified XMonad.StackSet as W
import XMonad.Operations (floatLocation, reveal)
-- | Lift an 'X' action to a 'Query'.
liftX :: X a -> Query a
liftX = Query . lift
-- | The identity hook that returns the WindowSet unchanged.
idHook :: Monoid m => m
idHook = mempty
-- | Infix 'mappend'. Compose two 'ManageHook' from right to left.
(<+>) :: Monoid m => m -> m -> m
(<+>) = mappend
-- | Compose the list of 'ManageHook's.
composeAll :: Monoid m => [m] -> m
composeAll = mconcat
infix 0 -->
-- | @p --> x@. If @p@ returns 'True', execute the 'ManageHook'.
--
-- > (-->) :: Monoid m => Query Bool -> Query m -> Query m -- a simpler type
(-->) :: (Monad m, Monoid a) => m Bool -> m a -> m a
p --> f = p >>= \b -> if b then f else return mempty
-- | @q =? x@. if the result of @q@ equals @x@, return 'True'.
(=?) :: Eq a => Query a -> a -> Query Bool
q =? x = fmap (== x) q
infixr 3 <&&>, <||>
-- | '&&' lifted to a 'Monad'.
(<&&>) :: Monad m => m Bool -> m Bool -> m Bool
(<&&>) = liftM2 (&&)
-- | '||' lifted to a 'Monad'.
(<||>) :: Monad m => m Bool -> m Bool -> m Bool
(<||>) = liftM2 (||)
-- | Return the window title.
title :: Query String
title = ask >>= \w -> liftX $ do
d <- asks display
let
getProp =
(internAtom d "_NET_WM_NAME" False >>= getTextProperty d w)
`E.catch` \(SomeException _) -> getTextProperty d w wM_NAME
extract prop = do l <- wcTextPropertyToTextList d prop
return $ if null l then "" else head l
io $ bracket getProp (xFree . tp_value) extract `E.catch` \(SomeException _) -> return ""
-- | Return the application name.
appName :: Query String
appName = ask >>= (\w -> liftX $ withDisplay $ \d -> fmap resName $ io $ getClassHint d w)
-- | Backwards compatible alias for 'appName'.
resource :: Query String
resource = appName
-- | Return the resource class.
className :: Query String
className = ask >>= (\w -> liftX $ withDisplay $ \d -> fmap resClass $ io $ getClassHint d w)
-- | A query that can return an arbitrary X property of type 'String',
-- identified by name.
stringProperty :: String -> Query String
stringProperty p = ask >>= (\w -> liftX $ withDisplay $ \d -> fmap (fromMaybe "") $ getStringProperty d w p)
getStringProperty :: Display -> Window -> String -> X (Maybe String)
getStringProperty d w p = do
a <- getAtom p
md <- io $ getWindowProperty8 d a w
return $ fmap (map (toEnum . fromIntegral)) md
-- | Modify the 'WindowSet' with a pure function.
doF :: (s -> s) -> Query (Endo s)
doF = return . Endo
-- | Move the window to the floating layer.
doFloat :: ManageHook
doFloat = ask >>= \w -> doF . W.float w . snd =<< liftX (floatLocation w)
-- | Map the window and remove it from the 'WindowSet'.
doIgnore :: ManageHook
doIgnore = ask >>= \w -> liftX (reveal w) >> doF (W.delete w)
-- | Move the window to a given workspace
doShift :: WorkspaceId -> ManageHook
doShift i = doF . W.shiftWin i =<< ask

690
src/XMonad/Operations.hs Normal file
View File

@@ -0,0 +1,690 @@
{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# LANGUAGE FlexibleContexts, FlexibleInstances, MultiParamTypeClasses, PatternGuards, TypeSynonymInstances #-}
-- --------------------------------------------------------------------------
-- |
-- Module : XMonad.Operations
-- Copyright : (c) Spencer Janssen 2007
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : dons@cse.unsw.edu.au
-- Stability : unstable
-- Portability : not portable, Typeable deriving, mtl, posix
--
-- Operations.
--
-----------------------------------------------------------------------------
module XMonad.Operations where
import XMonad.Core
import XMonad.Layout (Full(..))
import qualified XMonad.StackSet as W
import Data.Maybe
import Data.Monoid (Endo(..))
import Data.List (nub, (\\), find)
import Data.Bits ((.|.), (.&.), complement, testBit)
import Data.Ratio
import qualified Data.Map as M
import qualified Data.Set as S
import Control.Applicative
import Control.Arrow (second)
import Control.Monad.Reader
import Control.Monad.State
import qualified Control.Exception.Extensible as C
import System.IO
import System.Directory
import System.Posix.Process (executeFile)
import Graphics.X11.Xlib
import Graphics.X11.Xinerama (getScreenInfo)
import Graphics.X11.Xlib.Extras
-- ---------------------------------------------------------------------
-- |
-- Window manager operations
-- manage. Add a new window to be managed in the current workspace.
-- Bring it into focus.
--
-- Whether the window is already managed, or not, it is mapped, has its
-- border set, and its event mask set.
--
manage :: Window -> X ()
manage w = whenX (not <$> isClient w) $ withDisplay $ \d -> do
sh <- io $ getWMNormalHints d w
let isFixedSize = sh_min_size sh /= Nothing && sh_min_size sh == sh_max_size sh
isTransient <- isJust <$> io (getTransientForHint d w)
rr <- snd `fmap` floatLocation w
-- ensure that float windows don't go over the edge of the screen
let adjust (W.RationalRect x y wid h) | x + wid > 1 || y + h > 1 || x < 0 || y < 0
= W.RationalRect (0.5 - wid/2) (0.5 - h/2) wid h
adjust r = r
f ws | isFixedSize || isTransient = W.float w (adjust rr) . W.insertUp w . W.view i $ ws
| otherwise = W.insertUp w ws
where i = W.tag $ W.workspace $ W.current ws
mh <- asks (manageHook . config)
g <- appEndo <$> userCodeDef (Endo id) (runQuery mh w)
windows (g . f)
-- | unmanage. A window no longer exists, remove it from the window
-- list, on whatever workspace it is.
--
unmanage :: Window -> X ()
unmanage = windows . W.delete
-- | Kill the specified window. If we do kill it, we'll get a
-- delete notify back from X.
--
-- There are two ways to delete a window. Either just kill it, or if it
-- supports the delete protocol, send a delete event (e.g. firefox)
--
killWindow :: Window -> X ()
killWindow w = withDisplay $ \d -> do
wmdelt <- atom_WM_DELETE_WINDOW ; wmprot <- atom_WM_PROTOCOLS
protocols <- io $ getWMProtocols d w
io $ if wmdelt `elem` protocols
then allocaXEvent $ \ev -> do
setEventType ev clientMessage
setClientMessageEvent ev w wmprot 32 wmdelt 0
sendEvent d w False noEventMask ev
else killClient d w >> return ()
-- | Kill the currently focused client.
kill :: X ()
kill = withFocused killWindow
-- ---------------------------------------------------------------------
-- Managing windows
-- | windows. Modify the current window list with a pure function, and refresh
windows :: (WindowSet -> WindowSet) -> X ()
windows f = do
XState { windowset = old } <- get
let oldvisible = concatMap (W.integrate' . W.stack . W.workspace) $ W.current old : W.visible old
newwindows = W.allWindows ws \\ W.allWindows old
ws = f old
XConf { display = d , normalBorder = nbc, focusedBorder = fbc } <- ask
mapM_ setInitialProperties newwindows
whenJust (W.peek old) $ \otherw -> do
nbs <- asks (normalBorderColor . config)
setWindowBorderWithFallback d otherw nbs nbc
modify (\s -> s { windowset = ws })
-- notify non visibility
let tags_oldvisible = map (W.tag . W.workspace) $ W.current old : W.visible old
gottenhidden = filter (flip elem tags_oldvisible . W.tag) $ W.hidden ws
mapM_ (sendMessageWithNoRefresh Hide) gottenhidden
-- for each workspace, layout the currently visible workspaces
let allscreens = W.screens ws
summed_visible = scanl (++) [] $ map (W.integrate' . W.stack . W.workspace) allscreens
rects <- fmap concat $ forM (zip allscreens summed_visible) $ \ (w, vis) -> do
let wsp = W.workspace w
this = W.view n ws
n = W.tag wsp
tiled = (W.stack . W.workspace . W.current $ this)
>>= W.filter (`M.notMember` W.floating ws)
>>= W.filter (`notElem` vis)
viewrect = screenRect $ W.screenDetail w
-- just the tiled windows:
-- now tile the windows on this workspace, modified by the gap
(rs, ml') <- runLayout wsp { W.stack = tiled } viewrect `catchX`
runLayout wsp { W.stack = tiled, W.layout = Layout Full } viewrect
updateLayout n ml'
let m = W.floating ws
flt = [(fw, scaleRationalRect viewrect r)
| fw <- filter (flip M.member m) (W.index this)
, Just r <- [M.lookup fw m]]
vs = flt ++ rs
io $ restackWindows d (map fst vs)
-- return the visible windows for this workspace:
return vs
let visible = map fst rects
mapM_ (uncurry tileWindow) rects
whenJust (W.peek ws) $ \w -> do
fbs <- asks (focusedBorderColor . config)
setWindowBorderWithFallback d w fbs fbc
mapM_ reveal visible
setTopFocus
-- hide every window that was potentially visible before, but is not
-- given a position by a layout now.
mapM_ hide (nub (oldvisible ++ newwindows) \\ visible)
-- all windows that are no longer in the windowset are marked as
-- withdrawn, it is important to do this after the above, otherwise 'hide'
-- will overwrite withdrawnState with iconicState
mapM_ (flip setWMState withdrawnState) (W.allWindows old \\ W.allWindows ws)
isMouseFocused <- asks mouseFocused
unless isMouseFocused $ clearEvents enterWindowMask
asks (logHook . config) >>= userCodeDef ()
-- | Produce the actual rectangle from a screen and a ratio on that screen.
scaleRationalRect :: Rectangle -> W.RationalRect -> Rectangle
scaleRationalRect (Rectangle sx sy sw sh) (W.RationalRect rx ry rw rh)
= Rectangle (sx + scale sw rx) (sy + scale sh ry) (scale sw rw) (scale sh rh)
where scale s r = floor (toRational s * r)
-- | setWMState. set the WM_STATE property
setWMState :: Window -> Int -> X ()
setWMState w v = withDisplay $ \dpy -> do
a <- atom_WM_STATE
io $ changeProperty32 dpy w a a propModeReplace [fromIntegral v, fromIntegral none]
-- | Set the border color using the window's color map, if possible,
-- otherwise fallback to the color in @Pixel@.
setWindowBorderWithFallback :: Display -> Window -> String -> Pixel -> X ()
setWindowBorderWithFallback dpy w color basic = io $
C.handle fallback $ do
wa <- getWindowAttributes dpy w
pixel <- color_pixel . fst <$> allocNamedColor dpy (wa_colormap wa) color
setWindowBorder dpy w pixel
where
fallback :: C.SomeException -> IO ()
fallback e = do hPrint stderr e >> hFlush stderr
setWindowBorder dpy w basic
-- | hide. Hide a window by unmapping it, and setting Iconified.
hide :: Window -> X ()
hide w = whenX (gets (S.member w . mapped)) $ withDisplay $ \d -> do
cMask <- asks $ clientMask . config
io $ do selectInput d w (cMask .&. complement structureNotifyMask)
unmapWindow d w
selectInput d w cMask
setWMState w iconicState
-- this part is key: we increment the waitingUnmap counter to distinguish
-- between client and xmonad initiated unmaps.
modify (\s -> s { waitingUnmap = M.insertWith (+) w 1 (waitingUnmap s)
, mapped = S.delete w (mapped s) })
-- | reveal. Show a window by mapping it and setting Normal
-- this is harmless if the window was already visible
reveal :: Window -> X ()
reveal w = withDisplay $ \d -> do
setWMState w normalState
io $ mapWindow d w
whenX (isClient w) $ modify (\s -> s { mapped = S.insert w (mapped s) })
-- | Set some properties when we initially gain control of a window
setInitialProperties :: Window -> X ()
setInitialProperties w = asks normalBorder >>= \nb -> withDisplay $ \d -> do
setWMState w iconicState
asks (clientMask . config) >>= io . selectInput d w
bw <- asks (borderWidth . config)
io $ setWindowBorderWidth d w bw
-- we must initially set the color of new windows, to maintain invariants
-- required by the border setting in 'windows'
io $ setWindowBorder d w nb
-- | refresh. Render the currently visible workspaces, as determined by
-- the 'StackSet'. Also, set focus to the focused window.
--
-- This is our 'view' operation (MVC), in that it pretty prints our model
-- with X calls.
--
refresh :: X ()
refresh = windows id
-- | clearEvents. Remove all events of a given type from the event queue.
clearEvents :: EventMask -> X ()
clearEvents mask = withDisplay $ \d -> io $ do
sync d False
allocaXEvent $ \p -> fix $ \again -> do
more <- checkMaskEvent d mask p
when more again -- beautiful
-- | tileWindow. Moves and resizes w such that it fits inside the given
-- rectangle, including its border.
tileWindow :: Window -> Rectangle -> X ()
tileWindow w r = withDisplay $ \d -> withWindowAttributes d w $ \wa -> do
-- give all windows at least 1x1 pixels
let bw = fromIntegral $ wa_border_width wa
least x | x <= bw*2 = 1
| otherwise = x - bw*2
io $ moveResizeWindow d w (rect_x r) (rect_y r)
(least $ rect_width r) (least $ rect_height r)
-- ---------------------------------------------------------------------
-- | Returns 'True' if the first rectangle is contained within, but not equal
-- to the second.
containedIn :: Rectangle -> Rectangle -> Bool
containedIn r1@(Rectangle x1 y1 w1 h1) r2@(Rectangle x2 y2 w2 h2)
= and [ r1 /= r2
, x1 >= x2
, y1 >= y2
, fromIntegral x1 + w1 <= fromIntegral x2 + w2
, fromIntegral y1 + h1 <= fromIntegral y2 + h2 ]
-- | Given a list of screens, remove all duplicated screens and screens that
-- are entirely contained within another.
nubScreens :: [Rectangle] -> [Rectangle]
nubScreens xs = nub . filter (\x -> not $ any (x `containedIn`) xs) $ xs
-- | Cleans the list of screens according to the rules documented for
-- nubScreens.
getCleanedScreenInfo :: MonadIO m => Display -> m [Rectangle]
getCleanedScreenInfo = io . fmap nubScreens . getScreenInfo
-- | rescreen. The screen configuration may have changed (due to
-- xrandr), update the state and refresh the screen, and reset the gap.
rescreen :: X ()
rescreen = do
xinesc <- withDisplay getCleanedScreenInfo
windows $ \ws@(W.StackSet { W.current = v, W.visible = vs, W.hidden = hs }) ->
let (xs, ys) = splitAt (length xinesc) $ map W.workspace (v:vs) ++ hs
(a:as) = zipWith3 W.Screen xs [0..] $ map SD xinesc
in ws { W.current = a
, W.visible = as
, W.hidden = ys }
-- ---------------------------------------------------------------------
-- | setButtonGrab. Tell whether or not to intercept clicks on a given window
setButtonGrab :: Bool -> Window -> X ()
setButtonGrab grab w = do
pointerMode <- asks $ \c -> if clickJustFocuses (config c)
then grabModeAsync
else grabModeSync
withDisplay $ \d -> io $ if grab
then forM_ [button1, button2, button3] $ \b ->
grabButton d b anyModifier w False buttonPressMask
pointerMode grabModeSync none none
else ungrabButton d anyButton anyModifier w
-- ---------------------------------------------------------------------
-- Setting keyboard focus
-- | Set the focus to the window on top of the stack, or root
setTopFocus :: X ()
setTopFocus = withWindowSet $ maybe (setFocusX =<< asks theRoot) setFocusX . W.peek
-- | Set focus explicitly to window 'w' if it is managed by us, or root.
-- This happens if X notices we've moved the mouse (and perhaps moved
-- the mouse to a new screen).
focus :: Window -> X ()
focus w = local (\c -> c { mouseFocused = True }) $ withWindowSet $ \s -> do
let stag = W.tag . W.workspace
curr = stag $ W.current s
mnew <- maybe (return Nothing) (fmap (fmap stag) . uncurry pointScreen)
=<< asks mousePosition
root <- asks theRoot
case () of
_ | W.member w s && W.peek s /= Just w -> windows (W.focusWindow w)
| Just new <- mnew, w == root && curr /= new
-> windows (W.view new)
| otherwise -> return ()
-- | Call X to set the keyboard focus details.
setFocusX :: Window -> X ()
setFocusX w = withWindowSet $ \ws -> do
dpy <- asks display
-- clear mouse button grab and border on other windows
forM_ (W.current ws : W.visible ws) $ \wk ->
forM_ (W.index (W.view (W.tag (W.workspace wk)) ws)) $ \otherw ->
setButtonGrab True otherw
-- If we ungrab buttons on the root window, we lose our mouse bindings.
whenX (not <$> isRoot w) $ setButtonGrab False w
hints <- io $ getWMHints dpy w
protocols <- io $ getWMProtocols dpy w
wmprot <- atom_WM_PROTOCOLS
wmtf <- atom_WM_TAKE_FOCUS
currevt <- asks currentEvent
let inputHintSet = wmh_flags hints `testBit` inputHintBit
when ((inputHintSet && wmh_input hints) || (not inputHintSet)) $
io $ do setInputFocus dpy w revertToPointerRoot 0
when (wmtf `elem` protocols) $
io $ allocaXEvent $ \ev -> do
setEventType ev clientMessage
setClientMessageEvent ev w wmprot 32 wmtf $ maybe currentTime event_time currevt
sendEvent dpy w False noEventMask ev
where event_time ev =
if (ev_event_type ev) `elem` timedEvents then
ev_time ev
else
currentTime
timedEvents = [ keyPress, keyRelease, buttonPress, buttonRelease, enterNotify, leaveNotify, selectionRequest ]
------------------------------------------------------------------------
-- Message handling
-- | Throw a message to the current 'LayoutClass' possibly modifying how we
-- layout the windows, then refresh.
sendMessage :: Message a => a -> X ()
sendMessage a = do
w <- W.workspace . W.current <$> gets windowset
ml' <- handleMessage (W.layout w) (SomeMessage a) `catchX` return Nothing
whenJust ml' $ \l' ->
windows $ \ws -> ws { W.current = (W.current ws)
{ W.workspace = (W.workspace $ W.current ws)
{ W.layout = l' }}}
-- | Send a message to all layouts, without refreshing.
broadcastMessage :: Message a => a -> X ()
broadcastMessage a = withWindowSet $ \ws -> do
let c = W.workspace . W.current $ ws
v = map W.workspace . W.visible $ ws
h = W.hidden ws
mapM_ (sendMessageWithNoRefresh a) (c : v ++ h)
-- | Send a message to a layout, without refreshing.
sendMessageWithNoRefresh :: Message a => a -> W.Workspace WorkspaceId (Layout Window) Window -> X ()
sendMessageWithNoRefresh a w =
handleMessage (W.layout w) (SomeMessage a) `catchX` return Nothing >>=
updateLayout (W.tag w)
-- | Update the layout field of a workspace
updateLayout :: WorkspaceId -> Maybe (Layout Window) -> X ()
updateLayout i ml = whenJust ml $ \l ->
runOnWorkspaces $ \ww -> return $ if W.tag ww == i then ww { W.layout = l} else ww
-- | Set the layout of the currently viewed workspace
setLayout :: Layout Window -> X ()
setLayout l = do
ss@(W.StackSet { W.current = c@(W.Screen { W.workspace = ws })}) <- gets windowset
handleMessage (W.layout ws) (SomeMessage ReleaseResources)
windows $ const $ ss {W.current = c { W.workspace = ws { W.layout = l } } }
------------------------------------------------------------------------
-- Utilities
-- | Return workspace visible on screen 'sc', or 'Nothing'.
screenWorkspace :: ScreenId -> X (Maybe WorkspaceId)
screenWorkspace sc = withWindowSet $ return . W.lookupWorkspace sc
-- | Apply an 'X' operation to the currently focused window, if there is one.
withFocused :: (Window -> X ()) -> X ()
withFocused f = withWindowSet $ \w -> whenJust (W.peek w) f
-- | 'True' if window is under management by us
isClient :: Window -> X Bool
isClient w = withWindowSet $ return . W.member w
-- | Combinations of extra modifier masks we need to grab keys\/buttons for.
-- (numlock and capslock)
extraModifiers :: X [KeyMask]
extraModifiers = do
nlm <- gets numberlockMask
return [0, nlm, lockMask, nlm .|. lockMask ]
-- | Strip numlock\/capslock from a mask
cleanMask :: KeyMask -> X KeyMask
cleanMask km = do
nlm <- gets numberlockMask
return (complement (nlm .|. lockMask) .&. km)
-- | Get the 'Pixel' value for a named color
initColor :: Display -> String -> IO (Maybe Pixel)
initColor dpy c = C.handle (\(C.SomeException _) -> return Nothing) $
(Just . color_pixel . fst) <$> allocNamedColor dpy colormap c
where colormap = defaultColormap dpy (defaultScreen dpy)
------------------------------------------------------------------------
-- | A type to help serialize xmonad's state to a file.
data StateFile = StateFile
{ sfWins :: W.StackSet WorkspaceId String Window ScreenId ScreenDetail
, sfExt :: [(String, String)]
} deriving (Show, Read)
-- | Write the current window state (and extensible state) to a file
-- so that xmonad can resume with that state intact.
writeStateToFile :: X ()
writeStateToFile = do
let maybeShow (t, Right (PersistentExtension ext)) = Just (t, show ext)
maybeShow (t, Left str) = Just (t, str)
maybeShow _ = Nothing
wsData = W.mapLayout show . windowset
extState = catMaybes . map maybeShow . M.toList . extensibleState
path <- stateFileName
stateData <- gets (\s -> StateFile (wsData s) (extState s))
catchIO (writeFile path $ show stateData)
-- | Read the state of a previous xmonad instance from a file and
-- return that state. The state file is removed after reading it.
readStateFile :: (LayoutClass l Window, Read (l Window)) => XConfig l -> X (Maybe XState)
readStateFile xmc = do
path <- stateFileName
-- I'm trying really hard here to make sure we read the entire
-- contents of the file before it is removed from the file system.
sf' <- userCode . io $ do
raw <- withFile path ReadMode readStrict
return $! maybeRead reads raw
io (removeFile path)
return $ do
sf <- join sf'
let winset = W.ensureTags layout (workspaces xmc) $ W.mapLayout (fromMaybe layout . maybeRead lreads) (sfWins sf)
extState = M.fromList . map (second Left) $ sfExt sf
return XState { windowset = winset
, numberlockMask = 0
, mapped = S.empty
, waitingUnmap = M.empty
, dragging = Nothing
, extensibleState = extState
}
where
layout = Layout (layoutHook xmc)
lreads = readsLayout layout
maybeRead reads' s = case reads' s of
[(x, "")] -> Just x
_ -> Nothing
readStrict :: Handle -> IO String
readStrict h = hGetContents h >>= \s -> length s `seq` return s
-- | Migrate state from a previously running xmonad instance that used
-- the older @--resume@ technique.
{-# DEPRECATED migrateState "will be removed some point in the future." #-}
migrateState :: (Functor m, MonadIO m) => String -> String -> m ()
migrateState ws xs = do
io (putStrLn "WARNING: --resume is no longer supported.")
whenJust stateData $ \s -> do
path <- stateFileName
catchIO (writeFile path $ show s)
where
stateData = StateFile <$> maybeRead ws <*> maybeRead xs
maybeRead s = case reads s of
[(x, "")] -> Just x
_ -> Nothing
-- | @restart name resume@. Attempt to restart xmonad by executing the program
-- @name@. If @resume@ is 'True', restart with the current window state.
-- When executing another window manager, @resume@ should be 'False'.
restart :: String -> Bool -> X ()
restart prog resume = do
broadcastMessage ReleaseResources
io . flush =<< asks display
when resume writeStateToFile
catchIO (executeFile prog True [] Nothing)
------------------------------------------------------------------------
-- | Floating layer support
-- | Given a window, find the screen it is located on, and compute
-- the geometry of that window wrt. that screen.
floatLocation :: Window -> X (ScreenId, W.RationalRect)
floatLocation w =
catchX go $ do
-- Fallback solution if `go' fails. Which it might, since it
-- calls `getWindowAttributes'.
sc <- W.current <$> gets windowset
return (W.screen sc, W.RationalRect 0 0 1 1)
where fi x = fromIntegral x
go = withDisplay $ \d -> do
ws <- gets windowset
wa <- io $ getWindowAttributes d w
let bw = (fromIntegral . wa_border_width) wa
sc <- fromMaybe (W.current ws) <$> pointScreen (fi $ wa_x wa) (fi $ wa_y wa)
let sr = screenRect . W.screenDetail $ sc
rr = W.RationalRect ((fi (wa_x wa) - fi (rect_x sr)) % fi (rect_width sr))
((fi (wa_y wa) - fi (rect_y sr)) % fi (rect_height sr))
(fi (wa_width wa + bw*2) % fi (rect_width sr))
(fi (wa_height wa + bw*2) % fi (rect_height sr))
return (W.screen sc, rr)
-- | Given a point, determine the screen (if any) that contains it.
pointScreen :: Position -> Position
-> X (Maybe (W.Screen WorkspaceId (Layout Window) Window ScreenId ScreenDetail))
pointScreen x y = withWindowSet $ return . find p . W.screens
where p = pointWithin x y . screenRect . W.screenDetail
-- | @pointWithin x y r@ returns 'True' if the @(x, y)@ co-ordinate is within
-- @r@.
pointWithin :: Position -> Position -> Rectangle -> Bool
pointWithin x y r = x >= rect_x r &&
x < rect_x r + fromIntegral (rect_width r) &&
y >= rect_y r &&
y < rect_y r + fromIntegral (rect_height r)
-- | Make a tiled window floating, using its suggested rectangle
float :: Window -> X ()
float w = do
(sc, rr) <- floatLocation w
windows $ \ws -> W.float w rr . fromMaybe ws $ do
i <- W.findTag w ws
guard $ i `elem` map (W.tag . W.workspace) (W.screens ws)
f <- W.peek ws
sw <- W.lookupWorkspace sc ws
return (W.focusWindow f . W.shiftWin sw w $ ws)
-- ---------------------------------------------------------------------
-- Mouse handling
-- | Accumulate mouse motion events
mouseDrag :: (Position -> Position -> X ()) -> X () -> X ()
mouseDrag f done = do
drag <- gets dragging
case drag of
Just _ -> return () -- error case? we're already dragging
Nothing -> do
XConf { theRoot = root, display = d } <- ask
io $ grabPointer d root False (buttonReleaseMask .|. pointerMotionMask)
grabModeAsync grabModeAsync none none currentTime
modify $ \s -> s { dragging = Just (motion, cleanup) }
where
cleanup = do
withDisplay $ io . flip ungrabPointer currentTime
modify $ \s -> s { dragging = Nothing }
done
motion x y = do z <- f x y
clearEvents pointerMotionMask
return z
-- | drag the window under the cursor with the mouse while it is dragged
mouseMoveWindow :: Window -> X ()
mouseMoveWindow w = whenX (isClient w) $ withDisplay $ \d -> do
io $ raiseWindow d w
wa <- io $ getWindowAttributes d w
(_, _, _, ox', oy', _, _, _) <- io $ queryPointer d w
let ox = fromIntegral ox'
oy = fromIntegral oy'
mouseDrag (\ex ey -> do
io $ moveWindow d w (fromIntegral (fromIntegral (wa_x wa) + (ex - ox)))
(fromIntegral (fromIntegral (wa_y wa) + (ey - oy)))
float w
)
(float w)
-- | resize the window under the cursor with the mouse while it is dragged
mouseResizeWindow :: Window -> X ()
mouseResizeWindow w = whenX (isClient w) $ withDisplay $ \d -> do
io $ raiseWindow d w
wa <- io $ getWindowAttributes d w
sh <- io $ getWMNormalHints d w
io $ warpPointer d none w 0 0 0 0 (fromIntegral (wa_width wa)) (fromIntegral (wa_height wa))
mouseDrag (\ex ey -> do
io $ resizeWindow d w `uncurry`
applySizeHintsContents sh (ex - fromIntegral (wa_x wa),
ey - fromIntegral (wa_y wa))
float w)
(float w)
-- ---------------------------------------------------------------------
-- | Support for window size hints
type D = (Dimension, Dimension)
-- | Given a window, build an adjuster function that will reduce the given
-- dimensions according to the window's border width and size hints.
mkAdjust :: Window -> X (D -> D)
mkAdjust w = withDisplay $ \d -> liftIO $ do
sh <- getWMNormalHints d w
wa <- C.try $ getWindowAttributes d w
case wa of
Left err -> const (return id) (err :: C.SomeException)
Right wa' ->
let bw = fromIntegral $ wa_border_width wa'
in return $ applySizeHints bw sh
-- | Reduce the dimensions if needed to comply to the given SizeHints, taking
-- window borders into account.
applySizeHints :: Integral a => Dimension -> SizeHints -> (a, a) -> D
applySizeHints bw sh =
tmap (+ 2 * bw) . applySizeHintsContents sh . tmap (subtract $ 2 * fromIntegral bw)
where
tmap f (x, y) = (f x, f y)
-- | Reduce the dimensions if needed to comply to the given SizeHints.
applySizeHintsContents :: Integral a => SizeHints -> (a, a) -> D
applySizeHintsContents sh (w, h) =
applySizeHints' sh (fromIntegral $ max 1 w, fromIntegral $ max 1 h)
-- | XXX comment me
applySizeHints' :: SizeHints -> D -> D
applySizeHints' sh =
maybe id applyMaxSizeHint (sh_max_size sh)
. maybe id (\(bw, bh) (w, h) -> (w+bw, h+bh)) (sh_base_size sh)
. maybe id applyResizeIncHint (sh_resize_inc sh)
. maybe id applyAspectHint (sh_aspect sh)
. maybe id (\(bw,bh) (w,h) -> (w-bw, h-bh)) (sh_base_size sh)
-- | Reduce the dimensions so their aspect ratio falls between the two given aspect ratios.
applyAspectHint :: (D, D) -> D -> D
applyAspectHint ((minx, miny), (maxx, maxy)) x@(w,h)
| or [minx < 1, miny < 1, maxx < 1, maxy < 1] = x
| w * maxy > h * maxx = (h * maxx `div` maxy, h)
| w * miny < h * minx = (w, w * miny `div` minx)
| otherwise = x
-- | Reduce the dimensions so they are a multiple of the size increments.
applyResizeIncHint :: D -> D -> D
applyResizeIncHint (iw,ih) x@(w,h) =
if iw > 0 && ih > 0 then (w - w `mod` iw, h - h `mod` ih) else x
-- | Reduce the dimensions if they exceed the given maximum dimensions.
applyMaxSizeHint :: D -> D -> D
applyMaxSizeHint (mw,mh) x@(w,h) =
if mw > 0 && mh > 0 then (min w mw,min h mh) else x

558
src/XMonad/StackSet.hs Normal file
View File

@@ -0,0 +1,558 @@
{-# LANGUAGE PatternGuards #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.StackSet
-- Copyright : (c) Don Stewart 2007
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : dons@galois.com
-- Stability : experimental
-- Portability : portable, Haskell 98
--
module XMonad.StackSet (
-- * Introduction
-- $intro
-- ** The Zipper
-- $zipper
-- ** Xinerama support
-- $xinerama
-- ** Master and Focus
-- $focus
StackSet(..), Workspace(..), Screen(..), Stack(..), RationalRect(..),
-- * Construction
-- $construction
new, view, greedyView,
-- * Xinerama operations
-- $xinerama
lookupWorkspace,
screens, workspaces, allWindows, currentTag,
-- * Operations on the current stack
-- $stackOperations
peek, index, integrate, integrate', differentiate,
focusUp, focusDown, focusUp', focusDown', focusMaster, focusWindow,
tagMember, renameTag, ensureTags, member, findTag, mapWorkspace, mapLayout,
-- * Modifying the stackset
-- $modifyStackset
insertUp, delete, delete', filter,
-- * Setting the master window
-- $settingMW
swapUp, swapDown, swapMaster, shiftMaster, modify, modify', float, sink, -- needed by users
-- * Composite operations
-- $composite
shift, shiftWin,
-- for testing
abort
) where
import Prelude hiding (filter)
import Data.Maybe (listToMaybe,isJust,fromMaybe)
import qualified Data.List as L (deleteBy,find,splitAt,filter,nub)
import Data.List ( (\\) )
import qualified Data.Map as M (Map,insert,delete,empty)
-- $intro
--
-- The 'StackSet' data type encodes a window manager abstraction. The
-- window manager is a set of virtual workspaces. On each workspace is a
-- stack of windows. A given workspace is always current, and a given
-- window on each workspace has focus. The focused window on the current
-- workspace is the one which will take user input. It can be visualised
-- as follows:
--
-- > Workspace { 0*} { 1 } { 2 } { 3 } { 4 }
-- >
-- > Windows [1 [] [3* [6*] []
-- > ,2*] ,4
-- > ,5]
--
-- Note that workspaces are indexed from 0, windows are numbered
-- uniquely. A '*' indicates the window on each workspace that has
-- focus, and which workspace is current.
-- $zipper
--
-- We encode all the focus tracking directly in the data structure, with a 'zipper':
--
-- A Zipper is essentially an `updateable' and yet pure functional
-- cursor into a data structure. Zipper is also a delimited
-- continuation reified as a data structure.
--
-- The Zipper lets us replace an item deep in a complex data
-- structure, e.g., a tree or a term, without an mutation. The
-- resulting data structure will share as much of its components with
-- the old structure as possible.
--
-- Oleg Kiselyov, 27 Apr 2005, haskell\@, "Zipper as a delimited continuation"
--
-- We use the zipper to keep track of the focused workspace and the
-- focused window on each workspace, allowing us to have correct focus
-- by construction. We closely follow Huet's original implementation:
--
-- G. Huet, /Functional Pearl: The Zipper/,
-- 1997, J. Functional Programming 75(5):549-554.
-- and:
-- R. Hinze and J. Jeuring, /Functional Pearl: The Web/.
--
-- and Conor McBride's zipper differentiation paper.
-- Another good reference is:
--
-- The Zipper, Haskell wikibook
-- $xinerama
-- Xinerama in X11 lets us view multiple virtual workspaces
-- simultaneously. While only one will ever be in focus (i.e. will
-- receive keyboard events), other workspaces may be passively
-- viewable. We thus need to track which virtual workspaces are
-- associated (viewed) on which physical screens. To keep track of
-- this, 'StackSet' keeps separate lists of visible but non-focused
-- workspaces, and non-visible workspaces.
-- $focus
--
-- Each stack tracks a focused item, and for tiling purposes also tracks
-- a 'master' position. The connection between 'master' and 'focus'
-- needs to be well defined, particularly in relation to 'insert' and
-- 'delete'.
--
------------------------------------------------------------------------
-- |
-- A cursor into a non-empty list of workspaces.
--
-- We puncture the workspace list, producing a hole in the structure
-- used to track the currently focused workspace. The two other lists
-- that are produced are used to track those workspaces visible as
-- Xinerama screens, and those workspaces not visible anywhere.
data StackSet i l a sid sd =
StackSet { current :: !(Screen i l a sid sd) -- ^ currently focused workspace
, visible :: [Screen i l a sid sd] -- ^ non-focused workspaces, visible in xinerama
, hidden :: [Workspace i l a] -- ^ workspaces not visible anywhere
, floating :: M.Map a RationalRect -- ^ floating windows
} deriving (Show, Read, Eq)
-- | Visible workspaces, and their Xinerama screens.
data Screen i l a sid sd = Screen { workspace :: !(Workspace i l a)
, screen :: !sid
, screenDetail :: !sd }
deriving (Show, Read, Eq)
-- |
-- A workspace is just a tag, a layout, and a stack.
--
data Workspace i l a = Workspace { tag :: !i, layout :: l, stack :: Maybe (Stack a) }
deriving (Show, Read, Eq)
-- | A structure for window geometries
data RationalRect = RationalRect Rational Rational Rational Rational
deriving (Show, Read, Eq)
-- |
-- A stack is a cursor onto a window list.
-- The data structure tracks focus by construction, and
-- the master window is by convention the top-most item.
-- Focus operations will not reorder the list that results from
-- flattening the cursor. The structure can be envisaged as:
--
-- > +-- master: < '7' >
-- > up | [ '2' ]
-- > +--------- [ '3' ]
-- > focus: < '4' >
-- > dn +----------- [ '8' ]
--
-- A 'Stack' can be viewed as a list with a hole punched in it to make
-- the focused position. Under the zipper\/calculus view of such
-- structures, it is the differentiation of a [a], and integrating it
-- back has a natural implementation used in 'index'.
--
data Stack a = Stack { focus :: !a -- focused thing in this set
, up :: [a] -- clowns to the left
, down :: [a] } -- jokers to the right
deriving (Show, Read, Eq)
-- | this function indicates to catch that an error is expected
abort :: String -> a
abort x = error $ "xmonad: StackSet: " ++ x
-- ---------------------------------------------------------------------
-- $construction
-- | /O(n)/. Create a new stackset, of empty stacks, with given tags,
-- with physical screens whose descriptions are given by 'm'. The
-- number of physical screens (@length 'm'@) should be less than or
-- equal to the number of workspace tags. The first workspace in the
-- list will be current.
--
-- Xinerama: Virtual workspaces are assigned to physical screens, starting at 0.
--
new :: (Integral s) => l -> [i] -> [sd] -> StackSet i l a s sd
new l wids m | not (null wids) && length m <= length wids && not (null m)
= StackSet cur visi unseen M.empty
where (seen,unseen) = L.splitAt (length m) $ map (\i -> Workspace i l Nothing) wids
(cur:visi) = [ Screen i s sd | (i, s, sd) <- zip3 seen [0..] m ]
-- now zip up visibles with their screen id
new _ _ _ = abort "non-positive argument to StackSet.new"
-- |
-- /O(w)/. Set focus to the workspace with index \'i\'.
-- If the index is out of range, return the original 'StackSet'.
--
-- Xinerama: If the workspace is not visible on any Xinerama screen, it
-- becomes the current screen. If it is in the visible list, it becomes
-- current.
view :: (Eq s, Eq i) => i -> StackSet i l a s sd -> StackSet i l a s sd
view i s
| i == currentTag s = s -- current
| Just x <- L.find ((i==).tag.workspace) (visible s)
-- if it is visible, it is just raised
= s { current = x, visible = current s : L.deleteBy (equating screen) x (visible s) }
| Just x <- L.find ((i==).tag) (hidden s) -- must be hidden then
-- if it was hidden, it is raised on the xine screen currently used
= s { current = (current s) { workspace = x }
, hidden = workspace (current s) : L.deleteBy (equating tag) x (hidden s) }
| otherwise = s -- not a member of the stackset
where equating f = \x y -> f x == f y
-- 'Catch'ing this might be hard. Relies on monotonically increasing
-- workspace tags defined in 'new'
--
-- and now tags are not monotonic, what happens here?
-- |
-- Set focus to the given workspace. If that workspace does not exist
-- in the stackset, the original workspace is returned. If that workspace is
-- 'hidden', then display that workspace on the current screen, and move the
-- current workspace to 'hidden'. If that workspace is 'visible' on another
-- screen, the workspaces of the current screen and the other screen are
-- swapped.
greedyView :: (Eq s, Eq i) => i -> StackSet i l a s sd -> StackSet i l a s sd
greedyView w ws
| any wTag (hidden ws) = view w ws
| (Just s) <- L.find (wTag . workspace) (visible ws)
= ws { current = (current ws) { workspace = workspace s }
, visible = s { workspace = workspace (current ws) }
: L.filter (not . wTag . workspace) (visible ws) }
| otherwise = ws
where wTag = (w == ) . tag
-- ---------------------------------------------------------------------
-- $xinerama
-- | Find the tag of the workspace visible on Xinerama screen 'sc'.
-- 'Nothing' if screen is out of bounds.
lookupWorkspace :: Eq s => s -> StackSet i l a s sd -> Maybe i
lookupWorkspace sc w = listToMaybe [ tag i | Screen i s _ <- current w : visible w, s == sc ]
-- ---------------------------------------------------------------------
-- $stackOperations
-- |
-- The 'with' function takes a default value, a function, and a
-- StackSet. If the current stack is Nothing, 'with' returns the
-- default value. Otherwise, it applies the function to the stack,
-- returning the result. It is like 'maybe' for the focused workspace.
--
with :: b -> (Stack a -> b) -> StackSet i l a s sd -> b
with dflt f = maybe dflt f . stack . workspace . current
-- |
-- Apply a function, and a default value for 'Nothing', to modify the current stack.
--
modify :: Maybe (Stack a) -> (Stack a -> Maybe (Stack a)) -> StackSet i l a s sd -> StackSet i l a s sd
modify d f s = s { current = (current s)
{ workspace = (workspace (current s)) { stack = with d f s }}}
-- |
-- Apply a function to modify the current stack if it isn't empty, and we don't
-- want to empty it.
--
modify' :: (Stack a -> Stack a) -> StackSet i l a s sd -> StackSet i l a s sd
modify' f = modify Nothing (Just . f)
-- |
-- /O(1)/. Extract the focused element of the current stack.
-- Return 'Just' that element, or 'Nothing' for an empty stack.
--
peek :: StackSet i l a s sd -> Maybe a
peek = with Nothing (return . focus)
-- |
-- /O(n)/. Flatten a 'Stack' into a list.
--
integrate :: Stack a -> [a]
integrate (Stack x l r) = reverse l ++ x : r
-- |
-- /O(n)/ Flatten a possibly empty stack into a list.
integrate' :: Maybe (Stack a) -> [a]
integrate' = maybe [] integrate
-- |
-- /O(n)/. Turn a list into a possibly empty stack (i.e., a zipper):
-- the first element of the list is current, and the rest of the list
-- is down.
differentiate :: [a] -> Maybe (Stack a)
differentiate [] = Nothing
differentiate (x:xs) = Just $ Stack x [] xs
-- |
-- /O(n)/. 'filter p s' returns the elements of 's' such that 'p' evaluates to
-- 'True'. Order is preserved, and focus moves as described for 'delete'.
--
filter :: (a -> Bool) -> Stack a -> Maybe (Stack a)
filter p (Stack f ls rs) = case L.filter p (f:rs) of
f':rs' -> Just $ Stack f' (L.filter p ls) rs' -- maybe move focus down
[] -> case L.filter p ls of -- filter back up
f':ls' -> Just $ Stack f' ls' [] -- else up
[] -> Nothing
-- |
-- /O(s)/. Extract the stack on the current workspace, as a list.
-- The order of the stack is determined by the master window -- it will be
-- the head of the list. The implementation is given by the natural
-- integration of a one-hole list cursor, back to a list.
--
index :: StackSet i l a s sd -> [a]
index = with [] integrate
-- |
-- /O(1), O(w) on the wrapping case/.
--
-- focusUp, focusDown. Move the window focus up or down the stack,
-- wrapping if we reach the end. The wrapping should model a 'cycle'
-- on the current stack. The 'master' window, and window order,
-- are unaffected by movement of focus.
--
-- swapUp, swapDown, swap the neighbour in the stack ordering, wrapping
-- if we reach the end. Again the wrapping model should 'cycle' on
-- the current stack.
--
focusUp, focusDown, swapUp, swapDown :: StackSet i l a s sd -> StackSet i l a s sd
focusUp = modify' focusUp'
focusDown = modify' focusDown'
swapUp = modify' swapUp'
swapDown = modify' (reverseStack . swapUp' . reverseStack)
-- | Variants of 'focusUp' and 'focusDown' that work on a
-- 'Stack' rather than an entire 'StackSet'.
focusUp', focusDown' :: Stack a -> Stack a
focusUp' (Stack t (l:ls) rs) = Stack l ls (t:rs)
focusUp' (Stack t [] rs) = Stack x xs [] where (x:xs) = reverse (t:rs)
focusDown' = reverseStack . focusUp' . reverseStack
swapUp' :: Stack a -> Stack a
swapUp' (Stack t (l:ls) rs) = Stack t ls (l:rs)
swapUp' (Stack t [] rs) = Stack t (reverse rs) []
-- | reverse a stack: up becomes down and down becomes up.
reverseStack :: Stack a -> Stack a
reverseStack (Stack t ls rs) = Stack t rs ls
--
-- | /O(1) on current window, O(n) in general/. Focus the window 'w',
-- and set its workspace as current.
--
focusWindow :: (Eq s, Eq a, Eq i) => a -> StackSet i l a s sd -> StackSet i l a s sd
focusWindow w s | Just w == peek s = s
| otherwise = fromMaybe s $ do
n <- findTag w s
return $ until ((Just w ==) . peek) focusUp (view n s)
-- | Get a list of all screens in the 'StackSet'.
screens :: StackSet i l a s sd -> [Screen i l a s sd]
screens s = current s : visible s
-- | Get a list of all workspaces in the 'StackSet'.
workspaces :: StackSet i l a s sd -> [Workspace i l a]
workspaces s = workspace (current s) : map workspace (visible s) ++ hidden s
-- | Get a list of all windows in the 'StackSet' in no particular order
allWindows :: Eq a => StackSet i l a s sd -> [a]
allWindows = L.nub . concatMap (integrate' . stack) . workspaces
-- | Get the tag of the currently focused workspace.
currentTag :: StackSet i l a s sd -> i
currentTag = tag . workspace . current
-- | Is the given tag present in the 'StackSet'?
tagMember :: Eq i => i -> StackSet i l a s sd -> Bool
tagMember t = elem t . map tag . workspaces
-- | Rename a given tag if present in the 'StackSet'.
renameTag :: Eq i => i -> i -> StackSet i l a s sd -> StackSet i l a s sd
renameTag o n = mapWorkspace rename
where rename w = if tag w == o then w { tag = n } else w
-- | Ensure that a given set of workspace tags is present by renaming
-- existing workspaces and\/or creating new hidden workspaces as
-- necessary.
ensureTags :: Eq i => l -> [i] -> StackSet i l a s sd -> StackSet i l a s sd
ensureTags l allt st = et allt (map tag (workspaces st) \\ allt) st
where et [] _ s = s
et (i:is) rn s | i `tagMember` s = et is rn s
et (i:is) [] s = et is [] (s { hidden = Workspace i l Nothing : hidden s })
et (i:is) (r:rs) s = et is rs $ renameTag r i s
-- | Map a function on all the workspaces in the 'StackSet'.
mapWorkspace :: (Workspace i l a -> Workspace i l a) -> StackSet i l a s sd -> StackSet i l a s sd
mapWorkspace f s = s { current = updScr (current s)
, visible = map updScr (visible s)
, hidden = map f (hidden s) }
where updScr scr = scr { workspace = f (workspace scr) }
-- | Map a function on all the layouts in the 'StackSet'.
mapLayout :: (l -> l') -> StackSet i l a s sd -> StackSet i l' a s sd
mapLayout f (StackSet v vs hs m) = StackSet (fScreen v) (map fScreen vs) (map fWorkspace hs) m
where
fScreen (Screen ws s sd) = Screen (fWorkspace ws) s sd
fWorkspace (Workspace t l s) = Workspace t (f l) s
-- | /O(n)/. Is a window in the 'StackSet'?
member :: Eq a => a -> StackSet i l a s sd -> Bool
member a s = isJust (findTag a s)
-- | /O(1) on current window, O(n) in general/.
-- Return 'Just' the workspace tag of the given window, or 'Nothing'
-- if the window is not in the 'StackSet'.
findTag :: Eq a => a -> StackSet i l a s sd -> Maybe i
findTag a s = listToMaybe
[ tag w | w <- workspaces s, has a (stack w) ]
where has _ Nothing = False
has x (Just (Stack t l r)) = x `elem` (t : l ++ r)
-- ---------------------------------------------------------------------
-- $modifyStackset
-- |
-- /O(n)/. (Complexity due to duplicate check). Insert a new element
-- into the stack, above the currently focused element. The new
-- element is given focus; the previously focused element is moved
-- down.
--
-- If the element is already in the stackset, the original stackset is
-- returned unmodified.
--
-- Semantics in Huet's paper is that insert doesn't move the cursor.
-- However, we choose to insert above, and move the focus.
--
insertUp :: Eq a => a -> StackSet i l a s sd -> StackSet i l a s sd
insertUp a s = if member a s then s else insert
where insert = modify (Just $ Stack a [] []) (\(Stack t l r) -> Just $ Stack a l (t:r)) s
-- insertDown :: a -> StackSet i l a s sd -> StackSet i l a s sd
-- insertDown a = modify (Stack a [] []) $ \(Stack t l r) -> Stack a (t:l) r
-- Old semantics, from Huet.
-- > w { down = a : down w }
-- |
-- /O(1) on current window, O(n) in general/. Delete window 'w' if it exists.
-- There are 4 cases to consider:
--
-- * delete on an 'Nothing' workspace leaves it Nothing
--
-- * otherwise, try to move focus to the down
--
-- * otherwise, try to move focus to the up
--
-- * otherwise, you've got an empty workspace, becomes 'Nothing'
--
-- Behaviour with respect to the master:
--
-- * deleting the master window resets it to the newly focused window
--
-- * otherwise, delete doesn't affect the master.
--
delete :: (Ord a) => a -> StackSet i l a s sd -> StackSet i l a s sd
delete w = sink w . delete' w
-- | Only temporarily remove the window from the stack, thereby not destroying special
-- information saved in the 'Stackset'
delete' :: (Eq a) => a -> StackSet i l a s sd -> StackSet i l a s sd
delete' w s = s { current = removeFromScreen (current s)
, visible = map removeFromScreen (visible s)
, hidden = map removeFromWorkspace (hidden s) }
where removeFromWorkspace ws = ws { stack = stack ws >>= filter (/=w) }
removeFromScreen scr = scr { workspace = removeFromWorkspace (workspace scr) }
------------------------------------------------------------------------
-- | Given a window, and its preferred rectangle, set it as floating
-- A floating window should already be managed by the 'StackSet'.
float :: Ord a => a -> RationalRect -> StackSet i l a s sd -> StackSet i l a s sd
float w r s = s { floating = M.insert w r (floating s) }
-- | Clear the floating status of a window
sink :: Ord a => a -> StackSet i l a s sd -> StackSet i l a s sd
sink w s = s { floating = M.delete w (floating s) }
------------------------------------------------------------------------
-- $settingMW
-- | /O(s)/. Set the master window to the focused window.
-- The old master window is swapped in the tiling order with the focused window.
-- Focus stays with the item moved.
swapMaster :: StackSet i l a s sd -> StackSet i l a s sd
swapMaster = modify' $ \c -> case c of
Stack _ [] _ -> c -- already master.
Stack t ls rs -> Stack t [] (xs ++ x : rs) where (x:xs) = reverse ls
-- natural! keep focus, move current to the top, move top to current.
-- | /O(s)/. Set the master window to the focused window.
-- The other windows are kept in order and shifted down on the stack, as if you
-- just hit mod-shift-k a bunch of times.
-- Focus stays with the item moved.
shiftMaster :: StackSet i l a s sd -> StackSet i l a s sd
shiftMaster = modify' $ \c -> case c of
Stack _ [] _ -> c -- already master.
Stack t ls rs -> Stack t [] (reverse ls ++ rs)
-- | /O(s)/. Set focus to the master window.
focusMaster :: StackSet i l a s sd -> StackSet i l a s sd
focusMaster = modify' $ \c -> case c of
Stack _ [] _ -> c
Stack t ls rs -> Stack x [] (xs ++ t : rs) where (x:xs) = reverse ls
--
-- ---------------------------------------------------------------------
-- $composite
-- | /O(w)/. shift. Move the focused element of the current stack to stack
-- 'n', leaving it as the focused element on that stack. The item is
-- inserted above the currently focused element on that workspace.
-- The actual focused workspace doesn't change. If there is no
-- element on the current stack, the original stackSet is returned.
--
shift :: (Ord a, Eq s, Eq i) => i -> StackSet i l a s sd -> StackSet i l a s sd
shift n s = maybe s (\w -> shiftWin n w s) (peek s)
-- | /O(n)/. shiftWin. Searches for the specified window 'w' on all workspaces
-- of the stackSet and moves it to stack 'n', leaving it as the focused
-- element on that stack. The item is inserted above the currently
-- focused element on that workspace.
-- The actual focused workspace doesn't change. If the window is not
-- found in the stackSet, the original stackSet is returned.
shiftWin :: (Ord a, Eq s, Eq i) => i -> a -> StackSet i l a s sd -> StackSet i l a s sd
shiftWin n w s = case findTag w s of
Just from | n `tagMember` s && n /= from -> go from s
_ -> s
where go from = onWorkspace n (insertUp w) . onWorkspace from (delete' w)
onWorkspace :: (Eq i, Eq s) => i -> (StackSet i l a s sd -> StackSet i l a s sd)
-> (StackSet i l a s sd -> StackSet i l a s sd)
onWorkspace n f s = view (currentTag s) . f . view n $ s

7
stack.yaml Normal file
View File

@@ -0,0 +1,7 @@
resolver: lts-7.19
packages:
- ./
extra-deps:
- X11-1.8

140
tests/Instances.hs Normal file
View File

@@ -0,0 +1,140 @@
{-# LANGUAGE ScopedTypeVariables #-}
module Instances where
import Test.QuickCheck
import Utils
import XMonad.StackSet
import Control.Monad
import Data.List (nub, genericLength)
import Debug.Trace
import Graphics.X11 (Rectangle(Rectangle))
import Control.Applicative
--
-- The all important Arbitrary instance for StackSet.
--
instance (Integral i, Integral s, Eq a, Arbitrary a, Arbitrary l, Arbitrary sd)
=> Arbitrary (StackSet i l a s sd) where
arbitrary = do
-- TODO: Fix this to be a reasonable higher number, Possibly use PositiveSized
numWs <- choose (1, 20) -- number of workspaces, there must be at least 1.
numScreens <- choose (1, numWs) -- number of physical screens, there must be at least 1
lay <- arbitrary -- pick any layout
wsIdxInFocus <- choose (1, numWs) -- pick index of WS to be in focus
-- The same screen id's will be present in the list, with high possibility.
screens <- replicateM numScreens arbitrary
-- Generate a list of "windows" for each workspace.
wsWindows <- vector numWs :: Gen [[a]]
-- Pick a random window "number" in each workspace, to give focus.
focus <- sequence [ if null windows
then return Nothing
else liftM Just $ choose (0, length windows - 1)
| windows <- wsWindows ]
let tags = [1 .. fromIntegral numWs]
focusWsWindows = zip focus wsWindows
wss = zip tags focusWsWindows -- tmp representation of a workspace (tag, windows)
initSs = new lay tags screens
return $
view (fromIntegral wsIdxInFocus) $
foldr (\(tag, (focus, windows)) ss -> -- Fold through all generated (tags,windows).
-- set workspace active by tag and fold through all
-- windows while inserting them. Apply the given number
-- of `focusUp` on the resulting StackSet.
applyN focus focusUp $ foldr insertUp (view tag ss) windows
) initSs wss
--
-- Just generate StackSets with Char elements.
--
type Tag = Int
type Window = Char
type T = StackSet Tag Int Window Int Int
newtype EmptyStackSet = EmptyStackSet T
deriving Show
instance Arbitrary EmptyStackSet where
arbitrary = do
(NonEmptyNubList ns) <- arbitrary
(NonEmptyNubList sds) <- arbitrary
l <- arbitrary
-- there cannot be more screens than workspaces:
return . EmptyStackSet . new l ns $ take (min (length ns) (length sds)) sds
newtype NonEmptyWindowsStackSet = NonEmptyWindowsStackSet T
deriving Show
instance Arbitrary NonEmptyWindowsStackSet where
arbitrary =
NonEmptyWindowsStackSet `fmap` (arbitrary `suchThat` (not . null . allWindows))
instance Arbitrary Rectangle where
arbitrary = Rectangle <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary
newtype SizedPositive = SizedPositive Int
deriving (Eq, Ord, Show, Read)
instance Arbitrary SizedPositive where
arbitrary = sized $ \s -> do x <- choose (1, max 1 s)
return $ SizedPositive x
newtype NonEmptyNubList a = NonEmptyNubList [a]
deriving ( Eq, Ord, Show, Read )
instance (Eq a, Arbitrary a) => Arbitrary (NonEmptyNubList a) where
arbitrary = NonEmptyNubList `fmap` ((liftM nub arbitrary) `suchThat` (not . null))
-- | Pull out an arbitrary tag from the StackSet. This removes the need for the
-- precondition "n `tagMember x` in many properties and thus reduces the number
-- of discarded tests.
--
-- n <- arbitraryTag x
--
-- We can do the reverse with a simple `suchThat`:
--
-- n <- arbitrary `suchThat` \n' -> not $ n' `tagMember` x
arbitraryTag :: T -> Gen Tag
arbitraryTag x = do
let ts = tags x
-- There must be at least 1 workspace, thus at least 1 tag.
idx <- choose (0, (length ts) - 1)
return $ ts!!idx
-- | Pull out an arbitrary window from a StackSet that is guaranteed to have a
-- non empty set of windows. This eliminates the precondition "i `member` x" in
-- a few properties.
--
--
-- foo (nex :: NonEmptyWindowsStackSet) = do
-- let NonEmptyWindowsStackSet x = nex
-- w <- arbitraryWindow nex
-- return $ .......
--
-- We can do the reverse with a simple `suchThat`:
--
-- n <- arbitrary `suchThat` \n' -> not $ n `member` x
arbitraryWindow :: NonEmptyWindowsStackSet -> Gen Window
arbitraryWindow (NonEmptyWindowsStackSet x) = do
let ws = allWindows x
-- We know that there are at least 1 window in a NonEmptyWindowsStackSet.
idx <- choose(0, (length ws) - 1)
return $ ws!!idx

View File

@@ -1,347 +1,201 @@
{-# OPTIONS -fglasgow-exts #-}
import Test.QuickCheck
import StackSet
import Operations (tile,vtile)
-- Our QC instances and properties.
import Instances
import Properties.Delete
import Properties.Failure
import Properties.Floating
import Properties.Focus
import Properties.GreedyView
import Properties.Insert
import Properties.Screen
import Properties.Shift
import Properties.Stack
import Properties.StackSet
import Properties.Swap
import Properties.View
import Properties.Workspace
import Properties.Layout.Full
import Properties.Layout.Tall
import Debug.Trace
import Data.Word
import Graphics.X11.Xlib.Types (Rectangle(..),Position,Dimension)
import Data.Ratio
import Data.Maybe
import System.Environment
import Control.Exception (assert)
import Control.Monad
import Test.QuickCheck hiding (promote)
import System.IO
import System.Random
import Text.Printf
import Data.List (nub,sort,group,sort,intersperse)
import Data.Map (keys,elems)
-- ---------------------------------------------------------------------
-- QuickCheck properties for the StackSet
-- | Height of stack 'n'
height :: Int -> T -> Int
height i w = length (index i w)
-- build (non-empty) StackSets with between 1 and 100 stacks
instance (Integral i, Integral j, Ord a, Arbitrary a) => Arbitrary (StackSet i j a) where
arbitrary = do
sz <- choose (1,20)
n <- choose (0,sz-1)
sc <- choose (1,sz)
ls <- vector sz
return $ fromList (fromIntegral n,sc,ls)
coarbitrary = error "no coarbitrary for StackSet"
prop_id x = fromList (toList x) == x
where _ = x :: T
prop_member1 i n m = member i (push i x)
where x = empty n m :: T
prop_member2 i x = not (member i (delete i x))
where _ = x :: T
prop_member3 i n m = member i (empty n m :: T) == False
prop_sizepush is n m = n > 0 ==> size (foldr push x is ) == n
where x = empty n m :: T
prop_currentpush is n m = n > 0 ==>
height (current x) (foldr push x js) == length js
where
js = nub is
x = empty n m :: T
prop_pushpeek x is = not (null is) ==> fromJust (peek (foldr push x is)) == head is
where _ = x :: T
prop_peekmember x = case peek x of
Just w -> member w x
Nothing -> True {- then we don't know anything -}
where _ = x :: T
prop_peek_peekStack n x =
if current x == n then peekStack n x == peek x
else True -- so we don't exhaust
where _ = x :: T
prop_notpeek_peekStack n x = current x /= n && isJust (peek x) ==> peekStack n x /= peek x
where _ = x :: T
------------------------------------------------------------------------
type T = StackSet Int Int Int
prop_delete_uniq i x = not (member i x) ==> delete i x == x
where _ = x :: T
prop_delete_push i x = not (member i x) ==> delete i (push i x) == x
where _ = x :: T
prop_delete2 i x =
delete i x == delete i (delete i x)
where _ = x :: T
prop_focus1 i x = member i x ==> peek (raiseFocus i x) == Just i
where _ = x :: T
prop_rotaterotate x = rotate LT (rotate GT x) == x
where _ = x :: T
prop_viewview r x =
let n = current x
sz = size x
i = r `mod` sz
in view n (view (fromIntegral i) x) == x
where _ = x :: T
prop_shiftshift r x =
let n = current x
in shift n (shift r x) == x
where _ = x :: T
prop_fullcache x = cached == allvals where
cached = sort . keys $ cache x
allvals = sort . concat . elems $ stacks x
_ = x :: T
prop_currentwsvisible x = (current x) `elem` (visibleWorkspaces x)
where _ = x :: T
prop_ws2screen_screen2ws x = (ws == ws') && (sc == sc')
where ws = sort . keys $ ws2screen x
ws' = sort . elems $ screen2ws x
sc = sort . keys $ screen2ws x
sc' = sort . elems $ ws2screen x
_ = x :: T
prop_screenworkspace x = all test [0..((fromIntegral $ size x)-1)]
where test ws = case screen ws x of
Nothing -> True
Just sc -> workspace sc x == Just ws
_ = x :: T
prop_swap a b xs = swap a b (swap a b ys) == ys
where ys = nub xs :: [Int]
------------------------------------------------------------------------
-- promote is idempotent
prop_promote2 x = promote (promote x) == (promote x)
where _ = x :: T
-- focus doesn't change
prop_promotefocus x = focus (promote x) == focus x
where _ = x :: T
-- screen certainly should't change
prop_promotecurrent x = current (promote x) == current x
where _ = x :: T
-- the physical screen doesn't change
prop_promotescreen n x = screen n (promote x) == screen n x
where _ = x :: T
-- promote doesn't mess with other windows
prop_promoterotate x b = focus (rotate dir (promote x)) == focus (rotate dir x)
where _ = x :: T
dir = if b then LT else GT
------------------------------------------------------------------------
-- some properties for layouts:
-- 1 window should always be tiled fullscreen
prop_tile_fullscreen rect = tile pct rect [1] == [(1, rect)]
prop_vtile_fullscreen rect = vtile pct rect [1] == [(1, rect)]
-- multiple windows
prop_tile_non_overlap rect windows = noOverlaps (tile pct rect windows)
where _ = rect :: Rectangle
prop_vtile_non_overlap rect windows = noOverlaps (vtile pct rect windows)
where _ = rect :: Rectangle
pct = 3 % 100
noOverlaps [] = True
noOverlaps [_] = True
noOverlaps xs = and [ verts a `notOverlap` verts b
| (_,a) <- xs
, (_,b) <- filter (\(_,b) -> a /= b) xs
]
where
verts (Rectangle a b w h) = (a,b,a + fromIntegral w - 1, b + fromIntegral h - 1)
notOverlap (left1,bottom1,right1,top1)
(left2,bottom2,right2,top2)
= (top1 < bottom2 || top2 < bottom1)
|| (right1 < left2 || right2 < left1)
------------------------------------------------------------------------
instance Random Word8 where
randomR = integralRandomR
random = randomR (minBound,maxBound)
instance Arbitrary Word8 where
arbitrary = choose (minBound,maxBound)
coarbitrary n = variant (fromIntegral ((fromIntegral n) `rem` 4))
instance Random Word64 where
randomR = integralRandomR
random = randomR (minBound,maxBound)
instance Arbitrary Word64 where
arbitrary = choose (minBound,maxBound)
coarbitrary n = variant (fromIntegral ((fromIntegral n) `rem` 4))
integralRandomR :: (Integral a, RandomGen g) => (a,a) -> g -> (a,g)
integralRandomR (a,b) g = case randomR (fromIntegral a :: Integer,
fromIntegral b :: Integer) g of
(x,g) -> (fromIntegral x, g)
instance Arbitrary Position where
arbitrary = do n <- arbitrary :: Gen Word8
return (fromIntegral n)
coarbitrary = undefined
instance Arbitrary Dimension where
arbitrary = do n <- arbitrary :: Gen Word8
return (fromIntegral n)
coarbitrary = undefined
instance Arbitrary Rectangle where
arbitrary = do
sx <- arbitrary
sy <- arbitrary
sw <- arbitrary
sh <- arbitrary
return $ Rectangle sx sy sw sh
instance Arbitrary Rational where
arbitrary = do
n <- arbitrary
d' <- arbitrary
let d = if d' == 0 then 1 else d'
return (n % d)
coarbitrary = undefined
------------------------------------------------------------------------
import Control.Monad
import Control.Applicative
main :: IO ()
main = do
args <- getArgs
let n = if null args then 100 else read (head args)
mapM_ (\(s,a) -> printf "%-25s: " s >> a n) tests
where
n = 100
arg <- fmap (drop 1) getArgs
let n = if null arg then 100 else read $ head arg
args = stdArgs { maxSuccess = n, maxSize = 100 }
qc t = do
c <- quickCheckWithResult args t
case c of
Success {} -> return True
_ -> return False
perform (s, t) = printf "%-35s: " s >> qc t
n <- length . filter not <$> mapM perform tests
unless (n == 0) (error (show n ++ " test(s) failed"))
tests =
[("read.show ", mytest prop_id)
,("member/push ", mytest prop_member1)
,("member/peek ", mytest prop_peekmember)
,("member/delete ", mytest prop_member2)
,("member/empty ", mytest prop_member3)
,("size/push ", mytest prop_sizepush)
,("height/push ", mytest prop_currentpush)
,("push/peek ", mytest prop_pushpeek)
tests =
[("StackSet invariants", property prop_invariant)
,("empty: invariant", property prop_empty_I)
,("empty is empty", property prop_empty)
,("empty / current", property prop_empty_current)
,("empty / member", property prop_member_empty)
,("peek/peekStack" , mytest prop_peek_peekStack)
,("not . peek/peekStack", mytest prop_notpeek_peekStack)
,("delete/not.member", mytest prop_delete_uniq)
,("delete idempotent", mytest prop_delete2)
,("delete.push identity" , mytest prop_delete_push)
,("view : invariant", property prop_view_I)
,("view sets current", property prop_view_current)
,("view idempotent", property prop_view_idem)
,("view reversible", property prop_view_reversible)
,("focus", mytest prop_focus1)
,("view is local", property prop_view_local)
,("rotate/rotate ", mytest prop_rotaterotate)
,("greedyView : invariant", property prop_greedyView_I)
,("greedyView sets current", property prop_greedyView_current)
,("greedyView is safe", property prop_greedyView_current_id)
,("greedyView idempotent", property prop_greedyView_idem)
,("greedyView reversible", property prop_greedyView_reversible)
,("greedyView is local", property prop_greedyView_local)
,("view/view ", mytest prop_viewview)
,("fullcache ", mytest prop_fullcache)
,("currentwsvisible ", mytest prop_currentwsvisible)
,("ws screen mapping", mytest prop_ws2screen_screen2ws)
,("screen/workspace ", mytest prop_screenworkspace)
,("peek/member", property prop_member_peek)
,("promote idempotent", mytest prop_promote2)
,("promote focus", mytest prop_promotefocus)
,("promote current", mytest prop_promotecurrent)
,("promote only swaps", mytest prop_promoterotate)
,("promote/screen" , mytest prop_promotescreen)
,("index/length", property prop_index_length)
,("swap", mytest prop_swap)
,("focus left : invariant", property prop_focusUp_I)
,("focus master : invariant", property prop_focusMaster_I)
,("focus right: invariant", property prop_focusDown_I)
,("focusWindow: invariant", property prop_focus_I)
,("focus left/master", property prop_focus_left_master)
,("focus right/master", property prop_focus_right_master)
,("focus master/master", property prop_focus_master_master)
,("focusWindow master", property prop_focusWindow_master)
,("focus left/right", property prop_focus_left)
,("focus right/left", property prop_focus_right)
,("focus all left", property prop_focus_all_l)
,("focus all right", property prop_focus_all_r)
,("focus down is local", property prop_focus_down_local)
,("focus up is local", property prop_focus_up_local)
,("focus master is local", property prop_focus_master_local)
,("focus master idemp", property prop_focusMaster_idem)
------------------------------------------------------------------------
,("focusWindow is local", property prop_focusWindow_local)
,("focusWindow works" , property prop_focusWindow_works)
,("focusWindow identity", property prop_focusWindow_identity)
,("tile 1 window fullsize", mytest prop_tile_fullscreen)
,("vtile 1 window fullsize", mytest prop_vtile_fullscreen)
,("vtiles never overlap", mytest prop_vtile_non_overlap )
,("findTag", property prop_findIndex)
,("allWindows/member", property prop_allWindowsMember)
,("currentTag", property prop_currentTag)
]
,("insert: invariant", property prop_insertUp_I)
,("insert/new", property prop_insert_empty)
,("insert is idempotent", property prop_insert_idem)
,("insert is reversible", property prop_insert_delete)
,("insert is local", property prop_insert_local)
,("insert duplicates", property prop_insert_duplicate)
,("insert/peek", property prop_insert_peek)
,("insert/size", property prop_size_insert)
debug = False
,("delete: invariant", property prop_delete_I)
,("delete/empty", property prop_empty)
,("delete/member", property prop_delete)
,("delete is reversible", property prop_delete_insert)
,("delete is local", property prop_delete_local)
,("delete/focus", property prop_delete_focus)
,("delete last/focus up", property prop_delete_focus_end)
,("delete ~last/focus down", property prop_delete_focus_not_end)
mytest :: Testable a => a -> Int -> IO ()
mytest a n = mycheck defaultConfig
{ configMaxTest=n
, configEvery= \n args -> if debug then show n ++ ":\n" ++ unlines args else [] } a
,("filter preserves order", property prop_filter_order)
mycheck :: Testable a => Config -> a -> IO ()
mycheck config a = do
rnd <- newStdGen
mytests config (evaluate a) rnd 0 0 []
,("swapLeft", property prop_swap_left)
,("swapRight", property prop_swap_right)
mytests :: Config -> Gen Result -> StdGen -> Int -> Int -> [[String]] -> IO ()
mytests config gen rnd0 ntest nfail stamps
| ntest == configMaxTest config = do done "OK," ntest stamps
| nfail == configMaxFail config = do done "Arguments exhausted after" ntest stamps
| otherwise =
do putStr (configEvery config ntest (arguments result)) >> hFlush stdout
case ok result of
Nothing ->
mytests config gen rnd1 ntest (nfail+1) stamps
Just True ->
mytests config gen rnd1 (ntest+1) nfail (stamp result:stamps)
Just False ->
putStr ( "Falsifiable after "
++ show ntest
++ " tests:\n"
++ unlines (arguments result)
) >> hFlush stdout
where
result = generate (configSize config ntest) rnd2 gen
(rnd1,rnd2) = split rnd0
,("swapMaster: invariant", property prop_swap_master_I)
,("swapUp: invariant" , property prop_swap_left_I)
,("swapDown: invariant", property prop_swap_right_I)
,("swapMaster id on focus", property prop_swap_master_focus)
,("swapUp id on focus", property prop_swap_left_focus)
,("swapDown id on focus", property prop_swap_right_focus)
,("swapMaster is idempotent", property prop_swap_master_idempotent)
,("swap all left", property prop_swap_all_l)
,("swap all right", property prop_swap_all_r)
,("swapMaster is local", property prop_swap_master_local)
,("swapUp is local", property prop_swap_left_local)
,("swapDown is local", property prop_swap_right_local)
done :: String -> Int -> [[String]] -> IO ()
done mesg ntest stamps = putStr ( mesg ++ " " ++ show ntest ++ " tests" ++ table )
where
table = display
. map entry
. reverse
. sort
. map pairLength
. group
. sort
. filter (not . null)
$ stamps
,("shiftMaster id on focus", property prop_shift_master_focus)
,("shiftMaster is local", property prop_shift_master_local)
,("shiftMaster is idempotent", property prop_shift_master_idempotent)
,("shiftMaster preserves ordering", property prop_shift_master_ordering)
display [] = ".\n"
display [x] = " (" ++ x ++ ").\n"
display xs = ".\n" ++ unlines (map (++ ".") xs)
,("shift: invariant" , property prop_shift_I)
,("shift is reversible" , property prop_shift_reversible)
,("shiftWin: invariant" , property prop_shift_win_I)
,("shiftWin is shift on focus", property prop_shift_win_focus)
,("shiftWin fix current" , property prop_shift_win_fix_current)
,("shiftWin identity", property prop_shift_win_indentity)
pairLength xss@(xs:_) = (length xss, xs)
entry (n, xs) = percentage n ntest
++ " "
++ concat (intersperse ", " xs)
,("floating is reversible" , property prop_float_reversible)
,("floating sets geometry" , property prop_float_geometry)
,("floats can be deleted", property prop_float_delete)
,("screens includes current", property prop_screens)
,("differentiate works", property prop_differentiate)
,("lookupTagOnScreen", property prop_lookup_current)
,("lookupTagOnVisbleScreen", property prop_lookup_visible)
,("screens works", property prop_screens_works)
,("renaming works", property prop_rename1)
,("ensure works", property prop_ensure)
,("ensure hidden semantics", property prop_ensure_append)
,("mapWorkspace id", property prop_mapWorkspaceId)
,("mapWorkspace inverse", property prop_mapWorkspaceInverse)
,("mapLayout id", property prop_mapLayoutId)
,("mapLayout inverse", property prop_mapLayoutInverse)
,("abort fails", property prop_abort)
,("new fails with abort", property prop_new_abort)
,("point within", property prop_point_within)
-- tall layout
,("tile 1 window fullsize", property prop_tile_fullscreen)
,("tiles never overlap", property prop_tile_non_overlap)
,("split horizontal", property prop_split_horizontal)
,("split vertical", property prop_split_vertical)
,("pure layout tall", property prop_purelayout_tall)
,("send shrink tall", property prop_shrink_tall)
,("send expand tall", property prop_expand_tall)
,("send incmaster tall", property prop_incmaster_tall)
-- full layout
,("pure layout full", property prop_purelayout_full)
,("send message full", property prop_sendmsg_full)
,("describe full", property prop_desc_full)
,("describe mirror", property prop_desc_mirror)
-- resize hints
,("window resize hints: inc", property prop_resize_inc)
,("window resize hints: inc all", property prop_resize_inc_extra)
,("window resize hints: max", property prop_resize_max)
,("window resize hints: max all ", property prop_resize_max_extra)
,("window aspect hints: fits", property prop_aspect_fits)
,("window aspect hints: shrinks ", property prop_aspect_hint_shrink)
,("pointWithin", property prop_point_within)
,("pointWithin mirror", property prop_point_within_mirror)
]
percentage n m = show ((100 * n) `div` m) ++ "%"
------------------------------------------------------------------------

View File

@@ -0,0 +1,70 @@
{-# LANGUAGE ScopedTypeVariables #-}
module Properties.Delete where
import Test.QuickCheck
import Instances
import Utils
import XMonad.StackSet hiding (filter)
-- ---------------------------------------------------------------------
-- 'delete'
-- deleting the current item removes it.
prop_delete x =
case peek x of
Nothing -> True
Just i -> not (member i (delete i x))
where _ = x :: T
-- delete is reversible with 'insert'.
-- It is the identiy, except for the 'master', which is reset on insert and delete.
--
prop_delete_insert (x :: T) =
case peek x of
Nothing -> True
Just n -> insertUp n (delete n y) == y
where
y = swapMaster x
-- delete should be local
prop_delete_local (x :: T) =
case peek x of
Nothing -> True
Just i -> hidden_spaces x == hidden_spaces (delete i x)
-- delete should not affect focus unless the focused element is what is being deleted
prop_delete_focus = do
-- There should be at least two windows. One in focus, and some to try and
-- delete (doesn't have to be windows on the current workspace). We generate
-- our own, since we can't rely on NonEmptyWindowsStackSet returning one in
-- the argument with at least two windows.
x <- arbitrary `suchThat` \x' -> length (allWindows x') >= 2
w <- arbitraryWindow (NonEmptyWindowsStackSet x)
-- Make sure we pick a window that is NOT the currently focused
`suchThat` \w' -> Just w' /= peek x
return $ peek (delete w x) == peek x
-- focus movement in the presence of delete:
-- when the last window in the stack set is focused, focus moves `up'.
-- usual case is that it moves 'down'.
prop_delete_focus_end = do
-- Generate a StackSet with at least two windows on the current workspace.
x <- arbitrary `suchThat` \(x' :: T) -> length (index x') >= 2
let w = last (index x)
y = focusWindow w x -- focus last window in stack
return $ peek (delete w y) == peek (focusUp y)
-- focus movement in the presence of delete:
-- when not in the last item in the stack, focus moves down
prop_delete_focus_not_end = do
x <- arbitrary
-- There must be at least two windows and the current focused is not the
-- last one in the stack.
`suchThat` \(x' :: T) ->
let currWins = index x'
in length (currWins) >= 2 && peek x' /= Just (last currWins)
-- This is safe, as we know there are >= 2 windows
let Just n = peek x
return $ peek (delete n x) == peek (focusDown x)

View File

@@ -0,0 +1,30 @@
module Properties.Failure where
import XMonad.StackSet hiding (filter)
import qualified Control.Exception.Extensible as C
import System.IO.Unsafe
import Data.List (isPrefixOf)
-- ---------------------------------------------------------------------
-- testing for failure and help out hpc
--
-- Since base 4.9.0.0 `error` appends a stack trace. The tests below
-- use `isPrefixOf` to only test equality on the error message.
--
prop_abort :: Int -> Bool
prop_abort _ = unsafePerformIO $ C.catch (abort "fail") check
where
check (C.SomeException e) =
return $ "xmonad: StackSet: fail" `isPrefixOf` show e
-- new should fail with an abort
prop_new_abort :: Int -> Bool
prop_new_abort _ = unsafePerformIO $ C.catch f check
where
f = new undefined{-layout-} [] [] `seq` return False
check (C.SomeException e) =
return $ "xmonad: StackSet: non-positive argument to StackSet.new" `isPrefixOf` show e
-- TODO: Fix this?
-- prop_view_should_fail = view {- with some bogus data -}

View File

@@ -0,0 +1,36 @@
{-# LANGUAGE ScopedTypeVariables #-}
module Properties.Floating where
import Test.QuickCheck
import Instances
import XMonad.StackSet hiding (filter)
import qualified Data.Map as M
------------------------------------------------------------------------
-- properties for the floating layer:
prop_float_reversible (nex :: NonEmptyWindowsStackSet) = do
let NonEmptyWindowsStackSet x = nex
w <- arbitraryWindow nex
return $ sink w (float w geom x) == x
where
geom = RationalRect 100 100 100 100
prop_float_geometry (nex :: NonEmptyWindowsStackSet) = do
let NonEmptyWindowsStackSet x = nex
w <- arbitraryWindow nex
let s = float w geom x
return $ M.lookup w (floating s) == Just geom
where
geom = RationalRect 100 100 100 100
prop_float_delete (nex :: NonEmptyWindowsStackSet) = do
let NonEmptyWindowsStackSet x = nex
w <- arbitraryWindow nex
let s = float w geom x
t = delete w s
return $ not (w `member` t)
where
geom = RationalRect 100 100 100 100

74
tests/Properties/Focus.hs Normal file
View File

@@ -0,0 +1,74 @@
{-# LANGUAGE ScopedTypeVariables #-}
module Properties.Focus where
import Test.QuickCheck
import Instances
import Utils
import XMonad.StackSet hiding (filter)
import Data.Maybe (fromJust)
-- ---------------------------------------------------------------------
-- rotating focus
--
-- master/focus
--
-- The tiling order, and master window, of a stack is unaffected by focus changes.
--
prop_focus_left_master (SizedPositive n) (x::T) =
index (applyN (Just n) focusUp x) == index x
prop_focus_right_master (SizedPositive n) (x::T) =
index (applyN (Just n) focusDown x) == index x
prop_focus_master_master (SizedPositive n) (x::T) =
index (applyN (Just n) focusMaster x) == index x
prop_focusWindow_master (NonNegative n) (x :: T) =
case peek x of
Nothing -> True
Just _ -> let s = index x
i = n `mod` length s
in index (focusWindow (s !! i) x) == index x
-- shifting focus is trivially reversible
prop_focus_left (x :: T) = (focusUp (focusDown x)) == x
prop_focus_right (x :: T) = (focusDown (focusUp x)) == x
-- focus master is idempotent
prop_focusMaster_idem (x :: T) = focusMaster x == focusMaster (focusMaster x)
-- focusWindow actually leaves the window focused...
prop_focusWindow_works (NonNegative (n :: Int)) (x :: T) =
case peek x of
Nothing -> True
Just _ -> let s = index x
i = fromIntegral n `mod` length s
in (focus . fromJust . stack . workspace . current) (focusWindow (s !! i) x) == (s !! i)
-- rotation through the height of a stack gets us back to the start
prop_focus_all_l (x :: T) = (foldr (const focusUp) x [1..n]) == x
where n = length (index x)
prop_focus_all_r (x :: T) = (foldr (const focusDown) x [1..n]) == x
where n = length (index x)
-- prop_rotate_all (x :: T) = f (f x) == f x
-- f x' = foldr (\_ y -> rotate GT y) x' [1..n]
-- focus is local to the current workspace
prop_focus_down_local (x :: T) = hidden_spaces (focusDown x) == hidden_spaces x
prop_focus_up_local (x :: T) = hidden_spaces (focusUp x) == hidden_spaces x
prop_focus_master_local (x :: T) = hidden_spaces (focusMaster x) == hidden_spaces x
prop_focusWindow_local (NonNegative (n :: Int)) (x::T ) =
case peek x of
Nothing -> True
Just _ -> let s = index x
i = fromIntegral n `mod` length s
in hidden_spaces (focusWindow (s !! i) x) == hidden_spaces x
-- On an invalid window, the stackset is unmodified
prop_focusWindow_identity (x::T ) = do
n <- arbitrary `suchThat` \n' -> not $ n' `member` x
return $ focusWindow n x == x

View File

@@ -0,0 +1,44 @@
{-# LANGUAGE ScopedTypeVariables #-}
module Properties.GreedyView where
import Test.QuickCheck
import Instances
import Utils
import XMonad.StackSet hiding (filter)
import Data.List (sortBy)
-- ---------------------------------------------------------------------
-- greedyViewing workspaces
-- greedyView sets the current workspace to 'n'
prop_greedyView_current (x :: T) = do
n <- arbitraryTag x
return $ currentTag (greedyView n x) == n
-- greedyView leaves things unchanged for invalid workspaces
prop_greedyView_current_id (x :: T) = do
n <- arbitrary `suchThat` \n' -> not $ n' `tagMember` x
return $ currentTag (greedyView n x) == currentTag x
-- greedyView *only* sets the current workspace, and touches Xinerama.
-- no workspace contents will be changed.
prop_greedyView_local (x :: T) = do
n <- arbitraryTag x
return $ workspaces x == workspaces (greedyView n x)
where
workspaces a = sortBy (\s t -> tag s `compare` tag t) $
workspace (current a)
: map workspace (visible a) ++ hidden a
-- greedyView is idempotent
prop_greedyView_idem (x :: T) = do
n <- arbitraryTag x
return $ greedyView n (greedyView n x) == (greedyView n x)
-- greedyView is reversible, though shuffles the order of hidden/visible
prop_greedyView_reversible (x :: T) = do
n <- arbitraryTag x
return $ normal (greedyView n' (greedyView n x)) == normal x
where n' = currentTag x

View File

@@ -0,0 +1,52 @@
{-# LANGUAGE ScopedTypeVariables #-}
module Properties.Insert where
import Test.QuickCheck
import Instances
import Utils
import XMonad.StackSet hiding (filter)
import Data.List (nub)
-- ---------------------------------------------------------------------
-- 'insert'
-- inserting a item into an empty stackset means that item is now a member
prop_insert_empty i (EmptyStackSet x)= member i (insertUp i x)
-- insert should be idempotent
prop_insert_idem i (x :: T) = insertUp i x == insertUp i (insertUp i x)
-- insert when an item is a member should leave the stackset unchanged
prop_insert_duplicate (nex :: NonEmptyWindowsStackSet) = do
let NonEmptyWindowsStackSet x = nex
w <- arbitraryWindow nex
return $ insertUp w x == x
-- push shouldn't change anything but the current workspace
prop_insert_local (x :: T) = do
i <- arbitrary `suchThat` \i' -> not $ i' `member` x
return $ hidden_spaces x == hidden_spaces (insertUp i x)
-- Inserting a (unique) list of items into an empty stackset should
-- result in the last inserted element having focus.
prop_insert_peek (EmptyStackSet x) (NonEmptyNubList is) =
peek (foldr insertUp x is) == Just (head is)
-- insert >> delete is the identity, when i `notElem` .
-- Except for the 'master', which is reset on insert and delete.
--
prop_insert_delete x = do
n <- arbitrary `suchThat` \n -> not $ n `member` x
return $ delete n (insertUp n y) == (y :: T)
where
y = swapMaster x -- sets the master window to the current focus.
-- otherwise, we don't have a rule for where master goes.
-- inserting n elements increases current stack size by n
prop_size_insert is (EmptyStackSet x) =
size (foldr insertUp x ws ) == (length ws)
where
ws = nub is
size = length . index

View File

@@ -0,0 +1,34 @@
{-# LANGUAGE ScopedTypeVariables #-}
module Properties.Layout.Full where
import Test.QuickCheck
import Instances
import XMonad.StackSet hiding (filter)
import XMonad.Core
import XMonad.Layout
import Data.Maybe
------------------------------------------------------------------------
-- Full layout
-- pureLayout works for Full
prop_purelayout_full rect = do
x <- (arbitrary :: Gen T) `suchThat` (isJust . peek)
let layout = Full
st = fromJust . stack . workspace . current $ x
ts = pureLayout layout rect st
return $
length ts == 1 -- only one window to view
&&
snd (head ts) == rect -- and sets fullscreen
&&
fst (head ts) == fromJust (peek x) -- and the focused window is shown
-- what happens when we send an IncMaster message to Full --- Nothing
prop_sendmsg_full (NonNegative k) =
isNothing (Full `pureMessage` (SomeMessage (IncMasterN k)))
prop_desc_full = description Full == show Full

View File

@@ -0,0 +1,116 @@
{-# LANGUAGE ScopedTypeVariables #-}
module Properties.Layout.Tall where
import Test.QuickCheck
import Instances
import Utils
import XMonad.StackSet hiding (filter)
import XMonad.Core
import XMonad.Layout
import Graphics.X11.Xlib.Types (Rectangle(..))
import Data.Maybe
import Data.List (sort)
import Data.Ratio
------------------------------------------------------------------------
-- The Tall layout
-- 1 window should always be tiled fullscreen
prop_tile_fullscreen rect = tile pct rect 1 1 == [rect]
where pct = 1/2
-- multiple windows
prop_tile_non_overlap rect windows nmaster = noOverlaps (tile pct rect nmaster windows)
where _ = rect :: Rectangle
pct = 3 % 100
-- splitting horizontally yields sensible results
prop_split_horizontal (NonNegative n) x =
(noOverflows (+) (rect_x x) (rect_width x)) ==>
sum (map rect_width xs) == rect_width x
&&
all (== rect_height x) (map rect_height xs)
&&
(map rect_x xs) == (sort $ map rect_x xs)
where
xs = splitHorizontally n x
-- splitting vertically yields sensible results
prop_split_vertical (r :: Rational) x =
rect_x x == rect_x a && rect_x x == rect_x b
&&
rect_width x == rect_width a && rect_width x == rect_width b
where
(a,b) = splitVerticallyBy r x
-- pureLayout works.
prop_purelayout_tall n r1 r2 rect = do
x <- (arbitrary :: Gen T) `suchThat` (isJust . peek)
let layout = Tall n r1 r2
st = fromJust . stack . workspace . current $ x
ts = pureLayout layout rect st
return $
length ts == length (index x)
&&
noOverlaps (map snd ts)
&&
description layout == "Tall"
-- Test message handling of Tall
-- what happens when we send a Shrink message to Tall
prop_shrink_tall (NonNegative n) (Positive delta) (NonNegative frac) =
n == n' && delta == delta' -- these state components are unchanged
&& frac' <= frac && (if frac' < frac then frac' == 0 || frac' == frac - delta
else frac == 0 )
-- remaining fraction should shrink
where
l1 = Tall n delta frac
Just l2@(Tall n' delta' frac') = l1 `pureMessage` (SomeMessage Shrink)
-- pureMessage :: layout a -> SomeMessage -> Maybe (layout a)
-- what happens when we send a Shrink message to Tall
prop_expand_tall (NonNegative n)
(Positive delta)
(NonNegative n1)
(Positive d1) =
n == n'
&& delta == delta' -- these state components are unchanged
&& frac' >= frac
&& (if frac' > frac
then frac' == 1 || frac' == frac + delta
else frac == 1 )
-- remaining fraction should shrink
where
frac = min 1 (n1 % d1)
l1 = Tall n delta frac
Just l2@(Tall n' delta' frac') = l1 `pureMessage` (SomeMessage Expand)
-- pureMessage :: layout a -> SomeMessage -> Maybe (layout a)
-- what happens when we send an IncMaster message to Tall
prop_incmaster_tall (NonNegative n) (Positive delta) (NonNegative frac)
(NonNegative k) =
delta == delta' && frac == frac' && n' == n + k
where
l1 = Tall n delta frac
Just l2@(Tall n' delta' frac') = l1 `pureMessage` (SomeMessage (IncMasterN k))
-- pureMessage :: layout a -> SomeMessage -> Maybe (layout a)
-- toMessage LT = SomeMessage Shrink
-- toMessage EQ = SomeMessage Expand
-- toMessage GT = SomeMessage (IncMasterN 1)
prop_desc_mirror n r1 r2 = description (Mirror $! t) == "Mirror Tall"
where t = Tall n r1 r2

View File

@@ -0,0 +1,73 @@
{-# LANGUAGE ScopedTypeVariables #-}
module Properties.Screen where
import Utils
import Test.QuickCheck
import Instances
import Control.Applicative
import XMonad.StackSet hiding (filter)
import XMonad.Operations
import Graphics.X11.Xlib.Types (Dimension)
import Graphics.X11 (Rectangle(Rectangle))
import XMonad.Layout
prop_screens (x :: T) = n `elem` screens x
where
n = current x
-- screens makes sense
prop_screens_works (x :: T) = screens x == current x : visible x
------------------------------------------------------------------------
-- Hints
prop_resize_inc (Positive inc_w,Positive inc_h) b@(w,h) =
w' `mod` inc_w == 0 && h' `mod` inc_h == 0
where (w',h') = applyResizeIncHint a b
a = (inc_w,inc_h)
prop_resize_inc_extra ((NonNegative inc_w)) b@(w,h) =
(w,h) == (w',h')
where (w',h') = applyResizeIncHint a b
a = (-inc_w,0::Dimension)-- inc_h)
prop_resize_max (Positive inc_w,Positive inc_h) b@(w,h) =
w' <= inc_w && h' <= inc_h
where (w',h') = applyMaxSizeHint a b
a = (inc_w,inc_h)
prop_resize_max_extra ((NonNegative inc_w)) b@(w,h) =
(w,h) == (w',h')
where (w',h') = applyMaxSizeHint a b
a = (-inc_w,0::Dimension)-- inc_h)
prop_aspect_hint_shrink hint (w,h) = case applyAspectHint hint (w,h) of
(w',h') -> w' <= w && h' <= h
-- applyAspectHint does nothing when the supplied (x,y) fits
-- the desired range
prop_aspect_fits =
forAll ((,,,) <$> pos <*> pos <*> pos <*> pos) $ \ (x,y,a,b) ->
let f v = applyAspectHint ((x, y+a), (x+b, y)) v
in and [ noOverflows (*) x (y+a), noOverflows (*) (x+b) y ]
==> f (x,y) == (x,y)
where pos = choose (0, 65535)
mul a b = toInteger (a*b) /= toInteger a * toInteger b
prop_point_within r @ (Rectangle x y w h) =
forAll ((,) <$>
choose (0, fromIntegral w - 1) <*>
choose (0, fromIntegral h - 1)) $
\(dx,dy) ->
and [ dx > 0, dy > 0,
noOverflows (\ a b -> a + abs b) x w,
noOverflows (\ a b -> a + abs b) y h ]
==> pointWithin (x+dx) (y+dy) r
prop_point_within_mirror r (x,y) = pointWithin x y r == pointWithin y x (mirrorRect r)

70
tests/Properties/Shift.hs Normal file
View File

@@ -0,0 +1,70 @@
{-# LANGUAGE ScopedTypeVariables #-}
module Properties.Shift where
import Test.QuickCheck
import Instances
import Utils
import XMonad.StackSet hiding (filter)
import qualified Data.List as L
-- ---------------------------------------------------------------------
-- shift
-- shift is fully reversible on current window, when focus and master
-- are the same. otherwise, master may move.
prop_shift_reversible (x :: T) = do
i <- arbitraryTag x
case peek y of
Nothing -> return True
Just _ -> return $ normal ((view n . shift n . view i . shift i) y) == normal y
where
y = swapMaster x
n = currentTag y
------------------------------------------------------------------------
-- shiftMaster
-- focus/local/idempotent same as swapMaster:
prop_shift_master_focus (x :: T) = peek x == (peek $ shiftMaster x)
prop_shift_master_local (x :: T) = hidden_spaces x == hidden_spaces (shiftMaster x)
prop_shift_master_idempotent (x :: T) = shiftMaster (shiftMaster x) == shiftMaster x
-- ordering is constant modulo the focused window:
prop_shift_master_ordering (x :: T) = case peek x of
Nothing -> True
Just m -> L.delete m (index x) == L.delete m (index $ shiftMaster x)
-- ---------------------------------------------------------------------
-- shiftWin
-- shiftWin on current window is the same as shift
prop_shift_win_focus (x :: T) = do
n <- arbitraryTag x
case peek x of
Nothing -> return True
Just w -> return $ shiftWin n w x == shift n x
-- shiftWin on a non-existant window is identity
prop_shift_win_indentity (x :: T) = do
n <- arbitraryTag x
w <- arbitrary `suchThat` \w' -> not (w' `member` x)
return $ shiftWin n w x == x
-- shiftWin leaves the current screen as it is, if neither n is the tag
-- of the current workspace nor w on the current workspace
prop_shift_win_fix_current = do
x <- arbitrary `suchThat` \(x' :: T) ->
-- Invariant, otherWindows are NOT in the current workspace.
let otherWindows = allWindows x' L.\\ index x'
in length(tags x') >= 2 && length(otherWindows) >= 1
-- Sadly we have to construct `otherWindows` again, for the actual StackSet
-- that got chosen.
let otherWindows = allWindows x L.\\ index x
-- We know such tag must exists, due to the precondition
n <- arbitraryTag x `suchThat` (/= currentTag x)
-- we know length is >= 1, from above precondition
idx <- choose(0, length(otherWindows) - 1)
let w = otherWindows !! idx
return $ (current $ x) == (current $ shiftWin n w x)

51
tests/Properties/Stack.hs Normal file
View File

@@ -0,0 +1,51 @@
{-# LANGUAGE ScopedTypeVariables #-}
module Properties.Stack where
import Test.QuickCheck
import Instances
import XMonad.StackSet hiding (filter)
import qualified XMonad.StackSet as S (filter)
import Data.Maybe
-- The list returned by index should be the same length as the actual
-- windows kept in the zipper
prop_index_length (x :: T) =
case stack . workspace . current $ x of
Nothing -> length (index x) == 0
Just it -> length (index x) == length (focus it : up it ++ down it)
-- For all windows in the stackSet, findTag should identify the
-- correct workspace
prop_findIndex (x :: T) =
and [ tag w == fromJust (findTag i x)
| w <- workspace (current x) : map workspace (visible x) ++ hidden x
, t <- maybeToList (stack w)
, i <- focus t : up t ++ down t
]
prop_allWindowsMember (NonEmptyWindowsStackSet x) = do
-- Reimplementation of arbitraryWindow, but to make sure that
-- implementation doesn't change in the future, and stop using allWindows,
-- which is a key component in this test (together with member).
let ws = allWindows x
-- We know that there are at least 1 window in a NonEmptyWindowsStackSet.
idx <- choose(0, (length ws) - 1)
return $ member (ws!!idx) x
-- preserve order
prop_filter_order (x :: T) =
case stack $ workspace $ current x of
Nothing -> True
Just s@(Stack i _ _) -> integrate' (S.filter (/= i) s) == filter (/= i) (integrate' (Just s))
-- differentiate should return Nothing if the list is empty or Just stack, with
-- the first element of the list is current, and the rest of the list is down.
prop_differentiate xs =
if null xs then differentiate xs == Nothing
else (differentiate xs) == Just (Stack (head xs) [] (tail xs))
where _ = xs :: [Int]

View File

@@ -0,0 +1,135 @@
{-# LANGUAGE ScopedTypeVariables #-}
module Properties.StackSet where
import Test.QuickCheck
import Instances
import Utils
import XMonad.StackSet hiding (filter)
import Data.Maybe
import Data.List (nub)
-- ---------------------------------------------------------------------
-- QuickCheck properties for the StackSet
-- Some general hints for creating StackSet properties:
--
-- * ops that mutate the StackSet are usually local
-- * most ops on StackSet should either be trivially reversible, or
-- idempotent, or both.
------------------------------------------------------------------------
-- Basic data invariants of the StackSet
--
-- With the new zipper-based StackSet, tracking focus is no longer an
-- issue: the data structure enforces focus by construction.
--
-- But we still need to ensure there are no duplicates, and master/and
-- the xinerama mapping aren't checked by the data structure at all.
--
-- * no element should ever appear more than once in a StackSet
-- * the xinerama screen map should be:
-- -- keys should always index valid workspaces
-- -- monotonically ascending in the elements
-- * the current workspace should be a member of the xinerama screens
--
invariant (s :: T) = and
-- no duplicates
[ noDuplicates
-- TODO: Fix this.
-- all this xinerama stuff says we don't have the right structure
-- , validScreens
-- , validWorkspaces
-- , inBounds
]
where
ws = concat [ focus t : up t ++ down t
| w <- workspace (current s) : map workspace (visible s) ++ hidden s
, t <- maybeToList (stack w)] :: [Char]
noDuplicates = nub ws == ws
-- validScreens = monotonic . sort . M. . (W.current s : W.visible : W$ s
-- validWorkspaces = and [ w `elem` allworkspaces | w <- (M.keys . screens) s ]
-- where allworkspaces = map tag $ current s : prev s ++ next s
-- inBounds = and [ w >=0 && w < size s | (w,sc) <- M.assocs (screens s) ]
monotonic [] = True
monotonic (x:[]) = True
monotonic (x:y:zs) | x == y-1 = monotonic (y:zs)
| otherwise = False
prop_invariant = invariant
-- and check other ops preserve invariants
prop_empty_I (SizedPositive n) l = forAll (choose (1, fromIntegral n)) $ \m ->
forAll (vector m) $ \ms ->
invariant $ new l [0..fromIntegral n-1] ms
prop_view_I n (x :: T) =
invariant $ view n x
prop_greedyView_I n (x :: T) =
invariant $ greedyView n x
prop_focusUp_I (SizedPositive n) (x :: T) =
invariant $ applyN (Just n) focusUp x
prop_focusMaster_I (SizedPositive n) (x :: T) =
invariant $ applyN (Just n) focusMaster x
prop_focusDown_I (SizedPositive n) (x :: T) =
invariant $ applyN (Just n) focusDown x
prop_focus_I (SizedPositive n) (x :: T) =
case peek x of
Nothing -> True
Just _ -> let w = focus . fromJust . stack . workspace . current $
applyN (Just n) focusUp x
in invariant $ focusWindow w x
prop_insertUp_I n (x :: T) = invariant $ insertUp n x
prop_delete_I (x :: T) = invariant $
case peek x of
Nothing -> x
Just i -> delete i x
prop_swap_master_I (x :: T) = invariant $ swapMaster x
prop_swap_left_I (SizedPositive n) (x :: T) =
invariant $ applyN (Just n) swapUp x
prop_swap_right_I (SizedPositive n) (x :: T) =
invariant $ applyN (Just n) swapDown x
prop_shift_I (x :: T) = do
n <- arbitraryTag x
return $ invariant $ shift (fromIntegral n) x
prop_shift_win_I (nex :: NonEmptyWindowsStackSet) = do
let NonEmptyWindowsStackSet x = nex
w <- arbitraryWindow nex
n <- arbitraryTag x
return $ invariant $ shiftWin n w x
-- ---------------------------------------------------------------------
-- empty StackSets have no windows in them
prop_empty (EmptyStackSet x) =
all (== Nothing) [ stack w | w <- workspace (current x)
: map workspace (visible x) ++ hidden x ]
-- empty StackSets always have focus on first workspace
prop_empty_current (EmptyStackSet x) = currentTag x == head (tags x)
-- no windows will be a member of an empty workspace
prop_member_empty i (EmptyStackSet x) = member i x == False
-- peek either yields nothing on the Empty workspace, or Just a valid window
prop_member_peek (x :: T) =
case peek x of
Nothing -> True {- then we don't know anything -}
Just i -> member i x

47
tests/Properties/Swap.hs Normal file
View File

@@ -0,0 +1,47 @@
{-# LANGUAGE ScopedTypeVariables #-}
module Properties.Swap where
import Test.QuickCheck
import Instances
import Utils
import XMonad.StackSet hiding (filter)
-- ---------------------------------------------------------------------
-- swapUp, swapDown, swapMaster: reordiring windows
-- swap is trivially reversible
prop_swap_left (x :: T) = (swapUp (swapDown x)) == x
prop_swap_right (x :: T) = (swapDown (swapUp x)) == x
-- TODO swap is reversible
-- swap is reversible, but involves moving focus back the window with
-- master on it. easy to do with a mouse...
{-
prop_promote_reversible x b = (not . null . fromMaybe [] . flip index x . current $ x) ==>
(raiseFocus y . promote . raiseFocus z . promote) x == x
where _ = x :: T
dir = if b then LT else GT
(Just y) = peek x
(Just (z:_)) = flip index x . current $ x
-}
-- swap doesn't change focus
prop_swap_master_focus (x :: T) = peek x == (peek $ swapMaster x)
-- = case peek x of
-- Nothing -> True
-- Just f -> focus (stack (workspace $ current (swap x))) == f
prop_swap_left_focus (x :: T) = peek x == (peek $ swapUp x)
prop_swap_right_focus (x :: T) = peek x == (peek $ swapDown x)
-- swap is local
prop_swap_master_local (x :: T) = hidden_spaces x == hidden_spaces (swapMaster x)
prop_swap_left_local (x :: T) = hidden_spaces x == hidden_spaces (swapUp x)
prop_swap_right_local (x :: T) = hidden_spaces x == hidden_spaces (swapDown x)
-- rotation through the height of a stack gets us back to the start
prop_swap_all_l (x :: T) = (foldr (const swapUp) x [1..n]) == x
where n = length (index x)
prop_swap_all_r (x :: T) = (foldr (const swapDown) x [1..n]) == x
where n = length (index x)
prop_swap_master_idempotent (x :: T) = swapMaster (swapMaster x) == swapMaster x

47
tests/Properties/View.hs Normal file
View File

@@ -0,0 +1,47 @@
{-# LANGUAGE ScopedTypeVariables #-}
module Properties.View where
import Test.QuickCheck
import Instances
import Utils
import XMonad.StackSet hiding (filter)
import Data.List (sortBy)
-- ---------------------------------------------------------------------
-- viewing workspaces
-- view sets the current workspace to 'n'
prop_view_current (x :: T) = do
n <- arbitraryTag x
return $ (tag . workspace . current . view n) x == n
-- view *only* sets the current workspace, and touches Xinerama.
-- no workspace contents will be changed.
prop_view_local (x :: T) = do
n <- arbitraryTag x
return $ workspaces x == workspaces (view n x)
where
workspaces a = sortBy (\s t -> tag s `compare` tag t) $
workspace (current a)
: map workspace (visible a) ++ hidden a
-- TODO: Fix this
-- view should result in a visible xinerama screen
-- prop_view_xinerama (x :: T) (n :: NonNegative Int) = i `tagMember` x ==>
-- M.member i (screens (view i x))
-- where
-- i = fromIntegral n
-- view is idempotent
prop_view_idem (x :: T) = do
n <- arbitraryTag x
return $ view n (view n x) == (view n x)
-- view is reversible, though shuffles the order of hidden/visible
prop_view_reversible (x :: T) = do
n <- arbitraryTag x
return $ normal (view n' (view n x)) == normal x
where
n' = currentTag x

View File

@@ -0,0 +1,65 @@
{-# LANGUAGE ScopedTypeVariables #-}
module Properties.Workspace where
import Test.QuickCheck
import Instances
import Utils
import XMonad.StackSet hiding (filter)
import Data.Maybe
-- looking up the tag of the current workspace should always produce a tag.
prop_lookup_current (x :: T) = lookupWorkspace scr x == Just tg
where
(Screen (Workspace tg _ _) scr _) = current x
-- looking at a visible tag
prop_lookup_visible = do
-- make sure we have some xinerama screens.
x <- arbitrary `suchThat` \(x' :: T) -> visible x' /= []
let tags = [ tag (workspace y) | y <- visible x ]
scr = last [ screen y | y <- visible x ]
return $ fromJust (lookupWorkspace scr x) `elem` tags
prop_currentTag (x :: T) =
currentTag x == tag (workspace (current x))
-- Rename a given tag if present in the StackSet.
prop_rename1 (x::T) = do
o <- arbitraryTag x
n <- arbitrary `suchThat` \n' -> not $ n' `tagMember` x
-- Rename o to n
let y = renameTag o n x
return $ n `tagMember` y
-- Ensure that a given set of workspace tags is present by renaming
-- existing workspaces and\/or creating new hidden workspaces as
-- necessary.
--
prop_ensure (x :: T) l xs = let y = ensureTags l xs x
in and [ n `tagMember` y | n <- xs ]
-- adding a tag should create a new hidden workspace
prop_ensure_append (x :: T) l = do
n <- arbitrary `suchThat` \n' -> not $ n' `tagMember` x
let ts = tags x
y = ensureTags l (n:ts) x
return $ hidden y /= hidden x -- doesn't append, renames
&& and [ isNothing (stack z) && layout z == l | z <- hidden y, tag z == n ]
prop_mapWorkspaceId (x::T) = x == mapWorkspace id x
prop_mapWorkspaceInverse (x::T) = x == mapWorkspace predTag (mapWorkspace succTag x)
where predTag w = w { tag = pred $ tag w }
succTag w = w { tag = succ $ tag w }
prop_mapLayoutId (x::T) = x == mapLayout id x
prop_mapLayoutInverse (x::T) = x == mapLayout pred (mapLayout succ x)

47
tests/Utils.hs Normal file
View File

@@ -0,0 +1,47 @@
{-# LANGUAGE RankNTypes #-}
module Utils where
import XMonad.StackSet hiding (filter)
import Graphics.X11.Xlib.Types (Rectangle(..))
import Data.List (sortBy)
-- Useful operation, the non-local workspaces
hidden_spaces x = map workspace (visible x) ++ hidden x
-- normalise workspace list
normal s = s { hidden = sortBy g (hidden s), visible = sortBy f (visible s) }
where
f = \a b -> tag (workspace a) `compare` tag (workspace b)
g = \a b -> tag a `compare` tag b
noOverlaps [] = True
noOverlaps [_] = True
noOverlaps xs = and [ verts a `notOverlap` verts b
| a <- xs
, b <- filter (a /=) xs
]
where
verts (Rectangle a b w h) = (a,b,a + fromIntegral w - 1, b + fromIntegral h - 1)
notOverlap (left1,bottom1,right1,top1)
(left2,bottom2,right2,top2)
= (top1 < bottom2 || top2 < bottom1)
|| (right1 < left2 || right2 < left1)
applyN :: (Integral n) => Maybe n -> (a -> a) -> a -> a
applyN Nothing f v = v
applyN (Just 0) f v = v
applyN (Just n) f v = applyN (Just $ n-1) f (f v)
tags x = map tag $ workspaces x
-- | noOverflows op a b is True if @a `op` fromIntegral b@ overflows (or
-- otherwise gives the same answer when done using Integer
noOverflows :: (Integral b, Integral c) =>
(forall a. Integral a => a -> a -> a) -> b -> c -> Bool
noOverflows op a b = toInteger (a `op` fromIntegral b) == toInteger a `op` toInteger b

View File

@@ -5,12 +5,10 @@ main = do foo <- getContents
let actual_loc = filter (not.null) $ filter isntcomment $
map (dropWhile (==' ')) $ lines foo
loc = length actual_loc
putStrLn $ show loc
print loc
-- uncomment the following to check for mistakes in isntcomment
-- putStr $ unlines $ actual_loc
when (loc > 500) $ fail "Too many lines of code!"
-- print actual_loc
isntcomment "" = False
isntcomment ('-':'-':_) = False
isntcomment ('{':'-':_) = False -- pragmas
isntcomment _ = True

98
util/GenerateManpage.hs Normal file
View File

@@ -0,0 +1,98 @@
{-# LANGUAGE FlexibleContexts #-}
-- Unlike the rest of xmonad, this file is released under the GNU General
-- Public License version 2 or later.
--
-- Generates man/xmonad.1 from man/xmonad.1.in by filling the list of
-- keybindings with values scraped from Config.hs
--
-- Uses cabal to grab the xmonad version from xmonad.cabal
--
-- Uses pandoc to convert the "xmonad.1.markdown" to "xmonad.1"
--
-- Format for the docstrings in Config.hs takes the following form:
--
-- -- mod-x %! Frob the whatsit
--
-- "Frob the whatsit" will be used as the description for keybinding "mod-x"
--
-- If the keybinding name is omitted, it will try to guess from the rest of the
-- line. For example:
--
-- [ ((modMask .|. shiftMask, xK_Return), spawn "xterm") -- %! Launch an xterm
--
-- Here, mod-shift-return will be used as the keybinding name.
import Control.Monad
import Control.Applicative
import Text.Regex.Posix
import Data.Char
import Data.List
import Distribution.PackageDescription.Parse
import Distribution.Verbosity
import Distribution.Package
import Distribution.PackageDescription
import Text.PrettyPrint.HughesPJ
import Distribution.Text
import Text.Pandoc -- works with 1.15.x
releaseDate = "31 December 2012"
trim :: String -> String
trim = reverse . dropWhile isSpace . reverse . dropWhile isSpace
guessKeys line = concat $ intersperse "-" (modifiers ++ [map toLower key])
where modifiers = map (!!1) (line =~ "(mod|shift|control)Mask")
(_, _, _, [key]) = line =~ "xK_([_[:alnum:]]+)" :: (String, String, String, [String])
binding :: [String] -> (String, String)
binding [ _, bindingLine, "", desc ] = (guessKeys bindingLine, desc)
binding [ _, _, keyCombo, desc ] = (keyCombo, desc)
allBindings :: String -> [(String, String)]
allBindings xs = map (binding . map trim) (xs =~ "(.*)--(.*)%!(.*)")
-- FIXME: What escaping should we be doing on these strings?
markdownDefn :: (String, String) -> String
markdownDefn (key, desc) = key ++ "\n: " ++ desc
replace :: Eq a => a -> a -> [a] -> [a]
replace x y = map (\a -> if a == x then y else a)
-- rawSystem "pandoc" ["--read=markdown","--write=man","man/xmonad.1.markdown"]
main = do
releaseName <- (show . disp . package . packageDescription)
`liftM`readPackageDescription normal "xmonad.cabal"
keybindings <- (intercalate "\n\n" . map markdownDefn . allBindings)
`liftM` readFile "./src/XMonad/Config.hs"
let manHeader = unwords [".TH xmonad 1","\""++releaseDate++"\"",releaseName,"\"xmonad manual\""]
Right parsed <- readMarkdown def
. unlines
. replace "___KEYBINDINGS___" keybindings
. lines
<$> readFile "./man/xmonad.1.markdown"
Right template <- getDefaultTemplate Nothing "man"
writeFile "./man/xmonad.1"
. (manHeader ++)
. writeMan def{ writerTemplate = Just template }
$ parsed
putStrLn "Documentation created: man/xmonad.1"
Right template <- getDefaultTemplate Nothing "html"
writeFile "./man/xmonad.1.html"
. writeHtmlString def
{ writerVariables =
[("include-before"
,"<h1>"++releaseName++"</h1>"++
"<p>Section: xmonad manual (1)<br/>"++
"Updated: "++releaseDate++"</p>"++
"<hr/>")]
, writerTemplate = Just template
, writerTableOfContents = True }
$ parsed
putStrLn "Documentation created: man/xmonad.1.html"

33
util/hpcReport.sh Normal file
View File

@@ -0,0 +1,33 @@
#!/bin/bash
set -e
if [[ ! ( -e xmonad.cabal && -e dist/hpc/tix/properties/properties.tix ) ]]; then
echo "run in the same dir as xmonad.cabal after having run
cabal configure --enable-tests --enable-library-coverage; cabal test
"
exit 1
fi
propsExclude=$(find tests/Properties -name '*.hs' \
| sed -e 's_/_._g' -e 's_.hs$__' -e 's_^tests._--exclude=_' )
hpcFlags="
--hpcdir=dist/hpc/mix/
dist/hpc/tix/properties/properties.tix
"
if [[ ! (-e dist/hpc/mix/Main.mix) ]]; then
mv dist/hpc/mix/properties/* dist/hpc/mix/
mv dist/hpc/mix/xmonad-*/xmonad-*/* dist/hpc/mix/xmonad-*/
fi
hpc markup --destdir=dist/hpc $hpcFlags > /dev/null
echo "see dist/hpc/hpc_index.html
"
hpc report $hpcFlags

View File

@@ -1,18 +1,126 @@
name: xmonad
version: 0.1
description: A lightweight X11 window manager.
synopsis: A lightweight X11 window manager.
version: 0.14
homepage: http://xmonad.org
synopsis: A tiling window manager
description:
xmonad is a tiling window manager for X. Windows are arranged
automatically to tile the screen without gaps or overlap, maximising
screen use. All features of the window manager are accessible from
the keyboard: a mouse is strictly optional. xmonad is written and
extensible in Haskell. Custom layout algorithms, and other
extensions, may be written by the user in config files. Layouts are
applied dynamically, and different layouts may be used on each
workspace. Xinerama is fully supported, allowing windows to be tiled
on several screens.
category: System
license: BSD3
license-file: LICENSE
author: Spencer Janssen
maintainer: sjanssen@cse.unl.edu
build-depends: base>=1.0, X11>=1.1, X11-extras>=0.0, mtl>=1.0, unix>=1.0
extra-source-files: README TODO tests/loc.hs tests/Properties.hs
maintainer: xmonad@haskell.org
extra-source-files: README.md CHANGES.md CONFIG STYLE
tests/*.hs
tests/Properties/*.hs
tests/Properties/Layout/*.hs
man/xmonad.1.markdown man/xmonad.1 man/xmonad.1.html
util/GenerateManpage.hs
util/hpcReport.sh
cabal-version: >= 1.8
bug-reports: https://github.com/xmonad/xmonad/issues
build-type: Simple
executable: xmonad
main-is: Main.hs
other-modules: Config Operations StackSet XMonad
ghc-options: -funbox-strict-fields -O2 -Wall -optl-Wl,-s
ghc-prof-options: -prof -auto-all
extensions: GeneralizedNewtypeDeriving
tested-with:
GHC==7.6.3,
GHC==7.8.4,
GHC==7.10.3,
GHC==8.0.2,
GHC==8.2.2,
GHC==8.4.3
data-files: man/xmonad.hs, man/xmonad.1, man/xmonad.1.html
source-repository head
type: git
location: https://github.com/xmonad/xmonad
flag testing
description: Testing mode, only build minimal components
default: False
manual: True
flag generatemanpage
description: Build the tool for generating the man page
default: False
manual: True
library
hs-source-dirs: src
exposed-modules: XMonad
XMonad.Main
XMonad.Core
XMonad.Config
XMonad.Layout
XMonad.ManageHook
XMonad.Operations
XMonad.StackSet
other-modules: Paths_xmonad
build-depends: base < 5 && >=3,
containers,
data-default,
directory,
extensible-exceptions,
filepath,
setlocale,
mtl,
process,
unix,
utf8-string >= 0.3 && < 1.1,
X11>=1.8 && < 1.10,
semigroups
if true
ghc-options: -funbox-strict-fields -Wall
if impl(ghc >= 6.12.1)
ghc-options: -fno-warn-unused-do-bind
if impl(ghc < 7.0.0)
extensions: UndecidableInstances
-- needed for XMonad.Config's instance Default (XConfig a)
if flag(testing)
buildable: False
executable xmonad
main-is: Main.hs
build-depends: base,
mtl,
unix,
X11,
xmonad
ghc-options: -Wall
if impl(ghc >= 6.12.1)
ghc-options: -Wall -fno-warn-unused-do-bind
executable generatemanpage
main-is: GenerateManpage.hs
hs-source-dirs: util
if flag(generatemanpage)
build-depends: base,
Cabal,
pandoc,
pretty,
regex-posix
else
buildable: False
-- note util/hpcReport.sh
test-suite properties
type: exitcode-stdio-1.0
hs-source-dirs: tests
build-depends: base,
containers,
extensible-exceptions,
QuickCheck >= 2,
X11,
xmonad
main-is: Properties.hs