Skip to content

Commit

Permalink
Improve handling for new StatusNotifierWatcher
Browse files Browse the repository at this point in the history
Earlier we just re-registered our item when a new StatusNotifierWatcher showed up but there are actually three cases where this happens:

* In case the watcher got replaced. This is what #1801 actually targeted and works fine for.
* Initially if a watcher is available. This means we actually register the item twice: Directly from within the constructor and from the handler. Does not hurt but is unnecessary.
* In case a watcher actually just showed up. In this case, we are already showing using the GtkStatusItem fallback, though, and this thus leads to two icons, see #1870.

Instead of re-registering, this change causes blueman-tray to reload if a watcher appears after we failed to register the item or a watcher appears for the second time.
  • Loading branch information
cschramm committed Oct 6, 2022
1 parent 2f3685d commit 6b219de
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 30 deletions.
7 changes: 3 additions & 4 deletions blueman/main/Tray.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,7 @@ def _on_name_appeared(self, _connection: Gio.DBusConnection, name: str, _owner:
for indicator_name in applet.GetStatusIconImplementations():
indicator_class = getattr(import_module('blueman.main.indicators.' + indicator_name), indicator_name)
try:
self.indicator = indicator_class(
applet.GetIconName(), self._activate_menu_item, self._activate_status_icon)
self.indicator = indicator_class(self, applet.GetIconName())
break
except IndicatorNotAvailable:
logging.info(f'Indicator "{indicator_name}" is not available')
Expand All @@ -58,10 +57,10 @@ def _on_name_vanished(self, _connection: Gio.DBusConnection, _name: str) -> None
logging.debug("Applet shutdown or not available at startup")
self.quit()

def _activate_menu_item(self, *indexes: int) -> None:
def activate_menu_item(self, *indexes: int) -> None:
AppletService().ActivateMenuItem('(ai)', indexes)

def _activate_status_icon(self) -> None:
def activate_status_icon(self) -> None:
AppletService().Activate()

def on_signal(self, _applet: AppletService, _sender_name: str, signal_name: str, args: GLib.Variant) -> None:
Expand Down
15 changes: 5 additions & 10 deletions blueman/main/indicators/GtkStatusIcon.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import gi

from blueman.main.Tray import BluemanTray
from blueman.main.indicators.IndicatorInterface import IndicatorInterface

gi.require_version("Gtk", "3.0")
Expand All @@ -14,12 +15,7 @@
from blueman.plugins.applet.Menu import MenuItemDict, SubmenuItemDict

class MenuItemActivator(Protocol):
@overload
def __call__(self, idx: int) -> None:
...

@overload
def __call__(self, idx: int, subid: int) -> None:
def __call__(self, *idx: int) -> None:
...


Expand Down Expand Up @@ -60,13 +56,12 @@ def build_menu(items: Iterable[Tuple[int, "SubmenuItemDict"]], activate: Callabl


class GtkStatusIcon(IndicatorInterface):
def __init__(self, icon_name: str, on_activate_menu_item: "MenuItemActivator",
on_activate_status_icon: Callable[[], None]) -> None:
self._on_activate = on_activate_menu_item
def __init__(self, tray: BluemanTray, icon_name: str) -> None:
self._on_activate = tray.activate_menu_item
self.indicator = Gtk.StatusIcon(icon_name=icon_name)
self.indicator.set_title('blueman')
self.indicator.connect('popup-menu', self.on_popup_menu)
self.indicator.connect('activate', lambda _status_icon: on_activate_status_icon())
self.indicator.connect('activate', lambda _status_icon: tray.activate_status_icon())
self._tooltip_title = ""
self._tooltip_text = ""
self._menu: Optional[Gtk.Menu] = None
Expand Down
40 changes: 24 additions & 16 deletions blueman/main/indicators/StatusNotifierItem.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from collections import OrderedDict
from typing import Iterable, TYPE_CHECKING, Callable, List, Tuple, Dict, Union, TypeVar
from typing import Iterable, TYPE_CHECKING, Callable, List, Tuple, Dict, Union, TypeVar, Any

from gi.repository import Gio, GLib, Pango

from blueman.main.DbusService import DbusService
from blueman.main.Tray import BluemanTray
from blueman.main.indicators.IndicatorInterface import IndicatorInterface, IndicatorNotAvailable

if TYPE_CHECKING:
Expand Down Expand Up @@ -99,14 +100,13 @@ class StatusNotifierItemService(DbusService):
Title = "blueman"
ItemIsMenu = False

def __init__(self, icon_name: str, on_activate_status_icon: Callable[[], None],
on_activate_menu_item: "MenuItemActivator") -> None:
def __init__(self, tray: BluemanTray, icon_name: str) -> None:
super().__init__(None, "org.kde.StatusNotifierItem", "/org/blueman/sni", Gio.BusType.SESSION,
{"Category": "s", "Id": "s", "IconName": "s", "Status": "s", "Title": "s",
"ToolTip": "(sa(iiay)ss)", "Menu": "o", "ItemIsMenu": "b"})
self.add_method("Activate", ("i", "i"), "", lambda x, y: on_activate_status_icon())
self.add_method("Activate", ("i", "i"), "", lambda x, y: tray.activate_status_icon())

self.menu = MenuService(on_activate_menu_item)
self.menu = MenuService(tray.activate_menu_item)

self.IconName = icon_name
self.Status = "Active"
Expand All @@ -129,27 +129,35 @@ def unregister(self) -> None:
class StatusNotifierItem(IndicatorInterface):
_SNI_BUS_NAME = _SNI_INTERFACE_NAME = "org.kde.StatusNotifierWatcher"

def __init__(self, icon_name: str, on_activate_menu_item: "MenuItemActivator",
on_activate_status_icon: Callable[[], None]) -> None:
self._sni = StatusNotifierItemService(icon_name, on_activate_status_icon, on_activate_menu_item)
def __init__(self, tray: BluemanTray, icon_name: str) -> None:
self._sni = StatusNotifierItemService(tray, icon_name)
self._sni.register()

self._bus = Gio.bus_get_sync(Gio.BusType.SESSION)

watcher_expected: bool

def on_watcher_appeared(*args: Any) -> None:
nonlocal watcher_expected

if watcher_expected:
watcher_expected = False
else:
tray.activate()

Gio.bus_watch_name(Gio.BusType.SESSION, self._SNI_BUS_NAME, Gio.BusNameWatcherFlags.NONE,
lambda *args: self._register(), None)
on_watcher_appeared, None)

try:
self._register()
Gio.bus_get_sync(Gio.BusType.SESSION).call_sync(
self._SNI_BUS_NAME, "/StatusNotifierWatcher", self._SNI_INTERFACE_NAME,
"RegisterStatusNotifierItem", GLib.Variant("(s)", ("/org/blueman/sni",)),
None, Gio.DBusCallFlags.NONE, -1)
watcher_expected = True
except GLib.Error:
watcher_expected = False
raise IndicatorNotAvailable

def _register(self) -> None:
Gio.bus_get_sync(Gio.BusType.SESSION).call_sync(
self._SNI_BUS_NAME, "/StatusNotifierWatcher", self._SNI_INTERFACE_NAME,
"RegisterStatusNotifierItem", GLib.Variant("(s)", ("/org/blueman/sni",)),
None, Gio.DBusCallFlags.NONE, -1)

def set_icon(self, icon_name: str) -> None:
self._sni.IconName = icon_name
self._sni.emit_signal("NewIcon")
Expand Down

0 comments on commit 6b219de

Please sign in to comment.