2011-07-17 19:20:19 +02:00
|
|
|
{-# LANGUAGE TypeFamilies, DeriveDataTypeable #-}
|
|
|
|
|
|
|
|
module Phi.Widgets.Systray ( systray
|
|
|
|
) where
|
|
|
|
|
|
|
|
import Control.Concurrent
|
|
|
|
import Control.Monad
|
|
|
|
|
|
|
|
import Data.Maybe
|
|
|
|
|
|
|
|
import Foreign.C.Types
|
|
|
|
|
|
|
|
import Graphics.X11.Xlib hiding (Display)
|
|
|
|
import qualified Graphics.X11.Xlib as Xlib
|
|
|
|
import Graphics.X11.Xlib.Extras
|
|
|
|
|
|
|
|
import Phi.Bindings.Util
|
|
|
|
|
|
|
|
import Phi.Phi
|
|
|
|
import Phi.Types
|
|
|
|
import Phi.Widget
|
|
|
|
import Phi.X11.Atoms
|
|
|
|
|
|
|
|
|
|
|
|
data SystrayIconState = SystrayIconState deriving Show
|
|
|
|
|
2011-07-18 20:57:19 +02:00
|
|
|
data SystrayState = SystrayState Rectangle [SystrayIconState] deriving Show
|
2011-07-17 19:20:19 +02:00
|
|
|
|
|
|
|
data Systray = Systray deriving Show
|
|
|
|
|
|
|
|
|
|
|
|
instance WidgetClass Systray where
|
|
|
|
type WidgetData Systray = SystrayState
|
|
|
|
|
|
|
|
initWidget (Systray) phi dispvar = do
|
|
|
|
forkIO $ systrayRunner phi dispvar
|
|
|
|
|
2011-07-18 20:57:19 +02:00
|
|
|
return $ SystrayState (head . getScreens $ dispvar) []
|
2011-07-17 19:20:19 +02:00
|
|
|
|
2011-07-18 20:57:19 +02:00
|
|
|
minSize _ (SystrayState systrayScreen icons) height screen = case True of
|
|
|
|
_ | screen == systrayScreen -> (length icons)*height
|
|
|
|
| otherwise -> 0
|
|
|
|
|
2011-07-17 19:20:19 +02:00
|
|
|
weight _ = 0
|
|
|
|
|
2011-07-18 20:57:19 +02:00
|
|
|
render Systray (SystrayState systrayScreen icons) w h screen = case True of
|
|
|
|
_ | screen == systrayScreen -> do
|
|
|
|
return ()
|
|
|
|
| otherwise -> return ()
|
2011-07-17 19:20:19 +02:00
|
|
|
|
|
|
|
|
|
|
|
systrayRunner :: Phi -> Display -> IO ()
|
|
|
|
systrayRunner phi dispvar = do
|
|
|
|
let atoms = getAtoms dispvar
|
|
|
|
initSuccess <- withDisplay dispvar $ flip initSystray atoms
|
|
|
|
|
|
|
|
case initSuccess of
|
|
|
|
Just xembedWindow -> forever $ do
|
|
|
|
m <- receiveMessage phi
|
|
|
|
case (fromMessage m) of
|
|
|
|
Just event ->
|
|
|
|
handleEvent event phi dispvar xembedWindow
|
|
|
|
_ ->
|
|
|
|
return ()
|
|
|
|
Nothing ->
|
|
|
|
return ()
|
|
|
|
|
|
|
|
|
|
|
|
initSystray :: Xlib.Display -> Atoms -> IO (Maybe Window)
|
|
|
|
initSystray disp atoms = do
|
|
|
|
currentSystrayWin <- xGetSelectionOwner disp $ atom_NET_SYSTEM_TRAY_SCREEN atoms
|
|
|
|
|
|
|
|
if currentSystrayWin /= 0 then do
|
|
|
|
pid <- liftM (fromMaybe "" . fmap (\pid -> " (pid" ++ show (fromIntegral pid :: CUShort) ++ ")") . join . fmap listToMaybe) $
|
|
|
|
getWindowProperty16 disp (atom_NET_WM_PID atoms) currentSystrayWin
|
|
|
|
|
|
|
|
putStrLn $ "Phi: another systray is running." ++ pid
|
|
|
|
|
|
|
|
return Nothing
|
|
|
|
else do
|
|
|
|
xembedWin <- createSimpleWindow disp (defaultRootWindow disp) (-1) (-1) 1 1 0 0 0
|
|
|
|
|
|
|
|
-- orient horizontally
|
|
|
|
changeProperty32 disp xembedWin (atom_NET_SYSTEM_TRAY_ORIENTATION atoms) cARDINAL propModeReplace [0]
|
|
|
|
|
|
|
|
-- set visual
|
|
|
|
let rootwin = defaultRootWindow disp
|
|
|
|
screen = defaultScreen disp
|
|
|
|
visual = defaultVisual disp screen
|
|
|
|
visualID = visualIDFromVisual visual
|
|
|
|
changeProperty32 disp xembedWin (atom_NET_SYSTEM_TRAY_VISUAL atoms) vISUALID propModeReplace [fromIntegral visualID]
|
|
|
|
|
|
|
|
xSetSelectionOwner disp (atom_NET_SYSTEM_TRAY_SCREEN atoms) xembedWin currentTime
|
|
|
|
systrayWin <- xGetSelectionOwner disp $ atom_NET_SYSTEM_TRAY_SCREEN atoms
|
|
|
|
if systrayWin /= xembedWin then do
|
|
|
|
destroyWindow disp xembedWin
|
|
|
|
putStrLn $ "Phi: can't initialize systray."
|
|
|
|
return Nothing
|
|
|
|
|
|
|
|
else do
|
|
|
|
allocaXEvent $ \event -> do
|
|
|
|
putClientMessage event rootwin (atomMANAGER atoms) [fromIntegral currentTime, fromIntegral (atom_NET_SYSTEM_TRAY_SCREEN atoms), fromIntegral xembedWin, 0, 0]
|
|
|
|
sendEvent disp rootwin False structureNotifyMask event
|
|
|
|
|
|
|
|
return $ Just xembedWin
|
|
|
|
|
|
|
|
|
|
|
|
sYSTEM_TRAY_REQUEST_DOCK :: CInt
|
|
|
|
sYSTEM_TRAY_REQUEST_DOCK = 0
|
|
|
|
|
|
|
|
sYSTEM_TRAY_BEGIN_MESSAGE :: CInt
|
|
|
|
sYSTEM_TRAY_BEGIN_MESSAGE = 1
|
|
|
|
|
|
|
|
sYSTEM_TRAY_CANCEL_MESSAGE :: CInt
|
|
|
|
sYSTEM_TRAY_CANCEL_MESSAGE = 2
|
|
|
|
|
|
|
|
|
|
|
|
handleEvent :: Event -> Phi -> Display -> Window -> IO ()
|
|
|
|
handleEvent ClientMessageEvent { ev_message_type = message_type, ev_data = messageData, ev_window = window } phi dispvar xembedWindow = do
|
|
|
|
let atoms = getAtoms dispvar
|
|
|
|
when (window == xembedWindow && message_type == atom_NET_SYSTEM_TRAY_OPCODE atoms) $ do
|
|
|
|
case messageData of
|
|
|
|
(_:opcode:iconID:_) -> do
|
|
|
|
case True of
|
2011-07-18 20:57:19 +02:00
|
|
|
_ | opcode == sYSTEM_TRAY_REQUEST_DOCK ->
|
|
|
|
when (iconID /= 0) $ addIcon phi dispvar $ fromIntegral iconID
|
2011-07-17 19:20:19 +02:00
|
|
|
|
2011-07-18 20:57:19 +02:00
|
|
|
| opcode == sYSTEM_TRAY_BEGIN_MESSAGE || opcode == sYSTEM_TRAY_CANCEL_MESSAGE ->
|
2011-07-17 19:20:19 +02:00
|
|
|
return ()
|
|
|
|
|
|
|
|
| otherwise -> do
|
2011-07-18 20:57:19 +02:00
|
|
|
putStrLn "Phi: unknown tray message"
|
2011-07-17 19:20:19 +02:00
|
|
|
return ()
|
|
|
|
|
|
|
|
|
|
|
|
_ ->
|
|
|
|
return ()
|
2011-07-18 20:57:19 +02:00
|
|
|
|
2011-07-17 19:20:19 +02:00
|
|
|
handleEvent _ _ _ _ = return ()
|
|
|
|
|
2011-07-18 20:57:19 +02:00
|
|
|
|
|
|
|
addIcon :: Phi -> Display -> Window -> IO ()
|
|
|
|
addIcon phi display window = do
|
|
|
|
return ()
|
|
|
|
|
|
|
|
|
2011-07-17 19:20:19 +02:00
|
|
|
systray :: Widget
|
|
|
|
systray = Widget $ Systray
|