65 lines
2.1 KiB
Haskell
65 lines
2.1 KiB
Haskell
module SendXMsg (XMsgType(..), sendXMsg, splitXMsg) where
|
|
|
|
import Data.Char
|
|
|
|
import Graphics.X11.Types
|
|
import Graphics.X11.Xlib.Atom
|
|
import Graphics.X11.Xlib.Display
|
|
import Graphics.X11.Xlib.Event
|
|
import Graphics.X11.Xlib.Extras
|
|
|
|
-- These are the "types" of client messages to send; add more here as needed
|
|
data XMsgType = ACPI
|
|
| Workspace
|
|
deriving (Eq, Show)
|
|
|
|
instance Enum XMsgType where
|
|
toEnum 0 = ACPI
|
|
toEnum 1 = Workspace
|
|
toEnum _ = errorWithoutStackTrace "ACPI.Enum.ACPIEvent.toEnum: bad argument"
|
|
|
|
fromEnum ACPI = 0
|
|
fromEnum Workspace = 1
|
|
|
|
sendXMsg :: XMsgType -> String -> IO ()
|
|
sendXMsg xtype tag = do
|
|
dpy <- openDisplay ""
|
|
root <- rootWindow dpy $ defaultScreen dpy
|
|
allocaXEvent $ \e -> do
|
|
setEventType e clientMessage
|
|
-- NOTE: This function is written such that the penultimate
|
|
-- argument represents the first 40 bits of the 160 bit data
|
|
-- field, and it also only takes a decimal digit, which means the
|
|
-- string to be stored in the data field needs to be converted to
|
|
-- its decimal equivalent. The penultimate argument will be used
|
|
-- for the magic string and the last will be used for the tag.
|
|
setClientMessageEvent e root bITMAP 8 x t
|
|
sendEvent dpy root False substructureNotifyMask e
|
|
flush dpy
|
|
closeDisplay dpy
|
|
where
|
|
x = fromIntegral $ fromEnum xtype
|
|
t = str2digit $ tag ++ [garbageDelim]
|
|
|
|
str2digit :: String -> Time
|
|
str2digit = fromIntegral
|
|
. sum
|
|
. map (\(p, n) -> n * 256 ^ p)
|
|
. zip [0 :: Int ..]
|
|
. map fromEnum
|
|
|
|
splitXMsg :: (Integral a) => [a] -> (XMsgType, String)
|
|
splitXMsg msg = (xtype, tag)
|
|
where
|
|
xtype = toEnum $ fromInteger $ toInteger $ head msg
|
|
tag = filterGarbage $ mapToChr $ drop 5 msg
|
|
filterGarbage = filter isAlphaNum . takeWhile (/= garbageDelim)
|
|
mapToChr = map (chr . fromInteger . toInteger)
|
|
|
|
-- WORKAROUND: setClientMessageEvent seems to put garbage on the end
|
|
-- of the data field (which is probably some yucky c problem I don't
|
|
-- understand). Easy solution, put something at the end of the tag to
|
|
-- separate the tag from the garbage
|
|
garbageDelim :: Char
|
|
garbageDelim = '~'
|