Compare commits

..

282 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
46 changed files with 1755 additions and 953 deletions

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

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

View File

@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Clone project
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Install dependencies
run: |
@ -26,8 +26,8 @@ jobs:
- name: Commit/push if changed
run: |
set -ex
git config user.name github-actions
git config user.email github-actions@github.com
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

@ -2,14 +2,16 @@ Piggy-back on the haskell-ci workflow for automatic releases to Hackage.
This extends the workflow with two additional triggers:
* When a release is created on GitHub, 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).
* 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).
* To make a final release, the workflow can be triggered manually by entering
the correct version number matching the version in the cabal file. This is
here because promoting the candidate on Hackage discards the uploaded docs
(https://github.com/haskell/hackage-server/issues/70).
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
@ -17,7 +19,7 @@ set in GitHub repository secrets.
--- .github/workflows/haskell-ci.yml.orig
+++ .github/workflows/haskell-ci.yml
@@ -14,8 +14,17 @@
@@ -14,8 +14,15 @@
#
name: Haskell-CI
on:
@ -31,53 +33,66 @@ set in GitHub repository secrets.
+ workflow_dispatch:
+ inputs:
+ version:
+ # releases to Hackage are final and cannot be reverted, thus require
+ # manual entry of version as a poor man's mistake avoidance
+ description: version (must match version in cabal file)
+ description: candidate version (must match version in cabal file)
jobs:
linux:
name: Haskell-CI - Linux - ${{ matrix.compiler }}
@@ -28,6 +37,7 @@
include:
- compiler: ghc-9.0.1
@@ -33,6 +40,7 @@
compilerVersion: 9.8.4
setup-method: ghcup
allow-failure: false
+ upload: true
- compiler: ghc-8.10.4
allow-failure: false
- compiler: ghc-8.8.4
@@ -171,8 +181,66 @@
${CABAL} -vnormal check
- compiler: ghc-9.6.7
compilerKind: ghc
compilerVersion: 9.6.7
@@ -257,6 +265,10 @@
- name: haddock
run: |
- $CABAL v2-haddock $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all
$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: upload artifacts (sdist)
@@ -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@v2
+ uses: actions/upload-artifact@v4
+ with:
+ name: sdist
+ path: ${{ github.workspace }}/sdist/*.tar.gz
+ - name: upload artifacts (haddock)
+ - name: upload artifact (haddock)
+ if: matrix.upload
+ uses: actions/upload-artifact@v2
+ 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 == 'release'
+ 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 --fail \
+ --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 --fail \
+ --silent --show-error --output /dev/stderr --write-out '%{http_code}' \
+ -X PUT \
+ --header "Accept: text/plain" \
+ --header "Authorization: X-ApiKey $HACKAGE_API_KEY" \
@ -85,23 +100,30 @@ set in GitHub repository secrets.
+ --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.release.tag_name }}
+ PACKAGE_VERSION: ${{ github.event.inputs.version }}
+ - name: hackage upload (release)
+ if: matrix.upload && github.event_name == 'workflow_dispatch'
+ if: matrix.upload && github.event_name == 'release'
+ shell: bash
+ run: |
+ set -ex
+ PACKAGE_VERSION="${PACKAGE_VERSION#v}"
+ res=$(
+ curl \
+ --silent --show-error --fail \
+ --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 --fail \
+ --silent --show-error --output /dev/stderr --write-out '%{http_code}' \
+ -X PUT \
+ --header "Accept: text/plain" \
+ --header "Authorization: X-ApiKey $HACKAGE_API_KEY" \
@ -109,7 +131,9 @@ set in GitHub repository secrets.
+ --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.inputs.version }}
+ PACKAGE_VERSION: ${{ github.event.release.tag_name }}

View File

@ -8,9 +8,9 @@
#
# For more information, see https://github.com/haskell-CI/haskell-ci
#
# version: 0.12
# version: 0.19.20250506
#
# REGENDATA ("0.12",["github","cabal.project"])
# REGENDATA ("0.19.20250506",["github","cabal.project"])
#
name: Haskell-CI
on:
@ -22,63 +22,116 @@ on:
workflow_dispatch:
inputs:
version:
# releases to Hackage are final and cannot be reverted, thus require
# manual entry of version as a poor man's mistake avoidance
description: version (must match version in cabal file)
description: candidate version (must match version in cabal file)
jobs:
linux:
name: Haskell-CI - Linux - ${{ matrix.compiler }}
runs-on: ubuntu-18.04
runs-on: ubuntu-24.04
timeout-minutes:
60
container:
image: buildpack-deps:bionic
image: buildpack-deps:jammy
continue-on-error: ${{ matrix.allow-failure }}
strategy:
matrix:
include:
- compiler: ghc-9.0.1
- 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-8.10.4
- 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
allow-failure: false
- compiler: ghc-8.4.4
compilerKind: ghc
compilerVersion: 8.6.5
setup-method: ghcup
allow-failure: false
fail-fast: false
steps:
- name: apt
- name: apt-get install
run: |
apt-get update
apt-get install -y --no-install-recommends gnupg ca-certificates dirmngr curl git software-properties-common
apt-add-repository -y 'ppa:hvr/ghc'
apt-get update
apt-get install -y $CC cabal-install-3.4 libx11-dev libxext-dev libxinerama-dev libxrandr-dev libxss-dev
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:
CC: ${{ matrix.compiler }}
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
HCDIR=$(echo "/opt/$CC" | sed 's/-/\//')
HCNAME=ghc
HC=$HCDIR/bin/$HCNAME
echo "HC=$HC" >> $GITHUB_ENV
echo "HCPKG=$HCDIR/bin/$HCNAME-pkg" >> $GITHUB_ENV
echo "HADDOCK=$HCDIR/bin/haddock" >> $GITHUB_ENV
echo "CABAL=/opt/cabal/3.4/bin/cabal -vnormal+nowrap" >> $GITHUB_ENV
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=--$HCNAME --with-compiler=$HC" >> $GITHUB_ENV
echo "GHCJSARITH=0" >> $GITHUB_ENV
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:
CC: ${{ matrix.compiler }}
HCKIND: ${{ matrix.compilerKind }}
HCNAME: ${{ matrix.compiler }}
HCVER: ${{ matrix.compilerVersion }}
- name: env
run: |
env
@ -101,6 +154,10 @@ jobs:
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: |
@ -113,14 +170,14 @@ jobs:
- name: install cabal-plan
run: |
mkdir -p $HOME/.cabal/bin
curl -sL https://github.com/haskell-hvr/cabal-plan/releases/download/v0.6.2.0/cabal-plan-0.6.2.0-x86_64-linux.xz > cabal-plan.xz
echo 'de73600b1836d3f55e32d80385acc055fd97f60eaa0ab68a755302685f5d81bc cabal-plan.xz' | sha256sum -c -
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@v2
uses: actions/checkout@v4
with:
path: source
- name: initial cabal.project for sdist
@ -139,7 +196,8 @@ jobs:
- 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
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
@ -151,15 +209,15 @@ jobs:
package xmonad
flags: +pedantic
EOF
$HCPKG list --simple-output --names-only | perl -ne 'for (split /\s+/) { print "constraints: $_ installed\n" unless /^(xmonad)$/; }' >> cabal.project.local
$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: cache
uses: actions/cache@v2
- name: restore cache
uses: actions/cache/restore@v4
with:
key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }}
path: ~/.cabal/store
@ -182,35 +240,55 @@ jobs:
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: upload artifacts (sdist)
if: matrix.upload
uses: actions/upload-artifact@v2
- 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 artifacts (haddock)
- name: upload artifact (haddock)
if: matrix.upload
uses: actions/upload-artifact@v2
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 == 'release'
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 --fail \
--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 --fail \
--silent --show-error --output /dev/stderr --write-out '%{http_code}' \
-X PUT \
--header "Accept: text/plain" \
--header "Authorization: X-ApiKey $HACKAGE_API_KEY" \
@ -218,23 +296,30 @@ jobs:
--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.release.tag_name }}
PACKAGE_VERSION: ${{ github.event.inputs.version }}
- name: hackage upload (release)
if: matrix.upload && github.event_name == 'workflow_dispatch'
if: matrix.upload && github.event_name == 'release'
shell: bash
run: |
set -ex
PACKAGE_VERSION="${PACKAGE_VERSION#v}"
res=$(
curl \
--silent --show-error --fail \
--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 --fail \
--silent --show-error --output /dev/stderr --write-out '%{http_code}' \
-X PUT \
--header "Accept: text/plain" \
--header "Authorization: X-ApiKey $HACKAGE_API_KEY" \
@ -242,7 +327,9 @@ jobs:
--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.inputs.version }}
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

View File

@ -12,14 +12,10 @@ jobs:
contents: read
steps:
- name: Install Nix
uses: cachix/install-nix-action@v13
uses: cachix/install-nix-action@v31
with:
install_url: https://nixos-nix-install-tests.cachix.org/serve/i6laym9jw3wg9mw6ncyrk6gjx4l34vvx/install
install_options: '--tarball-url-prefix https://nixos-nix-install-tests.cachix.org/serve'
extra_nix_config: |
experimental-features = nix-command flakes
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
github_access_token: ${{ secrets.GITHUB_TOKEN }}
- name: Clone project
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Build
run: nix build --print-build-logs

View File

@ -13,16 +13,16 @@ jobs:
steps:
- name: Clone project
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Setup Haskell
uses: haskell/actions/setup@v1
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
echo "$HOME/.cabal/bin" >> $GITHUB_PATH
cd # go somewhere without a cabal.project
cabal install packdeps
- name: Check package bounds (all)
continue-on-error: true
@ -38,3 +38,11 @@ jobs:
--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

View File

@ -12,30 +12,23 @@ jobs:
fail-fast: false
matrix:
include:
- resolver: lts-12
ghc: 8.4.4
- resolver: lts-14
ghc: 8.6.5
- resolver: lts-16
ghc: 8.8.4
- resolver: lts-17
ghc: 8.10.4
- resolver: lts-18
ghc: 8.10.7
- 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@v2
- name: Prepare apt sources
run: |
set -ex
sudo add-apt-repository -y ppa:hvr/ghc
sudo apt update -y
uses: actions/checkout@v4
- name: Install C dependencies
run: |
set -ex
sudo apt update -y
sudo apt install -y \
libx11-dev \
libxext-dev \
@ -44,31 +37,23 @@ jobs:
libxss-dev \
#
- name: Install GHC
# use system ghc (if available) in stack, don't waste GH Actions cache space
continue-on-error: true
run: |
set -ex
sudo apt install -y ghc-${{ matrix.ghc }}
echo /opt/ghc/${{ matrix.ghc }}/bin >> $GITHUB_PATH
- 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
# 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: |
echo "::set-output name=date::$(date +%Y-%m)"
date +date=1-%Y-%m >> $GITHUB_OUTPUT
- name: Cache Haskell package metadata
uses: actions/cache@v2
uses: actions/cache@v4
with:
path: ~/.stack/pantry
key: stack-pantry-${{ runner.os }}-${{ steps.cache-date.outputs.date }}
restore-keys: |
stack-pantry-${{ runner.os }}-
- name: Cache Haskell dependencies
uses: actions/cache@v2
uses: actions/cache@v4
with:
path: |
~/.stack/*
@ -78,7 +63,6 @@ jobs:
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 }}-
stack-${{ runner.os }}-${{ matrix.resolver }}-
- name: Update hackage index
# always update index to prevent the shared ~/.stack/pantry cache from being empty

3
.gitignore vendored
View File

@ -27,3 +27,6 @@ tags
/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"}

View File

@ -35,4 +35,5 @@ Valery V. Vorotyntsev <valery.vv@gmail.com>
Vanessa McHale <vamchale@gmail.com> <vanessa.mchale@reconfigure.io>
Wirt Wolff <wirtwolff@gmail.com>
slotThe <soliditsallgood@mailbox.org> <50166980+slotThe@users.noreply.github.com>
Tony Zorman <soliditsallgood@mailbox.org> <50166980+slotThe@users.noreply.github.com>
Tony Zorman <soliditsallgood@mailbox.org>

View File

@ -1,5 +1,86 @@
# 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

View File

@ -70,8 +70,11 @@ Here are some tips for getting your changes merged into xmonad:
and [xmonad][] have test-suites that you could run with
`stack test` for example.
* Make sure you read the section on rebasing and squashing commits
below.
* 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
@ -83,7 +86,7 @@ as well!
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, …)
(`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
@ -95,7 +98,7 @@ as well!
enforced in our GitHub CI.
* Partial functions are to be avoided: the window manager should not
crash, so do not call `error` or `undefined`
crash, so do not call `error` or `undefined`.
* Any pure function added to the core should have QuickCheck
properties precisely defining its behavior.
@ -103,84 +106,15 @@ as well!
* New modules should identify the author, and be submitted under the
same license as xmonad (BSD3 license).
## Rebasing and Squashing Commits
## Keep rocking!
Under no circumstances should you ever merge the master branch into
your feature branch. This makes it nearly impossible to review your
changes and we *will not accept your PR* if you do this.
Instead of merging you should rebase your changes on top of the master
branch. If a core team member asks you to "rebase your changes" this
is what they are talking about.
It's also helpful to squash all of your commits so that your pull
request only contains a single commit. Again, this makes it easier to
review your changes and identify the changes later on in the Git
history.
### How to Rebase Your Changes
The goal of rebasing is to bring recent changes from the master branch
into your feature branch. This often helps resolve conflicts where
you have changed a file that also changed in a recently merged pull
request (i.e. the `CHANGES.md` file). Here is how you do that.
1. Make sure that you have a `git remote` configured for the main
repository. I like to call this remote `upstream`:
```shell
$ git remote add upstream https://github.com/xmonad/xmonad-contrib.git
```
2. Pull from upstream and rewrite your changes on top of master. For
this to work you should not have any modified files in your
working directory. Run these commands from within your feature
branch (the branch you are asking to be merged):
```shell
$ git fetch --all
$ git pull --rebase upstream master
```
3. If the rebase was successful you can now push your feature branch
back to GitHub. You need to force the push since your commits
have been rewritten and have new IDs:
```shell
$ git push --force-with-lease
```
4. Your pull request should now be conflict-free and only contain the
changes that you actually made.
### How to Squash Commits
The goal of squashing commits is to produce a clean Git history where
each pull request contains just one commit.
1. Use `git log` to see how many commits you are including in your
pull request. (If you've already submitted your pull request you
can see this in the GitHub interface.)
2. Rebase all of those commits into a single commit. Assuming you
want to squash the last four (4) commits into a single commit:
```shell
$ git rebase -i HEAD~4
```
3. Git will open your editor and display the commits you are
rebasing with the word "pick" in front of them.
4. Leave the first listed commit as "pick" and change the remaining
commits from "pick" to "squash".
5. Save the file and exit your editor. Git will create a new commit
and open your editor so you can modify the commit message.
6. If everything was successful you can push your changed history
back up to GitHub:
```shell
$ git push --force-with-lease
```
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
@ -191,3 +125,7 @@ each pull request contains just one commit.
[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

View File

@ -47,10 +47,21 @@ $ sudo dnf install \
``` 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
@ -90,8 +101,8 @@ 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.15 https://github.com/xmonad/xmonad
$ git clone --branch v0.16 https://github.com/xmonad/xmonad-contrib
$ 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,
@ -112,7 +123,9 @@ Unless you already know which one you prefer, use Stack, which is easier.
#### Install Stack
The easiest way to get [stack] is probably via your system's package
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
@ -134,9 +147,6 @@ stack via its [documentation][stack]):
$ curl -sSL https://get.haskellstack.org/ | sh
```
Yet another way would be via [ghcup]; this is similar to installers like
`rustup`, in case you prefer that.
#### Create a New Project
Let's create a stack project. Since we're already in the correct
@ -199,7 +209,9 @@ 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`!
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
@ -209,7 +221,9 @@ be that you don't have the required C libraries installed. See
#### Install cabal-install
The easiest way to get [cabal-install] is probably via your system's package
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
@ -218,22 +232,22 @@ $ sudo dnf install cabal-install # Fedora
$ sudo pacman -S cabal-install # Arch
```
If your distribution does not package cabal-install, [ghcup][] is another
option. See also <https://www.haskell.org/cabal/#install-upgrade>.
See also <https://www.haskell.org/cabal/#install-upgrade>.
#### Create a New Project
Let's create a cabal project. Since we're already in the correct
directory (`~/.config/xmonad`) with `xmonad` and `xmonad-contrib`
subdirectories, we'll instruct cabal to use them. Create a file named
`cabal.project` containing:
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 skip this step, cabal will use the latest releases from [Hackage][]
instead.)
(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
@ -242,7 +256,7 @@ libraries and then build the xmonad binary:
``` console
$ cabal update
$ cabal install --package-env=$HOME/.config/xmonad --lib xmonad xmonad-contrib
$ cabal install --package-env=$HOME/.config/xmonad --lib base xmonad xmonad-contrib
$ cabal install --package-env=$HOME/.config/xmonad xmonad
```
@ -343,6 +357,15 @@ exec stack ghc -- \
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
@ -371,6 +394,9 @@ executable will also be within that directory and not in
[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/
[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

View File

@ -2,7 +2,7 @@
## The XMonad Core Team
* Brandon S Allbery [GitHub][geekosaur], IRC: `geekosaur`
* Brandon S Allbery [GitHub][geekosaur], IRC: `geekosaur`, [GPG][gpg:geekosaur]
* Brent Yorgey [GitHub][byorgey], IRC: `byorgey`
@ -10,10 +10,10 @@
* Sibi Prabakaran [GitHub][psibi], [Twitter][twitter:psibi], IRC: `sibi`
* slotThe [GitHub][slotThe], IRC: `Solid`
* Tomáš Janoušek [GitHub][liskin], [Twitter][twitter:liskin], IRC: `liskin`, [GPG][gpg:liskin]
* Tony Zorman [GitHub][slotThe], IRC: `Solid`, [GPG][gpg:slotThe]
[geekosaur]: https://github.com/geekosaur
[byorgey]: https://github.com/byorgey
[dmwit]: https://github.com/dmwit
@ -21,7 +21,9 @@
[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
@ -71,38 +73,40 @@ When the time comes to release another version of xmonad and xmonad-contrib:
2. Review documentation files and make sure they are accurate:
- [`README.md`](README.md)
- [`CHANGES.md`](CHANGES.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/)
If the manpage changes, wait for the CI to rebuild the rendered outputs.
3. Make sure that `tested-with:` covers several recent releases of GHC, that
3. Update the website:
- Draft a [new release announcement][web-announce].
- Check install instructions, guided tour, keybindings cheat sheet, …
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.
4. Create a release on GitHub:
- https://github.com/xmonad/xmonad/releases/new
- https://github.com/xmonad/xmonad-contrib/releases/new
CI will upload a release candidate to Hackage. Check again that
everything looks good. To publish a final release, run the CI workflow
once again with the correct version number:
5. Trigger the Haskell-CI workflow and fill in the candidate version number.
This will upload a release candidate to Hackage.
- https://github.com/xmonad/xmonad/actions/workflows/haskell-ci.yml
- https://github.com/xmonad/xmonad-contrib/actions/workflows/haskell-ci.yml
See [haskell-ci-hackage.patch][] for details about the release infrastructure.
Check that everything looks good. If not, push fixes and do another
candidate. When everything's ready, create a release on GitHub:
5. Update the website:
- https://github.com/xmonad/xmonad/releases/new
- https://github.com/xmonad/xmonad-contrib/releases/new
- Post a [new release announcement][web-announce]
- Check install instructions, guided tour, keybindings cheat sheet, …
CI will automatically upload the final release to Hackage.
7. Post announcement to:
See [haskell-ci-hackage.patch][] for details about the Hackage automation.
6. Post announcement to:
- [xmonad.org website](https://github.com/xmonad/xmonad-web/tree/gh-pages/news/_posts)
- [XMonad mailing list](https://mail.haskell.org/mailman/listinfo/xmonad)
@ -111,13 +115,22 @@ When the time comes to release another version of xmonad and xmonad-contrib:
- [Twitter](https://twitter.com/xmonad)
- [Reddit](https://www.reddit.com/r/xmonad/)
See [old announcements][old-announce] for inspiration.
See [old announcements][old-announce] ([even older][older-announce]) for inspiration.
7. Trigger xmonad-docs build to generate and persist docs for the just
released version:
- https://github.com/xmonad/xmonad-docs/actions/workflows/stack.yml
8. Bump version for development (add `.9`) and prepare fresh sections in
[`CHANGES.md`](CHANGES.md).
[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/tree/55614349421ebafaef4a47424fcb16efa80ff768
[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
## Website and Other Accounts

View File

@ -1,35 +1,20 @@
<p align="center">
<a href="https://xmonad.org/">
<img alt="XMonad logo" src="https://xmonad.org/images/logo-wrapped.svg" height=150>
</a>
<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>
<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/workflow/status/xmonad/xmonad/Stack?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/workflow/status/xmonad/xmonad/Haskell-CI?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/workflow/status/xmonad/xmonad/Nix?label=Nix&logo=githubactions&logoColor=white">
</a>
<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>
<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>
# xmonad

View File

@ -38,13 +38,13 @@ package manager, you will need to `xmonad --recompile` _every time_ a
Haskell dependency is updated—else xmonad may fail to start when you
want to log in!
We're going to assume xmonad version `0.17.0` and xmonad-contrib version
`0.17.0` here, though most of these steps should work with older
versions as well. When we get to the relevant parts, will point you to
alternatives that work with at least xmonad version `0.15` and
xmonad-contrib version `0.16`. This will usually be accompanied by a
big "_IF YOU ARE ON A VERSION `< 0.17.0`_", so don't worry about missing
it!
We're going to assume xmonad version `>= 0.17.0` and xmonad-contrib
version `>= 0.17.0` here, though most of these steps should work with
older versions as well. When we get to the relevant parts, will point
you to alternatives that work with at least xmonad version `0.15` and
xmonad-contrib version `0.16`. This will usually be accompanied by big
warning labels for the respective version bounds, so don't worry about
missing it!
Throughout the tutorial we will use, for keybindings, a syntax very akin
to the [GNU Emacs conventions] for the same thing—so `C-x` means "hold
@ -54,7 +54,7 @@ in our case `M` will not necessarily mean Alt (also called `Meta`), but
to Super instead (I will show you how to do this below).
This guide should work for any GNU/Linux distribution and even for BSD
folks. Because debian-based distributions are still rather popular, we
folks. Because Debian-based distributions are still rather popular, we
will give you the `apt` commands when it comes to installing software.
If you use another distribution, just substitute the appropriate
commands for your system.
@ -77,6 +77,11 @@ a live xmonad session in some capacity. If you have set up your
`~/.xinitrc` as directed in the xmonad guided tour, you should be good
to go! If not, just smack an `exec xmonad` at the bottom of that file.
In particular, it might be a good idea to set a wallpaper beforehand.
Otherwise, when switching workspaces or closing windows, you might start
seeing "shadows" of windows that were there before, unable to interact
with them.
## Installing Xmobar
What we need to do now—provided we want to use a bar at all—is to
@ -108,6 +113,8 @@ utility modules we will use. At the very top of the file, write
import XMonad
import XMonad.Util.EZConfig
-- NOTE: Only needed for versions < 0.18.0! For 0.18.0 and up, this is
-- already included in the XMonad import and will give you a warning!
import XMonad.Util.Ungrab
```
@ -187,8 +194,8 @@ example, but that will change soon enough so it's worth introducing it
here as well.
What if we wanted to add other keybindings? Say you also want to bind
`M-S-z` to lock your screen with the screensaver, `M-S-=` to take a
snapshot of one window, and `M-]` to spawn Firefox. This can be
`M-S-z` to lock your screen with the screensaver, `M-C-s` to take a
snapshot of one window, and `M-f` to spawn Firefox. This can be
achieved with the `additionalKeysP` function from the
[XMonad.Util.EZConfig] module—luckily we already have it imported! Our
config file, starting with `main`, now looks like:
@ -200,8 +207,8 @@ main = xmonad $ def
}
`additionalKeysP`
[ ("M-S-z", spawn "xscreensaver-command -lock")
, ("M-S-=", unGrab *> spawn "scrot -s" )
, ("M-]" , spawn "firefox" )
, ("M-C-s", unGrab *> spawn "scrot -s" )
, ("M-f" , spawn "firefox" )
]
```
@ -247,7 +254,7 @@ import XMonad.Layout.ThreeColumns
to the top of our configuration file. Most modules have a lot of
accompanying text and usage examples in them—so while the type
signatures may seem scary, don't be afraid to look up the
[xmonad-contrib documentation] on hackage!
[xmonad-contrib documentation] on Hackage!
Next we just need to tell xmonad that we want to use that particular
layout. To do this, there is the `layoutHook`. Let's use the default
@ -263,7 +270,7 @@ myLayout = tiled ||| Mirror tiled ||| Full
```
The so-called `where`-clause above simply consists of local declarations
that might clutter things up where they all declared at the top-level
that might clutter things up were they all declared at the top-level
like this
``` haskell
@ -313,8 +320,8 @@ main = xmonad $ def
}
`additionalKeysP`
[ ("M-S-z", spawn "xscreensaver-command -lock")
, ("M-S-=", unGrab *> spawn "scrot -s" )
, ("M-]" , spawn "firefox" )
, ("M-C-s", unGrab *> spawn "scrot -s" )
, ("M-f" , spawn "firefox" )
]
```
@ -379,12 +386,16 @@ effect (and some applications, like chromium, will misbehave and need
some [Hacks] to make this work), we will also add the relevant function
to get "proper" fullscreen behaviour here.
---
_IF YOU ARE ON A VERSION `< 0.17.0`_: The `ewmhFullscreen` function does
not exist in these versions. Instead of it, you can try to add
`fullscreenEventHook` to your `handleEventHook` to achieve similar
functionality (how to do this is explained in the documentation of
[XMonad.Hooks.EwmhDesktops]).
---
To use the two combinators, we compose them with the `xmonad` function
in the following way:
@ -396,8 +407,8 @@ main = xmonad $ ewmhFullscreen $ ewmh $ def
}
`additionalKeysP`
[ ("M-S-z", spawn "xscreensaver-command -lock")
, ("M-S-=", unGrab *> spawn "scrot -s" )
, ("M-]" , spawn "firefox" )
, ("M-C-s", unGrab *> spawn "scrot -s" )
, ("M-f" , spawn "firefox" )
]
```
@ -420,8 +431,8 @@ myConfig = def
}
`additionalKeysP`
[ ("M-S-z", spawn "xscreensaver-command -lock")
, ("M-S-=", unGrab *> spawn "scrot -s" )
, ("M-]" , spawn "firefox" )
, ("M-C-s", unGrab *> spawn "scrot -s" )
, ("M-f" , spawn "firefox" )
]
```
@ -430,7 +441,7 @@ Much better!
## Make XMonad and Xmobar Talk to Each Other
Onto the main dish. First, we have to import the necessary modules.
Add the following to your list of imports:
Add the following to your list of imports
``` haskell
import XMonad.Hooks.DynamicLog
@ -438,23 +449,27 @@ import XMonad.Hooks.StatusBar
import XMonad.Hooks.StatusBar.PP
```
_IF YOU ARE ON A VERSION `< 0.17.0`_: The `XMonad.Hooks.StatusBar` and
`XMonad.Hooks.StatusBar.PP` modules don't exist yet. You can find
everything you need in the `XMonad.Hooks.DynamicLog` module, so remove
these two imports.
Replace your `main` function above with:
and replace your `main` function above with:
``` haskell
main :: IO ()
main = xmonad $ ewmhFullscreen $ ewmh $ xmobarProp $ myConfig
```
_IF YOU ARE ON A VERSION `< 0.17.0`_: The `xmobarProp` function does not
exist in these versions. Instead of it, use `xmobar` via
`main = xmonad . ewmh =<< xmobar myConfig` and carefully read the part
about pipes later on (`xmobar` uses pipes to make xmobar talk to
xmonad).
---
_IF YOU ARE ON A VERSION `< 0.17.0`_: The `XMonad.Hooks.StatusBar` and
`XMonad.Hooks.StatusBar.PP` modules don't exist yet. You can find
everything you need in the `XMonad.Hooks.DynamicLog` module, so remove
these two imports.
Further, the `xmobarProp` function does not exist in older versions.
Instead of it, use `xmobar` via `main = xmonad . ewmh =<< xmobar
myConfig` and carefully read the part about pipes later on (`xmobar`
uses pipes to make xmobar talk to xmonad). Do note the lack of
`ewmhFullscreen`, as explained above!
---
As a quick side-note, we could have also written
@ -540,11 +555,15 @@ when things are not being read! For this reason we have to use
(this is useful, for example, for [XMonad.Util.ClickableWorkspaces],
which is a new feature in `0.17.0`).
---
_IF YOU ARE ON A VERSION `< 0.17.0`_: As discussed above, the `xmobar`
function uses pipes, so you actually do want to use the `StdinReader`.
Simply replace _all_ occurences of `XMonadLog` with `StdinReader`
below (don't forget the template!)
---
## Configuring Xmobar
Now, before this will work, we have to configure xmobar. Here's a nice
@ -592,14 +611,14 @@ Config { overrideRedirect = False
```
First, we set the font to use for the bar, as well as the colors. The
position options are documented well on the [xmobar home page] or,
alternatively, in the [quick-start.org] on GitHub. The particular
option of `TopW L 90` says to put the bar in the upper left of the
screen, and make it consume 90% of the width of the screen (we need to
leave a little bit of space for `trayer-srg`). If you're up for it—and
this really requires more shell-scripting than Haskell knowledge—you can
also try to seamlessly embed trayer into xmobar by using
[trayer-padding-icon.sh] and following the advice given in that thread.
position options are documented well in xmobar's [quick-start.org]. The
particular option of `TopW L 90` says to put the bar in the upper left
of the screen, and make it consume 90% of the width of the screen (we
need to leave a little bit of space for `trayer-srg`). If you're up for
it—and this really requires more shell-scripting than Haskell
knowledge—you can also try to seamlessly embed trayer into xmobar by
using [trayer-padding-icon.sh] and following the advice given in that
thread.
In the commands list you, well, define commands. Commands are the
pieces that generate the content to be displayed in your bar. These
@ -660,6 +679,8 @@ main = xmonad
$ myConfig
```
---
_IF YOU ARE ON A VERSION `< 0.17.0`_: `xmobar` has a similar definition,
relying on `statusBar` alone: `xmobar = statusBar "xmobar" xmobarPP
toggleStrutsKey`. Sadly, the `defToggleStrutsKey` function is not yet
@ -668,7 +689,6 @@ _IF YOU ARE ON A VERSION `< 0.17.0`_: `xmobar` has a similar definition,
``` haskell
main :: IO ()
main = xmonad
. ewmhFullscreen
. ewmh
=<< statusBar "xmobar" def toggleStrutsKey myConfig
where
@ -676,6 +696,8 @@ main = xmonad
toggleStrutsKey XConfig{ modMask = m } = (m, xK_b)
```
---
The `defToggleStrutsKey` here is just the key with which you can toggle
the bar; it is bound to `M-b`. If you want to change this, you can also
define your own:
@ -772,6 +794,8 @@ myXmobarPP = def
lowWhite = xmobarColor "#bbbbbb" ""
```
---
_IF YOU ARE ON A VERSION `< 0.17`_: Both `logTitles` and `xmobarBorder`
are not available yet, so you will have to remove them. As an
alternative to `xmobarBorder`, a common way to "mark" the currently
@ -779,6 +803,8 @@ _IF YOU ARE ON A VERSION `< 0.17`_: Both `logTitles` and `xmobarBorder`
`ppCurrent = wrap (blue "[") (blue "]")` and see if you like it. Also
read the bit about `ppOrder` further down!
---
That's a lot! But don't worry, take a deep breath and remind yourself
of what you read above in the documentation of the [PP record]. Even if
you haven't read the documentation yet, most of the fields should be
@ -882,10 +908,10 @@ apt-get install nm-applet feh xfce4-power-manager
First, configure xscreensaver how you like it with the
`xscreensaver-demo` command. Now, we will set these things up in
`~/.xinitrc` (we could also do most of this in xmonad's `startupHook`,
but `~/.xinitrc` is perhaps more standard). If you want to use xmonad
with a desktop environment, see [Basic Desktop Environment Integration]
for how to do this.
`~/.xinitrc`. If you want to use XMonad with a desktop environment, see
[Basic Desktop Environment Integration] for how to do this. For a
version using XMonad's built in functionality instead, see the [next
section][using-the-startupHook].
Your `~/.xinitrc` may wind up looking like this:
@ -933,6 +959,38 @@ Mission accomplished!
Of course substitute the wallpaper for one of your own. If you like the
one used above, you can find it [here](https://i.imgur.com/9MQHuZx.png).
### Using the `startupHook`
Instead of the `.xinitrc` file, one can also use XMonad's built in
`startupHook` in order to auto start programs. The
[XMonad.Util.SpawnOnce] library is perfect for this use case, allowing
programs to start only once, and not with every invocation of `M-q`!
This requires but a small change in `myConfig`:
``` haskell
-- import XMonad.Util.SpawnOnce (spawnOnce)
myConfig = def
{ modMask = mod4Mask -- Rebind Mod to the Super key
, layoutHook = myLayout -- Use custom layouts
, startupHook = myStartupHook
}
`additionalKeysP`
[ ("M-S-z", spawn "xscreensaver-command -lock")
, ("M-C-s", unGrab *> spawn "scrot -s" )
, ("M-f" , spawn "firefox" )
]
myStartupHook :: X ()
myStartupHook = do
spawnOnce "trayer --edge top --align right --SetDockType true \
\--SetPartialStrut true --expand true --width 10 \
\--transparent true --tint 0x5f5f5f --height 18"
spawnOnce "feh --bg-fill --no-fehbg ~/.wallpapers/haskell-red-noise.png"
-- … and so on …
```
## Final Touches
There may be some programs that you don't want xmonad to tile. The
@ -965,9 +1023,9 @@ class name to float by defining the following manageHook:
myManageHook = (className =? "Gimp" --> doFloat)
```
Say we also want to float all dialogs. This is easy with the `isDialog`
function from [XMonad.Hooks.ManageHelpers] (which you should import) and
a little modification to the `myManageHook` function:
Say we also want to float all dialog windows. This is easy with the
`isDialog` function from [XMonad.Hooks.ManageHelpers] (which you should
import) and a little modification to the `myManageHook` function:
``` haskell
myManageHook :: ManageHook
@ -989,8 +1047,8 @@ myConfig = def
}
`additionalKeysP`
[ ("M-S-z", spawn "xscreensaver-command -lock")
, ("M-S-=", unGrab *> spawn "scrot -s" )
, ("M-]" , spawn "firefox" )
, ("M-C-s", unGrab *> spawn "scrot -s" )
, ("M-f" , spawn "firefox" )
]
```
@ -1010,6 +1068,9 @@ import XMonad.Hooks.StatusBar.PP
import XMonad.Util.EZConfig
import XMonad.Util.Loggers
-- NOTE: Importing XMonad.Util.Ungrab is only necessary for versions
-- < 0.18.0! For 0.18.0 and up, this is already included in the
-- XMonad import and will generate a warning instead!
import XMonad.Util.Ungrab
import XMonad.Layout.Magnifier
@ -1032,8 +1093,8 @@ myConfig = def
}
`additionalKeysP`
[ ("M-S-z", spawn "xscreensaver-command -lock")
, ("M-S-=", unGrab *> spawn "scrot -s" )
, ("M-]" , spawn "firefox" )
, ("M-C-s", unGrab *> spawn "scrot -s" )
, ("M-f" , spawn "firefox" )
]
myManageHook :: ManageHook
@ -1113,7 +1174,7 @@ Config { overrideRedirect = False
}
```
For an explanation of the battery commands used above, see xmobars
For an explanation of the battery commands used above, see xmobar's
[battery] documentation.
You can also specify workspaces in the same way and feed them to xmobar
@ -1121,13 +1182,15 @@ via the property (e.g. have `"<fn=1>\xf120</fn>"` as one of your
workspace names).
As an example how this would look like in a real configuration, you can
look at [Liskin's], [slotThe's], or [TheMC47's] xmobar configuration.
Do note that the last two are Haskell-based and thus may be a little
hard to understand for newcomers.
look at [Liskin's old][liskin-xmobarrc-old], [Liskin's current][liskin-xmobarrc],
[slotThe's][slotThe-xmobarrc], or [TheMC47's][TheMC47-xmobarrc] xmobar
configuration. Do note that the last three are Haskell-based and thus may
be a little hard to understand for newcomers.
[Liskin's]: https://github.com/liskin/dotfiles/blob/home/.xmobarrc
[TheMC47's]: https://github.com/TheMC47/dotfiles/tree/master/xmobar/xmobarrc
[slotThe's]: https://gitlab.com/slotThe/dotfiles/-/blob/master/xmobar/.config/xmobarrc/src/xmobarrc.hs
[liskin-xmobarrc-old]: https://github.com/liskin/dotfiles/blob/75dfc057c33480ee9d3300d4d02fb79a986ef3a5/.xmobarrc
[liskin-xmobarrc]: https://github.com/liskin/dotfiles/blob/home/.xmonad/xmobar.hs
[TheMC47-xmobarrc]: https://github.com/TheMC47/dotfiles/tree/master/xmobar/xmobarrc
[slotThe-xmobarrc]: https://gitlab.com/slotThe/dotfiles/-/blob/master/xmobar/.config/xmobarrc/src/xmobarrc.hs
### Renaming Layouts
@ -1222,7 +1285,7 @@ either :)
[log]: https://ircbrowse.tomsmeding.com/browse/lcxmonad
[EWMH]: https://specifications.freedesktop.org/wm-spec/wm-spec-1.3.html
[ICCCM]: https://tronche.com/gui/x/icccm/
[webchat]: https://kiwiirc.com/nextclient/irc.libera.chat/?#xmonad
[webchat]: https://web.libera.chat/#xmonad
[about xmonad]: https://xmonad.org/about.html
[shell variable]: https://www.shellscript.sh/variables1.html
[xmonad-testing]: https://github.com/xmonad/xmonad-testing
@ -1230,35 +1293,35 @@ either :)
[xmonad guided tour]: https://xmonad.org/tour.html
[xmonad mailing list]: https://mail.haskell.org/mailman/listinfo/xmonad
[xmonad's GitHub page]: https://github.com/xmonad/xmonad
[trayer-padding-icon.sh]: https://github.com/jaor/xmobar/issues/239#issuecomment-233206552
[trayer-padding-icon.sh]: https://codeberg.org/xmobar/xmobar/issues/239#issuecomment-537931
[xmonad-contrib documentation]: https://hackage.haskell.org/package/xmonad-contrib
[GNU Image Manipulation Program]: https://www.gimp.org/
[Basic Desktop Environment Integration]: https://wiki.haskell.org/Xmonad/Basic_Desktop_Environment_Integration
[Hacks]: https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Util-Hacks.html
[PP record]: https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Hooks-DynamicLog.html#t:PP
[INSTALL.md]: INSTALL.md
[PP record]: https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Hooks-DynamicLog.html#t:PP
[XMonad.Config]: https://github.com/xmonad/xmonad/blob/master/src/XMonad/Config.hs
[XMonad.ManageHook]: https://xmonad.github.io/xmonad-docs/xmonad/XMonad-ManageHook.html
[XMonad.Util.Loggers]: https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Util-Loggers.html
[XMonad.Util.EZConfig]: https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Util-EZConfig.html
[XMonad.Layout.Renamed]: https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Layout-Renamed.html
[XMonad.Layout.Magnifier]: https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Layout-Magnifier.html
[XMonad.Doc.Contributing]: https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Doc-Configuring.html
[XMonad.Hooks.EwmhDesktops]: https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Hooks-EwmhDesktops.html
[XMonad.Layout.ThreeColumns]: https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Layout-ThreeColumns.html
[XMonad.Hooks.ManageHelpers]: https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Hooks-ManageHelpers.html
[XMonad.Layout.Magnifier]: https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Layout-Magnifier.html
[XMonad.Layout.Renamed]: https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Layout-Renamed.html
[XMonad.Layout.ThreeColumns]: https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Layout-ThreeColumns.html
[XMonad.ManageHook]: https://xmonad.github.io/xmonad-docs/xmonad/XMonad-ManageHook.html
[XMonad.Util.ClickableWorkspaces]: https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Util-ClickableWorkspaces.html
[XMonad.Util.EZConfig]: https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Util-EZConfig.html
[XMonad.Util.Loggers]: https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Util-Loggers.html
[XMonad.Util.SpawnOnce]: https://hackage.haskell.org/package/xmonad-contrib/docs/XMonad-Util-SpawnOnce.html
[xmobar]: https://xmobar.org/
[battery]: https://github.com/jaor/xmobar/blob/master/doc/plugins.org#batteryp-dirs-args-refreshrate
[xmobar.hs]: https://github.com/jaor/xmobar/blob/master/examples/xmobar.hs
[xmobar]: https://codeberg.org/xmobar/xmobar
[battery]: https://codeberg.org/xmobar/xmobar/src/branch/master/doc/plugins.org#batteryp-dirs-args-refreshrate
[xmobar.hs]: https://codeberg.org/xmobar/xmobar/src/branch/master/etc/xmobar.hs
[Wikipedia page]: https://en.wikipedia.org/wiki/ICAO_airport_code#Prefixes
[quick-start.org]: https://github.com/jaor/xmobar/blob/master/doc/quick-start.org#configuration-options
[quick-start.org]: https://codeberg.org/xmobar/xmobar/src/branch/master/doc/quick-start.org#configuration-options
[jao's xmobar.hs]: https://codeberg.org/jao/xmobar-config
[weather monitor]: https://github.com/jaor/xmobar/blob/master/doc/plugins.org#weather-monitors
[xmobar home page]: https://xmobar.org/
[xmobar's `Installation` section]: https://github.com/jaor/xmobar#installation
[weather monitor]: https://codeberg.org/xmobar/xmobar/src/branch/master/doc/plugins.org#weather-monitors
[xmobar's `Installation` section]: https://codeberg.org/xmobar/xmobar#installation
[Haskell]: https://www.haskell.org/
[trayer-srg]: https://github.com/sargon/trayer-srg

View File

@ -12,3 +12,6 @@ raw-project
optimization: False
package xmonad
flags: +pedantic
-- avoid --haddock-all which overwrites *-docs.tar.gz with tests docs
haddock-components: libs

105
flake.nix
View File

@ -1,27 +1,106 @@
# This file is maintained by @IvanMalison (github)
# 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:IvanMalison/gitignore.nix/master;
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, git-ignore-nix }:
outputs = { self, flake-utils, nixpkgs, unstable, git-ignore-nix }:
let
overlay = final: prev: {
haskellPackages = prev.haskellPackages.override (old: {
overrides = prev.lib.composeExtensions (old.overrides or (_: _: {}))
(hself: hsuper: {
xmonad = hself.callCabal2nix "xmonad" (git-ignore-nix.gitIgnoreSource ./.) { };
});
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 = pkgs.haskellPackages.shellFor {
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; };
};
defaultPackage = pkgs.haskellPackages.xmonad;
}) // { inherit overlay overlays; } ;
}

View File

@ -1,10 +1,24 @@
.\" Automatically generated by Pandoc 2.5
.\" Automatically generated by Pandoc 3.1.3
.\"
.\" 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 \- Tiling Window Manager
xmonad - Tiling Window Manager
.SH Description
.PP
\f[I]xmonad\f[R] is a minimalist tiling window manager for X, written in
@ -36,27 +50,27 @@ 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[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[R] starts, workspace 1 is on screen 1, workspace 2 is
on screen 2, etc.
@ -67,115 +81,115 @@ and visible workspaces are swapped.
xmonad has several flags which you may pass to the executable.
These flags are:
.TP
.B \[en]recompile
\[en]recompile
Recompiles your \f[I]xmonad.hs\f[R] configuration
.TP
.B \[en]restart
\[en]restart
Causes the currently running \f[I]xmonad\f[R] process to restart
.TP
.B \[en]replace
\[en]replace
Replace the current window manager with xmonad
.TP
.B \[en]version
\[en]version
Display version of \f[I]xmonad\f[R]
.TP
.B \[en]verbose\-version
\[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
.TP
.B mod\-p
mod-p
Launch dmenu
.TP
.B mod\-shift\-p
mod-shift-p
Launch gmrun
.TP
.B mod\-shift\-c
mod-shift-c
Close the focused window
.TP
.B mod\-space
mod-space
Rotate through the available layout algorithms
.TP
.B mod\-shift\-space
mod-shift-space
Reset the layouts on the current workspace to default
.TP
.B mod\-n
mod-n
Resize viewed windows to the correct size
.TP
.B mod\-tab
mod-tab
Move focus to the next window
.TP
.B mod\-shift\-tab
mod-shift-tab
Move focus to the previous window
.TP
.B mod\-j
mod-j
Move focus to the next window
.TP
.B mod\-k
mod-k
Move focus to the previous window
.TP
.B mod\-m
mod-m
Move focus to the master window
.TP
.B mod\-return
mod-return
Swap the focused window and the master window
.TP
.B mod\-shift\-j
mod-shift-j
Swap the focused window with the next window
.TP
.B mod\-shift\-k
mod-shift-k
Swap the focused window with the previous window
.TP
.B mod\-h
mod-h
Shrink the master area
.TP
.B mod\-l
mod-l
Expand the master area
.TP
.B mod\-t
mod-t
Push window back into tiling
.TP
.B mod\-comma
mod-comma
Increment the number of windows in the master area
.TP
.B mod\-period
mod-period
Deincrement the number of windows in the master area
.TP
.B mod\-shift\-q
mod-shift-q
Quit xmonad
.TP
.B mod\-q
mod-q
Restart xmonad
.TP
.B mod\-shift\-slash
mod-shift-slash
Run xmessage with a summary of the default keybindings (useful for
beginners)
.TP
.B mod\-question
mod-question
Run xmessage with a summary of the default keybindings (useful for
beginners)
.TP
.B mod\-[1..9]
mod-[1..9]
Switch to workspace N
.TP
.B mod\-shift\-[1..9]
mod-shift-[1..9]
Move client to workspace N
.TP
.B mod\-{w,e,r}
mod-{w,e,r}
Switch to physical/Xinerama screens 1, 2, or 3
.TP
.B mod\-shift\-{w,e,r}
mod-shift-{w,e,r}
Move client to screen 1, 2, or 3
.TP
.B mod\-button1
mod-button1
Set the window to floating mode and move by dragging
.TP
.B mod\-button2
mod-button2
Raise the window to the top of the stack
.TP
.B mod\-button3
mod-button3
Set the window to floating mode and resize by dragging
.SH Examples
.PP
@ -188,27 +202,26 @@ exec xmonad
.SH Customization
.PP
xmonad is customized in your \f[I]xmonad.hs\f[R], and then restarted
with mod\-q.
with mod-q.
You can choose where your configuration file lives by
.IP "1." 3
Setting \f[C]XMONAD_DATA_DIR,\f[R] \f[C]XMONAD_CONFIG_DIR\f[R], and
\f[C]XMONAD_CACHE_DIR\f[R]; \f[I]xmonad.hs\f[R] is then expected to be
in \f[C]XMONAD_CONFIG_DIR\f[R].
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[C]XDG_CONFIG_HOME\f[R].
Note that, in this case, xmonad will use \f[C]XDG_DATA_HOME\f[R] and
\f[C]XDG_CACHE_HOME\f[R] for its data and cache directory respectively.
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 (https://xmonad.org).
.SS Modular Configuration
.PP
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.
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]\[ti]/.xmonad/lib/XMonad/Stack/MyAdditions.hs\f[R] could contain:
.IP
@ -220,7 +233,7 @@ module XMonad.Stack.MyAdditions (function1) where
.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

@ -7,33 +7,186 @@
<meta name="author" content="" />
<meta name="dcterms.date" content="2021-10-27" />
<title>XMONAD(1) Tiling Window Manager</title>
<style type="text/css">
<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;}
span.underline{text-decoration: underline;}
div.column{display: inline-block; vertical-align: top; width: 50%;}
</style>
<style type="text/css">
a.sourceLine { display: inline-block; line-height: 1.25; }
a.sourceLine { pointer-events: none; color: inherit; text-decoration: inherit; }
a.sourceLine:empty { height: 1.2em; }
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 { white-space: pre; position: relative; }
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 {
code.sourceCode { white-space: pre-wrap; }
a.sourceLine { text-indent: -1em; padding-left: 1em; }
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource a.sourceLine
{ position: relative; left: -4em; }
pre.numberSource a.sourceLine::before
{ content: attr(title);
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; pointer-events: all; display: inline-block;
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;
@ -44,13 +197,13 @@ pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-le
div.sourceCode
{ }
@media screen {
a.sourceLine::before { text-decoration: underline; }
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 { } /* BuiltIn */
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 */
@ -63,7 +216,7 @@ code span.er { color: #ff0000; font-weight: bold; } /* Error */
code span.ex { } /* Extension */
code span.fl { color: #40a070; } /* Float */
code span.fu { color: #06287e; } /* Function */
code span.im { } /* Import */
code span.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 */
@ -83,165 +236,255 @@ code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warni
<p class="author"></p>
<p class="date">27 October 2021</p>
</header>
<nav id="TOC">
<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>
</nav>
<h1 id="name">Name</h1>
<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 “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>
<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 <em>xmonad.hs</em> configuration
<dd>
Recompiles your <em>xmonad.hs</em> configuration
</dd>
<dt>restart</dt>
<dd>Causes the currently running <em>xmonad</em> process to restart
<dd>
Causes the currently running <em>xmonad</em> process to restart
</dd>
<dt>replace</dt>
<dd>Replace the current window manager with xmonad
<dd>
Replace the current window manager with xmonad
</dd>
<dt>version</dt>
<dd>Display version of <em>xmonad</em>
<dd>
Display version of <em>xmonad</em>
</dd>
<dt>verbose-version</dt>
<dd>Display detailed version of <em>xmonad</em>
<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>
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 your <em>xmonad.hs</em>, and then restarted with mod-q. You can choose where your configuration file lives by</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>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>
<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>
<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 GHCs searchpath. Hierarchical modules are supported: for example, the file <em>~/.xmonad/lib/XMonad/Stack/MyAdditions.hs</em> could contain:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb1-1" title="1"><span class="kw">module</span> <span class="dt">XMonad.Stack.MyAdditions</span> (function1) <span class="kw">where</span></a>
<a class="sourceLine" id="cb1-2" title="2"> function1 <span class="ot">=</span> <span class="fu">error</span> <span class="st">&quot;function1: Not implemented yet!&quot;</span></a></code></pre></div>
<p>Your xmonad.hs may then import XMonad.Stack.MyAdditions as if that module was contained within xmonad or xmonad-contrib.</p>
<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

@ -123,7 +123,7 @@ 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")
@ -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)
]

View File

@ -1,5 +1,6 @@
{-# OPTIONS_GHC -fno-warn-missing-signatures -fno-warn-orphans #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Config
@ -218,7 +219,7 @@ 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 ), helpCommand) -- %! Run xmessage with a summary of the default keybindings (useful for beginners)

View File

@ -1,6 +1,14 @@
{-# LANGUAGE ExistentialQuantification, FlexibleInstances, GeneralizedNewtypeDeriving,
MultiParamTypeClasses, TypeSynonymInstances, DeriveDataTypeable,
LambdaCase, NamedFieldPuns, DeriveTraversable #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE ViewPatterns #-}
-----------------------------------------------------------------------------
-- |
@ -26,7 +34,7 @@ module XMonad.Core (
StateExtension(..), ExtensionClass(..), ConfExtension(..),
runX, catchX, userCode, userCodeDef, io, catchIO, installSignalHandlers, uninstallSignalHandlers,
withDisplay, withWindowSet, isRoot, runOnWorkspaces,
getAtom, spawn, spawnPID, xfork, xmessage, recompile, trace, whenJust, whenX,
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, Directories'(..), Directories, getDirectories,
@ -35,17 +43,21 @@ module XMonad.Core (
import XMonad.StackSet hiding (modify)
import Prelude
import Control.Exception (fromException, try, bracket, bracket_, throw, finally, SomeException(..))
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 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 Data.List (isInfixOf)
import System.Environment (lookupEnv)
import Data.List (isInfixOf, intercalate, (\\))
import System.FilePath
import System.IO
import System.Info
@ -60,8 +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 (Ap(..))
import qualified Data.Map as M
import qualified Data.Set as S
@ -156,18 +168,8 @@ newtype ScreenDetail = SD { screenRect :: Rectangle }
-- instantiated on 'XConf' and 'XState' automatically.
--
newtype X a = X (ReaderT XConf (StateT XState IO) a)
deriving (Functor, Monad, MonadFail, MonadIO, MonadState XState, MonadReader XConf)
instance Applicative X where
pure = return
(<*>) = ap
instance Semigroup a => Semigroup (X a) where
(<>) = liftM2 (<>)
instance (Monoid a) => Monoid (X a) where
mempty = return mempty
mappend = liftM2 mappend
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
@ -175,16 +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 Semigroup a => Semigroup (Query a) where
(<>) = liftM2 (<>)
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
@ -201,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
@ -209,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
@ -235,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
@ -421,9 +417,13 @@ data StateExtension =
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
@ -437,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
@ -451,14 +451,19 @@ 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
executeFile "xmessage" True
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-*-*-*-*-*-*-*"
@ -577,21 +582,32 @@ srcFileName, libFileName :: Directories -> FilePath
srcFileName Directories{ cfgDir } = cfgDir </> "xmonad.hs"
libFileName Directories{ cfgDir } = cfgDir </> "lib"
buildScriptFileName, stackYamlFileName :: Directories -> FilePath
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 | CompileStackGhc FilePath | CompileScript FilePath
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 <|> useGhc
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
@ -605,17 +621,57 @@ detectCompile dirs = tryScript <|> tryStack <|> useGhc
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 neither "
<> show buildScript <> " nor " <> show stackYaml <> " exists."
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
@ -635,12 +691,15 @@ shouldCompile dirs CompileGhc = do
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."
@ -651,17 +710,32 @@ getModTime f = E.catch (Just <$> getModificationTime f) (\(SomeException _) -> r
compile :: Directories -> Compile -> IO ExitCode
compile dirs method =
bracket_ uninstallSignalHandlers installSignalHandlers $
bracket (openFile (errFileName dirs) WriteMode) hClose $ \err -> do
let run = runProc (cfgDir dirs) err
withFile (errFileName dirs) WriteMode $ \err -> do
let run = runProc err
case method of
CompileGhc ->
run "ghc" ghcArgs
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@
@ -673,13 +747,51 @@ compile dirs method =
, "-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 cwd err exe args = do
hPutStrLn err $ unwords $ "$" : exe : args
hFlush err
(_, _, _, h) <- createProcess_ "runProc" (proc exe args){ cwd = Just cwd, std_err = UseHandle err }
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
@ -779,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, LambdaCase, MultiWayIf #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PatternGuards #-}
-- --------------------------------------------------------------------------
-- |
@ -39,7 +41,7 @@ import Data.Maybe (fromMaybe)
data Resize = Shrink | Expand
-- | Increase the number of clients in the master pane.
data IncMasterN = IncMasterN !Int
newtype IncMasterN = IncMasterN Int
instance Message Resize
instance Message IncMasterN
@ -60,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)
@ -199,8 +205,8 @@ choose (Choose d l r) d' ml mr = f lr
(CL, CR) -> (hide l' , return r')
(CR, CL) -> (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
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 CL l r) ms) =

View File

@ -1,4 +1,6 @@
{-# LANGUAGE MultiParamTypeClasses, FlexibleContexts, NamedFieldPuns #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE MultiParamTypeClasses #-}
----------------------------------------------------------------------------
-- |
-- Module : XMonad.Main
@ -13,17 +15,18 @@
--
-----------------------------------------------------------------------------
module XMonad.Main (xmonad, launch) where
module XMonad.Main (xmonad, buildLaunch, launch) where
import System.Locale.SetLocale
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 Control.Monad (filterM, guard, unless, void, when, forever)
import Data.Maybe (fromMaybe, isJust)
import Data.Monoid (getAll)
@ -87,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.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
@ -128,25 +131,6 @@ buildLaunch dirs = do
args <- getArgs
executeFile bin 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 []
sendEvent dpy rw False structureNotifyMask e
sync dpy False
-- | a wrapper for 'replace'
sendReplace :: IO ()
sendReplace = do
dpy <- openDisplay ""
let dflt = defaultScreen dpy
rootw <- rootWindow dpy dflt
replace dpy dflt rootw
-- | Entry point into xmonad for custom builds.
--
-- This function isn't meant to be called by the typical xmonad user
@ -194,11 +178,11 @@ launch initxmc drs = do
xinesc <- getCleanedScreenInfo dpy
nbc <- do v <- initColor dpy $ normalBorderColor xmc
~(Just nbc_) <- initColor dpy $ normalBorderColor Default.def
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
@ -242,7 +226,7 @@ launch initxmc drs = do
let extst = maybe M.empty extensibleState serializedSt
modify (\s -> s {extensibleState = extst})
setNumlockMask
cacheNumlockMask
grabKeys
grabButtons
@ -330,7 +314,7 @@ handle e@(DestroyWindowEvent {ev_window = w}) = do
-- 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
@ -340,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.
@ -428,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
@ -459,38 +443,14 @@ 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])
-- keycodeToKeysym returns noSymbol for all unbound keycodes, and we don't
-- want to grab those whenever someone accidentally uses def :: KeySym
let keysymMap = M.delete noSymbol keysymMap'
let 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)
-- | Grab the buttons
grabButtons :: X ()
@ -501,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
--
@ -27,7 +24,7 @@ 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,17 +58,14 @@ infixr 3 <&&>, <||>
-- | '&&' lifted to a 'Monad'.
(<&&>) :: Monad m => m Bool -> m Bool -> m Bool
(<&&>) x y = ifM x y (pure False)
x <&&> y = ifM x y (pure False)
-- | '||' lifted to a 'Monad'.
(<||>) :: Monad m => m Bool -> m Bool -> m Bool
(<||>) x y = ifM x (pure True) y
x <||> y = ifM x (pure True) y
-- | 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
-- | 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
@ -80,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)
@ -91,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
@ -106,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,4 +1,10 @@
{-# LANGUAGE FlexibleContexts, FlexibleInstances, MultiParamTypeClasses, PatternGuards #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE ScopedTypeVariables #-}
-- --------------------------------------------------------------------------
-- |
-- Module : XMonad.Operations
@ -18,7 +24,7 @@ module XMonad.Operations (
manage, unmanage, killWindow, kill, isClient,
setInitialProperties, setWMState, setWindowBorderWithFallback,
hide, reveal, tileWindow,
setTopFocus, focus,
setTopFocus, focus, isFixedSizeOrTransient,
-- * Manage Windows
windows, refresh, rescreen, modifyWindowSet, windowBracket, windowBracket_, clearEvents, getCleanedScreenInfo,
@ -27,10 +33,11 @@ module XMonad.Operations (
-- * Keyboard and Mouse
cleanMask, extraModifiers,
mouseDrag, mouseMoveWindow, mouseResizeWindow,
setButtonGrab, setFocusX,
setButtonGrab, setFocusX, cacheNumlockMask, mkGrabs, unGrab,
-- * Messages
sendMessage, broadcastMessage, sendMessageWithNoRefresh,
sendRestart, sendReplace,
-- * Save and Restore State
StateFile (..), writeStateToFile, readStateFile, restart,
@ -57,15 +64,17 @@ import qualified XMonad.StackSet as W
import Data.Maybe
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.Arrow (second)
import Control.Monad.Fix (fix)
import Control.Monad.Reader
import Control.Monad.State
import Control.Monad (forM, forM_, guard, join, unless, void, when)
import qualified Control.Exception as C
import System.IO
@ -78,6 +87,16 @@ import Graphics.X11.Xlib.Extras
-- ---------------------------------------------------------------------
-- Window manager operations
-- | 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.
@ -87,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
@ -98,7 +115,7 @@ 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
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
@ -128,7 +145,7 @@ killWindow w = withDisplay $ \d -> do
setEventType ev clientMessage
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 ()
@ -179,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
@ -205,7 +223,7 @@ 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
@ -221,8 +239,8 @@ windowBracket :: (a -> Bool) -> X a -> X a
windowBracket p action = withWindowSet $ \old -> do
a <- action
when (p a) . withWindowSet $ \new -> do
modifyWindowSet $ \_ -> old
windows $ \_ -> new
modifyWindowSet $ const old
windows $ const new
return a
-- | Perform an @X@ action. If it returns @Any True@, unwind the
@ -250,12 +268,11 @@ 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 a window by unmapping it and setting Iconified.
hide :: Window -> X ()
@ -342,12 +359,13 @@ getCleanedScreenInfo = io . fmap nubScreens . getScreenInfo
-- | 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
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 }
@ -409,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
@ -417,12 +435,68 @@ 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
@ -430,7 +504,7 @@ setFocusX w = withWindowSet $ \ws -> do
-- layout the windows, in which case changes are handled through a refresh.
sendMessage :: Message a => a -> X ()
sendMessage a = windowBracket_ $ do
w <- W.workspace . W.current <$> gets windowset
w <- gets $ W.workspace . W.current . windowset
ml' <- handleMessage (W.layout w) (SomeMessage a) `catchX` return Nothing
whenJust ml' $ \l' ->
modifyWindowSet $ \ws -> ws { W.current = (W.current ws)
@ -465,10 +539,63 @@ updateLayout i ml = whenJust ml $ \l ->
-- | 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 } } }
-- | 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
@ -504,10 +631,14 @@ cleanMask km = do
nlm <- gets numberlockMask
return (complement (nlm .|. lockMask) .&. km)
-- | 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)
------------------------------------------------------------------------
@ -527,7 +658,7 @@ writeStateToFile = do
maybeShow _ = Nothing
wsData = W.mapLayout show . windowset
extState = catMaybes . map maybeShow . M.toList . extensibleState
extState = mapMaybe maybeShow . M.toList . extensibleState
path <- asks $ stateFileName . directories
stateData <- gets (\s -> StateFile (wsData s) (extState s))
@ -590,12 +721,12 @@ 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
point_sc <- pointScreen (fi $ wa_x wa) (fi $ wa_y wa)
@ -610,16 +741,20 @@ floatLocation w =
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 = fi (wa_width wa + bw*2) % fi (rect_width sr)
height = fi (wa_height wa + bw*2) % 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 width height
else W.RationalRect (0.5 - width/2) (0.5 - height/2) width height
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))
@ -650,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
@ -675,7 +816,9 @@ mouseMoveWindow w = whenX (isClient w) $ withDisplay $ \d -> do
(_, _, _, 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
@ -688,12 +831,13 @@ mouseResizeWindow w = whenX (isClient w) $ withDisplay $ \d -> do
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)
-- ---------------------------------------------------------------------
@ -709,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

