1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
|
-----------------------------------------------------------------------------
-- |
-- Module : XMonad.Util.WindowProperties
-- Copyright : (c) Roman Cheplyaka
-- License : BSD-style (see LICENSE)
--
-- Maintainer : Roman Cheplyaka <roma@ro-che.info>
-- Stability : unstable
-- Portability : unportable
--
-- EDSL for specifying window properties; various utilities related to window
-- properties.
--
-----------------------------------------------------------------------------
module XMonad.Util.WindowProperties (
-- * EDSL for window properties
-- $edsl
Property(..), hasProperty, focusedHasProperty, allWithProperty,
propertyToQuery,
-- * Helper functions
-- $helpers
getProp32, getProp32s)
where
import XMonad
import qualified XMonad.StackSet as W
import Foreign.C.Types (CLong)
import Control.Monad
-- $edsl
-- Allows to specify window properties, such as title, classname or
-- resource, and to check them.
--
-- In contrast to ManageHook properties, these are instances of Show and Read,
-- so they can be used in layout definitions etc. For example usage see "XMonad.Layout.IM"
-- | Most of the property constructors are quite self-explaining.
data Property = Title String
| ClassName String
| Resource String
| Role String -- ^ WM_WINDOW_ROLE property
| Machine String -- ^ WM_CLIENT_MACHINE property
| And Property Property
| Or Property Property
| Not Property
| Const Bool
deriving (Read, Show)
infixr 9 `And`
infixr 8 `Or`
-- | Does given window have this property?
hasProperty :: Property -> Window -> X Bool
hasProperty (Title s) w = withDisplay $ \d -> fmap (Just s ==) $ io $ fetchName d w
hasProperty (Resource s) w = withDisplay $ \d -> fmap ((==) s . resName ) $ io $ getClassHint d w
hasProperty (ClassName s) w = withDisplay $ \d -> fmap ((==) s . resClass) $ io $ getClassHint d w
hasProperty (Role s) w = withDisplay $ \d -> fmap ((==) (Just s)) $ getStringProperty d w "WM_WINDOW_ROLE"
hasProperty (Machine s) w = withDisplay $ \d -> fmap ((==) (Just s)) $ getStringProperty d w "WM_CLIENT_MACHINE"
hasProperty (And p1 p2) w = do { r1 <- hasProperty p1 w; r2 <- hasProperty p2 w; return $ r1 && r2 }
hasProperty (Or p1 p2) w = do { r1 <- hasProperty p1 w; r2 <- hasProperty p2 w; return $ r1 || r2 }
hasProperty (Not p1) w = do { r1 <- hasProperty p1 w; return $ not r1 }
hasProperty (Const b) _ = return b
-- | Does the focused window have this property?
focusedHasProperty :: Property -> X Bool
focusedHasProperty p = do
ws <- gets windowset
let ms = W.stack $ W.workspace $ W.current ws
case ms of
Just s -> hasProperty p $ W.focus s
Nothing -> return False
-- | Find all existing windows with specified property
allWithProperty :: Property -> X [Window]
allWithProperty prop = withDisplay $ \dpy -> do
rootw <- asks theRoot
(_,_,wins) <- io $ queryTree dpy rootw
hasProperty prop `filterM` wins
-- | Convert property to 'Query' 'Bool' (see "XMonad.ManageHook")
propertyToQuery :: Property -> Query Bool
propertyToQuery (Title s) = title =? s
propertyToQuery (Resource s) = resource =? s
propertyToQuery (ClassName s) = className =? s
propertyToQuery (Role s) = stringProperty "WM_WINDOW_ROLE" =? s
propertyToQuery (Machine s) = stringProperty "WM_CLIENT_MACHINE" =? s
propertyToQuery (And p1 p2) = propertyToQuery p1 <&&> propertyToQuery p2
propertyToQuery (Or p1 p2) = propertyToQuery p1 <||> propertyToQuery p2
propertyToQuery (Not p) = not `fmap` propertyToQuery p
propertyToQuery (Const b) = return b
-- $helpers
-- | Get a window property from atom
getProp32 :: Atom -> Window -> X (Maybe [CLong])
getProp32 a w = withDisplay $ \dpy -> io $ getWindowProperty32 dpy a w
-- | Get a window property from string
getProp32s :: String -> Window -> X (Maybe [CLong])
getProp32s str w = do { a <- getAtom str; getProp32 a w }
|