packages feed

aosd 0.1.2 → 0.1.3

raw patch · 6 files changed

+399/−222 lines, 6 filesdep +monad-controlPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: monad-control

API changes (from Hackage documentation)

- Graphics.Aosd: AosdPtr :: ForeignPtr C'Aosd -> AosdPtr
- Graphics.Aosd: instance AosdRenderer GeneralRenderer
- Graphics.Aosd: instance Bounded Position
- Graphics.Aosd: instance Enum Position
- Graphics.Aosd: instance Show FlashDurations
- Graphics.Aosd: instance Show Position
- Graphics.Aosd: instance Show ScreenSize
- Graphics.Aosd: instance Show Transparency
- Graphics.Aosd: instance Show XClassHint
- Graphics.Aosd: newtype AosdPtr
- Graphics.Aosd: unAosdPtr :: AosdPtr -> ForeignPtr C'Aosd
+ Graphics.Aosd: aosdDestroy :: AosdForeignPtr -> IO ()
+ Graphics.Aosd: data AosdForeignPtr
+ Graphics.Aosd: debugRenderer :: GeneralRenderer
- Graphics.Aosd: aosdHide :: AosdPtr -> IO ()
+ Graphics.Aosd: aosdHide :: AosdForeignPtr -> IO ()
- Graphics.Aosd: aosdLoopFor :: AosdPtr -> CUInt -> IO ()
+ Graphics.Aosd: aosdLoopFor :: AosdForeignPtr -> CUInt -> IO ()
- Graphics.Aosd: aosdLoopOnce :: AosdPtr -> IO ()
+ Graphics.Aosd: aosdLoopOnce :: AosdForeignPtr -> IO ()
- Graphics.Aosd: aosdNew :: AosdRenderer a => AosdOptions -> a -> IO AosdPtr
+ Graphics.Aosd: aosdNew :: AosdRenderer renderer => AosdOptions -> renderer -> IO AosdForeignPtr
- Graphics.Aosd: aosdRender :: AosdPtr -> IO ()
+ Graphics.Aosd: aosdRender :: AosdForeignPtr -> IO ()
- Graphics.Aosd: aosdShow :: AosdPtr -> IO ()
+ Graphics.Aosd: aosdShow :: AosdForeignPtr -> IO ()
- Graphics.Aosd: reconfigure :: AosdRenderer a => AosdOptions -> a -> AosdPtr -> IO ()
+ Graphics.Aosd: reconfigure :: AosdRenderer renderer => AosdOptions -> renderer -> AosdForeignPtr -> IO ()

Files