View File

@ -58,6 +58,8 @@ 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
@ -92,21 +94,23 @@ import qualified Data.Map as M (Map,insert,delete,empty)
-- 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
@ -208,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"
@ -238,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'
@ -311,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
@ -343,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)
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) []
@ -523,7 +540,7 @@ sink w s = s { floating = M.delete w (floating s) }
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 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.
@ -540,7 +557,7 @@ shiftMaster = modify' $ \c -> case c of
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 t (l:ls) rs -> Stack x [] (xs ++ t : rs) where (x :| xs) = NE.reverse (l :| ls)
--
-- ---------------------------------------------------------------------

View File

@ -1,4 +1,4 @@
resolver: lts-16.22
resolver: lts-21.12
packages:
- ./
@ -6,13 +6,6 @@ packages:
extra-deps:
- X11-1.10
flags:
xmonad:
# stack doesn't support automatic flags
# https://cabal.readthedocs.io/en/latest/cabal-package.html#resolution-of-conditions-and-flags
# https://github.com/commercialhaskell/stack/issues/1313#issuecomment-157259270
quickcheck-classes: false
nix:
packages:
- zlib

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

@ -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)
{- 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)

View File

@ -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

@ -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

@ -53,8 +53,8 @@ prop_aspect_hint_shrink hint (w,h) = case applyAspectHint hint (w,h) of
-- 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 ]
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)

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,6 +1,6 @@
{-# LANGUAGE CPP #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Properties.Stack where
import Test.QuickCheck
@ -11,20 +11,18 @@ import qualified XMonad.StackSet as S (filter)
import Data.Maybe
#ifdef VERSION_quickcheck_classes
import Data.Proxy
import Test.QuickCheck.Classes (
Laws (lawsTypeclass, lawsProperties), Proxy1 (Proxy1),
foldableLaws, traversableLaws,
)
#endif
-- 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)
@ -43,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
@ -56,12 +54,11 @@ 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]
#ifdef VERSION_quickcheck_classes
-- Check type class laws of 'Data.Foldable.Foldable' and 'Data.Traversable.Traversable'.
newtype TestStack a = TestStack (Stack a)
deriving (Eq, Read, Show, Foldable, Functor)
@ -78,6 +75,3 @@ prop_laws_Stack = format (foldableLaws p) <> format (traversableLaws p)
p = Proxy :: Proxy TestStack
format laws = [ ("Stack: " <> lawsTypeclass laws <> ": " <> name, prop)
| (name, prop) <- lawsProperties laws ]
#else
prop_laws_Stack = []
#endif

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

