From b5b2b2fcc3e58be793624ba3a7dd45485813935a Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Mon, 6 Jul 2026 18:44:30 -0400 Subject: [PATCH 01/20] fix: popup cleanup --- winit/src/platform_specific/wayland/event_loop/state.rs | 3 ++- .../platform_specific/wayland/handlers/shell/xdg_popup.rs | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/winit/src/platform_specific/wayland/event_loop/state.rs b/winit/src/platform_specific/wayland/event_loop/state.rs index b817e4d5..3cbc21cb 100644 --- a/winit/src/platform_specific/wayland/event_loop/state.rs +++ b/winit/src/platform_specific/wayland/event_loop/state.rs @@ -1392,7 +1392,7 @@ impl SctkState { }, }; let mut to_destroy = vec![sctk_popup]; - // TODO optionally destroy parents if they request to be destroyed with children + while let Some(popup_to_destroy_last) = to_destroy.last().and_then(|popup| self .popups .iter() @@ -1839,6 +1839,7 @@ impl SctkState { s: &WlSurface, ) { let existing_blur = self.blur_surfaces.entry(id); + match (existing_blur, rectangles) { (Entry::Occupied(occupied_entry), None) => { let blur_surface = occupied_entry.remove(); diff --git a/winit/src/platform_specific/wayland/handlers/shell/xdg_popup.rs b/winit/src/platform_specific/wayland/handlers/shell/xdg_popup.rs index 55bf2b87..432f5bde 100644 --- a/winit/src/platform_specific/wayland/handlers/shell/xdg_popup.rs +++ b/winit/src/platform_specific/wayland/handlers/shell/xdg_popup.rs @@ -84,6 +84,11 @@ impl PopupHandler for SctkState { for popup in to_destroy.into_iter().rev() { if let Some(id) = self.id_map.remove(&popup.popup.wl_surface().id()) { + if let Some(blurred) = self.blur_surfaces.remove(&id) { + blurred.destroy(); + } + _ = self.corner_radii.remove(&id); + _ = self.destroyed.insert(id); } From 371dd94a2ad2922f26c218c5741a8c1c6b85e875 Mon Sep 17 00:00:00 2001 From: Ilia Malanin Date: Tue, 7 Jul 2026 10:55:41 +0200 Subject: [PATCH 02/20] fix: intersect nested clip bounds with parent layer --- graphics/src/layer.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/graphics/src/layer.rs b/graphics/src/layer.rs index 31cfe68a..210b8309 100644 --- a/graphics/src/layer.rs +++ b/graphics/src/layer.rs @@ -83,13 +83,20 @@ impl Stack { /// Pushes a new clipping region in the [`Stack`]; creating a new layer in the /// process. pub fn push_clip(&mut self, bounds: Rectangle) { + let bounds = bounds * self.transformation(); + let bounds = bounds + .intersection(&self.layers[self.current].bounds()) + .unwrap_or(Rectangle { + width: 0.0, + height: 0.0, + ..bounds + }); + self.previous.push(self.current); self.current = self.active_count; self.active_count += 1; - let bounds = bounds * self.transformation(); - if self.current == self.layers.len() { self.layers.push(T::with_bounds(bounds)); } else { From 5671e49c9b2bf82a773f4c058a91726d0058cc87 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Mon, 6 Jul 2026 19:07:11 -0700 Subject: [PATCH 03/20] wgpu: Apply Nvidia driver workaround regardless of `cctk` feature --- Cargo.lock | 5 +++-- Cargo.toml | 1 + wgpu/Cargo.toml | 1 + wgpu/src/window.rs | 1 - wgpu/src/window/compositor.rs | 12 ------------ wgpu/src/window/wayland.rs | 6 +++--- 6 files changed, 8 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 11a85d77..3fe192d4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1294,7 +1294,7 @@ dependencies = [ [[package]] name = "cosmic-client-toolkit" version = "0.2.0" -source = "git+https://github.com/pop-os/cosmic-protocols?rev=a7d2d7a#a7d2d7a6188425f699eaddf7a025617ce56068ae" +source = "git+https://github.com/pop-os/cosmic-protocols?rev=32283d7#32283d76a8d0342da74c4cc022a533c52dcf378f" dependencies = [ "bitflags 2.11.0", "cosmic-protocols", @@ -1307,7 +1307,7 @@ dependencies = [ [[package]] name = "cosmic-protocols" version = "0.2.0" -source = "git+https://github.com/pop-os/cosmic-protocols?rev=a7d2d7a#a7d2d7a6188425f699eaddf7a025617ce56068ae" +source = "git+https://github.com/pop-os/cosmic-protocols?rev=32283d7#32283d76a8d0342da74c4cc022a533c52dcf378f" dependencies = [ "bitflags 2.11.0", "wayland-backend", @@ -3195,6 +3195,7 @@ dependencies = [ "resvg", "rustc-hash 2.1.2", "rustix 0.38.44", + "smithay-client-toolkit 0.20.0", "thiserror 2.0.18", "tiny-xlib", "wayland-backend", diff --git a/Cargo.toml b/Cargo.toml index 555f7901..0bbcfebe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -308,6 +308,7 @@ winit = { git = "https://github.com/pop-os/winit.git", tag = "cosmic-0.14" } winit-core = { git = "https://github.com/pop-os/winit.git", tag = "cosmic-0.14" } cursor-icon = "1.1.0" +sctk = { package = "smithay-client-toolkit", version = "0.20.0" } [workspace.lints.rust] rust_2018_idioms = { level = "deny", priority = -1 } diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml index 48fca1b8..f347f363 100644 --- a/wgpu/Cargo.toml +++ b/wgpu/Cargo.toml @@ -65,3 +65,4 @@ x11rb = { version = "0.13.1", features = [ "dri3", "randr", ] } +sctk.workspace = true diff --git a/wgpu/src/window.rs b/wgpu/src/window.rs index b9ec54bd..385041c2 100644 --- a/wgpu/src/window.rs +++ b/wgpu/src/window.rs @@ -2,7 +2,6 @@ pub mod compositor; #[cfg(all( unix, - feature = "cctk", not(target_os = "macos"), not(target_os = "redox") ))] diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs index 58c7d713..2269b9b7 100644 --- a/wgpu/src/window/compositor.rs +++ b/wgpu/src/window/compositor.rs @@ -11,7 +11,6 @@ use crate::{Engine, Renderer}; #[cfg(all( unix, - feature = "cctk", not(target_os = "macos"), not(target_os = "redox") ))] @@ -67,7 +66,6 @@ impl Compositor { ) -> Result { #[cfg(all( unix, - feature = "cctk", not(target_os = "macos"), not(target_os = "redox") ))] @@ -76,16 +74,6 @@ impl Compositor { .or_else(|| get_x11_device_ids(window)) }); - #[cfg(all( - unix, - not(feature = "cctk"), - not(target_os = "macos"), - not(target_os = "redox") - ))] - let ids = compatible_window - .as_ref() - .and_then(|window| get_x11_device_ids(window)); - // HACK: // 1. If we specifically didn't select an nvidia gpu // 2. and the user didn't specifically request an nvidia gpu diff --git a/wgpu/src/window/wayland.rs b/wgpu/src/window/wayland.rs index 48e00def..af448d94 100644 --- a/wgpu/src/window/wayland.rs +++ b/wgpu/src/window/wayland.rs @@ -1,5 +1,5 @@ use crate::graphics::compositor::Window; -use cctk::sctk::{ +use sctk::{ dmabuf::{DmabufFeedback, DmabufHandler, DmabufState}, registry::{ProvidesRegistryState, RegistryState}, registry_handlers, @@ -111,5 +111,5 @@ pub fn get_wayland_device_ids(window: &W) -> Option<(u16, u16)> { } } -cctk::sctk::delegate_dmabuf!(AppData); -cctk::sctk::delegate_registry!(AppData); +sctk::delegate_dmabuf!(AppData); +sctk::delegate_registry!(AppData); From 5da1188557b58cdbe1951c72aad4360ebe05f5f4 Mon Sep 17 00:00:00 2001 From: Hojjat Date: Thu, 9 Jul 2026 17:32:45 -0600 Subject: [PATCH 04/20] fix: validate corner radius against window geometry --- .../wayland/event_loop/state.rs | 65 +++++++++++++++++-- .../platform_specific/wayland/winit_window.rs | 4 ++ 2 files changed, 63 insertions(+), 6 deletions(-) diff --git a/winit/src/platform_specific/wayland/event_loop/state.rs b/winit/src/platform_specific/wayland/event_loop/state.rs index 3cbc21cb..805bfaff 100644 --- a/winit/src/platform_specific/wayland/event_loop/state.rs +++ b/winit/src/platform_specific/wayland/event_loop/state.rs @@ -238,6 +238,43 @@ pub struct Common { pub(crate) size: LogicalSize, pub(crate) requested_size: (Option, Option), pub(crate) wp_viewport: Option, + pub(crate) corner_radius: Option, + pub(crate) requested_corner_radius: Option, + /// Geometry last committed via `set_window_geometry`/`set_size` + /// This is what compositor validates the corner radius against + pub(crate) corner_geometry: LogicalSize, +} + +impl Common { + pub(crate) fn set_corner_geometry(&mut self, width: u32, height: u32) { + self.corner_geometry = LogicalSize::new(width, height); + self.apply_corner_radius(); + } + + pub(crate) fn apply_corner_radius(&self) { + let (Some(radius_object), Some(requested)) = + (self.corner_radius.as_ref(), self.requested_corner_radius) + else { + return; + }; + let max_radius = + self.corner_geometry.width.min(self.corner_geometry.height) / 2; + let clamp = |radius: u32| radius.min(max_radius); + match radius_object.0.as_ref() { + CornerRadiusWrapper::Xdg(surface) => surface.set_radius( + clamp(requested.top_left), + clamp(requested.top_right), + clamp(requested.bottom_right), + clamp(requested.bottom_left), + ), + CornerRadiusWrapper::Wlr(surface) => surface.set_radius( + clamp(requested.top_left), + clamp(requested.top_right), + clamp(requested.bottom_right), + clamp(requested.bottom_left), + ), + }; + } } impl Default for Common { @@ -250,6 +287,9 @@ impl Default for Common { size: LogicalSize::new(1, 1), requested_size: (None, None), wp_viewport: None, + corner_radius: None, + requested_corner_radius: None, + corner_geometry: LogicalSize::new(1, 1), } } } @@ -258,6 +298,7 @@ impl From> for Common { fn from(value: LogicalSize) -> Self { Common { size: value, + corner_geometry: value, ..Default::default() } } @@ -290,6 +331,7 @@ impl SctkPopup { // update positioner self.data.positioner.set_size(w as i32, h as i32); self.popup.reposition(&self.data.positioner, token); + self.common.lock().unwrap().set_corner_geometry(w, h); } pub(crate) fn update_viewport(&mut self, w: u32, h: u32) { @@ -1489,6 +1531,7 @@ impl SctkState { sctk_popup.popup .xdg_surface() .set_window_geometry(0, 0, w as i32, h as i32); + sctk_popup.common.lock().unwrap().set_corner_geometry(w, h); sctk_popup.update_viewport(w, h); // update positioner sctk_popup.data.positioner.set_size(w as i32, h as i32); @@ -1706,20 +1749,22 @@ impl SctkState { Wlr(ZwlrLayerSurfaceV1), } let s = if let Some(w) = self.windows.iter_mut().find(|w| w.id == id) { - Some((Surface::Xdg(w.xdg_surface(&self.connection), Some(w.xdg_toplevel(&self.connection))), w.window.surface_size().cast::().to_logical(w.window.scale_factor()))) + Some((Surface::Xdg(w.xdg_surface(&self.connection), Some(w.xdg_toplevel(&self.connection))), w.window.surface_size().cast::().to_logical(w.window.scale_factor()), None)) } else if let Some(p) = self.popups.iter_mut().find(|w| w.data.id == id) { - let guard = p.common.lock().unwrap(); - Some((Surface::Xdg(p.popup.xdg_surface().clone(), None), guard.size.cast::())) + let common = p.common.clone(); + let geo_size = common.lock().unwrap().corner_geometry.cast::(); + Some((Surface::Xdg(p.popup.xdg_surface().clone(), None), geo_size, Some(common))) } else if let Some(l) = self.layer_surfaces.iter_mut().find(|l| l.id == id) { - let guard = l.common.lock().unwrap(); + let common = l.common.clone(); + let geo_size = common.lock().unwrap().corner_geometry.cast::(); match l.surface.kind() { - SurfaceKind::Wlr(l) => Some((Surface::Wlr(l.clone()), guard.size.cast::())), + SurfaceKind::Wlr(l) => Some((Surface::Wlr(l.clone()), geo_size, Some(common))), _ => None } } else { None }; - if let Some((s, geo_size)) = s { + if let Some((s, geo_size, common)) = s { let half_min_dim = (geo_size.width as u32).min(geo_size.height as u32) / 2; if let Some(radii) = v { @@ -1783,7 +1828,15 @@ impl SctkState { }; _ = self.corner_radii.insert(id, (SctkCornerRadius(Arc::new(protocol_object)), Some(adjusted_radii.clone()))); } + if let Some(common) = &common { + let mut guard = common.lock().unwrap(); + guard.corner_radius = self.corner_radii.get(&id).map(|(object, _)| object.clone()); + guard.requested_corner_radius = Some(radii); + } } else { + if let Some(common) = &common { + common.lock().unwrap().requested_corner_radius = None; + } if let Some(old) = self.corner_radii.get_mut(&id) { match old.0.0.as_ref() { CornerRadiusWrapper::Xdg(protocol_object) => protocol_object.unset_radius(), diff --git a/winit/src/platform_specific/wayland/winit_window.rs b/winit/src/platform_specific/wayland/winit_window.rs index b33b7f9e..86d3e231 100644 --- a/winit/src/platform_specific/wayland/winit_window.rs +++ b/winit/src/platform_specific/wayland/winit_window.rs @@ -145,6 +145,8 @@ impl winit::window::Window for SctkWinitWindow { guard.size.height as i32, ); } + let (width, height) = (guard.size.width, guard.size.height); + guard.set_corner_geometry(width, height); } CommonSurface::Layer(layer_surface) => { guard.requested_size = ( @@ -171,6 +173,8 @@ impl winit::window::Window for SctkWinitWindow { guard.size.height as i32, ); } + let (width, height) = (guard.size.width, guard.size.height); + guard.set_corner_geometry(width, height); } CommonSurface::Lock(_) => {} CommonSurface::Subsurface { .. } => { From 775abd45d189abf657b130bec8b98d2bbc49166e Mon Sep 17 00:00:00 2001 From: Hojjat Date: Mon, 13 Jul 2026 14:15:25 -0600 Subject: [PATCH 05/20] Revert "fix: validate corner radius against window geometry" This reverts commit 5da1188557b58cdbe1951c72aad4360ebe05f5f4. --- .../wayland/event_loop/state.rs | 65 ++----------------- .../platform_specific/wayland/winit_window.rs | 4 -- 2 files changed, 6 insertions(+), 63 deletions(-) diff --git a/winit/src/platform_specific/wayland/event_loop/state.rs b/winit/src/platform_specific/wayland/event_loop/state.rs index 805bfaff..3cbc21cb 100644 --- a/winit/src/platform_specific/wayland/event_loop/state.rs +++ b/winit/src/platform_specific/wayland/event_loop/state.rs @@ -238,43 +238,6 @@ pub struct Common { pub(crate) size: LogicalSize, pub(crate) requested_size: (Option, Option), pub(crate) wp_viewport: Option, - pub(crate) corner_radius: Option, - pub(crate) requested_corner_radius: Option, - /// Geometry last committed via `set_window_geometry`/`set_size` - /// This is what compositor validates the corner radius against - pub(crate) corner_geometry: LogicalSize, -} - -impl Common { - pub(crate) fn set_corner_geometry(&mut self, width: u32, height: u32) { - self.corner_geometry = LogicalSize::new(width, height); - self.apply_corner_radius(); - } - - pub(crate) fn apply_corner_radius(&self) { - let (Some(radius_object), Some(requested)) = - (self.corner_radius.as_ref(), self.requested_corner_radius) - else { - return; - }; - let max_radius = - self.corner_geometry.width.min(self.corner_geometry.height) / 2; - let clamp = |radius: u32| radius.min(max_radius); - match radius_object.0.as_ref() { - CornerRadiusWrapper::Xdg(surface) => surface.set_radius( - clamp(requested.top_left), - clamp(requested.top_right), - clamp(requested.bottom_right), - clamp(requested.bottom_left), - ), - CornerRadiusWrapper::Wlr(surface) => surface.set_radius( - clamp(requested.top_left), - clamp(requested.top_right), - clamp(requested.bottom_right), - clamp(requested.bottom_left), - ), - }; - } } impl Default for Common { @@ -287,9 +250,6 @@ impl Default for Common { size: LogicalSize::new(1, 1), requested_size: (None, None), wp_viewport: None, - corner_radius: None, - requested_corner_radius: None, - corner_geometry: LogicalSize::new(1, 1), } } } @@ -298,7 +258,6 @@ impl From> for Common { fn from(value: LogicalSize) -> Self { Common { size: value, - corner_geometry: value, ..Default::default() } } @@ -331,7 +290,6 @@ impl SctkPopup { // update positioner self.data.positioner.set_size(w as i32, h as i32); self.popup.reposition(&self.data.positioner, token); - self.common.lock().unwrap().set_corner_geometry(w, h); } pub(crate) fn update_viewport(&mut self, w: u32, h: u32) { @@ -1531,7 +1489,6 @@ impl SctkState { sctk_popup.popup .xdg_surface() .set_window_geometry(0, 0, w as i32, h as i32); - sctk_popup.common.lock().unwrap().set_corner_geometry(w, h); sctk_popup.update_viewport(w, h); // update positioner sctk_popup.data.positioner.set_size(w as i32, h as i32); @@ -1749,22 +1706,20 @@ impl SctkState { Wlr(ZwlrLayerSurfaceV1), } let s = if let Some(w) = self.windows.iter_mut().find(|w| w.id == id) { - Some((Surface::Xdg(w.xdg_surface(&self.connection), Some(w.xdg_toplevel(&self.connection))), w.window.surface_size().cast::().to_logical(w.window.scale_factor()), None)) + Some((Surface::Xdg(w.xdg_surface(&self.connection), Some(w.xdg_toplevel(&self.connection))), w.window.surface_size().cast::().to_logical(w.window.scale_factor()))) } else if let Some(p) = self.popups.iter_mut().find(|w| w.data.id == id) { - let common = p.common.clone(); - let geo_size = common.lock().unwrap().corner_geometry.cast::(); - Some((Surface::Xdg(p.popup.xdg_surface().clone(), None), geo_size, Some(common))) + let guard = p.common.lock().unwrap(); + Some((Surface::Xdg(p.popup.xdg_surface().clone(), None), guard.size.cast::())) } else if let Some(l) = self.layer_surfaces.iter_mut().find(|l| l.id == id) { - let common = l.common.clone(); - let geo_size = common.lock().unwrap().corner_geometry.cast::(); + let guard = l.common.lock().unwrap(); match l.surface.kind() { - SurfaceKind::Wlr(l) => Some((Surface::Wlr(l.clone()), geo_size, Some(common))), + SurfaceKind::Wlr(l) => Some((Surface::Wlr(l.clone()), guard.size.cast::())), _ => None } } else { None }; - if let Some((s, geo_size, common)) = s { + if let Some((s, geo_size)) = s { let half_min_dim = (geo_size.width as u32).min(geo_size.height as u32) / 2; if let Some(radii) = v { @@ -1828,15 +1783,7 @@ impl SctkState { }; _ = self.corner_radii.insert(id, (SctkCornerRadius(Arc::new(protocol_object)), Some(adjusted_radii.clone()))); } - if let Some(common) = &common { - let mut guard = common.lock().unwrap(); - guard.corner_radius = self.corner_radii.get(&id).map(|(object, _)| object.clone()); - guard.requested_corner_radius = Some(radii); - } } else { - if let Some(common) = &common { - common.lock().unwrap().requested_corner_radius = None; - } if let Some(old) = self.corner_radii.get_mut(&id) { match old.0.0.as_ref() { CornerRadiusWrapper::Xdg(protocol_object) => protocol_object.unset_radius(), diff --git a/winit/src/platform_specific/wayland/winit_window.rs b/winit/src/platform_specific/wayland/winit_window.rs index 86d3e231..b33b7f9e 100644 --- a/winit/src/platform_specific/wayland/winit_window.rs +++ b/winit/src/platform_specific/wayland/winit_window.rs @@ -145,8 +145,6 @@ impl winit::window::Window for SctkWinitWindow { guard.size.height as i32, ); } - let (width, height) = (guard.size.width, guard.size.height); - guard.set_corner_geometry(width, height); } CommonSurface::Layer(layer_surface) => { guard.requested_size = ( @@ -173,8 +171,6 @@ impl winit::window::Window for SctkWinitWindow { guard.size.height as i32, ); } - let (width, height) = (guard.size.width, guard.size.height); - guard.set_corner_geometry(width, height); } CommonSurface::Lock(_) => {} CommonSurface::Subsurface { .. } => { From c1952328750f405250a5cc9817eec6f9e1e36dc1 Mon Sep 17 00:00:00 2001 From: Hojjat Date: Mon, 13 Jul 2026 14:15:59 -0600 Subject: [PATCH 06/20] =?UTF-8?q?fix:=20avoid=201=C3=971=20popup=20geometr?= =?UTF-8?q?y=20that=20trips=20corner-radius=20validation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- winit/src/platform_specific/wayland/event_loop/state.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/winit/src/platform_specific/wayland/event_loop/state.rs b/winit/src/platform_specific/wayland/event_loop/state.rs index 3cbc21cb..ec0e53ce 100644 --- a/winit/src/platform_specific/wayland/event_loop/state.rs +++ b/winit/src/platform_specific/wayland/event_loop/state.rs @@ -1268,11 +1268,11 @@ impl SctkState { || self.layer_surfaces.iter().any(|l| l.id == settings.parent && p.data.parent.wl_surface() == l.surface.wl_surface())) ) { let existing = &mut self.popups[existing]; - let size = if settings.positioner.size.is_none() { - log::info!("No configured popup size"); - (1, 1) + let size = if let Some(size) = settings.positioner.size { + size } else { - settings.positioner.size.unwrap() + let guard = existing.common.lock().unwrap(); + (guard.size.width, guard.size.height) }; let Ok(positioner) = XdgPositioner::new(&self.xdg_shell_state) .map_err(PopupCreationError::PositionerCreationFailed) else { From f6daee14ac8f7cf090a5413ee1576aa59649a956 Mon Sep 17 00:00:00 2001 From: Ilia Malanin Date: Sun, 5 Jul 2026 14:06:04 +0200 Subject: [PATCH 07/20] fix: avoid panic on sub-pixel rounded borders --- tiny_skia/src/engine.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tiny_skia/src/engine.rs b/tiny_skia/src/engine.rs index 61323f04..9f0b54f2 100644 --- a/tiny_skia/src/engine.rs +++ b/tiny_skia/src/engine.rs @@ -263,6 +263,10 @@ impl Engine { } else { // Draw corners that have too small border radii as having no border radius, // but mask them with the rounded rectangle with the correct border radius. + if path_bounds.width < 1.0 || path_bounds.height < 1.0 { + return; + } + let mut temp_pixmap = tiny_skia::Pixmap::new( path_bounds.width as u32, path_bounds.height as u32, From b3b0ab1cd57aa1b90f42bc9aa1efd558f0a1ff52 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Wed, 15 Jul 2026 12:34:42 -0400 Subject: [PATCH 08/20] fix: feature gates --- Cargo.lock | 13 +++++++++++ Cargo.toml | 23 ++++++++++++-------- build.rs | 3 +++ build_helpers/Cargo.toml | 17 +++++++++++++++ build_helpers/src/lib.rs | 23 ++++++++++++++++++++ core/Cargo.toml | 10 +++++++-- core/build.rs | 3 +++ core/src/event.rs | 5 +++-- runtime/Cargo.toml | 11 +++++++--- runtime/build.rs | 3 +++ runtime/src/platform_specific/mod.rs | 8 +++---- runtime/src/window.rs | 2 +- src/lib.rs | 2 +- wgpu/Cargo.toml | 5 ++++- wgpu/build.rs | 3 +++ wgpu/src/window.rs | 6 +----- wgpu/src/window/compositor.rs | 23 +++++--------------- wgpu/src/window/wayland.rs | 6 +++--- widget/Cargo.toml | 11 +++++++--- widget/build.rs | 3 +++ winit/Cargo.toml | 30 +++++++++++++++----------- winit/build.rs | 3 +++ winit/src/clipboard.rs | 2 +- winit/src/conversion.rs | 8 +++---- winit/src/lib.rs | 22 ++++++++----------- winit/src/platform_specific/mod.rs | 32 ++++++++++++---------------- 26 files changed, 176 insertions(+), 101 deletions(-) create mode 100644 build.rs create mode 100644 build_helpers/Cargo.toml create mode 100644 build_helpers/src/lib.rs create mode 100644 core/build.rs create mode 100644 runtime/build.rs create mode 100644 wgpu/build.rs create mode 100644 widget/build.rs create mode 100644 winit/build.rs diff --git a/Cargo.lock b/Cargo.lock index 3fe192d4..b309db1d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -787,6 +787,13 @@ dependencies = [ "cfg_aliases", ] +[[package]] +name = "build_helpers" +version = "0.14.0" +dependencies = [ + "cfg_aliases", +] + [[package]] name = "built" version = "0.8.0" @@ -2957,6 +2964,7 @@ dependencies = [ name = "iced" version = "0.14.0" dependencies = [ + "build_helpers", "criterion", "dnd", "iced_accessibility", @@ -3008,6 +3016,7 @@ version = "0.14.0" dependencies = [ "approx", "bitflags 2.11.0", + "build_helpers", "bytes", "cosmic-client-toolkit", "dnd", @@ -3114,6 +3123,7 @@ dependencies = [ name = "iced_runtime" version = "0.14.0" dependencies = [ + "build_helpers", "bytes", "cosmic-client-toolkit", "dnd", @@ -3181,6 +3191,7 @@ version = "0.14.0" dependencies = [ "as-raw-xcb-connection", "bitflags 2.11.0", + "build_helpers", "bytemuck", "cosmic-client-toolkit", "cryoglyph", @@ -3210,6 +3221,7 @@ dependencies = [ name = "iced_widget" version = "0.14.2" dependencies = [ + "build_helpers", "cosmic-client-toolkit", "dnd", "iced_accessibility", @@ -3231,6 +3243,7 @@ dependencies = [ name = "iced_winit" version = "0.14.0" dependencies = [ + "build_helpers", "cosmic-client-toolkit", "cursor-icon", "dnd", diff --git a/Cargo.toml b/Cargo.toml index 0bbcfebe..27ac2ca0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -118,13 +118,17 @@ winit = [ "iced_accessibility?/accesskit_winit", "iced_program/winit", ] -wayland = ["iced_renderer/wayland", "iced_winit/wayland"] -cctk = ["iced_winit/cctk", "iced_widget/cctk", "iced_core/cctk", "wayland"] -# Enables the sctk shell. +wayland = [ + "iced_renderer/wayland", + "iced_winit/wayland", + "iced_runtime/wayland", + "iced_widget/wayland", + "iced_core/wayland", +] + [dependencies] - - iced_devtools.workspace = true +iced_devtools.optional = true iced_debug.workspace = true iced_program.workspace = true @@ -134,10 +138,9 @@ iced_renderer.workspace = true iced_runtime.workspace = true iced_widget.workspace = true iced_winit.workspace = true -iced_devtools.optional = true +iced_winit.optional = true iced_tester.workspace = true iced_tester.optional = true -iced_winit.optional = true iced_highlighter.workspace = true iced_highlighter.optional = true iced_accessibility.workspace = true @@ -190,6 +193,7 @@ members = [ "winit", "examples/*", "accessibility", + "build_helpers", ] exclude = ["examples/integration"] @@ -308,8 +312,6 @@ winit = { git = "https://github.com/pop-os/winit.git", tag = "cosmic-0.14" } winit-core = { git = "https://github.com/pop-os/winit.git", tag = "cosmic-0.14" } cursor-icon = "1.1.0" -sctk = { package = "smithay-client-toolkit", version = "0.20.0" } - [workspace.lints.rust] rust_2018_idioms = { level = "deny", priority = -1 } unused_results = "deny" @@ -334,3 +336,6 @@ useless_conversion = "deny" [workspace.lints.rustdoc] broken_intra_doc_links = "forbid" + +[build-dependencies] +build_helpers = { path = "./build_helpers" } diff --git a/build.rs b/build.rs new file mode 100644 index 00000000..db00a773 --- /dev/null +++ b/build.rs @@ -0,0 +1,3 @@ +fn main() { + build_helpers::cfg_aliases_setup(); +} diff --git a/build_helpers/Cargo.toml b/build_helpers/Cargo.toml new file mode 100644 index 00000000..ff319f69 --- /dev/null +++ b/build_helpers/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "build_helpers" +version.workspace = true +authors.workspace = true +edition.workspace = true +license.workspace = true +repository.workspace = true +homepage.workspace = true +categories.workspace = true +keywords.workspace = true +rust-version.workspace = true + +[dependencies] +cfg_aliases = { version = "0.2.1" } + +[lints] +workspace = true diff --git a/build_helpers/src/lib.rs b/build_helpers/src/lib.rs new file mode 100644 index 00000000..e9ac85a5 --- /dev/null +++ b/build_helpers/src/lib.rs @@ -0,0 +1,23 @@ +use cfg_aliases::cfg_aliases; + +pub fn cfg_aliases_setup() { + // The script doesn't depend on our code + println!("cargo:rerun-if-changed=build.rs"); + + // Setup cfg aliases + cfg_aliases! { + // Systems. + android_platform: { target_os = "android" }, + wasm_platform: { all(target_family = "wasm", not(target_os = "emscripten")) }, + macos_platform: { target_os = "macos" }, + ios_platform: { target_os = "ios" }, + windows_platform: { target_os = "windows" }, + apple: { any(target_os = "ios", target_os = "macos") }, + free_unix: { all(unix, not(apple), not(android_platform), not(target_os = "emscripten")) }, + redox: { target_os = "redox" }, + + // Native displays. + wayland_platform: { all(feature = "wayland", free_unix, not(wasm), not(redox)) }, + orbital_platform: { redox }, + } +} diff --git a/core/Cargo.toml b/core/Cargo.toml index 0a376b7c..f3136a87 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -19,6 +19,7 @@ crisp = [] basic-shaping = [] advanced-shaping = [] a11y = ["iced_accessibility"] +wayland = ["cctk"] [dependencies] palette = "0.7" @@ -43,8 +44,6 @@ window_clipboard.workspace = true dnd.workspace = true mime.workspace = true -cctk.workspace = true -cctk.optional = true # /TODO(POP) [dependencies.iced_accessibility] version = "0.1.0" @@ -56,3 +55,10 @@ raw-window-handle.workspace = true [dev-dependencies] approx = "0.5" + +[target.'cfg(all(unix, not(any(target_os = "redox", target_family = "wasm", target_os = "android", target_vendor = "apple"))))'.dependencies] +cctk.workspace = true +cctk.optional = true + +[build-dependencies] +build_helpers = { path = "../build_helpers" } diff --git a/core/build.rs b/core/build.rs new file mode 100644 index 00000000..db00a773 --- /dev/null +++ b/core/build.rs @@ -0,0 +1,3 @@ +fn main() { + build_helpers::cfg_aliases_setup(); +} diff --git a/core/src/event.rs b/core/src/event.rs index 1aaf4ff4..b4a28a29 100644 --- a/core/src/event.rs +++ b/core/src/event.rs @@ -7,7 +7,8 @@ use crate::keyboard; use crate::mouse; use crate::touch; use crate::window; -#[cfg(all(feature = "cctk", target_os = "linux"))] + +#[cfg(wayland_platform)] /// A platform specific event for wayland pub mod wayland; /// A user interface event. @@ -49,7 +50,7 @@ pub enum Event { /// A platform specific event #[derive(Debug, Clone, PartialEq)] pub enum PlatformSpecific { - #[cfg(all(feature = "cctk", target_os = "linux"))] + #[cfg(wayland_platform)] /// A Wayland specific event Wayland(wayland::Event), } diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index ea4741d1..1cb23e23 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -17,7 +17,7 @@ workspace = true debug = [] selector = ["dep:iced_selector"] a11y = ["iced_accessibility", "iced_core/a11y"] -cctk = ["iced_core/cctk", "dep:cctk"] +wayland = ["iced_core/wayland", "dep:cctk"] [dependencies] bytes.workspace = true @@ -33,9 +33,14 @@ sipper.optional = true iced_selector.workspace = true iced_selector.optional = true iced_futures.features = ["thread-pool"] -cctk.workspace = true -cctk.optional = true iced_accessibility.workspace = true iced_accessibility.optional = true window_clipboard.workspace = true dnd.workspace = true + +[target.'cfg(all(unix, not(any(target_os = "redox", target_family = "wasm", target_os = "android", target_vendor = "apple"))))'.dependencies] +cctk.workspace = true +cctk.optional = true + +[build-dependencies] +build_helpers = { path = "../build_helpers" } diff --git a/runtime/build.rs b/runtime/build.rs new file mode 100644 index 00000000..db00a773 --- /dev/null +++ b/runtime/build.rs @@ -0,0 +1,3 @@ +fn main() { + build_helpers::cfg_aliases_setup(); +} diff --git a/runtime/src/platform_specific/mod.rs b/runtime/src/platform_specific/mod.rs index 4ef5ad9f..9cc66ddd 100644 --- a/runtime/src/platform_specific/mod.rs +++ b/runtime/src/platform_specific/mod.rs @@ -2,23 +2,23 @@ use std::fmt; -#[cfg(all(feature = "cctk", target_os = "linux"))] +#[cfg(wayland_platform)] /// Platform specific actions defined for wayland pub mod wayland; /// Platform specific actions defined for wayland pub enum Action { /// Wayland Specific Actions - #[cfg(all(feature = "cctk", target_os = "linux"))] + #[cfg(wayland_platform)] Wayland(wayland::Action), } impl fmt::Debug for Action { fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - #[cfg(all(feature = "cctk", target_os = "linux"))] + #[cfg(wayland_platform)] Action::Wayland(action) => action.fmt(_f), - #[cfg(not(all(feature = "cctk", target_os = "linux")))] + #[cfg(not(wayland_platform))] _ => Ok(()), } } diff --git a/runtime/src/window.rs b/runtime/src/window.rs index 4d2f5650..ae6445ec 100644 --- a/runtime/src/window.rs +++ b/runtime/src/window.rs @@ -222,7 +222,7 @@ pub fn frames() -> Subscription<(Id, Instant)> { _ => None, }) } -#[cfg(all(feature = "cctk", target_os = "linux"))] +#[cfg(wayland_platform)] /// Subscribes to the frames of the window of the running application. /// /// The resulting [`Subscription`] will produce items at a rate equal to the diff --git a/src/lib.rs b/src/lib.rs index 6e57128b..28870ee2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -606,7 +606,7 @@ pub mod font { pub mod event { //! Handle events of a user interface. pub use crate::core::event::PlatformSpecific; - #[cfg(all(feature = "cctk", target_os = "linux"))] + #[cfg(wayland_platform)] pub use crate::core::event::wayland; pub use crate::core::event::{Event, Status}; pub use iced_futures::event::{listen, listen_raw, listen_with}; diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml index f347f363..1d8ece88 100644 --- a/wgpu/Cargo.toml +++ b/wgpu/Cargo.toml @@ -25,6 +25,7 @@ svg = ["iced_graphics/svg", "resvg/text"] web-colors = ["iced_graphics/web-colors"] webgl = ["wgpu/webgl"] strict-assertions = [] +wayland = ["cctk"] [dependencies] iced_debug.workspace = true @@ -65,4 +66,6 @@ x11rb = { version = "0.13.1", features = [ "dri3", "randr", ] } -sctk.workspace = true + +[build-dependencies] +build_helpers = { path = "../build_helpers" } diff --git a/wgpu/build.rs b/wgpu/build.rs new file mode 100644 index 00000000..db00a773 --- /dev/null +++ b/wgpu/build.rs @@ -0,0 +1,3 @@ +fn main() { + build_helpers::cfg_aliases_setup(); +} diff --git a/wgpu/src/window.rs b/wgpu/src/window.rs index 385041c2..af90dd78 100644 --- a/wgpu/src/window.rs +++ b/wgpu/src/window.rs @@ -1,10 +1,6 @@ //! Display rendering results on windows. pub mod compositor; -#[cfg(all( - unix, - not(target_os = "macos"), - not(target_os = "redox") -))] +#[cfg(wayland_platform)] mod wayland; #[cfg(all(unix, not(target_os = "macos"), not(target_os = "redox")))] mod x11; diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs index 2269b9b7..f0c39208 100644 --- a/wgpu/src/window/compositor.rs +++ b/wgpu/src/window/compositor.rs @@ -9,15 +9,10 @@ use crate::graphics::{self, Shell, Viewport}; use crate::settings::{self, Settings}; use crate::{Engine, Renderer}; -#[cfg(all( - unix, - not(target_os = "macos"), - not(target_os = "redox") -))] +#[cfg(wayland_platform)] use super::wayland::get_wayland_device_ids; -#[cfg(all(unix, not(target_os = "macos"), not(target_os = "redox")))] +#[cfg(wayland_platform)] use super::x11::get_x11_device_ids; -use std::future::Future; /// A window graphics backend for iced powered by `wgpu`. pub struct Compositor { @@ -64,11 +59,7 @@ impl Compositor { compatible_window: Option, shell: Shell, ) -> Result { - #[cfg(all( - unix, - not(target_os = "macos"), - not(target_os = "redox") - ))] + #[cfg(wayland_platform)] let ids = compatible_window.as_ref().and_then(|window| { get_wayland_device_ids(window) .or_else(|| get_x11_device_ids(window)) @@ -80,7 +71,7 @@ impl Compositor { // 3. and the user didn't set an adapter name, // 4. and the user didn't request the high power pref // => don't load the nvidia icd, as it might power on the gpu in hybrid setups causing severe delays - #[cfg(all(unix, not(target_os = "macos"), not(target_os = "redox")))] + #[cfg(wayland_platform)] if !matches!(ids, Some((0x10de, _))) && std::env::var_os("__NV_PRIME_RENDER_OFFLOAD") .is_none_or(|var| var == "0") @@ -140,11 +131,7 @@ impl Compositor { let mut adapter = None; #[cfg_attr(not(unix), allow(dead_code))] if std::env::var_os("WGPU_ADAPTER_NAME").is_none() { - #[cfg(all( - unix, - not(target_os = "macos"), - not(target_os = "redox") - ))] + #[cfg(wayland_platform)] if let Some((vendor_id, device_id)) = ids { adapter = instance .enumerate_adapters(settings.backends) diff --git a/wgpu/src/window/wayland.rs b/wgpu/src/window/wayland.rs index af448d94..48e00def 100644 --- a/wgpu/src/window/wayland.rs +++ b/wgpu/src/window/wayland.rs @@ -1,5 +1,5 @@ use crate::graphics::compositor::Window; -use sctk::{ +use cctk::sctk::{ dmabuf::{DmabufFeedback, DmabufHandler, DmabufState}, registry::{ProvidesRegistryState, RegistryState}, registry_handlers, @@ -111,5 +111,5 @@ pub fn get_wayland_device_ids(window: &W) -> Option<(u16, u16)> { } } -sctk::delegate_dmabuf!(AppData); -sctk::delegate_registry!(AppData); +cctk::sctk::delegate_dmabuf!(AppData); +cctk::sctk::delegate_registry!(AppData); diff --git a/widget/Cargo.toml b/widget/Cargo.toml index ab34819b..0726ae40 100644 --- a/widget/Cargo.toml +++ b/widget/Cargo.toml @@ -29,15 +29,13 @@ highlighter = ["dep:iced_highlighter"] advanced = [] crisp = [] a11y = ["iced_accessibility"] -cctk = ["iced_runtime/cctk", "dep:cctk"] +wayland = ["iced_runtime/wayland", "dep:cctk"] [dependencies] iced_renderer.workspace = true iced_runtime.workspace = true iced_accessibility.workspace = true iced_accessibility.optional = true -cctk.workspace = true -cctk.optional = true num-traits.workspace = true log.workspace = true rustc-hash.workspace = true @@ -57,3 +55,10 @@ pulldown-cmark.optional = true iced_highlighter.workspace = true iced_highlighter.optional = true + +[target.'cfg(all(unix, not(any(target_os = "redox", target_family = "wasm", target_os = "android", target_vendor = "apple"))))'.dependencies] +cctk.workspace = true +cctk.optional = true + +[build-dependencies] +build_helpers = { path = "../build_helpers" } diff --git a/widget/build.rs b/widget/build.rs new file mode 100644 index 00000000..db00a773 --- /dev/null +++ b/widget/build.rs @@ -0,0 +1,3 @@ +fn main() { + build_helpers::cfg_aliases_setup(); +} diff --git a/winit/Cargo.toml b/winit/Cargo.toml index 41e4a582..741528b5 100644 --- a/winit/Cargo.toml +++ b/winit/Cargo.toml @@ -14,7 +14,18 @@ keywords.workspace = true workspace = true [features] -wayland = ["winit/wayland", "wayland-csd-adwaita"] +wayland = [ + "winit/wayland", + "wayland-csd-adwaita", + "wayland-protocols", + "raw-window-handle", + "iced_runtime/wayland", + "wayland-backend", + "xkbcommon", + "xkbcommon-dl", + "xkeysym", + "dep:cctk", +] default = ["x11", "wayland-dlopen"] debug = ["iced_debug/enable"] sysinfo = ["dep:sysinfo"] @@ -26,17 +37,6 @@ program = [] wayland-dlopen = ["winit/wayland-dlopen"] wayland-csd-adwaita = ["winit/wayland-csd-adwaita"] a11y = ["iced_accessibility", "iced_runtime/a11y"] -cctk = [ - "wayland", - "wayland-protocols", - "raw-window-handle", - "iced_runtime/cctk", - "wayland-backend", - "xkbcommon", - "xkbcommon-dl", - "xkeysym", - "dep:cctk", -] # Prevents multiple separate process instances. single-instance = [] @@ -64,7 +64,8 @@ iced_debug.workspace = true iced_program.workspace = true -[target.'cfg(target_os = "linux")'.dependencies] +[target.'cfg(all(unix, not(any(target_os = "redox", target_family = "wasm", target_os = "android", target_vendor = "apple"))))'.dependencies] + mundy.workspace = true mundy.optional = true @@ -89,3 +90,6 @@ winapi.workspace = true web-sys.workspace = true web-sys.features = ["Document", "Window", "HtmlCanvasElement"] wasm-bindgen-futures.workspace = true + +[build-dependencies] +build_helpers = { path = "../build_helpers" } diff --git a/winit/build.rs b/winit/build.rs new file mode 100644 index 00000000..db00a773 --- /dev/null +++ b/winit/build.rs @@ -0,0 +1,3 @@ +fn main() { + build_helpers::cfg_aliases_setup(); +} diff --git a/winit/src/clipboard.rs b/winit/src/clipboard.rs index d302ac36..2c9e4a32 100644 --- a/winit/src/clipboard.rs +++ b/winit/src/clipboard.rs @@ -92,7 +92,7 @@ impl Clipboard { }) .unwrap_or(State::Unavailable); - #[cfg(target_os = "linux")] + #[cfg(wayland_platform)] if let State::Connected { clipboard, .. } = &state { clipboard.init_dnd(Box::new(sender)); } diff --git a/winit/src/conversion.rs b/winit/src/conversion.rs index 97cc97a6..d385266e 100644 --- a/winit/src/conversion.rs +++ b/winit/src/conversion.rs @@ -424,7 +424,7 @@ pub fn window_event( WindowEvent::ScaleFactorChanged { scale_factor, .. } => { Some(Event::Window(window::Event::Rescaled(scale_factor as f32))) } - #[cfg(all(feature = "cctk", target_os = "linux"))] + #[cfg(wayland_platform)] WindowEvent::SuggestedBounds(bounds) => { let size = bounds.map(|bounds| { let size = bounds.to_logical(scale_factor); @@ -437,7 +437,7 @@ pub fn window_event( ), ))) } - #[cfg(all(feature = "cctk", target_os = "linux"))] + #[cfg(wayland_platform)] WindowEvent::WindowStateChanged => { use cctk::sctk::reexports::csd_frame::WindowState; use winit::platform::wayland::WindowExtWayland; @@ -1491,7 +1491,7 @@ pub fn winit_key_code( }) } -#[cfg(all(feature = "cctk", target_os = "linux"))] +#[cfg(wayland_platform)] fn winit_native_key_code( keycode: keyboard::key::NativeCode, ) -> winit::keyboard::NativeKeyCode { @@ -1515,7 +1515,7 @@ fn winit_native_key_code( } /// Reconstruct the raw keycode -#[cfg(all(feature = "cctk", target_os = "linux"))] +#[cfg(wayland_platform)] pub fn physical_to_scancode(physical: keyboard::key::Physical) -> Option { let Some(physical_key) = (match physical { keyboard::key::Physical::Code(code) => { diff --git a/winit/src/lib.rs b/winit/src/lib.rs index 517eddbc..9b631321 100644 --- a/winit/src/lib.rs +++ b/winit/src/lib.rs @@ -47,7 +47,6 @@ mod window; pub use clipboard::Clipboard; pub use error::Error; pub use proxy::Proxy; -use winit::dpi::LogicalSize; use winit::dpi::PhysicalPosition; use winit::dpi::PhysicalSize; @@ -92,10 +91,10 @@ where let event_loop = EventLoop::new().expect("Create event loop"); - #[cfg(all(feature = "cctk", target_os = "linux"))] + #[cfg(wayland_platform)] let is_wayland = winit::platform::wayland::EventLoopExtWayland::is_wayland(&event_loop); - #[cfg(not(all(feature = "cctk", target_os = "linux")))] + #[cfg(not(wayland_platform))] let is_wayland = false; // TODO this is new.. @@ -260,7 +259,7 @@ where | winit::event::WindowEvent::Moved(_) ); - #[cfg(all(feature = "cctk", target_os = "linux"))] + #[cfg(wayland_platform)] { if matches!(event, WindowEvent::RedrawRequested) { for id in @@ -575,10 +574,7 @@ where .expect("Send event"); } Control::Winit(id, e) => { - #[cfg(all( - feature = "cctk", - target_os = "linux" - ))] + #[cfg(wayland_platform)] { if matches!(e, WindowEvent::RedrawRequested) { @@ -774,7 +770,7 @@ async fn run_instance

