2020-03-20 20:10:15 -04:00
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
-- | DBus module for X11 screensave/DPMS control
|
|
|
|
|
2020-04-01 20:17:47 -04:00
|
|
|
module XMonad.Internal.DBus.Screensaver
|
2020-03-20 23:47:02 -04:00
|
|
|
( exportScreensaver
|
|
|
|
, callToggle
|
|
|
|
, callQuery
|
|
|
|
, matchSignal
|
2021-11-20 19:35:24 -05:00
|
|
|
, ssSignalDep
|
2020-03-20 23:47:02 -04:00
|
|
|
) where
|
|
|
|
|
2021-11-11 00:11:15 -05:00
|
|
|
import Control.Monad (void)
|
2020-03-20 20:10:15 -04:00
|
|
|
|
2020-03-25 18:35:04 -04:00
|
|
|
import DBus
|
|
|
|
import DBus.Client
|
2021-11-20 19:35:24 -05:00
|
|
|
import qualified DBus.Introspection as I
|
2020-03-20 20:10:15 -04:00
|
|
|
|
2020-03-25 18:35:04 -04:00
|
|
|
import Graphics.X11.XScreenSaver
|
2021-06-19 00:54:01 -04:00
|
|
|
import Graphics.X11.Xlib.Display
|
2020-03-20 20:10:15 -04:00
|
|
|
|
2020-04-01 20:17:47 -04:00
|
|
|
import XMonad.Internal.DBus.Common
|
2021-11-07 13:35:08 -05:00
|
|
|
import XMonad.Internal.Dependency
|
2020-04-06 00:14:56 -04:00
|
|
|
import XMonad.Internal.Process
|
2020-03-20 20:10:15 -04:00
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
-- | Low-level functions
|
|
|
|
|
|
|
|
type SSState = Bool -- true is enabled
|
|
|
|
|
2021-11-09 00:59:17 -05:00
|
|
|
ssExecutable :: String
|
|
|
|
ssExecutable = "xset"
|
|
|
|
|
2020-03-20 20:10:15 -04:00
|
|
|
toggle :: IO SSState
|
|
|
|
toggle = do
|
|
|
|
st <- query
|
|
|
|
-- TODO figure out how not to do this with shell commands
|
2021-11-09 00:59:17 -05:00
|
|
|
void $ createProcess' $ proc ssExecutable $ "s" : args st
|
2020-03-20 20:10:15 -04:00
|
|
|
-- TODO this assumes the command succeeds
|
|
|
|
return $ not st
|
|
|
|
where
|
|
|
|
args s = if s then ["off", "-dpms"] else ["on", "+dpms"]
|
|
|
|
|
|
|
|
query :: IO SSState
|
|
|
|
query = do
|
|
|
|
dpy <- openDisplay ""
|
|
|
|
xssi <- xScreenSaverQueryInfo dpy
|
|
|
|
closeDisplay dpy
|
|
|
|
return $ case xssi of
|
|
|
|
Just XScreenSaverInfo { xssi_state = ScreenSaverDisabled } -> False
|
|
|
|
Just XScreenSaverInfo { xssi_state = _ } -> True
|
|
|
|
-- TODO handle errors better (at least log them?)
|
|
|
|
Nothing -> False
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
-- | DBus Interface
|
|
|
|
--
|
2020-03-20 23:47:02 -04:00
|
|
|
-- Define a methods to toggle the screensaver. This methods will emit signal
|
|
|
|
-- with the new state when called. Define another method to get the current
|
|
|
|
-- state.
|
2020-03-20 20:10:15 -04:00
|
|
|
|
2021-06-21 23:41:57 -04:00
|
|
|
ssPath :: ObjectPath
|
|
|
|
ssPath = objectPath_ "/screensaver"
|
2020-03-20 20:10:15 -04:00
|
|
|
|
2020-03-20 23:47:02 -04:00
|
|
|
interface :: InterfaceName
|
2021-06-21 23:41:57 -04:00
|
|
|
interface = interfaceName_ "org.xmonad.Screensaver"
|
2020-03-20 20:10:15 -04:00
|
|
|
|
2020-03-20 23:47:02 -04:00
|
|
|
memState :: MemberName
|
2021-06-21 23:41:57 -04:00
|
|
|
memState = memberName_ "State"
|
2020-03-20 20:10:15 -04:00
|
|
|
|
2020-03-20 23:47:02 -04:00
|
|
|
memToggle :: MemberName
|
2021-06-21 23:41:57 -04:00
|
|
|
memToggle = memberName_ "Toggle"
|
2020-03-20 20:10:15 -04:00
|
|
|
|
2020-03-20 23:47:02 -04:00
|
|
|
memQuery :: MemberName
|
2021-06-21 23:41:57 -04:00
|
|
|
memQuery = memberName_ "Query"
|
2020-03-20 20:10:15 -04:00
|
|
|
|
2020-03-20 23:47:02 -04:00
|
|
|
sigCurrentState :: Signal
|
2021-06-21 23:41:57 -04:00
|
|
|
sigCurrentState = signal ssPath interface memState
|
2020-03-20 20:10:15 -04:00
|
|
|
|
2020-03-20 23:47:02 -04:00
|
|
|
ruleCurrentState :: MatchRule
|
|
|
|
ruleCurrentState = matchAny
|
2021-06-21 23:41:57 -04:00
|
|
|
{ matchPath = Just ssPath
|
2020-03-20 23:47:02 -04:00
|
|
|
, matchInterface = Just interface
|
|
|
|
, matchMember = Just memState
|
2020-03-20 20:10:15 -04:00
|
|
|
}
|
|
|
|
|
2020-03-20 23:47:02 -04:00
|
|
|
emitState :: Client -> SSState -> IO ()
|
|
|
|
emitState client sss = emit client $ sigCurrentState { signalBody = [toVariant sss] }
|
|
|
|
|
|
|
|
bodyGetCurrentState :: [Variant] -> Maybe SSState
|
|
|
|
bodyGetCurrentState [b] = fromVariant b :: Maybe SSState
|
|
|
|
bodyGetCurrentState _ = Nothing
|
|
|
|
|
2020-04-01 20:17:47 -04:00
|
|
|
--------------------------------------------------------------------------------
|
2020-03-20 23:47:02 -04:00
|
|
|
-- | Exported haskell API
|
|
|
|
|
2021-11-21 22:47:43 -05:00
|
|
|
exportScreensaver :: Maybe Client -> FeatureIO
|
2021-11-20 12:40:53 -05:00
|
|
|
exportScreensaver client = Feature
|
2021-11-21 22:47:43 -05:00
|
|
|
{ ftrMaybeAction = DBusBus_ cmd xmonadBusName client [Executable ssExecutable]
|
2021-11-20 19:35:24 -05:00
|
|
|
, ftrName = "screensaver interface"
|
|
|
|
, ftrWarning = Default
|
2021-11-11 00:11:15 -05:00
|
|
|
}
|
|
|
|
where
|
2021-11-21 22:47:43 -05:00
|
|
|
cmd cl = export cl ssPath defaultInterface
|
2021-11-11 00:11:15 -05:00
|
|
|
{ interfaceName = interface
|
|
|
|
, interfaceMethods =
|
2021-11-21 22:47:43 -05:00
|
|
|
[ autoMethod memToggle $ emitState cl =<< toggle
|
2021-11-11 00:11:15 -05:00
|
|
|
, autoMethod memQuery query
|
|
|
|
]
|
2021-11-20 19:35:24 -05:00
|
|
|
, interfaceSignals = [sig]
|
|
|
|
}
|
|
|
|
sig = I.Signal
|
|
|
|
{ I.signalName = memState
|
|
|
|
, I.signalArgs =
|
|
|
|
[
|
|
|
|
I.SignalArg
|
|
|
|
{ I.signalArgName = "enabled"
|
|
|
|
, I.signalArgType = TypeBoolean
|
|
|
|
}
|
|
|
|
]
|
2021-11-11 00:11:15 -05:00
|
|
|
}
|
|
|
|
|
2021-11-21 22:47:43 -05:00
|
|
|
callToggle :: Maybe Client -> FeatureIO
|
2021-11-21 18:18:09 -05:00
|
|
|
callToggle client =
|
|
|
|
(featureEndpoint xmonadBusName ssPath interface memToggle client)
|
|
|
|
{ ftrName = "screensaver toggle" }
|
|
|
|
-- callToggle client = Feature
|
|
|
|
-- { ftrMaybeAction = cmd
|
|
|
|
-- , ftrName = "screensaver toggle"
|
|
|
|
-- , ftrWarning = Default
|
|
|
|
-- , ftrChildren = [xDbusDep ssPath interface $ Method_ memToggle]
|
|
|
|
-- }
|
|
|
|
-- where
|
|
|
|
-- cmd = void $ callMethod client xmonadBusName ssPath interface memToggle
|
2020-03-20 20:10:15 -04:00
|
|
|
|
2021-11-21 17:54:00 -05:00
|
|
|
callQuery :: Client -> IO (Maybe SSState)
|
|
|
|
callQuery client = do
|
|
|
|
reply <- callMethod client xmonadBusName ssPath interface memQuery
|
2021-11-21 16:58:01 -05:00
|
|
|
return $ either (const Nothing) bodyGetCurrentState reply
|
2020-03-20 20:10:15 -04:00
|
|
|
|
|
|
|
matchSignal :: (Maybe SSState -> IO ()) -> IO SignalHandler
|
2020-03-20 23:47:02 -04:00
|
|
|
matchSignal cb = addMatchCallback ruleCurrentState $ cb . bodyGetCurrentState
|
2021-11-21 00:53:45 -05:00
|
|
|
|
2021-11-21 22:47:43 -05:00
|
|
|
-- ssSignalDep :: Dependency
|
|
|
|
ssSignalDep :: Endpoint
|
|
|
|
-- ssSignalDep = DBusEndpoint xmonadBus $ Endpoint ssPath interface
|
|
|
|
-- $ Signal_ memState
|
|
|
|
ssSignalDep = Endpoint ssPath interface $ Signal_ memState
|