X11: Fix request_redraw not waking the event loop (#1756)

This commit is contained in:
Murarth 2020-11-05 16:42:03 -07:00 committed by GitHub
parent 3a077ff211
commit 45e4fd6ec1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 41 additions and 38 deletions

View file

@ -9,6 +9,7 @@
- On Windows, fix use after free crash during window destruction. - On Windows, fix use after free crash during window destruction.
- On Web, fix `WindowEvent::ReceivedCharacter` never being sent on key input. - On Web, fix `WindowEvent::ReceivedCharacter` never being sent on key input.
- On macOS, fix compilation when targeting aarch64 - On macOS, fix compilation when targeting aarch64
- On X11, fix `Window::request_redraw` not waking the event loop.
# 0.23.0 (2020-10-02) # 0.23.0 (2020-10-02)

View file

@ -24,7 +24,7 @@ pub use self::{
use std::{ use std::{
cell::RefCell, cell::RefCell,
collections::{HashMap, HashSet}, collections::HashMap,
ffi::CStr, ffi::CStr,
mem::{self, MaybeUninit}, mem::{self, MaybeUninit},
ops::Deref, ops::Deref,
@ -32,7 +32,7 @@ use std::{
ptr, ptr,
rc::Rc, rc::Rc,
slice, slice,
sync::{mpsc, Arc, Mutex, Weak}, sync::{mpsc, Arc, Weak},
time::{Duration, Instant}, time::{Duration, Instant},
}; };
@ -58,6 +58,7 @@ use crate::{
const X_TOKEN: Token = Token(0); const X_TOKEN: Token = Token(0);
const USER_TOKEN: Token = Token(1); const USER_TOKEN: Token = Token(1);
const REDRAW_TOKEN: Token = Token(2);
pub struct EventLoopWindowTarget<T> { pub struct EventLoopWindowTarget<T> {
xconn: Arc<XConnection>, xconn: Arc<XConnection>,
@ -67,13 +68,14 @@ pub struct EventLoopWindowTarget<T> {
root: ffi::Window, root: ffi::Window,
ime: RefCell<Ime>, ime: RefCell<Ime>,
windows: RefCell<HashMap<WindowId, Weak<UnownedWindow>>>, windows: RefCell<HashMap<WindowId, Weak<UnownedWindow>>>,
pending_redraws: Arc<Mutex<HashSet<WindowId>>>, redraw_sender: Sender<WindowId>,
_marker: ::std::marker::PhantomData<T>, _marker: ::std::marker::PhantomData<T>,
} }
pub struct EventLoop<T: 'static> { pub struct EventLoop<T: 'static> {
poll: Poll, poll: Poll,
event_processor: EventProcessor<T>, event_processor: EventProcessor<T>,
redraw_channel: Receiver<WindowId>,
user_channel: Receiver<T>, user_channel: Receiver<T>,
user_sender: Sender<T>, user_sender: Sender<T>,
target: Rc<RootELW<T>>, target: Rc<RootELW<T>>,
@ -174,32 +176,16 @@ impl<T: 'static> EventLoop<T> {
xconn.update_cached_wm_info(root); xconn.update_cached_wm_info(root);
let pending_redraws: Arc<Mutex<HashSet<WindowId>>> = Default::default();
let mut mod_keymap = ModifierKeymap::new(); let mut mod_keymap = ModifierKeymap::new();
mod_keymap.reset_from_x_connection(&xconn); 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 poll = Poll::new().unwrap();
let (user_sender, user_channel) = channel(); let (user_sender, user_channel) = channel();
let (redraw_sender, redraw_channel) = channel();
poll.register( poll.register(
&EventedFd(&get_xtarget(&target).xconn.x11_fd), &EventedFd(&xconn.x11_fd),
X_TOKEN, X_TOKEN,
Ready::readable(), Ready::readable(),
PollOpt::level(), PollOpt::level(),
@ -214,6 +200,29 @@ impl<T: 'static> EventLoop<T> {
) )
.unwrap(); .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 { let event_processor = EventProcessor {
target: target.clone(), target: target.clone(),
dnd, dnd,
@ -239,6 +248,7 @@ impl<T: 'static> EventLoop<T> {
let result = EventLoop { let result = EventLoop {
poll, poll,
redraw_channel,
user_channel, user_channel,
user_sender, user_sender,
event_processor, event_processor,
@ -277,8 +287,6 @@ impl<T: 'static> EventLoop<T> {
// Process all pending events // Process all pending events
self.drain_events(&mut callback, &mut control_flow); self.drain_events(&mut callback, &mut control_flow);
let wt = get_xtarget(&self.target);
// Empty the user event buffer // Empty the user event buffer
{ {
while let Ok(event) = self.user_channel.try_recv() { while let Ok(event) = self.user_channel.try_recv() {
@ -301,12 +309,10 @@ impl<T: 'static> EventLoop<T> {
} }
// Empty the redraw requests // Empty the redraw requests
{ {
// Release the lock to prevent deadlock while let Ok(window_id) = self.redraw_channel.try_recv() {
let windows: Vec<_> = wt.pending_redraws.lock().unwrap().drain().collect(); let window_id = crate::window::WindowId(super::WindowId::X(window_id));
for wid in windows {
sticky_exit_callback( sticky_exit_callback(
Event::RedrawRequested(crate::window::WindowId(super::WindowId::X(wid))), Event::RedrawRequested(window_id),
&self.target, &self.target,
&mut control_flow, &mut control_flow,
&mut callback, &mut callback,
@ -408,7 +414,7 @@ impl<T: 'static> EventLoop<T> {
super::WindowId::X(wid), super::WindowId::X(wid),
)) = event )) = event
{ {
wt.pending_redraws.lock().unwrap().insert(wid); wt.redraw_sender.send(wid).unwrap();
} else { } else {
callback(event, window_target, control_flow); callback(event, window_target, control_flow);
} }

View file

@ -1,8 +1,6 @@
use raw_window_handle::unix::XlibHandle; use raw_window_handle::unix::XlibHandle;
use std::{ use std::{
cmp, cmp, env,
collections::HashSet,
env,
ffi::CString, ffi::CString,
mem::{self, replace, MaybeUninit}, mem::{self, replace, MaybeUninit},
os::raw::*, os::raw::*,
@ -12,6 +10,7 @@ use std::{
}; };
use libc; use libc;
use mio_extras::channel::Sender;
use parking_lot::Mutex; use parking_lot::Mutex;
use crate::{ use crate::{
@ -104,7 +103,7 @@ pub struct UnownedWindow {
cursor_visible: Mutex<bool>, cursor_visible: Mutex<bool>,
ime_sender: Mutex<ImeSender>, ime_sender: Mutex<ImeSender>,
pub shared_state: Mutex<SharedState>, pub shared_state: Mutex<SharedState>,
pending_redraws: Arc<::std::sync::Mutex<HashSet<WindowId>>>, redraw_sender: Sender<WindowId>,
} }
impl UnownedWindow { impl UnownedWindow {
@ -249,7 +248,7 @@ impl UnownedWindow {
cursor_visible: Mutex::new(true), cursor_visible: Mutex::new(true),
ime_sender: Mutex::new(event_loop.ime_sender.clone()), ime_sender: Mutex::new(event_loop.ime_sender.clone()),
shared_state: SharedState::new(guessed_monitor, window_attrs.visible), 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 // Title must be set before mapping. Some tiling window managers (i.e. i3) use the window
@ -1314,10 +1313,7 @@ impl UnownedWindow {
#[inline] #[inline]
pub fn request_redraw(&self) { pub fn request_redraw(&self) {
self.pending_redraws self.redraw_sender.send(WindowId(self.xwindow)).unwrap();
.lock()
.unwrap()
.insert(WindowId(self.xwindow));
} }
#[inline] #[inline]