From 260432213c33b1c18e5a46dbd94ad33ebbb289d2 Mon Sep 17 00:00:00 2001 From: Sander Sweers Date: Mon, 28 Nov 2022 21:56:37 +0100 Subject: [PATCH 1/3] Also check for cython3 --- configure.ac | 2 +- module/meson.build | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 1c1debad7..25d0d715d 100644 --- a/configure.ac +++ b/configure.ac @@ -58,7 +58,7 @@ AC_SUBST([PYGOBJECT_LIBS]) AC_ARG_VAR([CYTHONEXEC], [Cython compiler]) if test "x$CYTHONEXEC" = "x"; then - AC_PATH_PROG([CYTHONEXEC],[cython]) + AC_PATH_PROGS([CYTHONEXEC],[cython3 cython]) fi AC_SUBST([CYTHONEXEC]) AC_MSG_CHECKING([for cython executable]) diff --git a/module/meson.build b/module/meson.build index f490a3d7e..096ad7c8e 100644 --- a/module/meson.build +++ b/module/meson.build @@ -1,4 +1,4 @@ -cython = find_program('cython', required: true) +cython = find_program('cython', 'cython3' ,required: true) blueman_c = custom_target( 'blueman_c', From 9c9c07bb046424bfe3860d92fc4a61b63dc4a89b Mon Sep 17 00:00:00 2001 From: Sander Sweers Date: Thu, 28 Jul 2022 22:06:52 +0200 Subject: [PATCH 2/3] launch: move constants to the caller --- blueman/Functions.py | 7 ------- blueman/gui/manager/ManagerDeviceList.py | 3 ++- blueman/gui/manager/ManagerMenu.py | 8 +++++--- blueman/main/Manager.py | 9 ++++++--- blueman/plugins/applet/GameControllerWakelock.py | 6 ++++-- blueman/plugins/applet/StandardItems.py | 6 ++++-- blueman/plugins/applet/StatusIcon.py | 7 +++++-- blueman/plugins/applet/TransferService.py | 3 ++- blueman/plugins/manager/Notes.py | 4 +++- 9 files changed, 31 insertions(+), 22 deletions(-) diff --git a/blueman/Functions.py b/blueman/Functions.py index f8ccd9aba..e29cb113b 100644 --- a/blueman/Functions.py +++ b/blueman/Functions.py @@ -37,7 +37,6 @@ import cairo from blueman.main.DBusProxies import AppletService, DBusProxyFailed -from blueman.Constants import BIN_DIR import gi gi.require_version("Gtk", "3.0") @@ -87,7 +86,6 @@ def check_bluetooth_status(message: str, exitfunc: Callable[[], Any]) -> None: def launch( cmd: str, paths: Optional[Iterable[str]] = None, - system: bool = False, icon_name: Optional[str] = None, name: str = "blueman", sn: bool = True, @@ -113,11 +111,6 @@ def launch( env = os.environ env["BLUEMAN_EVENT_TIME"] = str(timestamp) - if not system: - cmd = os.path.join(BIN_DIR, cmd) - else: - cmd = os.path.expanduser(cmd) - if paths: files: Optional[List[Gio.File]] = [Gio.File.new_for_commandline_arg(p) for p in paths] else: diff --git a/blueman/gui/manager/ManagerDeviceList.py b/blueman/gui/manager/ManagerDeviceList.py index 0651f4385..7c23284b4 100644 --- a/blueman/gui/manager/ManagerDeviceList.py +++ b/blueman/gui/manager/ManagerDeviceList.py @@ -12,6 +12,7 @@ from blueman.DeviceClass import get_minor_class, get_major_class, gatt_appearance_to_name from blueman.gui.GenericList import ListDataDict from blueman.gui.manager.ManagerDeviceMenu import ManagerDeviceMenu +from blueman.Constants import BIN_DIR from blueman.Functions import launch from blueman.Sdp import ServiceUUID, OBEX_OBJPUSH_SVCLASS_ID from blueman.gui.GtkAnimation import TreeRowFade, CellFade, AnimBase @@ -161,7 +162,7 @@ def drag_recv(self, _widget: Gtk.Widget, context: Gdk.DragContext, x: int, y: in device = self.get(tree_iter, "device")["device"] command = f"blueman-sendto --device={device['Address']}" - launch(command, paths=uris, name=_("File Sender")) + launch(os.path.join(BIN_DIR, command), paths=uris, name=_("File Sender")) context.finish(True, False, time) else: context.finish(False, False, time) diff --git a/blueman/gui/manager/ManagerMenu.py b/blueman/gui/manager/ManagerMenu.py index 45cbeed62..854d72198 100644 --- a/blueman/gui/manager/ManagerMenu.py +++ b/blueman/gui/manager/ManagerMenu.py @@ -1,5 +1,6 @@ from gettext import gettext as _ import logging +import os from typing import Dict, Tuple, TYPE_CHECKING, Any, Optional, Sequence from blueman.bluez.Adapter import Adapter @@ -8,7 +9,7 @@ from blueman.gui.manager.ManagerDeviceList import ManagerDeviceList from blueman.gui.manager.ManagerDeviceMenu import ManagerDeviceMenu from blueman.gui.CommonUi import show_about_dialog -from blueman.Constants import WEBSITE +from blueman.Constants import WEBSITE, BIN_DIR from blueman.Functions import create_menuitem, launch, adapter_path_to_name import gi @@ -46,7 +47,7 @@ def __init__(self, blueman: "Blueman"): report_item.show() help_menu.append(report_item) - report_item.connect("activate", lambda x: launch(f"xdg-open {WEBSITE}/issues")) + report_item.connect("activate", lambda x: launch(os.path.join(BIN_DIR, f"xdg-open {WEBSITE}/issues"))) sep = Gtk.SeparatorMenuItem() sep.show() @@ -130,7 +131,8 @@ def __init__(self, blueman: "Blueman"): item_plugins.connect('activate', self._on_plugin_dialog_activate) item_services = create_menuitem(_("_Local Services") + "…", "document-properties-symbolic") - item_services.connect('activate', lambda *args: launch("blueman-services", name=_("Service Preferences"))) + item_services.connect('activate', lambda *args: launch(os.path.join(BIN_DIR, "blueman-services"), + name=_("Service Preferences"))) view_menu.append(item_services) item_services.show() diff --git a/blueman/main/Manager.py b/blueman/main/Manager.py index 73cb0868f..3c4abe536 100644 --- a/blueman/main/Manager.py +++ b/blueman/main/Manager.py @@ -1,5 +1,6 @@ import logging import signal +import os from gettext import gettext as _ from typing import Optional, Any, Tuple @@ -7,6 +8,7 @@ from blueman.bluez.Device import Device from blueman.bluez.Manager import Manager from blueman.bluez.errors import DBusNoSuchAdapterError +from blueman.Constants import BIN_DIR from blueman.Functions import * from blueman.gui.manager.ManagerDeviceList import ManagerDeviceList from blueman.gui.manager.ManagerToolbar import ManagerToolbar @@ -264,8 +266,8 @@ def error_handler(e: Exception) -> None: device.pair(error_handler=error_handler) @staticmethod - def adapter_properties() -> None: - launch("blueman-adapters", name=_("Adapter Preferences")) + def adapter_properties(self) -> None: + launch(os.path.join(BIN_DIR, "blueman-adapters"), name=_("Adapter Preferences")) @staticmethod def toggle_trust(device: Device) -> None: @@ -280,7 +282,8 @@ def send(self, device: Device) -> None: assert adapter - command = f"blueman-sendto --source={adapter['Address']} --device={device['Address']}" + command = os.path.join(self.settings.bindir, f"blueman-sendto --source={adapter['Address']}" + f" --device={device['Address']}") launch(command, name=_("File Sender")) def remove(self, device: Device) -> None: diff --git a/blueman/plugins/applet/GameControllerWakelock.py b/blueman/plugins/applet/GameControllerWakelock.py index 693d40078..a30d9eb5c 100644 --- a/blueman/plugins/applet/GameControllerWakelock.py +++ b/blueman/plugins/applet/GameControllerWakelock.py @@ -1,8 +1,10 @@ from gettext import gettext as _ import logging +import os from typing import Any from blueman.bluez.Device import Device +from blueman.Constants import BIN_DIR from blueman.Functions import launch from blueman.plugins.AppletPlugin import AppletPlugin from blueman.plugins.errors import UnsupportedPlatformError @@ -59,7 +61,7 @@ def xdg_screensaver(self, action: str) -> None: elif self.wake_lock > 1: self.wake_lock -= 1 else: - ret = launch(command, sn=False) + ret = launch(os.path.join(BIN_DIR, command), sn=False) if ret: self.wake_lock -= 1 else: @@ -69,7 +71,7 @@ def xdg_screensaver(self, action: str) -> None: if self.wake_lock >= 1: self.wake_lock += 1 else: - ret = launch(command, sn=False) + ret = launch(os.path.join(BIN_DIR, command), sn=False) if ret: self.wake_lock += 1 else: diff --git a/blueman/plugins/applet/StandardItems.py b/blueman/plugins/applet/StandardItems.py index c86d18ec4..9302ade85 100644 --- a/blueman/plugins/applet/StandardItems.py +++ b/blueman/plugins/applet/StandardItems.py @@ -1,6 +1,8 @@ from gettext import gettext as _ from typing import Optional +import os +from blueman.Constants import BIN_DIR from blueman.Functions import launch from blueman.main.DBusProxies import ManagerService from blueman.plugins.AppletPlugin import AppletPlugin @@ -79,10 +81,10 @@ def on_devices(self) -> None: m.startstop() def on_adapters(self) -> None: - launch("blueman-adapters", name=_("Adapter Preferences")) + launch(os.path.join(BIN_DIR, "blueman-adapters"), name=_("Adapter Preferences")) def on_local_services(self) -> None: - launch("blueman-services", name=_("Service Preferences")) + launch(os.path.join(BIN_DIR, "blueman-services"), name=_("Service Preferences")) def on_about(self) -> None: about = show_about_dialog("Blueman " + _("applet"), run=False) diff --git a/blueman/plugins/applet/StatusIcon.py b/blueman/plugins/applet/StatusIcon.py index 6c8b60baf..890d9ed67 100644 --- a/blueman/plugins/applet/StatusIcon.py +++ b/blueman/plugins/applet/StatusIcon.py @@ -1,7 +1,10 @@ from gettext import gettext as _ from typing import Optional, Tuple, List +import os from gi.repository import GObject, GLib, Gio + +from blueman.Constants import BIN_DIR from blueman.Functions import launch from blueman.main.PluginManager import PluginManager from blueman.plugins.AppletPlugin import AppletPlugin @@ -103,7 +106,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(os.path.join(BIN_DIR, 'blueman-tray'), icon_name='blueman', sn=False) def _on_plugins_changed(self, _plugins: PluginManager, _name: str) -> None: implementations = self._get_status_icon_implementations() @@ -111,7 +114,7 @@ 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(os.path.join(BIN_DIR, 'blueman-tray'), icon_name='blueman', sn=False) def _get_status_icon_implementations(self) -> List[str]: return [implementation for implementation, _ in sorted( diff --git a/blueman/plugins/applet/TransferService.py b/blueman/plugins/applet/TransferService.py index 959469161..72117bfd0 100644 --- a/blueman/plugins/applet/TransferService.py +++ b/blueman/plugins/applet/TransferService.py @@ -10,6 +10,7 @@ from blueman.bluez.obex.Manager import Manager from blueman.bluez.obex.Transfer import Transfer from blueman.bluez.obex.Session import Session +from blueman.Constants import BIN_DIR from blueman.Functions import launch from blueman.gui.Notification import Notification, _NotificationBubble, _NotificationDialog from blueman.main.Applet import BluemanApplet @@ -271,7 +272,7 @@ def _add_open(self, n: NotificationType, name: str, path: str) -> None: def on_open(_action: str) -> None: self._notification = None logging.info("open") - launch("xdg-open", paths=[path], system=True) + launch(os.path.expanduser("xdg-open"), paths=[path]) n.add_action("open", name, on_open) diff --git a/blueman/plugins/manager/Notes.py b/blueman/plugins/manager/Notes.py index 0838b400c..7c4ff3095 100644 --- a/blueman/plugins/manager/Notes.py +++ b/blueman/plugins/manager/Notes.py @@ -3,6 +3,8 @@ from tempfile import NamedTemporaryFile from typing import List + +from blueman.Constants import BIN_DIR from blueman.Functions import create_menuitem, launch from blueman.bluez.Device import Device from blueman.gui.manager.ManagerDeviceMenu import MenuItemsProvider, ManagerDeviceMenu, DeviceMenuItem @@ -33,7 +35,7 @@ def send_note_cb(dialog: Gtk.Dialog, response_id: int, device_address: str, text 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]) + launch(os.path.join(BIN_DIR, f"blueman-sendto --delete --device={device_address}"), paths=[tempfile.name]) def send_note(device: Device, parent: Gtk.Window) -> None: From 7b8f714d35c9a4981afef61f423dda0fd9827926 Mon Sep 17 00:00:00 2001 From: Sander Sweers Date: Thu, 28 Jul 2022 22:50:41 +0200 Subject: [PATCH 3/3] Replace generated Constants.py with a simple json file --- apps/blueman-adapters.in | 18 +++++++++++--- apps/blueman-applet.in | 18 +++++++++++--- apps/blueman-manager.in | 16 +++++++++++-- apps/blueman-mechanism.in | 19 +++++++++++++-- apps/blueman-sendto.in | 19 +++++++++++++-- apps/blueman-services.in | 16 +++++++++++-- blueman/Constants.py.in | 18 -------------- blueman/Functions.py | 17 +++++++++++++ blueman/Makefile.am | 5 ---- blueman/Service.py | 8 +++++-- blueman/config/Settings.py | 15 ++++++++++++ blueman/gui/CommonUi.py | 19 ++++++++------- blueman/gui/DeviceList.py | 7 +++--- blueman/gui/manager/ManagerDeviceList.py | 3 +-- blueman/gui/manager/ManagerMenu.py | 11 +++++---- blueman/main/Adapter.py | 5 +++- blueman/main/Applet.py | 4 +++- blueman/main/Manager.py | 8 +++---- blueman/main/MechanismApplication.py | 15 +++++++----- blueman/main/NetConf.py | 24 ++++++++++++------- blueman/main/PluginManager.py | 2 +- blueman/main/Sendto.py | 3 ++- blueman/main/Services.py | 6 +++-- blueman/main/applet/BluezAgent.py | 4 +++- blueman/plugins/AppletPlugin.py | 4 +++- blueman/plugins/ManagerPlugin.py | 4 +++- blueman/plugins/MechanismPlugin.py | 4 +++- blueman/plugins/ServicePlugin.py | 4 +++- blueman/plugins/applet/AuthAgent.py | 2 +- blueman/plugins/applet/AutoConnect.py | 5 ++-- blueman/plugins/applet/DisconnectItems.py | 5 ++-- .../plugins/applet/GameControllerWakelock.py | 5 ++-- blueman/plugins/applet/NetUsage.py | 2 +- blueman/plugins/applet/StandardItems.py | 5 ++-- blueman/plugins/applet/StatusIcon.py | 5 ++-- blueman/plugins/applet/TransferService.py | 1 - blueman/plugins/manager/Notes.py | 15 ++++++------ blueman/plugins/manager/Services.py | 2 +- blueman/plugins/mechanism/Rfcomm.py | 3 +-- blueman/services/Functions.py | 13 ++++++---- blueman/services/meta/NetworkService.py | 9 ++++--- blueman/services/meta/SerialService.py | 12 ++++++---- configure.ac | 6 ++--- data/configs/Makefile.am | 1 + data/configs/settings.json.in | 12 ++++++++++ meson.build | 13 ++++++---- po/POTFILES.in | 1 - 47 files changed, 277 insertions(+), 136 deletions(-) delete mode 100644 blueman/Constants.py.in create mode 100644 blueman/config/Settings.py create mode 100644 data/configs/settings.json.in diff --git a/apps/blueman-adapters.in b/apps/blueman-adapters.in index 1be06ddc9..a7c5480fc 100755 --- a/apps/blueman-adapters.in +++ b/apps/blueman-adapters.in @@ -6,21 +6,32 @@ import gettext resource_file = "@pkgdatadir@/blueman.gresource" +settings_path = "@pkgdatadir@/settings.json" +src_paths = {} + # 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 os.environ["GSETTINGS_SCHEMA_DIR"] = os.path.join(_dirname, "data") resource_file = os.path.join(_dirname, "data", "blueman.gresource") + settings_path = os.path.join(_dirname, "data", "configs", "settings.json") + src_paths.update({ + "bindir": os.path.join(_dirname, "apps"), + "rfcomm_watcher_path": os.path.join(_dirname, "apps") + }) gettext.textdomain("@GETTEXT_PACKAGE@") -from blueman.Functions import create_parser, create_logger, set_proc_title +from blueman.Functions import create_parser, create_logger, set_proc_title, load_json +from blueman.config.Settings import BluemanSettings from blueman.main.Adapter import BluemanAdapters +settings = load_json(settings_path, src_paths) +bm_settings = BluemanSettings(**settings) if __name__ == '__main__': - parser = parser = create_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") args = parser.parse_args() @@ -42,5 +53,6 @@ if __name__ == '__main__': set_proc_title() - app = blueman_adapters = BluemanAdapters(args.adapter, args.socket_id, resource_file) + app = blueman_adapters = BluemanAdapters(args.adapter, args.socket_id, resource_file, bm_settings) + app.run() diff --git a/apps/blueman-applet.in b/apps/blueman-applet.in index 937e10ca2..4de235f90 100755 --- a/apps/blueman-applet.in +++ b/apps/blueman-applet.in @@ -5,18 +5,30 @@ import logging import gettext resource_file = "@pkgdatadir@/blueman.gresource" +settings_path = os.path.join("@settings_path@", "settings.json") +src_paths = {} + # support running uninstalled -_dirname = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) +_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") resource_file = os.path.join(_dirname, "data", "blueman.gresource") + settings_path = os.path.join(_dirname, "data", "configs", "settings.json") + src_paths.update({ + "bindir": os.path.join(_dirname, "apps"), + "rfcomm_watcher_path": os.path.join(_dirname, "apps") + }) + gettext.textdomain("@GETTEXT_PACKAGE@") -from blueman.Functions import create_logger, create_parser, set_proc_title from blueman.main.Applet import BluemanApplet +from blueman.config.Settings import BluemanSettings +from blueman.Functions import set_proc_title, create_parser, create_logger, load_json +settings = load_json(settings_path, src_paths) +bm_settings = BluemanSettings(**settings) if __name__ == '__main__': parser = create_parser() @@ -38,5 +50,5 @@ if __name__ == '__main__': create_logger(log_level, "blueman-applet", syslog=args.syslog) set_proc_title() - app = BluemanApplet(resource_file) + app = BluemanApplet(resource_file, bm_settings) app.run() diff --git a/apps/blueman-manager.in b/apps/blueman-manager.in index d7994f581..585a7ea87 100755 --- a/apps/blueman-manager.in +++ b/apps/blueman-manager.in @@ -5,18 +5,30 @@ import logging import gettext resource_file = "@pkgdatadir@/blueman.gresource" +settings_path = os.path.join("@settings_path@", "settings.json") +src_paths = {} + # 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 os.environ["GSETTINGS_SCHEMA_DIR"] = os.path.join(_dirname, "data") resource_file = os.path.join(_dirname, "data", "blueman.gresource") + settings_path = os.path.join(_dirname, "data", "configs", "settings.json") + src_paths.update({ + "bindir": os.path.join(_dirname, "apps"), + "rfcomm_watcher_path": os.path.join(_dirname, "apps") + }) + gettext.textdomain("@GETTEXT_PACKAGE@") from blueman.main.Manager import Blueman -from blueman.Functions import set_proc_title, create_parser, create_logger +from blueman.config.Settings import BluemanSettings +from blueman.Functions import set_proc_title, create_parser, create_logger, load_json +settings = load_json(settings_path, src_paths) +bm_settings = BluemanSettings(**settings) if __name__ == '__main__': parser = create_parser() @@ -37,6 +49,6 @@ if __name__ == '__main__': create_logger(log_level, "blueman-manager", syslog=args.syslog) - app = Blueman(resource_file) + app = Blueman(resource_file, bm_settings) set_proc_title() app.run() diff --git a/apps/blueman-mechanism.in b/apps/blueman-mechanism.in index f369090ee..0e1a68590 100755 --- a/apps/blueman-mechanism.in +++ b/apps/blueman-mechanism.in @@ -5,13 +5,28 @@ import logging from blueman.main.MechanismApplication import MechanismApplication +resource_file = "@pkgdatadir@/blueman.gresource" +settings_path = os.path.join("@settings_path@", "settings.json") +src_paths = {} + # 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 os.environ["GSETTINGS_SCHEMA_DIR"] = os.path.join(_dirname, "data") + resource_file = os.path.join(_dirname, "data", "blueman.gresource") + settings_path = os.path.join(_dirname, "data", "configs", "settings.json") + src_paths.update({ + "bindir": os.path.join(_dirname, "apps"), + "rfcomm_watcher_path": os.path.join(_dirname, "apps") + }) + + +from blueman.config.Settings import BluemanSettings +from blueman.Functions import set_proc_title, create_parser, create_logger, load_json -from blueman.Functions import set_proc_title, create_logger, create_parser +settings = load_json(settings_path, src_paths) +bm_settings = BluemanSettings(**settings) class StreamToLogger: @@ -65,5 +80,5 @@ logging.info("Starting blueman-mechanism") os.environ["PATH"] = "/usr/bin:/bin:/usr/sbin:/sbin" set_proc_title() -app = MechanismApplication(args.stoptimer) +app = MechanismApplication(args.stoptimer, bm_settings) app.run() diff --git a/apps/blueman-sendto.in b/apps/blueman-sendto.in index 01551ace7..8c5a75f69 100755 --- a/apps/blueman-sendto.in +++ b/apps/blueman-sendto.in @@ -12,12 +12,21 @@ gi.require_version("Gdk", "3.0") from gi.repository import Gtk, Gio resource_file = "@pkgdatadir@/blueman.gresource" +settings_path = os.path.join("@settings_path@", "settings.json") +src_paths = {} + # 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 os.environ["GSETTINGS_SCHEMA_DIR"] = os.path.join(_dirname, "data") resource_file = os.path.join(_dirname, "data", "blueman.gresource") + settings_path = os.path.join(_dirname, "data", "configs", "settings.json") + src_paths.update({ + "bindir": os.path.join(_dirname, "apps"), + "rfcomm_watcher_path": os.path.join(_dirname, "apps") + }) + _ = gettext.gettext gettext.textdomain("@GETTEXT_PACKAGE@") @@ -27,8 +36,11 @@ from blueman.Functions import ( set_proc_title, create_parser, create_logger, - bmexit + bmexit, + load_json ) +from blueman.config.Settings import BluemanSettings +from blueman.main.Config import Config from blueman.main.Sendto import Sender from blueman.bluez.Manager import Manager from blueman.bluez.errors import DBusNoSuchAdapterError @@ -37,6 +49,9 @@ from blueman.gui.DeviceSelectorDialog import DeviceSelectorDialog # Workaround introspection bug, gnome bug 622084 signal.signal(signal.SIGINT, signal.SIG_DFL) +settings = load_json(settings_path, src_paths) +bm_settings = BluemanSettings(**settings) + class SendTo: def __init__(self, parsed_args): @@ -98,7 +113,7 @@ class SendTo: logging.warning("No files to send") bmexit() - sender = Sender(self.device, self.adapter_path, self.files) + sender = Sender(self.device, self.adapter_path, self.files, bm_settings) def on_result(sender, res): Gtk.main_quit() diff --git a/apps/blueman-services.in b/apps/blueman-services.in index e674ac87a..991666edf 100755 --- a/apps/blueman-services.in +++ b/apps/blueman-services.in @@ -7,19 +7,31 @@ import signal import gettext resource_file = "@pkgdatadir@/blueman.gresource" +settings_path = os.path.join("@settings_path@", "settings.json") +src_paths = {} + # 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 os.environ["GSETTINGS_SCHEMA_DIR"] = os.path.join(_dirname, "data") resource_file = os.path.join(_dirname, "data", "blueman.gresource") + settings_path = os.path.join(_dirname, "data", "configs", "settings.json") + src_paths.update({ + "bindir": os.path.join(_dirname, "apps"), + "rfcomm_watcher_path": os.path.join(_dirname, "apps") + }) + _ = gettext.gettext gettext.textdomain("@GETTEXT_PACKAGE@") -from blueman.Functions import set_proc_title, create_logger, create_parser +from blueman.Functions import set_proc_title, create_logger, create_parser, load_json +from blueman.config.Settings import BluemanSettings from blueman.main.Services import BluemanServices +settings = load_json(settings_path, src_paths) +bm_settings = BluemanSettings(**settings) if __name__ == '__main__': parser = create_parser() @@ -41,5 +53,5 @@ if __name__ == '__main__': create_logger(log_level, "blueman-services", syslog=args.syslog) set_proc_title() - app = BluemanServices(resource_file) + app = BluemanServices(resource_file, bm_settings) app.run() diff --git a/blueman/Constants.py.in b/blueman/Constants.py.in deleted file mode 100644 index 6bf06e51f..000000000 --- a/blueman/Constants.py.in +++ /dev/null @@ -1,18 +0,0 @@ -__all__ = ["VERSION", "PACKAGE", "WEBSITE", "BIN_DIR"] - -VERSION = "@VERSION@" -PACKAGE = "@PACKAGE@" -WEBSITE = "https://github.com/blueman-project/blueman" -PREFIX = "@prefix@" -BIN_DIR = "@BINDIR@" -LOCALEDIR = "@LOCALEDIR@" -DHCP_CONFIG_FILE = "@dhconfig@" -POLKIT = @POLKIT@ -GETTEXT_PACKAGE = "@GETTEXT_PACKAGE@" -RFCOMM_WATCHER_PATH = "@LIBEXECDIR@/blueman-rfcomm-watcher" - -import os - -if 'BLUEMAN_SOURCE' in os.environ: - _dirname = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) - BIN_DIR = os.path.join(_dirname, 'apps') diff --git a/blueman/Functions.py b/blueman/Functions.py index e29cb113b..d3d6417fe 100644 --- a/blueman/Functions.py +++ b/blueman/Functions.py @@ -33,6 +33,7 @@ import socket import array import time +import json import cairo @@ -322,3 +323,19 @@ def get_local_interfaces() -> Dict[str, Tuple[str, Optional[str]]]: def bmexit(msg: Optional[Union[str, int]] = None) -> None: raise SystemExit(msg) + + +def load_json(json_path: str, updates: Dict[str, str]) -> dict[str, Union[str, bool]]: + settings_dict = {} + try: + with open(json_path) as f: + data = json.load(f) + settings_dict.update(data) + settings_dict.update(updates) + return settings_dict + except json.JSONDecodeError: + logging.error("Could not decode json file.") + return {} + except FileNotFoundError: + logging.error("Settings file not found. Reinstall blueman.") + return {} diff --git a/blueman/Makefile.am b/blueman/Makefile.am index 1dfb48766..a4e70143a 100644 --- a/blueman/Makefile.am +++ b/blueman/Makefile.am @@ -8,7 +8,6 @@ SUBDIRS = \ bluemandir = $(pythondir)/blueman blueman_PYTHON = \ - Constants.py \ DeviceClass.py \ Functions.py \ Sdp.py \ @@ -18,14 +17,10 @@ blueman_PYTHON = \ __init__.py CLEANFILES = \ - Constants.py \ $(BUILT_SOURCES) DISTCLEANFILES = \ $(CLEANFILES) - -EXTRA_DIST = \ - Constants.py.in clean-local: find . \( -name \*.pyc -o -name \*.pyo -o -name __pycache__ \) -prune -exec rm -rf {} + diff --git a/blueman/Service.py b/blueman/Service.py index 0c92850a3..5a250a678 100644 --- a/blueman/Service.py +++ b/blueman/Service.py @@ -1,9 +1,12 @@ from abc import ABC, abstractmethod -from typing import Optional, Callable, List, Set, Collection +from typing import Optional, Callable, List, Set, Collection, TYPE_CHECKING from blueman.Sdp import ServiceUUID from blueman.bluez.Device import Device +if TYPE_CHECKING: + from blueman.config.Settings import BluemanSettings + class Instance: def __init__(self, name: str, port: int = 0) -> None: @@ -31,9 +34,10 @@ class Service(ABC): __icon__: str __priority__: int - def __init__(self, device: Device, uuid: str): + def __init__(self, device: Device, uuid: str, settings: "BluemanSettings"): self.__device = device self.__uuid = uuid + self._settings = settings @property def name(self) -> str: diff --git a/blueman/config/Settings.py b/blueman/config/Settings.py new file mode 100644 index 000000000..733d98ac9 --- /dev/null +++ b/blueman/config/Settings.py @@ -0,0 +1,15 @@ +from dataclasses import dataclass + + +@dataclass +class BluemanSettings: + version: str + package: str + website: str + prefix: str + bindir: str + localedir: str + dhcp_config_file: str + polkit: bool + gettext_package: str + rfcomm_watcher_path: str diff --git a/blueman/gui/CommonUi.py b/blueman/gui/CommonUi.py index cbdec40ae..6b188dd1c 100644 --- a/blueman/gui/CommonUi.py +++ b/blueman/gui/CommonUi.py @@ -2,13 +2,12 @@ from gettext import gettext as _ from typing import Optional, overload, TYPE_CHECKING -from blueman.Constants import WEBSITE, VERSION - import gi gi.require_version("Gtk", "3.0") from gi.repository import Gtk if TYPE_CHECKING: + from blueman.config.Settings import BluemanSettings from typing_extensions import Literal @@ -40,16 +39,18 @@ def __init__(self, markup: str, secondary_markup: Optional[str] = None, excp: Op @overload -def show_about_dialog(app_name: str, run: "Literal[True]" = True, parent: Optional[Gtk.Window] = None) -> None: +def show_about_dialog(app_name: str, settings: "BluemanSettings", run: "Literal[True]" = True, + parent: Optional[Gtk.Window] = None) -> None: ... @overload -def show_about_dialog(app_name: str, run: "Literal[False]", parent: Optional[Gtk.Window] = None) -> Gtk.AboutDialog: +def show_about_dialog(app_name: str, settings: "BluemanSettings", run: "Literal[False]", + parent: Optional[Gtk.Window] = None) -> Gtk.AboutDialog: ... -def show_about_dialog(app_name: str, run: bool = True, parent: Optional[Gtk.Window] = None +def show_about_dialog(app_name: str, settings: "BluemanSettings", run: bool = True, parent: Optional[Gtk.Window] = None, ) -> Optional[Gtk.AboutDialog]: about = Gtk.AboutDialog() about.set_transient_for(parent) @@ -57,19 +58,19 @@ def show_about_dialog(app_name: str, run: bool = True, parent: Optional[Gtk.Wind # on KDE it shows a close button which is unconnected. about.connect("response", lambda x, y: about.destroy()) about.set_name(app_name) - about.set_version(VERSION) + about.set_version(settings.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_website(WEBSITE) - about.set_website_label(WEBSITE) + about.set_website(settings.website) + about.set_website_label(settings.website) about.set_icon_name('blueman') about.set_logo_icon_name('blueman') about.set_authors(['Valmantas Palikša ', 'Tadas Dailyda ', - f'{WEBSITE}/graphs/contributors' + f'{settings.website}/graphs/contributors' ]) if run: about.show() diff --git a/blueman/gui/DeviceList.py b/blueman/gui/DeviceList.py index 0685a9ed6..6d2e8fee8 100644 --- a/blueman/gui/DeviceList.py +++ b/blueman/gui/DeviceList.py @@ -40,8 +40,8 @@ class DeviceList(GenericList): '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 = [] @@ -185,7 +185,8 @@ def set_adapter(self, adapter: Optional[str] = None) -> None: self.stop_discovery() self.emit("adapter-property-changed", self.Adapter, ("Discovering", False)) - adapter = adapter_path_to_name(adapter) + logging.debug(f"{adapter} {repr(adapter)}") + adapter = adapter_path_to_name(adapter) if adapter else None logging.debug(f"Setting adapter to: {adapter}") diff --git a/blueman/gui/manager/ManagerDeviceList.py b/blueman/gui/manager/ManagerDeviceList.py index 7c23284b4..0d85724cc 100644 --- a/blueman/gui/manager/ManagerDeviceList.py +++ b/blueman/gui/manager/ManagerDeviceList.py @@ -12,7 +12,6 @@ from blueman.DeviceClass import get_minor_class, get_major_class, gatt_appearance_to_name from blueman.gui.GenericList import ListDataDict from blueman.gui.manager.ManagerDeviceMenu import ManagerDeviceMenu -from blueman.Constants import BIN_DIR from blueman.Functions import launch from blueman.Sdp import ServiceUUID, OBEX_OBJPUSH_SVCLASS_ID from blueman.gui.GtkAnimation import TreeRowFade, CellFade, AnimBase @@ -162,7 +161,7 @@ def drag_recv(self, _widget: Gtk.Widget, context: Gdk.DragContext, x: int, y: in device = self.get(tree_iter, "device")["device"] command = f"blueman-sendto --device={device['Address']}" - launch(os.path.join(BIN_DIR, command), paths=uris, name=_("File Sender")) + launch(os.path.join(self.Blueman.settings.bindir, command), paths=uris, name=_("File Sender")) context.finish(True, False, time) else: context.finish(False, False, time) diff --git a/blueman/gui/manager/ManagerMenu.py b/blueman/gui/manager/ManagerMenu.py index 854d72198..2c960abbb 100644 --- a/blueman/gui/manager/ManagerMenu.py +++ b/blueman/gui/manager/ManagerMenu.py @@ -9,7 +9,6 @@ from blueman.gui.manager.ManagerDeviceList import ManagerDeviceList from blueman.gui.manager.ManagerDeviceMenu import ManagerDeviceMenu from blueman.gui.CommonUi import show_about_dialog -from blueman.Constants import WEBSITE, BIN_DIR from blueman.Functions import create_menuitem, launch, adapter_path_to_name import gi @@ -47,7 +46,8 @@ def __init__(self, blueman: "Blueman"): report_item.show() help_menu.append(report_item) - report_item.connect("activate", lambda x: launch(os.path.join(BIN_DIR, f"xdg-open {WEBSITE}/issues"))) + website_cmd = os.path.join(blueman.settings.bindir, f"xdg-open {blueman.settings.website}/issues") + report_item.connect("activate", lambda x: launch(website_cmd)) sep = Gtk.SeparatorMenuItem() sep.show() @@ -60,7 +60,8 @@ 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'), blueman.settings, + parent=window)) view_menu = Gtk.Menu() self.item_view.set_submenu(view_menu) @@ -130,9 +131,9 @@ def __init__(self, blueman: "Blueman"): view_menu.append(item_plugins) item_plugins.connect('activate', self._on_plugin_dialog_activate) + services_cmd = os.path.join(blueman.settings.bindir, "blueman-services") item_services = create_menuitem(_("_Local Services") + "…", "document-properties-symbolic") - item_services.connect('activate', lambda *args: launch(os.path.join(BIN_DIR, "blueman-services"), - name=_("Service Preferences"))) + item_services.connect('activate', lambda *args: launch(services_cmd, name=_("Service Preferences"))) view_menu.append(item_services) item_services.show() diff --git a/blueman/main/Adapter.py b/blueman/main/Adapter.py index 8b3c99663..9989e6d31 100644 --- a/blueman/main/Adapter.py +++ b/blueman/main/Adapter.py @@ -5,6 +5,7 @@ import signal from typing import Dict, TYPE_CHECKING, Optional, Any +from blueman.config.Settings import BluemanSettings from blueman.Functions import * from blueman.bluez.Manager import Manager from blueman.bluez.Adapter import Adapter @@ -31,7 +32,8 @@ class Tab(TypedDict): class BluemanAdapters(Gtk.Application): - def __init__(self, selected_hci_dev: Optional[str], socket_id: Optional[int], resource_file: str) -> None: + def __init__(self, selected_hci_dev: Optional[str], socket_id: Optional[int], + resource_file: str, settings: BluemanSettings) -> None: super().__init__(application_id="org.blueman.Adapters") def do_quit(_: object) -> bool: @@ -46,6 +48,7 @@ def do_quit(_: object) -> bool: Gio.Resource._register(gresource) Gtk.IconTheme.get_default().add_resource_path("/org/blueman/") + self.settings = settings self.socket_id = socket_id self.selected_hci_dev = selected_hci_dev diff --git a/blueman/main/Applet.py b/blueman/main/Applet.py index 6ca45d6d8..9bb850759 100644 --- a/blueman/main/Applet.py +++ b/blueman/main/Applet.py @@ -6,6 +6,7 @@ gi.require_version("Gtk", "3.0") from gi.repository import Gio, GLib, Gtk +from blueman.config.Settings import BluemanSettings from blueman.bluez.Manager import Manager from blueman.bluez.Adapter import AnyAdapter from blueman.bluez.Device import AnyDevice @@ -22,11 +23,12 @@ class BluemanApplet(Gio.Application): - def __init__(self, resource_file: str) -> None: + def __init__(self, resource_file: str, settings: BluemanSettings) -> None: super().__init__(application_id="org.blueman.Applet", flags=Gio.ApplicationFlags.FLAGS_NONE) gresource = Gio.Resource.load(resource_file) Gio.Resource._register(gresource) Gtk.IconTheme.get_default().add_resource_path("/org/blueman") + self.settings = settings def do_quit(_: object) -> bool: self.quit() diff --git a/blueman/main/Manager.py b/blueman/main/Manager.py index 3c4abe536..8240a2b20 100644 --- a/blueman/main/Manager.py +++ b/blueman/main/Manager.py @@ -8,7 +8,7 @@ from blueman.bluez.Device import Device from blueman.bluez.Manager import Manager from blueman.bluez.errors import DBusNoSuchAdapterError -from blueman.Constants import BIN_DIR +from blueman.config.Settings import BluemanSettings from blueman.Functions import * from blueman.gui.manager.ManagerDeviceList import ManagerDeviceList from blueman.gui.manager.ManagerToolbar import ManagerToolbar @@ -30,7 +30,7 @@ class Blueman(Gtk.Application): - def __init__(self, resource_file: str) -> None: + def __init__(self, resource_file: str, settings: BluemanSettings) -> None: super().__init__(application_id="org.blueman.Manager") def do_quit(_: object) -> bool: @@ -40,6 +40,7 @@ def do_quit(_: object) -> bool: s = GLib.unix_signal_source_new(signal.SIGINT) s.set_callback(do_quit) s.attach() + self.settings = settings gresource = Gio.Resource.load(resource_file) Gio.Resource._register(gresource) @@ -265,9 +266,8 @@ def error_handler(e: Exception) -> None: device.pair(error_handler=error_handler) - @staticmethod def adapter_properties(self) -> None: - launch(os.path.join(BIN_DIR, "blueman-adapters"), name=_("Adapter Preferences")) + launch(os.path.join(self.settings.bindir, "blueman-adapters"), name=_("Adapter Preferences")) @staticmethod def toggle_trust(device: Device) -> None: diff --git a/blueman/main/MechanismApplication.py b/blueman/main/MechanismApplication.py index 8ccc03b0f..db27aec05 100644 --- a/blueman/main/MechanismApplication.py +++ b/blueman/main/MechanismApplication.py @@ -1,15 +1,17 @@ import importlib import logging import os -from typing import Optional +from typing import Optional, TYPE_CHECKING import blueman.plugins.mechanism -from blueman.Constants import POLKIT from gi.repository import GLib, Gio from blueman.main.DbusService import DbusService, DbusError from blueman.plugins.MechanismPlugin import MechanismPlugin +if TYPE_CHECKING: + from blueman.config.Settings import BluemanSettings + class Timer: def __init__(self, loop: GLib.MainLoop): @@ -39,14 +41,15 @@ def resume(self) -> None: class MechanismApplication(DbusService): - def __init__(self, stoptimer: bool): + def __init__(self, stoptimer: bool, settings: "BluemanSettings"): super().__init__("org.blueman.Mechanism", "org.blueman.Mechanism", "/org/blueman/mechanism", Gio.BusType.SYSTEM) self._loop = GLib.MainLoop() self.timer = Timer(self._loop) + self.settings = settings if stoptimer: self.timer.stop() - if POLKIT: + if settings.polkit: try: self.pk: Optional[Gio.DBusProxy] = Gio.DBusProxy.new_for_bus_sync( Gio.BusType.SYSTEM, @@ -77,7 +80,7 @@ def __init__(self, stoptimer: bool): classes = MechanismPlugin.__subclasses__() for cls in classes: logging.info(f"loading {cls.__name__}") - cls(self) + cls(self, self.settings) self.register() @@ -86,7 +89,7 @@ def run(self) -> None: def confirm_authorization(self, subject: str, action_id: str) -> None: self.timer.reset() - if not POLKIT: + if not self.settings.polkit: return else: if not self.pk: diff --git a/blueman/main/NetConf.py b/blueman/main/NetConf.py index f9a2316b9..495834d1e 100644 --- a/blueman/main/NetConf.py +++ b/blueman/main/NetConf.py @@ -6,15 +6,17 @@ from time import sleep import logging import signal -from typing import List, Tuple, Optional, Type +from typing import List, Tuple, Optional, Type, TYPE_CHECKING -from blueman.Constants import DHCP_CONFIG_FILE from blueman.Functions import have from _blueman import create_bridge, destroy_bridge, BridgeException from subprocess import call, Popen, PIPE from blueman.main.DNSServerProvider import DNSServerProvider +if TYPE_CHECKING: + from blueman.config.Settings import BluemanSettings + class NetworkSetupError(Exception): pass @@ -51,8 +53,9 @@ class DHCPHandler: def _key(self) -> str: return self._BINARIES[-1] - def __init__(self) -> None: + def __init__(self, settings: "BluemanSettings") -> None: self._pid: Optional[int] = None + self.settings = settings @staticmethod def _get_arguments(ip4_address: str) -> List[str]: @@ -142,13 +145,12 @@ def _start(self, binary: str, ip4_address: str, ip4_mask: str, dns_servers: List class DhcpdHandler(DHCPHandler): _BINARIES = ["dhcpd3", "dhcpd"] - @staticmethod - def _read_dhcp_config() -> Tuple[str, str]: + def _read_dhcp_config(self) -> Tuple[str, str]: dhcp_config = '' existing_subnet = '' start = end = False - with open(DHCP_CONFIG_FILE) as f: + with open(self.settings.dhcp_config_file) as f: for line in f: if line == '#### BLUEMAN AUTOMAGIC SUBNET ####\n': start = True @@ -184,7 +186,7 @@ def _start(self, binary: str, ip4_address: str, ip4_mask: str, dns_servers: List subnet = self._generate_subnet_config(ip4_address, ip4_mask, dns_servers) - with open(DHCP_CONFIG_FILE, "w") as f: + with open(self.settings.dhcp_config_file, "w") as f: f.write(dhcp_config) f.write(subnet) @@ -197,7 +199,7 @@ def _start(self, binary: str, ip4_address: str, ip4_mask: str, dns_servers: List def _clean_up_configuration(self) -> None: dhcp_config, existing_subnet = self._read_dhcp_config() - with open(DHCP_CONFIG_FILE, "w") as f: + with open(self.settings.dhcp_config_file, "w") as f: f.write(dhcp_config) @@ -252,6 +254,10 @@ class NetConf: _IPV4_SYS_PATH = "/proc/sys/net/ipv4" _RUN_PATH = "/var/run" + _settings: BluemanSettings + + def __init__(self, settings: BluemanSettings): + self._settings = settings @classmethod def _enable_ip4_forwarding(cls) -> None: @@ -284,7 +290,7 @@ def apply_settings(cls, ip4_address: str, ip4_mask: str, handler: Type["DHCPHand if cls._dhcp_handler is not None: cls._dhcp_handler.clean_up() - cls._dhcp_handler = handler() + cls._dhcp_handler = handler(cls._settings) try: create_bridge("pan1") diff --git a/blueman/main/PluginManager.py b/blueman/main/PluginManager.py index 68ed667da..7b1d5eeb0 100644 --- a/blueman/main/PluginManager.py +++ b/blueman/main/PluginManager.py @@ -157,7 +157,7 @@ def __load_plugin(self, cls: Type[_T]) -> None: raise LoadException(f"Not loading conflicting plugin {cls.__name__} due to lower priority") logging.info(f"loading {cls}") - inst = cls(self.parent) + inst = cls(self.parent, self.parent.settings) try: inst._load() except Exception: diff --git a/blueman/main/Sendto.py b/blueman/main/Sendto.py index 15b5a54a6..44e793391 100644 --- a/blueman/main/Sendto.py +++ b/blueman/main/Sendto.py @@ -4,6 +4,7 @@ from gettext import ngettext from typing import List, Iterable, Optional +from blueman.config.Settings import BluemanSettings from blueman.bluez.Device import Device from blueman.bluez.errors import BluezDBusException from blueman.main.Builder import Builder @@ -28,7 +29,7 @@ class Sender(Gtk.Dialog): 'result': (GObject.SignalFlags.RUN_FIRST, None, (GObject.TYPE_BOOLEAN,)), } - def __init__(self, device: Device, adapter_path: str, files: Iterable[str]) -> None: + def __init__(self, device: Device, adapter_path: str, files: Iterable[str], settings: BluemanSettings) -> None: super().__init__( title=_("Bluetooth File Transfer"), name="BluemanSendTo", diff --git a/blueman/main/Services.py b/blueman/main/Services.py index 8a41096cf..0e669ab81 100644 --- a/blueman/main/Services.py +++ b/blueman/main/Services.py @@ -5,6 +5,7 @@ import signal from typing import List, Optional +from blueman.config.Settings import BluemanSettings from blueman.gui.GenericList import GenericList, ListDataDict import blueman.plugins.services from blueman.plugins.ServicePlugin import ServicePlugin @@ -17,8 +18,9 @@ class BluemanServices(Gtk.Application): - def __init__(self, resource_file: str) -> None: + def __init__(self, resource_file: str, settings: BluemanSettings) -> None: super().__init__(application_id="org.blueman.Services") + self.settings = settings self.window: Optional[Gtk.Window] = None def do_quit(_: object) -> bool: @@ -111,7 +113,7 @@ def load_plugins(self) -> None: for cls in ServicePlugin.__subclasses__(): # FIXME this should not fail, if it does its a bug in the plugin try: - inst = cls(self) + inst = cls(self, self.settings) except: # noqa: E722 logging.error(f"Failed to create instance of {cls}", exc_info=True) continue diff --git a/blueman/main/applet/BluezAgent.py b/blueman/main/applet/BluezAgent.py index 430623139..f59bd3ac7 100644 --- a/blueman/main/applet/BluezAgent.py +++ b/blueman/main/applet/BluezAgent.py @@ -4,6 +4,7 @@ from xml.etree import ElementTree from typing import Dict, Optional, overload, Callable, Union, TYPE_CHECKING, Tuple, Any, List +from blueman.config.Settings import BluemanSettings from blueman.bluez.Device import Device from blueman.bluez.AgentManager import AgentManager from blueman.Sdp import ServiceUUID @@ -33,8 +34,9 @@ class BluezErrorRejected(DbusError): class BluezAgent(DbusService): __agent_path = '/org/bluez/agent/blueman' - def __init__(self) -> None: + def __init__(self, settings: BluemanSettings) -> None: super().__init__(None, "org.bluez.Agent1", self.__agent_path, Gio.BusType.SYSTEM) + self.settings = settings self.add_method("Release", (), "", self._on_release) self.add_method("RequestPinCode", ("o",), "s", self._on_request_pin_code, is_async=True) diff --git a/blueman/plugins/AppletPlugin.py b/blueman/plugins/AppletPlugin.py index d51a52efe..a6a6213e9 100644 --- a/blueman/plugins/AppletPlugin.py +++ b/blueman/plugins/AppletPlugin.py @@ -7,15 +7,17 @@ from gi.repository import Gtk if TYPE_CHECKING: + from blueman.config.Settings import BluemanSettings from blueman.main.Applet import BluemanApplet class AppletPlugin(BasePlugin): __icon__ = "application-x-addon-symbolic" - def __init__(self, parent: "BluemanApplet"): + def __init__(self, parent: "BluemanApplet", settings: "BluemanSettings"): super().__init__() self.parent = parent + self.settings = settings if not Gtk.IconTheme.get_default().has_icon(self.__class__.__icon__): self.__class__.__icon__ = "application-x-addon-symbolic" diff --git a/blueman/plugins/ManagerPlugin.py b/blueman/plugins/ManagerPlugin.py index 35189e528..ff8dfcb84 100644 --- a/blueman/plugins/ManagerPlugin.py +++ b/blueman/plugins/ManagerPlugin.py @@ -3,13 +3,15 @@ from blueman.plugins.BasePlugin import BasePlugin if TYPE_CHECKING: + from blueman.config.Settings import BluemanSettings from blueman.main.Manager import Blueman class ManagerPlugin(BasePlugin): - def __init__(self, parent: "Blueman"): + def __init__(self, parent: "Blueman", settings: "BluemanSettings"): super().__init__() self.parent = parent + self.settings = settings def on_unload(self) -> None: pass diff --git a/blueman/plugins/MechanismPlugin.py b/blueman/plugins/MechanismPlugin.py index 29641871f..04dadea18 100644 --- a/blueman/plugins/MechanismPlugin.py +++ b/blueman/plugins/MechanismPlugin.py @@ -1,12 +1,14 @@ from typing import TYPE_CHECKING if TYPE_CHECKING: + from blueman.config.Settings import BluemanSettings from blueman.main.MechanismApplication import MechanismApplication class MechanismPlugin: - def __init__(self, parent: "MechanismApplication"): + def __init__(self, parent: "MechanismApplication", settings: "BluemanSettings"): self.parent = parent + self.settings = settings self.timer = self.parent.timer self.confirm_authorization = self.parent.confirm_authorization diff --git a/blueman/plugins/ServicePlugin.py b/blueman/plugins/ServicePlugin.py index fba5a77a7..38dd65dce 100644 --- a/blueman/plugins/ServicePlugin.py +++ b/blueman/plugins/ServicePlugin.py @@ -8,6 +8,7 @@ if TYPE_CHECKING: from typing_extensions import Literal + from blueman.config.Settings import BluemanSettings from blueman.main.Services import BluemanServices @@ -16,10 +17,11 @@ class ServicePlugin: instances: List["ServicePlugin"] = [] __plugin_info__: Tuple[str, str] - def __init__(self, parent: "BluemanServices"): + def __init__(self, parent: "BluemanServices", settings: "BluemanSettings"): ServicePlugin.instances.append(self) self._options = [] self.parent = parent + self.settings = settings self.__is_exposed = False self._is_loaded = False diff --git a/blueman/plugins/applet/AuthAgent.py b/blueman/plugins/applet/AuthAgent.py index 1e1f05774..5d1c5f526 100644 --- a/blueman/plugins/applet/AuthAgent.py +++ b/blueman/plugins/applet/AuthAgent.py @@ -18,7 +18,7 @@ def on_unload(self) -> None: def on_manager_state_changed(self, state: bool) -> None: if state: - self._agent = BluezAgent() + self._agent = BluezAgent(self.settings) self._agent.register_agent() else: # At this point bluez already called Release on the agent diff --git a/blueman/plugins/applet/AutoConnect.py b/blueman/plugins/applet/AutoConnect.py index efb4d16d6..764adf01d 100644 --- a/blueman/plugins/applet/AutoConnect.py +++ b/blueman/plugins/applet/AutoConnect.py @@ -9,6 +9,7 @@ from blueman.plugins.AppletPlugin import AppletPlugin if TYPE_CHECKING: + from blueman.config.Settings import BluemanSettings from blueman.main.Applet import BluemanApplet @@ -27,8 +28,8 @@ class AutoConnect(AppletPlugin): "services": {"type": list, "default": "[]"} } - def __init__(self, parent: "BluemanApplet"): - super().__init__(parent) + def __init__(self, parent: "BluemanApplet", settings: "BluemanSettings"): + super().__init__(parent, settings) GLib.timeout_add(60000, self._run) def on_manager_state_changed(self, state: bool) -> None: diff --git a/blueman/plugins/applet/DisconnectItems.py b/blueman/plugins/applet/DisconnectItems.py index 2f14b7416..160922972 100644 --- a/blueman/plugins/applet/DisconnectItems.py +++ b/blueman/plugins/applet/DisconnectItems.py @@ -4,6 +4,7 @@ from blueman.plugins.AppletPlugin import AppletPlugin if TYPE_CHECKING: + from blueman.config.Settings import BluemanSettings from blueman.main.Applet import BluemanApplet @@ -13,8 +14,8 @@ class DisconnectItems(AppletPlugin): __author__ = "cschramm" __description__ = _("Adds disconnect menu items") - def __init__(self, parent: "BluemanApplet"): - super().__init__(parent) + def __init__(self, parent: "BluemanApplet", settings: "BluemanSettings"): + super().__init__(parent, settings) self._menu = self.parent.Plugins.Menu def on_unload(self) -> None: diff --git a/blueman/plugins/applet/GameControllerWakelock.py b/blueman/plugins/applet/GameControllerWakelock.py index a30d9eb5c..2219b301c 100644 --- a/blueman/plugins/applet/GameControllerWakelock.py +++ b/blueman/plugins/applet/GameControllerWakelock.py @@ -4,7 +4,6 @@ from typing import Any from blueman.bluez.Device import Device -from blueman.Constants import BIN_DIR from blueman.Functions import launch from blueman.plugins.AppletPlugin import AppletPlugin from blueman.plugins.errors import UnsupportedPlatformError @@ -61,7 +60,7 @@ def xdg_screensaver(self, action: str) -> None: elif self.wake_lock > 1: self.wake_lock -= 1 else: - ret = launch(os.path.join(BIN_DIR, command), sn=False) + ret = launch(os.path.join(self.settings.bindir, command), sn=False) if ret: self.wake_lock -= 1 else: @@ -71,7 +70,7 @@ def xdg_screensaver(self, action: str) -> None: if self.wake_lock >= 1: self.wake_lock += 1 else: - ret = launch(os.path.join(BIN_DIR, command), sn=False) + ret = launch(os.path.join(self.settings.bindir, command), sn=False) if ret: self.wake_lock += 1 else: diff --git a/blueman/plugins/applet/NetUsage.py b/blueman/plugins/applet/NetUsage.py index 2cb29dff8..da61ef7cb 100644 --- a/blueman/plugins/applet/NetUsage.py +++ b/blueman/plugins/applet/NetUsage.py @@ -100,7 +100,7 @@ def poll_stats(self) -> bool: class Dialog: running = False - def __init__(self, plugin: "NetUsage"): + def __init__(self, plugin: "NetUsage", ui_path: str): if not Dialog.running: Dialog.running = True else: diff --git a/blueman/plugins/applet/StandardItems.py b/blueman/plugins/applet/StandardItems.py index 9302ade85..e41ed5030 100644 --- a/blueman/plugins/applet/StandardItems.py +++ b/blueman/plugins/applet/StandardItems.py @@ -2,7 +2,6 @@ from typing import Optional import os -from blueman.Constants import BIN_DIR from blueman.Functions import launch from blueman.main.DBusProxies import ManagerService from blueman.plugins.AppletPlugin import AppletPlugin @@ -81,10 +80,10 @@ def on_devices(self) -> None: m.startstop() def on_adapters(self) -> None: - launch(os.path.join(BIN_DIR, "blueman-adapters"), name=_("Adapter Preferences")) + launch(os.path.join(self.settings.bindir, "blueman-adapters"), name=_("Adapter Preferences")) def on_local_services(self) -> None: - launch(os.path.join(BIN_DIR, "blueman-services"), name=_("Service Preferences")) + launch(os.path.join(self.settings.bindir, "blueman-services"), name=_("Service Preferences")) def on_about(self) -> None: about = show_about_dialog("Blueman " + _("applet"), run=False) diff --git a/blueman/plugins/applet/StatusIcon.py b/blueman/plugins/applet/StatusIcon.py index 890d9ed67..d0ca9e305 100644 --- a/blueman/plugins/applet/StatusIcon.py +++ b/blueman/plugins/applet/StatusIcon.py @@ -4,7 +4,6 @@ from gi.repository import GObject, GLib, Gio -from blueman.Constants import BIN_DIR from blueman.Functions import launch from blueman.main.PluginManager import PluginManager from blueman.plugins.AppletPlugin import AppletPlugin @@ -106,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(os.path.join(BIN_DIR, 'blueman-tray'), icon_name='blueman', sn=False) + launch(os.path.join(self.settings.bindir, 'blueman-tray'), icon_name='blueman', sn=False) def _on_plugins_changed(self, _plugins: PluginManager, _name: str) -> None: implementations = self._get_status_icon_implementations() @@ -114,7 +113,7 @@ def _on_plugins_changed(self, _plugins: PluginManager, _name: str) -> None: self._implementations = implementations if self.parent.manager_state: - launch(os.path.join(BIN_DIR, 'blueman-tray'), icon_name='blueman', sn=False) + launch(os.path.join(self.settings.bindir, 'blueman-tray'), icon_name='blueman', sn=False) def _get_status_icon_implementations(self) -> List[str]: return [implementation for implementation, _ in sorted( diff --git a/blueman/plugins/applet/TransferService.py b/blueman/plugins/applet/TransferService.py index 72117bfd0..8b933f9bb 100644 --- a/blueman/plugins/applet/TransferService.py +++ b/blueman/plugins/applet/TransferService.py @@ -10,7 +10,6 @@ from blueman.bluez.obex.Manager import Manager from blueman.bluez.obex.Transfer import Transfer from blueman.bluez.obex.Session import Session -from blueman.Constants import BIN_DIR from blueman.Functions import launch from blueman.gui.Notification import Notification, _NotificationBubble, _NotificationDialog from blueman.main.Applet import BluemanApplet diff --git a/blueman/plugins/manager/Notes.py b/blueman/plugins/manager/Notes.py index 7c4ff3095..2a819fe8b 100644 --- a/blueman/plugins/manager/Notes.py +++ b/blueman/plugins/manager/Notes.py @@ -1,10 +1,10 @@ import datetime +import os from gettext import gettext as _ from tempfile import NamedTemporaryFile from typing import List - -from blueman.Constants import BIN_DIR +from blueman.config.Settings import BluemanSettings from blueman.Functions import create_menuitem, launch from blueman.bluez.Device import Device from blueman.gui.manager.ManagerDeviceMenu import MenuItemsProvider, ManagerDeviceMenu, DeviceMenuItem @@ -16,7 +16,8 @@ from gi.repository import Gtk -def send_note_cb(dialog: Gtk.Dialog, response_id: int, device_address: str, text_view: Gtk.Entry) -> None: +def send_note_cb(dialog: Gtk.Dialog, response_id: int, device_address: str, text_view: Gtk.Entry, + settings: BluemanSettings) -> None: text = text_view.get_buffer().props.text dialog.destroy() if response_id == Gtk.ResponseType.REJECT: @@ -35,16 +36,16 @@ def send_note_cb(dialog: Gtk.Dialog, response_id: int, device_address: str, text tempfile = NamedTemporaryFile(suffix='.vnt', prefix='note', delete=False) tempfile.write(data.encode('utf-8')) tempfile.close() - launch(os.path.join(BIN_DIR, f"blueman-sendto --delete --device={device_address}"), paths=[tempfile.name]) + launch(os.path.join(settings.bindir, f"blueman-sendto --delete --device={device_address}"), paths=[tempfile.name]) -def send_note(device: Device, parent: Gtk.Window) -> None: +def send_note(device: Device, parent: Gtk.Window, settings: BluemanSettings) -> None: builder = Builder("note.ui") dialog = builder.get_widget("dialog", Gtk.Dialog) dialog.set_transient_for(parent) 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, settings) dialog.present() @@ -55,5 +56,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: send_note(device, window)) + item.connect('activate', lambda x: send_note(device, window, self.parent.settings)) return [DeviceMenuItem(item, DeviceMenuItem.Group.ACTIONS, 500)] diff --git a/blueman/plugins/manager/Services.py b/blueman/plugins/manager/Services.py index 1e757a648..02427cd26 100644 --- a/blueman/plugins/manager/Services.py +++ b/blueman/plugins/manager/Services.py @@ -43,7 +43,7 @@ def on_request_menu_items(self, manager_menu: ManagerDeviceMenu, device: Device) items: List[DeviceMenuItem] = [] appl = AppletService() - services = get_services(device) + services = get_services(device, self.settings) connectable_services = [service for service in services if service.connectable] for service in connectable_services: diff --git a/blueman/plugins/mechanism/Rfcomm.py b/blueman/plugins/mechanism/Rfcomm.py index 945053f6f..c26098c98 100644 --- a/blueman/plugins/mechanism/Rfcomm.py +++ b/blueman/plugins/mechanism/Rfcomm.py @@ -1,7 +1,6 @@ import os import subprocess import signal -from blueman.Constants import RFCOMM_WATCHER_PATH from blueman.plugins.MechanismPlugin import MechanismPlugin @@ -11,7 +10,7 @@ def on_load(self) -> None: self.parent.add_method("CloseRFCOMM", ("d",), "", self._close_rfcomm) def _open_rfcomm(self, port_id: int) -> None: - subprocess.Popen([RFCOMM_WATCHER_PATH, '/dev/rfcomm%d' % port_id]) + subprocess.Popen([self.settings.rfcomm_watcher_path, '/dev/rfcomm%d' % port_id]) def _close_rfcomm(self, port_id: int) -> None: command = 'blueman-rfcomm-watcher /dev/rfcomm%d' % port_id diff --git a/blueman/services/Functions.py b/blueman/services/Functions.py index 0801c02e7..95ba981a1 100644 --- a/blueman/services/Functions.py +++ b/blueman/services/Functions.py @@ -1,6 +1,6 @@ import inspect import logging -from typing import Optional, List +from typing import Optional, List, TYPE_CHECKING from blueman.Service import Service from blueman.Sdp import ServiceUUID @@ -8,18 +8,21 @@ from blueman.bluez.errors import BluezDBusException import blueman.services +if TYPE_CHECKING: + from blueman.config.Settings import BluemanSettings -def get_service(device: Device, uuid: str) -> Optional[Service]: + +def get_service(device: Device, uuid: str, settings: "BluemanSettings") -> Optional[Service]: for name, cls in inspect.getmembers(blueman.services, inspect.isclass): if ServiceUUID(uuid).short_uuid == cls.__svclass_id__: - svc: Service = cls(device, uuid) + svc: Service = cls(device, uuid, settings) return svc return None -def get_services(device: Device) -> List[Service]: +def get_services(device: Device, settings: "BluemanSettings") -> List[Service]: try: - services = (get_service(device, uuid) for uuid in device['UUIDs']) + services = (get_service(device, uuid, settings) 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..60e73aaa5 100644 --- a/blueman/services/meta/NetworkService.py +++ b/blueman/services/meta/NetworkService.py @@ -1,5 +1,5 @@ from gettext import gettext as _ -from typing import Optional, Callable, List, Set +from typing import Optional, Callable, List, Set, TYPE_CHECKING from blueman.main.DBusProxies import AppletService @@ -8,10 +8,13 @@ from blueman.bluez.Network import Network from blueman.bluez.errors import BluezDBusException +if TYPE_CHECKING: + from blueman.config.Settings import BluemanSettings + class NetworkService(Service): - def __init__(self, device: Device, uuid: str): - super().__init__(device, uuid) + def __init__(self, device: Device, uuid: str, settings: "BluemanSettings"): + super().__init__(device, uuid, settings) self._service = Network(obj_path=device.get_object_path()) @property diff --git a/blueman/services/meta/SerialService.py b/blueman/services/meta/SerialService.py index 28f84f9c3..714c3cb17 100644 --- a/blueman/services/meta/SerialService.py +++ b/blueman/services/meta/SerialService.py @@ -2,7 +2,7 @@ import logging import os import subprocess -from typing import Callable, Dict, Optional, List +from typing import Callable, Dict, Optional, List, TYPE_CHECKING from gi.repository import Gio, GLib @@ -11,12 +11,14 @@ from blueman.Service import Service, Instance from blueman.bluez.Device import Device from blueman.main.DBusProxies import Mechanism -from blueman.Constants import RFCOMM_WATCHER_PATH + +if TYPE_CHECKING: + from blueman.config.Settings import BluemanSettings class SerialService(Service): - def __init__(self, device: Device, uuid: str) -> None: - super().__init__(device, uuid) + def __init__(self, device: Device, uuid: str, settings: "BluemanSettings") -> None: + super().__init__(device, uuid, settings) self._handlerids: Dict[int, int] = {} @property @@ -61,7 +63,7 @@ def try_replace_root_watcher(self, monitor: Gio.FileMonitor, path: str, port: in logging.info(f'User was granted access to {path}') logging.info('Replacing root watcher') Mechanism().CloseRFCOMM('(d)', port) - subprocess.Popen([RFCOMM_WATCHER_PATH, path]) + subprocess.Popen([self._settings.rfcomm_watcher_path, path]) if port in self._handlerids: handler_id = self._handlerids.pop(port) monitor.disconnect(handler_id) diff --git a/configure.ac b/configure.ac index 25d0d715d..6202172ad 100644 --- a/configure.ac +++ b/configure.ac @@ -151,8 +151,8 @@ AS_IF([test "x$enable_polkit" = "xyes"], AM_CONDITIONAL([HAVE_POLKIT], [test "x$have_polkit" = "xyes"]) AS_IF([test "x$have_polkit" = "xyes"], - [POLKIT=True], - [POLKIT=False]) + [POLKIT=true], + [POLKIT=false]) AC_SUBST([POLKIT]) @@ -250,7 +250,6 @@ apps/blueman-sendto apps/blueman-services apps/blueman-tray blueman/Makefile -blueman/Constants.py blueman/bluez/Makefile blueman/bluez/obex/Makefile blueman/config/Makefile @@ -269,6 +268,7 @@ blueman/services/Makefile blueman/services/meta/Makefile data/Makefile data/configs/Makefile +data/configs/settings.json data/icons/Makefile data/icons/hicolor/Makefile data/icons/hicolor/16x16/Makefile diff --git a/data/configs/Makefile.am b/data/configs/Makefile.am index 0cdafcefc..471823ee0 100644 --- a/data/configs/Makefile.am +++ b/data/configs/Makefile.am @@ -52,6 +52,7 @@ CLEANFILES = \ org.blueman.Mechanism.service \ org.blueman.Applet.service \ org.blueman.policy \ + settings.json \ $(BUILT_SOURCES) DISTCLEANFILES = \ diff --git a/data/configs/settings.json.in b/data/configs/settings.json.in new file mode 100644 index 000000000..042727c2a --- /dev/null +++ b/data/configs/settings.json.in @@ -0,0 +1,12 @@ +{ + "version": "@VERSION@", + "package": "@PACKAGE@", + "website": "https://github.com/blueman-project/blueman", + "prefix": "@prefix@", + "bindir": "@BINDIR@", + "localedir": "@LOCALEDIR@", + "dhcp_config_file": "@dhconfig@", + "polkit": @POLKIT@, + "gettext_package": "@GETTEXT_PACKAGE@", + "rfcomm_watcher_path": "@LIBEXECDIR@/blueman-rfcomm-watcher" +} diff --git a/meson.build b/meson.build index 7a4ce0d16..5f710b0cb 100644 --- a/meson.build +++ b/meson.build @@ -45,9 +45,12 @@ conf_data.set('pkgdatadir', pkgdatadir) conf_data.set('LOCALEDIR', join_paths(prefix, get_option('localedir'))) conf_data.set('icondir', join_paths(datadir, 'icons')) conf_data.set('dhconfig', get_option('dhcp-config-path')) -conf_data.set('POLKIT', have_polkit) +conf_data.set('POLKIT', get_option('policykit').to_string()) conf_data.set('GETTEXT_PACKAGE', package_name) conf_data.set('PYTHON', pyinstall.path()) +conf_data.set('settings_path', pkgdatadir) + +message(get_option('policykit')) # Check for build dependencies pythonlib = pyinstall.dependency() @@ -163,9 +166,6 @@ install_man( # Gather all configurable files configurable_files = [ - ['blueman/Constants.py.in', - 'Constants.py', - join_paths(pythondir, package_name)], ['data/configs/org.blueman.Applet.service.in', 'org.blueman.Applet.service', join_paths(datadir, 'dbus-1', 'services')], @@ -174,7 +174,10 @@ configurable_files = [ join_paths(datadir, 'dbus-1', 'services')], ['data/configs/org.blueman.Mechanism.service.in', 'org.blueman.Mechanism.service', - join_paths(datadir, 'dbus-1', 'system-services')] + join_paths(datadir, 'dbus-1', 'system-services')], + ['data/configs/settings.json.in', + 'settings.json', + pkgdatadir] ] systemd_user_dir = get_option('systemduserunitdir') diff --git a/po/POTFILES.in b/po/POTFILES.in index 3ca4c615f..c4d492808 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -48,7 +48,6 @@ blueman/gui/DeviceSelectorWidget.py blueman/DeviceClass.py blueman/__init__.py blueman/Sdp.py -blueman/Constants.py.in blueman/bluez/Adapter.py blueman/bluez/errors.py blueman/bluez/Device.py