diff --git a/src/x11/event_loop.rs b/src/x11/event_loop.rs index 49144cb..e548277 100644 --- a/src/x11/event_loop.rs +++ b/src/x11/event_loop.rs @@ -1,57 +1,71 @@ +use crate::x11::handle::ParentHandle; use crate::x11::keyboard::{convert_key_press_event, convert_key_release_event, key_mods}; -use crate::x11::{ParentHandle, Window, WindowInner}; +use crate::x11::Window; use crate::{ Event, MouseButton, MouseEvent, PhyPoint, PhySize, ScrollDelta, WindowEvent, WindowHandler, WindowInfo, }; use std::error::Error; +use std::os::fd::AsRawFd; use std::rc::Rc; use std::time::{Duration, Instant}; use x11rb::connection::Connection; - use x11rb::protocol::Event as XEvent; pub(super) struct EventLoop { - // Using the trait object will be necessary when we add multi-window support anyway handler: Box, window: Rc, - handle_receiver: Option, + parent_handle: Option, + new_physical_size: Option, frame_interval: Duration, - event_loop_running: bool, - close_request_handled: bool, - - new_size: Option, } impl EventLoop { pub fn new( - window: Rc, handler: impl WindowHandler, - handle_receiver: Option, + window: Rc, handler: impl WindowHandler, parent_handle: Option, ) -> Self { Self { window, handler: Box::new(handler), - handle_receiver, + parent_handle, frame_interval: Duration::from_millis(15), event_loop_running: false, - close_request_handled: false, - new_size: None, + new_physical_size: None, + } + } + + #[inline] + fn drain_xcb_events(&mut self) -> Result<(), Box> { + // the X server has a tendency to send spurious/extraneous configure notify events when a + // window is resized, and we need to batch those together and just send one resize event + // when they've all been coalesced. + self.new_physical_size = None; + + while let Some(event) = self.window.xcb_connection.conn.poll_for_event()? { + self.handle_xcb_event(event); + } + + if let Some(size) = self.new_physical_size.take() { + let window_info = + WindowInfo::from_physical_size(size, self.window.x11_window.dpi_scale_factor); + + self.handler.on_event(Event::Window(WindowEvent::Resized(window_info))); } + + Ok(()) } // Event loop // FIXME: poll() acts fine on linux, sometimes funky on *BSD. XCB upstream uses a define to // switch between poll() and select() (the latter of which is fine on *BSD), and we should do // the same. - // NOTE: x11rb uses calloop under the hood, so that won't be an issue anymore once we switch to - // it pub fn run(&mut self) -> Result<(), Box> { use nix::poll::*; - let xcb_fd = self.window.xcb_connection.file_descriptor(); + let xcb_fd = self.window.xcb_connection.conn.as_raw_fd(); let mut last_frame = Instant::now(); self.event_loop_running = true; @@ -95,40 +109,25 @@ impl EventLoop { // FIXME: This will need to be changed from just setting an atomic to somehow // synchronizing with the window being closed (using a synchronous channel, or // by joining on the event loop thread). - if let Some(parent_handle) = &self.handle_receiver { - if parent_handle.close_requested() { + if let Some(parent_handle) = &self.parent_handle { + if parent_handle.parent_did_drop() { self.handle_must_close(); + self.window.close_requested.set(false); } } // Check if the user has requested the window to close if self.window.close_requested.get() { self.handle_must_close(); + self.window.close_requested.set(false); } } Ok(()) } - fn handle_close_requested(&mut self) { - // FIXME: handler should decide whether window stays open or not - self.handle_must_close(); - } - - fn handle_must_close(&mut self) { - if self.close_request_handled { - return; - } - self.handler.on_event(Event::Window(WindowEvent::WillClose)); - - self.event_loop_running = false; - self.close_request_handled = true; - } - fn handle_xcb_event(&mut self, event: XEvent) { - let xcb_connection = &self.window.xcb_connection; - - // For all of the keyboard and mouse events, you can fetch + // For all the keyboard and mouse events, you can fetch // `x`, `y`, `detail`, and `state`. // - `x` and `y` are the position inside the window where the cursor currently is // when the event happened. @@ -154,18 +153,21 @@ impl EventLoop { //// XEvent::ClientMessage(event) => { if event.format == 32 - && event.data.as_data32()[0] == xcb_connection.atoms.WM_DELETE_WINDOW + && event.data.as_data32()[0] + == self.window.xcb_connection.atoms.WM_DELETE_WINDOW { self.handle_close_requested(); } } XEvent::ConfigureNotify(event) => { - let new_size = PhySize::new(event.width as u32, event.height as u32); + let new_physical_size = PhySize::new(event.width as u32, event.height as u32); - match self.new_size { - None => self.new_size = Some(new_size), - Some(s) if s != new_size => self.new_size = Some(new_size), + match self.new_physical_size { + None => self.new_physical_size = Some(new_physical_size), + Some(s) if s != new_physical_size => { + self.new_physical_size = Some(new_physical_size) + } _ => {} } } @@ -249,24 +251,15 @@ impl EventLoop { } } - fn drain_xcb_events(&mut self) -> Result<(), Box> { - // the X server has a tendency to send spurious/extraneous configure notify events when a - // window is resized, and we need to batch those together and just send one resize event - // when they've all been coalesced. - self.new_size = None; - - while let Some(event) = self.window.xcb_connection.conn.poll_for_event()? { - self.handle_xcb_event(event); - } - - if let Some(size) = self.new_size.take() { - let window_info = - WindowInfo::from_physical_size(size, self.window.x11_window.dpi_scale_factor); + fn handle_close_requested(&mut self) { + // FIXME: handler should decide whether window stays open or not + self.handle_must_close(); + } - self.handler.on_event(Event::Window(WindowEvent::Resized(window_info))); - } + fn handle_must_close(&mut self) { + self.handler.on_event(Event::Window(WindowEvent::WillClose)); - Ok(()) + self.event_loop_running = false; } } diff --git a/src/x11/handle.rs b/src/x11/handle.rs index 5664c59..58eb9f6 100644 --- a/src/x11/handle.rs +++ b/src/x11/handle.rs @@ -45,11 +45,11 @@ impl WindowHandle { } /// Receives the requests sent from the [`WindowHandle`] -pub struct WindowHandleReceiver { +pub struct ParentHandle { shared: Arc, } -impl WindowHandleReceiver { +impl ParentHandle { pub fn new() -> (Self, UninitializedWindowHandle) { let shared = Arc::new(HandleShared { close_requested: AtomicBool::new(false), @@ -59,13 +59,13 @@ impl WindowHandleReceiver { (Self { shared: shared.clone() }, UninitializedWindowHandle { shared }) } - pub fn close_requested(&self) -> bool { + pub fn parent_did_drop(&self) -> bool { self.shared.close_requested.load(Ordering::Relaxed) } } // Notify the external handles that the window has been closed -impl Drop for WindowHandleReceiver { +impl Drop for ParentHandle { fn drop(&mut self) { self.shared.is_open.store(false, Ordering::Relaxed); } diff --git a/src/x11/window.rs b/src/x11/window.rs index a4f47c3..c2369b3 100644 --- a/src/x11/window.rs +++ b/src/x11/window.rs @@ -9,7 +9,7 @@ use std::thread; use raw_window_handle::{HasRawWindowHandle, RawDisplayHandle, RawWindowHandle, XcbWindowHandle}; use crate::x11::event_loop::EventLoop; -use crate::x11::handle::{WindowHandle, WindowHandleReceiver}; +use crate::x11::handle::{ParentHandle, WindowHandle}; use crate::{Event, MouseCursor, Size, WindowEvent, WindowHandler, WindowInfo, WindowOpenOptions}; use crate::x11::x11_window::X11Window; @@ -41,7 +41,7 @@ impl Window { let (tx, rx) = mpsc::sync_channel::(1); - let (parent_handle, window_handle) = WindowHandleReceiver::new(); + let (parent_handle, window_handle) = ParentHandle::new(); // TODO: handle window creation errors thread::spawn(move || { @@ -64,8 +64,7 @@ impl Window { fn window_thread( parent: Option, options: WindowOpenOptions, build: B, - tx: Option>, - handle_receiver: Option, + tx: Option>, handle_receiver: Option, ) -> Result<(), Box> where H: WindowHandler, diff --git a/src/x11/xcb_connection.rs b/src/x11/xcb_connection.rs index 37d120d..cdbf659 100644 --- a/src/x11/xcb_connection.rs +++ b/src/x11/xcb_connection.rs @@ -3,7 +3,6 @@ use std::cell::RefCell; use std::collections::hash_map::{Entry, HashMap}; use std::error::Error; use std::ffi::{c_int, c_void}; -use std::os::fd::{AsRawFd, RawFd}; use x11::{xlib, xlib::Display, xlib_xcb}; @@ -125,10 +124,6 @@ impl XcbConnection { &self.conn.setup().roots[self.screen] } - pub fn file_descriptor(&self) -> RawFd { - self.conn.as_raw_fd() - } - pub fn raw_display_handle(&self) -> RawDisplayHandle { let mut handle = XlibDisplayHandle::empty();