From b92a16d41d63b30d75fd68e0e7a15dace7cfc118 Mon Sep 17 00:00:00 2001 From: jgcodes2020 Date: Sun, 11 Feb 2024 22:53:41 -0500 Subject: [PATCH 01/13] initial work --- .../linux/wayland/window/state.rs | 31 ++++++++++--------- .../linux/wayland/window/state/subsurface.rs | 7 +++++ .../linux/wayland/window/state/toplevel.rs | 5 +++ 3 files changed, 29 insertions(+), 14 deletions(-) create mode 100644 src/platform_impl/linux/wayland/window/state/subsurface.rs create mode 100644 src/platform_impl/linux/wayland/window/state/toplevel.rs diff --git a/src/platform_impl/linux/wayland/window/state.rs b/src/platform_impl/linux/wayland/window/state.rs index 4a59a0741c..1aa0503ab8 100644 --- a/src/platform_impl/linux/wayland/window/state.rs +++ b/src/platform_impl/linux/wayland/window/state.rs @@ -44,6 +44,9 @@ use crate::platform_impl::wayland::seat::{ }; use crate::platform_impl::wayland::state::{WindowCompositorUpdate, WinitState}; +mod subsurface; +mod toplevel; + #[cfg(feature = "sctk-adwaita")] pub type WinitFrame = sctk_adwaita::AdwaitaFrame; #[cfg(not(feature = "sctk-adwaita"))] @@ -60,6 +63,20 @@ pub struct WindowState { /// The window frame, which is created from the configure request. frame: Option, + /// Whether the client side decorations have pending move operations. + /// + /// The value is the serial of the event triggered moved. + has_pending_move: Option, + + /// The underlying SCTK window. + pub window: Window, + + /// The current window title. + title: String, + + /// Whether the frame is resizable. + resizable: bool, + /// The `Shm` to set cursor. pub shm: WlShm, @@ -86,12 +103,6 @@ pub struct WindowState { /// Theme varaint. theme: Option, - /// The current window title. - title: String, - - /// Whether the frame is resizable. - resizable: bool, - // NOTE: we can't use simple counter, since it's racy when seat getting destroyed and new // is created, since add/removed stuff could be delivered a bit out of order. /// Seats that has keyboard focus on that window. @@ -147,14 +158,6 @@ pub struct WindowState { fractional_scale: Option, blur: Option, blur_manager: Option, - - /// Whether the client side decorations have pending move operations. - /// - /// The value is the serial of the event triggered moved. - has_pending_move: Option, - - /// The underlying SCTK window. - pub window: Window, } impl WindowState { diff --git a/src/platform_impl/linux/wayland/window/state/subsurface.rs b/src/platform_impl/linux/wayland/window/state/subsurface.rs new file mode 100644 index 0000000000..04ce085d1f --- /dev/null +++ b/src/platform_impl/linux/wayland/window/state/subsurface.rs @@ -0,0 +1,7 @@ +use wayland_client::protocol::{wl_subsurface::WlSubsurface, wl_surface::WlSurface}; + +struct SubsurfaceState { + parent_surface: WlSurface, + surface: WlSurface, + subsurface: WlSubsurface +} \ No newline at end of file diff --git a/src/platform_impl/linux/wayland/window/state/toplevel.rs b/src/platform_impl/linux/wayland/window/state/toplevel.rs new file mode 100644 index 0000000000..555cd73b3b --- /dev/null +++ b/src/platform_impl/linux/wayland/window/state/toplevel.rs @@ -0,0 +1,5 @@ +use sctk::shell::xdg::window::Window; + +struct ToplevelState { + window: Window +} \ No newline at end of file From 8eb210e5b661e74db20438e5f8a9adf169ac99ee Mon Sep 17 00:00:00 2001 From: jgcodes2020 Date: Thu, 15 Feb 2024 14:51:05 -0500 Subject: [PATCH 02/13] the refactor builds now --- .../wayland/window/{state.rs => state/mod.rs} | 627 +++++++++++------- .../linux/wayland/window/state/subsurface.rs | 21 +- .../linux/wayland/window/state/toplevel.rs | 46 +- 3 files changed, 429 insertions(+), 265 deletions(-) rename src/platform_impl/linux/wayland/window/{state.rs => state/mod.rs} (66%) diff --git a/src/platform_impl/linux/wayland/window/state.rs b/src/platform_impl/linux/wayland/window/state/mod.rs similarity index 66% rename from src/platform_impl/linux/wayland/window/state.rs rename to src/platform_impl/linux/wayland/window/state/mod.rs index 1aa0503ab8..ca33c6e13b 100644 --- a/src/platform_impl/linux/wayland/window/state.rs +++ b/src/platform_impl/linux/wayland/window/state/mod.rs @@ -44,6 +44,9 @@ use crate::platform_impl::wayland::seat::{ }; use crate::platform_impl::wayland::state::{WindowCompositorUpdate, WinitState}; +use self::subsurface::SubsurfaceState; +use self::toplevel::ToplevelState; + mod subsurface; mod toplevel; @@ -55,27 +58,28 @@ pub type WinitFrame = sctk::shell::xdg::fallback_frame::FallbackFrame = LogicalSize::new(2, 1); +#[allow(unused)] // this is temporary +pub enum SurfaceRoleState { + Toplevel(ToplevelState), + Subsurface(SubsurfaceState), +} + +impl WaylandSurface for SurfaceRoleState { + fn wl_surface(&self) -> &wayland_client::protocol::wl_surface::WlSurface { + match self { + SurfaceRoleState::Toplevel(toplevel) => toplevel.wl_surface(), + SurfaceRoleState::Subsurface(subsurface) => subsurface.wl_surface(), + } + } +} + /// The state of the window which is being updated from the [`WinitState`]. pub struct WindowState { /// The connection to Wayland server. pub connection: Connection, - /// The window frame, which is created from the configure request. - frame: Option, - - /// Whether the client side decorations have pending move operations. - /// - /// The value is the serial of the event triggered moved. - has_pending_move: Option, - - /// The underlying SCTK window. - pub window: Window, - - /// The current window title. - title: String, - - /// Whether the frame is resizable. - resizable: bool, + /// State specific to a surface role. + surface_role: SurfaceRoleState, /// The `Shm` to set cursor. pub shm: WlShm, @@ -132,12 +136,6 @@ pub struct WindowState { /// The inner size of the window, as in without client side decorations. size: LogicalSize, - /// Whether the CSD fail to create, so we don't try to create them on each iteration. - csd_fails: bool, - - /// Whether we should decorate the frame. - decorate: bool, - /// Min size. min_inner_size: LogicalSize, max_inner_size: Option>, @@ -186,16 +184,21 @@ impl WindowState { blur_manager: winit_state.kwin_blur_manager.clone(), compositor, connection, - csd_fails: false, + surface_role: SurfaceRoleState::Toplevel(ToplevelState { + window, + frame: None, + has_pending_move: None, + title: String::default(), + resizable: true, + csd_fails: false, + decorate: true, + }), cursor_grab_mode: GrabState::new(), selected_cursor: Default::default(), cursor_visible: true, - decorate: true, fractional_scale, - frame: None, frame_callback_state: FrameCallbackState::None, seat_focus: Default::default(), - has_pending_move: None, ime_allowed: false, ime_purpose: ImePurpose::Normal, last_configure: None, @@ -204,7 +207,6 @@ impl WindowState { pointer_constraints, pointers: Default::default(), queue_handle: queue_handle.clone(), - resizable: true, scale_factor: 1., shm: winit_state.shm.wl_shm().clone(), custom_cursor_pool: winit_state.custom_cursor_pool.clone(), @@ -213,10 +215,8 @@ impl WindowState { initial_size: Some(initial_size), text_inputs: Vec::new(), theme, - title: String::default(), transparent: false, viewport, - window, } } @@ -251,7 +251,7 @@ impl WindowState { /// Request a frame callback if we don't have one for this window in flight. pub fn request_frame_callback(&mut self) { - let surface = self.window.wl_surface(); + let surface = self.surface_role.wl_surface(); match self.frame_callback_state { FrameCallbackState::None | FrameCallbackState::Received => { self.frame_callback_state = FrameCallbackState::Requested; @@ -275,60 +275,65 @@ impl WindowState { self.stateless_size = self.size; } - if let Some(subcompositor) = subcompositor.as_ref().filter(|_| { - configure.decoration_mode == DecorationMode::Client - && self.frame.is_none() - && !self.csd_fails - }) { - match WinitFrame::new( - &self.window, - shm, - #[cfg(feature = "sctk-adwaita")] - self.compositor.clone(), - subcompositor.clone(), - self.queue_handle.clone(), - #[cfg(feature = "sctk-adwaita")] - into_sctk_adwaita_config(self.theme), - ) { - Ok(mut frame) => { - frame.set_title(&self.title); - frame.set_scaling_factor(self.scale_factor); - // Hide the frame if we were asked to not decorate. - frame.set_hidden(!self.decorate); - self.frame = Some(frame); - } - Err(err) => { - warn!("Failed to create client side decorations frame: {err}"); - self.csd_fails = true; + let (mut new_size, constrain) = if let SurfaceRoleState::Toplevel(toplevel) = &mut self.surface_role { + if let Some(subcompositor) = subcompositor.as_ref().filter(|_| { + configure.decoration_mode == DecorationMode::Client + && toplevel.frame.is_none() + && !toplevel.csd_fails + }) { + match WinitFrame::new( + &toplevel.window, + shm, + #[cfg(feature = "sctk-adwaita")] + self.compositor.clone(), + subcompositor.clone(), + self.queue_handle.clone(), + #[cfg(feature = "sctk-adwaita")] + into_sctk_adwaita_config(self.theme), + ) { + Ok(mut frame) => { + frame.set_title(&toplevel.title); + frame.set_scaling_factor(self.scale_factor); + // Hide the frame if we were asked to not decorate. + frame.set_hidden(!toplevel.decorate); + toplevel.frame = Some(frame); + } + Err(err) => { + warn!("Failed to create client side decorations frame: {err}"); + toplevel.csd_fails = true; + } } + } else if configure.decoration_mode == DecorationMode::Server { + // Drop the frame for server side decorations to save resources. + toplevel.frame = None; } - } else if configure.decoration_mode == DecorationMode::Server { - // Drop the frame for server side decorations to save resources. - self.frame = None; - } - - let stateless = Self::is_stateless(&configure); - - let (mut new_size, constrain) = if let Some(frame) = self.frame.as_mut() { - // Configure the window states. - frame.update_state(configure.state); - - match configure.new_size { - (Some(width), Some(height)) => { - let (width, height) = frame.subtract_borders(width, height); - let width = width.map(|w| w.get()).unwrap_or(1); - let height = height.map(|h| h.get()).unwrap_or(1); - ((width, height).into(), false) + + let stateless = Self::is_stateless(&configure); + + let (new_size, constrain) = if let Some(frame) = toplevel.frame.as_mut() { + // Configure the window states. + frame.update_state(configure.state); + + match configure.new_size { + (Some(width), Some(height)) => { + let (width, height) = frame.subtract_borders(width, height); + let width = width.map(|w| w.get()).unwrap_or(1); + let height = height.map(|h| h.get()).unwrap_or(1); + ((width, height).into(), false) + } + (_, _) if stateless => (self.stateless_size, true), + _ => (self.size, true), } - (_, _) if stateless => (self.stateless_size, true), - _ => (self.size, true), - } + } else { + match configure.new_size { + (Some(width), Some(height)) => ((width.get(), height.get()).into(), false), + _ if stateless => (self.stateless_size, true), + _ => (self.size, true), + } + }; + (new_size, constrain) } else { - match configure.new_size { - (Some(width), Some(height)) => ((width.get(), height.get()).into(), false), - _ if stateless => (self.stateless_size, true), - _ => (self.size, true), - } + return false; }; // Apply configure bounds only when compositor let the user decide what size to pick. @@ -381,15 +386,19 @@ impl WindowState { None => (None, None), }; - if let Some(frame) = self.frame.as_ref() { - let (width, height) = frame.subtract_borders( - configure_bounds.0.unwrap_or(NonZeroU32::new(1).unwrap()), - configure_bounds.1.unwrap_or(NonZeroU32::new(1).unwrap()), - ); - ( - configure_bounds.0.and(width), - configure_bounds.1.and(height), - ) + if let SurfaceRoleState::Toplevel(toplevel) = &self.surface_role { + if let Some(frame) = toplevel.frame.as_ref() { + let (width, height) = frame.subtract_borders( + configure_bounds.0.unwrap_or(NonZeroU32::new(1).unwrap()), + configure_bounds.1.unwrap_or(NonZeroU32::new(1).unwrap()), + ); + ( + configure_bounds.0.and(width), + configure_bounds.1.and(height), + ) + } else { + configure_bounds + } } else { configure_bounds } @@ -402,27 +411,35 @@ impl WindowState { /// Start interacting drag resize. pub fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), ExternalError> { - let xdg_toplevel = self.window.xdg_toplevel(); - - // TODO(kchibisov) handle touch serials. - self.apply_on_poiner(|_, data| { - let serial = data.latest_button_serial(); - let seat = data.seat(); - xdg_toplevel.resize(seat, serial, direction.into()); - }); + if let SurfaceRoleState::Toplevel(toplevel) = &self.surface_role { + let xdg_toplevel = toplevel.window.xdg_toplevel(); + + // TODO(kchibisov) handle touch serials. + self.apply_on_poiner(|_, data| { + let serial = data.latest_button_serial(); + let seat = data.seat(); + xdg_toplevel.resize(seat, serial, direction.into()); + }); + } else { + warn!("System move handles can only be triggered on toplevels"); + } Ok(()) } /// Start the window drag. pub fn drag_window(&self) -> Result<(), ExternalError> { - let xdg_toplevel = self.window.xdg_toplevel(); - // TODO(kchibisov) handle touch serials. - self.apply_on_poiner(|_, data| { - let serial = data.latest_button_serial(); - let seat = data.seat(); - xdg_toplevel._move(seat, serial); - }); + if let SurfaceRoleState::Toplevel(toplevel) = &self.surface_role { + let xdg_toplevel = toplevel.window.xdg_toplevel(); + // TODO(kchibisov) handle touch serials. + self.apply_on_poiner(|_, data| { + let serial = data.latest_button_serial(); + let seat = data.seat(); + xdg_toplevel._move(seat, serial); + }); + } else { + warn!("System move handles can only be triggered on toplevels"); + } Ok(()) } @@ -439,37 +456,47 @@ impl WindowState { window_id: WindowId, updates: &mut Vec, ) -> Option { - match self.frame.as_mut()?.on_click(timestamp, click, pressed)? { - FrameAction::Minimize => self.window.set_minimized(), - FrameAction::Maximize => self.window.set_maximized(), - FrameAction::UnMaximize => self.window.unset_maximized(), - FrameAction::Close => WinitState::queue_close(updates, window_id), - FrameAction::Move => self.has_pending_move = Some(serial), - FrameAction::Resize(edge) => { - let edge = match edge { - ResizeEdge::None => XdgResizeEdge::None, - ResizeEdge::Top => XdgResizeEdge::Top, - ResizeEdge::Bottom => XdgResizeEdge::Bottom, - ResizeEdge::Left => XdgResizeEdge::Left, - ResizeEdge::TopLeft => XdgResizeEdge::TopLeft, - ResizeEdge::BottomLeft => XdgResizeEdge::BottomLeft, - ResizeEdge::Right => XdgResizeEdge::Right, - ResizeEdge::TopRight => XdgResizeEdge::TopRight, - ResizeEdge::BottomRight => XdgResizeEdge::BottomRight, - _ => return None, - }; - self.window.resize(seat, serial, edge); - } - FrameAction::ShowMenu(x, y) => self.window.show_window_menu(seat, serial, (x, y)), - _ => (), - }; + if let SurfaceRoleState::Toplevel(toplevel) = &mut self.surface_role { + match toplevel + .frame + .as_mut()? + .on_click(timestamp, click, pressed)? + { + FrameAction::Minimize => toplevel.window.set_minimized(), + FrameAction::Maximize => toplevel.window.set_maximized(), + FrameAction::UnMaximize => toplevel.window.unset_maximized(), + FrameAction::Close => WinitState::queue_close(updates, window_id), + FrameAction::Move => toplevel.has_pending_move = Some(serial), + FrameAction::Resize(edge) => { + let edge = match edge { + ResizeEdge::None => XdgResizeEdge::None, + ResizeEdge::Top => XdgResizeEdge::Top, + ResizeEdge::Bottom => XdgResizeEdge::Bottom, + ResizeEdge::Left => XdgResizeEdge::Left, + ResizeEdge::TopLeft => XdgResizeEdge::TopLeft, + ResizeEdge::BottomLeft => XdgResizeEdge::BottomLeft, + ResizeEdge::Right => XdgResizeEdge::Right, + ResizeEdge::TopRight => XdgResizeEdge::TopRight, + ResizeEdge::BottomRight => XdgResizeEdge::BottomRight, + _ => return None, + }; + toplevel.window.resize(seat, serial, edge); + } + FrameAction::ShowMenu(x, y) => { + toplevel.window.show_window_menu(seat, serial, (x, y)) + } + _ => (), + }; + } Some(false) } pub fn frame_point_left(&mut self) { - if let Some(frame) = self.frame.as_mut() { - frame.click_point_left(); + if let SurfaceRoleState::Toplevel(toplevel) = &mut self.surface_role { + if let Some(frame) = toplevel.frame.as_mut() { + frame.click_point_left(); + } } } @@ -482,18 +509,22 @@ impl WindowState { x: f64, y: f64, ) -> Option { - // Take the serial if we had any, so it doesn't stick around. - let serial = self.has_pending_move.take(); - - if let Some(frame) = self.frame.as_mut() { - let cursor = frame.click_point_moved(timestamp, &surface.id(), x, y); - // If we have a cursor change, that means that cursor is over the decorations, - // so try to apply move. - if let Some(serial) = cursor.is_some().then_some(serial).flatten() { - self.window.move_(seat, serial); - None + if let SurfaceRoleState::Toplevel(toplevel) = &mut self.surface_role { + // Take the serial if we had any, so it doesn't stick around. + let serial = toplevel.has_pending_move.take(); + + if let Some(frame) = toplevel.frame.as_mut() { + let cursor = frame.click_point_moved(timestamp, &surface.id(), x, y); + // If we have a cursor change, that means that cursor is over the decorations, + // so try to apply move. + if let Some(serial) = cursor.is_some().then_some(serial).flatten() { + toplevel.window.move_(seat, serial); + None + } else { + cursor + } } else { - cursor + None } } else { None @@ -503,7 +534,11 @@ impl WindowState { /// Get the stored resizable state. #[inline] pub fn resizable(&self) -> bool { - self.resizable + if let SurfaceRoleState::Toplevel(toplevel) = &self.surface_role { + toplevel.resizable + } else { + false + } } /// Set the resizable state on the window. @@ -511,25 +546,61 @@ impl WindowState { /// Returns `true` when the state was applied. #[inline] pub fn set_resizable(&mut self, resizable: bool) -> bool { - if self.resizable == resizable { - return false; + { + let toplevel: &mut ToplevelState; + if let SurfaceRoleState::Toplevel(self_toplevel) = &mut self.surface_role { + toplevel = self_toplevel; + } else { + return false; + } + + if toplevel.resizable == resizable { + return false; + } } - self.resizable = resizable; if resizable { - // Restore min/max sizes of the window. self.reload_min_max_hints(); } else { self.set_min_inner_size(Some(self.size)); self.set_max_inner_size(Some(self.size)); } - // Reload the state on the frame as well. - if let Some(frame) = self.frame.as_mut() { - frame.set_resizable(resizable); + { + if let SurfaceRoleState::Toplevel(toplevel) = &mut self.surface_role { + if let Some(frame) = toplevel.frame.as_mut() { + frame.set_resizable(resizable); + } + } else { + panic!("This shouldn't happen!"); + } } true + + // if let SurfaceRoleState::Toplevel(toplevel) = &mut self.surface_role { + // if toplevel.resizable == resizable { + // return false; + // } + + // toplevel.resizable = resizable; + // if resizable { + // // Restore min/max sizes of the window. + // self.reload_min_max_hints(); + // } else { + // self.set_min_inner_size(Some(self.size)); + // self.set_max_inner_size(Some(self.size)); + // } + + // // Reload the state on the frame as well. + // if let Some(frame) = toplevel.frame.as_mut() { + // frame.set_resizable(resizable); + // } + + // true + // } else { + // false + // } } /// Whether the window is focused by any seat. @@ -558,26 +629,35 @@ impl WindowState { #[inline] pub fn is_decorated(&mut self) -> bool { - let csd = self - .last_configure - .as_ref() - .map(|configure| configure.decoration_mode == DecorationMode::Client) - .unwrap_or(false); - if let Some(frame) = csd.then_some(self.frame.as_ref()).flatten() { - !frame.is_hidden() + if let SurfaceRoleState::Toplevel(toplevel) = &mut self.surface_role { + let csd = self + .last_configure + .as_ref() + .map(|configure| configure.decoration_mode == DecorationMode::Client) + .unwrap_or(false); + if let Some(frame) = csd.then_some(toplevel.frame.as_ref()).flatten() { + !frame.is_hidden() + } else { + // Server side decorations. + true + } } else { - // Server side decorations. - true + false } } /// Get the outer size of the window. #[inline] pub fn outer_size(&self) -> LogicalSize { - self.frame - .as_ref() - .map(|frame| frame.add_borders(self.size.width, self.size.height).into()) - .unwrap_or(self.size) + if let SurfaceRoleState::Toplevel(toplevel) = &self.surface_role { + toplevel + .frame + .as_ref() + .map(|frame| frame.add_borders(self.size.width, self.size.height).into()) + .unwrap_or(self.size) + } else { + self.size + } } /// Register pointer on the top-level. @@ -605,9 +685,11 @@ impl WindowState { /// Refresh the decorations frame if it's present returning whether the client should redraw. pub fn refresh_frame(&mut self) -> bool { - if let Some(frame) = self.frame.as_mut() { - if !frame.is_hidden() && frame.is_dirty() { - return frame.draw(); + if let SurfaceRoleState::Toplevel(toplevel) = &mut self.surface_role { + if let Some(frame) = toplevel.frame.as_mut() { + if !frame.is_hidden() && frame.is_dirty() { + return frame.draw(); + } } } @@ -628,7 +710,7 @@ impl WindowState { /// Reissue the transparency hint to the compositor. pub fn reload_transparency_hint(&self) { - let surface = self.window.wl_surface(); + let surface = self.surface_role.wl_surface(); if self.transparent { surface.set_opaque_region(None); @@ -664,33 +746,40 @@ impl WindowState { } // Update the inner frame. - let ((x, y), outer_size) = if let Some(frame) = self.frame.as_mut() { - // Resize only visible frame. - if !frame.is_hidden() { - frame.resize( - NonZeroU32::new(self.size.width).unwrap(), - NonZeroU32::new(self.size.height).unwrap(), - ); - } - - ( - frame.location(), - frame.add_borders(self.size.width, self.size.height).into(), - ) - } else { - ((0, 0), self.size) - }; + let ((x, y), outer_size) = + if let SurfaceRoleState::Toplevel(toplevel) = &mut self.surface_role { + if let Some(frame) = toplevel.frame.as_mut() { + // Resize only visible frame. + if !frame.is_hidden() { + frame.resize( + NonZeroU32::new(self.size.width).unwrap(), + NonZeroU32::new(self.size.height).unwrap(), + ); + } + + ( + frame.location(), + frame.add_borders(self.size.width, self.size.height).into(), + ) + } else { + ((0, 0), self.size) + } + } else { + ((0, 0), self.size) + }; // Reload the hint. self.reload_transparency_hint(); // Set the window geometry. - self.window.xdg_surface().set_window_geometry( - x, - y, - outer_size.width as i32, - outer_size.height as i32, - ); + if let SurfaceRoleState::Toplevel(toplevel) = &mut self.surface_role { + toplevel.window.xdg_surface().set_window_geometry( + x, + y, + outer_size.width as i32, + outer_size.height as i32, + ); + } // Update the target viewport, this is used if and only if fractional scaling is in use. if let Some(viewport) = self.viewport.as_ref() { @@ -784,40 +873,44 @@ impl WindowState { /// Set maximum inner window size. pub fn set_min_inner_size(&mut self, size: Option>) { // Ensure that the window has the right minimum size. - let mut size = size.unwrap_or(MIN_WINDOW_SIZE); - size.width = size.width.max(MIN_WINDOW_SIZE.width); - size.height = size.height.max(MIN_WINDOW_SIZE.height); - - // Add the borders. - let size = self - .frame - .as_ref() - .map(|frame| frame.add_borders(size.width, size.height).into()) - .unwrap_or(size); + if let SurfaceRoleState::Toplevel(toplevel) = &mut self.surface_role { + let mut size = size.unwrap_or(MIN_WINDOW_SIZE); + size.width = size.width.max(MIN_WINDOW_SIZE.width); + size.height = size.height.max(MIN_WINDOW_SIZE.height); + + // Add the borders. + let size = toplevel + .frame + .as_ref() + .map(|frame| frame.add_borders(size.width, size.height).into()) + .unwrap_or(size); - self.min_inner_size = size; - self.window.set_min_size(Some(size.into())); + self.min_inner_size = size; + toplevel.window.set_min_size(Some(size.into())); + } } /// Set maximum inner window size. pub fn set_max_inner_size(&mut self, size: Option>) { - let size = size.map(|size| { - self.frame - .as_ref() - .map(|frame| frame.add_borders(size.width, size.height).into()) - .unwrap_or(size) - }); - - self.max_inner_size = size; - self.window.set_max_size(size.map(Into::into)); + if let SurfaceRoleState::Toplevel(toplevel) = &mut self.surface_role { + let size = size.map(|size| { + toplevel + .frame + .as_ref() + .map(|frame| frame.add_borders(size.width, size.height).into()) + .unwrap_or(size) + }); + + self.max_inner_size = size; + toplevel.window.set_max_size(size.map(Into::into)); + } } /// Set the CSD theme. pub fn set_theme(&mut self, theme: Option) { self.theme = theme; - #[cfg(feature = "sctk-adwaita")] - if let Some(frame) = self.frame.as_mut() { - frame.set_config(into_sctk_adwaita_config(theme)) + if let SurfaceRoleState::Toplevel(toplevel) = &mut self.surface_role { + toplevel.set_theme(theme); } } @@ -861,7 +954,7 @@ impl WindowState { } } - let surface = self.window.wl_surface(); + let surface = self.surface_role.wl_surface(); match mode { CursorGrabMode::Locked => self.apply_on_poiner(|pointer, data| { let pointer = pointer.pointer(); @@ -881,11 +974,15 @@ impl WindowState { pub fn show_window_menu(&self, position: LogicalPosition) { // TODO(kchibisov) handle touch serials. - self.apply_on_poiner(|_, data| { - let serial = data.latest_button_serial(); - let seat = data.seat(); - self.window.show_window_menu(seat, serial, position.into()); - }); + if let SurfaceRoleState::Toplevel(toplevel) = &self.surface_role { + self.apply_on_poiner(|_, data| { + let serial = data.latest_button_serial(); + let seat = data.seat(); + toplevel + .window + .show_window_menu(seat, serial, position.into()); + }); + } } /// Set the position of the cursor. @@ -933,32 +1030,35 @@ impl WindowState { /// Whether show or hide client side decorations. #[inline] pub fn set_decorate(&mut self, decorate: bool) { - if decorate == self.decorate { - return; - } + if let SurfaceRoleState::Toplevel(toplevel) = &mut self.surface_role { + if decorate == toplevel.decorate { + return; + } - self.decorate = decorate; + toplevel.decorate = decorate; - match self - .last_configure - .as_ref() - .map(|configure| configure.decoration_mode) - { - Some(DecorationMode::Server) if !self.decorate => { - // To disable decorations we should request client and hide the frame. - self.window - .request_decoration_mode(Some(DecorationMode::Client)) + match self + .last_configure + .as_ref() + .map(|configure| configure.decoration_mode) + { + Some(DecorationMode::Server) if !toplevel.decorate => { + // To disable decorations we should request client and hide the frame. + toplevel + .window + .request_decoration_mode(Some(DecorationMode::Client)) + } + _ if toplevel.decorate => toplevel + .window + .request_decoration_mode(Some(DecorationMode::Server)), + _ => (), } - _ if self.decorate => self - .window - .request_decoration_mode(Some(DecorationMode::Server)), - _ => (), - } - if let Some(frame) = self.frame.as_mut() { - frame.set_hidden(!decorate); - // Force the resize. - self.resize(self.size); + if let Some(frame) = toplevel.frame.as_mut() { + frame.set_hidden(!decorate); + // Force the resize. + self.resize(self.size); + } } } @@ -1028,11 +1128,16 @@ impl WindowState { // NOTE: When fractional scaling is not used update the buffer scale. if self.fractional_scale.is_none() { - let _ = self.window.set_buffer_scale(self.scale_factor as _); + let _ = self + .surface_role + .wl_surface() + .set_buffer_scale(self.scale_factor as _); } - if let Some(frame) = self.frame.as_mut() { - frame.set_scaling_factor(scale_factor); + if let SurfaceRoleState::Toplevel(toplevel) = &mut self.surface_role { + if let Some(frame) = toplevel.frame.as_mut() { + frame.set_scaling_factor(scale_factor); + } } } @@ -1041,7 +1146,7 @@ impl WindowState { pub fn set_blur(&mut self, blurred: bool) { if blurred && self.blur.is_none() { if let Some(blur_manager) = self.blur_manager.as_ref() { - let blur = blur_manager.blur(self.window.wl_surface(), &self.queue_handle); + let blur = blur_manager.blur(self.surface_role.wl_surface(), &self.queue_handle); blur.commit(); self.blur = Some(blur); } else { @@ -1051,7 +1156,7 @@ impl WindowState { self.blur_manager .as_ref() .unwrap() - .unset(self.window.wl_surface()); + .unset(self.surface_role.wl_surface()); self.blur.take().unwrap().release(); } } @@ -1062,21 +1167,23 @@ impl WindowState { pub fn set_title(&mut self, mut title: String) { // Truncate the title to at most 1024 bytes, so that it does not blow up the protocol // messages - if title.len() > 1024 { - let mut new_len = 1024; - while !title.is_char_boundary(new_len) { - new_len -= 1; + if let SurfaceRoleState::Toplevel(toplevel) = &mut self.surface_role { + if title.len() > 1024 { + let mut new_len = 1024; + while !title.is_char_boundary(new_len) { + new_len -= 1; + } + title.truncate(new_len); } - title.truncate(new_len); - } - // Update the CSD title. - if let Some(frame) = self.frame.as_mut() { - frame.set_title(&title); - } + // Update the CSD title. + if let Some(frame) = toplevel.frame.as_mut() { + frame.set_title(&title); + } - self.window.set_title(&title); - self.title = title; + toplevel.window.set_title(&title); + toplevel.title = title; + } } /// Mark the window as transparent. @@ -1105,7 +1212,11 @@ impl WindowState { /// Get the cached title. #[inline] pub fn title(&self) -> &str { - &self.title + if let SurfaceRoleState::Toplevel(toplevel) = &self.surface_role { + &toplevel.title + } else { + "" + } } } diff --git a/src/platform_impl/linux/wayland/window/state/subsurface.rs b/src/platform_impl/linux/wayland/window/state/subsurface.rs index 04ce085d1f..83c9ccf95f 100644 --- a/src/platform_impl/linux/wayland/window/state/subsurface.rs +++ b/src/platform_impl/linux/wayland/window/state/subsurface.rs @@ -1,7 +1,20 @@ +use sctk::shell::WaylandSurface; use wayland_client::protocol::{wl_subsurface::WlSubsurface, wl_surface::WlSurface}; -struct SubsurfaceState { - parent_surface: WlSurface, - surface: WlSurface, - subsurface: WlSubsurface +#[allow(unused)] +pub(in crate::platform_impl::platform::wayland) struct SubsurfaceState { + /// The parent surface for this subsurface. + pub parent_surface: WlSurface, + + /// The surface. + pub surface: WlSurface, + + /// The subsurface role. Allows control over position. + pub subsurface: WlSubsurface +} + +impl WaylandSurface for SubsurfaceState { + fn wl_surface(&self) -> &wayland_client::protocol::wl_surface::WlSurface { + return &self.surface; + } } \ No newline at end of file diff --git a/src/platform_impl/linux/wayland/window/state/toplevel.rs b/src/platform_impl/linux/wayland/window/state/toplevel.rs index 555cd73b3b..63994e1f6f 100644 --- a/src/platform_impl/linux/wayland/window/state/toplevel.rs +++ b/src/platform_impl/linux/wayland/window/state/toplevel.rs @@ -1,5 +1,45 @@ -use sctk::shell::xdg::window::Window; +use sctk::shell::{xdg::window::Window, WaylandSurface}; -struct ToplevelState { - window: Window +use crate::platform::wayland::Theme; + +use super::{into_sctk_adwaita_config, WinitFrame}; + +pub(in crate::platform_impl::platform::wayland) struct ToplevelState { + /// The underlying SCTK window. + pub window: Window, + + /// The window frame, which is created from the configure request. + pub frame: Option, + + /// Whether the client side decorations have pending move operations. + /// + /// The value is the serial of the event triggered moved. + pub has_pending_move: Option, + + /// The current window title. + pub title: String, + + /// Whether the frame is resizable. + pub resizable: bool, + + /// Whether the CSD fail to create, so we don't try to create them on each iteration. + pub csd_fails: bool, + + /// Whether we should decorate the frame. + pub decorate: bool, +} + +impl ToplevelState { + pub fn set_theme(&mut self, theme: Option) { + #[cfg(feature = "sctk-adwaita")] + if let Some(frame) = self.frame.as_mut() { + frame.set_config(into_sctk_adwaita_config(theme)) + } + } +} + +impl WaylandSurface for ToplevelState { + fn wl_surface(&self) -> &wayland_client::protocol::wl_surface::WlSurface { + self.window.wl_surface() + } } \ No newline at end of file From a8bb62a47c2f6e204461c7efb5ea547920d74ef2 Mon Sep 17 00:00:00 2001 From: jgcodes2020 Date: Fri, 16 Feb 2024 11:54:33 -0500 Subject: [PATCH 03/13] fix CI errors, improve configure --- .../linux/wayland/window/state/mod.rs | 56 +++++++++---------- .../linux/wayland/window/state/subsurface.rs | 2 +- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/platform_impl/linux/wayland/window/state/mod.rs b/src/platform_impl/linux/wayland/window/state/mod.rs index ca33c6e13b..6efeaa6214 100644 --- a/src/platform_impl/linux/wayland/window/state/mod.rs +++ b/src/platform_impl/linux/wayland/window/state/mod.rs @@ -275,7 +275,7 @@ impl WindowState { self.stateless_size = self.size; } - let (mut new_size, constrain) = if let SurfaceRoleState::Toplevel(toplevel) = &mut self.surface_role { + if let SurfaceRoleState::Toplevel(toplevel) = &mut self.surface_role { if let Some(subcompositor) = subcompositor.as_ref().filter(|_| { configure.decoration_mode == DecorationMode::Client && toplevel.frame.is_none() @@ -307,33 +307,34 @@ impl WindowState { // Drop the frame for server side decorations to save resources. toplevel.frame = None; } - - let stateless = Self::is_stateless(&configure); - - let (new_size, constrain) = if let Some(frame) = toplevel.frame.as_mut() { - // Configure the window states. - frame.update_state(configure.state); - - match configure.new_size { - (Some(width), Some(height)) => { - let (width, height) = frame.subtract_borders(width, height); - let width = width.map(|w| w.get()).unwrap_or(1); - let height = height.map(|h| h.get()).unwrap_or(1); - ((width, height).into(), false) - } - (_, _) if stateless => (self.stateless_size, true), - _ => (self.size, true), - } - } else { - match configure.new_size { - (Some(width), Some(height)) => ((width.get(), height.get()).into(), false), - _ if stateless => (self.stateless_size, true), - _ => (self.size, true), + } + + let stateless = Self::is_stateless(&configure); + + let (mut new_size, constrain) = if let SurfaceRoleState::Toplevel(ToplevelState { + frame: Some(frame), + .. + }) = &mut self.surface_role + { + // Configure the window states. + frame.update_state(configure.state); + + match configure.new_size { + (Some(width), Some(height)) => { + let (width, height) = frame.subtract_borders(width, height); + let width = width.map(|w| w.get()).unwrap_or(1); + let height = height.map(|h| h.get()).unwrap_or(1); + ((width, height).into(), false) } - }; - (new_size, constrain) + (_, _) if stateless => (self.stateless_size, true), + _ => (self.size, true), + } } else { - return false; + match configure.new_size { + (Some(width), Some(height)) => ((width.get(), height.get()).into(), false), + _ if stateless => (self.stateless_size, true), + _ => (self.size, true), + } }; // Apply configure bounds only when compositor let the user decide what size to pick. @@ -1128,8 +1129,7 @@ impl WindowState { // NOTE: When fractional scaling is not used update the buffer scale. if self.fractional_scale.is_none() { - let _ = self - .surface_role + self.surface_role .wl_surface() .set_buffer_scale(self.scale_factor as _); } diff --git a/src/platform_impl/linux/wayland/window/state/subsurface.rs b/src/platform_impl/linux/wayland/window/state/subsurface.rs index 83c9ccf95f..3502c62e65 100644 --- a/src/platform_impl/linux/wayland/window/state/subsurface.rs +++ b/src/platform_impl/linux/wayland/window/state/subsurface.rs @@ -15,6 +15,6 @@ pub(in crate::platform_impl::platform::wayland) struct SubsurfaceState { impl WaylandSurface for SubsurfaceState { fn wl_surface(&self) -> &wayland_client::protocol::wl_surface::WlSurface { - return &self.surface; + &self.surface } } \ No newline at end of file From 9213f6374fb8053432e318ee58f363a1b78bd24a Mon Sep 17 00:00:00 2001 From: jgcodes2020 Date: Fri, 16 Feb 2024 14:19:57 -0500 Subject: [PATCH 04/13] realize that separate structs won't work --- src/platform_impl/linux/wayland/window/mod.rs | 12 +- .../wayland/window/{state/mod.rs => state.rs} | 300 ++++++++++-------- .../linux/wayland/window/state/subsurface.rs | 20 -- .../linux/wayland/window/state/toplevel.rs | 45 --- 4 files changed, 176 insertions(+), 201 deletions(-) rename src/platform_impl/linux/wayland/window/{state/mod.rs => state.rs} (85%) delete mode 100644 src/platform_impl/linux/wayland/window/state/subsurface.rs delete mode 100644 src/platform_impl/linux/wayland/window/state/toplevel.rs diff --git a/src/platform_impl/linux/wayland/window/mod.rs b/src/platform_impl/linux/wayland/window/mod.rs index c6578b6fb3..7c3798ac6c 100644 --- a/src/platform_impl/linux/wayland/window/mod.rs +++ b/src/platform_impl/linux/wayland/window/mod.rs @@ -44,6 +44,12 @@ pub struct Window { /// Reference to the underlying SCTK window. window: SctkWindow, + /// Xdg activation to request user attention. + xdg_activation: Option, + + /// The state of the requested attention from the `xdg_activation`. + attention_requested: Arc, + /// Window id. window_id: WindowId, @@ -57,12 +63,6 @@ pub struct Window { #[allow(dead_code)] display: WlDisplay, - /// Xdg activation to request user attention. - xdg_activation: Option, - - /// The state of the requested attention from the `xdg_activation`. - attention_requested: Arc, - /// Handle to the main queue to perform requests. queue_handle: QueueHandle, diff --git a/src/platform_impl/linux/wayland/window/state/mod.rs b/src/platform_impl/linux/wayland/window/state.rs similarity index 85% rename from src/platform_impl/linux/wayland/window/state/mod.rs rename to src/platform_impl/linux/wayland/window/state.rs index 6efeaa6214..d30b5ce539 100644 --- a/src/platform_impl/linux/wayland/window/state/mod.rs +++ b/src/platform_impl/linux/wayland/window/state.rs @@ -60,14 +60,37 @@ const MIN_WINDOW_SIZE: LogicalSize = LogicalSize::new(2, 1); #[allow(unused)] // this is temporary pub enum SurfaceRoleState { - Toplevel(ToplevelState), + Toplevel { + /// The underlying SCTK window. + window: Window, + + /// The window frame, which is created from the configure request. + frame: Option, + + /// Whether the client side decorations have pending move operations. + /// + /// The value is the serial of the event triggered moved. + has_pending_move: Option, + + /// The current window title. + title: String, + + /// Whether the frame is resizable. + resizable: bool, + + /// Whether the CSD fail to create, so we don't try to create them on each iteration. + csd_fails: bool, + + /// Whether we should decorate the frame. + decorate: bool, + }, Subsurface(SubsurfaceState), } impl WaylandSurface for SurfaceRoleState { fn wl_surface(&self) -> &wayland_client::protocol::wl_surface::WlSurface { match self { - SurfaceRoleState::Toplevel(toplevel) => toplevel.wl_surface(), + SurfaceRoleState::Toplevel { window: window, .. } => window.wl_surface(), SurfaceRoleState::Subsurface(subsurface) => subsurface.wl_surface(), } } @@ -184,7 +207,7 @@ impl WindowState { blur_manager: winit_state.kwin_blur_manager.clone(), compositor, connection, - surface_role: SurfaceRoleState::Toplevel(ToplevelState { + surface_role: SurfaceRoleState::Toplevel { window, frame: None, has_pending_move: None, @@ -192,7 +215,7 @@ impl WindowState { resizable: true, csd_fails: false, decorate: true, - }), + }, cursor_grab_mode: GrabState::new(), selected_cursor: Default::default(), cursor_visible: true, @@ -275,14 +298,22 @@ impl WindowState { self.stateless_size = self.size; } - if let SurfaceRoleState::Toplevel(toplevel) = &mut self.surface_role { + if let SurfaceRoleState::Toplevel { + frame, + csd_fails, + window, + title, + decorate, + .. + } = &mut self.surface_role + { if let Some(subcompositor) = subcompositor.as_ref().filter(|_| { configure.decoration_mode == DecorationMode::Client - && toplevel.frame.is_none() - && !toplevel.csd_fails + && frame.is_none() + && !*csd_fails }) { match WinitFrame::new( - &toplevel.window, + window, shm, #[cfg(feature = "sctk-adwaita")] self.compositor.clone(), @@ -291,30 +322,30 @@ impl WindowState { #[cfg(feature = "sctk-adwaita")] into_sctk_adwaita_config(self.theme), ) { - Ok(mut frame) => { - frame.set_title(&toplevel.title); - frame.set_scaling_factor(self.scale_factor); + Ok(mut new_frame) => { + new_frame.set_title(title.clone()); + new_frame.set_scaling_factor(self.scale_factor); // Hide the frame if we were asked to not decorate. - frame.set_hidden(!toplevel.decorate); - toplevel.frame = Some(frame); + new_frame.set_hidden(!*decorate); + *frame = Some(new_frame); } Err(err) => { warn!("Failed to create client side decorations frame: {err}"); - toplevel.csd_fails = true; + *csd_fails = true; } } } else if configure.decoration_mode == DecorationMode::Server { // Drop the frame for server side decorations to save resources. - toplevel.frame = None; + *frame = None; } } let stateless = Self::is_stateless(&configure); - let (mut new_size, constrain) = if let SurfaceRoleState::Toplevel(ToplevelState { + let (mut new_size, constrain) = if let SurfaceRoleState::Toplevel { frame: Some(frame), .. - }) = &mut self.surface_role + } = &mut self.surface_role { // Configure the window states. frame.update_state(configure.state); @@ -387,8 +418,8 @@ impl WindowState { None => (None, None), }; - if let SurfaceRoleState::Toplevel(toplevel) = &self.surface_role { - if let Some(frame) = toplevel.frame.as_ref() { + if let SurfaceRoleState::Toplevel { frame, .. } = &self.surface_role { + if let Some(frame) = frame.as_ref() { let (width, height) = frame.subtract_borders( configure_bounds.0.unwrap_or(NonZeroU32::new(1).unwrap()), configure_bounds.1.unwrap_or(NonZeroU32::new(1).unwrap()), @@ -412,8 +443,8 @@ impl WindowState { /// Start interacting drag resize. pub fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), ExternalError> { - if let SurfaceRoleState::Toplevel(toplevel) = &self.surface_role { - let xdg_toplevel = toplevel.window.xdg_toplevel(); + if let SurfaceRoleState::Toplevel { window, .. } = &self.surface_role { + let xdg_toplevel = window.xdg_toplevel(); // TODO(kchibisov) handle touch serials. self.apply_on_poiner(|_, data| { @@ -430,8 +461,8 @@ impl WindowState { /// Start the window drag. pub fn drag_window(&self) -> Result<(), ExternalError> { - if let SurfaceRoleState::Toplevel(toplevel) = &self.surface_role { - let xdg_toplevel = toplevel.window.xdg_toplevel(); + if let SurfaceRoleState::Toplevel { window, .. } = &self.surface_role { + let xdg_toplevel = window.xdg_toplevel(); // TODO(kchibisov) handle touch serials. self.apply_on_poiner(|_, data| { let serial = data.latest_button_serial(); @@ -457,17 +488,19 @@ impl WindowState { window_id: WindowId, updates: &mut Vec, ) -> Option { - if let SurfaceRoleState::Toplevel(toplevel) = &mut self.surface_role { - match toplevel - .frame - .as_mut()? - .on_click(timestamp, click, pressed)? - { - FrameAction::Minimize => toplevel.window.set_minimized(), - FrameAction::Maximize => toplevel.window.set_maximized(), - FrameAction::UnMaximize => toplevel.window.unset_maximized(), + if let SurfaceRoleState::Toplevel { + window, + has_pending_move, + frame, + .. + } = &mut self.surface_role + { + match frame.as_mut()?.on_click(timestamp, click, pressed)? { + FrameAction::Minimize => window.set_minimized(), + FrameAction::Maximize => window.set_maximized(), + FrameAction::UnMaximize => window.unset_maximized(), FrameAction::Close => WinitState::queue_close(updates, window_id), - FrameAction::Move => toplevel.has_pending_move = Some(serial), + FrameAction::Move => *has_pending_move = Some(serial), FrameAction::Resize(edge) => { let edge = match edge { ResizeEdge::None => XdgResizeEdge::None, @@ -481,11 +514,9 @@ impl WindowState { ResizeEdge::BottomRight => XdgResizeEdge::BottomRight, _ => return None, }; - toplevel.window.resize(seat, serial, edge); - } - FrameAction::ShowMenu(x, y) => { - toplevel.window.show_window_menu(seat, serial, (x, y)) + window.resize(seat, serial, edge); } + FrameAction::ShowMenu(x, y) => window.show_window_menu(seat, serial, (x, y)), _ => (), }; } @@ -494,10 +525,11 @@ impl WindowState { } pub fn frame_point_left(&mut self) { - if let SurfaceRoleState::Toplevel(toplevel) = &mut self.surface_role { - if let Some(frame) = toplevel.frame.as_mut() { - frame.click_point_left(); - } + if let SurfaceRoleState::Toplevel { + frame: Some(frame), .. + } = &mut self.surface_role + { + frame.click_point_left(); } } @@ -510,16 +542,22 @@ impl WindowState { x: f64, y: f64, ) -> Option { - if let SurfaceRoleState::Toplevel(toplevel) = &mut self.surface_role { + if let SurfaceRoleState::Toplevel { + frame, + window, + has_pending_move, + .. + } = &mut self.surface_role + { // Take the serial if we had any, so it doesn't stick around. - let serial = toplevel.has_pending_move.take(); + let serial = has_pending_move.take(); - if let Some(frame) = toplevel.frame.as_mut() { + if let Some(frame) = frame.as_mut() { let cursor = frame.click_point_moved(timestamp, &surface.id(), x, y); // If we have a cursor change, that means that cursor is over the decorations, // so try to apply move. if let Some(serial) = cursor.is_some().then_some(serial).flatten() { - toplevel.window.move_(seat, serial); + window.move_(seat, serial); None } else { cursor @@ -535,8 +573,8 @@ impl WindowState { /// Get the stored resizable state. #[inline] pub fn resizable(&self) -> bool { - if let SurfaceRoleState::Toplevel(toplevel) = &self.surface_role { - toplevel.resizable + if let SurfaceRoleState::Toplevel { resizable, .. } = &self.surface_role { + *resizable } else { false } @@ -547,17 +585,14 @@ impl WindowState { /// Returns `true` when the state was applied. #[inline] pub fn set_resizable(&mut self, resizable: bool) -> bool { + if let SurfaceRoleState::Toplevel { + resizable: self_resizable, + .. + } = &mut self.surface_role { - let toplevel: &mut ToplevelState; - if let SurfaceRoleState::Toplevel(self_toplevel) = &mut self.surface_role { - toplevel = self_toplevel; - } else { - return false; - } - - if toplevel.resizable == resizable { - return false; - } + *self_resizable = resizable + } else { + return false; } if resizable { @@ -568,12 +603,12 @@ impl WindowState { } { - if let SurfaceRoleState::Toplevel(toplevel) = &mut self.surface_role { - if let Some(frame) = toplevel.frame.as_mut() { + if let SurfaceRoleState::Toplevel { frame, .. } = &mut self.surface_role { + if let Some(frame) = frame.as_mut() { frame.set_resizable(resizable); } } else { - panic!("This shouldn't happen!"); + panic!("This should never happen, there is likely a data race"); } } @@ -630,13 +665,13 @@ impl WindowState { #[inline] pub fn is_decorated(&mut self) -> bool { - if let SurfaceRoleState::Toplevel(toplevel) = &mut self.surface_role { + if let SurfaceRoleState::Toplevel { frame, .. } = &mut self.surface_role { let csd = self .last_configure .as_ref() .map(|configure| configure.decoration_mode == DecorationMode::Client) .unwrap_or(false); - if let Some(frame) = csd.then_some(toplevel.frame.as_ref()).flatten() { + if let Some(frame) = csd.then_some(frame.as_ref()).flatten() { !frame.is_hidden() } else { // Server side decorations. @@ -650,9 +685,8 @@ impl WindowState { /// Get the outer size of the window. #[inline] pub fn outer_size(&self) -> LogicalSize { - if let SurfaceRoleState::Toplevel(toplevel) = &self.surface_role { - toplevel - .frame + if let SurfaceRoleState::Toplevel { frame, .. } = &self.surface_role { + frame .as_ref() .map(|frame| frame.add_borders(self.size.width, self.size.height).into()) .unwrap_or(self.size) @@ -686,11 +720,12 @@ impl WindowState { /// Refresh the decorations frame if it's present returning whether the client should redraw. pub fn refresh_frame(&mut self) -> bool { - if let SurfaceRoleState::Toplevel(toplevel) = &mut self.surface_role { - if let Some(frame) = toplevel.frame.as_mut() { - if !frame.is_hidden() && frame.is_dirty() { - return frame.draw(); - } + if let SurfaceRoleState::Toplevel { + frame: Some(frame), .. + } = &mut self.surface_role + { + if !frame.is_hidden() && frame.is_dirty() { + return frame.draw(); } } @@ -747,34 +782,32 @@ impl WindowState { } // Update the inner frame. - let ((x, y), outer_size) = - if let SurfaceRoleState::Toplevel(toplevel) = &mut self.surface_role { - if let Some(frame) = toplevel.frame.as_mut() { - // Resize only visible frame. - if !frame.is_hidden() { - frame.resize( - NonZeroU32::new(self.size.width).unwrap(), - NonZeroU32::new(self.size.height).unwrap(), - ); - } + let ((x, y), outer_size) = if let SurfaceRoleState::Toplevel { + frame: Some(frame), .. + } = &mut self.surface_role + { + // Resize only visible frame. + if !frame.is_hidden() { + frame.resize( + NonZeroU32::new(self.size.width).unwrap(), + NonZeroU32::new(self.size.height).unwrap(), + ); + } - ( - frame.location(), - frame.add_borders(self.size.width, self.size.height).into(), - ) - } else { - ((0, 0), self.size) - } - } else { - ((0, 0), self.size) - }; + ( + frame.location(), + frame.add_borders(self.size.width, self.size.height).into(), + ) + } else { + ((0, 0), self.size) + }; // Reload the hint. self.reload_transparency_hint(); // Set the window geometry. - if let SurfaceRoleState::Toplevel(toplevel) = &mut self.surface_role { - toplevel.window.xdg_surface().set_window_geometry( + if let SurfaceRoleState::Toplevel { window, .. } = &mut self.surface_role { + window.xdg_surface().set_window_geometry( x, y, outer_size.width as i32, @@ -874,44 +907,45 @@ impl WindowState { /// Set maximum inner window size. pub fn set_min_inner_size(&mut self, size: Option>) { // Ensure that the window has the right minimum size. - if let SurfaceRoleState::Toplevel(toplevel) = &mut self.surface_role { + if let SurfaceRoleState::Toplevel { frame, window, .. } = &mut self.surface_role { let mut size = size.unwrap_or(MIN_WINDOW_SIZE); size.width = size.width.max(MIN_WINDOW_SIZE.width); size.height = size.height.max(MIN_WINDOW_SIZE.height); // Add the borders. - let size = toplevel - .frame + let size = frame .as_ref() .map(|frame| frame.add_borders(size.width, size.height).into()) .unwrap_or(size); self.min_inner_size = size; - toplevel.window.set_min_size(Some(size.into())); + window.set_min_size(Some(size.into())); } } /// Set maximum inner window size. pub fn set_max_inner_size(&mut self, size: Option>) { - if let SurfaceRoleState::Toplevel(toplevel) = &mut self.surface_role { + if let SurfaceRoleState::Toplevel { frame, window, .. } = &mut self.surface_role { let size = size.map(|size| { - toplevel - .frame + frame .as_ref() .map(|frame| frame.add_borders(size.width, size.height).into()) .unwrap_or(size) }); self.max_inner_size = size; - toplevel.window.set_max_size(size.map(Into::into)); + window.set_max_size(size.map(Into::into)); } } /// Set the CSD theme. pub fn set_theme(&mut self, theme: Option) { self.theme = theme; - if let SurfaceRoleState::Toplevel(toplevel) = &mut self.surface_role { - toplevel.set_theme(theme); + if let SurfaceRoleState::Toplevel { + frame: Some(frame), .. + } = &mut self.surface_role + { + frame.set_config(into_sctk_adwaita_config(theme)); } } @@ -975,13 +1009,11 @@ impl WindowState { pub fn show_window_menu(&self, position: LogicalPosition) { // TODO(kchibisov) handle touch serials. - if let SurfaceRoleState::Toplevel(toplevel) = &self.surface_role { + if let SurfaceRoleState::Toplevel { window, .. } = &self.surface_role { self.apply_on_poiner(|_, data| { let serial = data.latest_button_serial(); let seat = data.seat(); - toplevel - .window - .show_window_menu(seat, serial, position.into()); + window.show_window_menu(seat, serial, position.into()); }); } } @@ -1031,32 +1063,34 @@ impl WindowState { /// Whether show or hide client side decorations. #[inline] pub fn set_decorate(&mut self, decorate: bool) { - if let SurfaceRoleState::Toplevel(toplevel) = &mut self.surface_role { - if decorate == toplevel.decorate { + if let SurfaceRoleState::Toplevel { + frame, + window, + decorate: self_decorate, + .. + } = &mut self.surface_role + { + if decorate == *self_decorate { return; } - toplevel.decorate = decorate; + *self_decorate = decorate; match self .last_configure .as_ref() .map(|configure| configure.decoration_mode) { - Some(DecorationMode::Server) if !toplevel.decorate => { + Some(DecorationMode::Server) if !*self_decorate => { // To disable decorations we should request client and hide the frame. - toplevel - .window - .request_decoration_mode(Some(DecorationMode::Client)) + window.request_decoration_mode(Some(DecorationMode::Client)) } - _ if toplevel.decorate => toplevel - .window - .request_decoration_mode(Some(DecorationMode::Server)), + _ if *self_decorate => window.request_decoration_mode(Some(DecorationMode::Server)), _ => (), } - if let Some(frame) = toplevel.frame.as_mut() { - frame.set_hidden(!decorate); + if let Some(frame) = frame.as_mut() { + frame.set_hidden(!*self_decorate); // Force the resize. self.resize(self.size); } @@ -1134,10 +1168,11 @@ impl WindowState { .set_buffer_scale(self.scale_factor as _); } - if let SurfaceRoleState::Toplevel(toplevel) = &mut self.surface_role { - if let Some(frame) = toplevel.frame.as_mut() { - frame.set_scaling_factor(scale_factor); - } + if let SurfaceRoleState::Toplevel { + frame: Some(frame), .. + } = &mut self.surface_role + { + frame.set_scaling_factor(scale_factor); } } @@ -1167,7 +1202,13 @@ impl WindowState { pub fn set_title(&mut self, mut title: String) { // Truncate the title to at most 1024 bytes, so that it does not blow up the protocol // messages - if let SurfaceRoleState::Toplevel(toplevel) = &mut self.surface_role { + if let SurfaceRoleState::Toplevel { + frame, + window, + title: self_title, + .. + } = &mut self.surface_role + { if title.len() > 1024 { let mut new_len = 1024; while !title.is_char_boundary(new_len) { @@ -1177,12 +1218,12 @@ impl WindowState { } // Update the CSD title. - if let Some(frame) = toplevel.frame.as_mut() { + if let Some(frame) = frame.as_mut() { frame.set_title(&title); } - toplevel.window.set_title(&title); - toplevel.title = title; + window.set_title(&title); + *self_title = title; } } @@ -1212,10 +1253,9 @@ impl WindowState { /// Get the cached title. #[inline] pub fn title(&self) -> &str { - if let SurfaceRoleState::Toplevel(toplevel) = &self.surface_role { - &toplevel.title - } else { - "" + match &self.surface_role { + SurfaceRoleState::Toplevel { title, .. } => title.as_ref(), + _ => "" } } } diff --git a/src/platform_impl/linux/wayland/window/state/subsurface.rs b/src/platform_impl/linux/wayland/window/state/subsurface.rs deleted file mode 100644 index 3502c62e65..0000000000 --- a/src/platform_impl/linux/wayland/window/state/subsurface.rs +++ /dev/null @@ -1,20 +0,0 @@ -use sctk::shell::WaylandSurface; -use wayland_client::protocol::{wl_subsurface::WlSubsurface, wl_surface::WlSurface}; - -#[allow(unused)] -pub(in crate::platform_impl::platform::wayland) struct SubsurfaceState { - /// The parent surface for this subsurface. - pub parent_surface: WlSurface, - - /// The surface. - pub surface: WlSurface, - - /// The subsurface role. Allows control over position. - pub subsurface: WlSubsurface -} - -impl WaylandSurface for SubsurfaceState { - fn wl_surface(&self) -> &wayland_client::protocol::wl_surface::WlSurface { - &self.surface - } -} \ No newline at end of file diff --git a/src/platform_impl/linux/wayland/window/state/toplevel.rs b/src/platform_impl/linux/wayland/window/state/toplevel.rs deleted file mode 100644 index 63994e1f6f..0000000000 --- a/src/platform_impl/linux/wayland/window/state/toplevel.rs +++ /dev/null @@ -1,45 +0,0 @@ -use sctk::shell::{xdg::window::Window, WaylandSurface}; - -use crate::platform::wayland::Theme; - -use super::{into_sctk_adwaita_config, WinitFrame}; - -pub(in crate::platform_impl::platform::wayland) struct ToplevelState { - /// The underlying SCTK window. - pub window: Window, - - /// The window frame, which is created from the configure request. - pub frame: Option, - - /// Whether the client side decorations have pending move operations. - /// - /// The value is the serial of the event triggered moved. - pub has_pending_move: Option, - - /// The current window title. - pub title: String, - - /// Whether the frame is resizable. - pub resizable: bool, - - /// Whether the CSD fail to create, so we don't try to create them on each iteration. - pub csd_fails: bool, - - /// Whether we should decorate the frame. - pub decorate: bool, -} - -impl ToplevelState { - pub fn set_theme(&mut self, theme: Option) { - #[cfg(feature = "sctk-adwaita")] - if let Some(frame) = self.frame.as_mut() { - frame.set_config(into_sctk_adwaita_config(theme)) - } - } -} - -impl WaylandSurface for ToplevelState { - fn wl_surface(&self) -> &wayland_client::protocol::wl_surface::WlSurface { - self.window.wl_surface() - } -} \ No newline at end of file From 699a21d1a72a95d6be5ac19d5c28d83f02f28dbf Mon Sep 17 00:00:00 2001 From: jgcodes2020 Date: Sun, 18 Feb 2024 12:13:19 -0500 Subject: [PATCH 05/13] finish basic plumbing --- Cargo.toml | 5 +- examples/child_window.rs | 6 +- src/platform_impl/linux/wayland/window/mod.rs | 219 +++++++++++++----- .../linux/wayland/window/state.rs | 57 +++-- .../linux/wayland/window/subsurface.rs | 66 ++++++ 5 files changed, 272 insertions(+), 81 deletions(-) create mode 100644 src/platform_impl/linux/wayland/window/subsurface.rs diff --git a/Cargo.toml b/Cargo.toml index 9be0076827..c1393ae710 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,7 +45,7 @@ rustdoc-args = ["--cfg", "docsrs"] [features] default = ["rwh_06", "x11", "wayland", "wayland-dlopen", "wayland-csd-adwaita"] x11 = ["x11-dl", "bytemuck", "percent-encoding", "xkbcommon-dl/x11", "x11rb"] -wayland = ["wayland-client", "wayland-backend", "wayland-protocols", "wayland-protocols-plasma", "sctk", "ahash", "memmap2"] +wayland = ["wayland-client", "wayland-backend", "wayland-sys", "wayland-protocols", "wayland-protocols-plasma", "sctk", "ahash", "memmap2"] wayland-dlopen = ["wayland-backend/dlopen"] wayland-csd-adwaita = ["sctk-adwaita", "sctk-adwaita/ab_glyph"] wayland-csd-adwaita-crossfont = ["sctk-adwaita", "sctk-adwaita/crossfont"] @@ -183,8 +183,9 @@ percent-encoding = { version = "2.0", optional = true } rustix = { version = "0.38.4", default-features = false, features = ["std", "system", "thread", "process"] } sctk = { package = "smithay-client-toolkit", version = "0.18.0", default-features = false, features = ["calloop"], optional = true } sctk-adwaita = { version = "0.8.0", default_features = false, optional = true } +wayland-sys = { version = "0.31.1" , optional = true} wayland-backend = { version = "0.3.0", default_features = false, features = ["client_system"], optional = true } -wayland-client = { version = "0.31.1", optional = true } +wayland-client = { version = "0.31.0", optional = true } wayland-protocols = { version = "0.31.0", features = [ "staging"], optional = true } wayland-protocols-plasma = { version = "0.2.0", features = [ "client" ], optional = true } x11-dl = { version = "2.18.5", optional = true } diff --git a/examples/child_window.rs b/examples/child_window.rs index b9e28313c2..9f5be44803 100644 --- a/examples/child_window.rs +++ b/examples/child_window.rs @@ -1,13 +1,13 @@ #[cfg(all( feature = "rwh_06", - any(x11_platform, macos_platform, windows_platform) + any(x11_platform, wayland_platform, macos_platform, windows_platform) ))] #[path = "util/fill.rs"] mod fill; #[cfg(all( feature = "rwh_06", - any(x11_platform, macos_platform, windows_platform) + any(x11_platform, wayland_platform, macos_platform, windows_platform) ))] #[allow(deprecated)] fn main() -> Result<(), impl std::error::Error> { @@ -90,7 +90,7 @@ fn main() -> Result<(), impl std::error::Error> { #[cfg(not(all( feature = "rwh_06", - any(x11_platform, macos_platform, windows_platform) + any(x11_platform, wayland_platform, macos_platform, windows_platform) )))] fn main() { panic!("This example is supported only on x11, macOS, and Windows, with the `rwh_06` feature enabled."); diff --git a/src/platform_impl/linux/wayland/window/mod.rs b/src/platform_impl/linux/wayland/window/mod.rs index 7c3798ac6c..e534a4b2f3 100644 --- a/src/platform_impl/linux/wayland/window/mod.rs +++ b/src/platform_impl/linux/wayland/window/mod.rs @@ -11,11 +11,12 @@ use sctk::reexports::client::QueueHandle; use sctk::compositor::{CompositorState, Region, SurfaceData}; use sctk::reexports::protocols::xdg::activation::v1::client::xdg_activation_v1::XdgActivationV1; -use sctk::shell::xdg::window::Window as SctkWindow; use sctk::shell::xdg::window::WindowDecorations; +use sctk::shell::xdg::window::Window as SctkWindow; use sctk::shell::WaylandSurface; use log::warn; +use wayland_backend::client::ObjectId; use crate::dpi::{LogicalSize, PhysicalPosition, PhysicalSize, Position, Size}; use crate::error::{ExternalError, NotSupportedError, OsError as RootOsError}; @@ -29,6 +30,8 @@ use crate::window::{ WindowAttributes, WindowButtons, WindowLevel, }; +use self::subsurface::Subsurface; + use super::event_loop::sink::EventSink; use super::output::MonitorHandle; use super::state::WinitState; @@ -36,13 +39,30 @@ use super::types::xdg_activation::XdgActivationTokenData; use super::{EventLoopWindowTarget, WaylandError, WindowId}; pub(crate) mod state; +pub(crate) mod subsurface; pub use state::WindowState; +#[allow(dead_code)] +#[derive(Clone)] +pub enum WindowRole { + Toplevel(SctkWindow), + Subsurface(Subsurface), +} + +impl WaylandSurface for WindowRole { + fn wl_surface(&self) -> &wayland_client::protocol::wl_surface::WlSurface { + match self { + WindowRole::Toplevel(window) => window.wl_surface(), + WindowRole::Subsurface(window) => window.wl_surface(), + } + } +} + /// The Wayland window. pub struct Window { /// Reference to the underlying SCTK window. - window: SctkWindow, + window: WindowRole, /// Xdg activation to request user attention. xdg_activation: Option, @@ -109,19 +129,63 @@ impl Window { WindowDecorations::RequestClient }; - let window = - state - .xdg_shell - .create_window(surface.clone(), default_decorations, &queue_handle); - - let mut window_state = WindowState::new( - event_loop_window_target.connection.clone(), - &event_loop_window_target.queue_handle, - &state, - size, - window.clone(), - attributes.preferred_theme, - ); + // if let Some(parent_window) = attributes.parent_window() { + // match parent_window { + // rwh_06::RawWindowHandle::Wayland(_) => { + + // }, + // _ => panic!("Parent window of a Wayland window must be a Wayland window"), + // } + // } + let (window, mut window_state) = match attributes.parent_window() { + Some(rwh_06::RawWindowHandle::Wayland(wl_handle)) => unsafe { + let parent_surface = WlSurface::from_id( + &event_loop_window_target.connection, + ObjectId::from_ptr( + WlSurface::interface(), + wl_handle.surface.as_ptr() as *mut wayland_sys::client::wl_proxy, + ) + .expect("Invalid parent surface handle!"), + ) + .expect("Broke!"); + + let window = WindowRole::Subsurface(Subsurface::from_parent( + &parent_surface, + state.subcompositor_state.as_ref().unwrap(), + &queue_handle, + )); + + let window_state = WindowState::new( + event_loop_window_target.connection.clone(), + &event_loop_window_target.queue_handle, + &state, + size, + window.clone(), + attributes.preferred_theme, + ); + + (window, window_state) + }, + None => { + let window = WindowRole::Toplevel(state.xdg_shell.create_window( + surface.clone(), + default_decorations, + &queue_handle, + )); + + let window_state = WindowState::new( + event_loop_window_target.connection.clone(), + &event_loop_window_target.queue_handle, + &state, + size, + window.clone(), + attributes.preferred_theme, + ); + + (window, window_state) + } + _ => panic!("Parent window of a Wayland surface must be a Wayland surface"), + }; // Set transparency hint. window_state.set_transparent(attributes.transparent); @@ -133,7 +197,11 @@ impl Window { // Set the app_id. if let Some(name) = attributes.platform_specific.name.map(|name| name.general) { - window.set_app_id(name); + if let WindowRole::Toplevel(window) = &window { + window.set_app_id(name); + } else { + warn!("Only toplevel windows can have an app ID"); + } } // Set the window title. @@ -150,22 +218,24 @@ impl Window { window_state.set_resizable(attributes.resizable); // Set startup mode. - match attributes.fullscreen.map(Into::into) { - Some(Fullscreen::Exclusive(_)) => { - warn!("`Fullscreen::Exclusive` is ignored on Wayland"); - } - Some(Fullscreen::Borderless(monitor)) => { - let output = monitor.and_then(|monitor| match monitor { - PlatformMonitorHandle::Wayland(monitor) => Some(monitor.proxy), - #[cfg(x11_platform)] - PlatformMonitorHandle::X(_) => None, - }); - - window.set_fullscreen(output.as_ref()) - } - _ if attributes.maximized => window.set_maximized(), - _ => (), - }; + if let WindowRole::Toplevel(window) = &window { + match attributes.fullscreen.map(Into::into) { + Some(Fullscreen::Exclusive(_)) => { + warn!("`Fullscreen::Exclusive` is ignored on Wayland"); + } + Some(Fullscreen::Borderless(monitor)) => { + let output = monitor.and_then(|monitor| match monitor { + PlatformMonitorHandle::Wayland(monitor) => Some(monitor.proxy), + #[cfg(x11_platform)] + PlatformMonitorHandle::X(_) => None, + }); + + window.set_fullscreen(output.as_ref()) + } + _ if attributes.maximized => window.set_maximized(), + _ => (), + }; + } match attributes.cursor { Cursor::Icon(icon) => window_state.set_cursor(icon), @@ -268,17 +338,41 @@ impl Window { #[inline] pub fn outer_position(&self) -> Result, NotSupportedError> { - Err(NotSupportedError::new()) + match &self.window { + WindowRole::Toplevel(_) => { + warn!("Toplevel windows cannot get their position"); + Err(NotSupportedError::new()) + }, + WindowRole::Subsurface(window) => { + Ok(window.get_position()) + }, + } + + } #[inline] pub fn inner_position(&self) -> Result, NotSupportedError> { - Err(NotSupportedError::new()) + match &self.window { + WindowRole::Toplevel(_) => { + warn!("Toplevel windows cannot get their position"); + Err(NotSupportedError::new()) + }, + WindowRole::Subsurface(window) => { + Ok(window.get_position()) + }, + } } #[inline] - pub fn set_outer_position(&self, _: Position) { - // Not possible on Wayland. + pub fn set_outer_position(&self, pos: Position) { + match &self.window { + WindowRole::Toplevel(_) => warn!("Toplevel windows cannot set their position"), + WindowRole::Subsurface(window) => { + let physical_pos: PhysicalPosition = pos.to_physical(self.scale_factor()); + window.set_position(physical_pos); + }, + } } #[inline] @@ -446,13 +540,16 @@ impl Window { #[inline] pub fn set_minimized(&self, minimized: bool) { - // You can't unminimize the window on Wayland. - if !minimized { - warn!("Unminimizing is ignored on Wayland."); - return; + if let WindowRole::Toplevel(window) = &self.window { + // You can't unminimize the window on Wayland. + if !minimized { + warn!("Unminimizing is ignored on Wayland."); + return; + } + window.set_minimized(); + } else { + warn!("Only toplevel windows can be minimized on Wayland."); } - - self.window.set_minimized(); } #[inline] @@ -468,10 +565,14 @@ impl Window { #[inline] pub fn set_maximized(&self, maximized: bool) { - if maximized { - self.window.set_maximized() + if let WindowRole::Toplevel(window) = &self.window { + if maximized { + window.set_maximized(); + } else { + window.unset_maximized(); + } } else { - self.window.unset_maximized() + warn!("Only toplevel windows can be maximized on Wayland."); } } @@ -496,20 +597,22 @@ impl Window { #[inline] pub(crate) fn set_fullscreen(&self, fullscreen: Option) { - match fullscreen { - Some(Fullscreen::Exclusive(_)) => { - warn!("`Fullscreen::Exclusive` is ignored on Wayland"); - } - Some(Fullscreen::Borderless(monitor)) => { - let output = monitor.and_then(|monitor| match monitor { - PlatformMonitorHandle::Wayland(monitor) => Some(monitor.proxy), - #[cfg(x11_platform)] - PlatformMonitorHandle::X(_) => None, - }); - - self.window.set_fullscreen(output.as_ref()) + if let WindowRole::Toplevel(window) = &self.window { + match fullscreen { + Some(Fullscreen::Exclusive(_)) => { + warn!("`Fullscreen::Exclusive` is ignored on Wayland"); + } + Some(Fullscreen::Borderless(monitor)) => { + let output = monitor.and_then(|monitor| match monitor { + PlatformMonitorHandle::Wayland(monitor) => Some(monitor.proxy), + #[cfg(x11_platform)] + PlatformMonitorHandle::X(_) => None, + }); + + window.set_fullscreen(output.as_ref()) + } + None => window.unset_fullscreen(), } - None => self.window.unset_fullscreen(), } } diff --git a/src/platform_impl/linux/wayland/window/state.rs b/src/platform_impl/linux/wayland/window/state.rs index d30b5ce539..86607f964f 100644 --- a/src/platform_impl/linux/wayland/window/state.rs +++ b/src/platform_impl/linux/wayland/window/state.rs @@ -31,7 +31,7 @@ use sctk::subcompositor::SubcompositorState; use wayland_protocols_plasma::blur::client::org_kde_kwin_blur::OrgKdeKwinBlur; use crate::cursor::CustomCursor as RootCustomCursor; -use crate::dpi::{LogicalPosition, LogicalSize, PhysicalSize, Size}; +use crate::dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Size}; use crate::error::{ExternalError, NotSupportedError}; use crate::platform_impl::wayland::logical_to_physical_rounded; use crate::platform_impl::wayland::types::cursor::{CustomCursor, SelectedCursor}; @@ -44,11 +44,8 @@ use crate::platform_impl::wayland::seat::{ }; use crate::platform_impl::wayland::state::{WindowCompositorUpdate, WinitState}; -use self::subsurface::SubsurfaceState; -use self::toplevel::ToplevelState; - -mod subsurface; -mod toplevel; +use super::subsurface::Subsurface; +use super::WindowRole; #[cfg(feature = "sctk-adwaita")] pub type WinitFrame = sctk_adwaita::AdwaitaFrame; @@ -84,14 +81,17 @@ pub enum SurfaceRoleState { /// Whether we should decorate the frame. decorate: bool, }, - Subsurface(SubsurfaceState), + Subsurface { + /// The underlying subsurface. + window: Subsurface + }, } impl WaylandSurface for SurfaceRoleState { fn wl_surface(&self) -> &wayland_client::protocol::wl_surface::WlSurface { match self { - SurfaceRoleState::Toplevel { window: window, .. } => window.wl_surface(), - SurfaceRoleState::Subsurface(subsurface) => subsurface.wl_surface(), + SurfaceRoleState::Toplevel { window, .. } => window.wl_surface(), + SurfaceRoleState::Subsurface { window } => window.wl_surface(), } } } @@ -188,7 +188,7 @@ impl WindowState { queue_handle: &QueueHandle, winit_state: &WinitState, initial_size: Size, - window: Window, + window: WindowRole, theme: Option, ) -> Self { let compositor = winit_state.compositor_state.clone(); @@ -207,14 +207,21 @@ impl WindowState { blur_manager: winit_state.kwin_blur_manager.clone(), compositor, connection, - surface_role: SurfaceRoleState::Toplevel { - window, - frame: None, - has_pending_move: None, - title: String::default(), - resizable: true, - csd_fails: false, - decorate: true, + surface_role: match window { + WindowRole::Toplevel(window) => { + SurfaceRoleState::Toplevel { + window, + frame: None, + has_pending_move: None, + title: String::default(), + resizable: true, + csd_fails: false, + decorate: true, + } + }, + WindowRole::Subsurface(window) => { + SurfaceRoleState::Subsurface { window } + }, }, cursor_grab_mode: GrabState::new(), selected_cursor: Default::default(), @@ -1225,6 +1232,9 @@ impl WindowState { window.set_title(&title); *self_title = title; } + else { + warn!("Only toplevel windows may have a title"); + } } /// Mark the window as transparent. @@ -1258,6 +1268,17 @@ impl WindowState { _ => "" } } + + /// Set + #[inline] + pub fn set_position(&mut self, pos: PhysicalPosition) { + if let SurfaceRoleState::Subsurface { window } = &self.surface_role { + window.set_position(pos); + } + else { + warn!("Only subsurfaces can set their (parent-relative) position") + } + } } impl Drop for WindowState { diff --git a/src/platform_impl/linux/wayland/window/subsurface.rs b/src/platform_impl/linux/wayland/window/subsurface.rs new file mode 100644 index 0000000000..ca09bdc438 --- /dev/null +++ b/src/platform_impl/linux/wayland/window/subsurface.rs @@ -0,0 +1,66 @@ +use std::sync::{Arc, RwLock}; + +use sctk::{ + compositor::SurfaceData, + shell::WaylandSurface, + subcompositor::{SubcompositorState, SubsurfaceData}, +}; +use wayland_client::{ + protocol::{wl_subsurface::WlSubsurface, wl_surface::WlSurface}, + Dispatch, QueueHandle, +}; + +use crate::dpi::PhysicalPosition; + +#[derive(Clone)] +pub struct Subsurface(Arc); + +struct SubsurfaceInner { + pub surface: WlSurface, + pub subsurface: WlSubsurface, + pub position: RwLock> +} + +impl Subsurface { + pub fn from_parent( + parent: &WlSurface, + subcompositor: &SubcompositorState, + queue_handle: &QueueHandle, + ) -> Subsurface where + T: Dispatch + Dispatch + 'static, + { + let (subsurface, surface) = + subcompositor.create_subsurface(parent.clone(), queue_handle); + + Subsurface(Arc::new(SubsurfaceInner { + surface, + subsurface, + position: RwLock::new(PhysicalPosition::new(0, 0)) + })) + } + + pub fn set_position(&self, pos: PhysicalPosition) { + let inner = &*self.0; + + inner.subsurface.set_position(pos.x, pos.y); + *inner.position.write().unwrap() = pos; + } + + pub fn get_position(&self) -> PhysicalPosition { + *self.0.position.read().unwrap() + } + + pub fn set_sync(&self) { + self.0.subsurface.set_sync(); + } + + pub fn set_desync(&self) { + self.0.subsurface.set_desync(); + } +} + +impl WaylandSurface for Subsurface { + fn wl_surface(&self) -> &wayland_client::protocol::wl_surface::WlSurface { + &self.0.surface + } +} \ No newline at end of file From a51875760a26629f80c3c9e0cc6421b7be62438c Mon Sep 17 00:00:00 2001 From: jgcodes2020 Date: Sun, 18 Feb 2024 12:19:23 -0500 Subject: [PATCH 06/13] run cargo fmt --- src/platform_impl/linux/wayland/window/mod.rs | 18 ++++------- .../linux/wayland/window/state.rs | 32 ++++++++----------- .../linux/wayland/window/subsurface.rs | 16 +++++----- 3 files changed, 27 insertions(+), 39 deletions(-) diff --git a/src/platform_impl/linux/wayland/window/mod.rs b/src/platform_impl/linux/wayland/window/mod.rs index e534a4b2f3..79f4deabd8 100644 --- a/src/platform_impl/linux/wayland/window/mod.rs +++ b/src/platform_impl/linux/wayland/window/mod.rs @@ -11,8 +11,8 @@ use sctk::reexports::client::QueueHandle; use sctk::compositor::{CompositorState, Region, SurfaceData}; use sctk::reexports::protocols::xdg::activation::v1::client::xdg_activation_v1::XdgActivationV1; -use sctk::shell::xdg::window::WindowDecorations; use sctk::shell::xdg::window::Window as SctkWindow; +use sctk::shell::xdg::window::WindowDecorations; use sctk::shell::WaylandSurface; use log::warn; @@ -342,13 +342,9 @@ impl Window { WindowRole::Toplevel(_) => { warn!("Toplevel windows cannot get their position"); Err(NotSupportedError::new()) - }, - WindowRole::Subsurface(window) => { - Ok(window.get_position()) - }, + } + WindowRole::Subsurface(window) => Ok(window.get_position()), } - - } #[inline] @@ -357,10 +353,8 @@ impl Window { WindowRole::Toplevel(_) => { warn!("Toplevel windows cannot get their position"); Err(NotSupportedError::new()) - }, - WindowRole::Subsurface(window) => { - Ok(window.get_position()) - }, + } + WindowRole::Subsurface(window) => Ok(window.get_position()), } } @@ -371,7 +365,7 @@ impl Window { WindowRole::Subsurface(window) => { let physical_pos: PhysicalPosition = pos.to_physical(self.scale_factor()); window.set_position(physical_pos); - }, + } } } diff --git a/src/platform_impl/linux/wayland/window/state.rs b/src/platform_impl/linux/wayland/window/state.rs index 86607f964f..c5be12b602 100644 --- a/src/platform_impl/linux/wayland/window/state.rs +++ b/src/platform_impl/linux/wayland/window/state.rs @@ -83,7 +83,7 @@ pub enum SurfaceRoleState { }, Subsurface { /// The underlying subsurface. - window: Subsurface + window: Subsurface, }, } @@ -208,20 +208,16 @@ impl WindowState { compositor, connection, surface_role: match window { - WindowRole::Toplevel(window) => { - SurfaceRoleState::Toplevel { - window, - frame: None, - has_pending_move: None, - title: String::default(), - resizable: true, - csd_fails: false, - decorate: true, - } - }, - WindowRole::Subsurface(window) => { - SurfaceRoleState::Subsurface { window } + WindowRole::Toplevel(window) => SurfaceRoleState::Toplevel { + window, + frame: None, + has_pending_move: None, + title: String::default(), + resizable: true, + csd_fails: false, + decorate: true, }, + WindowRole::Subsurface(window) => SurfaceRoleState::Subsurface { window }, }, cursor_grab_mode: GrabState::new(), selected_cursor: Default::default(), @@ -1231,8 +1227,7 @@ impl WindowState { window.set_title(&title); *self_title = title; - } - else { + } else { warn!("Only toplevel windows may have a title"); } } @@ -1265,7 +1260,7 @@ impl WindowState { pub fn title(&self) -> &str { match &self.surface_role { SurfaceRoleState::Toplevel { title, .. } => title.as_ref(), - _ => "" + _ => "", } } @@ -1274,8 +1269,7 @@ impl WindowState { pub fn set_position(&mut self, pos: PhysicalPosition) { if let SurfaceRoleState::Subsurface { window } = &self.surface_role { window.set_position(pos); - } - else { + } else { warn!("Only subsurfaces can set their (parent-relative) position") } } diff --git a/src/platform_impl/linux/wayland/window/subsurface.rs b/src/platform_impl/linux/wayland/window/subsurface.rs index ca09bdc438..3fd4f64889 100644 --- a/src/platform_impl/linux/wayland/window/subsurface.rs +++ b/src/platform_impl/linux/wayland/window/subsurface.rs @@ -18,7 +18,7 @@ pub struct Subsurface(Arc); struct SubsurfaceInner { pub surface: WlSurface, pub subsurface: WlSubsurface, - pub position: RwLock> + pub position: RwLock>, } impl Subsurface { @@ -26,16 +26,16 @@ impl Subsurface { parent: &WlSurface, subcompositor: &SubcompositorState, queue_handle: &QueueHandle, - ) -> Subsurface where + ) -> Subsurface + where T: Dispatch + Dispatch + 'static, { - let (subsurface, surface) = - subcompositor.create_subsurface(parent.clone(), queue_handle); + let (subsurface, surface) = subcompositor.create_subsurface(parent.clone(), queue_handle); - Subsurface(Arc::new(SubsurfaceInner { - surface, + Subsurface(Arc::new(SubsurfaceInner { + surface, subsurface, - position: RwLock::new(PhysicalPosition::new(0, 0)) + position: RwLock::new(PhysicalPosition::new(0, 0)), })) } @@ -63,4 +63,4 @@ impl WaylandSurface for Subsurface { fn wl_surface(&self) -> &wayland_client::protocol::wl_surface::WlSurface { &self.0.surface } -} \ No newline at end of file +} From 8acc341d8d42dd4b259842603b373f3e569417f7 Mon Sep 17 00:00:00 2001 From: jgcodes2020 Date: Mon, 19 Feb 2024 15:45:02 -0500 Subject: [PATCH 07/13] fix waiting on configure --- examples/child_window.rs | 76 ++++++++++--------- src/platform_impl/linux/wayland/window/mod.rs | 2 +- .../linux/wayland/window/state.rs | 6 +- .../linux/wayland/window/subsurface.rs | 7 ++ src/window.rs | 11 ++- 5 files changed, 60 insertions(+), 42 deletions(-) diff --git a/examples/child_window.rs b/examples/child_window.rs index 9f5be44803..4a791286d5 100644 --- a/examples/child_window.rs +++ b/examples/child_window.rs @@ -13,77 +13,81 @@ mod fill; fn main() -> Result<(), impl std::error::Error> { use std::collections::HashMap; + use rwh_06::HasRawWindowHandle; use winit::{ - dpi::{LogicalPosition, LogicalSize, Position}, + dpi::{LogicalPosition, LogicalSize}, event::{ElementState, Event, KeyEvent, WindowEvent}, event_loop::{EventLoop, EventLoopWindowTarget}, - raw_window_handle::HasRawWindowHandle, + keyboard::{KeyCode, PhysicalKey}, window::{Window, WindowId}, }; - fn spawn_child_window( + fn spawn_child( parent: &Window, event_loop: &EventLoopWindowTarget, - windows: &mut HashMap, + children: &mut HashMap, ) { - let parent = parent.raw_window_handle().unwrap(); let mut builder = Window::builder() - .with_title("child window") + .with_position(LogicalPosition::new(0, 0)) .with_inner_size(LogicalSize::new(200.0f32, 200.0f32)) - .with_position(Position::Logical(LogicalPosition::new(0.0, 0.0))) .with_visible(true); - // `with_parent_window` is unsafe. Parent window must be a valid window. - builder = unsafe { builder.with_parent_window(Some(parent)) }; - let child_window = builder.build(event_loop).unwrap(); - let id = child_window.id(); - windows.insert(id, child_window); - println!("child window created with id: {id:?}"); + builder = unsafe { builder.with_parent_window(parent.raw_window_handle().ok()) }; + + let child = builder.build(event_loop).unwrap(); + let child_id = child.id(); + + children.insert(child_id, child); } - let mut windows = HashMap::new(); + let event_loop = EventLoop::new().unwrap(); - let event_loop: EventLoop<()> = EventLoop::new().unwrap(); - let parent_window = Window::builder() + let window = Window::builder() .with_title("parent window") - .with_position(Position::Logical(LogicalPosition::new(0.0, 0.0))) - .with_inner_size(LogicalSize::new(640.0f32, 480.0f32)) + .with_inner_size(winit::dpi::LogicalSize::new(640.0, 480.0)) .build(&event_loop) .unwrap(); + let mut children = HashMap::::new(); - println!("parent window: {parent_window:?})"); - - event_loop.run(move |event: Event<()>, elwt| { - if let Event::WindowEvent { event, window_id } = event { - match event { + event_loop.run(move |event, elwt| { + match event { + Event::WindowEvent { event, window_id } => match event { WindowEvent::CloseRequested => { - windows.clear(); + children.clear(); elwt.exit(); } - WindowEvent::CursorEntered { device_id: _ } => { - // On x11, println when the cursor entered in a window even if the child window is created - // by some key inputs. - // the child windows are always placed at (0, 0) with size (200, 200) in the parent window, - // so we also can see this log when we move the cursor arround (200, 200) in parent window. - println!("cursor entered in the window {window_id:?}"); + WindowEvent::RedrawRequested => { + // Notify the windowing system that we'll be presenting to the window. + if let Some(child_window) = children.get(&window_id) { + child_window.pre_present_notify(); + fill::fill_window(&child_window); + } else if window_id == window.id() { + window.pre_present_notify(); + fill::fill_window(&window); + } } WindowEvent::KeyboardInput { event: KeyEvent { + physical_key: PhysicalKey::Code(KeyCode::Enter), state: ElementState::Pressed, .. }, .. } => { - spawn_child_window(&parent_window, elwt, &mut windows); + println!("Spawning child..."); + spawn_child(&window, &elwt, &mut children); } - WindowEvent::RedrawRequested => { - if let Some(window) = windows.get(&window_id) { - fill::fill_window(window); - } + WindowEvent::CursorEntered { .. } => { + println!("cursor entered window {window_id:?}"); } _ => (), + }, + Event::AboutToWait => { + window.request_redraw(); } + + _ => (), } }) } @@ -93,5 +97,5 @@ fn main() -> Result<(), impl std::error::Error> { any(x11_platform, wayland_platform, macos_platform, windows_platform) )))] fn main() { - panic!("This example is supported only on x11, macOS, and Windows, with the `rwh_06` feature enabled."); + panic!("This example is supported only on X11, Wayland, macOS, and Windows, with the `rwh_06` feature enabled."); } diff --git a/src/platform_impl/linux/wayland/window/mod.rs b/src/platform_impl/linux/wayland/window/mod.rs index 79f4deabd8..ff0fbbeb43 100644 --- a/src/platform_impl/linux/wayland/window/mod.rs +++ b/src/platform_impl/linux/wayland/window/mod.rs @@ -147,7 +147,7 @@ impl Window { ) .expect("Invalid parent surface handle!"), ) - .expect("Broke!"); + .expect("Invalid parent surface handle!"); let window = WindowRole::Subsurface(Subsurface::from_parent( &parent_surface, diff --git a/src/platform_impl/linux/wayland/window/state.rs b/src/platform_impl/linux/wayland/window/state.rs index c5be12b602..0dfd656369 100644 --- a/src/platform_impl/linux/wayland/window/state.rs +++ b/src/platform_impl/linux/wayland/window/state.rs @@ -663,7 +663,11 @@ impl WindowState { /// Whether the window received initial configure event from the compositor. #[inline] pub fn is_configured(&self) -> bool { - self.last_configure.is_some() + if let SurfaceRoleState::Toplevel { .. } = &self.surface_role { + self.last_configure.is_some() + } else { + true + } } #[inline] diff --git a/src/platform_impl/linux/wayland/window/subsurface.rs b/src/platform_impl/linux/wayland/window/subsurface.rs index 3fd4f64889..e32bafb519 100644 --- a/src/platform_impl/linux/wayland/window/subsurface.rs +++ b/src/platform_impl/linux/wayland/window/subsurface.rs @@ -21,6 +21,13 @@ struct SubsurfaceInner { pub position: RwLock>, } +impl Drop for SubsurfaceInner { + fn drop(&mut self) { + self.subsurface.destroy(); + self.surface.destroy(); + } +} + impl Subsurface { pub fn from_parent( parent: &WlSurface, diff --git a/src/window.rs b/src/window.rs index fb3f435bdc..6b6a59205c 100644 --- a/src/window.rs +++ b/src/window.rs @@ -705,8 +705,9 @@ impl Window { /// - **iOS:** Can only be called on the main thread. Returns the top left coordinates of the /// window's [safe area] in the screen space coordinate system. /// - **Web:** Returns the top-left coordinates relative to the viewport. _Note: this returns the - /// same value as [`Window::outer_position`]._ - /// - **Android / Wayland:** Always returns [`NotSupportedError`]. + /// same value as [`Window::outer_position`]. + /// - **Wayland:** Returns [`NotSupportedError`] for toplevel windows. + /// - **Android:** Always returns [`NotSupportedError`]. /// /// [safe area]: https://developer.apple.com/documentation/uikit/uiview/2891103-safeareainsets?language=objc #[inline] @@ -729,7 +730,8 @@ impl Window { /// - **iOS:** Can only be called on the main thread. Returns the top left coordinates of the /// window in the screen space coordinate system. /// - **Web:** Returns the top-left coordinates relative to the viewport. - /// - **Android / Wayland:** Always returns [`NotSupportedError`]. + /// - **Wayland:** Returns [`NotSupportedError`] for toplevel windows. + /// - **Android:** Always returns [`NotSupportedError`]. #[inline] pub fn outer_position(&self) -> Result, NotSupportedError> { self.window.maybe_wait_on_main(|w| w.outer_position()) @@ -759,7 +761,8 @@ impl Window { /// window in the screen space coordinate system. /// - **Web:** Sets the top-left coordinates relative to the viewport. Doesn't account for CSS /// [`transform`]. - /// - **Android / Wayland:** Unsupported. + /// - **Wayland:** Only supported on child windows. + /// - **Android** Unsupported. /// /// [`transform`]: https://developer.mozilla.org/en-US/docs/Web/CSS/transform #[inline] From 44a50cd5b62cdef4ea15ff35a15f9ad1826058a2 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Thu, 1 Feb 2024 14:27:44 +0100 Subject: [PATCH 08/13] Make `EventLoopProxy` Sync Co-authored-by: daxpedda Closes: #3448 --- CHANGELOG.md | 1 + src/event_loop.rs | 3 ++- src/platform_impl/ios/event_loop.rs | 1 + src/platform_impl/macos/event_loop.rs | 1 + src/platform_impl/web/async/dispatcher.rs | 4 ++-- src/platform_impl/web/async/waker.rs | 4 ++-- src/platform_impl/web/async/wrapper.rs | 14 +++++++------- tests/send_objects.rs | 2 +- tests/sync_object.rs | 9 +++++++++ 9 files changed, 26 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7769640216..8e12b62c5a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ Unreleased` header. - On X11, don't require XIM to run. - On X11, fix xkb state not being updated correctly sometimes leading to wrong input. - Fix compatibility with 32-bit platforms without 64-bit atomics. +- Implement `Sync` for `EventLoopProxy`. - On X11, fix swapped instance and general class names. - **Breaking:** Removed unnecessary generic parameter `T` from `EventLoopWindowTarget`. - On Windows, macOS, X11, Wayland and Web, implement setting images as cursors. See the `custom_cursors.rs` example. diff --git a/src/event_loop.rs b/src/event_loop.rs index ad2bfa59e4..b8dd1a2140 100644 --- a/src/event_loop.rs +++ b/src/event_loop.rs @@ -253,7 +253,8 @@ impl EventLoop { self.event_loop.run(event_handler) } - /// Creates an [`EventLoopProxy`] that can be used to dispatch user events to the main event loop. + /// Creates an [`EventLoopProxy`] that can be used to dispatch user events + /// to the main event loop, possibly from another thread. pub fn create_proxy(&self) -> EventLoopProxy { EventLoopProxy { event_loop_proxy: self.event_loop.create_proxy(), diff --git a/src/platform_impl/ios/event_loop.rs b/src/platform_impl/ios/event_loop.rs index cf69eec5a8..1df992ccfe 100644 --- a/src/platform_impl/ios/event_loop.rs +++ b/src/platform_impl/ios/event_loop.rs @@ -229,6 +229,7 @@ pub struct EventLoopProxy { } unsafe impl Send for EventLoopProxy {} +unsafe impl Sync for EventLoopProxy {} impl Clone for EventLoopProxy { fn clone(&self) -> EventLoopProxy { diff --git a/src/platform_impl/macos/event_loop.rs b/src/platform_impl/macos/event_loop.rs index 32cc199087..59c6e2b403 100644 --- a/src/platform_impl/macos/event_loop.rs +++ b/src/platform_impl/macos/event_loop.rs @@ -532,6 +532,7 @@ pub struct EventLoopProxy { } unsafe impl Send for EventLoopProxy {} +unsafe impl Sync for EventLoopProxy {} impl Drop for EventLoopProxy { fn drop(&mut self) { diff --git a/src/platform_impl/web/async/dispatcher.rs b/src/platform_impl/web/async/dispatcher.rs index f7307d9f3a..a83d4ab2f9 100644 --- a/src/platform_impl/web/async/dispatcher.rs +++ b/src/platform_impl/web/async/dispatcher.rs @@ -5,7 +5,7 @@ use std::{ sync::{Arc, Condvar, Mutex}, }; -pub struct Dispatcher(Wrapper>, Closure>); +pub struct Dispatcher(Wrapper>, Closure>); struct Closure(Box); @@ -85,7 +85,7 @@ impl Dispatcher { } pub struct DispatchRunner { - wrapper: Wrapper>, Closure>, + wrapper: Wrapper>, Closure>, receiver: Receiver>, } diff --git a/src/platform_impl/web/async/waker.rs b/src/platform_impl/web/async/waker.rs index fd8733af97..8280e13da8 100644 --- a/src/platform_impl/web/async/waker.rs +++ b/src/platform_impl/web/async/waker.rs @@ -6,9 +6,9 @@ use std::task::Poll; use super::super::main_thread::MainThreadMarker; use super::{AtomicWaker, Wrapper}; -pub struct WakerSpawner(Wrapper, Sender, usize>); +pub struct WakerSpawner(Wrapper, Sender, usize>); -pub struct Waker(Wrapper, Sender, usize>); +pub struct Waker(Wrapper, Sender, usize>); struct Handler { value: T, diff --git a/src/platform_impl/web/async/wrapper.rs b/src/platform_impl/web/async/wrapper.rs index d8b05c713c..1825df132b 100644 --- a/src/platform_impl/web/async/wrapper.rs +++ b/src/platform_impl/web/async/wrapper.rs @@ -6,14 +6,14 @@ use std::sync::Arc; // Unsafe wrapper type that allows us to use `T` when it's not `Send` from other threads. // `value` **must** only be accessed on the main thread. -pub struct Wrapper { - value: Value, +pub struct Wrapper { + value: Value, handler: fn(&RefCell>, E), sender_data: S, sender_handler: fn(&S, E), } -struct Value { +struct Value { // SAFETY: // This value must not be accessed if not on the main thread. // @@ -28,11 +28,11 @@ struct Value { } // SAFETY: See `Self::value`. -unsafe impl Send for Value {} +unsafe impl Send for Value {} // SAFETY: See `Self::value`. -unsafe impl Sync for Value {} +unsafe impl Sync for Value {} -impl Wrapper { +impl Wrapper { #[track_caller] pub fn new>( _: MainThreadMarker, @@ -81,7 +81,7 @@ impl Wrapper { } } -impl Clone for Wrapper { +impl Clone for Wrapper { fn clone(&self) -> Self { Self { value: Value { diff --git a/tests/send_objects.rs b/tests/send_objects.rs index 0a5d1a9eb3..a238d5bb1b 100644 --- a/tests/send_objects.rs +++ b/tests/send_objects.rs @@ -5,7 +5,7 @@ fn needs_send() {} fn event_loop_proxy_send() { #[allow(dead_code)] fn is_send() { - // ensures that `winit::EventLoopProxy` implements `Send` + // ensures that `winit::EventLoopProxy` implements `Send` needs_send::>(); } } diff --git a/tests/sync_object.rs b/tests/sync_object.rs index 8500ac5fa7..7740b8fc67 100644 --- a/tests/sync_object.rs +++ b/tests/sync_object.rs @@ -1,6 +1,15 @@ #[allow(dead_code)] fn needs_sync() {} +#[test] +fn event_loop_proxy_send() { + #[allow(dead_code)] + fn is_send() { + // ensures that `winit::EventLoopProxy` implements `Sync` + needs_sync::>(); + } +} + #[test] fn window_sync() { // ensures that `winit::Window` implements `Sync` From f4a002d0dad37f46a9d8c79c36a163e512267027 Mon Sep 17 00:00:00 2001 From: Kirill Chibisov Date: Mon, 19 Feb 2024 08:34:39 +0400 Subject: [PATCH 09/13] Fix warnings with latest nightly --- examples/web_aspect_ratio.rs | 1 - src/platform_impl/ios/ffi.rs | 2 -- src/platform_impl/linux/common/xkb/mod.rs | 1 - src/platform_impl/linux/wayland/event_loop/mod.rs | 1 - src/platform_impl/linux/wayland/window/mod.rs | 1 - src/platform_impl/linux/x11/mod.rs | 2 +- src/platform_impl/macos/observer.rs | 1 - src/platform_impl/web/event_loop/runner.rs | 1 - src/platform_impl/web/web_sys/event.rs | 1 - 9 files changed, 1 insertion(+), 10 deletions(-) diff --git a/examples/web_aspect_ratio.rs b/examples/web_aspect_ratio.rs index da03d1b8a3..6ade931c13 100644 --- a/examples/web_aspect_ratio.rs +++ b/examples/web_aspect_ratio.rs @@ -7,7 +7,6 @@ pub fn main() { #[cfg(web_platform)] mod wasm { use wasm_bindgen::prelude::*; - use wasm_bindgen::JsCast; use web_sys::HtmlCanvasElement; use winit::{ dpi::PhysicalSize, diff --git a/src/platform_impl/ios/ffi.rs b/src/platform_impl/ios/ffi.rs index 1f57265a17..8d2b6f26ae 100644 --- a/src/platform_impl/ios/ffi.rs +++ b/src/platform_impl/ios/ffi.rs @@ -1,7 +1,5 @@ #![allow(non_camel_case_types, non_snake_case, non_upper_case_globals)] -use std::convert::TryInto; - use icrate::Foundation::{NSInteger, NSUInteger}; use objc2::encode::{Encode, Encoding}; diff --git a/src/platform_impl/linux/common/xkb/mod.rs b/src/platform_impl/linux/common/xkb/mod.rs index 00696c3f7b..a861b5d6c8 100644 --- a/src/platform_impl/linux/common/xkb/mod.rs +++ b/src/platform_impl/linux/common/xkb/mod.rs @@ -1,4 +1,3 @@ -use std::convert::TryInto; use std::ops::Deref; use std::os::raw::c_char; use std::ptr::{self, NonNull}; diff --git a/src/platform_impl/linux/wayland/event_loop/mod.rs b/src/platform_impl/linux/wayland/event_loop/mod.rs index a41e7add4c..380c910d39 100644 --- a/src/platform_impl/linux/wayland/event_loop/mod.rs +++ b/src/platform_impl/linux/wayland/event_loop/mod.rs @@ -10,7 +10,6 @@ use std::sync::atomic::Ordering; use std::sync::{Arc, Mutex}; use std::time::{Duration, Instant}; -use sctk::reexports::calloop; use sctk::reexports::calloop::Error as CalloopError; use sctk::reexports::calloop_wayland_source::WaylandSource; use sctk::reexports::client::globals; diff --git a/src/platform_impl/linux/wayland/window/mod.rs b/src/platform_impl/linux/wayland/window/mod.rs index ff0fbbeb43..d698b8dc12 100644 --- a/src/platform_impl/linux/wayland/window/mod.rs +++ b/src/platform_impl/linux/wayland/window/mod.rs @@ -3,7 +3,6 @@ use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, Mutex}; -use sctk::reexports::calloop; use sctk::reexports::client::protocol::wl_display::WlDisplay; use sctk::reexports::client::protocol::wl_surface::WlSurface; use sctk::reexports::client::Proxy; diff --git a/src/platform_impl/linux/x11/mod.rs b/src/platform_impl/linux/x11/mod.rs index 18e4e78602..4e97d10b7f 100644 --- a/src/platform_impl/linux/x11/mod.rs +++ b/src/platform_impl/linux/x11/mod.rs @@ -17,7 +17,7 @@ use std::{ptr, slice, str}; use calloop::generic::Generic; use calloop::EventLoop as Loop; use calloop::{ping::Ping, Readiness}; -use libc::{self, setlocale, LC_CTYPE}; +use libc::{setlocale, LC_CTYPE}; use log::warn; use x11rb::connection::RequestConnection; diff --git a/src/platform_impl/macos/observer.rs b/src/platform_impl/macos/observer.rs index 1dd5ff2e36..3317595fd5 100644 --- a/src/platform_impl/macos/observer.rs +++ b/src/platform_impl/macos/observer.rs @@ -1,5 +1,4 @@ use std::{ - self, ffi::c_void, panic::{AssertUnwindSafe, UnwindSafe}, ptr, diff --git a/src/platform_impl/web/event_loop/runner.rs b/src/platform_impl/web/event_loop/runner.rs index f7932ff76e..860e9b8449 100644 --- a/src/platform_impl/web/event_loop/runner.rs +++ b/src/platform_impl/web/event_loop/runner.rs @@ -15,7 +15,6 @@ use crate::window::WindowId; use std::{ cell::{Cell, RefCell}, - clone::Clone, collections::{HashSet, VecDeque}, iter, ops::Deref, diff --git a/src/platform_impl/web/web_sys/event.rs b/src/platform_impl/web/web_sys/event.rs index 86ebd06ac5..084acfc728 100644 --- a/src/platform_impl/web/web_sys/event.rs +++ b/src/platform_impl/web/web_sys/event.rs @@ -4,7 +4,6 @@ use crate::keyboard::{Key, KeyLocation, ModifiersState, NamedKey, PhysicalKey}; use smol_str::SmolStr; use std::cell::OnceCell; -use std::convert::TryInto; use wasm_bindgen::prelude::wasm_bindgen; use wasm_bindgen::{JsCast, JsValue}; use web_sys::{KeyboardEvent, MouseEvent, PointerEvent, WheelEvent}; From af9158850512f1a404fa254a6a6a431ac51bac51 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Mon, 19 Feb 2024 11:58:44 +0700 Subject: [PATCH 10/13] Fix various typos Mainly fix typos in comments, but also some minor code changes: * Rename `apply_on_poiner` to `apply_on_pointer`. * Rename `ImeState::Commited` to `ImeState::Committed` * Correct `cfg_attr` usage: `wayland_platfrom` -> `wayland_platform`. --- CHANGELOG.md | 16 +++++----- examples/control_flow.rs | 2 +- examples/fullscreen.rs | 2 +- examples/handling_close.rs | 2 +- examples/multithreaded.rs | 2 +- examples/window_debug.rs | 4 +-- src/dpi.rs | 2 +- src/event.rs | 8 ++--- src/event_loop.rs | 2 +- src/keyboard.rs | 10 +++--- src/platform/scancode.rs | 2 +- src/platform/wayland.rs | 2 +- src/platform/x11.rs | 4 +-- src/platform_impl/ios/app_state.rs | 2 +- src/platform_impl/ios/event_loop.rs | 2 +- src/platform_impl/ios/mod.rs | 2 +- src/platform_impl/linux/wayland/seat/mod.rs | 2 +- .../linux/wayland/seat/pointer/mod.rs | 2 +- .../linux/wayland/seat/text_input/mod.rs | 2 +- src/platform_impl/linux/wayland/state.rs | 6 ++-- .../linux/wayland/window/state.rs | 32 +++++++++---------- .../linux/x11/event_processor.rs | 2 +- src/platform_impl/linux/x11/ime/context.rs | 2 +- .../linux/x11/ime/input_method.rs | 2 +- .../linux/x11/util/window_property.rs | 2 +- src/platform_impl/macos/app_delegate.rs | 4 +-- src/platform_impl/macos/event_loop.rs | 4 +-- src/platform_impl/macos/menu.rs | 4 +-- src/platform_impl/macos/view.rs | 18 +++++------ src/platform_impl/macos/window_delegate.rs | 6 ++-- src/platform_impl/orbital/window.rs | 2 +- src/platform_impl/windows/drop_handler.rs | 4 +-- src/platform_impl/windows/event_loop.rs | 10 +++--- src/platform_impl/windows/keyboard.rs | 4 +-- src/platform_impl/windows/keyboard_layout.rs | 8 ++--- src/window.rs | 6 ++-- 36 files changed, 93 insertions(+), 93 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e12b62c5a..289c921d17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -133,7 +133,7 @@ Unreleased` header. # 0.29.3 - On Wayland, apply correct scale to `PhysicalSize` passed in `WindowBuilder::with_inner_size` when possible. -- On Wayland, fix `RedrawRequsted` being always sent without decorations and `sctk-adwaita` feature. +- On Wayland, fix `RedrawRequested` being always sent without decorations and `sctk-adwaita` feature. - On Wayland, ignore resize requests when the window is fully tiled. - On Wayland, use `configure_bounds` to constrain `with_inner_size` when compositor wants users to pick size. - On Windows, fix deadlock when accessing the state during `Cursor{Enter,Leave}`. @@ -385,7 +385,7 @@ Unreleased` header. - **Breaking:**: Removed deprecated method `platform::unix::WindowExtUnix::is_ready`. - Removed `parking_lot` dependency. - **Breaking:** On macOS, add support for two-finger touchpad magnification and rotation gestures with new events `WindowEvent::TouchpadMagnify` and `WindowEvent::TouchpadRotate`. Also add support for touchpad smart-magnification gesture with a new event `WindowEvent::SmartMagnify`. -- **Breaking:** On web, the `WindowBuilderExtWebSys::with_prevent_default` setting (enabled by default), now additionally prevents scrolling of the webpage in mobile browsers, previously it only disabled scrolling on desktop. +- **Breaking:** On Web, the `WindowBuilderExtWebSys::with_prevent_default` setting (enabled by default), now additionally prevents scrolling of the webpage in mobile browsers, previously it only disabled scrolling on desktop. - On Wayland, `wayland-csd-adwaita` now uses `ab_glyph` instead of `crossfont` to render the title for decorations. - On Wayland, a new `wayland-csd-adwaita-crossfont` feature was added to use `crossfont` instead of `ab_glyph` for decorations. - On Wayland, if not otherwise specified use upstream automatic CSD theme selection. @@ -405,7 +405,7 @@ Unreleased` header. - Added `Window::set_transparent` to provide a hint about transparency of the window on Wayland and macOS. - On macOS, fix the mouse buttons other than left/right/middle being reported as middle. - On Wayland, support fractional scaling via the wp-fractional-scale protocol. -- On web, fix removal of mouse event listeners from the global object upon window distruction. +- On Web, fix removal of mouse event listeners from the global object upon window destruction. - Add WindowAttributes getter to WindowBuilder to allow introspection of default values. - Added `Window::set_ime_purpose` for setting the IME purpose, currently implemented on Wayland only. @@ -511,7 +511,7 @@ Unreleased` header. - On Web, add `with_prevent_default` and `with_focusable` to `WindowBuilderExtWebSys` to control whether events should be propagated. - On Windows, fix focus events being sent to inactive windows. - **Breaking**, update `raw-window-handle` to `v0.5` and implement `HasRawDisplayHandle` for `Window` and `EventLoopWindowTarget`. -- On X11, add function `register_xlib_error_hook` into `winit::platform::unix` to subscribe for errors comming from Xlib. +- On X11, add function `register_xlib_error_hook` into `winit::platform::unix` to subscribe for errors coming from Xlib. - On Android, upgrade `ndk` and `ndk-glue` dependencies to the recently released `0.7.0`. - All platforms can now be relied on to emit a `Resumed` event. Applications are recommended to lazily initialize graphics state and windows on first resume for portability. - **Breaking:**: Reverse horizontal scrolling sign in `MouseScrollDelta` to match the direction of vertical scrolling. A positive X value now means moving the content to the right. The meaning of vertical scrolling stays the same: a positive Y value means moving the content down. @@ -810,7 +810,7 @@ Unreleased` header. - On Windows, fix handling of surrogate pairs when dispatching `ReceivedCharacter`. - On macOS 10.15, fix freeze upon exiting exclusive fullscreen mode. - On iOS, fix panic upon closing the app. -- On X11, allow setting mulitple `XWindowType`s. +- On X11, allow setting multiple `XWindowType`s. - On iOS, fix null window on initial `HiDpiFactorChanged` event. - On Windows, fix fullscreen window shrinking upon getting restored to a normal window. - On macOS, fix events not being emitted during modal loops, such as when windows are being resized @@ -963,7 +963,7 @@ and `WindowEvent::HoveredFile`. - On Windows, hiding the cursor no longer hides the cursor for all Winit windows - just the one `hide_cursor` was called on. - On Windows, cursor grabs used to get perpetually canceled when the grabbing window lost focus. Now, cursor grabs automatically get re-initialized when the window regains focus and the mouse moves over the client area. - On Windows, only vertical mouse wheel events were handled. Now, horizontal mouse wheel events are also handled. -- On Windows, ignore the AltGr key when populating the `ModifersState` type. +- On Windows, ignore the AltGr key when populating the `ModifiersState` type. # Version 0.18.1 (2018-12-30) @@ -1243,7 +1243,7 @@ _Yanked_ # Version 0.8.2 (2017-09-28) -- Uniformize keyboard scancode values accross Wayland and X11 (#297). +- Uniformize keyboard scancode values across Wayland and X11 (#297). - Internal rework of the wayland event loop - Added method `os::linux::WindowExt::is_ready` @@ -1257,7 +1257,7 @@ _Yanked_ - Added `Window::set_maximized`, `WindowAttributes::maximized` and `WindowBuilder::with_maximized`. - Added `Window::set_fullscreen`. - Changed `with_fullscreen` to take a `Option` instead of a `MonitorId`. -- Removed `MonitorId::get_native_identifer()` in favor of platform-specific traits in the `os` +- Removed `MonitorId::get_native_identifier()` in favor of platform-specific traits in the `os` module. - Changed `get_available_monitors()` and `get_primary_monitor()` to be methods of `EventsLoop` instead of stand-alone methods. diff --git a/examples/control_flow.rs b/examples/control_flow.rs index 1154b33f6c..cff46a003b 100644 --- a/examples/control_flow.rs +++ b/examples/control_flow.rs @@ -70,7 +70,7 @@ fn main() -> Result<(), impl std::error::Error> { }, .. } => match key.as_ref() { - // WARNING: Consider using `key_without_modifers()` if available on your platform. + // WARNING: Consider using `key_without_modifiers()` if available on your platform. // See the `key_binding` example Key::Character("1") => { mode = Mode::Wait; diff --git a/examples/fullscreen.rs b/examples/fullscreen.rs index 979b216f7d..022433237e 100644 --- a/examples/fullscreen.rs +++ b/examples/fullscreen.rs @@ -66,7 +66,7 @@ fn main() -> Result<(), impl std::error::Error> { .. } => match key { Key::Named(NamedKey::Escape) => elwt.exit(), - // WARNING: Consider using `key_without_modifers()` if available on your platform. + // WARNING: Consider using `key_without_modifiers()` if available on your platform. // See the `key_binding` example Key::Character(ch) => match ch.to_lowercase().as_str() { "f" | "b" if window.fullscreen().is_some() => { diff --git a/examples/handling_close.rs b/examples/handling_close.rs index da15d65752..f44d6dee58 100644 --- a/examples/handling_close.rs +++ b/examples/handling_close.rs @@ -51,7 +51,7 @@ fn main() -> Result<(), impl std::error::Error> { }, .. } => { - // WARNING: Consider using `key_without_modifers()` if available on your platform. + // WARNING: Consider using `key_without_modifiers()` if available on your platform. // See the `key_binding` example match key.as_ref() { Key::Character("y") => { diff --git a/examples/multithreaded.rs b/examples/multithreaded.rs index e38bb53ddd..cda3548220 100644 --- a/examples/multithreaded.rs +++ b/examples/multithreaded.rs @@ -78,7 +78,7 @@ fn main() -> Result<(), impl std::error::Error> { } println!("Picking video mode: {}", video_modes[video_mode_id]); } - // WARNING: Consider using `key_without_modifers()` if available on your platform. + // WARNING: Consider using `key_without_modifiers()` if available on your platform. // See the `key_binding` example Key::Character(ch) => match ch.to_lowercase().as_str() { "1" => window.set_window_level(WindowLevel::AlwaysOnTop), diff --git a/examples/window_debug.rs b/examples/window_debug.rs index 3f219d0581..74c5e8ff5c 100644 --- a/examples/window_debug.rs +++ b/examples/window_debug.rs @@ -27,7 +27,7 @@ fn main() -> Result<(), impl std::error::Error> { eprintln!("debugging keys:"); eprintln!(" (E) Enter exclusive fullscreen"); eprintln!(" (F) Toggle borderless fullscreen"); - eprintln!(" (P) Toggle borderless fullscreen on system's preffered monitor"); + eprintln!(" (P) Toggle borderless fullscreen on system's preferred monitor"); eprintln!(" (M) Toggle minimized"); eprintln!(" (Q) Quit event loop"); eprintln!(" (V) Toggle visibility"); @@ -76,7 +76,7 @@ fn main() -> Result<(), impl std::error::Error> { }, .. } => match key_str.as_ref() { - // WARNING: Consider using `key_without_modifers()` if available on your platform. + // WARNING: Consider using `key_without_modifiers()` if available on your platform. // See the `key_binding` example "e" => { fn area(size: PhysicalSize) -> u32 { diff --git a/src/dpi.rs b/src/dpi.rs index 3c99251a75..3d7b7b2395 100644 --- a/src/dpi.rs +++ b/src/dpi.rs @@ -168,7 +168,7 @@ pub fn validate_scale_factor(scale_factor: f64) -> bool { /// A position represented in logical pixels. /// /// The position is stored as floats, so please be careful. Casting floats to integers truncates the -/// fractional part, which can cause noticable issues. To help with that, an `Into<(i32, i32)>` +/// fractional part, which can cause noticeable issues. To help with that, an `Into<(i32, i32)>` /// implementation is provided which does the rounding for you. #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Default, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] diff --git a/src/event.rs b/src/event.rs index 4da049c463..fbd55610d7 100644 --- a/src/event.rs +++ b/src/event.rs @@ -309,7 +309,7 @@ pub enum WindowEvent { /// The activation token was delivered back and now could be used. /// #[cfg_attr( - not(any(x11_platform, wayland_platfrom)), + not(any(x11_platform, wayland_platform)), allow(rustdoc::broken_intra_doc_links) )] /// Delivered in response to [`request_activation_token`]. @@ -473,7 +473,7 @@ pub enum WindowEvent { /// The event is general enough that its generating gesture is allowed to vary /// across platforms. It could also be generated by another device. /// - /// Unfortunatly, neither [Windows](https://support.microsoft.com/en-us/windows/touch-gestures-for-windows-a9d28305-4818-a5df-4e2b-e5590f850741) + /// Unfortunately, neither [Windows](https://support.microsoft.com/en-us/windows/touch-gestures-for-windows-a9d28305-4818-a5df-4e2b-e5590f850741) /// nor [Wayland](https://wayland.freedesktop.org/libinput/doc/latest/gestures.html) /// support this gesture or any other gesture with the same effect. /// @@ -1112,7 +1112,7 @@ pub enum MouseScrollDelta { PixelDelta(PhysicalPosition), } -/// Handle to synchroniously change the size of the window from the +/// Handle to synchronously change the size of the window from the /// [`WindowEvent`]. #[derive(Debug, Clone)] pub struct InnerSizeWriter { @@ -1125,7 +1125,7 @@ impl InnerSizeWriter { Self { new_inner_size } } - /// Try to request inner size which will be set synchroniously on the window. + /// Try to request inner size which will be set synchronously on the window. pub fn request_inner_size( &mut self, new_inner_size: PhysicalSize, diff --git a/src/event_loop.rs b/src/event_loop.rs index b8dd1a2140..a4b5ecec12 100644 --- a/src/event_loop.rs +++ b/src/event_loop.rs @@ -513,7 +513,7 @@ pub enum DeviceEvents { /// This could be used to identify the async request once it's done /// and a specific action must be taken. /// -/// One of the handling scenarious could be to maintain a working list +/// One of the handling scenarios could be to maintain a working list /// containing [`AsyncRequestSerial`] and some closure associated with it. /// Then once event is arriving the working list is being traversed and a job /// executed and removed from the list. diff --git a/src/keyboard.rs b/src/keyboard.rs index 5f5ba50b58..4fc9fdb027 100644 --- a/src/keyboard.rs +++ b/src/keyboard.rs @@ -20,7 +20,7 @@ // the W3C short notice apply to the `Key` and `KeyCode` enums and their variants and the // documentation attached to their variants. -// --------- BEGGINING OF W3C LICENSE -------------------------------------------------------------- +// --------- BEGINNING OF W3C LICENSE -------------------------------------------------------------- // // License // @@ -55,7 +55,7 @@ // // --------- END OF W3C LICENSE -------------------------------------------------------------------- -// --------- BEGGINING OF W3C SHORT NOTICE --------------------------------------------------------- +// --------- BEGINNING OF W3C SHORT NOTICE --------------------------------------------------------- // // winit: https://github.com/rust-windowing/winit // @@ -744,7 +744,7 @@ pub enum KeyCode { /// - The `Super` variant here, is named `Meta` in the aforementioned specification. (There's /// another key which the specification calls `Super`. That does not exist here.) /// - The `Space` variant here, can be identified by the character it generates in the -/// specificaiton. +/// specification. /// /// [`KeyboardEvent.key`]: https://w3c.github.io/uievents-key/ #[non_exhaustive] @@ -914,7 +914,7 @@ pub enum NamedKey { Standby, /// The WakeUp key. (`KEYCODE_WAKEUP`) WakeUp, - /// Initate the multi-candidate mode. + /// Initiate the multi-candidate mode. AllCandidates, Alphanumeric, /// Initiate the Code Input mode to allow characters to be entered by @@ -1459,7 +1459,7 @@ pub enum NamedKey { /// This is a superset of the UI Events Specification's [`KeyboardEvent.key`] with /// additions: /// - All simple variants are wrapped under the `Named` variant -/// - The `Unidentified` variant here, can still identifiy a key through it's `NativeKeyCode`. +/// - The `Unidentified` variant here, can still identify a key through it's `NativeKeyCode`. /// - The `Dead` variant here, can specify the character which is inserted when pressing the /// dead-key twice. /// diff --git a/src/platform/scancode.rs b/src/platform/scancode.rs index 35d101da5e..c175e5b8bf 100644 --- a/src/platform/scancode.rs +++ b/src/platform/scancode.rs @@ -9,7 +9,7 @@ use crate::keyboard::{KeyCode, PhysicalKey}; pub trait PhysicalKeyExtScancode { /// The raw value of the platform-specific physical key identifier. /// - /// Returns `Some(key_id)` if the conversion was succesful; returns `None` otherwise. + /// Returns `Some(key_id)` if the conversion was successful; returns `None` otherwise. /// /// ## Platform-specific /// - **Windows:** A 16bit extended scancode diff --git a/src/platform/wayland.rs b/src/platform/wayland.rs index e8f3fd5d90..985e0e1de2 100644 --- a/src/platform/wayland.rs +++ b/src/platform/wayland.rs @@ -55,7 +55,7 @@ pub trait WindowBuilderExtWayland { /// Build window with the given name. /// /// The `general` name sets an application ID, which should match the `.desktop` - /// file destributed with your program. The `instance` is a `no-op`. + /// file distributed with your program. The `instance` is a `no-op`. /// /// For details about application ID conventions, see the /// [Desktop Entry Spec](https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#desktop-file-id) diff --git a/src/platform/x11.rs b/src/platform/x11.rs index 7dc3e8cde7..ee2375d712 100644 --- a/src/platform/x11.rs +++ b/src/platform/x11.rs @@ -61,7 +61,7 @@ pub enum WindowType { pub type XlibErrorHook = Box bool + Send + Sync>; -/// A unique identifer for an X11 visual. +/// A unique identifier for an X11 visual. pub type XVisualID = u32; /// A unique identifier for an X11 window. @@ -69,7 +69,7 @@ pub type XWindow = u32; /// Hook to winit's xlib error handling callback. /// -/// This method is provided as a safe way to handle the errors comming from X11 +/// This method is provided as a safe way to handle the errors coming from X11 /// when using xlib in external crates, like glutin for GLX access. Trying to /// handle errors by speculating with `XSetErrorHandler` is [`unsafe`]. /// diff --git a/src/platform_impl/ios/app_state.rs b/src/platform_impl/ios/app_state.rs index eac89365f8..cb1a9202ef 100644 --- a/src/platform_impl/ios/app_state.rs +++ b/src/platform_impl/ios/app_state.rs @@ -551,7 +551,7 @@ pub fn did_finish_launching(mtm: MainThreadMarker) { // // relevant iOS log: // ``` - // [ApplicationLifecycle] Windows were created before application initialzation + // [ApplicationLifecycle] Windows were created before application initialization // completed. This may result in incorrect visual appearance. // ``` let screen = window.screen(); diff --git a/src/platform_impl/ios/event_loop.rs b/src/platform_impl/ios/event_loop.rs index 1df992ccfe..fe635545b2 100644 --- a/src/platform_impl/ios/event_loop.rs +++ b/src/platform_impl/ios/event_loop.rs @@ -76,7 +76,7 @@ impl EventLoopWindowTarget { pub(crate) fn exit(&self) { // https://developer.apple.com/library/archive/qa/qa1561/_index.html - // it is not possible to quit an iOS app gracefully and programatically + // it is not possible to quit an iOS app gracefully and programmatically log::warn!("`ControlFlow::Exit` ignored on iOS"); } diff --git a/src/platform_impl/ios/mod.rs b/src/platform_impl/ios/mod.rs index 7f8c23fc24..aefad6f749 100644 --- a/src/platform_impl/ios/mod.rs +++ b/src/platform_impl/ios/mod.rs @@ -85,7 +85,7 @@ pub(crate) use crate::platform_impl::Fullscreen; /// There is no way to detect which device that performed a certain event in /// UIKit (i.e. you can't differentiate between different external keyboards, -/// or wether it was the main touchscreen, assistive technologies, or some +/// or whether it was the main touchscreen, assistive technologies, or some /// other pointer device that caused a touch event). #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct DeviceId; diff --git a/src/platform_impl/linux/wayland/seat/mod.rs b/src/platform_impl/linux/wayland/seat/mod.rs index 2e2fa43874..6ddda26bea 100644 --- a/src/platform_impl/linux/wayland/seat/mod.rs +++ b/src/platform_impl/linux/wayland/seat/mod.rs @@ -54,7 +54,7 @@ pub struct WinitSeatState { /// The current modifiers state on the seat. modifiers: ModifiersState, - /// Wether we have pending modifiers. + /// Whether we have pending modifiers. modifiers_pending: bool, } diff --git a/src/platform_impl/linux/wayland/seat/pointer/mod.rs b/src/platform_impl/linux/wayland/seat/pointer/mod.rs index 3b62bae10d..e9dee8f21f 100644 --- a/src/platform_impl/linux/wayland/seat/pointer/mod.rs +++ b/src/platform_impl/linux/wayland/seat/pointer/mod.rs @@ -196,7 +196,7 @@ impl PointerHandler for WinitState { TouchPhase::Ended } else { match pointer_data.phase { - // Descrete scroll only results in moved events. + // Discrete scroll only results in moved events. _ if has_discrete_scroll => TouchPhase::Moved, TouchPhase::Started | TouchPhase::Moved => TouchPhase::Moved, _ => TouchPhase::Started, diff --git a/src/platform_impl/linux/wayland/seat/text_input/mod.rs b/src/platform_impl/linux/wayland/seat/text_input/mod.rs index cff18dffeb..69cdb4b985 100644 --- a/src/platform_impl/linux/wayland/seat/text_input/mod.rs +++ b/src/platform_impl/linux/wayland/seat/text_input/mod.rs @@ -94,7 +94,7 @@ impl Dispatch for TextInputState { let window_id = wayland::make_wid(&surface); // XXX this check is essential, because `leave` could have a - // refence to nil surface... + // reference to nil surface... let mut window = match windows.get(&window_id) { Some(window) => window.lock().unwrap(), None => return, diff --git a/src/platform_impl/linux/wayland/state.rs b/src/platform_impl/linux/wayland/state.rs index add461d727..cf805c1b60 100644 --- a/src/platform_impl/linux/wayland/state.rs +++ b/src/platform_impl/linux/wayland/state.rs @@ -60,7 +60,7 @@ pub struct WinitState { /// The pool where custom cursors are allocated. pub custom_cursor_pool: Arc>, - /// The XDG shell that is used for widnows. + /// The XDG shell that is used for windows. pub xdg_shell: XdgShell, /// The currently present windows. @@ -72,7 +72,7 @@ pub struct WinitState { /// The events that were generated directly from the window. pub window_events_sink: Arc>, - /// The update for the `windows` comming from the compositor. + /// The update for the `windows` coming from the compositor. pub window_compositor_updates: Vec, /// Currently handled seats. @@ -395,7 +395,7 @@ impl ProvidesRegistryState for WinitState { sctk::registry_handlers![OutputState, SeatState]; } -// The window update comming from the compositor. +// The window update coming from the compositor. #[derive(Debug, Clone, Copy)] pub struct WindowCompositorUpdate { /// The id of the window this updates belongs to. diff --git a/src/platform_impl/linux/wayland/window/state.rs b/src/platform_impl/linux/wayland/window/state.rs index 0dfd656369..50d81cf2d5 100644 --- a/src/platform_impl/linux/wayland/window/state.rs +++ b/src/platform_impl/linux/wayland/window/state.rs @@ -118,7 +118,7 @@ pub struct WindowState { selected_cursor: SelectedCursor, - /// Wether the cursor is visible. + /// Whether the cursor is visible. pub cursor_visible: bool, /// Pointer constraints to lock/confine pointer. @@ -127,7 +127,7 @@ pub struct WindowState { /// Queue handle. pub queue_handle: QueueHandle, - /// Theme varaint. + /// Theme variant. theme: Option, // NOTE: we can't use simple counter, since it's racy when seat getting destroyed and new @@ -247,7 +247,7 @@ impl WindowState { } /// Apply closure on the given pointer. - fn apply_on_poiner, &WinitPointerData)>( + fn apply_on_pointer, &WinitPointerData)>( &self, callback: F, ) { @@ -450,7 +450,7 @@ impl WindowState { let xdg_toplevel = window.xdg_toplevel(); // TODO(kchibisov) handle touch serials. - self.apply_on_poiner(|_, data| { + self.apply_on_pointer(|_, data| { let serial = data.latest_button_serial(); let seat = data.seat(); xdg_toplevel.resize(seat, serial, direction.into()); @@ -467,7 +467,7 @@ impl WindowState { if let SurfaceRoleState::Toplevel { window, .. } = &self.surface_role { let xdg_toplevel = window.xdg_toplevel(); // TODO(kchibisov) handle touch serials. - self.apply_on_poiner(|_, data| { + self.apply_on_pointer(|_, data| { let serial = data.latest_button_serial(); let seat = data.seat(); xdg_toplevel._move(seat, serial); @@ -843,7 +843,7 @@ impl WindowState { return; } - self.apply_on_poiner(|pointer, _| { + self.apply_on_pointer(|pointer, _| { if pointer.set_cursor(&self.connection, cursor_icon).is_err() { warn!("Failed to set cursor to {:?}", cursor_icon); } @@ -878,7 +878,7 @@ impl WindowState { } fn apply_custom_cursor(&self, cursor: &CustomCursor) { - self.apply_on_poiner(|pointer, _| { + self.apply_on_pointer(|pointer, _| { let surface = pointer.surface(); let scale = surface @@ -988,21 +988,21 @@ impl WindowState { match old_mode { CursorGrabMode::None => (), - CursorGrabMode::Confined => self.apply_on_poiner(|_, data| { + CursorGrabMode::Confined => self.apply_on_pointer(|_, data| { data.unconfine_pointer(); }), CursorGrabMode::Locked => { - self.apply_on_poiner(|_, data| data.unlock_pointer()); + self.apply_on_pointer(|_, data| data.unlock_pointer()); } } let surface = self.surface_role.wl_surface(); match mode { - CursorGrabMode::Locked => self.apply_on_poiner(|pointer, data| { + CursorGrabMode::Locked => self.apply_on_pointer(|pointer, data| { let pointer = pointer.pointer(); data.lock_pointer(pointer_constraints, surface, pointer, &self.queue_handle) }), - CursorGrabMode::Confined => self.apply_on_poiner(|pointer, data| { + CursorGrabMode::Confined => self.apply_on_pointer(|pointer, data| { let pointer = pointer.pointer(); data.confine_pointer(pointer_constraints, surface, pointer, &self.queue_handle) }), @@ -1017,7 +1017,7 @@ impl WindowState { pub fn show_window_menu(&self, position: LogicalPosition) { // TODO(kchibisov) handle touch serials. if let SurfaceRoleState::Toplevel { window, .. } = &self.surface_role { - self.apply_on_poiner(|_, data| { + self.apply_on_pointer(|_, data| { let serial = data.latest_button_serial(); let seat = data.seat(); window.show_window_menu(seat, serial, position.into()); @@ -1031,7 +1031,7 @@ impl WindowState { return Err(ExternalError::NotSupported(NotSupportedError::new())); } - // Positon can be set only for locked cursor. + // Position can be set only for locked cursor. if self.cursor_grab_mode.current_grab_mode != CursorGrabMode::Locked { return Err(ExternalError::Os(os_error!( crate::platform_impl::OsError::Misc( @@ -1040,7 +1040,7 @@ impl WindowState { ))); } - self.apply_on_poiner(|_, data| { + self.apply_on_pointer(|_, data| { data.set_locked_cursor_position(position.x, position.y); }); @@ -1205,7 +1205,7 @@ impl WindowState { /// Set the window title to a new value. /// - /// This will autmatically truncate the title to something meaningfull. + /// This will automatically truncate the title to something meaningful. pub fn set_title(&mut self, mut title: String) { // Truncate the title to at most 1024 bytes, so that it does not blow up the protocol // messages @@ -1320,7 +1320,7 @@ impl GrabState { /// The state of the frame callback. #[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] pub enum FrameCallbackState { - /// No frame callback was requsted. + /// No frame callback was requested. #[default] None, /// The frame callback was requested, but not yet arrived, the redraw events are throttled. diff --git a/src/platform_impl/linux/x11/event_processor.rs b/src/platform_impl/linux/x11/event_processor.rs index 2f01b93b96..e9bab0d798 100644 --- a/src/platform_impl/linux/x11/event_processor.rs +++ b/src/platform_impl/linux/x11/event_processor.rs @@ -1692,7 +1692,7 @@ impl EventProcessor { /// Send modifiers for the active window. /// - /// The event won't be send when the `modifiers` match the previosly `sent` modifiers value. + /// The event won't be sent when the `modifiers` match the previously `sent` modifiers value. fn send_modifiers)>( &self, modifiers: ModifiersState, diff --git a/src/platform_impl/linux/x11/ime/context.rs b/src/platform_impl/linux/x11/ime/context.rs index e04f74b1f6..1214a1a7e2 100644 --- a/src/platform_impl/linux/x11/ime/context.rs +++ b/src/platform_impl/linux/x11/ime/context.rs @@ -195,7 +195,7 @@ pub struct ImeContext { pub(crate) ic: ffi::XIC, pub(crate) ic_spot: ffi::XPoint, pub(crate) style: Style, - // Since the data is passed shared between X11 XIM callbacks, but couldn't be direclty free from + // Since the data is passed shared between X11 XIM callbacks, but couldn't be directly free from // there we keep the pointer to automatically deallocate it. _client_data: Box, } diff --git a/src/platform_impl/linux/x11/ime/input_method.rs b/src/platform_impl/linux/x11/ime/input_method.rs index faad41effb..87bf708f49 100644 --- a/src/platform_impl/linux/x11/ime/input_method.rs +++ b/src/platform_impl/linux/x11/ime/input_method.rs @@ -170,7 +170,7 @@ impl From for GetXimServersError { } } -// The root window has a property named XIM_SERVERS, which contains a list of atoms represeting +// The root window has a property named XIM_SERVERS, which contains a list of atoms representing // the availabile XIM servers. For instance, if you're using ibus, it would contain an atom named // "@server=ibus". It's possible for this property to contain multiple atoms, though presumably // rare. Note that we replace "@server=" with "@im=" in order to match the format of locale diff --git a/src/platform_impl/linux/x11/util/window_property.rs b/src/platform_impl/linux/x11/util/window_property.rs index 2a2ed52347..1f6a6b4c55 100644 --- a/src/platform_impl/linux/x11/util/window_property.rs +++ b/src/platform_impl/linux/x11/util/window_property.rs @@ -73,7 +73,7 @@ impl XConnection { new_value .len() .try_into() - .expect("too many items for propery"), + .expect("too many items for property"), bytemuck::cast_slice::(new_value), ) .map_err(Into::into) diff --git a/src/platform_impl/macos/app_delegate.rs b/src/platform_impl/macos/app_delegate.rs index ee3ac878d3..226cd6212d 100644 --- a/src/platform_impl/macos/app_delegate.rs +++ b/src/platform_impl/macos/app_delegate.rs @@ -177,7 +177,7 @@ impl ApplicationDelegate { } /// If `pump_events` is called to progress the event loop then we - /// bootstrap the event loop via `-[NSAppplication run]` but will use + /// bootstrap the event loop via `-[NSApplication run]` but will use /// `CFRunLoopRunInMode` for subsequent calls to `pump_events`. pub fn set_stop_on_launch(&self) { self.ivars().stop_on_launch.set(true); @@ -538,7 +538,7 @@ fn window_activation_hack(app: &NSApplication) { // TODO: Proper ordering of the windows app.windows().into_iter().for_each(|window| { // Call `makeKeyAndOrderFront` if it was called on the window in `WinitWindow::new` - // This way we preserve the user's desired initial visiblity status + // This way we preserve the user's desired initial visibility status // TODO: Also filter on the type/"level" of the window, and maybe other things? if window.isVisible() { log::trace!("Activating visible window"); diff --git a/src/platform_impl/macos/event_loop.rs b/src/platform_impl/macos/event_loop.rs index 59c6e2b403..bccb048650 100644 --- a/src/platform_impl/macos/event_loop.rs +++ b/src/platform_impl/macos/event_loop.rs @@ -169,8 +169,8 @@ fn map_user_event( pub struct EventLoop { /// Store a reference to the application for convenience. /// - /// We intentially don't store `WinitApplication` since we want to have - /// the possiblity of swapping that out at some point. + /// We intentionally don't store `WinitApplication` since we want to have + /// the possibility of swapping that out at some point. app: Id, /// The application delegate that we've registered. /// diff --git a/src/platform_impl/macos/menu.rs b/src/platform_impl/macos/menu.rs index 2e65abc549..6d6142d9be 100644 --- a/src/platform_impl/macos/menu.rs +++ b/src/platform_impl/macos/menu.rs @@ -35,7 +35,7 @@ pub fn initialize(app: &NSApplication) { let services_item = menu_item(mtm, ns_string!("Services"), None, None); services_item.setSubmenu(Some(&services_menu)); - // Seperator menu item + // Separator menu item let sep_first = NSMenuItem::separatorItem(mtm); // Hide application menu item @@ -71,7 +71,7 @@ pub fn initialize(app: &NSApplication) { None, ); - // Seperator menu item + // Separator menu item let sep = NSMenuItem::separatorItem(mtm); // Quit application menu item diff --git a/src/platform_impl/macos/view.rs b/src/platform_impl/macos/view.rs index a202e44f65..2ca8cf24c4 100644 --- a/src/platform_impl/macos/view.rs +++ b/src/platform_impl/macos/view.rs @@ -65,8 +65,8 @@ enum ImeState { /// The IME is in preedit. Preedit, - /// The text was just commited, so the next input from the keyboard must be ignored. - Commited, + /// The text was just committed, so the next input from the keyboard must be ignored. + Committed, } bitflags::bitflags! { @@ -397,7 +397,7 @@ declare_class!( if unsafe { self.hasMarkedText() } && self.is_ime_enabled() && !is_control { self.queue_event(WindowEvent::Ime(Ime::Preedit(String::new(), None))); self.queue_event(WindowEvent::Ime(Ime::Commit(string))); - self.ivars().ime_state.set(ImeState::Commited); + self.ivars().ime_state.set(ImeState::Committed); } } @@ -406,10 +406,10 @@ declare_class!( #[method(doCommandBySelector:)] fn do_command_by_selector(&self, _command: Sel) { trace_scope!("doCommandBySelector:"); - // We shouldn't forward any character from just commited text, since we'll end up sending + // We shouldn't forward any character from just committed text, since we'll end up sending // it twice with some IMEs like Korean one. We'll also always send `Enter` in that case, // which is not desired given it was used to confirm IME input. - if self.ivars().ime_state.get() == ImeState::Commited { + if self.ivars().ime_state.get() == ImeState::Committed { return; } @@ -452,8 +452,8 @@ declare_class!( let events_for_nsview = NSArray::from_slice(&[&*event]); unsafe { self.interpretKeyEvents(&events_for_nsview) }; - // If the text was commited we must treat the next keyboard event as IME related. - if self.ivars().ime_state.get() == ImeState::Commited { + // If the text was committed we must treat the next keyboard event as IME related. + if self.ivars().ime_state.get() == ImeState::Committed { // Remove any marked text, so normal input can continue. *self.ivars().marked_text.borrow_mut() = NSMutableAttributedString::new(); } @@ -462,7 +462,7 @@ declare_class!( self.update_modifiers(&event, false); let had_ime_input = match self.ivars().ime_state.get() { - ImeState::Commited => { + ImeState::Committed => { // Allow normal input after the commit. self.ivars().ime_state.set(ImeState::Ground); true @@ -924,7 +924,7 @@ impl WinitView { let mut event = create_key_event(ns_event, false, false, Some(physical_key)); let key = code_to_key(physical_key, scancode); - // Ignore processing of unkown modifiers because we can't determine whether + // Ignore processing of unknown modifiers because we can't determine whether // it was pressed or release reliably. let Some(event_modifier) = key_to_modifier(&key) else { break 'send_event; diff --git a/src/platform_impl/macos/window_delegate.rs b/src/platform_impl/macos/window_delegate.rs index 118e6da8b0..9a496aee58 100644 --- a/src/platform_impl/macos/window_delegate.rs +++ b/src/platform_impl/macos/window_delegate.rs @@ -300,12 +300,12 @@ declare_class!( /// Invoked when fail to enter fullscreen /// /// When this window launch from a fullscreen app (e.g. launch from VS Code - /// terminal), it creates a new virtual destkop and a transition animation. + /// terminal), it creates a new virtual desktop and a transition animation. /// This animation takes one second and cannot be disable without /// elevated privileges. In this animation time, all toggleFullscreen events /// will be failed. In this implementation, we will try again by using /// performSelector:withObject:afterDelay: until window_did_enter_fullscreen. - /// It should be fine as we only do this at initialzation (i.e with_fullscreen + /// It should be fine as we only do this at initialization (i.e with_fullscreen /// was set). /// /// From Apple doc: @@ -1128,7 +1128,7 @@ impl WindowDelegate { pub(crate) fn is_zoomed(&self) -> bool { // because `isZoomed` doesn't work if the window's borderless, - // we make it resizable temporalily. + // we make it resizable temporarily. let curr_mask = self.window().styleMask(); let required = NSWindowStyleMaskTitled | NSWindowStyleMaskResizable; diff --git a/src/platform_impl/orbital/window.rs b/src/platform_impl/orbital/window.rs index 7f9e7fa4c6..155abea7db 100644 --- a/src/platform_impl/orbital/window.rs +++ b/src/platform_impl/orbital/window.rs @@ -489,7 +489,7 @@ impl Window { pub fn raw_window_handle_rwh_06(&self) -> Result { let handle = rwh_06::OrbitalWindowHandle::new({ let window = self.window_socket.fd as *mut _; - std::ptr::NonNull::new(window).expect("orbital fd shoul never be null") + std::ptr::NonNull::new(window).expect("orbital fd should never be null") }); Ok(rwh_06::RawWindowHandle::Orbital(handle)) } diff --git a/src/platform_impl/windows/drop_handler.rs b/src/platform_impl/windows/drop_handler.rs index ced6629adf..f7a646c219 100644 --- a/src/platform_impl/windows/drop_handler.rs +++ b/src/platform_impl/windows/drop_handler.rs @@ -214,10 +214,10 @@ impl FileDropHandler { } else if get_data_result == DV_E_FORMATETC { // If the dropped item is not a file this error will occur. // In this case it is OK to return without taking further action. - debug!("Error occured while processing dropped/hovered item: item is not a file."); + debug!("Error occurred while processing dropped/hovered item: item is not a file."); None } else { - debug!("Unexpected error occured while processing dropped/hovered item."); + debug!("Unexpected error occurred while processing dropped/hovered item."); None } } diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index 21ca4c0325..7b34ad126c 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -427,7 +427,7 @@ impl EventLoop { // The Windows API has no documented requirement for bitwise // initializing a `MSG` struct (it can be uninitialized memory for the C // API) and there's no API to construct or initialize a `MSG`. This - // is the simplest way avoid unitialized memory in Rust + // is the simplest way avoid uninitialized memory in Rust let mut msg = unsafe { mem::zeroed() }; let msg_status = wait_for_msg(&mut msg, timeout); @@ -475,7 +475,7 @@ impl EventLoop { // The Windows API has no documented requirement for bitwise // initializing a `MSG` struct (it can be uninitialized memory for the C // API) and there's no API to construct or initialize a `MSG`. This - // is the simplest way avoid unitialized memory in Rust + // is the simplest way avoid uninitialized memory in Rust let mut msg = unsafe { mem::zeroed() }; loop { @@ -1102,7 +1102,7 @@ unsafe fn public_window_callback_inner( .unwrap_or_else(|| result = ProcResult::Value(-1)); // I decided to bind the closure to `callback` and pass it to catch_unwind rather than passing - // the closure to catch_unwind directly so that the match body indendation wouldn't change and + // the closure to catch_unwind directly so that the match body indentation wouldn't change and // the git blame and history would be preserved. let callback = || match msg { WM_NCCALCSIZE => { @@ -2381,7 +2381,7 @@ unsafe extern "system" fn thread_event_target_callback( let mut userdata_removed = false; // I decided to bind the closure to `callback` and pass it to catch_unwind rather than passing - // the closure to catch_unwind directly so that the match body indendation wouldn't change and + // the closure to catch_unwind directly so that the match body indentation wouldn't change and // the git blame and history would be preserved. let callback = || match msg { WM_NCDESTROY => { @@ -2391,7 +2391,7 @@ unsafe extern "system" fn thread_event_target_callback( } WM_PAINT => unsafe { ValidateRect(window, ptr::null()); - // Default WM_PAINT behaviour. This makes sure modals and popups are shown immediatly when opening them. + // Default WM_PAINT behaviour. This makes sure modals and popups are shown immediately when opening them. DefWindowProcW(window, msg, wparam, lparam) }, diff --git a/src/platform_impl/windows/keyboard.rs b/src/platform_impl/windows/keyboard.rs index 05d108ead4..00b985b205 100644 --- a/src/platform_impl/windows/keyboard.rs +++ b/src/platform_impl/windows/keyboard.rs @@ -328,7 +328,7 @@ impl KeyEventBuilder { } } - // Alowing nominimal_bool lint because the `is_key_pressed` macro triggers this warning + // Allowing nominimal_bool lint because the `is_key_pressed` macro triggers this warning // and I don't know of another way to resolve it and also keeping the macro #[allow(clippy::nonminimal_bool)] fn synthesize_kbd_state( @@ -737,7 +737,7 @@ fn get_async_kbd_state() -> [u8; 256] { /// On windows, AltGr == Ctrl + Alt /// -/// Due to this equivalence, the system generates a fake Ctrl key-press (and key-release) preceeding +/// Due to this equivalence, the system generates a fake Ctrl key-press (and key-release) preceding /// every AltGr key-press (and key-release). We check if the current event is a Ctrl event and if /// the next event is a right Alt (AltGr) event. If this is the case, the current event must be the /// fake Ctrl event. diff --git a/src/platform_impl/windows/keyboard_layout.rs b/src/platform_impl/windows/keyboard_layout.rs index a0fdb9561e..ac2a3444b6 100644 --- a/src/platform_impl/windows/keyboard_layout.rs +++ b/src/platform_impl/windows/keyboard_layout.rs @@ -192,7 +192,7 @@ pub(crate) struct Layout { /// Maps numpad keys from Windows virtual key to a `Key`. /// - /// This is useful because some numpad keys generate different charcaters based on the locale. + /// This is useful because some numpad keys generate different characters based on the locale. /// For example `VK_DECIMAL` is sometimes "." and sometimes ",". Note: numpad-specific virtual /// keys are only produced by Windows when the NumLock is active. /// @@ -790,7 +790,7 @@ fn vkey_to_non_char_key( //VK_HANGEUL => Key::Named(NamedKey::HangulMode), // Deprecated in favour of VK_HANGUL // VK_HANGUL and VK_KANA are defined as the same constant, therefore - // we use appropriate conditions to differentate between them + // we use appropriate conditions to differentiate between them VK_HANGUL if is_korean => Key::Named(NamedKey::HangulMode), VK_KANA if is_japanese => Key::Named(NamedKey::KanaMode), @@ -798,7 +798,7 @@ fn vkey_to_non_char_key( VK_FINAL => Key::Named(NamedKey::FinalMode), // VK_HANJA and VK_KANJI are defined as the same constant, therefore - // we use appropriate conditions to differentate between them + // we use appropriate conditions to differentiate between them VK_HANJA if is_korean => Key::Named(NamedKey::HanjaMode), VK_KANJI if is_japanese => Key::Named(NamedKey::KanjiMode), @@ -983,7 +983,7 @@ fn vkey_to_non_char_key( // This matches IE and Firefox behaviour according to // https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values // At the time of writing, there is no `NamedKey::Finish` variant as - // Finish is not mentionned at https://w3c.github.io/uievents-key/ + // Finish is not mentioned at https://w3c.github.io/uievents-key/ // Also see: https://github.com/pyfisch/keyboard-types/issues/9 Key::Unidentified(native_code) } diff --git a/src/window.rs b/src/window.rs index 6b6a59205c..b715a3ae40 100644 --- a/src/window.rs +++ b/src/window.rs @@ -662,7 +662,7 @@ impl Window { /// // Notify winit that we're about to submit buffer to the windowing system. /// window.pre_present_notify(); /// - /// // Sumbit buffer to the windowing system. + /// // Submit buffer to the windowing system. /// swap_buffers(); /// ``` /// @@ -796,7 +796,7 @@ impl Window { /// may not be generated. /// /// On platforms where resizing is disallowed by the windowing system, the current - /// inner size is returned immidiatelly, and the user one is ignored. + /// inner size is returned immediately, and the user one is ignored. /// /// When `None` is returned, it means that the request went to the display system, /// and the actual size will be delivered later with the [`WindowEvent::Resized`]. @@ -941,7 +941,7 @@ impl Window { /// Change the window transparency state. /// /// This is just a hint that may not change anything about - /// the window transparency, however doing a missmatch between + /// the window transparency, however doing a mismatch between /// the content of your window and this hint may result in /// visual artifacts. /// From 29a8c56573d6dd04adc296c11ae830d9e534f759 Mon Sep 17 00:00:00 2001 From: jgcodes2020 Date: Mon, 19 Feb 2024 22:19:59 -0500 Subject: [PATCH 11/13] fix subsurface pointer events --- examples/child_window.rs | 1 + .../linux/wayland/seat/pointer/mod.rs | 52 +++++++++++++++---- src/platform_impl/linux/wayland/window/mod.rs | 51 +++++++++--------- .../linux/wayland/window/state.rs | 10 +++- 4 files changed, 78 insertions(+), 36 deletions(-) diff --git a/examples/child_window.rs b/examples/child_window.rs index 4a791286d5..1f932ffc4a 100644 --- a/examples/child_window.rs +++ b/examples/child_window.rs @@ -36,6 +36,7 @@ fn main() -> Result<(), impl std::error::Error> { let child = builder.build(event_loop).unwrap(); let child_id = child.id(); + println!("child ID: {child_id:?}"); children.insert(child_id, child); } diff --git a/src/platform_impl/linux/wayland/seat/pointer/mod.rs b/src/platform_impl/linux/wayland/seat/pointer/mod.rs index e9dee8f21f..52a1ba007d 100644 --- a/src/platform_impl/linux/wayland/seat/pointer/mod.rs +++ b/src/platform_impl/linux/wayland/seat/pointer/mod.rs @@ -44,23 +44,55 @@ impl PointerHandler for WinitState { let device_id = crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland(DeviceId)); - for event in events { + 'processing_events: for event in events { let surface = &event.surface; // The parent surface. let parent_surface = match event.surface.data::() { - Some(data) => data.parent_surface().unwrap_or(surface), + Some(data) => data.parent_surface(), None => continue, }; - let window_id = wayland::make_wid(parent_surface); + // Determine which window to direct the events to, and also whether + // the event came from a decoration frame. + let (mut window, window_id, is_decoration) = { + let surface_wid = wayland::make_wid(surface); + match parent_surface { + Some(parent_surface) => 'found_surface: { + // If the current window is a registered subsurface, then use it. + if let Some(window_mutex) = self.windows.get_mut().get_mut(&surface_wid) { + let window = window_mutex.lock().unwrap(); + if window.is_subsurface() { + break 'found_surface (window, surface_wid, false); + } + } - // Ensure that window exists. - let mut window = match self.windows.get_mut().get_mut(&window_id) { - Some(window) => window.lock().unwrap(), - None => continue, + // If the current window's parent is a registered surface, it is likely a + // decoration frame provided by SCTK. + let parent_wid = wayland::make_wid(parent_surface); + if let Some(window_mutex) = self.windows.get_mut().get_mut(&parent_wid) { + let window = window_mutex.lock().unwrap(); + break 'found_surface (window, parent_wid, true); + } + + continue 'processing_events; + } + // Toplevel windows can easily handle themselves. + None => match self.windows.get_mut().get_mut(&surface_wid) { + Some(window) => (window.lock().unwrap(), surface_wid, false), + None => continue 'processing_events, + }, + } }; + // let window_id = wayland::make_wid(parent_surface); + + // Ensure that window exists. + // let mut window = match self.windows.get_mut().get_mut(&window_id) { + // Some(window) => window.lock().unwrap(), + // None => continue, + // }; + let scale_factor = window.scale_factor(); let position: PhysicalPosition = LogicalPosition::new(event.position.0, event.position.1).to_physical(scale_factor); @@ -68,7 +100,7 @@ impl PointerHandler for WinitState { match event.kind { // Pointer movements on decorations. PointerEventKind::Enter { .. } | PointerEventKind::Motion { .. } - if parent_surface != surface => + if is_decoration => { if let Some(icon) = window.frame_point_moved( seat, @@ -82,7 +114,7 @@ impl PointerHandler for WinitState { } } } - PointerEventKind::Leave { .. } if parent_surface != surface => { + PointerEventKind::Leave { .. } if is_decoration => { window.frame_point_left(); } ref kind @ PointerEventKind::Press { @@ -94,7 +126,7 @@ impl PointerHandler for WinitState { button, serial, time, - } if parent_surface != surface => { + } if is_decoration => { let click = match wayland_button_to_winit(button) { MouseButton::Left => FrameClick::Normal, MouseButton::Right => FrameClick::Alternate, diff --git a/src/platform_impl/linux/wayland/window/mod.rs b/src/platform_impl/linux/wayland/window/mod.rs index d698b8dc12..8a317d6d53 100644 --- a/src/platform_impl/linux/wayland/window/mod.rs +++ b/src/platform_impl/linux/wayland/window/mod.rs @@ -108,7 +108,6 @@ impl Window { let monitors = state.monitors.clone(); - let surface = state.compositor_state.create_surface(&queue_handle); let compositor = state.compositor_state.clone(); let xdg_activation = state .xdg_activation @@ -128,44 +127,46 @@ impl Window { WindowDecorations::RequestClient }; - // if let Some(parent_window) = attributes.parent_window() { - // match parent_window { - // rwh_06::RawWindowHandle::Wayland(_) => { - - // }, - // _ => panic!("Parent window of a Wayland window must be a Wayland window"), - // } - // } - let (window, mut window_state) = match attributes.parent_window() { - Some(rwh_06::RawWindowHandle::Wayland(wl_handle)) => unsafe { - let parent_surface = WlSurface::from_id( - &event_loop_window_target.connection, - ObjectId::from_ptr( - WlSurface::interface(), - wl_handle.surface.as_ptr() as *mut wayland_sys::client::wl_proxy, + // Subsurfaces have very different behaviour from toplevels. We handle that here. + let (surface, window, mut window_state) = match attributes.parent_window() { + Some(rwh_06::RawWindowHandle::Wayland(wl_handle)) => { + // wayland-rs has lots of layers involved in converting *mut wl_proxy to an actual object. + // This would be a single pointer cast in C. + let parent_surface = unsafe { + WlSurface::from_id( + &event_loop_window_target.connection, + ObjectId::from_ptr( + WlSurface::interface(), + wl_handle.surface.as_ptr() as *mut wayland_sys::client::wl_proxy, + ) + .expect("Invalid parent surface handle!"), ) - .expect("Invalid parent surface handle!"), - ) - .expect("Invalid parent surface handle!"); + .expect("Invalid parent surface handle!") + }; - let window = WindowRole::Subsurface(Subsurface::from_parent( + let subsurface = Subsurface::from_parent( &parent_surface, state.subcompositor_state.as_ref().unwrap(), &queue_handle, - )); + ); + + let surface = subsurface.wl_surface().clone(); + let window_role = WindowRole::Subsurface(subsurface); let window_state = WindowState::new( event_loop_window_target.connection.clone(), &event_loop_window_target.queue_handle, &state, size, - window.clone(), + window_role.clone(), attributes.preferred_theme, ); - (window, window_state) - }, + (surface, window_role, window_state) + } None => { + let surface = state.compositor_state.create_surface(&queue_handle); + let window = WindowRole::Toplevel(state.xdg_shell.create_window( surface.clone(), default_decorations, @@ -181,7 +182,7 @@ impl Window { attributes.preferred_theme, ); - (window, window_state) + (surface, window, window_state) } _ => panic!("Parent window of a Wayland surface must be a Wayland surface"), }; diff --git a/src/platform_impl/linux/wayland/window/state.rs b/src/platform_impl/linux/wayland/window/state.rs index 50d81cf2d5..a19306f326 100644 --- a/src/platform_impl/linux/wayland/window/state.rs +++ b/src/platform_impl/linux/wayland/window/state.rs @@ -1268,7 +1268,7 @@ impl WindowState { } } - /// Set + /// Set the window's position, if it can be set. #[inline] pub fn set_position(&mut self, pos: PhysicalPosition) { if let SurfaceRoleState::Subsurface { window } = &self.surface_role { @@ -1277,6 +1277,14 @@ impl WindowState { warn!("Only subsurfaces can set their (parent-relative) position") } } + + /// Returns true if the window is a subsurface. + pub fn is_subsurface(&self) -> bool { + match &self.surface_role { + SurfaceRoleState::Subsurface { .. } => true, + SurfaceRoleState::Toplevel { .. } => false, + } + } } impl Drop for WindowState { From 3245d64c8a6ec5e350d82b835485ffc6a0cf33d4 Mon Sep 17 00:00:00 2001 From: jgcodes2020 Date: Mon, 19 Feb 2024 22:42:11 -0500 Subject: [PATCH 12/13] documentation changes, rwh_06 compatibility shenanigans --- examples/child_window.rs | 6 ++++-- src/platform_impl/linux/wayland/window/mod.rs | 3 ++- src/window.rs | 6 +++++- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/examples/child_window.rs b/examples/child_window.rs index 1f932ffc4a..6185438fce 100644 --- a/examples/child_window.rs +++ b/examples/child_window.rs @@ -18,7 +18,7 @@ fn main() -> Result<(), impl std::error::Error> { dpi::{LogicalPosition, LogicalSize}, event::{ElementState, Event, KeyEvent, WindowEvent}, event_loop::{EventLoop, EventLoopWindowTarget}, - keyboard::{KeyCode, PhysicalKey}, + keyboard::{Key, NamedKey}, window::{Window, WindowId}, }; @@ -32,6 +32,8 @@ fn main() -> Result<(), impl std::error::Error> { .with_inner_size(LogicalSize::new(200.0f32, 200.0f32)) .with_visible(true); + // Adding a parent window handle is inherently unsafe, as it is the programmer's + // responsibility to ensure that the parent handle is valid. builder = unsafe { builder.with_parent_window(parent.raw_window_handle().ok()) }; let child = builder.build(event_loop).unwrap(); @@ -70,7 +72,7 @@ fn main() -> Result<(), impl std::error::Error> { WindowEvent::KeyboardInput { event: KeyEvent { - physical_key: PhysicalKey::Code(KeyCode::Enter), + logical_key: Key::Named(NamedKey::Enter), state: ElementState::Pressed, .. }, diff --git a/src/platform_impl/linux/wayland/window/mod.rs b/src/platform_impl/linux/wayland/window/mod.rs index 8a317d6d53..5854cb8c64 100644 --- a/src/platform_impl/linux/wayland/window/mod.rs +++ b/src/platform_impl/linux/wayland/window/mod.rs @@ -129,6 +129,7 @@ impl Window { // Subsurfaces have very different behaviour from toplevels. We handle that here. let (surface, window, mut window_state) = match attributes.parent_window() { + #[cfg(feature = "rwh_06")] Some(rwh_06::RawWindowHandle::Wayland(wl_handle)) => { // wayland-rs has lots of layers involved in converting *mut wl_proxy to an actual object. // This would be a single pointer cast in C. @@ -164,7 +165,7 @@ impl Window { (surface, window_role, window_state) } - None => { + _ => { let surface = state.compositor_state.create_surface(&queue_handle); let window = WindowRole::Toplevel(state.xdg_shell.create_window( diff --git a/src/window.rs b/src/window.rs index b715a3ae40..ac70c2a060 100644 --- a/src/window.rs +++ b/src/window.rs @@ -523,7 +523,11 @@ impl WindowBuilder { /// to the client area of its parent window. For more information, see /// /// - **X11**: A child window is confined to the client area of its parent window. - /// - **Android / iOS / Wayland / Web:** Unsupported. + /// - **Wayland**: A child window (or in Wayland speak, "subsurface") is *not* confined + /// to the client area of its parent window. In addition, it must be created on the same + /// event loop as its parent. For more information, see + /// + /// - **Android / iOS / Web:** Unsupported. #[cfg(feature = "rwh_06")] #[inline] pub unsafe fn with_parent_window( From 20ecfa4df8e4834e4d787de042f5b381a143a761 Mon Sep 17 00:00:00 2001 From: jgcodes2020 Date: Mon, 19 Feb 2024 22:49:51 -0500 Subject: [PATCH 13/13] properly implement rwh_06 conditional, mess with changelog --- CHANGELOG.md | 1 + src/platform_impl/linux/wayland/window/mod.rs | 26 +++++++++++++++++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 289c921d17..bd6a1c1fdb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -72,6 +72,7 @@ Unreleased` header. - On Orbital, implement `set_window_level`. - On Orbital, emit `DeviceEvent::MouseMotion`. - On Wayland, fix title in CSD not updated from `AboutToWait`. +- Implemented `WindowBuilder::with_parent_window` for Wayland. # 0.29.10 diff --git a/src/platform_impl/linux/wayland/window/mod.rs b/src/platform_impl/linux/wayland/window/mod.rs index 5854cb8c64..ab26eaf2e3 100644 --- a/src/platform_impl/linux/wayland/window/mod.rs +++ b/src/platform_impl/linux/wayland/window/mod.rs @@ -128,8 +128,8 @@ impl Window { }; // Subsurfaces have very different behaviour from toplevels. We handle that here. + #[cfg(feature = "rwh_06")] let (surface, window, mut window_state) = match attributes.parent_window() { - #[cfg(feature = "rwh_06")] Some(rwh_06::RawWindowHandle::Wayland(wl_handle)) => { // wayland-rs has lots of layers involved in converting *mut wl_proxy to an actual object. // This would be a single pointer cast in C. @@ -165,7 +165,7 @@ impl Window { (surface, window_role, window_state) } - _ => { + None => { let surface = state.compositor_state.create_surface(&queue_handle); let window = WindowRole::Toplevel(state.xdg_shell.create_window( @@ -187,6 +187,28 @@ impl Window { } _ => panic!("Parent window of a Wayland surface must be a Wayland surface"), }; + // Revert to old behaviour if rwh_06 isn't supported. + #[cfg(not(feature = "rwh_06"))] + let (surface, window, mut window_state) = { + let surface = state.compositor_state.create_surface(&queue_handle); + + let window = WindowRole::Toplevel(state.xdg_shell.create_window( + surface.clone(), + default_decorations, + &queue_handle, + )); + + let window_state = WindowState::new( + event_loop_window_target.connection.clone(), + &event_loop_window_target.queue_handle, + &state, + size, + window.clone(), + attributes.preferred_theme, + ); + + (surface, window, window_state) + }; // Set transparency hint. window_state.set_transparent(attributes.transparent);