2222 c_ushort ,
2323 c_void_p ,
2424)
25- from types import SimpleNamespace
2625from typing import Any , Dict , Optional , Tuple , Union
2726
2827from .base import MSSBase , lock
3332__all__ = ("MSS" ,)
3433
3534
36- ERROR = SimpleNamespace (details = None )
3735PLAINMASK = 0x00FFFFFF
3836ZPIXMAP = 2
3937
@@ -158,29 +156,46 @@ class XRRCrtcInfo(Structure):
158156 ]
159157
160158
159+ _ERROR = {}
160+
161+
161162@CFUNCTYPE (c_int , POINTER (Display ), POINTER (Event ))
162- def error_handler (_ : Any , event : Any ) -> int :
163+ def error_handler (display : Display , event : Event ) -> int :
163164 """Specifies the program's supplied error handler."""
165+ x11 = ctypes .util .find_library ("X11" )
166+ if not x11 :
167+ return 0
168+
169+ # Get the specific error message
170+ xlib = ctypes .cdll .LoadLibrary (x11 )
171+ get_error = getattr (xlib , "XGetErrorText" )
172+ get_error .argtypes = [POINTER (Display ), c_int , c_char_p , c_int ]
173+ get_error .restype = c_void_p
174+
164175 evt = event .contents
165- ERROR .details = {
166- "type" : evt .type ,
167- "serial" : evt .serial ,
176+ error = ctypes .create_string_buffer (1024 )
177+ get_error (display , evt .error_code , error , len (error ))
178+
179+ _ERROR [threading .current_thread ()] = {
180+ "error" : error .value .decode ("utf-8" ),
168181 "error_code" : evt .error_code ,
169- "request_code" : evt .request_code ,
170182 "minor_code" : evt .minor_code ,
183+ "request_code" : evt .request_code ,
184+ "serial" : evt .serial ,
185+ "type" : evt .type ,
171186 }
187+
172188 return 0
173189
174190
175- def validate (
176- retval : int , func : Any , args : Tuple [Any , Any ]
177- ) -> Optional [Tuple [Any , Any ]]:
191+ def validate (retval : int , func : Any , args : Tuple [Any , Any ]) -> Tuple [Any , Any ]:
178192 """Validate the returned value of a Xlib or XRANDR function."""
179193
180- if retval != 0 and not ERROR .details :
194+ current_thread = threading .current_thread ()
195+ if retval != 0 and current_thread not in _ERROR :
181196 return args
182197
183- details = { "retval" : retval , "args" : args }
198+ details = _ERROR . pop ( current_thread , {})
184199 raise ScreenShotError (f"{ func .__name__ } () failed" , details = details )
185200
186201
@@ -196,7 +211,6 @@ def validate(
196211CFUNCTIONS : CFunctions = {
197212 "XDefaultRootWindow" : ("xlib" , [POINTER (Display )], POINTER (XWindowAttributes )),
198213 "XDestroyImage" : ("xlib" , [POINTER (XImage )], c_void_p ),
199- "XGetErrorText" : ("xlib" , [POINTER (Display ), c_int , c_char_p , c_int ], c_void_p ),
200214 "XGetImage" : (
201215 "xlib" ,
202216 [
@@ -331,15 +345,13 @@ def _get_display(self, disp: Optional[bytes] = None) -> int:
331345 Since the current thread and main thread are always alive, reuse their
332346 *display* value first.
333347 """
334- cur_thread , main_thread = threading .current_thread (), threading .main_thread ()
335- current_display = MSS ._display_dict .get (cur_thread ) or MSS ._display_dict .get (
336- main_thread
337- )
348+ current_thread = threading .current_thread ()
349+ current_display = MSS ._display_dict .get (current_thread )
338350 if current_display :
339351 display = current_display
340352 else :
341353 display = self .xlib .XOpenDisplay (disp )
342- MSS ._display_dict [cur_thread ] = display
354+ MSS ._display_dict [current_thread ] = display
343355 return display
344356
345357 def _set_cfunctions (self ) -> None :
@@ -360,27 +372,6 @@ def _set_cfunctions(self) -> None:
360372 restype = restype ,
361373 )
362374
363- def get_error_details (self ) -> Optional [Dict [str , Any ]]:
364- """Get more information about the latest X server error."""
365-
366- details : Dict [str , Any ] = {}
367-
368- if ERROR .details :
369- details = {"xerror_details" : ERROR .details }
370- ERROR .details = None
371- xserver_error = ctypes .create_string_buffer (1024 )
372- self .xlib .XGetErrorText (
373- self ._get_display (),
374- details .get ("xerror_details" , {}).get ("error_code" , 0 ),
375- xserver_error ,
376- len (xserver_error ),
377- )
378- xerror = xserver_error .value .decode ("utf-8" )
379- if xerror != "0" :
380- details ["xerror" ] = xerror
381-
382- return details
383-
384375 def _monitors_impl (self ) -> None :
385376 """Get positions of monitors. It will populate self._monitors."""
386377
0 commit comments