packages feed

gtk-sni-tray 0.1.10.3 → 0.1.11.0

raw patch · 5 files changed

+90/−59 lines, 5 filesdep +gi-dbusmenugtk3PVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: gi-dbusmenugtk3

API changes (from Hackage documentation)

+ StatusNotifier.Tray: HaskellDBusMenu :: MenuBackend
+ StatusNotifier.Tray: LibDBusMenu :: MenuBackend
+ StatusNotifier.Tray: [trayMenuBackend] :: TrayParams -> MenuBackend
+ StatusNotifier.Tray: data MenuBackend
+ StatusNotifier.Tray: instance GHC.Classes.Eq StatusNotifier.Tray.MenuBackend
+ StatusNotifier.Tray: instance GHC.Internal.Show.Show StatusNotifier.Tray.MenuBackend
- StatusNotifier.Tray: TrayParams :: Orientation -> TrayImageSize -> Bool -> StrutAlignment -> Rational -> TrayClickAction -> TrayClickAction -> TrayClickAction -> TrayParams
+ StatusNotifier.Tray: TrayParams :: Orientation -> TrayImageSize -> Bool -> StrutAlignment -> Rational -> TrayClickAction -> TrayClickAction -> TrayClickAction -> MenuBackend -> TrayParams

Files

ChangeLog.md view
@@ -1,5 +1,12 @@ # Changelog for gtk-sni-tray +## 0.1.11.0++- Restore `libdbusmenu` (`gi-dbusmenugtk3`) as the default menu backend.+- Add runtime-configurable menu backend selection: `LibDBusMenu` (default) or+  `HaskellDBusMenu` via `trayMenuBackend` in `TrayParams` and `--menu-backend`+  CLI flag.+ ## 0.1.10.2  - Fix menu popups not appearing: restore `widgetShowAll` so menu items are
app/Main.hs view
@@ -131,7 +131,6 @@         GtkLayerShell.setNamespace window (T.pack "gtk-sni-tray")         GtkLayerShell.setLayer window GtkLayerShell.LayerTop -        -- Default behavior if monitor info isn't available: behave like a full-width/height panel.         GtkLayerShell.setMargin window GtkLayerShell.EdgeLeft xpadding         GtkLayerShell.setMargin window GtkLayerShell.EdgeRight xpadding         GtkLayerShell.setMargin window GtkLayerShell.EdgeTop ypadding@@ -468,6 +467,21 @@   <> value (5 % 7)   ) +menuBackendP :: Parser MenuBackend+menuBackendP =+  option (eitherReader parseMenuBackend)+  (  long "menu-backend"+  <> help "Menu backend: libdbusmenu (default) | haskell"+  <> value LibDBusMenu+  <> metavar "BACKEND"+  )+  where+    parseMenuBackend s =+      case map toLower s of+        "libdbusmenu" -> Right LibDBusMenu+        "haskell" -> Right HaskellDBusMenu+        _ -> Left "expected one of: libdbusmenu, haskell"+ getColor :: String -> IO Gdk.RGBA getColor colorString = do   rgba <- Gdk.newZeroRGBA@@ -490,9 +504,10 @@              -> Bool              -> Rational              -> Rational+             -> MenuBackend              -> IO () buildWindows pos align size padding monitors priority backendChoice maybeColorString expand-             startWatcher noStrut barLength overlayScale = do+             startWatcher noStrut barLength overlayScale menuBackend = do   _ <- Gtk.init Nothing   logger <- getLogger "StatusNotifier"   saveGlobalLogger $ setLevel priority logger@@ -557,9 +572,9 @@             , trayLeftClickAction = Activate             , trayMiddleClickAction = SecondaryActivate             , trayRightClickAction = PopupMenu+            , trayMenuBackend = menuBackend             }         window <- Gtk.windowNew Gtk.WindowTypeToplevel-        -- Make it behave more like a panel/tray window in the fallback cases.         Gtk.windowSetResizable window False         Gtk.windowSetSkipTaskbarHint window True         Gtk.windowSetSkipPagerHint window True@@ -591,7 +606,7 @@ parser =   buildWindows <$> positionP <*> alignmentP <*> sizeP <*> paddingP <*>   monitorNumberP <*> logP <*> backendChoiceP <*> colorP <*> expandP <*> startWatcherP <*>-  noStrutP <*> barLengthP <*> overlayScaleP+  noStrutP <*> barLengthP <*> overlayScaleP <*> menuBackendP  versionOption :: Parser (a -> a) versionOption = infoOption
gtk-sni-tray.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack  name:           gtk-sni-tray-version:        0.1.10.3+version:        0.1.11.0 synopsis:       A standalone StatusNotifierItem/AppIndicator tray description:    Please see the README on Github at <https://github.com/IvanMalison/gtk-sni-tray#readme> category:       System@@ -49,6 +49,7 @@     , gi-cairo     , gi-cairo-connector     , gi-cairo-render+    , gi-dbusmenugtk3     , gi-gdk3     , gi-gdkpixbuf >=2.0.16     , gi-glib
src/StatusNotifier/DBusMenu.hs view
@@ -18,6 +18,8 @@ import System.Log.Logger (Priority(..), logM) import Text.Printf +import qualified StatusNotifier.DBus.Client.DBusMenu as DM+ dbusMenuLogger :: Priority -> String -> IO () dbusMenuLogger = logM "StatusNotifier.DBusMenu" @@ -39,45 +41,47 @@   children <- traverse variantToLayout kids   pure LayoutNode { lnId = i, lnProps = props, lnChildren = children } -callMenu-  :: Client-  -> BusName-  -> ObjectPath-  -> MemberName-  -> [Variant]-  -> IO [Variant]-callMenu client dest path member body = do-  let call0 =-        (methodCall path "com.canonical.dbusmenu" member)-          { methodCallDestination = Just dest-          , methodCallBody = body-          }-  reply <- call client call0-  case reply of-    Left err -> fail $ "DBusMenu call failed: " <> show err-    Right ret -> pure (methodReturnBody ret)+tupleToLayout :: LayoutTuple -> LayoutNode+tupleToLayout (i, props, kids) =+  LayoutNode+    { lnId = i+    , lnProps = props+    , lnChildren = [ n | v <- kids, Just n <- [variantToLayout v] ]+    } +-- | Unwrap an Either MethodError, failing on Left.+unwrapCall :: String -> Either MethodError a -> IO a+unwrapCall label (Left err) = fail $ label <> " failed: " <> show err+unwrapCall _ (Right a) = pure a+ aboutToShow :: Client -> BusName -> ObjectPath -> Int32 -> IO Bool-aboutToShow client dest path i = do-  body <- callMenu client dest path "AboutToShow" [toVariant i]-  case body of-    (v : _) -> pure $ fromMaybe False (fromVariant v)-    _ -> pure False+aboutToShow client dest path i =+  either (const False) id <$> DM.aboutToShow client dest path i  getLayout :: Client -> BusName -> ObjectPath -> Int32 -> Int32 -> [String] -> IO (Word32, LayoutNode) getLayout client dest path parentId depth propNames = do-  body <- callMenu client dest path "GetLayout"-    [ toVariant parentId-    , toVariant depth-    , toVariant propNames-    ]-  case body of-    (revV : layoutV : _) -> do-      rev <- maybe (fail "GetLayout: bad revision") pure (fromVariant revV)-      node <- maybe (fail "GetLayout: bad layout") pure (variantToLayout layoutV)-      pure (rev, node)-    _ -> fail "GetLayout: unexpected reply body"+  (rev, tup) <- unwrapCall "GetLayout" =<<+    DM.getLayout client dest path parentId depth propNames+  pure (rev, tupleToLayout tup) +sendClicked :: Client -> BusName -> ObjectPath -> Int32 -> Word32 -> IO ()+sendClicked client dest path itemId ts = do+  -- Use the TH-generated eventMethodCall for the method call structure, but+  -- call it with callNoReply: the Event method has no output args, and many+  -- services never send a reply, so using `call` (as DM.event does) would+  -- block the GTK main thread until the dbus timeout (~25s).+  let mc = DM.eventMethodCall+        { methodCallDestination = Just dest+        , methodCallPath = path+        , methodCallBody =+            [ toVariant itemId+            , toVariant ("clicked" :: String)+            , toVariant (toVariant (0 :: Int32))+            , toVariant ts+            ]+        }+  callNoReply client mc+ getPropS :: String -> LayoutNode -> Maybe String getPropS key LayoutNode { lnProps = props } =   Map.lookup key props >>= fromVariant@@ -110,17 +114,6 @@  menuItemToggleState :: LayoutNode -> Maybe Int32 menuItemToggleState = getPropI32 "toggle-state"--sendClicked :: Client -> BusName -> ObjectPath -> Int32 -> Word32 -> IO ()-sendClicked client dest path itemId ts = do-  -- "clicked" is the common event for activating menu items in the DBusMenu spec.-  _ <- callMenu client dest path "Event"-    [ toVariant itemId-    , toVariant ("clicked" :: String)-    , toVariant ("" :: String) -- v (data)-    , toVariant ts-    ]-  pure ()  populateGtkMenu :: Client -> BusName -> ObjectPath -> Gtk.Menu -> LayoutNode -> IO () populateGtkMenu client dest path gtkMenu root = do
src/StatusNotifier/Tray.hs view
@@ -15,6 +15,7 @@ import qualified Data.ByteString as BS import           Data.Coerce import           Data.Foldable (traverse_)+import           Data.GI.Base (unsafeCastTo) import qualified Data.GI.Base.ManagedPtr as ManagedPtr import           Data.GI.Base.GError import           Data.Int@@ -24,6 +25,7 @@ import           Data.Ord import           Data.Ratio import qualified Data.Text as T+import qualified GI.DbusmenuGtk3.Objects.Menu as DM import qualified GI.GLib as GLib import           GI.GLib.Structs.Bytes import qualified GI.Gdk as Gdk@@ -201,6 +203,8 @@  data TrayClickAction = Activate | SecondaryActivate | PopupMenu +data MenuBackend = LibDBusMenu | HaskellDBusMenu deriving (Eq, Show)+ data TrayParams = TrayParams   { trayOrientation :: Gtk.Orientation   , trayImageSize :: TrayImageSize@@ -210,6 +214,7 @@   , trayLeftClickAction :: TrayClickAction   , trayMiddleClickAction :: TrayClickAction   , trayRightClickAction :: TrayClickAction+  , trayMenuBackend :: MenuBackend   }  defaultTrayParams :: TrayParams@@ -222,6 +227,7 @@   , trayLeftClickAction = Activate   , trayMiddleClickAction = SecondaryActivate   , trayRightClickAction = PopupMenu+  , trayMenuBackend = LibDBusMenu   }  buildTray :: Host -> Client -> TrayParams -> IO Gtk.Box@@ -239,6 +245,7 @@                      , trayLeftClickAction = leftClickAction                      , trayMiddleClickAction = middleClickAction                      , trayRightClickAction = rightClickAction+                     , trayMenuBackend = menuBackend                      } = do   trayLogger INFO "Building tray" @@ -371,7 +378,10 @@                popupGtkMenu gtkMenu triggerEvent = do                 Gtk.menuAttachToWidget gtkMenu eventBox Nothing-                _ <- Gtk.onWidgetHide gtkMenu (Gtk.widgetDestroy gtkMenu)+                _ <- Gtk.onWidgetHide gtkMenu $+                  void $ GLib.idleAdd GLib.PRIORITY_DEFAULT_IDLE $ do+                    Gtk.widgetDestroy gtkMenu+                    return False                 Gtk.widgetShowAll gtkMenu                 evPtr <- ManagedPtr.unsafeManagedPtrCastPtr triggerEvent :: IO (Ptr Gdk.Event)                 ManagedPtr.withTransient evPtr $ \ev ->@@ -403,7 +413,14 @@                 menuPath' <- getInfoAttr menuPath Nothing serviceName                 traverse_                   (\p -> catchAny-                    (DBusMenu.buildMenu client serviceName p >>= (`popupGtkMenu` event))+                    (do gtkMenu <- case menuBackend of+                          LibDBusMenu -> do+                            let sn = T.pack (coerce serviceName :: String)+                                mp = T.pack (coerce p :: String)+                            DM.menuNew sn mp >>= unsafeCastTo Gtk.Menu+                          HaskellDBusMenu ->+                            DBusMenu.buildMenu client serviceName p+                        popupGtkMenu gtkMenu event)                     (logActionError "PopupMenu"))                   menuPath'             return False@@ -415,8 +432,6 @@                                ScrollDirectionLeft -> Just "horizontal"                                ScrollDirectionRight -> Just "horizontal"                                _ -> Nothing-                -- deltaX/deltaY are provided only in case of smooth scrolling which-                -- is enabled via additional flag, we don't to enable/handle it                 delta = case direction of                           ScrollDirectionUp -> -1                           ScrollDirectionDown -> 1@@ -469,12 +484,12 @@             _mainHeight <- getPixbufHeight pixbuf             _mainWidth <- getPixbufWidth pixbuf             pixbufComposite overlayPixbuf pixbuf-              0 0                           -- Top left corner-              actualOWidth actualOHeight    -- Overlay size-              0 0                           -- Offset-              1.0 1.0                       -- Scale-              InterpTypeBilinear            -- InterpType-              255                           -- Source image alpha+              0 0+              actualOWidth actualOHeight+              0 0+              1.0 1.0+              InterpTypeBilinear+              255         return pixbuf        getScaledPixBufFromInfo size info =