packages feed

status-notifier-item 0.2.1.0 → 0.2.2.0

raw patch · 9 files changed

+173/−148 lines, 9 filesdep +dbus-hsloggerPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: dbus-hslogger

API changes (from Hackage documentation)

- StatusNotifier.Item.Client: printItemClient :: IO ()
- StatusNotifier.Item.Client: printItemSignals :: IO ()
- StatusNotifier.Item.Constants: defaultPath :: ObjectPath
- StatusNotifier.Item.Constants: generationParams :: GenerationParams
- StatusNotifier.Item.Constants: introspectionInterface :: Interface
- StatusNotifier.Item.Constants: introspectionObject :: Object
- StatusNotifier.Util: defaultHandler :: GenericHandler Handle
- StatusNotifier.Util: getXMLDataFile :: String -> IO FilePath
- StatusNotifier.Util: makeDefaultLogger :: String -> Logger
- StatusNotifier.Watcher.Constants: [watcherLogger] :: WatcherParams -> Logger
+ StatusNotifier.Host.Service: [forceUpdate] :: Host -> BusName -> IO ()
+ StatusNotifier.Item.Client: defaultPath :: ObjectPath
+ StatusNotifier.Util: generateClientFromFile :: GenerationParams -> Bool -> FilePath -> Q [Dec]
+ StatusNotifier.Util: getIntrospectionObjectFromFile :: FilePath -> ObjectPath -> Q Object
- StatusNotifier.Host.Service: Host :: IO (Map BusName ItemInfo) -> (UpdateHandler -> IO Unique) -> (Unique -> IO ()) -> Host
+ StatusNotifier.Host.Service: Host :: IO (Map BusName ItemInfo) -> (UpdateHandler -> IO Unique) -> (Unique -> IO ()) -> (BusName -> IO ()) -> Host
- StatusNotifier.Util: getInterfaceAt :: Client -> BusName -> ObjectPath -> IO Either MethodError Maybe Object
+ StatusNotifier.Util: getInterfaceAt :: Client -> BusName -> ObjectPath -> IO (Either MethodError (Maybe Object))
- StatusNotifier.Watcher.Constants: WatcherParams :: String -> String -> Logger -> IO () -> Maybe Client -> WatcherParams
+ StatusNotifier.Watcher.Constants: WatcherParams :: String -> String -> IO () -> Maybe Client -> WatcherParams

Files

