Skip to content

Commit 730531f

Browse files
committed
Update the docs
Also, before marking XShmGetImage as unavailable if the first grab() fails, also test to see if the fallback XGetImage also fails (such as if the user gave an out-of-bounds rect). In that case, just reraise the exception and try XShmGetImage again with the next grab().
1 parent 3bcc540 commit 730531f

File tree

14 files changed

+238
-20
lines changed

14 files changed

+238
-20
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ See Git checking messages for full history.
55
## 10.1.1.dev0 (2025-xx-xx)
66
- Linux: check the server for Xrandr support version (#417)
77
- Linux: improve typing and error messages for X libraries (#418)
8-
- Linux: add a new XCB backend for better thread safety, error-checking, and future development (#425)
8+
- Linux: introduce an XCB-powered backend stack with a factory in ``mss.linux`` while keeping the Xlib code as a fallback (#425)
9+
- Linux: add the XShmGetImage backend with automatic XGetImage fallback and explicit status reporting (#431)
910
- :heart: contributors: @jholveck
1011

1112
## 10.1.0 (2025-08-16)

CHANGES.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,19 @@
11
# Technical Changes
22

3+
## 10.1.1 (2025-xx-xx)
4+
5+
### linux/__init__.py
6+
- Added an ``mss()`` factory to select between the different GNU/Linux backends.
7+
8+
### linux/xlib.py
9+
- Moved the legacy Xlib backend into the ``mss.linux.xlib`` module to be used as a fallback implementation.
10+
11+
### linux/xgetimage.py
12+
- Added an XCB-based backend that mirrors XGetImage semantics.
13+
14+
### linux/xshmgetimage.py
15+
- Added an XCB backend powered by XShmGetImage with ``shm_status`` and ``shm_fallback_reason`` attributes for diagnostics.
16+
317
## 10.1.0 (2025-08-16)
418

519
### darwin.py

docs/source/api.rst

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,36 @@ GNU/Linux
3333

3434
.. module:: mss.linux
3535

36+
Factory function to return the appropriate backend implementation.
37+
38+
.. function:: mss(backend="default", **kwargs)
39+
40+
:keyword str backend: Backend name ("default", "xlib", "xgetimage", or "xshmgetimage").
41+
:keyword display: Display name (e.g., ":0.0") for the X server. Default is taken from the :envvar:`DISPLAY` environment variable.
42+
:type display: str or None
43+
:param kwargs: Additional arguments passed to the backend MSS class.
44+
:rtype: :class:`mss.base.MSSBase`
45+
:return: Backend-specific MSS instance.
46+
47+
Factory returning a proper MSS class instance for GNU/Linux.
48+
The backend parameter selects the implementation:
49+
50+
- "default" or "xlib": Traditional Xlib-based backend (default)
51+
- "xgetimage": XCB-based backend using XGetImage
52+
- "xshmgetimage": XCB-based backend using XShmGetImage (falls back to XGetImage if unavailable)
53+
54+
.. function:: MSS(*args, **kwargs)
55+
56+
Alias for :func:`mss` for backward compatibility.
57+
58+
59+
Xlib Backend
60+
^^^^^^^^^^^^
61+
62+
.. module:: mss.linux.xlib
63+
64+
Traditional Xlib-based backend (default).
65+
3666
.. attribute:: CFUNCTIONS
3767

3868
.. versionadded:: 6.1.0
@@ -79,6 +109,55 @@ GNU/Linux
79109

80110
.. versionadded:: 8.0.0
81111

112+
113+
XGetImage Backend
114+
^^^^^^^^^^^^^^^^^
115+
116+
.. module:: mss.linux.xgetimage
117+
118+
XCB-based backend using XGetImage protocol.
119+
120+
.. class:: MSS
121+
122+
XCB implementation using XGetImage for screenshot capture.
123+
124+
125+
XShmGetImage Backend
126+
^^^^^^^^^^^^^^^^^^^^
127+
128+
.. module:: mss.linux.xshmgetimage
129+
130+
XCB-based backend using XShmGetImage protocol with shared memory.
131+
132+
.. class:: ShmStatus
133+
134+
Enum describing the availability of the X11 MIT-SHM extension used by the backend.
135+
136+
.. attribute:: UNKNOWN
137+
138+
Initial state before any capture confirms availability or failure.
139+
140+
.. attribute:: AVAILABLE
141+
142+
Shared-memory capture works and will continue to be used.
143+
144+
.. attribute:: UNAVAILABLE
145+
146+
Shared-memory capture failed; MSS will use XGetImage.
147+
148+
.. class:: MSS
149+
150+
XCB implementation using XShmGetImage for screenshot capture.
151+
Falls back to XGetImage if shared memory extension is unavailable.
152+
153+
.. attribute:: shm_status
154+
155+
Current shared-memory availability, using :class:`mss.linux.xshmgetimage.ShmStatus`.
156+
157+
.. attribute:: shm_fallback_reason
158+
159+
Optional string describing why the backend fell back to XGetImage when MIT-SHM is unavailable.
160+
82161
Windows
83162
-------
84163

docs/source/developers.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,12 @@ To build the documentation, simply type::
5050

5151
$ python -m pip install -e '.[docs]'
5252
$ sphinx-build -d docs docs/source docs_out --color -W -bhtml
53+
54+
55+
XCB Code Generator
56+
==================
57+
58+
The GNU/Linux XCB backends rely on generated ctypes bindings. If you need to
59+
add new XCB requests or types, do **not** edit ``src/mss/linux/xcbgen.py`` by
60+
hand. Instead, follow the workflow described in ``src/xcbproto/README.md``,
61+
which explains how to update ``gen_xcb_to_py.py`` and regenerate the bindings.

docs/source/examples.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,15 @@ You can handle data using a custom class:
103103

104104
.. versionadded:: 3.1.0
105105

106+
GNU/Linux XShm backend
107+
----------------------
108+
109+
Select the XShmGetImage backend explicitly and inspect whether it is active or
110+
falling back to XGetImage::
111+
112+
.. literalinclude:: examples/linux_xshm_backend.py
113+
:lines: 7-
114+
106115
PIL
107116
===
108117

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
"""This is part of the MSS Python's module.
2+
Source: https://github.com/BoboTiG/python-mss.
3+
4+
Select the XShmGetImage backend explicitly and inspect its status.
5+
"""
6+
7+
from mss.linux.xshmgetimage import MSS as mss
8+
9+
with mss() as sct:
10+
screenshot = sct.grab(sct.monitors[1])
11+
print(f"Captured screenshot dimensions: {screenshot.size.width}x{screenshot.size.height}")
12+
13+
print(f"shm_status: {sct.shm_status.name}")
14+
if sct.shm_fallback_reason:
15+
print(f"Falling back to XGetImage because: {sct.shm_fallback_reason}")
16+
else:
17+
print("MIT-SHM capture active.")

docs/source/usage.rst

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Usage
55
Import
66
======
77

8-
So MSS can be used as simply as::
8+
MSS can be used as simply as::
99

1010
from mss import mss
1111

@@ -20,6 +20,11 @@ Or import the good one based on your operating system::
2020
# Microsoft Windows
2121
from mss.windows import MSS as mss
2222

23+
On GNU/Linux you can also import a specific backend (see :ref:`backends`)
24+
directly when you need a particular implementation, for example::
25+
26+
from mss.linux.xshmgetimage import MSS as mss
27+
2328

2429
Instance
2530
========
@@ -49,19 +54,57 @@ This is a much better usage, memory efficient::
4954
Also, it is a good thing to save the MSS instance inside an attribute of your class and calling it when needed.
5055

5156

57+
.. _backends:
58+
59+
Backends
60+
--------
61+
62+
Some platforms have multiple ways to take screenshots. In MSS, these are known as *backends*. The :py:func:`mss` functions will normally autodetect which one is appropriate for your situation, but you can override this if you want. For instance, you may know that your specific situation requires a particular backend.
63+
64+
If you want to choose a particular backend, you can use the :py::`backend` keyword to :py:func:`mss`:::
65+
66+
with mss(backend="xgetimage") as sct:
67+
...
68+
69+
Instead, you can also directly import the backend you want to use:::
70+
71+
from mss.linux.xgetimage import MSS as mss
72+
73+
Currently, only the GNU/Linux implementation has multiple backends. These are described in their own section below.
74+
75+
5276
GNU/Linux
5377
---------
5478

55-
On GNU/Linux, you can specify which display to use (useful for distant screenshots via SSH)::
79+
Display
80+
^^^^^^^
81+
82+
On GNU/Linux, the default display is taken from the :envvar:`DISPLAY` environment variable. You can instead specify which display to use (useful for distant screenshots via SSH) using the :keyword:`display` keyword::
5683

5784
with mss(display=":0.0") as sct:
58-
# ...
85+
...
5986

6087
A more specific example (only valid on GNU/Linux):
6188

6289
.. literalinclude:: examples/linux_display_keyword.py
6390
:lines: 9-
6491

92+
Backends
93+
^^^^^^^^
94+
95+
The GNU/Linux implementation has multiple backends (see :ref:`backends`), or ways it can take screenshots. The :py:func:`mss.mss` and :py:func:`mss.linux.mss` functions will normally autodetect which one is appropriate, but you can override this if you want.
96+
97+
There are three available backends.
98+
99+
:py:mod:`xlib` (default)
100+
The legacy backend, based on :c:func:`XGetImage`. This backend is not being improved anymore. It is only provided in case the newer backends don't work for some reason.
101+
102+
:py:mod:`xgetimage`
103+
A highly-compatible, but slow, backend, based on :c:func:`xcb_get_image`. This backend is the slowest of the new backends, but works in all situations. You can use this if you know that :py:mod:`xshmgetimage` won't work.
104+
105+
:py:mod:`xshmgetimage`
106+
The fastest backend, based on :c:func:`xcb_shm_get_image`. This backend is the fastest, about three times faster than :py:mod:`xgetimage`. However, it doesn't work for remote screenshots, such as over SSH. If you use it with a remote display, then it will automatically switch to :py:mod:`xgetimage` instead. It's always safe to use this backend.
107+
65108

66109
Command Line
67110
============

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ ignore = [
179179
"docs/source/*" = [
180180
"ERA001", # commented code
181181
"INP001", # file `xxx` is part of an implicit namespace package
182+
"N811", # importing constant (MSS) as non-constant (mss)
182183
]
183184
"src/tests/*" = [
184185
"FBT001", # boolean-typed positional argument in function definition
@@ -191,4 +192,4 @@ ignore = [
191192
]
192193

193194
[tool.ruff.per-file-target-version]
194-
"src/xcbproto/*" = "py312"
195+
"src/xcbproto/*" = "py312"

src/mss/base.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,15 @@
1818

1919
from mss.models import Monitor, Monitors
2020

21+
# Prior to 3.11, Python didn't have the Self type. typing_extensions does, but we don't want to depend on it.
22+
try:
23+
from typing import Self
24+
except ImportError: # pragma: nocover
25+
try:
26+
from typing_extensions import Self
27+
except ImportError: # pragma: nocover
28+
Self = Any # type: ignore[assignment]
29+
2130
try:
2231
from datetime import UTC
2332
except ImportError: # pragma: nocover
@@ -58,7 +67,7 @@ def __init__(
5867
msg = 'The only valid backend on this platform is "default".'
5968
raise ScreenShotError(msg)
6069

61-
def __enter__(self) -> MSSBase: # noqa:PYI034
70+
def __enter__(self) -> Self:
6271
"""For the cool call `with MSS() as mss:`."""
6372
return self
6473

src/mss/factory.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ def mss(**kwargs: Any) -> MSSBase:
2929
if os_ == "linux":
3030
from mss import linux # noqa: PLC0415
3131

32-
return linux.MSS(**kwargs)
32+
# Linux has its own factory to choose the backend.
33+
return linux.mss(**kwargs)
3334

3435
if os_ == "windows":
3536
from mss import windows # noqa: PLC0415

0 commit comments

Comments
 (0)