From 91f1894e8bce3c965ce9335629f1346bb6d12ee4 Mon Sep 17 00:00:00 2001 From: Swapnil Devesh Date: Wed, 26 Jul 2023 16:23:57 +0530 Subject: [PATCH] Add support for process condition under wayland using solaar-gnome-extension (#2101) * Add support for process condition under wayland using solaar-gnome-extension * Fix typo * Improvements * Rename dbus extension * Final fixes * Fix style checks * More styling fixes * More fixes * More fixes --------- Co-authored-by: Peter F. Patel-Schneider --- docs/installation.md | 2 +- lib/logitech_receiver/diversion.py | 54 ++++++++++++++++++++++++++---- setup.py | 1 + 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/docs/installation.md b/docs/installation.md index c292a94e..ad36dbd2 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -33,7 +33,7 @@ The `udev` package must be installed and its daemon running. Solaar requires Python 3.7+ and requires several packages to be installed. If you are running the system version of Python you should have the -`python3-pyudev`, `python3-psutil`, `python3-xlib`, `python3-evdev`, `python3-typing-extensions`, +`python3-pyudev`, `python3-psutil`, `python3-xlib`, `python3-evdev`, `python3-typing-extensions`, `dbus-python`, and `python3-yaml` or `python3-pyyaml` packages installed. To run the GUI Solaar also requires Gtk3 and its GObject introspection bindings. diff --git a/lib/logitech_receiver/diversion.py b/lib/logitech_receiver/diversion.py index c925066e..30852b53 100644 --- a/lib/logitech_receiver/diversion.py +++ b/lib/logitech_receiver/diversion.py @@ -28,6 +28,7 @@ from logging import getLogger from math import sqrt as _sqrt from struct import unpack as _unpack +import dbus import evdev import keysyms.keysymdef as _keysymdef import psutil @@ -94,7 +95,10 @@ if _log.isEnabledFor(_INFO): wayland = _os.getenv('WAYLAND_DISPLAY') # is this Wayland? if wayland: - _log.warn('rules cannot access active process or modifier keys in Wayland') + _log.warn( + 'rules cannot access modifier keys in Wayland, ' + 'accessing process only works on GNOME with Solaar Gnome extension installed' + ) try: import Xlib @@ -108,6 +112,8 @@ Xkbdisplay = None # xkb might be available modifier_keycodes = [] XkbUseCoreKbd = 0x100 +_dbus_interface = None + class XkbDisplay(_ctypes.Structure): """ opaque struct """ @@ -143,6 +149,20 @@ def x11_setup(): return _x11 +def gnome_dbus_interface_setup(): + global _dbus_interface + if _dbus_interface is not None: + return _dbus_interface + try: + bus = dbus.SessionBus() + remote_object = bus.get_object('org.gnome.Shell', '/io/github/pwr_solaar/solaar') + _dbus_interface = dbus.Interface(remote_object, 'io.github.pwr_solaar.solaar') + except dbus.exceptions.DBusException: + _log.warn('Solaar Gnome extension not installed - some rule capabilities inoperable', exc_info=_sys.exc_info()) + _dbus_interface = False + return _dbus_interface + + def xkb_setup(): global X11Lib, Xkbdisplay if Xkbdisplay is not None: @@ -562,13 +582,30 @@ def x11_pointer_prog(): return (wm_class[0], wm_class[1], name) if wm_class else (name, ) +def gnome_dbus_focus_prog(): + if not gnome_dbus_interface_setup(): + return None + wm_class = _dbus_interface.ActiveWindow() + return (wm_class, ) if wm_class else None + + +def gnome_dbus_pointer_prog(): + if not gnome_dbus_interface_setup(): + return None + wm_class = _dbus_interface.PointerOverWindow() + return (wm_class, ) if wm_class else None + + class Process(Condition): def __init__(self, process, warn=True): self.process = process - if wayland or not x11_setup(): + if (not wayland and not x11_setup()) or (wayland and not gnome_dbus_interface_setup()): if warn: - _log.warn('rules can only access active process in X11 - %s', self) + _log.warn( + 'rules can only access active process in X11 or in wayland under GNOME with Solaar Gnome extension - %s', + self + ) if not isinstance(process, str): if warn: _log.warn('rule Process argument not a string: %s', process) @@ -582,7 +619,7 @@ class Process(Condition): _log.debug('evaluate condition: %s', self) if not isinstance(self.process, str): return False - focus = x11_focus_prog() + focus = x11_focus_prog() if not wayland else gnome_dbus_focus_prog() result = any(bool(s and s.startswith(self.process)) for s in focus) if focus else None return result @@ -594,9 +631,12 @@ class MouseProcess(Condition): def __init__(self, process, warn=True): self.process = process - if wayland or not x11_setup(): + if (not wayland and not x11_setup()) or (wayland and not gnome_dbus_interface_setup()): if warn: - _log.warn('rules cannot access active mouse process in X11 - %s', self) + _log.warn( + 'rules cannot access active mouse process ' + 'in X11 or in wayland under GNOME with Solaar Gnome extension - %s', self + ) if not isinstance(process, str): if warn: _log.warn('rule MouseProcess argument not a string: %s', process) @@ -610,7 +650,7 @@ class MouseProcess(Condition): _log.debug('evaluate condition: %s', self) if not isinstance(self.process, str): return False - pointer_focus = x11_pointer_prog() + pointer_focus = x11_pointer_prog() if not wayland else gnome_dbus_pointer_prog() result = any(bool(s and s.startswith(self.process)) for s in pointer_focus) if pointer_focus else None return result diff --git a/setup.py b/setup.py index 24751a8d..ccb343a8 100755 --- a/setup.py +++ b/setup.py @@ -82,6 +82,7 @@ For instructions on installing Solaar see https://pwr-solaar.github.io/Solaar/in 'PyYAML (>= 3.12)', 'python-xlib (>= 0.27)', 'psutil (>= 5.4.3)', + 'dbus-python (>=1.3.2)', ], extras_require={ 'report-descriptor': ['hid-parser'],