diff --git a/lib/Phi/Bindings/Cairo.hsc b/lib/Phi/Bindings/Cairo.hsc deleted file mode 100644 index 246bc13..0000000 --- a/lib/Phi/Bindings/Cairo.hsc +++ /dev/null @@ -1,51 +0,0 @@ -{-# LANGUAGE ForeignFunctionInterface #-} - -module Phi.Bindings.Cairo ( createXCBSurface - ) where - -import Control.Monad - -import Data.Int -import Data.Word - -import Foreign.C.Types -import Foreign.ForeignPtr -import Foreign.Marshal.Alloc -import Foreign.Marshal.Utils -import Foreign.Ptr -import Foreign.Storable - -import Graphics.Rendering.Cairo.Types -import Graphics.XHB (toValue) -import Graphics.XHB.Connection.XCB -import Graphics.XHB.Gen.Xproto (DRAWABLE, VISUALTYPE(..)) - - -#include - - -foreign import ccall "cairo-xlib.h cairo_xcb_surface_create" - cairo_xcb_surface_create :: Ptr XCBConnection -> DRAWABLE -> Ptr VISUALTYPE -> CInt -> CInt -> IO (Ptr Surface) - -instance Storable VISUALTYPE where - sizeOf _ = (#size xcb_visualtype_t) - alignment _ = alignment (undefined :: CInt) - - peek _ = error "VISUALTYPE: peek not implemented" - - poke vt (MkVISUALTYPE visual_id _class bits_per_rgb_value colormap_entries red_mask green_mask blue_mask) = do - (#poke xcb_visualtype_t, visual_id) vt visual_id - (#poke xcb_visualtype_t, _class) vt (toValue _class :: Word8) - (#poke xcb_visualtype_t, bits_per_rgb_value) vt bits_per_rgb_value - (#poke xcb_visualtype_t, colormap_entries) vt colormap_entries - (#poke xcb_visualtype_t, red_mask) vt red_mask - (#poke xcb_visualtype_t, green_mask) vt green_mask - (#poke xcb_visualtype_t, blue_mask) vt blue_mask - -createXCBSurface :: Connection -> DRAWABLE -> VISUALTYPE -> CInt -> CInt -> IO Surface -createXCBSurface conn drawable visual width height = - with visual $ \visualptr -> withConnection conn $ \connptr -> do - surfacePtr <- cairo_xcb_surface_create connptr drawable visualptr width height - surface <- mkSurface surfacePtr - manageSurface surface - return surface diff --git a/lib/Phi/Bindings/XCB.hsc b/lib/Phi/Bindings/XCB.hsc new file mode 100644 index 0000000..33aff03 --- /dev/null +++ b/lib/Phi/Bindings/XCB.hsc @@ -0,0 +1,92 @@ +{-# LANGUAGE ForeignFunctionInterface #-} + +module Phi.Bindings.XCB ( Connection + , connect + , createXCBSurface + , flush + , clearArea + ) where + +import Control.Monad + +import Data.Int +import Data.Word + +import Foreign.C.String +import Foreign.C.Types +import Foreign.ForeignPtr +import Foreign.Marshal.Alloc +import Foreign.Marshal.Utils +import Foreign.Ptr +import Foreign.Storable + +import Graphics.Rendering.Cairo.Types +import Graphics.XHB (toValue) +import Graphics.XHB.Gen.Xproto (DRAWABLE, WINDOW, VISUALTYPE(..)) + + +#include +#include +#include + + +data Connection = Connection (ForeignPtr Connection) + +foreign import ccall "xcb/xcb.h xcb_connect" xcb_connect :: CString -> Ptr CInt -> IO (Ptr Connection) +foreign import ccall "xcb/xcb.h &xcb_disconnect" p_xcb_disconnect :: FunPtr (Ptr Connection -> IO ()) + +connect :: IO Connection +connect = do + conn <- xcb_connect nullPtr nullPtr + newForeignPtr p_xcb_disconnect conn >>= return . Connection + +foreign import ccall "cairo-xlib.h cairo_xcb_surface_create" + cairo_xcb_surface_create :: Ptr Connection -> DRAWABLE -> Ptr VISUALTYPE -> CInt -> CInt -> IO (Ptr Surface) + +instance Storable VISUALTYPE where + sizeOf _ = (#size xcb_visualtype_t) + alignment _ = alignment (undefined :: CInt) + + peek _ = error "VISUALTYPE: peek not implemented" + + poke vt (MkVISUALTYPE visual_id _class bits_per_rgb_value colormap_entries red_mask green_mask blue_mask) = do + (#poke xcb_visualtype_t, visual_id) vt visual_id + (#poke xcb_visualtype_t, _class) vt (toValue _class :: Word8) + (#poke xcb_visualtype_t, bits_per_rgb_value) vt bits_per_rgb_value + (#poke xcb_visualtype_t, colormap_entries) vt colormap_entries + (#poke xcb_visualtype_t, red_mask) vt red_mask + (#poke xcb_visualtype_t, green_mask) vt green_mask + (#poke xcb_visualtype_t, blue_mask) vt blue_mask + +createXCBSurface :: Connection -> DRAWABLE -> VISUALTYPE -> CInt -> CInt -> IO Surface +createXCBSurface (Connection conn) drawable visual width height = + with visual $ \visualptr -> withForeignPtr conn $ \connptr -> do + surfacePtr <- cairo_xcb_surface_create connptr drawable visualptr width height + surface <- mkSurface surfacePtr + manageSurface surface + return surface + +foreign import ccall "xcb/xcb.h xcb_flush" + xcb_flush :: Ptr Connection -> IO () + +flush :: Connection -> IO () +flush (Connection conn) = withForeignPtr conn xcb_flush + +type VOID_COOKIE = CUInt + +foreign import ccall "xcb/xcb.h xcb_request_check" + xcb_request_check :: Ptr Connection -> VOID_COOKIE -> IO (Ptr ()) + +requestCheck :: Ptr Connection -> VOID_COOKIE -> IO () +requestCheck conn cookie = do + ret <- xcb_request_check conn cookie + when (ret /= nullPtr) $ + free ret + +foreign import ccall "xcb/xproto.h xcb_clear_area" + xcb_clear_area :: Ptr Connection -> Word8 -> WINDOW -> Int16 -> Int16 -> Word16 -> Word16 -> IO VOID_COOKIE + +clearArea :: Connection -> Bool -> WINDOW -> Int16 -> Int16 -> Word16 -> Word16 -> IO () +clearArea (Connection conn) exposures window x y width height = withForeignPtr conn $ \connptr -> do + cookie <- xcb_clear_area connptr (if exposures then 1 else 0) window x y width height + requestCheck connptr cookie diff --git a/lib/Phi/Border.hs b/lib/Phi/Border.hs index 2e1e008..ca5e515 100644 --- a/lib/Phi/Border.hs +++ b/lib/Phi/Border.hs @@ -56,11 +56,11 @@ defaultBorderConfig = BorderConfig { margin = simpleBorderWidth 0 , borderWeight = 1 } -data Border w s c d = (Widget w s c d) => Border !BorderConfig !w +data Border w s c = (Widget w s c) => Border !BorderConfig !w -data BorderCache w s c d = (Widget w s c d) => BorderCache !c +data BorderCache w s c = (Widget w s c) => BorderCache !c -instance (Eq s, Display d) => Widget (Border w s c d) s (BorderCache w s c d) d where +instance Eq s => Widget (Border w s c) s (BorderCache w s c) where initWidget (Border _ w) = initWidget w initCache (Border _ w) = BorderCache $ initCache w @@ -165,5 +165,5 @@ roundRectangle x y width height radius = do arc (x + radius) (y + radius) radius pi (pi*3/2) closePath -border :: (Widget w s c d) => BorderConfig -> w -> Border w s c d +border :: (Widget w s c) => BorderConfig -> w -> Border w s c border = Border diff --git a/lib/Phi/Phi.hs b/lib/Phi/Phi.hs index 4a896c7..df71a1c 100644 --- a/lib/Phi/Phi.hs +++ b/lib/Phi/Phi.hs @@ -7,7 +7,6 @@ module Phi.Phi ( Phi , initPhi , dupPhi , sendMessage - , sendMessages , receiveMessage , messageAvailable ) where @@ -37,9 +36,6 @@ dupPhi (Phi chan) = liftM Phi $ liftIO $ atomically $ dupTChan chan sendMessage :: (MonadIO m, Typeable a, Show a) => Phi -> a -> m () sendMessage (Phi chan) = liftIO . atomically . writeTChan chan . Message -sendMessages :: (MonadIO m, Typeable a, Show a) => Phi -> [a] -> m () -sendMessages (Phi chan) = liftIO . atomically . mapM_ (writeTChan chan . Message) - receiveMessage :: MonadIO m => Phi -> m Message receiveMessage (Phi chan) = liftIO $ atomically $ readTChan chan diff --git a/lib/Phi/Widget.hs b/lib/Phi/Widget.hs index 3687630..788abc2 100644 --- a/lib/Phi/Widget.hs +++ b/lib/Phi/Widget.hs @@ -1,7 +1,10 @@ -{-# LANGUAGE ExistentialQuantification, StandaloneDeriving, MultiParamTypeClasses, FunctionalDependencies, TypeSynonymInstances, FlexibleInstances, TypeFamilies #-} +{-# LANGUAGE ExistentialQuantification, StandaloneDeriving, DeriveDataTypeable, MultiParamTypeClasses, FunctionalDependencies, TypeSynonymInstances, FlexibleInstances #-} -module Phi.Widget ( Rectangle(..) +module Phi.Widget ( XEvent(..) , Display(..) + , withDisplay + , getAtoms + , XMessage(..) , unionArea , SurfaceSlice(..) , Widget(..) @@ -20,6 +23,7 @@ module Phi.Widget ( Rectangle(..) import Control.Arrow import Control.Arrow.Transformer import Control.CacheArrow +import Control.Concurrent.MVar import Control.Monad import Control.Monad.State.Strict hiding (lift) import Control.Monad.IO.Class @@ -27,57 +31,67 @@ import Control.Monad.IO.Class import Data.Maybe import Data.Typeable +import Graphics.XHB import Graphics.Rendering.Cairo import Phi.Phi import Phi.X11.Atoms -data Rectangle = Rectangle { rect_x :: !Int - , rect_y :: !Int - , rect_width :: !Int - , rect_height :: !Int - } deriving (Show, Eq) +data Display = Display !Connection !Atoms -class Display d where - type Window d :: * +newtype XEvent = XEvent SomeEvent deriving Typeable + +instance Show XEvent where + show _ = "XEvent (..)" -unionArea :: Rectangle -> Rectangle -> Int -unionArea a b = uw*uh +withDisplay :: MonadIO m => Display -> (Connection -> m a) -> m a +withDisplay (Display conn _) f = f conn + +getAtoms :: Display -> Atoms +getAtoms (Display _ atoms) = atoms + +data XMessage = UpdateScreens [(RECTANGLE, WINDOW)] deriving (Show, Typeable) + + +unionArea :: RECTANGLE -> RECTANGLE -> Int +unionArea a b = fromIntegral $ uw*uh where uw = max 0 $ (min ax2 bx2) - (max ax1 bx1) uh = max 0 $ (min ay2 by2) - (max ay1 by1) - Rectangle ax1 ay1 aw ah = a - Rectangle bx1 by1 bw bh = b + MkRECTANGLE ax1 ay1 aw ah = a + MkRECTANGLE bx1 by1 bw bh = b - ax2 = ax1 + aw - ay2 = ay1 + ah + ax2 = ax1 + fromIntegral aw + ay2 = ay1 + fromIntegral ah - bx2 = bx1 + bw - by2 = by1 + bh + bx2 = bx1 + fromIntegral bw + by2 = by1 + fromIntegral bh data SurfaceSlice = SurfaceSlice !Int !Surface -class (Eq s, Display d) => Widget w s c d | w -> s, w -> c, w -> d where - initWidget :: w -> Phi -> d -> [(Rectangle, Window d)] -> IO s +class Eq s => Widget w s c | w -> s, w -> c where + initWidget :: w -> Phi -> Display -> [(RECTANGLE, WINDOW)] -> IO s initCache :: w -> c - minSize :: w -> s -> Int -> Rectangle -> Int + minSize :: w -> s -> Int -> RECTANGLE -> Int weight :: w -> Float weight _ = 0 - render :: w -> s -> Int -> Int -> Int -> Int -> Rectangle -> StateT c IO [(Bool, SurfaceSlice)] + render :: w -> s -> Int -> Int -> Int -> Int -> RECTANGLE -> StateT c IO [(Bool, SurfaceSlice)] handleMessage :: w -> s -> Message -> s handleMessage _ priv _ = priv +deriving instance Eq RECTANGLE + type IOCache = CacheArrow (Kleisli IO) -type RenderCache s = IOCache (s, Int, Int, Int, Int, Rectangle) Surface +type RenderCache s = IOCache (s, Int, Int, Int, Int, RECTANGLE) Surface createIOCache :: Eq a => (a -> IO b) -> IOCache a b createIOCache = lift . Kleisli @@ -89,8 +103,8 @@ runIOCache a = do put cache' return b -createRenderCache :: (s -> Int -> Int -> Int -> Int -> Rectangle -> Render ()) - -> CacheArrow (Kleisli IO) (s, Int, Int, Int, Int, Rectangle) Surface +createRenderCache :: (s -> Int -> Int -> Int -> Int -> RECTANGLE -> Render ()) + -> CacheArrow (Kleisli IO) (s, Int, Int, Int, Int, RECTANGLE) Surface createRenderCache f = lift . Kleisli $ \(state, x, y, w, h, screen) -> do surface <- createImageSurface FormatARGB32 w h renderWith surface $ do @@ -100,22 +114,22 @@ createRenderCache f = lift . Kleisli $ \(state, x, y, w, h, screen) -> do f state x y w h screen return surface -renderCached :: Eq s => s -> Int -> Int -> Int -> Int -> Rectangle -> StateT (RenderCache s) IO [(Bool, SurfaceSlice)] +renderCached :: Eq s => s -> Int -> Int -> Int -> Int -> RECTANGLE -> StateT (RenderCache s) IO [(Bool, SurfaceSlice)] renderCached state x y w h screen = do cache <- get (surf, updated, cache') <- liftIO $ runKleisli (runCache' cache) (state, x, y, w, h, screen) put cache' return [(updated, SurfaceSlice 0 surf)] -data CompoundWidget a sa ca b sb cb d = (Widget a sa ca d, Widget b sb cb d) => CompoundWidget !a !b +data CompoundWidget a sa ca b sb cb = (Widget a sa ca, Widget b sb cb) => CompoundWidget !a !b -data CompoundState a sa ca b sb cb d = (Widget a sa ca d, Widget b sb cb d) => CompoundState !sa !sb -deriving instance Eq (CompoundState a sa ca b sb cb d) +data CompoundState a sa ca b sb cb = (Widget a sa ca, Widget b sb cb) => CompoundState !sa !sb +deriving instance Eq (CompoundState a sa ca b sb cb) -data CompoundCache a sa ca b sb cb d = (Widget a sa ca d, Widget b sb cb d) => CompoundCache !ca !cb +data CompoundCache a sa ca b sb cb = (Widget a sa ca, Widget b sb cb) => CompoundCache !ca !cb -instance Display d => Widget (CompoundWidget a sa ca b sb cb d) (CompoundState a sa ca b sb cb d) (CompoundCache a sa ca b sb cb d) d where +instance Widget (CompoundWidget a sa ca b sb cb) (CompoundState a sa ca b sb cb) (CompoundCache a sa ca b sb cb) where initWidget (CompoundWidget a b) phi disp screens = liftM2 CompoundState (initWidget a phi disp screens) (initWidget b phi disp screens) initCache (CompoundWidget a b) = CompoundCache (initCache a) (initCache b) @@ -140,15 +154,15 @@ instance Display d => Widget (CompoundWidget a sa ca b sb cb d) (CompoundState a handleMessage (CompoundWidget a b) (CompoundState sa sb) message = CompoundState (handleMessage a sa message) (handleMessage b sb message) -weight' :: (Widget a sa ca d) => a -> Float +weight' :: (Widget a sa ca) => a -> Float weight' = max 0 . weight -(<~>) :: (Widget a sa ca d, Widget b sb cb d) => a -> b -> CompoundWidget a sa ca b sb cb d +(<~>) :: (Widget a sa ca, Widget b sb cb) => a -> b -> CompoundWidget a sa ca b sb cb a <~> b = CompoundWidget a b -data Separator d = Separator !Int !Float deriving (Show, Eq) +data Separator = Separator !Int !Float deriving (Show, Eq) -instance Display d => Widget (Separator d) () (RenderCache ()) d where +instance Widget Separator () (RenderCache ()) where initWidget _ _ _ _ = return () initCache _ = createRenderCache $ \_ _ _ _ _ _ -> do setOperator OperatorClear @@ -159,5 +173,5 @@ instance Display d => Widget (Separator d) () (RenderCache ()) d where render _ = renderCached -separator :: Int -> Float -> Separator d +separator :: Int -> Float -> Separator separator = Separator diff --git a/lib/Phi/Widgets/AlphaBox.hs b/lib/Phi/Widgets/AlphaBox.hs index 59f8aea..6f989ea 100644 --- a/lib/Phi/Widgets/AlphaBox.hs +++ b/lib/Phi/Widgets/AlphaBox.hs @@ -13,11 +13,11 @@ import Control.Monad.State.Strict import Graphics.Rendering.Cairo -data AlphaBox w s c d = (Widget w s c d) => AlphaBox !Double !w +data AlphaBox w s c = (Widget w s c) => AlphaBox !Double !w -data AlphaBoxCache w s c d = (Widget w s c d) => AlphaBoxCache !c +data AlphaBoxCache w s c = (Widget w s c) => AlphaBoxCache !c -instance (Eq s, Display d) => Widget (AlphaBox w s c d) s (AlphaBoxCache w s c d) d where +instance Eq s => Widget (AlphaBox w s c) s (AlphaBoxCache w s c) where initWidget (AlphaBox _ w) = initWidget w initCache (AlphaBox _ w) = AlphaBoxCache $ initCache w @@ -47,6 +47,6 @@ instance (Eq s, Display d) => Widget (AlphaBox w s c d) s (AlphaBoxCache w s c d handleMessage (AlphaBox _ w) = handleMessage w -alphaBox :: (Widget w s c d) => Double -> w -> AlphaBox w s c d +alphaBox :: (Widget w s c) => Double -> w -> AlphaBox w s c alphaBox = AlphaBox diff --git a/lib/Phi/Widgets/Clock.hs b/lib/Phi/Widgets/Clock.hs index 26b777f..9282432 100644 --- a/lib/Phi/Widgets/Clock.hs +++ b/lib/Phi/Widgets/Clock.hs @@ -34,7 +34,7 @@ data ClockConfig = ClockConfig { clockFormat :: !String defaultClockConfig :: ClockConfig defaultClockConfig = ClockConfig "%R" (0, 0, 0, 1) 0 50 -data Clock d = Clock !ClockConfig deriving (Show, Eq) +data Clock = Clock !ClockConfig deriving (Show, Eq) deriving instance Eq ZonedTime @@ -42,7 +42,7 @@ data ClockState = ClockState !ZonedTime deriving (Show, Eq) data ClockMessage = UpdateTime !ZonedTime deriving (Show, Typeable) -instance Display d => Widget (Clock d) ClockState (RenderCache ClockState) d where +instance Widget Clock ClockState (RenderCache ClockState) where initWidget (Clock _) phi _ _ = do forkIO $ forever $ do time <- getZonedTime @@ -85,6 +85,6 @@ instance Display d => Widget (Clock d) ClockState (RenderCache ClockState) d whe _ -> priv -clock :: ClockConfig -> Clock d +clock :: ClockConfig -> Clock clock config = do - Clock config + Clock config \ No newline at end of file diff --git a/lib/Phi/Widgets/X11/Systray.hs b/lib/Phi/Widgets/Systray.hs similarity index 96% rename from lib/Phi/Widgets/X11/Systray.hs rename to lib/Phi/Widgets/Systray.hs index 8f10a60..27a5e34 100644 --- a/lib/Phi/Widgets/X11/Systray.hs +++ b/lib/Phi/Widgets/Systray.hs @@ -1,7 +1,7 @@ {-# LANGUAGE MultiParamTypeClasses, DeriveDataTypeable, TypeSynonymInstances, FlexibleInstances #-} -module Phi.Widgets.X11.Systray ( systray - ) where +module Phi.Widgets.Systray ( systray + ) where import Control.Concurrent import Control.Monad @@ -178,6 +178,18 @@ initSystray disp atoms = do 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 + +xEMBED_EMBEDDED_NOTIFY :: CInt +xEMBED_EMBEDDED_NOTIFY = 0 + handleEvent :: Event -> Phi -> Display -> Window -> Window -> StateT (M.Map Window Window) IO () handleEvent message@ClientMessageEvent { ev_message_type = message_type, ev_data = messageData, ev_window = window } phi dispvar panelWindow xembedWindow = do let atoms = getAtoms dispvar diff --git a/lib/Phi/Widgets/X11/Taskbar.hs b/lib/Phi/Widgets/Taskbar.hs similarity index 75% rename from lib/Phi/Widgets/X11/Taskbar.hs rename to lib/Phi/Widgets/Taskbar.hs index d52d600..34ec0a5 100644 --- a/lib/Phi/Widgets/X11/Taskbar.hs +++ b/lib/Phi/Widgets/Taskbar.hs @@ -1,17 +1,16 @@ {-# LANGUAGE MultiParamTypeClasses, DeriveDataTypeable, TypeSynonymInstances, FlexibleInstances #-} -module Phi.Widgets.X11.Taskbar ( IconStyle - , idIconStyle - , desaturateIconStyle - , TaskStyle(..) - , DesktopStyle(..) - , TaskbarConfig(..) - , defaultTaskbarConfig - , Taskbar - , taskbar - ) where +module Phi.Widgets.Taskbar ( IconStyle + , idIconStyle + , desaturateIconStyle + , TaskStyle(..) + , DesktopStyle(..) + , TaskbarConfig(..) + , defaultTaskbarConfig + , Taskbar + , taskbar + ) where -import Control.Arrow import Control.Concurrent import Control.Monad import Control.Monad.State.Strict @@ -39,8 +38,9 @@ import Graphics.Rendering.Pango.Enums (PangoRectangle(..)) import Graphics.Rendering.Pango.Layout import Graphics.Rendering.Pango.Font -import Graphics.XHB -import Graphics.XHB.Gen.Xproto +import Graphics.X11.Xlib (Window) +import qualified Graphics.X11.Xlib as Xlib +import qualified Graphics.X11.Xlib.Extras as XExtras import Codec.Binary.UTF8.String @@ -48,9 +48,7 @@ import Phi.Phi import Phi.Types import Phi.Border import Phi.Widget -import Phi.X11 import Phi.X11.Atoms -import Phi.X11.Util newtype IconStyle = IconStyle { withIconStyle :: Surface -> Render () } @@ -139,13 +137,13 @@ defaultTaskbarConfig = TaskbarConfig { taskMaxSize = 200 data Taskbar = Taskbar TaskbarConfig -data TaskbarState = TaskbarState { taskbarScreens :: ![Rectangle] - , taskbarActiveWindow :: !WINDOW +data TaskbarState = TaskbarState { taskbarScreens :: ![Xlib.Rectangle] + , taskbarActiveWindow :: !Window , taskbarDesktopCount :: !Int , taskbarCurrentDesktop :: !Int , taskbarDesktopNames :: ![String] - , taskbarWindows :: ![WINDOW] - , taskbarWindowStates :: !(M.Map WINDOW WindowState) + , taskbarWindows :: ![Window] + , taskbarWindowStates :: !(M.Map Window WindowState) } deriving Eq data Icon = Icon !Unique !Int !Surface @@ -162,7 +160,7 @@ data WindowState = WindowState { windowTitle :: !String , windowDesktop :: !Int , windowVisible :: !Bool , windowIcons :: ![Icon] - , windowGeometry :: !Rectangle + , windowGeometry :: !Xlib.Rectangle } deriving (Eq, Show) data WindowCache = WindowCache { createScaledIconCached :: !(IOCache ([Icon], Int) (Maybe Icon)) @@ -181,7 +179,7 @@ emptyWindowCache = WindowCache { createScaledIconCached = createIOCache createSc } data TaskbarCache = TaskbarCache { desktopCaches :: !(M.Map Int DesktopCache) - , windowCaches :: !(M.Map WINDOW WindowCache) + , windowCaches :: !(M.Map Window WindowCache) } -- substitute for the liftT function in Data.Accessor.MonadState that uses the strict StateT variant @@ -202,19 +200,19 @@ liftIOStateT m = do cached :: (MonadIO m, Eq a) => A.T s (IOCache a b) -> a -> StateT s m b cached t = liftT t . liftIOStateT . runIOCache -data TaskbarMessage = WindowListUpdate ![WINDOW] !(M.Map WINDOW WindowState) +data TaskbarMessage = WindowListUpdate ![Xlib.Window] !(M.Map Window WindowState) | DesktopCountUpdate !Int | CurrentDesktopUpdate !Int | DesktopNamesUpdate ![String] - | ActiveWindowUpdate !WINDOW + | ActiveWindowUpdate !Window deriving (Typeable, Show) -instance Widget Taskbar TaskbarState (M.Map WINDOW WindowCache) X11 where +instance Widget Taskbar TaskbarState (M.Map Window WindowCache) where initWidget (Taskbar _) phi dispvar screens = do phi' <- dupPhi phi forkIO $ taskbarRunner phi' dispvar - return $ TaskbarState (map fst screens) (fromXid xidNone) 0 (-1) [] [] M.empty + return $ TaskbarState (map fst screens) 0 0 (-1) [] [] M.empty initCache _ = M.empty @@ -399,14 +397,14 @@ windowOnDesktop :: Int -> WindowState -> Bool windowOnDesktop desktop state = (windowVisible state) && (desktop == windowDesktop state) -taskbarRunner :: Phi -> X11 -> IO () -taskbarRunner phi x11 = do - (windows, states) <- liftIO $ do - (windows, states) <- getWindowStates x11 M.empty - desktopCount <- getDesktopCount x11 - current <- getCurrentDesktop x11 - names <- getDesktopNames x11 - activeWindow <- getActiveWindow x11 +taskbarRunner :: Phi -> Display -> IO () +taskbarRunner phi dispvar = do + (windows, states) <- liftIO $ withDisplay dispvar $ \disp -> do + (windows, states) <- getWindowStates disp (getAtoms dispvar) M.empty + desktopCount <- getDesktopCount disp (getAtoms dispvar) + current <- getCurrentDesktop disp (getAtoms dispvar) + names <- getDesktopNames disp (getAtoms dispvar) + activeWindow <- getActiveWindow disp (getAtoms dispvar) sendMessage phi $ WindowListUpdate windows states sendMessage phi $ DesktopCountUpdate desktopCount sendMessage phi $ CurrentDesktopUpdate current @@ -418,57 +416,47 @@ taskbarRunner phi x11 = do flip evalStateT (windows, states) $ forever $ do m <- receiveMessage phi case (fromMessage m) of - Just (XEvent event) -> - handleEvent phi x11 event + Just event -> + handleEvent phi dispvar event _ -> return () - -handleEvent :: Phi -> X11 -> SomeEvent -> StateT ([WINDOW], M.Map WINDOW WindowState) IO () -handleEvent phi x11 event = - case (fromEvent event) of - Just e -> handlePropertyNotifyEvent phi x11 e - Nothing -> case (fromEvent event) of - Just e -> handleConfigureNotifyEvent phi x11 e - Nothing -> return () - -handlePropertyNotifyEvent :: Phi -> X11 -> PropertyNotifyEvent -> StateT ([WINDOW], M.Map WINDOW WindowState) IO () -handlePropertyNotifyEvent phi x11 MkPropertyNotifyEvent {atom_PropertyNotifyEvent = atom, window_PropertyNotifyEvent = window} = do - let atoms = x11Atoms x11 - rootwin = root_SCREEN . x11Screen $ x11 - - when (elem atom $ map ($ atoms) [ atom_NET_ACTIVE_WINDOW - , atom_NET_NUMBER_OF_DESKTOPS - , atom_NET_CURRENT_DESKTOP - , atom_NET_DESKTOP_NAMES - , atom_NET_CLIENT_LIST - , atom_NET_WM_ICON - , atomWM_NAME - , atom_NET_WM_NAME - , atom_NET_WM_DESKTOP - , atom_NET_WM_STATE - ]) $ do +handleEvent :: Phi -> Display -> XExtras.Event -> StateT ([Window], M.Map Window WindowState) IO () +handleEvent phi dispvar XExtras.PropertyEvent {XExtras.ev_atom = atom, XExtras.ev_window = window} = do + let atoms = getAtoms dispvar + + when (elem atom $ Xlib.wM_NAME : map ($ atoms) [ atom_NET_ACTIVE_WINDOW + , atom_NET_NUMBER_OF_DESKTOPS + , atom_NET_CURRENT_DESKTOP + , atom_NET_DESKTOP_NAMES + , atom_NET_CLIENT_LIST + , atom_NET_WM_ICON + , atom_NET_WM_NAME + , atom_NET_WM_DESKTOP + , atom_NET_WM_STATE + ]) $ withDisplay dispvar $ \disp -> do + let rootwin = Xlib.defaultRootWindow disp if (window == rootwin) then do when (atom == atom_NET_ACTIVE_WINDOW atoms) $ do - activeWindow <- liftIO $ getActiveWindow x11 + activeWindow <- liftIO $ getActiveWindow disp atoms sendMessage phi $ ActiveWindowUpdate activeWindow sendMessage phi Repaint when (atom == atom_NET_NUMBER_OF_DESKTOPS atoms) $ do - desktopCount <- liftIO $ getDesktopCount x11 + desktopCount <- liftIO $ getDesktopCount disp atoms sendMessage phi $ DesktopCountUpdate desktopCount sendMessage phi Repaint when (atom == atom_NET_CURRENT_DESKTOP atoms) $ do - current <- liftIO $ getCurrentDesktop x11 + current <- liftIO $ getCurrentDesktop disp atoms sendMessage phi $ CurrentDesktopUpdate current sendMessage phi Repaint when (atom == atom_NET_DESKTOP_NAMES atoms) $ do - names <- liftIO $ getDesktopNames x11 + names <- liftIO $ getDesktopNames disp atoms sendMessage phi $ DesktopNamesUpdate names sendMessage phi Repaint when (atom == atom_NET_CLIENT_LIST atoms) $ do (windows, windowStates) <- get - (windows', windowStates') <- liftIO $ getWindowStates x11 windowStates + (windows', windowStates') <- liftIO $ getWindowStates disp atoms windowStates when (windows /= windows') $ do sendMessage phi $ WindowListUpdate windows' windowStates' @@ -480,14 +468,14 @@ handlePropertyNotifyEvent phi x11 MkPropertyNotifyEvent {atom_PropertyNotifyEven when (elem window windows) $ do case () of _ | (atom == atom_NET_WM_ICON atoms) -> do - icons <- liftIO $ getWindowIcons x11 window + icons <- liftIO $ getWindowIcons disp atoms window let windowStates' = M.update (\state -> Just state {windowIcons = icons}) window windowStates sendMessage phi $ WindowListUpdate windows windowStates' sendMessage phi Repaint put (windows, windowStates') | otherwise -> do - (name, desktop, visible) <- liftIO $ getWindowInfo x11 window + (name, desktop, visible) <- liftIO $ getWindowInfo disp atoms window let mwindowState = M.lookup window windowStates case mwindowState of Just windowState -> do @@ -501,45 +489,44 @@ handlePropertyNotifyEvent phi x11 MkPropertyNotifyEvent {atom_PropertyNotifyEven Nothing -> return () - -handleConfigureNotifyEvent :: Phi -> X11 -> ConfigureNotifyEvent -> StateT ([WINDOW], M.Map WINDOW WindowState) IO () -handleConfigureNotifyEvent phi x11 MkConfigureNotifyEvent {window_ConfigureNotifyEvent = window} = do - let conn = x11Connection x11 +handleEvent phi dispvar XExtras.ConfigureEvent {XExtras.ev_window = window} = do (windows, windowStates) <- get - when (elem window windows) $ do - let geom = fmap windowGeometry . M.lookup window $ windowStates - geom' <- liftIO $ getWindowGeometry x11 window + when (elem window windows) $ withDisplay dispvar $ \disp -> do + let geom = fmap windowGeometry . M.lookup window $ windowStates + geom' <- liftIO $ getWindowGeometry disp window when (geom /= (Just geom')) $ do let windowStates' = M.update (\state -> Just state {windowGeometry = geom'}) window windowStates sendMessage phi $ WindowListUpdate windows windowStates' sendMessage phi Repaint put (windows, windowStates') +handleEvent _ _ _ = return () -getDesktopCount :: X11 -> IO Int -getDesktopCount x11 = - liftM (fromIntegral . fromMaybe 0 . join . fmap listToMaybe) $ getProperty32 (x11Connection x11) (root_SCREEN . x11Screen $ x11) (atom_NET_NUMBER_OF_DESKTOPS . x11Atoms $ x11) -getCurrentDesktop :: X11 -> IO Int -getCurrentDesktop x11 = - liftM (fromIntegral . fromMaybe (-1) . join . fmap listToMaybe) $ getProperty32 (x11Connection x11) (root_SCREEN . x11Screen $ x11) (atom_NET_CURRENT_DESKTOP . x11Atoms $ x11) +getDesktopCount :: Xlib.Display -> Atoms -> IO Int +getDesktopCount disp atoms = + liftM (fromIntegral . fromMaybe 0 . join . fmap listToMaybe) $ XExtras.getWindowProperty32 disp (atom_NET_NUMBER_OF_DESKTOPS atoms) $ Xlib.defaultRootWindow disp -getDesktopNames :: X11 -> IO [String] -getDesktopNames x11 = - liftM (map (decode . map fromIntegral) . break' . fromMaybe []) $ getProperty8 (x11Connection x11) (root_SCREEN . x11Screen $ x11) (atom_NET_DESKTOP_NAMES . x11Atoms $ x11) +getCurrentDesktop :: Xlib.Display -> Atoms -> IO Int +getCurrentDesktop disp atoms = + liftM (fromIntegral . fromMaybe (-1) . join . fmap listToMaybe) $ XExtras.getWindowProperty32 disp (atom_NET_CURRENT_DESKTOP atoms) $ Xlib.defaultRootWindow disp + +getDesktopNames :: Xlib.Display -> Atoms -> IO [String] +getDesktopNames disp atoms = + liftM (map (decode . map fromIntegral) . break' . fromMaybe []) $ XExtras.getWindowProperty8 disp (atom_NET_DESKTOP_NAMES atoms) $ Xlib.defaultRootWindow disp where break' l = case dropWhile (== 0) l of [] -> [] l' -> w : break' l'' where (w, l'') = break (== 0) l' -getActiveWindow :: X11 -> IO WINDOW -getActiveWindow x11 = - liftM (fromXid . toXid . fromMaybe 0 . join . fmap listToMaybe) $ getProperty32 (x11Connection x11) (root_SCREEN . x11Screen $ x11) (atom_NET_ACTIVE_WINDOW . x11Atoms $ x11) +getActiveWindow :: Xlib.Display -> Atoms -> IO Window +getActiveWindow disp atoms = + liftM (fromIntegral . fromMaybe 0 . join . fmap listToMaybe) $ XExtras.getWindowProperty32 disp (atom_NET_ACTIVE_WINDOW atoms) $ Xlib.defaultRootWindow disp -getWindowStates :: X11 -> M.Map WINDOW WindowState -> IO ([WINDOW], M.Map WINDOW WindowState) -getWindowStates x11 windowStates = do - windows <- getWindowList x11 +getWindowStates :: Xlib.Display -> Atoms -> M.Map Window WindowState -> IO ([Window], M.Map Window WindowState) +getWindowStates disp atoms windowStates = do + windows <- getWindowList disp atoms let windowStates' = map (\w -> (w, M.lookup w windowStates)) windows @@ -549,15 +536,15 @@ getWindowStates x11 windowStates = do where getWindowState' (window, Just windowState) = return (window, windowState) getWindowState' (window, Nothing) = do - changeWindowAttributes (x11Connection x11) window $ toValueParam [(CWEventMask, toMask [EventMaskPropertyChange, EventMaskStructureNotify])] - windowState <- getWindowState x11 window + Xlib.selectInput disp window $ Xlib.propertyChangeMask .|. Xlib.structureNotifyMask + windowState <- getWindowState disp atoms window return (window, windowState) -getWindowState :: X11 -> WINDOW -> IO WindowState -getWindowState x11 window = do - (name, workspace, visible) <- getWindowInfo x11 window - icons <- getWindowIcons x11 window - geom <- getWindowGeometry x11 window +getWindowState :: Xlib.Display -> Atoms -> Window -> IO WindowState +getWindowState disp atoms window = do + (name, workspace, visible) <- getWindowInfo disp atoms window + icons <- getWindowIcons disp atoms window + geom <- getWindowGeometry disp window return $ WindowState { windowTitle = name , windowDesktop = workspace @@ -566,27 +553,25 @@ getWindowState x11 window = do , windowGeometry = geom } -getWindowInfo :: X11 -> WINDOW -> IO (String, Int, Bool) -getWindowInfo x11 window = do - let conn = x11Connection x11 - atoms = x11Atoms x11 - netwmname <- liftM (fmap (decode . map fromIntegral)) $ getProperty8 conn window (atom_NET_WM_NAME atoms) +getWindowInfo :: Xlib.Display -> Atoms -> Window -> IO (String, Int, Bool) +getWindowInfo disp atoms window = do + netwmname <- liftM (fmap (decode . map fromIntegral)) $ XExtras.getWindowProperty8 disp (atom_NET_WM_NAME atoms) window wmname <- case netwmname of Just name -> return name - Nothing -> liftM (map unsignedChr . fromMaybe []) $ getProperty8 conn window (atomWM_NAME atoms) + Nothing -> liftM (map unsignedChr . fromMaybe []) $ XExtras.getWindowProperty8 disp Xlib.wM_NAME window - workspace <- liftM (fromIntegral . fromMaybe 0xFFFFFFFF . join . fmap listToMaybe) $ getProperty32 conn window (atom_NET_WM_DESKTOP atoms) - visible <- showWindow conn atoms window + workspace <- liftM (fromIntegral . fromMaybe 0xFFFFFFFF . join . fmap listToMaybe) $ XExtras.getWindowProperty32 disp (atom_NET_WM_DESKTOP atoms) window + visible <- showWindow disp atoms window return (wmname, workspace, visible) where - unsignedChr = chr . fromIntegral + unsignedChr = chr . fromIntegral . (fromIntegral :: (CChar -> CUChar)) -getWindowIcons :: X11 -> WINDOW -> IO [Icon] -getWindowIcons x11 window = getProperty32 (x11Connection x11) window (atom_NET_WM_ICON . x11Atoms $ x11) >>= readIcons . fromMaybe [] +getWindowIcons :: Xlib.Display -> Atoms -> Window -> IO [Icon] +getWindowIcons disp atoms window = XExtras.getWindowProperty32 disp (atom_NET_WM_ICON atoms) window >>= readIcons . fromMaybe [] -readIcons :: [Word32] -> IO [Icon] +readIcons :: [CLong] -> IO [Icon] readIcons (width:height:iconData) = do if ((fromIntegral $ length iconData) < (width*height)) then return [] else do let (thisIcon, rest) = splitAt (fromIntegral (width*height)) iconData @@ -616,23 +601,22 @@ premultiply c = a .|. r .|. g .|. b b = pm bmask -getWindowGeometry :: X11 -> WINDOW -> IO Rectangle -getWindowGeometry x11 window = - getGeometry (x11Connection x11) (fromXid . toXid $ window) >>= getReply >>= - return . ((const $ Rectangle 0 0 0 0) ||| (\(MkGetGeometryReply _ _ x y width height _) -> Rectangle (fi x) (fi y) (fi width) (fi height))) - where - fi :: (Integral a, Num b) => a -> b - fi = fromIntegral +getWindowGeometry :: Xlib.Display -> Window -> IO Xlib.Rectangle +getWindowGeometry disp window = flip catch (\_ -> return $ Xlib.Rectangle 0 0 0 0) $ do + (_, _, _, width, height, _, _) <- Xlib.getGeometry disp window + (ret, x, y, _) <- Xlib.translateCoordinates disp window (Xlib.defaultRootWindow disp) 0 0 + + return $ if ret then Xlib.Rectangle x y width height else Xlib.Rectangle 0 0 0 0 + -showWindow :: ConnectionClass c => c -> Atoms -> WINDOW -> IO Bool -showWindow conn atoms window = do - states <- liftM (map (fromXid . toXid) . fromMaybe []) $ getProperty32 conn window (atom_NET_WM_STATE atoms) - transientFor <- liftM (map fromIntegral . fromMaybe []) $ getProperty32 conn window (atomWM_TRANSIENT_FOR atoms) - windowType <- liftM (fromMaybe (atom_NET_WM_WINDOW_TYPE_NORMAL atoms) . fmap (fromXid . toXid) . join . fmap listToMaybe) $ - getProperty32 conn window (atom_NET_WM_STATE atoms) +showWindow :: Xlib.Display -> Atoms -> Window -> IO Bool +showWindow disp atoms window = do + states <- liftM (map fromIntegral . fromMaybe []) $ XExtras.getWindowProperty32 disp (atom_NET_WM_STATE atoms) window + transientForHint <- XExtras.getTransientForHint disp window + windowType <- liftM (fromMaybe (atom_NET_WM_WINDOW_TYPE_NORMAL atoms) . fmap fromIntegral . join . fmap listToMaybe) $ XExtras.getWindowProperty32 disp (atom_NET_WM_STATE atoms) window return $ not $ or [ elem (atom_NET_WM_STATE_SKIP_TASKBAR atoms) states - , transientFor /= [] && transientFor /= [0] + , transientForHint /= Nothing , elem windowType $ map ($ atoms) [ atom_NET_WM_WINDOW_TYPE_DOCK , atom_NET_WM_WINDOW_TYPE_DESKTOP , atom_NET_WM_WINDOW_TYPE_TOOLBAR @@ -642,8 +626,8 @@ showWindow conn atoms window = do ] -getWindowList :: X11 -> IO [WINDOW] -getWindowList x11 = liftM (map (fromXid . toXid) . join . maybeToList) $ getProperty32 (x11Connection x11) (root_SCREEN . x11Screen $ x11) (atom_NET_CLIENT_LIST . x11Atoms $ x11) +getWindowList :: Xlib.Display -> Atoms -> IO [Window] +getWindowList disp atoms = liftM (map fromIntegral . join . maybeToList) $ XExtras.getWindowProperty32 disp (atom_NET_CLIENT_LIST atoms) $ Xlib.defaultRootWindow disp taskbar :: TaskbarConfig -> Taskbar taskbar = Taskbar diff --git a/lib/Phi/X11.hs b/lib/Phi/X11.hs index 7a673c3..cc53cea 100644 --- a/lib/Phi/X11.hs +++ b/lib/Phi/X11.hs @@ -1,17 +1,13 @@ -{-# LANGUAGE GeneralizedNewtypeDeriving, ExistentialQuantification, TypeFamilies, FlexibleContexts, DeriveDataTypeable #-} +{-# LANGUAGE GeneralizedNewtypeDeriving, ExistentialQuantification #-} -module Phi.X11 ( X11(..) - , XEvent(..) - , XMessage(..) - , XConfig(..) +module Phi.X11 ( XConfig(..) , defaultXConfig , runPhi ) where -import Graphics.XHB hiding (Window) -import Graphics.XHB.Connection.XCB +import Graphics.XHB import Graphics.XHB.Gen.Xinerama -import Graphics.XHB.Gen.Xproto hiding (Window) +import Graphics.XHB.Gen.Xproto import Graphics.Rendering.Cairo @@ -34,53 +30,39 @@ import System.Exit import System.Posix.Signals import System.Posix.Types -import Phi.Bindings.Cairo +import qualified Phi.Bindings.XCB as XCB import Phi.Phi import Phi.X11.Util import qualified Phi.Types as Phi import qualified Phi.Panel as Panel -import qualified Phi.Widget as Widget (handleMessage) -import Phi.Widget hiding (handleMessage) +import qualified Phi.Widget as Widget +import Phi.Widget hiding (Display, handleMessage) import Phi.X11.Atoms -data X11 = X11 { x11Connection :: !Connection - , x11Atoms :: !Atoms - , x11Screen :: !SCREEN - } - -instance Display X11 where - type Window X11 = WINDOW - - -newtype XEvent = XEvent SomeEvent deriving (Show, Typeable) - -data XMessage = UpdateScreens [(Rectangle, WINDOW)] deriving (Show, Typeable) - - -data XConfig = XConfig { phiXScreenInfo :: !(X11 -> IO [Rectangle]) +data XConfig = XConfig { phiXScreenInfo :: !(Connection -> IO [RECTANGLE]) } -data PhiState w s c = (Widget w s c X11) => PhiState { phiRootImage :: !Surface - , phiPanels :: ![PanelState w s c] - , phiRepaint :: !Bool - , phiShutdown :: !Bool - , phiShutdownHold :: !Int - , phiWidgetState :: !s - } +data PhiState w s c = (Widget.Widget w s c) => PhiState { phiRootImage :: !Surface + , phiPanels :: ![PanelState w s c] + , phiRepaint :: !Bool + , phiShutdown :: !Bool + , phiShutdownHold :: !Int + , phiWidgetState :: !s + } -data PanelState w s c = (Widget w s c X11) => PanelState { panelWindow :: !WINDOW - , panelPixmap :: !PIXMAP - , panelArea :: !Rectangle - , panelScreenArea :: !Rectangle - , panelWidgetCache :: !c - } +data PanelState w s c = (Widget.Widget w s c) => PanelState { panelWindow :: !WINDOW + , panelPixmap :: !PIXMAP + , panelArea :: !RECTANGLE + , panelScreenArea :: !RECTANGLE + , panelWidgetCache :: !c + } data PhiConfig w s c = PhiConfig { phiPhi :: !Phi , phiPanelConfig :: !Panel.PanelConfig , phiXConfig :: !XConfig - , phiX11 :: !X11 + , phiAtoms :: !Atoms , phiWidget :: !w } @@ -99,22 +81,17 @@ runPhiX config st (PhiX a) = runPhiReader config $ runStateT a st defaultXConfig = XConfig { phiXScreenInfo = getScreenInfo } -getScreenInfo :: X11 -> IO [Rectangle] -getScreenInfo x11 = do - let conn = x11Connection x11 - screen = x11Screen x11 +getScreenInfo :: Connection -> IO [RECTANGLE] +getScreenInfo conn = do exs <- queryScreens conn >>= getReply case exs of Right xs -> return . map screenInfoToRect $ screen_info_QueryScreensReply xs - Left _ -> getGeometry conn (fromXid . toXid $ root_SCREEN screen) >>= getReply' "getScreenInfo: getGeometry failed" >>= - return . (\(MkGetGeometryReply _ _ x y w h _) -> [Rectangle (fi x) (fi y) (fi w) (fi h)]) + Left _ -> getGeometry conn (fromXid . toXid $ getRoot conn) >>= getReply' "getScreenInfo: getGeometry failed" >>= + return . (\(MkGetGeometryReply _ _ x y w h _) -> [MkRECTANGLE x y w h]) where - screenInfoToRect (MkScreenInfo x y w h) = Rectangle (fi x) (fi y) (fi w) (fi h) - - fi :: (Integral a, Num b) => a -> b - fi = fromIntegral + screenInfoToRect (MkScreenInfo x y w h) = MkRECTANGLE x y w h -runPhi :: (Widget w s c X11) => XConfig -> Panel.PanelConfig -> w -> IO () +runPhi :: (Widget.Widget w s c) => XConfig -> Panel.PanelConfig -> w -> IO () runPhi xconfig config widget = do phi <- initPhi @@ -123,67 +100,57 @@ runPhi xconfig config widget = do installHandler sigQUIT (termHandler phi) Nothing conn <- liftM fromJust connect + xcb <- XCB.connect - let screen = (roots_Setup . connectionSetup $ conn) !! connectionScreen conn - atoms <- initAtoms conn - changeWindowAttributes conn (root_SCREEN screen) $ toValueParam [(CWEventMask, toMask [EventMaskPropertyChange, EventMaskStructureNotify])] + changeWindowAttributes conn (getRoot conn) $ toValueParam [(CWEventMask, toMask [EventMaskPropertyChange, EventMaskStructureNotify])] bg <- createImageSurface FormatRGB24 1 1 - let x11 = X11 conn atoms screen - - screens <- liftIO $ phiXScreenInfo xconfig x11 - panelWindows <- mapM (createPanelWindow conn screen config) screens - - let widget' = widget <~> separator 0 (if weight widget > 0 then 0 else 1) + screens <- liftIO $ phiXScreenInfo xconfig conn + panelWindows <- mapM (createPanelWindow conn config) screens + let dispvar = Widget.Display conn atoms + widget' = widget <~> separator 0 (if weight widget > 0 then 0 else 1) screenPanels = zip screens panelWindows - initialState <- initWidget widget' phi x11 screenPanels + initialState <- Widget.initWidget widget' phi dispvar screenPanels runPhiX PhiConfig { phiPhi = phi , phiXConfig = xconfig , phiPanelConfig = config - , phiX11 = x11 + , phiAtoms = atoms , phiWidget = widget' } PhiState { phiRootImage = bg , phiPanels = [] - , phiRepaint = False + , phiRepaint = True , phiShutdown = False , phiShutdownHold = 0 , phiWidgetState = initialState } $ do - updateRootImage + updateRootImage conn xcb - panels <- mapM (\(screen, window) -> createPanel window screen) screenPanels + panels <- mapM (\(screen, window) -> createPanel conn window screen) screenPanels - forM_ panels setPanelProperties + forM_ panels $ \panel -> do + setPanelProperties conn panel + liftIO $ mapWindow conn (panelWindow panel) modify $ \state -> state { phiPanels = panels } - updatePanels - - forM_ panels $ liftIO . mapWindow conn . panelWindow - - liftIO $ do - forkIO $ receiveEvents phi conn - forkIO $ receiveErrors phi conn + liftIO $ forkIO $ receiveEvents phi conn forever $ do available <- messageAvailable phi - repaint <- gets phiRepaint - when (not available && repaint) $ liftIO $ threadDelay 20000 - - available <- messageAvailable phi - when (not available && repaint) $ do - updatePanels - modify $ \state -> state {phiRepaint = False} + unless available $ do + repaint <- gets phiRepaint + when repaint $ do + updatePanels conn xcb + modify $ \state -> state {phiRepaint = False} message <- receiveMessage phi - handleMessage message - + handleMessage conn xcb message case (fromMessage message) of Just Shutdown -> @@ -208,8 +175,8 @@ termHandler :: Phi -> Handler termHandler phi = Catch $ sendMessage phi Shutdown -handleMessage :: (Widget w s c X11) => Message -> PhiX w s c () -handleMessage m = do +handleMessage :: (Widget w s c) => Connection -> XCB.Connection -> Message -> PhiX w s c () +handleMessage conn xcb m = do w <- asks phiWidget modify $ \state -> state {phiWidgetState = Widget.handleMessage w (phiWidgetState state) m} @@ -219,107 +186,80 @@ handleMessage m = do _ -> case (fromMessage m) of Just (XEvent event) -> - handleEvent event + handleEvent conn xcb event _ -> return () -handleEvent :: (Widget w s c X11) => SomeEvent -> PhiX w s c () -handleEvent event = +handleEvent :: (Widget w s c) => Connection -> XCB.Connection -> SomeEvent -> PhiX w s c () +handleEvent conn xcb event = do case (fromEvent event) of - Just e -> handlePropertyNotifyEvent e + Just e -> handlePropertyNotifyEvent conn xcb e Nothing -> case (fromEvent event) of - Just e -> handleConfigureNotifyEvent e + Just e -> handleConfigureNotifyEvent conn e Nothing -> return () -handlePropertyNotifyEvent :: (Widget w s c X11) => PropertyNotifyEvent -> PhiX w s c () -handlePropertyNotifyEvent MkPropertyNotifyEvent { atom_PropertyNotifyEvent = atom } = do +handlePropertyNotifyEvent :: (Widget w s c) => Connection -> XCB.Connection -> PropertyNotifyEvent -> PhiX w s c () +handlePropertyNotifyEvent conn xcb MkPropertyNotifyEvent { atom_PropertyNotifyEvent = atom } = do phi <- asks phiPhi - atoms <- asks (x11Atoms . phiX11) + atoms <- asks phiAtoms panels <- gets phiPanels when (atom == atom_XROOTPMAP_ID atoms || atom == atom_XROOTMAP_ID atoms) $ do - updateRootImage + updateRootImage conn xcb sendMessage phi ResetBackground sendMessage phi Repaint -handleConfigureNotifyEvent :: (Widget w s c X11) => ConfigureNotifyEvent -> PhiX w s c () -handleConfigureNotifyEvent MkConfigureNotifyEvent { window_ConfigureNotifyEvent = window } = do - x11 <- asks phiX11 - let conn = x11Connection x11 - screen = x11Screen x11 - rootWindow = root_SCREEN screen - when (window == rootWindow) $ do - phi <- asks phiPhi - xconfig <- asks phiXConfig - config <- asks phiPanelConfig - panels <- gets phiPanels - let screens = map panelScreenArea panels - screens' <- liftIO $ phiXScreenInfo xconfig x11 +handleConfigureNotifyEvent :: (Widget w s c) => Connection -> ConfigureNotifyEvent -> PhiX w s c () +handleConfigureNotifyEvent conn MkConfigureNotifyEvent { window_ConfigureNotifyEvent = window } | window == getRoot conn = do + phi <- asks phiPhi + xconfig <- asks phiXConfig + config <- asks phiPanelConfig + panels <- gets phiPanels + let screens = map panelScreenArea panels + screens' <- liftIO $ phiXScreenInfo xconfig conn + + when (screens /= screens') $ do + liftIO $ do + mapM_ (freePixmap conn . panelPixmap) panels + mapM_ (destroyWindow conn . panelWindow) $ drop (length screens') panels - when (screens /= screens') $ do - liftIO $ do - mapM_ (freePixmap conn . panelPixmap) panels - mapM_ (destroyWindow conn . panelWindow) $ drop (length screens') panels - - let panelsScreens = zip screens' $ map Just panels ++ repeat Nothing - - panels' <- forM panelsScreens $ \(screenarea, mpanel) -> - case mpanel of - Just panel -> do - let rect = panelBounds config screenarea - win = panelWindow panel - - liftIO $ configureWindow conn $ MkConfigureWindow win (toMask [ConfigWindowX, ConfigWindowY, ConfigWindowWidth, ConfigWindowHeight]) $ - toValueParam [ (ConfigWindowX, fromIntegral $ rect_x rect) - , (ConfigWindowY, fromIntegral $ rect_y rect) - , (ConfigWindowWidth, fromIntegral $ rect_width rect) - , (ConfigWindowHeight, fromIntegral $ rect_height rect) - ] - - panel' <- createPanel win screenarea - setPanelProperties panel' - - return panel' - Nothing -> do - win <- liftIO $ createPanelWindow conn screen config screenarea - panel <- createPanel win screenarea - setPanelProperties panel - liftIO $ mapWindow conn $ panelWindow panel - return panel - - modify $ \state -> state { phiPanels = panels' } - - sendMessage phi $ UpdateScreens $ map (panelScreenArea &&& panelWindow) panels' - sendMessage phi Repaint - - -maybeReceiveEvents' :: Connection -> IO [XEvent] -maybeReceiveEvents' conn = do - yield - mevent <- pollForEvent conn - case mevent of - Just event -> - liftM2 (:) (return . XEvent $ event) (maybeReceiveEvents' conn) - Nothing -> - return [] - - -receiveEvents' :: Connection -> IO [XEvent] -receiveEvents' conn = do - liftM2 (:) (liftM XEvent $ waitForEvent conn) (maybeReceiveEvents' conn) + let panelsScreens = zip screens' $ map Just panels ++ repeat Nothing + + panels' <- forM panelsScreens $ \(screen, mpanel) -> + case mpanel of + Just panel -> do + let rect = panelBounds config screen + win = panelWindow panel + + liftIO $ configureWindow conn win $ toValueParam [ (ConfigWindowX, fromIntegral $ x_RECTANGLE rect) + , (ConfigWindowY, fromIntegral $ y_RECTANGLE rect) + , (ConfigWindowWidth, fromIntegral $ width_RECTANGLE rect) + , (ConfigWindowHeight, fromIntegral $ height_RECTANGLE rect) + ] + + panel' <- createPanel conn win screen + setPanelProperties conn panel' + + return panel' + Nothing -> do + win <- liftIO $ createPanelWindow conn config screen + panel <- createPanel conn win screen + setPanelProperties conn panel + liftIO $ mapWindow conn $ panelWindow panel + return panel + + modify $ \state -> state { phiPanels = panels' } + + sendMessage phi $ UpdateScreens $ map (panelScreenArea &&& panelWindow) panels' + sendMessage phi Repaint receiveEvents :: Phi -> Connection -> IO () -receiveEvents phi conn = - forever $ receiveEvents' conn >>= sendMessages phi +receiveEvents phi conn = do + forever $ waitForEvent conn >>= sendMessage phi . XEvent -receiveErrors :: Phi -> Connection -> IO () -receiveErrors phi conn = - forever $ waitForError conn >>= putStrLn . ("XHB error: " ++) . show - -updatePanels :: (Widget w s c X11) => PhiX w s c () -updatePanels = do - X11 conn _ screen <- asks phiX11 +updatePanels :: (Widget w s c) => Connection -> XCB.Connection -> PhiX w s c () +updatePanels conn xcb = do w <- asks phiWidget s <- gets phiWidgetState rootImage <- gets phiRootImage @@ -330,16 +270,17 @@ updatePanels = do area = panelArea panel (panelSurfaces, cache') <- liftIO $ flip runStateT (panelWidgetCache panel) $ - (withDimension area $ render w s 0 0) (panelScreenArea panel) + (withDimension area $ Widget.render w s 0 0) (panelScreenArea panel) - let visualtype = fromJust $ findVisualtype screen (root_visual_SCREEN screen) + let screen = head . roots_Setup . connectionSetup $ conn + visualtype = fromJust $ findVisualtype screen (root_visual_SCREEN screen) - xbuffer <- liftIO $ withDimension area $ createXCBSurface conn (fromXid . toXid $ pixmap) visualtype + xbuffer <- liftIO $ withDimension area $ XCB.createXCBSurface xcb (fromXid . toXid $ pixmap) visualtype liftIO $ (withDimension area $ withSimilarSurface xbuffer ContentColor) $ \buffer -> do renderWith buffer $ do save - translate (-(fromIntegral $ rect_x area)) (-(fromIntegral $ rect_y area)) + translate (-(fromIntegral $ x_RECTANGLE area)) (-(fromIntegral $ y_RECTANGLE area)) withPatternForSurface rootImage $ \pattern -> do patternSetExtend pattern ExtendRepeat setSource pattern @@ -360,20 +301,19 @@ updatePanels = do surfaceFinish xbuffer -- update window - liftIO $ do - clearArea conn $ withDimension area $ MkClearArea True (panelWindow panel) 0 0 - flush conn + liftIO $ withDimension area $ XCB.clearArea xcb True (panelWindow panel) 0 0 return $ panel { panelWidgetCache = cache' } modify $ \state -> state { phiPanels = panels' } -updateRootImage :: PhiX w s c () -updateRootImage = do - X11 conn atoms screen <- asks phiX11 +updateRootImage :: Connection -> XCB.Connection -> PhiX w s c () +updateRootImage conn xcb = do + atoms <- asks phiAtoms - let visualtype = fromJust $ findVisualtype screen (root_visual_SCREEN screen) + let screen = head . roots_Setup . connectionSetup $ conn + visualtype = fromJust $ findVisualtype screen (root_visual_SCREEN screen) rootwin = root_SCREEN screen pixmap <- liftM (fromXid . toXid . fromMaybe 0 . listToMaybe . join . catMaybes) $ forM [atom_XROOTPMAP_ID atoms, atom_XROOTMAP_ID atoms] $ @@ -400,7 +340,7 @@ updateRootImage = do setSourceRGB 0 0 0 paint _ -> do - rootSurface <- liftIO $ createXCBSurface conn (fromXid . toXid $ pixmap) visualtype (fromIntegral pixmapWidth) (fromIntegral pixmapHeight) + rootSurface <- liftIO $ XCB.createXCBSurface xcb (fromXid . toXid $ pixmap) visualtype (fromIntegral pixmapWidth) (fromIntegral pixmapHeight) renderWith bg $ withPatternForSurface rootSurface $ \pattern -> do setSource pattern @@ -410,12 +350,12 @@ updateRootImage = do return () -createPanel :: (Widget w s c X11) => WINDOW -> Rectangle -> PhiX w s c (PanelState w s c) -createPanel win screenRect = do - (conn, screen) <- asks $ (x11Connection &&& x11Screen) . phiX11 +createPanel :: (Widget w s c) => Connection -> WINDOW -> RECTANGLE -> PhiX w s c (PanelState w s c) +createPanel conn win screenRect = do config <- asks phiPanelConfig w <- asks phiWidget let rect = panelBounds config screenRect + screen = head . roots_Setup . connectionSetup $ conn depth = root_depth_SCREEN screen pixmap <- liftIO $ newResource conn @@ -429,9 +369,10 @@ createPanel win screenRect = do , panelWidgetCache = initCache w } -createPanelWindow :: Connection -> SCREEN -> Panel.PanelConfig -> Rectangle -> IO WINDOW -createPanelWindow conn screen config screenRect = do +createPanelWindow :: Connection -> Panel.PanelConfig -> RECTANGLE -> IO WINDOW +createPanelWindow conn config screenRect = do let rect = panelBounds config screenRect + screen = head . roots_Setup . connectionSetup $ conn depth = root_depth_SCREEN screen rootwin = root_SCREEN screen visual = root_visual_SCREEN screen @@ -441,9 +382,9 @@ createPanelWindow conn screen config screenRect = do return win -setPanelProperties :: PanelState w s c -> PhiX w s c () -setPanelProperties panel = do - (conn, atoms) <- asks $ (x11Connection &&& x11Atoms) . phiX11 +setPanelProperties :: Connection -> PanelState w s c -> PhiX w s c () +setPanelProperties conn panel = do + atoms <- asks phiAtoms liftIO $ do let name = map (fromIntegral . ord) "Phi" changeProperty8 conn PropModeReplace (panelWindow panel) (atomWM_NAME atoms) (atomSTRING atoms) name @@ -462,28 +403,28 @@ setPanelProperties panel = do changeProperty8 conn PropModeReplace (panelWindow panel) (atomWM_CLASS atoms) (atomSTRING atoms) $ map (fromIntegral . ord) "phi\0Phi" - setStruts panel + setStruts conn panel -setStruts :: PanelState w s c -> PhiX w s c () -setStruts panel = do - X11 conn atoms screen <- asks phiX11 +setStruts :: Connection -> PanelState w s c -> PhiX w s c () +setStruts conn panel = do + atoms <- asks phiAtoms config <- asks phiPanelConfig - let rootwin = root_SCREEN screen + let rootwin = getRoot conn position = Panel.panelPosition config area = panelArea panel rootHeight <- liftIO $ getGeometry conn (fromXid . toXid $ rootwin) >>= getReply' "setStruts: getGeometry failed" >>= return . height_GetGeometryReply let struts = [makeStruts i | i <- [0..11]] where - makeTopStruts 2 = (fromIntegral $ rect_y area) + (fromIntegral $ rect_height area) - makeTopStruts 8 = (fromIntegral $ rect_x area) - makeTopStruts 9 = (fromIntegral $ rect_x area) + (fromIntegral $ rect_width area) - 1 + makeTopStruts 2 = (fromIntegral $ y_RECTANGLE area) + (fromIntegral $ height_RECTANGLE area) + makeTopStruts 8 = (fromIntegral $ x_RECTANGLE area) + makeTopStruts 9 = (fromIntegral $ x_RECTANGLE area) + (fromIntegral $ width_RECTANGLE area) - 1 makeTopStruts _ = 0 - makeBottomStruts 3 = (fromIntegral rootHeight) - (fromIntegral $ rect_y area) - makeBottomStruts 10 = (fromIntegral $ rect_x area) - makeBottomStruts 11 = (fromIntegral $ rect_x area) + (fromIntegral $ rect_width area) - 1 + makeBottomStruts 3 = (fromIntegral rootHeight) - (fromIntegral $ y_RECTANGLE area) + makeBottomStruts 10 = (fromIntegral $ x_RECTANGLE area) + makeBottomStruts 11 = (fromIntegral $ x_RECTANGLE area) + (fromIntegral $ width_RECTANGLE area) - 1 makeBottomStruts _ = 0 makeStruts = case position of @@ -495,17 +436,17 @@ setStruts panel = do changeProperty32 conn PropModeReplace (panelWindow panel) (atom_NET_WM_STRUT_PARTIAL atoms) (atomCARDINAL atoms) struts -panelBounds :: Panel.PanelConfig -> Rectangle -> Rectangle +panelBounds :: Panel.PanelConfig -> RECTANGLE -> RECTANGLE panelBounds config screenBounds = case Panel.panelPosition config of - Phi.Top -> screenBounds { rect_height = Panel.panelSize config } - Phi.Bottom -> screenBounds { rect_height = Panel.panelSize config, - rect_y = rect_y screenBounds + rect_height screenBounds - Panel.panelSize config } + Phi.Top -> screenBounds { height_RECTANGLE = fromIntegral $ Panel.panelSize config } + Phi.Bottom -> screenBounds { height_RECTANGLE = fromIntegral $ Panel.panelSize config, + y_RECTANGLE = (y_RECTANGLE screenBounds) + (fromIntegral $ height_RECTANGLE screenBounds) - (fromIntegral $ Panel.panelSize config) } -withRectangle :: (Num x, Num y, Num w, Num h) => Rectangle -> (x -> y -> w -> h -> a) -> a +withRectangle :: (Num x, Num y, Num w, Num h) => RECTANGLE -> (x -> y -> w -> h -> a) -> a withRectangle r = withDimension r . withPosition r -withPosition :: (Num x, Num y) => Rectangle -> (x -> y -> a) -> a -withPosition r f = f (fromIntegral $ rect_x r) (fromIntegral $ rect_y r) +withPosition :: (Num x, Num y) => RECTANGLE -> (x -> y -> a) -> a +withPosition r f = f (fromIntegral $ x_RECTANGLE r) (fromIntegral $ y_RECTANGLE r) -withDimension :: (Num w, Num h) => Rectangle -> (w -> h -> a) -> a -withDimension r f = f (fromIntegral $ rect_width r) (fromIntegral $ rect_height r) +withDimension :: (Num w, Num h) => RECTANGLE -> (w -> h -> a) -> a +withDimension r f = f (fromIntegral $ width_RECTANGLE r) (fromIntegral $ height_RECTANGLE r) diff --git a/lib/Phi/X11/AtomList.hs b/lib/Phi/X11/AtomList.hs index bc91efa..d05bad2 100644 --- a/lib/Phi/X11/AtomList.hs +++ b/lib/Phi/X11/AtomList.hs @@ -7,16 +7,15 @@ module Phi.X11.AtomList ( atoms import Language.Haskell.TH import Graphics.XHB +import Graphics.XHB.Connection.Open atoms :: [String] atoms = [ "ATOM" , "CARDINAL" , "STRING" - , "VISUALID" , "UTF8_STRING" , "WM_NAME" , "WM_CLASS" - , "WM_TRANSIENT_FOR" , "MANAGER" , "_NET_WM_NAME" , "_NET_WM_WINDOW_TYPE" @@ -48,10 +47,9 @@ atoms = [ "ATOM" , "_XEMBED" , "_XROOTPMAP_ID" , "_XROOTMAP_ID" - , "PHI_SYSTRAY_HELPER" ] --- the expression must have the type (ConnectionClass c => c -> String) +-- the expression must have the type (Connection -> String) specialAtoms :: [(String, Q Exp)] -specialAtoms = [ ("_NET_SYSTEM_TRAY_SCREEN", [|("_NET_SYSTEM_TRAY_S" ++) . show . connectionScreen|]) - ] +specialAtoms = [ ("_NET_SYSTEM_TRAY_SCREEN", [|("_NET_SYSTEM_TRAY_S" ++) . show . screen . displayInfo|]) + ] \ No newline at end of file diff --git a/lib/Phi/X11/Atoms.hs b/lib/Phi/X11/Atoms.hs index 6e69b37..0a8f66a 100644 --- a/lib/Phi/X11/Atoms.hs +++ b/lib/Phi/X11/Atoms.hs @@ -21,7 +21,7 @@ $(let atomsName = mkName "Atoms" in return [DataD [] atomsName [] [RecC atomsName fields] []] ) -initAtoms :: ConnectionClass c => c -> IO Atoms +initAtoms :: Connection -> IO Atoms initAtoms conn = $(do normalAtomNames <- mapM (\atom -> do diff --git a/lib/Phi/X11/Util.hs b/lib/Phi/X11/Util.hs index 07eb1cf..cadceeb 100644 --- a/lib/Phi/X11/Util.hs +++ b/lib/Phi/X11/Util.hs @@ -6,10 +6,8 @@ module Phi.X11.Util ( getReply' , getProperty16 , getProperty32 , findVisualtype - , serializeClientMessage ) where -import Control.Exception (assert) import Control.Monad import Data.Int @@ -17,11 +15,8 @@ import Data.List import Data.Maybe import Data.Word -import Foreign.C.Types import Foreign.Marshal.Array -import Foreign.Marshal.Utils import Foreign.Ptr -import Foreign.Storable import Graphics.XHB import Graphics.XHB.Gen.Xproto @@ -55,22 +50,18 @@ castWord8to32 input = unsafePerformIO $ withArray input $ \ptr -> peekArray (length input `div` 4) (castPtr ptr) -castToCChar :: Storable s => s -> [CChar] -castToCChar input = unsafePerformIO $ - with input $ \ptr -> - peekArray (sizeOf input) (castPtr ptr) -changeProperty8 :: ConnectionClass c => c -> PropMode -> WINDOW -> ATOM -> ATOM -> [Word8] -> IO () +changeProperty8 :: Connection -> PropMode -> WINDOW -> ATOM -> ATOM -> [Word8] -> IO () changeProperty8 conn mode win prop proptype propdata = changeProperty conn $ MkChangeProperty mode win prop proptype 8 (genericLength propdata) propdata -changeProperty16 :: ConnectionClass c => c -> PropMode -> WINDOW -> ATOM -> ATOM -> [Word16] -> IO () +changeProperty16 :: Connection -> PropMode -> WINDOW -> ATOM -> ATOM -> [Word16] -> IO () changeProperty16 conn mode win prop proptype propdata = changeProperty conn $ MkChangeProperty mode win prop proptype 16 (genericLength propdata) (castWord16to8 propdata) -changeProperty32 :: ConnectionClass c => c -> PropMode -> WINDOW -> ATOM -> ATOM -> [Word32] -> IO () +changeProperty32 :: Connection -> PropMode -> WINDOW -> ATOM -> ATOM -> [Word32] -> IO () changeProperty32 conn mode win prop proptype propdata = changeProperty conn $ MkChangeProperty mode win prop proptype 32 (genericLength propdata) (castWord32to8 propdata) -getProperty' :: ConnectionClass c => Word8 -> c -> WINDOW -> ATOM -> IO (Maybe [Word8]) +getProperty' :: Word8 -> Connection -> WINDOW -> ATOM -> IO (Maybe [Word8]) getProperty' format conn win prop = do reply <- getProperty conn (MkGetProperty False win prop (fromXid xidNone) 0 4) >>= getReply case reply of @@ -84,43 +75,15 @@ getProperty' format conn win prop = do Right (MkGetPropertyReply {format_GetPropertyReply = format'}) | format' /= format -> return Nothing Right (MkGetPropertyReply {value_GetPropertyReply = value}) -> return $ Just value -getProperty8 :: ConnectionClass c => c -> WINDOW -> ATOM -> IO (Maybe [Word8]) +getProperty8 :: Connection -> WINDOW -> ATOM -> IO (Maybe [Word8]) getProperty8 = getProperty' 8 -getProperty16 :: ConnectionClass c => c -> WINDOW -> ATOM -> IO (Maybe [Word16]) +getProperty16 :: Connection -> WINDOW -> ATOM -> IO (Maybe [Word16]) getProperty16 conn win prop = getProperty' 16 conn win prop >>= return . fmap castWord8to16 -getProperty32 :: ConnectionClass c => c -> WINDOW -> ATOM -> IO (Maybe [Word32]) +getProperty32 :: Connection -> WINDOW -> ATOM -> IO (Maybe [Word32]) getProperty32 conn win prop = getProperty' 32 conn win prop >>= return . fmap castWord8to32 findVisualtype :: SCREEN -> VISUALID -> Maybe VISUALTYPE -findVisualtype screen id = listToMaybe . filter ((== id) . visual_id_VISUALTYPE) . join . map visuals_DEPTH . allowed_depths_SCREEN $ screen - - -instance Storable ClientMessageData where - sizeOf _ = 20 - alignment _ = 1 - peek _ = error "ClientMessageData: peek not implemented" - poke ptr (ClientData8 d) = assert (length d == 20) $ pokeArray (castPtr ptr) d - poke ptr (ClientData16 d) = assert (length d == 10) $ pokeArray (castPtr ptr) d - poke ptr (ClientData32 d) = assert (length d == 5) $ pokeArray (castPtr ptr) d - -instance Storable ClientMessageEvent where - sizeOf _ = 32 - alignment _ = 1 - peek _ = error "ClientMessageEvent: peek not implemented" - poke ptr ev = do - poke' 0 (33 :: Word8) -- ClientMessage == 33 -- response_type - poke' 1 (format_ClientMessageEvent ev) -- format - poke' 2 (0 :: Word16) -- sequence - poke' 4 (fromXid . toXid . window_ClientMessageEvent $ ev :: Word32) -- window - poke' 8 (fromXid . toXid . type_ClientMessageEvent $ ev :: Word32) -- type - poke' 12 (data_ClientMessageEvent ev) -- data - where - poke' :: Storable s => Int -> s -> IO () - poke' = poke . plusPtr ptr - - -serializeClientMessage :: ClientMessageEvent -> [CChar] -serializeClientMessage = castToCChar +findVisualtype screen id = listToMaybe . filter ((== id) . visual_id_VISUALTYPE) . join . map visuals_DEPTH . allowed_depths_SCREEN $ screen \ No newline at end of file diff --git a/phi.cabal b/phi.cabal index 2938ee6..75d633f 100644 --- a/phi.cabal +++ b/phi.cabal @@ -10,28 +10,20 @@ author: Matthias Schiffer maintainer: mschiffer@universe-factory.net build-type: Simple - library - build-depends: base >= 4, template-haskell, stm, array, containers, transformers, mtl, utf8-string, time, old-locale, xhb >= 0.5, xhb-xcb, + build-depends: base >= 4, template-haskell, stm, array, containers, transformers, mtl, utf8-string, time, old-locale, xhb, cairo, pango, unix, data-accessor, arrows, CacheArrow exposed-modules: Phi.Types, Phi.Phi, Phi.Panel, Phi.Widget, Phi.Border, Phi.X11 - Phi.Widgets.AlphaBox, Phi.Widgets.Clock, Phi.Widgets.X11.Taskbar - -- , Phi.Widgets.Systray - other-modules: Phi.X11.AtomList, Phi.Bindings.Cairo, Phi.X11.Atoms, Phi.X11.Util + Phi.Widgets.AlphaBox, Phi.Widgets.Clock + -- , Phi.Widgets.Taskbar, Phi.Widgets.Systray + other-modules: Phi.X11.Util, Phi.X11.Atoms, Phi.X11.AtomList, Phi.Bindings.XCB include-dirs: include hs-source-dirs: lib - pkgconfig-depends: cairo >= 1.2.0, cairo-xcb + extra-libraries: X11 + pkgconfig-depends: xcb, cairo >= 1.2.0, cairo-xcb ghc-options: -fspec-constr-count=16 -threaded -executable phi-systray-helper - build-depends: base >= 4, template-haskell, mtl, xhb >= 0.5, xhb-xcb - hs-source-dirs: src, lib - main-is: SystrayHelper.hs - other-modules: Phi.X11.AtomList, Phi.X11.Atoms, Phi.X11.Util - ghc-options: -threaded - -executable phi +executable Phi build-depends: base >= 4, phi hs-source-dirs: src main-is: Phi.hs - ghc-options: -threaded diff --git a/src/Phi.hs b/src/Phi.hs index 3f476f8..6ffff61 100644 --- a/src/Phi.hs +++ b/src/Phi.hs @@ -6,13 +6,13 @@ import Phi.X11 import Phi.Widgets.AlphaBox import Phi.Widgets.Clock -import Phi.Widgets.X11.Taskbar ---import Phi.Widgets.X11.Systray +--import Phi.Widgets.Taskbar +--import Phi.Widgets.Systray main :: IO () main = do - runPhi defaultXConfig defaultPanelConfig { panelPosition = Bottom } $ alphaBox 0.9 $ theTaskbar <~> {-brightBorder theSystray <~> -} brightBorder theClock + runPhi defaultXConfig defaultPanelConfig { panelPosition = Bottom } $ alphaBox 0.9 $ {- theTaskbar <~> brightBorder theSystray <~> -} brightBorder theClock where normalTaskBorder = BorderConfig (BorderWidth (-1) (-3) (-1) 7) 1 (BorderWidth 0 5 0 5) (0.9, 0.9, 0.9, 0.8) (0.45, 0.45, 0.45, 0.8) 5 0 activeTaskBorder = normalTaskBorder { borderColor = (1, 1, 1, 0.8) @@ -25,7 +25,7 @@ main = do } currentDesktopBorder = normalDesktopBorder { backgroundColor = (0.2, 0.2, 0.2, 0.9) } - taskStyle = TaskStyle { taskFont = "Sans 7" + {-taskStyle = TaskStyle { taskFont = "Sans 7" , taskColor = (1, 1, 1, 1) , taskBorder = normalTaskBorder , taskIconStyle = idIconStyle @@ -46,11 +46,11 @@ main = do , desktopStyle = Just (normalDesktopStyle, currentDesktopStyle) } - --theSystray = systray + theSystray = systray-} - theClock = clock defaultClockConfig { clockFormat = "%R\n%a, %b %d" - , lineSpacing = (-1) - , clockSize = 55 + theClock = clock defaultClockConfig { clockFormat = "%R\n%A %d %B" + , lineSpacing = (-3) + , clockSize = 75 } - brightBorder :: (Widget w s c d) => w -> Border w s c d + brightBorder :: (Widget w s c) => w -> Border w s c brightBorder = border normalDesktopBorder diff --git a/src/SystrayHelper.hs b/src/SystrayHelper.hs deleted file mode 100644 index f39176f..0000000 --- a/src/SystrayHelper.hs +++ /dev/null @@ -1,106 +0,0 @@ -import Control.Concurrent -import Control.Monad -import Control.Monad.State.Strict - -import Data.Word -import Data.Maybe - -import Graphics.XHB -import Graphics.XHB.Connection.XCB -import Graphics.XHB.Gen.Xproto - -import System.Exit - -import Phi.X11.Atoms -import Phi.X11.Util - - -sYSTEM_TRAY_REQUEST_DOCK :: Word32 -sYSTEM_TRAY_REQUEST_DOCK = 0 - -sYSTEM_TRAY_BEGIN_MESSAGE :: Word32 -sYSTEM_TRAY_BEGIN_MESSAGE = 1 - -sYSTEM_TRAY_CANCEL_MESSAGE :: Word32 -sYSTEM_TRAY_CANCEL_MESSAGE = 2 - -xEMBED_EMBEDDED_NOTIFY :: Word32 -xEMBED_EMBEDDED_NOTIFY = 0 - - -data SystrayState = SystrayState - { systrayIcons :: [(WINDOW, WINDOW)] - } - - -main :: IO () -main = do - conn <- liftM fromJust connect - forkIO $ receiveErrors conn - - atoms <- initAtoms conn - - let screen = (roots_Setup . connectionSetup $ conn) !! connectionScreen conn - - (xembedWin, systrayWin) <- initSystray conn atoms screen - - execStateT (runSystray xembedWin systrayWin) $ SystrayState [] - - return () - -receiveErrors :: Connection -> IO () -receiveErrors conn = - forever $ waitForError conn >>= putStrLn . ("XHB error: " ++) . show - -initSystray :: Connection -> Atoms -> SCREEN -> IO (WINDOW, WINDOW) -initSystray conn atoms screen = do - currentSystrayWin <- getSelectionOwner conn (atom_NET_SYSTEM_TRAY_SCREEN atoms) >>= getReply' "initSystray: getSelectionOwner failed" - when (currentSystrayWin /= fromXid xidNone) $ do - putStrLn "phi-systray-helper: another systray is running." - exitFailure - - currentSystrayHelperWin <- getSelectionOwner conn (atomPHI_SYSTRAY_HELPER atoms) >>= getReply' "initSystray: getSelectionOwner failed" - when (currentSystrayHelperWin /= fromXid xidNone) $ do - putStrLn "phi-systray-helper: another systray helper is running." - exitFailure - - let rootwin = root_SCREEN screen - depth = root_depth_SCREEN screen - visual = root_visual_SCREEN screen - xembedWin <- newResource conn - createWindow conn $ MkCreateWindow depth xembedWin rootwin (-1) (-1) 1 1 0 WindowClassInputOutput visual emptyValueParam - - -- orient horizontally - changeProperty32 conn PropModeReplace xembedWin (atom_NET_SYSTEM_TRAY_ORIENTATION atoms) (atomCARDINAL atoms) [0] - - -- set visual - changeProperty32 conn PropModeReplace xembedWin (atom_NET_SYSTEM_TRAY_VISUAL atoms) (atomVISUALID atoms) [fromIntegral visual] - - setSelectionOwner conn $ MkSetSelectionOwner xembedWin (atom_NET_SYSTEM_TRAY_SCREEN atoms) 0 - systrayWin <- getSelectionOwner conn (atom_NET_SYSTEM_TRAY_SCREEN atoms) >>= getReply' "initSystray: getSelectionOwner failed" - when (systrayWin /= xembedWin) $ do - destroyWindow conn xembedWin - putStrLn $ "phi-systray-helper: can't initialize systray." - exitFailure - - systrayWin <- newResource conn - createWindow conn $ MkCreateWindow depth systrayWin rootwin (-1) (-1) 1 1 0 WindowClassInputOutput visual emptyValueParam - - setSelectionOwner conn $ MkSetSelectionOwner systrayWin (atomPHI_SYSTRAY_HELPER atoms) 0 - systrayHelperWin <- getSelectionOwner conn (atomPHI_SYSTRAY_HELPER atoms) >>= getReply' "initSystray: getSelectionOwner failed" - when (systrayHelperWin /= systrayWin) $ do - destroyWindow conn systrayHelperWin - destroyWindow conn xembedWin - putStrLn $ "phi-systray-helper: can't initialize systray helper." - exitFailure - - sendEvent conn $ MkSendEvent False rootwin [EventMaskStructureNotify] $ - serializeClientMessage $ MkClientMessageEvent 32 rootwin (atomMANAGER atoms) $ - ClientData32 [0, fromXid . toXid $ atom_NET_SYSTEM_TRAY_SCREEN atoms, fromXid . toXid $ xembedWin, 0, 0] - - return (xembedWin, systrayWin) - - -runSystray :: WINDOW -> WINDOW -> StateT SystrayState IO () -runSystray xembedWin systrayWin = do - return ()