module XMonad.Util.DebugWindow (debugWindow) where
import Prelude
import XMonad
import XMonad.Prelude
import Codec.Binary.UTF8.String (decodeString)
import Control.Exception as E
import Foreign.C.String
import Numeric (showHex)
import System.Exit
debugWindow :: Window -> X String
debugWindow :: Atom -> X String
debugWindow Atom
0 = forall (m :: * -> *) a. Monad m => a -> m a
return String
"-no window-"
debugWindow Atom
w = do
Display
d <- forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks XConf -> Display
display
let wx :: String
wx = Int -> Char -> String -> String
pad Int
8 Char
'0' forall a b. (a -> b) -> a -> b
$ forall a. (Integral a, Show a) => a -> String -> String
showHex Atom
w String
""
Maybe WindowAttributes
w' <- Atom -> X (Maybe WindowAttributes)
safeGetWindowAttributes Atom
w
case Maybe WindowAttributes
w' of
Maybe WindowAttributes
Nothing ->
forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ String
"(deleted window " forall a. [a] -> [a] -> [a]
++ String
wx forall a. [a] -> [a] -> [a]
++ String
")"
Just WindowAttributes
{ wa_x :: WindowAttributes -> CInt
wa_x = CInt
x
, wa_y :: WindowAttributes -> CInt
wa_y = CInt
y
, wa_width :: WindowAttributes -> CInt
wa_width = CInt
wid
, wa_height :: WindowAttributes -> CInt
wa_height = CInt
ht
, wa_border_width :: WindowAttributes -> CInt
wa_border_width = CInt
bw
, wa_map_state :: WindowAttributes -> CInt
wa_map_state = CInt
m
, wa_override_redirect :: WindowAttributes -> Bool
wa_override_redirect = Bool
o
} -> do
Maybe [CChar]
c' <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
io (Display -> Atom -> Atom -> IO (Maybe [CChar])
getWindowProperty8 Display
d Atom
wM_CLASS Atom
w)
let c :: String
c = case Maybe [CChar]
c' of
Maybe [CChar]
Nothing -> String
""
Just [CChar]
c'' -> forall a. [a] -> [[a]] -> [a]
intercalate String
"/" forall a b. (a -> b) -> a -> b
$
forall a b c. (a -> b -> c) -> b -> a -> c
flip forall b a. (b -> Maybe (a, b)) -> b -> [a]
unfoldr (forall a b. (a -> b) -> [a] -> [b]
map (forall a. Enum a => Int -> a
toEnum forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Enum a => a -> Int
fromEnum) [CChar]
c'') forall a b. (a -> b) -> a -> b
$
\String
s -> if forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
s
then forall a. Maybe a
Nothing
else let (String
w'',String
s'') = forall a. (a -> Bool) -> [a] -> ([a], [a])
break (forall a. Eq a => a -> a -> Bool
== Char
'\NUL') String
s
s' :: String
s' = forall a. Int -> [a] -> [a]
drop Int
1 String
s''
in forall a. a -> Maybe a
Just (String
w'',String
s')
String
t <- forall a. X a -> X a -> X a
catchX' (String -> String
wrap forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> Atom -> X String
getEWMHTitle String
"VISIBLE" Atom
w) forall a b. (a -> b) -> a -> b
$
forall a. X a -> X a -> X a
catchX' (String -> String
wrap forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> Atom -> X String
getEWMHTitle String
"" Atom
w) forall a b. (a -> b) -> a -> b
$
forall a. X a -> X a -> X a
catchX' (String -> String
wrap forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Atom -> X String
getICCCMTitle Atom
w) forall a b. (a -> b) -> a -> b
$
forall (m :: * -> *) a. Monad m => a -> m a
return String
""
String
h' <- Atom -> X String
getMachine Atom
w
let h :: String
h = if forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
h' then String
"" else Char
'@'forall a. a -> [a] -> [a]
:String
h'
[String]
p' <- Display -> Atom -> X [String]
safeGetCommand Display
d Atom
w
let p :: String
p = if forall (t :: * -> *) a. Foldable t => t a -> Bool
null [String]
p' then String
"" else String -> String
wrap forall a b. (a -> b) -> a -> b
$ [String] -> String
unwords [String]
p'
Atom
nWP <- String -> X Atom
getAtom String
"_NET_WM_PID"
Maybe [CLong]
pid' <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
io forall a b. (a -> b) -> a -> b
$ Display -> Atom -> Atom -> IO (Maybe [CLong])
getWindowProperty32 Display
d Atom
nWP Atom
w
let pid :: String
pid = case Maybe [CLong]
pid' of
Just [CLong
pid''] -> Char
'('forall a. a -> [a] -> [a]
:forall a. Show a => a -> String
show CLong
pid'' forall a. [a] -> [a] -> [a]
++ String
")"
Maybe [CLong]
_ -> String
""
let cmd :: String
cmd = String
p forall a. [a] -> [a] -> [a]
++ String
pid forall a. [a] -> [a] -> [a]
++ String
h
let (String
lb,String
rb) = case () of
() | CInt
m forall a. Eq a => a -> a -> Bool
== CInt
waIsViewable -> (String
"",String
"")
| Bool
otherwise -> (String
"[",String
"]")
o' :: String
o' = if Bool
o then String
"!" else String
""
Atom
wT <- String -> X Atom
getAtom String
"_NET_WM_WINDOW_TYPE"
Maybe [CLong]
wt' <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
io forall a b. (a -> b) -> a -> b
$ Display -> Atom -> Atom -> IO (Maybe [CLong])
getWindowProperty32 Display
d Atom
wT Atom
w
String
ewmh <- case Maybe [CLong]
wt' of
Just [CLong]
wt'' -> Display -> Atom -> [Atom] -> X String
windowType Display
d Atom
w (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a b. (Integral a, Num b) => a -> b
fi [CLong]
wt'')
Maybe [CLong]
_ -> forall (m :: * -> *) a. Monad m => a -> m a
return String
""
forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [String
lb
,String
o'
,String
wx
,String
t
,String
" "
,forall a. Show a => a -> String
show CInt
wid
,Char
'x'forall a. a -> [a] -> [a]
:forall a. Show a => a -> String
show CInt
ht
,if CInt
bw forall a. Eq a => a -> a -> Bool
== CInt
0 then String
"" else Char
'+'forall a. a -> [a] -> [a]
:forall a. Show a => a -> String
show CInt
bw
,String
"@"
,forall a. Show a => a -> String
show CInt
x
,Char
','forall a. a -> [a] -> [a]
:forall a. Show a => a -> String
show CInt
y
,if forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
c then String
"" else Char
' 'forall a. a -> [a] -> [a]
:String
c
,if forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
cmd then String
"" else Char
' 'forall a. a -> [a] -> [a]
:String
cmd
,String
ewmh
,String
rb
]
getEWMHTitle :: String -> Window -> X String
getEWMHTitle :: String -> Atom -> X String
getEWMHTitle String
sub Atom
w = do
Atom
a <- String -> X Atom
getAtom forall a b. (a -> b) -> a -> b
$ String
"_NET_WM_" forall a. [a] -> [a] -> [a]
++ (if forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
sub then String
"" else Char
'_'forall a. a -> [a] -> [a]
:String
sub) forall a. [a] -> [a] -> [a]
++ String
"_NAME"
Atom -> Atom -> X String
getDecodedStringProp Atom
w Atom
a
getICCCMTitle :: Window -> X String
getICCCMTitle :: Atom -> X String
getICCCMTitle Atom
w = Atom -> Atom -> X String
getDecodedStringProp Atom
w Atom
wM_NAME
getDecodedStringProp :: Window -> Atom -> X String
getDecodedStringProp :: Atom -> Atom -> X String
getDecodedStringProp Atom
w Atom
a = do
t :: TextProperty
t@(TextProperty CString
t' Atom
_ CInt
8 Atom
_) <- forall a. (Display -> X a) -> X a
withDisplay forall a b. (a -> b) -> a -> b
$ \Display
d -> forall (m :: * -> *) a. MonadIO m => IO a -> m a
io forall a b. (a -> b) -> a -> b
$ Display -> Atom -> Atom -> IO TextProperty
getTextProperty Display
d Atom
w Atom
a
[String
s] <- forall a. X a -> X a -> X a
catchX' (TextProperty -> X [String]
tryUTF8 TextProperty
t) forall a b. (a -> b) -> a -> b
$
forall a. X a -> X a -> X a
catchX' (TextProperty -> X [String]
tryCompound TextProperty
t) forall a b. (a -> b) -> a -> b
$
forall (m :: * -> *) a. MonadIO m => IO a -> m a
io ((forall a. a -> [a] -> [a]
:[]) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> CString -> IO String
peekCString CString
t')
forall (m :: * -> *) a. Monad m => a -> m a
return String
s
tryUTF8 :: TextProperty -> X [String]
tryUTF8 :: TextProperty -> X [String]
tryUTF8 (TextProperty CString
s Atom
enc CInt
_ Atom
_) = do
Atom
uTF8_STRING <- String -> X Atom
getAtom String
"UTF8_STRING"
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Atom
enc forall a. Eq a => a -> a -> Bool
/= Atom
uTF8_STRING) forall a b. (a -> b) -> a -> b
$ forall a. HasCallStack => String -> a
error String
"String is not UTF8_STRING"
forall a b. (a -> b) -> [a] -> [b]
map String -> String
decodeString forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String]
splitNul forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *) a. MonadIO m => IO a -> m a
io (CString -> IO String
peekCAString CString
s)
tryCompound :: TextProperty -> X [String]
tryCompound :: TextProperty -> X [String]
tryCompound t :: TextProperty
t@(TextProperty CString
_ Atom
enc CInt
_ Atom
_) = do
Atom
cOMPOUND_TEXT <- String -> X Atom
getAtom String
"COMPOUND_TEXT"
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Atom
enc forall a. Eq a => a -> a -> Bool
/= Atom
cOMPOUND_TEXT) forall a b. (a -> b) -> a -> b
$ forall a. HasCallStack => String -> a
error String
"String is not COMPOUND_TEXT"
forall a. (Display -> X a) -> X a
withDisplay forall a b. (a -> b) -> a -> b
$ \Display
d -> forall (m :: * -> *) a. MonadIO m => IO a -> m a
io forall a b. (a -> b) -> a -> b
$ Display -> TextProperty -> IO [String]
wcTextPropertyToTextList Display
d TextProperty
t
splitNul :: String -> [String]
splitNul :: String -> [String]
splitNul String
"" = []
splitNul String
s = let (String
s',String
ss') = forall a. (a -> Bool) -> [a] -> ([a], [a])
break (forall a. Eq a => a -> a -> Bool
== Char
'\NUL') String
s in String
s' forall a. a -> [a] -> [a]
: String -> [String]
splitNul String
ss'
pad :: Int -> Char -> String -> String
pad :: Int -> Char -> String -> String
pad Int
w Char
c String
s = forall a. Int -> a -> [a]
replicate (Int
w forall a. Num a => a -> a -> a
- forall (t :: * -> *) a. Foldable t => t a -> Int
length String
s) Char
c forall a. [a] -> [a] -> [a]
++ String
s
catchX' :: X a -> X a -> X a
catchX' :: forall a. X a -> X a -> X a
catchX' X a
job X a
errcase = do
XState
st <- forall s (m :: * -> *). MonadState s m => m s
get
XConf
c <- forall r (m :: * -> *). MonadReader r m => m r
ask
(a
a, XState
s') <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
io forall a b. (a -> b) -> a -> b
$ forall a. XConf -> XState -> X a -> IO (a, XState)
runX XConf
c XState
st X a
job forall e a. Exception e => IO a -> (e -> IO a) -> IO a
`E.catch` \SomeException
e -> case forall e. Exception e => SomeException -> Maybe e
fromException SomeException
e of
Just ExitCode
x -> forall a e. Exception e => e -> a
throw SomeException
e forall a b. a -> b -> a
`const` (ExitCode
x forall a. a -> a -> a
`asTypeOf` ExitCode
ExitSuccess)
Maybe ExitCode
_ -> forall a. XConf -> XState -> X a -> IO (a, XState)
runX XConf
c XState
st X a
errcase
forall s (m :: * -> *). MonadState s m => s -> m ()
put XState
s'
forall (m :: * -> *) a. Monad m => a -> m a
return a
a
wrap :: String -> String
wrap :: String -> String
wrap String
s = Char
' ' forall a. a -> [a] -> [a]
: Char
'"' forall a. a -> [a] -> [a]
: String -> String
wrap' String
s forall a. [a] -> [a] -> [a]
++ String
"\""
where
wrap' :: String -> String
wrap' (Char
s':String
ss) | Char
s' forall a. Eq a => a -> a -> Bool
== Char
'"' = Char
'\\' forall a. a -> [a] -> [a]
: Char
s' forall a. a -> [a] -> [a]
: String -> String
wrap' String
ss
| Char
s' forall a. Eq a => a -> a -> Bool
== Char
'\\' = Char
'\\' forall a. a -> [a] -> [a]
: Char
s' forall a. a -> [a] -> [a]
: String -> String
wrap' String
ss
| Bool
otherwise = Char
s' forall a. a -> [a] -> [a]
: String -> String
wrap' String
ss
wrap' String
"" = String
""
safeGetCommand :: Display -> Window -> X [String]
safeGetCommand :: Display -> Atom -> X [String]
safeGetCommand Display
d Atom
w = do
Atom
wC <- String -> X Atom
getAtom String
"WM_COMMAND"
Maybe [CChar]
p <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
io forall a b. (a -> b) -> a -> b
$ Display -> Atom -> Atom -> IO (Maybe [CChar])
getWindowProperty8 Display
d Atom
wC Atom
w
case Maybe [CChar]
p of
Maybe [CChar]
Nothing -> forall (m :: * -> *) a. Monad m => a -> m a
return []
Just [CChar]
cs' -> do
let cs :: String
cs = forall a b. (a -> b) -> [a] -> [b]
map (forall a. Enum a => Int -> a
toEnum forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Enum a => a -> Int
fromEnum) [CChar]
cs'
go :: ([String], (String, String)) -> ([String], (String, String))
go ([String]
a,(String
s,String
"\NUL")) = (String
sforall a. a -> [a] -> [a]
:[String]
a,(String
"",String
""))
go ([String]
a,(String
s,Char
'\NUL':String
ss)) = ([String], (String, String)) -> ([String], (String, String))
go (String
sforall a. a -> [a] -> [a]
:[String]
a,String -> (String, String)
go' String
ss)
go ([String], (String, String))
r = ([String], (String, String))
r
go' :: String -> (String, String)
go' = forall a. (a -> Bool) -> [a] -> ([a], [a])
break (forall a. Eq a => a -> a -> Bool
== Char
'\NUL')
in forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a. [a] -> [a]
reverse forall a b. (a -> b) -> a -> b
$ forall a b. (a, b) -> a
fst forall a b. (a -> b) -> a -> b
$ ([String], (String, String)) -> ([String], (String, String))
go ([],String -> (String, String)
go' String
cs)
getMachine :: Window -> X String
getMachine :: Atom -> X String
getMachine Atom
w = forall a. X a -> X a -> X a
catchX' (String -> X Atom
getAtom String
"WM_CLIENT_MACHINE" forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Atom -> Atom -> X String
getDecodedStringProp Atom
w) (forall (m :: * -> *) a. Monad m => a -> m a
return String
"")
windowType :: Display -> Window -> [Atom] -> X String
windowType :: Display -> Atom -> [Atom] -> X String
windowType Display
d Atom
w [Atom]
ts = do
String
tstr <- [Atom] -> X String
decodeType [Atom]
ts
Atom
wS <- String -> X Atom
getAtom String
"_NET_WM_STATE"
Maybe [CLong]
ss' <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
io forall a b. (a -> b) -> a -> b
$ Display -> Atom -> Atom -> IO (Maybe [CLong])
getWindowProperty32 Display
d Atom
wS Atom
w
String
sstr <- case Maybe [CLong]
ss' of
Just [CLong]
ss -> [Atom] -> X String
windowState (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a b. (Integral a, Num b) => a -> b
fi [CLong]
ss)
Maybe [CLong]
_ -> forall (m :: * -> *) a. Monad m => a -> m a
return String
""
forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ String
" (" forall a. [a] -> [a] -> [a]
++ String
tstr forall a. [a] -> [a] -> [a]
++ String
sstr forall a. [a] -> [a] -> [a]
++ String
")"
where
decodeType :: [Atom] -> X String
decodeType :: [Atom] -> X String
decodeType [] = forall (m :: * -> *) a. Monad m => a -> m a
return String
""
decodeType [Atom
t] = String -> Atom -> X String
simplify String
"_NET_WM_WINDOW_TYPE_" Atom
t
decodeType [Atom]
tys = [Atom] -> String -> Bool -> X String
unAtoms [Atom]
tys String
" (" Bool
False
unAtoms :: [Atom] -> String -> Bool -> X String
unAtoms :: [Atom] -> String -> Bool -> X String
unAtoms [] String
t Bool
i = forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ if Bool
i then String
t else String
t forall a. [a] -> [a] -> [a]
++ String
")"
unAtoms (Atom
a:[Atom]
as) String
t Bool
i = do
Maybe String
s' <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
io forall a b. (a -> b) -> a -> b
$ Display -> Atom -> IO (Maybe String)
getAtomName Display
d Atom
a
let s :: String
s = case Maybe String
s' of
Just String
s'' -> String
s''
Maybe String
_ -> Char
'<'forall a. a -> [a] -> [a]
:forall a. Show a => a -> String
show Atom
a forall a. [a] -> [a] -> [a]
++ String
">"
[Atom] -> String -> Bool -> X String
unAtoms [Atom]
as (String
t forall a. [a] -> [a] -> [a]
++ (if Bool
i then Char
' 'forall a. a -> [a] -> [a]
:String
s else String
s)) Bool
True
simplify :: String -> Atom -> X String
simplify :: String -> Atom -> X String
simplify String
pfx Atom
a = do
Maybe String
s' <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
io forall a b. (a -> b) -> a -> b
$ Display -> Atom -> IO (Maybe String)
getAtomName Display
d Atom
a
case Maybe String
s' of
Maybe String
Nothing -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ Char
'<'forall a. a -> [a] -> [a]
:forall a. Show a => a -> String
show Atom
a forall a. [a] -> [a] -> [a]
++ String
">"
Just String
s -> if String
pfx forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf` String
s then
forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toLower (forall a. Int -> [a] -> [a]
drop (forall (t :: * -> *) a. Foldable t => t a -> Int
length String
pfx) String
s)
else
forall (m :: * -> *) a. Monad m => a -> m a
return String
s
windowState :: [Atom] -> X String
windowState :: [Atom] -> X String
windowState [] = forall (m :: * -> *) a. Monad m => a -> m a
return String
""
windowState [Atom]
as' = [Atom] -> String -> X String
go [Atom]
as' String
";"
where
go :: [Atom] -> String -> X String
go [] String
t = forall (m :: * -> *) a. Monad m => a -> m a
return String
t
go (Atom
a:[Atom]
as) String
t = String -> Atom -> X String
simplify String
"_NET_WM_STATE_" Atom
a forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \String
t' -> [Atom] -> String -> X String
go [Atom]
as (String
t forall a. [a] -> [a] -> [a]
++ Char
' 'forall a. a -> [a] -> [a]
:String
t')