diff --git a/examples/open_window.rs b/examples/open_window.rs index e784425..911a039 100644 --- a/examples/open_window.rs +++ b/examples/open_window.rs @@ -15,7 +15,7 @@ impl WindowHandler for MyProgram { match event { Event::Mouse(e) => println!("Mouse event: {:?}", e), Event::Keyboard(e) => println!("Keyboard event: {:?}", e), - Event::Window(e) => println!("Window event: {:?}", e) + Event::Window(e) => println!("Window event: {:?}", e), } } diff --git a/src/event.rs b/src/event.rs index a888dd1..ef4f4c7 100644 --- a/src/event.rs +++ b/src/event.rs @@ -91,5 +91,5 @@ pub enum WindowEvent { pub enum Event { Mouse(MouseEvent), Keyboard(KeyboardEvent), - Window(WindowEvent) + Window(WindowEvent), } diff --git a/src/macos/window.rs b/src/macos/window.rs index 84020fa..6e718ba 100644 --- a/src/macos/window.rs +++ b/src/macos/window.rs @@ -11,8 +11,8 @@ use cocoa::foundation::{NSAutoreleasePool, NSPoint, NSRect, NSSize, NSString}; use raw_window_handle::{macos::MacOSHandle, HasRawWindowHandle, RawWindowHandle}; use crate::{ - Event, KeyboardEvent, MouseButton, MouseEvent, ScrollDelta, WindowEvent, - WindowHandler, WindowOpenOptions, + Event, KeyboardEvent, MouseButton, MouseEvent, ScrollDelta, WindowEvent, WindowHandler, + WindowOpenOptions, }; pub struct Window { diff --git a/src/win/window.rs b/src/win/window.rs index 5c2e3b8..95de2f0 100644 --- a/src/win/window.rs +++ b/src/win/window.rs @@ -19,8 +19,8 @@ use std::rc::Rc; use raw_window_handle::{windows::WindowsHandle, HasRawWindowHandle, RawWindowHandle}; use crate::{ - Event, KeyboardEvent, MouseButton, MouseEvent, Parent::WithParent, ScrollDelta, - WindowEvent, WindowHandler, WindowInfo, WindowOpenOptions, + Event, KeyboardEvent, MouseButton, MouseEvent, Parent::WithParent, ScrollDelta, WindowEvent, + WindowHandler, WindowInfo, WindowOpenOptions, }; unsafe fn message_box(title: &str, msg: &str) { @@ -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 f57534a..6722bcf 100644 --- a/src/x11/window.rs +++ b/src/x11/window.rs @@ -1,29 +1,29 @@ use std::os::raw::{c_ulong, c_void}; use std::sync::mpsc; -use std::time::*; use std::thread; +use std::time::*; +use std::time::*; use raw_window_handle::{unix::XlibHandle, HasRawWindowHandle, RawWindowHandle}; use super::XcbConnection; use crate::{ - Event, KeyboardEvent, MouseButton, MouseEvent, Parent, ScrollDelta, WindowEvent, - WindowHandler, WindowOpenOptions, + Event, KeyboardEvent, MouseButton, MouseEvent, Parent, ScrollDelta, WindowEvent, 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 { @@ -47,12 +47,13 @@ impl Window { // FIXME: placeholder types for returning errors in the future let _ = rx.recv(); - WindowHandle { - thread - } + WindowHandle { thread } } - fn window_thread(options: WindowOpenOptions, tx: mpsc::SyncSender) -> WindowOpenResult { + fn window_thread( + options: WindowOpenOptions, + tx: mpsc::SyncSender, + ) -> WindowOpenResult { // Connect to the X server // FIXME: baseview error type instead of unwrap() let xcb_connection = XcbConnection::new().unwrap(); @@ -102,7 +103,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, )], ); @@ -120,14 +122,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], ); }); @@ -135,13 +139,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); @@ -152,6 +162,10 @@ impl Window { Ok(()) } + pub fn window_info(&self) -> &WindowInfo { + &self.window_info + } + #[inline] fn drain_xcb_events(&mut self, handler: &mut H) { while let Some(event) = self.xcb_connection.conn.poll_for_event() { @@ -176,23 +190,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) { @@ -231,9 +241,8 @@ impl Window { match event_type { //// - // keys + // window //// - xcb::EXPOSE => { handler.on_frame(); } @@ -245,7 +254,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)); @@ -255,10 +268,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(); @@ -266,7 +291,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, + }), ); } } @@ -314,19 +342,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 //