Compare commits

...

1712 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
Tomas Janousek
0fde4c8848 Fix Haskell2010 incompatibilities 2021-10-27 18:06:41 +01:00
Tomas Janousek
991dc6dfac xmonad-contrib.cabal: Specify default-language
Required for cabal-version >= 1.10
2021-10-27 17:57:10 +01:00
Tomas Janousek
805de214d8 Bump cabal-version in xmonad-contrib.cabal
Hackage won't accept the release otherwise.
2021-10-27 17:49:44 +01:00
Tomas Janousek
585558bfb0 Bump version number (0.17.0), update date in changelog 2021-10-27 17:00:33 +01:00
Tomáš Janoušek
a7ccfe61f3
Merge pull request #605 from TheMC47/pp-predicates
`ppPrinters` for custom workspace types, `copiesPP` fix
2021-10-27 10:16:46 +01:00
Yecine Megdiche
16b9f0f96d X.A.CopyWindow: fix copiesPP
Related: https://github.com/xmonad/xmonad-contrib/issues/557

Co-authored-by: Tomáš Janoušek <tomi@nomi.cz>
2021-10-27 10:15:29 +01:00
Yecine Megdiche
2d849cc0b7 X.H.SB.PP: ppPrinters and custom workspace types
Using `ppPrinters` with `WorkspacePredicate` and `WorkspaceFormatter`
allows users to define custom workspace types, beyond the ones
integrated in PP (i.e. urgent, current, visible, visible with no
windows, hidden, and hidden with no windows). `WorkspacePredicate`s are
added for these predicates (`isType`) with unsafe versions that assume
that predicates with a higher precedence already faield `isType'`.
`WorkspacePredicate`s can also be combined and modified with `notWP`,
`andWP`, and `orWP`.

Related: https://github.com/xmonad/xmonad-contrib/issues/557

Co-authored-by: Tomáš Janoušek <tomi@nomi.cz>
2021-10-27 10:15:29 +01:00
Aleksei Pirogov
8b6f17ba66
X.H.ManageHelpers: Add new operators (#633)
Closes: #628
2021-10-26 21:53:52 +02:00
Tomáš Janoušek
e1f4f77346
Merge pull request #632 from Targuinia/patch-1
Minor documentation fixes to `XMonad.Hooks.FadeWindows`
2021-10-26 18:43:34 +01:00
Targuinia
9824b57d12
Corrected a comment in XMonad.Hooks.FadeWindows 2021-10-26 17:03:12 +02:00
Targuinia
a335809767
Fix Haddock comments in XMonad.Hooks.FadeWindows
Some Haddocks comments were for the wrong declaration (-- ^ instead of -- |)
2021-10-26 16:52:29 +02:00
slotThe
719c8ecfe9 X.D.Developing: Refer to cabal instead of runhaskell 2021-10-25 18:40:05 +02:00
slotThe
bc5d4f18e2 X.D.Developing: Refer to CONTRIBUTING for style
The CONTRIBUTING.md file for xmonad now has style guidelines [1].  Since
X.D.Developing does not add anything new here and we direct new
contributors to CONTRIBUTING.md anyways, simply refer to the relevant
section.

[1]: bc8f7ff133
2021-10-25 14:40:26 +02:00
slotThe
5d9a599c9f X.D.Developing: Update Haddock introduction
* The Haddock documentation is a very good resource for the general
  markup syntax.
* Since we are very biased in favour of stack, document how to build
  Haddock docks with it.
2021-10-25 14:40:26 +02:00
Tomas Janousek
7a4dc29418 X.L.Fullscreen: Silence deprecation warning temporarily
Deprecation warnings are now shown to users via xmessage when xmonad
recompiles, and this may include warnings in xmonad(-contrib) itself if
people have a build script that invokes stack/cabal without --silent,
and they then may get confused. The deprecation warning in that case
won't be shown every recompile but only once whenever xmonad(-contrib)
needs to be rebuilt, but it's still annoying.

This silences the warning. We intend to refactor this part of the code
so this is a temporary measure.

Fixes: f666cf4e4e0e ("X.H.EwmhDesktops: Deprecate standalone hooks")
2021-10-25 10:45:51 +01:00
Tomas Janousek
c51353c6c6 Merge branch 'packdeps' 2021-10-24 13:56:53 +01:00
Tomas Janousek
046f3c3871 Bump lower bound for base
We only test with GHC 8.4+ so it's unlikely this builds with older base
(Semigroup stuff …).
2021-10-24 13:55:19 +01:00
Tomas Janousek
8edc8ab789 Bump upper bounds for bytestring, time
I've tested these manually by adding them to extra-deps. Hopefully
they'll soon be available in a release of GHC or Stackage, so I'm not
adding an extra stack.yaml to test this.
2021-10-24 13:55:19 +01:00
Tomas Janousek
5cc26aaa21 ci: Check package bounds using packdeps once a week
This was a part of the release procedure but we should do it proactively
instead.

Related: https://github.com/xmonad/xmonad-contrib/issues/393
2021-10-24 13:55:02 +01:00
Tomas Janousek
d6b4f174d6 ci: Add Stackage LTS 18 to Stack test matrix 2021-10-24 11:17:41 +01:00
Tomas Janousek
0be6780559 ci: Avoid caching GHC
We install GHC using apt, so stack shouldn't install it, but should it
ever end up installing it anyway (version mismatch, version unavailable
in hvr/ghc ppa, …), we don't want it wasting valuable cache space.
2021-10-24 11:11:48 +01:00
slotThe
f39218ddb5 X.D.Developing: Drop confusing "or freer" part
Currently, all contrib modules are licensed under a 3-clause BSD license
anyways.  The term "freer" is quite confusing and may even refer to
several (non-BSD) licenses, depending on the authors sensibilities.
2021-10-24 08:04:38 +02:00
slotThe
9b840a1189
Merge pull request #631 from liskin/readme
README: Improve badges, Installation/Contributing sections; CHANGES prep
2021-10-23 09:38:39 +02:00
Tomas Janousek
c71756095e CHANGES: Almost final prep 2021-10-23 00:41:27 +01:00
Tomas Janousek
32028915a3 README: Improve Installation/Contributing sections further
(Copy&paste from https://github.com/xmonad/xmonad/pull/340 mostly.)
2021-10-23 00:34:39 +01:00
Tomas Janousek
4560abd1e6 README: Tweak badges a bit 2021-10-22 23:24:15 +01:00
Tomáš Janoušek
2c01279d1c
Merge pull request #630 from liskin/readme
README: Long overdue update
2021-10-22 22:12:20 +01:00
Tomas Janousek
33ccf910a6 Add CONTRIBUTING.md
This makes GitHub show a link to it when opening issues/PRs.
2021-10-22 22:11:56 +01:00
Tomas Janousek
268fc70d0e README: Long overdue update
* "community-maintained" is more accurate and sounds better than "third-party"
* refresh description
* add logo and badges to make it prettier
* update doc links
2021-10-22 22:11:56 +01:00
Tomas Janousek
c0cea57604 LICENSE: Fix wording to make it detectable by GitHub 2021-10-22 22:11:56 +01:00
Tomáš Janoušek
0f6403c2e9
Merge pull request #629 from liskin/managedocks-hooks-deprecation
X.H.ManageDocks: Deprecate individual hooks
2021-10-22 20:48:16 +01:00
Tomas Janousek
c2e36da92c X.H.ManageDocks: Deprecate individual hooks
This will make it easier to transition to an implementation of EWMH that
doesn't expose the individual hooks: X.H.ManageDocks would become a
deprecated compatibility reexport of X.H.EWMH.Struts for a release or
two, but the individual hooks need to be removed before that.

Note that individual hooks in X.H.EwmhDesktops were deprecated earlier
and individual hooks in XMonad.Hooks.UrgencyHook aren't exported any
more (or perhaps never been), so this only leaves X.H.SetWMName, which
unfortunately does not have a combinator interface at this point.

Related: https://github.com/xmonad/xmonad-contrib/pull/625
2021-10-22 16:07:31 +01:00
slotThe
0aeaf93a6e
Merge pull request #438 from elkowar/cleanup-independent-screens
X.L.IndependentScreens: Add utility functions, refactor
2021-10-22 08:30:21 +02:00
elkowar
b552b453d5 X.L.IndependentScreens: Add utility functions, refactor
* Add a few utility functions which make working with IndependentScreens
  more ergonomic; namely workspaceOnScreen, focusWindow', focusScreen,
  nthWorkspace, and withWspOnScreen.
* Clean up whenCurrentOn and make it more readable.
* Fix the type-signature of onCurrentScreen.
2021-10-22 08:21:24 +02:00
Tomas Janousek
956d51c225 Update .mailmap
Drop lines that aren't needed.
Add lines to deduplicate people.
Add lines to add/fix some names.
2021-10-21 16:22:07 +01:00
slotThe
08b8b285a8
Merge pull request #620 from TheMC47/extending-module-list
`X.D.Extending`: Remove module list
2021-10-21 14:49:37 +02:00
Yecine Megdiche
b2d4aa7dad Pull Request Template: Drop X.D.Extending 2021-10-21 08:28:35 +02:00
Yecine Megdiche
839302533b X.D.Extending: Remove module list
As of 38c11c1e3cfa1b91d9af796872e3d011895b4d50, all modules now include
a `Description` string that can be rendered using Haddock. This makes
the list in `XMonad.Doc.Extending` redundant.

Related: https://github.com/xmonad/xmonad-contrib/issues/619
2021-10-21 08:28:35 +02:00
Tomáš Janoušek
e5b5ce74b2
Merge pull request #626 from liskin/ewmh-refactor-quick
EWMH: Improve interface for custom sorting, filtering, renaming and window activation
2021-10-20 16:58:40 +02:00
Tomas Janousek
6ab136eb56 scripts/xmonadctl: Fix build
Fixes: bd5b969d9ba2 ("Apply hlint hints")
2021-10-20 15:24:55 +01:00
Tomas Janousek
f666cf4e4e X.H.EwmhDesktops: Deprecate standalone hooks
We should get rid of this error-prone interface ASAP, so mark it as
deprecated to give people some time to adapt their configs.
2021-10-20 14:51:39 +01:00
Tomas Janousek
860f80a6d3 X.H.Focus: Adapt docs to the new activation interface
Fixes: https://github.com/xmonad/xmonad-contrib/issues/396
Related: https://github.com/xmonad/xmonad-contrib/pull/192
Related: https://github.com/xmonad/xmonad-contrib/pull/128
2021-10-20 14:51:23 +01:00
Tomas Janousek
79b130b9d6 Add some docs references for workspace filtering 2021-10-20 14:51:23 +01:00
Tomas Janousek
08ec79eec1 X.H.EwmhDesktops: Improve interface for hooking window activation
https://github.com/xmonad/xmonad-contrib/pull/192 introduced a breaking change:

  * `XMonad.Hooks.EwmhDesktops`

    `ewmh` function will use `logHook` for handling activated window. And now
    by default window activation will do nothing.

This breaking change can be avoided if we designed that a bit
differently. #192 changed `ewmhDesktopsEventHook` to invoke `logHook`
instead of focusing the window that requested activation and now
`logHook` is supposed to invoke a `ManageHook` through `activateLogHook`
which consults a global `NetActivated` extensible state to tell if it's
being invoked from `ewmhDesktopsEventHook`. This seems convoluted to me.

A better design, in my opinion, is to invoke the `ManageHook` directly
from `ewmhDesktopsEventHook`, and we just need a way to configure the
hook. Luckily, we now have `X.U.ExtensibleConf` which makes this
straightforward. So we now have a `setEwmhActivateHook`, and the
activation hook defaults to focusing the window, undoing the breaking
change.

Fixes: https://github.com/xmonad/xmonad-contrib/issues/396
Related: https://github.com/xmonad/xmonad-contrib/pull/110
Related: https://github.com/xmonad/xmonad-contrib/pull/192
Related: https://github.com/xmonad/xmonad-contrib/pull/128
2021-10-20 14:51:23 +01:00
Tomas Janousek
3175f276be X.A.WorkspaceNames: Adapt EwmhDesktops integration to the new interface
Related: https://github.com/xmonad/xmonad-contrib/pull/105
Related: https://github.com/xmonad/xmonad-contrib/pull/122
Related: f271d59c345e ("X.A.WorkspaceNames: Provide workspaceListTransform for EwmhDesktops")
2021-10-20 14:50:17 +01:00
Tomas Janousek
fe933c3707 X.H.EwmhDesktops: Improve interface for custom workspace sorting, filtering and renaming
Now that we have `XMonad.Util.ExtensibleConf`, users can comfortably use
the `ewmh` combinator and still customize workspace ordering, filter out
scratchpads and expose altered workspace names.

To make this all work nicely, we introduce not one, but two
configuration options: a sort/filter function and a rename function.
This is because renaming and sorting in one go makes it hard (perhaps
even impossible) to decide which workspace to switch to upon receipt of
a _NET_CURRENT_DESKTOP request from a pager or wmctrl/xdotool. (The only
reason this wasn't a problem before is because one could pass the
renaming function to `ewmhDesktopsLogHookCustom` only, not
`ewmhDesktopsEventHookCustom`, which is a confusing hack as can be seen
in the related closed pull requests.)

Related: https://github.com/xmonad/xmonad-contrib/pull/238
Related: https://github.com/xmonad/xmonad-contrib/pull/105
Related: https://github.com/xmonad/xmonad-contrib/pull/122
2021-10-20 14:50:17 +01:00
Tomas Janousek
6b9520b03b X.H.EwmhDesktops: Mostly cosmetic, mostly docs cleanups 2021-10-20 14:48:41 +01:00
Tomas Janousek
6358683058 X.H.UrgencyHook: Add askUrgent and doAskUrgent
These are useful when one blocks some _NET_ACTIVE_WINDOW requests but
still wants to somehow show that a window requested focus.

Related: https://github.com/xmonad/xmonad-contrib/pull/110
Related: https://github.com/xmonad/xmonad-contrib/pull/128
Related: https://github.com/xmonad/xmonad-contrib/pull/192
2021-10-20 14:46:52 +01:00
Tomas Janousek
3a72dd5355 X.U.ExtensibleConf: Add high-level idioms for non-Semigroup, but Default types
For configuration values that don't compose well using a Semigroup
instance, provide a high-level API allowing arbitrary modification of
the value, taking its Default if absent. This API is only usable for
separate configuration data and cannot be used to guard addition of hook
using `once`.
2021-10-20 14:46:52 +01:00
Tomas Janousek
3dbdc51158 X.U.ExtensibleConf: Perform 'add' before modifying in once(M)
This better matches the documentation.

It is still, however, considered bad practice to rely on the order of
these operations. `f` isn't meant to touch any extensible configuration.
If it happens to do so anyway, it no longer loops. :-)
2021-10-19 22:57:50 +01:00
Yecine Megdiche
e0c7e35b3d
Merge pull request #613 from TheMC47/update-dynamiclog-docs
Update `X.H.DynamicLog` references
2021-10-19 21:54:01 +02:00
slotThe
8e0e8a605d X.A.Search: Make (!>) right associative
Unless specified otherwise, operators in Haskell associative to the
left.  However, the ergonomics of (!>) heavily lean towards the left
operand being a "single" search engine, not a combined one.

This causes trouble when not using `multi` or defining search engines
with a right fold, but (following the documentation) writing something
like

    multiEngine = intelligent (wikipedia !> mathworld !> (prefixAware google))

instead.  This particular definition would force the user to write
`wikipedia/mathworld:wikipedia:search-term` instead of just
`wikipedia:search-term` to access the first search engine.

Simply giving (!>) an explicit associativity fixes these problems.
2021-10-19 18:48:47 +02:00
Yecine Megdiche
53adf02b38 X.A.Prefix: Update X.H.DynamicLog references 2021-10-19 07:56:11 +02:00
Yecine Megdiche
a5b335469a Update X.H.DynamicLog references 2021-10-19 07:56:11 +02:00
Yecine Megdiche
8defd7f4c8 xmonadpropread.hs: Update X.H.DynamicLog references 2021-10-19 07:56:11 +02:00
Yecine Megdiche
c2f45b49ff X.A.WorkspaceNames: Update X.H.DynamicLog references 2021-10-19 07:56:11 +02:00
Yecine Megdiche
45a07b0e1b X.U.L.NamedScratchpad: Update X.H.DynamicLog references 2021-10-19 07:56:11 +02:00
Yecine Megdiche
8b3ed5224a X.U.WorkspaceCompare: Update X.H.DynamicLog references 2021-10-19 07:56:11 +02:00
Yecine Megdiche
2cbb342adc X.A.DynamicWorkspaceOrder: Update X.H.DynamicLog references 2021-10-19 07:56:11 +02:00
Yecine Megdiche
74f3b6206f X.H.DynamicBars: Deprecate in favor of X.H.StatusBar 2021-10-19 07:56:11 +02:00
Yecine Megdiche
76bab07eb9 X.A.WindowNavigation: Added bind example 2021-10-19 07:56:11 +02:00
Yecine Megdiche
6ca1e334eb X.U.Loggers: Update X.H.DynamicLog references 2021-10-19 07:56:11 +02:00
Yecine Megdiche
0e3001681d X.U.NamedScratchpad: Update X.H.DynamicLog references 2021-10-19 07:56:11 +02:00
Yecine Megdiche
3f2210206f X.L.IndependentScreens: Update X.H.DynamicLog references 2021-10-19 07:56:11 +02:00
Yecine Megdiche
9151492c6e X.U.Loggers: Update X.H.DynamicLog references 2021-10-19 07:56:11 +02:00
Yecine Megdiche
5e7085661e X.H.FloatNext: Update X.H.DynamicLog references 2021-10-19 07:56:11 +02:00
Yecine Megdiche
cfe7533c42 X.H.UrgencyHook: Update X.H.DynamicLog references 2021-10-19 07:56:11 +02:00
Yecine Megdiche
ac6705a144 X.A.WorkspaceCursors: Update X.H.DynamicLog references 2021-10-19 07:56:11 +02:00
Yecine Megdiche
6ddde878ec X.L.LayoutModifier: Update X.H.DynamicLog reference 2021-10-19 07:56:11 +02:00
Yecine Megdiche
2932a8e2f8 X.H.ToggleHook: Update X.H.DynamicLog references 2021-10-19 07:56:11 +02:00
Yecine Megdiche
7ec3a4e034 X.A.TopicSpace: Update X.H.DynamicLog references 2021-10-19 07:56:11 +02:00
Tomas Janousek
586416b0f9 X.H.Rescreen: XConfig (a ⇒ l)
It's a layout, `a` is misleading.
2021-10-18 10:30:41 +01:00
Tomas Janousek
087526dee3 X.H.Rescreen: Fix typo in haddocks 2021-10-18 10:30:41 +01:00
Tomas Janousek
0de958e09c X.H.Rescreen: import X.Prelude
A race condition between merging the Prelude PR and the Rescreen PR. :-)
2021-10-18 10:30:41 +01:00
brandon s allbery kf8nh
fa3536b40b
Merge pull request #624 from alternateved/add-usage-section
X.H.DynamicProperty: Add usage section
2021-10-14 13:50:09 -04:00
alternateved
ab98b40034 Add X.H.DynamicProperty usage section 2021-10-14 19:28:33 +02:00
Yecine Megdiche
50996809aa
Merge pull request #623 from alternateved/fix-missing-information
X.A.CycleWS: Fix missing type names in documentation
2021-10-14 18:02:59 +02:00
alternateved
2a9ccf3002 X.A.CycleWS: Fix names in example 2021-10-14 17:57:00 +02:00
Tomáš Janoušek
5085e72217
Merge pull request #622 from alternateved/fix-missing-export
X.A.Search: Fix missing export
2021-10-13 20:38:39 +02:00
alternateved
374293c179 Fix missing export 2021-10-13 19:23:40 +02:00
Tomáš Janoušek
3b4a262658
Merge pull request #621 from slotThe/dynamic-workspaces-nub
X.A.DynamicWorkspaces: Remove duplicates when melding
2021-10-13 16:51:05 +02:00
slotThe
bb5b64a198 Update CHANGES.md: Fix X.A.DynamicWorkspaces freeze 2021-10-13 14:29:56 +02:00
slotThe
929a6a3f6f X.A.DynamicWorkspaces: Remove duplicates when melding
When removing a workspace and distributing its windows, it's important
to remove any duplicates that may be there due to, for example, usage of
X.A.CopyWindow.  X will only draw one of these window, leading to some
artifacts.

Related: https://github.com/xmonad/xmonad-contrib/issues/565

Co-authored-by: Tomas Janousek <tomi@nomi.cz>
2021-10-13 12:05:52 +02:00
slotThe
f821a2ec0c
Merge pull request #617 from slotThe/runorraise-dir-exe
X.P.RunOrRaise: Disambiguate directories and executables
2021-10-11 20:42:59 +02:00
slotThe
5bdc5993f9 X.P.RunOrRaise: Disambiguate directories and executables
When there is a directory and a file in $PATH of the same name `foo`, we
display `foo`, as well as `foo/` in the prompt, but selecting either one
of them will invariably run or raise the directory, as this test is done
beforehand.

Since directories already carry a trailing forward slash from the shell
prompt's `getShellCompl`, this is easily disambiguated by incorporating
an additional check.

It is duly noted that the same problem also exists for files in the
current directory.  This could be fixed in a similar way (adding a
unique suffix to files and checking for that), but since this would
involve changing `getShellCompl` and no-one has complained about this so
far, it was deemed "not worth it" for now.

Fixes: https://github.com/xmonad/xmonad-contrib/issues/616
2021-10-11 20:41:57 +02:00
Tomáš Janoušek
b331821275
Merge pull request #618 from aartamonau/master
EwmhDesktops: Advertise _NET_WM_STATE_DEMANDS_ATTENTION.
2021-10-10 11:09:37 +02:00
Aliaksey Artamonau
2b1febb40b EwmhDesktops: Advertise _NET_WM_STATE_DEMANDS_ATTENTION.
XMonad.Hooks.UrgencyHook knows how to understand this hint, but it's
not advertised as supported via _NET_SUPPORTED. This prevents certain
applications (e.g. kitty terminal emulator) from using it.
2021-10-09 16:12:04 -07:00
Yecine Megdiche
8ef05975c7 X.H.DynamicIcons: Add X.H.StatusBar support 2021-10-05 21:45:42 +02:00
Yecine Megdiche
f470f18cf0 X.H.DynamicIcons: tweak docs example 2021-10-04 18:03:58 +02:00
slotThe
9ff7f89664
Merge pull request #608 from slotThe/ez-prefix
X.A.Prefix: Use EZConfig parser for usePrefixKey
2021-10-04 16:33:40 +02:00
slotThe
82f0a7ad57 X.A.FloatKeys: Use Int for offset deltas
So far, we have used the `D` tuple, as defined in X.Operations, for
these.  However, `D` uses `Word32` for its components, which are not
supposed to carry negative values.

Fixes: https://github.com/xmonad/xmonad-contrib/issues/578
2021-10-03 17:35:07 +02:00
slotThe
967cc9a869 X.A.FloatKeys: Use fi
Instead of fromIntegral, use the somewhat more concise and often used fi
alias.
2021-10-03 17:24:54 +02:00
slotThe
30c139e298 X.A.Prefix: Use EZConfig parser for usePrefixKey
Utilise EZConfig's Emacs style syntax for entering the prefix key.

The syntax has been well-established for use in configuration files;
especially in this case it can be a bit awkward having to specify a
function that takes a config just for a single keybinding.
2021-10-03 08:55:31 +02:00
slotThe
3058d1ca22
Merge pull request #609 from slotThe/fun-with-descriptions
Add Description string to modules
2021-09-30 15:10:07 +02:00
slotThe
38c11c1e3c Add "Description" field to module headers
Fixes: https://github.com/xmonad/xmonad-contrib/issues/592
2021-09-26 14:15:54 +02:00
slotThe
4d1f76f7d8 X.D.Extending: Add missing modules
X.D.Extending claims to index all of the contrib library, but this was
not really the case.  While most modules where indeed indexed, some
notable ones were missing from this list.  Since we're pointing users to
this quite prominently, this is something that needs to be fixed.
2021-09-26 14:14:44 +02:00
slotThe
20fdcbad01
Merge pull request #606 from alternateved/remove-outdated-search-engines
* X.A.Search: Update/Remove outdated URLs, add GitHub

  - The `codesearch`, `openstreetmap`, and `thesaurus` searches were
    using old URLs; update those.
  - Remove the now defunct isoHunt serach.
  - Add a search for GitHub.

* X.A.Search: Change http to https
2021-09-23 12:30:00 +02:00
slotThe
7f49fe3b4d X.A.Search: Change http to https
It really is time.
2021-09-23 12:16:29 +02:00
alternateved
732a3b6e75 X.A.Search: Update/Remove outdated URLs, add GitHub
- The `codesearch`, `openstreetmap`, and `thesaurus` searches were
    using old URLs; update those.
  - Remove the now defunct isoHunt serach.
  - Add a search for GitHub.
2021-09-23 12:16:29 +02:00
slotThe
948c048832
Merge pull request #602 from ssbothwell/master
X.A.WithAll: Add killOthers
2021-09-22 16:51:51 +02:00
Solomon Bothwell
7a2001cfa2 X.A.WithAll: Add killOthers
This adds the function `killOthers`, which kills all unfocused windows
on the current workspace.

As discussed in the PR itself [1], the module suffix `WithAll` is not
quite optimal at this point, as we are acting on window _groups_ and not
necessarily just all window on a workspace.  However, in order to keep
this commit atomic, this consideration is postponed until another day.

[1]: https://github.com/xmonad/xmonad-contrib/pull/602
2021-09-22 16:45:37 +02:00
slotThe
0c6fdf4e75
Merge pull request #601 from ssbothwell/feature/custom-xmonad-prompt-title
Add custom title to xmonad prompts
2021-09-09 21:49:37 +02:00
Solomon Bothwell
b79fbf6975 X.P.XMonad: Add xmonadPromptCT
Currently when creating an XMonad Prompt one is stuck with "XMonad:" as
the title for the prompt.  However, sometimes it is nice to be able to
create a prompt with custom commands that has a particular title.

This changes the internals of X.P.XMonad to facilitate this and adds
xmonadPromptCT as a user facing function.
2021-09-09 21:43:43 +02:00
slotThe
81339f2044
Merge pull request #598 from slotThe/spacing-docs
Update X.L.Spacing documentation
2021-08-30 10:48:02 +02:00
slotThe
34af6ebed1 X.L.Spacing: Extend documentation
Users are having trouble with this module all the time.  Now that
certain helper functions are undeprecated, we should tell users how they
may use them.  It is also worth explaining the scary-looking
`spacingRaw` command a bit further.

Related: https://github.com/xmonad/xmonad-contrib/pull/597
2021-08-29 10:10:49 +02:00
slotThe
4a63999df6 X.L.Spacing: Reorder export list 2021-08-29 10:03:01 +02:00
slotThe
64e67d5749 CHANGES.md: Mention X.L.Spacing undeprecations
Related: https://github.com/xmonad/xmonad-contrib/pull/597
2021-08-29 10:03:01 +02:00
slotThe
d8f4f841a0 X.L.Spacing: Remove link to backwards compatibility section
This has been removed already, so remove the link and move the
undeprecated functions out of there.

Related: https://github.com/xmonad/xmonad-contrib/pull/597 (cadb178819fa70b7fc83c69399c11030491de8b9)
2021-08-29 09:37:28 +02:00
slotThe
04eadeb5ed
Merge pull request #597 from IvanMalison/unDeprecateSpacingFunctions
Undeprecate spacing convenience functions
2021-08-28 10:49:21 +02:00
Ivan Malison
cadb178819 Undeprecate spacing convenience functions
These should be undeprecated for several reasons:

  - The suggestion to use spacingRaw is pretty ridiculous; the interface
    to spacingRaw is very general and flexible, which is great, but I
    think that most people probably do not need all of that flexibility,
    and one of these convenience functions may suit their needs better.

  - There is precendent for having convenience functions like
    these (like X.L.Magnifier)

These were deprecated in a rewrite to make X.L.Spacing support a
non-uniform border length, but from a usability perspective wrappers
should always be preferred to such a general interface with rather shaky
documentation.

Related: https://github.com/xmonad/xmonad-contrib/pull/243 (2c53d507ee6c49ab053e17fff0a2149087df3292)
2021-08-28 10:45:00 +02:00
slotThe
04713d2e9c
Merge pull request #596 from slotThe/logTitlesOnScreen
X.U.Loggers: Add `logTitlesOnScreen`
2021-08-19 08:40:01 +02:00
slotThe
0935fd26e0 Update CHANGES.md: Add logTitlesOnScreen 2021-08-18 08:05:14 +02:00
slotThe
1cab211bf0 X.U.Loggers: Add logTitlesOnScreen
This works like logTitles, but gets an explicit screen to log the window
titles on.  This may be useful when having status bars for each screen
that show all windows on their respective visible workspaces.
2021-08-17 12:26:34 +02:00
Tomáš Janoušek
a9ad56be11
Merge pull request #585 from liskin/xmessage
Use xmessage from core
2021-08-17 11:01:29 +01:00
Tomas Janousek
07040cbd58 Use xmessage from core
Related: https://github.com/xmonad/xmonad/pull/318
2021-08-17 10:56:14 +01:00
Tomas Janousek
8d557c6954 github: Drop FUNDING.yml
Replaced with https://github.com/xmonad/.github/blob/main/FUNDING.yml,
which points to xmonad's funding platforms instead of mine.

Related: https://github.com/xmonad/xmonad/pull/295
Related: https://github.com/xmonad/xmonad-contrib/pull/544
2021-08-15 22:29:27 +01:00
Tomas Janousek
89ecfe72a1 ci: Hackage release automation
Tested on https://github.com/xmonad/X11/releases/tag/1.10.1 so we can
deploy this here as well now.

Related: https://github.com/xmonad/xmonad/pull/308
Related: https://github.com/xmonad/xmonad-contrib/issues/393
2021-08-15 17:37:22 +01:00
slotThe
fa00fad1d9
Merge pull request #594 from IvanMalison/windowBringerFilter
X.A.WindowBringer: Add a filter function to config
2021-08-15 17:32:34 +02:00
slotThe
ee40542cb8 X.P.OrgMode: Allow specifying home dir starting with ~
It is already possible to "start" from $HOME by specifying a relative
directory (one starting without a starting slash).  However, it is often
nice to be explicit about this by writing `~/' directly—support this.
2021-08-15 17:04:21 +02:00
Ivan Malison
09b1dc1a6e X.A.WindowBringer: Add a filter function to config 2021-08-15 17:01:26 +02:00
slotThe
5417969522 X.P.OrgMode: Update documentation
Fix spelling mistakes, as well as make the existing documentation a
little bit more accurate in places.
2021-08-15 16:34:41 +02:00
Tomáš Janoušek
b4a13e6b1b
Merge pull request #119 from IvanMalison/query_toggle_state
X.L.MultiToggle: Add function to query toggle state
2021-08-13 01:26:04 +01:00
Ivan Malison
3e83068e0a X.L.MultiToggle: Add function to query toggle state 2021-08-13 01:25:03 +01:00
Yecine Megdiche
a03d58cf6a
Merge pull request #474 from TheMC47/fixed-aspect-ratio
New layout modifier: XMonad.Layout.FixedAspectRatio
2021-08-11 12:21:03 +01:00
Yecine Megdiche
b6b6616400 Added XMonad.Layout.FixedAspectRatio
Layout modifier for user provided per-window aspect ratios.
2021-08-11 13:15:21 +02:00
slotThe
efcc424c98
Merge pull request #587 from slotThe/fix-orgmode-parser
X.P.OrgMode: Fix behaviour of getLast
2021-08-11 07:16:52 +02:00
slotThe
e4b8b1f6f2 Tests: Add tests for OrgMode regressions
Add regression tests to make sure we keep the behaviour fixed by
97aeaf11c10a0f38b4cd1df4726a10bb9188f4ca.

Related: https://github.com/xmonad/xmonad-contrib/issues/584
2021-08-11 07:11:54 +02:00
slotThe
b42303aa6f X.P.OrgMode: Fix behaviour of getLast
So far, while parsing strings like "<ptn><more-letters>", the `getLast`
function immediately stopped on strings of the form "<ptn><whitespace>".
This may be a bit confusing given the functions name.  Strings of
the—perhaps artificial—form

    "a +d f 1 +d f 2"

would be cut short and parsed as

    Deadline "a" (Time { date = Next Friday, tod = Just 01:00 })

instead of the more intuitive

    Deadline "a +d f 1" (Time { date = Next Friday, tod = Just 02:00 }).

This is readily fixed by applying the `go` parser as often as possible,
only returning the longest list, and then pruning eventual leftovers at
the end of the string.  Since we were already invoking `dropWhileEnd` to
trim whitespace before, the added `reverse`s should not impact
performance at all.

Fixes: https://github.com/xmonad/xmonad-contrib/issues/584
2021-08-11 07:11:54 +02:00
Yecine Megdiche
e1a2bad168 Export placeRectangle 2021-08-09 12:06:19 +02:00
Tomáš Janoušek
8fab380724
Merge pull request #580 from IvanMalison/add-nix-flake
Add a flake.nix file
2021-08-09 10:57:21 +01:00
Ivan Malison
7402a7c250 Use "nix develop -c cabal v2-build -O0" to speed up the workflow
With "nix build", just the build of xmonad-contrib itself takes 3
minutes (it builds twice, the second build with profiling enabled), so
it ends up being almost 6 minutes in total, making this workflow the
slowest one.
2021-08-09 10:50:10 +01:00
Ivan Malison
7c7ff1fabd Add workflow for testing nix flake 2021-08-09 10:46:15 +01:00
Ivan Malison
3e43315def Add a flake.nix file 2021-08-09 10:46:15 +01:00
Tomáš Janoušek
6f0b9e3142
Merge pull request #577 from liskin/focus-under-pointer
X.A.UpdateFocus: Add focusUnderPointer
2021-08-09 10:20:41 +01:00
Tomas Janousek
fefebd56b2 X.A.UpdateFocus: Add focusUnderPointer
Some people like their mouse pointer to move when changing focus with
the keyboard, other people like their pointer to stay and focus to
follow. xmonad(-contrib) supports both preferences, but imperfectly:
The former requires using the XMonad.Actions.UpdatePointer contrib
module, the latter (focusFollowsMouse) only reacts to CrossingEvent; the
focus isn't updated after changing workspaces or layouts.

This adds an inverse of XMonad.Actions.UpdatePointer.updatePointer that
immediately updates the focus instead.

Fixes: https://github.com/xmonad/xmonad/issues/108
2021-08-09 10:20:00 +01:00
Tomáš Janoušek
78373349c2
Merge pull request #586 from liskin/submap-sync
X.A.Submap, X.U.Ungrab: Sync after ungrab (fixes issues with runProcessWithInput)
2021-08-09 10:12:44 +01:00
Tomas Janousek
91995df559 X.A.Submap, X.U.Ungrab: Sync after ungrab (fixes issues with runProcessWithInput)
When `runProcessWithInput` is invoked immediately after
`ungrabPointer`/`ungrabKeyboard`, we don't actually ungrab at all
because `runProcessWithInput` blocks and the ungrab requests wait in
Xlib's queue for a requests that needs a queue flush.

Common uses of `unGrab` (before `spawn`) aren't followed by a blocking
action, so the ungrab requests are flushed by xmonad's main loop, and
this is merely a timing issue—fork/exec takes a while and xmonad
probably manages to get back to its main loop in time. Uses of
`runProcessWithInput` in ordinary non-submap key bindings happen to work
because key bindings are passive grabs—the grab is released by the
user's fingers releasing the key itself, even if xmonad's ungrab
requests are stuck in a blocked queue. Submap key bindings, however,
take an active grab and therefore need to ungrab explicitly.

Easy fix—explicit `sync`.

Fixes: https://github.com/xmonad/xmonad/issues/313
2021-08-08 16:05:49 +01:00
Tomas Janousek
73e4691ba7 ci: Test with GHC 8.10.4 2021-08-08 11:41:16 +01:00
Tomas Janousek
8de415743d ci: Disable optimization in the haskell-ci workflow
Cuts a minute from the build. This was already disabled in the Stack
workflow and we just forgot to put it here as well.

Related: https://github.com/xmonad/xmonad-contrib/pull/580
2021-08-08 11:37:29 +01:00
Tomas Janousek
c5654c47ba tests: Show counterexamples for test failures in OrgMode 2021-08-07 15:25:35 +01:00
Tomas Janousek
97508ac109 X.H.TaffybarPagerHints: Correct module name in haddock header
Fixes: f754b9f926d4 ("X.U.TaffybarPagerHints: init")
2021-08-01 09:22:58 +01:00
Tomas Janousek
ad23988a99 Merge branch 'addTaffybarPagerHints' 2021-07-31 23:07:10 +01:00
Ivan Malison
f754b9f926 X.U.TaffybarPagerHints: init 2021-07-31 23:06:19 +01:00
Tomas Janousek
4c759ff70c CHANGES: Fix whitespace 2021-07-26 18:52:22 +01:00
slotThe
97289ff6ca
Merge pull request #574 from slotThe/only-float
X.L.NoBorders: Add OnlyFloat
2021-07-24 10:22:46 +02:00
slotThe
815d0e397b
Merge pull request #562 from 4caraml/window-sublayouting
Add sublayouting to X.H.WindowSwallowing
2021-07-23 19:18:48 +02:00
4caraml
bbd972012e X.H.WindowSwallowing: Implement SubLayout window "swallowing"
This implements window swallowing on top of SubLayouts; the matched
windows are simply tabbed together instead of one actually being
swallowed.  This provides an improved experience for people using
SubLayouts, as the parent window is still accessible.

Done as part of ZuriHac 2021.

Related: https://github.com/xmonad/xmonad-contrib/issues/416#issuecomment-777400194
2021-07-23 18:48:37 +02:00
slotThe
a3aff3b946
Merge pull request #576 from liskin/fix-def-k
X.H.StatusBar: Simplify the fix for `def` as `k`
2021-07-23 08:20:00 +02:00
Tomas Janousek
af2183b316 X.H.StatusBar: Simplify the fix for def as k
Fixes: 58e2b803a478 ("fix: handle `const (0,0)` from passing `def` as keybinding action")
2021-07-22 18:47:10 +01:00
Yecine Megdiche
6b16e45166
Merge pull request #575 from geekosaur/def-keybinding-function
trap `(0,0)` keybinding function and use default binding
2021-07-22 10:48:34 +01:00
brandon s allbery kf8nh
58e2b803a4 fix: handle const (0,0) from passing def as keybinding action
Before https://github.com/xmonad/xmonad/commit/383ffb7 this would
bind all unbound keys to toggle struts; after it, it would bind no
keys at all. With this commit, it will check for this case and use
the default keybinding instead.

Users who intend no key to be bound should probably use `withSB`
instead, especially in light of aforementioned commit.
2021-07-21 15:30:29 -04:00
slotThe
03f055fe0d Updates CHANGES.md: Add OnlyFloat 2021-07-21 07:59:22 +02:00
slotThe
ad58f0a388 X.L.NoBorders: Add property test for OnlyFloat
OnlyFloat should remove all floating borders at all times; this is a
property that's readily tested with the multihead setup that's already
defined.
2021-07-21 07:59:22 +02:00
slotThe
220656aab0 Add Arbitrary instance for RationalRect 2021-07-21 07:59:22 +02:00
slotThe
8a0a84f1d5
Merge pull request #573 from Rogach/pr--fix-color-range-from-class-name
Rewrite GridSelect.stringToRatio to use randomR (fixes #572)
2021-07-20 10:38:16 +02:00
Platon Pronko
71e57caa8e rewrite GridSelect.stringToRatio to use randomR (fixes #572)
Due to differences between random-1.1 and random-1.2, on newer systems
stringToRatio returns numbers outside [0, 1] range, which breaks
colorRangeFromClassName colorizers.

This commit fixes the issue by using randomR to directly generate the random number.

Also this fixes the compilation warning (genRange and next are deprecated in random-1.2).
2021-07-19 21:20:40 +03:00
slotThe
28fff7c1a2 X.L.NoBorders: Add OnlyFloat
This adds a new constructor to Ambiguity to unconditionally remove
borders for all floating windows.
2021-07-16 13:52:20 +02:00
slotThe
da2fb360b8
Merge pull request #568 from kurnevsky/ewmh-windows-ordering
Change EWMH windows ordering to be closer to the spec

Fixes: #567
2021-07-14 19:36:34 +02:00
Tomas Janousek
5d0a3de24d Merge branch 'AusCyberman/master'
Closes: https://github.com/xmonad/xmonad-contrib/pull/569
2021-07-13 10:43:10 +01:00
Tomas Janousek
747862c1eb X.H.DynamicIcons: Import X.H.StatusBar.PP instead of the obsolete X.H.DynamicLog 2021-07-13 10:42:55 +01:00
Tomas Janousek
23e3decbb2 CHANGES: Clarify X.H.DynamicIcons entry
This should've been part of a0caca5edce9f00b7bdc7d709fa696d5630ad1dd but
got lost.

Fixes: a0caca5edce9 ("X.H.DynamicIcons: Update docs")
2021-07-13 10:42:55 +01:00
AusCyber
bbb093d466 X.H.DynamicIcons: Add icon filtering to configuration 2021-07-13 10:42:55 +01:00
slotThe
27ae4bd2a4
Merge pull request #570 from skewerr/master
X.A.DynamicWorkspaceOrder: Export swapOrder and swapWithCurrent
2021-07-13 10:10:08 +02:00
spoonm
31b12ebb8a
X.A.DynamicWorkspaceOrder: Export swapOrder and swapWithCurrent
These actions are very convenient for managing the workspace order, and
should be made available for use through the module.
2021-07-13 04:02:02 -03:00
Evgeny Kurnevsky
fa82db1130
Change EWMH windows ordering to be closer to the spec. 2021-07-02 23:13:54 +03:00
slotThe
1351f9a931
Merge pull request #564 from slotThe/nspHide
X.U.NamedScratchpad: Add logHook to auto-hide named scratchpads on focus loss
2021-06-29 14:15:29 +02:00
slotThe
159adddb3b Update CHANGES.md: Add nsHideOnFocusLoss 2021-06-29 14:07:05 +02:00
slotThe
361a34d797 X.U.NamedScratchpad: Add nsHideOnFocusLoss
This adds a new logHook, nsHideOnFocusLoss, that hides the given
scratchpads when they lose focus.  This is akin to the functionality
provided by a lot of dropdown terminals.
2021-06-29 14:07:05 +02:00
slotThe
5fffe03e06
Merge pull request #563 from ss7m/master
Add shiftWin to X.U.PureX
2021-06-28 09:06:03 +02:00
ss7m
7d4c3e36c9 Update CHANGES.md: Add shiftWin 2021-06-28 08:59:42 +02:00
sam-barr
640388942b X.U.PureX Add shiftWin 2021-06-28 08:59:36 +02:00
slotThe
e30269fe96 Update CHANGES.md: Move X.A.EasyMotion to 0.17 section
Moving this from the new modules in 0.14 to the current release was
missed when the pr was resurrected.

Related: https://github.com/xmonad/xmonad-contrib/pull/222
Related: https://github.com/xmonad/xmonad-contrib/pull/515
2021-06-25 18:54:52 +02:00
slotThe
67c9d7fe90 X.H.RefocusLast: Export withRecentsIn
This exports the `withRecentsIn` function, as it's quite useful when
using X.H.RefocusLast in other modules as a library.

It is already possible (RecentsMap is fully exported) to completely
define this function outside of the module, so we are not exposing any
more internals than we were before.
2021-06-23 09:51:33 +02:00
slotThe
722967cb12
Merge pull request #561 from exorcist365/master
Remove all derivations of Typeable
2021-06-18 14:12:51 +02:00
Joan Milev
f732082fdc Remove all derivations of Typeable
Typeable has been automatically derived for every type since GHC 7.10,
so remove these obsolete derivations.  This also allows us to get rid of
the `DeriveDataTypeable` pragma quite naturally.

Related: https://github.com/xmonad/xmonad/pull/299 (xmonad/xmonad@9e5b16ed8a)
Related: bd5b969d9ba24236c0d5ef521c0397390dbc4b37
Fixes: https://github.com/xmonad/xmonad-contrib/issues/548
2021-06-18 14:10:23 +02:00
slotThe
4ddb3e4915
Merge pull request #559 from slotThe/OrgMode-tests
X.P.OrgMode: Add property tests
2021-06-17 09:47:35 +02:00
Yecine Megdiche
35197c8907
Merge pull request #558 from TheMC47/X.A.CycleWS-refactor-wstype
`X.A.CycleWS`: deprecate `WSType` constructors, add `ignoringWSs` predicate
2021-06-15 11:40:43 +01:00
Yecine Megdiche
ea990921e2 X.A.CycleWS: Added ignoringWSs
`ignoringWSs` is useful in combination with `X.U.NamedScratchpad` to
skip a list of tags
2021-06-15 08:51:02 +02:00
Yecine Megdiche
51394c6e3e X.A.CycleWS: Deprecated WSType Data Constructors
By deprecating everything except `WSIs` and adding constructors to
logically combine `WSType` values, we can have a more flexible interface.
Adding anything to the old interface would mean going through `WSIs`, and
all old constructors can be implemented of terms of `WSIs`.
2021-06-15 08:48:53 +02:00
slotThe
5995d6c117 X.C.Desktop: Add type signatures
When we applied hlint hints in bd5b969d9ba24236c0d5ef521c0397390dbc4b37,
the definition of desktopLayoutModifiers got (via the hint to eta
reduce) changed from

    desktopLayoutModifiers layout = avoidStruts layout

to

    desktopLayoutModifiers = avoidStruts

While the former is general enough to infer the type signature

    LayoutClass l a => l a -> ModifiedLayout AvoidStruts l a

the latter just sees the usage site of

    , layoutHook = desktopLayoutModifiers $ layoutHook def

in the desktopConfig function and thus—through the magic of
MonomorphismRestriction—infers the specialized type

    Choose Tall (Choose (Mirror Tall) Full) Window
      -> ModifiedLayout AvoidStruts
           (Choose Tall (Choose (Mirror Tall) Full)) Window

This obviously completely falls apart once someone wants to change the
layout and still uses desktopLayoutModifiers (unaware that it is just
avoidStruts at the moment).  The easy fix is to give things type
signatures, so nothing needs to be inferred.

The _actual_ solution would be, in my opinion, to completely deprecate
X.C.Desktop and remove it in a future release, as well as to completely
rewrite the provided Example.hs.  This needs more deliberation though.

Fixes: https://github.com/xmonad/xmonad-contrib/issues/560
Related: bd5b969d9ba24236c0d5ef521c0397390dbc4b37
2021-06-14 18:36:04 +02:00
slotThe
cfc793e94f tests: Add OrgMode
Adds a pretty-printer, as well as property tests that this is in fact
an proper inverse for the parser.
2021-06-13 19:52:48 +02:00
slotThe
dea8d9dced X.P.OrgMode: Appropriately pad output time
The standard formatting for org is to left-pad single digits with a
zero; do that.
2021-06-13 19:33:08 +02:00
slotThe
1c6e6c808d X.P.OrgMode: Start counting years at 25
This is for disambiguation purposes.  Otherwise, there is no way to
decide whether

    message +s 17 jul 12

wants to schedule the note for the 17th of july at 12:00, or for
the 17th of july in the year 12.  The easiest way around this is to
stipulate that people want to make these notes for the future more
often than not and to simply prohibit note before the year 25 (as that
is where the valid times end).
2021-06-13 19:08:09 +02:00
slotThe
4b15ea2ecc X.P.OrgMode: Parse empty message
Empty messages seem quite useless, but it's an easy fix for the parser
to be able to deal with them, so do it.
2021-06-13 19:02:01 +02:00
slotThe
c1cb3aaa24 X.P.OrgMode: Only parse actual words
Instead of trying to find a prefix and then killing the rest of the
word, actually see whether it at least fits the pattern.  This means
that

    message +s saturated

will no longer parse as a scheduled item for saturday, while

    message +s satur

still will.
2021-06-13 19:01:59 +02:00
slotThe
5067164d19
Merge pull request #556 from slotThe/org-mode-link
X.P.OrgMode: Linkify URLs with `orgPromptPrimary`
2021-06-11 16:49:04 +02:00
slotThe
c9ca4ce026 X.P.OrgMode: Linkify URLs in orgPromptPrimary
If we have a URL in the clipboard and we use `orgPromptPrimary`, it
would be nice if

    message +s 11 jan 2013

would result in

    * TODO [[_URL_][message]]
      SCHEDULED: <2013-01-11 Fri>

instead of the current

    * TODO message
      SCHEDULED: <2013-01-11 Fri>
      _URL_

This has the advantage that if one shows scheduled or deadlines items in
the org-agenda, it is possible to immediately follow this link with
`C-c C-o` or similar functionality.

The URL detection is very rudimentary right now.  One use `parseURI`
from `network-uri`, but that would be an additional dependency that I
didn't think was worth it.
2021-06-10 15:46:48 +02:00
slotThe
5da9b26142 X.P.OrgMode: Prune extra whitespace
This implements whitespace pruning at the end of a sheduled item or
deadline.  If we have a message like

    This is a message                +s today

it is expected that we created a heading of just "This is a message",
without the extra whitespace.
2021-06-10 15:43:27 +02:00
slotThe
6d184e859c
Merge pull request #534 from oogeek/X.A.CopyWindow-doc-improve
X.A.CopyWindow: Add copiesPP
2021-06-10 14:08:27 +02:00
oogeek
d521d18dde X.A.CopyWindow: Add copiesPP
This is a function that takes a pretty-printer and makes it aware of
copies of the currently focused window.  This is particularly nice when
using it with a StatusBarConfig.

Related: https://github.com/xmonad/xmonad-contrib/pull/463
2021-06-10 14:03:52 +02:00
slotThe
c89730fc32
Merge pull request #501 from oogeek/for-layout-independentscreens
X.L.IndependentScreens: Add workspacesOn, withScreen, fix marshallPP always sorting lexically
2021-06-10 11:09:14 +02:00
oogeek
8899078b00 X.L.IndependentScreens: Add workspacesOn, withScreen, fix marshallPP always sorting lexically
- Added `workspacesOn` for filtering workspaces on the current screen.

- Added `withScreen` to specify names for a given single screen.

- Added new aliases `PhysicalWindowSpace` and `VirtualWindowSpace`
  for a `WindowSpace` for easier to read function signatures.

- Fixed a bug where `marshallPP` always sorted workspace names
  lexically.

Fixes: https://github.com/xmonad/xmonad-contrib/issues/420
2021-06-10 11:07:49 +02:00
Tomas Janousek
b6cd47db29 X.H.StatusBar.PP: Clarify ppOutput doc + minor cleanups 2021-06-08 00:14:17 +01:00
Tomas Janousek
c3b67ab0df X.U.ClickableWorkspaces: Fix Haddock formatting 2021-06-08 00:14:17 +01:00
slotThe
4bc0470e62
Merge pull request #525 from slotThe/compl-docs
X.Prompt: Document, simplify completion window implementation
2021-06-07 09:39:04 +02:00
slotThe
f76318ce5f X.Prompt: Calculate prompt width once at the start
At the moment, we re-calculate the prompt width every time we want
to (re)draw the prompt window.  This is unnecessary, as the screen
dimensions or the preferred position changing _while the prompt is
active_ is extremely unlikely.

This now calculates the desired width at the start of the prompts event
loop and threads it through to the places that need it.
2021-06-07 09:33:35 +02:00
slotThe
5bc0d9d777 X.Prompt: Remove non-IORef complWin
While it is true that we need an IORef complWin in case of an exception,
so the window can be destroyed correctly, we do not need its non-IORef
counterpart at all.

When we need to access the complWin it's undoubtably when we want to do
_something_ with regards to window management; these things naturally
live in `XP ()` and so there's not loss of purity with this change.
2021-06-07 09:33:35 +02:00
slotThe
84dcc9b716 X.Prompt: Document createPromptWin 2021-06-07 09:33:35 +02:00
slotThe
a49c4066b9 X.Prompt: Simplify nextComplIndex 2021-06-07 09:33:35 +02:00
slotThe
6036151ca7 X.Prompt: Document destroyComplWin 2021-06-07 09:33:35 +02:00
slotThe
aa35d6a2f2 X.Prompt: Document getCompletions 2021-06-07 09:33:35 +02:00
slotThe
26c4fb0f2d X.Prompt: Document printComplList, rename 2021-06-07 09:33:35 +02:00
slotThe
5f58fb5cd1 X.Prompt: Document drawComplWin 2021-06-07 09:33:35 +02:00
slotThe
2f6546a8d6 X.Prompt: Document getComplWinDim 2021-06-07 09:33:34 +02:00
slotThe
96640f7aae X.Prompt: Document printPrompt 2021-06-07 09:32:56 +02:00
slotThe
548595ed34 X.Prompt: Document redrawComplWin 2021-06-07 09:32:56 +02:00
slotThe
b7dbc277a7 X.Prompt: write updateWindows in terms of redrawWindows
Also document the functions because they dearly need it.
2021-06-07 09:32:56 +02:00
slotThe
0af9435d58 X.Prompt: Make ComplWindowDim a proper type 2021-06-07 09:32:56 +02:00
Tomas Janousek
402d29b306 ci: Enable hlint in haskell-ci 2021-06-06 18:47:13 +01:00
slotThe
9f52af27b9 Add .hlint.yaml
We do want to ignore some hints.

Currently this is:

  - Evaluate: Some type level magic sometimes requires us to write
    expressions that could be evaluated further, but should not.

Related: https://github.com/xmonad/xmonad-contrib/issues/537
2021-06-06 18:59:05 +02:00
slotThe
bd5b969d9b Apply hlint hints
All hints are applied in one single commit, as a commit per hint would
result in 80+ separate commits—tihs is really just too much noise.

Related: https://github.com/xmonad/xmonad-contrib/issues/537
2021-06-06 18:59:05 +02:00
Tomas Janousek
b96899afb6 X.H.StatusBar: Fix misleading doc comment about encodeString
This isn't true since 63e31ccd8d28, `xmonadPropLog'` does the encoding
now and accepts a normal Haskell String now.

Fixes: 63e31ccd8d28 ("X.H.DynamicLog: Move UTF8 encoding from dynamicLogString to xmonadPropLog'")
2021-06-06 13:56:40 +01:00
Tomas Janousek
e9334b5268 Bump xmonad dependency
Merging NewSelect into Choose is a breaking change, bump the dependency
to let users know they absolutely have to fetch today's xmonad git as
well.
2021-06-04 19:04:17 +01:00
Tomáš Janoušek
8c72f77c8e
Merge pull request #493 from slotThe/NewSel
Move X.L.LayoutCombinators.(|||) to XMonad.Layout
2021-06-04 18:30:03 +01:00
slotThe
4489ab2147 Update CHANGES.md 2021-06-04 18:24:42 +01:00
slotThe
9af232489d Remove unnecessary imports of X.L.LayoutCombinators 2021-06-04 18:23:37 +01:00
slotThe
921ee69064 X.L.LayoutCombinators: Update for new X.L.(|||)
With xmonad/xmonad@45b2275b88 going live
the functionality of X.L.LayoutCombinators.(|||) was moved into xmonad
core, more specifically into X.L.(|||).  We just need to clean up the
contrib side of things, which involves making JumpToLayout and NewSelect
type aliases and cutting out the custom layout combinator.

Related:
  - https://github.com/xmonad/xmonad/pull/281
  - xmonad/xmonad@45b2275b88
  - https://github.com/xmonad/xmonad-contrib/issues/116
2021-06-04 18:23:37 +01:00
Tomas Janousek
bb71111b75 X.L.LayoutModifier: Drop outdated comment about haddock bug
This doesn't seem to be true any more with haddock 2.23.0.
2021-06-04 16:38:20 +01:00
Tomas Janousek
5230f038b3 Merge branch 'pr/rescreen' 2021-06-03 11:10:58 +01:00
Tomas Janousek
30995c41ff X.H.StatusBar: Use addAfterRescreenHook instead of listening for RRScreenChangeNotifyEvent
The new X.H.Rescreen provides a simpler composable API for hooking into
rescreen. Unfortunately it also breaks other code that listens for
RRScreenChangeNotifyEvent, so this conversion isn't really optional.

Not that there's any dispute this is nicer, is there? :-)
2021-06-03 11:10:33 +01:00
Tomas Janousek
eab9a3a58e X.U.ExtensibleConf: Flip arguments of once(M)
This appears to be more natural. The function will most often be fixed
by the module using `XC.once` and the configuration will often be
supplied by users of those modules, so it's better to partially apply
the function first.
2021-06-03 11:10:33 +01:00
Tomas Janousek
13b1de27a9 X.H.StatusBar: Add statusBarGeneric for taffybar/trayer/stalonetray
`statusBarGeneric`: A generic `StatusBarConfig` that launches a status
bar but takes a generic `X ()` logging function instead of a `PP`. This
has several uses:

 * With `xmonadPropLog` or `xmonadPropLog'` in the logging function, a
   custom non-`PP`-based logger can be used for logging into an `xmobar`.

 * With `mempty` as the logging function, it's possible to manage a status
   bar that reads information from EWMH properties like `taffybar`.

 * With `mempty` as the logging function, any other dock like `trayer` or
   `stalonetray` can be managed by this module.

Related: https://github.com/xmonad/xmonad-contrib/pull/463
2021-06-03 02:31:47 +01:00
Tomas Janousek
4a6f21604f X.H.Rescreen: Port to ExtensibleConf 2021-06-03 01:02:57 +01:00
Tomas Janousek
280964b9f5 Update CHANGES, X.D.Extending: add X.H.Rescreen 2021-06-03 01:02:57 +01:00
Tomas Janousek
90c7621e1f X.H.Rescreen: Merge the two hooks together and improve their behaviour
Now that randrChangeHook is only invoked for changes that don't result
in rescreen, it can actually be used for autorandr.
2021-06-03 01:02:57 +01:00
Tomas Janousek
1ff954b4b6 X.H.Rescreen: Add randrHook 2021-06-03 01:02:57 +01:00
Tomas Janousek
5b28f5ee54 Add X.H.Rescreen module (custom rescreen hooks) 2021-06-03 01:02:57 +01:00
Tomas Janousek
f71095885f Fix more GHC warnings: -Wdeprecations
With the bumped xmonad dependency, we can drop these, leaving just 4
warnings visible in ghcid. \o/

Related: https://github.com/xmonad/xmonad/pull/258
2021-06-03 00:01:27 +01:00
Yecine Megdiche
dac3acc5dd
Merge pull request #553 from TheMC47/postpone-pipe
X.H.StatusBar.statusBarPipe: spawn in the startupHook
2021-06-02 16:02:57 +02:00
Yecine Megdiche
465044d5ce X.H.StatusBar.statusBarPipe: spawn in the startupHook
statusBarPipe abuses the interface of StatusBarConfig by starting the
status bar before the startupHook. This worked correctly before, but it
does not play will with `dynamicSBs`
2021-06-02 15:52:05 +02:00
Tomáš Janoušek
e1db71c42c
Merge pull request #546 from slotThe/set-class
Set `WM_CLASS` for some windows
2021-06-02 11:48:19 +01:00
slotThe
f19b3f6de3 Update CHANGES.md 2021-06-02 12:37:53 +02:00
Tomas Janousek
086db3123b Temporarily symlink stack.yaml to stack-master.yaml
This shall be reverted together with the .github/workflows/stack.yml
part of 229d52ff0735e1d1d8a949d221560ccdd9872e5d once xmonad 0.17 is
out.
2021-06-02 11:06:30 +01:00
Tomas Janousek
7d122b2edf Fix typo in stack.yaml and bump resolver
Fixes: 229d52ff0735 ("Bump X11, xmonad dependencies")
2021-06-02 11:05:44 +01:00
slotThe
ff42434be3
Merge pull request #543 from slotThe/view-ws-instead-of-entering-parallel-universe-where-the-focus-is-somewhere-else
X.A.CycleRecentWS: Cycle workspaces, not windowsets
2021-06-02 09:42:09 +02:00
slotThe
055c4877a1 Update CHANGES.md 2021-06-02 09:18:43 +02:00
Tomas Janousek
86522a27b0 X.A.CycleRecentWS: Make unView work with greedyView as well
Entirely unnecessary for the current version of `cycleWindowSets`, but
if anyone ever wants to use `greedyView`, this shows that it's not at
all complicated to adapt `unView` to that.
2021-06-02 09:18:43 +02:00
Tomas Janousek
1e2e1273b8 X.A.CycleRecentWS: Revert setOption changes
These are remnants of the first fix attempt, but are no longer
necessary. This reduces the diff to `view . unview` instead of `const`.
2021-06-02 09:18:43 +02:00
Tomas Janousek
b65b83661b X.A.CycleRecentWS: Simplify unView even more
Instead of implementing `view` in reverse, we can use it directly and
then just fix the order of visible/hidden workspaces.
2021-06-02 09:18:43 +02:00
Tomas Janousek
12b30c393c X.A.CycleRecentWS: Simplify/fix unView
To make this more "obviously correct", make it resemble the `view`
implementation, just do the exact reverse. Now the only complex bit is
the "undelete" operation.

This also fixes another issue: state was only preserved in the focused
workspace, but it may have changed in another visible workspace as well.
The property test is updated to test this.
2021-06-02 08:32:41 +02:00
Tomas Janousek
24786c6d04 X.A.CycleRecentWS: Add property test for unView
Scary looking code better be tested. :-)

(For the record, the test did find an issue that is already fixed in the
previous commit.)
2021-06-02 08:32:34 +02:00
Tomas Janousek
3db9167da4 X.A.CycleRecentWS: Rename restoreOrder to unView
Makes it more obvious what it really does.

Also, don't expose origWSet as a variable, lest someone uses it. :-)
2021-06-02 08:31:53 +02:00
slotThe
f0809e5d1d X.A.CycleRecentWS: Cycle workspaces, not windowsets
The way that workspace cycling is implemented right now—by generating
new windowsets where the things we want happen to be true and then
replacing the old windowsets—is not safe, as workspaces and layouts may
carry state with them.  That state will get lost in translation when
windowsets are simply replaced.

As an example, a conflict occurs when using `X.L.ShowWName.showWName` in
one's layoutHook.  When cycling through workspaces via, e.g.,
`cycleRecentWS` the flashed workspace tag will not disappear, as the
necessary state to control this isn't present in the new windowset.

Instead, what we want to do is to keep the "current" windowset alive and
actually switch to the requested workspaces.  This mostly works without
much trouble, the only hard part is maintaining the invariant that
previewed workspaces don't count towards the history of recently-viewed
workspaces.  This is done by remembering the tag-order of the original
windowset and then restoring that at the end.

This is a breaking change, insofar as it changes the type signatures of
the exported functions `recentWS`, `cycleWindowSets`, and
`toggleWindowSets` to return a list of `WorkspaceId`s instead of a list
of `WindowSet`s.

Fixes: https://github.com/xmonad/xmonad-contrib/issues/504
2021-06-02 08:31:53 +02:00
slotThe
fd5d8267d2 Set WM_CLASS for created windows
Set the WM_CLASS property for long-living windows that need it.  This
helps users to properly match on these windows for certain tasks.

Fixes:
  - https://github.com/xmonad/xmonad-contrib/issues/526
  - https://github.com/xmonad/xmonad-contrib/issues/369
2021-06-02 08:18:11 +02:00
Joan Milev
f4673d611b X.L.BinarySpacePartition: Customizable ratio in messages that resize windows
Co-authored-by: Yecine Megdiche <yecine.megdiche@gmail.com>
2021-06-01 19:56:58 +01:00
Tomas Janousek
f6b1e5dd88 X.U.ExtensibleConf: New helper module for extensible config
It's often difficult to make contrib modules work together. When one
depends on a functionality of another, it is often necessary to expose
lots of low-level functions and hooks and have the user combine these
into a complex configuration that works. This is error-prone, and
arguably a bad UX in general.

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

This requires changes to xmonad core: https://github.com/xmonad/xmonad/pull/294

A couple examples of what this gives us:

* [X.H.RescreenHook](https://github.com/xmonad/xmonad-contrib/pull/460)
  can be made safe to apply multiple times, making it composable and
  usable in other contrib modules like X.H.StatusBar

* `withSB` from X.H.StatusBar can also be made safe to apply multiple
  times, and we can even provide an API [similar to what we had
  before](https://hackage.haskell.org/package/xmonad-contrib-0.16/docs/XMonad-Hooks-DynamicLog.html#v:statusBar)
  if we want (probably not, consistency with the new dynamic status bars
  of https://github.com/xmonad/xmonad-contrib/pull/463 is more important)

* The [X.H.EwmhDesktops refactor](https://github.com/xmonad/xmonad-contrib/pull/399)
  can possibly be made without breaking the `ewmh`/`ewmhFullscreen` API.
  And we will finally be able to have composable EWMH hooks.

Related: https://github.com/xmonad/xmonad/pull/294
2021-06-01 19:07:13 +01:00
Tomas Janousek
56cf96cfa9 X.H.ManageDocks: Fix button events on decoration windows
Decoration windows are created using XMonad.Util.XUtils.createNewWindow
which happens to set _NET_WM_WINDOW_TYPE to _NET_WM_WINDOW_TYPE_DESKTOP,
and ManageDocks considers such windows candidates for struts and
therefore requests property events, thus overriding the original event
mask requested by decorations.

The fix is to first obtain the current event mask, set the required bits
in it only then reset the mask.

Fixes: https://github.com/xmonad/xmonad-contrib/issues/517
Fixes: ec146171238b ("X.H.ManageDocks: React to strut updates of override_redirect docks")
Related: https://github.com/xmonad/X11/pull/77
2021-06-01 18:56:44 +01:00
Tomas Janousek
1427c9484a Bump version number (pre-release 0.16.999) 2021-06-01 18:35:03 +01:00
Tomas Janousek
229d52ff07 Bump X11, xmonad dependencies 2021-06-01 18:34:40 +01:00
Yecine Megdiche
5c73845c68
Merge pull request #463 from TheMC47/dynamic-status-bar-configs
Dynamic Status Bars support for XMonad.Hooks.StatusBar
2021-05-28 22:50:35 +02:00
Yecine Megdiche
d2f3a8de74 Added support for dynamic status bars.
This is heavily inspired by "XMonad.Hooks.DynamicBars", but it can be
used with any status-bar.
2021-05-28 18:47:50 +02:00
Yecine Megdiche
b6e364ce42 Rename 'spawnStatusBarAndRemember' and 'cleanupStatusBars', made them
command specific

- The names were awfully long. spawnStatusBar and killStatusBar are
perfectly fine alternatives.
- It's more flexible to have killStatusBar command specific. Also added
killAllStatusBars to provide the old functionality
2021-05-28 18:47:50 +02:00
Tomas Janousek
fde7f4f8b0 X.H.EwmhDesktops: Ignore _NET_WM_STATE_FULLSCREEN from unmanaged windows
This prevents an unnecessary refresh.

That refresh would normally be harmless but it does reset the input
focus, which happens to upset some non-conforming clients such as
https://github.com/flameshot-org/flameshot. Flameshot is an interactive
screenshot tool that creates an override-redirect fullscreen window to
let the user select a rectangle to capture and then allows drawing and
adding text and so on, but it unfortunately doesn't follow ICCCM
recommendations:

> If it is necessary for a client to receive keystrokes on an
> override-redirect window, either the client must grab the keyboard, or
> the client must have another top-level window that is not
> override-redirect and that has selected the Locally Active or Globally
> Active focus model.

Instead, it just takes input focus and hopes for the best. And it also
sends an entirely useless _NET_WM_STATE_FULLSCREEN request, which would
trigger a refresh and take that focus away.

This commit works around that by not handling that useless
_NET_WM_STATE_FULLSCREEN for unmanaged windows and thus preventing that
refresh. It's just a workaround, however: if a legitimate refresh is
necessary at any point, the focus _will_ be taken away.

Fixes: https://github.com/xmonad/xmonad-contrib/issues/550
Fixes: https://github.com/flameshot-org/flameshot/issues/773
2021-05-28 15:13:09 +01:00
Tomas Janousek
37fc86c5c4 CHANGES: Join xmobarBorder, xmobarFont entries into one
Related: https://github.com/xmonad/xmonad-contrib/pull/549
2021-05-24 20:32:24 +01:00
Yecine Megdiche
ff391de17d
Merge pull request #549 from rolsdorph/add-xmobarfont
Add xmobarFont
2021-05-24 21:26:44 +02:00
Mads Rolsdorph
1fabce659f Add xmobarFont
xmobar allows you to define a list of additional fonts (additionalFonts) and to use the fn tag to choose between them. xmobarFont is essentially the same as the xmobarColor function, but for fonts.
2021-05-24 19:45:31 +02:00
Tomas Janousek
9b933b1f69 ci: Speed up builds using ghc-options: -j
Building xmonad-contrib benefits greatly from compiling modules in
parallel. Vanessa McHale suggested setting ghc-options in
xmonad-contrib.cabal in #431, but that's bad practice—these options
should be set by the user/environment where it's being built, not
selfishly hardcoded for specific package. In stack.yaml and
cabal.haskell-ci, we know for sure that xmonad-contrib is the terminal
(leaf) library, so we can set it there and speed up builds in our CI and
also for anyone who uses our stack.yaml (not that anyone should).

Closes: https://github.com/xmonad/xmonad-contrib/pull/431
2021-05-24 18:12:10 +01:00
Tomas Janousek
17ef2b95db ci: Workaround for stack/pantry caching of github archives
Turns out `commit: master` doesn't really mean latest master, because
it's cached. It sometimes works, because when the GHA cache comes from
a job that depended on xmonad-0.15, then the master archive isn't cached
and is fetched. When the cache comes from a job that previously fetched
master, it's not fetched again.

The least ugly way to fix it I found is to use the `[<refname>]@{<date>}`
git revision format, and substitute current date/time before invoking
stack. To make stack-master.yaml valid without the substitution, we use
`master@{today}` which is a valid git revision that GitHub understands.
2021-05-24 17:49:03 +01:00
Tomas Janousek
cef324795e ci: Enable -Werror
Related: 14d9fa247a
Related: 5cdf428f55
2021-05-24 17:49:03 +01:00
Tomas Janousek
43e35952c8 Fix a few warnings reported by GHC 9.0 2021-05-24 00:21:07 +01:00
Tomas Janousek
147e83cbd0 Fix ambiguous occurrence ‘singleton’ with GHC 9.0 2021-05-24 00:19:37 +01:00
Tomas Janousek
52751f47d0 ci: Refresh caches once a month
GitHub Actions writes caches on the first miss and then never updates
them again. If the CI is used frequently, the caches never expire and
as they get old, become less useful.

To avoid this, force refreshing the caches once a month.
2021-05-24 00:19:37 +01:00
Tomas Janousek
d1a4820b55 ci: Prevent ~/.stack/pantry cache from being empty
When building with an LTS version that has exactly the dependencies we
need (xmonad-0.15), stack doesn't need to download the Hackage index. If
GitHub Actions cache locking chooses this job as the one that writes the
cache, then the "stack-pantry-Linux" cache entry stays empty, possibly
forever.

Force Hackage index update to prevent this from happening.
2021-05-24 00:19:37 +01:00
Tomas Janousek
96aae28641 ci: Cache pantry (hackage metadata) separately
This further reduces our usage of cache storage by caching the metadata
only once per repo. Now the metadata cache is ~250MB and the individual
caches with built dependencies are ~10M each.

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

Related: 9fce3805fc
Related: a5cee9bac2
Related: https://github.com/xmonad/X11/pull/75
2021-05-24 00:18:41 +01:00
Tomas Janousek
10574d9b61 ci: Reduce stack test matrix
Drop nightly and lts-15: they don't add GHC versions to the matrix and
new deps are better tested in the haskell-ci (cabal) workflow.

There's also little point in testing against both xmonad 0.15 and xmonad
master with all LTS versions. Drop most of those, reduces GitHub cache
and CPU time usage.

Related: fd243ca1c1
Related: https://github.com/xmonad/X11/pull/75
2021-05-24 00:18:34 +01:00
Tomas Janousek
6384cd04a4 ci: Refresh tested-with
Related: fd243ca1c1
Related: https://github.com/xmonad/X11/pull/75
2021-05-23 22:20:17 +01:00
Tomas Janousek
0c11288ea0 ci: Use xmonad master for haskell-ci workflow
Last released xmonad doesn't build with GHC 9.0 and haskell-ci doesn't
let us tweak the test matrix easily. Let's hope the stack.yml workflow
is sufficient to test backward compat.

Related: 2a1a18023a
2021-05-23 22:19:59 +01:00
Tomas Janousek
8d2d34ed6b ci: Move apt deps to cabal.haskell-ci and regenerate haskell-ci
Related: e4659c2475
Related: https://github.com/xmonad/X11/pull/75
2021-05-23 18:35:34 +01:00
Tomas Janousek
5c40a928a1 ci: Minor cleanup
* rename workflow to Stack

* tweak C deps

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

Related: caae51c399
Related: https://github.com/xmonad/X11/pull/75
2021-05-23 18:26:46 +01:00
slotThe
cbd44dd9f9 Fix GHC warning: -Wmissing-home-modules
Related: https://github.com/xmonad/xmonad-contrib/issues/537
2021-05-21 17:37:09 +02:00
slotThe
410469e124 Fix GHC warnings in tests/
Related:
  - https://github.com/xmonad/xmonad-contrib/issues/537
  - 673f727206b9c066691bc8ed37382aee79017d2e
2021-05-21 17:37:09 +02:00
slotThe
ea09fc2bf4 Fix GHC warning: -Wdeprecations
Related: https://github.com/xmonad/xmonad-contrib/issues/537
2021-05-21 17:37:09 +02:00
slotThe
bf55122a82 Fix GHC warning: -Wincomplete-patterns
Related: https://github.com/xmonad/xmonad-contrib/issues/537
2021-05-21 17:37:09 +02:00
Tomas Janousek
5b171640fb Merge branch 'pr/funding' 2021-05-21 12:20:29 +01:00
Tomas Janousek
ebe2a6284a X.H.EwmhDesktops: Avoid some unnecessary refreshes (border flicker)
Current version of Steam sends _NET_ACTIVE_WINDOW ClientMessage for
every mouse click which results in a lot of border blinking.

Ignore requests that would result in no change to get rid of the
annoying border flicker that is inevitable with the current
implementation of XMonad.Operations.windows.

(Note that Steam also sends ConfigureRequest events, and these cause
an additional refresh due to the call to `float` when handling the event
in xmonad core. Not sure if worth fixing.)

Related: https://github.com/xmonad/xmonad-contrib/pull/371
Related: https://github.com/xmonad/xmonad-contrib/pull/399
2021-05-21 12:19:45 +01:00
slotThe
2fb435724f
Merge pull request #539 from slotThe/topic-item
X.A.TopicSpace: Add `TopicItem`
2021-05-21 13:07:48 +02:00
slotThe
7ad38d4063 Fix GHC warning: -Wtabs
Related: https://github.com/xmonad/xmonad-contrib/issues/537
2021-05-20 17:32:18 +02:00
slotThe
518e96b384 Fix GHC warning: -Wmissing-signatures
Related: https://github.com/xmonad/xmonad-contrib/issues/537
2021-05-20 17:32:17 +02:00
slotThe
7894bcec5c Fix GHC warning: -Woverlapping-patterns
Related: https://github.com/xmonad/xmonad-contrib/issues/537
2021-05-20 17:32:16 +02:00
slotThe
25ad725e0c Fix GHC warning: -Wtype-defaults
Related: https://github.com/xmonad/xmonad-contrib/issues/537
2021-05-20 17:32:13 +02:00
slotThe
6b014e6025 Fix GHC warning: -Wunused-local-binds
Related: https://github.com/xmonad/xmonad-contrib/issues/537
2021-05-20 17:32:08 +02:00
slotThe
538089db83 X.H.EwmhDesktops, X.L.Spacing: Use PatternGuards
Fixes a GHC warning about non-standard pattern guards.

Related: https://github.com/xmonad/xmonad-contrib/issues/537
2021-05-20 17:32:04 +02:00
slotThe
673f727206 Fix GHC warning: -Wname-shadowing
Related: https://github.com/xmonad/xmonad-contrib/issues/537
2021-05-20 17:32:03 +02:00
slotThe
b51ccc87b8 Fix GHC warning: -Wunused-matches
Related: https://github.com/xmonad/xmonad-contrib/issues/537
2021-05-20 17:32:02 +02:00
slotThe
f81cb24f0a Update CHANGES.md: Add TopicItem 2021-05-20 11:24:58 +02:00
slotThe
c5781f225e X.A.TopicSpace: Update documentation
- Only suggest the usage of TopicItem; this is much easier to work
    with and essentially a straight upgrade to the old method.

  - Use a more stripped-down example so we don't confuse beginners more
    than necessary (though this is still not optimal).
2021-05-20 11:24:58 +02:00
slotThe
35a32b22d0 X.A.TopicSpace: Add TopicItem and helper functions
Add the convenience type `TopicItem`, for easier (and safer!)
specification of topics, as well as several small helper functions to
help users work with it.
2021-05-20 11:24:58 +02:00
Yecine Megdiche
3f8c570347
X.A.DynamicWorkspaceGroups: TopicSpace support (#538)
* `X.A.DynamicWorkspaceGroups`: TopicSpace support

This adds `viewTopicGroup` and a corresponding prompt. This is similar
to `viewWSGroup`, but it calls `switchTopic` instead of `W.greedyView`,
inorder to run the topic action on the workspace.
2021-05-18 09:31:05 +02:00
Tomas Janousek
12b17c4935 X.D.Extending: Fix nested lists; fix StatusBar.PP placement
Fixes: 5eb3dbd61b3f ("Split XMonad.Hooks.DynamicLog")
2021-05-17 22:21:57 +01:00
Tomas Janousek
41ba7fd0d3 X.H.EwmhDesktops: Fix _NET_ACTIVE_WINDOW requests from pagers being ignored
This makes window switching apps like rofi and alttab able to activate
windows even if the logHook doesn't activate them (which it doesn't by
default, and that's a regression).

Fixes: 45052b984dbe ("X.H.EwmhDesktops. run 'logHook' for activated window.")
Related: https://github.com/xmonad/xmonad-contrib/issues/396
Related: https://github.com/xmonad/xmonad-contrib/pull/110
Related: https://github.com/xmonad/xmonad-contrib/pull/192
2021-05-16 15:02:37 +01:00
Tomas Janousek
82ecde86fe X.H.EwmhDesktops: Clean up "handle"
Related: https://github.com/xmonad/xmonad-contrib/issues/396
Related: https://github.com/xmonad/xmonad-contrib/pull/399
Related: https://github.com/xmonad/xmonad-contrib/pull/192
2021-05-16 15:02:37 +01:00
Tomas Janousek
6946bbc48b X.{H.EwmhDesktops,L.Fullscreen}: Kill a few warnings
Related: https://github.com/xmonad/xmonad-contrib/issues/396
Related: https://github.com/xmonad/xmonad-contrib/pull/399
2021-05-16 14:58:44 +01:00
Tomas Janousek
2c1c96c3e5 X.H.{EwmhDesktops,ManageDocks}: Improve the usage doc a bit
Don't assume ewmh/docks are the only xmonad config combinator out there.

Related: https://github.com/xmonad/xmonad-contrib/issues/396
Related: https://github.com/xmonad/xmonad-contrib/pull/399
2021-05-16 14:58:38 +01:00
Tomas Janousek
19b2665246 Add Sponsor button to GitHub
These past months I've spent a lot of time working on xmonad and I feel
like I've done a lot. This is, however, not sustainable long term. :-(

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

I know that the correct approach probably is for the xmonad project to
find a fiscal sponsor like the Software Freedom Conservancy or Open
Collective or something and accept donations as a project, and then
redistribute that to people, but I don't think the project has enough
momentum to do something as complicated as that. :-/
2021-05-14 17:06:22 +01:00
slotThe
bf5dce592f
Merge pull request #499 from slotThe/contrib-prelude
New module: XMonad.Prelude
2021-05-14 16:09:50 +02:00
slotThe
00e7a5c197 X.D.Developing: Add X.Prelude
Add a small note in order to aid discoverability amongst developers.
2021-05-13 17:44:50 +02:00
slotThe
2469269119 New module: XMonad.Prelude
This is a convenience module in order to have less import noise.  It
re-exports the following:

  a) Commonly used modules in full (Data.Foldable, Data.Applicative, and
     so on); though only those that play nicely with each other, so that
     XMonad.Prelude can be imported unqualified without any problems.
     This prevents things like `Prelude.(.)` and `Control.Category.(.)`
     fighting with each other.

  b) Helper functions that don't necessarily fit in any other module;
     e.g., the often used abbreviation `fi = fromIntegral`.
2021-05-13 17:44:47 +02:00
slotThe
6ece010c01 Use reverseS instead of self-defined functions 2021-05-13 17:43:32 +02:00
Yecine Megdiche
02d0b79289
Merge pull request #536 from TheMC47/add-loggers-reference
Documentation tweaks for `X.H.StatusBar(.PP)`
2021-05-12 11:36:59 +02:00
Tomas Janousek
a622c0808f Merge branches 'sublayouts-floating-order', 'sublayouts-stack-of-stacks' 2021-05-11 15:25:18 +01:00
Tomas Janousek
8cdbb5d422 X.L.SubLayouts: Fix focusWindow' being quadratic 2021-05-11 15:10:56 +01:00
Tomas Janousek
36d06c1c5d X.L.SubLayouts: Rewrite updateGroup, updateWs' using stack of stacks
A stack of stacks is a more natural representation of what SubLayouts
does: it packs information about the global focus as well as focus in
individual groups (sublayouts).

It doesn't carry information about the sublayouts themselves (but a
similar structure in X.L.Groups does), so we still use Groups and
fromGroups in some places, but future refactor can simplify that as
well, I'm sure.

My main motivation for this is that I need to expose the window groups
to the user config, and a stack of stacks seems to be a nice data
structure for that. The motivation for exposing the groups is that I
want to manipulate focus in a way that takes groups into account. As an
example, I want the following:

 * mod-1, mod-2 to mod-0 switches to n-th group if not already focused,
   and if focused, focus next in the group

 * show these numbers and window titles in xmobar (like tmux/screen/vim
   status line), like so:

     1a weechat  1b browser  2 vim  3 mutt

Achieving this just using BoringWindows is quite tricky, but with the
ability to somehow (InspectLayout, which is work-in-progress, or message
with IORef) get the stack of stacks out of SubLayouts, this becomes
easy.
2021-05-11 15:10:52 +01:00
Tomas Janousek
975a99d9dd X.L.SubLayouts: Simplify updateWs' using updateGroup
Turns out similar logic is already in updateGroup, and we don't even
need to worry about extra/missing windows and we can just differentiate
the result of reordering.
2021-05-11 15:09:40 +01:00
Tomas Janousek
9c93d90970 X.L.SubLayouts: Avoid moving floats to end of window stack
This makes the following sequence of operations idempotent, as it should be:

    windows $ W.float w $ W.RationalRect 0 0 1 1
    windows $ W.sink w

Previously, any window not visible to the SubLayout modifier (xmonad
invokes runLayout with tiled windows only) would be reordered to the end
of stack. This commit changes the reordering logic to only reorder
windows in Groups and keep all other windows where they were.
2021-05-11 15:09:40 +01:00
Yecine Megdiche
644f993fef Added reference to "XMonad.Util.Loggers" 2021-05-11 12:32:12 +02:00
slotThe
da59f9f360
Merge pull request #540 from liskin/treeselect-xft-color
X.A.TreeSelect: Only swap green/blue for X11-xft < 0.3.3
2021-05-11 08:01:52 +02:00
Tomas Janousek
57674eb545 X.A.TreeSelect: Only swap green/blue for X11-xft < 0.3.3
The issue was fixed upstream in 0.3.3:
24f6275791
24f6275791^
(it is yet to be uploaded to Hackage, Clemens lost his Hackage
credentials :-))

Related: https://github.com/xmonad/xmonad-contrib/pull/486
Related: 46f24bb27ec4 ("X.A.TreeSelect: Fix swapped green/blue in foreground when using Xft")
2021-05-10 22:53:25 +01:00
Yecine Megdiche
0f617114c8 Updated the example usage of statusBarProp 2021-05-09 13:07:50 +02:00
slotThe
8cbe3ecd48
Merge pull request #535 from slotThe/ppWindowTitle
Move `ppTitleUnfocused` to X.U.Loggers
2021-05-08 08:10:44 +02:00
slotThe
017f79fd7a Update CHANGES.md 2021-05-08 08:07:33 +02:00
slotThe
322e06eed9 X.H.SB.PP: Move ppTitleUnfocused to X.U.Loggers
This way, people not using this functionality don't get the burden of a
bunch of `getName`s that they haven't asked about.
2021-05-08 08:07:33 +02:00
Tomáš Janoušek
aa6d1eb60b
Merge pull request #533 from slotThe/update-templates
Update issue and pull-request templates
2021-05-07 00:24:54 +01:00
slotThe
4815c42482 Change xmonad-testing box to question about tests
I don't think I've ever seen anyone check that mark, so let's transform
it into something more useful.
2021-05-06 13:13:13 +02:00
slotThe
4badaa45ed Update issue template
- We would really like a full template and not just a snippet where
  we'll have to guess the context.

- It's generally nice to know which versions of xmonad and contrib a
  users was using when encountering an issue.
2021-05-04 07:57:38 +02:00
slotThe
a99c76cce4
Merge pull request #532 from oogeek/StatusBar-doc-improve
X.H.StatusBar: update example for multiple monitors
2021-04-30 16:54:33 +02:00
oogeek
79e06cf76a update doc example for multiple monitors 2021-04-30 21:13:25 +08:00
slotThe
130e675837
Merge pull request #515 from slotThe/ezmotion
X.A.EasyMotion: Cleanup, doc improvement
2021-04-26 08:16:05 +02:00
slotThe
6a23836539
Merge pull request #529 from slotThe/ezconfig-removeKeys
X.U.EZConfig: Simplify removeKeys, removeMouseBindings
2021-04-25 16:36:07 +02:00
slotThe
226b385729 X.U.EZConfig: Simplify removeKeys, removeMouseBindings
We're not parsing anything (as opposed to the respective `P` functions)
and so there's no need to create a dummy map with units as values and
then take the difference; we can simply remove the relevant keys from
the map.
2021-04-24 09:23:02 +02:00
slotThe
1b8c3993e2
Merge pull request #506 from slotThe/safeDirPrompt
X.P.Shell: Add `safeDirPrompt`
2021-04-23 07:45:33 +02:00
slotThe
c17fc2ed65
Merge pull request #521 from oogeek/add-format-wallpapersetter
X.H.WallpaperSetter: Add defWPNamesPng, defWPNamesJpg
2021-04-22 07:25:10 +02:00
slotThe
5d148b53a3 Update CHANGES.md 2021-04-21 20:22:48 +02:00
oogeek
e214c94f0d X.H.WallpaperSetter: Add defWPNamesPng, defWPNamesJpg
This also deprecates defWPNames in favour of the (equivalent)
defWPNamesJpg.
2021-04-21 20:22:48 +02:00
slotThe
41df4b4079
Merge pull request #522 from oogeek/resize-git-X.U.Hacks
X.U.Hacks: Resize GIF
2021-04-20 18:28:22 +02:00
oogeek
1009284a03 add link to resized gifs 2021-04-20 15:27:14 +08:00
slotThe
1324baa193 Update CHANGES.md: add safeDirPrompt 2021-04-20 07:57:40 +02:00
slotThe
07439cc169 X.P.Shell: add safeDirPrompt
A new prompt that works like 'safePrompt', but is optimized for the
use-case of a program that needs a file as an argument.

This is necessarily a new function and can't just be achieved by using
the old `safePrompt`, as `getShellCompl'` does not at all filter the
files (compgen already does that based on the input), but only the
available commands.  If we start the prompt with a single command then
the chosen `searchPredicate` becomes quite useless and we can't take
advantage of fuzzy matching for file finding.  This, however, is quite
useful when having a program that explicitly expects a file as one of
its arguments, e.g. dragon [1].

What we have to do instead of to generate all available files with
compgen and _then_ filter this down to what we want via a given
function.  In order to make this change backwards compatible we have to
introduce the rather ugly `shellComplImpl`, which takes a laundry list
of all of the different parameters that we need.  Since the function is
not exported, this ugliness does perhaps not matter too much.

[1]: https://github.com/mwh/dragon
2021-04-20 07:57:40 +02:00
slotThe
6687a5bc40 CHANGES.md: Fix typo 2021-04-17 09:27:28 +02:00
slotThe
b1782da37c
Merge pull request #520 from nikshalark/master
Redefine `ComplCaseSensitivity` as a proper sum type. (#509)
2021-04-17 09:23:09 +02:00
nikshalark
f49e7d653a Redefined ComplCaseSensitivity as a proper sum type. (#509) 2021-04-17 02:19:16 -04:00
Tomas Janousek
336afc82ca X.U.ClickableWorkspaces: Fix typo 2021-04-15 10:51:32 +01:00
Tomas Janousek
52bb28824d X.U.ClickableWorkspaces: Improve getWsIndex doc 2021-04-15 08:48:40 +01:00
slotThe
1d7abb102f
Merge pull request #512 from oogeek/ClickableWorkspace-Improve
X.U.ClickableWorkspaces: Fix integration with X.A.DynamicWorkspaces
2021-04-15 08:44:10 +02:00
slotThe
ad1e858bac
Merge pull request #508 from slotThe/prompt-ah-immediate
X.Prompt: fix selection not entering history
2021-04-14 08:12:23 +02:00
slotThe
83aaf0414b X.A.EasyMotion: Update documentation 2021-04-13 19:16:31 +02:00
slotThe
c649d314fa X.A.EasyMotion: Small nits
Superficial simplifications for certain functions
2021-04-13 19:16:16 +02:00
slotThe
78f3ad26ed X.A.EasyMotion: Strictify records
There is no reason for these not to be strict.
2021-04-13 19:16:08 +02:00
slotThe
827ea89b6b X.A.EasyMotion: Add Haddock headings
These are generally very useful for users in order to get a quick
overview of what the module offers them.
2021-04-13 19:16:03 +02:00
oogeek
a33de7f73a ClickableWorkspace Improvement for X.A.DynamicWorkspaces 2021-04-13 20:38:54 +08:00
Joan MIlev
f5464224e2
X.A.EasyMotion: export proportional (#514) 2021-04-12 19:14:19 +02:00
slotThe
563aa08fae X.A.EasyMotion: font -> emFont
the `font` field is already exported by X.Prompt and so there is a
conflict when importing both modules unqualified (as many people do).
2021-04-12 09:16:46 +02:00
slotThe
a05128359a X.A.EasyMotion: consistent indentation, hlint nits 2021-04-12 08:28:19 +02:00
Matt Kingston
99ea4c23e8
New module: Actions.EasyMotion (#222) 2021-04-12 08:12:42 +02:00
Tomáš Janoušek
0ebd3a0534
Merge pull request #507 from slotThe/minimal-pragmas
Add `MINIMAL` pragmas to `HasName` and `XPrompt`
2021-04-10 09:29:09 +01:00
slotThe
8aefbf8883 Add MINIMAL for HasName 2021-04-10 08:32:32 +02:00
slotThe
7702fa052b Add MINIMAL for XPrompt 2021-04-10 08:32:32 +02:00
slotThe
828983060d X.Prompt: fix selection not entering history
When `alwaysHighlight` is enabled and one immediately presses (by
default) Return after opening the prompt (because the highlighted
completion is what one wants) then the selection will not enter the
prompt history.  Instead, an empty string will be entered because there
hasn't been any input yet and hence the `highlightedCompl` field has not
yet been filled in.

The fix is simply checking whether `alwaysHighlight` is set during
startup and, if yes, already setting the highlighted completion to the
first suggestion.
2021-04-09 15:29:51 +02:00
slotThe
d7ad486a6e X.Prompt: get rid of MultiWayIf
Not needed anymore
2021-04-08 14:47:59 +02:00
slotThe
344ace492b X.Prompt: Properly handle one completion in hlComplete
This builds upon the idea of 780360abf078d47908c446941bc0c0bae6b8664d
but it fixes the issue in a bit of a nicer way; instead of throwing an
exception and closing the prompt, we simply check if there is only a
single completion available inside `hlComplete` directly.

While what 780360abf078d47908c446941bc0c0bae6b8664d said is true insofar
that we have incomplete information when inside `hlComplete`, this does
not actually matter in this case.  We have access to the complete user
input (possibly consisting of things not from this round of completion),
which is enough here.
2021-04-08 14:47:39 +02:00
Tomáš Janoušek
72548b9206
Merge pull request #491 from liskin/pr/dynamicicons-changes
X.H.DynamicIcons: Cleanups, docs improvements, composability with other *PPs
2021-04-08 09:26:48 +01:00
slotThe
c5ccb1a7ef
Merge pull request #505 from slotThe/hl-item
X.Prompt: Special handling of one highlighted item
2021-04-07 15:26:56 +02:00
slotThe
780360abf0 X.Prompt: Special handling of one highlighted item
Fixes a bug introduced in f2cfaa33980061f4fb39b689403701d36babe33f.

The changes there allowed the prompt to cycle through its input; it now
becomes necessary to single out the case of only having a single
suggestion that's also highlighted.  Otherwise, `hlComplete` (condition:
`alwaysHighlight` is enabled) will loop forever.  This case can't be
handled from within hlComplete, as we are giving it incomplete
information to start with (by only calling it with the last word of the
current completion in `handleCompletion`), which is necessary for things
like completing arguments.
2021-04-06 19:46:21 +02:00
Tomas Janousek
78b6df0e69 Drop some recently added trailing whitespace 2021-04-05 21:24:43 +01:00
Yecine Megdiche
a668b0f13a
Merge pull request #503 from oogeek/X.L.Rename-KeepWordsLR
add KeepWordsLeft and KeepWordsRight for X.L.Renamed
2021-04-05 18:46:02 +01:00
oogeek
c3c033bb91 add KeepWordsLeft and KeepWordsRight for X.L.Renamed and updated CHANGES.md 2021-04-06 01:32:19 +08:00
Tomáš Janoušek
0efc99ae13
Merge pull request #502 from TheMC47/rework-status-bar
X.H.StatusBar: Removed unnecessary IO
2021-04-04 10:56:45 +01:00
Yecine Megdiche
168cb6a6c3 Removed unnecessary IO
This applies for withSB and withEasySB, as well as statusBarProp and
statusBarPropTo, making composability better. statusBarPipe is more
awkward to use now, but that's fine
2021-04-04 00:53:42 +02:00
Tomas Janousek
654fa5045c Merge branch 'TheMC47/split-dynamic-log' 2021-04-02 21:36:38 +01:00
Tomas Janousek
a1c2d144b3 Final touch of DynamicLog/StatusBar/PP docs 2021-04-02 21:28:41 +01:00
Yecine Megdiche
06fd90a5f8 Rename makeStatusBar to withSB, makeStatusBar' to withEasySB 2021-04-02 21:19:34 +01:00
slotThe
3e11bae4b1 X.H.StatusBar: Doc suggestions 2021-04-02 21:19:34 +01:00
Yecine Megdiche
b9913bd4df Cleanup CHANGES.md
Adapted mentions of `XMonad.Hooks.DynamicLog`, and moved the changes in
`XMonad.Hooks.DynamicLog` to the appropriate entries
2021-04-02 21:19:34 +01:00
Tomas Janousek
8e39d22cec X.H.StatusBar.PP: Move dynamicLog to DynamicLog
This function isn't useful in the new interface, ditch it.
2021-04-02 21:19:34 +01:00
Tomas Janousek
4e1b277784 X.H.StatusBar: Clean up usage documentation 2021-04-02 21:19:34 +01:00
Tomas Janousek
e32e17aa2d X.U.ClickableWorkspaces: Update docs for X.H.StatusBar 2021-04-02 21:19:34 +01:00
Tomas Janousek
2865268a7a Improve descriptions of X.H.{DynamicLog,StatusBar,StatusBar.PP} 2021-04-02 21:19:34 +01:00
Tomas Janousek
f316d52c1c X.H.StatusBar: Reword the $multiple section
Do not assume knowledge of what this used to be like in the past. Start
by describing how to configure multiple status bars now.
2021-04-02 21:19:34 +01:00
Tomas Janousek
eea41cbf76 Sort exposed-modules in xmonad-contrib.cabal 2021-04-02 21:19:34 +01:00
Yecine Megdiche
5eb3dbd61b Split XMonad.Hooks.DynamicLog
- XMonad.Hooks.DynamicLog.PP: the pretty-printing abstracion, with the
corresponding utilities
- XMonad.Hooks.StatusBar: A new module to provide a better interface to
manage external status bars.
2021-04-02 21:19:34 +01:00
slotThe
42307c2855
Merge pull request #500 from slotThe/xmonad.prompt.orgmode
New Module: XMonad.Prompt.OrgMode
2021-04-02 16:58:02 +02:00
slotThe
fd20202c23 X.P.OrgMode: Add ability to schedule hours/minutes 2021-04-02 08:15:28 +02:00
slotThe
db8e47e0b4 Update CHANGES.md, X.D.Extending.hs: add X.P.OrgMode 2021-04-01 18:36:31 +02:00
slotThe
e2eee301e0 New module: XMonad.Prompt.OrgMode 2021-04-01 18:36:31 +02:00
slotThe
902c2bb17d
Merge pull request #497 from l29ah/ghc-9.0.1
Fix ghc-9.0.1 compatibility
2021-03-26 07:37:05 +01:00
Sergey Alirzaev
1033818631
ghc-9.0.1 compatibility fixes 2021-03-26 05:20:49 +03:00
slotThe
7d5426a183 X.L.Magnifier: All -> AllWins
This was exposed in afb6ef841296fc4810e068e848bbfe6c1a7ce935, but
clashes with Data.Monoid.All
2021-03-25 21:16:04 +01:00
slotThe
08059e8fb7
Merge pull request #496 from slotThe/magnifier-n
X.L.Magnifier: Add `magnify` combinator and magnification at N windows
2021-03-25 17:49:49 +01:00
slotThe
9618a0b616 Update CHANGES.md 2021-03-25 15:24:43 +01:00
slotThe
315d1acaea X.L.Magnifier: Update documentation 2021-03-25 15:24:43 +01:00
slotThe
afb6ef8412 X.L.Magnifier: Add magnify
This more general function subsumes (almost) all previously known
combinators in this library (it is still symmetric with regards to
magnification, as this is what most users want).  Also export some
previously internal (but not crucial to the implementation) types to
make this possible.
2021-03-25 15:24:43 +01:00
slotThe
2b6075666c X.L.Magnifier: Add way to magnify only starting at N windows
Also fix the rather embarrassing mistake of
bb205e92051de531c6c8b7eb1d692779969b6710 to not just make everything a
proper record.
2021-03-25 13:59:29 +01:00
slotThe
b56804d5f2 X.L.Magnifier: re-indent handleMess
More conventional style
2021-03-25 13:24:59 +01:00
Tomas Janousek
a0caca5edc X.H.DynamicIcons: Update docs 2021-03-25 10:08:37 +00:00
Tomas Janousek
835aeaaffb X.H.DynamicIcons: Move stuff around a bit (similar order to export list)
Makes the other commits easier to review.
2021-03-25 10:08:37 +00:00
Tomas Janousek
52f6aa2c4b X.H.DynamicIcons: Use ppRename - simpler, better interop with other modules
This ports DynamicIcons to the recently introduced ppRename mechanism,
which means DynamicIcons can now safely be combined with clickablePP,
workspaceNamesPP and marshallPP.

This also fixes DynamicIcons not working properly with urgent workspaces
due to forgotten ppUrgent counterpart in data Icon. Also,
ppVisibleNoWindows wouldn't work properly.

The code is now considerably simpler, but we lost the ability to use
different icons depending on whether the workspace is
visible/hidden/urgent/etc. If anyone needs that, it can be worked around
by using some markup that is later interpreted in
ppVisible/ppHidden/ppUrgent/etc.

Related: https://github.com/xmonad/xmonad-contrib/pull/481
2021-03-25 10:08:37 +00:00
Tomas Janousek
a18a155a8b X.H.DynamicIcons: Refactor dynamicIconsPP, getIcons a bit
Move all the workspaces and icon generation logic into getWorkspaceIcons
and drop the Maybe which is no longer necessary since we made the
formatting logic configurable.

Related: https://github.com/xmonad/xmonad-contrib/pull/450
2021-03-25 10:08:37 +00:00
Tomas Janousek
a000438526 X.H.DynamicIcons: Refactor dynamicLogIconsConvert a bit
Rename to dynamicIconsPP and change the type to something similar to
workspaceNamesPP and marshallPP.

Related: https://github.com/xmonad/xmonad-contrib/pull/450
2021-03-25 10:08:37 +00:00
Tomas Janousek
f127cf55f4 X.H.DynamicIcons: Improve configuration of output formatting
Make it possible to keep workspace id in the output (iconsFmtAppend) and
to wrap icons even if there's just one, or zero.

Also, change the default to use curly brackets to avoid confict with
brackets/parentheses used by default PPs in DynamicLog.

Related: https://github.com/xmonad/xmonad-contrib/pull/450
2021-03-25 10:08:37 +00:00
slotThe
c9a9cabcce
Merge pull request #495 from slotThe/magnifier-cleanup
X.L.Magnifier: Add `magnifierczOff` and `magnifierczOff'`
2021-03-24 18:48:07 +01:00
slotThe
3aadb487ed Update CHANGES.md 2021-03-24 18:33:47 +01:00
slotThe
bb205e9205 X.L.Magnifier: Strictify and document Magnifier type 2021-03-24 18:33:47 +01:00
slotThe
1726bdb67b
Merge pull request #349 from sergeykish/master
Use XFT fonts if available
2021-03-24 12:44:09 +01:00
Sergey Kish
619d0819af Use XFT fonts if available
The silent error `user error (createFontSet)` would break certain
modules (like the prompt) by simply not showing anything.

Pango 1.44 dropped support for FreeType in favor of HarfBuzz, losing
support for traditional BDF/PCF bitmap fonts.  Hence, some distributions
don't ship `xorg-fonts-misc` anymore.

Fixes https://github.com/xmonad/xmonad-contrib/issues/348
2021-03-24 12:29:18 +01:00
slotThe
b49ebdf2e0 X.L.Magnifier: Add magnifierczOff and magnifierczOff'
Instead of exporting the internal constructor, define a few more
functions for people who like their magnifier to start of in the Off
position.

Closes: https://github.com/xmonad/xmonad-contrib/issues/168
2021-03-24 10:08:10 +01:00
slotThe
5fbfcaada0 X.L.Magnifier: Implement magnifier['] in term of magnifiercz['] 2021-03-24 10:08:10 +01:00
Tomáš Janoušek
cd24f84774
Merge pull request #490 from liskin/pr/hacks-trayer
X.U.Hacks: Add "Stacking trays (trayer) above panels (xmobar)"
2021-03-23 21:55:19 +00:00
Tomáš Janoušek
06dafe3772
Merge pull request #492 from liskin/pr/managedocks-override-redirect
X.H.ManageDocks: React to strut updates of override_redirect docks
2021-03-23 21:55:07 +00:00
Tomas Janousek
ec14617123 X.H.ManageDocks: React to strut updates of override_redirect docks
We only requested PropertyChange events from docks in the `manageDocks`
manageHook, but that only gets called for normal windows, not
override_redirect ones. Therefore, xmobar in its default configuration
wouldn't get its struts refreshed on changes. This resulted in gaps not
updating after xmobar repositions itself on xrandr changes.

If one wanted to handle that repositioning in xmonad, it was possible to
configure xmobar with `overrideRedirect = False`, which is meant for
window managers with proper EWMH stacking order support [1], so in
xmonad it resulted in xmobar covering fullscreen windows. That can be
worked around by adding `checkDock --> doLower` to manageHook, but it
starts to smell of too many workarounds.

[1]: https://specifications.freedesktop.org/wm-spec/wm-spec-1.5.html#STACKINGORDER

The fix is to request PropertyChange events for all windows that we
treat as docks.

Related: https://github.com/xmonad/xmonad-contrib/pull/490
2021-03-23 14:24:30 +00:00
Tomas Janousek
88b9c80618 X.H.ManageDocks: Refactor strut cache
This is primarily a cleanup to make it easier to use `setDocksMask` from
the on-demand cache init (see further commits), but it makes the code
nicer:

- the logic to refresh and cache a strut is now concentrated in
  `updateStrut` instead of being spread over `updateStrutCache` and
  `docksEventHook`

- the logic to initialize the cache if not yet initialized is now
  concentrated in `maybeInitStrutCache` instead of being spread over
  `initStrutCache` and `getStrutCache`, so the dual-purpose return type
  of `getStrutCache` is no more

- the logic to detect changes and refresh is now always handled by
  `XS.modifiedM` instead of an additional `||`

Related: https://github.com/xmonad/xmonad-contrib/pull/406
2021-03-23 14:24:10 +00:00
Tomas Janousek
37fbf24ba7 X.U.ExtensibleState: Add modifiedM for effectful modifications 2021-03-23 14:23:55 +00:00
Tomas Janousek
04be5fc22e X.H.ManageDocks: Fix typo in deleteFromStructCache
Fixes: c48d81e37845 ("Fix caching issues in ManageDocks")
2021-03-23 14:22:36 +00:00
Tomas Janousek
74e55421d3 Update CHANGES 2021-03-23 14:15:34 +00:00
Tomas Janousek
6d42c540a5 X.U.Hacks: Add "Stacking trays (trayer) above panels (xmobar)" 2021-03-23 14:15:34 +00:00
slotThe
c3fa5138f9
Merge pull request #479 from slotThe/topic-history
X.A.TopicSpace: Deprecate internal history
2021-03-23 07:51:16 +01:00
Tomas Janousek
46f24bb27e X.A.TreeSelect: Fix swapped green/blue in foreground when using Xft
Closes: https://github.com/xmonad/xmonad-contrib/pull/486
Co-authored-by: Joan Milev <joantmilev@gmail.com>
2021-03-22 15:30:03 +00:00
Tomas Janousek
b6bd6f6d9d X.U.Hacks: Minor cleanup
Improve diffability of module exports; fix haddock.
2021-03-22 10:29:27 +00:00
slotThe
bebcb605a8
Merge pull request #185 from aplaice/master
Improve conversion of Char to KeySym in XMonad.Util.Paste
2021-03-22 07:35:33 +01:00
Tomáš Janoušek
0d93820160
Merge pull request #470 from liskin/pr/notifications-obscured-by-floats
Apply two xmonad core fixes to float moving/resizing in various contrib modules
2021-03-21 21:31:01 +00:00
slotThe
43d68bd451 Update CHANGES.md 2021-03-21 08:01:19 +01:00
slotThe
3c4f42d2da X.A.TopicSpace: More aggressively use X.H.WorkspaceHistory
Ever since ce5aae54035957846baa68f8980218cd11334722 TopicSpace uses the
history implementation of X.H.WorkspaceHistory instead of something
hand-rolled.  This, however, did not go far enough; at this point, we
can deprecate essentially all of TopicSpace's redundant history handling
and explicitly tell users to use the more modular X.H.WorkspaceHistory
instead.
2021-03-21 08:00:44 +01:00
slotThe
280c1a8ed5 X.H.WorkspaceHistory: Fix hlint nits, strictness
There is no reason why the used maps should not be strict, as we are
definitely traversing.
2021-03-21 08:00:44 +01:00
slotThe
62e9941d3d X.H.WorkspaceHistory: Add ability to exclude workspaces 2021-03-21 08:00:44 +01:00
Tomáš Janoušek
ab60361c5b
Merge pull request #487 from slotThe/old-time->time
Use time instead of old-time and old-locale
2021-03-21 00:02:12 +00:00
slotThe
e3a13a57e8
Merge pull request #471 from liskin/pr/spawnpipe-dynamiclog-encoding
Fix encoding issues in spawnPipe/dynamicLogString/xmonadPropLog
2021-03-20 18:18:35 +01:00
Tomas Janousek
63e31ccd8d X.H.DynamicLog: Move UTF8 encoding from dynamicLogString to xmonadPropLog'
For many (10+) years, we had a cascade of ugly workarounds:

 * X.U.Run.spawnPipe returned a binary handle, so the String passed to
   it must have been encoded by C.B.UTF8.String.encodeString

 * X.H.DynamicLog.dynamicLogString therefore returned such an encoded
   String, so one could use it directly in a hPutStrLn, but literal
   Strings wouldn't work

 * xmonadPropLog' also expected an encoded String to make it easier to
   use together with dynamicLogString, again breaking usage with String
   literals and other normal unicode Strings

Then in 1d0eaddc2530 Sibi fixed spawnPipe to return a handle usable with
normal Strings, which then obviously broke the entire cascade. But,
instead of using the opportunity to remove all the ugly workarounds, he
decided to add some more on top, so now spawnPipe with dynamicLogString
outputs doubly encoded UTF-8 and xmobar has a hack to strip this double
encoding (https://github.com/jaor/xmobar/pull/482), which only works
when XFT is in use and breaks on some long unicode codepoints. :-(

There is a better way: make everything just use normal Strings and only
encode when it goes out the wire. This means dynamicLogString can be
freely mixed with String literals, manual uses of xmonadPropLog' don't
need encodeString, and everything just works nicely.

This obviously breaks configs that used some of these pieces in
isolation (like mine), but that's a small price to pay. After all, right
now all users of spawnPipe/dynamicLogString are getting doubly encoded
UTF-8 which might or might not work in xmobar and probably breaks
horribly everywhere else, so this fix should be a clear improvement. :-)

Fixes: 1d0eaddc2530 ("Make spawnPipe to use system's locale encoding")
Fixes: https://github.com/xmonad/xmonad-contrib/issues/377
Fixes: https://github.com/jaor/xmobar/issues/476
Related: https://github.com/xmonad/xmonad-contrib/pull/334
Related: https://github.com/jaor/xmobar/pull/482
2021-03-20 18:11:33 +01:00
Tomas Janousek
21fb9dfc43 X.U.Run: Clean up spawnPipes a bit
This makes it easier to see the differences between these functions,
makes it less likely someone will change one and not the others, etc.
More importantly, the documentation doesn't contain circular references
any more. :-)

Also, let's just use hSetEncoding. The concern of this being stateful
and theoretically having something written in the wrong encoding is
pointless: nobody has the handle until we return it from `spawnPipe'`.

(This also means that spawnPipeWithNoEncoding is now a text handle that
possibly does newline translation, just with char8 encoding. There
should be no difference in practice.)

Fixes: 8b2bd3ae5cd1 ("Add new variants of spawnPipe functions with encoding support")
2021-03-20 18:11:33 +01:00
slotThe
d32febd60d
Merge pull request #392 from wygulmage/nix
Add nix packages to stack.yaml.
2021-03-20 16:53:01 +01:00
Keith
d05b934cbf Add nix packages to stack.yaml. 2021-03-20 16:46:17 +01:00
slotThe
cf9388a918
Merge pull request #481 from liskin/pr/pp-composable-rename
Extend PP with ppRename: nicer compose of WorkspaceNames, ClickableWorkspaces, …
2021-03-20 16:32:57 +01:00
slotThe
94f1e943d4 Use time instead of old-time and old-locale
Get rid of these deprecated libraries, as the new `time' library
provides a strict superset of the functionality of `old-time' and
`old-locale'.
2021-03-20 16:14:26 +01:00
slotThe
f1bd315448
Merge pull request #484 from ulrikdem/max-compl-columns
X.Prompt: Add maxComplColumns field to XPConfig
2021-03-20 08:03:22 +01:00
Tomas Janousek
dbaf0e60ce Merge branch 'AusCyberman/master' 2021-03-19 17:05:30 +00:00
Tomas Janousek
b0f5c69baf X.U.ClickableWorkspaces: Drop escaping from clickableWrap
This breaks putting <fn> tags and icons into workspace names, which some
people might like. Those few who generate workspace names dynamically
from window titles may (and should) escape it themselves.
2021-03-18 22:17:19 +00:00
Ulrik de Muelenaere
577fd81450 X.Prompt: Add maxComplColumns field to XPConfig
This allows limiting the number of columns in the completion window. The
window width is divided equally between the columns.
2021-03-18 23:09:00 +02:00
Tomáš Janoušek
fcbccc1df2
Merge pull request #480 from slotThe/prompt.pass
X.P.Pass: Update Documentation
2021-03-17 16:47:30 +00:00
Tomas Janousek
7dbedb17d6 Merge branch 'antoniotrkdz/mate-main-menu' 2021-03-17 12:04:09 +00:00
Tomas Janousek
47a0f17230 Update CHANGES 2021-03-17 12:02:45 +00:00
antoniotrkdz
670124e309 X.C.Mate: Add Main Menu keybinding
Now it is possible to use mod+d to open the Mate Main Menu.
2021-03-17 12:01:08 +00:00
Tomas Janousek
e91b0fef82 X.A.WorkspaceNames, X.L.IndependentScreens, X.U.ClickableWorkspaces: Use ppRename
Also, drop now useless integrations from X.U.ClickableWorkspaces:
workspaceNamesPP, marshallPP and clickablePP can now be composed
directly using >>= and it just works.

Related: https://github.com/xmonad/xmonad-contrib/pull/390
Related: https://github.com/xmonad/xmonad-contrib/pull/462
2021-03-17 11:53:44 +00:00
slotThe
cb86dd3c61 Fix inconsistency in CHANGES.md 2021-03-17 09:54:15 +01:00
Joan MIlev
d9a7f4388a
Add fullscreenSupportBorder (#476)
Add fullscreenSupportBorder for autohiding window borders
2021-03-17 09:50:16 +01:00
Tomas Janousek
be963c0e93 X.H.ManageHelpers: Fix trailing whitespace 2021-03-16 20:24:33 +00:00
Tomas Janousek
91010f6eb9 X.H.DynamicLog: Add ppRename (composable tag augmentation)
This one is a Reader in WindowSpace, and therefore significantly
simplifies the composition of WorkspaceNames, IndependentScreens,
ClickableWorkspaces and possibly other similar modules.

Related: https://github.com/xmonad/xmonad-contrib/pull/390
Related: https://github.com/xmonad/xmonad-contrib/pull/462
2021-03-16 18:45:19 +00:00
Tomas Janousek
fc7ea97582 X.H.DynamicLog: Reindent pprWindowSet 2021-03-16 18:23:28 +00:00
slotThe
c8de3b92af X.P.Pass: Update documentation 2021-03-16 14:13:24 +01:00
slotThe
90974fd820 X.L.Magnifier: Update screenshot 2021-03-16 10:36:25 +01:00
Tomáš Janoušek
62d65d3cdd
Merge pull request #459 from slotThe/prompt-spaces
X.Prompt: Correct tab completion handling
2021-03-15 18:33:04 +01:00
AusCyber
feb9306222 Added Dynamic Icon Support
Created a separate module DynamicIcons
2021-03-12 11:46:54 +00:00
Tomas Janousek
8a0151fe77 X.U.ClickableWorkspaces: Drop obsolete doc reference 2021-03-12 11:46:23 +00:00
Tomas Janousek
690e928a1c Merge branch 'pr/trackfloating' 2021-03-12 11:17:57 +00:00
Tomas Janousek
3df6d2af01 CHANGES: Fix whitespace
Fixes: 2e2d344d9254 ("X.C.Mate: logout, shutdown options (#475)")
2021-03-12 11:16:14 +00:00
Tomas Janousek
652dd03319 Merge branch 'pr/servermode' 2021-03-12 11:15:32 +00:00
Tomas Janousek
60bf7a4d42 Merge branch 'pr/urgencyhook' 2021-03-12 11:04:33 +00:00
Tomáš Janoušek
c826d068bc
Merge pull request #473 from mflav/master
X.H.ManageHelpers: Add shiftToSame, clientLeader
2021-03-12 11:18:19 +01:00
Matthew Flavin
e38274e05c X.H.ManageHelpers: Revised documentation for new sameBy and shiftToSame functions 2021-03-11 22:51:09 -05:00
brandon s allbery kf8nh
2e2d344d92
X.C.Mate: logout, shutdown options (#475)
* New logout options

Factor out Mate logout action and add a shutdown action which the user can bind additionally or in its place.

* Add documentation

* Update CHANGES.md
2021-03-11 22:29:50 +01:00
Tomas Janousek
9f6c829c94 Update CHANGES (X.H.ManageHelpers) 2021-03-10 00:24:34 +00:00
Tomas Janousek
2bec3175cc X.H.ManageHelpers: Generalize shiftByLeader to shiftToSame (supports pid as well) 2021-03-10 00:15:02 +00:00
Tomas Janousek
c7e9d914e1 X.H.ManageHelpers: Simplify shiftToLeader implementation
Short-circuiting the search isn't worth the code complexity, so just
search for all windows with the same leader and then pick the first one
using `listToMaybe` and pass that to `doShiftTo`.

Also, rename to `shiftByLeader` because we aren't really shifting to the
leader itself. We just shift to another window that has the same leader.
2021-03-09 23:40:20 +00:00
Tomas Janousek
289c7e433a X.H.ManageHelpers: Factor doShiftTo out of transience and switch to W.shiftWin
Will be useful for shiftToLeader.

Use W.shiftWin instead of W.shift as it isn't guaranteed that the window
being managed by the ManageHook is still in focus.
2021-03-09 23:27:14 +00:00
Matthew Flavin
8202594b1d Added leader functions 2021-03-08 14:52:01 -05:00
Tomas Janousek
9451d81427 Apply two xmonad core fixes to float moving/resizing in various contrib modules
This applies fixes from
4565e2c90e
and
b9ce5b034b.

tl;dr:
When dragging, refloat and refresh to fix https://github.com/xmonad/xmonad/issues/63.
When starting dragging, raising the window is then unnecessary, and
removing it fixes https://github.com/xmonad/xmonad/issues/208.
Also remove unnecessary raises for keyboard moving/resizing which always
refloated the window.

Fixes: https://github.com/xmonad/xmonad/issues/63
Fixes: https://github.com/xmonad/xmonad/issues/208
2021-02-16 12:23:28 +00:00
Tomas Janousek
3d6844c65f Update CHANGES 2021-02-15 17:58:26 +00:00
Tomas Janousek
1b327a059a X.H.UrgencyHook: Generalize filterUrgencyHook to Query Bool 2021-02-15 17:58:21 +00:00
Tomas Janousek
d49f7a49a2 X.H.ManageHelpers: Add windowTag
Not useful in a manageHook, but useful when a Query is used to select an
existing managed window.
2021-02-15 17:58:15 +00:00
Tomas Janousek
43592c84d4 X.L.TrackFloating: Fix changing focus on inactive workspaces
When focus changes¹ on an inactive workspace (not `current`, but
`visible`), TrackFloating and UseTransientFor would think they should
use the remembered focus point as they look at the wrong (`current`)
workspace instead of the workspace they're supposed to layout, and so
focus seems to be out of their set of windows, when actually it is not.

Fix this by looking at the correct workspace.

¹) This isn't entirely straightforward, as there are normally no
   keybindings or StackSet operations for this, but it's perfectly legal
   to `W.view` the inactive workspace, change focus, and `W.view` back
   in a single `windows` action.
2021-02-15 17:25:48 +00:00
Tomas Janousek
9e6e521fbb X.H.UrgencyHook: Cleanup stale urgents in startupHook (small memleak workaround)
If a manually crafted ClientMessageEvent with invalid (nonexistent)
ev_window is sent to xmonad (by sending it to the root window), the
nonexistent window is added to Urgents and stays there forever.

This can also happen when a window in Urgents disappears while xmonad is
restarting, in which case xmonad never sees the DestroyWindowEvent and
never gets to remove the window from Urgents.

As both of these are fairly unlikely, only do the cleanup in
startupHook to not waste cycles.
2021-02-15 12:17:57 +00:00
Tomas Janousek
13f21f4704 X.H.UrgencyHook: Export clearUrgents'
This makes it possible to clear urgency of selected windows only, which
may be useful to some users (like me).
2021-02-15 12:17:57 +00:00
Tomas Janousek
101d6e89bd X.H.UrgencyHook: Clear EWMH urgency in clearUrgents and filterUrgencyHook
The EWMH support added in 7e9c986217cf only added handling of
_NET_WM_STATE_DEMANDS_ATTENTION to handleEvent and cleanupUrgents, but
manual urgency clearing via clearUrgents or automatic urgency clearing
via filterUrgencyHook was left without EWMH support. This commit adds
the missing pieces.

Fixes: 7e9c986217cf ("Add EWMH DEMANDS_ATTENTION support to UrgencyHook.")
2021-02-15 12:17:57 +00:00
Tomas Janousek
90737d6d03 X.H.UrgencyHook: Drop $note (obsolete for 12 years)
The note doesn't apply since 9a7dcbbabb21 ("Adjustments to use the new
event hook feature instead of Hooks.EventHook").
2021-02-15 12:17:57 +00:00
Tomas Janousek
b24a88a3a3 Update CHANGES 2021-02-15 11:49:00 +00:00
Tomas Janousek
fc60ccb1fb scripts: Make scripts executable and add #!runhaskell to xmonad{ctl,propread} 2021-02-15 11:42:23 +00:00
Tomas Janousek
52717dd5fb X.H.ServerMode: Only read the first ClientMessage data item
Atoms are at most 32-bit even on 64-bit platforms, per the X protocol,
despite them being stored in a CLong. Even if they weren't (and they
are, see /usr/include/X11/Xproto.h and
https://stackoverflow.com/a/23265984/3407728), xmonadctl isn't unpacking
the CLong into multiple data items.
2021-02-15 11:42:23 +00:00
Tomas Janousek
d70128418b xmonadctl: Tidy help a bit 2021-02-15 11:42:23 +00:00
Tomas Janousek
eb752b15d8 Pass 0 to setClientMessageEvent where appropriate
Stop pretending it has anything to do with time, it's zero, and it's not
being read anywhere, we're passing the parameter only because
setClientMessageEvent needs one. We should switch to
setClientMessageEvent' and pass no data, but that would move the X11
dependency lower bound.
2021-02-15 11:42:23 +00:00
Tomas Janousek
a7bb1a776a X.H.ServerMode: Move xmonadctl source code to scripts/
Makes it easier to build and maintain.
2021-02-15 11:42:23 +00:00
Tomas Janousek
ebf9561d76 scripts/xmonadpropread: Print current property value at start
It was only printed after the first change.
2021-02-11 21:24:08 +00:00
Tomas Janousek
f2993f5a25 X.D.Extending: Fix typo 2021-02-11 15:53:19 +00:00
Tomas Janousek
ccebeb675d scripts/xmonadpropread: Document and support custom props 2021-02-11 15:53:17 +00:00
Tomáš Janoušek
cdc6c6d39c
Merge pull request #443 from TheMC47/refactor-dynamic-log
Refactor X.H.DynamicLog and multiple loggers support
2021-02-10 22:16:14 +01:00
Yecine Megdiche
44c575930a Added StatusBarConfig and multiple loggers support
- StatusBarConfig serves as an abstraction over status bars. This
enables users to customize their status bars without having to do
the plumbing themselves.
- Multiple status bars can be used directly thanks to the
StatusBarConfig, which provides a way to compose status bars
2021-02-10 21:05:23 +00:00
Tomáš Janoušek
b63eb1c283
Merge pull request #464 from TheMC47/java-hack
X.U.Hacks: Add javaHack
2021-02-10 13:05:37 +01:00
Yecine Megdiche
c3e5c1a9aa Added javaHack
Fixes Java applications that don't work well with xmonad, by setting @_JAVA_AWT_WM_NONREPARENTING=1@
2021-02-08 17:30:13 +01:00
Tomáš Janoušek
747202a214
Merge pull request #462 from liskin/pr/clickable
X.U.ClickableWorkspaces: Integrations with X.L.IndependentScreens and X.A.WorkspaceNames
2021-02-04 20:56:06 +01:00
Tomáš Janoušek
39a9c041c5
Merge pull request #458 from liskin/pr/dolower-doraise
X.H.ManageHelpers: Add doLower, doRaise
2021-02-04 17:18:40 +01:00
Tomas Janousek
3876f2fc86 X.H.ManageHelpers: Add doLower, doRaise
I need this in my config and I've seen it being useful for others on
Reddit and IRC.
2021-02-04 16:03:05 +00:00
Tomas Janousek
18c5498aeb X.U.ClickableWorkspaces: Improve docs a bit 2021-02-04 16:01:19 +00:00
Tomas Janousek
30d6d7ed4c X.L.IndependentScreens: Use the unmarshallW abstraction where appropriate 2021-02-04 16:01:19 +00:00
Tomas Janousek
c37737bf73 Add missing ppVisibleNoWindows to workspaceNamesPP, marshallPP, clickableRenamedPP
The ppVisibleNoWindows was added in #241 but none of the modules that
rename/mangle workspace names were updated (or didn't exist at the
time). This fixes this.

Related: https://github.com/xmonad/xmonad-contrib/pull/241
Related: 670eb3bc605b ("Added pretty printer for empty visible workspaces")
2021-02-04 16:01:19 +00:00
Tomas Janousek
c6b4e69f39 X.U.ClickableWorkspaces: Add integrations with X.L.IndependentScreens and X.A.WorkspaceNames
Having these work together isn't entirely trivial so let's provide the
integrations.

Related: https://github.com/xmonad/xmonad-contrib/pull/390
2021-02-04 16:01:19 +00:00
Tomas Janousek
5990456cc9 X.U.ClickableWorkspaces: Use xdotool instead of the unmaintained wmctrl
The last release of wmctrl was in 2005 and it doesn't correctly set
source indication in _NET_ACTIVE_WINDOW client messages
(https://specifications.freedesktop.org/wm-spec/wm-spec-1.3.html#sourceindication),
which is obviously completely irrelevant here, but if one decides to
implement clickableWrap for switching windows as well (like I did), it's
nice to use the same tool for it.

It's also nice to use a tool that compiles and runs on 64-bit
architectures without having to patch it (taken care of by distros,
though). :-)
2021-02-04 16:01:19 +00:00
slotThe
00a6e4839a Update CHANGES.md 2021-02-04 15:29:18 +01:00
slotThe
ee4a3a932d XMonad.Prompt: Fix alwaysHighlight tab-completion
526336ecec98aa2fe1cc98521473372b0664e19d introduced a bug where
tab-completion has an issue when a completion contains spaces; it only
deletes the last word of that completion, causing the next TAB to again
select the current selection and add it to the command.  In this way,
the prompt can get "stuck" on an item, endlessly adding all but the
first word to the command every time TAB is pressed.

C.f. xmonad/xmonad-contrib/issues/455
2021-02-04 10:16:09 +01:00
slotThe
0a2e1f7254 XMonad.Prompt: hlint nits 2021-02-04 10:16:09 +01:00
slotThe
f2cfaa3398 Safe indexing in 'highlightedItem'
Just because there are some completions doesn't mean that the given
index may not still be too big.

Incidentally, this now allows every prompt to cycle through its items in
a nice way.
2021-02-04 10:16:09 +01:00
slotThe
4eec511eb8
Merge pull request #461 from slotThe/changes-cleanup
Clean up and unify CHANGES.md
2021-02-04 09:04:11 +00:00
slotThe
db972afbc6 Clean up and unify CHANGES.md 2021-02-03 08:04:22 +01:00
slotThe
b13447b361
Merge pull request #448 from TheMC47/more-loggers
More loggers: A `maybe`-like combinator, and screen-specific loggers
2021-01-30 20:22:51 +00:00
Tomáš Janoušek
f42989112c
Merge pull request #457 from slotThe/issue-template
Add "Steps to Reproduce" to ISSUE_TEMPLATE.md
2021-01-30 17:42:20 +01:00
slotThe
3c7ec6343a Add "Steps to Reproduce" to ISSUE_TEMPLATE.md 2021-01-30 16:40:46 +01:00
Yecine Megdiche
32ffca599e Added more loggers
- `logWhenActive` to have loggers active only when a certain screen is
active.
- `logTitleOnScreen`, `logCurrentOnScreen` and `logLayoutOnScreen` as
screen-specific variants of `logTitle`, `logCurrent`, `logLayout`
- `logConst` to log a constant `String`
- `logMaybe` and `.|` to combine loggers.
2021-01-30 15:29:51 +01:00
Tomáš Janoušek
2eb67ed341
Merge pull request #418 from liskin/trackfloating-focustracking
X.L.TrackFloating: Clean up and simplify
2021-01-30 12:53:09 +01:00
Tomáš Janoušek
c3c0d38b26
Merge pull request #397 from liskin/purex-focusnth
X.U.PureX: Add focusWindow and focusNth
2021-01-30 12:46:29 +01:00
Tomáš Janoušek
000590fa62
Merge pull request #453 from slotThe/default->def
Remove last occurences of non Data.Default defaults
2021-01-28 21:48:25 +01:00
slotThe
227a3e0aa5 X.A.TreeSelect: Deprecate tsDefaultConfig
Replace with Data.Default.def, as already happened a while ago (in
0f1b6fb7726fc54b0ef318143ab2ffc43faed8fa) in all other modules.
2021-01-28 21:39:45 +01:00
slotThe
e83081b6ef Remove mentions of defaultConfig
These were superseded, but forgotten to be updated, by Data.Default.def
in 5140f5b5d06790e055eb7fb0cf3eccc4997aa736.
2021-01-28 21:36:48 +01:00
Tomáš Janoušek
444bdc09f0
Merge pull request #440 from liskin/pr/borders
X.L.NoBorders: Fix float handling on multihead setups
2021-01-27 22:29:28 +01:00
Tomas Janousek
48156cafb8 X.L.NoBorders: Add unit test for multihead floats 2021-01-27 20:14:17 +00:00
Tomas Janousek
9cff824a24 X.L.NoBorders: Fix float handling on multihead setups
Before c6cdb77e3b3d6a3842b914a0cf64357f03fcf0c1, handling of floats was
trivial (too trivial, and thus inefficient and flickery): any float
whose rectangle covered (RationalRect 0 0 1 1), regardless of what
screen or workspace it belonged to, got its borders hidden.

Then c6cdb77e3b3d6a3842b914a0cf64357f03fcf0c1 added some nuance
(OnlyLayoutFloatBelow, OnlyLayoutFloat, OnlyScreenFloat) which requires
looking at floats in the context of individual screens. Unfortunately
the implementation only worked in singlehead setups, as it always used
only the active screen/workspace regardless of which screen/workspace
was currently being layouted. This resulted in the new functionality not
working correctly on inactive screens and also regressed the handling of
fullscreen floats on inactive screens.

The fix is conceptually easy: use the screen that is being layouted.

There is a catch, unfortunately: this code runs in redoLayout, but the
information we need is only available in modifyLayout and
modifyLayoutWithUpdate. I could store a screen id in the
ConfigurableBorder record in modifyLayoutWithUpdate and use it later in
redoLayout, but that'd be a massive hack, so what I do instead is to
find the relevant screen by searching for one that covers the `lr`
(layout/screen rectangle). In most setups, this should be reliable. If
it turns out it is not, we can fix this later.

Fixes: c6cdb77e3b3d ("'XMonad.Layout.NoBorders': various improvements:")
Fixes: https://github.com/xmonad/xmonad-contrib/issues/280
2021-01-27 20:14:08 +00:00
Tomas Janousek
a98cc194ad X.L.NoBorders: Fix docs of data Ambiguity
In c6cdb77e3b3d6a3842b914a0cf64357f03fcf0c1, several new constructors
were added but not "In order of increasing ambiguity (less borders more
frequently)" as the docs for data Ambiguity say. Correct the order and
clarify that Never only considers ambiguity of tiled windows (as in the
doc for smartBorders).

Fixes: c6cdb77e3b3d ("'XMonad.Layout.NoBorders': various improvements:")
Related: https://github.com/xmonad/xmonad-contrib/issues/280
2021-01-27 20:13:49 +00:00
Tomáš Janoušek
081629d39f
Merge pull request #451 from liskin/pr/ci
ci: Maintenance
2021-01-27 21:12:03 +01:00
Tomáš Janoušek
627e203bcf
Merge pull request #452 from liskin/pr/hspec
tests: Use hspec as test driver (prep for #407 #430 #440 unit tests); speed up
2021-01-27 21:05:49 +01:00
Tomáš Janoušek
94670a72be
Merge pull request #447 from slotThe/grab-pointer
Grab the Pointer in X.Prompt and X.A.TreeSelect
2021-01-27 17:43:42 +01:00
slotThe
6d1f34cf18 Update CHANGES.md 2021-01-27 16:37:59 +01:00
slotThe
c59805636d XMonad.Action.TreeSelect: Allow Pointer Events
If this is not done, trying to select another window with the mouse when
the treeselect window is up, the X server executes a pointer/keyboard
grab until `allowEvents' is called; which it never is and so both remain
frozen indefinitely.

C.f.:
  - xmonad/xmonad/issues/116
  - xmonad/xmonad-contrib/issues/445
2021-01-27 16:37:59 +01:00
slotThe
08a165df40 XMonad.Prompt: Allow Pointer Events
If this is not done, trying to select another window with the mouse when
the prompt is up, the X server executes a pointer/keyboard grab until
`allowEvents' is called; which it never is and so both remain frozen
indefinitely.

C.f.:
  - xmonad/xmonad/issues/116
  - xmonad/xmonad-contrib/issues/445
2021-01-27 08:30:41 +01:00
Tomas Janousek
6179ed9dbe X.L.LimitWindows: Silence duplicate export warnings in tests 2021-01-26 22:21:20 +00:00
Tomas Janousek
2691e3a490 X.A.GridSelect: Use OVERLAPPABLE, seems to help with unnecessary recompiles
Without this, any change to tests triggers a recompile of GridSelect
when invoking "stack test", adding a couple seconds. This seems to help.
2021-01-26 13:43:35 +00:00
Tomas Janousek
5c7e1194d0 ci: Drop some unnecessary build deps from tests (stack) workflow
Consistency with the other workflow…
2021-01-25 22:34:28 +00:00
Tomas Janousek
42771e4658 ci: Run tests (stack) workflow in all branches
Consistency with haskell-ci (cabal) workflow. It's nice to see the
results before opening a PR so that one doesn't need to embarrass
themselves.
2021-01-25 22:34:28 +00:00
Tomas Janousek
d4d78abc4a ci: Minor cleanup
* split into buildenv deps and stack build
* make the deps list more git-friendly
* use stack from github environment (I've seen the curl fail intermittently)
* indent consistency
2021-01-25 22:34:28 +00:00
Tomas Janousek
55747ecced ci: Add lts-17 and nightly 2021-01-25 22:34:28 +00:00
Tomas Janousek
245dac496b tests: Speed up by producing less discarded tests in SwapWorkspaces 2021-01-25 22:14:47 +00:00
Tomas Janousek
cd5b1a1015 tests: Use hspec as test driver
My main motivation here is that I'd like to add some unit tests (as
opposed to testing everything using QuickCheck properties), but there
are other benefits: it's now easier to run a subset of tests -- the
command-line interface is more powerful.

Also, rename the test-suite to "tests" as it's no longer limited to
properties.
2021-01-25 22:14:47 +00:00
Tomas Janousek
320fe8c537 tests: Clean up test-suite in cabal
* silence warnings about unlisted modules
* remove xmonad-contrib dependency to make it unambiguous that modules
  are recompiled with -DTESTING, not taken from the library
* sort build-depends
2021-01-25 22:14:47 +00:00
Tomáš Janoušek
b8ac9804fc
Merge pull request #449 from TheMC47/cleanup-dynamic-log
Cleanup: XMonad.Hooks.DynamicLog
2021-01-24 17:32:21 +01:00
Yecine Megdiche
67341e30a2 Cleanup: hlint hints 2021-01-24 17:20:50 +01:00
Tomáš Janoušek
3e6f0f9f51
Merge pull request #406 from liskin/managedocks-cache-on-demand
X.H.ManageDocks: Init strut cache on demand if necessary
2021-01-24 16:43:56 +01:00
Peter Simons
8b50ee5c9b
Merge pull request #446 from xmonad/t/haskell-ci
Generate CI with the haskell-ci utility.
2021-01-19 21:05:31 +01:00
Peter Simons
14393a2cf9 Add haskell-ci generated Github actions. 2021-01-19 20:55:56 +01:00
Peter Simons
96e3f00a1f xmonad-contrib.cabal: update the list of supported compilers 2021-01-19 20:55:29 +01:00
Tomáš Janoušek
03650d5d3f
Merge pull request #444 from slotThe/exception-extensible
Control.Exception.Extensible -> Control.Exception
2021-01-17 20:35:38 +01:00
slotThe
77b047316c Control.Exception.Extensible -> Control.Exception
According to its documentation[1], this module simply re-exports
Control.Exception on recent GHC versions.  As we only support recent
versions, this import is unnecessary.

[1] http://hackage.haskell.org/package/extensible-exceptions-0.1.1.4/docs/Control-Exception-Extensible.html
2021-01-12 11:13:29 +01:00
slotThe
0a44981d0f
Merge pull request #442 from slotThe/prompt-ah-history
X.Prompt: Correctly Update History with alwaysHighlight
2021-01-11 15:10:26 +00:00
slotThe
b3316c2e34 Update CHANGES.md 2021-01-08 17:15:31 +01:00
slotThe
404b3f59b4 X.Prompt: correctly update history
So far, when `alwaysHighlight' was enabled and the user selected an item
while not having completely written it out in the prompt, the input
string and not the eventual completion string would be entered into the
prompt history, which is obviously not the desired behaviour.  This can
cause the history to clutter up with all these abbreviations, making
subsequent invocations of the prompt tedious to work with.

For example, an input of "xm" would narrow to both "xmonad" and
"xmobar", but thanks to `alwaysHighlight' "xmobar" was selected.  If the
user now pressed enter, the prompt would correctly return "xmobar" as
the string to act upon, but "xm" would be entered into the prompt
history!
2021-01-08 17:08:53 +01:00
Tomáš Janoušek
d0813f0b3a
Merge pull request #441 from slotThe/xdg-mess
Revise XDG handling
2021-01-07 19:52:23 +01:00
slotThe
c39a5cf618 Update CHANGES.md 2021-01-07 15:23:54 +01:00
slotThe
9d520dc880 X.Prompt: X constraint for historyCompletion[P]
This is needed because the cache directory is now a part of XConf, which
is calculated once on startup and hence any recalculation would be
fragile.

Some internal functions that are not exposed (like writeHistory) were
also changed to accept that directory as an argument.
2021-01-07 10:33:47 +01:00
slotThe
3213925b6b X.H.Script: Add X constraint 2021-01-07 10:33:47 +01:00
slotThe
9fe3444374
Merge pull request #437 from slotThe/ppTitleUnfocused
X.H.DynamicLog: Add ppTitleUnfocused
2021-01-07 09:31:57 +00:00
slotThe
e06eafbadd Update CHANGES.md 2021-01-07 10:23:53 +01:00
slotThe
a3e06685ef X.H.DynamicLog: Add ppTitleUnfocused 2021-01-07 10:23:53 +01:00
slotThe
0313b26cd8
Merge pull request #403 from elkowar/fullscreen-fix
Add new module XMonad.Util.Hacks (formerly XMonad.Hooks.WindowedFullscreenFix)
2021-01-07 09:22:49 +00:00
slotThe
ba94d48464
Merge pull request #170 from mavant/issue/164
Only modify the last word during tab completion
2021-01-04 13:01:26 +00:00
slotThe
526336ecec Only modify the last word during tab completion
Fixes #164.

It's not clear to me why these functions take in XPState as a param only
to then produce some XP () values. It seems like they could just as well
call `get`.
2021-01-04 10:17:28 +01:00
slotThe
f9a226e75a
Merge pull request #439 from TheMC47/cleanupStatusBars-startup
Add cleanupStatusBars to statusBarPropTo
2021-01-02 10:07:26 +00:00
Yecine Megdiche
6c83af1c69 Added cleanupStatusBars to the startup-hook 2021-01-01 21:08:51 +01:00
elkowar
71863c735a Fix documentation issues and add gifs 2021-01-01 16:37:49 +01:00
elkowar
d293a053e1 Fix typo and remove +1 from resizeWindow 2021-01-01 14:40:33 +01:00
elkowar
b41a5a50e9 Move module to new module XMonad.Util.Hacks 2021-01-01 13:15:18 +01:00
elkowar
3d553ad5e0 Add new module XMonad.Hooks.WindowedFullscreenFix 2021-01-01 13:14:05 +01:00
Tomáš Janoušek
b963c3cf9d
Merge pull request #434 from TheMC47/restart-docks
Restarting status bars on restart
2020-12-30 09:57:01 +01:00
Yecine Megdiche
78df487e4c Added spawnStatusBarAndRemember and cleanupStatusBars
In order to effectively restart status bars without relying
on pipes, spawnStatusBarAndRemember saves the PID of status
bars to kill them with cleanupStatusBars.

Removed checking for docks

Cleaned imports

Use signalProcesGroup instead of inverting the PID

Updated the documentation

Updated the documentation
2020-12-29 21:45:33 +01:00
slotThe
63a3282133
Merge pull request #428 from pshevtsov/lxqt-config
Add XMonad.Config.LXQt
2020-12-29 20:13:05 +00:00
Petr Shevtsov
2809ed105e Add new module XMonad.Config.LXQt 2020-12-29 21:39:02 +03:00
slotThe
ef3697c09c
Merge pull request #427 from slotThe/fix-fadewindows
Fix Documentation in X.H.FadeWindows
2020-12-29 17:37:27 +00:00
Tomas Janousek
555cd7c596 X.H.DynamicLog: Minor doc tweaks 2020-12-19 18:27:19 +00:00
Sibi Prabakaran
cff344811f
Merge pull request #408 from slotThe/dynamic-log
X.H.DynamicLog: Start recommending poperty-based logging
2020-12-19 18:46:46 +05:30
Tomáš Janoušek
88ddd54084
Merge pull request #435 from wz1000/master
Export modifyProject in XMonad.Actions.DynamicProjects
2020-12-19 11:32:08 +00:00
Zubin Duggal
c66345467e
Export modifyProject 2020-12-19 16:42:20 +05:30
slotThe
06af11a463 Update CHANGES.md 2020-12-18 21:10:44 +01:00
slotThe
6977d0cdfb X.H.DynamicLog: Update documentation
Stop recommending pipes as the best/first thing to do and instead
recommend property based logging for all bars that support it.  Also
strongly recommend users to use the already pre-made functions that do
all of the plumbing.

Add comments for the arguments of the most important user-facing
functions.
2020-12-18 21:10:44 +01:00
slotThe
9b6c098c9c Add xmobarProp, statusBarProp, and statusBarPropTo
In an effort to modernize XMonad.Hooks.DynamicLog (and thus to stop
recommending pipes as the best way to interface with xmobar), implement
property log based solutions for the most important functions.  Sadly
dzen does not seem to support this kind of interfacing with xmonad.

The descriptions of xmobar, statusBar, and statusBar' have been updated
to reflect that they should be seen as secondary choices.
2020-12-18 13:54:22 +01:00
Tomas Janousek
35e794b1b2 Minor cleanup of CI 2020-12-16 11:22:41 +00:00
Sibi Prabakaran
8648ea790a
Merge pull request #432 from slotThe/unused-imports
Get rid of unused imports
2020-12-16 10:32:43 +05:30
slotThe
0490e77970 Fix Documentation in X.H.FadeWindows 2020-12-15 17:23:35 +01:00
slotThe
d6cc525500 X.H.FadeWindows: Default to opacity 1 2020-12-15 17:22:18 +01:00
slotThe
53903b086f Conditionally error on unused imports
This turns off the warnings about unused imports _unless_ one is using
the oldest supported version of GHC (right now that's 8.4.4 or older);
then it turns them into errors!  This prevents xmonad from emitting
warnings about imports that have to be there due to backwards
compatibility, but are obsolete in newer versions (think MFP), while at
the same time preventing bitrot.
2020-12-14 14:04:57 +01:00
slotThe
6715c75c50 Drop old versions of GHC
Removes references to all versions of GHC that are not part of the CI,
as these can't be guaranteed to be built against master every time
2020-12-14 14:04:19 +01:00
slotThe
78d526d1dd Get rid of unused imports
Starting with 5240116f3cdf169e3aa226d9f8206a5f5b99c867 we only support
GHC versions 8.4.4 and up (more precisely, the GHC version associated
with stackage lts-12 and up).  The imports in question are now in
Prelude and need not be imported explicitly.
2020-12-14 13:41:28 +01:00
Sibi Prabakaran
5240116f3c
Add CI workflow against xmonad latest commit (#429) 2020-12-14 17:22:01 +05:30
Tomas Janousek
89646d75fd X.H.DynamicLog: Add shorten' and shortenLeft' (customizable end) 2020-12-13 21:38:35 +00:00
Petr Shevtsov
5e0ef3777a Update CHANGES.md 2020-12-12 21:39:53 +03:00
Petr Shevtsov
69c1821818 Initial commit 2020-12-12 21:35:36 +03:00
Tomáš Janoušek
27f03ad9c5
Merge pull request #426 from pshevtsov/patch-1
Use the default XFCE terminal with `XMonad.Config.Xfce`
2020-12-12 00:33:22 +00:00
Tomáš Janoušek
bd9a79cb80
Merge pull request #421 from slotThe/filterOutWsPP
Add filterOutWs[PP]
2020-12-11 17:58:16 +00:00
slotThe
e956fbf3ce Update CHANGES 2020-12-11 18:54:11 +01:00
slotThe
6087bdd40d Deprecate namedScratchpadFilterOutWorkspace[PP]
These were superseded by more generic function in
XMonad.Hooks.DynamicLog.
2020-12-11 18:54:11 +01:00
slotThe
d3f11d041a Export scratchpadWorkspaceTag
Users are now able to use this, instead of hard-coding the "NSP" name in
their configurations
2020-12-11 18:54:11 +01:00
slotThe
0cbee237c7 Add filterOutWs and filterOutWsPP
These are more generic versions of the respective functions in
XMonad.Util.NamedScratchpad.
2020-12-11 18:54:11 +01:00
Sibi Prabakaran
83b005ee79
Merge pull request #417 from TheMC47/refactor-test-suite
Refactor the test-suite
2020-12-11 22:47:32 +05:30
Yecine Megdiche
048b12995a removed tests/* from extra-source-files 2020-12-11 18:03:22 +01:00
Yecine Megdiche
7ef0faa986 added new test-suite 2020-12-11 18:03:22 +01:00
Sibi Prabakaran
69a2886a8b
Merge pull request #425 from xmonad/ci-github
Add github actions for test
2020-12-11 22:22:10 +05:30
Petr Shevtsov
f24788260d
Update CHANGES.md 2020-12-11 18:35:19 +03:00
Petr Shevtsov
6e44ddb57a
Use xfce4-terminal for terminal 2020-12-11 18:29:29 +03:00
Sibi Prabakaran
2e900cc10b
Update README 2020-12-11 17:46:03 +05:30
Sibi Prabakaran
f73ebf1da1
Update 2020-12-11 17:29:14 +05:30
Sibi Prabakaran
84caa46dab
Add github actions for test 2020-12-11 17:20:59 +05:30
Tomáš Janoušek
5db2589abf
Merge pull request #423 from dminuoso/fix-toenum-crash
Check for text encoding correctly and avoid bottom (#422)
2020-12-11 01:53:41 +00:00
Victor Nawothnig
b594d97604 Check for text encoding correctly and avoid crash (#422) 2020-12-11 02:46:40 +01:00
Tomas Janousek
89dbdd4767 X.L.TrackFloating: Simplify focus logic
It seems the logic used in X.L.StateFull's FocusTracking should cover
all use cases here. Let's try it for a while. :-)
2020-12-09 00:20:41 +00:00
Tomas Janousek
0e9c865e72 X.L.TrackFloating: Drop redundant _wasFloating
It was added in 81d338952d in an attempt to fix focus handling after
closing a floating window, but shortly after made redundant in
a551d1367c when we noticed it causes more harm than good. Unfortunately
it wasn't fully reverted, making the code more complex than necessary.

Drop the remaining bits.

Now it's almost obvious that the only difference between this and
X.L.StateFull.FocusTracking is the isF condition.

BTW the original issue 81d338952d was trying to fix can be fixed by
using X.H.RefocusLast, from the author of X.L.StateFull.FocusTracking.
:-)
2020-12-09 00:20:41 +00:00
Tomas Janousek
8afd51517c X.L.TrackFloating: Simplify by using X.U.Stack.findZ
X.L.TrackFloating is more or less the same as X.L.StateFull's
FocusTracking, so it's no surprise the same helpers can be used...
2020-12-09 00:20:41 +00:00
Tomas Janousek
72b5e662de X.U.Stack: Fix/simplify find{S,Z} types
Drop Eq constraint that isn't needed.

Drop the redundant Maybe from findZ return type. Breaks symmetry but
makes it easier to use (join no longer needed).
2020-12-09 00:20:41 +00:00
Brent Yorgey
6381a4687f
Merge pull request #411 from PRESFIL/fix-Example.hs
Fix transients managing in X.C.Example
2020-12-02 13:17:28 -06:00
Brent Yorgey
a74ed5f724
Merge pull request #203 from Ongy/dzen-dock
Add -dock to dzen command
2020-12-02 13:15:28 -06:00
Brent Yorgey
317eb23654
Merge branch 'master' into dzen-dock 2020-12-02 13:15:01 -06:00
Brent Yorgey
e3558bce93
Merge pull request #401 from elkowar/cycle-action
Add new module XMonad.Util.ActionCycle
2020-12-01 14:32:54 -06:00
Matus Goljer
d9ad93a888
Add Emacs-style Prefix handling (#159)
* Add Emacs-style Prefix handling

* Update CHANGES.md

* Add helper tests for prefix type

* Add docstrings.

* Fix handling of repeated prefix when we fall-back with no binding.

* Add a caveat about nested prefix binding
2020-11-29 22:35:52 +05:30
Tomáš Janoušek
8f7f5f0a56
Merge pull request #414 from srid/patch-1
Loggers: don't hardcode /usr/bin
2020-11-29 11:55:45 +00:00
Brent Yorgey
8694656840
Merge pull request #405 from slotThe/toggleTopic
Update XMonad.Actions.TopicSpace
2020-11-28 14:00:41 -06:00
Tomáš Janoušek
a29b1565d4
Merge pull request #413 from amenonsen/dev/issue-111
Fix typo in X.L.IndependentScreens example code
2020-11-28 00:15:27 +00:00
Sridhar Ratnakumar
e52c20f70c
Update CHANGES.md 2020-11-27 21:56:13 +00:00
Sridhar Ratnakumar
95f68e2ca3
Loggers: don't hardcode /usr/bin
Some Linux distros, like NixOS, don't put these binaries under /usr/bin.
2020-11-27 21:54:07 +00:00
Abhijit Menon-Sen
d8cfdaf020 Fix typo in X.L.IndependentScreens example code
Closes #111
2020-11-27 21:51:09 +05:30
PRESFIL
2cfa5ef23a
Fix: reorder statements 2020-11-26 13:24:43 +00:00
PRESFIL
d18bcdc165
Replace composeOne with composeAll 2020-11-26 13:23:33 +00:00
slotThe
78796a24f9 Update changelog 2020-11-26 12:54:55 +01:00
slotThe
8822d2ff51 Add getLastFocusedTopicsByScreen, switchNthLastFocusedByScreen 2020-11-26 12:54:55 +01:00
slotThe
ce5aae5403 Use WorkspaceHistory
Instead of defining our own (internal) history, use an already established
module.
2020-11-24 08:35:08 +01:00
slotThe
3e7df4911a Add workspaceHistoryModify 2020-11-24 08:27:39 +01:00
slotThe
ae6c658bc4 Add switchTopicWith 2020-11-24 08:27:39 +01:00
slotThe
1400d167ad Cons on new topic before filtering the last used topics
Because the there is a hard limit on the number of items in the topic
history now, it makes sense to first cons on the topic and then filter
the result (so setLastFocusedTopic can be used to exclude certain topics
from ever entering the history).
2020-11-24 08:27:39 +01:00
slotThe
6079c61063 Use sortOn instead of sortBy comparing 2020-11-24 08:27:39 +01:00
slotThe
aa67fa5352 Respect maxTopicHistory when entering topics into the history
So far, maxTopicHistory was only used when pretty-printing the history
via pprWindowSet, which does not line up with the documentation that it
has.
2020-11-24 08:27:39 +01:00
slotThe
4c0b5330e7 Consistent indentation throughout the module
Two spaces seem to be a bit more common here, hence it was chosen over four
spaces.
2020-11-24 08:27:39 +01:00
slotThe
3c1866979d Update documentation 2020-11-24 08:27:39 +01:00
slotThe
6b22ce17c7 Add switchNthLastFocusedExclude
This may be used to exclude certain topics that one never wants to
"switch back" to, even if it was visited (for example, the named
scratchpad topic).
2020-11-24 08:27:39 +01:00
slotThe
d13a26b11e Update last focused topics when switching to a new one 2020-11-24 08:27:39 +01:00
Sibi Prabakaran
9976aa3b3c
Merge pull request #404 from slotThe/remove-default-deprecations
Remove Data.Default Deprecations
2020-11-24 12:29:13 +05:30
PRESFIL
02c6e0b0d4 Handle floating windows after making windows floating
Inspired with hgabreu's config. Now it makes more sense.
2020-11-24 00:33:54 +03:00
PRESFIL
e504f40f88 Fix transient windows handling
Since *transient windows* are a subset of *dialog windows*, they need to be caught early.
Otherwise, they are never managed by `transience`.
2020-11-24 00:33:34 +03:00
Tomas Janousek
6db6854752 X.U.PureX: Add focusWindow and focusNth
This can be used to reduce flicker in noop focus actions.
2020-11-17 14:10:20 +00:00
Tomas Janousek
14dc3a7f79 X.H.ManageDocks: Init strut cache on demand if necessary
This makes docksStartupHook unnecessary. That is desirable because we
didn't add a changelog entry about it being necessary, and 4 years after
its introduction we still have users grabbing old configs and reporting
(https://github.com/xmonad/xmonad/issues/21#issuecomment-596161669) that
ManageDocks doesn't work properly.

I would love to finally settle this.

Full story follows:

xmonad-contrib 0.12 introduced (00be056a1bad, merged in April 2013)
caching to ManageDocks to avoid queryTree calls on every runLayout,
which brought in several bugs. Attempts to fix these bugs in
xmonad-contrib 0.13 introduced (28e9f8bce781, merged in February 2016) a
breaking change in ManageDocks that required users to add
docksStartupHook (or docks, after e38fb3bdb8bb got merged in November
2016) to their configs for avoidStruts to still work after xmonad
restart. Unfortunately this was never mentioned in the changelog nor in
any compilation warning (which get discarded by xmonad --recompile
anyway !!!), so as of March 2020 we still have users being bitten by
this.

Back in September 2016 in a discussion about other bugs introduced in
28e9f8bce781 I suggested that we use Maybe to indicate whether the cache
had been initialized and initialize it on demand when it had not.
Unfortunately I wasn't sufficiently clear about what I meant and Brandon
was going through some health issues, so we just got into a heated
argument and ended up merging a suboptimal solution. :-(

And since we're _still_ getting complaints from users every now and
then, I believe it's worth dealing with even after all these years.
If nothing else, let this serve as a reminder that breaking users'
configs without any warning is wrong.

(Oh and we should probably stop hiding xmonad.hs compilation warnings,
otherwise we can't ever hope to provide smooth deprecation and upgrade
paths.)

Fixes: 00be056a1bad ("Cache results from calcGap in ManageDocks")
Fixes: 28e9f8bce781 ("add docksStartupHook for handling docks when restarted")
Fixes: e38fb3bdb8bb ("Make usage of ManageDocks simpler and more robust")
Related: https://github.com/xmonad/xmonad-contrib/issues/118
Related: https://github.com/xmonad/xmonad-contrib/pull/30
Related: https://github.com/xmonad/xmonad-contrib/pull/80
Related: https://github.com/xmonad/xmonad/issues/21
2020-11-17 00:46:12 +00:00
Tomas Janousek
f271d59c34 X.A.WorkspaceNames: Provide workspaceListTransform for EwmhDesktops
Together with ewmhDesktopsLogHookCustom this exposes workspace names to
external pagers.

Fixes: https://github.com/xmonad/xmonad-contrib/pull/105
Fixes: https://github.com/xmonad/xmonad-contrib/pull/122
Co-authored-by: Ivan Malison <IvanMalison@gmail.com>
2020-11-16 11:16:59 +00:00
Tomas Janousek
3dc6b44f86 X.A.WorkspaceNames: Kill a warning 2020-11-16 10:55:22 +00:00
Tomas Janousek
bda1d3356d CHANGES: Trailing whitespace fixes 2020-11-16 10:55:22 +00:00
slotThe
683344ed25 Update CHANGES.md 2020-11-16 10:31:02 +01:00
slotThe
5140f5b5d0 Remove things deprecated by Data.Default 2020-11-16 10:31:02 +01:00
Sibi Prabakaran
cd1c1d1d69
Merge pull request #402 from elkowar/fix-usage-missing
Fix missing usage-section in XMonad.Hooks.WindowSwallowing
2020-11-15 22:01:50 +05:30
elkowar
9e3d17c1c0 Fix missing usage-section in XMonad.Hooks.WindowSwallowing 2020-11-15 13:28:13 +01:00
elkowar
ffae2dcd2f Add new module XMonad.Util.ActionCycle 2020-11-15 13:22:11 +01:00
Tomas Janousek
5d2a6d75a8 X.H.EwmhDesktops: Fix _NET_* properties not being set at startup
None of these properties are currently being set when xmonad starts:

    _NET_ACTIVE_WINDOW(WINDOW): window id # 0x0
    _NET_CURRENT_DESKTOP(CARDINAL) = 0
    _NET_CLIENT_LIST_STACKING(WINDOW): window id #
    _NET_CLIENT_LIST(WINDOW): window id #

because the caching introduced in 92fe5f34ffff408fa859f initializes the
cache with the same values that they should have in an empty session, so
we don't detect a change and don't set them.

Fix it by initializing the cache with impossible (or at least extremely
improbable) values.

Fixes: https://github.com/xmonad/xmonad-contrib/issues/363
2020-11-09 22:15:25 +00:00
Brent Yorgey
e042bcce97
Merge pull request #398 from liskin/layoutclass-typeable
Add Typeable constraint to a few LayoutClass instances
2020-11-09 14:13:09 -06:00
Tomas Janousek
b989655cea Add Typeable constraint to a few LayoutClass instances
This enables adding the Typeable constraint to LayoutClass itself
(https://github.com/xmonad/xmonad/pull/242) which in turn enables
querying the current layout state. That might be useful to e.g. show the
current X.L.WorkspaceDir in xmobar.

This is a preparation commit that fixes the compile failures that would
result in merging that change to xmonad. For this to be generally useful
we first need to merge (and ideally also release) that xmonad change,
and then we'll need some documentation and perhaps a type class to help
find the right LayoutModifier in the tree of ModifiedLayouts and
Choices. That will come later.
2020-11-09 16:37:30 +00:00
Tomas Janousek
087076f136 CHANGES: Document last 3 commits 2020-11-04 16:23:37 +00:00
Tomas Janousek
0996e71c7e X.H.DynamicLog: Add shortenLeft
This can be sometimes useful, e.g. when showing a directory.
2020-11-04 16:17:32 +00:00
Tomas Janousek
d5b64c1e5d X.L.WorkspaceDir: Export Chdir
This makes it possible to change the workspace directory by sending a
message, which enables automation/scripting not possible with
`changeDir` which displays a prompt.

Example of such usage:
6ea6c52aac/.xmonad/xmonad.hs (L183-L189)
2020-11-04 16:16:51 +00:00
Tomas Janousek
73eb28f669 XMonad.Prompt.Directory: Sort completion suggestions 2020-11-04 11:31:50 +00:00
Brent Yorgey
aa67439bfe
Merge pull request #192 from sgf-dma/x.h.focus
Resubmit #128 (X.H.Focus)
2020-10-29 19:55:41 -05:00
sgf
2cc20b4116 Add new module XMonad.Hooks.Focus .
Extend ManageHook EDSL to work on focused windows and current workspace.
2020-10-28 17:51:40 +03:00
sgf
45052b984d X.H.EwmhDesktops. run 'logHook' for activated window.
- By default window activation does nothing.
- `activateLogHook` may be used for running some 'ManageHook' for
activated window.
- `activated` predicate may be used for checking was window activated or
not.
2020-10-28 17:51:40 +03:00
sgf
b2e16d3bf1 X.H.ManageHelpers: Make type of ManageHook combinators more general. 2020-10-19 15:18:00 +03:00
sgf
3a7399b56a X.H.SetWMName: Add getWMName function. 2020-10-19 15:18:00 +03:00
Brent Yorgey
4670ec002f
Merge pull request #389 from skewerr/master
add XMonad.Layout.VoidBorders
2020-10-17 06:39:18 -05:00
Wilson Sales
5fd8ff86e9
add XMonad.Layout.VoidBorders
This module contains a modifier that simply sets X11 window border width
to 0 for every window in the layout it modifies. No efforts are made to
bring the border back, which can be annoying if windows are moved to a
different workspace, but it prevents the "border flash" you get with
XMonad.Layout.NoBorders.
2020-10-17 00:08:40 -03:00
Brent Yorgey
d4e15cddd1
Merge pull request #390 from ivanbrennan/export-clickableWrap
Export clickableWrap
2020-10-16 17:36:34 -05:00
Brent Yorgey
4f9dec9760
Merge pull request #391 from NickHu/unicode
Fixes for XMonad.Prompt.Unicode
2020-10-16 17:35:18 -05:00
Nick Hu
598a40da9c
add missing documentation of XMonad.Prompt.FuzzyMatch and
XMonad.Prompt.Unicode to XMonad.Doc.Extending
2020-10-14 17:20:28 +01:00
Nick Hu
1a085bec43
XMonad.Prompt.FuzzyMatch: handle case when input is not a subsequence of every completion 2020-10-14 17:16:06 +01:00
Nick Hu
a69794892b
XMonad.Prompt.Unicode: respect searchPredicate and sorter from XPConfig 2020-10-14 17:13:30 +01:00
ivanbrennan
8e12681925
export clickableWrap
Configs that apply WorkspaceId transformations, such as
IndependentScreens (adding/removing a screen-number prefix) and
NamedWorkspaces (adding/removing a name suffix), cannot use clickablePP
as is, since they need to apply clickableWrap to an appropriately
transformed WorkspaceId. Rather than force them to reimpliment
clickableWrap, export it.

An example use-case, where IndependentScreens has added a screen number
prefix to the workspace ids (0_1, 0_2, ...), and we want a status-bar
that shows the ids without screen number (1, 2, ...), but also makes
them clickable:

    getClickable :: (WorkspaceId -> WorkspaceId) -> X (WorkspaceId -> String)
    getClickable f = do
      wsIndex <- getWsIndex
      pure $ \ws -> case wsIndex (f ws) of
                      Just idx -> clickableWrap idx ws
                      Nothing -> ws

    composePP :: PP -> ScreenId -> X PP
    composePP pp s = do
      clickable <- getClickable (marshall s)
      return
        . marshallPP s
        $ pp
          { ppCurrent         = ppCurrent         pp . clickable,
            ppVisible         = ppVisible         pp . clickable,
            ppHidden          = ppHidden          pp . clickable,
            ppHiddenNoWindows = ppHiddenNoWindows pp . clickable,
            ppUrgent          = ppUrgent          pp . clickable
          }
2020-10-14 07:31:44 -04:00
Nick Hu
9c09072843
XMonad.Prompt.Unicode: use spawnPipe instead of runProcessWithInput 2020-10-13 20:39:21 +01:00
Tomáš Janoušek
02baee5f7e
Merge pull request #388 from ivanbrennan/export-clickable-workspaces
Add ClickableWorkspaces to exposed modules
2020-10-12 01:28:08 +02:00
ivanbrennan
00d829803d
expose XMonad.Util.ClickableWorkspaces
This module was not exposed, so any attempt to use it resulted in a
compilation error.
2020-10-11 18:49:41 -04:00
Brent Yorgey
9c4c417936
Merge pull request #386 from ivanbrennan/compl-case-sensitivity
Allow case-insensitive shell prompt completion
2020-09-30 17:56:23 -05:00
ivanbrennan
52c5bd61cb
use complCaseSensitivity field
Use the newly-added complCaseSensitivity field of XPConfig where
possible, rather than declaring primed function variants.
2020-09-28 22:36:05 -04:00
ivanbrennan
b63159fd00
add complCaseSensitivity field to XPConfig 2020-09-28 21:51:45 -04:00
ivanbrennan
bbcc7e576f
CHANGES: directory completion case sensitivity 2020-09-24 08:14:50 -04:00
ivanbrennan
86ef180162
usage: changeDir' 2020-09-24 07:57:34 -04:00
ivanbrennan
4de529a923
DynamicProjects: allow case-insensitive prompts
Provide a way to use case-insensitive directory completion.
2020-09-24 07:57:33 -04:00
ivanbrennan
0c9c330295
Dir: ComplCaseSensitivity field (breaking change)
Parameterizing completion case-sensitivity for single-mode prompts was
possible without making any breaking changes. For multi-mode prompts,
however, the completion function is expressed through the XPrompt
'completionFunction' method. The only argument that method receives is a
Dir value, so parameterizing completion case-sensitivity means adding a
new field to the Dir constructor.
2020-09-24 07:57:33 -04:00
ivanbrennan
795be75a58
prompt completion: case-sensitivity
Provide a way to perform case-insensitive file / directory completion.
We're using compgen to generate completion candidates, and this is
case-sensitive by default. We can control this by setting the
completion-ignore-case Readline variable prior to invoking compgen. If
we're running a Bash with Readline support, this works as expected.
Otherwise, it has no effect -- completion candidates are still returned,
but compgen generates them in a case-sensitive manner.

To avoid breaking changes, the signatures and behavior of existing
exported functions are unchanged:
  - XMonad.Layout.WorkspaceDir.changeDir
  - XMonad.Prompt.Directory.directoryPrompt
  - XMonad.Prompt.Shell.getShellCompl

New variations of these functions are provided, allowing the caller
to specify the desired case-sensitivity via a ComplCaseSensitivity
argument:
  - XMonad.Layout.WorkspaceDir.changeDir'
  - XMonad.Prompt.Directory.directoryPrompt'
  - XMonad.Prompt.Shell.getShellCompl'

The XMonad.Prompt.Shell exports a couple new functions:
  - compgenDirectories
  - compgenFiles

We make use of this in XMonad.Prompt.Directory to avoid duplicating the
compgen code.
2020-09-24 07:57:33 -04:00
Brent Yorgey
b5105381bf
Merge pull request #384 from ivanbrennan/rotate-some
RotateSome
2020-09-24 05:09:06 -05:00
ivanbrennan
c5ff88b87b
improve RotateSome documentation and readability
Add an example and more comments to the documentation, and make some
small code tweaks (more type signatures and a couple variable renames)
to aid readability.
2020-09-23 16:55:14 -04:00
Ivan
1e73a97500
Merge pull request #383 from ivanbrennan/pretty-printing-modifier
Add statusBar' to support dynamic pretty printing modifiers
2020-09-19 15:27:41 -04:00
ivanbrennan
551ff2b8ac
CHANGES: add XMonad.Hooks.DynamicLog.statusBar' 2020-09-19 15:12:54 -04:00
ivanbrennan
ebfc068b99
DynamicLog: statusBar'
Add a statusBar' function that accepts pretty printing options embedded
in the X monad, so users can leverage dynamic printing modifiers, such
as workspaceNamesPP.
2020-09-19 15:12:40 -04:00
Brent Yorgey
dea887d487
Merge pull request #385 from TomSmeets/tree-select-fix-origin
TreeSelect: Resolve issue #362 with origin offset being ignored
2020-09-19 13:23:35 -05:00
ivanbrennan
8fe0eabaf8
add tests/RotateSome.hs to extra-source-files 2020-09-19 14:05:49 -04:00
Brent Yorgey
010cd4ff5f
Merge pull request #382 from ivanbrennan/boring-sift
BoringWindows: siftUp, siftDown
2020-09-19 11:12:25 -05:00
ivanbrennan
957f4518b9
surfaceNext, surfacePrev exclude floating windows
I was naively passing the workspace to runLayout without filtering out
floating windows from its stack, like XMonad.Operations.windows does.
The fact that 'windows' does this filtering explains how layouts like
those in LimitWindows continue to behave correctly in the presence of
floating windows.

This fixes some incorrect behavior where the presence of a floating
windows caused visible windows (other than the focused one) to be
included in the surfaceRing.
2020-09-19 11:29:30 -04:00
Tom Smeets
4b65f9eef0 TreeSelect: Resolve issue #362 with origin offset being ignored
The config values `ts_originX` and `ts_originY` were not behaving like documented. They weren't doing anything at all.
This should fix that.
2020-09-18 21:31:10 +02:00
ivanbrennan
e88e7ee1f0
CHANGES: add XMonad.Actions.RotateSome 2020-09-18 12:03:45 -04:00
ivanbrennan
c5745b6299
add RotateSome property tests
Verify that rotateSome behaves as expected and never fails to pattern
match.

In order to run these tests, I ran a custom script:

  scripts/run-tests.sh tests/RotateSome.hs

where the script contained the following:

  set -eu

  toplevel=$(git rev-parse --show-toplevel)
  XMONAD="${XMONAD:-$toplevel/../xmonad}"
  main=$(realpath -e "$1")

  instances_target="$XMONAD/tests/Instances.hs"
  instances_symlink="$toplevel/tests/Instances.hs"

  properties_target="$XMONAD/tests/Properties"
  properties_symlink="$toplevel/tests/Properties"

  utils_target="$XMONAD/tests/Utils.hs"
  utils_symlink="$toplevel/tests/Utils.hs"

  trap "
      rm '$instances_symlink' '$utils_symlink' '$properties_symlink' || true
  " EXIT INT QUIT TERM

  ln -s "$instances_target" "$instances_symlink"
  ln -s "$properties_target" "$properties_symlink"
  ln -s "$utils_target" "$utils_symlink"

  runghc -DTESTING \
      -i"$toplevel" \
      -i"$toplevel/tests" \
      "$main"
2020-09-18 11:31:50 -04:00
ivanbrennan
f06ee5e1ff
add XMonad.Actions.RotateSome
This module provides a pure function, 'rotateSome', as well as a pair of
X actions that use it to rotate unshown windows through the focused
stack position while leaving other windows in place. I find this useful
in combination with layouts such as LimitWindows, which determine window
visibility based on stack position.
2020-09-17 22:51:16 -04:00
ivanbrennan
db3e5d85b5
CHANGES: additions to XMonad.Layout.BoringWindows 2020-09-14 17:56:41 -04:00
ivanbrennan
aa3939e66b
XMonad.Layout.BoringWindows: siftUp, siftDown
Provide boring-aware versions of the 'siftUp' and 'siftDown' functions.
Since these actions never affect the position of boring windows, they
work well with layouts that decide which windows are visible/hidden
based on stack position, such as LimitWindows.
2020-09-14 17:37:38 -04:00
Brent Yorgey
fe027ce358
Merge pull request #380 from ivanbrennan/sift
XMonad.Actions.Sift
2020-09-14 14:00:50 -05:00
Brent Yorgey
3661471377
Merge pull request #378 from ivanbrennan/boring-swaps
BoringWindows: swapUp, swapDown
2020-09-14 13:50:33 -05:00
ivanbrennan
33ad9e526d
CHANGES: add XMonad.Actions.Sift 2020-09-12 13:49:35 -04:00
ivanbrennan
e2fa1ce8a1
add XMonad.Actions.Sift (siftUp, siftDown)
Provide swap-like functions that handle the wrapping case by exchanging
the windows at either end of the stack rather than rotating the stack.

https://github.com/xmonad/xmonad/issues/234
2020-09-12 09:35:35 -04:00
ivanbrennan
f94984c141
CHANGES: additions to XMonad.Layout.BoringWindows 2020-09-10 07:38:11 -04:00
ivanbrennan
c2dd9b0b7a
skip boring: extract common iterate/filter logic 2020-09-10 06:40:14 -04:00
ivanbrennan
610fb0e200
skipBoring: drop zeroth iteration before filtering
The effect is the same, but this seems to express the intent more
clearly, and it will make it easier to factor out the shared behavior
with skipBoringSwapUp.
2020-09-10 06:39:50 -04:00
ivanbrennan
53b0edae28
BoringWindows: swapUp, swapDown
Provide boring-aware versions of 'swapUp' and 'swapDown'.

Note that 'iterate f x' produces a list whose zeroth element is
'x' prior to any application of 'f'. The 'focusUp' and 'focusDown'
operations reject this iteration by checking in the filter predicate
that the focus actually changed:

  filter ((`notElem` W.focus st:bs) . W.focus)

We can't do that for swaps, since our focus never changes, so we drop
the zeroth iteration prior to any predicate-based filtering.

The filter predicate checks whether the window immediately below the
our focus is boring. If so, we've performed an uninteresting upwards
swap and should continue swapping until we either swap past a window
that is not boring or wrap around the top of the stack.

It's particularly important that we accept the wrapping case regardless
of any boring neighbor, otherwise we risk missing a legitimate
non-boring swap. Consider, for example, the following stack:

  focus: A
  up: []
  down: [B, boringC]

A swapUp yields:

  focus: A
  up: [boringC, B]
  down: []

This should be considered non-boring, since the non-boring windows
swapped order: A B -> B A. If we were to reject it, we'd swap A up past
boringC and up again past B, putting us back where we started.

Put another way, if our focus was at the top of the stack, then all
other windows were necessarily below it. We want a swapUp to place our
focus below the lowest non-boring window. A wrap around to the bottom of
the stack guarantees that is the case.
2020-09-10 06:39:47 -04:00
Brent Yorgey
58feba91d9
Merge pull request #375 from ivanbrennan/minimize-export
Minimize: export type constructor
2020-08-30 14:04:47 -05:00
ivanbrennan
6e162280b9
CHANGES: XMonad.Layout.Minimize export Minimize 2020-08-30 14:58:34 -04:00
ivanbrennan
1c97ca63c3
export Minimize type constructor
Some users like to include type signatures in their configuration. The
Minimize type constructor was not exported, making it impossible to
write a type signature when using minimize.

With this change, a user can write an xmonad.hs like:

  import XMonad
  import XMonad.Layout.Minimize (Minimize, minimize)
  import XMonad.Layout.LayoutModifier

  myLayout :: ModifiedLayout
              Minimize
              (Choose Tall (Choose (Mirror Tall) Full))
              Window
  myLayout = minimize $ layoutHook def

  main :: IO ()
  main = xmonad def { layoutHook = myLayout }
2020-08-30 14:54:39 -04:00
Brent Yorgey
2ad0c04447
Merge pull request #373 from TheMC47/xmobarBorder
Added xmobarBorder utility function to add borders to strings
2020-08-29 15:31:51 -05:00
Yecine Megdiche
40b939f7a6 typo 2020-08-29 20:26:49 +02:00
Yecine Megdiche
ab04e29e42 added xmobarBorder 2020-08-29 19:44:01 +02:00
Brent Yorgey
51bc4f8c2f
Merge pull request #370 from felixonmars/patch-1
Depend on semigroups only on GHC < 8.0
2020-08-15 11:28:12 -05:00
Brent Yorgey
07717e5dea
Merge pull request #368 from sam-barr/master
Export AvoidStruts constructor and doSink
2020-08-13 17:41:52 -05:00
Felix Yan
e61a408e9d
Depend on semigroups only on GHC < 8.0
They are not needed on newer GHC.
2020-08-11 17:40:27 +08:00
sam-barr
c60d8fc29d
Merge branch 'master' into master 2020-08-06 07:48:49 -05:00
Brent Yorgey
15dbfeff32
Merge pull request #365 from frozencemetery/xf86bluetooth
EZConfig: Learn about XF86Bluetooth
2020-08-06 07:00:59 -05:00
sam-barr
dcf5fad5f9 Expose internal state of AvoidStruts layout modifier
Updated Changes.md

Export doSink
2020-08-05 19:31:52 -05:00
Brent Yorgey
4a6bbb63b4
Merge pull request #367 from elkowar/fix/window-swallowing-bug
Fix rare issues with windows wrongly dissapearing after windowswallowing
2020-07-27 05:19:34 -05:00
elkowar
8059d4c38c Fix rare issues with windows wrongly dissapearing after windowswallowing 2020-07-27 11:50:16 +02:00
Geoff deRosenroll
c7afc2904b
Add XMonad.Util.ClickableWorkspaces module (#364)
This module enables clickable workspace tags in XMobar in a relatively unobtrusive fashion.
Inspired by https://arch-ed.dk/xmobar-clickable-workspaces
2020-07-24 01:11:48 +02:00
Robbie Harwood
04ccc4d972 EZConfig: Learn about XF86Bluetooth 2020-07-22 16:14:38 -04:00
Brent Yorgey
3dc49721b6
Merge pull request #357 from elkowar/window_swallowing
Add XMonad.Hooks.WindowSwallowing
2020-06-23 09:05:23 -05:00
Brent Yorgey
4d6209e17a
Merge pull request #360 from Xandaros/iss359
Export EZConfig parsers
2020-06-22 06:19:03 -05:00
Martin Zeller
abfeff5db7
Export EZConfig parsers 2020-06-22 13:01:48 +02:00
Leon Kowarschick
5869af1c56 Fix floating state not correctly being cleaned after swallowing and make handleEventHook take Query Bool rather than [Query Bool] 2020-06-21 11:54:40 +02:00
Leon Kowarschick
ba247afd0a Add XMonad.Hooks.WindowSwallowing 2020-06-20 14:00:54 +02:00
Brent Yorgey
e3632cb0b4
Merge pull request #355 from wz1000/zsh-prompt
Add XMonad.Prompt.Zsh
2020-06-19 18:02:19 -05:00
Brent Yorgey
9fa69a5603
Merge pull request #356 from elkowar/hidden_layout_pop_specific
Add restoreHiddenWindow function to XMonad.Layout.Hidden
2020-06-19 17:59:39 -05:00
Brent Yorgey
5c8ff36bcb
Merge pull request #351 from elkowar/master
Make XMonad.Util.NamedScratchpad more flexible
2020-06-18 07:06:21 -05:00
Leon Kowarschick
65036457cc Add restoreHiddenWindow function to XMonad.Layout.Hidden, restoring a specific window 2020-06-13 15:01:25 +02:00
Zubin Duggal
8c39850dc0
Add XMonad.Prompt.Zsh 2020-06-13 04:07:09 +05:30
Leon Kowarschick
5f3edb110e Refactor someNamedScratchpadOption to use Data.NonEmpty and to improve readability 2020-06-06 14:55:31 +02:00
Brent Yorgey
8ba646aec6
Merge pull request #340 from igor04/max-magnifier-off
Add maxMagnifierOff to Magnifier layout
2020-06-05 15:38:59 -05:00
ElKowar
22fcf69e83
Add PR-template checkbox about updating XMonad.Doc.Extending (#353) 2020-06-03 20:33:57 +05:30
Leon Kowarschick
a861a8f954 Add more customizability to how scratchpads are initially started in XMonad.Util.NamedScratchpad 2020-06-03 10:35:28 +02:00
Brent Yorgey
24d2f26302
Merge pull request #344 from elkowar/master
add new XMonad.Actions.TiledWindowDragging module
2020-06-01 15:36:41 -05:00
Brent Yorgey
aa3f93afea
Merge pull request #350 from davama/master
Add Ebay Function to X.A.Search
2020-06-01 14:25:50 -05:00
Dave
faf89612aa
Update Search.hs
Add ebay function
2020-06-01 12:00:04 -04:00
Brent Yorgey
6c60740f7e
Merge pull request #345 from mephory/master
X.U.DynamicScratchpads: Make any window a scratchpad
2020-05-30 07:17:48 -05:00
Brent Yorgey
4aa6f22899
Merge pull request #346 from psibi/338-no-encoding
Make spawnPipe to use system's locale encoding
2020-05-30 07:15:56 -05:00
Brent Yorgey
290d58dd9a
Merge pull request #347 from psibi/update-stack-resolver
Update stack resolver
2020-05-30 07:14:31 -05:00
Sibi Prabakaran
89603c4a36
Update stack resolver 2020-05-29 22:28:33 +05:30
Sibi Prabakaran
b200d0c735
Update changelog 2020-05-29 22:25:34 +05:30
Sibi Prabakaran
1d0eaddc25
Make spawnPipe to use system's locale encoding
Add a function named spawnPipeWithNoEncoding for people who might want
to use binary handles.

Fixes https://github.com/xmonad/xmonad-contrib/issues/338
2020-05-29 22:21:38 +05:30
mephory
1fdfb4b8d0
X.U.DynamicScratchpads: added missing functions 2020-05-29 16:15:51 +02:00
mephory
ff0ab6f977
X.U.DynamicScratchpads: Make any window a scratchpad 2020-05-29 15:51:24 +02:00
Leon Kowarschick
b2446cd633 Adjust code style to match guidelines 2020-05-27 18:01:01 +02:00
Leon Kowarschick
365988774f include changes in CHANGES.md 2020-05-27 18:00:44 +02:00
Leon Kowarschick
08b54edbf9 add new XMonad.Layout.TiledWindowDragging module 2020-05-27 17:52:58 +02:00
Brent Yorgey
28e29fa238
Merge pull request #339 from samtay/three-column-resizable
Add ResizableThreeColumns layout
2020-05-23 13:45:46 -05:00
Sam Tay
0c642c3e9a Add ResizableThreeColumns layout
Based on ThreeColumns and ResizableTile
2020-05-18 14:18:36 -07:00
igor04
2149f0a07b Add maxMagnifierOff to Magnifier layout 2020-05-17 19:37:07 +03:00
Brent Yorgey
14faa12f69
Merge pull request #336 from ivanbrennan/hidden-windows-export
HiddenWindows: export type constructor
2020-05-14 14:46:43 -05:00
Brent Yorgey
d95dc14970
Merge pull request #335 from sam-barr/master
Add a doSink manage hook
2020-05-11 06:41:01 -05:00
Sibi Prabakaran
f8105131e1
Merge pull request #334 from psibi/spawn-functions
Add new variants of spawnPipe functions with encoding support
2020-05-09 19:44:55 +05:30
ivanbrennan
57936bf6d9
CHANGES: XMonad.Layout.Hidden export HiddenWindows 2020-05-03 13:33:42 -04:00
ivanbrennan
c201a9e33e
export HiddenWindows type constructor
Some users like to include type signatures in their configuration. The
HiddenWindows type constructor was not exported, making it impossible to
write a type signature when using hiddenWindows.

With this change, a user can write an xmonad.hs like:

  import XMonad
  import XMonad.Layout.Hidden (HiddenWindows, hiddenWindows)
  import XMonad.Layout.LayoutModifier

  myLayout :: ModifiedLayout
              HiddenWindows
              (Choose Tall (Choose (Mirror Tall) Full))
              Window
  myLayout = hiddenWindows $ layoutHook def

  main :: IO ()
  main = xmonad def { layoutHook = myLayout }
2020-05-03 13:32:28 -04:00
sam-barr
dea927d887 Fix failing build 2020-04-29 20:29:07 -05:00
sam-barr
0eed434b0e Noted doSink in CHANGES.md 2020-04-29 20:18:18 -05:00
sam-barr
04625d0d04 added doSink ManageHook 2020-04-29 20:12:57 -05:00
Sibi Prabakaran
8b2bd3ae5c
Add new variants of spawnPipe functions with encoding support
The current handle returned by `spawnPipe` doesn't have any encoding
and it uses the function fdToHandle which returns a Binary
Handle. When spawnPipe is used with a program like xmobar, this can
easily lead to errors:

λ> h <- spawnPipe "xmobar"
λ> hPutStrLn h
"\35753Haskell\25110\32773Ghci\33021\27491\30830\26174\31034\27721\23383\24182\19988\35835\21462\27721\23383\21629\21517\30340\25991\26723"
<stdin>: hGetLine: invalid argument (invalid byte sequence)

One workaround, to avoid this is to use `hSetEncoding`. But from
reading GHC's source code - the entire Handle and write operations
seems stateful. So doing something like hPutStr and hSetEncoding can
theoretically lead to an undefined state as the first write will use
latin encoding and the second write will use the new encoding. More
details about it are present here:

* http://hackage.haskell.org/package/base-4.12.0.0/docs/src/GHC.IO.Handle.Internals.html#writeCharBuffer
* http://hackage.haskell.org/package/base-4.12.0.0/docs/src/GHC.IO.Buffer.html#CharBuffer

So having these new functions will ensure that we get the handles in
the proper encoding in the first place.
2020-04-24 14:12:21 +05:30
Brent Yorgey
252e6e4d00
Merge pull request #333 from wz1000/master
Allow WindowPrompt to execute arbitrary actions with the window
2020-04-16 22:05:28 -05:00
Zubin Duggal
f7ed56fc6b
Update changelog 2020-04-09 01:11:04 +05:30
Zubin Duggal
5880e01ad2
Add message to window prompt to execute arbitrary actions with the window 2020-04-09 01:06:20 +05:30
Brent Yorgey
5521b432dd
Merge pull request #331 from ivanbrennan/toggle-recent-workspace
CycleRecentWS: add non-empty and toggle functionality
2020-03-08 17:52:58 -05:00
ivanbrennan
c48ddb08af
CHANGES: additions to XMonad.Actions.CycleRecentWS 2020-03-06 08:31:55 -05:00
ivanbrennan
5aca3fb542
export recentWS
Allow consumers of this module to filter the recency list with a custom
predicate when cycling/toggling workspaces.
2020-03-06 08:31:55 -05:00
ivanbrennan
423d70593d
refactor recentWS
Instead of constructing workspaces and rearranging it with tail and
head, construct it in the desired formation directly.
2020-03-05 09:13:14 -05:00
ivanbrennan
53a59d6592
cycleRecentNonEmptyWS, toggleRecentNonEmptyWS
Add non-empty variants to these workspace cycling/toggling functions.
2020-03-05 09:13:13 -05:00
ivanbrennan
dcf1f3e694
add toggleRecentWS
Add toggleRecentWS to switch to the most recent workspace, with repeated
use toggling between a pair of workspaces.
2020-03-05 09:13:13 -05:00
Brent Yorgey
1e3448fc53
Merge pull request #330 from slotThe/master
X.A.Search: Add promptSearchBrowser'
2020-02-14 17:59:10 -06:00
slotThe
eacd20ad00 Update CHANGES.md 2020-01-19 22:22:50 +01:00
slotThe
5493ff190d Add promptSearchBrowser' to further filter suggestions
Users may suggesting previous searches if and only if they came from the same
search engine more natural.
2020-01-19 22:08:48 +01:00
Brent Yorgey
a3afd6219d
Merge pull request #328 from atondwal/master
X.L.MouseResizableTile borderWidth via focused win
2020-01-18 09:34:53 -06:00
Brent Yorgey
c4f64bc7d6
Merge pull request #326 from mrVanDalo/boring/broadcast
XMonad.Layout.BoringWindows: add markBoringEverywhere
2020-01-03 14:18:32 -06:00
Brent Yorgey
eb38b064a7
Merge pull request #324 from tidues/master
New Feature for TallMastersCombo: Switch between Focused Windows across All Sub-layouts
2020-01-03 14:15:46 -06:00
Brent Yorgey
fca0929876
Merge pull request #325 from jcpetruzza/prompt-searchPredicate-in-more-cases
Prompt: Use searchPredicate in more cases
2019-12-17 13:25:17 -06:00
Brent Yorgey
f1fc219732
Merge pull request #329 from josephcsible/patch-1
Use `drop 1` instead of reimplementing it in terms of `tail`
2019-12-15 20:59:50 -06:00
Joseph C. Sible
5860864e45
Use drop 1 instead of reimplementing it in terms of tail 2019-12-14 23:43:31 -05:00
Anish Tondwalkar
d6244a1069 X.L.MouseResizableTile borderWidth via focused win
When we calculate draggerGeometry, we should use the current width of
the border (if available), rather than the initial borderWidth.
2019-12-01 17:09:54 -08:00
Ingolf Wagner
1a3d58143e
XMonad.Layout.BoringWindows: add markBoringEverywhere
to mark the currently focused window boring on all layouts,
when using XMonad.Actions.CopyWindow.
2019-11-21 17:42:01 +13:00
Daniel Gorin
28b3e34fd7 Prompt: Use searchPredicate in more cases
Prompts based on `mkComplFunList` and `mkComplFunList'` were not
taking into account the `searchPredicate` funtion from `XPConfig`.
This was rather confusing.

We fix it by passing `XPConfig` to these functions; although
this is strictly more than they need, it makes the breaking change very
easy to fix and is also more future-proof.
2019-11-18 20:13:40 +00:00
Brent Yorgey
52f8c82504
Merge pull request #109 from liskin/ewmh-fullscreen
X.H.EwmhDesktops: optionally advertise fullscreen support in _NET_SUPPORTED
2019-11-04 05:14:39 -06:00
tidues
3825c56e1d TallMastersCombo New Feature 2019-10-29 01:20:11 -04:00
brandon s allbery kf8nh
37a3d08d73
Merge pull request #323 from liskin/changes
CHANGES: Move stuff merged post-0.16 upwards
2019-10-16 10:32:21 -04:00
Tomas Janousek
d07f0a9ee4 X.L.Fullscreen: fullscreenSupport advertises fs support in _NET_SUPPORTED
Makes X.L.Fullscreen behave similarly to ewmhFullscreen. See the
X.H.EwmhDesktops commit for details.
2019-10-16 16:25:37 +02:00
Tomas Janousek
7bf8544f1c X.H.EwmhDesktops: optionally advertise fullscreen support in _NET_SUPPORTED
Provide a way to advertise _NET_WM_STATE_FULLSCREEN in _NET_SUPPORTED.
I had this hardcoded for a while but read the mpv manpage recently:

    Specifically, yes will force use of NetWM fullscreen support, even
    if not advertised by the WM. This can be useful for WMs that are
    broken on purpose, like XMonad. (XMonad supposedly doesn't advertise
    fullscreen support, because Flash uses it. Apparently, applications
    which want to use fullscreen anyway are supposed to either ignore
    the NetWM support hints, or provide a workaround. Shame on XMonad
    for deliberately breaking X protocols (as if X isn't bad enough
    already).

I'm not sure Flash is still a good reason these days to not advertise
fullscreen support yet still handle it and look like idiots while doing
so. (And if anyone thinks it is a good reason, their unchanged xmonad
config will continue behaving that way.)
2019-10-16 16:25:36 +02:00
Tomas Janousek
dc2b96d575 Use Graphics.X11.Xlib.Atom constants in invocations of changeProperty 2019-10-16 16:24:29 +02:00
Tomas Janousek
d8e496d3f0 CHANGES: Move stuff merged post-0.16 upwards 2019-10-16 16:21:29 +02:00
Brent Yorgey
a58c1a6071
Merge pull request #321 from slotThe/master
Remove redundant do's
2019-10-12 05:59:06 -05:00
slotThe
bcd4dde298 Remove redundant do's 2019-10-11 16:35:54 +02:00
Brent Yorgey
c3bb1cb2e7
Merge pull request #320 from slotThe/master
Remove legacy code regarding fmap
2019-10-09 05:07:15 -05:00
slotThe
30d45f8993 Clean up Control.Monad imports 2019-10-08 11:27:30 +02:00
slotThe
273ae32438 Replace 'join . fmap' with =<< 2019-10-08 11:19:09 +02:00
slotThe
22aebcb26d Replace 'fmap f $ fa' with 'f <$> fa', apply functor laws 2019-10-08 11:13:02 +02:00
slotThe
e8da66e575 Replace liftM with fmap 2019-10-08 10:45:44 +02:00
slotThe
0b26ddf489 Replace liftM2 with liftA2 2019-10-08 10:41:14 +02:00
slotThe
53b57eba14 Replace liftM and fmap with <$> 2019-10-08 10:33:56 +02:00
slotThe
f3024e6779 Remove unnecessary imports of Control.Applicative 2019-10-08 10:21:15 +02:00
Brent Yorgey
f98095d33e
Merge pull request #311 from skewerr/master
Added module X.A.PerWindowKeys
2019-10-07 10:45:29 -05:00
Brent Yorgey
809ba2a8c0
Merge pull request #310 from psibi/named-window
Added 'allApplications' to XMonad.Prompt.Window
2019-10-06 20:35:09 -05:00
Sibi Prabakaran
a8d41df92b Added allApplications to XMonad.Prompt.Window 2019-10-06 10:06:02 +05:30
Brent Yorgey
7100e7db4f
Merge pull request #315 from tidues/master
A New Layout Combinator: TallMastersCombo
2019-10-05 17:52:18 -05:00
Brent Yorgey
6040fe6c8f
Merge pull request #318 from slotThe/master
X.A.Search: Update hoogle URL
2019-10-05 08:05:44 -05:00
Brent Yorgey
b87e801872
Merge pull request #317 from budevg/fix-spelling-mistake
XMonad/Actions/Search: fix spelling mistake
2019-10-05 08:05:10 -05:00
slotThe
48e6bb5529 X.A.Search: Update hoogle URL 2019-10-05 10:30:50 +02:00
Evgeny Budilovsky
3c7d58b836 XMonad/Actions/Search: fix spelling mistake 2019-10-05 09:11:38 +03:00
Wilson Sales
6eae27390d Added module X.A.PerWindowKeys
Allows one to shortcut actions that are performed based on queries.

Signed-off-by: Wilson Sales <spoonm@spoonm.org>
2019-09-30 21:21:46 -03:00
tidues
b43fdcb57f edit CHANGES.md 2019-09-27 16:57:50 -04:00
tidues
599c0f8613 XMonad.Layout.TallMastersCombo v1.0 2019-09-27 16:43:04 -04:00
tidues
6da250003f XMonad.Layout.TallMastersCombo v1.0 2019-09-27 16:36:30 -04:00
Peter Simons
60101b9a70 Bump version number to 0.16 for the upcoming release. 2019-09-22 10:33:26 +02:00
Peter Simons
5f1fc602ab CHANGES.md: document changes from 303f0c24bc36298df6985785891e73cd0ea13e4b 2019-09-22 10:11:10 +02:00
Peter Simons
303f0c24bc cabal.project: the new setlocale version works fine 2019-09-22 10:02:29 +02:00
Peter Simons
8df80e7805 travis.yml: re-generate with the latest version of haskell-ci 2019-09-21 21:10:12 +02:00
Peter Simons
36dba39c44 cabal.project: don't hard-code paths to ../xmonad and ../x11
Not everyone has those repositories checked out at those paths. IMHO, it would
be much better to configure these as "optional-packages". In any case, users
should probably configure those in their cabal.project.local.
2019-09-21 21:07:56 +02:00
Peter Simons
8847b3b2f6 cabal.project: configure allower-newer for setlocale
This allows us to compile with GHC 8.8.1.
2019-09-21 21:03:13 +02:00
Peter Simons
1b061245af xmonad-contrib.cabal: update our tested-with declaration 2019-09-21 21:03:13 +02:00
Peter Simons
94662bffc6 XMonad.Util.Invisible: fix build with GHC 8.8.1
This change needs base-4.9.0.0 or later so that we can
include Control.Monad.Fail. We could jump through hoops to
support older compilers still, but it feels like it's not
worthwhile.
2019-09-21 21:03:13 +02:00
Brent Yorgey
23102a6d5c
Merge pull request #289 from berkeleyinc/improved-left-right-tabbed
Improved tabbedRight and tabbedLeft in XMonad.Layout.Tabbed
2019-09-16 16:47:28 -05:00
Brent Yorgey
728f9bc270
Merge pull request #299 from pkinsky/master
Add configurable border width fields to XMonad.Layout.Decoration.Theme
2019-08-12 08:32:22 -05:00
Brent Yorgey
d9856b955a
Merge pull request #303 from obszczymucha/master
Add SplitShiftDirectional message into BinarySpacePartition layout.
2019-08-12 07:22:52 -05:00
Brent Yorgey
603fc4ccb7
Merge branch 'master' into master 2019-08-12 07:22:39 -05:00
Brent Yorgey
65e7153874
Merge pull request #309 from ryantrinkle/pass-generate-and-copy
Add XMonad.Prompt.Pass.passGenerateAndCopy
2019-08-10 16:45:14 -05:00
Ryan Trinkle
6a0dc1685c Add XMonad.Prompt.Pass.passGenerateAndCopy 2019-08-10 10:25:34 -04:00
Brent Yorgey
41e8708eb5
Merge pull request #308 from kurnevsky/fuzzy-sort
Make fuzzy sort show shorter strings first
2019-08-08 21:45:23 -05:00
Evgeny Kurnevsky
18979de5f6
Make fuzzy sort show shorter strings first. 2019-08-08 09:12:48 +03:00
Brent Yorgey
5ffb4e7f52
Merge pull request #307 from ryantrinkle/pass-traverse-symlinks
Make XMonad.Prompt.Pass traverse symlinks for its tab completion
2019-08-07 22:22:27 -05:00
Ryan Trinkle
52a3800b96 Make XMonad.Prompt.Pass traverse symlinks for its tab completion 2019-08-07 13:09:40 -04:00
Brent Yorgey
dd89eae446
Merge pull request #300 from roosemberth/refocuslast
RefocusLast Module
2019-05-26 20:32:30 -05:00
Obszczymucha
6b68ec5c00 Add SplitShiftDirectional message into BinarySpacePartition layout. 2019-05-26 16:01:06 +10:00
Sibi
db80842e65
Merge pull request #301 from h-jones-uk/master
Fix broken internal Haddock links
2019-05-08 21:04:13 +05:30
Henri Jones
4e4856c722 Fix broken internal Haddock links 2019-05-07 22:32:05 +01:00
Roosembert Palacios
b5eb418fa4
cabal: Export module XMonad.Hooks.RefocusLast
Signed-off-by: Roosembert Palacios <roosembert.palacios@epfl.ch>
2019-05-01 23:53:38 +02:00
L. S. Leary
04b32ae021
X.H.RefocusLast: added action to swap current window with last + minor refactoring. 2019-05-01 23:53:07 +02:00
L. S. Leary
9c6d1e696f
X.H.RefocusLast: added runtime toggle and refactored predicate system. 2019-05-01 16:56:44 +02:00
L. S. Leary
dad911913c
RefocusLast bug fix, extension to support float-only refocusing and
improved support for refocusing on non-current workspaces.
2019-05-01 16:56:39 +02:00
Paul Kinsky
b3f5a09673 record changes 2019-04-17 16:40:48 -07:00
Brent Yorgey
4ad6ecf892
Merge pull request #297 from ajgrf/bg-ratio
Hooks.WallpaperSetter: Preserve aspect ratio while scaling images
2019-04-10 22:07:22 -05:00
Brent Yorgey
fcd296e87a
Merge branch 'master' into bg-ratio 2019-04-10 22:07:06 -05:00
Brent Yorgey
fddd5ea1fe
Merge pull request #298 from orhan89/pass-otp
Support OTP in XMonad.Prompt.Pass
2019-04-05 04:44:09 -05:00
Ricky Hariady
c3cee11ad6 Support OTP in XMonad.Prompt.Pass
update CHANGES.md
2019-04-05 09:31:49 +07:00
Brent Yorgey
22e6d4b017
Merge pull request #296 from ajgrf/adwaita-theme
XMonad.Util.Themes: Add adwaitaTheme and adwaitaDarkTheme
2019-04-02 05:50:26 -05:00
Alex Griffin
fcced8991a Hooks.WallpaperSetter: Preserve aspect ratio while scaling images 2019-03-18 16:32:35 -05:00
Alex Griffin
bfb52a5025 XMonad.Util.Themes: Add adwaitaTheme and adwaitaDarkTheme 2019-03-13 14:48:10 -05:00
Brent Yorgey
c53436f3a6
Merge pull request #178 from bforte/module-MutexScratchpads
add new module X.U.ExclusiveScratchpads
2019-03-06 15:14:51 -06:00
Brent Yorgey
66c1977c29
Merge branch 'master' into module-MutexScratchpads 2019-03-06 15:14:27 -06:00
Brent Yorgey
a18395a13c
Merge pull request #295 from alhirzel/add-isOnAnyVisibleWS
Actions.GroupNavigation: fix bad import
2019-03-03 21:15:56 -06:00
Alex Hirzel
ca69574cfe Actions.GroupNavigation: add CMS import 2019-03-03 10:59:58 -05:00
Alex Hirzel
faa252e309 Actions.GroupNavigation: another import issue 2019-03-03 10:20:22 -05:00
Alex Hirzel
71fec4f61a Actions.GroupNavigation: fix bad import 2019-03-03 10:08:25 -05:00
Brent Yorgey
0301d6e21b
Merge pull request #294 from alhirzel/add-isOnAnyVisibleWS
Add isOnAnyVisibleWS function to Actions.GroupNavigation
2019-03-03 08:57:04 -06:00
Alex Hirzel
0cfe3a288e whitespace reformat in changelog 2019-03-02 09:36:47 -05:00
Alex Hirzel
84c63abda6 Add changelog entry for isOnAnyVisibleWS 2019-03-02 09:36:36 -05:00
Alex Hirzel
e12511c658 Actions.GroupNavigation: move "Utilities" header for documentation 2019-03-02 09:32:16 -05:00
Alex Hirzel
52890f6007 Actions.GroupNavigation: document isOnAnyVisibleWS 2019-02-27 23:08:07 -05:00
Alex Hirzel
51bc32ea75 Actions.GroupNavigation: add isOnAnyVisibleWS 2019-02-27 23:08:07 -05:00
Alex Hirzel
cce7f50372 Actions.GroupNavigation: hlint fixes 2019-02-27 23:08:04 -05:00
Brent Yorgey
ba9b108a68
Merge pull request #263 from bgamari/ewmh-wakeup-reduction
Wakeup reduction in EwmhDesktops
2019-02-27 21:21:37 -06:00
Brent Yorgey
e12c047870 move change from #284 to the right place 2019-02-13 05:54:03 -06:00
Brent Yorgey
2ce876c330
Merge pull request #284 from skewerr/master
X.A.DynamicWorkspaceOrder: add transformation-aware withNthWorkspace
2019-02-13 05:49:42 -06:00
Brent Yorgey
3faa9b2c38
Merge pull request #292 from wz1000/master
Use absolute paths in DynamicProjects
2019-02-13 05:40:18 -06:00
Zubin Duggal
6720eefce7
update CHANGES.md 2019-02-13 16:19:01 +05:30
Zubin Duggal
cf789504e8
Use absolute paths in DynamicProjects 2019-02-13 16:06:10 +05:30
Brent Yorgey
deaaf6b177
Merge pull request #287 from mgsloan/bracket-prompt-resources
Use bracket pattern in XMonad.Prompt
2019-02-12 09:14:02 -06:00
Brent Yorgey
60b35ff431
Merge branch 'master' into bracket-prompt-resources 2019-02-12 09:13:51 -06:00
Brent Yorgey
cd404eb644
Merge pull request #291 from mgsloan/fix-prompt-max-rows-wrap-around-217
Fix XMonad.Prompt wraparound when maxComplRows not Nothing #217
2019-02-12 09:08:23 -06:00
Michael Sloan
d9f43c78d6 Fix XMonad.Prompt wraparound when maxComplRows not Nothing #217 2019-02-10 04:47:16 -08:00
Michael Sloan
b9603a0e10 Also destroy completion window on exceptions #180 2019-02-10 04:18:56 -08:00
Michael Sloan
09a5fa111c Use bracket pattern in XMonad.Prompt 2019-02-10 04:18:30 -08:00
Michael Sloan
41a2db5563 Refactoring: helper for mkXPromptWithReturn and mkXPromptWithModes 2019-02-10 03:51:40 -08:00
Yclept Nemo
1706160b14
Merge pull request #245 from orbisvicis/vimishPrompt
Vimish Prompt
2019-01-26 16:23:49 -05:00
Yclept Nemo
207d5962e2 Vim for 'XMonad.Prompt': backwards compatibility
Colors in 'XPState' continue to use 'XPColor' since it provides a
cleaner interface. For backwards compatibility color changes to
'XPConfig' were reverted. To avoid accessor clashes you'll have to deal
with slightly different names:

| 'XPState'/'XPColor' | 'XPConfig'  |
| ------------------- | ----------- |
| bgNormal            | bgColor     |
| fgNormal            | fgColor     |
| bgHighlight         | bgHLight    |
| fgHighlight         | fgHLight    |
| border              | borderColor |
2019-01-26 15:18:27 -05:00
Yclept Nemo
c7e02726bf Vim for 'XMonad.Prompt': advertise changes 2019-01-26 15:03:18 -05:00
Yclept Nemo
b0d6e0f942 Vim for 'XMonad.Prompt':
A vim-like keymap, yay! And dynamic colors and a reworked event loop.
Also fixes 'showCompletionOnTab' which was broken, and many new or
improved prompt interface functions.

Changes moveWord/moveWord' but updates the old keymaps to retain the
original behavior. See the documentation to do the same to your XMonad
configuration.

P.S. That bug I mention was there before my changes.
2019-01-26 14:49:52 -05:00
Brent Yorgey
a774168415
Merge pull request #264 from namo626/module/TwoPanePersistent
Added module X.L.TwoPanePersistent
2019-01-22 11:15:36 -06:00
Brent Yorgey
17da8bc8ee
Merge pull request #259 from u11gh/passEditPrompt
Add passEditPrompt to Xmonad.Prompt.Pass
2019-01-21 16:49:38 -06:00
Brent Yorgey
c2c0585d7e
Merge branch 'master' into module/TwoPanePersistent 2019-01-21 11:03:26 -06:00
yuri
7a6d24712f Merge branch 'improved-left-right-tabbed' of github.com:berkeleyinc/xmonad-contrib into improved-left-right-tabbed 2019-01-09 07:42:58 +01:00
yuri
13260cae58 Merge branch 'improved-left-right-tabbed' of github.com:berkeleyinc/xmonad-contrib into improved-left-right-tabbed 2019-01-09 07:42:46 +01:00
yuri
07f4ce8029 Merge branch 'improved-left-right-tabbed' of github.com:berkeleyinc/xmonad-contrib into improved-left-right-tabbed 2019-01-09 07:41:49 +01:00
yuri
298cdd6114 improving tabbedRight/tabbedLeft by having their tabs' height set by decoHeight 2019-01-09 07:41:10 +01:00
yuri
36356dd8f5 improving tabbedRight/tabbedLeft by having their tabs' height set by decoHeight 2019-01-09 07:37:03 +01:00
Wilson Sales
dd905d2603 X.A.DynamicWorkspaceOrder: add transformation-aware withNthWorkspace
The user may modify the list of workspace tags that results form
applying the dynamic order. This way one may filter workspaces they
don't want in the order (e.g. "NSP") or apply any transformation he
wishes to the list of tags.
2018-11-08 19:02:59 -02:00
L. S. Leary
dda242a459 Relocate change in CHANGES.md. 2018-10-18 05:49:30 +13:00
Leary
204524328d
Merge pull request #282 from anthraxx/fixup/prompt-fuzzymatch
XMonad.Prompt sorter for FuzzyMatch
2018-10-18 05:36:51 +13:00
Peter Simons
81a980823e Bump version number and update the changelog. 2018-09-30 13:38:33 +02:00
Peter Simons
677e64dcf6 travis.yml: enable builds with ghc 8.6.1 2018-09-28 11:50:27 +02:00
Peter Simons
c5c3fec26c inhale: avoid monadic pattern matching in pure code
These changes avoid the need for having a MonadFail instance for Decoder.
2018-09-28 11:47:11 +02:00
Peter Simons
59fbcdfba9 dumpExcept: avoid monadic pattern matching in pure code
These changes avoid the need for having a MonadFail instance for Decoder.
2018-09-28 11:46:33 +02:00
Peter Simons
778e32305f dumpString: avoid monadic pattern matching in pure code
These changes avoid the need for having a MonadFail instance for Decoder.
2018-09-28 11:45:39 +02:00
Peter Simons
5334130bf7 historyCompletion: prefer Data.Map.foldr over deprecated fold function 2018-09-28 11:44:49 +02:00
Peter Simons
aca76956ba xmonad-contrib.cabal: support containers-0.6 from ghc-8.6.x
The build works fine with the new version.
2018-09-27 16:01:43 +02:00
anthraxx
6dcc36c904 XMonad.Prompt.FuzzyMatch: favor modern windowPrompt in docs
Use modern windowPrompt in docs instead of the deprecated
windowPromptGoto.
2018-09-25 22:16:06 +02:00
anthraxx
705494eb4c XMonad.Prompt.FuzzyMatch: fix missing docs code block 2018-09-25 22:16:06 +02:00
Sergey Alirzaev
6b9fb096d6 employ the prompt sorter for the window selector
as in https://markmail.org/thread/kgrybzqarqzqiige
2018-09-25 22:15:45 +02:00
L. S. Leary
02278e5bbb Merge pull request #281 from LSLeary/purex. 2018-09-26 01:57:04 +12:00
L. S. Leary
4dcc78b59e Added the X.U.PureX module and generalised type signatures in
`X.U.ExtensibleState`.
2018-09-19 02:35:55 +12:00
L. S. Leary
e7c92bc628 Merge pull request #276 from LSLeary/groups. 2018-09-16 16:22:49 +12:00
L. S. Leary
dba402aba4 X.L.G.Helpers: replace (deprecated) send with sendMessageB as we
may now need the refresh it can perform.
2018-09-16 13:52:43 +12:00
L. S. Leary
8ea584cdb9 X.L.Groups:
* Rewrite the `refocus` function such that it modifies the windowset
   without performing a refresh, instead returning the given layout
   object when one is required.
 * Message handling which uses `refocus` has been rewritten to less
   frequently request unnecessary refreshes.
2018-09-16 13:52:43 +12:00
L. S. Leary
6ea4ee8fbd X.A.MessageFeedback: update manual Message handlers following
changes to `X.O.sendMessage`.
2018-09-16 13:52:43 +12:00
L. S. Leary
f1c7b09656 Core xmonad currently does not build against sub-8 GHC; exclude from travis. 2018-09-16 13:50:38 +12:00
Brent Yorgey
13e5429dc2
Merge pull request #279 from orbisvicis/fullscreenFix
X.L.Fullscreen: 'FullscreenFull' hides all windows
2018-09-11 05:56:11 -05:00
Yclept Nemo
8ec1efd472 X.L.Fullscreen: 'FullscreenFull' hides all windows
The 'FullscreenFull' layout modifier hides all windows fully covered by
the fullscreen area, even when no fullscreen windows are present. Fix
this, closing #278. Also switch to 'X.U.Rectangle'.
2018-09-05 07:47:25 -04:00
Peter Simons
337ca60f76
Merge pull request #277 from NickHu/patch-1
Typo in PhysicalScreens.hs
2018-08-08 15:09:27 +02:00
Nick Hu
62d161ca4e
Typo in PhysicalScreens.hs
The documentation has a typo so copying and pasting the example does not work.
2018-08-08 16:53:44 +09:00
Peter Simons
16836b6f91
Merge pull request #275 from LSLeary/point14
0.14
2018-07-31 09:54:42 +02:00
L. S. Leary
065c305fed version bump to 0.14 2018-07-30 23:44:56 +12:00
L. S. Leary
9a80f2d891 Clean up CHANGES.md:
* 0.14 (Not Yet) -> 0.14
 * Removed reverted changes left over from #128 & #161
 * Fixed some typos
 * Made markup more consistent.
2018-07-30 23:44:56 +12:00
LSLeary
a1111a3418
Merge pull request #274 from LSLeary/travis 2018-07-30 23:43:49 +12:00
L. S. Leary
fdc3f78588 Drop GHC 7.6 compatibility. 2018-07-30 22:50:03 +12:00
L. S. Leary
259c170ac9 Travis-CI:
* don't constrain to precise
 * add libxrandr dependency
 * test against new GHC versions
 * install xmonad from git before cabal can install it from hackage
2018-07-30 22:50:03 +12:00
L. S. Leary
4f23016e54 GHC 7.8 compatibility:
* Explicitly import pure, (<$>), (<*>) and (<$) from Control.Applicative.
 * Use DeriveDataTypeable pragma.
 * Remove type signature from pattern synonym.
2018-07-30 22:50:03 +12:00
LSLeary
4ec78aa3f2
Merge pull request #273 from orbisvicis/reSpaced
reSpaced: Compatibility v2
2018-07-30 22:12:55 +12:00
L. S. Leary
ea39960bd4 Merge pull request #261 from orbisvicis/messaging 2018-07-30 22:05:48 +12:00
L. S. Leary
d015416573 Revert "Merge pull request #256 from LSLeary/refocuslast"
This reverts commit b0f9197e048c3bdf10266e9a965a6803952ad20a, reversing
changes made to 6b8a8f9c8db5ab279d38ecd3aaaba6116ee1d0b4.

Not for 0.14.
2018-07-30 16:53:44 +12:00
Brent Yorgey
c90241807a
Merge pull request #269 from MichielDerhaeg/belgianKeys
add support for belgian keyboards in XMonad.Config.Azerty
2018-07-27 11:40:50 -05:00
Brent Yorgey
0731407537
Merge pull request #270 from lucianposton/doc
X.L.MultiToggle: Doc improvement
2018-07-27 11:39:01 -05:00
Brent Yorgey
a6a69394be
Merge pull request #271 from lucianposton/tbf
Add the X.L.MultiToggle.TabBarDecoration module
2018-07-27 11:38:35 -05:00
Brent Yorgey
0fb36d418b
Merge pull request #272 from lucianposton/darktheme
X.U.Themes: Add darkTheme
2018-07-27 11:37:19 -05:00
Yclept Nemo
3e68036360 XMonad.Layout.Spacing: extreme compatibility
* Reintroduce the original 'ModifySpacing' type and constructor as
  deprecated; the new 'ModifySpacing' type was renamed to
  'SpacingModifier'. Suggested by @LSLeary.
* Types 'SpacingWithEdge', 'SmartSpacing', and 'SmartSpacingWithEdge'
  have been reintroduced as deprecated type synonyms of 'Spacing'. Work
  by @LSLeary.

Also 'borderMap' is now exported; it might be useful.
2018-07-19 15:06:35 -04:00
Lucian Poston
8109a605fd
X.U.Themes: Add darkTheme 2018-07-17 19:17:45 -07:00
Lucian Poston
048bb42e7a
Add the X.L.MultiToggle.TabBarDecoration module 2018-07-16 19:51:14 -07:00
Lucian Poston
b9ef1649b0
X.L.MultiToggle: Doc improvement 2018-07-15 17:18:12 -07:00
LSLeary
a4b430bfa7
Merge pull request #266 from LSLeary/master
Fix to X.L.Grid as per issue #223
2018-07-09 05:34:45 +12:00
Michiel Derhaeg
d0e283d175 add support for belgian keyboards in XMonad.Config.Azerty 2018-07-05 22:22:28 +02:00
L.S. Leary
90e54a9abb Fix to X.L.Grid as per issue #223; it will no longer calculate more columns than there are windows. 2018-07-02 18:20:13 +12:00
namo626
913183463a added module X.L.TwoPanePersistent
updated CHANGES.md
2018-06-22 18:40:14 -04:00
Ben Gamari
92fe5f34ff EwmhDesktops: Cache properties independently 2018-06-19 12:39:24 -04:00
Ben Gamari
8c309f87b8 EwmhDesktops: Cache active window as well 2018-06-19 11:54:20 -04:00
Ben Gamari
f6f925c823 Use extensible state instead of IORef 2018-06-19 11:54:18 -04:00
Ben Gamari
203e63b055 EwmhDesktops: Only update properties when something changed 2018-06-19 10:03:20 -04:00
Ben Gamari
e814f748b5 EwmhDesktops: Cache property values to avoid needless property changes 2018-06-19 01:47:08 -04:00
Yclept Nemo
9fcea6cb55
Merge pull request #252 from orbisvicis/swapPromote
Swap Promote
2018-06-15 12:29:14 -04:00
Yclept Nemo
7e54a9d90b 'XMonad.Actions.SwapPromote': advertise changes...
... and expose the new module.
2018-06-15 12:26:28 -04:00
Yclept Nemo
66281f07f1 'XMonad.Actions.SwapPromote': 'stackMerge' fixes
Make 'stackMerge' safer by implicitly appending any leftover elements
rather than discarding them. Otherwise on refresh the missing windows
will be deleted. This is only necessary if the stack has been shortened
- i.e. not required by this module.

Minor miscellaneous documentation fixes.
2018-06-15 12:26:28 -04:00
Yclept Nemo
56a76df88f 'XMonad.Actions.SwapPromote': new module
Module for tracking master window history per workspace, and associated
functions for manipulating the stack using such history.
2018-06-15 12:26:28 -04:00
Yclept Nemo
b6a09f5d80
Merge pull request #242 from orbisvicis/borderControl
Border Control
2018-06-15 12:19:07 -04:00
Yclept Nemo
2fde742e7a 'XMonad.Layout.Spacing': compatibility tweaks
* All the backwards-compatibility functions now accept `Int` rather than
  `Integer`: `spacing`, `spacingWithEdge`, `smartSpacing`,
  `smartSpacingWithEdge`, `setSpacing`, and `incSpacing`. Work done by
  @LSLeary.
* Introduce the new functions `setScreenWindowSpacing`,
  `incScreenWindowSpacing`, `decScreenWindowSpacing`. Unlike their
  original `setSpacing`, `incSpacing` counterparts, these refresh no
  more than once. Requires `sendMessages` from my PR of
  `XMonad.Actions.MessageFeedback`. Suggestion by @LSLeary and
  implemented so any combination of messages can be sent without
  triggering unnecessary refreshes.
2018-06-14 13:10:19 -04:00
Yclept Nemo
8ee2e39fb2 'XMonad.Actions.MessageFeedback': standardize
- Follow the naming conventions of `XMonad.Operations`. Functions returning
  `X ()` are named regularly (previously these ended in underscore) while
  those returning `X Bool` are suffixed with an uppercase 'B'.

- Provide all `X Bool` and `SomeMessage` variations for `sendMessage` and
  `sendMessageWithNoRefresh`, not just `sendMessageWithNoRefreshToCurrent`
  (renamed from `send`).

- The new `tryInOrderB` and `tryMessageB` functions accept a parameter of
  type `SomeMessage -> X Bool`, which means you are no longer constrained
  to the behavior of the `sendMessageWithNoRefreshToCurrent` dispatcher.

- The `send*Messages*` family of funtions allows for sequencing arbitrary
  sets of messages with minimal refresh. It makes little sense for these
  functions to support custom message dispatchers.

- Remain backwards compatible. Maintain deprecated aliases of all renamed
  functions:
  - `send`          -> `sendMessageWithNoRefreshToCurrentB`
  - `sendSM`        -> `sendSomeMessageWithNoRefreshToCurrentB`
  - `sendSM_`       -> `sendSomeMessageWithNoRefreshToCurrent`
  - `tryInOrder`    -> `tryInOrderWithNoRefreshToCurrentB`
  - `tryInOrder_`   -> `tryInOrderWithNoRefreshToCurrent`
  - `tryMessage`    -> `tryMessageWithNoRefreshToCurrentB`
  - `tryMessage_`   -> `tryMessageWithNoRefreshToCurrent`
2018-06-13 15:26:18 -04:00
Yclept Nemo
9d342cddb7 'XMonad.Layout.NoBorders': document upgrade path
Document upgrade path for 'hiddens', which added a 'Rectangle'
parameter.
2018-06-10 19:45:17 -04:00
Yclept Nemo
0c1a6c25f6 'XMonad.Layout.NoBorders': advertise changes 2018-06-10 18:12:21 -04:00
Yclept Nemo
c6cdb77e3b 'XMonad.Layout.NoBorders': various improvements:
The layout now maintains a list of windows that never have borders, and
a list of windows that always have borders. Use 'BorderMessage' to
manage these lists and the accompanying event hook ('borderEventHook')
to remove destroyed windows from them. Also provides the 'hasBorder'
manage hook.

Two new conditions have been added to 'Ambiguity': 'OnlyLayoutFloat' and
'OnlyLayoutFloatBelow'; 'OnlyFloat' was renamed to 'OnlyScreenFloat'.
See the documentation for more information.
2018-06-10 18:06:00 -04:00
Brent Yorgey
e0b1954e62
Merge pull request #254 from mimi1vx/patch-1
Allow build with X11-1.9
2018-06-09 07:43:49 -05:00
Brent Yorgey
178ec86cc6
Merge pull request #257 from skewerr/master
Added two actions to X.A.DynamicWorkspaceOrder
2018-06-09 07:37:38 -05:00
Brent Yorgey
b0f9197e04
Merge pull request #256 from LSLeary/refocuslast
RefocusLast
2018-06-09 07:34:22 -05:00
L. S. Leary
d7461c037e Added the X.H.RefocusLast module. 2018-06-06 18:43:28 +12:00
Ulf Jasper
ed32ccd080 Add passEditPrompt to Xmonad.Prompt.Pass 2018-06-05 19:34:06 +02:00
Brent Yorgey
6b8a8f9c8d add X.U.Rectangle to exposed-modules 2018-06-04 14:28:33 -05:00
Brent Yorgey
cfe7a90d4a
Merge pull request #244 from orbisvicis/rectangle
Rectangle
2018-06-04 14:27:59 -05:00
Brent Yorgey
44306eb0ab
Merge branch 'master' into rectangle 2018-06-04 14:27:11 -05:00
Brent Yorgey
18eb79ce73 add X.L.BinaryColumn to exposed-modules
Also fix typo in CHANGES.md. See #233.
2018-06-04 14:24:18 -05:00
Brent Yorgey
3f54045af2
Merge pull request #253 from LSLeary/statefull
StateFull: Fixing Full (and other layouts we lie to)
2018-06-04 14:18:31 -05:00
Brent Yorgey
22345dce9f
Merge pull request #248 from jktomer/master
Fullscreen.hs: don't lay out windows obscured by fullscreen
2018-06-04 14:12:28 -05:00
Brent Yorgey
bc63ff3f0d
Merge pull request #243 from orbisvicis/reSpaced
reSpaced
2018-06-04 13:59:33 -05:00
Brent Yorgey
83e421c495
Merge branch 'master' into reSpaced 2018-06-04 13:59:21 -05:00
L. S. Leary
c4c007806c Added the X.L.StateFull module providing the StateFull layout and the FocusTracking layout transformer. 2018-05-29 22:58:51 +12:00
spoonm
635a9dee4c
Added updateName and removeName to X.A.DynamicWorkspaceOrder
This adds the possibility to maintain the ordering of workspaces after
they are renamed and to remove them from sorting when they are deleted.
2018-05-21 16:22:52 -03:00
L. S. Leary
0cd4690f9b Added findS/Z and reverseS/Z to X.U.Stack. 2018-05-18 11:04:09 +12:00
Brent Yorgey
d3d0818e9b
Merge pull request #246 from orbisvicis/xmobar
Xmobar
2018-05-17 16:47:19 -05:00
Ondřej Súkup
d3ae0eeac2
Allow build with X11-1.9 2018-05-15 13:02:38 +02:00
Brent Yorgey
295adf056e
Merge pull request #250 from LSLeary/master
X.P.FuzzyMatch: Relocate imports so that haddock generation succeeds.
2018-05-08 21:33:09 -05:00
L. S. Leary
56f7b3acb3 X.P.FuzzyMatch: Relocate imports so that haddock generation succeeds. 2018-05-08 03:29:46 +12:00
Brent Yorgey
9a68684ec1
Merge pull request #233 from ideasman42/layout-binary-column
Add BinaryColumn layout
2018-05-07 06:02:28 -05:00
Brent Yorgey
54ee8933ee
Merge pull request #241 from miguelclean/master
Added pretty printer for empty visible workspaces (wrapped in Maybe)
2018-04-24 15:58:13 -05:00
jktomer
d338e11110 Fullscreen.hs: don't lay out windows obscured by fullscreen
There's no reason to return a rectangle for any window that is totally
obscured by a full-screen window, and not doing so has the nice property that
when hidden windows' borders overlap with a full-screen window's, the user
will not be confused by overlapping partially-drawn borders. It also makes the
Fullscreen modifiers combine much better with smartBorders.
2018-04-24 07:06:23 -07:00
Brent Yorgey
09426e9d71
Merge pull request #239 from marcsaegesser/SpawnOnceEnhancements
Add spawnOnOnce and related functions.
2018-04-21 11:47:21 -05:00
Yclept Nemo
2c53d507ee 'XMonad.Layout.Spacing': backwards compatibility 2018-04-21 11:43:53 -04:00
Yclept Nemo
19a020837d 'XMonad.Layout.Spacing': advertise changes 2018-04-20 12:55:08 -04:00
Yclept Nemo
fdccc873de 'XMonad.Layout.Spacing': the finished product.
Both screen and window borders can now be disabled. Implement missing
messages. The layout now handles windows that are displayed but not part
of the stack, such as those created by 'XMonad.Layout.Decoration'.
Several additional fixes.
2018-04-20 12:55:08 -04:00
Yclept Nemo
f1ed0a5edb 'Layout.Spacing': Improve the smart screen border:
The 'smartBorder' now depends on the window/rectangle list resulting
from 'runLayout' rather than the stack, which means that the child
layout will always be called with the screen border. If only a single
window is displayed, it will be expanded into the original layout
rectangle.
2018-04-20 12:55:08 -04:00
Yclept Nemo
6ae7c2c8b4 Rewrite of 'XMonad.Layout.Spacing':
* Independent screen/window borders
* Configurable top/bottom/right/left borders
2018-04-20 12:55:08 -04:00
Yclept Nemo
108431d03d 'XMonad.Util.Rectangle': advertise changes 2018-04-20 12:54:09 -04:00
Yclept Nemo
31bfcc217f 'XMonad.Util.Rectangle': 'withBorder' fixes
Fix handling of negative borders in 'withBorder'.
2018-04-20 12:54:09 -04:00
Yclept Nemo
cc00a93f1a 'XMonad.Util.Rectangle': new module
A new module for handling pixel rectangles.
2018-04-20 12:54:09 -04:00
Yclept Nemo
26d6bde9c3 'XMonad.Hooks.DynamicLog': advertise changes 2018-04-20 12:52:22 -04:00
Yclept Nemo
348861da00 'XMonad.Hooks.DynamicLog': xmobar tags
Support xmobar's <action> and <raw> tags.
2018-04-20 12:52:22 -04:00
Miguel
670eb3bc60 Added pretty printer for empty visible workspaces
Simple extensions of the pretty printer to differentiate between empty
and non-empty visible workspaces. Analogical to the existing
functionality for hidden workspaces. Particularly useful if some
displays managed by xmonad are turned off temporarily.

The new 'ppVisibleNoWindows' function was wrapped in a Maybe data type.
Its value dafaults to 'Nothing' and 'ppVisible' is used as fallback.
2018-04-18 11:36:46 +02:00
Campbell Barton
869311090c Correct docs 2018-04-11 07:58:11 +02:00
Brent Yorgey
5f2afb08e9
Merge pull request #240 from ae-g-i-s/more-dzen-options
Implement additional options for Dzen
2018-04-10 23:08:34 -05:00
Brent Yorgey
1ce035ee7d
Merge pull request #232 from l29ah/fuzzymatch
+ FuzzyMatch by @nzeh
2018-04-10 20:56:08 -05:00
Brent Yorgey
41e6343a7e
Merge pull request #237 from ccrusius/master
Add a `ModifyX` message to `Groups`
2018-04-10 20:43:28 -05:00
ae-g-i-s
b20cf7c1e6 Implement additional options for Dzen 2018-04-04 14:25:42 +02:00
Brent Yorgey
5cdf4e408c
Merge pull request #234 from vmandela/dzen
DynamicLog: add dzenWithFlags function
2018-04-02 10:14:50 -05:00
Marc A. Saegesser
9c4dad9946 Add spawnOnOnce and related functions. 2018-03-30 13:43:05 -05:00
geekosaur
13e37b964e
Merge pull request #238 from IvanMalison/remove_gnome_panel_ewmh_code
Remove gnome-panel hack from ewmh desktop code
2018-03-28 22:01:02 -04:00
Ivan Malison
a512351d3a
Remove gnome-panel hack from ewmh desktop code
Fixes #216
2018-03-28 15:06:33 -07:00
Venkateswara Rao Mandela
82aba52541 DynamicLog: add dzenWithFlags function
This commit adds `dzenWithFlags` function for users who wish to change the
command line arguments passed to `dzen`. The behaviour of `dzen` function is
kept the same.
2018-03-27 20:09:34 +05:30
Cesar Crusius
62e04de68e
Add a ModifyX message to Groups
The `group3` addition I made in a previous commit enabled one to go so
far, but then quickly hit some walls due to non-exported symbols from
`XMonad.Layout.Groups`.

This commit removes `group3`, as it would hardly be useful to anybody,
and introduces a new `ModifyX` message that allows the modifying
function to return a `Groups` layout inside the `X` monad. Here's an
example on why this is useful:

Say you have a master layout with tabbed sub-layouts, and you have
terminal windows sprinkled around these sub-layouts. You now want to
gather all of them into a single tabbed sub-layout, effectively
implementing a "tabbed terminal" (or browser, or editor, etc). With
functionality like this, `XMonad` can become a unified multi-window
application manager: one does not need tabbed browsers, terminals,
etc.

In order for this to be possible, however, the modifier function needs
to be able to query for things like the window class name with
`runQuery`, and that in turn means it has to operate inside the `X`
monad. This is only possible if `Groups` accepts the modifier
introduced in this commit.

I bet many other uses for a `ModifierX` message can be found. I have
the functionality of the example I gave implemented and working with
this change, since it was my motivation to get it done (and I must say
it is quite sweet to have tabbed window unification).
2018-03-21 21:16:06 -07:00
Brent Yorgey
2448a2a6a6
Merge pull request #236 from MichielDerhaeg/ghc84-compat
update to work with GHC 8.4.1
2018-03-21 15:26:15 -05:00
Michiel Derhaeg
86595e193e update to work with GHC 8.4.1 2018-03-20 22:06:18 +01:00
Campbell Barton
236ca9959d Add BinaryColumn layout
This is similar to 'Column' layout with some differences.

- Add/remove windows keeps window bounds.
- Enforce minimum window size.
- Negative scale can be used to increase the size of the last window
  instead of the master window.
2018-03-11 20:45:20 +11:00
Sergey Alirzaev
d5d82267c5
+ FuzzyMatch by @nzeh
Provides a predicate 'fuzzyMatch' that is much more lenient in matching
completions in XMonad.Prompt than the default prefix match.  Also provides
a function 'fuzzySort' that allows sorting the fuzzy matches by "how well"
they match.

Not sure why wasn't it accepted.
Discussion: https://markmail.org/thread/kgrybzqarqzqiige
2018-03-10 09:07:00 +03:00
Brent Yorgey
3d3e898166
Merge pull request #229 from ccrusius/master
Add three-dimensional group layout
2018-03-06 20:52:56 -06:00
Brent Yorgey
e03844dd20
Merge pull request #230 from IamfromSpace/add-layout-multi-dishes-squashed
Add a new layout MultiDishes
2018-03-06 20:50:15 -06:00
Nathan Fairhurst
b42a1392da Add a new layout MultiDishes, which behaves like Dishes, but allows a configurable number windows within each stack. 2018-03-04 21:03:45 -08:00
Brent Yorgey
0bde284129
Merge pull request #219 from LSLeary/master
New sideNavigation strategy for X.A.Navigation2D
2018-03-02 05:55:33 -06:00
ccrusius
1c52484753
Add three-dimensional group layout
This is as per the work done in
http://lynnard.me/blog/2013/12/30/more-xmonad-goodies/, where the
functionality is explained in detail.

This also fixes #214. The original suggestion in that bug report is
not enough. Even if we export `gen` and `Uniq`, we would still have to
export the `Groups` type constructor. I thought it better to simply
allow the user to create a three-dimensional group instead.
2018-02-28 18:37:24 -08:00
Brent Yorgey
d7c6ee940b
Merge pull request #228 from codetriage-readme-bot/codetriage-badge
Add CodeTriage badge to xmonad/xmonad-contrib
2018-02-14 22:13:46 -06:00
Brent Yorgey
a96d1d0bb7
Merge pull request #225 from maciasello/master
Add appendFilePrompt' to allow transforming text before appending
2018-02-12 09:59:40 -06:00
codetriage-readme-bot
a590034a23 Add CodeTriage badge to xmonad/xmonad-contrib
Adds a badge showing the number of people helping this repo on CodeTriage.

[![Open Source Helpers](https://www.codetriage.com/xmonad/xmonad-contrib/badges/users.svg)](https://www.codetriage.com/xmonad/xmonad-contrib)

## What is CodeTriage?

CodeTriage is an Open Source app that is designed to make contributing to Open Source projects easier. It works by sending subscribers a few open issues in their inbox. If subscribers get busy, there is an algorithm that backs off issue load so they do not get overwhelmed

[Read more about the CodeTriage project](https://www.codetriage.com/what).

## Why am I getting this PR?

Your project was picked by the human, @schneems. They selected it from the projects submitted to https://www.codetriage.com and hand edited the PR. How did your project get added to [CodeTriage](https://www.codetriage.com/what)? Roughly 7 months ago, [wisn](https://github.com/wisn) added this project to CodeTriage in order to start contributing. Since then, 2 people have subscribed to help this repo.

## What does adding a badge accomplish?

Adding a badge invites people to help contribute to your project. It also lets developers know that others are invested in the longterm success and maintainability of the project.

You can see an example of a CodeTriage badge on these popular OSS READMEs:

- [![](https://www.codetriage.com/rails/rails/badges/users.svg)](https://www.codetriage.com/rails/rails) https://github.com/rails/rails
- [![](https://www.codetriage.com/crystal-lang/crystal/badges/users.svg)](https://www.codetriage.com/crystal-lang/crystal) https://github.com/crystal-lang/crystal

## Have a question or comment?

While I am a bot, this PR was manually reviewed and monitored by a human - @schneems. My job is writing commit messages and handling PR logistics.

If you have any questions, you can reply back to this PR and they will be answered by @schneems. If you do not want a badge right now, no worries, close the PR, you will not hear from me again.

Thanks for making your project Open Source! Any feedback is greatly appreciated.
2018-02-11 13:51:19 -06:00
Maciej Ligenza
ff3e415b9d Add appendFilePrompt' to allow transforming text before appending to file 2018-01-21 02:12:24 +01:00
Brent Yorgey
3044577a4c
Merge pull request #182 from strokyl/157_allow_custom_physical_screen_order
157 allow user to customize screen ordering
2018-01-18 23:43:25 -06:00
Luc DUZAN
756507e2b6 157 allow user to customize screen ordering
Now when using getSortByXineramaPhysicalRule and all helper given by
Actions.PhysicalScreens the user have to provide a screen comparator that can
compare screen using their id or/and their coordinate.
2018-01-14 22:13:31 +01:00
L.S. Leary
4a98a27950 Added navigation strategy sideNavigation and parameterised variant sideNavigationWithBias to X.A.Navigation2D. 2017-12-16 17:37:52 +13:00
Brent Yorgey
51857a1a20
Merge pull request #218 from LSLeary/master
Extended the sendMessage interface of X.L.Gaps to allow arbitrary modifications
2017-11-28 23:58:33 -05:00
L.S. Leary
cc9622ab28 Extended the sendMessage interface of X.L.Gaps to allow arbitrary modifications to the GapSpec. 2017-11-22 07:58:41 +13:00
Brent Yorgey
89a0fdf7fe Merge pull request #181 from NickHu/master
Make UnicodeData.txt path configurable, remove unsafePerformIO
2017-10-16 00:18:43 -04:00
Nick Hu
50b2abce5b Merge branch 'master' into master 2017-10-09 12:52:41 +01:00
Brent Yorgey
dc30cbd2f9 Merge pull request #197 from NickHu/pass
Add facility for automatically typing passwords via XMonad.Prompt.Pass, and handle special characters in pass labels
2017-10-07 16:43:21 -04:00
Peter J. Jones
6b5d08c46b Merge pull request #212 from LSLeary/master
Generalised hybridNavigation to hybridOf
2017-09-26 11:49:26 -07:00
L.S. Leary
c778b9c2af Generalised (and hence deprecated) hybridNavigation to hybridOf so that users can choose order of preference of navigation strategies. 2017-09-27 07:25:35 +13:00
Peter J. Jones
823362ce79 Update .travis.yml 2017-09-26 10:53:02 -07:00
Nick Hu
ecd0048d83 Make UnicodeData.txt path configurable, remove unsafePerformIO in favour
of ExtensibleState

Add facility to type Unicode character via xdotool
2017-08-19 00:27:52 +01:00
Nick Hu
8daa84375b Pipe password to xdotool via undocumented --file to prevent snatch
from `ps`, and also some backwards compatibility.
2017-08-17 21:46:41 +01:00
Nick Hu
cee5aa2a58 Adds a new function to spawn a pass prompt which will use xdotool to
type in a password, bypassing the clipboard. Also incorporate some shell
escapes to properly handle pass labels with spaces and special
characters in them.
2017-08-17 21:46:41 +01:00
Brent Yorgey
676d83ce83 Merge pull request #196 from Ongy/sessionstartup
Add XMonad.Util.SessionStart
2017-07-25 11:44:33 -04:00
Brent Yorgey
6b1f755e20 Merge pull request #206 from foreverbell/master
Export XMonad.Prompt.insertString.
2017-07-24 17:41:51 -04:00
Brent Yorgey
df88bc62d7 Merge pull request #189 from skewerr/master
Added functions to perform actions with the first minimized window.
2017-07-24 11:37:42 -04:00
Brent Yorgey
dcc2a69fbc Merge branch 'master' into master 2017-07-24 11:37:32 -04:00
foreverbell
ff3ecd2032
Update CHANGES.md 2017-07-23 00:59:02 +08:00
foreverbell
96e9cab753
Export XMonad.Prompt.insertString. 2017-07-23 00:52:43 +08:00
Brent Yorgey
97daafa723 Merge pull request #205 from Gekkio/fix-gnome-config-mod-shift-q
Fix Gnome config modm+shift+Q logout command
2017-07-17 17:40:29 -04:00
Joonas Javanainen
26690e2d0b
Fix Gnome config modm+shift+Q logout command
The --kill option was deprecated in 2.23.x (year 2008):
c91d138b33/NEWS (L1843)

gnome-session-save was renamed to gnome-session-quit in 2.91.x (year 2011):
c91d138b33/NEWS (L988)
2017-07-16 15:04:00 +03:00
Brent Yorgey
dc04c3821c Merge pull request #200 from xrvdg/readme
README.md: Update links and add contributing info.
2017-07-10 11:44:34 -04:00
Brent Yorgey
430942e981 Merge pull request #201 from xrvdg/commands-dmenulike
X.A.Commands: Parameterize runCommand to accept dmenu-like launchers.
2017-07-10 11:41:17 -04:00
Brent Yorgey
62028bbff7 Merge pull request #202 from xrvdg/spacing-gaps-documentation
X.L.Spacing + X.L.Gaps: add mutual hyperlink
2017-07-10 11:37:17 -04:00
Brent Yorgey
4719dfe260 Merge pull request #190 from crocket/master
Replace X with MonadIO in XMonad.Util.Dmenu
2017-07-10 11:35:49 -04:00
Markus Ongyerth
b1f28e64d7 Add -dock to dzen command 2017-07-08 08:37:35 +02:00
crocket
7930151604 Make XMonad.Util.Dmenu.menuArgs compatible with GHC < 7.10
menuArgs breaks compilation on GHC < 7.10 because it uses fmap but
only has a MonadIO constraint.
Functor was not a superclass of Monad until GHC 7.10.
2017-07-08 08:16:14 +09:00
Xander Rémon van der Goot
cad6bb7769 X.L.Spacing + X.L.Gaps: add mutual hyperlink
These layout have different applications but their names could cause some
confusion since the module names could just as well be swapped. To support this claim,
what we call "spacing" is named "gaps" in i3wm (i3-gaps). Therefore hyperlinks have
been added to inform the reader of the existence of the other module.
2017-07-03 21:27:58 +02:00
Xander Rémon van der Goot
d5dd9329b5 X.A.Commands: Parameterize runCommand to accept dmenu-like launchers.
The X.U.Dmenu library has support to run dmenu-like launchers, but X.A.Commands
has the use of dmenu hardcoded. This commit makes it possible to use other
launchers without duplicating existing code.
2017-07-03 19:41:11 +02:00
xrvdg
1b1a0eeada README.md: Update links and add contributing info.
Firstly, the links are updated to point to Hackage rather than xmonad.org since not all redirect work correctly. For example the link to developing documentation went to the main XMonad's Hackage page rather then XMonad.Docs.Extending on Hackage.

Secondly, the links are changed such that their [id]-tag isn't showing.

Lastly, a link to XMonad's contributing.md has been added.
2017-07-03 17:53:50 +02:00
Markus Ongyerth
c8ce8dcd41 Add XMonad.Util.SessionStart
This module provides a way to query the session startup.
Currently the flag has to be set by calling setSessionStarted in
the startupHook. The goal would be to merge this into xmonad at some
point and set the flag when the state file is read in, and remove the
need to manually set it.
2017-06-25 12:15:17 +02:00
spoonm
8266feba95 Added withFirstMinimized and withFirstMinimized'.
Also changed the order of the `L.intersect` line to prevent the map key ordering from changing the minimizedStack.
2017-06-17 10:20:49 -03:00
crocket
3282fb420d Replace X with MonadIO in XMonad.Util.Dmenu
MonadIO is compatible with xfork which prevents dmenu prompts from
freezing XMonad.
Without xfork, if I try to give focus to another window while dmenu is
waiting, XMonad freezes until I kill dmenu in virtual terminal or ssh
session.
2017-06-06 10:17:00 +09:00
Peter J. Jones
12227d37ca Merge pull request #186 from ankaan/multicolumns-layouthints-windoworderfix
Fix render order of LayoutHints and MultiColumns
2017-05-24 16:52:41 -07:00
Anders Engström
cff3343a8c Fix render order of LayoutHints and MultiColumns
Before this fix, when using layoutHintsToCenter together with
MultiColumns, in certain situations XMonad would render the border of
the focused window below a border of unfocused windows. This looks odd
and is here fixed by changing MultiColumns to always place the focused
window in front (even though they should not really overlap) and making
LayoutHints preserve the order returned from the underlying layout,
except for the focused window that is placed on top.

This is a good idea since layoutHintsToCenter requires the focused
window to be on top for good rendering, even if that is not really
required when the underlying layout is used on its own. This way
layoutHintsToCenter requires less of the layout that is modified and
MultiColumns is more compatible with future layout modifiers that are
not so considerate.
2017-05-24 22:18:34 +02:00
Adam Plaice
a5c5c52745 Improve conversion of Char to KeySym in XMonad.Util.Paste 2017-05-23 03:05:16 +01:00
bforte
2314dd628a reimplemented with X.A.Minimize 2017-05-10 00:57:49 +02:00
Bruce Forte
95cd118c9a forgot importing <$> 2017-05-07 14:15:49 +02:00
Bruce Forte
53481b2269 Update xmonad-contrib.cabal 2017-05-07 14:01:38 +02:00
Bruce Forte
c1c7c30532 renamed the module to X.U.ExclusiveScratchpads 2017-05-07 14:00:40 +02:00
Bruce Forte
617099badd Update CHANGES.md 2017-05-07 13:38:34 +02:00
Bruce Forte
b05f5f12cf import (<$>) because travis failed 2017-05-06 04:12:44 +02:00
bforte
270ca2da23 add new module X.U.MutexScratchpads 2017-05-06 00:37:28 +02:00
Daniel Wagner
ade890ac63 Merge pull request #172 from bforte/fixed-haddock-comments
trivial changes to fix haddock documentation
2017-04-29 15:23:01 -07:00
Bruce Forte
295d416e9d Update CycleWorkspaceByScreen.hs 2017-04-29 22:53:42 +02:00
bforte
38b7a2e7f4 trivial changes to fix haddock documentation 2017-04-29 21:08:12 +02:00
Peter J. Jones
abb5f3d45c Merge pull request #171 from pjones/pjones/combop-parition
Add message to "re-partition" a ComboP layout
2017-04-28 21:14:33 -07:00
Peter Jones
e3c46b36db
Add message to "re-partition" a ComboP layout
This is especially useful with the `Tagged' window property.
2017-04-27 21:28:00 -07:00
Peter J. Jones
e5534d16cd Merge pull request #167 from IvanMalison/CycleWorkspaceByScreen
Cycle workspace by screen
2017-04-21 14:37:10 -07:00
Ivan Malison
0e35b6e504
Add X.A.CycleWorkspaceByScreen, Per screen WorkspaceHistory 2017-04-20 15:46:23 -07:00
Peter J. Jones
7e47ecc124 Merge pull request #102 from f1u77y/rewrite-minimize
Rewrite minimization-related modules
2017-04-20 10:46:26 -07:00
Bogdan Sinitsyn
c99606bbdd Rewrite minimization-related modules
* Use global state instead of per-layout - so now window is minimized on
  all workspaces (EWMH requires that windows with _NET_WM_STATE_HIDDEN
  set should be minimized on any workspace but previously they were not)
* Use `windows` instead of `modify`. That should fix bugs related to
  actions that should be done by `windows` and not done by
  `modify` (fixes #46)
* Mark module X.H.RestoreMinimized as deprecated
2017-04-20 20:09:16 +03:00
Brent Yorgey
a226ca62c7 Merge pull request #156 from strokyl/add_modifySpacing_message_handling_to_smartpacing
Add ModifySpacing message handling to SmartPacing and SmartSpacingWit…
2017-04-19 12:25:38 -04:00
Peter J. Jones
87683afd72 Merge pull request #165 from davama/master
X.P.Pass doc typo
2017-04-13 11:30:59 -07:00
Dave
20e8a33e0c Typo fix 2017-04-13 13:37:30 -04:00
Peter J. Jones
21062dd392 Merge pull request #44 from deepfire/spawnon-child-pid-tracking
Spawnon child pid tracking
2017-04-12 08:26:18 -07:00
Peter J. Jones
cfc99693fe Merge pull request #161 from xmonad/revert-128-master
Requesting focus causes layout order to change

Reverts xmonad/xmonad-contrib#128
2017-04-10 16:52:12 -07:00
Peter J. Jones
1b738c2bed Revert "Add new module XMonad.Hooks.Focus ." 2017-04-10 16:19:06 -07:00
Kosyrev Serge
33237f47f7 Actions.SpawnOn: make spawnOn more reliable on Linux, by tracking children across fork 2017-04-11 01:00:47 +03:00
Peter Jones
65ac029636
Move example configuration file into xmonad-contrib for better visibility 2017-04-10 10:38:23 -07:00
Brent Yorgey
7136394282 Merge pull request #147 from pjones/pjones/windowMultiPrompt
New function: `X.P.Window.windowMultiPrompt'
2017-03-30 16:15:50 -05:00
Brent Yorgey
0ecbc68b98 Merge branch 'master' into pjones/windowMultiPrompt 2017-03-30 16:15:06 -05:00
Brent Yorgey
3ab4a94d6f clean up Hooks.Focus-related CHANGES and move to 0.14 2017-03-30 16:10:21 -05:00
Brent Yorgey
3b9924b181 Merge pull request #128 from sgf-dma/master
Add new module XMonad.Hooks.Focus .
2017-03-30 16:03:18 -05:00
Brent Yorgey
08abaccdce Merge branch 'master' into master 2017-03-30 16:02:47 -05:00
geekosaur
acdea28dfd Merge pull request #158 from xmonad/ezconfig-latin1
X.U.EZConfig: include Latin1 keys
2017-03-28 20:20:04 -04:00
Brent Yorgey
4ba56ee388 update CHANGES for EZConfig Latin1 changes 2017-03-26 22:06:05 -05:00
Brent Yorgey
057af44998 X.U.EZConfig: include Latin1 keys 2017-03-26 22:02:48 -05:00
Luc DUZAN
b4e7ab3d37 Add ModifySpacing message handling to SmartPacing and SmartSpacingWithEdge 2017-03-15 17:53:02 +01:00
Daniel Wagner
8984ce64bb Merge pull request #153 from mitchellwrosen/master
Respect number of master windows in Magnify layout
2017-02-25 10:07:01 -08:00
Mitchell Rosen
1b96c646c1
Respect number of master windows in Magnify layout 2017-02-25 10:02:29 -05:00
Brent Yorgey
78a15b9d49 Merge pull request #151 from samdoshi/gridselect
GridSelect: border colour and vertically centring text
2017-02-21 20:20:20 -06:00
Brent Yorgey
4c00eb5848 fix ThreeColMid window shuffling
Fixes #137.
2017-02-19 20:45:43 -06:00
geekosaur
a372b455dc typo in navigation2DP example
The example code in the documentation uses `navigation2D` instead of `navigation2DP`, evidently a simple copy/paste error. No actual code change.
2017-02-18 17:19:59 -05:00
Sam Doshi
a79a116934 improve the vertical centring in X.A.GridSelect 2017-02-18 13:46:30 +00:00
Sam Doshi
b1dee9b0b4 allow border colour to be specified in GSConfig 2017-02-17 08:29:12 +00:00
Brent Yorgey
54ef9f6f8d Merge pull request #149 from pjones/pjones/tagged
X.U.WindowProperties: Added the ability to test if a window has a tag…
2017-02-16 21:59:09 -06:00
Brent Yorgey
cffc36e21a Merge pull request #148 from samdoshi/bsp
export BinarySpacePartition type
2017-02-16 21:52:46 -06:00
Peter Jones
025433c658
X.U.WindowProperties: Added the ability to test if a window has a tag from X.A.TagWindows
New data constructor `Tagged` that uses `hasTag` from
`X.A.TagWindows`.  This is great for building layouts based off of
window tags.
2017-02-15 09:36:35 -07:00
Sam Doshi
0f9a6015e4 export BinarySpacePartition type 2017-02-15 14:45:11 +00:00
Peter Jones
00eb2abd87
New function: `X.P.Window.windowMultiPrompt'
Like 'windowPrompt', but uses the multiple modes feature of
@Prompt@ (via 'mkXPromptWithModes').

Given a list of actions along with the windows they should work
with, display the appropriate prompt with the ability to switch
between them using the @changeModeKey@.

For example, to have a prompt that first shows you all windows, but
allows you to narrow the list down to just the windows on the
current workspace:

> windowMultiPrompt config [(Goto, allWindows), (Goto, wsWindows)]
2017-02-14 10:32:50 -07:00
sgf
6f8145a2dc X.H.Focus: Add predefined configurations and more examples. 2017-02-14 20:13:49 +03:00
Peter Jones
298e51f939
Correctly mark functions in X.P.Window as deprecated 2017-02-13 16:16:04 -07:00
Peter J. Jones
9d2ffeb8e1 Merge pull request #139 from mekeor/better-xpc-font-description
Better description of 'font' field of 'XPC' record
2017-02-13 12:15:59 -07:00
Mekeor Melire
878987071b Better description of 'font' field of 'XPC' record
Describe how to use the 'font' field of 'XPC' record by adding two different examples.
2017-02-13 13:25:25 +01:00
sgf
a3593e5607 Remove no longer relevant changes from CHANGES.md. Fix merge conflicts. 2017-01-06 18:01:41 +03:00
sgf
c07be09e17 X.H.EwmhDesktops: use manageHook for handling activated window.
Move EWMH code from `X.H.Focus` to `X.H.EwmhDesktops`. Thus:

- I'll use `manageHook` for handling activated window.
- By default window activation do nothing (assuming default `ManageHook`).
- I can use `activated` predicate for changing window activation behavior.
- I may use additional combinators from `X.H.Focus` for more complex
  focus/workspace switch strategies.
2016-12-16 23:59:04 +03:00
sgf
8e5931272c X.H.ManageHelpers: Make type of ManageHook combinators more general. 2016-12-16 14:22:39 +03:00
sgf
2807935900 X.H.SetWMName: Add getWMName function.
And do not overwrite wm name in `handleFocusQuery`, if user has already set
it.
2016-12-15 22:13:48 +03:00
sgf
195cfbe77e Add new module XMonad.Hooks.Focus .
Extend ManageHook EDSL to work on focused windows and current workspace.
2016-12-15 22:13:42 +03:00
380 changed files with 31360 additions and 9256 deletions

View File

@ -1,12 +1,16 @@
### Problem Description
Describe the problem you are having, what you expect to happen
instead, and how to reproduce the problem.
Describe the problem you are having and what you expect to happen
instead.
### Steps to Reproduce
Give detailed step-by-step instructions on how to reproduce the problem.
### Configuration File
Please include the smallest configuration file that reproduces the
problem you are experiencing:
Please include the smallest _full_ configuration file that reproduces
the problem you are experiencing:
```haskell
module Main (main) where
@ -21,4 +25,6 @@ main = xmonad def
- [ ] I've read [CONTRIBUTING.md](https://github.com/xmonad/xmonad/blob/master/CONTRIBUTING.md)
- [ ] I tested my configuration with [xmonad-testing](https://github.com/xmonad/xmonad-testing)
- I tested my configuration
- [ ] With `xmonad` version XXX (commit XXX if using git)
- [ ] With `xmonad-contrib` version XXX (commit XXX if using git)

View File

@ -7,6 +7,7 @@ behind them.
- [ ] I've read [CONTRIBUTING.md](https://github.com/xmonad/xmonad/blob/master/CONTRIBUTING.md)
- [ ] I tested my changes with [xmonad-testing](https://github.com/xmonad/xmonad-testing)
- [ ] I've considered how to best test these changes (property, unit,
manually, ...) and concluded: XXX
- [ ] I updated the `CHANGES.md` file

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

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

View File

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

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

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

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

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

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

@ -0,0 +1,26 @@
name: Nix
on:
push:
pull_request:
jobs:
build:
runs-on: ubuntu-latest
name: Nix Flake - Linux
permissions:
contents: read
steps:
- name: Install Nix
uses: cachix/install-nix-action@v31
with:
github_access_token: ${{ secrets.GITHUB_TOKEN }}
- name: Clone project
uses: actions/checkout@v4
- name: Build
# "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-update -O0 -j
nix develop -c cabal v2-build -O0 -j

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

@ -0,0 +1,50 @@
name: Packdeps
on:
workflow_dispatch:
schedule:
# Run every Saturday
- cron: '0 3 * * 6'
jobs:
packdeps:
name: Packdeps
runs-on: ubuntu-latest
steps:
- name: Clone project
uses: actions/checkout@v4
- name: Setup Haskell
uses: haskell-actions/setup@v2
with:
# packdeps doesn't build with newer as of 2021-10
ghc-version: '8.8'
- name: Install packdeps
run: |
set -ex
cd # go somewhere without a cabal.project
cabal install packdeps
- name: Check package bounds (all)
continue-on-error: true
run: |
set -ex
packdeps \
--exclude X11 \
--exclude xmonad \
*.cabal
- name: Check package bounds (preferred)
run: |
set -ex
packdeps \
--preferred \
--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

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

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

6
.gitignore vendored
View File

@ -24,3 +24,9 @@ tags
# stack artifacts
/.stack-work/
/cabal.project.local
stack.yaml.lock
# nix artifacts
result
flake.lock

2
.hlint.yaml Normal file
View File

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

View File

@ -13,90 +13,97 @@ Bogdan Sinitsyn <bogdan.sinitsyn@gmail.com>
Brandon S Allbery KF8NH <allbery.b@gmail.com>
Brandon S Allbery KF8NH <allbery.b@gmail.com> <allbery@ece.cmu.edu>
Brent Yorgey <byorgey@gmail.com> <byorgey@cis.upenn.edu>
Bruce Forte <fuererb@student.ethz.ch>
Carlos Lopez-Camey <c.lopez@kmels.net>
Carsten Otto <xmonad@c-otto.de>
Cesar Crusius <ccrusius@google.com> <ccrusius@ccrusius-glaptop.roam.corp.google.com>
Christian Dietrich <stettberger@dokucode.de>
Christian Wills <cwills.dev@gmail.com>
Daniel Neri <daniel.neri@sigicom.com> <daniel.neri@sigicom.se>
Daniel Schoepe <daniel.schoepe@googlemail.com> <asgaroth_@gmx.de>
Daniel Schoepe <daniel.schoepe@googlemail.com> <daniel.schoepe@gmail.com>
Daniel Schoepe <daniel.schoepe@gmail.com> <asgaroth_@gmx.de>
Daniel Schoepe <daniel.schoepe@gmail.com> <daniel.schoepe@googlemail.com>
Daniel Wagner <me@dmwit.com> <daniel@wagner-home.com>
Dave Harrison <dave@nullcube.com>
Dave Macias <davama@gmail.com>
David Glasser <glasser@mit.edu>
David McLean <gopsychonauts@gmail.com>
Devin Mullins <devin.mullins@gmail.com> <devinmullins@gmail.com>
Devin Mullins <devin.mullins@gmail.com> <me@twifkak.com>
Dominik Bruhn <dominik@dbruhn.de>
Don Stewart <dons00@gmail.com> <dons@cse.unsw.edu.au>
Don Stewart <dons00@gmail.com> <dons@galois.com>
Edward Z. Yang <ezyang@cs.stanford.edu>
Evgeny Kurnevsky <kurnevsky@gmail.com>
Gwern Branwen <gwern@gwern.net>
Gwern Branwen <gwern@gwern.net> <gwern0@gmail.com>
Henrique Abreu <hgabreu@gmail.com>
Ilya Portnov <portnov84@rambler.ru>
intrigeri <intrigeri@boum.org>
Ivan Brennen <ivan.brennan@gmail.com>
Ivan Brennen <ivan.brennan@gmail.com> <ivanbrennan@users.noreply.github.com>
Ivan Miljenovic <Ivan.Miljenovic@gmail.com>
Jan-David Quesel <quesel@informatik.uni-oldenburg.de>
Jens Petersen <juhp@community.haskell.org> <petersen@haskell.org>
Jeremy Apthorp <nornagon@gmail.com>
Joachim Breitner <mail@joachim-breitner.de>
Joachim Fasting <joachim.fasting@gmail.com>
Joel Suovaniemi <joel.suovaniemi@iki.fi>
Joan Milev <joantmilev@gmail.com> <51526053+exorcist365@users.noreply.github.com>
Joe Thornber <joe.thornber@gmail.com>
Joel Suovaniemi <joel.suovaniemi@iki.fi>
Johann Giwer <johanngiwer@web.de>
Jussi Maki <joamaki@gmail.com>
Konstantin Sobolev <konstantin.sobolev@gmail.com>
L. S. Leary <LSLeary@users.noreply.github.com>
Lanny Ripple <lan3ny@gmail.com>
Lei Chen <linxray@gmail.com>
Leon Kowarschick <lkowarschick@gmail.com>
Leon Kowarschick <lkowarschick@gmail.com> <5300871+elkowar@users.noreply.github.com>
Leonardo Serra <leoserra@minaslivre.org>
Luc Duzan <lduzan@linagora.com>
Luc Duzan <lduzan@linagora.com> <stroky.l@gmail.com>
Luis Cabellos <zhen.sydow@gmail.com>
Lukas Mai <l.mai@web.de>
Mario Pastorelli <pastorelli.mario@gmail.com>
Mathias Stearn <redbeard0531@gmail.com>
Matt Brown <deadguysfrom@gmail.com>
Matthew Hague <matthewhague@zoho.com>
Michael G. Sloan <mgsloan@gmail.com>
Nathaniel Filardo <nwfilardo@gmail.com>
Nelson Elhage <nelhage@mit.edu>
Nicolas Dudebout <nicolas.dudebout@gatech.edu>
Nicolas Pouillard <nicolas.pouillard@gmail.com>
Nils Schweinsberg <mail@n-sch.de>
Norbert Zeh <nzeh@cs.dal.ca>
Peter J. Jones <pjones@devalot.com>
Peter J. Jones <pjones@devalot.com> <pjones@pmade.com>
Peter Olson <polson2@hawk.iit.edu>
Quentin Moser <moserq@gmail.com>
Quentin Moser <quentin.moser@unifr.ch>
Quentin Moser <moserq@gmail.com> <quentin.moser@unifr.ch>
Rickard Gustafsson <acura@allyourbase.se>
Robert Marlow <bobstopper@bobturf.org>
Robert Marlow <bobstopper@bobturf.org> <robreim@bobturf.org>
Rohan Jain <crodjer@gmail.com>
Sibi Prabakaran <sibi@psibi.in> <psibi2000@gmail.com>
Sean Escriva <sean.escriva@gmail.com>
Sean McEligot <seanmce33@gmail.com>
Sibi Prabakaran <sibi@psibi.in>
Spencer Janssen <spencerjanssen@gmail.com> <sjanssen@cse.unl.edu>
Tomohiro Matsuyama <matsuyama3@ariel-networks.com>
Timothy Hobbs <tim.thelion@gmail.com>
Tom Rauchenwald <its.sec@gmx.net>
Tom Smeets <tom.tsmeets@gmail.com> <Tom.TSmeets@Gmail.com>
Tomas Janousek <tomi@nomi.cz>
Tomohiro Matsuyama <matsuyama3@ariel-networks.com>
Tony Morris <haskell@tmorris.net>
Valery V. Vorotyntsev <valery.vv@gmail.com>
Will Farrington <wcfarrington@gmail.com>
Wirt Wolff <wirtwolff@gmail.com>
Yaakov Nemoy <loupgaroublond@gmail.com>
Yclept Nemo <orbisvicis@gmail.com> <pscjtwjdjtAhnbjm/dpn>
Yecine Megdiche <yecine.megdiche@gmail.com> <megdiche@in.tum.de>
brian <brian@lorf.org>
cardboard42 <cardboard42@gmail.com>
daedalusinfinity <daedalusinfinity@gmail.com>
hexago.nl <xmonad-contrib@hexago.nl>
intrigeri <intrigeri@boum.org>
jakob <jakob@pipefour.org>
kedals0 <kedals0@gmail.com>
lithis <xmonad@selg.hethrael.org>
lithis <xmonad@selg.hethrael.org> <xmonad@s001.hethrael.com>
longpoke <longpoke@gmail.com>
md143rbh7f <md143rbh7f@gmail.com>
perlkat <perlkat@katspace.org>
rupa <rupa@lrrr.us> <rupa@lrrr.us>
timthelion <tim.thelion@gmail.com>
# for core only
Neil Mitchell <http://www.cs.york.ac.uk/~ndm/>, Neil Mitchell
Nick Burlett <nickburlett@mac.com>
Sam Hughes <hughes@rpi.edu>
Shae Erisson <shae@ScannedInAvian.com>
Conrad Irwin <conrad.irwin@gmail.com>
sam-barr <mail@samf.bar> <samfbarr@outlook.com>
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,91 +0,0 @@
# This file has been generated -- see https://github.com/hvr/multi-ghc-travis
language: c
sudo: false
cache:
directories:
- $HOME/.cabsnap
- $HOME/.cabal/packages
before_cache:
- rm -fv $HOME/.cabal/packages/hackage.haskell.org/build-reports.log
- rm -fv $HOME/.cabal/packages/hackage.haskell.org/00-index.tar
matrix:
include:
- env: CABALVER=1.16 GHCVER=7.6.3
compiler: ": #GHC 7.6.3"
addons: {apt: {packages: [cabal-install-1.16,ghc-7.6.3], sources: [hvr-ghc]}}
- env: CABALVER=1.18 GHCVER=7.8.4
compiler: ": #GHC 7.8.4"
addons: {apt: {packages: [cabal-install-1.18,ghc-7.8.4], sources: [hvr-ghc]}}
- env: CABALVER=1.22 GHCVER=7.10.3
compiler: ": #GHC 7.10.3"
addons: {apt: {packages: [cabal-install-1.22,ghc-7.10.3], sources: [hvr-ghc]}}
- env: CABALVER=1.24 GHCVER=8.0.1
compiler: ": #GHC 8.0.1"
addons: {apt: {packages: [cabal-install-1.24,ghc-8.0.1], sources: [hvr-ghc]}}
before_install:
- unset CC
- export PATH=/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:$PATH
install:
# build xmonad from HEAD
- git clone https://github.com/xmonad/xmonad.git
- cabal --version
- echo "$(ghc --version) [$(ghc --print-project-git-commit-id 2> /dev/null || echo '?')]"
- if [ -f $HOME/.cabal/packages/hackage.haskell.org/00-index.tar.gz ];
then
zcat $HOME/.cabal/packages/hackage.haskell.org/00-index.tar.gz >
$HOME/.cabal/packages/hackage.haskell.org/00-index.tar;
fi
- travis_retry cabal update -v
- sed -i 's/^jobs:/-- jobs:/' ${HOME}/.cabal/config
- cabal install --only-dependencies --enable-tests --enable-benchmarks --dry -v > installplan.txt
- sed -i -e '1,/^Resolving /d' installplan.txt; cat installplan.txt
# check whether current requested install-plan matches cached package-db snapshot
- if diff -u $HOME/.cabsnap/installplan.txt installplan.txt;
then
echo "cabal build-cache HIT";
rm -rfv .ghc;
cp -a $HOME/.cabsnap/ghc $HOME/.ghc;
cp -a $HOME/.cabsnap/lib $HOME/.cabsnap/share $HOME/.cabsnap/bin $HOME/.cabal/;
else
echo "cabal build-cache MISS";
rm -rf $HOME/.cabsnap;
mkdir -p $HOME/.ghc $HOME/.cabal/lib $HOME/.cabal/share $HOME/.cabal/bin;
cabal install --only-dependencies --enable-tests --enable-benchmarks;
fi
# snapshot package-db on cache miss
- if [ ! -d $HOME/.cabsnap ];
then
echo "snapshotting package-db to build-cache";
mkdir $HOME/.cabsnap;
cp -a $HOME/.ghc $HOME/.cabsnap/ghc;
cp -a $HOME/.cabal/lib $HOME/.cabal/share $HOME/.cabal/bin installplan.txt $HOME/.cabsnap/;
fi
- cabal install xmonad/
# Here starts the actual work to be performed for the package under test;
# any command which exits with a non-zero exit code causes the build to fail.
script:
- if [ -f configure.ac ]; then autoreconf -i; fi
- cabal configure --enable-tests --enable-benchmarks -v2 # -v2 provides useful information for debugging
- cabal build # this builds all libraries and executables (including tests/benchmarks)
- cabal test
# - cabal check # complains about -Werror even though it is
# hidden behind a manual flag with default false
- cabal sdist # tests that a source-distribution can be generated
# Check that the resulting source distribution can be built & installed.
# If there are no other `.tar.gz` files in `dist`, this can be even simpler:
# `cabal install --force-reinstalls dist/*-*.tar.gz`
- SRC_TGZ=$(cabal info . | awk '{print $2;exit}').tar.gz &&
(cd dist && cabal install --force-reinstalls "$SRC_TGZ")
# EOF

2038
CHANGES.md

File diff suppressed because it is too large Load Diff

5
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,5 @@
# Contributing to xmonad and xmonad-contrib
Please refer to XMonad's [CONTRIBUTING][gh:xmonad:contributing].
[gh:xmonad:contributing]: https://github.com/xmonad/xmonad/blob/master/CONTRIBUTING.md

45
LICENSE
View File

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

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,42 +1,82 @@
# xmonad-contrib: Third Party Extensions to the xmonad Window Manager
<p align="center">
<a href="https://xmonad.org/"><img alt="XMonad logo" src="https://xmonad.org/images/logo-wrapped.svg" height=150></a>
</p>
<p align="center">
<a href="https://hackage.haskell.org/package/xmonad-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/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>
<br>
<a href="https://web.libera.chat/#xmonad"><img alt="Chat on #xmonad@irc.libera.chat" src="https://img.shields.io/badge/%23%20chat-on%20libera-brightgreen"></a>
<a href="https://matrix.to/#/#xmonad:matrix.org"><img alt="Chat on #xmonad:matrix.org" src="https://img.shields.io/matrix/xmonad:matrix.org?logo=matrix"></a>
</p>
[![Build Status](https://travis-ci.org/xmonad/xmonad-contrib.svg?branch=master)](https://travis-ci.org/xmonad/xmonad-contrib)
# xmonad-contrib
You need the ghc compiler and xmonad window manager installed in
order to use these extensions.
**Community-maintained extensions for the [XMonad][web:xmonad] window manager.**
For installation and configuration instructions, please see the
[xmonad website] [xmonad], the documents included with the
[xmonad source distribution] [xmonad-git], and the
[online haddock documentation] [xmonad-docs].
[xmonad core][gh:xmonad] is minimal, stable, yet extensible.
[xmonad-contrib][gh:xmonad-contrib] is home to hundreds of additional tiling
algorithms and extension modules. The two combined make for a powerful X11
window-manager with endless customization possibilities. They are, quite
literally, libraries for creating your own window manager.
## Getting or Updating XMonadContrib
## Installation
* Latest release: <https://hackage.haskell.org/package/xmonad-contrib>
For installation and configuration instructions, please see:
* Git version: <https://github.com/xmonad/xmonad-contrib>
* [downloading and installing xmonad][web:download]
* [installing latest xmonad snapshot from git][web:install]
* [configuring xmonad][web:tutorial]
(To use git xmonad-contrib you must also use the
[git version of xmonad] [xmonad-git].)
If you run into any trouble, consult our [documentation][web:documentation] or
ask the [community][web:community] for help.
## Contributing
Haskell code contributed to this repo should live under the
appropriate subdivision of the `XMonad` namespace (currently includes
`Actions`, `Config`, `Hooks`, `Layout`, `Prompt`, and `Util`). For
example, to use the Grid layout, one would import:
We welcome all forms of contributions:
XMonad.Layout.Grid
* [bug reports and feature ideas][gh:xmonad-contrib:issues]
(also to [xmonad][gh:xmonad:issues])
* [bug fixes, new features, new extensions][gh:xmonad-contrib:pulls]
(also to [xmonad][gh:xmonad:pulls])
* documentation fixes and improvements: [xmonad][gh:xmonad],
[xmonad-contrib][gh:xmonad-contrib], [xmonad-web][gh:xmonad-web]
* helping others in the [community][web:community]
* financial support: [GitHub Sponsors][gh:xmonad:sponsors],
[Open Collective][opencollective:xmonad]
For further details, see the [documentation] [developing] for the
`XMonad.Doc.Developing` module and the [xmonad website] [xmonad].
Please do read the [CONTRIBUTING][gh:xmonad:contributing] document for more
information about bug reporting and code contributions. For a brief overview
of the architecture and code conventions, see the [documentation for the
`XMonad.Doc.Developing` module][doc:developing]. If in doubt, [talk to
us][web:community].
## License
Code submitted to the contrib repo is licensed under the same license as
xmonad itself, with copyright held by the authors.
Code submitted to the xmonad-contrib repo is licensed under the same license
as xmonad core itself, with copyright held by the authors.
[xmonad]: http://xmonad.org
[xmonad-git]: https://github.com/xmonad/xmonad
[xmonad-docs]: http://www.xmonad.org/xmonad-docs
[developing]: http://xmonad.org/xmonad-docs/xmonad-contrib/XMonad-Doc-Developing.html
[doc:developing]: https://xmonad.github.io/xmonad-docs/xmonad-contrib/XMonad-Doc-Developing.html
[gh:xmonad-contrib:issues]: https://github.com/xmonad/xmonad-contrib/issues
[gh:xmonad-contrib:pulls]: https://github.com/xmonad/xmonad-contrib/pulls
[gh:xmonad-contrib]: https://github.com/xmonad/xmonad-contrib
[gh:xmonad-web]: https://github.com/xmonad/xmonad-web
[gh:xmonad:contributing]: https://github.com/xmonad/xmonad/blob/master/CONTRIBUTING.md
[gh:xmonad:issues]: https://github.com/xmonad/xmonad/issues
[gh:xmonad:pulls]: https://github.com/xmonad/xmonad/pulls
[gh:xmonad:sponsors]: https://github.com/sponsors/xmonad
[gh:xmonad]: https://github.com/xmonad/xmonad
[opencollective:xmonad]: https://opencollective.com/xmonad
[web:community]: https://xmonad.org/community.html
[web:documentation]: https://xmonad.org/documentation.html
[web:download]: https://xmonad.org/download.html
[web:install]: https://xmonad.org/INSTALL.html
[web:tutorial]: https://xmonad.org/TUTORIAL.html
[web:xmonad]: https://xmonad.org/

View File

@ -1,6 +1,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.AfterDrag
-- Description : Allows you to add actions dependent on the current mouse drag.
-- Copyright : (c) 2014 Anders Engstrom <ankaan@gmail.com>
-- License : BSD3-style (see LICENSE)
--
@ -19,10 +20,11 @@ module XMonad.Actions.AfterDrag (
ifClick') where
import XMonad
import System.Time
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
--
@ -53,7 +55,7 @@ afterDrag task = do drag <- gets dragging
-- A drag is considered a click if it is completed within 300 ms.
ifClick
:: X () -- ^ The action to take if the dragging turned out to be a click.
-> X ()
-> X ()
ifClick action = ifClick' 300 action (return ())
-- | Take an action if the current dragging is completed within a certain time (in milliseconds.)
@ -61,11 +63,11 @@ ifClick'
:: Int -- ^ Maximum time of dragging for it to be considered a click (in milliseconds.)
-> X () -- ^ The action to take if the dragging turned out to be a click.
-> X () -- ^ The action to take if the dragging turned out to not be a click.
-> X ()
-> X ()
ifClick' ms click drag = do
start <- io $ getClockTime
afterDrag $ do
stop <- io $ getClockTime
if diffClockTimes stop start <= noTimeDiff { tdPicosec = fromIntegral ms * 10^(9 :: Integer) }
start <- io getCurrentTime
afterDrag $ do
stop <- io getCurrentTime
if diffUTCTime stop start <= (fromIntegral ms / 10^(3 :: Integer) :: NominalDiffTime)
then click
else drag

View File

@ -1,6 +1,7 @@
----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.BluetileCommands
-- Description : Interface with the [Bluetile](https://hackage.haskell.org/package/bluetile) tiling window manager.
-- Copyright : (c) Jan Vornberger 2009
-- License : BSD3-style (see LICENSE)
--
@ -24,12 +25,11 @@ module XMonad.Actions.BluetileCommands (
import XMonad
import qualified XMonad.StackSet as W
import XMonad.Layout.LayoutCombinators
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
@ -43,7 +43,7 @@ import System.Exit
workspaceCommands :: Int -> X [(String, X ())]
workspaceCommands sid = asks (workspaces . config) >>= \spaces -> return
[(("greedyView" ++ show i),
[( "greedyView" ++ show i,
activateScreen sid >> windows (W.greedyView i))
| i <- spaces ]
@ -66,7 +66,7 @@ masterAreaCommands sid = [ ("increase master n", activateScreen sid >>
]
quitCommands :: [(String, X ())]
quitCommands = [ ("quit bluetile", io (exitWith ExitSuccess))
quitCommands = [ ("quit bluetile", io exitSuccess)
, ("quit bluetile and start metacity", restart "metacity" False)
]

View File

@ -1,6 +1,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.Commands
-- Description : Run internal xmonad commands using a dmenu menu.
-- Copyright : (c) David Glasser 2007
-- License : BSD3
--
@ -19,6 +20,7 @@ module XMonad.Actions.Commands (
-- $usage
commandMap,
runCommand,
runCommandConfig,
runCommand',
workspaceCommands,
screenCommands,
@ -31,11 +33,11 @@ import XMonad.Util.Dmenu (dmenu)
import qualified Data.Map as M
import System.Exit
import Data.Maybe
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
--
@ -55,23 +57,23 @@ import Data.Maybe
-- 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.
commandMap :: [(String, X ())] -> M.Map String (X ())
commandMap c = M.fromList c
commandMap = M.fromList
-- | Generate a list of commands to switch to\/send windows to workspaces.
workspaceCommands :: X [(String, X ())]
workspaceCommands = asks (workspaces . config) >>= \spaces -> return
[((m ++ show i), windows $ f i)
[( m ++ show i, windows $ f i)
| i <- spaces
, (f, m) <- [(view, "view"), (shift, "shift")] ]
-- | Generate a list of commands dealing with multiple screens.
screenCommands :: [(String, X ())]
screenCommands = [((m ++ show sc), screenWorkspace (fromIntegral sc) >>= flip whenJust (windows . f))
screenCommands = [( m ++ show sc, screenWorkspace (fromIntegral sc) >>= flip whenJust (windows . f))
| sc <- [0, 1]::[Int] -- TODO: adapt to screen changes
, (f, m) <- [(view, "screen"), (shift, "screen-to-")]
]
@ -99,15 +101,22 @@ defaultCommands = do
, ("swap-down" , windows swapDown )
, ("swap-master" , windows swapMaster )
, ("sink" , withFocused $ windows . sink )
, ("quit-wm" , io $ exitWith ExitSuccess )
, ("quit-wm" , io exitSuccess )
]
-- | Given a list of command\/action pairs, prompt the user to choose a
-- command and return the corresponding action.
-- command using dmenu and return the corresponding action.
runCommand :: [(String, X ())] -> X ()
runCommand cl = do
runCommand = runCommandConfig dmenu
-- | Given a list of command\/action pairs, prompt the user to choose a
-- command using dmenu-compatible launcher and return the corresponding action.
-- See X.U.Dmenu for compatible launchers.
runCommandConfig :: ([String] -> X String) -> [(String, X ())] -> X()
runCommandConfig f cl = do
let m = commandMap cl
choice <- dmenu (M.keys m)
choice <- f (M.keys m)
fromMaybe (return ()) (M.lookup choice m)
-- | Given the name of a command from 'defaultCommands', return the

View File

@ -1,6 +1,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.ConstrainedResize
-- Description : Constrain the aspect ratio of a floating window.
-- Copyright : (c) Dougal Stanton
-- License : BSD3-style (see LICENSE)
--
@ -25,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
--
@ -43,9 +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
io $ raiseWindow d w
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
@ -53,5 +53,6 @@ mouseResizeWindow w c = whenX (isClient w) $ withDisplay $ \d -> do
y = ey - fromIntegral (wa_y wa)
sz = if c then (max x y, max x y) else (x,y)
io $ resizeWindow d w `uncurry`
applySizeHintsContents sh sz)
applySizeHintsContents sh sz
float w)
(float w)

View File

@ -1,7 +1,9 @@
{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE RecordWildCards #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.CopyWindow
-- Description : Duplicate a window on multiple workspaces.
-- Copyright : (c) David Roundy <droundy@darcs.net>, Ivan Veselov <veselov@gmail.com>, Lanny Ripple <lan3ny@gmail.com>
-- License : BSD3-style (see LICENSE)
--
@ -18,22 +20,24 @@ module XMonad.Actions.CopyWindow (
-- * Usage
-- $usage
copy, copyToAll, copyWindow, runOrCopy
, killAllOtherCopies, kill1
, killAllOtherCopies, kill1, taggedWindows, copiesOfOn
-- * Highlight workspaces containing copies in logHook
-- $logHook
, wsContainingCopies
, wsContainingCopies, copiesPP
) where
import XMonad
import XMonad.Prelude
import Control.Arrow ((&&&))
import qualified Data.List as L
import XMonad.Actions.WindowGo
import XMonad.Hooks.StatusBar.PP (PP(..), WS(..), isHidden)
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
--
@ -73,21 +77,27 @@ 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
-- To distinguish workspaces containing copies of the focused window use
-- something like:
--
-- > sampleLogHook h = do
-- > copies <- wsContainingCopies
-- > let check ws | ws `elem` copies = pad . xmobarColor "red" "black" $ ws
-- > | otherwise = pad ws
-- > dynamicLogWithPP myPP {ppHidden = check, ppOutput = hPutStrLn h}
-- >
-- > main = do
-- > h <- spawnPipe "xmobar"
-- > xmonad def { logHook = sampleLogHook h }
-- To distinguish workspaces containing copies of the focused window, use 'copiesPP'.
-- 'copiesPP' takes a pretty printer and makes it aware of copies of the focused window.
-- It can be applied when creating a 'XMonad.Hooks.StatusBar.StatusBarConfig'.
--
-- A sample config looks like this:
--
-- > mySB = statusBarProp "xmobar" (copiesPP (pad . xmobarColor "red" "black") xmobarPP)
-- > main = xmonad $ withEasySB mySB defToggleStrutsKey def
-- | Take a pretty printer and make it aware of copies by using the provided function
-- to show hidden workspaces that contain copies of the focused window.
copiesPP :: (WorkspaceId -> String) -> PP -> X PP
copiesPP wtoS pp = do
copies <- wsContainingCopies
let check WS{..} = W.tag wsWS `elem` copies
let printer = (asks (isHidden <&&> check) >>= guard) $> wtoS
return pp{ ppPrinters = printer <|> ppPrinters pp }
-- | Copy the focused window to a workspace.
copy :: (Eq s, Eq i, Eq a) => i -> W.StackSet i l a s sd -> W.StackSet i l a s sd
@ -96,7 +106,7 @@ copy n s | Just w <- W.peek s = copyWindow w n s
-- | Copy the focused window to all workspaces.
copyToAll :: (Eq s, Eq i, Eq a) => W.StackSet i l a s sd -> W.StackSet i l a s sd
copyToAll s = foldr copy s $ map W.tag (W.workspaces s)
copyToAll s = foldr (copy . W.tag) s (W.workspaces s)
-- | Copy an arbitrary window to a workspace.
copyWindow :: (Eq a, Eq i, Eq s) => a -> i -> W.StackSet i l a s sd -> W.StackSet i l a s sd
@ -104,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
@ -142,9 +152,9 @@ killAllOtherCopies = do ss <- gets windowset
W.view (W.currentTag ss) .
delFromAllButCurrent w
where
delFromAllButCurrent w ss = foldr ($) ss $
map (delWinFromWorkspace w . W.tag) $
W.hidden ss ++ map W.workspace (W.visible ss)
delFromAllButCurrent w ss = foldr (delWinFromWorkspace w . W.tag)
ss
(W.hidden ss ++ map W.workspace (W.visible ss))
delWinFromWorkspace w wid = viewing wid $ W.modify Nothing (W.filter (/= w))
viewing wis f ss = W.view (W.currentTag ss) $ f $ W.view wis ss

View File

@ -1,6 +1,11 @@
{-# LANGUAGE CPP #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE MultiWayIf #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.CycleRecentWS
-- Description : Cycle through most recently used workspaces.
-- Copyright : (c) Michal Janeczek <janeczek@gmail.com>
-- License : BSD3-style (see LICENSE)
--
@ -19,21 +24,37 @@ module XMonad.Actions.CycleRecentWS (
-- * Usage
-- $usage
cycleRecentWS,
cycleWindowSets
cycleRecentNonEmptyWS,
cycleWindowSets,
toggleRecentWS,
toggleRecentNonEmptyWS,
toggleWindowSets,
recentWS,
#ifdef TESTING
unView,
#endif
) where
import XMonad.Actions.Repeatable (repeatableSt)
import XMonad hiding (workspaces)
import XMonad.StackSet
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
@ -47,39 +68,91 @@ cycleRecentWS :: [KeySym] -- ^ A list of modifier keys used when invoking this a
-> KeySym -- ^ Key used to switch to previous (more recent) workspace.
-- If it's the same as the nextWorkspace key, it is effectively ignored.
-> X ()
cycleRecentWS = cycleWindowSets options
where options w = map (view `flip` w) (recentTags w)
recentTags w = map tag $ tail (workspaces w) ++ [head (workspaces w)]
cycleRecentWS = cycleWindowSets $ recentWS (const True)
cycref :: [a] -> Int -> a
cycref l i = l !! (i `mod` length l)
-- | Like 'cycleRecentWS', but restricted to non-empty workspaces.
cycleRecentNonEmptyWS :: [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 (less recent) workspace.
-> KeySym -- ^ Key used to switch to previous (more recent) workspace.
-- If it's the same as the nextWorkspace key, it is effectively ignored.
-> X ()
cycleRecentNonEmptyWS = cycleWindowSets $ recentWS (not . null . stack)
-- | Cycle through a finite list of WindowSets with repeated presses of a key, while
-- | Switch to the most recent workspace. The stack of most recently used workspaces
-- is updated, so repeated use toggles between a pair of workspaces.
toggleRecentWS :: X ()
toggleRecentWS = toggleWindowSets $ recentWS (const True)
-- | Like 'toggleRecentWS', but restricted to non-empty workspaces.
toggleRecentNonEmptyWS :: X ()
toggleRecentNonEmptyWS = toggleWindowSets $ recentWS (not . null . stack)
-- | Given a predicate @p@ and the current 'WindowSet' @w@, create a
-- list of workspaces to choose from. They are ordered by recency and
-- have to satisfy @p@.
recentWS :: (WindowSpace -> Bool) -- ^ A workspace predicate.
-> WindowSet -- ^ The current WindowSet
-> [WorkspaceId]
recentWS p w = map tag
$ filter p
$ map workspace (visible w)
++ hidden w
++ [workspace (current w)]
-- | Cycle through a finite list of workspaces with repeated presses of a key, while
-- a modifier key is held down. For best effects use the same modkey+key combination
-- as the one used to invoke this action.
cycleWindowSets :: (WindowSet -> [WindowSet]) -- ^ A function used to create a list of WindowSets to choose from
-> [KeySym] -- ^ A list of modifier keys used when invoking this action.
-- As soon as one of them is released, the final WindowSet is chosen and the action exits.
-> KeySym -- ^ Key used to preview next WindowSet from the list of generated options
-> KeySym -- ^ Key used to preview previous WindowSet from the list of generated options.
-- If it's the same as nextOption key, it is effectively ignored.
cycleWindowSets :: (WindowSet -> [WorkspaceId]) -- ^ A function used to create a list of workspaces to choose from
-> [KeySym] -- ^ A list of modifier keys used when invoking this action.
-- As soon as one of them is released, the final workspace is chosen and the action exits.
-> KeySym -- ^ Key used to preview next workspace from the list of generated options
-> KeySym -- ^ Key used to preview previous workspace from the list of generated options.
-- If it's the same as nextOption key, it is effectively ignored.
-> X ()
cycleWindowSets genOptions mods keyNext keyPrev = do
(options, unView') <- gets $ (genOptions &&& unView) . windowset
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
-- former inside of the latter. This respects any new state that the
-- new 'WindowSet' may have accumulated.
unView :: forall i l a s sd. (Eq i, Eq s)
=> StackSet i l a s sd -> StackSet i l a s sd -> StackSet i l a s sd
unView w0 w1 = fixOrderH . fixOrderV . view' (currentTag w0) $ w1
where
view' = if screen (current w0) == screen (current w1) then greedyView else view
fixOrderV w | v : vs <- visible w = w{ visible = insertAt (pfxV (visible w0) vs) v vs }
| otherwise = w
fixOrderH w | h : hs <- hidden w = w{ hidden = insertAt (pfxH (hidden w0) hs) h hs }
| otherwise = w
pfxV = commonPrefix `on` fmap (tag . workspace)
pfxH = commonPrefix `on` fmap tag
insertAt :: Int -> x -> [x] -> [x]
insertAt n x xs = let (l, r) = splitAt n xs in l ++ [x] ++ r
commonPrefix :: Eq x => [x] -> [x] -> Int
commonPrefix a b = length $ takeWhile id $ zipWith (==) a b
-- | Given some function that generates a list of workspaces from a
-- given 'WindowSet', switch to the first generated workspace.
toggleWindowSets :: (WindowSet -> [WorkspaceId]) -> X ()
toggleWindowSets genOptions = do
options <- gets $ genOptions . 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 $ const $ options `cycref` n
(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
case options of
[] -> return ()
o:_ -> windows (view o)

View File

@ -1,6 +1,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.CycleSelectedLayouts
-- Description : Cycle through the given subset of layouts.
-- Copyright : (c) Roman Cheplyaka
-- License : BSD3-style (see LICENSE)
--
@ -18,34 +19,29 @@ module XMonad.Actions.CycleSelectedLayouts (
cycleThroughLayouts) where
import XMonad
import Data.List (findIndex)
import Data.Maybe (fromMaybe)
import XMonad.Layout.LayoutCombinators (JumpToLayout(..))
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 hiding ((|||))
-- > import XMonad.Layout.LayoutCombinators ((|||))
-- > import XMonad
-- > import XMonad.Actions.CycleSelectedLayouts
--
-- > , ((modm, xK_t ), cycleThroughLayouts ["Tall", "Mirror Tall"])
--
-- Make sure you are using NewSelect from XMonad.Layout.LayoutCombinators,
-- rather than the Select defined in xmonad core.
cycleToNext :: (Eq a) => [a] -> a -> Maybe a
cycleToNext lst a = do
-- not beautiful but simple and readable
ind <- findIndex (a==) lst
ind <- elemIndex a lst
return $ lst !! if ind == length lst - 1 then 0 else ind+1
-- | 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

@ -1,6 +1,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.CycleWS
-- Description : Cycle through workspaces.
-- Copyright : (c) Joachim Breitner <mail@joachim-breitner.de>,
-- Nelson Elhage <nelhage@mit.edu> (`toggleWS' function)
-- License : BSD3-style (see LICENSE)
@ -18,13 +19,13 @@
--
-- Note that this module now subsumes the functionality of the former
-- @XMonad.Actions.RotView@. Former users of @rotView@ can simply replace
-- @rotView True@ with @moveTo Next NonEmptyWS@, and so on.
-- @rotView True@ with @moveTo Next (Not emptyWS)@, and so on.
--
-- If you want to exactly replicate the action of @rotView@ (cycling
-- through workspace in order lexicographically by tag, instead of in
-- the order specified in the config), it can be implemented as:
--
-- > rotView b = do t <- findWorkspace getSortByTag (bToDir b) NonEmptyWS 1
-- > rotView b = do t <- findWorkspace getSortByTag (bToDir b) (Not emptyWS) 1
-- > windows . greedyView $ t
-- > where bToDir True = Next
-- > bToDir False = Prev
@ -63,6 +64,11 @@ module XMonad.Actions.CycleWS (
, Direction1D(..)
, WSType(..)
, emptyWS
, hiddenWS
, anyWS
, wsTagGroup
, ignoringWSs
, shiftTo
, moveTo
@ -78,9 +84,7 @@ module XMonad.Actions.CycleWS (
) where
import Data.List ( find, findIndex )
import Data.Maybe ( isNothing, isJust )
import XMonad.Prelude (find, findIndex, isJust, isNothing, liftM2)
import XMonad hiding (workspaces)
import qualified XMonad.Hooks.WorkspaceHistory as WH
import XMonad.StackSet hiding (filter)
@ -88,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
-- >
@ -112,13 +116,13 @@ import XMonad.Util.WorkspaceCompare
-- You can also get fancier with 'moveTo', 'shiftTo', and 'findWorkspace'.
-- For example:
--
-- > , ((modm , xK_f), moveTo Next EmptyWS) -- find a free workspace
-- > , ((modm , xK_f), moveTo Next emptyWS) -- find a free workspace
-- > , ((modm .|. controlMask, xK_Right), -- a crazy keybinding!
-- > do t <- findWorkspace getSortByXineramaRule Next NonEmptyWS 2
-- > do t <- findWorkspace getSortByXineramaRule Next (Not emptyWS) 2
-- > 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
@ -201,8 +205,7 @@ skipTags wss ids = filter ((`notElem` ids) . tag) wss
lastViewedHiddenExcept :: [WorkspaceId] -> X (Maybe WorkspaceId)
lastViewedHiddenExcept skips = do
hs <- gets $ map tag . flip skipTags skips . hidden . windowset
vs <- WH.workspaceHistory
return $ choose hs (find (`elem` hs) vs)
choose hs . find (`elem` hs) <$> WH.workspaceHistory
where choose [] _ = Nothing
choose (h:_) Nothing = Just h
choose _ vh@(Just _) = vh
@ -213,8 +216,8 @@ switchWorkspace d = wsBy d >>= windows . greedyView
shiftBy :: Int -> X ()
shiftBy d = wsBy d >>= windows . shift
wsBy :: Int -> X (WorkspaceId)
wsBy = findWorkspace getSortByIndex Next AnyWS
wsBy :: Int -> X WorkspaceId
wsBy = findWorkspace getSortByIndex Next anyWS
{- $taketwo
@ -223,7 +226,7 @@ through subsets of workspaces.
For example,
> moveTo Next EmptyWS
> moveTo Next emptyWS
will move to the first available workspace with no windows, and
@ -234,6 +237,13 @@ the letter 'p' in its name. =)
-}
{-# DEPRECATED EmptyWS "Use emptyWS instead." #-}
{-# DEPRECATED HiddenWS "Use hiddenWS instead." #-}
{-# DEPRECATED NonEmptyWS "Use Not emptyWS instead." #-}
{-# DEPRECATED HiddenNonEmptyWS "Use hiddenWS :&: Not emptyWS instead." #-}
{-# DEPRECATED HiddenEmptyWS "Use hiddenWS :&: emptyWS instead." #-}
{-# DEPRECATED AnyWS "Use anyWS instead." #-}
{-# DEPRECATED WSTagGroup "Use wsTagGroup instead." #-}
-- | What type of workspaces should be included in the cycle?
data WSType = EmptyWS -- ^ cycle through empty workspaces
| NonEmptyWS -- ^ cycle through non-empty workspaces
@ -248,6 +258,11 @@ data WSType = EmptyWS -- ^ cycle through empty workspaces
| WSIs (X (WindowSpace -> Bool))
-- ^ cycle through workspaces satisfying
-- an arbitrary predicate
| WSType :&: WSType -- ^ cycle through workspaces satisfying both
-- predicates.
| WSType :|: WSType -- ^ cycle through workspaces satisfying one of
-- the predicates.
| Not WSType -- ^ cycle through workspaces not satisfying the predicate
-- | Convert a WSType value to a predicate on workspaces.
wsTypeToPred :: WSType -> X (WindowSpace -> Bool)
@ -262,10 +277,46 @@ wsTypeToPred HiddenEmptyWS = do ne <- wsTypeToPred EmptyWS
hi <- wsTypeToPred HiddenWS
return (\w -> hi w && ne w)
wsTypeToPred AnyWS = return (const True)
wsTypeToPred (WSTagGroup sep) = do cur <- (groupName.workspace.current) `fmap` gets windowset
wsTypeToPred (WSTagGroup sep) = do cur <- groupName.workspace.current <$> gets windowset
return $ (cur ==).groupName
where groupName = takeWhile (/=sep).tag
wsTypeToPred (WSIs p) = p
wsTypeToPred (WSIs p ) = p
wsTypeToPred (p :&: q) = liftM2 (&&) <$> wsTypeToPred p <*> wsTypeToPred q
wsTypeToPred (p :|: q) = liftM2 (||) <$> wsTypeToPred p <*> wsTypeToPred q
wsTypeToPred (Not p ) = fmap not <$> wsTypeToPred p
-- | Cycle through empty workspaces
emptyWS :: WSType
emptyWS = WSIs . return $ isNothing . stack
-- | Cycle through non-visible workspaces
hiddenWS :: WSType
hiddenWS = WSIs $ do
hs <- gets (map tag . hidden . windowset)
return $ (`elem` hs) . tag
-- | Cycle through all workspaces
anyWS :: WSType
anyWS = WSIs . return $ const True
-- | Cycle through workspaces that are not in the given list. This could, for
-- example, be used for skipping the workspace reserved for
-- "XMonad.Util.NamedScratchpad":
--
-- > moveTo Next $ hiddenWS :&: Not emptyWS :&: ignoringWSs [scratchpadWorkspaceTag]
--
ignoringWSs :: [WorkspaceId] -> WSType
ignoringWSs ts = WSIs . return $ (`notElem` ts) . tag
-- | Cycle through workspaces in the same group, the
-- group name is all characters up to the first
-- separator character or the end of the tag
wsTagGroup :: Char -> WSType
wsTagGroup sep = WSIs $ do
cur <- groupName . workspace . current <$> gets windowset
return $ (cur ==) . groupName
where groupName = takeWhile (/= sep) . tag
-- | View the next workspace in the given direction that satisfies
-- the given condition.
@ -299,7 +350,7 @@ findWorkspace :: X WorkspaceSort -> Direction1D -> WSType -> Int -> X WorkspaceI
findWorkspace s dir t n = findWorkspaceGen s (wsTypeToPred t) (maybeNegate dir n)
where
maybeNegate Next d = d
maybeNegate Prev d = (-d)
maybeNegate Prev d = -d
findWorkspaceGen :: X WorkspaceSort -> X (WindowSpace -> Bool) -> Int -> X WorkspaceId
findWorkspaceGen _ _ 0 = gets (currentTag . windowset)
@ -309,7 +360,7 @@ findWorkspaceGen sortX wsPredX d = do
ws <- gets windowset
let cur = workspace (current ws)
sorted = sort (workspaces ws)
pivoted = let (a,b) = span ((/= (tag cur)) . tag) sorted in b ++ a
pivoted = let (a,b) = span ((/= tag cur) . tag) sorted in b ++ a
ws' = filter wsPred pivoted
mCurIx = findWsIndex cur ws'
d' = if d > 0 then d - 1 else d
@ -321,7 +372,7 @@ findWorkspaceGen sortX wsPredX d = do
return $ tag next
findWsIndex :: WindowSpace -> [WindowSpace] -> Maybe Int
findWsIndex ws wss = findIndex ((== tag ws) . tag) wss
findWsIndex ws = findIndex ((== tag ws) . tag)
-- | View next screen
nextScreen :: X ()
@ -349,7 +400,7 @@ the default screen keybindings:
> , (f, m) <- [(W.view, 0), (W.shift, shiftMask)]]
-}
screenBy :: Int -> X (ScreenId)
screenBy :: Int -> X ScreenId
screenBy d = do ws <- gets windowset
--let ss = sortBy screen (screens ws)
let now = screen (current ws)

View File

@ -1,6 +1,9 @@
{-# LANGUAGE ViewPatterns, MultiWayIf #-}
--------------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.CycleWindows
-- Description : Cycle windows while maintaining focus in place.
-- Copyright : (c) Wirt Wolff <wirtwolff@gmail.com>
-- License : BSD3-style (see LICENSE)
--
@ -47,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
@ -74,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
@ -116,7 +122,7 @@ cycleRecentWindows :: [KeySym] -- ^ A list of modifier keys used when invoking t
-- If it's the same as the first key, it is effectively ignored.
-> X ()
cycleRecentWindows = cycleStacks' stacks where
stacks s = map (shiftToFocus' `flip` s) (wins s)
stacks s = map (`shiftToFocus'` s) (wins s)
wins (W.Stack t l r) = t : r ++ reverse l
@ -134,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.
@ -178,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)
@ -204,8 +202,8 @@ 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)
rotFocused' f s@(W.Stack _ _ _) = rotSlaves' f s -- otherwise
where (notEmpty -> t' :| rs') = f (t:rs)
rotFocused' f s@W.Stack{} = rotSlaves' f s -- otherwise
-- $unfocused
@ -222,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

@ -0,0 +1,111 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.CycleWorkspaceByScreen
-- Description : Cycle workspaces in a screen-aware fashion.
-- Copyright : (c) 2017 Ivan Malison
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : IvanMalison@gmail.com
-- Stability : unstable
-- Portability : unportable
--
-- Cycle through previously viewed workspaces in the order they were viewed most
-- recently on the screen where cycling is taking place.
--
-----------------------------------------------------------------------------
module XMonad.Actions.CycleWorkspaceByScreen (
-- * Usage
-- $usage
cycleWorkspaceOnScreen
, cycleWorkspaceOnCurrentScreen
, handleKeyEvent
, repeatableAction
) where
import Data.IORef
import XMonad
import XMonad.Prelude
import XMonad.Hooks.WorkspaceHistory
import XMonad.Actions.Repeatable (repeatable)
import qualified XMonad.StackSet as W
-- $usage
--
-- 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)
{-# DEPRECATED repeatableAction "Use XMonad.Actions.Repeatable.repeatable" #-}
repeatableAction :: [KeySym] -> KeySym -> (EventType -> KeySym -> X ()) -> X ()
repeatableAction = repeatable
handleKeyEvent :: EventType
-> KeySym
-> X ()
-> EventType
-> KeySym
-> Maybe (X ())
handleKeyEvent eventType key action = helper
where
helper et k
| et == eventType && k == key = Just action
| otherwise = Nothing
runFirst :: [EventType -> KeySym -> Maybe (X ())] -> EventType -> KeySym -> X ()
runFirst matchers eventType key =
fromMaybe (return ()) $ join $ find isJust $ map (\fn -> fn eventType key) matchers
-- | 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
let cycleWorkspaces = fromMaybe [] $ lookup screenId startingHistory
getAndIncrementWS increment = do
current <- readIORef currentWSIndex
modifyIORef
currentWSIndex
((`mod` length cycleWorkspaces) . (+ increment))
return $ cycleWorkspaces !! current
focusIncrement i = io (getAndIncrementWS i) >>= (windows . W.greedyView)
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 =
withWindowSet $ \ws ->
cycleWorkspaceOnScreen (W.screen $ W.current ws) mods n p

View File

@ -1,6 +1,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.DeManage
-- Description : Cease management of a window without unmapping it.
-- Copyright : (c) Spencer Janssen <spencerjanssen@gmail.com>
-- License : BSD3-style (see LICENSE)
--
@ -38,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
--
@ -47,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

@ -1,6 +1,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.DwmPromote
-- Description : DWM-like swap function for xmonad.
-- Copyright : (c) Miikka Koskinen 2007
-- License : BSD3-style (see LICENSE)
--
@ -24,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
--
@ -36,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
@ -44,6 +48,6 @@ import XMonad.StackSet
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 _ [] [] -> c
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

@ -1,8 +1,7 @@
{-# LANGUAGE DeriveDataTypeable #-}
--------------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.DynamicProjects
-- Description : Treat workspaces as individual project areas.
-- Copyright : (c) Peter J. Jones
-- License : BSD3-style (see LICENSE)
--
@ -39,18 +38,14 @@ module XMonad.Actions.DynamicProjects
, lookupProject
, currentProject
, activateProject
, modifyProject
) where
--------------------------------------------------------------------------------
import Control.Applicative ((<|>))
import Control.Monad (when, unless)
import Data.Char (isSpace)
import Data.List (sort, union, stripPrefix)
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import Data.Maybe (fromMaybe, isNothing)
import Data.Monoid ((<>))
import System.Directory (setCurrentDirectory, getHomeDirectory)
import System.Directory (setCurrentDirectory, getHomeDirectory, makeAbsolute)
import XMonad.Prelude
import XMonad
import XMonad.Actions.DynamicWorkspaces
import XMonad.Prompt
@ -74,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
@ -114,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
@ -130,14 +127,14 @@ data Project = Project
{ projectName :: !ProjectName -- ^ Workspace name.
, projectDirectory :: !FilePath -- ^ Working directory.
, projectStartHook :: !(Maybe (X ())) -- ^ Optional start-up hook.
} deriving Typeable
}
--------------------------------------------------------------------------------
-- | Internal project state.
data ProjectState = ProjectState
{ projects :: !ProjectTable
, previousProject :: !(Maybe WorkspaceId)
} deriving Typeable
}
--------------------------------------------------------------------------------
instance ExtensionClass ProjectState where
@ -145,24 +142,24 @@ instance ExtensionClass ProjectState where
--------------------------------------------------------------------------------
-- Internal types for working with XPrompt.
data ProjectPrompt = ProjectPrompt ProjectMode [ProjectName]
data ProjectPrompt = ProjectPrompt XPConfig ProjectMode [ProjectName]
data ProjectMode = SwitchMode | ShiftMode | RenameMode | DirMode
instance XPrompt ProjectPrompt where
showXPrompt (ProjectPrompt submode _) =
showXPrompt (ProjectPrompt _ submode _) =
case submode of
SwitchMode -> "Switch or Create Project: "
ShiftMode -> "Send Window to Project: "
RenameMode -> "New Project Name: "
DirMode -> "Change Project Directory: "
completionFunction (ProjectPrompt RenameMode _) = return . (:[])
completionFunction (ProjectPrompt DirMode _) =
let xpt = directoryMultipleModes "" (const $ return ())
completionFunction (ProjectPrompt _ RenameMode _) = return . (:[])
completionFunction (ProjectPrompt c DirMode _) =
let xpt = directoryMultipleModes' (complCaseSensitivity c) "" (const $ return ())
in completionFunction xpt
completionFunction (ProjectPrompt _ ns) = mkComplFunFromList' ns
completionFunction (ProjectPrompt c _ ns) = mkComplFunFromList' c ns
modeAction (ProjectPrompt SwitchMode _) buf auto = do
modeAction (ProjectPrompt _ SwitchMode _) buf auto = do
let name = if null auto then buf else auto
ps <- XS.gets projects
@ -171,18 +168,19 @@ instance XPrompt ProjectPrompt where
Nothing | null name -> return ()
| otherwise -> switchProject (defProject name)
modeAction (ProjectPrompt ShiftMode _) buf auto = do
modeAction (ProjectPrompt _ ShiftMode _) buf auto = do
let name = if null auto then buf else auto
ps <- XS.gets projects
shiftToProject . fromMaybe (defProject name) $ Map.lookup name ps
modeAction (ProjectPrompt RenameMode _) name _ =
modeAction (ProjectPrompt _ RenameMode _) name _ =
when (not (null name) && not (all isSpace name)) $ do
renameWorkspaceByName name
modifyProject (\p -> p { projectName = name })
modeAction (ProjectPrompt DirMode _) buf auto = do
let dir = if null auto then buf else auto
modeAction (ProjectPrompt _ DirMode _) buf auto = do
let dir' = if null auto then buf else auto
dir <- io $ makeAbsolute dir'
modifyProject (\p -> p { projectDirectory = dir })
--------------------------------------------------------------------------------
@ -230,11 +228,13 @@ dynamicProjectsStartupHook ps = XS.modify go
--------------------------------------------------------------------------------
-- | Find a project based on its name.
lookupProject :: ProjectName -> X (Maybe Project)
lookupProject name = Map.lookup name `fmap` XS.gets projects
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)
@ -259,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
@ -326,11 +313,11 @@ changeProjectDirPrompt = projectPrompt [ DirMode
-- | Prompt for a project name.
projectPrompt :: [ProjectMode] -> XPConfig -> X ()
projectPrompt submodes c = do
ws <- map W.tag `fmap` gets (W.workspaces . windowset)
ws <- map W.tag <$> gets (W.workspaces . windowset)
ps <- XS.gets projects
let names = sort (Map.keys ps `union` ws)
modes = map (\m -> XPT $ ProjectPrompt m names) submodes
modes = map (\m -> XPT $ ProjectPrompt c m names) submodes
mkXPromptWithModes modes c

View File

@ -1,8 +1,7 @@
{-# LANGUAGE DeriveDataTypeable #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.DynamicWorkspaceGroups
-- Description : Dynamically manage workspace groups in multi-head setups.
-- Copyright : (c) Brent Yorgey 2009
-- License : BSD-style (see LICENSE)
--
@ -34,20 +33,25 @@ module XMonad.Actions.DynamicWorkspaceGroups
, promptWSGroupForget
, WSGPrompt
-- * TopicSpace Integration
-- $topics
, viewTopicGroup
, promptTopicGroupView
) where
import Data.List (find)
import Control.Arrow ((&&&))
import qualified Data.Map as M
import XMonad
import XMonad.Prelude (find, for_)
import qualified XMonad.StackSet as W
import XMonad.Prompt
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
--
@ -63,14 +67,14 @@ type WSGroup = [(ScreenId,WorkspaceId)]
type WSGroupId = String
data WSGroupStorage = WSG { unWSG :: M.Map WSGroupId WSGroup }
deriving (Typeable, Read, Show)
newtype WSGroupStorage = WSG { unWSG :: M.Map WSGroupId WSGroup }
deriving (Read, Show)
withWSG :: (M.Map WSGroupId WSGroup -> M.Map WSGroupId WSGroup) -> WSGroupStorage -> WSGroupStorage
withWSG f = WSG . f . unWSG
instance ExtensionClass WSGroupStorage where
initialValue = WSG $ M.empty
initialValue = WSG M.empty
extensionType = PersistentExtension
-- | Add a new workspace group of the given name, mapping to an
@ -85,9 +89,7 @@ addWSGroup :: WSGroupId -> [WorkspaceId] -> X ()
addWSGroup name wids = withWindowSet $ \w -> do
let wss = map ((W.tag . W.workspace) &&& W.screen) $ W.screens w
wmap = mapM (strength . (flip lookup wss &&& id)) wids
case wmap of
Just ps -> addRawWSGroup name ps
Nothing -> return ()
for_ wmap (addRawWSGroup name)
where strength (ma, b) = ma >>= \a -> return (a,b)
-- | Give a name to the current workspace group.
@ -103,20 +105,23 @@ forgetWSGroup = XS.modify . withWSG . M.delete
-- | View the workspace group with the given name.
viewWSGroup :: WSGroupId -> X ()
viewWSGroup name = do
WSG m <- XS.get
case M.lookup name m of
Just grp -> mapM_ (uncurry viewWS) grp
Nothing -> return ()
viewWSGroup = viewGroup (windows . W.greedyView)
-- | View the given workspace on the given screen.
viewWS :: ScreenId -> WorkspaceId -> X ()
viewWS sid wid = do
-- | Internal function for viewing a group.
viewGroup :: (WorkspaceId -> X ()) -> WSGroupId -> X ()
viewGroup fview name = do
WSG m <- XS.get
for_ (M.lookup name m) $
mapM_ (uncurry (viewWS fview))
-- | View the given workspace on the given screen, using the provided function.
viewWS :: (WorkspaceId -> X ()) -> ScreenId -> WorkspaceId -> X ()
viewWS fview sid wid = do
mw <- findScreenWS sid
case mw of
Just w -> do
windows $ W.view w
windows $ W.greedyView wid
fview wid
Nothing -> return ()
-- | Find the workspace which is currently on the given screen.
@ -124,16 +129,20 @@ findScreenWS :: ScreenId -> X (Maybe WorkspaceId)
findScreenWS sid = withWindowSet $
return . fmap (W.tag . W.workspace) . find ((==sid) . W.screen) . W.screens
data WSGPrompt = WSGPrompt String
newtype WSGPrompt = WSGPrompt String
instance XPrompt WSGPrompt where
showXPrompt (WSGPrompt s) = s
-- | Prompt for a workspace group to view.
promptWSGroupView :: XPConfig -> String -> X ()
promptWSGroupView xp s = do
promptWSGroupView = promptGroupView viewWSGroup
-- | Internal function for making a prompt to view a workspace group
promptGroupView :: (WSGroupId -> X ()) -> XPConfig -> String -> X ()
promptGroupView fview xp s = do
gs <- fmap (M.keys . unWSG) XS.get
mkXPrompt (WSGPrompt s) xp (mkComplFunFromList' gs) viewWSGroup
mkXPrompt (WSGPrompt s) xp (mkComplFunFromList' xp gs) fview
-- | Prompt for a name for the current workspace group.
promptWSGroupAdd :: XPConfig -> String -> X ()
@ -144,4 +153,25 @@ promptWSGroupAdd xp s =
promptWSGroupForget :: XPConfig -> String -> X ()
promptWSGroupForget xp s = do
gs <- fmap (M.keys . unWSG) XS.get
mkXPrompt (WSGPrompt s) xp (mkComplFunFromList' gs) forgetWSGroup
mkXPrompt (WSGPrompt s) xp (mkComplFunFromList' xp gs) forgetWSGroup
-- $topics
-- You can use this module with "XMonad.Actions.TopicSpace" — just replace
-- 'promptWSGroupView' with 'promptTopicGroupView':
--
-- > , ("M-y n", promptWSGroupAdd myXPConfig "Name this group: ")
-- > , ("M-y g", promptTopicGroupView myTopicConfig myXPConfig "Go to group: ")
-- > , ("M-y d", promptWSGroupForget myXPConfig "Forget group: ")
--
-- It's also a good idea to replace 'spawn' with
-- 'XMonad.Actions.SpawnOn.spawnOn' or 'XMonad.Actions.SpawnOn.spawnHere' in
-- your topic actions, so everything is spawned where it should be.
-- | Prompt for a workspace group to view, treating the workspaces as topics.
promptTopicGroupView :: TopicConfig -> XPConfig -> String -> X ()
promptTopicGroupView = promptGroupView . viewTopicGroup
-- | View the workspace group with the given name, treating the workspaces as
-- topics.
viewTopicGroup :: TopicConfig -> WSGroupId -> X ()
viewTopicGroup = viewGroup . switchTopic

View File

@ -1,8 +1,7 @@
{-# LANGUAGE DeriveDataTypeable #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.DynamicWorkspaceOrder
-- Description : Remember a dynamically updateable ordering on workspaces.
-- Copyright : (c) Brent Yorgey 2009
-- License : BSD-style (see LICENSE)
--
@ -12,7 +11,7 @@
--
-- Remember a dynamically updateable ordering on workspaces, together
-- with tools for using this ordering with "XMonad.Actions.CycleWS"
-- and "XMonad.Hooks.DynamicLog".
-- and "XMonad.Hooks.StatusBar.PP".
--
-----------------------------------------------------------------------------
@ -23,11 +22,16 @@ module XMonad.Actions.DynamicWorkspaceOrder
getWsCompareByOrder
, getSortByOrder
, swapWith
, swapWithCurrent
, swapOrder
, updateName
, removeName
, moveTo
, moveToGreedy
, shiftTo
, withNthWorkspace'
, withNthWorkspace
) where
@ -41,11 +45,11 @@ import XMonad.Actions.CycleWS (findWorkspace, WSType(..), Direction1D(..), doTo)
import qualified Data.Map as M
import qualified Data.Set as S
import Data.Maybe (fromJust, fromMaybe)
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
--
@ -64,10 +68,10 @@ import Data.Ord (comparing)
-- order of workspaces must be updated to use the auxiliary ordering.
--
-- To change the order in which workspaces are displayed by
-- "XMonad.Hooks.DynamicLog", use 'getSortByOrder' in your
-- 'XMonad.Hooks.DynamicLog.ppSort' field, for example:
-- "XMonad.Hooks.StatusBar.PP", use 'getSortByOrder' in your
-- 'XMonad.Hooks.StatusBar.PP.ppSort' field, for example:
--
-- > ... dynamicLogWithPP $ byorgeyPP {
-- > myPP = ... byorgeyPP {
-- > ...
-- > , ppSort = DO.getSortByOrder
-- > ...
@ -86,8 +90,8 @@ import Data.Ord (comparing)
-- tweak as desired.
-- | Extensible state storage for the workspace order.
data WSOrderStorage = WSO { unWSO :: Maybe (M.Map WorkspaceId Int) }
deriving (Typeable, Read, Show)
newtype WSOrderStorage = WSO { unWSO :: Maybe (M.Map WorkspaceId Int) }
deriving (Read, Show)
instance ExtensionClass WSOrderStorage where
initialValue = WSO Nothing
@ -148,10 +152,26 @@ 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
-- | Update the name of a workspace in the stored order.
updateName :: WorkspaceId -> WorkspaceId -> X ()
updateName oldId newId = XS.modify . withWSO $ changeKey oldId newId
-- | Remove a workspace from the stored order.
removeName :: WorkspaceId -> X ()
removeName = XS.modify . withWSO . M.delete
-- | Update a key in a Map.
changeKey :: Ord k => k -> k -> M.Map k a -> M.Map k a
changeKey oldKey newKey oldMap =
case M.updateLookupWithKey (\_ _ -> Nothing) oldKey oldMap of
(Nothing, _) -> oldMap
(Just val, newMap) -> M.insert newKey val newMap
-- | View the next workspace of the given type in the given direction,
-- where \"next\" is determined using the dynamic workspace order.
moveTo :: Direction1D -> WSType -> X ()
@ -166,13 +186,19 @@ moveToGreedy dir t = doTo dir t getSortByOrder (windows . W.greedyView)
shiftTo :: Direction1D -> WSType -> X ()
shiftTo dir t = doTo dir t getSortByOrder (windows . W.shift)
-- | Do something with the nth workspace in the dynamic order after
-- transforming it. The callback is given the workspace's tag as well
-- as the 'WindowSet' of the workspace itself.
withNthWorkspace' :: ([WorkspaceId] -> [WorkspaceId]) -> (String -> WindowSet -> WindowSet) -> Int -> X ()
withNthWorkspace' tr job wnum = do
sort <- getSortByOrder
ws <- gets (tr . map W.tag . sort . W.workspaces . windowset)
case drop wnum ws of
(w:_) -> windows $ job w
[] -> return ()
-- | Do something with the nth workspace in the dynamic order. The
-- callback is given the workspace's tag as well as the 'WindowSet'
-- of the workspace itself.
withNthWorkspace :: (String -> WindowSet -> WindowSet) -> Int -> X ()
withNthWorkspace job wnum = do
sort <- getSortByOrder
ws <- gets (map W.tag . sort . W.workspaces . windowset)
case drop wnum ws of
(w:_) -> windows $ job w
[] -> return ()
withNthWorkspace = withNthWorkspace' id

View File

@ -1,8 +1,7 @@
{-# LANGUAGE DeriveDataTypeable #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.DynamicWorkspaces
-- Description : Provides bindings to add and delete workspaces.
-- Copyright : (c) David Roundy <droundy@darcs.net>
-- License : BSD3-style (see LICENSE)
--
@ -35,19 +34,17 @@ module XMonad.Actions.DynamicWorkspaces (
WorkspaceIndex
) where
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 Data.List (find)
import Data.Maybe (isNothing)
import Control.Monad (when)
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)
@ -78,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
@ -88,8 +85,8 @@ type WorkspaceIndex = Int
-- | Internal dynamic project state that stores a mapping between
-- workspace indexes and workspace tags.
data DynamicWorkspaceState = DynamicWorkspaceState {workspaceIndexMap :: Map.Map WorkspaceIndex WorkspaceTag}
deriving (Typeable, Read, Show)
newtype DynamicWorkspaceState = DynamicWorkspaceState {workspaceIndexMap :: Map.Map WorkspaceIndex WorkspaceTag}
deriving (Read, Show)
instance ExtensionClass DynamicWorkspaceState where
initialValue = DynamicWorkspaceState Map.empty
@ -108,11 +105,7 @@ withWorkspaceIndex job widx = do
maybe (return ()) (windows . job) wtag
where
ilookup :: WorkspaceIndex -> X (Maybe WorkspaceTag)
ilookup idx = Map.lookup idx `fmap` XS.gets workspaceIndexMap
mkCompl :: [String] -> String -> IO [String]
mkCompl l s = return $ filter (\x -> take (length s) x == s) l
ilookup idx = Map.lookup idx <$> XS.gets workspaceIndexMap
withWorkspace :: XPConfig -> (String -> X ()) -> X ()
withWorkspace c job = do ws <- gets (workspaces . windowset)
@ -120,21 +113,21 @@ withWorkspace c job = do ws <- gets (workspaces . windowset)
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
renameWorkspaceByName :: String -> X ()
renameWorkspaceByName w = do old <- gets (currentTag . windowset)
windows $ \s -> let sett wk = wk { tag = w }
setscr scr = scr { workspace = sett $ workspace scr }
sets q = q { current = setscr $ current q }
windows $ \s -> let sett wk = wk { tag = w }
setscr scr = scr { workspace = sett $ workspace scr }
sets q = q { current = setscr $ current q }
in sets $ removeWorkspace' w s
updateIndexMap old w
where updateIndexMap old new = do
updateIndexMap old w
where updateIndexMap oldIM newIM = do
wmap <- XS.gets workspaceIndexMap
XS.modify $ \s -> s {workspaceIndexMap = Map.map (\t -> if t == old then new else t) wmap}
XS.modify $ \s -> s {workspaceIndexMap = Map.map (\t -> if t == oldIM then newIM else t) wmap}
toNthWorkspace :: (String -> X ()) -> Int -> X ()
toNthWorkspace job wnum = do sort <- getSortByIndex
@ -241,20 +234,20 @@ isEmpty t = do wsl <- gets $ workspaces . windowset
return $ maybe True (isNothing . stack) mws
addHiddenWorkspace' :: (Workspace i l a -> [Workspace i l a] -> [Workspace i l a]) -> i -> l -> StackSet i l a sid sd -> StackSet i l a sid sd
addHiddenWorkspace' add newtag l s@(StackSet { hidden = ws }) = s { hidden = add (Workspace newtag l Nothing) ws }
addHiddenWorkspace' add newtag l s@StackSet{ hidden = ws } = s { hidden = add (Workspace newtag l Nothing) ws }
-- | Remove the hidden workspace with the given tag from the StackSet, if
-- it exists. All the windows in that workspace are moved to the current
-- workspace.
removeWorkspace' :: (Eq i) => i -> StackSet i l a sid sd -> StackSet i l a sid sd
removeWorkspace' torem s@(StackSet { current = scr@(Screen { workspace = wc })
, hidden = hs })
removeWorkspace' :: (Eq i, Eq a) => i -> StackSet i l a sid sd -> StackSet i l a sid sd
removeWorkspace' torem s@StackSet{ current = scr@Screen { workspace = wc }
, hidden = hs }
= let (xs, ys) = break ((== torem) . tag) hs
in removeWorkspace'' xs ys
where meld Nothing Nothing = Nothing
meld x Nothing = x
meld Nothing x = x
meld (Just x) (Just y) = differentiate (integrate x ++ integrate y)
meld (Just x) (Just y) = differentiate . nub $ integrate x ++ integrate y
removeWorkspace'' xs (y:ys) = s { current = scr { workspace = wc { stack = meld (stack y) (stack wc) } }
, hidden = xs ++ ys }
removeWorkspace'' _ _ = s

View File

@ -0,0 +1,391 @@
{-# LANGUAGE CPP #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE ScopedTypeVariables #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.EasyMotion
-- Description : Focus a visible window using a key chord.
-- Copyright : (c) Matt Kingston <mattkingston@gmail.com>
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : mattkingston@gmail.com
-- Stability : unstable
-- Portability : unportable
--
-- Provides functionality to use key chords to focus a visible window. Overlays a unique key chord
-- (a string) above each visible window and allows the user to select a window by typing that
-- chord.
-- Inspired by <https://github.com/easymotion/vim-easymotion vim-easymotion>.
-- Thanks to <https://github.com/larkery Tom Hinton> for some feature inspiration and window
-- sorting code.
--
-----------------------------------------------------------------------------
module XMonad.Actions.EasyMotion ( -- * Usage
-- $usage
selectWindow
-- * Configuration
, EasyMotionConfig(..)
, ChordKeys(..)
, def
-- * Creating overlays
, fullSize
, fixedSize
, textSize
, proportional
, bar
) where
import XMonad
import XMonad.Prelude
import qualified XMonad.StackSet as W
import XMonad.Util.Font (releaseXMF, initXMF, Align(AlignCenter), XMonadFont(..), textExtentsXMF)
import XMonad.Util.XUtils (createNewWindow, paintAndWrite, deleteWindow, showWindow)
import Control.Arrow ((&&&))
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.hs@:
--
-- > import XMonad.Actions.EasyMotion (selectWindow)
--
-- To customise
--
-- > import XMonad.Actions.EasyMotion (selectWindow, EasyMotionConfig(..))
--
-- Then add a keybinding and an action to the 'selectWindow' function.
-- In this case @M-f@ to focus the selected window:
--
-- > , ((modm, xK_f), selectWindow def >>= (`whenJust` windows . W.focusWindow))
--
-- Similarly, to kill a window with @M-f@:
--
-- > , ((modm, xK_f), selectWindow def >>= (`whenJust` killWindow))
--
-- See 'EasyMotionConfig' for all configuration options. A short summary follows.
--
-- Default chord keys are @s,d,f,j,k,l@. To customise these and display options assign
-- different values to 'def' (the default configuration):
--
-- > , ((modm, xK_f), (selectWindow def{sKeys = AnyKeys [xK_f, xK_d]}) >>= (`whenJust` windows . W.focusWindow))
--
-- You must supply at least two different keys in the 'sKeys' list. Keys provided earlier in the list
-- will be used preferentially—therefore, keys you would like to use more frequently should be
-- earlier in the list.
--
-- To map different sets of keys to different screens. The following configuration maps keys @fdsa@
-- to screen 0 and @hjkl@ to screen 1. Keys provided earlier in the list will be used preferentially.
-- Providing the same key for multiple screens is possible but will break down in some scenarios.
--
-- > import qualified Data.Map.Strict as StrictMap (fromList)
-- > emConf :: EasyMotionConfig
-- > emConf = def { sKeys = PerScreenKeys $ StrictMap.fromList [(0, [xK_f, xK_d, xK_s, xK_a]), (1, [xK_h, xK_j, xK_k, xK_l])] }
-- > -- key bindings
-- > , ((modm, xK_f), selectWindow emConf >>= (`whenJust` windows . W.focusWindow))
--
-- To customise the font:
--
-- > , ((modm, xK_f), (selectWindow def{emFont = "xft: Sans-40"}) >>= (`whenJust` windows . W.focusWindow))
--
-- The 'emFont' field provided is supplied directly to the 'initXMF' function. The default is
-- @"xft:Sans-100"@. Some example options:
--
-- > "xft: Sans-40"
-- > "xft: Arial-100"
-- > "xft: Cambria-80"
--
-- Customise the overlay by supplying a function to 'overlayF'. The signature is
-- @'Position' -> 'Rectangle' -> 'Rectangle'@. The parameters are the height in pixels of
-- the selection chord and the rectangle of the window to be overlaid. Some are provided:
--
-- > import XMonad.Actions.EasyMotion (selectWindow, EasyMotionConfig(..), proportional, bar, fullSize)
-- > , ((modm, xK_f), (selectWindow def{ overlayF = proportional 0.3 }) >>= (`whenJust` windows . W.focusWindow))
-- > , ((modm, xK_f), (selectWindow def{ overlayF = bar 0.5 }) >>= (`whenJust` windows . W.focusWindow))
-- > , ((modm, xK_f), (selectWindow def{ overlayF = fullSize }) >>= (`whenJust` windows . W.focusWindow))
-- > , ((modm, xK_f), (selectWindow def{ overlayF = fixedSize 300 350 }) >>= (`whenJust` windows . W.focusWindow))
-- TODO:
-- - An overlay function that creates an overlay a proportion of the width XOR height of the
-- window it's over, and with a fixed w/h proportion? E.g. overlay-height = 0.3 *
-- target-window-height; overlay-width = 0.5 * overlay-height.
-- - An overlay function that creates an overlay of a fixed w,h, aligned mid,mid, or parametrised
-- alignment?
-- - Parametrise chord generation?
-- - W.shift example; bring window from other screen to current screen? Only useful if we don't
-- show chords on current workspace.
-- - Use stringToKeysym, keysymToKeycode, keycodeToKeysym, keysymToString to take a string from
-- the user?
-- - Think a bit more about improving functionality with floating windows.
-- - currently, floating window z-order is not respected
-- - could ignore floating windows
-- - may be able to calculate the visible section of a floating window, and display the chord in
-- that space
-- - Provide an option to prepend the screen key to the easymotion keys (i.e. w,e,r)?
-- - overlay alpha
-- - Delay after selection so the user can see what they've chosen? Min-delay: 0 seconds. If
-- there's a delay, perhaps keep the other windows covered briefly to naturally draw the user's
-- attention to the window they've selected? Or briefly highlight the border of the selected
-- window?
-- - Option to cover windows that will not be selected by the current chord, such that it's
-- slightly more obvious where to maintain focus.
-- - Something unpleasant happens when the user provides only two keys (let's say f, d) for
-- chords. When they have five windows open, the following chords are generated: ddd, ddf, dfd,
-- dff, fdd. When 'f' is pressed, all chords disappear unexpectedly because we know there are no
-- other valid options. The user expects to press 'fdd'. This is an optimisation in software but
-- pretty bad for usability, as the user continues firing keys into their
-- now-unexpectedly-active window. And is of course only one concrete example of a more general
-- problem.
-- Short-term solution:
-- - Keep displaying the chord until the user has fully entered it
-- Fix:
-- - Show the shortest possible chords
-- | Associates a user window, an overlay window created by this module and a rectangle
-- circumscribing these windows
data OverlayWindow =
OverlayWindow { win :: !Window -- ^ The window managed by xmonad
, attrs :: !WindowAttributes -- ^ Window attributes for @win@
, overlay :: !Window -- ^ Our window used to display the overlay
, rect :: !Rectangle -- ^ The rectangle of @overlay@
}
-- | An overlay window and the chord used to select it
data Overlay =
Overlay { overlayWin :: !OverlayWindow -- ^ The window managed by xmonad
, chord :: ![KeySym] -- ^ The chord we'll display in the overlay
}
-- | Maps keys to windows. 'AnyKeys' maps keys to windows regardless which screen they're on.
-- 'PerScreenKeys' maps keys to screens to windows. See @Usage@ for more examples.
data ChordKeys = AnyKeys ![KeySym]
| PerScreenKeys !(M.Map ScreenId [KeySym])
-- | Configuration options for EasyMotion.
--
-- All colors are hex strings, e.g. "#000000"
--
-- If the number of windows for which chords are required exceeds 'maxChordLen', chords
-- will simply not be generated for these windows. In this way, single-key selection may be
-- preferred over the ability to select any window.
--
-- 'cancelKey', @xK_BackSpace@ and any duplicates will be removed from 'sKeys' if included.
-- See @Usage@ for examples of 'sKeys'.
data EasyMotionConfig =
EMConf { txtCol :: !String -- ^ Color of the text displayed
, bgCol :: !String -- ^ Color of the window overlaid
, overlayF :: !(Position -> Rectangle -> Rectangle) -- ^ Function to generate overlay rectangle
, borderCol :: !String -- ^ Color of the overlay window borders
, sKeys :: !ChordKeys -- ^ Keys to use for window selection
, cancelKey :: !KeySym -- ^ Key to use to cancel selection
, emFont :: !String -- ^ Font for selection characters (passed to 'initXMF')
, borderPx :: !Int -- ^ Width of border in pixels
, maxChordLen :: !Int -- ^ Maximum chord length. Use 0 for no maximum.
}
instance Default EasyMotionConfig where
def =
EMConf { txtCol = "#ffffff"
, bgCol = "#000000"
, overlayF = proportional (0.3::Double)
, borderCol = "#ffffff"
, sKeys = AnyKeys [xK_s, xK_d, xK_f, xK_j, xK_k, xK_l]
, cancelKey = xK_q
, borderPx = 1
, maxChordLen = 0
#ifdef XFT
, emFont = "xft:Sans-100"
#else
, emFont = "-misc-fixed-*-*-*-*-200-*-*-*-*-*-*-*"
#endif
}
-- | Create overlay windows of the same size as the window they select
fullSize :: Position -> Rectangle -> Rectangle
fullSize _ = id
-- | Create overlay windows a proportion of the size of the window they select
proportional :: RealFrac f => f -> Position -> Rectangle -> Rectangle
proportional f th r = Rectangle { rect_width = newW
, rect_height = newH
, rect_x = rect_x r + fi (rect_width r - newW) `div` 2
, rect_y = rect_y r + fi (rect_height r - newH) `div` 2 }
where
newH = max (fi th) (round $ f * fi (rect_height r))
newW = newH
-- | Create fixed-size overlay windows
fixedSize :: (Integral a, Integral b) => a -> b -> Position -> Rectangle -> Rectangle
fixedSize w h th r = Rectangle { rect_width = rw
, rect_height = rh
, rect_x = rect_x r + fi (rect_width r - rw) `div` 2
, rect_y = rect_y r + fi (rect_height r - rh) `div` 2 }
where
rw = max (fi w) (fi th)
rh = max (fi h) (fi th)
-- | Create overlay windows the minimum size to contain their key chord
textSize :: Position -> Rectangle -> Rectangle
textSize th r = Rectangle { rect_width = fi th
, rect_height = fi th
, rect_x = rect_x r + (fi (rect_width r) - fi th) `div` 2
, rect_y = rect_y r + (fi (rect_height r) - fi th) `div` 2 }
-- | Create overlay windows the full width of the window they select, the minimum height to contain
-- their chord, and a proportion of the distance from the top of the window they select
bar :: RealFrac f => f -> Position -> Rectangle -> Rectangle
bar f th r = Rectangle { rect_width = rect_width r
, rect_height = fi th
, rect_x = rect_x r
, rect_y = rect_y r + round (f' * (fi (rect_height r) - fi th)) }
where
-- clamp f in [0,1] as other values will appear to lock up xmonad as the overlay will be
-- displayed off-screen
f' = min 0.0 $ max f 1.0
-- | Handles overlay display and window selection. Called after config has been sanitised.
handleSelectWindow :: EasyMotionConfig -> X (Maybe Window)
handleSelectWindow EMConf { sKeys = AnyKeys [] } = return Nothing
handleSelectWindow c = do
f <- initXMF $ emFont c
th <- (\(asc, dsc) -> asc + dsc + 2) <$> textExtentsXMF f (concatMap keysymToString (allKeys . sKeys $ c))
XConf { theRoot = rw, display = dpy } <- ask
XState { mapped = mappedWins, windowset = ws } <- get
-- build overlays depending on key configuration
overlays :: [Overlay] <- case sKeys c of
AnyKeys ks -> buildOverlays ks <$> sortedOverlayWindows
where
visibleWindows :: [Window]
visibleWindows = toList mappedWins
sortedOverlayWindows :: X [OverlayWindow]
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 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 th (visibleWindowsOnScreen sid)
status <- io $ grabKeyboard dpy rw True grabModeAsync grabModeAsync currentTime
if status == grabSuccess
then do
resultWin <- handleKeyboard dpy (displayOverlay f) (cancelKey c) overlays []
io $ ungrabKeyboard dpy currentTime
mapM_ (deleteWindow . overlay . overlayWin) overlays
io $ sync dpy False
releaseXMF f
case resultWin of
-- focus the selected window
Selected o -> return . Just . win . overlayWin $ o
-- return focus correctly
_ -> whenJust (W.peek ws) (windows . W.focusWindow) $> Nothing
else releaseXMF f $> Nothing
where
allKeys :: ChordKeys -> [KeySym]
allKeys (AnyKeys ks) = ks
allKeys (PerScreenKeys m) = concat $ M.elems m
buildOverlays :: [KeySym] -> [OverlayWindow] -> [Overlay]
buildOverlays = appendChords (maxChordLen c)
buildOverlayWindows :: Position -> [Window] -> X [OverlayWindow]
buildOverlayWindows th = fmap (fromMaybe [] . sequenceA)
. traverse (buildOverlayWin th)
sortOverlayWindows :: [OverlayWindow] -> [OverlayWindow]
sortOverlayWindows = sortOn ((wa_x &&& wa_y) . attrs)
makeRect :: WindowAttributes -> Rectangle
makeRect wa = Rectangle (fi (wa_x wa)) (fi (wa_y wa)) (fi (wa_width wa)) (fi (wa_height wa))
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 . Just $ OverlayWindow { rect=r, overlay=o, win=w, attrs=wAttrs }
-- | Display an overlay with the provided formatting
displayOverlay :: XMonadFont -> Overlay -> X ()
displayOverlay f Overlay { overlayWin = OverlayWindow { rect = r, overlay = o }, chord = ch } = do
showWindow o
paintAndWrite o f (fi (rect_width r)) (fi (rect_height r)) (fi (borderPx c)) (bgCol c) (borderCol c) (txtCol c) (bgCol c) [AlignCenter] [concatMap keysymToString ch]
-- | Display overlay windows and chords for window selection
selectWindow :: EasyMotionConfig -> X (Maybe Window)
selectWindow conf =
handleSelectWindow conf { sKeys = sanitiseKeys (sKeys conf) }
where
-- make sure the key lists don't contain: backspace, our cancel key, or duplicates
sanitise :: [KeySym] -> [KeySym]
sanitise = nub . filter (`notElem` [xK_BackSpace, cancelKey conf])
sanitiseKeys :: ChordKeys -> ChordKeys
sanitiseKeys cKeys =
case cKeys of
AnyKeys ks -> AnyKeys . sanitise $ ks
PerScreenKeys m -> PerScreenKeys $ M.map sanitise m
-- | Take a list of overlays lacking chords, return a list of overlays with key chords
appendChords :: Int -> [KeySym] -> [OverlayWindow] -> [Overlay]
appendChords _ [] _ = []
appendChords maxUserSelectedLen ks overlayWins =
zipWith Overlay overlayWins chords
where
chords = replicateM chordLen ks
-- the minimum necessary chord length to assign a unique chord to each visible window
minCoverLen = -((-(length overlayWins)) `div` length ks)
-- if the user has specified a max chord length we use this even if it will not cover all
-- windows, as they may prefer to focus windows with fewer keys over the ability to focus any
-- window
chordLen = if maxUserSelectedLen <= 0 then minCoverLen else min minCoverLen maxUserSelectedLen
-- | A three-state result for handling user-initiated selection cancellation, successful selection,
-- or backspace.
data HandleResult = Exit | Selected Overlay | Backspace
-- | Handle key press events for window selection.
handleKeyboard :: Display -> (Overlay -> X()) -> KeySym -> [Overlay] -> [Overlay] -> X HandleResult
handleKeyboard _ _ _ [] _ = return Exit
handleKeyboard dpy drawFn cancel selected deselected = do
redraw
ev <- io $ allocaXEvent $ \e -> do
maskEvent dpy (keyPressMask .|. keyReleaseMask .|. buttonPressMask) e
getEvent e
if | ev_event_type ev == keyPress -> do
s <- io $ keycodeToKeysym dpy (ev_keycode ev) 0
if | s == cancel -> return Exit
| s == xK_BackSpace -> return Backspace
| isNextOverlayKey s -> handleNextOverlayKey s
| otherwise -> handleKeyboard dpy drawFn cancel selected deselected
| ev_event_type ev == buttonPress -> do
-- See XMonad.Prompt Note [Allow ButtonEvents]
io $ allowEvents dpy replayPointer currentTime
handleKeyboard dpy drawFn cancel selected deselected
| otherwise -> handleKeyboard dpy drawFn cancel selected deselected
where
redraw = mapM (mapM_ drawFn) [selected, deselected]
retryBackspace x =
case x of
Backspace -> redraw >> handleKeyboard dpy drawFn cancel selected deselected
_ -> return x
isNextOverlayKey keySym = isJust (find ((== Just keySym) . listToMaybe .chord) selected)
handleNextOverlayKey keySym =
case fg of
[x] -> return $ Selected x
_ -> handleKeyboard dpy drawFn cancel (trim fg) (clear bg) >>= retryBackspace
where
(fg, bg) = partition ((== Just keySym) . listToMaybe . chord) selected
trim = map (\o -> o { chord = drop 1 $ chord o })
clear = map (\o -> o { chord = [] })

View File

@ -1,6 +1,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.FindEmptyWorkspace
-- Description : Find an empty workspace.
-- Copyright : (c) Miikka Koskinen 2007
-- License : BSD3-style (see LICENSE)
--
@ -18,15 +19,13 @@ module XMonad.Actions.FindEmptyWorkspace (
viewEmptyWorkspace, tagToEmptyWorkspace, sendToEmptyWorkspace
) where
import Data.List
import Data.Maybe ( isNothing )
import XMonad.Prelude
import XMonad
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
--
@ -39,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

@ -1,8 +1,9 @@
{-# LANGUAGE FlexibleInstances, TypeSynonymInstances #-}
{-# LANGUAGE FlexibleInstances #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.FlexibleManipulate
-- Description : Move and resize floating windows without warping the mouse.
-- Copyright : (c) Michael Sloan
-- License : BSD3-style (see LICENSE)
--
@ -23,11 +24,12 @@ module XMonad.Actions.FlexibleManipulate (
) where
import XMonad
import XMonad.Prelude ((<&>), fi)
import qualified Prelude as P
import Prelude (($), (.), fst, snd, uncurry, const, id, Ord(..), Monad(..), fromIntegral, Double, Integer, map, round, otherwise)
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
--
@ -78,43 +80,36 @@ 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
io $ raiseWindow d w
[wpos, wsize] <- io $ getWindowAttributes d w >>= return . 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 >>= return . pointerPos
pointer <- io $ queryPointer d w <&> pointerPos
let uv = (pointer - wpos) / wsize
fc = mapP f uv
mul = mapP (\x -> 2 P.- 2 P.* P.abs(x P.- 0.5)) fc --Fudge factors: interpolation between 1 when on edge, 2 in middle
atl = ((1, 1) - fc) * mul
abr = fc * mul
mouseDrag (\ex ey -> io $ do
mouseDrag (\ex ey -> do
let offset = (fromIntegral ex, fromIntegral ey) - pointer
npos = wpos + offset * atl
nbr = (wpos + wsize) + offset * abr
ntl = minP (nbr - (32, 32)) npos --minimum size
nwidth = applySizeHintsContents sh $ mapP (round :: Double -> Integer) (nbr - ntl)
moveResizeWindow d w (round $ fst ntl) (round $ snd ntl) `uncurry` nwidth
return ())
io $ moveResizeWindow d w (round $ fst ntl) (round $ snd ntl) `uncurry` nwidth
float w)
(float w)
float w
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)
@ -132,4 +127,3 @@ infixl 7 *, /
(*) = zipP (P.*)
(/) :: (P.Fractional a) => (a,a) -> (a,a) -> (a,a)
(/) = zipP (P./)

View File

@ -1,6 +1,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.FlexibleResize
-- Description : Resize floating windows from any corner.
-- Copyright : (c) Lukas Mai
-- License : BSD3-style (see LICENSE)
--
@ -20,11 +21,11 @@ module XMonad.Actions.FlexibleResize (
) where
import XMonad
import XMonad.Util.XUtils (fi)
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
--
@ -49,29 +50,32 @@ 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
io $ raiseWindow d w
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
(cy, fy, gy) = mkSel north height pos_y
io $ warpPointer d none w 0 0 0 0 cx cy
mouseDrag (\ex ey -> do let (nw,nh) = applySizeHintsContents sh (gx ex, gy ey)
io $ moveResizeWindow d w (fx nw) (fy nh) nw nh)
io $ moveResizeWindow d w (fx nw) (fy nh) nw nh
float w)
(float w)
where
findPos :: CInt -> Position -> Maybe Bool
findPos m s = if p < 0.5 - edge/2
then Just True
else if p < 0.5 + edge/2
then Nothing
else Just False
where p = fi m / fi s
findPos m s
| p < 0.5 - edge/2 = Just True
| p < 0.5 + edge/2 = Nothing
| otherwise = Just False
where
p = fi m / fi s
mkSel :: Maybe Bool -> Position -> Position -> (Position, Dimension -> Position, Position -> Dimension)
mkSel b k p = case b of
Just True -> (0, (fi k + fi p -).fi, (fi k + fi p -).fi)

View File

@ -1,6 +1,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.FloatKeys
-- Description : Move and resize floating windows.
-- Copyright : (c) Karsten Schoelzel <kuser@gmx.de>
-- License : BSD
--
@ -18,13 +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
--
@ -36,17 +42,44 @@ import XMonad
-- > , ((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
io $ raiseWindow d w
wa <- io $ getWindowAttributes d w
io $ moveWindow d w (fromIntegral (fromIntegral (wa_x wa) + dx))
(fromIntegral (fromIntegral (wa_y wa) + dy))
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
-- | @keysMoveWindowTo (x, y) (gx, gy)@ moves the window relative
@ -60,15 +93,15 @@ 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
io $ raiseWindow d w
wa <- io $ getWindowAttributes d w
io $ moveWindow d w (x - round (gx * fromIntegral (wa_width wa)))
(y - round (gy * fromIntegral (wa_height wa)))
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
type G = (Rational, Rational)
type P = (Position, Position)
type ChangeDim = (Int, Int)
-- | @keysResizeWindow (dx, dy) (gx, gy)@ changes the width by @dx@
-- and the height by @dy@, leaving the window-relative point @(gx,
@ -80,7 +113,7 @@ type P = (Position, Position)
-- > keysResizeWindow (10, 0) (0, 1%2) -- does the same, unless sizeHints are applied
-- > keysResizeWindow (10, 10) (1%2, 1%2) -- add 5 pixels on each side
-- > keysResizeWindow (-10, -10) (0, 1) -- shrink the window in direction of the bottom-left corner
keysResizeWindow :: D -> G -> Window -> X ()
keysResizeWindow :: ChangeDim -> G -> Window -> X ()
keysResizeWindow = keysMoveResize keysResizeWindow'
-- | @keysAbsResizeWindow (dx, dy) (ax, ay)@ changes the width by @dx@
@ -90,34 +123,34 @@ keysResizeWindow = keysMoveResize keysResizeWindow'
-- For example:
--
-- > keysAbsResizeWindow (10, 10) (0, 0) -- enlarge the window; if it is not in the top-left corner it will also be moved down and to the right.
keysAbsResizeWindow :: D -> D -> Window -> X ()
keysAbsResizeWindow :: ChangeDim -> D -> Window -> X ()
keysAbsResizeWindow = keysMoveResize keysAbsResizeWindow'
keysAbsResizeWindow' :: SizeHints -> P -> D -> D -> D -> (P,D)
keysAbsResizeWindow' :: SizeHints -> P -> D -> ChangeDim -> D -> (P,D)
keysAbsResizeWindow' sh (x,y) (w,h) (dx,dy) (ax, ay) = ((round nx, round ny), (nw, nh))
where
(nw, nh) = applySizeHintsContents sh (w + dx, h + dy)
-- The width and height of a window are positive and thus
-- converting to 'Dimension' should be safe.
(nw, nh) = applySizeHintsContents sh (fi w + dx, fi h + dy)
nx :: Rational
nx = fromIntegral (ax * w + nw * (fromIntegral x - ax)) / fromIntegral w
nx = fi (ax * w + nw * (fi x - ax)) / fi w
ny :: Rational
ny = fromIntegral (ay * h + nh * (fromIntegral y - ay)) / fromIntegral h
ny = fi (ay * h + nh * (fi y - ay)) / fi h
keysResizeWindow' :: SizeHints -> P -> D -> D -> G -> (P,D)
keysResizeWindow' :: SizeHints -> P -> D -> ChangeDim -> G -> (P,D)
keysResizeWindow' sh (x,y) (w,h) (dx,dy) (gx, gy) = ((nx, ny), (nw, nh))
where
(nw, nh) = applySizeHintsContents sh (w + dx, h + dy)
nx = round $ fromIntegral x + gx * fromIntegral w - gx * fromIntegral nw
ny = round $ fromIntegral y + gy * fromIntegral h - gy * fromIntegral nh
(nw, nh) = applySizeHintsContents sh (fi w + dx, fi h + dy)
nx = round $ fi x + gx * fi w - gx * fi nw
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
io $ raiseWindow d w
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 = (fromIntegral $ wa_width wa, fromIntegral $ wa_height wa)
wa_pos = (fromIntegral $ wa_x wa, fromIntegral $ wa_y wa)
let wa_dim = (fi $ wa_width wa, fi $ wa_height wa)
wa_pos = (fi $ wa_x wa, fi $ wa_y wa)
(wn_pos, wn_dim) = f sh wa_pos wa_dim move resize
io $ resizeWindow d w `uncurry` wn_dim
io $ moveWindow d w `uncurry` wn_pos
float w

View File

@ -1,6 +1,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Layout.FloatSnap
-- Description : Snap to other windows or the edge of the screen while moving or resizing.
-- Copyright : (c) 2009 Anders Engstrom <ankaan@gmail.com>
-- License : BSD3-style (see LICENSE)
--
@ -27,9 +28,7 @@ module XMonad.Actions.FloatSnap (
ifClick') where
import XMonad
import Control.Applicative((<$>))
import Data.List (sort)
import Data.Maybe (listToMaybe,fromJust,isNothing)
import XMonad.Prelude (fromJust, isNothing, listToMaybe, sort, when)
import qualified XMonad.StackSet as W
import qualified Data.Set as S
@ -38,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
--
@ -54,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:
--
@ -93,17 +92,17 @@ 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)
ml = if x <= (0.5 - middle/2) then [L] else []
mr = if x > (0.5 + middle/2) then [R] else []
mu = if y <= (0.5 - middle/2) then [U] else []
md = if y > (0.5 + middle/2) then [D] else []
let x = (fromIntegral px - wx wa)/ww wa
y = (fromIntegral py - wy wa)/wh wa
ml = [L | x <= (0.5 - middle/2)]
mr = [R | x > (0.5 + middle/2)]
mu = [U | y <= (0.5 - middle/2)]
md = [D | y > (0.5 + middle/2)]
mdir = ml++mr++mu++md
dir = if mdir == []
dir = if null mdir
then [L,R,U,D]
else mdir
snapMagicResize dir collidedist snapdist w
@ -120,19 +119,17 @@ 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
io $ raiseWindow d w
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
let xbegin' = if L `elem` dir then xbegin else (wx wa)
xend' = if R `elem` dir then xend else (wx wa + ww wa)
ybegin' = if U `elem` dir then ybegin else (wy wa)
yend' = if D `elem` dir then yend else (wy wa + wh wa)
let xbegin' = if L `elem` dir then xbegin else wx wa
xend' = if R `elem` dir then xend else wx wa + ww wa
ybegin' = if U `elem` dir then ybegin else wy wa
yend' = if D `elem` dir then yend else wy wa + wh wa
io $ moveWindow d w (fromIntegral $ xbegin') (fromIntegral $ ybegin')
io $ moveWindow d w (fromIntegral xbegin') (fromIntegral ybegin')
io $ resizeWindow d w (fromIntegral $ xend' - xbegin') (fromIntegral $ yend' - ybegin')
float w
where
@ -152,13 +149,13 @@ snapMagicResize dir collidedist snapdist w = whenX (isClient w) $ withDisplay $
(Nothing,Nothing) -> wpos wa
end = if fs
then wpos wa + wdim wa
else case (if mfl==(Just begin) then Nothing else mfl,mfr) of
else case (if mfl==Just begin then Nothing else mfl,mfr) of
(Just fl,Just fr) -> if wpos wa + wdim wa - fl < fr - wpos wa - wdim wa then fl else fr
(Just fl,Nothing) -> fl
(Nothing,Just fr) -> fr
(Nothing,Nothing) -> wpos wa + wdim wa
begin' = if isNothing snapdist || abs (begin - wpos wa) <= fromJust snapdist then begin else (wpos wa)
end' = if isNothing snapdist || abs (end - wpos wa - wdim wa) <= fromJust snapdist then end else (wpos wa + wdim wa)
begin' = if isNothing snapdist || abs (begin - wpos wa) <= fromJust snapdist then begin else wpos wa
end' = if isNothing snapdist || abs (end - wpos wa - wdim wa) <= fromJust snapdist then end else wpos wa + wdim wa
return (begin',end')
where
(wpos, wdim, _, _) = constructors horiz
@ -170,10 +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
io $ raiseWindow d w
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
@ -194,8 +189,8 @@ snapMagicMove collidedist snapdist w = whenX (isClient w) $ withDisplay $ \d ->
(Just fl,Nothing) -> fl
(Nothing,Just fr) -> fr
(Nothing,Nothing) -> wpos wa
newpos = if abs (b - wpos wa) <= abs (f - wpos wa - wdim wa) then b else (f - wdim wa)
in if isNothing snapdist || abs (newpos - wpos wa) <= fromJust snapdist then newpos else (wpos wa)
newpos = if abs (b - wpos wa) <= abs (f - wpos wa - wdim wa) then b else f - wdim wa
in if isNothing snapdist || abs (newpos - wpos wa) <= fromJust snapdist then newpos else wpos wa
where
(wpos, wdim, _, _) = constructors horiz
@ -211,9 +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
io $ raiseWindow d w
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)
@ -251,9 +245,8 @@ snapShrink
snapShrink = snapResize False
snapResize :: Bool -> Direction2D -> Maybe Int -> Window -> X ()
snapResize grow dir collidedist w = whenX (isClient w) $ withDisplay $ \d -> do
io $ raiseWindow d w
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
@ -274,9 +267,8 @@ snapResize grow dir collidedist w = whenX (isClient w) $ withDisplay $ \d -> do
case mr of
Nothing -> return ()
Just (nx,ny,nw,nh) -> if nw>0 && nh>0 then do io $ moveWindow d w (fromIntegral nx) (fromIntegral ny)
io $ resizeWindow d w (fromIntegral nw) (fromIntegral nh)
else return ()
Just (nx,ny,nw,nh) -> when (nw>0 && nh>0) $ do io $ moveWindow d w (fromIntegral nx) (fromIntegral ny)
io $ resizeWindow d w (fromIntegral nw) (fromIntegral nh)
float w
where
wx = fromIntegral.wa_x
@ -291,8 +283,8 @@ getSnap horiz collidedist d w = do
screen <- W.current <$> gets windowset
let sr = screenRect $ W.screenDetail screen
wl = W.integrate' . W.stack $ W.workspace screen
gr <- fmap ($sr) $ calcGap $ S.fromList [minBound .. maxBound]
wla <- filter (collides wa) `fmap` (io $ mapM (getWindowAttributes d) $ filter (/=w) wl)
gr <- ($ sr) <$> calcGap (S.fromList [minBound .. maxBound])
wla <- filter (collides wa) <$> io (mapM (getWindowAttributes d) $ filter (/=w) wl)
return ( neighbours (back wa sr gr wla) (wpos wa)
, neighbours (front wa sr gr wla) (wpos wa + wdim wa)
@ -306,8 +298,8 @@ getSnap horiz collidedist d w = do
back wa sr gr wla = dropWhile (< rpos sr) $
takeWhile (< rpos sr + rdim sr) $
sort $ (rpos sr):(rpos gr):(rpos gr + rdim gr):
foldr (\a as -> (wpos a):(wpos a + wdim a + wborder a + wborder wa):as) [] wla
sort $ rpos sr:rpos gr:(rpos gr + rdim gr):
foldr (\a as -> wpos a:(wpos a + wdim a + wborder a + wborder wa):as) [] wla
front wa sr gr wla = dropWhile (<= rpos sr) $
takeWhile (<= rpos sr + rdim sr) $
@ -321,8 +313,8 @@ getSnap horiz collidedist d w = do
collides wa oa = case collidedist of
Nothing -> True
Just dist -> ( refwpos oa - wborder oa < refwpos wa + refwdim wa + wborder wa + dist
&& refwpos wa - wborder wa - dist < refwpos oa + refwdim oa + wborder oa )
Just dist -> refwpos oa - wborder oa < refwpos wa + refwdim wa + wborder wa + dist
&& refwpos wa - wborder wa - dist < refwpos oa + refwdim oa + wborder oa
constructors :: Bool -> (WindowAttributes -> Int, WindowAttributes -> Int, Rectangle -> Int, Rectangle -> Int)

View File

@ -1,6 +1,9 @@
{-# LANGUAGE ViewPatterns #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.FocusNth
-- Description : Focus the nth window of the current workspace.
-- Copyright : (c) Karsten Schoelzel <kuser@gmx.de>
-- License : BSD
--
@ -17,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
--
@ -32,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 ()
@ -49,14 +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

@ -1,7 +1,8 @@
{-# LANGUAGE ScopedTypeVariables, GeneralizedNewtypeDeriving, TypeSynonymInstances, FlexibleInstances, OverlappingInstances #-}
{-# LANGUAGE ScopedTypeVariables, GeneralizedNewtypeDeriving, FlexibleInstances, TupleSections #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.GridSelect
-- Description : Display items in a 2D grid and select from it with the keyboard or the mouse.
-- Copyright : Clemens Fruhwirth <clemens@endorphin.org>
-- License : BSD-style (see LICENSE)
--
@ -28,7 +29,6 @@ module XMonad.Actions.GridSelect (
-- * Configuration
GSConfig(..),
def,
defaultGSConfig,
TwoDPosition,
buildDefaultGSConfig,
@ -48,6 +48,7 @@ module XMonad.Actions.GridSelect (
fromClassName,
stringColorizer,
colorRangeFromClassName,
stringToRatio,
-- * Navigation Mode assembly
TwoD,
@ -79,16 +80,14 @@ module XMonad.Actions.GridSelect (
-- * Types
TwoDState,
) where
import Data.Maybe
import Control.Arrow ((***))
import Data.Bits
import Data.Char
import Data.Ord (comparing)
import Control.Applicative
import Control.Monad.State
import Control.Arrow
import Data.List as L
import qualified Data.Map as M
import XMonad hiding (liftX)
import XMonad.Prelude
import XMonad.Util.Font
import XMonad.Prompt (mkUnmanagedWindow)
import XMonad.StackSet as W
@ -96,24 +95,25 @@ import XMonad.Layout.Decoration
import XMonad.Util.NamedWindows
import XMonad.Actions.WindowBringer (bringWindow)
import Text.Printf
import System.Random (mkStdGen, genRange, next)
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
--
-- Then add a keybinding, e.g.
--
-- > , ((modm, xK_g), goToSelected defaultGSConfig)
-- > , ((modm, xK_g), goToSelected def)
--
-- This module also supports displaying arbitrary information in a grid and letting
-- the user select from it. E.g. to spawn an application from a given list, you
-- can use the following:
--
-- > , ((modm, xK_s), spawnSelected defaultGSConfig ["xterm","gmplayer","gvim"])
-- > , ((modm, xK_s), spawnSelected def ["xterm","gmplayer","gvim"])
-- $commonGSConfig
--
@ -123,9 +123,9 @@ import Data.Word (Word8)
-- > {-# LANGUAGE NoMonomorphismRestriction #-}
-- > import XMonad
-- > ...
-- > gsconfig1 = defaultGSConfig { gs_cellheight = 30, gs_cellwidth = 100 }
-- > 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,8 +143,8 @@ import Data.Word (Word8)
--
-- Then you can bind to:
--
-- > ,((modm, xK_g), goToSelected $ gsconfig2 myWinColorizer)
-- > ,((modm, xK_p), spawnSelected $ spawnSelected defaultColorizer)
-- > ,((modm, xK_g), goToSelected $ gsconfig2 myWinColorizer)
-- > ,((modm, xK_p), spawnSelected (gsconfig2 defaultColorizer) ["xterm","gvim"])
-- $keybindings
--
@ -203,9 +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_originFractY :: Double,
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
@ -221,18 +225,14 @@ instance HasColorizer Window where
instance HasColorizer String where
defaultColorizer = stringColorizer
instance HasColorizer a where
instance {-# OVERLAPPABLE #-} HasColorizer a where
defaultColorizer _ isFg =
let getColor = if isFg then focusedBorderColor else normalBorderColor
in asks $ flip (,) "black" . getColor . config
in asks $ (, "black") . getColor . config
instance HasColorizer a => Default (GSConfig a) where
def = buildDefaultGSConfig defaultColorizer
{-# DEPRECATED defaultGSConfig "Use def (from Data.Default, and re-exported from XMonad.Actions.GridSelect) instead." #-}
defaultGSConfig :: HasColorizer a => GSConfig a
defaultGSConfig = def
type TwoDPosition = (Integer, Integer)
type TwoDElementMap a = [(TwoDPosition,(String,a))]
@ -263,7 +263,7 @@ generateElementmap s = do
-- Sorts the elementmap
sortedElements = orderElementmap searchString filteredElements
-- Case Insensitive version of isInfixOf
needle `isInfixOfI` haystack = (upper needle) `isInfixOf` (upper haystack)
needle `isInfixOfI` haystack = upper needle `isInfixOf` upper haystack
upper = map toUpper
@ -289,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
@ -307,30 +303,30 @@ diamondLayer n =
-- tr = top right
-- r = ur ++ 90 degree clock-wise rotation of ur
let tr = [ (x,n-x) | x <- [0..n-1] ]
r = tr ++ (map (\(x,y) -> (y,-x)) tr)
in r ++ (map (negate *** negate) r)
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)
drawWinBox :: Window -> XMonadFont -> (String, String) -> Integer -> Integer -> String -> Integer -> Integer -> Integer -> X ()
drawWinBox win font (fg,bg) ch cw text x y cp =
drawWinBox :: Window -> XMonadFont -> (String, String) -> String -> Integer -> Integer -> String -> Integer -> Integer -> Integer -> X ()
drawWinBox win font (fg,bg) bc ch cw text x y cp =
withDisplay $ \dpy -> do
gc <- liftIO $ createGC dpy win
bordergc <- liftIO $ createGC dpy win
liftIO $ do
Just fgcolor <- initColor dpy fg
Just bgcolor <- initColor dpy bg
Just bordercolor <- initColor dpy borderColor
Just bordercolor <- initColor dpy bc
setForeground dpy gc fgcolor
setBackground dpy gc bgcolor
setForeground dpy bordergc bordercolor
@ -338,9 +334,12 @@ drawWinBox win font (fg,bg) ch cw text x y cp =
drawRectangle dpy win bordergc (fromInteger x) (fromInteger y) (fromInteger cw) (fromInteger ch)
stext <- shrinkWhile (shrinkIt shrinkText)
(\n -> do size <- liftIO $ textWidthXMF dpy font n
return $ size > (fromInteger (cw-(2*cp))))
return $ size > fromInteger (cw-(2*cp)))
text
printStringXMF dpy win font gc bg fg (fromInteger (x+cp)) (fromInteger (y+(div ch 2))) stext
-- calculate the offset to vertically centre the text based on the ascender and descender
(asc,desc) <- liftIO $ textExtentsXMF font stext
let offset = ((ch - fromIntegral (asc + desc)) `div` 2) + fromIntegral asc
printStringXMF dpy win font gc bg fg (fromInteger (x+cp)) (fromInteger (y+offset)) stext
liftIO $ freeGC dpy gc
liftIO $ freeGC dpy bordergc
@ -378,6 +377,7 @@ updateElementsWithColorizer colorizer elementmap = do
colors <- colorizer element (pos == curpos)
drawWinBox win font
colors
(gs_bordercolor gsconfig)
cellheight
cellwidth
text
@ -387,18 +387,25 @@ updateElementsWithColorizer colorizer elementmap = do
mapM_ updateElement elementmap
stdHandle :: Event -> TwoD a (Maybe a) -> TwoD a (Maybe a)
stdHandle (ButtonEvent { ev_event_type = t, ev_x = x, ev_y = y }) contEventloop
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
stdHandle ExposeEvent{} contEventloop = updateAllElements >> contEventloop
stdHandle _ contEventloop = 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
@ -430,7 +438,7 @@ shadowWithKeymap keymap dflt keyEvent@(ks,_,m') = fromMaybe (dflt keyEvent) (M.l
select :: TwoD a (Maybe a)
select = do
s <- get
return $ fmap (snd . snd) $ findInElementMap (td_curpos s) (td_elementmap s)
return $ snd . snd <$> findInElementMap (td_curpos s) (td_elementmap s)
-- | Closes gridselect returning no element.
cancel :: TwoD a (Maybe a)
@ -445,7 +453,7 @@ setPos newPos = do
oldPos = td_curpos s
when (isJust newSelectedEl && newPos /= oldPos) $ do
put s { td_curpos = newPos }
updateElements (catMaybes [(findInElementMap oldPos elmap), newSelectedEl])
updateElements (catMaybes [findInElementMap oldPos elmap, newSelectedEl])
-- | Moves the cursor by the offsets specified
move :: (Integer, Integer) -> TwoD a ()
@ -545,7 +553,7 @@ navNSearch = makeXEventhandler $ shadowWithKeymap navNSearchKeyMap navNSearchDef
,((0,xK_Up) , move (0,-1) >> navNSearch)
,((0,xK_Tab) , moveNext >> navNSearch)
,((shiftMask,xK_Tab), movePrev >> navNSearch)
,((0,xK_BackSpace), transformSearchString (\s -> if (s == "") then "" else init s) >> navNSearch)
,((0,xK_BackSpace), transformSearchString (\s -> if s == "" then "" else init s) >> navNSearch)
]
-- The navigation handler ignores unknown key symbols, therefore we const
navNSearchDefaultHandler (_,s,_) = do
@ -559,7 +567,7 @@ substringSearch returnNavigation = fix $ \me ->
let searchKeyMap = M.fromList [
((0,xK_Escape) , transformSearchString (const "") >> returnNavigation)
,((0,xK_Return) , returnNavigation)
,((0,xK_BackSpace), transformSearchString (\s -> if (s == "") then "" else init s) >> me)
,((0,xK_BackSpace), transformSearchString (\s -> if s == "" then "" else init s) >> me)
]
searchDefaultHandler (_,s,_) = do
transformSearchString (++ s)
@ -571,8 +579,8 @@ substringSearch returnNavigation = fix $ \me ->
-- Conversion scheme as in http://en.wikipedia.org/wiki/HSV_color_space
hsv2rgb :: Fractional a => (Integer,a,a) -> (a,a,a)
hsv2rgb (h,s,v) =
let hi = (div h 60) `mod` 6 :: Integer
f = (((fromInteger h)/60) - (fromInteger hi)) :: Fractional a => a
let hi = div h 60 `mod` 6 :: Integer
f = ((fromInteger h/60) - fromInteger hi) :: Fractional a => a
q = v * (1-f)
p = v * (1-s)
t = v * (1-(1-f)*s)
@ -589,19 +597,19 @@ hsv2rgb (h,s,v) =
stringColorizer :: String -> Bool -> X (String, String)
stringColorizer s active =
let seed x = toInteger (sum $ map ((*x).fromEnum) s) :: Integer
(r,g,b) = hsv2rgb ((seed 83) `mod` 360,
(fromInteger ((seed 191) `mod` 1000))/2500+0.4,
(fromInteger ((seed 121) `mod` 1000))/2500+0.4)
(r,g,b) = hsv2rgb (seed 83 `mod` 360,
fromInteger (seed 191 `mod` 1000)/2500+0.4,
fromInteger (seed 121 `mod` 1000)/2500+0.4)
in if active
then return ("#faff69", "black")
else return ("#" ++ concat (map (twodigitHex.(round :: Double -> Word8).(*256)) [r, g, b] ), "white")
else return ("#" ++ concatMap (twodigitHex.(round :: Double -> Word8).(*256)) [r, g, b], "white")
-- | Colorize a window depending on it's className.
fromClassName :: Window -> Bool -> X (String, String)
fromClassName w active = runQuery className w >>= flip defaultColorizer active
twodigitHex :: Word8 -> String
twodigitHex a = printf "%02x" a
twodigitHex = printf "%02x"
-- | A colorizer that picks a color inside a range,
-- and depending on the window's class.
@ -630,15 +638,12 @@ mix (r1, g1, b1) (r2, g2, b2) r = (mix' r1 r2, mix' g1 g2, mix' b1 b2)
-- | Generates a Double from a string, trying to
-- achieve a random distribution.
-- We create a random seed from the sum of all characters
-- We create a random seed from the hash of all characters
-- in the string, and use it to generate a ratio between 0 and 1
stringToRatio :: String -> Double
stringToRatio "" = 0
stringToRatio s = let gen = mkStdGen $ sum $ map fromEnum s
range = (\(a, b) -> b - a) $ genRange gen
randomInt = foldr1 combine $ replicate 20 next
combine f1 f2 g = let (_, g') = f1 g in f2 g'
in fi (fst $ randomInt gen) / fi range
stringToRatio s = let gen = mkStdGen $ foldl' (\t c -> t * 31 + fromEnum c) 0 s
in fst $ randomR (0, 1) gen
-- | Brings up a 2D grid of elements in the center of the screen, and one can
-- select an element with cursors keys. The selected element is returned.
@ -653,18 +658,18 @@ 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
selectedElement <- if (status == grabSuccess) then do
selectedElement <- if status == grabSuccess then do
let restriction ss cs = (fromInteger ss/fromInteger (cs gsconfig)-1)/2 :: Double
restrictX = floor $ restriction screenWidth gs_cellwidth
restrictY = floor $ restriction screenHeight gs_cellheight
originPosX = floor $ ((gs_originFractX gsconfig) - (1/2)) * 2 * fromIntegral restrictX
originPosY = floor $ ((gs_originFractY gsconfig) - (1/2)) * 2 * fromIntegral restrictY
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,
@ -675,7 +680,7 @@ gridselect gsconfig elements =
td_searchString = "",
td_elementmap = [] }
m <- generateElementmap s
evalTwoD (updateAllElements >> (gs_navigate gsconfig))
evalTwoD (updateAllElements >> gs_navigate gsconfig)
(s { td_elementmap = m })
else
return Nothing
@ -697,27 +702,21 @@ gridselectWindow gsconf = windowMap >>= gridselect gsconf
withSelectedWindow :: (Window -> X ()) -> GSConfig Window -> X ()
withSelectedWindow callback conf = do
mbWindow <- gridselectWindow conf
case mbWindow of
Just w -> callback w
Nothing -> return ()
for_ mbWindow callback
windowMap :: X [(String,Window)]
windowMap = do
ws <- gets windowset
wins <- mapM keyValuePair (W.allWindows ws)
return wins
where keyValuePair w = flip (,) w `fmap` decorateName' w
mapM keyValuePair (W.allWindows ws)
where keyValuePair w = (, w) <$> decorateName' w
decorateName' :: Window -> X String
decorateName' w = do
fmap show $ getName w
show <$> getName w
-- | 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)
borderColor :: String
borderColor = "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 ()
@ -768,7 +767,7 @@ gridselectWorkspace' conf func = withWindowSet $ \ws -> do
--
-- > import XMonad.Actions.DynamicWorkspaces (addWorkspace)
-- >
-- > gridselectWorkspace' defaultGSConfig
-- > gridselectWorkspace' def
-- > { gs_navigate = navNSearch
-- > , gs_rearranger = searchStringRearrangerGenerator id
-- > }
@ -787,7 +786,7 @@ noRearranger _ = return
-- already present).
searchStringRearrangerGenerator :: (String -> a) -> Rearranger a
searchStringRearrangerGenerator f =
let r "" xs = return $ xs
r s xs | s `elem` map fst xs = return $ xs
let r "" xs = return xs
r s xs | s `elem` map fst xs = return xs
| otherwise = return $ xs ++ [(s, f s)]
in r

View File

@ -1,8 +1,8 @@
{-# LANGUAGE DeriveDataTypeable #-}
{-# language DeriveGeneric, DeriveAnyClass #-}
----------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.GroupNavigation
-- Description : Cycle through groups of windows across workspaces.
-- Copyright : (c) nzeh@cs.dal.ca
-- License : BSD3-style (see LICENSE)
--
@ -16,7 +16,7 @@
-- query.
--
-- Also provides a method for jumping back to the most recently used
-- window in any given group.
-- window in any given group, and predefined groups.
--
----------------------------------------------------------------------
@ -27,24 +27,33 @@ module XMonad.Actions.GroupNavigation ( -- * Usage
, nextMatchOrDo
, nextMatchWithThis
, historyHook
-- * Utilities
-- $utilities
, isOnAnyVisibleWS
) where
import Control.Monad.Reader
import Data.Foldable as Fold
import Data.Map as Map
import Data.Sequence as Seq
import Data.Set as Set
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 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
@ -120,14 +129,14 @@ 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 = liftM (\(HistoryDB w ws) -> maybe ws (ws |>) w) XS.get
orderedWindowList History = fmap (\(HistoryDB w ws) -> maybe ws (ws |>) w) XS.get
orderedWindowList dir = withWindowSet $ \ss -> do
wsids <- asks (Seq.fromList . workspaces . config)
let wspcs = orderedWorkspaceList ss wsids
wins = dirfun dir
$ Fold.foldl' (><) Seq.empty
$ foldl' (><) Seq.empty
$ fmap (Seq.fromList . SS.integrate' . SS.stack) wspcs
cur = SS.peek ss
return $ maybe wins (rotfun wins) cur
@ -136,13 +145,13 @@ 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
wspcs = SS.workspaces ss
wspcsMap = Fold.foldl' (\m ws -> Map.insert (SS.tag ws) ws m) Map.empty wspcs
wspcs' = fmap (\wsid -> wspcsMap ! wsid) wsids
wspcsMap = foldl' (\m ws -> Map.insert (SS.tag ws) ws m) Map.empty wspcs
wspcs' = fmap (wspcsMap !) wsids
isCurWS ws = SS.tag ws == SS.tag (SS.workspace $ SS.current ss)
--- History navigation, requires a layout modifier -------------------
@ -150,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, Typeable)
deriving (Read, Show, Generic, NFData)
instance ExtensionClass HistoryDB where
@ -160,33 +169,18 @@ 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 = flt (flip Set.member wins) (ins oldcur oldhist)
return $ HistoryDB newcur (del newcur newhist)
newhist = Seq.filter (`Set.member` wins) (ins oldcur oldhist)
in pure $ HistoryDB newcur (del newcur newhist)
where
ins x xs = maybe xs (<| xs) x
del x xs = maybe xs (\x' -> flt (/= x') xs) x
--- Two replacements for Seq.filter and Seq.breakl available only in
--- containers-0.3.0.0, which only ships with ghc 6.12. Once we
--- decide to no longer support ghc < 6.12, these should be replaced
--- with Seq.filter and Seq.breakl.
flt :: (a -> Bool) -> Seq a -> Seq a
flt p = Fold.foldl (\xs x -> if p x then xs |> x else xs) Seq.empty
brkl :: (a -> Bool) -> Seq a -> (Seq a, Seq a)
brkl p xs = flip Seq.splitAt xs
$ snd
$ Fold.foldr (\x (i, j) -> if p x then (i-1, i-1) else (i-1, j)) (l, l) xs
where
l = Seq.length xs
del x xs = maybe xs (\x' -> Seq.filter (/= x') xs) x
--- Some sequence helpers --------------------------------------------
@ -200,7 +194,7 @@ rotate xs = rotate' (viewl xs)
-- Rotates the sequence until an element matching the given condition
-- is at the beginning of the sequence.
rotateTo :: (a -> Bool) -> Seq a -> Seq a
rotateTo cond xs = let (lxs, rxs) = brkl cond xs in rxs >< lxs
rotateTo cond xs = let (lxs, rxs) = Seq.breakl cond xs in rxs >< lxs
--- A monadic find ---------------------------------------------------
@ -216,3 +210,21 @@ findM cond xs = findM' cond (viewl xs)
if isMatch
then return (Just x')
else findM qry xs'
-- $utilities
-- #utilities#
-- Below are handy queries for use with 'nextMatch', 'nextMatchOrDo',
-- and 'nextMatchWithThis'.
-- | A query that matches all windows on visible workspaces. This is
-- useful for configurations with multiple screens, and matches even
-- invisible windows.
isOnAnyVisibleWS :: Query Bool
isOnAnyVisibleWS = do
w <- ask
ws <- liftX $ gets windowset
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

@ -1,7 +1,7 @@
{-# LANGUAGE DeriveDataTypeable #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.KeyRemap
-- Description : Remap Keybinding on the fly.
-- Copyright : (c) Christian Dietrich
-- License : BSD-style (as xmonad)
--
@ -27,14 +27,13 @@ module XMonad.Actions.KeyRemap (
) where
import XMonad
import XMonad.Prelude
import XMonad.Util.Paste
import Data.List
import qualified XMonad.Util.ExtensibleState as XS
import Control.Monad
data KeymapTable = KeymapTable [((KeyMask, KeySym), (KeyMask, KeySym))] deriving (Typeable, Show)
newtype KeymapTable = KeymapTable [((KeyMask, KeySym), (KeyMask, KeySym))] deriving (Show)
instance ExtensionClass KeymapTable where
initialValue = KeymapTable []
@ -125,8 +124,8 @@ extractKeyMapping (KeymapTable table) mask sym =
buildKeyRemapBindings :: [KeymapTable] -> [((KeyMask, KeySym), X ())]
buildKeyRemapBindings keyremaps =
[((mask, sym), doKeyRemap mask sym) | (mask, sym) <- bindings]
where mappings = concat (map (\(KeymapTable table) -> table) keyremaps)
bindings = nub (map (\binding -> fst binding) mappings)
where mappings = concatMap (\(KeymapTable table) -> table) keyremaps
bindings = nub (map fst mappings)
-- Here come the Keymappings
@ -138,7 +137,7 @@ emptyKeyRemap = KeymapTable []
dvorakProgrammerKeyRemap :: KeymapTable
dvorakProgrammerKeyRemap =
KeymapTable [((charToMask maskFrom, from), (charToMask maskTo, to)) |
(maskFrom, from, maskTo, to) <- (zip4 layoutUsShift layoutUsKey layoutDvorakShift layoutDvorakKey)]
(maskFrom, from, maskTo, to) <- zip4 layoutUsShift layoutUsKey layoutDvorakShift layoutDvorakKey]
where
layoutUs = map (fromIntegral . fromEnum) "`1234567890-=qwertyuiop[]\\asdfghjkl;'zxcvbnm,./~!@#$%^&*()_+QWERTYUIOP{}|ASDFGHJKL:\"ZXCVBNM<>?" :: [KeySym]
@ -149,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

@ -1,5 +1,6 @@
{- |
Module : XMonad.Actions.Launcher
Description : A set of prompts for XMonad.
Copyright : (C) 2012 Carlos López-Camey
License : None; public domain
@ -18,10 +19,9 @@ module XMonad.Actions.Launcher(
, launcherPrompt
) where
import Data.List (find, findIndex, isPrefixOf, tails)
import qualified Data.Map as M
import Data.Maybe (isJust)
import XMonad hiding (config)
import XMonad.Prelude
import XMonad.Prompt
import XMonad.Util.Run
@ -62,15 +62,15 @@ 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 (length s == 0) then return [] else do
fmap lines $ runProcessWithInput "calc" [s] ""
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
-- | Uses the program `hoogle` to search for functions
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]
@ -88,7 +88,7 @@ instance XPrompt HoogleMode where
-- | Creates an autocompletion function for a programm given the program's name and a list of args to send to the command.
completionFunctionWith :: String -> [String] -> IO [String]
completionFunctionWith cmd args = do fmap lines $ runProcessWithInput cmd args ""
completionFunctionWith cmd args = lines <$> runProcessWithInput cmd args ""
-- | Creates a prompt with the given modes
launcherPrompt :: XPConfig -> [XPMode] -> X()

View File

@ -1,6 +1,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.LinkWorkspaces
-- Description : Bindings to add and delete links between workspaces.
-- Copyright : (c) Jan-David Quesel <quesel@gmail.org>
-- License : BSD3-style (see LICENSE)
--
@ -14,7 +15,6 @@
--
-----------------------------------------------------------------------------
{-# LANGUAGE DeriveDataTypeable #-}
module XMonad.Actions.LinkWorkspaces (
-- * Usage
-- $usage
@ -27,6 +27,7 @@ module XMonad.Actions.LinkWorkspaces (
) where
import XMonad
import XMonad.Prelude (for_)
import qualified XMonad.StackSet as W
import XMonad.Layout.IndependentScreens(countScreens)
import qualified XMonad.Util.ExtensibleState as XS (get, put)
@ -35,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
--
@ -57,9 +58,9 @@ 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())
data MessageConfig = MessageConfig { messageFunction :: ScreenId -> [Char] -> [Char] -> [Char] -> X()
, foreground :: [Char]
, alertedForeground :: [Char]
, background :: [Char]
@ -75,8 +76,8 @@ noMessageFn :: ScreenId -> [Char] -> [Char] -> [Char] -> X()
noMessageFn _ _ _ _ = return () :: X ()
-- | Stuff for linking workspaces
data WorkspaceMap = WorkspaceMap (M.Map WorkspaceId WorkspaceId) deriving (Read, Show, Typeable)
instance ExtensionClass WorkspaceMap
newtype WorkspaceMap = WorkspaceMap (M.Map WorkspaceId WorkspaceId) deriving (Read, Show)
instance ExtensionClass WorkspaceMap
where initialValue = WorkspaceMap M.empty
extensionType = PersistentExtension
@ -85,12 +86,12 @@ switchWS f m ws = switchWS' f m ws Nothing
-- | Switch to the given workspace in a non greedy way, stop if we reached the first screen
-- | we already did switching on
switchWS' :: (WorkspaceId -> X ()) -> MessageConfig -> WorkspaceId -> (Maybe ScreenId) -> X ()
switchWS' :: (WorkspaceId -> X ()) -> MessageConfig -> WorkspaceId -> Maybe ScreenId -> X ()
switchWS' switchFn message workspace stopAtScreen = do
ws <- gets windowset
nScreens <- countScreens
let now = W.screen (W.current ws)
let next = ((now + 1) `mod` nScreens)
let next = (now + 1) `mod` nScreens
switchFn workspace
case stopAtScreen of
Nothing -> sTM now next (Just now)
@ -99,21 +100,21 @@ switchWS' switchFn message workspace stopAtScreen = do
-- | Switch to the workspace that matches the current one, executing switches for that workspace as well.
-- | The function switchWorkspaceNonGreedy' will take of stopping if we reached the first workspace again.
switchToMatching :: (WorkspaceId -> (Maybe ScreenId) -> X ()) -> MessageConfig -> WorkspaceId -> ScreenId
-> ScreenId -> (Maybe ScreenId) -> X ()
switchToMatching :: (WorkspaceId -> Maybe ScreenId -> X ()) -> MessageConfig -> WorkspaceId -> ScreenId
-> ScreenId -> Maybe ScreenId -> X ()
switchToMatching f message t now next stopAtScreen = do
WorkspaceMap matchings <- XS.get :: X WorkspaceMap
case (M.lookup t matchings) of
case M.lookup t matchings of
Nothing -> return () :: X()
Just newWorkspace -> do
onScreen' (f newWorkspace stopAtScreen) FocusCurrent next
onScreen' (f newWorkspace stopAtScreen) FocusCurrent next
messageFunction message now (foreground message) (background message) ("Switching to: " ++ (t ++ " and " ++ newWorkspace))
-- | Insert a mapping between t1 and t2 or remove it was already present
toggleMatching :: MessageConfig -> WorkspaceId -> WorkspaceId -> X ()
toggleMatching message t1 t2 = do
WorkspaceMap matchings <- XS.get :: X WorkspaceMap
case (M.lookup t1 matchings) of
case M.lookup t1 matchings of
Nothing -> setMatching message t1 t2 matchings
Just t -> if t == t2 then removeMatching' message t1 t2 matchings else setMatching message t1 t2 matchings
return ()
@ -142,7 +143,7 @@ removeAllMatchings :: MessageConfig -> X ()
removeAllMatchings message = do
ws <- gets windowset
let now = W.screen (W.current ws)
XS.put $ WorkspaceMap $ M.empty
XS.put $ WorkspaceMap M.empty
messageFunction message now (alertedForeground message) (background message) "All links removed!"
-- | remove all matching regarding a given workspace
@ -163,7 +164,6 @@ toggleLinkWorkspaces' first message = do
let now = W.screen (W.current ws)
let next = (now + 1) `mod` nScreens
if next == first then return () else do -- this is also the case if there is only one screen
case (W.lookupWorkspace next ws) of
Nothing -> return ()
Just name -> toggleMatching message (W.currentTag ws) (name)
for_ (W.lookupWorkspace next ws)
(toggleMatching message (W.currentTag ws))
onScreen' (toggleLinkWorkspaces' first message) FocusCurrent next

View File

@ -1,7 +1,9 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.MessageFeedback
-- Copyright : (c) Quentin Moser <moserq@gmail.com>
-- Description : An alternative @sendMessage@.
-- Copyright : (c) -- Quentin Moser <moserq@gmail.com>
-- 2018 Yclept Nemo
-- License : BSD3
--
-- Maintainer : orphaned
@ -13,87 +15,212 @@
-- this facility.
-----------------------------------------------------------------------------
module XMonad.Actions.MessageFeedback (
-- * Usage
-- $usage
module XMonad.Actions.MessageFeedback
( -- * Usage
-- $usage
send
, tryMessage
, tryMessage_
, tryInOrder
, tryInOrder_
, sm
, sendSM
, sendSM_
) where
-- * Messaging variants
import XMonad.Core ( X (), Message, SomeMessage(..), LayoutClass(..), windowset, catchX )
import XMonad.StackSet ( current, workspace, layout, tag )
import XMonad.Operations ( updateLayout )
-- ** 'SomeMessage'
sendSomeMessageB, sendSomeMessage
, sendSomeMessageWithNoRefreshB, sendSomeMessageWithNoRefresh
, sendSomeMessageWithNoRefreshToCurrentB, sendSomeMessageWithNoRefreshToCurrent
import Control.Monad.State ( gets )
import Data.Maybe ( isJust )
import Control.Applicative ((<$>))
-- ** 'Message'
, sendMessageB
, sendMessageWithNoRefreshB
, sendMessageWithNoRefreshToCurrentB, sendMessageWithNoRefreshToCurrent
-- * Utility Functions
-- ** Send All
, sendSomeMessagesB, sendSomeMessages, sendMessagesB, sendMessages
-- ** Send Until
, tryInOrderB, tryInOrderWithNoRefreshToCurrentB, tryInOrderWithNoRefreshToCurrent
, tryMessageB, tryMessageWithNoRefreshToCurrentB, tryMessageWithNoRefreshToCurrent
-- ** Aliases
, sm
) 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
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
--
-- You can then use this module's functions wherever an action is expected.
-- You can then use this module's functions wherever an action is expected. All
-- feedback variants are supported:
--
-- * message to any workspace with no refresh
-- * message to current workspace with no refresh
-- * message to current workspace with refresh
--
-- Except "message to any workspace with refresh" which makes little sense.
--
-- Note that most functions in this module have a return type of @X Bool@
-- whereas configuration options will expect a @X ()@ action.
-- For example, the key binding
-- whereas configuration options will expect a @X ()@ action. For example, the
-- key binding:
--
-- > -- Shrink the master area of a tiled layout, or move the focused window
-- > -- to the left in a WindowArranger-based layout
-- > ((modKey, xK_Left), tryMessage Shrink (MoveLeft 50))
-- > ((modKey, xK_Left), tryMessageWithNoRefreshToCurrentB Shrink (MoveLeft 50))
--
-- is mis-typed. For this reason, this module provides alternatives (ending with
-- an underscore, e.g. tryMessage_) that discard their result and return an @X ()@.
-- For example, to correct the previous example:
-- is mis-typed. For this reason, this module provides alternatives (not ending
-- with an uppercase \"B\", e.g. 'XMonad.Operations.sendMessage' rather than
-- 'sendMessageB') that discard their boolean result and return an @X ()@. For
-- example, to correct the previous example:
--
-- > ((modKey, xK_Left), tryMessage_ Shrink (MoveLeft 50))
-- > ((modKey, xK_Left), tryMessageWithNoRefreshToCurrent Shrink (MoveLeft 50))
--
-- This module also provides 'SomeMessage' variants of each 'Message' function
-- for when the messages are of differing types (but still instances of
-- 'Message'). First box each message using 'SomeMessage' or the convenience
-- alias 'sm'. Then, for example, to send each message:
--
-- > sendSomeMessages [sm messageOfTypeA, sm messageOfTypeB]
--
-- This is /not/ equivalent to the following example, which will not refresh
-- the workspace unless the last message is handled:
--
-- > sendMessageWithNoRefreshToCurrent messageOfTypeA >> sendMessage messageOfTypeB
-- | Behaves like 'XMonad.Operations.sendMessage', but returns True of the
-- message was handled by the layout, False otherwise.
send :: Message a => a -> X Bool
send = sendSM . sm
-- | Variant of 'XMonad.Operations.sendMessage'. Accepts 'SomeMessage'; to use
-- 'Message' see 'sendMessageB'. Returns @True@ if the message was handled,
-- @False@ otherwise. Instead of using 'sendSomeMessageWithNoRefreshToCurrentB'
-- for efficiency this is pretty much an exact copy of the
-- 'XMonad.Operations.sendMessage' code - foregoes the O(n) 'updateLayout'.
sendSomeMessageB :: SomeMessage -> X Bool
sendSomeMessageB m = windowBracket id $ do
w <- gets ((workspace . current) . windowset)
ml <- handleMessage (layout w) m `catchX` return Nothing
whenJust ml $ \l ->
modifyWindowSet $ \ws -> ws { current = (current ws)
{ workspace = (workspace $ current ws)
{ layout = l }}}
return $ isJust ml
-- | Sends the first message, and if it was not handled, sends the second.
-- Returns True if either message was handled, False otherwise.
tryMessage :: (Message a, Message b) => a -> b -> X Bool
tryMessage m1 m2 = do b <- send m1
if b then return True else send m2
-- | Variant of 'sendSomeMessageB' that discards the result.
sendSomeMessage :: SomeMessage -> X ()
sendSomeMessage = void . sendSomeMessageB
tryMessage_ :: (Message a, Message b) => a -> b -> X ()
tryMessage_ m1 m2 = tryMessage m1 m2 >> return ()
-- | Variant of 'XMonad.Operations.sendMessageWithNoRefresh'. Accepts
-- 'SomeMessage'; to use 'Message' see 'sendMessageWithNoRefreshB'. Returns
-- @True@ if the message was handled, @False@ otherwise.
sendSomeMessageWithNoRefreshB :: SomeMessage -> Workspace WorkspaceId (Layout Window) Window -> X Bool
sendSomeMessageWithNoRefreshB m w
= handleMessage (layout w) m `catchX` return Nothing
>>= liftA2 (>>) (updateLayout $ tag w) (return . isJust)
-- | Tries sending every message of the list in order until one of them
-- is handled. Returns True if one of the messages was handled, False otherwise.
tryInOrder :: [SomeMessage] -> X Bool
tryInOrder [] = return False
tryInOrder (m:ms) = do b <- sendSM m
if b then return True else tryInOrder ms
-- | Variant of 'sendSomeMessageWithNoRefreshB' that discards the result.
sendSomeMessageWithNoRefresh :: SomeMessage -> Workspace WorkspaceId (Layout Window) Window -> X ()
sendSomeMessageWithNoRefresh m = void . sendSomeMessageWithNoRefreshB m
tryInOrder_ :: [SomeMessage] -> X ()
tryInOrder_ ms = tryInOrder ms >> return ()
-- | Variant of 'XMonad.Operations.sendMessageWithNoRefresh' that sends the
-- message to the current layout. Accepts 'SomeMessage'; to use 'Message' see
-- 'sendMessageWithNoRefreshToCurrentB'. Returns @True@ if the message was
-- handled, @False@ otherwise. This function is somewhat of a cross between
-- 'XMonad.Operations.sendMessage' (sends to the current layout) and
-- 'XMonad.Operations.sendMessageWithNoRefresh' (does not refresh).
sendSomeMessageWithNoRefreshToCurrentB :: SomeMessage -> X Bool
sendSomeMessageWithNoRefreshToCurrentB m
= gets (workspace . current . windowset)
>>= sendSomeMessageWithNoRefreshB m
-- | Variant of 'sendSomeMessageWithNoRefreshToCurrentB' that discards the
-- result.
sendSomeMessageWithNoRefreshToCurrent :: SomeMessage -> X ()
sendSomeMessageWithNoRefreshToCurrent = void . sendSomeMessageWithNoRefreshToCurrentB
-- | Convenience shorthand for 'XMonad.Core.SomeMessage'.
-- | Variant of 'sendSomeMessageB' which like 'XMonad.Operations.sendMessage'
-- accepts 'Message' rather than 'SomeMessage'. Returns @True@ if the message
-- was handled, @False@ otherwise.
sendMessageB :: Message a => a -> X Bool
sendMessageB = sendSomeMessageB . SomeMessage
-- | Variant of 'sendSomeMessageWithNoRefreshB' which like
-- 'XMonad.Operations.sendMessageWithNoRefresh' accepts 'Message' rather than
-- 'SomeMessage'. Returns @True@ if the message was handled, @False@ otherwise.
sendMessageWithNoRefreshB :: Message a => a -> Workspace WorkspaceId (Layout Window) Window -> X Bool
sendMessageWithNoRefreshB = sendSomeMessageWithNoRefreshB . SomeMessage
-- | Variant of 'sendSomeMessageWithNoRefreshToCurrentB' which accepts
-- 'Message' rather than 'SomeMessage'. Returns @True@ if the message was
-- handled, @False@ otherwise.
sendMessageWithNoRefreshToCurrentB :: Message a => a -> X Bool
sendMessageWithNoRefreshToCurrentB = sendSomeMessageWithNoRefreshToCurrentB . SomeMessage
-- | Variant of 'sendMessageWithNoRefreshToCurrentB' that discards the result.
sendMessageWithNoRefreshToCurrent :: Message a => a -> X ()
sendMessageWithNoRefreshToCurrent = void . sendMessageWithNoRefreshToCurrentB
-- | Send each 'SomeMessage' to the current layout without refresh (using
-- 'sendSomeMessageWithNoRefreshToCurrentB') and collect the results. If any
-- message was handled, refresh. If you want to sequence a series of messages
-- that would have otherwise used 'XMonad.Operations.sendMessage' while
-- minimizing refreshes, use this.
sendSomeMessagesB :: [SomeMessage] -> X [Bool]
sendSomeMessagesB
= windowBracket or
. mapM sendSomeMessageWithNoRefreshToCurrentB
-- | Variant of 'sendSomeMessagesB' that discards the results.
sendSomeMessages :: [SomeMessage] -> X ()
sendSomeMessages = void . sendSomeMessagesB
-- | Variant of 'sendSomeMessagesB' which accepts 'Message' rather than
-- 'SomeMessage'. Use this if all the messages are of the same type.
sendMessagesB :: Message a => [a] -> X [Bool]
sendMessagesB = sendSomeMessagesB . map SomeMessage
-- | Variant of 'sendMessagesB' that discards the results.
sendMessages :: Message a => [a] -> X ()
sendMessages = void . sendMessagesB
-- | Apply the dispatch function in order to each message of the list until one
-- is handled. Returns @True@ if so, @False@ otherwise.
tryInOrderB :: (SomeMessage -> X Bool) -> [SomeMessage] -> X Bool
tryInOrderB _ [] = return False
tryInOrderB f (m:ms) = do b <- f m
if b then return True else tryInOrderB f ms
-- | Variant of 'tryInOrderB' that sends messages to the current layout without
-- refresh using 'sendSomeMessageWithNoRefreshToCurrentB'.
tryInOrderWithNoRefreshToCurrentB :: [SomeMessage] -> X Bool
tryInOrderWithNoRefreshToCurrentB = tryInOrderB sendSomeMessageWithNoRefreshToCurrentB
-- | Variant of 'tryInOrderWithNoRefreshToCurrent' that discards the results.
tryInOrderWithNoRefreshToCurrent :: [SomeMessage] -> X ()
tryInOrderWithNoRefreshToCurrent = void . tryInOrderWithNoRefreshToCurrentB
-- | Apply the dispatch function to the first message, and if it was not
-- handled, apply it to the second. Returns @True@ if either message was
-- handled, @False@ otherwise.
tryMessageB :: (Message a, Message b) => (SomeMessage -> X Bool) -> a -> b -> X Bool
tryMessageB f m1 m2 = tryInOrderB f [sm m1,sm m2]
-- | Variant of 'tryMessageB' that sends messages to the current layout without
-- refresh using 'sendMessageWithNoRefreshToCurrentB'.
tryMessageWithNoRefreshToCurrentB :: (Message a, Message b) => a -> b -> X Bool
tryMessageWithNoRefreshToCurrentB = tryMessageB sendSomeMessageWithNoRefreshToCurrentB
-- | Variant of 'tryMessage' that discards the results.
tryMessageWithNoRefreshToCurrent :: (Message a, Message b) => a -> b -> X ()
tryMessageWithNoRefreshToCurrent m = void . tryMessageWithNoRefreshToCurrentB m
-- | Convenience shorthand for 'SomeMessage'.
sm :: Message a => a -> SomeMessage
sm = SomeMessage
sendSM :: SomeMessage -> X Bool
sendSM m = do w <- workspace . current <$> gets windowset
ml' <- handleMessage (layout w) m `catchX` return Nothing
updateLayout (tag w) ml'
return $ isJust ml'
sendSM_ :: SomeMessage -> X ()
sendSM_ m = sendSM m >> return ()

147
XMonad/Actions/Minimize.hs Normal file
View File

@ -0,0 +1,147 @@
----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.Minimize
-- Description : Actions for minimizing and maximizing windows.
-- Copyright : (c) Bogdan Sinitsyn (2016)
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : Bogdan Sinitsyn <bogdan.sinitsyn@gmail.com>
-- Stability : unstable
-- Portability : not portable
--
-- 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.Minimize" and use actions from
-- this module
--
-- Possible keybindings:
--
-- > , ((modm, xK_m ), withFocused minimizeWindow)
-- > , ((modm .|. shiftMask, xK_m ), withLastMinimized maximizeWindowAndFocus)
--
-----------------------------------------------------------------------------
module XMonad.Actions.Minimize
( -- * Usage
-- $usage
minimizeWindow
, maximizeWindow
, maximizeWindowAndFocus
, withLastMinimized
, withLastMinimized'
, withFirstMinimized
, withFirstMinimized'
, withMinimized
) where
import XMonad
import XMonad.Prelude (fromMaybe, join, listToMaybe)
import qualified XMonad.StackSet as W
import qualified XMonad.Layout.BoringWindows as BW
import qualified XMonad.Util.ExtensibleState as XS
import XMonad.Util.Minimize
import XMonad.Util.WindowProperties (getProp32)
import Foreign.C.Types (CLong)
import qualified Data.List as L
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)
setMinimizedState :: Window -> Int -> (CLong -> [CLong] -> [CLong]) -> X ()
setMinimizedState win st f = do
setWMState win st
withDisplay $ \dpy -> do
wm_state <- getAtom "_NET_WM_STATE"
hidden <- fromIntegral <$> getAtom "_NET_WM_STATE_HIDDEN"
wstate <- fromMaybe [] <$> getProp32 wm_state win
io $ changeProperty32 dpy win wm_state aTOM propModeReplace (f hidden wstate)
setMinimized :: Window -> X ()
setMinimized win = setMinimizedState win iconicState (:)
setNotMinimized :: Window -> X ()
setNotMinimized win = setMinimizedState win normalState L.delete
-- It does not just set minimizedStack to newWindows because it should save
-- order in which elements were added (newer first)
modified :: (RectMap -> RectMap) -> X Bool
modified f = XS.modified $
\Minimized { rectMap = oldRectMap, minimizedStack = oldStack } ->
let newRectMap = f oldRectMap
newWindows = M.keys newRectMap
in Minimized { rectMap = newRectMap
, minimizedStack = (newWindows L.\\ oldStack)
++
(oldStack `L.intersect` newWindows)
}
-- | Minimize a window
minimizeWindow :: Window -> X ()
minimizeWindow w = withWindowSet $ \ws ->
whenX (modified $ M.insert w (M.lookup w $ W.floating ws)) $ do
setMinimized w
windows $ W.sink w
BW.focusDown
-- | Maximize window and apply a function to maximized window and 'WindowSet'
maximizeWindowAndChangeWSet :: (Window -> WindowSet -> WindowSet) -> Window -> X ()
maximizeWindowAndChangeWSet f w = do
mrect <- XS.gets (join . M.lookup w . rectMap)
whenX (modified $ M.delete w) $ do
setNotMinimized w
broadcastMessage BW.UpdateBoring
windows $ f w . maybe id (W.float w) mrect
-- | Just maximize a window without focusing
maximizeWindow :: Window -> X ()
maximizeWindow = maximizeWindowAndChangeWSet $ const id
-- | Maximize a window and then focus it
maximizeWindowAndFocus :: Window -> X ()
maximizeWindowAndFocus = maximizeWindowAndChangeWSet W.focusWindow
-- | Perform an action with first minimized window on current workspace
-- or do nothing if there is no minimized windows on current workspace
withFirstMinimized :: (Window -> X ()) -> X ()
withFirstMinimized action = withFirstMinimized' (`whenJust` action)
-- | Like withFirstMinimized but the provided action is always invoked with a
-- 'Maybe Window', that will be nothing if there is no first minimized window.
withFirstMinimized' :: (Maybe Window -> X ()) -> X ()
withFirstMinimized' action = withMinimized (action . listToMaybe . reverse)
-- | Perform an action with last minimized window on current workspace
-- or do nothing if there is no minimized windows on current workspace
withLastMinimized :: (Window -> X ()) -> X ()
withLastMinimized action = withLastMinimized' (`whenJust` action)
-- | Like withLastMinimized but the provided action is always invoked with a
-- 'Maybe Window', that will be nothing if there is no last minimized window.
withLastMinimized' :: (Maybe Window -> X ()) -> X ()
withLastMinimized' action = withMinimized (action . listToMaybe)
withMinimized :: ([Window] -> X a) -> X a
withMinimized action = do
minimized <- XS.gets minimizedStack
currentStack <- withWindowSet $ return . W.index
action $ minimized `L.intersect` currentStack

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

@ -1,6 +1,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.MouseGestures
-- Description : Support for simple mouse gestures.
-- Copyright : (c) Lukas Mai
-- License : BSD3-style (see LICENSE)
--
@ -21,18 +22,17 @@ module XMonad.Actions.MouseGestures (
mkCollect
) where
import XMonad.Prelude
import XMonad
import XMonad.Util.Types (Direction2D(..))
import Data.IORef
import qualified Data.Map as M
import Data.Map (Map)
import Data.Maybe
import Control.Monad
-- $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 d' = dir pivot np
when (isNothing stx || od /= d') $ hook d'
io $ writeIORef st (Just (d', np))
fromMaybe (return ()) cont
let pivot = maybe op snd stx
when (significant np pivot) $ do
let d' = dir pivot np
when ((fst <$> stx) /= Just d') $ hook d'
io $ writeIORef st (Just (d', np))
where
significant a b = delta a b >= 10
@ -111,7 +105,7 @@ mouseGestureH moveHook endHook = do
mouseGesture :: Map [Direction2D] (Window -> X ()) -> Window -> X ()
mouseGesture tbl win = do
(mov, end) <- mkCollect
mouseGestureH (\d -> mov d >> return ()) $ end >>= \gest ->
mouseGestureH (void . mov) $ end >>= \gest ->
case M.lookup gest tbl of
Nothing -> return ()
Just f -> f win

View File

@ -1,8 +1,9 @@
{-# LANGUAGE GeneralizedNewtypeDeriving, MultiParamTypeClasses, PatternGuards, TypeSynonymInstances #-}
{-# LANGUAGE MultiParamTypeClasses, PatternGuards, TypeSynonymInstances #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.MouseResize
-- Description : A layout modifier to resize windows with the mouse.
-- Copyright : (c) 2007 Andrea Rossato
-- License : BSD-style (see xmonad/LICENSE)
--
@ -36,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
@ -49,14 +50,14 @@ 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 [])
data MouseResize a = MR [((a,Rectangle),Maybe a)]
newtype MouseResize a = MR [((a,Rectangle),Maybe a)]
instance Show (MouseResize a) where show _ = ""
instance Read (MouseResize a) where readsPrec _ s = [(MR [], s)]
@ -68,7 +69,7 @@ instance LayoutModifier MouseResize Window where
where
wrs' = wrs_to_state [] . filter (isInStack s . fst) $ wrs
initState = mapM createInputWindow wrs'
processState = mapM (deleteInputWin . snd) st >> mapM createInputWindow wrs'
processState = mapM_ (deleteInputWin . snd) st >> mapM createInputWindow wrs'
inputRectangle (Rectangle x y wh ht) = Rectangle (x + fi wh - 5) (y + fi ht - 5) 10 10
@ -105,7 +106,7 @@ handleResize st ButtonEvent { ev_window = ew, ev_event_type = et }
handleResize _ _ = return ()
createInputWindow :: ((Window,Rectangle), Maybe Rectangle) -> X ((Window,Rectangle),Maybe Window)
createInputWindow ((w,r),mr) = do
createInputWindow ((w,r),mr) =
case mr of
Just tr -> withDisplay $ \d -> do
tw <- mkInputWindow d tr

View File

@ -1,8 +1,9 @@
{-# LANGUAGE DeriveDataTypeable, MultiParamTypeClasses, PatternGuards, RankNTypes, TypeSynonymInstances #-}
{-# LANGUAGE MultiParamTypeClasses, PatternGuards, RankNTypes, TypeSynonymInstances #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Layout.Navigation2D
-- Description : Directional navigation of windows and screens.
-- Copyright : (c) 2011 Norbert Zeh <nzeh@cs.dal.ca>
-- License : BSD3-style (see LICENSE)
--
@ -39,11 +40,12 @@ module XMonad.Actions.Navigation2D ( -- * Usage
, withNavigation2DConfig
, Navigation2DConfig(..)
, def
, defaultNavigation2DConfig
, Navigation2D
, lineNavigation
, centerNavigation
, hybridNavigation
, sideNavigation
, sideNavigationWithBias
, hybridOf
, fullScreenRect
, singleWindowRect
, switchLayer
@ -55,33 +57,35 @@ module XMonad.Actions.Navigation2D ( -- * Usage
, Direction2D(..)
) where
import Control.Applicative
import qualified Data.List as L
import qualified Data.Map as M
import Data.Maybe
import Control.Arrow (second)
import XMonad.Prelude
import XMonad hiding (Screen)
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#
-- Navigation2D provides directional navigation (go left, right, up, down) for
-- windows and screens. It treats floating and tiled windows as two separate
-- layers and provides mechanisms to navigate within each layer and to switch
-- between layers. Navigation2D provides two different navigation strategies
-- (see <#Technical_Discussion> for details): /Line navigation/ feels rather
-- natural but may make it impossible to navigate to a given window from the
-- current window, particularly in the floating layer. /Center navigation/
-- feels less natural in certain situations but ensures that all windows can be
-- reached without the need to involve the mouse. A third option is to use
-- /Hybrid navigation/, which automatically chooses between the two whenever
-- navigation is attempted. Navigation2D allows different navigation strategies
-- to be used in the two layers and allows customization of the navigation strategy
-- for the tiled layer based on the layout currently in effect.
-- between layers. Navigation2D provides three different navigation strategies
-- (see <#Technical_Discussion> for details): /Line navigation/ and
-- /Side navigation/ feel rather natural but may make it impossible to navigate
-- to a given window from the current window, particularly in the floating
-- layer. /Center navigation/ feels less natural in certain situations but
-- ensures that all windows can be reached without the need to involve the
-- mouse. Another option is to use a /Hybrid/ of the three strategies,
-- automatically choosing whichever first provides a suitable target window.
-- Navigation2D allows different navigation strategies to be used in the two
-- 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
--
@ -94,17 +98,25 @@ 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.
--
-- > main = xmonad $ navigation2D def
-- > ("<Up>", "<Left>", "<Down>", "<Right>")
-- > [("M-", windowGo ),
-- > ("M-S-", windowSwap)]
-- > False
-- Alternatively to 'navigation2D', you can use 'navigation2DP':
--
-- > main = xmonad $ navigation2DP def
-- > ("<Up>", "<Left>", "<Down>", "<Right>")
-- > [("M-", windowGo ),
-- > ("M-S-", windowSwap)]
-- > False
-- > $ 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)
@ -158,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#
@ -175,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
@ -318,12 +340,42 @@ lineNavigation = N 1 doLineNavigation
centerNavigation :: Navigation2D
centerNavigation = N 2 doCenterNavigation
-- | Hybrid navigation. This attempts Line navigation, then falls back on Center
-- navigation if it does not find any suitable target windows. This is useful since
-- Line navigation tends to fail on gaps, but provides more intuitive motions
-- when it succeeds—provided there are no floating windows.
hybridNavigation :: Navigation2D
hybridNavigation = N 2 doHybridNavigation
-- | Side navigation. Consider navigating to the right this time. The strategy
-- is to take the line segment forming the right boundary of the current window,
-- 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".
sideNavigation :: Navigation2D
sideNavigation = N 1 (doSideNavigationWithBias 1)
-- | Side navigation with bias. Consider a case where the screen is divided
-- up into three vertical panes; the side panes occupied by one window each and
-- the central pane split across the middle by two windows. By the criteria
-- of side navigation, the two central windows are equally good choices when
-- navigating inwards from one of the side panes. Hence in order to be
-- equitable, symmetric and pleasant to use, different windows are chosen when
-- navigating from different sides. In particular, the lower is chosen when
-- going left and the higher when going right, causing L, L, R, R, L, L, etc to
-- cycle through the four windows clockwise. This is implemented by using a bias
-- of 1. /Bias/ is how many pixels off centre the vertical split can be before
-- this behaviour is lost and the same window chosen every time. A negative bias
-- swaps the preferred window for each direction. A bias of zero disables the
-- behaviour.
sideNavigationWithBias :: Int -> Navigation2D
sideNavigationWithBias b = N 1 (doSideNavigationWithBias b)
-- | Hybrid of two modes of navigation, preferring the motions of the first.
-- Use this if you want to fall back on a second strategy whenever the first
-- does not find a candidate window. E.g.
-- @hybridOf lineNavigation centerNavigation@ is a good strategy for the
-- floating layer, and @hybridOf sideNavigation centerNavigation@ will enable
-- you to take advantage of some of the latter strategy's more interesting
-- motions in the tiled layer.
hybridOf :: Navigation2D -> Navigation2D -> Navigation2D
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
-- | Stores the configuration of directional navigation. The 'Default' instance
-- uses line navigation for the tiled layer and for navigation between screens,
@ -347,10 +399,10 @@ data Navigation2DConfig = Navigation2DConfig
-- function calculates a rectangle for a given unmapped
-- window from the screen it is on and its window ID.
-- See <#Finer_Points> for how to use this.
} deriving Typeable
}
-- | 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
@ -395,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 =
@ -412,12 +464,8 @@ withNavigation2DConfig conf2d xconf = xconf { startupHook = startupHook xconf
>> XS.put conf2d
}
{-# DEPRECATED defaultNavigation2DConfig "Use def (from Data.Default, and re-exported from XMonad.Actions.Navigation2D) instead." #-}
defaultNavigation2DConfig :: Navigation2DConfig
defaultNavigation2DConfig = def
instance Default Navigation2DConfig where
def = Navigation2DConfig { defaultTiledNavigation = lineNavigation
def = Navigation2DConfig { defaultTiledNavigation = hybridOf lineNavigation sideNavigation
, floatNavigation = centerNavigation
, screenNavigation = lineNavigation
, layoutNavigation = []
@ -443,7 +491,7 @@ switchLayer = actOnLayer otherLayer
-- navigation should wrap around (e.g., from the left edge of the leftmost
-- screen to the right edge of the rightmost screen).
windowGo :: Direction2D -> Bool -> X ()
windowGo dir wrap = actOnLayer thisLayer
windowGo dir = actOnLayer thisLayer
( \ conf cur wins -> windows
$ doTiledNavigation conf dir W.focusWindow cur wins
)
@ -453,7 +501,6 @@ windowGo dir wrap = actOnLayer thisLayer
( \ conf cur wspcs -> windows
$ doScreenNavigation conf dir W.view cur wspcs
)
wrap
-- | Swaps the current window with the next window in the given direction and in
-- the same layer as the current window. (In the floating layer, all that
@ -462,7 +509,7 @@ windowGo dir wrap = actOnLayer thisLayer
-- window's screen but retains its position and size relative to the screen.)
-- The second argument indicates wrapping (see 'windowGo').
windowSwap :: Direction2D -> Bool -> X ()
windowSwap dir wrap = actOnLayer thisLayer
windowSwap dir = actOnLayer thisLayer
( \ conf cur wins -> windows
$ doTiledNavigation conf dir swap cur wins
)
@ -470,32 +517,28 @@ windowSwap dir wrap = actOnLayer thisLayer
$ doFloatNavigation conf dir swap cur wins
)
( \ _ _ _ -> return () )
wrap
-- | Moves the current window to the next screen in the given direction. The
-- second argument indicates wrapping (see 'windowGo').
windowToScreen :: Direction2D -> Bool -> X ()
windowToScreen dir wrap = actOnScreens ( \ conf cur wspcs -> windows
windowToScreen dir = actOnScreens ( \ conf cur wspcs -> windows
$ doScreenNavigation conf dir W.shift cur wspcs
)
wrap
-- | Moves the focus to the next screen in the given direction. The second
-- argument indicates wrapping (see 'windowGo').
screenGo :: Direction2D -> Bool -> X ()
screenGo dir wrap = actOnScreens ( \ conf cur wspcs -> windows
screenGo dir = actOnScreens ( \ conf cur wspcs -> windows
$ doScreenNavigation conf dir W.view cur wspcs
)
wrap
-- | Swaps the workspace on the current screen with the workspace on the screen
-- in the given direction. The second argument indicates wrapping (see
-- 'windowGo').
screenSwap :: Direction2D -> Bool -> X ()
screenSwap dir wrap = actOnScreens ( \ conf cur wspcs -> windows
screenSwap dir = actOnScreens ( \ conf cur wspcs -> windows
$ doScreenNavigation conf dir W.greedyView cur wspcs
)
wrap
-- | Maps each window to a fullscreen rect. This may not be the same rectangle the
-- window maps to under the Full layout or a similar layout if the layout
@ -587,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
----------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------
@ -615,7 +655,7 @@ doFocusClosestWindow (cur, rect) winrects
where
ctr = centerOf rect
winctrs = filter ((cur /=) . fst)
$ map (\(w, r) -> (w, centerOf r)) winrects
$ map (second centerOf) winrects
closer wc1@(_, c1) wc2@(_, c2) | lDist ctr c1 > lDist ctr c2 = wc2
| otherwise = wc1
@ -635,8 +675,7 @@ doTiledNavigation conf dir act cur winrects winset
nav = maximum
$ map ( fromMaybe (defaultTiledNavigation conf)
. flip L.lookup (layoutNavigation conf)
)
$ layouts
) layouts
-- | Implements navigation for the float layer
doFloatNavigation :: Navigation2DConfig
@ -681,7 +720,7 @@ doLineNavigation dir (cur, rect) winrects
-- The list of windows that are candidates to receive focus.
winrects' = filter dirFilter
$ filter ((cur /=) . fst)
. filter ((cur /=) . fst)
$ winrects
-- Decides whether a given window matches the criteria to be a candidate to
@ -722,9 +761,8 @@ doCenterNavigation dir (cur, rect) winrects
-- center rotated so the right cone becomes the relevant cone.
-- The windows are ordered in the order they should be preferred
-- when they are otherwise tied.
winctrs = map (\(w, r) -> (w, dirTransform . centerOf $ r))
$ stackTransform
$ winrects
winctrs = map (second (dirTransform . centerOf))
$ stackTransform winrects
-- Give preference to windows later in the stack for going left or up and to
-- windows earlier in the stack for going right or down. (The stack order
@ -746,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.
@ -767,12 +804,53 @@ doCenterNavigation dir (cur, rect) winrects
-- or it has the same distance but comes later
-- in the window stack
-- | Implements Hybrid navigation. This attempts Line navigation first,
-- then falls back on Center navigation if it finds no suitable target window.
doHybridNavigation :: Eq a => Direction2D -> Rect a -> [Rect a] -> Maybe a
doHybridNavigation = applyToBoth (<|>) doLineNavigation doCenterNavigation
where
applyToBoth f g h a b c = f (g a b c) (h a b c)
-- x -y w h format is a pain. Let's use side coordinates. We assume x1 <= x2 and
-- y1 <= y2, and make the assumption valid by initialising SideRects with the
-- property and carefully preserving it over any individual transformation.
data SideRect = SideRect { x1 :: Int, x2 :: Int, y1 :: Int, y2 :: Int }
deriving Show
-- Conversion from Rectangle format to SideRect.
toSR :: Rectangle -> SideRect
toSR (Rectangle x y w h) = SideRect (fi x) (fi x + fi w) (-fi y - fi h) (-fi y)
-- Implements side navigation with bias.
doSideNavigationWithBias ::
Eq a => Int -> Direction2D -> Rect a -> [Rect a] -> Maybe a
doSideNavigationWithBias bias dir (cur, rect)
= fmap fst . listToMaybe
. L.sortOn dist . foldr acClosest []
. filter (`toRightOf` (cur, transform rect))
. map (fmap transform)
where
-- Getting the center of the current window so we can make it the new origin.
cOf r = ((x1 r + x2 r) `div` 2, (y1 r + y2 r) `div` 2)
(x0, y0) = cOf . toSR $ rect
-- Translate the given SideRect by (-x0, -y0).
translate r = SideRect (x1 r - x0) (x2 r - x0) (y1 r - y0) (y2 r - y0)
-- Rotate the given SideRect 90 degrees counter-clockwise about the origin.
rHalfPiCC r = SideRect (-y2 r) (-y1 r) (x1 r) (x2 r)
-- Apply the above function until d becomes synonymous with R (wolog).
rotateToR d = fromJust . lookup d . zip [R, D, L, U] . iterate rHalfPiCC
transform = rotateToR dir . translate . toSR
-- (_, r) `toRightOf` (_, c) iff r has points to the right of c that aren't
-- below or above c, i.e. iff:
-- [x1 r, x2 r] x [y1 r, y2 r] intersects (x2 c, infinity) x (y1 c, y2 c)
toRightOf (_, r) (_, c) = (x2 r > x2 c) && (y2 r > y1 c) && (y1 r < y2 c)
-- Greedily accumulate the windows tied for the leftmost left side.
acClosest (w, r) l@((_, r'):_) | x1 r == x1 r' = (w, r) : l
| x1 r > x1 r' = l
acClosest (w, r) _ = [(w, r)]
-- Given a (_, SideRect), calculate how far it is from the y=bias line.
dist (_, r) | (y1 r <= bias) && (bias <= y2 r) = 0
| otherwise = min (abs $ y1 r - bias) (abs $ y2 r - bias)
-- | Swaps the current window with the window given as argument
swap :: Window -> WindowSet -> WindowSet
@ -789,7 +867,7 @@ swap win winset = W.focusWindow cur
visws = map W.workspace scrs
-- The focused windows of the visible workspaces
focused = mapMaybe (\ws -> W.focus <$> W.stack ws) visws
focused = mapMaybe (fmap W.focus . W.stack) visws
-- The window lists of the visible workspaces
wins = map (W.integrate' . W.stack) visws
@ -806,22 +884,18 @@ 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
centerOf :: Rectangle -> (Position, Position)
centerOf r = (rect_x r + fi (rect_width r) `div` 2, rect_y r + fi (rect_height r) `div` 2)
-- | Shorthand for integer conversions
fi :: (Integral a, Num b) => a -> b
fi = fromIntegral
-- | Functions to choose the subset of windows to operate on
thisLayer, otherLayer :: a -> a -> a
thisLayer = curry fst
otherLayer = curry snd
thisLayer = const
otherLayer _ x = x
-- | Returns the list of visible workspaces and their screen rects
visibleWorkspaces :: WindowSet -> Bool -> [WSRect]
@ -858,8 +932,8 @@ wrapOffsets winset = (max_x - min_x, max_y - min_y)
where
min_x = fi $ minimum $ map rect_x rects
min_y = fi $ minimum $ map rect_y rects
max_x = fi $ maximum $ map (\r -> rect_x r + (fi $ rect_width r)) rects
max_y = fi $ maximum $ map (\r -> rect_y r + (fi $ rect_height r)) rects
max_x = fi $ maximum $ map (\r -> rect_x r + fi (rect_width r)) rects
max_y = fi $ maximum $ map (\r -> rect_y r + fi (rect_height r)) rects
rects = map snd $ visibleWorkspaces winset False
@ -869,16 +943,16 @@ sortedScreens :: WindowSet -> [Screen]
sortedScreens winset = L.sortBy cmp
$ W.screens winset
where
cmp s1 s2 | x1 < x2 = LT
| x1 > x2 = GT
| y1 < x2 = LT
| y1 > y2 = GT
cmp s1 s2 | x < x' = LT
| x > x' = GT
| y < x' = LT
| y > y' = GT
| otherwise = EQ
where
(x1, y1) = centerOf (screenRect . W.screenDetail $ s1)
(x2, y2) = centerOf (screenRect . W.screenDetail $ s2)
(x , y ) = centerOf (screenRect . W.screenDetail $ s1)
(x', y') = centerOf (screenRect . W.screenDetail $ s2)
-- | Calculates the L1-distance between two points.
lDist :: (Position, Position) -> (Position, Position) -> Int
lDist (x1, y1) (x2, y2) = abs (fi $ x1 - x2) + abs (fi $ y1 - y2)
lDist (x, y) (x', y') = abs (fi $ x - x') + abs (fi $ y - y')

View File

@ -1,6 +1,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.NoBorders
-- Description : Helper functions for dealing with window borders.
-- Copyright : (c) Lukas Mai
-- License : BSD3-style (see LICENSE)
--
@ -26,8 +27,7 @@ import XMonad
toggleBorder :: Window -> X ()
toggleBorder w = do
bw <- asks (borderWidth . config)
withDisplay $ \d -> io $ do
cw <- wa_border_width `fmap` 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,157 +1,187 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.OnScreen
-- Copyright : (c) 2009 Nils Schweinsberg
-- Description : Control workspaces on different screens (in xinerama mode).
-- 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 (empty, fromMaybe, guard)
import XMonad.StackSet hiding (new)
import Control.Monad (guard)
-- import Control.Monad.State.Class (gets)
import Data.Maybe (fromMaybe)
-- | 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
ws <- lookupWorkspace sc st
let fStack = f $ view ws st
return $ setFocus foc st fStack
let fStack = f $ view ws st
return $ setFocus foc st fStack
-- set focus for new stack
setFocus :: Focus
-> WindowSet -- ^ old stack
-> WindowSet -- ^ new stack
-> WindowSet
setFocus FocusNew _ new = new
setFocus FocusCurrent old new =
case lookupWorkspace (screen $ current old) new of
Nothing -> new
Just i -> view i new
setFocus (FocusTag i) _ new = view i new
setFocus ::
Focus ->
-- | old stack
WindowSet ->
-- | new stack
WindowSet ->
WindowSet
setFocus FocusNew _ new = new
setFocus FocusCurrent old new =
case lookupWorkspace (screen $ current old) new of
Nothing -> new
Just i -> view i new
setFocus (FocusTag i) _ new = view i new
setFocus (FocusTagVisible i) old new =
if i `elem` map (tag . workspace) (visible old)
then setFocus (FocusTag i) old new
else setFocus FocusCurrent old new
if i `elem` map (tag . workspace) (visible old)
then setFocus (FocusTag i) old new
else setFocus FocusCurrent old new
-- | A variation of @onScreen@ which will take any @X ()@ function and run it
-- 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
Nothing -> return ()
Just ws -> do
windows $ view ws
x
windows $ setFocus foc st
st <- gets windowset
case lookupWorkspace sc st of
Nothing -> return ()
Just ws -> do
windows $ view ws
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
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
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
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
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
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
let st' = hidden st
-- make sure we actually have to do something
guard $ i == (tag . workspace $ current 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
--
@ -185,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

@ -0,0 +1,61 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.PerWindowKeys
-- Description : Define key-bindings on a per-window basis.
-- Copyright : (c) Wilson Sales, 2019
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : Wilson Sales <spoonm@spoonm.org>
-- Stability : unstable
-- Portability : unportable
--
-- Define key-bindings on a per-window basis.
--
-----------------------------------------------------------------------------
module XMonad.Actions.PerWindowKeys (
-- * Usage
-- $usage
bindAll,
bindFirst
) where
import XMonad
-- $usage
--
-- You can use this module with the following in your @xmonad.hs@:
--
-- > import XMonad.Actions.PerWindowKeys
--
-- > ,((0, xK_F2), bindFirst [(className =? "firefox", spawn "dmenu"), (isFloat, withFocused $ windows . W.sink)])
--
-- > ,((0, xK_F3), bindAll [(isDialog, kill), (pure True, doSomething)])
--
-- If you want an action that will always run, but also want to do something for
-- other queries, you can use @'bindAll' [(query1, action1), ..., (pure True,
-- alwaysDoThisAction)]@.
--
-- Similarly, if you want a default action to be run if all the others failed,
-- you can use @'bindFirst' [(query1, action1), ..., (pure True,
-- doThisIfTheOthersFail)]@.
--
-- For detailed instructions on editing your key bindings, see
-- <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.
bindAll :: [(Query Bool, X ())] -> X ()
bindAll = mapM_ choose where
choose (mh,action) = withFocused $ \w -> whenX (runQuery mh w) action
-- | Run the action paired with the first Query that holds true.
bindFirst :: [(Query Bool, X ())] -> X ()
bindFirst = withFocused . chooseOne
chooseOne :: [(Query Bool, X ())] -> Window -> X ()
chooseOne [] _ = return ()
chooseOne ((mh,a):bs) w = do
c <- runQuery mh w
if c then a
else chooseOne bs w

View File

@ -1,6 +1,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.PerWorkspaceKeys
-- Description : Define key-bindings on per-workspace basis.
-- Copyright : (c) Roman Cheplyaka, 2008
-- License : BSD3-style (see LICENSE)
--
@ -24,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()
@ -46,4 +47,3 @@ bindOn bindings = chooseAction chooser where
Nothing -> case lookup "" bindings of
Just action -> action
Nothing -> return ()

View File

@ -1,7 +1,10 @@
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE ParallelListComp #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.PhysicalScreens
-- Description : Manipulate screens ordered by physical location instead of ID.
-- Copyright : (c) Nelson Elhage <nelhage@mit.edu>
-- License : BSD
--
@ -21,14 +24,21 @@ module XMonad.Actions.PhysicalScreens (
, sendToScreen
, onNextNeighbour
, onPrevNeighbour
, horizontalScreenOrderer
, verticalScreenOrderer
, ScreenComparator(ScreenComparator)
, getScreenIdAndRectangle
, screenComparatorById
, screenComparatorByRectangle
, rescreen
) where
import XMonad
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
import Data.List (sortBy,findIndex)
import Data.Function (on)
{- $usage
This module allows you name Xinerama screens from XMonad using their
@ -36,17 +46,20 @@ physical location relative to each other (as reported by Xinerama),
rather than their @ScreenID@ s, which are arbitrarily determined by
your X server and graphics hardware.
Screens are ordered by the upper-left-most corner, from top-to-bottom
You can specify how to order the screen by giving a ScreenComparator.
To create a screen comparator you can use screenComparatorByRectangle or screenComparatorByScreenId.
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
> , ((modMask, xK_a), onPrevNeighbour W.view)
> , ((modMask, xK_o), onNextNeighbour W.view)
> , ((modMask .|. shiftMask, xK_a), onPrevNeighbour W.shift)
> , ((modMask .|. shiftMask, xK_o), onNextNeighbour W.shift)
> , ((modMask, xK_a), onPrevNeighbour def W.view)
> , ((modMask, xK_o), onNextNeighbour def W.view)
> , ((modMask .|. shiftMask, xK_a), onPrevNeighbour def W.shift)
> , ((modMask .|. shiftMask, xK_o), onNextNeighbour def W.shift)
> --
> -- mod-{w,e,r}, Switch to physical/Xinerama screens 1, 2, or 3
@ -54,61 +67,137 @@ Example usage in your @~\/.xmonad\/xmonad.hs@ file:
> --
> [((modm .|. mask, key), f sc)
> | (key, sc) <- zip [xK_w, xK_e, xK_r] [0..]
> , (f, mask) <- [(viewScreen, 0), (sendToScreen, shiftMask)]]
> , (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
newtype PhysicalScreen = P Int deriving (Eq,Ord,Show,Read,Enum,Num,Integral,Real)
-- | Translate a physical screen index to a "ScreenId"
getScreen :: PhysicalScreen -> X (Maybe ScreenId)
getScreen (P i) = do w <- gets windowset
let screens = W.current w : W.visible w
if i<0 || i >= length screens
then return Nothing
else let ss = sortBy (cmpScreen `on` (screenRect . W.screenDetail)) screens
in return $ Just $ W.screen $ ss !! i
getScreenIdAndRectangle :: W.Screen i l a ScreenId ScreenDetail -> (ScreenId, Rectangle)
getScreenIdAndRectangle screen = (W.screen screen, rect) where
rect = screenRect $ W.screenDetail screen
-- | 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
if i<0 || i >= length screens
then return Nothing
else let ss = sortBy (cmpScreen `on` getScreenIdAndRectangle) screens
in return $ Just $ W.screen $ ss !! i
-- | Switch to a given physical screen
viewScreen :: PhysicalScreen -> X ()
viewScreen p = do i <- getScreen p
whenJust i $ \s -> do
w <- screenWorkspace s
whenJust w $ windows . W.view
viewScreen :: ScreenComparator -> PhysicalScreen -> X ()
viewScreen sc p = do i <- getScreen sc p
whenJust i $ \s -> do
w <- screenWorkspace s
whenJust w $ windows . W.view
-- | Send the active window to a given physical screen
sendToScreen :: PhysicalScreen -> X ()
sendToScreen p = do i <- getScreen p
whenJust i $ \s -> do
w <- screenWorkspace s
whenJust w $ windows . W.shift
sendToScreen :: ScreenComparator -> PhysicalScreen -> X ()
sendToScreen sc p = do i <- getScreen sc p
whenJust i $ \s -> do
w <- screenWorkspace s
whenJust w $ windows . W.shift
-- | Compare two screens by their top-left corners, ordering
-- | top-to-bottom and then left-to-right.
cmpScreen :: Rectangle -> Rectangle -> Ordering
cmpScreen (Rectangle x1 y1 _ _) (Rectangle x2 y2 _ _) = compare (y1,x1) (y2,x2)
-- | A ScreenComparator allow to compare two screen based on their coordonate and Xinerama Id
newtype ScreenComparator = ScreenComparator ((ScreenId, Rectangle) -> (ScreenId, Rectangle) -> Ordering)
-- | The default ScreenComparator orders screens by the upper-left-most corner, from top-to-bottom
instance Default ScreenComparator where
def= verticalScreenOrderer
-- | Compare screen only by their coordonate
screenComparatorByRectangle :: (Rectangle -> Rectangle -> Ordering) -> ScreenComparator
screenComparatorByRectangle rectComparator = ScreenComparator comparator where
comparator (_, rec1) (_, rec2) = rectComparator rec1 rec2
-- | Compare screen only by their Xinerama id
screenComparatorById :: (ScreenId -> ScreenId -> Ordering) -> ScreenComparator
screenComparatorById idComparator = ScreenComparator comparator where
comparator (id1, _) (id2, _) = idComparator id1 id2
-- | orders screens by the upper-left-most corner, from top-to-bottom
verticalScreenOrderer :: ScreenComparator
verticalScreenOrderer = screenComparatorByRectangle comparator where
comparator (Rectangle x1 y1 _ _) (Rectangle x2 y2 _ _) = compare (y1, x1) (y2, x2)
-- | orders screens by the upper-left-most corner, from left-to-right
horizontalScreenOrderer :: ScreenComparator
horizontalScreenOrderer = screenComparatorByRectangle comparator where
comparator (Rectangle x1 y1 _ _) (Rectangle x2 y2 _ _) = compare (x1, y1) (x2, y2)
-- | Get ScreenId for neighbours of the current screen based on position offset.
getNeighbour :: Int -> X ScreenId
getNeighbour d = do w <- gets windowset
let ss = map W.screen $ sortBy (cmpScreen `on` (screenRect . W.screenDetail)) $ W.current w : W.visible w
curPos = maybe 0 id $ findIndex (== W.screen (W.current w)) ss
pos = (curPos + d) `mod` length ss
return $ ss !! pos
getNeighbour :: ScreenComparator -> Int -> X ScreenId
getNeighbour (ScreenComparator cmpScreen) d =
do w <- gets windowset
let ss = map W.screen $ sortBy (cmpScreen `on` getScreenIdAndRectangle) $ W.current w : W.visible w
curPos = fromMaybe 0 $ elemIndex (W.screen (W.current w)) ss
pos = (curPos + d) `mod` length ss
return $ ss !! pos
neighbourWindows :: Int -> (WorkspaceId -> WindowSet -> WindowSet) -> X ()
neighbourWindows d f = do s <- getNeighbour d
w <- screenWorkspace s
whenJust w $ windows . f
neighbourWindows :: ScreenComparator -> Int -> (WorkspaceId -> WindowSet -> WindowSet) -> X ()
neighbourWindows sc d f = do s <- getNeighbour sc d
w <- screenWorkspace s
whenJust w $ windows . f
-- | Apply operation on a WindowSet with the WorkspaceId of the next screen in the physical order as parameter.
onNextNeighbour :: (WorkspaceId -> WindowSet -> WindowSet) -> X ()
onNextNeighbour = neighbourWindows 1
onNextNeighbour :: ScreenComparator -> (WorkspaceId -> WindowSet -> WindowSet) -> X ()
onNextNeighbour sc = neighbourWindows sc 1
-- | Apply operation on a WindowSet with the WorkspaceId of the previous screen in the physical order as parameter.
onPrevNeighbour :: (WorkspaceId -> WindowSet -> WindowSet) -> X ()
onPrevNeighbour = neighbourWindows (-1)
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

@ -1,6 +1,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.Plane
-- Description : Navigate through workspaces in a bidimensional manner.
-- Copyright : (c) Marco Túlio Gontijo e Silva <marcot@riseup.net>,
-- Leonardo Serra <leoserra@minaslivre.org>
-- License : BSD3-style (see LICENSE)
@ -38,17 +39,15 @@ module XMonad.Actions.Plane
)
where
import Control.Monad
import Data.List
import Data.Map hiding (split)
import Data.Maybe
import Data.Map (Map, fromList)
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)
@ -60,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

222
XMonad/Actions/Prefix.hs Normal file
View File

@ -0,0 +1,222 @@
{-# LANGUAGE FlexibleContexts #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.Prefix
-- Description : Use an Emacs-style prefix argument for commands.
-- Copyright : (c) Matus Goljer <matus.goljer@gmail.com>
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : Matus Goljer <matus.goljer@gmail.com>
-- Stability : unstable
-- Portability : unportable
--
-- A module that allows the user to use a prefix argument (raw or numeric).
--
-----------------------------------------------------------------------------
module XMonad.Actions.Prefix
(
-- * Usage
-- $usage
-- * Installation
-- $installation
PrefixArgument(..)
, usePrefixArgument
, useDefaultPrefixArgument
, withPrefixArgument
, isPrefixRaw
, isPrefixNumeric
, orIfPrefixed
, ppFormatPrefix
) where
import qualified Data.Map as M
import XMonad.Prelude
import XMonad
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'.
To initiate the "prefix mode" you hit the prefix keybinding (default
C-u). This sets the Raw argument value to 1. Repeatedly hitting this
key increments the raw value by 1. The Raw argument is usually used
as a toggle, changing the behaviour of the function called in some way.
An example might be calling "mpc add" to add new song to the playlist,
but with C-u we also clean up the playlist beforehand.
When in the "Raw mode", you can hit numeric keys 0..9 (with no
modifier) to enter a "Numeric argument". Numeric argument represents
a natural number. Hitting numeric keys in sequence produces the
decimal number that would result from typing them. That is, the
sequence C-u 4 2 sets the Numeric argument value to the number 42.
If you have a function which understands the prefix argument, for example:
> addMaybeClean :: PrefixArgument -> X ()
> addMaybeClean (Raw _) = spawn "mpc clear" >> spawn "mpc add <file>"
> addMaybeClean _ = spawn "mpc add <file>"
you can turn it into an X action with the function 'withPrefixArgument'.
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
clear the playlist and then add the file.
You can of course use an anonymous action, like so:
> ((modm, xK_a), withPrefixArgument $ \prefix -> do
> case prefix of ...
> )
If the prefix key is followed by a binding which is unknown to XMonad,
the prefix along with that binding is sent to the active window.
There is one caveat: when you use an application which has a nested
C-u binding, for example C-c C-u in Emacs org-mode, you have to hit
C-g (or any other non-recognized key really) to get out of the "xmonad
grab" and let the C-c C-u be sent to the application.
-}
{- $installation
The simplest way to enable this is to use 'useDefaultPrefixArgument'
> xmonad $ useDefaultPrefixArgument $ def { .. }
The default prefix argument is C-u. If you want to customize the
prefix argument, 'usePrefixArgument' can be used:
> xmonad $ usePrefixArgument "M-u" $ def { .. }
where the key is entered in Emacs style (or "XMonad.Util.EZConfig"
style) notation. The letter `M` stands for your chosen modifier. The
function defaults to C-u if the argument could not be parsed.
-}
data PrefixArgument = Raw Int | Numeric Int | None
deriving (Read, Show)
instance ExtensionClass PrefixArgument where
initialValue = None
extensionType = PersistentExtension
-- | Run 'job' in the 'X' monad and then execute 'cleanup'. In case
-- of exception, 'cleanup' is executed anyway.
--
-- Return the return value of 'job'.
finallyX :: X a -> X a -> X a
finallyX job cleanup = catchX (job >>= \r -> cleanup >> return r) cleanup
-- | Set up Prefix. Defaults to C-u when given an invalid key.
--
-- See usage section.
usePrefixArgument :: LayoutClass l Window
=> String
-> XConfig l
-> XConfig l
usePrefixArgument prefix conf =
conf{ keys = M.insert binding (handlePrefixArg (binding :| [])) . keys conf }
where
binding = case readKeySequence conf prefix of
Just (key :| []) -> key
_ -> (controlMask, xK_u)
-- | Set Prefix up with default prefix key (C-u).
useDefaultPrefixArgument :: LayoutClass l Window
=> XConfig l
-> XConfig l
useDefaultPrefixArgument = usePrefixArgument "C-u"
handlePrefixArg :: NonEmpty (KeyMask, KeySym) -> X ()
handlePrefixArg events = do
ks <- asks keyActions
logger <- asks (logHook . config)
flip finallyX (XS.put None >> logger) $ do
prefix <- XS.get
case prefix of
Raw a -> XS.put $ Raw (a + 1)
None -> XS.put $ Raw 1
_ -> return ()
logger
submapDefaultWithKey defaultKey ks
where defaultKey key@(m, k) =
if k `elem` (xK_0 : [xK_1 .. xK_9]) && m == noModMask
then do
prefix <- XS.get
let x = fromJust (Prelude.lookup k keyToNum)
case prefix of
Raw _ -> XS.put $ Numeric x
Numeric a -> XS.put $ Numeric $ a * 10 + x
None -> return () -- should never happen
handlePrefixArg (key <| events)
else do
prefix <- XS.get
mapM_ (uncurry sendKey) $ case prefix of
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 a) -> X a
withPrefixArgument = (>>=) XS.get
-- | Test if 'PrefixArgument' is 'Raw' or not.
isPrefixRaw :: PrefixArgument -> Bool
isPrefixRaw (Raw _) = True
isPrefixRaw _ = False
-- | Test if 'PrefixArgument' is 'Numeric' or not.
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.
--
-- To add this formatted prefix to printer output, you can set it up
-- like so
--
-- > myPrinter :: PP
-- > myPrinter = def { ppExtras = [ppFormatPrefix] }
--
-- And then add to your status bar using "XMonad.Hooks.StatusBar":
--
-- > mySB = statusBarProp "xmobar" myPrinter
-- > main = xmonad $ withEasySB mySB defToggleStrutsKey def
--
-- Or, directly in your 'logHook' configuration
--
-- > logHook = dynamicLogWithPP myPrinter
ppFormatPrefix :: X (Maybe String)
ppFormatPrefix = do
prefix <- XS.get
return $ case prefix of
Raw n -> Just $ foldr1 (\a b -> a ++ " " ++ b) $ replicate n "C-u"
Numeric n -> Just $ "C-u " ++ show n
None -> Nothing

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

@ -1,6 +1,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.Promote
-- Description : Alternate promote function for xmonad.
-- Copyright : (c) Miikka Koskinen 2007
-- License : BSD3-style (see LICENSE)
--
@ -27,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
--
@ -36,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

@ -1,6 +1,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.RandomBackground
-- Description : Start terminals with a random background color.
-- Copyright : (c) 2009 Anze Slosar
-- translation to Haskell by Adam Vogt
-- License : BSD3-style (see LICENSE)
@ -24,7 +25,6 @@ module XMonad.Actions.RandomBackground (
import XMonad(X, XConf(config), XConfig(terminal), io, spawn,
MonadIO, asks)
import System.Random
import Control.Monad(liftM)
import Numeric(showHex)
-- $usage
@ -55,7 +55,7 @@ randPermutation xs g = swap $ zip (randoms g) xs
-- | @randomBg'@ produces a random hex number in the form @'#xxyyzz'@
randomBg' :: (MonadIO m) => RandomColor -> m String
randomBg' (RGB l h) = io $ liftM (toHex . take 3 . randomRs (l,h)) newStdGen
randomBg' (RGB l h) = io $ fmap (toHex . take 3 . randomRs (l,h)) newStdGen
randomBg' (HSV s v) = io $ do
g <- newStdGen
let x = (^(2::Int)) $ fst $ randomR (0,sqrt $ pi / 3) g

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,6 +1,9 @@
{-# LANGUAGE ViewPatterns #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.RotSlaves
-- Description : Rotate all windows except the master window and keep the focus in place.
-- Copyright : (c) Hans Philipp Annen <haphi@gmx.net>, Mischa Dieterle <der_m@freenet.de>
-- License : BSD3-style (see LICENSE)
--
@ -14,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
--
@ -35,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

@ -0,0 +1,163 @@
{-# LANGUAGE ViewPatterns #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.RotateSome
-- Description : Rotate some elements around the stack.
-- Copyright : (c) 2020 Ivan Brennan <ivanbrennan@gmail.com>
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : Ivan Brennan <ivanbrennan@gmail.com>
-- Stability : stable
-- Portability : unportable
--
-- Functions for rotating some elements around the stack while keeping others
-- anchored in place. Useful in combination with layouts that dictate window
-- visibility based on stack position, such as "XMonad.Layout.LimitWindows".
--
-----------------------------------------------------------------------------
module XMonad.Actions.RotateSome (
-- * Usage
-- $usage
-- * Example
-- $example
surfaceNext,
surfacePrev,
rotateSome,
) where
import Control.Arrow ((***))
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.hs@:
> import XMonad.Actions.RotateSome
and add keybindings such as the following:
> , ((modMask .|. controlMask, xK_n), surfaceNext)
> , ((modMask .|. controlMask, xK_p), surfacePrev)
-}
{- $example
#Example#
Consider a workspace whose stack contains five windows A B C D E but whose
layout limits how many will actually be shown, showing only the first plus
two additional windows, starting with the third:
>
> C
> A
> D
>
>
> A B C D E
> _ ____
If C has focus and we'd like to replace it with one of the unshown windows,
'surfaceNext' will move the next unshown window, E, into the focused position:
>
> *C* *E*
> A surfaceNext -> A
> D D
>
>
> A B *C* D E A C *E* D B
> _ ____ _ ____
This repositioned windows B C E by treating them as a sequence that can be
rotated through the focused stack position. Windows A and D remain anchored
to their original (visible) positions.
A second call to 'surfaceNext' moves B into focus:
>
> *E* *B*
> A surfaceNext -> A
> D D
>
>
> A C *E* D B A E *B* D C
> _ ____ _ ____
A third call would complete the cycle, bringing C back into focus.
-}
-- |
-- Treating the focused window and any unshown windows as a ring that can be
-- rotated through the focused position, surface the next element in the ring.
surfaceNext :: X ()
surfaceNext = do
ring <- surfaceRing
windows . modify' $ rotateSome (`elem` ring)
-- | Like 'surfaceNext' in reverse.
surfacePrev :: X ()
surfacePrev = do
ring <- surfaceRing
windows . modify' $ reverseS . rotateSome (`elem` ring) . reverseS
-- |
-- Return a list containing the current focus plus any unshown windows. Note
-- that windows are shown if 'runLayout' provides them with a rectangle or if
-- they are floating.
surfaceRing :: X [Window]
surfaceRing = withWindowSet $ \wset -> do
let Screen wsp _ sd = current wset
case stack wsp >>= filter' (`M.notMember` floating wset) of
Nothing -> pure []
Just st -> go st <$> layoutWindows wsp {stack = Just st} (screenRect sd)
where
go :: Stack Window -> [Window] -> [Window]
go (Stack t ls rs) shown = t : ((ls ++ rs) \\ shown)
layoutWindows :: WindowSpace -> Rectangle -> X [Window]
layoutWindows wsp rect = map fst . fst <$> runLayout wsp rect
-- | Like "XMonad.StackSet.filter" but won't move focus.
filter' :: (a -> Bool) -> Stack a -> Maybe (Stack a)
filter' p (Stack f ls rs)
| p f = Just $ Stack f (filter p ls) (filter p rs)
| otherwise = Nothing
-- |
-- @'rotateSome' p stack@ treats the elements of @stack@ that satisfy predicate
-- @p@ as a ring that can be rotated, while all other elements remain anchored
-- in place.
rotateSome :: (a -> Bool) -> Stack a -> Stack a
rotateSome p (Stack t ls rs) =
let
-- Flatten the stack, index each element relative to the focused position,
-- then partition into movable and anchored elements.
(movables, anchors) =
partition (p . snd) $
zip
[negate (length ls)..]
(reverse ls ++ t : rs)
-- Pair each movable element with the index of its next movable neighbor.
-- 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', notEmpty -> t' :| rs') =
(map snd *** map snd)
. span ((< 0) . fst)
. sortOn fst
. (++) anchors
$ zipWith (curry (fst *** snd)) movables (rotate movables)
in
Stack t' (reverse ls') rs'
rotate :: [a] -> [a]
rotate = uncurry (flip (++)) . splitAt 1

View File

@ -1,4 +1,6 @@
{- | Module : XMonad.Actions.Search
{- |
Module : XMonad.Actions.Search
Description : Easily run Internet searches on web sites through xmonad.
Copyright : (C) 2007 Gwern Branwen
License : None; public domain
@ -18,6 +20,7 @@ module XMonad.Actions.Search ( -- * Usage
searchEngineF,
promptSearch,
promptSearchBrowser,
promptSearchBrowser',
selectSearch,
selectSearchBrowser,
isPrefixOf,
@ -28,32 +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,
isohunt,
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
@ -63,13 +84,12 @@ module XMonad.Actions.Search ( -- * Usage
) where
import Codec.Binary.UTF8.String (encode)
import Data.Char (isAlphaNum, isAscii)
import Data.List (isPrefixOf)
import Text.Printf
import XMonad (X (), liftIO)
import XMonad.Prompt (XPConfig (), XPrompt (showXPrompt, nextCompletion, commandToComplete),
getNextCompletion,
historyCompletionP, mkXPrompt)
import XMonad.Prelude (isAlphaNum, isAscii, isPrefixOf)
import XMonad.Prompt.Shell (getBrowser)
import XMonad.Util.Run (safeSpawn)
import XMonad.Util.XSelection (getSelection)
@ -99,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.
@ -113,41 +141,71 @@ 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.
* 'imdb' -- the Internet Movie Database.
* 'isohunt' -- isoHunt search.
* 'lucky' -- Google "I'm feeling lucky" search.
* 'maps' -- Google maps.
* '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.
* 'thesaurus' -- thesaurus.reference.com 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.
@ -191,7 +249,7 @@ Or in combination with XMonad.Util.EZConfig:
>
> searchList :: [(String, S.SearchEngine)]
> searchList = [ ("g", S.google)
> , ("h", S.hoohle)
> , ("h", S.hoogle)
> , ("w", S.wikipedia)
> ]
@ -210,7 +268,7 @@ engine.
Happy searching! -}
-- | A customized prompt indicating we are searching, and the name of the site.
data Search = Search Name
newtype Search = Search Name
instance XPrompt Search where
showXPrompt (Search name)= "Search [" ++ name ++ "]: "
nextCompletion _ = getNextCompletion
@ -248,7 +306,7 @@ search browser site query = safeSpawn browser [site query]
appends it to the base. You can easily define a new engine locally using
exported functions without needing to modify "XMonad.Actions.Search":
> myNewEngine = searchEngine "site" "http://site.com/search="
> myNewEngine = searchEngine "site" "https://site.com/search="
The important thing is that the site has a interface which accepts the escaped query
string as part of the URL. Alas, the exact URL to feed searchEngine varies
@ -257,21 +315,21 @@ search browser site query = safeSpawn browser [site query]
Generally, examining the resultant URL of a search will allow you to reverse-engineer
it if you can't find the necessary URL already described in other projects such as Surfraw. -}
searchEngine :: Name -> String -> SearchEngine
searchEngine name site = searchEngineF name (\s -> site ++ (escape s))
searchEngine name site = searchEngineF name (\s -> site ++ escape s)
{- | If your search engine is more complex than this (you may want to identify
the kind of input and make the search URL dependent on the input or put the query
inside of a URL instead of in the end) you can use the alternative 'searchEngineF' function.
> searchFunc :: String -> String
> searchFunc s | "wiki:" `isPrefixOf` s = "http://en.wikipedia.org/wiki/" ++ (escape $ tail $ snd $ break (==':') s)
> | "http://" `isPrefixOf` s = s
> | otherwise = (use google) 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
@searchFunc@ here searches for a word in wikipedia if it has a prefix
of \"wiki:\" (you can use the 'escape' function to escape any forbidden characters), opens an address
directly if it starts with \"http:\/\/\" and otherwise uses the provided google search engine.
directly if it starts with \"https:\/\/\" and otherwise uses the provided google search engine.
You can use other engines inside of your own through the 'use' function as shown above to make
complex searches.
@ -281,38 +339,57 @@ searchEngineF :: Name -> Site -> SearchEngine
searchEngineF = SearchEngine
-- The engines.
amazon, alpha, codesearch, deb, debbts, debpts, dictionary, google, hackage, hoogle,
images, imdb, isohunt, lucky, maps, mathworld, openstreetmap, scholar, stackage, thesaurus, vocabulary, wayback, wikipedia, wiktionary,
youtube, duckduckgo :: SearchEngine
amazon = searchEngine "amazon" "http://www.amazon.com/s/ref=nb_sb_noss_2?url=search-alias%3Daps&field-keywords="
alpha = searchEngine "alpha" "http://www.wolframalpha.com/input/?i="
codesearch = searchEngine "codesearch" "http://www.google.com/codesearch?q="
deb = searchEngine "deb" "http://packages.debian.org/"
debbts = searchEngine "debbts" "http://bugs.debian.org/"
debpts = searchEngine "debpts" "http://packages.qa.debian.org/"
dictionary = searchEngine "dict" "http://dictionary.reference.com/browse/"
google = searchEngine "google" "http://www.google.com/search?num=100&q="
hackage = searchEngine "hackage" "http://hackage.haskell.org/package/"
hoogle = searchEngine "hoogle" "http://www.haskell.org/hoogle/?q="
images = searchEngine "images" "http://images.google.fr/images?q="
imdb = searchEngine "imdb" "http://www.imdb.com/find?s=all&q="
isohunt = searchEngine "isohunt" "http://isohunt.com/torrents/?ihq="
lucky = searchEngine "lucky" "http://www.google.com/search?btnI&q="
maps = searchEngine "maps" "http://maps.google.com/maps?q="
mathworld = searchEngine "mathworld" "http://mathworld.wolfram.com/search/?query="
openstreetmap = searchEngine "openstreetmap" "http://gazetteer.openstreetmap.org/namefinder/?find="
scholar = searchEngine "scholar" "http://scholar.google.com/scholar?q="
stackage = searchEngine "stackage" "www.stackage.org/lts/hoogle?q="
thesaurus = searchEngine "thesaurus" "http://thesaurus.reference.com/search?q="
wikipedia = searchEngine "wiki" "http://en.wikipedia.org/wiki/Special:Search?go=Go&search="
wiktionary = searchEngine "wikt" "http://en.wiktionary.org/wiki/Special:Search?go=Go&search="
youtube = searchEngine "youtube" "http://www.youtube.com/results?search_type=search_videos&search_query="
wayback = searchEngineF "wayback" ("http://web.archive.org/web/*/"++)
vocabulary = searchEngine "vocabulary" "http://www.vocabulary.com/search?q="
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?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="
zbmath = searchEngine "zbmath" "https://zbmath.org/?q="
multi :: SearchEngine
multi = namedEngine "multi" $ foldr1 (!>) [amazon, alpha, codesearch, deb, debbts, debpts, dictionary, google, hackage, hoogle, images, imdb, isohunt, 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
@ -320,9 +397,9 @@ multi = namedEngine "multi" $ foldr1 (!>) [amazon, alpha, codesearch, deb, debbt
> myIntelligentGoogleEngine = intelligent google
Now if you search for http:\/\/xmonad.org it will directly open in your browser-}
Now if you search for https:\/\/xmonad.org it will directly open in your browser-}
intelligent :: SearchEngine -> SearchEngine
intelligent (SearchEngine name site) = searchEngineF name (\s -> if (fst $ break (==':') s) `elem` ["http", "https", "ftp"] then s else (site s))
intelligent (SearchEngine name site) = searchEngineF name (\s -> if takeWhile (/= ':') s `elem` ["http", "https", "ftp"] then s else site s)
-- | > removeColonPrefix "foo://bar" ~> "//bar"
-- > removeColonPrefix "foo//bar" ~> "foo//bar"
@ -342,6 +419,7 @@ removeColonPrefix s = if ':' `elem` s then drop 1 $ dropWhile (':' /=) s else s
google. The use of intelligent will make sure that URLs are opened directly. -}
(!>) :: SearchEngine -> SearchEngine -> SearchEngine
(SearchEngine name1 site1) !> (SearchEngine name2 site2) = searchEngineF (name1 ++ "/" ++ name2) (\s -> if (name1++":") `isPrefixOf` s then site1 (removeColonPrefix s) else site2 s)
infixr 6 !>
{- | Makes a search engine prefix-aware. Especially useful together with '!>'.
It will automatically remove the prefix from a query so that you don\'t end
@ -358,8 +436,18 @@ namedEngine name (SearchEngine _ site) = searchEngineF name site
Prompt's result, passes it to a given searchEngine and opens it in a given
browser. -}
promptSearchBrowser :: XPConfig -> Browser -> SearchEngine -> X ()
promptSearchBrowser config browser (SearchEngine name site) =
mkXPrompt (Search name) config (historyCompletionP ("Search [" `isPrefixOf`)) $ search browser site
promptSearchBrowser config browser (SearchEngine name site) = do
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 config (searchName `isPrefixOf`)
mkXPrompt (Search name) config hc $ search browser site
where
searchName = showXPrompt (Search name)
{- | Like 'search', but in this case, the string is not specified but grabbed
from the user's response to a prompt. Example:

View File

@ -1,7 +1,9 @@
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE MultiWayIf #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.ShowText
-- Description : Display text on the screen.
-- Copyright : (c) Mario Pastorelli (2012)
-- License : BSD-style (see xmonad/LICENSE)
--
@ -17,17 +19,15 @@ module XMonad.Actions.ShowText
( -- * Usage
-- $usage
def
, defaultSTConfig
, handleTimerEvent
, flashText
, ShowTextConfig(..)
) where
import Control.Monad (when)
import Data.Map (Map,empty,insert,lookup)
import Data.Monoid (mempty, All)
import Prelude hiding (lookup)
import XMonad
import XMonad.Prelude (All, fi, listToMaybe)
import XMonad.StackSet (current,screen)
import XMonad.Util.Font (Align(AlignCenter)
, initXMF
@ -37,19 +37,18 @@ import XMonad.Util.Font (Align(AlignCenter)
import XMonad.Util.Timer (startTimer)
import XMonad.Util.XUtils (createNewWindow
, deleteWindow
, fi
, showWindow
, paintAndWrite)
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:
--
@ -58,7 +57,7 @@ import qualified XMonad.Util.ExtensibleState as ES
-- | ShowText contains the map with timers as keys and created windows as values
newtype ShowText = ShowText (Map Atom Window)
deriving (Read,Show,Typeable)
deriving (Read,Show)
instance ExtensionClass ShowText where
initialValue = ShowText empty
@ -75,22 +74,23 @@ data ShowTextConfig =
instance Default ShowTextConfig where
def =
#ifdef XFT
STC { st_font = "xft:monospace-20"
#else
STC { st_font = "-misc-fixed-*-*-*-*-20-*-*-*-*-*-*-*"
#endif
, st_bg = "black"
, st_fg = "white"
}
{-# DEPRECATED defaultSTConfig "Use def (from Data.Default, and re-exported by XMonad.Actions.ShowText) instead." #-}
defaultSTConfig :: ShowTextConfig
defaultSTConfig = def
-- | Handles timer events that notify when a window should be removed
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 && length d >= 1)
(whenJust (lookup (fromIntegral $ d !! 0) m) deleteWindow)
if | mtyp == a, Just dh <- listToMaybe d ->
whenJust (lookup (fromIntegral dh) m) deleteWindow
| otherwise -> pure ()
mempty
handleTimerEvent _ = mempty

56
XMonad/Actions/Sift.hs Normal file
View File

@ -0,0 +1,56 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.Sift
-- Description : Functions for sifting windows up and down.
-- Copyright : (c) 2020 Ivan Brennan <ivanbrennan@gmail.com>
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : Ivan Brennan <ivanbrennan@gmail.com>
-- Stability : stable
-- Portability : unportable
--
-- Functions for sifting windows up and down. Sifts behave identically to
-- swaps (i.e. 'swapUp' and 'swapDown' from "XMonad.StackSet"), except in
-- the wrapping case: rather than rotating the entire stack by one position
-- like a swap would, a sift causes the windows at either end of the stack
-- to trade positions.
--
-----------------------------------------------------------------------------
module XMonad.Actions.Sift (
-- * Usage
-- $usage
siftUp,
siftDown,
) where
import XMonad.StackSet (Stack (Stack), StackSet, modify')
import XMonad.Util.Stack (reverseS)
-- $usage
-- You can use this module with the following in your @xmonad.hs@:
--
-- > import XMonad.Actions.Sift
--
-- and add keybindings such as the following:
--
-- > , ((modMask .|. shiftMask, xK_j ), windows siftDown)
-- > , ((modMask .|. shiftMask, xK_k ), windows siftUp )
--
-- |
-- siftUp, siftDown. Exchange the focused window with its neighbour in
-- the stack ordering, wrapping if we reach the end. Unlike 'swapUp' and
-- 'swapDown', wrapping is handled by trading positions with the window
-- at the other end of the stack.
--
siftUp, siftDown :: StackSet i l a s sd -> StackSet i l a s sd
siftUp = modify' siftUp'
siftDown = modify' (reverseS . siftUp' . reverseS)
siftUp' :: Stack a -> Stack a
siftUp' (Stack t (l:ls) rs) = Stack t ls (l:rs)
siftUp' (Stack t [] rs) =
case reverse rs of
(x:xs) -> Stack t (xs ++ [x]) []
[] -> Stack t [] []

View File

@ -1,6 +1,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.SimpleDate
-- Description : An example external contrib module for XMonad.
-- Copyright : (c) Don Stewart 2007
-- License : BSD3-style (see LICENSE)
--
@ -23,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
--
@ -34,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

@ -1,6 +1,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.SinkAll
-- Description : (DEPRECATED) Push floating windows back into tiling.
-- License : BSD3-style (see LICENSE)
-- Stability : unstable
-- Portability : unportable
@ -12,7 +13,7 @@
-- 'sinkAll' function for backwards compatibility.
-----------------------------------------------------------------------------
module XMonad.Actions.SinkAll (
module XMonad.Actions.SinkAll {-# DEPRECATED "Use XMonad.Actions.WithAll instead" #-} (
-- * Usage
-- $usage
@ -22,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
--
@ -31,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,7 +1,9 @@
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE LambdaCase #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.SpawnOn
-- Description : Modify a window spawned by a command.
-- Copyright : (c) Spencer Janssen
-- License : BSD
--
@ -28,26 +30,27 @@ module XMonad.Actions.SpawnOn (
shellPromptOn
) where
import Data.List (isInfixOf)
import System.Posix.Types (ProcessID)
import XMonad
import XMonad.Prelude
import qualified XMonad.StackSet as W
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
-- > ...
-- > }
--
@ -60,9 +63,9 @@ 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)]} deriving Typeable
newtype Spawner = Spawner {pidsRef :: [(ProcessID, ManageHook)]}
instance ExtensionClass Spawner where
initialValue = Spawner []
@ -72,6 +75,9 @@ instance ExtensionClass Spawner where
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
@ -80,20 +86,20 @@ 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
Spawner pids <- liftX XS.get
mp <- pid
case flip lookup pids =<< mp of
Nothing -> idHook
Just mh -> do
whenJust mp $ \p -> liftX $ do
ps <- XS.gets pidsRef
XS.put . Spawner =<< garbageCollect (filter ((/= p) . fst) ps)
mh
manageSpawnWithGC garbageCollect = pid >>= \case
Nothing -> mempty
Just p -> do
Spawner pids <- liftX XS.get
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
cmds <- io $ getCommands
cmds <- io getCommands
mkXPrompt Shell c (getShellCompl cmds $ searchPredicate c) cb
-- | Replacement for Shell prompt ("XMonad.Prompt.Shell") which launches
@ -114,13 +120,13 @@ spawnHere cmd = withWindowSet $ \ws -> spawnOn (W.currentTag ws) cmd
-- | Replacement for 'spawn' which launches
-- application on given workspace.
spawnOn :: WorkspaceId -> String -> X ()
spawnOn ws cmd = spawnAndDo (doShift ws) cmd
spawnOn ws = spawnAndDo (doShift ws)
-- | Spawn an application and apply the manage hook when it opens.
spawnAndDo :: ManageHook -> String -> X ()
spawnAndDo mh cmd = do
p <- spawnPID $ mangle cmd
modifySpawner $ ((p,mh) :)
modifySpawner ((p,mh) :)
where
-- TODO this is silly, search for a better solution
mangle xs | any (`elem` metaChars) xs || "exec" `isInfixOf` xs = xs

View File

@ -1,6 +1,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.Submap
-- Description : Create a sub-mapping of key bindings.
-- Copyright : (c) Jason Creighton <jcreigh@gmail.com>
-- License : BSD3-style (see LICENSE)
--
@ -16,21 +17,23 @@ module XMonad.Actions.Submap (
-- * Usage
-- $usage
submap,
visualSubmap,
visualSubmapSorted,
submapDefault,
submapDefaultWithKey
submapDefaultWithKey,
-- * Utilities
subName,
) where
import Data.Bits
import Data.Maybe (fromMaybe)
import XMonad hiding (keys)
import qualified Data.Map as M
import Control.Monad.Fix (fix)
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,27 +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
none none currentTime
-----------------------------------------------------------------------
-- 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
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

@ -0,0 +1,404 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.SwapPromote
-- Description : Track the master window history per workspace.
-- Copyright : (c) 2018 Yclept Nemo
-- License : BSD-style (see LICENSE)
--
-- Maintainer :
-- Stability : unstable
-- Portability : unportable
--
-- Module for tracking master window history per workspace, and associated
-- functions for manipulating the stack using such history.
--
-----------------------------------------------------------------------------
module XMonad.Actions.SwapPromote
( -- * Usage
-- $usage
MasterHistory (..)
-- * State Accessors
, getMasterHistoryMap
, getMasterHistoryFromTag
, getMasterHistoryCurrent
, getMasterHistoryFromWindow
, modifyMasterHistoryFromTag
, modifyMasterHistoryCurrent
-- * Log Hook
, masterHistoryHook
-- * Log Hook Building Blocks
, masterHistoryHook'
, updateMasterHistory
-- * Actions
, swapPromote
, swapPromote'
, swapIn
, swapIn'
, swapHybrid
, swapHybrid'
-- * Action Building Blocks
, swapApply
, swapPromoteStack
, swapInStack
, swapHybridStack
-- * List Utilities
, cycleN
, split
, split'
, merge
, merge'
-- * Stack Utilities
, stackSplit
, stackMerge
) where
import XMonad
import XMonad.Prelude
import qualified XMonad.StackSet as W
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
-- Given your configuration file, import this module:
--
-- > import XMonad.Actions.SwapPromote
--
-- First add 'masterHistoryHook' to your 'logHook' to track master windows per
-- workspace:
--
-- > myLogHook = otherHook >> masterHistoryHook
--
-- Then replace xmonad's default promote keybinding with 'swapPromote'':
--
-- > , ((mod1Mask, xK_Return), swapPromote' False)
--
-- Depending on your xmonad configuration or window actions the master history
-- may be empty. If this is the case you can still chain another promotion
-- function:
--
-- > import XMonad.Actions.DwmPromote
-- > , ((mod1Mask, xK_Return), whenX (swapPromote False) dwmpromote)
--
-- To be clear, this is only called when the lack of master history hindered
-- the swap and not other conditions, such as having a only a single window.
--
-- While 'swapPromote' preserves window focus, 'swapIn' preserves the focus
-- position - effectively "swapping" new windows into focus without moving the
-- zipper. A mix of both, 'swapHybrid' promotes focused non-master windows
-- while swapping windows into the focused master. This works well on layouts
-- with large masters. Both come with chainable variants, see 'swapIn'' and
-- 'swapHybrid''.
--
-- 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
-- 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.
--
-- All together:
--
-- > , ((mod1Mask, xK_Return), whenX (swapHybrid True) dwmpromote)
-- | Mapping from workspace tag to master history list. The current master is
-- the head of the list, the previous master the second element, and so on.
-- Without history, the list is empty.
newtype MasterHistory = MasterHistory
{ getMasterHistory :: M.Map WorkspaceId [Window]
} deriving (Read,Show)
instance ExtensionClass MasterHistory where
initialValue = MasterHistory M.empty
-- | Return the master history map from the state.
getMasterHistoryMap :: X (M.Map WorkspaceId [Window])
getMasterHistoryMap = XS.gets getMasterHistory
-- | Return the master history list of a given tag. The master history list may
-- be empty. An invalid tag will also result in an empty list.
getMasterHistoryFromTag :: WorkspaceId -> X [Window]
getMasterHistoryFromTag t = M.findWithDefault [] t <$> getMasterHistoryMap
-- | Return the master history list of the current workspace.
getMasterHistoryCurrent :: X [Window]
getMasterHistoryCurrent = gets (W.currentTag . windowset)
>>= getMasterHistoryFromTag
-- | Return the master history list of the workspace containing the given
-- window. Return an empty list if the window is not in the stackset.
getMasterHistoryFromWindow :: Window -> X [Window]
getMasterHistoryFromWindow w = gets (W.findTag w . windowset)
>>= maybe (return []) getMasterHistoryFromTag
-- | Modify the master history list of a given workspace, or the empty list of
-- no such workspace is mapped. The result is then re-inserted into the master
-- history map.
modifyMasterHistoryFromTag :: WorkspaceId -> ([Window] -> [Window]) -> X ()
modifyMasterHistoryFromTag t f = XS.modify $ \(MasterHistory m) ->
let l = M.findWithDefault [] t m
in MasterHistory $ M.insert t (f l) m
-- | Modify the master history list of the current workspace. While the current
-- workspace is guaranteed to exist; its master history may not. For more
-- information see 'modifyMasterHistoryFromTag'.
modifyMasterHistoryCurrent :: ([Window] -> [Window]) -> X ()
modifyMasterHistoryCurrent f = gets (W.currentTag . windowset)
>>= flip modifyMasterHistoryFromTag f
-- | A 'logHook' to update the master history mapping. Non-existent workspaces
-- are removed, and the master history list for the current workspaces is
-- updated. See 'masterHistoryHook''.
masterHistoryHook :: X ()
masterHistoryHook = masterHistoryHook' True updateMasterHistory
-- | Backend for 'masterHistoryHook'.
masterHistoryHook' :: Bool
-- ^ If @True@, remove non-existent workspaces.
-> ([Window] -> [Window] -> [Window])
-- ^ Function used to update the master history list of
-- the current workspace. First argument is the master
-- history, second is the integrated stack. See
-- 'updateMasterHistory' for more details.
-> X ()
masterHistoryHook' removeWorkspaces historyModifier = do
wset <- gets windowset
let W.Workspace wid _ mst = W.workspace . W.current $ wset
tags = map W.tag $ W.workspaces wset
st = W.integrate' mst
XS.modify $ \(MasterHistory mm) ->
let mm' = if removeWorkspaces
then restrictKeys mm $ S.fromList tags
else mm
ms = M.findWithDefault [] wid mm'
ms' = historyModifier ms st
in MasterHistory $ M.insert wid ms' mm'
-- | Less efficient version of 'M.restrictKeys'. Given broader eventual
-- adoption, replace this with 'M.restrictKeys'.
restrictKeys :: Ord k => M.Map k a -> S.Set k -> M.Map k a
restrictKeys m s = M.filterWithKey (\k _ -> k `S.member` s) m
-- | Given the current master history list and an integrated stack, return the
-- new master history list. The current master is either moved (if it exists
-- within the history) or added to the head of the list, and all missing (i.e.
-- closed) windows are removed.
updateMasterHistory :: [Window] -- ^ The master history list.
-> [Window] -- ^ The integrated stack.
-> [Window]
updateMasterHistory _ [] = []
updateMasterHistory ms ws@(w:_) = (w : delete w ms) `intersect` ws
-- | Wrap 'swapPromoteStack'; see also 'swapApply'.
swapPromote :: Bool -> X Bool
swapPromote = flip swapApply swapPromoteStack
-- | Like 'swapPromote'' but discard the result.
swapPromote' :: Bool -> X ()
swapPromote' = void . swapPromote
-- | Wrap 'swapInStack'; see also 'swapApply'.
swapIn :: Bool -> X Bool
swapIn = flip swapApply swapInStack
-- | Like 'swapIn'' but discard the result.
swapIn' :: Bool -> X ()
swapIn' = void . swapIn
-- | Wrap 'swapHybridStack'; see also 'swapApply'.
swapHybrid :: Bool -> X Bool
swapHybrid = flip swapApply swapHybridStack
-- | Like 'swapHybrid'' but discard the result.
swapHybrid' :: Bool -> X ()
swapHybrid' = void . swapHybrid
-- | Apply the given master history stack modifier to the current stack. If
-- given @True@, all non-focused floating windows will be ignored. Return
-- @True@ if insufficient history; if so use 'whenX' to sequence a backup
-- promotion function.
swapApply :: Bool
-> (Maybe Window -> W.Stack Window -> (Bool,W.Stack Window))
-> X Bool
swapApply ignoreFloats swapFunction = do
fl <- gets $ W.floating . windowset
st <- gets $ W.stack . W.workspace . W.current . windowset
ch <- getMasterHistoryCurrent
let swapApply' s1 =
let fl' = if ignoreFloats then M.keysSet fl else S.empty
ff = (||) <$> (`S.notMember` fl') <*> (== W.focus s1)
fh = filter ff ch
pm = listToMaybe . drop 1 $ fh
(r,s2) = stackSplit s1 fl' :: ([(Int,Window)],W.Stack Window)
(b,s3) = swapFunction pm s2
s4 = stackMerge s3 r
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
-- Any floating master windows will be added to the history when 'windows'
-- calls the log hook.
modifyMasterHistoryCurrent z
windows $ W.modify Nothing . const $ y
return x
-- | If the focused window is the master window and there is no previous
-- master, do nothing. Otherwise swap the master with the previous master. If
-- the focused window is not the master window, swap it with the master window.
-- In either case focus follows the original window, i.e. the focused window
-- does not change, only its position.
--
-- The first argument is the previous master (which may not exist), the second
-- a window stack. Return @True@ if the master history hindered the swap; the
-- history is either empty or out-of-sync. Though the latter shouldn't happen
-- this function never changes the stack under such circumstances.
swapPromoteStack :: Maybe Window -> W.Stack Window -> (Bool,W.Stack Window)
swapPromoteStack _ st@(W.Stack _x [] []) = (False,st)
swapPromoteStack Nothing st@(W.Stack _x [] _r) = (True,st)
swapPromoteStack (Just pm) (W.Stack x [] r) =
let (r',l') = (reverse *** cycleN 1) $ span (/= pm) $ reverse r
st' = W.Stack x l' r'
b = null l'
in (b,st')
swapPromoteStack _ (W.Stack x l r) =
let r' = (++ r) . cycleN 1 . reverse $ l
st' = W.Stack x [] r'
in (False,st')
-- | Perform the same swap as 'swapPromoteStack'. However the new window
-- receives the focus; it appears to "swap into" the position of the original
-- window. Under this model focus follows stack position and the zipper does
-- not move.
--
-- See 'swapPromoteStack' for more details regarding the parameters.
swapInStack :: Maybe Window -> W.Stack Window -> (Bool,W.Stack Window)
swapInStack _ st@(W.Stack _x [] []) = (False,st)
swapInStack Nothing st@(W.Stack _x [] _r) = (True,st)
swapInStack (Just pm) (W.Stack x [] r) =
let (x',r') = case span (/= pm) r of
(__,[]) -> (x,r)
(sl,sr) -> (pm,sl ++ x : drop 1 sr)
st' = W.Stack x' [] r'
b = x' == x
in (b,st')
swapInStack _ (W.Stack x l r) =
let l' = init l ++ [x]
x' = last l
st' = W.Stack x' l' r
in (False,st')
-- | If the focused window is the master window, use 'swapInStack'. Otherwise use
-- 'swapPromoteStack'.
--
-- See 'swapPromoteStack' for more details regarding the parameters.
swapHybridStack :: Maybe Window -> W.Stack Window -> (Bool,W.Stack Window)
swapHybridStack m st@(W.Stack _ [] _) = swapInStack m st
swapHybridStack m st = swapPromoteStack m st
-- | Cycle a list by the given count. If positive, cycle to the left. If
-- negative, cycle to the right:
--
-- >>> cycleN 2 [1,2,3,4,5]
-- [3,4,5,1,2]
-- >>> cycleN (-2) [1,2,3,4,5]
-- [4,5,1,2,3]
cycleN :: Int -> [a] -> [a]
cycleN n ls =
let l = length ls
in take l $ drop (n `mod` l) $ cycle ls
-- | Wrap 'split'' with an initial index of @0@, discarding the list's length.
split :: (Num a, Enum a) => (b -> Bool) -> [b] -> ([(a,b)],[b])
split p l =
let (_,ys,ns) = split' p 0 l
in (ys,ns)
-- | Given a predicate, an initial index and a list, return a tuple containing:
--
-- * List length.
-- * Indexed list of elements which satisfy the predicate. An indexed element
-- is a tuple containing the element index (offset by the initial index) and
-- the element.
-- * List of elements which do not satisfy the predicate.
--
-- The initial index and length of the list simplify chaining calls to this
-- function, such as for zippers of lists.
split' :: (Num a, Enum a) => (b -> Bool) -> a -> [b] -> (a,[(a,b)],[b])
split' p i l =
let accumulate e (c,ys,ns) = if p (snd e)
then (c+1,e:ys,ns)
else (c+1,ys,e:ns)
(c',ys',ns') = foldr accumulate (0,[],[]) $ zip [i..] l
in (c',ys',map snd ns')
-- | Wrap 'merge'' with an initial virtual index of @0@. Return only the
-- unindexed list with elements from the leftover indexed list appended.
merge :: (Ord a, Num a) => [(a,b)] -> [b] -> [b]
merge il ul =
let (_,il',ul') = merge' 0 il ul
in ul' ++ map snd il'
-- | Inverse of 'split'. Merge an indexed list with an unindexed list (see
-- 'split''). Given a virtual index, an indexed list and an unindexed list,
-- return a tuple containing:
--
-- * Virtual index /after/ the unindexed list
-- * Remainder of the indexed list
-- * Merged unindexed list
--
-- If the indexed list is empty, this functions consumes the entire unindexed
-- list. If the unindexed list is empty, this function consumes only adjacent
-- indexed elements. For example, @[(10,"ten"),(12,"twelve")]@ implies missing
-- unindexed elements and so once @(10,"ten")@ is consumed this function
-- concludes.
--
-- The indexed list is assumed to have been created by 'split'' and not checked
-- for correctness. Indices are assumed to be ascending, i.e.
-- > [(1,"one"),(2,"two"),(4,"four")]
--
-- The initial and final virtual indices simplify chaining calls to the this
-- function, as as for zippers of lists. Positive values shift the unindexed
-- list towards the tail, as if preceded by that many elements.
merge' :: (Ord a, Num a) => a -> [(a,b)] -> [b] -> (a,[(a,b)],[b])
merge' i il@((j,a):ps) ul@(b:bs) = if j <= i
then let (x,y,z) = merge' (i+1) ps ul
in (x,y,a:z)
else let (x,y,z) = merge' (i+1) il bs
in (x,y,b:z)
merge' i [] (b:bs) =
let (x,y,z) = merge' (i+1) [] bs
in (x,y,b:z)
merge' i il@((j,a):ps) [] = if j <= i
then let (x,y,z) = merge' (i+1) ps []
in (x,y,a:z)
else (i,il,[])
merge' i [] [] =
(i,[],[])
-- | Remove all elements of the set from the stack. Skip the currently focused
-- member. Return an indexed list of excluded elements and the modified stack.
-- Use 'stackMerge' to re-insert the elements using this list.
stackSplit :: (Num a, Enum a, Ord b) => W.Stack b -> S.Set b -> ([(a,b)],W.Stack b)
stackSplit (W.Stack x l r) s =
let (c,fl,tl) = split' (`S.member` s) 0 (reverse l)
(_,fr,tr) = split' (`S.member` s) (c+1) r
in (fl++fr,W.Stack x (reverse tl) tr)
-- | Inverse of 'stackSplit'. Given a list of elements and their original
-- indices, re-insert the elements into these same positions within the stack.
-- Skip the currently focused member. Works best if the stack's length hasn't
-- changed, though if shorter any leftover elements will be tacked on.
stackMerge :: (Ord a, Num a) => W.Stack b -> [(a,b)] -> W.Stack b
stackMerge (W.Stack x l r) il =
let (i,il1,l') = merge' 0 il (reverse l)
(_,il2,r') = merge' (i+1) il1 r
in W.Stack x (reverse l') (r' ++ map snd il2)

View File

@ -1,6 +1,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.SwapWorkspaces
-- Description : Swap workspace tags without having to move individual windows.
-- Copyright : (c) Devin Mullins <me@twifkak.com>
-- License : BSD3-style (see LICENSE)
--
@ -29,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
--
@ -43,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@.
@ -53,12 +54,13 @@ swapWithCurrent t s = swapWorkspaces t (currentTag s) s
-- | Say @swapTo Next@ or @swapTo Prev@ to move your current workspace.
-- This is an @X ()@ so can be hooked up to your keybindings directly.
swapTo :: Direction1D -> X ()
swapTo dir = findWorkspace getSortByIndex dir AnyWS 1 >>= windows . swapWithCurrent
swapTo dir = findWorkspace getSortByIndex dir anyWS 1 >>= windows . swapWithCurrent
-- | Takes two workspace tags and an existing XMonad.StackSet and returns a new
-- one with the two corresponding workspaces' tags swapped.
swapWorkspaces :: Eq i => i -> i -> StackSet i l a s sd -> StackSet i l a s sd
swapWorkspaces t1 t2 = mapWorkspace swap
where swap w = if tag w == t1 then w { tag = t2 }
else if tag w == t2 then w { tag = t1 }
else w
where swap w
| tag w == t1 = w { tag = t2 }
| tag w == t2 = w { tag = t1 }
| otherwise = w

View File

@ -1,6 +1,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.TagWindows
-- Description : Functions for tagging windows and selecting them by tags.
-- Copyright : (c) Karsten Schoelzel <kuser@gmx.de>
-- License : BSD
--
@ -26,21 +27,19 @@ module XMonad.Actions.TagWindows (
TagPrompt,
) where
import Data.List (nub,sortBy)
import Control.Monad
import Control.Exception as E
import XMonad.StackSet hiding (filter)
import XMonad.Prompt
import XMonad hiding (workspaces)
import XMonad.Prelude
import XMonad.Prompt
import XMonad.StackSet hiding (filter)
econst :: Monad m => a -> IOException -> m a
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
@ -65,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 ()
@ -84,18 +83,17 @@ getTags w = withDisplay $ \d ->
io $ E.catch (internAtom d "_XMONAD_TAGS" False >>=
getTextProperty d w >>=
wcTextPropertyToTextList d)
(econst [[]])
>>= return . words . unwords
(econst [[]]) <&> (words . unwords)
-- | check a window for the given tag
hasTag :: String -> Window -> X Bool
hasTag s w = (s `elem`) `fmap` getTags w
hasTag s w = (s `elem`) <$> getTags w
-- | add a tag to the existing ones
addTag :: String -> Window -> X ()
addTag s w = do
tags <- getTags w
if (s `notElem` tags) then setTags (s:tags) w else return ()
when (s `notElem` tags) $ setTags (s:tags) w
-- | remove a tag from a window, if it exists
delTag :: String -> Window -> X ()
@ -136,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)
@ -158,7 +151,7 @@ withTagged' t m = gets windowset >>= filterM (hasTag t) . index >>= m
withTaggedGlobal' :: String -> ([Window] -> X ()) -> X ()
withTaggedGlobal' t m = gets windowset >>=
filterM (hasTag t) . concat . map (integrate' . stack) . workspaces >>= m
filterM (hasTag t) . concatMap (integrate' . stack) . workspaces >>= m
withFocusedP :: (Window -> WindowSet -> WindowSet) -> X ()
withFocusedP f = withFocused $ windows . f
@ -167,7 +160,7 @@ shiftHere :: (Ord a, Eq s, Eq i) => a -> StackSet i l a s sd -> StackSet i l a s
shiftHere w s = shiftWin (currentTag s) w s
shiftToScreen :: (Ord a, Eq s, Eq i) => s -> a -> StackSet i l a s sd -> StackSet i l a s sd
shiftToScreen sid w s = case filter (\m -> sid /= screen m) ((current s):(visible s)) of
shiftToScreen sid w s = case filter (\m -> sid /= screen m) (current s:visible s) of
[] -> s
(t:_) -> shiftWin (tag . workspace $ t) w s
@ -180,20 +173,19 @@ instance XPrompt TagPrompt where
tagPrompt :: XPConfig -> (String -> X ()) -> X ()
tagPrompt c f = do
sc <- tagComplList
mkXPrompt TagPrompt c (mkComplFunFromList' sc) f
mkXPrompt TagPrompt c (mkComplFunFromList' c sc) f
tagComplList :: X [String]
tagComplList = gets (concat . map (integrate' . stack) . workspaces . windowset) >>=
mapM getTags >>=
return . nub . concat
tagComplList = gets (concatMap (integrate' . stack) . workspaces . windowset)
>>= mapM getTags
<&> nub . concat
tagDelPrompt :: XPConfig -> X ()
tagDelPrompt c = do
sc <- tagDelComplList
if (sc /= [])
then mkXPrompt TagPrompt c (mkComplFunFromList' sc) (\s -> withFocused (delTag s))
else return ()
when (sc /= []) $
mkXPrompt TagPrompt c (mkComplFunFromList' c sc) (withFocused . delTag)
tagDelComplList :: X [String]
tagDelComplList = gets windowset >>= maybe (return []) getTags . peek

View File

@ -0,0 +1,92 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.TiledWindowDragging
-- Description : Change the position of windows by dragging them.
-- Copyright : (c) 2020 Leon Kowarschick
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : Leon Kowarschick. <thereal.elkowar@gmail.com>
-- Stability : unstable
-- Portability : unportable
--
-- Provides an action that allows you to change the position of windows by dragging them around.
--
-----------------------------------------------------------------------------
module XMonad.Actions.TiledWindowDragging
(
-- * Usage
-- $usage
dragWindow
)
where
import XMonad
import XMonad.Prelude
import qualified XMonad.StackSet as W
import XMonad.Layout.DraggingVisualizer
-- $usage
-- You can use this module with the following in your @xmonad.hs@:
--
-- > import XMonad.Actions.TiledWindowDragging
-- > import XMonad.Layout.DraggingVisualizer
--
-- then edit your 'layoutHook' by adding the draggingVisualizer to your layout:
--
-- > myLayout = draggingVisualizer $ layoutHook def
--
-- Then add a mouse binding for 'dragWindow':
--
-- > , ((modMask .|. shiftMask, button1), dragWindow)
--
-- For detailed instructions on editing your mouse bindings, see
-- "XMonad.Doc.Extending#Editing_mouse_bindings".
-- | 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) $ withDisplay $ \dpy ->
withWindowAttributes dpy window $ \wa -> do
focus window
(offsetX, offsetY) <- getPointerOffset window
let (winX, winY, winWidth, winHeight) = getWindowPlacement wa
mouseDrag
(\posX posY ->
let rect = Rectangle (fi (fi winX + (posX - fi offsetX)))
(fi (fi winY + (posY - fi offsetY)))
(fi winWidth)
(fi winHeight)
in sendMessage $ DraggingWindow window rect
)
(sendMessage DraggingStopped >> performWindowSwitching window)
-- | get the pointer offset relative to the given windows root coordinates
getPointerOffset :: Window -> X (Int, Int)
getPointerOffset win = do
(_, _, _, oX, oY, _, _, _) <- withDisplay (\d -> io $ queryPointer d win)
return (fi oX, fi oY)
-- | return a tuple of windowX, windowY, windowWidth, windowHeight
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
root <- asks theRoot
(_, _, selWin, _, _, _, _, _) <- withDisplay (\d -> io $ queryPointer d root)
ws <- gets windowset
let allWindows = W.index ws
when ((win `elem` allWindows) && (selWin `elem` allWindows)) $ do
let allWindowsSwitched = map (switchEntries win selWin) allWindows
(ls, t : rs) <- pure $ break (== win) allWindowsSwitched
let newStack = W.Stack t (reverse ls) rs
windows $ W.modify' $ const newStack
where
switchEntries a b x | x == a = b
| x == b = a
| otherwise = x

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

@ -1,7 +1,8 @@
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE NamedFieldPuns #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.TopicSpace
-- Description : Turns your workspaces into a more topic oriented system.
-- Copyright : (c) Nicolas Pouillard
-- License : BSD-style (see LICENSE)
--
@ -19,21 +20,49 @@ module XMonad.Actions.TopicSpace
-- * Usage
-- $usage
Topic
-- * Types for Building Topics
Topic
, Dir
, TopicConfig(..)
, def
, defaultTopicConfig
, getLastFocusedTopics
, setLastFocusedTopic
, reverseLastFocusedTopics
, pprWindowSet
, TopicItem(..)
-- * Managing 'TopicItem's
, topicNames
, tiActions
, tiDirs
, noAction
, inHome
-- * Switching and Shifting Topics
, switchTopic
, switchNthLastFocused
, switchNthLastFocusedByScreen
, switchNthLastFocusedExclude
, shiftNthLastFocused
-- * Topic Actions
, topicActionWithPrompt
, topicAction
, currentTopicAction
, switchTopic
, switchNthLastFocused
, shiftNthLastFocused
-- * Getting the Topic History
, getLastFocusedTopics
, workspaceHistory
, workspaceHistoryByScreen
-- * Modifying the Topic History
, setLastFocusedTopic
, reverseLastFocusedTopics
-- * History hooks
, workspaceHistoryHook
, workspaceHistoryHookExclude
-- * Pretty Printing
, pprWindowSet
-- * Utility
, currentTopicDir
, checkTopicConfig
, (>*>)
@ -41,25 +70,26 @@ module XMonad.Actions.TopicSpace
where
import XMonad
import XMonad.Prelude
import Data.List
import Data.Maybe (fromMaybe, isNothing, listToMaybe, fromJust)
import Data.Ord
import qualified Data.Map as M
import Control.Monad (liftM2,when,unless,replicateM_)
import System.IO
import qualified Data.Map.Strict as M
import qualified XMonad.Hooks.StatusBar.PP as SBPP
import qualified XMonad.StackSet as W
import qualified XMonad.StackSet as W
import Data.Map (Map)
import XMonad.Prompt
import XMonad.Prompt.Workspace
import XMonad.Prompt (XPConfig)
import XMonad.Prompt.Workspace (workspacePrompt)
import XMonad.Hooks.UrgencyHook
import XMonad.Hooks.DynamicLog (PP(..))
import qualified XMonad.Hooks.DynamicLog as DL
import XMonad.Util.Run (spawnPipe)
import qualified XMonad.Util.ExtensibleState as XS
import XMonad.Hooks.StatusBar.PP (PP(ppHidden, ppVisible))
import XMonad.Hooks.UrgencyHook (readUrgents)
import XMonad.Hooks.WorkspaceHistory
( workspaceHistory
, workspaceHistoryByScreen
, workspaceHistoryHook
, workspaceHistoryHookExclude
, workspaceHistoryModify
)
-- $overview
-- This module allows to organize your workspaces on a precise topic basis. So
@ -73,112 +103,133 @@ import qualified XMonad.Util.ExtensibleState as XS
-- 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
-- Here is an example of configuration using TopicSpace:
-- You can use this module with the following in your @xmonad.hs@:
--
-- > -- The list of all topics/workspaces of your xmonad configuration.
-- > -- The order is important, new topics must be inserted
-- > -- at the end of the list if you want hot-restarting
-- > -- to work.
-- > myTopics :: [Topic]
-- > myTopics =
-- > [ "dashboard" -- the first one
-- > , "admin", "build", "cleaning", "conf", "darcs", "haskell", "irc"
-- > , "mail", "movie", "music", "talk", "text", "tools", "web", "xmonad"
-- > , "yi", "documents", "twitter", "pdf"
-- > ]
-- > import qualified Data.Map.Strict as M
-- > import qualified XMonad.StackSet as W
-- >
-- > import XMonad.Actions.TopicSpace
-- > import XMonad.Util.EZConfig -- for the keybindings
-- > import XMonad.Prompt.Workspace -- if you want to use the prompt
--
-- You will then have to
--
-- * Define a new 'TopicConfig' via 'TopicItem's
--
-- * Add the appropriate keybindings
--
-- * Replace the @workspaces@ field in your 'XConfig' with a list of
-- your topics names
--
-- * Optionally, if you want to use the history features, add
-- 'workspaceHistoryHook' from "XMonad.Hooks.WorkspaceHistory"
-- (re-exported by this module) or an equivalent function to your
-- @logHook@. See the documentation of
-- "XMonad.Hooks.WorkspaceHistory" for further details
--
-- Let us go through a full example together.
--
-- A 'TopicItem' consists of three things: the name of the topic, its
-- root directory, and the action associated to it—to be executed if the
-- topic is empty or the action is forced via a keybinding.
--
-- We start by specifying our chosen topics as a list of such
-- 'TopicItem's:
--
-- > topicItems :: [TopicItem]
-- > topicItems =
-- > [ inHome "1:WEB" (spawn "firefox")
-- > , noAction "2" "."
-- > , noAction "3:VID" "videos"
-- > , TI "4:VPN" "openvpn" (spawn "urxvt -e randomVPN.sh")
-- > , inHome "5:IM" (spawn "signal" *> spawn "telegram")
-- > , inHome "6:IRC" (spawn "urxvt -e weechat")
-- > , TI "dts" ".dotfiles" spawnShell
-- > , TI "xm-con" "hs/xm-con" (spawnShell *> spawnShellIn "hs/xm")
-- > ]
--
-- Then we just need to put together our topic config:
--
-- > myTopicConfig :: TopicConfig
-- > myTopicConfig = def
-- > { topicDirs = M.fromList $
-- > [ ("conf", "w/conf")
-- > , ("dashboard", "Desktop")
-- > , ("yi", "w/dev-haskell/yi")
-- > , ("darcs", "w/dev-haskell/darcs")
-- > , ("haskell", "w/dev-haskell")
-- > , ("xmonad", "w/dev-haskell/xmonad")
-- > , ("tools", "w/tools")
-- > , ("movie", "Movies")
-- > , ("talk", "w/talks")
-- > , ("music", "Music")
-- > , ("documents", "w/documents")
-- > , ("pdf", "w/documents")
-- > ]
-- > , defaultTopicAction = const $ spawnShell >*> 3
-- > , defaultTopic = "dashboard"
-- > , topicActions = M.fromList $
-- > [ ("conf", spawnShell >> spawnShellIn "wd/ertai/private")
-- > , ("darcs", spawnShell >*> 3)
-- > , ("yi", spawnShell >*> 3)
-- > , ("haskell", spawnShell >*> 2 >>
-- > spawnShellIn "wd/dev-haskell/ghc")
-- > , ("xmonad", spawnShellIn "wd/x11-wm/xmonad" >>
-- > spawnShellIn "wd/x11-wm/xmonad/contrib" >>
-- > spawnShellIn "wd/x11-wm/xmonad/utils" >>
-- > spawnShellIn ".xmonad" >>
-- > spawnShellIn ".xmonad")
-- > , ("mail", mailAction)
-- > , ("irc", ssh somewhere)
-- > , ("admin", ssh somewhere >>
-- > ssh nowhere)
-- > , ("dashboard", spawnShell)
-- > , ("twitter", spawnShell)
-- > , ("web", spawn browserCmd)
-- > , ("movie", spawnShell)
-- > , ("documents", spawnShell >*> 2 >>
-- > spawnShellIn "Documents" >*> 2)
-- > , ("pdf", spawn pdfViewerCmd)
-- > ]
-- > { topicDirs = tiDirs topicItems
-- > , topicActions = tiActions topicItems
-- > , defaultTopicAction = const (pure ()) -- by default, do nothing
-- > , defaultTopic = "1:WEB" -- fallback
-- > }
-- >
-- > -- extend your keybindings
-- > myKeys conf@XConfig{modMask=modm} =
-- > [ ((modm , xK_n ), spawnShell) -- %! Launch terminal
-- > , ((modm , xK_a ), currentTopicAction myTopicConfig)
-- > , ((modm , xK_g ), promptedGoto)
-- > , ((modm .|. shiftMask, xK_g ), promptedShift)
-- > {- more keys ... -}
-- > ]
-- > ++
-- > [ ((modm, k), switchNthLastFocused myTopicConfig i)
-- > | (i, k) <- zip [1..] workspaceKeys]
-- >
--
-- Above, we have used the `spawnShell` and `spawnShellIn` helper
-- functions; here they are:
--
-- > spawnShell :: X ()
-- > spawnShell = currentTopicDir myTopicConfig >>= spawnShellIn
-- >
-- > spawnShellIn :: Dir -> X ()
-- > spawnShellIn dir = spawn $ "urxvt '(cd ''" ++ dir ++ "'' && " ++ myShell ++ " )'"
-- >
-- > spawnShellIn dir = spawn $ "alacritty --working-directory " ++ dir
--
-- Next, we define some other other useful helper functions. It is
-- rather common to have a lot of topics—much more than available keys!
-- In a situation like that, it's very convenient to switch topics with
-- a prompt; the following use of 'workspacePrompt' does exactly that.
--
-- > goto :: Topic -> X ()
-- > goto = switchTopic myTopicConfig
-- >
-- > promptedGoto :: X ()
-- > promptedGoto = workspacePrompt myXPConfig goto
-- > promptedGoto = workspacePrompt def goto
-- >
-- > promptedShift :: X ()
-- > promptedShift = workspacePrompt myXPConfig $ windows . W.shift
-- >
-- > myConfig = do
-- > checkTopicConfig myTopics myTopicConfig
-- > myLogHook <- makeMyLogHook
-- > return $ def
-- > { borderWidth = 1 -- Width of the window border in pixels.
-- > , workspaces = myTopics
-- > , layoutHook = myModifiers myLayout
-- > , manageHook = myManageHook
-- > , logHook = myLogHook
-- > , handleEventHook = myHandleEventHook
-- > , terminal = myTerminal -- The preferred terminal program.
-- > , normalBorderColor = "#3f3c6d"
-- > , focusedBorderColor = "#4f66ff"
-- > , XMonad.modMask = mod1Mask
-- > , keys = myKeys
-- > , mouseBindings = myMouseBindings
-- > }
-- > promptedShift = workspacePrompt def $ windows . W.shift
-- >
-- > -- Toggle between the two most recently used topics, but keep
-- > -- screens separate. This needs @workspaceHistoryHook@.
-- > toggleTopic :: X ()
-- > toggleTopic = switchNthLastFocusedByScreen myTopicConfig 1
--
-- Hopefully you've gotten a general feeling of how to define these kind of
-- small helper functions using what's provided in this module.
--
-- Adding the appropriate keybindings works as it normally would. Here,
-- we'll use "XMonad.Util.EZConfig" syntax:
--
-- > myKeys :: [(String, X ())]
-- > myKeys =
-- > [ ("M-n" , spawnShell)
-- > , ("M-a" , currentTopicAction myTopicConfig)
-- > , ("M-g" , promptedGoto)
-- > , ("M-S-g" , promptedShift)
-- > , ("M-S-<Space>", toggleTopic)
-- > ]
-- > ++
-- > -- The following does two things:
-- > -- 1. Switch topics (no modifier)
-- > -- 2. Move focused window to topic N (shift modifier)
-- > [ ("M-" ++ m ++ k, f i)
-- > | (i, k) <- zip (topicNames topicItems) (map show [1 .. 9 :: Int])
-- > , (f, m) <- [(goto, ""), (windows . W.shift, "S-")]
-- > ]
--
-- This makes @M-1@ to @M-9@ switch to the first nine topics that we
-- have specified in @topicItems@.
--
-- You can also switch to the nine last-used topics instead:
--
-- > [ ("M-" ++ show i, switchNthLastFocused myTopicConfig i)
-- > | i <- [1 .. 9]
-- > ]
--
-- We can now put the whole configuration together with the following:
--
-- > main :: IO ()
-- > main = xmonad =<< myConfig
-- > main = xmonad $ def
-- > { workspaces = topicNames topicItems
-- > }
-- > `additionalKeysP` myKeys
-- | An alias for @flip replicateM_@
(>*>) :: Monad m => m a -> Int -> m ()
@ -188,85 +239,79 @@ infix >*>
-- | 'Topic' is just an alias for 'WorkspaceId'
type Topic = WorkspaceId
-- | 'Dir' is just an alias for 'FilePath' but should points to a directory.
-- | 'Dir' is just an alias for 'FilePath', but should point to a directory.
type Dir = FilePath
-- | Here is the topic space configuration area.
data TopicConfig = TopicConfig { topicDirs :: M.Map Topic Dir
-- ^ This mapping associate a directory to each topic.
, topicActions :: M.Map Topic (X ())
-- ^ This mapping associate an action to trigger when
data TopicConfig = TopicConfig { topicDirs :: Map Topic Dir
-- ^ This mapping associates a directory to each topic.
, topicActions :: Map Topic (X ())
-- ^ This mapping associates an action to trigger when
-- switching to a given topic which workspace is empty.
, defaultTopicAction :: Topic -> X ()
-- ^ This is the default topic action.
, defaultTopic :: Topic
-- ^ This is the default topic.
-- ^ This is the default (= fallback) topic.
, maxTopicHistory :: Int
-- ^ This setups the maximum depth of topic history, usually
-- 10 is a good default since we can bind all of them using
-- numeric keypad.
-- ^ This specifies the maximum depth of the topic history;
-- usually 10 is a good default since we can bind all of
-- them using numeric keypad.
}
{-# DEPRECATED maxTopicHistory "This field will be removed in the future; history is now handled by XMonad.Hooks.WorkspaceHistory" #-}
instance Default TopicConfig where
def = TopicConfig { topicDirs = M.empty
, topicActions = M.empty
, defaultTopicAction = const (ask >>= spawn . terminal . config)
, defaultTopic = "1"
, maxTopicHistory = 10
}
def = TopicConfig { topicDirs = M.empty
, topicActions = M.empty
, defaultTopicAction = const (ask >>= spawn . terminal . config)
, defaultTopic = "1"
, maxTopicHistory = 10
}
{-# DEPRECATED defaultTopicConfig "Use def (from Data.Default, and re-exported by XMonad.Actions.TopicSpace) instead." #-}
defaultTopicConfig :: TopicConfig
defaultTopicConfig = def
-- | Return the (possibly empty) list of last focused topics.
getLastFocusedTopics :: X [Topic]
getLastFocusedTopics = workspaceHistory
{-# DEPRECATED getLastFocusedTopics "Use XMonad.Hooks.WorkspaceHistory.workspaceHistory (re-exported by this module) instead" #-}
newtype PrevTopics = PrevTopics { getPrevTopics :: [String] } deriving (Read,Show,Typeable)
instance ExtensionClass PrevTopics where
initialValue = PrevTopics []
extensionType = PersistentExtension
-- | Returns the list of last focused workspaces the empty list otherwise.
getLastFocusedTopics :: X [String]
getLastFocusedTopics = XS.gets getPrevTopics
-- | Given a 'TopicConfig', the last focused topic, and a predicate that will
-- select topics that one want to keep, this function will set the property
-- of last focused topics.
setLastFocusedTopic :: Topic -> (Topic -> Bool) -> X ()
setLastFocusedTopic w predicate =
XS.modify $ PrevTopics
. seqList . nub . (w:) . filter predicate
. getPrevTopics
where seqList xs = length xs `seq` xs
-- | Given a 'TopicConfig', a topic, and a predicate to select topics that one
-- wants to keep, this function will cons the topic in front of the list of
-- last focused topics and filter it according to the predicate. Note that we
-- prune the list in case that its length exceeds 'maxTopicHistory'.
setLastFocusedTopic :: TopicConfig -> Topic -> (Topic -> Bool) -> X ()
setLastFocusedTopic tc w predicate = do
sid <- gets $ W.screen . W.current . windowset
workspaceHistoryModify $
take (maxTopicHistory tc) . nub . filter (predicate . snd) . ((sid, w) :)
{-# DEPRECATED setLastFocusedTopic "Use XMonad.Hooks.WorkspaceHistory instead" #-}
-- | Reverse the list of "last focused topics"
reverseLastFocusedTopics :: X ()
reverseLastFocusedTopics =
XS.modify $ PrevTopics . reverse . getPrevTopics
reverseLastFocusedTopics = workspaceHistoryModify reverse
-- | This function is a variant of 'DL.pprWindowSet' which takes a topic configuration
-- and a pretty-printing record 'PP'. It will show the list of topics sorted historically
-- and highlighting topics with urgent windows.
-- | This function is a variant of 'SBPP.pprWindowSet' which takes a topic
-- configuration and a pretty-printing record 'PP'. It will show the list of
-- topics sorted historically and highlight topics with urgent windows.
pprWindowSet :: TopicConfig -> PP -> X String
pprWindowSet tg pp = do
winset <- gets windowset
urgents <- readUrgents
let empty_workspaces = map W.tag $ filter (isNothing . W.stack) $ W.workspaces winset
maxDepth = maxTopicHistory tg
setLastFocusedTopic (W.tag . W.workspace . W.current $ winset)
(`notElem` empty_workspaces)
lastWs <- getLastFocusedTopics
let depth topic = fromJust $ elemIndex topic (lastWs ++ [topic])
add_depth proj topic = proj pp . (((topic++":")++) . show) . depth $ topic
pp' = pp { ppHidden = add_depth ppHidden, ppVisible = add_depth ppVisible }
sortWindows = take maxDepth . sortBy (comparing $ depth . W.tag)
return $ DL.pprWindowSet sortWindows urgents pp' winset
winset <- gets windowset
urgents <- readUrgents
let empty_workspaces = map W.tag $ filter (isNothing . W.stack) $ W.workspaces winset
maxDepth = maxTopicHistory tg
setLastFocusedTopic tg
(W.tag . W.workspace . W.current $ winset)
(`notElem` empty_workspaces)
lastWs <- workspaceHistory
let depth topic = fromJust $ elemIndex topic (lastWs ++ [topic])
add_depth proj topic = proj pp . (((topic++":")++) . show) . depth $ topic
pp' = pp { ppHidden = add_depth ppHidden, ppVisible = add_depth ppVisible }
sortWindows = take maxDepth . sortOn (depth . W.tag)
return $ SBPP.pprWindowSet sortWindows urgents pp' winset
-- | Given a prompt configuration and a topic configuration, triggers the action associated with
-- | Given a prompt configuration and a topic configuration, trigger the action associated with
-- the topic given in prompt.
topicActionWithPrompt :: XPConfig -> TopicConfig -> X ()
topicActionWithPrompt xp tg = workspacePrompt xp (liftM2 (>>) (switchTopic tg) (topicAction tg))
topicActionWithPrompt xp tg = workspacePrompt xp (liftA2 (>>) (switchTopic tg) (topicAction tg))
-- | Given a configuration and a topic, triggers the action associated with the given topic.
-- | Given a configuration and a topic, trigger the action associated with the given topic.
topicAction :: TopicConfig -> Topic -> X ()
topicAction tg topic = fromMaybe (defaultTopicAction tg topic) $ M.lookup topic $ topicActions tg
@ -276,46 +321,94 @@ currentTopicAction tg = topicAction tg =<< gets (W.tag . W.workspace . W.current
-- | Switch to the given topic.
switchTopic :: TopicConfig -> Topic -> X ()
switchTopic tg topic = do
switchTopic tc topic = do
-- Switch to topic and add it to the last seen topics
windows $ W.greedyView topic
-- If applicable, execute the topic action
wins <- gets (W.integrate' . W.stack . W.workspace . W.current . windowset)
when (null wins) $ topicAction tg topic
when (null wins) $ topicAction tc topic
-- | Switch to the Nth last focused topic or failback to the 'defaultTopic'.
-- | Switch to the Nth last focused topic or fall back to the 'defaultTopic'.
switchNthLastFocused :: TopicConfig -> Int -> X ()
switchNthLastFocused tg depth = do
lastWs <- getLastFocusedTopics
switchTopic tg $ (lastWs ++ repeat (defaultTopic tg)) !! depth
switchNthLastFocused = switchNthLastFocusedExclude []
-- | Shift the focused window to the Nth last focused topic, or fallback to doing nothing.
-- | Like 'switchNthLastFocused', but also filter out certain topics.
switchNthLastFocusedExclude :: [Topic] -> TopicConfig -> Int -> X ()
switchNthLastFocusedExclude excludes tc depth = do
lastWs <- filter (`notElem` excludes) <$> workspaceHistory
switchTopic tc $ (lastWs ++ repeat (defaultTopic tc)) !! depth
-- | Like 'switchNthLastFocused', but only consider topics that used to
-- be on the current screen.
--
-- For example, the following function allows one to toggle between the
-- currently focused and the last used topic, while treating different
-- screens completely independently from one another.
--
-- > toggleTopicScreen = switchNthLastFocusedByScreen myTopicConfig 1
switchNthLastFocusedByScreen :: TopicConfig -> Int -> X ()
switchNthLastFocusedByScreen tc depth = do
sid <- gets $ W.screen . W.current . windowset
sws <- fromMaybe []
. listToMaybe
. map snd
. filter ((== sid) . fst)
<$> workspaceHistoryByScreen
switchTopic tc $ (sws ++ repeat (defaultTopic tc)) !! depth
-- | Shift the focused window to the Nth last focused topic, or fall back to doing nothing.
shiftNthLastFocused :: Int -> X ()
shiftNthLastFocused n = do
ws <- fmap (listToMaybe . drop n) getLastFocusedTopics
ws <- fmap (listToMaybe . drop n) workspaceHistory
whenJust ws $ windows . W.shift
-- | Returns the directory associated with current topic returns the empty string otherwise.
currentTopicDir :: TopicConfig -> X String
-- | Return the directory associated with the current topic, or return the empty
-- string if the topic could not be found.
currentTopicDir :: TopicConfig -> X FilePath
currentTopicDir tg = do
topic <- gets (W.tag . W.workspace . W.current . windowset)
return . fromMaybe "" . M.lookup topic $ topicDirs tg
-- | Check the given topic configuration for duplicates topics or undefined topics.
-- | Check the given topic configuration for duplicate or undefined topics.
checkTopicConfig :: [Topic] -> TopicConfig -> IO ()
checkTopicConfig tags tg = do
-- tags <- gets $ map W.tag . workspaces . windowset
-- tags <- gets $ map W.tag . workspaces . windowset
let
seenTopics = nub $ sort $ M.keys (topicDirs tg) ++ M.keys (topicActions tg)
dups = tags \\ nub tags
diffTopic = seenTopics \\ sort tags
check lst msg = unless (null lst) $ xmessage $ msg ++ " (tags): " ++ show lst
let
seenTopics = nub $ sort $ M.keys (topicDirs tg) ++ M.keys (topicActions tg)
dups = tags \\ nub tags
diffTopic = seenTopics \\ sort tags
check lst msg = unless (null lst) $ xmessage $ msg ++ " (tags): " ++ show lst
check diffTopic "Seen but missing topics/workspaces"
check dups "Duplicate topics/workspaces"
check diffTopic "Seen but missing topics/workspaces"
check dups "Duplicate topics/workspaces"
-- | Display the given message using the @xmessage@ program.
xmessage :: String -> IO ()
xmessage s = do
h <- spawnPipe "xmessage -file -"
hPutStr h s
hClose h
-- | Convenience type for specifying topics.
data TopicItem = TI
{ tiName :: !Topic -- ^ 'Topic' ≡ 'String'
, tiDir :: !Dir -- ^ Directory associated with topic; 'Dir' ≡ 'String'
, tiAction :: !(X ()) -- ^ Startup hook when topic is empty
}
-- | Extract the names from a given list of 'TopicItem's.
topicNames :: [TopicItem] -> [Topic]
topicNames = map tiName
-- | From a list of 'TopicItem's, build a map that can be supplied as
-- the 'topicDirs'.
tiDirs :: [TopicItem] -> Map Topic Dir
tiDirs = M.fromList . map (\TI{ tiName, tiDir } -> (tiName, tiDir))
-- | From a list of 'TopicItem's, build a map that can be supplied as
-- the 'topicActions'.
tiActions :: [TopicItem] -> Map Topic (X ())
tiActions = M.fromList . map (\TI{ tiName, tiAction } -> (tiName, tiAction))
-- | Associate a directory with the topic, but don't spawn anything.
noAction :: Topic -> Dir -> TopicItem
noAction n d = TI n d (pure ())
-- | Topic with @tiDir = ~/@.
inHome :: Topic -> X () -> TopicItem
inHome n = TI n "."

View File

@ -1,9 +1,12 @@
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE LambdaCase #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.TreeSelect
-- Description : Display workspaces or actions in a tree-like format.
-- Copyright : (c) Tom Smeets <tom.tsmeets@gmail.com>
-- License : BSD3-style (see LICENSE)
--
@ -39,6 +42,7 @@ module XMonad.Actions.TreeSelect
, TSConfig(..)
, tsDefaultConfig
, def
-- * Navigation
-- $navigation
@ -60,16 +64,13 @@ module XMonad.Actions.TreeSelect
, treeselectAt
) where
import Control.Applicative
import Control.Monad.Reader
import Control.Monad.State
import Data.List (find)
import Data.Maybe
import Data.Tree
import Foreign
import Foreign (shiftL, shiftR, (.&.))
import System.IO
import System.Posix.Process (forkProcess, executeFile)
import XMonad hiding (liftX)
import XMonad.Prelude
import XMonad.StackSet as W
import XMonad.Util.Font
import XMonad.Util.NamedWindows
@ -78,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
@ -113,10 +115,10 @@ import Graphics.X11.Xrender
--
-- Optionally, if you add 'workspaceHistoryHook' to your 'logHook' you can use the \'o\' and \'i\' keys to select from previously-visited workspaces
--
-- > xmonad $ defaultConfig { ...
-- > , workspaces = toWorkspaces myWorkspaces
-- > , logHook = workspaceHistoryHook
-- > }
-- > xmonad $ def { ...
-- > , workspaces = toWorkspaces myWorkspaces
-- > , logHook = workspaceHistoryHook
-- > }
--
-- After that you still need to bind buttons to 'treeselectWorkspace' to start selecting a workspaces and moving windows
--
@ -131,22 +133,22 @@ import Graphics.X11.Xrender
-- $config
-- The selection menu is very configurable, you can change the font, all colors and the sizes of the boxes.
--
-- The default config defined as 'tsDefaultConfig'
-- The default config defined as 'def'
--
-- > tsDefaultConfig = TSConfig { ts_hidechildren = True
-- > , ts_background = 0xc0c0c0c0
-- > , ts_font = "xft:Sans-16"
-- > , ts_node = (0xff000000, 0xff50d0db)
-- > , ts_nodealt = (0xff000000, 0xff10b8d6)
-- > , ts_highlight = (0xffffffff, 0xffff0000)
-- > , ts_extra = 0xff000000
-- > , ts_node_width = 200
-- > , ts_node_height = 30
-- > , ts_originX = 0
-- > , ts_originY = 0
-- > , ts_indent = 80
-- > , ts_navigate = defaultNavigation
-- > }
-- > def = TSConfig { ts_hidechildren = True
-- > , ts_background = 0xc0c0c0c0
-- > , ts_font = "xft:Sans-16"
-- > , ts_node = (0xff000000, 0xff50d0db)
-- > , ts_nodealt = (0xff000000, 0xff10b8d6)
-- > , ts_highlight = (0xffffffff, 0xffff0000)
-- > , ts_extra = 0xff000000
-- > , ts_node_width = 200
-- > , ts_node_height = 30
-- > , ts_originX = 0
-- > , ts_originY = 0
-- > , ts_indent = 80
-- > , ts_navigate = defaultNavigation
-- > }
-- $pixel
--
@ -160,8 +162,8 @@ import Graphics.X11.Xrender
-- white = 0xffffffff
-- black = 0xff000000
-- red = 0xffff0000
-- blue = 0xff00ff00
-- green = 0xff0000ff
-- green = 0xff00ff00
-- blue = 0xff0000ff
-- transparent = 0x00000000
-- @
@ -258,6 +260,7 @@ defaultNavigation = M.fromList
-- Using nice alternating blue nodes
tsDefaultConfig :: TSConfig a
tsDefaultConfig = def
{-# DEPRECATED tsDefaultConfig "Use def (from Data.Default, and re-exported by XMonad.Actions.TreeSelect) instead." #-}
-- | Tree Node With a name and extra text
data TSNode a = TSNode { tsn_name :: String
@ -316,7 +319,9 @@ treeselectAt conf@TSConfig{..} zipper hist = withDisplay $ \display -> do
set_colormap attributes colormap
set_background_pixel attributes ts_background
set_border_pixel attributes 0
createWindow display rootw rect_x rect_y rect_width rect_height 0 (visualInfo_depth vinfo) inputOutput (visualInfo_visual vinfo) (cWColormap .|. cWBorderPixel .|. cWBackPixel) attributes
w <- createWindow display rootw rect_x rect_y rect_width rect_height 0 (visualInfo_depth vinfo) inputOutput (visualInfo_visual vinfo) (cWColormap .|. cWBorderPixel .|. cWBackPixel) attributes
setClassHint display w (ClassHint "xmonad-tree_select" "xmonad")
pure w
liftIO $ do
-- TODO: move below?
@ -405,7 +410,7 @@ treeselectWorkspace c xs f = do
, "XConfig.workspaces: "
] ++ map tag ws
hPutStrLn stderr msg
_ <- forkProcess $ executeFile "xmessage" True [msg] Nothing
xmessage msg
return ()
where
mkNode n w = do
@ -448,8 +453,8 @@ splitPath i = case break (== '.') i of
-- > ]
-- > ]
treeselectAction :: TSConfig (X a) -> Forest (TSNode (X a)) -> X ()
treeselectAction c xs = treeselect c xs >>= \x -> case x of
Just a -> a >> return ()
treeselectAction c xs = treeselect c xs >>= \case
Just a -> void a
Nothing -> return ()
forMForest :: (Functor m, Applicative m, Monad m) => [Tree a] -> (a -> m b) -> m [Tree b]
@ -461,7 +466,7 @@ mapMTree f (Node x xs) = Node <$> f x <*> mapM (mapMTree f) xs
-- | Quit returning the currently selected node
select :: TreeSelect a (Maybe a)
select = Just <$> gets (tsn_value . cursor . tss_tree)
select = gets (Just . (tsn_value . cursor . tss_tree))
-- | Quit without returning anything
cancel :: TreeSelect a (Maybe a)
@ -523,18 +528,21 @@ moveWith f = do
-- | wait for keys and run navigation
navigate :: TreeSelect a (Maybe a)
navigate = gets tss_display >>= \d -> join . liftIO . allocaXEvent $ \e -> do
maskEvent d (exposureMask .|. keyPressMask .|. buttonReleaseMask) e
maskEvent d (exposureMask .|. keyPressMask .|. buttonReleaseMask .|. buttonPressMask) e
ev <- getEvent e
if ev_event_type ev == keyPress
then do
(ks, _) <- lookupString $ asKeyEvent e
return $ do
mask <- liftX $ cleanMask (ev_state ev)
f <- asks ts_navigate
fromMaybe navigate $ M.lookup (mask, fromMaybe xK_VoidSymbol ks) f
else return navigate
if | ev_event_type ev == keyPress -> do
ks <- keycodeToKeysym d (ev_keycode ev) 0
return $ do
mask <- liftX $ cleanKeyMask <*> pure (ev_state ev)
f <- asks ts_navigate
fromMaybe navigate $ M.lookup (mask, ks) f
| ev_event_type ev == buttonPress -> do
-- See XMonad.Prompt Note [Allow ButtonEvents]
allowEvents d replayPointer currentTime
return navigate
| otherwise -> return navigate
-- | Request a full redraw
redraw :: TreeSelect a ()
@ -599,7 +607,7 @@ drawNode ix iy TSNode{..} col = do
colormap <- gets tss_colormap
visual <- gets tss_visual
liftIO $ drawWinBox window display visual colormap gc font col tsn_name ts_extra tsn_extra
(ix * ts_indent) (iy * ts_node_height)
(ix * ts_indent + ts_originX) (iy * ts_node_height + ts_originY)
ts_node_width ts_node_height
-- TODO: draw extra text (transparent background? or ts_background)
@ -641,17 +649,29 @@ 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'
--
-- Note that it uses short to represent its components
fromARGB :: Pixel -> XRenderColor
fromARGB x = XRenderColor (fromIntegral $ 0xff00 .&. shiftR x 8) -- red
(fromIntegral $ 0xff00 .&. x) -- green
(fromIntegral $ 0xff00 .&. shiftL x 8) -- blue
(fromIntegral $ 0xff00 .&. shiftR x 16) -- alpha
fromARGB x =
#if MIN_VERSION_X11_xft(0, 3, 3)
XRenderColor r g b a
#else
-- swapped green/blue as a workaround for the faulty Storable instance in X11-xft < 0.3.3
XRenderColor r b g a
#endif
where
r = fromIntegral $ 0xff00 .&. shiftR x 8
g = fromIntegral $ 0xff00 .&. x
b = fromIntegral $ 0xff00 .&. shiftL x 8
a = fromIntegral $ 0xff00 .&. shiftR x 16
#endif

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

@ -1,6 +1,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.UpdateFocus
-- Description : Updates the focus on mouse move in unfocused windows.
-- Copyright : (c) Daniel Schoepe
-- License : BSD3-style (see LICENSE)
--
@ -16,17 +17,17 @@ module XMonad.Actions.UpdateFocus (
-- * Usage
-- $usage
focusOnMouseMove,
adjustEventInput
adjustEventInput,
focusUnderPointer,
) where
import XMonad
import XMonad.Prelude
import qualified XMonad.StackSet as W
import Control.Monad (when)
import Data.Monoid
-- $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 {
@ -40,7 +41,7 @@ import Data.Monoid
-- | Changes the focus if the mouse is moved within an unfocused window.
focusOnMouseMove :: Event -> X All
focusOnMouseMove (MotionEvent { ev_x = x, ev_y = y, ev_window = root }) = do
focusOnMouseMove MotionEvent{ ev_x = x, ev_y = y, ev_window = root } = do
-- check only every 15 px to avoid excessive calls to translateCoordinates
when (x `mod` 15 == 0 || y `mod` 15 == 0) $ do
dpy <- asks display
@ -58,3 +59,25 @@ adjustEventInput = withDisplay $ \dpy -> do
io $ selectInput dpy rootw $ substructureRedirectMask .|. substructureNotifyMask
.|. enterWindowMask .|. leaveWindowMask .|. structureNotifyMask
.|. buttonPressMask .|. pointerMotionMask
-- | Focus the window under the mouse pointer, unless we're currently changing
-- focus with the mouse or dragging. This is the inverse to
-- "XMonad.Actions.UpdatePointer": instead of moving the mouse pointer to
-- match the focus, we change the focus to match the mouse pointer.
--
-- This is meant to be used together with
-- 'XMonad.Actions.UpdatePointer.updatePointer' in individual key bindings.
-- Bindings that change focus should invoke
-- 'XMonad.Actions.UpdatePointer.updatePointer' at the end, bindings that
-- switch workspaces or change layouts should call 'focusUnderPointer' at the
-- end. Neither should go to 'logHook', as that would override the other.
--
-- This is more finicky to set up than 'focusOnMouseMove', but ensures that
-- focus is updated immediately, without having to touch the mouse.
focusUnderPointer :: X ()
focusUnderPointer = whenX (not <$> (asks mouseFocused <||> gets (isJust . dragging))) $ do
dpy <- asks display
root <- asks theRoot
(_, _, w', _, _, _, _, _) <- io $ queryPointer dpy root
w <- gets (W.peek . windowset)
when (w' /= none && Just w' /= w) (focus w')

View File

@ -2,6 +2,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonadContrib.UpdatePointer
-- Description : Causes the pointer to follow whichever window focus changes to.
-- Copyright : (c) Robert Marlow <robreim@bobturf.org>, 2015 Evgeny Kurnevsky
-- License : BSD3-style (see LICENSE)
--
@ -24,15 +25,13 @@ module XMonad.Actions.UpdatePointer
where
import XMonad
import XMonad.Util.XUtils (fi)
import Control.Arrow
import Control.Monad
import XMonad.Prelude
import XMonad.StackSet (member, peek, screenDetail, current)
import Data.Maybe
import Control.Exception
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
@ -61,6 +60,11 @@ import Control.Exception
-- | Update the pointer's location to the currently focused
-- window or empty screen unless it's already there, or unless the user was changing
-- focus with the mouse
--
-- See also 'XMonad.Actions.UpdateFocus.focusUnderPointer' for an inverse
-- operation that updates the focus instead. The two can be combined in a
-- single config if neither goes into 'logHook' but are invoked explicitly in
-- individual key bindings.
updatePointer :: (Rational, Rational) -> (Rational, Rational) -> X ()
updatePointer refPos ratio = do
ws <- gets windowset
@ -68,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
@ -105,6 +108,7 @@ lerp :: (RealFrac r, Real a, Real b) => r -> a -> b -> r
lerp r a b = (1 - r) * realToFrac a + r * realToFrac b
clip :: Ord a => (a, a) -> a -> a
clip (lower, upper) x = if x < lower then lower
else if x > upper then upper else x
clip (lower, upper) x
| x < lower = lower
| x > upper = upper
| otherwise = x

View File

@ -1,6 +1,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.Warp
-- Description : Warp the pointer to a given window or screen.
-- Copyright : (c) daniel@wagner-home.com
-- License : BSD3-style (see LICENSE)
--
@ -22,12 +23,12 @@ module XMonad.Actions.Warp (
warpToWindow
) where
import Data.List
import XMonad.Prelude
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
@ -44,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
@ -90,18 +91,16 @@ 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
warp w (fraction h (wa_width wa)) (fraction v (wa_height wa))
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
-- right = (1,1)) on the given screen.
warpToScreen :: ScreenId -> Rational -> Rational -> X ()
warpToScreen n h v = do
root <- asks theRoot
(StackSet {current = x, visible = xs}) <- gets windowset
StackSet{current = x, visible = xs} <- gets windowset
whenJust (fmap (screenRect . W.screenDetail) . find ((n==) . W.screen) $ x : xs)
$ \r ->
warp root (rect_x r + fraction h (rect_width r))

View File

@ -2,6 +2,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.WindowBringer
-- Description : Dmenu operations to bring windows to you, and bring you to windows.
-- Copyright : Devin Mullins <me@twifkak.com>
-- License : BSD-style (see LICENSE)
--
@ -21,21 +22,23 @@ module XMonad.Actions.WindowBringer (
WindowBringerConfig(..),
gotoMenu, gotoMenuConfig, gotoMenu', gotoMenuArgs, gotoMenuArgs',
bringMenu, bringMenuConfig, bringMenu', bringMenuArgs, bringMenuArgs',
windowMap, windowMap', bringWindow, actionMenu
copyMenu, copyMenuConfig, copyMenu', copyMenuArgs, copyMenuArgs',
windowMap, windowAppMap, windowMap', bringWindow, actionMenu
) where
import Control.Applicative((<$>))
import Control.Monad
import qualified Data.Map as M
import qualified XMonad.StackSet as W
import XMonad
import qualified XMonad as X
import XMonad.Util.Dmenu (menuMapArgs)
import XMonad.Util.NamedWindows (getName)
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
--
@ -43,20 +46,23 @@ import XMonad.Util.NamedWindows (getName)
--
-- > , ((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
, menuArgs :: [String] -- ^ Arguments to be passed to menuCommand
, windowTitler :: X.WindowSpace -> Window -> X String -- ^ A function that produces window titles given a workspace and a window
, windowFilter :: Window -> X Bool -- ^ Filter function to decide which windows to consider
}
instance Default WindowBringerConfig where
def = WindowBringerConfig{ menuCommand = "dmenu"
, menuArgs = ["-i"]
, windowTitler = decorateName
, windowFilter = \_ -> return True
}
-- | Pops open a dmenu with window titles. Choose one, and you will be
@ -87,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 ()
@ -123,11 +160,8 @@ bringWindow w ws = W.shiftWin (W.currentTag ws) w ws
-- | Calls dmenuMap to grab the appropriate Window, and hands it off to action
-- if found.
actionMenu :: WindowBringerConfig -> (Window -> X.WindowSet -> X.WindowSet) -> X ()
actionMenu WindowBringerConfig{ menuCommand = cmd
, menuArgs = args
, windowTitler = titler
} action
= windowMap' titler >>= menuMapFunction >>= flip X.whenJust (windows . action)
actionMenu c@WindowBringerConfig{ menuCommand = cmd, menuArgs = args } action =
windowMap' c >>= menuMapFunction >>= flip X.whenJust (windows . action)
where
menuMapFunction :: M.Map String a -> X (Maybe a)
menuMapFunction = menuMapArgs cmd args
@ -135,15 +169,20 @@ actionMenu WindowBringerConfig{ menuCommand = cmd
-- | A map from window names to Windows.
windowMap :: X (M.Map String Window)
windowMap = windowMap' decorateName
windowMap = windowMap' def
-- | A map from application executable names to Windows.
windowAppMap :: X (M.Map String Window)
windowAppMap = windowMap' def { windowTitler = decorateAppName }
-- | A map from window names to Windows, given a windowTitler function.
windowMap' :: (X.WindowSpace -> Window -> X String) -> X (M.Map String Window)
windowMap' titler = do
ws <- gets X.windowset
M.fromList . concat <$> mapM keyValuePairs (W.workspaces ws)
where keyValuePairs ws = mapM (keyValuePair ws) $ W.integrate' (W.stack ws)
keyValuePair ws w = flip (,) w <$> titler ws w
windowMap' :: WindowBringerConfig -> X (M.Map String Window)
windowMap' WindowBringerConfig{ windowTitler = titler, windowFilter = include } = do
windowSet <- gets X.windowset
M.fromList . concat <$> mapM keyValuePairs (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
-- | Returns the window name as will be listed in dmenu.
-- Tagged with the workspace ID, to guarantee uniqueness, and to let the user
@ -152,3 +191,11 @@ decorateName :: X.WindowSpace -> Window -> X String
decorateName ws w = do
name <- show <$> getName w
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 its workspace
-- ID.
decorateAppName :: X.WindowSpace -> Window -> X String
decorateAppName ws w = do
name <- show <$> getNameWMClass w
return $ name ++ " [" ++ W.tag ws ++ "]"

View File

@ -1,5 +1,8 @@
{-# LANGUAGE ViewPatterns #-}
{- |
Module : XMonad.Actions.WindowGo
Description : Operations for raising (traveling to) windows.
License : Public domain
Maintainer : <gwern0@gmail.com>
@ -36,10 +39,8 @@ module XMonad.Actions.WindowGo (
module XMonad.ManageHook
) where
import Control.Monad
import Data.Char (toLower)
import qualified Data.List as L (nub,sortBy)
import Data.Monoid
import XMonad.Prelude
import XMonad (Query(), X(), ManageHook, WindowSet, withWindowSet, runQuery, liftIO, ask)
import Graphics.X11 (Window)
import XMonad.ManageHook
@ -47,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
@ -65,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]
@ -88,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.
@ -159,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
in windows $ focusFn y
_ -> windows . focusFn . head $ ws
Just w | w `elem` ws ->
let (notEmpty -> _ :| (notEmpty -> y :| _)) = dropWhile (/=w) $ cycle ws
-- cannot fail to match
in windows $ focusFn y
_ -> 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

@ -1,6 +1,7 @@
----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.WindowMenu
-- Description : Display window management actions in the center of the focused window.
-- Copyright : (c) Jan Vornberger 2009
-- License : BSD3-style (see LICENSE)
--
@ -28,12 +29,12 @@ import XMonad
import qualified XMonad.StackSet as W
import XMonad.Actions.GridSelect
import XMonad.Layout.Maximize
import XMonad.Layout.Minimize
import XMonad.Util.XUtils (fi)
import XMonad.Actions.Minimize
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
--
@ -50,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
@ -68,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,9 +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
@ -36,21 +39,20 @@ module XMonad.Actions.WindowNavigation (
withWindowNavigationKeys,
WNAction(..),
go, swap,
goPure, swapPure,
Direction2D(..), WNState,
) where
import XMonad
import XMonad hiding (state)
import XMonad.Prelude (catMaybes, fromMaybe, sortOn)
import XMonad.Util.Types (Direction2D(..))
import qualified XMonad.StackSet as W
import Control.Applicative ((<$>))
import Control.Arrow (second)
import Data.IORef
import Data.List (sortBy)
import Data.Map (Map())
import Data.List (partition, find)
import qualified Data.Map as M
import Data.Maybe (catMaybes, fromMaybe, listToMaybe)
import Data.Ord (comparing)
import qualified Data.Set as S
-- $usage
@ -65,6 +67,11 @@ import qualified Data.Set as S
-- > $ def { ... }
-- > xmonad config
--
-- Or, for the brave souls:
--
-- > main = xmonad =<< withWindowNavigation (xK_w, xK_a, xK_s, xK_d)
-- > $ def { ... }
--
-- Here, we pass in the keys for navigation in counter-clockwise order from up.
-- It creates keybindings for @modMask@ to move to window, and @modMask .|. shiftMask@
-- to swap windows.
@ -98,118 +105,316 @@ 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 ws@(W.Workspace { W.stack = s }) = ws { W.stack = mapWindows'' f <$> s }
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 = if win == win1 then win2 else if win == win2 then win1 else win
swapWin win1 win2 win
| win == win1 = win2
| 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 -> do
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 -> do
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
then pos
else midPoint lower 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 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 = sortBy $ comparing (rect_y . snd)
sortby R = sortBy $ comparing (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

@ -1,28 +1,30 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.WithAll
-- Description : Perform a given action on all or certain groups of windows.
-- License : BSD3-style (see LICENSE)
-- Stability : unstable
-- Portability : unportable
--
-- Provides functions for performing a given action on all windows of
-- the current workspace.
-- Provides functions for performing a given action on all or certain
-- groups of windows on the current workspace.
-----------------------------------------------------------------------------
module XMonad.Actions.WithAll (
-- * Usage
-- $usage
sinkAll, withAll,
withAll', killAll) where
withAll', killAll,
killOthers) where
import Data.Foldable hiding (foldr)
import XMonad.Prelude hiding (foldr)
import XMonad
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
--
@ -31,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 ()
@ -49,4 +51,8 @@ withAll f = withWindowSet $ \ws -> let all' = integrate' . stack . workspace . c
-- | Kill all the windows on the current workspace.
killAll :: X()
killAll = withAll killWindow
killAll = withAll killWindow
-- | Kill all the unfocused windows on the current workspace.
killOthers :: X ()
killOthers = withUnfocused killWindow

View File

@ -1,6 +1,9 @@
{-# LANGUAGE ViewPatterns #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.Workscreen
-- Description: Display a set of workspaces on several screens.
-- Copyright : (c) 2012 kedals0
-- License : BSD3-style (see LICENSE)
--
@ -20,7 +23,6 @@
-- This also permits to see all workspaces of a workscreen even if just
-- one screen is present, and to move windows from workspace to workscreen.
-----------------------------------------------------------------------------
{-# LANGUAGE DeriveDataTypeable #-}
module XMonad.Actions.Workscreen (
-- * Usage
@ -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,26 +58,26 @@ 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,Typeable)
data Workscreen = Workscreen{workscreenId::Int,workspaces::[WorkspaceId]} deriving (Show)
type WorkscreenId=Int
data WorkscreenStorage = WorkscreenStorage WorkscreenId [Workscreen] deriving (Show,Typeable)
data WorkscreenStorage = WorkscreenStorage WorkscreenId [Workscreen] deriving (Show)
instance ExtensionClass WorkscreenStorage where
initialValue = WorkscreenStorage 0 []
-- | Helper to group workspaces. Multiply workspace by screens number.
expandWorkspace :: Int -> [WorkspaceId] -> [WorkspaceId]
expandWorkspace nscr ws = concat $ map expandId ws
expandWorkspace nscr = concatMap expandId
where expandId wsId = let t = wsId ++ "_"
in map ((++) t . show ) [1..nscr]
-- | Create workscreen list from workspace list. Group workspaces to
-- packets of screens number size.
fromWorkspace :: Int -> [WorkspaceId] -> [Workscreen]
fromWorkspace n ws = map (\(a,b) -> Workscreen a b) $ zip [0..] (fromWorkspace' n ws)
fromWorkspace n ws = zipWith Workscreen [0..] (fromWorkspace' n ws)
fromWorkspace' :: Int -> [WorkspaceId] -> [[WorkspaceId]]
fromWorkspace' _ [] = []
fromWorkspace' n ws = take n ws : fromWorkspace' n (drop n ws)
@ -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

@ -1,7 +1,8 @@
{-# LANGUAGE DeriveDataTypeable, FlexibleInstances, MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.WorkspaceCursors
-- Description : Like "XMonad.Actions.Plane" for an arbitrary number of dimensions.
-- Copyright : (c) 2009 Adam Vogt <vogt.adam@gmail.com>
-- License : BSD
--
@ -46,14 +47,10 @@ import qualified XMonad.StackSet as W
import XMonad.Actions.FocusNth(focusNth')
import XMonad.Layout.LayoutModifier(ModifiedLayout(..),
LayoutModifier(handleMess, redoLayout))
import XMonad(Typeable, Message, WorkspaceId, X, XState(windowset),
import XMonad(Message, WorkspaceId, X, XState(windowset),
fromMessage, sendMessage, windows, gets)
import Control.Monad((<=<), guard, liftM, liftM2, when)
import Control.Applicative((<$>))
import Data.Foldable(Foldable(foldMap), toList)
import Data.Maybe(fromJust, listToMaybe)
import Data.Monoid(Monoid(mappend, mconcat))
import Data.Traversable(sequenceA)
import XMonad.Util.Stack (reverseS)
import XMonad.Prelude
-- $usage
--
@ -61,13 +58,10 @@ import Data.Traversable(sequenceA)
--
-- > import XMonad
-- > import XMonad.Actions.WorkspaceCursors
-- > import XMonad.Hooks.DynamicLog
-- > import XMonad.Util.EZConfig
-- > import qualified XMonad.StackSet as W
-- >
-- > main = do
-- > x <- xmobar conf
-- > xmonad x
-- > main = xmonad conf
-- >
-- > conf = additionalKeysP def
-- > { layoutHook = workspaceCursors myCursors $ layoutHook def
@ -92,7 +86,8 @@ import Data.Traversable(sequenceA)
-- workspaces. Or change it such that workspaces are created when you try to
-- view it.
--
-- * Function for pretty printing for DynamicLog that groups workspaces by
-- * Function for pretty printing for "XMonad.Hooks.StatusBar.PP" that groups
-- workspaces by
-- common prefixes
--
-- * Examples of adding workspaces to the cursors, having them appear multiple
@ -100,10 +95,10 @@ import Data.Traversable(sequenceA)
-- | 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 [] = error "Workspace Cursors cannot be empty"
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
@ -118,7 +113,7 @@ end = Cons . fromJust . W.differentiate . map End
data Cursors a
= Cons (W.Stack (Cursors a))
| End a deriving (Eq,Show,Read,Typeable)
| End a deriving (Eq,Show,Read)
instance Foldable Cursors where
foldMap f (End x) = f x
@ -144,7 +139,7 @@ getFocus (End x) = x
-- This could be made more efficient, if the fact that the suffixes are grouped
focusTo :: (Eq t) => t -> Cursors t -> Maybe (Cursors t)
focusTo x = listToMaybe . filter ((x==) . getFocus) . changeFocus (const True)
focusTo x = find ((x==) . getFocus) . changeFocus (const True)
-- | non-wrapping version of 'W.focusUp''
noWrapUp :: W.Stack t -> W.Stack t
@ -153,20 +148,19 @@ noWrapUp x@(W.Stack _ [] _ ) = x
-- | non-wrapping version of 'W.focusDown''
noWrapDown :: W.Stack t -> W.Stack t
noWrapDown = reverseStack . noWrapUp . reverseStack
where reverseStack (W.Stack t ls rs) = W.Stack t rs ls
noWrapDown = reverseS . noWrapUp . reverseS
focusDepth :: Cursors t -> Int
focusDepth (Cons x) = 1 + focusDepth (W.focus x)
focusDepth (End _) = 0
descend :: Monad m =>(W.Stack (Cursors a) -> m (W.Stack (Cursors a)))-> Int-> Cursors a-> m (Cursors a)
descend f 1 (Cons x) = Cons `liftM` f x
descend f n (Cons x) | n > 1 = liftM Cons $ descend f (pred n) `onFocus` x
descend f 1 (Cons x) = Cons <$> f x
descend f n (Cons x) | n > 1 = fmap Cons $ descend f (pred n) `onFocus` x
descend _ _ x = return x
onFocus :: (Monad m) => (a1 -> m a1) -> W.Stack a1 -> m (W.Stack a1)
onFocus f st = (\x -> st { W.focus = x}) `liftM` f (W.focus st)
onFocus f st = (\x -> st { W.focus = x}) <$> f (W.focus st)
-- | @modifyLayer@ is used to change the focus at a given depth
modifyLayer :: (W.Stack (Cursors String) -> W.Stack (Cursors String)) -> Int -> X ()
@ -192,10 +186,10 @@ modifyLayer' :: (W.Stack (Cursors String) -> X (W.Stack (Cursors String))) -> In
modifyLayer' f depth = modifyCursors (descend f depth)
modifyCursors :: (Cursors String -> X (Cursors String)) -> X ()
modifyCursors = sendMessage . ChangeCursors . (liftM2 (>>) updateXMD return <=<)
modifyCursors = sendMessage . ChangeCursors . (liftA2 (>>) updateXMD return <=<)
data WorkspaceCursors a = WorkspaceCursors (Cursors String)
deriving (Typeable,Read,Show)
newtype WorkspaceCursors a = WorkspaceCursors (Cursors String)
deriving (Read,Show)
-- | The state is stored in the 'WorkspaceCursors' layout modifier. Put this as
-- your outermost modifier, unless you want different cursors at different
@ -203,8 +197,7 @@ data WorkspaceCursors a = WorkspaceCursors (Cursors String)
workspaceCursors :: Cursors String -> l a -> ModifiedLayout WorkspaceCursors l a
workspaceCursors = ModifiedLayout . WorkspaceCursors
data ChangeCursors = ChangeCursors { unWrap :: Cursors String -> X (Cursors String) }
deriving (Typeable)
newtype ChangeCursors = ChangeCursors { unWrap :: Cursors String -> X (Cursors String) }
instance Message ChangeCursors
@ -219,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

@ -1,6 +1,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.WorkspaceNames
-- Description : Persistently rename workspace and swap them along with their names.
-- Copyright : (c) Tomas Janousek <tomi@nomi.cz>
-- License : BSD3-style (see LICENSE)
--
@ -8,22 +9,19 @@
-- Stability : experimental
-- Portability : unportable
--
-- Provides bindings to rename workspaces, show these names in DynamicLog and
-- Provides bindings to rename workspaces, show these names in a status bar and
-- swap workspaces along with their names. These names survive restart.
-- Together with "XMonad.Layout.WorkspaceDir" this provides for a fully
-- dynamic topic space workflow.
--
-----------------------------------------------------------------------------
{-# LANGUAGE DeriveDataTypeable #-}
module XMonad.Actions.WorkspaceNames (
-- * Usage
-- $usage
-- * Workspace naming
renameWorkspace,
workspaceNamesPP,
getWorkspaceNames',
getWorkspaceNames,
getWorkspaceName,
@ -37,26 +35,30 @@ module XMonad.Actions.WorkspaceNames (
swapWithCurrent,
-- * Workspace prompt
workspaceNamePrompt
workspaceNamePrompt,
-- * StatusBar, EwmhDesktops integration
workspaceNamesPP,
workspaceNamesEwmh,
) where
import XMonad
import XMonad.Prelude (fromMaybe, isInfixOf, (<&>), (>=>))
import qualified XMonad.StackSet as W
import qualified XMonad.Util.ExtensibleState as XS
import XMonad.Actions.CycleWS (findWorkspace, WSType(..), Direction1D(..))
import XMonad.Actions.CycleWS (findWorkspace, WSType(..), Direction1D(..), anyWS)
import qualified XMonad.Actions.SwapWorkspaces as Swap
import XMonad.Hooks.DynamicLog (PP(..))
import XMonad.Prompt (mkXPrompt, XPConfig)
import XMonad.Hooks.StatusBar.PP (PP(..))
import XMonad.Hooks.EwmhDesktops (addEwmhWorkspaceRename)
import XMonad.Prompt (mkXPrompt, XPConfig, historyCompletionP)
import XMonad.Prompt.Workspace (Wor(Wor))
import XMonad.Util.WorkspaceCompare (getSortByIndex)
import qualified Data.Map as M
import Data.Maybe (fromMaybe)
import Data.List (isInfixOf)
-- $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
--
@ -64,10 +66,17 @@ import Data.List (isInfixOf)
--
-- > , ((modm .|. shiftMask, xK_r ), renameWorkspace def)
--
-- and apply workspaceNamesPP to your DynamicLog pretty-printer:
-- and apply workspaceNamesPP to your pretty-printer:
--
-- > myLogHook =
-- > workspaceNamesPP xmobarPP >>= dynamicLogString >>= xmonadPropLog
-- > myPP = workspaceNamesPP xmobarPP
--
-- Check "XMonad.Hooks.StatusBar" for more information on how to incorprate
-- this into your status bar.
--
-- To expose workspace names to pagers and other EWMH clients, integrate this
-- with "XMonad.Hooks.EwmhDesktops":
--
-- > main = xmonad $ … . workspaceNamesEwmh . ewmh . … $ def{…}
--
-- We also provide a modification of "XMonad.Actions.SwapWorkspaces"\'s
-- functionality, which may be used this way:
@ -79,13 +88,13 @@ import Data.List (isInfixOf)
-- > | (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>.
-- | Workspace names container.
newtype WorkspaceNames = WorkspaceNames (M.Map WorkspaceId String)
deriving (Typeable, Read, Show)
deriving (Read, Show)
instance ExtensionClass WorkspaceNames where
initialValue = WorkspaceNames M.empty
@ -97,21 +106,20 @@ getWorkspaceNames' = do
WorkspaceNames m <- XS.get
return (`M.lookup` m)
-- | Returns a function that maps workspace tag @\"t\"@ to @\"t:name\"@ for
-- workspaces with a name, and to @\"t\"@ otherwise.
getWorkspaceNames :: X (WorkspaceId -> String)
getWorkspaceNames = do
lookup <- getWorkspaceNames'
return $ \wks -> wks ++ maybe "" (':' :) (lookup wks)
-- | Returns a function for 'ppRename' that appends @sep@ and the workspace
-- name, if set.
getWorkspaceNames :: String -> X (String -> WindowSpace -> String)
getWorkspaceNames sep = ren <$> getWorkspaceNames'
where
ren name s w = s ++ maybe "" (sep ++) (name (W.tag w))
-- | Gets the name of a workspace, if set, otherwise returns nothing.
getWorkspaceName :: WorkspaceId -> X (Maybe String)
getWorkspaceName w = ($ w) `fmap` getWorkspaceNames'
getWorkspaceName w = ($ w) <$> getWorkspaceNames'
-- | Gets the name of the current workspace. See 'getWorkspaceName'
getCurrentWorkspaceName :: X (Maybe String)
getCurrentWorkspaceName = do
getWorkspaceName =<< gets (W.currentTag . windowset)
getCurrentWorkspaceName = getWorkspaceName =<< gets (W.currentTag . windowset)
-- | Sets the name of a workspace. Empty string makes the workspace unnamed
-- again.
@ -130,26 +138,14 @@ setCurrentWorkspaceName name = do
-- | Prompt for a new name for the current workspace and set it.
renameWorkspace :: XPConfig -> X ()
renameWorkspace conf = do
mkXPrompt pr conf (const (return [])) setCurrentWorkspaceName
where pr = Wor "Workspace name: "
-- | Modify "XMonad.Hooks.DynamicLog"\'s pretty-printing format to show
-- workspace names as well.
workspaceNamesPP :: PP -> X PP
workspaceNamesPP pp = do
names <- getWorkspaceNames
return $
pp {
ppCurrent = ppCurrent pp . names,
ppVisible = ppVisible pp . names,
ppHidden = ppHidden pp . names,
ppHiddenNoWindows = ppHiddenNoWindows pp . names,
ppUrgent = ppUrgent pp . names
}
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 ()
swapTo dir = swapTo' dir AnyWS
swapTo dir = swapTo' dir anyWS
-- | Swap with the previous or next workspace of the given type.
swapTo' :: Direction1D -> WSType -> X ()
@ -169,19 +165,27 @@ swapNames w1 w2 = do
WorkspaceNames m <- XS.get
let getname w = fromMaybe "" $ M.lookup w m
set w name m' = if null name then M.delete w m' else M.insert w name m'
XS.put $ WorkspaceNames $ set w1 (getname w2) $ set w2 (getname w1) $ m
XS.put $ WorkspaceNames $ set w1 (getname w2) $ set w2 (getname w1) m
-- | Same behavior than 'XMonad.Prompt.Workspace.workspacePrompt' excepted it acts on the workspace name provided by this module.
workspaceNamePrompt :: XPConfig -> (String -> X ()) -> X ()
workspaceNamePrompt :: XPConfig -> (WorkspaceId -> X ()) -> X ()
workspaceNamePrompt conf job = do
myWorkspaces <- gets $ map W.tag . W.workspaces . windowset
myWorkspacesName <- getWorkspaceNames >>= \f -> return $ map f myWorkspaces
let pairs = zip myWorkspacesName myWorkspaces
myWorkspaces <- gets $ W.workspaces . windowset
myWorkspacesName <- getWorkspaceNames ":" <&> \n -> [n (W.tag w) w | w <- myWorkspaces]
let pairs = zip myWorkspacesName (map W.tag myWorkspaces)
mkXPrompt (Wor "Select workspace: ") conf
(contains myWorkspacesName)
(job . toWsId pairs)
where toWsId pairs name = case lookup name pairs of
Nothing -> ""
Just i -> i
where toWsId pairs name = fromMaybe "" (lookup name pairs)
contains completions input =
return $ filter (Data.List.isInfixOf input) completions
return $ filter (isInfixOf input) completions
-- | Modify 'XMonad.Hooks.StatusBar.PP.PP'\'s pretty-printing format to show
-- workspace names as well.
workspaceNamesPP :: PP -> X PP
workspaceNamesPP pp = getWorkspaceNames ":" <&> \ren -> pp{ ppRename = ppRename pp >=> ren }
-- | Tell "XMonad.Hooks.EwmhDesktops" to append workspace names to desktop
-- names.
workspaceNamesEwmh :: XConfig l -> XConfig l
workspaceNamesEwmh = addEwmhWorkspaceRename $ getWorkspaceNames ":"

View File

@ -3,6 +3,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Config.Arossato
-- Description : Andrea Rossato's xmonad configuration.
-- Copyright : (c) Andrea Rossato 2007
-- License : BSD3-style (see LICENSE)
--
@ -15,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
@ -22,7 +24,7 @@ module XMonad.Config.Arossato
import qualified Data.Map as M
import XMonad hiding ( (|||) )
import XMonad
import qualified XMonad.StackSet as W
import XMonad.Actions.CycleWS
@ -30,7 +32,6 @@ import XMonad.Hooks.DynamicLog hiding (xmobar)
import XMonad.Hooks.ManageDocks
import XMonad.Hooks.ServerMode
import XMonad.Layout.Accordion
import XMonad.Layout.LayoutCombinators
import XMonad.Layout.Magnifier
import XMonad.Layout.NoBorders
import XMonad.Layout.SimpleFloat
@ -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
--
@ -147,8 +148,8 @@ arossatoConfig = do
, ((modMask x , xK_F3 ), shellPrompt def )
, ((modMask x , xK_F4 ), sshPrompt def )
, ((modMask x , xK_F5 ), themePrompt def )
, ((modMask x , xK_F6 ), windowPromptGoto def )
, ((modMask x , xK_F7 ), windowPromptBring def )
, ((modMask x , xK_F6 ), windowPrompt def Goto allWindows )
, ((modMask x , xK_F7 ), windowPrompt def Bring allWindows )
, ((modMask x , xK_comma ), prevWS )
, ((modMask x , xK_period), nextWS )
, ((modMask x , xK_Right ), windows W.focusDown )

View File

@ -3,6 +3,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Config.Azerty
-- Description : Fix some keybindings for users of French keyboard layouts.
-- Copyright : (c) Devin Mullins <me@twifkak.com>
-- License : BSD
--
@ -17,7 +18,7 @@
module XMonad.Config.Azerty (
-- * Usage
-- $usage
azertyConfig, azertyKeys
azertyConfig, azertyKeys, belgianConfig, belgianKeys
) where
import XMonad
@ -26,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
@ -36,15 +37,21 @@ 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 }
azertyKeys conf@(XConfig {modMask = modm}) = M.fromList $
belgianConfig = def { keys = belgianKeys <> keys def }
azertyKeys = azertyKeysTop [0x26,0xe9,0x22,0x27,0x28,0x2d,0xe8,0x5f,0xe7,0xe0]
belgianKeys = azertyKeysTop [0x26,0xe9,0x22,0x27,0x28,0xa7,0xe8,0x21,0xe7,0xe0]
azertyKeysTop topRow conf@XConfig{modMask = modm} = M.fromList $
[((modm, xK_semicolon), sendMessage (IncMasterN (-1)))]
++
[((m .|. modm, k), windows $ f i)
| (i, k) <- zip (workspaces conf) [0x26,0xe9,0x22,0x27,0x28,0x2d,0xe8,0x5f,0xe7,0xe0],
| (i, k) <- zip (workspaces conf) topRow,
(f, m) <- [(W.greedyView, 0), (W.shift, shiftMask)]]
++
-- mod-{z,e,r} %! Switch to physical/Xinerama screens 1, 2, or 3

View File

@ -3,6 +3,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Config.Bepo
-- Description : Fix keybindings for the BEPO keyboard layout.
-- Copyright : (c) Yorick Laupa <yo.eight@gmail.com>
-- License : BSD
--
@ -25,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
@ -37,11 +38,10 @@ 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)))]
++
[((m .|. modm, k), windows $ f i)
| (i, k) <- zip (workspaces conf) [0x22,0xab,0xbb,0x28,0x29,0x40,0x2b,0x2d,0x2f,0x2a],
(f, m) <- [(W.greedyView, 0), (W.shift, shiftMask)]]
bepoKeys conf@XConfig { modMask = modm } = M.fromList $
((modm, xK_semicolon), sendMessage (IncMasterN (-1)))
: [((m .|. modm, k), windows $ f i)
| (i, k) <- zip (workspaces conf) [0x22,0xab,0xbb,0x28,0x29,0x40,0x2b,0x2d,0x2f,0x2a],
(f, m) <- [(W.greedyView, 0), (W.shift, shiftMask)]]

View File

@ -3,6 +3,7 @@
----------------------------------------------------------------------------
-- |
-- Module : XMonad.Config.Bluetile
-- Description : Default configuration of [Bluetile](http://projects.haskell.org/bluetile/).
-- Copyright : (c) Jan Vornberger 2009
-- License : BSD3-style (see LICENSE)
--
@ -25,25 +26,25 @@ module XMonad.Config.Bluetile (
bluetileConfig
) where
import XMonad hiding ( (|||) )
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
import XMonad.Layout.DraggingVisualizer
import XMonad.Layout.LayoutCombinators
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
import XMonad.Actions.BluetileCommands
import XMonad.Actions.CycleWS
import XMonad.Actions.Minimize
import XMonad.Actions.WindowMenu
import XMonad.Hooks.CurrentWorkspaceOnTop
@ -61,11 +62,10 @@ import qualified XMonad.StackSet as W
import qualified Data.Map as M
import System.Exit
import Data.Monoid
import Control.Monad(when)
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
@ -81,7 +81,7 @@ bluetileWorkspaces :: [String]
bluetileWorkspaces = ["1","2","3","4","5","6","7","8","9","0"]
bluetileKeys :: XConfig Layout -> M.Map (KeyMask, KeySym) (X ())
bluetileKeys conf@(XConfig {XMonad.modMask = modMask'}) = M.fromList $
bluetileKeys conf@XConfig{XMonad.modMask = modMask'} = M.fromList $
-- launching and killing programs
[ ((modMask' , xK_Return), spawn $ XMonad.terminal conf) -- %! Launch terminal
, ((modMask', xK_p ), gnomeRun) -- %! Launch Gnome "Run application" dialog
@ -112,14 +112,14 @@ bluetileKeys conf@(XConfig {XMonad.modMask = modMask'}) = M.fromList $
-- floating layer support
, ((modMask', xK_t ), withFocused $ windows . W.sink) -- %! Push window back into tiling
, ((modMask' .|. shiftMask, xK_t ), withFocused $ float ) -- %! Float window
, ((modMask' .|. shiftMask, xK_t ), withFocused float ) -- %! Float window
-- increase or decrease number of windows in the master area
, ((modMask' , xK_comma ), sendMessage (IncMasterN 1)) -- %! Increment the number of windows in the master area
, ((modMask' , xK_period), sendMessage (IncMasterN (-1))) -- %! Deincrement the number of windows in the master area
-- quit, or restart
, ((modMask' .|. shiftMask, xK_q ), io (exitWith ExitSuccess)) -- %! Quit
, ((modMask' .|. shiftMask, xK_q ), io exitSuccess) -- %! Quit
, ((modMask' , xK_q ), restart "xmonad" True) -- %! Restart
-- Metacity-like workspace switching
@ -143,7 +143,7 @@ bluetileKeys conf@(XConfig {XMonad.modMask = modMask'}) = M.fromList $
-- Minimizing
, ((modMask', xK_m ), withFocused minimizeWindow)
, ((modMask' .|. shiftMask, xK_m ), sendMessage RestoreNextMinimizedWin)
, ((modMask' .|. shiftMask, xK_m ), withLastMinimized maximizeWindow)
]
++
-- mod-[1..9] ++ [0] %! Switch to workspace N
@ -159,19 +159,19 @@ bluetileKeys conf@(XConfig {XMonad.modMask = modMask'}) = M.fromList $
, (f, m) <- [(W.view, 0), (W.shift, shiftMask)]]
bluetileMouseBindings :: XConfig Layout -> M.Map (KeyMask, Button) (Window -> X ())
bluetileMouseBindings (XConfig {XMonad.modMask = modMask'}) = M.fromList $
bluetileMouseBindings XConfig{XMonad.modMask = modMask'} = M.fromList
-- mod-button1 %! Move a floated window by dragging
[ ((modMask', button1), (\w -> isFloating w >>= \isF -> when (isF) $
focus w >> mouseMoveWindow w >> windows W.shiftMaster))
[ ((modMask', button1), \w -> isFloating w >>= \isF -> when isF $
focus w >> mouseMoveWindow w >> windows W.shiftMaster)
-- mod-button2 %! Switch to next and first layout
, ((modMask', button2), (\_ -> sendMessage NextLayout))
, ((modMask' .|. shiftMask, button2), (\_ -> sendMessage $ JumpToLayout "Floating"))
, ((modMask', button2), \_ -> sendMessage NextLayout)
, ((modMask' .|. shiftMask, button2), \_ -> sendMessage $ JumpToLayout "Floating")
-- mod-button3 %! Resize a floated window by dragging
, ((modMask', button3), (\w -> isFloating w >>= \isF -> when (isF) $
focus w >> mouseResizeWindow w >> windows W.shiftMaster))
, ((modMask', button3), \w -> isFloating w >>= \isF -> when isF $
focus w >> mouseResizeWindow w >> windows W.shiftMaster)
]
isFloating :: Window -> X (Bool)
isFloating :: Window -> X Bool
isFloating w = do
ws <- gets windowset
return $ M.member w (W.floating ws)
@ -182,31 +182,28 @@ bluetileManageHook = composeAll
, className =? "MPlayer" --> doFloat
, isFullscreen --> doFullFloat]
bluetileLayoutHook = avoidStruts $ minimize $ boringWindows $ (
named "Floating" floating |||
named "Tiled1" tiled1 |||
named "Tiled2" tiled2 |||
named "Fullscreen" fullscreen
)
bluetileLayoutHook = avoidStruts $ minimize $ boringWindows $
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
tiled2 = tilingDeco $ maximize $ mouseResizableTile
floating = floatingDeco $ maximize $ borderResize positionStoreFloat
tiled1 = tilingDeco $ maximize mouseResizableTileMirrored
tiled2 = tilingDeco $ maximize mouseResizableTile
fullscreen = tilingDeco $ maximize $ smartBorders Full
tilingDeco l = windowSwitcherDecorationWithButtons shrinkText defaultThemeWithButtons (draggingVisualizer l)
floatingDeco l = buttonDeco shrinkText defaultThemeWithButtons l
floatingDeco = buttonDeco shrinkText defaultThemeWithButtons
bluetileConfig =
docks $
docks . ewmhFullscreen . ewmh $
def
{ modMask = mod4Mask, -- logo key
manageHook = bluetileManageHook,
layoutHook = bluetileLayoutHook,
logHook = currentWorkspaceOnTop >> ewmhDesktopsLogHook,
handleEventHook = ewmhDesktopsEventHook
`mappend` fullscreenEventHook
`mappend` minimizeEventHook
logHook = currentWorkspaceOnTop,
handleEventHook = minimizeEventHook
`mappend` serverModeEventHook' bluetileCommands
`mappend` positionStoreEventHook,
workspaces = bluetileWorkspaces,

View File

@ -3,6 +3,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Config.Desktop
-- Description : Core settings for interfacing with desktop environments.
-- Copyright : (c) Spencer Janssen <spencerjanssen@gmail.com>
-- License : BSD
--
@ -23,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:
--
@ -57,6 +58,7 @@ module XMonad.Config.Desktop (
import XMonad
import XMonad.Hooks.ManageDocks
import XMonad.Hooks.EwmhDesktops
import XMonad.Layout.LayoutModifier (ModifiedLayout)
import XMonad.Util.Cursor
import qualified Data.Map as M
@ -70,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@.
@ -89,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.
@ -104,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
@ -127,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@:
--
@ -141,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
--
@ -155,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
@ -164,13 +166,16 @@ import qualified Data.Map as M
-- > adjustEventInput
--
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 {modMask = modm}) = M.fromList $
desktopKeys :: XConfig l -> M.Map (KeyMask, KeySym) (X ())
desktopKeys XConfig{modMask = modm} = M.fromList
[ ((modm, xK_b), sendMessage ToggleStruts) ]
desktopLayoutModifiers layout = avoidStruts layout
desktopLayoutModifiers :: LayoutClass l a => l a -> ModifiedLayout AvoidStruts l a
desktopLayoutModifiers = avoidStruts

View File

@ -1,14 +1,16 @@
-- boilerplate {{{
{-# LANGUAGE ExistentialQuantification, NoMonomorphismRestriction, TypeSynonymInstances #-}
{-# LANGUAGE ExistentialQuantification, NoMonomorphismRestriction, TypeSynonymInstances, ViewPatterns, LambdaCase #-}
{-# OPTIONS_GHC -fno-warn-missing-signatures -fno-warn-type-defaults #-}
module XMonad.Config.Dmwit where
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Config.Dmwit
-- Description : Daniel Wagner's xmonad configuration.
--
------------------------------------------------------------------------
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.Applicative
import Control.Monad
import Control.Monad.Trans
import Data.Char
import Data.List
import Data.Map (Map, fromList)
import Data.Ratio
import Data.Word
@ -29,9 +31,10 @@ import XMonad.Hooks.DynamicLog
import XMonad.Hooks.ManageDocks
import XMonad.Hooks.ManageHelpers
import XMonad.Layout.Grid
import XMonad.Layout.IndependentScreens
import XMonad.Layout.IndependentScreens hiding (withScreen)
import XMonad.Layout.Magnifier
import XMonad.Layout.NoBorders
import XMonad.Prelude hiding (fromList)
import XMonad.Util.Dzen hiding (x, y)
import XMonad.Util.SpawnOnce
-- }}}
@ -75,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"
-- }}}
@ -112,7 +115,6 @@ fullscreenMPlayer = className =? "MPlayer" --> do
Just (16 :% 9) -> viewFullOn 1 "5" win
_ -> doFloat
where
fi = fromIntegral :: Dimension -> Double
approx (n, d) = approxRational (fi n / fi d) (1/100)
operationOn f s n w = do
@ -215,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]
@ -236,7 +238,7 @@ keyBindings conf = let m = modMask conf in fromList . anyMask $ [
((m .|. shiftMask , xK_p ), spawnHere termLauncher),
((m .|. shiftMask , xK_c ), kill),
((m , xK_q ), restart "xmonad" True),
((m .|. shiftMask , xK_q ), io (exitWith ExitSuccess)),
((m .|. shiftMask , xK_q ), io exitSuccess),
((m , xK_grave ), sendMessage NextLayout),
((m .|. shiftMask , xK_grave ), setLayout $ layoutHook conf),
((m , xK_o ), sendMessage Toggle),
@ -306,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")
}
@ -316,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,25 +1,27 @@
{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE TupleSections #-}
{-# OPTIONS_GHC -fno-warn-missing-signatures -fno-warn-orphans #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Config.Droundy
-- Description : David Roundy's xmonad config.
-- Copyright : (c) Spencer Janssen 2007
-- License : BSD3-style (see LICENSE)
--
------------------------------------------------------------------------
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
module XMonad.Config.Droundy ( config, mytab ) where
import XMonad hiding (keys, config, (|||))
import XMonad hiding (keys, config)
import qualified XMonad (keys)
import qualified XMonad.StackSet as W
import qualified Data.Map as M
import System.Exit ( exitWith, ExitCode(ExitSuccess) )
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),
@ -39,8 +41,8 @@ import XMonad.Prompt.Shell ( shellPrompt )
import XMonad.Actions.CopyWindow ( kill1, copy )
import XMonad.Actions.DynamicWorkspaces ( withNthWorkspace, withWorkspace,
selectWorkspace, renameWorkspace, removeWorkspace )
import XMonad.Actions.CycleWS ( moveTo, WSType( HiddenNonEmptyWS ),
Direction1D( Prev, Next) )
import XMonad.Actions.CycleWS ( moveTo, hiddenWS, emptyWS,
Direction1D( Prev, Next), WSType ((:&:), Not) )
import XMonad.Hooks.ManageDocks ( avoidStruts, docks )
import XMonad.Hooks.EwmhDesktops ( ewmh )
@ -77,11 +79,11 @@ keys x = M.fromList $
, ((modMask x, xK_t ), withFocused $ windows . W.sink) -- %! Push window back into tiling
-- quit, or restart
, ((modMask x .|. shiftMask, xK_Escape), io (exitWith ExitSuccess)) -- %! Quit xmonad
, ((modMask x .|. shiftMask, xK_Escape), io exitSuccess) -- %! Quit xmonad
, ((modMask x , xK_Escape), restart "xmonad" True) -- %! Restart xmonad
, ((modMask x .|. shiftMask, xK_Right), moveTo Next HiddenNonEmptyWS)
, ((modMask x .|. shiftMask, xK_Left), moveTo Prev HiddenNonEmptyWS)
, ((modMask x .|. shiftMask, xK_Right), moveTo Next $ hiddenWS :&: Not emptyWS)
, ((modMask x .|. shiftMask, xK_Left), moveTo Prev $ hiddenWS :&: Not emptyWS)
, ((modMask x, xK_Right), sendMessage $ Go R)
, ((modMask x, xK_Left), sendMessage $ Go L)
, ((modMask x, xK_Up), sendMessage $ Go U)
@ -113,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.
@ -123,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.

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