@@ -182,14 +182,32 @@ class XWindowAttributes(Structure):
182182
183183
184184_ERROR = {}
185+ _X11 = find_library ("X11" )
186+ _XFIXES = find_library ("Xfixes" )
187+ _XRANDR = find_library ("Xrandr" )
188+
189+
190+ @CFUNCTYPE (c_int , POINTER (Display ), POINTER (Event ))
191+ def _default_error_handler (display : Display , event : Event ) -> int :
192+ """
193+ Specifies the default program's supplied error handler.
194+ It's useful when exiting MSS to prevent letting `_error_handler()` as default handler.
195+ Doing so would crash when using Tk/Tkinter, see issue #220.
196+
197+ Interesting technical stuff can be found here:
198+ https://core.tcl-lang.org/tk/file?name=generic/tkError.c&ci=a527ef995862cb50
199+ https://github.com/tcltk/tk/blob/b9cdafd83fe77499ff47fa373ce037aff3ae286a/generic/tkError.c
200+ """
201+ # pylint: disable=unused-argument
202+ return 0 # pragma: nocover
185203
186204
187205@CFUNCTYPE (c_int , POINTER (Display ), POINTER (Event ))
188206def _error_handler (display : Display , event : Event ) -> int :
189207 """Specifies the program's supplied error handler."""
190208
191209 # Get the specific error message
192- xlib = cdll .LoadLibrary (find_library ( "X11" ) ) # type: ignore[arg-type]
210+ xlib = cdll .LoadLibrary (_X11 ) # type: ignore[arg-type]
193211 get_error = xlib .XGetErrorText
194212 get_error .argtypes = [POINTER (Display ), c_int , c_char_p , c_int ]
195213 get_error .restype = c_void_p
@@ -278,24 +296,21 @@ def __init__(self, /, **kwargs: Any) -> None:
278296 if b":" not in display :
279297 raise ScreenShotError (f"Bad display value: { display !r} ." )
280298
281- x11 = find_library ("X11" )
282- if not x11 :
299+ if not _X11 :
283300 raise ScreenShotError ("No X11 library found." )
284- self .xlib = cdll .LoadLibrary (x11 )
301+ self .xlib = cdll .LoadLibrary (_X11 )
285302
286303 # Install the error handler to prevent interpreter crashes:
287304 # any error will raise a ScreenShotError exception.
288305 self .xlib .XSetErrorHandler (_error_handler )
289306
290- xrandr = find_library ("Xrandr" )
291- if not xrandr :
307+ if not _XRANDR :
292308 raise ScreenShotError ("No Xrandr extension found." )
293- self .xrandr = cdll .LoadLibrary (xrandr )
309+ self .xrandr = cdll .LoadLibrary (_XRANDR )
294310
295311 if self .with_cursor :
296- xfixes = find_library ("Xfixes" )
297- if xfixes :
298- self .xfixes = cdll .LoadLibrary (xfixes )
312+ if _XFIXES :
313+ self .xfixes = cdll .LoadLibrary (_XFIXES )
299314 else :
300315 self .with_cursor = False
301316
@@ -314,10 +329,15 @@ def __init__(self, /, **kwargs: Any) -> None:
314329 self ._handles .drawable = cast (self ._handles .root , POINTER (Display ))
315330
316331 def close (self ) -> None :
332+ # Remove our error handler
333+ self .xlib .XSetErrorHandler (_default_error_handler )
334+
335+ # Clean-up
317336 if self ._handles .display is not None :
318337 self .xlib .XCloseDisplay (self ._handles .display )
319338 self ._handles .display = None
320339
340+ # Also empty the error dict
321341 _ERROR .clear ()
322342
323343 def _is_extension_enabled (self , name : str , / ) -> bool :
@@ -350,7 +370,8 @@ def _set_cfunctions(self) -> None:
350370 }
351371 for func , (attr , argtypes , restype ) in CFUNCTIONS .items ():
352372 with suppress (AttributeError ):
353- cfactory (attrs [attr ], func , argtypes , restype , errcheck = _validate )
373+ errcheck = None if func == "XSetErrorHandler" else _validate
374+ cfactory (attrs [attr ], func , argtypes , restype , errcheck = errcheck )
354375
355376 def _monitors_impl (self ) -> None :
356377 """Get positions of monitors. It will populate self._monitors."""
0 commit comments