118 Commits
v0.12 ... v0.15

Author SHA1 Message Date
Peter Simons
bb13853929 Bump version number, update changelog, and re-generate the man page. 2018-09-30 13:34:01 +02:00
Brent Yorgey
3d1720c3f3 Merge pull request #176 from LSLeary/sendmessage
Reimplement sendMessage to deal properly with windowset changes made during handling
2018-09-12 17:31:18 -05:00
L. S. Leary
0614ffb65c XMonad.Operations
* Add `windowBracket`: provide a means of handling windowset changes
   made during the course of arbitrary `X` actions. Buys composability.
 * Add `windowBracket_` variant.
 * Add `modifyWindowSet` utility for use with the above.
 * Re-implement `sendMessage` using `windowBracket_` so that its refresh
   handles changes made to the windowset by the message handler.
2018-09-13 08:19:37 +12:00
Sibi
85b47fc3ac Merge pull request #182 from nikolas/patch-1
Fix typo in delete test comment: identiy -> identity
2018-08-31 22:57:03 +05:30
nikolas
1a99280227 typo fix in delete test comment: identiy -> identity 2018-08-31 12:37:04 -04:00
Peter Simons
e8133eb9a6 CHANGES.md: add an entry for the 0.14.2 version 2018-08-24 12:11:20 +02:00
Peter Simons
4ccaff8f25 xmonad.cabal: bump version number to 0.14.2 for release 2018-08-21 09:59:02 +02:00
Peter Simons
56dc186e68 xmonad.cabal: the author attribute is free-form, not a list
I rather not trust other code that interprets that file to know how to strip
the white space before the commas.
2018-08-21 09:57:59 +02:00
Peter Simons
10b2efe81c xmonad.cabal: add missing xmonad.hs file to the tarball again
Fixes https://github.com/xmonad/xmonad/issues/181.
2018-08-21 09:57:11 +02:00
Peter Simons
49c69fa73b xmonad.cabal: require at least base version 4.9
We need GHC 8.x and beyond for Data.Semigroup, Control.Monad.Fail, etc.
2018-08-20 14:06:32 +02:00
Peter Simons
120ebce490 xmonad.cabal: simplify and modernize the Cabal file
It's also pretty-printed with 'stylish-cabal' for consistent formatting.
2018-08-20 14:05:33 +02:00
Peter Simons
c0cf91303f Tentatively bump version number to 0.14.1. 2018-08-20 13:49:34 +02:00
Peter Simons
80f1c6f027 CHANGES.md: move PR entries into the right section 2018-08-20 13:49:34 +02:00
Peter Simons
c54e7088f0 Merge pull request #167 from mgsloan/log-recompilation-info
Log information about xmonad compile + avoid unnecessary recompile
2018-08-20 13:49:10 +02:00
Peter Simons
1f3a27f9b9 Don't build generatemanpage with ghc 8.6.x yet: we're lacking pandoc. 2018-08-20 12:44:16 +02:00
Peter Simons
ec97d83f3f GenerateManpage: fix compiler warnings 2018-08-20 12:01:33 +02:00
Peter Simons
f0975b734c git: ignore "cabal new-build"-style artifacts 2018-08-20 12:01:33 +02:00
Peter Simons
2324266fae travis.yml: build with -fgeneratemanpage 2018-08-20 12:01:33 +02:00
Peter Simons
3b0559c6cc Merge pull request #129 from madnight/patch-2
Change comment for grabButtons in Main.hs
2018-08-20 11:47:45 +02:00
Peter Simons
886a0d4041 GenerateManpage: greatly simplify the code
We can take advantage of modern Pandoc features to move information like the
release date, the man page section, etc. into the markdown source rather than
having to insert that data during the rendering process. The only thing that
remains to be figured out by this tool is the set of known key bindings.
2018-08-20 11:35:31 +02:00
Peter Simons
98f39eabc1 xmonad.cabal: don't depend on semigroups when building with GHC 8.x
Recent compiler versions have Data.Semigroup in 'base'.
2018-08-20 10:40:03 +02:00
Peter Simons
425c3c0872 Core: derive 'MonadFail X' instance for GHC 8.6.x and beyond
A side effect of that change is that our code no longer compiles with GHC
versions prior to 8.0.x. We could work around that, no doubt, but the resulting
code would require CPP and Cabal flags and whatnot. It feels more reasonable to
just require a moderately recent compiler instead of going through all that
trouble.
2018-08-20 10:40:03 +02:00
Peter Simons
29c9819daa xmonad.cabal: update constraints on 'base'
- Our code does not compile with versions prior to 4.6, because we need
   System.Environment.lookupEnv.

 - Our code does not compile with version 4.12 (GHC 8.6.x) and beyond.

Closes https://github.com/xmonad/xmonad/issues/180.
2018-08-20 08:45:11 +02:00
Sibi
3c2b09c213 Merge pull request #179 from countermeasure/patch-1
Update Debian packages in README
2018-08-07 10:35:16 +05:30
Sky
64a660894d Update Debian packages in README 2018-08-06 18:42:59 -07:00
Peter Simons
27b1ce9dd7 Merge pull request #98 from tmciver/master
Update README to add xrandr dependency and add build/install instruct…
2018-07-30 12:43:33 +02:00
Peter Simons
5caf235f6b CHANGES.md: document recent changes 2018-07-30 12:42:16 +02:00
Peter Simons
4ef9c12d13 Merge pull request #99 from gliptak/warnings1
Cleanup build warnings
2018-07-30 12:40:09 +02:00
Peter Simons
d6705fd595 Merge pull request #128 from madnight/patch-1
Remove unused CPP extension from Core.hs
2018-07-30 12:38:16 +02:00
Peter Simons
7c1065c43f Merge pull request #127 from dudebout/patch-1
remove the man pages from data-files
2018-07-30 12:31:26 +02:00
Peter Simons
af104509c3 GenerateManpage does not compile with Cabal 2.2.x. 2018-07-30 11:56:07 +02:00
Michiel Derhaeg
586ee75a9a fix manpage generation 2018-07-30 11:53:58 +02:00
Clint Adams
013da018a1 Port GenerateManpage.hs to pandoc 2
Closes: #123

There is a regression here in terms of aesthetics.
2018-07-30 11:53:58 +02:00
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
Michael Sloan
b6d92b4e38 Log information about xmonad compile + avoid unnecessary recompile
Particularly with the addition of build scripts, it can be tricky to figure out
what XMonad is doing when attempting recompilation.  This makes it clearer by
adding some logging.

