{-# LANGUAGE BangPatterns        #-}
{-# LANGUAGE LambdaCase          #-}
{-# LANGUAGE ScopedTypeVariables #-}
--------------------------------------------------------------------
-- |
-- Module      :  XMonad.Prelude
-- Description :  Utility functions and re-exports.
-- Copyright   :  (c) 2021  Tony Zorman
-- License     :  BSD3-style (see LICENSE)
--
-- Maintainer  :  Tony Zorman <soliditsallgood@mailbox.org>
--
-- Utility functions and re-exports for a more ergonomic developing
-- experience.  Users themselves will not find much use here.
--
--------------------------------------------------------------------
module XMonad.Prelude (
    module Exports,
    fi,
    chunksOf,
    (.:),
    (!?),
    NonEmpty((:|)),
    notEmpty,
    safeGetWindowAttributes,
    mkAbsolutePath,

    -- * Keys
    keyToString,
    keymaskToString,
    cleanKeyMask,
    regularKeys,
    allSpecialKeys,
    specialKeys,
    multimediaKeys,
    functionKeys,
    WindowScreen,
) where

import Foreign (alloca, peek)
import XMonad

import Control.Applicative as Exports
import Control.Monad       as Exports
import Data.Bool           as Exports
import Data.Char           as Exports
import Data.Foldable       as Exports
import Data.Function       as Exports
import Data.Functor        as Exports
import Data.List           as Exports
import Data.Maybe          as Exports
import Data.Monoid         as Exports
import Data.Traversable    as Exports

import qualified Data.Map.Strict as Map

import Control.Arrow ((&&&), first)
import Data.Bifunctor (bimap)
import Data.Bits
import Data.List.NonEmpty (NonEmpty ((:|)))
import Data.Tuple (swap)
import GHC.Stack
import System.Directory (getHomeDirectory)
import System.Environment (getEnv)
import Control.Exception (SomeException, handle)
import qualified XMonad.StackSet as W

-- | Short for 'fromIntegral'.
fi :: (Integral a, Num b) => a -> b
fi :: a -> b
fi = a -> b
forall a b. (Integral a, Num b) => a -> b
fromIntegral

-- | Given a maximum length, splits a list into sublists
--
-- >>> chunksOf 5 (take 30 $ repeat 'a')
-- ["aaaaa","aaaaa","aaaaa","aaaaa","aaaaa","aaaaa"]
chunksOf :: Int -> [a] -> [[a]]
chunksOf :: Int -> [a] -> [[a]]
chunksOf Int
_ [] = []
chunksOf Int
i [a]
xs = [a]
chunk [a] -> [[a]] -> [[a]]
forall a. a -> [a] -> [a]
: Int -> [a] -> [[a]]
forall a. Int -> [a] -> [[a]]
chunksOf Int
i [a]
rest
  where !([a]
chunk, [a]
rest) = Int -> [a] -> ([a], [a])
forall a. Int -> [a] -> ([a], [a])
splitAt Int
i [a]
xs

-- | Safe version of '(!!)'.
(!?) :: [a] -> Int -> Maybe a
!? :: [a] -> Int -> Maybe a
(!?) [a]
xs Int
n | Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0 = Maybe a
forall a. Maybe a
Nothing
          | Bool
otherwise = [a] -> Maybe a
forall a. [a] -> Maybe a
listToMaybe ([a] -> Maybe a) -> [a] -> Maybe a
forall a b. (a -> b) -> a -> b
$ Int -> [a] -> [a]
forall a. Int -> [a] -> [a]
drop Int
n [a]
xs

-- | Multivariable composition.
--
-- > f .: g ≡ (f .) . g ≡ \c d -> f (g c d)
(.:) :: (a -> b) -> (c -> d -> a) -> c -> d -> b
.: :: (a -> b) -> (c -> d -> a) -> c -> d -> b
(.:) = ((d -> a) -> d -> b) -> (c -> d -> a) -> c -> d -> b
forall b c a. (b -> c) -> (a -> b) -> a -> c
(.) (((d -> a) -> d -> b) -> (c -> d -> a) -> c -> d -> b)
-> ((a -> b) -> (d -> a) -> d -> b)
-> (a -> b)
-> (c -> d -> a)
-> c
-> d
-> b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> b) -> (d -> a) -> d -> b
forall b c a. (b -> c) -> (a -> b) -> a -> c
(.)

-- | 'Data.List.NonEmpty.fromList' with a better error message. Useful to
-- silence GHC's Pattern match(es) are non-exhaustive warning in places where
-- the programmer knows it's always non-empty, but it's infeasible to express
-- that in the type system.
notEmpty :: HasCallStack => [a] -> NonEmpty a
notEmpty :: [a] -> NonEmpty a
notEmpty [] = [Char] -> NonEmpty a
forall a. HasCallStack => [Char] -> a
error [Char]
"unexpected empty list"
notEmpty (a
x:[a]
xs) = a
x a -> [a] -> NonEmpty a
forall a. a -> [a] -> NonEmpty a
:| [a]
xs

-- | A safe version of 'Graphics.X11.Extras.getWindowAttributes'.
safeGetWindowAttributes :: Window -> X (Maybe WindowAttributes)
safeGetWindowAttributes :: Window -> X (Maybe WindowAttributes)
safeGetWindowAttributes Window
w = (Display -> X (Maybe WindowAttributes))
-> X (Maybe WindowAttributes)
forall a. (Display -> X a) -> X a
withDisplay ((Display -> X (Maybe WindowAttributes))
 -> X (Maybe WindowAttributes))
-> (Display -> X (Maybe WindowAttributes))
-> X (Maybe WindowAttributes)
forall a b. (a -> b) -> a -> b
$ \Display
dpy -> IO (Maybe WindowAttributes) -> X (Maybe WindowAttributes)
forall (m :: * -> *) a. MonadIO m => IO a -> m a
io (IO (Maybe WindowAttributes) -> X (Maybe WindowAttributes))
-> ((Ptr WindowAttributes -> IO (Maybe WindowAttributes))
    -> IO (Maybe WindowAttributes))
-> (Ptr WindowAttributes -> IO (Maybe WindowAttributes))
-> X (Maybe WindowAttributes)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Ptr WindowAttributes -> IO (Maybe WindowAttributes))
-> IO (Maybe WindowAttributes)
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((Ptr WindowAttributes -> IO (Maybe WindowAttributes))
 -> X (Maybe WindowAttributes))
-> (Ptr WindowAttributes -> IO (Maybe WindowAttributes))
-> X (Maybe WindowAttributes)
forall a b. (a -> b) -> a -> b
$ \Ptr WindowAttributes
p ->
  Display -> Window -> Ptr WindowAttributes -> IO Status
xGetWindowAttributes Display
dpy Window
w Ptr WindowAttributes
p IO Status
-> (Status -> IO (Maybe WindowAttributes))
-> IO (Maybe WindowAttributes)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
    Status
0 -> Maybe WindowAttributes -> IO (Maybe WindowAttributes)
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe WindowAttributes
forall a. Maybe a
Nothing
    Status
_ -> WindowAttributes -> Maybe WindowAttributes
forall a. a -> Maybe a
Just (WindowAttributes -> Maybe WindowAttributes)
-> IO WindowAttributes -> IO (Maybe WindowAttributes)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Ptr WindowAttributes -> IO WindowAttributes
forall a. Storable a => Ptr a -> IO a
peek Ptr WindowAttributes
p

-- | (Naïvely) turn a relative path into an absolute one.
--
-- * If the path starts with @\/@, do nothing.
--
-- * If it starts with @~\/@, replace that with the actual home
-- * directory.
--
-- * If it starts with @$@, read the name of an environment
-- * variable and replace it with the contents of that.
--
-- * Otherwise, prepend the home directory and @\/@ to the path.
mkAbsolutePath :: MonadIO m => FilePath -> m FilePath
mkAbsolutePath :: [Char] -> m [Char]
mkAbsolutePath [Char]
ps = do
  [Char]
home <- IO [Char] -> m [Char]
forall (m :: * -> *) a. MonadIO m => IO a -> m a
io IO [Char]
getHomeDirectory
  case [Char]
ps of
    Char
'/'       : [Char]
_ -> [Char] -> m [Char]
forall (f :: * -> *) a. Applicative f => a -> f a
pure [Char]
ps
    Char
'~' : Char
'/' : [Char]
_ -> [Char] -> m [Char]
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([Char]
home [Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<> Int -> [Char] -> [Char]
forall a. Int -> [a] -> [a]
drop Int
1 [Char]
ps)
    Char
'$'       : [Char]
_ -> let ([Char]
v,[Char]
ps') = (Char -> Bool) -> [Char] -> ([Char], [Char])
forall a. (a -> Bool) -> [a] -> ([a], [a])
span (Char -> [Char] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` ([Char]
"_"[Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<>[Char
'A'..Char
'Z'][Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<>[Char
'a'..Char
'z'][Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<>[Char
'0'..Char
'9'])) (Int -> [Char] -> [Char]
forall a. Int -> [a] -> [a]
drop Int
1 [Char]
ps)
                      in IO [Char] -> m [Char]
forall (m :: * -> *) a. MonadIO m => IO a -> m a
io ((\(SomeException
_ :: SomeException) -> [Char] -> IO [Char]
forall (f :: * -> *) a. Applicative f => a -> f a
pure [Char]
"") (SomeException -> IO [Char]) -> IO [Char] -> IO [Char]
forall e a. Exception e => (e -> IO a) -> IO a -> IO a
`handle` [Char] -> IO [Char]
getEnv [Char]
v) m [Char] -> ([Char] -> [Char]) -> m [Char]
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
Exports.<&> ([Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<> [Char]
ps')
    [Char]
_             -> [Char] -> m [Char]
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([Char]
home [Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<> (Char
'/' Char -> [Char] -> [Char]
forall a. a -> [a] -> [a]
: [Char]
ps))
{-# SPECIALISE mkAbsolutePath :: FilePath -> IO FilePath #-}
{-# SPECIALISE mkAbsolutePath :: FilePath -> X  FilePath #-}

-----------------------------------------------------------------------
-- Keys

-- | Convert a modifier mask into a useful string.
keymaskToString :: KeyMask -- ^ Num lock mask
                -> KeyMask -- ^ Modifier mask
                -> String
keymaskToString :: KeyMask -> KeyMask -> [Char]
keymaskToString KeyMask
numLockMask KeyMask
msk =
  [[Char]] -> [Char]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([[Char]] -> [Char])
-> ([(KeyMask, [Char])] -> [[Char]])
-> [(KeyMask, [Char])]
-> [Char]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [[Char]] -> [[Char]]
forall a. [a] -> [a]
reverse ([[Char]] -> [[Char]])
-> ([(KeyMask, [Char])] -> [[Char]])
-> [(KeyMask, [Char])]
-> [[Char]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([[Char]], KeyMask) -> [[Char]]
forall a b. (a, b) -> a
fst (([[Char]], KeyMask) -> [[Char]])
-> ([(KeyMask, [Char])] -> ([[Char]], KeyMask))
-> [(KeyMask, [Char])]
-> [[Char]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((KeyMask, [Char]) -> ([[Char]], KeyMask) -> ([[Char]], KeyMask))
-> ([[Char]], KeyMask)
-> [(KeyMask, [Char])]
-> ([[Char]], KeyMask)
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr (KeyMask, [Char]) -> ([[Char]], KeyMask) -> ([[Char]], KeyMask)
go ([], KeyMask
msk) ([(KeyMask, [Char])] -> [Char]) -> [(KeyMask, [Char])] -> [Char]
forall a b. (a -> b) -> a -> b
$ [(KeyMask, [Char])]
masks
 where
  masks :: [(KeyMask, String)]
  masks :: [(KeyMask, [Char])]
masks = (KeyMask -> (KeyMask, [Char])) -> [KeyMask] -> [(KeyMask, [Char])]
forall a b. (a -> b) -> [a] -> [b]
map (\KeyMask
m -> (KeyMask
m, KeyMask -> [Char]
forall a. Show a => a -> [Char]
show KeyMask
m))
              [KeyMask
0 .. Int -> KeyMask
forall a. Enum a => Int -> a
toEnum (KeyMask -> Int
forall b. FiniteBits b => b -> Int
finiteBitSize KeyMask
msk Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1)]
       [(KeyMask, [Char])] -> [(KeyMask, [Char])] -> [(KeyMask, [Char])]
forall a. [a] -> [a] -> [a]
++ [ (KeyMask
numLockMask, [Char]
"num-" )
          , (KeyMask
lockMask,    [Char]
"lock-")
          , (KeyMask
controlMask, [Char]
"C-"   )
          , (KeyMask
shiftMask,   [Char]
"S-"   )
          , (KeyMask
mod5Mask,    [Char]
"M5-"  )
          , (KeyMask
mod4Mask,    [Char]
"M4-"  )
          , (KeyMask
mod3Mask,    [Char]
"M3-"  )
          , (KeyMask
mod2Mask,    [Char]
"M2-"  )
          , (KeyMask
mod1Mask,    [Char]
"M1-"  )
          ]

  go :: (KeyMask, String) -> ([String], KeyMask) -> ([String], KeyMask)
  go :: (KeyMask, [Char]) -> ([[Char]], KeyMask) -> ([[Char]], KeyMask)
go (KeyMask
m, [Char]
s) a :: ([[Char]], KeyMask)
a@([[Char]]
ss, KeyMask
v)
    | KeyMask
v KeyMask -> KeyMask -> Bool
forall a. Eq a => a -> a -> Bool
== KeyMask
0       = ([[Char]], KeyMask)
a
    | KeyMask
v KeyMask -> KeyMask -> KeyMask
forall a. Bits a => a -> a -> a
.&. KeyMask
m KeyMask -> KeyMask -> Bool
forall a. Eq a => a -> a -> Bool
== KeyMask
m = ([Char]
s [Char] -> [[Char]] -> [[Char]]
forall a. a -> [a] -> [a]
: [[Char]]
ss, KeyMask
v KeyMask -> KeyMask -> KeyMask
forall a. Bits a => a -> a -> a
.&. KeyMask -> KeyMask
forall a. Bits a => a -> a
complement KeyMask
m)
    | Bool
otherwise    = ([[Char]], KeyMask)
a

-- | Convert a full key combination; i.e., a 'KeyMask' and 'KeySym'
-- pair, into a string.
keyToString :: (KeyMask, KeySym) -> String
keyToString :: (KeyMask, Window) -> [Char]
keyToString = ([Char] -> [Char] -> [Char]) -> ([Char], [Char]) -> [Char]
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
(++) (([Char], [Char]) -> [Char])
-> ((KeyMask, Window) -> ([Char], [Char]))
-> (KeyMask, Window)
-> [Char]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (KeyMask -> [Char])
-> (Window -> [Char]) -> (KeyMask, Window) -> ([Char], [Char])
forall (p :: * -> * -> *) a b c d.
Bifunctor p =>
(a -> b) -> (c -> d) -> p a c -> p b d
bimap (KeyMask -> KeyMask -> [Char]
keymaskToString KeyMask
0) Window -> [Char]
ppKeysym
 where
  ppKeysym :: KeySym -> String
  ppKeysym :: Window -> [Char]
ppKeysym Window
x = case Map Window [Char]
specialMap Map Window [Char] -> Window -> Maybe [Char]
forall k a. Ord k => Map k a -> k -> Maybe a
Map.!? Window
x of
    Just [Char]
s  -> [Char]
"<" [Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<> [Char]
s [Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<> [Char]
">"
    Maybe [Char]
Nothing -> case Map Window [Char]
regularMap Map Window [Char] -> Window -> Maybe [Char]
forall k a. Ord k => Map k a -> k -> Maybe a
Map.!? Window
x of
      Maybe [Char]
Nothing -> Window -> [Char]
keysymToString Window
x
      Just [Char]
s  -> [Char]
s

  regularMap :: Map Window [Char]
regularMap = [(Window, [Char])] -> Map Window [Char]
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList ((([Char], Window) -> (Window, [Char]))
-> [([Char], Window)] -> [(Window, [Char])]
forall a b. (a -> b) -> [a] -> [b]
map ([Char], Window) -> (Window, [Char])
forall a b. (a, b) -> (b, a)
swap [([Char], Window)]
regularKeys)
  specialMap :: Map Window [Char]
specialMap = [(Window, [Char])] -> Map Window [Char]
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList ((([Char], Window) -> (Window, [Char]))
-> [([Char], Window)] -> [(Window, [Char])]
forall a b. (a -> b) -> [a] -> [b]
map ([Char], Window) -> (Window, [Char])
forall a b. (a, b) -> (b, a)
swap [([Char], Window)]
allSpecialKeys)

-- | Strip numlock, capslock, mouse buttons and XKB group from a 'KeyMask',
-- leaving only modifier keys like Shift, Control, Super, Hyper in the mask
-- (hence the \"Key\" in \"cleanKeyMask\").
--
-- Core's 'cleanMask' only strips the first two because key events from
-- passive grabs (key bindings) are stripped of mouse buttons and XKB group by
-- the X server already for compatibility reasons. For more info, see:
-- <https://www.x.org/releases/X11R7.7/doc/kbproto/xkbproto.html#Delivering_a_Key_or_Button_Event_to_a_Client>
cleanKeyMask :: X (KeyMask -> KeyMask)
cleanKeyMask :: X (KeyMask -> KeyMask)
cleanKeyMask = KeyMask -> KeyMask -> KeyMask
cleanKeyMask' (KeyMask -> KeyMask -> KeyMask)
-> X KeyMask -> X (KeyMask -> KeyMask)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (XState -> KeyMask) -> X KeyMask
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets XState -> KeyMask
numberlockMask

cleanKeyMask' :: KeyMask -> KeyMask -> KeyMask
cleanKeyMask' :: KeyMask -> KeyMask -> KeyMask
cleanKeyMask' KeyMask
numLockMask KeyMask
mask =
    KeyMask
mask KeyMask -> KeyMask -> KeyMask
forall a. Bits a => a -> a -> a
.&. KeyMask -> KeyMask
forall a. Bits a => a -> a
complement (KeyMask
numLockMask KeyMask -> KeyMask -> KeyMask
forall a. Bits a => a -> a -> a
.|. KeyMask
lockMask) KeyMask -> KeyMask -> KeyMask
forall a. Bits a => a -> a -> a
.&. (KeyMask
button1Mask KeyMask -> KeyMask -> KeyMask
forall a. Num a => a -> a -> a
- KeyMask
1)

-- | A list of "regular" (extended ASCII) keys.
regularKeys :: [(String, KeySym)]
regularKeys :: [([Char], Window)]
regularKeys = ((Char, Window) -> ([Char], Window))
-> [(Char, Window)] -> [([Char], Window)]
forall a b. (a -> b) -> [a] -> [b]
map ((Char -> [Char]) -> (Char, Window) -> ([Char], Window)
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (b, d) (c, d)
first (Char -> [Char] -> [Char]
forall a. a -> [a] -> [a]
:[]))
            ([(Char, Window)] -> [([Char], Window)])
-> [(Char, Window)] -> [([Char], Window)]
forall a b. (a -> b) -> a -> b
$ [Char] -> [Window] -> [(Char, Window)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Char
'!'             .. Char
'~'          ] -- ASCII
                  [Window
xK_exclam       .. Window
xK_asciitilde]
           [(Char, Window)] -> [(Char, Window)] -> [(Char, Window)]
forall a. Semigroup a => a -> a -> a
<> [Char] -> [Window] -> [(Char, Window)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Char
'\xa0'          .. Char
'\xff'       ] -- Latin1
                  [Window
xK_nobreakspace .. Window
xK_ydiaeresis]

-- | A list of all special key names and their associated KeySyms.
allSpecialKeys :: [(String, KeySym)]
allSpecialKeys :: [([Char], Window)]
allSpecialKeys = [([Char], Window)]
functionKeys [([Char], Window)] -> [([Char], Window)] -> [([Char], Window)]
forall a. Semigroup a => a -> a -> a
<> [([Char], Window)]
specialKeys [([Char], Window)] -> [([Char], Window)] -> [([Char], Window)]
forall a. Semigroup a => a -> a -> a
<> [([Char], Window)]
multimediaKeys

-- | A list pairing function key descriptor strings (e.g. @\"<F2>\"@)
-- with the associated KeySyms.
functionKeys :: [(String, KeySym)]
functionKeys :: [([Char], Window)]
functionKeys = [ (Char
'F' Char -> [Char] -> [Char]
forall a. a -> [a] -> [a]
: Int -> [Char]
forall a. Show a => a -> [Char]
show Int
n, Window
k)
               | (Int
n,Window
k) <- [Int] -> [Window] -> [(Int, Window)]
forall a b. [a] -> [b] -> [(a, b)]
zip ([Int
1..Int
24] :: [Int]) [Window
xK_F1..]
               ]

-- | A list of special key names and their corresponding KeySyms.
specialKeys :: [(String, KeySym)]
specialKeys :: [([Char], Window)]
specialKeys =
  [ ([Char]
"Backspace"  , Window
xK_BackSpace)
  , ([Char]
"Tab"        , Window
xK_Tab)
  , ([Char]
"Return"     , Window
xK_Return)
  , ([Char]
"Pause"      , Window
xK_Pause)
  , ([Char]
"Num_Lock"   , Window
xK_Num_Lock)
  , ([Char]
"Caps_Lock"  , Window
xK_Caps_Lock)
  , ([Char]
"Scroll_lock", Window
xK_Scroll_Lock)
  , ([Char]
"Sys_Req"    , Window
xK_Sys_Req)
  , ([Char]
"Print"      , Window
xK_Print)
  , ([Char]
"Escape"     , Window
xK_Escape)
  , ([Char]
"Esc"        , Window
xK_Escape)
  , ([Char]
"Delete"     , Window
xK_Delete)
  , ([Char]
"Home"       , Window
xK_Home)
  , ([Char]
"Left"       , Window
xK_Left)
  , ([Char]
"Up"         , Window
xK_Up)
  , ([Char]
"Right"      , Window
xK_Right)
  , ([Char]
"Down"       , Window
xK_Down)
  , ([Char]
"L"          , Window
xK_Left)
  , ([Char]
"U"          , Window
xK_Up)
  , ([Char]
"R"          , Window
xK_Right)
  , ([Char]
"D"          , Window
xK_Down)
  , ([Char]
"Page_Up"    , Window
xK_Page_Up)
  , ([Char]
"Page_Down"  , Window
xK_Page_Down)
  , ([Char]
"End"        , Window
xK_End)
  , ([Char]
"Insert"     , Window
xK_Insert)
  , ([Char]
"Break"      , Window
xK_Break)
  , ([Char]
"Space"      , Window
xK_space)
  , ([Char]
"Control_L"  , Window
xK_Control_L)
  , ([Char]
"Control_R"  , Window
xK_Control_R)
  , ([Char]
"Shift_L"    , Window
xK_Shift_L)
  , ([Char]
"Shift_R"    , Window
xK_Shift_R)
  , ([Char]
"Alt_L"      , Window
xK_Alt_L)
  , ([Char]
"Alt_R"      , Window
xK_Alt_R)
  , ([Char]
"Meta_L"     , Window
xK_Meta_L)
  , ([Char]
"Meta_R"     , Window
xK_Meta_R)
  , ([Char]
"Super_L"    , Window
xK_Super_L)
  , ([Char]
"Super_R"    , Window
xK_Super_R)
  , ([Char]
"Hyper_L"    , Window
xK_Hyper_L)
  , ([Char]
"Hyper_R"    , Window
xK_Hyper_R)
  , ([Char]
"KP_Space"   , Window
xK_KP_Space)
  , ([Char]
"KP_Tab"     , Window
xK_KP_Tab)
  , ([Char]
"KP_Enter"   , Window
xK_KP_Enter)
  , ([Char]
"KP_F1"      , Window
xK_KP_F1)
  , ([Char]
"KP_F2"      , Window
xK_KP_F2)
  , ([Char]
"KP_F3"      , Window
xK_KP_F3)
  , ([Char]
"KP_F4"      , Window
xK_KP_F4)
  , ([Char]
"KP_Home"    , Window
xK_KP_Home)
  , ([Char]
"KP_Left"    , Window
xK_KP_Left)
  , ([Char]
"KP_Up"      , Window
xK_KP_Up)
  , ([Char]
"KP_Right"   , Window
xK_KP_Right)
  , ([Char]
"KP_Down"    , Window
xK_KP_Down)
  , ([Char]
"KP_Prior"   , Window
xK_KP_Prior)
  , ([Char]
"KP_Page_Up" , Window
xK_KP_Page_Up)
  , ([Char]
"KP_Next"    , Window
xK_KP_Next)
  , ([Char]
"KP_Page_Down", Window
xK_KP_Page_Down)
  , ([Char]
"KP_End"     , Window
xK_KP_End)
  , ([Char]
"KP_Begin"   , Window
xK_KP_Begin)
  , ([Char]
"KP_Insert"  , Window
xK_KP_Insert)
  , ([Char]
"KP_Delete"  , Window
xK_KP_Delete)
  , ([Char]
"KP_Equal"   , Window
xK_KP_Equal)
  , ([Char]
"KP_Multiply", Window
xK_KP_Multiply)
  , ([Char]
"KP_Add"     , Window
xK_KP_Add)
  , ([Char]
"KP_Separator", Window
xK_KP_Separator)
  , ([Char]
"KP_Subtract", Window
xK_KP_Subtract)
  , ([Char]
"KP_Decimal" , Window
xK_KP_Decimal)
  , ([Char]
"KP_Divide"  , Window
xK_KP_Divide)
  , ([Char]
"KP_0"       , Window
xK_KP_0)
  , ([Char]
"KP_1"       , Window
xK_KP_1)
  , ([Char]
"KP_2"       , Window
xK_KP_2)
  , ([Char]
"KP_3"       , Window
xK_KP_3)
  , ([Char]
"KP_4"       , Window
xK_KP_4)
  , ([Char]
"KP_5"       , Window
xK_KP_5)
  , ([Char]
"KP_6"       , Window
xK_KP_6)
  , ([Char]
"KP_7"       , Window
xK_KP_7)
  , ([Char]
"KP_8"       , Window
xK_KP_8)
  , ([Char]
"KP_9"       , Window
xK_KP_9)
  ]

-- | List of multimedia keys. If Xlib does not know about some keysym
-- it's omitted from the list ('stringToKeysym' returns 'noSymbol' in
-- this case).
multimediaKeys :: [(String, KeySym)]
multimediaKeys :: [([Char], Window)]
multimediaKeys = (([Char], Window) -> Bool)
-> [([Char], Window)] -> [([Char], Window)]
forall a. (a -> Bool) -> [a] -> [a]
filter ((Window -> Window -> Bool
forall a. Eq a => a -> a -> Bool
/= Window
noSymbol) (Window -> Bool)
-> (([Char], Window) -> Window) -> ([Char], Window) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Char], Window) -> Window
forall a b. (a, b) -> b
snd) ([([Char], Window)] -> [([Char], Window)])
-> ([[Char]] -> [([Char], Window)])
-> [[Char]]
-> [([Char], Window)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Char] -> ([Char], Window)) -> [[Char]] -> [([Char], Window)]
forall a b. (a -> b) -> [a] -> [b]
map ([Char] -> [Char]
forall a. a -> a
id ([Char] -> [Char])
-> ([Char] -> Window) -> [Char] -> ([Char], Window)
forall (a :: * -> * -> *) b c c'.
Arrow a =>
a b c -> a b c' -> a b (c, c')
&&& [Char] -> Window
stringToKeysym) ([[Char]] -> [([Char], Window)]) -> [[Char]] -> [([Char], Window)]
forall a b. (a -> b) -> a -> b
$
  [ [Char]
"XF86ModeLock"
  , [Char]
"XF86MonBrightnessUp"
  , [Char]
"XF86MonBrightnessDown"
  , [Char]
"XF86KbdLightOnOff"
  , [Char]
"XF86KbdBrightnessUp"
  , [Char]
"XF86KbdBrightnessDown"
  , [Char]
"XF86Standby"
  , [Char]
"XF86AudioLowerVolume"
  , [Char]
"XF86AudioMute"
  , [Char]
"XF86AudioRaiseVolume"
  , [Char]
"XF86AudioPlay"
  , [Char]
"XF86AudioStop"
  , [Char]
"XF86AudioPrev"
  , [Char]
"XF86AudioNext"
  , [Char]
"XF86HomePage"
  , [Char]
"XF86Mail"
  , [Char]
"XF86Start"
  , [Char]
"XF86Search"
  , [Char]
"XF86AudioRecord"
  , [Char]
"XF86Calculator"
  , [Char]
"XF86Memo"
  , [Char]
"XF86ToDoList"
  , [Char]
"XF86Calendar"
  , [Char]
"XF86PowerDown"
  , [Char]
"XF86ContrastAdjust"
  , [Char]
"XF86RockerUp"
  , [Char]
"XF86RockerDown"
  , [Char]
"XF86RockerEnter"
  , [Char]
"XF86Back"
  , [Char]
"XF86Forward"
  , [Char]
"XF86Stop"
  , [Char]
"XF86Refresh"
  , [Char]
"XF86PowerOff"
  , [Char]
"XF86WakeUp"
  , [Char]
"XF86Eject"
  , [Char]
"XF86ScreenSaver"
  , [Char]
"XF86WWW"
  , [Char]
"XF86Sleep"
  , [Char]
"XF86Favorites"
  , [Char]
"XF86AudioPause"
  , [Char]
"XF86AudioMedia"
  , [Char]
"XF86MyComputer"
  , [Char]
"XF86VendorHome"
  , [Char]
"XF86LightBulb"
  , [Char]
"XF86Shop"
  , [Char]
"XF86History"
  , [Char]
"XF86OpenURL"
  , [Char]
"XF86AddFavorite"
  , [Char]
"XF86HotLinks"
  , [Char]
"XF86BrightnessAdjust"
  , [Char]
"XF86Finance"
  , [Char]
"XF86Community"
  , [Char]
"XF86AudioRewind"
  , [Char]
"XF86BackForward"
  , [Char]
"XF86Launch0"
  , [Char]
"XF86Launch1"
  , [Char]
"XF86Launch2"
  , [Char]
"XF86Launch3"
  , [Char]
"XF86Launch4"
  , [Char]
"XF86Launch5"
  , [Char]
"XF86Launch6"
  , [Char]
"XF86Launch7"
  , [Char]
"XF86Launch8"
  , [Char]
"XF86Launch9"
  , [Char]
"XF86LaunchA"
  , [Char]
"XF86LaunchB"
  , [Char]
"XF86LaunchC"
  , [Char]
"XF86LaunchD"
  , [Char]
"XF86LaunchE"
  , [Char]
"XF86LaunchF"
  , [Char]
"XF86ApplicationLeft"
  , [Char]
"XF86ApplicationRight"
  , [Char]
"XF86Book"
  , [Char]
"XF86CD"
  , [Char]
"XF86Calculater"
  , [Char]
"XF86Clear"
  , [Char]
"XF86Close"
  , [Char]
"XF86Copy"
  , [Char]
"XF86Cut"
  , [Char]
"XF86Display"
  , [Char]
"XF86DOS"
  , [Char]
"XF86Documents"
  , [Char]
"XF86Excel"
  , [Char]
"XF86Explorer"
  , [Char]
"XF86Game"
  , [Char]
"XF86Go"
  , [Char]
"XF86iTouch"
  , [Char]
"XF86LogOff"
  , [Char]
"XF86Market"
  , [Char]
"XF86Meeting"
  , [Char]
"XF86MenuKB"
  , [Char]
"XF86MenuPB"
  , [Char]
"XF86MySites"
  , [Char]
"XF86New"
  , [Char]
"XF86News"
  , [Char]
"XF86OfficeHome"
  , [Char]
"XF86Open"
  , [Char]
"XF86Option"
  , [Char]
"XF86Paste"
  , [Char]
"XF86Phone"
  , [Char]
"XF86Q"
  , [Char]
"XF86Reply"
  , [Char]
"XF86Reload"
  , [Char]
"XF86RotateWindows"
  , [Char]
"XF86RotationPB"
  , [Char]
"XF86RotationKB"
  , [Char]
"XF86Save"
  , [Char]
"XF86ScrollUp"
  , [Char]
"XF86ScrollDown"
  , [Char]
"XF86ScrollClick"
  , [Char]
"XF86Send"
  , [Char]
"XF86Spell"
  , [Char]
"XF86SplitScreen"
  , [Char]
"XF86Support"
  , [Char]
"XF86TaskPane"
  , [Char]
"XF86Terminal"
  , [Char]
"XF86Tools"
  , [Char]
"XF86Travel"
  , [Char]
"XF86UserPB"
  , [Char]
"XF86User1KB"
  , [Char]
"XF86User2KB"
  , [Char]
"XF86Video"
  , [Char]
"XF86WheelButton"
  , [Char]
"XF86Word"
  , [Char]
"XF86Xfer"
  , [Char]
"XF86ZoomIn"
  , [Char]
"XF86ZoomOut"
  , [Char]
"XF86Away"
  , [Char]
"XF86Messenger"
  , [Char]
"XF86WebCam"
  , [Char]
"XF86MailForward"
  , [Char]
"XF86Pictures"
  , [Char]
"XF86Music"
  , [Char]
"XF86TouchpadToggle"
  , [Char]
"XF86AudioMicMute"
  , [Char]
"XF86_Switch_VT_1"
  , [Char]
"XF86_Switch_VT_2"
  , [Char]
"XF86_Switch_VT_3"
  , [Char]
"XF86_Switch_VT_4"
  , [Char]
"XF86_Switch_VT_5"
  , [Char]
"XF86_Switch_VT_6"
  , [Char]
"XF86_Switch_VT_7"
  , [Char]
"XF86_Switch_VT_8"
  , [Char]
"XF86_Switch_VT_9"
  , [Char]
"XF86_Switch_VT_10"
  , [Char]
"XF86_Switch_VT_11"
  , [Char]
"XF86_Switch_VT_12"
  , [Char]
"XF86_Ungrab"
  , [Char]
"XF86_ClearGrab"
  , [Char]
"XF86_Next_VMode"
  , [Char]
"XF86_Prev_VMode"
  , [Char]
"XF86Bluetooth"
  ]

-- | The specialized 'W.Screen' derived from 'WindowSet'.
type WindowScreen -- FIXME move to core
    = W.Screen WorkspaceId (Layout Window) Window ScreenId ScreenDetail