2022-12-26 14:45:49 -05:00
|
|
|
{-# LANGUAGE OverloadedStrings #-}
|
|
|
|
|
2020-04-01 20:17:47 -04:00
|
|
|
--------------------------------------------------------------------------------
|
2022-12-30 14:58:23 -05:00
|
|
|
-- Commands for controlling power
|
2020-04-01 20:17:47 -04:00
|
|
|
|
|
|
|
module XMonad.Internal.Command.Power
|
2022-12-30 14:58:23 -05:00
|
|
|
-- commands
|
2020-03-28 18:38:38 -04:00
|
|
|
( runHibernate
|
|
|
|
, runOptimusPrompt
|
|
|
|
, runPowerOff
|
|
|
|
, runPowerPrompt
|
|
|
|
, runReboot
|
|
|
|
, runScreenLock
|
|
|
|
, runSuspend
|
|
|
|
, runSuspendPrompt
|
|
|
|
, runQuitPrompt
|
2022-07-03 01:11:32 -04:00
|
|
|
-- daemons
|
|
|
|
, runAutolock
|
|
|
|
-- functions
|
2021-06-23 20:47:41 -04:00
|
|
|
, hasBattery
|
2022-07-02 17:09:21 -04:00
|
|
|
, suspendPrompt
|
|
|
|
, quitPrompt
|
2022-06-26 20:07:25 -04:00
|
|
|
, powerPrompt
|
2022-07-09 01:02:37 -04:00
|
|
|
, defFontPkgs
|
|
|
|
, promptFontDep
|
2022-12-30 14:58:23 -05:00
|
|
|
)
|
|
|
|
where
|
|
|
|
|
|
|
|
import Data.Either
|
|
|
|
import Data.Internal.Dependency
|
|
|
|
import qualified Data.Map as M
|
|
|
|
import Graphics.X11.Types
|
|
|
|
import RIO
|
|
|
|
import RIO.FilePath
|
|
|
|
import qualified RIO.Process as P
|
|
|
|
import qualified RIO.Text as T
|
|
|
|
import System.IO.Error
|
2022-12-31 19:04:37 -05:00
|
|
|
import UnliftIO.Directory
|
2022-12-30 14:58:23 -05:00
|
|
|
import XMonad.Core hiding (spawn)
|
|
|
|
import XMonad.Internal.Shell
|
|
|
|
import qualified XMonad.Internal.Theme as XT
|
|
|
|
import XMonad.Prompt
|
|
|
|
import XMonad.Prompt.ConfirmPrompt
|
2020-03-28 18:38:38 -04:00
|
|
|
|
2021-06-20 01:01:36 -04:00
|
|
|
--------------------------------------------------------------------------------
|
2022-12-30 14:58:23 -05:00
|
|
|
-- Executables
|
2022-12-26 14:45:49 -05:00
|
|
|
myScreenlock :: FilePath
|
2021-06-20 01:01:36 -04:00
|
|
|
myScreenlock = "screenlock"
|
|
|
|
|
2022-12-26 14:45:49 -05:00
|
|
|
myOptimusManager :: FilePath
|
2021-06-20 01:01:36 -04:00
|
|
|
myOptimusManager = "optimus-manager"
|
|
|
|
|
2022-12-26 14:45:49 -05:00
|
|
|
myPrimeOffload :: FilePath
|
2022-07-02 17:09:21 -04:00
|
|
|
myPrimeOffload = "prime-offload"
|
|
|
|
|
2022-07-09 01:02:37 -04:00
|
|
|
--------------------------------------------------------------------------------
|
2022-12-30 14:58:23 -05:00
|
|
|
-- Packages
|
2022-07-09 01:02:37 -04:00
|
|
|
|
|
|
|
optimusPackages :: [Fulfillment]
|
2022-07-09 14:59:42 -04:00
|
|
|
optimusPackages = [Package AUR "optimus-manager"]
|
2022-07-09 01:02:37 -04:00
|
|
|
|
2020-03-28 18:38:38 -04:00
|
|
|
--------------------------------------------------------------------------------
|
2022-12-30 14:58:23 -05:00
|
|
|
-- Core commands
|
2020-03-28 18:38:38 -04:00
|
|
|
|
2022-06-21 00:56:42 -04:00
|
|
|
runScreenLock :: SometimesX
|
2022-12-30 14:58:23 -05:00
|
|
|
runScreenLock =
|
|
|
|
sometimesExe
|
|
|
|
"screen locker"
|
|
|
|
"i3lock script"
|
|
|
|
[Package AUR "i3lock-color"]
|
|
|
|
False
|
|
|
|
myScreenlock
|
2020-03-28 18:38:38 -04:00
|
|
|
|
|
|
|
runPowerOff :: X ()
|
|
|
|
runPowerOff = spawn "systemctl poweroff"
|
|
|
|
|
|
|
|
runSuspend :: X ()
|
|
|
|
runSuspend = spawn "systemctl suspend"
|
|
|
|
|
|
|
|
runHibernate :: X ()
|
|
|
|
runHibernate = spawn "systemctl hibernate"
|
|
|
|
|
|
|
|
runReboot :: X ()
|
|
|
|
runReboot = spawn "systemctl reboot"
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
2022-12-30 14:58:23 -05:00
|
|
|
-- Autolock
|
2022-07-03 01:11:32 -04:00
|
|
|
|
2022-12-29 12:01:40 -05:00
|
|
|
runAutolock :: Sometimes (FIO (P.Process () () ()))
|
2022-07-03 01:11:32 -04:00
|
|
|
runAutolock = sometimesIO_ "automatic screen lock" "xss-lock" tree cmd
|
|
|
|
where
|
2022-12-30 14:58:23 -05:00
|
|
|
tree =
|
|
|
|
And_ (Only_ $ sysExe [Package Official "xss-lock"] "xss-lock") $
|
|
|
|
Only_ $
|
|
|
|
IOSometimes_ runScreenLock
|
2022-12-29 12:01:40 -05:00
|
|
|
cmd = P.proc "xss-lock" ["--ignore-sleep", "screenlock"] (P.startProcess . P.setCreateGroup True)
|
2022-07-03 01:11:32 -04:00
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
2022-12-30 14:58:23 -05:00
|
|
|
-- Confirmation prompts
|
2022-07-02 17:09:21 -04:00
|
|
|
|
2022-12-26 14:45:49 -05:00
|
|
|
promptFontDep :: IOTree XT.FontBuilder
|
|
|
|
promptFontDep = fontTreeAlt XT.defFontFamily defFontPkgs
|
2022-07-09 01:02:37 -04:00
|
|
|
|
|
|
|
defFontPkgs :: [Fulfillment]
|
2022-07-09 14:59:42 -04:00
|
|
|
defFontPkgs = [Package Official "ttf-dejavu"]
|
2022-07-09 01:02:37 -04:00
|
|
|
|
2022-12-26 14:45:49 -05:00
|
|
|
confirmPrompt' :: T.Text -> X () -> XT.FontBuilder -> X ()
|
|
|
|
confirmPrompt' s x fb = confirmPrompt (XT.promptTheme fb) (T.unpack s) x
|
2022-07-02 17:09:21 -04:00
|
|
|
|
2022-12-26 14:45:49 -05:00
|
|
|
suspendPrompt :: XT.FontBuilder -> X ()
|
2022-07-02 17:09:21 -04:00
|
|
|
suspendPrompt = confirmPrompt' "suspend?" runSuspend
|
|
|
|
|
2022-12-26 14:45:49 -05:00
|
|
|
quitPrompt :: XT.FontBuilder -> X ()
|
2022-07-02 17:09:21 -04:00
|
|
|
quitPrompt = confirmPrompt' "quit?" $ io exitSuccess
|
|
|
|
|
2022-12-26 14:45:49 -05:00
|
|
|
sometimesPrompt :: T.Text -> (XT.FontBuilder -> X ()) -> SometimesX
|
|
|
|
sometimesPrompt n = sometimesIO n (T.append n " command") promptFontDep
|
2020-03-28 18:38:38 -04:00
|
|
|
|
2021-11-20 01:15:04 -05:00
|
|
|
-- TODO doesn't this need to also lock the screen?
|
2022-07-02 17:09:21 -04:00
|
|
|
runSuspendPrompt :: SometimesX
|
|
|
|
runSuspendPrompt = sometimesPrompt "suspend prompt" suspendPrompt
|
2020-03-28 18:38:38 -04:00
|
|
|
|
2022-07-02 17:09:21 -04:00
|
|
|
runQuitPrompt :: SometimesX
|
|
|
|
runQuitPrompt = sometimesPrompt "quit prompt" quitPrompt
|
2020-03-28 18:38:38 -04:00
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
2022-12-30 14:58:23 -05:00
|
|
|
-- Nvidia Optimus
|
2020-03-28 18:38:38 -04:00
|
|
|
|
|
|
|
-- TODO for some reason the screen never wakes up after suspend when
|
|
|
|
-- the nvidia card is up, so block suspend if nvidia card is running
|
|
|
|
-- and warn user
|
|
|
|
isUsingNvidia :: IO Bool
|
|
|
|
isUsingNvidia = doesDirectoryExist "/sys/module/nvidia"
|
|
|
|
|
2022-12-26 14:45:49 -05:00
|
|
|
hasBattery :: IO (Maybe T.Text)
|
2021-06-23 20:47:41 -04:00
|
|
|
hasBattery = do
|
|
|
|
ps <- fromRight [] <$> tryIOError (listDirectory syspath)
|
|
|
|
ts <- mapM readType ps
|
2021-11-19 00:35:54 -05:00
|
|
|
return $ if "Battery\n" `elem` ts then Nothing else Just "battery not found"
|
2021-06-23 20:47:41 -04:00
|
|
|
where
|
|
|
|
readType p = fromRight [] <$> tryIOError (readFile $ syspath </> p </> "type")
|
|
|
|
syspath = "/sys/class/power_supply"
|
2021-06-20 01:01:36 -04:00
|
|
|
|
2022-12-26 14:45:49 -05:00
|
|
|
runOptimusPrompt' :: XT.FontBuilder -> X ()
|
2022-07-02 17:09:21 -04:00
|
|
|
runOptimusPrompt' fb = do
|
2020-03-28 18:38:38 -04:00
|
|
|
nvidiaOn <- io isUsingNvidia
|
2021-06-20 01:01:36 -04:00
|
|
|
switch $ if nvidiaOn then "integrated" else "nvidia"
|
2020-03-28 18:38:38 -04:00
|
|
|
where
|
2022-07-02 17:09:21 -04:00
|
|
|
switch mode = confirmPrompt' (prompt mode) (cmd mode) fb
|
2022-12-26 14:45:49 -05:00
|
|
|
prompt mode = T.concat ["gpu switch to ", mode, "?"]
|
2022-12-30 14:58:23 -05:00
|
|
|
cmd mode =
|
|
|
|
spawn $
|
|
|
|
T.pack myPrimeOffload
|
|
|
|
#!&& T.unwords [T.pack myOptimusManager, "--switch", mode, "--no-confirm"]
|
|
|
|
#!&& "killall xmonad"
|
2020-03-28 18:38:38 -04:00
|
|
|
|
2022-06-21 00:56:42 -04:00
|
|
|
runOptimusPrompt :: SometimesX
|
2022-12-30 14:58:23 -05:00
|
|
|
runOptimusPrompt =
|
|
|
|
Sometimes
|
|
|
|
"graphics switcher"
|
|
|
|
(\x -> xpfOptimus x && xpfBattery x)
|
|
|
|
[s]
|
2022-07-02 17:09:21 -04:00
|
|
|
where
|
2022-12-30 14:58:23 -05:00
|
|
|
s = Subfeature {sfData = r, sfName = "optimus manager"}
|
2022-07-02 17:09:21 -04:00
|
|
|
r = IORoot runOptimusPrompt' t
|
2022-12-30 14:58:23 -05:00
|
|
|
t =
|
|
|
|
And1 promptFontDep $
|
|
|
|
listToAnds (socketExists "optimus-manager" [] socketName) $
|
|
|
|
sysExe optimusPackages <$> [myOptimusManager, myPrimeOffload]
|
2022-07-08 18:17:41 -04:00
|
|
|
socketName = (</> "optimus-manager") <$> getTemporaryDirectory
|
2021-06-20 01:01:36 -04:00
|
|
|
|
2020-03-28 18:38:38 -04:00
|
|
|
--------------------------------------------------------------------------------
|
2022-12-30 14:58:23 -05:00
|
|
|
-- Universal power prompt
|
2020-03-28 18:38:38 -04:00
|
|
|
|
2022-12-30 14:58:23 -05:00
|
|
|
data PowerMaybeAction
|
|
|
|
= Poweroff
|
|
|
|
| Shutdown
|
|
|
|
| Hibernate
|
|
|
|
| Reboot
|
|
|
|
deriving (Eq)
|
2020-03-28 18:38:38 -04:00
|
|
|
|
2021-11-21 10:26:28 -05:00
|
|
|
instance Enum PowerMaybeAction where
|
2020-03-28 18:38:38 -04:00
|
|
|
toEnum 0 = Poweroff
|
|
|
|
toEnum 1 = Shutdown
|
|
|
|
toEnum 2 = Hibernate
|
|
|
|
toEnum 3 = Reboot
|
2021-11-21 10:26:28 -05:00
|
|
|
toEnum _ = errorWithoutStackTrace "Main.Enum.PowerMaybeAction.toEnum: bad argument"
|
2020-03-28 18:38:38 -04:00
|
|
|
|
2022-12-30 14:58:23 -05:00
|
|
|
fromEnum Poweroff = 0
|
|
|
|
fromEnum Shutdown = 1
|
2020-03-28 18:38:38 -04:00
|
|
|
fromEnum Hibernate = 2
|
2022-12-30 14:58:23 -05:00
|
|
|
fromEnum Reboot = 3
|
2020-03-28 18:38:38 -04:00
|
|
|
|
|
|
|
data PowerPrompt = PowerPrompt
|
|
|
|
|
|
|
|
instance XPrompt PowerPrompt where
|
2022-12-30 14:58:23 -05:00
|
|
|
showXPrompt PowerPrompt = "(P)oweroff (S)uspend (H)ibernate (R)eboot:"
|
2020-03-28 18:38:38 -04:00
|
|
|
|
2022-07-03 18:23:32 -04:00
|
|
|
runPowerPrompt :: SometimesX
|
2022-07-08 18:57:12 -04:00
|
|
|
runPowerPrompt = Sometimes "power prompt" (const True) [sf]
|
2022-06-26 20:07:25 -04:00
|
|
|
where
|
2022-07-08 19:02:49 -04:00
|
|
|
sf = Subfeature withLock "prompt with lock"
|
2022-07-02 17:09:21 -04:00
|
|
|
withLock = IORoot (uncurry powerPrompt) tree
|
2022-07-09 01:02:37 -04:00
|
|
|
tree = And12 (,) lockTree promptFontDep
|
2022-07-03 18:23:32 -04:00
|
|
|
lockTree = Or (Only $ IOSometimes runScreenLock id) (Only $ IOConst skip)
|
2022-06-26 20:07:25 -04:00
|
|
|
|
2022-12-26 14:45:49 -05:00
|
|
|
powerPrompt :: X () -> XT.FontBuilder -> X ()
|
2022-07-02 17:09:21 -04:00
|
|
|
powerPrompt lock fb = mkXPrompt PowerPrompt theme comp executeMaybeAction
|
2020-03-28 18:38:38 -04:00
|
|
|
where
|
2022-03-05 18:18:16 -05:00
|
|
|
comp = mkComplFunFromList theme []
|
2022-12-30 14:58:23 -05:00
|
|
|
theme = (XT.promptTheme fb) {promptKeymap = keymap}
|
|
|
|
keymap =
|
|
|
|
M.fromList $
|
|
|
|
((controlMask, xK_g), quit)
|
|
|
|
: map
|
|
|
|
(first $ (,) 0)
|
|
|
|
[ (xK_p, sendMaybeAction Poweroff)
|
|
|
|
, (xK_s, sendMaybeAction Shutdown)
|
|
|
|
, (xK_h, sendMaybeAction Hibernate)
|
|
|
|
, (xK_r, sendMaybeAction Reboot)
|
|
|
|
, (xK_Return, quit)
|
|
|
|
, (xK_Escape, quit)
|
|
|
|
]
|
2021-11-21 10:26:28 -05:00
|
|
|
sendMaybeAction a = setInput (show $ fromEnum a) >> setSuccess True >> setDone True
|
|
|
|
executeMaybeAction a = case toEnum $ read a of
|
2022-12-30 14:58:23 -05:00
|
|
|
Poweroff -> runPowerOff
|
|
|
|
Shutdown -> lock >> runSuspend
|
2021-11-19 22:42:19 -05:00
|
|
|
Hibernate -> lock >> runHibernate
|
2022-12-30 14:58:23 -05:00
|
|
|
Reboot -> runReboot
|