diff --git a/blueman/gui/manager/ManagerDeviceList.py b/blueman/gui/manager/ManagerDeviceList.py index 15a1d4e3f..804780dba 100644 --- a/blueman/gui/manager/ManagerDeviceList.py +++ b/blueman/gui/manager/ManagerDeviceList.py @@ -5,6 +5,7 @@ import cairo import os +from blueman.bluez.Adapter import Adapter from blueman.bluez.Battery import Battery from blueman.bluez.Device import Device from blueman.bluez.Manager import Manager @@ -242,7 +243,7 @@ def on_event_clicked(self, _widget: Gtk.Widget, event: Gdk.Event) -> bool: if self.menu.show_generic_connect_calc(row["device"]['UUIDs']): if row["connected"]: self.menu.disconnect_service(row["device"]) - else: + elif Adapter(obj_path=row["device"]["Adapter"])["Powered"]: self.menu.connect_service(row["device"]) if event.type == Gdk.EventType.BUTTON_PRESS and cast(Gdk.EventButton, event).button == 3: diff --git a/blueman/gui/manager/ManagerDeviceMenu.py b/blueman/gui/manager/ManagerDeviceMenu.py index 3bed94c81..69d81c1d6 100644 --- a/blueman/gui/manager/ManagerDeviceMenu.py +++ b/blueman/gui/manager/ManagerDeviceMenu.py @@ -5,6 +5,7 @@ from typing import Dict, List, Tuple, Optional, TYPE_CHECKING, Union, Iterable from blueman.Functions import create_menuitem, e_ +from blueman.bluez.Adapter import Adapter from blueman.bluez.Network import AnyNetwork from blueman.bluez.Device import AnyDevice, Device from blueman.config.AutoConnectConfig import AutoConnectConfig @@ -46,7 +47,13 @@ def __init__(self, item: Gtk.MenuItem, group: Group, position: int): class MenuItemsProvider: - def on_request_menu_items(self, _manager_menu: "ManagerDeviceMenu", _device: Device) -> List[DeviceMenuItem]: + def on_request_menu_items( + self, + _manager_menu: + "ManagerDeviceMenu", + _device: Device, + _powered: bool, + ) -> List[DeviceMenuItem]: return [] @@ -282,13 +289,15 @@ def generate(self) -> None: show_generic_connect = self.show_generic_connect_calc(self.SelectedDevice['UUIDs']) - if not row["connected"] and show_generic_connect: + powered = Adapter(obj_path=self.SelectedDevice["Adapter"])["Powered"] + + if not row["connected"] and show_generic_connect and powered: connect_item = create_menuitem(_("_Connect"), "bluetooth-symbolic") connect_item.connect("activate", lambda _item: self.connect_service(self.SelectedDevice)) connect_item.props.tooltip_text = _("Connects auto connect profiles A2DP source, A2DP sink, and HID") connect_item.show() self.append(connect_item) - elif show_generic_connect: + elif row["connected"] and show_generic_connect: connect_item = create_menuitem(_("_Disconnect"), "bluetooth-disabled-symbolic") connect_item.props.tooltip_text = _("Forcefully disconnect the device") connect_item.connect("activate", lambda _item: self.disconnect_service(self.SelectedDevice)) @@ -298,7 +307,7 @@ def generate(self) -> None: logging.debug(row["alias"]) items = [item for plugin in self.Blueman.Plugins.get_loaded_plugins(MenuItemsProvider) - for item in plugin.on_request_menu_items(self, self.SelectedDevice)] + for item in plugin.on_request_menu_items(self, self.SelectedDevice, powered)] connect_items = [i for i in items if i.group == DeviceMenuItem.Group.CONNECT] disconnect_items = [i for i in items if i.group == DeviceMenuItem.Group.DISCONNECT] @@ -332,7 +341,7 @@ def generate(self) -> None: for it in sorted(autoconnect_items, key=attrgetter("position")): self.append(it.item) - if show_generic_connect or connect_items or disconnect_items or autoconnect_items: + if (powered and show_generic_connect) or connect_items or disconnect_items or autoconnect_items: item = Gtk.SeparatorMenuItem() item.show() self.append(item) @@ -340,18 +349,19 @@ def generate(self) -> None: for it in sorted(action_items, key=attrgetter("position")): self.append(it.item) - send_item = create_menuitem(_("Send a _File…"), "blueman-send-symbolic") - send_item.props.sensitive = False - self.append(send_item) - send_item.show() + if powered: + send_item = create_menuitem(_("Send a _File…"), "blueman-send-symbolic") + send_item.props.sensitive = False + self.append(send_item) + send_item.show() - if row["objpush"]: - send_item.connect("activate", lambda x: self.Blueman.send(self.SelectedDevice)) - send_item.props.sensitive = True + if row["objpush"]: + send_item.connect("activate", lambda x: self.Blueman.send(self.SelectedDevice)) + send_item.props.sensitive = True - item = Gtk.SeparatorMenuItem() - item.show() - self.append(item) + item = Gtk.SeparatorMenuItem() + item.show() + self.append(item) item = create_menuitem(_("_Pair"), "blueman-pair-symbolic") item.props.tooltip_text = _("Create pairing with the device") diff --git a/blueman/gui/manager/ManagerMenu.py b/blueman/gui/manager/ManagerMenu.py index 8364cd7f2..2c399dc9e 100644 --- a/blueman/gui/manager/ManagerMenu.py +++ b/blueman/gui/manager/ManagerMenu.py @@ -56,6 +56,8 @@ def __init__(self, blueman: "Blueman"): item_unnamed = blueman.builder.get_widget("hide_unnamed_item", Gtk.CheckMenuItem) self.blueman.Config.bind("hide-unnamed", item_unnamed, "active", Gio.SettingsBindFlags.DEFAULT) + self.device_menu: Optional[ManagerDeviceMenu] = None + self._sort_alias_item = blueman.builder.get_widget("sort_name_item", Gtk.CheckMenuItem) self._sort_timestamp_item = blueman.builder.get_widget("sort_added_item", Gtk.CheckMenuItem) @@ -105,8 +107,6 @@ def __init__(self, blueman: "Blueman"): for adapter in self._manager.get_adapters(): self.on_adapter_added(None, adapter.get_object_path()) - self.device_menu: Optional[ManagerDeviceMenu] = None - self.Config.connect("changed", self._on_settings_changed) self._sort_alias_item.connect("activate", self._on_sorting_changed, "alias") self._sort_timestamp_item.connect("activate", self._on_sorting_changed, "timestamp") @@ -229,6 +229,9 @@ def on_adapter_removed(self, _manager: Manager, adapter_path: str) -> None: self._update_power() def _update_power(self) -> None: + if self.device_menu is not None: + self.device_menu.generate() + if any(adapter["Powered"] for (_, adapter) in self.adapter_items.values()): self.Search.props.visible = True self._adapter_settings.props.visible = True diff --git a/blueman/gui/manager/ManagerToolbar.py b/blueman/gui/manager/ManagerToolbar.py index 9ecb4b6a7..c042b8d61 100644 --- a/blueman/gui/manager/ManagerToolbar.py +++ b/blueman/gui/manager/ManagerToolbar.py @@ -56,52 +56,39 @@ def on_action(self, _button: Gtk.ToolButton, func: Callable[[Device], None]) -> if device is not None: func(device) - def on_adapter_property_changed(self, _lst: ManagerDeviceList, _adapter: Adapter, + def on_adapter_property_changed(self, _lst: ManagerDeviceList, adapter: Adapter, key_value: Tuple[str, object]) -> None: key, value = key_value - if key == "Discovering": - if value: - self.b_search.props.sensitive = False - else: - self.b_search.props.sensitive = True + if key == "Discovering" or key == "Powered": + self._update_buttons(adapter) def on_adapter_changed(self, _lst: ManagerDeviceList, adapter_path: Optional[str]) -> None: logging.debug(f"toolbar adapter {adapter_path}") - if adapter_path is None: - self.b_search.props.sensitive = False - self.b_send.props.sensitive = False - else: - self.b_search.props.sensitive = True + self._update_buttons(None if adapter_path is None else Adapter(obj_path=adapter_path)) + + def on_device_selected(self, dev_list: ManagerDeviceList, device: Device, _tree_iter: Gtk.TreeIter) -> None: + self._update_buttons(Adapter(obj_path=device["Adapter"])) + + def _update_buttons(self, adapter: Optional[Adapter]) -> None: + powered = adapter is not None and adapter["Powered"] + self.b_search.props.sensitive = powered and not (adapter and adapter["Discovering"]) - def on_device_selected(self, dev_list: ManagerDeviceList, device: Device, tree_iter: Gtk.TreeIter) -> None: - if device is None or tree_iter is None: + tree_iter = self.blueman.List.selected() + if tree_iter is None: self.b_bond.props.sensitive = False - self.b_remove.props.sensitive = False self.b_trust.props.sensitive = False + self.b_remove.props.sensitive = False + self.b_send.props.sensitive = False else: - row = dev_list.get(tree_iter, "paired", "trusted", "objpush") + row = self.blueman.List.get(tree_iter, "paired", "trusted", "objpush") + self.b_bond.props.sensitive = powered and not row["paired"] + self.b_trust.props.sensitive = True self.b_remove.props.sensitive = True - if row["paired"]: - self.b_bond.props.sensitive = False - else: - self.b_bond.props.sensitive = True - - if row["trusted"]: - image = Gtk.Image(icon_name="blueman-untrust-symbolic", pixel_size=24, visible=True) - self.b_trust.props.icon_widget = image - self.b_trust.props.sensitive = True - self.b_trust.props.label = _("Untrust") - - else: - image = Gtk.Image(icon_name="blueman-trust-symbolic", pixel_size=24, visible=True) - self.b_trust.props.icon_widget = image - self.b_trust.props.sensitive = True - self.b_trust.props.label = _("Trust") - - if row["objpush"]: - self.b_send.props.sensitive = True - else: - self.b_send.props.sensitive = False + self.b_send.props.sensitive = powered and row["objpush"] + + icon_name = "blueman-untrust-symbolic" if row["trusted"] else "blueman-trust-symbolic" + self.b_trust.props.icon_widget = Gtk.Image(icon_name=icon_name, pixel_size=24, visible=True) + self.b_trust.props.label = _("Untrust") if row["trusted"] else _("Trust") def on_device_propery_changed(self, dev_list: ManagerDeviceList, device: Device, tree_iter: Gtk.TreeIter, key_value: Tuple[str, object]) -> None: diff --git a/blueman/plugins/manager/Info.py b/blueman/plugins/manager/Info.py index e23342acc..b1a518609 100644 --- a/blueman/plugins/manager/Info.py +++ b/blueman/plugins/manager/Info.py @@ -116,7 +116,12 @@ def on_accel_activated(_group: Gtk.AccelGroup, _dialog: GObject, key: int, _modi class Info(ManagerPlugin, MenuItemsProvider): - def on_request_menu_items(self, manager_menu: ManagerDeviceMenu, device: Device) -> List[DeviceMenuItem]: + def on_request_menu_items( + self, + manager_menu: ManagerDeviceMenu, + device: Device, + _powered: bool, + ) -> List[DeviceMenuItem]: item = create_menuitem(_("_Info"), "dialog-information-symbolic") item.props.tooltip_text = _("Show device information") _window = manager_menu.get_toplevel() diff --git a/blueman/plugins/manager/Notes.py b/blueman/plugins/manager/Notes.py index 9dc59a6a3..3222f186b 100644 --- a/blueman/plugins/manager/Notes.py +++ b/blueman/plugins/manager/Notes.py @@ -47,7 +47,15 @@ def send_note(device: Device, parent: Gtk.ApplicationWindow) -> None: class Notes(ManagerPlugin, MenuItemsProvider): - def on_request_menu_items(self, manager_menu: ManagerDeviceMenu, device: Device) -> List[DeviceMenuItem]: + def on_request_menu_items( + self, + manager_menu: ManagerDeviceMenu, + device: Device, + powered: bool, + ) -> List[DeviceMenuItem]: + if not powered: + return [] + item = create_menuitem(_("Send _note"), "dialog-information-symbolic") item.props.tooltip_text = _("Send a text note") assert isinstance(manager_menu.Blueman.window, Gtk.ApplicationWindow) diff --git a/blueman/plugins/manager/PulseAudioProfile.py b/blueman/plugins/manager/PulseAudioProfile.py index 6c8f6beea..f1ffa34cf 100644 --- a/blueman/plugins/manager/PulseAudioProfile.py +++ b/blueman/plugins/manager/PulseAudioProfile.py @@ -110,7 +110,12 @@ def generate_menu(self, device: Device, item: Gtk.MenuItem) -> None: item.set_submenu(sub) item.show() - def on_request_menu_items(self, manager_menu: ManagerDeviceMenu, device: Device) -> List[DeviceMenuItem]: + def on_request_menu_items( + self, + manager_menu: ManagerDeviceMenu, + device: Device, + _powered: bool, + ) -> List[DeviceMenuItem]: audio_source = False for uuid in device['UUIDs']: if ServiceUUID(uuid).short_uuid in (AUDIO_SOURCE_SVCLASS_ID, AUDIO_SINK_SVCLASS_ID): diff --git a/blueman/plugins/manager/Services.py b/blueman/plugins/manager/Services.py index 4a975e0fa..5aaf6c7ba 100644 --- a/blueman/plugins/manager/Services.py +++ b/blueman/plugins/manager/Services.py @@ -39,21 +39,27 @@ def _make_x_icon(self, icon_name: str, size: int) -> cairo.ImageSurface: return target - def on_request_menu_items(self, manager_menu: ManagerDeviceMenu, device: Device) -> List[DeviceMenuItem]: + def on_request_menu_items( + self, + manager_menu: ManagerDeviceMenu, + device: Device, + powered: bool, + ) -> List[DeviceMenuItem]: items: List[DeviceMenuItem] = [] appl = AppletService() services = get_services(device) - connectable_services = [service for service in services if service.connectable] - for service in connectable_services: - item: Gtk.MenuItem = create_menuitem(service.name, service.icon) - if service.description: - item.props.tooltip_text = service.description - item.connect("activate", lambda _item: manager_menu.connect_service(service.device, service.uuid)) - items.append(DeviceMenuItem(item, DeviceMenuItem.Group.CONNECT, service.priority)) - item.props.sensitive = service.available - item.show() + if powered: + connectable_services = [service for service in services if service.connectable] + for service in connectable_services: + item: Gtk.MenuItem = create_menuitem(service.name, service.icon) + if service.description: + item.props.tooltip_text = service.description + item.connect("activate", lambda _item: manager_menu.connect_service(service.device, service.uuid)) + items.append(DeviceMenuItem(item, DeviceMenuItem.Group.CONNECT, service.priority)) + item.props.sensitive = service.available + item.show() connected_services = [service for service in services if service.connected_instances] for service in connected_services: