From 6825fed07379b942e6a8df94f7ee16514d5f7e7c Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 10 Feb 2024 17:40:06 -0700 Subject: [PATCH] On Orbital, implement various Window methods Implement the following methods on the `Window`: - `Window::set_cursor_grab`. - `Window::set_cursor_visible`. - `Window::drag_window`. - `Window::drag_resize_window`. - `Window::set_transparent`. - `Window::set_visible`. - `Window::is_visible`. - `Window::set_resizable`. - `Window::is_resizable`. - `Window::set_maximized`. - `Window::is_maximized`. - `Window::set_decorations`. - `Window::is_decorated`. - `Window::set_window_level`. To make locked pointer useful, the `DeviceEvent::MouseMotion` event was also implemented. --- CHANGELOG.md | 15 +++ src/platform_impl/orbital/event_loop.rs | 14 ++- src/platform_impl/orbital/window.rs | 145 +++++++++++++++++------- src/window.rs | 16 +-- 4 files changed, 140 insertions(+), 50 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1387d34a..87a7522e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,6 +53,21 @@ Unreleased` header. - On Orbital, fix `logical_key` and `text` not reported in `KeyEvent`. - On Orbital, implement `KeyEventExtModifierSupplement`. - On Orbital, map keys to `NamedKey` when possible. +- On Orbital, implement `set_cursor_grab`. +- On Orbital, implement `set_cursor_visible`. +- On Orbital, implement `drag_window`. +- On Orbital, implement `drag_resize_window`. +- On Orbital, implement `set_transparent`. +- On Orbital, implement `set_visible`. +- On Orbital, implement `is_visible`. +- On Orbital, implement `set_resizable`. +- On Orbital, implement `is_resizable`. +- On Orbital, implement `set_maximized`. +- On Orbital, implement `is_maximized`. +- On Orbital, implement `set_decorations`. +- On Orbital, implement `is_decorated`. +- On Orbital, implement `set_window_level`. +- On Orbital, emit `DeviceEvent::MouseMotion`. # 0.29.10 diff --git a/src/platform_impl/orbital/event_loop.rs b/src/platform_impl/orbital/event_loop.rs index fcdfc645..ae332b6a 100644 --- a/src/platform_impl/orbital/event_loop.rs +++ b/src/platform_impl/orbital/event_loop.rs @@ -9,8 +9,8 @@ use std::{ use bitflags::bitflags; use orbclient::{ - ButtonEvent, EventOption, FocusEvent, HoverEvent, KeyEvent, MouseEvent, MoveEvent, QuitEvent, - ResizeEvent, ScrollEvent, TextInputEvent, + ButtonEvent, EventOption, FocusEvent, HoverEvent, KeyEvent, MouseEvent, MouseRelativeEvent, + MoveEvent, QuitEvent, ResizeEvent, ScrollEvent, TextInputEvent, }; use smol_str::SmolStr; @@ -457,6 +457,14 @@ impl EventLoop { }, }); } + EventOption::MouseRelative(MouseRelativeEvent { dx, dy }) => { + event_handler(event::Event::DeviceEvent { + device_id: event::DeviceId(DeviceId), + event: event::DeviceEvent::MouseMotion { + delta: (dx as f64, dy as f64), + }, + }); + } EventOption::Button(ButtonEvent { left, middle, @@ -510,7 +518,7 @@ impl EventLoop { // Acknowledge resize after event loop. event_state.resize_opt = Some((width, height)); } - //TODO: Clipboard + //TODO: Screen, Clipboard, Drop EventOption::Hover(HoverEvent { entered }) => { if entered { event_handler(event::Event::WindowEvent { diff --git a/src/platform_impl/orbital/window.rs b/src/platform_impl/orbital/window.rs index a019a8e6..7f9e7fa4 100644 --- a/src/platform_impl/orbital/window.rs +++ b/src/platform_impl/orbital/window.rs @@ -13,7 +13,8 @@ use crate::{ }; use super::{ - EventLoopWindowTarget, MonitorHandle, RedoxSocket, TimeSocket, WindowId, WindowProperties, + EventLoopWindowTarget, MonitorHandle, OsError, RedoxSocket, TimeSocket, WindowId, + WindowProperties, }; // These values match the values uses in the `window_new` function in orbital: @@ -21,7 +22,9 @@ use super::{ const ORBITAL_FLAG_ASYNC: char = 'a'; const ORBITAL_FLAG_BACK: char = 'b'; const ORBITAL_FLAG_FRONT: char = 'f'; +const ORBITAL_FLAG_HIDDEN: char = 'h'; const ORBITAL_FLAG_BORDERLESS: char = 'l'; +const ORBITAL_FLAG_MAXIMIZED: char = 'm'; const ORBITAL_FLAG_RESIZABLE: char = 'r'; const ORBITAL_FLAG_TRANSPARENT: char = 't'; @@ -57,11 +60,15 @@ impl Window { // Async by default. let mut flag_str = ORBITAL_FLAG_ASYNC.to_string(); + if attrs.maximized { + flag_str.push(ORBITAL_FLAG_MAXIMIZED); + } + if attrs.resizable { flag_str.push(ORBITAL_FLAG_RESIZABLE); } - //TODO: maximized, fullscreen, visible + //TODO: fullscreen if attrs.transparent { flag_str.push(ORBITAL_FLAG_TRANSPARENT); @@ -71,6 +78,10 @@ impl Window { flag_str.push(ORBITAL_FLAG_BORDERLESS); } + if !attrs.visible { + flag_str.push(ORBITAL_FLAG_HIDDEN); + } + match attrs.window_level { window::WindowLevel::AlwaysOnBottom => { flag_str.push(ORBITAL_FLAG_BACK); @@ -129,6 +140,23 @@ impl Window { f(self) } + fn get_flag(&self, flag: char) -> Result { + let mut buf: [u8; 4096] = [0; 4096]; + let path = self + .window_socket + .fpath(&mut buf) + .map_err(|err| error::ExternalError::Os(os_error!(OsError::new(err))))?; + let properties = WindowProperties::new(path); + Ok(properties.flags.contains(flag)) + } + + fn set_flag(&self, flag: char, value: bool) -> Result<(), error::ExternalError> { + self.window_socket + .write(format!("F,{flag},{}", if value { 1 } else { 0 }).as_bytes()) + .map_err(|err| error::ExternalError::Os(os_error!(OsError::new(err))))?; + Ok(()) + } + #[inline] pub fn id(&self) -> WindowId { WindowId { @@ -254,17 +282,21 @@ impl Window { } #[inline] - pub fn set_transparent(&self, _transparent: bool) {} + pub fn set_transparent(&self, transparent: bool) { + let _ = self.set_flag(ORBITAL_FLAG_TRANSPARENT, transparent); + } #[inline] pub fn set_blur(&self, _blur: bool) {} #[inline] - pub fn set_visible(&self, _visibility: bool) {} + pub fn set_visible(&self, visible: bool) { + let _ = self.set_flag(ORBITAL_FLAG_HIDDEN, !visible); + } #[inline] pub fn is_visible(&self) -> Option { - None + Some(!self.get_flag(ORBITAL_FLAG_HIDDEN).unwrap_or(false)) } #[inline] @@ -276,17 +308,13 @@ impl Window { pub fn set_resize_increments(&self, _increments: Option) {} #[inline] - pub fn set_resizable(&self, _resizeable: bool) {} + pub fn set_resizable(&self, resizeable: bool) { + let _ = self.set_flag(ORBITAL_FLAG_RESIZABLE, resizeable); + } #[inline] pub fn is_resizable(&self) -> bool { - let mut buf: [u8; 4096] = [0; 4096]; - let path = self - .window_socket - .fpath(&mut buf) - .expect("failed to read properties"); - let properties = WindowProperties::new(path); - properties.flags.contains(ORBITAL_FLAG_RESIZABLE) + self.get_flag(ORBITAL_FLAG_RESIZABLE).unwrap_or(false) } #[inline] @@ -298,11 +326,13 @@ impl Window { } #[inline] - pub fn set_maximized(&self, _maximized: bool) {} + pub fn set_maximized(&self, maximized: bool) { + let _ = self.set_flag(ORBITAL_FLAG_MAXIMIZED, maximized); + } #[inline] pub fn is_maximized(&self) -> bool { - false + self.get_flag(ORBITAL_FLAG_MAXIMIZED).unwrap_or(false) } #[inline] @@ -314,21 +344,30 @@ impl Window { } #[inline] - pub fn set_decorations(&self, _decorations: bool) {} - - #[inline] - pub fn is_decorated(&self) -> bool { - let mut buf: [u8; 4096] = [0; 4096]; - let path = self - .window_socket - .fpath(&mut buf) - .expect("failed to read properties"); - let properties = WindowProperties::new(path); - !properties.flags.contains(ORBITAL_FLAG_BORDERLESS) + pub fn set_decorations(&self, decorations: bool) { + let _ = self.set_flag(ORBITAL_FLAG_BORDERLESS, !decorations); } #[inline] - pub fn set_window_level(&self, _level: window::WindowLevel) {} + pub fn is_decorated(&self) -> bool { + !self.get_flag(ORBITAL_FLAG_BORDERLESS).unwrap_or(false) + } + + #[inline] + pub fn set_window_level(&self, level: window::WindowLevel) { + match level { + window::WindowLevel::AlwaysOnBottom => { + let _ = self.set_flag(ORBITAL_FLAG_BACK, true); + } + window::WindowLevel::Normal => { + let _ = self.set_flag(ORBITAL_FLAG_BACK, false); + let _ = self.set_flag(ORBITAL_FLAG_FRONT, false); + } + window::WindowLevel::AlwaysOnTop => { + let _ = self.set_flag(ORBITAL_FLAG_FRONT, true); + } + } + } #[inline] pub fn set_window_icon(&self, _window_icon: Option) {} @@ -359,30 +398,58 @@ impl Window { } #[inline] - pub fn set_cursor_grab(&self, _: window::CursorGrabMode) -> Result<(), error::ExternalError> { - Err(error::ExternalError::NotSupported( - error::NotSupportedError::new(), - )) + pub fn set_cursor_grab( + &self, + mode: window::CursorGrabMode, + ) -> Result<(), error::ExternalError> { + let (grab, relative) = match mode { + window::CursorGrabMode::None => (false, false), + window::CursorGrabMode::Confined => (true, false), + window::CursorGrabMode::Locked => (true, true), + }; + self.window_socket + .write(format!("M,G,{}", if grab { 1 } else { 0 }).as_bytes()) + .map_err(|err| error::ExternalError::Os(os_error!(OsError::new(err))))?; + self.window_socket + .write(format!("M,R,{}", if relative { 1 } else { 0 }).as_bytes()) + .map_err(|err| error::ExternalError::Os(os_error!(OsError::new(err))))?; + Ok(()) } #[inline] - pub fn set_cursor_visible(&self, _: bool) {} + pub fn set_cursor_visible(&self, visible: bool) { + let _ = self + .window_socket + .write(format!("M,C,{}", if visible { 1 } else { 0 }).as_bytes()); + } #[inline] pub fn drag_window(&self) -> Result<(), error::ExternalError> { - Err(error::ExternalError::NotSupported( - error::NotSupportedError::new(), - )) + self.window_socket + .write(b"D") + .map_err(|err| error::ExternalError::Os(os_error!(OsError::new(err))))?; + Ok(()) } #[inline] pub fn drag_resize_window( &self, - _direction: window::ResizeDirection, + direction: window::ResizeDirection, ) -> Result<(), error::ExternalError> { - Err(error::ExternalError::NotSupported( - error::NotSupportedError::new(), - )) + let arg = match direction { + window::ResizeDirection::East => "R", + window::ResizeDirection::North => "T", + window::ResizeDirection::NorthEast => "T,R", + window::ResizeDirection::NorthWest => "T,L", + window::ResizeDirection::South => "B", + window::ResizeDirection::SouthEast => "B,R", + window::ResizeDirection::SouthWest => "B,L", + window::ResizeDirection::West => "L", + }; + self.window_socket + .write(format!("D,{}", arg).as_bytes()) + .map_err(|err| error::ExternalError::Os(os_error!(OsError::new(err))))?; + Ok(()) } #[inline] diff --git a/src/window.rs b/src/window.rs index 12747113..fb3f435b 100644 --- a/src/window.rs +++ b/src/window.rs @@ -946,7 +946,7 @@ impl Window { /// /// ## Platform-specific /// - /// - **Web / iOS / Android / Orbital:** Unsupported. + /// - **Web / iOS / Android:** Unsupported. /// - **X11:** Can only be set while building the window, with [`WindowBuilder::with_transparent`]. #[inline] pub fn set_transparent(&self, transparent: bool) { @@ -1079,7 +1079,7 @@ impl Window { /// /// ## Platform-specific /// - /// - **iOS / Android / Web / Orbital:** Unsupported. + /// - **iOS / Android / Web:** Unsupported. #[inline] pub fn set_maximized(&self, maximized: bool) { self.window @@ -1090,7 +1090,7 @@ impl Window { /// /// ## Platform-specific /// - /// - **iOS / Android / Web / Orbital:** Unsupported. + /// - **iOS / Android / Web:** Unsupported. #[inline] pub fn is_maximized(&self) -> bool { self.window.maybe_wait_on_main(|w| w.is_maximized()) @@ -1450,7 +1450,7 @@ impl Window { /// - **Wayland:** The cursor is only hidden within the confines of the window. /// - **macOS:** The cursor is hidden as long as the window has input focus, even if the cursor is /// outside of the window. - /// - **iOS / Android / Orbital:** Unsupported. + /// - **iOS / Android:** Unsupported. #[inline] pub fn set_cursor_visible(&self, visible: bool) { self.window @@ -1467,7 +1467,7 @@ impl Window { /// - **X11:** Un-grabs the cursor. /// - **Wayland:** Requires the cursor to be inside the window to be dragged. /// - **macOS:** May prevent the button release event to be triggered. - /// - **iOS / Android / Web / Orbital:** Always returns an [`ExternalError::NotSupported`]. + /// - **iOS / Android / Web:** Always returns an [`ExternalError::NotSupported`]. #[inline] pub fn drag_window(&self) -> Result<(), ExternalError> { self.window.maybe_wait_on_main(|w| w.drag_window()) @@ -1481,7 +1481,7 @@ impl Window { /// ## Platform-specific /// /// - **macOS:** Always returns an [`ExternalError::NotSupported`] - /// - **iOS / Android / Web / Orbital:** Always returns an [`ExternalError::NotSupported`]. + /// - **iOS / Android / Web:** Always returns an [`ExternalError::NotSupported`]. #[inline] pub fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), ExternalError> { self.window @@ -1642,7 +1642,7 @@ pub enum CursorGrabMode { /// ## Platform-specific /// /// - **macOS:** Not implemented. Always returns [`ExternalError::NotSupported`] for now. - /// - **iOS / Android / Web / Orbital:** Always returns an [`ExternalError::NotSupported`]. + /// - **iOS / Android / Web:** Always returns an [`ExternalError::NotSupported`]. Confined, /// The cursor is locked inside the window area to the certain position. @@ -1653,7 +1653,7 @@ pub enum CursorGrabMode { /// ## Platform-specific /// /// - **X11 / Windows:** Not implemented. Always returns [`ExternalError::NotSupported`] for now. - /// - **iOS / Android / Orbital:** Always returns an [`ExternalError::NotSupported`]. + /// - **iOS / Android:** Always returns an [`ExternalError::NotSupported`]. Locked, }