Fix a rare crash in some X11 implementations (details below).

This commit is contained in:
Glenn Watson 2015-07-17 08:07:46 +10:00 committed by Paul Rouget
parent e90f377b9f
commit 86408438fc

View file

@ -38,6 +38,13 @@ fn with_c_str<F, T>(s: &str, f: F) -> T where F: FnOnce(*const libc::c_char) ->
f(c_str.as_ptr()) f(c_str.as_ptr())
} }
struct WindowProxyData {
display: Arc<XConnection>,
window: ffi::Window,
}
unsafe impl Send for WindowProxyData {}
pub struct XWindow { pub struct XWindow {
display: Arc<XConnection>, display: Arc<XConnection>,
window: ffi::Window, window: ffi::Window,
@ -48,6 +55,7 @@ pub struct XWindow {
ic: ffi::XIC, ic: ffi::XIC,
im: ffi::XIM, im: ffi::XIM,
colormap: ffi::Colormap, colormap: ffi::Colormap,
window_proxy_data: Arc<Mutex<Option<WindowProxyData>>>,
} }
pub enum Context { pub enum Context {
@ -65,6 +73,10 @@ unsafe impl Sync for Window {}
impl Drop for XWindow { impl Drop for XWindow {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { unsafe {
// Clear out the window proxy data arc, so that any window proxy objects
// are no longer able to send messages to this window.
*self.window_proxy_data.lock().unwrap() = None;
// we don't call MakeCurrent(0, 0) because we are not sure that the context // we don't call MakeCurrent(0, 0) because we are not sure that the context
// is still the current one // is still the current one
self.context = Context::None; self.context = Context::None;
@ -86,25 +98,29 @@ impl Drop for XWindow {
#[derive(Clone)] #[derive(Clone)]
pub struct WindowProxy { pub struct WindowProxy {
x: Arc<XWindow>, data: Arc<Mutex<Option<WindowProxyData>>>,
} }
impl WindowProxy { impl WindowProxy {
pub fn wakeup_event_loop(&self) { pub fn wakeup_event_loop(&self) {
let window_proxy_data = self.data.lock().unwrap();
if let Some(ref data) = *window_proxy_data {
let mut xev = ffi::XClientMessageEvent { let mut xev = ffi::XClientMessageEvent {
type_: ffi::ClientMessage, type_: ffi::ClientMessage,
window: self.x.window, window: data.window,
format: 32, format: 32,
message_type: 0, message_type: 0,
serial: 0, serial: 0,
send_event: 0, send_event: 0,
display: self.x.display.display, display: data.display.display,
data: unsafe { mem::zeroed() }, data: unsafe { mem::zeroed() },
}; };
unsafe { unsafe {
(self.x.display.xlib.XSendEvent)(self.x.display.display, self.x.window, 0, 0, mem::transmute(&mut xev)); (data.display.xlib.XSendEvent)(data.display.display, data.window, 0, 0, mem::transmute(&mut xev));
(self.x.display.xlib.XFlush)(self.x.display.display); (data.display.xlib.XFlush)(data.display.display);
}
} }
} }
} }
@ -513,6 +529,12 @@ impl Window {
}; };
// creating the window object // creating the window object
let window_proxy_data = WindowProxyData {
display: display.clone(),
window: window,
};
let window_proxy_data = Arc::new(Mutex::new(Some(window_proxy_data)));
let window = Window { let window = Window {
x: Arc::new(XWindow { x: Arc::new(XWindow {
display: display.clone(), display: display.clone(),
@ -524,6 +546,7 @@ impl Window {
is_fullscreen: is_fullscreen, is_fullscreen: is_fullscreen,
xf86_desk_mode: xf86_desk_mode, xf86_desk_mode: xf86_desk_mode,
colormap: cmap, colormap: cmap,
window_proxy_data: window_proxy_data,
}), }),
is_closed: AtomicBool::new(false), is_closed: AtomicBool::new(false),
wm_delete_window: wm_delete_window, wm_delete_window: wm_delete_window,
@ -603,7 +626,7 @@ impl Window {
pub fn create_window_proxy(&self) -> WindowProxy { pub fn create_window_proxy(&self) -> WindowProxy {
WindowProxy { WindowProxy {
x: self.x.clone() data: self.x.window_proxy_data.clone()
} }
} }