Compare commits

...

644 Commits

Author SHA1 Message Date
Tomáš Janoušek
00832bf5e6
Merge pull request #935 from xmonad/haskell-ci-update
ci: Regenerate haskell-ci
2025-05-12 18:28:30 +02:00
Tomas Janousek
410b34f074 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:21:36 +01:00
Tony Zorman
15dd45be0e ci/nix: Switch to ubuntu-latest 2025-05-12 17:17:26 +01:00
github-actions[bot]
f7451b9378 ci: Regenerate haskell-ci 2025-05-10 03:30:43 +00:00
github-actions[bot]
849208d1b8 ci: Bump GHC patch versions in tested-with 2025-05-10 03:30:43 +00:00
github-actions[bot]
4b86621051 ci: Regenerate haskell-ci 2025-04-13 16:57:26 +01:00
github-actions[bot]
18eb8aca94 ci: Bump GHC patch versions in tested-with 2025-04-13 16:57:26 +01:00
github-actions[bot]
a84f3e8540 ci: Regenerate haskell-ci 2025-04-05 08:36:22 +01:00
Tony Zorman
bd81961a63
Merge pull request #932 from xmonad/haskell-ci-update
ci: Regenerate haskell-ci
2025-03-31 08:24:48 +00:00
github-actions[bot]
209839f3ca ci: Regenerate haskell-ci 2025-03-29 03:18:50 +00:00
Tony Zorman
50e7dd4262
Merge pull request #931 from xmonad/haskell-ci-update
ci: Regenerate haskell-ci
2025-03-22 05:40:18 +00:00
github-actions[bot]
e2cdc0cc2c ci: Regenerate haskell-ci 2025-03-22 03:22:15 +00:00
github-actions[bot]
68da8c44ba ci: Bump GHC patch versions in tested-with 2025-03-22 03:22:15 +00:00
Tony Zorman
0517c94960
Merge pull request #926 from m1mir/feat/ewmh-hidden-viewport
X.H.EwmhDesktops: Add setEwmhHiddenWorkspaceToScreenMapping function.
2025-03-18 06:38:02 +00:00
m1mir
b1bf33d6eb
X.H.IndependentScreens: Added screenOnMonitor to the export list. 2025-03-17 10:16:01 +01:00
m1mir
195a0ac3c0
X.H.EwmhDesktops: Added setEwmhHiddenWorkspaceToScreenMapping function. 2025-03-17 10:15:48 +01:00
Tony Zorman
b470de0d75
Merge pull request #930 from geekosaur/containers-0.8
support containers-0.8
2025-03-11 07:04:15 +01:00
Tony Zorman
87585a6884
Merge pull request #929 from xmonad/dependabot/github_actions/cachix/install-nix-action-31
build(deps): bump cachix/install-nix-action from 30 to 31
2025-03-11 07:03:58 +01:00
brandon s allbery kf8nh
41f1d1434c
support containers-0.8
compiled locally to test
2025-03-10 21:43:03 -04:00
dependabot[bot]
ddcce31597
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-10 16:50:50 +00:00
github-actions[bot]
4496b4f2d5 ci: Regenerate haskell-ci 2025-02-22 11:12:33 +00:00
Tony Zorman
5119626269
Merge pull request #927 from portnov/master
X.U.EZConfig: support "<Menu>" for xK_Menu key.
2025-02-10 11:06:52 +01:00
Ilya V. Portnov
27c86d0dda Update Changes.md 2025-02-10 14:51:12 +05:00
Ilya V. Portnov
58dbf59cab X.U.EZConfig: support "<Menu>" for xK_Menu key. 2025-02-10 12:30:59 +05:00
Tony Zorman
9d457a73ce
Merge pull request #924 from m1mir/feat/independentDoFocus
X.L.IndependentScreens: Add doFocus' ManageHook.
2025-02-07 07:22:05 +01:00
m1mir
f1f392cd01
X.L.IndependentScreens: Added doFocus' ManageHook. 2025-02-07 06:26:49 +01:00
Tony Zorman
6c1441d9db
Merge pull request #925 from philib/master
fix unintended window hiding
2025-01-31 06:21:15 +01:00
philib
6a6d913dee fix unintended window hiding
the refactoring that introduced `nsHideOnCondition` caused a
misbehaviour in `nsSingleScratchpadPerWorkspace`, leading to unintended
window hiding. Now, when opening a new scratchpad, only the previous
active scratchpad is hidden.
2025-01-30 12:22:18 +01:00
Tomas Janousek
4fc3642fa2 Merge remote-tracking branch 'origin/haskell-ci-update' into tmp 2025-01-26 23:00:19 +00:00
Tomas Janousek
7614f94d92 ci: Add GHC 9.8 (Stackage LTS 23) to Stack test matrix 2025-01-26 23:00:19 +00:00
Tomas Janousek
c7061b0d73 Remove last remaining derivations of Typeable
GHC 9.12 now warns about this:

    Deriving ‘Typeable’ has no effect: all types now auto-derive Typeable

and we specify -Werror so this is needed to fix CI builds with 9.12.

Related: f732082fdccb ("Remove all derivations of Typeable")
2025-01-26 23:00:19 +00:00
Tony Zorman
6df1044265
Merge pull request #923 from m1mir/feat/setEwmhSwitchDesktopAction
X.H.EwmhDesktops: Add customization for handling the _NET_CURRENT_DESKTOP requests
2025-01-25 17:54:20 +01:00
m1mir
619a347f3f X.L.IndependentScreens: Added focusWorkspace function. 2025-01-25 17:31:46 +01:00
m1mir
2b11459496 X.H.EwmhDesktops: Added customization for external desktop switching.
Added a configuration option to change the action for handling the
_NET_CURRENT_DESKTOP requests.
2025-01-25 17:31:46 +01:00
github-actions[bot]
beabe75dda ci: Regenerate haskell-ci 2025-01-25 03:08:40 +00:00
github-actions[bot]
0404372fd3 ci: Bump GHC patch versions in tested-with 2025-01-25 03:08:40 +00:00
Tony Zorman
c0a5bc5f0f workflows/stack: Add non-master resolver for lts-16 2025-01-18 18:17:07 +01:00
Tony Zorman
1f13bb2468 fixup! cabal: Drop support for GHC 8.6 2025-01-18 11:44:54 -05:00
Tony Zorman
d4473946d4 cabal: Drop support for GHC 8.6
See https://github.com/xmonad/xmonad-contrib/pull/921
2025-01-18 11:44:54 -05:00
brandon s allbery kf8nh
55e1adde4c add XF86WLAN special key 2025-01-18 11:44:54 -05:00
Tony Zorman
de01015af5
Merge pull request #918 from nilscc/feature/auto-format-to-hls
Auto-format `OnScreen` and `ScreenCorners` to HLS
2025-01-02 22:07:23 +01:00
Nils
7f0f0ad498 {X.A.OnScreen,X.H.ScreenCorners}: Reformat 2025-01-02 22:06:53 +01:00
Nils
195537e97e Update email and copyright 2025-01-02 09:25:46 -05:00
Tony Zorman
d9e54c1b96
Merge pull request #915 from sol/patch-1
docs: Don't link to re-exports from XMonad.Config.Prime
2024-12-22 19:10:50 +01:00
Simon Hengel
b570ab1a74
docs: Don't link to re-exports from XMonad.Config.Prime 2024-12-19 21:46:55 +07:00
Tony Zorman
0dc879698d
Merge pull request #914 from liskin/noborders-resetborder
X.L.NoBorders: Listen to DestroyWindowEvents and garbage collect
2024-11-24 10:51:25 +01:00
Tomas Janousek
fe826ca8db X.L.NoBorders: Listen to DestroyWindowEvents and garbage collect
Previously, it was necessary to use `borderEventHook` to make sure the
`alwaysHidden`/`neverHidden` lists are garbage collected when a window
is destroyed, but this was largely undocumented. Since xmonad v0.17.0,
the DestroyWindowEvent is broadcast to layouts, so we can just use that
instead and deprecate the event hook.
2024-11-23 14:44:29 +00:00
github-actions[bot]
d19ea051d4 ci: Regenerate haskell-ci 2024-11-16 05:44:55 +00:00
brandon s allbery kf8nh
c5032a43fb
Merge pull request #911 from liskin/rescreen
X.H.Rescreen, X.A.PhysicalScreens: Add facilities to avoid (some) workspace reshuffling
2024-10-21 06:58:57 -04:00
Tomas Janousek
61f8b4aa8e CHANGES: Document the X.H.Rescreen, X.A.PhysicalScreens additions 2024-10-17 17:52:42 +01:00
Tomas Janousek
60fc830e2e CHANGES: Inline links
Seems somewhat likely that "on the website", "this PR" and "priorities"
may be used again in a different context…
2024-10-17 17:47:06 +01:00
Tomas Janousek
f97ce867ac X.A.PhysicalScreens: Add rescreen alternative to avoid ws reshuffle
Probably a very niche use-case: I have an ultra-wide display that I
split into two using `xrandr --setmonitor`, and I want the workspaces to
stay in place when the split ratio is adjusted.

Furthermore, this fixes workspace reshuffling when a virtual monitor is
added for screensharing a portion of the screen
(https://news.ycombinator.com/item?id=41837204).

Can't think of a scenario involving just physical screens where this
would be useful. Those are mostly added/removed, so if anything, one
might wish to preserve the workspace that is currently being showed, but
that would require knowing the output name (only available via RandR,
not via Xinerama). If someone physically moves their displays around and
then invokes `xrandr` to update the layout, this might very well do the
right thing, but I don't think anyone moves their displays around often
enough to be annoyed by xmonad reshuffling the workspaces. :-)
2024-10-17 17:42:17 +01:00
Tomas Janousek
2f42d2e7b4 X.H.Rescreen: Configurable wait/delay for events to settle 2024-10-17 17:42:17 +01:00
Tomas Janousek
b454f1e0be X.H.Rescreen: Move error handling to rescreenHook
This handles errors in hooks set using `rescreenHook` as well, not just
those set using the individual adders/setters.

Fixes: 2e3254a9080c ("X.H.Rescreen: Catch exceptions in user-provided hooks in add*Hook")
2024-10-17 17:42:17 +01:00
Tomas Janousek
5680205c72 X.H.Rescreen: Allow overriding rescreen itself
The primary motivation is to fix `rescreen` messing up the
workspaces/screens order when making small changes to the layout of
multiple screens — such as resizing virtual monitors via `xrandr
--setmonitor`.
2024-10-17 17:42:17 +01:00
dependabot[bot]
1c5261d65a 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 20:07:26 +02:00
brandon s allbery kf8nh
2c161ff670
Merge pull request #908 from xmonad/dependabot/github_actions/cachix/install-nix-action-v29
build(deps): bump cachix/install-nix-action from V28 to 29
2024-09-30 13:02:50 -04:00
dependabot[bot]
2ec4bbc833
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 16:37:08 +00:00
dependabot[bot]
42340e0f76 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 19:14:53 +01:00
Christina Sørensen
4350936ba5 fix: deprecated url literals
Signed-off-by: Christina Sørensen <christina@cafkafk.com>
2024-09-15 19:08:49 -04:00
Tony Zorman
2973c283ae fixup! X.L.OnHost: Query gethostname if $HOST lookup fails 2024-09-03 20:57:02 -04:00
Tony Zorman
a96a2031f6 X.L.OnHost: Query gethostname if $HOST lookup fails
Fixes: https://github.com/xmonad/xmonad-contrib/issues/899
2024-09-03 20:57:02 -04:00
Giacomo Rosin
1e5fcb1216 X.A.DynamicProjects: Update CHANGES.md 2024-09-03 20:56:29 -04:00
Giacomo Rosin
6bc6bf8abd X.A.DynamicProjects: Improve documentation
Describe how to close projects and the output of `currentProject` function.
2024-09-03 20:56:29 -04:00
Giacomo Rosin
c98715623d X.A.DynamicProjects: Don't autodelete projects
Fixes #902 by no longer deleting projects on switch, as it is more confusing than useful.
2024-09-03 20:56:29 -04:00
Tony Zorman
b3c249434d X.H.StatusBar: Make barSpawner pure
Related: https://github.com/xmonad/xmonad-contrib/pull/878
Related: https://github.com/xmonad/xmonad-contrib/issues/880
2024-08-27 08:23:19 +02:00
Tony Zorman
d0d9d42761
Merge pull request #900 from slotThe/x.a.upkeys
X.A.UpKeys: Init
2024-08-27 08:20:09 +02:00
Tony Zorman
e203096143 X.A.UpKeys: Init
Original implementation from https://stackoverflow.com/a/11308086
2024-08-22 18:35:31 +02:00
Tony Zorman
6811b9e296 cabal: Bump version to development version 2024-08-20 18:50:34 +02:00
Tony Zorman
f5f99c8abf cabal: Update DXMONAD_CONTRIB_VERSION_PATCH 2024-08-20 18:21:57 +02:00
Tony Zorman
d41f36fa5c cabal: Bump version number 2024-08-20 18:17:57 +02:00
Tony Zorman
e4e04aa017 nix.yml: Update index before building 2024-08-18 14:11:16 +02:00
brandon s allbery kf8nh
ec5c751b35
fix module name in haddock markup
This was forgotten when the module was renamed.
2024-08-06 18:53:00 -04:00
Tony Zorman
eb7268451c
Merge pull request #896 from Rogach/pr/window-navigation
X.A.WindowNavigation: better handling of floating windows and Full layout
2024-07-28 20:16:44 +02:00
github-actions[bot]
0dcecb41c5 ci: Regenerate haskell-ci 2024-07-13 06:21:31 +01:00
Tomáš Janoušek
5d285ced1f
Merge pull request #897 from xmonad/haskell-ci-update
ci: Regenerate haskell-ci
2024-07-07 15:37:27 +01:00
Tomas Janousek
91e59c3651 Add base bounds for test-suite
cabal 3.12+ is stricter in its checks. Our test suite doesn't depend on
xmonad-contrib (it compiles the modules itself with possibly different
preprocessor defines), thus it doesn't inherit its base bounds.

See https://github.com/haskell/cabal/issues/10162
2024-07-07 15:26:54 +01:00
github-actions[bot]
5f82296536 ci: Regenerate haskell-ci 2024-07-07 15:20:58 +01:00
github-actions[bot]
e8029cb51d ci: Bump GHC patch versions in tested-with 2024-07-07 15:20:58 +01:00
Tomas Janousek
1211a709dc Bump lower bound for base
We only test with GHC 8.6+ and the bounds should reflect that.

Related: 5d0013ef534d ("ci: Drop support for GHC 8.4")
Related: 046f3c3871a7 ("Bump lower bound for base")
2024-07-07 15:19:54 +01:00
Platon Pronko
66d334f4cd X.A.WindowNavigation: better handling of floating windows and Full layout
Previous version most of the time just got "stuck" on floating windows,
switching back and forth between floating window and tiled window underneath.
This was because "magic point" was left in the same position and thus next
navigation commands selected the same windows over and over again.
Now the "magic point" is moved around such that it doesn't overlap with the previously selected window,
and there are more complicated rules to make navigation between floating and tiled windows more natural.

The original behavior of navigating between tiled windows is preserved almost precisely.

Previous version also prevented switching windows using focusUp/focusDown
when in Full layout. Now there's a special case that handles such situations.
2024-07-01 19:44:56 +04:00
brandon s allbery kf8nh
55f4c4ff1b
Fix typo in comment 2024-06-16 00:38:12 -04:00
halting
bbbf5c3b44 missing dependencies in the test suite 2024-06-16 00:35:39 -04:00
halting
b3ca4362af X.A.WindowBringer: Add copyMenu 2024-06-16 00:35:39 -04:00
Tony Zorman
5325ca8902
Merge pull request #894 from sylecn/grid-select
XMonad.Actions.GridSelect: added gs_cancelOnEmptyClick field
2024-06-10 08:19:24 +02:00
Yuanle Song
0bc28ac473 X.A.GridSelect: Add gs_cancelOnEmptyClick field
In the original code, when a GridSelect is shown, user has to use
keyboard to cancel it (ESC key by default). With this field added,
when it is set to True (the default), mouse click on empty space
can cancel the GridSelect.
2024-06-10 08:12:15 +02:00
Yuanle Song
077b4ff34b XMonad.Hooks.ScreenCorners: Add support for edges
Previously only corners are supported, now support for edges are added. This
is similar to Hot Edge shell extension in GNOME.
2024-06-08 22:32:27 -04:00
Tomas Janousek
7109b0ce8f 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:44:08 +01:00
jecaro
b57212cc18 Make the width of the fst column configurable 2024-05-20 16:49:33 -04:00
jecaro
da3e4bef33 Remove the call to singleton 2024-05-20 16:49:33 -04:00
jecaro
d014d7ac84 Add a new layout Columns
This layout organizes windows in columns and allows to move/resize them
in every directions.
2024-05-20 16:49:33 -04:00
Tomas Janousek
a88b5aa58d ci: gh-workflow-keepalive no longer needs a GITHUB_TOKEN input 2024-05-20 21:13:04 +01:00
Tomáš Janoušek
58f956c29f
Merge pull request #891 from xmonad/dependabot/github_actions/cachix/install-nix-action-27
build(deps): bump cachix/install-nix-action from 26 to 27
2024-05-20 17:59:59 +01:00
dependabot[bot]
7ac0f44db4
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 16:37:20 +00:00
Tomáš Janoušek
d6ea38e7be
Merge pull request #890 from xmonad/haskell-ci-update
ci: Regenerate haskell-ci
2024-05-18 07:46:08 +01:00
github-actions[bot]
c8c5cc1838 ci: Regenerate haskell-ci 2024-05-18 03:12:44 +00:00
Tomáš Janoušek
7210251138
Merge pull request #889 from xmonad/haskell-ci-update
ci: Regenerate haskell-ci (add GHC 9.10)
2024-05-13 20:46:40 +01:00
github-actions[bot]
7dc39c7154 ci: Regenerate haskell-ci 2024-05-13 20:29:52 +01:00
github-actions[bot]
6fece17d3d ci: Bump GHC patch versions in tested-with 2024-05-13 20:29:52 +01:00
Tomas Janousek
8e34c2f745 X.U.Grab: Drop mkGrabs, setNumlockMask in favor of the new core exports
Now that we require xmonad 0.18.0, we can do this.

Related: https://github.com/xmonad/xmonad/pull/405
Related: 0934fe5cd758 ("X.U.Grab: Hide mkGrabs from XMonad")
2024-05-13 16:08:28 +01:00
Tomas Janousek
02f124cf4b ci: Expand stack test matrix 2024-05-13 12:28:24 +01:00
Tomas Janousek
840ede1e9e ci: Bump the oldest xmonad version we test against
Stackage LTS 22 has mtl-2.3 and unix-2.8, which xmonad 0.17 excludes in
its bounds.
2024-05-13 12:28:24 +01:00
Tony Zorman
8fb1973e05
Merge pull request #888 from andwu137/master
Add a method to re-sort keys for visualSubmap
2024-05-09 08:27:34 +02:00
Andrew Nguyen
abef527f73 X.A.Submap: Add visualSubmapSorted 2024-05-09 08:14:11 +02:00
Tomas Janousek
cbdee7db6f X.H.EwmhDesktops: Fix _NET_CURRENT_DESKTOP handling
_NET_CURRENT_DESKTOP doesn't act on a specific window and its ev_window
is set to the root window, but the root window is considered unmanaged
so this would be caught by the "not member" guard and ignored. We need
to move the guard a bit further down.

Fixes: 3839c8bce99b ("X.H.EwmhDesktops: Fix menus in Steam client")
Fixes: https://old.reddit.com/r/xmonad/comments/1cfclhh/psa_steam_fixes_merged_to_xmonadcontrib_master/l2hjwuy/
2024-05-04 09:25:38 +01:00
Tony Zorman
0622ed11ed X.P.OrgMode: Do not default the day if no time is given
Partially reverts b8d5c391cc03cfa5d7d95caa79f590d366e3c0ba
Fixes: https://github.com/liskin/xmonad-contrib/actions/runs/8869462044/job/24350171604
2024-04-30 08:30:14 +02:00
Tomáš Janoušek
700507fcd0
Merge pull request #886 from liskin/steam-fixes
Fixes/workarounds for Steam client menus/flickering
2024-04-28 19:39:21 +02:00
Tomas Janousek
ca5e70ffc4 CHANGES: Document this branch's additions/fixes 2024-04-28 19:37:56 +02:00
Tomas Janousek
67472aa307 CHANGES: Whitespace/punctuation fixes 2024-04-28 19:37:56 +02:00
Tomas Janousek
c33efbbefd X.H.FloatConfigureReq: Add fixSteamFlicker
For ease of use, provide `fixSteamFlicker` as a pre-packaged
`floatConfReqHook` that can easily be added directly to a
`handleEventHook`.

Also, for discoverability, re-export it from X.U.Hacks.
2024-04-28 19:37:56 +02:00
Tomas Janousek
2b77997259 X.H.FloatConfigureReq: New module to customize ConfigureRequest handling
Implements a replacement event handler for 'ConfigureRequestEvent' to
work around misbehaving client applications such as Steam, URxvt and
others that try to restore their absolute window positions. Primarily
motivated by the Steam client being almost completely unusable in xmonad
lately.

(I've been running this code in my xmonad.hs for other purposes for
years.)
2024-04-28 19:37:56 +02:00
Tomas Janousek
3839c8bce9 X.H.EwmhDesktops: Fix menus in Steam client
More specifically, ignore ClientMessageEvents for unmanaged windows.
Steam likes to send _NET_ACTIVE_WINDOW requests for all its windows,
including override-redirect ones, which used to result in an invocation
of `windows` with a no-op Endo—equivalent to a call to `refresh`. But
this refresh makes Steam close its menus immediately.

Fixes: https://github.com/ValveSoftware/steam-for-linux/issues/9376
Fixes: https://github.com/xmonad/xmonad/issues/451
2024-04-28 19:37:52 +02:00
Tony Zorman
8efff53a06 X.P.OrgMode: More strictly enfore +s and +d ending with a space
Fixes: https://github.com/xmonad/xmonad-contrib/actions/runs/8772077289/job/24070588575
2024-04-27 19:43:14 +02:00
Tomáš Janoušek
cab938f07b
Merge pull request #885 from xmonad/haskell-ci-update
ci: Regenerate haskell-ci
2024-04-21 12:44:26 +02:00
github-actions[bot]
f3d936ef97 ci: Regenerate haskell-ci 2024-04-21 07:50:43 +00:00
github-actions[bot]
aff212654d ci: Bump GHC patch versions in tested-with 2024-04-21 07:50:42 +00:00
Tony Zorman
6e43da8598
Merge pull request #864 from dcousens/no-xp-io
X.P: Add escape hatch for preventing X.P IO
2024-03-31 09:58:37 +02:00
Daniel Cousens
fcd2f60226 X.P: Don't read/write to history file if size is 0
This contains a breaking change for readHistory, writeHistory,
historyCompletion, and historyCompletionP to take an XPConfig, so they
are aware of this choice. While the latter two are exported, it seems
unlikely to affect many users.
2024-03-31 09:58:09 +02:00
Tony Zorman
51926854d9
Merge pull request #883 from slotThe/orgmode-time
X.P.OrgMode: Add time spans
2024-03-31 09:37:24 +02:00
Tony Zorman
0d2b68374c
Merge pull request #884 from geekosaur/time-1.14-again
time 1.14 update missed the test suite
2024-03-30 06:39:11 +01:00
brandon s allbery kf8nh
933cb57b90
missed the test suite 2024-03-30 00:46:28 -04:00
Tony Zorman
ebe1b9b036 X.P.OrgMode: Add ability to specify time spans 2024-03-29 20:47:52 +01:00
Tony Zorman
d691d25d1c X.P.OrgMode: Fallback to "today" if no day is given 2024-03-29 13:57:27 +01:00
Tony Zorman
8ac84079a2
Merge pull request #881 from geekosaur/bounds-time
update time to <1.15
2024-03-23 07:46:19 +01:00
Tony Zorman
7aa2ff6798
Merge pull request #882 from xmonad/haskell-ci-update
ci: Regenerate haskell-ci
2024-03-23 07:45:28 +01:00
github-actions[bot]
21a75bfeb4 ci: Regenerate haskell-ci 2024-03-23 03:16:36 +00:00
brandon s allbery kf8nh
78bad11578
remove extraneous ) in docstring 2024-03-20 03:29:02 -04:00
brandon s allbery kf8nh
51ee223ec3
update time to <1.15 2024-03-17 16:39:10 -04:00
Yecine Megdiche
2b079bf9fb
Merge pull request #878 from Chobbes/dynamic-status-bars-x
Update StatusBar library to use the X monad instead of IO.
2024-03-13 10:53:16 +01:00
Tony Zorman
94bccd3e16
Merge pull request #879 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:09:50 +01:00
dependabot[bot]
35ded4259b
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 16:48:47 +00:00
Calvin Beck
e735339b75 Update StatusBar library to use the X monad instead of IO.
This change allows dynamic status bars to pull information out of the
X monad, which can be really useful for status bars. For instance, you
can now query the screen width in order to set the width of status
bars appropriately.

Existing configurations may need to be updated in order to lift an
`IO StatusBarConfig` to an `X StatusBarConfig`. This can be done using
either the `io` function provided by `XMonad.Core`, or `liftIO` from
`base` in `Control.Monad.IO.Class`

- https://hackage.haskell.org/package/xmonad-0.18.0/docs/XMonad-Core.html#v:io
- https://hackage.haskell.org/package/base-4.19.1.0/docs/Control-Monad-IO-Class.html#v:liftIO
2024-03-09 10:40:13 -05:00
Tomáš Janoušek
de5ef6cabd
Merge pull request #877 from ilya-bobyr/master
X.H.ManageHelpers: `isNotification` predicate
2024-03-04 12:28:38 +00:00
Illia Bobyr
da5566d59f
X.H.ManageHelpers: isNotification predicate
Very similar to `isDialog`, `isNotification` checks for the
`_NET_WM_WINDOW_TYPE_NOTIFICATION` value in the `_NET_WM_WINDOW_TYPE`
property.
2024-03-02 12:38:10 -08:00
Tony Zorman
82191700e6
Merge pull request #876 from xmonad/haskell-ci-update
ci: Regenerate haskell-ci
2024-03-02 07:53:10 +01:00
github-actions[bot]
ced5b7abfc ci: Regenerate haskell-ci 2024-03-02 03:15:25 +00:00
github-actions[bot]
ca8e9ce722 ci: Bump GHC patch versions in tested-with 2024-03-02 03:15:25 +00:00
Tony Zorman
5ce04d6664 .mailmap: Update 2024-02-28 09:07:41 +01:00
mislavzanic
bfe2f5b3f9 feat: add profiles 2024-02-16 11:05:46 -05:00
Tony Zorman
c8dff5e2dc
Merge pull request #874 from ulrikdem/ezconfig-duplicate
X.U.EZConfig: Fix checkKeymap warning that all keybindings are duplicate
2024-02-16 07:25:34 +01:00
Ulrik de Muelenaere
aec21860ba X.U.EZConfig: Fix checkKeymap warning that all keybindings are duplicate
This reverts part of 42179b8625d83b2cd3c3a35da84de6f6c0dea6d6, which
effectively changed the duplicate check from >1 to >=1.
2024-02-15 20:49:06 -05:00
Tomas Janousek
93ad0ef2ea 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:26 +00:00
Tony Zorman
ae5949657b
Merge pull request #873 from mislavzanic/mini_refactor_hidden_layout
X.L.Hidden: use the modifyWindowSet function
2024-02-12 13:57:16 +01:00
mislavzanic
dda929dfc5 X.L.Hidden: use the modifyWindowSet function 2024-02-12 10:58:48 +01:00
Daniel Cousens
a84cec9b2d
X.*: Fix typos (#871)
* X.*: fix typos

* X.*: fix typos

* X.*: fix typos

* X.Util: fix typo

---------

Co-authored-by: Daniel Cousens <dcousens@users.noreply.github.com>
2024-02-12 07:55:20 +01:00
Tony Zorman
1d8305d515
Merge pull request #872 from gabrielsimoes/patch-1
Fix build-with-cabal.sh when XDG_CONFIG_HOME is defined
2024-02-12 07:54:46 +01:00
Gabriel Simões
e963382d62
Update CHANGES.md 2024-02-11 21:23:20 -05:00
Gabriel Simões
e6dae98c44
Fix build-with-cabal.sh when XDG_CONFIG_HOME is defined 2024-02-11 21:20:30 -05:00
Tony Zorman
7843d4dd28 Bump version to 0.18.0.9 2024-02-03 18:43:21 +01:00
Tony Zorman
9217ac18e9 cabal: Bump xmonad dependency 2024-02-03 16:06:47 +01:00
Tony Zorman
c65ea8d3ab Bump version to 0.18.0 2024-02-03 16:02:47 +01:00
Tony Zorman
d54d37e344
Merge pull request #869 from dcousens/patch-1
X.P: Fix some typos in comments
2024-01-24 14:40:44 +01:00
Daniel Cousens
903e50a65c
X.P: Fix some typos in comments 2024-01-25 00:17:18 +11:00
dependabot[bot]
f3ee6289ec 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:55:52 +00:00
brandon s allbery kf8nh
318ee92e61 only sink window if actually fullscreened
`EwmhFullscreen` unconditionally sinks windows in response to a
`_NET_WM_STATE` root window message removing `_NET_WM_STATE_FULLSCREEN`.
Unfortunately, at least some versions of either the Gtk or GNOME
libraries send this on startup while restoring a window's last
known state, which means a `manageHook` `doFloat` will be undone.

This change ignores the remove if the window is not fullscreen.

A followup issue, #865, has been added for the follow-on problem
that the floating state of a window is not restored on removal of
the fullscreen state.

Fixes: #820
2024-01-21 12:07:09 -05:00
Ilya V. Portnov
a5fb7e021a
X.L.DecorationEx: extensible mechanism for window decorations (#857)
* First version of DecorationEx.

* Fixed most warnings.

* Fix build error with ghc-9.8.1.

* Fix title shrinking with text decoration.

* Add convinience re-exports.

* Get rid of orphan instances.

* Fix a couple of warnings.

* Rename X.L.DecorationEx.Types -> X.L.DecorationEx.Common

* Add instance Default StandardCommand.

* Fix some typos and formatting

thanks to @geekosaur

Co-authored-by: brandon s allbery kf8nh <allbery.b@gmail.com>

* Fix reference to xmonad.hs

See also #859

Co-authored-by: brandon s allbery kf8nh <allbery.b@gmail.com>

* Fix reference to xmonad.hs

Co-authored-by: brandon s allbery kf8nh <allbery.b@gmail.com>

* Fix formatting

Co-authored-by: brandon s allbery kf8nh <allbery.b@gmail.com>

* Fix some typos and formatting

thanks to @geekosaur

Co-authored-by: brandon s allbery kf8nh <allbery.b@gmail.com>

* Remove commented code.

* Update CHANGES.md.

* calcWidgetPlace is now allowed to return rectangle with any X,

but that will be ignored.

* More generic instance for DecorationWidget GenericWidget.

* Replace explicit definition of `fi` with import from X.Prelude.

thanks to @slotThe.

* Move fetch-all pattern to the end of definition.

thanks to @slotThe.

* X.L.DecorationEx: Add screenshot

---------

Co-authored-by: brandon s allbery kf8nh <allbery.b@gmail.com>
Co-authored-by: Tony Zorman <soliditsallgood@mailbox.org>
2024-01-21 12:02:08 -05:00
Tomáš Janoušek
09e37131ca
Merge pull request #863 from xmonad/haskell-ci-update
ci: Regenerate haskell-ci
2024-01-17 11:54:01 +00:00
github-actions[bot]
39310a6695 ci: Regenerate haskell-ci 2024-01-17 11:28:14 +00:00
github-actions[bot]
14e80f2f74 ci: Bump GHC patch versions in tested-with 2024-01-17 11:28:13 +00:00
dependabot[bot]
2272691ada 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-15 16:37:58 +00:00
Tomas Janousek
4bb6a2eedb X.H.EwmhDesktops: Fix haddock markup
Fixes: 2dcc3a92e70c ("X.H.EwmhDesktops: Add (un)fullscreen hooks")
2024-01-14 10:20:27 +00:00
Tony Zorman
7cb6b0f87b
Merge pull request #861 from dcousens/patch-1
XMonad.Prompt: export getCurrentCompletions (and setCurrentCompletions)
2024-01-10 08:06:04 +01:00
Daniel Cousens
385d7e9579 X.P: Export {selected,setCurrent,getCurrent}Completion[s] 2024-01-10 08:04:59 +01:00
Tony Zorman
99b24f314b
Merge pull request #860 from dcousens/patch-1
Fix Xmonad.Prompt.Input usage example
2023-12-28 16:02:38 +01:00
Daniel Cousens
9f51b2a1d6
Fix example Xmonad.Prompt.Input usage example 2023-12-28 00:54:36 +11:00
Tony Zorman
82e4260084
Merge pull request #859 from slotThe/kill-dots
`~/.xmonad/xmonad.hs` -> `xmonad.hs`
2023-12-23 08:08:43 +01:00
Tony Zorman
5ceaed8126
Merge pull request #858 from dcousens/fix-min-width
Fix minimum widths for Shrink and Expand
2023-12-23 08:07:57 +01:00
Daniel Cousens
cd32cac54b X.L.TwoPane[Persistent]: Add minimum widths for Shrink and Expand 2023-12-23 08:07:00 +01:00
Tony Zorman
b1b3c4c469 ~/.xmonad/xmonad.hs -> xmonad.hs
With XDG support so firmly ingrained now, it's about time we stop
hard-coding the configuration path in the docs.
2023-12-22 18:17:17 +01:00
Tony Zorman
c01cd3a33b
Merge pull request #848 from portnov/master
Add new module: X.L.CircleEx: advanced version of Circle layout
2023-12-21 19:58:00 +01:00
Ilya V. Portnov
4f2a5c7f43 X.L.Circle: Deprecate in favour of X.L.CircleEx 2023-12-21 19:52:20 +01:00
Ilya V. Portnov
19edf5a7a8 X.L.CircleEx: Init 2023-12-21 19:52:20 +01:00
Tony Zorman
75d67cfb1d
Merge pull request #856 from l29ah/prompt-return-normal-vim
X.Prompt: handle Return key in vim normal mode
2023-12-20 05:58:38 +01:00
Sergey Alirzaev
9609e0ef2e X.Prompt: handle Return key in vim normal mode 2023-12-20 05:57:58 +01:00
Tomas Janousek
3613d4d543 X.U.Ungrab: Avoid "Ambiguous occurrence" error in user configs 2023-12-18 10:32:03 +00:00
Tony Zorman
d54a7e21dd
Merge pull request #853 from liskin/ewmh-desktop-managehook
X.H.{EwmhDesktops,ManageHelpers}: Add _NET_WM_DESKTOP-handling ManageHook
2023-12-18 10:53:26 +01:00
Tony Zorman
0fe948feb3
Merge pull request #852 from liskin/renamed-named
X.L.Renamed: Provide "named" convenience alias
2023-12-18 10:48:19 +01:00
Tomas Janousek
3c329e0aad X.H.{EwmhDesktops,ManageHelpers}: Add _NET_WM_DESKTOP-handling ManageHook
Useful for restoring browser windows to where they were before restart
(which is something one should do several times a week as security
updates get released).
2023-12-17 21:58:57 +00:00
Tomas Janousek
92a7c030b2 X.L.Renamed: Provide "named" convenience alias
I believe this common use-case for the deprecated X.L.Named should still
be provided somewhere, rather than telling everybody to let-define this
themselves.

The other one – `nameTail` – only has about 6 uses in publicly available
configs (https://github.com/search?q=nameTail+path%3Axmonad&type=code),
so I'm not adding that one but I'm happy to be convinced to add it too.

Related: 3bf9d80c40b9 ("XMonad.Layout.Named: Deprecate")
2023-12-17 21:49:49 +00:00
Tony Zorman
e75eb16a93
Merge pull request #850 from slotThe/fix/prompt-ignores-left
X.Prompt: Execute keypress when it has an action associated to it
2023-12-17 13:39:27 +01:00
Tony Zorman
00993d46fa X.Prompt: Execute keypress when it has an action associated to it
It might be that the keypress does not have a valid stroke associated to
it, but is still bound to an action (e.g., xK_Left an friends). In this
case, we still want to execute it.

Closes: https://github.com/xmonad/xmonad-contrib/issues/845
2023-12-16 15:42:53 +01:00
Tony Zorman
5c30cadaf6
Merge pull request #843 from iogrt/ungrab
deprecate `XMonad.Util.Ungrab`
2023-12-09 08:18:51 +01:00
iogrt
22372abaab X.U.Ungrab: Deprecate 2023-12-09 07:49:49 +01:00
Tony Zorman
a34287dda6
Merge pull request #847 from xmonad/haskell-ci-update
ci: Regenerate haskell-ci
2023-12-09 07:34:19 +01:00
github-actions[bot]
34d55ede85 ci: Regenerate haskell-ci 2023-12-09 03:13:33 +00:00
dependabot[bot]
7ce7ddf9e6 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 16:51:51 +00:00
Tony Zorman
7464b36afa NIX.md: Add flakes semi-walkthrough 2023-12-02 16:04:49 +01:00
Tony Zorman
45dd67433c
Merge pull request #844 from xmonad/haskell-ci-update
ci: Regenerate haskell-ci
2023-11-18 08:06:46 +01:00
github-actions[bot]
ff8d4ebb94 ci: Regenerate haskell-ci 2023-11-18 03:15:29 +00:00
github-actions[bot]
f9d98e0936 ci: Bump GHC patch versions in tested-with 2023-11-18 03:15:29 +00:00
Tomáš Janoušek
ad28ae1daa
Merge pull request #842 from xmonad/haskell-ci-update
ci: Regenerate haskell-ci
2023-11-13 00:28:50 +00:00
Tomas Janousek
192c0da831 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:58:14 +00:00
github-actions[bot]
e38e19edc1 ci: Regenerate haskell-ci 2023-11-11 03:20:02 +00:00
Tony Zorman
8035db1bd0
Merge pull request #841 from jpolchlo/docs/unicode-prompt
Add documentation for unicode prompt
2023-11-08 10:34:40 +01:00
jpolchlo
da566d63e6 X.P.Unicode: Add docs about UnicodeData.txt
Having this file is required for the prompt to work, and how to obtain
it may not be immediately obvious.
2023-11-08 10:33:46 +01:00
Tony Zorman
c176a752de
Merge pull request #838 from xmonad/haskell-ci-update
ci: Regenerate haskell-ci
2023-10-28 12:55:13 +02:00
Tomas Janousek
532d64a0f9 ci: Disable x-partial warnings in the testsuite
Related: https://github.com/xmonad/xmonad/pull/477
2023-10-28 11:29:36 +01:00
github-actions[bot]
487b6d1677 ci: Regenerate haskell-ci 2023-10-28 11:44:37 +02:00
github-actions[bot]
a9ba19fb24 ci: Bump GHC patch versions in tested-with 2023-10-28 11:44:37 +02:00
Tony Zorman
105e529826 Fix partial uses of head
Fixes: https://github.com/xmonad/xmonad-contrib/issues/830
Related: https://github.com/xmonad/xmonad-contrib/pull/836
2023-10-28 11:41:24 +02:00
Tony Zorman
42179b8625 X.U.EZConfig: Make readKeySequence return non-empty list 2023-10-26 14:18:31 +02:00
Tony Zorman
d668e4cb10 X.Prelude: Add takeS 2023-10-26 11:52:40 +02:00
Tony Zorman
f654082c5b
Merge pull request #837 from philib/master
introduce single active scratchpad hook
2023-10-24 21:10:00 +02:00
Tony Zorman
e1dc2a3750 X.U.NamedScratchpad: Extract common parts of ns{HideOnFocusLoss,SingleScratchpadPerWorkspace} 2023-10-24 21:01:22 +02:00
philib
105cbe0362 X.U.NamedScratchpad: Add nsSingleScratchpadPerWorkspace
A logHook to allow only one active scratchpad per workspace.
2023-10-24 21:00:46 +02:00
Tony Zorman
9c4325f3ef
Merge pull request #836 from slotThe/wx-partial
Address some `-Wx-Partial` warnings
2023-10-20 08:21:59 +02:00
Tony Zorman
46a26487ba Reduce head usage 2023-10-20 08:13:24 +02:00
Tony Zorman
7680ebb93b Import X.Prelude unqualified if necessary
This gets rid of, for example,

    The import of ‘liftA2’ from module ‘XMonad.Prelude’ is redundant

-type warnings.
2023-10-20 08:13:23 +02:00
Tony Zorman
c3d16bfa99 X.L.Groups: Rewrite gen using infinite streams 2023-10-20 08:13:23 +02:00
Tony Zorman
7599c898ef X.Prelude: Add infinite stream type
Stolen from X.A.MostRecentlyUsed. This can be used in favour of lists
when we know the generated lists are definitely infinite.
2023-10-20 08:13:23 +02:00
Tony Zorman
8ee129483a X.U.Stack: Add zipperFocusedAtFirstOf 2023-10-20 08:13:02 +02:00
Tony Zorman
52a40f376c Replace tail with drop 1
Where appropriate.
2023-10-15 18:46:28 +02:00
Tony Zorman
c8c81474a2 X.A.CycleWindows: Move rot{Up,Down} to X.A.RotSlaves
Reexport them instead.
2023-10-15 11:00:35 +02:00
Tony Zorman
8c0ca8b9fe X.Prompt: Add isModifier
It seems sensible to abstract this away, if only to make the code a tad
more readable.
2023-10-11 09:43:26 +02:00
Tony Zorman
3cd1b066a2
Merge pull request #835 from slotThe/deprecate-cross
X.L.Cross: Deprecate
2023-10-10 07:35:28 +02:00
Tony Zorman
ba5011b874
Merge pull request #834 from slotThe/feat/prompt/cycle-backwards
X.Prompt: Allow for backwards cycling of completions
2023-10-09 16:36:42 +02:00
Tony Zorman
60867bdd2d X.L.Cross: Deprecate
The module has badly bitrotted, and is in such a state that it's
unlikely anyone is using it currently. Better alternatives exist, so
just deprecating seems appropriate here.

Closes: https://github.com/xmonad/xmonad-contrib/issues/793
2023-10-09 14:32:32 +02:00
Tony Zorman
8f8730b222
Merge pull request #833 from slotThe/pass-otp-type
X.P.Pass: Add passOTPTypePrompt
2023-10-06 10:03:17 +02:00
Tony Zorman
7854f7766e X.P.Pass: Properly escape backslashes 2023-10-06 09:07:11 +02:00
Tony Zorman
fde30fc073 X.P.Pass: Add passOTPTypePrompt 2023-10-06 09:07:11 +02:00
Tony Zorman
431ba22e3c X.P.Pass: Clean up code 2023-10-06 09:07:11 +02:00
Tony Zorman
570bd17a51 cabal: Bump containers dependency
Version 0.7 was confirmed to build via

    cabal build --flags=pedantic --constraint='containers >= 0.7'
2023-10-04 13:09:58 +02:00
Tony Zorman
4c0d3cac8d X.Prompt: Allow for backwards cycling of completions
+ Add a new prevCompletionKey to XPConfig, in order to cycle backwards.
  Bound to S-<Tab> by default.

+ Already handle null keystrings (times when only a modifier was
  pressed) in handleMain, such that completions aren't cleared
  prematurely.

+ Augment nextComplIndex (now computeComplIndex) with the ability to go
  in an arbitrary 1-dimensional direction. As a result, that function,
  as well as handleCompletion and handleCompletionMain now take an
  additional Direction1D argument.

Based on: https://github.com/solomon-b/xmonad-contrib/tree/feature/scrolling-prompt-completions
Fixes: https://github.com/xmonad/xmonad-contrib/issues/831

Co-authored-by: Solomon Bothwell <ssbothwell@gmail.com>
2023-10-04 09:27:53 +02:00
Christina Sørensen
a379850f50
XMonad.actions.search: Add NixOS and home-manager searchEngines (#832)
* feat(search): add nixos as searchEngine
* feat(search): add homeManager as searchEngine
* docs(CHANGES): add nixos, homeManager to searchEngine section

Signed-off-by: Christina Sørensen <christina@cafkafk.com>
2023-09-27 11:05:09 -04:00
Tony Zorman
7bb1f0b887 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:14:30 +02:00
Tony Zorman
4f6a9deaf8
Merge pull request #829 from slotThe/ghc/head
X.Prelude: Compatibility with base-4.18.0.0
2023-09-20 17:53:23 +02:00
Tony Zorman
32ff4db11c cabal: Bump bytestring dependency
Related: https://mail.haskell.org/pipermail/xmonad/2023-September/015647.html
2023-09-18 17:39:27 +02:00
Tomas Janousek
ac9265e774 ci: Replace deprecated haskell/actions/hlint-*
See https://github.com/haskell/actions/pull/301#issuecomment-1722353522
2023-09-18 15:42:25 +01:00
Tomas Janousek
c9a096ac1f 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:17:05 +01:00
dependabot[bot]
51ba23b776 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)
2023-09-17 21:22:45 +01:00
Tomas Janousek
b358c90a73 ci: Drop unnecessary cmd from "Install packdeps"
Not needed since https://github.com/haskell/actions/pull/165 (Jan 2023).
2023-09-17 21:21:18 +01:00
Tony Zorman
000cd14799 X.Prelude: Compatibility with base-4.18.0.0
Will ship with GHC 9.8.

Fixes: https://github.com/xmonad/xmonad-contrib/issues/826
2023-09-17 12:23:22 +02:00
Tony Zorman
0e2d3c159d
Merge pull request #827 from xmonad/dependabot/github_actions/cachix/install-nix-action-23
build(deps): bump cachix/install-nix-action from 22 to 23
2023-09-04 21:48:52 +02:00
dependabot[bot]
63a758243a
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-04 16:50:28 +00:00
Tony Zorman
2df26cf9f8 stack: Bump resolver to 21.6
This is the newest lts resolver for 9.4.5.
2023-08-12 14:22:26 +02:00
Tomas Janousek
6912eca829 X.A.WorkspaceNames: Use history for completion in renameWorkspace 2023-08-11 00:12:43 +01:00
Tony Zorman
348df92b89 X.U.Run: Fix definitions of >&&> and >||>
Whoops.

Fixes: 1b7fd6d8c99eee0b99261e48ed030b2ba42c88b5
2023-08-09 06:07:10 +02:00
Tony Zorman
1b7fd6d8c9 X.U.Run: Add >&&> and >||> 2023-08-08 20:08:11 +02:00
Tony Zorman
0ca3ce7a18 X.U.Run: Add toInput 2023-08-08 20:01:23 +02:00
Tony Zorman
bf41a85d9c
Merge pull request #822 from Zawaken/magnifiercxy
Add magnifiyxy combinator to XMonad.Layout.Magnifier
2023-08-06 09:35:48 +02:00
Zawaken
a0bfa8a447 X.L.Magnifier: Add magnifyxy
The combinator allows for different magnification to be used in the
horizontal and vertical direction.
2023-08-06 09:28:23 +02:00
Tony Zorman
7062b75ea9
Merge pull request #819 from slotThe/ci/bump
Bump cabal/stack CI
2023-07-18 09:35:44 +02:00
Tony Zorman
34b544b7a1 ci/cabal: Bump GHC versions 2023-07-16 17:27:16 +02:00
Tony Zorman
5b5a51787c ci/stack: Add lts-21 resolver 2023-07-16 17:26:49 +02:00
Tomáš Janoušek
4d0f3ee944
Merge pull request #818 from geekosaur/debugwindow-fix-decode
fix double decode in `debugWindow`
2023-06-26 14:56:14 +02:00
Tony Zorman
e02400b1c7 X.A.Prefix: Add orIfPrefixed
- Generalise signature of withPrefixArgument, in order to accommodate
  this.
2023-06-23 08:14:38 +02:00
brandon s allbery kf8nh
4a60866ea4
fix double decode in debugWindow
At some point `peekCString` became locale aware. This is a double
bug, since (a) `decodeString` was being applied to the result and
(b) the locale might not be UTF-8, but the string being decoded
always is.

The fix is to use `peekCAString` which bypasses the locale decode,
then continuing to do UTF-8 decode.
2023-06-22 06:25:56 -04:00
Tomáš Janoušek
4bdcab8bf6
Merge pull request #817 from xmonad/dependabot/github_actions/cachix/install-nix-action-22
build(deps): bump cachix/install-nix-action from 21 to 22
2023-06-19 22:52:20 +02:00
dependabot[bot]
f2ac181616
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 17:00:04 +00:00
Tomáš Janoušek
b6c0dd9cfc
Merge pull request #816 from xmonad/dependabot/github_actions/cachix/install-nix-action-21
build(deps): bump cachix/install-nix-action from 20 to 21
2023-05-29 20:15:44 +02:00
dependabot[bot]
611317f398
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 16:59:34 +00:00
Tony Zorman
ad48cdc2cb
Merge pull request #814 from geekosaur/808-supported-partial-struts
add `_NET_WM_STRUT_PARTIAL` to `_NET_SUPPORTED`
2023-05-14 12:28:06 +02:00
brandon s allbery kf8nh
1486d076dc
add _NET_WM_STRUT_PARTIAL to _NET_SUPPORTED
For docks that don't support `_NET_WM_STRUT` any more,
notably `xfce4-panel`.
2023-05-12 12:29:37 -04:00
brandon s allbery kf8nh
1243bbbded Fix many bugs and shortcomings in debugEventsHook
Added support for several more properties, and fixed parsing of many
others. Still doesn't handle COMPOUND_TEXT and the code in DebugWindow
is wrong. I have correct code in C++ but it will require some work to
translate to Haskell so it can be used in both places.
2023-04-26 13:24:01 -04:00
Mahdi Seyedan
cf00d2d237 Add CenterMainFluid layout 2023-04-21 10:23:13 -04:00
brandon s allbery kf8nh
87ae269b82 Put a cap on window names
It turns out qutebrowser will place an entire `data:` URL in
`_NET_WM_NAME`, up to at least 389K characters including
newlines and possibly binary characters.

Clamping window titles to the first line, and to 2K chars
because `defaultShrinker` is quadratic in the title length.
2023-04-19 12:53:33 -04:00
Tomáš Janoušek
673de11ca8
Merge pull request #768 from liskin/fullscreen-hooks
Add (un)fullscreen hooks and float-restoring toggleFullFloat action
2023-04-01 12:32:01 +02:00
Tomas Janousek
02bd9eb0c0 CHANGES: Document X.A.ToggleFullFloat and setEwmhFullscreenHooks 2023-04-01 12:06:58 +02:00
Tomas Janousek
d86f9ade22 Add X.A.ToggleFullFloat - state-remembering fullscreen hooks
Fixes: https://github.com/xmonad/xmonad-contrib/issues/456
Related: https://github.com/xmonad/xmonad-contrib/issues/394
Related: https://github.com/xmonad/xmonad-contrib/pull/626
2023-04-01 12:06:58 +02:00
Tomas Janousek
2dcc3a92e7 X.H.EwmhDesktops: Add (un)fullscreen hooks
Fairly straightforward, just add two hooks for (un)fullscreening. There
are multiple motivations for this:

* Users are calling for unfullscreened windows to revert back to their
  original location if they were floating.

* XMonad.Layout.Fullscreen uses some deprecated exports from
  XMonad.Hooks.EwmhDesktops and reimplements fullscreenEventHook.

This commit only adds the hooks. Neither of the motivations are dealt
with yet, so the docs are a bit terse still.

Related: https://github.com/xmonad/xmonad-contrib/issues/456
Related: https://github.com/xmonad/xmonad-contrib/issues/394
Related: https://github.com/xmonad/xmonad-contrib/pull/626
2023-04-01 12:06:58 +02:00
Tony Zorman
815a595b46 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: 67064ddd9264bbe39d6fa88fd8336086817dd0db
2023-03-31 07:50:09 +02:00
Tony Zorman
1d84db959c 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.
2023-03-31 07:48:02 +02:00
Tony Zorman
f127f71c91 X.Prompt: Alias C-m to RET in Emacs/Vim bindings
Both programs interpret C-m as RET, so the prompt should reflect this as
well.
2023-03-29 08:26:20 +02:00
Tony Zorman
fb63987ac8 X.Prompt: Factor out how to accept the current selection 2023-03-29 08:22:26 +02:00
Tony Zorman
635711e994 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: https://github.com/xmonad/xmonad-contrib/issues/805
2023-03-28 07:53:09 +02:00
Tony Zorman
4929da0eac CI: Fix build with mtl-2.3.1
Technically, contrib still does not build with stack, as it forces
xmonad-0.17.0, while only HEAD builds with newer mtl versions.  However,
until our dependencies are at least revbumped, this may be the best we
can do.

Related: https://github.com/xmonad/xmonad-contrib/issues/805
2023-03-27 08:17:36 +02:00
Tony Zorman
e60805bd45
Merge pull request #804 from xmonad/dependabot/github_actions/cachix/install-nix-action-20
build(deps): bump cachix/install-nix-action from 19 to 20
2023-03-06 18:39:48 +01:00
dependabot[bot]
49edaf37fd
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 17:08:28 +00:00
Tomáš Janoušek
5324f53501
Merge pull request #802 from geekosaur/801-dynamicLogString
`dynamicLogString` forces its result and recovers
2023-02-20 21:45:42 +00:00
brandon s allbery kf8nh
4a97716d59
dynamicLogString forces its result and recovers
Originally, `dynamicLogString` could have a bottom hidden in it and
thereby crash the `logHook`. Under some circumstances (see #801)
this could cause xmonad to get stuck. We now force the result, and
`dynamicLogString` catches the exception and substitutes a
message (currently "_|_"). Use `dynamicLogString'` for the old behavior.
2023-02-20 16:39:49 -05:00
Tony Zorman
6063855a3e X.P.OrgMode: Simplify refile 2023-02-18 13:23:15 +01:00
Yecine Megdiche
1bcdbc9072
Merge pull request #800 from 1in1/master
Add loggers for window classname
2023-02-13 10:49:07 +01:00
l
2dd3c614e2 add loggers for window classname 2023-02-12 11:17:32 +00:00
Leary
6b19388139
Merge pull request #784 from LSLeary/focus-tracking
Extract redundant layouts into new module: X.L.FocusTracking
2023-02-12 20:36:32 +13:00
L. S. Leary
a52e646cc1 Extract redundant layouts into new module: X.L.FocusTracking
X.L.StateFull's `FocusTracking` and the eponymous `TrackFloating` were
redundant, hence the former was slated for deprecation. However,
the latter and its host module are somewhat poorly named; the layout
modifier has little relation to floats. As such, it's renamed and
rehosted, becoming the eponymous `FocusTracking`.

The redundant offerings in the original modules are redefined in terms
of the new module where possible, and deprecated.

See: #418; comments on #253, #783.
2023-02-12 20:20:52 +13:00
brandon s allbery kf8nh
29f0e03256 Config modifiers infixl 4 so you can use (++) 2023-02-09 03:52:58 -05:00
dependabot[bot]
726e887239 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-06 20:48:12 +00:00
Tony Zorman
6fba80168d
Merge pull request #796 from slotThe/fix/named-actions/key-overwriting
X.U.NamedActions: Do not discard all keybindings in addDescrKeys
2023-01-29 08:24:47 +01:00
Tony Zorman
90f4a96f93 X.U.NamedActions: Do not discard all keybindings in addDescrKeys
Discarding keybindings may yield unintended behaviour when keybindings
are added via combinators, instead of the `keys` field.  This makes the
combinators noncommutative, which is very counterintuitive.

Related: https://old.reddit.com/r/xmonad/comments/10g1v1r/deftogglestrutskey_not_working/
2023-01-27 20:34:43 +01:00
Tony Zorman
33c1e24288
Merge pull request #794 from slotThe/ezconfig/remapkeysp
X.U.EZConfig: Add remapKeysP
2023-01-25 21:02:51 +01:00
Tony Zorman
49904ec4d3 X.U.NamedScratchpad: Fix typo in exclusive docs
Fixes: f059829f03
2023-01-25 07:49:05 +01:00
Tony Zorman
339dbbf2fd
Merge pull request #795 from TheMC47/feat/start-sbs
X.H.StatusBar: Added startAllStatusBars
2023-01-24 20:35:34 +01:00
Yecine Megdiche
6caba97b34 X.H.StatusBar: Added startAllStatusBars 2023-01-24 20:34:58 +01:00
Tony Zorman
0afbbf9129 X.U.EZConfig: Add remapKeysP 2023-01-21 07:05:08 +01:00
Tony Zorman
df1fc2d334 X.A.Search: Export noogle
Fixes: 7665b67ff4f90343324ad11618324892a902b184
2023-01-18 20:42:45 +01:00
Tony Zorman
7665b67ff4 X.A.Search: Add noogle 2023-01-18 17:56:57 +01:00
Tony Zorman
a790c816d2
Merge pull request #766 from LSLeary/repeatable
Factor X.A.Cycle* modules; Write Alt+Tab style window switching
2023-01-14 15:29:50 +01:00
L. S. Leary
b9263ad17e Write new module: X.A.MostRecentlyUsed 2023-01-12 17:53:26 +01:00
L. S. Leary
8f0912a674 Write new module: X.U.History 2023-01-12 17:52:58 +01:00
L. S. Leary
dd7855da3d Factor shared logic out of X.A.Cycle* modules
These modules were duplicating a substantial amount of low-level code.

`X.A.CycleWorkspaceByScreen` had already separated most of the
implementation details from the logic with `repeatableAction`; all that
was left was to generalise it a little further, put it in a suitable
place and express the other modules through it.
2023-01-12 17:52:18 +01:00
Tony Zorman
e85f0151b2 X.A.VisualSubmap: Fix example 2023-01-11 16:50:42 +01:00
Tony Zorman
840d740366
Merge pull request #792 from TheMC47/master
README: update badge URLs
2023-01-06 19:03:42 +01:00
Yecine Megdiche
a5bd5d96ca README: update badge URLs
See https://github.com/badges/shields/issues/8671
2023-01-06 13:44:16 +01:00
Tony Zorman
4e8857ecee
Merge pull request #791 from pbrisbin/pb/desktop-viewport
Add EWMH configuration to not set _NET_DESKTOP_VIEWPORT
2023-01-05 07:51:37 +01:00
patrick brisbin
cf13f8f9a7 X.H.EwmhDesktops: Add disableEwmhManageDesktopViewport
This combinator forces XMonad to *not* set _NET_DESKTOP_VIEWPORT.

This information is picked up by polybar's xworkspaces module and used
to re-group the workspaces by monitor. I (and others) find this super
confusing, but polybar doesn't not seem open to addressing it.

https://github.com/polybar/polybar/issues/2603

Opting in to the old behavior of not managing this property is one way
to work around it instead.
2023-01-05 07:47:16 +01:00
Tomas Janousek
e2ffa533da 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: b7afb0c0bc3f ("ci: Pin runner in hlint, nix workflows to ubuntu-20.04")
2023-01-02 20:45:19 +01:00
Tomas Janousek
6b20dbca42 Apply hlint 3.5 hints 2023-01-02 20:45:19 +01:00
Tony Zorman
6117a867d9 Update CHANGES.md
Mention f7e9c0cf0d0584be1b586041580c7ec8d8d57647
2022-12-31 13:52:32 +01:00
Tony Zorman
f7e9c0cf0d X.L.ResizableThreeColumns: Fix bottom right window not resizing
...by introducing yet another special case.  Unsurprisingly, this is
just a bandaid—the logic in this module is just wrong.  It
purposefully (not introduced with this change) computes the wrong
positions for certain extreme points such that splitVertically (which
simply goes down the list of stack windows _in order_) still works.

What we should do instead is to either

  - keep track of windows that want to change their size and compute a
    rectangle for them first, or

  - immediately when handling the resize message, compute *all* of the
    new sizes immediately (instead of only for the window getting
    resized).

The latter would force us to keep track of the size of the current stack
we operate in, but since 'handleMessage' lives in X this should not pose
a big problem.  I reckon this is the better approach.

Fixes: https://github.com/xmonad/xmonad-contrib/issues/788
2022-12-31 13:33:36 +01:00
Tony Zorman
e0be851074 X.L.ResizableThreeColumns: Change terminology
For everything, except the exported fields.  Perhaps we should change
these as well, but that's for another commit.
2022-12-31 13:33:36 +01:00
Tony Zorman
55855ccb5f
Merge pull request #785 from geekosaur/debugwindow-fix-netwm
fix EWMH titles
2022-12-28 16:43:41 +01:00
brandon s allbery kf8nh
4df2036187 remove references to baseConfig
that's from my private config and has no referent here
2022-12-12 16:16:45 -05:00
brandon s allbery kf8nh
4998e946cc
fix EWMH titles
I have no idea what I was thinking when I wrote that code.
While at it, just reused the code for ICCCM title which already
assumes the client may have broken the rules (I think we have
seen a case of `WM_NAME` being `UTF8_STRING`).
2022-12-12 13:30:42 -05:00
Tomas Janousek
04c0ddd3e0 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:48 +00:00
Tomas Janousek
b7afb0c0bc 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:09:25 +00:00
Tomas Janousek
18eca4e8d6 ci: Drop ppa:hvr/ghc
Breaks `apt update` on the ubuntu-22.04 runner, which is what
ubuntu-latest resolves to these days.

Fixes: 7312d6f3f3f7 ("ci: Drop GHC installation via apt")
2022-12-01 12:06:17 +00:00
dependabot[bot]
797fd24112 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:42:25 +00:00
Tomáš Janoušek
cf0e3531f9 ci: Configure dependabot to keep GH Actions up to date 2022-11-27 17:42:25 +00:00
Tomas Janousek
8cd09601b1 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:42:25 +00:00
Tomas Janousek
0bd43c072f ci: Update to GHC 9.4.3 2022-11-27 17:42:25 +00:00
Tony Zorman
10c1a93963 X.U.NamedScratchpads: Check for "new" workspace in nsHideOnFocusLoss
When XMonad was recently restarted, it can happen that the workspace
history is empty, hence the last focused window could actually be the
currently focused one.  In that case, we don't want to go through the
machinery of looking to hide any NSPs, as there is only one window in
the current workspace (the focused one).  This may or may not be a
scratchpad, we don't care.

Fixes: https://github.com/xmonad/xmonad-contrib/issues/779
2022-11-20 17:06:35 +01:00
Tony Zorman
58e7f6d3c3
Merge pull request #778 from slotThe/drop-8.4
Drop GHC 8.4
2022-11-20 17:01:48 +01:00
Tony Zorman
502f6a0e75 X.P.OrgMode: Fix deprecation warning
Starting with time-1.10, the iso8601DateFormat function was deprecated
in favour of more sophisticated methods for showing ISO 8601 date
formats—as such, follow the libraries lead.

Sadly, the new functionality was only introduced in time-1.9, meaning
GHC 8.8 and up.  Since we still support 8.6, the introduction of some
CPP is necessary.
2022-11-20 16:53:36 +01:00
Tony Zorman
35e434ed85 stack: Bump resolver to lts-20.0 2022-11-20 16:53:36 +01:00
Tony Zorman
b96bb908db Simplify instance declarations
Many instance declarations can now be derived either by DerivingVia or
GeneralizedNewtypeDeriving.
2022-11-20 16:53:36 +01:00
Tony Zorman
5d0013ef53 ci: Drop support for GHC 8.4
Debian stable and Ubuntu 20.04 are now 8.8 and 8.6, respectively, which
was always our guide as to which GHC versions we want to support.
2022-11-20 16:53:06 +01:00
Tony Zorman
0f69215fc8 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-19 09:18:35 +01:00
Tony Zorman
57b5055858 X.A.Search: Add arXiv, clojureDocs, cratesIo, rustStd, zbmath
Related: 233a05908d6953be79f02a030ab5f20272357630
         (https://github.com/xmonad/xmonad-contrib/pull/777)
2022-11-15 09:29:08 +01:00
Tony Zorman
af5fced79a X.A.Search: voidpackages -> voidpgks_x86_64{_musl}
Musl on Void is popular enough that it makes sense to provide an extra
search engine for it.

Related: https://github.com/xmonad/xmonad-contrib/pull/777/files
2022-11-13 10:16:23 +01:00
Tony Zorman
d7499d1db0 CHANGES: Reindent
Fixes: https://github.com/xmonad/xmonad-contrib/pull/777
2022-11-13 10:04:19 +01:00
Luc-Saccoccio
233a05908d Added AUR, Flora, nCatLab, ProtonDB, RosettaCode, Sourcehut, Steam, Void
Linux packages. Reorganized the list, and added wiktionary which was
forgotten in the list although it was implemented.
2022-11-12 12:43:12 -05:00
Tony Zorman
e406e27139
Merge pull request #774 from slotThe/nsp/exclusive
X.U.NamedScratchpad: Add exclusive scratchpad capabilities
2022-11-11 21:06:10 +01:00
Tony Zorman
1c6ae39fc9 X.P.OrgMode: Also parse time in HHMM format 2022-11-10 11:50:28 +01:00
Tony Zorman
b627306772 X.P.OrgMode: Include 00:xx and xx:00 in the date range 2022-11-10 11:49:46 +01:00
Tony Zorman
8b4560dc1e X.P.OrgMode: Parse dates case-insensitively 2022-11-10 11:49:46 +01:00
L. S. Leary
608a8e4b88 Fix documentation bug in X.A.GridSelect 2022-11-08 23:02:51 +13:00
Tony Zorman
6373dc41fa
Merge pull request #772 from ilya-bobyr/master
EwmhDesktops: _NET_CLIENT_LIST_STACKING: In focus order
2022-11-07 08:01:52 +01:00
Tony Zorman
8cb789af39 CI: Compatibility with mtl 2.3.1
Libraries like Control.Monad are no longer exported from
Control.Monad.Reader et.al.

Related: https://github.com/xmonad/xmonad/pull/427
         xmonad/xmonad#d170e99bc5e97db96be9a02b72149103e8d419af
2022-11-03 08:25:00 +01:00
Illia Bobyr
cf975d082e
EwmhDesktops: _NET_CLIENT_LIST_STACKING: In focus order
Order workspaces based on the visibility, before collecting windows.
`_NET_CLIENT_LIST_STACKING` is supposed to be in the focus order.
2022-11-02 11:03:08 -07:00
Tony Zorman
e0d1f177ea
Merge pull request #773 from aplaice/broken_links_doc
Fix some more broken inter-module docs links
2022-11-02 15:50:32 +01:00
Tony Zorman
bb9d6edad6 CHANGES: Re-indent newest changes
To conform with the style that all of the other changes (and the
breaking changes of the same release) have.
2022-11-02 11:17:51 +01:00
Tony Zorman
ab6299a488 X.U.ExclusiveScratchpads: Deprecate
Obsoleted by the exclusive scratchpad functionality of X.U.NSP.
2022-11-02 11:17:51 +01:00
Tony Zorman
226629977b X.U.NamedScratchpad: Add documentation about other types
With [1] and now [2], NSP has a lot more functionality that used to be
confined to other modules.  This is indicated in the TOC when viewing
the documentation, but it should perhaps be more prominently mentioned
in the introduction/usage docs.

[1]: https://github.com/xmonad/xmonad-contrib/pull/690
     533e17135e953938834551558062566a73e1ae2c
[2]: https://github.com/xmonad/xmonad-contrib/pull/774
2022-11-02 11:17:51 +01:00
Tony Zorman
f059829f03 X.U.NamedScratchpad: Add exclusive scratchpad capabilities 2022-11-02 11:17:51 +01:00
Tony Zorman
49e9570f12 X.U.NamedScratchpad: Factor out isNSP
This function can be pretty useful in a general context, so let's factor
it out.
2022-11-02 11:17:49 +01:00
Tony Zorman
48a6d34f55 X.Prelude: Add findM
Several definitions of this were scattered over a few modules, so just
re-export it from our prelude.
2022-11-02 11:17:26 +01:00
Adam Plaice
ca866229f6 Fix most remaining broken inter-module docs links
The links were broken due to:

1. Incorrect quotes (' instead of " for module links and occasionally
vice-versa).

2. Changes in the name of the "target" module not reflected in the
"source" docs.

3. Typos to begin with.

4. Use of `<foo>` in the docs is rendered as just `foo` with a link to
`/foo`.

5. Similarly for `"Foo"` if it starts with a capital letter (and hence
could be a module).

6. Markup inside `@` code blocks still being applied.

e.g. `@M-<arrow-keys>@` is rendered as `M-arrow-keys` with a spurious
hyperlink from arrow-keys to `/arrow-keys`, which is confusing.

Three links from XMonad.Util.Run have been removed outright, since
they're no longer examples of the usage of 'runProcessWithInput'.
WmiiActions has been gone since 2008, while XMonad.Prompt.Directory
and XMonad.Layout.WorkspaceDir haven't been using
'runProcessWithInput' since 2020 and 2012, respectively.

In some cases the `<foo>` were surrounded with @, especially in the
case of key definitions, for consistency.  (This wasn't done
everywhere, because it looks ugly in the source.)

MoreManageHelpers has never been in xmonad-contrib.  ManageHelpers
seems to fill the expected role.

In the case of the module description for X.H.ManageDebug the quotes
were simply removed because none of the likely options to make the
link work were successful.
2022-11-01 19:35:55 +01:00
Tony Zorman
d301affabb
Merge pull request #760 from slotThe/orgmode/refile
X.P.OrgMode: Add orgPromptRefile[To]
2022-10-31 14:38:25 +01:00
Tony Zorman
a97a1acf87 X.P.OrgMode: Remove the need for todoKeywords argument
This is (i) much simpler to use and (ii) helps us with refiling.  Emacs
will ignore todo keywords _that it knows_ when refiling, but when
started in batch-mode it doesn't know a whole lot.  One would need to
thread the `todoKeywords' through to `refile' and then set
`org-todo-keywords' or a similar variable, which does not sound like a
good experience.  Hence, falling back to showing the todo keyword to the
user when deciding upon a headline sounds acceptable.
2022-10-31 14:29:43 +01:00
Tony Zorman
bdb13e2551 X.P.OrgMode: Add orgPromptRefile[To]
Add orgPromptRefile and orgPromptRefileTo in order to refile entries
after insertion.
2022-10-31 14:29:43 +01:00
Tomáš Janoušek
3d0502f7b6
Merge pull request #775 from liskin/ci
CI maintenance (GHA deprecations, GHC 9.4)
2022-10-31 11:45:12 +00:00
Tomas Janousek
6880417911 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: 7cee1915169d ("CI: Remove hlint from haskell-ci")
2022-10-30 23:01:41 +00:00
Tomas Janousek
c4dca3592e 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:52:10 +00:00
Tomas Janousek
4242fa02a0 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:23 +00:00
Tomas Janousek
f81b9fb725 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:24:46 +00:00
Tomas Janousek
b0b8e4fb2c 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:20:21 +00:00
Tomas Janousek
7312d6f3f3 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 21:19:16 +00:00
Tomas Janousek
b75ed7295c 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 21:11:20 +00:00
Tony Zorman
c27a1f0791
Merge pull request #770 from slotThe/bikeshed/dynamicproperty
New module: XMonad.Hooks.OnPropertyChange
2022-10-29 14:48:43 +02:00
Tony Zorman
eaab5bfbba New module: XMonad.Hooks.OnPropertyChange
This is the same module as X.H.DynamicProperty, just with (hopefully)
more discoverable names.

Closes: https://github.com/xmonad/xmonad-contrib/issues/588

Co-authored-by: Tomas Janousek <tomi@nomi.cz>
2022-10-29 14:42:48 +02:00
Tony Zorman
fce5558b62
Merge pull request #769 from aplaice/spawnonce_doc_link
Fix broken link in doc for XMonad.Util.SpawnOnce
2022-10-27 07:45:48 +02:00
Adam Plaice
2ab520eeda Fix inter-module link (use " instead of ')
Otherwise, haddock tries to link to a (non-existent) function in
"XMonad.Util", which gives a "page not found".

See:

https://haskell-haddock.readthedocs.io/en/latest/markup.html#
linking-to-modules
2022-10-26 21:19:29 +02:00
Tony Zorman
cd95bf9c28 X.P.OrgMode: Return "exitCode" mkOrgPrompt
More formally, return whether the user cancelled the prompt or not.
This is useful in case we want to do things only after a "successful"
input.
2022-10-26 20:25:53 +02:00
Tony Zorman
b9c8294045 X.P.OrgMode: Add mkOrgCfg
This ensures that we always immediately expand the file path upon
constructing an `OrgMode' record.  We thus do not have to do this in
`mkOrgPrompt' anymore.
2022-10-26 20:25:53 +02:00
Tony Zorman
2ffc5de6cf X.U.Run: Don't use elispFun in progn
This is already taken care of by execute and eval, so forcing it in
progn only hampers composability.
2022-10-26 20:25:53 +02:00
Tony Zorman
08071706ba X.U.Run: Add list, saveExcursion 2022-10-26 20:25:53 +02:00
Tony Zorman
f55502f723
Merge pull request #765 from slotThe/hlint-workflow
Create HLint workflow
2022-10-25 08:55:14 +02:00
Tony Zorman
7cee191516 CI: Remove hlint from haskell-ci
As we have a proper hlint action now, this is no longer needed.
2022-10-25 08:49:23 +02:00
Tony Zorman
dd26fcc3f1 CI: Add hlint workflow
Closes: https://github.com/xmonad/xmonad-contrib/issues/669
2022-10-25 08:49:23 +02:00
Tony Zorman
571d017b82
Merge pull request #763 from slotThe/extending->tutorial
A Potpourri of Small Changes
2022-10-21 09:24:46 +02:00
Tony Zorman
570eb8ccb8 X.A.Navigation2D: Add sideNavigation as to default tiled navigation
Add sideNavigation as a fallback if needed.  This should not have any
user-facing behaviour change when not using gaps or spacing, as line
navigation is preferred.  However, users who do use spacing or gaps
should now potentially not have to change the default strategy in order
to have a usable module.
2022-10-21 09:18:06 +02:00
Tony Zorman
cca2ccfc71 X.A.Navigation2D: More prominently document strategies
Also, add a note that users who use gaps or spacing may need to look
into these strategies a bit more deeply.

Fixes: https://github.com/xmonad/xmonad-contrib/issues/627
2022-10-21 09:18:06 +02:00
Tony Zorman
41d6ac96d5 X.H.InsertPosition: Add combinator
Users may not see the warning that insertPosition definitely needs to be
inserted at the leftmost position, which can cause undesired behaviour.
Having a combinator that handles this automatically seems like a sane
idea.

Fixes: https://github.com/xmonad/xmonad-contrib/issues/709

       (Note that `docs` wasn't changed since it already inserts itself
       rightmost.)
2022-10-21 09:18:06 +02:00
Tony Zorman
4c8edd3bfb X.A.FloatKeys: Add direction{Move,Resize}Window
These are simpler, more easily understood, alternatives to the existing
functions.

Fixes: https://github.com/xmonad/xmonad-contrib/issues/712
2022-10-21 09:18:04 +02:00
Tony Zorman
3d65a6bf72 Refer to the tutorial instead of X.D.Extending more often
Essentially, whenever the tutorial actually has decent material on the
subject matter.  The replacement is roughly done as follows:

  - logHook → tutorial
  - keybindings → tutorial, as this is thoroughly covered
  - manageHook → tutorial + X.D.Extending, as the manageHook stuff the
    tutorial talks about is a little bit of an afterthought.
  - X.D.Extending (on its own) → tutorial + X.D.Extending
  - layoutHook → tutorial + X.D.Extending, as the tutorial, while
    talking about layouts, doesn't necessarily have a huge focus there.
  - mouse bindings → leave this alone, as the tutorial does not at all
    talk about them.
2022-10-21 09:17:43 +02:00
Tony Zorman
05c4c776af
Merge pull request #759 from slotThe/parser/feature-parity
X.U.Parser: Achieve feature parity with ReadP
2022-10-17 17:23:44 +02:00
Tony Zorman
2b1a15c9e5 X.P.OrgMode: Remove pLast
Use the more aptly named `option` instead.
2022-10-17 14:04:43 +02:00
Tony Zorman
0bef428f8f X.U.Parser: Inline definitions
Most of these definitions are probably small enough to be inlined on
their own, but tell GHC to try really hard regardless.  This is commonly
done by other parser libraries as well; e.g., [1], so it shouldn't cause
any issues either way.

[1]: https://hackage.haskell.org/package/parsers-0.12.11
2022-10-17 14:04:43 +02:00
Tony Zorman
4d7ae81f7a X.U.Parser: Feature parity with ReadP
While not many of these more exotic combinators are used right now, it's
still nice to have feature parity (i.e., everything that one could want
from a basic parser) such that people don't have to add their own
combinators, in case they want to use one that's not already
implemented.
2022-10-17 14:04:43 +02:00
Tony Zorman
7d4f0aaece
Merge pull request #761 from exorcist365/master
X.H.Modal: Remove `Keys` type alias
2022-10-14 07:24:02 +02:00
exorcist365
4734551c76 X.H.Modal: Remove Keys type alias
This was only used in three places throughout the module and is sort of
non-standard terminology, hence it might confuse users.  Talking about
functions of type

    XConfig Layout -> M.Map (ButtonMask, KeySym) (X ())

is relatively standard in other modules as well, so it's probably best
to remove the type alias for it.
2022-10-14 07:20:42 +02:00
Tony Zorman
865c63a361 X.U.Run: Add executeNoQuote 2022-10-11 19:22:40 +02:00
Tomas Janousek
c3ea62c972 CHANGES: Fix thinko in module name 2022-10-05 22:21:23 +01:00
Tomas Janousek
005951535b CHANGES: Fix whitespace and misplaced underscores 2022-10-05 22:17:57 +01:00
Tony Zorman
ecd052b7fd
Merge pull request #410 from slotThe/remove-deprecations
Remove (more) Deprecations, Properly Deprecate Modules
2022-10-04 07:10:18 +02:00
Tony Zorman
e15f2d17e5
Merge pull request #758 from alexandersokolow/master
expose more messages in MouseResizableTile layout
2022-09-30 11:38:38 +02:00
alexandersokolow
9e55ae9184 expose more messages in MouseResizableTile layout 2022-09-29 19:43:28 +02:00
L. S. Leary
b9794e6a13 Fix documentation bug in X.U.NSP
The Usage section made reference to a non-existent
`namedScratchpadSpawnAction` function. It has been replaced with
`namedScratchpadAction` in accordance with the documented bindings
below.
2022-09-23 19:21:48 +12:00
slotThe
1e3b49f064 CHANGES: Mention deprecations and removals
This reflects the changes made in the following previous commits:

  - f02b3a98691d4c51bd8ea2171d6a7ce9a94064a3
  - 3bf9d80c40b9ec8f2900fe9fffa4fc17627b5b0d
  - 4a8bd762afd5c25df716d1e66201490761bddb70
  - d28c0a242517e12eb6958d3ed27e5c2d94bbb16f
  - 6f49a9394f542a54fc70c82c0705df68bf5ed5eb
  - 287b8bf95f0400b382a238b07e37c414d564a7c4
  - d8a23d47bfbcb88678e7fe8b5d7af708aecf6024
  - 16701c2df2990f92a9ffbb13e8532ce7e3f4d9e1
  - 6ab4d9c0bc1256f8d4892afcee97cce3b1b76890
2022-09-22 07:59:14 +02:00
slotThe
f02b3a9869 XMonad.Actions.SinkAll: Deprecate 2022-09-22 07:51:52 +02:00
slotThe
3bf9d80c40 XMonad.Layout.Named: Deprecate 2022-09-22 07:51:52 +02:00
slotThe
4a8bd762af XMonad.Hooks.RestoreMinimized: Remove 2022-09-22 07:39:54 +02:00
slotThe
d28c0a2425 XMonad.Layout.LayoutBuilderP: Remove 2022-09-22 07:39:54 +02:00
slotThe
6f49a9394f XMonad.Hooks.ICCCMFocus: Remove 2022-09-22 07:39:54 +02:00
slotThe
287b8bf95f XMonad.Layout.Navigation2D: Remove deprecations 2022-09-22 07:39:54 +02:00
slotThe
d8a23d47bf XMonad.Layout.Spacing: Remove deprecations 2022-09-22 07:39:54 +02:00
slotThe
16701c2df2 XMonad.Actions.MessageFeedback: Remove deprecations 2022-09-22 07:39:54 +02:00
slotThe
6ab4d9c0bc XMonad.Prompt.Window: Remove deprecations 2022-09-22 07:39:54 +02:00
Tony Zorman
24f11362c7 docs: Add additional external blog posts
This may seem a bit self-indulgent, but both of these features are
either quite new or so old that no one remembers them anymore, so not a
lot of up-to-date content exists for them.
2022-09-22 07:37:28 +02:00
Tony Zorman
a267fed24f
Merge pull request #757 from slotThe/deprecate-sp
X.U.Scratchpad: Deprecate
2022-09-20 11:54:32 +02:00
Tony Zorman
a44df170f4 X.U.Run: Add findFile 2022-09-19 09:43:42 +02:00
Tony Zorman
2ebbe57bc2 X.U.Run: Quote string in execute and eval
Ordinarily, this should already be the case.  If for some reason it is
not, definitely make sure to quote the input string that we want to
execute.
2022-09-19 09:43:42 +02:00
Tony Zorman
ea16598a78 X.U.Scratchpad: Deprecate
This is i) broken and ii) just the functionality of X.U.NamedScratchpad
rewrapped (and not necessarily improved upon) at this point.

With recent changes to the way named scratchpads work[1], we would have
to export internals of X.U.NamedScratchpad in order to restore
X.U.Scratchpad to its full functionality.  This does not seem worth it,
as the latter does not bring anything substantially new to the table.

Closes: https://github.com/xmonad/xmonad-contrib/issues/756
Related: https://github.com/xmonad/xmonad-contrib/issues/591
[1]: 3fc830aa09368dca04df24bf7ec4ac817f2de479
2022-09-18 17:29:26 +02:00
Tony Zorman
4a3f8eb032 X.U.Font: Add a fallback font to initXMF
In case a font could not be opened, simply fall back to "xft:monospace"
and open that.  The initCoreFont and initUtf8Font functions already have
mechanisms like this, is was just missing from initXMF.

Closes: https://github.com/xmonad/xmonad-contrib/issues/723
2022-09-15 19:02:26 +02:00
Tony Zorman
b0fc55499d
Merge pull request #754 from Quoteme/master
made borderresize take a parameter
2022-09-10 16:30:15 +02:00
Luca Leon Happel
ae652b40f4 X.L.BorderResize: Add borderResizeNear
TODO
The parameter is how many pixels near the border of a window resizing
will be possible
2022-09-10 16:20:35 +02:00
Tony Zorman
8a6542f6b3
Merge pull request #751 from slotThe/x.d.extending/round-two
X.D.Extending: Round Two
2022-09-08 13:10:31 +02:00
Tony Zorman
5378e93e15 X.D.Extending: Remove keyAddDel and logHook
+ $keyAddDel can just be a side note in $keyDel, it does not need its
  own section.

+ $logHook is covered in more detail in the tutorial and does not serve
  a real purpose anymore.  One could rewrite it to be more in-depth
  about the inner workings of X.H.StatusBar, but for the time removing
  it seems like the best option.

Closes: https://github.com/xmonad/xmonad-contrib/issues/645
2022-09-08 13:09:55 +02:00
Tony Zorman
cedb8d7c78 X.D.Extending: Rewrite keyDel
Nowadays, removing keys is mostly done via removeKeys and removeKeysP,
so the documentation should reflect that fact.  This part is less
step-by-step instructive than the section about adding keys, but read in
succession it presents a way to deepen the newly acquired knowledge.
2022-09-08 13:09:55 +02:00
Tony Zorman
9809b2013f X.D.Extending: Update hooks
+ Refer to X.H.StatusBar whenever possible at the start.
+ Fix some small typos throughout the module.

Related: https://github.com/xmonad/xmonad-contrib/issues/645
2022-09-08 13:09:55 +02:00
Tony Zorman
9b6bef7e9d X.D.Extending: Add links to headings
This is more ergonomic to use than the old-style headings; plus, the
generated Haddock is easier to read than just stating
"XMonad.Doc.Extending".
2022-09-06 20:16:21 +02:00
Tony Zorman
fd5970fb34 NIX.md: Suggest a recent revision of GHC 9.2
Lest anyone run into https://github.com/xmonad/xmonad/issues/389.
2022-09-05 19:05:27 +02:00
Tony Zorman
b0ca330d08
Merge pull request #750 from LSLeary/nixflake
Fixes and Workarounds in flake.nix, Documentation in NIX.md
2022-09-05 17:50:56 +02:00
L. S. Leary
edf8e2526d flake.nix:
* Support comp.nix.
  * Re-order overlays and modules dependency-last for sanity.
  * Re-export `xmonad.modernise`.
NIX.md:
  * Document comp.nix.
  * Simplify example system flake, removing direct dependency on the
    xmonad flake.
  * Advise sane module ordering.
  * Include and document `modernise` workaround.
  * Clarify user-substituted `<foo>` values.
.gitignore:
  * Include nix 'result' symlink.
2022-09-05 20:57:17 +12:00
Tomas Janousek
d0d222e974 Bump version to 0.17.1.9 and prepare CHANGES.md sections 2022-09-03 16:25:12 +01:00
Tony Zorman
c688975625 CHANGES: Fix date for 0.17.1 release
Derp.
2022-09-03 16:50:41 +02:00
Tony Zorman
afd6824ce0 Bump version to 0.17.1 2022-09-03 14:54:32 +02:00
brandon s allbery kf8nh
f5de0fc764 Document WNConfig
And rearrange the documentation slightly so it makes more sense.
Also document the defaults, and clean up the existing markup a bit.
2022-08-28 01:56:32 -04:00
Tony Zorman
c701a75002 X.P.OrgMode: Require whitespace before priority
By being a bit less greedy with consuming whitespace in the date/time
parsers, we can make the `prop_{encode,decode}Preservation` properties
well-defined again.
2022-08-28 07:41:08 +02:00
Tony Zorman
f77fb802eb X.P.OrgMode: Mention more resources
Specifically, a blog post by yours truly featuring some animated GIFs,
which might be more digestible than a wall of text.
2022-08-27 12:43:28 +02:00
Tony Zorman
063d97f8d3
Merge pull request #735 from PRESFIL/x-p-unicode-unidescriptions
`X.P.Unicode`: `BS` -> `String` to support Unicode descriptions
2022-08-24 15:09:49 +02:00
PRESFIL
c187dfde4c X.P.Unicode: BS -> String to support Unicode descriptions
Switch the underlying UnicodeData data type from the current ByteString
implementation to String.  This is in order to facilitate descriptions
Unicode descriptions of the Unicode characters themselves.  We chose
String instead of Text because it does not incur an extra dependency.

Fixes: https://github.com/xmonad/xmonad-contrib/issues/733
2022-08-24 15:08:07 +02:00
Tony Zorman
766667d8fa X.U.Loggers: Make logTitlesOnScreen default to correct value
To keep the behaviour of the old code, we want to fall back to the
unfocused format here, not the identity.

Fixes: cfc6a5293537a7cd61b9992c337279df5dba7628
2022-08-24 14:55:11 +02:00
Tony Zorman
113dda4389
Merge pull request #747 from slotThe/org-mode/priorities
X.P.OrgMode: Add ability to specify priorities
2022-08-24 14:36:35 +02:00
Tony Zorman
888a1e4f12 X.P.Pass: Add note about enabling fuzzy matching
Instead of providing these as default values, as originally planned,
just add a note for users who wish to customise that part of the prompt.
We simply get the user config in mkPassPrompt and so overriding that
with a custom searchPredicate and sorter seems unwise.

Closes: https://github.com/xmonad/xmonad-contrib/issues/746
2022-08-23 21:32:34 +02:00
Tony Zorman
4d11a372c9 tests/OrgMode: Generate arbitrary priorities
Add the trivial Arbitrary instance for Priority, extend the Arbitrary
instance of OrgMsg, as well as some plumbing.  Also work in some unit
tests for regression testing.
2022-08-23 18:49:38 +02:00
Tony Zorman
68b5a12f96 X.P.OrgMode: Add ability to specify priorities
Add the ability to specify alphabetic (`#A`, `#B`, and `#C`) org-mode
priorities[1] at the end of the input note.

[1]: https://orgmode.org/manual/Priorities.html
2022-08-23 18:47:03 +02:00
Tony Zorman
ae7f615b60
Merge pull request #743 from alternateved/add-log-titles-variant
X.U.Loggers: Add variants of logTitle with urgent windows support
2022-08-21 17:23:48 +02:00
Tomasz Hołubowicz
cfc6a52935 X.U.Loggers: Add variants of logTitle with urgent windows support 2022-08-21 16:53:39 +02:00
brandon s allbery kf8nh
699d7d5002
Merge pull request #745 from geekosaur/prompt-pass-specify
Allow users to specify custom prompts
2022-08-21 10:44:33 -04:00
brandon s allbery kf8nh
996921528d
Merge branch 'master' into prompt-pass-specify 2022-08-21 10:26:36 -04:00
Tony Zorman
2ae1c86ceb
Merge pull request #744 from geekosaur/absolute-path
Use `mkAbsolutePath` in `doAppend` (XMonad.Prompt.AppendFile)
2022-08-21 06:53:53 +02:00
brandon s allbery kf8nh
2c5ea5f94a
change XMonad.Prompt.AppendFile to use mkAbsolutePath 2022-08-20 17:18:52 -04:00
brandon s allbery kf8nh
64eb4e46ec
modify mkAbsolutePath to support environment vars
If you want more general support, comment on PR #744.
2022-08-20 17:18:51 -04:00
brandon s allbery kf8nh
a7ed269a01
update CHANGES.md 2022-08-20 17:18:00 -04:00
brandon s allbery kf8nh
84f928068f
versions of pass functions with user-specified prompt
By request of a user on IRC
2022-08-20 17:18:00 -04:00
Tony Zorman
40171824cd
Merge pull request #742 from slotThe/sideborderdec
New module: XMonad.Layout.SideBorderDecoration
2022-08-19 09:54:03 +02:00
Tony Zorman
7185b28e09 New module: XMonad.Layout.SideBorderDecoration
New module that allows for having a configurable border position around
windows.  Originally found in a comment by L. S. Leary in [1].  Enough
people have requested this on IRC in recent memory to warrant a proper
module.

[1]: https://github.com/xmonad/xmonad/issues/152#issuecomment-362716434

Co-authored-by: L. S. Leary <LSLeary@users.noreply.github.com>
2022-08-19 09:43:02 +02:00
Tony Zorman
284463a172 X.U.Parser: Give (Parser a) an IsString instance when a ~ String
When the -XOverloadedStrings language extension is on, treat a string s
as the parser 'string' s, when appropriate.  This allows one to write
things like "a" *> otherParser instead of 'string' "a" *> otherParser.
2022-08-19 09:37:07 +02:00
Tony Zorman
df3d0aa057 X.U.Run: Use isPrefixOf in withEmacsLibs
The `lisp` and `elpa` lists will simply be the (unqualified) file names.
Thus, if we use isInfixOf and try to require a library with a very short
name (like s.el), other things may be chosen over it.  isPrefixOf,
together with the additional `-`, prevents this from happening.
2022-08-16 07:38:18 +02:00
Tony Zorman
ee97eec17d Remove all remaining occurences of defaultTConf
Data.Default deprecations were removed in
5140f5b5d06790e055eb7fb0cf3eccc4997aa736, yet some comments still refer
to defaultTConf—fix that.

Related: 6b4675e3fa85f95f808a95f8cad790e798cf6ad5
2022-08-03 10:06:23 +02:00
brandon s allbery kf8nh
6b4675e3fa
fix some deprecated and removed defaultTConfs 2022-08-02 19:37:18 -04:00
Tony Zorman
0934fe5cd7 X.U.Grab: Hide mkGrabs from XMonad
With [1] merged, the XMonad module from core now exports mkGrabs and
setNumlockMask (now cacheNumlockMask).  However, since we want
xmonad-contrib 0.17.1 to compile against xmonad 0.17.0 still, hide the
function for now and continue to use the vendored copies we have in
X.U.Grab currently.  We have to ignore the dodgy-imports warning when
-fpedantic is on, but that seems like a small price to pay.

A breaking change for this is planned for 0.18.0.

[1]: https://github.com/xmonad/xmonad/pull/405
2022-08-02 09:57:32 +02:00
Tony Zorman
8268cdde26
Merge pull request #736 from geekosaur/EWMH-windowDebug
print EWMH type and state in debugWindow
2022-07-29 09:10:02 +02:00
brandon s allbery kf8nh
607fdc2a12
print EWMH type and state in debugWindow 2022-07-28 10:18:11 -04:00
Yecine Megdiche
0a3fa0c3ed
Merge pull request #737 from geekosaur/bits-warning
silence warning about extraneous Data.Bits import
2022-07-26 12:39:20 +02:00
brandon s allbery kf8nh
1aad21e866
silence Data.Bits warning
I had missed that `(.&.)` was already being imported from
`XMonad.Prelude`.
2022-07-25 20:25:48 -04:00
Tomas Janousek
8da08b8848 scripts: Include xmonad{ctl,propread}.hs in the release tarball
Last year I thought a bit about making this an actual `executable` in
xmonad-contrib.cabal, but decided against it. Unfortunately I can't
remember why. So let's do the bare minimum to at least ship it now, and
if I remember or if anyone has any ideas, we can do the next step or
document why not.

Fixes: https://github.com/xmonad/xmonad-contrib/issues/734
2022-07-12 22:17:36 +01:00
Tomas Janousek
a45ecd3779 scripts: Drop obsolete grabDescriptions.hs
We haven't used this for a while, and since we dropped descriptions in
X.D.Extending in favor of the haddock-generated index in
839302533bed6c6ece709a9d8508cc9b773b3975, it's useless.
2022-07-12 22:13:31 +01:00
Tomas Janousek
820a2f75de scripts: Drop obsolete generate-configs
The last time this could work was 2007
(1e35714e1e01b1148c84076de7a5998045679a08).
2022-07-12 22:10:44 +01:00
brandon s allbery kf8nh
2a6ac58c71
change a defaultGSConfig doc to a def 2022-07-12 14:25:13 -04:00
Tomáš Janoušek
ea97c3562f
Merge pull request #732 from liskin/getppidof
X.A.SpawnOn, X.H.WindowSwallowing: Fix parsing of process PPIDs
2022-07-06 09:03:20 +01:00
Tomas Janousek
fc482b8771 X.A.SpawnOn, X.H.WindowSwallowing: Fix parsing of process PPIDs
This fixes several issues related to parsing of parent PIDs:

* A process with lines or spaces or parentheses in its process name
  would confuse the code in X.A.SpawnOn and possibly lead to a
  `Prelude.read: no parse` exception.

* `X.H.WindowSwallowing.isChildOf` looked for the parent PID anywhere in
  the output of pstree, so single-digit parent PIDs would be considered
  as parents of any process with that digit anywhere in its chain of
  parent PIDs. (Note that apps in PID namespaces like in Flatpak often
  have single-digit PIDs.)

* `pstree` is no longer required in `$PATH`.

Fixes: https://github.com/xmonad/xmonad-contrib/issues/726
2022-07-06 09:00:35 +01:00
brandon s allbery kf8nh
5557944fb6 Proper fix for alpha channel mishandling
X11 only handles alpha channels in a restricted set of APIs (such as
setting `border_color`); most others throw undocumented errors and/or
produce black pixels. Document this, and mask out alpha where it
matters.

Fixes xmonad/xmonad#395, xmonad/xmonad#398.
2022-07-05 17:34:49 -04:00
Tony Zorman
ebdb079a94
Merge pull request #727 from ilya-bobyr/master
X.H.UrgencyHook: Default for DzenUrgencyHook and UrgencyConfig
2022-07-05 08:32:35 +02:00
Illia Bobyr
3e7b22fe9b X.H.UrgencyHook: Default for DzenUrgencyHook and UrgencyConfig
As the XMonad config is commonly customized by saying

    def { startupHook = ...
        , manageHook = ...
        , ...
        }

It seems consistent to allow the same for an individual hook config:

    let urgencyHook = def { suppressWhen = ...
                          , remindWhen = ...
                          }
2022-07-05 08:28:59 +02:00
Tony Zorman
839bc907ba
Merge pull request #730 from slotThe/nsp-fix
X.U.NamedScratchpad: Initialise if necessary
2022-07-03 13:32:20 +02:00
Tony Zorman
7a33639aaa X.U.NamedScratchpads: Fill NSPState when necessary
Since 3fc830aa09368dca04df24bf7ec4ac817f2de479, scratchpads are now
added in namedScratchpadManageHook.  This, however, means that we need
some kind of MapRequestEvent to happen before processing scratchpads,
otherwise the manageHook didn't run yet and our extensible state is
being left empty.  When trying to open a scratchpad right after starting
xmonad—i.e., before having opened a window—this may not be the case.

Fixes: https://github.com/xmonad/xmonad-contrib/issues/728
2022-07-03 12:24:44 +02:00
Tony Zorman
a4c73ad090
Merge pull request #729 from slotThe/modal-fixups
X.H.Modal: Add EZConfig support
2022-07-02 17:28:00 +02:00
Tony Zorman
8ddc1f48e2 X.H.Modal: Update documentation
Now that we use a slightly different setup, as well as EZConfig support,
rewrite the introduction to the module a little.
2022-07-02 17:27:33 +02:00
Tony Zorman
fe337dc6b0 X.H.Modal: Add support for EZConfig-style bindings
Add support for EZConfig-style bindings while also maintaining some
guarantees as to which type of representation we will store in the
extensible state.  This means that parsing of the keys will happen no
later than the call to `modal`.

Users can choose to use `mkKeysEz` or `mkKeysFun` to create a new
collection of keys to bind for a mode.  This is deemed more ergonomic
than exporting the respective constructors directly.
2022-07-02 17:27:33 +02:00
Tony Zorman
87a36d7d31 X.H.Modal: Cleanup
Mostly small things, like making imports line up with the provided
comments.  Also:

+ Rename mode' -> modeWithExit.  This seems like a better name for
  discoverability reasons.

+ Make the fields of Mode strict, because they have no reason not to,
  really.
2022-06-29 15:00:40 +02:00
Yecine Megdiche
0891575518 New module: XMonad.Hooks.Modal
Based on the draft by L. S.
Leary.  (https://gist.github.com/LSLeary/6741b0572d62db3f0cea8e6618141b2f).
2022-06-28 22:27:29 +02:00
Yecine Megdiche
8b2594a526 New Module: XMonad.Util.Grab
Based on the draft by L. S.
Leary.  (https://gist.github.com/LSLeary/6741b0572d62db3f0cea8e6618141b2f).
2022-06-28 22:27:29 +02:00
brandon s allbery kf8nh
6e1a1fe0df
Stray def in additionalNav2DKeysP documentation 2022-06-24 19:47:14 -04:00
Tony Zorman
4287bab252 XMonad.Util.Run: Add quote
This is quite convenient in arguments; e.g.,

    progn [ "fun1" <> asString "string"
          , "fun2" <> quote "symbol"
          ]
2022-06-22 17:23:45 +02:00
Tony Zorman
2643528945
Merge pull request #725 from emptyflask/emptyflask/centered-if-single
CenteredIfSingle allow resizing in both dimensions
2022-06-21 13:22:29 +02:00
Jon Roberts
accea5b1d8 X.L.CenteredIfSingle: Allow specifying ratio in both dimensions
While monitors are, more often than not, wider than they are high,
specifying a ratio in the vertical direction can also make sense; e.g.,
when flipping a monitor by 90 degrees.  Thus, we should definitely
support both.
2022-06-21 13:16:50 +02:00
Tomas Janousek
0d5a952035 ci: Prevent scheduled workflows from being auto-disabled by GitHub 2022-06-19 17:14:24 +01:00
brandon s allbery kf8nh
f998cc2d2e Complete #708 by updating _NET_SUPPORTED. 2022-05-29 20:24:47 -04:00
Tony Zorman
a88d6328fe
Merge pull request #718 from slotThe/spawn-external
Extend X.U.Run with an EDSL for spawning processes
2022-05-24 08:18:57 +02:00
Tony Zorman
b6be0dca40 X.U.Run: Add examples to Haddocks 2022-05-23 20:12:57 +02:00
Tony Zorman
e466d9b1dc X.Prelude: Add mkAbsolutePath 2022-05-23 20:12:57 +02:00
Tony Zorman
473dc41afb X.U.Run: Improve and add documentation
This adds documentation for the new EDSL, as well as small fixes to
existing docs.

Importantly, I've added myself as a maintainer of the file (even though
we don't really care about this at this point) and updated the
copyright; the changes seem large enough to warrant this.
2022-05-23 20:12:57 +02:00
Tony Zorman
2b48f3ff09 X.U.Run: Add an EDSL to spawn external programs
Extend X.U.Run with an EDSL for spawning (external) processes.  For
example:

    do url <- getSelection  -- from XMonad.Util.XSelection
       proc $ inEmacs
          >-> withEmacsLibs [ElpaLib "dash", ElpaLib "s", OwnFile "arXiv-citation"]
          >-> asBatch
          >-> execute (elispFun $ "arXiv-citation" <> asString url)

is essentially equivalent to (line breaks mine)

    /usr/bin/sh -c "emacs -L /home/slot/.config/emacs/elpa/dash-20220417.2250
                          -L /home/slot/.config/emacs/elpa/s-20210616.619
                          -l /home/slot/.config/emacs/lisp/arXiv-citation.el
                          --batch
                          -e '(arXiv-citation \"<url-in-the-primary-selection>\")'"
2022-05-23 20:11:29 +02:00
brandon s allbery kf8nh
67243cbf7c
the rest of the fix for #719
It's just two more exports.
2022-05-08 09:27:56 -04:00
brandon s allbery kf8nh
41674386a6
Export shrinkText
Closes #719.
(This being a trivial one-line change and the description being already bigger than the change, I'm committing it directly.)
2022-05-08 09:06:18 -04:00
Tony Zorman
616222c9f0 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:39:19 +02:00
Tony Zorman
21e613e242
Merge pull request #717 from Pachin0/desktop-viewport
X.H.EwmhDesktops: Add `_NET_DESKTOP_VIEWPORT` support
2022-05-06 08:51:33 +02:00
Jose Antonio Martinez Vidaurre
2291d3a009 X.H.EwmhDesktops: Add _NET_DESKTOP_VIEWPORT support
Some panels—such as polybar—require _NET_DESKTOP_VIEWPORT support in
order to know which workspace is on which monitor.  They are then able
to only show workspaces defined on the same output as the bar with just
X11 properties.

Fixes: https://github.com/xmonad/xmonad-contrib/issues/708
2022-05-06 08:12:13 +02:00
Tony Zorman
6c787204aa Update my name 2022-05-05 21:07:27 +02:00
Tony Zorman
4a982e54c9
Merge pull request #711 from LSLeary/flake-module
Apply Patch in Nix Flake; Enable Configuration (Contrib Edition)
2022-05-04 20:53:31 +02:00
L. S. Leary
6ab69e97d3 NIX.md: Document the NixOS modules provided by the core and contrib flakes.
flake.nix: Assume maintainership.
2022-05-04 19:20:13 +12:00
Tony Zorman
0e14e13845
Merge pull request #716 from johnli360/master
Replace <+> with <>
2022-05-02 17:52:01 +02:00
John Lind
a7fd31d233 Replace <+> with <> 2022-05-02 08:28:36 +02:00
Tomas Janousek
3adb47235f Apply hlint 3.4 hints 2022-05-02 00:06:59 +01:00
Tomas Janousek
154388aa20 ci: Drop hlint -XCPP workaround
https://github.com/ndmitchell/hlint/issues/1360 is fixed and the fix
released.
2022-05-01 23:25:08 +01:00
Tony Zorman
716c634dc9
Merge pull request #715 from Ahanaf-Ether/master
X.A.PerLayoutKeys: Fix typo
2022-05-01 08:51:03 +02:00
Ether
51907ad59e X.A.PerLayoutKeys: Fix typo 2022-05-01 08:49:54 +02:00
L. S. Leary
fa498ca728 flake.nix: Provide a NixOS module corresponding to that of the
xmonad (core) flake.
2022-04-25 02:02:11 +12:00
L. S. Leary
b4b4d9b7c8 flake.nix: Expose hoverlay for use with fromHOL. 2022-04-25 01:51:24 +12:00
L. S. Leary
12cd1b9c6e flake.nix: Erase the noise with xmonad.lib.fromHOL. 2022-04-25 01:38:39 +12:00
Tomas Janousek
0e106ccfbe 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:39:01 +02:00
brandon s allbery kf8nh
b6d62fe9d3 migrate build scripts from xmonad-testing
The testing repo was not a good location for them, and is now
deprecated. They are now in `scripts/build`, and will be documented
in the main repo's `INSTALL.md`.
2022-04-18 17:30:51 -04:00
Tony Zorman
965c4052fb
Merge pull request #705 from kozlov721/repeat-action
added Actions.RepeatAction
2022-04-17 10:37:29 +02:00
Martin Kozlovsky
3f590b86c6 New module: XMonad.Actions.RepeatAction
Closes: https://github.com/xmonad/xmonad-contrib/issues/489
2022-04-17 10:25:47 +02:00
brandon s allbery kf8nh
80776d8969 buggy boolean blindness
`ManageDebug` was continuing to report in the `logHook` even after
the `manageHook` was done. In diagnosing this, I discovered that
the original code was using a tuple of `Bool`s and not even a
comment about which meant what.

The code now uses a proper pair type, and dedicated `data`s for
the two flags that make it clear what each means. This also fixed
the bug, so apparently I had the `Bool`s confused somewhere.

I also took the chance to clarify the documentation a little (a
misleading "persistent", since it doesn't use persistent XS) and
a few more cleanups. Also, it now logs all `manageHook` runs
before the `logHook` in case multiple windows are opened.
2022-04-15 14:17:50 -04:00
Tony Zorman
923c5a2548
Merge pull request #704 from amenonsen/master
Fix missing prompt configuration in DynamicProjects example
2022-04-12 09:06:27 +02:00
Abhijit Menon-Sen
cf3a2be6d9 Fix missing prompt configuration in DynamicProjects example 2022-04-12 12:25:44 +05:30
Yecine Megdiche
b7799c1e5b
Merge pull request #701 from PRESFIL/fix-synopsis-typo
Fix synopsis typo
2022-04-09 10:18:14 +02:00
PRESFIL
f43bd08728
Fix synopsis typo
Removes a repeating word in a package synopsis
2022-04-09 10:05:38 +03:00
brandon s allbery kf8nh
0833c347e7 Missed a reference to bindOn
The perils of making 1-line changes to another module….

Co-authored-by: Tomáš Janoušek <tomi@nomi.cz>
2022-04-06 13:13:55 -04:00
brandon s allbery kf8nh
84caf89894 new module XMonad.Actions.PerLayoutKeys 2022-04-06 13:13:55 -04:00
slotThe
78dce3d85b X.U.NamedScratchpad: Fix docs regarding dynamic NSPs
The documentation and usage example still had the old names.

Related: https://github.com/xmonad/xmonad-contrib/issues/699
2022-04-05 16:13:08 +02:00
Tomáš Janoušek
737f8040cb
Merge pull request #694 from slotThe/ci/update-ghcs
ci: Update supported GHC versions
2022-04-05 12:31:27 +01:00
slotThe
e3ffbf63f6 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, which ships with GHC 9.0.2.
+ Since a new version of 9.2 has been released, prefer 9.2.2 over 9.2.1.

Also, explicitly pass -XCPP to hlint; see [1].

[1]: https://github.com/ndmitchell/hlint/issues/1360
2022-04-05 12:18:12 +01:00
Tony Zorman
533e17135e
Merge pull request #690 from slotThe/scratchpads
X.U.NamedScratchpads: Add dynamic scratchpad capabilities
2022-04-01 08:40:37 +02:00
slotThe
4c350b9a65 X.U.NamedScratchpad: Use a map for internal state 2022-04-01 08:28:55 +02:00
slotThe
bc2aaf41af X.U.DynamicScratchpads: Deprecate 2022-04-01 08:28:55 +02:00
slotThe
f6334b6af6 X.U.NamedScratchpad: Create a `Deprecations' section
Since users should not use these functions, anyways, separating them out
seems like a good idea.  Plus, one now does not need to scroll over them
to get to the dynamic scratchpad functionality (people may stop when
seeing "DEPRECATED" signs everywhere).
2022-04-01 08:28:55 +02:00
slotThe
bf064710d0 X.U.NamedScratchpad: Add support for dynamic scratchpads
With the extensible state machinery in place[1], we are now able to
seamlessly integrate dynamic scratchpad functionality into
X.U.NamedScratchpad.  This is one step into the direction of having a
single scratchpad implementation that can "do anything".

Related: https://github.com/xmonad/xmonad-contrib/issues/591
Related: https://github.com/xmonad/xmonad-contrib/pull/662

[1]: 70d08b82f43057447e8e2479aa515b6db0d199e4
     (X.U.NamedScratchpad: Use ExtensibleState to store scratchpads)
2022-04-01 08:28:55 +02:00
slotThe
3fc830aa09 X.U.NamedScratchpad: Use ExtensibleState to store scratchpads
Instead of using the scratchpads that the user specifies (as this will
realistically just be "all of them"), create some extensible state for
the scratchpads to reside in.

To ensure that this is done in a backwards compatible way, function
signatures did not change and they instead just ignore the list of
scratchpads given to them and the initialisation is done in the
manageHook, which users already have to use anyways.
2022-04-01 08:28:55 +02:00
Tony Zorman
0f788a9d92
Merge pull request #697 from xmonad/696-add-SessionStart-ref
Have `X.U.SpawnOnce` point to `X.U.SessionStart`
2022-03-25 08:07:00 +01:00
brandon s allbery kf8nh
fad1411995
Have X.U.SpawnOnce point to X.U.SessionStart
Just a simple doc change, but should make `X.U.SessionStart` more discoverable.

Closes #696.
2022-03-24 20:18:49 -04:00
Tony Zorman
8693654bdd
Merge pull request #695 from a5ob7r/fix_typo_in_doc
Fix typo on the 'XMonad.Hooks.Rescreen' doc
2022-03-23 20:18:27 +01:00
a5ob7r
9128342f25 Fix typo on the 'XMonad.Hooks.Rescreen' doc 2022-03-22 11:21:53 +09:00
slotThe
8a28fbb29e cabal: Remove NIX.md from extra-source-files
We do not ship the nix flake in the release tarball, so it does not make
sense to include NIX.md in there either; at least for now.

Fixes: 4ca46c24148062064d266f85acac973de07aae24 (Add NIX.md)
2022-03-14 20:22:12 +01:00
slotThe
dcd5918d3a X.L.ThreeColumns: Resize screenshot
Fixes: https://github.com/xmonad/xmonad-contrib/issues/530
2022-03-06 20:23:15 +01:00
Tony Zorman
974c10dca7
Merge pull request #589 from IvanMalison/customizableNixDevelop
Provide a mechanism by which users can customize the nix devShell
2022-03-06 18:21:12 +01:00
slotThe
4ca46c2414 Add NIX.md
There are multiple ways one could use XMonad with nix, so a separate
file for documenting all of this seems appropriate.  E.g., when it
contains the respective installation instructions (e.g, "normally" as
instructed in the NixOS wiki, via stack, via flake, ...) we could link
to it from INSTALL.md.

For now it's a good place to document the new `develop.nix`
functionality.

Co-authored-by: Ivan Malison <IvanMalison@gmail.com>
2022-03-05 09:50:58 +01:00
Ivan Malison
f1ea1e533d Provide a mechanism by which users can customize the nix devShell 2022-03-05 09:50:58 +01:00
Tony Zorman
ca25b36aa0
Merge pull request #689 from slotThe/X.H.ShowWName
Add XMonad.Hooks.ShowWName
2022-02-28 08:55:59 +01:00
slotThe
fba22a7366 Add XMonad.Hooks.ShowWName
This is a reimplementation of X.L.ShowWName as a logHook, using the new
simpleWindow interface from 86b816ec5046ec09b911d48df282b7039a201dfc.

Fixes: https://github.com/xmonad/xmonad-contrib/issues/612
2022-02-28 08:53:22 +01:00
Yecine Megdiche
6a46ff449f
Merge pull request #684 from TheMC47/feature/workspace-screen
Export `WindowScreen` type and add a new module: `X.H.WorkspaceScreen`
2022-02-24 20:08:00 +01:00
Yecine Megdiche
eb8da2dcb2 New Module: XMonad.Hooks.WorkspaceScreen
In a multi-head setup, it might be useful to have screen information of the
visible workspaces combined with the workspace name, for example in a status
bar. This module provides utility functions to do just that.
2022-02-24 20:00:46 +01:00
Yecine Megdiche
2d33f18dec XMonad.Prelude: add the WindowScreen type
`WindowScreen` is a type synonym for the specialized `Screen` type, that
results from the `WindowSet` definition in XMonad.Core. Having this type
defined and exported in a central module saves extension developers from
trying to reconstruct it, whenever the general `Screen i l a sid sd` is
not suitable.

Note: this should be moved to `XMonad.Core` in the next core release.
2022-02-24 20:00:46 +01:00
Tomáš Janoušek
d2b174f269
Merge pull request #688 from liskin/dynamic-workspaces-nub-refresh-loop
X.H.ManageDocks: Avoid unnecessary refresh (loop) for decorations

This started as an investigation of the root cause of
<https://github.com/xmonad/xmonad-contrib/issues/565>, which was
addressed by <https://github.com/xmonad/xmonad-contrib/pull/621> without
having a full understanding of why xmonad ends up in a busy loop.

What was going on:

* X.L.SubLayouts group update algorithm assumes no duplicities in the
  Stack, and results in multiplying those duplicities otherwise. Note
  that this is a reasonable assumption—duplicities in a Stack have no
  defined behaviour in xmonad (X11 can't place a window on a screen
  twice), so "fixing" this algorithm is a waste of time.

* X.L.Decoration creates windows which X.H.ManageDocks treats as
  possible docks, resulting in extra refresh whenever they appear.

* The extra refresh causes X.L.SubLayouts to multiply the duplicities,
  X.L.Decoration to create new decoration windows, and these invalidate
  the X.H.ManageDocks strut cache, leading to yet another refresh, and
  an endless loop of these.

Having concluded that the no-duplicities assumption is a reasonable one,
there's nothing really to fix here after
<https://github.com/xmonad/xmonad-contrib/pull/621>. Still, the extra
refresh might be causing extra flicker in decorated layouts, and we can
easily avoid it, so I do that here. Plus a bit of documentation for
X.L.SubLayouts.
2022-02-20 18:24:59 +00:00
Tomas Janousek
253b952814 X.L.SubLayouts: Document assumptions/pre-conditions of toGroupStack
This started as an investigation/fix of xmonad freezing when a bug in
X.A.DynamicWorkspaces caused duplicate Windows in a single Workspace
Stack, but I soon(-ish) realized that trying to make SubLayouts robust
enough to handle duplicities in a Stack is futile. Any code that creates
duplicities in a Stack is buggy, and must be fixed; the rest can assume
there aren't any.

Instead, let's just document that this is a pre-condition, and that (and
how) stuff will misbehave.

Related: https://github.com/xmonad/xmonad-contrib/issues/565
2022-02-20 18:22:19 +00:00
Tomas Janousek
a6c048899c X.L.SubLayouts: Use ScopedTypeVariables as intended years ago
We don't need to support GHC 6.8.2 any more. :-)
2022-02-20 18:22:19 +00:00
Tomas Janousek
6a6e4bcce8 X.H.ManageDocks: Avoid unnecessary refresh (loop) for decorations
Windows created by X.U.XUtils.createNewWindow have _NET_WM_WINDOW_TYPE =
_NET_WM_WINDOW_TYPE_DESKTOP, which caused checkDock to match them and an
UpdateDocks event to be sent, causing an additional layout refresh
whenever a decoration window appeared.

This could in theory lead to a refresh loop with a layout (modifier)
that dropped and recreated its decoration windows on every
runLayout—which isn't entirely unreasonable, X.L.MouseResizableTile does
it, just luckily happens to not mark its windows as
_NET_WM_WINDOW_TYPE_DESKTOP.

In practice, such a refresh loop could be triggered when buggy
X.A.DynamicWorkspaces (before 929a6a3f6f) duplicated a Window in a
single workspace's Stack, and buggy X.L.SubLayouts then kept duplicating
the duplication (2 → 4 → 8 → …), triggering the creation of new
decoration window in each iteration.

Fixes: https://github.com/xmonad/xmonad-contrib/issues/565
2022-02-20 18:22:19 +00:00
slotThe
e98d666447 X.U.XUtils: Fix alignment in showSimpleWindow 2022-02-19 11:52:44 +01:00
Tony Zorman
ee3ea2402d
Merge pull request #685 from slotThe/ezconfig-property-tests
X.U.EZConfig: Add property tests
2022-02-13 16:16:54 +01:00
slotThe
153d46fd90 tests: Add property tests for X.U.EZConfig
Adds property tests in both directions for the parser in X.U.EZConfig.
As with the tests for X.P.OrgMode, these (modulo `Maybe` noise) take the
shape of the operation of an inverse semigroup:

    pp ∘ p ∘ pp ≡ pp        and        p ∘ pp ∘ p = p,

where pp is pretty-printing and p is parsing.
2022-02-13 15:00:21 +01:00
slotThe
7d91a1bf85 X.Prelude: Improve keyToString output
The keysymToString function prints the key names in pure ASCII; e.g.,
`keysymToString 250` returns "uacute" instead of "ú".  This is
undesirable when printing these keysyms in places like visualSubmap.

Thus, move all of the key infrastructure (heh) from X.U.EZConfig to
X.Prelude and look up the name of the key if possible.  For better
composability, slightly change the signature for `regularKeys` and the
associated parser.
2022-02-13 14:49:02 +01:00
slotThe
e6b50c5dd6 X.Prelude: Concat modifier keys instead of unwording
Instead of printing "M- S- C-", print "M-S-C".
2022-02-13 14:46:23 +01:00
Tomáš Janoušek
493b6adbc4
Merge pull request #686 from liskin/keypress-fixes
X.{A.{{Grid,Tree}Select,Submap},Prompt}: KeyPress handling fixes
2022-02-13 10:22:54 +00:00
Tomas Janousek
1b728ff96a CHANGES: Document the key bindings changes 2022-02-10 15:01:10 +00:00
Nikolay Yakimov
68c967ec0c X.A.{Grid,Tree}Select, X.Prompt: Fix keybindings like Shift-Tab and similar
This changes KeyPress handling in these modules to behave much closer to
how xmonad core itself handles keypresses. The primary difference lies
in that xmonad reads raw KeyCode and then converts it to unmodified
KeySym, while these modules used `lookupString` to find the actual
keysyms. As a consequence, key definitions like `(shiftMap, xK_Tab)`
didn't work on many layouts because an actual KeySym for `Shift-Tab` is
commonly `ISO_LEFT_TAB`, and not `Tab`.

Closes: https://github.com/xmonad/xmonad-contrib/pull/590
Co-authored-by: Tomas Janousek <tomi@nomi.cz>
2022-02-10 14:42:23 +00:00
Tomas Janousek
12c5518852 X.A.Submap, X.Prompt: Use cleanKeyMask
This replaces the custom `cleanMask` extension in these modules—which
only filtered out XKB group bits and Button5Mask¹—with the new
`cleanKeyMask` which additionally filters out all mouse buttons, as
these aren't relevant for key bindings.

¹) Filtering out Button5Mask was probably an off-by-one mistake.

Fixes: https://github.com/xmonad/xmonad-contrib/issues/290
Related: https://github.com/xmonad/xmonad-contrib/pull/590
2022-02-10 14:23:01 +00:00
Tomas Janousek
adced0a8c8 X.A.{Grid,Tree}Select: Fix keybindings in secondary kbd layouts
We didn't clean XKB group bits out of the KeyPress events' state so key
bindings only worked in the primary keyboard layout (first XKB group).
To fix this, this adds a `cleanKeyMask` function to X.Prelude which is
analogous to `cleanMask` but aimed at cleaning regular KeyPress states
(as opposed to just KeyPresses from passive key grabs), and this is then
used instead of `cleanMask`.

Related: https://github.com/xmonad/xmonad-contrib/issues/290
Related: https://github.com/xmonad/xmonad-contrib/pull/590
2022-02-09 23:53:16 +00:00
Tomas Janousek
2e3254a908 X.H.Rescreen: Catch exceptions in user-provided hooks in add*Hook
This way a single failing hook won't disturb other hooks (not just
rescreen hooks, also other event hooks).
2022-02-03 11:53:54 +00:00
Tomas Janousek
7445390432 X.H.Rescreen: Improve usage doc (recommend add*Hook)
There's no reason (other than me forgetting to update the docs when
these add-Hooks were added) to steer users towards the ugly record-based
low-level API.
2022-02-03 11:49:34 +00:00
Tony Zorman
a49b664276
Merge pull request #680 from slotThe/visual-submap
X.A.Submap: Add `visualSubmap`
2022-02-03 09:38:13 +01:00
slotThe
cf1d966ee6 X.A.Submap: Add visualSubmap
Add a `visualSubmap` function, which works much like the regular
`submap` one, except that it visualises the available choices in a
pop-up window.

Related: https://github.com/xmonad/xmonad-contrib/issues/472
2022-02-03 08:53:33 +01:00
slotThe
86b816ec50 X.U.XUtils: Add framework for manipulating simple windows
Adds several new functions and type for manipulating "simple windows".

There are several ways to draw windows in X.U.XUtils and other places
already, but they are all quite manual.  Most of the time one does not
want to think about dimensions much and assumes that the code is smart
enough to "figure it out"; this is an attempt to do exactly that.

There is a less-managed version `showSimpleWindow`, which just creates
and shows the windows, as well as a wrapper-like `withSimpleWindow` that
also destroys the window once some action finishes executing.

With these functions it should be possible to refactor some contrib
modules that currently draw windows manually, like X.U.EasyMotion.
2022-02-03 08:53:22 +01:00
slotThe
505577b755 X.Prelude: Add keymaskToString, keyToString
This technically introduces a regression with regards to the way that
modifier masks are printed in X.U.NamedActions and X.H.DebugEvents.
However, since this way of printing masks is move in line with
X.U.EZConfig, I personally don't think that this is noteworthy.
2022-02-03 08:53:22 +01:00
Tomas Janousek
54095f5420 X.U.Hacks: Clean up tray padding hooks a bit
Un-export trivial/useless definitions and adapt the generic versions of
trayerPaddingXmobarEventHook to be more generally useful.

Related: https://github.com/xmonad/xmonad-contrib/pull/643#issuecomment-962661655
2022-02-01 19:17:30 +00:00
Tomas Janousek
d71856431a CHANGES: Fix formatting of the VoidBorders entry 2022-02-01 19:16:13 +00:00
Tomáš Janoušek
ae9b9c43a4
Merge pull request #682 from rayes0/master
X.L.VoidBorders: Add ability to reset borders for certain layouts
2022-02-01 18:39:57 +00:00
Tomas Janousek
c4d718be9a X.L.VoidBorders: Improve doc a bit 2022-02-01 18:39:33 +00:00
rayes
a3012eaa27 X.L.VoidBorders: Add ability to reset borders for certain layouts 2022-01-30 21:07:46 -07:00
slotThe
741d90eb9b X.P.Man: Use System.FilePath
Instead of hand-written functions, just use what's already provided by
filepath.
2022-01-30 10:20:04 +01:00
slotThe
c36a888a59 X.P.FuzzyMatch: Use isSubsequenceOf
The implementation is exactly the same, just that this function is now
in base, so there should be no change in behaviour.
2022-01-30 10:20:04 +01:00
Tony Zorman
56cc296754
Merge pull request #643 from tulth/trayerResizeHook
add to hacks: rough draft trayer resize event hook
2022-01-21 09:30:46 +01:00
tulthix
4d24193baa X.U.Hacks: Add tray(er) event hooks
Adds event hooks to communicate with trayer or, more generally, with
other tray programs.  For convenience, a standard query for trayer is
also provided.
2022-01-21 09:16:28 +01:00
slotThe
de886d6182 CHANGES: Remove Bluetile from deprecated modules
Was undeprecated in 981166a2ab618f65367befa3379ff2aadf00f27c.
2022-01-17 18:33:22 +01:00
Tomas Janousek
201a14718e X.A.GroupNavigation, X.H.WorkspaceHistory: Leak fix cleanups
Simplify stuff a bit. Prevent memory leaks additionally in:
`workspaceHistoryTransaction` and `workspaceHistoryModify`.

Related: https://github.com/xmonad/xmonad-contrib/pull/653
2022-01-15 19:12:32 +00:00
Tomas Janousek
981166a2ab Un-deprecate X.C.Bluetile
This one isn't actually a personal configuration, it's more like
X.C.Desktop and the other desktop-specific configs. As I happen to
sometimes use it for testing whether everything still works with
decorated layouts, it shouldn't be considered abandoned.

Related: https://github.com/xmonad/xmonad-contrib/pull/679
2022-01-15 18:23:59 +00:00
Tomas Janousek
2b5d2c5ab8 X.U.ActionQueue: Separate ExtState and ExtConf data types
Using the same type for both is confusing and requires a bogus Semigroup
instance.
2022-01-15 13:43:16 +00:00
Tomas Janousek
50527a4613 X.H.BorderPerWindow: Improve module synopsis 2022-01-15 13:43:16 +00:00
Tomas Janousek
20753c1bdb flake.nix: Use upstream gitignore.nix instead of Ivan's fork 2022-01-15 12:24:03 +00:00
Tomas Janousek
756d73c78c Merge branch 'mikenrafter/master' 2022-01-15 12:23:22 +00:00
Tony Zorman
f90e76248f
Merge pull request #679 from slotThe/deprecate-modules
Deprecate user and abandoned modules
2022-01-14 07:55:52 +01:00
slotThe
478393fb7d Deprecate user and abandoned modules
Now that the user configs are on the website, it is time to deprecate
them.  At the same time deprecated X.C.Monad, which hasn't been updated
since 2008 and X.C.Prime, which has confused users quite recently,
thinking it to be a better starting place.

Fixes: https://github.com/xmonad/xmonad-contrib/issues/677
Fixes: https://github.com/xmonad/xmonad-contrib/issues/595
Related: https://github.com/xmonad/xmonad-web/pull/49
2022-01-14 07:58:18 +01:00
Mike Nrafter
77ba202548 Fixed flake.nix's use of GitIgnore. 2022-01-12 20:02:33 -07:00
Tony Zorman
41ca79986b
Merge pull request #676 from exorcist365/master
X.A.FloatKeys: Export ChangeDim
2022-01-08 09:05:51 +01:00
exorcist365
be1201cdeb X.A.FloatKeys: Export ChangeDim
Haddock displays exported types in a much nicer way.
2022-01-08 09:06:00 +01:00
brandon s allbery kf8nh
aad8a3a865
Missed a reference to the old SP workspace 2022-01-06 08:10:02 -05:00
slotThe
0a6048c66d X.U.EZConfig: Force readKeySequence to consume the whole input
When users specify non-existent keys, it seems most intuitive to just
abort the parse and not try to take the "longest" input that still
works.  For example, given the "key" `M-10` we should signal a parse
error (by returning `Nothing`) instead of parsing `M-1` and ignoring
the rest of the input.  The old EZConfig parser accounted for this but
when the module was rewritten to use X.U.Parser in [1], this was
forgotten about.

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

[1]: 8abeb81fd0693bd4ee914b522c0a2a2cfcfaf0dd
2022-01-05 15:06:17 +01:00
Yecine Megdiche
28d86f3a28
Merge pull request #675 from afreakk/patch-1
keysMoveWindow: change signature type D to ChangeDim in XMonad.Actions.FloatKeys
2022-01-03 11:08:42 +01:00
slotThe
324fdd802a tests: Fix typos in prop names 2022-01-03 08:59:41 +01:00
afreakk
7bcd81a7e9 keysMoveWindow signature D -> ChangeDim 2022-01-02 20:41:43 +01:00
Yecine Megdiche
5cc2db4a9a
Merge pull request #674 from TheMC47/minimize-haddock-formatting
X.A.Minimize: fix formatting
2022-01-01 23:12:16 +01:00
Yecine Megdiche
be6530808f X.A.Minimize: fix formatting 2022-01-01 17:55:51 +01:00
Tony Zorman
a17e2904dd
Merge pull request #671 from SimSaladin/simsaladin/minimize-improvements-rebased
X.L.BinarySpacePartition: Ignore minimized windows
2021-12-31 10:51:22 +01:00
Tony Zorman
3389241adb
Merge pull request #673 from slotThe/org-mode-parser
X.P.OrgMode: Update parser tests
2021-12-31 10:02:29 +01:00
slotThe
2e74c62be7 tests: Check for inverse semigroup property in OrgMode parser
Ever since [1] we allow a second representation for the month (namely,
the numerical one).  Since we lose this information during parsing,
pretty printing is now not a proper postinverse of parsing (it still is
a proper preinverse, however).

Thus, we can't simply check for an inverse anymore.  However, the
operations still form an inverse semigroup [2], which is something
that's easily checkable.  For simplicity, do this in both directions and
completely forget about linearity for now.

[1]: 91f1a0de1e4a536e6c81a3de96e566622b3eb20a (Fix date parsing issue
                                               for org mode plugin)
[2]: https://en.wikipedia.org/wiki/Inverse_semigroup
2021-12-31 09:55:49 +01:00
slotThe
4f048fb563 X.P.OrgMode: Check num validity while parsing
There are a lot of times when we could already check for "valid" input
during parsing instead of relaying possibly incorrect dates and times to
`org-mode`.  This seems like a sensible thing to do—I don't think anyone
would ever want to schedule anything for 35:90 :)
2021-12-31 09:55:49 +01:00
Sibi Prabakaran
0f8b3616b2
Merge pull request #672 from xmonad/org-mode-date-parsing-fix
Fix date parsing issue for org mode plugin
2021-12-29 23:30:48 +05:30
Sibi Prabakaran
66fb59e934
Update pfail to empty 2021-12-29 23:20:30 +05:30
Sibi Prabakaran
f47ed83462
Update changes.md 2021-12-29 15:02:47 +05:30
Sibi Prabakaran
91f1a0de1e
Fix date parsing issue for org mode plugin
This patch fixes the date parsing issue currently when an entry like
`todo +d 22 01 2022` is used. I have added tests too which demonstrate
the current issue so that we can prevent future regression.
2021-12-29 14:58:46 +05:30
Samuli Thomasson
508586bf44
X.L.BinarySpacePartition: Ignore minimized windows
Hidden windows are now ignored by the layout so that hidden windows in
the stack don't offset position calculations in the layout.

Also in X.H.ManageHelpers: added `isMinimized`
2021-12-28 22:33:52 +01:00
Tony Zorman
769e5f9c94
Merge pull request #670 from rdiaz02/withWorkspace-fuzzyMatch
X.A.DynamicWorkspaces.withWorkspace: honor custom search predicate
2021-12-28 14:04:07 +01:00
ramon diaz-uriarte (at Phelsuma)
540635fe1c X.A.DynamicWorkspaces: Honor searchPredicate in withWorkspace
If the user's prompt configuration has a custom `searchPredicate` (e.g.,
`X.P.FuzzyMatch.fuzzyMatch`) the `withWorkspace` prompt should make use
of it (instead of defaulting to an `isPrefixOf`-style matching).  For
details see

    https://mail.haskell.org/pipermail/xmonad/2021-December/015491.html
2021-12-28 14:00:52 +01:00
Tony Zorman
4d387bbfc9
Merge pull request #667 from geekosaur/664-spawnonce-documentation
document need for `manageSpawn` in `SpawnOnce`
2021-12-27 17:30:46 +01:00
brandon s allbery kf8nh
125c945cc9 X.U.SpawnOnce: Document need for manageSpawn
Also, reexport `manageSpawn` for convenience.
2021-12-27 17:31:54 +01:00
Tony Zorman
adeb27dc69
Merge pull request #666 from geekosaur/665-spacing-avoidstruts-documentation
Document interaction of `avoidStruts` with the screen rectangle
2021-12-23 09:52:41 +01:00
brandon s allbery kf8nh
d65cf05369 warn about using avoidStruts with gap modifiers 2021-12-22 16:41:30 -05:00
brandon s allbery kf8nh
2cf0a10f5b warn about use of avoidStruts with spacing modifiers 2021-12-22 16:38:11 -05:00
brandon s allbery kf8nh
a67be39673 document that avoidStruts must be applied before any modifier that
changes the screen rectangle
2021-12-22 16:27:21 -05:00
Tony Zorman
0010735aca
Merge pull request #659 from slotThe/x.u.parser
New Module: XMonad.Util.Parser
2021-12-17 12:13:02 +01:00
slotThe
520c51817a X.U.EZConfig: Add simple unit tests
Add very basic unit tests for EZConfig to see if it can parse all of the
keys (and key combinations) that it promises to parse.

The long-term goal here should be to write a pretty-printer for EZConfig
and to check whether that's a proper inverse (either in the normal sense
or in the inverse semigroup sense), as the tests for X.P.OrgMode do.
2021-12-13 16:11:57 +01:00
slotThe
8abeb81fd0 X.U.EZConfig: Use X.U.Parser
Using X.U.Parser works almost as a drop-in replacement for ReadP here.
In some places (like `parseSpecial`) we need to be a little bit more
careful when constructing the parser, but this is offset a much simpler
`readKeySequence`.
2021-12-13 16:11:57 +01:00
slotThe
b1532e666f X.P.OrgMode: Use X.U.Parser
Since we now have an "internal" parser library in xmonad, use it.  This
allows us to get rid of some hacks in this module that were needed
because of ReadP's parsing behaviour.
2021-12-13 16:11:57 +01:00
slotThe
8b3df5b268 New module: XMonad.Util.Parser
This module provides a parser combinator library based on base's ReadP,
which aims to function more like other popular combinator libraries like
attoparsec and megaparsec.

In particular, the Alternative and Monoid instances are left-biased now,
so combinators like `many` and `optional` from Control.Applicative work
in a more intuitive manner.  Further, some functions (like `endBy1`)
only return the "most successful" parse, instead of returning all of
them.  We can now get away with providing a single parsing result
instead of ReadP's list of results (as such, parsers need to be
disambiguated earlier instead of trimming the list down after parsing).
2021-12-13 16:11:57 +01:00
Tony Zorman
061faf1748
Merge pull request #646 from iliayar/feature/fallback-fonts
Add xft-based font fallback support
2021-12-11 19:12:14 +01:00
Ilya
42b392e06a X.U.Font: Add font-fallback support
This adds basic font-fallback support for X.U.Font, as well as modules
using it, like X.Prompt and X.A.TreeSelect.

In the new system, multiple fonts may be specified with the syntax

    "xft:iosevka-11,FontAwesome-9"

Fixes: https://github.com/xmonad/xmonad-contrib/issues/208
2021-12-11 15:08:42 +01:00
Tony Zorman
905a4fec9c
Merge pull request #660 from exorcist365/master
X.H.BorderPerWindow: Remove unused import
2021-12-07 09:10:20 +01:00
exorcist365
3569e7168b X.H.BorderPerWindow: Remove unused import
Dimension is already exported by XMonad.

Fixes: 95b37a9ab2cb3e5081b17f5f5161b66e0d9c69d5
2021-12-07 09:08:22 +01:00
slotThe
853264b113 X.H.BorderPerWindow: Fix typo in documentation
Fixes: 95b37a9ab2cb3e5081b17f5f5161b66e0d9c69d5
2021-12-06 12:38:04 +01:00
Tony Zorman
afdd466bc6
Merge pull request #640 from subbyte/master
Add X.U.ActionQueue and X.H.BorderPerWindow
2021-12-05 14:24:17 +01:00
slotThe
ba43dc6c7e X.U.ExtensibleConf: Fix typo in docs 2021-12-04 17:21:10 +01:00
Xiaokui Shu
95b37a9ab2 New module: XMonad.Hooks.BorderPerWindow 2021-12-04 17:21:10 +01:00
Xiaokui Shu
a981832aaf New module: XMonad.Util.ActionQueue 2021-12-04 17:21:10 +01:00
Tony Zorman
28aa164abd
Merge pull request #647 from slotThe/safe-window-attrs
Prefer safe alternatives to getWindowAttributes
2021-11-28 20:43:02 +01:00
Tony Zorman
243deb943f
Merge pull request #658 from d3adb5/master
X.L.MagicFocus: always use focused as master
2021-11-28 17:08:45 +01:00
d3adb5
97beb3efc7
X.L.MagicFocus: always use focused as master
Instead of searching for the currently focused window across workspaces,
make it so there is never any window above focus on the Stack that is
given to the modified layout.

Closes #657.
2021-11-28 02:04:22 -03:00
Tony Zorman
3d71669b0a
Merge pull request #653 from RubenAstudillo/feature/no-leak-history-hook
Fix memory leaks in `historyHook` and `workspaceHistoryHook`
2021-11-24 21:03:17 +01:00
Ruben Astudillo
b75d0d265e Use deepseq instead of parallel 2021-11-24 15:24:08 -03:00
Ruben Astudillo
44fb597350 Fix workspaceHistoryHook memory leak
The XS.modify was leaving thunk on the history that the demand analyser
could not prove to be neccesary as they depended on the future user
interaction. This was bad as the time advance there was less and less
neccesity to force such value, so the thunk would be increasing. Since the
datatypes that the `WorkspaceHistory` are really simple, we can just
evaluate and save a good chunk of memory.
2021-11-23 17:50:18 -03:00
Ruben Astudillo
ed5d6f0d78 Fix historyHook memory leak
updateHistory leaks unfiltered windows from previous states as it is never
forced. The consumer of such data structure is not visible to ghc, so the
demand analysis has to fallback on pure laziness.

We fix this inserting evaluation points on the `historyHook` function. We do
this for two reasons, this is the only function calling `updateHistory`.
Plus we cannot do it clearly at the `updateHistory` function as we operate
inside a continuation on withWindowSet. In respect to the `put`, everything
would be a big thunk.
2021-11-23 17:50:18 -03:00
Ruben Astudillo
282afefddf Add a modify' function on extensible state 2021-11-22 17:29:08 -03:00
Tony Zorman
2a02fb3753
Merge pull request #652 from Rogach/pr/fix-window-navigation
X.A.WindowNavigation: Fix navigation being "stuck" in certain situations
2021-11-22 21:10:39 +01:00
Platon Pronko
ca5841f7fa X.A.WindowNavigation: Fix navigation getting stuck
Update left and right navigation to behave correctly even if the
currently saved position is directly on the edge of the focused window.
This makes the L/R behavior consistent with U/D navigation.

How to reproduce the issue on a 16:9 resolution like 1920x1080:

  - configure Grid layout;
  - open 4 terminals;
  - navigate to the top-right terminal;
  - open another terminal;
  - immediately close it;
  - try navigating left from the currently focused top-right terminal;
  - observe navigation being "stuck".
2021-11-22 21:12:17 +01:00
Tomas Janousek
5f3d660fde README: Add badges for IRC and Matrix 2021-11-22 11:30:59 +00:00
Tomas Janousek
65408dc07a README: Make spaces _not_ part of hyperlinks 2021-11-22 11:30:35 +00:00
slotThe
61c3aff33c X.A.CycleWorkspaceByScreen: Document
The documentation for this module was lacking, making it significantly
harder to use than the functionality wise very similar
X.A.CycleRecentWS—change that.
2021-11-21 16:42:55 +01:00
slotThe
90a96dee49 X.H.ManageHelpers: Flip logic for (^?), (~?), and ($?)
This changes how the "is*Of" infix operators are hoisted into the
ManageHook context.  Instead of `q ~? x` being a lifted version of
`isPrefixOf q x` we instead let it be a lift of `isPrefixOf x q`.

While this obviously does not matter for symmetric operators like `(==)`
and `(/=)`, for `isInfixOf` it is rather essential.  The reason for that
is that the given `q` on the left side is an atom that can't (shouldn't)
be changed (by the user) and we only have control over the right hand
side.  Otherwise, things like

    title ~? "foo"

would read "only match if `title` is an infix of `foo`" instead of the
much more useful "only match if `foo` is an infix of `title`".

Fixes: 8b6f17ba6684a126fc1bde8d7275c166b3456d37
2021-11-17 20:14:26 +01:00
Artem Smaznov
e82a8b8849 X.U.EZConfig: Add modifier keys' KeySyms 2021-11-15 14:16:01 -05:00
slotThe
b6a8069e44 Prefer safe alternatives to getWindowAttributes
Whenever possible, prefer the safe wrappers withWindowAttributes or
safeGetWindowAttributes to getWindowAttributes.

Places where these are not applicable are limited to layouts, where
there is not good "default value" to give back in case these calls fail.
In these cases, we let the exception handling of the layout mechanism
handle it and fall back to the Full layout.

Fixes: https://github.com/xmonad/xmonad-contrib/issues/146
2021-11-13 21:26:02 +01:00
slotThe
528b9d9fde X.Prelude: Add safeGetWindowAttributes
Move the function from X.U.DebugWindow, where it was defined already.
This is a safe version of getWindowAttributes, returning a Maybe instead
of throwing an exception, in case the window attributes could not be
retrieved.
2021-11-13 20:44:15 +01:00
brandon s allbery kf8nh
6cb2796fc0
Fix thinko in documentation
This file was obviously copied from `DwmStyle`, and the author missed changing that
out to `simpleDeco` in one place. Just patching in place since it's a one-word change.
2021-11-12 13:47:21 -05:00
slotThe
67a92edd2a
Merge pull request #637 from slotThe/modernise-extending
Start modernising X.D.Extending
2021-11-10 11:47:31 +01:00
slotThe
3109e3966c X.D.Extending: Explain how to write additionalKeys
Instead of telling the user how to add custom keybindings to
xmonad—something which is already done in the tutorial—instead explain
instead how one would go about writing a version of
X.U.EZConfig.additionalKeys.  This mostly involves looking at the type
signatures and sticking some standard functions together, so it's quite
a decent way to learn about some of xmonad's internals.
2021-11-09 20:33:32 +01:00
Tomas Janousek
7807eb1be0 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:18:09 +00:00
Tomas Janousek
b40b672288 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:17:36 +00:00
slotThe
99e1b30e86 X.A.Search: Remove num=100 from google search engine
It no longer does what it was intended to do, and in fact, now does the
opposite.

When X.A.Search came to be in ~2007, Google's default of showing 10 or
so search hits was radically inadequate for poweruser needs. The 'num'
argument was used to force display of more hits (i.e., n meant 'display
at least n hits per page').

However, at some point, 'num' was inverted to mean something
catastrophically different: now it apparently means 'display no more
than n hits, total'. If you use that parameter, you will get 1 or 2
pages of hits at most reading 'About 98 results' or 'About 99
results' (no matter how many millions are available), and a blurb at the
bottom of the final page saying 'In order to show you the most relevant
results, we have omitted some entries very similar to the 99 already
displayed.' Removing the 'num' parameter then shows you all the hits
that were suppressed.

This is bad, and should be removed.

Fixes: https://github.com/xmonad/xmonad-contrib/issues/642

Co-authored-by: Gwern Branwen <gwern@gwern.net>
2021-11-08 16:46:24 +01:00
slotThe
42dec50c17
Merge pull request #644 from slotThe/window-swallowing-noborder
X.H.WindowSwallowing: Fix single window getting lost
2021-11-08 11:46:05 +01:00
slotThe
5c50387db0 X.H.WindowSwallowing: Fix single window getting lost
ConfigureEvents may occur after a window has been deleted, an UnmapEvent
has already been sent (and thus xmonad already unmanaged the window),
but before a DestroyWindowEvent is caught by the eventHook.  For
example, this is the case when one uses smartBorders with a single
window (such that smartBorders is "active").  The ConfigureEvents
sensibly already have an empty stack (because the UnmapEvent has already
been received), which we then copy to the history.

Whenever a parent window has been found, the sensible thing to do is to
always restore it.  The fact that oldStack is Nothing simply encodes an
empty workspace and is thus something we definitely need to handle as
well.

Fixes: https://github.com/xmonad/xmonad-contrib/issues/638
2021-11-07 16:06:30 +01:00
slotThe
feee11a0ba X.H.DynamicLog: Fix xmobarProp example
In [1] we changed the return type to not be an IO action and hence this
example can't work, even with an otherwise correct configuration.

[1]: 168cb6a6c3a774bc05032536e37b982cd6b4d7cc (Removed unnecessary IO)
2021-11-06 11:40:13 +01:00
slotThe
3bc06447d2 X.H.TaffybarPagerHints: Rename defaultConfig to def
The former was removed in [1], so only the latter is valid code right
now.

[1]: 5140f5b5d06790e055eb7fb0cf3eccc4997aa736
     (Remove things deprecated by Data.Default)
2021-11-06 11:40:13 +01:00
Tomáš Janoušek
52998657ef
Merge pull request #639 from liskin/ghc92
Test against GHC 9.2.1; fix new warnings
2021-11-05 10:30:22 +00:00
Tomas Janousek
d67df574cf ci: Run hlint with 9.0.1, not 9.2.1
cabal-3.6.2.0: Could not resolve dependencies:
    [__0] trying: hlint-3.3.4 (user goal)
    [__1] next goal: ghc-lib-parser (dependency of hlint +/-ghc-lib)
    [__1] rejecting: ghc-lib-parser-9.2.1.20211030 (conflict: hlint +/-ghc-lib =>
    ghc-lib-parser>=9.0 && <9.1)
    [__1] trying: ghc-lib-parser-9.0.1.20210324
    [__2] next goal: base (dependency of hlint)
    [__2] rejecting: base-4.16.0.0/installed-4.16.0.0 (conflict: ghc-lib-parser =>
    base>=4.13 && <4.16)
    [__2] skipping: base-4.16.0.0 (has the same characteristics that caused the
    previous version to fail: excluded by constraint '>=4.13 && <4.16' from
    'ghc-lib-parser')
    [__2] rejecting: base-4.15.0.0, base-4.14.3.0, base-4.14.2.0, base-4.14.1.0,
    base-4.14.0.0, base-4.13.0.0, base-4.12.0.0, base-4.11.1.0, base-4.11.0.0,
    base-4.10.1.0, base-4.10.0.0, base-4.9.1.0, base-4.9.0.0, base-4.8.2.0,
    base-4.8.1.0, base-4.8.0.0, base-4.7.0.2, base-4.7.0.1, base-4.7.0.0,
    base-4.6.0.1, base-4.6.0.0, base-4.5.1.0, base-4.5.0.0, base-4.4.1.0,
    base-4.4.0.0, base-4.3.1.0, base-4.3.0.0, base-4.2.0.2, base-4.2.0.1,
    base-4.2.0.0, base-4.1.0.0, base-4.0.0.0, base-3.0.3.2, base-3.0.3.1
    (constraint from non-upgradeable package requires installed instance)
    [__2] fail (backjumping, conflict set: base, ghc-lib-parser, hlint)
    After searching the rest of the dependency tree exhaustively, these were the
    goals I've had most trouble fulfilling: hlint (536), ghc-lib-parser (335),
    base (219)
2021-11-05 10:14:20 +00:00
Tomas Janousek
4b4f7f2dd6 ci: Test against GHC 9.2 2021-11-05 10:14:20 +00:00
Tomas Janousek
8623c29dd5 ci: Update haskell-ci 2021-11-05 10:14:20 +00:00
Tomas Janousek
5aff766a4c Apply hlint 3.3 hints 2021-11-05 10:14:20 +00:00
Tomas Janousek
e7f102bc9a Revert "Fix -Wdeprecations warnings (time 1.11)"
This doesn't work with the version of time shipped with GHC 8.4 and 8.6.

This reverts commit f2db7bcaa6367bc7db6b49c30e029f10534a99a2.
2021-11-05 10:14:20 +00:00
Tomas Janousek
8197cd9105 Fix -Wincomplete-uni-patterns warnings
I am not proud of this.
2021-11-05 10:14:20 +00:00
Tomas Janousek
5f3a6210a2 Fix -Wincomplete-record-updates warnings
(undefined has `HasCallStack =>` so this will give a useful error
message if anyone ever makes the code fail)
2021-11-05 10:14:20 +00:00
Tomas Janousek
b83f49d90b Fix -Wdeprecations warnings (time 1.11) 2021-11-05 10:14:20 +00:00
Tomas Janousek
850a3c245e Fix -Woperator-whitespace-ext-conflict warnings 2021-11-05 10:14:20 +00:00
Tomas Janousek
e252cc75b1 Fix -Wnoncanonical-monad-instances warnings 2021-11-05 10:14:20 +00:00
Tomas Janousek
d8faed6ad2 Fix -Wnoncanonical-monoid-instances warnings 2021-11-05 10:14:20 +00:00
slotThe
d2f0a0586c
Merge pull request #641 from slotThe/prompt-C-t
X.Prompt: Add transposeChars
2021-11-05 08:36:50 +01:00
slotThe
c30e406cfd X.Prompt: Add transposeChars
This is an analogue to Emacs's `transpose-chars` function (expect that
it does not take a universal argument), bound to its default keybinding.
2021-11-03 21:11:05 +01:00
Yecine Megdiche
0973107b29 X.L.CenteredIfSignle: Update CHANGES.md 2021-10-31 10:01:58 +01:00
Yecine Megdiche
f6bcf094e1
Merge pull request #634 from elkowar/centered-if-single
Add XMonad.Layout.CenteredIfSingle
2021-10-30 22:27:09 +02:00
elkowar
eeb36e0d08
Add XMonad.Layout.CenteredIfSingle 2021-10-30 22:11:45 +02:00
slotThe
ab2ba347e5 X.D.Extending: Rephrase introduction, update
Since the tutorial is really the better place to start learning how to
use xmonad, X.D.Extending can be the place for more "advanced" usage
examples.  These would be things like writing small functions to scratch
an itch (rather than entire modules).  Rewrite the introduction
accordingly.

On the way, remove some small inconsistencies/dead links/remarks about
how things are different from version 0.5 onwards—these times are long
gone now.
2021-10-30 14:25:27 +02:00
slotThe
edbff0dca1 X.D.Extending: Link to tutorial instead of the wiki
The configurations on the wiki are quite old and mostly non-functional
at this point.  Instead, we have a shiny new tutorial we can refer to.
It contains links to actual maintainers configurations (complex they may
be, at least they compile).
2021-10-30 14:25:22 +02:00
Tomas Janousek
2b98286ba3 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-contrib-0.17.0/
2021-10-28 17:58:18 +01:00
Tomas Janousek
f5f6ef41cb stack: Bump default resolver to 18.14
No impact on CI, just makes it easier for contributors to use the latest
8.10 GHC.
2021-10-28 17:22:54 +01:00
Tomas Janousek
4a356cfc7c ci: Reenable testing against released X11, xmonad
This was temporarily disabled in 229d52ff07 and 086db3123b because we
couldn't keep xmonad-contrib backwards compatible with xmonad 0.15 any
more, but xmonad 0.17.0 is out now and we can try to stay compatible for
a while.
2021-10-28 17:19:32 +01:00
327 changed files with 14109 additions and 4427 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

@ -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,111 @@ 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
allow-failure: false
- compiler: ghc-8.6.5
allow-failure: false
- compiler: ghc-8.4.4
compilerKind: ghc
compilerVersion: 8.8.4
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 libxft-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 libxft-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 +149,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: |
@ -110,28 +162,17 @@ jobs:
- name: update cabal index
run: |
$CABAL v2-update -v
- name: cache (tools)
uses: actions/cache@v2
with:
key: ${{ runner.os }}-${{ matrix.compiler }}-tools-6c71d9d3
path: ~/.haskell-ci-tools
- 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: install hlint
run: |
if [ $((HCNUMVER >= 90000)) -ne 0 ] ; then HLINTVER=$(cd /tmp && (${CABAL} v2-install -v $ARG_COMPILER --dry-run hlint --constraint='hlint >=3.2 && <3.3' | perl -ne 'if (/\bhlint-(\d+(\.\d+)*)\b/) { print "$1"; last; }')); echo "HLint version $HLINTVER" ; fi
if [ $((HCNUMVER >= 90000)) -ne 0 ] ; then if [ ! -e $HOME/.haskell-ci-tools/hlint-$HLINTVER/hlint ]; then echo "Downloading HLint version $HLINTVER"; mkdir -p $HOME/.haskell-ci-tools; curl --write-out 'Status Code: %{http_code} Redirects: %{num_redirects} Total time: %{time_total} Total Dsize: %{size_download}\n' --silent --location --output $HOME/.haskell-ci-tools/hlint-$HLINTVER.tar.gz "https://github.com/ndmitchell/hlint/releases/download/v$HLINTVER/hlint-$HLINTVER-x86_64-linux.tar.gz"; tar -xzv -f $HOME/.haskell-ci-tools/hlint-$HLINTVER.tar.gz -C $HOME/.haskell-ci-tools; fi ; fi
if [ $((HCNUMVER >= 90000)) -ne 0 ] ; then mkdir -p $CABAL_DIR/bin && ln -sf "$HOME/.haskell-ci-tools/hlint-$HLINTVER/hlint" $CABAL_DIR/bin/hlint ; fi
if [ $((HCNUMVER >= 90000)) -ne 0 ] ; then hlint --version ; fi
- name: checkout
uses: actions/checkout@v2
uses: actions/checkout@v4
with:
path: source
- name: initial cabal.project for sdist
@ -150,7 +191,8 @@ jobs:
- name: generate cabal.project
run: |
PKGDIR_xmonad_contrib="$(find "$GITHUB_WORKSPACE/unpacked" -maxdepth 1 -type d -regex '.*/xmonad-contrib-[0-9.]*')"
echo "PKGDIR_xmonad_contrib=${PKGDIR_xmonad_contrib}" >> $GITHUB_ENV
echo "PKGDIR_xmonad_contrib=${PKGDIR_xmonad_contrib}" >> "$GITHUB_ENV"
rm -f cabal.project cabal.project.local
touch cabal.project
touch cabal.project.local
echo "packages: ${PKGDIR_xmonad_contrib}" >> cabal.project
@ -168,15 +210,15 @@ jobs:
flags: +pedantic
ghc-options: -j
EOF
$HCPKG list --simple-output --names-only | perl -ne 'for (split /\s+/) { print "constraints: $_ installed\n" unless /^(xmonad-contrib)$/; }' >> cabal.project.local
$HCPKG list --simple-output --names-only | perl -ne 'for (split /\s+/) { print "constraints: any.$_ installed\n" unless /^(xmonad-contrib)$/; }' >> 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
@ -194,43 +236,60 @@ jobs:
- name: tests
run: |
$CABAL v2-test $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --test-show-details=direct
- name: hlint
run: |
if [ $((HCNUMVER >= 90000)) -ne 0 ] ; then (cd ${PKGDIR_xmonad_contrib} && hlint -h ${GITHUB_WORKSPACE}/source/.hlint.yaml .) ; fi
- name: cabal check
run: |
cd ${PKGDIR_xmonad_contrib} || 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" \
@ -238,23 +297,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" \
@ -262,7 +328,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: '["XMonad/", "tests/", "scripts/"]'
fail-on: status

View File

@ -12,17 +12,15 @@ 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
# "nix build" builds with full optimization and includes a profiling
# build, so just the build of xmonad-contrib itself takes 3 minutes.
# As a workaround, we invoke cabal manually here.
run: nix develop -c cabal v2-build -O0 -j
run: |
nix develop -c cabal v2-update -O0 -j
nix develop -c cabal v2-build -O0 -j

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
@ -40,3 +40,11 @@ jobs:
--exclude X11 \
--exclude xmonad \
*.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,42 +12,33 @@ jobs:
fail-fast: false
matrix:
include:
# XXX: temporarily disabled until xmonad 0.17 release
# - resolver: lts-12
# ghc: 8.4.4
# yaml: stack.yaml
- resolver: lts-12
ghc: 8.4.4
- resolver: lts-16 # GHC 8.8
yaml: stack.yaml
- resolver: lts-16 # GHC 8.8
yaml: stack-master.yaml
- resolver: lts-14
ghc: 8.6.5
- resolver: lts-18 # GHC 8.10
yaml: stack-master.yaml
- resolver: lts-16
ghc: 8.8.4
- resolver: lts-19 # GHC 9.0
yaml: stack-master.yaml
# - resolver: lts-17
# ghc: 8.10.4
# yaml: stack.yaml
- resolver: lts-17
ghc: 8.10.4
- resolver: lts-20 # GHC 9.2
yaml: stack-master.yaml
- resolver: lts-18
ghc: 8.10.7
- resolver: lts-21 # GHC 9.4
yaml: stack-master.yaml
- resolver: lts-22 # GHC 9.6
yaml: stack-master.yaml
- resolver: lts-23 # GHC 9.8
yaml: stack.yaml
- resolver: lts-23 # GHC 9.8
yaml: stack-master.yaml
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 \
@ -57,31 +48,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/*
@ -91,7 +74,6 @@ jobs:
restore-keys: |
stack-${{ runner.os }}-${{ matrix.resolver }}-${{ steps.cache-date.outputs.date }}-${{ hashFiles(matrix.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
stack.yaml.lock
# nix artifacts
result
flake.lock

View File

@ -103,6 +103,7 @@ hexago.nl <xmonad-contrib@hexago.nl>
lithis <xmonad@selg.hethrael.org>
lithis <xmonad@selg.hethrael.org> <xmonad@s001.hethrael.com>
sam-barr <mail@samf.bar> <samfbarr@outlook.com>
slotThe <soliditsallgood@mailbox.org> <50166980+slotThe@users.noreply.github.com>
slotThe <soliditsallgood@mailbox.org> <soliditsallgood@tuta.io>
Tony Zorman <soliditsallgood@mailbox.org> <50166980+slotThe@users.noreply.github.com>
Tony Zorman <soliditsallgood@mailbox.org> <soliditsallgood@tuta.io>
Tony Zorman <soliditsallgood@mailbox.org>
spoonm <spoonm@spoonm.org>

View File

@ -1,5 +1,722 @@
# Change Log / Release Notes
## _unreleased_
### Breaking Changes
* Drop support for GHC 8.6
### Bug Fixes and Minor Changes
* `XMonad.Util.EZConfig`
- Added `XF86WLAN` and `Menu` to the list of supported special keys.
* `XMonad.Actions.DynamicProjects`
- No longer autodelete projects when `switchProject` is called from
an empty workspace. This also fixes a bug where static workspaces
would be deleted when switching to a dynamic project.
- Improved documentation on how to close a project.
* `XMonad.Hooks.Rescreen`
- Allow overriding the `rescreen` operation itself. Additionally, the
`XMonad.Actions.PhysicalScreens` module now provides an alternative
implementation of `rescreen` that avoids reshuffling the workspaces if
the number of screens doesn't change and only their locations do (which
is especially common if one uses `xrandr --setmonitor` to split an
ultra-wide display in two).
- Added an optional delay when waiting for events to settle. This may be
used to avoid flicker and unnecessary workspace reshuffling if multiple
`xrandr` commands are used to reconfigure the display layout.
* `XMonad.Layout.NoBorders`
- It's no longer necessary to use `borderEventHook` to garbage collect
`alwaysHidden`/`neverHidden` lists. The layout listens to
`DestroyWindowEvent` messages instead, which are broadcast to layouts
since xmonad v0.17.0.
* `XMonad.Hooks.EwmhDesktops`
- Added a customization option for the action that gets executed when
a client sends a **_NET_CURRENT_DESKTOP** request. It is now possible
to change it using the `setEwmhSwitchDesktopHook`.
- Added a customization option for mapping hidden workspaces to screens
when setting the **_NET_DESKTOP_VIEWPORT**. This can be done using
the `setEwmhHiddenWorkspaceToScreenMapping`.
* `XMonad.Layout.IndependentScreens`
- Added `focusWorkspace` for focusing workspaces on the screen that they
belong to.
- Added `doFocus'` hook as an alternative for `doFocus` when using
IndependentScreens.
- Added `screenOnMonitor` for getting the active screen for a monitor.
* `XMonad.Util.NamedScratchPad`
- Fix unintended window hiding in `nsSingleScratchpadPerWorkspace`.
Only hide the previously active scratchpad.
## 0.18.1 (August 20, 2024)
### Breaking Changes
* `XMonad.Hooks.StatusBars`
- Move status bar functions from the `IO` to the `X` monad to
allow them to look up information from `X`, like the screen
width. Existing configurations may need to use `io` from
`XMonad.Core` or `liftIO` from `Control.Monad.IO.Class` in
order to lift any existing `IO StatusBarConfig` values into
`X StatusBarConfig` values.
* `XMonad.Prompt`
- Added an additional `XPConfig` argument to `historyCompletion` and
`historyCompletionP`. Calls along the lines of `historyCompletionP
myFunc` should be changed to `historyCompletionP myConf myFunc`.
If not `myConf` is lying around, `def` can be used instead.
* `XMonad.Actions.GridSelect`
- Added the `gs_cancelOnEmptyClick` field to `GSConfig`, which makes
mouse clicks into "empty space" cancel the current grid-select.
Users explicitly defining their own `GSConfig` record will have to
add this to their definitions. Additionally, the field defaults to
`True`—to retain the old behaviour, set it to `False`.
### New Modules
* `XMonad.Actions.Profiles`
- Group workspaces by similarity. Useful when one has lots
of workspaces and uses only a couple per unit of work.
* `XMonad.Hooks.FloatConfigureReq`
- Customize handling of floating windows' move/resize/restack requests
(ConfigureRequest). Useful as a workaround for some misbehaving client
applications (Steam, rxvt-unicode, anything that tries to restore
absolute position of floats).
* `XMonad.Layout.Columns`
- Organize windows in columns. This layout allows to move/resize windows in
every directions.
* `XMonad.Prompt.WindowBringer`
- Added `copyMenu`, a convenient way to copy a window to the current workspace.
### Bug Fixes and Minor Changes
* Fix build-with-cabal.sh when XDG_CONFIG_HOME is defined.
* `XMonad.Util.EZConfig`
- Fixed `checkKeymap` warning that all keybindings are duplicates.
* `XMonad.Hooks.ManageHelpers`
- Added `isNotification` predicate to check for windows with
`_NET_WM_WINDOW_TYPE` property of `_NET_WM_WINDOW_TYPE_NOTIFICATION`.
* `XMonad.Prompt.OrgMode`
- Added `HH:MM-HH:MM` and `HH:MM+HH` syntax to specify time spans.
* `XMonad.Prompt`
- The history file is not extraneously read and written anymore if
the `historySize` is set to 0.
* `XMonad.Hooks.EwmhDesktops`
- Requests for unmanaged windows no longer cause a refresh. This avoids
flicker and also fixes disappearing menus in the Steam client and
possibly a few other client applications.
(See also `XMonad.Hooks.FloatConfigureReq` and/or `XMonad.Util.Hacks`
for additional Steam client workarounds.)
* `XMonad.Actions.Submap`
- Added `visualSubmapSorted` to enable sorting of the keymap
descriptions.
* `XMonad.Hooks.ScreenCorners`
- Added screen edge support with `SCTop`, `SCBottom`, `SCLeft` and
`SCRight`. Now both corners and edges are supported.
* `XMonad.Actions.WindowNavigation`
- Improve navigation in presence of floating windows.
- Handle window switching when in `Full` layout.
### Other changes
## 0.18.0 (February 3, 2024)
### Breaking Changes
* Deprecated `XMonad.Layout.Cross` due to bitrot; refer to
`XMonad.Layout.Circle` and `XMonad.Layout.ThreeColumns` for
alternatives.
* Deprecated the `XMonad.Layout.StateFull` module and
`XMonad.Layout.TrackFloating.(t|T)rackFloating` in favour of
`XMonad.Layout.FocusTracking`.
* Dropped support for GHC 8.4.
* `XMonad.Util.ExclusiveScratchpads`
- Deprecated the module in favour of the (new) exclusive scratchpad
functionality of `XMonad.Util.NamedScratchpad`.
* `XMonad.Actions.CycleWorkspaceByScreen`
- The type of `repeatableAction` has changed, and it's deprecated in
favour of `X.A.Repeatable.repeatable`.
* `XMonad.Hooks.DynamicProperty`
- Deprecated the module in favour of the more aptly named
`XMonad.Hooks.OnPropertyChange`.
* `XMonad.Util.Scratchpad`:
- Deprecated the module; use `XMonad.Util.NamedScratchpad` instead.
* `XMonad.Actions.Navigation2D`
- Removed deprecated function `hybridNavigation`.
* `XMonad.Layout.Spacing`
- Removed deprecated functions `SpacingWithEdge`, `SmartSpacing`,
`SmartSpacingWithEdge`, `ModifySpacing`, `setSpacing`, and
`incSpacing`.
* `XMonad.Actions.MessageFeedback`
- Removed deprecated functions `send`, `sendSM`, `sendSM_`,
`tryInOrder`, `tryInOrder_`, `tryMessage`, and `tryMessage_`.
* `XMonad.Prompt.Window`
- Removed deprecated functions `windowPromptGoto`,
`windowPromptBring`, and `windowPromptBringCopy`.
* `XMonad.Hooks.ICCCMFocus`
- Removed deprecated module. This was merged into xmonad.
* `XMonad.Layout.LayoutBuilderP`
- Removed deprecated module; use `XMonad.Layout.LayoutBuilder`
instead.
* `XMonad.Hooks.RestoreMinimized`
- Removed deprecated module; use `XMonad.Hooks.Minimize` instead.
* `XMonad.Layout.Named`
- Deprecated the entire module, use `XMonad.Layout.Renamed` (which newly
provides `named` for convenience) instead.
* `XMonad.Actions.SinkAll`
- Deprecated the entire module, use `XMonad.Actions.WithAll`
instead.
* `XMonad.Layout.Circle`:
- Deprecated the entire module, use the `circle` function from
`XMonad.Layout.CircleEx` instead.
* `XMonad.Hooks.EwmhDesktops`
- `_NET_CLIENT_LIST_STACKING` puts windows in the current workspace at the
top in bottom-to-top order, followed by visible workspaces, followed by
invisible workspaces. Within visible and invisible groups, workspaces are
ordered lexicographically, as before. Currently focused window will
always be the topmost, meaning the last in the list.
* `XMonad.Util.NamedScratchpad`
- Added `nsSingleScratchpadPerWorkspace`—a logHook to allow only one
active scratchpad per workspace.
* `XMonad.Util.EZConfig`
- The function `readKeySequence` now returns a non-empty list if it
succeeded.
* Deprecate `XMonad.Util.Ungrab`; it was moved to `XMonad.Operations`
in core.
### New Modules
* `XMonad.Layout.CenterMainFluid`
- A three column layout with main column in the center and two stack
column surrounding it. Master window will be on center column and
spaces on the sides are reserved.
* `XMonad.Layout.FocusTracking`.
- Replaces `X.L.StateFull` and half of `X.L.TrackFloating`.
* `XMonad.Actions.MostRecentlyUsed`
- Tab through windows by recency of use. Based on the Alt+Tab behaviour
common outside of xmonad.
* `XMonad.Util.History`
- Track history in *O(log n)* time. Provides `History`, a variation on a
LIFO stack with a uniqueness property. In order to achieve the desired
asymptotics, the data type is implemented as an ordered Map.
* `XMonad.Actions.Repeatable`
- Actions you'd like to repeat. Factors out the shared logic of
`X.A.CycleRecentWS`, `X.A.CycleWorkspaceByScreen` and `X.A.CycleWindows`.
* `XMonad.Hooks.OnPropertyChange`:
- A new module replicating the functionality of
`XMonad.Hooks.DynamicProperty`, but with more discoverable names.
* `XMonad.Actions.ToggleFullFloat`:
- Fullscreen (float) a window while remembering its original state.
There's both an action to be bound to a key, and hooks that plug into
`XMonad.Hooks.EwmhDesktops`.
* `XMonad.Layout.CircleEx`:
- A new window layout, similar to X.L.Circle, but with more
possibilities for customisation.
* `XMonad.Layout.DecorationEx`:
- A new, more extensible, mechanism for window decorations, and some
standard types of decorations, including usual bar on top of window,
tabbed decorations and dwm-like decorations.
### Bug Fixes and Minor Changes
* `XMonad.Layout.Magnifier`
- Added `magnifyxy` to allow for different magnification in the
horizontal and vertical directions. Added `magnifierxy`,
`magnifierxy'`, `magnifierxyOff`, and `magnifierxyOff'` as
particular combinators.
* `XMonad.Util.Loggers`
- Added `logClassname`, `logClassnames`, `logClassnames'`,
`logClassnameOnScreen`, `logClassnamesOnScreen`, `logClassnamesOnScreen'`,
and `ClassnamesFormat`. These are all equivalents of their `Title`
counterparts, allowing logging the window classname instead.
* `XMonad.Hooks.StatusBar.PP`
- `dynamicLogString` now forces its result and produces an error string if
it throws an exception. Use `dynamicLogString'` if for some reason you
need the old behavior.
* `XMonad.Util.EZConfig`
- Added `remapKeysP`, which remaps keybindings from one binding to
another.
- Made `additionalKeys{,P}`, `removeKeys{,P}`, `remapKeysP`, and
`{additional,remove}MouseBindings` `infixl 4` so they can more easily
be concatenated with `(++)`.
* `XMonad.Util.NamedScratchpad`
- Added `addExclusives`, `resetFocusedNSP`, `setNoexclusive`,
`resizeNoexclusive`, and `floatMoveNoexclusive` in order to augment
named scratchpads with the exclusive scratchpad functionality of
`XMonad.Util.ExclusiveScratchpads`.
* `XMonad.Layout.BorderResize`
- Added `borderResizeNear` as a variant of `borderResize` that can
control how many pixels near a border resizing still works.
* `XMonad.Util.Run`
- It is now ensured that all arguments of `execute` and `eval` are
quoted. Likewise, `executeNoQuote` is added as a version of
`execute` that does not do that.
- Added `findFile` as a shorthand to call `find-file`.
- Added `list` and `saveExcursion` to the list of Emacs commands.
- Added `toList` to easily lift a `String` to an `X Input`.
- Added `>&&>` and `>||>` to glue together different inputs.
* `XMonad.Util.Parser`
- Added the `gather`, `count`, `between`, `option`, `optionally`,
`skipMany`, `skipMany1`, `chainr`, `chainr1`, `chainl`, `chainl1`,
and `manyTill` functions, in order to achieve feature parity with
`Text.ParserCombinators.ReadP`.
* `XMonad.Actions.FloatKeys`
- Added `directionMoveWindow` and `directionMoveWindow` as more
alternatives to the existing functions.
* `XMonad.Hooks.InsertPosition`
- Added `setupInsertPosition` as a combinator alternative to
`insertPosition`.
* `XMonad.Actions.Navigation2D`
- Added `sideNavigation` as a fallback to the default tiling strategy,
in case `lineNavigation` can't find a window. This benefits
especially users who use `XMonad.Layout.Spacing`.
* `XMonad.Prompt.OrgMode`
- Added `orgPromptRefile` and `orgPromptRefileTo` for interactive
and targeted refiling of the entered note into some existing tree
of headings, respectively.
- Allowed the time specification in `HHMM` format.
* `XMonad.Actions.Search`
- Added `aur`, `flora`, `ncatlab`, `protondb`, `rosettacode`, `sourcehut`,
`steam`, `voidpgks_x86_64`, `voidpgks_x86_64_musl`, `arXiv`,
`clojureDocs`, `cratesIo`, `rustStd`, `noogle`, `nixos`, `homeManager`,
and `zbmath` search engines.
* `XMonad.Layout.ResizableThreeColumns`
- Fixed an issue where the bottom right window would not respond to
`MirrorShrink` and `MirrorExpand` messages.
* `XMonad.Hooks.EwmhDesktops`
- Added `disableEwmhManageDesktopViewport` to avoid setting the
`_NET_DESKTOP_VIEWPORT` property, as it can lead to issues with
some status bars (see this
[polybar issue](https://github.com/polybar/polybar/issues/2603)).
- Added `setEwmhFullscreenHooks` to override the default fullfloat/sink
behaviour of `_NET_WM_STATE_FULLSCREEN` requests. See also
`XMonad.Actions.ToggleFullFloat` for a float-restoring implementation of
fullscreening.
- Added `ewmhDesktops(Maybe)ManageHook` that places windows in their
preferred workspaces. This is useful when restoring a browser session
after a restart.
* `XMonad.Hooks.StatusBar`
- Added `startAllStatusBars` to start the configured status bars.
* `XMonad.Util.NamedActions`
- Changed `addDescrKeys` and `addDescrKeys'` to not discard the
keybindings in the current config.
* `XMonad.Prompt`
- The `emacsLikeXPKeymap` and `vimLikeXPKeymap` keymaps now treat
`C-m` the same as `Return`.
- Added `prevCompletionKey` to `XPConfig`, facilitating the ability
to cycle through the completions backwards. This is bound to
`S-<TAB>` by default.
- The `vimLikeXPKeymap` now accepts the prompt upon pressing enter
in normal mode.
* `XMonad.Actions.Prefix`
- Added `orIfPrefixed`, a combinator to decide upon an action based
on whether any prefix argument was given.
* `XMonad.Actions.WorkspaceNames`
- Enabled prompt completion (from history) in `renameWorkspace`.
* `XMonad.Prompt.Pass`
- Added `passOTPTypePrompt` to type out one-time-passwords via
`xdotool`.
* `XMonad.Util.Stack`
- Added `zipperFocusedAtFirstOf` to differentiate two lists into a
zipper.
## 0.17.1 (September 3, 2022)
### Breaking Changes
* `XMonad.Util.EZConfig`
- The functions `parseKey`, `parseKeyCombo`, and `parseKeySequence`
now return a `Parser` (from `XMonad.Util.Parser`) instead of a
`ReadP`.
* `XMonad.Config.{Arossato,Dmwit,Droundy,Monad,Prime,Saegesser,Sjanssen}`
- Deprecated all of these modules. The user-specific configuration
modules may still be found [on the
website](https://xmonad.org/configurations.html)
* `XMonad.Util.NamedScratchpad`
- Scratchpads are now only based on the argument given to
`namedScratchpadManageHook`; all other scratchpad arguments are,
while still present, ignored. Users passing all of their
scratchpads to functions like `namedScratchpadAction` (as is shown
in the module's documentation) should _not_ notice any difference
in behaviour.
* `XMonad.Util.DynamicScratchpads`
- Deprecated the module; use the new dynamic scratchpad
functionality of `XMonad.Util.NamedScratchpad` instead.
* `XMonad.Hooks.UrgencyHook`
- Deprecated `urgencyConfig`; use `def` from the new `Default`
instance of `UrgencyConfig` instead.
### New Modules
* `XMonad.Actions.PerLayoutKeys`
Customizes a keybinding on a per-layout basis. Based on PerWorkspaceKeys.
* `XMonad.Layout.CenteredIfSingle`
Layout modifier that, if only a single window is on screen, places that window
in the middle of the screen.
* `XMonad.Util.ActionQueue`
Put XMonad actions in the queue to be executed every time the
`logHook` (or, alternatively, a hook of your choice) runs.
* `XMonad.Hooks.BorderPerWindow`
While XMonad provides config to set all window borders at the same
width, this extension lets user set border width for a specific window
using a ManageHook.
* `XMonad.Util.Parser`
A wrapper around the 'ReadP' parser combinator, providing behaviour
that's closer to the more popular parser combinator libraries.
* `XMonad.Hooks.StatusBar.WorkspaceScreen`
In multi-head setup, it might be useful to have screen information of the
visible workspaces combined with the workspace name, for example in a status
bar. This module provides utility functions to do just that.
* `XMonad.Hooks.ShowWName`
Flashes the name of the current workspace when switching to it.
Like `XMonad.Layout.ShowWName`, but as a logHook.
* `XMonad.Actions.RepeatAction`
A module for adding a keybinding to repeat the last action, similar
to Vim's `.` or Emacs's `dot-mode`.
* `XMonad.Util.Grab`
Utilities for making grabbing and ungrabbing keys more convenient.
* `XMonad.Hooks.Modal`
This module implements modal keybindings for xmonad.
* `XMonad.Layout.SideBorderDecoration`
This module allows for having a configurable border position around
windows; i.e., it can move the border to either cardinal direction.
### Bug Fixes and Minor Changes
* `XMonad.Prompt.Pass`
- Added new versions of the `pass` functions that allow user-specified
prompts.
* `XMonad.Prompt.AppendFile`
- Use `XMonad.Prelude.mkAbsolutePath` to force names to be relative to the
home directory and support `~/` prefixes.
* `XMonad.Prompt.OrgMode`
- Fixed the date parsing issue such that entries with a format of
`todo +d 12 02 2024` work.
- Added the ability to specify alphabetic (`#A`, `#B`, and `#C`)
[priorities](https://orgmode.org/manual/Priorities.html) at the end of
the input note.
* `XMonad.Prompt.Unicode`
- Fixed the display of non-ASCII characters in the description of Unicode
characters
* `XMonad.Prompt`
- Added `transposeChars` to interchange the characters around the
point and bound it to `C-t` in the Emacs XPKeymaps.
- Added xft-based font fallback support. This may be used by
appending other fonts to the given string:
`xft:iosevka-11,FontAwesome-9`. Note that this requires
`xmonad-contrib` to be compiled with `X11-xft` version 0.3.4 or
higher.
* `XMonad.Hooks.WindowSwallowing`
- Fixed windows getting lost when used in conjunction with
`smartBorders` and a single window.
- No longer needs `pstree` to detect child/parent relationships.
- Fixed some false positives in child/parent relationship detection.
* `XMonad.Actions.SpawnOn`
- Fixed parsing of `/proc/*/stat` to correctly handle complex process names.
* `XMonad.Util.EZConfig`
- Added support for Modifier Keys `KeySym`s for Emacs-like `additionalKeysP`.
* `XMonad.Hooks.ManageHelpers`
- Flipped how `(^?)`, `(~?)`, and `($?)` work to more accurately
reflect how one uses these operators.
- Added `isMinimized`
* `XMonad.Actions.WindowNavigation`
- Fixed navigation getting "stuck" in certain situations for
widescreen resolutions.
* `XMonad.Layout.BinarySpacePartition`
- Hidden windows are now ignored by the layout so that hidden windows in
the stack don't offset position calculations in the layout.
* `XMonad.Layout.MagicFocus`
- The focused window will always be at the master area in the stack being
passed onto the modified layout, even when focus leaves the workspace
using the modified layout.
* `XMonad.Actions.TreeSelect`
- Added xft-based font fallback support. This may be used by
appending other fonts to the given string:
`xft:iosevka-11,FontAwesome-9`. Note that this requires
`xmonad-contrib` to be compiled with `X11-xft` version 0.3.4 or
higher.
* `XMonad.Actions.FloatKeys`
- Changed type signature of `keysMoveWindow` from `D -> Window -> X ()`
to `ChangeDim -> Window -> X ()` to allow negative numbers without compiler warnings.
* `XMonad.Util.Hacks`
- Added `trayerPaddingXmobarEventHook` (plus generic variants for other
trays/panels) to communicate trayer resize events to XMobar so that
padding space may be reserved on xmobar for the tray. Requires `xmobar`
version 0.40 or higher.
* `XMonad.Layout.VoidBorders`
- Added new layout modifier `normalBorders` which can be used for
resetting borders back in layouts where you want borders after calling
`voidBorders`.
* `XMonad.Prelude`
- Added `keymaskToString` and `keyToString` to show a key mask and a
key in the style of `XMonad.Util.EZConfig`.
- Added `WindowScreen`, which is a type synonym for the specialized `Screen`
type, that results from the `WindowSet` definition in `XMonad.Core`.
- Modified `mkAbsolutePath` to support a leading environment variable, so
things like `$HOME/NOTES` work. If you want more general environment
variable support, comment on [this
PR](https://github.com/xmonad/xmonad-contrib/pull/744)
* `XMonad.Util.XUtils`
- Added `withSimpleWindow`, `showSimpleWindow`, `WindowConfig`, and
`WindowRect` in order to simplify the handling of simple popup
windows.
* `XMonad.Actions.Submap`
- Added `visualSubmap` to visualise the available keys and their
actions when inside a submap.
* `XMonad.Prompt`, `XMonad.Actions.TreeSelect`, `XMonad.Actions.GridSelect`
- Key bindings now behave similarly to xmonad core:
State of mouse buttons and XKB layout groups is ignored.
Translation of key codes to symbols ignores modifiers, so `Shift-Tab` is
now just `(shiftMap, xK_Tab)` instead of `(shiftMap, xK_ISO_Left_Tab)`.
* `XMonad.Util.NamedScratchpad`
- Added support for dynamic scratchpads in the form of
`dynamicNSPAction` and `toggleDynamicNSP`.
* `XMonad.Hooks.EwmhDesktops`
- Added support for `_NET_DESKTOP_VIEWPORT`, which is required by
some status bars.
* `XMonad.Util.Run`
- Added an EDSL—particularly geared towards programs like terminals
or Emacs—to spawn processes from XMonad in a compositional way.
* `XMonad.Hooks.UrgencyHook`
- Added a `Default` instance for `UrgencyConfig` and `DzenUrgencyHook`.
### Other changes
* Migrated the sample build scripts from the deprecated `xmonad-testing` repo to
`scripts/build`. This will be followed by a documentation update in the `xmonad`
repo.
## 0.17.0 (October 27, 2021)
### Breaking Changes
@ -549,6 +1266,11 @@
ones) on the focused workspace, as well as `logTitlesOnScreen` as
a screen-specific variant thereof.
- Added `logTitles'` and `logTitleOnScreen'`. These act like
`logTitles` and `logTitlesOnScreen` but use a record as an input
to enable logging for more window types. For example, currently
urgent windows are additionally supported.
* `XMonad.Layout.Minimize`
- Export `Minimize` type constructor.
@ -772,6 +1494,9 @@
- Fixed a system freeze when using `X.A.CopyWindow.copy` in
combination with `removeWorkspace`.
- `withWorkspace` now honors the users `searchPredicate`, for
example `fuzzyMatch` from `Prompt.FuzzyMatch`.
## 0.16
### Breaking Changes
@ -1511,8 +2236,8 @@
* `XMonad.Prompt.Pass`
This module provides 3 `XMonad.Prompt`s to ease passwords
manipulation (generate, read, remove) via [pass][].
This module provides 3 `XMonad.Prompt`s to ease passwords manipulation
(generate, read, remove) via [pass](http://www.passwordstore.org/).
* `XMonad.Util.RemoteWindows`
@ -1588,5 +2313,3 @@
## See Also
<https://wiki.haskell.org/Xmonad/Notable_changes_since_0.8>
[pass]: http://www.passwordstore.org/

106
NIX.md Normal file
View File

@ -0,0 +1,106 @@
# `nix` integration for XMonad
## Customizing the `nix-shell`
It's possible to use a file `develop.nix` to customize the `devShell`
provided by the flake. This is useful if e.g. you want to have the
`haskell-language-server` or other developer tools in the shell properly
configured (correct GHC versions, and the like).
Here is an example `develop.nix` for `haskell-language-server`:
``` nix
pkgs: devInputs: devInputs // {
nativeBuildInputs = with pkgs.haskellPackages;
[ cabal-install hlint ghcid ormolu implicit-hie haskell-language-server ];
}
```
## Selecting a Compiler
A `comp.nix` file can be used to set the compiler used for `nix build` etc. E.g.
```nix
{ compiler = "ghc924"; }
```
Note that you must `git add comp.nix`, or it will be invisible to the flake.
There is also a `prefix` option (see documentation below) but it doesn't really
work in this context, since the xmonad flakes don't see the effects of your
system overlays. Instead try the `--override-input` flag, e.g.
```sh
$ nix develop . --override-input nixpkgs 'github:NixOS/nixpkgs/nixos-unstable'
```
## NixOS Modules
The core and contrib flakes provide NixOS configuration modules.
You can bring them into your system flake like so:
```nix
{
inputs = {
nixpkgs.url = github:NixOS/nixpkgs/nixos-<version>;
# The xmonad-contrib flake depends upon and re-exports from the xmonad
# flake. As such, you don't need to use the latter directly. If you wish to
# use /only/ the xmonad flake, you should beware that the version of
# contrib you get from nixpkgs might not build against it.
xmonad-contrib.url = github:xmonad/xmonad-contrib;
};
outputs = { self, nixpkgs, xmonad-contrib }: {
nixosConfigurations.<hostname> = nixpkgs.lib.nixosSystem rec {
system = <system>;
# NixOS module composition is /not/ commutative; order matters.
# To avoid issues, add `xmonad-contrib.nixosModules` after your standard
# configuration, but before `modernise` or any module overlaying in a
# "prefix".
modules = [
./configuration.nix
./hardware-configuration.nix
<myMiscConfigModule>
] ++ xmonad-contrib.nixosModules ++ [
# `modernise` replaces the standard xmonad module and wrapper script
# with those from unstable. This is currently a necessary workaround to
# make Mod-q recompilation work.
xmonad-contrib.modernise.${system}
<myPrefixModule>
];
};
};
}
```
Note that `<thing>` should be replaced with a user-supplied `thing`.
`<version>`, `<hostname>` and `<system>` are necessary, while
` <myMiscConfigModule>` and `<myPrefixModule>` are entirely optional.
Having brought in `xmonad-contrib.nixosModules`, you can then set the provided
options in your `configuration.nix` under `flake`:
```nix
services.xserver.windowManager.xmonad = {
enable = true;
enableContribAndExtras = true;
flake = {
enable = true;
# prefix = "unstable";
compiler = "ghc924";
};
};
```
This will use core and contrib from git for your system xmonad, building your
config with the compiler of your choice.
With the flake enabled, the `xmonad.haskellPackages` option is not used
directly, and is instead set by the `flake.compiler` option. When `compiler` is
unset, the default `pkgs.haskellPackages` is used.
The `prefix` option is used if you wish to select your haskell packages from
within, e.g., unstable overlaid into `pkgs` as `pkgs.unstable`.
See the flakes themselves and nix flake documentation for full detail.
Additionally, a semi-walkthrough is available [here](https://tony-zorman.com/posts/xmonad-on-nixos.html).

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-contrib">
<img alt="Hackage" src="https://img.shields.io/hackage/v/xmonad-contrib?logo=haskell">
</a>
<a href="https://github.com/xmonad/xmonad-contrib/blob/readme/LICENSE">
<img alt="License" src="https://img.shields.io/github/license/xmonad/xmonad-contrib">
</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-contrib"><img alt="Hackage" src="https://img.shields.io/hackage/v/xmonad-contrib?logo=haskell"></a>
<a href="https://github.com/xmonad/xmonad-contrib/blob/readme/LICENSE"><img alt="License" src="https://img.shields.io/github/license/xmonad/xmonad-contrib"></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-contrib/actions/workflows/stack.yml">
<img alt="Stack" src="https://img.shields.io/github/workflow/status/xmonad/xmonad-contrib/Stack?label=Stack&logo=githubactions&logoColor=white">
</a>
<a href="https://github.com/xmonad/xmonad-contrib/actions/workflows/haskell-ci.yml">
<img alt="Cabal" src="https://img.shields.io/github/workflow/status/xmonad/xmonad-contrib/Haskell-CI?label=Cabal&logo=githubactions&logoColor=white">
</a>
<a href="https://github.com/xmonad/xmonad-contrib/actions/workflows/nix.yml">
<img alt="Nix" src="https://img.shields.io/github/workflow/status/xmonad/xmonad-contrib/Nix?label=Nix&logo=githubactions&logoColor=white">
</a>
<a href="https://github.com/xmonad/xmonad-contrib/actions/workflows/stack.yml"><img alt="Stack" src="https://img.shields.io/github/actions/workflow/status/xmonad/xmonad-contrib/stack.yml?label=Stack&logo=githubactions&logoColor=white"></a>
<a href="https://github.com/xmonad/xmonad-contrib/actions/workflows/haskell-ci.yml"><img alt="Cabal" src="https://img.shields.io/github/actions/workflow/status/xmonad/xmonad-contrib/haskell-ci.yml?label=Cabal&logo=githubactions&logoColor=white"></a>
<a href="https://github.com/xmonad/xmonad-contrib/actions/workflows/nix.yml"><img alt="Nix" src="https://img.shields.io/github/actions/workflow/status/xmonad/xmonad-contrib/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-contrib

View File

@ -24,7 +24,7 @@ import XMonad
import Data.Time (NominalDiffTime, diffUTCTime, getCurrentTime)
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
-- You can use this module with the following in your @xmonad.hs@:
--
-- > import XMonad.Actions.AfterDrag
--

View File

@ -29,7 +29,7 @@ import System.Exit
-- $usage
--
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
-- You can use this module with the following in your @xmonad.hs@:
--
-- > import XMonad.Hooks.ServerMode
-- > import XMonad.Actions.BluetileCommands

View File

@ -37,7 +37,7 @@ import XMonad.Prelude
-- $usage
--
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
-- You can use this module with the following in your @xmonad.hs@:
--
-- > import XMonad.Actions.Commands
--
@ -57,7 +57,7 @@ import XMonad.Prelude
-- bindings!)
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.
-- | Create a 'Data.Map.Map' from @String@s to xmonad actions from a
-- list of pairs.

View File

@ -26,7 +26,7 @@ import XMonad
-- $usage
--
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
-- You can use this module with the following in your @xmonad.hs@:
--
-- > import qualified XMonad.Actions.ConstrainedResize as Sqr
--
@ -44,8 +44,8 @@ import XMonad
-- | Resize (floating) window with optional aspect ratio constraints.
mouseResizeWindow :: Window -> Bool -> X ()
mouseResizeWindow w c = whenX (isClient w) $ withDisplay $ \d -> do
wa <- io $ getWindowAttributes d w
mouseResizeWindow w c = whenX (isClient w) $ withDisplay $ \d ->
withWindowAttributes d w $ \wa -> do
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

View File

@ -37,7 +37,7 @@ import qualified XMonad.StackSet as W
-- $usage
--
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@ file:
-- You can use this module with the following in your @xmonad.hs@ file:
--
-- > import XMonad.Actions.CopyWindow
--
@ -77,7 +77,7 @@ import qualified XMonad.StackSet as W
-- > , ((modm .|. shiftMask, xK_v ), killAllOtherCopies) -- @@ Toggle window state back
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.
-- $logHook
--
@ -114,10 +114,10 @@ copyWindow w n = copy'
where copy' s = if n `W.tagMember` s
then W.view (W.currentTag s) $ insertUp' w $ W.view n s
else s
insertUp' a s = W.modify (Just $ W.Stack a [] [])
insertUp' a = W.modify (Just $ W.Stack a [] [])
(\(W.Stack t l r) -> if a `elem` t:l++r
then Just $ W.Stack t l r
else Just $ W.Stack a (L.delete a l) (L.delete a (t:r))) s
else Just $ W.Stack a (L.delete a l) (L.delete a (t:r)))
-- | runOrCopy will run the provided shell command unless it can

View File

@ -1,6 +1,7 @@
{-# LANGUAGE CPP #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE MultiWayIf #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.CycleRecentWS
@ -35,21 +36,25 @@ module XMonad.Actions.CycleRecentWS (
#endif
) where
import XMonad.Actions.Repeatable (repeatableSt)
import XMonad hiding (workspaces)
import XMonad.StackSet hiding (filter)
import XMonad.Prelude (void, when)
import XMonad.StackSet hiding (filter, modify)
import Control.Arrow ((&&&))
import Data.Function (on)
import Control.Monad.State (lift)
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@ file:
-- You can use this module with the following in your @xmonad.hs@ file:
--
-- > import XMonad.Actions.CycleRecentWS
-- >
-- > , ((modm, xK_Tab), cycleRecentWS [xK_Alt_L] xK_Tab xK_grave)
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.
-- | Cycle through most recent workspaces with repeated presses of a key, while
-- a modifier key is held down. The recency of workspaces previewed while browsing
@ -111,25 +116,15 @@ cycleWindowSets :: (WindowSet -> [WorkspaceId]) -- ^ A function used to create a
-> X ()
cycleWindowSets genOptions mods keyNext keyPrev = do
(options, unView') <- gets $ (genOptions &&& unView) . windowset
XConf {theRoot = root, display = d} <- ask
let event = allocaXEvent $ \p -> do
maskEvent d (keyPressMask .|. keyReleaseMask) p
KeyEvent {ev_event_type = t, ev_keycode = c} <- getEvent p
s <- keycodeToKeysym d c 0
return (t, s)
let setOption n = do windows $ view (options `cycref` n) . unView'
(t, s) <- io event
case () of
() | t == keyPress && s == keyNext -> setOption (n+1)
| t == keyPress && s == keyPrev -> setOption (n-1)
| t == keyRelease && s `elem` mods -> return ()
| otherwise -> setOption n
io $ grabKeyboard d root False grabModeAsync grabModeAsync currentTime
setOption 0
io $ ungrabKeyboard d currentTime
where
cycref :: [a] -> Int -> a
cycref l i = l !! (i `mod` length l)
let
preview = do
i <- get
lift $ windows (view (options !! (i `mod` n)) . unView')
where n = length options
void . repeatableSt (-1) mods keyNext $ \t s -> when (t == keyPress) $ if
| s == keyNext -> modify succ >> preview
| s == keyPrev -> modify pred >> preview
| otherwise -> pure ()
-- | Given an old and a new 'WindowSet', which is __exactly__ one
-- 'view' away from the old one, restore the workspace order of the

View File

@ -23,7 +23,7 @@ import XMonad.Prelude (elemIndex, fromMaybe)
import qualified XMonad.StackSet as S
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
-- You can use this module with the following in your @xmonad.hs@:
--
-- > import XMonad
-- > import XMonad.Actions.CycleSelectedLayouts
@ -39,8 +39,9 @@ cycleToNext lst a = do
-- | If the current layout is in the list, cycle to the next layout. Otherwise,
-- apply the first layout from list.
cycleThroughLayouts :: [String] -> X ()
cycleThroughLayouts lst = do
cycleThroughLayouts [] = pure ()
cycleThroughLayouts lst@(x: _) = do
winset <- gets windowset
let ld = description . S.layout . S.workspace . S.current $ winset
let newld = fromMaybe (head lst) (cycleToNext lst ld)
let newld = fromMaybe x (cycleToNext lst ld)
sendMessage $ JumpToLayout newld

View File

@ -92,7 +92,7 @@ import XMonad.Util.Types
import XMonad.Util.WorkspaceCompare
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@ file:
-- You can use this module with the following in your @xmonad.hs@ file:
--
-- > import XMonad.Actions.CycleWS
-- >
@ -122,7 +122,7 @@ import XMonad.Util.WorkspaceCompare
-- > windows . view $ t )
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.
--
-- When using the toggle functions, in order to ensure that the workspace
-- to which you switch is the previously viewed workspace, use the

View File

@ -1,3 +1,5 @@
{-# LANGUAGE ViewPatterns, MultiWayIf #-}
--------------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.CycleWindows
@ -48,18 +50,21 @@ module XMonad.Actions.CycleWindows (
-- $pointer
-- * Generic list rotations
-- $generic
rotUp, rotDown
) where
import XMonad
import XMonad.Prelude
import qualified XMonad.StackSet as W
import qualified Data.List.NonEmpty as NE
import XMonad.Actions.RotSlaves
import XMonad.Actions.Repeatable (repeatableSt)
import Control.Arrow (second)
import Control.Monad.Trans (lift)
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@ file:
-- You can use this module with the following in your @xmonad.hs@ file:
--
-- > import XMonad.Actions.CycleWindows
-- > -- config
@ -75,7 +80,7 @@ import Control.Arrow (second)
--
-- Also, if you use focus follows mouse, you will want to read the section
-- on updating the mouse pointer below. For detailed instructions on
-- editing your key bindings, see "XMonad.Doc.Extending#Editing_key_bindings".
-- editing your key bindings, see <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.
{- $pointer
With FocusFollowsMouse == True, the focus is updated after binding
actions, possibly focusing a window you didn't intend to focus. Most
@ -135,27 +140,19 @@ cycleStacks' :: (W.Stack Window -> [W.Stack Window]) -- ^ A function to a finite
-> KeySym -- ^ Key used to select a \"previous\" stack.
-> X ()
cycleStacks' filteredPerms mods keyNext keyPrev = do
XConf {theRoot = root, display = d} <- ask
stacks <- gets $ maybe [] filteredPerms . W.stack . W.workspace . W.current . windowset
let evt = allocaXEvent $
\p -> do maskEvent d (keyPressMask .|. keyReleaseMask) p
KeyEvent {ev_event_type = t, ev_keycode = c} <- getEvent p
s <- keycodeToKeysym d c 0
return (t, s)
choose n (t, s)
| t == keyPress && s == keyNext = io evt >>= choose (n+1)
| t == keyPress && s == keyPrev = io evt >>= choose (n-1)
| t == keyPress && s `elem` [xK_0..xK_9] = io evt >>= choose (numKeyToN s)
| t == keyRelease && s `elem` mods = return ()
| otherwise = doStack n >> io evt >>= choose n
doStack n = windows . W.modify' . const $ stacks `cycref` n
io $ grabKeyboard d root False grabModeAsync grabModeAsync currentTime
io evt >>= choose 1
io $ ungrabKeyboard d currentTime
where cycref l i = l !! (i `mod` length l) -- modify' ensures l is never [], but must also be finite
numKeyToN = subtract 48 . read . show
stacks <- gets $ maybe [] filteredPerms
. W.stack . W.workspace . W.current . windowset
let
preview = do
i <- get
lift . windows . W.modify' . const $ stacks !! (i `mod` n)
where n = length stacks
void $ repeatableSt 0 mods keyNext $ \t s -> if
| t == keyPress && s == keyNext -> modify succ
| t == keyPress && s == keyPrev -> modify pred
| t == keyPress && s `elem` [xK_0..xK_9] -> put (numKeyToN s)
| otherwise -> preview
where numKeyToN = subtract 48 . read . show
-- | Given a stack element and a stack, shift or insert the element (window)
-- at the currently focused position.
@ -179,7 +176,7 @@ rotOpposite' :: W.Stack a -> W.Stack a
rotOpposite' (W.Stack t l r) = W.Stack t' l' r'
where rrvl = r ++ reverse l
part = (length rrvl + 1) `div` 2
(l',t':r') = second reverse . splitAt (length l) $
(l', notEmpty -> t' :| r') = second reverse . splitAt (length l) $
reverse (take part rrvl ++ t : drop part rrvl)
@ -205,7 +202,7 @@ rotFocusedDown = windows . W.modify' $ rotFocused' rotDown
rotFocused' :: ([a] -> [a]) -> W.Stack a -> W.Stack a
rotFocused' _ s@(W.Stack _ [] []) = s
rotFocused' f (W.Stack t [] (r:rs)) = W.Stack t' [] (r:rs') -- Master has focus
where (t':rs') = f (t:rs)
where (notEmpty -> t' :| rs') = f (t:rs)
rotFocused' f s@W.Stack{} = rotSlaves' f s -- otherwise
@ -223,14 +220,5 @@ rotUnfocused' :: ([a] -> [a]) -> W.Stack a -> W.Stack a
rotUnfocused' _ s@(W.Stack _ [] []) = s
rotUnfocused' f s@(W.Stack _ [] _ ) = rotSlaves' f s -- Master has focus
rotUnfocused' f (W.Stack t ls rs) = W.Stack t (reverse revls') rs' -- otherwise
where (master:revls) = reverse ls
where (master :| revls) = NE.reverse (let l:ll = ls in l :| ll)
(revls',rs') = splitAt (length ls) (f $ master:revls ++ rs)
-- $generic
-- Generic list rotations such that @rotUp [1..4]@ is equivalent to
-- @[2,3,4,1]@ and @rotDown [1..4]@ to @[4,1,2,3]@. They both are
-- @id@ for null or singleton lists.
rotUp :: [a] -> [a]
rotUp l = drop 1 l ++ take 1 l
rotDown :: [a] -> [a]
rotDown = reverse . rotUp . reverse

View File

@ -25,35 +25,36 @@ module XMonad.Actions.CycleWorkspaceByScreen (
import Data.IORef
import Graphics.X11.Xlib.Extras
import XMonad
import XMonad.Prelude
import XMonad.Hooks.WorkspaceHistory
import XMonad.Actions.Repeatable (repeatable)
import qualified XMonad.StackSet as W
-- $usage
-- This module must be used in conjuction with XMonad.Hooks.WorkspaceHistory
--
-- To use, add something like the following to your keybindings
-- , ((mod4Mask, xK_slash), cycleWorkspaceOnCurrentScreen [xK_Super_L] xK_slash xK_p)
-- To use this module, first import it as well as
-- "XMonad.Hooks.WorkspaceHistory":
--
-- > import XMonad.Hooks.WorkspaceHistory (workspaceHistoryHook)
-- > import XMonad.Actions.CycleWorkspaceByScreen
--
-- Then add 'workspaceHistoryHook' to your @logHook@ like this:
--
-- > main :: IO ()
-- > main = xmonad $ def
-- > { ...
-- > , logHook = workspaceHistoryHook >> ...
-- > }
--
-- Finally, define a new keybinding for cycling (seen) workspaces per
-- screen:
--
-- > , ((mod4Mask, xK_slash), cycleWorkspaceOnCurrentScreen [xK_Super_L] xK_slash xK_p)
repeatableAction :: [KeySym] -> (EventType -> KeySym -> X ()) -> X ()
repeatableAction mods pressHandler = do
XConf {theRoot = root, display = d} <- ask
let getNextEvent = io $ allocaXEvent $ \p ->
do
maskEvent d (keyPressMask .|. keyReleaseMask) p
KeyEvent {ev_event_type = t, ev_keycode = c} <- getEvent p
s <- io $ keycodeToKeysym d c 0
return (t, s)
handleEvent (t, s)
| t == keyRelease && s `elem` mods = return ()
| otherwise = pressHandler t s >> getNextEvent >>= handleEvent
io $ grabKeyboard d root False grabModeAsync grabModeAsync currentTime
getNextEvent >>= handleEvent
io $ ungrabKeyboard d currentTime
{-# DEPRECATED repeatableAction "Use XMonad.Actions.Repeatable.repeatable" #-}
repeatableAction :: [KeySym] -> KeySym -> (EventType -> KeySym -> X ()) -> X ()
repeatableAction = repeatable
handleKeyEvent :: EventType
-> KeySym
@ -72,7 +73,16 @@ runFirst :: [EventType -> KeySym -> Maybe (X ())] -> EventType -> KeySym -> X ()
runFirst matchers eventType key =
fromMaybe (return ()) $ join $ find isJust $ map (\fn -> fn eventType key) matchers
cycleWorkspaceOnScreen :: ScreenId -> [KeySym] -> KeySym -> KeySym -> X ()
-- | Like 'XMonad.Actions.CycleRecentWS.cycleRecentWS', but only cycle
-- through the most recent workspaces on the given screen.
cycleWorkspaceOnScreen
:: ScreenId -- ^ The screen to cycle on.
-> [KeySym] -- ^ A list of modifier keys used when invoking this
-- action; as soon as one of them is released, the final
-- switch is made.
-> KeySym -- ^ Key used to switch to next workspace.
-> KeySym -- ^ Key used to switch to previous workspace.
-> X ()
cycleWorkspaceOnScreen screenId mods nextKey prevKey = workspaceHistoryTransaction $ do
startingHistory <- workspaceHistoryByScreen
currentWSIndex <- io $ newIORef 1
@ -85,14 +95,15 @@ cycleWorkspaceOnScreen screenId mods nextKey prevKey = workspaceHistoryTransacti
return $ cycleWorkspaces !! current
focusIncrement i = io (getAndIncrementWS i) >>= (windows . W.greedyView)
focusIncrement 1 -- Do the first workspace cycle
repeatableAction mods $
repeatable mods nextKey $
runFirst
[ handleKeyEvent keyPress nextKey $ focusIncrement 1
, handleKeyEvent keyPress prevKey $ focusIncrement (-1)
]
return ()
-- | Like 'cycleWorkspaceOnScreen', but supply the currently focused
-- screen as the @screenId@.
cycleWorkspaceOnCurrentScreen
:: [KeySym] -> KeySym -> KeySym -> X ()
cycleWorkspaceOnCurrentScreen mods n p =

View File

@ -39,7 +39,7 @@ import qualified XMonad.StackSet as W
import XMonad
-- $usage
-- To use demanage, add this import to your @~\/.xmonad\/xmonad.hs@:
-- To use demanage, add this import to your @xmonad.hs@:
--
-- > import XMonad.Actions.DeManage
--
@ -48,7 +48,7 @@ import XMonad
-- > , ((modm, xK_d ), withFocused demanage)
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.
-- | Stop managing the currently focused window.
demanage :: Window -> X ()

View File

@ -25,10 +25,13 @@ module XMonad.Actions.DwmPromote (
import XMonad
import XMonad.StackSet
import XMonad.Prelude
import qualified Data.List.NonEmpty as NE
-- $usage
--
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
-- You can use this module with the following in your @xmonad.hs@:
--
-- > import XMonad.Actions.DwmPromote
--
@ -37,7 +40,7 @@ import XMonad.StackSet
-- > , ((modm, xK_Return), dwmpromote)
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.
-- | Swap the focused window with the master window. If focus is in
-- the master, swap it with the next window in the stack. Focus
@ -46,5 +49,5 @@ dwmpromote :: X ()
dwmpromote = windows $ modify' $
\c -> case c of
Stack _ [] [] -> c
Stack t [] (x:rs) -> Stack x [] (t:rs)
Stack t ls rs -> Stack t [] (ys ++ x : rs) where (x:ys) = reverse ls
Stack t [] (r:rs) -> Stack r [] (t:rs)
Stack t (l:ls) rs -> Stack t [] (ys ++ y : rs) where (y :| ys) = NE.reverse (l :| ls)

View File

@ -69,7 +69,9 @@ import qualified XMonad.Util.ExtensibleState as XS
-- the working directory to the one configured for the matching
-- project. If the workspace doesn't have any windows, the project's
-- start-up hook is executed. This allows you to launch applications
-- or further configure the workspace/project.
-- or further configure the workspace/project. To close a project,
-- you can use the functions provided by "XMonad.Actions.DynamicWorkspaces",
-- such as @removeWorkspace@ or @removeWorkspaceByTag@.
--
-- When using the @switchProjectPrompt@ function, workspaces are
-- created as needed. This means you can create new project spaces
@ -109,11 +111,11 @@ import qualified XMonad.Util.ExtensibleState as XS
--
-- And finally, configure some optional key bindings:
--
-- > , ((modm, xK_space), switchProjectPrompt)
-- > , ((modm, xK_slash), shiftToProjectPrompt)
-- > , ((modm, xK_space), switchProjectPrompt def)
-- > , ((modm, xK_slash), shiftToProjectPrompt def)
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.
--------------------------------------------------------------------------------
type ProjectName = String
@ -230,7 +232,9 @@ lookupProject name = Map.lookup name <$> XS.gets projects
--------------------------------------------------------------------------------
-- | Fetch the current project (the one being used for the currently
-- active workspace).
-- active workspace). If the workspace doesn't have a project, a
-- default project is returned, using the workspace name as the
-- project name.
currentProject :: X Project
currentProject = do
name <- gets (W.tag . W.workspace . W.current . windowset)
@ -255,20 +259,7 @@ modifyProject f = do
--------------------------------------------------------------------------------
-- | Switch to the given project.
switchProject :: Project -> X ()
switchProject p = do
oldws <- gets (W.workspace . W.current . windowset)
oldp <- currentProject
let name = W.tag oldws
ws = W.integrate' (W.stack oldws)
-- If the project we are switching away from has no windows, and
-- it's a dynamic project, remove it from the configuration.
when (null ws && isNothing (projectStartHook oldp)) $ do
removeWorkspaceByTag name -- also remove the old workspace
XS.modify (\s -> s {projects = Map.delete name $ projects s})
appendWorkspace (projectName p)
switchProject p = appendWorkspace (projectName p)
--------------------------------------------------------------------------------
-- | Prompt for a project name and then switch to it. Automatically

View File

@ -51,7 +51,7 @@ import qualified XMonad.Util.ExtensibleState as XS
import XMonad.Actions.TopicSpace
-- $usage
-- You can use this module by importing it into your ~\/.xmonad\/xmonad.hs file:
-- You can use this module by importing it into your @xmonad.hs@ file:
--
-- > import XMonad.Actions.DynamicWorkspaceGroups
--

View File

@ -49,7 +49,7 @@ import XMonad.Prelude (fromJust, fromMaybe)
import Data.Ord (comparing)
-- $usage
-- You can use this module by importing it into your ~\/.xmonad\/xmonad.hs file:
-- You can use this module by importing it into your @xmonad.hs@ file:
--
-- > import qualified XMonad.Actions.DynamicWorkspaceOrder as DO
--
@ -152,7 +152,8 @@ swapOrder :: WorkspaceId -> WorkspaceId -> X ()
swapOrder w1 w2 = do
io $ print (w1,w2)
WSO (Just m) <- XS.get
let [i1,i2] = map (fromJust . flip M.lookup m) [w1,w2]
let i1 = fromJust (w1 `M.lookup` m)
let i2 = fromJust (w2 `M.lookup` m)
XS.modify (withWSO (M.insert w1 i2 . M.insert w2 i1))
windows id -- force a status bar update

View File

@ -38,13 +38,13 @@ import XMonad.Prelude (find, isNothing, nub, when)
import XMonad hiding (workspaces)
import XMonad.StackSet hiding (filter, modify, delete)
import XMonad.Prompt.Workspace ( Wor(Wor), workspacePrompt )
import XMonad.Prompt ( XPConfig, mkXPrompt )
import XMonad.Prompt ( XPConfig, mkComplFunFromList', mkXPrompt )
import XMonad.Util.WorkspaceCompare ( getSortByIndex )
import qualified Data.Map.Strict as Map
import qualified XMonad.Util.ExtensibleState as XS
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@ file:
-- You can use this module with the following in your @xmonad.hs@ file:
--
-- > import XMonad.Actions.DynamicWorkspaces
-- > import XMonad.Actions.CopyWindow(copy)
@ -75,7 +75,7 @@ import qualified XMonad.Util.ExtensibleState as XS
-- > zip (zip (repeat (modm .|. controlMask)) [xK_1..xK_9]) (map (setWorkspaceIndex) [1..])
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings". See also the documentation for
-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>. See also the documentation for
-- "XMonad.Actions.CopyWindow", 'windows', 'shift', and 'XPConfig'.
type WorkspaceTag = String
@ -107,17 +107,13 @@ withWorkspaceIndex job widx = do
ilookup :: WorkspaceIndex -> X (Maybe WorkspaceTag)
ilookup idx = Map.lookup idx <$> XS.gets workspaceIndexMap
mkCompl :: [String] -> String -> IO [String]
mkCompl l s = return $ filter (\x -> take (length s) x == s) l
withWorkspace :: XPConfig -> (String -> X ()) -> X ()
withWorkspace c job = do ws <- gets (workspaces . windowset)
sort <- getSortByIndex
let ts = map tag $ sort ws
job' t | t `elem` ts = job t
| otherwise = addHiddenWorkspace t >> job t
mkXPrompt (Wor "") c (mkCompl ts) job'
mkXPrompt (Wor "") c (mkComplFunFromList' c ts) job'
renameWorkspace :: XPConfig -> X ()
renameWorkspace conf = workspacePrompt conf renameWorkspaceByName

View File

@ -1,4 +1,5 @@
{-# LANGUAGE CPP #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE ScopedTypeVariables #-}
-----------------------------------------------------------------------------
@ -50,7 +51,7 @@ import qualified Data.Map.Strict as M (Map, elems, map, mapWithKey)
-- $usage
--
-- You can use this module's basic functionality with the following in your
-- @~\/.xmonad\/xmonad.hs@:
-- @xmonad.hs@:
--
-- > import XMonad.Actions.EasyMotion (selectWindow)
--
@ -263,19 +264,19 @@ handleSelectWindow c = do
visibleWindows :: [Window]
visibleWindows = toList mappedWins
sortedOverlayWindows :: X [OverlayWindow]
sortedOverlayWindows = sortOverlayWindows <$> buildOverlayWindows dpy th visibleWindows
sortedOverlayWindows = sortOverlayWindows <$> buildOverlayWindows th visibleWindows
PerScreenKeys m ->
fmap concat
$ sequence
$ M.elems
$ M.mapWithKey (\sid ks -> buildOverlays ks <$> sortedOverlayWindows sid) m
where
screenById :: ScreenId -> Maybe (W.Screen WorkspaceId (Layout Window) Window ScreenId ScreenDetail)
screenById :: ScreenId -> Maybe WindowScreen
screenById sid = find ((== sid) . W.screen) (W.screens ws)
visibleWindowsOnScreen :: ScreenId -> [Window]
visibleWindowsOnScreen sid = filter (`elem` toList mappedWins) $ W.integrate' $ screenById sid >>= W.stack . W.workspace
sortedOverlayWindows :: ScreenId -> X [OverlayWindow]
sortedOverlayWindows sid = sortOverlayWindows <$> buildOverlayWindows dpy th (visibleWindowsOnScreen sid)
sortedOverlayWindows sid = sortOverlayWindows <$> buildOverlayWindows th (visibleWindowsOnScreen sid)
status <- io $ grabKeyboard dpy rw True grabModeAsync grabModeAsync currentTime
if status == grabSuccess
then do
@ -296,10 +297,11 @@ handleSelectWindow c = do
allKeys (PerScreenKeys m) = concat $ M.elems m
buildOverlays :: [KeySym] -> [OverlayWindow] -> [Overlay]
buildOverlays ks = appendChords (maxChordLen c) ks
buildOverlays = appendChords (maxChordLen c)
buildOverlayWindows :: Display -> Position -> [Window] -> X [OverlayWindow]
buildOverlayWindows dpy th ws = sequence $ buildOverlayWin dpy th <$> ws
buildOverlayWindows :: Position -> [Window] -> X [OverlayWindow]
buildOverlayWindows th = fmap (fromMaybe [] . sequenceA)
. traverse (buildOverlayWin th)
sortOverlayWindows :: [OverlayWindow] -> [OverlayWindow]
sortOverlayWindows = sortOn ((wa_x &&& wa_y) . attrs)
@ -307,12 +309,13 @@ handleSelectWindow c = do
makeRect :: WindowAttributes -> Rectangle
makeRect wa = Rectangle (fi (wa_x wa)) (fi (wa_y wa)) (fi (wa_width wa)) (fi (wa_height wa))
buildOverlayWin :: Display -> Position -> Window -> X OverlayWindow
buildOverlayWin dpy th w = do
wAttrs <- io $ getWindowAttributes dpy w
buildOverlayWin :: Position -> Window -> X (Maybe OverlayWindow)
buildOverlayWin th w = safeGetWindowAttributes w >>= \case
Nothing -> pure Nothing
Just wAttrs -> do
let r = overlayF c th $ makeRect wAttrs
o <- createNewWindow r Nothing "" True
return OverlayWindow { rect=r, overlay=o, win=w, attrs=wAttrs }
return . Just $ OverlayWindow { rect=r, overlay=o, win=w, attrs=wAttrs }
-- | Display an overlay with the provided formatting
displayOverlay :: XMonadFont -> Overlay -> X ()
@ -384,5 +387,5 @@ handleKeyboard dpy drawFn cancel selected deselected = do
_ -> handleKeyboard dpy drawFn cancel (trim fg) (clear bg) >>= retryBackspace
where
(fg, bg) = partition ((== Just keySym) . listToMaybe . chord) selected
trim = map (\o -> o { chord = tail $ chord o })
trim = map (\o -> o { chord = drop 1 $ chord o })
clear = map (\o -> o { chord = [] })

View File

@ -25,7 +25,7 @@ import XMonad.StackSet
-- $usage
--
-- To use, import this module into your @~\/.xmonad\/xmonad.hs@:
-- To use, import this module into your @xmonad.hs@:
--
-- > import XMonad.Actions.FindEmptyWorkspace
--
@ -38,7 +38,7 @@ import XMonad.StackSet
-- will tag the current window to an empty workspace and view it.
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.
-- | Find the first hidden empty workspace in a StackSet. Returns
-- Nothing if all workspaces are in use. Function searches currently

View File

@ -24,12 +24,12 @@ module XMonad.Actions.FlexibleManipulate (
) where
import XMonad
import XMonad.Prelude ((<&>))
import XMonad.Prelude ((<&>), fi)
import qualified Prelude as P
import Prelude (Double, Integer, Ord (..), const, fromIntegral, fst, id, map, otherwise, round, snd, uncurry, ($), (.))
import Prelude (Double, Integer, Ord (..), const, fromIntegral, fst, id, otherwise, round, snd, uncurry, ($))
-- $usage
-- First, add this import to your @~\/.xmonad\/xmonad.hs@:
-- First, add this import to your @xmonad.hs@:
--
-- > import qualified XMonad.Actions.FlexibleManipulate as Flex
--
@ -80,8 +80,10 @@ position = const 0.5
-- | Given an interpolation function, implement an appropriate window
-- manipulation action.
mouseWindow :: (Double -> Double) -> Window -> X ()
mouseWindow f w = whenX (isClient w) $ withDisplay $ \d -> do
[wpos, wsize] <- io $ getWindowAttributes d w <&> winAttrs
mouseWindow f w = whenX (isClient w) $ withDisplay $ \d ->
withWindowAttributes d w $ \wa -> do
let wpos = (fi (wa_x wa), fi (wa_y wa))
wsize = (fi (wa_width wa), fi (wa_height wa))
sh <- io $ getWMNormalHints d w
pointer <- io $ queryPointer d w <&> pointerPos
@ -104,18 +106,10 @@ mouseWindow f w = whenX (isClient w) $ withDisplay $ \d -> do
where
pointerPos (_,_,_,px,py,_,_,_) = (fromIntegral px,fromIntegral py) :: Pnt
winAttrs :: WindowAttributes -> [Pnt]
winAttrs x = pairUp $ map (fromIntegral . ($ x)) [wa_x, wa_y, wa_width, wa_height]
-- I'd rather I didn't have to do this, but I hate writing component 2d math
type Pnt = (Double, Double)
pairUp :: [a] -> [(a,a)]
pairUp [] = []
pairUp [_] = []
pairUp (x:y:xs) = (x, y) : pairUp xs
mapP :: (a -> b) -> (a, a) -> (b, b)
mapP f (x, y) = (f x, f y)
zipP :: (a -> b -> c) -> (a,a) -> (b,b) -> (c,c)

View File

@ -25,7 +25,7 @@ import XMonad.Prelude (fi)
import Foreign.C.Types
-- $usage
-- To use, first import this module into your @~\/.xmonad\/xmonad.hs@ file:
-- To use, first import this module into your @xmonad.hs@ file:
--
-- > import qualified XMonad.Actions.FlexibleResize as Flex
--
@ -50,12 +50,15 @@ mouseResizeEdgeWindow
:: Rational -- ^ The size of the area where only one edge is resized.
-> Window -- ^ The window to resize.
-> X ()
mouseResizeEdgeWindow edge w = whenX (isClient w) $ withDisplay $ \d -> do
wa <- io $ getWindowAttributes d w
mouseResizeEdgeWindow edge w = whenX (isClient w) $ withDisplay $ \d ->
withWindowAttributes d w $ \wa -> do
sh <- io $ getWMNormalHints d w
(_, _, _, _, _, ix, iy, _) <- io $ queryPointer d w
let
[pos_x, pos_y, width, height] = map (fi . ($ wa)) [wa_x, wa_y, wa_width, wa_height]
pos_x = fi $ wa_x wa
pos_y = fi $ wa_y wa
width = fi $ wa_width wa
height = fi $ wa_height wa
west = findPos ix width
north = findPos iy height
(cx, fx, gx) = mkSel west width pos_x

View File

@ -19,14 +19,18 @@ module XMonad.Actions.FloatKeys (
keysMoveWindowTo,
keysResizeWindow,
keysAbsResizeWindow,
P, G,
directionMoveWindow,
directionResizeWindow,
Direction2D(..),
P, G, ChangeDim
) where
import XMonad
import XMonad.Prelude (fi)
import XMonad.Util.Types
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
-- You can use this module with the following in your @xmonad.hs@:
--
-- > import XMonad.Actions.FloatKeys
--
@ -38,14 +42,42 @@ import XMonad.Prelude (fi)
-- > , ((modm .|. shiftMask, xK_s ), withFocused (keysAbsResizeWindow (10,10) (1024,752)))
-- > , ((modm, xK_a ), withFocused (keysMoveWindowTo (512,384) (1%2,1%2)))
--
-- Using "XMonad.Util.EZConfig" syntax, we can easily build keybindings
-- where @M-\<arrow-keys\>@ moves the currently focused window and
-- @M-S-\<arrow-keys\>@ resizes it using 'directionMoveWindow' and
-- 'directionResizeWindow':
--
-- > [ ("M-" <> m <> k, withFocused $ f i)
-- > | (i, k) <- zip [U, D, R, L] ["<Up>", "<Down>", "<Right>", "<Left>"]
-- > , (f, m) <- [(directionMoveWindow 10, ""), (directionResizeWindow 10, "S-")]
-- > ]
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.
-- | @directionMoveWindow delta dir win@ moves the window @win@ by
-- @delta@ pixels in direction @dir@.
directionMoveWindow :: Int -> Direction2D -> Window -> X ()
directionMoveWindow delta dir win = case dir of
U -> keysMoveWindow (0, -delta) win
D -> keysMoveWindow (0, delta) win
R -> keysMoveWindow (delta, 0) win
L -> keysMoveWindow (-delta, 0) win
-- | @directionResizeWindow delta dir win@ resizes the window @win@ by
-- @delta@ pixels in direction @dir@.
directionResizeWindow :: Int -> Direction2D -> Window -> X ()
directionResizeWindow delta dir win = case dir of
U -> keysResizeWindow (0, -delta) (0, 0) win
D -> keysResizeWindow (0, delta) (0, 0) win
R -> keysResizeWindow (delta, 0) (0, 0) win
L -> keysResizeWindow (-delta, 0) (0, 0) win
-- | @keysMoveWindow (dx, dy)@ moves the window by @dx@ pixels to the
-- right and @dy@ pixels down.
keysMoveWindow :: D -> Window -> X ()
keysMoveWindow (dx,dy) w = whenX (isClient w) $ withDisplay $ \d -> do
wa <- io $ getWindowAttributes d w
keysMoveWindow :: ChangeDim -> Window -> X ()
keysMoveWindow (dx,dy) w = whenX (isClient w) $ withDisplay $ \d ->
withWindowAttributes d w $ \wa -> do
io $ moveWindow d w (fi (fi (wa_x wa) + dx))
(fi (fi (wa_y wa) + dy))
float w
@ -61,8 +93,8 @@ keysMoveWindow (dx,dy) w = whenX (isClient w) $ withDisplay $ \d -> do
-- > keysMoveWindowTo (512,384) (1%2, 1%2) -- center the window on screen
-- > keysMoveWindowTo (1024,0) (1, 0) -- put window in the top right corner
keysMoveWindowTo :: P -> G -> Window -> X ()
keysMoveWindowTo (x,y) (gx, gy) w = whenX (isClient w) $ withDisplay $ \d -> do
wa <- io $ getWindowAttributes d w
keysMoveWindowTo (x,y) (gx, gy) w = whenX (isClient w) $ withDisplay $ \d ->
withWindowAttributes d w $ \wa -> do
io $ moveWindow d w (x - round (gx * fi (wa_width wa)))
(y - round (gy * fi (wa_height wa)))
float w
@ -113,8 +145,8 @@ keysResizeWindow' sh (x,y) (w,h) (dx,dy) (gx, gy) = ((nx, ny), (nw, nh))
ny = round $ fi y + gy * fi h - gy * fi nh
keysMoveResize :: (SizeHints -> P -> D -> a -> b -> (P,D)) -> a -> b -> Window -> X ()
keysMoveResize f move resize w = whenX (isClient w) $ withDisplay $ \d -> do
wa <- io $ getWindowAttributes d w
keysMoveResize f move resize w = whenX (isClient w) $ withDisplay $ \d ->
withWindowAttributes d w $ \wa -> do
sh <- io $ getWMNormalHints d w
let wa_dim = (fi $ wa_width wa, fi $ wa_height wa)
wa_pos = (fi $ wa_x wa, fi $ wa_y wa)

View File

@ -37,7 +37,7 @@ import XMonad.Util.Types (Direction2D(..))
import XMonad.Actions.AfterDrag
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
-- You can use this module with the following in your @xmonad.hs@:
--
-- > import XMonad.Actions.FloatSnap
--
@ -53,7 +53,7 @@ import XMonad.Actions.AfterDrag
-- > , ((modm .|. shiftMask, xK_Down), withFocused $ snapGrow D Nothing)
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.
--
-- And possibly add appropriate mouse bindings, for example:
--
@ -92,8 +92,8 @@ snapMagicMouseResize
-> Maybe Int -- ^ The maximum distance to snap. Use Nothing to not impose any boundary.
-> Window -- ^ The window to move and resize.
-> X ()
snapMagicMouseResize middle collidedist snapdist w = whenX (isClient w) $ withDisplay $ \d -> do
wa <- io $ getWindowAttributes d w
snapMagicMouseResize middle collidedist snapdist w = whenX (isClient w) $ withDisplay $ \d ->
withWindowAttributes d w $ \wa -> do
(_, _, _, px, py, _, _, _) <- io $ queryPointer d w
let x = (fromIntegral px - wx wa)/ww wa
y = (fromIntegral py - wy wa)/wh wa
@ -119,9 +119,8 @@ snapMagicResize
-> Maybe Int -- ^ The maximum distance to snap. Use Nothing to not impose any boundary.
-> Window -- ^ The window to move and resize.
-> X ()
snapMagicResize dir collidedist snapdist w = whenX (isClient w) $ withDisplay $ \d -> do
wa <- io $ getWindowAttributes d w
snapMagicResize dir collidedist snapdist w = whenX (isClient w) $ withDisplay $ \d ->
withWindowAttributes d w $ \wa -> do
(xbegin,xend) <- handleAxis True d wa
(ybegin,yend) <- handleAxis False d wa
@ -168,9 +167,8 @@ snapMagicMove
-> Maybe Int -- ^ The maximum distance to snap. Use Nothing to not impose any boundary.
-> Window -- ^ The window to move.
-> X ()
snapMagicMove collidedist snapdist w = whenX (isClient w) $ withDisplay $ \d -> do
wa <- io $ getWindowAttributes d w
snapMagicMove collidedist snapdist w = whenX (isClient w) $ withDisplay $ \d ->
withWindowAttributes d w $ \wa -> do
nx <- handleAxis True d wa
ny <- handleAxis False d wa
@ -208,8 +206,8 @@ snapMove U = doSnapMove False True
snapMove D = doSnapMove False False
doSnapMove :: Bool -> Bool -> Maybe Int -> Window -> X ()
doSnapMove horiz rev collidedist w = whenX (isClient w) $ withDisplay $ \d -> do
wa <- io $ getWindowAttributes d w
doSnapMove horiz rev collidedist w = whenX (isClient w) $ withDisplay $ \d ->
withWindowAttributes d w $ \wa -> do
((bl,br,_),(fl,fr,_)) <- getSnap horiz collidedist d w
let (mb,mf) = if rev then (bl,fl)
@ -247,8 +245,8 @@ snapShrink
snapShrink = snapResize False
snapResize :: Bool -> Direction2D -> Maybe Int -> Window -> X ()
snapResize grow dir collidedist w = whenX (isClient w) $ withDisplay $ \d -> do
wa <- io $ getWindowAttributes d w
snapResize grow dir collidedist w = whenX (isClient w) $ withDisplay $ \d ->
withWindowAttributes d w $ \wa -> do
mr <- case dir of
L -> do ((mg,ms,_),(_,_,_)) <- getSnap True collidedist d w
return $ case (if grow then mg else ms) of

View File

@ -1,3 +1,5 @@
{-# LANGUAGE ViewPatterns #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.FocusNth
@ -18,11 +20,12 @@ module XMonad.Actions.FocusNth (
focusNth,focusNth',
swapNth,swapNth') where
import XMonad.StackSet
import XMonad
import XMonad.Prelude
import XMonad.StackSet
-- $usage
-- Add the import to your @~\/.xmonad\/xmonad.hs@:
-- Add the import to your @xmonad.hs@:
--
-- > import XMonad.Actions.FocusNth
--
@ -33,15 +36,15 @@ import XMonad
-- > | (i, k) <- zip [0 .. 8] [xK_1 ..]]
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.
-- | Give focus to the nth window of the current workspace.
focusNth :: Int -> X ()
focusNth = windows . modify' . focusNth'
focusNth' :: Int -> Stack a -> Stack a
focusNth' n s@(Stack _ ls rs) | (n < 0) || (n > length ls + length rs) = s
| otherwise = listToStack n (integrate s)
focusNth' n s | n >= 0, (ls, t:rs) <- splitAt n (integrate s) = Stack t (reverse ls) rs
| otherwise = s
-- | Swap current window with nth. Focus stays in the same position
swapNth :: Int -> X ()
@ -50,11 +53,5 @@ swapNth = windows . modify' . swapNth'
swapNth' :: Int -> Stack a -> Stack a
swapNth' n s@(Stack c l r)
| (n < 0) || (n > length l + length r) || (n == length l) = s
| n < length l = let (nl, nc:nr) = splitAt (length l - n - 1) l in Stack nc (nl ++ c : nr) r
| otherwise = let (nl, nc:nr) = splitAt (n - length l - 1) r in Stack nc l (nl ++ c : nr)
listToStack :: Int -> [a] -> Stack a
listToStack n l = Stack t ls rs
where
(t:rs) = drop n l
ls = reverse (take n l)
| n < length l = let (nl, notEmpty -> nc :| nr) = splitAt (length l - n - 1) l in Stack nc (nl ++ c : nr) r
| otherwise = let (nl, notEmpty -> nc :| nr) = splitAt (n - length l - 1) r in Stack nc l (nl ++ c : nr)

View File

@ -97,10 +97,11 @@ import XMonad.Actions.WindowBringer (bringWindow)
import Text.Printf
import System.Random (mkStdGen, randomR)
import Data.Word (Word8)
import qualified Data.List.NonEmpty as NE
-- $usage
--
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
-- You can use this module with the following in your @xmonad.hs@:
--
-- > import XMonad.Actions.GridSelect
--
@ -124,7 +125,7 @@ import Data.Word (Word8)
-- > ...
-- > gsconfig1 = def { gs_cellheight = 30, gs_cellwidth = 100 }
--
-- An example where 'buildDefaultGSConfig' is used instead of 'defaultGSConfig'
-- An example where 'buildDefaultGSConfig' is used instead of 'def'
-- in order to specify a custom colorizer is @gsconfig2@ (found in
-- "XMonad.Actions.GridSelect#Colorizers"):
--
@ -143,7 +144,7 @@ import Data.Word (Word8)
-- Then you can bind to:
--
-- > ,((modm, xK_g), goToSelected $ gsconfig2 myWinColorizer)
-- > ,((modm, xK_p), spawnSelected $ spawnSelected defaultColorizer)
-- > ,((modm, xK_p), spawnSelected (gsconfig2 defaultColorizer) ["xterm","gvim"])
-- $keybindings
--
@ -202,10 +203,13 @@ data GSConfig a = GSConfig {
gs_colorizer :: a -> Bool -> X (String, String),
gs_font :: String,
gs_navigate :: TwoD a (Maybe a),
-- ^ Customize key bindings for a GridSelect
gs_rearranger :: Rearranger a,
gs_originFractX :: Double,
gs_originFractY :: Double,
gs_bordercolor :: String
gs_bordercolor :: String,
gs_cancelOnEmptyClick :: Bool
-- ^ When True, click on empty space will cancel GridSelect
}
-- | That is 'fromClassName' if you are selecting a 'Window', or
@ -285,11 +289,7 @@ orderElementmap searchString elements = if not $ null searchString then sortedEl
newtype TwoD a b = TwoD { unTwoD :: StateT (TwoDState a) X b }
deriving (Monad,Functor,MonadState (TwoDState a))
instance Applicative (TwoD a) where
(<*>) = ap
pure = return
deriving (Functor, Applicative, Monad, MonadState (TwoDState a))
liftX :: X a1 -> TwoD a a1
liftX = TwoD . lift
@ -306,14 +306,14 @@ diamondLayer n =
r = tr ++ map (\(x,y) -> (y,-x)) tr
in r ++ map (negate *** negate) r
diamond :: (Enum a, Num a, Eq a) => [(a, a)]
diamond = concatMap diamondLayer [0..]
diamond :: (Enum a, Num a, Eq a) => Stream (a, a)
diamond = fromList $ concatMap diamondLayer [0..]
diamondRestrict :: Integer -> Integer -> Integer -> Integer -> [(Integer, Integer)]
diamondRestrict x y originX originY =
L.filter (\(x',y') -> abs x' <= x && abs y' <= y) .
map (\(x', y') -> (x' + fromInteger originX, y' + fromInteger originY)) .
take 1000 $ diamond
takeS 1000 $ diamond
findInElementMap :: (Eq a) => a -> [(a, b)] -> Maybe (a, b)
findInElementMap pos = find ((== pos) . fst)
@ -389,13 +389,20 @@ updateElementsWithColorizer colorizer elementmap = do
stdHandle :: Event -> TwoD a (Maybe a) -> TwoD a (Maybe a)
stdHandle ButtonEvent{ ev_event_type = t, ev_x = x, ev_y = y } contEventloop
| t == buttonRelease = do
s@TwoDState { td_paneX = px, td_paneY = py,
td_gsconfig = (GSConfig ch cw _ _ _ _ _ _ _ _) } <- get
s@TwoDState{ td_paneX = px
, td_paneY = py
, td_gsconfig = GSConfig{ gs_cellheight = ch
, gs_cellwidth = cw
, gs_cancelOnEmptyClick = cancelOnEmptyClick
}
} <- get
let gridX = (fi x - (px - cw) `div` 2) `div` cw
gridY = (fi y - (py - ch) `div` 2) `div` ch
case lookup (gridX,gridY) (td_elementmap s) of
Just (_,el) -> return (Just el)
Nothing -> contEventloop
Nothing -> if cancelOnEmptyClick
then return Nothing
else contEventloop
| otherwise = contEventloop
stdHandle ExposeEvent{} contEventloop = updateAllElements >> contEventloop
@ -411,10 +418,11 @@ makeXEventhandler keyhandler = fix $ \me -> join $ liftX $ withDisplay $ \d -> l
ev <- getEvent e
if ev_event_type ev == keyPress
then do
(ks,s) <- lookupString $ asKeyEvent e
(_, s) <- lookupString $ asKeyEvent e
ks <- keycodeToKeysym d (ev_keycode ev) 0
return $ do
mask <- liftX $ cleanMask (ev_state ev)
keyhandler (fromMaybe xK_VoidSymbol ks, s, mask)
mask <- liftX $ cleanKeyMask <*> pure (ev_state ev)
keyhandler (ks, s, mask)
else
return $ stdHandle ev me
@ -650,7 +658,7 @@ gridselect gsconfig elements =
liftIO $ mapWindow dpy win
liftIO $ selectInput dpy win (exposureMask .|. keyPressMask .|. buttonReleaseMask)
status <- io $ grabKeyboard dpy win True grabModeAsync grabModeAsync currentTime
io $ grabPointer dpy win True buttonReleaseMask grabModeAsync grabModeAsync none none currentTime
void $ io $ grabPointer dpy win True buttonReleaseMask grabModeAsync grabModeAsync none none currentTime
font <- initXMF (gs_font gsconfig)
let screenWidth = toInteger $ rect_width scr
screenHeight = toInteger $ rect_height scr
@ -661,7 +669,7 @@ gridselect gsconfig elements =
originPosX = floor $ (gs_originFractX gsconfig - (1/2)) * 2 * fromIntegral restrictX
originPosY = floor $ (gs_originFractY gsconfig - (1/2)) * 2 * fromIntegral restrictY
coords = diamondRestrict restrictX restrictY originPosX originPosY
s = TwoDState { td_curpos = head coords,
s = TwoDState { td_curpos = NE.head (notEmpty coords),
td_availSlots = coords,
td_elements = elements,
td_gsconfig = gsconfig,
@ -708,7 +716,7 @@ decorateName' w = do
-- | Builds a default gs config from a colorizer function.
buildDefaultGSConfig :: (a -> Bool -> X (String,String)) -> GSConfig a
buildDefaultGSConfig col = GSConfig 50 130 10 col "xft:Sans-8" defaultNavigation noRearranger (1/2) (1/2) "white"
buildDefaultGSConfig col = GSConfig 50 130 10 col "xft:Sans-8" defaultNavigation noRearranger (1/2) (1/2) "white" True
-- | Brings selected window to the current workspace.
bringSelected :: GSConfig Window -> X ()

View File

@ -1,3 +1,4 @@
{-# language DeriveGeneric, DeriveAnyClass #-}
----------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.GroupNavigation
@ -32,25 +33,27 @@ module XMonad.Actions.GroupNavigation ( -- * Usage
, isOnAnyVisibleWS
) where
import Control.Monad.Reader
import Control.Monad.State
import Control.Monad.Reader (ask, asks)
import Control.Monad.State (gets)
import Control.DeepSeq
import Data.Map ((!))
import qualified Data.Map as Map
import Data.Sequence (Seq, ViewL (EmptyL, (:<)), viewl, (<|), (><), (|>))
import qualified Data.Sequence as Seq
import qualified Data.Set as Set
import Graphics.X11.Types
import Prelude hiding (concatMap, drop, elem, filter, null, reverse)
import GHC.Generics
import Prelude hiding (drop, elem, filter, null, reverse)
import XMonad.Core
import XMonad.ManageHook
import XMonad.Operations (windows, withFocused)
import XMonad.Prelude (elem, foldl')
import XMonad.Prelude (elem, foldl', (>=>))
import qualified XMonad.StackSet as SS
import qualified XMonad.Util.ExtensibleState as XS
{- $usage
Import the module into your @~\/.xmonad\/xmonad.hs@:
Import the module into your @xmonad.hs@:
> import XMonad.Actions.GroupNavigation
@ -126,7 +129,7 @@ focusNextMatchOrDo qry act = findM (runQuery qry)
>=> maybe act (windows . SS.focusWindow)
-- Returns the list of windows ordered by workspace as specified in
-- ~/.xmonad/xmonad.hs
-- @xmonad.hs@.
orderedWindowList :: Direction -> X (Seq Window)
orderedWindowList History = fmap (\(HistoryDB w ws) -> maybe ws (ws |>) w) XS.get
orderedWindowList dir = withWindowSet $ \ss -> do
@ -142,7 +145,7 @@ orderedWindowList dir = withWindowSet $ \ss -> do
dirfun _ = id
rotfun wins x = rotate $ rotateTo (== x) wins
-- Returns the ordered workspace list as specified in ~/.xmonad/xmonad.hs
-- Returns the ordered workspace list as specified in @xmonad.hs@.
orderedWorkspaceList :: WindowSet -> Seq String -> Seq WindowSpace
orderedWorkspaceList ss wsids = rotateTo isCurWS wspcs'
where
@ -156,7 +159,7 @@ orderedWorkspaceList ss wsids = rotateTo isCurWS wspcs'
-- The state extension that holds the history information
data HistoryDB = HistoryDB (Maybe Window) -- currently focused window
(Seq Window) -- previously focused windows
deriving (Read, Show)
deriving (Read, Show, Generic, NFData)
instance ExtensionClass HistoryDB where
@ -166,15 +169,15 @@ instance ExtensionClass HistoryDB where
-- | Action that needs to be executed as a logHook to maintain the
-- focus history of all windows as the WindowSet changes.
historyHook :: X ()
historyHook = XS.get >>= updateHistory >>= XS.put
historyHook = (XS.put $!) . force =<< updateHistory =<< XS.get
-- Updates the history in response to a WindowSet change
updateHistory :: HistoryDB -> X HistoryDB
updateHistory (HistoryDB oldcur oldhist) = withWindowSet $ \ss -> do
updateHistory (HistoryDB oldcur oldhist) = withWindowSet $ \ss ->
let newcur = SS.peek ss
wins = Set.fromList $ SS.allWindows ss
newhist = Seq.filter (`Set.member` wins) (ins oldcur oldhist)
return $ HistoryDB newcur (del newcur newhist)
in pure $ HistoryDB newcur (del newcur newhist)
where
ins x xs = maybe xs (<| xs) x
del x xs = maybe xs (\x' -> Seq.filter (/= x') xs) x
@ -221,7 +224,7 @@ isOnAnyVisibleWS :: Query Bool
isOnAnyVisibleWS = do
w <- ask
ws <- liftX $ gets windowset
let allVisible = concat $ maybe [] SS.integrate . SS.stack . SS.workspace <$> SS.current ws:SS.visible ws
let allVisible = concatMap (maybe [] SS.integrate . SS.stack . SS.workspace) (SS.current ws:SS.visible ws)
visibleWs = w `elem` allVisible
unfocused = Just w /= SS.peek ws
return $ visibleWs && unfocused

View File

@ -148,8 +148,6 @@ dvorakProgrammerKeyRemap =
layoutDvorakShift = map getShift layoutDvorak
layoutDvorakKey = map getKey layoutDvorak
getKey char = let Just index = elemIndex char layoutUs
in layoutUsKey !! index
getShift char = let Just index = elemIndex char layoutUs
in layoutUsShift !! index
getKey char = fromJust $ (layoutUsKey !?) =<< elemIndex char layoutUs
getShift char = fromJust $ (layoutUsShift !?) =<< elemIndex char layoutUs
charToMask char = if [char] == "0" then 0 else shiftMask

View File

@ -62,7 +62,7 @@ type ExtensionActions = M.Map String (String -> X())
instance XPrompt CalculatorMode where
showXPrompt CalcMode = "calc %s> "
commandToComplete CalcMode = id --send the whole string to `calc`
completionFunction CalcMode = \s -> if null s then return [] else
completionFunction CalcMode s = if null s then return [] else
lines <$> runProcessWithInput "calc" [s] ""
modeAction CalcMode _ _ = return () -- do nothing; this might copy the result to the clipboard
@ -70,7 +70,7 @@ instance XPrompt CalculatorMode where
instance XPrompt HoogleMode where
showXPrompt _ = "hoogle %s> "
commandToComplete _ = id
completionFunction (HMode pathToHoogleBin' _) = \s -> completionFunctionWith pathToHoogleBin' ["--count","8",s]
completionFunction (HMode pathToHoogleBin' _) s = completionFunctionWith pathToHoogleBin' ["--count","8",s]
-- This action calls hoogle again to find the URL corresponding to the autocompleted item
modeAction (HMode pathToHoogleBin'' browser') query result = do
completionsWithLink <- liftIO $ completionFunctionWith pathToHoogleBin'' ["--count","5","--link",query]

View File

@ -36,7 +36,7 @@ import qualified Data.Map as M
( insert, delete, Map, lookup, empty, filter )
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@ file:
-- You can use this module with the following in your @xmonad.hs@ file:
--
-- > import XMonad.Actions.LinkWorkspaces
--
@ -58,7 +58,7 @@ import qualified Data.Map as M
-- > , (i, k) <- zip (XMonad.workspaces conf) [xK_1 .. xK_9]]
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.
data MessageConfig = MessageConfig { messageFunction :: ScreenId -> [Char] -> [Char] -> [Char] -> X()
, foreground :: [Char]

View File

@ -42,24 +42,18 @@ module XMonad.Actions.MessageFeedback
-- ** Aliases
, sm
-- * Backwards Compatibility
-- $backwardsCompatibility
, send, sendSM, sendSM_
, tryInOrder, tryInOrder_
, tryMessage, tryMessage_
) where
import XMonad ( Window )
import XMonad.Core ( X(), Message, SomeMessage(..), LayoutClass(..), windowset, catchX, WorkspaceId, Layout, whenJust )
import XMonad.Operations ( updateLayout, windowBracket, modifyWindowSet )
import XMonad.Prelude ( isJust, liftA2, void )
import XMonad.Prelude
import XMonad.StackSet ( Workspace, current, workspace, layout, tag )
import Control.Monad.State ( gets )
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
-- You can use this module with the following in your @xmonad.hs@:
--
-- > import XMonad.Actions.MessageFeedback
--
@ -230,46 +224,3 @@ tryMessageWithNoRefreshToCurrent m = void . tryMessageWithNoRefreshToCurrentB m
-- | Convenience shorthand for 'SomeMessage'.
sm :: Message a => a -> SomeMessage
sm = SomeMessage
--------------------------------------------------------------------------------
-- Backwards Compatibility:
--------------------------------------------------------------------------------
{-# DEPRECATED send "Use sendMessageB instead." #-}
{-# DEPRECATED sendSM "Use sendSomeMessageB instead." #-}
{-# DEPRECATED sendSM_ "Use sendSomeMessage instead." #-}
{-# DEPRECATED tryInOrder "Use tryInOrderWithNoRefreshToCurrentB instead." #-}
{-# DEPRECATED tryInOrder_ "Use tryInOrderWithNoRefreshToCurrent instead." #-}
{-# DEPRECATED tryMessage "Use tryMessageWithNoRefreshToCurrentB instead." #-}
{-# DEPRECATED tryMessage_ "Use tryMessageWithNoRefreshToCurrent instead." #-}
-- $backwardsCompatibility
-- The following functions exist solely for compatibility with pre-0.14
-- releases.
-- | See 'sendMessageWithNoRefreshToCurrentB'.
send :: Message a => a -> X Bool
send = sendMessageWithNoRefreshToCurrentB
-- | See 'sendSomeMessageWithNoRefreshToCurrentB'.
sendSM :: SomeMessage -> X Bool
sendSM = sendSomeMessageWithNoRefreshToCurrentB
-- | See 'sendSomeMessageWithNoRefreshToCurrent'.
sendSM_ :: SomeMessage -> X ()
sendSM_ = sendSomeMessageWithNoRefreshToCurrent
-- | See 'tryInOrderWithNoRefreshToCurrentB'.
tryInOrder :: [SomeMessage] -> X Bool
tryInOrder = tryInOrderWithNoRefreshToCurrentB
-- | See 'tryInOrderWithNoRefreshToCurrent'.
tryInOrder_ :: [SomeMessage] -> X ()
tryInOrder_ = tryInOrderWithNoRefreshToCurrent
-- | See 'tryMessageWithNoRefreshToCurrentB'.
tryMessage :: (Message a, Message b) => a -> b -> X Bool
tryMessage = tryMessageWithNoRefreshToCurrentB
-- | See 'tryMessageWithNoRefreshToCurrent'.
tryMessage_ :: (Message a, Message b) => a -> b -> X ()
tryMessage_ = tryMessageWithNoRefreshToCurrent

View File

@ -12,7 +12,7 @@
-- Adds actions for minimizing and maximizing windows
--
-- This module should be used with "XMonad.Layout.Minimize". Add 'minimize' to your
-- layout modifiers as described in "XMonad.Layout.Minimized" and use actions from
-- layout modifiers as described in "XMonad.Layout.Minimize" and use actions from
-- this module
--
-- Possible keybindings:
@ -50,14 +50,18 @@ import qualified Data.Map as M
-- $usage
-- Import this module with "XMonad.Layout.Minimize" and "XMonad.Layout.BoringWindows":
--
-- > import XMonad.Actions.Minimize
-- > import XMonad.Layout.Minimize
-- > import qualified XMonad.Layout.BoringWindows as BW
--
-- Then apply 'minimize' and 'boringWindows' to your layout hook and use some
-- actions from this module:
--
-- > main = xmonad def { layoutHook = minimize . BW.boringWindows $ whatever }
--
-- Example keybindings:
--
-- > , ((modm, xK_m ), withFocused minimizeWindow )
-- > , ((modm .|. shiftMask, xK_m ), withLastMinimized maximizeWindow)

View File

@ -0,0 +1,205 @@
{-# LANGUAGE NamedFieldPuns, GeneralizedNewtypeDeriving #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.MostRecentlyUsed
-- Description : Tab through windows by recency of use.
-- Copyright : (c) 2022 L. S. Leary
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : @LSLeary (on github)
-- Stability : unstable
-- Portability : unportable
--
-- Based on the Alt+Tab behaviour common outside of xmonad.
--
-----------------------------------------------------------------------------
-- --< Imports & Exports >-- {{{
module XMonad.Actions.MostRecentlyUsed (
-- * Usage
-- $usage
-- * Interface
configureMRU,
mostRecentlyUsed,
withMostRecentlyUsed,
Location(..),
) where
-- base
import Data.List.NonEmpty (nonEmpty)
import Data.IORef (newIORef, readIORef, writeIORef, modifyIORef)
import Control.Monad.IO.Class (MonadIO)
-- mtl
import Control.Monad.Trans (lift)
import Control.Monad.State (get, put, gets)
-- containers
import qualified Data.Map.Strict as M
-- xmonad
import XMonad
( Window, KeySym, keyPress, io
, Event (DestroyWindowEvent, UnmapEvent, ev_send_event, ev_window)
)
import XMonad.Core
( X, XConfig(..), windowset, WorkspaceId, ScreenId
, ExtensionClass(..), StateExtension(..)
, waitingUnmap
)
import XMonad.Operations (screenWorkspace)
import qualified XMonad.StackSet as W
-- xmonad-contrib
import qualified XMonad.Util.ExtensibleConf as XC
import qualified XMonad.Util.ExtensibleState as XS
import XMonad.Util.PureX
(handlingRefresh, curScreenId, curTag, greedyView, view, peek, focusWindow)
import XMonad.Util.History (History, origin, event, erase, ledger)
import XMonad.Actions.Repeatable (repeatableSt)
import XMonad.Prelude
-- }}}
-- --< Core Data Types: WindowHistory & Location >-- {{{
data WindowHistory = WinHist
{ busy :: !Bool
, hist :: !(History Window Location)
} deriving (Show, Read)
instance ExtensionClass WindowHistory where
initialValue = WinHist
{ busy = False
, hist = origin
}
extensionType = PersistentExtension
data Location = Location
{ workspace :: !WorkspaceId
, screen :: !ScreenId
} deriving (Show, Read, Eq, Ord)
-- }}}
-- --< Interface >-- {{{
-- $usage
--
-- 'configureMRU' must be applied to your config in order for 'mostRecentlyUsed'
-- to work.
--
-- > main :: IO ()
-- > main = xmonad . configureMRU . ... $ def
-- > { ...
-- > }
--
-- Once that's done, it can be used normally in keybinds:
--
-- > , ((mod1Mask, xK_Tab), mostRecentlyUsed [xK_Alt_L, xK_Alt_R] xK_Tab)
--
-- N.B.: This example assumes that 'mod1Mask' corresponds to alt, which is not
-- always the case, depending on how your system is configured.
-- | Configure xmonad to support 'mostRecentlyUsed'.
configureMRU :: XConfig l -> XConfig l
configureMRU = XC.once f (MRU ()) where
f cnf = cnf
{ logHook = logHook cnf <> logWinHist
, handleEventHook = handleEventHook cnf <> winHistEH
}
newtype MRU = MRU () deriving Semigroup
-- | An action to browse through the history of focused windows, taking
-- another step back with each tap of the key.
mostRecentlyUsed
:: [KeySym] -- ^ The 'KeySym's corresponding to the modifier to which the
-- action is bound.
-> KeySym -- ^ The 'KeySym' corresponding to the key to which the action
-- is bound.
-> X ()
mostRecentlyUsed mods key = do
(toUndo, undo) <- undoer
let undoably curThing withThing thing = curThing >>= \cur ->
when (cur /= thing) $ withThing thing >> toUndo (withThing cur)
withMostRecentlyUsed mods key $ \win Location{workspace,screen} ->
handlingRefresh $ do
undo
undoably curScreenId viewScreen screen
undoably curTag greedyView workspace
mi <- gets (W.findTag win . windowset)
for_ mi $ \i -> do
undoably curTag greedyView i
mfw <- peek
for_ mfw $ \fw -> do
undoably (pure fw) focusWindow win
where
undoer :: (MonadIO m, Monoid a) => m (m a -> m (), m a)
undoer = do
ref <- io . newIORef $ pure mempty
let toUndo = io . modifyIORef ref . liftA2 (<>)
undo = join (io $ readIORef ref)
<* io (writeIORef ref $ pure mempty)
pure (toUndo, undo)
viewScreen :: ScreenId -> X Any
viewScreen scr = screenWorkspace scr >>= foldMap view
-- | A version of 'mostRecentlyUsed' that allows you to customise exactly what
-- is done with each window you tab through (the default being to visit its
-- previous 'Location' and give it focus).
withMostRecentlyUsed
:: [KeySym] -- ^ The 'KeySym's corresponding to the
-- modifier to which the action is bound.
-> KeySym -- ^ The 'KeySym' corresponding to the key to
-- which the action is bound.
-> (Window -> Location -> X ()) -- ^ The function applied to each window.
-> X ()
withMostRecentlyUsed mods tab preview = do
wh@WinHist{busy,hist} <- XS.get
unless busy $ do
XS.put wh{ busy = True }
for_ (nonEmpty $ ledger hist) $ \ne -> do
mfw <- gets (W.peek . windowset)
let iSt = case cycleS ne of
(w, _) :~ s | mfw == Just w -> s
s -> s
repeatableSt iSt mods tab $ \t s ->
when (t == keyPress && s == tab) (pop >>= lift . uncurry preview)
XS.modify $ \ws@WinHist{} -> ws{ busy = False }
logWinHist
where
pop = do
h :~ t <- get
put t $> h
-- }}}
-- --< Raw Config >-- {{{
logWinHist :: X ()
logWinHist = do
wh@WinHist{busy,hist} <- XS.get
unless busy $ do
cs <- gets (W.current . windowset)
let cws = W.workspace cs
for_ (W.stack cws) $ \st -> do
let location = Location{ workspace = W.tag cws, screen = W.screen cs }
XS.put wh{ hist = event (W.focus st) location hist }
winHistEH :: Event -> X All
winHistEH ev = All True <$ case ev of
UnmapEvent{ ev_send_event = synth, ev_window = w } -> do
e <- gets (fromMaybe 0 . M.lookup w . waitingUnmap)
when (synth || e == 0) (collect w)
DestroyWindowEvent{ ev_window = w } -> collect w
_ -> pure ()
where collect w = XS.modify $ \wh@WinHist{hist} -> wh{ hist = erase w hist }
-- }}}

View File

@ -32,7 +32,7 @@ import Data.Map (Map)
-- $usage
--
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
-- You can use this module with the following in your @xmonad.hs@:
--
-- > import XMonad.Actions.MouseGestures
-- > import qualified XMonad.StackSet as W
@ -79,17 +79,11 @@ gauge :: (Direction2D -> X ()) -> Pos -> IORef (Maybe (Direction2D, Pos)) -> Pos
gauge hook op st nx ny = do
let np = (nx, ny)
stx <- io $ readIORef st
let
(~(Just od), pivot) = case stx of
Nothing -> (Nothing, op)
Just (d, zp) -> (Just d, zp)
cont = do
guard $ significant np pivot
return $ do
let pivot = maybe op snd stx
when (significant np pivot) $ do
let d' = dir pivot np
when (isNothing stx || od /= d') $ hook d'
when ((fst <$> stx) /= Just d') $ hook d'
io $ writeIORef st (Just (d', np))
fromMaybe (return ()) cont
where
significant a b = delta a b >= 10

View File

@ -37,7 +37,7 @@ import XMonad.Util.XUtils
-- "XMonad.Layout.SimpleFloat" or "XMonad.Layout.DecorationMadness".
--
-- You can use this module with the following in your
-- @~\/.xmonad\/xmonad.hs@:
-- @xmonad.hs@:
--
-- > import XMonad.Actions.MouseResize
-- > import XMonad.Layout.WindowArranger
@ -50,9 +50,9 @@ import XMonad.Util.XUtils
--
-- > main = xmonad def { layoutHook = myLayout }
--
-- For more detailed instructions on editing the layoutHook see:
--
-- "XMonad.Doc.Extending#Editing_the_layout_hook"
-- For more detailed instructions on editing the layoutHook see
-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and
-- "XMonad.Doc.Extending#Editing_the_layout_hook".
mouseResize :: l a -> ModifiedLayout MouseResize l a
mouseResize = ModifiedLayout (MR [])

View File

@ -46,7 +46,6 @@ module XMonad.Actions.Navigation2D ( -- * Usage
, sideNavigation
, sideNavigationWithBias
, hybridOf
, hybridNavigation
, fullScreenRect
, singleWindowRect
, switchLayer
@ -67,6 +66,7 @@ import qualified XMonad.StackSet as W
import qualified XMonad.Util.ExtensibleState as XS
import XMonad.Util.EZConfig (additionalKeys, additionalKeysP)
import XMonad.Util.Types
import qualified Data.List.NonEmpty as NE
-- $usage
-- #Usage#
@ -85,7 +85,7 @@ import XMonad.Util.Types
-- layers and allows customization of the navigation strategy for the tiled
-- layer based on the layout currently in effect.
--
-- You can use this module with (a subset of) the following in your @~\/.xmonad\/xmonad.hs@:
-- You can use this module with (a subset of) the following in your @xmonad.hs@:
--
-- > import XMonad.Actions.Navigation2D
--
@ -98,7 +98,15 @@ import XMonad.Util.Types
-- > False
-- > $ def
--
-- Alternatively, you can use navigation2DP:
-- /NOTE/: the @def@ argument to 'navigation2D' contains the strategy
-- that decides which windows actually get selected. While the default
-- behaviour tries to keep them into account, if you use modules that
-- influence tiling in some way, like "XMonad.Layout.Spacing" or
-- "XMonad.Layout.Gaps", you should think about using a different
-- strategy, if you find the default behaviour to be unnatural. Check
-- out the [finer points](#g:Finer_Points) below for more information.
--
-- Alternatively to 'navigation2D', you can use 'navigation2DP':
--
-- > main = xmonad $ navigation2DP def
-- > ("<Up>", "<Left>", "<Down>", "<Right>")
@ -108,7 +116,7 @@ import XMonad.Util.Types
-- > $ def
--
-- That's it. If instead you'd like more control, you can combine
-- withNavigation2DConfig and additionalNav2DKeys or additionalNav2DKeysP:
-- 'withNavigation2DConfig' and 'additionalNav2DKeys' or 'additionalNav2DKeysP':
--
-- > main = xmonad $ withNavigation2DConfig def
-- > $ additionalNav2DKeys (xK_Up, xK_Left, xK_Down, xK_Right)
@ -162,7 +170,7 @@ import XMonad.Util.Types
--
-- For detailed instruction on editing the key binding see:
--
-- "XMonad.Doc.Extending#Editing_key_bindings".
-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.
-- $finer_points
-- #Finer_Points#
@ -179,9 +187,19 @@ import XMonad.Util.Types
-- values in the above example to 'True'. You could also decide you want
-- wrapping only for a subset of the operations and no wrapping for others.
--
-- By default, all layouts use the 'defaultTiledNavigation' strategy specified
-- in the 'Navigation2DConfig' (by default, line navigation is used). To
-- override this behaviour for some layouts, add a pair (\"layout name\",
-- By default, all layouts use the 'defaultTiledNavigation' strategy
-- specified in the 'Navigation2DConfig' (by default, line navigation is
-- used). Many more navigation strategies are available; some may feel
-- more natural, depending on the layout and user:
--
-- * 'lineNavigation'
-- * 'centerNavigation'
-- * 'sideNavigation'
-- * 'sideNavigationWithBias'
--
-- There is also the ability to combine two strategies with 'hybridOf'.
--
-- To override the default behaviour for some layouts, add a pair (\"layout name\",
-- navigation strategy) to the 'layoutNavigation' list in the
-- 'Navigation2DConfig', where \"layout name\" is the string reported by the
-- layout's description method (normally what is shown as the layout name in
@ -327,7 +345,7 @@ centerNavigation = N 2 doCenterNavigation
-- and push it to the right until it intersects with at least one other window.
-- Of those windows, one with a point that is the closest to the centre of the
-- line (+1) is selected. This is probably the most intuitive strategy for the
-- tiled layer when using XMonad.Layout.Spacing.
-- tiled layer when using "XMonad.Layout.Spacing".
sideNavigation :: Navigation2D
sideNavigation = N 1 (doSideNavigationWithBias 1)
@ -359,10 +377,6 @@ hybridOf (N g1 s1) (N g2 s2) = N (max g1 g2) $ applyToBoth s1 s2
where
applyToBoth f g a b c = f a b c <|> g a b c
{-# DEPRECATED hybridNavigation "Use hybridOf with lineNavigation and centerNavigation as arguments." #-}
hybridNavigation :: Navigation2D
hybridNavigation = hybridOf lineNavigation centerNavigation
-- | Stores the configuration of directional navigation. The 'Default' instance
-- uses line navigation for the tiled layer and for navigation between screens,
-- and center navigation for the float layer. No custom navigation strategies
@ -388,7 +402,7 @@ data Navigation2DConfig = Navigation2DConfig
}
-- | Shorthand for the tedious screen type
type Screen = W.Screen WorkspaceId (Layout Window) Window ScreenId ScreenDetail
type Screen = WindowScreen
-- | Convenience function for enabling Navigation2D with typical keybindings.
-- Takes a Navigation2DConfig, an (up, left, down, right) tuple, a mapping from
@ -433,7 +447,7 @@ additionalNav2DKeys (u, l, d, r) modifiers wrap =
-- mapping from key prefix to action, and a bool to indicate if wrapping should
-- occur, and returns a function from XConfig to XConfig. Example:
--
-- > additionalNav2DKeysP def ("w", "a", "s", "d") [("M-", windowGo), ("M-S-", windowSwap)] False myConfig
-- > additionalNav2DKeysP ("w", "a", "s", "d") [("M-", windowGo), ("M-S-", windowSwap)] False myConfig
additionalNav2DKeysP :: (String, String, String, String) -> [(String, Direction2D -> Bool -> X ())] ->
Bool -> XConfig l -> XConfig l
additionalNav2DKeysP (u, l, d, r) modifiers wrap =
@ -451,7 +465,7 @@ withNavigation2DConfig conf2d xconf = xconf { startupHook = startupHook xconf
}
instance Default Navigation2DConfig where
def = Navigation2DConfig { defaultTiledNavigation = lineNavigation
def = Navigation2DConfig { defaultTiledNavigation = hybridOf lineNavigation sideNavigation
, floatNavigation = centerNavigation
, screenNavigation = lineNavigation
, layoutNavigation = []
@ -616,11 +630,8 @@ actOnScreens act wrap = withWindowSet $ \winset -> do
-- | Determines whether a given window is mapped
isMapped :: Window -> X Bool
isMapped win = withDisplay
$ \dpy -> io
$ (waIsUnmapped /=)
. wa_map_state
<$> getWindowAttributes dpy win
isMapped = fmap (maybe False ((waIsUnmapped /=) . wa_map_state))
. safeGetWindowAttributes
----------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------
@ -773,8 +784,7 @@ doCenterNavigation dir (cur, rect) winrects
-- All the points that coincide with the current center and succeed it
-- in the (appropriately ordered) window stack.
onCtr' = L.tail $ L.dropWhile ((cur /=) . fst) onCtr
-- tail should be safe here because cur should be in onCtr
onCtr' = L.drop 1 $ L.dropWhile ((cur /=) . fst) onCtr
-- All the points that do not coincide with the current center and which
-- lie in the (rotated) right cone.
@ -824,8 +834,7 @@ doSideNavigationWithBias bias dir (cur, rect)
rHalfPiCC r = SideRect (-y2 r) (-y1 r) (x1 r) (x2 r)
-- Apply the above function until d becomes synonymous with R (wolog).
rotateToR d = let (_, _:l) = break (d ==) [U, L, D, R]
in foldr (const $ (.) rHalfPiCC) id l
rotateToR d = fromJust . lookup d . zip [R, D, L, U] . iterate rHalfPiCC
transform = rotateToR dir . translate . toSR
@ -875,8 +884,8 @@ swap win winset = W.focusWindow cur
-- Reconstruct the workspaces' window stacks to reflect the swap.
newvisws = zipWith (\ws wns -> ws { W.stack = W.differentiate wns }) visws newwins
newscrs = zipWith (\scr ws -> scr { W.workspace = ws }) scrs newvisws
newwinset = winset { W.current = head newscrs
, W.visible = tail newscrs
newwinset = winset { W.current = NE.head (notEmpty newscrs) -- Always at least one screen.
, W.visible = drop 1 newscrs
}
-- | Calculates the center of a rectangle

View File

@ -27,8 +27,7 @@ import XMonad
toggleBorder :: Window -> X ()
toggleBorder w = do
bw <- asks (borderWidth . config)
withDisplay $ \d -> io $ do
cw <- wa_border_width <$> getWindowAttributes d w
if cw == 0
withDisplay $ \d -> withWindowAttributes d w $ \wa -> io $
if wa_border_width wa == 0
then setWindowBorderWidth d w bw
else setWindowBorderWidth d w 0

View File

@ -1,51 +1,56 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.OnScreen
-- Description : Control workspaces on different screens (in xinerama mode).
-- Copyright : (c) 2009 Nils Schweinsberg
-- Copyright : (c) 2009-2025 Nils Schweinsberg
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : Nils Schweinsberg <mail@n-sch.de>
-- Maintainer : Nils Schweinsberg <mail@nils.cc>
-- Stability : unstable
-- Portability : unportable
--
-- Control workspaces on different screens (in xinerama mode).
--
-----------------------------------------------------------------------------
module XMonad.Actions.OnScreen (
-- * Usage
module XMonad.Actions.OnScreen
( -- * Usage
-- $usage
onScreen
, onScreen'
, Focus(..)
, viewOnScreen
, greedyViewOnScreen
, onlyOnScreen
, toggleOnScreen
, toggleGreedyOnScreen
) where
onScreen,
onScreen',
Focus (..),
viewOnScreen,
greedyViewOnScreen,
onlyOnScreen,
toggleOnScreen,
toggleGreedyOnScreen,
)
where
import XMonad
import XMonad.Prelude (fromMaybe, guard)
import XMonad.Prelude (empty, fromMaybe, guard)
import XMonad.StackSet hiding (new)
-- | Focus data definitions
data Focus = FocusNew -- ^ always focus the new screen
| FocusCurrent -- ^ always keep the focus on the current screen
| FocusTag WorkspaceId -- ^ always focus tag i on the new stack
| FocusTagVisible WorkspaceId -- ^ focus tag i only if workspace with tag i is visible on the old stack
data Focus
= -- | always focus the new screen
FocusNew
| -- | always keep the focus on the current screen
FocusCurrent
| -- | always focus tag i on the new stack
FocusTag WorkspaceId
| -- | focus tag i only if workspace with tag i is visible on the old stack
FocusTagVisible WorkspaceId
-- | Run any function that modifies the stack on a given screen. This function
-- will also need to know which Screen to focus after the function has been
-- run.
onScreen :: (WindowSet -> WindowSet) -- ^ function to run
-> Focus -- ^ what to do with the focus
-> ScreenId -- ^ screen id
-> WindowSet -- ^ current stack
-> WindowSet
onScreen ::
-- | function to run
(WindowSet -> WindowSet) ->
-- | what to do with the focus
Focus ->
-- | screen id
ScreenId ->
-- | current stack
WindowSet ->
WindowSet
onScreen f foc sc st = fromMaybe st $ do
ws <- lookupWorkspace sc st
@ -53,12 +58,14 @@ onScreen f foc sc st = fromMaybe st $ do
return $ setFocus foc st fStack
-- set focus for new stack
setFocus :: Focus
-> WindowSet -- ^ old stack
-> WindowSet -- ^ new stack
-> WindowSet
setFocus ::
Focus ->
-- | old stack
WindowSet ->
-- | new stack
WindowSet ->
WindowSet
setFocus FocusNew _ new = new
setFocus FocusCurrent old new =
case lookupWorkspace (screen $ current old) new of
@ -74,10 +81,14 @@ setFocus (FocusTagVisible i) old new =
-- on the given screen.
-- Warning: This function will change focus even if the function it's supposed
-- to run doesn't succeed.
onScreen' :: X () -- ^ X function to run
-> Focus -- ^ focus
-> ScreenId -- ^ screen id
-> X ()
onScreen' ::
-- | X function to run
X () ->
-- | focus
Focus ->
-- | screen id
ScreenId ->
X ()
onScreen' x foc sc = do
st <- gets windowset
case lookupWorkspace sc st of
@ -87,69 +98,90 @@ onScreen' x foc sc = do
x
windows $ setFocus foc st
-- | Switch to workspace @i@ on screen @sc@. If @i@ is visible use @view@ to
-- switch focus to the workspace @i@.
viewOnScreen :: ScreenId -- ^ screen id
-> WorkspaceId -- ^ index of the workspace
-> WindowSet -- ^ current stack
-> WindowSet
viewOnScreen ::
-- | screen id
ScreenId ->
-- | index of the workspace
WorkspaceId ->
-- | current stack
WindowSet ->
WindowSet
viewOnScreen sid i =
onScreen (view i) (FocusTag i) sid
-- | Switch to workspace @i@ on screen @sc@. If @i@ is visible use @greedyView@
-- to switch the current workspace with workspace @i@.
greedyViewOnScreen :: ScreenId -- ^ screen id
-> WorkspaceId -- ^ index of the workspace
-> WindowSet -- ^ current stack
-> WindowSet
greedyViewOnScreen ::
-- | screen id
ScreenId ->
-- | index of the workspace
WorkspaceId ->
-- | current stack
WindowSet ->
WindowSet
greedyViewOnScreen sid i =
onScreen (greedyView i) (FocusTagVisible i) sid
-- | Switch to workspace @i@ on screen @sc@. If @i@ is visible do nothing.
onlyOnScreen :: ScreenId -- ^ screen id
-> WorkspaceId -- ^ index of the workspace
-> WindowSet -- ^ current stack
-> WindowSet
onlyOnScreen ::
-- | screen id
ScreenId ->
-- | index of the workspace
WorkspaceId ->
-- | current stack
WindowSet ->
WindowSet
onlyOnScreen sid i =
onScreen (view i) FocusCurrent sid
-- | @toggleOrView@ as in "XMonad.Actions.CycleWS" for @onScreen@ with view
toggleOnScreen :: ScreenId -- ^ screen id
-> WorkspaceId -- ^ index of the workspace
-> WindowSet -- ^ current stack
-> WindowSet
toggleOnScreen ::
-- | screen id
ScreenId ->
-- | index of the workspace
WorkspaceId ->
-- | current stack
WindowSet ->
WindowSet
toggleOnScreen sid i =
onScreen (toggleOrView' view i) FocusCurrent sid
-- | @toggleOrView@ from "XMonad.Actions.CycleWS" for @onScreen@ with greedyView
toggleGreedyOnScreen :: ScreenId -- ^ screen id
-> WorkspaceId -- ^ index of the workspace
-> WindowSet -- ^ current stack
-> WindowSet
toggleGreedyOnScreen ::
-- | screen id
ScreenId ->
-- | index of the workspace
WorkspaceId ->
-- | current stack
WindowSet ->
WindowSet
toggleGreedyOnScreen sid i =
onScreen (toggleOrView' greedyView i) FocusCurrent sid
-- a \"pure\" version of X.A.CycleWS.toggleOrDoSkip
toggleOrView' :: (WorkspaceId -> WindowSet -> WindowSet) -- ^ function to run
-> WorkspaceId -- ^ tag to look for
-> WindowSet -- ^ current stackset
-> WindowSet
toggleOrView' ::
-- | function to run
(WorkspaceId -> WindowSet -> WindowSet) ->
-- | tag to look for
WorkspaceId ->
-- | current stackset
WindowSet ->
WindowSet
toggleOrView' f i st = fromMaybe (f i st) $ do
let st' = hidden st
-- make sure we actually have to do something
guard $ i == (tag . workspace $ current st)
guard $ not (null st')
-- finally, toggle!
return $ f (tag . head $ st') st
case st' of
[] -> empty
(h : _) -> return $ f (tag h) st -- finally, toggle!
-- $usage
--
-- This module provides an easy way to control, what you see on other screens in
-- xinerama mode without having to focus them. Put this into your
-- @~\/.xmonad\/xmonad.hs@:
-- @xmonad.hs@:
--
-- > import XMonad.Actions.OnScreen
--
@ -183,4 +215,4 @@ toggleOrView' f i st = fromMaybe (f i st) $ do
-- where 0 is the first screen and \"1\" the workspace with the tag \"1\".
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.

View File

@ -0,0 +1,49 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.PerLayoutKeys
-- Description : Define key-bindings on per-layout basis.
-- Copyright : (c) brandon s allbery kf8nh 2022, Roman Cheplyaka, 2008
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : brandon s allbery kf8ng <allbery.b@gmail.com>
-- Stability : unstable
-- Portability : unportable
--
-- Define key-bindings on per-layout basis.
--
-----------------------------------------------------------------------------
module XMonad.Actions.PerLayoutKeys (
-- * Usage
-- $usage
chooseActionByLayout,
bindByLayout
) where
import XMonad
import XMonad.StackSet as S
-- $usage
--
-- You can use this module with the following in your @xmonad.hs@:
--
-- > import XMonad.Actions.PerLayoutKeys
--
-- > ,((0, xK_F2), bindByLayout [("Tall", spawn "rxvt"), ("Mirror Tall", spawn "xeyes"), ("", spawn "xmessage hello")])
--
-- For detailed instructions on editing your key bindings, see
-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.
-- | Uses supplied function to decide which action to run depending on current layout name.
chooseActionByLayout :: (String->X()) -> X()
chooseActionByLayout f = withWindowSet (f . description . S.layout. S.workspace . S.current)
-- | If current layout is listed, run appropriate action (only the first match counts!)
-- If it isn't listed, then run default action (marked with empty string, \"\"), or do nothing if default isn't supplied.
bindByLayout :: [(String, X())] -> X()
bindByLayout bindings = chooseActionByLayout chooser where
chooser l = case lookup l bindings of
Just action -> action
Nothing -> case lookup "" bindings of
Just action -> action
Nothing -> return ()

View File

@ -24,7 +24,7 @@ import XMonad
-- $usage
--
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
-- You can use this module with the following in your @xmonad.hs@:
--
-- > import XMonad.Actions.PerWindowKeys
--
@ -41,7 +41,7 @@ import XMonad
-- doThisIfTheOthersFail)]@.
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.
-- | Run an action if a Query holds true. Doesn't stop at the first one that
-- does, however, and could potentially run all actions.

View File

@ -25,14 +25,14 @@ import XMonad.StackSet as S
-- $usage
--
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
-- You can use this module with the following in your @xmonad.hs@:
--
-- > import XMonad.Actions.PerWorkspaceKeys
--
-- > ,((0, xK_F2), bindOn [("1", spawn "rxvt"), ("2", spawn "xeyes"), ("", spawn "xmessage hello")])
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.
-- | Uses supplied function to decide which action to run depending on current workspace name.
chooseAction :: (String->X()) -> X()

View File

@ -1,4 +1,6 @@
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE ParallelListComp #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.PhysicalScreens
@ -28,10 +30,13 @@ module XMonad.Actions.PhysicalScreens (
, getScreenIdAndRectangle
, screenComparatorById
, screenComparatorByRectangle
, rescreen
) where
import XMonad
import XMonad.Prelude (elemIndex, fromMaybe, on, sortBy)
import Data.List.NonEmpty (nonEmpty)
import XMonad hiding (rescreen)
import XMonad.Prelude (elemIndex, fromMaybe, on, sortBy, NonEmpty((:|)))
import qualified Data.List.NonEmpty as NE
import qualified XMonad.StackSet as W
{- $usage
@ -46,7 +51,7 @@ To create a screen comparator you can use screenComparatorByRectangle or screenC
The default ScreenComparator orders screens by the upper-left-most corner, from top-to-bottom
and then left-to-right.
Example usage in your @~\/.xmonad\/xmonad.hs@ file:
Example usage in your @xmonad.hs@ file:
> import XMonad.Actions.PhysicalScreens
> import Data.Default
@ -65,7 +70,7 @@ Example usage in your @~\/.xmonad\/xmonad.hs@ file:
> , (f, mask) <- [(viewScreen def, 0), (sendToScreen def, shiftMask)]]
For detailed instructions on editing your key bindings, see
"XMonad.Doc.Extending#Editing_key_bindings".
<https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.
-}
-- | The type of the index of a screen by location
@ -75,7 +80,7 @@ getScreenIdAndRectangle :: W.Screen i l a ScreenId ScreenDetail -> (ScreenId, Re
getScreenIdAndRectangle screen = (W.screen screen, rect) where
rect = screenRect $ W.screenDetail screen
-- | Translate a physical screen index to a "ScreenId"
-- | Translate a physical screen index to a 'ScreenId'
getScreen:: ScreenComparator -> PhysicalScreen -> X (Maybe ScreenId)
getScreen (ScreenComparator cmpScreen) (P i) = do w <- gets windowset
let screens = W.current w : W.visible w
@ -146,3 +151,53 @@ onNextNeighbour sc = neighbourWindows sc 1
-- | Apply operation on a WindowSet with the WorkspaceId of the previous screen in the physical order as parameter.
onPrevNeighbour :: ScreenComparator -> (WorkspaceId -> WindowSet -> WindowSet) -> X ()
onPrevNeighbour sc = neighbourWindows sc (-1)
-- | An alternative to 'XMonad.Operations.rescreen' that avoids reshuffling
-- the workspaces if the number of screens doesn't change and only their
-- locations do. Useful for users of @xrandr --setmonitor@.
--
-- See 'XMonad.Hooks.Rescreen.setRescreenWorkspacesHook', which lets you
-- replace the builtin rescreen handler.
rescreen :: ScreenComparator -> X ()
rescreen (ScreenComparator cmpScreen) = withDisplay (fmap nonEmpty . getCleanedScreenInfo) >>= \case
Nothing -> trace "getCleanedScreenInfo returned []"
Just xinescs -> windows $ rescreen' xinescs
where
rescreen' :: NonEmpty Rectangle -> WindowSet -> WindowSet
rescreen' xinescs ws
| NE.length xinescs == length (W.visible ws) + 1 = rescreenSameLength xinescs ws
| otherwise = rescreenCore xinescs ws
-- the 'XMonad.Operations.rescreen' implementation from core as a fallback
rescreenCore :: NonEmpty Rectangle -> WindowSet -> WindowSet
rescreenCore (xinesc :| xinescs) 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 }
-- sort both existing screens and the screens we just got from xinerama
-- using cmpScreen, and then replace the rectangles in the WindowSet,
-- keeping the order of current/visible workspaces intact
rescreenSameLength :: NonEmpty Rectangle -> WindowSet -> WindowSet
rescreenSameLength xinescs ws =
ws{ W.current = (W.current ws){ W.screenDetail = SD newCurrentRect }
, W.visible = [ w{ W.screenDetail = SD r } | w <- W.visible ws | r <- newVisibleRects ]
}
where
undoSort =
NE.map fst $
NE.sortBy (cmpScreen `on` (getScreenIdAndRectangle . snd)) $
NE.zip ((0 :: Int) :| [1..]) $ -- add indices to undo the sort later
W.current ws :| W.visible ws
newCurrentRect :| newVisibleRects =
NE.map snd $ NE.sortWith fst $ NE.zip undoSort $ -- sort back into current:visible order
NE.map snd $ NE.sortBy cmpScreen $ NE.zip (0 :| [1..]) xinescs
-- TODO:
-- If number of screens before and after isn't the same, we might still
-- try to match locations and avoid changing the workspace for those that
-- didn't move, while making sure that the current workspace is still
-- visible somewhere.

View File

@ -41,13 +41,13 @@ module XMonad.Actions.Plane
import Data.Map (Map, fromList)
import XMonad.Prelude
import XMonad.Prelude hiding (fromList)
import XMonad
import XMonad.StackSet hiding (workspaces)
import XMonad.Util.Run
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@ file:
-- You can use this module with the following in your @xmonad.hs@ file:
--
-- > import XMonad.Actions.Plane
-- > import Data.Map (union)
@ -59,7 +59,7 @@ import XMonad.Util.Run
-- > myNewKeys (XConfig {modMask = modm}) = planeKeys modm (Lines 3) Finite
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.
-- | Direction to go in the plane.
data Direction = ToLeft | ToUp | ToRight | ToDown deriving Enum

View File

@ -29,6 +29,7 @@ module XMonad.Actions.Prefix
, withPrefixArgument
, isPrefixRaw
, isPrefixNumeric
, orIfPrefixed
, ppFormatPrefix
) where
@ -40,11 +41,13 @@ import XMonad.Util.ExtensibleState as XS
import XMonad.Util.Paste (sendKey)
import XMonad.Actions.Submap (submapDefaultWithKey)
import XMonad.Util.EZConfig (readKeySequence)
import qualified Data.List.NonEmpty as NE
import Data.List.NonEmpty ((<|))
{- $usage
This module implements Emacs-style prefix argument. The argument
comes in two flavours, "Raw" and "Numeric".
comes in two flavours, 'Raw' and 'Numeric'.
To initiate the "prefix mode" you hit the prefix keybinding (default
C-u). This sets the Raw argument value to 1. Repeatedly hitting this
@ -72,7 +75,7 @@ Binding it in your config
> ((modm, xK_a), withPrefixArgument addMaybeClean)
Hitting MOD-a will add the <file> to the playlist while C-u MOD-a will
Hitting MOD-a will add the @\<file\>@ to the playlist while C-u MOD-a will
clear the playlist and then add the file.
You can of course use an anonymous action, like so:
@ -128,10 +131,10 @@ usePrefixArgument :: LayoutClass l Window
-> XConfig l
-> XConfig l
usePrefixArgument prefix conf =
conf{ keys = M.insert binding (handlePrefixArg [binding]) . keys conf }
conf{ keys = M.insert binding (handlePrefixArg (binding :| [])) . keys conf }
where
binding = case readKeySequence conf prefix of
Just [key] -> key
Just (key :| []) -> key
_ -> (controlMask, xK_u)
-- | Set Prefix up with default prefix key (C-u).
@ -140,7 +143,7 @@ useDefaultPrefixArgument :: LayoutClass l Window
-> XConfig l
useDefaultPrefixArgument = usePrefixArgument "C-u"
handlePrefixArg :: [(KeyMask, KeySym)] -> X ()
handlePrefixArg :: NonEmpty (KeyMask, KeySym) -> X ()
handlePrefixArg events = do
ks <- asks keyActions
logger <- asks (logHook . config)
@ -161,19 +164,19 @@ handlePrefixArg events = do
Raw _ -> XS.put $ Numeric x
Numeric a -> XS.put $ Numeric $ a * 10 + x
None -> return () -- should never happen
handlePrefixArg (key:events)
handlePrefixArg (key <| events)
else do
prefix <- XS.get
mapM_ (uncurry sendKey) $ case prefix of
Raw a -> replicate a (head events) ++ [key]
_ -> reverse (key:events)
Raw a -> replicate a (NE.head events) ++ [key]
_ -> reverse (key : toList events)
keyToNum = (xK_0, 0) : zip [xK_1 .. xK_9] [1..9]
-- | Turn a prefix-aware X action into an X-action.
--
-- First, fetch the current prefix, then pass it as argument to the
-- original function. You should use this to "run" your commands.
withPrefixArgument :: (PrefixArgument -> X ()) -> X ()
withPrefixArgument :: (PrefixArgument -> X a) -> X a
withPrefixArgument = (>>=) XS.get
-- | Test if 'PrefixArgument' is 'Raw' or not.
@ -186,6 +189,13 @@ isPrefixNumeric :: PrefixArgument -> Bool
isPrefixNumeric (Numeric _) = True
isPrefixNumeric _ = False
-- | Execute the first action, unless any prefix argument is given,
-- in which case the second action is chosen instead.
--
-- > action1 `orIfPrefixed` action2
orIfPrefixed :: X a -> X a -> X a
orIfPrefixed xa xb = withPrefixArgument $ bool xa xb . isPrefixRaw
-- | Format the prefix using the Emacs convetion for use in a
-- statusbar, like xmobar.
--

545
XMonad/Actions/Profiles.hs Normal file
View File

@ -0,0 +1,545 @@
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE DerivingVia #-}
--------------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.Profiles
-- Description : Group your workspaces by similarity.
-- Copyright : (c) Mislav Zanic
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : Mislav Zanic <mislavzanic3@gmail.com>
-- Stability : experimental
-- Portability : unportable
--
--------------------------------------------------------------------------------
module XMonad.Actions.Profiles
( -- * Overview
-- $overview
-- * Usage
-- $usage
-- * Types
ProfileId
, Profile(..)
, ProfileConfig(..)
-- * Hooks
, addProfiles
, addProfilesWithHistory
-- * Switching profiles
, switchToProfile
-- * Workspace navigation and keybindings
, wsFilter
, bindOn
-- * Loggers and pretty printers
, excludeWSPP
, profileLogger
-- * Prompts
, switchProfilePrompt
, addWSToProfilePrompt
, removeWSFromProfilePrompt
, switchProfileWSPrompt
, shiftProfileWSPrompt
-- * Utilities
, currentProfile
, profileIds
, previousProfile
, profileHistory
, allProfileWindows
, profileWorkspaces
)where
--------------------------------------------------------------------------------
import Data.Map.Strict (Map)
import Data.List
import qualified Data.Map.Strict as Map
import Control.DeepSeq
import XMonad
import XMonad.Prelude
import qualified XMonad.StackSet as W
import XMonad.Actions.CycleWS
import qualified XMonad.Util.ExtensibleState as XS
import XMonad.Util.Loggers (Logger)
import XMonad.Prompt.Window (XWindowMap)
import XMonad.Actions.WindowBringer (WindowBringerConfig(..))
import XMonad.Actions.OnScreen (greedyViewOnScreen)
import XMonad.Hooks.Rescreen (addAfterRescreenHook)
import XMonad.Hooks.DynamicLog (PP(ppRename))
import XMonad.Prompt
--------------------------------------------------------------------------------
-- $overview
-- This module allows you to group your workspaces into 'Profile's based on certain similarities.
-- The idea is to expand upon the philosophy set by "XMonad.Actions.TopicSpace"
-- which states that you can look at a topic/workspace as a
-- single unit of work instead of multiple related units of work.
-- This comes in handy if you have lots of workspaces with windows open and need only to
-- work with a few of them at a time. With 'Profile's, you can focus on those few workspaces that
-- require your attention by not displaying, or allowing you to switch to the rest of the workspaces.
-- The best example is having a profile for development and a profile for leisure activities.
--------------------------------------------------------------------------------
-- $usage
-- To use @Profiles@ you need to add it to your XMonad configuration
-- and configure your profiles.
--
-- First you'll need to handle the imports.
--
-- > import XMonad.Actions.Profiles
-- > import XMonad.Util.EZConfig -- for keybindings
-- > import qualified XMonad.StackSet as W
-- > import qualified XMonad.Actions.DynamicWorkspaceOrder as DO -- for workspace navigation
--
-- Next you'll need to define your profiles.
--
-- > myStartingProfile :: ProfileId
-- > myStartingProfile = "Work"
-- >
-- > myProfiles :: [Profile]
-- > myProfiles =
-- > [ Profile { profileId = "Home"
-- > , profileWS = [ "www"
-- > , "rss"
-- > , "vid"
-- > , "vms"
-- > , "writing"
-- > , "notes"
-- > ]
-- > }
-- > , Profile { profileId = "Work"
-- > , profileWS = [ "www"
-- > , "slack"
-- > , "dev"
-- > , "k8s"
-- > , "notes"
-- > ]
-- > }
-- > ]
--
-- So, while using @Home@ 'Profile', you'll only be able to see, navigate to and
-- do actions with @["www", "rss", "vid", "vms", "writing", "notes"]@ workspaces.
--
-- You may also need to define some keybindings. Since @M-1@ .. @M-9@ are
-- sensible keybindings for switching workspaces, you'll need to use
-- 'bindOn' to have different keybindings per profile.
-- Here, we'll use "XMonad.Util.EZConfig" syntax:
--
-- > myKeys :: [(String, X())]
-- > myKeys =
-- > [ ("M-p", switchProfilePrompt xpConfig)
-- > , ("M-g", switchProfileWSPrompt xpConfig)
-- > , ("M1-j", DO.moveTo Next wsFilter)
-- > , ("M1-k", DO.moveTo Prev wsFilter)
-- > ]
-- > <>
-- > [ ("M-" ++ m ++ k, bindOn $ map (\x -> (fst x, f $ snd x)) i)
-- > | (i, k) <- map (\(x:xs) -> (map fst (x:xs), snd x)) $ sortGroupBy snd tupleList
-- > , (f, m) <- [(mby $ windows . W.greedyView, ""), (mby $ windows . W.shift, "S-")]
-- > ]
-- > where
-- > mby f wid = if wid == "" then return () else f wid
-- > sortGroupBy f = groupBy (\ x y -> f x == f y) . sortBy (\x y -> compare (f x) (f y))
-- > tupleList = concatMap (\p -> zip (map (\wid -> (profileId p, wid)) (profileWS p <> repeat "")) (map show [1..9 :: Int])) myProfiles
--
-- After that, you'll need to hook @Profiles@ into your XMonad config:
--
-- > main = xmonad $ addProfiles def { profiles = myProfiles
-- > , startingProfile = myStartingProfile
-- > }
-- > $ def `additionalKeysP` myKeys
--
--------------------------------------------------------------------------------
type ProfileId = String
type ProfileMap = Map ProfileId Profile
--------------------------------------------------------------------------------
-- | Profile representation.
data Profile = Profile
{ profileId :: !ProfileId -- ^ Profile name.
, profileWS :: ![WorkspaceId] -- ^ A list of workspaces contained within a profile.
}
--------------------------------------------------------------------------------
-- | Internal profile state.
data ProfileState = ProfileState
{ profilesMap :: !ProfileMap
, current :: !(Maybe Profile)
, previous :: !(Maybe ProfileId)
}
--------------------------------------------------------------------------------
-- | User config for profiles.
data ProfileConfig = ProfileConfig
{ workspaceExcludes :: ![WorkspaceId] -- ^ A list of workspaces to exclude from the @profileHistoryHook@.
, profiles :: ![Profile] -- ^ A list of user-defined profiles.
, startingProfile :: !ProfileId -- ^ Profile shown on startup.
}
--------------------------------------------------------------------------------
instance Default ProfileConfig where
def = ProfileConfig { workspaceExcludes = []
, profiles = []
, startingProfile = ""
}
--------------------------------------------------------------------------------
instance ExtensionClass ProfileState where
initialValue = ProfileState Map.empty Nothing Nothing
--------------------------------------------------------------------------------
-- Internal type for history tracking.
-- Main problem with @XMonad.Hooks.HistoryHook@ is that it isn't profile aware.
-- Because of that, when switching to a previous workspace, you might switch to
-- a workspace
newtype ProfileHistory = ProfileHistory
{ history :: Map ProfileId [(ScreenId, WorkspaceId)]
}
deriving (Read, Show)
deriving NFData via Map ProfileId [(Int, WorkspaceId)]
--------------------------------------------------------------------------------
instance ExtensionClass ProfileHistory where
extensionType = PersistentExtension
initialValue = ProfileHistory Map.empty
--------------------------------------------------------------------------------
newtype ProfilePrompt = ProfilePrompt String
--------------------------------------------------------------------------------
instance XPrompt ProfilePrompt where
showXPrompt (ProfilePrompt x) = x
--------------------------------------------------------------------------------
defaultProfile :: Profile
defaultProfile = defaultProfile
--------------------------------------------------------------------------------
-- | Returns current profile.
currentProfile :: X ProfileId
currentProfile = profileId . fromMaybe defaultProfile . current <$> XS.get
--------------------------------------------------------------------------------
-- | Returns previous profile.
previousProfile :: X (Maybe ProfileId)
previousProfile = XS.gets previous
--------------------------------------------------------------------------------
-- | Returns the history of viewed workspaces per profile.
profileHistory :: X (Map ProfileId [(ScreenId, WorkspaceId)])
profileHistory = XS.gets history
--------------------------------------------------------------------------------
profileMap :: X ProfileMap
profileMap = XS.gets profilesMap
--------------------------------------------------------------------------------
-- | Returns ids of all profiles.
profileIds :: X [ProfileId]
profileIds = Map.keys <$> XS.gets profilesMap
--------------------------------------------------------------------------------
currentProfileWorkspaces :: X [WorkspaceId]
currentProfileWorkspaces = XS.gets current <&> profileWS . fromMaybe defaultProfile
--------------------------------------------------------------------------------
-- | Hook profiles into XMonad. This function adds a startup hook that
-- sets up ProfileState. Also adds an afterRescreenHook for viewing correct
-- workspaces when adding new screens.
addProfiles :: ProfileConfig -> XConfig a -> XConfig a
addProfiles profConf conf = addAfterRescreenHook hook $ conf
{ startupHook = profileStartupHook' <> startupHook conf
}
where
profileStartupHook' :: X()
profileStartupHook' = profilesStartupHook (profiles profConf) (startingProfile profConf)
hook = currentProfile >>= switchWSOnScreens
--------------------------------------------------------------------------------
-- | Hooks profiles into XMonad and enables Profile history logging.
addProfilesWithHistory :: ProfileConfig -> XConfig a -> XConfig a
addProfilesWithHistory profConf conf = conf'
{ logHook = profileHistoryHookExclude (workspaceExcludes profConf) <> logHook conf
}
where
conf' = addProfiles profConf conf
--------------------------------------------------------------------------------
profileHistoryHookExclude :: [WorkspaceId] -> X()
profileHistoryHookExclude ews = do
cur <- gets $ W.current . windowset
vis <- gets $ W.visible . windowset
pws <- currentProfileWorkspaces
p <- currentProfile
updateHist p $ workspaceScreenPairs $ filterWS pws $ cur:vis
where
workspaceScreenPairs wins = zip (W.screen <$> wins) (W.tag . W.workspace <$> wins)
filterWS pws = filter ((\wid -> (wid `elem` pws) && (wid `notElem` ews)) . W.tag . W.workspace)
--------------------------------------------------------------------------------
updateHist :: ProfileId -> [(ScreenId, WorkspaceId)] -> X()
updateHist pid xs = profileWorkspaces pid >>= XS.modify' . update
where
update pws hs = force $ hs { history = doUpdate pws $ history hs }
doUpdate pws hist = foldl (\acc (sid, wid) -> Map.alter (f pws sid wid) pid acc) hist xs
f pws sid wid val = case val of
Nothing -> pure [(sid, wid)]
Just hs -> pure $ let new = (sid, wid) in new:filterWS pws new hs
filterWS :: [WorkspaceId] -> (ScreenId, WorkspaceId) -> [(ScreenId, WorkspaceId)] -> [(ScreenId, WorkspaceId)]
filterWS pws new = filter (\x -> snd x `elem` pws && x /= new)
--------------------------------------------------------------------------------
-- | Adds profiles to ProfileState and sets current profile using .
profilesStartupHook :: [Profile] -> ProfileId -> X ()
profilesStartupHook ps pid = XS.modify go >> switchWSOnScreens pid
where
go :: ProfileState -> ProfileState
go s = s {profilesMap = update $ profilesMap s, current = setCurrentProfile $ Map.fromList $ map entry ps}
update :: ProfileMap -> ProfileMap
update = Map.union (Map.fromList $ map entry ps)
entry :: Profile -> (ProfileId, Profile)
entry p = (profileId p, p)
setCurrentProfile :: ProfileMap -> Maybe Profile
setCurrentProfile s = case Map.lookup pid s of
Nothing -> Just $ Profile pid []
Just pn -> Just pn
--------------------------------------------------------------------------------
setPrevious :: ProfileId -> X()
setPrevious name = XS.modify update
where
update ps = ps { previous = doUpdate ps }
doUpdate ps = case Map.lookup name $ profilesMap ps of
Nothing -> previous ps
Just p -> Just $ profileId p
--------------------------------------------------------------------------------
setProfile :: ProfileId -> X ()
setProfile p = currentProfile >>= setPrevious >> setProfile' p
--------------------------------------------------------------------------------
setProfile' :: ProfileId -> X ()
setProfile' name = XS.modify update
where
update ps = ps { current = doUpdate ps }
doUpdate ps = case Map.lookup name $ profilesMap ps of
Nothing -> current ps
Just p -> Just p
--------------------------------------------------------------------------------
-- | Switch to a profile.
switchToProfile :: ProfileId -> X()
switchToProfile pid = setProfile pid >> switchWSOnScreens pid
--------------------------------------------------------------------------------
-- | Returns the workspace ids associated with a profile id.
profileWorkspaces :: ProfileId -> X [WorkspaceId]
profileWorkspaces pid = profileMap >>= findPWs
where
findPWs pm = return . profileWS . fromMaybe defaultProfile $ Map.lookup pid pm
--------------------------------------------------------------------------------
-- | Prompt for adding a workspace id to a profile.
addWSToProfilePrompt :: XPConfig -> X()
addWSToProfilePrompt c = do
ps <- profileIds
mkXPrompt (ProfilePrompt "Add ws to profile:") c (mkComplFunFromList' c ps) f
where
f :: String -> X()
f p = do
vis <- gets $ fmap (W.tag . W.workspace) . W.visible . windowset
cur <- gets $ W.tag . W.workspace . W.current . windowset
hid <- gets $ fmap W.tag . W.hidden . windowset
let
arr = cur:(vis <> hid)
in mkXPrompt (ProfilePrompt "Ws to add to profile:") c (mkComplFunFromList' c arr) (`addWSToProfile` p)
--------------------------------------------------------------------------------
-- | Prompt for switching profiles.
switchProfilePrompt :: XPConfig -> X()
switchProfilePrompt c = do
ps <- profileIds
mkXPrompt (ProfilePrompt "Profile: ") c (mkComplFunFromList' c ps) switchToProfile
--------------------------------------------------------------------------------
-- | Prompt for switching workspaces.
switchProfileWSPrompt :: XPConfig -> X ()
switchProfileWSPrompt c = mkPrompt =<< currentProfileWorkspaces
where
mkPrompt pws = mkXPrompt (ProfilePrompt "Switch to workspace:") c (mkComplFunFromList' c pws) mbygoto
mbygoto wid = do
pw <- profileWorkspaces =<< currentProfile
unless (wid `notElem` pw) (windows . W.greedyView $ wid)
--------------------------------------------------------------------------------
-- | Prompt for shifting windows to a different workspace.
shiftProfileWSPrompt :: XPConfig -> X ()
shiftProfileWSPrompt c = mkPrompt =<< currentProfileWorkspaces
where
mkPrompt pws = mkXPrompt (ProfilePrompt "Send window to workspace:") c (mkComplFunFromList' c pws) mbyshift
mbyshift wid = do
pw <- profileWorkspaces =<< currentProfile
unless (wid `notElem` pw) (windows . W.shift $ wid)
--------------------------------------------------------------------------------
addWSToProfile :: WorkspaceId -> ProfileId -> X()
addWSToProfile wid pid = XS.modify go
where
go :: ProfileState -> ProfileState
go ps = ps {profilesMap = update $ profilesMap ps, current = update' $ fromMaybe defaultProfile $ current ps}
update :: ProfileMap -> ProfileMap
update mp = case Map.lookup pid mp of
Nothing -> mp
Just p -> if wid `elem` profileWS p then mp else Map.adjust f pid mp
f :: Profile -> Profile
f p = Profile pid (wid : profileWS p)
update' :: Profile -> Maybe Profile
update' cp = if profileId cp == pid && wid `notElem` profileWS cp then Just (Profile pid $ wid:profileWS cp) else Just cp
--------------------------------------------------------------------------------
-- | Prompt for removing a workspace from a profile.
removeWSFromProfilePrompt :: XPConfig -> X()
removeWSFromProfilePrompt c = do
ps <- profileIds
mkXPrompt (ProfilePrompt "Remove ws from profile:") c (mkComplFunFromList' c ps) f
where
f :: String -> X()
f p = do
arr <- profileWorkspaces p
mkXPrompt (ProfilePrompt "Ws to remove from profile:") c (mkComplFunFromList' c arr) $
\ws -> do
cp <- currentProfile
ws `removeWSFromProfile` p
when (cp == p) $ currentProfile >>= switchWSOnScreens
--------------------------------------------------------------------------------
removeWSFromProfile :: WorkspaceId -> ProfileId -> X()
removeWSFromProfile wid pid = XS.modify go
where
go :: ProfileState -> ProfileState
go ps = ps {profilesMap = update $ profilesMap ps, current = update' $ fromMaybe defaultProfile $ current ps}
update :: ProfileMap -> ProfileMap
update mp = case Map.lookup pid mp of
Nothing -> mp
Just p -> if wid `elem` profileWS p then Map.adjust f pid mp else mp
f :: Profile -> Profile
f p = Profile pid (delete wid $ profileWS p)
update' :: Profile -> Maybe Profile
update' cp = if profileId cp == pid && wid `elem` profileWS cp then Just (Profile pid $ delete wid $ profileWS cp) else Just cp
--------------------------------------------------------------------------------
-- | Pretty printer for a bar. Prints workspace ids of current profile.
excludeWSPP :: PP -> X PP
excludeWSPP pp = modifyPP <$> currentProfileWorkspaces
where
modifyPP pws = pp { ppRename = ppRename pp . printTag pws }
printTag pws tag = if tag `elem` pws then tag else ""
--------------------------------------------------------------------------------
-- | For cycling through workspaces associated with the current.
wsFilter :: WSType
wsFilter = WSIs $ currentProfileWorkspaces >>= (\ws -> return $ (`elem` ws) . W.tag)
--------------------------------------------------------------------------------
-- Takes care of placing correct workspaces on their respective screens.
-- It does this by reducing the history of a Profile until it gets an array of length
-- equal to the number of screens with pairs that have unique workspace ids.
switchWSOnScreens :: ProfileId -> X()
switchWSOnScreens pid = do
hist <- profileHistory
vis <- gets $ W.visible . windowset
cur <- gets $ W.current . windowset
pws <- profileMap <&> (profileWS . fromMaybe (Profile pid []) . Map.lookup pid)
case Map.lookup pid hist of
Nothing -> switchScreens $ zip (W.screen <$> (cur:vis)) pws
Just xs -> compareAndSwitch (f (W.screen <$> cur:vis) xs) (cur:vis) pws
where
f :: [ScreenId] -> [(ScreenId, WorkspaceId)] -> [(ScreenId, WorkspaceId)]
f sids = reorderUniq . reorderUniq . reverse . filter ((`elem` sids) . fst)
reorderUniq :: (Ord k, Ord v) => [(k,v)] -> [(v,k)]
reorderUniq = map (\(x,y) -> (y,x)) . uniq
uniq :: (Ord k, Ord v) => [(k,v)] -> [(k,v)]
uniq = Map.toList . Map.fromList
viewWS fview sid wid = windows $ fview sid wid
switchScreens = mapM_ (uncurry $ viewWS greedyViewOnScreen)
compareAndSwitch hist wins pws | length hist < length wins = switchScreens $ hist <> populateScreens hist wins pws
| otherwise = switchScreens hist
populateScreens hist wins pws = zip (filter (`notElem` map fst hist) $ W.screen <$> wins) (filter (`notElem` map snd hist) pws)
--------------------------------------------------------------------------------
chooseAction :: (String -> X ()) -> X ()
chooseAction f = XS.gets current <&> (profileId . fromMaybe defaultProfile) >>= f
--------------------------------------------------------------------------------
-- | Create keybindings per profile.
bindOn :: [(String, X ())] -> X ()
bindOn bindings = chooseAction chooser
where
chooser profile = case lookup profile bindings of
Just action -> action
Nothing -> case lookup "" bindings of
Just action -> action
Nothing -> return ()
--------------------------------------------------------------------------------
-- | Loggs currentProfile and all profiles with hidden workspaces
-- (workspaces that aren't shown on a screen but have windows).
profileLogger :: (String -> String) -> (String -> String) -> Logger
profileLogger formatFocused formatUnfocused = do
hws <- gets $ W.hidden . windowset
p <- currentProfile
hm <- map fst
. filter (\(p', xs) -> any ((`elem` htags hws) . snd) xs || p' == p)
. Map.toList <$> profileHistory
return $ Just $ foldl (\a b -> a ++ " " ++ b) "" $ format p <$> hm
where
format p a = if a == p then formatFocused a else formatUnfocused a
htags wins = W.tag <$> filter (isJust . W.stack) wins
--------------------------------------------------------------------------------
-- | @XWindowMap@ of all windows contained in a profile.
allProfileWindows :: XWindowMap
allProfileWindows = allProfileWindows' def
--------------------------------------------------------------------------------
allProfileWindows' :: WindowBringerConfig -> XWindowMap
allProfileWindows' WindowBringerConfig{ windowTitler = titler, windowFilter = include } = do
pws <- currentProfileWorkspaces
windowSet <- gets windowset
Map.fromList . concat <$> mapM keyValuePairs (filter ((`elem` pws) . W.tag) $ W.workspaces windowSet)
where keyValuePairs ws = let wins = W.integrate' (W.stack ws)
in mapM (keyValuePair ws) =<< filterM include wins
keyValuePair ws w = (, w) <$> titler ws w

View File

@ -28,7 +28,7 @@ import XMonad.StackSet
-- $usage
--
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
-- You can use this module with the following in your @xmonad.hs@:
--
-- > import XMonad.Actions.Promote
--
@ -37,7 +37,7 @@ import XMonad.StackSet
-- > , ((modm, xK_Return), promote)
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.
-- | Move the focused window to the master pane. All other windows
-- retain their order. If focus is in the master, swap it with the

View File

@ -0,0 +1,84 @@
{-# LANGUAGE LambdaCase #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.RepeatAction
-- Description : Repeat the last performed action.
-- Copyright : (c) 2022 Martin Kozlovsky
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : <kozlovsky.m7@gmail.com>
-- Stability : unstable
-- Portability : not portable
--
-- Ability to repeat the last action.
--
-----------------------------------------------------------------------------
module XMonad.Actions.RepeatAction (
-- * Usage
-- $usage
rememberAction,
rememberActions,
repeatLast,
) where
import XMonad
import qualified XMonad.Util.ExtensibleState as XS
-- $usage
--
-- You can use this module with the following in your @xmonad.hs@:
--
-- > import XMonad.Actions.RepeatAction
--
-- Then join a dedicated key to run the last action with the rest of your
-- key bindings using the 'rememberActions':
--
-- > rememberActions (modm, xK_period) [((modm, xK_c), kill), …]
--
-- It can be also used in the same way for "XMonad.Util.EZConfig":
--
-- > rememberActions "M-." [("M-c", kill), …]
--
-- For example, if you use 'XMonad.Util.EZConfig.additionalKeysP',
--
-- > main = xmonad $ … $ def
-- > {
-- > …
-- > }
-- > `additionalKeysP` myKeys
--
-- you would adjust the call to 'XMonad.Util.EZConfig.additionalKeysP'
-- like so:
--
-- > `additionalKeysP` (rememberActions "M-." myKeys)
--
-- For more detailed instructions on editing your key bindings, see
-- <https://xmonad.org/TUTORIAL.html the tutorial>.
newtype LastAction = LastAction { runLastAction :: X () }
instance ExtensionClass LastAction where
initialValue = LastAction $ pure ()
-- | Transforms an action into an action that can be remembered and repeated.
rememberAction :: X () -> X ()
rememberAction x = userCode x >>= \case
Nothing -> pure ()
Just () -> XS.put (LastAction x) -- Only remember action if nothing went wrong.
-- | Maps 'rememberAction' over a list of key bindings.
rememberActions' :: [(a, X ())] -> [(a, X ())]
rememberActions' = map (fmap rememberAction)
infixl 4 `rememberActions`
-- | Maps 'rememberAction' over a list of key bindings and adds a dedicated
-- key to repeat the last action.
rememberActions :: a -> [(a, X ())] -> [(a, X ())]
rememberActions key keyList = (key, repeatLast) : rememberActions' keyList
-- | Runs the last remembered action.
-- / Be careful not to include this action in the remembered actions! /
repeatLast :: X ()
repeatLast = XS.get >>= runLastAction

View File

@ -0,0 +1,89 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.Repeatable
-- Description : Actions you'd like to repeat.
-- Copyright : (c) 2022 L. S. Leary
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : @LSLeary (on github)
-- Stability : unstable
-- Portability : unportable
--
-- This module factors out the shared logic of "XMonad.Actions.CycleRecentWS",
-- "XMonad.Actions.CycleWorkspaceByScreen", "XMonad.Actions.CycleWindows" and
-- "XMonad.Actions.MostRecentlyUsed".
--
-- See the source of these modules for usage examples.
--
-----------------------------------------------------------------------------
module XMonad.Actions.Repeatable
( repeatable
, repeatableSt
, repeatableM
) where
-- mtl
import Control.Monad.State (StateT(..))
-- X11
import Graphics.X11.Xlib.Extras
-- xmonad
import XMonad
-- | An action that temporarily usurps and responds to key press/release events,
-- concluding when one of the modifier keys is released.
repeatable
:: [KeySym] -- ^ The list of 'KeySym's under the
-- modifiers used to invoke the action.
-> KeySym -- ^ The keypress that invokes the action.
-> (EventType -> KeySym -> X ()) -- ^ The keypress handler.
-> X ()
repeatable = repeatableM id
-- | A more general variant of 'repeatable' with a stateful handler,
-- accumulating a monoidal return value throughout the events.
repeatableSt
:: Monoid a
=> s -- ^ Initial state.
-> [KeySym] -- ^ The list of 'KeySym's under the
-- modifiers used to invoke the
-- action.
-> KeySym -- ^ The keypress that invokes the
-- action.
-> (EventType -> KeySym -> StateT s X a) -- ^ The keypress handler.
-> X (a, s)
repeatableSt iSt = repeatableM $ \m -> runStateT m iSt
-- | A more general variant of 'repeatable' with an arbitrary monadic handler,
-- accumulating a monoidal return value throughout the events.
repeatableM
:: (MonadIO m, Monoid a)
=> (m a -> X b) -- ^ How to run the monad in 'X'.
-> [KeySym] -- ^ The list of 'KeySym's under the
-- modifiers used to invoke the action.
-> KeySym -- ^ The keypress that invokes the action.
-> (EventType -> KeySym -> m a) -- ^ The keypress handler.
-> X b
repeatableM run mods key pressHandler = do
XConf{ theRoot = root, display = d } <- ask
run (repeatableRaw d root mods key pressHandler)
repeatableRaw
:: (MonadIO m, Monoid a)
=> Display -> Window
-> [KeySym] -> KeySym -> (EventType -> KeySym -> m a) -> m a
repeatableRaw d root mods key pressHandler = do
io (grabKeyboard d root False grabModeAsync grabModeAsync currentTime)
handleEvent (keyPress, key) <* io (ungrabKeyboard d currentTime)
where
getNextEvent = io $ allocaXEvent $ \p -> do
maskEvent d (keyPressMask .|. keyReleaseMask) p
KeyEvent{ ev_event_type = t, ev_keycode = c } <- getEvent p
s <- keycodeToKeysym d c 0
return (t, s)
handleEvent (t, s)
| t == keyRelease && s `elem` mods = pure mempty
| otherwise = (<>) <$> pressHandler t s <*> (getNextEvent >>= handleEvent)

View File

@ -1,3 +1,5 @@
{-# LANGUAGE ViewPatterns #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.RotSlaves
@ -15,11 +17,16 @@
module XMonad.Actions.RotSlaves (
-- $usage
rotSlaves', rotSlavesUp, rotSlavesDown,
rotAll', rotAllUp, rotAllDown
rotAll', rotAllUp, rotAllDown,
-- * Generic list rotations
-- $generic
rotUp, rotDown
) where
import XMonad.StackSet
import XMonad
import XMonad.StackSet
import XMonad.Prelude
-- $usage
--
@ -36,28 +43,37 @@ import XMonad
-- TwoPane layout (see "XMonad.Layout.TwoPane").
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.
-- | Rotate the windows in the current stack, excluding the first one
-- (master).
rotSlavesUp,rotSlavesDown :: X ()
rotSlavesUp = windows $ modify' (rotSlaves' (\l -> tail l++[head l]))
rotSlavesDown = windows $ modify' (rotSlaves' (\l -> last l : init l))
rotSlavesUp = windows $ modify' (rotSlaves' rotUp)
rotSlavesDown = windows $ modify' (rotSlaves' rotDown)
-- | The actual rotation, as a pure function on the window stack.
rotSlaves' :: ([a] -> [a]) -> Stack a -> Stack a
rotSlaves' _ s@(Stack _ [] []) = s
rotSlaves' f (Stack t [] rs) = Stack t [] (f rs) -- Master has focus
rotSlaves' f s@(Stack _ ls _ ) = Stack t' (reverse revls') rs' -- otherwise
where (master:ws) = integrate s
(revls',t':rs') = splitAt (length ls) (master:f ws)
where (notEmpty -> master :| ws) = integrate s
(revls', notEmpty -> t' :| rs') = splitAt (length ls) (master:f ws)
-- | Rotate all the windows in the current stack.
rotAllUp,rotAllDown :: X ()
rotAllUp = windows $ modify' (rotAll' (\l -> tail l++[head l]))
rotAllDown = windows $ modify' (rotAll' (\l -> last l : init l))
rotAllUp = windows $ modify' (rotAll' rotUp)
rotAllDown = windows $ modify' (rotAll' rotDown)
-- | The actual rotation, as a pure function on the window stack.
rotAll' :: ([a] -> [a]) -> Stack a -> Stack a
rotAll' f s = Stack r (reverse revls) rs
where (revls,r:rs) = splitAt (length (up s)) (f (integrate s))
where (revls, notEmpty -> r :| rs) = splitAt (length (up s)) (f (integrate s))
-- $generic
-- Generic list rotations such that @rotUp [1..4]@ is equivalent to
-- @[2,3,4,1]@ and @rotDown [1..4]@ to @[4,1,2,3]@. They both are
-- @id@ for null or singleton lists.
rotUp :: [a] -> [a]
rotUp l = drop 1 l ++ take 1 l
rotDown :: [a] -> [a]
rotDown = reverse . rotUp . reverse

View File

@ -1,3 +1,5 @@
{-# LANGUAGE ViewPatterns #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.RotateSome
@ -26,14 +28,14 @@ module XMonad.Actions.RotateSome (
) where
import Control.Arrow ((***))
import XMonad.Prelude (partition, sortOn, (\\))
import XMonad.Prelude (NonEmpty(..), notEmpty, partition, sortOn, (\\))
import qualified Data.Map as M
import XMonad (Window, WindowSpace, Rectangle, X, runLayout, screenRect, windows, withWindowSet)
import XMonad.StackSet (Screen (Screen), Stack (Stack), current, floating, modify', stack)
import XMonad.Util.Stack (reverseS)
{- $usage
You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
You can use this module with the following in your @xmonad.hs@:
> import XMonad.Actions.RotateSome
@ -148,7 +150,7 @@ rotateSome p (Stack t ls rs) =
-- Append anchored elements, along with their unchanged indices, and sort
-- by index. Separate lefts (negative indices) from the rest, and grab the
-- new focus from the head of the remaining elements.
(ls', t':rs') =
(ls', notEmpty -> t' :| rs') =
(map snd *** map snd)
. span ((< 0) . fst)
. sortOn fst

View File

@ -31,33 +31,50 @@ module XMonad.Actions.Search ( -- * Usage
prefixAware,
namedEngine,
amazon,
alpha,
amazon,
arXiv,
aur,
clojureDocs,
codesearch,
cratesIo,
deb,
debbts,
debpts,
dictionary,
duckduckgo,
ebay,
flora,
github,
google,
hackage,
homeManager,
hoogle,
images,
imdb,
lucky,
maps,
mathworld,
ncatlab,
nixos,
noogle,
openstreetmap,
protondb,
rosettacode,
rustStd,
scholar,
sourcehut,
stackage,
steam,
thesaurus,
vocabulary,
voidpgks_x86_64,
voidpgks_x86_64_musl,
wayback,
wikipedia,
wiktionary,
youtube,
vocabulary,
duckduckgo,
zbmath,
multi,
-- * Use case: searching with a submap
-- $tip
@ -102,12 +119,20 @@ import XMonad.Util.XSelection (getSelection)
The currently available search engines are:
* 'amazon' -- Amazon keyword search.
* 'alpha' -- Wolfram|Alpha query.
* 'amazon' -- Amazon keyword search.
* 'arXiv' -- Open-access preprint archive.
* 'aur' -- Arch User Repository.
* 'clojureDocs' -- Documentation and examples repository for Clojure.
* 'codesearch' -- Google Labs Code Search search.
* 'cratesIo' -- Rust crate registry.
* 'deb' -- Debian package search.
* 'debbts' -- Debian Bug Tracking System.
@ -116,17 +141,21 @@ import XMonad.Util.XSelection (getSelection)
* 'dictionary' -- dictionary.reference.com search.
* 'duckduckgo' -- DuckDuckGo search engine.
* 'ebay' -- Ebay keyword search.
* 'flora' -- Prettier Haskell package database.
* 'github' -- GitHub keyword search.
* 'google' -- basic Google search.
* 'hackage' -- Hackage, the Haskell package database.
* 'hoogle' -- Hoogle, the Haskell libraries API search engine.
* 'homeManager' -- Search Nix's home-manager's options.
* 'stackage' -- Stackage, An alternative Haskell libraries API search engine.
* 'hoogle' -- Hoogle, the Haskell libraries API search engine.
* 'images' -- Google images.
@ -138,21 +167,45 @@ import XMonad.Util.XSelection (getSelection)
* 'mathworld' -- Wolfram MathWorld search.
* 'ncatlab' -- Higer Algebra, Homotopy and Category Theory Wiki.
* 'nixos' -- Search NixOS packages and options.
* 'noogle' -- 'hoogle'-like Nix API search engine.
* 'openstreetmap' -- OpenStreetMap free wiki world map.
* 'protondb' -- Steam Proton Game Database.
* 'rosettacode' -- Programming chrestomathy wiki.
* 'rustStd' -- Rust standard library documentation.
* 'scholar' -- Google scholar academic search.
* 'sourcehut' -- Sourcehut projects search.
* 'stackage' -- Stackage, An alternative Haskell libraries API search engine.
* 'steam' -- Steam games search.
* 'thesaurus' -- thesaurus.com search.
* 'vocabulary' -- Dictionary search.
* 'voidpgks_x86_64' -- Void Linux packages search for @x86_64@.
* 'voidpgks_x86_64_musl' -- Void Linux packages search for @x86_64-musl@.
* 'wayback' -- the Wayback Machine.
* 'wikipedia' -- basic Wikipedia search.
* 'wiktionary' -- Wiktionary search.
* 'youtube' -- Youtube video search.
* 'vocabulary' -- Dictionary search
* 'duckduckgo' -- DuckDuckGo search engine.
* 'zbmath' -- Open alternative to MathSciNet.
* 'multi' -- Search based on the prefix. \"amazon:Potter\" will use amazon, etc. With no prefix searches google.
@ -269,7 +322,7 @@ searchEngine name site = searchEngineF name (\s -> site ++ escape s)
inside of a URL instead of in the end) you can use the alternative 'searchEngineF' function.
> searchFunc :: String -> String
> searchFunc s | "wiki:" `isPrefixOf` s = "https://en.wikipedia.org/wiki/" ++ (escape $ tail $ snd $ break (==':') s)
> searchFunc s | "wiki:" `isPrefixOf` s = "https://en.wikipedia.org/wiki/" ++ (escape $ drop 1 $ snd $ break (==':') s)
> | "https://" `isPrefixOf` s = s
> | otherwise = (use google) s
> myNewEngine = searchEngineF "mymulti" searchFunc
@ -286,39 +339,57 @@ searchEngineF :: Name -> Site -> SearchEngine
searchEngineF = SearchEngine
-- The engines.
amazon, alpha, codesearch, deb, debbts, debpts, dictionary, ebay, github, google, hackage, hoogle,
images, imdb, lucky, maps, mathworld, openstreetmap, scholar, stackage, thesaurus, vocabulary, wayback, wikipedia, wiktionary,
youtube, duckduckgo :: SearchEngine
amazon = searchEngine "amazon" "https://www.amazon.com/s/ref=nb_sb_noss_2?url=search-alias%3Daps&field-keywords="
alpha, amazon, arXiv, aur, clojureDocs, codesearch, cratesIo, deb, debbts, debpts, dictionary, duckduckgo, ebay, flora,
github, google, hackage, homeManager, hoogle, images, imdb, lucky, maps, mathworld, ncatlab, nixos, noogle, openstreetmap, protondb,
rosettacode, rustStd, scholar, sourcehut, stackage, steam, thesaurus, vocabulary, voidpgks_x86_64, voidpgks_x86_64_musl, wayback,
wikipedia, wiktionary, youtube, zbmath :: SearchEngine
alpha = searchEngine "alpha" "https://www.wolframalpha.com/input/?i="
amazon = searchEngine "amazon" "https://www.amazon.com/s/ref=nb_sb_noss_2?url=search-alias%3Daps&field-keywords="
arXiv = searchEngineF "arXiv" (\s -> "https://arxiv.org/search/?query=" <> s <> "&searchtype=all")
aur = searchEngine "aur" "https://aur.archlinux.org/packages?&K="
clojureDocs = searchEngine "clojureDocs" "https://clojuredocs.org/search?q="
codesearch = searchEngine "codesearch" "https://developers.google.com/s/results/code-search?q="
cratesIo = searchEngine "cratesIo" "https://crates.io/search?q="
deb = searchEngine "deb" "https://packages.debian.org/"
debbts = searchEngine "debbts" "https://bugs.debian.org/"
debpts = searchEngine "debpts" "https://packages.qa.debian.org/"
dictionary = searchEngine "dict" "https://dictionary.reference.com/browse/"
duckduckgo = searchEngine "duckduckgo" "https://duckduckgo.com/?t=lm&q="
ebay = searchEngine "ebay" "https://www.ebay.com/sch/i.html?_nkw="
flora = searchEngine "flora" "https://flora.pm/search?q="
github = searchEngine "github" "https://github.com/search?q="
google = searchEngine "google" "https://www.google.com/search?num=100&q="
google = searchEngine "google" "https://www.google.com/search?q="
hackage = searchEngine "hackage" "https://hackage.haskell.org/package/"
homeManager = searchEngine "homeManager" "https://mipmip.github.io/home-manager-option-search/?query="
hoogle = searchEngine "hoogle" "https://hoogle.haskell.org/?hoogle="
images = searchEngine "images" "https://images.google.fr/images?q="
imdb = searchEngine "imdb" "https://www.imdb.com/find?s=all&q="
lucky = searchEngine "lucky" "https://www.google.com/search?btnI&q="
maps = searchEngine "maps" "https://maps.google.com/maps?q="
mathworld = searchEngine "mathworld" "https://mathworld.wolfram.com/search/?query="
ncatlab = searchEngine "ncatlab" "https://ncatlab.org/nlab/search?query="
nixos = searchEngine "nixos" "https://search.nixos.org/packages?channel=unstable&from=0&size=200&sort=relevance&type=packages&query="
noogle = searchEngineF "noogle" (\s -> "https://noogle.dev/?search=" <> s <> "&page=1&to=any&from=any")
openstreetmap = searchEngine "openstreetmap" "https://www.openstreetmap.org/search?query="
protondb = searchEngine "protondb" "https://www.protondb.com/search?q="
rosettacode = searchEngine "rosettacode" "https://rosettacode.org/w/index.php?search="
rustStd = searchEngine "rustStd" "https://doc.rust-lang.org/std/index.html?search="
scholar = searchEngine "scholar" "https://scholar.google.com/scholar?q="
sourcehut = searchEngine "sourcehut" "https://sr.ht/projects?search="
stackage = searchEngine "stackage" "https://www.stackage.org/lts/hoogle?q="
steam = searchEngine "steam" "https://store.steampowered.com/search/?term="
thesaurus = searchEngine "thesaurus" "https://thesaurus.com/browse/"
vocabulary = searchEngine "vocabulary" "https://www.vocabulary.com/search?q="
voidpgks_x86_64 = searchEngine "voidpackages" "https://voidlinux.org/packages/?arch=x86_64&q="
voidpgks_x86_64_musl = searchEngine "voidpackages" "https://voidlinux.org/packages/?arch=x86_64-musl&q="
wayback = searchEngineF "wayback" ("https://web.archive.org/web/*/"++)
wikipedia = searchEngine "wiki" "https://en.wikipedia.org/wiki/Special:Search?go=Go&search="
wiktionary = searchEngine "wikt" "https://en.wiktionary.org/wiki/Special:Search?go=Go&search="
youtube = searchEngine "youtube" "https://www.youtube.com/results?search_type=search_videos&search_query="
wayback = searchEngineF "wayback" ("https://web.archive.org/web/*/"++)
vocabulary = searchEngine "vocabulary" "https://www.vocabulary.com/search?q="
duckduckgo = searchEngine "duckduckgo" "https://duckduckgo.com/?t=lm&q="
zbmath = searchEngine "zbmath" "https://zbmath.org/?q="
multi :: SearchEngine
multi = namedEngine "multi" $ foldr1 (!>) [amazon, alpha, codesearch, deb, debbts, debpts, dictionary, ebay, github, google, hackage, hoogle, images, imdb, lucky, maps, mathworld, openstreetmap, scholar, thesaurus, wayback, wikipedia, wiktionary, duckduckgo, prefixAware google]
multi = namedEngine "multi" $ foldr1 (!>) [alpha, amazon, aur, codesearch, deb, debbts, debpts, dictionary, duckduckgo, ebay, flora, github, hackage, hoogle, images, imdb, lucky, maps, mathworld, ncatlab, openstreetmap, protondb, rosettacode, scholar, sourcehut, stackage, steam, thesaurus, vocabulary, voidpgks_x86_64, voidpgks_x86_64_musl, wayback, wikipedia, wiktionary, youtube, prefixAware google]
{- | This function wraps up a search engine and creates a new one, which works
like the argument, but goes directly to a URL if one is given rather than
@ -366,14 +437,14 @@ namedEngine name (SearchEngine _ site) = searchEngineF name site
browser. -}
promptSearchBrowser :: XPConfig -> Browser -> SearchEngine -> X ()
promptSearchBrowser config browser (SearchEngine name site) = do
hc <- historyCompletionP ("Search [" `isPrefixOf`)
hc <- historyCompletionP config ("Search [" `isPrefixOf`)
mkXPrompt (Search name) config hc $ search browser site
{- | Like 'promptSearchBrowser', but only suggest previous searches for the
given 'SearchEngine' in the prompt. -}
promptSearchBrowser' :: XPConfig -> Browser -> SearchEngine -> X ()
promptSearchBrowser' config browser (SearchEngine name site) = do
hc <- historyCompletionP (searchName `isPrefixOf`)
hc <- historyCompletionP config (searchName `isPrefixOf`)
mkXPrompt (Search name) config hc $ search browser site
where
searchName = showXPrompt (Search name)

View File

@ -1,4 +1,5 @@
{-# LANGUAGE CPP #-}
{-# LANGUAGE MultiWayIf #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.ShowText
@ -26,7 +27,7 @@ module XMonad.Actions.ShowText
import Data.Map (Map,empty,insert,lookup)
import Prelude hiding (lookup)
import XMonad
import XMonad.Prelude (All, fi, when)
import XMonad.Prelude (All, fi, listToMaybe)
import XMonad.StackSet (current,screen)
import XMonad.Util.Font (Align(AlignCenter)
, initXMF
@ -41,13 +42,13 @@ import XMonad.Util.XUtils (createNewWindow
import qualified XMonad.Util.ExtensibleState as ES
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
-- You can use this module with the following in your @xmonad.hs@:
--
-- > import XMonad.Actions.ShowText
--
-- Then add the event hook handler:
--
-- > xmonad { handleEventHook = myHandleEventHooks <+> handleTimerEvent }
-- > xmonad { handleEventHook = myHandleEventHooks <> handleTimerEvent }
--
-- You can then use flashText in your keybindings:
--
@ -87,8 +88,9 @@ handleTimerEvent :: Event -> X All
handleTimerEvent (ClientMessageEvent _ _ _ dis _ mtyp d) = do
(ShowText m) <- ES.get :: X ShowText
a <- io $ internAtom dis "XMONAD_TIMER" False
when (mtyp == a && not (null d))
(whenJust (lookup (fromIntegral $ head d) m) deleteWindow)
if | mtyp == a, Just dh <- listToMaybe d ->
whenJust (lookup (fromIntegral dh) m) deleteWindow
| otherwise -> pure ()
mempty
handleTimerEvent _ = mempty

View File

@ -28,7 +28,7 @@ import XMonad.StackSet (Stack (Stack), StackSet, modify')
import XMonad.Util.Stack (reverseS)
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
-- You can use this module with the following in your @xmonad.hs@:
--
-- > import XMonad.Actions.Sift
--

View File

@ -24,7 +24,7 @@ import XMonad.Core
import XMonad.Util.Run
-- $usage
-- To use, import this module into @~\/.xmonad\/xmonad.hs@:
-- To use, import this module into @xmonad.hs@:
--
-- > import XMonad.Actions.SimpleDate
--
@ -35,7 +35,7 @@ import XMonad.Util.Run
-- In this example, a popup date menu will now be bound to @mod-d@.
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.
date :: X ()
date = unsafeSpawn "(date; sleep 10) | dzen2"

View File

@ -13,7 +13,7 @@
-- 'sinkAll' function for backwards compatibility.
-----------------------------------------------------------------------------
module XMonad.Actions.SinkAll (
module XMonad.Actions.SinkAll {-# DEPRECATED "Use XMonad.Actions.WithAll instead" #-} (
-- * Usage
-- $usage
@ -23,7 +23,7 @@ import XMonad.Actions.WithAll (sinkAll)
-- $usage
--
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
-- You can use this module with the following in your @xmonad.hs@:
--
-- > import XMonad.Actions.SinkAll
--
@ -32,4 +32,4 @@ import XMonad.Actions.WithAll (sinkAll)
-- > , ((modm .|. shiftMask, xK_t), sinkAll)
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.

View File

@ -1,3 +1,5 @@
{-# LANGUAGE LambdaCase #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.SpawnOn
@ -28,11 +30,7 @@ module XMonad.Actions.SpawnOn (
shellPromptOn
) where
import Control.Exception (tryJust)
import System.IO.Error (isDoesNotExistError)
import System.IO.Unsafe (unsafePerformIO)
import System.Posix.Types (ProcessID)
import Text.Printf (printf)
import XMonad
import XMonad.Prelude
@ -42,16 +40,17 @@ import XMonad.Hooks.ManageHelpers
import XMonad.Prompt
import XMonad.Prompt.Shell
import qualified XMonad.Util.ExtensibleState as XS
import XMonad.Util.Process (getPPIDChain)
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
-- You can use this module with the following in your @xmonad.hs@:
--
-- > import XMonad.Actions.SpawnOn
--
-- > main = do
-- > xmonad def {
-- > ...
-- > manageHook = manageSpawn <+> manageHook def
-- > manageHook = manageSpawn <> manageHook def
-- > ...
-- > }
--
@ -64,7 +63,7 @@ import qualified XMonad.Util.ExtensibleState as XS
-- the spawned application(e.g. float or resize it).
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.
newtype Spawner = Spawner {pidsRef :: [(ProcessID, ManageHook)]}
@ -72,29 +71,13 @@ instance ExtensionClass Spawner where
initialValue = Spawner []
getPPIDOf :: ProcessID -> Maybe ProcessID
getPPIDOf thisPid =
case unsafePerformIO . tryJust (guard . isDoesNotExistError) . readFile . printf "/proc/%d/stat" $ toInteger thisPid of
Left _ -> Nothing
Right contents -> case lines contents of
[] -> Nothing
first : _ -> case words first of
_ : _ : _ : ppid : _ -> Just $ fromIntegral (read ppid :: Int)
_ -> Nothing
getPPIDChain :: ProcessID -> [ProcessID]
getPPIDChain thisPid = ppid_chain thisPid []
where ppid_chain pid' acc =
if pid' == 0
then acc
else case getPPIDOf pid' of
Nothing -> acc
Just ppid -> ppid_chain ppid (ppid : acc)
-- | Get the current Spawner or create one if it doesn't exist.
modifySpawner :: ([(ProcessID, ManageHook)] -> [(ProcessID, ManageHook)]) -> X ()
modifySpawner f = XS.modify (Spawner . f . pidsRef)
modifySpawnerM :: ([(ProcessID, ManageHook)] -> X [(ProcessID, ManageHook)]) -> X ()
modifySpawnerM f = XS.modifyM (fmap Spawner . f . pidsRef)
-- | Provides a manage hook to react on process spawned with
-- 'spawnOn', 'spawnHere' etc.
manageSpawn :: ManageHook
@ -103,24 +86,16 @@ manageSpawn = manageSpawnWithGC (return . take 20)
manageSpawnWithGC :: ([(ProcessID, ManageHook)] -> X [(ProcessID, ManageHook)])
-- ^ function to stop accumulation of entries for windows that never set @_NET_WM_PID@
-> ManageHook
manageSpawnWithGC garbageCollect = do
manageSpawnWithGC garbageCollect = pid >>= \case
Nothing -> mempty
Just p -> do
Spawner pids <- liftX XS.get
mp <- pid
let ppid_chain = case mp of
Just winpid -> winpid : getPPIDChain winpid
Nothing -> []
known_window_handlers = [ mh
| ppid <- ppid_chain
, let mpid = lookup ppid pids
, isJust mpid
, let (Just mh) = mpid ]
case known_window_handlers of
[] -> idHook
(mh:_) -> do
whenJust mp $ \p -> liftX $ do
ps <- XS.gets pidsRef
XS.put . Spawner =<< garbageCollect (filter ((/= p) . fst) ps)
mh
ppid_chain <- io $ getPPIDChain p
case mapMaybe (`lookup` pids) ppid_chain of
[] -> mempty
mh : _ -> liftX (gc p) >> mh
where
gc p = modifySpawnerM $ garbageCollect . filter ((/= p) . fst)
mkPrompt :: (String -> X ()) -> XPConfig -> X ()
mkPrompt cb c = do

View File

@ -17,20 +17,23 @@ module XMonad.Actions.Submap (
-- * Usage
-- $usage
submap,
visualSubmap,
visualSubmapSorted,
submapDefault,
submapDefaultWithKey
submapDefaultWithKey,
-- * Utilities
subName,
) where
import Data.Bits
import XMonad.Prelude (fix, fromMaybe)
import XMonad hiding (keys)
import qualified Data.Map as M
import XMonad hiding (keys)
import XMonad.Prelude (fix, fromMaybe, keyToString, cleanKeyMask)
import XMonad.Util.XUtils
{- $usage
First, import this module into your @~\/.xmonad\/xmonad.hs@:
First, import this module into your @xmonad.hs@:
> import XMonad.Actions.Submap
@ -51,7 +54,7 @@ because that is a special value passed to XGrabKey() and not an actual
modifier.
For detailed instructions on editing your key bindings, see
"XMonad.Doc.Extending#Editing_key_bindings".
<https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.
-}
@ -62,6 +65,61 @@ For detailed instructions on editing your key bindings, see
submap :: M.Map (KeyMask, KeySym) (X ()) -> X ()
submap = submapDefault (return ())
-- | Like 'submap', but visualise the relevant options.
--
-- ==== __Example__
--
-- > import qualified Data.Map as Map
-- > import XMonad.Actions.Submap
-- >
-- > gotoLayout :: [(String, X ())] -- for use with EZConfig
-- > gotoLayout = -- assumes you have a layout named "Tall" and one named "Full".
-- > [("M-l", visualSubmap def $ Map.fromList $ map (\(k, s, a) -> ((0, k), (s, a)))
-- > [ (xK_t, "Tall", switchToLayout "Tall") -- "M-l t" switches to "Tall"
-- > , (xK_r, "Full", switchToLayout "Full") -- "M-l r" switches to "full"
-- > ])]
--
-- One could alternatively also write @gotoLayout@ as
--
-- > gotoLayout = [("M-l", visualSubmap def $ Map.fromList $
-- > [ ((0, xK_t), subName "Tall" $ switchToLayout "Tall")
-- > , ((0, xK_r), subName "Full" $ switchToLayout "Full")
-- > ])]
visualSubmap :: WindowConfig -- ^ The config for the spawned window.
-> M.Map (KeyMask, KeySym) (String, X ())
-- ^ A map @keybinding -> (description, action)@.
-> X ()
visualSubmap = visualSubmapSorted id
-- | Like 'visualSubmap', but is able to sort the descriptions.
-- For example,
--
-- > import Data.Ord (comparing, Down)
-- >
-- > visualSubmapSorted (sortBy (comparing Down)) def
--
-- would sort the @(key, description)@ pairs by their keys in descending
-- order.
visualSubmapSorted :: ([((KeyMask, KeySym), String)] -> [((KeyMask, KeySym), String)])
-- ^ A function to resort the descriptions
-> WindowConfig -- ^ The config for the spawned window.
-> M.Map (KeyMask, KeySym) (String, X ())
-- ^ A map @keybinding -> (description, action)@.
-> X ()
visualSubmapSorted sorted wc keys =
withSimpleWindow wc descriptions waitForKeyPress >>= \(m', s) ->
maybe (pure ()) snd (M.lookup (m', s) keys)
where
descriptions :: [String]
descriptions =
map (\(key, desc) -> keyToString key <> ": " <> desc)
. sorted
$ zip (M.keys keys) (map fst (M.elems keys))
-- | Give a name to an action.
subName :: String -> X () -> (String, X ())
subName = (,)
-- | Like 'submap', but executes a default action if the key did not match.
submapDefault :: X () -> M.Map (KeyMask, KeySym) (X ()) -> X ()
submapDefault = submapDefaultWithKey . const
@ -71,28 +129,32 @@ submapDefault = submapDefaultWithKey . const
submapDefaultWithKey :: ((KeyMask, KeySym) -> X ())
-> M.Map (KeyMask, KeySym) (X ())
-> X ()
submapDefaultWithKey defAction keys = do
XConf { theRoot = root, display = d } <- ask
submapDefaultWithKey defAction keys = waitForKeyPress >>=
\(m', s) -> fromMaybe (defAction (m', s)) (M.lookup (m', s) keys)
io $ grabKeyboard d root False grabModeAsync grabModeAsync currentTime
io $ grabPointer d root False buttonPressMask grabModeAsync grabModeAsync
-----------------------------------------------------------------------
-- Internal stuff
waitForKeyPress :: X (KeyMask, KeySym)
waitForKeyPress = do
XConf{ theRoot = root, display = dpy } <- ask
io $ do grabKeyboard dpy root False grabModeAsync grabModeAsync currentTime
grabPointer dpy root False buttonPressMask grabModeAsync grabModeAsync
none none currentTime
(m, s) <- io $ allocaXEvent $ \p -> fix $ \nextkey -> do
maskEvent d (keyPressMask .|. buttonPressMask) p
maskEvent dpy (keyPressMask .|. buttonPressMask) p
ev <- getEvent p
case ev of
KeyEvent { ev_keycode = code, ev_state = m } -> do
keysym <- keycodeToKeysym d code 0
keysym <- keycodeToKeysym dpy code 0
if isModifierKey keysym
then nextkey
else return (m, keysym)
_ -> return (0, 0)
-- Remove num lock mask and Xkb group state bits
m' <- cleanMask $ m .&. ((1 `shiftL` 12) - 1)
io $ ungrabPointer d currentTime
io $ ungrabKeyboard d currentTime
io $ sync d False
fromMaybe (defAction (m', s)) (M.lookup (m', s) keys)
m' <- cleanKeyMask <*> pure m
io $ do ungrabPointer dpy currentTime
ungrabKeyboard dpy currentTime
sync dpy False
pure (m', s)

View File

@ -63,6 +63,7 @@ import qualified XMonad.Util.ExtensibleState as XS
import qualified Data.Map as M
import qualified Data.Set as S
import Control.Arrow
import qualified Data.List.NonEmpty as NE
-- $usage
@ -99,7 +100,7 @@ import Control.Arrow
-- So far floating windows have been treated no differently than tiled windows
-- even though their positions are independent of the stack. Often, yanking
-- floating windows in and out of the workspace will obliterate the stack
-- history - particularly frustrating with 'XMonad.Util.Scratchpad' since it is
-- history - particularly frustrating with "XMonad.Util.Scratchpad" since it is
-- toggled so frequenty and always replaces the master window. That's why the
-- swap functions accept a boolean argument; when @True@ non-focused floating
-- windows will be ignored.
@ -240,7 +241,7 @@ swapApply ignoreFloats swapFunction = do
(r,s2) = stackSplit s1 fl' :: ([(Int,Window)],W.Stack Window)
(b,s3) = swapFunction pm s2
s4 = stackMerge s3 r
mh = let w = head . W.integrate $ s3
mh = let w = NE.head . notEmpty . W.integrate $ s3
in const $ w : delete w ch
in (b,Just s4,mh)
(x,y,z) = maybe (False,Nothing,id) swapApply' st

View File

@ -30,7 +30,7 @@ import XMonad.Util.WorkspaceCompare
-- $usage
-- Add this import to your @~\/.xmonad\/xmonad.hs@:
-- Add this import to your @xmonad.hs@:
--
-- > import XMonad.Actions.SwapWorkspaces
--
@ -44,7 +44,7 @@ import XMonad.Util.WorkspaceCompare
-- will swap workspaces 1 and 5.
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.
-- | Swaps the currently focused workspace with the given workspace tag, via
-- @swapWorkspaces@.

View File

@ -39,7 +39,7 @@ econst = const . return
-- $usage
--
-- To use window tags, import this module into your @~\/.xmonad\/xmonad.hs@:
-- To use window tags, import this module into your @xmonad.hs@:
--
-- > import XMonad.Actions.TagWindows
-- > import XMonad.Prompt -- to use tagPrompt
@ -64,7 +64,7 @@ econst = const . return
-- the tags \"a\" and \"b\" but not \"a b\".
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.
-- | set multiple tags for a window at once (overriding any previous tags)
setTags :: [String] -> Window -> X ()
@ -134,11 +134,6 @@ focusTagged' :: (WindowSet -> [Window]) -> String -> X ()
focusTagged' wl t = gets windowset >>= findM (hasTag t) . wl >>=
maybe (return ()) (windows . focusWindow)
findM :: (Monad m) => (a -> m Bool) -> [a] -> m (Maybe a)
findM _ [] = return Nothing
findM p (x:xs) = do b <- p x
if b then return (Just x) else findM p xs
-- | apply a pure function to windows with a tag
withTaggedP, withTaggedGlobalP :: String -> (Window -> WindowSet -> WindowSet) -> X ()
withTaggedP t f = withTagged' t (winMap f)

View File

@ -27,7 +27,7 @@ import qualified XMonad.StackSet as W
import XMonad.Layout.DraggingVisualizer
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
-- You can use this module with the following in your @xmonad.hs@:
--
-- > import XMonad.Actions.TiledWindowDragging
-- > import XMonad.Layout.DraggingVisualizer
@ -48,10 +48,11 @@ import XMonad.Layout.DraggingVisualizer
-- | Create a mouse binding for this to be able to drag your windows around.
-- You need "XMonad.Layout.DraggingVisualizer" for this to look good.
dragWindow :: Window -> X ()
dragWindow window = whenX (isClient window) $ do
dragWindow window = whenX (isClient window) $ withDisplay $ \dpy ->
withWindowAttributes dpy window $ \wa -> do
focus window
(offsetX, offsetY) <- getPointerOffset window
(winX, winY, winWidth, winHeight) <- getWindowPlacement window
let (winX, winY, winWidth, winHeight) = getWindowPlacement wa
mouseDrag
(\posX posY ->
@ -71,11 +72,8 @@ getPointerOffset win = do
return (fi oX, fi oY)
-- | return a tuple of windowX, windowY, windowWidth, windowHeight
getWindowPlacement :: Window -> X (Int, Int, Int, Int)
getWindowPlacement window = do
wa <- withDisplay (\d -> io $ getWindowAttributes d window)
return (fi $ wa_x wa, fi $ wa_y wa, fi $ wa_width wa, fi $ wa_height wa)
getWindowPlacement :: WindowAttributes -> (Int, Int, Int, Int)
getWindowPlacement wa = (fi $ wa_x wa, fi $ wa_y wa, fi $ wa_width wa, fi $ wa_height wa)
performWindowSwitching :: Window -> X ()
performWindowSwitching win = do
@ -85,7 +83,7 @@ performWindowSwitching win = do
let allWindows = W.index ws
when ((win `elem` allWindows) && (selWin `elem` allWindows)) $ do
let allWindowsSwitched = map (switchEntries win selWin) allWindows
let (ls, t : rs) = break (== win) allWindowsSwitched
(ls, t : rs) <- pure $ break (== win) allWindowsSwitched
let newStack = W.Stack t (reverse ls) rs
windows $ W.modify' $ const newStack
where

View File

@ -0,0 +1,122 @@
-- |
-- Module : XMonad.Actions.ToggleFullFloat
-- Description : Fullscreen (float) a window while remembering its original state.
-- Copyright : (c) 2022 Tomáš Janoušek <tomi@nomi.cz>
-- License : BSD3
-- Maintainer : Tomáš Janoušek <tomi@nomi.cz>
--
module XMonad.Actions.ToggleFullFloat (
-- * Usage
-- $usage
toggleFullFloatEwmhFullscreen,
toggleFullFloat,
fullFloat,
unFullFloat,
gcToggleFullFloat,
) where
import qualified Data.Map.Strict as M
import XMonad
import XMonad.Prelude
import XMonad.Hooks.EwmhDesktops (setEwmhFullscreenHooks)
import XMonad.Hooks.ManageHelpers
import qualified XMonad.StackSet as W
import qualified XMonad.Util.ExtensibleState as XS
-- ---------------------------------------------------------------------
-- $usage
--
-- The main use-case is to make 'ewmhFullscreen' (re)store the size and
-- position of floating windows instead of just unconditionally sinking them
-- into the floating layer. To enable this, you'll need this in your
-- @xmonad.hs@:
--
-- > import XMonad
-- > import XMonad.Actions.ToggleFullFloat
-- > import XMonad.Hooks.EwmhDesktops
-- >
-- > main = xmonad $ … . toggleFullFloatEwmhFullscreen . ewmhFullscreen . ewmh . … $ def{…}
--
-- Additionally, this "smart" fullscreening can be bound to a key and invoked
-- manually whenever one needs a larger window temporarily:
--
-- > , ((modMask .|. shiftMask, xK_t), withFocused toggleFullFloat)
newtype ToggleFullFloat = ToggleFullFloat{ fromToggleFullFloat :: M.Map Window (Maybe W.RationalRect) }
deriving (Show, Read)
instance ExtensionClass ToggleFullFloat where
extensionType = PersistentExtension
initialValue = ToggleFullFloat mempty
-- | Full-float a window, remembering its state (tiled/floating and
-- position/size).
fullFloat :: Window -> X ()
fullFloat = windows . appEndo <=< runQuery doFullFloatSave
-- | Restore window to its remembered state.
unFullFloat :: Window -> X ()
unFullFloat = windows . appEndo <=< runQuery doFullFloatRestore
-- | Full-float a window, if it's not already full-floating. Otherwise,
-- restore its original state.
toggleFullFloat :: Window -> X ()
toggleFullFloat w = ifM (isFullFloat w) (unFullFloat w) (fullFloat w)
isFullFloat :: Window -> X Bool
isFullFloat w = gets $ (Just fullRect ==) . M.lookup w . W.floating . windowset
where
fullRect = W.RationalRect 0 0 1 1
doFullFloatSave :: ManageHook
doFullFloatSave = do
w <- ask
liftX $ do
f <- gets $ M.lookup w . W.floating . windowset
-- @M.insertWith const@ = don't overwrite stored original state
XS.modify' $ ToggleFullFloat . M.insertWith const w f . fromToggleFullFloat
doFullFloat
doFullFloatRestore :: ManageHook
doFullFloatRestore = do
w <- ask
mf <- liftX $ do
mf <- XS.gets $ M.lookup w . fromToggleFullFloat
XS.modify' $ ToggleFullFloat . M.delete w . fromToggleFullFloat
pure mf
doF $ case mf of
Just (Just f) -> W.float w f -- was floating before
Just Nothing -> W.sink w -- was tiled before
Nothing -> W.sink w -- fallback when not found in ToggleFullFloat
-- | Install ToggleFullFloat garbage collection hooks.
--
-- Note: This is included in 'toggleFullFloatEwmhFullscreen', only needed if
-- using the 'toggleFullFloat' separately from the EWMH hook.
gcToggleFullFloat :: XConfig a -> XConfig a
gcToggleFullFloat c = c { startupHook = startupHook c <> gcToggleFullFloatStartupHook
, handleEventHook = handleEventHook c <> gcToggleFullFloatEventHook }
-- | ToggleFullFloat garbage collection: drop windows when they're destroyed.
gcToggleFullFloatEventHook :: Event -> X All
gcToggleFullFloatEventHook DestroyWindowEvent{ev_window = w} = do
XS.modify' $ ToggleFullFloat . M.delete w . fromToggleFullFloat
mempty
gcToggleFullFloatEventHook _ = mempty
-- | ToggleFullFloat garbage collection: restrict to existing windows at
-- startup.
gcToggleFullFloatStartupHook :: X ()
gcToggleFullFloatStartupHook = withWindowSet $ \ws ->
XS.modify' $ ToggleFullFloat . M.filterWithKey (\w _ -> w `W.member` ws) . fromToggleFullFloat
-- | Hook this module into 'XMonad.Hooks.EwmhDesktops.ewmhFullscreen'. This
-- makes windows restore their original state (size and position if floating)
-- instead of unconditionally sinking into the tiling layer.
--
-- ('gcToggleFullFloat' is included here.)
toggleFullFloatEwmhFullscreen :: XConfig a -> XConfig a
toggleFullFloatEwmhFullscreen =
setEwmhFullscreenHooks doFullFloatSave doFullFloatRestore .
gcToggleFullFloat

View File

@ -103,9 +103,12 @@ import XMonad.Hooks.WorkspaceHistory
-- display your topics in an historical way using a custom `pprWindowSet'
-- function. You can also easily switch to recent topics using this history
-- of last focused topics.
--
-- A blog post highlighting some features of this module can be found
-- <https://tony-zorman.com/posts/topic-space/2022-09-11-topic-spaces.html here>.
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
-- You can use this module with the following in your @xmonad.hs@:
--
-- > import qualified Data.Map.Strict as M
-- > import qualified XMonad.StackSet as W

View File

@ -79,8 +79,9 @@ import XMonad.Hooks.WorkspaceHistory
import qualified Data.Map as M
#ifdef XFT
import Graphics.X11.Xft
import qualified Data.List.NonEmpty as NE
import Graphics.X11.Xrender
import Graphics.X11.Xft
#endif
-- $usage
@ -532,11 +533,11 @@ navigate = gets tss_display >>= \d -> join . liftIO . allocaXEvent $ \e -> do
ev <- getEvent e
if | ev_event_type ev == keyPress -> do
(ks, _) <- lookupString $ asKeyEvent e
ks <- keycodeToKeysym d (ev_keycode ev) 0
return $ do
mask <- liftX $ cleanMask (ev_state ev)
mask <- liftX $ cleanKeyMask <*> pure (ev_state ev)
f <- asks ts_navigate
fromMaybe navigate $ M.lookup (mask, fromMaybe xK_VoidSymbol ks) f
fromMaybe navigate $ M.lookup (mask, ks) f
| ev_event_type ev == buttonPress -> do
-- See XMonad.Prompt Note [Allow ButtonEvents]
allowEvents d replayPointer currentTime
@ -648,10 +649,14 @@ drawStringXMF display window visual colormap gc font col x y text = case font of
setForeground display gc col
wcDrawImageString display window fnt gc x y text
#ifdef XFT
Xft fnt -> do
Xft fnts -> do
withXftDraw display window visual colormap $
\ft_draw -> withXftColorValue display visual colormap (fromARGB col) $
\ft_color -> xftDrawString ft_draw ft_color fnt x y text
#if MIN_VERSION_X11_xft(0, 3, 4)
\ft_color -> xftDrawStringFallback ft_draw ft_color (NE.toList fnts) (fi x) (fi y) text
#else
\ft_color -> xftDrawString ft_draw ft_color (NE.head fnts) x y text
#endif
-- | Convert 'Pixel' to 'XRenderColor'
--

169
XMonad/Actions/UpKeys.hs Normal file
View File

@ -0,0 +1,169 @@
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE TypeApplications #-}
{- |
Module : XMonad.Actions.UpKeys
Description : Bind an action to the release of a key
Copyright : (c) Tony Zorman, 2024
License : BSD-3
Maintainer : Tony Zorman <soliditsallgood@mailbox.org>
A combinator for binding an action to the release of a key. This can be
useful for hold-type buttons, where the press of a key engages some
functionality, and its release releases it again.
-}
module XMonad.Actions.UpKeys
( -- * Usage
-- $usage
useUpKeys,
UpKeysConfig (..),
ezUpKeys,
)
where
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import XMonad
import XMonad.Prelude
import XMonad.Util.EZConfig (mkKeymap)
import qualified XMonad.Util.ExtensibleConf as XC
{- $usage
You can use this module with the following in your @xmonad.hs@:
> import XMonad.Actions.UpKeys
Next, define the keys and actions you want to have happen on the release
of a key:
> myUpKeys = ezUpKeys $
> [ ("M-z", myAction)
> , ("M-a", myAction2)
> ]
All that's left is to plug this definition into the 'useUpKeys'
combinator that this module provides:
> main :: IO ()
> main = xmonad
> . useUpKeys (def{ grabKeys = True, upKeys = myUpKeys })
> $ myConfig
Note the presence of @'grabKeys' = True@; this is for situations where
you don't have any of these keys bound to do something upon pressing
them; i.e., you use them solely for their release actions. If you want
something to happen in both cases, remove that part (@'grabKeys' =
False@ is the default) and bind the keys to actions as you normally
would.
==== __Examples__
As an extended example, consider the case where you want all of your
docks (e.g., status bar) to "pop up" when you press the super key, and
then vanish again once that keys is released.
Since docks are not generally part of XMonad's window-setotherwise, we
would have to manage themwe first need a way to access and manipulate
all docks.
> onAllDocks :: (Display -> Window -> IO ()) -> X ()
> onAllDocks act = withDisplay \dpy -> do
> rootw <- asks theRoot
> (_, _, wins) <- io $ queryTree dpy rootw
> traverse_ (io . act dpy) =<< filterM (runQuery checkDock) wins
This is also the place where one could filter for just status bar,
trayer, and so on.
Now we have to decide what kinds of keys we want to watch out for. Since
you most likely use left super as your modifier key, this is a little
bit more complicated than for other keys, as you will most likely see
the key both as a @KeyMask@, as well as a @KeySym@. One could think a
bit and probably come up with an elegant solution for thisor one could
grab all possible key combinations by brute-force!
> dockKeys :: X () -> [((KeyMask, KeySym), X ())]
> dockKeys act = map (actKey . foldr1 (.|.)) . combinations $ keyMasks
> where
> actKey :: KeyMask -> ((KeyMask, KeySym), X ())
> actKey mask = ((mask, xK_Super_L), act)
>
> keyMasks :: [KeyMask]
> keyMasks = [ noModMask, shiftMask, lockMask, controlMask, mod1Mask, mod2Mask, mod3Mask, mod4Mask, mod5Mask ]
>
> -- Return all combinations of a sequence of values.
> combinations :: [a] -> [[a]]
> combinations xs = concat [combs i xs | i <- [1 .. length xs]]
> where
> combs 0 _ = [[]]
> combs _ [] = []
> combs n (x:xs) = map (x:) (combs (n-1) xs) <> combs n xs
Given some action, like lowering or raising the window, we generate all
possible combinations of modifiers that may be pressed with the super
key. This is a good time to say that this is just for demonstrative
purposes, btwplease don't actually do this.
All that's left is to plug everything into the machinery of this module,
and we're done!
> import qualified Data.Map.Strict as Map
>
> main :: IO ()
> main = xmonad
> . -- other combinators
> . useUpKeys (def { upKeys = Map.fromList $ dockKeys (onAllDocks lowerWindow) })
> $ myConfig `additionalKeys` dockKeys (onAllDocks raiseWindow)
>
> myConfig =
-}
data UpKeysConfig = UpKeysConfig
{ -- | Whether to grab all keys that are not already grabbed.
grabKeys :: !Bool
-- | The keys themselves.
, upKeys :: !(Map (KeyMask, KeySym) (X ()))
}
-- | The default 'UpKeysConfig'; keys are not grabbed, and no upkeys are
-- specified.
instance Default UpKeysConfig where
def :: UpKeysConfig
def = UpKeysConfig { grabKeys = False, upKeys = mempty }
instance Semigroup UpKeysConfig where
(<>) :: UpKeysConfig -> UpKeysConfig -> UpKeysConfig
UpKeysConfig g u <> UpKeysConfig g' u' = UpKeysConfig (g && g') (u <> u')
-- | Bind actions to keys upon their release.
useUpKeys :: UpKeysConfig -> (XConfig l -> XConfig l)
useUpKeys upKeysConf = flip XC.once upKeysConf \conf -> conf
{ handleEventHook = handleEventHook conf <> (\e -> handleKeyUp e $> All True)
, startupHook = startupHook conf <> when (grabKeys upKeysConf) grabUpKeys
}
where
grabUpKeys :: X ()
grabUpKeys = do
XConf{ display = dpy, theRoot = rootw } <- ask
realKeys <- maybe mempty upKeys <$> XC.ask @X @UpKeysConfig
let grab :: (KeyMask, KeyCode) -> X ()
grab (km, kc) = io $ grabKey dpy kc km rootw True grabModeAsync grabModeAsync
traverse_ grab =<< mkGrabs (Map.keys realKeys)
-- | Parse the given EZConfig-style keys into the internal keymap
-- representation.
--
-- This is just 'mkKeymap' with a better name.
ezUpKeys :: XConfig l -> [(String, X ())] -> Map (KeyMask, KeySym) (X ())
ezUpKeys = mkKeymap
-- | A handler for key-up events.
handleKeyUp :: Event -> X ()
handleKeyUp KeyEvent{ ev_event_type, ev_state, ev_keycode }
| ev_event_type == keyRelease = withDisplay \dpy -> do
s <- io $ keycodeToKeysym dpy ev_keycode 0
cln <- cleanMask ev_state
ks <- maybe mempty upKeys <$> XC.ask @X @UpKeysConfig
userCodeDef () $ whenJust (ks Map.!? (cln, s)) id
handleKeyUp _ = pure ()

View File

@ -27,7 +27,7 @@ import qualified XMonad.StackSet as W
-- $usage
-- To make the focus update on mouse movement within an unfocused window, add the
-- following to your @~\/.xmonad\/xmonad.hs@:
-- following to your @xmonad.hs@:
--
-- > import XMonad.Actions.UpdateFocus
-- > xmonad $ def {

View File

@ -28,11 +28,10 @@ import XMonad
import XMonad.Prelude
import XMonad.StackSet (member, peek, screenDetail, current)
import Control.Exception (SomeException, try)
import Control.Arrow ((&&&), (***))
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
-- You can use this module with the following in your @xmonad.hs@:
--
-- > import XMonad
-- > import XMonad.Actions.UpdatePointer
@ -73,10 +72,9 @@ updatePointer refPos ratio = do
let defaultRect = screenRect $ screenDetail $ current ws
rect <- case peek ws of
Nothing -> return defaultRect
Just w -> do tryAttributes <- io $ try $ getWindowAttributes dpy w
return $ case tryAttributes of
Left (_ :: SomeException) -> defaultRect
Right attributes -> windowAttributesToRectangle attributes
Just w -> maybe defaultRect windowAttributesToRectangle
<$> safeGetWindowAttributes w
root <- asks theRoot
mouseIsMoving <- asks mouseFocused
(_sameRoot,_,currentWindow,rootX,rootY,_,_,_) <- io $ queryPointer dpy root

View File

@ -28,7 +28,7 @@ import XMonad
import XMonad.StackSet as W
{- $usage
You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
You can use this module with the following in your @xmonad.hs@:
> import XMonad.Actions.Warp
@ -45,7 +45,7 @@ Note that warping to a particular screen may change the focus.
-}
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.
data Corner = UpperLeft | UpperRight | LowerLeft | LowerRight
@ -91,10 +91,8 @@ warp w x y = withDisplay $ \d -> io $ warpPointer d none w 0 0 0 0 x y
-- | Warp the pointer to a given position relative to the currently
-- focused window. Top left = (0,0), bottom right = (1,1).
warpToWindow :: Rational -> Rational -> X ()
warpToWindow h v =
withDisplay $ \d ->
withFocused $ \w -> do
wa <- io $ getWindowAttributes d w
warpToWindow h v = withDisplay $ \d -> withFocused $ \w ->
withWindowAttributes d w $ \wa ->
warp w (fraction h (wa_width wa)) (fraction v (wa_height wa))
-- | Warp the pointer to the given position (top left = (0,0), bottom

View File

@ -22,6 +22,7 @@ module XMonad.Actions.WindowBringer (
WindowBringerConfig(..),
gotoMenu, gotoMenuConfig, gotoMenu', gotoMenuArgs, gotoMenuArgs',
bringMenu, bringMenuConfig, bringMenu', bringMenuArgs, bringMenuArgs',
copyMenu, copyMenuConfig, copyMenu', copyMenuArgs, copyMenuArgs',
windowMap, windowAppMap, windowMap', bringWindow, actionMenu
) where
@ -33,10 +34,11 @@ import XMonad
import qualified XMonad as X
import XMonad.Util.Dmenu (menuMapArgs)
import XMonad.Util.NamedWindows (getName, getNameWMClass)
import XMonad.Actions.CopyWindow (copyWindow)
-- $usage
--
-- Import the module into your @~\/.xmonad\/xmonad.hs@:
-- Import the module into your @xmonad.hs@:
--
-- > import XMonad.Actions.WindowBringer
--
@ -44,9 +46,10 @@ import XMonad.Util.NamedWindows (getName, getNameWMClass)
--
-- > , ((modm .|. shiftMask, xK_g ), gotoMenu)
-- > , ((modm .|. shiftMask, xK_b ), bringMenu)
-- > , ((modm .|. shiftMask, xK_y ), copyMenu)
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.
data WindowBringerConfig = WindowBringerConfig
{ menuCommand :: String -- ^ The shell command that will handle window selection
@ -90,6 +93,37 @@ gotoMenu' cmd = gotoMenuConfig def { menuArgs = [], menuCommand = cmd }
gotoMenuArgs' :: String -> [String] -> X ()
gotoMenuArgs' cmd args = gotoMenuConfig def { menuCommand = cmd, menuArgs = args }
-- | Pops open a dmenu with window titles. Choose one, and it will be copied into your current workspace.
copyMenu :: X ()
copyMenu = copyMenuArgs def
-- | Pops open a dmenu with window titles. Choose one, and it will be
-- copied into your current workspace. This version
-- accepts a configuration object.
copyMenuConfig :: WindowBringerConfig -> X ()
copyMenuConfig wbConfig = actionMenu wbConfig copyBringWindow
-- | Pops open a dmenu with window titles. Choose one, and it will be
-- copied into your current workspace. This version
-- takes a list of arguments to pass to dmenu.
copyMenuArgs :: [String] -> X ()
copyMenuArgs args = copyMenuConfig def { menuArgs = args }
-- | Pops open an application with window titles given over stdin. Choose one,
-- and it will be copied into your current workspace.
copyMenu' :: String -> X ()
copyMenu' cmd = copyMenuConfig def { menuArgs = [], menuCommand = cmd }
-- | Pops open an application with window titles given over stdin. Choose one,
-- and it will be copied into your current
-- workspace. This version allows arguments to the chooser to be specified.
copyMenuArgs' :: String -> [String] -> X ()
copyMenuArgs' cmd args = copyMenuConfig def { menuArgs = args, menuCommand = cmd }
-- | Brings a copy of the specified window into the current workspace.
copyBringWindow :: Window -> X.WindowSet -> X.WindowSet
copyBringWindow w ws = copyWindow w (W.currentTag ws) ws
-- | Pops open a dmenu with window titles. Choose one, and it will be
-- dragged, kicking and screaming, into your current workspace.
bringMenu :: X ()
@ -159,7 +193,7 @@ decorateName ws w = do
return $ name ++ " [" ++ W.tag ws ++ "]"
-- | Returns the window name as will be listed in dmenu. This will
-- return the executable name of the window along with it's workspace
-- return the executable name of the window along with its workspace
-- ID.
decorateAppName :: X.WindowSpace -> Window -> X String
decorateAppName ws w = do

View File

@ -1,3 +1,5 @@
{-# LANGUAGE ViewPatterns #-}
{- |
Module : XMonad.Actions.WindowGo
Description : Operations for raising (traveling to) windows.
@ -46,9 +48,11 @@ import XMonad.Operations (windows)
import XMonad.Prompt.Shell (getBrowser, getEditor)
import qualified XMonad.StackSet as W (peek, swapMaster, focusWindow, workspaces, StackSet, Workspace, integrate', tag, stack)
import XMonad.Util.Run (safeSpawnProg)
import qualified Data.List.NonEmpty as NE
{- $usage
Import the module into your @~\/.xmonad\/xmonad.hs@:
Import the module into your @xmonad.hs@:
> import XMonad.Actions.WindowGo
@ -64,7 +68,8 @@ appropriate one, or cover your bases by using instead something like:
> (className =? "Firefox" <||> className =? "Firefox-bin")
For detailed instructions on editing your key bindings, see
"XMonad.Doc.Extending#Editing_key_bindings". -}
<https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.
-}
-- | Get the list of workspaces sorted by their tag
workspacesSorted :: Ord i => W.StackSet i l a s sd -> [W.Workspace i l a]
@ -87,7 +92,10 @@ ifWindows qry f el = withWindowSet $ \wins -> do
-- | The same as ifWindows, but applies a ManageHook to the first match
-- instead and discards the other matches
ifWindow :: Query Bool -> ManageHook -> X () -> X ()
ifWindow qry mh = ifWindows qry (windows . appEndo <=< runQuery mh . head)
ifWindow qry mh = ifWindows qry (windows . appEndo <=< runQuery mh . NE.head . notEmpty)
-- ifWindows guarantees that the list given to the function is
-- non-empty. This should really use Data.List.NonEmpty, but, alas,
-- that would be a breaking change.
{- | 'action' is an executable to be run via 'safeSpawnProg' (of "XMonad.Util.Run") if the Window cannot be found.
Presumably this executable is the same one that you were looking for.
@ -158,9 +166,12 @@ raiseNextMaybeCustomFocus :: (Window -> WindowSet -> WindowSet) -> X() -> Query
raiseNextMaybeCustomFocus focusFn f qry = flip (ifWindows qry) f $ \ws -> do
foc <- withWindowSet $ return . W.peek
case foc of
Just w | w `elem` ws -> let (_:y:_) = dropWhile (/=w) $ cycle ws -- cannot fail to match
Just w | w `elem` ws ->
let (notEmpty -> _ :| (notEmpty -> y :| _)) = dropWhile (/=w) $ cycle ws
-- cannot fail to match
in windows $ focusFn y
_ -> windows . focusFn . head $ ws
_ -> windows . focusFn . NE.head . notEmpty $ ws
-- ws is non-empty by ifWindows's definition.
-- | Given a function which gets us a String, we try to raise a window with that classname,
-- or we then interpret that String as a executable name.

View File

@ -34,7 +34,7 @@ import XMonad.Prelude (fi)
-- $usage
--
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
-- You can use this module with the following in your @xmonad.hs@:
--
-- > import XMonad.Actions.WindowMenu
--
@ -51,9 +51,9 @@ colorizer _ isFg = do
else (nBC, fBC)
windowMenu :: X ()
windowMenu = withFocused $ \w -> do
windowMenu = withFocused $ \w -> withDisplay $ \d -> withWindowAttributes d w $ \wa -> do
tags <- asks (workspaces . config)
Rectangle x y wh ht <- getSize w
let Rectangle x y wh ht = getSize wa
Rectangle sx sy swh sht <- gets $ screenRect . W.screenDetail . W.current . windowset
let originFractX = (fi x - fi sx + fi wh / 2) / fi swh
originFractY = (fi y - fi sy + fi ht / 2) / fi sht
@ -69,12 +69,10 @@ windowMenu = withFocused $ \w -> do
| tag <- tags ]
runSelectedAction gsConfig actions
getSize :: Window -> X Rectangle
getSize w = do
d <- asks display
wa <- io $ getWindowAttributes d w
getSize :: WindowAttributes -> Rectangle
getSize wa =
let x = fi $ wa_x wa
y = fi $ wa_y wa
wh = fi $ wa_width wa
ht = fi $ wa_height wa
return (Rectangle x y wh ht)
in Rectangle x y wh ht

View File

@ -1,10 +1,12 @@
{-# LANGUAGE TupleSections #-} -- I didn't want this, it's hlint's "suggestion" and it's apparently non-negotiable
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.WindowNavigation
-- Description : Experimental rewrite of "XMonad.Layout.WindowNavigation".
-- Copyright : (c) 2007 David Roundy <droundy@darcs.net>,
-- Devin Mullins <me@twifkak.com>
-- Maintainer : Devin Mullins <me@twifkak.com>
-- Maintainer : Devin Mullins <me@twifkak.com>,
-- Platon Pronko <platon7pronko@gmail.com>
-- License : BSD3-style (see LICENSE)
-- Stability : unstable
-- Portability : unportable
@ -37,17 +39,19 @@ module XMonad.Actions.WindowNavigation (
withWindowNavigationKeys,
WNAction(..),
go, swap,
goPure, swapPure,
Direction2D(..), WNState,
) where
import XMonad
import XMonad.Prelude (catMaybes, fromMaybe, listToMaybe, sortOn)
import XMonad hiding (state)
import XMonad.Prelude (catMaybes, fromMaybe, sortOn)
import XMonad.Util.Types (Direction2D(..))
import qualified XMonad.StackSet as W
import Control.Arrow (second)
import Data.IORef
import Data.Map (Map())
import Data.List (partition, find)
import qualified Data.Map as M
import qualified Data.Set as S
@ -101,33 +105,66 @@ withWindowNavigation (u,l,d,r) conf@XConfig{modMask=modm} =
withWindowNavigationKeys :: [((KeyMask, KeySym), WNAction)] -> XConfig l -> IO (XConfig l)
withWindowNavigationKeys wnKeys conf = do
posRef <- newIORef M.empty
return conf { keys = \cnf -> M.fromList (map (second (fromWNAction posRef)) wnKeys)
stateRef <- newIORef M.empty
return conf { keys = \cnf -> M.fromList (map (second (fromWNAction stateRef)) wnKeys)
`M.union` keys conf cnf,
logHook = logHook conf >> trackMovement posRef }
where fromWNAction posRef (WNGo dir) = go posRef dir
fromWNAction posRef (WNSwap dir) = swap posRef dir
logHook = logHook conf >> trackMovement stateRef }
where fromWNAction stateRef (WNGo dir) = go stateRef dir
fromWNAction stateRef (WNSwap dir) = swap stateRef dir
data WNAction = WNGo Direction2D | WNSwap Direction2D
type WNState = Map WorkspaceId Point
-- go:
-- 1. get current position, verifying it matches the current window
-- 2. get target windowrect
-- 3. focus window
-- 4. set new position
-- | Focus window in the given direction.
go :: IORef WNState -> Direction2D -> X ()
go = withTargetWindow W.focusWindow
go stateRef dir = runPureAction stateRef (goPure dir)
-- | Swap current window with the window in the given direction.
-- Note: doesn't work with floating windows (don't think it makes much sense to swap floating windows).
swap :: IORef WNState -> Direction2D -> X ()
swap = withTargetWindow swapWithFocused
swap stateRef dir = runPureAction stateRef (swapPure dir)
type WindowRectFn x = (Window -> x (Maybe Rectangle))
-- | (state, oldWindowSet, mappedWindows, windowRect)
type WNInput x = (WNState, WindowSet, S.Set Window, WindowRectFn x)
type WNOutput = (WNState, WindowSet)
-- | Run the pure action inside X monad.
runPureAction :: IORef WNState -> (WNInput X -> X WNOutput) -> X ()
runPureAction stateRef action = do
oldState <- io (readIORef stateRef)
oldWindowSet <- gets windowset
mappedWindows <- gets mapped
(newState, newWindowSet) <- action (oldState, oldWindowSet, mappedWindows, windowRectX)
windows (const newWindowSet)
io $ writeIORef stateRef newState
-- | Version of `go` not dependent on X monad (needed for testing).
goPure :: Monad x => Direction2D -> WNInput x -> x WNOutput
goPure dir input@(oldState, oldWindowSet, mappedWindows, _) =
if length (filter (`S.member` mappedWindows) $ W.integrate' $ W.stack $ W.workspace $ W.current oldWindowSet) == 1
then
-- Handle the special case of Full layout, when there's only one mapped window on a screen.
return ( oldState
, case dir of
U -> W.focusUp oldWindowSet
L -> W.focusDown oldWindowSet
D -> W.focusDown oldWindowSet
R -> W.focusUp oldWindowSet
)
else
withTargetWindow W.focusWindow dir input
-- | Version of `swap` not dependent on X monad (needed for testing).
swapPure :: Monad x => Direction2D -> WNInput x -> x WNOutput
swapPure = withTargetWindow swapWithFocused
where swapWithFocused targetWin winSet =
case W.peek winSet of
Just currentWin -> W.focusWindow currentWin $
mapWindows (swapWin currentWin targetWin) winSet
Nothing -> winSet
mapWindows f ss = W.mapWorkspace (mapWindows' f) ss
mapWindows f = W.mapWorkspace (mapWindows' f)
mapWindows' f ws@W.Workspace{ W.stack = s } = ws { W.stack = mapWindows'' f <$> s }
mapWindows'' f (W.Stack focused up down) = W.Stack (f focused) (map f up) (map f down)
swapWin win1 win2 win
@ -135,87 +172,249 @@ swap = withTargetWindow swapWithFocused
| win == win2 = win1
| otherwise = win
withTargetWindow :: (Window -> WindowSet -> WindowSet) -> IORef WNState -> Direction2D -> X ()
withTargetWindow adj posRef dir = fromCurrentPoint posRef $ \win pos -> do
targets <- filter ((/= win) . fst) <$> navigableTargets pos dir
whenJust (listToMaybe targets) $ \(targetWin, targetRect) -> do
windows (adj targetWin)
setPosition posRef pos targetRect
-- | Select a target window in the given direction and modify the WindowSet.
-- 1. Get current position, verifying it matches the current window (exit if no focused window).
-- 2. Get the target window.
-- 3. Execute an action on the target window and windowset.
-- 4. Set the new position.
withTargetWindow :: Monad x => (Window -> WindowSet -> WindowSet) -> Direction2D -> WNInput x -> x WNOutput
withTargetWindow adj dir input@(oldState, oldWindowSet, _, _) = do
whenJust' (getCurrentWindow input) (oldState, oldWindowSet) $ \(win, winRect, pos) -> do
targetMaybe <- find ((/= win) . fst) <$> navigableTargets input dir winRect pos
whenJust' (pure targetMaybe) (oldState, oldWindowSet) $ \(targetWin, newPos) ->
let newWindowSet = adj targetWin oldWindowSet
in return (modifyState newWindowSet newPos oldState, newWindowSet)
-- | Update position on outside changes in windows.
trackMovement :: IORef WNState -> X ()
trackMovement posRef = fromCurrentPoint posRef $ \win pos ->
windowRect win >>= flip whenJust (setPosition posRef pos . snd)
trackMovement stateRef = do
oldState <- io (readIORef stateRef)
oldWindowSet <- gets windowset
mappedWindows <- gets mapped
whenJust' (getCurrentWindow (oldState, oldWindowSet, mappedWindows, windowRectX)) () $ \(_, _, pos) -> do
io $ writeIORef stateRef $ modifyState oldWindowSet pos oldState
fromCurrentPoint :: IORef WNState -> (Window -> Point -> X ()) -> X ()
fromCurrentPoint posRef f = withFocused $ \win ->
currentPosition posRef >>= f win
-- | Get focused window and current position.
getCurrentWindow :: Monad x => WNInput x -> x (Maybe (Window, Rectangle, Point))
getCurrentWindow input@(_, oldWindowSet, _, _) =
whenJust' (pure $ W.peek oldWindowSet) Nothing $ \window -> do
(pos, rect) <- currentPosition input
return $ Just (window, rect, pos)
-- Gets the current position from the IORef passed in, or if nothing (say, from
-- a restart), derives the current position from the current window. Also,
-- verifies that the position is congruent with the current window (say, if you
-- used mod-j/k or mouse or something).
currentPosition :: IORef WNState -> X Point
currentPosition posRef = do
root <- asks theRoot
currentWindow <- gets (W.peek . windowset)
currentRect <- maybe (Rectangle 0 0 0 0) snd <$> windowRect (fromMaybe root currentWindow)
-- | Gets the current position from the state passed in, or if nothing
-- (say, from a restart), derives the current position from the current window.
-- Also, verifies that the position is congruent with the current window
-- (say, if you moved focus using mouse or something).
-- Returns the window rectangle for convenience, since we'll need it later anyway.
currentPosition :: Monad x => WNInput x -> x (Point, Rectangle)
currentPosition (state, oldWindowSet, _, windowRect) = do
currentRect <- fromMaybe (Rectangle 0 0 0 0) <$> maybe (pure Nothing) windowRect (W.peek oldWindowSet)
let posMaybe = M.lookup (W.currentTag oldWindowSet) state
middleOf (Rectangle x y w h) = Point (midPoint x w) (midPoint y h)
return $ case posMaybe of
Nothing -> (middleOf currentRect, currentRect)
Just pos -> (centerPosition currentRect pos, currentRect)
wsid <- gets (W.currentTag . windowset)
mp <- M.lookup wsid <$> io (readIORef posRef)
-- | Inserts new position into the state.
modifyState :: WindowSet -> Point -> WNState -> WNState
modifyState oldWindowSet =
M.insert (W.currentTag oldWindowSet)
return $ maybe (middleOf currentRect) (`inside` currentRect) mp
where middleOf (Rectangle x y w h) = Point (midPoint x w) (midPoint y h)
setPosition :: IORef WNState -> Point -> Rectangle -> X ()
setPosition posRef oldPos newRect = do
wsid <- gets (W.currentTag . windowset)
io $ modifyIORef posRef $ M.insert wsid (oldPos `inside` newRect)
inside :: Point -> Rectangle -> Point
Point x y `inside` Rectangle rx ry rw rh =
Point (x `within` (rx, rw)) (y `within` (ry, rh))
where pos `within` (lower, dim) = if pos >= lower && pos < lower + fromIntegral dim
-- | "Jumps" the current position into the middle of target rectangle.
-- (keeps the position as-is if it is already inside the target rectangle)
centerPosition :: Rectangle -> Point -> Point
centerPosition r@(Rectangle rx ry rw rh) pos@(Point x y) = do
if pointWithin x y r
then pos
else midPoint lower dim
else Point (midPoint rx rw) (midPoint ry rh)
midPoint :: Position -> Dimension -> Position
midPoint pos dim = pos + fromIntegral dim `div` 2
navigableTargets :: Point -> Direction2D -> X [(Window, Rectangle)]
navigableTargets point dir = navigable dir point <$> windowRects
-- | Make a list of target windows we can navigate to,
-- sorted by desirability of navigation.
navigableTargets :: Monad x => WNInput x -> Direction2D -> Rectangle -> Point -> x [(Window, Point)]
navigableTargets input@(_, oldWindowSet, _, _) dir currentRect currentPos = do
allScreensWindowsAndRectangles <- mapSnd (rectTransform dir) <$> windowRects input
let
screenWindows = S.fromList $ W.integrate' $ W.stack $ W.workspace $ W.current oldWindowSet
(thisScreenWindowsAndRectangles, otherScreensWindowsAndRectangles) = partition (\(w, _) -> S.member w screenWindows) allScreensWindowsAndRectangles
-- Filters and sorts the windows in terms of what is closest from the Point in
-- the Direction2D.
navigable :: Direction2D -> Point -> [(Window, Rectangle)] -> [(Window, Rectangle)]
navigable d pt = sortby d . filter (inr d pt . snd)
pos = pointTransform dir currentPos
wr = rectTransform dir currentRect
-- Produces a list of normal-state windows, on any screen. Rectangles are
-- adjusted based on screen position relative to the current screen, because I'm
-- bad like that.
windowRects :: X [(Window, Rectangle)]
windowRects = fmap catMaybes . mapM windowRect . S.toList =<< gets mapped
rectInside r = (rect_p1 r >= rect_p1 wr && rect_p1 r < rect_p2 wr && rect_p2 r > rect_p1 wr && rect_p2 r <= rect_p2 wr) &&
((rect_o1 r >= rect_o1 wr && rect_o1 r < rect_o2 wr && rect_o2 r > rect_o1 wr && rect_o2 r <= rect_o2 wr) ||
(rect_o1 r <= rect_o1 wr && rect_o2 r >= rect_o2 wr)) -- include windows that fully overlaps current on the orthogonal axis
sortByP2 = sortOn (rect_p2 . snd)
posBeforeEdge r = point_p pos < rect_p2 r
windowRect :: Window -> X (Maybe (Window, Rectangle))
windowRect win = withDisplay $ \dpy -> do
rectOverlapsEdge r = rect_p1 r <= rect_p2 wr && rect_p2 r > rect_p2 wr &&
rect_o1 r < rect_o2 wr && rect_o2 r > rect_o1 wr
rectOverlapsOneEdge r = rectOverlapsEdge r && rect_p1 r > rect_p1 wr
rectOverlapsBothEdges r = rectOverlapsEdge r &&
rect_o1 r > rect_o1 wr && rect_o2 r < rect_o2 wr && point_o pos >= rect_o1 r && point_o pos < rect_o2 r
distanceToRectEdge r = max (max 0 (rect_o1 r - point_o pos)) (max 0 (point_o pos + 1 - rect_o2 r))
distanceToRectCenter r =
let distance = (rect_o1 r + rect_o2 r) `div` 2 - point_o pos
in if distance <= 0
then distance + 1
else distance
sortByPosDistance = sortOn ((\r -> (rect_p1 r, distanceToRectEdge r, distanceToRectCenter r)) . snd)
rectOutside r = rect_p1 r < rect_p1 wr && rect_p2 r > rect_p2 wr &&
rect_o1 r < rect_o1 wr && rect_o2 r > rect_o2 wr
sortByLength = sortOn (rect_psize . snd)
rectAfterEdge r = rect_p1 r > rect_p2 wr
-- Modified from David Roundy and Devin Mullins original implementation of WindowNavigation:
inr r = point_p pos < rect_p2 r && point_o pos >= rect_o1 r && point_o pos < rect_o2 r
clamp v v1 v2 | v < v1 = v1
| v >= v2 = v2 - 1
| otherwise = v
dragPos r = DirPoint (max (point_p pos) (rect_p1 r)) (clamp (point_o pos) (rect_o1 r) (rect_o2 r))
return $ mapSnd (inversePointTransform dir) $ concat
[
-- First, navigate to windows that are fully inside current window
-- and have higher coordinate bigger than current position.
-- ┌──────────────────┐
-- │ current │ (all examples assume direction=R)
-- │ ┌──────────┐ │
-- │ ──┼─► inside │ │
-- │ └──────────┘ │
-- └──────────────────┘
-- Also include windows fully overlapping current on the orthogonal axis:
-- ┌──────────────┐
-- │ overlapping │
-- ┌───────────┤ ├────┐
-- │ current ──┼─► │ │
-- └───────────┤ ├────┘
-- └──────────────┘
mapSnd dragPos $ sortByP2 $ filterSnd posBeforeEdge $ filterSnd rectInside thisScreenWindowsAndRectangles
-- Then navigate to windows that touch or overlap the edge of current window in the chosen direction.
-- ┌──────────────┬─────────────┐ ┌───────────┐ ┌─────────────┐
-- │ current │ adjacent │ │ current │ │ current │
-- │ ──┼─► │ │ ┌───┴───────────────┐ │ ┌───┴─────────────┐
-- │ │ │ │ ──┼─► │ overlapping │ │ ──┼─► │
-- │ ├─────────────┘ │ └───┬───────────────┘ └─────────┤ overlapping │
-- │ │ │ │ │ │
-- └──────────────┘ └───────────┘ └─────────────────┘
, mapSnd dragPos $ sortByPosDistance $ filterSnd rectOverlapsOneEdge thisScreenWindowsAndRectangles
-- Windows fully overlapping current window "in the middle" on the parallel axis are also included,
-- if position is inside them:
-- ┌───────────┐
-- │ current │
-- ┌───┤-----------├────────────────┐
-- │ │ * ──┼─► overlapping │
-- └───┤-----------├────────────────┘
-- └───────────┘
, mapSnd (\_ -> DirPoint (rect_p2 wr) (point_o pos)) $ sortByPosDistance $ filterSnd rectOverlapsBothEdges thisScreenWindowsAndRectangles
-- Then navigate to windows that fully encompass the current window.
-- ┌─────────────────────┐
-- │ outer │
-- │ ┌─────────────┐ │
-- │ │ current ──┼─► │
-- │ └─────────────┘ │
-- └─────────────────────┘
, mapSnd (\_ -> DirPoint (rect_p2 wr) (point_o pos)) $ sortByLength $ filterSnd rectOutside thisScreenWindowsAndRectangles
-- Then navigate to windows that are fully after current window in the chosen direction.
-- ┌──────────────┐
-- │ current │ ┌────────────────┐
-- │ │ │ │
-- │ ──┼──┼─► not adjacent │
-- │ │ │ │
-- │ │ └────────────────┘
-- └──────────────┘
, mapSnd dragPos $ sortByPosDistance $ filterSnd rectAfterEdge thisScreenWindowsAndRectangles
-- Cast a ray from the current position, jump to the first window (on another screen) that intersects this ray.
, mapSnd dragPos $ sortByPosDistance $ filterSnd inr otherScreensWindowsAndRectangles
-- If everything else fails, then navigate to the window that is fully inside current window,
-- but is before the current position.
-- This can happen when we are at the last window on a screen, and attempt to navigate even further.
-- In this case it seems okay to jump to the remaining inner windows, since we don't have any other choice anyway,
-- and user is probably not so fully aware of the precise position anyway.
, mapSnd (\r -> DirPoint (rect_p2 r - 1) (clamp (point_o pos) (rect_o1 r) (rect_o2 r))) $
sortByP2 $ filterSnd (not . posBeforeEdge) $ filterSnd rectInside thisScreenWindowsAndRectangles
]
-- Structs for direction-independent space - equivalent to rotating points and rectangles such that
-- navigation direction points to the right.
-- Allows us to abstract over direction in the navigation functions.
data DirPoint = DirPoint
{ point_p :: Position -- coordinate parallel to the direction
, point_o :: Position -- coordinate orthogonal to the direction
}
data DirRectangle = DirRectangle
{ rect_p1 :: Position -- lower rectangle coordinate parallel to the direction
, rect_p2 :: Position -- higher rectangle coordinate parallel to the direction
, rect_o1 :: Position -- lower rectangle coordinate orthogonal to the direction
, rect_o2 :: Position -- higher rectangle coordinate orthogonal to the direction
}
{- HLINT ignore "Use camelCase" -}
rect_psize :: DirRectangle -> Dimension
rect_psize r = fromIntegral (rect_p2 r - rect_p1 r)
-- | Transform a point from screen space into direction-independent space.
pointTransform :: Direction2D -> Point -> DirPoint
pointTransform dir (Point x y) = case dir of
U -> DirPoint (negate y - 1) x
L -> DirPoint (negate x - 1) (negate y - 1)
D -> DirPoint y (negate x - 1)
R -> DirPoint x y
-- | Transform a point from direction-independent space back into screen space.
inversePointTransform :: Direction2D -> DirPoint -> Point
inversePointTransform dir p = case dir of
U -> Point (point_o p) (negate $ point_p p + 1)
L -> Point (negate $ point_p p + 1) (negate $ point_o p + 1)
D -> Point (negate $ point_o p + 1) (point_p p)
R -> Point (point_p p) (point_o p)
-- | Transform a rectangle from screen space into direction-independent space.
rectTransform :: Direction2D -> Rectangle -> DirRectangle
rectTransform dir (Rectangle x y w h) = case dir of
U -> DirRectangle (negate $ y + fromIntegral h) (negate y) x (x + fromIntegral w)
L -> DirRectangle (negate $ x + fromIntegral w) (negate x) (negate $ y + fromIntegral h) (negate y)
D -> DirRectangle y (y + fromIntegral h) (negate $ x + fromIntegral w) (negate x)
R -> DirRectangle x (x + fromIntegral w) y (y + fromIntegral h)
-- | Produces a list of normal-state windows on all screens, excluding currently focused window.
windowRects :: Monad x => WNInput x -> x [(Window, Rectangle)]
windowRects (_, oldWindowSet, mappedWindows, windowRect) =
let
allWindows = filter (\w -> w `notElem` W.peek oldWindowSet) $ S.toList mappedWindows
windowRect2 w = fmap (w,) <$> windowRect w
in catMaybes <$> mapM windowRect2 allWindows
windowRectX :: Window -> X (Maybe Rectangle)
windowRectX win = withDisplay $ \dpy -> do
(_, x, y, w, h, bw, _) <- io $ getGeometry dpy win
return $ Just (win, Rectangle x y (w + 2 * bw) (h + 2 * bw))
return $ Just $ Rectangle x y (w + 2 * bw) (h + 2 * bw)
`catchX` return Nothing
-- Modified from droundy's implementation of WindowNavigation:
-- Maybe below functions can be replaced with some standard helper functions?
inr :: Direction2D -> Point -> Rectangle -> Bool
inr D (Point px py) (Rectangle rx ry w h) = px >= rx && px < rx + fromIntegral w &&
py < ry + fromIntegral h
inr U (Point px py) (Rectangle rx ry w _) = px >= rx && px < rx + fromIntegral w &&
py > ry
inr R (Point px py) (Rectangle rx ry _ h) = px < rx &&
py >= ry && py < ry + fromIntegral h
inr L (Point px py) (Rectangle rx ry w h) = px > rx + fromIntegral w &&
py >= ry && py < ry + fromIntegral h
-- | Execute a monadic action on the contents if Just, otherwise wrap default value and return it.
whenJust' :: Monad x => x (Maybe a) -> b -> (a -> x b) -> x b
whenJust' monadMaybeValue deflt f = do
maybeValue <- monadMaybeValue
case maybeValue of
Nothing -> return deflt
Just value -> f value
sortby :: Direction2D -> [(a,Rectangle)] -> [(a,Rectangle)]
sortby D = sortOn (rect_y . snd)
sortby R = sortOn (rect_x . snd)
sortby U = reverse . sortby D
sortby L = reverse . sortby R
-- | Filter a list of tuples on the second tuple member.
filterSnd :: (b -> Bool) -> [(a, b)] -> [(a, b)]
filterSnd f = filter (f . snd)
-- | Map a second tuple member in a list of tuples.
mapSnd :: (b -> b') -> [(a, b)] -> [(a, b')]
mapSnd f = map (second f)

View File

@ -24,7 +24,7 @@ import XMonad.StackSet
-- $usage
--
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
-- You can use this module with the following in your @xmonad.hs@:
--
-- > import XMonad.Actions.WithAll
--
@ -33,7 +33,7 @@ import XMonad.StackSet
-- , ((modm .|. shiftMask, xK_t), sinkAll)
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.
-- | Un-float all floating windows on the current workspace.
sinkAll :: X ()

View File

@ -1,3 +1,5 @@
{-# LANGUAGE ViewPatterns #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.Workscreen
@ -35,12 +37,13 @@ module XMonad.Actions.Workscreen (
) where
import XMonad hiding (workspaces)
import XMonad.Prelude
import qualified XMonad.StackSet as W
import qualified XMonad.Util.ExtensibleState as XS
import XMonad.Actions.OnScreen
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
-- You can use this module with the following in your @xmonad.hs@:
--
-- > import XMonad.Actions.Workscreen
-- > myWorkspaces = let myOldWorkspaces = ["adm","work","mail"]
@ -55,7 +58,7 @@ import XMonad.Actions.OnScreen
-- > , (f, m) <- [(Workscreen.viewWorkscreen, 0), (Workscreen.shiftToWorkscreen, shiftMask)]]
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.
data Workscreen = Workscreen{workscreenId::Int,workspaces::[WorkspaceId]} deriving (Show)
@ -90,7 +93,7 @@ viewWorkscreen wscrId = do (WorkscreenStorage c a) <- XS.get
let wscr = if wscrId == c
then Workscreen wscrId $ shiftWs (workspaces $ a !! wscrId)
else a !! wscrId
(x,_:ys) = splitAt wscrId a
(x, notEmpty -> _ :| ys) = splitAt wscrId a
newWorkscreenStorage = WorkscreenStorage wscrId (x ++ [wscr] ++ ys)
windows (viewWorkscreen' wscr)
XS.put newWorkscreenStorage
@ -106,5 +109,6 @@ shiftWs a = drop 1 a ++ take 1 a
-- @WorkscreenId@.
shiftToWorkscreen :: WorkscreenId -> X ()
shiftToWorkscreen wscrId = do (WorkscreenStorage _ a) <- XS.get
let ws = head . workspaces $ a !! wscrId
windows $ W.shift ws
case workspaces (a !! wscrId) of
[] -> pure ()
(w : _) -> windows $ W.shift w

View File

@ -50,7 +50,7 @@ import XMonad.Layout.LayoutModifier(ModifiedLayout(..),
import XMonad(Message, WorkspaceId, X, XState(windowset),
fromMessage, sendMessage, windows, gets)
import XMonad.Util.Stack (reverseS)
import XMonad.Prelude (find, fromJust, guard, liftA2, toList, when, (<=<))
import XMonad.Prelude
-- $usage
--
@ -96,9 +96,9 @@ import XMonad.Prelude (find, fromJust, guard, liftA2, toList, when, (<=<))
-- | makeCursors requires a nonempty string, and each sublist must be nonempty
makeCursors :: [[String]] -> Cursors String
makeCursors [] = error "Workspace Cursors cannot be empty"
makeCursors a = concat . reverse <$> foldl addDim x xs
where x = end $ map return $ head a
xs = map (map return) $ tail a
makeCursors (a : as) = concat . reverse <$> foldl addDim x xs
where x = end $ map return a
xs = map (map return) as
-- this could probably be simplified, but this true:
-- toList . makeCursors == map (concat . reverse) . sequence . reverse . map (map (:[]))
-- the strange order is used because it makes the regular M-1..9
@ -212,4 +212,4 @@ instance LayoutModifier WorkspaceCursors a where
return (arrs,WorkspaceCursors <$> focusTo cws cs)
handleMess (WorkspaceCursors cs) m =
sequenceA $ fmap WorkspaceCursors . ($ cs) . unWrap <$> fromMessage m
traverse (fmap WorkspaceCursors . ($ cs) . unWrap) (fromMessage m)

View File

@ -51,14 +51,14 @@ import XMonad.Actions.CycleWS (findWorkspace, WSType(..), Direction1D(..), anyWS
import qualified XMonad.Actions.SwapWorkspaces as Swap
import XMonad.Hooks.StatusBar.PP (PP(..))
import XMonad.Hooks.EwmhDesktops (addEwmhWorkspaceRename)
import XMonad.Prompt (mkXPrompt, XPConfig)
import XMonad.Prompt (mkXPrompt, XPConfig, historyCompletionP)
import XMonad.Prompt.Workspace (Wor(Wor))
import XMonad.Util.WorkspaceCompare (getSortByIndex)
import qualified Data.Map as M
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@ file:
-- You can use this module with the following in your @xmonad.hs@ file:
--
-- > import XMonad.Actions.WorkspaceNames
--
@ -88,7 +88,7 @@ import qualified Data.Map as M
-- > | (i, k) <- zip workspaces [xK_1 ..]]
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
-- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.
@ -137,9 +137,11 @@ setCurrentWorkspaceName name = do
-- | Prompt for a new name for the current workspace and set it.
renameWorkspace :: XPConfig -> X ()
renameWorkspace conf =
mkXPrompt pr conf (const (return [])) setCurrentWorkspaceName
where pr = Wor "Workspace name: "
renameWorkspace conf = do
completion <- historyCompletionP conf (prompt ==)
mkXPrompt (Wor prompt) conf completion setCurrentWorkspaceName
where
prompt = "Workspace name: "
-- | See 'XMonad.Actions.SwapWorkspaces.swapTo'. This is the same with names.
swapTo :: Direction1D -> X ()

View File

@ -16,6 +16,7 @@
------------------------------------------------------------------------
module XMonad.Config.Arossato
{-# DEPRECATED "This module contains a personal configuration, to be removed from xmonad-contrib. If you use this module, please copy the relevant parts to your configuration or obtain a copy of it on https://xmonad.org/configurations.html and include it as a local module." #-}
( -- * Usage
-- $usage
arossatoConfig
@ -46,7 +47,7 @@ import XMonad.Util.Themes
-- $usage
-- The simplest way to use this configuration module is to use an
-- @~\/.xmonad\/xmonad.hs@ like this:
-- @xmonad.hs@ like this:
--
-- > module Main (main) where
-- >
@ -63,7 +64,7 @@ import XMonad.Util.Themes
--
-- You can use this module also as a starting point for writing your
-- own configuration module from scratch. Save it as your
-- @~\/.xmonad\/xmonad.hs@ and:
-- @xmonad.hs@ and:
--
-- 1. Change the module name from
--

View File

@ -27,7 +27,7 @@ import qualified XMonad.StackSet as W
import qualified Data.Map as M
-- $usage
-- To use this module, start with the following @~\/.xmonad\/xmonad.hs@:
-- To use this module, start with the following @xmonad.hs@:
--
-- > import XMonad
-- > import XMonad.Config.Azerty
@ -37,11 +37,11 @@ import qualified Data.Map as M
-- If you prefer, an azertyKeys function is provided which you can use as so:
--
-- > import qualified Data.Map as M
-- > main = xmonad someConfig { keys = \c -> azertyKeys c <+> keys someConfig c }
-- > main = xmonad someConfig { keys = \c -> azertyKeys c <> keys someConfig c }
azertyConfig = def { keys = azertyKeys <+> keys def }
azertyConfig = def { keys = azertyKeys <> keys def }
belgianConfig = def { keys = belgianKeys <+> keys def }
belgianConfig = def { keys = belgianKeys <> keys def }
azertyKeys = azertyKeysTop [0x26,0xe9,0x22,0x27,0x28,0x2d,0xe8,0x5f,0xe7,0xe0]

View File

@ -26,7 +26,7 @@ import qualified XMonad.StackSet as W
import qualified Data.Map as M
-- $usage
-- To use this module, start with the following @~\/.xmonad\/xmonad.hs@:
-- To use this module, start with the following @xmonad.hs@:
--
-- > import XMonad
-- > import XMonad.Config.Bepo
@ -38,7 +38,7 @@ import qualified Data.Map as M
-- > import qualified Data.Map as M
-- > main = xmonad someConfig { keys = \c -> bepoKeys c `M.union` keys someConfig c }
bepoConfig = def { keys = bepoKeys <+> keys def }
bepoConfig = def { keys = bepoKeys <> keys def }
bepoKeys conf@XConfig { modMask = modm } = M.fromList $
((modm, xK_semicolon), sendMessage (IncMasterN (-1)))

View File

@ -29,7 +29,7 @@ module XMonad.Config.Bluetile (
import XMonad
import XMonad.Layout.BorderResize
import XMonad.Layout.BoringWindows
import XMonad.Layout.BoringWindows hiding (Replace)
import XMonad.Layout.ButtonDecoration
import XMonad.Layout.Decoration
import XMonad.Layout.DecorationAddons
@ -37,7 +37,7 @@ import XMonad.Layout.DraggingVisualizer
import XMonad.Layout.Maximize
import XMonad.Layout.Minimize
import XMonad.Layout.MouseResizableTile
import XMonad.Layout.Named
import XMonad.Layout.Renamed
import XMonad.Layout.NoBorders
import XMonad.Layout.PositionStoreFloat
import XMonad.Layout.WindowSwitcherDecoration
@ -65,7 +65,7 @@ import System.Exit
import XMonad.Prelude(when)
-- $usage
-- To use this module, start with the following @~\/.xmonad\/xmonad.hs@:
-- To use this module, start with the following @xmonad.hs@:
--
-- > import XMonad
-- > import XMonad.Config.Bluetile
@ -183,10 +183,10 @@ bluetileManageHook = composeAll
, isFullscreen --> doFullFloat]
bluetileLayoutHook = avoidStruts $ minimize $ boringWindows $
named "Floating" floating |||
named "Tiled1" tiled1 |||
named "Tiled2" tiled2 |||
named "Fullscreen" fullscreen
renamed [Replace "Floating"] floating |||
renamed [Replace "Tiled1"] tiled1 |||
renamed [Replace "Tiled2"] tiled2 |||
renamed [Replace "Fullscreen"] fullscreen
where
floating = floatingDeco $ maximize $ borderResize positionStoreFloat
tiled1 = tilingDeco $ maximize mouseResizableTileMirrored
@ -194,7 +194,7 @@ bluetileLayoutHook = avoidStruts $ minimize $ boringWindows $
fullscreen = tilingDeco $ maximize $ smartBorders Full
tilingDeco l = windowSwitcherDecorationWithButtons shrinkText defaultThemeWithButtons (draggingVisualizer l)
floatingDeco l = buttonDeco shrinkText defaultThemeWithButtons l
floatingDeco = buttonDeco shrinkText defaultThemeWithButtons
bluetileConfig =
docks . ewmhFullscreen . ewmh $

View File

@ -24,7 +24,7 @@ module XMonad.Config.Desktop (
-- specification. Extra xmonad settings unique to specific DE's are
-- added by overriding or modifying @desktopConfig@ fields in the
-- same way that the default configuration is customized in
-- @~\/.xmonad/xmonad.hs@.
-- @xmonad.hs@.
--
-- For more information about EWMH see:
--
@ -72,7 +72,7 @@ import qualified Data.Map as M
-- <http://haskell.org/haskellwiki/Xmonad>
--
-- To configure xmonad for use with a DE or with DE tools like panels
-- and pagers, in place of @def@ in your @~\/.xmonad/xmonad.hs@,
-- and pagers, in place of @def@ in your @xmonad.hs@,
-- use @desktopConfig@ or one of the other desktop configs from the
-- @XMonad.Config@ namespace. The following setup and customization examples
-- work the same way for the other desktop configs as for @desktopConfig@.
@ -91,7 +91,7 @@ import qualified Data.Map as M
-- $customizing
-- To customize a desktop config, modify its fields as is illustrated with
-- the default configuration @def@ in "XMonad.Doc.Extending#Extending xmonad".
-- the default configuration @def@ in <https://xmonad.org/TUTORIAL.html the tutorial>.
-- $layouts
-- See also "XMonad.Util.EZConfig" for more options for modifying key bindings.
@ -106,7 +106,7 @@ import qualified Data.Map as M
-- > main =
-- > xmonad $ desktopConfig {
-- > -- add manage hooks while still ignoring panels and using default manageHooks
-- > manageHook = myManageHook <+> manageHook desktopConfig
-- > manageHook = myManageHook <> manageHook desktopConfig
-- >
-- > -- add a fullscreen tabbed layout that does not avoid covering
-- > -- up desktop panels before the desktop layouts
@ -129,7 +129,7 @@ import qualified Data.Map as M
-- To add to the logHook while still sending workspace and window information
-- to DE apps use something like:
--
-- > , logHook = myLogHook <+> logHook desktopConfig
-- > , logHook = myLogHook <> logHook desktopConfig
--
-- Or for more elaborate logHooks you can use @do@:
--
@ -143,7 +143,7 @@ import qualified Data.Map as M
-- To customize xmonad's event handling while still having it respond
-- to EWMH events from pagers, task bars:
--
-- > , handleEventHook = myEventHooks <+> handleEventHook desktopConfig
-- > , handleEventHook = myEventHooks <> handleEventHook desktopConfig
--
-- or 'mconcat' if you write a list event of event hooks
--
@ -157,7 +157,7 @@ import qualified Data.Map as M
-- $startupHook
-- To run the desktop startupHook, plus add further actions to be run each
-- time xmonad starts or restarts, use '<+>' to combine actions as in the
-- time xmonad starts or restarts, use '<>' to combine actions as in the
-- logHook example, or something like:
--
-- > , startupHook = do
@ -169,9 +169,9 @@ import qualified Data.Map as M
desktopConfig :: XConfig (ModifiedLayout AvoidStruts
(Choose Tall (Choose (Mirror Tall) Full)))
desktopConfig = docks $ ewmh def
{ startupHook = setDefaultCursor xC_left_ptr <+> startupHook def
{ startupHook = setDefaultCursor xC_left_ptr <> startupHook def
, layoutHook = desktopLayoutModifiers $ layoutHook def
, keys = desktopKeys <+> keys def }
, keys = desktopKeys <> keys def }
desktopKeys :: XConfig l -> M.Map (KeyMask, KeySym) (X ())
desktopKeys XConfig{modMask = modm} = M.fromList

View File

@ -1,5 +1,5 @@
-- boilerplate {{{
{-# LANGUAGE ExistentialQuantification, NoMonomorphismRestriction, TypeSynonymInstances #-}
{-# LANGUAGE ExistentialQuantification, NoMonomorphismRestriction, TypeSynonymInstances, ViewPatterns, LambdaCase #-}
{-# OPTIONS_GHC -fno-warn-missing-signatures -fno-warn-type-defaults #-}
-----------------------------------------------------------------------------
-- |
@ -7,7 +7,7 @@
-- Description : Daniel Wagner's xmonad configuration.
--
------------------------------------------------------------------------
module XMonad.Config.Dmwit where
module XMonad.Config.Dmwit {-# DEPRECATED "This module contains a personal configuration, to be removed from xmonad-contrib. If you use this module, please copy the relevant parts to your configuration or obtain a copy of it on https://xmonad.org/configurations.html and include it as a local module." #-} where
-- system imports
import Control.Monad.Trans
@ -34,7 +34,7 @@ import XMonad.Layout.Grid
import XMonad.Layout.IndependentScreens hiding (withScreen)
import XMonad.Layout.Magnifier
import XMonad.Layout.NoBorders
import XMonad.Prelude
import XMonad.Prelude hiding (fromList)
import XMonad.Util.Dzen hiding (x, y)
import XMonad.Util.SpawnOnce
-- }}}
@ -78,7 +78,7 @@ modVolume kind n = do
where
sign | n > 0 = "+" | otherwise = "-"
ctlKind = map (\c -> if c == ' ' then '-' else c) kind
parseKind = unwords . map (\(c:cs) -> toUpper c : cs) . words $ kind
parseKind = unwords . map (\(notEmpty -> c :| cs) -> toUpper c : cs) . words $ kind
setCommand i = "pactl set-" ++ ctlKind ++ "-volume " ++ i ++ " -- " ++ sign ++ show (abs n) ++ "%"
listCommand = "pactl list " ++ ctlKind ++ "s"
-- }}}
@ -217,13 +217,13 @@ dmwitConfig nScreens = docks $ def {
keys = keyBindings,
layoutHook = magnifierOff $ avoidStruts (GridRatio 0.9) ||| noBorders Full,
manageHook = (title =? "CGoban: Main Window" --> doF sinkFocus)
<+> (className =? "Wine" <&&> (appName =? "hl2.exe" <||> appName =? "portal2.exe") --> ask >>= viewFullOn {-centerWineOn-} 1 "5")
<+> (className =? "VirtualBox" --> ask >>= viewFullOn 1 "5")
<+> (isFullscreen --> doFullFloat) -- TF2 matches the "isFullscreen" criteria, so its manage hook should appear after (e.g., to the left of a <+> compared to) this one
<+> (appName =? "huludesktop" --> doRectFloat fullscreen43on169)
<+> fullscreenMPlayer
<+> floatAll ["Gimp", "Wine"]
<+> manageSpawn,
<> (className =? "Wine" <&&> (appName =? "hl2.exe" <||> appName =? "portal2.exe") --> ask >>= viewFullOn {-centerWineOn-} 1 "5")
<> (className =? "VirtualBox" --> ask >>= viewFullOn 1 "5")
<> (isFullscreen --> doFullFloat) -- TF2 matches the "isFullscreen" criteria, so its manage hook should appear after (e.g., to the left of a <> compared to) this one
<> (appName =? "huludesktop" --> doRectFloat fullscreen43on169)
<> fullscreenMPlayer
<> floatAll ["Gimp", "Wine"]
<> manageSpawn,
logHook = allPPs nScreens,
startupHook = refresh
>> mapM_ (spawnOnce . xmobarCommand) [0 .. nScreens-1]
@ -308,7 +308,7 @@ allPPs nScreens = sequence_ [dynamicLogWithPP (pp s) | s <- [0..nScreens-1], pp
color c = xmobarColor c ""
ppFocus s@(S s_) = whenCurrentOn s def {
ppOrder = \(_:_:windowTitle:_) -> [windowTitle],
ppOrder = \case{ _:_:windowTitle:_ -> [windowTitle]; _ -> [] },
ppOutput = appendFile (pipeName "focus" s_) . (++ "\n")
}
@ -318,7 +318,7 @@ ppWorkspaces s@(S s_) = marshallPP s def {
ppHiddenNoWindows = color dark,
ppUrgent = color "red",
ppSep = "",
ppOrder = \(wss:_layout:_title:_) -> [wss],
ppOrder = \case{ wss:_layout:_title:_ -> [wss]; _ -> [] },
ppOutput = appendFile (pipeName "workspaces" s_) . (++"\n")
}
-- }}}

View File

@ -1,4 +1,5 @@
{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE TupleSections #-}
{-# OPTIONS_GHC -fno-warn-missing-signatures -fno-warn-orphans #-}
-----------------------------------------------------------------------------
-- |
@ -8,7 +9,7 @@
-- License : BSD3-style (see LICENSE)
--
------------------------------------------------------------------------
module XMonad.Config.Droundy ( config, mytab ) where
module XMonad.Config.Droundy {-# DEPRECATED "This module contains a personal configuration, to be removed from xmonad-contrib. If you use this module, please copy the relevant parts to your configuration or obtain a copy of it on https://xmonad.org/configurations.html and include it as a local module." #-} ( config, mytab ) where
import XMonad hiding (keys, config)
import qualified XMonad (keys)
@ -20,7 +21,7 @@ import System.Exit ( exitSuccess )
import XMonad.Layout.Tabbed ( tabbed,
shrinkText, Shrinker, shrinkIt, CustomShrink(CustomShrink) )
import XMonad.Layout.Combo ( combineTwo )
import XMonad.Layout.Named ( named )
import XMonad.Layout.Renamed ( Rename(Replace), renamed )
import XMonad.Layout.LayoutCombinators
import XMonad.Layout.Square ( Square(Square) )
import XMonad.Layout.WindowNavigation ( Navigate(Move,Swap,Go), Direction2D(U,D,R,L),
@ -114,9 +115,9 @@ keys x = M.fromList $
]
++
zip (zip (repeat $ modMask x) [xK_F1..xK_F12]) (map (withNthWorkspace W.greedyView) [0..])
zip (map (modMask x,) [xK_F1..xK_F12]) (map (withNthWorkspace W.greedyView) [0..])
++
zip (zip (repeat (modMask x .|. shiftMask)) [xK_F1..xK_F12]) (map (withNthWorkspace copy) [0..])
zip (map (modMask x .|. shiftMask,) [xK_F1..xK_F12]) (map (withNthWorkspace copy) [0..])
config = docks $ ewmh def
{ borderWidth = 1 -- Width of the window border in pixels.
@ -124,10 +125,10 @@ config = docks $ ewmh def
, layoutHook = showWName $ workspaceDir "~" $
boringWindows $ smartBorders $ windowNavigation $
maximizeVertical $ toggleLayouts Full $ avoidStruts $
named "tabbed" mytab |||
named "xclock" (mytab ****//* combineTwo Square mytab mytab) |||
named "three" (mytab **//* mytab *//* combineTwo Square mytab mytab) |||
named "widescreen" ((mytab *||* mytab)
renamed [Replace "tabbed"] mytab |||
renamed [Replace "xclock"] (mytab ****//* combineTwo Square mytab mytab) |||
renamed [Replace "three"] (mytab **//* mytab *//* combineTwo Square mytab mytab) |||
renamed [Replace "widescreen"] ((mytab *||* mytab)
****//* combineTwo Square mytab mytab) -- |||
--mosaic 0.25 0.5
, terminal = "xterm" -- The preferred terminal program.

View File

@ -28,10 +28,10 @@ main = do
-- simple overrides:
xmonad $ desktopConfig
{ modMask = mod4Mask -- Use the "Win" key for the mod key
, manageHook = myManageHook <+> manageHook desktopConfig
, manageHook = myManageHook <> manageHook desktopConfig
, layoutHook = desktopLayoutModifiers myLayouts
, logHook = (dynamicLogString def >>= xmonadPropLog)
<+> logHook desktopConfig
<> logHook desktopConfig
}
`additionalKeysP` -- Add some extra key bindings:
@ -72,7 +72,7 @@ myManageHook = composeOne
-- Handle floating windows:
[ transience -- move transient windows to their parent
, isDialog -?> doCenterFloat
] <+> composeAll
] <> composeAll
[ className =? "Pidgin" --> doFloat
, className =? "XCalc" --> doFloat
, className =? "mpv" --> doFloat

View File

@ -32,7 +32,7 @@ import qualified Data.Map as M
import System.Environment (getEnvironment)
-- $usage
-- To use this module, start with the following @~\/.xmonad\/xmonad.hs@:
-- To use this module, start with the following @xmonad.hs@:
--
-- > import XMonad
-- > import XMonad.Config.Gnome
@ -43,7 +43,7 @@ import System.Environment (getEnvironment)
gnomeConfig = desktopConfig
{ terminal = "gnome-terminal"
, keys = gnomeKeys <+> keys desktopConfig
, keys = gnomeKeys <> keys desktopConfig
, startupHook = gnomeRegister >> startupHook desktopConfig }
gnomeKeys XConfig{modMask = modm} = M.fromList

View File

@ -28,7 +28,7 @@ import XMonad.Config.Desktop
import qualified Data.Map as M
-- $usage
-- To use this module, start with the following @~\/.xmonad\/xmonad.hs@:
-- To use this module, start with the following @xmonad.hs@:
--
-- > import XMonad
-- > import XMonad.Config.Kde
@ -42,11 +42,11 @@ import qualified Data.Map as M
kdeConfig = desktopConfig
{ terminal = "konsole"
, keys = kdeKeys <+> keys desktopConfig }
, keys = kdeKeys <> keys desktopConfig }
kde4Config = desktopConfig
{ terminal = "konsole"
, keys = kde4Keys <+> keys desktopConfig }
, keys = kde4Keys <> keys desktopConfig }
kdeKeys XConfig{modMask = modm} = M.fromList
[ ((modm, xK_p), spawn "dcop kdesktop default popupExecuteCommand")

View File

@ -27,7 +27,7 @@ import XMonad.Config.Desktop
import qualified Data.Map as M
-- $usage
-- To use this module, start with the following @~\/.xmonad\/xmonad.hs@:
-- To use this module, start with the following @xmonad.hs@:
--
-- > import XMonad
-- > import XMonad.Config.LXQt
@ -38,7 +38,7 @@ import qualified Data.Map as M
lxqtConfig = desktopConfig
{ terminal = "qterminal"
, keys = lxqtKeys <+> keys desktopConfig }
, keys = lxqtKeys <> keys desktopConfig }
lxqtKeys XConfig{modMask = modm} = M.fromList
[ ((modm, xK_p), spawn "lxqt-runner")

View File

@ -1,5 +1,7 @@
{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
-- TODO: Remove when we depend on a version of xmonad that has unGrab.
{-# OPTIONS_GHC -Wno-deprecations #-}
{-# OPTIONS_GHC -Wno-dodgy-imports #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Config.Mate
@ -28,18 +30,17 @@ module XMonad.Config.Mate (
desktopLayoutModifiers
) where
import XMonad
import XMonad.Config.Desktop
import XMonad.Util.Run (safeSpawn)
import XMonad.Util.Ungrab
import XMonad.Prelude (toUpper)
import System.Environment (getEnvironment)
import qualified Data.Map as M
import System.Environment (getEnvironment)
import XMonad hiding (unGrab)
import XMonad.Config.Desktop
import XMonad.Prelude (toUpper)
import XMonad.Util.Run (safeSpawn)
import XMonad.Util.Ungrab (unGrab)
-- $usage
-- To use this module, start with the following @~\/.xmonad\/xmonad.hs@:
-- To use this module, start with the following @xmonad.hs@:
--
-- > import XMonad
-- > import XMonad.Config.Mate
@ -50,7 +51,7 @@ import System.Environment (getEnvironment)
mateConfig = desktopConfig
{ terminal = "mate-terminal"
, keys = mateKeys <+> keys desktopConfig
, keys = mateKeys <> keys desktopConfig
, startupHook = mateRegister >> startupHook desktopConfig }
mateKeys XConfig{modMask = modm} = M.fromList

View File

@ -15,7 +15,7 @@ ideas:
"only once" features like avoidStruts, ewmhDesktops
-}
module XMonad.Config.Monad where
module XMonad.Config.Monad {-# DEPRECATED "This module does not work." #-} where
import XMonad hiding (terminal, keys)
import qualified XMonad as X

View File

@ -1,3 +1,4 @@
{-# OPTIONS_HADDOCK hide #-}
{-# LANGUAGE FlexibleContexts, FlexibleInstances, FunctionalDependencies, KindSignatures, UndecidableInstances #-}
-----------------------------------------------------------------------------
@ -23,7 +24,7 @@
--
-----------------------------------------------------------------------------
module XMonad.Config.Prime (
module XMonad.Config.Prime {-# DEPRECATED "This module is a perpetual draft and will therefore be removed from xmonad-contrib in the near future." #-} (
-- Note: The identifiers here are listed in the order that makes the most sense
-- for a user, while the definitions below are listed in the order that makes
-- the most sense for a developer.
@ -126,7 +127,7 @@ import qualified XMonad as X (xmonad, XConfig(..))
import XMonad.Util.EZConfig (additionalKeysP, additionalMouseBindings, checkKeymap, removeKeysP, removeMouseBindings)
-- $start_here
-- To start with, create a @~\/.xmonad\/xmonad.hs@ that looks like this:
-- To start with, create a @xmonad.hs@ that looks like this:
--
-- > {-# LANGUAGE RebindableSyntax #-}
-- > import XMonad.Config.Prime
@ -280,7 +281,7 @@ instance SummableClass (Summable x y) y where
--
-- Note that operator precedence mandates the parentheses here.
manageHook :: Summable ManageHook ManageHook (XConfig l)
manageHook = Summable X.manageHook (\x c -> c { X.manageHook = x }) (<+>)
manageHook = Summable X.manageHook (\x c -> c { X.manageHook = x }) (<>)
-- | Custom X event handler. Return @All True@ if the default handler should
-- also be run afterwards. Default does nothing. To add an event handler:
@ -289,7 +290,7 @@ manageHook = Summable X.manageHook (\x c -> c { X.manageHook = x }) (<+>)
-- > ...
-- > handleEventHook =+ serverModeEventHook
handleEventHook :: Summable (Event -> X All) (Event -> X All) (XConfig l)
handleEventHook = Summable X.handleEventHook (\x c -> c { X.handleEventHook = x }) (<+>)
handleEventHook = Summable X.handleEventHook (\x c -> c { X.handleEventHook = x }) (<>)
-- | List of workspaces' names. Default: @map show [1 .. 9 :: Int]@. Adding
-- appends to the end:
@ -388,7 +389,7 @@ instance RemovableClass MouseBindings [(ButtonMask, Button)] where
MouseBindings { mRemove = r } =- sadBindings = return . r sadBindings
-- | Mouse button bindings to an 'X' actions on a window. Default: see @`man
-- xmonad`@. To make mod-<scrollwheel> switch workspaces:
-- xmonad`@. To make @mod-\<scrollwheel\>@ switch workspaces:
--
-- > import XMonad.Actions.CycleWS (nextWS, prevWS)
-- > ...

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