Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Respect adapter power state in manager #2183

Merged
merged 4 commits into from
Nov 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion blueman/gui/manager/ManagerDeviceList.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down
40 changes: 25 additions & 15 deletions blueman/gui/manager/ManagerDeviceMenu.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 []


Expand Down Expand Up @@ -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(_("<b>_Connect</b>"), "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(_("<b>_Disconnect</b>"), "bluetooth-disabled-symbolic")
connect_item.props.tooltip_text = _("Forcefully disconnect the device")
connect_item.connect("activate", lambda _item: self.disconnect_service(self.SelectedDevice))
Expand All @@ -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]
Expand Down Expand Up @@ -332,26 +341,27 @@ 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)

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")
Expand Down
7 changes: 5 additions & 2 deletions blueman/gui/manager/ManagerMenu.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -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
Expand Down
59 changes: 23 additions & 36 deletions blueman/gui/manager/ManagerToolbar.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
7 changes: 6 additions & 1 deletion blueman/plugins/manager/Info.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
10 changes: 9 additions & 1 deletion blueman/plugins/manager/Notes.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
7 changes: 6 additions & 1 deletion blueman/plugins/manager/PulseAudioProfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
26 changes: 16 additions & 10 deletions blueman/plugins/manager/Services.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
Loading