arbtt-0.1: src/Graphics/X11/XScreenSaver.hsc
{-# LANGUAGE ForeignFunctionInterface #-}
--------------------------------------------------------------------
-- |
-- Module : Graphics.X11.XScreenSaver
-- Copyright : (c) Haskell.org, 2009
-- License : BSD3
--
-- Maintainer: Joachim Breitner <mail@joachim-breitner.de>
-- Stability : provisional
-- Portability: portable
--
--------------------------------------------------------------------
--
-- Interface to XScreenSaver API
--
module Graphics.X11.XScreenSaver (
getXIdleTime,
XScreenSaverState(..),
XScreenSaverKind(..),
XScreenSaverInfo(..),
xScreenSaverQueryExtension,
xScreenSaverQueryVersion,
xScreenSaverQueryInfo,
compiledWithXScreenSaver
) where
import Foreign
import Foreign.C.Types
import Graphics.X11.Xlib
import Control.Monad
data XScreenSaverState = ScreenSaverOff | ScreenSaverOn | ScreenSaverDisabled deriving Show
data XScreenSaverKind = ScreenSaverBlanked | ScreenSaverInternal | ScreenSaverExternal deriving Show
-- | Representation of the XScreenSaverInfo struct.
data XScreenSaverInfo = XScreenSaverInfo
{ xssi_window :: !Window,
xssi_state :: !XScreenSaverState,
-- ^ The state field specified whether or not the screen saver is currently
-- active and how the til-or-since value should be interpreted:
--
-- ['ScreenSaverOff'] The screen is not currently being saved; til-or-since specifies the
-- number of milliseconds until the screen saver is expected to activate.
--
-- ['ScreenSaverOn'] The screen is currently being saved; til-or-since specifies the number
-- of milliseconds since the screen saver activated.
--
-- ['ScreenSaverDisabled'] The screen saver is currently disabled; til-or-since is zero.
xssi_kind :: !XScreenSaverKind,
-- ^ The kind field specifies the mechanism that either is currently being used
-- or would have been were the screen being saved:
--
-- ['ScreenSaverBlanked'] The video signal to the display monitor was disabled.
--
-- ['ScreenSaverInternal'] A server-dependent, built-in screen saver image was displayed;
-- either no client had set the screen saver window attributes or a different
-- client had the server grabbed when the screen saver activated.
--
-- ['ScreenSaverExternal'] The screen saver window was mapped with attributes set by a client
-- using the ScreenSaverSetAttributes request.
xssi_til_or_since :: !CULong,
xssi_idle :: !CULong,
-- ^ The idle field specifies the number of milliseconds since the last input
-- was received from the user on any of the input devices.
xssi_event_mask :: !CULong
-- ^ The event-mask field specifies which, if any, screen saver events this
-- client has requested using ScreenSaverSelectInput.
} deriving (Show)
-- | Simple wrapper around 'xScreenSaverQueryInfo' if you are only interested in
-- the idle time, in milliseconds. Returns 0 if the XScreenSaver extension is
-- not available
getXIdleTime :: Display -> IO Int
getXIdleTime dpy = maybe 0 (fromIntegral . xssi_idle) `fmap` xScreenSaverQueryInfo dpy
-- We have XScreenSaver, so the library will actually work
compiledWithXScreenSaver :: Bool
compiledWithXScreenSaver = True
-- for XFree() (already included from scrnsaver.h, but I don't know if I can count on that.)
#include <X11/Xlib.h>
#include <X11/extensions/scrnsaver.h>
xScreenSaverState2CInt :: XScreenSaverState -> CInt
xScreenSaverState2CInt ScreenSaverOn = #const ScreenSaverOn
xScreenSaverState2CInt ScreenSaverOff = #const ScreenSaverOff
xScreenSaverState2CInt ScreenSaverDisabled = #const ScreenSaverDisabled
cInt2XScreenSaverState :: CInt -> XScreenSaverState
cInt2XScreenSaverState (#const ScreenSaverOn) = ScreenSaverOn
cInt2XScreenSaverState (#const ScreenSaverOff) = ScreenSaverOff
cInt2XScreenSaverState (#const ScreenSaverDisabled) = ScreenSaverDisabled
cInt2XScreenSaverState _ = error "Unknown state in xScreenSaverQueryInfo"
instance Storable XScreenSaverState where
sizeOf _ = sizeOf (undefined :: CInt)
alignment _ = alignment (undefined :: CInt)
poke p xsss = poke (castPtr p) (xScreenSaverState2CInt xsss)
peek p = cInt2XScreenSaverState `fmap` peek (castPtr p)
xScreenSaverKind2CInt :: XScreenSaverKind -> CInt
xScreenSaverKind2CInt ScreenSaverBlanked = #const ScreenSaverBlanked
xScreenSaverKind2CInt ScreenSaverInternal = #const ScreenSaverInternal
xScreenSaverKind2CInt ScreenSaverExternal = #const ScreenSaverExternal
cInt2XScreenSaverKind :: CInt -> XScreenSaverKind
cInt2XScreenSaverKind (#const ScreenSaverBlanked) = ScreenSaverBlanked
cInt2XScreenSaverKind (#const ScreenSaverInternal) = ScreenSaverInternal
cInt2XScreenSaverKind (#const ScreenSaverExternal) = ScreenSaverExternal
cInt2XScreenSaverKind _ = error "Unknown kind in xScreenSaverQueryInfo"
instance Storable XScreenSaverKind where
sizeOf _ = sizeOf (undefined :: CInt)
alignment _ = alignment (undefined :: CInt)
poke p xsss = poke (castPtr p) (xScreenSaverKind2CInt xsss)
peek p = cInt2XScreenSaverKind `fmap` peek (castPtr p)
instance Storable XScreenSaverInfo where
sizeOf _ = #{size XScreenSaverInfo}
-- FIXME: Is this right?
alignment _ = alignment (undefined :: CInt)
poke p xssi = do
#{poke XScreenSaverInfo, window } p $ xssi_window xssi
#{poke XScreenSaverInfo, state } p $ xssi_state xssi
#{poke XScreenSaverInfo, kind } p $ xssi_kind xssi
#{poke XScreenSaverInfo, til_or_since } p $ xssi_til_or_since xssi
#{poke XScreenSaverInfo, idle } p $ xssi_idle xssi
#{poke XScreenSaverInfo, eventMask } p $ xssi_event_mask xssi
peek p = return XScreenSaverInfo
`ap` (#{peek XScreenSaverInfo, window} p)
`ap` (#{peek XScreenSaverInfo, state} p)
`ap` (#{peek XScreenSaverInfo, kind} p)
`ap` (#{peek XScreenSaverInfo, til_or_since} p)
`ap` (#{peek XScreenSaverInfo, idle} p)
`ap` (#{peek XScreenSaverInfo, eventMask} p)
xScreenSaverQueryExtension :: Display -> IO (Maybe (CInt, CInt))
xScreenSaverQueryExtension dpy = wrapPtr2 (cXScreenSaverQueryExtension dpy) go
where go False _ _ = Nothing
go True eventbase errorbase = Just (fromIntegral eventbase, fromIntegral errorbase)
xScreenSaverQueryVersion :: Display -> IO (Maybe (CInt, CInt))
xScreenSaverQueryVersion dpy = wrapPtr2 (cXScreenSaverQueryVersion dpy) go
where go False _ _ = Nothing
go True major minor = Just (fromIntegral major, fromIntegral minor)
wrapPtr2 :: (Storable a, Storable b) => (Ptr a -> Ptr b -> IO c) -> (c -> a -> b -> d) -> IO d
wrapPtr2 cfun f =
withPool $ \pool -> do aptr <- pooledMalloc pool
bptr <- pooledMalloc pool
ret <- cfun aptr bptr
a <- peek aptr
b <- peek bptr
return (f ret a b)
-- | xScreenSaverQueryInfo returns information about the current state of the
-- screen server. If the xScreenSaver extension is not available, it returns Nothing
xScreenSaverQueryInfo :: Display -> IO (Maybe XScreenSaverInfo)
xScreenSaverQueryInfo dpy = do
p <- cXScreenSaverAllocInfo
if p == nullPtr then return Nothing else do
s <- cXScreenSaverQueryInfo dpy (defaultRootWindow dpy) p
if s == 0 then return Nothing else do
xssi <- peek p
cXFree p
return (Just xssi)
foreign import ccall "XScreenSaverQueryExtension"
cXScreenSaverQueryExtension :: Display -> Ptr CInt -> Ptr CInt -> IO Bool
foreign import ccall "XScreenSaverQueryVersion"
cXScreenSaverQueryVersion :: Display -> Ptr CInt -> Ptr CInt -> IO Bool
foreign import ccall "XScreenSaverAllocInfo"
cXScreenSaverAllocInfo :: IO (Ptr XScreenSaverInfo)
foreign import ccall "XScreenSaverQueryInfo"
cXScreenSaverQueryInfo :: Display -> Drawable -> Ptr XScreenSaverInfo -> IO Status
foreign import ccall "XFree"
cXFree :: Ptr a -> IO CInt