-----------------------------------------------------------------------------
-- |
-- Module       : XMonad.Hooks.EwmhDesktops
-- Copyright    : (c) 2007, 2008 Joachim Breitner <mail@joachim-breitner.de>
-- License      : BSD
--
-- Maintainer   : Joachim Breitner <mail@joachim-breitner.de>
-- Stability    : unstable
-- Portability  : unportable
--
-- Makes xmonad use the EWMH hints to tell panel applications about its
-- workspaces and the windows therein. It also allows the user to interact
-- with xmonad by clicking on panels and window lists.
-----------------------------------------------------------------------------
module XMonad.Hooks.EwmhDesktops (
    -- * Usage
    -- $usage
    ewmh,
    ewmhDesktopsStartup,
    ewmhDesktopsLogHook,
    ewmhDesktopsLogHookCustom,
    ewmhDesktopsEventHook,
    ewmhDesktopsEventHookCustom,
    fullscreenEventHook
    ) where

import Codec.Binary.UTF8.String (encode)
import Control.Applicative((<$>))
import Data.List
import Data.Maybe
import Data.Monoid
import qualified Data.Map.Strict as M
import System.IO.Unsafe

import XMonad
import Control.Monad
import qualified XMonad.StackSet as W

import XMonad.Hooks.SetWMName
import qualified XMonad.Util.ExtensibleState as E
import XMonad.Util.XUtils (fi)
import XMonad.Util.WorkspaceCompare
import XMonad.Util.WindowProperties (getProp32)

-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
--
-- > import XMonad
-- > import XMonad.Hooks.EwmhDesktops
-- >
-- > main = xmonad $ ewmh def{ handleEventHook =
-- >            handleEventHook def <+> fullscreenEventHook }
--
-- You may also be interested in 'docks' from "XMonad.Hooks.ManageDocks".


-- | Add EWMH functionality to the given config.  See above for an example.
ewmh :: XConfig a -> XConfig a
ewmh :: XConfig a -> XConfig a
ewmh XConfig a
c = XConfig a
c { startupHook :: X ()
startupHook     = XConfig a -> X ()
forall (l :: * -> *). XConfig l -> X ()
startupHook XConfig a
c X () -> X () -> X ()
forall a. Monoid a => a -> a -> a
+++ X ()
ewmhDesktopsStartup
           , handleEventHook :: Event -> X All
handleEventHook = XConfig a -> Event -> X All
forall (l :: * -> *). XConfig l -> Event -> X All
handleEventHook XConfig a
c (Event -> X All) -> (Event -> X All) -> Event -> X All
forall a. Monoid a => a -> a -> a
+++ Event -> X All
ewmhDesktopsEventHook
           , logHook :: X ()
logHook         = XConfig a -> X ()
forall (l :: * -> *). XConfig l -> X ()
logHook XConfig a
c X () -> X () -> X ()
forall a. Monoid a => a -> a -> a
+++ X ()
ewmhDesktopsLogHook }
 -- @@@ will fix this correctly later with the rewrite
 where a
x +++ :: a -> a -> a
+++ a
y = a -> a -> a
forall a. Monoid a => a -> a -> a
mappend a
y a
x

-- |
-- Initializes EwmhDesktops and advertises EWMH support to the X
-- server
ewmhDesktopsStartup :: X ()
ewmhDesktopsStartup :: X ()
ewmhDesktopsStartup = X ()
setSupported

-- |
-- Notifies pagers and window lists, such as those in the gnome-panel
-- of the current state of workspaces and windows.
ewmhDesktopsLogHook :: X ()
ewmhDesktopsLogHook :: X ()
ewmhDesktopsLogHook = ([WindowSpace] -> [WindowSpace]) -> X ()
ewmhDesktopsLogHookCustom [WindowSpace] -> [WindowSpace]
forall a. a -> a
id

-- |
-- Cached desktop names (e.g. @_NET_NUMBER_OF_DESKTOPS@ and
-- @_NET_DESKTOP_NAMES@).
newtype DesktopNames = DesktopNames [String]
                     deriving (DesktopNames -> DesktopNames -> Bool
(DesktopNames -> DesktopNames -> Bool)
-> (DesktopNames -> DesktopNames -> Bool) -> Eq DesktopNames
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: DesktopNames -> DesktopNames -> Bool
$c/= :: DesktopNames -> DesktopNames -> Bool
== :: DesktopNames -> DesktopNames -> Bool
$c== :: DesktopNames -> DesktopNames -> Bool
Eq)

instance ExtensionClass DesktopNames where
    initialValue :: DesktopNames
initialValue = [String] -> DesktopNames
DesktopNames []

-- |
-- Cached client list (e.g. @_NET_CLIENT_LIST@).
newtype ClientList = ClientList [Window]
                   deriving (ClientList -> ClientList -> Bool
(ClientList -> ClientList -> Bool)
-> (ClientList -> ClientList -> Bool) -> Eq ClientList
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ClientList -> ClientList -> Bool
$c/= :: ClientList -> ClientList -> Bool
== :: ClientList -> ClientList -> Bool
$c== :: ClientList -> ClientList -> Bool
Eq)