( let mut platform_specific_handler = crate::platform_specific::PlatformSpecific::default(); - #[cfg(all(feature = "cctk", target_os = "linux"))] + #[cfg(wayland_platform)] if is_wayland { platform_specific_handler = platform_specific_handler.with_wayland( control_sender.clone(), @@ -885,7 +881,7 @@ async fn run_instance

( on_open, resize_border, } => { - #[cfg(all(feature = "cctk", target_os = "linux"))] + #[cfg(wayland_platform)] platform_specific_handler.send_wayland( platform_specific::Action::TrackWindow(window.clone(), id), ); @@ -1054,7 +1050,7 @@ async fn run_instance

( continue; } // XX must force update to corner radius before the surface is committed. - #[cfg(all(feature = "cctk", target_os = "linux"))] + #[cfg(wayland_platform)] if (window.surface_version != window.state.surface_version() || window.logical_size() != window.state.logical_size()) && !crate::subsurface_widget::is_subsurface(window_id) @@ -1394,7 +1390,7 @@ async fn run_instance

( } }); let no_window_events = window_events.is_empty(); - #[cfg(all(feature = "cctk", target_os = "linux"))] + #[cfg(wayland_platform)] window_events.push(core::Event::PlatformSpecific( core::event::PlatformSpecific::Wayland( core::event::wayland::Event::RequestResize, @@ -2126,7 +2122,7 @@ where _ = control_sender.start_send(Control::Cleanup(id)).ok(); } let proxy = clipboard.proxy(); - #[cfg(all(feature = "cctk", target_os = "linux"))] + #[cfg(wayland_platform)] platform_specific .send_wayland(platform_specific::Action::RemoveWindow(id)); if let Some(window) = window_manager.remove(id) { diff --git a/winit/src/platform_specific/mod.rs b/winit/src/platform_specific/mod.rs index 9b74ee9c..969c8299 100644 --- a/winit/src/platform_specific/mod.rs +++ b/winit/src/platform_specific/mod.rs @@ -1,24 +1,20 @@ //! Wayland specific shell //! -use std::{borrow::Cow, collections::HashMap, sync::Arc}; +use std::collections::HashMap; -#[cfg(all(feature = "cctk", target_os = "linux"))] -use cctk::sctk::reexports::client::Connection; -use iced_graphics::{Compositor, compositor}; +use iced_graphics::compositor; use iced_runtime::{ core::{Vector, window}, - platform_specific, user_interface, + user_interface, }; use winit::raw_window_handle::HasWindowHandle; -#[cfg(all(feature = "cctk", target_os = "linux"))] +#[cfg(wayland_platform)] pub mod wayland; -#[cfg(all(feature = "cctk", target_os = "linux"))] +#[cfg(wayland_platform)] pub use wayland::*; -#[cfg(all(feature = "cctk", target_os = "linux"))] -use wayland_backend::client::Backend; use crate::{CreateCompositor, Program, WindowManager}; @@ -35,7 +31,7 @@ pub type UserInterfaces<'a, P> = HashMap< #[derive(Debug)] pub enum Event { - #[cfg(all(feature = "cctk", target_os = "linux"))] + #[cfg(wayland_platform)] Wayland(sctk_event::SctkEvent), } @@ -61,7 +57,7 @@ impl SurfaceIdWrapper { #[derive(Debug, Default)] pub struct PlatformSpecific { - #[cfg(all(feature = "cctk", target_os = "linux"))] + #[cfg(wayland_platform)] wayland: WaylandSpecific, } @@ -71,7 +67,7 @@ impl PlatformSpecific { action: iced_runtime::platform_specific::Action, ) { match action { - #[cfg(all(feature = "cctk", target_os = "linux"))] + #[cfg(wayland_platform)] iced_runtime::platform_specific::Action::Wayland(a) => { self.send_wayland(wayland::Action::Action(a)); } @@ -82,14 +78,14 @@ impl PlatformSpecific { &mut self, keep: F, ) { - #[cfg(all(feature = "cctk", target_os = "linux"))] + #[cfg(wayland_platform)] { self.wayland.retain_subsurfaces(keep); } } pub(crate) fn clear_subsurface_list(&mut self) { - #[cfg(all(feature = "cctk", target_os = "linux"))] + #[cfg(wayland_platform)] { self.wayland.clear_subsurface_list(); } @@ -100,7 +96,7 @@ impl PlatformSpecific { id: window::Id, window: &dyn HasWindowHandle, ) { - #[cfg(all(feature = "cctk", target_os = "linux"))] + #[cfg(wayland_platform)] { use cctk::sctk::reexports::client::{ Proxy, protocol::wl_surface::WlSurface, @@ -151,7 +147,7 @@ impl PlatformSpecific { pub(crate) fn create_surface( &mut self, ) -> Option> { - #[cfg(all(feature = "cctk", target_os = "linux"))] + #[cfg(wayland_platform)] { return self.wayland.create_surface(); } @@ -167,7 +163,7 @@ impl PlatformSpecific { data: &[u8], offset: Vector, ) { - #[cfg(all(feature = "cctk", target_os = "linux"))] + #[cfg(wayland_platform)] { return self.wayland.update_surface_shm( surface, width, height, scale, data, offset, @@ -195,7 +191,7 @@ pub(crate) async fn handle_event<'a, 'b, P>( P: Program, { match e { - #[cfg(all(feature = "cctk", target_os = "linux"))] + #[cfg(wayland_platform)] Event::Wayland(e) => { platform_specific .wayland From a7c71f8dd3914e9f83363bf7552c99cbbb62ab2c Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Wed, 15 Jul 2026 15:06:59 -0400 Subject: [PATCH 09/20] improv: feature gate for xdg_portal --- build_helpers/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/build_helpers/src/lib.rs b/build_helpers/src/lib.rs index e9ac85a5..364b6ed8 100644 --- a/build_helpers/src/lib.rs +++ b/build_helpers/src/lib.rs @@ -18,6 +18,7 @@ pub fn cfg_aliases_setup() { // Native displays. wayland_platform: { all(feature = "wayland", free_unix, not(wasm), not(redox)) }, + xdg_portal: { all(feature = "xdg-portal", free_unix, not(wasm), not(redox)) }, orbital_platform: { redox }, } } From 300fa97ee2bcc2a39239ecc780eee0bf31a82b9f Mon Sep 17 00:00:00 2001 From: Frederic Laing Date: Fri, 17 Jul 2026 12:20:49 +0200 Subject: [PATCH 10/20] fix: consume XDG activation token on window creation --- winit/src/conversion.rs | 42 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/winit/src/conversion.rs b/winit/src/conversion.rs index d385266e..8ce3ed66 100644 --- a/winit/src/conversion.rs +++ b/winit/src/conversion.rs @@ -23,6 +23,33 @@ use winit::event::Force; use winit::icon::IconProvider; use winit::keyboard::SmolStr; +/// Returns the activation token provided by the compositor, if any. +/// +/// The token is single-use, so it is only ever handed out to the first window. +#[cfg(target_os = "linux")] +fn take_activation_token() -> Option { + use std::sync::Mutex; + use std::sync::OnceLock; + use winit::platform::startup_notify::reset_activation_token_env; + + static TOKEN: OnceLock>> = + OnceLock::new(); + + TOKEN + .get_or_init(|| { + let token = std::env::var("XDG_ACTIVATION_TOKEN") + .ok() + .map(winit::window::ActivationToken::from_raw); + + reset_activation_token_env(); + + Mutex::new(token) + }) + .lock() + .ok() + .and_then(|mut token| token.take()) +} + /// Converts some [`window::Settings`] into some `WindowAttributes` from `winit`. pub fn window_attributes( settings: window::Settings, @@ -182,12 +209,19 @@ pub fn window_attributes( { use winit::platform::wayland::WindowAttributesWayland; - attributes = attributes.with_platform_attributes(Box::new( - WindowAttributesWayland::default().with_name( + let mut wayland_attributes = WindowAttributesWayland::default() + .with_name( &settings.platform_specific.application_id, &settings.platform_specific.application_id, - ), - )); + ); + + if let Some(token) = take_activation_token() { + wayland_attributes = + wayland_attributes.with_activation_token(token); + } + + attributes = attributes + .with_platform_attributes(Box::new(wayland_attributes)); } } From 3a82d48548af147b2cbf431f3ed03533e6f552ec Mon Sep 17 00:00:00 2001 From: RipleyTom Date: Sat, 11 Jul 2026 12:35:07 +0200 Subject: [PATCH 11/20] fix: ignore resize border on fullscreen/maximized --- winit/src/application/drag_resize.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/winit/src/application/drag_resize.rs b/winit/src/application/drag_resize.rs index 6d575b52..29fa10da 100644 --- a/winit/src/application/drag_resize.rs +++ b/winit/src/application/drag_resize.rs @@ -49,7 +49,10 @@ pub fn event_func( position, .. } => { - if !window.is_decorated() { + let resizable = !window.is_decorated() + && !window.is_maximized() + && window.fullscreen().is_none(); + if resizable { let location = cursor_resize_direction( window.surface_size(), *position, From ba4f09b7bfaa6231892c116f7539806c0f4132a5 Mon Sep 17 00:00:00 2001 From: Hojjat Date: Fri, 17 Jul 2026 14:16:31 -0600 Subject: [PATCH 12/20] fix: tear down dnd surface when the dnd is ended programatically --- winit/src/lib.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/winit/src/lib.rs b/winit/src/lib.rs index 9b631321..e552cded 100644 --- a/winit/src/lib.rs +++ b/winit/src/lib.rs @@ -855,6 +855,8 @@ async fn run_instance

