From 7bdff338470285e02e9823a55afcb9c346916404 Mon Sep 17 00:00:00 2001 From: Billy Messenger Date: Fri, 11 Sep 2020 12:32:55 -0500 Subject: [PATCH] Detect window resize in x11 --- src/win/window.rs | 8 ++-- src/x11/window.rs | 94 +++++++++++++++++++++++++-------------- src/x11/xcb_connection.rs | 28 ++++-------- 3 files changed, 72 insertions(+), 58 deletions(-) diff --git a/src/win/window.rs b/src/win/window.rs index 0d69f00..fc42fe7 100644 --- a/src/win/window.rs +++ b/src/win/window.rs @@ -142,7 +142,7 @@ pub struct Window { } pub struct WindowHandle { - hwnd: HWND + hwnd: HWND, } impl WindowHandle { @@ -193,7 +193,7 @@ impl Window { WithParent(p) => { flags = WS_CHILD | WS_VISIBLE; p - }, + } _ => { AdjustWindowRectEx(&mut rect, flags, FALSE, 0); @@ -232,9 +232,7 @@ impl Window { SetWindowLongPtrA(hwnd, GWLP_USERDATA, Rc::into_raw(win) as *const _ as _); SetTimer(hwnd, 4242, 13, None); - WindowHandle { - hwnd - } + WindowHandle { hwnd } } } } diff --git a/src/x11/window.rs b/src/x11/window.rs index 25c6a4d..7a1a4b3 100644 --- a/src/x11/window.rs +++ b/src/x11/window.rs @@ -1,28 +1,27 @@ use std::os::raw::{c_ulong, c_void}; -use std::time::*; use std::thread; +use std::time::*; use raw_window_handle::{unix::XlibHandle, HasRawWindowHandle, RawWindowHandle}; use super::XcbConnection; use crate::{ Event, FileDropEvent, KeyboardEvent, MouseButton, MouseEvent, Parent, ScrollDelta, WindowEvent, - WindowHandler, WindowOpenOptions, + WindowHandler, WindowInfo, WindowOpenOptions, }; - pub struct Window { xcb_connection: XcbConnection, window_id: u32, - scaling: f64, + window_info: WindowInfo, frame_interval: Duration, - event_loop_running: bool + event_loop_running: bool, } // FIXME: move to outer crate context pub struct WindowHandle { - thread: std::thread::JoinHandle<()> + thread: std::thread::JoinHandle<()>, } impl WindowHandle { @@ -31,13 +30,12 @@ impl WindowHandle { } } - impl Window { pub fn open(options: WindowOpenOptions) -> WindowHandle { WindowHandle { thread: thread::spawn(move || { Self::window_thread::(options); - }) + }), } } @@ -91,7 +89,8 @@ impl Window { | xcb::EVENT_MASK_BUTTON_PRESS | xcb::EVENT_MASK_BUTTON_RELEASE | xcb::EVENT_MASK_KEY_PRESS - | xcb::EVENT_MASK_KEY_RELEASE, + | xcb::EVENT_MASK_KEY_RELEASE + | xcb::EVENT_MASK_STRUCTURE_NOTIFY, )], ); @@ -109,14 +108,16 @@ impl Window { title.as_bytes(), ); - xcb_connection.atoms.wm_protocols + xcb_connection + .atoms + .wm_protocols .zip(xcb_connection.atoms.wm_delete_window) .map(|(wm_protocols, wm_delete_window)| { xcb_util::icccm::set_wm_protocols( &xcb_connection.conn, window_id, wm_protocols, - &[wm_delete_window] + &[wm_delete_window], ); }); @@ -124,13 +125,19 @@ impl Window { let scaling = xcb_connection.get_scaling().unwrap_or(1.0); + let window_info = WindowInfo { + width: options.width as u32, + height: options.height as u32, + scale: scaling, + }; + let mut window = Self { xcb_connection, window_id, - scaling, + window_info, frame_interval: Duration::from_millis(15), - event_loop_running: false + event_loop_running: false, }; let mut handler = H::build(&mut window); @@ -162,23 +169,19 @@ impl Window { while self.event_loop_running { let now = Instant::now(); - let until_next_frame = - if now > next_frame { - handler.on_frame(); + let until_next_frame = if now > next_frame { + handler.on_frame(); - next_frame = now + self.frame_interval; - self.frame_interval - } else { - next_frame - now - }; + next_frame = now + self.frame_interval; + self.frame_interval + } else { + next_frame - now + }; - let mut fds = [ - PollFd::new(xcb_fd, PollFlags::POLLIN) - ]; + let mut fds = [PollFd::new(xcb_fd, PollFlags::POLLIN)]; // FIXME: handle errors - poll(&mut fds, until_next_frame.subsec_millis() as i32) - .unwrap(); + poll(&mut fds, until_next_frame.subsec_millis() as i32).unwrap(); if let Some(revents) = fds[0].revents() { if revents.contains(PollFlags::POLLERR) { @@ -217,9 +220,8 @@ impl Window { match event_type { //// - // keys + // window //// - xcb::EXPOSE => { handler.on_frame(); } @@ -231,7 +233,11 @@ impl Window { let data = event.data().data; let (_, data32, _) = unsafe { data.align_to::() }; - let wm_delete_window = self.xcb_connection.atoms.wm_delete_window.unwrap_or(xcb::NONE); + let wm_delete_window = self + .xcb_connection + .atoms + .wm_delete_window + .unwrap_or(xcb::NONE); if wm_delete_window == data32[0] { handler.on_event(self, Event::Window(WindowEvent::WillClose)); @@ -241,10 +247,22 @@ impl Window { } } + xcb::CONFIGURE_NOTIFY => { + let event = unsafe { xcb::cast_event::(&event) }; + + if self.window_info.width != event.width() as u32 + || self.window_info.height != event.height() as u32 + { + self.window_info.width = event.width() as u32; + self.window_info.height = event.height() as u32; + + handler.on_event(self, Event::Window(WindowEvent::Resized(self.window_info))) + } + } + //// // mouse //// - xcb::MOTION_NOTIFY => { let event = unsafe { xcb::cast_event::(&event) }; let detail = event.detail(); @@ -252,7 +270,10 @@ impl Window { if detail != 4 && detail != 5 { handler.on_event( self, - Event::Mouse(MouseEvent::CursorMoved { x: event.event_x() as i32, y: event.event_y() as i32 }), + Event::Mouse(MouseEvent::CursorMoved { + x: event.event_x() as i32, + y: event.event_y() as i32, + }), ); } } @@ -300,19 +321,24 @@ impl Window { //// // keys //// - xcb::KEY_PRESS => { let event = unsafe { xcb::cast_event::(&event) }; let detail = event.detail(); - handler.on_event(self, Event::Keyboard(KeyboardEvent::KeyPressed(detail as u32))); + handler.on_event( + self, + Event::Keyboard(KeyboardEvent::KeyPressed(detail as u32)), + ); } xcb::KEY_RELEASE => { let event = unsafe { xcb::cast_event::(&event) }; let detail = event.detail(); - handler.on_event(self, Event::Keyboard(KeyboardEvent::KeyReleased(detail as u32))); + handler.on_event( + self, + Event::Keyboard(KeyboardEvent::KeyReleased(detail as u32)), + ); } _ => { diff --git a/src/x11/xcb_connection.rs b/src/x11/xcb_connection.rs index ec6fd60..94b2949 100644 --- a/src/x11/xcb_connection.rs +++ b/src/x11/xcb_connection.rs @@ -1,22 +1,18 @@ /// A very light abstraction around the XCB connection. /// /// Keeps track of the xcb connection itself and the xlib display ID that was used to connect. - -use std::ffi::{ - CString, - CStr -}; +use std::ffi::{CStr, CString}; pub(crate) struct Atoms { pub wm_protocols: Option, - pub wm_delete_window: Option + pub wm_delete_window: Option, } pub struct XcbConnection { pub conn: xcb::Connection, pub xlib_display: i32, - pub(crate) atoms: Atoms + pub(crate) atoms: Atoms, } macro_rules! intern_atoms { @@ -36,15 +32,11 @@ macro_rules! intern_atoms { }}; } - impl XcbConnection { pub fn new() -> Result { let (conn, xlib_display) = xcb::Connection::connect_with_xlib_display()?; - let (wm_protocols, wm_delete_window) = - intern_atoms!(&conn, - WM_PROTOCOLS, - WM_DELETE_WINDOW); + let (wm_protocols, wm_delete_window) = intern_atoms!(&conn, WM_PROTOCOLS, WM_DELETE_WINDOW); Ok(Self { conn, @@ -52,8 +44,8 @@ impl XcbConnection { atoms: Atoms { wm_protocols, - wm_delete_window - } + wm_delete_window, + }, }) } @@ -62,7 +54,8 @@ impl XcbConnection { // If neither work, I guess just assume 96.0 and don't do any scaling. fn get_scaling_xft(&self) -> Option { use x11::xlib::{ - XResourceManagerString, XrmDestroyDatabase, XrmGetResource, XrmGetStringDatabase, XrmValue, + XResourceManagerString, XrmDestroyDatabase, XrmGetResource, XrmGetStringDatabase, + XrmValue, }; let display = self.conn.get_raw_dpy(); @@ -113,10 +106,7 @@ impl XcbConnection { fn get_scaling_screen_dimensions(&self) -> Option { // Figure out screen information let setup = self.conn.get_setup(); - let screen = setup - .roots() - .nth(self.xlib_display as usize) - .unwrap(); + let screen = setup.roots().nth(self.xlib_display as usize).unwrap(); // Get the DPI from the screen struct //