diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,12 @@
 # Unreleased
 
+# 5.1.1
+
+## Dependency Bumps
+
+ * Bump `dbus-menu` lower bound to 0.1.3.0 for menu-level click dispatch.
+ * Bump `gtk-sni-tray` lower bound to 0.1.13.1.
+
 # 5.1.0
 
 ## New Widgets
diff --git a/src/System/Taffybar/Context.hs b/src/System/Taffybar/Context.hs
--- a/src/System/Taffybar/Context.hs
+++ b/src/System/Taffybar/Context.hs
@@ -396,9 +396,6 @@
             logIO DEBUG $ printf "barConfigs: %s" $
                   show $ map strutConfig barConfigs
 
-            logIO DEBUG "Removing windows"
-            mapM_ (Gtk.widgetDestroy . sel2) removedWindows
-
             -- TODO: This should actually use the config that is provided from
             -- getBarConfigs so that the strut properties of the window can be
             -- altered.
@@ -409,9 +406,14 @@
             mapM (sequenceT . ((return :: a -> IO a) &&& buildBarWindow ctx))
                  newConfs
 
-          return $ newWindowPairs ++ remainingWindows
+          return (newWindowPairs ++ remainingWindows, map sel2 removedWindows)
 
-  lift $ MV.modifyMVar_ windowsVar rebuildWindows
+  -- Destroy removed windows AFTER releasing the MVar to avoid deadlock
+  -- with the onWidgetDestroy handler, which also modifies existingWindows.
+  windowsToDestroy <- lift $ MV.modifyMVar windowsVar rebuildWindows
+  lift $ do
+    logIO DEBUG "Removing windows"
+    mapM_ Gtk.widgetDestroy windowsToDestroy
   logC DEBUG "Finished refreshing windows"
   return ()
 
diff --git a/src/System/Taffybar/DBus/Toggle.hs b/src/System/Taffybar/DBus/Toggle.hs
--- a/src/System/Taffybar/DBus/Toggle.hs
+++ b/src/System/Taffybar/DBus/Toggle.hs
@@ -33,6 +33,7 @@
 import           System.FilePath.Posix
 import           System.Log.Logger
 import           System.Taffybar.Context
+import           System.Taffybar.Information.Hyprland (getFocusedMonitorPosition)
 import           System.Taffybar.Util
 import           Text.Printf
 import           Text.Read ( readMaybe )
@@ -55,8 +56,14 @@
 logT :: MonadIO m => System.Log.Logger.Priority -> String -> m ()
 logT p = liftIO . logIO p
 
-getActiveMonitorNumber :: MaybeT IO Int
-getActiveMonitorNumber = do
+getActiveMonitorNumber :: Context -> MaybeT IO Int
+getActiveMonitorNumber ctx =
+  case backend ctx of
+    BackendX11 -> getActiveMonitorNumberX11
+    BackendWayland -> getActiveMonitorNumberWayland ctx
+
+getActiveMonitorNumberX11 :: MaybeT IO Int
+getActiveMonitorNumberX11 = do
   display <- MaybeT Gdk.displayGetDefault
   seat <- lift $ Gdk.displayGetDefaultSeat display
   device <- MaybeT $ Gdk.seatGetPointer seat
@@ -64,6 +71,14 @@
     (_, x, y) <- Gdk.deviceGetPosition device
     Gdk.displayGetMonitorAtPoint display x y >>= getMonitorNumber
 
+getActiveMonitorNumberWayland :: Context -> MaybeT IO Int
+getActiveMonitorNumberWayland ctx = do
+  (x, y) <- MaybeT $ getFocusedMonitorPosition (hyprlandClient ctx)
+  display <- MaybeT Gdk.displayGetDefault
+  monitor <- lift $ Gdk.displayGetMonitorAtPoint display
+               (fromIntegral x) (fromIntegral y)
+  lift $ getMonitorNumber monitor
+
 getMonitorNumber :: Gdk.Monitor -> IO Int
 getMonitorNumber monitor = do
   display <- Gdk.monitorGetDisplay monitor
@@ -123,7 +138,7 @@
           return result
         refreshTaffyWindows
       toggleTaffy = do
-        num <- runMaybeT getActiveMonitorNumber
+        num <- runMaybeT $ getActiveMonitorNumber ctx
         toggleTaffyOnMon not $ fromMaybe 0 num
       takeInt :: (Int -> a) -> (Int32 -> a)
       takeInt = (. fromIntegral)
