REF move process functions to their own module

This commit is contained in:
Nathan Dwarshuis 2020-03-26 09:37:46 -04:00
parent a9468ef3dd
commit 738205cba2
4 changed files with 69 additions and 58 deletions

View File

@ -4,18 +4,17 @@
module Main (main) where
import ACPI
import DBus.Client (Client)
import Notify
import SendXMsg
import Shell
import WorkspaceMon
import DBus.Common
import DBus.IntelBacklight
import DBus.Screensaver
import Notify
import Process
import SendXMsg
import Shell
import qualified Theme as T
import WorkspaceMon
import Control.Arrow (first)
import Control.Concurrent
import Control.Monad
( forM
@ -30,27 +29,19 @@ import qualified Data.Map.Lazy as M
import Data.Maybe (catMaybes, isJust)
import Data.Monoid (All (..))
import DBus.Client (Client)
import Graphics.X11.Types
import Graphics.X11.Xlib.Atom
import Graphics.X11.Xlib.Extras
import Graphics.X11.Xrandr
import Control.Arrow (first)
import Control.Exception
import System.Directory
import System.Exit
import System.IO
import System.Posix.IO
import System.Posix.Process
import System.Posix.Signals
import System.Posix.Types
import System.Process (waitForProcess)
import System.Process.Internals
( ProcessHandle__ (ClosedHandle, OpenHandle)
, mkProcessHandle
, withProcessHandle
)
import Text.Read (readMaybe)
@ -72,12 +63,11 @@ import XMonad.Layout.PerWorkspace
import XMonad.Layout.Tabbed
import XMonad.Prompt
import XMonad.Prompt.ConfirmPrompt
import qualified XMonad.StackSet as W
import XMonad.Util.EZConfig
import XMonad.Util.NamedActions
import XMonad.Util.Run
import qualified XMonad.StackSet as W
main :: IO ()
main = do
dbClient <- startXMonadService
@ -196,9 +186,6 @@ myWindowSetXinerama ws = wsString ++ sep ++ layout
(_, Rectangle x0 _ _ _) = getScreenIdAndRectangle s0
(_, Rectangle x1 _ _ _) = getScreenIdAndRectangle s1
getFocusedScreen :: X Rectangle
getFocusedScreen = withWindowSet $ return . screenRect . W.screenDetail . W.current
myManageHook :: ManageHook
myManageHook = composeOne
-- assume virtualbox is not run with the toolbar in fullscreen mode
@ -235,7 +222,7 @@ myEventHook ClientMessageEvent { ev_message_type = t, ev_data = d }
ACPI -> do
let acpiTag = toEnum <$> readMaybe tag :: Maybe ACPIEvent
forM_ acpiTag $ \case
Power -> myPowerPrompt
Power -> runPowerPrompt
Sleep -> confirmPrompt T.promptTheme "suspend?" runSuspend
LidClose -> do
status <- io isDischarging
@ -281,8 +268,8 @@ instance Enum PowerAction where
fromEnum Hibernate = 2
fromEnum Reboot = 3
myPowerPrompt :: X ()
myPowerPrompt = mkXPrompt PowerPrompt theme comp executeAction
runPowerPrompt :: X ()
runPowerPrompt = mkXPrompt PowerPrompt theme comp executeAction
where
comp = mkComplFunFromList []
theme = T.promptTheme { promptKeymap = keymap }
@ -303,8 +290,8 @@ myPowerPrompt = mkXPrompt PowerPrompt theme comp executeAction
Hibernate -> runScreenLock >> runHibernate
Reboot -> runReboot
myQuitPrompt :: X ()
myQuitPrompt = confirmPrompt T.promptTheme "quit?" $ io exitSuccess
runQuitPrompt :: X ()
runQuitPrompt = confirmPrompt T.promptTheme "quit?" $ io exitSuccess
-- 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
@ -377,6 +364,9 @@ getMonitorName = do
(Rectangle x y _ _) <- getFocusedScreen
return (fromIntegral x, fromIntegral y)
getFocusedScreen :: X Rectangle
getFocusedScreen = withWindowSet $ return . screenRect . W.screenDetail . W.current
spawnDmenuCmd :: String -> [String] -> X ()
spawnDmenuCmd cmd args = do
name <- getMonitorName
@ -454,21 +444,6 @@ runCleanup ps client = io $ do
mapM_ killPID ps
stopXMonadService client
killPID :: ProcessID -> IO ()
killPID pID = do
h <- mkProcessHandle pID False
-- this may fail of the PID does not exist
_ <- try $ sendSIGTERM h :: IO (Either IOException ())
-- this may fail if the process exits instantly and the handle
-- is destroyed by the time we get to this line (I think?)
_ <- try $ waitForProcess h :: IO (Either IOException ExitCode)
return ()
where
sendSIGTERM h = withProcessHandle h $ \case
OpenHandle _ -> signalProcess sigTERM pID
ClosedHandle _ -> return ()
_ -> return () -- this should never happen
runRestart :: X ()
runRestart = restart "xmonad" True
@ -630,6 +605,7 @@ myKeys hs client c =
, ("M-C-t", addName "launch terminal" runTerm)
, ("M-C-q", addName "launch calc" runCalc)
, ("M-C-f", addName "launch file manager" runFileManager)
-- TODO shoudn't these be flipped?
, ("M-C-v", addName "launch windows VM" $ runVBox >> appendWorkspace myVMWorkspace)
, ("M-C-g", addName "launch GIMP" $ runGimp >> appendWorkspace myGimpWorkspace)
] ++
@ -653,7 +629,7 @@ myKeys hs client c =
, ("M-M1-=", addName "toggle screensaver" toggleDPMS)
, ("M-<F2>", addName "restart xmonad" $ runCleanup hs client >> runRestart)
, ("M-S-<F2>", addName "recompile xmonad" runRecompile)
, ("M-<End>", addName "power menu" myPowerPrompt)
, ("M-<Home>", addName "quit xmonad" myQuitPrompt)
, ("M-<End>", addName "power menu" runPowerPrompt)
, ("M-<Home>", addName "quit xmonad" runQuitPrompt)
, ("M-<Esc>", addName "switch gpu" runOptimusPrompt)
]

