Skip to content

Commit

Permalink
Put recent connections in toplevel applet menu
Browse files Browse the repository at this point in the history
Other applets like NetworkManager's do not try to keep menu small, so why should blueman...

Closes #1558
  • Loading branch information
cschramm committed Sep 10, 2022
1 parent c5baa24 commit 46cd283
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 34 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
* Drop auto-power feature. BlueZ now has the AutoEnable setting for even better auto-powering.
* Do not use pointless link quality value
* Do not re-use dbusmenu item identifiers; avoids issues at least with gnome-shell-extension-appindicator.
* Recent connections in toplevel applet menu

### Bugs fixed

Expand Down
17 changes: 9 additions & 8 deletions blueman/main/indicators/StatusNotifierItem.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,17 @@ def _advertise_revision(self) -> bool:
def _get_layout(self, parent_id: int, _recursion_depth: int, _property_names: List[str]
) -> Tuple[int, Tuple[int, Dict[str, GLib.Variant], List[GLib.Variant]]]:
if parent_id == 0:
return self._revision, (0, {}, self._render_menu(self._items.items(), self._render_submenu))
return self._revision, (0, {}, self._render_menu(((item["id"] << 8, item) for item in self._items.values()),
self._render_submenu))
else:
item = self._items[parent_id]
item = self._items[parent_id >> 8]
if "submenu" in item and _recursion_depth != 0:
return self._revision, (parent_id, self._render_item(item), self._render_submenu(item, parent_id))
return self._revision, (parent_id, self._render_item(item), [])

def _render_submenu(self, item: "MenuItemDict", idx: int) -> List[GLib.Variant]:
if "submenu" in item:
return self._render_menu(enumerate(item["submenu"], idx * 100 + 1), lambda _item, _isx: [])
return self._render_menu(enumerate(item["submenu"], idx + 1), lambda _item, _isx: [])
else:
return []

