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,45 +92,59 @@ 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
m <- receiveMessage phi sendMessage phi HoldShutdown
case (fromMessage m) of
Just event -> forever $ do
handleEvent event phi dispvar xembedWindow m <- receiveMessage phi
_ -> case (fromMessage m) of
case (fromMessage m) of Just event ->
Just (RenderIcon midParent window x y w h reset) -> do handleEvent event phi dispvar xembedWindow
errorWindowRef <- liftIO $ newIORef [] _ ->
case (fromMessage m) of
withDisplay dispvar $ \disp -> do Just (RenderIcon midParent window x y w h reset) -> do
liftIO $ do errorWindowRef <- liftIO $ newIORef []
sync disp False
setErrorHandler $ \disp eventptr -> do
event <- getErrorEvent eventptr
when (ev_error_code event == fromIntegral badWindow) $ do
errorWindows <- readIORef errorWindowRef
writeIORef errorWindowRef (ev_resourceid event:errorWindows)
(_, x', y', w', h', _, _) <- liftIO $ getGeometry disp midParent
let resize = (fromIntegral x) /= x' || (fromIntegral y) /= y' || (fromIntegral w) /= w' || (fromIntegral h) /= h'
when resize $ liftIO $ do withDisplay dispvar $ \disp -> do
moveResizeWindow disp midParent (fromIntegral x) (fromIntegral y) (fromIntegral w) (fromIntegral h) liftIO $ flip catch (\_ -> return ()) $ do
resizeWindow disp window (fromIntegral w) (fromIntegral h) sync disp False
liftIO $ sync disp False setErrorHandler $ \disp eventptr -> do
event <- getErrorEvent eventptr
when (resize || reset) $ liftIO $ do when (ev_error_code event == fromIntegral badWindow) $ do
clearArea disp midParent 0 0 (fromIntegral w) (fromIntegral h) True errorWindows <- readIORef errorWindowRef
liftIO $ sync disp False writeIORef errorWindowRef (ev_resourceid event:errorWindows)
clearArea disp window 0 0 (fromIntegral w) (fromIntegral h) True
liftIO $ sync disp False (_, x', y', w', h', _, _) <- getGeometry disp midParent
let resize = (fromIntegral x) /= x' || (fromIntegral y) /= y' || (fromIntegral w) /= w' || (fromIntegral h) /= h'
liftIO $ xSetErrorHandler
when resize $ do
errorWindows <- liftIO $ readIORef errorWindowRef moveResizeWindow disp midParent (fromIntegral x) (fromIntegral y) (fromIntegral w) (fromIntegral h)
mapM_ (removeIcon phi disp) errorWindows resizeWindow disp window (fromIntegral w) (fromIntegral h)
_ -> sync disp False
return ()
clearArea disp midParent 0 0 (fromIntegral w) (fromIntegral h) True
sync disp False
when (resize || reset) $ do
clearArea disp window 0 0 (fromIntegral w) (fromIntegral h) True
sync disp False
xSetErrorHandler
errorWindows <- liftIO $ readIORef errorWindowRef
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 ()
Nothing -> Nothing ->
return () return ()
@ -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
@ -35,9 +37,11 @@ import qualified Phi.Bindings.Util as Util
data XConfig = XConfig { phiXScreenInfo :: !(Display -> IO [Rectangle]) 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,9 +131,30 @@ 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 ()
shutdown <- gets phiShutdown
shutdownHold <- gets phiShutdownHold
when (shutdown && (shutdownHold == 0)) $
liftIO $ exitSuccess
return () 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'}
where where

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