( &mut is_window_opening, &mut system_theme, &mut platform_specific_handler, + &mut dnd_surface, + &mut dnd_surface_id, is_daemon, ) }; @@ -2068,6 +2070,10 @@ fn run_action<'a, P, C>( is_window_opening: &mut bool, system_theme: &mut theme::Mode, platform_specific: &mut crate::platform_specific::PlatformSpecific, + dnd_surface: &mut Option< + Arc>, + >, + dnd_surface_id: &mut Option, is_daemon: bool, ) -> bool where @@ -2583,6 +2589,10 @@ where } iced_runtime::dnd::DndAction::EndDnd => { clipboard.end_dnd(); + *dnd_surface = None; + if let Some(id) = dnd_surface_id.take() { + platform_specific.retain_subsurfaces(|other| other != id); + } } iced_runtime::dnd::DndAction::PeekDnd(m, channel) => { let data = clipboard.peek_dnd(m); From dc0e80edd8a25ada687d846cd6153fdde0c07da7 Mon Sep 17 00:00:00 2001 From: Inuxiuz Date: Sat, 11 Jul 2026 16:49:55 +0800 Subject: [PATCH 13/20] feat: add overflow option to Pin widget to allow content beyond boundaries --- widget/src/pin.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/widget/src/pin.rs b/widget/src/pin.rs index 8eb5906e..cef75944 100644 --- a/widget/src/pin.rs +++ b/widget/src/pin.rs @@ -60,6 +60,7 @@ where width: Length, height: Length, position: Point, + overflow: bool, } impl<'a, Message, Theme, Renderer> Pin<'a, Message, Theme, Renderer> @@ -75,6 +76,7 @@ where width: Length::Fill, height: Length::Fill, position: Point::ORIGIN, + overflow: false, } } @@ -107,6 +109,12 @@ where self.position.y = y.into().0; self } + + /// Sets whether the [`Pin`] can overflow its boundaries. + pub fn overflow(mut self, overflow: bool) -> Self { + self.overflow = overflow; + self + } } impl Widget @@ -145,8 +153,12 @@ where ) -> layout::Node { let limits = limits.width(self.width).height(self.height); - let available = - limits.max() - Size::new(self.position.x, self.position.y); + let available = + if self.overflow { + limits.max() + } else { + limits.max() - Size::new(self.position.x, self.position.y) + }; let node = self .content From 5a6cd771d15179803e950ec093fb3d2f84582ee1 Mon Sep 17 00:00:00 2001 From: sanua356 <51795446+sanua356@users.noreply.github.com> Date: Thu, 23 Jul 2026 21:15:43 +0300 Subject: [PATCH 14/20] fix: compiler error for e2k CPU architecture --- wgpu/src/window/x11.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/wgpu/src/window/x11.rs b/wgpu/src/window/x11.rs index 58da401a..a1508134 100644 --- a/wgpu/src/window/x11.rs +++ b/wgpu/src/window/x11.rs @@ -1,3 +1,5 @@ +#![allow(unexpected_cfgs)] + use std::{ fs, io::{BufRead, BufReader}, @@ -144,7 +146,9 @@ pub fn get_x11_device_ids(window: &W) -> Option<(u16, u16)> { { let stat = stat(Path::new("/dev/dri").join(device)).ok()?; - let dev = stat.st_rdev; + // Hack (u64 as u64) for E2K CPU architecture + #[allow(clippy::unnecessary_cast)] + let dev = stat.st_rdev as u64; return super::ids_from_dev(dev); } } @@ -165,7 +169,9 @@ pub fn get_x11_device_ids(window: &W) -> Option<(u16, u16)> { let dri3 = conn.dri3_open(root, x11rb::NONE).ok()?.reply().ok()?; let device_fd = dri3.device_fd; let stat = fstat(device_fd).ok()?; - let dev = stat.st_rdev; + // Hack (u64 as u64) for E2K CPU architecture + #[allow(clippy::unnecessary_cast)] + let dev = stat.st_rdev as u64; super::ids_from_dev(dev) } } From 65b5dbc67172208b0f9af1cf8a5a72f4017734cc Mon Sep 17 00:00:00 2001 From: Aadil <211808495+Aadil127@users.noreply.github.com> Date: Fri, 24 Jul 2026 12:55:32 +0530 Subject: [PATCH 15/20] feat(slider): add handle bounds to avoid handle shifting on hover (#357) --- widget/src/slider.rs | 105 ++++++++++++++++++++++++------------------- 1 file changed, 58 insertions(+), 47 deletions(-) diff --git a/widget/src/slider.rs b/widget/src/slider.rs index ff32f417..70cfc9e4 100644 --- a/widget/src/slider.rs +++ b/widget/src/slider.rs @@ -110,6 +110,8 @@ where height: f32, class: Theme::Class<'a>, status: Option, + handle_width: f32, + handle_height: f32, } impl<'a, T, Message, Theme> Slider<'a, T, Message, Theme> @@ -119,7 +121,13 @@ where Theme: Catalog, { /// The default height of a [`Slider`]. - pub const DEFAULT_HEIGHT: f32 = 16.0; + pub const DEFAULT_HEIGHT: f32 = 26.0; + + /// The default max height of a [`Handle`]. + pub const DEFAULT_MAX_HANDLE_HEIGHT: f32 = 26.0; + + /// The default max width of a [`Handle`]. + pub const DEFAULT_MAX_HANDLE_WIDTH: f32 = 26.0; /// Creates a new [`Slider`]. /// @@ -165,6 +173,8 @@ where height: Self::DEFAULT_HEIGHT, class: Theme::default(), status: None, + handle_width: Self::DEFAULT_MAX_HANDLE_WIDTH, + handle_height: Self::DEFAULT_MAX_HANDLE_HEIGHT, } } @@ -207,6 +217,24 @@ where self } + /// Sets the max width of the [`Handle`]. + /// + /// Theme can be used to change the size and shape of handle + /// but width of handle defined in theme will not exceed this width + pub fn handle_width(mut self, width: impl Into) -> Self { + self.handle_width = width.into().0; + self + } + + /// Sets the max height of the [`Handle`]. + /// + /// Theme can be used to change the size and shape of handle + /// but height of handle defined in theme will not exceed this height + pub fn handle_height(mut self, height: impl Into) -> Self { + self.handle_height = height.into().0; + self + } + /// Sets the step size of the [`Slider`]. pub fn step(mut self, step: impl Into) -> Self { self.step = step.into(); @@ -323,8 +351,15 @@ where let mut update = || { let current_value = self.value; + self.handle_width = self.handle_width.min(layout.bounds().width); + self.handle_height = self.handle_height.min(layout.bounds().height); + let locate = |cursor_position: Point| -> Option { - let bounds = layout.bounds(); + let bounds = Rectangle { + x: layout.bounds().x + self.handle_width / 2.0, + width: layout.bounds().width - self.handle_width, + ..layout.bounds() + }; if cursor_position.x <= bounds.x { Some(*self.range.start()) @@ -509,54 +544,30 @@ where _cursor: mouse::Cursor, _viewport: &Rectangle, ) { - let bounds = layout.bounds(); + let bounds = Rectangle { + x: layout.bounds().x + self.handle_width / 2.0, + width: layout.bounds().width - self.handle_width, + ..layout.bounds() + }; let style = theme.style(&self.class, self.status.unwrap_or(Status::Active)); - let border_width = style - .handle - .border_width - .min(bounds.height / 2.0) - .min(bounds.width / 2.0); - - let (handle_width, handle_height, handle_border_radius) = + let (mut handle_width, mut handle_height, handle_border_radius) = match style.handle.shape { HandleShape::Circle { radius } => { - let radius = (radius) - .max(2.0 * border_width) - .min(bounds.height / 2.0) - .min(bounds.width / 2.0 + 2.0 * border_width); (radius * 2.0, radius * 2.0, Radius::from(radius)) } HandleShape::Rectangle { height, width, border_radius, - } => { - let width = (f32::from(width)).max(2.0 * border_width); - let height = (f32::from(height)).max(2.0 * border_width); - let mut border_radius: [f32; 4] = border_radius.into(); - for r in &mut border_radius { - *r = (*r) - .min(height / 2.0) - .min(width / 2.0) - .max(*r * (width + border_width * 2.0) / width); - } - - ( - width, - height, - Radius { - top_left: border_radius[0], - top_right: border_radius[1], - bottom_right: border_radius[2], - bottom_left: border_radius[3], - }, - ) - } + } => (f32::from(width), f32::from(height), border_radius), }; + handle_width = handle_width.min(self.handle_width); + handle_height = handle_height.min(self.handle_height); + let value = self.value.into() as f32; let (range_start, range_end) = { let (start, end) = self.range.clone().into_inner(); @@ -567,8 +578,7 @@ where let offset = if range_start >= range_end { 0.0 } else { - (bounds.width - handle_width) * (value - range_start) - / (range_end - range_start) + bounds.width * (value - range_start) / (range_end - range_start) }; let rail_y = bounds.y + bounds.height / 2.0; @@ -590,7 +600,8 @@ where x: bounds.x + offset, y: rail_y + 6.0, width: BREAKPOINT_WIDTH, - height: 8.0, + height: 8.0_f32 + .min(bounds.y + bounds.height - (rail_y + 6.0)), }, border: Border { radius: 0.0.into(), @@ -607,9 +618,9 @@ where renderer::Quad { bounds: Rectangle { x: bounds.x, - y: rail_y - style.rail.width / 2.0, - width: offset + handle_width / 2.0, - height: style.rail.width, + y: rail_y - (style.rail.width).min(bounds.height) / 2.0, + width: offset, + height: (style.rail.width).min(bounds.height), }, border: style.rail.border, ..renderer::Quad::default() @@ -622,10 +633,10 @@ where renderer.fill_quad( renderer::Quad { bounds: Rectangle { - x: bounds.x + offset + handle_width / 2.0, - y: rail_y - style.rail.width / 2.0, - width: bounds.width - offset - handle_width / 2.0, - height: style.rail.width, + x: bounds.x + offset, + y: rail_y - (style.rail.width).min(bounds.height) / 2.0, + width: bounds.width - offset, + height: (style.rail.width).min(bounds.height), }, border: style.rail.border, ..renderer::Quad::default() @@ -637,7 +648,7 @@ where renderer.fill_quad( renderer::Quad { bounds: Rectangle { - x: bounds.x + offset, + x: bounds.x + offset - handle_width / 2.0, y: rail_y - (handle_height / 2.0), width: handle_width, height: handle_height, From f86d983896ca49fc4a2cfbc212301c56692a21ab Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Wed, 29 Jul 2026 11:19:16 -0400 Subject: [PATCH 16/20] fix: remove any old blur surface or corners on surface creation --- .../wayland/event_loop/state.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/winit/src/platform_specific/wayland/event_loop/state.rs b/winit/src/platform_specific/wayland/event_loop/state.rs index ec0e53ce..f4a8c5d7 100644 --- a/winit/src/platform_specific/wayland/event_loop/state.rs +++ b/winit/src/platform_specific/wayland/event_loop/state.rs @@ -874,6 +874,11 @@ impl SctkState { _ = wl_surface.frame(&self.queue_handle, wl_surface.clone()); + if let Some(old) = self.blur_surfaces.remove(&settings.id) { + old.destroy(); + } + _ = self.corner_radii.remove(&settings.id); + if let Some(blur) = self.pending_blur.remove(&settings.id) { self.apply_blur(settings.id, Some(blur), &wl_surface); } @@ -1011,6 +1016,12 @@ impl SctkState { layer_surface.set_input_region(Some(®ion)); region.destroy(); } + + if let Some(old) = self.blur_surfaces.remove(&id) { + old.destroy(); + } + _ = self.corner_radii.remove(&id); + if let Some(blur) = self.pending_blur.remove(&id) { self.apply_blur(id, Some(blur), &wl_surface); } @@ -2022,6 +2033,11 @@ impl SctkState { region.destroy(); } + if let Some(old) = self.blur_surfaces.remove(&settings.id) { + old.destroy(); + } + _ = self.corner_radii.remove(&settings.id); + if let Some(blur) = self.pending_blur.remove(&settings.id) { _ = self.apply_blur(settings.id, Some(blur), &wl_surface); } From 86b236f2e139e6543ccdac8ce40f7218cc051f4c Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Wed, 29 Jul 2026 11:19:52 -0400 Subject: [PATCH 17/20] fix: remove any old blur surface or corners on layer shell done event --- .../platform_specific/wayland/handlers/shell/layer.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/winit/src/platform_specific/wayland/handlers/shell/layer.rs b/winit/src/platform_specific/wayland/handlers/shell/layer.rs index 22fd6560..5e6bad57 100644 --- a/winit/src/platform_specific/wayland/handlers/shell/layer.rs +++ b/winit/src/platform_specific/wayland/handlers/shell/layer.rs @@ -27,6 +27,15 @@ impl LayerShellHandler for SctkState { None => return, }; + if let Some(id) = self.id_map.remove(&layer.surface.wl_surface().id()) { + if let Some(blurred) = self.blur_surfaces.remove(&id) { + blurred.destroy(); + } + _ = self.corner_radii.remove(&id); + + _ = self.destroyed.insert(id); + } + self.sctk_events.push(SctkEvent::LayerSurfaceEvent { variant: LayerSurfaceEventVariant::Done, id: layer.surface.wl_surface().clone(), From b87e660eedd486158919d2db82c4085ce52d734e Mon Sep 17 00:00:00 2001 From: Hojjat Date: Tue, 4 Aug 2026 11:49:05 -0600 Subject: [PATCH 18/20] perf: do not redraw on mouse move events --- winit/src/lib.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/winit/src/lib.rs b/winit/src/lib.rs index e552cded..21a2b38f 100644 --- a/winit/src/lib.rs +++ b/winit/src/lib.rs @@ -1391,7 +1391,6 @@ async fn run_instance

( true } }); - let no_window_events = window_events.is_empty(); #[cfg(wayland_platform)] window_events.push(core::Event::PlatformSpecific( core::event::PlatformSpecific::Wayland( @@ -1409,8 +1408,7 @@ async fn run_instance

