Compare commits

..

560 Commits

Author SHA1 Message Date
Tomáš Janoušek
fa8f34596d
Merge pull request #532 from xmonad/haskell-ci-update
ci: Regenerate haskell-ci
2025-05-12 18:44:00 +02:00
Tomas Janousek
799b0dc199 ci/nix: Drop weird magic URLs
I don't know what these are but I hope reverting to what
cachix/install-nix-action's documentation recommends will fix the errors
we're getting with presumably old Nix on new Ubuntu GitHub Actions
runners.
2025-05-12 17:34:47 +01:00
Tony Zorman
8ff0fb7b52 ci/nix: Switch to ubuntu-latest 2025-05-12 17:34:47 +01:00
github-actions[bot]
7a93f11bfd ci: Regenerate haskell-ci 2025-05-10 03:31:13 +00:00
github-actions[bot]
c605d09681 ci: Bump GHC patch versions in tested-with 2025-05-10 03:31:13 +00:00
github-actions[bot]
ebf265a84c ci: Regenerate haskell-ci 2025-04-13 16:57:14 +01:00
github-actions[bot]
da4ef9ea37 ci: Bump GHC patch versions in tested-with 2025-04-13 16:57:14 +01:00
github-actions[bot]
0d90d183a7 ci: Regenerate haskell-ci 2025-04-05 08:36:03 +01:00
Tony Zorman
756643c30e
Merge pull request #528 from xmonad/haskell-ci-update
ci: Regenerate haskell-ci
2025-03-31 08:24:37 +00:00
github-actions[bot]
ca1ba91360 ci: Regenerate haskell-ci 2025-03-29 03:18:46 +00:00
Tony Zorman
f2d1efbb6f
Merge pull request #527 from xmonad/haskell-ci-update
ci: Regenerate haskell-ci
2025-03-22 05:40:39 +00:00
github-actions[bot]
4173227e04 ci: Regenerate haskell-ci 2025-03-22 03:22:24 +00:00
github-actions[bot]
3a37d4c1f8 ci: Bump GHC patch versions in tested-with 2025-03-22 03:22:23 +00:00
Tony Zorman
bd99fd5f34
Merge pull request #526 from xmonad/dependabot/github_actions/cachix/install-nix-action-31
build(deps): bump cachix/install-nix-action from 30 to 31
2025-03-17 06:40:57 +00:00
dependabot[bot]
e9e1ad3190
build(deps): bump cachix/install-nix-action from 30 to 31
Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from 30 to 31.
- [Release notes](https://github.com/cachix/install-nix-action/releases)
- [Commits](https://github.com/cachix/install-nix-action/compare/v30...v31)

---
updated-dependencies:
- dependency-name: cachix/install-nix-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-17 00:32:32 +00:00
github-actions[bot]
07d95ad8fc ci: Regenerate haskell-ci 2025-02-22 11:12:16 +00:00
Tomas Janousek
39ae48970c ci: Add GHC 9.8 (Stackage LTS 23) to Stack test matrix 2025-01-26 22:51:37 +00:00
github-actions[bot]
eae89e25f9 ci: Regenerate haskell-ci 2025-01-25 09:36:33 +00:00
github-actions[bot]
ab6648ca8f ci: Bump GHC patch versions in tested-with 2025-01-25 09:36:33 +00:00
github-actions[bot]
5d73d294d4 man: Update 2025-01-02 21:10:55 +00:00
Tony Zorman
1c57ed4c9a
Merge pull request #523 from sol/cabal
Add recompilation support via `cabal`
2025-01-02 22:08:36 +01:00
Simon Hengel
30d3f7159b
Add recompilation support via cabal 2024-12-21 21:57:58 +07:00
github-actions[bot]
81cf71d7c6 ci: Regenerate haskell-ci 2024-11-16 05:44:27 +00:00
dependabot[bot]
eba9e97794 build(deps): bump cachix/install-nix-action from 29 to 30
Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from 29 to 30.
- [Release notes](https://github.com/cachix/install-nix-action/releases)
- [Commits](https://github.com/cachix/install-nix-action/compare/v29...v30)

---
updated-dependencies:
- dependency-name: cachix/install-nix-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-07 18:20:22 +02:00
Tony Zorman
aadb8df59b
Merge pull request #516 from xmonad/dependabot/github_actions/cachix/install-nix-action-v29
build(deps): bump cachix/install-nix-action from V28 to 29
2024-09-30 08:56:21 +02:00
dependabot[bot]
053c798085
build(deps): bump cachix/install-nix-action from V28 to 29
Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from V28 to 29. This release includes the previously tagged commit.
- [Release notes](https://github.com/cachix/install-nix-action/releases)
- [Commits](https://github.com/cachix/install-nix-action/compare/V28...v29)

---
updated-dependencies:
- dependency-name: cachix/install-nix-action
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-30 00:21:37 +00:00
dependabot[bot]
a4140b9349 build(deps): bump cachix/install-nix-action from V27 to 28
Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from V27 to 28. This release includes the previously tagged commit.
- [Release notes](https://github.com/cachix/install-nix-action/releases)
- [Commits](https://github.com/cachix/install-nix-action/compare/V27...V28)

---
updated-dependencies:
- dependency-name: cachix/install-nix-action
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-16 02:49:24 +01:00
Christina Sørensen
dad56b04f5 fix: deprecated url literals
Signed-off-by: Christina Sørensen <christina@cafkafk.com>
2024-09-15 19:09:07 -04:00
brandon s allbery kf8nh
a58ccac7ba restore the main loop
The ghc versions affected by the join point bug are long obsolete
and should not be being used by anyone.

This partially reverts #404.
2024-07-29 14:20:35 -04:00
github-actions[bot]
b1d9884d2d ci: Regenerate haskell-ci 2024-07-13 06:21:17 +01:00
Tomas Janousek
2ba1258cc1 Bump lower bound for base
We only test with GHC 8.6+ and the bounds should reflect that.

Related: a16541b834b5 ("ci: Drop support for GHC 8.4")
Related: 2e89e5ed23b4 ("Bump lower bound for base")
2024-07-07 15:07:49 +01:00
Tony Zorman
bcf3bf6c77
Merge pull request #508 from xmonad/haskell-ci-update
ci: Regenerate haskell-ci
2024-07-07 07:35:41 +02:00
github-actions[bot]
8b54c11558 ci: Regenerate haskell-ci 2024-07-06 03:15:57 +00:00
github-actions[bot]
7de2d3e969 ci: Bump GHC patch versions in tested-with 2024-07-06 03:15:57 +00:00
Tomas Janousek
cfbf1ad51d ci: Bump actions/upload-artifact to v4
v3 is deprecated:
https://github.blog/changelog/2024-04-16-deprecation-notice-v3-of-the-artifact-actions/
2024-05-21 22:40:50 +01:00
Tomáš Janoušek
21028ad648
Merge pull request #505 from xmonad/haskell-ci-update
ci: Regenerate haskell-ci (add GHC 9.10)
2024-05-21 21:32:58 +01:00
github-actions[bot]
4be171810c ci: Regenerate haskell-ci 2024-05-21 21:19:05 +01:00
github-actions[bot]
edadb427e7 ci: Bump GHC patch versions in tested-with 2024-05-21 21:19:05 +01:00
Tomas Janousek
38a303ea3e ci: gh-workflow-keepalive no longer needs a GITHUB_TOKEN input 2024-05-20 21:12:38 +01:00
Tony Zorman
4620a705b4
Merge pull request #506 from xmonad/dependabot/github_actions/cachix/install-nix-action-27
build(deps): bump cachix/install-nix-action from 26 to 27
2024-05-20 15:38:34 +02:00
dependabot[bot]
7d588210e2
build(deps): bump cachix/install-nix-action from 26 to 27
Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from 26 to 27.
- [Release notes](https://github.com/cachix/install-nix-action/releases)
- [Commits](https://github.com/cachix/install-nix-action/compare/v26...V27)

---
updated-dependencies:
- dependency-name: cachix/install-nix-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-20 01:00:14 +00:00
Tomas Janousek
f09d7aa641 ci: Expand stack test matrix 2024-05-13 11:36:40 +01:00
Markus Kurtz
cde1a25bca
Add details to ManageHook.hs docs (#504)
* Add details to ManageHook.hs docs

* Link specialised variants in `stringProperty` doc

* Fix typo

Co-authored-by: Tomáš Janoušek <tomi@nomi.cz>

---------

Co-authored-by: Tomáš Janoušek <tomi@nomi.cz>
2024-04-27 16:51:25 +02:00
Tomáš Janoušek
383e3d6f47
Merge pull request #502 from xmonad/haskell-ci-update
ci: Regenerate haskell-ci
2024-04-21 12:44:05 +02:00
github-actions[bot]
81a80b8a5d ci: Regenerate haskell-ci 2024-04-21 07:50:50 +00:00
github-actions[bot]
ce22dbf7db ci: Bump GHC patch versions in tested-with 2024-04-21 07:50:50 +00:00
Tony Zorman
88102c0afb
Merge pull request #501 from xmonad/haskell-ci-update
ci: Regenerate haskell-ci
2024-03-23 07:45:36 +01:00
github-actions[bot]
804bef7bcf ci: Regenerate haskell-ci 2024-03-23 03:16:30 +00:00
Tony Zorman
746880e9b9
Merge pull request #499 from xmonad/dependabot/github_actions/cachix/install-nix-action-26
build(deps): bump cachix/install-nix-action from 25 to 26
2024-03-11 20:10:05 +01:00
dependabot[bot]
82a7762f81
build(deps): bump cachix/install-nix-action from 25 to 26
Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from 25 to 26.
- [Release notes](https://github.com/cachix/install-nix-action/releases)
- [Commits](https://github.com/cachix/install-nix-action/compare/v25...v26)

---
updated-dependencies:
- dependency-name: cachix/install-nix-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-11 01:10:19 +00:00
Tony Zorman
459f6afeca TUTORIAL: Mention X.U.Ungrab being unnecessary with 0.18.0
Closes: https://github.com/xmonad/xmonad/issues/496
2024-03-10 16:42:24 -04:00
Tony Zorman
88b4ad3c13
Merge pull request #495 from xmonad/haskell-ci-update
ci: Regenerate haskell-ci
2024-03-02 07:53:23 +01:00
github-actions[bot]
7cb14762cb ci: Regenerate haskell-ci 2024-03-02 03:14:55 +00:00
github-actions[bot]
0ed6a2377e ci: Bump GHC patch versions in tested-with 2024-03-02 03:14:54 +00:00
Tony Zorman
e5548547e3 .mailmap: Update 2024-02-28 09:08:16 +01:00
Tomas Janousek
4b9ef59706 ci: Adopt the liskin/gh-workflow-keepalive action
This avoids hardcoding the workflow filename and thus makes
refactoring/renaming less error-prone.
2024-02-15 11:02:14 +00:00
Tony Zorman
5cf87c75cd flake: Use types.str instead of types.string
types.string is deprecated.

Related: https://github.com/NixOS/nixpkgs/pull/66346
2024-02-08 12:37:04 +01:00
Tony Zorman
c3acee78d0 Bump version to 0.18.0.9 2024-02-03 18:41:41 +01:00
Tony Zorman
1396343a58 Bump version to 0.18.0 2024-02-03 16:01:11 +01:00
dependabot[bot]
c9334fbae7 build(deps): bump actions/cache from 3 to 4
Bumps [actions/cache](https://github.com/actions/cache) from 3 to 4.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v3...v4)
2024-01-22 11:54:43 +00:00
Tomáš Janoušek
c496c31158
Merge pull request #489 from xmonad/haskell-ci-update
ci: Regenerate haskell-ci
2024-01-17 12:08:06 +00:00
github-actions[bot]
31f63bb162 ci: Regenerate haskell-ci 2024-01-17 11:52:56 +00:00
github-actions[bot]
ddb4292d5a ci: Bump GHC patch versions in tested-with 2024-01-17 11:52:56 +00:00
dependabot[bot]
765e059470 build(deps): bump cachix/install-nix-action from 24 to 25
Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from 24 to 25.
- [Release notes](https://github.com/cachix/install-nix-action/releases)
- [Commits](https://github.com/cachix/install-nix-action/compare/v24...v25)

---
updated-dependencies:
- dependency-name: cachix/install-nix-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-14 20:06:43 -05:00
Tomas Janousek
c4cf4715f7 Bump version number (pre-release 0.17.9)
Adding `unGrab` to X.Operations is potentially a user-config breaking
change (Ambiguous occurrence ‘unGrab’ …), so we need xmonad-contrib to
conditionally reexport this (instead of just deprecating the now
duplicated definition). Thus we need a version bump here.

Related: 0156e2963b4d ("X.Operations: Add unGrab")
2023-12-18 10:29:08 +00:00
Tony Zorman
fa124f5658
Merge pull request #482 from xmonad/haskell-ci-update
ci: Regenerate haskell-ci
2023-12-09 07:39:02 +01:00
Tony Zorman
855ff2f73c
Merge pull request #479 from iogrt/ungrab
Move `unGrab` to `XMonad.Operations`
2023-12-09 07:34:58 +01:00
github-actions[bot]
5a04fa185d ci: Regenerate haskell-ci 2023-12-09 03:13:35 +00:00
Tony Zorman
706f54862c
Merge pull request #481 from xmonad/dependabot/github_actions/cachix/install-nix-action-24
build(deps): bump cachix/install-nix-action from 23 to 24
2023-12-04 07:09:53 +01:00
dependabot[bot]
1d43cd203f
build(deps): bump cachix/install-nix-action from 23 to 24
Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from 23 to 24.
- [Release notes](https://github.com/cachix/install-nix-action/releases)
- [Commits](https://github.com/cachix/install-nix-action/compare/v23...v24)

---
updated-dependencies:
- dependency-name: cachix/install-nix-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-04 01:10:17 +00:00
Tony Zorman
8421b100dd flake: Allow users to modify the dev shell
Copy of xmonad/xmonad-contrib@f1ea1e533d
Documentation for this is already inside of contrib's NIX.md.

Co-authored-by: Ivan Malison <IvanMalison@gmail.com>
2023-11-20 19:37:31 +01:00
iogrt
0156e2963b X.Operations: Add unGrab 2023-11-20 19:30:47 +01:00
Tony Zorman
32afd5e7e8
Merge pull request #480 from xmonad/haskell-ci-update
ci: Regenerate haskell-ci
2023-11-18 08:06:22 +01:00
github-actions[bot]
404e50d560 ci: Regenerate haskell-ci 2023-11-18 03:15:27 +00:00
github-actions[bot]
05d6037f53 ci: Bump GHC patch versions in tested-with 2023-11-18 03:15:26 +00:00
Tomáš Janoušek
2f58567912
Merge pull request #478 from xmonad/haskell-ci-update
ci: Regenerate haskell-ci
2023-11-13 00:06:03 +00:00
Tomas Janousek
f2aa84e102 ci: Only build haddock for hackage with the latest GHC
Cabal 3.10.2.0 exposes a bug in Haddock shipped with GHC 9.0 and 9.2, so
we need to work around it by bumping the version of GHC/Haddock we use
for building/uploading docs to Hackage, and to prevent build failures we
don't ever try to build haddocks for Hackage with older versions of
GHC/Haddock.

Related: https://github.com/haskell/haddock/issues/1582#issuecomment-1611412223
Related: https://github.com/haskell/cabal/issues/8326
Related: https://github.com/haskell/cabal/issues/9060
Related: https://github.com/haskell/cabal/pull/9073
Related: https://github.com/haskell/cabal/pull/9049
2023-11-12 23:57:40 +00:00
github-actions[bot]
2b7e278f7f ci: Regenerate haskell-ci 2023-11-11 03:17:55 +00:00
Tomáš Janoušek
bd69d20d01
Merge pull request #477 from xmonad/haskell-ci-update
ci: Regenerate haskell-ci
2023-10-24 17:40:39 +01:00
Tomas Janousek
35fa7bf4a2 ci: Disable x-partial warnings in the testsuite
Related: https://github.com/xmonad/xmonad/pull/477
2023-10-24 17:27:34 +01:00
github-actions[bot]
a239a00977 ci: Regenerate haskell-ci 2023-10-24 12:30:27 +00:00
github-actions[bot]
afb66dd55c ci: Bump GHC patch versions in tested-with 2023-10-24 12:30:27 +00:00
Tony Zorman
1b7dea7acc
Merge pull request #476 from xmonad/haskell-ci-update
ci: Regenerate haskell-ci
2023-10-24 13:57:11 +02:00
github-actions[bot]
8e820945f4 ci: Regenerate haskell-ci 2023-10-24 11:22:30 +00:00
Tony Zorman
21cc6ebd93
Merge pull request #330 from colonelpanic8/nixRecompilationSupport
Add nix recompilation support
2023-10-07 12:00:39 +02:00
Tony Zorman
050ba6420d Export ifM from X.Core
This was added as a local function in
1e17c1c1bc26cdb93e23d4aa75e57fe48ff4c951, but it's actually present in
X.ManageHook already. However, since that module imports X.Core, we
can't use this as-is.
2023-10-07 11:43:27 +02:00
Ivan Malison
67b5510dde Add nix recompilation support 2023-10-07 11:41:58 +02:00
Tony Zorman
327c2cf0c1 stack: Bump resolver to lts-21.12
This also bumps the default GHC version from 9.4.6 to 9.4.7.
2023-09-23 14:19:05 +02:00
Tomas Janousek
96b3628b54 ci: Replace deprecated haskell/actions/hlint-*
See https://github.com/haskell/actions/pull/301#issuecomment-1722353522
2023-09-18 15:40:18 +01:00
Tomas Janousek
dc4d304802 Avoid use of partial function (head)
GHC 9.8 will produce warnings about it. (And HLS already does.)

Fixes: https://github.com/xmonad/xmonad/issues/468
2023-09-18 00:04:03 +01:00
Tomas Janousek
c264e4cdb3 ci: Replace deprecated haskell/actions/setup
See https://github.com/haskell/actions/pull/301 and
https://github.com/haskell/actions/pull/301/files
2023-09-17 23:16:39 +01:00
Tomáš Janoušek
bb895d8415
Merge pull request #467 from rnwst/patch-1
Fix typo in TUTORIAL.md
2023-09-17 21:31:01 +01:00
Tomas Janousek
897597463a ci: Drop unnecessary cmd from "Install packdeps"
Not needed since https://github.com/haskell/actions/pull/165 (Jan 2023).
2023-09-17 21:24:00 +01:00
R. N. West
937493256d
Fix typo in TUTORIAL.md 2023-09-17 13:54:24 +01:00
dependabot[bot]
8ec512b437 build(deps): bump actions/checkout from 3 to 4 (except haskell-ci workflow)
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-17 10:56:15 +01:00
Tony Zorman
e563e01a5f
Merge pull request #466 from xmonad/dependabot/github_actions/cachix/install-nix-action-23
build(deps): bump cachix/install-nix-action from 22 to 23
2023-09-11 05:51:07 +02:00
dependabot[bot]
0e4c1e6837
build(deps): bump cachix/install-nix-action from 22 to 23
Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from 22 to 23.
- [Release notes](https://github.com/cachix/install-nix-action/releases)
- [Commits](https://github.com/cachix/install-nix-action/compare/v22...v23)

---
updated-dependencies:
- dependency-name: cachix/install-nix-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-11 01:13:39 +00:00
Tony Zorman
5c2ba06902 stack: Bump resolver to 21.6
This is the newest lts resolver for 9.4.5.
2023-08-12 14:22:17 +02:00
Tony Zorman
efffa8946a
Merge pull request #463 from slotThe/tut/bits
TUTORIAL: Some Bits
2023-07-26 19:00:59 +02:00
Tony Zorman
431bb4b57c TUTORIAL: Add a subsection about the startupHook
This is especially relevant for people who use display managers and thus
probably do not want to use .xinitrc directly.
2023-07-22 11:47:42 +02:00
Tony Zorman
3c80296733 TUTORIAL: Mention the need for a wallpaper 2023-07-22 11:44:08 +02:00
Tony Zorman
f289b3b134
Merge pull request #462 from slotThe/ci/bump
Bump cabal/stack CI
2023-07-18 09:35:29 +02:00
Tony Zorman
0932779f15 ci/cabal: Bump GHC versions 2023-07-16 17:24:30 +02:00
Tony Zorman
9138046ec5 ci/stack: Add lts-21 resolver 2023-07-16 17:19:58 +02:00
Tomas Janousek
a24e9b4c7f ci: Use better github-actions user name/email
This one links to the GitHub Actions app.
2023-07-16 14:47:58 +01:00
brandon s allbery kf8nh
1aac6611d8
Correctly cite Conor McBride's paper
Per #461 which was brought up on `#haskell` recently after I mentioned our practical discussion of zippers as an alternative to the theoretical and mathematical ones usually brought up.
2023-06-28 14:28:54 -04:00
Tony Zorman
51e507e953
Merge pull request #460 from xmonad/geekosaur-patch-1
Update INSTALL.md
2023-06-26 08:38:44 +02:00
brandon s allbery kf8nh
10abd059b7
Update INSTALL.md
Patchup for cabal 3.10, which broke environment files: you now have to install `base` and any other dependencies explicitly.
2023-06-25 17:24:43 -04:00
Tony Zorman
d4c607c4f9
Merge pull request #457 from xmonad/dependabot/github_actions/cachix/install-nix-action-22
build(deps): bump cachix/install-nix-action from 21 to 22
2023-06-19 07:43:55 +02:00
dependabot[bot]
28bc7dacde
build(deps): bump cachix/install-nix-action from 21 to 22
Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from 21 to 22.
- [Release notes](https://github.com/cachix/install-nix-action/releases)
- [Commits](https://github.com/cachix/install-nix-action/compare/v21...v22)

---
updated-dependencies:
- dependency-name: cachix/install-nix-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-19 01:19:54 +00:00
Tomáš Janoušek
b7a76a5e8c
Merge pull request #456 from xmonad/dependabot/github_actions/cachix/install-nix-action-21
build(deps): bump cachix/install-nix-action from 20 to 21
2023-05-29 14:06:07 +02:00
dependabot[bot]
58f3e8c6f1
build(deps): bump cachix/install-nix-action from 20 to 21
Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from 20 to 21.
- [Release notes](https://github.com/cachix/install-nix-action/releases)
- [Commits](https://github.com/cachix/install-nix-action/compare/v20...v21)

---
updated-dependencies:
- dependency-name: cachix/install-nix-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-29 01:33:09 +00:00
Tomáš Janoušek
00045cfc2a
Merge pull request #446 from liskin/floatloc-size-hints
X.Operations: Apply size hints in floatLocation
2023-05-20 07:43:02 +01:00
Tomas Janousek
69134f9e8a X.Operations: Apply size hints in floatLocation
This is hopefully harmless with well-behaved clients and ordinary xmonad
configs, and it enables using re-floating to apply size hints to
existing windows. The only visible behaviour change I can foresee is
that tiled windows (which ignore hints by default, unless
X.L.LayoutHints is used) will now snap to size hints whenever they're
floated (either via a keybinding or on mouseMoveWindow), whereas
previously they'd only do so on mouseResizeWindow.

My use-case for this is the following: when I change fonts in my
terminal, it updates its size hints and then sends a
ConfigureRequestEvent to change its size to keep the number of rows and
columns the same, and it also happens to reset the position to 0, 0. If
it's tiled, that request is just ignored and hintsEventHook handles the
layout refresh. If it happens to be floating, I want neither the move to
0, 0 nor the window size change to keep rows/colums, so I have a
handleEventHook that ignores that ConfigureRequestEvent and just
refloats the window, but I need a way to reapply size hints.

I could add a separate function that applies these hints to the floating
RationalRect, but that seems like a lossy operation due to the Doubles
in there. So I'd probably end up replicating most of the code from
floatLocation, and then I might just improve that instead… :-)

(I'll submit that custom ConfigureRequestEvent-ignoring hook to
xmonad-contrib later.)
2023-05-20 08:34:07 +02:00
Tony Zorman
025a78508c
Merge pull request #455 from geekosaur/454-project-file
Clarify the use of `cabal.project`
2023-05-14 12:27:25 +02:00
brandon s allbery kf8nh
b03fa7a67b
Clarify the use of cabal.project
We've had a user show up in IRC who missed the parenthetical at the
end of the `cabal.project` step and got an error trying to build
from hackage. I've rephrased that part of the instructions to make
it clear that `cabal.project` is only needed when building from git.
2023-05-12 13:19:45 -04:00
brandon s allbery kf8nh
64fbf6a09d
Move willFloat to 0.17.1
Since it's a short doc change, I'm committing directly after verifying the preview is correct.
2023-05-01 10:00:00 -04:00
Tony Zorman
eeac754ac7
Merge pull request #445 from LSLeary/current-wins
Let the current screen win in the fight for dupes
2023-04-03 14:48:50 +02:00
L. S. Leary
5ee76ca48f Let the current screen win in the fight for dupes
`windows` generates mappings one screen at a time, starting with the
current. Tracking the windows it's already generated mappings for,
it excludes them from the tiles under consideration, hence supporting
window duplication in a first-biased manner. This allows the current
screen to win against any contenders and keep duplicated tiles within
reach.

However, it neglects to extend this treatment to floats; they end up
mapped in a last-biased manner. Consequently, duplicated floats become
very slippery, escaping to any inactive screen they can. This change
rectifies that issue.

See: xmonad/xmonad-contrib#797
2023-04-04 00:26:44 +12:00
Tony Zorman
aa9dd2696a cabal: Bump version to 0.17.2.9 2023-04-02 15:18:47 +02:00
Tony Zorman
19cba6b25f Merge branch 'release-v0.17.2' of https://github.com/xmonad/xmonad into after-0.17.2 2023-04-02 15:17:55 +02:00
Tony Zorman
a09ca446fb cabal: Update tested GHC versions
This syncs the cabal file with the reality of our CI.
2023-04-02 13:27:59 +02:00
Tomas Janousek
5641038500 CHANGES: Fix typo 2023-04-02 13:26:11 +02:00
Tony Zorman
990555c8ab Bump version to 0.17.2 2023-04-02 10:39:43 +02:00
Tony Zorman
a207e30751 CHANGES.md: Add changes for 0.17.2 2023-04-02 10:39:43 +02:00
Tony Zorman
970893f556 cabal: Update tested GHC versions
This syncs the cabal file with the reality of our CI.
2023-04-01 15:37:47 +02:00
Tony Zorman
460096dfc5 ci: Bump 9.2 and 9.4 minor versions
The stack CI already tests against 9.2.7 instead of 9.2.5 (as the cabal
file said), since we just specify the major version of the LTS resolver,
and lts-20 is up to 9.2.7 by now. Not much has changed since 9.2.5, but
update the haskell-ci workflow regardless. Likewise, 9.4 can be bumped
one minor version, so do that as well.

Related: xmonad/xmonad-contrib@1d84db959c
2023-04-01 15:18:23 +02:00
Tony Zorman
0817c6a7ff ci: Test against GHC 9.6.1
+ Regenerate haskell-ci and adjust relevant patches.
  - Remove haskell-ci-dependabot.patch, as it is no longer necessary.

Related: xmonad/xmonad-contrib@635711e994
2023-04-01 15:18:23 +02:00
Tomas Janousek
b59473b016 ci: Unpin runner in hlint workflow; bump hlint to 3.5
hlint 3.5 is built against libtinfo6 and works on Ubuntu 22.04 without
needing to install libtinfo5.

Fixes: e6329968ffe8 ("ci: Pin runner in hlint, nix workflows to ubuntu-20.04")
2023-04-01 15:18:08 +02:00
Tomas Janousek
c2aeaffc03 ci: Cabal install packdeps outside of project dir
Invoking cabal in the project directory with a cabal.project file might
fail on unrelated dependencies missing, see
4f539734be

Doesn't fail in this repo, but let's keep the workflows in sync.
2023-04-01 15:18:08 +02:00
Tomas Janousek
7f95f5ef07 ci: Pin runner in hlint, nix workflows to ubuntu-20.04
Both are now broken with ubuntu-22.04. Nix:

    error: could not set permissions on '/nix/var/nix/profiles/per-user' to 755: Operation not permitted

hlint:

    /opt/hostedtoolcache/hlint/3.4.1/x64/hlint: error while loading shared libraries: libtinfo.so.5: cannot open shared object file: No such file or directory
2023-04-01 15:18:08 +02:00
github-actions
57b715972b man: Update 2023-04-01 15:18:08 +02:00
Tomas Janousek
a9866836d9 ci: Drop ppa:hvr/ghc
Breaks `apt update` on the ubuntu-22.04 runner, which is what
ubuntu-latest resolves to these days.

Fixes: 3977a7a4e2d4 ("ci: Drop GHC installation via apt")
2023-04-01 15:18:08 +02:00
dependabot[bot]
099233812e build(deps): bump haskell/actions from 1 to 2
Bumps [haskell/actions](https://github.com/haskell/actions) from 1 to 2.
- [Release notes](https://github.com/haskell/actions/releases)
- [Commits](https://github.com/haskell/actions/compare/v1...v2)
2023-04-01 15:18:08 +02:00
Tomáš Janoušek
9cb13bdd3d ci: Configure dependabot to keep GH Actions up to date 2023-04-01 15:18:08 +02:00
Tomas Janousek
86bb4d2a21 ci: Bump actions/* to v3 in haskell-ci workflow
This gets rid of the deprecation warnings about
https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/
2023-04-01 15:18:08 +02:00
Tomas Janousek
30103efbc8 ci: Update to GHC 9.4.3 2023-04-01 15:18:08 +02:00
Tony Zorman
a16541b834 ci: Drop support for GHC 8.4
Debian stable is not on 8.6, which was always our guide as to which GHC
versions we want to support.

In particular, this lets us get rid of all the quickcheck-classes
special treatment.

Related: 400730fe3b
2023-04-01 15:17:45 +02:00
Tony Zorman
202fecf7ba ci: Update to GHC 9.2.5
+ A new stackage LTS is out with GHC 9.2.5, so test for this.
+ Update the haskell-ci jobs accordingly from 9.2.4.
2023-04-01 15:17:09 +02:00
Tomas Janousek
dd1e02555e ci: Fix docs tarball
haskell-ci by default passes --haddock-all to cabal v2-haddock, which
builds docs for all components and the …-docs.tar.gz tarball ends up
containing the docs for the last component, which happens to be tests.
We need the tarball to contain the library docs, for upload to Hackage.

Fixes: 25a4ed69da9c ("ci: Bump haskell-ci")
2023-04-01 15:17:01 +02:00
Tomas Janousek
4931bc4e41 X.Config: Appease -Werror=type-equality-requires-operators
GHC 9.4 complains:

    The use of ‘~’ without TypeOperators
    will become an error in a future GHC release.
2023-04-01 15:17:01 +02:00
Tomas Janousek
67267b7346 ci: Add GHC 9.4 to tested-with matrix (haskell-ci workflow)
(Also bump 9.2 to 9.2.4)
2023-04-01 15:17:01 +02:00
Tomas Janousek
4806b51a23 ci: Bump cachix/install-nix-action to v18
This gets rid of the deprecation warnings about
https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/
2023-04-01 15:17:01 +02:00
Tomas Janousek
98e5d1583d ci: Bump actions/{checkout,cache} to v3
This gets rid of the deprecation warnings about
https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/
2023-04-01 15:17:01 +02:00
Tomas Janousek
dc48e9e9c9 ci: Drop GHC installation via apt
The apt repo hosting these packages has been unmaintained for quite a
while, and we've excluded ~/.stack/programs from the cache long time
ago, so we can just let stack handle the installation. It's not much
slower than installing via apt, and even if it was, some matrix jobs
need to use the slow path anyway.

Related: 9fce3805fcf2 ("ci: Use system GHC in Stack to not waste GH Actions cache space")
Related: 7d10e470d71d ("ci: Avoid caching GHC")
2023-04-01 15:17:01 +02:00
Tomas Janousek
572d02d8e8 ci: Replace deprecated GHA set-output command
See https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/
2023-04-01 15:17:01 +02:00
Tomas Janousek
f53db04285 ci: Drop hlint from haskell-ci workflow
As we have a separate hlint workflow now, this is no longer needed.

Related: https://github.com/xmonad/xmonad-contrib/issues/669
Related: 7cee191516
2023-04-01 15:17:01 +02:00
Tomas Janousek
2324d21202 ci: Bump haskell-ci 2023-04-01 15:17:01 +02:00
Tomas Janousek
f2c9c75f67 ci: Add hlint workflow
The "haskell/actions/hlint-run" GitHub Action produces annotations which
GitHub shows in the code diff, in addition to just failing the workflow
when there are any suggestions. Also, now it runs in parallel to the
other workflows.

Related: https://github.com/xmonad/xmonad-contrib/issues/669
Related: dd26fcc3f1
2023-04-01 15:17:01 +02:00
Tony Zorman
1364ee4b1f stack: Bump resolver to lts-20.16
We test against 9.2.7 now, so we should make our stack config reflect
that—plus, it's more convenient for users, since one is more likely to
already have the latest minor version of GHC installed.

Related: xmonad/xmonad-contrib@d5c86dd17e
2023-03-31 07:49:53 +02:00
Tony Zorman
a17fa0d28b ci: Bump 9.2 and 9.4 minor versions
The stack CI already tests against 9.2.7 instead of 9.2.5 (as the cabal
file said), since we just specify the major version of the LTS resolver,
and lts-20 is up to 9.2.7 by now. Not much has changed since 9.2.5, but
update the haskell-ci workflow regardless. Likewise, 9.4 can be bumped
one minor version, so do that as well.

Related: xmonad/xmonad-contrib@1d84db959c
2023-03-31 07:48:46 +02:00
Tony Zorman
b394435443 ci: Test against GHC 9.6.1
+ Regenerate haskell-ci and adjust relevant patches.
  - Remove haskell-ci-dependabot.patch, as it is no longer necessary.

Related: xmonad/xmonad-contrib@635711e994
2023-03-31 07:46:37 +02:00
a5ob7r
faf5cf7b27 Fix compatibilities with unix 2.8.0.0
The version of unix removes the 3rd Maybe FileMode argument of openFd,
so we need to handle this breaking change using a MIN_VERSION macro. The
argument is integrated with the OpenFileFlags argument and the
integrated value in defaultFileFlags is Nothing, so there's no
difference between the two function calls.
2023-03-28 19:33:14 +02:00
a5ob7r
9d0fd62cb2 Fix compatibilities with mtl 2.3.1
No longer the version of mtl re-exports Control.Monad, Control.Monad.Fix
and Data.Monoid modules, so we need to import them directly instead.
2023-03-28 19:33:07 +02:00
Tony Zorman
386d4e6295
Merge pull request #441 from Equwece/suggest-to-use-ghcup
Suggest GHCup more intensively in INSTALL.md
2023-03-16 13:01:47 +01:00
Equwece
ea295dabcc INSTALL: Suggest to use ghcup more intensively
Closes: https://github.com/xmonad/xmonad/issues/373
2023-03-16 13:01:02 +01:00
Tony Zorman
4b3e5e0d07
Merge pull request #440 from xmonad/dependabot/github_actions/cachix/install-nix-action-20
build(deps): bump cachix/install-nix-action from 19 to 20
2023-03-06 08:02:38 +01:00
dependabot[bot]
4b2107a07a
build(deps): bump cachix/install-nix-action from 19 to 20
Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from 19 to 20.
- [Release notes](https://github.com/cachix/install-nix-action/releases)
- [Commits](https://github.com/cachix/install-nix-action/compare/v19...v20)

---
updated-dependencies:
- dependency-name: cachix/install-nix-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-06 01:38:12 +00:00
Tony Zorman
3ae5f46052
Merge pull request #439 from xmonad/dependabot/github_actions/cachix/install-nix-action-19
build(deps): bump cachix/install-nix-action from 18 to 19
2023-02-13 07:23:09 +01:00
dependabot[bot]
f734f19c1a
build(deps): bump cachix/install-nix-action from 18 to 19
Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from 18 to 19.
- [Release notes](https://github.com/cachix/install-nix-action/releases)
- [Commits](https://github.com/cachix/install-nix-action/compare/v18...v19)

---
updated-dependencies:
- dependency-name: cachix/install-nix-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-13 02:11:18 +00:00
Tomas Janousek
391c0fc0c9 TUTORIAL: Update xmobar URL
https://xmobar.org/ is no more.
2023-02-11 14:00:51 +00:00
Tony Zorman
5ecdf7591d
Merge pull request #437 from TheMC47/master
README: update badge URLs
2023-01-06 19:03:24 +01:00
Yecine Megdiche
301428e5df README: update badge URLs
See https://github.com/badges/shields/issues/8671
2023-01-06 13:49:07 +01:00
Tomas Janousek
63f73e18f9 ci: Unpin runner in hlint workflow; bump hlint to 3.5
hlint 3.5 is built against libtinfo6 and works on Ubuntu 22.04 without
needing to install libtinfo5.

Fixes: e6329968ffe8 ("ci: Pin runner in hlint, nix workflows to ubuntu-20.04")
2023-01-02 20:46:56 +01:00
Tomas Janousek
57c3a13125 ci: Cabal install packdeps outside of project dir
Invoking cabal in the project directory with a cabal.project file might
fail on unrelated dependencies missing, see
4f539734be

Doesn't fail in this repo, but let's keep the workflows in sync.
2022-12-03 13:15:30 +00:00
Tomas Janousek
e6329968ff ci: Pin runner in hlint, nix workflows to ubuntu-20.04
Both are now broken with ubuntu-22.04. Nix:

    error: could not set permissions on '/nix/var/nix/profiles/per-user' to 755: Operation not permitted

hlint:

    /opt/hostedtoolcache/hlint/3.4.1/x64/hlint: error while loading shared libraries: libtinfo.so.5: cannot open shared object file: No such file or directory
2022-12-01 12:02:23 +00:00
github-actions
c1670303c0 man: Update 2022-12-01 11:57:12 +00:00
Tomas Janousek
1d1c012cb9 ci: Drop ppa:hvr/ghc
Breaks `apt update` on the ubuntu-22.04 runner, which is what
ubuntu-latest resolves to these days.

Fixes: 3977a7a4e2d4 ("ci: Drop GHC installation via apt")
2022-12-01 11:55:06 +00:00
dependabot[bot]
a19ffb0404 build(deps): bump haskell/actions from 1 to 2
Bumps [haskell/actions](https://github.com/haskell/actions) from 1 to 2.
- [Release notes](https://github.com/haskell/actions/releases)
- [Commits](https://github.com/haskell/actions/compare/v1...v2)
2022-11-27 17:39:20 +00:00
Tomáš Janoušek
5aa70bd88a ci: Configure dependabot to keep GH Actions up to date 2022-11-27 17:39:20 +00:00
Tomas Janousek
2502fd8d55 ci: Bump actions/* to v3 in haskell-ci workflow
This gets rid of the deprecation warnings about
https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/
2022-11-27 17:38:41 +00:00
Tomas Janousek
d0942e37ad ci: Update to GHC 9.4.3 2022-11-27 17:37:40 +00:00
Tomas Janousek
40f8246080 MAINTAINERS: Add xmonad-docs build step to the release process 2022-11-25 19:32:43 +00:00
Tony Zorman
be8fd7fdc9 X.Core: Simplify DerivingVia instances
Fixes: cd86480ff7ff30eb7685b6281ce3e891497d2661

Co-authored-by: L. S. Leary <LSLeary@users.noreply.github.com>
2022-11-19 11:21:50 +01:00
Tomáš Janoušek
6e35910b62
Merge pull request #430 from slotThe/drop-8.4
Drop support for GHC 8.4
2022-11-19 09:55:42 +00:00
Tony Zorman
2f2d105098 stack: Bump resolver to lts-20.0 2022-11-19 09:50:02 +01:00
Tony Zorman
cd86480ff7 Use DerivingVia for obvious instances
Certain instance definitions are so automatic, they should be derivable.
Starting with GHC 8.6, they are!
2022-11-19 09:50:00 +01:00
Tony Zorman
5c7c28060c ci: Drop support for GHC 8.4
Debian stable is not on 8.6, which was always our guide as to which GHC
versions we want to support.

In particular, this lets us get rid of all the quickcheck-classes
special treatment.

Related: 400730fe3b
2022-11-19 09:29:37 +01:00
Tony Zorman
78719507a9 ci: Update to GHC 9.2.5
+ A new stackage LTS is out with GHC 9.2.5, so test for this.
+ Update the haskell-ci jobs accordingly from 9.2.4.
2022-11-18 19:12:57 +01:00
Tony Zorman
f4d25fcef4
Merge pull request #426 from damhiya/improve-tall
improve Tall
2022-11-10 15:53:40 +01:00
damhiya
314390937c X.Layout: Don't draw zero-area windows in Tall 2022-11-10 15:52:39 +01:00
Tony Zorman
cf4d6f31b1
Merge pull request #428 from a5ob7r/compatible_with_unix_2.8.0
Fix compatibilities with unix 2.8.0.0
2022-11-05 08:13:37 +01:00
a5ob7r
044d9244e5 Fix compatibilities with unix 2.8.0.0
The version of unix removes the 3rd Maybe FileMode argument of openFd,
so we need to handle this breaking change using a MIN_VERSION macro. The
argument is integrated with the OpenFileFlags argument and the
integrated value in defaultFileFlags is Nothing, so there's no
difference between the two function calls.
2022-11-05 12:54:50 +09:00
Tony Zorman
ab99c17a68
Merge pull request #427 from a5ob7r/compatible_with_mtl_2.3
Fix compatibilities with mtl 2.3.1
2022-11-03 08:10:31 +01:00
a5ob7r
d170e99bc5 Fix compatibilities with mtl 2.3.1
No longer the version of mtl re-exports Control.Monad, Control.Monad.Fix
and Data.Monoid modules, so we need to import them directly instead.
2022-11-03 14:39:28 +09:00
Tomáš Janoušek
96452213f4
Merge pull request #425 from xmonad/hlint
CI maintenance (hlint workflow, GHA deprecations, GHC 9.4)
2022-10-31 11:45:21 +00:00
Tomas Janousek
c19eb06807 ci: Fix docs tarball
haskell-ci by default passes --haddock-all to cabal v2-haddock, which
builds docs for all components and the …-docs.tar.gz tarball ends up
containing the docs for the last component, which happens to be tests.
We need the tarball to contain the library docs, for upload to Hackage.

Fixes: 25a4ed69da9c ("ci: Bump haskell-ci")
2022-10-30 23:05:31 +00:00
Tomas Janousek
6d7da8dc25 X.Config: Appease -Werror=type-equality-requires-operators
GHC 9.4 complains:

    The use of ‘~’ without TypeOperators
    will become an error in a future GHC release.
2022-10-30 21:48:40 +00:00
Tomas Janousek
f96b3f0398 ci: Add GHC 9.4 to tested-with matrix (haskell-ci workflow)
(Also bump 9.2 to 9.2.4)
2022-10-30 21:37:37 +00:00
Tomas Janousek
34f257ad6f ci: Bump cachix/install-nix-action to v18
This gets rid of the deprecation warnings about
https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/
2022-10-30 21:29:49 +00:00
Tomas Janousek
f94ad61a27 ci: Bump actions/{checkout,cache} to v3
This gets rid of the deprecation warnings about
https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/
2022-10-30 21:18:05 +00:00
Tomas Janousek
3977a7a4e2 ci: Drop GHC installation via apt
The apt repo hosting these packages has been unmaintained for quite a
while, and we've excluded ~/.stack/programs from the cache long time
ago, so we can just let stack handle the installation. It's not much
slower than installing via apt, and even if it was, some matrix jobs
need to use the slow path anyway.

Related: 9fce3805fcf2 ("ci: Use system GHC in Stack to not waste GH Actions cache space")
Related: 7d10e470d71d ("ci: Avoid caching GHC")
2022-10-30 20:59:39 +00:00
Tomas Janousek
3cd839f0ac ci: Replace deprecated GHA set-output command
See https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/
2022-10-30 20:39:15 +00:00
Tomas Janousek
a9abc4e09c ci: Drop hlint from haskell-ci workflow
As we have a separate hlint workflow now, this is no longer needed.

Related: https://github.com/xmonad/xmonad-contrib/issues/669
Related: 7cee191516
2022-10-30 20:31:04 +00:00
Tomas Janousek
25a4ed69da ci: Bump haskell-ci 2022-10-30 20:31:04 +00:00
Tomas Janousek
262dc4779f ci: Add hlint workflow
The "haskell/actions/hlint-run" GitHub Action produces annotations which
GitHub shows in the code diff, in addition to just failing the workflow
when there are any suggestions. Also, now it runs in parallel to the
other workflows.

Related: https://github.com/xmonad/xmonad-contrib/issues/669
Related: dd26fcc3f1
2022-10-30 20:30:57 +00:00
Tony Zorman
a2259bb309
Merge pull request #421 from slotThe/expose-internals
Expose buildLaunch, sendRestart, and sendReplace
2022-09-18 16:27:14 +02:00
Tony Zorman
3d8238b35d Expose buildLaunch, sendRestart, and sendReplace
+ Move sendRestart and sendRestart to X.Operations, as this seems like a
  better fit.

Closes: https://github.com/xmonad/xmonad/issues/416
2022-09-10 10:27:26 +02:00
Tony Zorman
fd9de8903f TUTORIAL: Add separators for < 0.17.0 instructions
At least one of the instructions spans multiple paragraphs, which makes
it difficult to make out when this kind of interlude ends and the rest
of the text picks back up.  Introducing separators, while slightly
visually jarring, solves this problem.  As such, make sure that these
sections are reasonably far apart and group ones that are close
together.
2022-09-08 19:20:35 +02:00
Tony Zorman
fb1f33258e TUTORIAL: Remove ewmhFullscreen from < 0.17.0 instructions
This is a new function in 0.17.0, despite it being around for a long
time.
2022-09-08 19:20:35 +02:00
Tony Zorman
d0f12af1ae
Merge pull request #420 from LSLeary/nixflake
Fixes and Workarounds in flake.nix
2022-09-05 17:50:49 +02:00
L. S. Leary
df6b40c980 flake.nix:
* Avoid mangling unused parts of pkgs.haskell in `fromHOL`.
  * Create 'defComp', specifying the default compiler, customisable
    through ./comp.nix.
  * Include `modernise` module as a workaround for NIX_GHC -> XMONAD_GHC.
.gitignore:
  * Include nix 'result' symlink.
2022-09-05 20:14:46 +12:00
Tomas Janousek
b771abeadc Bump version to 0.17.1.9 and prepare CHANGES.md sections 2022-09-03 16:21:52 +01:00
Tony Zorman
2db596fbe8
Merge pull request #419 from ErnestKz/master
CHANGES.md: Fix date.
2022-09-03 16:51:25 +02:00
ernestkz
0f31b24bd2 CHANGES.md: Fix date. 2022-09-03 15:37:32 +01:00
Tony Zorman
5cdddab1f1 INSTALL: Suggest newer tagged releases 2022-09-03 14:52:45 +02:00
Tony Zorman
488b52ffaa Bump version to 0.17.1 2022-09-03 14:47:26 +02:00
Tony Zorman
83a8bb8d51 TUTORIAL: Fix link to xmobar.hs example
In [1] xmobar renamed the "examples" directory to "etc".

[1]: 6330397707
2022-08-13 06:27:17 +02:00
Tony Zorman
b06d885e76 X.ManageHook: Clarify {app,class}Name documentation
Users often mistakenly use className to query the application (resource)
name of a window; probably since WM_CLASS even has "class" in its name,
so confusion ensues.  Improve the documentation to explicitly state
which of the two strings in WM_CLASS the respective functions match.
2022-08-08 11:03:25 +02:00
Tony Zorman
a13a1dcee8
Merge pull request #404 from geekosaur/forever-away
attempt to work around the join point bug (#389)
2022-08-04 08:48:43 +02:00
brandon s allbery kf8nh
8965e41d06 attempt to work around the join point bug (#389) 2022-08-04 08:44:50 +02:00
Tony Zorman
28afc9bdc6
Merge pull request #405 from slotThe/modal-util-to-core
X.Operations: Export setNumlockMask, grabKeys
2022-08-02 11:21:50 +02:00
Tony Zorman
23f36d7e23
Merge pull request #409 from alternateved/fix-nix-build
Fix Nix builds
2022-08-02 08:03:30 +02:00
Tomasz Hołubowicz
117583e473 flake.nix: Fix build
As advised in [1], provide a way to set the path for the xmessage and
ghc binaries via XMONAD_XMESSAGE and XMONAD_GHC environment variables.

[1]: 36d5761b3e
2022-08-02 08:02:40 +02:00
Tony Zorman
bf6e66b100 X.Operations: Export setNumlockMask, grabKeys
As discussed in xmonad/xmonad-contrib/#703, certain functions that
X.U.Grab has vendored should really just be exported from core.

Related: https://github.com/xmonad/xmonad-contrib/pull/703
2022-08-01 11:59:37 +02:00
Tomas Janousek
366c09b3d7 TUTORIAL: Fix links to xmobar 2022-07-30 14:59:14 +01:00
Tomas Janousek
ed5c8667b1 Revert "Revert "Merge pull request #350 from Thiago4532/opaque-window-border""
This reverts commit e5a258f19c0ae715c36c3d5646486578f4cdf94d.

https://github.com/xmonad/xmonad-contrib/pull/731 fixes the
WindowNavigation issue with alpha channels, so we can re-enable alpha
support.
2022-07-05 23:09:10 +01:00
brandon s allbery kf8nh
1695aeb28a
Revert "Revert "CHANGES: Add missing entry for #350""
This reverts commit 29475fa7f8f04dcb68913b78bffcdfa2e99ee33a.

xmonad/xmonad-contrib#731 fixes the WindowNavigation issue with alpha
channels, so we can re-enable alpha support. A subsequent commit will
bump versions/dependencies to keep things in sync, although strictly
speaking that's not necessary here.
2022-07-05 17:50:17 -04:00
Tony Zorman
521e8356fc X.ManageHook: Define infix operators in an infix way
As discussed in #401, while hlint complains on a definition like

    (<||>) x y = ifM x (pure True) y

because it could be eta reduced, actually doing that and writing

    (<||>) x = ifM x (pure True)

feels a bit awkward.  The solution is to always actually define these
kinds of infix operators in an infix way; i.e., we write

    x <||> y = ifM x (pure True) y

instead.  For the sake of consistency, it now seems prudent to define
all infix operators in this way (with exceptions for literal aliases,
like `(<+>) = mappend`).

Related: https://github.com/xmonad/xmonad/pull/401
2022-06-29 09:40:55 +02:00
Tomas Janousek
45a89130d9 Merge branch 'hlint' 2022-06-25 18:49:02 +01:00
Tomas Janousek
79602bfec5 tests: Apply hlint hints 2022-06-25 18:49:02 +01:00
Tomas Janousek
711b28f494 Apply hlint hints
Makes src/ hlint-clean.
2022-06-25 18:49:02 +01:00
Tomas Janousek
0edb65107b Clean up LANGUAGE pragmas
Make it git-friendly and drop some extra ones as suggested by hlint.
2022-06-25 18:49:02 +01:00
Tomas Janousek
845d770f35 man: Apply hlint hints
These were applied to src/XMonad/Config.hs back in 2010 (77b3f62610) … :-)
2022-06-25 18:49:02 +01:00
Tomas Janousek
3f1a37f216 ci: Enable hlint in haskell-ci
Closes: https://github.com/xmonad/xmonad/pull/402
Related: https://github.com/xmonad/xmonad-contrib/issues/669
2022-06-25 18:49:02 +01:00
Andrew Lushin
165e25f9e0 Lint some pieces of code
Closes: https://github.com/xmonad/xmonad/pull/401
2022-06-25 18:49:02 +01:00
Tomas Janousek
9189d002dd ci: Prevent scheduled workflows from being auto-disabled by GitHub 2022-06-19 17:04:43 +01:00
Tomas Janousek
29475fa7f8 Revert "CHANGES: Add missing entry for #350"
This reverts commit c537a0658a3b9ec25cb1ce108d3cdd3dce27f111.

A discussion of why, as well as a new way forward, in being discussed in

    https://github.com/xmonad/xmonad/issues/395

However, since we would like to release a new minor version soon-ish,
it's better to revert this for now.

Fixes: e5a258f19c0a ("Revert "Merge pull request #350 from Thiago4532/opaque-window-border"")
2022-06-19 16:54:29 +01:00
Tony Zorman
e5a258f19c Revert "Merge pull request #350 from Thiago4532/opaque-window-border"
This reverts commit dbe9c4f799fd826c199169d012c2d2687b210a7f, reversing
changes made to f6e4e278b54a8c37bfcd620debf4256cb59b875a.

A discussion of why, as well as a new way forward, in being discussed in

    https://github.com/xmonad/xmonad/issues/395

However, since we would like to release a new minor version soon-ish,
it's better to revert this for now.
2022-06-18 17:40:25 +02:00
Tomáš Janoušek
0c8ed88d8a
Merge pull request #342 from TheMC47/contributing-changes
CONTRIBUTING: Update to reflect current practices
2022-06-13 11:39:34 +02:00
Yecine Megdiche
9442871016 CONTRIBUTING: Document expectations about maintenance and getting involved
Related: https://github.com/xmonad/xmonad/issues/341
2022-06-13 11:05:25 +02:00
Tomas Janousek
adb363a480 CONTRIBUTING: Add missing periods
Related: https://github.com/xmonad/xmonad/issues/341
2022-06-13 11:03:28 +02:00
Yecine Megdiche
3d65a37c7e CONTRIBUTING: Drop "Rebasing and Squashing Commits" in favor of online docs
Single-commit pull requests are discouraged by the core team now, so
drop that section and just refer to cbeams a kernel docs instead.

Related: https://github.com/xmonad/xmonad/issues/341
2022-06-13 10:59:41 +02:00
Tony Zorman
54d921c5a6 TUTORIAL: Only user letter keys for the bindings
On IRC an issue came up where a user couldn't press M-] since they were
using a German keyboard layout and ] is put behind some AltGr
combination.  The correct way to specify that would be something along
the lines of M-M5-9, but we don't really want to go into that in the
tutorial.  Thus, only use the obvious modifiers, as well as letters,
which should work on every layout.
2022-05-17 18:31:01 +02:00
brandon s allbery kf8nh
f61fdbaf0c MAINTAINERS: Add geekosaur's GPG key 2022-05-15 22:08:38 +02:00
Tomas Janousek
d88643c639 TUTORIAL: Fix broken link to liskin's xmobarrc
I switched to compiled config as well now:
d816717dee
2022-05-09 11:59:21 +01:00
Tony Zorman
eaaf0aafcd stack: Bump default resolver to 19.6
No impact on CI, just makes it easier for contributors to use the latest
9.0 GHC.
2022-05-07 09:40:56 +02:00
Tony Zorman
23df88d778
Merge pull request #392 from LSLeary/flake-module
Apply Patch in Nix Flake; Enable Configuration
2022-05-04 20:46:41 +02:00
L. S. Leary
90d0ca4a2e flake.nix: Point to xmonad-contrib/NIX.md. Assume maintainership. 2022-05-04 19:18:11 +12:00
L. S. Leary
f3f0c712d8 flake.nix: Configure the flake via NixOS module. 2022-04-25 01:58:46 +12:00
L. S. Leary
a5b708ba00 flake.nix: Provide the hoverlay and a version of fromHOL taking a
compiler argument, as well as the hpath function that does the work.
2022-04-25 01:46:39 +12:00
L. S. Leary
6fc90cd9d3 flake.nix: Bring in the patch from unstable.
Separate the noise from the overlay, exporting it as lib.fromHOL for reuse
in the xmonad-contrib flake.
2022-04-25 01:40:53 +12:00
Tony Zorman
3009304352
Merge pull request #391 from geekosaur/document-build-scripts
document build scripts
2022-04-19 19:39:54 +02:00
brandon s allbery kf8nh
5dd964e109 document build scripts
Requires https://github.com/xmonad/xmonad-contrib/pull/710
2022-04-18 17:24:51 -04:00
Tomas Janousek
90c719148b ci: Discard old caches to fix build failures
We're getting "undefined reference" errors during linking, suggesting
some build artifacts in the cache are stale and need to be rebuilt.
2022-04-18 23:24:09 +02:00
slotThe
831ca49331 X.StackSet: Add links to references 2022-04-12 12:48:35 +02:00
slotThe
2c9e24e0f6 X.StackSet: Give all functions their own Haddock comments
So far, some functions like focus{Up,Down} and swap{Up,Down} had
combined Haddock comments, since giving each their own would result in
some duplication of information.  This is nicer when reading the source,
but Haddock can't really handle this when generating the HTML page,
which will come out a bit garbled in that case.  Since a lot of users
may be only reading the Haddocks, we should prefer this to a source with
as few redundancies as possible.

Closes: https://github.com/xmonad/xmonad/issues/387
2022-04-12 11:42:01 +02:00
slotThe
a854cdaf9b ci: Update supported GHC versions
+ Prefer GHC 8.10.7 to 8.10.4, as versions seem to have stabilised now.
+ Add support for Stackage LTS 19; this ships with GHC 9.0.2.
+ Since a new version of 9.2 has been released, prefer 9.2.2 over 9.2.1.

Related: https://github.com/xmonad/xmonad-contrib/pull/694
2022-04-05 14:33:23 +02:00
slotThe
c2904425e9 TUTORIAL: Fix typos
Mostly capitalising names that ought to be capitalised.
2022-03-11 15:49:01 +01:00
slotThe
89ea1356c1 INSTALL.md: Add Void dependencies
Since things like `ncurses-libtinfo` are needed due to [1], it makes
sense to have all dependencies spelled out explicitly.

Related: https://github.com/xmonad/xmonad-web/issues/57
[1]: https://github.com/void-linux/void-packages/issues/7403
2022-03-08 09:23:41 +01:00
Tomas Janousek
f4a5b88e64 MAINTAINERS: Tweak the release procedure a bit
* Clarify what needs to be done with CHANGES.md
* Early release announcement preparation
2022-02-14 18:15:53 +00:00
Tomas Janousek
906b9d34b3 X.Operations: Whitespace cleanup after #371 2022-02-01 18:12:05 +00:00
Tomas Janousek
c537a0658a CHANGES: Add missing entry for #350 2022-02-01 18:09:12 +00:00
Tony Zorman
8546ea095b
Merge pull request #371 from andrea-berling/will-float
Add function to detect floating windows in ManageHook
2022-01-26 11:22:53 +01:00
Andrea Berlingieri
c2e632a2b9 Factor our common logic for floating windows
Factour out the code used to detect whether a window should be floating
in Operations.hs in a new function named isFixedSizeOrTransient

Modify willFloat to use the factored out code from Opeartions.hs
2022-01-22 23:00:41 +01:00
Andrea Berlingieri
b6af6bb86a Add function to detect floating windows in ManageHook
Add a willFloat function to deteect whether the managed window will be
floating or not

Add description of added change to CHANGES.md
2022-01-22 21:56:53 +01:00
Tomas Janousek
eee0a0dc39 flake.nix: Use upstream gitignore.nix instead of Ivan's fork 2022-01-15 12:03:35 +00:00
Mike Nrafter
0f5b5c2297 Fixed flake.nix's use of GitIgnore. 2022-01-12 19:58:52 -07:00
slotThe
e25d090112 cabal: Add myself to authors
About time, I suppose :)
2021-12-11 19:54:05 +01:00
Tony Zorman
eb2ee340e4
Merge pull request #352 from slotThe/custom-cursor
X.Operations: Use custom cursor for dragging/resizing
2021-12-01 12:11:29 +01:00
slotThe
79278d9475 X.Operations: Use custom cursor for dragging/resizing
When dragging and resizing windows, users may expect the cursor to
change to indicate the respective behaviour.  In particular, many other
window managers already do this [1] [2].

Thus, introduce a new (non-exported) `mouseDragCursor` function that
takes a cursor shape and change the generic resize and move functions to
use that.  The reason that we don't change `mouseDrag` itself (for now)
is that this is exported and quite a few contrib modules use it—breaking
compatibility with xmonad-0.17.0 so soon after the release seems unwise.

Fixes: https://github.com/xmonad/xmonad/issues/348

[1]: https://git.suckless.org/dwm/file/dwm.c.html#l1567
[2]: 7a8fa9d27a/lib/awful/mouse/resize.lua (L23)
2021-11-25 09:12:22 +01:00
Tony Zorman
dbe9c4f799
Merge pull request #350 from Thiago4532/opaque-window-border
X.Operations: Make window borders opaque
2021-11-22 17:49:44 +01:00
Tomas Janousek
f6e4e278b5 README: Make spaces _not_ part of hyperlinks 2021-11-22 11:28:19 +00:00
Tomas Janousek
673de33436 README: Add badges for IRC and Matrix 2021-11-22 11:26:20 +00:00
slotThe
a5b6e09985 INSTALL.md: Remind users to check which xmonad
We have had this situation happen a few times now: users update
xmonad (say, to 0.17.0) but forget that they still have an older version
installed via the distributions repositories.  Features that depend on
the "bootstrap" xmonad executable to be updated (like the improved XDG
support) then fail badly.

Thus, remind users to check whether the right executable is present.
2021-11-20 11:26:18 +01:00
Thiago Mota
bb448cc293 X.Operations: Make window borders opaque 2021-11-18 19:53:05 -03:00
slotThe
ae4c5e26be MAINTAINERS.md: Add PGP key for slotThe
Also, move the bullet point to the end so as to keep the list
alphabetically ordered.
2021-11-17 19:34:38 +01:00
slotThe
54df2e9acd INSTALL.md: Mention more packages as dependencies for Arch
At least on Arch, none of the listed packages necessarily require that
the user has a working Xorg setup—this has already caused some confusion
for people.  In particular, xmessage is very much needed in order to
show warnings and compilation errors.
2021-11-14 13:26:34 +01:00
Tomas Janousek
7f6d758ce5 MAINTAINERS: Update the Hackage release step 2021-11-08 18:15:07 +00:00
Tomas Janousek
9f64c2ca90 ci: Show error body from Hackage when it fails
Prevents having to upload the candidate manually to see what's wrong.
2021-11-08 18:14:52 +00:00
Tomas Janousek
9849800dc5 ci: Swap candidate/final release logic
During the release of xmonad 0.17.0, I realized that we need to be able
to upload candidates before tagging the release on GitHub, because there
might be issues with the tarball and Hackage may reject it. When that
happened, I had to remove the release, delete the tag, upload the
candidate manually to see what's wrong with it, try to fix it, upload it
manually again, and so on.

This commit swaps the logic: when the workflow is invoked manually, it
uploads the candidate. This can be done multiple times, and once
everything is fine, the release can finally be tagged and it's released
to Hackage proper. The only disadvantage is that we need to remember to
try uploading the candidate. Not sure if there's a perfect solution…
2021-11-08 18:13:23 +00:00
Tomáš Janoušek
a902fefaf1
Merge pull request #346 from liskin/ghc92
Test against GHC 9.2.1; fix new warnings
2021-11-04 11:05:14 +00:00
Tomas Janousek
0f708e76b1 Fix -Wnoncanonical-monad-instances, -Wnoncanonical-monoid-instances 2021-10-31 11:53:42 +00:00
Tomas Janousek
6e6f562b0d Fix Pattern match(es) are non-exhaustive warnings
Many of these are legitimate, like the one in rescreen where it really
can be empty and xmonad might crash. Or the one in Main, where using an
irrefutable pattern means a pattern-match failure isn't reported using
the MonadFail instance of IO, but is left to crash later when the thunk
is evaluated.

Others are just GHC not knowing it won't crash, and we can use
Data.List.NonEmpty to tell it.
2021-10-31 11:41:53 +00:00
Tomas Janousek
12d1b31d6c ci: Test against GHC 9.2 2021-10-31 11:04:27 +00:00
Tomas Janousek
b92bd28d97 ci: Update haskell-ci 2021-10-31 10:52:58 +00:00
Tomáš Janoušek
e1daf46c75
Merge pull request #344 from slotThe/dont-print-getWindowAttributes
X.Operations: Silently catch in setWindowBorderWithFallback
2021-10-29 12:24:30 +01:00
slotThe
a8e1249ba7 stack: Bump default resolver to 18.14
No impact on CI, just makes it easier for contributors to use the latest
8.10 GHC.

Related: xmonad-contrib@f5f6ef41cb6cce3ba14957c31640f10b5751c90c
2021-10-29 11:00:04 +02:00
slotThe
e3824687c7 X.Operations: Silently catch in setWindowBorderWithFallback
While we catch the exception that `getWindowAttributes` can throw in
`setWindowBorderWithFallback`, we immediately turn around and print the
error to stderr.  Since this exception is raised every time a window is
closed[1] , it clutters stderr and may even confuse users as to why
xmonad is throwing these exceptions.

[1]: Depending on how the window is closed, we either have no way of
running `windows` on our own (say, the window is closed by a keybinding
of the program itself), or the focus change (and thus the call to
`windows`) runs before we can handle the DestroyWindowEvent.
2021-10-29 09:43:13 +02:00
Tomas Janousek
c979ee67c0 MAINTAINERS: Update release procedure (dev version bump, …) 2021-10-28 18:06:13 +01:00
Tomas Janousek
6c92dd22ad Bump version to 0.17.0.9 and prepare CHANGES.md sections
We need to bump the version early to avoid overwriting
https://xmonad.github.io/xmonad-docs/xmonad-0.17.0/
2021-10-28 18:05:15 +01:00
slotThe
66ac855959 TUTORIAL.md: Fix link for Libera webchat
The kiwiirc webchat was superseded by one hosted directly by the Libera
project.
2021-10-27 19:22:30 +02:00
Tomas Janousek
7fab71f5f0 xmonad.cabal: Specify default-language
Required for cabal-version >= 1.10
2021-10-27 17:55:00 +01:00
Tomas Janousek
055dce10af Bump cabal-version in xmonad.cabal
Hackage won't accept the release otherwise.
2021-10-27 17:48:44 +01:00
github-actions
292f19eab8 man: Update 2021-10-27 15:57:55 +00:00
Tomas Janousek
a204c9ed04 Bump version number (0.17.0), update date in changelog/manpage 2021-10-27 16:57:14 +01:00
Yecine Megdiche
78f1a8e716 CONTRIBUTING: Drop xmonad-testing
xmonad-testing isn't really being used, so the wording needs to be
changed in CONTRIBUTING.md and in the PR template. The important thing:
we want an example for new modules/functionality, and appropriate tests.

Related: https://github.com/xmonad/xmonad/issues/341
2021-10-27 16:50:10 +01:00
slotThe
72794d92b1 TUTORIAL.md: Rename versions 0.17 -> 0.17.0 2021-10-27 12:03:14 +02:00
slotThe
546d0b5ddb TUTORIAL.md: Remove note about 0.17.0 not being released
:)
2021-10-27 12:01:06 +02:00
slotThe
a03b6e86de CONTRIBUTING.md: Refer to pedantic
Instead of manually compiling with `-Wall -Werror` and the like, we have
a `pedantic` flag in xmonad's cabal file with which to run the CI.
Since contributors are very unlikely to not use either stack or cabal to
build xmonad, we should refer them to this flag instead of listing all
of the options they would need to compile xmonad with in order to check
their work.

Fixes: bc8f7ff133e6a5415fd831c3ab232199ab462800
2021-10-25 09:14:06 +02:00
Tomas Janousek
856c8b2c8d Merge branch 'packdeps' 2021-10-24 17:19:36 +01:00
Tomas Janousek
dbd441cc1b MAINTAINERS: Update release procedure 2021-10-24 17:08:10 +01:00
Tomas Janousek
2e89e5ed23 Bump lower bound for base
We only test with GHC 8.4+ so it's unlikely this builds with older base
(Semigroup stuff …).
2021-10-24 17:08:10 +01:00
Tomas Janousek
0ebedbb533 ci: Check package bounds using packdeps once a week
This was a part of the release procedure but we should do it proactively
instead.

Related: https://github.com/xmonad/xmonad/issues/264
2021-10-24 17:08:10 +01:00
Tomas Janousek
c2a1a3c0a6 ci: Add Stackage LTS 18 to Stack test matrix 2021-10-24 17:08:10 +01:00
Tomas Janousek
7d10e470d7 ci: Avoid caching GHC
We install GHC using apt, so stack shouldn't install it, but should it
ever end up installing it anyway (version mismatch, version unavailable
in hvr/ghc ppa, …), we don't want it wasting valuable cache space.
2021-10-24 17:08:10 +01:00
slotThe
6608f0012b CONTRIBUTING.md: Mention IRC/matrix before mailing list
Nowadays, the IRC and (since it is linked to it) matrix channels are
much faster ways to get into contact with us than the (very low traffic)
mailing list.  CONTRIBUTING should reflect that, since especially new
contributors might not know where to go to get a feeling for the people
working on the project—or worse, think we only communicate via pull
requests and issues!
2021-10-24 17:43:45 +02:00
slotThe
bc8f7ff133 Move STYLE to CONTRIBUTING.md
Style guidelines should be where most people will see them.  Since we
already ask people to read CONTIRBUTING.md when they submit a pull
request, putting them in there seems like the best place.

We can also drop the curious "or freer" clause from the licensing point,
much like xmonad-contrib@f39218ddb5ffeddce90f620910d5ef2c14f2b43d
already did.
2021-10-24 17:43:45 +02:00
slotThe
7845145706 Delete CONFIG
CONFIG has been completely replaced by TUTORIAL.md and it might be quite
confusing for new users if we keep two tutorials around.
2021-10-24 17:38:13 +02:00
slotThe
79afdfbbb9 CHANGES.md: Sectionise 0.17.0 changes
Create three sections (enhancements, bug fixes, breaking changes) in
order to organise the changes for the v0.17.0 release.

As discussed in [1], the breaking changes really aren't breaking changes
to normal users.  The only exception could be the GenerateManpage
change, but even that is only important for distro maintainers.  Hence,
move all of these to the very back, such that we can mention exciting
features like the stack integration at the top instead.

Related: https://github.com/xmonad/xmonad/pull/340

[1]: https://github.com/xmonad/xmonad/pull/340#discussion_r734956547
2021-10-24 08:18:42 +02:00
Tomáš Janoušek
8774081c15
Merge pull request #340 from liskin/readme
README: Long overdue update
2021-10-23 16:06:42 +01:00
Tomas Janousek
60f36e78ba CHANGES: Prepare version number and approx. date for release 2021-10-23 16:06:06 +01:00
Tomas Janousek
b198b80559 README: Long overdue update
* add logo and badges to make it prettier
* revamp installation sections
* update xmonad-contrib reference and move upwards
* drop other useful programs, this is in download.html
* add new Contributing section

Fixes: https://github.com/xmonad/xmonad/issues/199
2021-10-23 00:17:30 +01:00
Tomas Janousek
6bbd8b869e Update .mailmap with even more info from xmonad-contrib
The lesson here is that stuff like this should not be done manually.
For future reference, here's the machinery I ended up using:

    https://gist.github.com/7b78eba396024d4f56fa217867e2a3a8
2021-10-22 23:05:48 +01:00
Tomas Janousek
97aeb8577c LICENSE: Fix wording to make it detectable by GitHub 2021-10-22 22:55:47 +01:00
Tomas Janousek
0be6d2bec5 Update .mailmap with additional info from xmonad-contrib's
+ some Googling.

If the archaeologists ever come, we're ready for them. :-)
2021-10-21 15:33:12 +01:00
Tomas Janousek
b1fef9b18c Add .mailmap to clean git shortlog 2021-10-21 11:39:46 +01:00
slotThe
b5b95e27ce
Merge pull request #337 from slotThe/lazy-lifted-boolean-ops
Make `(<&&>)` and `(<||>)` lazy in their second argument
2021-10-17 10:14:02 +02:00
slotThe
4e30ef13a7 Update CHANGES.md 2021-10-17 10:13:00 +02:00
slotThe
d92125485a X.ManageHook: Make (<&&>) and (<||>) lazy in their second argument
While an implementation of `liftM2 (&&)` may seem like a straightforward
lift of `(&&)` into a monadic setting, it actually expands to

    (<&&>) :: Monad m => m Bool -> m Bool -> m Bool
    mb <&&> mb' = do
      a <- mb
      b <- mb'
      return (a && b)

which runs both monadic effects first and then applies `(&&)`.

This is fixed by introducing a monadic version of `if-then-else` (which
is also exported due to its usefulness) that checks the second result
only if this is explicitly necessary.
2021-10-16 16:33:04 +02:00
Tomas Janousek
33a86c0cdb X.Operations: Fix mouse in Tabbed decorations (revert broadcastMessage refactor)
Turns out there was another aspect of `broadcastMessage` behaviour that
I missed in my review of the refactor: X.L.Tabbed updates the windowset
during handleMessage (via `X.O.focus`) and expects that change to
persist (by returning `Nothing` and hoping no other layout or layout
modifier returns `Just`). That's quite a hack, but the LayoutClass
interface doesn't allow a cleaner way to do this (well, some extensible
state plus a custom event hook might work, but then the layout isn't
self-contained any more).

And since rereading workspace layouts during `modifyLayouts` would force
this back into O(n²), we might as well revert the whole refactor. :-/

Fixes: https://github.com/xmonad/xmonad/issues/329
2021-09-14 11:25:18 +01:00
Tomáš Janoušek
3bb653bf9c
Merge pull request #327 from ssbothwell/feature/withFocused-function
Adds withUnfocused function to XMonad.Operations
2021-09-14 11:09:42 +01:00
Tomas Janousek
ebce32d891 Minor cleanups of Solomon's PR 2021-09-14 11:08:48 +01:00
Solomon Bothwell
b3bd9c90d1 Adds withUnfocused function to XMonad.Operations 2021-09-13 23:00:37 -07:00
Tomáš Janoušek
5da25c5413
Merge pull request #291 from wygulmage/refactor_message_handling
added export list to Operations, refactored message handling.
2021-09-04 18:11:10 +01:00
Tomas Janousek
11d76e284c Adjust runOnWorkspaces processing order
We now use this in `broadcastMessage`, so to not change which workspaces
get the message first, we need to change the order here. This wouldn't
normally be safe to do either, but there are no other uses of
`runOnWorkspaces` neither here nor in xmonad-contrib, so it should
actually be fine.
2021-09-04 18:04:49 +01:00
Tomas Janousek
6d661203d3 Rename updateLayoutsBy to modifyLayouts
More consistent with our existing naming.
2021-09-04 18:01:36 +01:00
Tomas Janousek
30c2eeeeb3 Revert "changed order of broadcastMessage to match original."
We'll adjust runOnWorkspaces instead.

This reverts commit 5eff329fc607624f843f7b29fb5a4f2169e92cd0.
2021-09-04 17:54:17 +01:00
Tomas Janousek
d66e71d464 Revert "generalized signature of updateLayoutsBy"
This reverts commit eb48bb4aef638ba6958a4489a282c274e9779767.
2021-09-04 17:54:06 +01:00
Tomas Janousek
5c7e61def2 X.Operations: Small cleanup of module header 2021-09-04 17:52:01 +01:00
Keith
eb48bb4aef generalized signature of updateLayoutsBy 2021-09-04 17:52:01 +01:00
Keith
5eff329fc6 changed order of broadcastMessage to match original.
This uses two new functions (not exported):
`workspacesA` traverses the workspaces in a StackSet.
`runOnWorkspaces` runs `workspacesA` with the X state.
2021-09-04 17:52:01 +01:00
Keith
183e14725f changed broadcastMessage to be O(workspaces).
The current definition of broadcastMessage seems to be O(n^2) in the number of workspaces because it uses sendMessageWithNoRefresh and sendMessageWithNoRefresh uses updateLayout and updateLayout uses runOnWorkspaces.

This changes broadCastMessage and sendMessageWithNoRefresh to each use a single
call to runOnWorkspaces.
2021-09-04 17:52:01 +01:00
Keith
0ab42d4228 added export list to Operations.
This includes Haddock sections that will make the documentation render differently.
2021-09-04 17:52:01 +01:00
Keith
52a5e7ca8c updated documentation of Operations.
Added missing documentation for type alias `D`.

Moved misplaced documentation.

Edited to a consistent style that will play well with Haddock.
2021-09-04 17:46:05 +01:00
Tomas Janousek
f89df98f40 Drop unused import System.Environment (setEnv)
Fixes: 30719202b9da ("Fix xmessage in non-UTF-8 locales")
2021-08-30 18:04:23 +01:00
Tomas Janousek
30719202b9 Fix xmessage in non-UTF-8 locales
`executeFile` encodes the arguments with the current locale's encoding,
and GHC as invoked during recompilation quite likely also outputs any
errors in the locale encoding, which we then read using `readFile` again
decoding in the locale encoding, so it really makes no sense to force a
specific encoding here. What was I thinking? :-)

Related: https://github.com/xmonad/xmonad/issues/322#issuecomment-900503386
Fixes: https://github.com/xmonad/xmonad/issues/324
Fixes: aa35ea185683 ("Make xmessage handle UTF-8 and export it")
2021-08-30 17:45:47 +01:00
Tomáš Janoušek
aa18707c3e
Merge pull request #323 from MuhammedZakir/master
Add `--stack-yaml` flag to `stack build --silent`
2021-08-17 19:09:57 +01:00
MuhammedZakir
b77ba03ed9 Add --stack-yaml flag to stack build --silent
Fixes: https://github.com/xmonad/xmonad/issues/322
2021-08-17 23:02:45 +05:30
Tomáš Janoušek
be1d2269ce
Merge pull request #318 from liskin/stack-recompile
Recompilation overhaul: stack.yaml detection, deprecation warnings
2021-08-17 10:55:38 +01:00
Tomas Janousek
7bdc7ab9dc Print the recompilation command into the error file
When `stack build --silent` fails, the output is not helpful at all:

    Errors detected while compiling xmonad config: /home/slot/.config/xmonad/xmonad.hs
    ExitFailure 1

    Please check the file for errors.

And even in other circumstances it's helpful to see the command that was
executed, as it makes it easy for the user to diagnose what's wrong.
2021-08-17 10:46:07 +01:00
Tomas Janousek
ae97c1f107 CHANGES: Mention recompilation improvements 2021-08-17 10:46:07 +01:00
Tomas Janousek
782ac25b8e INSTALL: Update after stack.yaml autodetection
Related: https://github.com/xmonad/xmonad/issues/310
2021-08-17 10:46:07 +01:00
Tomas Janousek
8aa0d4a3e0 Detect deprecation warnings during recompilation and warn the user
Deprecation warnings were suppressed during recompilation, which made it
difficult to improve things in the codebase and API as users did not
(know they) have a transition period to adapt their configuration.

See additional discussions about deprecations:

 - https://github.com/xmonad/xmonad-contrib/pull/404#issuecomment-731607447
 - https://github.com/xmonad/xmonad-contrib/pull/410#issuecomment-732841235

Fixes: https://github.com/xmonad/xmonad/issues/304
Related: https://github.com/xmonad/xmonad-contrib/pull/404
Related: https://github.com/xmonad/xmonad-contrib/pull/410
2021-08-17 10:46:07 +01:00
Tomas Janousek
1f8e5b43e1 Fix indent in getDirectories
Fixes: 90101613e76d ("Unclobber dirs/Dirs in import XMonad")
2021-08-17 10:46:07 +01:00
Tomas Janousek
9813e218b0 Move config binary and GHC intermediate outputs to cacheDir
That's where they belong. As XDG was more or less broken in previous
xmonad releases, we can assume few people use it so now's the best time
to move files around.

For users of `~/.xmonad`, this only causes intermediate outputs (.o,
.hi) to go elsewhere.

Fixes: https://github.com/xmonad/xmonad/issues/178
2021-08-17 10:46:07 +01:00
Tomas Janousek
403e4df624 Use "stack ghc" for recompilation when stack.yaml exists
This makes it unnecessary for users of Stack to use a custom build
script, making installation easier.

Inspired by a similar feature in dyre:
a04be85f60

Fixes: https://github.com/xmonad/xmonad/issues/310
2021-08-17 10:46:07 +01:00
Tomas Janousek
aa35ea1856 Make xmessage handle UTF-8 and export it
This unfortunately breaks xmonad-contrib as several modules define their
own `xmessage` function.

Related: https://github.com/xmonad/xmonad/pull/309
2021-08-17 10:46:07 +01:00
Tomas Janousek
3b6d00ba91 Refactor 'recompile' to be less of a spaghetti-code
This is a preparation for autodetecting stack.yaml and using stack for
recompilation.

Related: https://github.com/xmonad/xmonad/issues/310
2021-08-17 10:46:07 +01:00
Tomas Janousek
befc4bc8d8 github: Drop FUNDING.yml
Replaced with https://github.com/xmonad/.github/blob/main/FUNDING.yml,
which points to xmonad's funding platforms instead of mine.

Related: https://github.com/xmonad/xmonad/pull/295
Related: https://github.com/xmonad/xmonad-contrib/pull/544
2021-08-15 22:27:39 +01:00
Tomas Janousek
6c31aad683 github: Sync ISSUE_TEMPLATE with xmonad-contrib
Related: https://github.com/xmonad/xmonad-contrib/pull/533
2021-08-15 22:25:59 +01:00
Tomas Janousek
3e76270245 ci: Disable optimization in the haskell-ci workflow
Cuts a couple dozen seconds from the build. This was already disabled in
the Stack workflow and we just forgot to put it here as well.

Related: https://github.com/xmonad/xmonad-contrib/pull/580
2021-08-08 11:54:58 +01:00
Tomas Janousek
3a414660fc MAINTAINERS: Link to maintainers' GPG keys
I'm the only one with valid GPG key uploaded to GitHub, it seems. :-/

Fixes: https://github.com/xmonad/xmonad/issues/75
2021-08-08 00:53:36 +01:00
Tomas Janousek
453010bb6d Link to xmonad-docs instead of hackage (fixes some links)
Fixes broken links to X.U.Hacks and X.U.ClickableWorkspaces.
2021-08-07 15:14:12 +01:00
Tomas Janousek
2ac8f0ea27 INSTALL: Fixes to ease inclusion into xmonad-web
Jekyll doesn't do autolinks, so wrap the one bare link in angle
brackets.

Also, link to additional resources for configuring xinitrc/xsession.
2021-08-02 21:36:16 +01:00
Tomas Janousek
ad7288030f TUTORIAL: Fixes to ease inclusion into xmonad-web
Also makes it easier to copy & paste.
2021-08-02 15:09:43 +01:00
Tomas Janousek
206fc918bb ci: Verbose nix build 2021-08-01 22:21:43 +01:00
Tomas Janousek
f5a60f82ee Merge branch 'add-nix-flake' 2021-08-01 22:07:11 +01:00
Ivan Malison
a1ee3b4530 Add comment explaining that I am maintaining flake.nix 2021-08-01 22:06:50 +01:00
Ivan Malison
89218fc57d Add nix github workflow 2021-08-01 22:06:49 +01:00
Ivan Malison
71af4239bd Add a flake.nix file 2021-08-01 22:06:49 +01:00
Tomas Janousek
f1d6316526 Merge branch 'broadcast-destroy-window-events' 2021-07-31 15:25:08 +01:00
Yecine Megdiche
92d01e37a0 Broadcast DestroyWindowEvent to layouts
Some layout and layout modifiers that keep track of some window
properties don't do garbage collection and update their state when
windows are destroyed. By broadcasting this event, it should be easier
for layouts to clean up

Related: https://github.com/xmonad/xmonad-contrib/pull/474
2021-07-31 15:24:31 +01:00
Tomas Janousek
101c7052f4 Merge branch 'install-instructions' 2021-07-29 11:33:19 +01:00
Tomas Janousek
7b7feeca42 INSTALL: Use "console" syntax highlighting for console listings 2021-07-29 11:32:20 +01:00
Tomas Janousek
cbe7ee7c03 INSTALL: Add instructions for cabal-install
Related: https://github.com/xmonad/xmonad/issues/199
Related: https://github.com/xmonad/xmonad/issues/310
2021-07-29 11:32:20 +01:00
Tomas Janousek
8adb8463ab INSTALL: Generalize the instructions a bit
Mention installation from distro; factor preparation/download out of
the Stack section (prep for inclusion of cabal-install section).
2021-07-29 11:32:20 +01:00
Tomas Janousek
256eb29ef1 INSTALL: Add section about launching XMonad as default WM 2021-07-25 10:44:41 +01:00
Tomas Janousek
4ba9c8b8c1 INSTALL: Mention dependencies for a couple common distros 2021-07-25 10:44:41 +01:00
Tomas Janousek
98173777fe INSTALL: Drop indent from code blocks
Makes it easier to copy&paste.
2021-07-25 01:17:40 +01:00
Tomáš Janoušek
05aeef0dc2
Merge pull request #308 from liskin/release-infra
Automate and document releasing to Hackage + couple cleanups
2021-07-25 02:17:21 +02:00
Tomas Janousek
85787ce059 Automate and document releasing to Hackage
Pioneered in https://github.com/xmonad/X11, this adds automation for
Hackage releases and updates MAINTAINERS.md with simplified instruction
for the release procedure.

Related: https://github.com/xmonad/xmonad/issues/75
Related: https://github.com/xmonad/xmonad/issues/264
Related: https://github.com/xmonad/xmonad-contrib/issues/393
2021-07-24 18:13:11 +01:00
Tomas Janousek
d64aeba80f Revise extra-source-files in xmonad.cabal
Ship the new docs, drop tests as these get picked up automatically.
2021-07-24 18:13:11 +01:00
Tomas Janousek
72cbe0667d Revise dependencies a bit
utf8-string isn't needed since d9e3ebf53194d1cf02bae28f0c885b5c75610cfa
(late 2014).

Most of the executable xmonad deps are unnecessary since
307b82a53d519f5c86c009eb1a54044a616e4a5c (early 2015).

Switch from data-default to data-default-class to avoid bringing in deps
and instances we don't need.
2021-07-24 18:13:11 +01:00
slotThe
af354f7528
Merge pull request #312 from mzrinsky/update-cheatsheet
Add help command to help message
2021-07-03 09:10:02 +02:00
Matt Zrinsky
1a4c95fac8 Add help command to help message.
Attempt to contribute to xmonad,
and add a simple line to the help message,
containing the help command itself.

Fixes xmonad/xmonad#287
2021-07-02 13:58:00 -05:00
slotThe
42d319545b
Merge pull request #309 from MuhammedZakir/xmessage-fix
Use printf instead of echo for xmessage help
2021-06-27 08:27:00 +02:00
MuhammedZakir
2e6eb9068d Use printf instead of echo for xmessage help
In some shells—like bash—the entire help message is shown in a single
line because a newline is printed as a literal "\n" character when using
echo.  Some distributions[1] have /bin/sh linked to bash, and so new
users are likely to run into this at some point.

We could fix this by either removing show and explicitly adding an
escaped quotation symbol before and after the string, or by using printf
instead of echo.  The printf solution seems more portable[2] and so I
propose we go with that one.

[1]: f5b9a25cdd/nixos/modules/config/shells-environment.nix (L129-L143)
[2]: https://unix.stackexchange.com/questions/65803/why-is-printf-better-than-echo/#65819
2021-06-27 08:09:33 +02:00
slotThe
13849c6230 INSTALL.md: Mention stack upgrade
Users who are installing stack on systems like Debian stable or Ubuntu
may get really old version of stack—much older than we currently
support.  Thankfully, stack can upgrade itself rather easily with one
single command, so mention that.

Fixes: https://github.com/xmonad/xmonad/issues/303
2021-06-15 10:10:17 +02:00
Tomas Janousek
6a7eb85e84 MAINTAINERS.md: Update xmonad core team, add hall of fame
More or less synced with https://xmonad.org/community.html

Fixes: https://github.com/xmonad/xmonad/issues/248
2021-06-07 10:35:48 +01:00
slotThe
2a3c358533 MAINTAINERS.md: Add slotThe
Related:
  - https://github.com/xmonad/xmonad/issues/75
  - https://github.com/xmonad/xmonad/issues/248
2021-06-07 09:44:29 +02:00
slotThe
28637d0db7 Tutorial: Remove ewmhFullscreen for versions < 0.17
Not released as of xmonad-contrib 0.16.

Related: https://github.com/xmonad/xmonad/issues/307
2021-06-07 08:44:50 +02:00
Tomas Janousek
b14b3ffcec Bump version number (pre-release 0.16.9999)
Merging NewSelect into Choose is a breaking change, bump the version to
let xmonad-contrib depend on it.
2021-06-04 19:03:11 +01:00
Tomáš Janoušek
bbb4a0ef25
Merge pull request #281 from slotThe/NewSelect
Merge X.L.LayoutCombinators.(|||) into X.L.(|||)
2021-06-04 18:22:40 +01:00
slotThe
9db74715f2 X.Layout: Simplify JumpToLayout implementation
The `choose` combinator is very general; much more so than the
combination of `switch`, `swap`, and `passOnM`.

We can thus replace most of the implementation with calls to `choose`
and properly put everything related to `JumpToLayout` under one guard.
Plus, we don't need to define any extra functions that would have to be
tested in some way.

Co-authored-by: Tomas Janousek <tomi@nomi.cz>
2021-06-04 18:17:13 +01:00
slotThe
5b064f474d Update CHANGES.md 2021-06-04 18:17:11 +01:00
slotThe
bffa6dc2ce Merge X.L.LayoutCombinators.(|||) into X.L.(|||)
The functionality of the former are quite handy to have in core and we
can do so with minimal code changes.

The drawbacks of this approach are

  1. We can't merge JumpToLayout into ChangeLayout because people may
     have imported JumpToLayout(..), which we can't simulate with type
     aliases, patterns, and the like.

  2. Because the internal structure of X.L.LayoutCombintors.(|||) is a
     bit different, this creates a regression for people who used
     NextLayoutNoWrap or Wrap in their configs.  We could work around
     this by creating fake instances of these fields in the new
     JumpToLayout constructor and simply not doing anything with them,
     but since this seems like quite an advanced and specific use-case,
     failing fast and hard (as opposed to adding deprecation messages
     and then "silently" not handling these messages) seems preferrable
     here.

Related: https://github.com/xmonad/xmonad-contrib/pull/493
Related: https://github.com/xmonad/xmonad-contrib/issues/116
2021-06-04 18:17:04 +01:00
Tomas Janousek
341dea5907 Call xrrUpdateConfiguration to sync Xlib's view of screen config
Xrandrint.h says:

    /*
     * if a configure notify on the root is recieved, or
     * an XRRScreenChangeNotify is recieved,
     * XRRUpdateConfiguration should be called to update the X library's
     * view of the screen configuration; it will also invalidate the cache
     * provided by XRRScreenConfig and XRRConfig, and force a round trip
     * when next used.  Returns invalid status if not an event type
     * the library routine understand.
     */

If any user code needs that info/cache to be correct, we need to call
this.
2021-06-01 18:45:36 +01:00
Tomas Janousek
676530307b Clean up uses of setClientMessageEvent
In sendRestart, switch to the new setClientMessageEvent' and pass no
data, as no data are expected. Passing currentTime was confusing, as
it's only interpreted as time in some ClientMessage types.

In killWindow, it's the other way around.
2021-06-01 18:41:21 +01:00
Tomas Janousek
09425bbe43 Bump version number (pre-release 0.16.999) 2021-06-01 18:37:19 +01:00
Tomas Janousek
1805666e9d Bump X11 dependency
We have a bunch of open PRs that need features added in X11-1.10.

Related: https://github.com/xmonad/xmonad/pull/274
Related: https://github.com/xmonad/xmonad/pull/273
Related: https://github.com/xmonad/xmonad-contrib/pull/545
Related: https://github.com/xmonad/xmonad-contrib/pull/546
Related: https://github.com/xmonad/xmonad-contrib/pull/399
2021-06-01 18:37:19 +01:00
slotThe
40cd2081da Upcase tutorial file, mention it in README
Related: https://github.com/xmonad/xmonad/pull/278#issuecomment-850717606
2021-05-29 07:41:18 +02:00
slotThe
66514127f3
Merge pull request #278 from slotThe/new-tutorial
Add New Tutorial
2021-05-28 17:43:03 +02:00
slotThe
fdc3bf0484 tutorial.md: Point IRC channel to libera.chat
The reference to the freenode matrix channel is deleted for now; though
it may be added back in later-on, as the matrix team is working towards
bridging Libera.  We may also link the other matrix channel at some
point.

Related: https://github.com/xmonad/xmonad-web/pull/21
2021-05-28 16:52:09 +02:00
slotThe
f97d2527ff tutorial.md: Use logTitles
Ever since 322e06eed9c4b23a465d2857df462b8a2d716246 `ppTitleUnfocused`
does not exist anymore, as it was moved to `X.U.Loggers.logTitles`.
This makes the tutorial aware of that.
2021-05-28 16:52:09 +02:00
slotThe
7199d953a7 Add tutorial.md 2021-05-28 16:52:09 +02:00
slotThe
15653d4669 Add INSTALL.md 2021-05-28 16:50:06 +02:00
Tomas Janousek
d64a22d8db Switch IRC channel to irc.libera.chat
Since freenode has decided to kick us off because we said that we're
moving to Libera:

    Topic for #xmonad is "This channel has moved to ##xmonad. The topic is in violation of freenode policy: https://freenode.net/policies"
    Topic set by freenodecom (~com@freenode/staff) on Wed, 26 May 2021 04:59:51

it is high time we change the official channel on the website—even
though we don't even have OP on Libera yet.

Related: https://github.com/xmonad/xmonad-web/pull/26/
Co-authored-by: slotThe <soliditsallgood@mailbox.org>
2021-05-26 10:55:52 +01:00
Tomas Janousek
2e9f8dc831 ci: Refresh caches once a month
GitHub Actions writes caches on the first miss and then never updates
them again. If the CI is used frequently, the caches never expire and
as they get old, become less useful.

To avoid this, force refreshing the caches once a month.

Related: 52751f47d0
2021-05-24 23:19:30 +01:00
Tomas Janousek
e8bfc5bb69 ci: Prevent ~/.stack/pantry cache from being empty
When building with an LTS version that has exactly the dependencies we
need (X11-1.9.2), stack doesn't need to download the Hackage index. If
GitHub Actions cache locking chooses this job as the one that writes the
cache, then the "stack-pantry-Linux" cache entry stays empty, possibly
forever.

Force Hackage index update to prevent this from happening.

Related: d1a4820b55
2021-05-24 23:13:45 +01:00
Joan Milev
9e5b16ed8a Remove all instances of deriving Typeable
The derivation of Typeable has been automatic for quite a while now.

Related: https://github.com/xmonad/xmonad-contrib/issues/548
2021-05-24 22:56:36 +01:00
Tomas Janousek
d72da951c9 Use -Wno-* instead of the obsolete -fno-warn-* 2021-05-24 11:19:53 +01:00
Tomas Janousek
90101613e7 Unclobber dirs/Dirs in import XMonad
"dirs" is used several times in xmonad-contrib as a short for
"directions" and when I tried renaming those uses, I had a really hard
time coming up with something nice/meaningful. Therefore I think it's
best if we rename this instead, "dirs" is a valuable part of the
namespace. :-)

Fixes: 735fb58f6cc2 ("Revise XDG handling")
2021-05-24 11:15:00 +01:00
Tomas Janousek
6caac22df1 ci: git-friendly apt deps in cabal.haskell-ci 2021-05-23 18:33:00 +01:00
Tomas Janousek
e9987b1adf Merge branches 'pr/grabkeys-nosymbol', 'pr/extensible-config' and 'pr/funding' 2021-05-21 11:49:52 +01:00
Tomas Janousek
383ffb772e Prevent grabKey from accidentally grabbing all unbound keys
grabKeys doesn't check that a KeySym is valid before looking up the
KeyCode(s) it's bound to. In particular, KeySym 0 (NoSymbol) gets mapped to every
unbound KeyCode, since that's what XKeycodeToKeysym returns for those.

This can most easily be reproduced using `statusBar` in xmonad-contrib,
with def as the key-mapping function; this unexpectedly invokes the
following instances:

    instance Default b => a -> b where def = const def
    instance (Default a, Default b) => (a, b) where def = (def, def)
    instance Default CInt where def = 0

thus producing a function which binds `toggleStruts` to the (KeyMask,
KeySym) pair (0, 0) (and demonstrating why Default is a dangerous
abstraction). The person who reported this used xmodmap to clear KeySyms
from their numpad keys, and then xmonad would bind strut toggling to the
entire numpad.

Note that it is not reliably possible to override `def` in this
situation (without introducing a new type); the only thing we can do is
try to avoid the aftermath, and I would expect that an inadvertent 0
KeySym is the most common error here anyway.

Fixes: https://github.com/xmonad/xmonad/issues/293
Fixes: 40cb12ce174a ("Grab all keycodes linked to each keysym, not just one")
Co-authored-by: Brandon S Allbery KF8NH <allbery.b@gmail.com>
2021-05-21 11:41:52 +01:00
Tomas Janousek
6379307baa Add Sponsor button to GitHub
These past months I've spent a lot of time working on xmonad¹ and I feel
like I've done a lot. This is, however, not sustainable long term. :-(

¹) primarily xmonad-contrib and the community in general

I'd like to try making my GitHub Sponsors profile a bit more visible,
hoping that would allow me to continue dedicating time to xmonad.

I know that the correct approach probably is for the xmonad project to
find a fiscal sponsor like the Software Freedom Conservancy or Open
Collective or something and accept donations as a project, and then
redistribute that to people, but I don't think the project has enough
momentum to do something as complicated as that. :-/

Related: https://github.com/xmonad/xmonad-contrib/pull/544
2021-05-18 16:53:07 +01:00
Tomas Janousek
d620639f7d Add support for extensible config in contrib modules
It's often difficult to make contrib modules work together. When one
depends on a functionality of another, it is often necessary to expose
lots of low-level functions and hooks and have the user combine these
into a complex configuration that works. This is error-prone, and
arguably a bad UX in general.

This commit presents a simple solution to that problem inspired by
"extensible state": extensible config. It allows contrib modules to
store custom configuration values inside XConfig. This lets them create
custom hooks, ensure they hook into xmonad core only once, and possibly
other use cases I haven't thought of yet.

For more, see the related pull request to xmonad-contrib.

Related: https://github.com/xmonad/xmonad-contrib/pull/547
2021-05-17 17:46:48 +01:00
Tomas Janousek
a5cee9bac2 ci: Fix failing installation of GHC
Since actions/virtual-environments#3268, the GHC PPA is no longer
enabled by default. :-(

(It would be better to use the haskell/actions/setup action, but it
insists on doing `cabal update` even if all we need is to install GHC
and Stack, which adds noticeable delay:
https://github.com/haskell/actions/issues/29)
2021-05-14 19:20:16 +01:00
github-actions
131fd3669f man: Update 2021-04-27 11:05:32 +01:00
Tomas Janousek
56f810d182 GenerateManpage: Drop all dependencies except base and invoke in CI
pandoc's API changes often enough that distros like Debian were patching
our GenerateManpage.hs to work with their version of pandoc, and it
doesn't build against any Stackage LTS except the recently released
LTS-17. Also, building pandoc from source takes quite some time and
resources.

But for what benefit? We're not using any special pandoc functionality
whatsoever. It's just that it was all in Haskell and the entire build
was orchestrated by cabal, but is all that complexity and resource
consumption worth it? I think not.

(Frankly, this whole thing was just a massive waste of time as the help
text in Config.hs isn't generated at all, so we still need to do this
manually. And then, the default key-bindings in core are unlikely to
change ever again.)

Let's simplify this:

* drop all dependencies except base and just run it through runhaskell

* add a Makefile and GH Actions workflow that invokes this after push

* only ship the results in release tarball, not the scripts which are
  considered our dev infrastructure

Closes: https://github.com/xmonad/xmonad/issues/283
Related: https://github.com/xmonad/xmonad/pull/260
Related: https://github.com/xmonad/xmonad/pull/261
Related: https://github.com/xmonad/xmonad/pull/265
Related: https://github.com/xmonad/xmonad/pull/266
Related: https://github.com/xmonad/xmonad/pull/267
Related: https://github.com/xmonad/xmonad/pull/268
2021-04-27 11:05:32 +01:00
Tomáš Janoušek
46f637e0be
Merge pull request #289 from slotThe/maintainers
Update MAINTAINERS.md: add twitter, website references
2021-04-08 21:14:57 +01:00
slotThe
095d0e37d6 Update MAINTAINERS.md: add twitter, website references
Relevant mailing list discussion for the website part is available at
[1].

[1]: https://mail.haskell.org/pipermail/xmonad/2020-February/015358.html
2021-04-08 19:29:38 +02:00
Tomáš Janoušek
7e798afd11
Merge pull request #288 from slotThe/minimal-pragma
Add `MINIMAL` for `ExtensionClass` and `LayoutClass`
2021-04-07 18:33:07 +01:00
slotThe
669a9aed9e LayoutClass: update documentation
Make it clearer that we in fact do not require implementations for a
minimal complete definition, but that the default implementations have a
certain kind of dependency structure.
2021-04-07 10:12:15 +02:00
slotThe
c869129c71 ExtensionClass: Use MINIMAL pragma 2021-04-07 10:12:14 +02:00
Tomáš Janoušek
b8523a3c9b
Merge pull request #202 from wygulmage/stack_instances
Add Functor, Foldable, and Traversable instances for StackSet.Stack
2021-04-04 09:56:45 +01:00
Tomas Janousek
400730fe3b Disable quickcheck-classes when building with stack
Stack doesn't support automatic flags: it doesn't backtrack when
dependency resolution fails using the default value of an automatic
flag, it just fails the build plan construction. We can't use automatic
flags to check if quickcheck-classes is available, and since the code is
tested by the haskell-ci.yml cabal workflow anyway, let's just disable
it here. It's not worth the hassle trying to enable it for select LTS
versions only. It's too much noise already, actually. :-(

Further reading:
https://cabal.readthedocs.io/en/latest/cabal-package.html#resolution-of-conditions-and-flags
https://github.com/commercialhaskell/stack/issues/1313#issuecomment-157259270
2021-04-03 17:13:25 +01:00
Tomas Janousek
6c5204b91c Simplify quickcheck-classes tests for Stack
We don't need the compat hacks for GHC 8.4.
2021-04-03 17:13:25 +01:00
Tomas Janousek
910d99cb74 Update CHANGES 2021-04-03 17:13:25 +01:00
Tomas Janousek
031bbd6230 Make quickcheck-classes dependency optional 2021-04-03 17:13:25 +01:00
Keith
05e8c204e9 Add quickcheck-classes tests for Stack
The tests are implemented by using a newtype wrapper `TestStack`. This is to
avoid creating `Eq1` and `Show1` instances for `Stack` itself, which are needed
by quickcheck-classes to run with GHC less than 8.5. Tests are automatically
generated by `traversalLaws` and `foldableLaws` using the `Arbitrary` instance
for `TestStack`.
2021-04-03 17:13:25 +01:00
Keith
2c91ea1621 Add Foldable, Functor, and Traversable instances for Stack
`Functor` is provided by DeriveFunctor.
`Foldable` uses `integrate` (`Stack`'s `toList`).
`Traversable` uses the `Reverse` Applicative to traverse the `up` list in
reverse order.
2021-04-03 17:13:25 +01:00
Tomas Janousek
5cdf428f55 ci: Enable -Werror
We don't want to ignore warnings do we?
2021-03-31 12:00:30 +01:00
Tomas Janousek
22b579bd14 Drop deprecated migrateState
migrateState is only necessary when _live_ upgrading from xmonad 0.12,
so I believe we can drop it now.

This fixes a compilation warning that we'd otherwise have to suppress.
2021-03-31 12:00:30 +01:00
Tomas Janousek
14d9fa247a Drop "testing" cabal flag
Since 8863761d660a70984595d9162319801e648b69ec (early 2014), the test
suite is a proper cabal test-suite and needs the "xmonad" library to be
built, and thus the flag serve no purpose.

Related: https://github.com/xmonad/xmonad/issues/283
2021-03-31 12:00:30 +01:00
Tomas Janousek
cfe99998fc ci: Cache pantry (hackage metadata) separately
This further reduces our usage of cache storage by caching the metadata
only once per repo. Now the metadata cache is ~250MB and the individual
caches with built dependencies are ~5M each.

Related: https://github.com/xmonad/X11/pull/75
Related: https://github.com/xmonad/xmonad/issues/283
2021-03-31 12:00:30 +01:00
Tomas Janousek
9fce3805fc ci: Use system GHC in Stack to not waste GH Actions cache space
Stack installation of GHC takes more than a gigabyte, so caching it
wastes space (GitHub docs say it will be aggressively evicted after
reaching the 5G limit) and also time (compression, decompression).

Related: https://github.com/xmonad/X11/pull/75
Related: https://github.com/xmonad/xmonad/issues/283
2021-03-31 12:00:30 +01:00
Tomas Janousek
fd243ca1c1 ci: Refresh tested-with
Related: https://github.com/xmonad/X11/pull/75
Related: https://github.com/xmonad/xmonad/issues/283
2021-03-31 12:00:30 +01:00
Tomas Janousek
c90df53081 tests: Fix build with GHC 9
Related: https://github.com/xmonad/xmonad/issues/283
2021-03-31 12:00:30 +01:00
Tomas Janousek
e4659c2475 ci: Move apt deps to cabal.haskell-ci and regenerate haskell-ci
Related: https://github.com/xmonad/X11/pull/75
Related: https://github.com/xmonad/xmonad/issues/283
2021-03-31 11:59:13 +01:00
Tomas Janousek
caae51c399 ci: Minor cleanup
* rename workflow to Stack

* test all branches (provides feedback before opening a PR)

* split into buildenv deps and stack build

* make the deps list more git-friendly; tweak the deps

* use stack from github environment (I've seen the curl fail intermittently)

* use `*.cabal` to minimize diff between our repos

Related: https://github.com/xmonad/X11/pull/75
Related: https://github.com/xmonad/xmonad/issues/283
2021-03-31 11:58:07 +01:00
Tomas Janousek
fb390fa9cc Revert "Revert "Re-enable lts based testing""
This reverts commit 8a8d5f71b16a929222579b3d3509ed31ae9e124d.

There will be a separate GH Actions workflow for rebuilding the manpage,
and generatemanpage will be dropped from xmonad.cabal (see
https://github.com/xmonad/xmonad/issues/283) therefore the revert no
longer makes sense and the stack workflow can indeed be reverted back to
a working state so we can continue from there.

For more information, see the following revenge revert storm:

Related: https://github.com/xmonad/xmonad/issues/283
Related: https://github.com/xmonad/xmonad/pull/260
Related: https://github.com/xmonad/xmonad/pull/261
Related: https://github.com/xmonad/xmonad/pull/265
Related: https://github.com/xmonad/xmonad/pull/266
Related: https://github.com/xmonad/xmonad/pull/267
Related: https://github.com/xmonad/xmonad/pull/268
2021-03-31 11:52:57 +01:00
Tomáš Janoušek
4a0b166998
Merge pull request #275 from liskin/pr/notifications-obscured-by-floats
Fix obscuring notifications when moving floats
2021-03-21 21:30:36 +00:00
Tomas Janousek
b9ce5b034b Fix obscuring notifications when moving floats
Since 4565e2c90ef5, not only do we raise the floating window to top when
starting dragging, we also restack all other managed windows directly
below it (mouse{Move,Resize}Window now call `float` while dragging,
which invoke `windows` and that restacks all windows). This means that
as soon as we start dragging, all xmonad-managed windows are raised to
the top, obscuring any unmanaged (override-redirect) windows that were
at the top before.

The good thing about 4565e2c90ef5 is that since we refloat and refresh
on every mouse move while dragging, we no longer need the `raiseWindow`.
It was probably only there so that it stays visible when dragging
between Xinerama screens (3cb64d74617), and that's taken care of by
refloating the window on every move. As the refresh restacks everything
anyway, the only function of the `raiseWindow` is to stack windows above
unmanaged ones, which is likely undesirable.

There is still one known issue related to obscuring notifications:
https://github.com/xmonad/xmonad/issues/89
That one is caused by X opening new windows at the top of stacking order
and xmonad then restacking all other windows directly beneath them if
the new window is in the master position of the stack. Some notification
daemons like dunst work around this by raising themselves whenever a new
window is opened
(77bfbc4f7f/src/x11/x.c (L348)).
Fixing this one is considerably more complicated as we'd need to keep
track of (unmanaged) windows that wish to be stacked above new windows,
therefore this won't be addressed here, and probably won't be addressed
in xmonad core ever.

Fixes: https://github.com/xmonad/xmonad/issues/208
Fixes: 4565e2c90ef5 ("fix #63: window jumping to origin position when dragging")
2021-02-16 12:00:28 +00:00
Tomáš Janoušek
a90558c07e
Merge pull request #223 from wygulmage/cleanup-tests
deleted unused 'mul' definition in 'prop_aspect_fits'.
2021-01-26 01:15:01 +01:00
Sibi Prabakaran
56b0f850bc
Merge pull request #200 from wygulmage/strict-rectangle
Make ScreenDetail a newtype and RationalRect strict in its contents
2021-01-23 19:46:15 +05:30
Peter Simons
51a179dc68
Merge pull request #267 from xmonad/revert-266-reenable-lts
Revert "Re-enable lts based testing"
2021-01-20 12:48:44 +01:00
Peter Simons
8a8d5f71b1
Revert "Re-enable lts based testing" 2021-01-20 12:48:13 +01:00
Tomáš Janoušek
4b69a456cc
Merge pull request #266 from xmonad/reenable-lts
Re-enable lts based testing
2021-01-20 12:27:53 +01:00
Sibi Prabakaran
e12d0be1b2
Re-enable lts based testing 2021-01-20 16:20:58 +05:30
Peter Simons
002326ceb1
Merge pull request #265 from xmonad/t/haskell-ci
Generate CI with the haskell-ci utility.
2021-01-19 20:58:01 +01:00
Peter Simons
758e3d85e6 Generate CI with the haskell-ci utility. 2021-01-19 20:48:16 +01:00
Keith
f5bd77a7f8 made ScreenDetail a newtype and RationalRect strict in its contents. 2021-01-19 12:06:07 -05:00
Tomáš Janoušek
519c79a57e
Merge pull request #263 from slotThe/exception-extensible
Control.Exception.Extensible -> Control.Exception
2021-01-17 20:39:00 +01:00
slotThe
0aa40480f9 Control.Exception.Extensible -> Control.Exception
According to its documentation[1], this module simply re-exports
Control.Exception on recent GHC versions.  As we only support recent
versions, this import is unnecessary.

[1] http://hackage.haskell.org/package/extensible-exceptions-0.1.1.4/docs/Control-Exception-Extensible.html
2021-01-12 11:57:34 +01:00
Peter Simons
36dd6afb49
Merge pull request #261 from xmonad/t/switch-stack-builds-to-nightly
stack.yaml: switch from Stackage LTS to Nightly
2021-01-10 19:36:12 +01:00
Peter Simons
3015968ee4 Run CI builds with Stackage Nightly.
Unfortunately, our CI builds have a hard-coded assumption that all kinds of
LTS-X builds can be performed with the same stack.yaml file, which is not true.
We need to use specialized build instructions for each version of the
environment we're building in, e.g. stack-lts-16.yaml, stack-nightly.yaml, and
so on. Making that change is not super hard, but it's not completely trivial
either because the hooks use a hash of the stack file to determine whether the
cash is still valid, etc., and I'm not entirely sure about the best way to
adapt that code to support multiple YAML files.

For the time being, the most important build IMHO is Stackage Nightly,
because (a) we really want to support the nightly snapshot since (b) it can
compile the genmanpage executable relatively easily.
2021-01-09 19:46:50 +01:00
Peter Simons
5bb6c88b41 stack.yaml: switch from Stackage LTS to Nightly
Let's use a moderately recent compiler like ghc-8.10.3
instead of the old 8.8.x branch for development. Same goes
for our dependencies; development should take place with
recent versions of our dependencies.
2021-01-09 18:06:17 +01:00
Tomáš Janoušek
f875a56620
Merge pull request #258 from slotThe/xdg-things
Revise XDG handling
2021-01-07 19:52:51 +01:00
slotThe
70a75e5e3f Update documentation 2021-01-07 17:25:30 +01:00
slotThe
735fb58f6c Revise XDG handling
Improve handling of the whole XDG situation.  This now looks as follows

  1. If all three of xmonad's environment variables (XMONAD_DATA_DIR,
     XMONAD_CONFIG_DIR, and XMONAD_CACHE_DIR) are set, use them.
  2. If there is a build script `build' or configuration `xmonad.hs' in
     `~/.xmonad', set all three directories to `~/.xmonad'.
  3. Otherwise, use XDG_DATA_HOME, XDG_CONFIG_HOME, and
     XDG_CACHE_HOME (or their respective fallbacks).

If none of the above exist, we default to using the XDG_* variables,
creating the necessary directories if needed.
2021-01-07 15:32:02 +01:00
Tomas Janousek
e8f48b77f9 Sync MAINTAINERS.md with reality on GitHub 2021-01-03 14:05:32 +01:00
Sibi Prabakaran
e363c44bb0
Merge pull request #259 from vmchale/master
Accord with new pattern-match
2021-01-01 11:52:44 +05:30
Vanessa McHale
ec1c3e0159 update changelog 2020-12-31 20:19:10 -06:00
Vanessa McHale
2a1a18023a Accord with new pattern-match 2020-12-31 20:17:22 -06:00
Tomas Janousek
ff738988d3 github: Sync test workflow with that of xmonad-contrib 2020-12-16 11:24:15 +00:00
Sibi Prabakaran
fc4657d529
Merge pull request #252 from slotThe/unused-imports
Get rid of unused imports
2020-12-16 10:30:05 +05:30
Tomáš Janoušek
bd961b7866
Merge pull request #255 from felixonmars/patch-1
Correct a typo in Layout.hs
2020-12-16 01:16:05 +00:00
Felix Yan
3df77d6f20
Correct a typo in Layout.hs 2020-12-16 00:54:36 +08:00
Yecine Megdiche
b59c768cdd
Updated CONTRIBUTING.md and MAINTAINERS.md (#253)
* Updated CONTRIBUTING.md and MAINTAINERS.md

* Fixed broken GitHub links
* Added instructions on how to run tests
* Linked XMonad.Doc.Developing

* updated hackage link
2020-12-15 21:19:07 +05:30
Sibi Prabakaran
a37a3cb6e8
Merge pull request #254 from slotThe/fix-LR
Rename LR = L | R to CLR = CL | CR
2020-12-14 18:07:30 +05:30
slotThe
823581816a Conditionally error on unused imports
This turns off the warnings about unused imports _unless_ one is using
the oldest supported version of GHC (right now that's 8.4.4 or older);
then it turns them into errors!  This prevents xmonad from emitting
warnings about imports that have to be there due to backwards
compatibility, but are obsolete in newer versions (think MFP), while at
the same time preventing bitrot.
2020-12-13 22:15:41 +01:00
slotThe
3ea0d74954 Drop unsupported GHC versions from tested-with
Removes all versions of GHC that are not part of the CI, as these can't
be guaranteed to be built against master every time
2020-12-13 22:15:41 +01:00
slotThe
b3c860b892 Rename LR to CLR
Some modules in xmonad-contrib define their own LR type with L and R as
data constructors, leading to build failures; this fixes that.
2020-12-13 17:23:14 +01:00
slotThe
958e701bf4 Get rid of unused imports
Starting with 28e75da77fa1918ec3ef4ce63ada32507a75b50c we only support
GHC versions 8.4.3 and up (more precisely, the GHC version associated
with stackage lts-12.0 and up).  The imports in question are now in
Prelude and need not be imported explicitly.
2020-12-13 15:57:19 +01:00
Sibi Prabakaran
28e75da77f
Merge pull request #251 from xmonad/github-ci
Add github CI integration
2020-12-12 12:51:48 +05:30
Sibi Prabakaran
a812869c0c
Use v2 of cache. Thanks to @liskin for the help! 2020-12-12 12:15:40 +05:30
Sibi Prabakaran
96fb01b9be
Add lts-12 2020-12-12 12:09:15 +05:30
Sibi Prabakaran
6fa0bb7d4f
Remove travis rule 2020-12-11 18:10:35 +05:30
Sibi Prabakaran
0a040cbc96
Add github CI integration 2020-12-11 17:49:45 +05:30
Sibi Prabakaran
96d4f1fe85
Merge pull request #219 from jumper149/master
Allow pattern-matching on 'XMonad.Layout.Choose' by exporting constructors
2020-12-08 21:14:27 +05:30
Felix Springer
30f2d9f325
Merge branch 'master' into master 2020-12-08 16:41:36 +01:00
Sibi Prabakaran
5be975b4f2
Merge pull request #247 from srid/patch-1
Fix dzen URL
2020-11-25 11:23:56 +05:30
Sridhar Ratnakumar
22c370a068
Fix dzen URL
dzen has moved to GitHub
2020-11-24 12:40:10 -05:00
Brent Yorgey
c3e032e08e
Merge pull request #242 from liskin/layoutclass-typeable
Make layouts Typeable
2020-11-09 14:14:13 -06:00
Peter Simons
2c3bf17dfb
Merge pull request #244 from blackgnezdo/flag-fix
Add required + before flag name cabal.project
2020-11-09 07:40:21 +01:00
Greg Steuck
a926b68838 Add required + before flag name cabal.project
This fixes the build with cabal-3.4.
2020-11-08 20:53:28 -08:00
Tomas Janousek
6dc1e319d1 Make layouts Typeable
This makes it possible to query the current layout state, which might be
useful to e.g. show the current X.L.WorkspaceDir in xmobar.

Example of use (assuming myLayout is the layout that is assigned to
layoutHook):

    asMyLayout (Layout l) = (`asTypeOf` myLayout) <$> cast l

    …

    layout <- asMyLayout . W.layout . W.workspace . W.current <$> gets windowset
    case layout of
        Just (WorkspaceDir d) -> …

Unfortunately this requires adding the Typeable constraint to a bunch of
classes in xmonad-contrib, so we need to merge those changes there first
(fortunately it doesn't need to go in lockstep, adding a Typeable
constraint to those classes in xmonad-contrib is harmless).
2020-11-04 15:28:04 +00:00
Peter Simons
0db71d552a
Merge pull request #221 from liskin/float-dimensions
Use current screen to set dimensions of new floating windows
2020-08-25 12:49:53 +02:00
Peter Simons
f52ed1d19e
Merge pull request #224 from dreamsmasher/master
Fixed typo in Main.hs
2020-08-25 12:48:03 +02:00
Peter Simons
ffcb01ad80 travis.yml: build GenerateManpage when compiling with ghc-8.6.x or later
Older versions will probably choke on pandoc-2.10.x.
2020-08-25 11:50:52 +02:00
Peter Simons
66d2241703 GenerateManpage: port the utility to pandoc 2.10.x 2020-08-25 11:46:30 +02:00
Peter Simons
11814bfec3 cabal.project: enable the generatemanpage flag by default in developer builds 2020-08-25 11:46:06 +02:00
Peter Simons
bbc1c010ed Re-generate the Travis-CI build instructions with the latest version of haskell-ci. 2020-08-25 11:45:51 +02:00
Norman Liu
eeeae810ae Fixed typo in Main.hs 2020-05-29 17:11:09 -04:00
Keith
3c6f52a349 deleted unused 'mul' definition in 'prop_aspect_fits'. 2020-05-25 13:03:08 -04:00
Sibi Prabakaran
40466b2be2
Merge pull request #222 from SCKelemen/patch-1
Nit: fix grammar/spelling issue
2020-05-23 12:43:36 +05:30
Samuel Kelemen
6a4a742feb
Nit: fix grammar/spelling issue 2020-05-22 23:56:52 -04:00
Tomas Janousek
f8b243b66e Use current screen to set dimensions of new floating windows
This fixes a bug when using multiple screens with different dimensions,
causing some floating windows to be smaller/larger than the size they
requested.

Some applications (e.g. pinentry) always map their window at (0, 0) so
floatLocation would compute the window size relative to the screen
containing (0, 0) and if the current workspace is on another screen with
a different size, this relative size results in a different absolute
size, which is undesirable for fixed size floats.

Other applications like ssh-agent place their window at the center of
the framebuffer (ignoring xinerama layout). Same problem.

Then there are apps that remember their position/size when minimizing to
tray and then attempt to restore it when reopened. Again, if they
restore it on another screen, we miscalculate the size.

The fix is to use the current screen for calculating dimensions of new
(not yet mapped) floating windows.

Co-Authored-By: Vincent Vinel <narthorn@gmail.com>
2020-05-13 20:11:32 +02:00
Felix Springer
fa9a3abe49 Allow pattern-matching on 'XMonad.Layout.Choose' by exporting constructors 2020-03-31 22:46:56 +02:00
Sibi
78b967198b
Merge pull request #215 from anandijain/master
update dead dmenu link
2020-03-24 15:21:53 +05:30
anand jain
68574be2cf
Update README.md
Co-Authored-By: Tomáš Janoušek <tomi@nomi.cz>
2020-03-19 15:08:49 -05:00
anand jain
2ab37aa4a4
update dead dmenu link 2020-03-18 19:56:32 -05:00
Peter Simons
5ab9fede6c
Merge pull request #204 from owm111/patch-2
Make "Default Keyboard Bindings" a heading
2019-12-27 11:38:48 +01:00
Owen McGrath
a81ba4ba53
Make "Default Keyboard Bindings" a heading
It looks like it should be a heading, but there wasn't a space so it wasn't one. Looked strange in the manpage.
2019-12-18 18:36:43 -06:00
Sibi
b65728032d
Merge pull request #203 from owm111/patch-1
Update example config link
2019-11-17 12:08:20 +05:30
Owen McGrath
e747377775
Update example config link
The link for the example config leads to file saying "go here instead"; change initial link to "there".
2019-11-16 12:50:38 -06:00
Peter Simons
d6f88918de
Merge pull request #196 from BPDanek/patch-1
punctuation change
2019-07-14 17:38:55 +02:00
Benjamin Danek
21cd920b61
punctuation change 2019-07-10 15:16:24 -07:00
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 d065038c8a07a132d04904089e3970bb193c8e48.

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
58 changed files with 5191 additions and 1398 deletions

View File

@ -1,12 +1,16 @@
### Problem Description
Describe the problem you are having, what you expect to happen
instead, and how to reproduce the problem.
Describe the problem you are having and what you expect to happen
instead.
### Steps to Reproduce
Give detailed step-by-step instructions on how to reproduce the problem.
### Configuration File
Please include the smallest configuration file that reproduces the
problem you are experiencing:
Please include the smallest _full_ configuration file that reproduces
the problem you are experiencing:
```haskell
module Main (main) where
@ -21,4 +25,6 @@ main = xmonad def
- [ ] 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)
- I tested my configuration
- [ ] With `xmonad` version XXX (commit XXX if using git)
- [ ] With `xmonad-contrib` version XXX (commit XXX if using git)

View File

@ -9,6 +9,7 @@ behind them.
- [ ] 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've considered how to best test these changes (property, unit,
manually, ...) and concluded: XXX
- [ ] I updated the `CHANGES.md` file

6
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,6 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"

33
.github/workflows/generatemanpage.yml vendored Normal file
View File

@ -0,0 +1,33 @@
name: Generate manpage
on:
push:
branches:
- master
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Clone project
uses: actions/checkout@v4
- name: Install dependencies
run: |
set -ex
sudo apt install -y pandoc
- name: Generate manpage
run: |
set -ex
for d in /opt/ghc/*/bin; do PATH="$d:$PATH"; break; done
make -B -C man
- name: Commit/push if changed
run: |
set -ex
git config user.name 'github-actions[bot]'
git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
git diff --quiet --exit-code && exit
git commit -a -m 'man: Update'
git push

View File

@ -0,0 +1,139 @@
Piggy-back on the haskell-ci workflow for automatic releases to Hackage.
This extends the workflow with two additional triggers:
* When the Haskell-CI workflow is triggered manually with a non-empty version
input (matching the version in the cabal file), a candidate release is
uploaded to Hackage and docs are submitted for it as Hackage can't build
them itself (https://github.com/haskell/hackage-server/issues/925).
Note that promoting the candidate on Hackage discards the uploaded docs
(https://github.com/haskell/hackage-server/issues/70). Don't do that.
* When a release is created on GitHub, a final release is uploaded to Hackage
and docs are submitted for it.
The automation uses a special Hackage user: https://hackage.haskell.org/user/xmonad
and each repo (X11, xmonad, xmonad-contrib) has its own HACKAGE_API_KEY token
set in GitHub repository secrets.
--- .github/workflows/haskell-ci.yml.orig
+++ .github/workflows/haskell-ci.yml
@@ -14,8 +14,15 @@
#
name: Haskell-CI
on:
- - push
- - pull_request
+ push:
+ pull_request:
+ release:
+ types:
+ - published
+ workflow_dispatch:
+ inputs:
+ version:
+ description: candidate version (must match version in cabal file)
jobs:
linux:
name: Haskell-CI - Linux - ${{ matrix.compiler }}
@@ -33,6 +40,7 @@
compilerVersion: 9.8.4
setup-method: ghcup
allow-failure: false
+ upload: true
- compiler: ghc-9.6.7
compilerKind: ghc
compilerVersion: 9.6.7
@@ -257,6 +265,10 @@
- name: haddock
run: |
$CABAL v2-haddock --disable-documentation $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all
+ - name: haddock for hackage
+ if: matrix.upload
+ run: |
+ $CABAL v2-haddock $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH --haddock-for-hackage --builddir $GITHUB_WORKSPACE/haddock all
- name: unconstrained build
run: |
rm -f cabal.project.local
@@ -267,3 +279,80 @@
with:
key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }}
path: ~/.cabal/store
+ # must be separate artifacts because GitHub Actions are still broken:
+ # https://github.com/actions/upload-artifact/issues/441
+ # https://github.com/actions/upload-artifact/issues/457
+ - name: upload artifact (sdist)
+ if: matrix.upload
+ uses: actions/upload-artifact@v4
+ with:
+ name: sdist
+ path: ${{ github.workspace }}/sdist/*.tar.gz
+ - name: upload artifact (haddock)
+ if: matrix.upload
+ uses: actions/upload-artifact@v4
+ with:
+ name: haddock
+ path: ${{ github.workspace }}/haddock/*-docs.tar.gz
+ - name: hackage upload (candidate)
+ if: matrix.upload && github.event_name == 'workflow_dispatch' && github.event.inputs.version != ''
+ shell: bash
+ run: |
+ set -ex
+ PACKAGE_VERSION="${PACKAGE_VERSION#v}"
+ res=$(
+ curl \
+ --silent --show-error --output /dev/stderr --write-out '%{http_code}' \
+ --header "Accept: text/plain" \
+ --header "Authorization: X-ApiKey $HACKAGE_API_KEY" \
+ --form package=@"${GITHUB_WORKSPACE}/sdist/${PACKAGE_NAME}-${PACKAGE_VERSION}.tar.gz" \
+ https://hackage.haskell.org/packages/candidates/
+ )
+ [[ $res == 2?? ]] # TODO: --fail-with-body once curl 7.76.0 is available
+ res=$(
+ curl \
+ --silent --show-error --output /dev/stderr --write-out '%{http_code}' \
+ -X PUT \
+ --header "Accept: text/plain" \
+ --header "Authorization: X-ApiKey $HACKAGE_API_KEY" \
+ --header "Content-Type: application/x-tar" \
+ --header "Content-Encoding: gzip" \
+ --data-binary @"${GITHUB_WORKSPACE}/haddock/${PACKAGE_NAME}-${PACKAGE_VERSION}-docs.tar.gz" \
+ https://hackage.haskell.org/package/${PACKAGE_NAME}-${PACKAGE_VERSION}/candidate/docs
+ )
+ [[ $res == 2?? ]]
+ env:
+ HACKAGE_API_KEY: ${{ secrets.HACKAGE_API_KEY }}
+ PACKAGE_NAME: ${{ github.event.repository.name }}
+ PACKAGE_VERSION: ${{ github.event.inputs.version }}
+ - name: hackage upload (release)
+ if: matrix.upload && github.event_name == 'release'
+ shell: bash
+ run: |
+ set -ex
+ PACKAGE_VERSION="${PACKAGE_VERSION#v}"
+ res=$(
+ curl \
+ --silent --show-error --output /dev/stderr --write-out '%{http_code}' \
+ --header "Accept: text/plain" \
+ --header "Authorization: X-ApiKey $HACKAGE_API_KEY" \
+ --form package=@"${GITHUB_WORKSPACE}/sdist/${PACKAGE_NAME}-${PACKAGE_VERSION}.tar.gz" \
+ https://hackage.haskell.org/packages/
+ )
+ [[ $res == 2?? ]] # TODO: --fail-with-body once curl 7.76.0 is available
+ res=$(
+ curl \
+ --silent --show-error --output /dev/stderr --write-out '%{http_code}' \
+ -X PUT \
+ --header "Accept: text/plain" \
+ --header "Authorization: X-ApiKey $HACKAGE_API_KEY" \
+ --header "Content-Type: application/x-tar" \
+ --header "Content-Encoding: gzip" \
+ --data-binary @"${GITHUB_WORKSPACE}/haddock/${PACKAGE_NAME}-${PACKAGE_VERSION}-docs.tar.gz" \
+ https://hackage.haskell.org/package/${PACKAGE_NAME}-${PACKAGE_VERSION}/docs
+ )
+ [[ $res == 2?? ]]
+ env:
+ HACKAGE_API_KEY: ${{ secrets.HACKAGE_API_KEY }}
+ PACKAGE_NAME: ${{ github.event.repository.name }}
+ PACKAGE_VERSION: ${{ github.event.release.tag_name }}

335
.github/workflows/haskell-ci.yml vendored Normal file
View File

@ -0,0 +1,335 @@
# This GitHub workflow config has been generated by a script via
#
# haskell-ci 'github' 'cabal.project'
#
# To regenerate the script (for example after adjusting tested-with) run
#
# haskell-ci regenerate
#
# For more information, see https://github.com/haskell-CI/haskell-ci
#
# version: 0.19.20250506
#
# REGENDATA ("0.19.20250506",["github","cabal.project"])
#
name: Haskell-CI
on:
push:
pull_request:
release:
types:
- published
workflow_dispatch:
inputs:
version:
description: candidate version (must match version in cabal file)
jobs:
linux:
name: Haskell-CI - Linux - ${{ matrix.compiler }}
runs-on: ubuntu-24.04
timeout-minutes:
60
container:
image: buildpack-deps:jammy
continue-on-error: ${{ matrix.allow-failure }}
strategy:
matrix:
include:
- compiler: ghc-9.12.2
compilerKind: ghc
compilerVersion: 9.12.2
setup-method: ghcup
allow-failure: false
- compiler: ghc-9.10.2
compilerKind: ghc
compilerVersion: 9.10.2
setup-method: ghcup
allow-failure: false
- compiler: ghc-9.8.4
compilerKind: ghc
compilerVersion: 9.8.4
setup-method: ghcup
allow-failure: false
upload: true
- compiler: ghc-9.6.7
compilerKind: ghc
compilerVersion: 9.6.7
setup-method: ghcup
allow-failure: false
- compiler: ghc-9.4.8
compilerKind: ghc
compilerVersion: 9.4.8
setup-method: ghcup
allow-failure: false
- compiler: ghc-9.2.8
compilerKind: ghc
compilerVersion: 9.2.8
setup-method: ghcup
allow-failure: false
- compiler: ghc-9.0.2
compilerKind: ghc
compilerVersion: 9.0.2
setup-method: ghcup
allow-failure: false
- compiler: ghc-8.10.7
compilerKind: ghc
compilerVersion: 8.10.7
setup-method: ghcup
allow-failure: false
- compiler: ghc-8.8.4
compilerKind: ghc
compilerVersion: 8.8.4
setup-method: ghcup
allow-failure: false
- compiler: ghc-8.6.5
compilerKind: ghc
compilerVersion: 8.6.5
setup-method: ghcup
allow-failure: false
fail-fast: false
steps:
- name: apt-get install
run: |
apt-get update
apt-get install -y --no-install-recommends gnupg ca-certificates dirmngr curl git software-properties-common libtinfo5
apt-get install -y libx11-dev libxext-dev libxinerama-dev libxrandr-dev libxss-dev
- name: Install GHCup
run: |
mkdir -p "$HOME/.ghcup/bin"
curl -sL https://downloads.haskell.org/ghcup/0.1.50.1/x86_64-linux-ghcup-0.1.50.1 > "$HOME/.ghcup/bin/ghcup"
chmod a+x "$HOME/.ghcup/bin/ghcup"
- name: Install cabal-install
run: |
"$HOME/.ghcup/bin/ghcup" install cabal 3.14.2.0 || (cat "$HOME"/.ghcup/logs/*.* && false)
echo "CABAL=$HOME/.ghcup/bin/cabal-3.14.2.0 -vnormal+nowrap" >> "$GITHUB_ENV"
- name: Install GHC (GHCup)
if: matrix.setup-method == 'ghcup'
run: |
"$HOME/.ghcup/bin/ghcup" install ghc "$HCVER" || (cat "$HOME"/.ghcup/logs/*.* && false)
HC=$("$HOME/.ghcup/bin/ghcup" whereis ghc "$HCVER")
HCPKG=$(echo "$HC" | sed 's#ghc$#ghc-pkg#')
HADDOCK=$(echo "$HC" | sed 's#ghc$#haddock#')
echo "HC=$HC" >> "$GITHUB_ENV"
echo "HCPKG=$HCPKG" >> "$GITHUB_ENV"
echo "HADDOCK=$HADDOCK" >> "$GITHUB_ENV"
env:
HCKIND: ${{ matrix.compilerKind }}
HCNAME: ${{ matrix.compiler }}
HCVER: ${{ matrix.compilerVersion }}
- name: Set PATH and environment variables
run: |
echo "$HOME/.cabal/bin" >> $GITHUB_PATH
echo "LANG=C.UTF-8" >> "$GITHUB_ENV"
echo "CABAL_DIR=$HOME/.cabal" >> "$GITHUB_ENV"
echo "CABAL_CONFIG=$HOME/.cabal/config" >> "$GITHUB_ENV"
HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\d+)\.(\d+)\.(\d+)(\.(\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')
echo "HCNUMVER=$HCNUMVER" >> "$GITHUB_ENV"
echo "ARG_TESTS=--enable-tests" >> "$GITHUB_ENV"
echo "ARG_BENCH=--enable-benchmarks" >> "$GITHUB_ENV"
echo "HEADHACKAGE=false" >> "$GITHUB_ENV"
echo "ARG_COMPILER=--$HCKIND --with-compiler=$HC" >> "$GITHUB_ENV"
env:
HCKIND: ${{ matrix.compilerKind }}
HCNAME: ${{ matrix.compiler }}
HCVER: ${{ matrix.compilerVersion }}
- name: env
run: |
env
- name: write cabal config
run: |
mkdir -p $CABAL_DIR
cat >> $CABAL_CONFIG <<EOF
remote-build-reporting: anonymous
write-ghc-environment-files: never
remote-repo-cache: $CABAL_DIR/packages
logs-dir: $CABAL_DIR/logs
world-file: $CABAL_DIR/world
extra-prog-path: $CABAL_DIR/bin
symlink-bindir: $CABAL_DIR/bin
installdir: $CABAL_DIR/bin
build-summary: $CABAL_DIR/logs/build.log
store-dir: $CABAL_DIR/store
install-dirs user
prefix: $CABAL_DIR
repository hackage.haskell.org
url: http://hackage.haskell.org/
EOF
cat >> $CABAL_CONFIG <<EOF
program-default-options
ghc-options: $GHCJOBS +RTS -M3G -RTS
EOF
cat $CABAL_CONFIG
- name: versions
run: |
$HC --version || true
$HC --print-project-git-commit-id || true
$CABAL --version || true
- name: update cabal index
run: |
$CABAL v2-update -v
- name: install cabal-plan
run: |
mkdir -p $HOME/.cabal/bin
curl -sL https://github.com/haskell-hvr/cabal-plan/releases/download/v0.7.3.0/cabal-plan-0.7.3.0-x86_64-linux.xz > cabal-plan.xz
echo 'f62ccb2971567a5f638f2005ad3173dba14693a45154c1508645c52289714cb2 cabal-plan.xz' | sha256sum -c -
xz -d < cabal-plan.xz > $HOME/.cabal/bin/cabal-plan
rm -f cabal-plan.xz
chmod a+x $HOME/.cabal/bin/cabal-plan
cabal-plan --version
- name: checkout
uses: actions/checkout@v4
with:
path: source
- name: initial cabal.project for sdist
run: |
touch cabal.project
echo "packages: $GITHUB_WORKSPACE/source/." >> cabal.project
cat cabal.project
- name: sdist
run: |
mkdir -p sdist
$CABAL sdist all --output-dir $GITHUB_WORKSPACE/sdist
- name: unpack
run: |
mkdir -p unpacked
find sdist -maxdepth 1 -type f -name '*.tar.gz' -exec tar -C $GITHUB_WORKSPACE/unpacked -xzvf {} \;
- name: generate cabal.project
run: |
PKGDIR_xmonad="$(find "$GITHUB_WORKSPACE/unpacked" -maxdepth 1 -type d -regex '.*/xmonad-[0-9.]*')"
echo "PKGDIR_xmonad=${PKGDIR_xmonad}" >> "$GITHUB_ENV"
rm -f cabal.project cabal.project.local
touch cabal.project
touch cabal.project.local
echo "packages: ${PKGDIR_xmonad}" >> cabal.project
echo "package xmonad" >> cabal.project
echo " ghc-options: -Werror=missing-methods" >> cabal.project
cat >> cabal.project <<EOF
optimization: False
package xmonad
flags: +pedantic
EOF
$HCPKG list --simple-output --names-only | perl -ne 'for (split /\s+/) { print "constraints: any.$_ installed\n" unless /^(xmonad)$/; }' >> cabal.project.local
cat cabal.project
cat cabal.project.local
- name: dump install plan
run: |
$CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dry-run all
cabal-plan
- name: restore cache
uses: actions/cache/restore@v4
with:
key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }}
path: ~/.cabal/store
restore-keys: ${{ runner.os }}-${{ matrix.compiler }}-
- name: install dependencies
run: |
$CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --dependencies-only -j2 all
$CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dependencies-only -j2 all
- name: build w/o tests
run: |
$CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
- name: build
run: |
$CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --write-ghc-environment-files=always
- name: tests
run: |
$CABAL v2-test $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --test-show-details=direct
- name: cabal check
run: |
cd ${PKGDIR_xmonad} || false
${CABAL} -vnormal check
- name: haddock
run: |
$CABAL v2-haddock --disable-documentation $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all
- name: haddock for hackage
if: matrix.upload
run: |
$CABAL v2-haddock $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH --haddock-for-hackage --builddir $GITHUB_WORKSPACE/haddock all
- name: unconstrained build
run: |
rm -f cabal.project.local
$CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
- name: save cache
if: always()
uses: actions/cache/save@v4
with:
key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }}
path: ~/.cabal/store
# must be separate artifacts because GitHub Actions are still broken:
# https://github.com/actions/upload-artifact/issues/441
# https://github.com/actions/upload-artifact/issues/457
- name: upload artifact (sdist)
if: matrix.upload
uses: actions/upload-artifact@v4
with:
name: sdist
path: ${{ github.workspace }}/sdist/*.tar.gz
- name: upload artifact (haddock)
if: matrix.upload
uses: actions/upload-artifact@v4
with:
name: haddock
path: ${{ github.workspace }}/haddock/*-docs.tar.gz
- name: hackage upload (candidate)
if: matrix.upload && github.event_name == 'workflow_dispatch' && github.event.inputs.version != ''
shell: bash
run: |
set -ex
PACKAGE_VERSION="${PACKAGE_VERSION#v}"
res=$(
curl \
--silent --show-error --output /dev/stderr --write-out '%{http_code}' \
--header "Accept: text/plain" \
--header "Authorization: X-ApiKey $HACKAGE_API_KEY" \
--form package=@"${GITHUB_WORKSPACE}/sdist/${PACKAGE_NAME}-${PACKAGE_VERSION}.tar.gz" \
https://hackage.haskell.org/packages/candidates/
)
[[ $res == 2?? ]] # TODO: --fail-with-body once curl 7.76.0 is available
res=$(
curl \
--silent --show-error --output /dev/stderr --write-out '%{http_code}' \
-X PUT \
--header "Accept: text/plain" \
--header "Authorization: X-ApiKey $HACKAGE_API_KEY" \
--header "Content-Type: application/x-tar" \
--header "Content-Encoding: gzip" \
--data-binary @"${GITHUB_WORKSPACE}/haddock/${PACKAGE_NAME}-${PACKAGE_VERSION}-docs.tar.gz" \
https://hackage.haskell.org/package/${PACKAGE_NAME}-${PACKAGE_VERSION}/candidate/docs
)
[[ $res == 2?? ]]
env:
HACKAGE_API_KEY: ${{ secrets.HACKAGE_API_KEY }}
PACKAGE_NAME: ${{ github.event.repository.name }}
PACKAGE_VERSION: ${{ github.event.inputs.version }}
- name: hackage upload (release)
if: matrix.upload && github.event_name == 'release'
shell: bash
run: |
set -ex
PACKAGE_VERSION="${PACKAGE_VERSION#v}"
res=$(
curl \
--silent --show-error --output /dev/stderr --write-out '%{http_code}' \
--header "Accept: text/plain" \
--header "Authorization: X-ApiKey $HACKAGE_API_KEY" \
--form package=@"${GITHUB_WORKSPACE}/sdist/${PACKAGE_NAME}-${PACKAGE_VERSION}.tar.gz" \
https://hackage.haskell.org/packages/
)
[[ $res == 2?? ]] # TODO: --fail-with-body once curl 7.76.0 is available
res=$(
curl \
--silent --show-error --output /dev/stderr --write-out '%{http_code}' \
-X PUT \
--header "Accept: text/plain" \
--header "Authorization: X-ApiKey $HACKAGE_API_KEY" \
--header "Content-Type: application/x-tar" \
--header "Content-Encoding: gzip" \
--data-binary @"${GITHUB_WORKSPACE}/haddock/${PACKAGE_NAME}-${PACKAGE_VERSION}-docs.tar.gz" \
https://hackage.haskell.org/package/${PACKAGE_NAME}-${PACKAGE_VERSION}/docs
)
[[ $res == 2?? ]]
env:
HACKAGE_API_KEY: ${{ secrets.HACKAGE_API_KEY }}
PACKAGE_NAME: ${{ github.event.repository.name }}
PACKAGE_VERSION: ${{ github.event.release.tag_name }}

22
.github/workflows/hlint.yaml vendored Normal file
View File

@ -0,0 +1,22 @@
name: hlint
on:
push:
pull_request:
jobs:
hlint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: 'Set up HLint'
uses: haskell-actions/hlint-setup@v2
with:
version: '3.5'
- name: 'Run HLint'
uses: haskell-actions/hlint-run@v2
with:
path: '.'
fail-on: status

21
.github/workflows/nix.yml vendored Normal file
View File

@ -0,0 +1,21 @@
name: Nix
on:
push:
pull_request:
jobs:
build:
runs-on: ubuntu-latest
name: Nix Flake - Linux
permissions:
contents: read
steps:
- name: Install Nix
uses: cachix/install-nix-action@v31
with:
github_access_token: ${{ secrets.GITHUB_TOKEN }}
- name: Clone project
uses: actions/checkout@v4
- name: Build
run: nix build --print-build-logs

48
.github/workflows/packdeps.yml vendored Normal file
View File

@ -0,0 +1,48 @@
name: Packdeps
on:
workflow_dispatch:
schedule:
# Run every Saturday
- cron: '0 3 * * 6'
jobs:
packdeps:
name: Packdeps
runs-on: ubuntu-latest
steps:
- name: Clone project
uses: actions/checkout@v4
- name: Setup Haskell
uses: haskell-actions/setup@v2
with:
# packdeps doesn't build with newer as of 2021-10
ghc-version: '8.8'
- name: Install packdeps
run: |
set -ex
cd # go somewhere without a cabal.project
cabal install packdeps
- name: Check package bounds (all)
continue-on-error: true
run: |
set -ex
packdeps \
--exclude X11 \
*.cabal
- name: Check package bounds (preferred)
run: |
set -ex
packdeps \
--preferred \
--exclude X11 \
*.cabal
workflow-keepalive:
if: github.event_name == 'schedule'
runs-on: ubuntu-latest
permissions:
actions: write
steps:
- uses: liskin/gh-workflow-keepalive@v1

79
.github/workflows/stack.yml vendored Normal file
View File

@ -0,0 +1,79 @@
name: Stack
on:
push:
pull_request:
jobs:
build:
name: Stack CI - Linux - ${{ matrix.resolver }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- resolver: lts-14 # GHC 8.6
- resolver: lts-16 # GHC 8.8
- resolver: lts-18 # GHC 8.10
- resolver: lts-19 # GHC 9.0
- resolver: lts-20 # GHC 9.2
- resolver: lts-21 # GHC 9.4
- resolver: lts-22 # GHC 9.6
- resolver: lts-23 # GHC 9.8
steps:
- name: Clone project
uses: actions/checkout@v4
- name: Install C dependencies
run: |
set -ex
sudo apt update -y
sudo apt install -y \
libx11-dev \
libxext-dev \
libxinerama-dev \
libxrandr-dev \
libxss-dev \
#
- name: Refresh caches once a month
id: cache-date
# GHA writes caches on the first miss and then never updates them again;
# force updating the cache at least once a month. Additionally, the
# date is prefixed with an epoch number to let us manually refresh the
# cache when needed. This is a workaround for https://github.com/actions/cache/issues/2
run: |
date +date=1-%Y-%m >> $GITHUB_OUTPUT
- name: Cache Haskell package metadata
uses: actions/cache@v4
with:
path: ~/.stack/pantry
key: stack-pantry-${{ runner.os }}-${{ steps.cache-date.outputs.date }}
- name: Cache Haskell dependencies
uses: actions/cache@v4
with:
path: |
~/.stack/*
!~/.stack/pantry
!~/.stack/programs
key: stack-${{ runner.os }}-${{ matrix.resolver }}-${{ steps.cache-date.outputs.date }}-${{ hashFiles('stack.yaml') }}-${{ hashFiles('*.cabal') }}
restore-keys: |
stack-${{ runner.os }}-${{ matrix.resolver }}-${{ steps.cache-date.outputs.date }}-${{ hashFiles('stack.yaml') }}-
stack-${{ runner.os }}-${{ matrix.resolver }}-${{ steps.cache-date.outputs.date }}-
- name: Update hackage index
# always update index to prevent the shared ~/.stack/pantry cache from being empty
run: |
set -ex
stack update
- name: Build and test
run: |
set -ex
stack test \
--fast --no-terminal \
--resolver=${{ matrix.resolver }} --system-ghc \
--flag=xmonad:pedantic

16
.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,4 +18,15 @@ tags
# stack artifacts
/.stack-work/
# cabal-install artifacts
/.*.environment.*-*
/.cabal-sandbox/
/cabal.config
/cabal.project.local
/cabal.sandbox.config
/dist-newstyle/
/dist/
# nix artifacts
result

2
.hlint.yaml Normal file
View File

@ -0,0 +1,2 @@
# Ignore these warnings.
- ignore: {name: "Use camelCase"}

39
.mailmap Normal file
View File

@ -0,0 +1,39 @@
Adam Plaice <plaice.adam+github@gmail.com>
Brandon S Allbery KF8NH <allbery.b@gmail.com>
Brent Yorgey <byorgey@gmail.com> <byorgey@cis.upenn.edu>
Conrad Irwin <conrad.irwin@gmail.com>
Daniel Neri <daniel.neri@sigicom.com> <daniel.neri@sigicom.se>
Daniel Schoepe <daniel.schoepe@gmail.com> <asgaroth_@gmx.de>
Daniel Wagner <me@dmwit.com> <daniel@wagner-home.com>
David Glasser <glasser@mit.edu>
Deven Lahoti <deven.lahoti@gmail.com>
Devin Mullins <devin.mullins@gmail.com> <me@twifkak.com>
Don Stewart <dons00@gmail.com> <dons@cse.unsw.edu.au>
Don Stewart <dons00@gmail.com> <dons@galois.com>
Felix Springer <felixspringer149@gmail.com> <39434424+jumper149@users.noreply.github.com>
Gwern Branwen <gwern@gwern.net> <gwern0@gmail.com>
Lukas Mai <l.mai@web.de>
Marshall Lochbaum <mwlochbaum@gmail.com>
Michael G. Sloan <mgsloan@gmail.com>
Neil Mitchell <ndmitchell@gmail.com> <http://www.cs.york.ac.uk/~ndm/>
Neil Mitchell <ndmitchell@gmail.com> Neil Mitchell <unknown>
Nick Burlett <nickburlett@mac.com>
Nicolas Pouillard <nicolas.pouillard@gmail.com>
Nik Nyby <nnyby@columbia.edu>
Peter J. Jones <pjones@devalot.com>
Peter J. Jones <pjones@devalot.com> <pjones@pmade.com>
Robert Marlow <bobstopper@bobturf.org>
Robert Marlow <bobstopper@bobturf.org> <robreim@bobturf.org>
Sam Hughes <hughes@rpi.edu>
Shae Erisson <shae@ScannedInAvian.com>
Sibi Prabakaran <sibi@psibi.in>
Sibi Prabakaran <sibi@psibi.in> <psibi2000@gmail.com>
Spencer Janssen <spencerjanssen@gmail.com> <sjanssen@cse.unl.edu>
Timothy Hobbs <tim.thelion@gmail.com>
Tomas Janousek <tomi@nomi.cz>
Valery V. Vorotyntsev <valery.vv@gmail.com>
Vanessa McHale <vamchale@gmail.com> <vanessa.mchale@reconfigure.io>
Wirt Wolff <wirtwolff@gmail.com>
Tony Zorman <soliditsallgood@mailbox.org> <50166980+slotThe@users.noreply.github.com>
Tony Zorman <soliditsallgood@mailbox.org>

View File

@ -1,85 +0,0 @@
# This file has been generated -- see https://github.com/hvr/multi-ghc-travis
language: c
sudo: false
cache:
directories:
- $HOME/.cabsnap
- $HOME/.cabal/packages
before_cache:
- rm -fv $HOME/.cabal/packages/hackage.haskell.org/build-reports.log
- rm -fv $HOME/.cabal/packages/hackage.haskell.org/00-index.tar
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.3
compiler: ": #GHC 7.10.3"
addons: {apt: {packages: [cabal-install-1.22,ghc-7.10.3], sources: [hvr-ghc]}}
- env: CABALVER=1.24 GHCVER=8.0.1
compiler: ": #GHC 8.0.1"
addons: {apt: {packages: [cabal-install-1.24,ghc-8.0.1], sources: [hvr-ghc]}}
before_install:
- unset CC
- export PATH=/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:$PATH
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
# check whether current requested install-plan matches cached package-db snapshot
- if diff -u $HOME/.cabsnap/installplan.txt 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
# 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
# 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
# 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")
# EOF

View File

@ -1,5 +1,234 @@
# Change Log / Release Notes
## _unreleased_
### Breaking Changes
* Use `cabal` for `--recompile` if there is a `.cabal` file in the config
directory and none of `build`, `stack.yaml`, `flake.nix`, nor `default.nix`
exist.
### Enhancements
### Bug Fixes
### Other
PR #404 (see last change in 0.17.1) has been reverted, because the affected
compilers are (hopefully) no longer being used.
All 9.0 releases of GHC, plus 9.2.1 and 9.2.2 have the join point bug.
Note that 9.0.x is known to also have GC issues and is officially deprecated,
and the only 9.2 release that should be used is 9.2.8. Additionally, GHC HQ
doesn't support releases before 9.6.6.
## 0.18.0 (February 3, 2024)
### Breaking Changes
* Dropped support for GHC 8.4.
### Enhancements
* Exported `sendRestart` and `sendReplace` from `XMonad.Operations`.
* Exported `buildLaunch` from `XMonad.Main`.
* `Tall` does not draw windows with zero area.
* `XMonad.Operations.floatLocation` now applies size hints. This means windows
will snap to these hints as soon as they're floated (mouse move, keybinding).
Previously that only happened on mouse resize.
* Recompilation now detects `flake.nix` and `default.nix` (can be a
symlink) and switches to using `nix build` as appropriate.
* Added `unGrab` to `XMonad.Operations`; this releases XMonad's passive
keyboard grab, so other applications (like `scrot`) can do their
thing.
### Bug Fixes
* Duplicated floats (e.g. from X.A.CopyToAll) no longer escape to inactive
screens.
## 0.17.2 (April 2, 2023)
### Bug Fixes
* Fixed the build with GHC 9.6.
## 0.17.1 (September 3, 2022)
### Enhancements
* Added custom cursor shapes for resizing and moving windows.
* Exported `cacheNumlockMask` and `mkGrabs` from `XMonad.Operations`.
* Added `willFloat` function to `XMonad.ManageHooks` to detect whether the
(about to be) managed window will be a floating window or not.
### Bug Fixes
* Fixed border color of windows with alpha channel. Now all windows have the
same opaque border color.
* Change the main loop to try to avoid [GHC bug 21708] on systems
running GHC 9.2 up to version 9.2.3. The issue has been fixed in
[GHC 9.2.4] and all later releases.
[GHC bug 21708]: https://gitlab.haskell.org/ghc/ghc/-/issues/21708
[GHC 9.2.4]: https://discourse.haskell.org/t/ghc-9-2-4-released/4851
## 0.17.0 (October 27, 2021)
### Enhancements
* Migrated `X.L.LayoutCombinators.(|||)` into `XMonad.Layout`, providing the
ability to directly jump to a layout with the `JumpToLayout` message.
* Recompilation now detects `stack.yaml` (can be a symlink) alongside
`xmonad.hs` and switches to using `stack ghc`. We also updated INSTALL.md
with instructions for cabal-install that lead to correct recompilation.
Deprecation warnings during recompilation are no longer suppressed to make
it easier for us to clean up the codebase. These can still be suppressed
manually using an `OPTIONS_GHC` pragma with `-Wno-deprecations`.
* Improve handling of XDG directories.
1. If all three of xmonad's environment variables (`XMONAD_DATA_DIR,`
`XMONAD_CONFIG_DIR`, and `XMONAD_CACHE_DIR`) are set, use them.
2. If there is a build script called `build` (see [these build scripts]
for usage examples) or configuration `xmonad.hs` in `~/.xmonad`, set
all three directories to `~/.xmonad`.
3. Otherwise, use the `xmonad` directory in `XDG_DATA_HOME`,
`XDG_CONFIG_HOME`, and `XDG_CACHE_HOME` (or their respective
fallbacks). These directories are created if necessary.
In the cases of 1. and 3., the build script or executable is expected to be
in the config dir.
Additionally, the xmonad config binary and intermediate object files were
moved to the cache directory (only relevant if using XDG or
`XMONAD_CACHE_DIR`).
* Added `Foldable`, `Functor`, and `Traversable` instances for `Stack`.
* Added `Typeable layout` constraint to `LayoutClass`, making it possible to
cast `Layout` back into a concrete type and extract current layout state
from it.
* Export constructor for `Choose` and `CLR` from `Module.Layout` to allow
pattern-matching on the left and right sub-layouts of `Choose l r a`.
* Added `withUnfocused` function to `XMonad.Operations`, allowing for `X`
operations to be applied to unfocused windows.
[these build scripts]: https://github.com/xmonad/xmonad-testing/tree/master/build-scripts
### Bug Fixes
* Fixed a bug when using multiple screens with different dimensions, causing
some floating windows to be smaller/larger than the size they requested.
* Compatibility with GHC 9.0
* Fixed dunst notifications being obscured when moving floats.
https://github.com/xmonad/xmonad/issues/208
### Breaking Changes
* Made `(<&&>)` and `(<||>)` non-strict in their right operand; i.e., these
operators now implement short-circuit evaluation so the right operand is
evaluated only if the left operand does not suffice to determine the
result.
* Change `ScreenDetail` to a newtype and make `RationalRect` strict in its
contents.
* Added the `extensibleConf` field to `XConfig` which makes it easier for
contrib modules to have composable configuration (custom hooks, …).
* `util/GenerateManpage.hs` is no longer distributed in the tarball.
Instead, the manpage source is regenerated and manpage rebuilt
automatically in CI.
* `DestroyWindowEvent` is now broadcasted to layouts to let them know
window-specific resources can be discarded.
## 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

82
CONFIG
View File

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

View File

@ -34,9 +34,15 @@ Awesome! Here are a few things to keep in mind:
nontrivial changes to xmonad. There are a couple of ways you can
chat with us:
- Join the [`#xmonad` IRC channel] on `irc.libera.chat` or the
official [matrix channel], which is linked to IRC. This is the
preferred (and fastest!) way to get into contact with us.
- Post a message to the [mailing list][ml].
- Join the `#xmonad` IRC channel on `chat.freenode.org`.
* [XMonad.Doc.Developing][xmonad-doc-developing] is a great
resource to get an overview of xmonad. Make sure to also check
it if you want more details on the coding style.
* Continue reading this document!
@ -55,12 +61,71 @@ Here are some tips for getting your changes merged into xmonad:
* 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 test your changes against the most recent commit of
[xmonad][] (and [xmonad-contrib][], if you're contributing there).
If you're adding a new module or functionality, make sure to add an
example in the documentation and in the PR description.
* Make sure you run the automated tests. Both [xmonad-contrib][]
and [xmonad][] have test-suites that you could run with
`stack test` for example.
* When committing, try to follow existing practices. For more
information on what good commit messages look like, see [How to
Write a Git Commit Message][commit-cbeams] and the [Kernel
documentation][commit-kernel] about committing logical changes
separately.
## Style Guidelines
Below are some common style guidelines that all of the core modules
follow. Before submitting a pull request, make sure that your code does
as well!
* Comment every top level function (particularly exported functions),
and provide a type signature; use Haddock syntax in the comments.
* Follow the coding style of the module that you are making changes to
(`n` spaces for indentation, where to break long type signatures, …).
* New code should not introduce any new warnings. If you want to
check this yourself before submitting a pull request, there is the
`pedantic` flag, which is enforced in our CI. You can enable it by
building your changes with `stack build --flag xmonad:pedantic` or
`cabal build --flag pedantic`.
* Likewise, your code should be free of [hlint] warnings; this is also
enforced in our GitHub CI.
* Partial functions are to be avoided: the window manager should not
crash, so do not call `error` or `undefined`.
* Any pure function added to the core should have QuickCheck
properties precisely defining its behavior.
* New modules should identify the author, and be submitted under the
same license as xmonad (BSD3 license).
## Keep rocking!
xmonad is a passion project created and maintained by the community.
We'd love for you to maintain your own contributed modules (approve
changes from other contributors, review code, etc.). However, before
we'd be comfortable adding you to the [xmonad GitHub
organization][xmonad-gh-org] we need to trust that you have sufficient
knowledge of Haskell and git; and have a way of chatting with you ([IRC,
Matrix, etc.][community]).
[hlint]: https://github.com/ndmitchell/hlint
[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
[xmonad-doc-developing]: https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Doc-Developing.html
[`#xmonad` IRC channel]: https://web.libera.chat/#xmonad
[matrix channel]: https://matrix.to/#/#xmonad:matrix.org
[commit-cbeams]: https://cbea.ms/git-commit/
[commit-kernel]: https://www.kernel.org/doc/html/v4.10/process/submitting-patches.html#separate-your-changes
[community]: https://xmonad.org/community.html
[xmonad-gh-org]: https://github.com/xmonad

402
INSTALL.md Normal file
View File

@ -0,0 +1,402 @@
# Install XMonad
On many systems xmonad is available as a binary package in your
distribution (Debian, Ubuntu, Fedora, Arch, Gentoo, …).
It's by far the easiest way to get xmonad, although you'll miss out on the
latest features and fixes that may not have been released yet.
If you do want the latest and greatest, continue reading.
Those who install from distro can skip this and go straight to
[the XMonad Configuration Tutorial](TUTORIAL.md).
<!-- https://github.com/frnmst/md-toc -->
<!-- regenerate via: md_toc -s1 -p github INSTALL.md -->
<!--TOC-->
- [Dependencies](#dependencies)
- [Preparation](#preparation)
- [Download XMonad sources](#download-xmonad-sources)
- [Build XMonad](#build-xmonad)
- [Build using Stack](#build-using-stack)
- [Build using cabal-install](#build-using-cabal-install)
- [Make XMonad your window manager](#make-xmonad-your-window-manager)
- [Custom Build Script](#custom-build-script)
<!--TOC-->
## Dependencies
#### Debian, Ubuntu
``` console
$ sudo apt install \
> git \
> libx11-dev libxft-dev libxinerama-dev libxrandr-dev libxss-dev
```
#### Fedora
``` console
$ sudo dnf install \
> git \
> libX11-devel libXft-devel libXinerama-devel libXrandr-devel libXScrnSaver-devel
```
#### Arch
``` console
$ sudo pacman -S \
> git \
> xorg-server xorg-apps xorg-xinit xorg-xmessage \
> libx11 libxft libxinerama libxrandr libxss \
> pkgconf
```
#### Void
``` console
$ sudo xbps-install \
> git \
> ncurses-libtinfo-libs ncurses-libtinfo-devel \
> libX11-devel libXft-devel libXinerama-devel libXrandr-devel libXScrnSaver-devel \
> pkg-config
```
## Preparation
We'll use the [XDG] directory specifications here, meaning our
configuration will reside within `$XDG_CONFIG_HOME`, which is
`~/.config` on most systems. Let's create this directory and move to
it:
``` console
$ mkdir -p ~/.config/xmonad && cd ~/.config/xmonad
```
If you already have an `xmonad.hs` configuration, you can copy it over
now. If not, you can use the defaults: create a file called `xmonad.hs`
with the following content:
``` haskell
import XMonad
main :: IO ()
main = xmonad def
```
Older versions of xmonad used `~/.xmonad` instead.
This is still supported, but XDG is preferred.
## Download XMonad sources
Still in `~/.config/xmonad`, clone `xmonad` and `xmonad-contrib` repositories
using [git][]:
``` console
$ git clone https://github.com/xmonad/xmonad
$ git clone https://github.com/xmonad/xmonad-contrib
```
This will give you the latest `HEAD`; if you want you can also check
out a tagged release, e.g.:
``` console
$ git clone --branch v0.17.2 https://github.com/xmonad/xmonad
$ git clone --branch v0.17.1 https://github.com/xmonad/xmonad-contrib
```
(Sources and binaries don't usually go into `~/.config`. In our case,
however, it avoids complexities related to Haskell build tools and lets us
focus on the important bits of XMonad installation.)
## Build XMonad
There are two widely used Haskell build tools:
* [Stack][stack]
* [cabal-install][cabal-install]
We include instructions for both.
Unless you already know which one you prefer, use Stack, which is easier.
### Build using Stack
#### Install Stack
Probably one of the best ways to get [stack] is to use [GHCup], which is the main Haskell installer according to language's official [website][GHCup] and community [survey]. GHCup is [widely available] and is considered less error prone than other installation options.
You can also use your system's package
manager:
``` console
$ sudo apt install haskell-stack # Debian, Ubuntu
$ sudo dnf install stack # Fedora
$ sudo pacman -S stack # Arch
```
If you install stack via this method, it is advisable that you run
`stack upgrade` after installation. This will make sure that you are on
the most recent version of the program, regardless of which version your
distribution actually packages.
If your distribution does not package stack, you can also easily install
it via the following command (this is the recommended way to install
stack via its [documentation][stack]):
``` console
$ curl -sSL https://get.haskellstack.org/ | sh
```
#### Create a New Project
Let's create a stack project. Since we're already in the correct
directory (`~/.config/xmonad`) with `xmonad` and `xmonad-contrib`
subdirectories, starting a new stack project is as simple as running `stack
init`.
Stack should now inform you that it will use the relevant `stack` and
`cabal` files from `xmonad` and `xmonad-contrib` to generate its
`stack.yaml` file. At the time of writing, this looks a little bit like
this:
``` console
$ stack init
Looking for .cabal or package.yaml files to use to init the project.
Using cabal packages:
- xmonad-contrib/
- xmonad/
Selecting the best among 19 snapshots...
* Matches https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/17/9.yaml
Selected resolver: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/17/9.yaml
Initialising configuration using resolver: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/17/9.yaml
Total number of user packages considered: 2
Writing configuration to file: stack.yaml
All done.
```
If you look into your current directory now, you should see a freshly
generated `stack.yaml` file:
``` console
$ ls
xmonad xmonad-contrib stack.yaml xmonad.hs
```
The meat of that file (comments start with `#`, we've omitted them here)
will look a little bit like
``` yaml
resolver:
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/17/9.yaml
packages:
- xmonad
- xmonad-contrib
```
With `stack.yaml` alongside `xmonad.hs`, xmonad now knows that it needs to use
`stack ghc` instead of just `ghc` when (re)compiling its configuration.
If you want to keep xmonad sources and the stack project elsewhere, but still
use `xmonad --recompile`, symlink your real `stack.yaml` into the xmonad
configuration directory, or [use a custom build script](#custom-build-script).
#### Install Everything
Installing things is as easy as typing `stack install`. This will
install the correct version of GHC, as well as build all of the required
packages (`stack build`) and then copy the relevant executables
(`xmonad`, in our case) to `~/.local/bin`. Make sure to add that
directory to your `$PATH`! The command `which xmonad` should now return
that executable. In case it does not, check if you still have xmonad
installed via your package manager and uninstall it.
If you're getting build failures while building the `X11` package it may
be that you don't have the required C libraries installed. See
[above](#dependencies).
### Build using cabal-install
#### Install cabal-install
Probably one of the best ways to get [cabal-install] is to use [GHCup], which is the main Haskell installer according to language's official [website][GHCup] and community [survey]. GHCup is [widely available] and is considered less error prone than other installation options.
You can also use your system's package
manager:
``` console
$ sudo apt install cabal-install # Debian, Ubuntu
$ sudo dnf install cabal-install # Fedora
$ sudo pacman -S cabal-install # Arch
```
See also <https://www.haskell.org/cabal/#install-upgrade>.
#### Create a New Project
If you want to use `xmonad` or `xmonad-contrib` from git, you will need a
`cabal.project` file. If you want to use both from [Hackage][], you should
skip this step.
Create a file named `cabal.project` containing:
```
packages: */*.cabal
```
(If you do this step without using [git] checkouts, you will get an error from
cabal in the next step. Simply remove `cabal.project` and try again.)
#### Install Everything
You'll need to update the cabal package index, build xmonad and xmonad-contrib
libraries and then build the xmonad binary:
``` console
$ cabal update
$ cabal install --package-env=$HOME/.config/xmonad --lib base xmonad xmonad-contrib
$ cabal install --package-env=$HOME/.config/xmonad xmonad
```
This will create a GHC environment in `~/.config/xmonad` so that the libraries
are available for recompilation of the config file, and also install the
xmonad binary to `~/.cabal/bin/xmonad`. Make sure you have that directory in
your `$PATH`!
If you're getting build failures while building the `X11` package it may
be that you don't have the required C libraries installed. See
[above](#dependencies).
## Make XMonad your window manager
This step varies depending on your distribution and X display manager (if
any).
#### Debian, Ubuntu
`/etc/X11/xinit/xinitrc` runs `/etc/X11/Xsession` which runs `~/.xsession`, so
you probably want to put `exec xmonad` there (don't forget the shebang and chmod).
(Tested with `startx`, `xdm`, `lightdm`.)
By using `~/.xsession`, the distro takes care of stuff like dbus, ssh-agent, X
resources, etc. If you want a completely manual X session, use `~/.xinitrc`
instead. Or invoke `startx`/`xinit` with an explicit path.
Some newer display managers require an entry in `/usr/share/xsessions`.
To use your custom `~/.xsession`, put these lines to
`/usr/share/xsessions/default.desktop`:
```
[Desktop Entry]
Name=Default X session
Type=Application
Exec=default
```
(Tested with `sddm`.)
#### Fedora
`/etc/X11/xinit/xinitrc` runs `~/.Xclients`, so you probably want to put `exec
xmonad` there (don't forget the shebang and chmod). Like in Debian, this can
be overridden by having a completely custom `~/.xinitrc` or passing arguments
to `startx`/`xinit`.
X display managers (e.g. `lightdm`) usually invoke `/etc/X11/xinit/Xsession`
instead, which additionally redirects output to `~/.xsession-errors` and also
tries `~/.xsession` before `~/.Xclients`.
Newer display managers require an entry in `/usr/share/xsessions`, which is
available in the `xorg-x11-xinit-session` package.
#### Arch
`/etc/X11/xinit/xinitrc` runs `twm`, `xclock` and 3 `xterm`s; users are
meant to just copy that to `~/.xinitrc` and
[customize](https://wiki.archlinux.org/title/Xinit#xinitrc) it: replace the
last few lines with `exec xmonad`.
Display managers like `lightdm` have their own `Xsession` script which invokes
`~/.xsession`. Other display managers need an entry in
`/usr/share/xsessions`, <https://aur.archlinux.org/packages/xinit-xsession/>
provides one.
#### See also
* <https://xmonad.org/documentation.html#in-your-environment>
* [FAQ: How can I use xmonad with a display manager? (xdm, kdm, gdm)](https://wiki.haskell.org/Xmonad/Frequently_asked_questions#How_can_I_use_xmonad_with_a_display_manager.3F_.28xdm.2C_kdm.2C_gdm.29)
## Custom Build Script
If you need to customize what happens during `xmonad --recompile` (bound to
`M-q` by default), perhaps because your xmonad configuration is a whole
separate Haskell package, you need to create a so-called `build` file. This
is quite literally just a shell script called `build` in your xmonad directory
(which is `~/.config/xmonad` for us) that tells xmonad how it should build its
executable.
A good starting point (this is essentially [what xmonad would do][]
without a build file, with the exception that we are invoking `stack
ghc` instead of plain `ghc`) would be
``` shell
#!/bin/sh
exec stack ghc -- \
--make xmonad.hs \
-i \
-ilib \
-fforce-recomp \
-main-is main \
-v0 \
-o "$1"
```
Don't forget to mark the file as `+x`: `chmod +x build`!
Some example build scripts for `stack` and `cabal` are provided in the
`xmonad-contrib` distribution. You can see those online in the
[scripts/build][] directory. You might wish to use these if you have
special dependencies for your `xmonad.hs`, especially with cabal as
you must use a cabal file and often a `cabal.project` to specify them;
`cabal install --lib` above generally isn't enough, and when it is
it can be difficult to keep track of when you want to replicate your
configuration on another system.
#### Don't Recompile on Every Startup
By default, xmonad always recompiles itself when a build script is used
(because the build script could contain arbitrary code, so a simple
check whether the `xmonad.hs` file changed is not enough). If you find
that too annoying, then you can use the `xmonad-ARCH` executable that
`xmonad --recompile` generates instead of `xmonad` in your startup. For
example, instead of writing
``` shell
exec xmonad
```
in your `~/.xinitrc`, you would write
``` shell
exec $HOME/.cache/xmonad/xmonad-x86_64-linux
```
The `~/.cache` prefix is the `$XDG_CACHE_HOME` directory. Note that
if your xmonad configuration resides within `~/.xmonad`, then the
executable will also be within that directory and not in
`$XDG_CACHE_HOME`.
[XDG]: https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
[git]: https://git-scm.com/
[stack]: https://docs.haskellstack.org/en/stable/README/
[cabal-install]: https://www.haskell.org/cabal/
[GHCup]: https://www.haskell.org/ghcup/
[survey]: https://taylor.fausak.me/2022/11/18/haskell-survey-results/
[widely available]: https://www.haskell.org/ghcup/install/#supported-platforms
[what xmonad would do]: https://github.com/xmonad/xmonad/blob/master/src/XMonad/Core.hs#L659-L667
[Hackage]: https://hackage.haskell.org/
[scripts/build]: https://github.com/xmonad/xmonad-contrib/blob/master/scripts/build

45
LICENSE
View File

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

View File

@ -2,82 +2,145 @@
## The XMonad Core Team
* Adam Vogt [GitHub][aavogt]
* Brandon S Allbery [GitHub][geekosaur], IRC: `geekosaur`
* Brandon S Allbery [GitHub][geekosaur], IRC: `geekosaur`, [GPG][gpg:geekosaur]
* Brent Yorgey [GitHub][byorgey], IRC: `byorgey`
* Daniel Wagner [GitHub][dmwit], IRC: `dmwit`
* Daniel Wagner [GitHub][dmwit], [Twitter][twitter:dmwit], IRC: `dmwit`
* David Lazar [GitHub][davidlazar]
* Sibi Prabakaran [GitHub][psibi], [Twitter][twitter:psibi], IRC: `sibi`
* Devin Mullins [GitHub][twifkak]
* Tomáš Janoušek [GitHub][liskin], [Twitter][twitter:liskin], IRC: `liskin`, [GPG][gpg:liskin]
* Peter J. Jones [GitHub][pjones], [Twitter][twitter:pjones], [OpenPGP Key][pgp:pjones], IRC: `pmade`
* Tony Zorman [GitHub][slotThe], IRC: `Solid`, [GPG][gpg:slotThe]
[geekosaur]: https://github.com/geekosaur
[byorgey]: https://github.com/byorgey
[dmwit]: https://github.com/dmwit
[psibi]: https://github.com/psibi
[liskin]: https://github.com/liskin
[slotThe]: https://github.com/slotThe
[gpg:geekosaur]: https://github.com/geekosaur.gpg
[gpg:liskin]: https://github.com/liskin.gpg
[gpg:slotThe]: https://github.com/slotThe.gpg
[twitter:dmwit]: https://twitter.com/dmwit13
[twitter:psibi]: https://twitter.com/psibi
[twitter:liskin]: https://twitter.com/Liskni_si
## Hall of Fame (past maintainers/developers)
* Adam Vogt [GitHub](https://github.com/aavogt)
* Peter Simons [GitHub](https://github.com/peti), [Twitter](https://twitter.com/OriginalPeti)
* Spencer Janssen [GitHub](https://github.com/spencerjanssen)
* Don Stewart [GitHub](https://github.com/donsbot), [Twitter](https://twitter.com/donsbot)
* Jason Creighton [GitHub](https://github.com/JasonCreighton)
* David Roundy [GitHub](https://github.com/droundy)
* Daniel Schoepe [GitHub](https://github.com/dschoepe)
* Eric Mertens [GitHub](https://github.com/glguy)
* Nicolas Pouillard [GitHub](https://github.com/np)
* Roman Cheplyaka [GitHub](https://github.com/UnkindPartition)
* Gwern Branwen [GitHub](https://github.com/gwern)
* Lukas Mai [GitHub](https://github.com/mauke)
* Braden Shepherdson [GitHub](https://github.com/shepheb)
* Devin Mullins [GitHub](https://github.com/twifkak)
* David Lazar [GitHub](https://github.com/davidlazar)
* Peter J. Jones [GitHub](https://github.com/pjones)
## Release Procedures
When the time comes to release another version of XMonad and Contrib...
When the time comes to release another version of xmonad and xmonad-contrib:
1. Create a release branch (e.g., `release-0.XX`).
1. Update the version number in all the `*.cabal` files and let the CI
verify that it all builds together.
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. Review documentation files and make sure they are accurate:
2. Update the version number in the `*.cabal` files and verify
dependencies and documentation. This includes the `tested-with:`
field.
- [`README.md`](README.md)
- [`CHANGES.md`](CHANGES.md) (bump version, set date)
- [`INSTALL.md`](INSTALL.md)
- [`man/xmonad.1.markdown.in`](man/xmonad.1.markdown.in)
- [haddocks](https://xmonad.github.io/xmonad-docs/)
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.
If the manpage changes, wait for the CI to rebuild the rendered outputs.
4. Review documentation files and make sure they are accurate:
3. Update the website:
- `README.md`
- `CHANGES.md`
- and the `example-config.hs` in the `xmonad-testing` repo
- Draft a [new release announcement][web-announce].
- Check install instructions, guided tour, keybindings cheat sheet, …
5. Generate the manpage:
4. Make sure that `tested-with:` covers several recent releases of GHC, that
`.github/workflows/haskell-ci.yml` had been updated to test all these GHC
versions and that `.github/workflows/stack.yml` tests with several recent
revisions of [Stackage][] LTS.
* `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`
5. Trigger the Haskell-CI workflow and fill in the candidate version number.
This will upload a release candidate to Hackage.
6. Tag the repository with the release version (e.g., `v0.13`)
- https://github.com/xmonad/xmonad/actions/workflows/haskell-ci.yml
- https://github.com/xmonad/xmonad-contrib/actions/workflows/haskell-ci.yml
7. Build the project tarballs (`cabal sdist`)
Check that everything looks good. If not, push fixes and do another
candidate. When everything's ready, create a release on GitHub:
8. Upload the packages to Hackage (`cabal upload`)
- https://github.com/xmonad/xmonad/releases/new
- https://github.com/xmonad/xmonad-contrib/releases/new
9. Merge the release branches into `master`
CI will automatically upload the final release to Hackage.
10. Update the website:
See [haskell-ci-hackage.patch][] for details about the Hackage automation.
* Generate and push haddocks with `xmonad-web/gen-docs.sh`
6. Post announcement to:
* Check that `tour.html` and `intro.html` are up to date, and
mention all core bindings
- [xmonad.org website](https://github.com/xmonad/xmonad-web/tree/gh-pages/news/_posts)
- [XMonad mailing list](https://mail.haskell.org/mailman/listinfo/xmonad)
- [Haskell Cafe](https://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe)
- [Haskell Discourse](https://discourse.haskell.org/)
- [Twitter](https://twitter.com/xmonad)
- [Reddit](https://www.reddit.com/r/xmonad/)
11. Update the topic for the IRC channel (`#xmonad`)
See [old announcements][old-announce] ([even older][older-announce]) for inspiration.
12. Send the `announce-0.XX.txt` file to:
7. Trigger xmonad-docs build to generate and persist docs for the just
released version:
- XMonad mailing list
- Haskell Cafe
- https://github.com/xmonad/xmonad-docs/actions/workflows/stack.yml
[packdeps]: http://hackage.haskell.org/package/packdeps
8. Bump version for development (add `.9`) and prepare fresh sections in
[`CHANGES.md`](CHANGES.md).
[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
[packdeps]: https://hackage.haskell.org/package/packdeps
[Stackage]: https://www.stackage.org/
[haskell-ci-hackage.patch]: .github/workflows/haskell-ci-hackage.patch
[web-announce]: https://github.com/xmonad/xmonad-web/tree/gh-pages/news/_posts
[old-announce]: https://github.com/xmonad/xmonad-web/blob/gh-pages/news/_posts/2021-10-27-xmonad-0-17-0.md
[older-announce]: https://github.com/xmonad/xmonad-web/tree/55614349421ebafaef4a47424fcb16efa80ff768
[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
## Website and Other Accounts
* The [xmonad twitter] is tended to by [liskin].
* The [xmonad.org] domain is owned by [eyenx] and the website itself is
deployed via GitHub Pages. It can be updated by making a pull request
against the [xmonad-web] repository.
[eyenx]: https://github.com/eyenx
[xmonad-web]: https://github.com/xmonad/xmonad-web/
[xmonad.org]: https://xmonad.org/
[xmonad twitter]: https://twitter.com/xmonad

179
README.md
View File

@ -1,8 +1,27 @@
# xmonad: A Tiling Window Manager
<p align="center">
<a href="https://xmonad.org/"><img alt="XMonad logo" src="https://xmonad.org/images/logo-wrapped.svg" height=150></a>
</p>
<p align="center">
<a href="https://hackage.haskell.org/package/xmonad"><img alt="Hackage" src="https://img.shields.io/hackage/v/xmonad?logo=haskell"></a>
<a href="https://github.com/xmonad/xmonad/blob/readme/LICENSE"><img alt="License" src="https://img.shields.io/github/license/xmonad/xmonad"></a>
<a href="https://haskell.org/"><img alt="Made in Haskell" src="https://img.shields.io/badge/Made%20in-Haskell-%235e5086?logo=haskell"></a>
<br>
<a href="https://github.com/xmonad/xmonad/actions/workflows/stack.yml"><img alt="Stack" src="https://img.shields.io/github/actions/workflow/status/xmonad/xmonad/stack.yml?label=Stack&logo=githubactions&logoColor=white"></a>
<a href="https://github.com/xmonad/xmonad/actions/workflows/haskell-ci.yml"><img alt="Cabal" src="https://img.shields.io/github/actions/workflow/status/xmonad/xmonad/haskell-ci.yml?label=Cabal&logo=githubactions&logoColor=white"></a>
<a href="https://github.com/xmonad/xmonad/actions/workflows/nix.yml"><img alt="Nix" src="https://img.shields.io/github/actions/workflow/status/xmonad/xmonad/nix.yml?label=Nix&logo=githubactions&logoColor=white"></a>
<br>
<a href="https://github.com/sponsors/xmonad"><img alt="GitHub Sponsors" src="https://img.shields.io/github/sponsors/xmonad?label=GitHub%20Sponsors&logo=githubsponsors"></a>
<a href="https://opencollective.com/xmonad"><img alt="Open Collective" src="https://img.shields.io/opencollective/all/xmonad?label=Open%20Collective&logo=opencollective"></a>
<br>
<a href="https://web.libera.chat/#xmonad"><img alt="Chat on #xmonad@irc.libera.chat" src="https://img.shields.io/badge/%23%20chat-on%20libera-brightgreen"></a>
<a href="https://matrix.to/#/#xmonad:matrix.org"><img alt="Chat on #xmonad:matrix.org" src="https://img.shields.io/matrix/xmonad:matrix.org?logo=matrix"></a>
</p>
[![Build Status](https://travis-ci.org/xmonad/xmonad.svg?branch=master)](https://travis-ci.org/xmonad/xmonad)
# xmonad
[xmonad][] is a tiling window manager for X. Windows are arranged
**A tiling window manager for X11.**
[XMonad][web:xmonad] is a tiling window manager for X11. Windows are arranged
automatically to tile the screen without gaps or overlap, maximising
screen use. Window manager features are accessible from the keyboard:
a mouse is optional. xmonad is written, configured and extensible in
@ -12,110 +31,74 @@ dynamically, and different layouts may be used on each
workspace. Xinerama is fully supported, allowing windows to be tiled
on several physical screens.
## Quick Start
This repository contains the [xmonad][hackage:xmonad] package, a minimal,
stable, yet extensible core. It is accompanied by
[xmonad-contrib][gh:xmonad-contrib], a library of hundreds of additional
community-maintained tiling algorithms and extension modules. The two combined
make for a powerful X11 window-manager with endless customization
possibilities. They are, quite literally, libraries for creating your own
window manager.
* From hackage:
## Installation
cabal update
cabal install xmonad xmonad-contrib
For installation and configuration instructions, please see:
* Alternatively, build from source using the following repositories:
* [downloading and installing xmonad][web:download]
* [installing latest xmonad snapshot from git][web:install]
* [configuring xmonad][web:tutorial]
- <https://github.com/xmonad/xmonad>
If you run into any trouble, consult our [documentation][web:documentation] or
ask the [community][web:community] for help.
- <https://github.com/xmonad/xmonad-contrib>
## Contributing
For the full story, read on.
We welcome all forms of contributions:
## Building
* [bug reports and feature ideas][gh:xmonad:issues]
(also to [xmonad-contrib][gh:xmonad-contrib:issues])
* [bug fixes, new features, new extensions][gh:xmonad:pulls]
(usually to [xmonad-contrib][gh:xmonad-contrib:pulls])
* documentation fixes and improvements: [xmonad][gh:xmonad],
[xmonad-contrib][gh:xmonad-contrib], [xmonad-web][gh:xmonad-web]
* helping others in the [community][web:community]
* financial support: [GitHub Sponsors][gh:xmonad:sponsors],
[Open Collective][opencollective:xmonad]
Building is quite straightforward, and requires a basic Haskell toolchain.
On many systems xmonad is available as a binary package in your
package system (e.g. on Debian or Gentoo). If at all possible, use this
in preference to a source build, as the dependency resolution will be
simpler.
We'll now walk through the complete list of toolchain dependencies.
* GHC: the Glasgow Haskell Compiler
You first need a Haskell compiler. Your distribution's package
system will have binaries of GHC (the Glasgow Haskell Compiler),
the compiler we use, so install that first. If your operating
system's package system doesn't provide a binary version of GHC
and the `cabal-install` tool, you can install both using the
[Haskell Platform][platform].
It shouldn't be necessary to compile GHC from source -- every common
system has a pre-build binary version. However, if you want to
build from source, the following links will be helpful:
- GHC: <http://haskell.org/ghc/>
- Cabal: <http://haskell.org/cabal/download.html>
* X11 libraries:
Since you're building an X application, you'll need the C X11
library headers. On many platforms, these come pre-installed. For
others, such as Debian, you can get them from your package manager:
$ apt-get install libx11-dev libxinerama-dev libxext-dev
## Running xmonad
If you built XMonad using `cabal` then add:
exec $HOME/.cabal/bin/xmonad
to the last line of your `.xsession` or `.xinitrc` file.
## Configuring
See the [CONFIG][] document and the [example configuration file][example-config].
## XMonadContrib
There are many extensions to xmonad available in the XMonadContrib
(xmc) library. Examples include an ion3-like tabbed layout, a
prompt/program launcher, and various other useful modules.
XMonadContrib is available at:
* Latest release: <http://hackage.haskell.org/package/xmonad-contrib>
* Git version: <https://github.com/xmonad/xmonad-contrib>
## Other Useful Programs
A nicer xterm replacement, that supports resizing better:
* urxvt: <http://software.schmorp.de/pkg/rxvt-unicode.html>
For custom status bars:
* xmobar: <http://hackage.haskell.org/package/xmobar>
* taffybar: <https://github.com/travitch/taffybar>
* dzen: <http://gotmor.googlepages.com/dzen>
For a program dispatch menu:
* [XMonad.Prompt.Shell][xmc-prompt-shell]: (from [XMonadContrib][])
* dmenu: <http://www.suckless.org/download/>
* gmrun: (in your package system)
Please do read the [CONTRIBUTING][gh:xmonad:contributing] document for more
information about bug reporting and code contributions. For a brief overview
of the architecture and code conventions, see the [documentation for the
`XMonad.Doc.Developing` module][doc:developing]. If in doubt, [talk to
us][web:community].
## Authors
* Spencer Janssen
* Don Stewart
* Jason Creighton
Started in 2007 by [Spencer Janssen][gh:spencerjanssen], [Don
Stewart][gh:donsbot] and [Jason Creighton][gh:JasonCreighton], the
[XMonad][web:xmonad] project lives on thanks to [new generations of
maintainers][gh:xmonad:maintainers] and [dozens of
contributors][gh:xmonad:contributors].
[xmonad]: http://xmonad.org
[xmonadcontrib]: https://hackage.haskell.org/package/xmonad-contrib
[xmc-prompt-shell]: https://hackage.haskell.org/package/xmonad-contrib/docs/XMonad-Prompt-Shell.html
[platform]: http://haskell.org/platform/
[example-config]: https://github.com/xmonad/xmonad-testing/blob/master/example-config.hs
[config]: https://github.com/xmonad/xmonad/blob/master/CONFIG
[gh:spencerjanssen]: https://github.com/spencerjanssen
[gh:donsbot]: https://github.com/donsbot
[gh:JasonCreighton]: https://github.com/JasonCreighton
[doc:developing]: https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Doc-Developing.html
[gh:xmonad-contrib:issues]: https://github.com/xmonad/xmonad-contrib/issues
[gh:xmonad-contrib:pulls]: https://github.com/xmonad/xmonad-contrib/pulls
[gh:xmonad-contrib]: https://github.com/xmonad/xmonad-contrib
[gh:xmonad-web]: https://github.com/xmonad/xmonad-web
[gh:xmonad:contributing]: https://github.com/xmonad/xmonad/blob/master/CONTRIBUTING.md
[gh:xmonad:contributors]: https://github.com/xmonad/xmonad/graphs/contributors
[gh:xmonad:issues]: https://github.com/xmonad/xmonad/issues
[gh:xmonad:maintainers]: https://github.com/xmonad/xmonad/blob/master/MAINTAINERS.md
[gh:xmonad:pulls]: https://github.com/xmonad/xmonad/pulls
[gh:xmonad:sponsors]: https://github.com/sponsors/xmonad
[gh:xmonad]: https://github.com/xmonad/xmonad
[hackage:xmonad]: https://hackage.haskell.org/package/xmonad
[opencollective:xmonad]: https://opencollective.com/xmonad
[web:community]: https://xmonad.org/community.html
[web:documentation]: https://xmonad.org/documentation.html
[web:download]: https://xmonad.org/download.html
[web:install]: https://xmonad.org/INSTALL.html
[web:tutorial]: https://xmonad.org/TUTORIAL.html
[web:xmonad]: https://xmonad.org/

22
STYLE
View File

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

1330
TUTORIAL.md Normal file

File diff suppressed because it is too large Load Diff

17
cabal.haskell-ci Normal file
View File

@ -0,0 +1,17 @@
apt:
libx11-dev
libxext-dev
libxinerama-dev
libxrandr-dev
libxss-dev
github-patches:
.github/workflows/haskell-ci-hackage.patch
raw-project
optimization: False
package xmonad
flags: +pedantic
-- avoid --haddock-all which overwrites *-docs.tar.gz with tests docs
haddock-components: libs

View File

@ -1 +1,4 @@
packages: ./
-- cabal.project
packages:
xmonad.cabal

106
flake.nix Normal file
View File

@ -0,0 +1,106 @@
# This file is maintained by @IvanMalison and @LSLeary (github)
# See xmonad-contrib/NIX.md for an overview of module usage.
{
inputs = {
flake-utils.url = "github:numtide/flake-utils";
git-ignore-nix.url = "github:hercules-ci/gitignore.nix/master";
unstable.url = "github:NixOS/nixpkgs/nixos-unstable";
};
outputs = { self, flake-utils, nixpkgs, unstable, git-ignore-nix }:
let
hpath = { prefix ? null, compiler ? null }:
(if prefix == null then [] else [ prefix ]) ++
(if compiler == null
then [ "haskellPackages" ]
else [ "haskell" "packages" compiler ]
);
fromHOL = hol: comp: final: prev: with prev.lib; with attrsets;
let
path = hpath comp;
root = head path;
branch = tail path;
hpkgs' = (getAttrFromPath path prev).override (old: {
overrides = composeExtensions (old.overrides or (_: _: {}))
(hol final prev);
});
in {
${root} = recursiveUpdate prev.${root} (setAttrByPath branch hpkgs');
};
hoverlay = final: prev: hself: hsuper:
with prev.haskell.lib.compose; {
xmonad = hself.callCabal2nix "xmonad"
(git-ignore-nix.lib.gitignoreSource ./.) { };
};
defComp = if builtins.pathExists ./comp.nix
then import ./comp.nix
else { };
overlay = fromHOL hoverlay defComp;
overlays = [ overlay ];
nixosModule = { config, pkgs, lib, ... }: with lib; with attrsets;
let
cfg = config.services.xserver.windowManager.xmonad.flake;
comp = { inherit (cfg) prefix compiler; };
in {
options = {
services.xserver.windowManager.xmonad.flake = with types; {
enable = mkEnableOption "flake";
prefix = mkOption {
default = null;
type = nullOr str;
example = literalExpression "\"unstable\"";
description = ''
Specify a nested alternative <literal>pkgs</literal> by attrName.
'';
};
compiler = mkOption {
default = null;
type = nullOr str;
example = literalExpression "\"ghc922\"";
description = ''
Which compiler to build xmonad with.
Must be an attribute of <literal>pkgs.haskell.packages</literal>.
Sets <option>xmonad.haskellPackages</option> to match.
'';
};
};
};
config = mkIf cfg.enable {
nixpkgs.overlays = [ (fromHOL hoverlay comp) ];
services.xserver.windowManager.xmonad.haskellPackages =
getAttrFromPath (hpath comp) pkgs;
};
};
nixosModules = [ nixosModule ];
in flake-utils.lib.eachDefaultSystem (system:
let pkgs = import nixpkgs { inherit system overlays; };
hpkg = pkgs.lib.attrsets.getAttrFromPath (hpath defComp) pkgs;
modifyDevShell =
if builtins.pathExists ./develop.nix
then import ./develop.nix
else _: x: x;
in
rec {
devShell = hpkg.shellFor (modifyDevShell pkgs {
packages = p: [ p.xmonad ];
});
defaultPackage = hpkg.xmonad;
# An auxiliary NixOS module that modernises the standard xmonad NixOS module
# and wrapper script used, replacing them with versions from unstable.
# Currently, due to the NIX_GHC --> XMONAD_GHC env var change, this is
# necessary in order for Mod-q recompilation to work out-of-the-box.
modernise =
let
xmonadModFile = "services/x11/window-managers/xmonad.nix";
unpkgs = import unstable { inherit system; };
replaceWrapper = _: _:
{ xmonad-with-packages = unpkgs.xmonad-with-packages; };
in {
disabledModules = [ xmonadModFile ];
imports = [ (unstable + "/nixos/modules/" + xmonadModFile) ];
nixpkgs.overlays = [ replaceWrapper ];
};
}) // {
inherit hoverlay overlay overlays nixosModule nixosModules;
lib = { inherit hpath fromHOL; };
};
}

11
man/Makefile Normal file
View File

@ -0,0 +1,11 @@
.PHONY: all
all: xmonad.1 xmonad.1.html
xmonad.1.markdown: xmonad.1.markdown.in
(cd .. && util/GenerateManpage.hs) <$< >$@
xmonad.1: xmonad.1.markdown
pandoc --from=markdown --to=man --standalone --output=$@ $<
xmonad.1.html: xmonad.1.markdown
pandoc --from=markdown --to=html --standalone --table-of-contents --output=$@ $<

View File

@ -1,13 +1,27 @@
.TH xmonad 1 "31 December 2012" xmonad-0.13 "xmonad manual".\" Automatically generated by Pandoc 1.19.2.1
.\" Automatically generated by Pandoc 3.1.3
.\"
.TH "" "" "" "" ""
.\" Define V font for inline verbatim, using C font in formats
.\" that render this, and otherwise B font.
.ie "\f[CB]x\f[]"x" \{\
. ftr V B
. ftr VI BI
. ftr VB B
. ftr VBI BI
.\}
.el \{\
. ftr V CR
. ftr VI CI
. ftr VB CB
. ftr VBI CBI
.\}
.TH "XMONAD" "1" "27 October 2021" "Tiling Window Manager" ""
.hy
.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
\f[I]xmonad\f[R] is a minimalist tiling window manager for X, written in
Haskell.
Windows are managed using automatic layout algorithms, which can be
dynamically reconfigured.
@ -15,14 +29,14 @@ At any time windows are arranged so as to maximize the use of screen
real estate.
All features of the window manager are accessible purely from the
keyboard: a mouse is entirely optional.
\f[I]xmonad\f[] is configured in Haskell, and custom layout algorithms
\f[I]xmonad\f[R] is configured in Haskell, and custom layout algorithms
may be implemented by the user in config files.
A principle of \f[I]xmonad\f[] is predictability: the user should know
A principle of \f[I]xmonad\f[R] is predictability: the user should know
in advance precisely the window arrangement that will result from any
action.
.PP
By default, \f[I]xmonad\f[] provides three layout algorithms: tall, wide
and fullscreen.
By default, \f[I]xmonad\f[R] 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
@ -31,34 +45,34 @@ Multiple physical monitors are supported via Xinerama, allowing
simultaneous display of a number of screens.
.PP
By utilizing the expressivity of a modern functional language with a
rich static type system, \f[I]xmonad\f[] provides a complete, featureful
window manager in less than 1200 lines of code, with an emphasis on
correctness and robustness.
rich static type system, \f[I]xmonad\f[R] 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.
type-based automated testing.
A benefit of this is that the code is simple to understand, and easy to
modify.
.SH Usage
.PP
\f[I]xmonad\f[] places each window into a "workspace".
\f[I]xmonad\f[R] 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.
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
You can toggle the layout mode with mod-space, which will cycle through
the available modes.
.PP
You can switch to workspace N with mod\-N.
For example, to switch to workspace 5, you would press mod\-5.
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.
mod-shift-N.
.PP
When running with multiple monitors (Xinerama), each screen has exactly
1 workspace visible.
mod\-{w,e,r} switch the focus between screens, while shift\-mod\-{w,e,r}
mod-{w,e,r} switch the focus between screens, while shift-mod-{w,e,r}
move the current window to that screen.
When \f[I]xmonad\f[] starts, workspace 1 is on screen 1, workspace 2 is
When \f[I]xmonad\f[R] 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.
@ -67,214 +81,159 @@ and visible workspaces are swapped.
xmonad has several flags which you may pass to the executable.
These flags are:
.TP
.B \-\-recompile
Recompiles your configuration in \f[I]~/.xmonad/xmonad.hs\f[]
.RS
.RE
\[en]recompile
Recompiles your \f[I]xmonad.hs\f[R] configuration
.TP
.B \-\-restart
Causes the currently running \f[I]xmonad\f[] process to restart
.RS
.RE
\[en]restart
Causes the currently running \f[I]xmonad\f[R] process to restart
.TP
.B \-\-replace
\[en]replace
Replace the current window manager with xmonad
.RS
.RE
.TP
.B \-\-version
Display version of \f[I]xmonad\f[]
.RS
.RE
\[en]version
Display version of \f[I]xmonad\f[R]
.TP
.B \-\-verbose\-version
Display detailed version of \f[I]xmonad\f[]
.RS
.RE
\[en]verbose-version
Display detailed version of \f[I]xmonad\f[R]
.SS Default keyboard bindings
.TP
.B mod\-shift\-return
mod-shift-return
Launch terminal
.RS
.RE
.TP
.B mod\-p
mod-p
Launch dmenu
.RS
.RE
.TP
.B mod\-shift\-p
mod-shift-p
Launch gmrun
.RS
.RE
.TP
.B mod\-shift\-c
mod-shift-c
Close the focused window
.RS
.RE
.TP
.B mod\-space
mod-space
Rotate through the available layout algorithms
.RS
.RE
.TP
.B mod\-shift\-space
mod-shift-space
Reset the layouts on the current workspace to default
.RS
.RE
.TP
.B mod\-n
mod-n
Resize viewed windows to the correct size
.RS
.RE
.TP
.B mod\-tab
mod-tab
Move focus to the next window
.RS
.RE
.TP
.B mod\-shift\-tab
mod-shift-tab
Move focus to the previous window
.RS
.RE
.TP
.B mod\-j
mod-j
Move focus to the next window
.RS
.RE
.TP
.B mod\-k
mod-k
Move focus to the previous window
.RS
.RE
.TP
.B mod\-m
mod-m
Move focus to the master window
.RS
.RE
.TP
.B mod\-return
mod-return
Swap the focused window and the master window
.RS
.RE
.TP
.B mod\-shift\-j
mod-shift-j
Swap the focused window with the next window
.RS
.RE
.TP
.B mod\-shift\-k
mod-shift-k
Swap the focused window with the previous window
.RS
.RE
.TP
.B mod\-h
mod-h
Shrink the master area
.RS
.RE
.TP
.B mod\-l
mod-l
Expand the master area
.RS
.RE
.TP
.B mod\-t
mod-t
Push window back into tiling
.RS
.RE
.TP
.B mod\-comma
mod-comma
Increment the number of windows in the master area
.RS
.RE
.TP
.B mod\-period
mod-period
Deincrement the number of windows in the master area
.RS
.RE
.TP
.B mod\-shift\-q
mod-shift-q
Quit xmonad
.RS
.RE
.TP
.B mod\-q
mod-q
Restart xmonad
.RS
.RE
.TP
.B mod\-shift\-slash
mod-shift-slash
Run xmessage with a summary of the default keybindings (useful for
beginners)
.RS
.RE
.TP
.B mod\-[1..9]
mod-question
Run xmessage with a summary of the default keybindings (useful for
beginners)
.TP
mod-[1..9]
Switch to workspace N
.RS
.RE
.TP
.B mod\-shift\-[1..9]
mod-shift-[1..9]
Move client to workspace N
.RS
.RE
.TP
.B mod\-{w,e,r}
mod-{w,e,r}
Switch to physical/Xinerama screens 1, 2, or 3
.RS
.RE
.TP
.B mod\-shift\-{w,e,r}
mod-shift-{w,e,r}
Move client to screen 1, 2, or 3
.RS
.RE
.TP
.B mod\-button1
mod-button1
Set the window to floating mode and move by dragging
.RS
.RE
.TP
.B mod\-button2
mod-button2
Raise the window to the top of the stack
.RS
.RE
.TP
.B mod\-button3
mod-button3
Set the window to floating mode and resize by dragging
.RS
.RE
.SH Examples
.PP
To use xmonad as your window manager add to your \f[I]~/.xinitrc\f[]
file:
To use xmonad as your window manager add to your
\f[I]\[ti]/.xinitrc\f[R] file:
.RS
.PP
exec xmonad
.RE
.SH Customization
.PP
xmonad is customized in ~/.xmonad/xmonad.hs, and then restarted with
mod\-q.
xmonad is customized in your \f[I]xmonad.hs\f[R], and then restarted
with mod-q.
You can choose where your configuration file lives by
.IP "1." 3
Setting \f[V]XMONAD_DATA_DIR,\f[R] \f[V]XMONAD_CONFIG_DIR\f[R], and
\f[V]XMONAD_CACHE_DIR\f[R]; \f[I]xmonad.hs\f[R] is then expected to be
in \f[V]XMONAD_CONFIG_DIR\f[R].
.IP "2." 3
Creating \f[I]xmonad.hs\f[R] in \f[I]\[ti]/.xmonad\f[R].
.IP "3." 3
Creating \f[I]xmonad.hs\f[R] in \f[V]XDG_CONFIG_HOME\f[R].
Note that, in this case, xmonad will use \f[V]XDG_DATA_HOME\f[R] and
\f[V]XDG_CACHE_HOME\f[R] for its data and cache directory respectively.
.PP
You can find many extensions to the core feature set in the xmonad\-
You can find many extensions to the core feature set in the xmonad-
contrib package, available through your package manager or from
xmonad.org (http://xmonad.org).
xmonad.org (https://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.
As of \f[I]xmonad-0.9\f[R], any additional Haskell modules may be placed
in \f[I]\[ti]/.xmonad/lib/\f[R] are available in GHC\[cq]s searchpath.
Hierarchical modules are supported: for example, the file
\f[I]~/.xmonad/lib/XMonad/Stack/MyAdditions.hs\f[] could contain:
\f[I]\[ti]/.xmonad/lib/XMonad/Stack/MyAdditions.hs\f[R] could contain:
.IP
.nf
\f[C]
module\ XMonad.Stack.MyAdditions\ (function1)\ where
\ \ function1\ =\ error\ "function1:\ Not\ implemented\ yet!"
\f[]
module XMonad.Stack.MyAdditions (function1) where
function1 = error \[dq]function1: Not implemented yet!\[dq]
\f[R]
.fi
.PP
Your xmonad.hs may then import XMonad.Stack.MyAdditions as if that
module was contained within xmonad or xmonad\-contrib.
module was contained within xmonad or xmonad-contrib.
.SH Bugs
.PP
Probably.

View File

@ -1,165 +1,490 @@
<!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="2021-10-27" />
<title>XMONAD(1) Tiling Window Manager</title>
<style>
html {
color: #1a1a1a;
background-color: #fdfdfd;
}
body {
margin: 0 auto;
max-width: 36em;
padding-left: 50px;
padding-right: 50px;
padding-top: 50px;
padding-bottom: 50px;
hyphens: auto;
overflow-wrap: break-word;
text-rendering: optimizeLegibility;
font-kerning: normal;
}
@media (max-width: 600px) {
body {
font-size: 0.9em;
padding: 12px;
}
h1 {
font-size: 1.8em;
}
}
@media print {
html {
background-color: white;
}
body {
background-color: transparent;
color: black;
font-size: 12pt;
}
p, h2, h3 {
orphans: 3;
widows: 3;
}
h2, h3, h4 {
page-break-after: avoid;
}
}
p {
margin: 1em 0;
}
a {
color: #1a1a1a;
}
a:visited {
color: #1a1a1a;
}
img {
max-width: 100%;
}
h1, h2, h3, h4, h5, h6 {
margin-top: 1.4em;
}
h5, h6 {
font-size: 1em;
font-style: italic;
}
h6 {
font-weight: normal;
}
ol, ul {
padding-left: 1.7em;
margin-top: 1em;
}
li > ol, li > ul {
margin-top: 0;
}
blockquote {
margin: 1em 0 1em 1.7em;
padding-left: 1em;
border-left: 2px solid #e6e6e6;
color: #606060;
}
code {
font-family: Menlo, Monaco, Consolas, 'Lucida Console', monospace;
font-size: 85%;
margin: 0;
hyphens: manual;
}
pre {
margin: 1em 0;
overflow: auto;
}
pre code {
padding: 0;
overflow: visible;
overflow-wrap: normal;
}
.sourceCode {
background-color: transparent;
overflow: visible;
}
hr {
background-color: #1a1a1a;
border: none;
height: 1px;
margin: 1em 0;
}
table {
margin: 1em 0;
border-collapse: collapse;
width: 100%;
overflow-x: auto;
display: block;
font-variant-numeric: lining-nums tabular-nums;
}
table caption {
margin-bottom: 0.75em;
}
tbody {
margin-top: 0.5em;
border-top: 1px solid #1a1a1a;
border-bottom: 1px solid #1a1a1a;
}
th {
border-top: 1px solid #1a1a1a;
padding: 0.25em 0.5em 0.25em 0.5em;
}
td {
padding: 0.125em 0.5em 0.25em 0.5em;
}
header {
margin-bottom: 4em;
text-align: center;
}
#TOC li {
list-style: none;
}
#TOC ul {
padding-left: 1.3em;
}
#TOC > ul {
padding-left: 0;
}
#TOC a:not(:hover) {
text-decoration: none;
}
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
div.columns{display: flex; gap: min(4vw, 1.5em);}
div.column{flex: auto; overflow-x: auto;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
/* The extra [class] is a hack that increases specificity enough to
override a similar rule in reveal.js */
ul.task-list[class]{list-style: none;}
ul.task-list li input[type="checkbox"] {
font-size: inherit;
width: 0.8em;
margin: 0 0.8em 0.2em -1.6em;
vertical-align: middle;
}
.display.math{display: block; text-align: center; margin: 0.5rem auto;}
/* CSS for syntax highlighting */
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; }
.sourceCode { overflow: visible; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
{ counter-reset: source-line 0; }
pre.numberSource code > span
{ position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::before
{ content: counter(source-line);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; 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 {
pre > code.sourceCode > span > a:first-child::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 { color: #008000; } /* 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 { color: #008000; font-weight: bold; } /* 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>
</head>
<body>
<h1>xmonad-0.13</h1><p>Section: xmonad manual (1)<br/>Updated: 31 December 2012</p><hr/>
<div id="TOC">
<header id="title-block-header">
<h1 class="title">XMONAD(1) Tiling Window Manager</h1>
<p class="author"></p>
<p class="date">27 October 2021</p>
</header>
<nav id="TOC" role="doc-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>
<li><a href="#name" id="toc-name">Name</a></li>
<li><a href="#description" id="toc-description">Description</a></li>
<li><a href="#usage" id="toc-usage">Usage</a>
<ul>
<li><a href="#flags" id="toc-flags">Flags</a></li>
<li><a href="#default-keyboard-bindings"
id="toc-default-keyboard-bindings">Default keyboard bindings</a></li>
</ul></li>
<li><a href="#examples">Examples</a></li>
<li><a href="#customization">Customization</a><ul>
<li><a href="#modular-configuration">Modular Configuration</a></li>
<li><a href="#examples" id="toc-examples">Examples</a></li>
<li><a href="#customization" id="toc-customization">Customization</a>
<ul>
<li><a href="#modular-configuration"
id="toc-modular-configuration">Modular Configuration</a></li>
</ul></li>
<li><a href="#bugs">Bugs</a></li>
<li><a href="#bugs" id="toc-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>
<p><em>xmonad</em> is a minimalist tiling window manager for X, written
in Haskell. Windows are managed using automatic layout algorithms, which
can be dynamically reconfigured. At any time windows are arranged so as
to maximize the use of screen real estate. All features of the window
manager are accessible purely from the keyboard: a mouse is entirely
optional. <em>xmonad</em> is configured in Haskell, and custom layout
algorithms may be implemented by the user in config files. A principle
of <em>xmonad</em> is predictability: the user should know in advance
precisely the window arrangement that will result from any action.</p>
<p>By default, <em>xmonad</em> provides three layout algorithms: tall,
wide and fullscreen. In tall or wide mode, windows are tiled and
arranged to prevent overlap and maximize screen use. Sets of windows are
grouped together on virtual screens, and each screen retains its own
layout, which may be reconfigured dynamically. Multiple physical
monitors are supported via Xinerama, allowing simultaneous display of a
number of screens.</p>
<p>By utilizing the expressivity of a modern functional language with a
rich static type system, <em>xmonad</em> provides a complete, featureful
window manager in less than 1200 lines of code, with an emphasis on
correctness and robustness. Internal properties of the window manager
are checked using a combination of static guarantees provided by the
type system, and type-based automated testing. A benefit of this is that
the code is simple to understand, and easy to modify.</p>
<h1 id="usage">Usage</h1>
<p><em>xmonad</em> places each window into a &quot;workspace&quot;. Each workspace can have any number of windows, which you can cycle though with mod-j and mod-k. Windows are either displayed full screen, tiled horizontally, or tiled vertically. You can toggle the layout mode with mod-space, which will cycle through the available modes.</p>
<p>You can switch to workspace N with mod-N. For example, to switch to workspace 5, you would press mod-5. Similarly, you can move the current window to another workspace with mod-shift-N.</p>
<p>When running with multiple monitors (Xinerama), each screen has exactly 1 workspace visible. mod-{w,e,r} switch the focus between screens, while shift-mod-{w,e,r} move the current window to that screen. When <em>xmonad</em> starts, workspace 1 is on screen 1, workspace 2 is on screen 2, etc. When switching workspaces to one that is already visible, the current and visible workspaces are swapped.</p>
<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>
<p>xmonad has several flags which you may pass to the executable. These
flags are:</p>
<dl>
<dt>--recompile</dt>
<dd>Recompiles your configuration in <em>~/.xmonad/xmonad.hs</em>
<dt>recompile</dt>
<dd>
Recompiles your <em>xmonad.hs</em> configuration
</dd>
<dt>--restart</dt>
<dd>Causes the currently running <em>xmonad</em> process to restart
<dt>restart</dt>
<dd>
Causes the currently running <em>xmonad</em> process to restart
</dd>
<dt>--replace</dt>
<dd>Replace the current window manager with xmonad
<dt>replace</dt>
<dd>
Replace the current window manager with xmonad
</dd>
<dt>--version</dt>
<dd>Display version of <em>xmonad</em>
<dt>version</dt>
<dd>
Display version of <em>xmonad</em>
</dd>
<dt>--verbose-version</dt>
<dd>Display detailed version of <em>xmonad</em>
<dt>verbose-version</dt>
<dd>
Display detailed version of <em>xmonad</em>
</dd>
</dl>
<h2 id="default-keyboard-bindings">Default keyboard bindings</h2>
<dl>
<dt>mod-shift-return</dt>
<dd>Launch terminal
<dd>
Launch terminal
</dd>
<dt>mod-p</dt>
<dd>Launch dmenu
<dd>
Launch dmenu
</dd>
<dt>mod-shift-p</dt>
<dd>Launch gmrun
<dd>
Launch gmrun
</dd>
<dt>mod-shift-c</dt>
<dd>Close the focused window
<dd>
Close the focused window
</dd>
<dt>mod-space</dt>
<dd>Rotate through the available layout algorithms
<dd>
Rotate through the available layout algorithms
</dd>
<dt>mod-shift-space</dt>
<dd>Reset the layouts on the current workspace to default
<dd>
Reset the layouts on the current workspace to default
</dd>
<dt>mod-n</dt>
<dd>Resize viewed windows to the correct size
<dd>
Resize viewed windows to the correct size
</dd>
<dt>mod-tab</dt>
<dd>Move focus to the next window
<dd>
Move focus to the next window
</dd>
<dt>mod-shift-tab</dt>
<dd>Move focus to the previous window
<dd>
Move focus to the previous window
</dd>
<dt>mod-j</dt>
<dd>Move focus to the next window
<dd>
Move focus to the next window
</dd>
<dt>mod-k</dt>
<dd>Move focus to the previous window
<dd>
Move focus to the previous window
</dd>
<dt>mod-m</dt>
<dd>Move focus to the master window
<dd>
Move focus to the master window
</dd>
<dt>mod-return</dt>
<dd>Swap the focused window and the master window
<dd>
Swap the focused window and the master window
</dd>
<dt>mod-shift-j</dt>
<dd>Swap the focused window with the next window
<dd>
Swap the focused window with the next window
</dd>
<dt>mod-shift-k</dt>
<dd>Swap the focused window with the previous window
<dd>
Swap the focused window with the previous window
</dd>
<dt>mod-h</dt>
<dd>Shrink the master area
<dd>
Shrink the master area
</dd>
<dt>mod-l</dt>
<dd>Expand the master area
<dd>
Expand the master area
</dd>
<dt>mod-t</dt>
<dd>Push window back into tiling
<dd>
Push window back into tiling
</dd>
<dt>mod-comma</dt>
<dd>Increment the number of windows in the master area
<dd>
Increment the number of windows in the master area
</dd>
<dt>mod-period</dt>
<dd>Deincrement the number of windows in the master area
<dd>
Deincrement the number of windows in the master area
</dd>
<dt>mod-shift-q</dt>
<dd>Quit xmonad
<dd>
Quit xmonad
</dd>
<dt>mod-q</dt>
<dd>Restart xmonad
<dd>
Restart xmonad
</dd>
<dt>mod-shift-slash</dt>
<dd>Run xmessage with a summary of the default keybindings (useful for beginners)
<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>
Switch to workspace N
</dd>
<dt>mod-shift-[1..9]</dt>
<dd>Move client to workspace N
<dd>
Move client to workspace N
</dd>
<dt>mod-{w,e,r}</dt>
<dd>Switch to physical/Xinerama screens 1, 2, or 3
<dd>
Switch to physical/Xinerama screens 1, 2, or 3
</dd>
<dt>mod-shift-{w,e,r}</dt>
<dd>Move client to screen 1, 2, or 3
<dd>
Move client to screen 1, 2, or 3
</dd>
<dt>mod-button1</dt>
<dd>Set the window to floating mode and move by dragging
<dd>
Set the window to floating mode and move by dragging
</dd>
<dt>mod-button2</dt>
<dd>Raise the window to the top of the stack
<dd>
Raise the window to the top of the stack
</dd>
<dt>mod-button3</dt>
<dd>Set the window to floating mode and resize by dragging
<dd>
Set the window to floating mode and resize by dragging
</dd>
</dl>
<h1 id="examples">Examples</h1>
<p>To use xmonad as your window manager add to your <em>~/.xinitrc</em> file:</p>
<p>To use xmonad as your window manager add to your <em>~/.xinitrc</em>
file:</p>
<blockquote>
<p>exec xmonad</p>
</blockquote>
<h1 id="customization">Customization</h1>
<p>xmonad is customized in ~/.xmonad/xmonad.hs, and then restarted with mod-q.</p>
<p>You can find many extensions to the core feature set in the xmonad- contrib package, available through your package manager or from <a href="http://xmonad.org">xmonad.org</a>.</p>
<p>xmonad is customized in your <em>xmonad.hs</em>, and then restarted
with mod-q. You can choose where your configuration file lives by</p>
<ol type="1">
<li>Setting <code>XMONAD_DATA_DIR,</code>
<code>XMONAD_CONFIG_DIR</code>, and <code>XMONAD_CACHE_DIR</code>;
<em>xmonad.hs</em> is then expected to be in
<code>XMONAD_CONFIG_DIR</code>.</li>
<li>Creating <em>xmonad.hs</em> in <em>~/.xmonad</em>.</li>
<li>Creating <em>xmonad.hs</em> in <code>XDG_CONFIG_HOME</code>. Note
that, in this case, xmonad will use <code>XDG_DATA_HOME</code> and
<code>XDG_CACHE_HOME</code> for its data and cache directory
respectively.</li>
</ol>
<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="https://xmonad.org">xmonad.org</a>.</p>
<h2 id="modular-configuration">Modular Configuration</h2>
<p>As of <em>xmonad-0.9</em>, any additional Haskell modules may be placed in <em>~/.xmonad/lib/</em> are available in GHC's searchpath. Hierarchical modules are supported: for example, the file <em>~/.xmonad/lib/XMonad/Stack/MyAdditions.hs</em> could contain:</p>
<pre class="haskell"><code>module XMonad.Stack.MyAdditions (function1) where
function1 = error &quot;function1: Not implemented yet!&quot;</code></pre>
<p>Your xmonad.hs may then import XMonad.Stack.MyAdditions as if that module was contained within xmonad or xmonad-contrib.</p>
<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"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">module</span> <span class="dt">XMonad.Stack.MyAdditions</span> (function1) <span class="kw">where</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a> function1 <span class="ot">=</span> <span class="fu">error</span> <span class="st">&quot;function1: Not implemented yet!&quot;</span></span></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>
<p>Probably. If you find any, please report them to the <a
href="https://github.com/xmonad/xmonad/issues">bugtracker</a></p>
</body>
</html>

View File

@ -1,7 +1,12 @@
#Name
xmonad - a tiling window manager
% XMONAD(1) Tiling Window Manager
%
% 27 October 2021
#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,12 +52,13 @@ 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:
--recompile
: Recompiles your configuration in _~/.xmonad/xmonad.hs_
: Recompiles your _xmonad.hs_ configuration
--restart
: Causes the currently running _xmonad_ process to restart
@ -66,24 +72,124 @@ These flags are:
--verbose-version
: Display detailed version of _xmonad_
##Default keyboard bindings
## Default keyboard bindings
___KEYBINDINGS___
mod-shift-return
: Launch terminal
mod-p
: Launch dmenu
mod-shift-p
: Launch gmrun
mod-shift-c
: Close the focused window
mod-space
: Rotate through the available layout algorithms
mod-shift-space
: Reset the layouts on the current workspace to default
mod-n
: Resize viewed windows to the correct size
mod-tab
: Move focus to the next window
mod-shift-tab
: Move focus to the previous window
mod-j
: Move focus to the next window
mod-k
: Move focus to the previous window
mod-m
: Move focus to the master window
mod-return
: Swap the focused window and the master window
mod-shift-j
: Swap the focused window with the next window
mod-shift-k
: Swap the focused window with the previous window
mod-h
: Shrink the master area
mod-l
: Expand the master area
mod-t
: Push window back into tiling
mod-comma
: Increment the number of windows in the master area
mod-period
: Deincrement the number of windows in the master area
mod-shift-q
: Quit xmonad
mod-q
: Restart xmonad
mod-shift-slash
: Run xmessage with a summary of the default keybindings (useful for beginners)
mod-question
: Run xmessage with a summary of the default keybindings (useful for beginners)
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
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
# Examples
#Examples
To use xmonad as your window manager add to your _~/.xinitrc_ file:
> exec xmonad
#Customization
xmonad is customized in ~/.xmonad/xmonad.hs, and then restarted
with mod-q.
# Customization
xmonad is customized in your _xmonad.hs_, and then restarted with mod-q.
You can choose where your configuration file lives by
1. Setting `XMONAD_DATA_DIR,` `XMONAD_CONFIG_DIR`, and
`XMONAD_CACHE_DIR`; _xmonad.hs_ is then expected to be in
`XMONAD_CONFIG_DIR`.
2. Creating _xmonad.hs_ in _~/.xmonad_.
3. Creating _xmonad.hs_ in `XDG_CONFIG_HOME`. Note that, in this
case, xmonad will use `XDG_DATA_HOME` and `XDG_CACHE_HOME` for its
data and cache directory respectively.
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,8 +203,8 @@ 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
[xmonad.org]: https://xmonad.org
[bugtracker]: https://github.com/xmonad/xmonad/issues

119
man/xmonad.1.markdown.in Normal file
View File

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

View File

@ -123,13 +123,13 @@ myKeys conf@(XConfig {XMonad.modMask = modm}) = M.fromList $
-- , ((modm , xK_b ), sendMessage ToggleStruts)
-- Quit xmonad
, ((modm .|. shiftMask, xK_q ), io (exitWith ExitSuccess))
, ((modm .|. shiftMask, xK_q ), io exitSuccess)
-- Restart xmonad
, ((modm , xK_q ), spawn "xmonad --recompile; xmonad --restart")
-- Run xmessage with a summary of the default keybindings (useful for beginners)
, ((modm .|. shiftMask, xK_slash ), spawn ("echo \"" ++ help ++ "\" | xmessage -file -"))
, ((modm .|. shiftMask, xK_slash ), xmessage help)
]
++
@ -154,18 +154,18 @@ myKeys conf@(XConfig {XMonad.modMask = modm}) = M.fromList $
------------------------------------------------------------------------
-- Mouse bindings: default actions bound to mouse events
--
myMouseBindings (XConfig {XMonad.modMask = modm}) = M.fromList $
myMouseBindings (XConfig {XMonad.modMask = modm}) = M.fromList
-- mod-button1, Set the window to floating mode and move by dragging
[ ((modm, button1), (\w -> focus w >> mouseMoveWindow w
>> windows W.shiftMaster))
[ ((modm, button1), \w -> focus w >> mouseMoveWindow w
>> windows W.shiftMaster)
-- mod-button2, Raise the window to the top of the stack
, ((modm, button2), (\w -> focus w >> windows W.shiftMaster))
, ((modm, button2), \w -> focus w >> windows W.shiftMaster)
-- mod-button3, Set the window to floating mode and resize by dragging
, ((modm, button3), (\w -> focus w >> mouseResizeWindow w
>> windows W.shiftMaster))
, ((modm, button3), \w -> focus w >> mouseResizeWindow w
>> windows W.shiftMaster)
-- you may also bind events to the mouse scroll wheel (button4 and button5)
]
@ -293,6 +293,7 @@ help = unlines ["The default modifier key is 'alt'. Default keybindings:",
"mod-Space Rotate through the available layout algorithms",
"mod-Shift-Space Reset the layouts on the current workSpace to default",
"mod-n Resize/refresh viewed windows to the correct size",
"mod-Shift-/ Show this help message with the default keybindings",
"",
"-- move focus up or down the window stack",
"mod-Tab Move focus to the next window",

View File

@ -1,5 +1,6 @@
{-# OPTIONS_GHC -fno-warn-missing-signatures -fno-warn-orphans #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Config
@ -39,7 +40,7 @@ import XMonad.Operations
import XMonad.ManageHook
import qualified XMonad.StackSet as W
import Data.Bits ((.|.))
import Data.Default
import Data.Default.Class
import Data.Monoid
import qualified Data.Map as M
import System.Exit
@ -218,12 +219,12 @@ keys conf@(XConfig {XMonad.modMask = modMask}) = M.fromList $
, ((modMask , xK_period), sendMessage (IncMasterN (-1))) -- %! Deincrement the number of windows in the master area
-- quit, or restart
, ((modMask .|. shiftMask, xK_q ), io (exitWith ExitSuccess)) -- %! Quit xmonad
, ((modMask .|. shiftMask, xK_q ), io 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 +238,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 = xmessage help
-- | Mouse bindings: default actions bound to mouse events
mouseBindings :: XConfig Layout -> M.Map (KeyMask, Button) (Window -> X ())
@ -274,6 +278,7 @@ instance (a ~ Choose Tall (Choose (Mirror Tall) Full)) => Default (XConfig a) wh
, XMonad.handleExtraArgs = \ xs theConf -> case xs of
[] -> return theConf
_ -> fail ("unrecognized flags:" ++ show xs)
, XMonad.extensibleConf = M.empty
}
-- | The default set of configuration values itself
@ -293,6 +298,7 @@ help = unlines ["The default modifier key is 'alt'. Default keybindings:",
"mod-Space Rotate through the available layout algorithms",
"mod-Shift-Space Reset the layouts on the current workSpace to default",
"mod-n Resize/refresh viewed windows to the correct size",
"mod-Shift-/ Show this help message with the default keybindings",
"",
"-- move focus up or down the window stack",
"mod-Tab Move focus to the next window",

View File

@ -1,5 +1,14 @@
{-# LANGUAGE ExistentialQuantification, FlexibleInstances, GeneralizedNewtypeDeriving,
MultiParamTypeClasses, TypeSynonymInstances, CPP, DeriveDataTypeable #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE ViewPatterns #-}
-----------------------------------------------------------------------------
-- |
@ -22,24 +31,33 @@ module XMonad.Core (
XConf(..), XConfig(..), LayoutClass(..),
Layout(..), readsLayout, Typeable, Message,
SomeMessage(..), fromMessage, LayoutMessages(..),
StateExtension(..), ExtensionClass(..),
StateExtension(..), ExtensionClass(..), ConfExtension(..),
runX, catchX, userCode, userCodeDef, io, catchIO, installSignalHandlers, uninstallSignalHandlers,
withDisplay, withWindowSet, isRoot, runOnWorkspaces,
getAtom, spawn, spawnPID, xfork, recompile, trace, whenJust, whenX,
getXMonadDir, getXMonadCacheDir, getXMonadDataDir, stateFileName,
getAtom, spawn, spawnPID, xfork, xmessage, recompile, trace, whenJust, whenX, ifM,
getXMonadDir, getXMonadCacheDir, getXMonadDataDir, stateFileName, binFileName,
atom_WM_STATE, atom_WM_PROTOCOLS, atom_WM_DELETE_WINDOW, atom_WM_TAKE_FOCUS, withWindowAttributes,
ManageHook, Query(..), runQuery
ManageHook, Query(..), runQuery, Directories'(..), Directories, getDirectories,
) where
import XMonad.StackSet hiding (modify)
import Prelude
import Control.Exception.Extensible (fromException, try, bracket, throw, finally, SomeException(..))
import qualified Control.Exception.Extensible as E
import Control.Applicative
import Control.Exception (fromException, try, bracket_, throw, finally, SomeException(..))
import qualified Control.Exception as E
import Control.Applicative ((<|>), empty)
import Control.Monad.Fail
import Control.Monad.Fix (fix)
import Control.Monad.State
import Control.Monad.Reader
import Data.Default
import Control.Monad (filterM, guard, void, when)
import Data.Char (isSpace)
import Data.Semigroup
import Data.Traversable (for)
import Data.Time.Clock (UTCTime)
import Data.Default.Class
import System.Environment (lookupEnv)
import Data.List (isInfixOf, intercalate, (\\))
import System.FilePath
import System.IO
import System.Info
@ -54,9 +72,8 @@ import System.Exit
import Graphics.X11.Xlib
import Graphics.X11.Xlib.Extras (getWindowAttributes, WindowAttributes, Event)
import Data.Typeable
import Data.List ((\\))
import Data.Maybe (isJust,fromMaybe)
import Data.Monoid
import Data.Monoid (Ap(..))
import qualified Data.Map as M
import qualified Data.Set as S
@ -71,7 +88,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.
}
@ -90,8 +107,8 @@ data XConf = XConf
, mousePosition :: !(Maybe (Position, Position))
-- ^ position of the mouse according to
-- the event currently being processed
, currentEvent :: !(Maybe Event)
-- ^ event currently being processed
, currentEvent :: !(Maybe Event) -- ^ event currently being processed
, directories :: !Directories -- ^ directories to use
}
-- todo, better name
@ -119,6 +136,11 @@ data XConfig l = XConfig
, rootMask :: !EventMask -- ^ The root events that xmonad is interested in
, handleExtraArgs :: !([String] -> XConfig Layout -> IO (XConfig Layout))
-- ^ Modify the configuration, complain about extra arguments etc. with arguments that are not handled by default
, extensibleConf :: !(M.Map TypeRep ConfExtension)
-- ^ Stores custom config information.
--
-- The module "XMonad.Util.ExtensibleConf" in xmonad-contrib
-- provides additional information and a simple interface for using this.
}
@ -132,7 +154,8 @@ type WorkspaceId = String
newtype ScreenId = S Int deriving (Eq,Ord,Show,Read,Enum,Num,Integral,Real)
-- | The 'Rectangle' with screen dimensions
data ScreenDetail = SD { screenRect :: !Rectangle } deriving (Eq,Show, Read)
newtype ScreenDetail = SD { screenRect :: Rectangle }
deriving (Eq,Show, Read)
------------------------------------------------------------------------
@ -145,15 +168,8 @@ 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)
instance Applicative X where
pure = return
(<*>) = ap
instance (Monoid a) => Monoid (X a) where
mempty = return mempty
mappend = liftM2 mappend
deriving (Functor, Applicative, Monad, MonadFail, MonadIO, MonadState XState, MonadReader XConf)
deriving (Semigroup, Monoid) via Ap X a
instance Default a => Default (X a) where
def = return def
@ -161,13 +177,10 @@ instance Default a => Default (X a) where
type ManageHook = Query (Endo WindowSet)
newtype Query a = Query (ReaderT Window X a)
deriving (Functor, Applicative, Monad, MonadReader Window, MonadIO)
deriving (Semigroup, Monoid) via Ap Query a
runQuery :: Query a -> Window -> X a
runQuery (Query m) w = runReaderT m w
instance Monoid a => Monoid (Query a) where
mempty = return mempty
mappend = liftM2 mappend
runQuery (Query m) = runReaderT m
instance Default a => Default (Query a) where
def = return def
@ -184,7 +197,7 @@ catchX job errcase = do
st <- get
c <- ask
(a, s') <- io $ runX c st job `E.catch` \e -> case fromException e of
Just x -> throw e `const` (x `asTypeOf` ExitSuccess)
Just (_ :: ExitCode) -> throw e
_ -> do hPrint stderr e; runX c st errcase
put s'
return a
@ -192,12 +205,12 @@ catchX job errcase = do
-- | Execute the argument, catching all exceptions. Either this function or
-- 'catchX' should be used at all callsites of user customized code.
userCode :: X a -> X (Maybe a)
userCode a = catchX (Just `liftM` a) (return Nothing)
userCode a = catchX (Just <$> a) (return Nothing)
-- | Same as userCode but with a default argument to return instead of using
-- Maybe, provided for convenience.
userCodeDef :: a -> X a -> X a
userCodeDef defValue a = fromMaybe defValue `liftM` userCode a
userCodeDef defValue a = fromMaybe defValue <$> userCode a
-- ---------------------------------------------------------------------
-- Convenient wrappers to state
@ -218,7 +231,7 @@ withWindowAttributes dpy win f = do
-- | True if the given window is the root window
isRoot :: Window -> X Bool
isRoot w = (w==) <$> asks theRoot
isRoot w = asks $ (w ==) . theRoot
-- | Wrapper for the common case of atom internment
getAtom :: String -> X Atom
@ -246,14 +259,18 @@ readsLayout (Layout l) s = [(Layout (asTypeOf x l), rs) | (x, rs) <- reads s]
-- | Every layout must be an instance of 'LayoutClass', which defines
-- the basic layout operations along with a sensible default for each.
--
-- Minimal complete definition:
-- All of the methods have default implementations, so there is no
-- minimal complete definition. They do, however, have a dependency
-- structure by default; this is something to be aware of should you
-- choose to implement one of these methods. Here is how a minimal
-- complete definition would look like if we did not provide any default
-- implementations:
--
-- * 'runLayout' || (('doLayout' || 'pureLayout') && 'emptyLayout'), and
-- * 'runLayout' || (('doLayout' || 'pureLayout') && 'emptyLayout')
--
-- * 'handleMessage' || 'pureMessage'
--
-- You should also strongly consider implementing 'description',
-- although it is not required.
-- * 'description'
--
-- Note that any code which /uses/ 'LayoutClass' methods should only
-- ever call 'runLayout', 'handleMessage', and 'description'! In
@ -262,7 +279,7 @@ readsLayout (Layout l) s = [(Layout (asTypeOf x l), rs) | (x, rs) <- reads s]
-- 'runLayout', 'handleMessage', and so on. This ensures that the
-- proper methods will be used, regardless of the particular methods
-- that any 'LayoutClass' instance chooses to define.
class Show (layout a) => LayoutClass layout a where
class (Show (layout a), Typeable layout) => LayoutClass layout a where
-- | By default, 'runLayout' calls 'doLayout' if there are any
-- windows to be laid out, and 'emptyLayout' otherwise. Most
@ -364,12 +381,12 @@ instance Message Event
-- layouts) should consider handling.
data LayoutMessages = Hide -- ^ sent when a layout becomes non-visible
| ReleaseResources -- ^ sent when xmonad is exiting or restarting
deriving (Typeable, Eq)
deriving Eq
instance Message LayoutMessages
-- ---------------------------------------------------------------------
-- Extensible state
-- Extensible state/config
--
-- | Every module must make the data it wants to store
@ -377,6 +394,7 @@ instance Message LayoutMessages
--
-- Minimal complete definition: initialValue
class Typeable a => ExtensionClass a where
{-# MINIMAL initialValue #-}
-- | Defines an initial value for the state extension
initialValue :: a
-- | Specifies whether the state extension should be
@ -395,10 +413,17 @@ data StateExtension =
| forall a. (Read a, Show a, ExtensionClass a) => PersistentExtension a
-- ^ Persistent extension
-- | Existential type to store a config extension.
data ConfExtension = forall a. Typeable a => ConfExtension a
-- ---------------------------------------------------------------------
-- | General utilities
--
-- Lift an 'IO' action into the 'X' monad
-- General utilities
-- | If-then-else lifted to a 'Monad'.
ifM :: Monad m => m Bool -> m a -> m a -> m a
ifM mb t f = mb >>= \b -> if b then t else f
-- | Lift an 'IO' action into the 'X' monad
io :: MonadIO m => IO a -> m a
io = liftIO
@ -412,7 +437,7 @@ catchIO f = io (f `E.catch` \(SomeException e) -> hPrint stderr e >> hFlush stde
--
-- Note this function assumes your locale uses utf8.
spawn :: MonadIO m => String -> m ()
spawn x = spawnPID x >> return ()
spawn x = void $ spawnPID x
-- | Like 'spawn', but returns the 'ProcessID' of the launched application
spawnPID :: MonadIO m => String -> m ProcessID
@ -426,10 +451,25 @@ xfork x = io . forkProcess . finally nullStdin $ do
x
where
nullStdin = do
#if MIN_VERSION_unix(2,8,0)
fd <- openFd "/dev/null" ReadOnly defaultFileFlags
#else
fd <- openFd "/dev/null" ReadOnly Nothing defaultFileFlags
#endif
dupTo fd stdInput
closeFd fd
-- | Use @xmessage@ to show information to the user.
xmessage :: MonadIO m => String -> m ()
xmessage msg = void . xfork $ do
xmessageBin <- fromMaybe "xmessage" <$> liftIO (lookupEnv "XMONAD_XMESSAGE")
executeFile xmessageBin True
[ "-default", "okay"
, "-xrm", "*international:true"
, "-xrm", "*fontSet:-*-fixed-medium-r-normal-*-18-*-*-*-*-*-*-*,-*-fixed-*-*-*-*-18-*-*-*-*-*-*-*,-*-*-*-*-*-*-18-*-*-*-*-*-*-*"
, msg
] Nothing
-- | This is basically a map function, running a function in the 'X' monad on
-- each workspace with the output of that function being the modified workspace.
runOnWorkspaces :: (WindowSpace -> X WindowSpace) -> X ()
@ -440,116 +480,361 @@ runOnWorkspaces job = do
$ current ws : visible ws
modify $ \s -> s { windowset = ws { current = c, visible = v, hidden = h } }
-- | Return the path to the xmonad configuration directory. This
-- directory is where user configuration files are stored (e.g, the
-- xmonad.hs file). You may also create a @lib@ subdirectory in the
-- configuration directory and the default recompile command will add
-- it to the GHC include path.
-- | All the directories that xmonad will use. They will be used for
-- the following purposes:
--
-- Several directories are considered. In order of
-- preference:
-- * @dataDir@: This directory is used by XMonad to store data files
-- such as the run-time state file.
--
-- 1. The directory specified in the @XMONAD_CONFIG_DIR@ environment variable.
-- 2. The @~\/.xmonad@ directory.
-- 3. The @XDG_CONFIG_HOME/xmonad@ directory.
-- * @cfgDir@: 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.
--
-- The first directory that exists will be used. If none of the
-- directories exist then (1) will be used if it is set, otherwise (2)
-- will be used. Either way, a directory will be created if necessary.
getXMonadDir :: MonadIO m => m String
getXMonadDir =
findFirstDirWithEnv "XMONAD_CONFIG_DIR"
[ getAppUserDataDirectory "xmonad"
, getXdgDirectory XdgConfig "xmonad"
]
-- * @cacheDir@: This directory is used to store temporary files that
-- can easily be recreated such as the configuration binary and any
-- intermediate object files generated by GHC.
-- Also, the XPrompt history file goes here.
--
-- For how these directories are chosen, see 'getDirectories'.
--
data Directories' a = Directories
{ dataDir :: !a
, cfgDir :: !a
, cacheDir :: !a
}
deriving (Show, Functor, Foldable, Traversable)
-- | 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"
]
-- | Convenient type alias for the most common case in which one might
-- want to use the 'Directories' type.
type Directories = Directories' FilePath
-- | 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.
-- | Build up the 'Dirs' that xmonad will use. They are chosen as
-- follows:
--
-- Several directories are considered. In order of preference:
-- 1. If all three of xmonad's environment variables (@XMONAD_DATA_DIR@,
-- @XMONAD_CONFIG_DIR@, and @XMONAD_CACHE_DIR@) are set, use them.
-- 2. If there is a build script called @build@ or configuration
-- @xmonad.hs@ in @~\/.xmonad@, set all three directories to
-- @~\/.xmonad@.
-- 3. Otherwise, use the @xmonad@ directory in @XDG_DATA_HOME@,
-- @XDG_CONFIG_HOME@, and @XDG_CACHE_HOME@ (or their respective
-- fallbacks). These directories are created if necessary.
--
-- 1. The directory specified in the @XMONAD_DATA_DIR@ environment variable.
-- 2. The @~\/.xmonad@ directory.
-- 3. The @XDG_DATA_HOME/xmonad@ directory.
-- The xmonad configuration file (or the build script, if present) is
-- always assumed to be in @cfgDir@.
--
-- 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
getDirectories :: IO Directories
getDirectories = xmEnvDirs <|> xmDirs <|> xdgDirs
where
go [] = return Nothing
go (x:xs) = do
dir <- io x
exists <- io (doesDirectoryExist dir)
if exists then return (Just dir) else go xs
-- | Check for xmonad's environment variables first
xmEnvDirs :: IO Directories
xmEnvDirs = do
let xmEnvs = Directories{ dataDir = "XMONAD_DATA_DIR"
, cfgDir = "XMONAD_CONFIG_DIR"
, cacheDir = "XMONAD_CACHE_DIR"
}
maybe empty pure . sequenceA =<< traverse getEnv xmEnvs
-- | 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)
-- | Check whether the config file or a build script is in the
-- @~\/.xmonad@ directory
xmDirs :: IO Directories
xmDirs = do
xmDir <- getAppUserDataDirectory "xmonad"
conf <- doesFileExist $ xmDir </> "xmonad.hs"
build <- doesFileExist $ xmDir </> "build"
case envPath' of
Nothing -> findFirstDirOf paths
Just envPath -> findFirstDirOf (return envPath:paths)
-- Place *everything* in ~/.xmonad if yes
guard $ conf || build
pure Directories{ dataDir = xmDir, cfgDir = xmDir, cacheDir = xmDir }
-- | Use XDG directories as a fallback
xdgDirs :: IO Directories
xdgDirs =
for Directories{ dataDir = XdgData, cfgDir = XdgConfig, cacheDir = XdgCache }
$ \dir -> do d <- getXdgDirectory dir "xmonad"
d <$ createDirectoryIfMissing True d
-- | Get the name of the file used to store the xmonad window state.
stateFileName :: (Functor m, MonadIO m) => m FilePath
stateFileName = (</> "xmonad.state") <$> getXMonadDataDir
-- | Return the path to the xmonad configuration directory.
getXMonadDir :: X String
getXMonadDir = asks (cfgDir . directories)
{-# DEPRECATED getXMonadDir "Use `asks (cfgDir . directories)' instead." #-}
-- | 'recompile force', recompile the xmonad configuration file when
-- any of the following apply:
-- | Return the path to the xmonad cache directory.
getXMonadCacheDir :: X String
getXMonadCacheDir = asks (cacheDir . directories)
{-# DEPRECATED getXMonadCacheDir "Use `asks (cacheDir . directories)' instead." #-}
-- | Return the path to the xmonad data directory.
getXMonadDataDir :: X String
getXMonadDataDir = asks (dataDir . directories)
{-# DEPRECATED getXMonadDataDir "Use `asks (dataDir . directories)' instead." #-}
binFileName, buildDirName :: Directories -> FilePath
binFileName Directories{ cacheDir } = cacheDir </> "xmonad-" <> arch <> "-" <> os
buildDirName Directories{ cacheDir } = cacheDir </> "build-" <> arch <> "-" <> os
errFileName, stateFileName :: Directories -> FilePath
errFileName Directories{ dataDir } = dataDir </> "xmonad.errors"
stateFileName Directories{ dataDir } = dataDir </> "xmonad.state"
srcFileName, libFileName :: Directories -> FilePath
srcFileName Directories{ cfgDir } = cfgDir </> "xmonad.hs"
libFileName Directories{ cfgDir } = cfgDir </> "lib"
buildScriptFileName, stackYamlFileName, nixFlakeFileName, nixDefaultFileName :: Directories -> FilePath
buildScriptFileName Directories{ cfgDir } = cfgDir </> "build"
stackYamlFileName Directories{ cfgDir } = cfgDir </> "stack.yaml"
nixFlakeFileName Directories{ cfgDir } = cfgDir </> "flake.nix"
nixDefaultFileName Directories{ cfgDir } = cfgDir </> "default.nix"
-- | Compilation method for xmonad configuration.
data Compile
= CompileGhc
| CompileCabal
| CompileStackGhc FilePath
| CompileNixFlake
| CompileNixDefault
| CompileScript FilePath
deriving (Show)
-- | Detect compilation method by looking for known file names in xmonad
-- configuration directory.
detectCompile :: Directories -> IO Compile
detectCompile dirs =
tryScript <|> tryStack <|> tryNixFlake <|> tryNixDefault <|> tryCabal <|> useGhc
where
buildScript = buildScriptFileName dirs
stackYaml = stackYamlFileName dirs
flakeNix = nixFlakeFileName dirs
defaultNix = nixDefaultFileName dirs
tryScript = do
guard =<< doesFileExist buildScript
isExe <- isExecutable buildScript
if isExe
then do
trace $ "XMonad will use build script at " <> show buildScript <> " to recompile."
pure $ CompileScript buildScript
else do
trace $ "XMonad will not use build script, because " <> show buildScript <> " is not executable."
trace $ "Suggested resolution to use it: chmod u+x " <> show buildScript
empty
tryNixFlake = do
guard =<< doesFileExist flakeNix
canonNixFlake <- canonicalizePath flakeNix
trace $ "XMonad will use nix flake at " <> show canonNixFlake <> " to recompile"
pure CompileNixFlake
tryNixDefault = do
guard =<< doesFileExist defaultNix
canonNixDefault <- canonicalizePath defaultNix
trace $ "XMonad will use nix file at " <> show canonNixDefault <> " to recompile"
pure CompileNixDefault
tryStack = do
guard =<< doesFileExist stackYaml
canonStackYaml <- canonicalizePath stackYaml
trace $ "XMonad will use stack ghc --stack-yaml " <> show canonStackYaml <> " to recompile."
pure $ CompileStackGhc canonStackYaml
tryCabal = let cwd = cfgDir dirs in listCabalFiles cwd >>= \ case
[] -> do
empty
[name] -> do
trace $ "XMonad will use " <> show name <> " to recompile."
pure CompileCabal
_ : _ : _ -> do
trace $ "XMonad will not use cabal, because there are multiple cabal files in " <> show cwd <> "."
empty
useGhc = do
trace $ "XMonad will use ghc to recompile, because none of "
<> intercalate ", "
[ show buildScript
, show stackYaml
, show flakeNix
, show defaultNix
] <> " nor a suitable .cabal file exist."
pure CompileGhc
listCabalFiles :: FilePath -> IO [FilePath]
listCabalFiles dir = map (dir </>) . Prelude.filter isCabalFile <$> listFiles dir
isCabalFile :: FilePath -> Bool
isCabalFile file = case splitExtension file of
(name, ".cabal") -> not (null name)
_ -> False
listFiles :: FilePath -> IO [FilePath]
listFiles dir = getDirectoryContents dir >>= filterM (doesFileExist . (dir </>))
-- | Determine whether or not the file found at the provided filepath is executable.
isExecutable :: FilePath -> IO Bool
isExecutable f = E.catch (executable <$> getPermissions f) (\(SomeException _) -> return False)
-- | Should we recompile xmonad configuration? Is it newer than the compiled
-- binary?
shouldCompile :: Directories -> Compile -> IO Bool
shouldCompile dirs CompileGhc = do
libTs <- mapM getModTime . Prelude.filter isSource =<< allFiles (libFileName dirs)
srcT <- getModTime (srcFileName dirs)
binT <- getModTime (binFileName dirs)
if any (binT <) (srcT : libTs)
then True <$ trace "XMonad recompiling because some files have changed."
else False <$ 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."
where
isSource = flip elem [".hs",".lhs",".hsc"] . takeExtension
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
shouldCompile _ CompileCabal = return True
shouldCompile dirs CompileStackGhc{} = do
stackYamlT <- getModTime (stackYamlFileName dirs)
binT <- getModTime (binFileName dirs)
if binT < stackYamlT
then True <$ trace "XMonad recompiling because some files have changed."
else shouldCompile dirs CompileGhc
shouldCompile _dirs CompileNixFlake{} = True <$ trace "XMonad recompiling because flake recompilation is being used."
shouldCompile _dirs CompileNixDefault{} = True <$ trace "XMonad recompiling because nix recompilation is being used."
shouldCompile _dirs CompileScript{} =
True <$ trace "XMonad recompiling because a custom build script is being used."
getModTime :: FilePath -> IO (Maybe UTCTime)
getModTime f = E.catch (Just <$> getModificationTime f) (\(SomeException _) -> return Nothing)
-- | Compile the configuration.
compile :: Directories -> Compile -> IO ExitCode
compile dirs method =
bracket_ uninstallSignalHandlers installSignalHandlers $
withFile (errFileName dirs) WriteMode $ \err -> do
let run = runProc err
case method of
CompileGhc -> do
ghc <- fromMaybe "ghc" <$> lookupEnv "XMONAD_GHC"
run ghc ghcArgs
CompileCabal -> run "cabal" ["build"] .&&. copyBinary
where
copyBinary :: IO ExitCode
copyBinary = readProc err "cabal" ["-v0", "list-bin", "."] >>= \ case
Left status -> return status
Right (trim -> path) -> copyBinaryFrom path
CompileStackGhc stackYaml ->
run "stack" ["build", "--silent", "--stack-yaml", stackYaml] .&&.
run "stack" ("ghc" : "--stack-yaml" : stackYaml : "--" : ghcArgs)
CompileNixFlake ->
run "nix" ["build"] >>= andCopyFromResultDir
CompileNixDefault ->
run "nix-build" [] >>= andCopyFromResultDir
CompileScript script ->
run script [binFileName dirs]
where
cwd :: FilePath
cwd = cfgDir dirs
ghcArgs :: [String]
ghcArgs = [ "--make"
, "xmonad.hs"
, "-i" -- only look in @lib@
, "-ilib"
, "-fforce-recomp"
, "-main-is", "main"
, "-v0"
, "-outputdir", buildDirName dirs
, "-o", binFileName dirs
]
andCopyFromResultDir :: ExitCode -> IO ExitCode
andCopyFromResultDir exitCode = do
if exitCode == ExitSuccess then copyFromResultDir else return exitCode
findM :: (Monad m, Foldable t) => (a -> m Bool) -> t a -> m (Maybe a)
findM p = foldr (\x -> ifM (p x) (pure $ Just x)) (pure Nothing)
catchAny :: IO a -> (SomeException -> IO a) -> IO a
catchAny = E.catch
copyFromResultDir :: IO ExitCode
copyFromResultDir = do
let binaryDirectory = cfgDir dirs </> "result" </> "bin"
binFiles <- map (binaryDirectory </>) <$> catchAny (listDirectory binaryDirectory) (\_ -> return [])
mfilepath <- findM isExecutable binFiles
case mfilepath of
Just filepath -> copyBinaryFrom filepath
Nothing -> return $ ExitFailure 1
copyBinaryFrom :: FilePath -> IO ExitCode
copyBinaryFrom filepath = copyFile filepath (binFileName dirs) >> return ExitSuccess
-- waitForProcess =<< System.Process.runProcess, but without closing the err handle
runProc :: Handle -> String -> [String] -> IO ExitCode
runProc err exe args = do
(Nothing, Nothing, Nothing, h) <- createProcess_ "runProc" =<< mkProc err exe args
waitForProcess h
readProc :: Handle -> String -> [String] -> IO (Either ExitCode String)
readProc err exe args = do
spec <- mkProc err exe args
(Nothing, Just out, Nothing, h) <- createProcess_ "readProc" spec{ std_out = CreatePipe }
result <- hGetContents out
hPutStr err result >> hFlush err
waitForProcess h >>= \ case
ExitSuccess -> return $ Right result
status -> return $ Left status
mkProc :: Handle -> FilePath -> [FilePath] -> IO CreateProcess
mkProc err exe args = do
hPutStrLn err $ unwords $ "$" : exe : args
hFlush err
return (proc exe args){ cwd = Just cwd, std_err = UseHandle err }
(.&&.) :: Monad m => m ExitCode -> m ExitCode -> m ExitCode
cmd1 .&&. cmd2 = cmd1 >>= \case
ExitSuccess -> cmd2
e -> pure e
-- | Check GHC output for deprecation warnings and notify the user if there
-- were any. Report success otherwise.
checkCompileWarnings :: Directories -> IO ()
checkCompileWarnings dirs = do
ghcErr <- readFile (errFileName dirs)
if "-Wdeprecations" `isInfixOf` ghcErr
then do
let msg = unlines $
["Deprecations detected while compiling xmonad config: " <> srcFileName dirs]
++ lines ghcErr
++ ["","Please correct them or silence using {-# OPTIONS_GHC -Wno-deprecations #-}."]
trace msg
xmessage msg
else
trace "XMonad recompilation process exited with success!"
-- | Notify the user that compilation failed and what was wrong.
compileFailed :: Directories -> ExitCode -> IO ()
compileFailed dirs status = do
ghcErr <- readFile (errFileName dirs)
let msg = unlines $
["Errors detected while compiling xmonad config: " <> srcFileName dirs]
++ 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
trace msg
xmessage msg
-- | Recompile the xmonad configuration file when any of the following apply:
--
-- * force is 'True'
-- * force is 'True'
--
-- * the xmonad executable does not exist
-- * the xmonad executable does not exist
--
-- * the xmonad executable is older than xmonad.hs or any file in
-- the @lib@ directory (under the configuration directory).
-- * the xmonad executable is older than @xmonad.hs@ or any file in
-- the @lib@ directory (under the configuration directory)
--
-- * custom @build@ script is being used
--
-- The -i flag is used to restrict recompilation to the xmonad.hs file only,
-- and any files in the aforementioned @lib@ directory.
@ -560,77 +845,21 @@ stateFileName = (</> "xmonad.state") <$> getXMonadDataDir
--
-- 'False' is returned if there are compilation errors.
--
recompile :: MonadIO m => Bool -> m Bool
recompile force = io $ do
cfgdir <- getXMonadDir
datadir <- getXMonadDataDir
let binn = "xmonad-"++arch++"-"++os
bin = datadir </> binn
err = datadir </> "xmonad.errors"
src = cfgdir </> "xmonad.hs"
lib = cfgdir </> "lib"
buildscript = cfgdir </> "build"
libTs <- mapM getModTime . Prelude.filter isSource =<< allFiles lib
srcT <- getModTime src
binT <- getModTime bin
useBuildscript <- do
exists <- doesFileExist buildscript
if exists then isExecutable buildscript else return False
if force || useBuildscript || any (binT <) (srcT : libTs)
recompile :: MonadIO m => Directories -> Bool -> m Bool
recompile dirs force = io $ do
method <- detectCompile dirs
willCompile <- if force
then True <$ trace "XMonad recompiling (forced)."
else shouldCompile dirs method
if willCompile
then do
-- temporarily disable SIGCHLD ignoring:
uninstallSignalHandlers
status <- bracket (openFile err WriteMode) hClose $ \errHandle ->
waitForProcess =<< if useBuildscript
then compileScript bin cfgdir buildscript errHandle
else compileGHC bin cfgdir errHandle
-- re-enable SIGCHLD:
installSignalHandlers
-- now, if it fails, run xmessage to let the user know:
when (status /= ExitSuccess) $ do
ghcErr <- readFile err
let msg = unlines $
["Error detected while loading xmonad configuration file: " ++ src]
++ lines (if null ghcErr then show status else ghcErr)
++ ["","Please check the file for errors."]
-- nb, the ordering of printing, then forking, is crucial due to
-- lazy evaluation
hPutStrLn stderr msg
forkProcess $ executeFile "xmessage" True ["-default", "okay", replaceUnicode msg] Nothing
return ()
return (status == ExitSuccess)
else return True
where getModTime f = E.catch (Just <$> getModificationTime f) (\(SomeException _) -> return Nothing)
isSource = flip elem [".hs",".lhs",".hsc"] . takeExtension
isExecutable f = E.catch (executable <$> getPermissions f) (\(SomeException _) -> return False)
allFiles t = do
let prep = map (t</>) . Prelude.filter (`notElem` [".",".."])
cs <- prep <$> E.catch (getDirectoryContents t) (\(SomeException _) -> return [])
ds <- filterM doesDirectoryExist cs
concat . ((cs \\ ds):) <$> mapM allFiles ds
-- Replace some of the unicode symbols GHC uses in its output
replaceUnicode = map $ \c -> case c of
'\8226' -> '*' --
'\8216' -> '`' --
'\8217' -> '`' --
_ -> c
compileGHC bin dir errHandle =
runProcess "ghc" ["--make"
, "xmonad.hs"
, "-i"
, "-ilib"
, "-fforce-recomp"
, "-main-is", "main"
, "-v0"
, "-o", bin
] (Just dir) Nothing Nothing Nothing (Just errHandle)
compileScript bin dir script errHandle =
runProcess script [bin] (Just dir) Nothing Nothing Nothing (Just errHandle)
status <- compile dirs method
if status == ExitSuccess
then checkCompileWarnings dirs
else compileFailed dirs status
pure $ status == ExitSuccess
else
pure True
-- | Conditionally run an action, using a @Maybe a@ to decide.
whenJust :: Monad m => Maybe a -> (a -> m ()) -> m ()
@ -662,3 +891,6 @@ uninstallSignalHandlers = io $ do
installHandler openEndedPipe Default Nothing
installHandler sigCHLD Default Nothing
return ()
trim :: String -> String
trim = reverse . dropWhile isSpace . reverse . dropWhile isSpace

View File

@ -1,4 +1,6 @@
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, PatternGuards, TypeSynonymInstances, DeriveDataTypeable #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PatternGuards #-}
-- --------------------------------------------------------------------------
-- |
@ -8,7 +10,7 @@
--
-- Maintainer : spencerjanssen@gmail.com
-- Stability : unstable
-- Portability : not portable, Typeable deriving, mtl, posix
-- Portability : not portable, mtl, posix
--
-- The collection of core layouts.
--
@ -16,7 +18,7 @@
module XMonad.Layout (
Full(..), Tall(..), Mirror(..),
Resize(..), IncMasterN(..), Choose, (|||), ChangeLayout(..),
Resize(..), IncMasterN(..), Choose(..), (|||), CLR(..), ChangeLayout(..), JumpToLayout(..),
mirrorRect, splitVertically,
splitHorizontally, splitHorizontallyBy, splitVerticallyBy,
@ -27,6 +29,7 @@ module XMonad.Layout (
import XMonad.Core
import Graphics.X11 (Rectangle(..))
import Graphics.X11.Xlib.Extras ( Event(DestroyWindowEvent) )
import qualified XMonad.StackSet as W
import Control.Arrow ((***), second)
import Control.Monad
@ -35,10 +38,10 @@ import Data.Maybe (fromMaybe)
------------------------------------------------------------------------
-- | Change the size of the master pane.
data Resize = Shrink | Expand deriving Typeable
data Resize = Shrink | Expand
-- | Increase the number of clients in the master pane.
data IncMasterN = IncMasterN !Int deriving Typeable
newtype IncMasterN = IncMasterN Int
instance Message Resize
instance Message IncMasterN
@ -59,9 +62,13 @@ data Tall a = Tall { tallNMaster :: !Int -- ^ The default number o
-- a nice pure layout, lots of properties for the layout, and its messages, in Properties.hs
instance LayoutClass Tall a where
pureLayout (Tall nmaster _ frac) r s = zip ws rs
pureLayout (Tall nmaster _ frac) r s
| frac == 0 = drop nmaster layout
| frac == 1 = take nmaster layout
| otherwise = layout
where ws = W.integrate s
rs = tile frac r nmaster (length ws)
layout = zip ws rs
pureMessage (Tall nmaster delta frac) m =
msum [fmap resize (fromMessage m)
@ -77,7 +84,7 @@ instance LayoutClass Tall a where
-- algorithm.
--
-- The screen is divided into two panes. All clients are
-- then partioned between these two panes. One pane, the master, by
-- then partitioned between these two panes. One pane, the master, by
-- convention has the least number of windows in it.
tile
:: Rational -- ^ @frac@, what proportion of the screen to devote to the master area
@ -131,23 +138,53 @@ mirrorRect (Rectangle rx ry rw rh) = Rectangle ry rx rh rw
-- LayoutClass selection manager
-- Layouts that transition between other layouts
-- | Messages to change the current layout.
data ChangeLayout = FirstLayout | NextLayout deriving (Eq, Show, Typeable)
-- | Messages to change the current layout. Also see 'JumpToLayout'.
data ChangeLayout = FirstLayout | NextLayout deriving (Eq, Show)
instance Message ChangeLayout
-- | A message to jump to a particular layout, specified by its
-- description string.
--
-- The argument given to a 'JumpToLayout' message should be the
-- @description@ of the layout to be selected. If you use
-- "XMonad.Hooks.DynamicLog" from @xmonad-contrib@, this is the name of
-- the layout displayed in your status bar. Alternatively, you can use
-- GHCi to determine the proper name to use. For example:
--
-- > $ ghci
-- > GHCi, version 6.8.2: http://www.haskell.org/ghc/ :? for help
-- > Loading package base ... linking ... done.
-- > :set prompt "> " -- don't show loaded module names
-- > > :m +XMonad.Core -- load the xmonad core
-- > > :m +XMonad.Layout.Grid -- load whatever module you want to use
-- > > description Grid -- find out what it's called
-- > "Grid"
--
-- As yet another (possibly easier) alternative, you can use the
-- "XMonad.Layout.Renamed" module (also in @xmonad-contrib@) to give
-- custom names to your layouts, and use those.
--
-- For example, if you want to jump directly to the 'Full' layout you
-- can do
--
-- > , ((modm .|. controlMask, xK_f), sendMessage $ JumpToLayout "Full")
--
newtype JumpToLayout = JumpToLayout String
instance Message JumpToLayout
-- | The layout choice combinator
(|||) :: l a -> r a -> Choose l r a
(|||) = Choose L
(|||) = Choose CL
infixr 5 |||
-- | A layout that allows users to switch between various layout options.
data Choose l r a = Choose LR (l a) (r a) deriving (Read, Show)
data Choose l r a = Choose CLR (l a) (r a) deriving (Read, Show)
-- | Are we on the left or right sub-layout?
data LR = L | R deriving (Read, Show, Eq)
-- | Choose the current sub-layout (left or right) in 'Choose'.
data CLR = CL | CR deriving (Read, Show, Eq)
data NextNoWrap = NextNoWrap deriving (Eq, Show, Typeable)
data NextNoWrap = NextNoWrap deriving (Eq, Show)
instance Message NextNoWrap
-- | A small wrapper around handleMessage, as it is tedious to write
@ -159,26 +196,26 @@ handle l m = handleMessage l (SomeMessage m)
-- new structure if any fields have changed, and performs any necessary cleanup
-- on newly non-visible layouts.
choose :: (LayoutClass l a, LayoutClass r a)
=> Choose l r a-> LR -> Maybe (l a) -> Maybe (r a) -> X (Maybe (Choose l r a))
=> Choose l r a -> CLR -> Maybe (l a) -> Maybe (r a) -> X (Maybe (Choose l r a))
choose (Choose d _ _) d' Nothing Nothing | d == d' = return Nothing
choose (Choose d l r) d' ml mr = f lr
where
(l', r') = (fromMaybe l ml, fromMaybe r mr)
lr = case (d, d') of
(L, R) -> (hide l' , return r')
(R, L) -> (return l', hide r' )
(_, _) -> (return l', return r')
f (x,y) = fmap Just $ liftM2 (Choose d') x y
hide x = fmap (fromMaybe x) $ handle x Hide
(CL, CR) -> (hide l' , return r')
(CR, CL) -> (return l', hide r' )
(_ , _ ) -> (return l', return r')
f (x,y) = Just <$> liftM2 (Choose d') x y
hide x = fromMaybe x <$> handle x Hide
instance (LayoutClass l a, LayoutClass r a) => LayoutClass (Choose l r) a where
runLayout (W.Workspace i (Choose L l r) ms) =
fmap (second . fmap $ flip (Choose L) r) . runLayout (W.Workspace i l ms)
runLayout (W.Workspace i (Choose R l r) ms) =
fmap (second . fmap $ Choose R l) . runLayout (W.Workspace i r ms)
runLayout (W.Workspace i (Choose CL l r) ms) =
fmap (second . fmap $ flip (Choose CL) r) . runLayout (W.Workspace i l ms)
runLayout (W.Workspace i (Choose CR l r) ms) =
fmap (second . fmap $ Choose CR l) . runLayout (W.Workspace i r ms)
description (Choose L l _) = description l
description (Choose R _ r) = description r
description (Choose CL l _) = description l
description (Choose CR _ r) = description r
handleMessage lr m | Just NextLayout <- fromMessage m = do
mlr' <- handle lr NextNoWrap
@ -186,25 +223,36 @@ instance (LayoutClass l a, LayoutClass r a) => LayoutClass (Choose l r) a where
handleMessage c@(Choose d l r) m | Just NextNoWrap <- fromMessage m =
case d of
L -> do
CL -> do
ml <- handle l NextNoWrap
case ml of
Just _ -> choose c L ml Nothing
Nothing -> choose c R Nothing =<< handle r FirstLayout
Just _ -> choose c CL ml Nothing
Nothing -> choose c CR Nothing =<< handle r FirstLayout
R -> choose c R Nothing =<< handle r NextNoWrap
CR -> choose c CR Nothing =<< handle r NextNoWrap
handleMessage c@(Choose _ l _) m | Just FirstLayout <- fromMessage m =
flip (choose c L) Nothing =<< handle l FirstLayout
flip (choose c CL) Nothing =<< handle l FirstLayout
handleMessage c@(Choose d l r) m | Just ReleaseResources <- fromMessage m =
join $ liftM2 (choose c d) (handle l ReleaseResources) (handle r ReleaseResources)
handleMessage c@(Choose d l r) m | Just e@DestroyWindowEvent{} <- fromMessage m =
join $ liftM2 (choose c d) (handle l e) (handle r e)
handleMessage c@(Choose d l r) m | Just (JumpToLayout desc) <- fromMessage m = do
ml <- handleMessage l m
mr <- handleMessage r m
let md | desc == description (fromMaybe l ml) = CL
| desc == description (fromMaybe r mr) = CR
| otherwise = d
choose c md ml mr
handleMessage c@(Choose d l r) m = do
ml' <- case d of
L -> handleMessage l m
R -> return Nothing
CL -> handleMessage l m
CR -> return Nothing
mr' <- case d of
L -> return Nothing
R -> handleMessage r m
CL -> return Nothing
CR -> handleMessage r m
choose c d ml' mr'

View File

@ -1,4 +1,6 @@
{-# LANGUAGE MultiParamTypeClasses, FlexibleContexts #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE MultiParamTypeClasses #-}
----------------------------------------------------------------------------
-- |
-- Module : XMonad.Main
@ -13,18 +15,19 @@
--
-----------------------------------------------------------------------------
module XMonad.Main (xmonad, launch) where
module XMonad.Main (xmonad, buildLaunch, launch) where
import System.Locale.SetLocale
import qualified Control.Exception.Extensible as E
import qualified Control.Exception as E
import Data.Bits
import Data.List ((\\))
import Data.Function
import Data.Foldable (traverse_)
import qualified Data.Map as M
import qualified Data.Set as S
import Control.Monad.Reader
import Control.Monad.State
import Data.Maybe (fromMaybe)
import Control.Monad (filterM, guard, unless, void, when, forever)
import Data.Maybe (fromMaybe, isJust)
import Data.Monoid (getAll)
import Graphics.X11.Xlib hiding (refreshKeyboardMapping)
@ -39,7 +42,7 @@ import XMonad.Operations
import System.IO
import System.Directory
import System.Info
import System.Environment
import System.Environment (getArgs, getProgName, withArgs)
import System.Posix.Process (executeFile)
import System.Exit (exitFailure)
import System.FilePath
@ -48,6 +51,7 @@ import Paths_xmonad (version)
import Data.Version (showVersion)
import Graphics.X11.Xinerama (compiledWithXinerama)
import Graphics.X11.Xrandr (xrrQueryExtension, xrrUpdateConfiguration)
------------------------------------------------------------------------
@ -59,17 +63,17 @@ xmonad :: (LayoutClass l Window, Read (l Window)) => XConfig l -> IO ()
xmonad conf = do
installSignalHandlers -- important to ignore SIGCHLD to avoid zombies
dirs <- getDirectories
let launch' args = do
catchIO buildLaunch
conf' @ XConfig { layoutHook = Layout l }
catchIO (buildLaunch dirs)
conf'@XConfig { layoutHook = Layout l }
<- handleExtraArgs conf args conf{ layoutHook = Layout (layoutHook conf) }
withArgs [] $ launch (conf' { layoutHook = l })
withArgs [] $ launch (conf' { layoutHook = l }) dirs
args <- getArgs
case args of
("--resume": ws : xs : args') -> migrateState ws xs >> launch' args'
["--help"] -> usage
["--recompile"] -> recompile True >>= flip unless exitFailure
["--recompile"] -> recompile dirs True >>= flip unless exitFailure
["--restart"] -> sendRestart
["--version"] -> putStrLn $ unwords shortVersion
["--verbose-version"] -> putStrLn . unwords $ shortVersion ++ longVersion
@ -86,14 +90,14 @@ usage :: IO ()
usage = do
self <- getProgName
putStr . unlines $
concat ["Usage: ", self, " [OPTION]"] :
"Options:" :
" --help Print this message" :
" --version Print the version number" :
" --recompile Recompile your ~/.xmonad/xmonad.hs" :
" --replace Replace the running window manager with xmonad" :
" --restart Request a running xmonad process to restart" :
[]
[ "Usage: " <> self <> " [OPTION]"
, "Options:"
, " --help Print this message"
, " --version Print the version number"
, " --recompile Recompile your xmonad.hs"
, " --replace Replace the running window manager with xmonad"
, " --restart Request a running xmonad process to restart"
]
-- | Build the xmonad configuration file with ghc, then execute it.
-- If there are no errors, this function does not return. An
@ -111,34 +115,21 @@ usage = do
--
-- * Missing XMonad\/XMonadContrib modules due to ghc upgrade
--
buildLaunch :: IO ()
buildLaunch = do
recompile False
dir <- getXMonadDataDir
args <- getArgs
buildLaunch :: Directories -> IO ()
buildLaunch dirs = do
whoami <- getProgName
let compiledConfig = "xmonad-"++arch++"-"++os
unless (whoami == compiledConfig) $
executeFile (dir </> compiledConfig) False args Nothing
sendRestart :: IO ()
sendRestart = do
dpy <- openDisplay ""
rw <- rootWindow dpy $ defaultScreen dpy
xmonad_restart <- internAtom dpy "XMONAD_RESTART" False
allocaXEvent $ \e -> do
setEventType e clientMessage
setClientMessageEvent e rw xmonad_restart 32 0 currentTime
sendEvent dpy rw False structureNotifyMask e
sync dpy False
-- | a wrapper for 'replace'
sendReplace :: IO ()
sendReplace = do
dpy <- openDisplay ""
let dflt = defaultScreen dpy
rootw <- rootWindow dpy dflt
replace dpy dflt rootw
let bin = binFileName dirs
let compiledConfig = takeFileName bin
unless (whoami == compiledConfig) $ do
trace $ concat
[ "XMonad is recompiling and replacing itself with another XMonad process because the current process is called "
, show whoami
, " but the compiled configuration should be called "
, show compiledConfig
]
recompile dirs False
args <- getArgs
executeFile bin False args Nothing
-- | Entry point into xmonad for custom builds.
--
@ -160,8 +151,8 @@ sendReplace = do
-- 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
launch :: (LayoutClass l Window, Read (l Window)) => XConfig l -> Directories -> IO ()
launch initxmc drs = do
-- setup locale information from environment
setLocale LC_ALL (Just "")
-- ignore SIGPIPE and SIGCHLD
@ -186,18 +177,17 @@ launch initxmc = do
xinesc <- getCleanedScreenInfo dpy
nbc <- do v <- initColor dpy $ normalBorderColor xmc
~(Just nbc_) <- initColor dpy $ normalBorderColor Default.def
nbc <- do v <- initColor dpy $ normalBorderColor xmc
Just nbc_ <- initColor dpy $ normalBorderColor Default.def
return (fromMaybe nbc_ v)
fbc <- do v <- initColor dpy $ focusedBorderColor xmc
~(Just fbc_) <- initColor dpy $ focusedBorderColor Default.def
Just fbc_ <- initColor dpy $ focusedBorderColor Default.def
return (fromMaybe fbc_ v)
hSetBuffering stdout NoBuffering
let layout = layoutHook xmc
lreads = readsLayout layout
initialWinset = let padToLen n xs = take (max n (length xs)) $ xs ++ repeat ""
in new layout (padToLen (length xinesc) (workspaces xmc)) $ map SD xinesc
@ -211,7 +201,9 @@ launch initxmc = do
, buttonActions = mouseBindings xmc xmc
, mouseFocused = False
, mousePosition = Nothing
, currentEvent = Nothing }
, currentEvent = Nothing
, directories = drs
}
st = XState
{ windowset = initialWinset
@ -226,7 +218,7 @@ launch initxmc = do
runX cf st $ do
-- check for serialized state in a file.
serializedSt <- do
path <- stateFileName
path <- asks $ stateFileName . directories
exists <- io (doesFileExist path)
if exists then readStateFile initxmc else return Nothing
@ -234,7 +226,7 @@ launch initxmc = do
let extst = maybe M.empty extensibleState serializedSt
modify (\s -> s {extensibleState = extst})
setNumlockMask
cacheNumlockMask
grabKeys
grabButtons
@ -255,8 +247,11 @@ launch initxmc = do
userCode $ startupHook initxmc
rrData <- io $ xrrQueryExtension dpy
let rrUpdate = when (isJust rrData) . void . xrrUpdateConfiguration
-- main loop, for all you HOF/recursion fans out there.
forever $ prehandle =<< io (nextEvent dpy e >> getEvent e)
forever $ prehandle =<< io (nextEvent dpy e >> rrUpdate e >> getEvent e)
return ()
where
@ -305,16 +300,21 @@ handle (MapRequestEvent {ev_window = w}) = withDisplay $ \dpy -> do
-- window destroyed, unmanage it
-- window gone, unmanage it
handle (DestroyWindowEvent {ev_window = w}) = whenX (isClient w) $ do
-- broadcast to layouts
handle e@(DestroyWindowEvent {ev_window = w}) = do
whenX (isClient w) $ do
unmanage w
modify (\s -> s { mapped = S.delete w (mapped s)
, waitingUnmap = M.delete w (waitingUnmap s)})
-- the window is already unmanged, but we broadcast the event to all layouts
-- to trigger garbage-collection in case they hold window-specific resources
broadcastMessage e
-- We track expected unmap events in waitingUnmap. We ignore this event unless
-- it is synthetic or we are not expecting an unmap notification from a window.
handle (UnmapEvent {ev_window = w, ev_send_event = synthetic}) = whenX (isClient w) $ do
e <- gets (fromMaybe 0 . M.lookup w . waitingUnmap)
if (synthetic || e == 0)
if synthetic || e == 0
then unmanage w
else modify (\s -> s { waitingUnmap = M.update mpred w (waitingUnmap s) })
where mpred 1 = Nothing
@ -324,7 +324,7 @@ handle (UnmapEvent {ev_window = w, ev_send_event = synthetic}) = whenX (isClient
handle e@(MappingNotifyEvent {}) = do
io $ refreshKeyboardMapping e
when (ev_request e `elem` [mappingKeyboard, mappingModifier]) $ do
setNumlockMask
cacheNumlockMask
grabKeys
-- handle button release, which may finish dragging.
@ -368,7 +368,9 @@ handle e@(CrossingEvent {ev_window = w, ev_event_type = t})
dpy <- asks display
root <- asks theRoot
(_, _, w', _, _, _, _, _) <- io $ queryPointer dpy root
when (w == w') (focus w)
-- 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})
@ -410,7 +412,7 @@ handle event@(PropertyEvent { ev_event_type = t, ev_atom = a })
handle e@ClientMessageEvent { ev_message_type = mt } = do
a <- getAtom "XMONAD_RESTART"
if (mt == a)
if mt == a
then restart "xmonad" True
else broadcastMessage e
@ -441,37 +443,16 @@ scan dpy rootw = do
skip :: E.SomeException -> IO Bool
skip _ = return False
setNumlockMask :: X ()
setNumlockMask = do
dpy <- asks display
ms <- io $ getModifierMapping dpy
xs <- sequence [ do
ks <- io $ keycodeToKeysym dpy kc 0
if ks == xK_Num_Lock
then return (setBit 0 (fromIntegral m))
else return (0 :: KeyMask)
| (m, kcs) <- ms, kc <- kcs, kc /= 0]
modify (\s -> s { numberlockMask = foldr (.|.) 0 xs })
-- | Grab the keys back
grabKeys :: X ()
grabKeys = do
XConf { display = dpy, theRoot = rootw } <- ask
let grab kc m = io $ grabKey dpy kc m rootw True grabModeAsync grabModeAsync
(minCode, maxCode) = displayKeycodes dpy
allCodes = [fromIntegral minCode .. fromIntegral maxCode]
io $ ungrabKey dpy anyKey anyModifier rootw
ks <- asks keyActions
-- build a map from keysyms to lists of keysyms (doing what
-- XGetKeyboardMapping would do if the X11 package bound it)
syms <- forM allCodes $ \code -> io (keycodeToKeysym dpy code 0)
let keysymMap = M.fromListWith (++) (zip syms [[code] | code <- allCodes])
keysymToKeycodes sym = M.findWithDefault [] sym keysymMap
forM_ (M.keys ks) $ \(mask,sym) ->
forM_ (keysymToKeycodes sym) $ \kc ->
mapM_ (grab kc . (mask .|.)) =<< extraModifiers
let grab :: (KeyMask, KeyCode) -> X ()
grab (km, kc) = io $ grabKey dpy kc km rootw True grabModeAsync grabModeAsync
traverse_ grab =<< mkGrabs =<< asks (M.keys . keyActions)
-- | XXX comment me
-- | Grab the buttons
grabButtons :: X ()
grabButtons = do
XConf { display = dpy, theRoot = rootw } <- ask
@ -480,37 +461,4 @@ grabButtons = do
io $ ungrabButton dpy anyButton anyModifier rootw
ems <- extraModifiers
ba <- asks buttonActions
mapM_ (\(m,b) -> mapM_ (grab b . (m .|.)) ems) (M.keys $ ba)
-- | @replace@ to signals compliant window managers to exit.
replace :: Display -> ScreenNumber -> Window -> IO ()
replace dpy dflt rootw = do
-- check for other WM
wmSnAtom <- internAtom dpy ("WM_S" ++ show dflt) False
currentWmSnOwner <- xGetSelectionOwner dpy wmSnAtom
when (currentWmSnOwner /= 0) $ do
-- prepare to receive destroyNotify for old WM
selectInput dpy currentWmSnOwner structureNotifyMask
-- create off-screen window
netWmSnOwner <- allocaSetWindowAttributes $ \attributes -> do
set_override_redirect attributes True
set_event_mask attributes propertyChangeMask
let screen = defaultScreenOfDisplay dpy
visual = defaultVisualOfScreen screen
attrmask = cWOverrideRedirect .|. cWEventMask
createWindow dpy rootw (-100) (-100) 1 1 0 copyFromParent copyFromParent visual attrmask attributes
-- try to acquire wmSnAtom, this should signal the old WM to terminate
xSetSelectionOwner dpy wmSnAtom netWmSnOwner currentTime
-- SKIPPED: check if we acquired the selection
-- SKIPPED: send client message indicating that we are now the WM
-- wait for old WM to go away
fix $ \again -> do
evt <- allocaXEvent $ \event -> do
windowEvent dpy currentWmSnOwner structureNotifyMask event
get_EventType event
when (evt /= destroyNotify) again
mapM_ (\(m,b) -> mapM_ (grab b . (m .|.)) ems) (M.keys ba)

View File

@ -1,5 +1,3 @@
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.ManageHook
@ -8,7 +6,6 @@
--
-- Maintainer : spencerjanssen@gmail.com
-- Stability : unstable
-- Portability : not portable, uses cunning newtype deriving
--
-- An EDSL for ManageHooks
--
@ -21,13 +18,13 @@ module XMonad.ManageHook where
import XMonad.Core
import Graphics.X11.Xlib.Extras
import Graphics.X11.Xlib (Display, Window, internAtom, wM_NAME)
import Control.Exception.Extensible (bracket, SomeException(..))
import qualified Control.Exception.Extensible as E
import Control.Exception (bracket, SomeException(..))
import qualified Control.Exception as E
import Control.Monad.Reader
import Data.Maybe
import Data.Monoid
import qualified XMonad.StackSet as W
import XMonad.Operations (floatLocation, reveal)
import XMonad.Operations (floatLocation, reveal, isFixedSizeOrTransient)
-- | Lift an 'X' action to a 'Query'.
liftX :: X a -> Query a
@ -61,13 +58,14 @@ infixr 3 <&&>, <||>
-- | '&&' lifted to a 'Monad'.
(<&&>) :: Monad m => m Bool -> m Bool -> m Bool
(<&&>) = liftM2 (&&)
x <&&> y = ifM x y (pure False)
-- | '||' lifted to a 'Monad'.
(<||>) :: Monad m => m Bool -> m Bool -> m Bool
(<||>) = liftM2 (||)
x <||> y = ifM x (pure True) y
-- | Return the window title.
-- | Return the window title; i.e., the string returned by @_NET_WM_NAME@,
-- or failing that, the string returned by @WM_NAME@.
title :: Query String
title = ask >>= \w -> liftX $ do
d <- asks display
@ -76,10 +74,11 @@ title = ask >>= \w -> liftX $ do
(internAtom d "_NET_WM_NAME" False >>= getTextProperty d w)
`E.catch` \(SomeException _) -> getTextProperty d w wM_NAME
extract prop = do l <- wcTextPropertyToTextList d prop
return $ if null l then "" else head l
return $ fromMaybe "" $ listToMaybe l
io $ bracket getProp (xFree . tp_value) extract `E.catch` \(SomeException _) -> return ""
-- | Return the application name.
-- | Return the application name; i.e., the /first/ string returned by
-- @WM_CLASS@.
appName :: Query String
appName = ask >>= (\w -> liftX $ withDisplay $ \d -> fmap resName $ io $ getClassHint d w)
@ -87,14 +86,17 @@ appName = ask >>= (\w -> liftX $ withDisplay $ \d -> fmap resName $ io $ getClas
resource :: Query String
resource = appName
-- | Return the resource class.
-- | Return the resource class; i.e., the /second/ string returned by
-- @WM_CLASS@.
className :: Query String
className = ask >>= (\w -> liftX $ withDisplay $ \d -> fmap resClass $ io $ getClassHint d w)
-- | A query that can return an arbitrary X property of type 'String',
-- identified by name.
-- identified by name. Works for ASCII strings only. For the properties
-- @_NET_WM_NAME@/@WM_NAME@ and @WM_CLASS@ the specialised variants 'title'
-- and 'appName'/'className' are preferred.
stringProperty :: String -> Query String
stringProperty p = ask >>= (\w -> liftX $ withDisplay $ \d -> fmap (fromMaybe "") $ getStringProperty d w p)
stringProperty p = ask >>= (\w -> liftX $ withDisplay $ \d -> fromMaybe "" <$> getStringProperty d w p)
getStringProperty :: Display -> Window -> String -> X (Maybe String)
getStringProperty d w p = do
@ -102,6 +104,10 @@ getStringProperty d w p = do
md <- io $ getWindowProperty8 d a w
return $ fmap (map (toEnum . fromIntegral)) md
-- | Return whether the window will be a floating window or not
willFloat :: Query Bool
willFloat = ask >>= \w -> liftX $ withDisplay $ \d -> isFixedSizeOrTransient d w
-- | Modify the 'WindowSet' with a pure function.
doF :: (s -> s) -> Query (Endo s)
doF = return . Endo

View File

@ -1,5 +1,10 @@
{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# LANGUAGE FlexibleContexts, FlexibleInstances, MultiParamTypeClasses, PatternGuards, TypeSynonymInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE ScopedTypeVariables #-}
-- --------------------------------------------------------------------------
-- |
-- Module : XMonad.Operations
@ -8,31 +13,69 @@
--
-- Maintainer : dons@cse.unsw.edu.au
-- Stability : unstable
-- Portability : not portable, Typeable deriving, mtl, posix
-- Portability : not portable, mtl, posix
--
-- Operations.
-- Operations. A module for functions that don't cleanly fit anywhere else.
--
-----------------------------------------------------------------------------
module XMonad.Operations where
module XMonad.Operations (
-- * Manage One Window
manage, unmanage, killWindow, kill, isClient,
setInitialProperties, setWMState, setWindowBorderWithFallback,
hide, reveal, tileWindow,
setTopFocus, focus, isFixedSizeOrTransient,
-- * Manage Windows
windows, refresh, rescreen, modifyWindowSet, windowBracket, windowBracket_, clearEvents, getCleanedScreenInfo,
withFocused, withUnfocused,
-- * Keyboard and Mouse
cleanMask, extraModifiers,
mouseDrag, mouseMoveWindow, mouseResizeWindow,
setButtonGrab, setFocusX, cacheNumlockMask, mkGrabs, unGrab,
-- * Messages
sendMessage, broadcastMessage, sendMessageWithNoRefresh,
sendRestart, sendReplace,
-- * Save and Restore State
StateFile (..), writeStateToFile, readStateFile, restart,
-- * Floating Layer
float, floatLocation,
-- * Window Size Hints
D, mkAdjust, applySizeHints, applySizeHints', applySizeHintsContents,
applyAspectHint, applyResizeIncHint, applyMaxSizeHint,
-- * Rectangles
containedIn, nubScreens, pointWithin, scaleRationalRect,
-- * Other Utilities
initColor, pointScreen, screenWorkspace,
setLayout, updateLayout,
) where
import XMonad.Core
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.Bits ((.|.), (.&.), complement, setBit, testBit)
import Data.Function (on)
import Data.Ratio
import qualified Data.Map as M
import qualified Data.Set as S
import Control.Applicative
import Control.Arrow (second)
import Control.Monad.Fix (fix)
import Control.Monad.Reader
import Control.Monad.State
import qualified Control.Exception.Extensible as C
import Control.Monad (forM, forM_, guard, join, unless, void, when)
import qualified Control.Exception as C
import System.IO
import System.Directory
@ -42,9 +85,20 @@ import Graphics.X11.Xinerama (getScreenInfo)
import Graphics.X11.Xlib.Extras
-- ---------------------------------------------------------------------
-- |
-- Window manager operations
-- manage. Add a new window to be managed in the current workspace.
-- | Detect whether a window has fixed size or is transient. This check
-- can be used to determine whether the window should be floating or not
--
isFixedSizeOrTransient :: Display -> Window -> X Bool
isFixedSizeOrTransient d w = do
sh <- io $ getWMNormalHints d w
let isFixedSize = isJust (sh_min_size sh) && sh_min_size sh == sh_max_size sh
isTransient <- isJust <$> io (getTransientForHint d w)
return (isFixedSize || isTransient)
-- |
-- Add a new window to be managed in the current workspace.
-- Bring it into focus.
--
-- Whether the window is already managed, or not, it is mapped, has its
@ -52,10 +106,8 @@ import Graphics.X11.Xlib.Extras
--
manage :: Window -> X ()
manage w = whenX (not <$> isClient w) $ withDisplay $ \d -> do
sh <- io $ getWMNormalHints d w
let isFixedSize = sh_min_size sh /= Nothing && sh_min_size sh == sh_max_size sh
isTransient <- isJust <$> io (getTransientForHint d w)
shouldFloat <- isFixedSizeOrTransient d w
rr <- snd `fmap` floatLocation w
-- ensure that float windows don't go over the edge of the screen
@ -63,15 +115,15 @@ manage w = whenX (not <$> isClient w) $ withDisplay $ \d -> do
= W.RationalRect (0.5 - wid/2) (0.5 - h/2) wid h
adjust r = r
f ws | isFixedSize || isTransient = W.float w (adjust rr) . W.insertUp w . W.view i $ ws
| otherwise = W.insertUp w ws
f ws | shouldFloat = W.float w (adjust rr) . W.insertUp w . W.view i $ ws
| otherwise = W.insertUp w ws
where i = W.tag $ W.workspace $ W.current ws
mh <- asks (manageHook . config)
g <- appEndo <$> userCodeDef (Endo id) (runQuery mh w)
windows (g . f)
-- | unmanage. A window no longer exists, remove it from the window
-- | A window no longer exists; remove it from the window
-- list, on whatever workspace it is.
--
unmanage :: Window -> X ()
@ -91,9 +143,9 @@ killWindow w = withDisplay $ \d -> do
io $ if wmdelt `elem` protocols
then allocaXEvent $ \ev -> do
setEventType ev clientMessage
setClientMessageEvent ev w wmprot 32 wmdelt 0
setClientMessageEvent ev w wmprot 32 wmdelt currentTime
sendEvent d w False noEventMask ev
else killClient d w >> return ()
else void (killClient d w)
-- | Kill the currently focused client.
kill :: X ()
@ -102,7 +154,7 @@ kill = withFocused killWindow
-- ---------------------------------------------------------------------
-- Managing windows
-- | windows. Modify the current window list with a pure function, and refresh
-- | Modify the current window list with a pure function, and refresh
windows :: (WindowSet -> WindowSet) -> X ()
windows f = do
XState { windowset = old } <- get
@ -144,7 +196,8 @@ windows f = do
let m = W.floating ws
flt = [(fw, scaleRationalRect viewrect r)
| fw <- filter (flip M.member m) (W.index this)
| fw <- filter (`M.member` m) (W.index this)
, fw `notElem` vis
, Just r <- [M.lookup fw m]]
vs = flt ++ rs
@ -170,38 +223,58 @@ windows f = do
-- all windows that are no longer in the windowset are marked as
-- withdrawn, it is important to do this after the above, otherwise 'hide'
-- will overwrite withdrawnState with iconicState
mapM_ (flip setWMState withdrawnState) (W.allWindows old \\ W.allWindows ws)
mapM_ (`setWMState` withdrawnState) (W.allWindows old \\ W.allWindows ws)
isMouseFocused <- asks mouseFocused
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 $ const old
windows $ const new
return a
-- | Perform an @X@ action. If it returns @Any True@, unwind the
-- changes to the @WindowSet@ and replay them using @windows@. This is
-- a version of @windowBracket@ that discards the return value and
-- handles an @X@ action that reports 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)
= Rectangle (sx + scale sw rx) (sy + scale sh ry) (scale sw rw) (scale sh rh)
where scale s r = floor (toRational s * r)
-- | setWMState. set the WM_STATE property
-- | Set a window's WM_STATE property.
setWMState :: Window -> Int -> X ()
setWMState w v = withDisplay $ \dpy -> do
a <- atom_WM_STATE
io $ changeProperty32 dpy w a a propModeReplace [fromIntegral v, fromIntegral none]
-- | Set the border color using the window's color map, if possible,
-- otherwise fallback to the color in @Pixel@.
-- | Set the border color using the window's color map, if possible;
-- otherwise fall back 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
pixel <- setPixelSolid . 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
fallback _ = setWindowBorder dpy w basic
-- | hide. Hide a window by unmapping it, and setting Iconified.
-- | Hide a window by unmapping it and setting Iconified.
hide :: Window -> X ()
hide w = whenX (gets (S.member w . mapped)) $ withDisplay $ \d -> do
cMask <- asks $ clientMask . config
@ -214,15 +287,15 @@ hide w = whenX (gets (S.member w . mapped)) $ withDisplay $ \d -> do
modify (\s -> s { waitingUnmap = M.insertWith (+) w 1 (waitingUnmap s)
, mapped = S.delete w (mapped s) })
-- | reveal. Show a window by mapping it and setting Normal
-- this is harmless if the window was already visible
-- | Show a window by mapping it and setting Normal.
-- This is harmless if the window was already visible.
reveal :: Window -> X ()
reveal w = withDisplay $ \d -> do
setWMState w normalState
io $ mapWindow d w
whenX (isClient w) $ modify (\s -> s { mapped = S.insert w (mapped s) })
-- | Set some properties when we initially gain control of a window
-- | Set some properties when we initially gain control of a window.
setInitialProperties :: Window -> X ()
setInitialProperties w = asks normalBorder >>= \nb -> withDisplay $ \d -> do
setWMState w iconicState
@ -233,7 +306,7 @@ setInitialProperties w = asks normalBorder >>= \nb -> withDisplay $ \d -> do
-- required by the border setting in 'windows'
io $ setWindowBorder d w nb
-- | refresh. Render the currently visible workspaces, as determined by
-- | Render the currently visible workspaces, as determined by
-- the 'StackSet'. Also, set focus to the focused window.
--
-- This is our 'view' operation (MVC), in that it pretty prints our model
@ -242,7 +315,7 @@ setInitialProperties w = asks normalBorder >>= \nb -> withDisplay $ \d -> do
refresh :: X ()
refresh = windows id
-- | clearEvents. Remove all events of a given type from the event queue.
-- | Remove all events of a given type from the event queue.
clearEvents :: EventMask -> X ()
clearEvents mask = withDisplay $ \d -> io $ do
sync d False
@ -250,8 +323,8 @@ clearEvents mask = withDisplay $ \d -> io $ do
more <- checkMaskEvent d mask p
when more again -- beautiful
-- | tileWindow. Moves and resizes w such that it fits inside the given
-- rectangle, including its border.
-- | Move and resize @w@ such that it fits inside the given rectangle,
-- including its border.
tileWindow :: Window -> Rectangle -> X ()
tileWindow w r = withDisplay $ \d -> withWindowAttributes d w $ \wa -> do
-- give all windows at least 1x1 pixels
@ -278,27 +351,28 @@ containedIn r1@(Rectangle x1 y1 w1 h1) r2@(Rectangle x2 y2 w2 h2)
nubScreens :: [Rectangle] -> [Rectangle]
nubScreens xs = nub . filter (\x -> not $ any (x `containedIn`) xs) $ xs
-- | Cleans the list of screens according to the rules documented for
-- | Clean the list of screens according to the rules documented for
-- nubScreens.
getCleanedScreenInfo :: MonadIO m => Display -> m [Rectangle]
getCleanedScreenInfo = io . fmap nubScreens . getScreenInfo
-- | rescreen. The screen configuration may have changed (due to
-- xrandr), update the state and refresh the screen, and reset the gap.
-- | The screen configuration may have changed (due to -- xrandr),
-- update the state and refresh the screen, and reset the gap.
rescreen :: X ()
rescreen = do
xinesc <- withDisplay getCleanedScreenInfo
windows $ \ws@(W.StackSet { W.current = v, W.visible = vs, W.hidden = hs }) ->
let (xs, ys) = splitAt (length xinesc) $ map W.workspace (v:vs) ++ hs
(a:as) = zipWith3 W.Screen xs [0..] $ map SD xinesc
in ws { W.current = a
, W.visible = as
, W.hidden = ys }
rescreen = withDisplay getCleanedScreenInfo >>= \case
[] -> trace "getCleanedScreenInfo returned []"
xinesc:xinescs ->
windows $ \ws@W.StackSet{ W.current = v, W.visible = vs, W.hidden = hs } ->
let (xs, ys) = splitAt (length xinescs) (map W.workspace vs ++ hs)
a = W.Screen (W.workspace v) 0 (SD xinesc)
as = zipWith3 W.Screen xs [1..] $ map SD xinescs
in ws { W.current = a
, W.visible = as
, W.hidden = ys }
-- ---------------------------------------------------------------------
-- | setButtonGrab. Tell whether or not to intercept clicks on a given window
-- | Tell whether or not to intercept clicks on a given window
setButtonGrab :: Bool -> Window -> X ()
setButtonGrab grab w = do
pointerMode <- asks $ \c -> if clickJustFocuses (config c)
@ -353,7 +427,7 @@ setFocusX w = withWindowSet $ \ws -> do
currevt <- asks currentEvent
let inputHintSet = wmh_flags hints `testBit` inputHintBit
when ((inputHintSet && wmh_input hints) || (not inputHintSet)) $
when (inputHintSet && wmh_input hints || not inputHintSet) $
io $ do setInputFocus dpy w revertToPointerRoot 0
when (wmtf `elem` protocols) $
io $ allocaXEvent $ \ev -> do
@ -361,56 +435,171 @@ setFocusX w = withWindowSet $ \ws -> do
setClientMessageEvent ev w wmprot 32 wmtf $ maybe currentTime event_time currevt
sendEvent dpy w False noEventMask ev
where event_time ev =
if (ev_event_type ev) `elem` timedEvents then
if ev_event_type ev `elem` timedEvents then
ev_time ev
else
currentTime
timedEvents = [ keyPress, keyRelease, buttonPress, buttonRelease, enterNotify, leaveNotify, selectionRequest ]
cacheNumlockMask :: X ()
cacheNumlockMask = do
dpy <- asks display
ms <- io $ getModifierMapping dpy
xs <- sequence [ do ks <- io $ keycodeToKeysym dpy kc 0
if ks == xK_Num_Lock
then return (setBit 0 (fromIntegral m))
else return (0 :: KeyMask)
| (m, kcs) <- ms, kc <- kcs, kc /= 0
]
modify (\s -> s { numberlockMask = foldr (.|.) 0 xs })
-- | Given a list of keybindings, turn the given 'KeySym's into actual
-- 'KeyCode's and prepare them for grabbing.
mkGrabs :: [(KeyMask, KeySym)] -> X [(KeyMask, KeyCode)]
mkGrabs ks = withDisplay $ \dpy -> do
let (minCode, maxCode) = displayKeycodes dpy
allCodes = [fromIntegral minCode .. fromIntegral maxCode]
-- build a map from keysyms to lists of keysyms (doing what
-- XGetKeyboardMapping would do if the X11 package bound it)
syms <- forM allCodes $ \code -> io (keycodeToKeysym dpy code 0)
let -- keycodeToKeysym returns noSymbol for all unbound keycodes,
-- and we don't want to grab those whenever someone accidentally
-- uses def :: KeySym
keysymMap = M.delete noSymbol $
M.fromListWith (++) (zip syms [[code] | code <- allCodes])
keysymToKeycodes sym = M.findWithDefault [] sym keysymMap
extraMods <- extraModifiers
pure [ (mask .|. extraMod, keycode)
| (mask, sym) <- ks
, keycode <- keysymToKeycodes sym
, extraMod <- extraMods
]
-- | Release XMonad's keyboard grab, so other grabbers can do their thing.
--
-- Start a keyboard action with this if it is going to run something
-- that needs to do a keyboard, pointer, or server grab. For example,
--
-- > , ((modm .|. controlMask, xK_p), unGrab >> spawn "scrot")
--
-- (Other examples are certain screen lockers and "gksu".)
-- This avoids needing to insert a pause/sleep before running the
-- command.
--
-- XMonad retains the keyboard grab during key actions because if they
-- use a submap, they need the keyboard to be grabbed, and if they had
-- to assert their own grab then the asynchronous nature of X11 allows
-- race conditions between XMonad, other clients, and the X server that
-- would cause keys to sometimes be "leaked" to the focused window.
unGrab :: X ()
unGrab = withDisplay $ \d -> io $ do
ungrabKeyboard d currentTime
ungrabPointer d currentTime
sync d False
------------------------------------------------------------------------
-- 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
w <- W.workspace . W.current <$> gets windowset
sendMessage a = windowBracket_ $ do
w <- gets $ W.workspace . W.current . 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 ()
broadcastMessage a = withWindowSet $ \ws -> do
let c = W.workspace . W.current $ ws
v = map W.workspace . W.visible $ ws
h = W.hidden ws
mapM_ (sendMessageWithNoRefresh a) (c : v ++ h)
-- this is O(n²), but we can't really fix this as there's code in
-- xmonad-contrib that touches the windowset during handleMessage
-- (returning Nothing for changes to not get overwritten), so we
-- unfortunately need to do this one by one and persist layout states
-- of each workspace separately)
let c = W.workspace . W.current $ ws
v = map W.workspace . W.visible $ ws
h = W.hidden ws
mapM_ (sendMessageWithNoRefresh a) (c : v ++ h)
-- | Send a message to a layout, without refreshing.
sendMessageWithNoRefresh :: Message a => a -> W.Workspace WorkspaceId (Layout Window) Window -> X ()
sendMessageWithNoRefresh :: Message a => a -> WindowSpace -> X ()
sendMessageWithNoRefresh a w =
handleMessage (W.layout w) (SomeMessage a) `catchX` return Nothing >>=
updateLayout (W.tag w)
-- | Update the layout field of a workspace
-- | Update the layout field of a workspace.
updateLayout :: WorkspaceId -> Maybe (Layout Window) -> X ()
updateLayout i ml = whenJust ml $ \l ->
runOnWorkspaces $ \ww -> return $ if W.tag ww == i then ww { W.layout = l} else ww
-- | Set the layout of the currently viewed workspace
-- | Set the layout of the currently viewed workspace.
setLayout :: Layout Window -> X ()
setLayout l = do
ss@(W.StackSet { W.current = c@(W.Screen { W.workspace = ws })}) <- gets windowset
ss@W.StackSet{ W.current = c@W.Screen{ W.workspace = ws }} <- gets windowset
handleMessage (W.layout ws) (SomeMessage ReleaseResources)
windows $ const $ ss {W.current = c { W.workspace = ws { W.layout = l } } }
windows $ const $ ss{ W.current = c{ W.workspace = ws{ W.layout = l } } }
-- | Signal xmonad to restart itself.
sendRestart :: IO ()
sendRestart = do
dpy <- openDisplay ""
rw <- rootWindow dpy $ defaultScreen dpy
xmonad_restart <- internAtom dpy "XMONAD_RESTART" False
allocaXEvent $ \e -> do
setEventType e clientMessage
setClientMessageEvent' e rw xmonad_restart 32 []
sendEvent dpy rw False structureNotifyMask e
sync dpy False
-- | Signal compliant window managers to exit.
sendReplace :: IO ()
sendReplace = do
dpy <- openDisplay ""
let dflt = defaultScreen dpy
rootw <- rootWindow dpy dflt
replace dpy dflt rootw
-- | Signal compliant window managers to exit.
replace :: Display -> ScreenNumber -> Window -> IO ()
replace dpy dflt rootw = do
-- check for other WM
wmSnAtom <- internAtom dpy ("WM_S" ++ show dflt) False
currentWmSnOwner <- xGetSelectionOwner dpy wmSnAtom
when (currentWmSnOwner /= 0) $ do
-- prepare to receive destroyNotify for old WM
selectInput dpy currentWmSnOwner structureNotifyMask
-- create off-screen window
netWmSnOwner <- allocaSetWindowAttributes $ \attributes -> do
set_override_redirect attributes True
set_event_mask attributes propertyChangeMask
let screen = defaultScreenOfDisplay dpy
visual = defaultVisualOfScreen screen
attrmask = cWOverrideRedirect .|. cWEventMask
createWindow dpy rootw (-100) (-100) 1 1 0 copyFromParent copyFromParent visual attrmask attributes
-- try to acquire wmSnAtom, this should signal the old WM to terminate
xSetSelectionOwner dpy wmSnAtom netWmSnOwner currentTime
-- SKIPPED: check if we acquired the selection
-- SKIPPED: send client message indicating that we are now the WM
-- wait for old WM to go away
fix $ \again -> do
evt <- allocaXEvent $ \event -> do
windowEvent dpy currentWmSnOwner structureNotifyMask event
get_EventType event
when (evt /= destroyNotify) again
------------------------------------------------------------------------
-- Utilities
-- | Return workspace visible on screen 'sc', or 'Nothing'.
-- | Return workspace visible on screen @sc@, or 'Nothing'.
screenWorkspace :: ScreenId -> X (Maybe WorkspaceId)
screenWorkspace sc = withWindowSet $ return . W.lookupWorkspace sc
@ -418,7 +607,14 @@ screenWorkspace sc = withWindowSet $ return . W.lookupWorkspace sc
withFocused :: (Window -> X ()) -> X ()
withFocused f = withWindowSet $ \w -> whenJust (W.peek w) f
-- | 'True' if window is under management by us
-- | Apply an 'X' operation to all unfocused windows on the current workspace, if there are any.
withUnfocused :: (Window -> X ()) -> X ()
withUnfocused f = withWindowSet $ \ws ->
whenJust (W.peek ws) $ \w ->
let unfocusedWindows = filter (/= w) $ W.index ws
in mapM_ f unfocusedWindows
-- | Is the window is under management by xmonad?
isClient :: Window -> X Bool
isClient w = withWindowSet $ return . W.member w
@ -429,16 +625,20 @@ extraModifiers = do
nlm <- gets numberlockMask
return [0, nlm, lockMask, nlm .|. lockMask ]
-- | Strip numlock\/capslock from a mask
-- | Strip numlock\/capslock from a mask.
cleanMask :: KeyMask -> X KeyMask
cleanMask km = do
nlm <- gets numberlockMask
return (complement (nlm .|. lockMask) .&. km)
-- | Get the 'Pixel' value for a named color
-- | Set the 'Pixel' alpha value to 255.
setPixelSolid :: Pixel -> Pixel
setPixelSolid p = p .|. 0xff000000
-- | Get the 'Pixel' value for a named color.
initColor :: Display -> String -> IO (Maybe Pixel)
initColor dpy c = C.handle (\(C.SomeException _) -> return Nothing) $
(Just . color_pixel . fst) <$> allocNamedColor dpy colormap c
Just . setPixelSolid . color_pixel . fst <$> allocNamedColor dpy colormap c
where colormap = defaultColormap dpy (defaultScreen dpy)
------------------------------------------------------------------------
@ -458,21 +658,28 @@ writeStateToFile = do
maybeShow _ = Nothing
wsData = W.mapLayout show . windowset
extState = catMaybes . map maybeShow . M.toList . extensibleState
extState = mapMaybe maybeShow . M.toList . extensibleState
path <- stateFileName
path <- asks $ stateFileName . directories
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.
-- 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
raw <- userCode $ io (readFile path)
path <- asks $ stateFileName . directories
-- 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 <- maybeRead reads =<< raw
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
@ -491,23 +698,11 @@ readStateFile xmc = do
[(x, "")] -> Just x
_ -> Nothing
-- | 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
readStrict :: Handle -> IO String
readStrict h = hGetContents h >>= \s -> length s `seq` return s
-- | @restart name resume@. Attempt to restart xmonad by executing the program
-- @name@. If @resume@ is 'True', restart with the current window state.
-- | @restart name resume@ attempts to restart xmonad by executing the program
-- @name@. If @resume@ is 'True', restart with the current window state.
-- When executing another window manager, @resume@ should be 'False'.
restart :: String -> Bool -> X ()
restart prog resume = do
@ -517,33 +712,49 @@ restart prog resume = do
catchIO (executeFile prog True [] Nothing)
------------------------------------------------------------------------
-- | Floating layer support
-- Floating layer support
-- | Given a window, find the screen it is located on, and compute
-- the geometry of that window wrt. that screen.
-- the geometry of that window WRT that screen.
floatLocation :: Window -> X (ScreenId, W.RationalRect)
floatLocation w =
catchX go $ do
-- Fallback solution if `go' fails. Which it might, since it
-- calls `getWindowAttributes'.
sc <- W.current <$> gets windowset
sc <- gets $ W.current . windowset
return (W.screen sc, W.RationalRect 0 0 1 1)
where fi x = fromIntegral x
go = withDisplay $ \d -> do
where go = withDisplay $ \d -> do
ws <- gets windowset
sh <- io $ getWMNormalHints d w
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)
point_sc <- pointScreen (fi $ wa_x wa) (fi $ wa_y wa)
managed <- isClient w
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))
-- ignore pointScreen for new windows unless it's the current
-- screen, otherwise the float's relative size is computed against
-- a different screen and the float ends up with the wrong size
let sr_eq = (==) `on` fmap (screenRect . W.screenDetail)
sc = fromMaybe (W.current ws) $
if managed || point_sc `sr_eq` Just (W.current ws) then point_sc else Nothing
sr = screenRect . W.screenDetail $ sc
x = (fi (wa_x wa) - fi (rect_x sr)) % fi (rect_width sr)
y = (fi (wa_y wa) - fi (rect_y sr)) % fi (rect_height sr)
(width, height) = applySizeHintsContents sh (wa_width wa, wa_height wa)
rwidth = fi (width + bw*2) % fi (rect_width sr)
rheight = fi (height + bw*2) % fi (rect_height sr)
-- adjust x/y of unmanaged windows if we ignored or didn't get pointScreen,
-- it might be out of bounds otherwise
rr = if managed || point_sc `sr_eq` Just sc
then W.RationalRect x y rwidth rheight
else W.RationalRect (0.5 - rwidth/2) (0.5 - rheight/2) rwidth rheight
return (W.screen sc, rr)
fi :: (Integral a, Num b) => a -> b
fi = fromIntegral
-- | Given a point, determine the screen (if any) that contains it.
pointScreen :: Position -> Position
-> X (Maybe (W.Screen WorkspaceId (Layout Window) Window ScreenId ScreenDetail))
@ -574,14 +785,20 @@ float w = do
-- | Accumulate mouse motion events
mouseDrag :: (Position -> Position -> X ()) -> X () -> X ()
mouseDrag f done = do
mouseDrag = mouseDragCursor Nothing
-- | Like 'mouseDrag', but with the ability to specify a custom cursor
-- shape.
mouseDragCursor :: Maybe Glyph -> (Position -> Position -> X ()) -> X () -> X ()
mouseDragCursor cursorGlyph f done = do
drag <- gets dragging
case drag of
Just _ -> return () -- error case? we're already dragging
Nothing -> do
XConf { theRoot = root, display = d } <- ask
io $ grabPointer d root False (buttonReleaseMask .|. pointerMotionMask)
grabModeAsync grabModeAsync none none currentTime
io $ do cursor <- maybe (pure none) (createFontCursor d) cursorGlyph
grabPointer d root False (buttonReleaseMask .|. pointerMotionMask)
grabModeAsync grabModeAsync none cursor currentTime
modify $ \s -> s { dragging = Just (motion, cleanup) }
where
cleanup = do
@ -592,39 +809,41 @@ mouseDrag f done = do
clearEvents pointerMotionMask
return z
-- | drag the window under the cursor with the mouse while it is dragged
-- | Drag the window under the cursor with the mouse while it is dragged.
mouseMoveWindow :: Window -> X ()
mouseMoveWindow w = whenX (isClient w) $ withDisplay $ \d -> do
io $ raiseWindow d w
wa <- io $ getWindowAttributes d w
(_, _, _, ox', oy', _, _, _) <- io $ queryPointer d w
let ox = fromIntegral ox'
oy = fromIntegral oy'
mouseDrag (\ex ey -> do
mouseDragCursor
(Just xC_fleur)
(\ex ey -> do
io $ moveWindow d w (fromIntegral (fromIntegral (wa_x wa) + (ex - ox)))
(fromIntegral (fromIntegral (wa_y wa) + (ey - oy)))
float w
)
(float w)
-- | resize the window under the cursor with the mouse while it is dragged
-- | Resize the window under the cursor with the mouse while it is dragged.
mouseResizeWindow :: Window -> X ()
mouseResizeWindow w = whenX (isClient w) $ withDisplay $ \d -> do
io $ raiseWindow d w
wa <- io $ getWindowAttributes d w
sh <- io $ getWMNormalHints d w
io $ warpPointer d none w 0 0 0 0 (fromIntegral (wa_width wa)) (fromIntegral (wa_height wa))
mouseDrag (\ex ey -> do
mouseDragCursor
(Just xC_bottom_right_corner)
(\ex ey -> do
io $ resizeWindow d w `uncurry`
applySizeHintsContents sh (ex - fromIntegral (wa_x wa),
ey - fromIntegral (wa_y wa))
float w)
(float w)
-- ---------------------------------------------------------------------
-- | Support for window size hints
-- Support for window size hints
-- | An alias for a (width, height) pair
type D = (Dimension, Dimension)
-- | Given a window, build an adjuster function that will reduce the given
@ -634,7 +853,7 @@ mkAdjust w = withDisplay $ \d -> liftIO $ do
sh <- getWMNormalHints d w
wa <- C.try $ getWindowAttributes d w
case wa of
Left err -> const (return id) (err :: C.SomeException)
Left (_ :: C.SomeException) -> return id
Right wa' ->
let bw = fromIntegral $ wa_border_width wa'
in return $ applySizeHints bw sh
@ -652,7 +871,7 @@ applySizeHintsContents :: Integral a => SizeHints -> (a, a) -> D
applySizeHintsContents sh (w, h) =
applySizeHints' sh (fromIntegral $ max 1 w, fromIntegral $ max 1 h)
-- | XXX comment me
-- | Use X11 size hints to scale a pair of dimensions.
applySizeHints' :: SizeHints -> D -> D
applySizeHints' sh =
maybe id applyMaxSizeHint (sh_max_size sh)

View File

@ -1,4 +1,5 @@
{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE DeriveFunctor #-}
-----------------------------------------------------------------------------
-- |
@ -52,9 +53,13 @@ module XMonad.StackSet (
) where
import Prelude hiding (filter)
import Control.Applicative.Backwards (Backwards (Backwards, forwards))
import Data.Foldable (foldr, toList)
import Data.Maybe (listToMaybe,isJust,fromMaybe)
import qualified Data.List as L (deleteBy,find,splitAt,filter,nub)
import Data.List ( (\\) )
import qualified Data.List.NonEmpty as NE
import Data.List.NonEmpty (NonEmpty((:|)))
import qualified Data.Map as M (Map,insert,delete,empty)
-- $intro
@ -85,25 +90,27 @@ import qualified Data.Map as M (Map,insert,delete,empty)
-- continuation reified as a data structure.
--
-- The Zipper lets us replace an item deep in a complex data
-- structure, e.g., a tree or a term, without an mutation. The
-- structure, e.g., a tree or a term, without a mutation. The
-- resulting data structure will share as much of its components with
-- the old structure as possible.
--
-- Oleg Kiselyov, 27 Apr 2005, haskell\@, "Zipper as a delimited continuation"
-- <https://mail.haskell.org/pipermail/haskell/2005-April/015769.html Oleg Kiselyov, 27 Apr 2005, haskell\@, "Zipper as a delimited continuation">
--
-- We use the zipper to keep track of the focused workspace and the
-- focused window on each workspace, allowing us to have correct focus
-- by construction. We closely follow Huet's original implementation:
--
-- G. Huet, /Functional Pearl: The Zipper/,
-- 1997, J. Functional Programming 75(5):549-554.
-- and:
-- R. Hinze and J. Jeuring, /Functional Pearl: The Web/.
-- <https://www.st.cs.uni-saarland.de/edu/seminare/2005/advanced-fp/docs/huet-zipper.pdf G. Huet, Functional Pearl: The Zipper; 1997, J. Functional Programming 75(5):549554>
--
-- and Conor McBride's zipper differentiation paper.
-- Another good reference is:
-- and
--
-- The Zipper, Haskell wikibook
-- <https://dspace.library.uu.nl/handle/1874/2532 R. Hinze and J. Jeuring, Functional Pearl: Weaving a Web>
--
-- and
--
-- <http://strictlypositive.org/diff.pdf Conor McBride, The Derivative of a Regular Type is its Type of One-Hole Contexts>.
--
-- Another good reference is: <https://wiki.haskell.org/Zipper The Zipper, Haskell wikibook>
-- $xinerama
-- Xinerama in X11 lets us view multiple virtual workspaces
@ -151,7 +158,7 @@ data Workspace i l a = Workspace { tag :: !i, layout :: l, stack :: Maybe (Stac
deriving (Show, Read, Eq)
-- | A structure for window geometries
data RationalRect = RationalRect Rational Rational Rational Rational
data RationalRect = RationalRect !Rational !Rational !Rational !Rational
deriving (Show, Read, Eq)
-- |
@ -175,8 +182,19 @@ data RationalRect = RationalRect Rational Rational Rational Rational
data Stack a = Stack { focus :: !a -- focused thing in this set
, up :: [a] -- clowns to the left
, down :: [a] } -- jokers to the right
deriving (Show, Read, Eq)
deriving (Show, Read, Eq, Functor)
instance Foldable Stack where
toList = integrate
foldr f z = foldr f z . toList
instance Traversable Stack where
traverse f s =
flip Stack
-- 'Backwards' applies the Applicative in reverse order.
<$> forwards (traverse (Backwards . f) (up s))
<*> f (focus s)
<*> traverse f (down s)
-- | this function indicates to catch that an error is expected
abort :: String -> a
@ -194,10 +212,11 @@ abort x = error $ "xmonad: StackSet: " ++ x
-- Xinerama: Virtual workspaces are assigned to physical screens, starting at 0.
--
new :: (Integral s) => l -> [i] -> [sd] -> StackSet i l a s sd
new l wids m | not (null wids) && length m <= length wids && not (null m)
= StackSet cur visi unseen M.empty
where (seen,unseen) = L.splitAt (length m) $ map (\i -> Workspace i l Nothing) wids
(cur:visi) = [ Screen i s sd | (i, s, sd) <- zip3 seen [0..] m ]
new l (wid:wids) (m:ms) | length ms <= length wids
= StackSet cur visi (map ws unseen) M.empty
where ws i = Workspace i l Nothing
(seen, unseen) = L.splitAt (length ms) wids
cur:visi = Screen (ws wid) 0 m : [ Screen (ws i) s sd | (i, s, sd) <- zip3 seen [1..] ms ]
-- now zip up visibles with their screen id
new _ _ _ = abort "non-positive argument to StackSet.new"
@ -224,7 +243,7 @@ view i s
| otherwise = s -- not a member of the stackset
where equating f = \x y -> f x == f y
where equating f x y = f x == f y
-- 'Catch'ing this might be hard. Relies on monotonically increasing
-- workspace tags defined in 'new'
@ -297,7 +316,7 @@ integrate :: Stack a -> [a]
integrate (Stack x l r) = reverse l ++ x : r
-- |
-- /O(n)/ Flatten a possibly empty stack into a list.
-- /O(n)/. Flatten a possibly empty stack into a list.
integrate' :: Maybe (Stack a) -> [a]
integrate' = maybe [] integrate
@ -329,32 +348,44 @@ filter p (Stack f ls rs) = case L.filter p (f:rs) of
index :: StackSet i l a s sd -> [a]
index = with [] integrate
-- |
-- /O(1), O(w) on the wrapping case/.
--
-- focusUp, focusDown. Move the window focus up or down the stack,
-- wrapping if we reach the end. The wrapping should model a 'cycle'
-- on the current stack. The 'master' window, and window order,
-- | /O(1), O(w) on the wrapping case/. Move the window focus up the
-- stack, wrapping if we reach the end. The wrapping should model a
-- @cycle@ on the current stack. The @master@ window and window order
-- are unaffected by movement of focus.
--
-- swapUp, swapDown, swap the neighbour in the stack ordering, wrapping
-- if we reach the end. Again the wrapping model should 'cycle' on
-- the current stack.
--
focusUp, focusDown, swapUp, swapDown :: StackSet i l a s sd -> StackSet i l a s sd
focusUp :: StackSet i l a s sd -> StackSet i l a s sd
focusUp = modify' focusUp'
-- | /O(1), O(w) on the wrapping case/. Like 'focusUp', but move the
-- window focus down the stack.
focusDown :: StackSet i l a s sd -> StackSet i l a s sd
focusDown = modify' focusDown'
-- | /O(1), O(w) on the wrapping case/. Swap the upwards (left)
-- neighbour in the stack ordering, wrapping if we reach the end. Much
-- like for 'focusUp' and 'focusDown', the wrapping model should 'cycle'
-- on the current stack.
swapUp :: StackSet i l a s sd -> StackSet i l a s sd
swapUp = modify' swapUp'
-- | /O(1), O(w) on the wrapping case/. Like 'swapUp', but for swapping
-- the downwards (right) neighbour.
swapDown :: StackSet i l a s sd -> StackSet i l a s sd
swapDown = modify' (reverseStack . swapUp' . reverseStack)
-- | Variants of 'focusUp' and 'focusDown' that work on a
-- | A variant of 'focusUp' with the same asymptotics that works on a
-- 'Stack' rather than an entire 'StackSet'.
focusUp', focusDown' :: Stack a -> Stack a
focusUp' :: Stack a -> Stack a
focusUp' (Stack t (l:ls) rs) = Stack l ls (t:rs)
focusUp' (Stack t [] rs) = Stack x xs [] where (x:xs) = reverse (t:rs)
focusDown' = reverseStack . focusUp' . reverseStack
focusUp' (Stack t [] rs) = Stack x xs []
where (x :| xs) = NE.reverse (t :| rs)
-- | A variant of 'focusDown' with the same asymptotics that works on a
-- 'Stack' rather than an entire 'StackSet'.
focusDown' :: Stack a -> Stack a
focusDown' = reverseStack . focusUp' . reverseStack
-- | A variant of 'spawUp' with the same asymptotics that works on a
-- 'Stack' rather than an entire 'StackSet'.
swapUp' :: Stack a -> Stack a
swapUp' (Stack t (l:ls) rs) = Stack t ls (l:rs)
swapUp' (Stack t [] rs) = Stack t (reverse rs) []
@ -508,8 +539,8 @@ sink w s = s { floating = M.delete w (floating s) }
-- Focus stays with the item moved.
swapMaster :: StackSet i l a s sd -> StackSet i l a s sd
swapMaster = modify' $ \c -> case c of
Stack _ [] _ -> c -- already master.
Stack t ls rs -> Stack t [] (xs ++ x : rs) where (x:xs) = reverse ls
Stack _ [] _ -> c -- already master.
Stack t (l:ls) rs -> Stack t [] (xs ++ x : rs) where (x :| xs) = NE.reverse (l :| ls)
-- natural! keep focus, move current to the top, move top to current.
@ -525,8 +556,8 @@ shiftMaster = modify' $ \c -> case c of
-- | /O(s)/. Set focus to the master window.
focusMaster :: StackSet i l a s sd -> StackSet i l a s sd
focusMaster = modify' $ \c -> case c of
Stack _ [] _ -> c
Stack t ls rs -> Stack x [] (xs ++ t : rs) where (x:xs) = reverse ls
Stack _ [] _ -> c
Stack t (l:ls) rs -> Stack x [] (xs ++ t : rs) where (x :| xs) = NE.reverse (l :| ls)
--
-- ---------------------------------------------------------------------

View File

@ -1,7 +1,15 @@
resolver: lts-7.19
resolver: lts-21.12
packages:
- ./
- ./
extra-deps:
- X11-1.8
- X11-1.10
nix:
packages:
- zlib
- xorg.libX11
- xorg.libXrandr
- xorg.libXScrnSaver
- xorg.libXext

View File

@ -36,7 +36,7 @@ instance (Integral i, Integral s, Eq a, Arbitrary a, Arbitrary l, Arbitrary sd)
-- Pick a random window "number" in each workspace, to give focus.
focus <- sequence [ if null windows
then return Nothing
else liftM Just $ choose (0, length windows - 1)
else Just <$> choose (0, length windows - 1)
| windows <- wsWindows ]
let tags = [1 .. fromIntegral numWs]
@ -80,7 +80,7 @@ newtype NonEmptyWindowsStackSet = NonEmptyWindowsStackSet T
instance Arbitrary NonEmptyWindowsStackSet where
arbitrary =
NonEmptyWindowsStackSet `fmap` (arbitrary `suchThat` (not . null . allWindows))
NonEmptyWindowsStackSet <$> (arbitrary `suchThat` (not . null . allWindows))
instance Arbitrary Rectangle where
arbitrary = Rectangle <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary
@ -99,7 +99,7 @@ newtype NonEmptyNubList a = NonEmptyNubList [a]
deriving ( Eq, Ord, Show, Read )
instance (Eq a, Arbitrary a) => Arbitrary (NonEmptyNubList a) where
arbitrary = NonEmptyNubList `fmap` ((liftM nub arbitrary) `suchThat` (not . null))
arbitrary = NonEmptyNubList <$> ((nub <$> arbitrary) `suchThat` (not . null))
@ -116,7 +116,7 @@ arbitraryTag :: T -> Gen Tag
arbitraryTag x = do
let ts = tags x
-- There must be at least 1 workspace, thus at least 1 tag.
idx <- choose (0, (length ts) - 1)
idx <- choose (0, length ts - 1)
return $ ts!!idx
-- | Pull out an arbitrary window from a StackSet that is guaranteed to have a
@ -136,5 +136,5 @@ arbitraryWindow :: NonEmptyWindowsStackSet -> Gen Window
arbitraryWindow (NonEmptyWindowsStackSet x) = do
let ws = allWindows x
-- We know that there are at least 1 window in a NonEmptyWindowsStackSet.
idx <- choose(0, (length ws) - 1)
idx <- choose (0, length ws - 1)
return $ ws!!idx

View File

@ -1,6 +1,6 @@
import Test.QuickCheck
-- Our QC instances and properties.
-- Our QC instances and properties:
import Instances
import Properties.Delete
import Properties.Failure
@ -166,11 +166,16 @@ tests =
-- tall layout
,("tile 1 window fullsize", property prop_tile_fullscreen)
,("tile max ratio", property prop_tile_max_ratio)
,("tile min ratio", property prop_tile_min_ratio)
,("tiles never overlap", property prop_tile_non_overlap)
,("split horizontal", property prop_split_horizontal)
,("split vertical", property prop_split_vertical)
,("pure layout tall", property prop_purelayout_tall)
,("pure layout tall", property prop_purelayout_tall)
{- Following two test cases should be automatically generated by QuickCheck ideally, but it fails. -}
,("pure layout tall: ratio = 0", property (\n d rect -> prop_purelayout_tall n d 0 rect))
,("pure layout tall: ratio = 1", property (\n d rect -> prop_purelayout_tall n d 1 rect))
,("send shrink tall", property prop_shrink_tall)
,("send expand tall", property prop_expand_tall)
,("send incmaster tall", property prop_incmaster_tall)
@ -196,6 +201,5 @@ tests =
,("pointWithin", property prop_point_within)
,("pointWithin mirror", property prop_point_within_mirror)
]
] <>
prop_laws_Stack

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
@ -64,7 +64,7 @@ prop_delete_focus_not_end = do
-- last one in the stack.
`suchThat` \(x' :: T) ->
let currWins = index x'
in length (currWins) >= 2 && peek x' /= Just (last currWins)
in length currWins >= 2 && peek x' /= Just (last currWins)
-- This is safe, as we know there are >= 2 windows
let Just n = peek x
return $ peek (delete n x) == peek (focusDown x)

View File

@ -2,7 +2,7 @@ module Properties.Failure where
import XMonad.StackSet hiding (filter)
import qualified Control.Exception.Extensible as C
import qualified Control.Exception as C
import System.IO.Unsafe
import Data.List (isPrefixOf)

View File

@ -32,8 +32,8 @@ prop_focusWindow_master (NonNegative n) (x :: T) =
in index (focusWindow (s !! i) x) == index x
-- shifting focus is trivially reversible
prop_focus_left (x :: T) = (focusUp (focusDown x)) == x
prop_focus_right (x :: T) = (focusDown (focusUp x)) == x
prop_focus_left (x :: T) = focusUp (focusDown x) == x
prop_focus_right (x :: T) = focusDown (focusUp x) == x
-- focus master is idempotent
prop_focusMaster_idem (x :: T) = focusMaster x == focusMaster (focusMaster x)
@ -47,9 +47,9 @@ prop_focusWindow_works (NonNegative (n :: Int)) (x :: T) =
in (focus . fromJust . stack . workspace . current) (focusWindow (s !! i) x) == (s !! i)
-- rotation through the height of a stack gets us back to the start
prop_focus_all_l (x :: T) = (foldr (const focusUp) x [1..n]) == x
prop_focus_all_l (x :: T) = foldr (const focusUp) x [1..n] == x
where n = length (index x)
prop_focus_all_r (x :: T) = (foldr (const focusDown) x [1..n]) == x
prop_focus_all_r (x :: T) = foldr (const focusDown) x [1..n] == x
where n = length (index x)
-- prop_rotate_all (x :: T) = f (f x) == f x

View File

@ -35,7 +35,7 @@ prop_greedyView_local (x :: T) = do
-- greedyView is idempotent
prop_greedyView_idem (x :: T) = do
n <- arbitraryTag x
return $ greedyView n (greedyView n x) == (greedyView n x)
return $ greedyView n (greedyView n x) == greedyView n x
-- greedyView is reversible, though shuffles the order of hidden/visible
prop_greedyView_reversible (x :: T) = do

View File

@ -46,7 +46,7 @@ prop_insert_delete x = do
-- inserting n elements increases current stack size by n
prop_size_insert is (EmptyStackSet x) =
size (foldr insertUp x ws ) == (length ws)
size (foldr insertUp x ws) == length ws
where
ws = nub is
size = length . index

View File

@ -29,6 +29,6 @@ prop_purelayout_full rect = do
-- what happens when we send an IncMaster message to Full --- Nothing
prop_sendmsg_full (NonNegative k) =
isNothing (Full `pureMessage` (SomeMessage (IncMasterN k)))
isNothing (Full `pureMessage` SomeMessage (IncMasterN k))
prop_desc_full = description Full == show Full

View File

@ -11,8 +11,9 @@ import XMonad.Layout
import Graphics.X11.Xlib.Types (Rectangle(..))
import Data.Maybe
import Control.Applicative
import Data.List (sort)
import Data.Maybe
import Data.Ratio
------------------------------------------------------------------------
@ -27,14 +28,30 @@ prop_tile_non_overlap rect windows nmaster = noOverlaps (tile pct rect nmaster w
where _ = rect :: Rectangle
pct = 3 % 100
-- with a ratio of 1, no stack windows are drawn of there is at least
-- one master window around.
prop_tile_max_ratio = extremeRatio 1 drop
-- with a ratio of 0, no master windows are drawn at all if there are
-- any stack windows around.
prop_tile_min_ratio = extremeRatio 0 take
extremeRatio amount getRects rect = do
w@(NonNegative windows) <- arbitrary `suchThat` (> NonNegative 0)
NonNegative nmaster <- arbitrary `suchThat` (< w)
let tiled = tile amount rect nmaster windows
pure $ if nmaster == 0
then prop_tile_non_overlap rect windows nmaster
else all ((== 0) . rect_width) $ getRects nmaster tiled
-- splitting horizontally yields sensible results
prop_split_horizontal (NonNegative n) x =
(noOverflows (+) (rect_x x) (rect_width x)) ==>
noOverflows (+) (rect_x x) (rect_width x) ==>
sum (map rect_width xs) == rect_width x
&&
all (== rect_height x) (map rect_height xs)
all (\s -> rect_height s == rect_height x) xs
&&
(map rect_x xs) == (sort $ map rect_x xs)
map rect_x xs == sort (map rect_x xs)
where
xs = splitHorizontally n x
@ -49,13 +66,20 @@ prop_split_vertical (r :: Rational) x =
-- pureLayout works.
prop_purelayout_tall n r1 r2 rect = do
prop_purelayout_tall n d r rect = do
x <- (arbitrary :: Gen T) `suchThat` (isJust . peek)
let layout = Tall n r1 r2
let layout = Tall n d r
st = fromJust . stack . workspace . current $ x
ts = pureLayout layout rect st
ntotal = length (index x)
return $
length ts == length (index x)
(if r == 0 then
-- (<=) for Bool is the logical implication
(0 <= n && n <= ntotal) <= (length ts == ntotal - n)
else if r == 1 then
(0 <= n && n <= ntotal) <= (length ts == n)
else
length ts == ntotal)
&&
noOverlaps (map snd ts)
&&
@ -72,7 +96,7 @@ prop_shrink_tall (NonNegative n) (Positive delta) (NonNegative frac) =
-- remaining fraction should shrink
where
l1 = Tall n delta frac
Just l2@(Tall n' delta' frac') = l1 `pureMessage` (SomeMessage Shrink)
Just l2@(Tall n' delta' frac') = l1 `pureMessage` SomeMessage Shrink
-- pureMessage :: layout a -> SomeMessage -> Maybe (layout a)
@ -93,7 +117,7 @@ prop_expand_tall (NonNegative n)
where
frac = min 1 (n1 % d1)
l1 = Tall n delta frac
Just l2@(Tall n' delta' frac') = l1 `pureMessage` (SomeMessage Expand)
Just l2@(Tall n' delta' frac') = l1 `pureMessage` SomeMessage Expand
-- pureMessage :: layout a -> SomeMessage -> Maybe (layout a)
-- what happens when we send an IncMaster message to Tall
@ -102,7 +126,7 @@ prop_incmaster_tall (NonNegative n) (Positive delta) (NonNegative frac)
delta == delta' && frac == frac' && n' == n + k
where
l1 = Tall n delta frac
Just l2@(Tall n' delta' frac') = l1 `pureMessage` (SomeMessage (IncMasterN k))
Just l2@(Tall n' delta' frac') = l1 `pureMessage` SomeMessage (IncMasterN k)
-- pureMessage :: layout a -> SomeMessage -> Maybe (layout a)

View File

@ -52,15 +52,14 @@ prop_aspect_hint_shrink hint (w,h) = case applyAspectHint hint (w,h) of
-- applyAspectHint does nothing when the supplied (x,y) fits
-- the desired range
prop_aspect_fits =
forAll ((,,,) <$> pos <*> pos <*> pos <*> pos) $ \ (x,y,a,b) ->
let f v = applyAspectHint ((x, y+a), (x+b, y)) v
in and [ noOverflows (*) x (y+a), noOverflows (*) (x+b) y ]
forAll ((,,,) <$> pos <*> pos <*> pos <*> pos) $ \ (x,y,a,b) ->
let f = applyAspectHint ((x, y+a), (x+b, y))
in noOverflows (*) x (y+a) && noOverflows (*) (x+b) y
==> f (x,y) == (x,y)
where pos = choose (0, 65535)
mul a b = toInteger (a*b) /= toInteger a * toInteger b
prop_point_within r @ (Rectangle x y w h) =
prop_point_within r@(Rectangle x y w h) =
forAll ((,) <$>
choose (0, fromIntegral w - 1) <*>
choose (0, fromIntegral h - 1)) $

View File

@ -27,7 +27,7 @@ prop_shift_reversible (x :: T) = do
-- shiftMaster
-- focus/local/idempotent same as swapMaster:
prop_shift_master_focus (x :: T) = peek x == (peek $ shiftMaster x)
prop_shift_master_focus (x :: T) = peek x == peek (shiftMaster x)
prop_shift_master_local (x :: T) = hidden_spaces x == hidden_spaces (shiftMaster x)
prop_shift_master_idempotent (x :: T) = shiftMaster (shiftMaster x) == shiftMaster x
-- ordering is constant modulo the focused window:
@ -57,14 +57,14 @@ prop_shift_win_fix_current = do
x <- arbitrary `suchThat` \(x' :: T) ->
-- Invariant, otherWindows are NOT in the current workspace.
let otherWindows = allWindows x' L.\\ index x'
in length(tags x') >= 2 && length(otherWindows) >= 1
in length (tags x') >= 2 && not (null otherWindows)
-- Sadly we have to construct `otherWindows` again, for the actual StackSet
-- that got chosen.
let otherWindows = allWindows x L.\\ index x
-- We know such tag must exists, due to the precondition
n <- arbitraryTag x `suchThat` (/= currentTag x)
-- we know length is >= 1, from above precondition
idx <- choose(0, length(otherWindows) - 1)
idx <- choose (0, length otherWindows - 1)
let w = otherWindows !! idx
return $ (current $ x) == (current $ shiftWin n w x)
return $ current x == current (shiftWin n w x)

View File

@ -1,4 +1,6 @@
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Properties.Stack where
import Test.QuickCheck
@ -9,12 +11,18 @@ import qualified XMonad.StackSet as S (filter)
import Data.Maybe
import Data.Proxy
import Test.QuickCheck.Classes (
Laws (lawsTypeclass, lawsProperties), Proxy1 (Proxy1),
foldableLaws, traversableLaws,
)
-- The list returned by index should be the same length as the actual
-- windows kept in the zipper
prop_index_length (x :: T) =
case stack . workspace . current $ x of
Nothing -> length (index x) == 0
Nothing -> null (index x)
Just it -> length (index x) == length (focus it : up it ++ down it)
@ -33,7 +41,7 @@ prop_allWindowsMember (NonEmptyWindowsStackSet x) = do
-- which is a key component in this test (together with member).
let ws = allWindows x
-- We know that there are at least 1 window in a NonEmptyWindowsStackSet.
idx <- choose(0, (length ws) - 1)
idx <- choose (0, length ws - 1)
return $ member (ws!!idx) x
@ -46,6 +54,24 @@ prop_filter_order (x :: T) =
-- differentiate should return Nothing if the list is empty or Just stack, with
-- the first element of the list is current, and the rest of the list is down.
prop_differentiate xs =
if null xs then differentiate xs == Nothing
else (differentiate xs) == Just (Stack (head xs) [] (tail xs))
if null xs then isNothing (differentiate xs)
else differentiate xs == Just (Stack (head xs) [] (tail xs))
where _ = xs :: [Int]
-- Check type class laws of 'Data.Foldable.Foldable' and 'Data.Traversable.Traversable'.
newtype TestStack a = TestStack (Stack a)
deriving (Eq, Read, Show, Foldable, Functor)
instance (Arbitrary a) => Arbitrary (TestStack a) where
arbitrary = TestStack <$> (Stack <$> arbitrary <*> arbitrary <*> arbitrary)
shrink = traverse shrink
instance Traversable TestStack where
traverse f (TestStack sx) = fmap TestStack (traverse f sx)
prop_laws_Stack = format (foldableLaws p) <> format (traversableLaws p)
where
p = Proxy :: Proxy TestStack
format laws = [ ("Stack: " <> lawsTypeclass laws <> ": " <> name, prop)
| (name, prop) <- lawsProperties laws ]

View File

@ -58,7 +58,7 @@ invariant (s :: T) = and
-- inBounds = and [ w >=0 && w < size s | (w,sc) <- M.assocs (screens s) ]
monotonic [] = True
monotonic (x:[]) = True
monotonic [x] = True
monotonic (x:y:zs) | x == y-1 = monotonic (y:zs)
| otherwise = False
@ -126,7 +126,7 @@ prop_empty (EmptyStackSet x) =
prop_empty_current (EmptyStackSet x) = currentTag x == head (tags x)
-- no windows will be a member of an empty workspace
prop_member_empty i (EmptyStackSet x) = member i x == False
prop_member_empty i (EmptyStackSet x) = not (member i x)
-- peek either yields nothing on the Empty workspace, or Just a valid window
prop_member_peek (x :: T) =

View File

@ -11,8 +11,8 @@ import XMonad.StackSet hiding (filter)
-- swapUp, swapDown, swapMaster: reordiring windows
-- swap is trivially reversible
prop_swap_left (x :: T) = (swapUp (swapDown x)) == x
prop_swap_right (x :: T) = (swapDown (swapUp x)) == x
prop_swap_left (x :: T) = swapUp (swapDown x) == x
prop_swap_right (x :: T) = swapDown (swapUp x) == x
-- TODO swap is reversible
-- swap is reversible, but involves moving focus back the window with
-- master on it. easy to do with a mouse...
@ -26,12 +26,12 @@ prop_promote_reversible x b = (not . null . fromMaybe [] . flip index x . curren
-}
-- swap doesn't change focus
prop_swap_master_focus (x :: T) = peek x == (peek $ swapMaster x)
prop_swap_master_focus (x :: T) = peek x == peek (swapMaster x)
-- = case peek x of
-- Nothing -> True
-- Just f -> focus (stack (workspace $ current (swap x))) == f
prop_swap_left_focus (x :: T) = peek x == (peek $ swapUp x)
prop_swap_right_focus (x :: T) = peek x == (peek $ swapDown x)
prop_swap_left_focus (x :: T) = peek x == peek (swapUp x)
prop_swap_right_focus (x :: T) = peek x == peek (swapDown x)
-- swap is local
prop_swap_master_local (x :: T) = hidden_spaces x == hidden_spaces (swapMaster x)
@ -39,9 +39,9 @@ prop_swap_left_local (x :: T) = hidden_spaces x == hidden_spaces (swapUp x)
prop_swap_right_local (x :: T) = hidden_spaces x == hidden_spaces (swapDown x)
-- rotation through the height of a stack gets us back to the start
prop_swap_all_l (x :: T) = (foldr (const swapUp) x [1..n]) == x
prop_swap_all_l (x :: T) = foldr (const swapUp) x [1..n] == x
where n = length (index x)
prop_swap_all_r (x :: T) = (foldr (const swapDown) x [1..n]) == x
prop_swap_all_r (x :: T) = foldr (const swapDown) x [1..n] == x
where n = length (index x)
prop_swap_master_idempotent (x :: T) = swapMaster (swapMaster x) == swapMaster x

View File

@ -37,7 +37,7 @@ prop_view_local (x :: T) = do
-- view is idempotent
prop_view_idem (x :: T) = do
n <- arbitraryTag x
return $ view n (view n x) == (view n x)
return $ view n (view n x) == view n x
-- view is reversible, though shuffles the order of hidden/visible
prop_view_reversible (x :: T) = do

View File

@ -12,8 +12,8 @@ hidden_spaces x = map workspace (visible x) ++ hidden x
-- normalise workspace list
normal s = s { hidden = sortBy g (hidden s), visible = sortBy f (visible s) }
where
f = \a b -> tag (workspace a) `compare` tag (workspace b)
g = \a b -> tag a `compare` tag b
f a b = tag (workspace a) `compare` tag (workspace b)
g a b = tag a `compare` tag b
noOverlaps [] = True

137
util/GenerateManpage.hs Normal file → Executable file
View File

@ -1,57 +1,66 @@
{-# LANGUAGE FlexibleContexts #-}
-- Unlike the rest of xmonad, this file is released under the GNU General
-- Public License version 2 or later.
#!/usr/bin/env runhaskell
-- Reads markdown (man/xmonad.1.markdown) from stdin, subtitutes
-- ___KEYBINDINGS___ for key-binding definitions generated from
-- src/XMonad/Config.hs, prints result to stdout.
--
-- 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. (Historical reasons, used to link with
-- GPL-licensed pandoc.)
import Data.Char
import Data.List
import Distribution.PackageDescription.Parse
import Distribution.Verbosity
import Distribution.Package
import Distribution.PackageDescription
import Text.PrettyPrint.HughesPJ
import Distribution.Text
main :: IO ()
main = do
keybindings <- guessBindings
interact $ unlines . replace "___KEYBINDINGS___" keybindings . lines
import Text.Pandoc -- works with 1.15.x
-- | 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.
releaseDate = "31 December 2012"
trim :: String -> String
trim = reverse . dropWhile isSpace . reverse . dropWhile isSpace
guessKeys line = concat $ intersperse "-" (modifiers ++ [map toLower key])
where modifiers = map (!!1) (line =~ "(mod|shift|control)Mask")
(_, _, _, [key]) = line =~ "xK_([_[:alnum:]]+)" :: (String, String, String, [String])
binding :: [String] -> (String, String)
binding [ _, bindingLine, "", desc ] = (guessKeys bindingLine, desc)
binding [ _, _, keyCombo, desc ] = (keyCombo, desc)
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 =~ "(.*)--(.*)%!(.*)")
allBindings = concatMap parseLine . lines
where
parseLine :: String -> [(String, String)]
parseLine l
| " -- " `isInfixOf` l
, Just d <- parseDesc l = [(intercalate "-" (parseKeys l), d)]
| otherwise = []
parseDesc :: String -> Maybe String
parseDesc = fmap (trim . drop 4) . find (" %! " `isPrefixOf`) . tails
parseKeys :: String -> [String]
parseKeys l = case lex l of
[("", _)] -> []
[("--", rest)] -> case words rest of
k : "%!" : _ -> [k]
_ -> []
[(k, rest)] -> parseKey k ++ parseKeys rest
parseKey :: String -> [String]
parseKey k | "Mask" `isSuffixOf` k = [reverse (drop 4 (reverse k))]
| "xK_" `isPrefixOf` k = [map toLower (drop 3 k)]
| otherwise = []
-- FIXME: What escaping should we be doing on these strings?
markdownDefn :: (String, String) -> String
@ -60,39 +69,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{ writerTemplate = Just template }
$ parsed
putStrLn "Documentation created: man/xmonad.1"
Right template <- getDefaultTemplate Nothing "html"
writeFile "./man/xmonad.1.html"
. writeHtmlString def
{ writerVariables =
[("include-before"
,"<h1>"++releaseName++"</h1>"++
"<p>Section: xmonad manual (1)<br/>"++
"Updated: "++releaseDate++"</p>"++
"<hr/>")]
, writerTemplate = Just template
, writerTableOfContents = True }
$ parsed
putStrLn "Documentation created: man/xmonad.1.html"
trim :: String -> String
trim = reverse . dropWhile isSpace . reverse . dropWhile isSpace

View File

@ -1,133 +1,136 @@
name: xmonad
version: 0.13
homepage: http://xmonad.org
version: 0.18.0.9
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, Tony Zorman
maintainer: xmonad@haskell.org
extra-source-files: README.md CHANGES.md CONFIG STYLE
tests/*.hs
tests/Properties/*.hs
tests/Properties/Layout/*.hs
man/xmonad.1.markdown man/xmonad.1 man/xmonad.1.html
util/GenerateManpage.hs
util/hpcReport.sh
cabal-version: >= 1.8
tested-with: GHC == 8.6.5 || == 8.8.4 || == 8.10.7 || == 9.0.2 || == 9.2.8 || == 9.4.8 || == 9.6.7 || == 9.8.4 || == 9.10.2 || == 9.12.2
category: System
homepage: http://xmonad.org
bug-reports: https://github.com/xmonad/xmonad/issues
build-type: Simple
tested-with:
GHC==7.6.3,
GHC==7.8.4,
GHC==7.10.3,
GHC==8.0.1
data-files: man/xmonad.hs, man/xmonad.1, man/xmonad.1.html
extra-source-files: README.md
CHANGES.md
CONTRIBUTING.md
INSTALL.md
MAINTAINERS.md
TUTORIAL.md
man/xmonad.1.markdown
man/xmonad.1
man/xmonad.1.html
man/xmonad.hs
util/hpcReport.sh
cabal-version: 1.12
source-repository head
type: git
location: https://github.com/xmonad/xmonad
flag testing
description: Testing mode, only build minimal components
default: False
manual: True
flag generatemanpage
description: Build the tool for generating the man page
default: False
manual: True
flag profiling
description: Enable profiling
default: False
manual: True
flag pedantic
description: Be pedantic (-Werror and the like)
default: False
manual: True
library
hs-source-dirs: src
exposed-modules: XMonad
XMonad.Main
XMonad.Core
XMonad.Config
XMonad.Layout
XMonad.ManageHook
XMonad.Operations
XMonad.StackSet
other-modules: Paths_xmonad
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.12 && < 5
, X11 >= 1.10 && < 1.11
, containers
, data-default-class
, directory
, filepath
, mtl
, process
, setlocale
, time
, transformers >= 0.3
, unix
ghc-options: -funbox-strict-fields -Wall -Wno-unused-do-bind
default-language: Haskell2010
build-depends: base < 5 && >=3,
containers,
data-default,
directory >= 1.2.3,
extensible-exceptions,
filepath,
setlocale,
mtl,
process,
unix,
utf8-string >= 0.3 && < 1.1,
X11>=1.8 && < 1.9
-- Keep this in sync with the oldest version in 'tested-with'
if impl(ghc > 8.6.5)
ghc-options: -Wno-unused-imports
if true
ghc-options: -funbox-strict-fields -Wall
if impl(ghc >= 6.12.1)
ghc-options: -fno-warn-unused-do-bind
if impl(ghc < 7.0.0)
extensions: UndecidableInstances
-- needed for XMonad.Config's instance Default (XConfig a)
if flag(profiling)
ghc-prof-options: -prof -auto-all
if flag(testing)
buildable: False
if flag(pedantic)
ghc-options: -Werror
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, xmonad
ghc-options: -Wall -Wno-unused-do-bind
default-language: Haskell2010
executable generatemanpage
main-is: GenerateManpage.hs
hs-source-dirs: util
if flag(generatemanpage)
build-depends: base,
Cabal,
pandoc,
pretty,
regex-posix
else
buildable: False
-- Keep this in sync with the oldest version in 'tested-with'
if impl(ghc > 8.6.5)
ghc-options: -Wno-unused-imports
if flag(pedantic)
ghc-options: -Werror
-- 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
, quickcheck-classes >= 0.4.3
, X11
, containers
, xmonad
default-language: Haskell2010
if impl(ghc > 9.8)
ghc-options: -Wno-x-partial
if flag(pedantic)
ghc-options: -Werror