From 25dc01988622d590030b51def7930056f58ab0ca Mon Sep 17 00:00:00 2001 From: Jan Palus Date: Tue, 11 Nov 2025 00:51:05 +0100 Subject: [PATCH 1/2] Unify librarry loading for X11/Wayland wmname libwayland-client.so is development symlink used during linking and there's no need to have it installed (usually shipped in -devel/-dev packages) on user's machines. Instead of hardcoding library file name, use same mechanism as in libX11 which let's Python figure the details and share common logic between X11 and Wayland. Fixes #8771 --- qutebrowser/misc/wmname.py | 25 +++++++++++++------------ tests/unit/misc/test_wmname.py | 3 ++- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/qutebrowser/misc/wmname.py b/qutebrowser/misc/wmname.py index 04d267d14..d59375bdb 100644 --- a/qutebrowser/misc/wmname.py +++ b/qutebrowser/misc/wmname.py @@ -26,12 +26,20 @@ class _WaylandDisplayStruct(ctypes.Structure): _WaylandDisplay = NewType("_WaylandDisplay", "ctypes._Pointer[_WaylandDisplayStruct]") +def _load_library(name: str) -> ctypes.CDLL: + lib = ctypes.util.find_library(name) + if lib is None: + raise Error(f"{name} library not found") + + try: + return ctypes.CDLL(lib) + except OSError as e: + raise Error(f"Failed to load {name} library: {e}") + + def _load_libwayland_client() -> ctypes.CDLL: """Load the Wayland client library.""" - try: - return ctypes.CDLL("libwayland-client.so") - except OSError as e: - raise Error(f"Failed to load libwayland-client: {e}") + return _load_library("wayland-client") def _pid_from_fd(fd: int) -> int: @@ -138,14 +146,7 @@ _X11Window = NewType("_X11Window", int) def _x11_load_lib() -> ctypes.CDLL: """Load the X11 library.""" - lib = ctypes.util.find_library("X11") - if lib is None: - raise Error("X11 library not found") - - try: - return ctypes.CDLL(lib) - except OSError as e: - raise Error(f"Failed to load X11 library: {e}") + return _load_library("X11") @contextlib.contextmanager diff --git a/tests/unit/misc/test_wmname.py b/tests/unit/misc/test_wmname.py index 4c4b6c50c..03c465d3b 100644 --- a/tests/unit/misc/test_wmname.py +++ b/tests/unit/misc/test_wmname.py @@ -28,9 +28,10 @@ def test_load_libwayland_client(): def test_load_libwayland_client_error(mocker: pytest_mock.MockerFixture): """Test that an error in loading the Wayland client library raises an error.""" + mocker.patch.object(ctypes.util, "find_library", return_value="libwayland-client.so.6") mocker.patch("ctypes.CDLL", side_effect=OSError("Library not found")) - with pytest.raises(wmname.Error, match="Failed to load libwayland-client"): + with pytest.raises(wmname.Error, match="Failed to load wayland-client"): wmname._load_libwayland_client() From bc191b798d28302754ae5750aa46f0f7c3f82e35 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 11 Nov 2025 09:06:49 +0100 Subject: [PATCH 2/2] wmname: Remove trivial functions --- qutebrowser/misc/wmname.py | 14 ++------------ tests/unit/misc/test_wmname.py | 12 ++++++------ 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/qutebrowser/misc/wmname.py b/qutebrowser/misc/wmname.py index d59375bdb..e27cca394 100644 --- a/qutebrowser/misc/wmname.py +++ b/qutebrowser/misc/wmname.py @@ -37,11 +37,6 @@ def _load_library(name: str) -> ctypes.CDLL: raise Error(f"Failed to load {name} library: {e}") -def _load_libwayland_client() -> ctypes.CDLL: - """Load the Wayland client library.""" - return _load_library("wayland-client") - - def _pid_from_fd(fd: int) -> int: """Get the process ID from a file descriptor using SO_PEERCRED. @@ -121,7 +116,7 @@ def wayland_compositor_name() -> str: Approach based on: https://stackoverflow.com/questions/69302630/wayland-client-get-compositor-name """ - wayland_client = _load_libwayland_client() + wayland_client = _load_library("wayland-client") with _wayland_display(wayland_client) as display: fd = _wayland_get_fd(wayland_client, display) pid = _pid_from_fd(fd) @@ -144,11 +139,6 @@ _X11Display = NewType("_X11Display", "ctypes._Pointer[_X11DisplayStruct]") _X11Window = NewType("_X11Window", int) -def _x11_load_lib() -> ctypes.CDLL: - """Load the X11 library.""" - return _load_library("X11") - - @contextlib.contextmanager def _x11_open_display(xlib: ctypes.CDLL) -> Iterator[_X11Display]: """Open a connection to the X11 display.""" @@ -308,7 +298,7 @@ def _x11_get_wm_name( def x11_wm_name() -> str: """Get the name of the running X11 window manager.""" - xlib = _x11_load_lib() + xlib = _load_library("X11") with _x11_open_display(xlib) as display: atoms = _X11Atoms( NET_SUPPORTING_WM_CHECK=_x11_intern_atom( diff --git a/tests/unit/misc/test_wmname.py b/tests/unit/misc/test_wmname.py index 03c465d3b..bc0e1daea 100644 --- a/tests/unit/misc/test_wmname.py +++ b/tests/unit/misc/test_wmname.py @@ -21,7 +21,7 @@ from qutebrowser.misc import wmname def test_load_libwayland_client(): """Test loading the Wayland client library, which might or might not exist.""" try: - wmname._load_libwayland_client() + wmname._load_library("wayland-client") except wmname.Error: pass @@ -32,7 +32,7 @@ def test_load_libwayland_client_error(mocker: pytest_mock.MockerFixture): mocker.patch("ctypes.CDLL", side_effect=OSError("Library not found")) with pytest.raises(wmname.Error, match="Failed to load wayland-client"): - wmname._load_libwayland_client() + wmname._load_library("wayland-client") @pytest.fixture @@ -178,7 +178,7 @@ def test_wayland_real(): def test_load_xlib(): """Test loading Xlib, which might or might not exist.""" try: - wmname._x11_load_lib() + wmname._load_library("X11") except wmname.Error: pass @@ -188,7 +188,7 @@ def test_load_xlib_not_found(monkeypatch: pytest.MonkeyPatch): monkeypatch.setattr(ctypes.util, "find_library", lambda x: None) with pytest.raises(wmname.Error, match="X11 library not found"): - wmname._x11_load_lib() + wmname._load_library("X11") def test_load_xlib_error(mocker: pytest_mock.MockerFixture): @@ -199,7 +199,7 @@ def test_load_xlib_error(mocker: pytest_mock.MockerFixture): with pytest.raises( wmname.Error, match="Failed to load X11 library: Failed to load library" ): - wmname._x11_load_lib() + wmname._load_library("X11") @pytest.fixture @@ -290,7 +290,7 @@ def test_x11_get_wm_name( qtbot.add_widget(w) w.setWindowTitle("Test Window") - xlib = wmname._x11_load_lib() + xlib = wmname._load_library("X11") with wmname._x11_open_display(xlib) as display: atoms = wmname._X11Atoms( NET_SUPPORTING_WM_CHECK=-1,