roundabout,
created on Saturday, 18 October 2025, 21:37:35 (1760823455),
received on Saturday, 18 October 2025, 21:37:38 (1760823458)
Author identity: Vlad <vlad.muntoiu@gmail.com>
3f4433e2f61623fe8c262b2f0bd9e292430f23bd
applets/app-menu/__init__.py
@@ -64,56 +64,6 @@ Gtk.StyleContext.add_provider_for_display(
)
def force_visible_on_visible_notify(widget, *args):
if not widget.get_visible():
widget.set_visible(True)
def add_icons_to_menu(popover: Gtk.PopoverMenu):
section = popover.get_child().get_first_child().get_first_child().get_first_child()
while section is not None:
child = section.get_first_child().get_first_child()
while child is not None:
gutter_box: Gtk.Box = child.get_first_child()
if isinstance(gutter_box.get_next_sibling(), Gtk.Image):
# For some reason GTK creates images but they're hidden?
image: Gtk.Image = gutter_box.get_next_sibling()
label: Gtk.Label = image.get_next_sibling()
image.set_icon_size(Gtk.IconSize.LARGE)
image.set_margin_start(8)
image.set_margin_end(8)
child.add_css_class("no-menu-item-padding")
# Push the arrow to the left
label.set_halign(Gtk.Align.FILL)
label.set_hexpand(True)
label.set_xalign(0)
# GTK pushes its stance on icons so hard it makes them invisible multiple times;
# force it visible
image.set_visible(True)
image.connect("notify::visible", force_visible_on_visible_notify)
# Find the submenu if there is one
subchild = child.get_first_child()
submenu = None
while subchild is not None:
if isinstance(subchild, Gtk.PopoverMenu):
submenu = subchild
subchild = subchild.get_next_sibling()
# Recursive
if submenu is not None:
add_icons_to_menu(submenu)
child = child.get_next_sibling()
section = section.get_next_sibling()
locale.bindtextdomain("panorama-app-menu", module_directory / "locale")
_ = lambda x: locale.dgettext("panorama-app-menu", x)
@@ -268,4 +218,4 @@ class AppMenu(panorama_panel.Applet):
item.set_submenu(submenu)
self.menu.append_item(item)
add_icons_to_menu(self.popover)
panorama_panel.add_icons_to_menu(self.popover)
applets/indicators/__init__.py
@@ -87,7 +87,7 @@ class StatusIcon(Gtk.MenuButton):
self.menu = None
try:
proxy = Gio.DBusProxy.new_sync(
self.proxy = Gio.DBusProxy.new_sync(
self.applet.connection,
Gio.DBusProxyFlags.NONE,
None,
@@ -97,21 +97,45 @@ class StatusIcon(Gtk.MenuButton):
None
)
self.applet.item_id += 1
icon_name = proxy.get_cached_property("IconName")
icon_name = self.proxy.get_cached_property("IconName")
if icon_name:
icon_name = icon_name.unpack()
self.icon = Gtk.Image.new_from_icon_name(icon_name)
self.set_child(self.icon)
menu = proxy.get_cached_property("Menu")
menu = self.proxy.get_cached_property("Menu")
if menu:
self.menu = dbusmenu.CanonicalMenuModel()
self.menu.connect("menu_changed", lambda x: panorama_panel.add_icons_to_menu(self.popover_menu, Gtk.IconSize.NORMAL))
self.menu.connect_dbus(connection, menu.get_string(), f"ac{self.applet.item_id}")
self.insert_action_group(f"ac{self.applet.item_id}", self.menu.actions)
self.popover_menu.set_menu_model(self.menu.menu)
# TODO: NewTitle etc.
self.applet.connection.signal_subscribe(
connection,
"org.kde.StatusNotifierItem",
"NewIcon",
path,
None,
Gio.DBusSignalFlags.NONE,
self.on_icon_change,
)
except Exception as e:
print(f"Could not get properties from {service}: {e}")
traceback.print_exc()
def on_icon_change(self, *args):
icon_name = self.proxy.call_sync(
"org.freedesktop.DBus.Properties.Get",
GLib.Variant("(ss)", ("org.kde.StatusNotifierItem", "IconName")),
Gio.DBusCallFlags.NONE,
-1,
None
)
if icon_name:
self.icon = Gtk.Image.new_from_icon_name(icon_name.unpack()[0])
self.set_child(self.icon)
class IndicatorApplet(panorama_panel.Applet):
name = _("Indicators")
applets/indicators/dbusmenu.py
@@ -130,6 +130,8 @@ class CanonicalMenuModel(GObject.Object):
self.actions.add_action(boolean_action)
else:
item.set_detailed_action(action_string)
if icon_name:
item.set_icon(Gio.ThemedIcon.new(icon_name))
action = Gio.SimpleAction(name=action_name)
def on_activate(action, vb, item=child):
@@ -149,3 +151,9 @@ class CanonicalMenuModel(GObject.Object):
root = self.client.get_root()
self.reconstitute(root)
self.emit("menu_changed")
@GObject.Signal
def menu_changed(self):
pass
shared/panorama_panel.py
@@ -141,3 +141,53 @@ POSITION_TO_ARROW = {
Gtk.PositionType.LEFT: Gtk.ArrowType.LEFT,
Gtk.PositionType.RIGHT: Gtk.ArrowType.RIGHT,
}
def add_icons_to_menu(popover: Gtk.PopoverMenu, size: Gtk.IconSize = Gtk.IconSize.LARGE):
section = popover.get_child().get_first_child().get_first_child().get_first_child()
while section is not None:
child = section.get_first_child().get_first_child()
while child is not None:
gutter_box: Gtk.Box = child.get_first_child()
if isinstance(gutter_box.get_next_sibling(), Gtk.Image):
# For some reason GTK creates images but they're hidden?
image: Gtk.Image = gutter_box.get_next_sibling()
label: Gtk.Label = image.get_next_sibling()
image.set_icon_size(Gtk.IconSize.LARGE)
image.set_margin_start(8)
image.set_margin_end(8)
child.add_css_class("no-menu-item-padding")
# Push the arrow to the left
label.set_halign(Gtk.Align.FILL)
label.set_hexpand(True)
label.set_xalign(0)
# GTK pushes its stance on icons so hard it makes them invisible multiple times;
# force it visible
image.set_visible(True)
image.connect("notify::visible", force_visible_on_visible_notify)
# Find the submenu if there is one
subchild = child.get_first_child()
submenu = None
while subchild is not None:
if isinstance(subchild, Gtk.PopoverMenu):
submenu = subchild
subchild = subchild.get_next_sibling()
# Recursive
if submenu is not None:
add_icons_to_menu(submenu)
child = child.get_next_sibling()
section = section.get_next_sibling()
def force_visible_on_visible_notify(widget, *args):
if not widget.get_visible():
widget.set_visible(True)