Gracefully shut down systray

This commit is contained in:
Matthias Schiffer 2011-07-19 12:25:08 +02:00
parent 19c4bb3521
commit 387613b2f0
5 changed files with 103 additions and 46 deletions

View file

@ -22,7 +22,7 @@ data Phi = Phi (TChan Message)
data Message = forall a. (Typeable a, Show a) => Message a data Message = forall a. (Typeable a, Show a) => Message a
deriving instance Show Message deriving instance Show Message
data DefaultMessage = Repaint | ResetBackground deriving (Typeable, Show) data DefaultMessage = Repaint | ResetBackground | Shutdown | HoldShutdown | ReleaseShutdown deriving (Typeable, Show)
fromMessage :: (Typeable a, Show a) => Message -> Maybe a fromMessage :: (Typeable a, Show a) => Message -> Maybe a
fromMessage (Message m) = cast m fromMessage (Message m) = cast m

View file

@ -92,7 +92,10 @@ systrayRunner phi dispvar = do
initSuccess <- withDisplay dispvar $ flip initSystray atoms initSuccess <- withDisplay dispvar $ flip initSystray atoms
case initSuccess of case initSuccess of
Just xembedWindow -> flip evalStateT M.empty $ forever $ do Just xembedWindow -> flip evalStateT M.empty $ do
sendMessage phi HoldShutdown
forever $ do
m <- receiveMessage phi m <- receiveMessage phi
case (fromMessage m) of case (fromMessage m) of
Just event -> Just event ->
@ -103,7 +106,7 @@ systrayRunner phi dispvar = do
errorWindowRef <- liftIO $ newIORef [] errorWindowRef <- liftIO $ newIORef []
withDisplay dispvar $ \disp -> do withDisplay dispvar $ \disp -> do
liftIO $ do liftIO $ flip catch (\_ -> return ()) $ do
sync disp False sync disp False
setErrorHandler $ \disp eventptr -> do setErrorHandler $ \disp eventptr -> do
event <- getErrorEvent eventptr event <- getErrorEvent eventptr
@ -111,24 +114,35 @@ systrayRunner phi dispvar = do
errorWindows <- readIORef errorWindowRef errorWindows <- readIORef errorWindowRef
writeIORef errorWindowRef (ev_resourceid event:errorWindows) writeIORef errorWindowRef (ev_resourceid event:errorWindows)
(_, x', y', w', h', _, _) <- liftIO $ getGeometry disp midParent (_, x', y', w', h', _, _) <- getGeometry disp midParent
let resize = (fromIntegral x) /= x' || (fromIntegral y) /= y' || (fromIntegral w) /= w' || (fromIntegral h) /= h' let resize = (fromIntegral x) /= x' || (fromIntegral y) /= y' || (fromIntegral w) /= w' || (fromIntegral h) /= h'
when resize $ liftIO $ do when resize $ do
moveResizeWindow disp midParent (fromIntegral x) (fromIntegral y) (fromIntegral w) (fromIntegral h) moveResizeWindow disp midParent (fromIntegral x) (fromIntegral y) (fromIntegral w) (fromIntegral h)
resizeWindow disp window (fromIntegral w) (fromIntegral h) resizeWindow disp window (fromIntegral w) (fromIntegral h)
liftIO $ sync disp False sync disp False
when (resize || reset) $ liftIO $ do
clearArea disp midParent 0 0 (fromIntegral w) (fromIntegral h) True clearArea disp midParent 0 0 (fromIntegral w) (fromIntegral h) True
liftIO $ sync disp False sync disp False
clearArea disp window 0 0 (fromIntegral w) (fromIntegral h) True
liftIO $ sync disp False
liftIO $ xSetErrorHandler when (resize || reset) $ do
clearArea disp window 0 0 (fromIntegral w) (fromIntegral h) True
sync disp False
xSetErrorHandler
errorWindows <- liftIO $ readIORef errorWindowRef errorWindows <- liftIO $ readIORef errorWindowRef
mapM_ (removeIcon phi disp) errorWindows mapM_ (removeIcon phi disp) errorWindows
_ ->
case (fromMessage m) of
Just Shutdown -> do
windows <- gets M.keys
withDisplay dispvar $ \disp -> do
mapM_ (removeIcon phi disp) windows
liftIO $ do
destroyWindow disp xembedWindow
sync disp False
sendMessage phi ReleaseShutdown
_ -> _ ->
return () return ()
Nothing -> Nothing ->
@ -265,8 +279,12 @@ removeIcon phi disp window = do
sendMessage phi $ RemoveIcon window sendMessage phi $ RemoveIcon window
sendMessage phi Repaint sendMessage phi Repaint
liftIO $ do liftIO $ do
selectInput disp window $ noEventMask
unmapWindow disp window
reparentWindow disp window (defaultRootWindow disp) 0 0 reparentWindow disp window (defaultRootWindow disp) 0 0
destroyWindow disp midParent destroyWindow disp midParent
sync disp False
modify $ M.delete window
_ -> _ ->
return () return ()

View file

@ -530,7 +530,7 @@ premultiply c = a .|. r .|. g .|. b
getWindowScreen :: Xlib.Display -> [Xlib.Rectangle] -> Window -> IO Xlib.Rectangle getWindowScreen :: Xlib.Display -> [Xlib.Rectangle] -> Window -> IO Xlib.Rectangle
getWindowScreen disp screens window = do getWindowScreen disp screens window = flip catch (\_ -> return $ head screens) $ do
(_, _, _, width, height, _, _) <- Xlib.getGeometry disp window (_, _, _, width, height, _, _) <- Xlib.getGeometry disp window
(ret, x, y, _) <- Xlib.translateCoordinates disp window (Xlib.defaultRootWindow disp) 0 0 (ret, x, y, _) <- Xlib.translateCoordinates disp window (Xlib.defaultRootWindow disp) 0 0