instance ExtensionClass ClientList where
    initialValue :: ClientList
initialValue = [Window] -> ClientList
ClientList []

-- |
-- Cached current desktop (e.g. @_NET_CURRENT_DESKTOP@).
newtype CurrentDesktop = CurrentDesktop Int
                       deriving (CurrentDesktop -> CurrentDesktop -> Bool
(CurrentDesktop -> CurrentDesktop -> Bool)
-> (CurrentDesktop -> CurrentDesktop -> Bool) -> Eq CurrentDesktop
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: CurrentDesktop -> CurrentDesktop -> Bool
$c/= :: CurrentDesktop -> CurrentDesktop -> Bool
== :: CurrentDesktop -> CurrentDesktop -> Bool
$c== :: CurrentDesktop -> CurrentDesktop -> Bool
Eq)

instance ExtensionClass CurrentDesktop where
    initialValue :: CurrentDesktop
initialValue = Int -> CurrentDesktop
CurrentDesktop Int
0

-- |
-- Cached window-desktop assignments (e.g. @_NET_CLIENT_LIST_STACKING@).
newtype WindowDesktops = WindowDesktops (M.Map Window Int)
                       deriving (WindowDesktops -> WindowDesktops -> Bool
(WindowDesktops -> WindowDesktops -> Bool)
-> (WindowDesktops -> WindowDesktops -> Bool) -> Eq WindowDesktops
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: WindowDesktops -> WindowDesktops -> Bool
$c/= :: WindowDesktops -> WindowDesktops -> Bool
== :: WindowDesktops -> WindowDesktops -> Bool
$c== :: WindowDesktops -> WindowDesktops -> Bool
Eq)

instance ExtensionClass WindowDesktops where
    initialValue :: WindowDesktops
initialValue = Map Window Int -> WindowDesktops
WindowDesktops Map Window Int
forall k a. Map k a
M.empty

-- |
-- The value of @_NET_ACTIVE_WINDOW@, cached to avoid unnecessary property
-- updates.
newtype ActiveWindow = ActiveWindow Window
                     deriving (ActiveWindow -> ActiveWindow -> Bool
(ActiveWindow -> ActiveWindow -> Bool)
-> (ActiveWindow -> ActiveWindow -> Bool) -> Eq ActiveWindow
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ActiveWindow -> ActiveWindow -> Bool
$c/= :: ActiveWindow -> ActiveWindow -> Bool
== :: ActiveWindow -> ActiveWindow -> Bool
$c== :: ActiveWindow -> ActiveWindow -> Bool
Eq)

instance ExtensionClass ActiveWindow where
    initialValue :: ActiveWindow
initialValue = Window -> ActiveWindow
ActiveWindow Window
none

-- | Compare the given value against the value in the extensible state. Run the
-- action if it has changed.
whenChanged :: (Eq a, ExtensionClass a) => a -> X () -> X ()
whenChanged :: a -> X () -> X ()
whenChanged a
v X ()
action = do
    a
v0 <- X a
forall a (m :: * -> *). (ExtensionClass a, XLike m) => m a
E.get
    Bool -> X () -> X ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (a
v a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
v0) (X () -> X ()) -> X () -> X ()
forall a b. (a -> b) -> a -> b
$ do
        X ()
action
        a -> X ()
forall a (m :: * -> *). (ExtensionClass a, XLike m) => a -> m ()
E.put a
v

-- |
-- Generalized version of ewmhDesktopsLogHook that allows an arbitrary
-- user-specified function to transform the workspace list (post-sorting)
ewmhDesktopsLogHookCustom :: ([WindowSpace] -> [WindowSpace]) -> X ()
ewmhDesktopsLogHookCustom :: ([WindowSpace] -> [WindowSpace]) -> X ()
ewmhDesktopsLogHookCustom [WindowSpace] -> [WindowSpace]
f = (WindowSet -> X ()) -> X ()
forall a. (WindowSet -> X a) -> X a
withWindowSet ((WindowSet -> X ()) -> X ()) -> (WindowSet -> X ()) -> X ()
forall a b. (a -> b) -> a -> b
$ \WindowSet
s -> do
    [WindowSpace] -> [WindowSpace]
sort' <- X ([WindowSpace] -> [WindowSpace])
getSortByIndex
    let ws :: [WindowSpace]
ws = [WindowSpace] -> [WindowSpace]
f ([WindowSpace] -> [WindowSpace]) -> [WindowSpace] -> [WindowSpace]
forall a b. (a -> b) -> a -> b
$ [WindowSpace] -> [WindowSpace]
sort' ([WindowSpace] -> [WindowSpace]) -> [WindowSpace] -> [WindowSpace]
forall a b. (a -> b) -> a -> b
$ WindowSet -> [WindowSpace]
forall i l a s sd. StackSet i l a s sd -> [Workspace i l a]
W.workspaces WindowSet
s

    -- Set number of workspaces and names thereof
    let desktopNames :: [String]
