python-mss: Unjustified Screenshot error after closing a Tkinter Toplevel (Linux)
General information:
- OS name: Ubuntu Linux
- OS version: 22.04
- OS architecture: 64 bits
- Resolutions:
- Monitor 1: 3440x1440 (issue occurs at all resolutions)
- Python version: 3.10.6
- MSS version: 6.1.0 & 7.0.1
For GNU/Linux users:
- Display server protocol and version, if known: X11 server
- Desktop Environment: ubuntu:GNOME
- Composite Window Manager name and version: X.Org v: 1.21.1.3, compositor: gnome-shell v: 42.5
Description of the warning/error
— The issue (and solution) is described in detail here —
In summary, the following error occurs when trying to instantiate an mss object after opening/closing a Tkinter Toplevel window. This error does not occur on Windows.
Full message
File "/home/my_project/src/utilities/geometry.py", line 64, in screenshot
with mss.mss() as sct:
File "/home/my_project/env/lib/python3.10/site-packages/mss/factory.py", line 34, in mss
return linux.MSS(**kwargs)
File "/home/my_project/env/lib/python3.10/site-packages/mss/linux.py", line 297, in __init__
self.root = self.xlib.XDefaultRootWindow(self._get_display(display))
File "/home/my_project/env/lib/python3.10/site-packages/mss/linux.py", line 184, in validate
raise ScreenShotError(f"{func.__name__}() failed", details=details)
mss.exception.ScreenShotError: XDefaultRootWindow() failed
Screenshot error: XDefaultRootWindow() failed, {'retval': <mss.linux.LP_XWindowAttributes object at 0x7f31d8d38ac0>,
'args': (<mss.linux.LP_Display object at 0x7f31d8d38740>,)}
Other details
The following code can be used to reproduce the error. Simply run this program and use the GUI button to open a new window that allows you to take a screenshot - then close the pop-up window and attempt to repeat the process.
import tkinter as tk
import mss
import mss.tools
def take_screenshot():
with mss.mss() as sct:
screen_part = {"top": 370, "left": 1090, "width": 80, "height": 390}
sct_img = sct.grab(screen_part)
mss.tools.to_png(sct_img.rgb, sct_img.size, output="./output.png")
def create_top_level_win():
top_level_win = tk.Toplevel(root)
take_screenshot_btn = tk.Button(top_level_win, text="Take screenshot", command=take_screenshot)
take_screenshot_btn.pack()
root = tk.Tk()
btn = tk.Button(root, text="Open TopLevel", command=create_top_level_win)
btn.pack()
root.mainloop()
A temporary workaround is to reuse a single mss object throughout the application, like so:
sct = mss.mss()
def take_screenshot():
global sct
screen_part = {"top": 370, "left": 1090, "width": 80, "height": 390}
sct_img = sct.grab(screen_part)
mss.tools.to_png(sct_img.rgb, sct_img.size, output="./output.png")
On StackOverflow, one answer suggests that the bug is due to “the current implementation of MSS changing the current X11 error handler and leaving it afterwards, which causes a conflict with Tcl/Tk (the backend of Python Tkinter), see here for details”
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Comments: 28 (21 by maintainers)
Commits related to this issue
- test: improve #220 test case — committed to BoboTiG/python-mss by BoboTiG a year ago
- Fix issue #220 by letting close() restore the previous error handler. — committed to relent95/python-mss by relent95 a year ago
- linux: fix issue #220 by letting close() restore the previous error handler. (#241) — committed to BoboTiG/python-mss by relent95 a year ago
IMHO, the current fix has a potential of another side effect, because the previous X11 error handler is not restored. The previous error handler needs to be backed up in the
MSS.__init__(). (TheXSetErrorHandler()returns the previous error handler.) And the backed up handler needs to be restored in theMSS.close().Looks like it’s resolved! Thanks for checking this out!
If #224 may not fix the issue, it will likely fix another issue regarding that any X11 error would not be cleared, and so subsequent legitimate calls to any X11 function would fail. I refactored that part, and I think it will help in your case, and your tests will be critical 😃
You should just use the version of MSS from the
masterbranch because I merged the PR.