44
lib/Process.hs Normal file
View File

@ -0,0 +1,44 @@
{-# LANGUAGE LambdaCase #-}
module Process where
import Control.Concurrent
import Control.Exception
import Control.Monad
import System.Directory
import System.Exit
import System.Posix.Signals
import System.Posix.Types
import System.Process (waitForProcess)
import System.Process.Internals
( ProcessHandle__ (ClosedHandle, OpenHandle)
, mkProcessHandle
, withProcessHandle
)
-- | Block until a PID has exited (in any form)
-- ASSUMPTION on linux PIDs will always increase until they overflow, in which
-- case they will start to recycle. Barring any fork bombs, this code should
-- work because we can reasonably expect that no processes will spawn with the
-- same PID within the delay limit
-- TODO this will not work if the process is a zombie (maybe I care...)
waitUntilExit :: Show t => t -> IO ()
waitUntilExit pid = do
res <- doesDirectoryExist $ "/proc/" ++ show pid
when res $ threadDelay 100000 >> waitUntilExit pid
killPID :: ProcessID -> IO ()
killPID pid = do
h <- mkProcessHandle pid False
-- this may fail of the PID does not exist
_ <- try $ sendSIGTERM h :: IO (Either IOException ())
-- this may fail if the process exits instantly and the handle
-- is destroyed by the time we get to this line (I think?)
_ <- try $ waitForProcess h :: IO (Either IOException ExitCode)
return ()
where
sendSIGTERM h = withProcessHandle h $ \case
OpenHandle _ -> signalProcess sigTERM pid
ClosedHandle _ -> return ()
_ -> return () -- this should never happen

View File

@ -2,6 +2,7 @@
module WorkspaceMon (M.fromList, runWorkspaceMon) where
import Process
import SendXMsg
import qualified Data.Map as M
@ -19,7 +20,6 @@ import Graphics.X11.Xlib.Extras
import Graphics.X11.Xlib.Misc
import Graphics.X11.Xlib.Types
import System.Directory
import System.Process (Pid)
-- TOOD it would be really nice if the manner we used to match windows was
@ -81,18 +81,8 @@ handle curPIDs MapNotifyEvent { ev_window = w } = do
handle _ _ = return ()
waitAndKill :: String -> Pid -> IO ()
waitAndKill tag pid = waitUntilExit pidDir
where
pidDir = "/proc/" ++ show pid
waitUntilExit d = do
-- TODO this will not work if the process is a zombie (maybe I care...)
-- ASSUMPTION on linux PIDs will always increase until they overflow, in
-- which case they will start to recycle. Barring any fork bombs, this
-- code should work because we can reasonably expect that no processes
-- will spawn with the same PID within the delay limit
res <- doesDirectoryExist d
if res then threadDelay 100000 >> waitUntilExit d
else sendXMsg Workspace tag
waitAndKill tag pid = waitUntilExit pid >> sendXMsg Workspace tag
withUniquePid :: WatchedPIDs -> Pid -> IO () -> IO ()
withUniquePid curPIDs pid f = do

View File

@ -15,6 +15,7 @@ library
, DBus.IntelBacklight
, DBus.Internal
, DBus.Screensaver
, Process
, Xmobar.Common
, Xmobar.Plugins.Bluetooth
, Xmobar.Plugins.IntelBacklight
@ -29,6 +30,7 @@ library
, fdo-notify
, io-streams >= 1.5.1.0
, mtl >= 2.2.2
, unix >= 2.7.2.2
, tcp-streams >= 1.0.1.1
, text >= 1.2.3.1
, directory >= 1.3.3.0
@ -47,7 +49,6 @@ executable xmonad
, dbus >= 1.2.7
, directory >= 1.3.3.0
, my-xmonad
, process >= 1.6.5.0
, unix >= 2.7.2.2
, xmonad >= 0.13
, xmonad-contrib >= 0.13