View File

@ -1,5 +1,5 @@
name: xmonad
version: 0.17.0
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
@ -25,9 +25,9 @@ author: Spencer Janssen, Don Stewart, Adam Vogt, David Roundy, Jason
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
Trevor Elliott, Wouter Swierstra, Conrad Irwin, Tim Thelion, Tony Zorman
maintainer: xmonad@haskell.org
tested-with: GHC == 8.4.4 || == 8.6.5 || == 8.8.4 || == 8.10.4 || == 9.0.1
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
@ -54,8 +54,6 @@ flag pedantic
default: False
manual: True
flag quickcheck-classes
library
exposed-modules: XMonad
XMonad.Config
@ -67,7 +65,7 @@ library
XMonad.StackSet
other-modules: Paths_xmonad
hs-source-dirs: src
build-depends: base >= 4.11 && < 5
build-depends: base >= 4.12 && < 5
, X11 >= 1.10 && < 1.11
, containers
, data-default-class
@ -83,7 +81,7 @@ library
default-language: Haskell2010
-- Keep this in sync with the oldest version in 'tested-with'
if impl(ghc > 8.4.4)
if impl(ghc > 8.6.5)
ghc-options: -Wno-unused-imports
if flag(pedantic)
@ -96,7 +94,7 @@ executable xmonad
default-language: Haskell2010
-- Keep this in sync with the oldest version in 'tested-with'
if impl(ghc > 8.4.4)
if impl(ghc > 8.6.5)
ghc-options: -Wno-unused-imports
if flag(pedantic)
@ -125,15 +123,14 @@ test-suite properties
hs-source-dirs: tests
build-depends: base
, QuickCheck >= 2
, quickcheck-classes >= 0.4.3
, X11
, containers
, xmonad
default-language: Haskell2010
if flag(quickcheck-classes) && impl(ghc > 8.5)
-- no quickcheck-classes in LTS-12
-- GHC 8.4 and lower needs too much boilerplate (Eq1, Show1, …)
build-depends: quickcheck-classes >= 0.4.3
if impl(ghc > 9.8)
ghc-options: -Wno-x-partial
if flag(pedantic)
ghc-options: -Werror