Due to this logging, I noticed that the lag of xmonad start was because it was
always recompiling!  When I startup my computer, I do not want it to delay
rebuilding my window manager. This also fixes that issue such that it only
recompiles XMonad if it is going to reinvoke due to getProgName not being the
expected string.
2018-05-09 18:41:46 -07: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
Fabian Beuke
3ec3536761 Change comment for grabButtons in Main.hs 2017-08-11 14:46:19 +02:00
Fabian Beuke
179b6a30f4 Remove unused CPP extension from Core.hs 2017-08-08 00:46:00 +02:00
Nicolas Dudebout
3dc65c3d2e remove the man pages from data-files
The man pages are available for packagers in `extra-source-files`.

Having them in `data-files` is confusing since, according to Cabal's user guide [1], `data-files` contains "A list of files to be installed for run-time use by the package.", but the man pages are not used at run-time by xmonad.

[1]: https://www.haskell.org/cabal/users-guide/developing-packages.html
2017-08-06 10:29:54 -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
Gábor Lipták
0c97a89754 Cleanup build warnings
Signed-off-by: Gábor Lipták <gliptak@gmail.com>
2017-04-15 18:16:40 -04:00
Tim McIver
5afdc16387 Update README to add xrandr dependency and add build/install instruction. 2017-04-13 22:31:34 -04: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
24 changed files with 1342 additions and 443 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

14
.gitignore vendored
View File

@@ -1,14 +1,9 @@
.cabal-sandbox/
cabal.sandbox.config
.hpc/
*.hi
*.o
*.p_hi
*.prof
*.tix
cabal.config
dist
dist-*
# editor temp files
@@ -23,3 +18,12 @@ tags
# stack artifacts
/.stack-work/
# cabal-install artifacts
/.*.environment.*-*
/.cabal-sandbox/
/cabal.config
/cabal.project.local
/cabal.sandbox.config
/dist-newstyle/
/dist/

View File

@@ -1,82 +1,135 @@
# This file has been generated -- see https://github.com/hvr/multi-ghc-travis
# 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/haskell-CI/haskell-ci
#
language: c
sudo: false
git:
submodules: false # whether to recursively clone submodules
cache:
directories:
- $HOME/.cabsnap
- $HOME/.cabal/packages
- $HOME/.cabal/store
before_cache:
- rm -fv $HOME/.cabal/packages/hackage.haskell.org/build-reports.log
- rm -fv $HOME/.cabal/packages/hackage.haskell.org/00-index.tar
# 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:
- env: CABALVER=1.16 GHCVER=7.6.3
compiler: ": #GHC 7.6.3"
addons: {apt: {packages: [cabal-install-1.16,ghc-7.6.3], sources: [hvr-ghc]}}
- env: CABALVER=1.18 GHCVER=7.8.4
compiler: ": #GHC 7.8.4"
addons: {apt: {packages: [cabal-install-1.18,ghc-7.8.4], sources: [hvr-ghc]}}
- env: CABALVER=1.22 GHCVER=7.10.2
compiler: ": #GHC 7.10.2"
addons: {apt: {packages: [cabal-install-1.22,ghc-7.10.2], sources: [hvr-ghc]}}
- compiler: "ghc-8.6.1"
env: GHCHEAD=true
addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-8.6.1,libxrandr-dev], sources: [hvr-ghc]}}
- 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]}}
allow_failures:
- compiler: "ghc-8.6.1"
before_install:
- unset CC
- export PATH=/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:$PATH
- 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 "$(ghc --version) [$(ghc --print-project-git-commit-id 2> /dev/null || echo '?')]"
- if [ -f $HOME/.cabal/packages/hackage.haskell.org/00-index.tar.gz ];
then
zcat $HOME/.cabal/packages/hackage.haskell.org/00-index.tar.gz >
$HOME/.cabal/packages/hackage.haskell.org/00-index.tar;
fi
- travis_retry cabal update -v
- sed -i 's/^jobs:/-- jobs:/' ${HOME}/.cabal/config
- cabal install --only-dependencies --enable-tests --enable-benchmarks --dry -v > installplan.txt
- sed -i -e '1,/^Resolving /d' installplan.txt; cat installplan.txt
- 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
# Overlay Hackage Package Index for GHC HEAD: https://github.com/hvr/head.hackage
- |
if $GHCHEAD; then
sed -i 's/-- allow-newer: .*/allow-newer: *:base/' ${HOME}/.cabal/config
for pkg in $($HCPKG list --simple-output); do pkg=$(echo $pkg | sed 's/-[^-]*$//'); sed -i "s/allow-newer: /allow-newer: *:$pkg, /" ${HOME}/.cabal/config; done
# check whether current requested install-plan matches cached package-db snapshot
- if diff -u installplan.txt $HOME/.cabsnap/installplan.txt;
then
echo "cabal build-cache HIT";
rm -rfv .ghc;
cp -a $HOME/.cabsnap/ghc $HOME/.ghc;
cp -a $HOME/.cabsnap/lib $HOME/.cabsnap/share $HOME/.cabsnap/bin $HOME/.cabal/;
else
echo "cabal build-cache MISS";
rm -rf $HOME/.cabsnap;
mkdir -p $HOME/.ghc $HOME/.cabal/lib $HOME/.cabal/share $HOME/.cabal/bin;
cabal install --only-dependencies --enable-tests --enable-benchmarks;
fi
echo 'repository head.hackage' >> ${HOME}/.cabal/config
echo ' url: http://head.hackage.haskell.org/' >> ${HOME}/.cabal/config
echo ' secure: True' >> ${HOME}/.cabal/config
echo ' root-keys: 07c59cb65787dedfaef5bd5f987ceb5f7e5ebf88b904bbd4c5cbdeb2ff71b740' >> ${HOME}/.cabal/config
echo ' 2e8555dde16ebd8df076f1a8ef13b8f14c66bad8eafefd7d9e37d0ed711821fb' >> ${HOME}/.cabal/config
echo ' 8f79fd2389ab2967354407ec852cbe73f2e8635793ac446d09461ffb99527f6e' >> ${HOME}/.cabal/config
echo ' key-threshold: 3' >> ${HOME}/.cabal.config
# snapshot package-db on cache miss
- if [ ! -d $HOME/.cabsnap ];
then
echo "snapshotting package-db to build-cache";
mkdir $HOME/.cabsnap;
cp -a $HOME/.ghc $HOME/.cabsnap/ghc;
cp -a $HOME/.cabal/lib $HOME/.cabal/share $HOME/.cabal/bin installplan.txt $HOME/.cabsnap/;
fi
grep -Ev -- '^\s*--' ${HOME}/.cabal/config | grep -Ev '^\s*$'
cabal new-update head.hackage -v
fi
- grep -Ev -- '^\s*--' ${HOME}/.cabal/config | grep -Ev '^\s*$'
- "printf 'packages: \".\"\\n' > cabal.project"
- "if [ $HCNUMVER -lt 80600 ]; then printf 'package xmonad\\n flags: +generatemanpage\n' >> cabal.project; fi"
- 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:
- if [ -f configure.ac ]; then autoreconf -i; fi
- cabal configure --enable-tests --enable-benchmarks -v2 # -v2 provides useful information for debugging
- cabal build # this builds all libraries and executables (including tests/benchmarks)
- cabal test
- cabal check
- cabal sdist # tests that a source-distribution can be generated
# 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"
- "if [ $HCNUMVER -lt 80600 ]; then printf 'package xmonad\\n flags: +generatemanpage\n' >> cabal.project; fi"
- 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
# Check that the resulting source distribution can be built & installed.
# If there are no other `.tar.gz` files in `dist`, this can be even simpler:
# `cabal install --force-reinstalls dist/*-*.tar.gz`
- SRC_TGZ=$(cabal info . | awk '{print $2;exit}').tar.gz &&
(cd dist && cabal install --force-reinstalls "$SRC_TGZ")
# 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

