From 2bf229575f986176314a9605457f9d244238e33a Mon Sep 17 00:00:00 2001 From: Billy Messenger Date: Thu, 15 Oct 2020 13:17:03 -0500 Subject: [PATCH 01/19] add UI scaling support --- examples/open_window.rs | 3 +- src/event.rs | 11 ++---- src/lib.rs | 24 +++++++++++-- src/window_info.rs | 76 +++++++++++++++++++++++++++++++++++++++++ src/x11/window.rs | 73 +++++++++++++++++---------------------- 5 files changed, 135 insertions(+), 52 deletions(-) create mode 100644 src/window_info.rs diff --git a/examples/open_window.rs b/examples/open_window.rs index 911a039..0f67440 100644 --- a/examples/open_window.rs +++ b/examples/open_window.rs @@ -27,9 +27,10 @@ fn main() { title: "baseview".into(), width: 512, height: 512, + scale: 1.0, parent: baseview::Parent::None, }; - let handle = Window::open::(window_open_options); + let (handle, _window_info) = Window::open::(window_open_options).unwrap(); handle.app_run_blocking(); } diff --git a/src/event.rs b/src/event.rs index ef4f4c7..87c4889 100644 --- a/src/event.rs +++ b/src/event.rs @@ -1,3 +1,5 @@ +use crate::WindowInfo; + #[derive(Debug, Clone, Copy, PartialEq)] pub enum KeyboardEvent { KeyPressed(u32), @@ -72,14 +74,7 @@ pub enum MouseEvent { CursorLeft, } -#[derive(Debug, Copy, Clone, PartialEq)] -pub struct WindowInfo { - pub width: u32, - pub height: u32, - pub scale: f64, -} - -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, PartialEq)] pub enum WindowEvent { Resized(WindowInfo), Focused, diff --git a/src/lib.rs b/src/lib.rs index fb84d94..f0ed8b7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,9 +18,11 @@ pub use macos::*; mod event; mod keyboard; mod mouse_cursor; +mod window_info; pub use event::*; pub use keyboard::*; pub use mouse_cursor::MouseCursor; +pub use window_info::WindowInfo; pub enum Parent { None, @@ -33,12 +35,30 @@ unsafe impl Send for Parent {} pub struct WindowOpenOptions { pub title: String, - pub width: usize, - pub height: usize, + /// The logical width of the window + pub width: u32, + /// The logical height of the window + pub height: u32, + + /// The dpi scale factor. This will used in conjunction with the dpi scale + /// factor of the system. + pub scale: f64, pub parent: Parent, } +pub struct WindowHandle { + thread: std::thread::JoinHandle<()>, +} + +impl WindowHandle { + pub fn app_run_blocking(self) { + let _ = self.thread.join(); + } +} + +type WindowOpenResult = Result; + pub trait WindowHandler { type Message; diff --git a/src/window_info.rs b/src/window_info.rs new file mode 100644 index 0000000..1e46be1 --- /dev/null +++ b/src/window_info.rs @@ -0,0 +1,76 @@ +/// The info about the window +#[derive(Debug, Copy, Clone, PartialEq)] +pub struct WindowInfo { + /// The physical the width of the window + physical_width: u32, + /// The physical height of the window + physical_height: u32, + /// The logical width of the window + logical_width: u32, + /// The logical height of the window + logical_height: u32, + /// The scale factor + scale: f64, + scale_recip: f64, +} + +impl WindowInfo { + pub fn from_logical_size(logical_width: u32, logical_height: u32, scale: f64) -> Self { + let scale_recip = 1.0 / scale; + + Self { + physical_width: (logical_width as f64 * scale).round() as u32, + physical_height: (logical_height as f64 * scale).round() as u32, + logical_width, + logical_height, + scale, + scale_recip, + } + } + + pub fn from_physical_size(physical_width: u32, physical_height: u32, scale: f64) -> Self { + let scale_recip = 1.0 / scale; + + Self { + physical_width, + physical_height, + logical_width: (physical_width as f64 * scale_recip).round() as u32, + logical_height: (physical_height as f64 * scale_recip).round() as u32, + scale, + scale_recip, + } + } + + /// The physical width of the window + pub fn physical_width(&self) -> u32 { + self.physical_width + } + + /// The physical height of the window + pub fn physical_height(&self) -> u32 { + self.physical_height + } + + /// The logical width of the window + pub fn logical_width(&self) -> u32 { + self.logical_width + } + + /// The logical height of the window + pub fn logical_height(&self) -> u32 { + self.logical_height + } + + /// The scale factor of the window + pub fn scale(&self) -> f64 { + self.scale + } + + /// Convert physical mouse coordinates to logical coordinates + pub fn physical_to_logical(&self, x: f64, y: f64) -> (f64, f64) { + ( + x * self.scale_recip, + y * self.scale_recip + ) + } +} \ No newline at end of file diff --git a/src/x11/window.rs b/src/x11/window.rs index c7cd911..507c67d 100644 --- a/src/x11/window.rs +++ b/src/x11/window.rs @@ -12,7 +12,7 @@ use raw_window_handle::{ use super::XcbConnection; use crate::{ Event, KeyboardEvent, MouseButton, MouseCursor, MouseEvent, Parent, ScrollDelta, WindowEvent, - WindowHandler,WindowInfo, WindowOpenOptions, + WindowHandler,WindowInfo, WindowOpenOptions, WindowOpenResult, WindowHandle, }; pub struct Window { @@ -24,24 +24,11 @@ pub struct Window { frame_interval: Duration, event_loop_running: bool, - new_size: Option<(u32, u32)> + new_physical_size: Option<(u32, u32)> } -// FIXME: move to outer crate context -pub struct WindowHandle { - thread: std::thread::JoinHandle<()>, -} - -impl WindowHandle { - pub fn app_run_blocking(self) { - let _ = self.thread.join(); - } -} - -type WindowOpenResult = Result<(), ()>; - impl Window { - pub fn open(options: WindowOpenOptions) -> WindowHandle { + pub fn open(options: WindowOpenOptions) -> Result<(WindowHandle, WindowInfo), ()> { let (tx, rx) = mpsc::sync_channel::(1); let thread = thread::spawn(move || { @@ -51,9 +38,9 @@ impl Window { }); // FIXME: placeholder types for returning errors in the future - let _ = rx.recv(); + let window_info = rx.recv().unwrap().unwrap(); - WindowHandle { thread } + Ok((WindowHandle { thread }, window_info)) } fn window_thread( @@ -92,6 +79,10 @@ impl Window { ], ); + let scaling = xcb_connection.get_scaling().unwrap_or(1.0) * options.scale; + + let window_info = WindowInfo::from_logical_size(options.width, options.height, scaling); + let window_id = xcb_connection.conn.generate_id(); xcb::create_window( &xcb_connection.conn, @@ -100,8 +91,8 @@ impl Window { parent_id, 0, // x coordinate of the new window 0, // y coordinate of the new window - options.width as u16, // window width - options.height as u16, // window height + window_info.physical_width() as u16, // window width + window_info.physical_height() as u16, // window height 0, // window border xcb::WINDOW_CLASS_INPUT_OUTPUT as u16, screen.root_visual(), @@ -144,14 +135,6 @@ impl Window { xcb_connection.conn.flush(); - 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, @@ -161,15 +144,15 @@ impl Window { frame_interval: Duration::from_millis(15), event_loop_running: false, - new_size: None + new_physical_size: None, }; let mut handler = H::build(&mut window); - let _ = tx.send(Ok(())); + let _ = tx.send(Ok(window_info)); window.run_event_loop(&mut handler); - Ok(()) + Ok(window_info) } pub fn window_info(&self) -> &WindowInfo { @@ -201,15 +184,18 @@ impl Window { // 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; + self.new_physical_size = None; while let Some(event) = self.xcb_connection.conn.poll_for_event() { self.handle_xcb_event(handler, event); } - if let Some((width, height)) = self.new_size.take() { - self.window_info.width = width; - self.window_info.height = height; + if let Some((width, height)) = self.new_physical_size.take() { + self.window_info = WindowInfo::from_physical_size( + width, + height, + self.window_info.scale() + ); handler.on_event(self, Event::Window( WindowEvent::Resized(self.window_info) @@ -312,11 +298,11 @@ impl Window { xcb::CONFIGURE_NOTIFY => { let event = unsafe { xcb::cast_event::(&event) }; - let new_size = (event.width() as u32, event.height() as u32); - let cur_size = (self.window_info.width, self.window_info.height); + let new_physical_size = (event.width() as u32, event.height() as u32); + let cur_physical_size = (self.window_info.physical_width(), self.window_info.physical_height()); - if self.new_size.is_some() || new_size != cur_size { - self.new_size = Some(new_size); + if self.new_physical_size.is_some() || new_physical_size != cur_physical_size { + self.new_physical_size = Some(new_physical_size); } } @@ -328,11 +314,16 @@ impl Window { let detail = event.detail(); if detail != 4 && detail != 5 { + let (logical_x, logical_y) = self.window_info.physical_to_logical( + event.event_x() as f64, + event.event_y() as f64 + ); + handler.on_event( self, Event::Mouse(MouseEvent::CursorMoved { - x: event.event_x() as i32, - y: event.event_y() as i32, + x: logical_x.round() as i32, + y: logical_y.round() as i32, }), ); } From ed1db27f5206f073fbee315c244a2aa1adef1392 Mon Sep 17 00:00:00 2001 From: Billy Messenger Date: Thu, 15 Oct 2020 13:24:08 -0500 Subject: [PATCH 02/19] revert WindowEvent traits --- src/event.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/event.rs b/src/event.rs index 87c4889..abaa010 100644 --- a/src/event.rs +++ b/src/event.rs @@ -74,7 +74,7 @@ pub enum MouseEvent { CursorLeft, } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Copy, Clone, PartialEq)] pub enum WindowEvent { Resized(WindowInfo), Focused, From 61de5e37f76af005034fc516eaa8514b1a56fcdb Mon Sep 17 00:00:00 2001 From: Billy Messenger Date: Thu, 15 Oct 2020 13:26:21 -0500 Subject: [PATCH 03/19] rename width, height to logical_width, logical_height --- examples/open_window.rs | 4 ++-- src/lib.rs | 4 ++-- src/x11/window.rs | 6 +++++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/examples/open_window.rs b/examples/open_window.rs index 0f67440..260e0ad 100644 --- a/examples/open_window.rs +++ b/examples/open_window.rs @@ -25,8 +25,8 @@ impl WindowHandler for MyProgram { fn main() { let window_open_options = baseview::WindowOpenOptions { title: "baseview".into(), - width: 512, - height: 512, + logical_width: 512, + logical_height: 512, scale: 1.0, parent: baseview::Parent::None, }; diff --git a/src/lib.rs b/src/lib.rs index f0ed8b7..be05a54 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -36,9 +36,9 @@ pub struct WindowOpenOptions { pub title: String, /// The logical width of the window - pub width: u32, + pub logical_width: u32, /// The logical height of the window - pub height: u32, + pub logical_height: u32, /// The dpi scale factor. This will used in conjunction with the dpi scale /// factor of the system. diff --git a/src/x11/window.rs b/src/x11/window.rs index 507c67d..13464a4 100644 --- a/src/x11/window.rs +++ b/src/x11/window.rs @@ -81,7 +81,11 @@ impl Window { let scaling = xcb_connection.get_scaling().unwrap_or(1.0) * options.scale; - let window_info = WindowInfo::from_logical_size(options.width, options.height, scaling); + let window_info = WindowInfo::from_logical_size( + options.logical_width, + options.logical_height, + scaling + ); let window_id = xcb_connection.conn.generate_id(); xcb::create_window( From 0758e4834be9b969b7c9da7583c4cb699fe40748 Mon Sep 17 00:00:00 2001 From: Billy Messenger Date: Thu, 15 Oct 2020 13:28:21 -0500 Subject: [PATCH 04/19] fix spacing in use statement --- src/x11/window.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/x11/window.rs b/src/x11/window.rs index 13464a4..b4a56b4 100644 --- a/src/x11/window.rs +++ b/src/x11/window.rs @@ -12,7 +12,7 @@ use raw_window_handle::{ use super::XcbConnection; use crate::{ Event, KeyboardEvent, MouseButton, MouseCursor, MouseEvent, Parent, ScrollDelta, WindowEvent, - WindowHandler,WindowInfo, WindowOpenOptions, WindowOpenResult, WindowHandle, + WindowHandle, WindowHandler, WindowInfo, WindowOpenOptions, WindowOpenResult, }; pub struct Window { From aee594d23c709fa9c6b83e31aadef862f6eb5d9e Mon Sep 17 00:00:00 2001 From: Billy Messenger Date: Thu, 15 Oct 2020 16:31:38 -0500 Subject: [PATCH 05/19] add window resize hints --- examples/open_window.rs | 4 ++-- src/lib.rs | 17 +++++++++++++---- src/x11/window.rs | 38 +++++++++++++++++++++++++++++++++++--- src/x11/xcb_connection.rs | 4 +++- 4 files changed, 53 insertions(+), 10 deletions(-) diff --git a/examples/open_window.rs b/examples/open_window.rs index 260e0ad..a764453 100644 --- a/examples/open_window.rs +++ b/examples/open_window.rs @@ -25,8 +25,8 @@ impl WindowHandler for MyProgram { fn main() { let window_open_options = baseview::WindowOpenOptions { title: "baseview".into(), - logical_width: 512, - logical_height: 512, + logical_size: (512, 512), + resize: baseview::WindowResize::None, scale: 1.0, parent: baseview::Parent::None, }; diff --git a/src/lib.rs b/src/lib.rs index be05a54..c0531ff 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,13 +32,22 @@ pub enum Parent { unsafe impl Send for Parent {} +pub enum WindowResize { + None, + MinMax { + min_logical_size: (u32, u32), + max_logical_size: (u32, u32), + keep_aspect: bool, + }, +} + pub struct WindowOpenOptions { pub title: String, - /// The logical width of the window - pub logical_width: u32, - /// The logical height of the window - pub logical_height: u32, + /// The logical width and height of the window + pub logical_size: (u32, u32), + + pub resize: WindowResize, /// The dpi scale factor. This will used in conjunction with the dpi scale /// factor of the system. diff --git a/src/x11/window.rs b/src/x11/window.rs index b4a56b4..a48bb46 100644 --- a/src/x11/window.rs +++ b/src/x11/window.rs @@ -12,7 +12,7 @@ use raw_window_handle::{ use super::XcbConnection; use crate::{ Event, KeyboardEvent, MouseButton, MouseCursor, MouseEvent, Parent, ScrollDelta, WindowEvent, - WindowHandle, WindowHandler, WindowInfo, WindowOpenOptions, WindowOpenResult, + WindowHandle, WindowHandler, WindowInfo, WindowOpenOptions, WindowOpenResult, WindowResize, }; pub struct Window { @@ -81,9 +81,10 @@ impl Window { let scaling = xcb_connection.get_scaling().unwrap_or(1.0) * options.scale; + let (logical_width, logical_height) = options.logical_size; let window_info = WindowInfo::from_logical_size( - options.logical_width, - options.logical_height, + logical_width, + logical_height, scaling ); @@ -126,6 +127,37 @@ impl Window { title.as_bytes(), ); + match options.resize { + WindowResize::MinMax { min_logical_size, max_logical_size, keep_aspect } => { + let size_hints = if keep_aspect { + xcb_util::icccm::SizeHints::empty() + .min_size(min_logical_size.0 as i32, min_logical_size.1 as i32) + .max_size(max_logical_size.0 as i32, max_logical_size.1 as i32) + .aspect( + (min_logical_size.0 as i32, min_logical_size.1 as i32), + (max_logical_size.0 as i32, max_logical_size.1 as i32), + ) + .build() + } else { + xcb_util::icccm::SizeHints::empty() + .min_size(min_logical_size.0 as i32, min_logical_size.1 as i32) + .max_size(max_logical_size.0 as i32, max_logical_size.1 as i32) + .build() + }; + + xcb_connection.atoms.wm_normal_hints + .map(|wm_normal_hints| { + xcb_util::icccm::set_wm_size_hints( + &xcb_connection.conn, + window_id, + wm_normal_hints, + &size_hints, + ); + }); + } + _ => {} + } + xcb_connection.atoms.wm_protocols .zip(xcb_connection.atoms.wm_delete_window) .map(|(wm_protocols, wm_delete_window)| { diff --git a/src/x11/xcb_connection.rs b/src/x11/xcb_connection.rs index 3819ee6..db2113a 100644 --- a/src/x11/xcb_connection.rs +++ b/src/x11/xcb_connection.rs @@ -13,6 +13,7 @@ use super::cursor; pub(crate) struct Atoms { pub wm_protocols: Option, pub wm_delete_window: Option, + pub wm_normal_hints: Option, } pub struct XcbConnection { @@ -45,7 +46,7 @@ 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, wm_normal_hints) = intern_atoms!(&conn, WM_PROTOCOLS, WM_DELETE_WINDOW, WM_NORMAL_HINTS); Ok(Self { conn, @@ -54,6 +55,7 @@ impl XcbConnection { atoms: Atoms { wm_protocols, wm_delete_window, + wm_normal_hints, }, cursor_cache: HashMap::new() From a4c226277c1a74fe60c32b05da45dd0b2e8c4b67 Mon Sep 17 00:00:00 2001 From: Billy Messenger Date: Thu, 15 Oct 2020 16:38:09 -0500 Subject: [PATCH 06/19] change size hints to physical size --- src/x11/window.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/x11/window.rs b/src/x11/window.rs index a48bb46..e8baf7a 100644 --- a/src/x11/window.rs +++ b/src/x11/window.rs @@ -129,19 +129,24 @@ impl Window { match options.resize { WindowResize::MinMax { min_logical_size, max_logical_size, keep_aspect } => { + let min_physical_width = (min_logical_size.0 as f64 * scaling).round() as i32; + let min_physical_height = (min_logical_size.1 as f64 * scaling).round() as i32; + let max_physical_width = (max_logical_size.0 as f64 * scaling).round() as i32; + let max_physical_height = (max_logical_size.1 as f64 * scaling).round() as i32; + let size_hints = if keep_aspect { xcb_util::icccm::SizeHints::empty() - .min_size(min_logical_size.0 as i32, min_logical_size.1 as i32) - .max_size(max_logical_size.0 as i32, max_logical_size.1 as i32) + .min_size(min_physical_width, min_physical_height) + .max_size(max_physical_width, max_physical_height) .aspect( - (min_logical_size.0 as i32, min_logical_size.1 as i32), - (max_logical_size.0 as i32, max_logical_size.1 as i32), + (min_physical_width, min_physical_height), + (max_physical_width, max_physical_height), ) .build() } else { xcb_util::icccm::SizeHints::empty() - .min_size(min_logical_size.0 as i32, min_logical_size.1 as i32) - .max_size(max_logical_size.0 as i32, max_logical_size.1 as i32) + .min_size(min_physical_width, min_physical_height) + .max_size(max_physical_width, max_physical_height) .build() }; From 1b9fbf9bb8889e21987041ef8ae16ae945d21ac4 Mon Sep 17 00:00:00 2001 From: Billy Messenger Date: Sat, 17 Oct 2020 13:35:39 -0500 Subject: [PATCH 07/19] refactor and modify events --- examples/open_window.rs | 12 ++++--- src/event.rs | 24 +++++++++---- src/lib.rs | 27 ++------------ src/window_info.rs | 12 +++++-- src/window_open_options.rs | 74 ++++++++++++++++++++++++++++++++++++++ src/x11/window.rs | 63 +++++++++----------------------- src/x11/xcb_connection.rs | 67 +++++++++++++++++++++++++++++++++- 7 files changed, 195 insertions(+), 84 deletions(-) create mode 100644 src/window_open_options.rs diff --git a/examples/open_window.rs b/examples/open_window.rs index a764453..aa3b59c 100644 --- a/examples/open_window.rs +++ b/examples/open_window.rs @@ -1,4 +1,4 @@ -use baseview::{Event, Window, WindowHandler}; +use baseview::{Event, Window, WindowHandler, WindowSize, WindowScalePolicy}; struct MyProgram {} @@ -25,9 +25,13 @@ impl WindowHandler for MyProgram { fn main() { let window_open_options = baseview::WindowOpenOptions { title: "baseview".into(), - logical_size: (512, 512), - resize: baseview::WindowResize::None, - scale: 1.0, + size: WindowSize::MinMaxLogical { + initial_size: (512, 512), + min_size: (200, 200), + max_size: (1024, 1024), + keep_aspect: false, + }, + scale: WindowScalePolicy::TrySystemScaleFactor, parent: baseview::Parent::None, }; diff --git a/src/event.rs b/src/event.rs index abaa010..5ada391 100644 --- a/src/event.rs +++ b/src/event.rs @@ -41,18 +41,28 @@ pub enum ScrollDelta { pub struct MouseClick { pub button: MouseButton, pub click_count: usize, - pub x: i32, - pub y: i32, + /// The logical X coordinate of the mouse position + logical_x: i32, + /// The logical Y coordinate of the mouse position + logical_y: i32, + /// The physical X coordinate of the mouse position + physical_x: i32, + /// The physical Y coordinate of the mouse position + physical_y: i32, } #[derive(Debug, Clone, Copy, PartialEq)] pub enum MouseEvent { /// The mouse cursor was moved CursorMoved { - /// The X coordinate of the mouse position - x: i32, - /// The Y coordinate of the mouse position - y: i32, + /// The logical X coordinate of the mouse position + logical_x: i32, + /// The logical Y coordinate of the mouse position + logical_y: i32, + /// The physical X coordinate of the mouse position + physical_x: i32, + /// The physical Y coordinate of the mouse position + physical_y: i32, }, /// A mouse button was pressed. @@ -74,7 +84,7 @@ pub enum MouseEvent { CursorLeft, } -#[derive(Debug, Copy, Clone, PartialEq)] +#[derive(Debug)] pub enum WindowEvent { Resized(WindowInfo), Focused, diff --git a/src/lib.rs b/src/lib.rs index c0531ff..65fdc14 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,11 +19,14 @@ mod event; mod keyboard; mod mouse_cursor; mod window_info; +mod window_open_options; pub use event::*; pub use keyboard::*; pub use mouse_cursor::MouseCursor; pub use window_info::WindowInfo; +pub use window_open_options::*; +#[derive(Debug)] pub enum Parent { None, AsIfParented, @@ -32,30 +35,6 @@ pub enum Parent { unsafe impl Send for Parent {} -pub enum WindowResize { - None, - MinMax { - min_logical_size: (u32, u32), - max_logical_size: (u32, u32), - keep_aspect: bool, - }, -} - -pub struct WindowOpenOptions { - pub title: String, - - /// The logical width and height of the window - pub logical_size: (u32, u32), - - pub resize: WindowResize, - - /// The dpi scale factor. This will used in conjunction with the dpi scale - /// factor of the system. - pub scale: f64, - - pub parent: Parent, -} - pub struct WindowHandle { thread: std::thread::JoinHandle<()>, } diff --git a/src/window_info.rs b/src/window_info.rs index 1e46be1..373936e 100644 --- a/src/window_info.rs +++ b/src/window_info.rs @@ -1,5 +1,5 @@ /// The info about the window -#[derive(Debug, Copy, Clone, PartialEq)] +#[derive(Debug, Copy, Clone)] pub struct WindowInfo { /// The physical the width of the window physical_width: u32, @@ -66,11 +66,19 @@ impl WindowInfo { self.scale } - /// Convert physical mouse coordinates to logical coordinates + /// Convert physical coordinates to logical coordinates pub fn physical_to_logical(&self, x: f64, y: f64) -> (f64, f64) { ( x * self.scale_recip, y * self.scale_recip ) } + + /// Convert logicalcoordinates to physical coordinates + pub fn logical_to_physical(&self, x: f64, y: f64) -> (f64, f64) { + ( + x * self.scale, + y * self.scale + ) + } } \ No newline at end of file diff --git a/src/window_open_options.rs b/src/window_open_options.rs new file mode 100644 index 0000000..1ebafa1 --- /dev/null +++ b/src/window_open_options.rs @@ -0,0 +1,74 @@ +use crate::{WindowInfo, Parent}; + +/// The size of the window +#[derive(Debug)] +pub enum WindowSize { + /// Use logical width and height + Logical(u32, u32), + /// Use physical width and height + Physical(u32, u32), + /// Use minimum and maximum logical width and height + MinMaxLogical { + /// The initial logical width and height + initial_size: (u32, u32), + /// The minimum logical width and height + min_size: (u32, u32), + /// The maximum logical width and height + max_size: (u32, u32), + /// Whether to keep the aspect ratio when resizing (true), or not (false) + keep_aspect: bool, + }, + /// Use minimum and maximum physical width and height + MinMaxPhysical { + /// The initial physical width and height + initial_size: (u32, u32), + /// The minimum physical width and height + min_size: (u32, u32), + /// The maximum physical width and height + max_size: (u32, u32), + /// Whether to keep the aspect ratio when resizing (true), or not (false) + keep_aspect: bool, + }, +} + +/// The dpi scaling policy of the window +#[derive(Debug)] +pub enum WindowScalePolicy { + /// Try using the system scale factor + TrySystemScaleFactor, + /// Try using the system scale factor in addition to the given scale factor + TrySystemScaleFactorTimes(f64), + /// Use the given scale factor + UseScaleFactor(f64), + /// No scaling + NoScaling, +} + +/// The options for opening a new window +#[derive(Debug)] +pub struct WindowOpenOptions { + pub title: String, + + /// The size information about the window + pub size: WindowSize, + + /// The scaling of the window + pub scale: WindowScalePolicy, + + pub parent: Parent, +} + +impl WindowOpenOptions { + pub(crate) fn window_info_from_scale(&self, scale: f64) -> WindowInfo { + match self.size { + WindowSize::Logical(w, h) => WindowInfo::from_logical_size(w, h, scale), + WindowSize::Physical(w, h) => WindowInfo::from_physical_size(w, h, scale), + WindowSize::MinMaxLogical { initial_size, .. } => { + WindowInfo::from_logical_size(initial_size.0, initial_size.1, scale) + }, + WindowSize::MinMaxPhysical { initial_size, .. } => { + WindowInfo::from_logical_size(initial_size.0, initial_size.1, scale) + } + } + } +} \ No newline at end of file diff --git a/src/x11/window.rs b/src/x11/window.rs index e8baf7a..0c97c46 100644 --- a/src/x11/window.rs +++ b/src/x11/window.rs @@ -12,7 +12,8 @@ use raw_window_handle::{ use super::XcbConnection; use crate::{ Event, KeyboardEvent, MouseButton, MouseCursor, MouseEvent, Parent, ScrollDelta, WindowEvent, - WindowHandle, WindowHandler, WindowInfo, WindowOpenOptions, WindowOpenResult, WindowResize, + WindowHandle, WindowHandler, WindowInfo, WindowOpenOptions, WindowOpenResult, + WindowScalePolicy, }; pub struct Window { @@ -79,14 +80,16 @@ impl Window { ], ); - let scaling = xcb_connection.get_scaling().unwrap_or(1.0) * options.scale; + let scaling = match options.scale { + WindowScalePolicy::TrySystemScaleFactor => + xcb_connection.get_scaling().unwrap_or(1.0), + WindowScalePolicy::TrySystemScaleFactorTimes(user_scale) => + xcb_connection.get_scaling().unwrap_or(1.0) * user_scale, + WindowScalePolicy::UseScaleFactor(user_scale) => user_scale, + WindowScalePolicy::NoScaling => 1.0, + }; - let (logical_width, logical_height) = options.logical_size; - let window_info = WindowInfo::from_logical_size( - logical_width, - logical_height, - scaling - ); + let window_info = options.window_info_from_scale(scaling); let window_id = xcb_connection.conn.generate_id(); xcb::create_window( @@ -127,42 +130,6 @@ impl Window { title.as_bytes(), ); - match options.resize { - WindowResize::MinMax { min_logical_size, max_logical_size, keep_aspect } => { - let min_physical_width = (min_logical_size.0 as f64 * scaling).round() as i32; - let min_physical_height = (min_logical_size.1 as f64 * scaling).round() as i32; - let max_physical_width = (max_logical_size.0 as f64 * scaling).round() as i32; - let max_physical_height = (max_logical_size.1 as f64 * scaling).round() as i32; - - let size_hints = if keep_aspect { - xcb_util::icccm::SizeHints::empty() - .min_size(min_physical_width, min_physical_height) - .max_size(max_physical_width, max_physical_height) - .aspect( - (min_physical_width, min_physical_height), - (max_physical_width, max_physical_height), - ) - .build() - } else { - xcb_util::icccm::SizeHints::empty() - .min_size(min_physical_width, min_physical_height) - .max_size(max_physical_width, max_physical_height) - .build() - }; - - xcb_connection.atoms.wm_normal_hints - .map(|wm_normal_hints| { - xcb_util::icccm::set_wm_size_hints( - &xcb_connection.conn, - window_id, - wm_normal_hints, - &size_hints, - ); - }); - } - _ => {} - } - xcb_connection.atoms.wm_protocols .zip(xcb_connection.atoms.wm_delete_window) .map(|(wm_protocols, wm_delete_window)| { @@ -173,6 +140,8 @@ impl Window { &[wm_delete_window], ); }); + + xcb_connection.set_resize_policy(window_id, &options.size, scaling); xcb_connection.conn.flush(); @@ -363,8 +332,10 @@ impl Window { handler.on_event( self, Event::Mouse(MouseEvent::CursorMoved { - x: logical_x.round() as i32, - y: logical_y.round() as i32, + logical_x: logical_x.round() as i32, + logical_y: logical_y.round() as i32, + physical_x: event.event_x() as i32, + physical_y: event.event_y() as i32, }), ); } diff --git a/src/x11/xcb_connection.rs b/src/x11/xcb_connection.rs index db2113a..d8a32ac 100644 --- a/src/x11/xcb_connection.rs +++ b/src/x11/xcb_connection.rs @@ -5,7 +5,7 @@ use std::ffi::{CStr, CString}; use std::collections::HashMap; -use crate::MouseCursor; +use crate::{MouseCursor, WindowSize}; use super::cursor; @@ -154,4 +154,69 @@ impl XcbConnection { .entry(cursor) .or_insert_with(|| cursor::get_xcursor(dpy, cursor)) } + + pub fn set_resize_policy(&self, window_id: u32, size: &WindowSize, scale: f64) { + match size { + WindowSize::MinMaxLogical { min_size, max_size, keep_aspect, .. } => { + let min_physical_width = (min_size.0 as f64 * scale).round() as i32; + let min_physical_height = (min_size.1 as f64 * scale).round() as i32; + let max_physical_width = (max_size.0 as f64 * scale).round() as i32; + let max_physical_height = (max_size.1 as f64 * scale).round() as i32; + + let size_hints = if *keep_aspect { + xcb_util::icccm::SizeHints::empty() + .min_size(min_physical_width, min_physical_height) + .max_size(max_physical_width, max_physical_height) + .aspect( + (min_physical_width, min_physical_height), + (max_physical_width, max_physical_height), + ) + .build() + } else { + xcb_util::icccm::SizeHints::empty() + .min_size(min_physical_width, min_physical_height) + .max_size(max_physical_width, max_physical_height) + .build() + }; + + self.atoms.wm_normal_hints + .map(|wm_normal_hints| { + xcb_util::icccm::set_wm_size_hints( + &self.conn, + window_id, + wm_normal_hints, + &size_hints, + ); + }); + } + WindowSize::MinMaxPhysical { min_size, max_size, keep_aspect, .. } => { + let size_hints = if *keep_aspect { + xcb_util::icccm::SizeHints::empty() + .min_size(min_size.0 as i32, min_size.1 as i32) + .max_size(max_size.0 as i32, max_size.1 as i32) + .aspect( + (min_size.0 as i32, min_size.1 as i32), + (max_size.0 as i32, max_size.1 as i32), + ) + .build() + } else { + xcb_util::icccm::SizeHints::empty() + .min_size(min_size.0 as i32, min_size.1 as i32) + .max_size(max_size.0 as i32, max_size.1 as i32) + .build() + }; + + self.atoms.wm_normal_hints + .map(|wm_normal_hints| { + xcb_util::icccm::set_wm_size_hints( + &self.conn, + window_id, + wm_normal_hints, + &size_hints, + ); + }); + } + _ => {} + } + } } From dc5d3b9622c88be8bc599364dc1cc0227453b394 Mon Sep 17 00:00:00 2001 From: Billy Messenger Date: Sat, 17 Oct 2020 14:01:03 -0500 Subject: [PATCH 08/19] Add Point and Size structs --- examples/open_window.rs | 6 +-- src/event.rs | 26 +++++-------- src/lib.rs | 30 +++++++++++++++ src/window_info.rs | 79 ++++++++++++++++---------------------- src/window_open_options.rs | 26 ++++++------- src/x11/window.rs | 30 ++++++--------- src/x11/xcb_connection.rs | 20 +++++----- 7 files changed, 110 insertions(+), 107 deletions(-) diff --git a/examples/open_window.rs b/examples/open_window.rs index aa3b59c..8834368 100644 --- a/examples/open_window.rs +++ b/examples/open_window.rs @@ -26,9 +26,9 @@ fn main() { let window_open_options = baseview::WindowOpenOptions { title: "baseview".into(), size: WindowSize::MinMaxLogical { - initial_size: (512, 512), - min_size: (200, 200), - max_size: (1024, 1024), + initial_size: baseview::Size::new(512, 512), + min_size: baseview::Size::new(200, 200), + max_size: baseview::Size::new(1024, 1024), keep_aspect: false, }, scale: WindowScalePolicy::TrySystemScaleFactor, diff --git a/src/event.rs b/src/event.rs index 5ada391..31d5e24 100644 --- a/src/event.rs +++ b/src/event.rs @@ -1,4 +1,4 @@ -use crate::WindowInfo; +use crate::{WindowInfo, Point}; #[derive(Debug, Clone, Copy, PartialEq)] pub enum KeyboardEvent { @@ -41,28 +41,20 @@ pub enum ScrollDelta { pub struct MouseClick { pub button: MouseButton, pub click_count: usize, - /// The logical X coordinate of the mouse position - logical_x: i32, - /// The logical Y coordinate of the mouse position - logical_y: i32, - /// The physical X coordinate of the mouse position - physical_x: i32, - /// The physical Y coordinate of the mouse position - physical_y: i32, + /// The logical coordinates of the mouse position + logical_pos: Point, + /// The physical coordinates of the mouse position + physical_pos: Point, } #[derive(Debug, Clone, Copy, PartialEq)] pub enum MouseEvent { /// The mouse cursor was moved CursorMoved { - /// The logical X coordinate of the mouse position - logical_x: i32, - /// The logical Y coordinate of the mouse position - logical_y: i32, - /// The physical X coordinate of the mouse position - physical_x: i32, - /// The physical Y coordinate of the mouse position - physical_y: i32, + /// The logical coordinates of the mouse position + logical_pos: Point, + /// The physical coordinates of the mouse position + physical_pos: Point, }, /// A mouse button was pressed. diff --git a/src/lib.rs b/src/lib.rs index 65fdc14..88d4fa3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -45,6 +45,36 @@ impl WindowHandle { } } +#[derive(Debug, Copy, Clone, PartialEq)] +pub struct Point { + pub x: T, + pub y: T, +} + +impl Point { + pub fn new(x: T, y: T) -> Self { + Self { x, y } + } +} + +impl From> for Point { + fn from(p: Point) -> Point { + Point::new(p.x.round() as i32, p.y.round() as i32) + } +} + +#[derive(Debug, Copy, Clone, PartialEq)] +pub struct Size { + pub width: u32, + pub height: u32, +} + +impl Size { + pub fn new(width: u32, height: u32) -> Self { + Self { width, height } + } +} + type WindowOpenResult = Result; pub trait WindowHandler { diff --git a/src/window_info.rs b/src/window_info.rs index 373936e..81da6bf 100644 --- a/src/window_info.rs +++ b/src/window_info.rs @@ -1,64 +1,51 @@ +use crate::{Size, Point}; + /// The info about the window #[derive(Debug, Copy, Clone)] pub struct WindowInfo { - /// The physical the width of the window - physical_width: u32, - /// The physical height of the window - physical_height: u32, - /// The logical width of the window - logical_width: u32, - /// The logical height of the window - logical_height: u32, - /// The scale factor + logical_size: Size, + physical_size: Size, scale: f64, scale_recip: f64, } impl WindowInfo { - pub fn from_logical_size(logical_width: u32, logical_height: u32, scale: f64) -> Self { + pub fn from_logical_size(logical_size: Size, scale: f64) -> Self { let scale_recip = 1.0 / scale; Self { - physical_width: (logical_width as f64 * scale).round() as u32, - physical_height: (logical_height as f64 * scale).round() as u32, - logical_width, - logical_height, + logical_size, + physical_size: Size { + width: (logical_size.width as f64 * scale).round() as u32, + height: (logical_size.height as f64 * scale).round() as u32, + }, scale, scale_recip, } } - pub fn from_physical_size(physical_width: u32, physical_height: u32, scale: f64) -> Self { + pub fn from_physical_size(physical_size: Size, scale: f64) -> Self { let scale_recip = 1.0 / scale; Self { - physical_width, - physical_height, - logical_width: (physical_width as f64 * scale_recip).round() as u32, - logical_height: (physical_height as f64 * scale_recip).round() as u32, + logical_size: Size { + width: (physical_size.width as f64 * scale_recip).round() as u32, + height: (physical_size.height as f64 * scale_recip).round() as u32, + }, + physical_size, scale, scale_recip, } } - /// The physical width of the window - pub fn physical_width(&self) -> u32 { - self.physical_width + /// The logical size of the window + pub fn logical_size(&self) -> Size { + self.logical_size } - /// The physical height of the window - pub fn physical_height(&self) -> u32 { - self.physical_height - } - - /// The logical width of the window - pub fn logical_width(&self) -> u32 { - self.logical_width - } - - /// The logical height of the window - pub fn logical_height(&self) -> u32 { - self.logical_height + /// The physical size of the window + pub fn physical_size(&self) -> Size { + self.physical_size } /// The scale factor of the window @@ -67,18 +54,18 @@ impl WindowInfo { } /// Convert physical coordinates to logical coordinates - pub fn physical_to_logical(&self, x: f64, y: f64) -> (f64, f64) { - ( - x * self.scale_recip, - y * self.scale_recip - ) + pub fn physical_to_logical(&self, physical: Point) -> Point { + Point { + x: physical.x * self.scale_recip, + y: physical.y * self.scale_recip + } } - /// Convert logicalcoordinates to physical coordinates - pub fn logical_to_physical(&self, x: f64, y: f64) -> (f64, f64) { - ( - x * self.scale, - y * self.scale - ) + /// Convert logical coordinates to physical coordinates + pub fn logical_to_physical(&self, logical: Point) -> Point { + Point { + x: logical.x * self.scale, + y: logical.y * self.scale + } } } \ No newline at end of file diff --git a/src/window_open_options.rs b/src/window_open_options.rs index 1ebafa1..5ca7e17 100644 --- a/src/window_open_options.rs +++ b/src/window_open_options.rs @@ -1,31 +1,31 @@ -use crate::{WindowInfo, Parent}; +use crate::{WindowInfo, Parent, Size}; /// The size of the window #[derive(Debug)] pub enum WindowSize { /// Use logical width and height - Logical(u32, u32), + Logical(Size), /// Use physical width and height - Physical(u32, u32), + Physical(Size), /// Use minimum and maximum logical width and height MinMaxLogical { /// The initial logical width and height - initial_size: (u32, u32), + initial_size: Size, /// The minimum logical width and height - min_size: (u32, u32), + min_size: Size, /// The maximum logical width and height - max_size: (u32, u32), + max_size: Size, /// Whether to keep the aspect ratio when resizing (true), or not (false) keep_aspect: bool, }, /// Use minimum and maximum physical width and height MinMaxPhysical { /// The initial physical width and height - initial_size: (u32, u32), + initial_size: Size, /// The minimum physical width and height - min_size: (u32, u32), + min_size: Size, /// The maximum physical width and height - max_size: (u32, u32), + max_size: Size, /// Whether to keep the aspect ratio when resizing (true), or not (false) keep_aspect: bool, }, @@ -61,13 +61,13 @@ pub struct WindowOpenOptions { impl WindowOpenOptions { pub(crate) fn window_info_from_scale(&self, scale: f64) -> WindowInfo { match self.size { - WindowSize::Logical(w, h) => WindowInfo::from_logical_size(w, h, scale), - WindowSize::Physical(w, h) => WindowInfo::from_physical_size(w, h, scale), + WindowSize::Logical(size) => WindowInfo::from_logical_size(size, scale), + WindowSize::Physical(size) => WindowInfo::from_physical_size(size, scale), WindowSize::MinMaxLogical { initial_size, .. } => { - WindowInfo::from_logical_size(initial_size.0, initial_size.1, scale) + WindowInfo::from_logical_size(initial_size, scale) }, WindowSize::MinMaxPhysical { initial_size, .. } => { - WindowInfo::from_logical_size(initial_size.0, initial_size.1, scale) + WindowInfo::from_logical_size(initial_size, scale) } } } diff --git a/src/x11/window.rs b/src/x11/window.rs index 0c97c46..92e5bba 100644 --- a/src/x11/window.rs +++ b/src/x11/window.rs @@ -13,7 +13,7 @@ use super::XcbConnection; use crate::{ Event, KeyboardEvent, MouseButton, MouseCursor, MouseEvent, Parent, ScrollDelta, WindowEvent, WindowHandle, WindowHandler, WindowInfo, WindowOpenOptions, WindowOpenResult, - WindowScalePolicy, + WindowScalePolicy, Size, Point, }; pub struct Window { @@ -25,7 +25,7 @@ pub struct Window { frame_interval: Duration, event_loop_running: bool, - new_physical_size: Option<(u32, u32)> + new_physical_size: Option } impl Window { @@ -99,8 +99,8 @@ impl Window { parent_id, 0, // x coordinate of the new window 0, // y coordinate of the new window - window_info.physical_width() as u16, // window width - window_info.physical_height() as u16, // window height + window_info.physical_size().width as u16, // window width + window_info.physical_size().height as u16, // window height 0, // window border xcb::WINDOW_CLASS_INPUT_OUTPUT as u16, screen.root_visual(), @@ -200,10 +200,9 @@ impl Window { self.handle_xcb_event(handler, event); } - if let Some((width, height)) = self.new_physical_size.take() { + if let Some(size) = self.new_physical_size.take() { self.window_info = WindowInfo::from_physical_size( - width, - height, + size, self.window_info.scale() ); @@ -308,10 +307,9 @@ impl Window { xcb::CONFIGURE_NOTIFY => { let event = unsafe { xcb::cast_event::(&event) }; - let new_physical_size = (event.width() as u32, event.height() as u32); - let cur_physical_size = (self.window_info.physical_width(), self.window_info.physical_height()); + let new_physical_size = Size::new(event.width() as u32, event.height() as u32); - if self.new_physical_size.is_some() || new_physical_size != cur_physical_size { + if self.new_physical_size.is_some() || new_physical_size != self.window_info.physical_size() { self.new_physical_size = Some(new_physical_size); } } @@ -324,18 +322,14 @@ impl Window { let detail = event.detail(); if detail != 4 && detail != 5 { - let (logical_x, logical_y) = self.window_info.physical_to_logical( - event.event_x() as f64, - event.event_y() as f64 - ); + let physical_pos = Point::new(event.event_x() as f64, event.event_y() as f64); + let logical_pos = self.window_info.physical_to_logical(physical_pos); handler.on_event( self, Event::Mouse(MouseEvent::CursorMoved { - logical_x: logical_x.round() as i32, - logical_y: logical_y.round() as i32, - physical_x: event.event_x() as i32, - physical_y: event.event_y() as i32, + logical_pos: logical_pos.into(), + physical_pos: physical_pos.into(), }), ); } diff --git a/src/x11/xcb_connection.rs b/src/x11/xcb_connection.rs index d8a32ac..557865a 100644 --- a/src/x11/xcb_connection.rs +++ b/src/x11/xcb_connection.rs @@ -158,10 +158,10 @@ impl XcbConnection { pub fn set_resize_policy(&self, window_id: u32, size: &WindowSize, scale: f64) { match size { WindowSize::MinMaxLogical { min_size, max_size, keep_aspect, .. } => { - let min_physical_width = (min_size.0 as f64 * scale).round() as i32; - let min_physical_height = (min_size.1 as f64 * scale).round() as i32; - let max_physical_width = (max_size.0 as f64 * scale).round() as i32; - let max_physical_height = (max_size.1 as f64 * scale).round() as i32; + let min_physical_width = (min_size.width as f64 * scale).round() as i32; + let min_physical_height = (min_size.height as f64 * scale).round() as i32; + let max_physical_width = (max_size.width as f64 * scale).round() as i32; + let max_physical_height = (max_size.height as f64 * scale).round() as i32; let size_hints = if *keep_aspect { xcb_util::icccm::SizeHints::empty() @@ -192,17 +192,17 @@ impl XcbConnection { WindowSize::MinMaxPhysical { min_size, max_size, keep_aspect, .. } => { let size_hints = if *keep_aspect { xcb_util::icccm::SizeHints::empty() - .min_size(min_size.0 as i32, min_size.1 as i32) - .max_size(max_size.0 as i32, max_size.1 as i32) + .min_size(min_size.width as i32, min_size.height as i32) + .max_size(max_size.width as i32, max_size.height as i32) .aspect( - (min_size.0 as i32, min_size.1 as i32), - (max_size.0 as i32, max_size.1 as i32), + (min_size.width as i32, min_size.height as i32), + (max_size.width as i32, max_size.height as i32), ) .build() } else { xcb_util::icccm::SizeHints::empty() - .min_size(min_size.0 as i32, min_size.1 as i32) - .max_size(max_size.0 as i32, max_size.1 as i32) + .min_size(min_size.width as i32, min_size.height as i32) + .max_size(max_size.width as i32, max_size.height as i32) .build() }; From 11ee384908725836a84a72ed61e03f7fb1926a5b Mon Sep 17 00:00:00 2001 From: Billy Messenger Date: Sat, 17 Oct 2020 15:19:06 -0500 Subject: [PATCH 09/19] fix windows build --- src/win/window.rs | 42 ++++++++++++++++++++++++++++++------------ src/window_info.rs | 36 ++++++++++++++++++++++++++---------- 2 files changed, 56 insertions(+), 22 deletions(-) diff --git a/src/win/window.rs b/src/win/window.rs index 6e077a6..aaa758b 100644 --- a/src/win/window.rs +++ b/src/win/window.rs @@ -24,7 +24,7 @@ use raw_window_handle::{ use crate::{ Event, KeyboardEvent, MouseButton, MouseEvent, Parent::WithParent, ScrollDelta, WindowEvent, - WindowHandler, WindowInfo, WindowOpenOptions, + WindowHandler, WindowInfo, WindowOpenOptions, WindowOpenResult, WindowScalePolicy, Size, Point, }; unsafe fn message_box(title: &str, msg: &str) { @@ -76,13 +76,21 @@ unsafe extern "system" fn wnd_proc( match msg { WM_MOUSEMOVE => { - let x = (lparam & 0xFFFF) as i32; - let y = ((lparam >> 16) & 0xFFFF) as i32; - window_state.borrow_mut().handler.on_event( + let x = (lparam & 0xFFFF) as f64; + let y = ((lparam >> 16) & 0xFFFF) as f64; + let physical_pos = Point::new(x, y); + + let mut window_state = window_state.borrow_mut(); + + // FIXME: For some reason, the data in window_info is corrupted. + // let logical_pos = window_state.window_info.physical_to_logical(physical_pos); + let logical_pos = physical_pos; + + window_state.handler.on_event( &mut window, Event::Mouse(MouseEvent::CursorMoved { - x: x as i32, - y: y as i32, + logical_pos: logical_pos.into(), + physical_pos: physical_pos.into(), }), ); return 0; @@ -134,7 +142,7 @@ unsafe fn unregister_wnd_class(wnd_class: ATOM) { struct WindowState { window_class: ATOM, - scaling: Option, // DPI scale, 96.0 is "default". + window_info: WindowInfo, handler: H, } @@ -166,7 +174,7 @@ impl WindowHandle { } impl Window { - pub fn open(options: WindowOpenOptions) -> WindowHandle { + pub fn open(options: WindowOpenOptions) -> Result<(WindowHandle, WindowInfo), ()> { unsafe { let title = (options.title.to_owned() + "\0").as_ptr() as *const i8; @@ -180,13 +188,23 @@ impl Window { | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CLIPSIBLINGS; + + let scaling = match options.scale { + // TODO: Find system scale factor + WindowScalePolicy::TrySystemScaleFactor => 1.0, + WindowScalePolicy::TrySystemScaleFactorTimes(user_scale) => 1.0 * user_scale, + WindowScalePolicy::UseScaleFactor(user_scale) => user_scale, + WindowScalePolicy::NoScaling => 1.0, + }; + + let window_info = options.window_info_from_scale(scaling); let mut rect = RECT { left: 0, top: 0, // todo: check if usize fits into i32 - right: options.width as i32, - bottom: options.height as i32, + right: window_info.physical_size().width as i32, + bottom: window_info.physical_size().height as i32, }; // todo: add check flags https://github.com/wrl/rutabaga/blob/f30ff67e157375cafdbafe5fb549f1790443a3a8/src/platform/win/window.c#L351 @@ -226,7 +244,7 @@ impl Window { let window_state = Rc::new(RefCell::new(WindowState { window_class, - scaling: None, + window_info, handler, })); @@ -235,7 +253,7 @@ impl Window { SetWindowLongPtrA(hwnd, GWLP_USERDATA, Rc::into_raw(win) as *const _ as _); SetTimer(hwnd, 4242, 13, None); - WindowHandle { hwnd } + Ok((WindowHandle { hwnd }, window_info)) } } } diff --git a/src/window_info.rs b/src/window_info.rs index 81da6bf..b125e77 100644 --- a/src/window_info.rs +++ b/src/window_info.rs @@ -1,6 +1,7 @@ use crate::{Size, Point}; /// The info about the window +#[repr(C)] #[derive(Debug, Copy, Clone)] pub struct WindowInfo { logical_size: Size, @@ -11,27 +12,42 @@ pub struct WindowInfo { impl WindowInfo { pub fn from_logical_size(logical_size: Size, scale: f64) -> Self { - let scale_recip = 1.0 / scale; + let (scale_recip, physical_size) = if scale == 1.0 { + (1.0, logical_size) + } else { + ( + 1.0 / scale, + Size { + width: (logical_size.width as f64 * scale).round() as u32, + height: (logical_size.height as f64 * scale).round() as u32, + } + ) + }; Self { logical_size, - physical_size: Size { - width: (logical_size.width as f64 * scale).round() as u32, - height: (logical_size.height as f64 * scale).round() as u32, - }, + physical_size, scale, scale_recip, } } pub fn from_physical_size(physical_size: Size, scale: f64) -> Self { - let scale_recip = 1.0 / scale; + let (scale_recip, logical_size) = if scale == 1.0 { + (1.0, physical_size) + } else { + let scale_recip = 1.0 / scale; + ( + scale_recip, + Size { + width: (physical_size.width as f64 * scale_recip).round() as u32, + height: (physical_size.height as f64 * scale_recip).round() as u32, + } + ) + }; Self { - logical_size: Size { - width: (physical_size.width as f64 * scale_recip).round() as u32, - height: (physical_size.height as f64 * scale_recip).round() as u32, - }, + logical_size, physical_size, scale, scale_recip, From 3fca9d3c78664964f821dc7d7525822fdf37f7af Mon Sep 17 00:00:00 2001 From: Billy Messenger Date: Sat, 17 Oct 2020 15:23:24 -0500 Subject: [PATCH 10/19] remove #[repr(C)] as it did not work --- src/window_info.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/window_info.rs b/src/window_info.rs index b125e77..ba0a2a7 100644 --- a/src/window_info.rs +++ b/src/window_info.rs @@ -1,7 +1,6 @@ use crate::{Size, Point}; /// The info about the window -#[repr(C)] #[derive(Debug, Copy, Clone)] pub struct WindowInfo { logical_size: Size, From 5866bf372e1e17151c874df95502686a3cfe5b90 Mon Sep 17 00:00:00 2001 From: Billy Messenger Date: Sat, 17 Oct 2020 15:42:16 -0500 Subject: [PATCH 11/19] fix window_info_from_scale --- src/window_open_options.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/window_open_options.rs b/src/window_open_options.rs index 5ca7e17..ef30b25 100644 --- a/src/window_open_options.rs +++ b/src/window_open_options.rs @@ -67,7 +67,7 @@ impl WindowOpenOptions { WindowInfo::from_logical_size(initial_size, scale) }, WindowSize::MinMaxPhysical { initial_size, .. } => { - WindowInfo::from_logical_size(initial_size, scale) + WindowInfo::from_physical_size(initial_size, scale) } } } From 6bae3e7507a3162f538c15c82bf3730301da2cd5 Mon Sep 17 00:00:00 2001 From: Billy Messenger Date: Sat, 17 Oct 2020 16:47:36 -0500 Subject: [PATCH 12/19] Fix window_state pointer --- src/win/window.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/win/window.rs b/src/win/window.rs index aaa758b..872f751 100644 --- a/src/win/window.rs +++ b/src/win/window.rs @@ -82,9 +82,7 @@ unsafe extern "system" fn wnd_proc( let mut window_state = window_state.borrow_mut(); - // FIXME: For some reason, the data in window_info is corrupted. - // let logical_pos = window_state.window_info.physical_to_logical(physical_pos); - let logical_pos = physical_pos; + let logical_pos = window_state.window_info.physical_to_logical(physical_pos); window_state.handler.on_event( &mut window, @@ -242,15 +240,13 @@ impl Window { let handler = H::build(&mut window); - let window_state = Rc::new(RefCell::new(WindowState { + let window_state = Box::new(RefCell::new(WindowState { window_class, window_info, handler, })); - let win = Rc::new(RefCell::new(window)); - - SetWindowLongPtrA(hwnd, GWLP_USERDATA, Rc::into_raw(win) as *const _ as _); + SetWindowLongPtrA(hwnd, GWLP_USERDATA, Box::into_raw(window_state) as *const _ as _); SetTimer(hwnd, 4242, 13, None); Ok((WindowHandle { hwnd }, window_info)) From 688d45c7200d67e2badb1bd3e84166660e8fcced Mon Sep 17 00:00:00 2001 From: Billy Messenger Date: Sat, 17 Oct 2020 17:27:06 -0500 Subject: [PATCH 13/19] refactor to use conversion between Point and Size to PhyPoint and PhySize --- examples/open_window.rs | 6 +-- src/coordinates.rs | 93 ++++++++++++++++++++++++++++++++++++++ src/event.rs | 8 +--- src/lib.rs | 32 +------------ src/win/window.rs | 13 +++--- src/window_info.rs | 56 +++++++---------------- src/window_open_options.rs | 10 ++-- 7 files changed, 129 insertions(+), 89 deletions(-) create mode 100644 src/coordinates.rs diff --git a/examples/open_window.rs b/examples/open_window.rs index 8834368..7a04268 100644 --- a/examples/open_window.rs +++ b/examples/open_window.rs @@ -26,9 +26,9 @@ fn main() { let window_open_options = baseview::WindowOpenOptions { title: "baseview".into(), size: WindowSize::MinMaxLogical { - initial_size: baseview::Size::new(512, 512), - min_size: baseview::Size::new(200, 200), - max_size: baseview::Size::new(1024, 1024), + initial_size: baseview::Size::new(512.0, 512.0), + min_size: baseview::Size::new(200.0, 200.0), + max_size: baseview::Size::new(1024.0, 1024.0), keep_aspect: false, }, scale: WindowScalePolicy::TrySystemScaleFactor, diff --git a/src/coordinates.rs b/src/coordinates.rs new file mode 100644 index 0000000..286c50f --- /dev/null +++ b/src/coordinates.rs @@ -0,0 +1,93 @@ +use crate::WindowInfo; + +/// A point in logical coordinates +#[derive(Debug, Copy, Clone, PartialEq)] +pub struct Point { + pub x: f64, + pub y: f64 +} + +impl Point { + /// Create a new point in logical coordinates + pub fn new(x: f64, y: f64) -> Self { + Self { x, y } + } + + /// Convert to actual physical coordinates + #[inline] + pub fn to_physical(&self, window_info: &WindowInfo) -> PhyPoint { + PhyPoint { + x: (self.x * window_info.scale()).round() as i32, + y: (self.y * window_info.scale()).round() as i32, + } + } +} + +/// A point in actual physical coordinates +#[derive(Debug, Copy, Clone, PartialEq)] +pub struct PhyPoint { + pub x: i32, + pub y: i32 +} + +impl PhyPoint { + /// Create a new point in actual physical coordinates + pub fn new(x: i32, y: i32) -> Self { + Self { x, y } + } + + /// Convert to logical coordinates + #[inline] + pub fn to_logical(&self, window_info: &WindowInfo) -> Point { + Point { + x: f64::from(self.x) * window_info.scale_recip(), + y: f64::from(self.y) * window_info.scale_recip(), + } + } +} + +/// A size in logical coordinates +#[derive(Debug, Copy, Clone, PartialEq)] +pub struct Size { + pub width: f64, + pub height: f64, +} + +impl Size { + /// Create a new size in logical coordinates + pub fn new(width: f64, height: f64) -> Self { + Self { width, height } + } + + /// Convert to actual physical size + #[inline] + pub fn to_physical(&self, window_info: &WindowInfo) -> PhySize { + PhySize { + width: (self.width * window_info.scale()).round() as u32, + height: (self.height * window_info.scale()).round() as u32, + } + } +} + +/// An actual size in physical coordinates +#[derive(Debug, Copy, Clone, PartialEq)] +pub struct PhySize { + pub width: u32, + pub height: u32, +} + +impl PhySize { + /// Create a new size in actual physical coordinates + pub fn new(width: u32, height: u32) -> Self { + Self { width, height } + } + + /// Convert to logical size + #[inline] + pub fn to_logical(&self, window_info: &WindowInfo) -> Size { + Size { + width: f64::from(self.width) * window_info.scale_recip(), + height: f64::from(self.height) * window_info.scale_recip(), + } + } +} \ No newline at end of file diff --git a/src/event.rs b/src/event.rs index 31d5e24..6fae242 100644 --- a/src/event.rs +++ b/src/event.rs @@ -42,9 +42,7 @@ pub struct MouseClick { pub button: MouseButton, pub click_count: usize, /// The logical coordinates of the mouse position - logical_pos: Point, - /// The physical coordinates of the mouse position - physical_pos: Point, + pub position: Point, } #[derive(Debug, Clone, Copy, PartialEq)] @@ -52,9 +50,7 @@ pub enum MouseEvent { /// The mouse cursor was moved CursorMoved { /// The logical coordinates of the mouse position - logical_pos: Point, - /// The physical coordinates of the mouse position - physical_pos: Point, + position: Point, }, /// A mouse button was pressed. diff --git a/src/lib.rs b/src/lib.rs index 88d4fa3..97a1f25 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,11 +15,13 @@ mod macos; #[cfg(target_os = "macos")] pub use macos::*; +mod coordinates; mod event; mod keyboard; mod mouse_cursor; mod window_info; mod window_open_options; +pub use coordinates::*; pub use event::*; pub use keyboard::*; pub use mouse_cursor::MouseCursor; @@ -45,36 +47,6 @@ impl WindowHandle { } } -#[derive(Debug, Copy, Clone, PartialEq)] -pub struct Point { - pub x: T, - pub y: T, -} - -impl Point { - pub fn new(x: T, y: T) -> Self { - Self { x, y } - } -} - -impl From> for Point { - fn from(p: Point) -> Point { - Point::new(p.x.round() as i32, p.y.round() as i32) - } -} - -#[derive(Debug, Copy, Clone, PartialEq)] -pub struct Size { - pub width: u32, - pub height: u32, -} - -impl Size { - pub fn new(width: u32, height: u32) -> Self { - Self { width, height } - } -} - type WindowOpenResult = Result; pub trait WindowHandler { diff --git a/src/win/window.rs b/src/win/window.rs index 872f751..a2bf4f6 100644 --- a/src/win/window.rs +++ b/src/win/window.rs @@ -25,6 +25,7 @@ use raw_window_handle::{ use crate::{ Event, KeyboardEvent, MouseButton, MouseEvent, Parent::WithParent, ScrollDelta, WindowEvent, WindowHandler, WindowInfo, WindowOpenOptions, WindowOpenResult, WindowScalePolicy, Size, Point, + PhySize, PhyPoint, }; unsafe fn message_box(title: &str, msg: &str) { @@ -76,19 +77,19 @@ unsafe extern "system" fn wnd_proc( match msg { WM_MOUSEMOVE => { - let x = (lparam & 0xFFFF) as f64; - let y = ((lparam >> 16) & 0xFFFF) as f64; - let physical_pos = Point::new(x, y); + let x = (lparam & 0xFFFF) as i32; + let y = ((lparam >> 16) & 0xFFFF) as i32; + + let physical_pos = PhyPoint { x, y }; let mut window_state = window_state.borrow_mut(); - let logical_pos = window_state.window_info.physical_to_logical(physical_pos); + let logical_pos = physical_pos.to_logical(&window_state.window_info); window_state.handler.on_event( &mut window, Event::Mouse(MouseEvent::CursorMoved { - logical_pos: logical_pos.into(), - physical_pos: physical_pos.into(), + position: logical_pos, }), ); return 0; diff --git a/src/window_info.rs b/src/window_info.rs index ba0a2a7..e37d52c 100644 --- a/src/window_info.rs +++ b/src/window_info.rs @@ -1,26 +1,21 @@ -use crate::{Size, Point}; +use crate::{Size, PhySize}; /// The info about the window #[derive(Debug, Copy, Clone)] pub struct WindowInfo { logical_size: Size, - physical_size: Size, + physical_size: PhySize, scale: f64, scale_recip: f64, } impl WindowInfo { pub fn from_logical_size(logical_size: Size, scale: f64) -> Self { - let (scale_recip, physical_size) = if scale == 1.0 { - (1.0, logical_size) - } else { - ( - 1.0 / scale, - Size { - width: (logical_size.width as f64 * scale).round() as u32, - height: (logical_size.height as f64 * scale).round() as u32, - } - ) + let scale_recip = if scale == 1.0 { 1.0 } else { 1.0 / scale }; + + let physical_size = PhySize { + width: (logical_size.width * scale).round() as u32, + height: (logical_size.height * scale).round() as u32, }; Self { @@ -31,18 +26,12 @@ impl WindowInfo { } } - pub fn from_physical_size(physical_size: Size, scale: f64) -> Self { - let (scale_recip, logical_size) = if scale == 1.0 { - (1.0, physical_size) - } else { - let scale_recip = 1.0 / scale; - ( - scale_recip, - Size { - width: (physical_size.width as f64 * scale_recip).round() as u32, - height: (physical_size.height as f64 * scale_recip).round() as u32, - } - ) + pub fn from_physical_size(physical_size: PhySize, scale: f64) -> Self { + let scale_recip = if scale == 1.0 { 1.0 } else { 1.0 / scale }; + + let logical_size = Size { + width: f64::from(physical_size.width) * scale_recip, + height: f64::from(physical_size.height) * scale_recip, }; Self { @@ -59,7 +48,7 @@ impl WindowInfo { } /// The physical size of the window - pub fn physical_size(&self) -> Size { + pub fn physical_size(&self) -> PhySize { self.physical_size } @@ -68,19 +57,8 @@ impl WindowInfo { self.scale } - /// Convert physical coordinates to logical coordinates - pub fn physical_to_logical(&self, physical: Point) -> Point { - Point { - x: physical.x * self.scale_recip, - y: physical.y * self.scale_recip - } - } - - /// Convert logical coordinates to physical coordinates - pub fn logical_to_physical(&self, logical: Point) -> Point { - Point { - x: logical.x * self.scale, - y: logical.y * self.scale - } + /// The reciprocal of the scale factor of the window + pub fn scale_recip(&self) -> f64 { + self.scale_recip } } \ No newline at end of file diff --git a/src/window_open_options.rs b/src/window_open_options.rs index ef30b25..08409df 100644 --- a/src/window_open_options.rs +++ b/src/window_open_options.rs @@ -1,4 +1,4 @@ -use crate::{WindowInfo, Parent, Size}; +use crate::{WindowInfo, Parent, Size, PhySize}; /// The size of the window #[derive(Debug)] @@ -6,7 +6,7 @@ pub enum WindowSize { /// Use logical width and height Logical(Size), /// Use physical width and height - Physical(Size), + Physical(PhySize), /// Use minimum and maximum logical width and height MinMaxLogical { /// The initial logical width and height @@ -21,11 +21,11 @@ pub enum WindowSize { /// Use minimum and maximum physical width and height MinMaxPhysical { /// The initial physical width and height - initial_size: Size, + initial_size: PhySize, /// The minimum physical width and height - min_size: Size, + min_size: PhySize, /// The maximum physical width and height - max_size: Size, + max_size: PhySize, /// Whether to keep the aspect ratio when resizing (true), or not (false) keep_aspect: bool, }, From a91a5a112626250c7efb3d70aca25eeaa0c436bc Mon Sep 17 00:00:00 2001 From: Billy Messenger Date: Sat, 17 Oct 2020 17:36:28 -0500 Subject: [PATCH 14/19] update x11 code --- .github/workflows/rust.yml | 0 .gitignore | 0 .rustfmt.toml | 0 Cargo.toml | 0 README.md | 0 examples/open_window.rs | 0 src/coordinates.rs | 93 ------------------------------------- src/event.rs | 0 src/keyboard.rs | 0 src/lib.rs | 4 +- src/macos/mod.rs | 0 src/macos/window.rs | 0 src/mouse_cursor.rs | 0 src/win/mod.rs | 0 src/win/window.rs | 0 src/window_info.rs | 94 +++++++++++++++++++++++++++++++++++++- src/window_open_options.rs | 0 src/x11/cursor.rs | 0 src/x11/mod.rs | 0 src/x11/window.rs | 13 +++--- src/x11/xcb_connection.rs | 0 21 files changed, 99 insertions(+), 105 deletions(-) mode change 100644 => 100755 .github/workflows/rust.yml mode change 100644 => 100755 .gitignore mode change 100644 => 100755 .rustfmt.toml mode change 100644 => 100755 Cargo.toml mode change 100644 => 100755 README.md mode change 100644 => 100755 examples/open_window.rs delete mode 100644 src/coordinates.rs mode change 100644 => 100755 src/event.rs mode change 100644 => 100755 src/keyboard.rs mode change 100644 => 100755 src/lib.rs mode change 100644 => 100755 src/macos/mod.rs mode change 100644 => 100755 src/macos/window.rs mode change 100644 => 100755 src/mouse_cursor.rs mode change 100644 => 100755 src/win/mod.rs mode change 100644 => 100755 src/win/window.rs mode change 100644 => 100755 src/window_info.rs mode change 100644 => 100755 src/window_open_options.rs mode change 100644 => 100755 src/x11/cursor.rs mode change 100644 => 100755 src/x11/mod.rs mode change 100644 => 100755 src/x11/window.rs mode change 100644 => 100755 src/x11/xcb_connection.rs diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml old mode 100644 new mode 100755 diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 diff --git a/.rustfmt.toml b/.rustfmt.toml old mode 100644 new mode 100755 diff --git a/Cargo.toml b/Cargo.toml old mode 100644 new mode 100755 diff --git a/README.md b/README.md old mode 100644 new mode 100755 diff --git a/examples/open_window.rs b/examples/open_window.rs old mode 100644 new mode 100755 diff --git a/src/coordinates.rs b/src/coordinates.rs deleted file mode 100644 index 286c50f..0000000 --- a/src/coordinates.rs +++ /dev/null @@ -1,93 +0,0 @@ -use crate::WindowInfo; - -/// A point in logical coordinates -#[derive(Debug, Copy, Clone, PartialEq)] -pub struct Point { - pub x: f64, - pub y: f64 -} - -impl Point { - /// Create a new point in logical coordinates - pub fn new(x: f64, y: f64) -> Self { - Self { x, y } - } - - /// Convert to actual physical coordinates - #[inline] - pub fn to_physical(&self, window_info: &WindowInfo) -> PhyPoint { - PhyPoint { - x: (self.x * window_info.scale()).round() as i32, - y: (self.y * window_info.scale()).round() as i32, - } - } -} - -/// A point in actual physical coordinates -#[derive(Debug, Copy, Clone, PartialEq)] -pub struct PhyPoint { - pub x: i32, - pub y: i32 -} - -impl PhyPoint { - /// Create a new point in actual physical coordinates - pub fn new(x: i32, y: i32) -> Self { - Self { x, y } - } - - /// Convert to logical coordinates - #[inline] - pub fn to_logical(&self, window_info: &WindowInfo) -> Point { - Point { - x: f64::from(self.x) * window_info.scale_recip(), - y: f64::from(self.y) * window_info.scale_recip(), - } - } -} - -/// A size in logical coordinates -#[derive(Debug, Copy, Clone, PartialEq)] -pub struct Size { - pub width: f64, - pub height: f64, -} - -impl Size { - /// Create a new size in logical coordinates - pub fn new(width: f64, height: f64) -> Self { - Self { width, height } - } - - /// Convert to actual physical size - #[inline] - pub fn to_physical(&self, window_info: &WindowInfo) -> PhySize { - PhySize { - width: (self.width * window_info.scale()).round() as u32, - height: (self.height * window_info.scale()).round() as u32, - } - } -} - -/// An actual size in physical coordinates -#[derive(Debug, Copy, Clone, PartialEq)] -pub struct PhySize { - pub width: u32, - pub height: u32, -} - -impl PhySize { - /// Create a new size in actual physical coordinates - pub fn new(width: u32, height: u32) -> Self { - Self { width, height } - } - - /// Convert to logical size - #[inline] - pub fn to_logical(&self, window_info: &WindowInfo) -> Size { - Size { - width: f64::from(self.width) * window_info.scale_recip(), - height: f64::from(self.height) * window_info.scale_recip(), - } - } -} \ No newline at end of file diff --git a/src/event.rs b/src/event.rs old mode 100644 new mode 100755 diff --git a/src/keyboard.rs b/src/keyboard.rs old mode 100644 new mode 100755 diff --git a/src/lib.rs b/src/lib.rs old mode 100644 new mode 100755 index 97a1f25..d45e20a --- a/src/lib.rs +++ b/src/lib.rs @@ -15,17 +15,15 @@ mod macos; #[cfg(target_os = "macos")] pub use macos::*; -mod coordinates; mod event; mod keyboard; mod mouse_cursor; mod window_info; mod window_open_options; -pub use coordinates::*; pub use event::*; pub use keyboard::*; pub use mouse_cursor::MouseCursor; -pub use window_info::WindowInfo; +pub use window_info::*; pub use window_open_options::*; #[derive(Debug)] diff --git a/src/macos/mod.rs b/src/macos/mod.rs old mode 100644 new mode 100755 diff --git a/src/macos/window.rs b/src/macos/window.rs old mode 100644 new mode 100755 diff --git a/src/mouse_cursor.rs b/src/mouse_cursor.rs old mode 100644 new mode 100755 diff --git a/src/win/mod.rs b/src/win/mod.rs old mode 100644 new mode 100755 diff --git a/src/win/window.rs b/src/win/window.rs old mode 100644 new mode 100755 diff --git a/src/window_info.rs b/src/window_info.rs old mode 100644 new mode 100755 index e37d52c..1dad5d5 --- a/src/window_info.rs +++ b/src/window_info.rs @@ -1,5 +1,3 @@ -use crate::{Size, PhySize}; - /// The info about the window #[derive(Debug, Copy, Clone)] pub struct WindowInfo { @@ -61,4 +59,96 @@ impl WindowInfo { pub fn scale_recip(&self) -> f64 { self.scale_recip } +} + +/// A point in logical coordinates +#[derive(Debug, Copy, Clone, PartialEq)] +pub struct Point { + pub x: f64, + pub y: f64 +} + +impl Point { + /// Create a new point in logical coordinates + pub fn new(x: f64, y: f64) -> Self { + Self { x, y } + } + + /// Convert to actual physical coordinates + #[inline] + pub fn to_physical(&self, window_info: &WindowInfo) -> PhyPoint { + PhyPoint { + x: (self.x * window_info.scale()).round() as i32, + y: (self.y * window_info.scale()).round() as i32, + } + } +} + +/// A point in actual physical coordinates +#[derive(Debug, Copy, Clone, PartialEq)] +pub struct PhyPoint { + pub x: i32, + pub y: i32 +} + +impl PhyPoint { + /// Create a new point in actual physical coordinates + pub fn new(x: i32, y: i32) -> Self { + Self { x, y } + } + + /// Convert to logical coordinates + #[inline] + pub fn to_logical(&self, window_info: &WindowInfo) -> Point { + Point { + x: f64::from(self.x) * window_info.scale_recip(), + y: f64::from(self.y) * window_info.scale_recip(), + } + } +} + +/// A size in logical coordinates +#[derive(Debug, Copy, Clone, PartialEq)] +pub struct Size { + pub width: f64, + pub height: f64, +} + +impl Size { + /// Create a new size in logical coordinates + pub fn new(width: f64, height: f64) -> Self { + Self { width, height } + } + + /// Convert to actual physical size + #[inline] + pub fn to_physical(&self, window_info: &WindowInfo) -> PhySize { + PhySize { + width: (self.width * window_info.scale()).round() as u32, + height: (self.height * window_info.scale()).round() as u32, + } + } +} + +/// An actual size in physical coordinates +#[derive(Debug, Copy, Clone, PartialEq)] +pub struct PhySize { + pub width: u32, + pub height: u32, +} + +impl PhySize { + /// Create a new size in actual physical coordinates + pub fn new(width: u32, height: u32) -> Self { + Self { width, height } + } + + /// Convert to logical size + #[inline] + pub fn to_logical(&self, window_info: &WindowInfo) -> Size { + Size { + width: f64::from(self.width) * window_info.scale_recip(), + height: f64::from(self.height) * window_info.scale_recip(), + } + } } \ No newline at end of file diff --git a/src/window_open_options.rs b/src/window_open_options.rs old mode 100644 new mode 100755 diff --git a/src/x11/cursor.rs b/src/x11/cursor.rs old mode 100644 new mode 100755 diff --git a/src/x11/mod.rs b/src/x11/mod.rs old mode 100644 new mode 100755 diff --git a/src/x11/window.rs b/src/x11/window.rs old mode 100644 new mode 100755 index 92e5bba..8549255 --- a/src/x11/window.rs +++ b/src/x11/window.rs @@ -13,7 +13,7 @@ use super::XcbConnection; use crate::{ Event, KeyboardEvent, MouseButton, MouseCursor, MouseEvent, Parent, ScrollDelta, WindowEvent, WindowHandle, WindowHandler, WindowInfo, WindowOpenOptions, WindowOpenResult, - WindowScalePolicy, Size, Point, + WindowScalePolicy, PhyPoint, PhySize, }; pub struct Window { @@ -25,7 +25,7 @@ pub struct Window { frame_interval: Duration, event_loop_running: bool, - new_physical_size: Option + new_physical_size: Option } impl Window { @@ -307,7 +307,7 @@ impl Window { xcb::CONFIGURE_NOTIFY => { let event = unsafe { xcb::cast_event::(&event) }; - let new_physical_size = Size::new(event.width() as u32, event.height() as u32); + let new_physical_size = PhySize::new(event.width() as u32, event.height() as u32); if self.new_physical_size.is_some() || new_physical_size != self.window_info.physical_size() { self.new_physical_size = Some(new_physical_size); @@ -322,14 +322,13 @@ impl Window { let detail = event.detail(); if detail != 4 && detail != 5 { - let physical_pos = Point::new(event.event_x() as f64, event.event_y() as f64); - let logical_pos = self.window_info.physical_to_logical(physical_pos); + let physical_pos = PhyPoint::new(event.event_x() as i32, event.event_y() as i32); + let logical_pos = physical_pos.to_logical(&self.window_info); handler.on_event( self, Event::Mouse(MouseEvent::CursorMoved { - logical_pos: logical_pos.into(), - physical_pos: physical_pos.into(), + position: logical_pos, }), ); } diff --git a/src/x11/xcb_connection.rs b/src/x11/xcb_connection.rs old mode 100644 new mode 100755 From ad12985d086e76bc48b39ea5656669ecddc45418 Mon Sep 17 00:00:00 2001 From: Billy Messenger Date: Tue, 20 Oct 2020 15:52:09 -0500 Subject: [PATCH 15/19] put WindowHandle back into platform-specific code --- src/lib.rs | 10 ---------- src/x11/window.rs | 13 ++++++++++++- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index d45e20a..2b9b126 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,16 +35,6 @@ pub enum Parent { unsafe impl Send for Parent {} -pub struct WindowHandle { - thread: std::thread::JoinHandle<()>, -} - -impl WindowHandle { - pub fn app_run_blocking(self) { - let _ = self.thread.join(); - } -} - type WindowOpenResult = Result; pub trait WindowHandler { diff --git a/src/x11/window.rs b/src/x11/window.rs index 8549255..f7df37a 100755 --- a/src/x11/window.rs +++ b/src/x11/window.rs @@ -12,7 +12,7 @@ use raw_window_handle::{ use super::XcbConnection; use crate::{ Event, KeyboardEvent, MouseButton, MouseCursor, MouseEvent, Parent, ScrollDelta, WindowEvent, - WindowHandle, WindowHandler, WindowInfo, WindowOpenOptions, WindowOpenResult, + WindowHandler, WindowInfo, WindowOpenOptions, WindowOpenResult, WindowScalePolicy, PhyPoint, PhySize, }; @@ -28,6 +28,17 @@ pub struct Window { new_physical_size: Option } +// FIXME: move to outer crate context +pub struct WindowHandle { + thread: std::thread::JoinHandle<()>, +} + +impl WindowHandle { + pub fn app_run_blocking(self) { + let _ = self.thread.join(); + } +} + impl Window { pub fn open(options: WindowOpenOptions) -> Result<(WindowHandle, WindowInfo), ()> { let (tx, rx) = mpsc::sync_channel::(1); From 3fe752ca807042d9423b86015329800746c8be68 Mon Sep 17 00:00:00 2001 From: Billy Messenger Date: Tue, 20 Oct 2020 16:06:40 -0500 Subject: [PATCH 16/19] remove min/max resize policy --- examples/open_window.rs | 7 +--- src/lib.rs | 2 -- src/window_open_options.rs | 28 ---------------- src/x11/window.rs | 15 ++++----- src/x11/xcb_connection.rs | 67 +------------------------------------- 5 files changed, 9 insertions(+), 110 deletions(-) diff --git a/examples/open_window.rs b/examples/open_window.rs index 7809817..bc68483 100755 --- a/examples/open_window.rs +++ b/examples/open_window.rs @@ -21,12 +21,7 @@ impl WindowHandler for OpenWindowExample { fn main() { let window_open_options = baseview::WindowOpenOptions { title: "baseview".into(), - size: WindowSize::MinMaxLogical { - initial_size: baseview::Size::new(512.0, 512.0), - min_size: baseview::Size::new(200.0, 200.0), - max_size: baseview::Size::new(1024.0, 1024.0), - keep_aspect: false, - }, + size: WindowSize::Logical(baseview::Size::new(512.0, 512.0)), scale: WindowScalePolicy::TrySystemScaleFactor, parent: baseview::Parent::None, }; diff --git a/src/lib.rs b/src/lib.rs index c2f855b..642ac54 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,8 +35,6 @@ pub enum Parent { unsafe impl Send for Parent {} -type WindowOpenResult = Result; - pub trait WindowHandler { type Message; diff --git a/src/window_open_options.rs b/src/window_open_options.rs index 08409df..a69b16e 100755 --- a/src/window_open_options.rs +++ b/src/window_open_options.rs @@ -7,28 +7,6 @@ pub enum WindowSize { Logical(Size), /// Use physical width and height Physical(PhySize), - /// Use minimum and maximum logical width and height - MinMaxLogical { - /// The initial logical width and height - initial_size: Size, - /// The minimum logical width and height - min_size: Size, - /// The maximum logical width and height - max_size: Size, - /// Whether to keep the aspect ratio when resizing (true), or not (false) - keep_aspect: bool, - }, - /// Use minimum and maximum physical width and height - MinMaxPhysical { - /// The initial physical width and height - initial_size: PhySize, - /// The minimum physical width and height - min_size: PhySize, - /// The maximum physical width and height - max_size: PhySize, - /// Whether to keep the aspect ratio when resizing (true), or not (false) - keep_aspect: bool, - }, } /// The dpi scaling policy of the window @@ -63,12 +41,6 @@ impl WindowOpenOptions { match self.size { WindowSize::Logical(size) => WindowInfo::from_logical_size(size, scale), WindowSize::Physical(size) => WindowInfo::from_physical_size(size, scale), - WindowSize::MinMaxLogical { initial_size, .. } => { - WindowInfo::from_logical_size(initial_size, scale) - }, - WindowSize::MinMaxPhysical { initial_size, .. } => { - WindowInfo::from_physical_size(initial_size, scale) - } } } } \ No newline at end of file diff --git a/src/x11/window.rs b/src/x11/window.rs index a6eeb21..f20d637 100755 --- a/src/x11/window.rs +++ b/src/x11/window.rs @@ -12,8 +12,7 @@ use raw_window_handle::{ use super::XcbConnection; use crate::{ Event, KeyboardEvent, MouseButton, MouseCursor, MouseEvent, Parent, ScrollDelta, WindowEvent, - WindowHandler, WindowInfo, WindowOpenOptions, WindowOpenResult, - WindowScalePolicy, PhyPoint, PhySize, + WindowHandler, WindowInfo, WindowOpenOptions, WindowScalePolicy, PhyPoint, PhySize, }; pub struct Window { @@ -39,6 +38,8 @@ impl WindowHandle { } } +type WindowOpenResult = Result<(), ()>; + impl Window { pub fn open(options: WindowOpenOptions, build: B) -> WindowHandle where H: WindowHandler, @@ -54,9 +55,9 @@ impl Window { }); // FIXME: placeholder types for returning errors in the future - let window_info = rx.recv().unwrap().unwrap(); + let _ = rx.recv(); - Ok((WindowHandle { thread }, window_info)) + WindowHandle { thread } } fn window_thread(options: WindowOpenOptions, build: B, @@ -158,8 +159,6 @@ impl Window { &[wm_delete_window], ); }); - - xcb_connection.set_resize_policy(window_id, &options.size, scaling); xcb_connection.conn.flush(); @@ -177,10 +176,10 @@ impl Window { let mut handler = build(&mut window); - let _ = tx.send(Ok(window_info)); + let _ = tx.send(Ok(())); window.run_event_loop(&mut handler); - Ok(window_info) + Ok(()) } pub fn window_info(&self) -> &WindowInfo { diff --git a/src/x11/xcb_connection.rs b/src/x11/xcb_connection.rs index 557865a..db2113a 100755 --- a/src/x11/xcb_connection.rs +++ b/src/x11/xcb_connection.rs @@ -5,7 +5,7 @@ use std::ffi::{CStr, CString}; use std::collections::HashMap; -use crate::{MouseCursor, WindowSize}; +use crate::MouseCursor; use super::cursor; @@ -154,69 +154,4 @@ impl XcbConnection { .entry(cursor) .or_insert_with(|| cursor::get_xcursor(dpy, cursor)) } - - pub fn set_resize_policy(&self, window_id: u32, size: &WindowSize, scale: f64) { - match size { - WindowSize::MinMaxLogical { min_size, max_size, keep_aspect, .. } => { - let min_physical_width = (min_size.width as f64 * scale).round() as i32; - let min_physical_height = (min_size.height as f64 * scale).round() as i32; - let max_physical_width = (max_size.width as f64 * scale).round() as i32; - let max_physical_height = (max_size.height as f64 * scale).round() as i32; - - let size_hints = if *keep_aspect { - xcb_util::icccm::SizeHints::empty() - .min_size(min_physical_width, min_physical_height) - .max_size(max_physical_width, max_physical_height) - .aspect( - (min_physical_width, min_physical_height), - (max_physical_width, max_physical_height), - ) - .build() - } else { - xcb_util::icccm::SizeHints::empty() - .min_size(min_physical_width, min_physical_height) - .max_size(max_physical_width, max_physical_height) - .build() - }; - - self.atoms.wm_normal_hints - .map(|wm_normal_hints| { - xcb_util::icccm::set_wm_size_hints( - &self.conn, - window_id, - wm_normal_hints, - &size_hints, - ); - }); - } - WindowSize::MinMaxPhysical { min_size, max_size, keep_aspect, .. } => { - let size_hints = if *keep_aspect { - xcb_util::icccm::SizeHints::empty() - .min_size(min_size.width as i32, min_size.height as i32) - .max_size(max_size.width as i32, max_size.height as i32) - .aspect( - (min_size.width as i32, min_size.height as i32), - (max_size.width as i32, max_size.height as i32), - ) - .build() - } else { - xcb_util::icccm::SizeHints::empty() - .min_size(min_size.width as i32, min_size.height as i32) - .max_size(max_size.width as i32, max_size.height as i32) - .build() - }; - - self.atoms.wm_normal_hints - .map(|wm_normal_hints| { - xcb_util::icccm::set_wm_size_hints( - &self.conn, - window_id, - wm_normal_hints, - &size_hints, - ); - }); - } - _ => {} - } - } } From 2ee975231b88252a7571f85804336c013d674221 Mon Sep 17 00:00:00 2001 From: Billy Messenger Date: Tue, 20 Oct 2020 17:04:37 -0500 Subject: [PATCH 17/19] fix Windows build --- .github/workflows/rust.yml | 0 .gitignore | 0 .rustfmt.toml | 0 Cargo.toml | 0 README.md | 0 examples/open_window.rs | 0 src/event.rs | 0 src/keyboard.rs | 0 src/lib.rs | 0 src/macos/mod.rs | 0 src/macos/window.rs | 0 src/mouse_cursor.rs | 0 src/win/mod.rs | 0 src/win/window.rs | 19 +++++++++++++------ src/window_info.rs | 0 src/window_open_options.rs | 0 src/x11/cursor.rs | 0 src/x11/mod.rs | 0 src/x11/window.rs | 0 src/x11/xcb_connection.rs | 0 20 files changed, 13 insertions(+), 6 deletions(-) mode change 100755 => 100644 .github/workflows/rust.yml mode change 100755 => 100644 .gitignore mode change 100755 => 100644 .rustfmt.toml mode change 100755 => 100644 Cargo.toml mode change 100755 => 100644 README.md mode change 100755 => 100644 examples/open_window.rs mode change 100755 => 100644 src/event.rs mode change 100755 => 100644 src/keyboard.rs mode change 100755 => 100644 src/lib.rs mode change 100755 => 100644 src/macos/mod.rs mode change 100755 => 100644 src/macos/window.rs mode change 100755 => 100644 src/mouse_cursor.rs mode change 100755 => 100644 src/win/mod.rs mode change 100755 => 100644 src/win/window.rs mode change 100755 => 100644 src/window_info.rs mode change 100755 => 100644 src/window_open_options.rs mode change 100755 => 100644 src/x11/cursor.rs mode change 100755 => 100644 src/x11/mod.rs mode change 100755 => 100644 src/x11/window.rs mode change 100755 => 100644 src/x11/xcb_connection.rs diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml old mode 100755 new mode 100644 diff --git a/.gitignore b/.gitignore old mode 100755 new mode 100644 diff --git a/.rustfmt.toml b/.rustfmt.toml old mode 100755 new mode 100644 diff --git a/Cargo.toml b/Cargo.toml old mode 100755 new mode 100644 diff --git a/README.md b/README.md old mode 100755 new mode 100644 diff --git a/examples/open_window.rs b/examples/open_window.rs old mode 100755 new mode 100644 diff --git a/src/event.rs b/src/event.rs old mode 100755 new mode 100644 diff --git a/src/keyboard.rs b/src/keyboard.rs old mode 100755 new mode 100644 diff --git a/src/lib.rs b/src/lib.rs old mode 100755 new mode 100644 diff --git a/src/macos/mod.rs b/src/macos/mod.rs old mode 100755 new mode 100644 diff --git a/src/macos/window.rs b/src/macos/window.rs old mode 100755 new mode 100644 diff --git a/src/mouse_cursor.rs b/src/mouse_cursor.rs old mode 100755 new mode 100644 diff --git a/src/win/mod.rs b/src/win/mod.rs old mode 100755 new mode 100644 diff --git a/src/win/window.rs b/src/win/window.rs old mode 100755 new mode 100644 index c74e7d4..bab6d9e --- a/src/win/window.rs +++ b/src/win/window.rs @@ -8,7 +8,7 @@ use winapi::um::winuser::{ SetWindowLongPtrA, TranslateMessage, UnregisterClassA, CS_OWNDC, GWLP_USERDATA, MB_ICONERROR, MB_OK, MB_TOPMOST, MSG, WM_CLOSE, WM_CREATE, WM_MOUSEMOVE, WM_PAINT, WM_SHOWWINDOW, WM_TIMER, WNDCLASSA, WS_CAPTION, WS_CHILD, WS_CLIPSIBLINGS, WS_MAXIMIZEBOX, WS_MINIMIZEBOX, - WS_POPUPWINDOW, WS_SIZEBOX, WS_VISIBLE, + WS_POPUPWINDOW, WS_SIZEBOX, WS_VISIBLE, WM_DPICHANGED, }; use std::cell::RefCell; @@ -24,8 +24,7 @@ use raw_window_handle::{ use crate::{ Event, KeyboardEvent, MouseButton, MouseEvent, Parent::WithParent, ScrollDelta, WindowEvent, - WindowHandler, WindowInfo, WindowOpenOptions, WindowOpenResult, WindowScalePolicy, Size, Point, - PhySize, PhyPoint, + WindowHandler, WindowInfo, WindowOpenOptions, WindowScalePolicy, Size, Point, PhySize, PhyPoint, }; unsafe fn message_box(title: &str, msg: &str) { @@ -108,6 +107,9 @@ unsafe extern "system" fn wnd_proc( .on_event(&mut window, Event::Window(WindowEvent::WillClose)); return DefWindowProcA(hwnd, msg, wparam, lparam); } + WM_DPICHANGED => { + // TODO: Notify app of DPI change + } _ => {} } } @@ -194,8 +196,8 @@ impl Window { let scaling = match options.scale { // TODO: Find system scale factor - WindowScalePolicy::TrySystemScaleFactor => 1.0, - WindowScalePolicy::TrySystemScaleFactorTimes(user_scale) => 1.0 * user_scale, + WindowScalePolicy::TrySystemScaleFactor => get_scaling().unwrap_or(1.0), + WindowScalePolicy::TrySystemScaleFactorTimes(user_scale) => get_scaling().unwrap_or(1.0) * user_scale, WindowScalePolicy::UseScaleFactor(user_scale) => user_scale, WindowScalePolicy::NoScaling => 1.0, }; @@ -254,7 +256,7 @@ impl Window { SetWindowLongPtrA(hwnd, GWLP_USERDATA, Box::into_raw(window_state) as *const _ as _); SetTimer(hwnd, 4242, 13, None); - Ok((WindowHandle { hwnd }, window_info)) + WindowHandle { hwnd } } } } @@ -267,3 +269,8 @@ unsafe impl HasRawWindowHandle for Window { }) } } + +fn get_scaling() -> Option { + // TODO: find system scaling + None +} \ No newline at end of file diff --git a/src/window_info.rs b/src/window_info.rs old mode 100755 new mode 100644 diff --git a/src/window_open_options.rs b/src/window_open_options.rs old mode 100755 new mode 100644 diff --git a/src/x11/cursor.rs b/src/x11/cursor.rs old mode 100755 new mode 100644 diff --git a/src/x11/mod.rs b/src/x11/mod.rs old mode 100755 new mode 100644 diff --git a/src/x11/window.rs b/src/x11/window.rs old mode 100755 new mode 100644 diff --git a/src/x11/xcb_connection.rs b/src/x11/xcb_connection.rs old mode 100755 new mode 100644 From 84cac3e7ba8d55fa0e8337f749dcfbd3e3fbe6e9 Mon Sep 17 00:00:00 2001 From: Billy Messenger Date: Tue, 20 Oct 2020 17:07:37 -0500 Subject: [PATCH 18/19] attempt to fix mac build --- src/macos/window.rs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/macos/window.rs b/src/macos/window.rs index e16f5b3..1152ea2 100644 --- a/src/macos/window.rs +++ b/src/macos/window.rs @@ -41,9 +41,22 @@ impl Window { unsafe { let _pool = NSAutoreleasePool::new(nil); + let scaling = match options.scale { + // TODO: Find system scale factor + WindowScalePolicy::TrySystemScaleFactor => get_scaling().unwrap_or(1.0), + WindowScalePolicy::TrySystemScaleFactorTimes(user_scale) => get_scaling().unwrap_or(1.0) * user_scale, + WindowScalePolicy::UseScaleFactor(user_scale) => user_scale, + WindowScalePolicy::NoScaling => 1.0, + }; + + let window_info = options.window_info_from_scale(scaling); + let rect = NSRect::new( NSPoint::new(0.0, 0.0), - NSSize::new(options.width as f64, options.height as f64), + NSSize::new( + window_info.logical_size().width as f64, + window_info.logical_size().height as f64 + ), ); let ns_window = NSWindow::alloc(nil) @@ -83,3 +96,8 @@ unsafe impl HasRawWindowHandle for Window { }) } } + +fn get_scaling() -> Option { + // TODO: find system scaling + None +} From b0196b8c5fc6c13dbd2667f8dac37ea90af90bcc Mon Sep 17 00:00:00 2001 From: Billy Messenger Date: Tue, 20 Oct 2020 17:09:59 -0500 Subject: [PATCH 19/19] attempt to fix mac build --- src/macos/window.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/macos/window.rs b/src/macos/window.rs index 1152ea2..c682f61 100644 --- a/src/macos/window.rs +++ b/src/macos/window.rs @@ -12,7 +12,7 @@ use raw_window_handle::{macos::MacOSHandle, HasRawWindowHandle, RawWindowHandle} use crate::{ Event, KeyboardEvent, MouseButton, MouseEvent, ScrollDelta, WindowEvent, WindowHandler, - WindowOpenOptions, + WindowOpenOptions, WindowScalePolicy, }; pub struct Window {