src/StatusNotifier/Host/Service.hs view
@@ -31,7 +31,6 @@ import           Text.Printf  import qualified StatusNotifier.Item.Client as I-import qualified StatusNotifier.Item.Constants as I import           StatusNotifier.Util import qualified StatusNotifier.Watcher.Client as W import qualified StatusNotifier.Watcher.Constants as W@@ -106,6 +105,7 @@   { itemInfoMap :: IO (Map.Map BusName ItemInfo)   , addUpdateHandler :: UpdateHandler -> IO Unique   , removeUpdateHandler :: Unique -> IO ()+  , forceUpdate :: BusName -> IO ()   } deriving Typeable  build :: Params -> IO (Maybe Host)@@ -184,7 +184,7 @@               clientSignalRegister signalRegisterFn handler =                 signalRegisterFn client matchAny handler logUnableToCallSignal -      handleItemAdded _ serviceName =+      handleItemAdded serviceName =         modifyMVar_ itemInfoMapVar $ \itemInfoMap ->           buildItemInfo serviceName >>=                         either (logErrorAndThen $ return itemInfoMap)@@ -196,13 +196,13 @@         maybe I.defaultPath itemServicePath . Map.lookup name <$>         readMVar itemInfoMapVar -      handleItemRemoved _ serviceName = let busName = busName_ serviceName in+      handleItemRemoved serviceName = let busName = busName_ serviceName in         modifyMVar_ itemInfoMapVar (return . Map.delete busName ) >>         doUpdate ItemRemoved defaultItemInfo { itemServiceName = busName }        watcherRegistrationPairs =-        [ (W.registerForStatusNotifierItemRegistered, handleItemAdded)-        , (W.registerForStatusNotifierItemUnregistered, handleItemRemoved)+        [ (W.registerForStatusNotifierItemRegistered, const handleItemAdded)+        , (W.registerForStatusNotifierItemUnregistered, const handleItemRemoved)         ]        getSender fn s@M.Signal { M.signalSender = Just sender} =@@ -289,9 +289,9 @@       { itemInfoMap = readMVar itemInfoMapVar       , addUpdateHandler = addHandler       , removeUpdateHandler = removeHandler+      , forceUpdate = handleItemAdded . coerce       }     else Nothing   else do     logErrorWithMessage "Failed to obtain desired service name" nameRequestResult     return Nothing-
src/StatusNotifier/Item/Client.hs view
@@ -1,17 +1,17 @@ {-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE OverloadedStrings #-} module StatusNotifier.Item.Client where  import DBus.Generation-import StatusNotifier.Item.Constants as C-import Language.Haskell.TH--generateClient C.generationParams C.introspectionInterface-generateSignalsFromInterface C.generationParams C.introspectionInterface+import DBus.Internal.Types+import StatusNotifier.Util+import System.FilePath -printItemClient =-  runQ (generateClient C.generationParams C.introspectionInterface) >>=-       putStrLn . pprint+generateClientFromFile+  defaultGenerationParams+  { genTakeSignalErrorHandler = True }+  False+  ("xml" </> "StatusNotifierItem.xml") -printItemSignals =-  runQ (generateSignalsFromInterface C.generationParams C.introspectionInterface) >>=-       putStrLn . pprint+defaultPath :: ObjectPath+defaultPath = "/StatusNotifierItem"
− src/StatusNotifier/Item/Constants.hs
@@ -1,26 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-module StatusNotifier.Item.Constants where--import DBus.Generation-import DBus.Introspection-import DBus.Internal.Types-import Data.Maybe-import Language.Haskell.TH-import System.IO.Unsafe--import StatusNotifier.Util--{-# NOINLINE introspectionObject #-}-introspectionObject = unsafePerformIO $-  head . maybeToList . parseXML "/" <$>-  readFile "xml/StatusNotifierItem.xml"--introspectionInterface =-  head $ objectInterfaces introspectionObject--defaultPath :: ObjectPath-defaultPath = objectPath introspectionObject--generationParams =-  defaultGenerationParams-  { genTakeSignalErrorHandler = True }
src/StatusNotifier/Util.hs view
@@ -7,26 +7,40 @@ import qualified DBus.Internal.Message as M import qualified DBus.Internal.Types as T import qualified DBus.Introspection as I+import qualified DBus.Generation as G import qualified Data.ByteString as BS+import           Data.Maybe import qualified Data.Vector.Storable as VS import           Data.Vector.Storable.ByteString import           Language.Haskell.TH import           Network.Socket (ntohl)-import           Paths_status_notifier_item ( getDataDir ) import           StatusNotifier.TH-import           System.FilePath import           System.IO import           System.IO.Unsafe import           System.Log.Handler.Simple import           System.Log.Logger -getXMLDataFile :: String -> IO FilePath-getXMLDataFile filename = (</> filename) . (</> "xml") <$> getDataDir+getIntrospectionObjectFromFile :: FilePath -> T.ObjectPath -> Q I.Object+getIntrospectionObjectFromFile filepath nodePath = runIO $+  head . maybeToList . I.parseXML nodePath <$> readFile filepath +generateClientFromFile :: G.GenerationParams -> Bool -> FilePath -> Q [Dec]+generateClientFromFile params useObjectPath filepath = do+  object <- getIntrospectionObjectFromFile filepath "/"+  let interface = head $ I.objectInterfaces object+      actualObjectPath = I.objectPath object+      realParams =+        if useObjectPath+        then params { G.genObjectPath = Just actualObjectPath }+        else params+  (++) <$> G.generateClient realParams interface <*>+           G.generateSignalsFromInterface realParams interface+ ifM :: Monad m => m Bool -> m a -> m a -> m a ifM cond whenTrue whenFalse =   cond >>= (\bool -> if bool then whenTrue else whenFalse) +makeLensesWithLSuffix :: Name -> DecsQ makeLensesWithLSuffix =   makeLensesWith $   lensRules & lensField .~ \_ _ name ->@@ -45,15 +59,6 @@ makeErrorReply :: ErrorName -> String -> Reply makeErrorReply e message = ReplyError e [T.toVariant message] -{-# NOINLINE defaultHandler #-}-defaultHandler :: GenericHandler Handle-defaultHandler = unsafePerformIO $ streamHandler stdout INFO--{-# NOINLINE makeDefaultLogger #-}-makeDefaultLogger :: String -> Logger-makeDefaultLogger name =-  unsafePerformIO $ getLogger name- logErrorWithDefault ::   Show a => Logger -> b -> String -> Either a b -> IO b logErrorWithDefault logger def message =@@ -97,5 +102,10 @@ (>>=/) :: Monad m => m a -> (a -> m b) -> m a (>>=/) a = (a >>=) . tee return +getInterfaceAt+  :: Client+  -> T.BusName+  -> T.ObjectPath+  -> IO (Either M.MethodError (Maybe I.Object)) getInterfaceAt client bus path =   right (I.parseXML "/") <$> introspect client bus path
src/StatusNotifier/Watcher/Constants.hs view
@@ -27,7 +27,6 @@ data WatcherParams = WatcherParams   { watcherNamespace :: String   , watcherPath :: String-  , watcherLogger :: Logger   , watcherStop :: IO ()   , watcherDBusClient :: Maybe Client   }@@ -36,7 +35,6 @@ defaultWatcherParams =   WatcherParams   { watcherNamespace = "org.kde"-  , watcherLogger = makeDefaultLogger "StatusNotifier.Watcher.Service"   , watcherStop = return ()   , watcherPath = "/StatusNotifierWatcher"   , watcherDBusClient = Nothing
src/StatusNotifier/Watcher/Service.hs view
@@ -20,6 +20,7 @@ import           Data.Maybe import           Data.Monoid import           Data.String+import qualified StatusNotifier.Item.Client as Item import           StatusNotifier.Util import           StatusNotifier.Watcher.Constants import           StatusNotifier.Watcher.Signals@@ -29,14 +30,14 @@  buildWatcher WatcherParams                { watcherNamespace = interfaceNamespace-               , watcherLogger = logger                , watcherStop = stopWatcher                , watcherPath = path                , watcherDBusClient = mclient                } = do   let watcherInterfaceName = getWatcherInterfaceName interfaceNamespace-      log = logL logger INFO-      logError = logL logger ERROR+      logNamespace = "StatusNotifier.Watcher.Service"+      log = logM logNamespace  INFO+      logError = logM logNamespace ERROR       mkLogCb cb msg = lift (log (show msg)) >> cb msg       mkLogMethod method = method { methodHandler = mkLogCb $ methodHandler method }       mkLogProperty name fn =@@ -50,13 +51,15 @@   let itemIsRegistered item items =         isJust $ find (== item) items -      registerStatusNotifierItem MethodCall { methodCallSender = sender } name = runExceptT $ do+      registerStatusNotifierItem MethodCall+                                   { methodCallSender = sender }+                                 name = runExceptT $ do         let maybeBusName = getFirst $ mconcat $                            map First [T.parseBusName name, sender]             parseServiceError = makeErrorReply errorInvalidParameters $               printf "the provided service %s could not be parsed \                      \as a bus name or an object path." name-            path = fromMaybe "/StatusNotifierItem"  $ T.parseObjectPath name+            path = fromMaybe Item.defaultPath $ T.parseObjectPath name             remapErrorName =               left $ (`makeErrorReply` "Failed to verify ownership.") .                    M.methodErrorName@@ -64,7 +67,8 @@         let item = ItemEntry { serviceName = busName                              , servicePath = path                              }-        hasOwner <- ExceptT $ remapErrorName <$> DBusTH.nameHasOwner client (coerce busName)+        hasOwner <- ExceptT $ remapErrorName <$>+                    DBusTH.nameHasOwner client (coerce busName)         lift $ modifyMVar_ notifierItems $ \currentItems ->           if itemIsRegistered item currentItems           then@@ -125,17 +129,25 @@           return ()        watcherMethods = map mkLogMethod-        [ autoMethodWithMsg "RegisterStatusNotifierItem" registerStatusNotifierItem-        , autoMethod "RegisterStatusNotifierHost" registerStatusNotifierHost-        , autoMethod "StopWatcher" stopWatcher-        , autoMethod "GetObjectPathForItemName" objectPathForItem+        [ autoMethodWithMsg "RegisterStatusNotifierItem"+          registerStatusNotifierItem+        , autoMethod "RegisterStatusNotifierHost"+          registerStatusNotifierHost+        , autoMethod "StopWatcher"+          stopWatcher+        , autoMethod "GetObjectPathForItemName"+          objectPathForItem         ]        watcherProperties =-        [ mkLogProperty "RegisteredStatusNotifierItems" registeredStatusNotifierItems-        , mkLogProperty "RegisteredSNIEntries" registeredSNIEntries-        , mkLogProperty "IsStatusNotifierHostRegistered" isStatusNotifierHostRegistered-        , mkLogProperty "ProtocolVersion" protocolVersion+        [ mkLogProperty "RegisteredStatusNotifierItems"+          registeredStatusNotifierItems+        , mkLogProperty "RegisteredSNIEntries"+          registeredSNIEntries+        , mkLogProperty "IsStatusNotifierHostRegistered"+          isStatusNotifierHostRegistered+        , mkLogProperty "ProtocolVersion"+          protocolVersion         ]        watcherInterface =@@ -151,7 +163,8 @@         case nameRequestResult of           NamePrimaryOwner ->             do-              _ <- DBusTH.registerForNameOwnerChanged client matchAny handleNameOwnerChanged+              _ <- DBusTH.registerForNameOwnerChanged client+                   matchAny handleNameOwnerChanged               export client (fromString path) watcherInterface           _ -> stopWatcher         return nameRequestResult@@ -163,5 +176,6 @@ -- IO isn't needed to build watcher {-# NOINLINE watcherInterface #-} watcherInterface = buildIntrospectionInterface clientInterface-  where (clientInterface, _) = unsafePerformIO $ buildWatcher-                               defaultWatcherParams { watcherDBusClient = Just undefined }+  where (clientInterface, _) =+          unsafePerformIO $ buildWatcher+          defaultWatcherParams { watcherDBusClient = Just undefined }
status-notifier-item.cabal view
@@ -2,10 +2,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: feda98a88b3e5480785430699b26288a4655a16b299f61f763431c4193ea54b4+-- hash: fab14775734399bef953c7eccd528496b0abd4ae265b3f999bf78e2ee151b2b4  name:           status-notifier-item-version:        0.2.1.0+version:        0.2.2.0 synopsis:       A wrapper over the StatusNotifierItem/libappindicator dbus specification description:    Please see the README on Github at <https://github.com/IvanMalison/status-notifier-item#readme> category:       Desktop@@ -31,7 +31,6 @@   exposed-modules:       StatusNotifier.Host.Service       StatusNotifier.Item.Client-      StatusNotifier.Item.Constants       StatusNotifier.TH       StatusNotifier.Util       StatusNotifier.Watcher.Client@@ -80,6 +79,7 @@   build-depends:       base >=4.7 && <5     , dbus >=1.0.0 && <2.0.0+    , dbus-hslogger >=0.1.0.1 && <0.2.0.0     , hslogger     , optparse-applicative     , status-notifier-item
watcher/Main.hs view
@@ -1,39 +1,68 @@ module Main where  import Control.Concurrent.MVar+import Control.Monad+import DBus.Client import Data.Semigroup ((<>))+import Data.Version (showVersion) import Options.Applicative import StatusNotifier.Watcher.Constants import StatusNotifier.Watcher.Service+import System.Log.DBus.Server import System.Log.Logger+import Text.Printf -setWatcherParams namespace path =-  defaultWatcherParams-  { watcherNamespace = namespace-  , watcherPath = path-  }+import Paths_status_notifier_item (version) -watcherParamsParser :: Parser WatcherParams-watcherParamsParser = setWatcherParams+getWatcherParams :: String -> String -> Priority -> IO WatcherParams+getWatcherParams namespace path priority = do+  logger <- getLogger "StatusNotifier"+  saveGlobalLogger $ setLevel priority logger+  client <- connectSession+  startLogServer client+  return $+    defaultWatcherParams+    { watcherNamespace = namespace+    , watcherPath = path+    , watcherDBusClient = Just client+    }++watcherParamsParser :: Parser (IO WatcherParams)+watcherParamsParser = getWatcherParams   <$> strOption   (  long "namespace"   <> short 'n'   <> metavar "NAMESPACE"   <> value "org.kde"-  <> help "The namespace the watcher should register at.")-  <*> strOption+  <> help "The namespace the watcher should register at."+  ) <*> strOption   (  long "path"   <> short 'p'   <> metavar "DBUS-PATH"   <> value "/StatusNotifierWatcher"-  <> help "The path at which to run the watcher." )+  <> help "The path at which to run the watcher."+  ) <*> option auto+  (  long "log-level"+  <> short 'l'+  <> help "Set the log level"+  <> metavar "LEVEL"+  <> value WARNING+  ) +versionOption :: Parser (a -> a)+versionOption = infoOption+                (printf "status-notifier-watcher %s" $ showVersion version)+                (  long "version"+                <> help "Show the version number of gtk-sni-tray"+                )++main :: IO () main = do-  watcherParams <- execParser $-                   info (watcherParamsParser <**> helper)+  watcherParams <- join $ execParser $+                   info (helper <*> versionOption <*> watcherParamsParser)                    (  fullDesc                    <> progDesc "Run a StatusNotifierWatcher")   stop <- newEmptyMVar   (_, startWatcher) <- buildWatcher watcherParams { watcherStop = putMVar stop () }-  startWatcher+  _ <- startWatcher   takeMVar stop
xml/StatusNotifierItem.xml view
@@ -1,68 +1,68 @@ <node name="/StatusNotifierItem">-    <interface name="org.kde.StatusNotifierItem">-        <property name="Category" type="s" access="read"/>-        <property name="Id" type="s" access="read"/>-        <property name="Title" type="s" access="read"/>-        <property name="Status" type="s" access="read"/>-        <property name="WindowId" type="i" access="read"/>-        <property name="Menu" type="o" access="read" />+  <interface name="org.kde.StatusNotifierItem">+    <property name="Category" type="s" access="read"/>+    <property name="Id" type="s" access="read"/>+    <property name="Title" type="s" access="read"/>+    <property name="Status" type="s" access="read"/>+    <property name="WindowId" type="i" access="read"/>+    <property name="Menu" type="o" access="read" /> -        <!-- main icon -->-        <!-- names are preferred over pixmaps -->-        <property name="IconName" type="s" access="read" />-        <property name="IconThemePath" type="s" access="read" />+    <!-- main icon -->+    <!-- names are preferred over pixmaps -->+    <property name="IconName" type="s" access="read" />+    <property name="IconThemePath" type="s" access="read" /> -        <!-- struct containing width, height and image data-->-        <!-- implementation has been dropped as of now -->-        <property name="IconPixmap" type="a(iiay)" access="read" />+    <!-- struct containing width, height and image data-->+    <!-- implementation has been dropped as of now -->+    <property name="IconPixmap" type="a(iiay)" access="read" /> -        <!-- not used in ayatana code, no test case so far -->-        <property name="OverlayIconName" type="s" access="read"/>-        <property name="OverlayIconPixmap" type="a(iiay)" access="read" />+    <!-- not used in ayatana code, no test case so far -->+    <property name="OverlayIconName" type="s" access="read"/>+    <property name="OverlayIconPixmap" type="a(iiay)" access="read" /> -        <!-- Requesting attention icon -->-        <property name="AttentionIconName" type="s" access="read"/>+    <!-- Requesting attention icon -->+    <property name="AttentionIconName" type="s" access="read"/> -        <!--same definition as image-->-        <property name="AttentionIconPixmap" type="a(iiay)" access="read" />+    <!--same definition as image-->+    <property name="AttentionIconPixmap" type="a(iiay)" access="read" /> -        <!-- tooltip data -->-        <!--(iiay) is an image-->-        <property name="ToolTip" type="(sa(iiay)ss)" access="read" />+    <!-- tooltip data -->+    <!--(iiay) is an image-->+    <property name="ToolTip" type="(sa(iiay)ss)" access="read" /> -        <!-- interaction: actually, we do not use them. -->-        <method name="Activate">-            <arg name="x" type="i" direction="in"/>-            <arg name="y" type="i" direction="in"/>-        </method>-        <method name="SecondaryActivate">-            <arg name="x" type="i" direction="in"/>-            <arg name="y" type="i" direction="in"/>-        </method>-        <method name="Scroll">-            <arg name="delta" type="i" direction="in"/>-            <arg name="dir"   type="s" direction="in"/>-        </method>+    <!-- interaction: actually, we do not use them. -->+    <method name="Activate">+      <arg name="x" type="i" direction="in"/>+      <arg name="y" type="i" direction="in"/>+    </method>+    <method name="SecondaryActivate">+      <arg name="x" type="i" direction="in"/>+      <arg name="y" type="i" direction="in"/>+    </method>+    <method name="Scroll">+      <arg name="delta" type="i" direction="in"/>+      <arg name="dir"   type="s" direction="in"/>+    </method> -        <!-- Signals: the client wants to change something in the status-->-        <signal name="NewTitle"></signal>-        <signal name="NewIcon"></signal>-        <signal name="NewIconThemePath">-            <arg type="s" name="icon_theme_path" direction="out" />-        </signal>-        <signal name="NewAttentionIcon"></signal>-        <signal name="NewOverlayIcon"></signal>-        <signal name="NewToolTip"></signal>-        <signal name="NewStatus">-            <arg name="status" type="s" />-        </signal>+    <!-- Signals: the client wants to change something in the status-->+    <signal name="NewTitle"></signal>+    <signal name="NewIcon"></signal>+    <signal name="NewIconThemePath">+      <arg type="s" name="icon_theme_path" direction="out" />+    </signal>+    <signal name="NewAttentionIcon"></signal>+    <signal name="NewOverlayIcon"></signal>+    <signal name="NewToolTip"></signal>+    <signal name="NewStatus">+      <arg name="status" type="s" />+    </signal> -        <!-- ayatana labels -->-        <signal name="XAyatanaNewLabel">-            <arg type="s" name="label" direction="out" />-            <arg type="s" name="guide" direction="out" />-        </signal>-        <property name="XAyatanaLabel" type="s" access="read" />-        <property name="XAyatanaLabelGuide" type="s" access="read" />-    </interface>+    <!-- ayatana labels -->+    <signal name="XAyatanaNewLabel">+      <arg type="s" name="label" direction="out" />+      <arg type="s" name="guide" direction="out" />+    </signal>+    <property name="XAyatanaLabel" type="s" access="read" />+    <property name="XAyatanaLabelGuide" type="s" access="read" />+  </interface> </node>