desktopNames = (WindowSpace -> String) -> [WindowSpace] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map WindowSpace -> String
forall i l a. Workspace i l a -> i
W.tag [WindowSpace]
ws
    DesktopNames -> X () -> X ()
forall a. (Eq a, ExtensionClass a) => a -> X () -> X ()
whenChanged ([String] -> DesktopNames
DesktopNames [String]
desktopNames) (X () -> X ()) -> X () -> X ()
forall a b. (a -> b) -> a -> b
$ do
        Int -> X ()
forall a. Integral a => a -> X ()
setNumberOfDesktops ([String] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [String]
desktopNames)
        [String] -> X ()
setDesktopNames [String]
desktopNames

    -- Set client list; all windows, with focused windows last
    let clientList :: [Window]
clientList = [Window] -> [Window]
forall a. Eq a => [a] -> [a]
nub ([Window] -> [Window])
-> ([WindowSpace] -> [Window]) -> [WindowSpace] -> [Window]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (WindowSpace -> [Window]) -> [WindowSpace] -> [Window]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap ([Window]
-> (Stack Window -> [Window]) -> Maybe (Stack Window) -> [Window]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [] (\(W.Stack Window
x [Window]
l [Window]
r) -> [Window] -> [Window]
forall a. [a] -> [a]
reverse [Window]
l [Window] -> [Window] -> [Window]
forall a. [a] -> [a] -> [a]
++ [Window]
r [Window] -> [Window] -> [Window]
forall a. [a] -> [a] -> [a]
++ [Window
x]) (Maybe (Stack Window) -> [Window])
-> (WindowSpace -> Maybe (Stack Window)) -> WindowSpace -> [Window]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. WindowSpace -> Maybe (Stack Window)
forall i l a. Workspace i l a -> Maybe (Stack a)
W.stack) ([WindowSpace] -> [Window]) -> [WindowSpace] -> [Window]
forall a b. (a -> b) -> a -> b
$ [WindowSpace]
ws
    ClientList -> X () -> X ()
forall a. (Eq a, ExtensionClass a) => a -> X () -> X ()
whenChanged ([Window] -> ClientList
ClientList [Window]
clientList) (X () -> X ()) -> X () -> X ()
forall a b. (a -> b) -> a -> b
$ [Window] -> X ()
setClientList [Window]
clientList

    -- Remap the current workspace to handle any renames that f might be doing.
    let maybeCurrent' :: Maybe String
maybeCurrent' = WindowSpace -> String
forall i l a. Workspace i l a -> i
W.tag (WindowSpace -> String) -> Maybe WindowSpace -> Maybe String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [WindowSpace] -> Maybe WindowSpace
forall a. [a] -> Maybe a
listToMaybe ([WindowSpace] -> [WindowSpace]
f [Screen String (Layout Window) Window ScreenId ScreenDetail
-> WindowSpace
forall i l a sid sd. Screen i l a sid sd -> Workspace i l a
W.workspace (Screen String (Layout Window) Window ScreenId ScreenDetail
 -> WindowSpace)
-> Screen String (Layout Window) Window ScreenId ScreenDetail
-> WindowSpace
forall a b. (a -> b) -> a -> b
$ WindowSet
-> Screen String (Layout Window) Window ScreenId ScreenDetail
forall i l a sid sd. StackSet i l a sid sd -> Screen i l a sid sd
W.current WindowSet
s])
        current :: Maybe Int