( &mut clipboard, &mut messages, ); - let mut needs_redraw = - !no_window_events || !messages.is_empty(); + let mut needs_redraw = !messages.is_empty(); if let Some(requested_size) = clipboard.requested_logical_size.lock().unwrap().take() { @@ -1466,8 +1464,17 @@ async fn run_instance

( mouse_interaction, .. } => { + let mouse_changed = + window.mouse_interaction != mouse_interaction; + window.update_mouse(mouse_interaction); + if mouse_changed { + window.request_redraw( + core::window::RedrawRequest::NextFrame, + ); + } + #[cfg(not(feature = "unconditional-rendering"))] window.request_redraw(_redraw_request); } From f5aa5a6f8cc2db6e2adbbc140c310a5a4af2f8d2 Mon Sep 17 00:00:00 2001 From: Hojjat Date: Tue, 4 Aug 2026 17:00:59 -0600 Subject: [PATCH 19/20] fix: don't request redraw for pointer --- .../wayland/handlers/seat/pointer.rs | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/winit/src/platform_specific/wayland/handlers/seat/pointer.rs b/winit/src/platform_specific/wayland/handlers/seat/pointer.rs index 8c962a4d..b40912ec 100644 --- a/winit/src/platform_specific/wayland/handlers/seat/pointer.rs +++ b/winit/src/platform_specific/wayland/handlers/seat/pointer.rs @@ -1,8 +1,5 @@ -use crate::{ - event_loop::state::FrameStatus, - platform_specific::wayland::{ - event_loop::state::SctkState, sctk_event::SctkEvent, - }, +use crate::platform_specific::wayland::{ + event_loop::state::SctkState, sctk_event::SctkEvent, }; use cctk::sctk::{ delegate_pointer, @@ -50,14 +47,6 @@ impl PointerHandler for SctkState { continue; } - let entry = self - .frame_status - .entry(e.surface.id()) - .or_insert(FrameStatus::RequestedRedraw); - if matches!(entry, FrameStatus::Received) { - *entry = FrameStatus::Ready; - } - self.sctk_events.push(SctkEvent::PointerEvent { variant: PointerEvent { surface: e.surface.clone(), From 7918b2826ec8ad4f9e0032f6a21286bac431e482 Mon Sep 17 00:00:00 2001 From: Hojjat Date: Fri, 7 Aug 2026 13:44:16 -0600 Subject: [PATCH 20/20] fix: request redraw for Text widget --- core/src/widget/text.rs | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/core/src/widget/text.rs b/core/src/widget/text.rs index 2ba0ada4..2598b74e 100644 --- a/core/src/widget/text.rs +++ b/core/src/widget/text.rs @@ -446,11 +446,22 @@ where | Event::Touch(touch::Event::FingerPressed { .. }) ) { if cursor.position_over(bounds).is_none() { + let was_visible = state.focused + || state.keyboard_focused + || state + .selection + .as_ref() + .is_some_and(|sel| sel.anchor != sel.end); + state.focused = false; state.keyboard_focused = false; if let Some(sel) = &mut state.selection { sel.clear(); } + + if was_visible { + shell.request_redraw(); + } } } @@ -511,6 +522,7 @@ where state.focused = true; state.keyboard_focused = false; shell.capture_event(); + shell.request_redraw(); } } @@ -520,6 +532,7 @@ where state.focused = true; state.keyboard_focused = false; shell.capture_event(); + shell.request_redraw(); } } @@ -544,7 +557,15 @@ where position.y - anchor.y, ); - sel.end = hit_to_grapheme(paragraph, relative, content); + let end = hit_to_grapheme(paragraph, relative, content); + + // Only the drag reaching a new grapheme changes what + // is drawn; plain motion inside one does not. + if end != sel.end { + sel.end = end; + shell.request_redraw(); + } + shell.capture_event(); } } @@ -587,6 +608,7 @@ where sel.anchor = 0; sel.end = grapheme_count; shell.capture_event(); + shell.request_redraw(); return; } _ => {} @@ -613,6 +635,7 @@ where sel.end = pos; } shell.capture_event(); + shell.request_redraw(); } keyboard::Key::Named(keyboard::key::Named::ArrowRight) => { let by_word = is_jump_modifier(*modifiers); @@ -633,6 +656,7 @@ where sel.end = pos; } shell.capture_event(); + shell.request_redraw(); } keyboard::Key::Named(keyboard::key::Named::Home) => { if modifiers.shift() { @@ -642,6 +666,7 @@ where sel.end = 0; } shell.capture_event(); + shell.request_redraw(); } keyboard::Key::Named(keyboard::key::Named::End) => { if modifiers.shift() { @@ -651,6 +676,7 @@ where sel.end = grapheme_count; } shell.capture_event(); + shell.request_redraw(); } _ => {} }