View file

@ -22,6 +22,8 @@ import Control.Monad.State
import Control.Monad.Reader import Control.Monad.Reader
import Control.Monad.Trans import Control.Monad.Trans
import System.Exit
import System.Posix.Signals
import System.Posix.Types import System.Posix.Types
import Phi.Phi import Phi.Phi
@ -38,6 +40,8 @@ data XConfig = XConfig { phiXScreenInfo :: !(Display -> IO [Rectangle])
data PhiState = PhiState { phiRootImage :: !Surface data PhiState = PhiState { phiRootImage :: !Surface
, phiPanels :: ![PanelState] , phiPanels :: ![PanelState]
, phiRepaint :: !Bool , phiRepaint :: !Bool
, phiShutdown :: !Bool
, phiShutdownHold :: !Int
} }
data PanelState = PanelState { panelWindow :: !Window data PanelState = PanelState { panelWindow :: !Window
@ -74,13 +78,27 @@ runPhi xconfig config widgets = do
xSetErrorHandler xSetErrorHandler
phi <- initPhi phi <- initPhi
installHandler sigTERM (termHandler phi) Nothing
installHandler sigINT (termHandler phi) Nothing
installHandler sigQUIT (termHandler phi) Nothing
disp <- openDisplay [] disp <- openDisplay []
atoms <- initAtoms disp atoms <- initAtoms disp
selectInput disp (defaultRootWindow disp) $ propertyChangeMask.|.structureNotifyMask selectInput disp (defaultRootWindow disp) $ propertyChangeMask.|.structureNotifyMask
bg <- createImageSurface FormatRGB24 1 1 bg <- createImageSurface FormatRGB24 1 1
runPhiX PhiConfig { phiPhi = phi, phiXConfig = xconfig, phiPanelConfig = config, phiAtoms = atoms } PhiState { phiRootImage = bg, phiPanels = [], phiRepaint = True } $ do runPhiX PhiConfig { phiPhi = phi
, phiXConfig = xconfig
, phiPanelConfig = config
, phiAtoms = atoms
} PhiState { phiRootImage = bg
, phiPanels = []
, phiRepaint = True
, phiShutdown = False
, phiShutdownHold = 0
} $ do
updateRootImage disp updateRootImage disp
screens <- liftIO $ phiXScreenInfo xconfig disp screens <- liftIO $ phiXScreenInfo xconfig disp
@ -113,8 +131,29 @@ runPhi xconfig config widgets = do
message <- receiveMessage phi message <- receiveMessage phi
handleMessage dispvar message handleMessage dispvar message
case (fromMessage message) of
Just Shutdown ->
modify $ \state -> state { phiShutdown = True }
Just HoldShutdown ->
modify $ \state -> state { phiShutdownHold = phiShutdownHold state + 1 }
Just ReleaseShutdown ->
modify $ \state -> state { phiShutdownHold = phiShutdownHold state - 1 }
_ ->
return () return ()
shutdown <- gets phiShutdown
shutdownHold <- gets phiShutdownHold
when (shutdown && (shutdownHold == 0)) $
liftIO $ exitSuccess
return ()
termHandler :: Phi -> Handler
termHandler phi = Catch $ sendMessage phi Shutdown
handlePanel :: Message -> PanelState -> PanelState handlePanel :: Message -> PanelState -> PanelState
handlePanel message panel@PanelState {panelWidgetStates = widgets} = panel {panelWidgetStates = widgets'} handlePanel message panel@PanelState {panelWidgetStates = widgets} = panel {panelWidgetStates = widgets'}

View file

@ -11,14 +11,14 @@ maintainer: mschiffer@universe-factory.net
build-type: Simple build-type: Simple
library library
build-depends: base >= 4, template-haskell, stm, array, containers, transformers, mtl, utf8-string, time, old-locale, X11, cairo, pango build-depends: base >= 4, template-haskell, stm, array, containers, transformers, mtl, utf8-string, time, old-locale, X11, cairo, pango, unix
exposed-modules: Phi.Types, Phi.Phi, Phi.Panel, Phi.Widget, Phi.Border, Phi.X11, exposed-modules: Phi.Types, Phi.Phi, Phi.Panel, Phi.Widget, Phi.Border, Phi.X11,
Phi.Widgets.AlphaBox, Phi.Widgets.Clock, Phi.Widgets.Taskbar, Phi.Widgets.Systray Phi.Widgets.AlphaBox, Phi.Widgets.Clock, Phi.Widgets.Taskbar, Phi.Widgets.Systray
other-modules: Phi.X11.Atoms, Phi.X11.AtomList, Phi.Bindings.Util other-modules: Phi.X11.Atoms, Phi.X11.AtomList, Phi.Bindings.Util
hs-source-dirs: lib hs-source-dirs: lib
extra-libraries: X11 extra-libraries: X11
pkgconfig-depends: cairo >= 1.2.0, cairo-xlib pkgconfig-depends: cairo >= 1.2.0, cairo-xlib
--ghc-options: -fspec-constr-count=16 -threaded ghc-options: -fspec-constr-count=16 -threaded
executable Phi executable Phi
build-depends: base >= 4, phi build-depends: base >= 4, phi