ENH make better error messages for features
This commit is contained in:
parent
b28279794c
commit
81830a8e96
|
@ -40,12 +40,9 @@ import XMonad.Hooks.DynamicLog
|
||||||
)
|
)
|
||||||
import XMonad.Internal.Command.Power (hasBattery)
|
import XMonad.Internal.Command.Power (hasBattery)
|
||||||
import XMonad.Internal.DBus.Brightness.IntelBacklight
|
import XMonad.Internal.DBus.Brightness.IntelBacklight
|
||||||
( curFileDep
|
|
||||||
, maxFileDep
|
|
||||||
)
|
|
||||||
-- import XMonad.Internal.DBus.Common (xmonadBus)
|
-- import XMonad.Internal.DBus.Common (xmonadBus)
|
||||||
-- import XMonad.Internal.DBus.Control (pathExists)
|
-- import XMonad.Internal.DBus.Control (pathExists)
|
||||||
import XMonad.Internal.DBus.Screensaver (ssDep)
|
import XMonad.Internal.DBus.Screensaver (ssSignalDep)
|
||||||
import XMonad.Internal.Dependency
|
import XMonad.Internal.Dependency
|
||||||
-- import XMonad.Internal.Shell (fmtCmd)
|
-- import XMonad.Internal.Shell (fmtCmd)
|
||||||
import qualified XMonad.Internal.Theme as T
|
import qualified XMonad.Internal.Theme as T
|
||||||
|
@ -226,20 +223,8 @@ dateCmd = CmdSpec
|
||||||
-- some commands depend on the presence of interfaces that can only be
|
-- some commands depend on the presence of interfaces that can only be
|
||||||
-- determined at runtime; define these checks here
|
-- determined at runtime; define these checks here
|
||||||
|
|
||||||
-- noSetup :: Monad m => a -> m (Maybe a)
|
|
||||||
-- noSetup = return . Just
|
|
||||||
|
|
||||||
-- toJust :: a -> Bool -> Maybe a
|
|
||||||
-- toJust x b = if b then Just x else Nothing
|
|
||||||
|
|
||||||
dbusDep :: Bool -> BusName -> ObjectPath -> InterfaceName -> DBusMember -> Dependency
|
dbusDep :: Bool -> BusName -> ObjectPath -> InterfaceName -> DBusMember -> Dependency
|
||||||
dbusDep usesys bus obj iface mem = DBusEndpoint
|
dbusDep usesys bus obj iface mem = DBusEndpoint (Bus usesys bus) (Endpoint obj iface mem)
|
||||||
{ ddDbusBus = bus
|
|
||||||
, ddDbusSystem = usesys
|
|
||||||
, ddDbusObject = obj
|
|
||||||
, ddDbusInterface = iface
|
|
||||||
, ddDbusMember = mem
|
|
||||||
}
|
|
||||||
|
|
||||||
-- in the case of network interfaces, assume that the system uses systemd in
|
-- in the case of network interfaces, assume that the system uses systemd in
|
||||||
-- which case ethernet interfaces always start with "en" and wireless
|
-- which case ethernet interfaces always start with "en" and wireless
|
||||||
|
@ -303,14 +288,15 @@ getWireless = do
|
||||||
getEthernet :: IO (MaybeExe CmdSpec)
|
getEthernet :: IO (MaybeExe CmdSpec)
|
||||||
getEthernet = do
|
getEthernet = do
|
||||||
i <- readInterface isEthernet
|
i <- readInterface isEthernet
|
||||||
evalFeature $ maybe BlankFeature (featureRun [dep] . ethernetCmd) i
|
evalFeature $ maybe BlankFeature (featureRun "ethernet status indicator" [dep] . ethernetCmd) i
|
||||||
where
|
where
|
||||||
dep = dbusDep True devBus devPath devInterface $ Method_ devGetByIP
|
dep = dbusDep True devBus devPath devInterface $ Method_ devGetByIP
|
||||||
|
|
||||||
getBattery :: BarFeature
|
getBattery :: BarFeature
|
||||||
getBattery = Feature
|
getBattery = Feature
|
||||||
{ ftrAction = batteryCmd
|
{ ftrAction = batteryCmd
|
||||||
, ftrSilent = False
|
, ftrName = "battery level indicator"
|
||||||
|
, ftrWarning = Default
|
||||||
, ftrChildren = [IOTest hasBattery]
|
, ftrChildren = [IOTest hasBattery]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -319,7 +305,8 @@ type BarFeature = Feature CmdSpec
|
||||||
getVPN :: BarFeature
|
getVPN :: BarFeature
|
||||||
getVPN = Feature
|
getVPN = Feature
|
||||||
{ ftrAction = vpnCmd
|
{ ftrAction = vpnCmd
|
||||||
, ftrSilent = False
|
, ftrName = "VPN status indicator"
|
||||||
|
, ftrWarning = Default
|
||||||
, ftrChildren = [d, v]
|
, ftrChildren = [d, v]
|
||||||
}
|
}
|
||||||
where
|
where
|
||||||
|
@ -329,7 +316,8 @@ getVPN = Feature
|
||||||
getBt :: BarFeature
|
getBt :: BarFeature
|
||||||
getBt = Feature
|
getBt = Feature
|
||||||
{ ftrAction = btCmd
|
{ ftrAction = btCmd
|
||||||
, ftrSilent = False
|
, ftrName = "bluetooth status indicator"
|
||||||
|
, ftrWarning = Default
|
||||||
, ftrChildren = [dep]
|
, ftrChildren = [dep]
|
||||||
}
|
}
|
||||||
where
|
where
|
||||||
|
@ -338,22 +326,25 @@ getBt = Feature
|
||||||
getAlsa :: BarFeature
|
getAlsa :: BarFeature
|
||||||
getAlsa = Feature
|
getAlsa = Feature
|
||||||
{ ftrAction = alsaCmd
|
{ ftrAction = alsaCmd
|
||||||
, ftrSilent = False
|
, ftrName = "volume level indicator"
|
||||||
, ftrChildren = [exe "alsactl"]
|
, ftrWarning = Default
|
||||||
|
, ftrChildren = [Executable "alsactl"]
|
||||||
}
|
}
|
||||||
|
|
||||||
getBl :: BarFeature
|
getBl :: BarFeature
|
||||||
getBl = Feature
|
getBl = Feature
|
||||||
{ ftrAction = blCmd
|
{ ftrAction = blCmd
|
||||||
, ftrSilent = False
|
, ftrName = "Intel backlight indicator"
|
||||||
, ftrChildren = [curFileDep, maxFileDep]
|
, ftrWarning = Default
|
||||||
|
, ftrChildren = [intelBacklightSignalDep]
|
||||||
}
|
}
|
||||||
|
|
||||||
getSs :: BarFeature
|
getSs :: BarFeature
|
||||||
getSs = Feature
|
getSs = Feature
|
||||||
{ ftrAction = ssCmd
|
{ ftrAction = ssCmd
|
||||||
, ftrSilent = False
|
, ftrName = "screensaver indicator"
|
||||||
, ftrChildren = [ssDep]
|
, ftrWarning = Default
|
||||||
|
, ftrChildren = [ssSignalDep]
|
||||||
}
|
}
|
||||||
|
|
||||||
getAllCommands :: [MaybeExe CmdSpec] -> IO BarRegions
|
getAllCommands :: [MaybeExe CmdSpec] -> IO BarRegions
|
||||||
|
|
|
@ -47,8 +47,8 @@ myDmenuNetworks = "networkmanager_dmenu"
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
-- | Other internal functions
|
-- | Other internal functions
|
||||||
|
|
||||||
spawnDmenuCmd :: [String] -> FeatureX
|
spawnDmenuCmd :: String -> [String] -> FeatureX
|
||||||
spawnDmenuCmd = featureSpawnCmd myDmenuCmd
|
spawnDmenuCmd n = featureSpawnCmd n myDmenuCmd
|
||||||
|
|
||||||
themeArgs :: String -> [String]
|
themeArgs :: String -> [String]
|
||||||
themeArgs hexColor =
|
themeArgs hexColor =
|
||||||
|
@ -63,7 +63,7 @@ myDmenuMatchingArgs = ["-i"] -- case insensitivity
|
||||||
-- | Exported Commands
|
-- | Exported Commands
|
||||||
|
|
||||||
runDevMenu :: FeatureX
|
runDevMenu :: FeatureX
|
||||||
runDevMenu = featureRun [exe myDmenuDevices] $ do
|
runDevMenu = featureRun "device manager" [Executable myDmenuDevices] $ do
|
||||||
c <- io $ getXdgDirectory XdgConfig "rofi/devices.yml"
|
c <- io $ getXdgDirectory XdgConfig "rofi/devices.yml"
|
||||||
spawnCmd myDmenuDevices
|
spawnCmd myDmenuDevices
|
||||||
$ ["-c", c]
|
$ ["-c", c]
|
||||||
|
@ -71,7 +71,7 @@ runDevMenu = featureRun [exe myDmenuDevices] $ do
|
||||||
++ myDmenuMatchingArgs
|
++ myDmenuMatchingArgs
|
||||||
|
|
||||||
runBwMenu :: FeatureX
|
runBwMenu :: FeatureX
|
||||||
runBwMenu = featureRun [exe myDmenuPasswords] $
|
runBwMenu = featureRun "password manager" [Executable myDmenuPasswords] $
|
||||||
spawnCmd myDmenuPasswords $ ["-c"] ++ themeArgs "#bb6600" ++ myDmenuMatchingArgs
|
spawnCmd myDmenuPasswords $ ["-c"] ++ themeArgs "#bb6600" ++ myDmenuMatchingArgs
|
||||||
|
|
||||||
-- TODO this is weirdly inverted
|
-- TODO this is weirdly inverted
|
||||||
|
@ -83,7 +83,8 @@ runShowKeys x = addName "Show Keybindings" $ do
|
||||||
$ defNoteError { body = Just $ Text "could not display keymap" }
|
$ defNoteError { body = Just $ Text "could not display keymap" }
|
||||||
|
|
||||||
runDMenuShowKeys :: [((KeyMask, KeySym), NamedAction)] -> FeatureX
|
runDMenuShowKeys :: [((KeyMask, KeySym), NamedAction)] -> FeatureX
|
||||||
runDMenuShowKeys kbs = featureRun [exe myDmenuCmd] $ io $ do
|
runDMenuShowKeys kbs =
|
||||||
|
featureRun "keyboard shortcut menu" [Executable myDmenuCmd] $ io $ do
|
||||||
(h, _, _, _) <- createProcess' $ (shell' cmd) { std_in = CreatePipe }
|
(h, _, _, _) <- createProcess' $ (shell' cmd) { std_in = CreatePipe }
|
||||||
forM_ h $ \h' -> hPutStr h' (unlines $ showKm kbs) >> hClose h'
|
forM_ h $ \h' -> hPutStr h' (unlines $ showKm kbs) >> hClose h'
|
||||||
where
|
where
|
||||||
|
@ -91,13 +92,14 @@ runDMenuShowKeys kbs = featureRun [exe myDmenuCmd] $ io $ do
|
||||||
++ themeArgs "#7f66ff" ++ myDmenuMatchingArgs
|
++ themeArgs "#7f66ff" ++ myDmenuMatchingArgs
|
||||||
|
|
||||||
runCmdMenu :: FeatureX
|
runCmdMenu :: FeatureX
|
||||||
runCmdMenu = spawnDmenuCmd ["-show", "run"]
|
runCmdMenu = spawnDmenuCmd "command menu" ["-show", "run"]
|
||||||
|
|
||||||
runAppMenu :: FeatureX
|
runAppMenu :: FeatureX
|
||||||
runAppMenu = spawnDmenuCmd ["-show", "drun"]
|
runAppMenu = spawnDmenuCmd "app launcher" ["-show", "drun"]
|
||||||
|
|
||||||
runClipMenu :: FeatureX
|
runClipMenu :: FeatureX
|
||||||
runClipMenu = featureRun [exe myDmenuCmd, exe "greenclip"]
|
runClipMenu =
|
||||||
|
featureRun "clipboard manager" [Executable myDmenuCmd, Executable "greenclip"]
|
||||||
$ spawnCmd myDmenuCmd args
|
$ spawnCmd myDmenuCmd args
|
||||||
where
|
where
|
||||||
args = [ "-modi", "\"clipboard:greenclip print\""
|
args = [ "-modi", "\"clipboard:greenclip print\""
|
||||||
|
@ -106,10 +108,12 @@ runClipMenu = featureRun [exe myDmenuCmd, exe "greenclip"]
|
||||||
] ++ themeArgs "#00c44e"
|
] ++ themeArgs "#00c44e"
|
||||||
|
|
||||||
runWinMenu :: FeatureX
|
runWinMenu :: FeatureX
|
||||||
runWinMenu = spawnDmenuCmd ["-show", "window"]
|
runWinMenu = spawnDmenuCmd "window switcher" ["-show", "window"]
|
||||||
|
|
||||||
runNetMenu :: FeatureX
|
runNetMenu :: FeatureX
|
||||||
runNetMenu = featureSpawnCmd myDmenuNetworks $ themeArgs "#ff3333"
|
runNetMenu =
|
||||||
|
featureSpawnCmd "network control menu" myDmenuNetworks $ themeArgs "#ff3333"
|
||||||
|
|
||||||
runAutorandrMenu :: FeatureX
|
runAutorandrMenu :: FeatureX
|
||||||
runAutorandrMenu = featureSpawnCmd myDmenuMonitors $ themeArgs "#ff0066"
|
runAutorandrMenu =
|
||||||
|
featureSpawnCmd "autorandr menu" myDmenuMonitors $ themeArgs "#ff0066"
|
||||||
|
|
|
@ -91,11 +91,12 @@ ethernetIface = "enp7s0f1"
|
||||||
-- | Some nice apps
|
-- | Some nice apps
|
||||||
|
|
||||||
runTerm :: FeatureX
|
runTerm :: FeatureX
|
||||||
runTerm = featureSpawn myTerm
|
runTerm = featureSpawn "terminal" myTerm
|
||||||
|
|
||||||
runTMux :: FeatureX
|
runTMux :: FeatureX
|
||||||
runTMux = featureRun [exe myTerm, exe "tmux", exe "bash"] cmd
|
runTMux = featureRun "terminal multiplexer" deps cmd
|
||||||
where
|
where
|
||||||
|
deps = [Executable myTerm, Executable "tmux", Executable "bash"]
|
||||||
cmd = spawn
|
cmd = spawn
|
||||||
$ "tmux has-session"
|
$ "tmux has-session"
|
||||||
#!&& fmtCmd myTerm ["-e", "bash", "-c", singleQuote c]
|
#!&& fmtCmd myTerm ["-e", "bash", "-c", singleQuote c]
|
||||||
|
@ -104,35 +105,37 @@ runTMux = featureRun [exe myTerm, exe "tmux", exe "bash"] cmd
|
||||||
msg = "could not connect to tmux session"
|
msg = "could not connect to tmux session"
|
||||||
|
|
||||||
runCalc :: FeatureX
|
runCalc :: FeatureX
|
||||||
runCalc = featureRun [exe myTerm, exe "R"] $ spawnCmd myTerm ["-e", "R"]
|
runCalc = featureRun "calculator" [Executable myTerm, Executable "R"]
|
||||||
|
$ spawnCmd myTerm ["-e", "R"]
|
||||||
|
|
||||||
runBrowser :: FeatureX
|
runBrowser :: FeatureX
|
||||||
runBrowser = featureSpawn myBrowser
|
runBrowser = featureSpawn "web browser" myBrowser
|
||||||
|
|
||||||
runEditor :: FeatureX
|
runEditor :: FeatureX
|
||||||
runEditor = featureSpawnCmd myEditor
|
runEditor = featureSpawnCmd "text editor" myEditor
|
||||||
["-c", "-e", doubleQuote "(select-frame-set-input-focus (selected-frame))"]
|
["-c", "-e", doubleQuote "(select-frame-set-input-focus (selected-frame))"]
|
||||||
|
|
||||||
runFileManager :: FeatureX
|
runFileManager :: FeatureX
|
||||||
runFileManager = featureSpawn "pcmanfm"
|
runFileManager = featureSpawn "file browser" "pcmanfm"
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
-- | Multimedia Commands
|
-- | Multimedia Commands
|
||||||
|
|
||||||
runMultimediaIfInstalled :: String -> FeatureX
|
runMultimediaIfInstalled :: String -> String -> FeatureX
|
||||||
runMultimediaIfInstalled cmd = featureSpawnCmd myMultimediaCtl [cmd]
|
runMultimediaIfInstalled n cmd =
|
||||||
|
featureSpawnCmd (n ++ " multimedia control") myMultimediaCtl [cmd]
|
||||||
|
|
||||||
runTogglePlay :: FeatureX
|
runTogglePlay :: FeatureX
|
||||||
runTogglePlay = runMultimediaIfInstalled "play-pause"
|
runTogglePlay = runMultimediaIfInstalled "play/pause" "play-pause"
|
||||||
|
|
||||||
runPrevTrack :: FeatureX
|
runPrevTrack :: FeatureX
|
||||||
runPrevTrack = runMultimediaIfInstalled "previous"
|
runPrevTrack = runMultimediaIfInstalled "previous track" "previous"
|
||||||
|
|
||||||
runNextTrack :: FeatureX
|
runNextTrack :: FeatureX
|
||||||
runNextTrack = runMultimediaIfInstalled "next"
|
runNextTrack = runMultimediaIfInstalled "next track" "next"
|
||||||
|
|
||||||
runStopPlay :: FeatureX
|
runStopPlay :: FeatureX
|
||||||
runStopPlay = runMultimediaIfInstalled "stop"
|
runStopPlay = runMultimediaIfInstalled "stop playback" "stop"
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
-- | Volume Commands
|
-- | Volume Commands
|
||||||
|
@ -146,42 +149,49 @@ playSound file = do
|
||||||
-- paplay seems to have less latency than aplay
|
-- paplay seems to have less latency than aplay
|
||||||
spawnCmd "paplay" [p]
|
spawnCmd "paplay" [p]
|
||||||
|
|
||||||
featureSound :: FilePath -> X () -> X () -> FeatureX
|
featureSound :: String -> FilePath -> X () -> X () -> FeatureX
|
||||||
featureSound file pre post = featureRun [exe "paplay"]
|
featureSound n file pre post =
|
||||||
|
featureRun ("volume " ++ n ++ " control") [Executable "paplay"]
|
||||||
$ pre >> playSound file >> post
|
$ pre >> playSound file >> post
|
||||||
|
|
||||||
runVolumeDown :: FeatureX
|
runVolumeDown :: FeatureX
|
||||||
runVolumeDown = featureSound volumeChangeSound (return ()) $ void (lowerVolume 2)
|
runVolumeDown = featureSound "up" volumeChangeSound (return ()) $ void (lowerVolume 2)
|
||||||
|
|
||||||
runVolumeUp :: FeatureX
|
runVolumeUp :: FeatureX
|
||||||
runVolumeUp = featureSound volumeChangeSound (return ()) $ void (raiseVolume 2)
|
runVolumeUp = featureSound "down" volumeChangeSound (return ()) $ void (raiseVolume 2)
|
||||||
|
|
||||||
runVolumeMute :: FeatureX
|
runVolumeMute :: FeatureX
|
||||||
runVolumeMute = featureSound volumeChangeSound (void toggleMute) $ return ()
|
runVolumeMute = featureSound "mute" volumeChangeSound (void toggleMute) $ return ()
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
-- | Notification control
|
-- | Notification control
|
||||||
|
|
||||||
runNotificationCmd :: String -> FeatureX
|
runNotificationCmd :: String -> String -> FeatureX
|
||||||
runNotificationCmd cmd = featureSpawnCmd myNotificationCtrl [cmd]
|
runNotificationCmd n cmd =
|
||||||
|
featureSpawnCmd (n ++ " control") myNotificationCtrl [cmd]
|
||||||
|
|
||||||
runNotificationClose :: FeatureX
|
runNotificationClose :: FeatureX
|
||||||
runNotificationClose = runNotificationCmd "close"
|
runNotificationClose = runNotificationCmd "close notification" "close"
|
||||||
|
|
||||||
runNotificationCloseAll :: FeatureX
|
runNotificationCloseAll :: FeatureX
|
||||||
runNotificationCloseAll = runNotificationCmd "close-all"
|
runNotificationCloseAll =
|
||||||
|
runNotificationCmd "close all notifications" "close-all"
|
||||||
|
|
||||||
runNotificationHistory :: FeatureX
|
runNotificationHistory :: FeatureX
|
||||||
runNotificationHistory = runNotificationCmd "history-pop"
|
runNotificationHistory =
|
||||||
|
runNotificationCmd "see notification history" "history-pop"
|
||||||
|
|
||||||
runNotificationContext :: FeatureX
|
runNotificationContext :: FeatureX
|
||||||
runNotificationContext = runNotificationCmd "context"
|
runNotificationContext =
|
||||||
|
runNotificationCmd "open notification context" "context"
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
-- | System commands
|
-- | System commands
|
||||||
|
|
||||||
runToggleBluetooth :: FeatureX
|
runToggleBluetooth :: FeatureX
|
||||||
runToggleBluetooth = featureRun [exe myBluetooth] $ spawn
|
runToggleBluetooth =
|
||||||
|
featureRun "bluetooth toggle" [Executable myBluetooth]
|
||||||
|
$ spawn
|
||||||
$ myBluetooth ++ " show | grep -q \"Powered: no\""
|
$ myBluetooth ++ " show | grep -q \"Powered: no\""
|
||||||
#!&& "a=on"
|
#!&& "a=on"
|
||||||
#!|| "a=off"
|
#!|| "a=off"
|
||||||
|
@ -189,7 +199,8 @@ runToggleBluetooth = featureRun [exe myBluetooth] $ spawn
|
||||||
#!&& fmtNotifyCmd defNoteInfo { body = Just $ Text "bluetooth powered $a" }
|
#!&& fmtNotifyCmd defNoteInfo { body = Just $ Text "bluetooth powered $a" }
|
||||||
|
|
||||||
runToggleEthernet :: FeatureX
|
runToggleEthernet :: FeatureX
|
||||||
runToggleEthernet = featureRun [exe "nmcli"] $ spawn
|
runToggleEthernet = featureRun "ethernet toggle" [Executable "nmcli"]
|
||||||
|
$ spawn
|
||||||
$ "nmcli -g GENERAL.STATE device show " ++ ethernetIface ++ " | grep -q disconnected"
|
$ "nmcli -g GENERAL.STATE device show " ++ ethernetIface ++ " | grep -q disconnected"
|
||||||
#!&& "a=connect"
|
#!&& "a=connect"
|
||||||
#!|| "a=disconnect"
|
#!|| "a=disconnect"
|
||||||
|
@ -197,14 +208,14 @@ runToggleEthernet = featureRun [exe "nmcli"] $ spawn
|
||||||
#!&& fmtNotifyCmd defNoteInfo { body = Just $ Text "ethernet \"$a\"ed" }
|
#!&& fmtNotifyCmd defNoteInfo { body = Just $ Text "ethernet \"$a\"ed" }
|
||||||
|
|
||||||
runStartISyncTimer :: FeatureX
|
runStartISyncTimer :: FeatureX
|
||||||
runStartISyncTimer = featureRun [userUnit "mbsync.timer"]
|
runStartISyncTimer = featureRun "isync timer" [userUnit "mbsync.timer"]
|
||||||
$ spawn
|
$ spawn
|
||||||
$ "systemctl --user start mbsync.timer"
|
$ "systemctl --user start mbsync.timer"
|
||||||
#!&& fmtNotifyCmd defNoteInfo { body = Just $ Text "Isync timer started" }
|
#!&& fmtNotifyCmd defNoteInfo { body = Just $ Text "Isync timer started" }
|
||||||
#!|| fmtNotifyCmd defNoteError { body = Just $ Text "Isync timer failed to start" }
|
#!|| fmtNotifyCmd defNoteError { body = Just $ Text "Isync timer failed to start" }
|
||||||
|
|
||||||
runStartISyncService :: FeatureX
|
runStartISyncService :: FeatureX
|
||||||
runStartISyncService = featureRun [userUnit "mbsync.service"]
|
runStartISyncService = featureRun "isync" [userUnit "mbsync.service"]
|
||||||
$ spawn
|
$ spawn
|
||||||
$ "systemctl --user start mbsync.service"
|
$ "systemctl --user start mbsync.service"
|
||||||
#!&& fmtNotifyCmd defNoteInfo { body = Just $ Text "Isync completed" }
|
#!&& fmtNotifyCmd defNoteInfo { body = Just $ Text "Isync completed" }
|
||||||
|
@ -248,25 +259,26 @@ getCaptureDir = do
|
||||||
where
|
where
|
||||||
fallback = (</> ".local/share") <$> getHomeDirectory
|
fallback = (</> ".local/share") <$> getHomeDirectory
|
||||||
|
|
||||||
runFlameshot :: String -> FeatureX
|
runFlameshot :: String -> String -> FeatureX
|
||||||
runFlameshot mode = featureRun [exe myCapture] $ do
|
runFlameshot n mode = featureRun n [Executable myCapture] $ do
|
||||||
ssDir <- io getCaptureDir
|
ssDir <- io getCaptureDir
|
||||||
spawnCmd myCapture $ mode : ["-p", ssDir]
|
spawnCmd myCapture $ mode : ["-p", ssDir]
|
||||||
|
|
||||||
-- TODO this will steal focus from the current window (and puts it
|
-- TODO this will steal focus from the current window (and puts it
|
||||||
-- in the root window?) ...need to fix
|
-- in the root window?) ...need to fix
|
||||||
runAreaCapture :: FeatureX
|
runAreaCapture :: FeatureX
|
||||||
runAreaCapture = runFlameshot "gui"
|
runAreaCapture = runFlameshot "screen area capture" "gui"
|
||||||
|
|
||||||
-- myWindowCap = "screencap -w" --external script
|
-- myWindowCap = "screencap -w" --external script
|
||||||
|
|
||||||
runDesktopCapture :: FeatureX
|
runDesktopCapture :: FeatureX
|
||||||
runDesktopCapture = runFlameshot "full"
|
runDesktopCapture = runFlameshot "fullscreen capture" "full"
|
||||||
|
|
||||||
runScreenCapture :: FeatureX
|
runScreenCapture :: FeatureX
|
||||||
runScreenCapture = runFlameshot "screen"
|
runScreenCapture = runFlameshot "screen capture" "screen"
|
||||||
|
|
||||||
runCaptureBrowser :: FeatureX
|
runCaptureBrowser :: FeatureX
|
||||||
runCaptureBrowser = featureRun [exe myImageBrowser] $ do
|
runCaptureBrowser =
|
||||||
|
featureRun "screen capture browser" [Executable myImageBrowser] $ do
|
||||||
dir <- io getCaptureDir
|
dir <- io getCaptureDir
|
||||||
spawnCmd myImageBrowser [dir]
|
spawnCmd myImageBrowser [dir]
|
||||||
|
|
|
@ -46,11 +46,7 @@ myOptimusManager = "optimus-manager"
|
||||||
-- | Core commands
|
-- | Core commands
|
||||||
|
|
||||||
runScreenLock :: Feature (X ())
|
runScreenLock :: Feature (X ())
|
||||||
runScreenLock = Feature
|
runScreenLock = featureSpawn "screen locker" myScreenlock
|
||||||
{ ftrAction = spawn myScreenlock
|
|
||||||
, ftrSilent = False
|
|
||||||
, ftrChildren = [exe myScreenlock]
|
|
||||||
}
|
|
||||||
|
|
||||||
runPowerOff :: X ()
|
runPowerOff :: X ()
|
||||||
runPowerOff = spawn "systemctl poweroff"
|
runPowerOff = spawn "systemctl poweroff"
|
||||||
|
@ -105,7 +101,8 @@ runOptimusPrompt' = do
|
||||||
#!&& "killall xmonad"
|
#!&& "killall xmonad"
|
||||||
|
|
||||||
runOptimusPrompt :: FeatureX
|
runOptimusPrompt :: FeatureX
|
||||||
runOptimusPrompt = featureRun [exe myOptimusManager] runOptimusPrompt'
|
runOptimusPrompt = featureRun "graphics switcher" [Executable myOptimusManager]
|
||||||
|
runOptimusPrompt'
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
-- | Universal power prompt
|
-- | Universal power prompt
|
||||||
|
|
|
@ -95,7 +95,7 @@ acpiPath = "/var/run/acpid.socket"
|
||||||
-- | Spawn a new thread that will listen for ACPI events on the acpid socket
|
-- | Spawn a new thread that will listen for ACPI events on the acpid socket
|
||||||
-- and send ClientMessage events when it receives them
|
-- and send ClientMessage events when it receives them
|
||||||
runPowermon :: FeatureIO
|
runPowermon :: FeatureIO
|
||||||
runPowermon = featureRun [pathR acpiPath] listenACPI
|
runPowermon = featureRun "ACPI event monitor" [pathR acpiPath] listenACPI
|
||||||
|
|
||||||
-- | Handle ClientMessage event containing and ACPI event (to be used in
|
-- | Handle ClientMessage event containing and ACPI event (to be used in
|
||||||
-- Xmonad's event hook)
|
-- Xmonad's event hook)
|
||||||
|
|
|
@ -34,13 +34,7 @@ memRemoved :: MemberName
|
||||||
memRemoved = memberName_ "InterfacesRemoved"
|
memRemoved = memberName_ "InterfacesRemoved"
|
||||||
|
|
||||||
dbusDep :: MemberName -> Dependency
|
dbusDep :: MemberName -> Dependency
|
||||||
dbusDep m = DBusEndpoint
|
dbusDep m = DBusEndpoint (Bus True bus) (Endpoint path interface $ Signal_ m)
|
||||||
{ ddDbusBus = bus
|
|
||||||
, ddDbusSystem = True
|
|
||||||
, ddDbusObject = path
|
|
||||||
, ddDbusInterface = interface
|
|
||||||
, ddDbusMember = Signal_ m
|
|
||||||
}
|
|
||||||
|
|
||||||
addedDep :: Dependency
|
addedDep :: Dependency
|
||||||
addedDep = dbusDep memAdded
|
addedDep = dbusDep memAdded
|
||||||
|
@ -91,4 +85,5 @@ listenDevices = do
|
||||||
$ playSoundMaybe p . f . signalBody
|
$ playSoundMaybe p . f . signalBody
|
||||||
|
|
||||||
runRemovableMon :: FeatureIO
|
runRemovableMon :: FeatureIO
|
||||||
runRemovableMon = featureRun [addedDep, removedDep] listenDevices
|
runRemovableMon =
|
||||||
|
featureRun "removeable device monitor" [addedDep, removedDep] listenDevices
|
||||||
|
|
|
@ -8,6 +8,7 @@ module XMonad.Internal.DBus.Brightness.Common
|
||||||
, brightnessExporter
|
, brightnessExporter
|
||||||
, callGetBrightness
|
, callGetBrightness
|
||||||
, matchSignal
|
, matchSignal
|
||||||
|
, signalDep
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Control.Monad (void)
|
import Control.Monad (void)
|
||||||
|
@ -16,6 +17,7 @@ import Data.Int (Int32)
|
||||||
|
|
||||||
import DBus
|
import DBus
|
||||||
import DBus.Client
|
import DBus.Client
|
||||||
|
import qualified DBus.Introspection as I
|
||||||
|
|
||||||
import XMonad.Internal.DBus.Common
|
import XMonad.Internal.DBus.Common
|
||||||
import XMonad.Internal.Dependency
|
import XMonad.Internal.Dependency
|
||||||
|
@ -37,6 +39,7 @@ data BrightnessConfig a b = BrightnessConfig
|
||||||
, bcGetMax :: IO a
|
, bcGetMax :: IO a
|
||||||
, bcPath :: ObjectPath
|
, bcPath :: ObjectPath
|
||||||
, bcInterface :: InterfaceName
|
, bcInterface :: InterfaceName
|
||||||
|
, bcName :: String
|
||||||
}
|
}
|
||||||
|
|
||||||
data BrightnessControls = BrightnessControls
|
data BrightnessControls = BrightnessControls
|
||||||
|
@ -47,25 +50,30 @@ data BrightnessControls = BrightnessControls
|
||||||
}
|
}
|
||||||
|
|
||||||
brightnessControls :: BrightnessConfig a b -> BrightnessControls
|
brightnessControls :: BrightnessConfig a b -> BrightnessControls
|
||||||
brightnessControls BrightnessConfig { bcPath = p, bcInterface = i } =
|
brightnessControls bc =
|
||||||
BrightnessControls
|
BrightnessControls
|
||||||
{ bctlMax = cb memMax
|
{ bctlMax = cb "max brightness" memMax
|
||||||
, bctlMin = cb memMin
|
, bctlMin = cb "min brightness" memMin
|
||||||
, bctlInc = cb memInc
|
, bctlInc = cb "increase brightness" memInc
|
||||||
, bctlDec = cb memDec
|
, bctlDec = cb "decrease brightness" memDec
|
||||||
}
|
}
|
||||||
where
|
where
|
||||||
cb = callBacklight p i
|
cb = callBacklight bc
|
||||||
|
|
||||||
callGetBrightness :: Num c => BrightnessConfig a b -> IO (Maybe c)
|
callGetBrightness :: Num c => BrightnessConfig a b -> IO (Maybe c)
|
||||||
callGetBrightness BrightnessConfig { bcPath = p, bcInterface = i } = do
|
callGetBrightness BrightnessConfig { bcPath = p, bcInterface = i } = do
|
||||||
reply <- callMethod $ methodCall p i memGet
|
reply <- callMethod $ methodCall p i memGet
|
||||||
return $ reply >>= bodyGetBrightness
|
return $ reply >>= bodyGetBrightness
|
||||||
|
|
||||||
|
signalDep :: BrightnessConfig a b -> Dependency
|
||||||
|
signalDep BrightnessConfig { bcPath = p, bcInterface = i } =
|
||||||
|
DBusEndpoint xmonadBus $ Endpoint p i $ Signal_ memCur
|
||||||
|
|
||||||
matchSignal :: Num c => BrightnessConfig a b -> (Maybe c -> IO ()) -> IO SignalHandler
|
matchSignal :: Num c => BrightnessConfig a b -> (Maybe c -> IO ()) -> IO SignalHandler
|
||||||
matchSignal BrightnessConfig { bcPath = p, bcInterface = i } cb = do
|
matchSignal BrightnessConfig { bcPath = p, bcInterface = i } cb = do
|
||||||
client <- connectSession
|
client <- connectSession
|
||||||
addMatch client brMatcher $ cb . bodyGetBrightness . signalBody
|
addMatch client brMatcher $ cb . bodyGetBrightness . signalBody
|
||||||
|
-- TODO disconnect here?
|
||||||
where
|
where
|
||||||
brMatcher = matchAny
|
brMatcher = matchAny
|
||||||
{ matchPath = Just p
|
{ matchPath = Just p
|
||||||
|
@ -78,10 +86,11 @@ matchSignal BrightnessConfig { bcPath = p, bcInterface = i } cb = do
|
||||||
|
|
||||||
brightnessExporter :: RealFrac b => [Dependency] -> BrightnessConfig a b
|
brightnessExporter :: RealFrac b => [Dependency] -> BrightnessConfig a b
|
||||||
-> Client -> FeatureIO
|
-> Client -> FeatureIO
|
||||||
brightnessExporter deps bc client = Feature
|
brightnessExporter deps bc@BrightnessConfig { bcName = n } client = Feature
|
||||||
{ ftrAction = exportBrightnessControls' bc client
|
{ ftrAction = exportBrightnessControls' bc client
|
||||||
, ftrSilent = False
|
, ftrName = n ++ " exporter"
|
||||||
, ftrChildren = deps
|
, ftrWarning = Default
|
||||||
|
, ftrChildren = DBusBus xmonadBus:deps
|
||||||
}
|
}
|
||||||
|
|
||||||
exportBrightnessControls' :: RealFrac b => BrightnessConfig a b -> Client -> IO ()
|
exportBrightnessControls' :: RealFrac b => BrightnessConfig a b -> Client -> IO ()
|
||||||
|
@ -98,7 +107,19 @@ exportBrightnessControls' bc client = do
|
||||||
, autoMethod' memDec bcDec
|
, autoMethod' memDec bcDec
|
||||||
, autoMethod memGet (round <$> funget maxval :: IO Int32)
|
, autoMethod memGet (round <$> funget maxval :: IO Int32)
|
||||||
]
|
]
|
||||||
|
, interfaceSignals = [sig]
|
||||||
}
|
}
|
||||||
|
where
|
||||||
|
sig = I.Signal
|
||||||
|
{ I.signalName = memCur
|
||||||
|
, I.signalArgs =
|
||||||
|
[
|
||||||
|
I.SignalArg
|
||||||
|
{ I.signalArgName = "brightness"
|
||||||
|
, I.signalArgType = TypeInt32
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
emitBrightness :: RealFrac b => BrightnessConfig a b -> Client -> b -> IO ()
|
emitBrightness :: RealFrac b => BrightnessConfig a b -> Client -> b -> IO ()
|
||||||
emitBrightness BrightnessConfig{ bcPath = p, bcInterface = i } client cur =
|
emitBrightness BrightnessConfig{ bcPath = p, bcInterface = i } client cur =
|
||||||
|
@ -106,11 +127,12 @@ emitBrightness BrightnessConfig{ bcPath = p, bcInterface = i } client cur =
|
||||||
where
|
where
|
||||||
sig = signal p i memCur
|
sig = signal p i memCur
|
||||||
|
|
||||||
callBacklight :: ObjectPath -> InterfaceName -> MemberName -> FeatureIO
|
callBacklight :: BrightnessConfig a b -> String -> MemberName -> FeatureIO
|
||||||
callBacklight p i m =
|
callBacklight BrightnessConfig { bcPath = p, bcInterface = i, bcName = n } controlName m =
|
||||||
Feature
|
Feature
|
||||||
{ ftrAction = void $ callMethod $ methodCall p i m
|
{ ftrAction = void $ callMethod $ methodCall p i m
|
||||||
, ftrSilent = False
|
, ftrName = unwords [n, controlName]
|
||||||
|
, ftrWarning = Default
|
||||||
, ftrChildren = [xDbusDep p i $ Method_ m]
|
, ftrChildren = [xDbusDep p i $ Method_ m]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,7 @@ module XMonad.Internal.DBus.Brightness.IntelBacklight
|
||||||
, matchSignalIB
|
, matchSignalIB
|
||||||
, exportIntelBacklight
|
, exportIntelBacklight
|
||||||
, intelBacklightControls
|
, intelBacklightControls
|
||||||
, curFileDep
|
, intelBacklightSignalDep
|
||||||
, maxFileDep
|
|
||||||
, blPath
|
, blPath
|
||||||
) where
|
) where
|
||||||
|
|
||||||
|
@ -78,6 +77,7 @@ intelBacklightConfig = BrightnessConfig
|
||||||
, bcGetMax = getMaxRawBrightness
|
, bcGetMax = getMaxRawBrightness
|
||||||
, bcPath = blPath
|
, bcPath = blPath
|
||||||
, bcInterface = interface
|
, bcInterface = interface
|
||||||
|
, bcName = "Intel backlight"
|
||||||
}
|
}
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
@ -89,6 +89,9 @@ curFileDep = pathRW curFile
|
||||||
maxFileDep :: Dependency
|
maxFileDep :: Dependency
|
||||||
maxFileDep = pathR maxFile
|
maxFileDep = pathR maxFile
|
||||||
|
|
||||||
|
intelBacklightSignalDep :: Dependency
|
||||||
|
intelBacklightSignalDep = signalDep intelBacklightConfig
|
||||||
|
|
||||||
exportIntelBacklight :: Client -> FeatureIO
|
exportIntelBacklight :: Client -> FeatureIO
|
||||||
exportIntelBacklight =
|
exportIntelBacklight =
|
||||||
brightnessExporter [curFileDep, maxFileDep] intelBacklightConfig
|
brightnessExporter [curFileDep, maxFileDep] intelBacklightConfig
|
||||||
|
|
|
@ -6,8 +6,9 @@ module XMonad.Internal.DBus.Common
|
||||||
, callMethod'
|
, callMethod'
|
||||||
, addMatchCallback
|
, addMatchCallback
|
||||||
, xmonadBus
|
, xmonadBus
|
||||||
|
, xmonadBusName
|
||||||
, xDbusDep
|
, xDbusDep
|
||||||
, initControls
|
-- , initControls
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import DBus
|
import DBus
|
||||||
|
@ -15,23 +16,22 @@ import DBus.Client
|
||||||
|
|
||||||
import XMonad.Internal.Dependency
|
import XMonad.Internal.Dependency
|
||||||
|
|
||||||
xmonadBus :: BusName
|
xmonadBusName :: BusName
|
||||||
xmonadBus = busName_ "org.xmonad"
|
xmonadBusName = busName_ "org.xmonad"
|
||||||
|
|
||||||
|
xmonadBus :: Bus
|
||||||
|
xmonadBus = Bus False xmonadBusName
|
||||||
|
|
||||||
xDbusDep :: ObjectPath -> InterfaceName -> DBusMember -> Dependency
|
xDbusDep :: ObjectPath -> InterfaceName -> DBusMember -> Dependency
|
||||||
xDbusDep o i m = DBusEndpoint
|
xDbusDep o i m = DBusEndpoint xmonadBus $ Endpoint o i m
|
||||||
{ ddDbusBus = xmonadBus
|
|
||||||
, ddDbusSystem = False
|
-- connectBus :: Bus -> IO (Maybe Client)
|
||||||
, ddDbusObject = o
|
|
||||||
, ddDbusInterface = i
|
|
||||||
, ddDbusMember = m
|
|
||||||
}
|
|
||||||
|
|
||||||
-- | Call a method and return its result if successful
|
-- | Call a method and return its result if successful
|
||||||
callMethod :: MethodCall -> IO (Maybe [Variant])
|
callMethod :: MethodCall -> IO (Maybe [Variant])
|
||||||
callMethod mc = do
|
callMethod mc = do
|
||||||
client <- connectSession
|
client <- connectSession
|
||||||
r <- callMethod' client (Just xmonadBus) mc
|
r <- callMethod' client (Just xmonadBusName) mc
|
||||||
disconnect client
|
disconnect client
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
@ -50,11 +50,11 @@ addMatchCallback rule cb = do
|
||||||
client <- connectSession
|
client <- connectSession
|
||||||
addMatch client rule $ cb . signalBody
|
addMatch client rule $ cb . signalBody
|
||||||
|
|
||||||
initControls :: Client -> (Client -> FeatureIO) -> (FeatureIO -> a) -> IO a
|
-- initControls :: Client -> (Client -> FeatureIO) -> (FeatureIO -> a) -> IO a
|
||||||
initControls client exporter controls = do
|
-- initControls client exporter controls = do
|
||||||
let x = exporter client
|
-- let x = exporter client
|
||||||
e <- evalFeature x
|
-- e <- evalFeature x
|
||||||
case e of
|
-- case e of
|
||||||
(Right c) -> c
|
-- (Right c) -> c
|
||||||
_ -> return ()
|
-- _ -> return ()
|
||||||
return $ controls x
|
-- return $ controls x
|
||||||
|
|
|
@ -19,7 +19,6 @@ import Data.Either
|
||||||
import DBus
|
import DBus
|
||||||
import DBus.Client
|
import DBus.Client
|
||||||
|
|
||||||
-- import XMonad.Internal.DBus.Brightness.Common
|
|
||||||
import XMonad.Internal.DBus.Brightness.IntelBacklight
|
import XMonad.Internal.DBus.Brightness.IntelBacklight
|
||||||
import XMonad.Internal.DBus.Common
|
import XMonad.Internal.DBus.Common
|
||||||
import XMonad.Internal.DBus.Screensaver
|
import XMonad.Internal.DBus.Screensaver
|
||||||
|
@ -42,7 +41,7 @@ startXMonadService = do
|
||||||
|
|
||||||
stopXMonadService :: Client -> IO ()
|
stopXMonadService :: Client -> IO ()
|
||||||
stopXMonadService client = do
|
stopXMonadService client = do
|
||||||
void $ releaseName client xmonadBus
|
void $ releaseName client xmonadBusName
|
||||||
disconnect client
|
disconnect client
|
||||||
|
|
||||||
getDBusClient :: IO (Maybe Client)
|
getDBusClient :: IO (Maybe Client)
|
||||||
|
@ -54,7 +53,7 @@ getDBusClient = do
|
||||||
|
|
||||||
requestXMonadName :: Client -> IO ()
|
requestXMonadName :: Client -> IO ()
|
||||||
requestXMonadName client = do
|
requestXMonadName client = do
|
||||||
res <- requestName client xmonadBus []
|
res <- requestName client xmonadBusName []
|
||||||
-- TODO if the client is not released on shutdown the owner will be
|
-- TODO if the client is not released on shutdown the owner will be
|
||||||
-- different
|
-- different
|
||||||
let msg | res == NamePrimaryOwner = Nothing
|
let msg | res == NamePrimaryOwner = Nothing
|
||||||
|
@ -64,7 +63,7 @@ requestXMonadName client = do
|
||||||
| otherwise = Just $ "unknown error when requesting " ++ xn
|
| otherwise = Just $ "unknown error when requesting " ++ xn
|
||||||
forM_ msg putStrLn
|
forM_ msg putStrLn
|
||||||
where
|
where
|
||||||
xn = "'" ++ formatBusName xmonadBus ++ "'"
|
xn = "'" ++ formatBusName xmonadBusName ++ "'"
|
||||||
|
|
||||||
pathExists :: Bool -> BusName -> ObjectPath -> IO Bool
|
pathExists :: Bool -> BusName -> ObjectPath -> IO Bool
|
||||||
pathExists sysbus n p = do
|
pathExists sysbus n p = do
|
||||||
|
|
|
@ -8,6 +8,7 @@ module XMonad.Internal.DBus.Screensaver
|
||||||
, matchSignal
|
, matchSignal
|
||||||
, ssPath
|
, ssPath
|
||||||
, ssDep
|
, ssDep
|
||||||
|
, ssSignalDep
|
||||||
, SSControls(..)
|
, SSControls(..)
|
||||||
) where
|
) where
|
||||||
|
|
||||||
|
@ -15,6 +16,7 @@ import Control.Monad (void)
|
||||||
|
|
||||||
import DBus
|
import DBus
|
||||||
import DBus.Client
|
import DBus.Client
|
||||||
|
import qualified DBus.Introspection as I
|
||||||
|
|
||||||
import Graphics.X11.XScreenSaver
|
import Graphics.X11.XScreenSaver
|
||||||
import Graphics.X11.Xlib.Display
|
import Graphics.X11.Xlib.Display
|
||||||
|
@ -34,6 +36,10 @@ ssExecutable = "xset"
|
||||||
ssDep :: Dependency
|
ssDep :: Dependency
|
||||||
ssDep = Executable ssExecutable
|
ssDep = Executable ssExecutable
|
||||||
|
|
||||||
|
ssSignalDep :: Dependency
|
||||||
|
ssSignalDep = DBusEndpoint xmonadBus $ Endpoint ssPath interface
|
||||||
|
$ Signal_ memState
|
||||||
|
|
||||||
toggle :: IO SSState
|
toggle :: IO SSState
|
||||||
toggle = do
|
toggle = do
|
||||||
st <- query
|
st <- query
|
||||||
|
@ -99,16 +105,12 @@ bodyGetCurrentState _ = Nothing
|
||||||
|
|
||||||
newtype SSControls = SSControls { ssToggle :: FeatureIO }
|
newtype SSControls = SSControls { ssToggle :: FeatureIO }
|
||||||
|
|
||||||
-- exportScreensaver :: Client -> IO SSControls
|
|
||||||
-- exportScreensaver client = initControls client exportScreensaver' controls
|
|
||||||
-- where
|
|
||||||
-- controls _ = SSControls { ssToggle = callToggle }
|
|
||||||
|
|
||||||
exportScreensaver :: Client -> FeatureIO
|
exportScreensaver :: Client -> FeatureIO
|
||||||
exportScreensaver client = Feature
|
exportScreensaver client = Feature
|
||||||
{ ftrAction = cmd
|
{ ftrAction = cmd
|
||||||
, ftrSilent = False
|
, ftrName = "screensaver interface"
|
||||||
, ftrChildren = [ssDep]
|
, ftrWarning = Default
|
||||||
|
, ftrChildren = [ssDep, DBusBus xmonadBus]
|
||||||
}
|
}
|
||||||
where
|
where
|
||||||
cmd = export client ssPath defaultInterface
|
cmd = export client ssPath defaultInterface
|
||||||
|
@ -117,12 +119,24 @@ exportScreensaver client = Feature
|
||||||
[ autoMethod memToggle $ emitState client =<< toggle
|
[ autoMethod memToggle $ emitState client =<< toggle
|
||||||
, autoMethod memQuery query
|
, autoMethod memQuery query
|
||||||
]
|
]
|
||||||
|
, interfaceSignals = [sig]
|
||||||
|
}
|
||||||
|
sig = I.Signal
|
||||||
|
{ I.signalName = memState
|
||||||
|
, I.signalArgs =
|
||||||
|
[
|
||||||
|
I.SignalArg
|
||||||
|
{ I.signalArgName = "enabled"
|
||||||
|
, I.signalArgType = TypeBoolean
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
callToggle :: FeatureIO
|
callToggle :: FeatureIO
|
||||||
callToggle = Feature
|
callToggle = Feature
|
||||||
{ ftrAction = cmd
|
{ ftrAction = cmd
|
||||||
, ftrSilent = False
|
, ftrName = "screensaver toggle"
|
||||||
|
, ftrWarning = Default
|
||||||
, ftrChildren = [xDbusDep ssPath interface $ Method_ memToggle]
|
, ftrChildren = [xDbusDep ssPath interface $ Method_ memToggle]
|
||||||
}
|
}
|
||||||
where
|
where
|
||||||
|
|
|
@ -5,14 +5,16 @@ module XMonad.Internal.Dependency
|
||||||
( MaybeExe
|
( MaybeExe
|
||||||
, UnitType(..)
|
, UnitType(..)
|
||||||
, Dependency(..)
|
, Dependency(..)
|
||||||
|
, Bus(..)
|
||||||
|
, Endpoint(..)
|
||||||
, DBusMember(..)
|
, DBusMember(..)
|
||||||
|
, Warning(..)
|
||||||
, MaybeX
|
, MaybeX
|
||||||
, FeatureX
|
, FeatureX
|
||||||
, FeatureIO
|
, FeatureIO
|
||||||
, Feature(..)
|
, Feature(..)
|
||||||
, ioFeature
|
, ioFeature
|
||||||
, evalFeature
|
, evalFeature
|
||||||
, exe
|
|
||||||
, systemUnit
|
, systemUnit
|
||||||
, userUnit
|
, userUnit
|
||||||
, pathR
|
, pathR
|
||||||
|
@ -34,14 +36,16 @@ module XMonad.Internal.Dependency
|
||||||
|
|
||||||
import Control.Monad.IO.Class
|
import Control.Monad.IO.Class
|
||||||
|
|
||||||
|
import Data.Bifunctor (bimap)
|
||||||
import Data.List (find)
|
import Data.List (find)
|
||||||
import Data.Maybe (listToMaybe, maybeToList)
|
import Data.Maybe (catMaybes, fromMaybe, listToMaybe)
|
||||||
|
|
||||||
import DBus
|
import DBus
|
||||||
import DBus.Client
|
import DBus.Client
|
||||||
import qualified DBus.Introspection as I
|
import qualified DBus.Introspection as I
|
||||||
|
|
||||||
import System.Directory (findExecutable, readable, writable)
|
import System.Directory (findExecutable, readable, writable)
|
||||||
|
import System.Environment
|
||||||
import System.Exit
|
import System.Exit
|
||||||
|
|
||||||
import XMonad.Core (X, io)
|
import XMonad.Core (X, io)
|
||||||
|
@ -59,21 +63,23 @@ data DBusMember = Method_ MemberName
|
||||||
| Property_ String
|
| Property_ String
|
||||||
deriving (Eq, Show)
|
deriving (Eq, Show)
|
||||||
|
|
||||||
|
data Bus = Bus Bool BusName deriving (Eq, Show)
|
||||||
|
|
||||||
|
data Endpoint = Endpoint ObjectPath InterfaceName DBusMember deriving (Eq, Show)
|
||||||
|
|
||||||
data Dependency = Executable String
|
data Dependency = Executable String
|
||||||
| AccessiblePath FilePath Bool Bool
|
| AccessiblePath FilePath Bool Bool
|
||||||
| IOTest (IO (Maybe String))
|
| IOTest (IO (Maybe String))
|
||||||
| DBusEndpoint
|
| DBusEndpoint Bus Endpoint
|
||||||
{ ddDbusBus :: BusName
|
| DBusBus Bus
|
||||||
, ddDbusSystem :: Bool
|
|
||||||
, ddDbusObject :: ObjectPath
|
|
||||||
, ddDbusInterface :: InterfaceName
|
|
||||||
, ddDbusMember :: DBusMember
|
|
||||||
}
|
|
||||||
| Systemd UnitType String
|
| Systemd UnitType String
|
||||||
|
|
||||||
|
data Warning = Silent | Default
|
||||||
|
|
||||||
data Feature a = Feature
|
data Feature a = Feature
|
||||||
{ ftrAction :: a
|
{ ftrAction :: a
|
||||||
, ftrSilent :: Bool
|
, ftrName :: String
|
||||||
|
, ftrWarning :: Warning
|
||||||
, ftrChildren :: [Dependency]
|
, ftrChildren :: [Dependency]
|
||||||
}
|
}
|
||||||
| ConstFeature a
|
| ConstFeature a
|
||||||
|
@ -91,16 +97,21 @@ ioFeature BlankFeature = BlankFeature
|
||||||
evalFeature :: Feature a -> IO (MaybeExe a)
|
evalFeature :: Feature a -> IO (MaybeExe a)
|
||||||
evalFeature (ConstFeature x) = return $ Right x
|
evalFeature (ConstFeature x) = return $ Right x
|
||||||
evalFeature BlankFeature = return $ Left []
|
evalFeature BlankFeature = return $ Left []
|
||||||
evalFeature Feature { ftrAction = a, ftrSilent = s, ftrChildren = c } = do
|
evalFeature Feature
|
||||||
es <- mapM go c
|
{ ftrAction = a
|
||||||
return $ case concat es of
|
, ftrName = n
|
||||||
|
, ftrWarning = w
|
||||||
|
, ftrChildren = c
|
||||||
|
} = do
|
||||||
|
procName <- getProgName
|
||||||
|
es <- catMaybes <$> mapM evalDependency c
|
||||||
|
return $ case es of
|
||||||
[] -> Right a
|
[] -> Right a
|
||||||
es' -> Left (if s then [] else es')
|
es' -> Left $ fmtWarnings procName es'
|
||||||
where
|
where
|
||||||
go = fmap maybeToList . depInstalled
|
fmtWarnings procName es = case w of
|
||||||
|
Silent -> []
|
||||||
exe :: String -> Dependency
|
Default -> fmap (fmtMsg procName "WARNING" . ((n ++ " disabled; ") ++)) es
|
||||||
exe = Executable
|
|
||||||
|
|
||||||
pathR :: String -> Dependency
|
pathR :: String -> Dependency
|
||||||
pathR n = AccessiblePath n True False
|
pathR n = AccessiblePath n True False
|
||||||
|
@ -123,18 +134,19 @@ type MaybeExe a = Either [String] a
|
||||||
|
|
||||||
type MaybeX = MaybeExe (X ())
|
type MaybeX = MaybeExe (X ())
|
||||||
|
|
||||||
featureRun :: [Dependency] -> a -> Feature a
|
featureRun :: String -> [Dependency] -> a -> Feature a
|
||||||
featureRun ds x = Feature
|
featureRun n ds x = Feature
|
||||||
{ ftrAction = x
|
{ ftrAction = x
|
||||||
, ftrSilent = False
|
, ftrName = n
|
||||||
|
, ftrWarning = Default
|
||||||
, ftrChildren = ds
|
, ftrChildren = ds
|
||||||
}
|
}
|
||||||
|
|
||||||
featureSpawnCmd :: MonadIO m => String -> [String] -> Feature (m ())
|
featureSpawnCmd :: MonadIO m => String -> String -> [String] -> Feature (m ())
|
||||||
featureSpawnCmd cmd args = featureRun [exe cmd] $ spawnCmd cmd args
|
featureSpawnCmd n cmd args = featureRun n [Executable cmd] $ spawnCmd cmd args
|
||||||
|
|
||||||
featureSpawn :: MonadIO m => String -> Feature (m ())
|
featureSpawn :: MonadIO m => String -> String -> Feature (m ())
|
||||||
featureSpawn cmd = featureSpawnCmd cmd []
|
featureSpawn n cmd = featureSpawnCmd n cmd []
|
||||||
|
|
||||||
exeInstalled :: String -> IO (Maybe String)
|
exeInstalled :: String -> IO (Maybe String)
|
||||||
exeInstalled x = do
|
exeInstalled x = do
|
||||||
|
@ -177,37 +189,69 @@ introspectInterface = interfaceName_ "org.freedesktop.DBus.Introspectable"
|
||||||
introspectMethod :: MemberName
|
introspectMethod :: MemberName
|
||||||
introspectMethod = memberName_ "Introspect"
|
introspectMethod = memberName_ "Introspect"
|
||||||
|
|
||||||
dbusInstalled :: BusName -> Bool -> ObjectPath -> InterfaceName -> DBusMember
|
callMethod :: Bus -> ObjectPath -> InterfaceName -> MemberName -> IO (Either String [Variant])
|
||||||
-> IO (Maybe String)
|
callMethod (Bus usesys bus) path iface mem = do
|
||||||
dbusInstalled bus usesystem objpath iface mem = do
|
client <- if usesys then connectSystem else connectSession
|
||||||
client <- if usesystem then connectSystem else connectSession
|
reply <- call client (methodCall path iface mem)
|
||||||
reply <- call_ client (methodCall objpath introspectInterface introspectMethod)
|
|
||||||
{ methodCallDestination = Just bus }
|
{ methodCallDestination = Just bus }
|
||||||
let res = findMem =<< I.parseXML objpath =<< fromVariant
|
|
||||||
=<< listToMaybe (methodReturnBody reply)
|
|
||||||
disconnect client
|
disconnect client
|
||||||
return $ case res of
|
return $ bimap methodErrorMessage methodReturnBody reply
|
||||||
Just _ -> Nothing
|
|
||||||
_ -> Just "some random dbus interface not found"
|
|
||||||
where
|
|
||||||
findMem obj = fmap (matchMem mem)
|
|
||||||
$ find (\i -> I.interfaceName i == iface)
|
|
||||||
$ I.objectInterfaces obj
|
|
||||||
matchMem (Method_ n) = elem n . fmap I.methodName . I.interfaceMethods
|
|
||||||
matchMem (Signal_ n) = elem n . fmap I.signalName . I.interfaceSignals
|
|
||||||
matchMem (Property_ n) = elem n . fmap I.propertyName . I.interfaceProperties
|
|
||||||
|
|
||||||
depInstalled :: Dependency -> IO (Maybe String)
|
dbusBusExists :: Bus -> IO (Maybe String)
|
||||||
depInstalled (Executable n) = exeInstalled n
|
dbusBusExists (Bus usesystem bus) = do
|
||||||
depInstalled (IOTest t) = t
|
ret <- callMethod (Bus usesystem queryBus) queryPath queryIface queryMem
|
||||||
depInstalled (Systemd t n) = unitInstalled t n
|
return $ case ret of
|
||||||
depInstalled (AccessiblePath p r w) = pathAccessible p r w
|
Left e -> Just e
|
||||||
depInstalled DBusEndpoint { ddDbusBus = b
|
Right b -> let ns = bodyGetNames b in
|
||||||
, ddDbusSystem = s
|
if bus' `elem` ns then Nothing
|
||||||
, ddDbusObject = o
|
else Just $ unwords ["name", singleQuote bus', "not found on dbus"]
|
||||||
, ddDbusInterface = i
|
where
|
||||||
, ddDbusMember = m
|
bus' = formatBusName bus
|
||||||
} = dbusInstalled b s o i m
|
queryBus = busName_ "org.freedesktop.DBus"
|
||||||
|
queryIface = interfaceName_ "org.freedesktop.DBus"
|
||||||
|
queryPath = objectPath_ "/"
|
||||||
|
queryMem = memberName_ "ListNames"
|
||||||
|
bodyGetNames [v] = fromMaybe [] $ fromVariant v :: [String]
|
||||||
|
bodyGetNames _ = []
|
||||||
|
|
||||||
|
dbusEndpointExists :: Bus -> Endpoint -> IO (Maybe String)
|
||||||
|
dbusEndpointExists b@(Bus _ bus) (Endpoint objpath iface mem) = do
|
||||||
|
ret <- callMethod b objpath introspectInterface introspectMethod
|
||||||
|
return $ case ret of
|
||||||
|
Left e -> Just e
|
||||||
|
Right body -> procBody body
|
||||||
|
where
|
||||||
|
procBody body = let res = findMem =<< I.parseXML objpath =<< fromVariant
|
||||||
|
=<< listToMaybe body in
|
||||||
|
case res of
|
||||||
|
Just True -> Nothing
|
||||||
|
_ -> Just $ fmtMsg' mem
|
||||||
|
findMem = fmap (matchMem mem)
|
||||||
|
. find (\i -> I.interfaceName i == iface)
|
||||||
|
. I.objectInterfaces
|
||||||
|
matchMem (Method_ n) = elemMember n I.methodName I.interfaceMethods
|
||||||
|
matchMem (Signal_ n) = elemMember n I.signalName I.interfaceSignals
|
||||||
|
matchMem (Property_ n) = elemMember n I.propertyName I.interfaceProperties
|
||||||
|
elemMember n fname fmember = elem n . fmap fname . fmember
|
||||||
|
fmtMem (Method_ n) = "method " ++ singleQuote (formatMemberName n)
|
||||||
|
fmtMem (Signal_ n) = "signal " ++ singleQuote (formatMemberName n)
|
||||||
|
fmtMem (Property_ n) = "property " ++ singleQuote n
|
||||||
|
fmtMsg' m = unwords
|
||||||
|
[ "could not find"
|
||||||
|
, fmtMem m
|
||||||
|
, "on interface"
|
||||||
|
, singleQuote $ formatInterfaceName iface
|
||||||
|
, "on bus"
|
||||||
|
, formatBusName bus
|
||||||
|
]
|
||||||
|
|
||||||
|
evalDependency :: Dependency -> IO (Maybe String)
|
||||||
|
evalDependency (Executable n) = exeInstalled n
|
||||||
|
evalDependency (IOTest t) = t
|
||||||
|
evalDependency (Systemd t n) = unitInstalled t n
|
||||||
|
evalDependency (AccessiblePath p r w) = pathAccessible p r w
|
||||||
|
evalDependency (DBusEndpoint b e) = dbusEndpointExists b e
|
||||||
|
evalDependency (DBusBus b) = dbusBusExists b
|
||||||
|
|
||||||
whenInstalled :: Monad m => MaybeExe (m ()) -> m ()
|
whenInstalled :: Monad m => MaybeExe (m ()) -> m ()
|
||||||
whenInstalled = flip ifInstalled skip
|
whenInstalled = flip ifInstalled skip
|
||||||
|
@ -217,7 +261,7 @@ ifInstalled (Right x) _ = x
|
||||||
ifInstalled _ alt = alt
|
ifInstalled _ alt = alt
|
||||||
|
|
||||||
warnMissing :: [MaybeExe a] -> IO ()
|
warnMissing :: [MaybeExe a] -> IO ()
|
||||||
warnMissing xs = warnMissing' $ fmap ("[WARNING] "++) $ concat $ [ m | (Left m) <- xs ]
|
warnMissing xs = warnMissing' $ concat $ [ m | (Left m) <- xs ]
|
||||||
|
|
||||||
warnMissing' :: [String] -> IO ()
|
warnMissing' :: [String] -> IO ()
|
||||||
warnMissing' = mapM_ putStrLn
|
warnMissing' = mapM_ putStrLn
|
||||||
|
@ -235,3 +279,9 @@ executeFeature = applyFeature id
|
||||||
|
|
||||||
executeFeature_ :: Feature (IO ()) -> IO ()
|
executeFeature_ :: Feature (IO ()) -> IO ()
|
||||||
executeFeature_ = executeFeature ()
|
executeFeature_ = executeFeature ()
|
||||||
|
|
||||||
|
fmtMsg :: String -> String -> String -> String
|
||||||
|
fmtMsg procName level msg = unwords [bracket procName, bracket level, msg]
|
||||||
|
where
|
||||||
|
bracket s = "[" ++ s ++ "]"
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue