diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a7fff41..903c3c70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ - On Windows, fix use after free crash during window destruction. - On Web, fix `WindowEvent::ReceivedCharacter` never being sent on key input. - On macOS, fix compilation when targeting aarch64 +- On X11, fix `Window::request_redraw` not waking the event loop. # 0.23.0 (2020-10-02) diff --git a/src/platform_impl/linux/x11/mod.rs b/src/platform_impl/linux/x11/mod.rs index 0849c0f9..ffb9fc6e 100644 --- a/src/platform_impl/linux/x11/mod.rs +++ b/src/platform_impl/linux/x11/mod.rs @@ -24,7 +24,7 @@ pub use self::{ use std::{ cell::RefCell, - collections::{HashMap, HashSet}, + collections::HashMap, ffi::CStr, mem::{self, MaybeUninit}, ops::Deref, @@ -32,7 +32,7 @@ use std::{ ptr, rc::Rc, slice, - sync::{mpsc, Arc, Mutex, Weak}, + sync::{mpsc, Arc, Weak}, time::{Duration, Instant}, }; @@ -58,6 +58,7 @@ use crate::{ const X_TOKEN: Token = Token(0); const USER_TOKEN: Token = Token(1); +const REDRAW_TOKEN: Token = Token(2); pub struct EventLoopWindowTarget { xconn: Arc, @@ -67,13 +68,14 @@ pub struct EventLoopWindowTarget { root: ffi::Window, ime: RefCell, windows: RefCell>>, - pending_redraws: Arc>>, + redraw_sender: Sender, _marker: ::std::marker::PhantomData, } pub struct EventLoop { poll: Poll, event_processor: EventProcessor, + redraw_channel: Receiver, user_channel: Receiver, user_sender: Sender, target: Rc>, @@ -174,32 +176,16 @@ impl EventLoop { xconn.update_cached_wm_info(root); - let pending_redraws: Arc>> = Default::default(); - let mut mod_keymap = ModifierKeymap::new(); mod_keymap.reset_from_x_connection(&xconn); - let target = Rc::new(RootELW { - p: super::EventLoopWindowTarget::X(EventLoopWindowTarget { - ime, - root, - windows: Default::default(), - _marker: ::std::marker::PhantomData, - ime_sender, - xconn, - wm_delete_window, - net_wm_ping, - pending_redraws: pending_redraws.clone(), - }), - _marker: ::std::marker::PhantomData, - }); - let poll = Poll::new().unwrap(); let (user_sender, user_channel) = channel(); + let (redraw_sender, redraw_channel) = channel(); poll.register( - &EventedFd(&get_xtarget(&target).xconn.x11_fd), + &EventedFd(&xconn.x11_fd), X_TOKEN, Ready::readable(), PollOpt::level(), @@ -214,6 +200,29 @@ impl EventLoop { ) .unwrap(); + poll.register( + &redraw_channel, + REDRAW_TOKEN, + Ready::readable(), + PollOpt::level(), + ) + .unwrap(); + + let target = Rc::new(RootELW { + p: super::EventLoopWindowTarget::X(EventLoopWindowTarget { + ime, + root, + windows: Default::default(), + _marker: ::std::marker::PhantomData, + ime_sender, + xconn, + wm_delete_window, + net_wm_ping, + redraw_sender, + }), + _marker: ::std::marker::PhantomData, + }); + let event_processor = EventProcessor { target: target.clone(), dnd, @@ -239,6 +248,7 @@ impl EventLoop { let result = EventLoop { poll, + redraw_channel, user_channel, user_sender, event_processor, @@ -277,8 +287,6 @@ impl EventLoop { // Process all pending events self.drain_events(&mut callback, &mut control_flow); - let wt = get_xtarget(&self.target); - // Empty the user event buffer { while let Ok(event) = self.user_channel.try_recv() { @@ -301,12 +309,10 @@ impl EventLoop { } // Empty the redraw requests { - // Release the lock to prevent deadlock - let windows: Vec<_> = wt.pending_redraws.lock().unwrap().drain().collect(); - - for wid in windows { + while let Ok(window_id) = self.redraw_channel.try_recv() { + let window_id = crate::window::WindowId(super::WindowId::X(window_id)); sticky_exit_callback( - Event::RedrawRequested(crate::window::WindowId(super::WindowId::X(wid))), + Event::RedrawRequested(window_id), &self.target, &mut control_flow, &mut callback, @@ -408,7 +414,7 @@ impl EventLoop { super::WindowId::X(wid), )) = event { - wt.pending_redraws.lock().unwrap().insert(wid); + wt.redraw_sender.send(wid).unwrap(); } else { callback(event, window_target, control_flow); } diff --git a/src/platform_impl/linux/x11/window.rs b/src/platform_impl/linux/x11/window.rs index 058b3aa7..47be20c8 100644 --- a/src/platform_impl/linux/x11/window.rs +++ b/src/platform_impl/linux/x11/window.rs @@ -1,8 +1,6 @@ use raw_window_handle::unix::XlibHandle; use std::{ - cmp, - collections::HashSet, - env, + cmp, env, ffi::CString, mem::{self, replace, MaybeUninit}, os::raw::*, @@ -12,6 +10,7 @@ use std::{ }; use libc; +use mio_extras::channel::Sender; use parking_lot::Mutex; use crate::{ @@ -104,7 +103,7 @@ pub struct UnownedWindow { cursor_visible: Mutex, ime_sender: Mutex, pub shared_state: Mutex, - pending_redraws: Arc<::std::sync::Mutex>>, + redraw_sender: Sender, } impl UnownedWindow { @@ -249,7 +248,7 @@ impl UnownedWindow { cursor_visible: Mutex::new(true), ime_sender: Mutex::new(event_loop.ime_sender.clone()), shared_state: SharedState::new(guessed_monitor, window_attrs.visible), - pending_redraws: event_loop.pending_redraws.clone(), + redraw_sender: event_loop.redraw_sender.clone(), }; // Title must be set before mapping. Some tiling window managers (i.e. i3) use the window @@ -1314,10 +1313,7 @@ impl UnownedWindow { #[inline] pub fn request_redraw(&self) { - self.pending_redraws - .lock() - .unwrap() - .insert(WindowId(self.xwindow)); + self.redraw_sender.send(WindowId(self.xwindow)).unwrap(); } #[inline]