1467 Commits

Author SHA1 Message Date
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: f666cf4e4e ("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 38c11c1e3c, 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: bd5b969d9b ("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: f271d59c34 ("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 (cadb178819)
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 (2c53d507ee)
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: f754b9f926 ("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: 58e2b803a4 ("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 a0caca5edc but
got lost.

Fixes: a0caca5edc ("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: bd5b969d9b
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 bd5b969d9b,
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: bd5b969d9b
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 63e31ccd8d, `xmonadPropLog'` does the encoding
now and accepts a normal Haskell String now.

Fixes: 63e31ccd8d ("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 229d52ff07 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: 229d52ff07 ("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: ec14617123 ("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
  - 673f727206
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: 5eb3dbd61b ("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: 45052b984d ("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: 46f24bb27e ("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 780360abf0
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 780360abf0 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 f2cfaa3398.

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 afb6ef8412, 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
bb205e9205 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: c48d81e378 ("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 ce5aae5403 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 1d0eaddc25 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: 1d0eaddc25 ("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: 8b2bd3ae5c ("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: 2e2d344d92 ("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 7e9c986217 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: 7e9c986217 ("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 9a7dcbbabb ("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: 670eb3bc60 ("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
526336ecec 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
0f1b6fb772) 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 5140f5b5d0.
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 c6cdb77e3b, 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 c6cdb77e3b 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: c6cdb77e3b ("'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 c6cdb77e3b, 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: c6cdb77e3b ("'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 5240116f3c 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 (00be056a1b, 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 (28e9f8bce7, merged in February 2016) a
breaking change in ManageDocks that required users to add
docksStartupHook (or docks, after e38fb3bdb8 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
28e9f8bce7 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: 00be056a1b ("Cache results from calcGap in ManageDocks")
Fixes: 28e9f8bce7 ("add docksStartupHook for handling docks when restarted")
Fixes: e38fb3bdb8 ("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 92fe5f34ff 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 303f0c24bc 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 b0f9197e04, reversing
changes made to 6b8a8f9c8d.

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
Peter Jones
ca9b7d9dfc Add a stack.yaml file for testing and easy Hackage upload 2017-02-10 16:20:42 -07:00
Peter Jones
615f007fe4 Add a cabal.project file 2017-02-10 16:04:33 -07:00
Peter Jones
e4e20da8f0 Clean up the change log just a bit 2017-02-10 16:02:41 -07:00
Peter Jones
b064d22c2d Add a release date 2017-02-09 16:25:24 -07:00
Peter Jones
d2ffb75031 Merge remote-tracking branch 'origin/pjones/rmworkarea' into release-0.13 2017-02-09 16:13:36 -07:00
Peter Jones
cb344d14b9 Bump version to 0.13 2017-02-09 16:12:55 -07:00
Peter J. Jones
d1a5f9cf91 Merge pull request #141 from pjones/pjones/prompt-complete
Better completion when using `alwaysHighlight'
2017-02-09 15:10:27 -07:00
Peter J. Jones
3b1c43cced Merge pull request #142 from pjones/pjones/border
Use `setWindowBorderWithFallback' to support windows with RGBA color maps
2017-02-09 15:10:13 -07:00
Peter J. Jones
76b1771a31 Merge pull request #144 from pjones/pjones/dzen
Manage struts even when _NET_WM_WINDOW_TYPE isn't a dock
2017-02-09 15:07:40 -07:00
Peter Jones
cd96de5378 Manage struts even when _NET_WM_WINDOW_TYPE isn't a dock
Relates to #21
2017-02-07 15:58:55 -07:00
Peter Jones
0a8e68b458 Delete _NET_WORKAREA instead of setting it
References:

  * 9c020877dd

  * https://github.com/qtile/qtile/issues/847

  * eec80838ab

  * https://github.com/xmonad/xmonad-contrib/pull/79
2017-02-07 15:42:35 -07:00
Peter Jones
de4a3bd0ed Use `setWindowBorderWithFallback' to support windows with RGBA color maps
This brings xmonad-contrib inline with xmonad in this regard.  Should
also be fix for #138
2017-02-07 14:49:01 -07:00
Peter Jones
4f3020313d Don't use `windows' in X.L.Hidden, it might cause an infinite loop
Fixes #132
2017-02-07 13:39:01 -07:00
Peter Jones
57c00b1086 Better completion when using `alwaysHighlight'
This change improves the UX of X.Prompt when `alwaysHighlight` is
enabled.  This is especially useful for use with `mkXPromptWithModes`
which forces `alwaysHighlight` to be `True`.

When the user presses the `complKey` and `alwaysHighlight` is `True`,
one of two things will happen:

  1. If this is the first time `complKey` is pressed in this round of
     completion then the prompt buffer will be updated so it contains
     the currently highlighted item.

  2. Every other time that the `complKey` is pressed the next
     completion item will be selected and the prompt buffer updated.

This gives immediate feedback to the user and allows using some
prompts with `alwaysHighlight` that weren't possible before (e.g.,
shellPrompt, directoryPrompt, etc.)
2017-02-05 19:38:00 -07:00
Peter Jones
bdec8df4c6 Improve prompts for X.A.DynamicProjects 2017-02-05 19:36:30 -07:00
Peter Jones
52087953fd Add `directoryMultipleModes'
Allow X.P.Directory to be used with `mkXPromptWithModes`
2017-02-05 19:31:41 -07:00
Peter Jones
33c805fadc Add GitHub templates 2017-01-12 12:27:11 -07:00
Peter J. Jones
32b9f00ce7 Merge pull request #134 from pjones/bugfix/prompt-history
Use the new getXMonadCacheDir function from #62
2017-01-08 21:26:13 -07:00
sgf
a3593e5607 Remove no longer relevant changes from CHANGES.md. Fix merge conflicts. 2017-01-06 18:01:41 +03:00
Peter Jones
4dd60756ea Update the change log 2017-01-04 14:47:20 -07:00
Peter Jones
74b281b5d3 Use the new getXMonadCacheDir function from #62
Prompt should have been using getXMonadDir this entire time but since
we now have getXMonadCacheDir use that instead.  This brings
xmonad-contrib inline with the changes in #62.

This also fixes xmonad/xmonad-contrib#68
2017-01-04 14:39:00 -07:00
Peter J. Jones
77e5e5190d Merge pull request #131 from sgf-dma/fix-changes.md
Fix CHANGES.md after b9d8f6c .
2017-01-03 15:49:09 -07:00
sgf
5bf4b27054 Fix CHANGES.md after b9d8f6c . 2016-12-25 14:59:30 +03:00
Brent Yorgey
8956684ff5 Merge pull request #130 from strokyl/add_HiddenEmptyWS_to_CycleWS
Add HiddenEmptyWS to CycleWS
2016-12-23 23:50:52 -05:00
Luc DUZAN
9da78669e7 Add HiddenEmptyWS to CycleWS
When I have multiscreen I think it's usefull to get the next empty workspace
that is not already displayed.
2016-12-22 22:48:23 +01: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
Peter J. Jones
c0cf18def2 Merge pull request #17 from kurnevsky/update_pointer_bugfix
UpdatePointer bugfix.
2016-12-14 14:48:52 -07:00
Peter Jones
d5aa562282 Add build status badge from Travis 2016-12-14 14:44:15 -07:00
Peter Jones
f1de0413da Update GHC versions to a more reasonable list 2016-12-14 14:29:52 -07:00
Peter Jones
6eac81cf51 Bump X11 version upper-bounds to 1.8 2016-12-14 14:11:30 -07:00
Kurnevsky Evgeny
a8d290b830 Update CHANGES.md 2016-12-14 11:49:28 +03:00
Kurnevsky Evgeny
86280c5063 Rewrite XMonad.Actions.UpdatePointer bugfix with Control.Exception.try. 2016-12-14 09:03:26 +03:00
Kurnevsky Evgeny
11e0d683af UpdatePointer bugfix. 2016-12-14 09:03:26 +03:00
geekosaur
061edbd954 Merge pull request #127 from bennofs/patch-1
DynamicProperty: execute other hooks
2016-12-09 23:10:06 -05:00
Benno Fünfstück
0949b9ec91 DynamicProperty: execute other hooks
All False short-cuts the default behavior for the event, which leads to a non-functioning window manager. Returning mempty ensures that the default action is still executed,
2016-12-09 22:35:11 +01:00
Peter J. Jones
f837a4fb36 Merge pull request #6 from sgf-dma/master
X.A.Submap: establish pointer grab to avoid freezing X.
2016-12-09 08:34:47 -07:00
sgf
b9d8f6ce34 X.A.Submap: establish pointer grab to avoid freezing X.
Establish active asynchronous pointer grab before entering infinity cycle.
Because xmonad already has passive synchronous pointer grab, this overwrites
it temporary and avoids freezing X, when button press occurs after submap key
press.

Also, terminate submap at button press in the same way, as we do for wrong key
press.
2016-12-09 12:38:33 +03:00
Peter J. Jones
c69b2933a3 Merge pull request #126 from pauleve/master
Fix #120 - Make Actions.WindowGo.raiseNextMaybe span over all workspaces
2016-12-08 14:39:30 -07:00
Loïc Paulevé
0573451789 Update CHANGES.md for #126 2016-12-08 22:24:24 +01:00
Loïc Paulevé
43673b3907 workspacesSorted: fix indentation + add comment 2016-12-05 13:37:26 +01:00
Loïc Paulevé
9f9b5d3748 Make Actions.WindowGo.raiseNextMaybe span over all workspaces. Fixes #120 2016-12-02 08:54:01 +01:00
Daniel Wagner
0a1d8505a0 Merge pull request #125 from vvv/fix-custom-keys-doc
CustomKeys.hs: Fix documentation
2016-11-30 18:41:54 +01:00
Valery V. Vorotyntsev
c392a407bb CustomKeys.hs: Fix documentation
Fix code example in documentation. (Wrong implementation of `delkeys`.)
Thanks to Lasse R.H. Nielsen for reporting the problem!
2016-11-30 17:55:20 +02:00
Brent Yorgey
16b80a4331 Merge pull request #124 from trofi/master
XMonad/Layout/Groups/Helpers.hs: drop broken ImpredicativeTypes extension (fixes #123)
2016-11-28 17:54:29 -05:00
Sergei Trofimovich
a681e68602 XMonad/Layout/Groups/Helpers.hs: drop broken ImpredicativeTypes extension (fixes #123)
ImpredicativeTypes is practically unsupported extension
on it's way to be removed from GHC:
    https://mail.haskell.org/pipermail/ghc-devs/2016-September/012826.html

GHC-8.0.2-rc1 already fails to build xmonad-contrib as:

  XMonad/Layout/Groups/Helpers.hs:181:22: error:
    • Couldn't match type ‘G.WithID l0 Window
                           -> XMonad.Util.Stack.Zipper (G.Group l0 Window)
                           -> XMonad.Util.Stack.Zipper (G.Group l0 Window)’
                     with ‘G.ModifySpec’
      Expected type: (G.WithID l0 Window
                      -> XMonad.Util.Stack.Zipper (G.Group l0 Window)
                      -> XMonad.Util.Stack.Zipper (G.Group l0 Window))
                     -> G.GroupsMessage
        Actual type: G.ModifySpec -> G.GroupsMessage
    • In the second argument of ‘(.)’, namely ‘G.Modify’
      In the expression: sendMessage . G.Modify
      In an equation for ‘wrap’: wrap = sendMessage . G.Modify

The workaround is simple: add explicit types to applications
or open-code direct application (this change).

Bug: https://github.com/xmonad/xmonad-contrib/issues/123
Signed-off-by: Sergei Trofimovich <siarheit@google.com>
2016-11-27 10:03:17 +00:00
Peter Jones
be036f9bb9 Export `removeEmptyWorkspaceByTag'
It looks like this function should have been exported all along but
was overlooked.
2016-11-21 17:15:53 -07:00
Peter Jones
217abc39a2 Compose startupHook/logHook in the same order as other modules
I believe this was causing issues where a dynamically created
workspace would not properly trigger manageDocks logic.
2016-11-16 15:13:58 -07:00
Peter Jones
5790913eae Teach X.A.DynamicProjects to use removeWorkspaceByTag when deleting a project
When deleting a dynamic project, also delete its workspace.
2016-11-15 17:00:50 -07:00
Brent Yorgey
d21ed81801 Merge pull request #106 from IvanMalison/custom_focus_raise_next_maybe
X.A.WindowGo: Add arg for custom focus fn to raiseNextMaybe
2016-11-08 22:59:21 -05:00
Brent Yorgey
cc44be649d Merge pull request #113 from pjones/xmonad/features/layoutb
Refactor all X.L.LayoutBuilderP functionality into X.L.LayoutBuilder
2016-11-08 22:57:08 -05:00
Brent Yorgey
a7059e1a32 Merge pull request #114 from liskin/workspacenames2
X.A.WorkspaceNames: add getWorkspaceNames'
2016-11-08 22:53:31 -05:00
Tomas Janousek
7ada94df42 X.A.WorkspaceNames: add getWorkspaceNames' 2016-11-07 20:59:20 +01:00
Peter Jones
c0a0a44fbc Update CHANGES.md for PR #113 2016-11-05 10:00:17 -07:00
Peter Jones
ca5fbc155b Refactor all X.L.LayoutBuilderP functionality into X.L.LayoutBuilder
X.L.LayoutBuilderP is nearly identical to X.L.LayoutBuilder.  Originally
I wanted to add the ability to dynamically resize the layout boxes so it
make a lot of sense to join these two modules together so I wouldn't
have to do it in both.  Even though I never got around to that I still
think it's a good idea to merge these two modules into one.

I believe I was able to merge these without creating any
backward-compatibility issues.  I've been sitting on these changes since
2015 and they work for me without having to change older parts of my
config (relating to X.L.LayoutBuilder).

If anyone wants to work on dynamically resizing layout boxes the issue I
created for it is #36.
2016-11-05 09:51:28 -07:00
Ivan Malison
856b125186 X.A.WindowGo: Make comment style more consistent 2016-11-03 19:22:49 -07:00
Ivan Malison
c51bd739d7 X.A.WindowGo: Add a haddock comment to raiseNextMaybeCustomFocus 2016-11-03 19:21:52 -07:00
Ivan Malison
0e1cecd135 Merge remote-tracking branch 'origin/master' into custom_focus_raise_next_maybe 2016-11-03 19:15:28 -07:00
Brent Yorgey
ec5f9a9e59 Merge pull request #80 from f1u77y/managedocks-global-cache
Make strut cache global
2016-11-03 17:40:04 -04:00
Brent Yorgey
65bbe1a995 Merge pull request #108 from liskin/workspacenames
X.A.WorkspaceNames: add get(Current)WorkspaceName
2016-11-02 21:25:06 -04:00
Brent Yorgey
7b8798cb30 Merge pull request #104 from IvanMalison/windowBringerDefaults
X.A.WindowBringer: Add a config object with a X.C.Default implementation
2016-11-02 21:23:20 -04:00
Tomas Janousek
0a74e3479e X.A.WorkspaceNames: add get(Current)WorkspaceName 2016-10-29 23:36:19 +02:00
Ivan Malison
8e061c0c6d X.A.WindowGo: Remove uncurry from raiseNextMaybeCustomFocus 2016-10-26 17:24:45 -07:00
Ivan Malison
49fecdf4eb X.A.WindowGo: Add arg for custom focus fn to raiseNextMaybe 2016-10-26 17:09:42 -07:00
Ivan Malison
993dedf6d3 X.A.WindowBringer: Use <$> instead of fmap 2016-10-24 22:38:45 -07:00
Bogdan Sinitsyn
fcb57bd657 Move modifyXS to X.U.ExtensibleState 2016-10-25 08:22:02 +03:00
Ivan Malison
05d7493888 X.A.WindowBringer: Misc. cleanup and whitespace fixes 2016-10-24 22:10:56 -07:00
Ivan Malison
4983ecfd23 X.A.WindowBringer: Add haddocks for WindowBringerConfig 2016-10-24 22:10:09 -07:00
Brent Yorgey
ae7fd21e29 Merge pull request #97 from samdoshi/prompt-haddock
fix broken XPConfig docs
2016-10-24 17:57:53 -04:00
Ivan Malison
6cb10c9300 X.A.WindowBringer: Add a X.C.Default impl
This provides a less complicated interface to the specification of
custom behavior. In particular it allows the specification of a custom
window titling function.
2016-10-21 20:14:52 -07:00
Brent Yorgey
e98fedfaa5 Merge pull request #92 from jschwab/use-searchPredicate-in-prompt-pass
XMonad.Prompt.Pass: Use searchPredicate from XPConfig
2016-10-21 22:35:09 -04:00
Sam Doshi
dcc2759c4d fix broken XPConfig docs 2016-10-19 11:41:06 +01:00
Brent Yorgey
b871a0c7ee Merge pull request #91 from nomeata/prompt-unicode
Add XMonad.Prompt.Unicode
2016-10-19 19:13:47 +09:00
Brent Yorgey
c71f72ff66 Merge pull request #95 from Fuco1/feature/add-submapdefaultwithkey
Feature/add submapdefaultwithkey
2016-10-18 10:58:27 +09:00
Matus Goljer
e5ca066057 Add submapDefaultWithKey.
This is useful for when we want to decide what to do in the default
action based on the key that failed to match in the submap.
2016-10-16 16:40:13 +02:00
Matus Goljer
444986d993 Remove unneeded argument 2016-10-16 16:36:18 +02:00
Matus Goljer
1553d81ce7 Use fromMaybe over "maybe .. id" 2016-10-16 16:33:49 +02:00
Josiah Schwab
082c64ec37 XMonad.Prompt.Pass: Use searchPredicate from XPConfig
XMonad.Prompt allows the user to specify a search predicate in XPConfig.
However, previously XMonad.Prompt.Pass did not apply this predicate.
This now applies the predicate in similar manner as XMonad.Prompt.Shell.
2016-10-12 10:28:01 -07:00
Joachim Breitner
01ddbb7b82 Do not use sortOn
as it is not available in old versions of base.
2016-10-07 15:40:04 -04:00
Joachim Breitner
feec53c78c Avoid attoparsec dependency for this simple parsing task 2016-10-07 15:29:03 -04:00
Joachim Breitner
e4e120bb8e Add XMonad.Prompt.Unicode
I have been using this code locally for years now, and it turned out to
be quite useful in many cases, so I thought it is about time to submit
it to the repository.
2016-10-07 11:50:21 -04:00
Brent Yorgey
858a906240 Merge pull request #87 from nlewo/master
X.A.DynamicWorkspaces: associate indexes to workspaces
2016-10-05 20:32:34 +09:00
Brent Yorgey
1b81ac7314 Merge pull request #86 from aiya000/master
Export XMonad.Actions.Workscreen (WorkscreenId)
2016-10-05 20:29:18 +09:00
Brent Yorgey
262e78770f Merge pull request #82 from 41px/dev-41px
Switch/Move to physical/Xinerama screens 1, 2 or 3
2016-09-23 07:14:17 +09:00
Brent Yorgey
1c8e17e127 Merge pull request #84 from TomSmeets/treeselect
Fix incorrect documentation in TreeSelect
2016-09-23 07:11:56 +09:00
Antoine Eiche
f3de3e2719 X.A.DynamicWorkspace: update index map on workspace renaming 2016-09-20 20:42:03 +02:00
Antoine Eiche
464a99b842 X.A.DynamicWorkspaces: associate indexes to workspaces
You can add indexes to workspaces and use them to do actions on
workspaces. This allows you to dynamicaly associate a workspace to a
keybinding without depending of the workspace name or the workspace
position.
2016-09-19 14:33:18 +02:00
aiya000
f6ded1a4d7 Export XMonad.Actions.Workscreen (WorkscreenId)
This is fixing for problem that
WorkscreenId was shown in XMonad.Actions.Workscreen document
(ex: viewWorkscreen),
but never shown WorkscreenId definition.
2016-09-19 16:31:43 +09:00
Tom Smeets
3b4a3d2bd2 Fix incorrect documentation for WorkspaceHistory 2016-09-14 20:02:07 +02:00
Brent Yorgey
753e9ce4b0 Merge pull request #72 from TomSmeets/treeselect
Add TreeSelect action for selecting from many workspaces and X actions
2016-09-14 07:22:05 -04:00
Daniel Wagner
bf1f4fcc76 Merge pull request #81 from asjo/add_note_to_stoppable
Add note about when Stoppable does not work.
2016-09-11 16:04:39 -07:00
Tom Smeets
305c8eff0d Add optional workspace-history navigation
To enable this feature add `workspaceHisotryHook` from
`XMonad.Hooks.WorkspaceHistory` to your logHook.

Your previously-visited workspaces can be navigated with
the 'moveHistBack' and 'moveHistForward' actions (which are bound to the 'o' and 'i' keys)
2016-09-08 17:00:21 +02:00
Tom Smeets
52b180e6b2 Fixed getSubForest and rootNode 2016-09-08 17:00:21 +02:00
Tom Smeets
c2331f9657 Fixed a small error in the documentation 2016-09-08 17:00:21 +02:00
Tom Hinton
953f1576f4 Determine which groups to Hide correctly
This is a fix I have applied locally to make sure that when I use decorated layouts like tabbed in groups, XMonad does not leave bogus decoration windows lying around.

I think that the issue fixed is that the set of groups to send `Hide` to is determined by subtracting the extant groups from `l`, but `l` has already been put through `readapt` and so some groups may have been removed (if they are empty), so they don't get the Hide message.

The comparison should therefore be between `_l` and the new groups.
2016-09-08 17:00:21 +02:00
Alexandre Px
7629f774c6 fix Couldn't match expected type `KeyMask' 2016-09-07 21:54:09 +02:00
Alexandre Px
a1adb0b801 Replace M.union to <+> in documentation 2016-09-07 21:48:49 +02:00
Alexandre Px
c3081bd783 Switch/Move to physical/Xinerama screens 1, 2 or 3 2016-09-07 21:44:15 +02:00
Tomas Janousek
e38fb3bdb8 Make usage of ManageDocks simpler and more robust
As it now consists of a startup hook, a manage hook, an event hook and
a layout modifier, and behaves erratically when any one component is not
included in a user's config (which happens to be the case for all
configs from xmonad-contrib 0.12 since the startup hook is a new
inclusion), it's probably wise to have a single function that adds
all the hooks to the config instead.

NB: This will need a release notes entry anyway!
2016-09-07 13:26:58 +03:00
Bogdan Sinitsyn
c48d81e378 Fix caching issues in ManageDocks
Commits d638dc8b and a5e87e38 introduced a per-AvoidStruts-instance
strut cache that

a) didn't get initialized at startup,
b) didn't get reinitialized after layout reset and
c) didn't get updates if it wasn't the active layout, for example when
   layoutHook = avoidStruts tall ||| avoidStruts (mirror tall)

a) + b) could be fixed by using the docksStartupHook introduced in
28e9f8bc, although this wasn't documented and having to call
docksStartupHook after setLayout is far from obvious.

By moving the strut cache from AvoidStruts instances to a global state,
b) and c) are fixed. One still has to invoke the docksStartupHook for
a), and this will be addressed in the next commit.
2016-09-07 13:26:50 +03:00
Brent Yorgey
94c7cb513c Merge pull request #77 from LSLeary/master
A very simple extension to Navigation2D so it plays better with gaps
2016-09-06 13:19:17 -04:00
Adam Sjøgren
61038f95fb Add note about when Stoppable does not work. 2016-09-03 23:41:10 +02:00
L.S. Leary
4358f58de8 Swapped pickSomething for <|> in doHybridNavigation. 2016-08-30 13:11:54 +12:00
Brent Yorgey
899ff52316 Merge pull request #78 from larkery/patch-1
Determine which groups to Hide correctly
2016-08-29 19:04:13 -04:00
L.S. Leary
ea6e1a5d6d Removed extraneous blank line from Nav2D. 2016-08-29 16:53:46 +12:00
LSLeary
4aaf053273 Rewrote doHybridNavigation. 2016-08-29 14:30:03 +12:00
Tom Hinton
2e53a6cdd6 Determine which groups to Hide correctly
This is a fix I have applied locally to make sure that when I use decorated layouts like tabbed in groups, XMonad does not leave bogus decoration windows lying around.

I think that the issue fixed is that the set of groups to send `Hide` to is determined by subtracting the extant groups from `l`, but `l` has already been put through `readapt` and so some groups may have been removed (if they are empty), so they don't get the Hide message.

The comparison should therefore be between `_l` and the new groups.
2016-08-27 17:12:34 +01:00
L.S. Leary
76565e42c4 Removed an extraneous comment that had been accidentally left in place. 2016-08-27 03:49:52 +12:00
L.S. Leary
a7d5696e5a Punctuation tweak in docs. 2016-08-27 03:27:08 +12:00
L.S. Leary
b9215181bb Rather than writing over the vanilla Line navigation function, Hybrid navigation has been implemented separately. 2016-08-27 03:17:05 +12:00
L.S. Leary
806a501d51 Modified Line to default to Center if it can't move. This provides the best way to get around if you use gaps and float no windows. 2016-08-27 02:37:35 +12:00
Tom Smeets
529683660c Show error when using incorrect XConfig.workspaces 2016-08-22 21:18:04 +02:00
Tom Smeets
15a2a86d46 Removed a useless comment 2016-08-22 20:15:25 +02:00
Tom Smeets
25df357a4a Fixed a small bug 2016-08-10 10:30:39 +02:00
Tom Smeets
c2e0fc517c Fixed incompatibility with older GHC versions 2016-08-08 18:53:27 +02:00
Tom Smeets
1087844a7f Add screenshots and a little more info 2016-08-08 17:26:26 +02:00
Tom Smeets
8bfbafeae9 Add entry to XMonad.Doc.Extending 2016-08-08 11:47:08 +02:00
Tom Smeets
7e777bebfd Select your workspaces and actions in a Tree format.
TreeSelect displays your workspaces or actions in a Tree-like format.
You can select the desired workspace/action with the cursor or hjkl keys.

This module is fully configurable and very useful if you like to have a
lot of workspaces.

Please see the Documentation provided by 'XMonad.Actions.TreeSelect'.
2016-08-07 20:40:40 +02:00
Brent Yorgey
8d2582f032 Merge pull request #66 from mathstuf/fix-warnings
Fix warnings
2016-08-01 14:12:35 -04:00
Brent Yorgey
81f1eab1ee X.A.Search: fix amazon search URL
Closes #71.
2016-08-01 13:01:30 -05:00
Ben Boeckel
4e880b37a2 IfMax: add the PatternGuards extension 2016-07-16 13:23:11 -04:00
Ben Boeckel
637c5c67b1 BinarySpacePartition: add type signature for noRef 2016-07-16 13:22:45 -04:00
Ben Boeckel
8fd8c5d02d warnings: remove unused variables 2016-07-16 13:22:34 -04:00
Ben Boeckel
d414c76da8 warnings: rename shadowing variables 2016-07-16 13:22:12 -04:00
geekosaur
ddcc9e0209 Merge pull request #63 from oldmanmike/XMonad-Config-Desktop-update
Update XMonad.Config.Desktop for 0.12 ManageDocks
2016-07-13 15:46:08 -04:00
Brent Yorgey
e280f62a57 Merge pull request #61 from oldmanmike/update-extending-docs
Add missing Extending documentation for new modules
2016-07-05 15:19:56 -04:00
oldmanmike
a8ca8bcd6f Update XMonad.Config.Desktop for 0.12 ManageDocks 2016-07-02 02:14:36 -04:00
oldmanmike
f3dc89f821 Add missing Extending documentation for new modules 2016-07-01 12:36:15 -04:00
Adam Vogt
6a9e9e5a78 Merge pull request #59 from chongli/master
New SortedLayout module.
2016-07-01 11:52:22 -04:00
Kurt Dietrich
1d5cdc108a New SortedLayout module. 2016-06-30 15:33:15 -04:00
Daniel Wagner
d6243c9564 improve documentation on fonts in Prompt 2016-06-22 13:17:28 -07:00
Daniel Wagner
c2c6a94834 Merge branch 'master' of github:xmonad/xmonad-contrib 2016-06-22 12:57:14 -07:00
Brent Yorgey
6aa289c713 Merge pull request #4 from mathstuf/dynamic-bars-partial-cleanup
X.H.DynamicBars: support per-monitor cleanup
2016-06-16 17:31:05 -04:00
Ben Boeckel
cc77b5019d DynamicBars: improve documentation 2016-06-12 20:03:22 -04:00
geekosaur
a421da29e6 Merge pull request #57 from CaptainPatate/master
Fix minor things
2016-06-12 19:00:45 -04:00
Amaury Gauthier
2831378f8f Fix type of additionalKeys and removeKeys functions 2016-06-08 00:35:25 +02:00
Amaury Gauthier
34f9dda006 Fix documentation 2016-06-08 00:35:25 +02:00
Ben Boeckel
e698e5fe53 X.H.DynamicBars: support per-monitor cleanup
Add functions to allow cleaning up only screens which disappear. This
works better where killing the statusbar for a specific screen is
possible. The old way is still relevant for setups which do not have
such a method (e.g., safeSpawn xmobar/spawnPipe xmonadpropwrite).
2016-05-22 17:28:46 -04:00
Brent Yorgey
fce36bda16 Merge pull request #24 from nlewo/master
X.P.Window: add window selector for the prompt and BringToMaster action
2016-05-12 12:11:25 -04:00
Antoine Eiche
73134369ea X.P.Window: add window selector for the prompt and BringToMaster action
- The set of windows proposed by the prompt can be parametrized. Two
  helper functions are currently defined. One for selecting all
  available windows and another one for selecting all windows of the
  current workspace.

- Add BringToMaster action which brings the selected window to the
  current workspace and set it as master.

- windowPromptGoto, windowPromptBring, windowPromptBringCopy are
  marked as deprecated since they can be realized by the more generic
  windowPrompt function.  For instance, "windowPromptGoto prompt" can
  be easily replaced by "windowPrompt prompt Goto allWindows".
2016-05-10 09:54:41 +02:00
Brent Yorgey
26b50c043c Merge pull request #52 from geekosaur/nsp-loggers
XMonad.Util.Loggers for NamedScratchPad-s
2016-05-09 20:55:25 -04:00
brandon s allbery kf8nh
ed4909aa65 pre-Typeable-unsafeCoerce-fix ghc needs a deriving pragma 2016-05-02 23:06:08 -04:00
Brent Yorgey
f12167b298 Merge pull request #53 from jablko/master
Make WindowBringer case insensitive
2016-05-02 23:00:55 -04:00
Brent Yorgey
00c6a44bdc Merge pull request #51 from seanstrom/feature/dynamicbars-multiPPFormat
DynamicBars: Add new multiPPFormat function
2016-05-02 22:47:27 -04:00
geekosaur
b41544b6cc Merge pull request #55 from Delapouite/docs
docs: fix typo Repace → Replace in XMonad.Layout.Renamed
2016-04-29 10:02:47 -04:00
Delapouite
da44e76f75 docs: fix typo Repace → Replace in XMonad.Layout.Renamed 2016-04-29 13:31:59 +02:00
Jack Bates
75b3cae49f Make WindowBringer case insensitive 2016-04-27 09:48:36 -07:00
brandon s allbery kf8nh
72956159b6 Add XMonad.Util.NoTaskbar, XMonad.Util.Loggers.NamedScratchpad 2016-04-21 14:49:13 -04:00
geekosaur
9a187f243c Merge pull request #50 from damianfral/patch-1
Fix updatePointer equivalence table.
2016-04-12 11:15:56 -04:00
Damián Franco Álvarez
e0211ad7d6 Fix updatePointer equivalence table.
In order to get the behavior I had with `updatePointer (Relative 0.5 0.5)`, I have to use `updatePointer (0.5,0.5) (0,0)`.
2016-04-12 16:36:56 +02:00
geekosaur
c08d48f6aa Merge pull request #31 from geekosaur/master
add X.U.Ungrab
2016-04-07 14:22:47 -04:00
geekosaur
81dd1cba1d Merge pull request #48 from f1u77y/fix-ifmax-3
Final(I hope) attempt to fix X.L.IfMax
2016-04-06 23:04:25 -04:00
brandon s allbery kf8nh
abe911a8d6 Merge remote-tracking branch 'upstream/master' 2016-04-06 21:24:21 -04:00
seanstrom
1452c9e273 add new multiPPFormat function 2016-04-03 16:04:49 -07:00
Bogdan Sinitsyn
44abb6c8d4 handle ReleaseResources correctly 2016-03-26 16:28:23 +03:00
Bogdan Sinitsyn
43fccf1a6c use workspace name for running layouts 2016-03-26 16:28:23 +03:00
Bogdan Sinitsyn
f429843b66 remove reundant ReleaseResources handling 2016-03-26 16:28:23 +03:00
Bogdan Sinitsyn
dd5a36cc08 hide layout when changing to another 2016-03-26 16:28:23 +03:00
Brent Yorgey
01ea659a06 Merge pull request #21 from f1u77y/#16
fix #16
2016-03-15 22:02:39 -05:00
geekosaur
f1d3118417 Merge pull request #45 from f1u77y/fix-ifmax-2
watch only for tiled windows in X.L.IfMax
2016-03-10 19:53:25 -05:00
Bogdan Sinitsyn
ceb2df8931 watch only for tiled windows in X.L.IfMax 2016-02-29 14:12:36 +03:00
Adam Vogt
99cc0b6c85 Merge pull request #42 from f1u77y/fix-ifmax
handle messages in X.L.IfMax
2016-02-28 19:23:16 -05:00
Adam Vogt
9c95c81a90 Merge pull request #22 from f1u77y/#14
close #14
2016-02-28 19:20:20 -05:00
Adam Vogt
15c645d9f2 use traverse_ instead of traverse in DynamicBars 2016-02-26 19:08:57 -05:00
Bogdan Sinitsyn
94a7e97ac8 handle messages in X.L.IfMax 2016-02-23 16:06:21 +03:00
Brent Yorgey
c736d52268 Merge pull request #41 from jmickelin/wmii-togglegroupfull-fix
Fixed bottom-yielding definition of toggleGroupFull
2016-02-23 06:30:09 -06:00
Jonne Mickelin Sätherblom
c27ef4d418 Fixed bottom-yielding definition of toggleGroupFull 2016-02-19 19:51:31 +01:00
Brent Yorgey
571193a219 Merge pull request #34 from bb-h8/master
Added missing boundary check in Layout.Spacing.shrinkRect
2016-02-14 16:42:03 -06:00
f1u77y
bbbdad8faa prevent losing focus in gridSelect(fix #16) 2016-02-14 20:15:26 +03:00
geekosaur
311d3a0582 Merge pull request #38 from kurnevsky/docmentation_fix
Documentation fix.
2016-02-14 11:10:53 -05:00
geekosaur
b14db06f65 Merge pull request #39 from f1u77y/fix-prompt-numlock
strip numlock from mask in X.Prompt(fixes #37)
2016-02-14 11:10:04 -05:00
Bogdan Sinitsyn
30f657a437 strip numlock from mask in X.Prompt(fixes #37) 2016-02-14 14:54:26 +03:00
Kurnevsky Evgeny
a6f286dbdc Documentation fix. 2016-02-14 12:59:29 +03:00
brandon s allbery kf8nh
3796569268 whoops, CHANGES.md 2016-02-13 21:29:06 -05:00
geekosaur
d5eb7316d1 Merge pull request #30 from f1u77y/fix-docks
fix xmonad/xmonad#21
2016-02-13 21:23:50 -05:00
bb-h8
baf1dd9251 Added missing boundary check in Layout.Spacing.shrinkRect 2016-01-26 21:27:49 +01:00
Bogdan Sinitsyn
5e96324d80 send all docks messages only from event hook 2016-01-18 12:02:40 +03:00
Bogdan Sinitsyn
5df7ba160e some minor fixes in X.H.ManageDocks 2016-01-18 10:37:04 +03:00
Bogdan Sinitsyn
431fd66527 fix slowdown when removing docks 2016-01-17 18:15:41 +03:00
Bogdan Sinitsyn
f79e3fadea handle docks remove correctly 2016-01-17 16:32:56 +03:00
Bogdan Sinitsyn
28e9f8bce7 add docksStartupHook for handling docks when restarted 2016-01-17 11:55:59 +03:00
Bogdan Sinitsyn
f73eb1c938 handle PropertyNotify events on docks 2016-01-17 11:46:53 +03:00
Bogdan Sinitsyn
83ee18ad94 add new dock if it hasn't strut properties 2016-01-17 10:53:55 +03:00
Bogdan Sinitsyn
f4d4bde026 typo 2016-01-17 10:38:51 +03:00
Bogdan Sinitsyn
f1b9a0c193 add calcGapForAll for other modules 2016-01-17 10:35:26 +03:00
Bogdan Sinitsyn
34beb76562 fix X.H.PositionStoreHooks for new signature of calcGaps 2016-01-17 10:14:51 +03:00
Bogdan Sinitsyn
028ad6d6ec minor fixes in X.H.ManageDocks 2016-01-17 10:08:20 +03:00
Bogdan Sinitsyn
a5e87e3894 never query all the tree in X.H.ManageHook 2016-01-17 10:03:07 +03:00
brandon s allbery kf8nh
2855ed3d70 add X.U.Ungrab 2016-01-16 00:37:19 -05:00
Bogdan Sinitsyn
68cfa84b91 fix build with older ghc 2016-01-15 21:21:47 +03:00
Peter J. Jones
b20e7fa1e4 Merge pull request #29 from f1u77y/prompt-position
Prompt position
2016-01-10 16:06:29 -07:00
Bogdan Sinitsyn
58c3062910 typo 2016-01-10 23:52:13 +03:00
Bogdan Sinitsyn
889cd97d08 add myself to .mailmap and edit changelog 2016-01-10 23:51:00 +03:00
Bogdan Sinitsyn
4a9e28ca8b Merge branch 'master' of https://github.com/xmonad/xmonad-contrib into prompt-position 2016-01-10 23:43:11 +03:00
Peter J. Jones
604a262f38 Merge pull request #23 from psibi/prompt-multiple-key
Add multiple key support for completion key
2016-01-10 12:01:06 -07:00
Sibi Prabakaran
0510da7659 Add changelog for the patch. 2016-01-10 23:17:00 +05:30
Sibi Prabakaran
93b2620ad3 Add myself in mailmap 2016-01-10 23:17:00 +05:30
Sibi Prabakaran
727e214195 Add multiple key support for completion key
This patch enables support for key binding like Ctrl + i which was not
previously possible. Technically, this changes the type of completionKey
from KeySym to (KeyMask, KeySym).
2016-01-10 23:17:00 +05:30
Bogdan Sinitsyn
9a7a63bfb4 improve documentation for X.Prompt 2016-01-08 20:58:56 +03:00
Bogdan Sinitsyn
a61ce8dd74 improve documentation for X.Prompt 2016-01-08 20:29:45 +03:00
Bogdan Sinitsyn
d638dc8b0a fix xmonad/xmonad#21 2016-01-03 12:41:15 +03:00
Bogdan Sinitsyn
bce9c551ef fix CenteredAt in X.Prompt 2016-01-01 00:22:45 +03:00
Bogdan Sinitsyn
26309d1622 improve CenteredAt in X.Prompt 2015-12-31 23:51:03 +03:00
Bogdan Sinitsyn
d81b4e5bcb add documentation for XPPosition in X.Prompt 2015-12-31 23:36:07 +03:00
Bogdan Sinitsyn
6043914841 fix border between prompt and completions in X.Prompt 2015-12-31 16:03:00 +03:00
Bogdan Sinitsyn
ed7be9a791 fix border between prompt and completion window in X.Prompt 2015-12-31 15:57:36 +03:00
Bogdan Sinitsyn
becb724f95 fix prompt width 2015-12-28 19:37:52 +03:00
Bogdan Sinitsyn
0447c76d48 change documentation 2015-12-28 15:19:02 +03:00
Bogdan Sinitsyn
e47794148c fix border drawing 2015-12-28 15:14:35 +03:00
Bogdan Sinitsyn
edd6b8be55 add customization for prompt position 2015-12-28 14:49:36 +03:00
Bogdan Sinitsyn
ddcf5abcbf fix swapNth' 2015-12-23 09:28:18 +03:00
Bogdan Sinitsyn
e19460677a fix swapNth' 2015-12-23 09:16:01 +03:00
Adam Vogt
b23f56d65d clean up `git shortlog' output 2015-12-22 16:42:06 -05:00
Brent Yorgey
c3b05ceb7f travis: comment out cabal check for now
It complains about the -Werror enabled by the 'testing' flag,
even though the testing flag is set to manual: True, default: False
2015-12-22 07:51:37 -06:00
Brent Yorgey
9f68077c6c .cabal: remove outdated flag
xmonad no longer supports GHC 6.10, and the -O0 was causing
cabal to generate a warning.
2015-12-22 07:39:06 -06:00
Brent Yorgey
723494f01e travis: build xmonad from HEAD 2015-12-22 07:35:05 -06:00
Brent Yorgey
ae6b8db29b Update lower bounds for containers and base
Closes #28.
2015-12-22 07:31:36 -06:00
Brent Yorgey
1ce26e8cd2 .cabal: make testing flag manual 2015-12-21 13:15:00 -06:00
Brent Yorgey
cc7ddcfa60 Merge pull request #25 from iblech/patch-1
Fix tiny markup typo
2015-12-18 14:11:11 -06:00
Brent Yorgey
02ddfebf05 Merge pull request #26 from pjones/release-0.12
Release 0.12
2015-12-18 11:22:32 -06:00
Daniel Wagner
800ae670e2 use a record pattern to be robust against additions to the X11 library 2015-12-15 07:44:36 -08:00
Peter Jones
093352f6c5 Finial tweaks before release 2015-12-14 13:30:55 -07:00
Ingo Blechschmidt
fa3e774a65 Fix tiny markup typo 2015-12-14 16:24:16 +01:00
Peter Jones
126ce6f3c9 Update development references (darcs, code.google.com, etc.)
* All references to darcs have been updated to git

  * Most Google Code references have been changed to GitHub

  * References to specific issues at code.google.com have been left
    alone

  * Updated the GenerateManpage.hs to work with the latest version of
    pandoc
2015-12-11 11:17:26 -07:00
Peter Jones
c98f2b16db Add change log entries for recent merges 2015-12-11 10:31:58 -07:00
Peter Jones
0d6c2b1668 Use a table format that works with Pandoc and GitHub 2015-12-11 09:49:52 -07:00
Peter Jones
5739da65b3 Added more detail to the change log
* Brought in changes from https://wiki.haskell.org/Xmonad/Notable_changes_since_0.11

  * List all new modules along with their description
2015-12-11 09:49:52 -07:00
Peter Jones
4d3f633c73 Reformat README.md, add CHANGES.md, update xmonad-contrib.cabal 2015-12-11 09:49:52 -07:00
Peter Jones
6177841488 Rename the REAME file for GitHub/Hackage 2015-12-11 09:49:52 -07:00
f1u77y
d81c48d022 fix #14 2015-12-11 16:42:14 +03:00
Brent Yorgey
b9b4f4af07 Merge pull request #19 from kurnevsky/move_history_bugfix
Bugfix for moveHistory when alwaysHighlight is enabled.
2015-12-10 21:35:15 -06:00
Brent Yorgey
8e532562e7 X.P.Shell: fix shadowing warning 2015-12-10 21:08:38 -06:00
Brent Yorgey
e521d6546f X.A.Search: fix missing type sig warning 2015-12-10 21:07:24 -06:00
Brent Yorgey
dfeed762d4 Merge pull request #11 from pjones/projects
New module: XMonad.Actions.DynamicProjects
2015-12-10 20:55:42 -06:00
David Unric
0d4439b7a7 stop ignoring Prompt.Shell searchPredicate
Closes #9.

See also https://code.google.com/p/xmonad/issues/detail?id=393 .
2015-12-10 20:50:38 -06:00
Kurnevsky Evgeny
09f3c3fbea Bugfix for moveHistory when alwaysHighlight is enabled. 2015-12-09 17:50:15 +03:00
Brent Yorgey
6ae90737de Merge pull request #10 from pjones/dirfix
NixOS does not have /bin/bash
2015-12-08 21:25:41 -06:00
Brent Yorgey
1c61f3cf05 Merge pull request #5 from kurnevsky/master
Add layout hook for ScreenCorners.
2015-12-08 21:24:02 -06:00
Kurnevsky Evgeny
dfb1c52c66 Add layout hook for ScreenCorners. 2015-12-08 08:39:55 +03:00
Peter Jones
f35083da9f Don't auto-delete workspaces
* Previously I was removing empty workspaces after switching away from
    them, but this seemed to cause a bug when workspaces were defined
    statically in your XMonad configuration.

  * Next up: a function to delete an existing project.
2015-12-02 20:07:57 -07:00
Brent Yorgey
dc5fbfecc4 Merge pull request #12 from psibi/add-search-engine
Add Stackage and Vocabulary as new search engines.
2015-12-02 16:56:24 -06:00
Brent Yorgey
8cc31b5c76 Merge pull request #15 from nikolas/patch-1
Fix typo in Monitor layout description
2015-12-02 15:49:18 -06:00
Peter Jones
ea8e0ea7b6 Add renameProjectPrompt, fix directory prompting completion 2015-12-01 12:08:52 -07:00
Nik Nyby
62dac9ccd2 Fix typo in Monitor layout description 2015-11-30 20:10:17 -05:00
Peter Jones
60922e0cae Remove unnecessary call to XS.modify 2015-11-30 12:54:06 -07:00
Sibi Prabakaran
9eb55c76ea Add Stackage and Vocabulary as new search engines. 2015-11-22 15:10:14 +05:30
Peter Jones
08c88abfb2 Fix a small space leak in DynamicProjects
Add a couple of strictness annotations to keep ExtensibleState from
building up thunks.
2015-11-18 13:53:31 -07:00
Peter Jones
b1360f08d0 Fix warnings from hlint 2015-11-16 13:12:49 -07:00
Peter Jones
3b9c6d6ff2 New module: XMonad.Actions.DynamicProjects 2015-11-16 11:51:31 -07:00
Peter Jones
6f0a9785d6 NixOS does not have /bin/bash 2015-11-16 10:10:34 -07:00
Brent Yorgey
dbfd81b3f9 add generated .travis.yml 2015-11-06 14:51:52 -06:00
Brent Yorgey
e6350c91b8 .cabal: update tested-with field 2015-11-06 14:51:15 -06:00
geekosaur
32f3fbdb2f Merge pull request #2 from vrs/master
X.H.DynamicLog: make xmobarStrip actually strip xmobar tags
2015-09-11 17:03:05 -04:00
geekosaur
62e40287a6 Merge pull request #1 from 0/dynamic-bars
Use existing connection in X.H.DynamicBars
2015-09-11 17:01:22 -04:00
vrs
0a7ae19f90 X.H.DynamicLog: make xmobarStrip actually strip xmobar tags
consider the old implementation:
> xmobarStrip "<<fc=#f00>fc=#f00>foo</</fc>fc>"
"<fc=#f00>foo</fc>"
2015-09-07 22:59:38 +02:00
Dmitri Iouchtchenko
42a69bfa98 Use existing connection in X.H.DynamicBars
Adapted from patch attributed to geekosaur
(https://code.google.com/p/xmonad/issues/detail?id=538).
2015-08-24 01:56:46 -04:00
brandon s allbery kf8nh
05f3eb17f5 Add .gitignore
Shamelessly ganked from cabal.
2015-08-22 14:01:56 -04:00
Tuncer Ayaz
d26da8e63a Fix 7.10.2 compile 2015-06-17 19:09:33 +00:00
Brent Yorgey
c1db249147 X.A.WorkspaceNames: convert tabs to spaces, cleanup 2015-06-03 14:20:27 +00:00
Antoine Eiche
bbf36809e9 XMonad.Actions.WorkspaceName.workspaceNamePrompt is XMonad.Prompt.Workspace.workspacePrompt acting on the workspace name. 2015-06-01 09:32:53 +00:00
anton.pirogov at gmail . com
c4b3895af6 BinarySpacePartition: make all actions work on nodes, add MoveNode feature 2015-05-07 09:08:42 +00:00
allbery.b
e41d7135a9 ewmh-hook-order
Reorder the application of hooks so that users' config is honored.
Notably, this means setWMName works in startupHook instead of
needing to do it repeatedly in logHook.
2015-04-23 15:44:36 +00:00
ezyang
f7f87c03cb Add XMonad.Layout.PerScreen 2015-05-02 04:53:53 +00:00
Adam Vogt
0d061462c7 make X.A.Plane example config actually compile 2015-04-24 01:22:09 +00:00
Adam Vogt
08beff45b9 address warnings 2015-04-14 19:48:38 +00:00
allbery.b
d3ffb1661a dynamicproperty
Run a ManageHook from handleEventHook when a window property changes.
You would use this to match e.g. browser windows whose title is not
"final" until after the on-load hooks of the loaded document complete.
2015-04-14 15:36:57 +00:00
Daniel Wagner
33c0e81a4a minor doc fixes to X.C.Mate 2015-03-30 18:07:52 +00:00
allbery.b
b5b8558acc mate-comment-fixup
Correct the docstrings / comments in X.C.Mate, which still referenced
gnomeConfig. Also update the session manager configuration to use
dconf and a current (on Mint at least) path for the session config.
2015-03-30 16:05:23 +00:00
Peter Jones
c2f00b8e61 Add the ability to specify padding used with Maximize 2015-03-09 23:29:39 +00:00
Peter Jones
a0cd3f92e5 Don't restore windows when changing workspaces 2015-03-10 20:17:09 +00:00
Peter Jones
e2e63440ee New layout modifier: Hidden
A layout modifer that is meant to work with the BinarySpacePartition
layout.  By removing windows from the window set and adding them back
at a later time, you can move windows to a different branch of the BSP
tree.
2015-03-09 22:30:36 +00:00
anton.pirogov
cf5739a484 Fixes to warnings with BSP layout 2015-03-15 10:00:41 +00:00
anton.pirogov
37f47d0bcb Improved BinarySpacePartition, added Equalize,Balance and FocusParent and mouse resize support 2015-03-12 14:52:20 +00:00
nzeh
00187576db New layout module X.L.Dwindle
This adds three layouts:  Spiral is a reimplementation of X.L.Spiral.spiral
with a (to me) more intuitive splitting policy.  Dwindle is similar but pushes
the smaller windows into a corner rather than into the center.  Squeeze just
stacks windows vertically or horizontally using geometrically decreasing sizes.
2015-03-15 13:09:13 +00:00
Adam Vogt
466f184c65 address warnings in P.Pass 2015-03-13 01:56:36 +00:00
ankaan
c8c5d28a9c X.L.AvoidFloats more useful default settings
Changed default settings with the simple layout modifier. Instead of asking for a bool indicating if all windows should be avoided, no such bool is asked for. No windows are avoided by default. I think this will be a more useful default setting since it would be annoying if dialogue windows are avoided. The same functionality is possible with the advanced constructor. This will be easier for new users.

This will break configurations using the old module, but this will not be much of an issue since the module has not been added to the repo as of this writing.
2015-03-10 21:20:22 +00:00
ankaan
3405d561b8 Resolve minor conflict in xmonad-contrib.cabal 2015-03-06 17:54:36 +00:00
ankaan
b2531a6f48 X.L.AvoidFloats, like avoidStruts but for floats
Checks for floating windows within the layout area and finds a maximum area
rectangle within that does not overlap with any of the floating windows.
This rectangle is used for all non-floating windows.

This new functionality introduced problems with the recommended configuration
of one of my other modules (X.A.FloatSnap.) A new and more reliable method of
distinguishing between clicks and drags where therefore introduced in the new
module X.A.AfterDrag.

This does not break any prior use of FloatSnap, but will require changes in
configuration if used together with AvoidFloats. (This is mentioned in the
docs for AvoidFloats and I recommend using the new configuration method even if
AvoidFloats is not in use.)
2015-03-06 17:17:02 +00:00
ankaan
16db912751 X.L.LayoutBuilder place active on top
Make sure that the active layout area is placed on top of all other areas when placing windows. This makes overlapping areas usable.
2015-03-06 16:42:00 +00:00
Dmitri Iouchtchenko
2f5e49919d Add rearrangers to X.A.GridSelect 2013-01-23 04:40:38 +00:00
Dmitri Iouchtchenko
2e1474f230 Avoid repainting elements in X.A.GridSelect 2013-01-23 04:38:50 +00:00
Dmitri Iouchtchenko
e98f0657bb Give a name to the initial state in X.A.GridSelect 2013-01-21 06:13:24 +00:00
Adam Vogt
45e4bd4ff6 Add XMonad.Config.Bepo (Yorick Laupa) 2015-03-10 21:43:14 +00:00
Adam Vogt
8ba4e0bed2 add instance Default WallpaperConf 2015-03-10 21:42:46 +00:00
Joachim Breitner
88fd1dd4fb XMonad.Prompt.Pass: Handle hierachical password stores
pass stores its passwords in directories, so the contents of the directory
store needs to be enumerated recursively. Alexander Sulfrian provided this
patch on the mailinglist, which I tested (it works) and cleaned up slightly.
2015-02-18 09:18:16 +00:00
Adam Vogt
9bb1f3b91e remove warnings and text dependency from H.WallpaperSetter 2015-03-10 19:29:33 +00:00
anton.pirogov
dcbff492fe Added the new hook WallpaperSetter 2015-02-28 16:23:35 +00:00
Adam Vogt
d82bfc6baf adjust an import to fix the build 2015-03-10 18:24:03 +00:00
Adam Vogt
e4fde08a0a merge conflicts in X.L.Spacing
I should have just applied Anton Pirogov March 4 patch.
2015-03-10 18:20:46 +00:00
anton.pirogov
0857f71938 Added messages to adjust the gap dynamically 2015-03-04 08:25:20 +00:00
Adam Vogt
80348bb4b7 X.L.Spacing needs -XPatternGuards now 2015-03-10 18:12:48 +00:00
Adam Vogt
c1abaa0183 add ConfirmPrompt (Antoine Beaupré) 2015-03-10 18:10:36 +00:00
anton.pirogov
20e69af48b Added messages to adjust the gap dynamically 2015-03-03 21:01:43 +00:00
Adam Vogt
6cbddae8c2 add another extension to actually fix the build with ghc-7.10-RC1 2015-01-24 11:19:39 +00:00
benweitzman
19860e2fa0 BinarySpacePartition downstream changes
Pulled in changes from my repo for this layout on github (https://github.com/benweitzman/BinarySpacePartition)
Includes a new mode for resizing windows in a more intuitive way, also contains a bug fix that was preventing users from
resiving a window up.

Includes changes from github users egasimus (Adam Avramov) and SolitaryCipher (Nick)
2014-11-10 20:22:59 +00:00
Adam Vogt
c115650d0d add XF86AudioMicMute to EZConfig (#582) 2014-12-22 04:53:06 +00:00
nrujac
5816a473dd Generalize new workspace addition functions to support arbitrary insertion.
The current DynamicWorkspaces module only supports adding new workspaces
at the start of the list of workspaces. This means when binding workspaces
to keys based on the position in the list, key bindings can change 
as workspaces are added in removed in a far more destructive way than
necessary. Instead, supporting appending and arbitrary insertion allows
the user to determine where the new workspace should be added.

This patch is a straight generalization of the addHiddenWorkspace' function.
Rather than always using `(:)` to insert the new workspace into the list
of workspaces, this patches causes it to use an arbitrary list insertion
function instead. A few new functions are added to prevent breakage of
external code while exported functions are left unchanged.

List of new functions:
  appendWorkspace
  appendWorkspacePrompt
  addWorkspaceAt
  addHiddenWorkspaceAt

Existing functions were modified to call their generalized brethren where possible
without changing functionality. This patch should not change behavior for any
existing users of this module.
2014-12-19 00:23:09 +00:00
Adam Vogt
0903f339b6 address another bitSize/finiteBitSize warning 2014-12-22 03:33:00 +00:00
Anton Vorontsov
201c25e7a4 X.L.Master: Add FixMaster layout modifier
This layout modifier is useful for the case if you desire to add a master
pane that has fixed width (it's fixed even if there is just one window
opened). Especially nice feature if you don't want to have too wide
terminal in a master pane.

The layout is implemented as an addition to Master layout, so it reuses
most of the code.
2014-12-20 01:13:39 +00:00
Adam Vogt
3b6d0c2458 filepath dependency for P.Pass was left out 2014-12-21 21:41:29 +00:00
Adam Vogt
7dac12829d remove unused imports 2014-08-15 05:12:34 +00:00
Adam Vogt
6d33617e1c fix build with ghc-6.12 2014-08-15 05:12:14 +00:00
Adam Vogt
8a195a2a48 use FiniteBitSize with ghc >= 7.8 2014-08-15 05:11:36 +00:00
Felix Crux
6c410a8a00 Layout.Spacing: Outer window edges now get as much spacing as inner ones
Layout.Spacing applies a customizable amount of space around the outside of each
window. At window edges where two windows meet, the total distance between them
is therefore twice the customized value (one space value from each window). At
the edge of the screen, however, the spacing is only applied once. This results
in uneven amounts of spacing and differently-sized gaps on the screen.

This patch extends the Spacing layout to include a further gap all around the
edge of the screen, thus making all spaces around windows equal in size.
2014-12-19 22:36:46 +00:00
Adam Vogt
95365822da add filepath package dependency needed by Prompt.Pass
filepath comes with ghc, and it's used by xmonad-core anyways
2014-09-09 14:52:16 +00:00
Devin Mullins
d0039a2f8b X.C.Prime: doc tweaks 2014-10-02 07:59:39 +00:00
Devin Mullins
c648a3959b X.A.Navigation2D: add convenience functions for setting config & keybindings
1. Added 'additionalNav2DKeys' which adds keybindings for the cartesian product
   of direction keys and (modifier, action) pairs given.
2. Added 'navigation2D' which combines that with 'withNavigation2DConfig'.
3. Added 'additionalNav2DKeysP' and 'navigation2DP' which do the same, but use
   the 'additionalKeysP' syntax.
2014-10-02 07:57:57 +00:00
Devin Mullins
0f21017370 X.C.Prime: doc fixes 2014-10-01 07:58:55 +00:00
Devin Mullins
6c96f4d5c6 X.C.Prime: add 'withScreens' and friends
The screen equivalent of 'withWorkspaces' lets you more easily define keys that
move/swap between screens.

Also, rename wsKeyspecs to wsKeys, and make a couple of doc tweaks.
2014-10-01 07:52:50 +00:00
Anton Vorontsov
27f4d5dafe Implement proper handling of dynamically changing hostname
The module implements a proper way of finding out whether the window is
remote or local.

Just checking for a hostname and WM_CLIENT_MACHINE being equal is often
not enough because the hostname is a changing subject (without any
established notification mechanisms), and thus WM_CLIENT_MACHINE and the
hostname can diverge even for a local window.

This module solves the problem. As soon as there is a new window created,
we check the hostname and WM_CLIENT_MACHINE, and then we cache the result
into the XMONAD_REMOTE property.

Notice that XMonad itself does not know anything about hostnames, nor does
it have any dependency on Network.* modules. For this module it is not a
problem: you can provide a mean to get the hostname through your config
file (see usage). Or, if you don't like the hassle of handling dynamic
hostnames (suppose your hostname never changes), it is also fine: this
module will fallback to using environment variables.
2014-09-01 07:21:58 +00:00
Anton Vorontsov
b2a885fe5a Add Stoppable layout for power saving
This module implements a special kind of layout modifier, which when
applied to a layout, causes xmonad to stop all non-visible processes. In a
way, this is a sledge-hammer for applications that drain power. For
example, given a web browser on a stoppable workspace, once the workspace
is hidden the web browser will be stopped.

Note that the stopped application won't be able to communicate with X11
clipboard. For this, the module actually stops applications after a
certain delay, giving a chance for a user to complete copy-paste sequence.
By default, the delay equals to 15 seconds, it is configurable via
'Stoppable' constructor.

The stoppable modifier prepends a mark (by default equals to "Stoppable")
to the layout description (alternatively, you can choose your own mark and
use it with 'Stoppable' constructor). The stoppable layout (identified by
a mark) spans to multiple workspaces, letting you to create groups of
stoppable workspaces that only stop processes when none of the workspaces
are visible, and conversely, unfreezing all processes even if one of the
stoppable workspaces are visible.

To stop the process we use signals, which works for most cases. For
processes that tinker with signal handling (debuggers), another
(Linux-centric) approach may be used. See
https://www.kernel.org/doc/Documentation/cgroups/freezer-subsystem.txt
2014-09-01 07:21:41 +00:00
Devin Mullins
12ec2d0be4 X.C.Prime: doc changes 2014-09-25 20:30:37 +00:00
Devin Mullins
74c3f059b0 X.C.Prime: add withWorkspaces et al.
This allows easier configuration of workspaces and their keybindings. Required
generalizing the 'Prime' type, so lots of other lines changed in rather trivial
ways.
2014-09-25 20:30:34 +00:00
Devin Mullins
cbcd42dc83 X.C.Prime: add ifThenElse binding
This is necessary for if-then-else support in the user's config.
2014-09-24 19:15:09 +00:00
Devin Mullins
c5290be3c8 X.C.Prime: doc fixes 2014-09-15 08:06:01 +00:00
Devin Mullins
972ee2c19f X.C.Prime: fix 'def' hyperlink in doc 2014-09-14 07:53:52 +00:00
Devin Mullins
babbd208a6 XMonad.Config.Prime, a do-notation for config
Note that the use of RebindableSyntax is because of the need to vary the
layoutHook type throughout the config. The alternative, using the existential
Layout type, was rejected because it required TemplateHaskell in order to look
nice, and TemplateHaskell is not portable.

I've tried to make a version of (>>) that also worked on normal monads, but
have had no luck as of yet. Maybe some intrepid soul can add it later.
2014-09-14 06:48:28 +00:00
me
4ef0beab55 X.P.Shell: fix doc typo 2013-03-17 11:55:16 +00:00
nwfilardo
c073651cc2 reverse workspaces, so that switching to a dynamic workspace group restores the focus to the screen that was focused at group creation time 2014-09-13 17:41:18 +00:00
me
4efaa673fe add filepath dependency, needed by new X.P.Pass module 2014-09-13 07:09:26 +00:00
eniotna.t
9f453fdb58 add-new-xmonad-prompt-pass
This module provides 3 <XMonad.Prompt> to ease passwords manipulation (generate, read, remove):

- one to lookup passwords in the password-storage.

- one to generate a password for a given password label that the user inputs.

- one to delete a stored password for a given password label that the user inputs.

All those prompts benefit from the completion system provided by the module <XMonad.Prompt>.

The password store is setuped through an environment variable PASSWORD_STORE_DIR.
If this is set, use the content of the variable.
Otherwise, the password store is located on user's home @$HOME\/.password-store@.


Source:

- The password storage implementation is <http://git.zx2c4.com/password-store the password-store cli>.

- Inspired from <http://babushk.in/posts/combining-xmonad-and-pass.html>
2014-08-29 13:19:28 +00:00
Adam Vogt
6137b1e2ff use Data.Map instead of Data.Map.Strict to support containers < 0.5 2014-08-15 04:31:41 +00:00
allbery.b
7d4a083906 config-mate
Initial support for the Mate desktop environment (http://mate-desktop.org).
Based on existing Gnome 2 support, since Mate is a maintained fork of
Gnome 2.
2014-08-03 02:06:59 +00:00
allbery.b
56c6b9fef5 debug-managehook
A set of hooks, and convenience combinators, to help with ManageHook debugging.
Ordinary users may well want to use debugManageHookOn in normal configs,
specifying a key sequence which can be pressed before running a command in
order to capture debug information just for that command's main window.

This is especially useful when trying to diagnose issues such as programs
that do not play well with SpawnOn, or ManageHook matching on 'title' when
the program does not set the window title until after it is mapped.
2014-08-03 02:06:01 +00:00
allbery.b
ec0fb3ba8a debug-debug
Various fixes and enhancements to DebugWindow and DebugStack. ManageDebug
requires these fixes, but some of them are significant even if not using
ManageDebug.
2014-08-03 02:05:30 +00:00
Adam Vogt
11265ad69b derive Applicative instances to suppress AMP warning 2014-07-10 16:39:50 +00:00
Adam Vogt
8ff856a761 clean up cabal file and drop support for base < 3 2014-07-10 01:32:55 +00:00
eniotna.t
1173c6c54f add-duck-duck-go-search-engine 2014-06-17 17:42:46 +00:00
gwern
eca9d7318e XSelection: getSelection: fix connection exhaustion bug (issue #573); include warning 2014-06-01 02:50:19 +00:00
md143rbh7f
72a537cf46 Fix dbus-send call in XMonad.Config.Gnome
dbus-send --print-reply=string is invalid, but it was silently ignored until recently:
http://cgit.freedesktop.org/dbus/dbus/commit/tools/dbus-send.c?id=c690ee4351f99ed5e629ffcf5f4a2edcd418d103
I've changed XMonad.Config.Gnome to run --print-reply=literal, since that's what the old behavior was.
2014-01-29 03:21:14 +00:00
Adam Vogt
2f44f16fac warning police (unused variables) 2014-05-05 00:12:42 +00:00
linxray
2b7add99aa This patch makes the Ssh extension works with **user** arguments in ssh, .e.g ssh admin@localhost. 2014-05-04 09:11:20 +00:00
Adam Vogt
c9b63a8f40 remove trailing whitespace in L.BinarySpacePartition 2014-05-01 01:19:43 +00:00
Adam Vogt
fb7ca05a63 replace Bound with the equivalent Direction2D 2014-05-01 01:15:40 +00:00
Adam Vogt
fcf0545475 remove unused extension in BSP 2014-05-01 01:14:55 +00:00
benweitzman
ec56f2c47c Add BinarySpacePartition layout 2014-04-30 20:58:48 +00:00
Brent Yorgey
25b9a25925 X.Actions.DynamicWorkspaceGroups: export new function addRawWSGroup 2014-04-28 14:29:01 +00:00
Adam Vogt
6a2ad3f1ee Remove unneeded context with the IfMax layout instance
Extra constraints on instances are about as useful as -XDataTypeContexts
2014-04-22 22:11:05 +00:00
nrujac
e2ff50687e Adding side tabs and replacing TabbarLocation with Direction2D. 2014-02-19 20:08:11 +00:00
Daniel Wagner
fb3b9f59e4 warning police 2014-03-16 18:37:47 +00:00
Dmitry Bogatov
ca9961c1ca New module: XMonad.Util.WindowState
Save almost arbitary data per window
2014-02-18 10:02:29 +00:00
nrujac
0f6bed2ff7 Add side tabs to the tabbed layout. 2014-02-13 21:52:47 +00:00
cwills.dev
c1b8674aa0 SpawnNamedPipe hlint cleanup 2014-02-02 21:36:13 +00:00
cwills.dev
d88153d3be document and cleanup SpawnNamedPipe 2014-02-02 21:10:00 +00:00
cwills.dev
6b46603147 Added SpawnNamedPipe 2014-02-02 14:34:15 +00:00
md143rbh7f
9403542db0 Make commandToComplete in XMonad.Prompt.Shell complete last word
The following change from 2013-02-09 breaks shell completion for me:
    hunk ./XMonad/Prompt/Shell.hs 65
    +    commandToComplete _ c = c

It seems to be passing the entire string into compgen in order to get the file completions, but it should only pass the last word. I propose reverting this change. Comments are appreciated.
2014-01-30 20:00:50 +00:00
Daniel Wagner
35ed0601f4 expose and document X.L.IndependentScreens.marshallSort 2014-01-28 21:28:44 +00:00
Adam Vogt
df824edf5f ServerMode properly indent 2013-12-19 20:14:40 +00:00
Adam Vogt
78ed2e1a9e remove ServerMode tabs 2013-12-19 20:10:00 +00:00
Adam Vogt
f453a9a375 fix -Wall ServerMode 2013-12-19 18:10:30 +00:00
Adam Vogt
c6b91b546e documentation note that ServerMode is similar to wmctrl 2013-12-19 18:07:48 +00:00
polson2
7ccac6a9a0 Generalized XMonad.Hooks.ServerMode 2013-12-16 02:51:00 +00:00
Ilya Portnov
f10a18670a IfMax-Layout
This adds a new ("conditional") layout, IfMax, which simply runs one layout, if there are <= N windows, and else runs another layout.
2013-12-01 07:26:34 +00:00
Adam Vogt
ab3f5b3d5d fix UrgencyHook and add filterUrgencyHook 2013-09-24 22:47:38 +00:00
Adam Vogt
075b7d69ed export XMonad.Hooks.UrgencyHook.clearUrgency (issue 533) 2013-09-23 03:13:49 +00:00
Daniel Wagner
95372520bb minor documentation fix: manageDocks doesn't do anything with struts, so don't claim it does 2013-08-14 12:51:06 +00:00
Daniel Wagner
0906634f3a don't pretend to be LG3D in X.C.Dmwit because this confuses modern GTK 2013-08-13 21:16:36 +00:00
Liyang HU
fd23bd692b XMonad.Actions.UpdatePointer: generalise updatePointer 2013-07-30 07:10:07 +00:00
Liyang HU
2fe30c6730 XMonad.Actions.UpdatePointer: document TowardsCentre 2013-07-30 05:37:46 +00:00
Adam Vogt
8f712f0a04 Haddock formatting in H.Minimize 2013-07-23 15:56:58 +00:00
Adam Vogt
1a916d1c57 Bump version (and xmonad dependency) to 0.12
This makes a breakage due to missing patches in core a bit more obvious.
Previously you would have a build failure regarding some missing identifiers
(def re-exported by XMonad from Data.Default), while after applying this patch
it will be clear that xmonad-core needs to be updated.
2013-07-20 20:58:57 +00:00
Adam Vogt
7246defb90 Fix issue 551 by also getting manpath without -g flag.
Instead of taking Ondrej's approach of figuring out which man (man-db or
http://primates.ximian.com/~flucifredi/man/) is used by the system, just try
both sets of flags.
2013-07-16 03:05:36 +00:00
Adam Vogt
d3b2a01e3d Escape dzen markup and remove xmobar tags from window titles by default.
The issue was that window titles, such as those set by, for example a browser,
could set the window title to display something like

   <action=malicious shell command>normal title</action>

Which could be executed by xmobar (or dzen).

This adds a ppTitleSanitize which does the above functions. This way when users
override ppTitle, the benefits are not lost.

Thanks to Raúl Benencia and Joachim Breitner for bringing this to my attention.
2013-07-08 14:48:13 +00:00
gopsychonauts
129e98773e DynamicBars-use-ExtensibleState
Hooks.DynamicBars was previously using an MVar and the unsafePerformIO hack (
http://www.haskell.org/haskellwiki/Top_level_mutable_state ) to store bar
state. Since ExtensibleState exists to solve these sorts of problems, I've
switched the file over to use unsafePerformIO instead.

Some functions' types had to be changed to allow access to XState, but the
public API is unchanged.
2013-06-18 07:47:55 +00:00
Thomas Tuegel
7958f8905e Catch exceptions when finding commands on PATH in Prompt.Shell 2013-06-16 23:02:19 +00:00
Adam Vogt
646090a3d9 Fix haddock parse error in X.A.LinkWorkspaces 2013-05-28 13:34:48 +00:00
Daniel Wagner
0f1b6fb772 use Data.Default wherever possible, and deprecate the things it replaces 2013-05-28 01:39:09 +00:00
Daniel Wagner
daa2731d3d eliminate references to defaultConfig 2013-05-28 00:58:25 +00:00
Daniel Wagner
0287b2861c minimal change needed to get xmonad-contrib to build with xmonad's data-default patch 2013-05-28 00:10:40 +00:00
Francesco Ariis
e8259ebd43 Remove unneeded XSync call in Layout.ShowWName 2013-05-17 15:33:41 +00:00
Adam Vogt
12b91b9630 Remove misleading comment: we definitely don't support ghc-6.6 anymore 2013-05-14 21:58:51 +00:00
Adam Vogt
546b582a3d Fix module name in comment of X.L.Fullscreen 2013-05-14 21:57:27 +00:00
Adam Vogt
91a5d13005 Minor update to cabal file (adding modules & maintainership) 2013-05-14 21:56:32 +00:00
Adam Vogt
31ec8cc26a Remove trailing whitespace in X.A.LinkWorkspaces 2013-05-14 21:54:21 +00:00
quesel
0fcb4ae238 Update documentation of LinkWorkspaces Module 2011-03-28 07:28:13 +00:00
quesel
3722f48da9 Added a module for linking workspaces
This module provides a way to link certain workspaces in a multihead setup.
That way, when switching to the first one the other heads display the linked
workspaces.
2011-02-10 16:50:18 +00:00
Adam Vogt
00be056a1b Cache results from calcGap in ManageDocks
http://www.haskell.org/pipermail/xmonad/2013-April/013670.html
2013-04-25 15:58:11 +00:00
Adam Vogt
eae925fc29 Remove unnecessary contexts from L.MultiToggle 2013-02-17 16:33:56 +00:00
gopsychonauts
faa61bbbab Generalises modWorkspace to take any layout-transforming function
modWorkspace already was capable of modifying the layout with an arbitrary
layout -> layout function, but its original type restricted it such that it
could only apply a single LayoutModifier; this was often inconvenient, as for
example it was not possible simply to compose LayoutModifiers for use with
modWorkspace.

This patch also reimplements onWorkspaces in terms of modWorkspaces, since with
the latter's less restrictive type this is now possible.
2013-05-01 15:14:25 +00:00
Daniel Wagner
ac8aefbc92 since XMonad.Config.Dmwit mentions xmobar, we should include the associated .xmobarrc file 2013-05-03 19:40:55 +00:00
Daniel Wagner
469ff726a4 warning police 2013-05-02 01:27:00 +00:00
Daniel Wagner
e11d97137e XMonad.Config.Dmwit 2013-05-02 01:21:32 +00:00
Daniel Wagner
a56a135313 minor fixes to the haddock markup in X.L.IndependentScreens 2013-04-11 19:38:49 +00:00
Daniel Wagner
faf0997881 add whenCurrentOn to X.L.IndependentScreens 2013-04-08 22:52:51 +00:00
Paul Fertser
7dda5f976f Allow to specify the initial gaps' states in X.L.Gaps 2013-02-22 07:22:32 +00:00
Daniel Wagner
493db20cf0 should bump X11 dependency, too, to make sure we have getAtomName 2013-02-25 18:05:27 +00:00
Daniel Wagner
5c04a573db getAtomName is now defined in the X11 library 2013-02-25 18:03:23 +00:00
Paul Fertser
8bfe148416 Allow to limit maximum row count in X.Prompt completion window
On a keyboard-less device (such as a smartphone), where one has to use
an on-screen keyboard, the maximum completion window height must be
limited to avoid overlapping the keyboard.
2013-02-21 12:20:50 +00:00
Adam Vogt
945714f250 Note in U.NameActions that xmonad core can list default keys now 2013-02-17 23:30:26 +00:00
Adam Vogt
10ee484a59 Export U.NamedActions.addDescrKeys per evaryont's request. 2013-02-17 23:26:19 +00:00
Maarten de Vries
7e9c986217 Add EWMH DEMANDS_ATTENTION support to UrgencyHook.
Add support for the _NET_WM_STATE_DEMANDS_ATTENTION atom
by treating it the same way as the WM_HINTS urgency flag.
2013-02-12 18:12:29 +00:00
Adam Vogt
0aeef31c5d Unconditionally set _NET_WORKAREA in ManageDocks 2013-01-17 18:08:51 +00:00
c.lopez
34800741e5 spawn command when no completion is available (if alwaysHighlight is True); changes commandToComplete in Prompt/Shell to complete the whole word instead of using getLastWord 2013-02-09 19:04:56 +00:00
matthewhague
a45d8d38a6 order-unindexed-ws-last
Changes the WorkspaceCompare module's comparison by index to put workspaces without an index last (rather than first).
2012-07-03 22:27:26 +00:00
Adam Vogt
c0b0d52678 SpawnOn modification for issue 523
This moves the function to help clean up the `Spawner' to the ManageHook
rather than in functions like spawnOn. Probably it makes no difference, the
reason is because there's one manageSpawn function but many different so this
way there are less functions to write.
2013-01-14 01:46:42 +00:00
Adam Vogt
a33f355232 Update L.TrackFloating.useTransient example code
Suggest useTransient goes to the right of trackFloating which is the
configuration actually tested.
2013-01-12 04:12:39 +00:00
Adam Vogt
ced8f5e0f0 Adapt ideas of issue 306 patch to a new modifier in L.TrackFloating 2013-01-12 03:57:01 +00:00
Dmitri Iouchtchenko
498a50d109 Make X.A.CycleWS not rely on hidden WS order 2013-01-09 02:33:28 +00:00
Dmitri Iouchtchenko
5d93450b5e Add X.H.WorkspaceHistory 2013-01-09 02:33:07 +00:00
Dmitri Iouchtchenko
9b6ed4c505 Allow removing arbitrary workspaces 2012-12-31 21:43:43 +00:00
Dmitri Iouchtchenko
d83442b8eb Remove first-hidden restriction from X.A.DynamicWorkspaces.removeWorkspace' 2012-12-31 21:41:48 +00:00
Adam Vogt
78d44079c2 Add authorspellings file for `darcs show authors'.
This authorspellings file includes a couple people who've contributed to xmonad
(not XMonadContrib). When people have multiple addresses, the most recent one
has been picked.
2013-01-01 04:00:31 +00:00
342 changed files with 26369 additions and 6058 deletions

30
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,30 @@
### Problem Description
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 _full_ configuration file that reproduces
the problem you are experiencing:
```haskell
module Main (main) where
import XMonad
main :: IO ()
main = xmonad def
```
### Checklist
- [ ] I've read [CONTRIBUTING.md](https://github.com/xmonad/xmonad/blob/master/CONTRIBUTING.md)
- I tested my configuration
- [ ] With `xmonad` version XXX (commit XXX if using git)
- [ ] With `xmonad-contrib` version XXX (commit XXX if using git)

13
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,13 @@
### Description
Include a description for your changes, including the motivation
behind them.
### Checklist
- [ ] I've read [CONTRIBUTING.md](https://github.com/xmonad/xmonad/blob/master/CONTRIBUTING.md)
- [ ] I've considered how to best test these changes (property, unit,
manually, ...) and concluded: XXX
- [ ] I updated the `CHANGES.md` file

View File

@@ -0,0 +1,115 @@
Piggy-back on the haskell-ci workflow for automatic releases to Hackage.
This extends the workflow with two additional triggers:
* When a release is created on GitHub, a candidate release is uploaded to
Hackage and docs are submitted for it as Hackage can't build them itself
(https://github.com/haskell/hackage-server/issues/925).
* To make a final release, the workflow can be triggered manually by entering
the correct version number matching the version in the cabal file. This is
here because promoting the candidate on Hackage discards the uploaded docs
(https://github.com/haskell/hackage-server/issues/70).
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,17 @@
#
name: Haskell-CI
on:
- - push
- - pull_request
+ push:
+ pull_request:
+ release:
+ types:
+ - published
+ workflow_dispatch:
+ inputs:
+ version:
+ # releases to Hackage are final and cannot be reverted, thus require
+ # manual entry of version as a poor man's mistake avoidance
+ description: version (must match version in cabal file)
jobs:
linux:
name: Haskell-CI - Linux - ${{ matrix.compiler }}
@@ -28,6 +37,7 @@
include:
- compiler: ghc-9.0.1
allow-failure: false
+ upload: true
- compiler: ghc-8.10.4
allow-failure: false
- compiler: ghc-8.8.4
@@ -171,8 +181,66 @@
${CABAL} -vnormal check
- name: haddock
run: |
- $CABAL v2-haddock $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all
+ $CABAL v2-haddock $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH --haddock-for-hackage --builddir $GITHUB_WORKSPACE/haddock all
- name: unconstrained build
run: |
rm -f cabal.project.local
$CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
+ - name: upload artifacts (sdist)
+ if: matrix.upload
+ uses: actions/upload-artifact@v2
+ with:
+ path: ${{ github.workspace }}/sdist/*.tar.gz
+ - name: upload artifacts (haddock)
+ if: matrix.upload
+ uses: actions/upload-artifact@v2
+ with:
+ path: ${{ github.workspace }}/haddock/*-docs.tar.gz
+ - name: hackage upload (candidate)
+ if: matrix.upload && github.event_name == 'release'
+ run: |
+ set -ex
+ PACKAGE_VERSION="${PACKAGE_VERSION#v}"
+ curl \
+ --silent --show-error --fail \
+ --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/
+ curl \
+ --silent --show-error --fail \
+ -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
+ env:
+ HACKAGE_API_KEY: ${{ secrets.HACKAGE_API_KEY }}
+ PACKAGE_NAME: ${{ github.event.repository.name }}
+ PACKAGE_VERSION: ${{ github.event.release.tag_name }}
+ - name: hackage upload (release)
+ if: matrix.upload && github.event_name == 'workflow_dispatch'
+ run: |
+ set -ex
+ PACKAGE_VERSION="${PACKAGE_VERSION#v}"
+ curl \
+ --silent --show-error --fail \
+ --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/
+ curl \
+ --silent --show-error --fail \
+ -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
+ env:
+ HACKAGE_API_KEY: ${{ secrets.HACKAGE_API_KEY }}
+ PACKAGE_NAME: ${{ github.event.repository.name }}
+ PACKAGE_VERSION: ${{ github.event.inputs.version }}

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

@@ -0,0 +1,268 @@
# 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.12
#
# REGENDATA ("0.12",["github","cabal.project"])
#
name: Haskell-CI
on:
push:
pull_request:
release:
types:
- published
workflow_dispatch:
inputs:
version:
# releases to Hackage are final and cannot be reverted, thus require
# manual entry of version as a poor man's mistake avoidance
description: version (must match version in cabal file)
jobs:
linux:
name: Haskell-CI - Linux - ${{ matrix.compiler }}
runs-on: ubuntu-18.04
container:
image: buildpack-deps:bionic
continue-on-error: ${{ matrix.allow-failure }}
strategy:
matrix:
include:
- compiler: ghc-9.0.1
allow-failure: false
upload: true
- compiler: ghc-8.10.4
allow-failure: false
- compiler: ghc-8.8.4
allow-failure: false
- compiler: ghc-8.6.5
allow-failure: false
- compiler: ghc-8.4.4
allow-failure: false
fail-fast: false
steps:
- name: apt
run: |
apt-get update
apt-get install -y --no-install-recommends gnupg ca-certificates dirmngr curl git software-properties-common
apt-add-repository -y 'ppa:hvr/ghc'
apt-get update
apt-get install -y $CC cabal-install-3.4 libx11-dev libxext-dev libxft-dev libxinerama-dev libxrandr-dev libxss-dev
env:
CC: ${{ matrix.compiler }}
- name: Set PATH and environment variables
run: |
echo "$HOME/.cabal/bin" >> $GITHUB_PATH
echo "LANG=C.UTF-8" >> $GITHUB_ENV
echo "CABAL_DIR=$HOME/.cabal" >> $GITHUB_ENV
echo "CABAL_CONFIG=$HOME/.cabal/config" >> $GITHUB_ENV
HCDIR=$(echo "/opt/$CC" | sed 's/-/\//')
HCNAME=ghc
HC=$HCDIR/bin/$HCNAME
echo "HC=$HC" >> $GITHUB_ENV
echo "HCPKG=$HCDIR/bin/$HCNAME-pkg" >> $GITHUB_ENV
echo "HADDOCK=$HCDIR/bin/haddock" >> $GITHUB_ENV
echo "CABAL=/opt/cabal/3.4/bin/cabal -vnormal+nowrap" >> $GITHUB_ENV
HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\d+)\.(\d+)\.(\d+)(\.(\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')
echo "HCNUMVER=$HCNUMVER" >> $GITHUB_ENV
echo "ARG_TESTS=--enable-tests" >> $GITHUB_ENV
echo "ARG_BENCH=--enable-benchmarks" >> $GITHUB_ENV
echo "HEADHACKAGE=false" >> $GITHUB_ENV
echo "ARG_COMPILER=--$HCNAME --with-compiler=$HC" >> $GITHUB_ENV
echo "GHCJSARITH=0" >> $GITHUB_ENV
env:
CC: ${{ matrix.compiler }}
- 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
- 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: cache (tools)
uses: actions/cache@v2
with:
key: ${{ runner.os }}-${{ matrix.compiler }}-tools-6c71d9d3
path: ~/.haskell-ci-tools
- name: install cabal-plan
run: |
mkdir -p $HOME/.cabal/bin
curl -sL https://github.com/haskell-hvr/cabal-plan/releases/download/v0.6.2.0/cabal-plan-0.6.2.0-x86_64-linux.xz > cabal-plan.xz
echo 'de73600b1836d3f55e32d80385acc055fd97f60eaa0ab68a755302685f5d81bc cabal-plan.xz' | sha256sum -c -
xz -d < cabal-plan.xz > $HOME/.cabal/bin/cabal-plan
rm -f cabal-plan.xz
chmod a+x $HOME/.cabal/bin/cabal-plan
cabal-plan --version
- name: install hlint
run: |
if [ $((HCNUMVER >= 90000)) -ne 0 ] ; then HLINTVER=$(cd /tmp && (${CABAL} v2-install -v $ARG_COMPILER --dry-run hlint --constraint='hlint >=3.2 && <3.3' | perl -ne 'if (/\bhlint-(\d+(\.\d+)*)\b/) { print "$1"; last; }')); echo "HLint version $HLINTVER" ; fi
if [ $((HCNUMVER >= 90000)) -ne 0 ] ; then if [ ! -e $HOME/.haskell-ci-tools/hlint-$HLINTVER/hlint ]; then echo "Downloading HLint version $HLINTVER"; mkdir -p $HOME/.haskell-ci-tools; curl --write-out 'Status Code: %{http_code} Redirects: %{num_redirects} Total time: %{time_total} Total Dsize: %{size_download}\n' --silent --location --output $HOME/.haskell-ci-tools/hlint-$HLINTVER.tar.gz "https://github.com/ndmitchell/hlint/releases/download/v$HLINTVER/hlint-$HLINTVER-x86_64-linux.tar.gz"; tar -xzv -f $HOME/.haskell-ci-tools/hlint-$HLINTVER.tar.gz -C $HOME/.haskell-ci-tools; fi ; fi
if [ $((HCNUMVER >= 90000)) -ne 0 ] ; then mkdir -p $CABAL_DIR/bin && ln -sf "$HOME/.haskell-ci-tools/hlint-$HLINTVER/hlint" $CABAL_DIR/bin/hlint ; fi
if [ $((HCNUMVER >= 90000)) -ne 0 ] ; then hlint --version ; fi
- name: checkout
uses: actions/checkout@v2
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
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: $_ installed\n" unless /^(xmonad-contrib)$/; }' >> cabal.project.local
cat cabal.project
cat cabal.project.local
- name: dump install plan
run: |
$CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dry-run all
cabal-plan
- name: cache
uses: actions/cache@v2
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: hlint
run: |
if [ $((HCNUMVER >= 90000)) -ne 0 ] ; then (cd ${PKGDIR_xmonad_contrib} && hlint -h ${GITHUB_WORKSPACE}/source/.hlint.yaml .) ; fi
- name: cabal check
run: |
cd ${PKGDIR_xmonad_contrib} || false
${CABAL} -vnormal check
- name: haddock
run: |
$CABAL v2-haddock $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH --haddock-for-hackage --builddir $GITHUB_WORKSPACE/haddock all
- name: unconstrained build
run: |
rm -f cabal.project.local
$CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
- name: upload artifacts (sdist)
if: matrix.upload
uses: actions/upload-artifact@v2
with:
path: ${{ github.workspace }}/sdist/*.tar.gz
- name: upload artifacts (haddock)
if: matrix.upload
uses: actions/upload-artifact@v2
with:
path: ${{ github.workspace }}/haddock/*-docs.tar.gz
- name: hackage upload (candidate)
if: matrix.upload && github.event_name == 'release'
run: |
set -ex
PACKAGE_VERSION="${PACKAGE_VERSION#v}"
curl \
--silent --show-error --fail \
--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/
curl \
--silent --show-error --fail \
-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
env:
HACKAGE_API_KEY: ${{ secrets.HACKAGE_API_KEY }}
PACKAGE_NAME: ${{ github.event.repository.name }}
PACKAGE_VERSION: ${{ github.event.release.tag_name }}
- name: hackage upload (release)
if: matrix.upload && github.event_name == 'workflow_dispatch'
run: |
set -ex
PACKAGE_VERSION="${PACKAGE_VERSION#v}"
curl \
--silent --show-error --fail \
--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/
curl \
--silent --show-error --fail \
-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
env:
HACKAGE_API_KEY: ${{ secrets.HACKAGE_API_KEY }}
PACKAGE_NAME: ${{ github.event.repository.name }}
PACKAGE_VERSION: ${{ github.event.inputs.version }}

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

@@ -0,0 +1,28 @@
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@v13
with:
install_url: https://nixos-nix-install-tests.cachix.org/serve/i6laym9jw3wg9mw6ncyrk6gjx4l34vvx/install
install_options: '--tarball-url-prefix https://nixos-nix-install-tests.cachix.org/serve'
extra_nix_config: |
experimental-features = nix-command flakes
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
- name: Clone project
uses: actions/checkout@v2
- name: Build
# "nix build" builds with full optimization and includes a profiling
# build, so just the build of xmonad-contrib itself takes 3 minutes.
# As a workaround, we invoke cabal manually here.
run: nix develop -c cabal v2-build -O0 -j

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

@@ -0,0 +1,42 @@
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@v2
- name: Setup Haskell
uses: haskell/actions/setup@v1
with:
# packdeps doesn't build with newer as of 2021-10
ghc-version: '8.8'
- name: Install packdeps
run: |
set -ex
echo "$HOME/.cabal/bin" >> $GITHUB_PATH
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

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

@@ -0,0 +1,113 @@
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:
# XXX: temporarily disabled until xmonad 0.17 release
# - resolver: lts-12
# ghc: 8.4.4
# yaml: stack.yaml
- resolver: lts-12
ghc: 8.4.4
yaml: stack-master.yaml
- resolver: lts-14
ghc: 8.6.5
yaml: stack-master.yaml
- resolver: lts-16
ghc: 8.8.4
yaml: stack-master.yaml
# - resolver: lts-17
# ghc: 8.10.4
# yaml: stack.yaml
- resolver: lts-17
ghc: 8.10.4
yaml: stack-master.yaml
- resolver: lts-18
ghc: 8.10.7
yaml: stack-master.yaml
steps:
- name: Clone project
uses: actions/checkout@v2
- name: Prepare apt sources
run: |
set -ex
sudo add-apt-repository -y ppa:hvr/ghc
sudo apt update -y
- name: Install C dependencies
run: |
set -ex
sudo apt install -y \
libx11-dev \
libxext-dev \
libxft-dev \
libxinerama-dev \
libxrandr-dev \
libxss-dev \
#
- name: Install GHC
# use system ghc (if available) in stack, don't waste GH Actions cache space
continue-on-error: true
run: |
set -ex
sudo apt install -y ghc-${{ matrix.ghc }}
echo /opt/ghc/${{ matrix.ghc }}/bin >> $GITHUB_PATH
- name: Refresh caches once a month
id: cache-date
# GHA writes caches on the first miss and then never updates them again;
# force updating the cache at least once a month
run: |
echo "::set-output name=date::$(date +%Y-%m)"
- name: Cache Haskell package metadata
uses: actions/cache@v2
with:
path: ~/.stack/pantry
key: stack-pantry-${{ runner.os }}-${{ steps.cache-date.outputs.date }}
restore-keys: |
stack-pantry-${{ runner.os }}-
- name: Cache Haskell dependencies
uses: actions/cache@v2
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 }}-
stack-${{ runner.os }}-${{ matrix.resolver }}-
- 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

29
.gitignore vendored Normal file
View File

@@ -0,0 +1,29 @@
.cabal-sandbox/
cabal.sandbox.config
.hpc/
*.hi
*.o
*.p_hi
*.prof
*.tix
cabal.config
dist
dist-*
# editor temp files
*#
.#*
*~
.*.swp
# TAGS files
TAGS
tags
# stack artifacts
/.stack-work/
/cabal.project.local
stack.yaml.lock

2
.hlint.yaml Normal file
View File

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

108
.mailmap Normal file
View File

@@ -0,0 +1,108 @@
Alejandro Serrano Mena <trupill@gmail.com>
Alexandre Buisse <buisse@cs.chalmers.se>
Anders Engstrom <ankaan@gmail.com>
Antoine R. Dumont <eniotna.t@gmail.com>
Anton Pirogov <anton.pirogov@gmail.com>
Anton Pirogov <anton.pirogov@gmail.com> anton.pirogov at gmail . com <unknown>
Arjun Comar <nrujac@gmail.com>
Audun Skaugen <audun@skaugen.name> <audunskaugen@gmail.com>
Bas van Dijk <v.dijk.bas@gmail.com>
Ben Boeckel <mathstuf@gmail.com>
Ben Weitzman <benweitzman@gmail.com>
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@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>
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>
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 <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>
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>
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>
hexago.nl <xmonad-contrib@hexago.nl>
lithis <xmonad@selg.hethrael.org>
lithis <xmonad@selg.hethrael.org> <xmonad@s001.hethrael.com>
sam-barr <mail@samf.bar> <samfbarr@outlook.com>
slotThe <soliditsallgood@mailbox.org> <50166980+slotThe@users.noreply.github.com>
slotThe <soliditsallgood@mailbox.org> <soliditsallgood@tuta.io>
spoonm <spoonm@spoonm.org>

1592
CHANGES.md Normal file

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.

82
README
View File

@@ -1,82 +0,0 @@
xmonad-contrib : third party extensions to the xmonad window manager
http://xmonad.org
You need the ghc compiler and xmonad window manager installed in
order to use these extensions.
For installation and configuration instructions, please see the
xmonad website, the documents included with the xmonad source
distribution, and online haddock documentation:
http://www.xmonad.org/xmonad-docs
------------------------------------------------------------------------
Changelogs
For a list of changes since the 0.8.x releases, see:
http://www.haskell.org/haskellwiki/Xmonad/Notable_changes_since_0.8
------------------------------------------------------------------------
Updates to XMonadContrib-0.9 that may Require Changes to ~/.xmonad/xmonad.hs
Please see the Changelogs and xmonad-contrib haddock documentation
links for further details regarding the following changes.
* XMonad.Hooks.EwmhDesktops no longer uses layoutHook, the
ewmhDesktopsLayout modifier has been removed from xmonad-contrib. It
uses logHook, handleEventHook, and startupHook instead and provides
a convenient function 'ewmh' to add EWMH support to a defaultConfig.
* Most DynamicLog users can continue with configs unchanged, but users
of the quickbar functions 'xmobar' or 'dzen' will need to change
xmonad.hs: their types have changed to allow easier composition with
other XConfig modifiers. The 'dynamicLogDzen' and 'dynamicLogXmobar'
functions have been removed.
* WindowGo or safeSpawn users may need to change command lines due to
safeSpawn changes.
* People explicitly referencing the "SP" scratchpad workspace should
change it to "NSP" which is also used by the new Util.NamedScratchpad.
* (Optional) People who explicitly use swapMaster in key or mouse
bindings should change it to shiftMaster. It's the current default
used where swapMaster had been used previously. It works better than
swapMaster when using floating and tiled windows together on the
same workspace.
------------------------------------------------------------------------
Getting or updating XMonadContrib
latest release: http://hackage.haskell.org/cgi-bin/hackage-scripts/package/xmonad-contrib
darcs version: darcs get http://code.haskell.org/XMonadContrib
(To use darcs xmonad-contrib you must also use the darcs version
of xmonad.)
------------------------------------------------------------------------
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:
XMonad.Layout.Grid
For further details, see the documentation for the
XMonad.Doc.Developing module and http://xmonad.org website.
------------------------------------------------------------------------
Code submitted to the contrib repo is licensed under the same license as
xmonad itself, with copyright held by the authors.
------------------------------------------------------------------------

97
README.md Normal file
View File

@@ -0,0 +1,97 @@
<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/workflow/status/xmonad/xmonad-contrib/Stack?label=Stack&logo=githubactions&logoColor=white">
</a>
<a href="https://github.com/xmonad/xmonad-contrib/actions/workflows/haskell-ci.yml">
<img alt="Cabal" src="https://img.shields.io/github/workflow/status/xmonad/xmonad-contrib/Haskell-CI?label=Cabal&logo=githubactions&logoColor=white">
</a>
<a href="https://github.com/xmonad/xmonad-contrib/actions/workflows/nix.yml">
<img alt="Nix" src="https://img.shields.io/github/workflow/status/xmonad/xmonad-contrib/Nix?label=Nix&logo=githubactions&logoColor=white">
</a>
<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>
</p>
# xmonad-contrib
**Community-maintained extensions for the [XMonad][web:xmonad] window manager.**
[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.
## Installation
For installation and configuration instructions, please see:
* [downloading and installing xmonad][web:download]
* [installing latest xmonad snapshot from git][web:install]
* [configuring xmonad][web:tutorial]
If you run into any trouble, consult our [documentation][web:documentation] or
ask the [community][web:community] for help.
## Contributing
We welcome all forms of contributions:
* [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]
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 xmonad-contrib repo is licensed under the same license
as xmonad core itself, with copyright held by the authors.
[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

@@ -0,0 +1,73 @@
-----------------------------------------------------------------------------
-- |
-- 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)
--
-- Maintainer : Anders Engstrom <ankaan@gmail.com>
-- Stability : unstable
-- Portability : unportable
--
-- Perform an action after the current mouse drag is completed.
-----------------------------------------------------------------------------
module XMonad.Actions.AfterDrag (
-- * Usage
-- $usage
afterDrag,
ifClick,
ifClick') where
import XMonad
import Data.Time (NominalDiffTime, diffUTCTime, getCurrentTime)
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
--
-- > import XMonad.Actions.AfterDrag
--
-- Then add appropriate mouse bindings, for example:
--
-- > , ((modm, button3), (\w -> focus w >> mouseResizeWindow w >> ifClick (windows $ W.float w $ W.RationalRect 0 0 1 1)))
--
-- This will allow you to resize windows as usual, but if you instead of
-- draging click the mouse button the window will be automatically resized to
-- fill the whole screen.
--
-- For detailed instructions on editing your mouse bindings, see
-- "XMonad.Doc.Extending#Editing_mouse_bindings".
--
-- More practical examples are available in "XMonad.Actions.FloatSnap".
-- | Schedule a task to take place after the current dragging is completed.
afterDrag
:: X () -- ^ The task to schedule.
-> X ()
afterDrag task = do drag <- gets dragging
case drag of
Nothing -> return () -- Not dragging
Just (motion, cleanup) -> modify $ \s -> s { dragging = Just(motion, cleanup >> task) }
-- | Take an action if the current dragging can be considered a click,
-- supposing the drag just started before this function is called.
-- 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 ()
ifClick action = ifClick' 300 action (return ())
-- | Take an action if the current dragging is completed within a certain time (in milliseconds.)
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 ()
ifClick' ms click drag = do
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,7 +25,6 @@ module XMonad.Actions.BluetileCommands (
import XMonad
import qualified XMonad.StackSet as W
import XMonad.Layout.LayoutCombinators
import System.Exit
-- $usage
@@ -36,14 +36,14 @@ import System.Exit
--
-- Then edit your @handleEventHook@:
--
-- > main = xmonad defaultConfig { handleEventHook = serverModeEventHook' bluetileCommands }
-- > main = xmonad def { handleEventHook = serverModeEventHook' bluetileCommands }
--
-- See the documentation of "XMonad.Hooks.ServerMode" for details on
-- how to actually invoke the commands from external programs.
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,7 +33,7 @@ import XMonad.Util.Dmenu (dmenu)
import qualified Data.Map as M
import System.Exit
import Data.Maybe
import XMonad.Prelude
-- $usage
--
@@ -60,18 +62,18 @@ import Data.Maybe
-- | 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)
--
@@ -44,7 +45,6 @@ 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
sh <- io $ getWMNormalHints d w
io $ warpPointer d none w 0 0 0 0 (fromIntegral (wa_width wa)) (fromIntegral (wa_height wa))
@@ -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,17 +20,19 @@ 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
@@ -76,18 +80,24 @@ import qualified XMonad.StackSet as W
-- "XMonad.Doc.Extending#Editing_key_bindings".
-- $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 defaultConfig { 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
@@ -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,10 @@
{-# LANGUAGE CPP #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE PatternGuards #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.CycleRecentWS
-- Description : Cycle through most recently used workspaces.
-- Copyright : (c) Michal Janeczek <janeczek@gmail.com>
-- License : BSD3-style (see LICENSE)
--
@@ -19,11 +23,23 @@ module XMonad.Actions.CycleRecentWS (
-- * Usage
-- $usage
cycleRecentWS,
cycleWindowSets
cycleRecentNonEmptyWS,
cycleWindowSets,
toggleRecentWS,
toggleRecentNonEmptyWS,
toggleWindowSets,
recentWS,
#ifdef TESTING
unView,
#endif
) where
import XMonad hiding (workspaces)
import XMonad.StackSet
import XMonad.StackSet hiding (filter)
import Control.Arrow ((&&&))
import Data.Function (on)
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@ file:
@@ -47,33 +63,61 @@ 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 <- gets $ genOptions . windowset
(options, unView') <- gets $ (genOptions &&& unView) . windowset
XConf {theRoot = root, display = d} <- ask
let event = allocaXEvent $ \p -> do
maskEvent d (keyPressMask .|. keyReleaseMask) p
KeyEvent {ev_event_type = t, ev_keycode = c} <- getEvent p
s <- keycodeToKeysym d c 0
return (t, s)
let setOption n = do windows $ const $ options `cycref` n
let setOption n = do windows $ view (options `cycref` n) . unView'
(t, s) <- io event
case () of
() | t == keyPress && s == keyNext -> setOption (n+1)
@@ -83,3 +127,37 @@ cycleWindowSets genOptions mods keyNext keyPrev = do
io $ grabKeyboard d root False grabModeAsync grabModeAsync currentTime
setOption 0
io $ ungrabKeyboard d currentTime
where
cycref :: [a] -> Int -> a
cycref l i = l !! (i `mod` length l)
-- | 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
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,27 +19,21 @@ 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@:
--
-- > 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,

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,11 +84,9 @@ module XMonad.Actions.CycleWS (
) where
import Control.Monad ( unless )
import Data.List ( 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)
import XMonad.Util.Types
import XMonad.Util.WorkspaceCompare
@@ -112,13 +116,17 @@ 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".
--
-- When using the toggle functions, in order to ensure that the workspace
-- to which you switch is the previously viewed workspace, use the
-- 'logHook' in "XMonad.Hooks.WorkspaceHistory".
{- $moving
@@ -158,9 +166,7 @@ toggleWS = toggleWS' []
-- > -- Ignore the scratchpad workspace while toggling:
-- > ("M-b", toggleWS' ["NSP"])
toggleWS' :: [WorkspaceId] -> X ()
toggleWS' skips = do
hs' <- cleanHiddens skips
unless (null hs') (windows . view . tag $ head hs')
toggleWS' skips = lastViewedHiddenExcept skips >>= flip whenJust (windows . view)
-- | 'XMonad.StackSet.greedyView' a workspace, or if already there, view
-- the previously displayed workspace ala weechat. Change @greedyView@ to
@@ -184,10 +190,9 @@ toggleOrView = toggleOrDoSkip [] greedyView
toggleOrDoSkip :: [WorkspaceId] -> (WorkspaceId -> WindowSet -> WindowSet)
-> WorkspaceId -> X ()
toggleOrDoSkip skips f toWS = do
hs' <- cleanHiddens skips
cur <- gets (currentTag . windowset)
if toWS == cur
then unless (null hs') (windows . f . tag $ head hs')
then lastViewedHiddenExcept skips >>= flip whenJust (windows . f)
else windows (f toWS)
-- | List difference ('\\') for workspaces and tags. Removes workspaces
@@ -195,8 +200,15 @@ toggleOrDoSkip skips f toWS = do
skipTags :: (Eq i) => [Workspace i l a] -> [i] -> [Workspace i l a]
skipTags wss ids = filter ((`notElem` ids) . tag) wss
cleanHiddens :: [WorkspaceId] -> X [WindowSpace]
cleanHiddens skips = gets $ (flip skipTags) skips . hidden . windowset
-- | Ignoring the skips, find the best candidate for the last viewed hidden
-- workspace.
lastViewedHiddenExcept :: [WorkspaceId] -> X (Maybe WorkspaceId)
lastViewedHiddenExcept skips = do
hs <- gets $ map tag . flip skipTags skips . hidden . windowset
choose hs . find (`elem` hs) <$> WH.workspaceHistory
where choose [] _ = Nothing
choose (h:_) Nothing = Just h
choose _ vh@(Just _) = vh
switchWorkspace :: Int -> X ()
switchWorkspace d = wsBy d >>= windows . greedyView
@@ -204,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
@@ -214,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
@@ -225,11 +237,19 @@ 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
| HiddenWS -- ^ cycle through non-visible workspaces
| HiddenNonEmptyWS -- ^ cycle through non-empty non-visible workspaces
| HiddenEmptyWS -- ^ cycle through empty non-visible workspaces
| AnyWS -- ^ cycle through all workspaces
| WSTagGroup Char
-- ^ cycle through workspaces in the same group, the
@@ -238,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)
@@ -248,11 +273,50 @@ wsTypeToPred HiddenWS = do hs <- gets (map tag . hidden . windowset)
wsTypeToPred HiddenNonEmptyWS = do ne <- wsTypeToPred NonEmptyWS
hi <- wsTypeToPred HiddenWS
return (\w -> hi w && ne w)
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.
@@ -286,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)
@@ -296,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
@@ -308,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 ()
@@ -336,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,7 @@
--------------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.CycleWindows
-- Description : Cycle windows while maintaining focus in place.
-- Copyright : (c) Wirt Wolff <wirtwolff@gmail.com>
-- License : BSD3-style (see LICENSE)
--
@@ -116,7 +117,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
@@ -205,7 +206,7 @@ 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
rotFocused' f s@W.Stack{} = rotSlaves' f s -- otherwise
-- $unfocused

View File

@@ -0,0 +1,100 @@
-----------------------------------------------------------------------------
-- |
-- 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 Graphics.X11.Xlib.Extras
import XMonad
import XMonad.Prelude
import XMonad.Hooks.WorkspaceHistory
import qualified XMonad.StackSet as W
-- $usage
-- This module must be used in conjuction with XMonad.Hooks.WorkspaceHistory
--
-- To use, add something like the following to your keybindings
-- , ((mod4Mask, xK_slash), cycleWorkspaceOnCurrentScreen [xK_Super_L] xK_slash xK_p)
repeatableAction :: [KeySym] -> (EventType -> KeySym -> X ()) -> X ()
repeatableAction mods pressHandler = do
XConf {theRoot = root, display = d} <- ask
let getNextEvent = io $ allocaXEvent $ \p ->
do
maskEvent d (keyPressMask .|. keyReleaseMask) p
KeyEvent {ev_event_type = t, ev_keycode = c} <- getEvent p
s <- io $ keycodeToKeysym d c 0
return (t, s)
handleEvent (t, s)
| t == keyRelease && s `elem` mods = return ()
| otherwise = pressHandler t s >> getNextEvent >>= handleEvent
io $ grabKeyboard d root False grabModeAsync grabModeAsync currentTime
getNextEvent >>= handleEvent
io $ ungrabKeyboard d currentTime
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
cycleWorkspaceOnScreen :: ScreenId -> [KeySym] -> KeySym -> KeySym -> 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)
focusIncrement 1 -- Do the first workspace cycle
repeatableAction mods $
runFirst
[ handleKeyEvent keyPress nextKey $ focusIncrement 1
, handleKeyEvent keyPress prevKey $ focusIncrement (-1)
]
return ()
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)
--

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

View File

@@ -0,0 +1,359 @@
--------------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.DynamicProjects
-- Description : Treat workspaces as individual project areas.
-- Copyright : (c) Peter J. Jones
-- License : BSD3-style (see LICENSE)
--
-- Maintainer : Peter Jones <pjones@devalot.com>
-- Stability : unstable
-- Portability : not portable
--
-- Imbues workspaces with additional features so they can be treated
-- as individual project areas.
--------------------------------------------------------------------------------
module XMonad.Actions.DynamicProjects
( -- * Overview
-- $overview
-- * Usage
-- $usage
-- * Types
Project (..)
, ProjectName
-- * Hooks
, dynamicProjects
-- * Bindings
, switchProjectPrompt
, shiftToProjectPrompt
, renameProjectPrompt
, changeProjectDirPrompt
-- * Helper Functions
, switchProject
, shiftToProject
, lookupProject
, currentProject
, activateProject
, modifyProject
) where
--------------------------------------------------------------------------------
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import System.Directory (setCurrentDirectory, getHomeDirectory, makeAbsolute)
import XMonad.Prelude
import XMonad
import XMonad.Actions.DynamicWorkspaces
import XMonad.Prompt
import XMonad.Prompt.Directory
import qualified XMonad.StackSet as W
import qualified XMonad.Util.ExtensibleState as XS
--------------------------------------------------------------------------------
-- $overview
-- Inspired by @TopicSpace@, @DynamicWorkspaces@, and @WorkspaceDir@,
-- @DynamicProjects@ treats workspaces as projects while maintaining
-- compatibility with all existing workspace-related functionality in
-- XMonad.
--
-- Instead of using generic workspace names such as @3@ or @work@,
-- @DynamicProjects@ allows you to dedicate workspaces to specific
-- projects and then switch between projects easily.
--
-- A project is made up of a name, working directory, and a start-up
-- hook. When you switch to a workspace, @DynamicProjects@ changes
-- 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.
--
-- When using the @switchProjectPrompt@ function, workspaces are
-- created as needed. This means you can create new project spaces
-- (and therefore workspaces) on the fly. (These dynamic projects are
-- not preserved across restarts.)
--
-- Additionally, frequently used projects can be configured statically
-- in your XMonad configuration. Doing so allows you to configure the
-- per-project start-up hook.
--------------------------------------------------------------------------------
-- $usage
-- To use @DynamicProjects@ you need to add it to your XMonad
-- configuration and then configure some optional key bindings.
--
-- > import XMonad.Actions.DynamicProjects
--
-- Start by defining some projects:
--
-- > projects :: [Project]
-- > projects =
-- > [ Project { projectName = "scratch"
-- > , projectDirectory = "~/"
-- > , projectStartHook = Nothing
-- > }
-- >
-- > , Project { projectName = "browser"
-- > , projectDirectory = "~/download"
-- > , projectStartHook = Just $ do spawn "conkeror"
-- > spawn "chromium"
-- > }
-- > ]
--
-- Then inject @DynamicProjects@ into your XMonad configuration:
--
-- > main = xmonad $ dynamicProjects projects def
--
-- And finally, configure some optional key bindings:
--
-- > , ((modm, xK_space), switchProjectPrompt)
-- > , ((modm, xK_slash), shiftToProjectPrompt)
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
--------------------------------------------------------------------------------
type ProjectName = String
type ProjectTable = Map ProjectName Project
--------------------------------------------------------------------------------
-- | Details about a workspace that represents a project.
data Project = Project
{ projectName :: !ProjectName -- ^ Workspace name.
, projectDirectory :: !FilePath -- ^ Working directory.
, projectStartHook :: !(Maybe (X ())) -- ^ Optional start-up hook.
}
--------------------------------------------------------------------------------
-- | Internal project state.
data ProjectState = ProjectState
{ projects :: !ProjectTable
, previousProject :: !(Maybe WorkspaceId)
}
--------------------------------------------------------------------------------
instance ExtensionClass ProjectState where
initialValue = ProjectState Map.empty Nothing
--------------------------------------------------------------------------------
-- Internal types for working with XPrompt.
data ProjectPrompt = ProjectPrompt XPConfig ProjectMode [ProjectName]
data ProjectMode = SwitchMode | ShiftMode | RenameMode | DirMode
instance XPrompt ProjectPrompt where
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 c DirMode _) =
let xpt = directoryMultipleModes' (complCaseSensitivity c) "" (const $ return ())
in completionFunction xpt
completionFunction (ProjectPrompt c _ ns) = mkComplFunFromList' c ns
modeAction (ProjectPrompt _ SwitchMode _) buf auto = do
let name = if null auto then buf else auto
ps <- XS.gets projects
case Map.lookup name ps of
Just p -> switchProject p
Nothing | null name -> return ()
| otherwise -> switchProject (defProject name)
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 _ =
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
dir <- io $ makeAbsolute dir'
modifyProject (\p -> p { projectDirectory = dir })
--------------------------------------------------------------------------------
-- | Add dynamic projects support to the given config.
dynamicProjects :: [Project] -> XConfig a -> XConfig a
dynamicProjects ps c =
c { startupHook = dynamicProjectsStartupHook ps <> startupHook c
, logHook = dynamicProjectsLogHook <> logHook c
}
--------------------------------------------------------------------------------
-- | Log hook for tracking workspace changes.
dynamicProjectsLogHook :: X ()
dynamicProjectsLogHook = do
name <- gets (W.tag . W.workspace . W.current . windowset)
xstate <- XS.get
unless (Just name == previousProject xstate) $ do
XS.put (xstate {previousProject = Just name})
activateProject . fromMaybe (defProject name) $
Map.lookup name (projects xstate)
--------------------------------------------------------------------------------
-- | Start-up hook for recording configured projects.
dynamicProjectsStartupHook :: [Project] -> X ()
dynamicProjectsStartupHook ps = XS.modify go
where
go :: ProjectState -> ProjectState
go s = s {projects = update $ projects s}
update :: ProjectTable -> ProjectTable
update = Map.union (Map.fromList $ map entry ps)
entry :: Project -> (ProjectName, Project)
entry p = (projectName p, addDefaultHook p)
-- Force the hook to be a @Just@ so that it doesn't automatically
-- get deleted when switching away from a workspace with no
-- windows.
addDefaultHook :: Project -> Project
addDefaultHook p = p { projectStartHook = projectStartHook p <|>
Just (return ())
}
--------------------------------------------------------------------------------
-- | Find a project based on its name.
lookupProject :: ProjectName -> X (Maybe Project)
lookupProject name = Map.lookup name <$> XS.gets projects
--------------------------------------------------------------------------------
-- | Fetch the current project (the one being used for the currently
-- active workspace).
currentProject :: X Project
currentProject = do
name <- gets (W.tag . W.workspace . W.current . windowset)
proj <- lookupProject name
return $ fromMaybe (defProject name) proj
--------------------------------------------------------------------------------
-- | Modify the current project using a pure function.
modifyProject :: (Project -> Project) -> X ()
modifyProject f = do
p <- currentProject
ps <- XS.gets projects
-- If a project is renamed to match another project, the old project
-- will be removed and replaced with this one.
let new = f p
ps' = Map.insert (projectName new) new $ Map.delete (projectName p) ps
XS.modify $ \s -> s {projects = ps'}
activateProject new
--------------------------------------------------------------------------------
-- | 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)
--------------------------------------------------------------------------------
-- | Prompt for a project name and then switch to it. Automatically
-- creates a project if a new name is returned from the prompt.
switchProjectPrompt :: XPConfig -> X ()
switchProjectPrompt = projectPrompt [ SwitchMode
, ShiftMode
, RenameMode
, DirMode
]
--------------------------------------------------------------------------------
-- | Shift the currently focused window to the given project.
shiftToProject :: Project -> X ()
shiftToProject p = do
addHiddenWorkspace (projectName p)
windows (W.shift $ projectName p)
--------------------------------------------------------------------------------
-- | Prompts for a project name and then shifts the currently focused
-- window to that project.
shiftToProjectPrompt :: XPConfig -> X ()
shiftToProjectPrompt = projectPrompt [ ShiftMode
, RenameMode
, SwitchMode
, DirMode
]
--------------------------------------------------------------------------------
-- | Rename the current project.
renameProjectPrompt :: XPConfig -> X ()
renameProjectPrompt = projectPrompt [ RenameMode
, DirMode
, SwitchMode
, ShiftMode
]
--------------------------------------------------------------------------------
-- | Change the working directory used for the current project.
--
-- NOTE: This will only affect new processed started in this project.
-- Existing processes will maintain the previous working directory.
changeProjectDirPrompt :: XPConfig -> X ()
changeProjectDirPrompt = projectPrompt [ DirMode
, SwitchMode
, ShiftMode
, RenameMode
]
--------------------------------------------------------------------------------
-- | Prompt for a project name.
projectPrompt :: [ProjectMode] -> XPConfig -> X ()
projectPrompt submodes c = do
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 c m names) submodes
mkXPromptWithModes modes c
--------------------------------------------------------------------------------
-- | Activate a project by updating the working directory and
-- possibly running its start-up hook. This function is automatically
-- invoked when the workspace changes.
activateProject :: Project -> X ()
activateProject p = do
ws <- gets (W.integrate' . W.stack . W.workspace . W.current . windowset)
home <- io getHomeDirectory
-- Change to the project's directory.
catchIO (setCurrentDirectory $ expandHome home $ projectDirectory p)
-- Possibly run the project's startup hook.
when (null ws) $ fromMaybe (return ()) (projectStartHook p)
where
-- Replace an initial @~@ character with the home directory.
expandHome :: FilePath -> FilePath -> FilePath
expandHome home dir = case stripPrefix "~" dir of
Nothing -> dir
Just xs -> home ++ xs
--------------------------------------------------------------------------------
-- | Default project.
defProject :: ProjectName -> Project
defProject name = Project name "~/" Nothing

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)
--
@@ -23,6 +22,7 @@ module XMonad.Actions.DynamicWorkspaceGroups
WSGroupId
, addRawWSGroup
, addWSGroup
, addCurrentWSGroup
, forgetWSGroup
@@ -33,17 +33,22 @@ 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:
@@ -62,30 +67,35 @@ 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
-- explicitly specified association between screen IDs and workspace
-- names. This function could be useful for, say, creating some
-- standard workspace groups in your startup hook.
addRawWSGroup :: WSGroupId -> [(ScreenId, WorkspaceId)] -> X ()
addRawWSGroup name = XS.modify . withWSG . M.insert name
-- | Add a new workspace group with the given name.
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 -> XS.modify . withWSG . M.insert 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.
addCurrentWSGroup :: WSGroupId -> X ()
addCurrentWSGroup name = withWindowSet $ \w ->
addWSGroup name $ map (W.tag . W.workspace) (W.current w : W.visible w)
addWSGroup name $ map (W.tag . W.workspace) (reverse $ W.current w : W.visible w)
-- | Delete the named workspace group from the list of workspace
-- groups. Note that this has no effect on the workspaces involved;
@@ -95,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.
@@ -116,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 ()
@@ -136,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,7 +45,7 @@ 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
@@ -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
@@ -152,6 +156,21 @@ swapOrder w1 w2 = do
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 +185,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,6 +1,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.DynamicWorkspaces
-- Description : Provides bindings to add and delete workspaces.
-- Copyright : (c) David Roundy <droundy@darcs.net>
-- License : BSD3-style (see LICENSE)
--
@@ -16,25 +17,31 @@ module XMonad.Actions.DynamicWorkspaces (
-- * Usage
-- $usage
addWorkspace, addWorkspacePrompt,
appendWorkspace, appendWorkspacePrompt,
addWorkspaceAt,
removeWorkspace,
removeWorkspaceByTag,
removeEmptyWorkspace,
removeEmptyWorkspaceByTag,
removeEmptyWorkspaceAfter,
removeEmptyWorkspaceAfterExcept,
addHiddenWorkspace,
addHiddenWorkspace, addHiddenWorkspaceAt,
withWorkspace,
selectWorkspace, renameWorkspace,
renameWorkspaceByName,
toNthWorkspace, withNthWorkspace
toNthWorkspace, withNthWorkspace,
setWorkspaceIndex, withWorkspaceIndex,
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.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:
@@ -45,21 +52,60 @@ import Control.Monad (when)
-- Then add keybindings like the following:
--
-- > , ((modm .|. shiftMask, xK_BackSpace), removeWorkspace)
-- > , ((modm .|. shiftMask, xK_v ), selectWorkspace defaultXPConfig)
-- > , ((modm, xK_m ), withWorkspace defaultXPConfig (windows . W.shift))
-- > , ((modm .|. shiftMask, xK_m ), withWorkspace defaultXPConfig (windows . copy))
-- > , ((modm .|. shiftMask, xK_r ), renameWorkspace defaultXPConfig)
-- > , ((modm .|. shiftMask, xK_v ), selectWorkspace def)
-- > , ((modm, xK_m ), withWorkspace def (windows . W.shift))
-- > , ((modm .|. shiftMask, xK_m ), withWorkspace def (windows . copy))
-- > , ((modm .|. shiftMask, xK_r ), renameWorkspace def)
--
-- > -- mod-[1..9] %! Switch to workspace N
-- > -- mod-shift-[1..9] %! Move client to workspace N
-- > -- mod-[1..9] %! Switch to workspace N in the list of workspaces
-- > -- mod-shift-[1..9] %! Move client to workspace N in the list of workspaces
-- > ++
-- > zip (zip (repeat (modm)) [xK_1..xK_9]) (map (withNthWorkspace W.greedyView) [0..])
-- > ++
-- > zip (zip (repeat (modm .|. shiftMask)) [xK_1..xK_9]) (map (withNthWorkspace W.shift) [0..])
--
-- Alternatively, you can associate indexes (which don't depend of the
-- workspace list order) to workspaces by using following keybindings:
--
-- > -- mod-[1..9] %! Switch to workspace of index N
-- > -- mod-control-[1..9] %! Set index N to the current workspace
-- > ++
-- > zip (zip (repeat (modm)) [xK_1..xK_9]) (map (withWorkspaceIndex W.greedyView) [1..])
-- > ++
-- > 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
-- "XMonad.Actions.CopyWindow", 'windows', 'shift', and 'defaultXPConfig'.
-- "XMonad.Actions.CopyWindow", 'windows', 'shift', and 'XPConfig'.
type WorkspaceTag = String
-- | The workspace index is mapped to a workspace tag by the user and
-- can be updated.
type WorkspaceIndex = Int
-- | Internal dynamic project state that stores a mapping between
-- workspace indexes and workspace tags.
newtype DynamicWorkspaceState = DynamicWorkspaceState {workspaceIndexMap :: Map.Map WorkspaceIndex WorkspaceTag}
deriving (Read, Show)
instance ExtensionClass DynamicWorkspaceState where
initialValue = DynamicWorkspaceState Map.empty
extensionType = PersistentExtension
-- | Set the index of the current workspace.
setWorkspaceIndex :: WorkspaceIndex -> X ()
setWorkspaceIndex widx = do
wtag <- gets (currentTag . windowset)
wmap <- XS.gets workspaceIndexMap
XS.modify $ \s -> s {workspaceIndexMap = Map.insert widx wtag wmap}
withWorkspaceIndex :: (String -> WindowSet -> WindowSet) -> WorkspaceIndex -> X ()
withWorkspaceIndex job widx = do
wtag <- ilookup widx
maybe (return ()) (windows . job) wtag
where
ilookup :: WorkspaceIndex -> X (Maybe WorkspaceTag)
ilookup idx = Map.lookup idx <$> XS.gets workspaceIndexMap
mkCompl :: [String] -> String -> IO [String]
@@ -77,10 +123,15 @@ renameWorkspace :: XPConfig -> X ()
renameWorkspace conf = workspacePrompt conf renameWorkspaceByName
renameWorkspaceByName :: String -> X ()
renameWorkspaceByName w = 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
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 }
in sets $ removeWorkspace' w s
updateIndexMap old w
where updateIndexMap oldIM newIM = do
wmap <- XS.gets workspaceIndexMap
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
@@ -107,20 +158,41 @@ selectWorkspace conf = workspacePrompt conf $ \w ->
-- workspace with the given name already exists; then switch to the
-- newly created workspace.
addWorkspace :: String -> X ()
addWorkspace newtag = addHiddenWorkspace newtag >> windows (greedyView newtag)
addWorkspace = addWorkspaceAt (:)
-- | Same as addWorkspace, but adds the workspace to the end of the list of workspaces
appendWorkspace :: String -> X()
appendWorkspace = addWorkspaceAt (flip (++) . return)
-- | Adds a new workspace with the given name to the current list of workspaces.
-- This function allows the user to pass a function that inserts an element
-- into a list at an arbitrary spot.
addWorkspaceAt :: (WindowSpace -> [WindowSpace] -> [WindowSpace]) -> String -> X ()
addWorkspaceAt add newtag = addHiddenWorkspaceAt add newtag >> windows (greedyView newtag)
-- | Prompt for the name of a new workspace, add it if it does not
-- already exist, and switch to it.
addWorkspacePrompt :: XPConfig -> X ()
addWorkspacePrompt conf = mkXPrompt (Wor "New workspace name: ") conf (const (return [])) addWorkspace
-- | Prompt for the name of a new workspace, appending it to the end of the list of workspaces
-- if it does not already exist, and switch to it.
appendWorkspacePrompt :: XPConfig -> X ()
appendWorkspacePrompt conf = mkXPrompt (Wor "New workspace name: ") conf (const (return [])) appendWorkspace
-- | Add a new hidden workspace with the given name, or do nothing if
-- a workspace with the given name already exists. Takes a function to insert
-- the workspace at an arbitrary spot in the list.
addHiddenWorkspaceAt :: (WindowSpace -> [WindowSpace] -> [WindowSpace]) -> String -> X ()
addHiddenWorkspaceAt add newtag =
whenX (gets (not . tagMember newtag . windowset)) $ do
l <- asks (layoutHook . config)
windows (addHiddenWorkspace' add newtag l)
-- | Add a new hidden workspace with the given name, or do nothing if
-- a workspace with the given name already exists.
addHiddenWorkspace :: String -> X ()
addHiddenWorkspace newtag =
whenX (gets (not . tagMember newtag . windowset)) $ do
l <- asks (layoutHook . config)
windows (addHiddenWorkspace' newtag l)
addHiddenWorkspace = addHiddenWorkspaceAt (:)
-- | Remove the current workspace if it contains no windows.
removeEmptyWorkspace :: X ()
@@ -130,12 +202,11 @@ removeEmptyWorkspace = gets (currentTag . windowset) >>= removeEmptyWorkspaceByT
removeWorkspace :: X ()
removeWorkspace = gets (currentTag . windowset) >>= removeWorkspaceByTag
-- | Remove workspace with specific tag if it contains no windows. Only works
-- on the current or the last workspace.
-- | Remove workspace with specific tag if it contains no windows.
removeEmptyWorkspaceByTag :: String -> X ()
removeEmptyWorkspaceByTag t = whenX (isEmpty t) $ removeWorkspaceByTag t
-- | Remove workspace with specific tag. Only works on the current or the last workspace.
-- | Remove workspace with specific tag.
removeWorkspaceByTag :: String -> X ()
removeWorkspaceByTag torem = do
s <- gets windowset
@@ -166,16 +237,21 @@ isEmpty t = do wsl <- gets $ workspaces . windowset
let mws = find (\ws -> tag ws == t) wsl
return $ maybe True (isNothing . stack) mws
addHiddenWorkspace' :: i -> l -> StackSet i l a sid sd -> StackSet i l a sid sd
addHiddenWorkspace' newtag l s@(StackSet { hidden = ws }) = s { hidden = Workspace newtag l Nothing:ws }
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 }
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 = (w:ws) })
| tag w == torem = s { current = scr { workspace = wc { stack = meld (stack w) (stack wc) } }
, hidden = 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, 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)
removeWorkspace' _ s = s
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,388 @@
{-# LANGUAGE CPP #-}
{-# 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\/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 dpy th visibleWindows
PerScreenKeys m ->
fmap concat
$ sequence
$ M.elems
$ M.mapWithKey (\sid ks -> buildOverlays ks <$> sortedOverlayWindows sid) m
where
screenById :: ScreenId -> Maybe (W.Screen WorkspaceId (Layout Window) Window ScreenId ScreenDetail)
screenById sid = find ((== sid) . W.screen) (W.screens ws)
visibleWindowsOnScreen :: ScreenId -> [Window]
visibleWindowsOnScreen sid = filter (`elem` toList mappedWins) $ W.integrate' $ screenById sid >>= W.stack . W.workspace
sortedOverlayWindows :: ScreenId -> X [OverlayWindow]
sortedOverlayWindows sid = sortOverlayWindows <$> buildOverlayWindows dpy th (visibleWindowsOnScreen sid)
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 ks = appendChords (maxChordLen c) ks
buildOverlayWindows :: Display -> Position -> [Window] -> X [OverlayWindow]
buildOverlayWindows dpy th ws = sequence $ buildOverlayWin dpy th <$> ws
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 :: Display -> Position -> Window -> X OverlayWindow
buildOverlayWin dpy th w = do
wAttrs <- io $ getWindowAttributes dpy w
let r = overlayF c th $ makeRect wAttrs
o <- createNewWindow r Nothing "" True
return 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 = tail $ 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,9 +19,7 @@ module XMonad.Actions.FindEmptyWorkspace (
viewEmptyWorkspace, tagToEmptyWorkspace, sendToEmptyWorkspace
) where
import Data.List
import Data.Maybe ( isNothing )
import XMonad.Prelude
import XMonad
import XMonad.StackSet

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,8 +24,9 @@ module XMonad.Actions.FlexibleManipulate (
) where
import XMonad
import XMonad.Prelude ((<&>))
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, map, otherwise, round, snd, uncurry, ($), (.))
-- $usage
-- First, add this import to your @~\/.xmonad\/xmonad.hs@:
@@ -79,24 +81,23 @@ position = const 0.5
-- 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
[wpos, wsize] <- io $ getWindowAttributes d w <&> winAttrs
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
@@ -113,7 +114,7 @@ type Pnt = (Double, Double)
pairUp :: [a] -> [(a,a)]
pairUp [] = []
pairUp [_] = []
pairUp (x:y:xs) = (x, y) : (pairUp xs)
pairUp (x:y:xs) = (x, y) : pairUp xs
mapP :: (a -> b) -> (a, a) -> (b, b)
mapP f (x, y) = (f x, f y)
@@ -132,4 +133,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,7 +21,7 @@ module XMonad.Actions.FlexibleResize (
) where
import XMonad
import XMonad.Util.XUtils (fi)
import XMonad.Prelude (fi)
import Foreign.C.Types
-- $usage
@@ -50,7 +51,6 @@ mouseResizeEdgeWindow
-> Window -- ^ The window to resize.
-> X ()
mouseResizeEdgeWindow edge w = whenX (isClient w) $ withDisplay $ \d -> do
io $ raiseWindow d w
wa <- io $ getWindowAttributes d w
sh <- io $ getWMNormalHints d w
(_, _, _, _, _, ix, iy, _) <- io $ queryPointer d w
@@ -62,16 +62,17 @@ mouseResizeEdgeWindow edge w = whenX (isClient w) $ withDisplay $ \d -> do
(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
--
@@ -22,6 +23,7 @@ module XMonad.Actions.FloatKeys (
) where
import XMonad
import XMonad.Prelude (fi)
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
@@ -43,10 +45,9 @@ import XMonad
-- 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))
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
@@ -61,14 +62,14 @@ keysMoveWindow (dx,dy) w = whenX (isClient w) $ withDisplay $ \d -> do
-- > 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)))
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 +81,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 +91,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
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)
--
@@ -21,18 +22,19 @@ module XMonad.Actions.FloatSnap (
snapShrink,
snapMagicMove,
snapMagicResize,
snapMagicMouseResize) where
snapMagicMouseResize,
afterDrag,
ifClick,
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
import XMonad.Hooks.ManageDocks (calcGap)
import XMonad.Util.Types (Direction2D(..))
import qualified Data.Set as S
import XMonad.Actions.AfterDrag
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
@@ -53,17 +55,24 @@ import qualified Data.Set as S
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
--
-- And possibly add an appropriate mouse binding, for example:
-- And possibly add appropriate mouse bindings, for example:
--
-- > , ((modm, button1), (\w -> focus w >> mouseMoveWindow w >> snapMagicMove (Just 50) (Just 50) w))
-- > , ((modm .|. shiftMask, button1), (\w -> focus w >> mouseMoveWindow w >> snapMagicResize [L,R,U,D] (Just 50) (Just 50) w))
-- > , ((modm, button3), (\w -> focus w >> mouseResizeWindow w >> snapMagicResize [R,D] (Just 50) (Just 50) w))
-- > , ((modm, button1), (\w -> focus w >> mouseMoveWindow w >> ifClick (snapMagicMove (Just 50) (Just 50) w)))
-- > , ((modm .|. shiftMask, button1), (\w -> focus w >> mouseMoveWindow w >> ifClick (snapMagicResize [L,R,U,D] (Just 50) (Just 50) w)))
-- > , ((modm, button3), (\w -> focus w >> mouseResizeWindow w >> ifClick (snapMagicResize [R,D] (Just 50) (Just 50) w)))
--
-- For detailed instructions on editing your mouse bindings, see
-- "XMonad.Doc.Extending#Editing_mouse_bindings".
--
-- Using these mouse bindings, it will not snap while moving, but allow you to click the window once after it has been moved or resized to snap it into place.
-- Note that the order in which the commands are applied in the mouse bindings are important.
-- Note that the order in which the commands are applied in the mouse bindings are important. Snapping can also be used together with other window resizing
-- functions, such as those from "XMonad.Actions.FlexibleResize"
--
-- An alternative set of mouse bindings that will always snap after the drag is:
--
-- > , ((modm, button1), (\w -> focus w >> mouseMoveWindow w >> afterDrag (snapMagicMove (Just 50) (Just 50) w)))
-- > , ((modm .|. shiftMask, button1), (\w -> focus w >> mouseMoveWindow w >> afterDrag (snapMagicResize [L,R,U,D] (Just 50) (Just 50) w)))
-- > , ((modm, button3), (\w -> focus w >> mouseResizeWindow w >> afterDrag (snapMagicResize [R,D] (Just 50) (Just 50) w)))
--
-- Interesting values for the distance to look for window in the orthogonal axis are Nothing (to snap against every window), Just 0 (to only snap
-- against windows that we should collide with geometrically while moving) and Just 1 (to also snap against windows we brush against).
@@ -86,14 +95,14 @@ snapMagicMouseResize
snapMagicMouseResize middle collidedist snapdist w = whenX (isClient w) $ withDisplay $ \d -> do
wa <- io $ getWindowAttributes d w
(_, _, _, 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
@@ -111,18 +120,17 @@ snapMagicResize
-> 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
(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
@@ -142,13 +150,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
@@ -161,7 +169,6 @@ snapMagicMove
-> 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
nx <- handleAxis True d wa
@@ -184,8 +191,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
@@ -202,7 +209,6 @@ 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
((bl,br,_),(fl,fr,_)) <- getSnap horiz collidedist d w
@@ -242,7 +248,6 @@ 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
mr <- case dir of
L -> do ((mg,ms,_),(_,_,_)) <- getSnap True collidedist d w
@@ -264,9 +269,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
@@ -281,8 +285,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)
@@ -296,8 +300,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) $
@@ -311,8 +315,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,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.FocusNth
-- Description : Focus the nth window of the current workspace.
-- Copyright : (c) Karsten Schoelzel <kuser@gmx.de>
-- License : BSD
--
@@ -14,7 +15,8 @@
module XMonad.Actions.FocusNth (
-- * Usage
-- $usage
focusNth,focusNth') where
focusNth,focusNth',
swapNth,swapNth') where
import XMonad.StackSet
import XMonad
@@ -38,13 +40,21 @@ 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
focusNth' n s@(Stack _ ls rs) | (n < 0) || (n > length ls + length rs) = s
| otherwise = listToStack n (integrate s)
-- | Swap current window with nth. Focus stays in the same position
swapNth :: Int -> X ()
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)

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)
--
@@ -27,7 +28,7 @@ module XMonad.Actions.GridSelect (
-- * Configuration
GSConfig(..),
defaultGSConfig,
def,
TwoDPosition,
buildDefaultGSConfig,
@@ -38,6 +39,7 @@ module XMonad.Actions.GridSelect (
bringSelected,
goToSelected,
gridselectWorkspace,
gridselectWorkspace',
spawnSelected,
runSelectedAction,
@@ -46,6 +48,7 @@ module XMonad.Actions.GridSelect (
fromClassName,
stringColorizer,
colorRangeFromClassName,
stringToRatio,
-- * Navigation Mode assembly
TwoD,
@@ -65,22 +68,26 @@ module XMonad.Actions.GridSelect (
cancel,
transformSearchString,
-- * Rearrangers
-- $rearrangers
Rearranger,
noRearranger,
searchStringRearrangerGenerator,
-- * Screenshots
-- $screenshots
-- * 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
@@ -88,7 +95,7 @@ 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)
-- $usage
@@ -99,13 +106,13 @@ import Data.Word (Word8)
--
-- 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
--
@@ -115,7 +122,7 @@ 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'
-- in order to specify a custom colorizer is @gsconfig2@ (found in
@@ -167,7 +174,7 @@ import Data.Word (Word8)
--
-- You can then define @gsconfig3@ which may be used in exactly the same manner as @gsconfig1@:
--
-- > gsconfig3 = defaultGSConfig
-- > gsconfig3 = def
-- > { gs_cellheight = 30
-- > , gs_cellwidth = 100
-- > , gs_navigate = myNavigation
@@ -183,6 +190,11 @@ import Data.Word (Word8)
--
-- <<http://haskell.org/wikiupload/3/35/Xmonad-gridselect-window-aavogt.png>>
-- | The 'Default' instance gives a basic configuration for 'gridselect', with
-- the colorizer chosen based on the type.
--
-- If you want to replace the 'gs_colorizer' field, use 'buildDefaultGSConfig'
-- instead of 'def' to avoid ambiguous type variables.
data GSConfig a = GSConfig {
gs_cellheight :: Integer,
gs_cellwidth :: Integer,
@@ -190,8 +202,10 @@ data GSConfig a = GSConfig {
gs_colorizer :: a -> Bool -> X (String, String),
gs_font :: String,
gs_navigate :: TwoD a (Maybe a),
gs_rearranger :: Rearranger a,
gs_originFractX :: Double,
gs_originFractY :: Double
gs_originFractY :: Double,
gs_bordercolor :: String
}
-- | That is 'fromClassName' if you are selecting a 'Window', or
@@ -207,17 +221,13 @@ 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
-- | A basic configuration for 'gridselect', with the colorizer chosen based on the type.
--
-- If you want to replace the 'gs_colorizer' field, use 'buildDefaultGSConfig'
-- instead, to avoid ambiguous type variables.
defaultGSConfig :: HasColorizer a => GSConfig a
defaultGSConfig = buildDefaultGSConfig defaultColorizer
instance HasColorizer a => Default (GSConfig a) where
def = buildDefaultGSConfig defaultColorizer
type TwoDPosition = (Integer, Integer)
@@ -232,19 +242,24 @@ data TwoDState a = TwoDState { td_curpos :: TwoDPosition
, td_paneY :: Integer
, td_drawingWin :: Window
, td_searchString :: String
, td_elementmap :: TwoDElementMap a
}
td_elementmap :: TwoDState a -> [(TwoDPosition,(String,a))]
td_elementmap s = zipWith (,) positions sortedElements
generateElementmap :: TwoDState a -> X (TwoDElementMap a)
generateElementmap s = do
rearrangedElements <- rearranger searchString sortedElements
return $ zip positions rearrangedElements
where
TwoDState {td_availSlots = positions,
td_gsconfig = gsconfig,
td_searchString = searchString} = s
GSConfig {gs_rearranger = rearranger} = gsconfig
-- Filter out any elements that don't contain the searchString (case insensitive)
filteredElements = L.filter ((searchString `isInfixOfI`) . fst) (td_elements s)
-- 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
@@ -288,8 +303,8 @@ 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..]
@@ -303,15 +318,15 @@ diamondRestrict x y originX originY =
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
@@ -319,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
@@ -331,11 +349,11 @@ updateAllElements =
s <- get
updateElements (td_elementmap s)
grayoutAllElements :: TwoD a ()
grayoutAllElements =
grayoutElements :: Int -> TwoD a ()
grayoutElements skip =
do
s <- get
updateElementsWithColorizer grayOnly (td_elementmap s)
updateElementsWithColorizer grayOnly $ drop skip (td_elementmap s)
where grayOnly _ _ = return ("#808080", "#808080")
updateElements :: TwoDElementMap a -> TwoD a ()
@@ -359,6 +377,7 @@ updateElementsWithColorizer colorizer elementmap = do
colors <- colorizer element (pos == curpos)
drawWinBox win font
colors
(gs_bordercolor gsconfig)
cellheight
cellwidth
text
@@ -368,10 +387,10 @@ 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 ch cw _ _ _ _ _ _ _ _) } <- 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
@@ -379,7 +398,7 @@ stdHandle (ButtonEvent { ev_event_type = t, ev_x = x, ev_y = y }) contEventloop
Nothing -> contEventloop
| otherwise = contEventloop
stdHandle (ExposeEvent { }) contEventloop = updateAllElements >> contEventloop
stdHandle ExposeEvent{} contEventloop = updateAllElements >> contEventloop
stdHandle _ contEventloop = contEventloop
@@ -411,7 +430,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)
@@ -426,7 +445,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 ()
@@ -467,11 +486,17 @@ transformSearchString f = do
let oldSearchString = td_searchString s
newSearchString = f oldSearchString
when (newSearchString /= oldSearchString) $ do
-- FIXME: grayoutAllElements + updateAllElements paint some fields twice causing flickering
-- we would need a much smarter update strategy to fix that
when (length newSearchString > length oldSearchString) grayoutAllElements
-- FIXME curpos might end up outside new bounds
put s { td_searchString = newSearchString }
let s' = s { td_searchString = newSearchString }
m <- liftX $ generateElementmap s'
let s'' = s' { td_elementmap = m }
oldLen = length $ td_elementmap s
newLen = length $ td_elementmap s''
-- All the elements in the previous element map should be
-- grayed out, except for those which will be covered by
-- elements in the new element map.
when (newLen < oldLen) $ grayoutElements newLen
put s''
updateAllElements
-- | By default gridselect used the defaultNavigation action, which
@@ -520,7 +545,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
@@ -534,7 +559,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)
@@ -546,8 +571,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)
@@ -564,19 +589,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.
@@ -605,15 +630,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.
@@ -622,38 +644,42 @@ gridselect _ [] = return Nothing
gridselect gsconfig elements =
withDisplay $ \dpy -> do
rootw <- asks theRoot
s <- gets $ screenRect . W.screenDetail . W.current . windowset
scr <- gets $ screenRect . W.screenDetail . W.current . windowset
win <- liftIO $ mkUnmanagedWindow dpy (defaultScreenOfDisplay dpy) rootw
(rect_x s) (rect_y s) (rect_width s) (rect_height s)
(rect_x scr) (rect_y scr) (rect_width scr) (rect_height scr)
liftIO $ mapWindow dpy win
liftIO $ selectInput dpy win (exposureMask .|. keyPressMask .|. buttonReleaseMask)
status <- io $ grabKeyboard dpy win True grabModeAsync grabModeAsync currentTime
io $ grabButton dpy button1 anyModifier win True buttonReleaseMask grabModeAsync grabModeAsync none none
io $ grabPointer dpy win True buttonReleaseMask grabModeAsync grabModeAsync none none currentTime
font <- initXMF (gs_font gsconfig)
let screenWidth = toInteger $ rect_width s;
screenHeight = toInteger $ rect_height s;
selectedElement <- if (status == grabSuccess) then do
let screenWidth = toInteger $ rect_width scr
screenHeight = toInteger $ rect_height scr
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
evalTwoD (updateAllElements >> (gs_navigate gsconfig)) TwoDState { td_curpos = (head coords),
td_availSlots = coords,
td_elements = elements,
td_gsconfig = gsconfig,
td_font = font,
td_paneX = screenWidth,
td_paneY = screenHeight,
td_drawingWin = win,
td_searchString = "" }
s = TwoDState { td_curpos = head coords,
td_availSlots = coords,
td_elements = elements,
td_gsconfig = gsconfig,
td_font = font,
td_paneX = screenWidth,
td_paneY = screenHeight,
td_drawingWin = win,
td_searchString = "",
td_elementmap = [] }
m <- generateElementmap s
evalTwoD (updateAllElements >> gs_navigate gsconfig)
(s { td_elementmap = m })
else
return Nothing
liftIO $ do
unmapWindow dpy win
destroyWindow dpy win
ungrabPointer dpy currentTime
sync dpy False
releaseXMF font
return selectedElement
@@ -668,27 +694,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 (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"
-- | Brings selected window to the current workspace.
bringSelected :: GSConfig Window -> X ()
@@ -721,6 +741,44 @@ runSelectedAction conf actions = do
-- > gridselectWorkspace (\ws -> W.greedyView ws . W.shift ws)
gridselectWorkspace :: GSConfig WorkspaceId ->
(WorkspaceId -> WindowSet -> WindowSet) -> X ()
gridselectWorkspace conf viewFunc = withWindowSet $ \ws -> do
gridselectWorkspace conf viewFunc = gridselectWorkspace' conf (windows . viewFunc)
-- | Select a workspace and run an arbitrary action on it.
gridselectWorkspace' :: GSConfig WorkspaceId -> (WorkspaceId -> X ()) -> X ()
gridselectWorkspace' conf func = withWindowSet $ \ws -> do
let wss = map W.tag $ W.hidden ws ++ map W.workspace (W.current ws : W.visible ws)
gridselect conf (zip wss wss) >>= flip whenJust (windows . viewFunc)
gridselect conf (zip wss wss) >>= flip whenJust func
-- $rearrangers
--
-- Rearrangers allow for arbitrary post-filter rearranging of the grid
-- elements.
--
-- For example, to be able to switch to a new dynamic workspace by typing
-- in its name, you can use the following keybinding action:
--
-- > import XMonad.Actions.DynamicWorkspaces (addWorkspace)
-- >
-- > gridselectWorkspace' def
-- > { gs_navigate = navNSearch
-- > , gs_rearranger = searchStringRearrangerGenerator id
-- > }
-- > addWorkspace
-- | A function taking the search string and a list of elements, and
-- returning a potentially rearranged list of elements.
type Rearranger a = String -> [(String, a)] -> X [(String, a)]
-- | A rearranger that leaves the elements unmodified.
noRearranger :: Rearranger a
noRearranger _ = return
-- | A generator for rearrangers that append a single element based on the
-- search string, if doing so would not be redundant (empty string or value
-- already present).
searchStringRearrangerGenerator :: (String -> a) -> Rearranger a
searchStringRearrangerGenerator f =
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,7 @@
{-# LANGUAGE DeriveDataTypeable #-}
----------------------------------------------------------------------
-- |
-- 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 +15,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,18 +26,25 @@ 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.State
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 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
@@ -73,7 +79,7 @@ Finally, you can define keybindings to jump to the most recent window
matching a certain Boolean query. To do this, you need to add
'historyHook' to your logHook:
> main = xmonad $ defaultConfig { logHook = historyHook }
> main = xmonad $ def { logHook = historyHook }
Then the following keybindings, for example, allow you to return to
the most recent xterm or emacs window or to simply to the most recent
@@ -122,12 +128,12 @@ focusNextMatchOrDo qry act = findM (runQuery qry)
-- Returns the list of windows ordered by workspace as specified in
-- ~/.xmonad/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
@@ -141,8 +147,8 @@ 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 +156,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)
instance ExtensionClass HistoryDB where
@@ -167,26 +173,11 @@ updateHistory :: HistoryDB -> X HistoryDB
updateHistory (HistoryDB oldcur oldhist) = withWindowSet $ \ss -> do
let newcur = SS.peek ss
wins = Set.fromList $ SS.allWindows ss
newhist = flt (flip Set.member wins) (ins oldcur oldhist)
newhist = Seq.filter (`Set.member` wins) (ins oldcur oldhist)
return $ 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 +191,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 +207,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 = concat $ 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]

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
@@ -34,10 +34,10 @@ import XMonad.Util.Run
To test it, modify your local .xmonad:
> import XMonad.Prompt(defaultXPConfig)
> import XMonad.Prompt(def)
> import XMonad.Actions.Launcher
> ((modm .|. controlMask, xK_l), launcherPrompt defaultXPConfig $ defaultLauncherModes launcherConfig)
> ((modm .|. controlMask, xK_l), launcherPrompt def $ defaultLauncherModes launcherConfig)
A LauncherConfig contains settings for the default modes, modify them accordingly.
@@ -45,7 +45,7 @@ import XMonad.Util.Run
Restart xmonad. Press Ctrl + Your_Modkey + L and the first prompt should pop up.
If you used 'defaultXPConfig', you can change mode with 'xK_grave'. If you are using your own 'XPConfig', define the value for 'changeModeKey'.
If you used the default 'XPConfig', you can change mode with 'xK_grave'. If you are using your own 'XPConfig', define the value for 'changeModeKey'.
-}
data HoogleMode = HMode FilePath String --path to hoogle and browser
@@ -62,8 +62,8 @@ 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
@@ -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

@@ -0,0 +1,169 @@
-----------------------------------------------------------------------------
-- |
-- 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)
--
-- Maintainer : none
-- Stability : unstable
-- Portability : unportable
--
-- Provides bindings to add and delete links between workspaces. It is aimed
-- at providing useful links between workspaces in a multihead setup. Linked
-- workspaces are view at the same time.
--
-----------------------------------------------------------------------------
module XMonad.Actions.LinkWorkspaces (
-- * Usage
-- $usage
switchWS,
removeAllMatchings,
unMatch,
toggleLinkWorkspaces,
defaultMessageConf,
MessageConfig(..)
) 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)
import XMonad.Actions.OnScreen(Focus(FocusCurrent), onScreen')
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:
--
-- > import XMonad.Actions.LinkWorkspaces
--
-- and add a function to print messages like
--
-- > message_command (S screen) = " dzen2 -p 1 -w 300 -xs " ++ show (screen + 1)
-- > message_color_func c1 c2 msg = dzenColor c1 c2 msg
-- > message screen c1 c2 msg = spawn $ "echo '" ++ (message_color_func c1 c2 msg) ++ "' | " ++ message_command screen
--
-- alternatively you can use the noMessages function as the argument
--
-- Then add keybindings like the following:
--
-- > ,((modm, xK_p), toggleLinkWorkspaces message)
-- > ,((modm .|. shiftMask, xK_p), removeAllMatchings message)
--
-- > [ ((modm .|. m, k), a i)
-- > | (a, m) <- [(switchWS (\y -> windows $ view y) message, 0),(switchWS (\x -> windows $ shift x . view x) message, shiftMask)]
-- > , (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".
data MessageConfig = MessageConfig { messageFunction :: ScreenId -> [Char] -> [Char] -> [Char] -> X()
, foreground :: [Char]
, alertedForeground :: [Char]
, background :: [Char]
}
defaultMessageConf :: MessageConfig
defaultMessageConf = MessageConfig { messageFunction = noMessageFn
, background = "#000000"
, alertedForeground = "#ff7701"
, foreground = "#00ff00" }
noMessageFn :: ScreenId -> [Char] -> [Char] -> [Char] -> X()
noMessageFn _ _ _ _ = return () :: X ()
-- | Stuff for linking workspaces
newtype WorkspaceMap = WorkspaceMap (M.Map WorkspaceId WorkspaceId) deriving (Read, Show)
instance ExtensionClass WorkspaceMap
where initialValue = WorkspaceMap M.empty
extensionType = PersistentExtension
switchWS :: (WorkspaceId -> X ()) -> MessageConfig -> WorkspaceId -> X ()
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' switchFn message workspace stopAtScreen = do
ws <- gets windowset
nScreens <- countScreens
let now = W.screen (W.current ws)
let next = (now + 1) `mod` nScreens
switchFn workspace
case stopAtScreen of
Nothing -> sTM now next (Just now)
Just sId -> if sId == next then return () else sTM now next (Just sId)
where sTM = switchToMatching (switchWS' switchFn message) message workspace
-- | 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 f message t now next stopAtScreen = do
WorkspaceMap matchings <- XS.get :: X WorkspaceMap
case M.lookup t matchings of
Nothing -> return () :: X()
Just newWorkspace -> do
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
Nothing -> setMatching message t1 t2 matchings
Just t -> if t == t2 then removeMatching' message t1 t2 matchings else setMatching message t1 t2 matchings
return ()
-- | Insert a mapping between t1 and t2 and display a message
setMatching :: MessageConfig -> WorkspaceId -> WorkspaceId -> M.Map WorkspaceId WorkspaceId -> X ()
setMatching message t1 t2 matchings = do
ws <- gets windowset
let now = W.screen (W.current ws)
XS.put $ WorkspaceMap $ M.insert t1 t2 matchings
messageFunction message now (foreground message) (background message) ("Linked: " ++ (t1 ++ " " ++ t2))
-- currently this function is called manually this means that if workspaces
-- were deleted, some links stay in the RAM even though they are not used
-- anymore... because of the small amount of memory used for those there is no
-- special cleanup so far
removeMatching' :: MessageConfig -> WorkspaceId -> WorkspaceId -> M.Map WorkspaceId WorkspaceId -> X ()
removeMatching' message t1 t2 matchings = do
ws <- gets windowset
let now = W.screen (W.current ws)
XS.put $ WorkspaceMap $ M.delete t1 matchings
messageFunction message now (alertedForeground message) (background message) ("Unlinked: " ++ t1 ++ " " ++ t2)
-- | Remove all maps between workspaces
removeAllMatchings :: MessageConfig -> X ()
removeAllMatchings message = do
ws <- gets windowset
let now = W.screen (W.current ws)
XS.put $ WorkspaceMap M.empty
messageFunction message now (alertedForeground message) (background message) "All links removed!"
-- | remove all matching regarding a given workspace
unMatch :: WorkspaceId -> X ()
unMatch workspace = do
WorkspaceMap matchings <- XS.get :: X WorkspaceMap
XS.put $ WorkspaceMap $ M.delete workspace (M.filter (/= workspace) matchings)
-- | Toggle the currently displayed workspaces as matching. Starting from the one with focus
-- | a linked list of workspaces is created that will later be iterated by switchToMatching.
toggleLinkWorkspaces :: MessageConfig -> X ()
toggleLinkWorkspaces message = withWindowSet $ \ws -> toggleLinkWorkspaces' (W.screen (W.current ws)) message
toggleLinkWorkspaces' :: ScreenId -> MessageConfig -> X ()
toggleLinkWorkspaces' first message = do
ws <- gets windowset
nScreens <- countScreens
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
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,261 @@
-- 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
-- * Backwards Compatibility
-- $backwardsCompatibility
, send, sendSM, sendSM_
, tryInOrder, tryInOrder_
, tryMessage, tryMessage_
) where
import XMonad ( Window )
import XMonad.Core ( X(), Message, SomeMessage(..), LayoutClass(..), windowset, catchX, WorkspaceId, Layout, whenJust )
import XMonad.Operations ( updateLayout, windowBracket, modifyWindowSet )
import XMonad.Prelude ( isJust, liftA2, void )
import XMonad.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@:
--
-- > 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
--------------------------------------------------------------------------------
-- Backwards Compatibility:
--------------------------------------------------------------------------------
{-# DEPRECATED send "Use sendMessageB instead." #-}
{-# DEPRECATED sendSM "Use sendSomeMessageB instead." #-}
{-# DEPRECATED sendSM_ "Use sendSomeMessage instead." #-}
{-# DEPRECATED tryInOrder "Use tryInOrderWithNoRefreshToCurrentB instead." #-}
{-# DEPRECATED tryInOrder_ "Use tryInOrderWithNoRefreshToCurrent instead." #-}
{-# DEPRECATED tryMessage "Use tryMessageWithNoRefreshToCurrentB instead." #-}
{-# DEPRECATED tryMessage_ "Use tryMessageWithNoRefreshToCurrent instead." #-}
-- $backwardsCompatibility
-- The following functions exist solely for compatibility with pre-0.14
-- releases.
-- | See 'sendMessageWithNoRefreshToCurrentB'.
send :: Message a => a -> X Bool
send = sendMessageWithNoRefreshToCurrentB
-- | See 'sendSomeMessageWithNoRefreshToCurrentB'.
sendSM :: SomeMessage -> X Bool
sendSM m = do w <- workspace . current <$> gets windowset
ml' <- handleMessage (layout w) m `catchX` return Nothing
updateLayout (tag w) ml'
return $ isJust ml'
sendSM = sendSomeMessageWithNoRefreshToCurrentB
-- | See 'sendSomeMessageWithNoRefreshToCurrent'.
sendSM_ :: SomeMessage -> X ()
sendSM_ m = sendSM m >> return ()
sendSM_ = sendSomeMessageWithNoRefreshToCurrent
-- | See 'tryInOrderWithNoRefreshToCurrentB'.
tryInOrder :: [SomeMessage] -> X Bool
tryInOrder = tryInOrderWithNoRefreshToCurrentB
-- | See 'tryInOrderWithNoRefreshToCurrent'.
tryInOrder_ :: [SomeMessage] -> X ()
tryInOrder_ = tryInOrderWithNoRefreshToCurrent
-- | See 'tryMessageWithNoRefreshToCurrentB'.
tryMessage :: (Message a, Message b) => a -> b -> X Bool
tryMessage = tryMessageWithNoRefreshToCurrentB
-- | See 'tryMessageWithNoRefreshToCurrent'.
tryMessage_ :: (Message a, Message b) => a -> b -> X ()
tryMessage_ = tryMessageWithNoRefreshToCurrent

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

@@ -0,0 +1,143 @@
----------------------------------------------------------------------------
-- |
-- 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.Minimized" 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

@@ -1,6 +1,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.MouseGestures
-- Description : Support for simple mouse gestures.
-- Copyright : (c) Lukas Mai
-- License : BSD3-style (see LICENSE)
--
@@ -21,14 +22,13 @@ 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
--
@@ -111,7 +111,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)
--
@@ -43,11 +44,11 @@ import XMonad.Util.XUtils
--
-- Then edit your @layoutHook@ by modifying a given layout:
--
-- > myLayout = mouseResize $ windowArrange $ layoutHook defaultConfig
-- > myLayout = mouseResize $ windowArrange $ layoutHook def
--
-- and then:
--
-- > main = xmonad defaultConfig { layoutHook = myLayout }
-- > main = xmonad def { layoutHook = myLayout }
--
-- For more detailed instructions on editing the layoutHook see:
--
@@ -56,7 +57,7 @@ import XMonad.Util.XUtils
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)
--
@@ -32,12 +33,20 @@ module XMonad.Actions.Navigation2D ( -- * Usage
-- * Exported functions and types
-- #Exports#
withNavigation2DConfig
navigation2D
, navigation2DP
, additionalNav2DKeys
, additionalNav2DKeysP
, withNavigation2DConfig
, Navigation2DConfig(..)
, defaultNavigation2DConfig
, def
, Navigation2D
, lineNavigation
, centerNavigation
, sideNavigation
, sideNavigationWithBias
, hybridOf
, hybridNavigation
, fullScreenRect
, singleWindowRect
, switchLayer
@@ -49,13 +58,14 @@ 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
-- $usage
@@ -63,24 +73,62 @@ import XMonad.Util.Types
-- 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. 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@:
--
-- > import XMonad.Actions.Navigation2D
--
-- Then edit your keybindings:
-- Then add the configuration of the module to your main function:
--
-- > main = xmonad $ navigation2D def
-- > (xK_Up, xK_Left, xK_Down, xK_Right)
-- > [(mod4Mask, windowGo ),
-- > (mod4Mask .|. shiftMask, windowSwap)]
-- > False
-- > $ def
--
-- Alternatively, 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:
--
-- > main = xmonad $ withNavigation2DConfig def
-- > $ additionalNav2DKeys (xK_Up, xK_Left, xK_Down, xK_Right)
-- > [(mod4Mask, windowGo ),
-- > (mod4Mask .|. shiftMask, windowSwap)]
-- > False
-- > $ additionalNav2DKeys (xK_u, xK_l, xK_d, xK_r)
-- > [(mod4Mask, screenGo ),
-- > (mod4Mask .|. shiftMask, screenSwap)]
-- > False
-- > $ def
--
-- Or you can add the configuration of the module to your main function:
--
-- > main = xmonad $ withNavigation2DConfig def $ def
--
-- And specify your keybindings normally:
--
-- > -- Switch between layers
-- > , ((modm, xK_space), switchLayers)
-- > , ((modm, xK_space), switchLayer)
-- >
-- > -- Directional navigation of windows
-- > , ((modm, xK_Right), windowGo R False)
@@ -112,11 +160,6 @@ import XMonad.Util.Types
-- > , ((modm .|. mod1Mask, xK_u ), windowToScreen U False)
-- > , ((modm .|. mod1Mask, xK_d ), windowToScreen D False)
--
-- and add the configuration of the module to your main function:
--
-- > main = xmonad $ withNavigation2DConfig defaultNavigation2DConfig
-- > $ defaultConfig
--
-- For detailed instruction on editing the key binding see:
--
-- "XMonad.Doc.Extending#Editing_key_bindings".
@@ -147,10 +190,10 @@ import XMonad.Util.Types
-- example, for the Full layout, is to switch to center navigation for the Full
-- layout:
--
-- > myNavigation2DConfig = defaultNavigation2DConfig { layoutNavigation = [("Full", centerNavigation)] }
-- > myNavigation2DConfig = def { layoutNavigation = [("Full", centerNavigation)] }
-- >
-- > main = xmonad $ withNavigation2DConfig myNavigation2DConfig
-- > $ defaultConfig
-- > $ def
--
-- The navigation between windows is based on their screen rectangles, which are
-- available /and meaningful/ only for mapped windows. Thus, as already said,
@@ -164,12 +207,12 @@ import XMonad.Util.Types
-- on top of each other so that only the frontmost one is visible. This can be
-- done as follows:
--
-- > myNavigation2DConfig = defaultNavigation2DConfig { layoutNavigation = [("Full", centerNavigation)]
-- > , unmappedWindowRect = [("Full", singleWindowRect)]
-- > }
-- > myNavigation2DConfig = def { layoutNavigation = [("Full", centerNavigation)]
-- > , unmappedWindowRect = [("Full", singleWindowRect)]
-- > }
-- >
-- > main = xmonad $ withNavigation2DConfig myNavigation2DConfig
-- > $ defaultConfig
-- > $ def
--
-- With this setup, Left/Up navigation behaves like standard
-- 'XMonad.StackSet.focusUp' and Right/Down navigation behaves like
@@ -279,7 +322,51 @@ lineNavigation = N 1 doLineNavigation
centerNavigation :: Navigation2D
centerNavigation = N 2 doCenterNavigation
-- | Stores the configuration of directional navigation
-- | 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
{-# DEPRECATED hybridNavigation "Use hybridOf with lineNavigation and centerNavigation as arguments." #-}
hybridNavigation :: Navigation2D
hybridNavigation = hybridOf lineNavigation centerNavigation
-- | Stores the configuration of directional navigation. The 'Default' instance
-- uses line navigation for the tiled layer and for navigation between screens,
-- and center navigation for the float layer. No custom navigation strategies
-- or rectangles for unmapped windows are defined for individual layouts.
data Navigation2DConfig = Navigation2DConfig
{ defaultTiledNavigation :: Navigation2D -- ^ default navigation strategy for the tiled layer
, floatNavigation :: Navigation2D -- ^ navigation strategy for the float layer
@@ -298,14 +385,64 @@ 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
-- | Convenience function for enabling Navigation2D with typical keybindings.
-- Takes a Navigation2DConfig, an (up, left, down, right) tuple, a mapping from
-- modifier key to action, and a bool to indicate if wrapping should occur, and
-- returns a function from XConfig to XConfig.
-- Example:
--
-- > navigation2D def (xK_w, xK_a, xK_s, xK_d) [(mod4Mask, windowGo), (mod4Mask .|. shiftMask, windowSwap)] False myConfig
navigation2D :: Navigation2DConfig -> (KeySym, KeySym, KeySym, KeySym) -> [(ButtonMask, Direction2D -> Bool -> X ())] ->
Bool -> XConfig l -> XConfig l
navigation2D navConfig (u, l, d, r) modifiers wrap xconfig =
additionalNav2DKeys (u, l, d, r) modifiers wrap $
withNavigation2DConfig navConfig xconfig
-- | Convenience function for enabling Navigation2D with typical keybindings,
-- using the syntax defined in 'XMonad.Util.EZConfig.mkKeymap'. Takes a
-- Navigation2DConfig, an (up, left, down, right) tuple, a mapping from key
-- prefix to action, and a bool to indicate if wrapping should occur, and
-- returns a function from XConfig to XConfig. Example:
--
-- > navigation2DP def ("w", "a", "s", "d") [("M-", windowGo), ("M-S-", windowSwap)] False myConfig
navigation2DP :: Navigation2DConfig -> (String, String, String, String) -> [(String, Direction2D -> Bool -> X ())] ->
Bool -> XConfig l -> XConfig l
navigation2DP navConfig (u, l, d, r) modifiers wrap xconfig =
additionalNav2DKeysP (u, l, d, r) modifiers wrap $
withNavigation2DConfig navConfig xconfig
-- | Convenience function for adding keybindings. Takes an (up, left, down,
-- right) tuple, a mapping from key prefix to action, and a bool to indicate if
-- wrapping should occur, and returns a function from XConfig to XConfig.
-- Example:
--
-- > additionalNav2DKeys (xK_w, xK_a, xK_s, xK_d) [(mod4Mask, windowGo), (mod4Mask .|. shiftMask, windowSwap)] False myConfig
additionalNav2DKeys :: (KeySym, KeySym, KeySym, KeySym) -> [(ButtonMask, Direction2D -> Bool -> X ())] ->
Bool -> XConfig l -> XConfig l
additionalNav2DKeys (u, l, d, r) modifiers wrap =
flip additionalKeys [((modif, k), func dir wrap) | (modif, func) <- modifiers, (k, dir) <- dirKeys]
where dirKeys = [(u, U), (l, L), (d, D), (r, R)]
-- | Convenience function for adding keybindings, using the syntax defined in
-- 'XMonad.Util.EZConfig.mkKeymap'. Takes an (up, left, down, right) tuple, a
-- 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 :: (String, String, String, String) -> [(String, Direction2D -> Bool -> X ())] ->
Bool -> XConfig l -> XConfig l
additionalNav2DKeysP (u, l, d, r) modifiers wrap =
flip additionalKeysP [(modif ++ k, func dir wrap) | (modif, func) <- modifiers, (k, dir) <- dirKeys]
where dirKeys = [(u, U), (l, L), (d, D), (r, R)]
-- So we can store the configuration in extensible state
instance ExtensionClass Navigation2DConfig where
initialValue = defaultNavigation2DConfig
initialValue = def
-- | Modifies the xmonad configuration to store the Navigation2D configuration
withNavigation2DConfig :: Navigation2DConfig -> XConfig a -> XConfig a
@@ -313,12 +450,8 @@ withNavigation2DConfig conf2d xconf = xconf { startupHook = startupHook xconf
>> XS.put conf2d
}
-- | Default navigation configuration. It uses line navigation for the tiled
-- layer and for navigation between screens, and center navigation for the float
-- layer. No custom navigation strategies or rectangles for unmapped windows are
-- defined for individual layouts.
defaultNavigation2DConfig :: Navigation2DConfig
defaultNavigation2DConfig = Navigation2DConfig { defaultTiledNavigation = lineNavigation
instance Default Navigation2DConfig where
def = Navigation2DConfig { defaultTiledNavigation = lineNavigation
, floatNavigation = centerNavigation
, screenNavigation = lineNavigation
, layoutNavigation = []
@@ -344,7 +477,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
)
@@ -354,7 +487,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
@@ -363,7 +495,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
)
@@ -371,32 +503,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
@@ -516,7 +644,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
@@ -536,8 +664,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
@@ -582,7 +709,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
@@ -623,9 +750,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
@@ -668,6 +794,55 @@ doCenterNavigation dir (cur, rect) winrects
-- or it has the same distance but comes later
-- in the window stack
-- 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 = let (_, _:l) = break (d ==) [U, L, D, R]
in foldr (const $ (.) rHalfPiCC) id l
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
swap win winset = W.focusWindow cur
@@ -683,7 +858,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
@@ -708,14 +883,10 @@ swap win winset = W.focusWindow cur
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]
@@ -752,8 +923,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
@@ -763,16 +934,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)
--
@@ -27,7 +28,7 @@ toggleBorder :: Window -> X ()
toggleBorder w = do
bw <- asks (borderWidth . config)
withDisplay $ \d -> io $ do
cw <- wa_border_width `fmap` getWindowAttributes d w
cw <- wa_border_width <$> getWindowAttributes d w
if cw == 0
then setWindowBorderWidth d w bw
else setWindowBorderWidth d w 0

View File

@@ -1,6 +1,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.OnScreen
-- Description : Control workspaces on different screens (in xinerama mode).
-- Copyright : (c) 2009 Nils Schweinsberg
-- License : BSD3-style (see LICENSE)
--
@@ -26,12 +27,9 @@ module XMonad.Actions.OnScreen (
) where
import XMonad
import XMonad.Prelude (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

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\/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
-- "XMonad.Doc.Extending#Editing_key_bindings".
-- | 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)
--
@@ -46,4 +47,3 @@ bindOn bindings = chooseAction chooser where
Nothing -> case lookup "" bindings of
Just action -> action
Nothing -> return ()

View File

@@ -2,6 +2,7 @@
-----------------------------------------------------------------------------
-- |
-- 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 +22,18 @@ module XMonad.Actions.PhysicalScreens (
, sendToScreen
, onNextNeighbour
, onPrevNeighbour
, horizontalScreenOrderer
, verticalScreenOrderer
, ScreenComparator(ScreenComparator)
, getScreenIdAndRectangle
, screenComparatorById
, screenComparatorByRectangle
) where
import XMonad
import XMonad.Prelude (elemIndex, fromMaybe, on, sortBy)
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 +41,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:
> 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,7 +62,7 @@ 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".
@@ -63,52 +71,78 @@ For detailed instructions on editing your key bindings, see
-- | The type of the index of a screen by location
newtype PhysicalScreen = P Int deriving (Eq,Ord,Show,Read,Enum,Num,Integral,Real)
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 :: 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
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)

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,11 +39,9 @@ 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
import XMonad
import XMonad.StackSet hiding (workspaces)
import XMonad.Util.Run
@@ -51,12 +50,13 @@ import XMonad.Util.Run
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@ file:
--
-- > import XMonad.Actions.Plane
-- > import Data.Map (union)
-- >
-- > main = xmonad defaultConfig {keys = myKeys}
-- > main = xmonad def {keys = myKeys}
-- >
-- > myKeys conf = union (keys defaultConfig conf) $ myNewKeys conf
-- > myKeys conf = union (keys def conf) $ myNewKeys conf
-- >
-- > myNewkeys (XConfig {modMask = modm}) = planeKeys modm (Lines 3) Finite
-- > myNewKeys (XConfig {modMask = modm}) = planeKeys modm (Lines 3) Finite
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
@@ -226,4 +226,4 @@ gconftool :: String
gconftool = "gconftool-2"
parameters :: [String]
parameters = ["--get", "/apps/panel/applets/workspace_switcher_screen0/prefs/num_rows"]
parameters = ["--get", "/apps/panel/applets/workspace_switcher_screen0/prefs/num_rows"]

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

@@ -0,0 +1,212 @@
{-# 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
, 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)
{- $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 :: [(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 (head events) ++ [key]
_ -> reverse (key:events)
keyToNum = (xK_0, 0) : zip [xK_1 .. xK_9] [1..9]
-- | Turn a prefix-aware X action into an X-action.
--
-- First, fetch the current prefix, then pass it as argument to the
-- original function. You should use this to "run" your commands.
withPrefixArgument :: (PrefixArgument -> X ()) -> X ()
withPrefixArgument = (>>=) 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
-- | 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

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

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

@@ -1,6 +1,7 @@
-----------------------------------------------------------------------------
-- |
-- 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)
--
@@ -40,8 +41,8 @@ import XMonad
-- | 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' (\l -> tail l++[head l]))
rotSlavesDown = windows $ modify' (rotSlaves' (\l -> last l : init l))
-- | The actual rotation, as a pure function on the window stack.
rotSlaves' :: ([a] -> [a]) -> Stack a -> Stack a
@@ -49,12 +50,12 @@ 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))
(revls',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' (\l -> tail l++[head l]))
rotAllDown = windows $ modify' (rotAll' (\l -> last l : init l))
-- | The actual rotation, as a pure function on the window stack.
rotAll' :: ([a] -> [a]) -> Stack a -> Stack a

View File

@@ -0,0 +1,161 @@
-----------------------------------------------------------------------------
-- |
-- 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 (partition, sortOn, (\\))
import qualified Data.Map as M
import XMonad (Window, WindowSpace, Rectangle, X, runLayout, screenRect, windows, withWindowSet)
import XMonad.StackSet (Screen (Screen), Stack (Stack), current, floating, modify', stack)
import XMonad.Util.Stack (reverseS)
{- $usage
You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
> 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', 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,
@@ -35,22 +38,26 @@ module XMonad.Actions.Search ( -- * Usage
debbts,
debpts,
dictionary,
ebay,
github,
google,
hackage,
hoogle,
images,
imdb,
isohunt,
lucky,
maps,
mathworld,
openstreetmap,
scholar,
stackage,
thesaurus,
wayback,
wikipedia,
wiktionary,
youtube,
vocabulary,
duckduckgo,
multi,
-- * Use case: searching with a submap
-- $tip
@@ -59,15 +66,16 @@ module XMonad.Actions.Search ( -- * Usage
Browser, Site, Query, Name, Search
) where
import Codec.Binary.UTF8.String (encode)
import Data.Char (isAlphaNum, isAscii)
import Data.List (isPrefixOf)
import Text.Printf
import XMonad (X(), MonadIO, liftIO)
import XMonad.Prompt (XPrompt(showXPrompt, nextCompletion, commandToComplete), mkXPrompt, XPConfig(), historyCompletionP, getNextCompletion)
import XMonad.Prompt.Shell (getBrowser)
import XMonad.Util.Run (safeSpawn)
import XMonad.Util.XSelection (getSelection)
import Codec.Binary.UTF8.String (encode)
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)
{- $usage
@@ -108,18 +116,22 @@ import XMonad.Util.XSelection (getSelection)
* 'dictionary' -- dictionary.reference.com search.
* 'ebay' -- Ebay keyword search.
* 'github' -- GitHub keyword search.
* 'google' -- basic Google search.
* 'hackage' -- Hackage, the Haskell package database.
* 'hoogle' -- Hoogle, the Haskell libraries API search engine.
* 'stackage' -- Stackage, An alternative 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.
@@ -130,7 +142,7 @@ import XMonad.Util.XSelection (getSelection)
* 'scholar' -- Google scholar academic search.
* 'thesaurus' -- thesaurus.reference.com search.
* 'thesaurus' -- thesaurus.com search.
* 'wayback' -- the Wayback Machine.
@@ -138,6 +150,10 @@ import XMonad.Util.XSelection (getSelection)
* 'youtube' -- Youtube video search.
* 'vocabulary' -- Dictionary search
* 'duckduckgo' -- DuckDuckGo search engine.
* 'multi' -- Search based on the prefix. \"amazon:Potter\" will use amazon, etc. With no prefix searches google.
Feel free to add more! -}
@@ -157,7 +173,7 @@ Then add the following to your key bindings:
> ...
> -- Search commands
> , ((modm, xK_s), SM.submap $ searchEngineMap $ S.promptSearch P.defaultXPConfig)
> , ((modm, xK_s), SM.submap $ searchEngineMap $ S.promptSearch P.def)
> , ((modm .|. shiftMask, xK_s), SM.submap $ searchEngineMap $ S.selectSearch)
>
> ...
@@ -173,14 +189,14 @@ Or in combination with XMonad.Util.EZConfig:
> ...
> ] -- end of regular keybindings
> -- Search commands
> ++ [("M-s " ++ k, S.promptSearch P.defaultXPConfig f) | (k,f) <- searchList ]
> ++ [("M-s " ++ k, S.promptSearch P.def f) | (k,f) <- searchList ]
> ++ [("M-S-s " ++ k, S.selectSearch f) | (k,f) <- searchList ]
>
> ...
>
> searchList :: [(String, S.SearchEngine)]
> searchList = [ ("g", S.google)
> , ("h", S.hoohle)
> , ("h", S.hoogle)
> , ("w", S.wikipedia)
> ]
@@ -199,7 +215,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
@@ -237,7 +253,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
@@ -246,21 +262,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 $ tail $ 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.
@@ -270,35 +286,39 @@ 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, thesaurus, wayback, wikipedia, wiktionary,
youtube :: SearchEngine
amazon = searchEngine "amazon" "http://www.amazon.com/exec/obidos/external-search?index=all&keyword="
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="
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/*/"++)
amazon, alpha, codesearch, deb, debbts, debpts, dictionary, ebay, github, google, hackage, hoogle,
images, imdb, lucky, maps, mathworld, openstreetmap, scholar, stackage, thesaurus, vocabulary, wayback, wikipedia, wiktionary,
youtube, duckduckgo :: SearchEngine
amazon = searchEngine "amazon" "https://www.amazon.com/s/ref=nb_sb_noss_2?url=search-alias%3Daps&field-keywords="
alpha = searchEngine "alpha" "https://www.wolframalpha.com/input/?i="
codesearch = searchEngine "codesearch" "https://developers.google.com/s/results/code-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/"
ebay = searchEngine "ebay" "https://www.ebay.com/sch/i.html?_nkw="
github = searchEngine "github" "https://github.com/search?q="
google = searchEngine "google" "https://www.google.com/search?num=100&q="
hackage = searchEngine "hackage" "https://hackage.haskell.org/package/"
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="
openstreetmap = searchEngine "openstreetmap" "https://www.openstreetmap.org/search?query="
scholar = searchEngine "scholar" "https://scholar.google.com/scholar?q="
stackage = searchEngine "stackage" "https://www.stackage.org/lts/hoogle?q="
thesaurus = searchEngine "thesaurus" "https://thesaurus.com/browse/"
wikipedia = searchEngine "wiki" "https://en.wikipedia.org/wiki/Special:Search?go=Go&search="
wiktionary = searchEngine "wikt" "https://en.wiktionary.org/wiki/Special:Search?go=Go&search="
youtube = searchEngine "youtube" "https://www.youtube.com/results?search_type=search_videos&search_query="
wayback = searchEngineF "wayback" ("https://web.archive.org/web/*/"++)
vocabulary = searchEngine "vocabulary" "https://www.vocabulary.com/search?q="
duckduckgo = searchEngine "duckduckgo" "https://duckduckgo.com/?t=lm&q="
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, (prefixAware google)]
multi = namedEngine "multi" $ foldr1 (!>) [amazon, alpha, codesearch, deb, debbts, debpts, dictionary, ebay, github, google, hackage, hoogle, images, imdb, lucky, maps, mathworld, openstreetmap, scholar, thesaurus, wayback, wikipedia, wiktionary, duckduckgo, prefixAware google]
{- | 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
@@ -306,9 +326,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"
@@ -328,6 +348,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
@@ -344,8 +365,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 ("Search [" `isPrefixOf`)
mkXPrompt (Search name) config hc $ search browser site
{- | Like 'promptSearchBrowser', but only suggest previous searches for the
given 'SearchEngine' in the prompt. -}
promptSearchBrowser' :: XPConfig -> Browser -> SearchEngine -> X ()
promptSearchBrowser' config browser (SearchEngine name site) = do
hc <- historyCompletionP (searchName `isPrefixOf`)
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,8 @@
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE CPP #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.ShowText
-- Description : Display text on the screen.
-- Copyright : (c) Mario Pastorelli (2012)
-- License : BSD-style (see xmonad/LICENSE)
--
@@ -16,17 +17,16 @@
module XMonad.Actions.ShowText
( -- * Usage
-- $usage
defaultSTConfig
def
, 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, when)
import XMonad.StackSet (current,screen)
import XMonad.Util.Font (Align(AlignCenter)
, initXMF
@@ -36,7 +36,6 @@ 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
@@ -52,12 +51,12 @@ import qualified XMonad.Util.ExtensibleState as ES
--
-- You can then use flashText in your keybindings:
--
-- > ((modMask, xK_Right), flashText defaultSTConfig 1 "->" >> nextWS)
-- > ((modMask, xK_Right), flashText def 1 "->" >> nextWS)
--
-- | 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
@@ -72,9 +71,13 @@ data ShowTextConfig =
, st_fg :: String -- ^ Foreground color
}
defaultSTConfig :: ShowTextConfig
defaultSTConfig =
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"
}
@@ -84,8 +87,8 @@ 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)
when (mtyp == a && not (null d))
(whenJust (lookup (fromIntegral $ head d) m) deleteWindow)
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\/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)
--

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

View File

@@ -1,7 +1,7 @@
{-# LANGUAGE DeriveDataTypeable #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.SpawnOn
-- Description : Modify a window spawned by a command.
-- Copyright : (c) Spencer Janssen
-- License : BSD
--
@@ -20,6 +20,7 @@ module XMonad.Actions.SpawnOn (
-- $usage
Spawner,
manageSpawn,
manageSpawnWithGC,
spawnHere,
spawnOn,
spawnAndDo,
@@ -27,10 +28,14 @@ module XMonad.Actions.SpawnOn (
shellPromptOn
) where
import Data.List (isInfixOf)
import Control.Exception (tryJust)
import System.IO.Error (isDoesNotExistError)
import System.IO.Unsafe (unsafePerformIO)
import System.Posix.Types (ProcessID)
import Text.Printf (printf)
import XMonad
import XMonad.Prelude
import qualified XMonad.StackSet as W
import XMonad.Hooks.ManageHelpers
@@ -44,16 +49,16 @@ import qualified XMonad.Util.ExtensibleState as XS
-- > import XMonad.Actions.SpawnOn
--
-- > main = do
-- > xmonad defaultConfig {
-- > xmonad def {
-- > ...
-- > manageHook = manageSpawn <+> manageHook defaultConfig
-- > manageHook = manageSpawn <+> manageHook def
-- > ...
-- > }
--
-- To ensure that application appears on a workspace it was launched at, add keybindings like:
--
-- > , ((mod1Mask,xK_o), spawnHere "urxvt")
-- > , ((mod1Mask,xK_s), shellPromptHere defaultXPConfig)
-- > , ((mod1Mask,xK_s), shellPromptHere def)
--
-- The module can also be used to apply other manage hooks to the window of
-- the spawned application(e.g. float or resize it).
@@ -61,13 +66,30 @@ import qualified XMonad.Util.ExtensibleState as XS
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
newtype Spawner = Spawner {pidsRef :: [(ProcessID, ManageHook)]} deriving Typeable
newtype Spawner = Spawner {pidsRef :: [(ProcessID, ManageHook)]}
instance ExtensionClass Spawner where
initialValue = Spawner []
maxPids :: Int
maxPids = 5
getPPIDOf :: ProcessID -> Maybe ProcessID
getPPIDOf thisPid =
case unsafePerformIO . tryJust (guard . isDoesNotExistError) . readFile . printf "/proc/%d/stat" $ toInteger thisPid of
Left _ -> Nothing
Right contents -> case lines contents of
[] -> Nothing
first : _ -> case words first of
_ : _ : _ : ppid : _ -> Just $ fromIntegral (read ppid :: Int)
_ -> Nothing
getPPIDChain :: ProcessID -> [ProcessID]
getPPIDChain thisPid = ppid_chain thisPid []
where ppid_chain pid' acc =
if pid' == 0
then acc
else case getPPIDOf pid' of
Nothing -> acc
Just ppid -> ppid_chain ppid (ppid : acc)
-- | Get the current Spawner or create one if it doesn't exist.
modifySpawner :: ([(ProcessID, ManageHook)] -> [(ProcessID, ManageHook)]) -> X ()
@@ -76,20 +98,34 @@ modifySpawner f = XS.modify (Spawner . f . pidsRef)
-- | Provides a manage hook to react on process spawned with
-- 'spawnOn', 'spawnHere' etc.
manageSpawn :: ManageHook
manageSpawn = do
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 . modifySpawner $ filter ((/= p) . fst)
let ppid_chain = case mp of
Just winpid -> winpid : getPPIDChain winpid
Nothing -> []
known_window_handlers = [ mh
| ppid <- ppid_chain
, let mpid = lookup ppid pids
, isJust mpid
, let (Just mh) = mpid ]
case known_window_handlers of
[] -> idHook
(mh:_) -> do
whenJust mp $ \p -> liftX $ do
ps <- XS.gets pidsRef
XS.put . Spawner =<< garbageCollect (filter ((/= p) . fst) ps)
mh
mkPrompt :: (String -> X ()) -> XPConfig -> X ()
mkPrompt cb c = do
cmds <- io $ getCommands
mkXPrompt Shell c (getShellCompl cmds) cb
cmds <- io getCommands
mkXPrompt Shell c (getShellCompl cmds $ searchPredicate c) cb
-- | Replacement for Shell prompt ("XMonad.Prompt.Shell") which launches
-- application on current workspace.
@@ -109,13 +145,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 $ (take maxPids . ((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,12 +17,13 @@ module XMonad.Actions.Submap (
-- * Usage
-- $usage
submap,
submapDefault
submapDefault,
submapDefaultWithKey
) where
import Data.Bits
import XMonad.Prelude (fix, fromMaybe)
import XMonad hiding (keys)
import qualified Data.Map as M
import Control.Monad.Fix (fix)
{- $usage
@@ -58,25 +60,39 @@ For detailed instructions on editing your key bindings, see
-- corresponding action, or does nothing if the key is not found in
-- the map.
submap :: M.Map (KeyMask, KeySym) (X ()) -> X ()
submap keys = submapDefault (return ()) keys
submap = submapDefault (return ())
-- | Like 'submap', but executes a default action if the key did not match.
submapDefault :: X () -> M.Map (KeyMask, KeySym) (X ()) -> X ()
submapDefault def keys = do
submapDefault = submapDefaultWithKey . const
-- | Like 'submapDefault', but sends the unmatched key to the default
-- action as argument.
submapDefaultWithKey :: ((KeyMask, KeySym) -> X ())
-> M.Map (KeyMask, KeySym) (X ())
-> X ()
submapDefaultWithKey defAction keys = do
XConf { theRoot = root, display = d } <- ask
io $ grabKeyboard d root False grabModeAsync grabModeAsync currentTime
io $ grabPointer d root False buttonPressMask grabModeAsync grabModeAsync
none none currentTime
(m, s) <- io $ allocaXEvent $ \p -> fix $ \nextkey -> do
maskEvent d keyPressMask p
KeyEvent { ev_keycode = code, ev_state = m } <- getEvent p
keysym <- keycodeToKeysym d code 0
if isModifierKey keysym
then nextkey
else return (m, keysym)
maskEvent d (keyPressMask .|. buttonPressMask) p
ev <- getEvent p
case ev of
KeyEvent { ev_keycode = code, ev_state = m } -> do
keysym <- keycodeToKeysym d code 0
if isModifierKey keysym
then nextkey
else return (m, keysym)
_ -> return (0, 0)
-- Remove num lock mask and Xkb group state bits
m' <- cleanMask $ m .&. ((1 `shiftL` 12) - 1)
io $ ungrabPointer d currentTime
io $ ungrabKeyboard d currentTime
io $ sync d False
maybe def id (M.lookup (m', s) keys)
fromMaybe (defAction (m', s)) (M.lookup (m', s) keys)

View File

@@ -0,0 +1,403 @@
-----------------------------------------------------------------------------
-- |
-- 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
-- $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 = head . 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)
--
@@ -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,14 +27,12 @@ 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
@@ -53,12 +52,12 @@ econst = const . return
-- > , ((modm, xK_d ), withTaggedP "abc" (W.shiftWin "2"))
-- > , ((modm .|. shiftMask, xK_d ), withTaggedGlobalP "abc" shiftHere)
-- > , ((modm .|. controlMask, xK_d ), focusUpTaggedGlobal "abc")
-- > , ((modm, xK_g ), tagPrompt defaultXPConfig (\s -> withFocused (addTag s)))
-- > , ((modm .|. controlMask, xK_g ), tagDelPrompt defaultXPConfig)
-- > , ((modm .|. shiftMask, xK_g ), tagPrompt defaultXPConfig (\s -> withTaggedGlobal s float))
-- > , ((modWinMask, xK_g ), tagPrompt defaultXPConfig (\s -> withTaggedP s (W.shiftWin "2")))
-- > , ((modWinMask .|. shiftMask, xK_g ), tagPrompt defaultXPConfig (\s -> withTaggedGlobalP s shiftHere))
-- > , ((modWinMask .|. controlMask, xK_g ), tagPrompt defaultXPConfig (\s -> focusUpTaggedGlobal s))
-- > , ((modm, xK_g ), tagPrompt def (\s -> withFocused (addTag s)))
-- > , ((modm .|. controlMask, xK_g ), tagDelPrompt def)
-- > , ((modm .|. shiftMask, xK_g ), tagPrompt def (\s -> withTaggedGlobal s float))
-- > , ((modWinMask, xK_g ), tagPrompt def (\s -> withTaggedP s (W.shiftWin "2")))
-- > , ((modWinMask .|. shiftMask, xK_g ), tagPrompt def (\s -> withTaggedGlobalP s shiftHere))
-- > , ((modWinMask .|. controlMask, xK_g ), tagPrompt def (\s -> focusUpTaggedGlobal s))
--
-- NOTE: Tags are saved as space separated strings and split with
-- 'unwords'. Thus if you add a tag \"a b\" the window will have
@@ -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 ()
@@ -158,7 +156,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 +165,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 +178,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,94 @@
-----------------------------------------------------------------------------
-- |
-- 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\/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) $ do
focus window
(offsetX, offsetY) <- getPointerOffset window
(winX, winY, winWidth, winHeight) <- getWindowPlacement window
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 :: Window -> X (Int, Int, Int, Int)
getWindowPlacement window = do
wa <- withDisplay (\d -> io $ getWindowAttributes d window)
return (fi $ wa_x wa, fi $ wa_y wa, fi $ wa_width wa, fi $ wa_height wa)
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
let (ls, t : rs) = 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

@@ -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,20 +20,49 @@ module XMonad.Actions.TopicSpace
-- * Usage
-- $usage
Topic
-- * Types for Building Topics
Topic
, Dir
, TopicConfig(..)
, 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
, (>*>)
@@ -40,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
@@ -74,110 +105,128 @@ import qualified XMonad.Util.ExtensibleState as XS
-- of last focused topics.
-- $usage
-- Here is an example of configuration using TopicSpace:
-- You can use this module with the following in your @~\/.xmonad\/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 = defaultTopicConfig
-- > { 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)
-- > ]
-- > myTopicConfig = def
-- > { 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 $ defaultConfig
-- > { 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 ()
@@ -187,81 +236,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
}
defaultTopicConfig :: TopicConfig
defaultTopicConfig = TopicConfig { topicDirs = M.empty
, topicActions = M.empty
, defaultTopicAction = const (ask >>= spawn . terminal . config)
, defaultTopic = "1"
, maxTopicHistory = 10
}
-- | 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
@@ -271,46 +318,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

@@ -0,0 +1,672 @@
{-# 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)
--
-- Maintainer : Tom Smeets <tom.tsmeets@gmail.com>
-- Stability : unstable
-- Portability : unportable
--
--
-- TreeSelect displays your workspaces or actions in a Tree-like format.
-- You can select the desired workspace/action with the cursor or hjkl keys.
--
-- This module is fully configurable and very useful if you like to have a
-- lot of workspaces.
--
-- Only the nodes up to the currently selected are displayed.
-- This will be configurable in the near future by changing 'ts_hidechildren' to @False@, this is not yet implemented.
--
-- <<https://wiki.haskell.org/wikiupload/thumb/0/0b/Treeselect-Workspace.png/800px-Treeselect-Workspace.png>>
--
-----------------------------------------------------------------------------
module XMonad.Actions.TreeSelect
(
-- * Usage
-- $usage
treeselectWorkspace
, toWorkspaces
, treeselectAction
-- * Configuring
-- $config
, Pixel
-- $pixel
, TSConfig(..)
, tsDefaultConfig
, def
-- * Navigation
-- $navigation
, defaultNavigation
, select
, cancel
, moveParent
, moveChild
, moveNext
, movePrev
, moveHistBack
, moveHistForward
, moveTo
-- * Advanced usage
-- $advusage
, TSNode(..)
, treeselect
, treeselectAt
) where
import Control.Monad.Reader
import Control.Monad.State
import Data.Tree
import Foreign (shiftL, shiftR, (.&.))
import System.IO
import XMonad hiding (liftX)
import XMonad.Prelude
import XMonad.StackSet as W
import XMonad.Util.Font
import XMonad.Util.NamedWindows
import XMonad.Util.TreeZipper
import XMonad.Hooks.WorkspaceHistory
import qualified Data.Map as M
#ifdef XFT
import Graphics.X11.Xft
import Graphics.X11.Xrender
#endif
-- $usage
--
-- These imports are used in the following example
--
-- > import Data.Tree
-- > import XMonad.Actions.TreeSelect
-- > import XMonad.Hooks.WorkspaceHistory
-- > import qualified XMonad.StackSet as W
--
-- For selecting Workspaces, you need to define them in a tree structure using 'Data.Tree.Node' instead of just a standard list
--
-- Here is an example workspace-tree
--
-- > myWorkspaces :: Forest String
-- > myWorkspaces = [ Node "Browser" [] -- a workspace for your browser
-- > , Node "Home" -- for everyday activity's
-- > [ Node "1" [] -- with 4 extra sub-workspaces, for even more activity's
-- > , Node "2" []
-- > , Node "3" []
-- > , Node "4" []
-- > ]
-- > , Node "Programming" -- for all your programming needs
-- > [ Node "Haskell" []
-- > , Node "Docs" [] -- documentation
-- > ]
-- > ]
--
-- Then add it to your 'XMonad.Core.workspaces' using the 'toWorkspaces' function.
--
-- Optionally, if you add 'workspaceHistoryHook' to your 'logHook' you can use the \'o\' and \'i\' keys to select from previously-visited workspaces
--
-- > 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
--
-- you could bind @Mod-f@ to switch workspace
--
-- > , ((modMask, xK_f), treeselectWorkspace myTreeConf myWorkspaces W.greedyView)
--
-- and bind @Mod-Shift-f@ to moving the focused windows to a workspace
--
-- > , ((modMask .|. shiftMask, xK_f), treeselectWorkspace myTreeConf myWorkspaces W.shift)
-- $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 'def'
--
-- > 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
--
-- The 'Pixel' Color format is in the form of @0xaarrggbb@
--
-- Note that transparency is only supported if you have a window compositor running like <https://github.com/chjj/compton compton>
--
-- Some Examples:
--
-- @
-- white = 0xffffffff
-- black = 0xff000000
-- red = 0xffff0000
-- green = 0xff00ff00
-- blue = 0xff0000ff
-- transparent = 0x00000000
-- @
-- $navigation
--
-- Keybindings for navigations can also be modified
--
-- This is the definition of 'defaultNavigation'
--
-- > defaultNavigation :: M.Map (KeyMask, KeySym) (TreeSelect a (Maybe a))
-- > defaultNavigation = M.fromList
-- > [ ((0, xK_Escape), cancel)
-- > , ((0, xK_Return), select)
-- > , ((0, xK_space), select)
-- > , ((0, xK_Up), movePrev)
-- > , ((0, xK_Down), moveNext)
-- > , ((0, xK_Left), moveParent)
-- > , ((0, xK_Right), moveChild)
-- > , ((0, xK_k), movePrev)
-- > , ((0, xK_j), moveNext)
-- > , ((0, xK_h), moveParent)
-- > , ((0, xK_l), moveChild)
-- > , ((0, xK_o), moveHistBack)
-- > , ((0, xK_i), moveHistForward)
-- > ]
-- $advusage
-- This module can also be used to select any other action
-- | Extensive configuration for displaying the tree.
--
-- This class also has a 'Default' instance
data TSConfig a = TSConfig { ts_hidechildren :: Bool -- ^ when enabled, only the parents (and their first children) of the current node will be shown (This feature is not yet implemented!)
, ts_background :: Pixel -- ^ background color filling the entire screen.
, ts_font :: String -- ^ XMF font for drawing the node name extra text
, ts_node :: (Pixel, Pixel) -- ^ node foreground (text) and background color when not selected
, ts_nodealt :: (Pixel, Pixel) -- ^ every other node will use this color instead of 'ts_node'
, ts_highlight :: (Pixel, Pixel) -- ^ node foreground (text) and background color when selected
, ts_extra :: Pixel -- ^ extra text color
, ts_node_width :: Int -- ^ node width in pixels
, ts_node_height :: Int -- ^ node height in pixels
, ts_originX :: Int -- ^ tree X position on the screen in pixels
, ts_originY :: Int -- ^ tree Y position on the screen in pixels
, ts_indent :: Int -- ^ indentation amount for each level in pixels
, ts_navigate :: M.Map (KeyMask, KeySym) (TreeSelect a (Maybe a)) -- ^ key bindings for navigating the tree
}
instance Default (TSConfig a) where
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
}
-- | Default navigation
--
-- * navigation using either arrow key or vi style hjkl
-- * Return or Space to confirm
-- * Escape or Backspace to cancel to
defaultNavigation :: M.Map (KeyMask, KeySym) (TreeSelect a (Maybe a))
defaultNavigation = M.fromList
[ ((0, xK_Escape), cancel)
, ((0, xK_Return), select)
, ((0, xK_space), select)
, ((0, xK_Up), movePrev)
, ((0, xK_Down), moveNext)
, ((0, xK_Left), moveParent)
, ((0, xK_Right), moveChild)
, ((0, xK_k), movePrev)
, ((0, xK_j), moveNext)
, ((0, xK_h), moveParent)
, ((0, xK_l), moveChild)
, ((0, xK_o), moveHistBack)
, ((0, xK_i), moveHistForward)
]
-- | Default configuration.
--
-- 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
, tsn_extra :: String -- ^ extra text, displayed next to the node name
, tsn_value :: a -- ^ value to return when this node is selected
}
-- | State used by TreeSelect.
--
-- Contains all needed information such as the window, font and a zipper over the tree.
data TSState a = TSState { tss_tree :: TreeZipper (TSNode a)
, tss_window :: Window
, tss_display :: Display
, tss_size :: (Int, Int) -- ^ size of 'tz_window'
, tss_xfont :: XMonadFont
, tss_gc :: GC
, tss_visual :: Visual
, tss_colormap :: Colormap
, tss_history :: ([[String]], [[String]]) -- ^ history zipper, navigated with 'moveHistBack' and 'moveHistForward'
}
-- | State monad transformer using 'TSState'
newtype TreeSelect a b = TreeSelect { runTreeSelect :: ReaderT (TSConfig a) (StateT (TSState a) X) b }
deriving (Monad, Applicative, Functor, MonadState (TSState a), MonadReader (TSConfig a), MonadIO)
-- | Lift the 'X' action into the 'XMonad.Actions.TreeSelect.TreeSelect' monad
liftX :: X a -> TreeSelect b a
liftX = TreeSelect . lift . lift
-- | Run Treeselect with a given config and tree.
-- This can be used for selectiong anything
--
-- * for switching workspaces and moving windows use 'treeselectWorkspace'
-- * for selecting actions use 'treeselectAction'
treeselect :: TSConfig a -- ^ config file
-> Forest (TSNode a) -- ^ a list of 'Data.Tree.Tree's to select from.
-> X (Maybe a)
treeselect c t = treeselectAt c (fromForest t) []
-- | Same as 'treeselect' but ad a specific starting position
treeselectAt :: TSConfig a -- ^ config file
-> TreeZipper (TSNode a) -- ^ tree structure with a cursor position (starting node)
-> [[String]] -- ^ list of paths that can be navigated with 'moveHistBack' and 'moveHistForward' (bound to the 'o' and 'i' keys)
-> X (Maybe a)
treeselectAt conf@TSConfig{..} zipper hist = withDisplay $ \display -> do
-- create a window on the currently focused screen
rootw <- asks theRoot
Rectangle{..} <- gets $ screenRect . W.screenDetail . W.current . windowset
Just vinfo <- liftIO $ matchVisualInfo display (defaultScreen display) 32 4
colormap <- liftIO $ createColormap display rootw (visualInfo_visual vinfo) allocNone
win <- liftIO $ allocaSetWindowAttributes $ \attributes -> do
set_override_redirect attributes True
set_colormap attributes colormap
set_background_pixel attributes ts_background
set_border_pixel attributes 0
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?
-- make the window visible
mapWindow display win
-- listen to key and mouse button events
selectInput display win (exposureMask .|. keyPressMask .|. buttonReleaseMask)
-- TODO: enable mouse select?
-- and mouse button 1
grabButton display button1 anyModifier win True buttonReleaseMask grabModeAsync grabModeAsync none none
-- grab the keyboard
status <- liftIO $ grabKeyboard display win True grabModeAsync grabModeAsync currentTime
r <- if status == grabSuccess
then do
-- load the XMF font
gc <- liftIO $ createGC display win
xfont <- initXMF ts_font
-- run the treeselect Monad
ret <- evalStateT (runReaderT (runTreeSelect (redraw >> navigate)) conf)
TSState{ tss_tree = zipper
, tss_window = win
, tss_display = display
, tss_xfont = xfont
, tss_size = (fromIntegral rect_width, fromIntegral rect_height)
, tss_gc = gc
, tss_visual = visualInfo_visual vinfo
, tss_colormap = colormap
, tss_history = ([], hist)
}
-- release the XMF font
releaseXMF xfont
liftIO $ freeGC display gc
return ret
else return Nothing
-- destroy the window
liftIO $ do
unmapWindow display win
destroyWindow display win
freeColormap display colormap
-- Flush the output buffer and wait for all the events to be processed
-- TODO: is this needed?
sync display False
return r
-- | Select a workspace and execute a \"view\" function from "XMonad.StackSet" on it.
treeselectWorkspace :: TSConfig WorkspaceId
-> Forest String -- ^ your tree of workspace-names
-> (WorkspaceId -> WindowSet -> WindowSet) -- ^ the \"view\" function.
-- Instances can be 'W.greedyView' for switching to a workspace
-- and/or 'W.shift' for moving the focused window to a selected workspace.
--
-- These actions can also be combined by doing
--
-- > \i -> W.greedyView i . W.shift i
-> X ()
treeselectWorkspace c xs f = do
-- get all defined workspaces
-- They have to be set with 'toWorkspaces'!
ws <- gets (W.workspaces . windowset)
-- check the 'XConfig.workspaces'
if all (`elem` map tag ws) (toWorkspaces xs)
then do
-- convert the 'Forest WorkspaceId' to 'Forest (TSNode WorkspaceId)'
wsf <- forMForest (mkPaths xs) $ \(n, i) -> maybe (return (TSNode n "Does not exist!" "")) (mkNode n) (find (\w -> i == tag w) ws)
-- get the current workspace path
me <- gets (W.tag . W.workspace . W.current . windowset)
hist <- workspaceHistory
treeselectAt c (fromJust $ followPath tsn_name (splitPath me) $ fromForest wsf) (map splitPath hist) >>= maybe (return ()) (windows . f)
else liftIO $ do
-- error!
let msg = unlines $ [ "Please add:"
, " workspaces = toWorkspaces myWorkspaces"
, "to your XMonad config!"
, ""
, "XConfig.workspaces: "
] ++ map tag ws
hPutStrLn stderr msg
xmessage msg
return ()
where
mkNode n w = do
-- find the focused window's name on this workspace
name <- maybe (return "") (fmap show . getName . W.focus) $ stack w
return $ TSNode n name (tag w)
-- | Convert the workspace-tree to a flat list of paths such that XMonad can use them
--
-- The Nodes will be separated by a dot (\'.\') character
toWorkspaces :: Forest String -> [WorkspaceId]
toWorkspaces = map snd . concatMap flatten . mkPaths
mkPaths :: Forest String -> Forest (String, WorkspaceId)
mkPaths = map (\(Node n ns) -> Node (n, n) (map (f n) ns))
where
f pth (Node x xs) = let pth' = pth ++ '.' : x
in Node (x, pth') (map (f pth') xs)
splitPath :: WorkspaceId -> [String]
splitPath i = case break (== '.') i of
(x, []) -> [x]
(x, _:xs) -> x : splitPath xs
-- | Select from a Tree of 'X' actions
--
-- <<https://wiki.haskell.org/wikiupload/thumb/9/9b/Treeselect-Action.png/800px-Treeselect-Action.png>>
--
-- Each of these actions have to be specified inside a 'TSNode'
--
-- Example
--
-- > treeselectAction myTreeConf
-- > [ Node (TSNode "Hello" "displays hello" (spawn "xmessage hello!")) []
-- > , Node (TSNode "Shutdown" "Poweroff the system" (spawn "shutdown")) []
-- > , Node (TSNode "Brightness" "Sets screen brightness using xbacklight" (return ()))
-- > [ Node (TSNode "Bright" "FULL POWER!!" (spawn "xbacklight -set 100")) []
-- > , Node (TSNode "Normal" "Normal Brightness (50%)" (spawn "xbacklight -set 50")) []
-- > , Node (TSNode "Dim" "Quite dark" (spawn "xbacklight -set 10")) []
-- > ]
-- > ]
treeselectAction :: TSConfig (X a) -> Forest (TSNode (X a)) -> X ()
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]
forMForest x g = mapM (mapMTree g) x
mapMTree :: (Functor m, Applicative m, Monad m) => (a -> m b) -> Tree a -> m (Tree b)
mapMTree f (Node x xs) = Node <$> f x <*> mapM (mapMTree f) xs
-- | Quit returning the currently selected node
select :: TreeSelect a (Maybe a)
select = gets (Just . (tsn_value . cursor . tss_tree))
-- | Quit without returning anything
cancel :: TreeSelect a (Maybe a)
cancel = return Nothing
-- TODO: redraw only what is necessary.
-- Examples: redrawAboveCursor, redrawBelowCursor and redrawCursor
-- | Move the cursor to its parent node
moveParent :: TreeSelect a (Maybe a)
moveParent = moveWith parent >> redraw >> navigate
-- | Move the cursor one level down, highlighting its first child-node
moveChild :: TreeSelect a (Maybe a)
moveChild = moveWith children >> redraw >> navigate
-- | Move the cursor to the next child-node
moveNext :: TreeSelect a (Maybe a)
moveNext = moveWith nextChild >> redraw >> navigate
-- | Move the cursor to the previous child-node
movePrev :: TreeSelect a (Maybe a)
movePrev = moveWith previousChild >> redraw >> navigate
-- | Move backwards in history
moveHistBack :: TreeSelect a (Maybe a)
moveHistBack = do
s <- get
case tss_history s of
(xs, a:y:ys) -> do
put s{tss_history = (a:xs, y:ys)}
moveTo y
_ -> navigate
-- | Move forward in history
moveHistForward :: TreeSelect a (Maybe a)
moveHistForward = do
s <- get
case tss_history s of
(x:xs, ys) -> do
put s{tss_history = (xs, x:ys)}
moveTo x
_ -> navigate
-- | Move to a specific node
moveTo :: [String] -- ^ path, always starting from the top
-> TreeSelect a (Maybe a)
moveTo i = moveWith (followPath tsn_name i . rootNode) >> redraw >> navigate
-- | Apply a transformation on the internal 'XMonad.Util.TreeZipper.TreeZipper'.
moveWith :: (TreeZipper (TSNode a) -> Maybe (TreeZipper (TSNode a))) -> TreeSelect a ()
moveWith f = do
s <- get
case f (tss_tree s) of
-- TODO: redraw cursor only?
Just t -> put s{ tss_tree = t }
Nothing -> return ()
-- | 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 .|. buttonPressMask) e
ev <- getEvent e
if | ev_event_type ev == keyPress -> 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
| 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 ()
redraw = do
win <- gets tss_window
dpy <- gets tss_display
-- clear window
-- TODO: not always needed!
liftIO $ clearWindow dpy win
t <- gets tss_tree
_ <- drawLayers 0 0 (reverse $ (tz_before t, cursor t, tz_after t) : tz_parents t)
return ()
drawLayers :: Int -- ^ indentation level
-> Int -- ^ height
-> [(Forest (TSNode a), TSNode a, Forest (TSNode a))] -- ^ node layers (from top to bottom!)
-> TreeSelect a Int
drawLayers _ yl [] = return yl
drawLayers xl yl ((bs, c, as):xs) = do
TSConfig{..} <- ask
let nodeColor y = if odd y then ts_node else ts_nodealt
-- draw nodes above
forM_ (zip [yl ..] (reverse bs)) $ \(y, Node n _) ->
drawNode xl y n (nodeColor y)
-- drawLayers (xl + 1) (y + 1) ns
-- TODO: draw rest? if not ts_hidechildren
-- drawLayers (xl + 1) (y + 1) ns
-- draw the current / parent node
-- if this is the last (currently focused) we use the 'ts_highlight' color
let current_level = yl + length bs
drawNode xl current_level c $
if null xs then ts_highlight
else nodeColor current_level
l2 <- drawLayers (xl + 1) (current_level + 1) xs
-- draw nodes below
forM_ (zip [l2 ..] as) $ \(y, Node n _) ->
drawNode xl y n (nodeColor y)
-- TODO: draw rest? if not ts_hidechildren
-- drawLayers (xl + 1) (y + 1) ns
return (l2 + length as)
-- | Draw a node at a given indentation and height level
drawNode :: Int -- ^ indentation level (not in pixels)
-> Int -- ^ height level (not in pixels)
-> TSNode a -- ^ node to draw
-> (Pixel, Pixel) -- ^ node foreground (font) and background color
-> TreeSelect a ()
drawNode ix iy TSNode{..} col = do
TSConfig{..} <- ask
window <- gets tss_window
display <- gets tss_display
font <- gets tss_xfont
gc <- gets tss_gc
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 + ts_originX) (iy * ts_node_height + ts_originY)
ts_node_width ts_node_height
-- TODO: draw extra text (transparent background? or ts_background)
-- drawWinBox window fnt col2 nodeH (scW-x) (mes) (x+nodeW) y 8
-- | Draw a simple box with text
drawWinBox :: Window -> Display -> Visual -> Colormap -> GC -> XMonadFont -> (Pixel, Pixel) -> String -> Pixel -> String -> Int -> Int -> Int -> Int -> IO ()
drawWinBox win display visual colormap gc font (fg, bg) text fg2 text2 x y w h = do
-- draw box
setForeground display gc bg
fillRectangle display win gc (fromIntegral x) (fromIntegral y) (fromIntegral w) (fromIntegral h)
-- dreaw text
drawStringXMF display win visual colormap gc font fg
(fromIntegral $ x + 8)
(fromIntegral $ y + h - 8)
text
-- dreaw extra text
drawStringXMF display win visual colormap gc font fg2
(fromIntegral $ x + w + 8)
(fromIntegral $ y + h - 8)
text2
-- | Modified version of 'XMonad.Util.Font.printStringXMF' that uses 'Pixel' as color format
drawStringXMF :: Display -> Drawable -> Visual -> Colormap -> GC
-> XMonadFont -- ^ XMF Font
-> Pixel -- ^ font color
-> Position -- ^ x-position
-> Position -- ^ y-position
-> String -- ^ string text
-> IO ()
drawStringXMF display window visual colormap gc font col x y text = case font of
Core fnt -> do
setForeground display gc col
setFont display gc $ fontFromFontStruct fnt
drawImageString display window gc x y text
Utf8 fnt -> do
setForeground display gc col
wcDrawImageString display window fnt gc x y text
#ifdef XFT
Xft fnt -> 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
-- | Convert 'Pixel' to 'XRenderColor'
--
-- Note that it uses short to represent its components
fromARGB :: Pixel -> XRenderColor
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

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,20 +17,20 @@ 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@:
--
-- > import XMonad.Actions.UpdateFocus
-- > xmonad $ defaultConfig {
-- > xmonad $ def {
-- > ..
-- > startupHook = adjustEventInput
-- > handleEventHook = focusOnMouseMove
@@ -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
@@ -57,4 +58,26 @@ adjustEventInput = withDisplay $ \dpy -> do
rootw <- asks theRoot
io $ selectInput dpy rootw $ substructureRedirectMask .|. substructureNotifyMask
.|. enterWindowMask .|. leaveWindowMask .|. structureNotifyMask
.|. buttonPressMask .|. pointerMotionMask
.|. 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

@@ -1,7 +1,9 @@
{-# LANGUAGE ScopedTypeVariables #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonadContrib.UpdatePointer
-- Copyright : (c) Robert Marlow <robreim@bobturf.org>
-- 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)
--
-- Maintainer : Robert Marlow <robreim@bobturf.org>
@@ -19,15 +21,15 @@ module XMonad.Actions.UpdatePointer
-- * Usage
-- $usage
updatePointer
, PointerPosition (..)
)
where
import XMonad
import XMonad.Util.XUtils (fi)
import Control.Monad
import XMonad.Prelude
import XMonad.StackSet (member, peek, screenDetail, current)
import Data.Maybe
import Control.Exception (SomeException, try)
import Control.Arrow ((&&&), (***))
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
@@ -35,71 +37,80 @@ import Data.Maybe
-- > import XMonad
-- > import XMonad.Actions.UpdatePointer
--
-- Enable it by including it in your logHook definition. Eg:
-- Enable it by including it in your logHook definition, e.g.:
--
-- > logHook = updatePointer Nearest
-- > logHook = updatePointer (0.5, 0.5) (1, 1)
--
-- which will move the pointer to the nearest point of a newly focused window, or
-- which will move the pointer to the nearest point of a newly focused
-- window. The first argument establishes a reference point within the
-- newly-focused window, while the second argument linearly interpolates
-- between said reference point and the edges of the newly-focused window to
-- obtain a bounding box for the pointer.
--
-- > logHook = updatePointer (Relative 0.5 0.5)
--
-- which will move the pointer to the center of a newly focused window.
-- > logHook = updatePointer (0.5, 0.5) (0, 0) -- exact centre of window
-- > logHook = updatePointer (0.25, 0.25) (0.25, 0.25) -- near the top-left
-- > logHook = updatePointer (0.5, 0.5) (1.1, 1.1) -- within 110% of the edge
--
-- To use this with an existing logHook, use >> :
--
-- > logHook = dynamicLog
-- > >> updatePointer (Relative 1 1)
-- > >> updatePointer (1, 1) (0, 0)
--
-- which moves the pointer to the bottom-right corner of the focused window.
data PointerPosition = Nearest | Relative Rational Rational | TowardsCentre Rational Rational
deriving (Read,Show)
-- | 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
updatePointer :: PointerPosition -> X ()
updatePointer p = do
--
-- 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
dpy <- asks display
let defaultRect = screenRect $ screenDetail $ current ws
rect <- case peek ws of
Nothing -> return $ (screenRect . screenDetail .current) ws
Just w -> windowAttributesToRectangle `fmap` io (getWindowAttributes dpy w)
Nothing -> return defaultRect
Just w -> do tryAttributes <- io $ try $ getWindowAttributes dpy w
return $ case tryAttributes of
Left (_ :: SomeException) -> defaultRect
Right attributes -> windowAttributesToRectangle attributes
root <- asks theRoot
mouseIsMoving <- asks mouseFocused
(_sameRoot,_,currentWindow,rootx,rooty,_,_,_) <- io $ queryPointer dpy root
(_sameRoot,_,currentWindow,rootX,rootY,_,_,_) <- io $ queryPointer dpy root
drag <- gets dragging
unless (pointWithin (fi rootx) (fi rooty) rect
unless (pointWithin (fi rootX) (fi rootY) rect
|| mouseIsMoving
|| isJust drag
|| not (currentWindow `member` ws || currentWindow == none)) $
case p of
Nearest -> do
let x = moveWithin (fi rootx) (rect_x rect) (fi (rect_x rect) + fi (rect_width rect))
y = moveWithin (fi rooty) (rect_y rect) (fi (rect_y rect) + fi (rect_height rect))
io $ warpPointer dpy none root 0 0 0 0 x y
TowardsCentre xfrc yfrc -> do
let cx = fi (rect_width rect) / 2 + fi (rect_x rect)
cy = fi (rect_height rect) / 2 + fi (rect_y rect)
x,y,cx,cy :: Rational
x = moveWithin (fi rootx) (fi $ rect_x rect) (fi (rect_x rect) + fi (rect_width rect))
y = moveWithin (fi rooty) (fi $ rect_y rect) (fi (rect_y rect) + fi (rect_height rect))
io $ warpPointer dpy none root 0 0 0 0 (round $ x + xfrc*(cx-x)) (round $ y + yfrc*(cy-y))
Relative h v ->
io $ warpPointer dpy none root 0 0 0 0
(rect_x rect + fraction h (rect_width rect))
(rect_y rect + fraction v (rect_height rect))
where fraction x y = floor (x * fromIntegral y)
|| not (currentWindow `member` ws || currentWindow == none)) $ let
-- focused rectangle
(rectX, rectY) = (rect_x &&& rect_y) rect
(rectW, rectH) = (fi . rect_width &&& fi . rect_height) rect
-- reference position, with (0,0) and (1,1) being top-left and bottom-right
refX = lerp (fst refPos) rectX (rectX + rectW)
refY = lerp (snd refPos) rectY (rectY + rectH)
-- final pointer bounds, lerped *outwards* from reference position
boundsX = join (***) (lerp (fst ratio) refX) (rectX, rectX + rectW)
boundsY = join (***) (lerp (snd ratio) refY) (rectY, rectY + rectH)
-- ideally we ought to move the pointer in a straight line towards the
-- reference point until it is within the above bounds, but…
in io $ warpPointer dpy none root 0 0 0 0
(round . clip boundsX $ fi rootX)
(round . clip boundsY $ fi rootY)
windowAttributesToRectangle :: WindowAttributes -> Rectangle
windowAttributesToRectangle wa = Rectangle (fi (wa_x wa))
(fi (wa_y wa))
(fi (wa_width wa + 2 * wa_border_width wa))
(fi (wa_height wa + 2 * wa_border_width wa))
moveWithin :: Ord a => a -> a -> a -> a
moveWithin now lower upper =
if now < lower
then lower
else if now > upper
then upper
else now
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
| 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,7 +23,7 @@ module XMonad.Actions.Warp (
warpToWindow
) where
import Data.List
import XMonad.Prelude
import XMonad
import XMonad.StackSet as W
@@ -101,7 +102,7 @@ warpToWindow h v =
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

@@ -1,6 +1,8 @@
{-# LANGUAGE TupleSections #-}
-----------------------------------------------------------------------------
-- |
-- 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)
--
@@ -17,20 +19,20 @@
module XMonad.Actions.WindowBringer (
-- * Usage
-- $usage
gotoMenu, gotoMenu', gotoMenuArgs, gotoMenuArgs',
bringMenu, bringMenu', bringMenuArgs, bringMenuArgs',
windowMap,
bringWindow
WindowBringerConfig(..),
gotoMenu, gotoMenuConfig, gotoMenu', gotoMenuArgs, gotoMenuArgs',
bringMenu, bringMenuConfig, bringMenu', bringMenuArgs, bringMenuArgs',
windowMap, windowAppMap, windowMap', bringWindow, actionMenu
) where
import Data.Char (toLower)
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)
-- $usage
--
@@ -46,54 +48,76 @@ import XMonad.Util.NamedWindows (getName)
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
-- | Default menu command
defaultCmd :: String
defaultCmd = "dmenu"
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
-- taken to the corresponding workspace.
gotoMenu :: X ()
gotoMenu = gotoMenuArgs []
gotoMenu = gotoMenuConfig def
-- | Pops open a dmenu with window titles. Choose one, and you will be
-- taken to the corresponding workspace. This version accepts a configuration
-- object.
gotoMenuConfig :: WindowBringerConfig -> X ()
gotoMenuConfig wbConfig = actionMenu wbConfig W.focusWindow
-- | Pops open a dmenu with window titles. Choose one, and you will be
-- taken to the corresponding workspace. This version takes a list of
-- arguments to pass to dmenu.
gotoMenuArgs :: [String] -> X ()
gotoMenuArgs menuArgs = gotoMenuArgs' defaultCmd menuArgs
gotoMenuArgs args = gotoMenuConfig def { menuArgs = args }
-- | Pops open an application with window titles given over stdin. Choose one,
-- and you will be taken to the corresponding workspace.
gotoMenu' :: String -> X ()
gotoMenu' menuCmd = gotoMenuArgs' menuCmd []
gotoMenu' cmd = gotoMenuConfig def { menuArgs = [], menuCommand = cmd }
-- | Pops open an application with window titles given over stdin. Choose one,
-- and you will be taken to the corresponding workspace. This version takes a
-- list of arguments to pass to dmenu.
gotoMenuArgs' :: String -> [String] -> X ()
gotoMenuArgs' menuCmd menuArgs = actionMenu menuCmd menuArgs W.focusWindow
gotoMenuArgs' cmd args = gotoMenuConfig def { menuCommand = cmd, menuArgs = args }
-- | Pops open a dmenu with window titles. Choose one, and it will be
-- dragged, kicking and screaming, into your current workspace.
bringMenu :: X ()
bringMenu = bringMenuArgs []
bringMenu = bringMenuArgs def
-- | Pops open a dmenu with window titles. Choose one, and it will be
-- dragged, kicking and screaming, into your current workspace. This version
-- accepts a configuration object.
bringMenuConfig :: WindowBringerConfig -> X ()
bringMenuConfig wbConfig = actionMenu wbConfig bringWindow
-- | Pops open a dmenu with window titles. Choose one, and it will be
-- dragged, kicking and screaming, into your current workspace. This version
-- takes a list of arguments to pass to dmenu.
bringMenuArgs :: [String] -> X ()
bringMenuArgs menuArgs = bringMenuArgs' defaultCmd menuArgs
bringMenuArgs args = bringMenuConfig def { menuArgs = args }
-- | Pops open an application with window titles given over stdin. Choose one,
-- and it will be dragged, kicking and screaming, into your current
-- workspace.
bringMenu' :: String -> X ()
bringMenu' menuCmd = bringMenuArgs' menuCmd []
bringMenu' cmd = bringMenuConfig def { menuArgs = [], menuCommand = cmd }
-- | Pops open an application with window titles given over stdin. Choose one,
-- and it will be dragged, kicking and screaming, into your current
-- workspace. This version allows arguments to the chooser to be specified.
bringMenuArgs' :: String -> [String] -> X ()
bringMenuArgs' menuCmd menuArgs = actionMenu menuCmd menuArgs bringWindow
bringMenuArgs' cmd args = bringMenuConfig def { menuArgs = args, menuCommand = cmd }
-- | Brings the specified window into the current workspace.
bringWindow :: Window -> X.WindowSet -> X.WindowSet
@@ -101,25 +125,43 @@ 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 :: String -> [String] -> (Window -> X.WindowSet -> X.WindowSet) -> X ()
actionMenu menuCmd menuArgs action = windowMap >>= menuMapFunction >>= flip X.whenJust (windows . action)
actionMenu :: WindowBringerConfig -> (Window -> X.WindowSet -> X.WindowSet) -> X ()
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 selectionMap = menuMapArgs menuCmd menuArgs selectionMap
menuMapFunction = menuMapArgs cmd args
-- | A map from window names to Windows.
windowMap :: X (M.Map String Window)
windowMap = do
ws <- gets X.windowset
M.fromList `fmap` concat `fmap` mapM keyValuePairs (W.workspaces ws)
where keyValuePairs ws = mapM (keyValuePair ws) $ W.integrate' (W.stack ws)
keyValuePair ws w = flip (,) w `fmap` decorateName ws w
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' :: 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.
-- Lowercased, for your convenience (since dmenu is case-sensitive).
-- Tagged with the workspace ID, to guarantee uniqueness, and to let the user
-- know where he's going.
decorateName :: X.WindowSpace -> Window -> X String
decorateName ws w = do
name <- fmap (map toLower . show) $ getName w
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 it's 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,6 @@
{- |
Module : XMonad.Actions.WindowGo
Description : Operations for raising (traveling to) windows.
License : Public domain
Maintainer : <gwern0@gmail.com>
@@ -21,6 +22,7 @@ module XMonad.Actions.WindowGo (
runOrRaiseNext,
raiseMaybe,
raiseNextMaybe,
raiseNextMaybeCustomFocus,
raiseBrowser,
raiseEditor,
@@ -35,15 +37,14 @@ module XMonad.Actions.WindowGo (
module XMonad.ManageHook
) where
import Control.Monad
import Data.Char (toLower)
import Data.Monoid
import XMonad (Query(), X(), ManageHook, withWindowSet, runQuery, liftIO, ask)
import qualified Data.List as L (nub,sortBy)
import XMonad.Prelude
import XMonad (Query(), X(), ManageHook, WindowSet, withWindowSet, runQuery, liftIO, ask)
import Graphics.X11 (Window)
import XMonad.ManageHook
import XMonad.Operations (windows)
import XMonad.Prompt.Shell (getBrowser, getEditor)
import qualified XMonad.StackSet as W (allWindows, peek, swapMaster, focusWindow)
import qualified XMonad.StackSet as W (peek, swapMaster, focusWindow, workspaces, StackSet, Workspace, integrate', tag, stack)
import XMonad.Util.Run (safeSpawnProg)
{- $usage
@@ -65,12 +66,20 @@ appropriate one, or cover your bases by using instead something like:
For detailed instructions on editing your key bindings, see
"XMonad.Doc.Extending#Editing_key_bindings". -}
-- | Get the list of workspaces sorted by their tag
workspacesSorted :: Ord i => W.StackSet i l a s sd -> [W.Workspace i l a]
workspacesSorted s = L.sortBy (\u t -> W.tag u `compare` W.tag t) $ W.workspaces s
-- | Get a list of all windows in the 'StackSet' with an absolute ordering of workspaces
allWindowsSorted :: Ord i => Eq a => W.StackSet i l a s sd -> [a]
allWindowsSorted = L.nub . concatMap (W.integrate' . W.stack) . workspacesSorted
-- | If windows that satisfy the query exist, apply the supplied
-- function to them, otherwise run the action given as
-- second parameter.
ifWindows :: Query Bool -> ([Window] -> X ()) -> X () -> X ()
ifWindows qry f el = withWindowSet $ \wins -> do
matches <- filterM (runQuery qry) $ W.allWindows wins
matches <- filterM (runQuery qry) $ allWindowsSorted wins
case matches of
[] -> el
ws -> f ws
@@ -137,16 +146,21 @@ raiseNext = raiseNextMaybe $ return ()
'raiseNextMaybe' is an alternative version that allows cycling
through the matching windows. If the focused window matches the
query the next matching window is raised. If no matches are found
the function f is executed.
-}
the function f is executed. -}
raiseNextMaybe :: X () -> Query Bool -> X ()
raiseNextMaybe f qry = flip (ifWindows qry) f $ \ws -> do
raiseNextMaybe = raiseNextMaybeCustomFocus W.focusWindow
{- | See 'raiseMaybe' and 'raiseNextMaybe'.
In addition to all of the options offered by 'raiseNextMaybe'
'raiseNextMaybeCustomFocus' allows the user to supply the function that
should be used to shift the focus to any window that is found. -}
raiseNextMaybeCustomFocus :: (Window -> WindowSet -> WindowSet) -> X() -> Query Bool -> X()
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 $ W.focusWindow y
_ -> windows . W.focusWindow . head $ ws
in windows $ focusFn y
_ -> windows . focusFn . head $ ws
-- | 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.
@@ -167,7 +181,8 @@ raiseAndDo :: X () -> Query Bool -> (Window -> X ()) -> X ()
raiseAndDo f qry after = ifWindow qry (afterRaise `mappend` raiseHook) f
where afterRaise = ask >>= (>> idHook) . liftX . after
{- | If a window matching the second argument is found, the window is focused and the third argument is called;
{- | If a window matching the second argument is found, the window is focused and
the third argument is called;
otherwise, the first argument is called. -}
runOrRaiseAndDo :: String -> Query Bool -> (Window -> X ()) -> X ()
runOrRaiseAndDo = raiseAndDo . safeSpawnProg
@@ -182,7 +197,6 @@ raiseMaster raisef thatUserQuery = raiseAndDo raisef thatUserQuery (\_ -> window
{- | If the window is found the window is focused and set to master
otherwise, action is run.
> runOrRaiseMaster "firefox" (className =? "Firefox"))
-}
> runOrRaiseMaster "firefox" (className =? "Firefox")) -}
runOrRaiseMaster :: String -> Query Bool -> X ()
runOrRaiseMaster run query = runOrRaiseAndDo run query (\_ -> windows W.swapMaster)

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,8 +29,8 @@ 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
--
@@ -68,7 +69,7 @@ windowMenu = withFocused $ \w -> do
| tag <- tags ]
runSelectedAction gsConfig actions
getSize :: Window -> X (Rectangle)
getSize :: Window -> X Rectangle
getSize w = do
d <- asks display
wa <- io $ getWindowAttributes d w

View File

@@ -1,6 +1,7 @@
-----------------------------------------------------------------------------
-- |
-- 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>
@@ -40,17 +41,14 @@ module XMonad.Actions.WindowNavigation (
) where
import XMonad
import XMonad.Prelude (catMaybes, fromMaybe, listToMaybe, 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 qualified Data.Map as M
import Data.Maybe (catMaybes, fromMaybe, listToMaybe)
import Data.Ord (comparing)
import qualified Data.Set as S
-- $usage
@@ -62,9 +60,14 @@ import qualified Data.Set as S
--
-- > main = do
-- > config <- withWindowNavigation (xK_w, xK_a, xK_s, xK_d)
-- > $ defaultConfig { ... }
-- > $ 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.
@@ -125,9 +128,12 @@ swap = withTargetWindow swapWithFocused
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 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
@@ -137,11 +143,11 @@ withTargetWindow adj posRef dir = fromCurrentPoint posRef $ \win pos -> do
setPosition posRef pos targetRect
trackMovement :: IORef WNState -> X ()
trackMovement posRef = fromCurrentPoint posRef $ \win pos -> do
trackMovement posRef = fromCurrentPoint posRef $ \win pos ->
windowRect win >>= flip whenJust (setPosition posRef pos . snd)
fromCurrentPoint :: IORef WNState -> (Window -> Point -> X ()) -> X ()
fromCurrentPoint posRef f = withFocused $ \win -> do
fromCurrentPoint posRef f = withFocused $ \win ->
currentPosition posRef >>= f win
-- Gets the current position from the IORef passed in, or if nothing (say, from
@@ -193,7 +199,7 @@ windowRects = fmap catMaybes . mapM windowRect . S.toList =<< gets mapped
windowRect :: Window -> X (Maybe (Window, Rectangle))
windowRect 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 (win, Rectangle x y (w + 2 * bw) (h + 2 * bw))
`catchX` return Nothing
-- Modified from droundy's implementation of WindowNavigation:
@@ -209,7 +215,7 @@ inr L (Point px py) (Rectangle rx ry w h) = px > rx + fromIntegral w
py >= ry && py < ry + fromIntegral h
sortby :: Direction2D -> [(a,Rectangle)] -> [(a,Rectangle)]
sortby D = sortBy $ comparing (rect_y . snd)
sortby R = sortBy $ comparing (rect_x . snd)
sortby D = sortOn (rect_y . snd)
sortby R = sortOn (rect_x . snd)
sortby U = reverse . sortby D
sortby L = reverse . sortby R

View File

@@ -1,21 +1,23 @@
-----------------------------------------------------------------------------
-- |
-- 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
@@ -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,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Actions.Workscreen
-- Description: Display a set of workspaces on several screens.
-- Copyright : (c) 2012 kedals0
-- License : BSD3-style (see LICENSE)
--
@@ -20,7 +21,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
@@ -31,6 +31,7 @@ module XMonad.Actions.Workscreen (
,shiftToWorkscreen
,fromWorkspace
,expandWorkspace
,WorkscreenId
) where
import XMonad hiding (workspaces)
@@ -57,23 +58,23 @@ import XMonad.Actions.OnScreen
-- "XMonad.Doc.Extending#Editing_key_bindings".
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)

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 (find, fromJust, guard, liftA2, toList, when, (<=<))
-- $usage
--
@@ -61,16 +58,13 @@ 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 defaultConfig
-- > { layoutHook = workspaceCursors myCursors $ layoutHook defaultConfig
-- > conf = additionalKeysP def
-- > { layoutHook = workspaceCursors myCursors $ layoutHook def
-- > , workspaces = toList myCursors } $
-- > [("M-"++shift++control++[k], f direction depth)
-- > | (f,shift) <- zip [modifyLayer,shiftModifyLayer] ["","S-"]
@@ -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
@@ -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

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,23 +9,23 @@
-- 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,
getCurrentWorkspaceName,
setWorkspaceName,
setCurrentWorkspaceName,
@@ -32,21 +33,29 @@ module XMonad.Actions.WorkspaceNames (
swapTo,
swapTo',
swapWithCurrent,
-- * Workspace prompt
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.Hooks.StatusBar.PP (PP(..))
import XMonad.Hooks.EwmhDesktops (addEwmhWorkspaceRename)
import XMonad.Prompt (mkXPrompt, XPConfig)
import XMonad.Prompt.Workspace (Wor(Wor))
import XMonad.Util.WorkspaceCompare (getSortByIndex)
import qualified Data.Map as M
import Data.Maybe (fromMaybe)
-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@ file:
@@ -55,12 +64,19 @@ import Data.Maybe (fromMaybe)
--
-- Then add keybindings like the following:
--
-- > , ((modm .|. shiftMask, xK_r ), renameWorkspace defaultXPConfig)
-- > , ((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:
@@ -78,20 +94,32 @@ import Data.Maybe (fromMaybe)
-- | 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
extensionType = PersistentExtension
-- | 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
-- | Returns a lookup function that maps workspace tags to workspace names.
getWorkspaceNames' :: X (WorkspaceId -> Maybe String)
getWorkspaceNames' = do
WorkspaceNames m <- XS.get
return $ \wks -> case M.lookup wks m of
Nothing -> wks
Just s -> wks ++ ":" ++ s
return (`M.lookup` m)
-- | 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) <$> getWorkspaceNames'
-- | Gets the name of the current workspace. See 'getWorkspaceName'
getCurrentWorkspaceName :: X (Maybe String)
getCurrentWorkspaceName = getWorkspaceName =<< gets (W.currentTag . windowset)
-- | Sets the name of a workspace. Empty string makes the workspace unnamed
-- again.
@@ -109,27 +137,13 @@ setCurrentWorkspaceName name = do
-- | Prompt for a new name for the current workspace and set it.
renameWorkspace :: XPConfig -> X ()
renameWorkspace conf = do
renameWorkspace conf =
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
}
-- | 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 ()
@@ -149,4 +163,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 -> (WorkspaceId -> X ()) -> X ()
workspaceNamePrompt conf job = do
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 = fromMaybe "" (lookup name pairs)
contains completions input =
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)
--
@@ -22,7 +23,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,13 +31,11 @@ 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
import XMonad.Layout.Tabbed
import XMonad.Layout.WindowArranger
import XMonad.Prompt
import XMonad.Prompt.Shell
import XMonad.Prompt.Ssh
import XMonad.Prompt.Theme
@@ -86,7 +85,7 @@ import XMonad.Util.Themes
arossatoConfig = do
xmobar <- spawnPipe "xmobar" -- REMOVE this line if you do not have xmobar installed!
return $ defaultConfig
return $ def
{ workspaces = ["home","var","dev","mail","web","doc"] ++
map show [7 .. 9 :: Int]
, logHook = myDynLog xmobar -- REMOVE this line if you do not have xmobar installed!
@@ -120,7 +119,7 @@ arossatoConfig = do
newManageHook = myManageHook
-- xmobar
myDynLog h = dynamicLogWithPP defaultPP
myDynLog h = dynamicLogWithPP def
{ ppCurrent = xmobarColor "yellow" "" . wrap "[" "]"
, ppTitle = xmobarColor "green" "" . shorten 40
, ppVisible = wrap "(" ")"
@@ -128,7 +127,7 @@ arossatoConfig = do
}
-- key bindings stuff
defKeys = keys defaultConfig
defKeys = keys def
delKeys x = foldr M.delete (defKeys x) (toRemove x)
newKeys x = foldr (uncurry M.insert) (delKeys x) (toAdd x)
-- remove some of the default key bindings
@@ -144,12 +143,12 @@ arossatoConfig = do
[(shiftMask .|. modMask x, k) | k <- [xK_1 .. xK_9]]
-- These are my personal key bindings
toAdd x =
[ ((modMask x , xK_F12 ), xmonadPrompt defaultXPConfig )
, ((modMask x , xK_F3 ), shellPrompt defaultXPConfig )
, ((modMask x , xK_F4 ), sshPrompt defaultXPConfig )
, ((modMask x , xK_F5 ), themePrompt defaultXPConfig )
, ((modMask x , xK_F6 ), windowPromptGoto defaultXPConfig )
, ((modMask x , xK_F7 ), windowPromptBring defaultXPConfig )
[ ((modMask x , xK_F12 ), xmonadPrompt def )
, ((modMask x , xK_F3 ), shellPrompt def )
, ((modMask x , xK_F4 ), sshPrompt def )
, ((modMask x , xK_F5 ), themePrompt 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
@@ -36,13 +37,25 @@ 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 `M.union` keys someConfig c }
-- > main = xmonad someConfig { keys = \c -> azertyKeys c <+> keys someConfig c }
azertyConfig = defaultConfig { keys = azertyKeys <+> keys defaultConfig }
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
-- mod-shift-{z,e,r} %! Move client to screen 1, 2, or 3
[((m .|. modm, key), screenWorkspace sc >>= flip whenJust (windows . f))
| (key, sc) <- zip [xK_z, xK_e, xK_r] [0..],
(f, m) <- [(W.view, 0), (W.shift, shiftMask)]]

47
XMonad/Config/Bepo.hs Normal file
View File

@@ -0,0 +1,47 @@
{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Config.Bepo
-- Description : Fix keybindings for the BEPO keyboard layout.
-- Copyright : (c) Yorick Laupa <yo.eight@gmail.com>
-- License : BSD
--
-- Maintainer : Yorick Laupa <yo.eight@gmail.com>
-- Stability : stable
-- Portability : unportable
--
-- This module fixes some of the keybindings for the francophone among you who
-- use a BEPO keyboard layout. Based on XMonad.Config.Azerty
module XMonad.Config.Bepo (
-- * Usage
-- $usage
bepoConfig, bepoKeys
) where
import XMonad
import qualified XMonad.StackSet as W
import qualified Data.Map as M
-- $usage
-- To use this module, start with the following @~\/.xmonad\/xmonad.hs@:
--
-- > import XMonad
-- > import XMonad.Config.Bepo
-- >
-- > main = xmonad bepoConfig
--
-- If you prefer, an bepoKeys function is provided which you can use as so:
--
-- > import qualified Data.Map as M
-- > main = xmonad someConfig { keys = \c -> bepoKeys c `M.union` keys someConfig c }
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)]]

View File

@@ -1,7 +1,9 @@
{-# LANGUAGE FlexibleContexts #-}
{-# OPTIONS -fno-warn-missing-signatures #-}
----------------------------------------------------------------------------
-- |
-- Module : XMonad.Config.Bluetile
-- Description : Default configuration of [Bluetile](http://projects.haskell.org/bluetile/).
-- Copyright : (c) Jan Vornberger 2009
-- License : BSD3-style (see LICENSE)
--
@@ -24,7 +26,7 @@ module XMonad.Config.Bluetile (
bluetileConfig
) where
import XMonad hiding ( (|||) )
import XMonad
import XMonad.Layout.BorderResize
import XMonad.Layout.BoringWindows
@@ -32,7 +34,6 @@ 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
@@ -43,6 +44,7 @@ import XMonad.Layout.WindowSwitcherDecoration
import XMonad.Actions.BluetileCommands
import XMonad.Actions.CycleWS
import XMonad.Actions.Minimize
import XMonad.Actions.WindowMenu
import XMonad.Hooks.CurrentWorkspaceOnTop
@@ -60,8 +62,7 @@ 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@:
@@ -80,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
@@ -111,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
@@ -142,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
@@ -158,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)
@@ -179,33 +180,30 @@ bluetileManageHook :: ManageHook
bluetileManageHook = composeAll
[ workspaceByPos, positionStoreManageHook (Just defaultThemeWithButtons)
, className =? "MPlayer" --> doFloat
, isFullscreen --> doFullFloat
, manageDocks]
, isFullscreen --> doFullFloat]
bluetileLayoutHook = avoidStruts $ minimize $ boringWindows $ (
bluetileLayoutHook = avoidStruts $ minimize $ boringWindows $
named "Floating" floating |||
named "Tiled1" tiled1 |||
named "Tiled2" tiled2 |||
named "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
bluetileConfig =
defaultConfig
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
--
@@ -22,7 +23,8 @@ module XMonad.Config.Desktop (
-- the DE via a subset of the Extended Window Manager Hints (EWMH)
-- specification. Extra xmonad settings unique to specific DE's are
-- added by overriding or modifying @desktopConfig@ fields in the
-- same way that @defaultConfig@ is customized in @~\/.xmonad/xmonad.hs@.
-- same way that the default configuration is customized in
-- @~\/.xmonad/xmonad.hs@.
--
-- For more information about EWMH see:
--
@@ -56,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
@@ -69,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 @defaultConfig@ in your @~\/.xmonad/xmonad.hs@,
-- and pagers, in place of @def@ in your @~\/.xmonad/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@.
@@ -88,7 +91,7 @@ import qualified Data.Map as M
-- $customizing
-- To customize a desktop config, modify its fields as is illustrated with
-- @defaultConfig@ in "XMonad.Doc.Extending#Extending xmonad".
-- the default configuration @def@ in "XMonad.Doc.Extending#Extending xmonad".
-- $layouts
-- See also "XMonad.Util.EZConfig" for more options for modifying key bindings.
@@ -163,14 +166,16 @@ import qualified Data.Map as M
-- > adjustEventInput
--
desktopConfig = ewmh defaultConfig
{ startupHook = setDefaultCursor xC_left_ptr
, layoutHook = desktopLayoutModifiers $ layoutHook defaultConfig
, manageHook = manageHook defaultConfig <+> manageDocks
, keys = desktopKeys <+> keys defaultConfig }
desktopConfig :: XConfig (ModifiedLayout AvoidStruts
(Choose Tall (Choose (Mirror Tall) Full)))
desktopConfig = docks $ ewmh def
{ startupHook = setDefaultCursor xC_left_ptr <+> startupHook def
, layoutHook = desktopLayoutModifiers $ layoutHook 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

324
XMonad/Config/Dmwit.hs Normal file
View File

@@ -0,0 +1,324 @@
-- boilerplate {{{
{-# LANGUAGE ExistentialQuantification, NoMonomorphismRestriction, TypeSynonymInstances #-}
{-# OPTIONS_GHC -fno-warn-missing-signatures -fno-warn-type-defaults #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Config.Dmwit
-- Description : Daniel Wagner's xmonad configuration.
--
------------------------------------------------------------------------
module XMonad.Config.Dmwit where
-- system imports
import Control.Monad.Trans
import Data.Map (Map, fromList)
import Data.Ratio
import Data.Word
import GHC.Real
import System.Environment
import System.Exit
import System.IO
import System.Process
-- xmonad core
import XMonad
import XMonad.StackSet hiding (workspaces)
-- xmonad contrib
import XMonad.Actions.SpawnOn
import XMonad.Actions.Warp
import XMonad.Hooks.DynamicLog
import XMonad.Hooks.ManageDocks
import XMonad.Hooks.ManageHelpers
import XMonad.Layout.Grid
import XMonad.Layout.IndependentScreens hiding (withScreen)
import XMonad.Layout.Magnifier
import XMonad.Layout.NoBorders
import XMonad.Prelude
import XMonad.Util.Dzen hiding (x, y)
import XMonad.Util.SpawnOnce
-- }}}
-- volume {{{
outputOf :: String -> IO String
outputOf s = do
uninstallSignalHandlers
(hIn, hOut, hErr, p) <- runInteractiveCommand s
mapM_ hClose [hIn, hErr]
hGetContents hOut <* waitForProcess p <* installSignalHandlers
geomMean :: Floating a => [a] -> a
geomMean xs = product xs ** (recip . fromIntegral . length $ xs)
arithMean :: Floating a => [a] -> a
arithMean xs = sum xs / fromIntegral (length xs)
namedNumbers n s = do
l <- lines s
guard (sentinel `isPrefixOf` l)
return (drop (length sentinel) l)
where sentinel = n ++ " #"
-- Data.List.Split.splitOn ":", but without involving an extra dependency
splitColon xs = case break (==':') xs of
(a, ':':b) -> a : splitColon b
(a, _) -> [a]
parse s = arithMean $ do
l <- lines s
guard ("\tVolume: " `isPrefixOf` l)
part <- splitColon l
(n,'%':_) <- reads part
return n
modVolume :: String -> Integer -> IO Double
modVolume kind n = do
is <- namedNumbers parseKind <$> outputOf listCommand
forM_ is (outputOf . setCommand)
parse <$> outputOf listCommand
where
sign | n > 0 = "+" | otherwise = "-"
ctlKind = map (\c -> if c == ' ' then '-' else c) kind
parseKind = unwords . map (\(c:cs) -> toUpper c : cs) . words $ kind
setCommand i = "pactl set-" ++ ctlKind ++ "-volume " ++ i ++ " -- " ++ sign ++ show (abs n) ++ "%"
listCommand = "pactl list " ++ ctlKind ++ "s"
-- }}}
-- convenient actions {{{
centerMouse = warpToWindow (1/2) (1/2)
statusBarMouse = warpToScreen 0 (5/1600) (5/1200)
withScreen s f = screenWorkspace s >>= flip whenJust (windows . f)
makeLauncher yargs run exec close = concat
["exe=`yeganesh ", yargs, "` && ", run, " ", exec, "$exe", close]
launcher = makeLauncher "" "eval" "\"exec " "\""
termLauncher = makeLauncher "-p withterm" "exec urxvt -e" "" ""
viewShift i = view i . shift i
floatAll = composeAll . map (\s -> className =? s --> doFloat)
sinkFocus = peek >>= maybe id sink
showMod k n = liftIO (modVolume k n) >>= volumeDzen . show . round
volumeDzen = dzenConfig $ onCurr (center 170 66) >=> font "-*-helvetica-*-r-*-*-64-*-*-*-*-*-*-*,-*-terminus-*-*-*-*-64-*-*-*-*-*-*-*"
-- }}}
altMask = mod1Mask
bright = "#80c0ff"
dark = "#13294e"
-- manage hooks for mplayer {{{
fullscreen43on169 = expand $ RationalRect 0 (-1/6) 1 (4/3) where
expand (RationalRect x y w h) = RationalRect (x - bwx) (y - bwy) (w + 2 * bwx) (h + 2 * bwy)
bwx = 2 / 1920 -- borderwidth
bwy = 2 / 1080
fullscreenMPlayer = className =? "MPlayer" --> do
dpy <- liftX $ asks display
win <- ask
hints <- liftIO $ getWMNormalHints dpy win
case fmap (approx . fst) (sh_aspect hints) of
Just ( 4 :% 3) -> viewFullOn 0 "5" win
Just (16 :% 9) -> viewFullOn 1 "5" win
_ -> doFloat
where
approx (n, d) = approxRational (fi n / fi d) (1/100)
operationOn f s n w = do
let ws = marshall s n
currws <- liftX $ screenWorkspace s
doF $ view ws . maybe id view currws . shiftWin ws w . f w
viewFullOn = operationOn sink
centerWineOn = operationOn (`XMonad.StackSet.float` RationalRect (79/960) (-1/540) (401/480) (271/270))
-- }}}
-- debugging {{{
class Show a => PPrint a where
pprint :: Int -> a -> String
pprint _ = show
data PPrintable = forall a. PPrint a => P a
instance Show PPrintable where show (P x) = show x
instance PPrint PPrintable where pprint n (P x) = pprint n x
record :: String -> Int -> [(String, PPrintable)] -> String
record s n xs = preamble ++ intercalate newline fields ++ postlude where
indentation = '\n' : replicate n '\t'
preamble = s ++ " {" ++ indentation
postlude = indentation ++ "}"
newline = ',' : indentation
fields = map (\(name, value) -> name ++ " = " ++ pprint (n+1) value) xs
instance PPrint a => PPrint (Maybe a) where
pprint n (Just x) = "Just (" ++ pprint n x ++ ")"
pprint _ x = show x
instance PPrint a => PPrint [a] where
pprint _ [] = "[]"
pprint n xs = preamble ++ intercalate newline allLines ++ postlude where
indentation = '\n' : replicate n '\t'
preamble = "[" ++ indentation
allLines = map (pprint (n+1)) xs
newline = ',' : indentation
postlude = indentation ++ "]"
instance PPrint Rectangle where
pprint n x = record "Rectangle" n [
("rect_x", P (rect_x x)),
("rect_y", P (rect_y x)),
("rect_width", P (rect_width x)),
("rect_height", P (rect_height x))
]
instance PPrint a => PPrint (Stack a) where
pprint n x = record "Stack" n [
("focus", P (XMonad.StackSet.focus x)),
("up", P (up x)),
("down", P (down x))
]
instance (PPrint i, PPrint l, PPrint a) => PPrint (Workspace i l a) where
pprint n x = record "Workspace" n [
("tag", P (tag x)),
("layout", P (layout x)),
("stack", P (stack x))
]
instance PPrint ScreenDetail where
pprint n x = record "SD" n [("screenRect", P (screenRect x))]
instance (PPrint i, PPrint l, PPrint a, PPrint sid, PPrint sd) => PPrint (XMonad.StackSet.Screen i l a sid sd) where
pprint n x = record "Screen" n [
("workspace", P (workspace x)),
("screen", P (screen x)),
("screenDetail", P (screenDetail x))
]
instance (PPrint i, PPrint l, PPrint a, PPrint sid, PPrint sd) => PPrint (StackSet i l a sid sd) where
pprint n x = record "StackSet" n [
("current", P (current x)),
("visible", P (visible x)),
("hidden", P (hidden x)),
("floating", P (floating x))
]
instance PPrint (Layout a)
instance PPrint Int
instance PPrint XMonad.Screen
instance PPrint Integer
instance PPrint Position
instance PPrint Dimension
instance PPrint Char
instance PPrint Word64
instance PPrint ScreenId
instance (Show a, Show b) => PPrint (Map a b)
-- }}}
-- main {{{
dmwitConfig nScreens = docks $ def {
borderWidth = 2,
workspaces = withScreens nScreens (map show [1..5]),
terminal = "urxvt",
normalBorderColor = dark,
focusedBorderColor = bright,
modMask = mod4Mask,
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,
logHook = allPPs nScreens,
startupHook = refresh
>> mapM_ (spawnOnce . xmobarCommand) [0 .. nScreens-1]
}
main = countScreens >>= xmonad . dmwitConfig
-- }}}
-- keybindings {{{
keyBindings conf = let m = modMask conf in fromList . anyMask $ [
((m , xK_BackSpace ), spawnHere "urxvt"),
((m , xK_p ), spawnHere launcher),
((m .|. shiftMask , xK_p ), spawnHere termLauncher),
((m .|. shiftMask , xK_c ), kill),
((m , xK_q ), restart "xmonad" True),
((m .|. shiftMask , xK_q ), io exitSuccess),
((m , xK_grave ), sendMessage NextLayout),
((m .|. shiftMask , xK_grave ), setLayout $ layoutHook conf),
((m , xK_o ), sendMessage Toggle),
((m , xK_x ), withFocused (windows . sink)),
((m , xK_Home ), windows focusUp),
((m .|. shiftMask , xK_Home ), windows swapUp),
((m , xK_End ), windows focusDown),
((m .|. shiftMask , xK_End ), windows swapDown),
((m , xK_a ), windows focusMaster),
((m .|. shiftMask , xK_a ), windows swapMaster),
((m , xK_Control_L ), withScreen 0 view),
((m .|. shiftMask , xK_Control_L ), withScreen 0 viewShift),
((m , xK_Alt_L ), withScreen 1 view),
((m .|. shiftMask , xK_Alt_L ), withScreen 1 viewShift),
((m , xK_u ), centerMouse),
((m .|. shiftMask , xK_u ), statusBarMouse),
((m , xK_s ), spawnHere "chromium --password-store=gnome"),
((m , xK_n ), spawnHere "gvim todo"),
((m , xK_t ), spawnHere "mpc toggle"),
((m , xK_h ), spawnHere "urxvt -e alsamixer"),
((m , xK_d ), spawnHere "wyvern"),
((m , xK_l ), spawnHere "urxvt -e sup"),
((m , xK_r ), spawnHere "urxvt -e ncmpcpp"),
((m , xK_c ), spawnHere "urxvt -e ghci"),
((m , xK_g ), spawnHere "slock" >> spawnHere "xscreensaver-command -lock"),
((m , xK_f ), spawnHere "gvim ~/.xmonad/xmonad.hs"),
(( noModMask , xK_F8 ), showMod "sink input" (-4)),
(( noModMask , xK_F9 ), showMod "sink input" 4 ),
(( shiftMask , xK_F8 ), showMod "sink" (-4)),
(( shiftMask , xK_F9 ), showMod "sink" 4 ),
(( noModMask , xK_Super_L ), return ()) -- make VirtualBox ignore stray hits of the Windows key
] ++ [
((m .|. e , key ), windows (onCurrentScreen f ws))
| (key, ws) <- zip [xK_1..xK_9] (workspaces' conf)
, (e, f) <- [(0, view), (shiftMask, viewShift)]
]
atSchool school home = do
host <- liftIO (getEnv "HOST")
return $ case host of
"sorghum" -> home
"buckwheat" -> home
_ -> school
anyMask xs = do
((mask, key), action) <- xs
extraMask <- [0, controlMask, altMask, controlMask .|. altMask]
return ((mask .|. extraMask, key), action)
-- }}}
-- logHook {{{
pipeName n s = "/home/dmwit/.xmonad/pipe-" ++ n ++ "-" ++ show s
xmobarCommand (S s) = unwords ["xmobar",
"-x", show s,
"-t", template s,
"-C", pipeReader
]
where
template 0 = "}%focus%{%workspaces%"
template _ = "%date%}%focus%{%workspaces%"
pipeReader = "'[\
\Run PipeReader \"" ++ pipeName "focus" s ++ "\" \"focus\",\
\Run PipeReader \"" ++ pipeName "workspaces" s ++ "\" \"workspaces\"\
\]'"
allPPs nScreens = sequence_ [dynamicLogWithPP (pp s) | s <- [0..nScreens-1], pp <- [ppFocus, ppWorkspaces]]
color c = xmobarColor c ""
ppFocus s@(S s_) = whenCurrentOn s def {
ppOrder = \(_:_:windowTitle:_) -> [windowTitle],
ppOutput = appendFile (pipeName "focus" s_) . (++ "\n")
}
ppWorkspaces s@(S s_) = marshallPP s def {
ppCurrent = color "white",
ppVisible = color "white",
ppHiddenNoWindows = color dark,
ppUrgent = color "red",
ppSep = "",
ppOrder = \(wss:_layout:_title:_) -> [wss],
ppOutput = appendFile (pipeName "workspaces" s_) . (++"\n")
}
-- }}}

View File

@@ -2,21 +2,22 @@
{-# 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 ( 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, defaultTheme,
import XMonad.Layout.Tabbed ( tabbed,
shrinkText, Shrinker, shrinkIt, CustomShrink(CustomShrink) )
import XMonad.Layout.Combo ( combineTwo )
import XMonad.Layout.Named ( named )
@@ -32,22 +33,22 @@ import XMonad.Layout.ToggleLayouts ( toggleLayouts, ToggleLayout(ToggleLayout) )
import XMonad.Layout.ShowWName ( showWName )
import XMonad.Layout.Magnifier ( maximizeVertical, MagnifyMsg(Toggle) )
import XMonad.Prompt ( defaultXPConfig, font, height, XPConfig )
import XMonad.Prompt ( font, height, XPConfig )
import XMonad.Prompt.Layout ( layoutPrompt )
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, manageDocks )
import XMonad.Hooks.ManageDocks ( avoidStruts, docks )
import XMonad.Hooks.EwmhDesktops ( ewmh )
myXPConfig :: XPConfig
myXPConfig = defaultXPConfig {font="-*-lucida-medium-r-*-*-14-*-*-*-*-*-*-*"
,height=22}
myXPConfig = def {font="-*-lucida-medium-r-*-*-14-*-*-*-*-*-*-*"
,height=22}
------------------------------------------------------------------------
@@ -77,11 +78,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)
@@ -117,7 +118,7 @@ keys x = M.fromList $
++
zip (zip (repeat (modMask x .|. shiftMask)) [xK_F1..xK_F12]) (map (withNthWorkspace copy) [0..])
config = ewmh defaultConfig
config = docks $ ewmh def
{ borderWidth = 1 -- Width of the window border in pixels.
, XMonad.workspaces = ["mutt","iceweasel"]
, layoutHook = showWName $ workspaceDir "~" $
@@ -129,7 +130,6 @@ config = ewmh defaultConfig
named "widescreen" ((mytab *||* mytab)
****//* combineTwo Square mytab mytab) -- |||
--mosaic 0.25 0.5
, manageHook = manageHook defaultConfig <+> manageDocks -- add panel-handling
, terminal = "xterm" -- The preferred terminal program.
, normalBorderColor = "#222222" -- Border color for unfocused windows.
, focusedBorderColor = "#00ff00" -- Border color for focused windows.
@@ -137,7 +137,7 @@ config = ewmh defaultConfig
, XMonad.keys = keys
}
mytab = tabbed CustomShrink defaultTheme
mytab = tabbed CustomShrink def
instance Shrinker CustomShrink where
shrinkIt shr s | Just s' <- dropFromHead " " s = shrinkIt shr s'

79
XMonad/Config/Example.hs Normal file
View File

@@ -0,0 +1,79 @@
--------------------------------------------------------------------------------
-- | Example.hs
--
-- Example configuration file for xmonad using the latest recommended
-- features (e.g., 'desktopConfig').
module Main (main) where
--------------------------------------------------------------------------------
import System.Exit
import XMonad
import XMonad.Config.Desktop
import XMonad.Hooks.DynamicLog
import XMonad.Hooks.ManageHelpers
import XMonad.Layout.BinarySpacePartition (emptyBSP)
import XMonad.Layout.NoBorders (noBorders)
import XMonad.Layout.ResizableTile (ResizableTall(..))
import XMonad.Layout.ToggleLayouts (ToggleLayout(..), toggleLayouts)
import XMonad.Prompt
import XMonad.Prompt.ConfirmPrompt
import XMonad.Prompt.Shell
import XMonad.Util.EZConfig
--------------------------------------------------------------------------------
main = do
spawn "xmobar" -- Start a task bar such as xmobar.
-- Start xmonad using the main desktop configuration with a few
-- simple overrides:
xmonad $ desktopConfig
{ modMask = mod4Mask -- Use the "Win" key for the mod key
, manageHook = myManageHook <+> manageHook desktopConfig
, layoutHook = desktopLayoutModifiers myLayouts
, logHook = (dynamicLogString def >>= xmonadPropLog)
<+> logHook desktopConfig
}
`additionalKeysP` -- Add some extra key bindings:
[ ("M-S-q", confirmPrompt myXPConfig "exit" (io exitSuccess))
, ("M-p", shellPrompt myXPConfig)
, ("M-<Esc>", sendMessage (Toggle "Full"))
]
--------------------------------------------------------------------------------
-- | Customize layouts.
--
-- This layout configuration uses two primary layouts, 'ResizableTall'
-- and 'BinarySpacePartition'. You can also use the 'M-<Esc>' key
-- binding defined above to toggle between the current layout and a
-- full screen layout.
myLayouts = toggleLayouts (noBorders Full) others
where
others = ResizableTall 1 (1.5/100) (3/5) [] ||| emptyBSP
--------------------------------------------------------------------------------
-- | Customize the way 'XMonad.Prompt' looks and behaves. It's a
-- great replacement for dzen.
myXPConfig = def
{ position = Top
, alwaysHighlight = True
, promptBorderWidth = 0
, font = "xft:monospace:size=9"
}
--------------------------------------------------------------------------------
-- | Manipulate windows as they are created. The list given to
-- @composeOne@ is processed from top to bottom. The first matching
-- rule wins.
--
-- Use the `xprop' tool to get the info you need for these matches.
-- For className, use the second value that xprop gives you.
myManageHook = composeOne
-- Handle floating windows:
[ transience -- move transient windows to their parent
, isDialog -?> doCenterFloat
] <+> composeAll
[ className =? "Pidgin" --> doFloat
, className =? "XCalc" --> doFloat
, className =? "mpv" --> doFloat
]

View File

@@ -3,6 +3,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Config.Gnome
-- Description : Config for integrating xmonad with GNOME.
-- Copyright : (c) Spencer Janssen <spencerjanssen@gmail.com>
-- License : BSD
--
@@ -18,7 +19,8 @@ module XMonad.Config.Gnome (
-- $usage
gnomeConfig,
gnomeRun,
gnomeRegister
gnomeRegister,
desktopLayoutModifiers
) where
import XMonad
@@ -44,9 +46,9 @@ gnomeConfig = desktopConfig
, keys = gnomeKeys <+> keys desktopConfig
, startupHook = gnomeRegister >> startupHook desktopConfig }
gnomeKeys (XConfig {modMask = modm}) = M.fromList $
gnomeKeys XConfig{modMask = modm} = M.fromList
[ ((modm, xK_p), gnomeRun)
, ((modm .|. shiftMask, xK_q), spawn "gnome-session-save --kill") ]
, ((modm .|. shiftMask, xK_q), spawn "gnome-session-quit --logout") ]
-- | Launch the "Run Application" dialog. gnome-panel must be running for this
-- to work.
@@ -71,10 +73,10 @@ gnomeRun = withDisplay $ \dpy -> do
-- > gconftool-2 -s /desktop/gnome/session/required_components/windowmanager xmonad --type string
gnomeRegister :: MonadIO m => m ()
gnomeRegister = io $ do
x <- lookup "DESKTOP_AUTOSTART_ID" `fmap` getEnvironment
x <- lookup "DESKTOP_AUTOSTART_ID" <$> getEnvironment
whenJust x $ \sessionId -> safeSpawn "dbus-send"
["--session"
,"--print-reply=string"
,"--print-reply=literal"
,"--dest=org.gnome.SessionManager"
,"/org/gnome/SessionManager"
,"org.gnome.SessionManager.RegisterClient"

View File

@@ -3,6 +3,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Config.Kde
-- Description : Config for integrating xmonad with KDE.
-- Copyright : (c) Spencer Janssen <spencerjanssen@gmail.com>
-- License : BSD
--
@@ -17,7 +18,8 @@ module XMonad.Config.Kde (
-- * Usage
-- $usage
kdeConfig,
kde4Config
kde4Config,
desktopLayoutModifiers
) where
import XMonad
@@ -46,12 +48,12 @@ kde4Config = desktopConfig
{ terminal = "konsole"
, keys = kde4Keys <+> keys desktopConfig }
kdeKeys (XConfig {modMask = modm}) = M.fromList $
kdeKeys XConfig{modMask = modm} = M.fromList
[ ((modm, xK_p), spawn "dcop kdesktop default popupExecuteCommand")
, ((modm .|. shiftMask, xK_q), spawn "dcop kdesktop default logout")
]
kde4Keys (XConfig {modMask = modm}) = M.fromList $
kde4Keys XConfig{modMask = modm} = M.fromList
[ ((modm, xK_p), spawn "krunner")
, ((modm .|. shiftMask, xK_q), spawn "dbus-send --print-reply --dest=org.kde.ksmserver /KSMServer org.kde.KSMServerInterface.logout int32:1 int32:0 int32:1")
]

46
XMonad/Config/LXQt.hs Normal file
View File

@@ -0,0 +1,46 @@
{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Config.LXQt
-- Description : Config for integrating xmonad with LXQt.
-- Copyright : (c) Petr Shevtsov <petr.shevtsov@gmail.com>
-- License : BSD
--
-- Maintainer : none
-- Stability : unstable
-- Portability : unportable
--
-- This module provides a config suitable for use with the LXQt desktop
-- environment.
module XMonad.Config.LXQt (
-- * Usage
-- $usage
lxqtConfig,
desktopLayoutModifiers
) where
import XMonad
import XMonad.Config.Desktop
import qualified Data.Map as M
-- $usage
-- To use this module, start with the following @~\/.xmonad\/xmonad.hs@:
--
-- > import XMonad
-- > import XMonad.Config.LXQt
-- >
-- > main = xmonad lxqtConfig
--
-- For example of how to further customize @lxqtConfig@ see "XMonad.Config.Desktop".
lxqtConfig = desktopConfig
{ terminal = "qterminal"
, keys = lxqtKeys <+> keys desktopConfig }
lxqtKeys XConfig{modMask = modm} = M.fromList
[ ((modm, xK_p), spawn "lxqt-runner")
, ((modm .|. shiftMask, xK_q), spawn "lxqt-leave")
]

111
XMonad/Config/Mate.hs Normal file
View File

@@ -0,0 +1,111 @@
{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Config.Mate
-- Description : Config for integrating xmonad with MATE.
-- Copyright : (c) Brandon S Allbery KF8NH, 2014
-- License : BSD
--
-- Maintainer : allbery.b@gmail.com
-- Stability : unstable
-- Portability : unportable
--
-- This module provides a config suitable for use with the MATE desktop
-- environment.
--
-----------------------------------------------------------------------------
module XMonad.Config.Mate (
-- * Usage
-- $usage
mateConfig,
mateRun,
matePanel,
mateRegister,
mateLogout,
mateShutdown,
desktopLayoutModifiers
) where
import XMonad
import XMonad.Config.Desktop
import XMonad.Util.Run (safeSpawn)
import XMonad.Util.Ungrab
import XMonad.Prelude (toUpper)
import qualified Data.Map as M
import System.Environment (getEnvironment)
-- $usage
-- To use this module, start with the following @~\/.xmonad\/xmonad.hs@:
--
-- > import XMonad
-- > import XMonad.Config.Mate
-- >
-- > main = xmonad mateConfig
--
-- For examples of how to further customize @mateConfig@ see "XMonad.Config.Desktop".
mateConfig = desktopConfig
{ terminal = "mate-terminal"
, keys = mateKeys <+> keys desktopConfig
, startupHook = mateRegister >> startupHook desktopConfig }
mateKeys XConfig{modMask = modm} = M.fromList
[ ((modm, xK_p), mateRun)
, ((modm, xK_d), unGrab >> matePanel "MAIN_MENU")
, ((modm .|. shiftMask, xK_q), mateLogout) ]
-- | Launch the "Run Application" dialog. mate-panel must be running for this
-- to work. partial application for existing keybinding compatibility.
mateRun :: X ()
mateRun = matePanel "RUN_DIALOG"
-- | Launch a panel action. Either the "Run Application" dialog ("run_dialog" parameter,
-- see above) or the main menu ("main_menu" parameter). mate-panel must be running
-- for this to work.
matePanel :: String -> X ()
matePanel action = withDisplay $ \dpy -> do
let panel = "_MATE_PANEL_ACTION"
rw <- asks theRoot
mate_panel <- getAtom panel
panel_action <- getAtom (panel ++ "_" ++ map toUpper action)
io $ allocaXEvent $ \e -> do
setEventType e clientMessage
setClientMessageEvent e rw mate_panel 32 panel_action 0
sendEvent dpy rw False structureNotifyMask e
sync dpy False
-- | Register xmonad with mate. 'dbus-send' must be in the $PATH with which
-- xmonad is started.
--
-- This action reduces a delay on startup only if you have configured
-- mate-session to start xmonad with a command such as (check local
-- documentation):
--
-- > dconf write /org/mate/desktop/session/required_components/windowmanager "'xmonad'"
--
-- (the extra quotes are required by dconf)
mateRegister :: MonadIO m => m ()
mateRegister = io $ do
x <- lookup "DESKTOP_AUTOSTART_ID" <$> getEnvironment
whenJust x $ \sessionId -> safeSpawn "dbus-send"
["--session"
,"--print-reply=literal"
,"--dest=org.mate.SessionManager"
,"/org/mate/SessionManager"
,"org.mate.SessionManager.RegisterClient"
,"string:xmonad"
,"string:"++sessionId]
-- | Display MATE logout dialog. This is the default mod-q action.
mateLogout :: MonadIO m => m ()
mateLogout = spawn "mate-session-save --logout-dialog"
-- | Display MATE shutdown dialog. You can override mod-q to invoke this, or bind it
-- to another key if you prefer.
mateShutdown :: MonadIO m => m ()
mateShutdown = spawn "mate-session-save --shutdown-dialog"

View File

@@ -20,7 +20,7 @@ module XMonad.Config.Monad where
import XMonad hiding (terminal, keys)
import qualified XMonad as X
import Control.Monad.Writer
import Data.Monoid
import XMonad.Prelude
import Data.Accessor
import Data.Accessor.Basic hiding (set)
@@ -45,5 +45,5 @@ add r x = tell (mkW (r ^: mappend x))
--
example :: Config ()
example = do
add layout $ LL [Layout $ Full] -- make this better
add layout $ LL [Layout Full] -- make this better
set terminal "urxvt"

690
XMonad/Config/Prime.hs Normal file
View File

@@ -0,0 +1,690 @@
{-# LANGUAGE FlexibleContexts, FlexibleInstances, FunctionalDependencies, KindSignatures, UndecidableInstances #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Config.Prime
-- Description : Draft of a brand new config syntax for xmonad.
-- Copyright : Devin Mullins <devin.mullins@gmail.com>
-- License : BSD-style (see LICENSE)
--
-- Maintainer : Devin Mullins <devin.mullins@gmail.com>
-- Stability : unstable
-- Portability : unportable
--
-- This is a draft of a brand new config syntax for xmonad. It aims to be:
--
-- * easier to copy/paste snippets from the docs
--
-- * easier to get the gist for what's going on, for you imperative programmers
--
-- It's brand new, so it's pretty much guaranteed to break or change syntax.
-- But what's the worst that could happen? Xmonad crashes and logs you out?
-- It probably won't do that. Give it a try.
--
-----------------------------------------------------------------------------
module XMonad.Config.Prime (
-- Note: The identifiers here are listed in the order that makes the most sense
-- for a user, while the definitions below are listed in the order that makes
-- the most sense for a developer.
-- * Start here
-- $start_here
xmonad,
nothing,
-- * Attributes you can set
-- $settables
normalBorderColor,
focusedBorderColor,
terminal,
modMask,
borderWidth,
focusFollowsMouse,
clickJustFocuses,
SettableClass(..),
UpdateableClass(..),
-- * Attributes you can add to
-- $summables
manageHook,
handleEventHook,
workspaces,
logHook,
startupHook,
clientMask,
rootMask,
SummableClass(..),
-- * Attributes you can add to or remove from
-- $removables
keys,
mouseBindings,
RemovableClass(..),
-- * Modifying the list of workspaces
-- $workspaces
withWorkspaces,
wsNames,
wsKeys,
wsActions,
wsSetName,
-- * Modifying the screen keybindings
-- $screens
withScreens,
sKeys,
sActions,
onScreens,
-- * Modifying the layoutHook
-- $layout
addLayout,
resetLayout,
modifyLayout,
-- * Updating the XConfig en masse
-- $update
startWith,
apply,
applyIO,
-- * The rest of the world
-- | Everything you know and love from the core "XMonad" module is available
-- for use in your config file, too.
module XMonad,
-- | (Almost) everything you know and love from the Haskell "Prelude" is
-- available for use in your config file. Note that '>>' has been overriden, so
-- if you want to create do-blocks for normal monads, you'll need some let
-- statements or a separate module. (See the Troubleshooting section.)
module Prelude,
-- * Core
-- | These are the building blocks on which the config language is built.
-- Regular people shouldn't need to know about these.
Prime,
Arr,
(>>),
ifThenElse,
-- * Example config
-- $example
-- * Troubleshooting
-- $troubleshooting
) where
import Prelude hiding ((>>), mod)
import qualified Prelude as P ((>>=), (>>))
import XMonad.Prelude (All)
import XMonad hiding (xmonad, XConfig(..))
import XMonad (XConfig(XConfig))
import qualified XMonad.StackSet as W
import qualified XMonad as X (xmonad, XConfig(..))
import XMonad.Util.EZConfig (additionalKeysP, additionalMouseBindings, checkKeymap, removeKeysP, removeMouseBindings)
-- $start_here
-- To start with, create a @~\/.xmonad\/xmonad.hs@ that looks like this:
--
-- > {-# LANGUAGE RebindableSyntax #-}
-- > import XMonad.Config.Prime
-- >
-- > -- Imports go here.
-- >
-- > main = xmonad $ do
-- > nothing
-- > -- Configs go here.
--
-- This will give you a default xmonad install, with room to grow. The lines
-- starting with double dashes are comments. You may delete them. Note that
-- Haskell is a bit precise about indentation. Make sure all the statements in
-- your do-block start at the same column, and make sure that any multi-line
-- statements are formatted with a hanging indent. (For an example, see the
-- 'keys =+' statement in the /Example config/ section, below.)
--
-- After changing your config file, restart xmonad with mod-q (where, by
-- default, "mod" == "alt").
--
-- The Prime "Monad"
--
-- | A Prime is a function that transforms an XConfig. It's not a monad, but we
-- turn on RebindableSyntax so we can abuse the pretty do notation.
type Prime l l' = Arr (XConfig l) (XConfig l')
-- | An Arr is a generalization of Prime. Don't reference the type, if you can
-- avoid it. It might go away in the future.
type Arr x y = x -> IO y
-- | Composes two Arrs using 'Prelude.>>=' from "Prelude".
(>>) :: Arr x y -> Arr y z -> Arr x z
(>>) x y c = (P.>>=) (x c) y
-- | Because of RebindableSyntax, this is necessary to enable you to use
-- if-then-else expressions. No need to call it directly.
ifThenElse :: Bool -> a -> a -> a
ifThenElse True a _ = a
ifThenElse False _ b = b
-- | This is the xmonad main function. It passes 'XMonad.Config.def' (the
-- default 'XConfig') into your do-block, takes the modified config out of your
-- do-block, and then runs xmonad.
--
-- The do-block is a 'Prime'. Advanced readers can skip right to that
-- definition.
xmonad :: (Default a, Read (l Window), LayoutClass l Window) =>
(a -> IO (XConfig l)) -> IO ()
xmonad prime = (P.>>=) (prime def) X.xmonad
-- | This doesn't modify the config in any way. It's just here for your initial
-- config because Haskell doesn't allow empty do-blocks. Feel free to delete it
-- once you've added other stuff.
nothing :: Prime l l
nothing = return
-- $settables
-- These are a bunch of attributes that you can set. Syntax looks like this:
--
-- > terminal =: "urxvt"
--
-- Strings are double quoted, Dimensions are unquoted integers, booleans are
-- 'True' or 'False' (case-sensitive), and 'modMask' is usually 'mod1Mask' or
-- 'mod4Mask'.
class UpdateableClass s x y | s -> x y where
-- | This lets you apply a function to an attribute (i.e. read, modify, write).
(=.) :: s c -> (x -> y) -> Arr c c
class SettableClass s x y | s -> x y where
-- | This lets you modify an attribute.
(=:) :: s c -> y -> Arr c c
-- Undecideable instance. But it's nice to leave open the possibility to write
-- fields you can't read (e.g. `wmName =: ...`).
instance UpdateableClass s x y => SettableClass s x y where
s =: y = s =. const y
data Settable x c = Settable (c -> x) -- getter
(x -> c -> c) -- setter
instance UpdateableClass (Settable x) x x where
(Settable g s =. f) c = return $ s (f $ g c) c
-- | Non-focused windows border color. Default: @\"#dddddd\"@
normalBorderColor :: Settable String (XConfig l)
normalBorderColor = Settable X.normalBorderColor (\x c -> c { X.normalBorderColor = x })
-- | Focused windows border color. Default: @\"#ff0000\"@
focusedBorderColor :: Settable String (XConfig l)
focusedBorderColor = Settable X.focusedBorderColor (\x c -> c { X.focusedBorderColor = x })
-- | The preferred terminal application. Default: @\"xterm\"@
terminal :: Settable String (XConfig l)
terminal = Settable X.terminal (\x c -> c { X.terminal = x })
-- | The mod modifier, as used by key bindings. Default: @mod1Mask@ (which is
-- probably alt on your computer).
modMask :: Settable KeyMask (XConfig l)
modMask = Settable X.modMask (\x c -> c { X.modMask = x })
-- | The border width (in pixels). Default: @1@
borderWidth :: Settable Dimension (XConfig l)
borderWidth = Settable X.borderWidth (\x c -> c { X.borderWidth = x })
-- | Whether window focus follows the mouse cursor on move, or requires a mouse
-- click. (Mouse? What's that?) Default: @True@
focusFollowsMouse :: Settable Bool (XConfig l)
focusFollowsMouse = Settable X.focusFollowsMouse (\x c -> c { X.focusFollowsMouse = x })
-- | If True, a mouse click on an inactive window focuses it, but the click is
-- not passed to the window. If False, the click is also passed to the window.
-- Default @True@
clickJustFocuses :: Settable Bool (XConfig l)
clickJustFocuses = Settable X.clickJustFocuses (\x c -> c { X.clickJustFocuses = x })
-- $summables
-- In addition to being able to set these attributes, they have a special
-- syntax for being able to add to them. The operator is @=+@ (the plus comes
-- /after/ the equals), but each attribute has a different syntax for what
-- comes after the operator.
class SummableClass s y | s -> y where
-- | This lets you add to an attribute.
(=+) :: s c -> y -> Arr c c
infix 0 =+
data Summable x y c = Summable (c -> x) -- getter
(x -> c -> c) -- setter
(x -> y -> x) -- accumulator
instance UpdateableClass (Summable x y) x x where
(Summable g s _ =. f) c = return $ s (f $ g c) c
instance SummableClass (Summable x y) y where
(Summable g s a =+ y) c = return $ s (g c `a` y) c
-- | The action to run when a new window is opened. Default:
--
-- > manageHook =: composeAll [className =? "MPlayer" --> doFloat, className =? "Gimp" --> doFloat]
--
-- To add more rules to this list, you can say, for instance:
--
-- > import XMonad.StackSet
-- > ...
-- > manageHook =+ (className =? "Emacs" --> doF kill)
-- > manageHook =+ (className =? "Vim" --> doF shiftMaster)
--
-- Note that operator precedence mandates the parentheses here.
manageHook :: Summable ManageHook ManageHook (XConfig l)
manageHook = Summable X.manageHook (\x c -> c { X.manageHook = x }) (<+>)
-- | Custom X event handler. Return @All True@ if the default handler should
-- also be run afterwards. Default does nothing. To add an event handler:
--
-- > import XMonad.Hooks.ServerMode
-- > ...
-- > handleEventHook =+ serverModeEventHook
handleEventHook :: Summable (Event -> X All) (Event -> X All) (XConfig l)
handleEventHook = Summable X.handleEventHook (\x c -> c { X.handleEventHook = x }) (<+>)
-- | List of workspaces' names. Default: @map show [1 .. 9 :: Int]@. Adding
-- appends to the end:
--
-- > workspaces =+ ["0"]
--
-- This is useless unless you also create keybindings for this.
workspaces :: Summable [String] [String] (XConfig l)
workspaces = Summable X.workspaces (\x c -> c { X.workspaces = x }) (++)
-- | The action to perform when the windows set is changed. This happens
-- whenever focus change, a window is moved, etc. @logHook =+@ takes an @X ()@
-- and appends it via '(>>)'. For instance:
--
-- > import XMonad.Hooks.ICCCMFocus
-- > ...
-- > logHook =+ takeTopFocus
--
-- Note that if your expression is parametrically typed (e.g. of type
-- @MonadIO m => m ()@), you'll need to explicitly annotate it, like so:
--
-- > logHook =+ (io $ putStrLn "Hello, world!" :: X ())
logHook :: Summable (X ()) (X ()) (XConfig l)
logHook = Summable X.logHook (\x c -> c { X.logHook = x }) (P.>>)
-- | The action to perform on startup. @startupHook =+@ takes an @X ()@ and
-- appends it via '(>>)'. For instance:
--
-- > import XMonad.Hooks.SetWMName
-- > ...
-- > startupHook =+ setWMName "LG3D"
--
-- Note that if your expression is parametrically typed (e.g. of type
-- @MonadIO m => m ()@), you'll need to explicitly annotate it, as documented
-- in 'logHook'.
startupHook :: Summable (X ()) (X ()) (XConfig l)
startupHook = Summable X.startupHook (\x c -> c { X.startupHook = x }) (P.>>)
-- | The client events that xmonad is interested in. This is useful in
-- combination with handleEventHook. Default: @structureNotifyMask .|.
-- enterWindowMask .|. propertyChangeMask@
--
-- > clientMask =+ keyPressMask .|. keyReleaseMask
clientMask :: Summable EventMask EventMask (XConfig l)
clientMask = Summable X.clientMask (\x c -> c { X.clientMask = x }) (.|.)
-- | The root events that xmonad is interested in. This is useful in
-- combination with handleEventHook. Default: @substructureRedirectMask .|.
-- substructureNotifyMask .|. enterWindowMask .|. leaveWindowMask .|.
-- structureNotifyMask .|. buttonPressMask@
rootMask :: Summable EventMask EventMask (XConfig l)
rootMask = Summable X.rootMask (\x c -> c { X.rootMask = x }) (.|.)
-- $removables
-- The following support the the @=+@ for adding items and the @=-@ operator
-- for removing items.
class RemovableClass r y | r -> y where
-- | This lets you remove from an attribute.
(=-) :: r c -> y -> Arr c c
infix 0 =-
data Keys c = Keys { kAdd :: [(String, X ())] -> c -> c,
kRemove :: [String] -> c -> c }
instance SummableClass Keys [(String, X ())] where
Keys { kAdd = a } =+ newKeys = return . a newKeys
instance RemovableClass Keys [String] where
Keys { kRemove = r } =- sadKeys = return . r sadKeys
-- | Key bindings to 'X' actions. Default: see @`man xmonad`@. 'keys'
-- takes a list of keybindings specified emacs-style, as documented in
-- 'XMonad.Util.EZConfig.mkKeyMap'. For example, to change the "kill window"
-- key:
--
-- > keys =- ["M-S-c"]
-- > keys =+ [("M-M1-x", kill)]
keys :: Keys (XConfig l)
keys = Keys {
-- Note that since checkKeymap happens on newKeys, it doesn't check for
-- duplicates between repeated applications. Probably OK. (Especially since
-- overriding defaults is a common behavior.) Also note that there's no
-- reference cycle here. Yay!
kAdd = \newKeys c -> (c `additionalKeysP` newKeys) { X.startupHook = (P.>>) (X.startupHook c) (checkKeymap c newKeys) },
kRemove = flip removeKeysP
}
data MouseBindings c = MouseBindings { mAdd :: [((ButtonMask, Button), Window -> X ())] -> c -> c,
mRemove :: [(ButtonMask, Button)] -> c -> c }
instance SummableClass MouseBindings [((ButtonMask, Button), Window -> X ())] where
MouseBindings { mAdd = a } =+ newBindings = return . a newBindings
instance RemovableClass MouseBindings [(ButtonMask, Button)] where
MouseBindings { mRemove = r } =- sadBindings = return . r sadBindings
-- | Mouse button bindings to an 'X' actions on a window. Default: see @`man
-- xmonad`@. To make mod-<scrollwheel> switch workspaces:
--
-- > import XMonad.Actions.CycleWS (nextWS, prevWS)
-- > ...
-- > mouseBindings =+ [((mod4Mask, button4), const prevWS),
-- > ((mod4Mask, button5), const nextWS)]
--
-- Note that you need to specify the numbered mod-mask e.g. 'mod4Mask' instead
-- of just 'modMask'.
mouseBindings :: MouseBindings (XConfig l)
mouseBindings = MouseBindings {
mAdd = flip additionalMouseBindings,
mRemove = flip removeMouseBindings
}
-- $workspaces
-- Workspaces can be configured through 'workspaces', but then the 'keys' need
-- to be set, and this can be a bit laborious. 'withWorkspaces' provides a
-- convenient mechanism for common workspace updates.
-- | Configure workspaces through a Prime-like interface. Example:
--
-- > withWorkspaces $ do
-- > wsKeys =+ ["0"]
-- > wsActions =+ [("M-M1-", windows . swapWithCurrent)]
-- > wsSetName 1 "mail"
--
-- This will set 'workspaces' and add the necessary keybindings to 'keys'. Note
-- that it won't remove old keybindings; it's just not that clever.
withWorkspaces :: Arr WorkspaceConfig WorkspaceConfig -> Prime l l
withWorkspaces wsarr xconf = (P.>>=) (wsarr def) $ \wsconf -> wsprime wsconf xconf
where wsprime :: WorkspaceConfig -> Prime l l
wsprime wsconf =
(workspaces =: allNames) >>
(keys =+ [(mod ++ key, action name) | (name, key) <- zip allNames (wsKeys_ wsconf),
(mod, action) <- wsActions_ wsconf])
where allNames = zipWith chooseName (wsNames_ wsconf) (wsKeys_ wsconf)
chooseName name keyspec = if not (null name) then name else keyspec
data WorkspaceConfig = WorkspaceConfig {
wsNames_ :: [String],
wsKeys_ :: [String],
wsActions_ :: [(String, String -> X ())]
}
instance Default WorkspaceConfig where
def = WorkspaceConfig {
wsNames_ = repeat "",
wsKeys_ = map (:[]) ['1'..'9'], -- The hungry monkey eats dots and turns them into numbers.
wsActions_ = [("M-", windows . W.greedyView),
("M-S-", windows . W.shift)]
}
-- | The list of workspace names, like 'workspaces' but with two differences:
--
-- 1. If any entry is the empty string, it'll be replaced with the
-- corresponding entry in 'wsKeys'.
-- 2. The list is truncated to the size of 'wsKeys'.
--
-- The default value is @'repeat' ""@.
--
-- If you'd like to create workspaces without associated keyspecs, you can do
-- that afterwards, outside the 'withWorkspaces' block, with @'workspaces' =+@.
wsNames :: Settable [String] WorkspaceConfig
wsNames = Settable wsNames_ (\x c -> c { wsNames_ = x })
-- | The list of workspace keys. These are combined with the modifiers in
-- 'wsActions' to form the keybindings for navigating to workspaces. Default:
-- @["1","2",...,"9"]@.
wsKeys :: Summable [String] [String] WorkspaceConfig
wsKeys = Summable wsKeys_ (\x c -> c { wsKeys_ = x }) (++)
-- | Mapping from key prefix to command. Its type is @[(String, String ->
-- X())]@. The key prefix may be a modifier such as @\"M-\"@, or a submap
-- prefix such as @\"M-a \"@, or both, as in @\"M-a M-\"@. The command is a
-- function that takes a workspace name and returns an @X ()@. 'withWorkspaces'
-- creates keybindings for the cartesian product of 'wsKeys' and 'wsActions'.
--
-- Default:
--
-- > [("M-", windows . W.greedyView),
-- > ("M-S-", windows . W.shift)]
wsActions :: Summable [(String, String -> X ())] [(String, String -> X ())] WorkspaceConfig
wsActions = Summable wsActions_ (\x c -> c { wsActions_ = x }) (++)
-- | A convenience for just modifying one entry in 'wsNames', in case you only
-- want a few named workspaces. Example:
--
-- > wsSetName 1 "mail"
-- > wsSetName 2 "web"
wsSetName :: Int -> String -> Arr WorkspaceConfig WorkspaceConfig
wsSetName index newName = wsNames =. zipWith (curry maybeSet) [0..]
where maybeSet (i, oldName) | i == (index - 1) = newName
| otherwise = oldName
-- $screens
-- 'withScreens' provides a convenient mechanism to set keybindings for moving
-- between screens, much like 'withWorkspaces'.
-- | Configure screen keys through a Prime-like interface:
--
-- > withScreens $ do
-- > sKeys =: ["e", "r"]
--
-- This will add the necessary keybindings to 'keys'. Note that it won't remove
-- old keybindings; it's just not that clever.
withScreens :: Arr ScreenConfig ScreenConfig -> Prime l l
withScreens sarr xconf = (P.>>=) (sarr def) $ \sconf -> sprime sconf xconf
where sprime :: ScreenConfig -> Prime l l
sprime sconf =
keys =+ [(mod ++ key, action sid) | (sid, key) <- zip [0..] (sKeys_ sconf),
(mod, action) <- sActions_ sconf]
data ScreenConfig = ScreenConfig {
sKeys_ :: [String],
sActions_ :: [(String, ScreenId -> X ())]
}
instance Default ScreenConfig where
def = ScreenConfig {
sKeys_ = ["w", "e", "r"],
sActions_ = [("M-", windows . onScreens W.view),
("M-S-", windows . onScreens W.shift)]
}
-- | The list of screen keys. These are combined with the modifiers in
-- 'sActions' to form the keybindings for navigating to workspaces. Default:
-- @["w","e","r"]@.
sKeys :: Summable [String] [String] ScreenConfig
sKeys = Summable sKeys_ (\x c -> c { sKeys_ = x }) (++)
-- | Mapping from key prefix to command. Its type is @[(String, ScreenId ->
-- X())]@. Works the same as 'wsActions' except for a different function type.
--
-- Default:
--
-- > [("M-", windows . onScreens W.view),
-- > ("M-S-", windows . onScreens W.shift)]
sActions :: Summable [(String, ScreenId -> X ())] [(String, ScreenId -> X ())] ScreenConfig
sActions = Summable sActions_ (\x c -> c { sActions_ = x }) (++)
-- | Converts a stackset transformer parameterized on the workspace type into one
-- parameterized on the screen type. For example, you can use @onScreens W.view
-- 0@ to navigate to the workspace on the 0th screen. If the screen id is not
-- recognized, the returned transformer acts as an identity function.
onScreens :: Eq s => (i -> W.StackSet i l a s sd -> W.StackSet i l a s sd) ->
s -> W.StackSet i l a s sd -> W.StackSet i l a s sd
onScreens f sc ws = maybe id f (W.lookupWorkspace sc ws) ws
-- $layout
-- Layouts are special. You can't modify them using the @=:@ or @=.@ operator.
-- You need to use the following functions.
-- | Add a layout to the list of layouts choosable with mod-space. For instance:
--
-- > import XMonad.Layout.Tabbed
-- > ...
-- > addLayout simpleTabbed
addLayout :: (LayoutClass l Window, LayoutClass r Window) => r Window -> Prime l (Choose l r)
addLayout r c = return c { X.layoutHook = X.layoutHook c ||| r }
-- | Reset the layoutHook from scratch. For instance, to get rid of the wide
-- layout:
--
-- > resetLayout $ Tall 1 (3/100) (1/2) ||| Full
--
-- (The dollar is like an auto-closing parenthesis, so all the stuff to the
-- right of it is treated like an argument to resetLayout.)
resetLayout :: (LayoutClass r Window) => r Window -> Prime l r
resetLayout r c = return c { X.layoutHook = r }
-- | Modify your 'layoutHook' with some wrapper function. You probably want to call
-- this after you're done calling 'addLayout'. Example:
--
-- > import XMonad.Layout.NoBorders
-- > ...
-- > modifyLayout smartBorders
modifyLayout :: (LayoutClass r Window) => (l Window -> r Window) -> Prime l r
modifyLayout f c = return c { X.layoutHook = f $ X.layoutHook c }
-- $update
-- Finally, there are a few contrib modules that bundle multiple attribute
-- updates together. There are three types: 1) wholesale replacements for the
-- default config, 2) pure functions on the config, and 3) IO actions on the
-- config. The syntax for each is different. Examples:
--
-- 1) To start with a 'XMonad.Config.Gnome.gnomeConfig' instead of the default,
-- we use 'startWith':
--
-- > import XMonad.Config.Gnome
-- > ...
-- > startWith gnomeConfig
--
-- 2) 'XMonad.Hooks.UrgencyHook.withUrgencyHook' is a pure function, so we need
-- to use 'apply':
--
-- > import XMonad.Hooks.UrgencyHook
-- > ...
-- > apply $ withUrgencyHook dzenUrgencyHook
--
-- 3) 'XMonad.Hooks.DynamicLog.xmobar' returns an @IO (XConfig l)@, so we need
-- to use 'applyIO':
--
-- > import XMonad.Hooks.DynamicLog
-- > ...
-- > applyIO xmobar
-- | Replace the current 'XConfig' with the given one. If you use this, you
-- probably want it to be the first line of your config.
startWith :: XConfig l' -> Prime l l'
startWith = const . return
-- | Turns a pure function on 'XConfig' into a 'Prime'.
apply :: (XConfig l -> XConfig l') -> Prime l l'
apply f = return . f
-- | Turns an IO function on 'XConfig' into a 'Prime'.
applyIO :: (XConfig l -> IO (XConfig l')) -> Prime l l'
applyIO = id -- This is here in case we want to change the Prime type later.
-- $example
-- As an example, I've included below a subset of my current config. Note that
-- my import statements specify individual identifiers in parentheticals.
-- That's optional. The default is to import the entire module. I just find it
-- helpful to remind me where things came from.
--
-- > {-# LANGUAGE RebindableSyntax #-}
-- > import XMonad.Config.Prime
-- >
-- > import XMonad.Actions.CycleWS (prevWS, nextWS)
-- > import XMonad.Actions.SwapWorkspaces (swapWithCurrent)
-- > import XMonad.Actions.WindowNavigation (withWindowNavigation)
-- > import XMonad.Layout.Fullscreen (fullscreenSupport)
-- > import XMonad.Layout.NoBorders (smartBorders)
-- > import XMonad.Layout.Tabbed (simpleTabbed)
-- >
-- > main = xmonad $ do
-- > modMask =: mod4Mask
-- > normalBorderColor =: "#222222"
-- > terminal =: "urxvt"
-- > focusFollowsMouse =: False
-- > resetLayout $ Tall 1 (3/100) (1/2) ||| simpleTabbed
-- > modifyLayout smartBorders
-- > apply fullscreenSupport
-- > applyIO $ withWindowNavigation (xK_w, xK_a, xK_s, xK_d)
-- > withWorkspaces $ do
-- > wsKeys =+ ["0"]
-- > wsActions =+ [("M-M1-", windows . swapWithCurrent)]
-- > keys =+ [
-- > ("M-,", sendMessage $ IncMasterN (-1)),
-- > ("M-.", sendMessage $ IncMasterN 1),
-- > ("M-M1-d", spawn "date | dzen2 -fg '#eeeeee' -p 2"),
-- > ("C-S-q", return ()),
-- > ("<XF86AudioLowerVolume>", spawn "amixer set Master 5%-"),
-- > ("<XF86AudioRaiseVolume>", spawn "amixer set Master 5%+"),
-- > ("M-M1-x", kill),
-- > ("M-i", prevWS),
-- > ("M-o", nextWS)
-- > ]
-- $troubleshooting
-- === Only the last line of my config seems to take effect. What gives?
-- You're missing the @{-\# LANGUAGE RebindableSyntax \#-}@ line at the top.
--
-- === How do I do use normal monads like 'X' or 'IO'?
-- Here are a couple of ways:
--
-- > import qualified Prelude as P
-- > ...
-- > test1, test2 :: X ()
-- > test1 = spawn "echo Hi" P.>> spawn "echo Bye"
-- > test2 = do spawn "echo Hi"
-- > spawn "echo Bye"
-- > where (>>) = (P.>>)
--
-- === How do I use the old keyboard syntax?
-- You can use 'apply' and supply your own Haskell function. For instance:
--
-- > apply $ flip additionalKeys $ [((mod1Mask, xK_z), spawn "date | dzen2 -fg '#eeeeee' -p 2")]
--
-- === How do I run a command before xmonad starts (like 'spawnPipe')?
-- If you're using it for a status bar, see if 'XMonad.Hooks.DynamicLog.dzen'
-- or 'XMonad.Hooks.DynamicLog.xmobar' does what you want. If so, you can apply
-- it with 'applyIO'.
--
-- If not, you can write your own @XConfig l -> IO (XConfig l)@ and apply it
-- with 'applyIO'. When writing this function, see the above tip about using
-- normal monads.
--
-- Alternatively, you could do something like this this:
--
-- > import qualified Prelude as P (>>)
-- >
-- > main =
-- > openFile ".xmonad.log" AppendMode >>= \log ->
-- > hSetBuffering log LineBuffering P.>>
-- > (xmonad $ do
-- > nothing -- Prime config here.
-- > )

78
XMonad/Config/Saegesser.hs Executable file
View File

@@ -0,0 +1,78 @@
{-# OPTIONS_GHC -fno-warn-missing-signatures -fno-warn-orphans #-}
{-# LANGUAGE OverloadedStrings #-}
---------------------------------------------------------------------
-- |
-- A mostly striped down configuration that demonstrates spawnOnOnce
--
---------------------------------------------------------------------
import System.IO
import XMonad
import XMonad.Hooks.DynamicLog
import XMonad.Hooks.ManageDocks
import XMonad.Hooks.ManageHelpers
import XMonad.Hooks.UrgencyHook
import XMonad.Hooks.FadeInactive
import XMonad.Layout.NoBorders
import XMonad.Layout.ResizableTile
import XMonad.Layout.Mosaic
import XMonad.Util.Run
import XMonad.Util.Cursor
import XMonad.Util.NamedScratchpad
import XMonad.Util.Scratchpad
import XMonad.Util.SpawnOnce
import XMonad.Actions.CopyWindow
import XMonad.Actions.SpawnOn
import qualified XMonad.StackSet as W
main = do
myStatusBarPipe <- spawnPipe "xmobar"
xmonad $ docks $ withUrgencyHook NoUrgencyHook $ def
{ terminal = "xterm"
, workspaces = myWorkspaces
, layoutHook = myLayoutHook
, manageHook = myManageHook <+> manageSpawn
, startupHook = myStartupHook
, logHook = myLogHook myStatusBarPipe
, focusFollowsMouse = False
}
myManageHook = composeOne
[ isDialog -?> doFloat
, className =? "trayer" -?> doIgnore
, className =? "Skype" -?> doShift "chat"
, appName =? "libreoffice" -?> doShift "office"
, return True -?> doF W.swapDown
]
myWorkspaces = [ "web", "emacs", "chat", "vm", "office", "media", "xterms", "8", "9", "0"]
myStartupHook = do
setDefaultCursor xC_left_ptr
spawnOnOnce "emacs" "emacs"
spawnNOnOnce 4 "xterms" "xterm"
myLayoutHook = smartBorders $ avoidStruts standardLayouts
where standardLayouts = tiled ||| mosaic 2 [3,2] ||| Mirror tiled ||| Full
tiled = ResizableTall nmaster delta ratio []
nmaster = 1
delta = 0.03
ratio = 0.6
myLogHook p = do
copies <- wsContainingCopies
let check ws | ws == "NSP" = "" -- Hide the scratchpad workspace
| ws `elem` copies = xmobarColor "red" "black" ws -- Workspaces with copied windows are red on black
| otherwise = ws
dynamicLogWithPP $ xmobarPP { ppHidden = check
, ppOutput = hPutStrLn p
, ppUrgent = xmobarColor "white" "red"
, ppTitle = xmobarColor "green" "" . shorten 180
}
fadeInactiveLogHook 0.6

View File

@@ -1,4 +1,10 @@
{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Config.Sjanssen
-- Description : Spencer Janssen's xmonad config.
--
------------------------------------------------------------------------
module XMonad.Config.Sjanssen (sjanssenConfig) where
import XMonad hiding (Tall(..))
@@ -21,21 +27,21 @@ import XMonad.Layout.TwoPane
import qualified Data.Map as M
sjanssenConfig =
ewmh $ defaultConfig
docks $ ewmh $ def
{ terminal = "exec urxvt"
, workspaces = ["irc", "web"] ++ map show [3 .. 9 :: Int]
, mouseBindings = \(XConfig {modMask = modm}) -> M.fromList $
[ ((modm, button1), (\w -> focus w >> mouseMoveWindow w))
, ((modm, button2), (\w -> focus w >> windows W.swapMaster))
, ((modm.|. shiftMask, button1), (\w -> focus w >> mouseResizeWindow w)) ]
, keys = \c -> mykeys c `M.union` keys defaultConfig c
, mouseBindings = \XConfig {modMask = modm} -> M.fromList
[ ((modm, button1), \w -> focus w >> mouseMoveWindow w)
, ((modm, button2), \w -> focus w >> windows W.swapMaster)
, ((modm.|. shiftMask, button1), \w -> focus w >> mouseResizeWindow w) ]
, keys = \c -> mykeys c `M.union` keys def c
, logHook = dynamicLogString sjanssenPP >>= xmonadPropLog
, layoutHook = modifiers layouts
, manageHook = composeAll [className =? x --> doShift w
| (x, w) <- [ ("Firefox", "web")
, ("Ktorrent", "7")
, ("Amarokapp", "7")]]
<+> manageHook defaultConfig <+> manageDocks <+> manageSpawn
<+> manageHook def <+> manageSpawn
<+> (isFullscreen --> doFullFloat)
, startupHook = mapM_ spawnOnce spawns
}
@@ -50,20 +56,20 @@ sjanssenConfig =
, "trayer --transparent true --expand true --align right "
++ "--edge bottom --widthtype request" ]
mykeys (XConfig {modMask = modm}) = M.fromList $
mykeys XConfig{modMask = modm} = M.fromList
[((modm, xK_p ), shellPromptHere myPromptConfig)
,((modm .|. shiftMask, xK_Return), spawnHere =<< asks (terminal . config))
,((modm .|. shiftMask, xK_c ), kill1)
,((modm .|. shiftMask .|. controlMask, xK_c ), kill)
,((modm .|. shiftMask, xK_0 ), windows $ copyToAll)
,((modm .|. shiftMask, xK_0 ), windows copyToAll)
,((modm, xK_z ), layoutScreens 2 $ TwoPane 0.5 0.5)
,((modm .|. shiftMask, xK_z ), rescreen)
, ((modm , xK_b ), sendMessage ToggleStruts)
]
myFont = "xft:Bitstream Vera Sans Mono:pixelsize=10"
myTheme = defaultTheme { fontName = myFont }
myPromptConfig = defaultXPConfig
myTheme = def { fontName = myFont }
myPromptConfig = def
{ position = Top
, font = myFont
, showCompletionOnTab = True

View File

@@ -3,6 +3,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Config.Xfce
-- Description : Config for integrating xmonad with Xfce.
-- Copyright : (c) Ivan Miljenovic <Ivan.Miljenovic@gmail.com>
-- License : BSD
--
@@ -16,7 +17,8 @@
module XMonad.Config.Xfce (
-- * Usage
-- $usage
xfceConfig
xfceConfig,
desktopLayoutModifiers
) where
import XMonad
@@ -35,10 +37,10 @@ import qualified Data.Map as M
-- For examples of how to further customize @xfceConfig@ see "XMonad.Config.Desktop".
xfceConfig = desktopConfig
{ terminal = "Terminal"
{ terminal = "xfce4-terminal"
, keys = xfceKeys <+> keys desktopConfig }
xfceKeys (XConfig {modMask = modm}) = M.fromList $
xfceKeys XConfig{modMask = modm} = M.fromList
[ ((modm, xK_p), spawn "xfrun4")
, ((modm .|. shiftMask, xK_p), spawn "xfce4-appfinder")
, ((modm .|. shiftMask, xK_q), spawn "xfce4-session-logout")

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