current = Maybe (Maybe Int) -> Maybe Int
forall (m :: * -> *) a. Monad m => m (m a) -> m a
join ((String -> [String] -> Maybe Int)
-> [String] -> String -> Maybe Int
forall a b c. (a -> b -> c) -> b -> a -> c
flip String -> [String] -> Maybe Int
forall a. Eq a => a -> [a] -> Maybe Int
elemIndex ((WindowSpace -> String) -> [WindowSpace] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map WindowSpace -> String
forall i l a. Workspace i l a -> i
W.tag [WindowSpace]
ws) (String -> Maybe Int) -> Maybe String -> Maybe (Maybe Int)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe String
maybeCurrent')
    CurrentDesktop -> X () -> X ()
forall a. (Eq a, ExtensionClass a) => a -> X () -> X ()
whenChanged (Int -> CurrentDesktop
CurrentDesktop (Int -> CurrentDesktop) -> Int -> CurrentDesktop
forall a b. (a -> b) -> a -> b
$ Int -> Maybe Int -> Int
forall a. a -> Maybe a -> a
fromMaybe Int
0 Maybe Int
current) (X () -> X ()) -> X () -> X ()
forall a b. (a -> b) -> a -> b
$ do
        (Int -> X ()) -> Maybe Int -> X ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ Int -> X ()
forall a. Integral a => a -> X ()
setCurrentDesktop Maybe Int
current

    -- Set window-desktop mapping
    let windowDesktops :: Map Window Int
windowDesktops =
          let f :: a -> Workspace i l k -> Map k a
f a
wsId Workspace i l k
workspace = [(k, a)] -> Map k a
forall k a. Ord k => [(k, a)] -> Map k a
M.fromList [ (k
winId, a
wsId) | k
winId <- Maybe (Stack k) -> [k]
forall a. Maybe (Stack a) -> [a]
W.integrate' (Maybe (Stack k) -> [k]) -> Maybe (Stack k) -> [k]
forall a b. (a -> b) -> a -> b
$ Workspace i l k -> Maybe (Stack k)
forall i l a. Workspace i l a -> Maybe (Stack a)
W.stack Workspace i l k
workspace ]
          in [Map Window Int] -> Map Window Int
forall (f :: * -> *) k a.
(Foldable f, Ord k) =>
f (Map k a) -> Map k a
M.unions ([Map Window Int] -> Map Window Int)
-> [Map Window Int] -> Map Window Int
forall a b. (a -> b) -> a -> b
$ (Int -> WindowSpace -> Map Window Int)
-> [Int] -> [WindowSpace] -> [Map Window Int]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith Int -> WindowSpace -> Map Window Int
forall k a i l. Ord k => a -> Workspace i l k -> Map k a
f [Int
0..] [WindowSpace]
ws
    WindowDesktops -> X () -> X ()
forall a. (Eq a, ExtensionClass a) => a -> X () -> X ()
whenChanged (Map Window Int -> WindowDesktops
WindowDesktops Map Window Int
windowDesktops) (X () -> X ()) -> X () -> X ()
forall a b. (a -> b) -> a -> b
$ do
        ((Window, Int) -> X ()) -> [(Window, Int)] -> X ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ ((Window -> Int -> X ()) -> (Window, Int) -> X ()
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry Window -> Int -> X ()
forall a. Integral a => Window -> a -> X ()
setWindowDesktop) (Map Window Int -> [(Window, Int)]
forall k a. Map k a -> [(k, a)]
M.toList Map Window Int
windowDesktops)

    -- Set active window
    let activeWindow' :: Window
activeWindow' = Window -> Maybe Window -> Window
forall a. a -> Maybe a -> a
fromMaybe Window
none (WindowSet -> Maybe Window
forall i l a s sd. StackSet i l a s sd -> Maybe a
W.peek WindowSet
s)
    ActiveWindow -> X () -> X ()
forall a. (Eq a, ExtensionClass a) => a -> X () -> X ()
whenChanged (Window -> ActiveWindow
ActiveWindow Window
activeWindow') (X () -> X ()) -> X () -> X ()
forall a b. (a -> b) -> a -> b
$ Window -> X ()
setActiveWindow Window
activeWindow'

-- |
-- Intercepts messages from pagers and similar applications and reacts on them.
-- Currently supports:
--
--  * _NET_CURRENT_DESKTOP (switching desktops)
--
--  * _NET_WM_DESKTOP (move windows to other desktops)
--
--  * _NET_ACTIVE_WINDOW (activate another window, changing workspace if needed)
ewmhDesktopsEventHook :: Event -> X All
ewmhDesktopsEventHook :: Event -> X All
ewmhDesktopsEventHook = ([WindowSpace] -> [WindowSpace]) -> Event -> X All
ewmhDesktopsEventHookCustom [WindowSpace] -> [WindowSpace]
forall a. a -> a
id

-- |
-- Generalized version of ewmhDesktopsEventHook that allows an arbitrary
-- user-specified function to transform the workspace list (post-sorting)
ewmhDesktopsEventHookCustom :: ([WindowSpace] -> [WindowSpace]) -> Event -> X All
ewmhDesktopsEventHookCustom :: ([WindowSpace] -> [WindowSpace]) -> Event -> X All
ewmhDesktopsEventHookCustom [WindowSpace] -> [WindowSpace]
f Event
e = ([WindowSpace] -> [WindowSpace]) -> Event -> X ()
handle [WindowSpace] -> [WindowSpace]
f Event
e X () -> X All -> X All
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> All -> X All
forall (m :: * -> *) a. Monad m => a -> m a
return (Bool -> All
All Bool
True)

handle :: ([WindowSpace] -> [WindowSpace]) -> Event -> X ()
handle :: ([WindowSpace] -> [WindowSpace]) -> Event -> X ()
handle [WindowSpace] -> [WindowSpace]
f (ClientMessageEvent {
               ev_window :: Event -> Window
ev_window = Window
w,
               ev_message_type :: Event -> Window
ev_message_type = Window
mt,
               ev_data :: Event -> [CInt]
ev_data = [CInt]
d
       }) = (WindowSet -> X ()) -> X ()
forall a. (WindowSet -> X a) -> X a
withWindowSet ((WindowSet -> X ()) -> X ()) -> (WindowSet -> X ()) -> X ()
forall a b. (a -> b) -> a -> b
$ \WindowSet
s -> do
       [WindowSpace] -> [WindowSpace]
sort' <- X ([WindowSpace] -> [WindowSpace])
getSortByIndex
       let ws :: [WindowSpace]
ws = [WindowSpace] -> [WindowSpace]
f ([WindowSpace] -> [WindowSpace]) -> [WindowSpace] -> [WindowSpace]
forall a b. (a -> b) -> a -> b
$ [WindowSpace] -> [WindowSpace]
sort' ([WindowSpace] -> [WindowSpace]) -> [WindowSpace] -> [WindowSpace]
forall a b. (a -> b) -> a -> b
$ WindowSet -> [WindowSpace]
forall i l a s sd. StackSet i l a s sd -> [Workspace i l a]
W.workspaces WindowSet
s

       Window
a_cd <- String -> X Window
getAtom String
"_NET_CURRENT_DESKTOP"
       Window
a_d <- String -> X Window
getAtom String
"_NET_WM_DESKTOP"
       Window
a_aw <- String -> X Window
getAtom String
"_NET_ACTIVE_WINDOW"
       Window
a_cw <- String -> X Window
getAtom String
"_NET_CLOSE_WINDOW"
       [Window]
a_ignore <- (String -> X Window) -> [String] -> X [Window]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM String -> X Window
getAtom [String
"XMONAD_TIMER"]
       if  Window
mt Window -> Window -> Bool
forall a. Eq a => a -> a -> Bool
== Window
a_cd then do
               let n :: CInt
n = [CInt] -> CInt
forall a. [a] -> a
head [CInt]
d
               if CInt
0 CInt -> CInt -> Bool
forall a. Ord a => a -> a -> Bool
<= CInt
n Bool -> Bool -> Bool
&& CInt -> Int
forall a b. (Integral a, Num b) => a -> b
fi CInt
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< [WindowSpace] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [WindowSpace]
ws then
                       (WindowSet -> WindowSet) -> X ()
windows ((WindowSet -> WindowSet) -> X ())
-> (WindowSet -> WindowSet) -> X ()
forall a b. (a -> b) -> a -> b
$ String -> WindowSet -> WindowSet
forall s i l a sd.
(Eq s, Eq i) =>
i -> StackSet i l a s sd -> StackSet i l a s sd
W.view (WindowSpace -> String
forall i l a. Workspace i l a -> i
W.tag ([WindowSpace]
ws [WindowSpace] -> Int -> WindowSpace
forall a. [a] -> Int -> a
!! CInt -> Int
forall a b. (Integral a, Num b) => a -> b
fi CInt
n))
                 else  String -> X ()
forall (m :: * -> *). MonadIO m => String -> m ()
trace (String -> X ()) -> String -> X ()
forall a b. (a -> b) -> a -> b
$ String
"Bad _NET_CURRENT_DESKTOP with data[0]="String -> String -> String
forall a. [a] -> [a] -> [a]
++CInt -> String
forall a. Show a => a -> String
show CInt
n
        else if Window
mt Window -> Window -> Bool
forall a. Eq a => a -> a -> Bool
== Window
a_d then do
               let n :: CInt
n = [CInt] -> CInt
forall a. [a] -> a
head [CInt]
d
               if CInt
0 CInt -> CInt -> Bool
forall a. Ord a => a -> a -> Bool
<= CInt
n Bool -> Bool -> Bool
&& CInt -> Int
forall a b. (Integral a, Num b) => a -> b
fi CInt
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< [WindowSpace] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [WindowSpace]
ws then
                       (WindowSet -> WindowSet) -> X ()
windows ((WindowSet -> WindowSet) -> X ())
-> (WindowSet -> WindowSet) -> X ()
forall a b. (a -> b) -> a -> b
$ String -> Window -> WindowSet -> WindowSet
forall a s i l sd.
(Ord a, Eq s, Eq i) =>
i -> a -> StackSet i l a s sd -> StackSet i l a s sd
W.shiftWin (WindowSpace -> String
forall i l a. Workspace i l a -> i
W.tag ([WindowSpace]
ws [WindowSpace] -> Int -> WindowSpace
forall a. [a] -> Int -> a
!! CInt -> Int
forall a b. (Integral a, Num b) => a -> b
fi CInt
n)) Window
w
                 else  String -> X ()
forall (m :: * -> *). MonadIO m => String -> m ()
trace (String -> X ()) -> String -> X ()
forall a b. (a -> b) -> a -> b
$ String
"Bad _NET_DESKTOP with data[0]="String -> String -> String
forall a. [a] -> [a] -> [a]
++CInt -> String
forall a. Show a => a -> String
show CInt
n
        else if Window
mt Window -> Window -> Bool
forall a. Eq a => a -> a -> Bool
== Window
a_aw then do
               (WindowSet -> WindowSet) -> X ()
windows ((WindowSet -> WindowSet) -> X ())
-> (WindowSet -> WindowSet) -> X ()
forall a b. (a -> b) -> a -> b
$ Window -> WindowSet -> WindowSet
forall s a i l sd.
(Eq s, Eq a, Eq i) =>
a -> StackSet i l a s sd -> StackSet i l a s sd
W.focusWindow Window
w
        else if Window
mt Window -> Window -> Bool
forall a. Eq a => a -> a -> Bool
== Window
a_cw then do
               Window -> X ()
killWindow Window
w
        else if Window
mt Window -> [Window] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Window]
a_ignore then do
           () -> X ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
        else do
          -- The Message is unknown to us, but that is ok, not all are meant
          -- to be handled by the window manager
          () -> X ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
handle [WindowSpace] -> [WindowSpace]
_ Event
_ = () -> X ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()

-- |
-- An event hook to handle applications that wish to fullscreen using the
-- _NET_WM_STATE protocol. This includes users of the gtk_window_fullscreen()
-- function, such as Totem, Evince and OpenOffice.org.
--
-- Note this is not included in 'ewmh'.
fullscreenEventHook :: Event -> X All
fullscreenEventHook :: Event -> X All
fullscreenEventHook (ClientMessageEvent EventType
_ CULong
_ Bool
_ Display
dpy Window
win Window
typ (CInt
action:[CInt]
dats)) = do
  Window
wmstate <- String -> X Window
getAtom String
"_NET_WM_STATE"
  Window
fullsc <- String -> X Window
getAtom String
"_NET_WM_STATE_FULLSCREEN"
  [CLong]
wstate <- [CLong] -> Maybe [CLong] -> [CLong]
forall a. a -> Maybe a -> a
fromMaybe [] (Maybe [CLong] -> [CLong]) -> X (Maybe [CLong]) -> X [CLong]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` Window -> Window -> X (Maybe [CLong])
getProp32 Window
wmstate Window
win

  let isFull :: Bool
isFull = Window -> CLong
forall a b. (Integral a, Num b) => a -> b
fromIntegral Window
fullsc CLong -> [CLong] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [CLong]
wstate

      -- Constants for the _NET_WM_STATE protocol:
      remove :: CInt
remove = CInt
0
      add :: CInt
add = CInt
1
      toggle :: CInt
toggle = CInt
2
      ptype :: Window
ptype = Window
4 -- The atom property type for changeProperty
      chWstate :: ([CLong] -> [CLong]) -> m ()
chWstate [CLong] -> [CLong]
f = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
io (IO () -> m ()) -> IO () -> m ()
forall a b. (a -> b) -> a -> b
$ Display -> Window -> Window -> Window -> CInt -> [CLong] -> IO ()
changeProperty32 Display
dpy Window
win Window
wmstate Window
ptype CInt
propModeReplace ([CLong] -> [CLong]
f [CLong]
wstate)

  Bool -> X () -> X ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Window
typ Window -> Window -> Bool
forall a. Eq a => a -> a -> Bool
== Window
wmstate Bool -> Bool -> Bool
&& Window -> CInt
forall a b. (Integral a, Num b) => a -> b
fi Window
fullsc CInt -> [CInt] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [CInt]
dats) (X () -> X ()) -> X () -> X ()
forall a b. (a -> b) -> a -> b
$ do
    Bool -> X () -> X ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (CInt
action CInt -> CInt -> Bool
forall a. Eq a => a -> a -> Bool
== CInt
add Bool -> Bool -> Bool
|| (CInt
action CInt -> CInt -> Bool
forall a. Eq a => a -> a -> Bool
== CInt
toggle Bool -> Bool -> Bool
&& Bool -> Bool
not Bool
isFull)) (X () -> X ()) -> X () -> X ()
forall a b. (a -> b) -> a -> b
$ do
      ([CLong] -> [CLong]) -> X ()
forall (m :: * -> *). MonadIO m => ([CLong] -> [CLong]) -> m ()
chWstate (Window -> CLong
forall a b. (Integral a, Num b) => a -> b
fi Window
fullscCLong -> [CLong] -> [CLong]
forall a. a -> [a] -> [a]
:)
      (WindowSet -> WindowSet) -> X ()
windows ((WindowSet -> WindowSet) -> X ())
-> (WindowSet -> WindowSet) -> X ()
forall a b. (a -> b) -> a -> b
$ Window -> RationalRect -> WindowSet -> WindowSet
forall a i l s sd.
Ord a =>
a -> RationalRect -> StackSet i l a s sd -> StackSet i l a s sd
W.float Window
win (RationalRect -> WindowSet -> WindowSet)
-> RationalRect -> WindowSet -> WindowSet
forall a b. (a -> b) -> a -> b
$ Rational -> Rational -> Rational -> Rational -> RationalRect
W.RationalRect Rational
0 Rational
0 Rational
1 Rational
1
    Bool -> X () -> X ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (CInt
action CInt -> CInt -> Bool
forall a. Eq a => a -> a -> Bool
== CInt
remove Bool -> Bool -> Bool
|| (CInt
action CInt -> CInt -> Bool
forall a. Eq a => a -> a -> Bool
== CInt
toggle Bool -> Bool -> Bool
&& Bool
isFull)) (X () -> X ()) -> X () -> X ()
forall a b. (a -> b) -> a -> b
$ do
      ([CLong] -> [CLong]) -> X ()
forall (m :: * -> *). MonadIO m => ([CLong] -> [CLong]) -> m ()
chWstate (([CLong] -> [CLong]) -> X ()) -> ([CLong] -> [CLong]) -> X ()
forall a b. (a -> b) -> a -> b
$ CLong -> [CLong] -> [CLong]
forall a. Eq a => a -> [a] -> [a]
delete (Window -> CLong
forall a b. (Integral a, Num b) => a -> b
fi Window
fullsc)
      (WindowSet -> WindowSet) -> X ()
windows ((WindowSet -> WindowSet) -> X ())
-> (WindowSet -> WindowSet) -> X ()
forall a b. (a -> b) -> a -> b
$ Window -> WindowSet -> WindowSet
forall a i l s sd.
Ord a =>
a -> StackSet i l a s sd -> StackSet i l a s sd
W.sink Window
win

  All -> X All
forall (m :: * -> *) a. Monad m => a -> m a
return (All -> X All) -> All -> X All
forall a b. (a -> b) -> a -> b
$ Bool -> All
All Bool
True

fullscreenEventHook Event
_ = All -> X All
forall (m :: * -> *) a. Monad m => a -> m a
return (All -> X All) -> All -> X All
forall a b. (a -> b) -> a -> b
$ Bool -> All
All Bool
True

setNumberOfDesktops :: (Integral a) => a -> X ()
setNumberOfDesktops :: a -> X ()
setNumberOfDesktops a
n = (Display -> X ()) -> X ()
forall a. (Display -> X a) -> X a
withDisplay ((Display -> X ()) -> X ()) -> (Display -> X ()) -> X ()
forall a b. (a -> b) -> a -> b
$ \Display
dpy -> do
    Window
a <- String -> X Window
getAtom String
"_NET_NUMBER_OF_DESKTOPS"
    Window
c <- String -> X Window
getAtom String
"CARDINAL"
    Window
r <- (XConf -> Window) -> X Window
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks XConf -> Window
theRoot
    IO () -> X ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
io (IO () -> X ()) -> IO () -> X ()
forall a b. (a -> b) -> a -> b
$ Display -> Window -> Window -> Window -> CInt -> [CLong] -> IO ()
changeProperty32 Display
dpy Window
r Window
a Window
c CInt
propModeReplace [a -> CLong
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
n]

setCurrentDesktop :: (Integral a) => a -> X ()
setCurrentDesktop :: a -> X ()
setCurrentDesktop a
i = (Display -> X ()) -> X ()
forall a. (Display -> X a) -> X a
withDisplay ((Display -> X ()) -> X ()) -> (Display -> X ()) -> X ()
forall a b. (a -> b) -> a -> b
$ \Display
dpy -> do
    Window
a <- String -> X Window
getAtom String
"_NET_CURRENT_DESKTOP"
    Window
c <- String -> X Window
getAtom String
"CARDINAL"
    Window
r <- (XConf -> Window) -> X Window
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks XConf -> Window
theRoot
    IO () -> X ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
io (IO () -> X ()) -> IO () -> X ()
forall a b. (a -> b) -> a -> b
$ Display -> Window -> Window -> Window -> CInt -> [CLong] -> IO ()
changeProperty32 Display
dpy Window
r Window
a Window
c CInt
propModeReplace [a -> CLong
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
i]

setDesktopNames :: [String] -> X ()
setDesktopNames :: [String] -> X ()
setDesktopNames [String]
names = (Display -> X ()) -> X ()
forall a. (Display -> X a) -> X a
withDisplay ((Display -> X ()) -> X ()) -> (Display -> X ()) -> X ()
forall a b. (a -> b) -> a -> b
$ \Display
dpy -> do
    -- Names thereof
    Window
r <- (XConf -> Window) -> X Window
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks XConf -> Window
theRoot
    Window
a <- String -> X Window
getAtom String
"_NET_DESKTOP_NAMES"
    Window
c <- String -> X Window
getAtom String
"UTF8_STRING"
    let names' :: [CChar]
names' = (Word8 -> CChar) -> [Word8] -> [CChar]
forall a b. (a -> b) -> [a] -> [b]
map Word8 -> CChar
forall a b. (Integral a, Num b) => a -> b
fromIntegral ([Word8] -> [CChar]) -> [Word8] -> [CChar]
forall a b. (a -> b) -> a -> b
$ (String -> [Word8]) -> [String] -> [Word8]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (([Word8] -> [Word8] -> [Word8]
forall a. [a] -> [a] -> [a]
++[Word8
0]) ([Word8] -> [Word8]) -> (String -> [Word8]) -> String -> [Word8]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [Word8]
encode) [String]
names
    IO () -> X ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
io (IO () -> X ()) -> IO () -> X ()
forall a b. (a -> b) -> a -> b
$ Display -> Window -> Window -> Window -> CInt -> [CChar] -> IO ()
changeProperty8 Display
dpy Window
r Window
a Window
c CInt
propModeReplace [CChar]
names'

setClientList :: [Window] -> X ()
setClientList :: [Window] -> X ()
setClientList [Window]
wins = (Display -> X ()) -> X ()
forall a. (Display -> X a) -> X a
withDisplay ((Display -> X ()) -> X ()) -> (Display -> X ()) -> X ()
forall a b. (a -> b) -> a -> b
$ \Display
dpy -> do
    -- (What order do we really need? Something about age and stacking)
    Window
r <- (XConf -> Window) -> X Window
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks XConf -> Window
theRoot
    Window
c <- String -> X Window
getAtom String
"WINDOW"
    Window
a <- String -> X Window
getAtom String
"_NET_CLIENT_LIST"
    IO () -> X ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
io (IO () -> X ()) -> IO () -> X ()
forall a b. (a -> b) -> a -> b
$ Display -> Window -> Window -> Window -> CInt -> [CLong] -> IO ()
changeProperty32 Display
dpy Window
r Window
a Window
c CInt
propModeReplace ((Window -> CLong) -> [Window] -> [CLong]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Window -> CLong
forall a b. (Integral a, Num b) => a -> b
fromIntegral [Window]
wins)
    Window
a' <- String -> X Window
getAtom String
"_NET_CLIENT_LIST_STACKING"
    IO () -> X ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
io (IO () -> X ()) -> IO () -> X ()
forall a b. (a -> b) -> a -> b
$ Display -> Window -> Window -> Window -> CInt -> [CLong] -> IO ()
changeProperty32 Display
dpy Window
r Window
a' Window
c CInt
propModeReplace ((Window -> CLong) -> [Window] -> [CLong]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Window -> CLong
forall a b. (Integral a, Num b) => a -> b
fromIntegral [Window]
wins)

setWindowDesktop :: (Integral a) => Window -> a -> X ()
setWindowDesktop :: Window -> a -> X ()
setWindowDesktop Window
win a
i = (Display -> X ()) -> X ()
forall a. (Display -> X a) -> X a
withDisplay ((Display -> X ()) -> X ()) -> (Display -> X ()) -> X ()
forall a b. (a -> b) -> a -> b
$ \Display
dpy -> do
    Window
a <- String -> X Window
getAtom String
"_NET_WM_DESKTOP"
    Window
c <- String -> X Window
getAtom String
"CARDINAL"
    IO () -> X ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
io (IO () -> X ()) -> IO () -> X ()
forall a b. (a -> b) -> a -> b
$ Display -> Window -> Window -> Window -> CInt -> [CLong] -> IO ()
changeProperty32 Display
dpy Window
win Window
a Window
c CInt
propModeReplace [a -> CLong
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
i]

setSupported :: X ()
setSupported :: X ()
setSupported = (Display -> X ()) -> X ()
forall a. (Display -> X a) -> X a
withDisplay ((Display -> X ()) -> X ()) -> (Display -> X ()) -> X ()
forall a b. (a -> b) -> a -> b
$ \Display
dpy -> do
    Window
r <- (XConf -> Window) -> X Window
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks XConf -> Window
theRoot
    Window
a <- String -> X Window
getAtom String
"_NET_SUPPORTED"
    Window
c <- String -> X Window
getAtom String
"ATOM"
    [Window]
supp <- (String -> X Window) -> [String] -> X [Window]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM String -> X Window
getAtom [String
"_NET_WM_STATE_HIDDEN"
                         ,String
"_NET_NUMBER_OF_DESKTOPS"
                         ,String
"_NET_CLIENT_LIST"
                         ,String
"_NET_CLIENT_LIST_STACKING"
                         ,String
"_NET_CURRENT_DESKTOP"
                         ,String
"_NET_DESKTOP_NAMES"
                         ,String
"_NET_ACTIVE_WINDOW"
                         ,String
"_NET_WM_DESKTOP"
                         ,String
"_NET_WM_STRUT"
                         ]
    IO () -> X ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
io (IO () -> X ()) -> IO () -> X ()
forall a b. (a -> b) -> a -> b
$ Display -> Window -> Window -> Window -> CInt -> [CLong] -> IO ()
changeProperty32 Display
dpy Window
r Window
a Window
c CInt
propModeReplace ((Window -> CLong) -> [Window] -> [CLong]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Window -> CLong
forall a b. (Integral a, Num b) => a -> b
fromIntegral [Window]
supp)

    String -> X ()
setWMName String
"xmonad"

setActiveWindow :: Window -> X ()
setActiveWindow :: Window -> X ()
setActiveWindow Window
w = (Display -> X ()) -> X ()
forall a. (Display -> X a) -> X a
withDisplay ((Display -> X ()) -> X ()) -> (Display -> X ()) -> X ()
forall a b. (a -> b) -> a -> b
$ \Display
dpy -> do
    Window
r <- (XConf -> Window) -> X Window
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks XConf -> Window
theRoot
    Window
a <- String -> X Window
getAtom String
"_NET_ACTIVE_WINDOW"
    Window
c <- String -> X Window
getAtom String
"WINDOW"
    IO () -> X ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
io (IO () -> X ()) -> IO () -> X ()
forall a b. (a -> b) -> a -> b
$ Display -> Window -> Window -> Window -> CInt -> [CLong] -> IO ()
changeProperty32 Display
dpy Window
r Window
a Window
c CInt
propModeReplace [Window -> CLong
forall a b. (Integral a, Num b) => a -> b
fromIntegral Window
w]