Converted core to XHB/XCB

This commit is contained in:
Matthias Schiffer 2011-09-07 16:38:36 +02:00
parent 42d5f27d32
commit 15d9304e05
11 changed files with 433 additions and 368 deletions

View file

@ -1,27 +0,0 @@
#include <SystrayErrorHandler.h>
static Window lastErrorWindow = 0;
static int systrayErrorHandler (Display *display, XErrorEvent *event)
{
if (event->error_code == BadWindow) {
lastErrorWindow = event->resourceid;
}
return 0;
}
void setSystrayErrorHandler (void)
{
lastErrorWindow = 0;
XSetErrorHandler(systrayErrorHandler);
}
Window getLastErrorWindow (void)
{
Window ret = lastErrorWindow;
lastErrorWindow = 0;
return ret;
}

View file

@ -1,17 +0,0 @@
{-# LANGUAGE ForeignFunctionInterface #-}
module Phi.Bindings.SystrayErrorHandler ( setSystrayErrorHandler
, getLastErrorWindow
) where
#include <SystrayErrorHandler.h>
import Graphics.X11.Xlib
foreign import ccall unsafe "SystrayErrorHandler.h setSystrayErrorHandler"
setSystrayErrorHandler :: IO ()
foreign import ccall unsafe "SystrayErrorHandler.h getLastErrorWindow"
getLastErrorWindow :: IO Window

View file

@ -1,90 +0,0 @@
{-# LANGUAGE ForeignFunctionInterface #-}
module Phi.Bindings.Util ( setClassHint
, visualIDFromVisual
, putClientMessage
, Phi.Bindings.Util.getEvent
, createXlibSurface
) where
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <cairo.h>
#include <cairo-xlib.h>
import Foreign.C.String (withCString)
import Foreign.C.Types
import Foreign.Ptr
import Foreign.Marshal.Alloc (alloca, allocaBytes)
import Foreign.Marshal.Array
import Foreign.Storable
import Graphics.X11.Xlib
import Graphics.X11.Xlib.Extras
import Graphics.Rendering.Cairo.Types
foreign import ccall unsafe "X11/Xutil.h XSetClassHint"
xSetClassHint :: Display -> Window -> Ptr ClassHint -> IO ()
setClassHint :: Display -> Window -> ClassHint -> IO ()
setClassHint disp wnd hint = allocaBytes (#size XClassHint) $ \p ->
withCString (resName hint) $ \res_name ->
withCString (resClass hint) $ \res_class -> do
(#poke XClassHint, res_name) p res_name
(#poke XClassHint, res_class) p res_class
xSetClassHint disp wnd p
foreign import ccall unsafe "X11/Xlib.h XVisualIDFromVisual"
visualIDFromVisual :: Visual -> VisualID
putClientMessage :: XEventPtr -> Window -> Atom -> [CLong] -> IO ()
putClientMessage event window message_type messageData = do
setEventType event clientMessage
(#poke XClientMessageEvent, window) event window
(#poke XClientMessageEvent, message_type) event message_type
(#poke XClientMessageEvent, format) event (32 :: CInt)
pokeArray ((#ptr XClientMessageEvent, data.l) event) $ take 5 messageData
foreign import ccall unsafe "cairo-xlib.h cairo_xlib_surface_create"
xlibSurfaceCreate :: Display -> Drawable -> Visual -> CInt -> CInt -> IO (Ptr Surface)
getEvent :: Display -> XEventPtr -> IO Event
getEvent display p = do
eventType <- get_EventType p
case True of
_ | eventType == clientMessage -> do
serial <- (#peek XClientMessageEvent, serial) p
send_event <- (#peek XClientMessageEvent, send_event) p
window <- (#peek XClientMessageEvent, window) p
message_type <- (#peek XClientMessageEvent, message_type) p
format <- (#peek XClientMessageEvent, format) p
let datPtr = (#ptr XClientMessageEvent, data) p
dat <- case (format::CInt) of
8 -> do a <- peekArray 20 datPtr
return $ map fromIntegral (a::[CUChar])
16 -> do a <- peekArray 10 datPtr
return $ map fromIntegral (a::[CUShort])
32 -> do a <- peekArray 5 datPtr
return $ map fromIntegral (a::[CULong])
return $ ClientMessageEvent { ev_event_type = eventType
, ev_serial = serial
, ev_send_event = send_event
, ev_event_display = display
, ev_window = window
, ev_message_type = message_type
, ev_data = dat
}
| otherwise -> Graphics.X11.Xlib.Extras.getEvent p
createXlibSurface :: Display -> Drawable -> Visual -> CInt -> CInt -> IO Surface
createXlibSurface dpy drawable visual width height = do
surfacePtr <- xlibSurfaceCreate dpy drawable visual width height
surface <- mkSurface surfacePtr
manageSurface surface
return surface

92
lib/Phi/Bindings/XCB.hsc Normal file
View file

@ -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 <xcb/xcb.h>
#include <xcb/xproto.h>
#include <cairo-xcb.h>
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

View file

@ -1,6 +1,7 @@
{-# LANGUAGE ExistentialQuantification, StandaloneDeriving, DeriveDataTypeable, MultiParamTypeClasses, FunctionalDependencies, TypeSynonymInstances, FlexibleInstances #-}
module Phi.Widget ( Display(..)
module Phi.Widget ( XEvent(..)
, Display(..)
, withDisplay
, getAtoms
, XMessage(..)
@ -30,36 +31,38 @@ import Control.Monad.IO.Class
import Data.Maybe
import Data.Typeable
import qualified Graphics.X11.Xlib as Xlib
import Graphics.XHB
import Graphics.Rendering.Cairo
import Phi.Phi
import Phi.X11.Atoms
data Display = Display !(MVar Xlib.Display) !Atoms
data Display = Display !Connection !Atoms
withDisplay :: MonadIO m => Display -> (Xlib.Display -> m a) -> m a
withDisplay (Display dispvar _) f = do
disp <- liftIO $ takeMVar dispvar
a <- f disp
liftIO $ putMVar dispvar disp
return a
newtype XEvent = XEvent SomeEvent deriving Typeable
instance Show XEvent where
show _ = "XEvent (..)"
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 [(Xlib.Rectangle, Xlib.Window)] deriving (Show, Typeable)
data XMessage = UpdateScreens [(RECTANGLE, WINDOW)] deriving (Show, Typeable)
unionArea :: Xlib.Rectangle -> Xlib.Rectangle -> Int
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)
Xlib.Rectangle ax1 ay1 aw ah = a
Xlib.Rectangle bx1 by1 bw bh = b
MkRECTANGLE ax1 ay1 aw ah = a
MkRECTANGLE bx1 by1 bw bh = b
ax2 = ax1 + fromIntegral aw
ay2 = ay1 + fromIntegral ah
@ -71,22 +74,24 @@ unionArea a b = fromIntegral $ uw*uh
data SurfaceSlice = SurfaceSlice !Int !Surface
class Eq s => Widget w s c | w -> s, w -> c where
initWidget :: w -> Phi -> Display -> [(Xlib.Rectangle, Xlib.Window)] -> IO s
initWidget :: w -> Phi -> Display -> [(RECTANGLE, WINDOW)] -> IO s
initCache :: w -> c
minSize :: w -> s -> Int -> Xlib.Rectangle -> Int
minSize :: w -> s -> Int -> RECTANGLE -> Int
weight :: w -> Float
weight _ = 0
render :: w -> s -> Int -> Int -> Int -> Int -> Xlib.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, Xlib.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
@ -98,8 +103,8 @@ runIOCache a = do
put cache'
return b
createRenderCache :: (s -> Int -> Int -> Int -> Int -> Xlib.Rectangle -> Render ())
-> CacheArrow (Kleisli IO) (s, Int, Int, Int, Int, Xlib.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
@ -109,7 +114,7 @@ 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 -> Xlib.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)

View file

@ -5,16 +5,19 @@ module Phi.X11 ( XConfig(..)
, runPhi
) where
import Graphics.X11.Xlib
import Graphics.X11.Xlib.Extras
import Graphics.X11.Xinerama
import Graphics.XHB
import Graphics.XHB.Gen.Xinerama
import Graphics.XHB.Gen.Xproto
import Graphics.Rendering.Cairo
import Control.Monad
import Data.Maybe
import Data.Bits
import Data.Char
import Data.List
import Data.Maybe
import Data.Typeable
import Data.Word
import Control.Arrow ((&&&))
import Control.Concurrent
@ -27,16 +30,18 @@ import System.Exit
import System.Posix.Signals
import System.Posix.Types
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
import Phi.Widget hiding (Display, handleMessage)
import Phi.X11.Atoms
import qualified Phi.Bindings.Util as Util
data XConfig = XConfig { phiXScreenInfo :: !(Display -> IO [Rectangle])
data XConfig = XConfig { phiXScreenInfo :: !(Connection -> IO [RECTANGLE])
}
data PhiState w s c = (Widget.Widget w s c) => PhiState { phiRootImage :: !Surface
@ -47,10 +52,10 @@ data PhiState w s c = (Widget.Widget w s c) => PhiState { phiRootImage :: !Su
, phiWidgetState :: !s
}
data PanelState w s c = (Widget.Widget w s c) => PanelState { panelWindow :: !Window
, panelPixmap :: !Pixmap
, panelArea :: !Rectangle
, panelScreenArea :: !Rectangle
data PanelState w s c = (Widget.Widget w s c) => PanelState { panelWindow :: !WINDOW
, panelPixmap :: !PIXMAP
, panelArea :: !RECTANGLE
, panelScreenArea :: !RECTANGLE
, panelWidgetCache :: !c
}
@ -76,27 +81,35 @@ runPhiX config st (PhiX a) = runPhiReader config $ runStateT a st
defaultXConfig = XConfig { phiXScreenInfo = getScreenInfo
}
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 $ getRoot conn) >>= getReply' "getScreenInfo: getGeometry failed" >>=
return . (\(MkGetGeometryReply _ _ x y w h _) -> [MkRECTANGLE x y w h])
where
screenInfoToRect (MkScreenInfo x y w h) = MkRECTANGLE x y w h
runPhi :: (Widget.Widget w s c) => XConfig -> Panel.PanelConfig -> w -> IO ()
runPhi xconfig config widget = do
xSetErrorHandler
phi <- initPhi
installHandler sigTERM (termHandler phi) Nothing
installHandler sigINT (termHandler phi) Nothing
installHandler sigQUIT (termHandler phi) Nothing
disp <- openDisplay []
conn <- liftM fromJust connect
xcb <- XCB.connect
atoms <- initAtoms disp
selectInput disp (defaultRootWindow disp) $ propertyChangeMask.|.structureNotifyMask
atoms <- initAtoms conn
changeWindowAttributes conn (getRoot conn) $ toValueParam [(CWEventMask, toMask [EventMaskPropertyChange, EventMaskStructureNotify])]
bg <- createImageSurface FormatRGB24 1 1
dispmvar <- newMVar disp
screens <- liftIO $ phiXScreenInfo xconfig disp
panelWindows <- mapM (createPanelWindow disp config) screens
let dispvar = Widget.Display dispmvar atoms
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
@ -116,29 +129,28 @@ runPhi xconfig config widget = do
, phiShutdownHold = 0
, phiWidgetState = initialState
} $ do
updateRootImage disp
updateRootImage conn xcb
Widget.withDisplay dispvar $ \disp -> do
panels <- mapM (\(screen, window) -> createPanel disp window screen) screenPanels
panels <- mapM (\(screen, window) -> createPanel conn window screen) screenPanels
forM_ panels $ \panel -> do
setPanelProperties disp panel
liftIO $ mapWindow disp (panelWindow panel)
setPanelProperties conn panel
liftIO $ mapWindow conn (panelWindow panel)
modify $ \state -> state { phiPanels = panels }
liftIO $ forkIO $ receiveEvents phi dispvar
liftIO $ forkIO $ receiveEvents phi conn
forever $ do
available <- messageAvailable phi
unless available $ do
repaint <- gets phiRepaint
when repaint $ do
updatePanels dispvar
updatePanels conn xcb
modify $ \state -> state {phiRepaint = False}
message <- receiveMessage phi
handleMessage dispvar message
handleMessage conn xcb message
case (fromMessage message) of
Just Shutdown ->
@ -163,8 +175,8 @@ termHandler :: Phi -> Handler
termHandler phi = Catch $ sendMessage phi Shutdown
handleMessage :: (Widget w s c) => Widget.Display -> Message -> PhiX w s c ()
handleMessage dispvar 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}
@ -173,34 +185,43 @@ handleMessage dispvar m = do
modify $ \state -> state {phiRepaint = True}
_ ->
case (fromMessage m) of
Just event ->
Widget.withDisplay dispvar $ flip handleEvent event
Just (XEvent event) ->
handleEvent conn xcb event
_ ->
return ()
handleEvent :: (Widget w s c) => Display -> Event -> PhiX w s c ()
handleEvent disp PropertyEvent { ev_atom = atom } = do
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 conn xcb e
Nothing -> case (fromEvent event) of
Just e -> handleConfigureNotifyEvent conn e
Nothing -> return ()
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 phiAtoms
panels <- gets phiPanels
when (atom == atom_XROOTPMAP_ID atoms || atom == atom_XROOTMAP_ID atoms) $ do
updateRootImage disp
updateRootImage conn xcb
sendMessage phi ResetBackground
sendMessage phi Repaint
handleEvent disp ConfigureEvent { ev_window = window } | window == defaultRootWindow disp = do
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 disp
screens' <- liftIO $ phiXScreenInfo xconfig conn
when (screens /= screens') $ do
liftIO $ do
mapM (freePixmap disp . panelPixmap) panels
mapM_ (destroyWindow disp . panelWindow) $ drop (length screens') panels
mapM_ (freePixmap conn . panelPixmap) panels
mapM_ (destroyWindow conn . panelWindow) $ drop (length screens') panels
let panelsScreens = zip screens' $ map Just panels ++ repeat Nothing
@ -210,17 +231,21 @@ handleEvent disp ConfigureEvent { ev_window = window } | window == defaultRootWi
let rect = panelBounds config screen
win = panelWindow panel
liftIO $ withRectangle rect $ moveResizeWindow disp win
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 disp win screen
setPanelProperties disp panel'
panel' <- createPanel conn win screen
setPanelProperties conn panel'
return panel'
Nothing -> do
win <- liftIO $ createPanelWindow disp config screen
panel <- createPanel disp win screen
setPanelProperties disp panel
liftIO $ mapWindow disp $ panelWindow panel
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' }
@ -228,30 +253,13 @@ handleEvent disp ConfigureEvent { ev_window = window } | window == defaultRootWi
sendMessage phi $ UpdateScreens $ map (panelScreenArea &&& panelWindow) panels'
sendMessage phi Repaint
handleEvent _ _ = return ()
receiveEvents :: Phi -> Connection -> IO ()
receiveEvents phi conn = do
forever $ waitForEvent conn >>= sendMessage phi . XEvent
receiveEvents :: Phi -> Widget.Display -> IO ()
receiveEvents phi dispvar = do
connection <- Widget.withDisplay dispvar $ return . Fd . connectionNumber
allocaXEvent $ \xevent -> forever $ do
handled <- Widget.withDisplay dispvar $ \disp -> do
pend <- pending disp
if pend /= 0 then
do
liftIO $ nextEvent disp xevent
event <- liftIO $ Util.getEvent disp xevent
sendMessage phi event
return True
else return False
--when (not handled) $ threadWaitRead connection
when (not handled) $ threadDelay 40000
updatePanels :: (Widget w s c) => Widget.Display -> PhiX w s c ()
updatePanels dispvar = do
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
@ -264,16 +272,15 @@ updatePanels dispvar = do
(panelSurfaces, cache') <- liftIO $ flip runStateT (panelWidgetCache panel) $
(withDimension area $ Widget.render w s 0 0) (panelScreenArea panel)
Widget.withDisplay dispvar $ \disp -> do
let screen = defaultScreen disp
visual = defaultVisual disp screen
let screen = head . roots_Setup . connectionSetup $ conn
visualtype = fromJust $ findVisualtype screen (root_visual_SCREEN screen)
xbuffer <- liftIO $ withDimension area $ Util.createXlibSurface disp pixmap visual
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
@ -294,30 +301,27 @@ updatePanels dispvar = do
surfaceFinish xbuffer
-- update window
liftIO $ do
(withDimension area $ clearArea disp (panelWindow panel) 0 0) True
sync disp False
liftIO $ withDimension area $ XCB.clearArea xcb True (panelWindow panel) 0 0
return $ panel { panelWidgetCache = cache' }
modify $ \state -> state { phiPanels = panels' }
updateRootImage :: Display -> PhiX w s c ()
updateRootImage disp = do
updateRootImage :: Connection -> XCB.Connection -> PhiX w s c ()
updateRootImage conn xcb = do
atoms <- asks phiAtoms
let screen = defaultScreen disp
visual = defaultVisual disp screen
rootwin = defaultRootWindow disp
pixmap <- liftM (fromIntegral . fromMaybe 0 . listToMaybe . join . catMaybes) $ forM [atom_XROOTPMAP_ID atoms, atom_XROOTMAP_ID atoms] $
\atom -> liftIO $ getWindowProperty32 disp atom rootwin
let screen = head . roots_Setup . connectionSetup $ conn
visualtype = fromJust $ findVisualtype screen (root_visual_SCREEN screen)
rootwin = root_SCREEN screen
(pixmapWidth, pixmapHeight) <- case pixmap of
pixmap <- liftM (fromXid . toXid . fromMaybe 0 . listToMaybe . join . catMaybes) $ forM [atom_XROOTPMAP_ID atoms, atom_XROOTMAP_ID atoms] $
\atom -> liftIO $ getProperty32 conn rootwin atom
(pixmapWidth, pixmapHeight) <- case (fromXid . toXid $ (pixmap :: PIXMAP) :: Word32) of
0 -> return (1, 1)
_ -> do
(_, _, _, pixmapWidth, pixmapHeight, _, _) <- liftIO $ getGeometry disp pixmap
return (pixmapWidth, pixmapHeight)
_ -> liftIO $ getGeometry conn (fromXid . toXid $ pixmap) >>= getReply' "updateRootImage: getGeometry failed" >>= return . (width_GetGeometryReply &&& height_GetGeometryReply)
-- update surface size
oldBg <- gets phiRootImage
@ -330,31 +334,33 @@ updateRootImage disp = do
bg <- gets phiRootImage
case pixmap of
case (fromXid . toXid $ pixmap :: Word32) of
0 -> do
renderWith bg $ do
setSourceRGB 0 0 0
paint
_ -> do
rootSurface <- liftIO $ Util.createXlibSurface disp pixmap visual (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
paint
surfaceFinish rootSurface
return ()
createPanel :: (Widget w s c) => Display -> Window -> Rectangle -> PhiX w s c (PanelState w s c)
createPanel disp win screenRect = do
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 = defaultScreen disp
depth = defaultDepth disp screen
screen = head . roots_Setup . connectionSetup $ conn
depth = root_depth_SCREEN screen
pixmap <- liftIO $ (withDimension rect $ createPixmap disp win) depth
liftIO $ setWindowBackgroundPixmap disp win pixmap
pixmap <- liftIO $ newResource conn
liftIO $ createPixmap conn $ withDimension rect $ MkCreatePixmap depth pixmap (fromXid . toXid $ win)
liftIO $ changeWindowAttributes conn win $ toValueParam [(CWBackPixmap, fromXid . toXid $ pixmap)]
return PanelState { panelWindow = win
, panelPixmap = pixmap
@ -363,74 +369,62 @@ createPanel disp win screenRect = do
, panelWidgetCache = initCache w
}
createPanelWindow :: Display -> Panel.PanelConfig -> Rectangle -> IO Window
createPanelWindow disp config screenRect = do
createPanelWindow :: Connection -> Panel.PanelConfig -> RECTANGLE -> IO WINDOW
createPanelWindow conn config screenRect = do
let rect = panelBounds config screenRect
screen = defaultScreen disp
depth = defaultDepth disp screen
visual = defaultVisual disp screen
colormap = defaultColormap disp screen
rootwin = defaultRootWindow disp
mask = cWEventMask.|.cWColormap.|.cWBackPixel.|.cWBorderPixel
allocaSetWindowAttributes $ \attr -> do
set_colormap attr colormap
set_background_pixel attr 0
set_border_pixel attr 0
set_event_mask attr exposureMask
withRectangle rect (createWindow disp rootwin) 0 depth inputOutput visual mask attr
screen = head . roots_Setup . connectionSetup $ conn
depth = root_depth_SCREEN screen
rootwin = root_SCREEN screen
visual = root_visual_SCREEN screen
win <- liftIO $ newResource conn
createWindow conn $ (withRectangle rect $ MkCreateWindow depth win rootwin) 0 WindowClassInputOutput visual $
toValueParam [(CWEventMask, toMask [EventMaskExposure]), (CWBackPixel, 0), (CWBorderPixel, 0)]
return win
setPanelProperties :: Display -> PanelState w s c -> PhiX w s c ()
setPanelProperties disp panel = do
setPanelProperties :: Connection -> PanelState w s c -> PhiX w s c ()
setPanelProperties conn panel = do
atoms <- asks phiAtoms
liftIO $ do
storeName disp (panelWindow panel) "Phi"
changeProperty8 disp (panelWindow panel) (atom_NET_WM_NAME atoms) (atomUTF8_STRING atoms) propModeReplace $ map (fromIntegral . ord) "Phi"
let name = map (fromIntegral . ord) "Phi"
changeProperty8 conn PropModeReplace (panelWindow panel) (atomWM_NAME atoms) (atomSTRING atoms) name
changeProperty8 conn PropModeReplace (panelWindow panel) (atom_NET_WM_NAME atoms) (atomUTF8_STRING atoms) name
changeProperty32 disp (panelWindow panel) (atom_NET_WM_WINDOW_TYPE atoms) aTOM propModeReplace [fromIntegral (atom_NET_WM_WINDOW_TYPE_DOCK atoms)]
changeProperty32 disp (panelWindow panel) (atom_NET_WM_DESKTOP atoms) cARDINAL propModeReplace [0xFFFFFFFF]
changeProperty32 disp (panelWindow panel) (atom_NET_WM_STATE atoms) aTOM propModeReplace [ fromIntegral (atom_NET_WM_STATE_SKIP_PAGER atoms)
, fromIntegral (atom_NET_WM_STATE_SKIP_TASKBAR atoms)
, fromIntegral (atom_NET_WM_STATE_STICKY atoms)
, fromIntegral (atom_NET_WM_STATE_BELOW atoms)
changeProperty32 conn PropModeReplace (panelWindow panel) (atom_NET_WM_WINDOW_TYPE atoms) (atomATOM atoms) [fromXid . toXid $ atom_NET_WM_WINDOW_TYPE_DOCK atoms]
changeProperty32 conn PropModeReplace (panelWindow panel) (atom_NET_WM_DESKTOP atoms) (atomCARDINAL atoms) [0xFFFFFFFF]
changeProperty32 conn PropModeReplace (panelWindow panel) (atom_NET_WM_STATE atoms) (atomATOM atoms) $
map (fromXid . toXid) [ atom_NET_WM_STATE_SKIP_PAGER atoms
, atom_NET_WM_STATE_SKIP_TASKBAR atoms
, atom_NET_WM_STATE_STICKY atoms
, atom_NET_WM_STATE_BELOW atoms
]
setWMHints disp (panelWindow panel) WMHints { wmh_flags = fromIntegral inputHintBit
, wmh_input = False
, wmh_initial_state = 0
, wmh_icon_pixmap = 0
, wmh_icon_window = 0
, wmh_icon_x = 0
, wmh_icon_y = 0
, wmh_icon_mask = 0
, wmh_window_group = 0
}
changeProperty32 disp (panelWindow panel) (atom_MOTIF_WM_HINTS atoms) (atom_MOTIF_WM_HINTS atoms) propModeReplace [ 2, 0, 0, 0, 0 ]
Util.setClassHint disp (panelWindow panel) ClassHint { resName = "phi", resClass = "Phi" }
changeProperty32 conn PropModeReplace (panelWindow panel) (atom_MOTIF_WM_HINTS atoms) (atom_MOTIF_WM_HINTS atoms) [ 2, 0, 0, 0, 0 ]
setStruts disp panel
changeProperty8 conn PropModeReplace (panelWindow panel) (atomWM_CLASS atoms) (atomSTRING atoms) $ map (fromIntegral . ord) "phi\0Phi"
setStruts conn panel
setStruts :: Display -> PanelState w s c -> PhiX w s c ()
setStruts disp panel = do
setStruts :: Connection -> PanelState w s c -> PhiX w s c ()
setStruts conn panel = do
atoms <- asks phiAtoms
config <- asks phiPanelConfig
let rootwin = defaultRootWindow disp
let rootwin = getRoot conn
position = Panel.panelPosition config
area = panelArea panel
(_, _, _, _, rootHeight, _, _) <- liftIO $ getGeometry disp rootwin
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
@ -438,21 +432,21 @@ setStruts disp panel = do
Phi.Bottom -> makeBottomStruts
liftIO $ do
changeProperty32 disp (panelWindow panel) (atom_NET_WM_STRUT atoms) cARDINAL propModeReplace $ take 4 struts
changeProperty32 disp (panelWindow panel) (atom_NET_WM_STRUT_PARTIAL atoms) cARDINAL propModeReplace struts
changeProperty32 conn PropModeReplace (panelWindow panel) (atom_NET_WM_STRUT atoms) (atomCARDINAL atoms) $ take 4 struts
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 = fromIntegral $ Panel.panelSize config }
Phi.Bottom -> screenBounds { rect_height = fromIntegral $ Panel.panelSize config,
rect_y = (rect_y screenBounds) + (fromIntegral $ rect_height screenBounds) - (fromIntegral $ 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)

View file

@ -6,10 +6,16 @@ module Phi.X11.AtomList ( atoms
import Language.Haskell.TH
import Graphics.X11.Xlib
import Graphics.XHB
import Graphics.XHB.Connection.Open
atoms :: [String]
atoms = [ "UTF8_STRING"
atoms = [ "ATOM"
, "CARDINAL"
, "STRING"
, "UTF8_STRING"
, "WM_NAME"
, "WM_CLASS"
, "MANAGER"
, "_NET_WM_NAME"
, "_NET_WM_WINDOW_TYPE"
@ -43,7 +49,7 @@ atoms = [ "UTF8_STRING"
, "_XROOTMAP_ID"
]
-- the expression must have the type (Display -> String)
-- the expression must have the type (Connection -> String)
specialAtoms :: [(String, Q Exp)]
specialAtoms = [ ("_NET_SYSTEM_TRAY_SCREEN", [|("_NET_SYSTEM_TRAY_S" ++) . show . defaultScreen|])
specialAtoms = [ ("_NET_SYSTEM_TRAY_SCREEN", [|("_NET_SYSTEM_TRAY_S" ++) . show . screen . displayInfo|])
]

View file

@ -5,36 +5,48 @@ module Phi.X11.Atoms ( Atoms(..)
) where
import Control.Monad
import Data.Char
import Data.List
import Language.Haskell.TH
import Graphics.X11
import Graphics.XHB
import Graphics.XHB.Gen.Xproto
import Phi.X11.AtomList
$(let atomsName = mkName "Atoms"
atomNames = map (\atom -> (atom, mkName ("atom" ++ atom))) $ atoms ++ (map fst specialAtoms)
fields = map (\(_, name) -> (name, IsStrict, ConT ''Atom)) atomNames
fields = map (\(_, name) -> (name, IsStrict, ConT ''ATOM)) atomNames
in return [DataD [] atomsName [] [RecC atomsName fields] []]
)
initAtoms :: Display -> IO Atoms
initAtoms display =
initAtoms :: Connection -> IO Atoms
initAtoms conn =
$(do
normalAtomNames <- mapM (\atom -> do
receiptName <- newName ('_':atom)
varName <- newName ('_':atom)
return ([|const atom|], mkName ("atom" ++ atom), varName)
return ([|const atom|], mkName ("atom" ++ atom), receiptName, varName)
) atoms
specialAtomNames <- mapM (\(name, atomgen) -> do
receiptName <- newName ('_':name)
varName <- newName ('_':name)
return (atomgen, mkName ("atom" ++ name), varName)
return (atomgen, mkName ("atom" ++ name), receiptName, varName)
) specialAtoms
let atomNames = normalAtomNames ++ specialAtomNames
atomReceipts <- forM atomNames $
\(atomgen, _, receiptName, _) -> liftM (BindS (VarP receiptName))
[|let name = ($atomgen conn)
in internAtom conn $ MkInternAtom False (genericLength name) $ map (fromIntegral . ord) name|]
atomInitializers <- forM atomNames $
\(atomgen, _, varName) -> liftM (BindS (VarP varName)) [| internAtom display ($atomgen display) False |]
\(_, _, receiptName, varName) -> liftM (BindS (VarP varName))
[|liftM (\(Right a) -> a) $ getReply $(return $ VarE receiptName)|]
let atomFieldExps = map (\(_, atomName, varName) -> (atomName, VarE varName)) atomNames
let atomFieldExps = map (\(_, atomName, _, varName) -> (atomName, VarE varName)) atomNames
atomsName = mkName "Atoms"
atomsContruction = NoBindS $ AppE (VarE 'return) $ RecConE atomsName atomFieldExps
return $ DoE $ atomInitializers ++ [atomsContruction]
return $ DoE $ atomReceipts ++ atomInitializers ++ [atomsContruction]
)

89
lib/Phi/X11/Util.hs Normal file
View file

@ -0,0 +1,89 @@
module Phi.X11.Util ( getReply'
, changeProperty8
, changeProperty16
, changeProperty32
, getProperty8
, getProperty16
, getProperty32
, findVisualtype
) where
import Control.Monad
import Data.Int
import Data.List
import Data.Maybe
import Data.Word
import Foreign.Marshal.Array
import Foreign.Ptr
import Graphics.XHB
import Graphics.XHB.Gen.Xproto
import System.IO.Unsafe
getReply' :: String -> Receipt a -> IO a
getReply' m = getReply >=> return . fromRight
where
fromRight (Left _) = error m
fromRight (Right a) = a
castWord16to8 :: [Word16] -> [Word8]
castWord16to8 input = unsafePerformIO $
withArray input $ \ptr ->
peekArray (2 * length input) (castPtr ptr)
castWord32to8 :: [Word32] -> [Word8]
castWord32to8 input = unsafePerformIO $
withArray input $ \ptr ->
peekArray (4 * length input) (castPtr ptr)
castWord8to16 :: [Word8] -> [Word16]
castWord8to16 input = unsafePerformIO $
withArray input $ \ptr ->
peekArray (length input `div` 2) (castPtr ptr)
castWord8to32 :: [Word8] -> [Word32]
castWord8to32 input = unsafePerformIO $
withArray input $ \ptr ->
peekArray (length input `div` 4) (castPtr ptr)
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 :: 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 :: 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' :: 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
Left _ -> return Nothing
Right (MkGetPropertyReply {format_GetPropertyReply = format'}) | format' /= format -> return Nothing
Right (MkGetPropertyReply {bytes_after_GetPropertyReply = 0, value_GetPropertyReply = value}) -> return $ Just value
Right (MkGetPropertyReply {bytes_after_GetPropertyReply = bytes_after}) -> do
reply' <- getProperty conn (MkGetProperty False win prop (fromXid xidNone) 0 (4+bytes_after)) >>= getReply
case reply' of
Left _ -> return Nothing
Right (MkGetPropertyReply {format_GetPropertyReply = format'}) | format' /= format -> return Nothing
Right (MkGetPropertyReply {value_GetPropertyReply = value}) -> return $ Just value
getProperty8 :: Connection -> WINDOW -> ATOM -> IO (Maybe [Word8])
getProperty8 = getProperty' 8
getProperty16 :: Connection -> WINDOW -> ATOM -> IO (Maybe [Word16])
getProperty16 conn win prop = getProperty' 16 conn win prop >>= return . fmap castWord8to16
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

View file

@ -11,15 +11,16 @@ 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, X11, 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.Taskbar, Phi.Widgets.Systray
other-modules: Phi.X11.Atoms, Phi.X11.AtomList, Phi.Bindings.Util, Phi.Bindings.SystrayErrorHandler
c-sources: csrc/SystrayErrorHandler.c
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.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
extra-libraries: X11
pkgconfig-depends: cairo >= 1.2.0, cairo-xlib
pkgconfig-depends: xcb, cairo >= 1.2.0, cairo-xcb
ghc-options: -fspec-constr-count=16 -threaded
executable Phi

View file

@ -6,13 +6,13 @@ import Phi.X11
import Phi.Widgets.AlphaBox
import Phi.Widgets.Clock
import Phi.Widgets.Taskbar
import Phi.Widgets.Systray
--import Phi.Widgets.Taskbar
--import Phi.Widgets.Systray
main :: IO ()
main = do
runPhi defaultXConfig defaultPanelConfig { panelPosition = Top } $ 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,7 +46,7 @@ main = do
, desktopStyle = Just (normalDesktopStyle, currentDesktopStyle)
}
theSystray = systray
theSystray = systray-}
theClock = clock defaultClockConfig { clockFormat = "<span font='Sans 8'>%R</span>\n<span font='Sans 6'>%A %d %B</span>"
, lineSpacing = (-3)