Graphics/Aosd.hs view
@@ -1,9 +1,9 @@-{-# LANGUAGE ExistentialQuantification, NamedFieldPuns, RecordWildCards #-}+{-# LANGUAGE FlexibleContexts, Rank2Types, KindSignatures, NoMonomorphismRestriction, ExistentialQuantification, NamedFieldPuns, RecordWildCards #-} {-# OPTIONS -Wall #-} -- | For a higher-level API for textual OSDs using /Pango/, use "Graphics.Aosd.Pango". module Graphics.Aosd(     -- * Renderers-    AosdRenderer(..), GeneralRenderer(..), +    AosdRenderer(..), GeneralRenderer(..), --     -- ** Simple combinators --     HCatRenderer(..), VCatRenderer(..),     -- * Options@@ -12,191 +12,100 @@     aosdFlash,     FlashDurations(..), symDurations,     -- ** Low-level operations-    AosdPtr(..),aosdNew,reconfigure,+    AosdForeignPtr,aosdNew,aosdDestroy,reconfigure,     aosdRender, aosdShow, aosdHide, aosdLoopOnce, aosdLoopFor, +    -- * Diagnostics+    debugRenderer,+     -- * Reexports     module Graphics.Rendering.Cairo,     Rectangle(..),     CInt, CUInt -    -         ) where +import Control.Concurrent.MVar import Control.Exception-import Control.Monad.IO.Class import Control.Monad.Trans.Reader-import Foreign import Foreign.C+import Foreign.Ptr+import Foreign.StablePtr+import Foreign.Storable import Graphics.Aosd.AOSD_H+import Graphics.Aosd.Options+import Graphics.Aosd.Renderer import Graphics.Aosd.Util+import Graphics.Aosd.XUtil import Graphics.Rendering.Cairo-import Graphics.Rendering.Cairo.Internal(runRender)-import Data.Functor+import Graphics.Rendering.Cairo.Internal(runRender,Cairo) import Graphics.Rendering.Pango.Enums-import Graphics.X11.Xlib(openDisplay,closeDisplay,displayHeight,displayWidth,defaultScreen)+import System.IO.Unsafe -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 -- ^ Left/top-              | Center -              | Max -- ^ Right/bottom-    deriving(Show,Enum,Bounded) -data AosdOptions = AosdOptions {-    -- | 'Nothing' = use /libaosd/ default.-    classHint :: Maybe XClassHint,-    -- | 'Nothing' = use /libaosd/ default.-    transparency :: Maybe Transparency,-    xPos :: Position,-    yPos :: Position,-    -- | Positive values denote a rightwards respectively downwards offset (in pixels).-    offset :: (CInt,CInt),-    -- | 'Nothing' = use /libaosd/ default.-    hideUponMouseEvent :: Maybe Bool,-    -- | Mouse-click event handler.-    mouseEventCB :: Maybe (C'AosdMouseEvent -> IO ())-}--data GeneralRenderer = GeneralRenderer {-    grRender :: Render (),-    -- | Part of the surface that the renderer actually draws on (determines the window size).-    grInkExtent :: Rectangle,-    -- | Part of the surface whose...-    ---    -- * ... left edge is aligned to the left edge of the screen, if 'xPos' is 'Min'-    ---    -- * ... center is aligned to the center of the screen, if 'xPos' is 'Center'-    ---    -- * ... right edge is aligned to the right edge of the screen, if 'xPos' is 'Max'-    ---    -- (Likewise for the /y/ axis)-    grPositioningExtent :: Rectangle-}----- -- | Horizontal concatenation--- data HCatRenderer = forall r1 r2. (AosdRenderer r1, AosdRenderer r2) => HCat r1 r2--- --- --- -- | Vertical concatenation--- data VCatRenderer = forall r1 r2. (AosdRenderer r1, AosdRenderer r2) => VCat r1 r2---instance AosdRenderer GeneralRenderer where-    toGeneralRenderer = return---- instance AosdRenderer HCatRenderer where---     toGeneralRenderer (HCat r1 r2) = do---         gr1 <- toGeneralRenderer r1---         gr2 <- toGeneralRenderer r2---         return GeneralRenderer {---                     grWidth = ((+) `on` grWidth) gr1 gr2,---                     grHeight = (max `on` grHeight) gr1 gr2,---                     grRender = do---                         grRender gr1---                         translate (fromIntegral $ grWidth gr1) 0---                         grRender gr2---                }--- --- instance AosdRenderer VCatRenderer where---     toGeneralRenderer (VCat r1 r2) = do---         gr1 <- toGeneralRenderer r1---         gr2 <- toGeneralRenderer r2---         return GeneralRenderer {---                     grWidth = (max `on` grWidth) gr1 gr2,---                     grHeight = ((+) `on` grHeight) gr1 gr2,---                     grRender = do---                         grRender gr1---                         translate 0 (fromIntegral $ grHeight gr1)---                         grRender gr2---                }--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-- -- toAosdCoordinate :: Position -> C'AosdCoordinate -- toAosdCoordinate Min = c'COORDINATE_MINIMUM -- toAosdCoordinate Center = c'COORDINATE_CENTER -- toAosdCoordinate Max = c'COORDINATE_MAXIMUM  -withAosd :: (Ptr C'Aosd -> IO a) -> IO a-withAosd k = do-    a <- c'aosd_new -    finally (k a) (c'aosd_destroy a)+c'aosd_new_debug :: String -> IO (Ptr C'Aosd)+c'aosd_new_debug cxt = do+    p <- c'aosd_new+    putDebugMemory cxt ("c'aosd_new ==> "++show p)+    return p +c'aosd_destroy_debug :: String -> Ptr C'Aosd -> IO ()+c'aosd_destroy_debug cxt p = do+    putDebugMemory cxt ("c'aosd_destroy "++show p)+    c'aosd_destroy p +withAosd :: (Ptr C'Aosd -> IO a) -> IO a+withAosd = bracket (c'aosd_new_debug "withAosd") (c'aosd_destroy_debug "withAosd") -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-    )+type Render0 = Cairo -> IO ()  -data ScreenSize = ScreenSize { screenWidth, screenHeight :: Int }-    deriving(Show)  +withConfiguredAosd :: (AosdRenderer renderer) =>+                                                 AosdOptions -> renderer+                                              -> (Ptr C'Aosd -> IO a)+                                              -> IO a+withConfiguredAosd opts x k =+    withAosd (\a -> do+        z <- reconfigure0 opts x a+        k a `finally` freeAosdStructOwnedData "withConfiguredAosd" z +    ) -getScreenSize :: IO ScreenSize-getScreenSize = do-        display <- openDisplay "" -        let go = do-                -- Work around unsafe FFI declarations in the X11 bindings...-                screen <- evaluate $ defaultScreen display-                screenWidth <- evaluate . fromIntegral $ displayWidth display screen-                screenHeight <- evaluate . fromIntegral $ displayHeight display screen -                return ScreenSize{..} -        go `finally` closeDisplay display--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+reconfigure0 :: (AosdRenderer renderer) => AosdOptions -> renderer -> Ptr C'Aosd -> IO AosdStructOwnedData+reconfigure0 AosdOptions{..} renderer ptr = do+        GeneralRenderer{..} <- toGeneralRenderer renderer          ScreenSize{..} <- getScreenSize  -        let -- l=Left, t=Top, w=Width, h=Height +        let -- l=Left, t=Top, w=Width, h=Height             Rectangle li ti wi hi = grInkExtent             Rectangle lp tp wp hp = grPositioningExtent -{- -(These comments only look at the x dimension; the other is analogous) +{-+(These comments only look at the x dimension; the other is analogous)  Consider the mapping "screenx" from grRender x coordinates to screen x coordinates  Since we translate grRender by -(li,ti), we have: -        screenx x = windowLeft + x - li +        screenx x = windowLeft + x - li -If xPos is Min, we want: +If xPos is Min, we want:          screenx lp = 0         <=>@@ -210,7 +119,7 @@         <=>         windowLeft + (lp + wp/2) - li = screenWidth/2         <=>-        windowLeft = li - lp + (screenWidth - wp)/2 +        windowLeft = li - lp + (screenWidth - wp)/2  If xPos is Max, we want: @@ -221,13 +130,12 @@         windowLeft = li - lp + screenWidth - wp  -}-            calculateOffsetAdjustment pos min_ink min_positioning size_positioning size_screen  = fromIntegral $ +            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 +                              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@@ -241,18 +149,41 @@   -        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+        maybeDo (setClassHint ptr) classHint+        maybeDo (setHideUponMouseEvent ptr) hideUponMouseEvent+        maybeDo (setMouseEventCB ptr) mouseEventCB +        rendererPtr <- newStablePtrDebug "reconfigure0" "renderer" (runReaderT . runRender $ finalRenderer)+++        maybeDo (c'aosd_set_transparency ptr . toAosdTransparency) transparency+        c'aosd_set_geometry ptr windowLeft windowTop windowWidth windowHeight+        c'aosd_set_renderer ptr theC'AosdRenderer (castCairoIOStablePtrToPtr rendererPtr)++        return (AosdStructOwnedData rendererPtr)++++castCairoIOStablePtrToPtr :: StablePtr Render0 -> Ptr ()+castCairoIOStablePtrToPtr = castStablePtrToPtr++-- | Excepts its second argument to be a (StablePtr (Cairo -> IO ())).+theAosdRenderer :: Cairo -> Ptr () -> IO ()+theAosdRenderer cairo p = do+    render <- Foreign.StablePtr.deRefStablePtr (Foreign.StablePtr.castPtrToStablePtr p) :: IO Render0+    render cairo++-- | A 'FunPtr' to 'theAosdRenderer'.+{-# NOINLINE theC'AosdRenderer #-}+theC'AosdRenderer :: C'AosdRenderer+theC'AosdRenderer = unsafePerformIO (mk'AosdRenderer theAosdRenderer)++ setClassHint :: Ptr C'Aosd -> XClassHint -> IO ()-setClassHint a XClassHint{ resName, resClass } = +setClassHint a XClassHint{ resName, resClass } =     withCString resName (\resName' ->         withCString resClass (\resClass' ->             c'aosd_set_names a resName' resClass'))@@ -263,86 +194,99 @@ 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+    c'aosd_set_mouse_event_cb a fptr Foreign.Ptr.nullPtr   where-    f' :: Ptr C'AosdMouseEvent -> Ptr () -> IO () -    f' p _ = do -        mouseEvent <- peek p +    f' :: Ptr C'AosdMouseEvent -> Ptr () -> IO ()+    f' p _ = do+        mouseEvent <- peek p         f mouseEvent --- | Non-'Nothing' defaults:------ *       transparency = Just Composite,------ *       xPos = Center, ------ *       yPos = Center,--- --- *       offset = (0,0),------ *       hideUponMouseEvent = Just True-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 -- ^ Fade-in time in milliseconds -  , fullMillis :: CUInt -- ^ Full display time in milliseconds-  , outMillis :: CUInt -- ^ Fade-out time in milliseconds-}-    deriving(Show)+-- | Main high-level displayer. Blocks.+aosdFlash :: (AosdRenderer a) => AosdOptions -> a -> FlashDurations -> IO ()+aosdFlash opts renderer durations = withConfiguredAosd opts renderer (aosdFlash' durations) --- | Construct a 'FlashDurations' with equal 'inMillis' and 'outMillis'.-symDurations :: -        CUInt -- ^ 'inMillis' and 'outMillis'. -     -> CUInt -- ^ 'fullMillis'.-     -> FlashDurations-symDurations fadeMillis fullMillis = FlashDurations fadeMillis fullMillis fadeMillis --- | Main high-level displayer. Blocks. -aosdFlash :: AosdRenderer a => AosdOptions -> a -> FlashDurations -> IO ()-aosdFlash opts renderer FlashDurations{..} = -    withConfiguredAosd opts renderer (\p -> c'aosd_flash p inMillis fullMillis outMillis)+aosdFlash' :: FlashDurations -> Ptr C'Aosd -> IO ()+aosdFlash' FlashDurations{..} a = (c'aosd_flash a inMillis fullMillis outMillis) -                               +data AosdForeignPtr = AosdForeignPtr { unAosdPtr :: !(Ptr C'Aosd)+                                        -- This has the sole purpose of keeping the AosdStructOwnedData alive+                                     , aosdStructOwnedDataVar :: !(MVar AosdStructOwnedData)+                                     } +aosdNew :: (AosdRenderer renderer) => AosdOptions -> renderer -> IO AosdForeignPtr+aosdNew opts r = do+    unAosdPtr <- c'aosd_new_debug "aosdNew"+    z <- reconfigure0 opts r unAosdPtr+    aosdStructOwnedDataVar <- newMVar z +    {-+        The ForeignPtr C'Aosd should keep the reference to its AosdStructOwnedData alive.+        Otherwise, something like this could access already freed memory: -newtype AosdPtr = AosdPtr { unAosdPtr :: ForeignPtr C'Aosd }+            do+                thunk <- do +                        aosd <- aosdNew defaultOpts debugRenderer  +                        return (aosdShow aosd)  --- | Create an /Aosd/ object managed by the garbage collector.-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+                -- @thunk@ only references @unAosdPtr aosd@, not @aosdStructOwnedDataVar aosd@!+                -- (The reference from the Aosd struct to the StablePtrs is only on the C side)+                --+                -- ... the @AosdStructOwnedData@ produced in aosdNew is finalized (the StablePtrs in it are freed) ... +                thunk -- Causes the C side to pass a dead StablePtr back to @theC'AosdRenderer@! -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+    return AosdForeignPtr {unAosdPtr,aosdStructOwnedDataVar} -aosdHide :: AosdPtr -> IO ()-aosdHide = (`withForeignPtr` c'aosd_hide) . unAosdPtr -aosdLoopOnce :: AosdPtr -> IO ()-aosdLoopOnce = (`withForeignPtr` c'aosd_loop_once) . unAosdPtr -aosdLoopFor :: AosdPtr -            -> CUInt -- ^ Time in milliseconds.-            -> IO ()-aosdLoopFor (AosdPtr fp) millis = (fp `withForeignPtr` (`c'aosd_loop_for` millis))  +reconfigure :: (AosdRenderer renderer) =>+        AosdOptions+     -> renderer+     -> AosdForeignPtr+     -> IO ()++reconfigure opts r (AosdForeignPtr fp var) = modifyMVar_ var+    (\zOld -> do+        zNew <- reconfigure0 opts r fp+        freeAosdStructOwnedData "reconfigure" zOld+        return zNew)+++aosdRender :: AosdForeignPtr -> IO ()+aosdRender = (c'aosd_render) . unAosdPtr++aosdShow :: AosdForeignPtr -> IO ()+aosdShow = (c'aosd_show) . unAosdPtr++aosdHide :: AosdForeignPtr -> IO ()+aosdHide = (c'aosd_hide) . unAosdPtr++aosdLoopOnce :: AosdForeignPtr -> IO ()+aosdLoopOnce = (c'aosd_loop_once) . unAosdPtr++aosdLoopFor ::+        AosdForeignPtr+     -> CUInt -- ^ Time in milliseconds.+     -> IO ()+aosdLoopFor (AosdForeignPtr fp _) millis = c'aosd_loop_for fp millis+++data AosdStructOwnedData = AosdStructOwnedData !(StablePtr (Cairo -> IO ()))++++freeAosdStructOwnedData :: String -> AosdStructOwnedData -> IO ()+freeAosdStructOwnedData cxt (AosdStructOwnedData sp_r) = do+    freeStablePtrDebug cxt "renderer" sp_r++aosdDestroy :: AosdForeignPtr -> IO ()+aosdDestroy (AosdForeignPtr p var) = do+    c'aosd_destroy_debug "aosdDestroy" p+    z <- readMVar var+    freeAosdStructOwnedData "aosdDestroy" z
+ Graphics/Aosd/Options.hs view
@@ -0,0 +1,74 @@+{-# OPTIONS -Wall #-}+module Graphics.Aosd.Options where++import Graphics.Aosd.AOSD_H+import Foreign.C.Types++data XClassHint = XClassHint { resName, resClass :: String }+    deriving(Show)++data Transparency = None | Fake | Composite+    deriving(Show)++data Position = Min -- ^ Left/top+              | Center+              | Max -- ^ Right/bottom+    deriving(Show,Enum,Bounded)++data AosdOptions = AosdOptions {+    -- | 'Nothing' = use /libaosd/ default.+    classHint :: Maybe XClassHint,+    -- | 'Nothing' = use /libaosd/ default.+    transparency :: Maybe Transparency,+    xPos :: Position,+    yPos :: Position,+    -- | Positive values denote a rightwards respectively downwards offset (in pixels).+    offset :: (CInt,CInt),+    -- | 'Nothing' = use /libaosd/ default.+    hideUponMouseEvent :: Maybe Bool,+    -- | Mouse-click event handler.+    mouseEventCB :: Maybe (C'AosdMouseEvent -> IO ())+}++toAosdTransparency :: Transparency -> C'AosdTransparency+toAosdTransparency None = c'TRANSPARENCY_NONE+toAosdTransparency Fake = c'TRANSPARENCY_FAKE+toAosdTransparency Composite = c'TRANSPARENCY_COMPOSITE++-- | Non-'Nothing' defaults:+--+-- *       transparency = Just Composite,+--+-- *       xPos = Center,+--+-- *       yPos = Center,+--+-- *       offset = (0,0),+--+-- *       hideUponMouseEvent = Just True+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 -- ^ Fade-in time in milliseconds+  , fullMillis :: CUInt -- ^ Full display time in milliseconds+  , outMillis :: CUInt -- ^ Fade-out time in milliseconds+}+    deriving(Show)++-- | Construct a 'FlashDurations' with equal 'inMillis' and 'outMillis'.+symDurations ::+        CUInt -- ^ 'inMillis' and 'outMillis'.+     -> CUInt -- ^ 'fullMillis'.+     -> FlashDurations+symDurations fadeMillis fullMillis_ = FlashDurations fadeMillis fullMillis_ fadeMillis+
+ Graphics/Aosd/Renderer.hs view
@@ -0,0 +1,82 @@+{-# OPTIONS -Wall #-}+module Graphics.Aosd.Renderer where+import Graphics.Rendering.Cairo+import Graphics.Rendering.Pango.Enums+import Graphics.Aosd.Util+++class AosdRenderer a where+    toGeneralRenderer :: a -> IO GeneralRenderer++data GeneralRenderer = GeneralRenderer {+    grRender :: Render (),+    -- | Part of the surface that the renderer actually draws on (determines the window size).+    grInkExtent :: Rectangle,+    -- | Part of the surface whose...+    --+    -- * ... left edge is aligned to the left edge of the screen, if 'xPos' is 'Min'+    --+    -- * ... center is aligned to the center of the screen, if 'xPos' is 'Center'+    --+    -- * ... right edge is aligned to the right edge of the screen, if 'xPos' is 'Max'+    --+    -- (Likewise for the /y/ axis)+    grPositioningExtent :: Rectangle+}+ +instance AosdRenderer GeneralRenderer where+    toGeneralRenderer = return++debugRenderer :: GeneralRenderer+debugRenderer =+    GeneralRenderer {+        grInkExtent = rect,+        grPositioningExtent = rect,+        grRender = do+            liftIO (putStdErr "debugRenderer invoked")+            setLineWidth lw+            setSourceRGB  0 1 0+            arc 0 0 (r - lw) 0 (2*pi)+            stroke+    }+        where+            rect = Rectangle (-r) (-r) (2*r) (2*r)+            r :: Num a => a+            r = 100+            lw = 5++-- -- | Horizontal concatenation+-- data HCatRenderer = forall r1 r2. (AosdRenderer r1, AosdRenderer r2) => HCat r1 r2+--+--+-- -- | Vertical concatenation+-- data VCatRenderer = forall r1 r2. (AosdRenderer r1, AosdRenderer r2) => VCat r1 r2++++-- instance AosdRenderer HCatRenderer where+--     toGeneralRenderer (HCat r1 r2) = do+--         gr1 <- toGeneralRenderer r1+--         gr2 <- toGeneralRenderer r2+--         return GeneralRenderer {+--                     grWidth = ((+) `on` grWidth) gr1 gr2,+--                     grHeight = (max `on` grHeight) gr1 gr2,+--                     grRender = do+--                         grRender gr1+--                         translate (fromIntegral $ grWidth gr1) 0+--                         grRender gr2+--                }+--+-- instance AosdRenderer VCatRenderer where+--     toGeneralRenderer (VCat r1 r2) = do+--         gr1 <- toGeneralRenderer r1+--         gr2 <- toGeneralRenderer r2+--         return GeneralRenderer {+--                     grWidth = (max `on` grWidth) gr1 gr2,+--                     grHeight = ((+) `on` grHeight) gr1 gr2,+--                     grRender = do+--                         grRender gr1+--                         translate 0 (fromIntegral $ grHeight gr1)+--                         grRender gr2+--                }+
Graphics/Aosd/Util.hs view
@@ -1,9 +1,15 @@-{-# LANGUAGE ViewPatterns, NoMonomorphismRestriction #-}+{-# LANGUAGE CPP, ViewPatterns, NoMonomorphismRestriction #-} module Graphics.Aosd.Util where import Graphics.Rendering.Pango.Enums import Control.Arrow import Data.Colour.SRGB import Graphics.Rendering.Cairo+import Foreign.StablePtr+import System.IO+import Control.Monad+import Foreign.Concurrent+import Foreign.Ptr+import Foreign.ForeignPtr(ForeignPtr)  maybeDo :: Monad m => (a -> m ()) -> Maybe a -> m () maybeDo f = maybe (return ()) f@@ -63,3 +69,39 @@ setSourceColour :: Colour Double -> Double -> Render () setSourceColour (toSRGB -> RGB r g b) a = setSourceRGBA r g b a +debugMemory :: Bool+putDebugMemory :: String -> String -> IO ()+#ifdef DEBUG_MEMORY+debugMemory = True+putDebugMemory cxt msg = putStdErr (cxt ++ ": "++replicate (30 - length cxt) ' ' ++ msg)+#else+debugMemory = False+putDebugMemory _ _ = return ()+#endif++showStablePtr ::  StablePtr a -> String+showStablePtr = show . castStablePtrToPtr++putStdErr :: String -> IO ()+putStdErr = hPutStrLn stderr+++newStablePtrDebug :: String -> String -> a -> IO (StablePtr a)+newStablePtrDebug cxt descr a = do+    sp <- newStablePtr a+    putDebugMemory cxt ("Created "++descr++" StablePtr: "++showStablePtr sp) +    return sp++freeStablePtrDebug :: String -> String -> StablePtr a -> IO ()+freeStablePtrDebug cxt descr sp = do+    putDebugMemory cxt ("Freeing "++descr++" StablePtr: "++showStablePtr sp) +    freeStablePtr sp++newForeignPtrDebug :: String -> String -> IO () -> Ptr a -> IO (ForeignPtr a)+newForeignPtrDebug cxt descr finalizer p = do+    fp <- newForeignPtr p +                (do+                    putDebugMemory "ForeignPtr finalizer" ("Finalizing "++descr++" ForeignPtr made in "++cxt)   +                    finalizer)+    putDebugMemory cxt ("Created "++descr++" ForeignPtr: "++show fp)+    return fp
+ Graphics/Aosd/XUtil.hs view
@@ -0,0 +1,24 @@+{-# LANGUAGE RecordWildCards #-}+{-# OPTIONS -Wall #-}+module Graphics.Aosd.XUtil where+import Graphics.X11.Xlib.Display+import Control.Exception++data ScreenSize = ScreenSize { screenWidth, screenHeight :: Int }+    deriving(Show)+++getScreenSize :: IO ScreenSize+getScreenSize = do+        display <- openDisplay ""++        let go = do+                -- Work around unsafe FFI declarations in the X11 bindings...+                screen <- evaluate $ defaultScreen display+                screenWidth <- evaluate . fromIntegral $ displayWidth display screen+                screenHeight <- evaluate . fromIntegral $ displayHeight display screen++                return ScreenSize{..}++        go `finally` closeDisplay display+
aosd.cabal view
@@ -2,9 +2,9 @@ -- see -- http://www.haskell.org/cabal/release/cabal-latest/doc/users-guide/authors.html#pkg-descr. Name:                aosd-Version:             0.1.2+Version:             0.1.3 Synopsis:            Bindings to libaosd, a library for Cairo-based on-screen displays-Description:         +Description:  <http://www.atheme.org/project/libaosd>  .  @An advanced on screen display (OSD) library, which uses Cairo to create high quality rendered graphics to be overlaid on top of the screen.@@@ -21,9 +21,9 @@  .  markup = pSized 50 (pUnlines [pItalic \"AOSD\",\"Example\"])  .- main = aosdFlash - \           defaultOpts - \           (textRenderer markup) &#123; alignment = Just AlignCenter, colour = orange &#125; + main = aosdFlash+ \           defaultOpts+ \           (textRenderer markup) &#123; alignment = Just AlignCenter, colour = orange &#125;  \           (symDurations 3000 3000)  @  .@@ -33,7 +33,7 @@ License-file:        LICENSE Author:              Daniel Schüssler Maintainer:          anotheraddress@gmx.de--- Copyright:           +-- Copyright: Category:            Graphics Build-type:          Simple Extra-source-files:  test/test.hs@@ -41,22 +41,33 @@  source-repository head   type:     hg-  location: https://dschuessler@bitbucket.org/dschuessler/haskell-aosd +  location: https://dschuessler@bitbucket.org/dschuessler/haskell-aosd +Flag DebugMemory+    Default: False+    Manual: True+ Library   Default-Extensions: ForeignFunctionInterface-  Exposed-modules: -    Graphics.Aosd.AOSD_H +  Exposed-modules:+    Graphics.Aosd.AOSD_H     Graphics.Aosd     Graphics.Aosd.Pango-  Other-modules:       +  Other-modules:+    Graphics.Aosd.Options+    Graphics.Aosd.Renderer     Graphics.Aosd.Util+    Graphics.Aosd.XUtil  -  Build-depends:       colour, transformers, X11, base >= 4 && < 5, bindings-DSL >= 1.0.11, cairo >= 0.12, pango >= 0.12 +  Build-depends:       monad-control, colour, transformers, X11, base >= 4 && < 5, bindings-DSL >= 1.0.11, cairo >= 0.12, pango >= 0.12   Build-tools:         hsc2hs   Pkgconfig-depends:   libaosd   Default-language: Haskell2010++  if(flag(DebugMemory))+    Cpp-options: -DDEBUG_MEMORY+  Test-Suite test-aosd     type:       exitcode-stdio-1.0