From 6eae27390db96ba7c0831eade3520de06ce9cc10 Mon Sep 17 00:00:00 2001
From: Wilson Sales <spoonm@spoonm.org>
Date: Wed, 21 Aug 2019 08:20:54 -0300
Subject: [PATCH] Added module X.A.PerWindowKeys

Allows one to shortcut actions that are performed based on queries.

Signed-off-by: Wilson Sales <spoonm@spoonm.org>
---
 CHANGES.md                      |  6 ++++
 XMonad/Actions/PerWindowKeys.hs | 60 +++++++++++++++++++++++++++++++++
 xmonad-contrib.cabal            |  1 +
 3 files changed, 67 insertions(+)
 create mode 100644 XMonad/Actions/PerWindowKeys.hs

diff --git a/CHANGES.md b/CHANGES.md
index 3a0d21a1..acd3844b 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -37,6 +37,12 @@
     that are exclusive on the same screen. It also allows to remove this
     constraint of being mutually exclusive with another scratchpad.
 
+  * `XMonad.Actions.PerWindowKeys`
+
+    Create actions that run on a `Query Bool`, usually associated with
+    conditions on a window, basis. Useful for creating bindings that are
+    excluded or exclusive for some windows.
+
 ### Bug Fixes and Minor Changes
 
   * `XMonad.Prompt`
diff --git a/XMonad/Actions/PerWindowKeys.hs b/XMonad/Actions/PerWindowKeys.hs
new file mode 100644
index 00000000..2c3e1fc2
--- /dev/null
+++ b/XMonad/Actions/PerWindowKeys.hs
@@ -0,0 +1,60 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  XMonad.Actions.PerWindowKeys
+-- Copyright   :  (c) Wilson Sales, 2019
+-- License     :  BSD3-style (see LICENSE)
+--
+-- Maintainer  :  Wilson Sales <spoonm@spoonm.org>
+-- Stability   :  unstable
+-- Portability :  unportable
+--
+-- Define key-bindings on 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
diff --git a/xmonad-contrib.cabal b/xmonad-contrib.cabal
index 5591cdb4..25ca8d24 100644
--- a/xmonad-contrib.cabal
+++ b/xmonad-contrib.cabal
@@ -116,6 +116,7 @@ library
                         XMonad.Actions.Navigation2D
                         XMonad.Actions.NoBorders
                         XMonad.Actions.OnScreen
+                        XMonad.Actions.PerWindowKeys
                         XMonad.Actions.PerWorkspaceKeys
                         XMonad.Actions.PhysicalScreens
                         XMonad.Actions.Plane