View File

@@ -1,5 +1,147 @@
# Change Log / Release Notes
## unknown (unknown)
## 0.15 (September 30, 2018)
* Reimplement `sendMessage` to deal properly with windowset changes made
during handling.
* Add new library functions `windowBracket` and `modifyWindowSet` to
`XMonad.Operations`.
## 0.14.2 (August 21, 2018)
### Bug Fixes
* Add the sample configuration file xmonad.hs again to the release tarball.
[https://github.com/xmonad/xmonad/issues/181]
## 0.14.1 (August 20, 2018)
### Breaking Changes
* The cabal build no longer installs xmonad.hs, xmonad.1, and xmonad.1.html
as data files. The location cabal picks for chose files isn't useful as
standard tools like man(1) won't find them there. Instead, we rely on
distributors to pick up the files from the source tarball during the build
and to install them into proper locations where their users expect them.
[https://github.com/xmonad/xmonad/pull/127]
### Bug Fixes
* Add support for GHC 8.6.x by providing an instance for 'MonadFail X'. A
side effect of that change is that our code no longer compiles with GHC
versions prior to 8.0.x. We could work around that, no doubt, but the
resulting code would require CPP and Cabal flags and whatnot. It feels more
reasonable to just require a moderately recent compiler instead of going
through all that trouble.
* xmonad no longer always recompile on startup. Now it only does so if the
executable does not have the name that would be used for the compilation
output. The purpose of recompiling and executing the results in this case is
so that the `xmonad` executable in the package can be used with custom
configurations.
### Enhancements
* Whenever xmonad recompiles, it now explains how it is attempting to
recompile, by outputting logs to stderr. If you are using xmonad as a custom
X session, then this will end up in a `.xsession-errors` file.
## 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

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

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

View File

@@ -1,5 +1,7 @@
# 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:
@@ -58,11 +60,19 @@ We'll now walk through the complete list of toolchain dependencies.
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
# for xmonad
$ apt-get install libx11-dev libxinerama-dev libxext-dev libxrandr-dev libxss-dev
# for xmonad-contrib
$ apt-get install libxft-dev
Then build and install with:
$ cabal install
## Running xmonad
Add:
If you built XMonad using `cabal` then add:
exec $HOME/.cabal/bin/xmonad
@@ -70,7 +80,7 @@ to the last line of your `.xsession` or `.xinitrc` file.
## Configuring
See the `CONFIG` document.
See the [CONFIG][] document and the [example configuration file][example-config].
## XMonadContrib
@@ -115,3 +125,5 @@ For a program dispatch menu:
[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

14
TODO
View File

@@ -1,14 +0,0 @@
= Release management =
* generate, and push website haddocks with xmonad-web/gen-docs.sh
* generate manpage, generate html manpage
* double check README build instructions
* bump xmonad.cabal version and X11 version
* update cabal "tested-with:" fields
* upload X11 and xmonad to Hackage
* update #xmonad topic
* check examples/text in user-facing Config.hs
* check tour.html and intro.html are up to date, and mention all core bindings
* confirm template config is type correct
* update haskellwiki notable changes since x.x
* email announce

1
cabal.project Normal file
View File

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

View File

@@ -1,10 +1,10 @@
.TH xmonad 1 "31 December 2012" xmonad-0.12 "xmonad manual".\" Automatically generated by Pandoc 1.15.1
.\" Automatically generated by Pandoc 2.2.1
.\"
.TH "XMONAD" "1" "30 September 2018" "Tiling Window Manager" ""
.hy
.TH "" "" "" "" ""
.SH Name
.PP
xmonad \- a tiling window manager
xmonad \- Tiling Window Manager
.SH Description
.PP
\f[I]xmonad\f[] is a minimalist tiling window manager for X, written in
@@ -41,7 +41,7 @@ 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".
\f[I]xmonad\f[] places each window into a \[lq]workspace\[rq].
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
@@ -67,31 +67,32 @@ and visible workspaces are swapped.
xmonad has several flags which you may pass to the executable.
These flags are:
.TP
.B \-\-recompile
.B \[en]recompile
Recompiles your configuration in \f[I]~/.xmonad/xmonad.hs\f[]
.RS
.RE
.TP
.B \-\-restart
.B \[en]restart
Causes the currently running \f[I]xmonad\f[] process to restart
.RS
.RE
.TP
.B \-\-replace
.B \[en]replace
Replace the current window manager with xmonad
.RS
.RE
.TP
.B \-\-version
.B \[en]version
Display version of \f[I]xmonad\f[]
.RS
.RE
.TP
.B \-\-verbose\-version
.B \[en]verbose\-version
Display detailed version of \f[I]xmonad\f[]
.RS
.RE
.SS Default keyboard bindings
.PP
##Default keyboard bindings
.TP
.B mod\-shift\-return
Launch terminal
@@ -209,6 +210,12 @@ beginners)
.RS
.RE
.TP
.B mod\-question
Run xmessage with a summary of the default keybindings (useful for
beginners)
.RS
.RE
.TP
.B mod\-[1..9]
Switch to workspace N
.RS
@@ -262,7 +269,7 @@ 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.
in \f[I]~/.xmonad/lib/\f[] are available in GHC's searchpath.
Hierarchical modules are supported: for example, the file
\f[I]~/.xmonad/lib/XMonad/Stack/MyAdditions.hs\f[] could contain:
.IP

View File

@@ -1,21 +1,97 @@
<!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">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-Style-Type" content="text/css" />
<meta charset="utf-8" />
<meta name="generator" content="pandoc" />
<title></title>
<style type="text/css">code{white-space: pre;}</style>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
<meta name="author" content="" />
<meta name="dcterms.date" content="2018-09-30" />
<title>XMONAD(1) Tiling Window Manager</title>
<style type="text/css">
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
span.underline{text-decoration: underline;}
div.column{display: inline-block; vertical-align: top; width: 50%;}
</style>
<style type="text/css">
a.sourceLine { display: inline-block; line-height: 1.25; }
a.sourceLine { pointer-events: none; color: inherit; text-decoration: inherit; }
a.sourceLine:empty { height: 1.2em; }
.sourceCode { overflow: visible; }
code.sourceCode { white-space: pre; position: relative; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
code.sourceCode { white-space: pre-wrap; }
a.sourceLine { text-indent: -1em; padding-left: 1em; }
}
pre.numberSource a.sourceLine
{ position: relative; left: -4em; }
pre.numberSource a.sourceLine::before
{ content: attr(data-line-number);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; pointer-events: all; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
color: #aaaaaa;
}
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
div.sourceCode
{ }
@media screen {
a.sourceLine::before { text-decoration: underline; }
}
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code span.at { color: #7d9029; } /* Attribute */
code span.bn { color: #40a070; } /* BaseN */
code span.bu { } /* BuiltIn */
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code span.ch { color: #4070a0; } /* Char */
code span.cn { color: #880000; } /* Constant */
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
code span.dt { color: #902000; } /* DataType */
code span.dv { color: #40a070; } /* DecVal */
code span.er { color: #ff0000; font-weight: bold; } /* Error */
code span.ex { } /* Extension */
code span.fl { color: #40a070; } /* Float */
code span.fu { color: #06287e; } /* Function */
code span.im { } /* Import */
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
code span.op { color: #666666; } /* Operator */
code span.ot { color: #007020; } /* Other */
code span.pp { color: #bc7a00; } /* Preprocessor */
code span.sc { color: #4070a0; } /* SpecialChar */
code span.ss { color: #bb6688; } /* SpecialString */
code span.st { color: #4070a0; } /* String */
code span.va { color: #19177c; } /* Variable */
code span.vs { color: #4070a0; } /* VerbatimString */
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
</style>
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
<![endif]-->
</head>
<body>
<h1>xmonad-0.12</h1><p>Section: xmonad manual (1)<br/>Updated: 31 December 2012</p><hr/>
<div id="TOC">
<header>
<h1 class="title">XMONAD(1) Tiling Window Manager</h1>
<p class="author"></p>
<p class="date">30 September 2018</p>
</header>
<nav 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>
@@ -23,37 +99,37 @@
</ul></li>
<li><a href="#bugs">Bugs</a></li>
</ul>
</div>
</nav>
<h1 id="name">Name</h1>
<p>xmonad - a tiling window manager</p>
<p>xmonad - 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><em>xmonad</em> 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.</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>
<dt>recompile</dt>
<dd>Recompiles your configuration in <em>~/.xmonad/xmonad.hs</em>
</dd>
<dt>--restart</dt>
<dt>restart</dt>
<dd>Causes the currently running <em>xmonad</em> process to restart
</dd>
<dt>--replace</dt>
<dt>replace</dt>
<dd>Replace the current window manager with xmonad
</dd>
<dt>--version</dt>
<dt>version</dt>
<dd>Display version of <em>xmonad</em>
</dd>
<dt>--verbose-version</dt>
<dt>verbose-version</dt>
<dd>Display detailed version of <em>xmonad</em>
</dd>
</dl>
<h2 id="default-keyboard-bindings">Default keyboard bindings</h2>
<p>##Default keyboard bindings</p>
<dl>
<dt>mod-shift-return</dt>
<dd>Launch terminal
@@ -124,6 +200,9 @@
<dt>mod-shift-slash</dt>
<dd>Run xmessage with a summary of the default keybindings (useful for beginners)
</dd>
<dt>mod-question</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>
@@ -155,9 +234,9 @@
<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>As of <em>xmonad-0.9</em>, any additional Haskell modules may be placed in <em>~/.xmonad/lib/</em> are available in GHCs searchpath. Hierarchical modules are supported: for example, the file <em>~/.xmonad/lib/XMonad/Stack/MyAdditions.hs</em> could contain:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb1-1" data-line-number="1"><span class="kw">module</span> <span class="dt">XMonad.Stack.MyAdditions</span> (function1) <span class="kw">where</span></a>
<a class="sourceLine" id="cb1-2" data-line-number="2"> function1 <span class="fu">=</span> error <span class="st">&quot;function1: Not implemented yet!&quot;</span></a></code></pre></div>
<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>

View File

@@ -1,7 +1,12 @@
#Name
xmonad - a tiling window manager
% XMONAD(1) Tiling Window Manager
%
% 30 September 2018
#Description
# Name
xmonad - 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
@@ -28,7 +33,7 @@ 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
# 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.
@@ -47,7 +52,8 @@ 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
## Flags
xmonad has several flags which you may pass to the executable.
These flags are:
@@ -70,12 +76,13 @@ These flags are:
___KEYBINDINGS___
#Examples
# Examples
To use xmonad as your window manager add to your _~/.xinitrc_ file:
> exec xmonad
#Customization
# Customization
xmonad is customized in ~/.xmonad/xmonad.hs, and then restarted
with mod-q.
@@ -83,7 +90,7 @@ 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
## 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
@@ -97,7 +104,7 @@ module XMonad.Stack.MyAdditions (function1) where
Your xmonad.hs may then import XMonad.Stack.MyAdditions as if that
module was contained within xmonad or xmonad-contrib.
#Bugs
# Bugs
Probably. If you find any, please report them to the [bugtracker]
[xmonad.org]: http://xmonad.org

View File

@@ -221,9 +221,9 @@ keys conf@(XConfig {XMonad.modMask = modMask}) = M.fromList $
, ((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 ), spawn ("echo \"" ++ help ++ "\" | xmessage -file -")) -- %! Run xmessage with a summary of the default keybindings (useful for beginners)
, ((modMask .|. shiftMask, xK_slash ), helpCommand) -- %! Run xmessage with a summary of the default keybindings (useful for beginners)
-- repeat the binding for non-American layout keyboards
, ((modMask , xK_question), spawn ("echo \"" ++ help ++ "\" | xmessage -file -"))
, ((modMask , xK_question), helpCommand) -- %! Run xmessage with a summary of the default keybindings (useful for beginners)
]
++
-- mod-[1..9] %! Switch to workspace N
@@ -237,6 +237,9 @@ keys conf@(XConfig {XMonad.modMask = modMask}) = M.fromList $
[((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 -")
-- | Mouse bindings: default actions bound to mouse events
mouseBindings :: XConfig Layout -> M.Map (KeyMask, Button) (Window -> X ())
@@ -320,9 +323,9 @@ help = unlines ["The default modifier key is 'alt'. Default keybindings:",
"-- quit, or restart",
"mod-Shift-q Quit xmonad",
"mod-q Restart xmonad",
"mod-[1..9] Switch to workSpace N",
"",
"-- 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",
@@ -330,4 +333,4 @@ help = unlines ["The default modifier key is 'alt'. Default keybindings:",
"-- 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"]
"mod-button3 Set the window to floating mode and resize by dragging"]

View File

@@ -1,5 +1,5 @@
{-# LANGUAGE ExistentialQuantification, FlexibleInstances, GeneralizedNewtypeDeriving,
MultiParamTypeClasses, TypeSynonymInstances, CPP, DeriveDataTypeable #-}
MultiParamTypeClasses, TypeSynonymInstances, DeriveDataTypeable #-}
-----------------------------------------------------------------------------
-- |
@@ -25,8 +25,10 @@ module XMonad.Core (
StateExtension(..), ExtensionClass(..),
runX, catchX, userCode, userCodeDef, io, catchIO, installSignalHandlers, uninstallSignalHandlers,
withDisplay, withWindowSet, isRoot, runOnWorkspaces,
getAtom, spawn, spawnPID, xfork, getXMonadDir, recompile, trace, whenJust, whenX,
atom_WM_STATE, atom_WM_PROTOCOLS, atom_WM_DELETE_WINDOW, atom_WM_TAKE_FOCUS, ManageHook, Query(..), runQuery
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)
@@ -34,13 +36,16 @@ 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.Applicative(Applicative, pure, (<$>), (<*>))
import Control.Monad.Fail
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
@@ -49,11 +54,12 @@ import System.Process
import System.Directory
import System.Exit
import Graphics.X11.Xlib
import Graphics.X11.Xlib.Extras (Event)
import Graphics.X11.Xlib.Extras (getWindowAttributes, WindowAttributes, Event)
import Data.Typeable
import Data.List ((\\))
import Data.Maybe (isJust,fromMaybe)
import Data.Monoid
import Data.Monoid hiding ((<>))
import System.Environment (lookupEnv)
import qualified Data.Map as M
import qualified Data.Set as S
@@ -68,7 +74,7 @@ data XState = XState
, extensibleState :: !(M.Map String (Either String StateExtension))
-- ^ stores custom state information.
--
-- The module "XMonad.Utils.ExtensibleState" in xmonad-contrib
-- The module "XMonad.Util.ExtensibleState" in xmonad-contrib
-- provides additional information and a simple interface for using this.
}
@@ -142,12 +148,15 @@ data ScreenDetail = SD { screenRect :: !Rectangle } deriving (Eq,Show, Read)
-- 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)
deriving (Functor, Monad, MonadFail, 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
@@ -162,6 +171,9 @@ newtype Query a = Query (ReaderT Window X a)
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
@@ -207,6 +219,12 @@ withDisplay f = asks display >>= f
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
@@ -431,73 +449,247 @@ runOnWorkspaces job = do
$ current ws : visible ws
modify $ \s -> s { windowset = ws { current = c, visible = v, hidden = h } }
-- | Return the path to @~\/.xmonad@.
-- | 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 = io $ getAppUserDataDirectory "xmonad"
getXMonadDir =
findFirstDirWithEnv "XMONAD_CONFIG_DIR"
[ getAppUserDataDirectory "xmonad"
, getXDGDirectory XDGConfig "xmonad"
]
-- | 'recompile force', recompile @~\/.xmonad\/xmonad.hs@ when any of the
-- following apply:
-- | 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
-- ~\/.xmonad\/lib
-- 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 ~\/.xmonad\/lib directory.
-- and any files in the aforementioned @lib@ directory.
--
-- Compilation errors (if any) are logged to ~\/.xmonad\/xmonad.errors. If
-- GHC indicates failure with a non-zero exit code, an xmessage displaying
-- that file is spawned.
-- 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
dir <- getXMonadDir
cfgdir <- getXMonadDir
datadir <- getXMonadDataDir
let binn = "xmonad-"++arch++"-"++os
bin = dir </> binn
base = dir </> "xmonad"
err = base ++ ".errors"
src = base ++ ".hs"
lib = dir </> "lib"
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
if force || any (binT <) (srcT : libTs)
useBuildscript <- do
exists <- doesFileExist buildscript
if exists
then do
isExe <- isExecutable buildscript
if isExe
then do
trace $ "XMonad will use build script at " ++ show buildscript ++ " to recompile."
return True
else do
trace $ unlines
[ "XMonad will not use build script, because " ++ show buildscript ++ " is not executable."
, "Suggested resolution to use it: chmod u+x " ++ show buildscript
]
return False
else do
trace $
"XMonad will use ghc to recompile, because " ++ show buildscript ++ " does not exist."
return False
shouldRecompile <-
if useBuildscript || force
then return True
else if any (binT <) (srcT : libTs)
then do
trace "XMonad doing recompile because some files have changed."
return True
else do
trace "XMonad skipping recompile because it is not forced (e.g. via --recompile), and neither xmonad.hs nor any *.hs / *.lhs / *.hsc files in lib/ have been changed."
return False
if shouldRecompile
then do
-- temporarily disable SIGCHLD ignoring:
uninstallSignalHandlers
status <- bracket (openFile err WriteMode) hClose $ \h ->
waitForProcess =<< runProcess "ghc" ["--make", "xmonad.hs", "-i", "-ilib", "-fforce-recomp", "-main-is", "main", "-v0", "-o",binn] (Just dir)
Nothing Nothing Nothing (Just h)
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", msg] Nothing
return ()
if status == ExitSuccess
then trace "XMonad recompilation process exited with success!"
else 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 ()

View File

@@ -137,7 +137,7 @@ data ChangeLayout = FirstLayout | NextLayout deriving (Eq, Show, Typeable)
instance Message ChangeLayout
-- | The layout choice combinator
(|||) :: (LayoutClass l a, LayoutClass r a) => l a -> r a -> Choose l r a
(|||) :: l a -> r a -> Choose l r a
(|||) = Choose L
infixr 5 |||

View File

@@ -13,10 +13,10 @@
--
-----------------------------------------------------------------------------
module XMonad.Main (xmonad) where
module XMonad.Main (xmonad, launch) where
import System.Locale.SetLocale
import Control.Arrow (second)
import qualified Control.Exception.Extensible as E
import Data.Bits
import Data.List ((\\))
import Data.Function
@@ -37,7 +37,7 @@ 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)
@@ -59,33 +59,29 @@ xmonad :: (LayoutClass l Window, Read (l Window)) => XConfig l -> IO ()
xmonad conf = do
installSignalHandlers -- important to ignore SIGCHLD to avoid zombies
let launch serializedWinset serializedExtState args = do
let launch' args = do
catchIO buildLaunch
conf' @ XConfig { layoutHook = Layout l }
<- handleExtraArgs conf args conf{ layoutHook = Layout (layoutHook conf) }
withArgs [] $
xmonadNoargs (conf' { layoutHook = l })
serializedWinset
serializedExtState
withArgs [] $ launch (conf' { layoutHook = l })
args <- getArgs
case args of
("--resume": ws : xs : args') -> launch (Just ws) (Just xs) args'
("--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' -> do
sendReplace
launch Nothing Nothing args'
_ -> launch Nothing Nothing args
"--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
@@ -99,13 +95,13 @@ usage = do
" --restart Request a running xmonad process to restart" :
[]
-- | Build "~\/.xmonad\/xmonad.hs" with ghc, then execute it. If there are no
-- errors, this function does not return. An exception is raised in any of
-- these cases:
-- | 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 "~\/.xmonad\/xmonad.hs" and "~\/.xmonad\/xmonad-$arch-$os" missing
-- * both the configuration file and executable are missing
--
-- * xmonad.hs fails to compile
--
@@ -117,12 +113,18 @@ usage = do
--
buildLaunch :: IO ()
buildLaunch = do
recompile False
dir <- getXMonadDir
args <- getArgs
whoami <- getProgName
let compiledConfig = "xmonad-"++arch++"-"++os
unless (whoami == compiledConfig) $
unless (whoami == compiledConfig) $ do
trace $ concat
[ "XMonad is recompiling and replacing itself another XMonad process because the current process is called "
, show whoami
, " but the compiled configuration should be called "
, show compiledConfig
]
recompile False
dir <- getXMonadDataDir
args <- getArgs
executeFile (dir </> compiledConfig) False args Nothing
sendRestart :: IO ()
@@ -144,15 +146,28 @@ sendReplace = do
rootw <- rootWindow dpy dflt
replace dpy dflt rootw
-- |
-- The main entry point
-- | Entry point into xmonad for custom builds.
--
xmonadNoargs :: (LayoutClass l Window, Read (l Window)) => XConfig l
-> Maybe String -- ^ serialized windowset
-> Maybe String -- ^ serialized extensible state
-> IO ()
xmonadNoargs initxmc serializedWinset serializedExtstate = do
-- 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
@@ -176,6 +191,7 @@ xmonadNoargs initxmc serializedWinset serializedExtstate = do
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)
@@ -187,22 +203,8 @@ xmonadNoargs initxmc serializedWinset serializedExtstate = do
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
maybeRead reads' s = case reads' s of
[(x, "")] -> Just x
_ -> Nothing
winset = fromMaybe initialWinset $ do
s <- serializedWinset
ws <- maybeRead reads s
return . W.ensureTags layout (workspaces xmc)
$ W.mapLayout (fromMaybe layout . maybeRead lreads) ws
extState = fromMaybe M.empty $ do
dyns <- serializedExtstate
vals <- maybeRead reads dyns
return . M.fromList . map (second Left) $ vals
cf = XConf
{ display = dpy
@@ -218,14 +220,24 @@ xmonadNoargs initxmc serializedWinset serializedExtstate = do
st = XState
{ windowset = initialWinset
, numberlockMask = 0
, numberlockMask = 0
, mapped = S.empty
, waitingUnmap = M.empty
, dragging = Nothing
, extensibleState = extState
, 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
@@ -240,6 +252,7 @@ xmonadNoargs initxmc serializedWinset serializedExtstate = do
-- 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
@@ -290,10 +303,10 @@ handle (KeyEvent {ev_event_type = t, ev_state = m, ev_keycode = code})
-- manage a new window
handle (MapRequestEvent {ev_window = w}) = withDisplay $ \dpy -> do
wa <- io $ getWindowAttributes dpy w -- 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) $ do manage w
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
@@ -356,7 +369,13 @@ handle e@(ButtonEvent {ev_window = w,ev_event_type = t,ev_button = b })
-- 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) (focus w)
= 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})
@@ -367,8 +386,6 @@ handle e@(CrossingEvent {ev_event_type = t})
-- configure a window
handle e@(ConfigureRequestEvent {ev_window = w}) = withDisplay $ \dpy -> do
ws <- gets windowset
wa <- io $ getWindowAttributes dpy w
bw <- asks (borderWidth . config)
if M.member w (floating ws)
@@ -382,7 +399,7 @@ handle e@(ConfigureRequestEvent {ev_window = w}) = withDisplay $ \dpy -> do
, wc_sibling = ev_above e
, wc_stack_mode = ev_detail e }
when (member w ws) (float w)
else io $ allocaXEvent $ \ev -> do
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)
@@ -416,7 +433,7 @@ handle e = broadcastMessage e -- trace (eventName e) -- ignoring
scan :: Display -> Window -> IO [Window]
scan dpy rootw = do
(_, _, ws) <- queryTree dpy rootw
filterM ok ws
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
@@ -428,6 +445,9 @@ scan dpy rootw = do
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
@@ -458,7 +478,7 @@ grabKeys = do
forM_ (keysymToKeycodes sym) $ \kc ->
mapM_ (grab kc . (mask .|.)) =<< extraModifiers
-- | XXX comment me
-- | Grab the buttons
grabButtons :: X ()
grabButtons = do
XConf { display = dpy, theRoot = rootw } <- ask

View File

@@ -1,6 +1,5 @@
{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, PatternGuards, TypeSynonymInstances #-}
{-# LANGUAGE FlexibleContexts, FlexibleInstances, MultiParamTypeClasses, PatternGuards, TypeSynonymInstances #-}
-- --------------------------------------------------------------------------
-- |
-- Module : XMonad.Operations
@@ -22,18 +21,22 @@ import XMonad.Layout (Full(..))
import qualified XMonad.StackSet as W
import Data.Maybe
import Data.Monoid (Endo(..))
import Data.Monoid (Endo(..),Any(..))
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.Applicative((<$>), (<*>))
import Control.Arrow (second)
import Control.Monad (void)
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)
@@ -111,7 +114,10 @@ windows f = do
mapM_ setInitialProperties newwindows
whenJust (W.peek old) $ \otherw -> io $ setWindowBorder d otherw nbc
whenJust (W.peek old) $ \otherw -> do
nbs <- asks (normalBorderColor . config)
setWindowBorderWithFallback d otherw nbs nbc
modify (\s -> s { windowset = ws })
-- notify non visibility
@@ -151,7 +157,9 @@ windows f = do
mapM_ (uncurry tileWindow) rects
whenJust (W.peek ws) $ \w -> io $ setWindowBorder d w fbc
whenJust (W.peek ws) $ \w -> do
fbs <- asks (focusedBorderColor . config)
setWindowBorderWithFallback d w fbs fbc
mapM_ reveal visible
setTopFocus
@@ -169,6 +177,25 @@ windows f = do
unless isMouseFocused $ clearEvents enterWindowMask
asks (logHook . config) >>= userCodeDef ()
-- | Modify the @WindowSet@ in state with no special handling.
modifyWindowSet :: (WindowSet -> WindowSet) -> X ()
modifyWindowSet f = modify $ \xst -> xst { windowset = f (windowset xst) }
-- | Perform an @X@ action and check its return value against a predicate p.
-- If p holds, unwind changes to the @WindowSet@ and replay them using @windows@.
windowBracket :: (a -> Bool) -> X a -> X a
windowBracket p action = withWindowSet $ \old -> do
a <- action
when (p a) . withWindowSet $ \new -> do
modifyWindowSet $ \_ -> old
windows $ \_ -> new
return a
-- | A version of @windowBracket@ that discards the return value, and handles an
-- @X@ action reporting its need for refresh via @Any@.
windowBracket_ :: X Any -> X ()
windowBracket_ = void . windowBracket getAny
-- | 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)
@@ -181,6 +208,19 @@ 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
@@ -233,10 +273,10 @@ clearEvents mask = withDisplay $ \d -> io $ do
-- | 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 -> do
bw <- (fromIntegral . wa_border_width) <$> io (getWindowAttributes d w)
tileWindow w r = withDisplay $ \d -> withWindowAttributes d w $ \wa -> do
-- give all windows at least 1x1 pixels
let least x | x <= bw*2 = 1
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)
@@ -351,15 +391,16 @@ setFocusX w = withWindowSet $ \ws -> do
-- Message handling
-- | Throw a message to the current 'LayoutClass' possibly modifying how we
-- layout the windows, then refresh.
-- layout the windows, in which case changes are handled through a refresh.
sendMessage :: Message a => a -> X ()
sendMessage a = do
sendMessage a = windowBracket_ $ 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)
modifyWindowSet $ \ws -> ws { W.current = (W.current ws)
{ W.workspace = (W.workspace $ W.current ws)
{ W.layout = l' }}}
return (Any $ isJust ml')
-- | Send a message to all layouts, without refreshing.
broadcastMessage :: Message a => a -> X ()
@@ -423,6 +464,79 @@ initColor dpy c = C.handle (\(C.SomeException _) -> return Nothing) $
------------------------------------------------------------------------
-- | 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'.
@@ -430,13 +544,8 @@ restart :: String -> Bool -> X ()
restart prog resume = do
broadcastMessage ReleaseResources
io . flush =<< asks display
let wsData = show . W.mapLayout show . windowset
maybeShow (t, Right (PersistentExtension ext)) = Just (t, show ext)
maybeShow (t, Left str) = Just (t, str)
maybeShow _ = Nothing
extState = return . show . catMaybes . map maybeShow . M.toList . extensibleState
args <- if resume then gets (\s -> "--resume":wsData s:extState s) else return []
catchIO (executeFile prog True args Nothing)
when resume writeStateToFile
catchIO (executeFile prog True [] Nothing)
------------------------------------------------------------------------
-- | Floating layer support
@@ -444,20 +553,27 @@ restart prog resume = do
-- | 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 = 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)
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)
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)
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
@@ -507,7 +623,7 @@ mouseDrag f done = do
clearEvents pointerMotionMask
return z
-- | XXX comment me
-- | 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
@@ -515,21 +631,26 @@ mouseMoveWindow w = whenX (isClient w) $ withDisplay $ \d -> do
(_, _, _, ox', oy', _, _, _) <- io $ queryPointer d w
let ox = fromIntegral ox'
oy = fromIntegral oy'
mouseDrag (\ex ey -> io $ moveWindow d w (fromIntegral (fromIntegral (wa_x wa) + (ex - ox)))
(fromIntegral (fromIntegral (wa_y wa) + (ey - 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)
-- | XXX comment me
-- | 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 ->
mouseDrag (\ex ey -> do
io $ resizeWindow d w `uncurry`
applySizeHintsContents sh (ex - fromIntegral (wa_x wa),
ey - fromIntegral (wa_y wa)))
ey - fromIntegral (wa_y wa))
float w)
(float w)
-- ---------------------------------------------------------------------
@@ -542,8 +663,12 @@ type D = (Dimension, Dimension)
mkAdjust :: Window -> X (D -> D)
mkAdjust w = withDisplay $ \d -> liftIO $ do
sh <- getWMNormalHints d w
bw <- fmap (fromIntegral . wa_border_width) $ getWindowAttributes d w
return $ applySizeHints bw sh
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.

View File

@@ -477,12 +477,12 @@ insertUp a s = if member a s then s else insert
--
-- * otherwise, delete doesn't affect the master.
--
delete :: (Ord a, Eq s) => a -> StackSet i l a s sd -> StackSet i l a s sd
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, Eq s) => a -> StackSet i l a s sd -> StackSet i l a s sd
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) }
@@ -547,7 +547,7 @@ shift n s = maybe s (\w -> shiftWin n w s) (peek s)
-- 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 a, Eq s, Eq i) => i -> a -> StackSet i l a s sd -> StackSet i l a s sd
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

7
stack.yaml Normal file
View File

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

View File

@@ -18,7 +18,7 @@ prop_delete x =
where _ = x :: T
-- delete is reversible with 'insert'.
-- It is the identiy, except for the 'master', which is reset on insert and delete.
-- It is the identity, except for the 'master', which is reset on insert and delete.
--
prop_delete_insert (x :: T) =
case peek x of

View File

@@ -4,23 +4,27 @@ 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
prop_abort x = unsafePerformIO $ C.catch (abort "fail")
(\(C.SomeException e) -> return $ show e == "xmonad: StackSet: fail" )
-- 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
_ = x :: Int
check (C.SomeException e) =
return $ "xmonad: StackSet: fail" `isPrefixOf` show e
-- new should fail with an abort
prop_new_abort x = unsafePerformIO $ C.catch f
(\(C.SomeException e) -> return $ show e == "xmonad: StackSet: non-positive argument to StackSet.new" )
prop_new_abort :: Int -> Bool
prop_new_abort _ = unsafePerformIO $ C.catch f check
where
f = new undefined{-layout-} [] [] `seq` return False
_ = x :: Int
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

@@ -1,57 +1,85 @@
{-# LANGUAGE FlexibleContexts #-}
-- Unlike the rest of xmonad, this file is copyright under the terms of the
-- GPL.
-- Generates a in-memory version of "man/xmonad.1.markdown" that has the list
-- of known key-bindings is inserted automatically from "Config.hs". That
-- document is then rendered with Pandoc as "man/xmonad.1" and
-- "man/xmonad.1.html".
--
-- 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
-- Unlike the rest of xmonad, this file is released under the GNU General
-- Public License version 2 or later.
import Control.Monad.IO.Class (liftIO)
import Data.Char
import Data.List
import qualified Data.Text as T
import qualified Data.Text.IO as TIO
import Text.Pandoc
import Text.Regex.Posix
import Distribution.PackageDescription.Parse
import Distribution.Verbosity
import Distribution.Package
import Distribution.PackageDescription
import Text.PrettyPrint.HughesPJ
import Distribution.Text
main :: IO ()
main = do
keybindings <- guessBindings
import Text.Pandoc -- works with 1.15.x
markdownSource <- readFile "./man/xmonad.1.markdown"
releaseDate = "31 December 2012"
runIOorExplode $ do
parsed <- readMarkdown (def { readerStandalone = True, readerExtensions = pandocExtensions })
. T.pack
. unlines
. replace "___KEYBINDINGS___" keybindings
. lines
$ markdownSource
trim :: String -> String
trim = reverse . dropWhile isSpace . reverse . dropWhile isSpace
manTemplate <- getDefaultTemplate "man"
manBody <- writeMan def { writerTemplate = Just manTemplate } parsed
liftIO $ TIO.writeFile "./man/xmonad.1" $ manBody
liftIO $ putStrLn "Documentation created: man/xmonad.1"
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])
htmltemplate <- getDefaultTemplate "html"
htmlBody <- writeHtml5String def
{ writerTemplate = Just htmltemplate
, writerTableOfContents = True }
parsed
liftIO $ TIO.writeFile "./man/xmonad.1.html" htmlBody
liftIO $ putStrLn "Documentation created: man/xmonad.1.html"
-- | The 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 name of the key binding is omitted, the function tries to guess it
-- 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 key binding name.
guessBindings :: IO String
guessBindings = do
buf <- readFile "./src/XMonad/Config.hs"
return (intercalate "\n\n" (map markdownDefn (allBindings buf)))
allBindings :: String -> [(String, String)]
allBindings xs = map (binding . map trim) (xs =~ "(.*)--(.*)%!(.*)")
binding :: [String] -> (String, String)
binding [ _, bindingLine, "", desc ] = (guessKeys bindingLine, desc)
binding [ _, _, keyCombo, desc ] = (keyCombo, desc)
binding x = error ("binding: called with unexpected argument " ++ show x)
allBindings :: String -> [(String, String)]
allBindings xs = map (binding . map trim) (xs =~ "(.*)--(.*)%!(.*)")
guessKeys :: String -> String
guessKeys line =
case keys of
[key] -> concat $ intersperse "-" (modifiers ++ [map toLower key])
_ -> error ("guessKeys: unexpected number of keys " ++ show keys)
where
modifiers = map (!!1) (line =~ "(mod|shift|control)Mask")
(_, _, _, keys) = line =~ "xK_([_[:alnum:]]+)" :: (String, String, String, [String])
-- FIXME: What escaping should we be doing on these strings?
markdownDefn :: (String, String) -> String
@@ -60,40 +88,5 @@ 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{ writerStandalone = True, writerTemplate = 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/>")]
, writerStandalone = True
, writerTemplate = template
, writerTableOfContents = True }
$ parsed
putStrLn "Documentation created: man/xmonad.1.html"
trim :: String -> String
trim = reverse . dropWhile isSpace . reverse . dropWhile isSpace

View File

@@ -1,125 +1,127 @@
name: xmonad
version: 0.12
homepage: http://xmonad.org
version: 0.15
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
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.
license: BSD3
license-file: LICENSE
author: Spencer Janssen
author: Spencer Janssen, Don Stewart, Adam Vogt, David Roundy, Jason Creighton,
Brent Yorgey, Peter Jones, Peter Simons, Andrea Rossato, Devin Mullins,
Lukas Mai, Alec Berryman, Stefan O'Rear, Daniel Wagner, Peter J. Jones,
Daniel Schoepe, Karsten Schoelzel, Neil Mitchell, Joachim Breitner,
Peter De Wachter, Eric Mertens, Geoff Reedy, Michiel Derhaeg,
Philipp Balzarek, Valery V. Vorotyntsev, Alex Tarkovsky, Fabian Beuke,
Felix Hirn, Michael Sloan, Tomas Janousek, Vanessa McHale, Nicolas Pouillard,
Aaron Denney, Austin Seipp, Benno Fünfstück, Brandon S Allbery, Chris Mears,
Christian Thiemann, Clint Adams, Daniel Neri, David Lazar, Ferenc Wagner,
Francesco Ariis, Gábor Lipták, Ivan N. Veselov, Ivan Tarasov, Javran Cheng,
Jens Petersen, Joey Hess, Jonne Ransijn, Josh Holland, Khudyakov Alexey,
Klaus Weidner, Michael G. Sloan, Mikkel Christiansen, Nicolas Dudebout,
Ondřej Súkup, Paul Hebble, Shachaf Ben-Kiki, Siim Põder, Tim McIver,
Trevor Elliott, Wouter Swierstra, Conrad Irwin, Tim Thelion
maintainer: xmonad@haskell.org
extra-source-files: README.md CHANGES.md TODO CONFIG STYLE
tested-with: GHC == 8.0.2, GHC == 8.2.2, GHC == 8.4.3, GHC == 8.6.1
category: System
homepage: http://xmonad.org
bug-reports: https://github.com/xmonad/xmonad/issues
build-type: Simple
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
man/xmonad.1.markdown
man/xmonad.1
man/xmonad.1.html
man/xmonad.hs
util/GenerateManpage.hs
util/hpcReport.sh
cabal-version: >= 1.8
bug-reports: https://github.com/xmonad/xmonad/issues
build-type: Simple
tested-with:
GHC==7.6.3,
GHC==7.8.4,
GHC==7.10.2
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
default: False
manual: True
description: Testing mode, only build minimal components
flag generatemanpage
description: Build the tool for generating the man page
default: False
manual: True
default: False
manual: True
description: Build the tool for generating the man page
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
exposed-modules: XMonad
XMonad.Config
XMonad.Core
XMonad.Layout
XMonad.Main
XMonad.ManageHook
XMonad.Operations
XMonad.StackSet
other-modules: Paths_xmonad
hs-source-dirs: src
build-depends: base >= 4.9 && < 5
, X11 >= 1.8 && < 1.10
, containers
, data-default
, directory
, extensible-exceptions
, filepath
, mtl
, process
, setlocale
, unix
, utf8-string >= 0.3 && < 1.1
ghc-options: -funbox-strict-fields -Wall -fno-warn-unused-do-bind
build-depends: base < 5 && >=3,
containers,
data-default,
directory,
extensible-exceptions,
filepath,
setlocale,
mtl,
process,
unix,
utf8-string >= 0.3 && < 1.1,
X11>=1.5 && < 1.7
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)
ghc-prof-options: -prof -auto-all
if flag(testing)
buildable: False
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
main-is: Main.hs
build-depends: base, X11, mtl, unix, xmonad
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
main-is: GenerateManpage.hs
hs-source-dirs: util
if flag(generatemanpage)
build-depends: base, pandoc >= 2, regex-posix, text
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
type: exitcode-stdio-1.0
main-is: Properties.hs
other-modules: Instances
Properties.Delete
Properties.Failure
Properties.Floating
Properties.Focus
Properties.GreedyView
Properties.Insert
Properties.Layout.Full
Properties.Layout.Tall
Properties.Screen
Properties.Shift
Properties.Stack
Properties.StackSet
Properties.Swap
Properties.View
Properties.Workspace
Utils
hs-source-dirs: tests
build-depends: base, QuickCheck >= 2, X11, containers, extensible-exceptions, xmonad