From d3ee3c398a613fd7506c02fda9182101d3ad7eba Mon Sep 17 00:00:00 2001 From: Florian Ludwig Date: Wed, 10 Jun 2020 15:51:35 +0200 Subject: [PATCH 1/3] add gnome-shell compatibility --- aw_watcher_window/lib.py | 68 +++++++++++++++++++++++++++++++++------- pyproject.toml | 9 ++++++ 2 files changed, 66 insertions(+), 11 deletions(-) diff --git a/aw_watcher_window/lib.py b/aw_watcher_window/lib.py index 010fb80..2abc660 100644 --- a/aw_watcher_window/lib.py +++ b/aw_watcher_window/lib.py @@ -1,19 +1,65 @@ import sys +import json from typing import Optional -def get_current_window_linux() -> Optional[dict]: - from . import xlib - window = xlib.get_current_window() +class Linux: + def __init__(self): + try: + import pydbus + self.bus = pydbus.SessionBus() + except ModuleNotFoundError: + self.bus = False + self.gnome_shell = None + + if self.bus: + import gi.repository.GLib + try: + self.gnome_shell = self.bus.get("org.gnome.Shell") + except gi.repository.GLib.Error: + self.gnome_shell = None + + def get_current_window(self) -> dict: + if self.gnome_shell: + return self.get_current_window_gnome_shell() + + return self.get_current_window_x11() + + def get_current_window_gnome_shell(self) -> dict: + """get current app from GNOME Shell via dbus""" + js_code = """ + var window_list = global.get_window_actors(); + var active_window_actor = window_list.find(window => window.meta_window.has_focus()); + var active_window = active_window_actor.get_meta_window() + var vm_class = active_window.get_wm_class(); + var title = active_window.get_title() + var result = {"title": title, "appname": vm_class}; + result + """ + + ok, result = self.gnome_shell.Eval(js_code) + if ok: + result_data = json.loads(result) + return result_data + + return {"appname": "unknown", "title": "unknown"} + + def get_current_window_x11(self) -> dict: + from . import xlib + window = xlib.get_current_window() + + if window is None: + cls = "unknown" + name = "unknown" + else: + cls = xlib.get_window_class(window) + name = xlib.get_window_name(window) + + return {"appname": cls, "title": name} - if window is None: - cls = "unknown" - name = "unknown" - else: - cls = xlib.get_window_class(window) - name = xlib.get_window_name(window) - return {"appname": cls, "title": name} +if sys.platform.startswith("linux"): + linux = Linux() def get_current_window_macos() -> Optional[dict]: @@ -41,7 +87,7 @@ def get_current_window_windows() -> Optional[dict]: def get_current_window() -> Optional[dict]: if sys.platform.startswith("linux"): - return get_current_window_linux() + return linux.get_current_window() elif sys.platform == "darwin": return get_current_window_macos() elif sys.platform in ["win32", "cygwin"]: diff --git a/pyproject.toml b/pyproject.toml index 07aa601..2cd5a3f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,11 +15,20 @@ python-xlib = {version = "^0.26", platform = "linux"} pypiwin32 = {version = "223", platform = "win32"} wmi = {version = "^1.4.9", platform = "win32"} +# pydbus depends on PyGObject, which needs several system libs installed, +# to be able to be compiled: +# * gobject-introspection-devel +# * cairo-gobject-devel +pydbus = { version = "^0.6.0", platform = "linux", optional = true } + [tool.poetry.dev-dependencies] pytest = "^5.3.2" mypy = "^0.761" macholib = {version = "^1.13", platform = "darwin"} # Needed for pyinstaller +[tool.poetry.extras] +gnome = ["pydbus"] + [build-system] requires = ["poetry>=0.12"] build-backend = "poetry.masonry.api" From fb94dc6ce58ac9e01f721f354e74499d7e5796dc Mon Sep 17 00:00:00 2001 From: Florian Ludwig Date: Wed, 10 Jun 2020 16:09:07 +0200 Subject: [PATCH 2/3] create JS function inside gnome shell this gives another ~23% performance increase for get_current_window_gnome_shell measured in wall clock time. --- aw_watcher_window/lib.py | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/aw_watcher_window/lib.py b/aw_watcher_window/lib.py index 2abc660..8bf3eef 100644 --- a/aw_watcher_window/lib.py +++ b/aw_watcher_window/lib.py @@ -16,6 +16,7 @@ def __init__(self): import gi.repository.GLib try: self.gnome_shell = self.bus.get("org.gnome.Shell") + self._setup_gnome() except gi.repository.GLib.Error: self.gnome_shell = None @@ -24,20 +25,27 @@ def get_current_window(self) -> dict: return self.get_current_window_gnome_shell() return self.get_current_window_x11() + + def _setup_gnome(self) -> None: + js_code = """ + global._aw_current_window = () => { + var window_list = global.get_window_actors(); + var active_window_actor = window_list.find(window => window.meta_window.has_focus()); + var active_window = active_window_actor.get_meta_window() + var vm_class = active_window.get_wm_class(); + var title = active_window.get_title() + var result = {"title": title, "appname": vm_class}; + return result + } + """ + ok, result = self.gnome_shell.Eval(js_code) + if not ok: + raise Error("failed seting up gnome-shell function: " + result) def get_current_window_gnome_shell(self) -> dict: """get current app from GNOME Shell via dbus""" - js_code = """ - var window_list = global.get_window_actors(); - var active_window_actor = window_list.find(window => window.meta_window.has_focus()); - var active_window = active_window_actor.get_meta_window() - var vm_class = active_window.get_wm_class(); - var title = active_window.get_title() - var result = {"title": title, "appname": vm_class}; - result - """ - ok, result = self.gnome_shell.Eval(js_code) + ok, result = self.gnome_shell.Eval("global._aw_current_window()") if ok: result_data = json.loads(result) return result_data From c72ebf423d589ded95624f398659ab5c10985c84 Mon Sep 17 00:00:00 2001 From: Florian Ludwig Date: Wed, 10 Jun 2020 16:13:01 +0200 Subject: [PATCH 3/3] add logging when pydbus is not installed --- aw_watcher_window/lib.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/aw_watcher_window/lib.py b/aw_watcher_window/lib.py index 8bf3eef..5ad669b 100644 --- a/aw_watcher_window/lib.py +++ b/aw_watcher_window/lib.py @@ -1,7 +1,10 @@ import sys import json +import logging from typing import Optional +logger = logging.getLogger(__name__) + class Linux: def __init__(self): @@ -9,6 +12,7 @@ def __init__(self): import pydbus self.bus = pydbus.SessionBus() except ModuleNotFoundError: + logger.info("pydbus not installed, GNOME-Shell Wayland support disabled") self.bus = False self.gnome_shell = None