Skip to content

Commit 89a1a39

Browse files
committed
Linux: better handling of the Xrandr extension (fixes BoboTiG#168)
1 parent e0afd3e commit 89a1a39

File tree

5 files changed

+42
-1
lines changed

5 files changed

+42
-1
lines changed

CHANGELOG

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ History:
77
- fixed flake8 usage in pre-commit
88
- the module is now available on conda (closes #170)
99
- MSS: the implementation is now thread-safe on all OSes (fixes #169)
10+
- Linux: better handling of the Xrandr extension (fixes #168)
1011
- tests: fixed a random bug on test_grab_with_tuple_percents() (fixes #142)
1112
- :heart: contributors: @
1213

CHANGES.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ darwin.py
1616

1717
linux.py
1818
--------
19+
- Added ``MSS.has_extension()``
1920
- Renamed ``MSS.grab()`` to ``MSS._grab_impl()``
2021
- Renamed ``MSS.monitors`` to ``MSS._monitors_impl()``
2122

mss/base.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from .tools import to_png
1414

1515
if TYPE_CHECKING:
16+
# pylint: disable=ungrouped-imports
1617
from typing import Any, Callable, Iterator, List, Optional, Type # noqa
1718

1819
from .models import Monitor, Monitors # noqa

mss/linux.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from types import SimpleNamespace
1111
from typing import TYPE_CHECKING
1212

13-
from .base import MSSBase
13+
from .base import MSSBase, lock
1414
from .exception import ScreenShotError
1515

1616
if TYPE_CHECKING:
@@ -227,10 +227,36 @@ def __init__(self, display=None):
227227

228228
self.root = self.xlib.XDefaultRootWindow(self._get_display(display))
229229

230+
if not self.has_extension("RANDR"):
231+
raise ScreenShotError("No Xrandr extension found.")
232+
230233
# Fix for XRRGetScreenResources and XGetImage:
231234
# expected LP_Display instance instead of LP_XWindowAttributes
232235
self.drawable = ctypes.cast(self.root, ctypes.POINTER(Display))
233236

237+
def has_extension(self, extension):
238+
# type: (str) -> bool
239+
"""Return True if the given *extension* is part of the extensions list of the server."""
240+
with lock:
241+
byref = ctypes.byref
242+
c_int = ctypes.c_int
243+
major_opcode_return = c_int()
244+
first_event_return = c_int()
245+
first_error_return = c_int()
246+
247+
try:
248+
self.xlib.XQueryExtension(
249+
self._get_display(),
250+
extension.encode("latin1"),
251+
byref(major_opcode_return),
252+
byref(first_event_return),
253+
byref(first_error_return),
254+
)
255+
except ScreenShotError:
256+
return False
257+
else:
258+
return True
259+
234260
def _get_display(self, disp=None):
235261
"""
236262
Retrieve a thread-safe display from XOpenDisplay().
@@ -297,6 +323,11 @@ def cfactory(func, argtypes, restype, attr=self.xlib):
297323
pointer(XImage),
298324
)
299325
cfactory("XDestroyImage", [pointer(XImage)], void)
326+
cfactory(
327+
"XQueryExtension",
328+
[pointer(Display), char_p, pointer(c_int), pointer(c_int), pointer(c_int)],
329+
uint,
330+
)
300331

301332
# A simple benchmark calling 10 times those 2 functions:
302333
# XRRGetScreenResources(): 0.1755971429956844 s

mss/tests/test_gnu_linux.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,3 +121,10 @@ def test_region_out_of_monitor_bounds():
121121
details = sct.get_error_details()
122122
assert details["xerror"]
123123
assert isinstance(details["xerror_details"], dict)
124+
125+
126+
def test_has_extension():
127+
display = os.getenv("DISPLAY")
128+
with mss.mss(display=display) as sct:
129+
assert sct.has_extension("RANDR")
130+
assert not sct.has_extension("NOEXT")

0 commit comments

Comments
 (0)