diff --git a/src/System/Taffybar/Information/Hyprland.hs b/src/System/Taffybar/Information/Hyprland.hs
--- a/src/System/Taffybar/Information/Hyprland.hs
+++ b/src/System/Taffybar/Information/Hyprland.hs
@@ -56,6 +56,9 @@
   , openHyprlandEventSocket
   , withHyprlandEventSocket
 
+    -- * Monitor queries
+  , getFocusedMonitorPosition
+
     -- * Errors
   , HyprlandError(..)
   ) where
@@ -72,7 +75,7 @@
 import           Control.Monad.IO.Class (MonadIO(..))
 import           Control.Monad.STM (atomically)
 import           Control.Monad.Trans.Reader (ReaderT, ask, runReaderT)
-import           Data.Aeson (FromJSON, eitherDecode')
+import           Data.Aeson (FromJSON(..), eitherDecode', withObject, (.:))
 import qualified Data.ByteString as BS
 import qualified Data.ByteString.Char8 as BS8
 import qualified Data.ByteString.Lazy as BL
@@ -341,6 +344,31 @@
             logH WARNING $ printf "Hyprland event socket failed: %s" (show e)
           void $ hClose handle `catchAny` \_ -> pure ()
           threadDelay retryDelayMicros
+
+-- | Minimal monitor info parsed from @hyprctl monitors -j@.
+data HyprMonitorInfo = HyprMonitorInfo
+  { hmX :: Int
+  , hmY :: Int
+  , hmFocused :: Bool
+  }
+
+instance FromJSON HyprMonitorInfo where
+  parseJSON = withObject "HyprMonitorInfo" $ \o ->
+    HyprMonitorInfo
+      <$> o .: "x"
+      <*> o .: "y"
+      <*> o .: "focused"
+
+-- | Get the global coordinates of the currently focused Hyprland monitor.
+getFocusedMonitorPosition :: HyprlandClient -> IO (Maybe (Int, Int))
+getFocusedMonitorPosition client = do
+  result <- runHyprlandCommandJson client (hyprCommandJson ["monitors"])
+  case result of
+    Left _ -> return Nothing
+    Right monitors ->
+      case filter hmFocused monitors of
+        (m:_) -> return $ Just (hmX m, hmY m)
+        [] -> return Nothing
 
 data HyprlandCommand = HyprlandCommand
   { commandArgs :: [String]
diff --git a/src/System/Taffybar/Widget/Wlsunset.hs b/src/System/Taffybar/Widget/Wlsunset.hs
--- a/src/System/Taffybar/Widget/Wlsunset.hs
+++ b/src/System/Taffybar/Widget/Wlsunset.hs
@@ -114,9 +114,7 @@
   -- Remove all state classes first
   mapM_ (Gtk.styleContextRemoveClass styleCtx) allStateClasses
   -- Add the appropriate class
-  case stateToClass st of
-    Just cls -> Gtk.styleContextAddClass styleCtx cls
-    Nothing  -> return ()
+  forM_ (stateToClass st) (Gtk.styleContextAddClass styleCtx)
 
 -- | Map a 'WlsunsetState' to its CSS class, or 'Nothing' for auto/running.
 stateToClass :: WlsunsetState -> Maybe T.Text
diff --git a/taffybar.cabal b/taffybar.cabal
--- a/taffybar.cabal
+++ b/taffybar.cabal
@@ -1,6 +1,6 @@
 cabal-version: 3.4
 name: taffybar
-version: 5.1.0
+version: 5.1.1
 synopsis: A desktop bar similar to xmobar, but with more GUI
 license: BSD-3-Clause
 license-file: LICENSE
@@ -66,7 +66,7 @@
                , data-default
                , dbus >= 1.2.11 && < 2.0.0
                , dbus-hslogger >= 0.1.1.0 && < 0.2.0.0
-               , dbus-menu >= 0.1.1.0
+               , dbus-menu >= 0.1.3.0
                , directory
                , disk-free-space >= 0.1.0.1
                , dyre >= 0.9.0 && < 0.10
@@ -85,7 +85,7 @@
                , gi-gtk3 >= 3.0.44 && < 4
                , gi-gtk-hs >= 0.3.17 && < 0.4
                , gi-pango
-               , gtk-sni-tray >= 0.1.13.0
+               , gtk-sni-tray >= 0.1.13.1
                , gtk-strut >= 0.1.2.1
                , haskell-gi-base >= 0.24
                , hslogger
