REF move process functions to their own module
This commit is contained in:
parent
a9468ef3dd
commit
738205cba2
|
@ -4,18 +4,17 @@
|
||||||
module Main (main) where
|
module Main (main) where
|
||||||
|
|
||||||
import ACPI
|
import ACPI
|
||||||
import DBus.Client (Client)
|
|
||||||
import Notify
|
|
||||||
import SendXMsg
|
|
||||||
import Shell
|
|
||||||
import WorkspaceMon
|
|
||||||
|
|
||||||
import DBus.Common
|
import DBus.Common
|
||||||
import DBus.IntelBacklight
|
import DBus.IntelBacklight
|
||||||
import DBus.Screensaver
|
import DBus.Screensaver
|
||||||
|
import Notify
|
||||||
|
import Process
|
||||||
|
import SendXMsg
|
||||||
|
import Shell
|
||||||
import qualified Theme as T
|
import qualified Theme as T
|
||||||
|
import WorkspaceMon
|
||||||
|
|
||||||
|
import Control.Arrow (first)
|
||||||
import Control.Concurrent
|
import Control.Concurrent
|
||||||
import Control.Monad
|
import Control.Monad
|
||||||
( forM
|
( forM
|
||||||
|
@ -30,27 +29,19 @@ import qualified Data.Map.Lazy as M
|
||||||
import Data.Maybe (catMaybes, isJust)
|
import Data.Maybe (catMaybes, isJust)
|
||||||
import Data.Monoid (All (..))
|
import Data.Monoid (All (..))
|
||||||
|
|
||||||
|
import DBus.Client (Client)
|
||||||
|
|
||||||
import Graphics.X11.Types
|
import Graphics.X11.Types
|
||||||
import Graphics.X11.Xlib.Atom
|
import Graphics.X11.Xlib.Atom
|
||||||
import Graphics.X11.Xlib.Extras
|
import Graphics.X11.Xlib.Extras
|
||||||
import Graphics.X11.Xrandr
|
import Graphics.X11.Xrandr
|
||||||
|
|
||||||
import Control.Arrow (first)
|
|
||||||
import Control.Exception
|
|
||||||
|
|
||||||
import System.Directory
|
import System.Directory
|
||||||
import System.Exit
|
import System.Exit
|
||||||
import System.IO
|
import System.IO
|
||||||
import System.Posix.IO
|
import System.Posix.IO
|
||||||
import System.Posix.Process
|
import System.Posix.Process
|
||||||
import System.Posix.Signals
|
|
||||||
import System.Posix.Types
|
import System.Posix.Types
|
||||||
import System.Process (waitForProcess)
|
|
||||||
import System.Process.Internals
|
|
||||||
( ProcessHandle__ (ClosedHandle, OpenHandle)
|
|
||||||
, mkProcessHandle
|
|
||||||
, withProcessHandle
|
|
||||||
)
|
|
||||||
|
|
||||||
import Text.Read (readMaybe)
|
import Text.Read (readMaybe)
|
||||||
|
|
||||||
|
@ -72,12 +63,11 @@ import XMonad.Layout.PerWorkspace
|
||||||
import XMonad.Layout.Tabbed
|
import XMonad.Layout.Tabbed
|
||||||
import XMonad.Prompt
|
import XMonad.Prompt
|
||||||
import XMonad.Prompt.ConfirmPrompt
|
import XMonad.Prompt.ConfirmPrompt
|
||||||
|
import qualified XMonad.StackSet as W
|
||||||
import XMonad.Util.EZConfig
|
import XMonad.Util.EZConfig
|
||||||
import XMonad.Util.NamedActions
|
import XMonad.Util.NamedActions
|
||||||
import XMonad.Util.Run
|
import XMonad.Util.Run
|
||||||
|
|
||||||
import qualified XMonad.StackSet as W
|
|
||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = do
|
main = do
|
||||||
dbClient <- startXMonadService
|
dbClient <- startXMonadService
|
||||||
|
@ -196,9 +186,6 @@ myWindowSetXinerama ws = wsString ++ sep ++ layout
|
||||||
(_, Rectangle x0 _ _ _) = getScreenIdAndRectangle s0
|
(_, Rectangle x0 _ _ _) = getScreenIdAndRectangle s0
|
||||||
(_, Rectangle x1 _ _ _) = getScreenIdAndRectangle s1
|
(_, Rectangle x1 _ _ _) = getScreenIdAndRectangle s1
|
||||||
|
|
||||||
getFocusedScreen :: X Rectangle
|
|
||||||
getFocusedScreen = withWindowSet $ return . screenRect . W.screenDetail . W.current
|
|
||||||
|
|
||||||
myManageHook :: ManageHook
|
myManageHook :: ManageHook
|
||||||
myManageHook = composeOne
|
myManageHook = composeOne
|
||||||
-- assume virtualbox is not run with the toolbar in fullscreen mode
|
-- 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
|
ACPI -> do
|
||||||
let acpiTag = toEnum <$> readMaybe tag :: Maybe ACPIEvent
|
let acpiTag = toEnum <$> readMaybe tag :: Maybe ACPIEvent
|
||||||
forM_ acpiTag $ \case
|
forM_ acpiTag $ \case
|
||||||
Power -> myPowerPrompt
|
Power -> runPowerPrompt
|
||||||
Sleep -> confirmPrompt T.promptTheme "suspend?" runSuspend
|
Sleep -> confirmPrompt T.promptTheme "suspend?" runSuspend
|
||||||
LidClose -> do
|
LidClose -> do
|
||||||
status <- io isDischarging
|
status <- io isDischarging
|
||||||
|
@ -281,8 +268,8 @@ instance Enum PowerAction where
|
||||||
fromEnum Hibernate = 2
|
fromEnum Hibernate = 2
|
||||||
fromEnum Reboot = 3
|
fromEnum Reboot = 3
|
||||||
|
|
||||||
myPowerPrompt :: X ()
|
runPowerPrompt :: X ()
|
||||||
myPowerPrompt = mkXPrompt PowerPrompt theme comp executeAction
|
runPowerPrompt = mkXPrompt PowerPrompt theme comp executeAction
|
||||||
where
|
where
|
||||||
comp = mkComplFunFromList []
|
comp = mkComplFunFromList []
|
||||||
theme = T.promptTheme { promptKeymap = keymap }
|
theme = T.promptTheme { promptKeymap = keymap }
|
||||||
|
@ -303,8 +290,8 @@ myPowerPrompt = mkXPrompt PowerPrompt theme comp executeAction
|
||||||
Hibernate -> runScreenLock >> runHibernate
|
Hibernate -> runScreenLock >> runHibernate
|
||||||
Reboot -> runReboot
|
Reboot -> runReboot
|
||||||
|
|
||||||
myQuitPrompt :: X ()
|
runQuitPrompt :: X ()
|
||||||
myQuitPrompt = confirmPrompt T.promptTheme "quit?" $ io exitSuccess
|
runQuitPrompt = confirmPrompt T.promptTheme "quit?" $ io exitSuccess
|
||||||
|
|
||||||
-- TODO for some reason the screen never wakes up after suspend when
|
-- 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
|
-- the nvidia card is up, so block suspend if nvidia card is running
|
||||||
|
@ -377,6 +364,9 @@ getMonitorName = do
|
||||||
(Rectangle x y _ _) <- getFocusedScreen
|
(Rectangle x y _ _) <- getFocusedScreen
|
||||||
return (fromIntegral x, fromIntegral y)
|
return (fromIntegral x, fromIntegral y)
|
||||||
|
|
||||||
|
getFocusedScreen :: X Rectangle
|
||||||
|
getFocusedScreen = withWindowSet $ return . screenRect . W.screenDetail . W.current
|
||||||
|
|
||||||
spawnDmenuCmd :: String -> [String] -> X ()
|
spawnDmenuCmd :: String -> [String] -> X ()
|
||||||
spawnDmenuCmd cmd args = do
|
spawnDmenuCmd cmd args = do
|
||||||
name <- getMonitorName
|
name <- getMonitorName
|
||||||
|
@ -454,21 +444,6 @@ runCleanup ps client = io $ do
|
||||||
mapM_ killPID ps
|
mapM_ killPID ps
|
||||||
stopXMonadService client
|
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 :: X ()
|
||||||
runRestart = restart "xmonad" True
|
runRestart = restart "xmonad" True
|
||||||
|
|
||||||
|
@ -630,6 +605,7 @@ myKeys hs client c =
|
||||||
, ("M-C-t", addName "launch terminal" runTerm)
|
, ("M-C-t", addName "launch terminal" runTerm)
|
||||||
, ("M-C-q", addName "launch calc" runCalc)
|
, ("M-C-q", addName "launch calc" runCalc)
|
||||||
, ("M-C-f", addName "launch file manager" runFileManager)
|
, ("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-v", addName "launch windows VM" $ runVBox >> appendWorkspace myVMWorkspace)
|
||||||
, ("M-C-g", addName "launch GIMP" $ runGimp >> appendWorkspace myGimpWorkspace)
|
, ("M-C-g", addName "launch GIMP" $ runGimp >> appendWorkspace myGimpWorkspace)
|
||||||
] ++
|
] ++
|
||||||
|
@ -653,7 +629,7 @@ myKeys hs client c =
|
||||||
, ("M-M1-=", addName "toggle screensaver" toggleDPMS)
|
, ("M-M1-=", addName "toggle screensaver" toggleDPMS)
|
||||||
, ("M-<F2>", addName "restart xmonad" $ runCleanup hs client >> runRestart)
|
, ("M-<F2>", addName "restart xmonad" $ runCleanup hs client >> runRestart)
|
||||||
, ("M-S-<F2>", addName "recompile xmonad" runRecompile)
|
, ("M-S-<F2>", addName "recompile xmonad" runRecompile)
|
||||||
, ("M-<End>", addName "power menu" myPowerPrompt)
|
, ("M-<End>", addName "power menu" runPowerPrompt)
|
||||||
, ("M-<Home>", addName "quit xmonad" myQuitPrompt)
|
, ("M-<Home>", addName "quit xmonad" runQuitPrompt)
|
||||||
, ("M-<Esc>", addName "switch gpu" runOptimusPrompt)
|
, ("M-<Esc>", addName "switch gpu" runOptimusPrompt)
|
||||||
]
|
]
|
||||||
|
|
|
@ -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
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
module WorkspaceMon (M.fromList, runWorkspaceMon) where
|
module WorkspaceMon (M.fromList, runWorkspaceMon) where
|
||||||
|
|
||||||
|
import Process
|
||||||
import SendXMsg
|
import SendXMsg
|
||||||
|
|
||||||
import qualified Data.Map as M
|
import qualified Data.Map as M
|
||||||
|
@ -19,7 +20,6 @@ import Graphics.X11.Xlib.Extras
|
||||||
import Graphics.X11.Xlib.Misc
|
import Graphics.X11.Xlib.Misc
|
||||||
import Graphics.X11.Xlib.Types
|
import Graphics.X11.Xlib.Types
|
||||||
|
|
||||||
import System.Directory
|
|
||||||
import System.Process (Pid)
|
import System.Process (Pid)
|
||||||
|
|
||||||
-- TOOD it would be really nice if the manner we used to match windows was
|
-- 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 ()
|
handle _ _ = return ()
|
||||||
|
|
||||||
waitAndKill :: String -> Pid -> IO ()
|
waitAndKill :: String -> Pid -> IO ()
|
||||||
waitAndKill tag pid = waitUntilExit pidDir
|
waitAndKill tag pid = waitUntilExit pid >> sendXMsg Workspace tag
|
||||||
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
|
|
||||||
|
|
||||||
withUniquePid :: WatchedPIDs -> Pid -> IO () -> IO ()
|
withUniquePid :: WatchedPIDs -> Pid -> IO () -> IO ()
|
||||||
withUniquePid curPIDs pid f = do
|
withUniquePid curPIDs pid f = do
|
||||||
|
|
|
@ -15,6 +15,7 @@ library
|
||||||
, DBus.IntelBacklight
|
, DBus.IntelBacklight
|
||||||
, DBus.Internal
|
, DBus.Internal
|
||||||
, DBus.Screensaver
|
, DBus.Screensaver
|
||||||
|
, Process
|
||||||
, Xmobar.Common
|
, Xmobar.Common
|
||||||
, Xmobar.Plugins.Bluetooth
|
, Xmobar.Plugins.Bluetooth
|
||||||
, Xmobar.Plugins.IntelBacklight
|
, Xmobar.Plugins.IntelBacklight
|
||||||
|
@ -29,6 +30,7 @@ library
|
||||||
, fdo-notify
|
, fdo-notify
|
||||||
, io-streams >= 1.5.1.0
|
, io-streams >= 1.5.1.0
|
||||||
, mtl >= 2.2.2
|
, mtl >= 2.2.2
|
||||||
|
, unix >= 2.7.2.2
|
||||||
, tcp-streams >= 1.0.1.1
|
, tcp-streams >= 1.0.1.1
|
||||||
, text >= 1.2.3.1
|
, text >= 1.2.3.1
|
||||||
, directory >= 1.3.3.0
|
, directory >= 1.3.3.0
|
||||||
|
@ -47,7 +49,6 @@ executable xmonad
|
||||||
, dbus >= 1.2.7
|
, dbus >= 1.2.7
|
||||||
, directory >= 1.3.3.0
|
, directory >= 1.3.3.0
|
||||||
, my-xmonad
|
, my-xmonad
|
||||||
, process >= 1.6.5.0
|
|
||||||
, unix >= 2.7.2.2
|
, unix >= 2.7.2.2
|
||||||
, xmonad >= 0.13
|
, xmonad >= 0.13
|
||||||
, xmonad-contrib >= 0.13
|
, xmonad-contrib >= 0.13
|
||||||
|
|
Loading…
Reference in New Issue