@@ -3,11 +3,14 @@ use std::fmt::{Debug, Formatter};
33use x11:: xlib;
44
55use std:: panic:: AssertUnwindSafe ;
6- use std:: sync:: atomic:: { AtomicPtr , Ordering } ;
76use std:: sync:: Mutex ;
87
9- static CURRENT_ERROR_PTR : AtomicPtr < Mutex < Option < xlib:: XErrorEvent > > > =
10- AtomicPtr :: new ( :: std:: ptr:: null_mut ( ) ) ;
8+ thread_local ! {
9+ /// Used as part of [`XerrorHandler::handle()`]. When an X11 error occurs during this function,
10+ /// the error gets copied to this mutex after which the program is allowed to resume. The error
11+ /// can then be converted to a regular Rust Result value afterwards.
12+ static CURRENT_X11_ERROR : Mutex <Option <xlib:: XErrorEvent >> = Mutex :: new( None ) ;
13+ }
1114
1215/// A helper struct for safe X11 error handling
1316pub struct XErrorHandler < ' a > {
@@ -33,24 +36,15 @@ impl<'a> XErrorHandler<'a> {
3336 /// Sets up a temporary X11 error handler for the duration of the given closure, and allows
3437 /// that closure to check on the latest X11 error at any time
3538 pub fn handle < T , F : FnOnce ( & mut XErrorHandler ) -> T > (
36- display : * mut xlib:: Display ,
37- handler : F ,
39+ display : * mut xlib:: Display , handler : F ,
3840 ) -> T {
3941 unsafe extern "C" fn error_handler (
40- _dpy : * mut xlib:: Display ,
41- err : * mut xlib:: XErrorEvent ,
42+ _dpy : * mut xlib:: Display , err : * mut xlib:: XErrorEvent ,
4243 ) -> i32 {
4344 // SAFETY: the error pointer should be safe to copy
4445 let err = * err;
45- // SAFETY: the ptr can only point to a valid instance or be null
46- let mutex = CURRENT_ERROR_PTR . load ( Ordering :: SeqCst ) . as_ref ( ) ;
47- let mutex = if let Some ( mutex) = mutex {
48- mutex
49- } else {
50- return 2 ;
51- } ;
52-
53- match mutex. lock ( ) {
46+
47+ CURRENT_X11_ERROR . with ( |mutex| match mutex. lock ( ) {
5448 Ok ( mut current_error) => {
5549 * current_error = Some ( err) ;
5650 0
@@ -62,33 +56,31 @@ impl<'a> XErrorHandler<'a> {
6256 ) ;
6357 1
6458 }
65- }
59+ } )
6660 }
6761
6862 // Flush all possible previous errors
6963 unsafe {
7064 xlib:: XSync ( display, 0 ) ;
7165 }
7266
73- let mut mutex = Mutex :: new ( None ) ;
74- CURRENT_ERROR_PTR . store ( & mut mutex, Ordering :: SeqCst ) ;
75-
76- let old_handler = unsafe { xlib:: XSetErrorHandler ( Some ( error_handler) ) } ;
77- let panic_result = std:: panic:: catch_unwind ( AssertUnwindSafe ( || {
78- let mut h = XErrorHandler {
79- display,
80- mutex : & mutex,
81- } ;
82- handler ( & mut h)
83- } ) ) ;
84- // Whatever happened, restore old error handler
85- unsafe { xlib:: XSetErrorHandler ( old_handler) } ;
86- CURRENT_ERROR_PTR . store ( :: core:: ptr:: null_mut ( ) , Ordering :: SeqCst ) ;
87-
88- match panic_result {
89- Ok ( v) => v,
90- Err ( e) => std:: panic:: resume_unwind ( e) ,
91- }
67+ CURRENT_X11_ERROR . with ( |mutex| {
68+ // Make sure to clear any errors from the last call to this function
69+ * mutex. lock ( ) . unwrap ( ) = None ;
70+
71+ let old_handler = unsafe { xlib:: XSetErrorHandler ( Some ( error_handler) ) } ;
72+ let panic_result = std:: panic:: catch_unwind ( AssertUnwindSafe ( || {
73+ let mut h = XErrorHandler { display, mutex : & mutex } ;
74+ handler ( & mut h)
75+ } ) ) ;
76+ // Whatever happened, restore old error handler
77+ unsafe { xlib:: XSetErrorHandler ( old_handler) } ;
78+
79+ match panic_result {
80+ Ok ( v) => v,
81+ Err ( e) => std:: panic:: resume_unwind ( e) ,
82+ }
83+ } )
9284 }
9385}
9486
0 commit comments