From fd3d7c72bd19b4ee425e02649851b71391843c64 Mon Sep 17 00:00:00 2001 From: Ashley Wulber <48420062+wash2@users.noreply.github.com> Date: Tue, 16 Jul 2024 10:41:11 -0400 Subject: [PATCH] feat(sctk): support for overflow widget --- core/src/event/wayland/window.rs | 30 ++++++++++++-- sctk/src/application.rs | 20 +++++---- sctk/src/event_loop/mod.rs | 12 ++---- sctk/src/event_loop/state.rs | 31 ++++++++------ sctk/src/handlers/seat/pointer.rs | 59 +++++++++++++-------------- sctk/src/handlers/shell/xdg_window.rs | 26 ++---------- sctk/src/sctk_event.rs | 56 +++++++++++++++++-------- 7 files changed, 129 insertions(+), 105 deletions(-) diff --git a/core/src/event/wayland/window.rs b/core/src/event/wayland/window.rs index 210b1ce1ca..bd771f4b03 100644 --- a/core/src/event/wayland/window.rs +++ b/core/src/event/wayland/window.rs @@ -1,12 +1,34 @@ #![allow(missing_docs)] -use sctk::reexports::csd_frame::{WindowManagerCapabilities, WindowState}; +use sctk::{ + reexports::csd_frame::{WindowManagerCapabilities, WindowState}, + shell::xdg::window::WindowConfigure, +}; /// window events -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone)] pub enum WindowEvent { - /// window manager capabilities + /// Window manager capabilities. WmCapabilities(WindowManagerCapabilities), - /// window state + /// Window state. State(WindowState), + /// Window configure event. + Configure(WindowConfigure), +} + +impl PartialEq for WindowEvent { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Self::WmCapabilities(a), Self::WmCapabilities(b)) => a == b, + (Self::State(a), Self::State(b)) => a == b, + (Self::Configure(a), Self::Configure(b)) => { + a.capabilities == b.capabilities + && a.state == b.state + && a.decoration_mode == b.decoration_mode + && a.new_size == b.new_size + && a.suggested_bounds == b.suggested_bounds + } + _ => false, + } + } } diff --git a/sctk/src/application.rs b/sctk/src/application.rs index 478dba5bc2..dadb47a65d 100644 --- a/sctk/src/application.rs +++ b/sctk/src/application.rs @@ -535,7 +535,12 @@ where crate::sctk_event::WindowEventVariant::WmCapabilities(_) | crate::sctk_event::WindowEventVariant::ConfigureBounds { .. } => {} crate::sctk_event::WindowEventVariant::Configure( - configure, + current_size, + _, + wl_surface, + first, + ) | crate::sctk_event::WindowEventVariant::Size( + current_size, wl_surface, first, ) => { @@ -543,6 +548,7 @@ where let Some(state) = states.get_mut(&id.inner()) else { continue; }; + let (w, h) = auto_size_surfaces.get(id).map_or_else(|| (current_size.0.get(), current_size.1.get()), |(w, h, _, _)| (*w, *h)); if state.surface.is_none() { let wrapper = SurfaceDisplayWrapper { backend: backend.clone(), @@ -553,16 +559,12 @@ where simple_clipboard = unsafe {Clipboard::connect(&h)}; } } - let mut c_surface = compositor.create_surface(wrapper.clone(), configure.new_size.0.unwrap().get(), configure.new_size.1.unwrap().get()); - compositor.configure_surface(&mut c_surface, configure.new_size.0.unwrap().get(), configure.new_size.1.unwrap().get()); + let mut c_surface = compositor.create_surface(wrapper.clone(), w, h); + compositor.configure_surface(&mut c_surface, w, h); state.surface = Some(c_surface); } - if let Some((w, h, _, is_dirty)) = auto_size_surfaces.get_mut(id) { - *is_dirty = first || *w != configure.new_size.0.map(|w| w.get()).unwrap_or_default() || *h != configure.new_size.1.map(|h| h.get()).unwrap_or_default(); - state.set_logical_size(*w as f32, *h as f32); - } else { - state.set_logical_size(configure.new_size.0.unwrap().get() as f32 , configure.new_size.1.unwrap().get() as f32); - } + state.set_logical_size(w as f32, h as f32); + if first { let user_interface = build_user_interface( &application, diff --git a/sctk/src/event_loop/mod.rs b/sctk/src/event_loop/mod.rs index 36fadfdd91..c89689a4e5 100644 --- a/sctk/src/event_loop/mod.rs +++ b/sctk/src/event_loop/mod.rs @@ -876,18 +876,12 @@ where }, platform_specific::wayland::window::Action::Size { id, width, height } => { if let Some(window) = self.state.windows.iter_mut().find(|w| w.id == id) { - window.set_size(LogicalSize::new(NonZeroU32::new(width).unwrap_or(NonZeroU32::new(1).unwrap()), NonZeroU32::new(1).unwrap())); + window.set_size(LogicalSize::new(NonZeroU32::new(width).unwrap_or(NonZeroU32::new(1).unwrap()), NonZeroU32::new(height).unwrap_or(NonZeroU32::new(1).unwrap()))); // TODO Ashley maybe don't force window size? pending_redraws.push(window.window.wl_surface().id()); - - if let Some(mut prev_configure) = window.last_configure.clone() { - let (width, height) = ( - NonZeroU32::new(width).unwrap_or(NonZeroU32::new(1).unwrap()), - NonZeroU32::new(height).unwrap_or(NonZeroU32::new(1).unwrap()), - ); - prev_configure.new_size = (Some(width), Some(height)); + if window.last_configure.is_some() { sticky_exit_callback( - IcedSctkEvent::SctkEvent(SctkEvent::WindowEvent { variant: WindowEventVariant::Configure(prev_configure, window.window.wl_surface().clone(), false), id: window.window.wl_surface().clone()}), + IcedSctkEvent::SctkEvent(SctkEvent::WindowEvent { variant: WindowEventVariant::Size(window.current_size, window.window.wl_surface().clone(), false), id: window.window.wl_surface().clone()}), &self.state, &mut control_flow, &mut callback, diff --git a/sctk/src/event_loop/state.rs b/sctk/src/event_loop/state.rs index 00c64797b7..5623f7e0b8 100644 --- a/sctk/src/event_loop/state.rs +++ b/sctk/src/event_loop/state.rs @@ -118,8 +118,8 @@ pub struct SctkWindow { pub(crate) id: window::Id, pub(crate) window: Window, pub(crate) scale_factor: Option, - pub(crate) requested_size: Option<(u32, u32)>, - pub(crate) current_size: Option<(NonZeroU32, NonZeroU32)>, + pub(crate) requested_size: Option<(NonZeroU32, NonZeroU32)>, + pub(crate) current_size: (NonZeroU32, NonZeroU32), pub(crate) last_configure: Option, pub(crate) resizable: Option, /// Requests that SCTK window should perform. @@ -131,18 +131,24 @@ pub struct SctkWindow { impl SctkWindow { pub(crate) fn set_size(&mut self, logical_size: LogicalSize) { - self.requested_size = - Some((logical_size.width.get(), logical_size.height.get())); - self.update_size(logical_size) + self.requested_size = Some((logical_size.width, logical_size.height)); + self.update_size((Some(logical_size.width), Some(logical_size.height))) } pub(crate) fn update_size( &mut self, - LogicalSize { width, height }: LogicalSize, + (width, height): (Option, Option), ) { + let (width, height) = ( + width.unwrap_or_else(|| self.current_size.0), + height.unwrap_or_else(|| self.current_size.1), + ); + if self.current_size == (width, height) { + return; + } self.window .set_window_geometry(0, 0, width.get(), height.get()); - self.current_size = Some((width, height)); + self.current_size = (width, height); // Update the target viewport, this is used if and only if fractional scaling is in use. if let Some(viewport) = self.wp_viewport.as_ref() { // Set inner size without the borders. @@ -733,15 +739,16 @@ where fsm.fractional_scaling(window.wl_surface(), &self.queue_handle) }); + let w = NonZeroU32::new(size.0 as u32) + .unwrap_or_else(|| NonZeroU32::new(1).unwrap()); + let h = NonZeroU32::new(size.1 as u32) + .unwrap_or_else(|| NonZeroU32::new(1).unwrap()); self.windows.push(SctkWindow { id: window_id, window, scale_factor: None, - requested_size: Some(size), - current_size: Some(( - NonZeroU32::new(1).unwrap(), - NonZeroU32::new(1).unwrap(), - )), + requested_size: Some((w, h)), + current_size: (w, h), last_configure: None, _pending_requests: Vec::new(), resizable, diff --git a/sctk/src/handlers/seat/pointer.rs b/sctk/src/handlers/seat/pointer.rs index eaddf814a0..eec170964e 100644 --- a/sctk/src/handlers/seat/pointer.rs +++ b/sctk/src/handlers/seat/pointer.rs @@ -35,37 +35,36 @@ impl PointerHandler for SctkState { .iter() .find(|w| w.window.wl_surface() == &e.surface) .and_then(|w| { - w.resizable.zip(w.current_size).and_then( - |(border, (width, height))| { - let (width, height) = - (width.get() as f64, height.get() as f64); - let (x, y) = e.position; - let left_edge = x < border; - let top_edge = y < border; - let right_edge = x > width - border; - let bottom_edge = y > height - border; + w.resizable.and_then(|border| { + let (width, height) = w.current_size; + let (width, height) = + (width.get() as f64, height.get() as f64); + let (x, y) = e.position; + let left_edge = x < border; + let top_edge = y < border; + let right_edge = x > width - border; + let bottom_edge = y > height - border; - if left_edge && top_edge { - Some((ResizeEdge::TopLeft, w)) - } else if left_edge && bottom_edge { - Some((ResizeEdge::BottomLeft, w)) - } else if right_edge && top_edge { - Some((ResizeEdge::TopRight, w)) - } else if right_edge && bottom_edge { - Some((ResizeEdge::BottomRight, w)) - } else if left_edge { - Some((ResizeEdge::Left, w)) - } else if right_edge { - Some((ResizeEdge::Right, w)) - } else if top_edge { - Some((ResizeEdge::Top, w)) - } else if bottom_edge { - Some((ResizeEdge::Bottom, w)) - } else { - None - } - }, - ) + if left_edge && top_edge { + Some((ResizeEdge::TopLeft, w)) + } else if left_edge && bottom_edge { + Some((ResizeEdge::BottomLeft, w)) + } else if right_edge && top_edge { + Some((ResizeEdge::TopRight, w)) + } else if right_edge && bottom_edge { + Some((ResizeEdge::BottomRight, w)) + } else if left_edge { + Some((ResizeEdge::Left, w)) + } else if right_edge { + Some((ResizeEdge::Right, w)) + } else if top_edge { + Some((ResizeEdge::Top, w)) + } else if bottom_edge { + Some((ResizeEdge::Bottom, w)) + } else { + None + } + }) }) { let icon = match resize_edge { diff --git a/sctk/src/handlers/shell/xdg_window.rs b/sctk/src/handlers/shell/xdg_window.rs index 6b4505737b..6dd9da14f4 100644 --- a/sctk/src/handlers/shell/xdg_window.rs +++ b/sctk/src/handlers/shell/xdg_window.rs @@ -37,7 +37,7 @@ impl WindowHandler for SctkState { _conn: &sctk::reexports::client::Connection, _qh: &sctk::reexports::client::QueueHandle, window: &sctk::shell::xdg::window::Window, - mut configure: sctk::shell::xdg::window::WindowConfigure, + configure: sctk::shell::xdg::window::WindowConfigure, _serial: u32, ) { let window = match self @@ -68,28 +68,7 @@ impl WindowHandler for SctkState { }); } - if configure.new_size.0.is_none() { - configure.new_size.0 = Some( - window - .requested_size - .and_then(|r| NonZeroU32::new(r.0)) - .unwrap_or_else(|| NonZeroU32::new(300).unwrap()), - ); - } - if configure.new_size.1.is_none() { - configure.new_size.1 = Some( - window - .requested_size - .and_then(|r| NonZeroU32::new(r.1)) - .unwrap_or_else(|| NonZeroU32::new(500).unwrap()), - ); - } - if let Some(new_size) = configure.new_size.0.zip(configure.new_size.1) { - window.update_size(LogicalSize { - width: new_size.0, - height: new_size.1, - }); - } + window.update_size(configure.new_size); let wl_surface = window.window.wl_surface(); let id = wl_surface.clone(); @@ -98,6 +77,7 @@ impl WindowHandler for SctkState { self.sctk_events.push(SctkEvent::WindowEvent { variant: WindowEventVariant::Configure( + window.current_size, configure, wl_surface.clone(), first, diff --git a/sctk/src/sctk_event.rs b/sctk/src/sctk_event.rs index c7a1f211c6..5c9ac61b39 100755 --- a/sctk/src/sctk_event.rs +++ b/sctk/src/sctk_event.rs @@ -41,7 +41,7 @@ use sctk::{ xdg::{popup::PopupConfigure, window::WindowConfigure}, }, }; -use std::{collections::HashMap, time::Instant}; +use std::{collections::HashMap, num::NonZeroU32, time::Instant}; use wayland_protocols::wp::viewporter::client::wp_viewport::WpViewport; use xkeysym::Keysym; @@ -310,8 +310,8 @@ pub enum WindowEventVariant { height: u32, }, /// - Configure(WindowConfigure, WlSurface, bool), - + Configure((NonZeroU32, NonZeroU32), WindowConfigure, WlSurface, bool), + Size((NonZeroU32, NonZeroU32), WlSurface, bool), /// window state changed StateChanged(sctk::reexports::csd_frame::WindowState), /// Scale Factor @@ -674,27 +674,46 @@ impl SctkEvent { WindowEventVariant::ConfigureBounds { .. } => { Default::default() } - WindowEventVariant::Configure(configure, surface, _) => { - if let (Some(new_width), Some(new_height)) = - configure.new_size - { - surface_ids - .get(&surface.id()) - .map(|id| { + WindowEventVariant::Configure( + (new_width, new_height), + configure, + surface, + _, + ) => surface_ids + .get(&surface.id()) + .map(|id| { + if configure.is_resizing() { + vec![iced_runtime::core::Event::Window( + id.inner(), + window::Event::Resized { + width: new_width.get(), + height: new_height.get(), + }, + )] + } else { + vec![ iced_runtime::core::Event::Window( id.inner(), window::Event::Resized { width: new_width.get(), height: new_height.get(), }, - ) - }) - .into_iter() - .collect() - } else { - Default::default() - } - } + ), + iced_runtime::core::Event::PlatformSpecific( + PlatformSpecific::Wayland( + wayland::Event::Window( + wayland::WindowEvent::Configure( + configure, + ), + surface, + id.inner(), + ), + ), + ), + ] + } + }) + .unwrap_or_default(), WindowEventVariant::ScaleFactorChanged(..) => { Default::default() } @@ -711,6 +730,7 @@ impl SctkEvent { }) .into_iter() .collect(), + WindowEventVariant::Size(_, _, _) => vec![], }, SctkEvent::LayerSurfaceEvent { variant,