From db2aab0a1f8056b358b3130a1efa4d8e1bd53e5f Mon Sep 17 00:00:00 2001 From: Sander Sweers Date: Mon, 9 Oct 2023 18:50:59 +0200 Subject: [PATCH 1/3] drop flake8 as it's incompatible with black --- .github/workflows/check.yml | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 833f0ed60..642afd8fa 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -21,24 +21,6 @@ jobs: - run: meson --warnlevel 3 --buildtype debug -Druntime_deps_check=false builddebug - run: ninja -v -C builddebug/ - flake8: - strategy: - fail-fast: false - matrix: - python: - - "3.8" - - "3.9" - - "3.10" - - "3.11" - - "3.12-rc" - runs-on: ubuntu-latest - container: - image: python:${{ matrix.python }} - steps: - - uses: actions/checkout@v2 - - run: python3 -m pip install --user flake8 - - run: python3 -m flake8 - mypy: strategy: fail-fast: false From 1d58b798ad3083ffd0fe56388772182941ecb188 Mon Sep 17 00:00:00 2001 From: Sander Sweers Date: Mon, 9 Oct 2023 18:54:54 +0200 Subject: [PATCH 2/3] Add black workflow --- .github/workflows/black.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .github/workflows/black.yml diff --git a/.github/workflows/black.yml b/.github/workflows/black.yml new file mode 100644 index 000000000..d6f9dff51 --- /dev/null +++ b/.github/workflows/black.yml @@ -0,0 +1,13 @@ +name: Lint + +on: [push, pull_request] + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: psf/black@stable + with: + options: "--check --verbose --line-length 120 -t py38 -t py39 -t py310 -t py311 -t py312" + src: "./blueman/" From b526b738add29336eb919fe697dea2c544516137 Mon Sep 17 00:00:00 2001 From: Sander Sweers Date: Mon, 9 Oct 2023 19:09:44 +0200 Subject: [PATCH 3/3] Big re-format by black. --- apps/blueman-adapters.in | 8 +- apps/blueman-applet.in | 6 +- apps/blueman-manager.in | 8 +- apps/blueman-mechanism.in | 9 +- apps/blueman-rfcomm-watcher.in | 3 +- apps/blueman-sendto.in | 41 +++-- apps/blueman-services.in | 8 +- apps/blueman-tray.in | 4 +- blueman/DeviceClass.py | 158 +++++++++------- blueman/Functions.py | 62 ++++--- blueman/Sdp.py | 142 +++++++-------- blueman/bluemantyping.py | 1 + blueman/bluez/Adapter.py | 16 +- blueman/bluez/AgentManager.py | 16 +- blueman/bluez/AnyBase.py | 10 +- blueman/bluez/Base.py | 55 +++--- blueman/bluez/Device.py | 10 +- blueman/bluez/Manager.py | 75 ++++---- blueman/bluez/Network.py | 10 +- blueman/bluez/NetworkServer.py | 10 +- blueman/bluez/errors.py | 46 ++--- blueman/bluez/obex/AgentManager.py | 12 +- blueman/bluez/obex/Base.py | 2 +- blueman/bluez/obex/Client.py | 19 +- blueman/bluez/obex/Manager.py | 43 ++--- blueman/bluez/obex/ObjectPush.py | 21 ++- blueman/bluez/obex/Session.py | 6 +- blueman/bluez/obex/Transfer.py | 27 +-- blueman/config/AutoConnectConfig.py | 1 + blueman/gui/Animation.py | 1 + blueman/gui/CommonUi.py | 61 ++++--- blueman/gui/DeviceList.py | 98 ++++++---- blueman/gui/DeviceSelectorDialog.py | 15 +- blueman/gui/DeviceSelectorList.py | 40 +++-- blueman/gui/DeviceSelectorWidget.py | 42 +++-- blueman/gui/GenericList.py | 7 +- blueman/gui/GsmSettings.py | 4 +- blueman/gui/GtkAnimation.py | 10 +- blueman/gui/Notification.py | 155 +++++++++------- blueman/gui/applet/PluginDialog.py | 53 +++--- blueman/gui/manager/ManagerDeviceList.py | 168 ++++++++++++------ blueman/gui/manager/ManagerDeviceMenu.py | 86 +++++---- blueman/gui/manager/ManagerMenu.py | 31 ++-- blueman/gui/manager/ManagerProgressbar.py | 2 +- blueman/gui/manager/ManagerStats.py | 21 ++- blueman/gui/manager/ManagerToolbar.py | 10 +- blueman/main/Adapter.py | 61 ++++--- blueman/main/Applet.py | 20 ++- blueman/main/BatteryWatcher.py | 8 +- blueman/main/DBusProxies.py | 54 +++--- blueman/main/DNSServerProvider.py | 24 +-- blueman/main/DbusService.py | 87 ++++++--- blueman/main/DhcpClient.py | 7 +- blueman/main/Manager.py | 47 +++-- blueman/main/MechanismApplication.py | 16 +- blueman/main/NetConf.py | 86 +++++---- blueman/main/NetworkManager.py | 59 +++--- blueman/main/PPPConnection.py | 52 +++--- blueman/main/PluginManager.py | 30 ++-- blueman/main/PulseAudioUtils.py | 106 +++++------ blueman/main/Sendto.py | 36 ++-- blueman/main/Services.py | 1 + blueman/main/Tray.py | 25 +-- blueman/main/applet/BluezAgent.py | 94 ++++++---- blueman/main/indicators/GtkStatusIcon.py | 33 ++-- blueman/main/indicators/StatusNotifierItem.py | 68 +++++-- blueman/plugins/AppletPlugin.py | 11 +- blueman/plugins/BasePlugin.py | 4 +- blueman/plugins/ServicePlugin.py | 2 +- blueman/plugins/applet/AutoConnect.py | 20 +-- blueman/plugins/applet/ConnectionNotifier.py | 6 +- blueman/plugins/applet/DBusService.py | 63 ++++--- blueman/plugins/applet/DhcpClient.py | 27 ++- blueman/plugins/applet/DisconnectItems.py | 10 +- blueman/plugins/applet/DiscvManager.py | 22 ++- blueman/plugins/applet/ExitItem.py | 5 +- .../plugins/applet/GameControllerWakelock.py | 9 +- blueman/plugins/applet/KillSwitch.py | 50 +++--- blueman/plugins/applet/Menu.py | 90 +++++++--- blueman/plugins/applet/NMDUNSupport.py | 10 +- blueman/plugins/applet/NMPANSupport.py | 10 +- blueman/plugins/applet/NetUsage.py | 90 +++++++--- blueman/plugins/applet/Networking.py | 21 ++- blueman/plugins/applet/PPPSupport.py | 40 +++-- blueman/plugins/applet/PowerManager.py | 22 +-- blueman/plugins/applet/PulseAudioProfile.py | 54 +++--- blueman/plugins/applet/RecentConns.py | 93 +++++----- blueman/plugins/applet/SerialManager.py | 53 +++--- blueman/plugins/applet/ShowConnected.py | 18 +- blueman/plugins/applet/StandardItems.py | 37 ++-- blueman/plugins/applet/StatusIcon.py | 32 ++-- blueman/plugins/applet/TransferService.py | 141 +++++++++------ blueman/plugins/manager/Info.py | 52 +++--- blueman/plugins/manager/Notes.py | 33 ++-- blueman/plugins/manager/PulseAudioProfile.py | 27 ++- blueman/plugins/manager/Services.py | 11 +- blueman/plugins/mechanism/Network.py | 12 +- blueman/plugins/mechanism/Ppp.py | 5 +- blueman/plugins/mechanism/RfKill.py | 4 +- blueman/plugins/mechanism/Rfcomm.py | 2 +- blueman/plugins/services/Network.py | 29 ++- blueman/plugins/services/Transfer.py | 2 +- blueman/services/DialupNetwork.py | 9 +- blueman/services/Functions.py | 2 +- blueman/services/meta/NetworkService.py | 11 +- blueman/services/meta/SerialService.py | 36 ++-- 106 files changed, 2202 insertions(+), 1520 deletions(-) diff --git a/apps/blueman-adapters.in b/apps/blueman-adapters.in index a8e9f4d98..06522c443 100755 --- a/apps/blueman-adapters.in +++ b/apps/blueman-adapters.in @@ -6,9 +6,9 @@ import gettext # support running uninstalled -_dirname = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) -if 'BLUEMAN_SOURCE' in os.environ: - sys.path = [_dirname, os.path.join(_dirname, 'module', '.libs')] + sys.path +_dirname = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) +if "BLUEMAN_SOURCE" in os.environ: + sys.path = [_dirname, os.path.join(_dirname, "module", ".libs")] + sys.path os.environ["GSETTINGS_SCHEMA_DIR"] = os.path.join(_dirname, "data") gettext.textdomain("@GETTEXT_PACKAGE@") @@ -17,7 +17,7 @@ from blueman.Functions import create_parser, create_logger, set_proc_title from blueman.main.Adapter import BluemanAdapters -if __name__ == '__main__': +if __name__ == "__main__": parser = parser = create_parser() parser.add_argument("--socket-id", dest="socket_id", action="store", type=int, metavar="ID") parser.add_argument("adapter", nargs="?", metavar="ADAPTER NAME") diff --git a/apps/blueman-applet.in b/apps/blueman-applet.in index 1b18d9b4e..65713c164 100755 --- a/apps/blueman-applet.in +++ b/apps/blueman-applet.in @@ -6,8 +6,8 @@ import gettext # support running uninstalled _dirname = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) -if 'BLUEMAN_SOURCE' in os.environ: - sys.path = [_dirname, os.path.join(_dirname, 'module', '.libs')] + sys.path +if "BLUEMAN_SOURCE" in os.environ: + sys.path = [_dirname, os.path.join(_dirname, "module", ".libs")] + sys.path os.environ["GSETTINGS_SCHEMA_DIR"] = os.path.join(_dirname, "data") gettext.textdomain("@GETTEXT_PACKAGE@") @@ -16,7 +16,7 @@ from blueman.Functions import create_logger, create_parser, set_proc_title from blueman.main.Applet import BluemanApplet -if __name__ == '__main__': +if __name__ == "__main__": parser = create_parser() args = parser.parse_args() diff --git a/apps/blueman-manager.in b/apps/blueman-manager.in index b29921caf..2bf7e6811 100755 --- a/apps/blueman-manager.in +++ b/apps/blueman-manager.in @@ -5,9 +5,9 @@ import logging import gettext # support running uninstalled -_dirname = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) -if 'BLUEMAN_SOURCE' in os.environ: - sys.path = [_dirname, os.path.join(_dirname, 'module', '.libs')] + sys.path +_dirname = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) +if "BLUEMAN_SOURCE" in os.environ: + sys.path = [_dirname, os.path.join(_dirname, "module", ".libs")] + sys.path os.environ["GSETTINGS_SCHEMA_DIR"] = os.path.join(_dirname, "data") gettext.textdomain("@GETTEXT_PACKAGE@") @@ -16,7 +16,7 @@ from blueman.main.Manager import Blueman from blueman.Functions import set_proc_title, create_parser, create_logger -if __name__ == '__main__': +if __name__ == "__main__": parser = create_parser() args = parser.parse_args() diff --git a/apps/blueman-mechanism.in b/apps/blueman-mechanism.in index f369090ee..e0a34badb 100755 --- a/apps/blueman-mechanism.in +++ b/apps/blueman-mechanism.in @@ -6,9 +6,9 @@ import logging from blueman.main.MechanismApplication import MechanismApplication # support running uninstalled -_dirname = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) -if 'BLUEMAN_SOURCE' in os.environ: - sys.path = [_dirname, os.path.join(_dirname, 'module', '.libs')] + sys.path +_dirname = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) +if "BLUEMAN_SOURCE" in os.environ: + sys.path = [_dirname, os.path.join(_dirname, "module", ".libs")] + sys.path os.environ["GSETTINGS_SCHEMA_DIR"] = os.path.join(_dirname, "data") from blueman.Functions import set_proc_title, create_logger, create_parser @@ -18,10 +18,11 @@ class StreamToLogger: """ Fake file-like stream object that redirects writes to a logger instance. """ + def __init__(self, logger, log_level=logging.INFO): self.logger = logger self.log_level = log_level - self.linebuf = '' + self.linebuf = "" def write(self, buf): for line in buf.rstrip().splitlines(): diff --git a/apps/blueman-rfcomm-watcher.in b/apps/blueman-rfcomm-watcher.in index 36e7c7604..b69ef3bb9 100755 --- a/apps/blueman-rfcomm-watcher.in +++ b/apps/blueman-rfcomm-watcher.in @@ -12,12 +12,13 @@ def on_file_changed(monitor, file, other_file, event_type): if event_type == Gio.FileMonitorEvent.DELETED: loop.quit() + parser = argparse.ArgumentParser() parser.add_argument("path", action="store") args = parser.parse_args() mon = Gio.File.new_for_path(args.path).monitor_file(Gio.FileMonitorFlags.NONE) -mon.connect('changed', on_file_changed) +mon.connect("changed", on_file_changed) fd = open_rfcomm(args.path, os.O_RDONLY) diff --git a/apps/blueman-sendto.in b/apps/blueman-sendto.in index dfc6e1555..4a9e08974 100755 --- a/apps/blueman-sendto.in +++ b/apps/blueman-sendto.in @@ -7,13 +7,14 @@ import logging import gettext import gi + gi.require_version("Gtk", "3.0") from gi.repository import Gtk, Gio # support running uninstalled -_dirname = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) -if 'BLUEMAN_SOURCE' in os.environ: - sys.path = [_dirname, os.path.join(_dirname, 'module', '.libs')] + sys.path +_dirname = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) +if "BLUEMAN_SOURCE" in os.environ: + sys.path = [_dirname, os.path.join(_dirname, "module", ".libs")] + sys.path os.environ["GSETTINGS_SCHEMA_DIR"] = os.path.join(_dirname, "data") _ = gettext.gettext @@ -25,7 +26,7 @@ from blueman.Functions import ( set_proc_title, create_parser, create_logger, - bmexit + bmexit, ) from blueman.main.Sendto import Sender from blueman.bluez.Manager import Manager @@ -73,9 +74,11 @@ class SendTo: self.adapter_path = adapter.get_object_path() if parsed_args.delete: + def delete_files(): for file in self.files: os.unlink(file) + atexit.register(delete_files) if parsed_args.device is None: @@ -106,7 +109,9 @@ class SendTo: @staticmethod def select_files(): - d = Gtk.FileChooserDialog(title=_("Select files to send"), icon_name='blueman-send-symbolic', select_multiple=True) + d = Gtk.FileChooserDialog( + title=_("Select files to send"), icon_name="blueman-send-symbolic", select_multiple=True + ) d.add_buttons(_("_Cancel"), Gtk.ResponseType.REJECT, _("_OK"), Gtk.ResponseType.ACCEPT) resp = d.run() @@ -133,15 +138,27 @@ class SendTo: return False -if __name__ == '__main__': +if __name__ == "__main__": parser = create_parser(syslog=True) - parser.add_argument("-d", "--device", "--dest", dest="device", action="store", - help=_("Send files to this device"), metavar="ADDRESS") - parser.add_argument("-s", "--source", dest="source", action="store", - help=_("Source adapter. Takes address or adapter's name eg. hci0"), metavar="PATTERN") + parser.add_argument( + "-d", + "--device", + "--dest", + dest="device", + action="store", + help=_("Send files to this device"), + metavar="ADDRESS", + ) + parser.add_argument( + "-s", + "--source", + dest="source", + action="store", + help=_("Source adapter. Takes address or adapter's name eg. hci0"), + metavar="PATTERN", + ) parser.add_argument("-u", "--delete", dest="delete", action="store_true", help=_("Delete files on exit")) - parser.add_argument("files", nargs="*", metavar="FILE", - help=_("Files to be send to the bluetooth device")) + parser.add_argument("files", nargs="*", metavar="FILE", help=_("Files to be send to the bluetooth device")) args = parser.parse_args() diff --git a/apps/blueman-services.in b/apps/blueman-services.in index 8a5fb6e79..bccb7943d 100755 --- a/apps/blueman-services.in +++ b/apps/blueman-services.in @@ -7,9 +7,9 @@ import signal import gettext # support running uninstalled -_dirname = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) -if 'BLUEMAN_SOURCE' in os.environ: - sys.path = [_dirname, os.path.join(_dirname, 'module', '.libs')] + sys.path +_dirname = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) +if "BLUEMAN_SOURCE" in os.environ: + sys.path = [_dirname, os.path.join(_dirname, "module", ".libs")] + sys.path os.environ["GSETTINGS_SCHEMA_DIR"] = os.path.join(_dirname, "data") _ = gettext.gettext @@ -19,7 +19,7 @@ from blueman.Functions import set_proc_title, setup_icon_path, create_logger, cr from blueman.main.Services import BluemanServices -if __name__ == '__main__': +if __name__ == "__main__": parser = create_parser() args = parser.parse_args() diff --git a/apps/blueman-tray.in b/apps/blueman-tray.in index 142b6b496..08e50b9e2 100755 --- a/apps/blueman-tray.in +++ b/apps/blueman-tray.in @@ -6,7 +6,7 @@ import gettext # support running uninstalled _dirname = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) -if 'BLUEMAN_SOURCE' in os.environ: +if "BLUEMAN_SOURCE" in os.environ: sys.path.insert(0, _dirname) gettext.textdomain("@GETTEXT_PACKAGE@") @@ -15,7 +15,7 @@ from blueman.Functions import set_proc_title, create_parser, create_logger from blueman.main.Tray import BluemanTray -if __name__ == '__main__': +if __name__ == "__main__": parser = create_parser() args = parser.parse_args() diff --git a/blueman/DeviceClass.py b/blueman/DeviceClass.py index 2a998f93c..c2fb5d878 100644 --- a/blueman/DeviceClass.py +++ b/blueman/DeviceClass.py @@ -21,7 +21,7 @@ # translators: device class _("Toy"), # translators: device class - _("Uncategorized") + _("Uncategorized"), ) computer_minor_cls = ( @@ -38,7 +38,7 @@ # translators: device class _("Palm"), # translators: device class - _("Wearable") + _("Wearable"), ) phone_minor_cls = ( @@ -53,7 +53,7 @@ # translators: device class _("Modem"), # translators: device class - _("ISDN") + _("ISDN"), ) access_point_minor_cls = ( @@ -72,7 +72,7 @@ # translators: device class _("83–99 percent"), # translators: device class - _("Not available") + _("Not available"), ) audio_video_minor_cls = ( @@ -113,7 +113,7 @@ # translators: device class _("Unknown"), # translators: device class - _("Gaming/Toy") + _("Gaming/Toy"), ) peripheral_minor_cls = ( @@ -124,7 +124,7 @@ # translators: device class _("Pointing"), # translators: device class - _("Combo") + _("Combo"), ) imaging_minor_cls = ( @@ -135,7 +135,7 @@ # translators: device class _("Scanner"), # translators: device class - _("Printer") + _("Printer"), ) wearable_minor_cls = ( @@ -148,7 +148,7 @@ # translators: device class _("Helmet"), # translators: device class - _("Glasses") + _("Glasses"), ) toy_minor_cls = ( @@ -161,70 +161,92 @@ # translators: device class _("Controller"), # translators: device class - _("Game") + _("Game"), ) gatt_appearance_categories = { - 0: ('Unknown', {0: _("Unknown")}), - 1: ('Phone', {0: _("Generic Phone")}), - 2: ('Computer', {0: _("Generic Computer")}), - 3: ('Watch', {0: _("Generic Watch"), - 1: _("Watch: Sports Watch")}), - 4: ('Clock', {0: _("Generic Clock")}), - 5: ('Display', {0: _("Generic Display")}), - 6: ('Remote Control', {0: _("Generic Remote Control")}), - 7: ('Eye-glasses', {0: _("Generic Eye-glasses")}), - 8: ('Tag', {0: _("Generic Tag")}), - 9: ('Keyring', {0: _("Generic Keyring")}), - 10: ('Media Player', {0: _("Generic Media Player")}), - 11: ('Barcode Scanner', {0: _("Generic Barcode Scanner")}), - 12: ('Thermometer', {0: _("Generic Thermometer"), - 1: _("Thermometer: Ear")}), - 13: ('Heart rate Sensor', {0: _("Generic Heart rate Sensor"), - 1: _("Heart Rate Sensor: Heart Rate Belt")}), - 14: ('Blood Pressure', {0: _("Generic Blood Pressure"), - 1: _("Blood Pressure: Arm"), - 2: _("Blood Pressure: Wrist")}), - 15: ('Human Interface Device (HID)', {0: _("Human Interface Device (HID)"), - 1: _("Keyboard"), - 2: _("Mouse"), - 3: _("Joystick"), - 4: _("Gamepad"), - 5: _("Digitizer Tablet"), - 6: _("Card Reader"), - 7: _("Digital Pen"), - 8: _("Barcode Scanner")}), - 16: ('Glucose Meter', {0: _("Generic Glucose Meter")}), - 17: ('Running Walking Sensor', {0: _("Generic: Running Walking Sensor"), - 1: _("Running Walking Sensor: In-Shoe"), - 2: _("Running Walking Sensor: On-Shoe"), - 3: _("Running Walking Sensor: On-Hip")}), - 18: ('Cycling', {0: _("Generic: Cycling"), - 1: _("Cycling: Cycling Computer"), - 2: _("Cycling: Speed Sensor"), - 3: _("Cycling: Cadence Sensor"), - 4: _("Cycling: Power Sensor"), - 5: _("Cycling: Speed and Cadence Sensor")}), + 0: ("Unknown", {0: _("Unknown")}), + 1: ("Phone", {0: _("Generic Phone")}), + 2: ("Computer", {0: _("Generic Computer")}), + 3: ("Watch", {0: _("Generic Watch"), 1: _("Watch: Sports Watch")}), + 4: ("Clock", {0: _("Generic Clock")}), + 5: ("Display", {0: _("Generic Display")}), + 6: ("Remote Control", {0: _("Generic Remote Control")}), + 7: ("Eye-glasses", {0: _("Generic Eye-glasses")}), + 8: ("Tag", {0: _("Generic Tag")}), + 9: ("Keyring", {0: _("Generic Keyring")}), + 10: ("Media Player", {0: _("Generic Media Player")}), + 11: ("Barcode Scanner", {0: _("Generic Barcode Scanner")}), + 12: ("Thermometer", {0: _("Generic Thermometer"), 1: _("Thermometer: Ear")}), + 13: ("Heart rate Sensor", {0: _("Generic Heart rate Sensor"), 1: _("Heart Rate Sensor: Heart Rate Belt")}), + 14: ( + "Blood Pressure", + {0: _("Generic Blood Pressure"), 1: _("Blood Pressure: Arm"), 2: _("Blood Pressure: Wrist")}, + ), + 15: ( + "Human Interface Device (HID)", + { + 0: _("Human Interface Device (HID)"), + 1: _("Keyboard"), + 2: _("Mouse"), + 3: _("Joystick"), + 4: _("Gamepad"), + 5: _("Digitizer Tablet"), + 6: _("Card Reader"), + 7: _("Digital Pen"), + 8: _("Barcode Scanner"), + }, + ), + 16: ("Glucose Meter", {0: _("Generic Glucose Meter")}), + 17: ( + "Running Walking Sensor", + { + 0: _("Generic: Running Walking Sensor"), + 1: _("Running Walking Sensor: In-Shoe"), + 2: _("Running Walking Sensor: On-Shoe"), + 3: _("Running Walking Sensor: On-Hip"), + }, + ), + 18: ( + "Cycling", + { + 0: _("Generic: Cycling"), + 1: _("Cycling: Cycling Computer"), + 2: _("Cycling: Speed Sensor"), + 3: _("Cycling: Cadence Sensor"), + 4: _("Cycling: Power Sensor"), + 5: _("Cycling: Speed and Cadence Sensor"), + }, + ), # 19 - 48 reserved - 49: ('Pulse Oximeter', {0: _("Generic: Pulse Oximeter"), - 1: _("Fingertip"), - 2: _("Wrist-Worn")}), - 50: ('Weight Scale', {0: _("Generic: Weight Scale")}), - 51: ('Personal Mobility Device', {0: _("Generic Personal Mobility Device"), - 1: _("Powered Wheelchair"), - 2: _("Mobility Scooter")}), - 52: ('Continuous Glucose Monitor', {0: _("Generic Continuous Glucose Monitor")}), - 53: ('Insulin Pump', {0: _("Generic Insulin Pump"), - 1: _("Insulin Pump, durable pump"), - 4: _("Insulin Pump, patch pump"), - 8: _("Insulin Pen")}), - 54: ('Medication Delivery', {0: _("Generic Medication Delivery")}), + 49: ("Pulse Oximeter", {0: _("Generic: Pulse Oximeter"), 1: _("Fingertip"), 2: _("Wrist-Worn")}), + 50: ("Weight Scale", {0: _("Generic: Weight Scale")}), + 51: ( + "Personal Mobility Device", + {0: _("Generic Personal Mobility Device"), 1: _("Powered Wheelchair"), 2: _("Mobility Scooter")}, + ), + 52: ("Continuous Glucose Monitor", {0: _("Generic Continuous Glucose Monitor")}), + 53: ( + "Insulin Pump", + { + 0: _("Generic Insulin Pump"), + 1: _("Insulin Pump, durable pump"), + 4: _("Insulin Pump, patch pump"), + 8: _("Insulin Pen"), + }, + ), + 54: ("Medication Delivery", {0: _("Generic Medication Delivery")}), # 55 - 80 reserved - 81: ('Outdoor Sports Activity', {0: _("Generic: Outdoor Sports Activity"), - 1: _("Location Display Device"), - 2: _("Location and Navigation Display Device"), - 3: _("Location Pod"), - 4: _("Location and Navigation Pod")}) + 81: ( + "Outdoor Sports Activity", + { + 0: _("Generic: Outdoor Sports Activity"), + 1: _("Location Display Device"), + 2: _("Location and Navigation Display Device"), + 3: _("Location Pod"), + 4: _("Location and Navigation Pod"), + }, + ), } @@ -294,7 +316,7 @@ def get_minor_class(klass: int) -> str: # First 10 bits is the category, the following 6 bits sub category def gatt_appearance_to_name(appearance: int) -> str: cat = appearance >> 0x6 - subcat = appearance & 0x3f + subcat = appearance & 0x3F if (19 <= cat <= 48) or (55 <= cat <= 80): # These ranges are reserved diff --git a/blueman/Functions.py b/blueman/Functions.py index 018ffaed4..cef434310 100644 --- a/blueman/Functions.py +++ b/blueman/Functions.py @@ -40,6 +40,7 @@ from blueman.Constants import BIN_DIR, ICON_PATH import gi + gi.require_version("Gtk", "3.0") gi.require_version("Gdk", "3.0") from gi.repository import Gtk @@ -47,9 +48,22 @@ from gi.repository import GdkPixbuf from gi.repository import Gio -__all__ = ["check_bluetooth_status", "launch", "setup_icon_path", "adapter_path_to_name", "e_", "bmexit", - "format_bytes", "create_menuitem", "have", "set_proc_title", "create_logger", "create_parser", "open_rfcomm", - "get_local_interfaces"] +__all__ = [ + "check_bluetooth_status", + "launch", + "setup_icon_path", + "adapter_path_to_name", + "e_", + "bmexit", + "format_bytes", + "create_menuitem", + "have", + "set_proc_title", + "create_logger", + "create_parser", + "open_rfcomm", + "get_local_interfaces", +] def check_bluetooth_status(message: str, exitfunc: Callable[[], Any]) -> None: @@ -66,8 +80,8 @@ def check_bluetooth_status(message: str, exitfunc: Callable[[], Any]) -> None: if not applet.GetBluetoothStatus(): d = Gtk.MessageDialog( - type=Gtk.MessageType.ERROR, icon_name="blueman", - text=_("Bluetooth Turned Off"), secondary_text=message) + type=Gtk.MessageType.ERROR, icon_name="blueman", text=_("Bluetooth Turned Off"), secondary_text=message + ) d.add_button(_("Exit"), Gtk.ResponseType.NO) d.add_button(_("Enable Bluetooth"), Gtk.ResponseType.YES) @@ -78,9 +92,9 @@ def check_bluetooth_status(message: str, exitfunc: Callable[[], Any]) -> None: exitfunc() return - applet.SetBluetoothStatus('(b)', True) + applet.SetBluetoothStatus("(b)", True) if not applet.GetBluetoothStatus(): - print('Failed to enable bluetooth') + print("Failed to enable bluetooth") exitfunc() @@ -141,7 +155,7 @@ def setup_icon_path() -> None: def adapter_path_to_name(path: Optional[str]) -> Optional[str]: - if path is None or path == '': + if path is None or path == "": return None match = re.search(r".*(hci[0-9]*)", path) @@ -203,7 +217,7 @@ def create_menuitem( def have(t: str) -> Optional[str]: - paths = os.environ['PATH'] + ':/sbin:/usr/sbin' + paths = os.environ["PATH"] + ":/sbin:/usr/sbin" for path in paths.split(os.pathsep): exec_path = os.path.join(path, t) exists = os.path.exists(exec_path) @@ -219,7 +233,7 @@ def set_proc_title(name: Optional[str] = None) -> int: if not name: name = os.path.basename(sys.argv[0]) - libc = cdll.LoadLibrary('libc.so.6') + libc = cdll.LoadLibrary("libc.so.6") buff = create_string_buffer(len(name) + 1) buff.value = name.encode("UTF-8") ret: int = libc.prctl(15, byref(buff), 0, 0, 0) @@ -230,9 +244,9 @@ def set_proc_title(name: Optional[str] = None) -> int: return ret -logger_format = '%(name)s %(asctime)s %(levelname)-8s %(module)s:%(lineno)s %(funcName)-10s: %(message)s' -syslog_logger_format = '%(name)s %(levelname)s %(module)s:%(lineno)s %(funcName)s: %(message)s' -logger_date_fmt = '%H.%M.%S' +logger_format = "%(name)s %(asctime)s %(levelname)-8s %(module)s:%(lineno)s %(funcName)-10s: %(message)s" +syslog_logger_format = "%(name)s %(levelname)s %(module)s:%(lineno)s %(funcName)s: %(message)s" +logger_date_fmt = "%H.%M.%S" def create_logger( @@ -290,43 +304,43 @@ def open_rfcomm(file: str, mode: int) -> int: def _netmask_for_ifacename(name: str, sock: socket.socket) -> Optional[str]: - siocgifnetmask = 0x891b - bytebuf = struct.pack('256s', name.encode('utf-8')) + siocgifnetmask = 0x891B + bytebuf = struct.pack("256s", name.encode("utf-8")) try: ret = fcntl.ioctl(sock.fileno(), siocgifnetmask, bytebuf) except OSError: - logging.error('siocgifnetmask failed') + logging.error("siocgifnetmask failed") return None return socket.inet_ntoa(ret[20:24]) def get_local_interfaces() -> Dict[str, Tuple[str, Optional[str]]]: - """ Returns a dictionary of name:ip, mask key value pairs. """ + """Returns a dictionary of name:ip, mask key value pairs.""" siocgifconf = 0x8912 - names = array.array('B', 4096 * b'\0') + names = array.array("B", 4096 * b"\0") names_address, names_length = names.buffer_info() - mutable_byte_buffer = struct.pack('iL', 4096, names_address) + mutable_byte_buffer = struct.pack("iL", 4096, names_address) try: with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock: try: mutated_byte_buffer = fcntl.ioctl(sock.fileno(), siocgifconf, mutable_byte_buffer) except OSError: - logging.error('siocgifconf failed') + logging.error("siocgifconf failed") return {} - max_bytes_out, names_address_out = struct.unpack('iL', mutated_byte_buffer) + max_bytes_out, names_address_out = struct.unpack("iL", mutated_byte_buffer) namestr = names.tobytes() ip_dict = {} for i in range(0, max_bytes_out, 24 + 2 * sizeof(c_long)): - name = namestr[i: i + 16].split(b'\0', 1)[0].decode('utf-8') - ipaddr = socket.inet_ntoa(namestr[i + 20: i + 24]) + name = namestr[i : i + 16].split(b"\0", 1)[0].decode("utf-8") + ipaddr = socket.inet_ntoa(namestr[i + 20 : i + 24]) mask = _netmask_for_ifacename(name, sock) ip_dict[name] = (ipaddr, mask) except OSError: - logging.error('Socket creation failed', exc_info=True) + logging.error("Socket creation failed", exc_info=True) return {} return ip_dict diff --git a/blueman/Sdp.py b/blueman/Sdp.py index 432971a8e..c34355e08 100644 --- a/blueman/Sdp.py +++ b/blueman/Sdp.py @@ -17,12 +17,12 @@ IRMC_SYNC_CMD_SVCLASS_ID = 0x1107 HEADSET_SVCLASS_ID = 0x1108 CORDLESS_TELEPHONY_SVCLASS_ID = 0x1109 -AUDIO_SOURCE_SVCLASS_ID = 0x110a -AUDIO_SINK_SVCLASS_ID = 0x110b -AV_REMOTE_TARGET_SVCLASS_ID = 0x110c -ADVANCED_AUDIO_SVCLASS_ID = 0x110d -AV_REMOTE_SVCLASS_ID = 0x110e -AV_REMOTE_CONTROLLER_SVCLASS_ID = 0x110f +AUDIO_SOURCE_SVCLASS_ID = 0x110A +AUDIO_SINK_SVCLASS_ID = 0x110B +AV_REMOTE_TARGET_SVCLASS_ID = 0x110C +ADVANCED_AUDIO_SVCLASS_ID = 0x110D +AV_REMOTE_SVCLASS_ID = 0x110E +AV_REMOTE_CONTROLLER_SVCLASS_ID = 0x110F INTERCOM_SVCLASS_ID = 0x1110 FAX_SVCLASS_ID = 0x1111 HEADSET_AGW_SVCLASS_ID = 0x1112 @@ -33,12 +33,12 @@ GN_SVCLASS_ID = 0x1117 DIRECT_PRINTING_SVCLASS_ID = 0x1118 REFERENCE_PRINTING_SVCLASS_ID = 0x1119 -IMAGING_SVCLASS_ID = 0x111a -IMAGING_RESPONDER_SVCLASS_ID = 0x111b -IMAGING_ARCHIVE_SVCLASS_ID = 0x111c -IMAGING_REFOBJS_SVCLASS_ID = 0x111d -HANDSFREE_SVCLASS_ID = 0x111e -HANDSFREE_AGW_SVCLASS_ID = 0x111f +IMAGING_SVCLASS_ID = 0x111A +IMAGING_RESPONDER_SVCLASS_ID = 0x111B +IMAGING_ARCHIVE_SVCLASS_ID = 0x111C +IMAGING_REFOBJS_SVCLASS_ID = 0x111D +HANDSFREE_SVCLASS_ID = 0x111E +HANDSFREE_AGW_SVCLASS_ID = 0x111F DIRECT_PRT_REFOBJS_SVCLASS_ID = 0x1120 REFLECTED_UI_SVCLASS_ID = 0x1121 BASIC_PRINTING_SVCLASS_ID = 0x1122 @@ -49,12 +49,12 @@ HCR_SCAN_SVCLASS_ID = 0x1127 CIP_SVCLASS_ID = 0x1128 VIDEO_CONF_GW_SVCLASS_ID = 0x1129 -UDI_MT_SVCLASS_ID = 0x112a -UDI_TA_SVCLASS_ID = 0x112b -AV_SVCLASS_ID = 0x112c -SAP_SVCLASS_ID = 0x112d -PBAP_PCE_SVCLASS_ID = 0x112e -PBAP_PSE_SVCLASS_ID = 0x112f +UDI_MT_SVCLASS_ID = 0x112A +UDI_TA_SVCLASS_ID = 0x112B +AV_SVCLASS_ID = 0x112C +SAP_SVCLASS_ID = 0x112D +PBAP_PCE_SVCLASS_ID = 0x112E +PBAP_PSE_SVCLASS_ID = 0x112F PBAP_SVCLASS_ID = 0x1130 MAP_MSE_SVCLASS_ID = 0x1132 MAP_MCE_SVCLASS_ID = 0x1133 @@ -94,10 +94,10 @@ 0x0007: _("ATT"), 0x0008: _("OBEX"), 0x0009: _("IP"), - 0x000a: _("FTP"), - 0x000c: _("HTTP"), - 0x000e: _("WSP"), - 0x000f: _("BNEP"), + 0x000A: _("FTP"), + 0x000C: _("HTTP"), + 0x000E: _("WSP"), + 0x000F: _("BNEP"), 0x0010: _("UPnP/ESDP"), 0x0011: _("HIDP"), 0x0012: _("Hardcopy Control Channel"), @@ -105,10 +105,10 @@ 0x0016: _("Hardcopy Notification"), 0x0017: _("AVCTP"), 0x0019: _("AVDTP"), - 0x001b: _("CMTP"), - 0x001d: _("UDI_C-Plane"), - 0x001e: _("Multi-Channel Adaptation Protocol (MCAP)"), - 0x001f: _("Multi-Channel Adaptation Protocol (MCAP)"), + 0x001B: _("CMTP"), + 0x001D: _("UDI_C-Plane"), + 0x001E: _("Multi-Channel Adaptation Protocol (MCAP)"), + 0x001F: _("Multi-Channel Adaptation Protocol (MCAP)"), 0x0100: _("L2CAP"), 0x1000: _("ServiceDiscoveryServerServiceClassID"), 0x1001: _("BrowseGroupDescriptorServiceClassID"), @@ -122,12 +122,12 @@ 0x1107: _("IrMC Sync Command"), 0x1108: _("Headset"), 0x1109: _("Cordless Telephony"), - 0x110a: _("Audio Source"), - 0x110b: _("Audio Sink"), - 0x110c: _("Remote Control Target"), - 0x110d: _("Advanced Audio"), - 0x110e: _("Remote Control"), - 0x110f: _("Video Conferencing"), + 0x110A: _("Audio Source"), + 0x110B: _("Audio Sink"), + 0x110C: _("Remote Control Target"), + 0x110D: _("Advanced Audio"), + 0x110E: _("Remote Control"), + 0x110F: _("Video Conferencing"), 0x1110: _("Intercom"), 0x1111: _("Fax"), 0x1112: _("Headset Audio Gateway"), @@ -138,12 +138,12 @@ 0x1117: _("Group Network"), 0x1118: _("DirectPrinting (BPP)"), 0x1119: _("ReferencePrinting (BPP)"), - 0x111a: _("Imaging (BIP)"), - 0x111b: _("ImagingResponder (BIP)"), - 0x111c: _("ImagingAutomaticArchive (BIP)"), - 0x111d: _("ImagingReferencedObjects (BIP)"), - 0x111e: _("Handsfree"), - 0x111f: _("Handsfree Audio Gateway"), + 0x111A: _("Imaging (BIP)"), + 0x111B: _("ImagingResponder (BIP)"), + 0x111C: _("ImagingAutomaticArchive (BIP)"), + 0x111D: _("ImagingReferencedObjects (BIP)"), + 0x111E: _("Handsfree"), + 0x111F: _("Handsfree Audio Gateway"), 0x1120: _("DirectPrintingReferenceObjectsService (BPP)"), 0x1121: _("ReflectedUI (BPP)"), 0x1122: _("Basic Printing (BPP)"), @@ -154,12 +154,12 @@ 0x1127: _("HCR_Scan (HCR)"), 0x1128: _("Common ISDN Access (CIP)"), 0x1129: _("VideoConferencingGW (VCP)"), - 0x112a: _("UDI-MT"), - 0x112b: _("UDI-TA"), - 0x112c: _("Audio/Video"), - 0x112d: _("SIM Access (SAP)"), - 0x112e: _("Phonebook Access (PBAP) - PCE"), - 0x112f: _("Phonebook Access (PBAP) - PSE"), + 0x112A: _("UDI-MT"), + 0x112B: _("UDI-TA"), + 0x112C: _("Audio/Video"), + 0x112D: _("SIM Access (SAP)"), + 0x112E: _("Phonebook Access (PBAP) - PCE"), + 0x112F: _("Phonebook Access (PBAP) - PSE"), 0x1130: _("Phonebook Access (PBAP)"), 0x1131: _("Headset"), 0x1132: _("Message Access Server"), @@ -170,11 +170,11 @@ 0x1137: _("3D Display"), 0x1138: _("3D Glasses"), 0x1139: _("3D Synchronization (3DSP)"), - 0x113a: _("Multi-Profile Specification (MPS) Profile"), - 0x113b: _("Multi-Profile Specification (MPS) Service"), - 0x113c: _("Calendar, Task, and Notes (CTN) Access Service"), - 0x113d: _("Calendar, Task, and Notes (CTN) Notification Service"), - 0x113e: _("Calendar, Task, and Notes (CTN) Profile"), + 0x113A: _("Multi-Profile Specification (MPS) Profile"), + 0x113B: _("Multi-Profile Specification (MPS) Service"), + 0x113C: _("Calendar, Task, and Notes (CTN) Access Service"), + 0x113D: _("Calendar, Task, and Notes (CTN) Notification Service"), + 0x113E: _("Calendar, Task, and Notes (CTN) Profile"), 0x1200: _("PnP Information"), 0x1201: _("Generic Networking"), 0x1202: _("Generic FileTransfer"), @@ -261,10 +261,10 @@ SDP_ATTR_SVCINFO_TTL = 0x0007 SDP_ATTR_SERVICE_AVAILABILITY = 0x0008 SDP_ATTR_PFILE_DESC_LIST = 0x0009 -SDP_ATTR_DOC_URL = 0x000a -SDP_ATTR_CLNT_EXEC_URL = 0x000b -SDP_ATTR_ICON_URL = 0x000c -SDP_ATTR_ADD_PROTO_DESC_LIST = 0x000d +SDP_ATTR_DOC_URL = 0x000A +SDP_ATTR_CLNT_EXEC_URL = 0x000B +SDP_ATTR_ICON_URL = 0x000C +SDP_ATTR_ADD_PROTO_DESC_LIST = 0x000D SDP_ATTR_SUPPORTED_REPOSITORIES = 0x0314 SDP_ATTR_MAS_INSTANCE_ID = 0x0315 @@ -289,11 +289,11 @@ SDP_ATTR_HID_LANG_ID_BASE_LIST = 0x0207 SDP_ATTR_HID_SDP_DISABLE = 0x0208 SDP_ATTR_HID_BATTERY_POWER = 0x0209 -SDP_ATTR_HID_REMOTE_WAKEUP = 0x020a -SDP_ATTR_HID_PROFILE_VERSION = 0x020b -SDP_ATTR_HID_SUPERVISION_TIMEOUT = 0x020c -SDP_ATTR_HID_NORMALLY_CONNECTABLE = 0x020d -SDP_ATTR_HID_BOOT_DEVICE = 0x020e +SDP_ATTR_HID_REMOTE_WAKEUP = 0x020A +SDP_ATTR_HID_PROFILE_VERSION = 0x020B +SDP_ATTR_HID_SUPERVISION_TIMEOUT = 0x020C +SDP_ATTR_HID_NORMALLY_CONNECTABLE = 0x020D +SDP_ATTR_HID_BOOT_DEVICE = 0x020E SDP_PRIMARY_LANG_BASE = 0x0100 @@ -305,10 +305,10 @@ TCS_AT_UUID = 0x0006 OBEX_UUID = 0x0008 IP_UUID = 0x0009 -FTP_UUID = 0x000a -HTTP_UUID = 0x000c -WSP_UUID = 0x000e -BNEP_UUID = 0x000f +FTP_UUID = 0x000A +HTTP_UUID = 0x000C +WSP_UUID = 0x000E +BNEP_UUID = 0x000F UPNP_UUID = 0x0010 HIDP_UUID = 0x0011 HCRP_CTRL_UUID = 0x0012 @@ -316,10 +316,10 @@ HCRP_NOTE_UUID = 0x0016 AVCTP_UUID = 0x0017 AVDTP_UUID = 0x0019 -CMTP_UUID = 0x001b -UDI_UUID = 0x001d -MCAP_CTRL_UUID = 0x001e -MCAP_DATA_UUID = 0x001f +CMTP_UUID = 0x001B +UDI_UUID = 0x001D +MCAP_CTRL_UUID = 0x001E +MCAP_DATA_UUID = 0x001F L2CAP_UUID = 0x0100 # GATT UUIDs section @@ -375,11 +375,13 @@ def name(self) -> str: except KeyError: return _("Unknown") elif self.int == 0: - return _('Audio and input profiles') + return _("Audio and input profiles") else: - return _('Proprietary') + return _("Proprietary") @property def reserved(self) -> bool: - return self.int & UUID('FFFF0000-0000-FFFF-FFFF-FFFFFFFFFFFF').int == \ - UUID('00000000-0000-1000-8000-00805F9B34FB').int + return ( + self.int & UUID("FFFF0000-0000-FFFF-FFFF-FFFFFFFFFFFF").int + == UUID("00000000-0000-1000-8000-00805F9B34FB").int + ) diff --git a/blueman/bluemantyping.py b/blueman/bluemantyping.py index bb4d7c8b4..5a7f7a953 100644 --- a/blueman/bluemantyping.py +++ b/blueman/bluemantyping.py @@ -7,6 +7,7 @@ class _HasGType(Protocol): __gtype__: GObject.GType + # Actually supported types are int, bool, str, float, and object but no subclasses, see # https://github.com/GNOME/pygobject/blob/ac576400ecd554879c906791e6638d64bb8bcc2a/gi/pygi-type.c#L498 # (We shield the possibility to provide a str to avoid errors) diff --git a/blueman/bluez/Adapter.py b/blueman/bluez/Adapter.py index f589a2f2d..7928e5c19 100644 --- a/blueman/bluez/Adapter.py +++ b/blueman/bluez/Adapter.py @@ -9,29 +9,29 @@ class Adapter(Base): - _interface_name = 'org.bluez.Adapter1' + _interface_name = "org.bluez.Adapter1" def __init__(self, obj_path: str): super().__init__(obj_path=obj_path) def start_discovery(self, error_handler: Optional[Callable[[BluezDBusException], None]] = None) -> None: - self._call('StartDiscovery', error_handler=error_handler) + self._call("StartDiscovery", error_handler=error_handler) def stop_discovery(self) -> None: - self._call('StopDiscovery') + self._call("StopDiscovery") def remove_device(self, device: Device) -> None: - param = GLib.Variant('(o)', (device.get_object_path(),)) - self._call('RemoveDevice', param) + param = GLib.Variant("(o)", (device.get_object_path(),)) + self._call("RemoveDevice", param) def get_name(self) -> str: - name: str = self['Alias'] + name: str = self["Alias"] return name def set_name(self, name: str) -> None: - self.set('Alias', name) + self.set("Alias", name) class AnyAdapter(AnyBase): def __init__(self) -> None: - super().__init__('org.bluez.Adapter1') + super().__init__("org.bluez.Adapter1") diff --git a/blueman/bluez/AgentManager.py b/blueman/bluez/AgentManager.py index 5f19acb62..c298cc40e 100644 --- a/blueman/bluez/AgentManager.py +++ b/blueman/bluez/AgentManager.py @@ -3,19 +3,19 @@ class AgentManager(Base): - _interface_name = 'org.bluez.AgentManager1' - _obj_path = '/org/bluez' + _interface_name = "org.bluez.AgentManager1" + _obj_path = "/org/bluez" def __init__(self) -> None: super().__init__(obj_path=self._obj_path) def register_agent(self, agent_path: str, capability: str = "", default: bool = False) -> None: - param = GLib.Variant('(os)', (agent_path, capability)) - self._call('RegisterAgent', param) + param = GLib.Variant("(os)", (agent_path, capability)) + self._call("RegisterAgent", param) if default: - default_param = GLib.Variant('(o)', (agent_path,)) - self._call('RequestDefaultAgent', default_param) + default_param = GLib.Variant("(o)", (agent_path,)) + self._call("RequestDefaultAgent", default_param) def unregister_agent(self, agent_path: str) -> None: - param = GLib.Variant('(o)', (agent_path,)) - self._call('UnregisterAgent', param) + param = GLib.Variant("(o)", (agent_path,)) + self._call("UnregisterAgent", param) diff --git a/blueman/bluez/AnyBase.py b/blueman/bluez/AnyBase.py index 8c4aae7b5..d4292e0c1 100644 --- a/blueman/bluez/AnyBase.py +++ b/blueman/bluez/AnyBase.py @@ -7,9 +7,7 @@ class AnyBase(GObject.GObject): - __gsignals__: GSignals = { - 'property-changed': (GObject.SignalFlags.NO_HOOKS, None, (str, object, str)) - } + __gsignals__: GSignals = {"property-changed": (GObject.SignalFlags.NO_HOOKS, None, (str, object, str))} connect_signal = GObject.GObject.connect disconnect_signal = GObject.GObject.disconnect @@ -32,7 +30,7 @@ def on_signal( iface_name, changed, invalidated = param.unpack() if iface_name == interface_name and this is not None: for key in list(changed) + invalidated: - this.emit('property-changed', key, changed.get(key, None), object_path) + this.emit("property-changed", key, changed.get(key, None), object_path) weakref.finalize( self, @@ -44,6 +42,6 @@ def on_signal( None, None, Gio.DBusSignalFlags.NONE, - on_signal - ) + on_signal, + ), ) diff --git a/blueman/bluez/Base.py b/blueman/bluez/Base.py index 9871cde9c..9aef7cef1 100644 --- a/blueman/bluez/Base.py +++ b/blueman/bluez/Base.py @@ -13,7 +13,7 @@ def __call__(cls, *args: object, **kwargs: str) -> "Base": if not hasattr(cls, "__instances__"): cls.__instances__: Dict[str, "Base"] = {} - path = kwargs.get('obj_path') + path = kwargs.get("obj_path") if path is None: path = getattr(cls, "_obj_path") @@ -27,13 +27,11 @@ def __call__(cls, *args: object, **kwargs: str) -> "Base": class Base(GObject.Object, metaclass=BaseMeta): - __name = 'org.bluez' + __name = "org.bluez" __bus_type = Gio.BusType.SYSTEM __proxy: Gio.DBusProxy - __gsignals__: GSignals = { - 'property-changed': (GObject.SignalFlags.NO_HOOKS, None, (str, object, str)) - } + __gsignals__: GSignals = {"property-changed": (GObject.SignalFlags.NO_HOOKS, None, (str, object, str))} __instances__: Dict[str, "Base"] _interface_name: str @@ -45,23 +43,18 @@ def __init__(self, *, obj_path: str): super().__init__() self.__proxy = Gio.DBusProxy.new_for_bus_sync( - self.__bus_type, - Gio.DBusProxyFlags.NONE, - None, - self.__name, - obj_path, - self._interface_name, - None + self.__bus_type, Gio.DBusProxyFlags.NONE, None, self.__name, obj_path, self._interface_name, None ) self.__proxy.connect("g-properties-changed", self._properties_changed) - self.__fallback = {'Icon': 'blueman', 'Class': 0, 'Appearance': 0} + self.__fallback = {"Icon": "blueman", "Class": 0, "Appearance": 0} - self.__variant_map = {str: 's', int: 'u', bool: 'b'} + self.__variant_map = {str: "s", int: "u", bool: "b"} - def _properties_changed(self, _proxy: Gio.DBusProxy, changed_properties: GLib.Variant, - invalidated_properties: List[str]) -> None: + def _properties_changed( + self, _proxy: Gio.DBusProxy, changed_properties: GLib.Variant, invalidated_properties: List[str] + ) -> None: changed = changed_properties.unpack() object_path = self.get_object_path() logging.debug(f"{object_path} {changed} {invalidated_properties} {self}") @@ -92,17 +85,19 @@ def callback( else: logging.error(f"Unhandled error for {self.__proxy.get_interface_name()}.{method}", exc_info=True) - self.__proxy.call(method, param, Gio.DBusCallFlags.NONE, GLib.MAXINT, None, - callback, reply_handler, error_handler) + self.__proxy.call( + method, param, Gio.DBusCallFlags.NONE, GLib.MAXINT, None, callback, reply_handler, error_handler + ) def get(self, name: str) -> Any: try: prop = self.__proxy.call_sync( - 'org.freedesktop.DBus.Properties.Get', - GLib.Variant('(ss)', (self._interface_name, name)), + "org.freedesktop.DBus.Properties.Get", + GLib.Variant("(ss)", (self._interface_name, name)), Gio.DBusCallFlags.NONE, GLib.MAXINT, - None) + None, + ) return prop.unpack()[0] except GLib.Error as e: property = self.__proxy.get_cached_property(name) @@ -115,23 +110,17 @@ def get(self, name: str) -> Any: def set(self, name: str, value: Union[str, int, bool]) -> None: v = GLib.Variant(self.__variant_map[type(value)], value) - param = GLib.Variant('(ssv)', (self._interface_name, name, v)) - self.__proxy.call('org.freedesktop.DBus.Properties.Set', - param, - Gio.DBusCallFlags.NONE, - GLib.MAXINT, - None) + param = GLib.Variant("(ssv)", (self._interface_name, name, v)) + self.__proxy.call("org.freedesktop.DBus.Properties.Set", param, Gio.DBusCallFlags.NONE, GLib.MAXINT, None) def get_object_path(self) -> str: return self.__proxy.get_object_path() def get_properties(self) -> Dict[str, Any]: - param = GLib.Variant('(s)', (self._interface_name,)) - res = self.__proxy.call_sync('org.freedesktop.DBus.Properties.GetAll', - param, - Gio.DBusCallFlags.NONE, - GLib.MAXINT, - None) + param = GLib.Variant("(s)", (self._interface_name,)) + res = self.__proxy.call_sync( + "org.freedesktop.DBus.Properties.GetAll", param, Gio.DBusCallFlags.NONE, GLib.MAXINT, None + ) props: Dict[str, Any] = res.unpack()[0] for k, v in self.__fallback.items(): diff --git a/blueman/bluez/Device.py b/blueman/bluez/Device.py index 469bf6240..077e87a36 100644 --- a/blueman/bluez/Device.py +++ b/blueman/bluez/Device.py @@ -6,7 +6,7 @@ class Device(Base): - _interface_name = 'org.bluez.Device1' + _interface_name = "org.bluez.Device1" def __init__(self, obj_path: str): super().__init__(obj_path=obj_path) @@ -16,21 +16,21 @@ def pair( reply_handler: Optional[Callable[[], None]] = None, error_handler: Optional[Callable[[BluezDBusException], None]] = None, ) -> None: - self._call('Pair', reply_handler=reply_handler, error_handler=error_handler) + self._call("Pair", reply_handler=reply_handler, error_handler=error_handler) def connect( # type: ignore self, reply_handler: Optional[Callable[[], None]] = None, error_handler: Optional[Callable[[BluezDBusException], None]] = None, ) -> None: - self._call('Connect', reply_handler=reply_handler, error_handler=error_handler) + self._call("Connect", reply_handler=reply_handler, error_handler=error_handler) def disconnect( # type: ignore self, reply_handler: Optional[Callable[[], None]] = None, error_handler: Optional[Callable[[BluezDBusException], None]] = None, ) -> None: - self._call('Disconnect', reply_handler=reply_handler, error_handler=error_handler) + self._call("Disconnect", reply_handler=reply_handler, error_handler=error_handler) @property def display_name(self) -> str: @@ -40,4 +40,4 @@ def display_name(self) -> str: class AnyDevice(AnyBase): def __init__(self) -> None: - super().__init__('org.bluez.Device1') + super().__init__("org.bluez.Device1") diff --git a/blueman/bluez/Manager.py b/blueman/bluez/Manager.py index 3390f64a6..f57bccae4 100644 --- a/blueman/bluez/Manager.py +++ b/blueman/bluez/Manager.py @@ -12,24 +12,30 @@ class Manager(GObject.GObject, metaclass=SingletonGObjectMeta): __gsignals__: GSignals = { - 'adapter-added': (GObject.SignalFlags.NO_HOOKS, None, (str,)), - 'adapter-removed': (GObject.SignalFlags.NO_HOOKS, None, (str,)), - 'device-created': (GObject.SignalFlags.NO_HOOKS, None, (str,)), - 'device-removed': (GObject.SignalFlags.NO_HOOKS, None, (str,)), - 'battery-created': (GObject.SignalFlags.NO_HOOKS, None, (str,)), - 'battery-removed': (GObject.SignalFlags.NO_HOOKS, None, (str,)), + "adapter-added": (GObject.SignalFlags.NO_HOOKS, None, (str,)), + "adapter-removed": (GObject.SignalFlags.NO_HOOKS, None, (str,)), + "device-created": (GObject.SignalFlags.NO_HOOKS, None, (str,)), + "device-removed": (GObject.SignalFlags.NO_HOOKS, None, (str,)), + "battery-created": (GObject.SignalFlags.NO_HOOKS, None, (str,)), + "battery-removed": (GObject.SignalFlags.NO_HOOKS, None, (str,)), } connect_signal = GObject.GObject.connect disconnect_signal = GObject.GObject.disconnect - __bus_name = 'org.bluez' + __bus_name = "org.bluez" def __init__(self) -> None: super().__init__() self._object_manager = Gio.DBusObjectManagerClient.new_for_bus_sync( - Gio.BusType.SYSTEM, Gio.DBusObjectManagerClientFlags.DO_NOT_AUTO_START, - self.__bus_name, '/', None, None, None) + Gio.BusType.SYSTEM, + Gio.DBusObjectManagerClientFlags.DO_NOT_AUTO_START, + self.__bus_name, + "/", + None, + None, + None, + ) self._object_manager.connect("object-added", self._on_object_added) self._object_manager.connect("object-removed", self._on_object_removed) @@ -37,67 +43,69 @@ def __init__(self) -> None: self._object_manager.connect("interface-removed", self._on_interface_removed) def _on_object_added(self, _object_manager: Gio.DBusObjectManager, dbus_object: Gio.DBusObject) -> None: - device_proxy = dbus_object.get_interface('org.bluez.Device1') - adapter_proxy = dbus_object.get_interface('org.bluez.Adapter1') - battery_proxy = dbus_object.get_interface('org.bluez.Battery1') + device_proxy = dbus_object.get_interface("org.bluez.Device1") + adapter_proxy = dbus_object.get_interface("org.bluez.Adapter1") + battery_proxy = dbus_object.get_interface("org.bluez.Battery1") if adapter_proxy: assert isinstance(adapter_proxy, Gio.DBusProxy) object_path = adapter_proxy.get_object_path() logging.debug(f"Adapter1: {object_path}") - self.emit('adapter-added', object_path) + self.emit("adapter-added", object_path) if device_proxy: assert isinstance(device_proxy, Gio.DBusProxy) object_path = device_proxy.get_object_path() logging.debug(f"Device1: {object_path}") - self.emit('device-created', object_path) + self.emit("device-created", object_path) if battery_proxy: assert isinstance(device_proxy, Gio.DBusProxy) object_path = device_proxy.get_object_path() logging.debug(f"Battery1: {object_path}") - self.emit('battery-created', object_path) + self.emit("battery-created", object_path) def _on_object_removed(self, _object_manager: Gio.DBusObjectManager, dbus_object: Gio.DBusObject) -> None: - device_proxy = dbus_object.get_interface('org.bluez.Device1') - adapter_proxy = dbus_object.get_interface('org.bluez.Adapter1') - battery_proxy = dbus_object.get_interface('org.bluez.Battery1') + device_proxy = dbus_object.get_interface("org.bluez.Device1") + adapter_proxy = dbus_object.get_interface("org.bluez.Adapter1") + battery_proxy = dbus_object.get_interface("org.bluez.Battery1") if adapter_proxy: assert isinstance(adapter_proxy, Gio.DBusProxy) object_path = adapter_proxy.get_object_path() logging.debug(object_path) - self.emit('adapter-removed', object_path) + self.emit("adapter-removed", object_path) if device_proxy: assert isinstance(device_proxy, Gio.DBusProxy) object_path = device_proxy.get_object_path() logging.debug(object_path) - self.emit('device-removed', object_path) + self.emit("device-removed", object_path) if battery_proxy: assert isinstance(device_proxy, Gio.DBusProxy) object_path = device_proxy.get_object_path() logging.debug(object_path) - self.emit('battery-removed', object_path) + self.emit("battery-removed", object_path) - def _on_interface_added(self, _object_manager: Gio.DBusObjectManager, dbus_object: Gio.DBusObject, - _dbus_interface: Gio.DBusInterface) -> None: + def _on_interface_added( + self, _object_manager: Gio.DBusObjectManager, dbus_object: Gio.DBusObject, _dbus_interface: Gio.DBusInterface + ) -> None: object_path = dbus_object.get_object_path() battery = dbus_object.get_interface("org.bluez.Battery1") if battery is not None: logging.debug(f"Battery1 added to {object_path}") - self.emit('battery-created', object_path) + self.emit("battery-created", object_path) - def _on_interface_removed(self, _object_manager: Gio.DBusObjectManager, dbus_object: Gio.DBusObject, - _dbus_interface: Gio.DBusInterface) -> None: + def _on_interface_removed( + self, _object_manager: Gio.DBusObjectManager, dbus_object: Gio.DBusObject, _dbus_interface: Gio.DBusInterface + ) -> None: object_path = dbus_object.get_object_path() battery = dbus_object.get_interface("org.bluez.Battery1") if battery is not None: logging.debug(f"Battery1 removed from {object_path}") - self.emit('battery-removed', object_path) + self.emit("battery-removed", object_path) def get_adapters(self) -> List[Adapter]: paths = [] for obj_proxy in self._object_manager.get_objects(): - proxy = obj_proxy.get_interface('org.bluez.Adapter1') + proxy = obj_proxy.get_interface("org.bluez.Adapter1") if proxy: assert isinstance(proxy, Gio.DBusProxy) @@ -115,14 +123,14 @@ def get_adapter(self, pattern: Optional[str] = None) -> Adapter: else: for adapter in adapters: path = adapter.get_object_path() - if path.endswith(pattern) or adapter['Address'] == pattern: + if path.endswith(pattern) or adapter["Address"] == pattern: return adapter raise DBusNoSuchAdapterError(f"No adapters found with pattern: {pattern}") def get_devices(self, adapter_path: str = "/") -> List[Device]: paths = [] for obj_proxy in self._object_manager.get_objects(): - proxy = obj_proxy.get_interface('org.bluez.Device1') + proxy = obj_proxy.get_interface("org.bluez.Device1") if proxy: assert isinstance(proxy, Gio.DBusProxy) @@ -143,7 +151,7 @@ def populate_devices(self, adapter_path: str = "/") -> None: def find_device(self, address: str, adapter_path: str = "/") -> Optional[Device]: for device in self.get_devices(adapter_path): - if device['Address'] == address: + if device["Address"] == address: return device return None @@ -153,5 +161,6 @@ def watch_name_owner( appeared_handler: Callable[[Gio.DBusConnection, str, str], None], vanished_handler: Callable[[Gio.DBusConnection, str], None], ) -> None: - Gio.bus_watch_name(Gio.BusType.SYSTEM, cls.__bus_name, Gio.BusNameWatcherFlags.AUTO_START, - appeared_handler, vanished_handler) + Gio.bus_watch_name( + Gio.BusType.SYSTEM, cls.__bus_name, Gio.BusNameWatcherFlags.AUTO_START, appeared_handler, vanished_handler + ) diff --git a/blueman/bluez/Network.py b/blueman/bluez/Network.py index 8193b4527..0a2df7653 100644 --- a/blueman/bluez/Network.py +++ b/blueman/bluez/Network.py @@ -8,7 +8,7 @@ class Network(Base): - _interface_name = 'org.bluez.Network1' + _interface_name = "org.bluez.Network1" def __init__(self, obj_path: str): super().__init__(obj_path=obj_path) @@ -19,17 +19,17 @@ def connect( # type: ignore reply_handler: Optional[Callable[[str], None]] = None, error_handler: Optional[Callable[[BluezDBusException], None]] = None, ) -> None: - param = GLib.Variant('(s)', (uuid,)) - self._call('Connect', param, reply_handler=reply_handler, error_handler=error_handler) + param = GLib.Variant("(s)", (uuid,)) + self._call("Connect", param, reply_handler=reply_handler, error_handler=error_handler) def disconnect( # type: ignore self, reply_handler: Optional[Callable[[], None]] = None, error_handler: Optional[Callable[[BluezDBusException], None]] = None, ) -> None: - self._call('Disconnect', reply_handler=reply_handler, error_handler=error_handler) + self._call("Disconnect", reply_handler=reply_handler, error_handler=error_handler) class AnyNetwork(AnyBase): def __init__(self) -> None: - super().__init__('org.bluez.Network1') + super().__init__("org.bluez.Network1") diff --git a/blueman/bluez/NetworkServer.py b/blueman/bluez/NetworkServer.py index a8625cf6b..e2d751d7d 100644 --- a/blueman/bluez/NetworkServer.py +++ b/blueman/bluez/NetworkServer.py @@ -3,15 +3,15 @@ class NetworkServer(Base): - _interface_name = 'org.bluez.NetworkServer1' + _interface_name = "org.bluez.NetworkServer1" def __init__(self, obj_path: str): super().__init__(obj_path=obj_path) def register(self, uuid: str, bridge: str) -> None: - param = GLib.Variant('(ss)', (uuid, bridge)) - self._call('Register', param) + param = GLib.Variant("(ss)", (uuid, bridge)) + self._call("Register", param) def unregister(self, uuid: str) -> None: - param = GLib.Variant('(s)', (uuid,)) - self._call('Unregister', param) + param = GLib.Variant("(s)", (uuid,)) + self._call("Unregister", param) diff --git a/blueman/bluez/errors.py b/blueman/bluez/errors.py index 6f31b1c77..d051810a5 100644 --- a/blueman/bluez/errors.py +++ b/blueman/bluez/errors.py @@ -101,33 +101,35 @@ class BluezUnavailableAgentMethodError(BluezDBusException): pass -__DICT_ERROR__ = {'org.bluez.Error.Failed': DBusFailedError, - 'org.bluez.Error.InvalidArguments': DBusInvalidArgumentsError, - 'org.bluez.Error.NotAuthorized': DBusNotAuthorizedError, - 'org.bluez.Error.OutOfMemory': DBusOutOfMemoryError, - 'org.bluez.Error.NoSuchAdapter': DBusNoSuchAdapterError, - 'org.bluez.Error.NotReady': DBusNotReadyError, - 'org.bluez.Error.NotAvailable': DBusNotAvailableError, - 'org.bluez.Error.NotConnected': DBusNotConnectedError, - 'org.bluez.serial.Error.ConnectionAttemptFailed': DBusConnectionAttemptFailedError, - 'org.bluez.Error.AlreadyExists': DBusAlreadyExistsError, - 'org.bluez.Error.DoesNotExist': DBusDoesNotExistError, - 'org.bluez.Error.InProgress': DBusInProgressError, - 'org.bluez.Error.NoReply': DBusNoReplyError, - 'org.bluez.Error.NotSupported': DBusNotSupportedError, - 'org.bluez.Error.AuthenticationFailed': DBusAuthenticationFailedError, - 'org.bluez.Error.AuthenticationTimeout': DBusAuthenticationTimeoutError, - 'org.bluez.Error.AuthenticationRejected': DBusAuthenticationRejectedError, - 'org.bluez.Error.AuthenticationCanceled': DBusAuthenticationCanceledError, - 'org.bluez.serial.Error.NotSupported': DBusNotSupportedError, - 'org.bluez.Error.UnsupportedMajorClass': DBusUnsupportedMajorClassError, - 'org.freedesktop.DBus.Error.ServiceUnknown': DBusServiceUnknownError} +__DICT_ERROR__ = { + "org.bluez.Error.Failed": DBusFailedError, + "org.bluez.Error.InvalidArguments": DBusInvalidArgumentsError, + "org.bluez.Error.NotAuthorized": DBusNotAuthorizedError, + "org.bluez.Error.OutOfMemory": DBusOutOfMemoryError, + "org.bluez.Error.NoSuchAdapter": DBusNoSuchAdapterError, + "org.bluez.Error.NotReady": DBusNotReadyError, + "org.bluez.Error.NotAvailable": DBusNotAvailableError, + "org.bluez.Error.NotConnected": DBusNotConnectedError, + "org.bluez.serial.Error.ConnectionAttemptFailed": DBusConnectionAttemptFailedError, + "org.bluez.Error.AlreadyExists": DBusAlreadyExistsError, + "org.bluez.Error.DoesNotExist": DBusDoesNotExistError, + "org.bluez.Error.InProgress": DBusInProgressError, + "org.bluez.Error.NoReply": DBusNoReplyError, + "org.bluez.Error.NotSupported": DBusNotSupportedError, + "org.bluez.Error.AuthenticationFailed": DBusAuthenticationFailedError, + "org.bluez.Error.AuthenticationTimeout": DBusAuthenticationTimeoutError, + "org.bluez.Error.AuthenticationRejected": DBusAuthenticationRejectedError, + "org.bluez.Error.AuthenticationCanceled": DBusAuthenticationCanceledError, + "org.bluez.serial.Error.NotSupported": DBusNotSupportedError, + "org.bluez.Error.UnsupportedMajorClass": DBusUnsupportedMajorClassError, + "org.freedesktop.DBus.Error.ServiceUnknown": DBusServiceUnknownError, +} def parse_dbus_error(exception: GLib.Error) -> BluezDBusException: global __DICT_ERROR__ - gerror, dbus_error, message = exception.message.split(':', 2) + gerror, dbus_error, message = exception.message.split(":", 2) try: return __DICT_ERROR__[dbus_error](message) except KeyError: diff --git a/blueman/bluez/obex/AgentManager.py b/blueman/bluez/obex/AgentManager.py index fda67ca98..c2b506389 100644 --- a/blueman/bluez/obex/AgentManager.py +++ b/blueman/bluez/obex/AgentManager.py @@ -6,8 +6,8 @@ class AgentManager(Base): - _interface_name = 'org.bluez.obex.AgentManager1' - _obj_path = '/org/bluez/obex' + _interface_name = "org.bluez.obex.AgentManager1" + _obj_path = "/org/bluez/obex" def __init__(self) -> None: super().__init__(obj_path=self._obj_path) @@ -19,8 +19,8 @@ def on_registered() -> None: def on_register_failed(error: BluezDBusException) -> None: logging.error(f"{agent_path} {error}") - param = GLib.Variant('(o)', (agent_path,)) - self._call('RegisterAgent', param, reply_handler=on_registered, error_handler=on_register_failed) + param = GLib.Variant("(o)", (agent_path,)) + self._call("RegisterAgent", param, reply_handler=on_registered, error_handler=on_register_failed) def unregister_agent(self, agent_path: str) -> None: def on_unregistered() -> None: @@ -29,5 +29,5 @@ def on_unregistered() -> None: def on_unregister_failed(error: BluezDBusException) -> None: logging.error(f"{agent_path} {error}") - param = GLib.Variant('(o)', (agent_path,)) - self._call('UnregisterAgent', param, reply_handler=on_unregistered, error_handler=on_unregister_failed) + param = GLib.Variant("(o)", (agent_path,)) + self._call("UnregisterAgent", param, reply_handler=on_unregistered, error_handler=on_unregister_failed) diff --git a/blueman/bluez/obex/Base.py b/blueman/bluez/obex/Base.py index b2223e6b3..6b0e727a6 100644 --- a/blueman/bluez/obex/Base.py +++ b/blueman/bluez/obex/Base.py @@ -4,4 +4,4 @@ class Base(BlueZBase): __bus_type = Gio.BusType.SESSION - __name = 'org.bluez.obex' + __name = "org.bluez.obex" diff --git a/blueman/bluez/obex/Client.py b/blueman/bluez/obex/Client.py index 170172703..344193615 100644 --- a/blueman/bluez/obex/Client.py +++ b/blueman/bluez/obex/Client.py @@ -9,11 +9,11 @@ class Client(Base): __gsignals__: GSignals = { - 'session-failed': (GObject.SignalFlags.NO_HOOKS, None, (object,)), + "session-failed": (GObject.SignalFlags.NO_HOOKS, None, (object,)), } - _interface_name = 'org.bluez.obex.Client1' - _obj_path = '/org/bluez/obex' + _interface_name = "org.bluez.obex.Client1" + _obj_path = "/org/bluez/obex" def __init__(self) -> None: super().__init__(obj_path=self._obj_path) @@ -26,10 +26,10 @@ def on_session_failed(error: BluezDBusException) -> None: logging.error(f"{dest_addr} {source_addr} {pattern} {error}") self.emit("session-failed", error) - v_source_addr = GLib.Variant('s', source_addr) - v_pattern = GLib.Variant('s', pattern) - param = GLib.Variant('(sa{sv})', (dest_addr, {"Source": v_source_addr, "Target": v_pattern})) - self._call('CreateSession', param, reply_handler=on_session_created, error_handler=on_session_failed) + v_source_addr = GLib.Variant("s", source_addr) + v_pattern = GLib.Variant("s", pattern) + param = GLib.Variant("(sa{sv})", (dest_addr, {"Source": v_source_addr, "Target": v_pattern})) + self._call("CreateSession", param, reply_handler=on_session_created, error_handler=on_session_failed) def remove_session(self, session_path: str) -> None: def on_session_removed() -> None: @@ -38,6 +38,5 @@ def on_session_removed() -> None: def on_session_remove_failed(error: BluezDBusException) -> None: logging.error(f"{session_path} {error}") - param = GLib.Variant('(o)', (session_path,)) - self._call('RemoveSession', param, reply_handler=on_session_removed, - error_handler=on_session_remove_failed) + param = GLib.Variant("(o)", (session_path,)) + self._call("RemoveSession", param, reply_handler=on_session_removed, error_handler=on_session_remove_failed) diff --git a/blueman/bluez/obex/Manager.py b/blueman/bluez/obex/Manager.py index f000796a5..d4af98d87 100644 --- a/blueman/bluez/obex/Manager.py +++ b/blueman/bluez/obex/Manager.py @@ -11,28 +11,28 @@ class Manager(GObject.GObject, metaclass=SingletonGObjectMeta): __gsignals__: GSignals = { - 'session-added': (GObject.SignalFlags.NO_HOOKS, None, (str,)), - 'session-removed': (GObject.SignalFlags.NO_HOOKS, None, (str,)), - 'transfer-started': (GObject.SignalFlags.NO_HOOKS, None, (str,)), - 'transfer-completed': (GObject.SignalFlags.NO_HOOKS, None, (str, bool)), + "session-added": (GObject.SignalFlags.NO_HOOKS, None, (str,)), + "session-removed": (GObject.SignalFlags.NO_HOOKS, None, (str,)), + "transfer-started": (GObject.SignalFlags.NO_HOOKS, None, (str,)), + "transfer-completed": (GObject.SignalFlags.NO_HOOKS, None, (str, bool)), } connect_signal = GObject.GObject.connect disconnect_signal = GObject.GObject.disconnect - __bus_name = 'org.bluez.obex' + __bus_name = "org.bluez.obex" def __init__(self) -> None: super().__init__() self.__transfers: Dict[str, Tuple[Transfer, Tuple[int, ...]]] = {} self._object_manager = Gio.DBusObjectManagerClient.new_for_bus_sync( - Gio.BusType.SESSION, Gio.DBusObjectManagerClientFlags.NONE, - self.__bus_name, '/', None, None, None) + Gio.BusType.SESSION, Gio.DBusObjectManagerClientFlags.NONE, self.__bus_name, "/", None, None, None + ) self._manager_handlerids: List[int] = [] - self._manager_handlerids.append(self._object_manager.connect('object-added', self._on_object_added)) - self._manager_handlerids.append(self._object_manager.connect('object-removed', self._on_object_removed)) + self._manager_handlerids.append(self._object_manager.connect("object-added", self._on_object_added)) + self._manager_handlerids.append(self._object_manager.connect("object-removed", self._on_object_removed)) weakref.finalize(self, self._on_delete) @@ -42,25 +42,25 @@ def _on_delete(self) -> None: self._manager_handlerids = [] def _on_object_added(self, _object_manager: Gio.DBusObjectManager, dbus_object: Gio.DBusObject) -> None: - session_proxy = dbus_object.get_interface('org.bluez.obex.Session1') - transfer_proxy = dbus_object.get_interface('org.bluez.obex.Transfer1') + session_proxy = dbus_object.get_interface("org.bluez.obex.Session1") + transfer_proxy = dbus_object.get_interface("org.bluez.obex.Transfer1") object_path = dbus_object.get_object_path() if transfer_proxy: logging.info(object_path) transfer = Transfer(obj_path=object_path) - chandlerid = transfer.connect_signal('completed', self._on_transfer_completed, True) - ehandlerid = transfer.connect_signal('error', self._on_transfer_completed, False) + chandlerid = transfer.connect_signal("completed", self._on_transfer_completed, True) + ehandlerid = transfer.connect_signal("error", self._on_transfer_completed, False) self.__transfers[object_path] = (transfer, (chandlerid, ehandlerid)) - self.emit('transfer-started', object_path) + self.emit("transfer-started", object_path) if session_proxy: logging.info(object_path) - self.emit('session-added', object_path) + self.emit("session-added", object_path) def _on_object_removed(self, _object_manager: Gio.DBusObjectManager, dbus_object: Gio.DBusObject) -> None: - session_proxy = dbus_object.get_interface('org.bluez.obex.Session1') - transfer_proxy = dbus_object.get_interface('org.bluez.obex.Transfer1') + session_proxy = dbus_object.get_interface("org.bluez.obex.Session1") + transfer_proxy = dbus_object.get_interface("org.bluez.obex.Transfer1") object_path = dbus_object.get_object_path() if transfer_proxy and object_path in self.__transfers: @@ -72,13 +72,13 @@ def _on_object_removed(self, _object_manager: Gio.DBusObjectManager, dbus_object if session_proxy: logging.info(object_path) - self.emit('session-removed', object_path) + self.emit("session-removed", object_path) def _on_transfer_completed(self, transfer: Transfer, success: bool) -> None: transfer_path = transfer.get_object_path() logging.info(f"{transfer_path} {success}") - self.emit('transfer-completed', transfer_path, success) + self.emit("transfer-completed", transfer_path, success) @classmethod def watch_name_owner( @@ -86,5 +86,6 @@ def watch_name_owner( appeared_handler: Callable[[Gio.DBusConnection, str, str], None], vanished_handler: Callable[[Gio.DBusConnection, str], None], ) -> None: - Gio.bus_watch_name(Gio.BusType.SESSION, cls.__bus_name, Gio.BusNameWatcherFlags.AUTO_START, - appeared_handler, vanished_handler) + Gio.bus_watch_name( + Gio.BusType.SESSION, cls.__bus_name, Gio.BusNameWatcherFlags.AUTO_START, appeared_handler, vanished_handler + ) diff --git a/blueman/bluez/obex/ObjectPush.py b/blueman/bluez/obex/ObjectPush.py index 81b8c38c9..63439cbfd 100644 --- a/blueman/bluez/obex/ObjectPush.py +++ b/blueman/bluez/obex/ObjectPush.py @@ -10,11 +10,18 @@ class ObjectPush(Base): __gsignals__: GSignals = { - 'transfer-started': (GObject.SignalFlags.NO_HOOKS, None, (str, str,)), - 'transfer-failed': (GObject.SignalFlags.NO_HOOKS, None, (str,)), + "transfer-started": ( + GObject.SignalFlags.NO_HOOKS, + None, + ( + str, + str, + ), + ), + "transfer-failed": (GObject.SignalFlags.NO_HOOKS, None, (str,)), } - _interface_name = 'org.bluez.obex.ObjectPush1' + _interface_name = "org.bluez.obex.ObjectPush1" def __init__(self, obj_path: str): super().__init__(obj_path=obj_path) @@ -22,14 +29,14 @@ def __init__(self, obj_path: str): def send_file(self, file_path: str) -> None: def on_transfer_started(transfer_path: str, props: Dict[str, str]) -> None: logging.info(" ".join((self.get_object_path(), file_path, transfer_path))) - self.emit('transfer-started', transfer_path, props['Filename']) + self.emit("transfer-started", transfer_path, props["Filename"]) def on_transfer_error(error: BluezDBusException) -> None: logging.error(f"{file_path} {error}") - self.emit('transfer-failed', error) + self.emit("transfer-failed", error) - param = GLib.Variant('(s)', (file_path,)) - self._call('SendFile', param, reply_handler=on_transfer_started, error_handler=on_transfer_error) + param = GLib.Variant("(s)", (file_path,)) + self._call("SendFile", param, reply_handler=on_transfer_started, error_handler=on_transfer_error) def get_session_path(self) -> str: path: str = self.get_object_path() diff --git a/blueman/bluez/obex/Session.py b/blueman/bluez/obex/Session.py index ee397ca28..9f40367f8 100644 --- a/blueman/bluez/obex/Session.py +++ b/blueman/bluez/obex/Session.py @@ -2,17 +2,17 @@ class Session(Base): - _interface_name = 'org.bluez.obex.Session1' + _interface_name = "org.bluez.obex.Session1" def __init__(self, obj_path: str): super().__init__(obj_path=obj_path) @property def address(self) -> str: - dest: str = self.get('Destination') + dest: str = self.get("Destination") return dest @property def root(self) -> str: - root: str = self.get('Root') + root: str = self.get("Root") return root diff --git a/blueman/bluez/obex/Transfer.py b/blueman/bluez/obex/Transfer.py index d25d84cb7..983ab8b92 100644 --- a/blueman/bluez/obex/Transfer.py +++ b/blueman/bluez/obex/Transfer.py @@ -9,12 +9,12 @@ class Transfer(Base): __gsignals__: GSignals = { - 'progress': (GObject.SignalFlags.NO_HOOKS, None, (int,)), - 'completed': (GObject.SignalFlags.NO_HOOKS, None, ()), - 'error': (GObject.SignalFlags.NO_HOOKS, None, ()) + "progress": (GObject.SignalFlags.NO_HOOKS, None, (int,)), + "completed": (GObject.SignalFlags.NO_HOOKS, None, ()), + "error": (GObject.SignalFlags.NO_HOOKS, None, ()), } - _interface_name = 'org.bluez.obex.Transfer1' + _interface_name = "org.bluez.obex.Transfer1" def __init__(self, obj_path: str): super().__init__(obj_path=obj_path) @@ -39,15 +39,16 @@ def size(self) -> Optional[int]: size: Optional[int] = self.get("Size") return size - def _properties_changed(self, _proxy: Gio.DBusProxy, changed_properties: GLib.Variant, - _invalidated_properties: List[str]) -> None: + def _properties_changed( + self, _proxy: Gio.DBusProxy, changed_properties: GLib.Variant, _invalidated_properties: List[str] + ) -> None: logging.debug(f"{changed_properties}") for name, value in changed_properties.unpack().items(): logging.debug(f"{self.get_object_path()} {name} {value}") - if name == 'Transferred': - self.emit('progress', value) - elif name == 'Status': - if value == 'complete': - self.emit('completed') - elif value == 'error': - self.emit('error') + if name == "Transferred": + self.emit("progress", value) + elif name == "Status": + if value == "complete": + self.emit("completed") + elif value == "error": + self.emit("error") diff --git a/blueman/config/AutoConnectConfig.py b/blueman/config/AutoConnectConfig.py index ab5869cfc..6bf07e14e 100644 --- a/blueman/config/AutoConnectConfig.py +++ b/blueman/config/AutoConnectConfig.py @@ -1,5 +1,6 @@ from typing import Tuple import gi + gi.require_version("Gtk", "3.0") from gi.repository import Gtk from gi.repository import Gio diff --git a/blueman/gui/Animation.py b/blueman/gui/Animation.py index 09cac38c8..136f7d68b 100644 --- a/blueman/gui/Animation.py +++ b/blueman/gui/Animation.py @@ -1,6 +1,7 @@ from typing import Iterable, Optional from gi import require_version + require_version("Gtk", "3.0") from gi.repository import GLib, Gtk diff --git a/blueman/gui/CommonUi.py b/blueman/gui/CommonUi.py index cbdec40ae..f82ee9fd7 100644 --- a/blueman/gui/CommonUi.py +++ b/blueman/gui/CommonUi.py @@ -5,6 +5,7 @@ from blueman.Constants import WEBSITE, VERSION import gi + gi.require_version("Gtk", "3.0") from gi.repository import Gtk @@ -13,13 +14,28 @@ class ErrorDialog(Gtk.MessageDialog): - def __init__(self, markup: str, secondary_markup: Optional[str] = None, excp: Optional[object] = None, - icon_name: str = "dialog-error", buttons: Gtk.ButtonsType = Gtk.ButtonsType.CLOSE, - title: Optional[str] = None, parent: Optional[Gtk.Container] = None, modal: bool = False, - margin_left: int = 0, - ) -> None: - super().__init__(name="ErrorDialog", icon_name=icon_name, buttons=buttons, - type=Gtk.MessageType.ERROR, title=title, parent=parent, modal=modal, margin_left=margin_left) + def __init__( + self, + markup: str, + secondary_markup: Optional[str] = None, + excp: Optional[object] = None, + icon_name: str = "dialog-error", + buttons: Gtk.ButtonsType = Gtk.ButtonsType.CLOSE, + title: Optional[str] = None, + parent: Optional[Gtk.Container] = None, + modal: bool = False, + margin_left: int = 0, + ) -> None: + super().__init__( + name="ErrorDialog", + icon_name=icon_name, + buttons=buttons, + type=Gtk.MessageType.ERROR, + title=title, + parent=parent, + modal=modal, + margin_left=margin_left, + ) self.set_markup(markup) @@ -49,8 +65,9 @@ def show_about_dialog(app_name: str, run: "Literal[False]", parent: Optional[Gtk ... -def show_about_dialog(app_name: str, run: bool = True, parent: Optional[Gtk.Window] = None - ) -> Optional[Gtk.AboutDialog]: +def show_about_dialog( + app_name: str, run: bool = True, parent: Optional[Gtk.Window] = None +) -> Optional[Gtk.AboutDialog]: about = Gtk.AboutDialog() about.set_transient_for(parent) about.set_modal(True) @@ -58,19 +75,23 @@ def show_about_dialog(app_name: str, run: bool = True, parent: Optional[Gtk.Wind about.connect("response", lambda x, y: about.destroy()) about.set_name(app_name) about.set_version(VERSION) - about.set_copyright('Copyright © 2008 Valmantas Palikša\n' - 'Copyright © 2008 Tadas Dailyda\n' - f'Copyright © 2008 - {datetime.now().year} blueman project' - ) - about.set_comments(_('Blueman is a GTK+ Bluetooth manager')) + about.set_copyright( + "Copyright © 2008 Valmantas Palikša\n" + "Copyright © 2008 Tadas Dailyda\n" + f"Copyright © 2008 - {datetime.now().year} blueman project" + ) + about.set_comments(_("Blueman is a GTK+ Bluetooth manager")) about.set_website(WEBSITE) about.set_website_label(WEBSITE) - about.set_icon_name('blueman') - about.set_logo_icon_name('blueman') - about.set_authors(['Valmantas Palikša ', - 'Tadas Dailyda ', - f'{WEBSITE}/graphs/contributors' - ]) + about.set_icon_name("blueman") + about.set_logo_icon_name("blueman") + about.set_authors( + [ + "Valmantas Palikša ", + "Tadas Dailyda ", + f"{WEBSITE}/graphs/contributors", + ] + ) if run: about.show() return None diff --git a/blueman/gui/DeviceList.py b/blueman/gui/DeviceList.py index 58684f1d1..b699f1b6b 100644 --- a/blueman/gui/DeviceList.py +++ b/blueman/gui/DeviceList.py @@ -25,24 +25,48 @@ class DeviceList(GenericList): __gsignals__: GSignals = { # @param: device TreeIter # note: None None is given when there ar no more rows, or when selected device is removed - 'device-selected': (GObject.SignalFlags.RUN_LAST, None, (Device, Gtk.TreeIter,)), + "device-selected": ( + GObject.SignalFlags.RUN_LAST, + None, + ( + Device, + Gtk.TreeIter, + ), + ), # @param: device, TreeIter, (key, value) - 'device-property-changed': (GObject.SignalFlags.RUN_LAST, None, (Device, Gtk.TreeIter, object,)), + "device-property-changed": ( + GObject.SignalFlags.RUN_LAST, + None, + ( + Device, + Gtk.TreeIter, + object, + ), + ), # @param: adapter, (key, value) - 'adapter-property-changed': (GObject.SignalFlags.RUN_LAST, None, (Adapter, object,)), + "adapter-property-changed": ( + GObject.SignalFlags.RUN_LAST, + None, + ( + Adapter, + object, + ), + ), # @param: progress (0 to 1) - 'discovery-progress': (GObject.SignalFlags.RUN_LAST, None, (float,)), - + "discovery-progress": (GObject.SignalFlags.RUN_LAST, None, (float,)), # @param: new adapter path, None if there are no more adapters - 'adapter-changed': (GObject.SignalFlags.RUN_LAST, None, (str,)), - + "adapter-changed": (GObject.SignalFlags.RUN_LAST, None, (str,)), # @param: adapter path - 'adapter-added': (GObject.SignalFlags.RUN_LAST, None, (str,)), - 'adapter-removed': (GObject.SignalFlags.RUN_LAST, None, (str,)), + "adapter-added": (GObject.SignalFlags.RUN_LAST, None, (str,)), + "adapter-removed": (GObject.SignalFlags.RUN_LAST, None, (str,)), } - def __init__(self, adapter_name: Optional[str] = None, tabledata: Optional[List[ListDataDict]] = None, - headers_visible: bool = True) -> None: + def __init__( + self, + adapter_name: Optional[str] = None, + tabledata: Optional[List[ListDataDict]] = None, + headers_visible: bool = True, + ) -> None: if not tabledata: tabledata = [] @@ -51,14 +75,18 @@ def __init__(self, adapter_name: Optional[str] = None, tabledata: Optional[List[ self.manager = Manager() self._managerhandlers: List[int] = [] - self._managerhandlers.append(self.manager.connect_signal('adapter-removed', self.__on_manager_signal, - 'adapter-removed')) - self._managerhandlers.append(self.manager.connect_signal('adapter-added', self.__on_manager_signal, - 'adapter-added')) - self._managerhandlers.append(self.manager.connect_signal('device-created', self.__on_manager_signal, - 'device-created')) - self._managerhandlers.append(self.manager.connect_signal('device-removed', self.__on_manager_signal, - 'device-removed')) + self._managerhandlers.append( + self.manager.connect_signal("adapter-removed", self.__on_manager_signal, "adapter-removed") + ) + self._managerhandlers.append( + self.manager.connect_signal("adapter-added", self.__on_manager_signal, "adapter-added") + ) + self._managerhandlers.append( + self.manager.connect_signal("device-created", self.__on_manager_signal, "device-created") + ) + self._managerhandlers.append( + self.manager.connect_signal("device-removed", self.__on_manager_signal, "device-removed") + ) self.any_device = AnyDevice() self._anydevhandler = self.any_device.connect_signal("property-changed", self._on_device_property_changed) @@ -72,7 +100,7 @@ def __init__(self, adapter_name: Optional[str] = None, tabledata: Optional[List[ {"id": "device", "type": object}, {"id": "dbus_path", "type": str}, {"id": "timestamp", "type": float}, - {"id": "no_name", "type": bool} + {"id": "no_name", "type": bool}, ] super().__init__(data, headers_visible=headers_visible) @@ -82,7 +110,7 @@ def __init__(self, adapter_name: Optional[str] = None, tabledata: Optional[List[ self._any_adapter = AnyAdapter() self._anyadapterhandler = self._any_adapter.connect_signal("property-changed", self._on_property_changed) - self._selectionhandler = self.selection.connect('changed', self.on_selection_changed) + self._selectionhandler = self.selection.connect("changed", self.on_selection_changed) self.icon_theme = Gtk.IconTheme.get_default() self.icon_theme.prepend_search_path(ICON_PATH) @@ -98,23 +126,23 @@ def destroy(self) -> None: super().destroy() def __on_manager_signal(self, _manager: Manager, path: str, signal_name: str) -> None: - if signal_name == 'adapter-removed': + if signal_name == "adapter-removed": self.emit("adapter-removed", path) if path == self.__adapter_path: self.clear() self.Adapter = None self.set_adapter() - if signal_name == 'adapter-added': + if signal_name == "adapter-added": if self.Adapter is None: self.set_adapter(path) self.emit("adapter-added", path) - if signal_name == 'device-created': + if signal_name == "device-created": self.device_add_event(path) - if signal_name == 'device-removed': + if signal_name == "device-removed": self.device_remove_event(path) def on_selection_changed(self, selection: Gtk.TreeSelection) -> None: @@ -190,7 +218,7 @@ def set_adapter(self, adapter: Optional[str] = None) -> None: self.Adapter = self.manager.get_adapter(adapter) self.__adapter_path = self.Adapter.get_object_path() except DBusNoSuchAdapterError: - logging.warning('Failed to set adapter, trying first available.') + logging.warning("Failed to set adapter, trying first available.") self.set_adapter(None) return else: @@ -223,7 +251,7 @@ def update_progress(self, time: float, totaltime: float) -> bool: def add_device(self, object_path: str) -> None: device = Device(obj_path=object_path) # device belongs to another adapter - if not self.Adapter or not device['Adapter'] == self.Adapter.get_object_path(): + if not self.Adapter or not device["Adapter"] == self.Adapter.get_object_path(): return logging.info("adding new device") @@ -231,8 +259,8 @@ def add_device(self, object_path: str) -> None: colls = { "device": device, "dbus_path": object_path, - "timestamp": float(datetime.strftime(datetime.now(), '%Y%m%d%H%M%S%f')), - "no_name": "Name" not in device + "timestamp": float(datetime.strftime(datetime.now(), "%Y%m%d%H%M%S%f")), + "no_name": "Name" not in device, } tree_iter = self.append(**colls) @@ -245,8 +273,9 @@ def populate_devices(self) -> None: self.clear() self.manager.populate_devices() - def discover_devices(self, time: float = 60.0, - error_handler: Optional[Callable[[BluezDBusException], None]] = None) -> None: + def discover_devices( + self, time: float = 60.0, error_handler: Optional[Callable[[BluezDBusException], None]] = None + ) -> None: if not self.discovering: self.__discovery_time = 0 if self.Adapter is not None: @@ -307,11 +336,11 @@ def do_cache(self, tree_iter: Gtk.TreeIter, kwargs: Dict[str, Any]) -> None: if "device" in kwargs: if kwargs["device"]: - object_path = kwargs['device'].get_object_path() + object_path = kwargs["device"].get_object_path() elif "dbus_path" in kwargs: if kwargs["dbus_path"]: - object_path = kwargs['dbus_path'] + object_path = kwargs["dbus_path"] else: existing = self.get(tree_iter, "dbus_path")["dbus_path"] if existing is not None: @@ -319,8 +348,7 @@ def do_cache(self, tree_iter: Gtk.TreeIter, kwargs: Dict[str, Any]) -> None: if object_path: logging.info(f"Caching new device {object_path}") - self.path_to_row[object_path] = Gtk.TreeRowReference.new(self.liststore, - self.liststore.get_path(tree_iter)) + self.path_to_row[object_path] = Gtk.TreeRowReference.new(self.liststore, self.liststore.get_path(tree_iter)) def append(self, **columns: object) -> Gtk.TreeIter: tree_iter = super().append(**columns) diff --git a/blueman/gui/DeviceSelectorDialog.py b/blueman/gui/DeviceSelectorDialog.py index dfd22cd11..b0ec0382a 100644 --- a/blueman/gui/DeviceSelectorDialog.py +++ b/blueman/gui/DeviceSelectorDialog.py @@ -6,13 +6,19 @@ from blueman.gui.DeviceSelectorWidget import DeviceSelectorWidget import gi + gi.require_version("Gtk", "3.0") from gi.repository import Gtk class DeviceSelectorDialog(Gtk.Dialog): - def __init__(self, title: str = _("Select Device"), parent: Optional[Gtk.Container] = None, discover: bool = True, - adapter_name: Optional[str] = None) -> None: + def __init__( + self, + title: str = _("Select Device"), + parent: Optional[Gtk.Container] = None, + discover: bool = True, + adapter_name: Optional[str] = None, + ) -> None: super().__init__(title=title, name="DeviceSelectorDialog", parent=parent, icon_name="blueman", resizable=False) self.add_buttons(_("_Cancel"), Gtk.ResponseType.REJECT, _("_OK"), Gtk.ResponseType.ACCEPT) @@ -38,8 +44,9 @@ def close(self) -> None: self.selector.destroy() super().close() - def on_row_activated(self, _treeview: Gtk.TreeView, _path: Gtk.TreePath, _view_column: Gtk.TreeViewColumn, - *_args: object) -> None: + def on_row_activated( + self, _treeview: Gtk.TreeView, _path: Gtk.TreePath, _view_column: Gtk.TreeViewColumn, *_args: object + ) -> None: self.response(Gtk.ResponseType.ACCEPT) def on_adapter_changed(self, _devlist: DeviceList, _adapter: str) -> None: diff --git a/blueman/gui/DeviceSelectorList.py b/blueman/gui/DeviceSelectorList.py index 7783fb22a..bbed893f6 100644 --- a/blueman/gui/DeviceSelectorList.py +++ b/blueman/gui/DeviceSelectorList.py @@ -17,16 +17,32 @@ class DeviceSelectorList(DeviceList): def __init__(self, adapter_name: Optional[str] = None) -> None: tabledata: List[ListDataDict] = [ # device picture - {"id": "device_icon", "type": str, "renderer": Gtk.CellRendererPixbuf(stock_size=Gtk.IconSize.MENU), - "render_attrs": {"icon_name": 0}}, + { + "id": "device_icon", + "type": str, + "renderer": Gtk.CellRendererPixbuf(stock_size=Gtk.IconSize.MENU), + "render_attrs": {"icon_name": 0}, + }, # device caption - {"id": "caption", "type": str, "renderer": Gtk.CellRendererText(ellipsize=Pango.EllipsizeMode.END), - "render_attrs": {"markup": 1}, - "view_props": {"expand": True}}, - {"id": "paired_icon", "type": str, "renderer": Gtk.CellRendererPixbuf(stock_size=Gtk.IconSize.MENU), - "render_attrs": {"icon_name": 2}}, - {"id": "trusted_icon", "type": str, "renderer": Gtk.CellRendererPixbuf(stock_size=Gtk.IconSize.MENU), - "render_attrs": {"icon_name": 3}} + { + "id": "caption", + "type": str, + "renderer": Gtk.CellRendererText(ellipsize=Pango.EllipsizeMode.END), + "render_attrs": {"markup": 1}, + "view_props": {"expand": True}, + }, + { + "id": "paired_icon", + "type": str, + "renderer": Gtk.CellRendererPixbuf(stock_size=Gtk.IconSize.MENU), + "render_attrs": {"icon_name": 2}, + }, + { + "id": "trusted_icon", + "type": str, + "renderer": Gtk.CellRendererPixbuf(stock_size=Gtk.IconSize.MENU), + "render_attrs": {"icon_name": 3}, + }, ] super().__init__(adapter_name, tabledata, headers_visible=False) @@ -37,10 +53,10 @@ def on_icon_theme_changed(self, _icon_them: Gtk.IconTheme) -> None: self.row_setup_event(row.iter, device) def row_setup_event(self, tree_iter: Gtk.TreeIter, device: Device) -> None: - self.row_update_event(tree_iter, "Trusted", device['Trusted']) - self.row_update_event(tree_iter, "Paired", device['Paired']) + self.row_update_event(tree_iter, "Trusted", device["Trusted"]) + self.row_update_event(tree_iter, "Paired", device["Paired"]) self.row_update_event(tree_iter, "Alias", device.display_name) - self.row_update_event(tree_iter, "Icon", device['Icon']) + self.row_update_event(tree_iter, "Icon", device["Icon"]) def row_update_event(self, tree_iter: Gtk.TreeIter, key: str, value: Any) -> None: if key == "Trusted": diff --git a/blueman/gui/DeviceSelectorWidget.py b/blueman/gui/DeviceSelectorWidget.py index 2c1ea94ca..b904acde3 100644 --- a/blueman/gui/DeviceSelectorWidget.py +++ b/blueman/gui/DeviceSelectorWidget.py @@ -7,25 +7,37 @@ from blueman.gui.DeviceSelectorList import DeviceSelectorList import gi + gi.require_version("Gtk", "3.0") from gi.repository import Gtk class DeviceSelectorWidget(Gtk.Box): - def __init__(self, adapter_name: Optional[str] = None, orientation: Gtk.Orientation = Gtk.Orientation.VERTICAL, - visible: bool = False) -> None: - - super().__init__(orientation=orientation, spacing=1, vexpand=True, - width_request=360, height_request=340, - name="DeviceSelectorWidget", visible=visible) + def __init__( + self, + adapter_name: Optional[str] = None, + orientation: Gtk.Orientation = Gtk.Orientation.VERTICAL, + visible: bool = False, + ) -> None: + super().__init__( + orientation=orientation, + spacing=1, + vexpand=True, + width_request=360, + height_request=340, + name="DeviceSelectorWidget", + visible=visible, + ) self.List = DeviceSelectorList(adapter_name) if self.List.Adapter is not None: self.List.populate_devices() - sw = Gtk.ScrolledWindow(hscrollbar_policy=Gtk.PolicyType.NEVER, - vscrollbar_policy=Gtk.PolicyType.AUTOMATIC, - shadow_type=Gtk.ShadowType.IN) + sw = Gtk.ScrolledWindow( + hscrollbar_policy=Gtk.PolicyType.NEVER, + vscrollbar_policy=Gtk.PolicyType.AUTOMATIC, + shadow_type=Gtk.ShadowType.IN, + ) sw.add(self.List) self.pack_start(sw, True, True, 0) @@ -38,11 +50,12 @@ def __init__(self, adapter_name: Optional[str] = None, orientation: Gtk.Orientat self.cb_adapters = Gtk.ComboBox(model=model, visible=True) self.cb_adapters.set_tooltip_text(_("Adapter selection")) self.cb_adapters.pack_start(cell, True) - self.cb_adapters.add_attribute(cell, 'text', 0) + self.cb_adapters.add_attribute(cell, "text", 0) spinner_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6, height_request=8) - self.spinner = Gtk.Spinner(halign=Gtk.Align.START, hexpand=True, has_tooltip=True, - tooltip_text=_("Discovering…"), margin=6) + self.spinner = Gtk.Spinner( + halign=Gtk.Align.START, hexpand=True, has_tooltip=True, tooltip_text=_("Discovering…"), margin=6 + ) spinner_box.add(self.cb_adapters) spinner_box.add(self.spinner) @@ -62,8 +75,9 @@ def __del__(self) -> None: self.List.destroy() logging.debug("Deleting widget") - def on_adapter_prop_changed(self, _devlist: DeviceSelectorList, adapter: Adapter, key_value: Tuple[str, object] - ) -> None: + def on_adapter_prop_changed( + self, _devlist: DeviceSelectorList, adapter: Adapter, key_value: Tuple[str, object] + ) -> None: key, value = key_value if key == "Name" or key == "Alias": self.update_adapters_list() diff --git a/blueman/gui/GenericList.py b/blueman/gui/GenericList.py index 50ed2db5b..67425c55a 100644 --- a/blueman/gui/GenericList.py +++ b/blueman/gui/GenericList.py @@ -1,6 +1,7 @@ from typing import Dict, Optional, TYPE_CHECKING, Iterable, Mapping, Callable, Tuple, Collection, Any import gi + gi.require_version("Gtk", "3.0") from gi.repository import Gtk @@ -16,8 +17,10 @@ class ListDataDict(_ListDataDictBase, total=False): renderer: Gtk.CellRenderer render_attrs: Mapping[str, int] view_props: Mapping[str, object] - celldata_func: Tuple[Callable[[Gtk.TreeViewColumn, Gtk.CellRenderer, Gtk.TreeModelFilter, Gtk.TreeIter, Any], - None], Any] + celldata_func: Tuple[ + Callable[[Gtk.TreeViewColumn, Gtk.CellRenderer, Gtk.TreeModelFilter, Gtk.TreeIter, Any], None], Any + ] + else: ListDataDict = dict diff --git a/blueman/gui/GsmSettings.py b/blueman/gui/GsmSettings.py index fd971f40f..6efa7a91b 100644 --- a/blueman/gui/GsmSettings.py +++ b/blueman/gui/GsmSettings.py @@ -3,6 +3,7 @@ from blueman.main.Builder import Builder import gi + gi.require_version("Gtk", "3.0") from gi.repository import Gtk from gi.repository import Gio @@ -19,8 +20,7 @@ def __init__(self, bd_address: str) -> None: gsm_grid = builder.get_widget("gsm_grid", Gtk.Grid) - self.config = Gio.Settings(schema_id="org.blueman.gsmsetting", - path=f"/org/blueman/gsmsettings/{bd_address}/") + self.config = Gio.Settings(schema_id="org.blueman.gsmsetting", path=f"/org/blueman/gsmsettings/{bd_address}/") self.props.icon_name = "network-wireless-symbolic" self.props.title = _("GSM Settings") diff --git a/blueman/gui/GtkAnimation.py b/blueman/gui/GtkAnimation.py index 4aeccd8db..5f0c56d6c 100644 --- a/blueman/gui/GtkAnimation.py +++ b/blueman/gui/GtkAnimation.py @@ -7,6 +7,7 @@ gi.require_version("Gtk", "3.0") from gi.repository import Gtk + gi.require_version("Gdk", "3.0") from gi.repository import Gdk from gi.repository import GObject @@ -15,12 +16,13 @@ if TYPE_CHECKING: from blueman.gui.manager.ManagerDeviceList import ManagerDeviceList + BaseContext = cairo.Context[cairo.Surface] class AnimBase(GObject.GObject): __gsignals__: GSignals = { - 'animation-finished': (GObject.SignalFlags.RUN_LAST, None, ()), + "animation-finished": (GObject.SignalFlags.RUN_LAST, None, ()), } def __init__(self, state: float = 1.0) -> None: @@ -101,9 +103,9 @@ def is_animating(self) -> bool: class TreeRowFade(AnimBase): - def __init__(self, tw: "ManagerDeviceList", - path: Gtk.TreePath, - columns: Optional[Collection[Gtk.TreeViewColumn]] = None) -> None: + def __init__( + self, tw: "ManagerDeviceList", path: Gtk.TreePath, columns: Optional[Collection[Gtk.TreeViewColumn]] = None + ) -> None: super().__init__(1.0) self.tw = tw assert self.tw.liststore is not None diff --git a/blueman/gui/Notification.py b/blueman/gui/Notification.py index 5635189fa..021f29232 100644 --- a/blueman/gui/Notification.py +++ b/blueman/gui/Notification.py @@ -1,6 +1,7 @@ from typing import Dict, List, Callable, Optional, Iterable, Tuple, Union, Type import gi + gi.require_version("Gtk", "3.0") gi.require_version("Gdk", "3.0") from gi.repository import Gtk @@ -24,12 +25,17 @@ def state_changed(self, state: float) -> None: class _NotificationDialog(Gtk.MessageDialog): - def __init__(self, summary: str, message: str, _timeout: int = -1, - actions: Optional[Iterable[Tuple[str, str]]] = None, - actions_cb: Optional[Callable[[str], None]] = None, icon_name: Optional[str] = None, - image_data: Optional[GdkPixbuf.Pixbuf] = None) -> None: - super().__init__(parent=None, type=Gtk.MessageType.QUESTION, - buttons=Gtk.ButtonsType.NONE, text=None) + def __init__( + self, + summary: str, + message: str, + _timeout: int = -1, + actions: Optional[Iterable[Tuple[str, str]]] = None, + actions_cb: Optional[Callable[[str], None]] = None, + icon_name: Optional[str] = None, + image_data: Optional[GdkPixbuf.Pixbuf] = None, + ) -> None: + super().__init__(parent=None, type=Gtk.MessageType.QUESTION, buttons=Gtk.ButtonsType.NONE, text=None) self.set_name("NotificationDialog") i = 100 @@ -119,43 +125,51 @@ def set_icon_from_icon_name(self, icon_name: str, size: int) -> None: class _NotificationBubble(Gio.DBusProxy): - def __init__(self, summary: str, message: str, timeout: int = -1, - actions: Optional[Iterable[Tuple[str, str]]] = None, - actions_cb: Optional[Callable[[str], None]] = None, icon_name: Optional[str] = None, - image_data: Optional[GdkPixbuf.Pixbuf] = None) -> None: + def __init__( + self, + summary: str, + message: str, + timeout: int = -1, + actions: Optional[Iterable[Tuple[str, str]]] = None, + actions_cb: Optional[Callable[[str], None]] = None, + icon_name: Optional[str] = None, + image_data: Optional[GdkPixbuf.Pixbuf] = None, + ) -> None: super().__init__( - g_name='org.freedesktop.Notifications', - g_interface_name='org.freedesktop.Notifications', - g_object_path='/org/freedesktop/Notifications', + g_name="org.freedesktop.Notifications", + g_interface_name="org.freedesktop.Notifications", + g_object_path="/org/freedesktop/Notifications", g_bus_type=Gio.BusType.SESSION, - g_flags=Gio.DBusProxyFlags.NONE) + g_flags=Gio.DBusProxyFlags.NONE, + ) self.init() - self._app_name = 'blueman' - self._app_icon = '' + self._app_name = "blueman" + self._app_icon = "" self._actions: List[str] = [] self._callbacks: Dict[str, Callable[[str], None]] = {} self._hints: Dict[str, GLib.Variant] = {} # hint : (variant format, spec version) self._supported_hints = { - 'action-icons': ('b', 1.2), - 'category': ('s', 0), - 'desktop-entry': ('s', 0), - 'image-data': ('(iiibiiay)', 1.2), - 'image_data': ('(iiibiiay)', 1.1), - 'image-path': ('s', 1.2), - 'image_path': ('s', 1.1), - 'icon_data': ('(iiibiiay)', 0), - 'resident': ('b', 1.2), - 'sound-file': ('s', 0), - 'sound-name': ('s', 0), - 'suppress-sound': ('b', 0), - 'transient': ('b', 1.2), - 'x': ('i', 0), - 'y': ('i', 0), - 'urgency': ('y', 0)} + "action-icons": ("b", 1.2), + "category": ("s", 0), + "desktop-entry": ("s", 0), + "image-data": ("(iiibiiay)", 1.2), + "image_data": ("(iiibiiay)", 1.1), + "image-path": ("s", 1.2), + "image_path": ("s", 1.1), + "icon_data": ("(iiibiiay)", 0), + "resident": ("b", 1.2), + "sound-file": ("s", 0), + "sound-name": ("s", 0), + "suppress-sound": ("b", 0), + "transient": ("b", 1.2), + "x": ("i", 0), + "y": ("i", 0), + "urgency": ("y", 0), + } self._body = message self._summary = summary @@ -174,13 +188,13 @@ def __init__(self, summary: str, message: str, timeout: int = -1, data = image_data.get_pixels() supported_spec = float(self.server_information[-1]) if supported_spec < 1.1: - key = 'icon_data' + key = "icon_data" elif supported_spec < 1.2: - key = 'image_data' + key = "image_data" elif supported_spec >= 1.2: - key = 'image-data' + key = "image-data" else: - raise ValueError('Not supported by server') + raise ValueError("Not supported by server") self.set_hint(key, (w, h, stride, alpha, bits, channel, data)) @@ -207,20 +221,20 @@ def server_information(self) -> Tuple[str, str, str, str]: @property def actions_supported(self) -> bool: - return 'actions' in self._capabilities + return "actions" in self._capabilities def set_hint(self, key: str, val: object) -> None: if key not in self._supported_hints: - raise ValueError('Unsupported hint') + raise ValueError("Unsupported hint") fmt, spec_version = self._supported_hints[key] if spec_version > float(self.server_information[-1]): - raise ValueError('Not supported by server') + raise ValueError("Not supported by server") param = GLib.Variant(fmt, val) self._hints[key] = param def remove_hint(self, key: str) -> None: - del (self._hints[key]) + del self._hints[key] def clear_hints(self) -> None: self._hints = {} @@ -241,46 +255,67 @@ def do_g_signal(self, _sender_name: str, signal_name: str, params: GLib.Variant) logging.info(signal_val) - if signal_name == 'NotificationClosed': + if signal_name == "NotificationClosed": if signal_val == 1: - logging.debug('The notification expired.') + logging.debug("The notification expired.") elif signal_val == 2: - logging.debug('The notification was dismissed by the user.') + logging.debug("The notification was dismissed by the user.") elif signal_val == 3: - logging.debug('The notification was closed by a call to CloseNotification.') + logging.debug("The notification was closed by a call to CloseNotification.") elif signal_val == 4: - logging.debug('Undefined/reserved reasons.') - elif signal_name == 'ActionInvoked': + logging.debug("Undefined/reserved reasons.") + elif signal_name == "ActionInvoked": if signal_val in self._callbacks: self._callbacks[signal_val](signal_val) def show(self) -> None: replace_id = self._return_id if self._return_id else 0 - return_id = self.Notify('(susssasa{sv}i)', self._app_name, replace_id, self._app_icon, - self._summary, self._body, self._actions, self._hints, - self._timeout) + return_id = self.Notify( + "(susssasa{sv}i)", + self._app_name, + replace_id, + self._app_icon, + self._summary, + self._body, + self._actions, + self._hints, + self._timeout, + ) self._return_id = return_id def close(self) -> None: - param = GLib.Variant('(u)', (self._return_id,)) - self.call_sync('CloseNotification', param, Gio.DBusCallFlags.NONE, -1, None) + param = GLib.Variant("(u)", (self._return_id,)) + self.call_sync("CloseNotification", param, Gio.DBusCallFlags.NONE, -1, None) self._return_id = None -def Notification(summary: str, message: str, timeout: int = -1, actions: Optional[Iterable[Tuple[str, str]]] = None, - actions_cb: Optional[Callable[[str], None]] = None, icon_name: Optional[str] = None, - image_data: Optional[GdkPixbuf.Pixbuf] = None) -> Union[_NotificationBubble, _NotificationDialog]: - - forced_fallback = not Gio.Settings(schema_id='org.blueman.general')['notification-daemon'] +def Notification( + summary: str, + message: str, + timeout: int = -1, + actions: Optional[Iterable[Tuple[str, str]]] = None, + actions_cb: Optional[Callable[[str], None]] = None, + icon_name: Optional[str] = None, + image_data: Optional[GdkPixbuf.Pixbuf] = None, +) -> Union[_NotificationBubble, _NotificationDialog]: + forced_fallback = not Gio.Settings(schema_id="org.blueman.general")["notification-daemon"] try: bus = Gio.bus_get_sync(Gio.BusType.SESSION) - caps = bus.call_sync('org.freedesktop.Notifications', '/org/freedesktop/Notifications', - 'org.freedesktop.Notifications', 'GetCapabilities', None, None, - Gio.DBusCallFlags.NONE, -1, None).unpack()[0] + caps = bus.call_sync( + "org.freedesktop.Notifications", + "/org/freedesktop/Notifications", + "org.freedesktop.Notifications", + "GetCapabilities", + None, + None, + Gio.DBusCallFlags.NONE, + -1, + None, + ).unpack()[0] except GLib.Error: caps = [] - if forced_fallback or 'body' not in caps or (actions and 'actions' not in caps): + if forced_fallback or "body" not in caps or (actions and "actions" not in caps): # Use fallback in the case: # * user does not want to use a notification daemon # * the notification daemon is not available diff --git a/blueman/gui/applet/PluginDialog.py b/blueman/gui/applet/PluginDialog.py index 7d339cea5..13fce96eb 100644 --- a/blueman/gui/applet/PluginDialog.py +++ b/blueman/gui/applet/PluginDialog.py @@ -9,6 +9,7 @@ from blueman.plugins.BasePlugin import Option import gi + gi.require_version("Gtk", "3.0") gi.require_version("Gdk", "3.0") from gi.repository import Gtk, Gdk, Gio @@ -19,11 +20,7 @@ class SettingsWidget(Gtk.Box): def __init__(self, inst: AppletPlugin, orientation: Gtk.Orientation = Gtk.Orientation.VERTICAL) -> None: - super().__init__( - name="SettingsWidget", - orientation=orientation, - spacing=2 - ) + super().__init__(name="SettingsWidget", orientation=orientation, spacing=2) self.inst = inst self.construct_settings() @@ -32,7 +29,6 @@ def __init__(self, inst: AppletPlugin, orientation: Gtk.Orientation = Gtk.Orient def construct_settings(self) -> None: for k, v in self.inst.__class__.__options__.items(): if len(v) > 2: - label = Gtk.Label(label=v["name"]) label.props.xalign = 0.0 @@ -99,7 +95,7 @@ def __init__(self, applet: "BluemanApplet") -> None: default_width=490, default_height=380, resizable=False, - visible=False + visible=False, ) self.set_position(Gtk.WindowPosition.CENTER) @@ -128,13 +124,22 @@ def __init__(self, applet: "BluemanApplet") -> None: cr.connect("toggled", self.on_toggled) data: List[ListDataDict] = [ - {"id": "active", "type": bool, "renderer": cr, "render_attrs": {"active": 0, "activatable": 1, - "visible": 1}}, + { + "id": "active", + "type": bool, + "renderer": cr, + "render_attrs": {"active": 0, "activatable": 1, "visible": 1}, + }, {"id": "activatable", "type": bool}, {"id": "icon", "type": str, "renderer": Gtk.CellRendererPixbuf(), "render_attrs": {"icon-name": 2}}, # device caption - {"id": "desc", "type": str, "renderer": Gtk.CellRendererText(), "render_attrs": {"markup": 3}, - "view_props": {"expand": True}}, + { + "id": "desc", + "type": str, + "renderer": Gtk.CellRendererText(), + "render_attrs": {"markup": 3}, + "view_props": {"expand": True}, + }, {"id": "name", "type": str}, ] @@ -165,8 +170,9 @@ def __init__(self, applet: "BluemanApplet") -> None: close_action.connect("activate", lambda x, y: self.close()) self.add_action(close_action) - def list_compare_func(self, _treemodel: Gtk.TreeModel, iter1: Gtk.TreeIter, iter2: Gtk.TreeIter, _user_data: object - ) -> int: + def list_compare_func( + self, _treemodel: Gtk.TreeModel, iter1: Gtk.TreeIter, iter2: Gtk.TreeIter, _user_data: object + ) -> int: a = self.list.get(iter1, "activatable", "name") b = self.list.get(iter2, "activatable", "name") @@ -258,11 +264,12 @@ def populate(self) -> None: loaded = self.applet.Plugins.get_loaded() for name, cls in classes.items(): if cls.is_configurable(): - desc = f"{name}" + desc = f'{name}' else: desc = name - self.list.append(active=(name in loaded), icon=cls.__icon__, activatable=cls.__unloadable__, name=name, - desc=desc) + self.list.append( + active=(name in loaded), icon=cls.__icon__, activatable=cls.__unloadable__, name=name, desc=desc + ) def plugin_state_changed(self, _plugins: PluginManager, name: str, loaded: bool) -> None: for row in self.list.liststore: @@ -289,8 +296,11 @@ def on_toggled(self, _toggle: Gtk.CellRendererToggle, path: str) -> None: if to_unload: if not self._ask_unload( - _("Plugin \"%(0)s\" depends on %(1)s. Unloading %(1)s will also unload " - "\"%(0)s\".\nProceed?") % {"0": ", ".join(to_unload), "1": name} + _( + 'Plugin "%(0)s" depends on %(1)s. Unloading %(1)s will also unload ' + '"%(0)s".\nProceed?' + ) + % {"0": ", ".join(to_unload), "1": name} ): return else: @@ -298,8 +308,11 @@ def on_toggled(self, _toggle: Gtk.CellRendererToggle, path: str) -> None: to_unload = [conf for conf in conflicts if conf in loaded] if to_unload and not self._ask_unload( - _("Plugin %(0)s conflicts with %(1)s. Loading %(1)s will unload %(0)s." - "\nProceed?") % {"0": ", ".join(to_unload), "1": name} + _( + "Plugin %(0)s conflicts with %(1)s. Loading %(1)s will unload %(0)s." + "\nProceed?" + ) + % {"0": ", ".join(to_unload), "1": name} ): return diff --git a/blueman/gui/manager/ManagerDeviceList.py b/blueman/gui/manager/ManagerDeviceList.py index 15a1d4e3f..3e36c7577 100644 --- a/blueman/gui/manager/ManagerDeviceList.py +++ b/blueman/gui/manager/ManagerDeviceList.py @@ -19,6 +19,7 @@ from _blueman import ConnInfoReadError, conn_info import gi + gi.require_version("Gtk", "3.0") from gi.repository import Gtk from gi.repository import GLib @@ -46,20 +47,45 @@ def __init__(self, inst: "Blueman", adapter: Optional[str] = None) -> None: cr.props.ellipsize = Pango.EllipsizeMode.END tabledata: List[ListDataDict] = [ # device picture - {"id": "device_surface", "type": SurfaceObject, "renderer": Gtk.CellRendererPixbuf(), - "render_attrs": {}, "celldata_func": (self._set_cell_data, None)}, + { + "id": "device_surface", + "type": SurfaceObject, + "renderer": Gtk.CellRendererPixbuf(), + "render_attrs": {}, + "celldata_func": (self._set_cell_data, None), + }, # device caption - {"id": "caption", "type": str, "renderer": cr, - "render_attrs": {"markup": 1}, "view_props": {"expand": True}}, - {"id": "battery_pb", "type": GdkPixbuf.Pixbuf, "renderer": Gtk.CellRendererPixbuf(), - "render_attrs": {}, "view_props": {"spacing": 0}, - "celldata_func": (self._set_cell_data, "battery")}, - {"id": "rssi_pb", "type": GdkPixbuf.Pixbuf, "renderer": Gtk.CellRendererPixbuf(), - "render_attrs": {}, "view_props": {"spacing": 0}, - "celldata_func": (self._set_cell_data, "rssi")}, - {"id": "tpl_pb", "type": GdkPixbuf.Pixbuf, "renderer": Gtk.CellRendererPixbuf(), - "render_attrs": {}, "view_props": {"spacing": 0}, - "celldata_func": (self._set_cell_data, "tpl")}, + { + "id": "caption", + "type": str, + "renderer": cr, + "render_attrs": {"markup": 1}, + "view_props": {"expand": True}, + }, + { + "id": "battery_pb", + "type": GdkPixbuf.Pixbuf, + "renderer": Gtk.CellRendererPixbuf(), + "render_attrs": {}, + "view_props": {"spacing": 0}, + "celldata_func": (self._set_cell_data, "battery"), + }, + { + "id": "rssi_pb", + "type": GdkPixbuf.Pixbuf, + "renderer": Gtk.CellRendererPixbuf(), + "render_attrs": {}, + "view_props": {"spacing": 0}, + "celldata_func": (self._set_cell_data, "rssi"), + }, + { + "id": "tpl_pb", + "type": GdkPixbuf.Pixbuf, + "renderer": Gtk.CellRendererPixbuf(), + "render_attrs": {}, + "view_props": {"spacing": 0}, + "celldata_func": (self._set_cell_data, "tpl"), + }, {"id": "alias", "type": str}, # used for quick access instead of device.GetProperties {"id": "connected", "type": bool}, # used for quick access instead of device.GetProperties {"id": "paired", "type": bool}, # used for quick access instead of device.GetProperties @@ -71,7 +97,7 @@ def __init__(self, inst: "Blueman", adapter: Optional[str] = None) -> None: {"id": "cell_fader", "type": CellFade}, {"id": "row_fader", "type": TreeRowFade}, {"id": "initial_anim", "type": bool}, - {"id": "blocked", "type": bool} + {"id": "blocked", "type": bool}, ] super().__init__(adapter, tabledata) self.set_name("ManagerDeviceList") @@ -86,7 +112,7 @@ def __init__(self, inst: "Blueman", adapter: Optional[str] = None) -> None: self._batteries: Dict[str, Battery] = {} self.Config = Gio.Settings(schema_id="org.blueman.general") - self.Config.connect('changed', self._on_settings_changed) + self.Config.connect("changed", self._on_settings_changed) # Set the correct sorting self._on_settings_changed(self.Config, "sort-by") self._on_settings_changed(self.Config, "sort-type") @@ -111,11 +137,11 @@ def __init__(self, inst: "Blueman", adapter: Optional[str] = None) -> None: self.filter.set_visible_func(self.filter_func) def _on_settings_changed(self, settings: Gio.Settings, key: str) -> None: - if key in ('sort-by', 'sort-order'): - sort_by = settings['sort-by'] - sort_order = settings['sort-order'] + if key in ("sort-by", "sort-order"): + sort_by = settings["sort-by"] + sort_order = settings["sort-order"] - if sort_order == 'ascending': + if sort_order == "ascending": sort_type = Gtk.SortType.ASCENDING else: sort_type = Gtk.SortType.DESCENDING @@ -159,9 +185,16 @@ def filter_func(self, _model: Gtk.TreeModel, tree_iter: Gtk.TreeIter, _data: Any else: return True - def drag_recv(self, _widget: Gtk.Widget, context: Gdk.DragContext, x: int, y: int, selection: Gtk.SelectionData, - _info: int, time: int) -> None: - + def drag_recv( + self, + _widget: Gtk.Widget, + context: Gdk.DragContext, + x: int, + y: int, + selection: Gtk.SelectionData, + _info: int, + time: int, + ) -> None: uris = list(selection.get_uris()) context.finish(True, False, time) @@ -239,7 +272,7 @@ def on_event_clicked(self, _widget: Gtk.Widget, event: Gdk.Event) -> bool: self.menu = ManagerDeviceMenu(self.Blueman) if event.type == Gdk.EventType._2BUTTON_PRESS and cast(Gdk.EventButton, event).button == 1: - if self.menu.show_generic_connect_calc(row["device"]['UUIDs']): + if self.menu.show_generic_connect_calc(row["device"]["UUIDs"]): if row["connected"]: self.menu.disconnect_service(row["device"]) else: @@ -260,8 +293,9 @@ def _load_surface(self, icon_name: str, size: int) -> cairo.ImageSurface: return cast(cairo.ImageSurface, surface) - def _make_device_icon(self, icon_name: str, is_paired: bool, is_connected: bool, is_trusted: bool, - is_blocked: bool) -> cairo.ImageSurface: + def _make_device_icon( + self, icon_name: str, is_paired: bool, is_connected: bool, is_trusted: bool, is_blocked: bool + ) -> cairo.ImageSurface: scale = self.get_scale_factor() target = self._load_surface(icon_name, 48) ctx = cairo.Context(target) @@ -307,8 +341,11 @@ def __fader_finished(self, object_path: str) -> None: @staticmethod def make_caption(name: str, klass: str, address: str) -> str: - return "%(0)s\n%(1)s\n%(2)s" \ - % {"0": html.escape(name), "1": klass, "2": address} + return "%(0)s\n%(1)s\n%(2)s" % { + "0": html.escape(name), + "1": klass, + "2": address, + } @staticmethod def make_display_name(alias: str, klass: int, address: str) -> str: @@ -319,11 +356,11 @@ def make_display_name(alias: str, klass: int, address: str) -> str: @staticmethod def get_device_class(device: Device) -> str: - klass = get_minor_class(device['Class']) + klass = get_minor_class(device["Class"]) if klass != _("Uncategorized"): return klass else: - return get_major_class(device['Class']) + return get_major_class(device["Class"]) def row_setup_event(self, tree_iter: Gtk.TreeIter, device: Device) -> None: if not self.get(tree_iter, "initial_anim")["initial_anim"]: @@ -346,7 +383,7 @@ def row_setup_event(self, tree_iter: Gtk.TreeIter, device: Device) -> None: self.set(tree_iter, initial_anim=False) has_objpush = self._has_objpush(device) - klass = get_minor_class(device['Class']) + klass = get_minor_class(device["Class"]) # Bluetooth >= 4 devices use Appearance property appearance = device["Appearance"] if klass != _("Uncategorized") and klass != _("Unknown"): @@ -354,22 +391,23 @@ def row_setup_event(self, tree_iter: Gtk.TreeIter, device: Device) -> None: elif klass == _("Unknown") and appearance: description = gatt_appearance_to_name(appearance) else: - description = get_major_class(device['Class']) + description = get_major_class(device["Class"]) - surface = self._make_device_icon(device["Icon"], device["Paired"], device["Connected"], device["Trusted"], - device["Blocked"]) + surface = self._make_device_icon( + device["Icon"], device["Paired"], device["Connected"], device["Trusted"], device["Blocked"] + ) surface_object = SurfaceObject(surface) - display_name = self.make_display_name(device.display_name, device["Class"], device['Address']) - caption = self.make_caption(display_name, description, device['Address']) + display_name = self.make_display_name(device.display_name, device["Class"], device["Address"]) + caption = self.make_caption(display_name, description, device["Address"]) self.set(tree_iter, caption=caption, alias=display_name, objpush=has_objpush, device_surface=surface_object) try: - self.row_update_event(tree_iter, "Trusted", device['Trusted']) + self.row_update_event(tree_iter, "Trusted", device["Trusted"]) except Exception as e: logging.exception(e) try: - self.row_update_event(tree_iter, "Paired", device['Paired']) + self.row_update_event(tree_iter, "Paired", device["Paired"]) except Exception as e: logging.exception(e) try: @@ -429,8 +467,9 @@ def row_update_event(self, tree_iter: Gtk.TreeIter, key: str, value: Any) -> Non device = self.get(tree_iter, "device")["device"] if key in ("Blocked", "Connected", "Paired", "Trusted"): - surface = self._make_device_icon(device["Icon"], device["Paired"], device["Connected"], device["Trusted"], - device["Blocked"]) + surface = self._make_device_icon( + device["Icon"], device["Paired"], device["Connected"], device["Trusted"], device["Blocked"] + ) self.set(tree_iter, device_surface=SurfaceObject(surface)) if key == "Trusted": @@ -446,7 +485,7 @@ def row_update_event(self, tree_iter: Gtk.TreeIter, key: str, value: Any) -> Non self.set(tree_iter, paired=False) elif key == "Alias": - c = self.make_caption(value, self.get_device_class(device), device['Address']) + c = self.make_caption(value, self.get_device_class(device), device["Address"]) name = self.make_display_name(device.display_name, device["Class"], device["Address"]) self.set(tree_iter, caption=c, alias=name) @@ -497,7 +536,7 @@ def _update_power_levels(self, tree_iter: Gtk.TreeIter, device: Device, cinfo: c w = 14 * self.get_scale_factor() h = 48 * self.get_scale_factor() - for (name, perc) in bars.items(): + for name, perc in bars.items(): if round(row[name], -1) != round(perc, -1): icon_name = f"blueman-{name}-{int(round(perc, -1))}.png" icon = GdkPixbuf.Pixbuf.new_from_file_at_scale(os.path.join(PIXMAP_PATH, icon_name), w, h, True) @@ -509,8 +548,9 @@ def _disable_power_levels(self, tree_iter: Gtk.TreeIter) -> None: return self.set(tree_iter, battery=0, rssi=0, tpl=0) - self._prepare_fader(row["cell_fader"], lambda: self.set(tree_iter, battery_pb=None, rssi_pb=None, - tpl_pb=None)).animate(start=1.0, end=0.0, duration=400) + self._prepare_fader( + row["cell_fader"], lambda: self.set(tree_iter, battery_pb=None, rssi_pb=None, tpl_pb=None) + ).animate(start=1.0, end=0.0, duration=400) def _prepare_fader(self, fader: AnimBase, callback: Optional[Callable[[], None]] = None) -> AnimBase: def on_finished(finished_fader: AnimBase) -> None: @@ -558,9 +598,11 @@ def tooltip_query(self, _tw: Gtk.Widget, x: int, y: int, _kb: bool, tooltip: Gtk self.tooltip_col = path[1] return True - elif path[1] == self.columns["battery_pb"] \ - or path[1] == self.columns["tpl_pb"] \ - or path[1] == self.columns["rssi_pb"]: + elif ( + path[1] == self.columns["battery_pb"] + or path[1] == self.columns["tpl_pb"] + or path[1] == self.columns["rssi_pb"] + ): tree_iter = self.get_iter(path[0]) assert tree_iter is not None @@ -593,11 +635,15 @@ def tooltip_query(self, _tw: Gtk.Widget, x: int, y: int, _kb: bool, tooltip: Gtk rssi_state = _("Too much") if path[1] == self.columns["rssi_pb"]: - lines.append(_("Received Signal Strength: %(rssi)u%% (%(rssi_state)s)") % - {"rssi": rssi, "rssi_state": rssi_state}) + lines.append( + _("Received Signal Strength: %(rssi)u%% (%(rssi_state)s)") + % {"rssi": rssi, "rssi_state": rssi_state} + ) else: - lines.append(_("Received Signal Strength: %(rssi)u%% (%(rssi_state)s)") % - {"rssi": rssi, "rssi_state": rssi_state}) + lines.append( + _("Received Signal Strength: %(rssi)u%% (%(rssi_state)s)") + % {"rssi": rssi, "rssi_state": rssi_state} + ) if tpl != 0: if tpl < 30: @@ -612,11 +658,15 @@ def tooltip_query(self, _tw: Gtk.Widget, x: int, y: int, _kb: bool, tooltip: Gtk tpl_state = _("Very High") if path[1] == self.columns["tpl_pb"]: - lines.append(_("Transmit Power Level: %(tpl)u%% (%(tpl_state)s)") % - {"tpl": tpl, "tpl_state": tpl_state}) + lines.append( + _("Transmit Power Level: %(tpl)u%% (%(tpl_state)s)") + % {"tpl": tpl, "tpl_state": tpl_state} + ) else: - lines.append(_("Transmit Power Level: %(tpl)u%% (%(tpl_state)s)") % - {"tpl": tpl, "tpl_state": tpl_state}) + lines.append( + _("Transmit Power Level: %(tpl)u%% (%(tpl_state)s)") + % {"tpl": tpl, "tpl_state": tpl_state} + ) tooltip.set_markup("\n".join(lines)) self.tooltip_row = path[0] @@ -633,8 +683,14 @@ def _has_objpush(self, device: Device) -> bool: return True return False - def _set_cell_data(self, _col: Gtk.TreeViewColumn, cell: Gtk.CellRenderer, model: Gtk.TreeModelFilter, - tree_iter: Gtk.TreeIter, data: Optional[str]) -> None: + def _set_cell_data( + self, + _col: Gtk.TreeViewColumn, + cell: Gtk.CellRenderer, + model: Gtk.TreeModelFilter, + tree_iter: Gtk.TreeIter, + data: Optional[str], + ) -> None: tree_iter = model.convert_iter_to_child_iter(tree_iter) if data is None: row = self.get(tree_iter, "device_surface") diff --git a/blueman/gui/manager/ManagerDeviceMenu.py b/blueman/gui/manager/ManagerDeviceMenu.py index 3bed94c81..bedf0e4a9 100644 --- a/blueman/gui/manager/ManagerDeviceMenu.py +++ b/blueman/gui/manager/ManagerDeviceMenu.py @@ -18,11 +18,14 @@ HANDSFREE_AGW_SVCLASS_ID, HANDSFREE_SVCLASS_ID, HEADSET_SVCLASS_ID, - HID_SVCLASS_ID) + HID_SVCLASS_ID, +) import gi + gi.require_version("Gtk", "3.0") from gi.repository import Gtk + gi.require_version("Gdk", "3.0") from gi.repository import Gdk from gi.repository import GLib @@ -63,15 +66,16 @@ def __init__(self, blueman: "Blueman") -> None: self.is_popup = False - self._device_property_changed_signal = self.Blueman.List.connect("device-property-changed", - self.on_device_property_changed) + self._device_property_changed_signal = self.Blueman.List.connect( + "device-property-changed", self.on_device_property_changed + ) ManagerDeviceMenu.__instances__.append(self) self._any_network = AnyNetwork() - self._any_network.connect_signal('property-changed', self._on_service_property_changed) + self._any_network.connect_signal("property-changed", self._on_service_property_changed) self._any_device = AnyDevice() - self._any_device.connect_signal('property-changed', self._on_service_property_changed) + self._any_device.connect_signal("property-changed", self._on_service_property_changed) try: self._appl: Optional[AppletService] = AppletService() @@ -117,8 +121,9 @@ def unset_op(self, device: Device) -> None: if inst.SelectedDevice == self.SelectedDevice and not (inst.is_popup and not inst.props.visible): inst.generate() - def _on_service_property_changed(self, _service: Union[AnyNetwork, AnyDevice], key: str, _value: object, - _path: str) -> None: + def _on_service_property_changed( + self, _service: Union[AnyNetwork, AnyDevice], key: str, _value: object, _path: str + ) -> None: if key == "Connected": self.generate() @@ -144,12 +149,12 @@ def fail(_obj: Optional[AppletService], result: GLib.Error, _user_data: None) -> prog.connect("cancelled", lambda x: self.disconnect_service(device)) if self._appl is None: - fail(None, GLib.Error('Applet DBus Service not available'), None) + fail(None, GLib.Error("Applet DBus Service not available"), None) return - self._appl.ConnectService('(os)', device.get_object_path(), uuid, - result_handler=success, error_handler=fail, - timeout=GLib.MAXINT) + self._appl.ConnectService( + "(os)", device.get_object_path(), uuid, result_handler=success, error_handler=fail, timeout=GLib.MAXINT + ) prog.start() @@ -165,14 +170,16 @@ def err(_obj: Optional[AppletService], result: GLib.Error, _user_date: None) -> self.generate() if self._appl is None: - err(None, GLib.Error('Applet DBus Service not available'), None) + err(None, GLib.Error("Applet DBus Service not available"), None) return - self._appl.DisconnectService('(osd)', device.get_object_path(), uuid, port, - result_handler=ok, error_handler=err, timeout=GLib.MAXINT) + self._appl.DisconnectService( + "(osd)", device.get_object_path(), uuid, port, result_handler=ok, error_handler=err, timeout=GLib.MAXINT + ) - def on_device_property_changed(self, lst: "ManagerDeviceList", _device: Device, tree_iter: Gtk.TreeIter, - key_value: Tuple[str, object]) -> None: + def on_device_property_changed( + self, lst: "ManagerDeviceList", _device: Device, tree_iter: Gtk.TreeIter, key_value: Tuple[str, object] + ) -> None: key, value = key_value # print "menu:", key, value if lst.compare(tree_iter, lst.selected()): @@ -183,8 +190,10 @@ def _handle_error_message(self, error: GLib.Error) -> None: err = self._BLUEZ_ERROR_MAP.get(error.message.split(":", 3)[-1].strip()) if err == self._BluezError.PROFILE_UNAVAILABLE: - logging.warning("No audio endpoints registered to bluetoothd. " - "Pulseaudio Bluetooth module, bluez-alsa, PipeWire or other audio support missing.") + logging.warning( + "No audio endpoints registered to bluetoothd. " + "Pulseaudio Bluetooth module, bluez-alsa, PipeWire or other audio support missing." + ) msg = _("No audio endpoints registered") elif err == self._BluezError.CREATE_SOCKET: logging.warning("bluetoothd reported input/output error. Check its logs for context.") @@ -192,8 +201,7 @@ def _handle_error_message(self, error: GLib.Error) -> None: elif err == self._BluezError.PAGE_TIMEOUT: msg = _("Device did not respond") elif err == self._BluezError.UNKNOWN: - logging.warning("bluetoothd reported an unknown error. " - "Retry or check its logs for context.") + logging.warning("bluetoothd reported an unknown error. " "Retry or check its logs for context.") msg = _("Unknown error") else: msg = error.message.split(":", 3)[-1].strip() @@ -232,12 +240,17 @@ def show_generic_connect_calc(self, device_uuids: Iterable[str]) -> bool: for uuid in device_uuids: service_uuid = ServiceUUID(uuid) if service_uuid.short_uuid in ( - AUDIO_SOURCE_SVCLASS_ID, AUDIO_SINK_SVCLASS_ID, HANDSFREE_AGW_SVCLASS_ID, HANDSFREE_SVCLASS_ID, - HEADSET_SVCLASS_ID, HID_SVCLASS_ID, 0x1812 + AUDIO_SOURCE_SVCLASS_ID, + AUDIO_SINK_SVCLASS_ID, + HANDSFREE_AGW_SVCLASS_ID, + HANDSFREE_SVCLASS_ID, + HEADSET_SVCLASS_ID, + HID_SVCLASS_ID, + 0x1812, ): return True elif not service_uuid.reserved: - if uuid == '03b80e5a-ede8-4b33-a751-6ce34ec4c700': + if uuid == "03b80e5a-ede8-4b33-a751-6ce34ec4c700": return True # LE devices do not appear to expose certain properties like uuids until connect to at least once. return not device_uuids @@ -249,8 +262,9 @@ def generate(self) -> None: selected = self.Blueman.List.selected() if not selected: return - row = self.Blueman.List.get(selected, "alias", "paired", "connected", "trusted", "objpush", "device", - "blocked") + row = self.Blueman.List.get( + selected, "alias", "paired", "connected", "trusted", "objpush", "device", "blocked" + ) else: (x, y) = self.Blueman.List.get_pointer() posdata = self.Blueman.List.get_path_at_pos(x, y) @@ -266,8 +280,9 @@ def generate(self) -> None: child_iter = self.Blueman.List.filter.convert_iter_to_child_iter(tree_iter) assert child_iter is not None - row = self.Blueman.List.get(child_iter, "alias", "paired", "connected", "trusted", "objpush", "device", - "blocked") + row = self.Blueman.List.get( + child_iter, "alias", "paired", "connected", "trusted", "objpush", "device", "blocked" + ) self.SelectedDevice = row["device"] @@ -280,7 +295,7 @@ def generate(self) -> None: self.append(item) return - show_generic_connect = self.show_generic_connect_calc(self.SelectedDevice['UUIDs']) + show_generic_connect = self.show_generic_connect_calc(self.SelectedDevice["UUIDs"]) if not row["connected"] and show_generic_connect: connect_item = create_menuitem(_("_Connect"), "bluetooth-symbolic") @@ -297,8 +312,11 @@ 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)] + items = [ + item + for plugin in self.Blueman.Plugins.get_loaded_plugins(MenuItemsProvider) + for item in plugin.on_request_menu_items(self, self.SelectedDevice) + ] 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] @@ -390,9 +408,9 @@ def on_rename(_item: Gtk.MenuItem, device: Device) -> None: def on_response(dialog: Gtk.Dialog, response_id: int) -> None: if response_id == Gtk.ResponseType.ACCEPT: assert isinstance(alias_entry, Gtk.Entry) # https://github.com/python/mypy/issues/2608 - device.set('Alias', alias_entry.get_text()) + device.set("Alias", alias_entry.get_text()) elif response_id == 1: - device.set('Alias', '') + device.set("Alias", "") dialog.destroy() builder = Builder("rename-device.ui") @@ -400,12 +418,12 @@ def on_response(dialog: Gtk.Dialog, response_id: int) -> None: dialog.set_transient_for(self.Blueman.window) dialog.props.icon_name = "blueman" alias_entry = builder.get_widget("alias_entry", Gtk.Entry) - alias_entry.set_text(device['Alias']) + alias_entry.set_text(device["Alias"]) dialog.connect("response", on_response) dialog.present() item = Gtk.MenuItem.new_with_mnemonic(_("R_ename device…")) - item.connect('activate', on_rename, self.SelectedDevice) + item.connect("activate", on_rename, self.SelectedDevice) self.append(item) item.show() diff --git a/blueman/gui/manager/ManagerMenu.py b/blueman/gui/manager/ManagerMenu.py index 8364cd7f2..6dd8f5d97 100644 --- a/blueman/gui/manager/ManagerMenu.py +++ b/blueman/gui/manager/ManagerMenu.py @@ -13,6 +13,7 @@ from blueman.Functions import launch, adapter_path_to_name import gi + gi.require_version("Gtk", "3.0") from gi.repository import Gtk from gi.repository import GLib @@ -45,7 +46,7 @@ def __init__(self, blueman: "Blueman"): widget = self.blueman.window.get_toplevel() assert isinstance(widget, Gtk.Window) window = widget - help_item.connect("activate", lambda x: show_about_dialog('Blueman ' + _('Device Manager'), parent=window)) + help_item.connect("activate", lambda x: show_about_dialog("Blueman " + _("Device Manager"), parent=window)) item_toolbar = blueman.builder.get_widget("show_tb_item", Gtk.CheckMenuItem) self.blueman.Config.bind("show-toolbar", item_toolbar, "active", Gio.SettingsBindFlags.DEFAULT) @@ -59,7 +60,7 @@ def __init__(self, blueman: "Blueman"): 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) - sort_config = self.Config['sort-by'] + sort_config = self.Config["sort-by"] if sort_config == "alias": self._sort_alias_item.props.active = True else: @@ -67,16 +68,16 @@ def __init__(self, blueman: "Blueman"): self._sort_type_item = blueman.builder.get_widget("sort_descending_item", Gtk.CheckMenuItem) - if self.Config['sort-order'] == "ascending": + if self.Config["sort-order"] == "ascending": self._sort_type_item.props.active = False else: self._sort_type_item.props.active = True item_plugins = blueman.builder.get_widget("plugins_item", Gtk.ImageMenuItem) - item_plugins.connect('activate', self._on_plugin_dialog_activate) + item_plugins.connect("activate", self._on_plugin_dialog_activate) item_services = blueman.builder.get_widget("services_item", Gtk.ImageMenuItem) - item_services.connect('activate', lambda *args: launch("blueman-services", name=_("Service Preferences"))) + item_services.connect("activate", lambda *args: launch("blueman-services", name=_("Service Preferences"))) self.Search = search_item = blueman.builder.get_widget("search_item", Gtk.ImageMenuItem) search_item.connect("activate", lambda x: self.blueman.inquiry()) @@ -87,10 +88,7 @@ def __init__(self, blueman: "Blueman"): self._power_item = blueman.builder.get_widget("power_item", Gtk.ImageMenuItem) self._power_item.connect( "activate", - lambda x: self.blueman.Applet.SetBluetoothStatus( - '(b)', - not self.blueman.Applet.GetBluetoothStatus() - ) + lambda x: self.blueman.Applet.SetBluetoothStatus("(b)", not self.blueman.Applet.GetBluetoothStatus()), ) exit_item = blueman.builder.get_widget("exit_item", Gtk.ImageMenuItem) @@ -112,7 +110,7 @@ def __init__(self, blueman: "Blueman"): self._sort_timestamp_item.connect("activate", self._on_sorting_changed, "timestamp") self._sort_type_item.connect("activate", self._on_sorting_changed, "sort-type") - self.blueman.Applet.connect('g-signal', self._on_applet_signal) + self.blueman.Applet.connect("g-signal", self._on_applet_signal) self._applet_plugins_changed() def _on_applet_signal(self, _proxy: AppletService, _sender: str, signal_name: str, params: GLib.Variant) -> None: @@ -123,11 +121,11 @@ def _applet_plugins_changed(self) -> None: self._power_item.set_visible("PowerManager" in self.blueman.Applet.QueryPlugins()) def _on_sorting_changed(self, btn: Gtk.CheckMenuItem, sort_opt: str) -> None: - if sort_opt == 'alias' and btn.props.active: - self.Config['sort-by'] = "alias" + if sort_opt == "alias" and btn.props.active: + self.Config["sort-by"] = "alias" elif sort_opt == "timestamp" and btn.props.active: - self.Config['sort-by'] = "timestamp" - elif sort_opt == 'sort-type': + self.Config["sort-by"] = "timestamp" + elif sort_opt == "sort-type": # FIXME bind widget to gsetting if btn.props.active: self.Config["sort-order"] = "descending" @@ -136,7 +134,7 @@ def _on_sorting_changed(self, btn: Gtk.CheckMenuItem, sort_opt: str) -> None: def _on_settings_changed(self, settings: Gio.Settings, key: str) -> None: value = settings[key] - if key == 'sort-by': + if key == "sort-by": if value == "alias": if not self._sort_alias_item.props.active: self._sort_alias_item.props.active = True @@ -162,10 +160,12 @@ def on_device_selected(self, _lst: ManagerDeviceList, device: Device, tree_iter: self.device_menu = ManagerDeviceMenu(self.blueman) self.item_device.set_submenu(self.device_menu) else: + def idle() -> bool: assert self.device_menu is not None # https://github.com/python/mypy/issues/2608 self.device_menu.generate() return False + GLib.idle_add(idle, priority=GLib.PRIORITY_LOW) else: @@ -241,4 +241,5 @@ def _update_power(self) -> None: def _on_plugin_dialog_activate(self, _item: Gtk.MenuItem) -> None: def cb(_proxy: Gio.DBusProxy, _res: Any, _userdata: Any) -> None: pass + self.blueman.Applet.OpenPluginDialog(result_handler=cb) diff --git a/blueman/gui/manager/ManagerProgressbar.py b/blueman/gui/manager/ManagerProgressbar.py index c57e37f2f..cf70752f6 100644 --- a/blueman/gui/manager/ManagerProgressbar.py +++ b/blueman/gui/manager/ManagerProgressbar.py @@ -20,7 +20,7 @@ class ManagerProgressbar(GObject.GObject): __gsignals__: GSignals = { - 'cancelled': (GObject.SignalFlags.RUN_LAST, None, ()), + "cancelled": (GObject.SignalFlags.RUN_LAST, None, ()), } __instances__: List["ManagerProgressbar"] = [] diff --git a/blueman/gui/manager/ManagerStats.py b/blueman/gui/manager/ManagerStats.py index 792d19f58..bceba4291 100644 --- a/blueman/gui/manager/ManagerStats.py +++ b/blueman/gui/manager/ManagerStats.py @@ -22,7 +22,6 @@ class ManagerStats: hbox: Gtk.Box def __init__(self, blueman: "Blueman") -> None: - blueman.List.connect("adapter-changed", self.on_adapter_changed) assert blueman.List.Adapter is not None @@ -58,7 +57,6 @@ def on_adapter_changed(self, _lst: ManagerDeviceList, adapter_path: Optional[str self.down_speed.reset() def set_blinker_by_speed(self, blinker: Animation, speed: float) -> None: - if speed > 0 and not blinker.status(): blinker.start() @@ -107,9 +105,18 @@ def stop_update(self) -> None: if self.timer: GLib.source_remove(self.timer) - def set_data(self, uploaded: float, u_name: str, downloaded: float, d_name: str, u_speed: float, us_name: str, - d_speed: float, ds_name: str) -> None: + def set_data( + self, + uploaded: float, + u_name: str, + downloaded: float, + d_name: str, + u_speed: float, + us_name: str, + d_speed: float, + ds_name: str, + ) -> None: self.down_rate.set_markup( - f'{downloaded:.2f} {d_name} {d_speed:5.2f} {ds_name}/s') - self.up_rate.set_markup( - f'{uploaded:.2f} {u_name} {u_speed:5.2f} {us_name}/s') + f'{downloaded:.2f} {d_name} {d_speed:5.2f} {ds_name}/s' + ) + self.up_rate.set_markup(f'{uploaded:.2f} {u_name} {u_speed:5.2f} {us_name}/s') diff --git a/blueman/gui/manager/ManagerToolbar.py b/blueman/gui/manager/ManagerToolbar.py index 9ecb4b6a7..262e92ac6 100644 --- a/blueman/gui/manager/ManagerToolbar.py +++ b/blueman/gui/manager/ManagerToolbar.py @@ -56,8 +56,9 @@ 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, - key_value: Tuple[str, object]) -> None: + 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: @@ -103,8 +104,9 @@ def on_device_selected(self, dev_list: ManagerDeviceList, device: Device, tree_i else: self.b_send.props.sensitive = False - def on_device_propery_changed(self, dev_list: ManagerDeviceList, device: Device, tree_iter: Gtk.TreeIter, - key_value: Tuple[str, object]) -> None: + def on_device_propery_changed( + self, dev_list: ManagerDeviceList, device: Device, tree_iter: Gtk.TreeIter, key_value: Tuple[str, object] + ) -> None: key, value = key_value if dev_list.compare(tree_iter, dev_list.selected()): if key == "Trusted" or key == "Paired" or key == "UUIDs": diff --git a/blueman/main/Adapter.py b/blueman/main/Adapter.py index eb82064eb..63a1a79d5 100644 --- a/blueman/main/Adapter.py +++ b/blueman/main/Adapter.py @@ -11,6 +11,7 @@ from blueman.main.Builder import Builder import gi + gi.require_version("Gtk", "3.0") gi.require_version("Gdk", "3.0") gi.require_version("Pango", "1.0") @@ -58,11 +59,11 @@ def do_quit(_: object) -> bool: adapters = self.manager.get_adapters() if not adapters: - logging.error('No adapter(s) found') + logging.error("No adapter(s) found") bmexit() - self.manager.connect_signal('adapter-added', self.on_adapter_added) - self.manager.connect_signal('adapter-removed', self.on_adapter_removed) + self.manager.connect_signal("adapter-added", self.on_adapter_added) + self.manager.connect_signal("adapter-removed", self.on_adapter_removed) for adapter in adapters: path = adapter.get_object_path() self.on_adapter_added(self.manager, path) @@ -73,7 +74,7 @@ def do_quit(_: object) -> bool: hci_dev_num = int(selected_hci_dev[3:]) self.notebook.set_current_page(hci_dev_num) else: - logging.error('Error: the selected adapter does not exist') + logging.error("Error: the selected adapter does not exist") self.notebook.show_all() close_action = Gio.SimpleAction.new("quit", None) @@ -89,13 +90,19 @@ def app_release(_plug: Gtk.Plug, _event: Gdk.Event) -> bool: self.hold() plug = Gtk.Plug.new(self.socket_id) plug.show() - plug.connect('delete-event', app_release) + plug.connect("delete-event", app_release) plug.add(self.notebook) return if not self.window: - self.window = Gtk.ApplicationWindow(application=self, title=_("Bluetooth Adapters"), border_width=10, - resizable=False, icon_name="blueman-device", name="BluemanAdapters") + self.window = Gtk.ApplicationWindow( + application=self, + title=_("Bluetooth Adapters"), + border_width=10, + resizable=False, + icon_name="blueman-device", + name="BluemanAdapters", + ) self.window.add(self.notebook) self.window.set_position(Gtk.WindowPosition.CENTER) @@ -136,27 +143,27 @@ def build_adapter_tab(self, adapter: Adapter) -> Tab: def on_hidden_toggle(radio: Gtk.RadioButton) -> None: if not radio.props.active: return - adapter['DiscoverableTimeout'] = 0 - adapter['Discoverable'] = False + adapter["DiscoverableTimeout"] = 0 + adapter["Discoverable"] = False hscale.set_sensitive(False) def on_always_toggle(radio: Gtk.RadioButton) -> None: if not radio.props.active: return - adapter['DiscoverableTimeout'] = 0 - adapter['Discoverable'] = True + adapter["DiscoverableTimeout"] = 0 + adapter["Discoverable"] = True hscale.set_sensitive(False) def on_temporary_toggle(radio: Gtk.RadioButton) -> None: if not radio.props.active: return - adapter['Discoverable'] = True + adapter["Discoverable"] = True hscale.set_sensitive(True) hscale.set_value(3) def on_scale_format_value(_scale: Gtk.Scale, value: float) -> str: if value == 0: - if adapter['Discoverable']: + if adapter["Discoverable"]: return _("Always") else: return _("Hidden") @@ -166,13 +173,13 @@ def on_scale_format_value(_scale: Gtk.Scale, value: float) -> str: def on_scale_value_changed(scale: Gtk.Scale) -> None: val = scale.get_value() logging.info(f"value: {val}") - if val == 0 and adapter['Discoverable']: + if val == 0 and adapter["Discoverable"]: always_radio.props.active = True timeout = int(val * 60) - adapter['DiscoverableTimeout'] = timeout + adapter["DiscoverableTimeout"] = timeout def on_name_changed(entry: Gtk.Entry) -> None: - adapter['Alias'] = entry.get_text() + adapter["Alias"] = entry.get_text() builder = Builder("adapters-tab.ui") @@ -186,11 +193,11 @@ def on_name_changed(entry: Gtk.Entry) -> None: always_radio = builder.get_widget("always", Gtk.RadioButton) temporary_radio = builder.get_widget("temporary", Gtk.RadioButton) - if adapter['Discoverable'] and adapter['DiscoverableTimeout'] > 0: + if adapter["Discoverable"] and adapter["DiscoverableTimeout"] > 0: temporary_radio.set_active(True) - hscale.set_value(adapter['DiscoverableTimeout']) + hscale.set_value(adapter["DiscoverableTimeout"]) hscale.set_sensitive(True) - elif adapter['Discoverable'] and adapter['DiscoverableTimeout'] == 0: + elif adapter["Discoverable"] and adapter["DiscoverableTimeout"] == 0: always_radio.set_active(True) else: hidden_radio.set_active(True) @@ -210,7 +217,7 @@ def on_name_changed(entry: Gtk.Entry) -> None: temparary_radio=temporary_radio, visible=False, label=Gtk.Label(), - name_entry=name_entry + name_entry=name_entry, ) def add_to_notebook(self, adapter: Adapter) -> None: @@ -220,26 +227,26 @@ def add_to_notebook(self, adapter: Adapter) -> None: if hci_dev not in self.tabs: self.tabs[hci_dev] = self.build_adapter_tab(adapter) else: - if self.tabs[hci_dev]['visible']: + if self.tabs[hci_dev]["visible"]: return # might need to update settings at this point ui = self.tabs[hci_dev] - ui['visible'] = True + ui["visible"] = True name = adapter.get_name() - if name == '': - name = _('Adapter') + ' %d' % (hci_dev_num + 1) + if name == "": + name = _("Adapter") + " %d" % (hci_dev_num + 1) label = Gtk.Label(label=name) - ui['label'] = label + ui["label"] = label label.set_max_width_chars(20) label.props.hexpand = True label.set_ellipsize(Pango.EllipsizeMode.END) - self.notebook.insert_page(ui['grid'], label, hci_dev_num) + self.notebook.insert_page(ui["grid"], label, hci_dev_num) def remove_from_notebook(self, adapter: Adapter) -> None: hci_dev = os.path.basename(adapter.get_object_path()) hci_dev_num = int(hci_dev[3:]) - self.tabs[hci_dev]['visible'] = False + self.tabs[hci_dev]["visible"] = False self.notebook.remove_page(hci_dev_num) # leave actual tab contents intact in case adapter becomes present once again diff --git a/blueman/main/Applet.py b/blueman/main/Applet.py index ad69aad26..596edefdd 100644 --- a/blueman/main/Applet.py +++ b/blueman/main/Applet.py @@ -1,4 +1,5 @@ import gi + gi.require_version("Gtk", "3.0") from gi.repository import Gio, GLib, Gtk @@ -40,13 +41,14 @@ def do_quit(_: object) -> bool: self._active = False self.Manager = Manager() - self.Manager.connect_signal('adapter-added', self.on_adapter_added) - self.Manager.connect_signal('adapter-removed', self.on_adapter_removed) - self.Manager.connect_signal('device-created', self.on_device_created) - self.Manager.connect_signal('device-removed', self.on_device_removed) - - self.DbusSvc = DbusService("org.blueman.Applet", "org.blueman.Applet", "/org/blueman/Applet", - Gio.BusType.SESSION) + self.Manager.connect_signal("adapter-added", self.on_adapter_added) + self.Manager.connect_signal("adapter-removed", self.on_adapter_removed) + self.Manager.connect_signal("device-created", self.on_device_created) + self.Manager.connect_signal("device-removed", self.on_device_removed) + + self.DbusSvc = DbusService( + "org.blueman.Applet", "org.blueman.Applet", "/org/blueman/Applet", Gio.BusType.SESSION + ) self.DbusSvc.register() self.Plugins = Plugins(self) @@ -58,10 +60,10 @@ def do_quit(_: object) -> bool: self.Manager.watch_name_owner(self._on_dbus_name_appeared, self._on_dbus_name_vanished) self._any_adapter = AnyAdapter() - self._any_adapter.connect_signal('property-changed', self._on_adapter_property_changed) + self._any_adapter.connect_signal("property-changed", self._on_adapter_property_changed) self._any_device = AnyDevice() - self._any_device.connect_signal('property-changed', self._on_device_property_changed) + self._any_device.connect_signal("property-changed", self._on_device_property_changed) def do_startup(self) -> None: Gtk.Application.do_startup(self) diff --git a/blueman/main/BatteryWatcher.py b/blueman/main/BatteryWatcher.py index b809c89d9..36177be2e 100644 --- a/blueman/main/BatteryWatcher.py +++ b/blueman/main/BatteryWatcher.py @@ -14,8 +14,8 @@ def __init__(self, callback: Callable[[str, int], None]) -> None: manager.disconnect_signal, manager.connect_signal( "battery-created", - lambda _manager, obj_path: callback(obj_path, Battery(obj_path=obj_path)["Percentage"]) - ) + lambda _manager, obj_path: callback(obj_path, Battery(obj_path=obj_path)["Percentage"]), + ), ) any_battery = AnyBattery() @@ -24,6 +24,6 @@ def __init__(self, callback: Callable[[str, int], None]) -> None: any_battery.disconnect_signal, any_battery.connect_signal( "property-changed", - lambda _any_battery, key, value, path: callback(path, value) if key == "Percentage" else None - ) + lambda _any_battery, key, value, path: callback(path, value) if key == "Percentage" else None, + ), ) diff --git a/blueman/main/DBusProxies.py b/blueman/main/DBusProxies.py index 9565c74a1..e9081c516 100644 --- a/blueman/main/DBusProxies.py +++ b/blueman/main/DBusProxies.py @@ -12,19 +12,21 @@ class DBusProxyFailed(Exception): class ProxyBase(Gio.DBusProxy, metaclass=SingletonGObjectMeta): - def __init__(self, name: str, interface_name: str, object_path: str = "/", systembus: bool = False, - flags: Gio.DBusProxyFlags = Gio.DBusProxyFlags.NONE) -> None: + def __init__( + self, + name: str, + interface_name: str, + object_path: str = "/", + systembus: bool = False, + flags: Gio.DBusProxyFlags = Gio.DBusProxyFlags.NONE, + ) -> None: if systembus: bustype = Gio.BusType.SYSTEM else: bustype = Gio.BusType.SESSION super().__init__( - g_name=name, - g_interface_name=interface_name, - g_object_path=object_path, - g_bus_type=bustype, - g_flags=flags + g_name=name, g_interface_name=interface_name, g_object_path=object_path, g_bus_type=bustype, g_flags=flags ) try: @@ -35,25 +37,33 @@ def __init__(self, name: str, interface_name: str, object_path: str = "/", syste class Mechanism(ProxyBase): def __init__(self) -> None: - super().__init__(name='org.blueman.Mechanism', interface_name='org.blueman.Mechanism', - object_path="/org/blueman/mechanism", systembus=True) + super().__init__( + name="org.blueman.Mechanism", + interface_name="org.blueman.Mechanism", + object_path="/org/blueman/mechanism", + systembus=True, + ) class AppletService(ProxyBase): def __init__(self) -> None: - super().__init__(name='org.blueman.Applet', interface_name='org.blueman.Applet', - object_path="/org/blueman/Applet") + super().__init__( + name="org.blueman.Applet", interface_name="org.blueman.Applet", object_path="/org/blueman/Applet" + ) class ManagerService(ProxyBase): def __init__(self) -> None: - super().__init__(name="org.blueman.Manager", interface_name="org.freedesktop.Application", - object_path="/org/blueman/Manager", - flags=Gio.DBusProxyFlags.DO_NOT_AUTO_START_AT_CONSTRUCTION) + super().__init__( + name="org.blueman.Manager", + interface_name="org.freedesktop.Application", + object_path="/org/blueman/Manager", + flags=Gio.DBusProxyFlags.DO_NOT_AUTO_START_AT_CONSTRUCTION, + ) def activate(self) -> None: try: - param = GLib.Variant('(a{sv})', ({},)) + param = GLib.Variant("(a{sv})", ({},)) self.call_sync("Activate", param, Gio.DBusCallFlags.NONE, -1, None) except GLib.Error: # This can different errors, depending on the system configuration, typically: @@ -62,10 +72,12 @@ def activate(self) -> None: logging.error("Call to %s failed", self.get_name(), exc_info=True) Notification( _("Failed to reach blueman-manager"), - _("It seems like blueman-manager could no get activated via D-Bus. " - "A typical cause for this is a broken graphical setup in the D-Bus activation environment " - "that can get resolved with a call to dbus-update-activation-environment, " - "typically issued from xinitrc (respectively the Sway config or similar)."), + _( + "It seems like blueman-manager could no get activated via D-Bus. " + "A typical cause for this is a broken graphical setup in the D-Bus activation environment " + "that can get resolved with a call to dbus-update-activation-environment, " + "typically issued from xinitrc (respectively the Sway config or similar)." + ), 0, ).show() @@ -76,5 +88,5 @@ def call_finish(proxy: "ManagerService", resp: Gio.AsyncResult) -> None: except GLib.Error: logging.error("Call to %s failed", self.get_name(), exc_info=True) - param = GLib.Variant('(sava{sv})', (name, [], {})) - self.call('ActivateAction', param, Gio.DBusCallFlags.NONE, -1, None, call_finish) + param = GLib.Variant("(sava{sv})", (name, [], {})) + self.call("ActivateAction", param, Gio.DBusCallFlags.NONE, -1, None, call_finish) diff --git a/blueman/main/DNSServerProvider.py b/blueman/main/DNSServerProvider.py index f15b82770..b9a0e2c10 100644 --- a/blueman/main/DNSServerProvider.py +++ b/blueman/main/DNSServerProvider.py @@ -43,22 +43,18 @@ def _get_servers_from_systemd_resolved(cls) -> Generator[IPv4Address, None, None GLib.Variant("(ss)", (cls._RESOLVED_MANAGER_INTERFACE, "DNS")), Gio.DBusCallFlags.NONE, -1, - None + None, ).unpack()[0] except GLib.Error: return - for (interface, address_family, address) in data: + for interface, address_family, address in data: if address_family != socket.AF_INET.value: continue if interface != 0: object_path = manager_proxy.call_sync( - "GetLink", - GLib.Variant("(i)", (interface,)), - Gio.DBusCallFlags.NONE, - -1, - None + "GetLink", GLib.Variant("(i)", (interface,)), Gio.DBusCallFlags.NONE, -1, None ).unpack()[0] if not bus.call_sync( @@ -70,11 +66,11 @@ def _get_servers_from_systemd_resolved(cls) -> Generator[IPv4Address, None, None None, Gio.DBusCallFlags.NONE, -1, - None + None, ).unpack()[0]: continue - addr = ip_address('.'.join(str(p) for p in address)) + addr = ip_address(".".join(str(p) for p in address)) assert isinstance(addr, IPv4Address) yield addr @@ -102,8 +98,14 @@ def on_signal( self._bus = Gio.bus_get_sync(Gio.BusType.SYSTEM) self._bus.signal_subscribe( - self._RESOLVED_NAME, "org.freedesktop.DBus.Properties", "PropertiesChanged", - "/org/freedesktop/resolve1", None, Gio.DBusSignalFlags.NONE, on_signal) + self._RESOLVED_NAME, + "org.freedesktop.DBus.Properties", + "PropertiesChanged", + "/org/freedesktop/resolve1", + None, + Gio.DBusSignalFlags.NONE, + on_signal, + ) def _subscribe_resolver(self) -> None: self._monitor = Gio.File.new_for_path(self.RESOLVER_PATH).monitor_file(Gio.FileMonitorFlags.NONE) diff --git a/blueman/main/DbusService.py b/blueman/main/DbusService.py index 1abefd509..b9acef512 100644 --- a/blueman/main/DbusService.py +++ b/blueman/main/DbusService.py @@ -25,8 +25,14 @@ def message(self) -> str: class DbusService: - def __init__(self, bus_name: Optional[str], interface_name: str, path: str, bus_type: Gio.BusType, - properties: Optional[Mapping[str, str]] = None) -> None: + def __init__( + self, + bus_name: Optional[str], + interface_name: str, + path: str, + bus_type: Gio.BusType, + properties: Optional[Mapping[str, str]] = None, + ) -> None: self._bus = Gio.bus_get_sync(bus_type) if bus_name: Gio.bus_own_name(bus_type, bus_name, Gio.BusNameOwnerFlags.NONE, None, None, None) @@ -38,18 +44,38 @@ def __init__(self, bus_name: Optional[str], interface_name: str, path: str, bus_ self._regid: Optional[int] = None @overload - def add_method(self, name: str, arguments: Tuple[str, ...], return_values: Union[str, Tuple[str, ...]], - method: Callable[..., None], pass_sender: bool = False, is_async: bool = False) -> None: + def add_method( + self, + name: str, + arguments: Tuple[str, ...], + return_values: Union[str, Tuple[str, ...]], + method: Callable[..., None], + pass_sender: bool = False, + is_async: bool = False, + ) -> None: ... @overload - def add_method(self, name: str, arguments: Tuple[str, ...], return_values: Tuple[str, ...], - method: Callable[..., Any], pass_sender: bool = False, - is_async: "Literal[False]" = False) -> None: + def add_method( + self, + name: str, + arguments: Tuple[str, ...], + return_values: Tuple[str, ...], + method: Callable[..., Any], + pass_sender: bool = False, + is_async: "Literal[False]" = False, + ) -> None: ... - def add_method(self, name: str, arguments: Tuple[str, ...], return_values: Union[str, Tuple[str, ...]], - method: Callable[..., Any], pass_sender: bool = False, is_async: bool = False) -> None: + def add_method( + self, + name: str, + arguments: Tuple[str, ...], + return_values: Union[str, Tuple[str, ...]], + method: Callable[..., Any], + pass_sender: bool = False, + is_async: bool = False, + ) -> None: if name in self._signals: raise Exception(f"{name} already defined") @@ -76,7 +102,7 @@ def _handle_return_type(self, types: Union[str, Tuple[str, ...]]) -> Tuple[str, if isinstance(types, str): if types: # A non-empty string is a single return type - return types, + return (types,) else: # An empty string is no return type return () @@ -88,8 +114,9 @@ def remove_signal(self, name: str) -> None: self._reregister() def emit_signal(self, name: str, *args: Any) -> None: - self._bus.emit_signal(None, self._path, self._interface_name, name, - self._prepare_arguments(self._signals[name], args)) + self._bus.emit_signal( + None, self._path, self._interface_name, name, self._prepare_arguments(self._signals[name], args) + ) def register(self) -> None: node_xml = f"" @@ -112,11 +139,8 @@ def register(self) -> None: node_info = Gio.DBusNodeInfo.new_for_xml(node_xml) regid = self._bus.register_object( - self._path, - node_info.interfaces[0], - self._handle_method_call, - self._get_property, - None) + self._path, node_info.interfaces[0], self._handle_method_call, self._get_property, None + ) if regid: self._regid = regid @@ -133,19 +157,31 @@ def _reregister(self) -> None: self.unregister() self.register() - def _handle_method_call(self, _connection: Gio.DBusConnection, sender: str, _path: str, interface_name: str, - method_name: str, parameters: GLib.Variant, invocation: Gio.DBusMethodInvocation) -> None: + def _handle_method_call( + self, + _connection: Gio.DBusConnection, + sender: str, + _path: str, + interface_name: str, + method_name: str, + parameters: GLib.Variant, + invocation: Gio.DBusMethodInvocation, + ) -> None: try: try: _arguments, result_signatures, method, options = self._methods[method_name] except KeyError: logging.warning(f"Unhandled method: {method_name}") - invocation.return_error_literal(Gio.dbus_error_quark(), Gio.DBusError.UNKNOWN_METHOD, - f"No such method on interface: {interface_name}.{method_name}") + invocation.return_error_literal( + Gio.dbus_error_quark(), + Gio.DBusError.UNKNOWN_METHOD, + f"No such method on interface: {interface_name}.{method_name}", + ) def ok(*result: Any) -> None: - invocation.return_value(self._prepare_arguments(result_signatures, - result[0] if len(result_signatures) > 1 else result)) + invocation.return_value( + self._prepare_arguments(result_signatures, result[0] if len(result_signatures) > 1 else result) + ) args = parameters.unpack() if "sender" in options: @@ -157,8 +193,9 @@ def ok(*result: Any) -> None: except Exception as e: self._return_dbus_error(invocation, e) - def _get_property(self, _connection: Gio.DBusConnection, _sender: str, path: str, interface_name: str, - property_name: str) -> GLib.Variant: + def _get_property( + self, _connection: Gio.DBusConnection, _sender: str, path: str, interface_name: str, property_name: str + ) -> GLib.Variant: assert interface_name == self._interface_name and path == self._path return GLib.Variant(self._properties[property_name], getattr(self, property_name)) diff --git a/blueman/main/DhcpClient.py b/blueman/main/DhcpClient.py index ccf9bfafb..72af54fbe 100644 --- a/blueman/main/DhcpClient.py +++ b/blueman/main/DhcpClient.py @@ -12,14 +12,14 @@ class DhcpClient(GObject.GObject): __gsignals__: GSignals = { # arg: interface name eg. ppp0 - 'connected': (GObject.SignalFlags.NO_HOOKS, None, (str,)), - 'error-occurred': (GObject.SignalFlags.NO_HOOKS, None, (int,)), + "connected": (GObject.SignalFlags.NO_HOOKS, None, (str,)), + "error-occurred": (GObject.SignalFlags.NO_HOOKS, None, (int,)), } COMMANDS = [ ["dhclient", "-e", "IF_METRIC=100", "-1"], ["dhcpcd", "-m", "100"], - ["udhcpc", "-t", "20", "-x", "hostname", socket.gethostname(), "-n", "-i"] + ["udhcpc", "-t", "20", "-x", "hostname", socket.gethostname(), "-n", "-i"], ] querying: List[str] = [] @@ -61,6 +61,7 @@ def _check_client(self) -> bool: netifs = get_local_interfaces() status = self._client.poll() if status == 0: + def complete() -> bool: ip = netifs[self._interface][0] logging.info(f"bound to {ip}") diff --git a/blueman/main/Manager.py b/blueman/main/Manager.py index c74ccef7c..9e7956fa8 100644 --- a/blueman/main/Manager.py +++ b/blueman/main/Manager.py @@ -22,6 +22,7 @@ from blueman.plugins.ManagerPlugin import ManagerPlugin import gi + gi.require_version("Gtk", "3.0") gi.require_version("Gdk", "3.0") from gi.repository import Gtk, Gio, Gdk, GLib @@ -91,13 +92,14 @@ def bt_status_changed(status: bool) -> None: assert self.window is not None if not status: self.window.hide() - check_bluetooth_status(_("Bluetooth needs to be turned on for the device manager to function"), - self.quit) + check_bluetooth_status( + _("Bluetooth needs to be turned on for the device manager to function"), self.quit + ) else: self.window.show() def on_applet_signal(_proxy: AppletService, _sender: str, signal_name: str, params: GLib.Variant) -> None: - if signal_name == 'BluetoothStatusChanged': + if signal_name == "BluetoothStatusChanged": status = params.unpack() bt_status_changed(status) @@ -112,10 +114,13 @@ def on_dbus_name_vanished(_connection: Gio.DBusConnection, name: str) -> None: d = ErrorDialog( _("Connection to BlueZ failed"), - _("Bluez daemon is not running, blueman-manager cannot continue.\n" - "This probably means that there were no Bluetooth adapters detected " - "or Bluetooth daemon was not started."), - icon_name="blueman") + _( + "Bluez daemon is not running, blueman-manager cannot continue.\n" + "This probably means that there were no Bluetooth adapters detected " + "or Bluetooth daemon was not started." + ), + icon_name="blueman", + ) d.run() d.destroy() @@ -132,21 +137,22 @@ def on_dbus_name_appeared(_connection: Gio.DBusConnection, name: str, owner: str print("Blueman applet needs to be running") bmexit() - check_bluetooth_status(_("Bluetooth needs to be turned on for the device manager to function"), - lambda: self.quit()) + check_bluetooth_status( + _("Bluetooth needs to be turned on for the device manager to function"), lambda: self.quit() + ) manager = Manager() try: - manager.get_adapter(self.Config['last-adapter']) + manager.get_adapter(self.Config["last-adapter"]) except DBusNoSuchAdapterError: - logging.error('Default adapter not found, trying first available.') + logging.error("Default adapter not found, trying first available.") try: manager.get_adapter(None) except DBusNoSuchAdapterError: - logging.error('No adapter(s) found, exiting') + logging.error("No adapter(s) found, exiting") bmexit() - self._applethandlerid = self.Applet.connect('g-signal', on_applet_signal) + self._applethandlerid = self.Applet.connect("g-signal", on_applet_signal) sw = self.builder.get_widget("scrollview", Gtk.ScrolledWindow) # Disable overlay scrolling @@ -245,8 +251,13 @@ def hide() -> bool: info_bar.set_revealed(False) GLib.timeout_add(250, hide) # transition is 250. elif response_id == 0: - dialog = Gtk.MessageDialog(parent=self.window, type=Gtk.MessageType.INFO, modal=True, - buttons=Gtk.ButtonsType.CLOSE, text=self._infobar_bt) + dialog = Gtk.MessageDialog( + parent=self.window, + type=Gtk.MessageType.INFO, + modal=True, + buttons=Gtk.ButtonsType.CLOSE, + text=self._infobar_bt, + ) dialog.connect("response", lambda d, _i: d.destroy()) dialog.connect("close", lambda d: d.destroy()) dialog.show() @@ -256,7 +267,7 @@ def bond(device: Device) -> None: def error_handler(e: Exception) -> None: logging.exception(e) message = f"Pairing failed for:\n{device.display_name} ({device['Address']})" - Notification('Bluetooth', message, icon_name="blueman").show() + Notification("Bluetooth", message, icon_name="blueman").show() device.pair(error_handler=error_handler) @@ -266,11 +277,11 @@ def adapter_properties() -> None: @staticmethod def toggle_trust(device: Device) -> None: - device['Trusted'] = not device['Trusted'] + device["Trusted"] = not device["Trusted"] @staticmethod def toggle_blocked(device: Device) -> None: - device['Blocked'] = not device['Blocked'] + device["Blocked"] = not device["Blocked"] def send(self, device: Device) -> None: adapter = self.List.Adapter diff --git a/blueman/main/MechanismApplication.py b/blueman/main/MechanismApplication.py index 8ccc03b0f..6a10bdb3f 100644 --- a/blueman/main/MechanismApplication.py +++ b/blueman/main/MechanismApplication.py @@ -21,7 +21,7 @@ def __init__(self, loop: GLib.MainLoop): def tick(self) -> bool: if not self.stopped: self.time += 1 - if self.time == (9999 if 'BLUEMAN_SOURCE' in os.environ else 30): + if self.time == (9999 if "BLUEMAN_SOURCE" in os.environ else 30): logging.info("Exiting") self._loop.quit() @@ -52,9 +52,10 @@ def __init__(self, stoptimer: bool): Gio.BusType.SYSTEM, Gio.DBusProxyFlags.NONE, None, - 'org.freedesktop.PolicyKit1', - '/org/freedesktop/PolicyKit1/Authority', - 'org.freedesktop.PolicyKit1.Authority') + "org.freedesktop.PolicyKit1", + "/org/freedesktop/PolicyKit1/Authority", + "org.freedesktop.PolicyKit1.Authority", + ) except Exception as e: logging.exception(e) self.pk = None @@ -92,9 +93,10 @@ def confirm_authorization(self, subject: str, action_id: str) -> None: if not self.pk: raise DbusError("Blueman was built with PolicyKit-1 support, but it's not available on the system") - v_subject = GLib.Variant('s', subject) - res = self.pk.CheckAuthorization('((sa{sv})sa{ss}us)', ("system-bus-name", {"name": v_subject}), - action_id, {}, 1, "") + v_subject = GLib.Variant("s", subject) + res = self.pk.CheckAuthorization( + "((sa{sv})sa{ss}us)", ("system-bus-name", {"name": v_subject}), action_id, {}, 1, "" + ) logging.debug(str(res)) (is_authorized, is_challenge, details) = res diff --git a/blueman/main/NetConf.py b/blueman/main/NetConf.py index f9a2316b9..8efe2d3d9 100644 --- a/blueman/main/NetConf.py +++ b/blueman/main/NetConf.py @@ -63,9 +63,12 @@ def _pid_path(self) -> str: return f"/var/run/{self._key}.pan1.pid" def apply(self, ip4_address: str, ip4_mask: str) -> None: - error = self._start(_get_binary(*self._BINARIES), ip4_address, ip4_mask, - [ip4_address if addr.is_loopback else str(addr) - for addr in DNSServerProvider.get_servers()]) + error = self._start( + _get_binary(*self._BINARIES), + ip4_address, + ip4_mask, + [ip4_address if addr.is_loopback else str(addr) for addr in DNSServerProvider.get_servers()], + ) if error is None: logging.info(f"{self._key} started correctly") with open(self._pid_path) as f: @@ -92,7 +95,7 @@ def clean_up(self) -> None: if pid is not None: running_binary: Optional[str] = next(binary for binary in self._BINARIES if _is_running(binary, pid)) if running_binary is not None: - print('Terminating ' + running_binary) + print("Terminating " + running_binary) os.kill(pid, signal.SIGTERM) else: running_binary = None @@ -110,11 +113,16 @@ class DnsMasqHandler(DHCPHandler): _BINARIES = ["dnsmasq"] def _start(self, binary: str, ip4_address: str, ip4_mask: str, dns_servers: List[str]) -> Optional[bytes]: - ipiface = ipaddress.ip_interface('/'.join((ip4_address, ip4_mask))) - cmd = [binary, f"--pid-file={self._pid_path}", "--except-interface=lo", - "--interface=pan1", "--bind-interfaces", - f"--dhcp-range={ipiface.network[2]},{ipiface.network[-2]},60m", - f"--dhcp-option=option:router,{ip4_address}"] + ipiface = ipaddress.ip_interface("/".join((ip4_address, ip4_mask))) + cmd = [ + binary, + f"--pid-file={self._pid_path}", + "--except-interface=lo", + "--interface=pan1", + "--bind-interfaces", + f"--dhcp-range={ipiface.network[2]},{ipiface.network[-2]},60m", + f"--dhcp-option=option:router,{ip4_address}", + ] with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: if s.connect_ex(("localhost", 53)) == 0: @@ -128,7 +136,7 @@ def _start(self, binary: str, ip4_address: str, ip4_mask: str, dns_servers: List return error if error else None -DHCPDSUBNET = '''#### BLUEMAN AUTOMAGIC SUBNET #### +DHCPDSUBNET = """#### BLUEMAN AUTOMAGIC SUBNET #### # Everything inside this section is destroyed after config change subnet %(ip_mask)s netmask %(netmask)s { option domain-name-servers %(dns)s; @@ -136,7 +144,7 @@ def _start(self, binary: str, ip4_address: str, ip4_mask: str, dns_servers: List option routers %(rtr)s; range %(start)s %(end)s; } -#### END BLUEMAN AUTOMAGIC SUBNET ####''' +#### END BLUEMAN AUTOMAGIC SUBNET ####""" class DhcpdHandler(DHCPHandler): @@ -144,15 +152,15 @@ class DhcpdHandler(DHCPHandler): @staticmethod def _read_dhcp_config() -> Tuple[str, str]: - dhcp_config = '' - existing_subnet = '' + dhcp_config = "" + existing_subnet = "" start = end = False with open(DHCP_CONFIG_FILE) as f: for line in f: - if line == '#### BLUEMAN AUTOMAGIC SUBNET ####\n': + if line == "#### BLUEMAN AUTOMAGIC SUBNET ####\n": start = True - elif line == '#### END BLUEMAN AUTOMAGIC SUBNET ####\n': + elif line == "#### END BLUEMAN AUTOMAGIC SUBNET ####\n": if not start: # Because of bug end string got left upon removal continue @@ -170,14 +178,16 @@ def _read_dhcp_config() -> Tuple[str, str]: @staticmethod def _generate_subnet_config(ip4_address: str, ip4_mask: str, dns_servers: List[str]) -> str: - ipiface = ipaddress.ip_interface('/'.join((ip4_address, ip4_mask))) + ipiface = ipaddress.ip_interface("/".join((ip4_address, ip4_mask))) - return DHCPDSUBNET % {"ip_mask": ipiface.network.network_address, - "netmask": ipiface.netmask, - "dns": ', '.join(dns_servers), - "rtr": ipiface.ip, - "start": ipiface.network[2], - "end": ipiface.network[-2]} + return DHCPDSUBNET % { + "ip_mask": ipiface.network.network_address, + "netmask": ipiface.netmask, + "dns": ", ".join(dns_servers), + "rtr": ipiface.ip, + "start": ipiface.network[2], + "end": ipiface.network[-2], + } def _start(self, binary: str, ip4_address: str, ip4_mask: str, dns_servers: List[str]) -> Optional[bytes]: dhcp_config, existing_subnet = self._read_dhcp_config() @@ -215,14 +225,16 @@ class UdhcpdHandler(DHCPHandler): _BINARIES = ["udhcpd"] def _generate_config(self, ip4_address: str, ip4_mask: str, dns_servers: List[str]) -> str: - ipiface = ipaddress.ip_interface('/'.join((ip4_address, ip4_mask))) + ipiface = ipaddress.ip_interface("/".join((ip4_address, ip4_mask))) - return UDHCP_CONF_TEMPLATE % {"ip_mask": ipiface.network.network_address, - "dns": ', '.join(dns_servers), - "rtr": ipiface.ip, - "start": ipiface.network[2], - "end": ipiface.network[-2], - "pid_path": self._pid_path} + return UDHCP_CONF_TEMPLATE % { + "ip_mask": ipiface.network.network_address, + "dns": ", ".join(dns_servers), + "rtr": ipiface.ip, + "start": ipiface.network[2], + "end": ipiface.network[-2], + "pid_path": self._pid_path, + } def _start(self, binary: str, ip4_address: str, ip4_mask: str, dns_servers: List[str]) -> Optional[bytes]: config_file, self._config_path = mkstemp(prefix="udhcpd-") @@ -278,8 +290,9 @@ def _del_ipt_rules(cls) -> None: cls.unlock("iptables") @classmethod - def apply_settings(cls, ip4_address: str, ip4_mask: str, handler: Type["DHCPHandler"], - address_changed: bool) -> None: + def apply_settings( + cls, ip4_address: str, ip4_mask: str, handler: Type["DHCPHandler"], address_changed: bool + ) -> None: if not isinstance(cls._dhcp_handler, handler): if cls._dhcp_handler is not None: cls._dhcp_handler.clean_up() @@ -302,16 +315,15 @@ def apply_settings(cls, ip4_address: str, ip4_mask: str, handler: Type["DHCPHand ret = call(["ip", "address", "add", "/".join((ip4_address, ip4_mask)), "dev", "pan1"]) if ret != 0: - raise NetworkSetupError(f"Failed to add ip address {ip4_address}" - f"with netmask {ip4_mask}") - elif have('ifconfig'): + raise NetworkSetupError(f"Failed to add ip address {ip4_address}" f"with netmask {ip4_mask}") + elif have("ifconfig"): ret = call(["ifconfig", "pan1", ip4_address, "netmask", ip4_mask, "up"]) if ret != 0: - raise NetworkSetupError(f"Failed to add ip address {ip4_address}" - f"with netmask {ip4_mask}") + raise NetworkSetupError(f"Failed to add ip address {ip4_address}" f"with netmask {ip4_mask}") else: raise NetworkSetupError( - "Neither ifconfig or ip commands are found. Please install net-tools or iproute2") + "Neither ifconfig or ip commands are found. Please install net-tools or iproute2" + ) cls.lock("netconfig") diff --git a/blueman/main/NetworkManager.py b/blueman/main/NetworkManager.py index 55179ab8a..d31c232e7 100644 --- a/blueman/main/NetworkManager.py +++ b/blueman/main/NetworkManager.py @@ -6,9 +6,9 @@ from blueman.Service import Service try: - gi.require_version('NM', '1.0') + gi.require_version("NM", "1.0") except ValueError: - raise ImportError('NM python bindings not found.') + raise ImportError("NM python bindings not found.") from gi.repository import GLib, GObject, NM, Gio @@ -20,14 +20,16 @@ class NMConnectionError(Exception): class NMConnectionBase: conntype: str - def __init__(self, service: Service, reply_handler: Callable[[], None], - error_handler: Callable[[Union[NMConnectionError, GLib.Error]], None]): - if self.conntype not in ('dun', 'panu'): - error_handler( - NMConnectionError(f"Invalid connection type {self.conntype}, should be panu or dun") - ) + def __init__( + self, + service: Service, + reply_handler: Callable[[], None], + error_handler: Callable[[Union[NMConnectionError, GLib.Error]], None], + ): + if self.conntype not in ("dun", "panu"): + error_handler(NMConnectionError(f"Invalid connection type {self.conntype}, should be panu or dun")) self.device = service.device - self.bdaddr = self.device['Address'] + self.bdaddr = self.device["Address"] self.error_handler = error_handler self.reply_handler = reply_handler self.connection = None @@ -58,8 +60,9 @@ def _on_device_state_changed(self, device: NM.Device, new_state: int, old_state: error_msg = f"Connection failed with reason: {state_reason.value_nick}" elif new == NM.DeviceState.ACTIVATED: logging.debug("Connection successfully activated") - elif (new <= NM.DeviceState.DISCONNECTED or new == NM.DeviceState.DEACTIVATING) and \ - (NM.DeviceState.DISCONNECTED < old <= NM.DeviceState.ACTIVATED): + elif (new <= NM.DeviceState.DISCONNECTED or new == NM.DeviceState.DEACTIVATING) and ( + NM.DeviceState.DISCONNECTED < old <= NM.DeviceState.ACTIVATED + ): error_msg = f"Connection disconnected with reason {state_reason.value_nick}" else: return # Keep checking the state changes @@ -86,7 +89,7 @@ def on_connection_activate(client: NM.Client, result: Gio.AsyncResult) -> None: elif device.get_state() == NM.DeviceState.ACTIVATED: self.error_handler(NMConnectionError(f"Device {self.bdaddr} already activated")) else: - self._statehandler = device.connect('state-changed', self._on_device_state_changed) + self._statehandler = device.connect("state-changed", self._on_device_state_changed) self.client.activate_connection_async(self.connection, device, None, None, on_connection_activate) def deactivate(self) -> None: @@ -112,15 +115,15 @@ def find_or_create_connection(self) -> None: logging.debug(f"Found existing connection with uuid {self.connection_uuid}") self.connection = conn - if self.conntype == 'dun': + if self.conntype == "dun": settings_gsm = conn.get_setting_gsm() - if settings_gsm.props.apn != self.Config['apn']: + if settings_gsm.props.apn != self.Config["apn"]: logging.debug(f"Updating apn on connection to {self.Config['apn']}") - settings_gsm.props.apn = self.Config['apn'] - if settings_gsm.props.number != self.Config['number']: + settings_gsm.props.apn = self.Config["apn"] + if settings_gsm.props.number != self.Config["number"]: logging.debug(f"Updating number on connection to {self.Config['number']}") - settings_gsm.props.number = self.Config['number'] + settings_gsm.props.number = self.Config["number"] conn.commit_changes(True, None) @@ -153,10 +156,10 @@ def connection_uuid(self) -> str: class NMPANConnection(NMConnectionBase): - conntype = 'panu' + conntype = "panu" def store_uuid(self, conn_uuid: str) -> None: - self.Config['nmpanuuid'] = conn_uuid + self.Config["nmpanuuid"] = conn_uuid @property def connection_uuid(self) -> str: @@ -169,7 +172,7 @@ def connection_uuid(self) -> str: res = conn_settings.get_uuid() break else: - res = self.Config['nmpanuuid'] + res = self.Config["nmpanuuid"] return res def create_connection(self) -> None: @@ -177,7 +180,7 @@ def create_connection(self) -> None: conn_id = f"{self.device['Name']} Network" conn_uuid = str(uuid.uuid4()) - conn_sett = NM.SettingConnection(type='bluetooth', id=conn_id, uuid=conn_uuid, autoconnect=False) + conn_sett = NM.SettingConnection(type="bluetooth", id=conn_id, uuid=conn_uuid, autoconnect=False) conn_sett_bt = NM.SettingBluetooth(type=self.conntype, bdaddr=self.bdaddr) conn.add_setting(conn_sett) conn.add_setting(conn_sett_bt) @@ -186,28 +189,28 @@ def create_connection(self) -> None: class NMDUNConnection(NMConnectionBase): - conntype = 'dun' + conntype = "dun" def store_uuid(self, conn_uuid: str) -> None: - self.Config['nmdunuuid'] = conn_uuid + self.Config["nmdunuuid"] = conn_uuid @property def connection_uuid(self) -> str: - res: str = self.Config['nmdunuuid'] + res: str = self.Config["nmdunuuid"] return res def create_connection(self) -> None: - if not self.Config['apn']: - self.error_handler(NMConnectionError('No apn configured, make sure to configure dialup settings')) + if not self.Config["apn"]: + self.error_handler(NMConnectionError("No apn configured, make sure to configure dialup settings")) return conn = NM.SimpleConnection() conn_id = f"blueman dun for {self.device.display_name}" conn_uuid = str(uuid.uuid4()) - conn_sett = NM.SettingConnection(type='bluetooth', id=conn_id, uuid=conn_uuid, autoconnect=False) + conn_sett = NM.SettingConnection(type="bluetooth", id=conn_id, uuid=conn_uuid, autoconnect=False) conn_sett_bt = NM.SettingBluetooth(type=self.conntype, bdaddr=self.bdaddr) - conn_sett_gsm = NM.SettingGsm(apn=self.Config['apn'], number=self.Config['number']) + conn_sett_gsm = NM.SettingGsm(apn=self.Config["apn"], number=self.Config["number"]) conn.add_setting(conn_sett) conn.add_setting(conn_sett_bt) conn.add_setting(conn_sett_gsm) diff --git a/blueman/main/PPPConnection.py b/blueman/main/PPPConnection.py index 2c5bb17f8..74a3dbae8 100644 --- a/blueman/main/PPPConnection.py +++ b/blueman/main/PPPConnection.py @@ -16,7 +16,7 @@ pppd_errors = { 1: "An immediately fatal error of some kind occurred, such as an essential system call failing, " - "or running out of virtual memory.", + "or running out of virtual memory.", 2: "An error was detected in processing the options given, such as two mutually exclusive options being used.", 3: "Pppd is not setuid-root and the invoking user is not root.", 4: "The kernel does not support PPP, for example, the PPP kernel driver is not included or cannot be loaded.", @@ -26,7 +26,7 @@ 8: "The connect script failed (returned a non-zero exit status).", 9: "The command specified as the argument to the pty option could not be run.", 10: "The PPP negotiation failed, that is, it didn't reach the point where at least one network protocol " - "(e.g. IP) was running.", + "(e.g. IP) was running.", 11: "The peer system failed (or refused) to authenticate itself.", 12: "The link was established successfully and terminated because it was idle.", 13: "The link was established successfully and terminated because the connect time limit was reached.", @@ -35,7 +35,7 @@ 16: "The link was terminated by the modem hanging up.", 17: "The PPP negotiation failed because serial loopback was detected.", 18: "The init script failed (returned a non-zero exit status).", - 19: "We failed to authenticate ourselves to the peer." + 19: "We failed to authenticate ourselves to the peer.", } @@ -45,8 +45,8 @@ class PPPException(Exception): class PPPConnection(GObject.GObject): __gsignals__: GSignals = { # arg: interface name eg. ppp0 - 'connected': (GObject.SignalFlags.NO_HOOKS, None, (str,)), - 'error-occurred': (GObject.SignalFlags.NO_HOOKS, None, (str,)) + "connected": (GObject.SignalFlags.NO_HOOKS, None, (str,)), + "error-occurred": (GObject.SignalFlags.NO_HOOKS, None, (str,)), } def __init__(self, port: str, number: str = "*99#", apn: str = "", user: str = "", pwd: str = "") -> None: @@ -66,8 +66,8 @@ def __init__(self, port: str, number: str = "*99#", apn: str = "", user: str = " ( f"ATD{self.number}", self.connect_callback, - ["CONNECT", "NO CARRIER", "BUSY", "NO ANSWER", "NO DIALTONE", "OK", "ERROR"] - ) + ["CONNECT", "NO CARRIER", "BUSY", "NO ANSWER", "NO DIALTONE", "OK", "ERROR"], + ), ] if self.apn != "": self.commands.insert(-1, f'AT+CGDCONT=1,"IP","{self.apn}"') @@ -79,8 +79,10 @@ def connect_callback(self, response: List[str]) -> None: if "CONNECT" in response: logging.info("Starting pppd") self.pppd = subprocess.Popen( - ["/usr/sbin/pppd", f"{self.port}", "115200", "defaultroute", "updetach", "usepeerdns"], bufsize=1, - stdout=subprocess.PIPE) + ["/usr/sbin/pppd", f"{self.port}", "115200", "defaultroute", "updetach", "usepeerdns"], + bufsize=1, + stdout=subprocess.PIPE, + ) assert self.pppd.stdout is not None GLib.io_add_watch(self.pppd.stdout, GLib.IO_IN | GLib.IO_ERR | GLib.IO_HUP, self.on_pppd_stdout) GLib.timeout_add(1000, self.check_pppd) @@ -90,8 +92,9 @@ def connect_callback(self, response: List[str]) -> None: self.cleanup() raise PPPException(f"Bad modem response {response[0]}, expected CONNECT") - def __cmd_response_cb(self, response: Optional[List[str]], exception: Optional[PPPException], - command_id: int) -> None: + def __cmd_response_cb( + self, response: Optional[List[str]], exception: Optional[PPPException], command_id: int + ) -> None: if exception: self.emit("error-occurred", str(exception)) else: @@ -116,24 +119,30 @@ def send_commands(self, start: int = 0) -> None: self.wait_for_reply(start) def connect_rfcomm(self) -> None: - self.file = open_rfcomm(self.port, os.O_RDWR) tty.setraw(self.file) attrs: List[Any] = termios.tcgetattr(self.file) - attrs[0] &= ~(termios.IGNCR | termios.ICRNL | termios.IUCLC | termios.INPCK | termios.IXON | termios.IXANY | - termios.IGNPAR) + attrs[0] &= ~( + termios.IGNCR + | termios.ICRNL + | termios.IUCLC + | termios.INPCK + | termios.IXON + | termios.IXANY + | termios.IGNPAR + ) attrs[1] &= ~(termios.OPOST | termios.OLCUC | termios.OCRNL | termios.ONLCR | termios.ONLRET) - attrs[3] &= ~(termios.ICANON | getattr(termios, 'XCASE', 4) | termios.ECHO | termios.ECHOE | termios.ECHONL) + attrs[3] &= ~(termios.ICANON | getattr(termios, "XCASE", 4) | termios.ECHO | termios.ECHOE | termios.ECHONL) attrs[3] &= ~(termios.ECHO | termios.ECHOE) attrs[6][termios.VMIN] = 1 attrs[6][termios.VTIME] = 0 attrs[6][termios.VEOF] = 1 attrs[2] &= ~(termios.CBAUD | termios.CSIZE | termios.CSTOPB | termios.CLOCAL | termios.PARENB) - attrs[2] |= (termios.B9600 | termios.CS8 | termios.CREAD | termios.PARENB) + attrs[2] |= termios.B9600 | termios.CS8 | termios.CREAD | termios.PARENB termios.tcsetattr(self.file, termios.TCSANOW, attrs) @@ -145,8 +154,8 @@ def on_pppd_stdout(self, source: IO[bytes], cond: GLib.IOCondition) -> bool: if cond & GLib.IO_ERR or cond & GLib.IO_HUP: return False - line = source.readline().decode('utf-8') - m = re.match(r'Using interface (ppp[0-9]*)', line) + line = source.readline().decode("utf-8") + m = re.match(r"Using interface (ppp[0-9]*)", line) if m: self.interface = m.groups()[0] @@ -184,7 +193,7 @@ def on_data_ready(self, _source: int, condition: GLib.IOCondition, command_id: i self.cleanup() return False try: - self.buffer += os.read(self.file, 1).decode('utf-8') + self.buffer += os.read(self.file, 1).decode("utf-8") except OSError as e: if e.errno == errno.EAGAIN: logging.error("Got EAGAIN") @@ -218,6 +227,7 @@ def on_timeout() -> bool: self.buffer = "" self.term_found = False - self.io_watch = GLib.io_add_watch(self.file, GLib.IO_IN | GLib.IO_ERR | GLib.IO_HUP, self.on_data_ready, - command_id) + self.io_watch = GLib.io_add_watch( + self.file, GLib.IO_IN | GLib.IO_ERR | GLib.IO_HUP, self.on_data_ready, command_id + ) self.timeout = GLib.timeout_add(15000, on_timeout) diff --git a/blueman/main/PluginManager.py b/blueman/main/PluginManager.py index f44c15211..5a3aac9dd 100644 --- a/blueman/main/PluginManager.py +++ b/blueman/main/PluginManager.py @@ -24,8 +24,8 @@ class LoadException(Exception): class PluginManager(GObject.GObject): __gsignals__: GSignals = { - 'plugin-loaded': (GObject.SignalFlags.NO_HOOKS, None, (GObject.TYPE_STRING,)), - 'plugin-unloaded': (GObject.SignalFlags.NO_HOOKS, None, (GObject.TYPE_STRING,)), + "plugin-loaded": (GObject.SignalFlags.NO_HOOKS, None, (GObject.TYPE_STRING,)), + "plugin-unloaded": (GObject.SignalFlags.NO_HOOKS, None, (GObject.TYPE_STRING,)), } def __init__(self, plugin_class: Type[_T], module_path: ModuleType, parent: object) -> None: @@ -64,11 +64,15 @@ def load_plugin(self, name: Optional[str] = None, user_action: bool = False) -> pass except Exception: if user_action: - d = ErrorDialog(_("An error has occurred while loading " - "a plugin. Please notify the developers " - "with the content of this message to our \n" - "website."), - excp=traceback.format_exc()) + d = ErrorDialog( + _( + "An error has occurred while loading " + "a plugin. Please notify the developers " + "with the content of this message to our \n" + 'website.' + ), + excp=traceback.format_exc(), + ) d.run() d.destroy() raise @@ -119,8 +123,9 @@ def load_plugin(self, name: Optional[str] = None, user_action: bool = False) -> if not self.__classes[dep].__unloadable__: cls.__unloadable__ = False - if (cls.__autoload__ or (cl and cls.__name__ in cl)) and \ - not (cls.__unloadable__ and cl and "!" + cls.__name__ in cl): + if (cls.__autoload__ or (cl and cls.__name__ in cl)) and not ( + cls.__unloadable__ and cl and "!" + cls.__name__ in cl + ): self.__load_plugin(cls) def disable_plugin(self, plugin: str) -> bool: @@ -145,8 +150,11 @@ def __load_plugin(self, cls: Type[_T]) -> None: for cfl in self.__cfls[cls.__name__]: if cfl in self.__classes: - if self.__classes[cfl].__priority__ > cls.__priority__ and not self.disable_plugin(cfl) \ - and not self.enable_plugin(cls.__name__): + if ( + self.__classes[cfl].__priority__ > cls.__priority__ + and not self.disable_plugin(cfl) + and not self.enable_plugin(cls.__name__) + ): logging.warning(f"Not loading {cls.__name__} because its conflict has higher priority") return diff --git a/blueman/main/PulseAudioUtils.py b/blueman/main/PulseAudioUtils.py index aded4bd90..9d48fa8ea 100644 --- a/blueman/main/PulseAudioUtils.py +++ b/blueman/main/PulseAudioUtils.py @@ -36,6 +36,7 @@ class CardInfo(TypedDict): profiles: List[CardProfileInfo] active_profile: str + pa_glib_mainloop_new = libpulse_glib.pa_glib_mainloop_new pa_glib_mainloop_new.argtypes = [c_void_p] pa_glib_mainloop_new.restype = c_void_p @@ -74,17 +75,17 @@ class EventType(IntEnum): # from enum pa_subscription_mask class SubscriptionMask(IntEnum): - NULL = 0x0000, - SINK = 0x0001, - SOURCE = 0x0002, - INPUT = 0x0004, - SOURCE_OUTPUT = 0x0008, - MODULE = 0x0010, - CLIENT = 0x0020, - SAMPLE_CACHE = 0x0040, - SERVER = 0x0080, - CARD = 0x0200, - ALL = 0x02ff + NULL = (0x0000,) + SINK = (0x0001,) + SOURCE = (0x0002,) + INPUT = (0x0004,) + SOURCE_OUTPUT = (0x0008,) + MODULE = (0x0010,) + CLIENT = (0x0020,) + SAMPLE_CACHE = (0x0040,) + SERVER = (0x0080,) + CARD = (0x0200,) + ALL = 0x02FF class NullError(Exception): @@ -97,24 +98,24 @@ class PANotConnected(Exception): class PaCardProfileInfo(Structure): _fields_ = [ - ('name', c_char_p), - ('description', c_char_p), - ('n_sinks', c_uint32), - ('n_sources', c_uint32), - ('priority', c_uint32), + ("name", c_char_p), + ("description", c_char_p), + ("n_sinks", c_uint32), + ("n_sources", c_uint32), + ("priority", c_uint32), ] class PaCardInfo(Structure): _fields_ = [ - ('index', c_uint32), - ('name', c_char_p), - ('owner_module', c_uint32), - ('driver', c_char_p), - ('n_profiles', c_uint32), - ('profiles', POINTER(PaCardProfileInfo)), - ('active_profile', POINTER(PaCardProfileInfo)), - ('proplist', c_void_p), + ("index", c_uint32), + ("name", c_char_p), + ("owner_module", c_uint32), + ("driver", c_char_p), + ("n_profiles", c_uint32), + ("profiles", POINTER(PaCardProfileInfo)), + ("active_profile", POINTER(PaCardProfileInfo)), + ("proplist", c_void_p), ] @@ -189,9 +190,9 @@ class PaCardInfo(Structure): class PulseAudioUtils(GObject.GObject, metaclass=SingletonGObjectMeta): __gsignals__: GSignals = { - 'connected': (GObject.SignalFlags.NO_HOOKS, None, ()), - 'disconnected': (GObject.SignalFlags.NO_HOOKS, None, ()), - 'event': (GObject.SignalFlags.NO_HOOKS, None, (int, int)), + "connected": (GObject.SignalFlags.NO_HOOKS, None, ()), + "disconnected": (GObject.SignalFlags.NO_HOOKS, None, ()), + "event": (GObject.SignalFlags.NO_HOOKS, None, (int, int)), } def check_connected(self) -> None: @@ -210,9 +211,7 @@ def pa_context_event(pa_context: c_void_p, self: "PulseAudioUtils") -> None: self.emit("connected") mask = SubscriptionMask.CARD | SubscriptionMask.MODULE - self.simple_callback(lambda x: logging.info(x), - pa_context_subscribe, - mask) + self.simple_callback(lambda x: logging.info(x), pa_context_subscribe, mask) else: if self.connected: self.emit("disconnected") @@ -237,19 +236,21 @@ def __get_proplist(self, proplist: c_void_p) -> Dict[str, str]: result = {} for item in ls: - spl = [x.strip(" \"") for x in item.split("=")] + spl = [x.strip(' "') for x in item.split("=")] if len(spl) == 2: result[spl[0]] = spl[1] return result if TYPE_CHECKING: + class _ListCallbackInfo(TypedDict): cb_info: "_FuncPointer" handler: Callable[[Optional["_Pointer[PaCardInfo]"], bool], None] - def __list_callback(self, _context: c_void_p, entry_info: "_Pointer[PaCardInfo]", eol: c_int, - info: "_ListCallbackInfo") -> None: + def __list_callback( + self, _context: c_void_p, entry_info: "_Pointer[PaCardInfo]", eol: c_int, info: "_ListCallbackInfo" + ) -> None: if entry_info: info["handler"](entry_info, False) @@ -257,9 +258,15 @@ def __list_callback(self, _context: c_void_p, entry_info: "_Pointer[PaCardInfo]" info["handler"](None, True) pythonapi.Py_DecRef(py_object(info)) - def __init_list_callback(self, func: Callable[..., c_void_p], cb_type: Callable[[Callable[[c_void_p, - "_Pointer[PaCardInfo]", c_int, "_ListCallbackInfo"], None]], "_FuncPointer"], - handler: Callable[[Optional["_Pointer[PaCardInfo]"], bool], None], *args: Any) -> None: + def __init_list_callback( + self, + func: Callable[..., c_void_p], + cb_type: Callable[ + [Callable[[c_void_p, "_Pointer[PaCardInfo]", c_int, "_ListCallbackInfo"], None]], "_FuncPointer" + ], + handler: Callable[[Optional["_Pointer[PaCardInfo]"], bool], None], + *args: Any, + ) -> None: info = {"cb_info": cb_type(self.__list_callback), "handler": handler} pythonapi.Py_IncRef(py_object(info)) @@ -268,7 +275,6 @@ def __init_list_callback(self, func: Callable[..., c_void_p], cb_type: Callable[ pa_operation_unref(op) def simple_callback(self, handler: Callable[[int], None], func: "_NamedFuncPointer", *args: Any) -> None: - def wrapper(_context: c_void_p, res: int, data: "_FuncPointer") -> None: handler(res) pythonapi.Py_DecRef(py_object(data)) @@ -290,14 +296,17 @@ def __card_info(self, card_info: "_Pointer[PaCardInfo]") -> "CardInfo": "owner_module": card_info[0].owner_module, "driver": card_info[0].driver.decode("UTF-8"), "index": card_info[0].index, - "profiles": [{ - "name": card_info[0].profiles[i].name.decode("UTF-8"), - "description": card_info[0].profiles[i].description.decode("UTF-8"), - "n_sinks": card_info[0].profiles[i].n_sinks, - "n_sources": card_info[0].profiles[i].n_sources, - "priority": card_info[0].profiles[i].priority, - } for i in range(0, card_info[0].n_profiles)], - "active_profile": card_info[0].active_profile[0].name.decode("UTF-8") + "profiles": [ + { + "name": card_info[0].profiles[i].name.decode("UTF-8"), + "description": card_info[0].profiles[i].description.decode("UTF-8"), + "n_sinks": card_info[0].profiles[i].n_sinks, + "n_sources": card_info[0].profiles[i].n_sources, + "priority": card_info[0].profiles[i].priority, + } + for i in range(0, card_info[0].n_profiles) + ], + "active_profile": card_info[0].active_profile[0].name.decode("UTF-8"), } def list_cards(self, callback: Callable[[Mapping[str, "CardInfo"]], None]) -> None: @@ -315,8 +324,7 @@ def handler(entry_info: Optional["_Pointer[PaCardInfo]"], end: bool) -> None: data[entry["name"]] = entry - self.__init_list_callback(pa_context_get_card_info_list, - pa_card_info_cb_t, handler) + self.__init_list_callback(pa_context_get_card_info_list, pa_card_info_cb_t, handler) def get_card(self, card: int, callback: Callable[["CardInfo"], None]) -> None: self.check_connected() @@ -371,9 +379,7 @@ def connect_pulseaudio(self) -> bool: pa_context_set_state_callback(self.pa_context, self.ctx_cb, self.weak) pa_context_connect(self.pa_context, None, 0, None) - pa_context_set_subscribe_callback(self.pa_context, - self.event_cb, - None) + pa_context_set_subscribe_callback(self.pa_context, self.event_cb, None) return False def _on_delete(self) -> None: diff --git a/blueman/main/Sendto.py b/blueman/main/Sendto.py index 07c178d44..971c0c056 100644 --- a/blueman/main/Sendto.py +++ b/blueman/main/Sendto.py @@ -18,6 +18,7 @@ from blueman.gui.CommonUi import ErrorDialog import gi + gi.require_version("Gtk", "3.0") gi.require_version("Gdk", "3.0") from gi.repository import Gdk, Gtk, GObject, GLib, Gio @@ -25,7 +26,7 @@ class Sender(Gtk.Dialog): __gsignals__: GSignals = { - 'result': (GObject.SignalFlags.RUN_FIRST, None, (GObject.TYPE_BOOLEAN,)), + "result": (GObject.SignalFlags.RUN_FIRST, None, (GObject.TYPE_BOOLEAN,)), } def __init__(self, device: Device, adapter_path: str, files: Iterable[str]) -> None: @@ -36,7 +37,7 @@ def __init__(self, device: Device, adapter_path: str, files: Iterable[str]) -> N border_width=5, default_width=400, window_position=Gtk.WindowPosition.CENTER, - type_hint=Gdk.WindowTypeHint.DIALOG + type_hint=Gdk.WindowTypeHint.DIALOG, ) self.b_cancel = self.add_button(_("_Stop"), Gtk.ResponseType.CLOSE) @@ -101,15 +102,18 @@ def __init__(self, device: Device, adapter_path: str, files: Iterable[str]) -> N try: self.client = Client() - self.manager.connect_signal('session-added', self.on_session_added) - self.manager.connect_signal('session-removed', self.on_session_removed) + self.manager.connect_signal("session-added", self.on_session_added) + self.manager.connect_signal("session-removed", self.on_session_removed) except GLib.Error as e: - if 'StartServiceByName' in e.message: + if "StartServiceByName" in e.message: logging.debug(e.message) parent = self.get_toplevel() assert isinstance(parent, Gtk.Container) - d = ErrorDialog(_("obexd not available"), _("Failed to autostart obex service. Make sure the obex " - "daemon is running"), parent=parent) + d = ErrorDialog( + _("obexd not available"), + _("Failed to autostart obex service. Make sure the obex " "daemon is running"), + parent=parent, + ) d.run() d.destroy() self.emit("result", False) @@ -121,7 +125,7 @@ def __init__(self, device: Device, adapter_path: str, files: Iterable[str]) -> N assert basename is not None self.l_file.props.label = basename - self.client.connect('session-failed', self.on_session_failed) + self.client.connect("session-failed", self.on_session_failed) logging.info(f"Sending to {device['Address']}") self.l_dest.props.label = device.display_name @@ -136,7 +140,7 @@ def __init__(self, device: Device, adapter_path: str, files: Iterable[str]) -> N self.show() def create_session(self) -> None: - self.client.create_session(self.device['Address'], self.adapter["Address"]) + self.client.create_session(self.device["Address"], self.adapter["Address"]) def on_cancel(self, button: Optional[Gtk.Button]) -> None: self.pb.props.text = _("Cancelling") @@ -175,7 +179,7 @@ def on_transfer_progress(self, _transfer: Transfer, progress: int) -> None: if self._last_bytes == 0: self.total_transferred += progress else: - self.total_transferred += (progress - self._last_bytes) + self.total_transferred += progress - self._last_bytes self._last_bytes = progress @@ -222,8 +226,14 @@ def on_transfer_error(self, _transfer: Optional[Transfer], msg: str = "") -> Non self.speed.reset() parent = self.get_toplevel() assert isinstance(parent, Gtk.Container) - d = ErrorDialog(msg, _("Error occurred while sending file %s") % self.files[-1].get_basename(), - modal=True, icon_name="blueman", parent=parent, buttons=Gtk.ButtonsType.NONE) + d = ErrorDialog( + msg, + _("Error occurred while sending file %s") % self.files[-1].get_basename(), + modal=True, + icon_name="blueman", + parent=parent, + buttons=Gtk.ButtonsType.NONE, + ) if len(self.files) > 1: d.add_button(_("Skip"), Gtk.ResponseType.NO) @@ -240,7 +250,7 @@ def on_response(dialog: Gtk.Dialog, resp: int) -> None: if resp == Gtk.ResponseType.CANCEL: self.on_cancel(None) elif resp == Gtk.ResponseType.NO: - finfo = self.files[-1].query_info('standard::*', Gio.FileQueryInfoFlags.NONE) + finfo = self.files[-1].query_info("standard::*", Gio.FileQueryInfoFlags.NONE) self.total_bytes -= finfo.get_size() self.total_transferred -= self.transferred self.transferred = 0 diff --git a/blueman/main/Services.py b/blueman/main/Services.py index 71b9fd147..76fefdd9e 100644 --- a/blueman/main/Services.py +++ b/blueman/main/Services.py @@ -9,6 +9,7 @@ from blueman.plugins.ServicePlugin import ServicePlugin import gi + gi.require_version("Gtk", "3.0") from gi.repository import Gtk from gi.repository import GLib diff --git a/blueman/main/Tray.py b/blueman/main/Tray.py index 43ba467d7..59134255a 100644 --- a/blueman/main/Tray.py +++ b/blueman/main/Tray.py @@ -28,8 +28,13 @@ def do_activate(self) -> None: logging.info("Already running, restarting instance") return - Gio.bus_watch_name(Gio.BusType.SESSION, 'org.blueman.Applet', Gio.BusNameWatcherFlags.NONE, - self._on_name_appeared, self._on_name_vanished) + Gio.bus_watch_name( + Gio.BusType.SESSION, + "org.blueman.Applet", + Gio.BusNameWatcherFlags.NONE, + self._on_name_appeared, + self._on_name_vanished, + ) self.hold() def _on_name_appeared(self, _connection: Gio.DBusConnection, name: str, _owner: str) -> None: @@ -37,7 +42,7 @@ def _on_name_appeared(self, _connection: Gio.DBusConnection, name: str, _owner: applet = AppletService() for indicator_name in applet.GetStatusIconImplementations(): - indicator_class = getattr(import_module('blueman.main.indicators.' + indicator_name), indicator_name) + indicator_class = getattr(import_module("blueman.main.indicators." + indicator_name), indicator_name) try: self.indicator = indicator_class(self, applet.GetIconName()) break @@ -45,7 +50,7 @@ def _on_name_appeared(self, _connection: Gio.DBusConnection, name: str, _owner: logging.info(f'Indicator "{indicator_name}" is not available') logging.info(f'Using indicator "{self.indicator.__class__.__name__}"') - applet.connect('g-signal', self.on_signal) + applet.connect("g-signal", self.on_signal) self.indicator.set_tooltip_title(applet.GetToolTipTitle()) self.indicator.set_tooltip_text(applet.GetToolTipText()) @@ -59,19 +64,19 @@ def _on_name_vanished(self, _connection: Gio.DBusConnection, _name: str) -> None self.quit() def activate_menu_item(self, *indexes: int) -> None: - AppletService().ActivateMenuItem('(ai)', indexes) + AppletService().ActivateMenuItem("(ai)", indexes) def activate_status_icon(self) -> None: AppletService().Activate() def on_signal(self, _applet: AppletService, _sender_name: str, signal_name: str, args: GLib.Variant) -> None: - if signal_name == 'IconNameChanged': + if signal_name == "IconNameChanged": self.indicator.set_icon(*args) - elif signal_name == 'ToolTipTitleChanged': + elif signal_name == "ToolTipTitleChanged": self.indicator.set_tooltip_title(*args) - elif signal_name == 'ToolTipTextChanged': + elif signal_name == "ToolTipTextChanged": self.indicator.set_tooltip_text(*args) - elif signal_name == 'VisibilityChanged': + elif signal_name == "VisibilityChanged": self.indicator.set_visibility(*args) - elif signal_name == 'MenuChanged': + elif signal_name == "MenuChanged": self.indicator.set_menu(*args) diff --git a/blueman/main/applet/BluezAgent.py b/blueman/main/applet/BluezAgent.py index c328b1983..07619e95c 100644 --- a/blueman/main/applet/BluezAgent.py +++ b/blueman/main/applet/BluezAgent.py @@ -31,7 +31,7 @@ class BluezErrorRejected(DbusError): class BluezAgent(DbusService): - __agent_path = '/org/bluez/agent/blueman' + __agent_path = "/org/bluez/agent/blueman" def __init__(self) -> None: super().__init__(None, "org.bluez.Agent1", self.__agent_path, Gio.BusType.SYSTEM) @@ -62,8 +62,9 @@ def unregister_agent(self) -> None: self.unregister() AgentManager().unregister_agent(self.__agent_path) - def build_passkey_dialog(self, device_alias: str, dialog_msg: str, is_numeric: bool - ) -> Tuple[Gtk.Dialog, Gtk.Entry]: + def build_passkey_dialog( + self, device_alias: str, dialog_msg: str, is_numeric: bool + ) -> Tuple[Gtk.Dialog, Gtk.Entry]: def on_insert_text(editable: Gtk.Entry, new_text: str, _new_text_length: int, _position: int) -> None: if not new_text.isdigit(): editable.stop_emission("insert-text") @@ -90,7 +91,7 @@ def on_insert_text(editable: Gtk.Entry, new_text: str, _new_text_length: int, _p pin_entry.set_visibility(False) show_input.connect("toggled", lambda x: pin_entry.set_visibility(x.props.active)) accept_button = builder.get_widget("accept", Gtk.Button) - pin_entry.connect("changed", lambda x: accept_button.set_sensitive(x.get_text() != '')) + pin_entry.connect("changed", lambda x: accept_button.set_sensitive(x.get_text() != "")) return dialog, pin_entry @@ -99,17 +100,35 @@ def get_device_string(self, object_path: str) -> str: return f"{escape(device.display_name)} ({device['Address']})" @overload - def ask_passkey(self, dialog_msg: str, is_numeric: "Literal[True]", object_path: str, ok: Callable[[int], None], - err: Callable[[Union[BluezErrorCanceled, BluezErrorRejected]], None]) -> None: + def ask_passkey( + self, + dialog_msg: str, + is_numeric: "Literal[True]", + object_path: str, + ok: Callable[[int], None], + err: Callable[[Union[BluezErrorCanceled, BluezErrorRejected]], None], + ) -> None: ... @overload - def ask_passkey(self, dialog_msg: str, is_numeric: "Literal[False]", object_path: str, ok: Callable[[str], None], - err: Callable[[Union[BluezErrorCanceled, BluezErrorRejected]], None]) -> None: + def ask_passkey( + self, + dialog_msg: str, + is_numeric: "Literal[False]", + object_path: str, + ok: Callable[[str], None], + err: Callable[[Union[BluezErrorCanceled, BluezErrorRejected]], None], + ) -> None: ... - def ask_passkey(self, dialog_msg: str, is_numeric: bool, object_path: str, ok: Callable[[Any], None], - err: Callable[[Union[BluezErrorCanceled, BluezErrorRejected]], None]) -> None: + def ask_passkey( + self, + dialog_msg: str, + is_numeric: bool, + object_path: str, + ok: Callable[[Any], None], + err: Callable[[Union[BluezErrorCanceled, BluezErrorRejected]], None], + ) -> None: def passkey_dialog_cb(dialog: Gtk.Dialog, response_id: int) -> None: if response_id == Gtk.ResponseType.ACCEPT: ret = pin_entry.get_text() @@ -159,8 +178,12 @@ def _close(self) -> None: self._notification.close() self._notification = None - def _on_request_pin_code(self, object_path: str, ok: Callable[[str], None], - err: Callable[[Union[BluezErrorCanceled, BluezErrorRejected]], None]) -> None: + def _on_request_pin_code( + self, + object_path: str, + ok: Callable[[str], None], + err: Callable[[Union[BluezErrorCanceled, BluezErrorRejected]], None], + ) -> None: logging.info("Agent.RequestPinCode") dialog_msg = _("Enter PIN code for authentication:") @@ -168,8 +191,12 @@ def _on_request_pin_code(self, object_path: str, ok: Callable[[str], None], if self.dialog: self.dialog.present() - def _on_request_passkey(self, object_path: str, ok: Callable[[int], None], - err: Callable[[Union[BluezErrorCanceled, BluezErrorRejected]], None]) -> None: + def _on_request_passkey( + self, + object_path: str, + ok: Callable[[int], None], + err: Callable[[Union[BluezErrorCanceled, BluezErrorRejected]], None], + ) -> None: logging.info("Agent.RequestPasskey") dialog_msg = _("Enter passkey for authentication:") self.ask_passkey(dialog_msg, True, object_path, ok, err) @@ -182,14 +209,16 @@ def _on_display_passkey(self, object_path: str, passkey: int, entered: int) -> N self._devhandlerids[object_path] = dev.connect_signal("property-changed", self._on_device_property_changed) key = f"{passkey:06}" - notify_message = _("Pairing passkey for") + f" {self.get_device_string(object_path)}: " \ - f"{key[:entered]}{key[entered]}{key[entered + 1:]}" + notify_message = ( + _("Pairing passkey for") + f" {self.get_device_string(object_path)}: " + f"{key[:entered]}{key[entered]}{key[entered + 1:]}" + ) self._close() self._notification = Notification("Bluetooth", notify_message, 0, icon_name="blueman") self._notification.show() def _on_display_pin_code(self, object_path: str, pin_code: str) -> None: - logging.info(f'DisplayPinCode ({object_path}, {pin_code})') + logging.info(f"DisplayPinCode ({object_path}, {pin_code})") dev = Device(obj_path=object_path) self._devhandlerids[object_path] = dev.connect_signal("property-changed", self._on_device_property_changed) @@ -197,8 +226,13 @@ def _on_display_pin_code(self, object_path: str, pin_code: str) -> None: self._notification = Notification("Bluetooth", notify_message, 0, icon_name="blueman") self._notification.show() - def _on_request_confirmation(self, object_path: str, passkey: Optional[int], ok: Callable[[], None], - err: Callable[[BluezErrorCanceled], None]) -> None: + def _on_request_confirmation( + self, + object_path: str, + passkey: Optional[int], + ok: Callable[[], None], + err: Callable[[BluezErrorCanceled], None], + ) -> None: def on_confirm_action(action: str) -> None: if action == "confirm": ok() @@ -212,16 +246,19 @@ def on_confirm_action(action: str) -> None: notify_message += "\n" + _("Confirm value for authentication:") + f" {passkey:06}" actions = [("confirm", _("Confirm")), ("deny", _("Deny"))] - self._notification = Notification("Bluetooth", notify_message, 0, actions, on_confirm_action, - icon_name="blueman") + self._notification = Notification( + "Bluetooth", notify_message, 0, actions, on_confirm_action, icon_name="blueman" + ) self._notification.show() - def _on_request_authorization(self, object_path: str, ok: Callable[[], None], - err: Callable[[BluezErrorCanceled], None]) -> None: + def _on_request_authorization( + self, object_path: str, ok: Callable[[], None], err: Callable[[BluezErrorCanceled], None] + ) -> None: self._on_request_confirmation(object_path, None, ok, err) - def _on_authorize_service(self, object_path: str, uuid: str, ok: Callable[[], None], - err: Callable[[BluezErrorRejected], None]) -> None: + def _on_authorize_service( + self, object_path: str, uuid: str, ok: Callable[[], None], err: Callable[[BluezErrorRejected], None] + ) -> None: def on_auth_action(action: str) -> None: logging.info(action) @@ -237,11 +274,8 @@ def on_auth_action(action: str) -> None: logging.info("Agent.Authorize") dev_str = self.get_device_string(object_path) service = ServiceUUID(uuid).name - notify_message = \ - _("Authorization request for:") + f"\n{dev_str}\n" + _("Service:") + f" {service}" - actions = [("always", _("Always accept")), - ("accept", _("Accept")), - ("deny", _("Deny"))] + notify_message = _("Authorization request for:") + f"\n{dev_str}\n" + _("Service:") + f" {service}" + actions = [("always", _("Always accept")), ("accept", _("Accept")), ("deny", _("Deny"))] n = Notification(_("Bluetooth Authentication"), notify_message, 0, actions, on_auth_action, icon_name="blueman") n.show() diff --git a/blueman/main/indicators/GtkStatusIcon.py b/blueman/main/indicators/GtkStatusIcon.py index 459847b06..1c6ff9fd0 100644 --- a/blueman/main/indicators/GtkStatusIcon.py +++ b/blueman/main/indicators/GtkStatusIcon.py @@ -32,22 +32,25 @@ def build_menu(items: Iterable[Tuple[int, "SubmenuItemDict"]], activate: Callabl def build_menu(items: Iterable[Tuple[int, "SubmenuItemDict"]], activate: Callable[..., None]) -> Gtk.Menu: menu = Gtk.Menu() for index, item in items: - if 'text' in item and 'icon_name' in item: - gtk_item: Gtk.MenuItem = create_menuitem(item['text'], item['icon_name']) + if "text" in item and "icon_name" in item: + gtk_item: Gtk.MenuItem = create_menuitem(item["text"], item["icon_name"]) label = gtk_item.get_child() assert isinstance(label, Gtk.Label) - if item['markup']: - label.set_markup_with_mnemonic(item['text']) + if item["markup"]: + label.set_markup_with_mnemonic(item["text"]) else: - label.set_text_with_mnemonic(item['text']) - gtk_item.connect('activate', cast(Callable[[Gtk.MenuItem], None], lambda _, idx=index: activate(idx))) - if 'submenu' in item: + label.set_text_with_mnemonic(item["text"]) + gtk_item.connect("activate", cast(Callable[[Gtk.MenuItem], None], lambda _, idx=index: activate(idx))) + if "submenu" in item: gtk_item.set_submenu( - build_menu(enumerate(item['submenu']), # type: ignore - cast(Callable[[int], None], lambda subid, idx=index: activate(idx, subid)))) - if 'tooltip' in item: - gtk_item.props.tooltip_text = item['tooltip'] - gtk_item.props.sensitive = item['sensitive'] + build_menu( + enumerate(item["submenu"]), # type: ignore + cast(Callable[[int], None], lambda subid, idx=index: activate(idx, subid)), + ) + ) + if "tooltip" in item: + gtk_item.props.tooltip_text = item["tooltip"] + gtk_item.props.sensitive = item["sensitive"] else: gtk_item = Gtk.SeparatorMenuItem() gtk_item.show() @@ -59,9 +62,9 @@ class GtkStatusIcon(IndicatorInterface): 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: tray.activate_status_icon()) + self.indicator.set_title("blueman") + self.indicator.connect("popup-menu", self.on_popup_menu) + self.indicator.connect("activate", lambda _status_icon: tray.activate_status_icon()) self._tooltip_title = "" self._tooltip_text = "" self._menu: Optional[Gtk.Menu] = None diff --git a/blueman/main/indicators/StatusNotifierItem.py b/blueman/main/indicators/StatusNotifierItem.py index 3ab75ad59..68a6155ce 100644 --- a/blueman/main/indicators/StatusNotifierItem.py +++ b/blueman/main/indicators/StatusNotifierItem.py @@ -24,9 +24,12 @@ def __init__(self, on_activate_menu_item: "MenuItemActivator") -> None: self.add_method("Event", ("i", "s", "v", "u"), (), self._on_event) self.add_method("AboutToShow", ("i",), ("b",), lambda _: self._revision > self._revision_advertised) - self.add_method("GetGroupProperties", ("ai", "as"), ("a(ia{sv})",), - lambda ids, props: [(idx, self._render_item(item)) for idx, item in self._iterate_items() - if idx in ids]) + self.add_method( + "GetGroupProperties", + ("ai", "as"), + ("a(ia{sv})",), + lambda ids, props: [(idx, self._render_item(item)) for idx, item in self._iterate_items() if idx in ids], + ) self.add_signal("LayoutUpdated", ("u", "i")) @@ -42,11 +45,15 @@ def _advertise_revision(self) -> bool: self._revision_advertised = self._revision return True - 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]]]: + 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(((item["id"] << 8, item) for item in self._items.values()), - 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 >> 8] if "submenu" in item and _recursion_depth != 0: @@ -61,10 +68,13 @@ def _render_submenu(self, item: "MenuItemDict", idx: int) -> List[GLib.Variant]: _T = TypeVar("_T", bound="SubmenuItemDict") - def _render_menu(self, items: Iterable[Tuple[int, _T]], submenu_callback: Callable[[_T, int], List[GLib.Variant]] - ) -> List[GLib.Variant]: - return [GLib.Variant("(ia{sv}av)", (idx, self._render_item(item), submenu_callback(item, idx))) - for (idx, item) in items] + def _render_menu( + self, items: Iterable[Tuple[int, _T]], submenu_callback: Callable[[_T, int], List[GLib.Variant]] + ) -> List[GLib.Variant]: + return [ + GLib.Variant("(ia{sv}av)", (idx, self._render_item(item), submenu_callback(item, idx))) + for (idx, item) in items + ] def _iterate_items(self) -> Iterable[Tuple[int, "SubmenuItemDict"]]: for item in self._items.values(): @@ -101,9 +111,22 @@ class StatusNotifierItemService(DbusService): ItemIsMenu = False 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"}) + 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: tray.activate_status_icon()) self.menu = MenuService(tray.activate_menu_item) @@ -145,14 +168,21 @@ def on_watcher_appeared(*args: Any) -> None: else: tray.activate() - Gio.bus_watch_name(Gio.BusType.SESSION, self._SNI_BUS_NAME, Gio.BusNameWatcherFlags.NONE, - on_watcher_appeared, None) + Gio.bus_watch_name( + Gio.BusType.SESSION, self._SNI_BUS_NAME, Gio.BusNameWatcherFlags.NONE, on_watcher_appeared, None + ) try: 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) + 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 diff --git a/blueman/plugins/AppletPlugin.py b/blueman/plugins/AppletPlugin.py index d51a52efe..575a16181 100644 --- a/blueman/plugins/AppletPlugin.py +++ b/blueman/plugins/AppletPlugin.py @@ -3,6 +3,7 @@ from blueman.plugins.BasePlugin import BasePlugin import gi + gi.require_version("Gtk", "3.0") from gi.repository import Gtk @@ -24,8 +25,14 @@ def __init__(self, parent: "BluemanApplet"): self._dbus_methods: Set[str] = set() self._dbus_signals: Set[str] = set() - def _add_dbus_method(self, name: str, arguments: Tuple[str, ...], return_value: str, method: Callable[..., Any], - is_async: bool = False) -> None: + def _add_dbus_method( + self, + name: str, + arguments: Tuple[str, ...], + return_value: str, + method: Callable[..., Any], + is_async: bool = False, + ) -> None: self._dbus_methods.add(name) self._dbus_service.add_method(name, arguments, return_value, method, is_async=is_async) diff --git a/blueman/plugins/BasePlugin.py b/blueman/plugins/BasePlugin.py index 5206b058c..d3afffd53 100644 --- a/blueman/plugins/BasePlugin.py +++ b/blueman/plugins/BasePlugin.py @@ -22,6 +22,7 @@ class Option(OptionBase, total=False): class GSettings(TypedDict): schema: str path: None + else: Option = dict @@ -46,8 +47,7 @@ class BasePlugin: def __init__(self, *_args: object) -> None: if self.__options__: self.__config = Gio.Settings( - schema_id=self.__class__.__gsettings__["schema"], - path=self.__class__.__gsettings__["path"] + schema_id=self.__class__.__gsettings__["schema"], path=self.__class__.__gsettings__["path"] ) weakref.finalize(self, self._on_plugin_delete) diff --git a/blueman/plugins/ServicePlugin.py b/blueman/plugins/ServicePlugin.py index 605211638..89ba2e033 100644 --- a/blueman/plugins/ServicePlugin.py +++ b/blueman/plugins/ServicePlugin.py @@ -2,6 +2,7 @@ import gi + gi.require_version("Gtk", "3.0") from gi.repository import Gtk @@ -26,7 +27,6 @@ def __init__(self, parent: "BluemanServices"): # call when option has changed. def option_changed_notify(self, option_id: str, state: bool = True) -> None: - if option_id not in self._options: self._options.append(option_id) else: diff --git a/blueman/plugins/applet/AutoConnect.py b/blueman/plugins/applet/AutoConnect.py index efb4d16d6..c3d6ed1af 100644 --- a/blueman/plugins/applet/AutoConnect.py +++ b/blueman/plugins/applet/AutoConnect.py @@ -19,13 +19,8 @@ class AutoConnect(AppletPlugin): __author__ = "cschramm" __description__ = _("Tries to auto-connect to configurable services on start and every 60 seconds.") - __gsettings__ = { - "schema": "org.blueman.plugins.autoconnect", - "path": None - } - __options__ = { - "services": {"type": list, "default": "[]"} - } + __gsettings__ = {"schema": "org.blueman.plugins.autoconnect", "path": None} + __options__ = {"services": {"type": list, "default": "[]"}} def __init__(self, parent: "BluemanApplet"): super().__init__(parent) @@ -40,16 +35,19 @@ def on_adapter_property_changed(self, path: str, key: str, value: Any) -> None: self._run() def _run(self) -> bool: - for address, uuid in self.get_option('services'): + for address, uuid in self.get_option("services"): device = self.parent.Manager.find_device(address) if device is None or device.get("Connected"): continue def reply(dev: Optional[Device] = device, service_name: str = ServiceUUID(uuid).name) -> None: assert isinstance(dev, Device) # https://github.com/python/mypy/issues/2608 - Notification(_("Connected"), _("Automatically connected to %(service)s on %(device)s") % - {"service": service_name, "device": dev.display_name}, - icon_name=dev["Icon"]).show() + Notification( + _("Connected"), + _("Automatically connected to %(service)s on %(device)s") + % {"service": service_name, "device": dev.display_name}, + icon_name=dev["Icon"], + ).show() def err(_reason: Union[Exception, str]) -> None: pass diff --git a/blueman/plugins/applet/ConnectionNotifier.py b/blueman/plugins/applet/ConnectionNotifier.py index 7e2b57639..24f0b6ba9 100644 --- a/blueman/plugins/applet/ConnectionNotifier.py +++ b/blueman/plugins/applet/ConnectionNotifier.py @@ -25,13 +25,11 @@ def on_device_property_changed(self, path: str, key: str, value: Any) -> None: device = Device(obj_path=path) if value: self._notifications[path] = notification = Notification( - device.display_name, - _('Connected'), - icon_name=device["Icon"] + device.display_name, _("Connected"), icon_name=device["Icon"] ) notification.show() else: - Notification(device.display_name, _('Disconnected'), icon_name=device["Icon"]).show() + Notification(device.display_name, _("Disconnected"), icon_name=device["Icon"]).show() def _on_battery_update(self, path: str, value: int) -> None: notification = self._notifications[path] diff --git a/blueman/plugins/applet/DBusService.py b/blueman/plugins/applet/DBusService.py index 516db2dd9..201ecf516 100644 --- a/blueman/plugins/applet/DBusService.py +++ b/blueman/plugins/applet/DBusService.py @@ -6,6 +6,7 @@ from blueman.Service import Service from blueman.bluez.errors import BluezDBusException + if TYPE_CHECKING: from blueman.main.NetworkManager import NMConnectionError from blueman.plugins.AppletPlugin import AppletPlugin @@ -26,18 +27,24 @@ def on_rfcomm_disconnect(self, port: int) -> None: class RFCOMMConnectHandler: - def rfcomm_connect_handler(self, _service: SerialService, _reply: Callable[[str], None], - _err: Callable[[Union[RFCOMMError, GLib.Error]], None]) -> bool: + def rfcomm_connect_handler( + self, + _service: SerialService, + _reply: Callable[[str], None], + _err: Callable[[Union[RFCOMMError, GLib.Error]], None], + ) -> bool: return False class ServiceConnectHandler: - def service_connect_handler(self, _service: Service, _ok: Callable[[], None], - _err: Callable[[Union["NMConnectionError", GLib.Error]], None]) -> bool: + def service_connect_handler( + self, _service: Service, _ok: Callable[[], None], _err: Callable[[Union["NMConnectionError", GLib.Error]], None] + ) -> bool: return False - def service_disconnect_handler(self, _service: Service, _ok: Callable[[], None], - _err: Callable[[Union["NMConnectionError", GLib.Error]], None]) -> bool: + def service_disconnect_handler( + self, _service: Service, _ok: Callable[[], None], _err: Callable[[Union["NMConnectionError", GLib.Error]], None] + ) -> bool: return False @@ -61,9 +68,13 @@ def on_load(self) -> None: def _plugins_changed(self) -> None: self._emit_dbus_signal("PluginsChanged") - def connect_service(self, object_path: str, uuid: str, ok: Callable[[], None], - err: Callable[[Union[BluezDBusException, "NMConnectionError", - RFCOMMError, GLib.Error, str]], None]) -> None: + def connect_service( + self, + object_path: str, + uuid: str, + ok: Callable[[], None], + err: Callable[[Union[BluezDBusException, "NMConnectionError", RFCOMMError, GLib.Error, str]], None], + ) -> None: try: self.parent.Plugins.RecentConns except KeyError: @@ -71,25 +82,30 @@ def connect_service(self, object_path: str, uuid: str, ok: Callable[[], None], else: self.parent.Plugins.RecentConns.notify(object_path, uuid) - if uuid == '00000000-0000-0000-0000-000000000000': + if uuid == "00000000-0000-0000-0000-000000000000": device = Device(obj_path=object_path) device.connect(reply_handler=ok, error_handler=err) else: service = get_service(Device(obj_path=object_path), uuid) assert service is not None - if any(plugin.service_connect_handler(service, ok, err) - for plugin in self.parent.Plugins.get_loaded_plugins(ServiceConnectHandler)): + if any( + plugin.service_connect_handler(service, ok, err) + for plugin in self.parent.Plugins.get_loaded_plugins(ServiceConnectHandler) + ): pass elif isinstance(service, SerialService): + def reply(rfcomm: str) -> None: assert isinstance(service, SerialService) # https://github.com/python/mypy/issues/2608 for plugin in self.parent.Plugins.get_loaded_plugins(RFCOMMConnectedListener): plugin.on_rfcomm_connected(service, rfcomm) ok() - if not any(plugin.rfcomm_connect_handler(service, reply, err) - for plugin in self.parent.Plugins.get_loaded_plugins(RFCOMMConnectHandler)): + if not any( + plugin.rfcomm_connect_handler(service, reply, err) + for plugin in self.parent.Plugins.get_loaded_plugins(RFCOMMConnectHandler) + ): service.connect(reply_handler=lambda port: ok(), error_handler=err) elif isinstance(service, NetworkService): service.connect(reply_handler=lambda interface: ok(), error_handler=err) @@ -97,18 +113,25 @@ def reply(rfcomm: str) -> None: logging.info("No handler registered") err("Service not supported\nPossibly the plugin that handles this service is not loaded") - def _disconnect_service(self, object_path: str, uuid: str, port: int, ok: Callable[[], None], - err: Callable[[Union[BluezDBusException, "NMConnectionError", - GLib.Error, str]], None]) -> None: - if uuid == '00000000-0000-0000-0000-000000000000': + def _disconnect_service( + self, + object_path: str, + uuid: str, + port: int, + ok: Callable[[], None], + err: Callable[[Union[BluezDBusException, "NMConnectionError", GLib.Error, str]], None], + ) -> None: + if uuid == "00000000-0000-0000-0000-000000000000": device = Device(obj_path=object_path) device.disconnect(reply_handler=ok, error_handler=err) else: service = get_service(Device(obj_path=object_path), uuid) assert service is not None - if any(plugin.service_disconnect_handler(service, ok, err) - for plugin in self.parent.Plugins.get_loaded_plugins(ServiceConnectHandler)): + if any( + plugin.service_disconnect_handler(service, ok, err) + for plugin in self.parent.Plugins.get_loaded_plugins(ServiceConnectHandler) + ): pass elif isinstance(service, SerialService): service.disconnect(port, reply_handler=ok, error_handler=err) diff --git a/blueman/plugins/applet/DhcpClient.py b/blueman/plugins/applet/DhcpClient.py index 09dca9c41..721d0cce9 100644 --- a/blueman/plugins/applet/DhcpClient.py +++ b/blueman/plugins/applet/DhcpClient.py @@ -19,7 +19,7 @@ class DhcpClient(AppletPlugin): def on_load(self) -> None: self._any_network = AnyNetwork() - self._any_network.connect_signal('property-changed', self._on_network_prop_changed) + self._any_network.connect_signal("property-changed", self._on_network_prop_changed) self.querying: List[str] = [] @@ -42,23 +42,32 @@ def dhcp_acquire(self, object_path: str) -> None: return if device != "": + def reply(_obj: Mechanism, result: str, _user_data: None) -> None: logging.info(result) - Notification(_("Bluetooth Network"), - _("Interface %(0)s bound to IP address %(1)s") % {"0": device, "1": result}, - icon_name="network-workgroup").show() + Notification( + _("Bluetooth Network"), + _("Interface %(0)s bound to IP address %(1)s") % {"0": device, "1": result}, + icon_name="network-workgroup", + ).show() self.querying.remove(device) def err(_obj: Mechanism, result: GLib.Error, _user_data: None) -> None: logging.warning(result) - Notification(_("Bluetooth Network"), _("Failed to obtain an IP address on %s") % device, - icon_name="network-workgroup").show() + Notification( + _("Bluetooth Network"), + _("Failed to obtain an IP address on %s") % device, + icon_name="network-workgroup", + ).show() self.querying.remove(device) - Notification(_("Bluetooth Network"), _("Trying to obtain an IP address on %s\nPlease wait…" % device), - icon_name="network-workgroup").show() + Notification( + _("Bluetooth Network"), + _("Trying to obtain an IP address on %s\nPlease wait…" % device), + icon_name="network-workgroup", + ).show() m = Mechanism() - m.DhcpClient('(s)', object_path, result_handler=reply, error_handler=err, timeout=120 * 1000) + m.DhcpClient("(s)", object_path, result_handler=reply, error_handler=err, timeout=120 * 1000) diff --git a/blueman/plugins/applet/DisconnectItems.py b/blueman/plugins/applet/DisconnectItems.py index 2f14b7416..f9f22e24e 100644 --- a/blueman/plugins/applet/DisconnectItems.py +++ b/blueman/plugins/applet/DisconnectItems.py @@ -37,6 +37,10 @@ def on_device_property_changed(self, path: str, key: str, value: Any) -> None: def _render(self) -> None: for idx, device in enumerate(self.parent.Manager.get_devices()): if device["Connected"]: - self._menu.add(self, (25, idx), text=_("Disconnect %s") % device.display_name, - icon_name="bluetooth-disconnected-symbolic", - callback=cast(Callable[[], None], lambda dev=device: dev.disconnect())) + self._menu.add( + self, + (25, idx), + text=_("Disconnect %s") % device.display_name, + icon_name="bluetooth-disconnected-symbolic", + callback=cast(Callable[[], None], lambda dev=device: dev.disconnect()), + ) diff --git a/blueman/plugins/applet/DiscvManager.py b/blueman/plugins/applet/DiscvManager.py index 6b3a5aeab..c7ba10818 100644 --- a/blueman/plugins/applet/DiscvManager.py +++ b/blueman/plugins/applet/DiscvManager.py @@ -13,28 +13,32 @@ class DiscvManager(AppletPlugin): __author__ = "Walmis" __icon__ = "edit-find-symbolic" __description__ = _( - "Provides a menu item for making the default adapter temporarily visible when it is set to hidden by default") + "Provides a menu item for making the default adapter temporarily visible when it is set to hidden by default" + ) - __gsettings__ = { - "schema": "org.blueman.plugins.discvmanager", - "path": None - } + __gsettings__ = {"schema": "org.blueman.plugins.discvmanager", "path": None} __options__ = { "time": { "type": int, "default": 60, "name": _("Discoverable timeout"), "desc": _("Amount of time in seconds discoverable mode will last"), - "range": (60, 600) + "range": (60, 600), } } adapter: Optional[Adapter] def on_load(self) -> None: - self.item = self.parent.Plugins.Menu.add(self, 20, text=_("_Make Discoverable"), icon_name="edit-find-symbolic", - tooltip=_("Make the default adapter temporarily visible"), - callback=self.on_set_discoverable, visible=False) + self.item = self.parent.Plugins.Menu.add( + self, + 20, + text=_("_Make Discoverable"), + icon_name="edit-find-symbolic", + tooltip=_("Make the default adapter temporarily visible"), + callback=self.on_set_discoverable, + visible=False, + ) self.adapter = None self.time_left = -1 diff --git a/blueman/plugins/applet/ExitItem.py b/blueman/plugins/applet/ExitItem.py index ed5bcdd3a..304e5c2d7 100644 --- a/blueman/plugins/applet/ExitItem.py +++ b/blueman/plugins/applet/ExitItem.py @@ -9,8 +9,9 @@ class ExitItem(AppletPlugin): __icon__ = "application-exit-symbolic" def on_load(self) -> None: - self.parent.Plugins.Menu.add(self, 100, text=_("_Exit"), icon_name='application-exit-symbolic', - callback=self.parent.quit) + self.parent.Plugins.Menu.add( + self, 100, text=_("_Exit"), icon_name="application-exit-symbolic", callback=self.parent.quit + ) def on_unload(self) -> None: self.parent.Plugins.Menu.unregister(self) diff --git a/blueman/plugins/applet/GameControllerWakelock.py b/blueman/plugins/applet/GameControllerWakelock.py index 216a67bb7..d62dff772 100644 --- a/blueman/plugins/applet/GameControllerWakelock.py +++ b/blueman/plugins/applet/GameControllerWakelock.py @@ -8,9 +8,10 @@ from blueman.plugins.errors import UnsupportedPlatformError import gi -gi.require_version('Gdk', '3.0') + +gi.require_version("Gdk", "3.0") try: - gi.require_version('GdkX11', '3.0') + gi.require_version("GdkX11", "3.0") except ValueError: raise ImportError("Couldn't find required namespace GdkX11") @@ -19,7 +20,7 @@ if not isinstance(Gdk.Screen.get_default(), GdkX11.X11Screen): - raise UnsupportedPlatformError('Only X11 platform is supported') + raise UnsupportedPlatformError("Only X11 platform is supported") class GameControllerWakelock(AppletPlugin): @@ -42,7 +43,7 @@ def on_unload(self) -> None: def on_device_property_changed(self, path: str, key: str, value: Any) -> None: if key == "Connected": - klass = Device(obj_path=path)["Class"] & 0x1fff + klass = Device(obj_path=path)["Class"] & 0x1FFF if klass == 0x504 or klass == 0x508: if value: diff --git a/blueman/plugins/applet/KillSwitch.py b/blueman/plugins/applet/KillSwitch.py index 721ded6d4..9d326bb82 100644 --- a/blueman/plugins/applet/KillSwitch.py +++ b/blueman/plugins/applet/KillSwitch.py @@ -20,8 +20,8 @@ RFKILL_EVENT_SIZE_V1 = 8 -if not os.path.exists('/dev/rfkill'): - raise ImportError('Hardware kill switch not found') +if not os.path.exists("/dev/rfkill"): + raise ImportError("Hardware kill switch not found") class Switch: @@ -34,19 +34,16 @@ def __init__(self, idx: int, switch_type: int, soft: int, hard: int): class KillSwitch(AppletPlugin, PowerStateHandler, StatusIconVisibilityHandler): __author__ = "Walmis" - __description__ = _("Switches Bluetooth killswitch status to match Bluetooth power state. " - "Allows turning Bluetooth back on from an icon that shows its status; " - "provided it isn't unplugged by the system, or physically.") + __description__ = _( + "Switches Bluetooth killswitch status to match Bluetooth power state. " + "Allows turning Bluetooth back on from an icon that shows its status; " + "provided it isn't unplugged by the system, or physically." + ) __depends__ = ["PowerManager"] __icon__ = "system-shutdown-symbolic" - __gsettings__ = { - "schema": "org.blueman.plugins.killswitch", - "path": None - } - __options__ = { - "checked": {"type": bool, "default": False} - } + __gsettings__ = {"schema": "org.blueman.plugins.killswitch", "path": None} + __options__ = {"checked": {"type": bool, "default": False}} _switches: Dict[int, Switch] = {} _iom = None @@ -55,12 +52,17 @@ class KillSwitch(AppletPlugin, PowerStateHandler, StatusIconVisibilityHandler): def on_load(self) -> None: self._connman_proxy: Optional[Gio.DBusProxy] = None - self._connman_watch_id = Gio.bus_watch_name(Gio.BusType.SYSTEM, "net.connman", Gio.BusNameWatcherFlags.NONE, - self._on_connman_appeared, self._on_connman_vanished) + self._connman_watch_id = Gio.bus_watch_name( + Gio.BusType.SYSTEM, + "net.connman", + Gio.BusNameWatcherFlags.NONE, + self._on_connman_appeared, + self._on_connman_vanished, + ) channel = GLib.IOChannel.new_file("/dev/rfkill", "r") if channel is None: - raise ImportError('Could not access RF kill switch') + raise ImportError("Could not access RF kill switch") self._iom = GLib.io_add_watch(channel, GLib.IO_IN | GLib.IO_ERR | GLib.IO_HUP, self.io_event) @@ -76,10 +78,11 @@ def _on_connman_appeared(self, connection: Gio.DBusConnection, name: str, owner: Gio.BusType.SYSTEM, Gio.DBusProxyFlags.DO_NOT_AUTO_START, None, - 'net.connman', - '/net/connman/technology/bluetooth', - 'net.connman.Technology', - None) + "net.connman", + "/net/connman/technology/bluetooth", + "net.connman.Technology", + None, + ) def _on_connman_vanished(self, connection: Gio.DBusConnection, name: str) -> None: logging.info(f"{name} vanished") @@ -117,7 +120,7 @@ def io_event(self, channel: GLib.IOChannel, condition: GLib.IOCondition) -> bool self._hardblocked = False for s in self._switches.values(): self._hardblocked |= s.hard == 1 - self._enabled &= (s.soft == 0 and s.hard == 0) + self._enabled &= s.soft == 0 and s.hard == 0 logging.info(f"State: {self._enabled}") @@ -146,11 +149,12 @@ def error(*_: Any) -> None: if self._connman_proxy: logging.debug(f"Using connman to set state: {state}") - self._connman_proxy.SetProperty('(sv)', 'Powered', GLib.Variant.new_boolean(state), - result_handler=reply, error_handler=error) + self._connman_proxy.SetProperty( + "(sv)", "Powered", GLib.Variant.new_boolean(state), result_handler=reply, error_handler=error + ) else: logging.debug(f"Using mechanism to set state: {state}") - Mechanism().SetRfkillState('(b)', state, result_handler=reply, error_handler=error) + Mechanism().SetRfkillState("(b)", state, result_handler=reply, error_handler=error) def on_query_force_status_icon_visibility(self) -> bool: # Force status icon to show if Bluetooth is soft-blocked diff --git a/blueman/plugins/applet/Menu.py b/blueman/plugins/applet/Menu.py index caca1198a..0f0868cb5 100644 --- a/blueman/plugins/applet/Menu.py +++ b/blueman/plugins/applet/Menu.py @@ -1,6 +1,5 @@ from gettext import gettext as _ -from typing import List, Union, Iterable, Dict, Optional, Callable, \ - TYPE_CHECKING, Tuple, Iterator, Mapping, Sequence +from typing import List, Union, Iterable, Dict, Optional, Callable, TYPE_CHECKING, Tuple, Iterator, Mapping, Sequence from gi.repository import GLib @@ -25,9 +24,20 @@ class MenuItemDict(MenuItemDictBase, total=False): class MenuItem: - 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): + 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 self._priority = priority @@ -40,8 +50,12 @@ def __init__(self, menu_plugin: "Menu", owner: AppletPlugin, priority: Tuple[int self._visible = visible self._sensitive = sensitive - assert text and icon_name and (callback or submenu_function) or \ - not any([text, icon_name, tooltip, callback, submenu_function]) + assert ( + text + and icon_name + and (callback or submenu_function) + or not any([text, icon_name, tooltip, callback, submenu_function]) + ) @property def owner(self) -> AppletPlugin: @@ -60,8 +74,8 @@ def visible(self) -> bool: return self._visible def _iter_base(self) -> Iterator[Tuple[str, Union[str, bool]]]: - for key in ['text', 'markup', 'icon_name', 'tooltip', 'sensitive']: - value = getattr(self, '_' + key) + for key in ["text", "markup", "icon_name", "tooltip", "sensitive"]: + value = getattr(self, "_" + key) if value is not None: yield key, value @@ -70,7 +84,7 @@ def __iter__(self) -> Iterator[Tuple[str, Union[int, str, bool, List[Dict[str, U yield from self._iter_base() submenu = self.submenu_items if submenu: - yield 'submenu', [dict(item) for item in submenu] + yield "submenu", [dict(item) for item in submenu] @property def submenu_items(self) -> List["SubmenuItem"]: @@ -79,10 +93,22 @@ def submenu_items(self) -> List["SubmenuItem"]: submenu_items = self._submenu_function() if not submenu_items: return [] - 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] + 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 + ] def set_text(self, text: str, markup: bool = False) -> None: self._text = text @@ -124,17 +150,25 @@ def on_load(self) -> None: 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: 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: - + 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) + item = MenuItem( + self, owner, priority, text, markup, icon_name, tooltip, callback, submenu_function, visible, sensitive + ) self.__menuitems[item.priority] = item self.on_menu_changed() return item @@ -149,13 +183,13 @@ def on_menu_changed(self) -> None: self._emit_dbus_signal("MenuChanged", self._get_menu()) def _get_menu(self) -> List[Dict[str, GLib.Variant]]: - return self._prepare_menu(dict(self.__menuitems[key]) - for key in sorted(self.__menuitems.keys()) - if self.__menuitems[key].visible) + return self._prepare_menu( + dict(self.__menuitems[key]) for key in sorted(self.__menuitems.keys()) if self.__menuitems[key].visible + ) - def _prepare_menu(self, data: Iterable[Mapping[str, Union[int, str, bool, - Iterable[Mapping[str, Union[str, bool]]]]]]) \ - -> List[Dict[str, GLib.Variant]]: + def _prepare_menu( + self, data: Iterable[Mapping[str, Union[int, str, bool, Iterable[Mapping[str, Union[str, bool]]]]]] + ) -> List[Dict[str, GLib.Variant]]: return [{k: self._build_variant(v) for k, v in item.items()} for item in data] def _build_variant(self, value: Union[int, str, bool, Iterable[Mapping[str, Union[str, bool]]]]) -> GLib.Variant: diff --git a/blueman/plugins/applet/NMDUNSupport.py b/blueman/plugins/applet/NMDUNSupport.py index fa00a1336..b79551331 100644 --- a/blueman/plugins/applet/NMDUNSupport.py +++ b/blueman/plugins/applet/NMDUNSupport.py @@ -18,8 +18,9 @@ class NMDUNSupport(AppletPlugin, ServiceConnectHandler): __description__ = _("Provides support for Dial Up Networking (DUN) with ModemManager and NetworkManager") __priority__ = 1 - def service_connect_handler(self, service: Service, ok: Callable[[], None], - err: Callable[[Union[NMConnectionError, GLib.Error]], None]) -> bool: + def service_connect_handler( + self, service: Service, ok: Callable[[], None], err: Callable[[Union[NMConnectionError, GLib.Error]], None] + ) -> bool: if DIALUP_NET_SVCLASS_ID != service.short_uuid: return False @@ -28,8 +29,9 @@ def service_connect_handler(self, service: Service, ok: Callable[[], None], return True - def service_disconnect_handler(self, service: Service, ok: Callable[[], None], - err: Callable[[Union[NMConnectionError, GLib.Error]], None]) -> bool: + def service_disconnect_handler( + self, service: Service, ok: Callable[[], None], err: Callable[[Union[NMConnectionError, GLib.Error]], None] + ) -> bool: if DIALUP_NET_SVCLASS_ID != service.short_uuid: return False diff --git a/blueman/plugins/applet/NMPANSupport.py b/blueman/plugins/applet/NMPANSupport.py index 69bd0a9f4..c5b01266b 100644 --- a/blueman/plugins/applet/NMPANSupport.py +++ b/blueman/plugins/applet/NMPANSupport.py @@ -18,8 +18,9 @@ class NMPANSupport(AppletPlugin, ServiceConnectHandler): __description__ = _("Provides support for Personal Area Networking (PAN) introduced in NetworkManager 0.8") __priority__ = 2 - def service_connect_handler(self, service: Service, ok: Callable[[], None], - err: Callable[[Union[NMConnectionError, GLib.Error]], None]) -> bool: + def service_connect_handler( + self, service: Service, ok: Callable[[], None], err: Callable[[Union[NMConnectionError, GLib.Error]], None] + ) -> bool: if not isinstance(service, NetworkService): return False @@ -28,8 +29,9 @@ def service_connect_handler(self, service: Service, ok: Callable[[], None], return True - def service_disconnect_handler(self, service: Service, ok: Callable[[], None], - err: Callable[[Union[NMConnectionError, GLib.Error]], None]) -> bool: + def service_disconnect_handler( + self, service: Service, ok: Callable[[], None], err: Callable[[Union[NMConnectionError, GLib.Error]], None] + ) -> bool: if not isinstance(service, NetworkService): return False diff --git a/blueman/plugins/applet/NetUsage.py b/blueman/plugins/applet/NetUsage.py index 30476009f..7fa374b3c 100644 --- a/blueman/plugins/applet/NetUsage.py +++ b/blueman/plugins/applet/NetUsage.py @@ -26,8 +26,8 @@ class MonitorBase(GObject.GObject): __gsignals__: GSignals = { - 'disconnected': (GObject.SignalFlags.NO_HOOKS, None, ()), - 'stats': (GObject.SignalFlags.NO_HOOKS, None, (int, int)), + "disconnected": (GObject.SignalFlags.NO_HOOKS, None, ()), + "stats": (GObject.SignalFlags.NO_HOOKS, None, (int, int)), } def __init__(self, device: Device, interface: str): @@ -36,8 +36,9 @@ def __init__(self, device: Device, interface: str): self.interface = interface self.device = device self.general_config = Gio.Settings(schema_id="org.blueman.general") - self.config = Gio.Settings(schema_id="org.blueman.plugins.netusage", - path=f"/org/blueman/plugins/netusages/{device['Address']}/") + self.config = Gio.Settings( + schema_id="org.blueman.plugins.netusage", path=f"/org/blueman/plugins/netusages/{device['Address']}/" + ) self.last_tx = 0 self.last_rx = 0 @@ -139,10 +140,10 @@ def __init__(self, plugin: "NetUsage"): self.cb_device.connect("changed", self.on_selection_changed) self.cb_device.pack_start(cr1, True) - self.cb_device.add_attribute(cr1, 'markup', 1) + self.cb_device.add_attribute(cr1, "markup", 1) self.cb_device.pack_start(cr2, False) - self.cb_device.add_attribute(cr2, 'markup', 2) + self.cb_device.add_attribute(cr2, "markup", 2) general_config = Gio.Settings(schema_id="org.blueman.general") @@ -151,8 +152,13 @@ def __init__(self, plugin: "NetUsage"): for m in plugin.monitors: if d == m.device["Address"]: titer = self.liststore.append( - [d, self.get_caption(m.device.display_name, m.device["Address"]), - _("Connected:") + " " + m.interface, m]) + [ + d, + self.get_caption(m.device.display_name, m.device["Address"]), + _("Connected:") + " " + m.interface, + m, + ] + ) if self.cb_device.get_active() == -1: self.cb_device.set_active_iter(titer) added = True @@ -172,10 +178,13 @@ def __init__(self, plugin: "NetUsage"): if self.cb_device.get_active() == -1: self.cb_device.set_active(0) else: - msg = _("No usage statistics are available yet. Try establishing a connection first and " - "then check this page.") - d = Gtk.MessageDialog(parent=self.dialog, modal=True, type=Gtk.MessageType.INFO, - buttons=Gtk.ButtonsType.CLOSE, text=msg) + msg = _( + "No usage statistics are available yet. Try establishing a connection first and " + "then check this page." + ) + d = Gtk.MessageDialog( + parent=self.dialog, modal=True, type=Gtk.MessageType.INFO, buttons=Gtk.ButtonsType.CLOSE, text=msg + ) d.props.icon_name = "blueman" d.run() d.destroy() @@ -205,7 +214,13 @@ def update_time(self) -> None: m = ngettext("minute", "minutes", delta.seconds % 3600 // 60) self.l_duration.props.label = _("%d %s %d %s and %d %s") % ( - delta.days, d, delta.seconds // 3600, h, delta.seconds % 3600 // 60, m) + delta.days, + d, + delta.seconds // 3600, + h, + delta.seconds % 3600 // 60, + m, + ) else: self.l_started.props.label = _("Unknown") self.l_duration.props.label = _("Unknown") @@ -214,8 +229,9 @@ def on_selection_changed(self, cb: Gtk.ComboBox) -> None: titer = cb.get_active_iter() assert titer is not None (addr,) = self.liststore.get(titer, 0) - self.config = Gio.Settings(schema_id="org.blueman.plugins.netusage", - path=f"/org/blueman/plugins/netusages/{addr}/") + self.config = Gio.Settings( + schema_id="org.blueman.plugins.netusage", path=f"/org/blueman/plugins/netusages/{addr}/" + ) self.update_counts(self.config["tx"], self.config["rx"]) self.update_time() @@ -238,9 +254,13 @@ def update_counts(self, tx: int, rx: int) -> None: self.update_time() def on_reset(self, _button: Gtk.Button) -> None: - d = Gtk.MessageDialog(parent=self.dialog, modal=True, type=Gtk.MessageType.QUESTION, - buttons=Gtk.ButtonsType.YES_NO, - text=_("Are you sure you want to reset the counter?")) + d = Gtk.MessageDialog( + parent=self.dialog, + modal=True, + type=Gtk.MessageType.QUESTION, + buttons=Gtk.ButtonsType.YES_NO, + text=_("Are you sure you want to reset the counter?"), + ) res = d.run() d.destroy() if res == Gtk.ResponseType.YES: @@ -268,8 +288,12 @@ def monitor_added(self, _parent: "NetUsage", monitor: Monitor) -> None: return self.liststore.append( - [monitor.device["Address"], self.get_caption(monitor.device.display_name, monitor.device["Address"]), - _("Connected:") + " " + monitor.interface, monitor] + [ + monitor.device["Address"], + self.get_caption(monitor.device.display_name, monitor.device["Address"]), + _("Connected:") + " " + monitor.interface, + monitor, + ] ) def monitor_removed(self, _parent: "NetUsage", monitor: Monitor) -> None: @@ -286,15 +310,17 @@ def monitor_removed(self, _parent: "NetUsage", monitor: Monitor) -> None: class NetUsage(AppletPlugin, GObject.GObject, PPPConnectedListener): __depends__ = ["Menu"] __icon__ = "network-wireless-symbolic" - __description__ = _("Allows you to monitor your (mobile broadband) network traffic usage. Useful for limited " - "data access plans. This plugin tracks every device separately.") + __description__ = _( + "Allows you to monitor your (mobile broadband) network traffic usage. Useful for limited " + "data access plans. This plugin tracks every device separately." + ) __author__ = "Walmis" __autoload__ = False __gsignals__: GSignals = { - 'monitor-added': (GObject.SignalFlags.NO_HOOKS, None, (Monitor,)), - 'monitor-removed': (GObject.SignalFlags.NO_HOOKS, None, (Monitor,)), + "monitor-added": (GObject.SignalFlags.NO_HOOKS, None, (Monitor,)), + "monitor-removed": (GObject.SignalFlags.NO_HOOKS, None, (Monitor,)), # monitor, tx, rx - 'stats': (GObject.SignalFlags.NO_HOOKS, None, (Monitor, int, int)), + "stats": (GObject.SignalFlags.NO_HOOKS, None, (Monitor, int, int)), } _any_network = None @@ -304,10 +330,16 @@ def on_load(self) -> None: self.monitors: List[Monitor] = [] self._any_network = AnyNetwork() - self._any_network.connect_signal('property-changed', self._on_network_property_changed) - - self.parent.Plugins.Menu.add(self, 84, text=_("Network _Usage"), icon_name="network-wireless-symbolic", - tooltip=_("Shows network traffic usage"), callback=self.activate_ui) + self._any_network.connect_signal("property-changed", self._on_network_property_changed) + + self.parent.Plugins.Menu.add( + self, + 84, + text=_("Network _Usage"), + icon_name="network-wireless-symbolic", + tooltip=_("Shows network traffic usage"), + callback=self.activate_ui, + ) def _on_network_property_changed(self, _network: AnyNetwork, key: str, value: Any, path: str) -> None: if key == "Interface" and value != "": diff --git a/blueman/plugins/applet/Networking.py b/blueman/plugins/applet/Networking.py index 65b084e32..48f1902bc 100644 --- a/blueman/plugins/applet/Networking.py +++ b/blueman/plugins/applet/Networking.py @@ -43,17 +43,26 @@ def reply(_obj: Mechanism, _result: None, _user_data: None) -> None: pass def err(_obj: Mechanism, result: GLib.Error, _user_data: None) -> None: - d = ErrorDialog("Failed to apply network settings", - "You might not be able to connect to the Bluetooth network via this machine", - result, - margin_left=9) + d = ErrorDialog( + "Failed to apply network settings", + "You might not be able to connect to the Bluetooth network via this machine", + result, + margin_left=9, + ) d.run() d.destroy() m = Mechanism() - m.EnableNetwork('(sssb)', self.Config["ip4-address"], self.Config["ip4-netmask"], self.Config["dhcp-handler"], - False, result_handler=reply, error_handler=err) + m.EnableNetwork( + "(sssb)", + self.Config["ip4-address"], + self.Config["ip4-netmask"], + self.Config["dhcp-handler"], + False, + result_handler=reply, + error_handler=err, + ) def on_unload(self) -> None: for adapter_path in self._registered: diff --git a/blueman/plugins/applet/PPPSupport.py b/blueman/plugins/applet/PPPSupport.py index 3a30b8e89..7c7d28d85 100644 --- a/blueman/plugins/applet/PPPSupport.py +++ b/blueman/plugins/applet/PPPSupport.py @@ -28,16 +28,22 @@ def on_ppp_connected(self, device: Device, rfcomm: str, ppp_port: str) -> None: class Connection: - def __init__(self, applet: "BluemanApplet", service: DialupNetwork, port: int, - ok: Callable[[str], None], err: Callable[[GLib.Error], None]): + def __init__( + self, + applet: "BluemanApplet", + service: DialupNetwork, + port: int, + ok: Callable[[str], None], + err: Callable[[GLib.Error], None], + ): self.reply_handler = ok self.error_handler = err self.service = service self.port = port self.parent = applet - stdout, stderr = subprocess.Popen(['ps', 'ax', '-o', 'pid,args'], stdout=subprocess.PIPE).communicate() - if b'ModemManager' in stdout: + stdout, stderr = subprocess.Popen(["ps", "ax", "-o", "pid,args"], stdout=subprocess.PIPE).communicate() + if b"ModemManager" in stdout: timeout = 10 logging.info(f"ModemManager is running, delaying connection {timeout} sec for it to complete probing") GLib.timeout_add_seconds(timeout, self.connect) @@ -45,12 +51,14 @@ def __init__(self, applet: "BluemanApplet", service: DialupNetwork, port: int, self.connect() def connect(self) -> bool: - c = Gio.Settings(schema_id="org.blueman.gsmsetting", - path=f"/org/blueman/gsmsettings/{self.service.device['Address']}/") + c = Gio.Settings( + schema_id="org.blueman.gsmsetting", path=f"/org/blueman/gsmsettings/{self.service.device['Address']}/" + ) m = Mechanism() - m.PPPConnect('(uss)', self.port, c["number"], c["apn"], result_handler=self.on_connected, - error_handler=self.on_error) + m.PPPConnect( + "(uss)", self.port, c["number"], c["apn"], result_handler=self.on_connected, error_handler=self.on_error + ) return False @@ -70,9 +78,10 @@ def on_connected(self, _obj: Mechanism, result: str, _user_data: None) -> None: for plugin in self.parent.Plugins.get_loaded_plugins(PPPConnectedListener): plugin.on_ppp_connected(self.service.device, rfcomm_dev, result) - msg = _("Successfully connected to DUN service on %(0)s.\n" - "Network is now available through %(1)s") % \ - {"0": self.service.device.display_name, "1": result} + msg = _( + "Successfully connected to DUN service on %(0)s.\n" + "Network is now available through %(1)s" + ) % {"0": self.service.device.display_name, "1": result} Notification(_("Connected"), msg, icon_name="network-wireless-symbolic").show() @@ -84,9 +93,14 @@ class PPPSupport(AppletPlugin, RFCOMMConnectHandler): __icon__ = "modem-symbolic" __priority__ = 0 - def rfcomm_connect_handler(self, service: SerialService, reply: Callable[[str], None], - err: Callable[[Union[RFCOMMError, GLib.Error]], None]) -> bool: + def rfcomm_connect_handler( + self, + service: SerialService, + reply: Callable[[str], None], + err: Callable[[Union[RFCOMMError, GLib.Error]], None], + ) -> bool: if isinstance(service, DialupNetwork): + def local_reply(port: int) -> None: assert isinstance(service, DialupNetwork) # https://github.com/python/mypy/issues/2608 Connection(self.parent, service, port, reply, err) diff --git a/blueman/plugins/applet/PowerManager.py b/blueman/plugins/applet/PowerManager.py index 7e35bfbea..63e89f637 100644 --- a/blueman/plugins/applet/PowerManager.py +++ b/blueman/plugins/applet/PowerManager.py @@ -20,8 +20,7 @@ class PowerStateHandler: def on_power_state_query(self) -> "PowerManager.State": return PowerManager.State.ON - def on_power_state_change_requested(self, manager: "PowerManager", state: bool, - cb: Callable[[bool], None]) -> None: + def on_power_state_change_requested(self, manager: "PowerManager", state: bool, cb: Callable[[bool], None]) -> None: ... @@ -38,10 +37,15 @@ class State(Enum): OFF_FORCED = 0 def on_load(self) -> None: - self.item = self.parent.Plugins.Menu.add(self, 1, text=_("Turn Bluetooth _Off"), markup=True, - icon_name="bluetooth-disabled-symbolic", - tooltip=_("Turn off all adapters"), - callback=self.on_bluetooth_toggled) + self.item = self.parent.Plugins.Menu.add( + self, + 1, + text=_("Turn Bluetooth _Off"), + markup=True, + icon_name="bluetooth-disabled-symbolic", + tooltip=_("Turn off all adapters"), + callback=self.on_bluetooth_toggled, + ) self.adapter_state = True self.current_state = True @@ -60,6 +64,7 @@ def CurrentState(self) -> bool: def on_manager_state_changed(self, state: bool) -> None: if state: + def timeout() -> bool: self.request_power_state(self.get_adapter_state()) return False @@ -132,8 +137,7 @@ def request_power_state(self, state: bool, force: bool = False) -> None: # queries other plugins to determine the current power state def update_power_state(self) -> None: - rets = [plugin.on_power_state_query() - for plugin in self.parent.Plugins.get_loaded_plugins(PowerStateHandler)] + rets = [plugin.on_power_state_query() for plugin in self.parent.Plugins.get_loaded_plugins(PowerStateHandler)] off = any(x != self.State.ON for x in rets) or not self.adapter_state foff = self.State.OFF_FORCED in rets @@ -141,7 +145,6 @@ def update_power_state(self) -> None: new_state = True if foff or off: - self.item.set_text(_("Turn Bluetooth _On"), markup=True) self.item.set_icon_name("bluetooth-symbolic") self.item.set_tooltip(_("Turn on all adapters")) @@ -150,7 +153,6 @@ def update_power_state(self) -> None: new_state = False elif on and not self.current_state: - self.item.set_text(_("Turn Bluetooth _Off"), markup=True) self.item.set_icon_name("bluetooth-disabled-symbolic") self.item.set_tooltip(_("Turn off all adapters")) diff --git a/blueman/plugins/applet/PulseAudioProfile.py b/blueman/plugins/applet/PulseAudioProfile.py index 16f19a2b8..846b1d3d5 100644 --- a/blueman/plugins/applet/PulseAudioProfile.py +++ b/blueman/plugins/applet/PulseAudioProfile.py @@ -4,8 +4,7 @@ from blueman.main.PulseAudioUtils import EventType, PulseAudioUtils from blueman.plugins.AppletPlugin import AppletPlugin -from blueman.Sdp import (AUDIO_SINK_SVCLASS_ID, AUDIO_SOURCE_SVCLASS_ID, - ServiceUUID) +from blueman.Sdp import AUDIO_SINK_SVCLASS_ID, AUDIO_SOURCE_SVCLASS_ID, ServiceUUID if TYPE_CHECKING: from blueman.bluez.Device import Device @@ -31,22 +30,22 @@ def on_load(self) -> None: def generate_menu(self) -> None: devices = self.parent.Manager.get_devices() for device in devices: - if device['Connected']: + if device["Connected"]: self.request_device_profile_menu(device) def request_device_profile_menu(self, device: "Device") -> None: audio_source = False - for uuid in device['UUIDs']: + for uuid in device["UUIDs"]: if ServiceUUID(uuid).short_uuid in (AUDIO_SOURCE_SVCLASS_ID, AUDIO_SINK_SVCLASS_ID): audio_source = True break - if device['Connected'] and audio_source: + if device["Connected"] and audio_source: pa = PulseAudioUtils() if not pa.connected: return - if not device['Address'] in self._devices: + if not device["Address"] in self._devices: self.query_pa(device) else: self.add_device_profile_menu(device) @@ -55,6 +54,7 @@ def add_device_profile_menu(self, device: "Device") -> None: def _activate_profile_wrapper(device: "Device", profile: "CardProfileInfo") -> Callable[[], None]: def _wrapper() -> None: self.on_activate_profile(device, profile) + return _wrapper def _generate_profiles_menu(info: "CardInfo") -> List["SubmenuItemDict"]: @@ -67,27 +67,33 @@ def _generate_profiles_menu(info: "CardInfo") -> List["SubmenuItemDict"]: if profile["name"] == info["active_profile"]: profile_name = f"{profile_name}" profile_icon = "dialog-ok" - items.append({ - "text": profile_name, - "markup": True, - "icon_name": profile_icon, - "sensitive": True, - "callback": _activate_profile_wrapper(device, profile), - "tooltip": "", - }) + items.append( + { + "text": profile_name, + "markup": True, + "icon_name": profile_icon, + "sensitive": True, + "callback": _activate_profile_wrapper(device, profile), + "tooltip": "", + } + ) return items - info = self._devices[device['Address']] - menu = self._menu.add(self, (42, info["index"]), _("Audio Profiles for %s") % device.display_name, - icon_name="audio-card-symbolic", - submenu_function=lambda: _generate_profiles_menu(info)) - self._device_menus[device['Address']] = menu + info = self._devices[device["Address"]] + menu = self._menu.add( + self, + (42, info["index"]), + _("Audio Profiles for %s") % device.display_name, + icon_name="audio-card-symbolic", + submenu_function=lambda: _generate_profiles_menu(info), + ) + self._device_menus[device["Address"]] = menu def query_pa(self, device: "Device") -> None: def list_cb(cards: Mapping[str, "CardInfo"]) -> None: for c in cards.values(): - if c["proplist"]["device.string"] == device['Address']: - self._devices[device['Address']] = c + if c["proplist"]["device.string"] == device["Address"]: + self._devices[device["Address"]] = c self.add_device_profile_menu(device) return @@ -97,7 +103,7 @@ def list_cb(cards: Mapping[str, "CardInfo"]) -> None: def on_activate_profile(self, device: "Device", profile: "CardProfileInfo") -> None: pa = PulseAudioUtils() - c = self._devices[device['Address']] + c = self._devices[device["Address"]] def on_result(res: int) -> None: if not res: @@ -109,9 +115,7 @@ def on_pa_event(self, utils: PulseAudioUtils, event: int, idx: int) -> None: logging.debug(f"{event} {idx}") def get_card_cb(card: "CardInfo") -> None: - drivers = ("module-bluetooth-device.c", - "module-bluez4-device.c", - "module-bluez5-device.c") + drivers = ("module-bluetooth-device.c", "module-bluez4-device.c", "module-bluez5-device.c") if card["driver"] in drivers: self._devices[card["proplist"]["device.string"]] = card diff --git a/blueman/plugins/applet/RecentConns.py b/blueman/plugins/applet/RecentConns.py index 84ec37a07..234a9de27 100644 --- a/blueman/plugins/applet/RecentConns.py +++ b/blueman/plugins/applet/RecentConns.py @@ -33,6 +33,7 @@ class Item(_ItemBase): class StoredIcon(_ItemBase): time: str + REGISTRY_VERSION = 0 @@ -42,18 +43,17 @@ class RecentConns(AppletPlugin, PowerStateListener): __description__ = _("Provides a menu item that contains last used connections for quick access") __author__ = "Walmis" - __gsettings__ = { - "schema": "org.blueman.plugins.recentconns", - "path": None - } + __gsettings__ = {"schema": "org.blueman.plugins.recentconns", "path": None} __options__ = { - "max-items": {"type": int, - "default": 6, - # the maximum number of items RecentConns menu will display - "name": _("Maximum items"), - "desc": _("The maximum number of items recent connections menu will display."), - "range": (6, 20)}, - "recent-connections": {"type": list, "default": "[]"} + "max-items": { + "type": int, + "default": 6, + # the maximum number of items RecentConns menu will display + "name": _("Maximum items"), + "desc": _("The maximum number of items recent connections menu will display."), + "range": (6, 20), + }, + "recent-connections": {"type": list, "default": "[]"}, } def on_load(self) -> None: @@ -68,8 +68,10 @@ def on_unload(self) -> None: self.parent.Plugins.Menu.unregister(self) def _rebuild(self) -> None: - if 'PowerManager' in self.parent.Plugins.get_loaded() and \ - not self.parent.Plugins.PowerManager.get_bluetooth_status(): + if ( + "PowerManager" in self.parent.Plugins.get_loaded() + and not self.parent.Plugins.PowerManager.get_bluetooth_status() + ): for mitem in self._mitems: mitem.set_sensitive(False) return @@ -84,7 +86,7 @@ def _rebuild(self) -> None: for mitem in self._mitems: mitem.set_sensitive(True) - self.__menuitems = [self._build_menu_item(item) for item in items[:self.get_option("max-items")]] + self.__menuitems = [self._build_menu_item(item) for item in items[: self.get_option("max-items")]] self._rebuild_menu() @@ -111,16 +113,16 @@ def notify(self, object_path: str, uuid: str) -> None: device = Device(obj_path=object_path) logging.info(f"{device} {uuid}") try: - adapter = self.parent.Manager.get_adapter(device['Adapter']) + adapter = self.parent.Manager.get_adapter(device["Adapter"]) except DBusNoSuchAdapterError: logging.warning("adapter not found") return item = { "adapter": adapter["Address"], - "address": device['Address'], + "address": device["Address"], "alias": device.display_name, - "icon": device['Icon'], + "icon": device["Icon"], "name": ServiceUUID(uuid).name, "uuid": uuid, "time": str(time.time()), @@ -129,9 +131,7 @@ def notify(self, object_path: str, uuid: str) -> None: stored_items = self.get_option("recent-connections") for i in stored_items: - if i["adapter"] == item["adapter"] and \ - i["address"] == item["address"] and \ - i["uuid"] == item["uuid"]: + if i["adapter"] == item["adapter"] and i["address"] == item["address"] and i["uuid"] == item["uuid"]: i["time"] = item["time"] i["device"] = object_path break @@ -152,14 +152,12 @@ def on_item_activated(self, item: "Item") -> None: def reply() -> None: assert item["mitem"] is not None # https://github.com/python/mypy/issues/2608 - Notification(_("Connected"), _("Connected to %s") % item["mitem"]["text"], - icon_name=item["icon"]).show() + Notification(_("Connected"), _("Connected to %s") % item["mitem"]["text"], icon_name=item["icon"]).show() item["mitem"]["sensitive"] = True self.parent.Plugins.Menu.on_menu_changed() def err(reason: Union[Exception, str]) -> None: - Notification(_("Failed to connect"), str(reason).split(": ")[-1], - icon_name="dialog-error").show() + Notification(_("Failed to connect"), str(reason).split(": ")[-1], icon_name="dialog-error").show() assert item["mitem"] is not None # https://github.com/python/mypy/issues/2608 item["mitem"]["sensitive"] = True self.parent.Plugins.Menu.on_menu_changed() @@ -173,8 +171,11 @@ def _build_menu_item(self, item: "Item") -> "SubmenuItemDict": "icon_name": item["mitem"]["icon_name"] if item["mitem"] is not None else item["icon"], "sensitive": item["device"] is not None, "tooltip": None if item["device"] is None else _("Adapter for this connection is not available"), - "callback": (item["mitem"]["callback"] if item["mitem"] is not None - else cast(Callable[[], None], lambda itm=item: self.on_item_activated(itm))) + "callback": ( + item["mitem"]["callback"] + if item["mitem"] is not None + else cast(Callable[[], None], lambda itm=item: self.on_item_activated(itm)) + ), } item["mitem"] = mitem @@ -185,9 +186,15 @@ def _rebuild_menu(self) -> None: menu: "Menu" = self.parent.Plugins.Menu self._mitems: List[MenuItem] = [] 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): + 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) @@ -202,19 +209,21 @@ def _get_device_path(self, adapter_path: str, address: str) -> Optional[str]: def _get_items(self) -> List["Item"]: return sorted( - ({ - "adapter": i["adapter"], - "address": i["address"], - "alias": i["alias"], - "icon": i["icon"], - "name": i["name"], - "uuid": i["uuid"], - "time": float(i["time"]), - "device": device, - "mitem": None - } + ( + { + "adapter": i["adapter"], + "address": i["address"], + "alias": i["alias"], + "icon": i["icon"], + "name": i["name"], + "uuid": i["uuid"], + "time": float(i["time"]), + "device": device, + "mitem": None, + } for i in self.get_option("recent-connections") - if (device := self._get_device_path(i["adapter"], i["address"]))), + if (device := self._get_device_path(i["adapter"], i["address"])) + ), key=itemgetter("time"), - reverse=True + reverse=True, ) diff --git a/blueman/plugins/applet/SerialManager.py b/blueman/plugins/applet/SerialManager.py index a47ada378..4cfa40a16 100644 --- a/blueman/plugins/applet/SerialManager.py +++ b/blueman/plugins/applet/SerialManager.py @@ -22,19 +22,21 @@ class SerialManager(AppletPlugin, RFCOMMConnectedListener): __description__ = _("Standard SPP profile connection handler, allows executing custom actions") __author__ = "walmis" - __gsettings__ = { - "schema": "org.blueman.plugins.serialmanager", - "path": None - } + __gsettings__ = {"schema": "org.blueman.plugins.serialmanager", "path": None} __options__ = { - "script": {"type": str, "default": "", - "name": _("Script to execute on connection"), - "desc": _("The following arguments will be passed:\n" - "Address, Name, service name, uuid16s, rfcomm node\n" - "For example:\n" - "AA:BB:CC:DD:EE:FF, Phone, DUN service, 0x1103, /dev/rfcomm0\n" - "uuid16s are returned as a comma separated list\n\n" - "Upon device disconnection the script will be sent a HUP signal")}, + "script": { + "type": str, + "default": "", + "name": _("Script to execute on connection"), + "desc": _( + 'The following arguments will be passed:\n' + "Address, Name, service name, uuid16s, rfcomm node\n" + "For example:\n" + "AA:BB:CC:DD:EE:FF, Phone, DUN service, 0x1103, /dev/rfcomm0\n" + "uuid16s are returned as a comma separated list\n\n" + "Upon device disconnection the script will be sent a HUP signal" + ), + }, } scripts: Dict[str, Dict[str, "Popen[Any]"]] = {} @@ -60,16 +62,14 @@ def on_device_property_changed(self, path: str, key: str, value: Any) -> None: def on_rfcomm_connected(self, service: SerialService, port: str) -> None: device = service.device if SERIAL_PORT_SVCLASS_ID == service.short_uuid: - Notification(_("Serial port connected"), - _("Serial port service on device %s now will be available via %s") % ( - device.display_name, port), - icon_name="blueman-serial").show() + Notification( + _("Serial port connected"), + _("Serial port service on device %s now will be available via %s") + % (device.display_name, port), + icon_name="blueman-serial", + ).show() - self.call_script(device['Address'], - device.display_name, - service.name, - service.short_uuid, - port) + self.call_script(device["Address"], device.display_name, service.name, service.short_uuid, port) def terminate_all_scripts(self, address: str) -> None: if address not in self.scripts: @@ -111,10 +111,11 @@ def call_script(self, address: str, name: str, sv_name: str, uuid16: int, node: except Exception as e: logging.debug(str(e)) - Notification(_("Serial port connection script failed"), - _("There was a problem launching script %s\n" - "%s") % (c, str(e)), - icon_name="blueman-serial").show() + Notification( + _("Serial port connection script failed"), + _("There was a problem launching script %s\n" "%s") % (c, str(e)), + icon_name="blueman-serial", + ).show() def on_rfcomm_disconnect(self, port: int) -> None: for bdaddr, scripts in self.scripts.items(): @@ -130,7 +131,7 @@ def on_device_disconnect(self, device: Device) -> None: return try: - active_ports = [rfcomm['id'] for rfcomm in rfcomm_list() if rfcomm['dst'] == device['Address']] + active_ports = [rfcomm["id"] for rfcomm in rfcomm_list() if rfcomm["dst"] == device["Address"]] except RFCOMMError as e: logging.error(f"rfcomm_list failed with: {e}") return diff --git a/blueman/plugins/applet/ShowConnected.py b/blueman/plugins/applet/ShowConnected.py index b809f8442..ca67ac042 100644 --- a/blueman/plugins/applet/ShowConnected.py +++ b/blueman/plugins/applet/ShowConnected.py @@ -18,16 +18,17 @@ class ShowConnected(AppletPlugin, StatusIconProvider): __author__ = "Walmis" __depends__ = ["StatusIcon"] __icon__ = "bluetooth-symbolic" - __description__ = _("Adds an indication on the status icon when Bluetooth is active and shows the " - "connections in the tooltip.") + __description__ = _( + "Adds an indication on the status icon when Bluetooth is active and shows the " "connections in the tooltip." + ) def on_load(self) -> None: self._connections: Set[str] = set() self.active = False self.initialized = False self._handlers: List[int] = [] - self._handlers.append(self.parent.Plugins.connect('plugin-loaded', self._on_plugins_changed)) - self._handlers.append(self.parent.Plugins.connect('plugin-unloaded', self._on_plugins_changed)) + self._handlers.append(self.parent.Plugins.connect("plugin-loaded", self._on_plugins_changed)) + self._handlers.append(self.parent.Plugins.connect("plugin-unloaded", self._on_plugins_changed)) self._battery_watcher = BatteryWatcher(lambda *args: self.update_statusicon()) def on_unload(self) -> None: @@ -48,9 +49,9 @@ def on_status_icon_query_icon(self) -> Optional[str]: return None def enumerate_connections(self) -> bool: - self._connections = {device.get_object_path() - for device in self.parent.Manager.get_devices() - if device["Connected"]} + self._connections = { + device.get_object_path() for device in self.parent.Manager.get_devices() if device["Connected"] + } logging.info(f"Found {len(self._connections):d} existing connections") if (self._connections and not self.active) or (not self._connections and self.active): @@ -62,6 +63,7 @@ def enumerate_connections(self) -> bool: def update_statusicon(self) -> None: if self._connections: + def build_line(obj_path: str) -> str: line: str = Device(obj_path=obj_path)["Alias"] try: @@ -73,7 +75,7 @@ def build_line(obj_path: str) -> str: self.parent.Plugins.StatusIcon.set_tooltip_text("\n".join(map(build_line, self._connections))) else: self.parent.Plugins.StatusIcon.set_tooltip_text(None) - if 'PowerManager' in self.parent.Plugins.get_loaded(): + if "PowerManager" in self.parent.Plugins.get_loaded(): status = self.parent.Plugins.PowerManager.get_bluetooth_status() if status: self.parent.Plugins.StatusIcon.set_tooltip_title(_("Bluetooth Enabled")) diff --git a/blueman/plugins/applet/StandardItems.py b/blueman/plugins/applet/StandardItems.py index 1ae9fe6a3..9f93231a7 100644 --- a/blueman/plugins/applet/StandardItems.py +++ b/blueman/plugins/applet/StandardItems.py @@ -29,33 +29,38 @@ def on_load(self) -> None: self.parent.Plugins.Menu.add(self, 31) - self.send = self.parent.Plugins.Menu.add(self, 40, text=_("Send _Files to Device") + "…", - icon_name="blueman-send-symbolic", callback=self.on_send) + self.send = self.parent.Plugins.Menu.add( + self, 40, text=_("Send _Files to Device") + "…", icon_name="blueman-send-symbolic", callback=self.on_send + ) self.parent.Plugins.Menu.add(self, 51) - self.devices = self.parent.Plugins.Menu.add(self, 60, text=_("_Devices") + "…", - icon_name="bluetooth-symbolic", - callback=self.on_devices) + self.devices = self.parent.Plugins.Menu.add( + self, 60, text=_("_Devices") + "…", icon_name="bluetooth-symbolic", callback=self.on_devices + ) - self.adapters = self.parent.Plugins.Menu.add(self, 70, text=_("Adap_ters") + "…", - icon_name="bluetooth-symbolic", - callback=self.on_adapters) + self.adapters = self.parent.Plugins.Menu.add( + self, 70, text=_("Adap_ters") + "…", icon_name="bluetooth-symbolic", callback=self.on_adapters + ) - self.parent.Plugins.Menu.add(self, 80, text=_("_Local Services") + "…", - icon_name="document-properties-symbolic", - callback=self.on_local_services) + self.parent.Plugins.Menu.add( + self, + 80, + text=_("_Local Services") + "…", + icon_name="document-properties-symbolic", + callback=self.on_local_services, + ) self.parent.Plugins.Menu.add(self, 81) - self.parent.Plugins.Menu.add(self, 90, text=_("_Help"), icon_name='help-about-symbolic', - callback=self.on_about) + self.parent.Plugins.Menu.add(self, 90, text=_("_Help"), icon_name="help-about-symbolic", callback=self.on_about) - self.parent.Plugins.Menu.add(self, 85, text=_("_Plugins"), icon_name="application-x-addon-symbolic", - callback=self.on_plugins) + self.parent.Plugins.Menu.add( + self, 85, text=_("_Plugins"), icon_name="application-x-addon-symbolic", callback=self.on_plugins + ) def change_sensitivity(self, sensitive: bool) -> None: - if 'PowerManager' in self.parent.Plugins.get_loaded(): + if "PowerManager" in self.parent.Plugins.get_loaded(): power = self.parent.Plugins.PowerManager.get_bluetooth_status() else: power = True diff --git a/blueman/plugins/applet/StatusIcon.py b/blueman/plugins/applet/StatusIcon.py index 6c2efd89c..51a13d7e2 100644 --- a/blueman/plugins/applet/StatusIcon.py +++ b/blueman/plugins/applet/StatusIcon.py @@ -43,8 +43,8 @@ def on_load(self) -> None: self.query_visibility(emit=False) - self.parent.Plugins.connect('plugin-loaded', self._on_plugins_changed) - self.parent.Plugins.connect('plugin-unloaded', self._on_plugins_changed) + self.parent.Plugins.connect("plugin-loaded", self._on_plugins_changed) + self.parent.Plugins.connect("plugin-unloaded", self._on_plugins_changed) self._add_dbus_method("GetVisibility", (), "b", lambda: self.visible) self._add_dbus_signal("VisibilityChanged", "b") @@ -58,9 +58,10 @@ def on_load(self) -> None: self._add_dbus_method("Activate", (), "", self.parent.Plugins.StandardItems.on_devices) def query_visibility(self, delay_hiding: bool = False, emit: bool = True) -> None: - if self.parent.Manager.get_adapters() or \ - any(plugin.on_query_force_status_icon_visibility() - for plugin in self.parent.Plugins.get_loaded_plugins(StatusIconVisibilityHandler)): + if self.parent.Manager.get_adapters() or any( + plugin.on_query_force_status_icon_visibility() + for plugin in self.parent.Plugins.get_loaded_plugins(StatusIconVisibilityHandler) + ): self.set_visible(True, emit) elif not self.visibility_timeout: if delay_hiding: @@ -104,7 +105,7 @@ def on_adapter_removed(self, _path: str) -> None: def on_manager_state_changed(self, state: bool) -> None: self.query_visibility() if state: - launch('blueman-tray', icon_name='blueman', sn=False) + launch("blueman-tray", icon_name="blueman", sn=False) def _on_plugins_changed(self, _plugins: PluginManager, _name: str) -> None: implementations = self._get_status_icon_implementations() @@ -112,15 +113,20 @@ def _on_plugins_changed(self, _plugins: PluginManager, _name: str) -> None: self._implementations = implementations if self.parent.manager_state: - launch('blueman-tray', icon_name='blueman', sn=False) + launch("blueman-tray", icon_name="blueman", sn=False) def _get_status_icon_implementations(self) -> List[str]: - return [implementation for implementation, _ in sorted( - (plugin.on_query_status_icon_implementation() - for plugin in self.parent.Plugins.get_loaded_plugins(StatusIconImplementationProvider)), - key=itemgetter(1), - reverse=True - )] + ["GtkStatusIcon"] + return [ + implementation + for implementation, _ in sorted( + ( + plugin.on_query_status_icon_implementation() + for plugin in self.parent.Plugins.get_loaded_plugins(StatusIconImplementationProvider) + ), + key=itemgetter(1), + reverse=True, + ) + ] + ["GtkStatusIcon"] def _get_icon_name(self) -> str: # default icon name diff --git a/blueman/plugins/applet/TransferService.py b/blueman/plugins/applet/TransferService.py index 792b55bdc..cd3526fc9 100644 --- a/blueman/plugins/applet/TransferService.py +++ b/blueman/plugins/applet/TransferService.py @@ -34,6 +34,7 @@ class PendingTransferDict(TypedDict): size: Optional[int] name: str + NotificationType = Union[_NotificationBubble, _NotificationDialog] @@ -46,7 +47,7 @@ class ObexErrorCanceled(DbusError): class Agent(DbusService): - __agent_path = '/org/bluez/obex/agent/blueman' + __agent_path = "/org/bluez/obex/agent/blueman" def __init__(self, applet: BluemanApplet): super().__init__(None, "org.bluez.obex.Agent1", self.__agent_path, Gio.BusType.SESSION) @@ -73,26 +74,27 @@ def unregister_from_manager(self) -> None: def _release(self) -> None: raise Exception(self.__agent_path + " was released unexpectedly") - def _authorize_push(self, transfer_path: str, ok: Callable[[str], None], - err: Callable[[ObexErrorRejected], None]) -> None: + def _authorize_push( + self, transfer_path: str, ok: Callable[[str], None], err: Callable[[ObexErrorRejected], None] + ) -> None: def on_action(action: str) -> None: logging.info(f"Action {action}") if action == "accept": assert self._pending_transfer - self.transfers[self._pending_transfer['transfer_path']] = { - 'path': self._pending_transfer['root'] + '/' + os.path.basename(self._pending_transfer['filename']), - 'size': self._pending_transfer['size'], - 'name': self._pending_transfer['name'] + self.transfers[self._pending_transfer["transfer_path"]] = { + "path": self._pending_transfer["root"] + "/" + os.path.basename(self._pending_transfer["filename"]), + "size": self._pending_transfer["size"], + "name": self._pending_transfer["name"], } - ok(self.transfers[self._pending_transfer['transfer_path']]['path']) + ok(self.transfers[self._pending_transfer["transfer_path"]]["path"]) - self._allowed_devices.append(self._pending_transfer['address']) + self._allowed_devices.append(self._pending_transfer["address"]) def _remove() -> bool: assert self._pending_transfer is not None # https://github.com/python/mypy/issues/2608 - self._allowed_devices.remove(self._pending_transfer['address']) + self._allowed_devices.remove(self._pending_transfer["address"]) return False GLib.timeout_add(60000, _remove) @@ -117,28 +119,36 @@ def _remove() -> bool: name = address trusted = False - self._pending_transfer = {'transfer_path': transfer_path, 'address': address, 'root': root, - 'filename': filename, 'size': size, 'name': name} + self._pending_transfer = { + "transfer_path": transfer_path, + "address": address, + "root": root, + "filename": filename, + "size": size, + "name": name, + } # This device was neither allowed nor is it trusted -> ask for confirmation - if address not in self._allowed_devices and not (self._config['opp-accept'] and trusted): + if address not in self._allowed_devices and not (self._config["opp-accept"] and trusted): self._notification = notification = Notification( _("Incoming file over Bluetooth"), - _("Incoming file %(0)s from %(1)s") % {"0": "" + escape(filename) + "", - "1": "" + escape(name) + ""}, - 30000, [("accept", _("Accept")), ("reject", _("Reject"))], on_action, - icon_name="blueman" + _("Incoming file %(0)s from %(1)s") + % {"0": "" + escape(filename) + "", "1": "" + escape(name) + ""}, + 30000, + [("accept", _("Accept")), ("reject", _("Reject"))], + on_action, + icon_name="blueman", ) notification.show() # Device is trusted or was already allowed, larger file -> display a notification, but auto-accept elif size and size > 350000: self._notification = notification = Notification( _("Receiving file"), - _("Receiving file %(0)s from %(1)s") % {"0": "" + escape(filename) + "", - "1": "" + escape(name) + ""}, - icon_name="blueman" + _("Receiving file %(0)s from %(1)s") + % {"0": "" + escape(filename) + "", "1": "" + escape(name) + ""}, + icon_name="blueman", ) - on_action('accept') + on_action("accept") notification.show() # Device is trusted or was already allowed. very small file -> auto-accept and transfer silently else: @@ -168,20 +178,27 @@ class TransferService(AppletPlugin): def on_load(self) -> None: def on_reset(_action: str) -> None: self._notification = None - self._config.reset('shared-path') - logging.info('Reset share path') + self._config.reset("shared-path") + logging.info("Reset share path") self._config = Gio.Settings(schema_id="org.blueman.transfer") share_path, invalid_share_path = self._make_share_path() if invalid_share_path: - text = _('Configured directory for incoming files does not exist') - secondary_text = _('Please make sure that directory "%s" exists or ' - 'configure it with blueman-services. Until then the default "%s" will be used') - self._notification = Notification(text, secondary_text % (self._config["shared-path"], share_path), - icon_name='blueman', timeout=30000, - actions=[('reset', 'Reset to default')], actions_cb=on_reset) + text = _("Configured directory for incoming files does not exist") + secondary_text = _( + 'Please make sure that directory "%s" exists or ' + 'configure it with blueman-services. Until then the default "%s" will be used' + ) + self._notification = Notification( + text, + secondary_text % (self._config["shared-path"], share_path), + icon_name="blueman", + timeout=30000, + actions=[("reset", "Reset to default")], + actions_cb=on_reset, + ) self._notification.show() self._watch = Manager.watch_name_owner(self._on_dbus_name_appeared, self._on_dbus_name_vanished) @@ -198,7 +215,7 @@ def _make_share_path(self) -> Tuple[str, bool]: path = None error = False - if config_path == '': + if config_path == "": path = default_path elif not os.path.isdir(config_path): path = default_path @@ -209,12 +226,12 @@ def _make_share_path(self) -> Tuple[str, bool]: if not path: path = os.path.expanduser("~") - logging.warning('Failed to get Download dir from XDG') + logging.warning("Failed to get Download dir from XDG") # We used to always store the full path which caused problems if config_path == default_path: - logging.info('Reset stored path, identical to default path.') - self._config["shared-path"] = '' + logging.info("Reset stored path, identical to default path.") + self._config["shared-path"] = "" return path, error @@ -235,7 +252,7 @@ def _on_dbus_name_appeared(self, _connection: Gio.DBusConnection, name: str, own self._manager = Manager() self._handlerids.append(self._manager.connect("transfer-started", self._on_transfer_started)) self._handlerids.append(self._manager.connect("transfer-completed", self._on_transfer_completed)) - self._handlerids.append(self._manager.connect('session-removed', self._on_session_removed)) + self._handlerids.append(self._manager.connect("session-removed", self._on_session_removed)) self._register_agent() @@ -257,7 +274,7 @@ def _on_transfer_started(self, _manager: Manager, transfer_path: str) -> None: # This is not an incoming transfer we authorized return - size = self._agent.transfers[transfer_path]['size'] + size = self._agent.transfers[transfer_path]["size"] assert size is not None if size > 350000: self._normal_transfers += 1 @@ -282,7 +299,7 @@ def _on_transfer_completed(self, _manager: Manager, transfer_path: str, success: attributes = self._agent.transfers[transfer_path] - src = attributes['path'] + src = attributes["path"] dest_dir, ignored = self._make_share_path() filename = os.path.basename(src) @@ -299,24 +316,24 @@ def _on_transfer_completed(self, _manager: Manager, transfer_path: str, success: success = False if success: - self._notification = Notification(_("File received"), - _("File %(0)s from %(1)s successfully received") % { - "0": "" + escape(filename) + "", - "1": "" + escape(attributes['name']) + ""}, - icon_name="blueman") + self._notification = Notification( + _("File received"), + _("File %(0)s from %(1)s successfully received") + % {"0": "" + escape(filename) + "", "1": "" + escape(attributes["name"]) + ""}, + icon_name="blueman", + ) self._add_open(self._notification, _("Open"), dest) self._notification.show() elif not success: n = Notification( _("Transfer failed"), - _("Transfer of file %(0)s failed") % { - "0": "" + escape(filename) + "", - "1": "" + escape(attributes['name']) + ""}, - icon_name="blueman" + _("Transfer of file %(0)s failed") + % {"0": "" + escape(filename) + "", "1": "" + escape(attributes["name"]) + ""}, + icon_name="blueman", ) n.show() - assert attributes['size'] is not None - if attributes['size'] > 350000: + assert attributes["size"] is not None + if attributes["size"] > 350000: self._normal_transfers -= 1 else: self._silent_transfers -= 1 @@ -329,19 +346,29 @@ def _on_session_removed(self, _manager: Manager, _session_path: str) -> None: share_path, ignored = self._make_share_path() if self._normal_transfers == 0: - self._notification = Notification(_("Files received"), - ngettext("Received %(files)d file in the background", - "Received %(files)d files in the background", - self._silent_transfers) % {"files": self._silent_transfers}, - icon_name="blueman") + self._notification = Notification( + _("Files received"), + ngettext( + "Received %(files)d file in the background", + "Received %(files)d files in the background", + self._silent_transfers, + ) + % {"files": self._silent_transfers}, + icon_name="blueman", + ) self._add_open(self._notification, _("Open Location"), share_path) self._notification.show() else: - self._notification = Notification(_("Files received"), - ngettext("Received %(files)d more file in the background", - "Received %(files)d more files in the background", - self._silent_transfers) % {"files": self._silent_transfers}, - icon_name="blueman") + self._notification = Notification( + _("Files received"), + ngettext( + "Received %(files)d more file in the background", + "Received %(files)d more files in the background", + self._silent_transfers, + ) + % {"files": self._silent_transfers}, + icon_name="blueman", + ) self._add_open(self._notification, _("Open Location"), share_path) self._notification.show() diff --git a/blueman/plugins/manager/Info.py b/blueman/plugins/manager/Info.py index e23342acc..163ca0844 100644 --- a/blueman/plugins/manager/Info.py +++ b/blueman/plugins/manager/Info.py @@ -18,16 +18,16 @@ def show_info(device: Device, parent: Gtk.Window) -> None: def format_boolean(x: bool) -> str: - return _('yes') if x else _('no') + return _("yes") if x else _("no") def format_rssi(rssi: int) -> str: - if rssi in [0x99, 0x7f]: - return f'invalid (0x{rssi:02x})' + if rssi in [0x99, 0x7F]: + return f"invalid (0x{rssi:02x})" else: - return f'{rssi} dBm (0x{rssi:02x})' + return f"{rssi} dBm (0x{rssi:02x})" def format_uuids(uuids: Iterable[str]) -> str: - return "\n".join([uuid + ' ' + ServiceUUID(uuid).name for uuid in uuids]) + return "\n".join([uuid + " " + ServiceUUID(uuid).name for uuid in uuids]) store = Gtk.ListStore(str, str) view = Gtk.TreeView(model=store, headers_visible=False) @@ -71,32 +71,32 @@ def on_accel_activated(_group: Gtk.AccelGroup, _dialog: GObject, key: int, _modi column = Gtk.TreeViewColumn() cell = Gtk.CellRendererText() column.pack_start(cell, True) - column.add_attribute(cell, 'text', i) + column.add_attribute(cell, "text", i) view.append_column(column) dialog_content_area.pack_start(view, True, False, 0) view.show_all() properties: Iterable[Tuple[str, Optional[Callable[[Any], str]]]] = ( - ('Address', None), - ('AddressType', None), - ('Name', None), - ('Alias', None), - ('Class', lambda x: f"0x{x:06x}"), - ('Appearance', lambda x: f"0x{x:04x}"), - ('Icon', None), - ('Paired', format_boolean), - ('Trusted', format_boolean), - ('Blocked', format_boolean), - ('LegacyPairing', format_boolean), - ('RSSI', format_rssi), - ('Connected', format_boolean), - ('UUIDs', format_uuids), - ('Modalias', None), - ('Adapter', None), + ("Address", None), + ("AddressType", None), + ("Name", None), + ("Alias", None), + ("Class", lambda x: f"0x{x:06x}"), + ("Appearance", lambda x: f"0x{x:04x}"), + ("Icon", None), + ("Paired", format_boolean), + ("Trusted", format_boolean), + ("Blocked", format_boolean), + ("LegacyPairing", format_boolean), + ("RSSI", format_rssi), + ("Connected", format_boolean), + ("UUIDs", format_uuids), + ("Modalias", None), + ("Adapter", None), # FIXME below 3 we need some sample data to decode and display properly - ('ManufacturerData', str), - ('ServiceData', str), - ('AdvertisingData', str) + ("ManufacturerData", str), + ("ServiceData", str), + ("AdvertisingData", str), ) for name, func in properties: try: @@ -122,5 +122,5 @@ def on_request_menu_items(self, manager_menu: ManagerDeviceMenu, device: Device) _window = manager_menu.get_toplevel() assert isinstance(_window, Gtk.Window) window = _window # https://github.com/python/mypy/issues/2608 - item.connect('activate', lambda x: show_info(device, window)) + item.connect("activate", lambda x: show_info(device, window)) return [DeviceMenuItem(item, DeviceMenuItem.Group.ACTIONS, 400)] diff --git a/blueman/plugins/manager/Notes.py b/blueman/plugins/manager/Notes.py index 9dc59a6a3..362cebb10 100644 --- a/blueman/plugins/manager/Notes.py +++ b/blueman/plugins/manager/Notes.py @@ -10,6 +10,7 @@ from blueman.plugins.ManagerPlugin import ManagerPlugin import gi + gi.require_version("Gtk", "3.0") from gi.repository import Gtk @@ -20,18 +21,20 @@ def send_note_cb(dialog: Gtk.Dialog, response_id: int, device_address: str, text if response_id == Gtk.ResponseType.REJECT: return - date = datetime.datetime.now().strftime('%Y%m%dT%H%M00') - data = ('BEGIN:VNOTE \n' - 'VERSION:1.1 \n' - f'BODY;CHARSET=UTF-8: {" ".join(text.splitlines())} \n' - f'DCREATED:{date} \n' - f'LAST-MODIFIED:{date} \n' - 'CLASS:PUBLIC \n' - 'X-IRMC-LUID:000001000000 \n' - 'END:VNOTE \n') - - tempfile = NamedTemporaryFile(suffix='.vnt', prefix='note', delete=False) - tempfile.write(data.encode('utf-8')) + date = datetime.datetime.now().strftime("%Y%m%dT%H%M00") + data = ( + "BEGIN:VNOTE \n" + "VERSION:1.1 \n" + f'BODY;CHARSET=UTF-8: {" ".join(text.splitlines())} \n' + f"DCREATED:{date} \n" + f"LAST-MODIFIED:{date} \n" + "CLASS:PUBLIC \n" + "X-IRMC-LUID:000001000000 \n" + "END:VNOTE \n" + ) + + tempfile = NamedTemporaryFile(suffix=".vnt", prefix="note", delete=False) + tempfile.write(data.encode("utf-8")) tempfile.close() launch(f"blueman-sendto --delete --device={device_address}", paths=[tempfile.name]) @@ -40,9 +43,9 @@ def send_note(device: Device, parent: Gtk.ApplicationWindow) -> None: builder = Builder("note.ui") dialog = builder.get_widget("dialog", Gtk.Dialog) dialog.set_transient_for(parent) - dialog.props.icon_name = 'blueman' + dialog.props.icon_name = "blueman" note = builder.get_widget("note", Gtk.Entry) - dialog.connect('response', send_note_cb, device['Address'], note) + dialog.connect("response", send_note_cb, device["Address"], note) dialog.present() @@ -52,5 +55,5 @@ def on_request_menu_items(self, manager_menu: ManagerDeviceMenu, device: Device) item.props.tooltip_text = _("Send a text note") assert isinstance(manager_menu.Blueman.window, Gtk.ApplicationWindow) window = manager_menu.Blueman.window # https://github.com/python/mypy/issues/2608 - item.connect('activate', lambda x: send_note(device, window)) + item.connect("activate", lambda x: send_note(device, window)) return [DeviceMenuItem(item, DeviceMenuItem.Group.ACTIONS, 500)] diff --git a/blueman/plugins/manager/PulseAudioProfile.py b/blueman/plugins/manager/PulseAudioProfile.py index 6c8f6beea..c523e5ea6 100644 --- a/blueman/plugins/manager/PulseAudioProfile.py +++ b/blueman/plugins/manager/PulseAudioProfile.py @@ -10,6 +10,7 @@ from blueman.Sdp import AUDIO_SOURCE_SVCLASS_ID, AUDIO_SINK_SVCLASS_ID, ServiceUUID import gi + gi.require_version("Gtk", "3.0") from gi.repository import Gtk @@ -31,23 +32,21 @@ def on_load(self) -> None: def on_pa_ready(self, _utils: PulseAudioUtils) -> None: logging.info("connected") for dev in self.deferred: - self.regenerate_with_device(dev['Address']) + self.regenerate_with_device(dev["Address"]) self.deferred = [] # updates all menu instances with the following device address def regenerate_with_device(self, device_addr: str) -> None: for inst in ManagerDeviceMenu.__instances__: - if inst.SelectedDevice['Address'] == device_addr and not inst.is_popup: + if inst.SelectedDevice["Address"] == device_addr and not inst.is_popup: inst.generate() def on_pa_event(self, utils: PulseAudioUtils, event: int, idx: int) -> None: logging.debug(f"{event} {idx}") def get_card_cb(card: "CardInfo") -> None: - drivers = ("module-bluetooth-device.c", - "module-bluez4-device.c", - "module-bluez5-device.c") + drivers = ("module-bluetooth-device.c", "module-bluez4-device.c", "module-bluez5-device.c") if card["driver"] in drivers: self.devices[card["proplist"]["device.string"]] = card @@ -67,8 +66,8 @@ def get_card_cb(card: "CardInfo") -> None: def query_pa(self, device: Device, item: Gtk.MenuItem) -> None: def list_cb(cards: Mapping[str, "CardInfo"]) -> None: for c in cards.values(): - if c["proplist"]["device.string"] == device['Address']: - self.devices[device['Address']] = c + if c["proplist"]["device.string"] == device["Address"]: + self.devices[device["Address"]] = c self.generate_menu(device, item) return @@ -79,7 +78,7 @@ def on_selection_changed(self, item: Gtk.CheckMenuItem, device: Device, profile: if item.get_active(): pa = PulseAudioUtils() - c = self.devices[device['Address']] + c = self.devices[device["Address"]] def on_result(res: int) -> None: if not res: @@ -88,7 +87,7 @@ def on_result(res: int) -> None: pa.set_card_profile(c["index"], profile, on_result) def generate_menu(self, device: Device, item: Gtk.MenuItem) -> None: - info = self.devices[device['Address']] + info = self.devices[device["Address"]] group: Sequence[Gtk.RadioMenuItem] = [] sub = Gtk.Menu() @@ -101,8 +100,7 @@ def generate_menu(self, device: Device, item: Gtk.MenuItem) -> None: if profile["name"] == info["active_profile"]: i.set_active(True) - i.connect("toggled", self.on_selection_changed, - device, profile["name"]) + i.connect("toggled", self.on_selection_changed, device, profile["name"]) sub.append(i) i.show() @@ -112,13 +110,12 @@ def generate_menu(self, device: Device, item: Gtk.MenuItem) -> None: def on_request_menu_items(self, manager_menu: ManagerDeviceMenu, device: Device) -> List[DeviceMenuItem]: audio_source = False - for uuid in device['UUIDs']: + for uuid in device["UUIDs"]: if ServiceUUID(uuid).short_uuid in (AUDIO_SOURCE_SVCLASS_ID, AUDIO_SINK_SVCLASS_ID): audio_source = True break - if device['Connected'] and audio_source: - + if device["Connected"] and audio_source: pa = PulseAudioUtils() if not pa.connected: self.deferred.append(device) @@ -127,7 +124,7 @@ def on_request_menu_items(self, manager_menu: ManagerDeviceMenu, device: Device) item = create_menuitem(_("Audio Profile"), "audio-card-symbolic") item.props.tooltip_text = _("Select audio profile for PulseAudio") - if not device['Address'] in self.devices: + if not device["Address"] in self.devices: self.query_pa(device, item) else: self.generate_menu(device, item) diff --git a/blueman/plugins/manager/Services.py b/blueman/plugins/manager/Services.py index 4a975e0fa..a54c1befd 100644 --- a/blueman/plugins/manager/Services.py +++ b/blueman/plugins/manager/Services.py @@ -62,7 +62,7 @@ def on_request_menu_items(self, manager_menu: ManagerDeviceMenu, device: Device) item = create_menuitem(instance.name, surface=surface) item.connect( "activate", - lambda _item: manager_menu.disconnect_service(service.device, service.uuid, instance.port) + lambda _item: manager_menu.disconnect_service(service.device, service.uuid, instance.port), ) items.append(DeviceMenuItem(item, DeviceMenuItem.Group.DISCONNECT, service.priority + 100)) item.show() @@ -78,9 +78,12 @@ def on_request_menu_items(self, manager_menu: ManagerDeviceMenu, device: Device) item.show() items.append(DeviceMenuItem(item, DeviceMenuItem.Group.AUTOCONNECT, service.priority)) - for action, priority in set((action, service.priority) - for service in services for action in service.common_actions - if any(plugin in appl.QueryPlugins() for plugin in action.plugins)): + for action, priority in set( + (action, service.priority) + for service in services + for action in service.common_actions + if any(plugin in appl.QueryPlugins() for plugin in action.plugins) + ): item = create_menuitem(action.title, action.icon) items.append(DeviceMenuItem(item, DeviceMenuItem.Group.ACTIONS, priority + 200)) item.show() diff --git a/blueman/plugins/mechanism/Network.py b/blueman/plugins/mechanism/Network.py index 1ddc3b9ff..19556ceaa 100644 --- a/blueman/plugins/mechanism/Network.py +++ b/blueman/plugins/mechanism/Network.py @@ -10,7 +10,7 @@ DHCPDHANDLERS: Dict[str, Type["DHCPHandler"]] = { "DnsMasqHandler": DnsMasqHandler, "DhcpdHandler": DhcpdHandler, - "UdhcpdHandler": UdhcpdHandler + "UdhcpdHandler": UdhcpdHandler, } @@ -20,8 +20,9 @@ def on_load(self) -> None: self.parent.add_method("EnableNetwork", ("s", "s", "s", "b"), "", self._enable_network, pass_sender=True) self.parent.add_method("DisableNetwork", (), "", self._disable_network, pass_sender=True) - def _run_dhcp_client(self, object_path: str, caller: str, ok: Callable[[str], None], - err: Callable[[Union[Exception, int]], None]) -> None: + def _run_dhcp_client( + self, object_path: str, caller: str, ok: Callable[[str], None], err: Callable[[Union[Exception, int]], None] + ) -> None: self.timer.stop() self.confirm_authorization(caller, "org.blueman.dhcp.client") @@ -44,8 +45,9 @@ def dh_connected(_dh: DhcpClient, ip: str) -> None: except Exception as e: err(e) - def _enable_network(self, ip_address: str, netmask: str, dhcp_handler: str, address_changed: bool, - caller: str) -> None: + def _enable_network( + self, ip_address: str, netmask: str, dhcp_handler: str, address_changed: bool, caller: str + ) -> None: self.confirm_authorization(caller, "org.blueman.network.setup") NetConf.apply_settings(ip_address, netmask, DHCPDHANDLERS[dhcp_handler], address_changed) diff --git a/blueman/plugins/mechanism/Ppp.py b/blueman/plugins/mechanism/Ppp.py index 25d5a592e..b19150038 100644 --- a/blueman/plugins/mechanism/Ppp.py +++ b/blueman/plugins/mechanism/Ppp.py @@ -16,8 +16,9 @@ def _ppp_error(self, _ppp: PPPConnection, message: str, err: Callable[[str], Non err(message) self.timer.resume() - def _ppp_connect(self, port: int, number: str, apn: str, caller: str, - ok: Callable[[str], None], err: Callable[[str], None]) -> None: + def _ppp_connect( + self, port: int, number: str, apn: str, caller: str, ok: Callable[[str], None], err: Callable[[str], None] + ) -> None: self.confirm_authorization(caller, "org.blueman.pppd.pppconnect") self.timer.stop() diff --git a/blueman/plugins/mechanism/RfKill.py b/blueman/plugins/mechanism/RfKill.py index 82098560e..45dd5bb7e 100644 --- a/blueman/plugins/mechanism/RfKill.py +++ b/blueman/plugins/mechanism/RfKill.py @@ -3,7 +3,7 @@ from blueman.plugins.MechanismPlugin import MechanismPlugin from blueman.plugins.applet.KillSwitch import RFKILL_TYPE_BLUETOOTH, RFKILL_OP_CHANGE_ALL -if not os.path.exists('/dev/rfkill'): +if not os.path.exists("/dev/rfkill"): raise ImportError("Hardware kill switch not found") @@ -13,5 +13,5 @@ def on_load(self) -> None: def _set_rfkill_state(self, state: bool, caller: str) -> None: self.confirm_authorization(caller, "org.blueman.rfkill.setstate") - with open('/dev/rfkill', 'r+b', buffering=0) as f: + with open("/dev/rfkill", "r+b", buffering=0) as f: f.write(struct.pack("IBBBB", 0, RFKILL_TYPE_BLUETOOTH, RFKILL_OP_CHANGE_ALL, (0 if state else 1), 0)) diff --git a/blueman/plugins/mechanism/Rfcomm.py b/blueman/plugins/mechanism/Rfcomm.py index 870b58120..d0f2653b5 100644 --- a/blueman/plugins/mechanism/Rfcomm.py +++ b/blueman/plugins/mechanism/Rfcomm.py @@ -14,7 +14,7 @@ def _open_rfcomm(self, port_id: int) -> None: subprocess.Popen([RFCOMM_WATCHER_PATH, f"/dev/rfcomm{port_id:d}"]) def _close_rfcomm(self, port_id: int) -> None: - out, err = subprocess.Popen(['ps', '-e', 'o', 'pid,args'], stdout=subprocess.PIPE).communicate() + out, err = subprocess.Popen(["ps", "-e", "o", "pid,args"], stdout=subprocess.PIPE).communicate() for line in out.decode("UTF-8").splitlines(): pid, cmdline = line.split(maxsplit=1) if f"blueman-rfcomm-watcher /dev/rfcomm{port_id:d}" in cmdline: diff --git a/blueman/plugins/services/Network.py b/blueman/plugins/services/Network.py index 99fa04ae8..d387612af 100644 --- a/blueman/plugins/services/Network.py +++ b/blueman/plugins/services/Network.py @@ -12,6 +12,7 @@ from blueman.gui.CommonUi import ErrorDialog import gi + gi.require_version("Gtk", "3.0") from gi.repository import Gio, Gtk, GObject @@ -23,7 +24,6 @@ class Network(ServicePlugin): __plugin_info__ = (_("Network"), "network-workgroup") def on_load(self) -> None: - self._builder = Builder("services-network.ui") self.widget = self._builder.get_widget("network", Gtk.Grid) @@ -32,7 +32,7 @@ def on_load(self) -> None: for iface in netifs: if iface != "lo" and iface != "pan1": logging.info(iface) - ipiface = ipaddress.ip_interface('/'.join(cast(Tuple[str, str], netifs[iface]))) + ipiface = ipaddress.ip_interface("/".join(cast(Tuple[str, str], netifs[iface]))) self.interfaces.append((iface, ipiface)) self.setup_network() @@ -42,14 +42,12 @@ def on_load(self) -> None: logging.exception(e) def on_apply(self) -> None: - if self.on_query_apply_state(): logging.info("network apply") m = Mechanism() nap_enable = self._builder.get_widget("nap-enable", Gtk.CheckButton) if nap_enable.props.active: - if self._builder.get_widget("r_dhcpd", Gtk.RadioButton).props.active: stype = "DhcpdHandler" elif self._builder.get_widget("r_dnsmasq", Gtk.RadioButton).props.active: @@ -61,7 +59,7 @@ def on_apply(self) -> None: try: changed = net_ip.props.text != self.Config["ip4-address"] - m.EnableNetwork('(sssb)', net_ip.props.text, "255.255.255.0", stype, changed) + m.EnableNetwork("(sssb)", net_ip.props.text, "255.255.255.0", stype, changed) if not self.Config["nap-enable"]: self.Config["nap-enable"] = True @@ -84,7 +82,7 @@ def on_apply(self) -> None: def ip_check(self) -> None: entry = self._builder.get_widget("net_ip", Gtk.Entry) try: - nap_ipiface = ipaddress.ip_interface('/'.join((entry.props.text, '255.255.255.0'))) + nap_ipiface = ipaddress.ip_interface("/".join((entry.props.text, "255.255.255.0"))) except (ValueError, ipaddress.AddressValueError): entry.props.secondary_icon_name = "dialog-error" entry.props.secondary_icon_tooltip_text = _("Invalid IP address") @@ -101,7 +99,8 @@ def ip_check(self) -> None: elif nap_ipiface.network == ipiface.network: tooltip_text = _( "IP address overlaps with subnet of interface %s, which has the following configuration %s/%s\n" - "This may cause incorrect network behavior" % (iface, ipiface.ip, ipiface.netmask)) + "This may cause incorrect network behavior" % (iface, ipiface.ip, ipiface.netmask) + ) entry.props.secondary_icon_name = "dialog-warning" entry.props.secondary_icon_tooltip_text = tooltip_text return @@ -203,20 +202,20 @@ def setup_network(self) -> None: def dun_support_toggled(rb: Gtk.RadioButton, x: str) -> None: if rb.props.active and x == "nm": - applet.SetPluginConfig('(sb)', "PPPSupport", False) - applet.SetPluginConfig('(sb)', "NMDUNSupport", True) + applet.SetPluginConfig("(sb)", "PPPSupport", False) + applet.SetPluginConfig("(sb)", "NMDUNSupport", True) elif rb.props.active and x == "blueman": - applet.SetPluginConfig('(sb)', "NMDUNSupport", False) - applet.SetPluginConfig('(sb)', "PPPSupport", True) + applet.SetPluginConfig("(sb)", "NMDUNSupport", False) + applet.SetPluginConfig("(sb)", "PPPSupport", True) def pan_support_toggled(rb: Gtk.RadioButton, x: str) -> None: if rb.props.active and x == "nm": - applet.SetPluginConfig('(sb)', "DhcpClient", False) - applet.SetPluginConfig('(sb)', "NMPANSupport", True) + applet.SetPluginConfig("(sb)", "DhcpClient", False) + applet.SetPluginConfig("(sb)", "NMPANSupport", True) elif rb.props.active and x == "blueman": - applet.SetPluginConfig('(sb)', "NMPANSupport", False) - applet.SetPluginConfig('(sb)', "DhcpClient", True) + applet.SetPluginConfig("(sb)", "NMPANSupport", False) + applet.SetPluginConfig("(sb)", "DhcpClient", True) if "PPPSupport" in active_plugins: rb_dun_blueman.props.active = True diff --git a/blueman/plugins/services/Transfer.py b/blueman/plugins/services/Transfer.py index 260741d4d..d7fa295a2 100644 --- a/blueman/plugins/services/Transfer.py +++ b/blueman/plugins/services/Transfer.py @@ -6,6 +6,7 @@ from blueman.main.DBusProxies import AppletService import gi + gi.require_version("Gtk", "3.0") from gi.repository import Gtk, Gio @@ -14,7 +15,6 @@ class Transfer(ServicePlugin): __plugin_info__ = (_("Transfer"), "folder") def on_load(self) -> None: - self._builder = Builder("services-transfer.ui") self.widget = self._builder.get_widget("transfer", Gtk.Grid) diff --git a/blueman/services/DialupNetwork.py b/blueman/services/DialupNetwork.py index e78c7f03a..dbcba5409 100644 --- a/blueman/services/DialupNetwork.py +++ b/blueman/services/DialupNetwork.py @@ -15,13 +15,8 @@ class DialupNetwork(SerialService): @property def common_actions(self) -> Set[Action]: def open_settings() -> None: - d = GsmSettings(self.device['Address']) + d = GsmSettings(self.device["Address"]) d.run() d.destroy() - return {Action( - _("Dialup Settings"), - "preferences-other", - {'PPPSupport', 'NMDUNSupport'}, - open_settings - )} + return {Action(_("Dialup Settings"), "preferences-other", {"PPPSupport", "NMDUNSupport"}, open_settings)} diff --git a/blueman/services/Functions.py b/blueman/services/Functions.py index 0801c02e7..8b1b101ac 100644 --- a/blueman/services/Functions.py +++ b/blueman/services/Functions.py @@ -19,7 +19,7 @@ def get_service(device: Device, uuid: str) -> Optional[Service]: def get_services(device: Device) -> List[Service]: try: - services = (get_service(device, uuid) for uuid in device['UUIDs']) + services = (get_service(device, uuid) for uuid in device["UUIDs"]) return [service for service in services if service] except BluezDBusException as e: logging.exception(e) diff --git a/blueman/services/meta/NetworkService.py b/blueman/services/meta/NetworkService.py index 0c3ba8ab5..cf831a206 100644 --- a/blueman/services/meta/NetworkService.py +++ b/blueman/services/meta/NetworkService.py @@ -45,11 +45,6 @@ def disconnect( @property def common_actions(self) -> Set[Action]: def renew() -> None: - AppletService().DhcpClient('(s)', self.device.get_object_path()) - - return {Action( - _("Renew IP Address"), - "view-refresh", - {"DhcpClient"}, - renew - )} + AppletService().DhcpClient("(s)", self.device.get_object_path()) + + return {Action(_("Renew IP Address"), "view-refresh", {"DhcpClient"}, renew)} diff --git a/blueman/services/meta/SerialService.py b/blueman/services/meta/SerialService.py index 83fd1960b..4c659986b 100644 --- a/blueman/services/meta/SerialService.py +++ b/blueman/services/meta/SerialService.py @@ -42,8 +42,11 @@ def connected_instances(self) -> List[Instance]: logging.error(e) return [] - return [Instance(_("Serial Port %s") % "rfcomm%d" % dev["id"], dev["id"]) for dev in lst - if dev["dst"] == self.device['Address'] and dev["state"] == "connected"] + return [ + Instance(_("Serial Port %s") % "rfcomm%d" % dev["id"], dev["id"]) + for dev in lst + if dev["dst"] == self.device["Address"] and dev["state"] == "connected" + ] def on_file_changed( self, @@ -51,10 +54,10 @@ def on_file_changed( file: Gio.File, _other_file: Gio.File, event_type: Gio.FileMonitorEvent, - port: int + port: int, ) -> None: if event_type == Gio.FileMonitorEvent.DELETED: - logging.info(f'{file.get_path()} got deleted') + logging.info(f"{file.get_path()} got deleted") if port in self._handlerids: handler_id = self._handlerids.pop(port) monitor.disconnect(handler_id) @@ -69,9 +72,9 @@ def try_replace_root_watcher(self, monitor: Gio.FileMonitor, path: str, port: in if not os.access(path, os.R_OK | os.W_OK): return - logging.info(f'User was granted access to {path}') - logging.info('Replacing root watcher') - Mechanism().CloseRFCOMM('(d)', port) + logging.info(f"User was granted access to {path}") + logging.info("Replacing root watcher") + Mechanism().CloseRFCOMM("(d)", port) subprocess.Popen([RFCOMM_WATCHER_PATH, path]) if port in self._handlerids: handler_id = self._handlerids.pop(port) @@ -82,12 +85,12 @@ def try_replace_root_watcher(self, monitor: Gio.FileMonitor, path: str, port: in def connect( self, reply_handler: Optional[Callable[[int], None]] = None, - error_handler: Optional[Callable[[RFCOMMError], None]] = None + error_handler: Optional[Callable[[RFCOMMError], None]] = None, ) -> bool: # We expect this service to have a reserved UUID uuid = self.short_uuid assert uuid - channel = get_rfcomm_channel(uuid, self.device['Address']) + channel = get_rfcomm_channel(uuid, self.device["Address"]) if channel is None or channel == 0: error = RFCOMMError("Failed to get rfcomm channel") if error_handler: @@ -97,13 +100,14 @@ def connect( raise error try: - port_id = create_rfcomm_device(Adapter(obj_path=self.device["Adapter"])['Address'], self.device["Address"], - channel) + port_id = create_rfcomm_device( + Adapter(obj_path=self.device["Adapter"])["Address"], self.device["Address"], channel + ) filename = f"/dev/rfcomm{port_id:d}" - logging.info('Starting rfcomm watcher as root') - Mechanism().OpenRFCOMM('(d)', port_id) + logging.info("Starting rfcomm watcher as root") + Mechanism().OpenRFCOMM("(d)", port_id) mon = Gio.File.new_for_path(filename).monitor_file(Gio.FileMonitorFlags.NONE) - self._handlerids[port_id] = mon.connect('changed', self.on_file_changed, port_id) + self._handlerids[port_id] = mon.connect("changed", self.on_file_changed, port_id) self.try_replace_root_watcher(mon, filename, port_id) if reply_handler: @@ -119,10 +123,10 @@ def disconnect( self, port_id: int, reply_handler: Optional[Callable[[], None]] = None, - error_handler: Optional[Callable[[str], None]] = None + error_handler: Optional[Callable[[str], None]] = None, ) -> None: try: - Mechanism().CloseRFCOMM('(d)', port_id) + Mechanism().CloseRFCOMM("(d)", port_id) except GLib.Error as e: if error_handler: error_handler(e.message)