module Graphics.Aosd(
AosdRenderer(..), GeneralRenderer(..),
AosdOptions(..), Transparency(..), Position(..), XClassHint(..), defaultOpts,
aosdFlash,
FlashDurations(..), symDurations,
AosdPtr(..),aosdNew,reconfigure,
aosdRender, aosdShow, aosdHide, aosdLoopOnce, aosdLoopFor,
module Graphics.Rendering.Cairo,
Rectangle(..),
CInt, CUInt
) where
import Control.Exception
import Control.Monad.IO.Class
import Control.Monad.Trans.Reader
import Foreign
import Foreign.C
import Graphics.Aosd.AOSD_H
import Graphics.Aosd.Util
import Graphics.Rendering.Cairo
import Graphics.Rendering.Cairo.Internal(runRender)
import Data.Functor
import Graphics.Rendering.Pango.Enums
import Graphics.X11.Xlib(openDisplay,displayHeight,displayWidth,defaultScreen)
class AosdRenderer a where
toGeneralRenderer :: a -> IO GeneralRenderer
data XClassHint = XClassHint { resName, resClass :: String }
deriving(Show)
data Transparency = None | Fake | Composite
deriving(Show)
data Position = Min
| Center
| Max
deriving(Show,Enum,Bounded)
data AosdOptions = AosdOptions {
classHint :: Maybe XClassHint,
transparency :: Maybe Transparency,
xPos :: Position,
yPos :: Position,
offset :: (CInt,CInt),
hideUponMouseEvent :: Maybe Bool,
mouseEventCB :: Maybe (C'AosdMouseEvent -> IO ())
}
data GeneralRenderer = GeneralRenderer {
grRender :: Render (),
grInkExtent :: Rectangle,
grPositioningExtent :: Rectangle
}
instance AosdRenderer GeneralRenderer where
toGeneralRenderer = return
toC'AosdRenderer :: Render () -> IO C'AosdRenderer
toC'AosdRenderer r = mk'AosdRenderer f
where
f cairo _ = runReaderT (runRender r) cairo
toAosdTransparency :: Transparency -> C'AosdTransparency
toAosdTransparency None = c'TRANSPARENCY_NONE
toAosdTransparency Fake = c'TRANSPARENCY_FAKE
toAosdTransparency Composite = c'TRANSPARENCY_COMPOSITE
withAosd :: (Ptr C'Aosd -> IO a) -> IO a
withAosd k = do
a <- c'aosd_new
finally (k a) (c'aosd_destroy a)
withConfiguredAosd :: AosdRenderer a => AosdOptions -> a -> (Ptr C'Aosd -> IO r) -> IO r
withConfiguredAosd opts x k =
withAosd (\a -> do
reconfigure0 opts x a
k a
)
reconfigure0 :: AosdRenderer a => AosdOptions -> a -> Ptr C'Aosd -> IO ()
reconfigure0 AosdOptions{..} renderer a = do
GeneralRenderer{..} <- toGeneralRenderer renderer
maybeDo (setClassHint a) classHint
maybeDo (c'aosd_set_transparency a . toAosdTransparency) transparency
display <- openDisplay ""
let screen = defaultScreen display
screenWidth = fromIntegral $ displayWidth display screen
screenHeight = fromIntegral $ displayHeight display screen
let
Rectangle li ti wi hi = grInkExtent
Rectangle lp tp wp hp = grPositioningExtent
calculateOffsetAdjustment pos min_ink min_positioning size_positioning size_screen = fromIntegral $
case pos of
Min -> min_ink min_positioning
Center -> min_ink min_positioning + div (size_screen size_positioning) 2
Max -> min_ink min_positioning + size_screen size_positioning
windowLeft = calculateOffsetAdjustment xPos li lp wp screenWidth + fst offset
windowTop = calculateOffsetAdjustment yPos ti tp hp screenHeight + snd offset
windowWidth = fromIntegral wi
windowHeight = fromIntegral hi
finalRenderer = do
translate (fi . negate $ li) (fi . negate $ ti)
grRender
c'aosd_set_geometry a windowLeft windowTop windowWidth windowHeight
rendererPtr <- toC'AosdRenderer finalRenderer
c'aosd_set_renderer a rendererPtr nullPtr
maybeDo (setHideUponMouseEvent a) hideUponMouseEvent
maybeDo (setMouseEventCB a) mouseEventCB
setClassHint :: Ptr C'Aosd -> XClassHint -> IO ()
setClassHint a XClassHint{ resName, resClass } =
withCString resName (\resName' ->
withCString resClass (\resClass' ->
c'aosd_set_names a resName' resClass'))
setHideUponMouseEvent :: Ptr C'Aosd -> Bool -> IO ()
setHideUponMouseEvent a b = c'aosd_set_hide_upon_mouse_event a (if b then 1 else 0)
setMouseEventCB :: Ptr C'Aosd -> (C'AosdMouseEvent -> IO ()) -> IO ()
setMouseEventCB a f = do
fptr <- mk'AosdMouseEventCb f'
c'aosd_set_mouse_event_cb a fptr nullPtr
where
f' :: Ptr C'AosdMouseEvent -> Ptr () -> IO ()
f' p _ = do
mouseEvent <- peek p
f mouseEvent
defaultOpts :: AosdOptions
defaultOpts =
AosdOptions {
classHint = Nothing,
transparency = Just Composite,
xPos = Center,
yPos = Center,
offset = (0,0),
hideUponMouseEvent = Just True,
mouseEventCB = Nothing
}
data FlashDurations = FlashDurations {
inMillis :: CUInt
, fullMillis :: CUInt
, outMillis :: CUInt
}
deriving(Show)
symDurations ::
CUInt
-> CUInt
-> FlashDurations
symDurations fadeMillis fullMillis = FlashDurations fadeMillis fullMillis fadeMillis
aosdFlash :: AosdRenderer a => AosdOptions -> a -> FlashDurations -> IO ()
aosdFlash opts renderer FlashDurations{..} =
withConfiguredAosd opts renderer (\p -> c'aosd_flash p inMillis fullMillis outMillis)
newtype AosdPtr = AosdPtr { unAosdPtr :: ForeignPtr C'Aosd }
aosdNew :: AosdRenderer a => AosdOptions -> a -> IO AosdPtr
aosdNew opts r = do
p <- c'aosd_new
reconfigure0 opts r p
AosdPtr <$> Foreign.newForeignPtr p'aosd_destroy p
reconfigure :: AosdRenderer a => AosdOptions -> a -> AosdPtr -> IO ()
reconfigure opts r = (`withForeignPtr` reconfigure0 opts r) . unAosdPtr
aosdRender :: AosdPtr -> IO ()
aosdRender = (`withForeignPtr` c'aosd_render) . unAosdPtr
aosdShow :: AosdPtr -> IO ()
aosdShow = (`withForeignPtr` c'aosd_show) . unAosdPtr
aosdHide :: AosdPtr -> IO ()
aosdHide = (`withForeignPtr` c'aosd_hide) . unAosdPtr
aosdLoopOnce :: AosdPtr -> IO ()
aosdLoopOnce = (`withForeignPtr` c'aosd_loop_once) . unAosdPtr
aosdLoopFor :: AosdPtr
-> CUInt
-> IO ()
aosdLoopFor (AosdPtr fp) millis = (fp `withForeignPtr` (`c'aosd_loop_for` millis))