libnotify 0.0.1.2 → 0.0.2.0
raw patch · 5 files changed
+168/−190 lines, 5 files
Files
- System/Libnotify.hs +76/−96
- System/Libnotify/Internal.hsc +23/−23
- System/Libnotify/Types.hs +53/−0
- System/Libnotify/Types.hsc +0/−55
- libnotify.cabal +16/−16
System/Libnotify.hs view
@@ -1,150 +1,130 @@-{-# LANGUAGE FlexibleInstances, FlexibleContexts #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-} -- | System.Libnotify module deals with notification session processing. {-# OPTIONS_HADDOCK prune #-} module System.Libnotify- ( oneShot, withNotifications+ ( Notify, NotifyState, NotifyError (..)+ , oneShot, withNotifications , new, continue, update, render, close , setTimeout, setCategory, setUrgency- , Hint(..), GeneralHint, removeHints+ , addHint, removeHints , addAction, removeActions- , notifyErrorHandler+ , setIconFromPixbuf, setImageFromPixbuf+ , module System.Libnotify.Types ) where -import Control.Exception (throw)-import Control.Monad.Reader (MonadIO, MonadReader, ReaderT, liftIO, runReaderT, ask)-import Data.Int (Int32)+import Control.Applicative ((<$>))+import Control.Monad.Reader (ReaderT, ask, runReaderT)+import Control.Monad.State (StateT, execStateT, get, put)+import Control.Monad.Trans (MonadIO, liftIO) import Data.Maybe (fromMaybe)-import Data.Word (Word8)-import qualified Data.ByteString as BS-import System.IO (stderr, hPutStrLn)+import Graphics.UI.Gtk.Gdk.Pixbuf (Pixbuf) +import System.Libnotify.Internal (Notification) import qualified System.Libnotify.Internal as N import System.Libnotify.Types --- | Notification session. Saves notification initial state.-data Session = Session- { notification :: N.Notification- , title :: Title- , body :: Body- , icon :: Icon- }+-- | Notification state. Contains next rendered notification data.+data NotifyState = NotifyState Title Body Icon +-- | Libnotify errors.+data NotifyError+ = NotifyInitHasFailed -- ^ notify_init() has failed.+ | NewCalledBeforeInit -- ^ 'new' has called before notify_init().+ deriving Show++-- | Notification monad. Saves notification context.+newtype Notify a = Notify { runNotify :: StateT NotifyState (ReaderT Notification IO) a } deriving (Functor, Monad, MonadIO)+ {-| Initializes and uninitializes libnotify API. Any notifications API calls should be wrapped into @withNotifications@, i.e. > main = withNotifications (Just "api-name") $ do { ... here are notification API calls ... } -}-withNotifications :: Maybe String -> IO a -> IO ()+withNotifications :: Maybe String -> IO a -> IO (Either NotifyError ()) withNotifications a x = (N.initNotify . fromMaybe " ") a >>= \initted -> if initted- then x >> N.uninitNotify- else throw NotifyInitHasFailed+ then Right <$> (x >> N.uninitNotify)+ else return $ Left NotifyInitHasFailed -- | Function for one-time notification with hints perhaps. Should be enough for a vast majority of applications.-oneShot :: Hint a => Title -> Body -> Icon -> [a] -> IO ()-oneShot t b i hs = withNotifications Nothing $- new t b i $- mapM_ addHint hs >> render+oneShot :: Title -> Body -> Icon -> Maybe [Hint] -> IO (Either NotifyError ())+oneShot t b i hs = withNotifications Nothing . new t b i $ mapM_ addHint (fromMaybe [] hs) >> render -- | Creates new notification session. Inside 'new' call one can manage current notification via 'update' or 'render' calls. -- Returns notification pointer. This could be useful if one wants to 'update' or 'close' the same notification after some time (see 'continue').-new :: Title -> Body -> Icon -> ReaderT Session IO t -> IO Session+new :: Title -> Body -> Icon -> Notify t -> IO (Either NotifyError (Notification, NotifyState)) new t b i f = N.isInitted >>= \initted -> if initted- then do n <- N.newNotify t (listToMaybeAll b) (listToMaybeAll i)- continue (Session n t b i) f- return (Session n t b i)- else throw NewCalledBeforeInit+ then do n <- N.newNotify t (listToMaybe b) (listToMaybe i)+ s <- continue (n, NotifyState t b i) f+ return $ Right (n, s)+ else return $ Left NewCalledBeforeInit -- | Continues old notification session.-continue :: Session -> ReaderT Session IO a -> IO ()-continue s f = runReaderT f s >> return ()+continue :: (Notification, NotifyState) -> Notify a -> IO NotifyState+continue (n, s) f = runReaderT (execStateT (runNotify f) s) n -- | Updates notification 'Title', 'Body' and 'Icon'. -- User can update notification partially, passing Nothing to arguments that should not changed.-update :: (MonadIO m, MonadReader Session m) => Maybe Title -> Maybe Body -> Maybe Icon -> m Bool-update nt nb ni = ask >>= \(Session n t b i) ->- liftIO $ N.updateNotify n- (fromMaybe t nt)- (listToMaybeAll (fromMaybe b nb))- (listToMaybeAll (fromMaybe i ni))+update :: Maybe Title -> Maybe Body -> Maybe Icon -> Notify Bool+update mt mb mi = Notify $+ do n <- ask+ NotifyState t b i <- get+ let nt = fromMaybe t mt+ nb = fromMaybe b mb+ ni = fromMaybe i mi+ put (NotifyState nt nb ni)+ liftIO $ N.updateNotify n nt (listToMaybe nb) (listToMaybe ni) -- | Shows notification to user.-render :: (MonadIO m, MonadReader Session m) => m Bool-render = ask >>= liftIO . N.showNotify . notification+render :: Notify Bool+render = Notify $ ask >>= liftIO . N.showNotify -- | Closes notification.-close :: (MonadIO m, MonadReader Session m) => m Bool-close = ask >>= liftIO . N.closeNotify . notification+close :: Notify Bool+close = Notify $ ask >>= liftIO . N.closeNotify -- | Sets notification 'Timeout'.-setTimeout :: (MonadIO m, MonadReader Session m) => Timeout -> m ()-setTimeout t = ask >>= liftIO . N.setTimeout t . notification+setTimeout :: Timeout -> Notify ()+setTimeout t = Notify $ ask >>= liftIO . N.setTimeout t -- | Sets notification 'Category'.-setCategory :: (MonadIO m, MonadReader Session m) => Category -> m ()-setCategory c = ask >>= liftIO . N.setCategory c . notification+setCategory :: Category -> Notify ()+setCategory c = Notify $ ask >>= liftIO . N.setCategory c -- | Sets notification 'Urgency'.-setUrgency :: (MonadIO m, MonadReader Session m) => Urgency -> m ()-setUrgency u = ask >>= liftIO . N.setUrgency u . notification---- | Instance of 'Hint' class. Useful for 'oneShot' calls with empty hint list.-data GeneralHint = HintInt String Int32 | HintDouble String Double | HintString String String | HintByte String Word8 | HintArray String BS.ByteString---- | Hint is some setting (server-dependent) which comes with notification.-class Hint a where- -- | Adds 'Hint' to notification.- addHint :: a -> (MonadIO m, MonadReader Session m) => m ()- -- | Generalizes 'Hint' to some type. Could be useful if one wants to pass list of distinct hints types.- generalize :: a -> GeneralHint--instance Hint GeneralHint where- addHint (HintInt k v) = addHint (k,v)- addHint (HintDouble k v) = addHint (k,v)- addHint (HintString k v) = addHint (k,v)- addHint (HintByte k v) = addHint (k,v)- addHint (HintArray k v) = addHint (k,v)- generalize = id--instance Hint (Key,Int32) where- addHint (k,v) = ask >>= \s -> liftIO $ N.setHintInt32 (notification s) k v- generalize (k,v) = HintInt k v--instance Hint (Key,Double) where- addHint (k,v) = ask >>= \s -> liftIO $ N.setHintDouble (notification s) k v- generalize (k,v) = HintDouble k v+setUrgency :: Urgency -> Notify ()+setUrgency u = Notify $ ask >>= liftIO . N.setUrgency u -instance Hint (Key,String) where- addHint (k,v) = ask >>= \s -> liftIO $ N.setHintString (notification s) k v- generalize (k,v) = HintString k v+-- | Sets notification icon from pixbuf+setIconFromPixbuf :: Pixbuf -> Notify ()+setIconFromPixbuf p = Notify $ ask >>= liftIO . N.setIconFromPixbuf p -instance Hint (Key,Word8) where- addHint (k,v) = ask >>= \s -> liftIO $ N.setHintByte (notification s) k v- generalize (k,v) = HintByte k v+-- | Sets notification image from pixbuf+setImageFromPixbuf :: Pixbuf -> Notify ()+setImageFromPixbuf p = Notify $ ask >>= liftIO . N.setImageFromPixbuf p -instance Hint (Key,BS.ByteString) where- addHint (k,v) = ask >>= \s -> liftIO $ N.setHintByteArray (notification s) k v- generalize (k,v) = HintArray k v+-- | Adds 'Hint' to notification.+addHint :: Hint -> Notify ()+addHint (HintInt k v) = Notify $ ask >>= liftIO . N.setHintInt32 k v+addHint (HintDouble k v) = Notify $ ask >>= liftIO . N.setHintDouble k v+addHint (HintString k v) = Notify $ ask >>= liftIO . N.setHintString k v+addHint (HintByte k v) = Notify $ ask >>= liftIO . N.setHintByte k v+addHint (HintArray k v) = Notify $ ask >>= liftIO . N.setHintByteArray k v -- | Removes hints from notification.-removeHints :: (MonadIO m, MonadReader Session m) => m ()-removeHints = ask >>= liftIO . N.clearHints . notification+removeHints :: Notify ()+removeHints = Notify $ ask >>= liftIO . N.clearHints -- | Adds action to notification.-addAction :: (MonadIO m, MonadReader Session m) => String -> String -> (N.Notification -> String -> IO ()) -> m ()-addAction a l c = ask >>= \s -> liftIO $ N.addAction (notification s) a l c+addAction :: String -> String -> (Notification -> String -> IO ()) -> Notify ()+addAction a l c = Notify $ ask >>= liftIO . N.addAction a l c -- | Removes actions from notification.-removeActions :: (MonadIO m, MonadReader Session m) => m ()-removeActions = ask >>= liftIO . N.clearActions . notification---- | Libnotify error handler-notifyErrorHandler :: NotifyError -> IO ()-notifyErrorHandler NotifyInitHasFailed = hPutStrLn stderr "withNotifications: init has failed."-notifyErrorHandler NewCalledBeforeInit = hPutStrLn stderr "new: Libnotify is not initialized properly."+removeActions :: Notify ()+removeActions = Notify $ ask >>= liftIO . N.clearActions -listToMaybeAll :: [a] -> Maybe [a]-listToMaybeAll [] = Nothing-listToMaybeAll xs = Just xs+listToMaybe :: [a] -> Maybe [a]+listToMaybe [] = Nothing+listToMaybe xs = Just xs
System/Libnotify/Internal.hsc view
@@ -15,11 +15,11 @@ , addAction, clearActions, closeNotify ) where +import Control.Exception (throw) import Foreign import Foreign.C import Graphics.UI.Gtk.Gdk.Pixbuf-import System.Glib.GError-import System.Glib.GList+import System.Glib.GError (GError) import Unsafe.Coerce import qualified Data.ByteString as BS @@ -85,9 +85,9 @@ p_error <- peek pp_error if p_error == nullPtr then return result- else do error <- peek p_error+ else do gerror <- peek p_error g_error_free p_error- throwGError error+ throw gerror foreign import ccall unsafe "libnotify/notify.h notify_notification_show" notify_notification_show :: Notification -> Ptr (Ptr GError) -> IO Bool@@ -125,8 +125,8 @@ foreign import ccall unsafe "libnotify/notify.h notify_notification_set_urgency" notify_notification_set_urgency :: Notification -> CInt -> IO () -setIconFromPixbuf :: Notification -> Pixbuf -> IO ()-setIconFromPixbuf notify pixbuf =+setIconFromPixbuf :: Pixbuf -> Notification -> IO ()+setIconFromPixbuf pixbuf notify = withForeignPtr (unsafeCoerce pixbuf) $ \p_pixbuf -> notify_notification_set_icon_from_pixbuf notify p_pixbuf @@ -135,8 +135,8 @@ -> Ptr Pixbuf -> IO () -setImageFromPixbuf :: Notification -> Pixbuf -> IO ()-setImageFromPixbuf notify pixbuf =+setImageFromPixbuf :: Pixbuf -> Notification -> IO ()+setImageFromPixbuf pixbuf notify = withForeignPtr (unsafeCoerce pixbuf) $ \p_pixbuf -> notify_notification_set_image_from_pixbuf notify p_pixbuf @@ -145,8 +145,8 @@ -> Ptr Pixbuf -> IO () -setHintInt32 :: Notification -> String -> Int32 -> IO ()-setHintInt32 notify key value =+setHintInt32 :: String -> Int32 -> Notification -> IO ()+setHintInt32 key value notify = withCString key $ \p_key -> notify_notification_set_hint_int32 notify p_key (fromIntegral value) @@ -156,8 +156,8 @@ -> CInt -> IO () -setHintDouble :: Notification -> String -> Double -> IO ()-setHintDouble notify key value =+setHintDouble :: String -> Double -> Notification -> IO ()+setHintDouble key value notify = withCString key $ \p_key -> notify_notification_set_hint_double notify p_key (realToFrac value) @@ -167,8 +167,8 @@ -> CDouble -> IO () -setHintString :: Notification -> String -> String -> IO ()-setHintString notify key value =+setHintString :: String -> String -> Notification -> IO ()+setHintString key value notify = withCString key $ \p_key -> withCString value $ \p_value -> notify_notification_set_hint_string notify p_key p_value@@ -179,8 +179,8 @@ -> CString -> IO () -setHintByte :: Notification -> String -> Word8 -> IO ()-setHintByte notify key value =+setHintByte :: String -> Word8 -> Notification -> IO ()+setHintByte key value notify = withCString key $ \p_key -> notify_notification_set_hint_byte notify p_key (fromIntegral value) @@ -190,8 +190,8 @@ -> CUChar -> IO () -setHintByteArray :: Notification -> String -> BS.ByteString -> IO ()-setHintByteArray notify key value =+setHintByteArray :: String -> BS.ByteString -> Notification -> IO ()+setHintByteArray key value notify = withCString key $ \p_key -> withArrayLen (BS.foldr' step [] value) $ \len p_bs -> notify_notification_set_hint_byte_array notify p_key p_bs (fromIntegral len)@@ -212,12 +212,12 @@ notify_notification_clear_hints :: Notification -> IO () addAction- :: Notification- -> String+ :: String -> String -> (Notification -> String -> IO ())+ -> Notification -> IO ()-addAction notify action label callback =+addAction action label callback notify = withCString action $ \p_action -> withCString label $ \p_label -> do p_callback <- wrapActionCallback $ makeCallback callback@@ -261,9 +261,9 @@ p_error <- peek pp_error if p_error == nullPtr then return result- else do error <- peek p_error+ else do gerror <- peek p_error g_error_free p_error- throwGError error+ throw gerror foreign import ccall unsafe "libnotify/notify.h notify_notification_close" notify_notification_close :: Notification -> Ptr (Ptr GError) -> IO Bool
+ System/Libnotify/Types.hs view
@@ -0,0 +1,53 @@+-- | System.Libnotify.Types module is a collection of types is used in other modules.+-- This is reexported with System.Libnotify module. Perhaps it'll never be needed to import explicitly.+{-# OPTIONS_HADDOCK prune #-}++module System.Libnotify.Types+ ( Timeout(..), Urgency(..), Category+ , Title, Body, Icon+ , ServerInfo(..)+ , Hint(..)+ ) where++import qualified Data.ByteString as BS+import Data.Int (Int32)+import Data.Word (Word8)++-- | Urgency can be used by the notification server to prioritize notifications.+-- Although urgency does not work with notify-osd.+data Urgency+ = Low -- ^ Low priority notification.+ | Normal -- ^ Default notification urgency.+ | Critical -- ^ Critical notification that requires immediate attention.++-- | Timeout in seconds after which notification is closed.+-- Although timeout does not work with notify-osd.+data Timeout+ = Default -- ^ Default server timeout.+ | Custom Int -- ^ User defined timeout (in milliseconds).+ | Infinite -- ^ Notification will not expire until user pays attention to it.++-- | Category can be used by the notification server to filter or display the data in a certain way.+type Category = String++-- | Type synonim for notification title.+type Title = String+-- | Type synonim for notification body.+type Body = String+-- | Type synonim for notification icon.+type Icon = String++-- | Server information.+data ServerInfo = ServerInfo+ { serverName :: String+ , serverVendor :: String+ , serverVersion :: String+ , serverSpecVersion :: String+ } deriving Show++-- | Hint is some setting (server-dependent) which comes with notification.+data Hint = HintInt String Int32+ | HintDouble String Double+ | HintString String String+ | HintByte String Word8+ | HintArray String BS.ByteString
− System/Libnotify/Types.hsc
@@ -1,55 +0,0 @@-{-# LANGUAGE ForeignFunctionInterface, DeriveDataTypeable #-}--- | System.Libnotify.Types module is a collection of types is used in other modules.--- This is reexported with System.Libnotify module. Perhaps it'll never be needed to import explicitly.-{-# OPTIONS_HADDOCK prune #-}--#include <libnotify/notify.h>--module System.Libnotify.Types- ( Timeout(..), Urgency(..), Category- , Title, Body, Icon- , Key- , ServerInfo(..)- , NotifyError(..)- ) where--import Control.Exception (Exception)-import Data.Typeable (Typeable)-import Foreign.C---- | Urgency can be used by the notification server to prioritize notifications.--- Although urgency does not work with notify-osd.-data Urgency = Low | Normal | Critical---- | Timeout in seconds after which notification is closed.--- Although timeout does not work with notify-osd.-data Timeout = Default | Custom Int | Infinite---- | Category can be used by the notification server to filter or display the data in a certain way.-type Category = String---- | Type synonim for notification title.-type Title = String--- | Type synonim for notification body.-type Body = String--- | Type synonim for notification icon.-type Icon = String---- | Type synonym for 'Hint' key type.-type Key = String---- | Server information.-data ServerInfo = ServerInfo- { serverName :: String- , serverVendor :: String- , serverVersion :: String- , serverSpecVersion :: String- } deriving Show---- | Libnotify errors.-data NotifyError- = NotifyInitHasFailed -- ^ notify_init() has failed.- | NewCalledBeforeInit -- ^ 'new' has called before notify_init().- deriving (Show, Typeable)--instance Exception NotifyError
libnotify.cabal view
@@ -1,20 +1,20 @@-Name: libnotify-Version: 0.0.1.2-Description: Usable binding to libnotify library.-License: MIT-License-file: LICENSE-Author: Emon Tsukimiya, Matvey Aksenov-Maintainer: Matvey Aksenov <matvey.aksenov@gmail.com>-Category: System, Desktop-Synopsis: Haskell binding for Libnotify-Cabal-Version: >= 1.6-Build-Type: Simple+Name: libnotify+Version: 0.0.2.0+Description: Usable binding to libnotify library.+License: MIT+License-file: LICENSE+Author: Emon Tsukimiya, Matvey Aksenov+Maintainer: Matvey Aksenov <matvey.aksenov@gmail.com>+Category: System, Desktop+Synopsis: Haskell binding for Libnotify+Cabal-Version: >= 1.6+Build-Type: Simple Library- Build-Depends: base >= 3 && < 5, bytestring, glib, gtk, mtl- Exposed-Modules: System.Libnotify, System.Libnotify.Internal, System.Libnotify.Server, System.Libnotify.Types- Pkgconfig-Depends: libnotify- Extensions: DeriveDataTypeable, FlexibleInstances, FlexibleContexts+ Build-Depends: base >= 3 && < 5, bytestring, glib, gtk, mtl+ Exposed-Modules: System.Libnotify, System.Libnotify.Internal, System.Libnotify.Server, System.Libnotify.Types+ Pkgconfig-Depends: libnotify+ GHC-options: -Wall source-repository head type: git@@ -23,4 +23,4 @@ source-repository this type: git location: https://github.com/supki/haskell-libnotify- tag: v0.0.1.2+ tag: v0.0.2.0