Expand All @@ -65,9 +66,9 @@ def _render_menu(self, items: Iterable[Tuple[int, _T]], submenu_callback: Callab

def _iterate_items(self) -> Iterable[Tuple[int, "SubmenuItemDict"]]:
for item in self._items.values():
yield item["id"], item
yield item["id"] << 8, item
if "submenu" in item:
yield from enumerate(item["submenu"], item["id"] * 100 + 1)
yield from enumerate(item["submenu"], (item["id"] << 8) + 1)

def _render_item(self, item: Union["MenuItemDict", "SubmenuItemDict"]) -> Dict[str, GLib.Variant]:
if "text" in item and "icon_name" in item:
Expand All @@ -85,10 +86,10 @@ def _render_item(self, item: Union["MenuItemDict", "SubmenuItemDict"]) -> Dict[s

def _on_event(self, idx: int, event_id: str, _data: GLib.Variant, _timestamp: int) -> None:
if event_id == "clicked":
if idx < 100:
self._on_activate(idx)
if idx % (1 << 8) == 0:
self._on_activate(idx >> 8)
else:
self._on_activate(int(idx / 100), idx % 100 - 1)
self._on_activate(idx >> 8, idx % (1 << 8) - 1)


class StatusNotifierItemService(DbusService):
Expand Down
22 changes: 13 additions & 9 deletions blueman/plugins/applet/Menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ class MenuItemDict(MenuItemDictBase, total=False):


class MenuItem:
def __init__(self, menu_plugin: "Menu", owner: AppletPlugin, priority: int, text: Optional[str], markup: bool,
icon_name: Optional[str], tooltip: Optional[str], callback: Optional[Callable[[], None]],
def __init__(self, menu_plugin: "Menu", owner: AppletPlugin, priority: Tuple[int, int], text: Optional[str],
markup: bool, icon_name: Optional[str], tooltip: Optional[str], callback: Optional[Callable[[], None]],
submenu_function: Optional[Callable[[], Iterable["SubmenuItemDict"]]], visible: bool, sensitive: bool):
self._menu_plugin = menu_plugin
self._owner = owner
Expand All @@ -48,7 +48,7 @@ def owner(self) -> AppletPlugin:
return self._owner

@property
def priority(self) -> int:
def priority(self) -> Tuple[int, int]:
return self._priority

@property
Expand All @@ -66,7 +66,7 @@ def _iter_base(self) -> Iterator[Tuple[str, Union[str, bool]]]:
yield key, value

def __iter__(self) -> Iterator[Tuple[str, Union[int, str, bool, List[Dict[str, Union[str, bool]]]]]]:
yield "id", self.priority
yield "id", (self._priority[0] << 8) + self._priority[1]
yield from self._iter_base()
submenu = self.submenu_items
if submenu:
Expand All @@ -79,7 +79,7 @@ def submenu_items(self) -> List["SubmenuItem"]:
submenu_items = self._submenu_function()
if not submenu_items:
return []
return [SubmenuItem(self._menu_plugin, self._owner, 0, item.get('text'), item.get('markup', False),
return [SubmenuItem(self._menu_plugin, self._owner, (0, 0), item.get('text'), item.get('markup', False),
item.get('icon_name'), item.get('tooltip'), item.get('callback'), None, True,
item.get('sensitive', True))
for item in submenu_items]
Expand Down Expand Up @@ -118,17 +118,21 @@ class Menu(AppletPlugin):
__unloadable__ = False

def on_load(self) -> None:
self.__menuitems: Dict[int, MenuItem] = {}
self.__menuitems: Dict[Tuple[int, int], MenuItem] = {}

self._add_dbus_signal("MenuChanged", "aa{sv}")
self._add_dbus_method("GetMenu", (), "aa{sv}", self._get_menu)
self._add_dbus_method("ActivateMenuItem", ("ai",), "", self._activate_menu_item)

def add(self, owner: AppletPlugin, priority: int, text: Optional[str] = None, markup: bool = False,
icon_name: Optional[str] = None, tooltip: Optional[str] = None,
def add(self, owner: AppletPlugin, priority: Union[int, Tuple[int, int]], text: Optional[str] = None,
markup: bool = False, icon_name: Optional[str] = None, tooltip: Optional[str] = None,
callback: Optional[Callable[[], None]] = None,
submenu_function: Optional[Callable[[], Iterable["SubmenuItemDict"]]] = None,
visible: bool = True, sensitive: bool = True) -> MenuItem:

if isinstance(priority, int):
priority = (priority, 0)

item = MenuItem(self, owner, priority, text, markup, icon_name, tooltip, callback, submenu_function, visible,
sensitive)
self.__menuitems[item.priority] = item
Expand Down Expand Up @@ -164,7 +168,7 @@ def _build_variant(self, value: Union[int, str, bool, Iterable[Mapping[str, Unio
return GLib.Variant("aa{sv}", self._prepare_menu(value))

def _activate_menu_item(self, indexes: Sequence[int]) -> None:
node = self.__menuitems[indexes[0]]
node = self.__menuitems[(indexes[0] >> 8, indexes[0] % (1 << 8))]
for index in list(indexes)[1:]:
node = node.submenu_items[index]
if node.callback:
Expand Down
40 changes: 23 additions & 17 deletions blueman/plugins/applet/RecentConns.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from blueman.plugins.applet.PowerManager import PowerManager, PowerStateListener

if TYPE_CHECKING:
from blueman.plugins.applet.Menu import SubmenuItemDict
from blueman.plugins.applet.Menu import Menu, SubmenuItemDict

from typing_extensions import TypedDict

Expand Down Expand Up @@ -55,15 +55,10 @@ class RecentConns(AppletPlugin, PowerStateListener):
"recent-connections": {"type": list, "default": "[]"}
}

_items = None

def on_load(self) -> None:
self.__menuitems: List["SubmenuItemDict"] = []

self._item = self.parent.Plugins.Menu.add(self, 52, text=_("Recent _Connections") + "…",
icon_name="document-open-recent-symbolic",
submenu_function=self.get_menu)
self.parent.Plugins.Menu.add(self, 53)
self._rebuild_menu()

def on_power_state_changed(self, manager: PowerManager, state: bool) -> None:
self._rebuild()
Expand All @@ -74,26 +69,30 @@ def on_unload(self) -> None:
def _rebuild(self) -> None:
if 'PowerManager' in self.parent.Plugins.get_loaded() and \
not self.parent.Plugins.PowerManager.get_bluetooth_status():
self._item.set_sensitive(False)
for mitem in self._mitems:
mitem.set_sensitive(False)
return

self._items = self._get_items()
items = self._get_items()

if len(self._items) == 0:
self._item.set_sensitive(False)
if len(items) == 0:
for mitem in self._mitems:
mitem.set_sensitive(False)
return

self._item.set_sensitive(True)
for mitem in self._mitems:
mitem.set_sensitive(True)

self.__menuitems = [self._build_menu_item(item) for item in self._items[:self.get_option("max-items")]]
self.__menuitems = [self._build_menu_item(item) for item in items[:self.get_option("max-items")]]

self.parent.Plugins.Menu.on_menu_changed()
self._rebuild_menu()

def on_manager_state_changed(self, state: bool) -> None:
if state:
self._rebuild()
else:
self._item.set_sensitive(False)
for mitem in self._mitems:
mitem.set_sensitive(False)

def on_device_created(self, path: str) -> None:
self._rebuild()
Expand Down Expand Up @@ -181,8 +180,15 @@ def _build_menu_item(self, item: "Item") -> "SubmenuItemDict":

return mitem

def get_menu(self) -> List["SubmenuItemDict"]:
return self.__menuitems
def _rebuild_menu(self) -> None:
menu: "Menu" = self.parent.Plugins.Menu
self._mitems = []
menu.unregister(self)
menu.add(self, 52, text=_("Recent _Connections"), icon_name="document-open-recent-symbolic",
sensitive=False, callback=lambda: None)
for (idx, item) in enumerate(self.__menuitems):
self._mitems.append(menu.add(self, (53, idx), **item))
menu.add(self, 59)

def _get_device_path(self, adapter_path: str, address: str) -> Optional[str]:
try:
Expand Down

0 comments on commit 46cd283

Please sign in to comment.