packages feed

status-notifier-item 0.3.2.8 → 0.3.2.9

raw patch · 4 files changed

+75/−12 lines, 4 filesdep ~optparse-applicativedep ~template-haskellPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: optparse-applicative, template-haskell

API changes (from Hackage documentation)

- StatusNotifier.Host.Service: instance GHC.Show.Show StatusNotifier.Host.Service.ItemInfo
- StatusNotifier.Host.Service: instance GHC.Show.Show StatusNotifier.Host.Service.UpdateType
- StatusNotifier.Item.Service: instance GHC.Read.Read StatusNotifier.Item.Service.ItemParams
- StatusNotifier.Item.Service: instance GHC.Show.Show StatusNotifier.Item.Service.ItemParams
- StatusNotifier.Watcher.Constants: instance GHC.Show.Show StatusNotifier.Watcher.Constants.ItemEntry
- StatusNotifier.Watcher.StateCache: instance GHC.Show.Show StatusNotifier.Watcher.StateCache.JsonValue
- StatusNotifier.Watcher.StateCache: instance GHC.Show.Show StatusNotifier.Watcher.StateCache.PersistedItemEntry
- StatusNotifier.Watcher.StateCache: instance GHC.Show.Show StatusNotifier.Watcher.StateCache.PersistedWatcherState
+ StatusNotifier.Host.Service: instance GHC.Internal.Show.Show StatusNotifier.Host.Service.ItemInfo
+ StatusNotifier.Host.Service: instance GHC.Internal.Show.Show StatusNotifier.Host.Service.UpdateType
+ StatusNotifier.Item.Service: instance GHC.Internal.Read.Read StatusNotifier.Item.Service.ItemParams
+ StatusNotifier.Item.Service: instance GHC.Internal.Show.Show StatusNotifier.Item.Service.ItemParams
+ StatusNotifier.Watcher.Constants: instance GHC.Internal.Show.Show StatusNotifier.Watcher.Constants.ItemEntry
+ StatusNotifier.Watcher.StateCache: instance GHC.Internal.Show.Show StatusNotifier.Watcher.StateCache.JsonValue
+ StatusNotifier.Watcher.StateCache: instance GHC.Internal.Show.Show StatusNotifier.Watcher.StateCache.PersistedItemEntry
+ StatusNotifier.Watcher.StateCache: instance GHC.Internal.Show.Show StatusNotifier.Watcher.StateCache.PersistedWatcherState

Files

ChangeLog.md view
@@ -1,7 +1,11 @@ # Changelog for status-notifier-item -## 0.3.2.8 - 2026-02-13-- Relax dependency bounds for GHC 9.12 (`template-haskell`, `optparse-applicative`).+## 0.3.2.9 - 2026-02-17+- Host: eliminate duplicate `ItemAdded` deliveries to newly-registered update+  handlers by making handler registration + initial replay atomic with respect+  to item map updates.+- Add a deterministic host integration test that reproduces and guards against+  duplicate `ItemAdded` events from replay/live-update races.  ## 0.3.2.7 - 2026-02-13 - Watcher: default `--log-level` is now INFO.
src/StatusNotifier/Host/Service.hs view
@@ -158,9 +158,13 @@        addHandler handler = do         unique <- newUnique-        modifyMVar_ updateHandlersVar (return . ((unique, handler):))-        let doUpdateForInfo info = doUpdateForHandler ItemAdded info (unique, handler)-        readMVar itemInfoMapVar >>= mapM_ doUpdateForInfo+        modifyMVar_ itemInfoMapVar $ \itemInfoMap -> do+          -- Register and replay under the item map lock so a concurrent add+          -- cannot be delivered both live and via replay.+          modifyMVar_ updateHandlersVar (return . ((unique, handler):))+          let doUpdateForInfo info = doUpdateForHandler ItemAdded info (unique, handler)+          mapM_ doUpdateForInfo itemInfoMap+          return itemInfoMap         return unique        removeHandler unique =
status-notifier-item.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack  name:           status-notifier-item-version:        0.3.2.8+version:        0.3.2.9 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@@ -53,7 +53,7 @@     , filepath <1.6     , hslogger <1.4     , lens <5.4-    , template-haskell <2.24+    , template-haskell <2.23     , text <2.2     , transformers <0.7     , vector <0.14@@ -68,7 +68,7 @@   build-depends:       base >=4.7 && <5     , dbus >=1.2.1 && <2-    , optparse-applicative <0.20+    , optparse-applicative <0.19     , status-notifier-item   default-language: Haskell2010 @@ -80,7 +80,7 @@       ./item   build-depends:       base >=4.7 && <5-    , optparse-applicative <0.20+    , optparse-applicative <0.19     , status-notifier-item   default-language: Haskell2010 @@ -95,7 +95,7 @@     , dbus >=1.2.1 && <2     , dbus-hslogger >=0.1.0.1 && <0.2     , hslogger <1.4-    , optparse-applicative <0.20+    , optparse-applicative <0.19     , status-notifier-item   default-language: Haskell2010 
test/HostSpec.hs view
@@ -2,9 +2,19 @@  module HostSpec (spec) where -import Control.Concurrent (newChan, readChan, writeChan)+import Control.Concurrent+  ( forkIO+  , newChan+  , newEmptyMVar+  , putMVar+  , readChan+  , takeMVar+  , threadDelay+  , tryPutMVar+  , writeChan+  ) import Control.Exception (finally)-import Control.Monad (replicateM)+import Control.Monad (replicateM, void) import Data.List (sort) import qualified Data.Map.Strict as Map import DBus (busName_, objectPath_)@@ -218,6 +228,51 @@           current <- itemInfoMap host           pure $ not $ Map.member (busName_ "org.test.HostWatcherOwnerChange") current       removed `shouldBe` True++    it "does not emit duplicate ItemAdded when addUpdateHandler races with replay" $ \() -> do+      _watcher <- startWatcher+      hostClient <- connectSession+      Just host <- build defaultParams {dbusClient = Just hostClient, uniqueIdentifier = "host-j"}++      itemClient <- connectSession+      buildStarted <- newEmptyMVar+      continueBuild <- newEmptyMVar+      let itemName = "org.test.HostHandlerRace"+          iface =+            Interface+              { interfaceName = "org.kde.StatusNotifierItem"+              , interfaceMethods = []+              , interfaceProperties =+                  [ readOnlyProperty "IconName" $ do+                      void $ tryPutMVar buildStarted ()+                      takeMVar continueBuild+                      pure ("folder" :: String)+                  , readOnlyProperty "OverlayIconName" (pure ("" :: String))+                  , readOnlyProperty "ItemIsMenu" (pure False)+                  ]+              , interfaceSignals = []+              }+      export itemClient (objectPath_ defaultPath) iface+      _ <- requestName itemClient (busName_ itemName) []+      WatcherClient.registerStatusNotifierItem itemClient itemName+        `shouldReturn` Right ()++      -- Host is now blocked building the item while holding itemInfoMapVar.+      takeMVar buildStarted++      events <- newChan+      _ <- forkIO $ do+        threadDelay 50000+        putMVar continueBuild ()+      _ <- addUpdateHandler host (\ut info -> writeChan events (ut, itemServiceName info))++      first <- timeout 1500000 (readChan events)+      first `shouldBe` Just (ItemAdded, busName_ itemName)+      second <- timeout 300000 (readChan events)+      second `shouldBe` Nothing++      _ <- releaseName itemClient (busName_ itemName)+      pure ()    describe "propertyUpdateFailureLogLevel" $ do     it "returns DEBUG when there are successful updates" $ do