diff --git a/CHANGELOG.md b/CHANGELOG.md index 61254e27..6a00b88d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ - macOS now generates `VirtualKeyCode::LAlt` and `VirtualKeyCode::RAlt` instead of `None` for both. - On macOS, `VirtualKeyCode::RWin` and `VirtualKeyCode::LWin` are no longer switched. - On macOS, windows without decorations can once again be resized. +- Fixed race conditions when creating an `EventsLoop` on X11, most commonly manifesting as "[xcb] Unknown sequence number while processing queue". # Version 0.15.0 (2018-05-22) diff --git a/src/platform/linux/mod.rs b/src/platform/linux/mod.rs index 69b3045b..020420ad 100644 --- a/src/platform/linux/mod.rs +++ b/src/platform/linux/mod.rs @@ -49,8 +49,8 @@ pub struct PlatformSpecificWindowBuilderAttributes { pub x11_window_type: x11::util::WindowType, } -lazy_static!( - pub static ref X11_BACKEND: Result, XNotSupported> = { +thread_local!( + pub static X11_BACKEND: Result, XNotSupported> = { XConnection::new(Some(x_error_callback)).map(Arc::new) }; ); @@ -342,27 +342,29 @@ unsafe extern "C" fn x_error_callback( display: *mut x11::ffi::Display, event: *mut x11::ffi::XErrorEvent, ) -> c_int { - if let Ok(ref xconn) = *X11_BACKEND { - let mut buf: [c_char; 1024] = mem::uninitialized(); - (xconn.xlib.XGetErrorText)( - display, - (*event).error_code as c_int, - buf.as_mut_ptr(), - buf.len() as c_int, - ); - let description = CStr::from_ptr(buf.as_ptr()).to_string_lossy(); + X11_BACKEND.with(|result| { + if let &Ok(ref xconn) = result { + let mut buf: [c_char; 1024] = mem::uninitialized(); + (xconn.xlib.XGetErrorText)( + display, + (*event).error_code as c_int, + buf.as_mut_ptr(), + buf.len() as c_int, + ); + let description = CStr::from_ptr(buf.as_ptr()).to_string_lossy(); - let error = XError { - description: description.into_owned(), - error_code: (*event).error_code, - request_code: (*event).request_code, - minor_code: (*event).minor_code, - }; + let error = XError { + description: description.into_owned(), + error_code: (*event).error_code, + request_code: (*event).request_code, + minor_code: (*event).minor_code, + }; - eprintln!("[winit X11 error] {:#?}", error); + eprintln!("[winit X11 error] {:#?}", error); - *xconn.latest_error.lock() = Some(error); - } + *xconn.latest_error.lock() = Some(error); + } + }); // Fun fact: this return value is completely ignored. 0 } @@ -424,10 +426,14 @@ r#"Failed to initialize any backend! } pub fn new_x11() -> Result { - match *X11_BACKEND { - Ok(ref x) => Ok(EventsLoop::X(x11::EventsLoop::new(x.clone()))), - Err(ref err) => Err(err.clone()), - } + X11_BACKEND.with(|result| { + result + .as_ref() + .map(Arc::clone) + .map(x11::EventsLoop::new) + .map(EventsLoop::X) + .map_err(|err| err.clone()) + }) } #[inline] diff --git a/src/platform/linux/x11/ime/input_method.rs b/src/platform/linux/x11/ime/input_method.rs index 7af30126..fee0a14f 100644 --- a/src/platform/linux/x11/ime/input_method.rs +++ b/src/platform/linux/x11/ime/input_method.rs @@ -5,12 +5,20 @@ use std::sync::Arc; use std::os::raw::c_char; use std::ffi::{CStr, CString, IntoStringError}; +use parking_lot::Mutex; + use super::{ffi, util, XConnection, XError}; +lazy_static! { + static ref GLOBAL_LOCK: Mutex<()> = Default::default(); +} + unsafe fn open_im( xconn: &Arc, locale_modifiers: &CStr, ) -> Option { + let _lock = GLOBAL_LOCK.lock(); + // XSetLocaleModifiers returns... // * The current locale modifiers if it's given a NULL pointer. // * The new locale modifiers if we succeeded in setting them.