From 90d2c418a73af0669302e58fb6a0978bb73a7436 Mon Sep 17 00:00:00 2001 From: Hojjat Date: Wed, 22 Apr 2026 14:36:39 -0600 Subject: [PATCH 01/93] chore: update to wgpu 28 and cosmic-text 0.19 --- Cargo.lock | 179 ++++++------------- Cargo.toml | 9 +- examples/custom_shader/src/scene/pipeline.rs | 12 +- examples/integration/src/scene.rs | 5 +- wgpu/src/buffer.rs | 3 - wgpu/src/color.rs | 5 +- wgpu/src/image/atlas.rs | 5 +- wgpu/src/image/cache.rs | 10 +- wgpu/src/image/mod.rs | 13 +- wgpu/src/lib.rs | 4 + wgpu/src/quad.rs | 4 +- wgpu/src/quad/gradient.rs | 6 +- wgpu/src/quad/solid.rs | 6 +- wgpu/src/text.rs | 2 +- wgpu/src/triangle.rs | 25 +-- wgpu/src/triangle/msaa.rs | 7 +- wgpu/src/window/compositor.rs | 3 + 17 files changed, 113 insertions(+), 185 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 805e6066..383d8cfa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -157,6 +157,12 @@ dependencies = [ "equator", ] +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + [[package]] name = "android-activity" version = "0.6.1" @@ -1314,8 +1320,9 @@ dependencies = [ [[package]] name = "cosmic-text" -version = "0.18.2" -source = "git+https://github.com/pop-os/cosmic-text.git#4d74f795cc771fdcc7ea0f9cacba63fcf036fad6" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be17b688510d934ce13f48a2beba700e11583e281e0fda99c22bb256a14eda73" dependencies = [ "bitflags 2.11.0", "fontdb", @@ -1439,7 +1446,7 @@ checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "cryoglyph" version = "0.1.0" -source = "git+https://github.com/pop-os/glyphon.git?tag=cosmic-0.14#c49de15bce4d8254ac136d1be9911960cc85ce12" +source = "git+https://github.com/iced-rs/cryoglyph.git?rev=e429a025df36ab8145708acb309080ae3deec17a#e429a025df36ab8145708acb309080ae3deec17a" dependencies = [ "cosmic-text", "etagere", @@ -1561,7 +1568,7 @@ dependencies = [ "libc", "option-ext", "redox_users 0.5.2", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -1789,7 +1796,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -2292,7 +2299,7 @@ dependencies = [ "gobject-sys", "libc", "system-deps", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -2403,35 +2410,18 @@ dependencies = [ "system-deps", ] -[[package]] -name = "gpu-alloc" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171" -dependencies = [ - "bitflags 2.11.0", - "gpu-alloc-types", -] - -[[package]] -name = "gpu-alloc-types" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4" -dependencies = [ - "bitflags 2.11.0", -] - [[package]] name = "gpu-allocator" -version = "0.27.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c151a2a5ef800297b4e79efa4f4bec035c5f51d5ae587287c9b952bdf734cacd" +checksum = "51255ea7cfaadb6c5f1528d43e92a82acb2b96c43365989a28b2d44ee38f8795" dependencies = [ + "ash", + "hashbrown 0.16.1", "log", "presser", - "thiserror 1.0.69", - "windows 0.58.0", + "thiserror 2.0.18", + "windows 0.57.0", ] [[package]] @@ -2699,6 +2689,8 @@ version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" dependencies = [ + "allocator-api2", + "equivalent", "foldhash 0.2.0", ] @@ -3478,7 +3470,7 @@ checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" dependencies = [ "hermit-abi", "libc", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -3536,7 +3528,7 @@ dependencies = [ "portable-atomic", "portable-atomic-util", "serde_core", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -4045,9 +4037,9 @@ dependencies = [ [[package]] name = "metal" -version = "0.32.0" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00c15a6f673ff72ddcc22394663290f870fb224c1bfce55734a75c414150e605" +checksum = "c7047791b5bc903b8cd963014b355f71dc9864a9a0b727057676c1dcae5cbc15" dependencies = [ "bitflags 2.11.0", "block", @@ -4193,9 +4185,9 @@ checksum = "13d2233c9842d08cfe13f9eac96e207ca6a2ea10b80259ebe8ad0268be27d2af" [[package]] name = "naga" -version = "27.0.3" +version = "28.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "066cf25f0e8b11ee0df221219010f213ad429855f57c494f995590c861a9a7d8" +checksum = "618f667225063219ddfc61251087db8a9aec3c3f0950c916b614e403486f1135" dependencies = [ "arrayvec", "bit-set", @@ -4300,7 +4292,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -5706,7 +5698,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.4.15", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -5719,7 +5711,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.12.1", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -6334,7 +6326,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -6628,7 +6620,7 @@ dependencies = [ "getrandom 0.4.2", "once_cell", "rustix 1.1.4", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -7167,7 +7159,7 @@ checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e" dependencies = [ "memoffset", "tempfile", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -7823,12 +7815,13 @@ checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" [[package]] name = "wgpu" -version = "27.0.1" +version = "28.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfe68bac7cde125de7a731c3400723cadaaf1703795ad3f4805f187459cd7a77" +checksum = "f9cb534d5ffd109c7d1135f34cdae29e60eab94855a625dcfe1705f8bc7ad79f" dependencies = [ "arrayvec", "bitflags 2.11.0", + "bytemuck", "cfg-if", "cfg_aliases", "document-features", @@ -7852,9 +7845,9 @@ dependencies = [ [[package]] name = "wgpu-core" -version = "27.0.3" +version = "28.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27a75de515543b1897b26119f93731b385a19aea165a1ec5f0e3acecc229cae7" +checksum = "d23f4642f53f666adcfd2d3218ab174d1e6681101aef18696b90cbe64d1c10f9" dependencies = [ "arrayvec", "bit-set", @@ -7885,45 +7878,45 @@ dependencies = [ [[package]] name = "wgpu-core-deps-apple" -version = "27.0.0" +version = "28.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0772ae958e9be0c729561d5e3fd9a19679bcdfb945b8b1a1969d9bfe8056d233" +checksum = "87b7b696b918f337c486bf93142454080a32a37832ba8a31e4f48221890047da" dependencies = [ "wgpu-hal", ] [[package]] name = "wgpu-core-deps-emscripten" -version = "27.0.0" +version = "28.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06ac3444a95b0813ecfd81ddb2774b66220b264b3e2031152a4a29fda4da6b5" +checksum = "34b251c331f84feac147de3c4aa3aa45112622a95dd7ee1b74384fa0458dbd79" dependencies = [ "wgpu-hal", ] [[package]] name = "wgpu-core-deps-wasm" -version = "27.0.0" +version = "28.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b1027dcf3b027a877e44819df7ceb0e2e98578830f8cd34cd6c3c7c2a7a50b7" +checksum = "12a2cf578ce8d7d50d0e63ddc2345c7dcb599f6eb90b888813406ea78b9b7010" dependencies = [ "wgpu-hal", ] [[package]] name = "wgpu-core-deps-windows-linux-android" -version = "27.0.0" +version = "28.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71197027d61a71748e4120f05a9242b2ad142e3c01f8c1b47707945a879a03c3" +checksum = "68ca976e72b2c9964eb243e281f6ce7f14a514e409920920dcda12ae40febaae" dependencies = [ "wgpu-hal", ] [[package]] name = "wgpu-hal" -version = "27.0.4" +version = "28.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b21cb61c57ee198bc4aff71aeadff4cbb80b927beb912506af9c780d64313ce" +checksum = "44d6cb474beb218824dcc9e1ce679d973f719262789bfb27407da560cac20eeb" dependencies = [ "android_system_properties", "arrayvec", @@ -7937,7 +7930,6 @@ dependencies = [ "core-graphics-types 0.2.0", "glow", "glutin_wgl_sys", - "gpu-alloc", "gpu-allocator", "gpu-descriptor", "hashbrown 0.16.1", @@ -7964,21 +7956,20 @@ dependencies = [ "wasm-bindgen", "web-sys", "wgpu-types", - "windows 0.58.0", - "windows-core 0.58.0", + "windows 0.62.2", + "windows-core 0.62.2", ] [[package]] name = "wgpu-types" -version = "27.0.1" +version = "28.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afdcf84c395990db737f2dd91628706cb31e86d72e53482320d368e52b5da5eb" +checksum = "e18308757e594ed2cd27dddbb16a139c42a683819d32a2e0b1b0167552f5840c" dependencies = [ "bitflags 2.11.0", "bytemuck", "js-sys", "log", - "thiserror 2.0.18", "web-sys", ] @@ -8004,7 +7995,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -8038,16 +8029,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" -dependencies = [ - "windows-core 0.58.0", - "windows-targets 0.52.6", -] - [[package]] name = "windows" version = "0.61.3" @@ -8103,19 +8084,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-core" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" -dependencies = [ - "windows-implement 0.58.0", - "windows-interface 0.58.0", - "windows-result 0.2.0", - "windows-strings 0.1.0", - "windows-targets 0.52.6", -] - [[package]] name = "windows-core" version = "0.61.2" @@ -8175,17 +8143,6 @@ dependencies = [ "syn", ] -[[package]] -name = "windows-implement" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "windows-implement" version = "0.60.2" @@ -8208,17 +8165,6 @@ dependencies = [ "syn", ] -[[package]] -name = "windows-interface" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "windows-interface" version = "0.59.3" @@ -8282,15 +8228,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-result" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-result" version = "0.3.4" @@ -8309,16 +8246,6 @@ dependencies = [ "windows-link 0.2.1", ] -[[package]] -name = "windows-strings" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" -dependencies = [ - "windows-result 0.2.0", - "windows-targets 0.52.6", -] - [[package]] name = "windows-strings" version = "0.4.2" diff --git a/Cargo.toml b/Cargo.toml index 49b4b5d7..d60bcb8d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -202,7 +202,7 @@ repository = "https://github.com/iced-rs/iced" homepage = "https://iced.rs" categories = ["gui"] keywords = ["gui", "ui", "graphics", "interface", "widgets"] -rust-version = "1.89" +rust-version = "1.92" [workspace.dependencies] iced = { version = "0.14.0", path = "." } @@ -238,10 +238,9 @@ async-std = "1.0" bitflags = "2.5" bytemuck = { version = "1.0", features = ["derive"] } bytes = "1.6" -cosmic-text = { git = "https://github.com/pop-os/cosmic-text.git" } -# cosmic-text = "0.10" +cosmic-text = "0.19" +cryoglyph = { git = "https://github.com/iced-rs/cryoglyph.git", rev = "e429a025df36ab8145708acb309080ae3deec17a" } dark-light = "1.0" -cryoglyph = { package = "cryoglyph", git = "https://github.com/pop-os/glyphon.git", tag = "cosmic-0.14" } resvg = "0.45" web-sys = "0.3.69" guillotiere = "0.6" @@ -288,7 +287,7 @@ url = "2.5" wasm-bindgen-futures = "0.4" wasmtimer = "0.4.2" web-time = "1.1" -wgpu = { version = "27.0", default-features = false, features = [ +wgpu = { version = "28.0", default-features = false, features = [ "std", "wgsl", ] } diff --git a/examples/custom_shader/src/scene/pipeline.rs b/examples/custom_shader/src/scene/pipeline.rs index 80b0d533..30262a5d 100644 --- a/examples/custom_shader/src/scene/pipeline.rs +++ b/examples/custom_shader/src/scene/pipeline.rs @@ -140,7 +140,7 @@ impl Pipeline { address_mode_w: wgpu::AddressMode::ClampToEdge, mag_filter: wgpu::FilterMode::Linear, min_filter: wgpu::FilterMode::Linear, - mipmap_filter: wgpu::FilterMode::Linear, + mipmap_filter: wgpu::MipmapFilterMode::Linear, ..Default::default() }); @@ -223,7 +223,7 @@ impl Pipeline { device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("cubes pipeline layout"), bind_group_layouts: &[&uniform_bind_group_layout], - push_constant_ranges: &[], + immediate_size: 0, }); let shader = @@ -280,7 +280,7 @@ impl Pipeline { compilation_options: wgpu::PipelineCompilationOptions::default(), }), - multiview: None, + multiview_mask: None, cache: None, }); @@ -388,6 +388,7 @@ impl Pipeline { ), timestamp_writes: None, occlusion_query_set: None, + multiview_mask: None, }); pass.set_viewport( @@ -478,7 +479,7 @@ impl DepthPipeline { device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("cubes.depth_pipeline.layout"), bind_group_layouts: &[&bind_group_layout], - push_constant_ranges: &[], + immediate_size: 0, }); let shader = @@ -520,7 +521,7 @@ impl DepthPipeline { compilation_options: wgpu::PipelineCompilationOptions::default(), }), - multiview: None, + multiview_mask: None, cache: None, }); @@ -586,6 +587,7 @@ impl DepthPipeline { ), timestamp_writes: None, occlusion_query_set: None, + multiview_mask: None, }); pass.set_viewport( diff --git a/examples/integration/src/scene.rs b/examples/integration/src/scene.rs index 4e4757fa..1b248036 100644 --- a/examples/integration/src/scene.rs +++ b/examples/integration/src/scene.rs @@ -43,6 +43,7 @@ impl Scene { depth_stencil_attachment: None, timestamp_writes: None, occlusion_query_set: None, + multiview_mask: None, }) } @@ -64,8 +65,8 @@ fn build_pipeline( let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: None, - push_constant_ranges: &[], bind_group_layouts: &[], + immediate_size: 0, }); device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { @@ -101,7 +102,7 @@ fn build_pipeline( mask: !0, alpha_to_coverage_enabled: false, }, - multiview: None, + multiview_mask: None, cache: None, }) } diff --git a/wgpu/src/buffer.rs b/wgpu/src/buffer.rs index 172922da..e251e979 100644 --- a/wgpu/src/buffer.rs +++ b/wgpu/src/buffer.rs @@ -63,7 +63,6 @@ impl Buffer { /// Returns the size of the written bytes. pub fn write( &mut self, - device: &wgpu::Device, encoder: &mut wgpu::CommandEncoder, belt: &mut wgpu::util::StagingBelt, offset: usize, @@ -79,7 +78,6 @@ impl Buffer { &self.raw, (offset + bytes_written) as u64, MAX_WRITE_SIZE_U64, - device, ) .copy_from_slice( &bytes[bytes_written..bytes_written + MAX_WRITE_SIZE], @@ -100,7 +98,6 @@ impl Buffer { &self.raw, (offset + bytes_written) as u64, bytes_left, - device, ) .copy_from_slice(&bytes[bytes_written..]); diff --git a/wgpu/src/color.rs b/wgpu/src/color.rs index 52fe8463..642d4ea7 100644 --- a/wgpu/src/color.rs +++ b/wgpu/src/color.rs @@ -99,7 +99,7 @@ pub fn convert( device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("iced_wgpu.offscreen.blit.pipeline_layout"), bind_group_layouts: &[&constant_layout, &texture_layout], - push_constant_ranges: &[], + immediate_size: 0, }); let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { @@ -149,7 +149,7 @@ pub fn convert( }, depth_stencil: None, multisample: wgpu::MultisampleState::default(), - multiview: None, + multiview_mask: None, cache: None, }); @@ -194,6 +194,7 @@ pub fn convert( depth_stencil_attachment: None, timestamp_writes: None, occlusion_query_set: None, + multiview_mask: None, }); pass.set_pipeline(&pipeline); diff --git a/wgpu/src/image/atlas.rs b/wgpu/src/image/atlas.rs index 09258329..d23e7452 100644 --- a/wgpu/src/image/atlas.rs +++ b/wgpu/src/image/atlas.rs @@ -132,7 +132,7 @@ impl Atlas { match &entry { Entry::Contiguous(allocation) => { self.upload_allocation( - pixels, width, 0, allocation, device, encoder, belt, + pixels, width, 0, allocation, encoder, belt, ); } Entry::Fragmented { fragments, .. } => { @@ -145,7 +145,6 @@ impl Atlas { width, offset, &fragment.allocation, - device, encoder, belt, ); @@ -312,7 +311,6 @@ impl Atlas { image_width: u32, offset: usize, allocation: &Allocation, - device: &wgpu::Device, encoder: &mut wgpu::CommandEncoder, belt: &mut wgpu::util::StagingBelt, ) { @@ -334,7 +332,6 @@ impl Atlas { let buffer_slice = belt.allocate( wgpu::BufferSize::new(total_bytes as u64).unwrap(), wgpu::BufferSize::new(8 * 4).unwrap(), - device, ); const PIXEL: usize = 4; diff --git a/wgpu/src/image/cache.rs b/wgpu/src/image/cache.rs index 097a383f..88a48640 100644 --- a/wgpu/src/image/cache.rs +++ b/wgpu/src/image/cache.rs @@ -38,7 +38,10 @@ impl Cache { raster: Raster { cache: crate::image::raster::Cache::default(), pending: HashMap::new(), - belt: wgpu::util::StagingBelt::new(2 * 1024 * 1024), + belt: wgpu::util::StagingBelt::new( + device.clone(), + 2 * 1024 * 1024, + ), }, #[cfg(feature = "svg")] vector: crate::image::vector::Cache::default(), @@ -451,7 +454,10 @@ mod worker { backend, texture_layout, shell: shell.clone(), - belt: wgpu::util::StagingBelt::new(4 * 1024 * 1024), + belt: wgpu::util::StagingBelt::new( + device.clone(), + 4 * 1024 * 1024, + ), jobs: jobs_receiver, output: work_sender, quit: quit_receiver, diff --git a/wgpu/src/image/mod.rs b/wgpu/src/image/mod.rs index ba98f443..d0665ee4 100644 --- a/wgpu/src/image/mod.rs +++ b/wgpu/src/image/mod.rs @@ -45,7 +45,7 @@ impl Pipeline { address_mode_w: wgpu::AddressMode::ClampToEdge, min_filter: wgpu::FilterMode::Nearest, mag_filter: wgpu::FilterMode::Nearest, - mipmap_filter: wgpu::FilterMode::Nearest, + mipmap_filter: wgpu::MipmapFilterMode::Nearest, ..Default::default() }); @@ -55,7 +55,7 @@ impl Pipeline { address_mode_w: wgpu::AddressMode::ClampToEdge, min_filter: wgpu::FilterMode::Linear, mag_filter: wgpu::FilterMode::Linear, - mipmap_filter: wgpu::FilterMode::Linear, + mipmap_filter: wgpu::MipmapFilterMode::Linear, ..Default::default() }); @@ -106,8 +106,8 @@ impl Pipeline { let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("iced_wgpu::image pipeline layout"), - push_constant_ranges: &[], bind_group_layouts: &[&constant_layout, &texture_layout], + immediate_size: 0, }); let shader = @@ -191,7 +191,7 @@ impl Pipeline { mask: !0, alpha_to_coverage_enabled: false, }, - multiview: None, + multiview_mask: None, cache: None, }); @@ -528,7 +528,6 @@ impl Layer { &self.uniforms, 0, (bytes.len() as u64).try_into().expect("Sized uniforms"), - device, ) .copy_from_slice(bytes); @@ -539,11 +538,11 @@ impl Layer { let mut offset = 0; if !nearest.is_empty() { - offset += self.instances.write(device, encoder, belt, 0, nearest); + offset += self.instances.write(encoder, belt, 0, nearest); } if !linear.is_empty() { - let _ = self.instances.write(device, encoder, belt, offset, linear); + let _ = self.instances.write(encoder, belt, offset, linear); } } diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 4eb52cc8..03a72042 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -126,6 +126,7 @@ impl Renderer { // It would be great if the `StagingBelt` API exposed methods // for introspection to detect when a resize may be worth it. staging_belt: wgpu::util::StagingBelt::new( + engine.device.clone(), buffer::MAX_WRITE_SIZE as u64, ), @@ -454,6 +455,7 @@ impl Renderer { depth_stencil_attachment: None, timestamp_writes: None, occlusion_query_set: None, + multiview_mask: None, }, )); @@ -528,6 +530,7 @@ impl Renderer { depth_stencil_attachment: None, timestamp_writes: None, occlusion_query_set: None, + multiview_mask: None, }, )); } @@ -621,6 +624,7 @@ impl Renderer { depth_stencil_attachment: None, timestamp_writes: None, occlusion_query_set: None, + multiview_mask: None, }, )); } diff --git a/wgpu/src/quad.rs b/wgpu/src/quad.rs index 31bf69cf..4cab2598 100644 --- a/wgpu/src/quad.rs +++ b/wgpu/src/quad.rs @@ -209,7 +209,7 @@ impl Layer { transformation: Transformation, scale: f32, ) { - self.update(device, encoder, belt, transformation, scale); + self.update(encoder, belt, transformation, scale); if !quads.solids.is_empty() { self.solid.prepare(device, encoder, belt, &quads.solids); @@ -223,7 +223,6 @@ impl Layer { pub fn update( &mut self, - device: &wgpu::Device, encoder: &mut wgpu::CommandEncoder, belt: &mut wgpu::util::StagingBelt, transformation: Transformation, @@ -237,7 +236,6 @@ impl Layer { &self.constants_buffer, 0, (bytes.len() as u64).try_into().expect("Sized uniforms"), - device, ) .copy_from_slice(bytes); } diff --git a/wgpu/src/quad/gradient.rs b/wgpu/src/quad/gradient.rs index 6a5eed8d..55e62e79 100644 --- a/wgpu/src/quad/gradient.rs +++ b/wgpu/src/quad/gradient.rs @@ -51,7 +51,7 @@ impl Layer { instances: &[Gradient], ) { let _ = self.instances.resize(device, instances.len()); - let _ = self.instances.write(device, encoder, belt, 0, instances); + let _ = self.instances.write(encoder, belt, 0, instances); self.instance_count = instances.len(); } @@ -75,8 +75,8 @@ impl Pipeline { let layout = device.create_pipeline_layout( &wgpu::PipelineLayoutDescriptor { label: Some("iced_wgpu.quad.gradient.pipeline"), - push_constant_ranges: &[], bind_group_layouts: &[constants_layout], + immediate_size: 0, }, ); @@ -155,7 +155,7 @@ impl Pipeline { mask: !0, alpha_to_coverage_enabled: false, }, - multiview: None, + multiview_mask: None, cache: None, }, ); diff --git a/wgpu/src/quad/solid.rs b/wgpu/src/quad/solid.rs index 7e48358e..49e4cf01 100644 --- a/wgpu/src/quad/solid.rs +++ b/wgpu/src/quad/solid.rs @@ -45,7 +45,7 @@ impl Layer { instances: &[Solid], ) { let _ = self.instances.resize(device, instances.len()); - let _ = self.instances.write(device, encoder, belt, 0, instances); + let _ = self.instances.write(encoder, belt, 0, instances); self.instance_count = instances.len(); } @@ -65,8 +65,8 @@ impl Pipeline { let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("iced_wgpu.quad.solid.pipeline"), - push_constant_ranges: &[], bind_group_layouts: &[constants_layout], + immediate_size: 0, }); let shader = @@ -139,7 +139,7 @@ impl Pipeline { mask: !0, alpha_to_coverage_enabled: false, }, - multiview: None, + multiview_mask: None, cache: None, }); diff --git a/wgpu/src/text.rs b/wgpu/src/text.rs index 16efa092..b6d9e679 100644 --- a/wgpu/src/text.rs +++ b/wgpu/src/text.rs @@ -619,7 +619,7 @@ fn prepare( )?; Some(cryoglyph::TextArea { - buffer, + text: buffer.layout_runs(), left: position.x, top: position.y, scale: transformation.scale_factor() diff --git a/wgpu/src/triangle.rs b/wgpu/src/triangle.rs index fa5ecb9c..5607d03a 100644 --- a/wgpu/src/triangle.rs +++ b/wgpu/src/triangle.rs @@ -313,6 +313,7 @@ fn render<'a>( depth_stencil_attachment: None, timestamp_writes: None, occlusion_query_set: None, + multiview_mask: None, }) }; @@ -425,18 +426,13 @@ impl Layer { let indices = mesh.indices(); - index_offset += self.index_buffer.write( - device, - encoder, - belt, - index_offset, - indices, - ); + index_offset += + self.index_buffer + .write(encoder, belt, index_offset, indices); match mesh { Mesh::Solid { buffers, .. } => { solid_vertex_offset += self.solid.vertices.write( - device, encoder, belt, solid_vertex_offset, @@ -444,16 +440,14 @@ impl Layer { ); solid_uniform_offset += self.solid.uniforms.write( - device, encoder, belt, solid_uniform_offset, &[uniforms], - ); + ) } Mesh::Gradient { buffers, .. } => { gradient_vertex_offset += self.gradient.vertices.write( - device, encoder, belt, gradient_vertex_offset, @@ -461,7 +455,6 @@ impl Layer { ); gradient_uniform_offset += self.gradient.uniforms.write( - device, encoder, belt, gradient_uniform_offset, @@ -731,7 +724,7 @@ mod solid { &wgpu::PipelineLayoutDescriptor { label: Some("iced_wgpu.triangle.solid.pipeline_layout"), bind_group_layouts: &[&constants_layout], - push_constant_ranges: &[], + immediate_size: 0, }, ); @@ -784,7 +777,7 @@ mod solid { primitive: triangle::primitive_state(), depth_stencil: None, multisample: triangle::multisample_state(antialiasing), - multiview: None, + multiview_mask: None, cache: None, }, ); @@ -886,7 +879,7 @@ mod gradient { &wgpu::PipelineLayoutDescriptor { label: Some("iced_wgpu.triangle.gradient.pipeline_layout"), bind_group_layouts: &[&constants_layout], - push_constant_ranges: &[], + immediate_size: 0, }, ); @@ -949,7 +942,7 @@ mod gradient { primitive: triangle::primitive_state(), depth_stencil: None, multisample: triangle::multisample_state(antialiasing), - multiview: None, + multiview_mask: None, cache: None, }, ); diff --git a/wgpu/src/triangle/msaa.rs b/wgpu/src/triangle/msaa.rs index 8ca49461..46118361 100644 --- a/wgpu/src/triangle/msaa.rs +++ b/wgpu/src/triangle/msaa.rs @@ -69,8 +69,8 @@ impl Pipeline { let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("iced_wgpu::triangle::msaa pipeline layout"), - push_constant_ranges: &[], bind_group_layouts: &[&constant_layout, &texture_layout], + immediate_size: 0, }); let shader = @@ -116,7 +116,7 @@ impl Pipeline { mask: !0, alpha_to_coverage_enabled: false, }, - multiview: None, + multiview_mask: None, cache: None, }); @@ -177,6 +177,7 @@ impl Pipeline { depth_stencil_attachment: None, timestamp_writes: None, occlusion_query_set: None, + multiview_mask: None, }) } } @@ -320,7 +321,6 @@ impl State { 0, NonZeroU64::new(std::mem::size_of::() as u64) .expect("non-empty ratio"), - device, ) .copy_from_slice(bytemuck::bytes_of(&ratio)); @@ -351,6 +351,7 @@ impl State { depth_stencil_attachment: None, timestamp_writes: None, occlusion_query_set: None, + multiview_mask: None, }); render_pass.set_pipeline(&pipeline.raw); diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs index 833a642e..b575ef61 100644 --- a/wgpu/src/window/compositor.rs +++ b/wgpu/src/window/compositor.rs @@ -126,6 +126,7 @@ impl Compositor { // if log::max_level() >= log::LevelFilter::Info { // let available_adapters: Vec<_> = instance // .enumerate_adapters(settings.backends) + // .await // .iter() // .map(wgpu::Adapter::get_info) // .collect(); @@ -155,6 +156,7 @@ impl Compositor { if let Some((vendor_id, device_id)) = ids { adapter = instance .enumerate_adapters(settings.backends) + .await .into_iter() .filter(|adapter| { let info = adapter.get_info(); @@ -172,6 +174,7 @@ impl Compositor { } else if let Ok(name) = std::env::var("WGPU_ADAPTER_NAME") { adapter = instance .enumerate_adapters(settings.backends) + .await .into_iter() .filter(|adapter| { let info = adapter.get_info(); From 3928e0d38572d63ff1ef1d768b17770e9a91d7c0 Mon Sep 17 00:00:00 2001 From: edwloef Date: Sat, 27 Dec 2025 16:57:41 +0100 Subject: [PATCH 02/93] wgpu: request devices with `SHADER_F16` feature --- wgpu/src/window/compositor.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs index b575ef61..d3f4bf8c 100644 --- a/wgpu/src/window/compositor.rs +++ b/wgpu/src/window/compositor.rs @@ -297,7 +297,7 @@ impl Compositor { label: Some( "iced_wgpu::window::compositor device descriptor", ), - required_features: wgpu::Features::empty(), + required_features: wgpu::Features::SHADER_F16, required_limits: required_limits.clone(), memory_hints: wgpu::MemoryHints::MemoryUsage, trace: wgpu::Trace::Off, From e000c71ff230036244b5ed4e82d1ba3b0c59bdad Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Wed, 6 May 2026 11:27:02 -0400 Subject: [PATCH 03/93] fix: send redraw request after events creation events must be handled before processing redraws --- .../wayland/event_loop/mod.rs | 33 ++++++++++--------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/winit/src/platform_specific/wayland/event_loop/mod.rs b/winit/src/platform_specific/wayland/event_loop/mod.rs index 976595a7..61bf12ea 100644 --- a/winit/src/platform_specific/wayland/event_loop/mod.rs +++ b/winit/src/platform_specific/wayland/event_loop/mod.rs @@ -488,6 +488,23 @@ impl SctkEventLoop { let had_events = !state.state.sctk_events.is_empty(); let mut wake_up = had_events; + for e in state.state.sctk_events.drain(..) { + if let SctkEvent::Winit(id, e) = e { + _ = state + .state + .events_sender + .unbounded_send(Control::Winit(id, e)); + } else { + _ = + state + .state + .events_sender + .unbounded_send(Control::PlatformSpecific( + crate::platform_specific::Event::Wayland(e), + )); + } + } + for s in state .state @@ -532,22 +549,6 @@ impl SctkEventLoop { ); } - for e in state.state.sctk_events.drain(..) { - if let SctkEvent::Winit(id, e) = e { - _ = state - .state - .events_sender - .unbounded_send(Control::Winit(id, e)); - } else { - _ = - state - .state - .events_sender - .unbounded_send(Control::PlatformSpecific( - crate::platform_specific::Event::Wayland(e), - )); - } - } if wake_up { state.state.proxy.wake_up(); } From d7595fab95579f640d43d90e16c174709c4b5c01 Mon Sep 17 00:00:00 2001 From: Lcstyle Date: Wed, 18 Feb 2026 17:22:13 -0500 Subject: [PATCH 04/93] fix: bootstrap FrameStatus on session lock surface configure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The session lock configure handler was missing receive_frame() and request_redraw() calls that the layer surface configure handler has. Without these, after S3 resume or DPMS wake, the FrameStatus entry for lock surfaces could be missing, causing the rendering gate to never reach Ready state — resulting in permanently grey lock screens. Co-Authored-By: Claude Opus 4.6 --- .../platform_specific/wayland/handlers/session_lock.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/winit/src/platform_specific/wayland/handlers/session_lock.rs b/winit/src/platform_specific/wayland/handlers/session_lock.rs index d0eee5ef..6c617a20 100644 --- a/winit/src/platform_specific/wayland/handlers/session_lock.rs +++ b/winit/src/platform_specific/wayland/handlers/session_lock.rs @@ -1,6 +1,10 @@ use crate::{ event_loop::state::CommonSurface, - platform_specific::wayland::{handlers::SctkState, sctk_event::SctkEvent}, + platform_specific::wayland::{ + event_loop::state::receive_frame, + handlers::SctkState, + sctk_event::SctkEvent, + }, }; use cctk::sctk::{ delegate_session_lock, @@ -67,6 +71,10 @@ impl SessionLockHandler for SctkState { configure, first, }); + + let wl_surface = session_lock_surface.wl_surface().clone(); + receive_frame(&mut self.frame_status, &wl_surface); + self.request_redraw(&wl_surface); } } From f752bba18f4651eee63d2d187ebfdfb0e620f8ef Mon Sep 17 00:00:00 2001 From: KENZ Date: Sat, 25 Apr 2026 09:54:04 +0900 Subject: [PATCH 05/93] =?UTF-8?q?Revert=20"Fix=20the=20candidate=20window?= =?UTF-8?q?=20position=20of=20fcitx5=20which=20does't=20work=20well=20wi?= =?UTF-8?q?=E2=80=A6"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit a9bcb0052944d9fbf33ce0f6a01a80a20cbcd61b. --- winit/src/window.rs | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/winit/src/window.rs b/winit/src/window.rs index 87d35a5a..e56483f4 100644 --- a/winit/src/window.rs +++ b/winit/src/window.rs @@ -335,19 +335,9 @@ where } if self.ime_state != Some((cursor, purpose)) { - // Specify only the bottom-left position of the cursor on Linux - // because fcitx5 doesn't work well with cursor areas of - // the top-left position and height. - // The candidate window hides the composing text (a.k.a. preedit). - let (cursor_y, cursor_height) = - if cfg!(not(any(target_os = "windows", target_os = "macos"))) { - (cursor.y + cursor.height, 0.0) - } else { - (cursor.y, cursor.height) - }; self.raw.set_ime_cursor_area( - LogicalPosition::new(cursor.x, cursor_y).into(), - LogicalSize::new(cursor.width, cursor_height).into(), + LogicalPosition::new(cursor.x, cursor.y).into(), + LogicalSize::new(cursor.width, cursor.height).into(), ); self.raw.set_ime_purpose(conversion::ime_purpose(purpose)); From 1444d5c43e8b103ca8077555606443ab77e03ce5 Mon Sep 17 00:00:00 2001 From: KENZ Date: Sat, 2 May 2026 14:28:09 +0900 Subject: [PATCH 06/93] fix(ime): Don't panic if some IME sends DeleteSurrounding events --- winit/src/conversion.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/winit/src/conversion.rs b/winit/src/conversion.rs index cc5676b5..97cc97a6 100644 --- a/winit/src/conversion.rs +++ b/winit/src/conversion.rs @@ -387,19 +387,19 @@ pub fn window_event( self::modifiers(new_modifiers.state()), ))) } - WindowEvent::Ime(event) => Some(Event::InputMethod(match event { - Ime::Enabled => input_method::Event::Opened, - Ime::Preedit(content, size) => input_method::Event::Preedit( + WindowEvent::Ime(event) => match event { + Ime::Enabled => Some(input_method::Event::Opened), + Ime::Preedit(content, size) => Some(input_method::Event::Preedit( content, size.map(|(start, end)| start..end), - ), - Ime::Commit(content) => input_method::Event::Commit(content), - Ime::Disabled => input_method::Event::Closed, - Ime::DeleteSurrounding { - before_bytes, - after_bytes, - } => todo!(), - })), + )), + Ime::Commit(content) => Some(input_method::Event::Commit(content)), + Ime::Disabled => Some(input_method::Event::Closed), + // Upstream iced depends on the winit version which doesn't support + // this kind of ime event. + Ime::DeleteSurrounding { .. } => None, + } + .map(Event::InputMethod), WindowEvent::Focused(focused) => Some(Event::Window(if focused { window::Event::Focused } else { From 347d91f7ead2912694f67416e60a72afdba00715 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Mon, 20 Apr 2026 12:16:44 -0400 Subject: [PATCH 07/93] improv(wgpu): adapter selection --- wgpu/src/window/compositor.rs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs index d3f4bf8c..0c354dfd 100644 --- a/wgpu/src/window/compositor.rs +++ b/wgpu/src/window/compositor.rs @@ -76,18 +76,23 @@ 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 // 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, - feature = "cctk", - not(target_os = "macos"), - not(target_os = "redox") - ))] + #[cfg(all(unix, not(target_os = "macos"), not(target_os = "redox")))] if !matches!(ids, Some((0x10de, _))) && std::env::var_os("__NV_PRIME_RENDER_OFFLOAD") .is_none_or(|var| var == "0") @@ -149,7 +154,6 @@ impl Compositor { if std::env::var_os("WGPU_ADAPTER_NAME").is_none() { #[cfg(all( unix, - feature = "cctk", not(target_os = "macos"), not(target_os = "redox") ))] @@ -187,6 +191,8 @@ impl Compositor { true } }); + } else { + adapter = instance.request_adapter(&adapter_options).await.ok(); } let adapter = match adapter { From 251254ad5179f05b849e420425b72d4c40091db1 Mon Sep 17 00:00:00 2001 From: Hojjat Date: Fri, 15 May 2026 13:38:15 -0600 Subject: [PATCH 08/93] feat: add `selectable()` to Text --- Cargo.lock | 1 + core/Cargo.toml | 1 + core/src/widget/text.rs | 451 +++++++++++++++++++++++++++++++++++-- examples/todos/src/main.rs | 1 + tester/src/lib.rs | 2 + widget/src/checkbox.rs | 1 + widget/src/radio.rs | 1 + widget/src/text/rich.rs | 2 +- widget/src/toggler.rs | 1 + 9 files changed, 442 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 383d8cfa..38f19187 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3023,6 +3023,7 @@ dependencies = [ "serde", "smol_str", "thiserror 2.0.18", + "unicode-segmentation", "web-time", "window_clipboard", ] diff --git a/core/Cargo.toml b/core/Cargo.toml index e64a5c37..0a376b7c 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -31,6 +31,7 @@ num-traits.workspace = true rustc-hash.workspace = true smol_str.workspace = true thiserror.workspace = true +unicode-segmentation.workspace = true web-time.workspace = true serde.workspace = true diff --git a/core/src/widget/text.rs b/core/src/widget/text.rs index 1e40bf9e..0c0ddc54 100644 --- a/core/src/widget/text.rs +++ b/core/src/widget/text.rs @@ -22,16 +22,18 @@ //! ``` use crate::alignment; use crate::layout; -use crate::mouse; +use crate::mouse::{self, click}; use crate::renderer; +use crate::text; use crate::text::paragraph::{self, Paragraph}; -use crate::text::{self, Fragment}; use crate::widget::tree::{self, Tree}; use crate::{ - Color, Element, Layout, Length, Pixels, Rectangle, Size, Theme, Widget, + Clipboard, Color, Element, Event, Layout, Length, Pixels, Point, Rectangle, + Shell, Size, Theme, Widget, keyboard, touch, }; -use std::borrow::Cow; +use unicode_segmentation::UnicodeSegmentation; + pub use text::{Alignment, Ellipsize, LineHeight, Shaping, Wrapping}; /// A bunch of text. @@ -65,6 +67,7 @@ where fragment: text::Fragment<'a>, format: Format, class: Theme::Class<'a>, + selectable: bool, } impl<'a, Theme, Renderer> Text<'a, Theme, Renderer> @@ -79,6 +82,7 @@ where fragment: fragment.into_fragment(), format: Format::default(), class: Theme::default(), + selectable: false, } } @@ -189,7 +193,17 @@ where { let color = color.map(Into::into); - self.style(move |_theme| Style { color }) + self.style(move |_theme| Style { + color, + ..Style::default() + }) + } + + /// Makes the [`Text`] selectable. When enabled, the user can click and + /// drag to select text, and copy it with Ctrl+C / Cmd+C. + pub fn selectable(mut self) -> Self { + self.selectable = true; + self } /// Sets the style class of the [`Text`]. @@ -202,7 +216,53 @@ where } /// The internal state of a [`Text`] widget. -pub type State

= paragraph::Plain

; +pub struct State { + /// The cached paragraph layout. + pub paragraph: paragraph::Plain

, + /// Lazily allocated when text is selectable and first interacted with. + selection: Option>, +} + +impl Default for State

{ + fn default() -> Self { + Self { + paragraph: paragraph::Plain::default(), + selection: None, + } + } +} + +impl std::fmt::Debug for State

{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("State") + .field("selection", &self.selection) + .finish_non_exhaustive() + } +} + +impl std::ops::Deref for State

{ + type Target = paragraph::Plain

; + + fn deref(&self) -> ¶graph::Plain

{ + &self.paragraph + } +} + +impl std::ops::DerefMut for State

{ + fn deref_mut(&mut self) -> &mut paragraph::Plain

{ + &mut self.paragraph + } +} + +#[derive(Debug, Clone, Default)] +struct SelectionState { + anchor: usize, + end: usize, + dragging: bool, + focused: bool, + modifiers: keyboard::Modifiers, + last_click: Option, +} impl Widget for Text<'_, Theme, Renderer> @@ -215,7 +275,7 @@ where } fn state(&self) -> tree::State { - tree::State::new(paragraph::Plain::::default()) + tree::State::new(State::::default()) } fn size(&self) -> Size { @@ -231,8 +291,10 @@ where renderer: &Renderer, limits: &layout::Limits, ) -> layout::Node { + let state = tree.state.downcast_mut::>(); + layout( - tree.state.downcast_mut::>(), + &mut state.paragraph, renderer, limits, &self.fragment, @@ -252,15 +314,285 @@ where ) { let state = tree.state.downcast_ref::>(); let style = theme.style(&self.class); + let bounds = layout.bounds(); + let paragraph = state.paragraph.raw(); + if let Some(sel) = &state.selection { + let left = sel.anchor.min(sel.end); + let right = sel.anchor.max(sel.end); + let content: &str = self.fragment.as_ref(); - draw( - renderer, - defaults, - layout.bounds(), - state.raw(), - style, - viewport, - ); + if left != right { + let lo_byte = grapheme_to_byte(content, left); + let hi_byte = grapheme_to_byte(content, right); + + let anchor = bounds.anchor( + paragraph.min_bounds(), + paragraph.align_x(), + paragraph.align_y(), + ); + + let rects = paragraph.highlight( + 0, + (lo_byte, text::Affinity::After), + (hi_byte, text::Affinity::Before), + ); + + for r in rects { + renderer.fill_quad( + renderer::Quad { + bounds: Rectangle { + x: anchor.x + r.x, + y: anchor.y + r.y, + width: r.width, + height: r.height, + }, + ..renderer::Quad::default() + }, + style.selected_fill, + ); + } + } + } + + draw(renderer, defaults, bounds, paragraph, style, viewport); + } + + fn update( + &mut self, + tree: &mut Tree, + event: &Event, + layout: Layout<'_>, + cursor: mouse::Cursor, + _renderer: &Renderer, + clipboard: &mut dyn Clipboard, + shell: &mut Shell<'_, Message>, + _viewport: &Rectangle, + ) { + if !self.selectable { + return; + } + + let state = tree.state.downcast_mut::>(); + let bounds = layout.bounds(); + let content: &str = self.fragment.as_ref(); + let grapheme_count = content.graphemes(true).count(); + let paragraph = state.paragraph.raw(); + + match event { + Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) + | Event::Touch(touch::Event::FingerPressed { .. }) => { + if let Some(pos) = cursor.position_over(bounds) { + let sel = state.selection.get_or_insert_with(|| { + Box::new(SelectionState::default()) + }); + + let anchor = bounds.anchor( + paragraph.min_bounds(), + paragraph.align_x(), + paragraph.align_y(), + ); + let relative = + Point::new(pos.x - anchor.x, pos.y - anchor.y); + + let grapheme_pos = + hit_to_grapheme(paragraph, relative, content); + + let new_click = click::Click::new( + pos, + mouse::Button::Left, + sel.last_click.take(), + ); + + match new_click.kind() { + click::Kind::Single => { + if sel.modifiers.shift() { + sel.end = grapheme_pos; + } else { + sel.anchor = grapheme_pos; + sel.end = grapheme_pos; + } + sel.dragging = true; + } + click::Kind::Double => { + sel.anchor = + previous_start_of_word(content, grapheme_pos); + sel.end = next_end_of_word(content, grapheme_pos); + sel.dragging = true; + } + click::Kind::Triple => { + sel.anchor = 0; + sel.end = grapheme_count; + sel.dragging = true; + } + } + + sel.last_click = Some(new_click); + sel.focused = true; + shell.capture_event(); + } else if let Some(sel) = &mut state.selection { + sel.focused = false; + sel.anchor = 0; + sel.end = 0; + sel.dragging = false; + } + } + + Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left)) + | Event::Touch(touch::Event::FingerLifted { .. }) => { + if let Some(sel) = &mut state.selection { + sel.dragging = false; + } + } + + Event::Mouse(mouse::Event::CursorMoved { position }) + | Event::Touch(touch::Event::FingerMoved { position, .. }) => { + if let Some(sel) = &mut state.selection { + if sel.dragging { + let anchor = bounds.anchor( + paragraph.min_bounds(), + paragraph.align_x(), + paragraph.align_y(), + ); + let relative = Point::new( + position.x - anchor.x, + position.y - anchor.y, + ); + + sel.end = hit_to_grapheme(paragraph, relative, content); + shell.capture_event(); + } + } + } + + Event::Keyboard(keyboard::Event::KeyPressed { + key, + modifiers, + physical_key, + text: _, + .. + }) => { + let focused = + state.selection.as_ref().is_some_and(|s| s.focused); + if !focused { + return; + } + let sel = state.selection.as_mut().unwrap(); + + if modifiers.command() { + match key.to_latin(*physical_key) { + Some('c') => { + let left = sel.anchor.min(sel.end); + let right = sel.anchor.max(sel.end); + if left != right { + let selected: String = content + .graphemes(true) + .skip(left) + .take(right - left) + .collect(); + clipboard.write( + crate::clipboard::Kind::Standard, + selected, + ); + } + shell.capture_event(); + return; + } + Some('a') => { + sel.anchor = 0; + sel.end = grapheme_count; + shell.capture_event(); + return; + } + _ => {} + } + } + + match key { + keyboard::Key::Named(keyboard::key::Named::ArrowLeft) => { + let by_word = is_jump_modifier(*modifiers); + if modifiers.shift() { + sel.end = if by_word { + previous_start_of_word(content, sel.end) + } else { + sel.end.saturating_sub(1) + }; + } else { + let left = sel.anchor.min(sel.end); + let pos = if by_word { + previous_start_of_word(content, left) + } else { + left.saturating_sub(1) + }; + sel.anchor = pos; + sel.end = pos; + } + shell.capture_event(); + } + keyboard::Key::Named(keyboard::key::Named::ArrowRight) => { + let by_word = is_jump_modifier(*modifiers); + if modifiers.shift() { + sel.end = if by_word { + next_end_of_word(content, sel.end) + } else { + (sel.end + 1).min(grapheme_count) + }; + } else { + let right = sel.anchor.max(sel.end); + let pos = if by_word { + next_end_of_word(content, right) + } else { + (right + 1).min(grapheme_count) + }; + sel.anchor = pos; + sel.end = pos; + } + shell.capture_event(); + } + keyboard::Key::Named(keyboard::key::Named::Home) => { + if modifiers.shift() { + sel.end = 0; + } else { + sel.anchor = 0; + sel.end = 0; + } + shell.capture_event(); + } + keyboard::Key::Named(keyboard::key::Named::End) => { + if modifiers.shift() { + sel.end = grapheme_count; + } else { + sel.anchor = grapheme_count; + sel.end = grapheme_count; + } + shell.capture_event(); + } + _ => {} + } + } + + Event::Keyboard(keyboard::Event::ModifiersChanged(modifiers)) => { + if let Some(sel) = &mut state.selection { + sel.modifiers = *modifiers; + } + } + + _ => {} + } + } + + fn mouse_interaction( + &self, + _tree: &Tree, + layout: Layout<'_>, + cursor: mouse::Cursor, + _viewport: &Rectangle, + _renderer: &Renderer, + ) -> mouse::Interaction { + if self.selectable && cursor.is_over(layout.bounds()) { + mouse::Interaction::Text + } else { + mouse::Interaction::None + } } fn operate( @@ -471,12 +803,23 @@ where } /// The appearance of some text. -#[derive(Debug, Clone, Copy, PartialEq, Default)] +#[derive(Debug, Clone, Copy, PartialEq)] pub struct Style { /// The [`Color`] of the text. /// /// The default, `None`, means using the inherited color. pub color: Option, + /// The fill [`Color`] of the selection highlight. + pub selected_fill: Color, +} + +impl Default for Style { + fn default() -> Self { + Self { + color: None, + selected_fill: DEFAULT_SELECTION_COLOR, + } + } } /// The theme catalog of a [`Text`]. @@ -510,13 +853,14 @@ impl Catalog for Theme { /// The default text styling; color is inherited. pub fn default(_theme: &Theme) -> Style { - Style { color: None } + Style::default() } /// Text with the default base color. pub fn base(theme: &Theme) -> Style { Style { color: Some(theme.palette().text), + ..Style::default() } } @@ -524,6 +868,7 @@ pub fn base(theme: &Theme) -> Style { pub fn primary(theme: &Theme) -> Style { Style { color: Some(theme.palette().primary), + ..Style::default() } } @@ -531,6 +876,7 @@ pub fn primary(theme: &Theme) -> Style { pub fn secondary(theme: &Theme) -> Style { Style { color: Some(theme.extended_palette().secondary.base.color), + ..Style::default() } } @@ -538,6 +884,7 @@ pub fn secondary(theme: &Theme) -> Style { pub fn success(theme: &Theme) -> Style { Style { color: Some(theme.palette().success), + ..Style::default() } } @@ -545,6 +892,7 @@ pub fn success(theme: &Theme) -> Style { pub fn warning(theme: &Theme) -> Style { Style { color: Some(theme.palette().warning), + ..Style::default() } } @@ -552,5 +900,72 @@ pub fn warning(theme: &Theme) -> Style { pub fn danger(theme: &Theme) -> Style { Style { color: Some(theme.palette().danger), + ..Style::default() + } +} + +const DEFAULT_SELECTION_COLOR: Color = Color { + r: 0.0, + g: 0.47, + b: 0.84, + a: 0.3, +}; + +fn grapheme_to_byte(content: &str, grapheme_index: usize) -> usize { + content + .graphemes(true) + .take(grapheme_index) + .map(|g| g.len()) + .sum() +} + +fn hit_to_grapheme( + paragraph: &P, + point: Point, + content: &str, +) -> usize { + match paragraph.hit_test(point) { + Some(hit) => { + let byte_offset = hit.cursor().min(content.len()); + content[..byte_offset].graphemes(true).count() + } + None => content.graphemes(true).count(), + } +} + +fn previous_start_of_word(content: &str, grapheme_index: usize) -> usize { + let graphemes: Vec<&str> = content.graphemes(true).collect(); + let clamped = grapheme_index.min(graphemes.len()); + let before: String = graphemes[..clamped].concat(); + + UnicodeSegmentation::split_word_bound_indices(&*before) + .filter(|(_, word)| !word.trim_start().is_empty()) + .next_back() + .map_or(0, |(i, prev_word)| { + clamped + - prev_word.graphemes(true).count() + - before[i + prev_word.len()..].graphemes(true).count() + }) +} + +fn next_end_of_word(content: &str, grapheme_index: usize) -> usize { + let graphemes: Vec<&str> = content.graphemes(true).collect(); + let clamped = grapheme_index.min(graphemes.len()); + let after: String = graphemes[clamped..].concat(); + + UnicodeSegmentation::split_word_bound_indices(&*after) + .find(|(_, word)| !word.trim_start().is_empty()) + .map_or(graphemes.len(), |(i, next_word)| { + clamped + + next_word.graphemes(true).count() + + after[..i].graphemes(true).count() + }) +} + +fn is_jump_modifier(modifiers: keyboard::Modifiers) -> bool { + if cfg!(target_os = "macos") { + modifiers.alt() + } else { + modifiers.control() } } diff --git a/examples/todos/src/main.rs b/examples/todos/src/main.rs index 2e3722b1..9fe39035 100644 --- a/examples/todos/src/main.rs +++ b/examples/todos/src/main.rs @@ -477,6 +477,7 @@ fn delete_icon() -> Text<'static> { fn subtle(theme: &Theme) -> text::Style { text::Style { color: Some(theme.extended_palette().background.strongest.color), + ..text::Style::default() } } diff --git a/tester/src/lib.rs b/tester/src/lib.rs index 334f17bc..f41fbb68 100644 --- a/tester/src/lib.rs +++ b/tester/src/lib.rs @@ -775,6 +775,7 @@ impl Tester

{ } _ => None, }, + ..text::Style::default() }) .into() }, @@ -945,6 +946,7 @@ where text(label).size(14).style(|theme: &core::Theme| { text::Style { color: Some(theme.extended_palette().background.weak.text), + ..text::Style::default() } }), space::horizontal(), diff --git a/widget/src/checkbox.rs b/widget/src/checkbox.rs index 873a4541..6ac48b0e 100644 --- a/widget/src/checkbox.rs +++ b/widget/src/checkbox.rs @@ -505,6 +505,7 @@ where state.raw(), crate::text::Style { color: style.text_color, + ..crate::text::Style::default() }, viewport, ); diff --git a/widget/src/radio.rs b/widget/src/radio.rs index 1aa97355..bdca259c 100644 --- a/widget/src/radio.rs +++ b/widget/src/radio.rs @@ -459,6 +459,7 @@ where state.raw(), crate::text::Style { color: style.text_color, + ..crate::text::Style::default() }, viewport, ); diff --git a/widget/src/text/rich.rs b/widget/src/text/rich.rs index cd368e83..80abc8d5 100644 --- a/widget/src/text/rich.rs +++ b/widget/src/text/rich.rs @@ -179,7 +179,7 @@ where { let color = color.map(Into::into); - self.style(move |_theme| Style { color }) + self.style(move |_theme| Style { color, ..Style::default() }) } /// Sets the default style class of the [`Rich`] text. diff --git a/widget/src/toggler.rs b/widget/src/toggler.rs index d398a79b..6709f1dc 100644 --- a/widget/src/toggler.rs +++ b/widget/src/toggler.rs @@ -483,6 +483,7 @@ where state.raw(), crate::text::Style { color: style.text_color, + ..crate::text::Style::default() }, viewport, ); From 346faf2e7951dd4ea6fe7fb3f677e34631145d88 Mon Sep 17 00:00:00 2001 From: Ericky Dos Santos Date: Tue, 6 Jan 2026 13:26:01 -0500 Subject: [PATCH 09/93] Make shader_f16 optional because it does not work in webgl --- wgpu/src/window/compositor.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs index 0c354dfd..bbef994d 100644 --- a/wgpu/src/window/compositor.rs +++ b/wgpu/src/window/compositor.rs @@ -295,6 +295,13 @@ impl Compositor { ..limits }); + // Request SHADER_F16 only if the adapter supports it (e.g., not available in WebGL2) + let required_features = if adapter.features().contains(wgpu::Features::SHADER_F16) { + wgpu::Features::SHADER_F16 + } else { + wgpu::Features::empty() + }; + let mut errors = Vec::new(); for required_limits in limits { @@ -303,7 +310,7 @@ impl Compositor { label: Some( "iced_wgpu::window::compositor device descriptor", ), - required_features: wgpu::Features::SHADER_F16, + required_features, required_limits: required_limits.clone(), memory_hints: wgpu::MemoryHints::MemoryUsage, trace: wgpu::Trace::Off, From 9ae155b8e26480fd78ff289fceec0cdf2d476463 Mon Sep 17 00:00:00 2001 From: Hojjat Date: Wed, 20 May 2026 00:25:37 -0600 Subject: [PATCH 10/93] fix: crash while resizing on x11 --- wgpu/src/window/compositor.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs index bbef994d..4033aea4 100644 --- a/wgpu/src/window/compositor.rs +++ b/wgpu/src/window/compositor.rs @@ -368,6 +368,13 @@ pub fn present( ) -> Result<(), compositor::SurfaceError> { match surface.get_current_texture() { Ok(frame) => { + if frame.suboptimal + || frame.texture.width() != viewport.physical_width() + || frame.texture.height() != viewport.physical_height() + { + return Err(compositor::SurfaceError::Outdated); + } + let view = &frame .texture .create_view(&wgpu::TextureViewDescriptor::default()); From 2e1e4bd6e0a8cc46290d9354428bf7a0f3ca752d Mon Sep 17 00:00:00 2001 From: Hojjat Date: Tue, 19 May 2026 19:36:16 -0600 Subject: [PATCH 11/93] feat: add HasSelectableText trait to Text widget --- core/src/widget/text.rs | 220 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 208 insertions(+), 12 deletions(-) diff --git a/core/src/widget/text.rs b/core/src/widget/text.rs index 0c0ddc54..2ba0ada4 100644 --- a/core/src/widget/text.rs +++ b/core/src/widget/text.rs @@ -221,6 +221,9 @@ pub struct State { pub paragraph: paragraph::Plain

, /// Lazily allocated when text is selectable and first interacted with. selection: Option>, + focused: bool, + keyboard_focused: bool, + context_menu_position: Option, } impl Default for State

{ @@ -228,6 +231,9 @@ impl Default for State

{ Self { paragraph: paragraph::Plain::default(), selection: None, + focused: false, + keyboard_focused: false, + context_menu_position: None, } } } @@ -236,10 +242,43 @@ impl std::fmt::Debug for State

{ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("State") .field("selection", &self.selection) + .field("focused", &self.focused) .finish_non_exhaustive() } } +impl State

{ + /// Returns `true` if the widget currently has focus. + pub fn is_focused(&self) -> bool { + self.focused + } + + /// Returns `true` if focus was gained via keyboard navigation (Tab). + pub fn is_keyboard_focused(&self) -> bool { + self.keyboard_focused + } + + /// Clears focus, selection, and all interaction state. + pub fn clear_focus(&mut self) { + self.focused = false; + self.keyboard_focused = false; + self.context_menu_position = None; + if let Some(sel) = &mut self.selection { + sel.clear(); + } + } + + /// Returns the context menu position, if a context menu should be shown. + pub fn context_menu_position(&self) -> Option { + self.context_menu_position + } + + /// Sets or clears the context menu position. + pub fn set_context_menu_position(&mut self, pos: Option) { + self.context_menu_position = pos; + } +} + impl std::ops::Deref for State

{ type Target = paragraph::Plain

; @@ -259,11 +298,33 @@ struct SelectionState { anchor: usize, end: usize, dragging: bool, - focused: bool, modifiers: keyboard::Modifiers, last_click: Option, } +impl SelectionState { + fn clear(&mut self) { + self.anchor = 0; + self.end = 0; + self.dragging = false; + } +} + +impl crate::widget::operation::Focusable for State

{ + fn is_focused(&self) -> bool { + self.focused + } + + fn focus(&mut self) { + self.focused = true; + self.keyboard_focused = true; + } + + fn unfocus(&mut self) { + self.clear_focus(); + } +} + impl Widget for Text<'_, Theme, Renderer> where @@ -378,9 +439,29 @@ where let grapheme_count = content.graphemes(true).count(); let paragraph = state.paragraph.raw(); + // Any click outside this widget clears selection and focus. + if matches!( + event, + Event::Mouse(mouse::Event::ButtonPressed(_)) + | Event::Touch(touch::Event::FingerPressed { .. }) + ) { + if cursor.position_over(bounds).is_none() { + state.focused = false; + state.keyboard_focused = false; + if let Some(sel) = &mut state.selection { + sel.clear(); + } + } + } + match event { Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) | Event::Touch(touch::Event::FingerPressed { .. }) => { + if state.context_menu_position.take().is_some() { + shell.capture_event(); + return; + } + if let Some(pos) = cursor.position_over(bounds) { let sel = state.selection.get_or_insert_with(|| { Box::new(SelectionState::default()) @@ -427,13 +508,18 @@ where } sel.last_click = Some(new_click); - sel.focused = true; + state.focused = true; + state.keyboard_focused = false; + shell.capture_event(); + } + } + + Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Right)) => { + if let Some(pos) = cursor.position_over(bounds) { + state.context_menu_position = Some(pos); + state.focused = true; + state.keyboard_focused = false; shell.capture_event(); - } else if let Some(sel) = &mut state.selection { - sel.focused = false; - sel.anchor = 0; - sel.end = 0; - sel.dragging = false; } } @@ -471,12 +557,12 @@ where text: _, .. }) => { - let focused = - state.selection.as_ref().is_some_and(|s| s.focused); - if !focused { + if !state.focused { return; } - let sel = state.selection.as_mut().unwrap(); + let sel = state + .selection + .get_or_insert_with(|| Box::new(SelectionState::default())); if modifiers.command() { match key.to_latin(*physical_key) { @@ -597,12 +683,17 @@ where fn operate( &mut self, - _tree: &mut Tree, + tree: &mut Tree, layout: Layout<'_>, _renderer: &Renderer, operation: &mut dyn super::Operation, ) { operation.text(None, layout.bounds(), &self.fragment); + + if self.selectable { + let state = tree.state.downcast_mut::>(); + operation.focusable(None, layout.bounds(), state); + } } #[cfg(feature = "a11y")] @@ -904,6 +995,111 @@ pub fn danger(theme: &Theme) -> Style { } } +use crate::widget::tree::Tree as WidgetTree; + +/// Implement this on a **widget** to enable context menu support for +/// text selection (Copy, Select All, and optionally Cut / Paste) in libcosmic +pub trait HasSelectableText { + /// Returns the currently selected text, if any. + fn selected_text(&self, tree: &WidgetTree) -> Option; + + /// Selects all text. + fn select_all(&self, tree: &mut WidgetTree); + + /// Returns `true` if the widget is editable (enables Cut / Paste). + fn is_editable(&self) -> bool { + false + } + + /// Returns `true` if the widget is currently focused. + fn is_focused(&self, tree: &WidgetTree) -> bool; + + /// Returns the position where the context menu should appear + fn context_menu_position(&self, tree: &WidgetTree) -> Option; + + /// Sets or clears the context menu position. + fn set_context_menu_position( + &self, + tree: &mut WidgetTree, + pos: Option, + ); + + /// Copies the selection to the clipboard. + fn copy_to_clipboard( + &self, + tree: &WidgetTree, + clipboard: &mut dyn Clipboard, + ) { + if let Some(text) = self.selected_text(tree) { + clipboard.write(crate::clipboard::Kind::Standard, text); + } + } + + /// Deletes the selected text and returns the new full content. + /// Only called when [`is_editable`](Self::is_editable) is `true`. + fn delete_selection(&self, _tree: &mut WidgetTree) -> Option { + None + } + + /// Inserts `text` at the cursor (replacing any selection) and returns + /// the new full content. + /// Only called when [`is_editable`](Self::is_editable) is `true`. + fn paste_text( + &self, + _tree: &mut WidgetTree, + _text: &str, + ) -> Option { + None + } +} + +impl HasSelectableText + for Text<'_, Theme, Renderer> +{ + fn selected_text(&self, tree: &WidgetTree) -> Option { + let state = tree.state.downcast_ref::>(); + let sel = state.selection.as_ref()?; + let left = sel.anchor.min(sel.end); + let right = sel.anchor.max(sel.end); + if left == right { + return None; + } + let content = state.paragraph.content(); + let lo = grapheme_to_byte(content, left); + let hi = grapheme_to_byte(content, right); + content.get(lo..hi).map(|s| s.to_owned()) + } + + fn select_all(&self, tree: &mut WidgetTree) { + let state = tree.state.downcast_mut::>(); + let count = state.paragraph.content().graphemes(true).count(); + let sel = state + .selection + .get_or_insert_with(|| Box::new(SelectionState::default())); + sel.anchor = 0; + sel.end = count; + } + + fn is_focused(&self, tree: &WidgetTree) -> bool { + let state = tree.state.downcast_ref::>(); + state.is_focused() + } + + fn context_menu_position(&self, tree: &WidgetTree) -> Option { + let state = tree.state.downcast_ref::>(); + state.context_menu_position() + } + + fn set_context_menu_position( + &self, + tree: &mut WidgetTree, + pos: Option, + ) { + let state = tree.state.downcast_mut::>(); + state.set_context_menu_position(pos); + } +} + const DEFAULT_SELECTION_COLOR: Color = Color { r: 0.0, g: 0.47, From a7ca336eb4db0fe89d2bdeb90b57140e0ebca141 Mon Sep 17 00:00:00 2001 From: Hojjat Date: Tue, 19 May 2026 19:36:22 -0600 Subject: [PATCH 12/93] feat: HasSelectableText impl to TextEditor --- core/src/text/editor.rs | 2 + graphics/src/text/editor.rs | 4 ++ widget/src/text_editor.rs | 126 +++++++++++++++++++++++++++++++++++- 3 files changed, 131 insertions(+), 1 deletion(-) diff --git a/core/src/text/editor.rs b/core/src/text/editor.rs index e0b87756..ff89af01 100644 --- a/core/src/text/editor.rs +++ b/core/src/text/editor.rs @@ -78,6 +78,8 @@ pub enum Action { SelectLine, /// Select the entire buffer. SelectAll, + /// Clear the selection + ClearSelection, /// Perform an [`Edit`]. Edit(Edit), /// Click the [`Editor`] at the given [`Point`]. diff --git a/graphics/src/text/editor.rs b/graphics/src/text/editor.rs index b284c76b..1586479e 100644 --- a/graphics/src/text/editor.rs +++ b/graphics/src/text/editor.rs @@ -336,6 +336,10 @@ impl editor::Editor for Editor { } } + Action::ClearSelection => { + editor.set_selection(cosmic_text::Selection::None); + } + // Editing events Action::Edit(edit) => { let topmost_line_before_edit = editor diff --git a/widget/src/text_editor.rs b/widget/src/text_editor.rs index b93c96f3..a8f243fa 100644 --- a/widget/src/text_editor.rs +++ b/widget/src/text_editor.rs @@ -544,6 +544,8 @@ pub struct State { highlighter: RefCell, highlighter_settings: Highlighter::Settings, highlighter_format_address: usize, + context_menu_position: Option, + pending_edit: Option, } #[derive(Debug, Clone)] @@ -579,6 +581,14 @@ impl State { pub fn is_focused(&self) -> bool { self.focus.is_some() } + + /// Clears focus, selection, and all interaction state. + pub fn clear_focus(&mut self) { + self.focus = None; + self.drag_click = None; + self.context_menu_position = None; + self.pending_edit = Some(Action::ClearSelection); + } } impl operation::Focusable @@ -593,7 +603,7 @@ impl operation::Focusable } fn unfocus(&mut self) { - self.focus = None; + self.clear_focus(); } } @@ -621,6 +631,8 @@ where )), highlighter_settings: self.highlighter_settings.clone(), highlighter_format_address: self.highlighter_format as usize, + context_menu_position: None, + pending_edit: None, }) } @@ -699,6 +711,58 @@ where shell: &mut Shell<'_, Message>, _viewport: &Rectangle, ) { + // Handle context menu and focus-loss on clicks outside. + { + let state = tree.state.downcast_mut::>(); + let text_bounds = layout.bounds(); + + if matches!( + event, + Event::Mouse(mouse::Event::ButtonPressed(_)) + | Event::Touch( + crate::core::touch::Event::FingerPressed { .. } + ) + ) && cursor.position_over(text_bounds).is_none() + { + state.clear_focus(); + } + + match event { + Event::Mouse(mouse::Event::ButtonPressed( + mouse::Button::Right, + )) => { + if let Some(pos) = cursor.position_over(text_bounds) { + if state.focus.is_none() { + state.focus = Some(Focus::now()); + } + state.context_menu_position = Some(pos); + shell.capture_event(); + return; + } + } + Event::Mouse(mouse::Event::ButtonPressed( + mouse::Button::Left, + )) => { + if state.context_menu_position.take().is_some() { + shell.capture_event(); + return; + } + } + _ => {} + } + } + + // Process pending edits from context menu + // publishes via on_edit so the app calls content.perform(). + { + let state = tree.state.downcast_mut::>(); + if let Some(action) = state.pending_edit.take() { + if let Some(on_edit) = self.on_edit.as_ref() { + shell.publish((on_edit)(action)); + } + } + } + let Some(on_edit) = self.on_edit.as_ref() else { return; }; @@ -1545,3 +1609,63 @@ pub(crate) fn convert_macos_shortcut( Some(keyboard::Key::Named(key)) } + +use crate::core::widget::text::HasSelectableText; + +impl HasSelectableText + for TextEditor<'_, Highlighter, Message, Theme, Renderer> +where + Highlighter: text::Highlighter, + Theme: Catalog, + Renderer: text::Renderer, +{ + fn selected_text(&self, _tree: &widget::Tree) -> Option { + self.content.selection() + } + + fn select_all(&self, tree: &mut widget::Tree) { + let state = tree.state.downcast_mut::>(); + state.pending_edit = Some(Action::SelectAll); + } + + fn is_editable(&self) -> bool { + self.on_edit.is_some() + } + + fn is_focused(&self, tree: &widget::Tree) -> bool { + tree.state.downcast_ref::>().is_focused() + } + + fn context_menu_position(&self, tree: &widget::Tree) -> Option { + tree.state + .downcast_ref::>() + .context_menu_position + } + + fn set_context_menu_position( + &self, + tree: &mut widget::Tree, + pos: Option, + ) { + tree.state + .downcast_mut::>() + .context_menu_position = pos; + } + + fn delete_selection(&self, tree: &mut widget::Tree) -> Option { + let state = tree.state.downcast_mut::>(); + state.pending_edit = Some(Action::Edit(Edit::Delete)); + Some(String::new()) + } + + fn paste_text( + &self, + tree: &mut widget::Tree, + text: &str, + ) -> Option { + let state = tree.state.downcast_mut::>(); + state.pending_edit = + Some(Action::Edit(Edit::Paste(Arc::new(text.to_owned())))); + Some(String::new()) + } +} From b007caba44b0be1d282edbe1cd6fcd440ef06eab Mon Sep 17 00:00:00 2001 From: Hojjat Date: Tue, 19 May 2026 19:36:26 -0600 Subject: [PATCH 13/93] feat: add direct SCTK action sender for wayland popups --- winit/src/platform_specific/wayland/mod.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/winit/src/platform_specific/wayland/mod.rs b/winit/src/platform_specific/wayland/mod.rs index 9b3a7ec0..0ba156d7 100644 --- a/winit/src/platform_specific/wayland/mod.rs +++ b/winit/src/platform_specific/wayland/mod.rs @@ -25,10 +25,23 @@ use std::{collections::HashMap, sync::Arc}; use subsurface_widget::{SubsurfaceInstance, SubsurfaceState}; use wayland_backend::client::ObjectId; use wayland_client::{Connection, Proxy}; +use std::sync::OnceLock; use winit::dpi::Size; use winit::event_loop::OwnedDisplayHandle; use winit::window::ImePurpose; +static SCTK_ACTION_SENDER: OnceLock> = OnceLock::new(); + +/// Sends a platform-specific wayland action directly to the SCTK event loop, +/// bypassing the async Task system. This is needed when widgets queue popup +/// actions outside of the normal message flow (e.g., text context menus that +/// don't publish app messages). +pub fn send_wayland_action_direct(action: iced_runtime::platform_specific::wayland::Action) { + if let Some(sender) = SCTK_ACTION_SENDER.get() { + _ = sender.send(Action::Action(action)); + } +} + pub(crate) enum Action { Action(iced_runtime::platform_specific::wayland::Action), SetCursor(CursorIcon), @@ -136,6 +149,9 @@ impl PlatformSpecific { self.wayland.display_handle.clone().unwrap(), ) .ok(); + if let Some(ref sender) = self.wayland.sender { + _ = SCTK_ACTION_SENDER.set(sender.clone()); + } self } From 98fb6a0fba98cfdb6c04f33ccf0be6abad7fcfff Mon Sep 17 00:00:00 2001 From: Michael Aaron Murphy Date: Wed, 20 May 2026 17:00:28 +0200 Subject: [PATCH 14/93] docs: update cosmic-protocols with docs cfg fix --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d60bcb8d..e9f43f7f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -120,7 +120,7 @@ winit = [ ] wayland = ["iced_renderer/wayland", "iced_winit/wayland"] cctk = ["iced_winit/cctk", "iced_widget/cctk", "iced_core/cctk", "wayland"] -# Enables the sctk shell. +# Enables the sctk shell. [dependencies] @@ -274,7 +274,7 @@ tiny-skia = { version = "0.11", default-features = false, features = [ "std", "simd", ] } -cctk = { git = "https://github.com/pop-os/cosmic-protocols", package = "cosmic-client-toolkit", rev = "160b086" } +cctk = { git = "https://github.com/pop-os/cosmic-protocols", package = "cosmic-client-toolkit", rev = "c253ec1" } softbuffer = { git = "https://github.com/pop-os/softbuffer", tag = "cosmic-4.0" } syntect = "5.2" tokio = "1.0" From 6105d8bdef8bcd39fbca1ef168d82c986dd18d20 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Fri, 22 May 2026 15:40:59 -0400 Subject: [PATCH 15/93] reexport geometry from iced_graphics --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 8d408969..46685d76 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -682,7 +682,7 @@ pub use error::Error; pub use event::Event; pub use executor::Executor; pub use font::Font; -pub use renderer::Renderer; +pub use renderer::{Renderer, graphics::geometry}; pub use task::Task; pub use window::Window; From a7d71d9aceddcdd6cad5628b6ca18aab89edfa97 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Wed, 27 May 2026 11:30:30 -0400 Subject: [PATCH 16/93] chore: modifiers event on keyboard enter and leave --- .../wayland/event_loop/state.rs | 8 +-- .../wayland/handlers/seat/keyboard.rs | 60 +++++++++++++++++-- .../wayland/handlers/seat/seat.rs | 5 +- 3 files changed, 61 insertions(+), 12 deletions(-) diff --git a/winit/src/platform_specific/wayland/event_loop/state.rs b/winit/src/platform_specific/wayland/event_loop/state.rs index f99e48ba..e47caa94 100644 --- a/winit/src/platform_specific/wayland/event_loop/state.rs +++ b/winit/src/platform_specific/wayland/event_loop/state.rs @@ -30,7 +30,6 @@ use std::{ convert::Infallible, fmt::Debug, sync::{Arc, Mutex, atomic::AtomicU32}, - thread::panicking, time::Duration, }; use wayland_backend::client::ObjectId; @@ -71,7 +70,7 @@ use cctk::{ registry::RegistryState, seat::{ SeatState, - keyboard::KeyEvent, + keyboard::{KeyEvent, Modifiers}, pointer::{CursorIcon, PointerData, ThemedPointer}, touch::TouchData, }, @@ -97,7 +96,6 @@ use cctk::{ }; use iced_runtime::{ core::{self, Point, touch}, - keyboard::Modifiers, platform_specific::{ self, wayland::{ @@ -1469,7 +1467,7 @@ impl SctkState { // TODO how to handle this when there's no lock? if let Some((surface, _)) = self.get_lock_surface(id, &output) { let wl_surface = surface.wl_surface(); - + receive_frame(&mut self.frame_status, &wl_surface); } } @@ -1653,7 +1651,7 @@ impl SctkState { bg_effect_mgr.enqueue(id, rectangles.clone()); return Ok(()); } - + let s = if let Some(s) = self.popups.iter().find(|s| s.data.id == id) { s.popup.wl_surface() } else if let Some(s) = self.layer_surfaces.iter().find(|s| s.id == id) { diff --git a/winit/src/platform_specific/wayland/handlers/seat/keyboard.rs b/winit/src/platform_specific/wayland/handlers/seat/keyboard.rs index 5ff7fb4b..f83e1180 100644 --- a/winit/src/platform_specific/wayland/handlers/seat/keyboard.rs +++ b/winit/src/platform_specific/wayland/handlers/seat/keyboard.rs @@ -4,10 +4,46 @@ use crate::platform_specific::wayland::{ }; use cctk::sctk::{ delegate_keyboard, - seat::keyboard::{KeyboardHandler, Keysym}, + seat::keyboard::{KeyboardHandler, Keysym, Modifiers}, }; use cctk::sctk::{reexports::client::Proxy, seat::keyboard::RawModifiers}; +fn modifiers_from_keysyms( + keysyms: &[Keysym], + previous: Modifiers, +) -> Modifiers { + let mut modifiers = Modifiers { + caps_lock: previous.caps_lock, + num_lock: previous.num_lock, + ..Modifiers::default() + }; + + for keysym in keysyms { + match keysym.raw() { + xkeysym::key::Shift_L | xkeysym::key::Shift_R => { + modifiers.shift = true + } + xkeysym::key::Control_L | xkeysym::key::Control_R => { + modifiers.ctrl = true + } + xkeysym::key::Alt_L | xkeysym::key::Alt_R => modifiers.alt = true, + xkeysym::key::Super_L + | xkeysym::key::Super_R + | xkeysym::key::Hyper_L + | xkeysym::key::Hyper_R + | xkeysym::key::Meta_L + | xkeysym::key::Meta_R => modifiers.logo = true, + xkeysym::key::Caps_Lock | xkeysym::key::Shift_Lock => { + modifiers.caps_lock = true + } + xkeysym::key::Num_Lock => modifiers.num_lock = true, + _ => {} + } + } + + modifiers +} + impl KeyboardHandler for SctkState { fn enter( &mut self, @@ -17,9 +53,9 @@ impl KeyboardHandler for SctkState { surface: &cctk::sctk::reexports::client::protocol::wl_surface::WlSurface, _serial: u32, _raw: &[u32], - _keysyms: &[Keysym], + keysyms: &[Keysym], ) { - let (i, mut is_active, seat) = { + let (i, mut is_active, seat, modifiers) = { let (i, is_active, my_seat) = match self.seats.iter_mut().enumerate().find_map(|(i, s)| { if s.kbd.as_ref() == Some(keyboard) { @@ -41,9 +77,11 @@ impl KeyboardHandler for SctkState { surface }; _ = my_seat.kbd_focus.replace(surface.clone()); + let modifiers = modifiers_from_keysyms(keysyms, my_seat._modifiers); + my_seat._modifiers = modifiers; let seat = my_seat.seat.clone(); - (i, is_active, seat) + (i, is_active, seat, modifiers) }; if !is_active && self.seats[0].kbd_focus.is_none() { @@ -73,6 +111,12 @@ impl KeyboardHandler for SctkState { seat_id: seat.clone(), surface: surface.clone(), }); + self.sctk_events.push(SctkEvent::KeyboardEvent { + variant: KeyboardEventVariant::Modifiers(modifiers), + kbd_id: keyboard.clone(), + seat_id: seat.clone(), + surface: surface.clone(), + }); } } } @@ -126,6 +170,7 @@ impl KeyboardHandler for SctkState { if self.windows.iter().any(|w| w.window.id() == id) { continue; } + let modifiers = s._modifiers; self.sctk_events.push(SctkEvent::Winit( id, winit::event::WindowEvent::Focused(true), @@ -137,6 +182,12 @@ impl KeyboardHandler for SctkState { kbd_id: s.kbd.clone().unwrap(), seat_id: s.seat.clone(), surface: surface.clone(), + }); + self.sctk_events.push(SctkEvent::KeyboardEvent { + variant: KeyboardEventVariant::Modifiers(modifiers), + kbd_id: s.kbd.clone().unwrap(), + seat_id: s.seat.clone(), + surface: surface.clone(), }) } } @@ -248,6 +299,7 @@ impl KeyboardHandler for SctkState { }; let seat_id = my_seat.seat.clone(); let kbd_id = keyboard.clone(); + my_seat._modifiers = modifiers; if is_active { if let Some(surface) = my_seat.kbd_focus.clone() { diff --git a/winit/src/platform_specific/wayland/handlers/seat/seat.rs b/winit/src/platform_specific/wayland/handlers/seat/seat.rs index 2901ce8e..ee6b0e6e 100644 --- a/winit/src/platform_specific/wayland/handlers/seat/seat.rs +++ b/winit/src/platform_specific/wayland/handlers/seat/seat.rs @@ -4,10 +4,9 @@ use crate::platform_specific::wayland::{ }; use cctk::sctk::{ delegate_seat, - reexports::client::{protocol::wl_keyboard::WlKeyboard, Proxy}, - seat::{pointer::ThemeSpec, SeatHandler}, + reexports::client::{Proxy, protocol::wl_keyboard::WlKeyboard}, + seat::{SeatHandler, keyboard::Modifiers, pointer::ThemeSpec}, }; -use iced_runtime::keyboard::Modifiers; use std::sync::Arc; impl SeatHandler for SctkState { From 0094b347d408aabc78091f744cb4eac49de1a7e4 Mon Sep 17 00:00:00 2001 From: Hojjat Date: Thu, 21 May 2026 17:38:04 -0600 Subject: [PATCH 17/93] fix: avoid deadlock in context menu rendering --- winit/src/platform_specific/wayland/event_loop/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/winit/src/platform_specific/wayland/event_loop/mod.rs b/winit/src/platform_specific/wayland/event_loop/mod.rs index 61bf12ea..3949d270 100644 --- a/winit/src/platform_specific/wayland/event_loop/mod.rs +++ b/winit/src/platform_specific/wayland/event_loop/mod.rs @@ -538,7 +538,6 @@ impl SctkEventLoop { wake_up = true; _ = s.frame(&state.state.queue_handle, s.clone()); - _ = state.state.frame_status.remove(&id); _ = state.state.events_sender.unbounded_send( Control::Winit( winit::window::WindowId::from_raw( @@ -547,6 +546,7 @@ impl SctkEventLoop { winit::event::WindowEvent::RedrawRequested, ), ); + _ = state.state.frame_status.insert(id, state::FrameStatus::Received); } if wake_up { From dfcd989947a7493b73342732ace786c0af873261 Mon Sep 17 00:00:00 2001 From: Hojjat Date: Wed, 27 May 2026 14:50:31 -0600 Subject: [PATCH 18/93] fix: present suboptimal frames --- wgpu/src/window/compositor.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs index 4033aea4..f0595f2b 100644 --- a/wgpu/src/window/compositor.rs +++ b/wgpu/src/window/compositor.rs @@ -368,13 +368,14 @@ pub fn present( ) -> Result<(), compositor::SurfaceError> { match surface.get_current_texture() { Ok(frame) => { - if frame.suboptimal - || frame.texture.width() != viewport.physical_width() + if frame.texture.width() != viewport.physical_width() || frame.texture.height() != viewport.physical_height() { return Err(compositor::SurfaceError::Outdated); } + let suboptimal = frame.suboptimal; + let view = &frame .texture .create_view(&wgpu::TextureViewDescriptor::default()); @@ -390,6 +391,10 @@ pub fn present( on_pre_present(); frame.present(); + if suboptimal { + return Err(compositor::SurfaceError::Outdated); + } + Ok(()) } Err(error) => match error { From 9c748f1656bc15d159651eea0091c13c024ebc47 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Wed, 27 May 2026 17:25:49 -0400 Subject: [PATCH 19/93] Revert "fix: avoid deadlock in context menu rendering" This reverts commit 0094b347d408aabc78091f744cb4eac49de1a7e4. --- winit/src/platform_specific/wayland/event_loop/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/winit/src/platform_specific/wayland/event_loop/mod.rs b/winit/src/platform_specific/wayland/event_loop/mod.rs index 3949d270..61bf12ea 100644 --- a/winit/src/platform_specific/wayland/event_loop/mod.rs +++ b/winit/src/platform_specific/wayland/event_loop/mod.rs @@ -538,6 +538,7 @@ impl SctkEventLoop { wake_up = true; _ = s.frame(&state.state.queue_handle, s.clone()); + _ = state.state.frame_status.remove(&id); _ = state.state.events_sender.unbounded_send( Control::Winit( winit::window::WindowId::from_raw( @@ -546,7 +547,6 @@ impl SctkEventLoop { winit::event::WindowEvent::RedrawRequested, ), ); - _ = state.state.frame_status.insert(id, state::FrameStatus::Received); } if wake_up { From 590e093086247dfc0b41580f752a4d59d5817a78 Mon Sep 17 00:00:00 2001 From: Gavin John Date: Fri, 29 May 2026 10:47:32 -0700 Subject: [PATCH 20/93] fix(text): don't reload cache every redraw I have >1000 fonts installed. COSMIC has always been somewhat laggy for me, but I had assumed it was just like that for everyone, or was the fault of my T480s. Eventually, when trying to diagnose some hitching, I ended up discovering that cosmic-launcher was consuming on average ~5% total CPU over time, which led me to discover that it was fetching all the fonts from disk and software rendering the fonts, every redraw, causing the high cpu usage *and* the stutters (as a result of hammering disk I/O). Oops. The fix is simple: just persist the cache across redraws. --- tiny_skia/src/text.rs | 11 ++++++++--- wgpu/src/text.rs | 5 ++++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/tiny_skia/src/text.rs b/tiny_skia/src/text.rs index add4dee8..dfd4d5f8 100644 --- a/tiny_skia/src/text.rs +++ b/tiny_skia/src/text.rs @@ -15,6 +15,7 @@ use std::collections::hash_map; pub struct Pipeline { glyph_cache: GlyphCache, cache: RefCell, + swash_cache: cosmic_text::SwashCache, } impl Pipeline { @@ -22,6 +23,7 @@ impl Pipeline { Pipeline { glyph_cache: GlyphCache::new(), cache: RefCell::new(Cache::new()), + swash_cache: cosmic_text::SwashCache::new(), } } @@ -54,6 +56,7 @@ impl Pipeline { draw( font_system.raw(), &mut self.glyph_cache, + &mut self.swash_cache, paragraph.buffer(), position, color, @@ -81,6 +84,7 @@ impl Pipeline { draw( font_system.raw(), &mut self.glyph_cache, + &mut self.swash_cache, editor.buffer(), position, color, @@ -142,6 +146,7 @@ impl Pipeline { draw( font_system, &mut self.glyph_cache, + &mut self.swash_cache, &entry.buffer, Point::new(x, y), color, @@ -165,6 +170,7 @@ impl Pipeline { draw( font_system.raw(), &mut self.glyph_cache, + &mut self.swash_cache, buffer, position, color, @@ -183,6 +189,7 @@ impl Pipeline { fn draw( font_system: &mut cosmic_text::FontSystem, glyph_cache: &mut GlyphCache, + swash_cache: &mut cosmic_text::SwashCache, buffer: &cosmic_text::Buffer, position: Point, color: Color, @@ -192,8 +199,6 @@ fn draw( ) { let position = position * transformation; - let mut swash = cosmic_text::SwashCache::new(); - for run in buffer.layout_runs() { for glyph in run.glyphs { let physical_glyph = glyph.physical( @@ -205,7 +210,7 @@ fn draw( physical_glyph.cache_key, glyph.color_opt.map(from_color).unwrap_or(color), font_system, - &mut swash, + swash_cache, ) { let pixmap = tiny_skia::PixmapRef::from_bytes( buffer, diff --git a/wgpu/src/text.rs b/wgpu/src/text.rs index b6d9e679..76b16c5c 100644 --- a/wgpu/src/text.rs +++ b/wgpu/src/text.rs @@ -308,6 +308,7 @@ pub struct State { prepare_layer: usize, cache: BufferCache, storage: Storage, + swash_cache: cryoglyph::SwashCache, } impl State { @@ -352,6 +353,7 @@ impl State { renderer, &mut atlas, &mut self.cache, + &mut self.swash_cache, text, layer_bounds * layer_transformation, layer_transformation * *transformation, @@ -448,6 +450,7 @@ fn prepare( renderer: &mut cryoglyph::TextRenderer, atlas: &mut cryoglyph::TextAtlas, buffer_cache: &mut BufferCache, + swash_cache: &mut cryoglyph::SwashCache, sections: &[Text], layer_bounds: Rectangle, layer_transformation: Transformation, @@ -643,6 +646,6 @@ fn prepare( atlas, viewport, text_areas, - &mut cryoglyph::SwashCache::new(), + swash_cache, ) } From ebb3b125bfc829617411f831afada122b6b4d02c Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Fri, 29 May 2026 16:43:44 -0400 Subject: [PATCH 21/93] Revert "fix(text): don't reload cache every redraw" This reverts commit 590e093086247dfc0b41580f752a4d59d5817a78. --- tiny_skia/src/text.rs | 11 +++-------- wgpu/src/text.rs | 5 +---- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/tiny_skia/src/text.rs b/tiny_skia/src/text.rs index dfd4d5f8..add4dee8 100644 --- a/tiny_skia/src/text.rs +++ b/tiny_skia/src/text.rs @@ -15,7 +15,6 @@ use std::collections::hash_map; pub struct Pipeline { glyph_cache: GlyphCache, cache: RefCell, - swash_cache: cosmic_text::SwashCache, } impl Pipeline { @@ -23,7 +22,6 @@ impl Pipeline { Pipeline { glyph_cache: GlyphCache::new(), cache: RefCell::new(Cache::new()), - swash_cache: cosmic_text::SwashCache::new(), } } @@ -56,7 +54,6 @@ impl Pipeline { draw( font_system.raw(), &mut self.glyph_cache, - &mut self.swash_cache, paragraph.buffer(), position, color, @@ -84,7 +81,6 @@ impl Pipeline { draw( font_system.raw(), &mut self.glyph_cache, - &mut self.swash_cache, editor.buffer(), position, color, @@ -146,7 +142,6 @@ impl Pipeline { draw( font_system, &mut self.glyph_cache, - &mut self.swash_cache, &entry.buffer, Point::new(x, y), color, @@ -170,7 +165,6 @@ impl Pipeline { draw( font_system.raw(), &mut self.glyph_cache, - &mut self.swash_cache, buffer, position, color, @@ -189,7 +183,6 @@ impl Pipeline { fn draw( font_system: &mut cosmic_text::FontSystem, glyph_cache: &mut GlyphCache, - swash_cache: &mut cosmic_text::SwashCache, buffer: &cosmic_text::Buffer, position: Point, color: Color, @@ -199,6 +192,8 @@ fn draw( ) { let position = position * transformation; + let mut swash = cosmic_text::SwashCache::new(); + for run in buffer.layout_runs() { for glyph in run.glyphs { let physical_glyph = glyph.physical( @@ -210,7 +205,7 @@ fn draw( physical_glyph.cache_key, glyph.color_opt.map(from_color).unwrap_or(color), font_system, - swash_cache, + &mut swash, ) { let pixmap = tiny_skia::PixmapRef::from_bytes( buffer, diff --git a/wgpu/src/text.rs b/wgpu/src/text.rs index 76b16c5c..b6d9e679 100644 --- a/wgpu/src/text.rs +++ b/wgpu/src/text.rs @@ -308,7 +308,6 @@ pub struct State { prepare_layer: usize, cache: BufferCache, storage: Storage, - swash_cache: cryoglyph::SwashCache, } impl State { @@ -353,7 +352,6 @@ impl State { renderer, &mut atlas, &mut self.cache, - &mut self.swash_cache, text, layer_bounds * layer_transformation, layer_transformation * *transformation, @@ -450,7 +448,6 @@ fn prepare( renderer: &mut cryoglyph::TextRenderer, atlas: &mut cryoglyph::TextAtlas, buffer_cache: &mut BufferCache, - swash_cache: &mut cryoglyph::SwashCache, sections: &[Text], layer_bounds: Rectangle, layer_transformation: Transformation, @@ -646,6 +643,6 @@ fn prepare( atlas, viewport, text_areas, - swash_cache, + &mut cryoglyph::SwashCache::new(), ) } From 5013f63956d9797571cfcebba6778adf9c8c3d87 Mon Sep 17 00:00:00 2001 From: Hojjat Date: Fri, 29 May 2026 17:16:30 -0600 Subject: [PATCH 22/93] improv: reuse loaded fonts by cosmic-text for svg renderer --- graphics/src/text.rs | 8 ++++++++ tiny_skia/src/vector.rs | 15 ++++++++++----- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/graphics/src/text.rs b/graphics/src/text.rs index 230a362d..910cbbde 100644 --- a/graphics/src/text.rs +++ b/graphics/src/text.rs @@ -161,6 +161,14 @@ impl FontSystem { &mut self.raw } + /// Returns a reference to the underlying [`fontdb::Database`]. + /// + /// Unlike going through [`raw`](Self::raw) and `db_mut`, this does not + /// clear `cosmic-text`'s internal font-match cache. + pub fn db(&self) -> &cosmic_text::fontdb::Database { + self.raw.db() + } + /// Loads a font from its bytes. pub fn load_font(&mut self, bytes: Cow<'static, [u8]>) { if let Cow::Borrowed(bytes) = bytes { diff --git a/tiny_skia/src/vector.rs b/tiny_skia/src/vector.rs index 59cd1993..2c3b219c 100644 --- a/tiny_skia/src/vector.rs +++ b/tiny_skia/src/vector.rs @@ -1,5 +1,6 @@ use crate::core::svg::{Data, Handle}; use crate::core::{Color, Rectangle, Size}; +use crate::graphics::text; use resvg::usvg; use rustc_hash::{FxHashMap, FxHashSet}; @@ -74,6 +75,7 @@ struct Cache { rasters: FxHashMap, raster_hits: FxHashSet, fontdb: Option>, + fontdb_version: Option, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -87,12 +89,15 @@ impl Cache { fn load(&mut self, handle: &Handle) -> Option<&usvg::Tree> { let id = handle.id(); - // TODO: Reuse `cosmic-text` font database - if self.fontdb.is_none() { - let mut fontdb = usvg::fontdb::Database::new(); - fontdb.load_system_fonts(); + // Reuse the font database already loaded by the `cosmic-text` font + // system. We clone it once and refresh only when a font is + // loaded (i.e. when the font system's version changes). + let font_system = text::font_system().read().expect("Read font system"); + let version = font_system.version(); - self.fontdb = Some(Arc::new(fontdb)); + if self.fontdb_version != Some(version) { + self.fontdb = Some(Arc::new(font_system.db().clone())); + self.fontdb_version = Some(version); } let options = usvg::Options { From dcf4cf01943b5a1baf7b7360ab7d604369a5c470 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Fri, 5 Jun 2026 19:20:37 -0400 Subject: [PATCH 23/93] improv: ignore duplicate surfaces and log a warning --- .../wayland/event_loop/state.rs | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/winit/src/platform_specific/wayland/event_loop/state.rs b/winit/src/platform_specific/wayland/event_loop/state.rs index e47caa94..6e39fdc2 100644 --- a/winit/src/platform_specific/wayland/event_loop/state.rs +++ b/winit/src/platform_specific/wayland/event_loop/state.rs @@ -508,6 +508,10 @@ pub struct SctkState { /// An error that occurred while running an application. #[derive(Debug, thiserror::Error)] pub enum PopupCreationError { + /// The requested ID already exists. + #[error("The requested ID already exists")] + AlreadyExists, + /// Positioner creation failed #[error("Positioner creation failed")] PositionerCreationFailed(GlobalError), @@ -528,6 +532,10 @@ pub enum PopupCreationError { /// An error that occurred while running an application. #[derive(Debug, thiserror::Error)] pub enum LayerSurfaceCreationError { + /// The requested ID already exists. + #[error("The requested ID already exists")] + AlreadyExists, + /// Layer shell is not supported by the compositor #[error("Layer shell is not supported by the compositor")] LayerShellNotSupported, @@ -544,6 +552,10 @@ pub enum LayerSurfaceCreationError { /// An error that occurred while running an application. #[derive(Debug, thiserror::Error)] pub enum SubsurfaceCreationError { + /// The requested ID already exists. + #[error("The requested ID already exists")] + AlreadyExists, + /// Subsurface creation failed #[error("Subsurface creation failed")] CreationFailed(GlobalError), @@ -682,6 +694,18 @@ impl SctkState { ), PopupCreationError, > { + if self.layer_surfaces.iter().any(|s| s.id == settings.id) + || self.windows.iter().any(|w| w.id == settings.id) + || self.popups.iter().any(|p| p.data.id == settings.id) + || self.subsurfaces.iter().any(|s| s.id == settings.id) + { + log::warn!( + "Popup surface with id {:?} already exists", + settings.id + ); + return Err(PopupCreationError::AlreadyExists); + } + let (parent, toplevel) = if let Some(parent) = self.layer_surfaces.iter().find(|l| l.id == settings.parent) { @@ -922,6 +946,15 @@ impl SctkState { IcedOutput::Output(output) => Some(output), }; + if self.layer_surfaces.iter().any(|s| s.id == id) + || self.windows.iter().any(|w| w.id == id) + || self.popups.iter().any(|p| p.data.id == id) + || self.subsurfaces.iter().any(|s| s.id == id) + { + log::warn!("Layer surface with id {id:?} already exists"); + return Err(LayerSurfaceCreationError::AlreadyExists); + } + let layer_shell = self .layer_shell .as_ref() @@ -1015,6 +1048,14 @@ impl SctkState { id: core::window::Id, output: &WlOutput, ) -> Option<(CommonSurface, Arc>)> { + if self.layer_surfaces.iter().any(|s| s.id == id) + || self.windows.iter().any(|w| w.id == id) + || self.popups.iter().any(|p| p.data.id == id) + || self.subsurfaces.iter().any(|s| s.id == id) + { + log::warn!("Lock surface with id {id:?} already exists"); + return None; + } if let Some(lock) = self.session_lock.as_ref() { let wl_surface = self.compositor_state.create_surface(&self.queue_handle); @@ -1755,6 +1796,14 @@ impl SctkState { let Some(subsurface_state) = self.subsurface_state.as_ref() else { return Err(SubsurfaceCreationError::Unsupported); }; + if self.layer_surfaces.iter().any(|s| s.id == settings.id) + || self.windows.iter().any(|w| w.id == settings.id) + || self.popups.iter().any(|p| p.data.id == settings.id) + || self.subsurfaces.iter().any(|s| s.id == settings.id) + { + log::warn!("Subsurface with id {:?} already exists", settings.id); + return Err(SubsurfaceCreationError::AlreadyExists); + } let size = settings.size.unwrap_or(Size::new(1., 1.)); let half_w = size.width / 2.; From f725961c8714b3e7f9257c70f44d9a5fb1589a07 Mon Sep 17 00:00:00 2001 From: Ilia Malanin Date: Tue, 9 Jun 2026 13:56:32 +0200 Subject: [PATCH 24/93] fix: reuse wgpu compositor across windows --- winit/src/lib.rs | 53 +++++++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/winit/src/lib.rs b/winit/src/lib.rs index 735d73aa..95df205b 100644 --- a/winit/src/lib.rs +++ b/winit/src/lib.rs @@ -864,28 +864,30 @@ async fn run_instance

( platform_specific_handler.send_wayland( platform_specific::Action::TrackWindow(window.clone(), id), ); - match create_compositor::

( - window.clone(), - CreateCompositor { - proxy: &proxy, - runtime: &mut runtime, - display_handle: &display_handle, - graphics_settings: &graphics_settings, - default_fonts: &default_fonts, - }, - ) - .await - { - Ok(comp) => { - compositor = Some(comp); - } - Err(error) => { - control_sender - .start_send(Control::Crash( - Error::GraphicsCreationFailed(error), - )) - .expect("Send control message"); - continue; + if compositor.is_none() { + match create_compositor::

( + window.clone(), + CreateCompositor { + proxy: &proxy, + runtime: &mut runtime, + display_handle: &display_handle, + graphics_settings: &graphics_settings, + default_fonts: &default_fonts, + }, + ) + .await + { + Ok(comp) => { + compositor = Some(comp); + } + Err(error) => { + control_sender + .start_send(Control::Crash( + Error::GraphicsCreationFailed(error), + )) + .expect("Send control message"); + continue; + } } } @@ -1014,6 +1016,7 @@ async fn run_instance

( &mut is_window_opening, &mut system_theme, &mut platform_specific_handler, + is_daemon, ); if exited { runtime.track(None.into_iter()); @@ -1171,6 +1174,7 @@ async fn run_instance

( &mut is_window_opening, &mut system_theme, &mut platform_specific_handler, + is_daemon, ); } @@ -1369,6 +1373,7 @@ async fn run_instance

( &mut is_window_opening, &mut system_theme, &mut platform_specific_handler, + is_daemon, ); } else { window.state.update(&program, window.raw.as_ref(), &event); @@ -1562,6 +1567,7 @@ async fn run_instance

( &mut is_window_opening, &mut system_theme, &mut platform_specific_handler, + is_daemon, ); if exited { runtime.track(None.into_iter()); @@ -2106,6 +2112,7 @@ fn run_action<'a, P, C>( is_window_opening: &mut bool, system_theme: &mut theme::Mode, platform_specific: &mut crate::platform_specific::PlatformSpecific, + is_daemon: bool, ) -> bool where P: Program, @@ -2190,7 +2197,7 @@ where )); } - if window_manager.is_empty() { + if window_manager.is_empty() && !is_daemon { *compositor = None; } } From c3c8fcf52cbe46c864459e74357dfe7985072a70 Mon Sep 17 00:00:00 2001 From: Ilia Malanin Date: Tue, 9 Jun 2026 14:06:09 +0200 Subject: [PATCH 25/93] refactor: wrap repeated run_action call in a macro --- winit/src/lib.rs | 94 ++++++++++++++---------------------------------- 1 file changed, 26 insertions(+), 68 deletions(-) diff --git a/winit/src/lib.rs b/winit/src/lib.rs index 95df205b..410949ac 100644 --- a/winit/src/lib.rs +++ b/winit/src/lib.rs @@ -838,6 +838,28 @@ async fn run_instance

( log::info!("System theme: {system_theme:?}"); + macro_rules! run_action { + ($action:expr) => { + run_action( + $action, + &program, + &mut runtime, + &mut compositor, + &mut events, + &mut messages, + &mut clipboard, + &mut control_sender, + &mut user_interfaces, + &mut window_manager, + &mut ui_caches, + &mut is_window_opening, + &mut system_theme, + &mut platform_specific_handler, + is_daemon, + ) + }; + } + 'next_event: loop { // Empty the queue if possible let event = if let Ok(event) = event_receiver.try_recv() { @@ -1001,23 +1023,7 @@ async fn run_instance

( } } Event::UserEvent(action) => { - let exited = run_action( - action, - &program, - &mut runtime, - &mut compositor, - &mut events, - &mut messages, - &mut clipboard, - &mut control_sender, - &mut user_interfaces, - &mut window_manager, - &mut ui_caches, - &mut is_window_opening, - &mut system_theme, - &mut platform_specific_handler, - is_daemon, - ); + let exited = run_action!(action); if exited { runtime.track(None.into_iter()); } @@ -1159,23 +1165,7 @@ async fn run_instance

( continue; } - _ = run_action( - action, - &program, - &mut runtime, - &mut compositor, - &mut events, - &mut messages, - &mut clipboard, - &mut control_sender, - &mut user_interfaces, - &mut window_manager, - &mut ui_caches, - &mut is_window_opening, - &mut system_theme, - &mut platform_specific_handler, - is_daemon, - ); + _ = run_action!(action); } for (window_id, window) in window_manager.iter_mut() { @@ -1358,23 +1348,7 @@ async fn run_instance

( if matches!(event, winit::event::WindowEvent::CloseRequested) && window.exit_on_close_request { - _ = run_action( - Action::Window(runtime::window::Action::Close(id)), - &program, - &mut runtime, - &mut compositor, - &mut events, - &mut messages, - &mut clipboard, - &mut control_sender, - &mut user_interfaces, - &mut window_manager, - &mut ui_caches, - &mut is_window_opening, - &mut system_theme, - &mut platform_specific_handler, - is_daemon, - ); + _ = run_action!(Action::Window(runtime::window::Action::Close(id))); } else { window.state.update(&program, window.raw.as_ref(), &event); @@ -1552,23 +1526,7 @@ async fn run_instance

( )); for action in actions { - let exited = run_action( - action, - &program, - &mut runtime, - &mut compositor, - &mut events, - &mut messages, - &mut clipboard, - &mut control_sender, - &mut user_interfaces, - &mut window_manager, - &mut ui_caches, - &mut is_window_opening, - &mut system_theme, - &mut platform_specific_handler, - is_daemon, - ); + let exited = run_action!(action); if exited { runtime.track(None.into_iter()); } From 62b90179a298b06ed3e88362e08ef47f8557da27 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 10 Jun 2026 11:47:42 -0600 Subject: [PATCH 26/93] Fix List widget not updating children because iterator not consumed --- widget/src/list.rs | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/widget/src/list.rs b/widget/src/list.rs index de9fe9b8..d7cadd50 100644 --- a/widget/src/list.rs +++ b/widget/src/list.rs @@ -363,24 +363,25 @@ where let state = tree.state.downcast_mut::(); let offset = layout.position() - Point::ORIGIN; - self.visible_elements + for (element, (index, layout, tree)) in self + .visible_elements .iter_mut() .zip(&mut state.visible_layouts) - .map(|(element, (index, layout, tree))| { - element.as_widget_mut().update( - tree, - event, - Layout::with_offset( - offset + Vector::new(0.0, self.spacing * *index as f32), - layout, - ), - cursor, - renderer, - clipboard, - shell, - viewport, - ) - }); + { + element.as_widget_mut().update( + tree, + event, + Layout::with_offset( + offset + Vector::new(0.0, self.spacing * *index as f32), + layout, + ), + cursor, + renderer, + clipboard, + shell, + viewport, + ); + } if let Event::Window(window::Event::RedrawRequested(_)) = event { match &mut state.task { From 7afd9ee0f83cfd1a4e9f9b56cf0f365e5ae60347 Mon Sep 17 00:00:00 2001 From: Hojjat Date: Fri, 19 Jun 2026 18:31:15 -0600 Subject: [PATCH 27/93] fix: add alt clipboard bindings for text_editor --- widget/src/text_editor.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/widget/src/text_editor.rs b/widget/src/text_editor.rs index a8f243fa..34a8825f 100644 --- a/widget/src/text_editor.rs +++ b/widget/src/text_editor.rs @@ -1287,6 +1287,23 @@ impl Binding { return Some(binding); } + let alt_clipboard = match key.as_ref() { + keyboard::Key::Named(key::Named::Insert) if modifiers.shift() => { + Some(Self::Paste) + } + keyboard::Key::Named(key::Named::Insert) if modifiers.command() => { + Some(Self::Copy) + } + keyboard::Key::Named(key::Named::Delete) if modifiers.shift() => { + Some(Self::Cut) + } + _ => None, + }; + + if let Some(binding) = alt_clipboard { + return Some(binding); + } + #[cfg(target_os = "macos")] let modified_key = convert_macos_shortcut(&key, modifiers).unwrap_or(modified_key); From 9f410558611b6e7e1027a7b227a7fab0b9019b93 Mon Sep 17 00:00:00 2001 From: Hojjat Date: Mon, 29 Jun 2026 14:41:20 -0600 Subject: [PATCH 28/93] Revert "feat: add direct SCTK action sender for wayland popups" This reverts commit b007caba44b0be1d282edbe1cd6fcd440ef06eab. --- winit/src/platform_specific/wayland/mod.rs | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/winit/src/platform_specific/wayland/mod.rs b/winit/src/platform_specific/wayland/mod.rs index 0ba156d7..9b3a7ec0 100644 --- a/winit/src/platform_specific/wayland/mod.rs +++ b/winit/src/platform_specific/wayland/mod.rs @@ -25,23 +25,10 @@ use std::{collections::HashMap, sync::Arc}; use subsurface_widget::{SubsurfaceInstance, SubsurfaceState}; use wayland_backend::client::ObjectId; use wayland_client::{Connection, Proxy}; -use std::sync::OnceLock; use winit::dpi::Size; use winit::event_loop::OwnedDisplayHandle; use winit::window::ImePurpose; -static SCTK_ACTION_SENDER: OnceLock> = OnceLock::new(); - -/// Sends a platform-specific wayland action directly to the SCTK event loop, -/// bypassing the async Task system. This is needed when widgets queue popup -/// actions outside of the normal message flow (e.g., text context menus that -/// don't publish app messages). -pub fn send_wayland_action_direct(action: iced_runtime::platform_specific::wayland::Action) { - if let Some(sender) = SCTK_ACTION_SENDER.get() { - _ = sender.send(Action::Action(action)); - } -} - pub(crate) enum Action { Action(iced_runtime::platform_specific::wayland::Action), SetCursor(CursorIcon), @@ -149,9 +136,6 @@ impl PlatformSpecific { self.wayland.display_handle.clone().unwrap(), ) .ok(); - if let Some(ref sender) = self.wayland.sender { - _ = SCTK_ACTION_SENDER.set(sender.clone()); - } self } From 1bcba7e30cb082df1629f8ecdb02123f1403439b Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Thu, 16 Apr 2026 23:01:58 -0400 Subject: [PATCH 29/93] wip: corner radius v2 --- Cargo.lock | 4 +- Cargo.toml | 2 +- src/lib.rs | 4 +- .../wayland/event_loop/mod.rs | 13 +- .../wayland/event_loop/state.rs | 123 ++++++++++++------ .../wayland/handlers/shell/corner_radius.rs | 55 +++++--- winit/src/platform_specific/wayland/mod.rs | 1 - 7 files changed, 137 insertions(+), 65 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 38f19187..11a85d77 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=160b086#160b086abe03cd34a8a375d7fbe47b24308d1f38" +source = "git+https://github.com/pop-os/cosmic-protocols?rev=a7d2d7a#a7d2d7a6188425f699eaddf7a025617ce56068ae" 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=160b086#160b086abe03cd34a8a375d7fbe47b24308d1f38" +source = "git+https://github.com/pop-os/cosmic-protocols?rev=a7d2d7a#a7d2d7a6188425f699eaddf7a025617ce56068ae" dependencies = [ "bitflags 2.11.0", "wayland-backend", diff --git a/Cargo.toml b/Cargo.toml index e9f43f7f..b5e1b8d7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -274,7 +274,7 @@ tiny-skia = { version = "0.11", default-features = false, features = [ "std", "simd", ] } -cctk = { git = "https://github.com/pop-os/cosmic-protocols", package = "cosmic-client-toolkit", rev = "c253ec1" } +cctk = { git = "https://github.com/pop-os/cosmic-protocols", package = "cosmic-client-toolkit", rev = "a7d2d7a" } softbuffer = { git = "https://github.com/pop-os/softbuffer", tag = "cosmic-4.0" } syntect = "5.2" tokio = "1.0" diff --git a/src/lib.rs b/src/lib.rs index 46685d76..6e57128b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -682,7 +682,9 @@ pub use error::Error; pub use event::Event; pub use executor::Executor; pub use font::Font; -pub use renderer::{Renderer, graphics::geometry}; +pub use renderer::Renderer; +#[cfg(feature = "canvas")] +pub use renderer::graphics::geometry; pub use task::Task; pub use window::Window; diff --git a/winit/src/platform_specific/wayland/event_loop/mod.rs b/winit/src/platform_specific/wayland/event_loop/mod.rs index 61bf12ea..fea1c28c 100644 --- a/winit/src/platform_specific/wayland/event_loop/mod.rs +++ b/winit/src/platform_specific/wayland/event_loop/mod.rs @@ -33,7 +33,7 @@ use cctk::{ reexports::{ calloop::{self, EventLoop}, client::{ - ConnectError, Connection, Proxy, globals::registry_queue_init, + Connection, Proxy, globals::registry_queue_init, }, }, registry::RegistryState, @@ -46,8 +46,6 @@ use cctk::{ }; use raw_window_handle::HasDisplayHandle; use state::{FrameStatus, SctkWindow, send_event}; -#[cfg(feature = "a11y")] -use std::sync::{Arc, Mutex}; use std::{ collections::{HashMap, HashSet}, fmt::Debug, @@ -71,8 +69,8 @@ pub struct SctkEventLoop { pub(crate) state: SctkState, } +#[derive(Debug)] pub enum Error { - Connect(ConnectError), Calloop(calloop::Error), Global(GlobalError), NoDisplayHandle, @@ -129,7 +127,7 @@ impl SctkEventLoop { crate::platform_specific::Action::ResizeWindow(id) => { if let Some((_, v)) = state.windows.iter() .find(|w| w.id == id) - .map(|w| w.corner_radius.as_ref()) + .map(|w| state.corner_radii.get(&id)) .unwrap_or_default() { _ = state.handle_action(iced_runtime::platform_specific::wayland::Action::RoundedCorners(id, *v)); } @@ -138,7 +136,7 @@ impl SctkEventLoop { window, id, ) => { - state.windows.push(SctkWindow { window, id, corner_radius: Default::default() }); + state.windows.push(SctkWindow { window, id }); if let Some(v) = state.pending_corner_radius.remove(&id) { _ = state.handle_action(iced_runtime::platform_specific::wayland::Action::RoundedCorners(id, Some(v))); } @@ -350,7 +348,7 @@ impl SctkEventLoop { ), corner_radius_manager: registry_state.bind_one::( &qh, - 1..=1, + 1..=2, (), ).ok(), toplevel_manager: ToplevelManagerState::try_new( @@ -377,6 +375,7 @@ impl SctkEventLoop { seats: Vec::new(), windows: Vec::new(), blur_surfaces: HashMap::new(), + corner_radii: HashMap::new(), layer_surfaces: Vec::new(), popups: Vec::new(), lock_surfaces: Vec::new(), diff --git a/winit/src/platform_specific/wayland/event_loop/state.rs b/winit/src/platform_specific/wayland/event_loop/state.rs index 6e39fdc2..11f987f9 100644 --- a/winit/src/platform_specific/wayland/event_loop/state.rs +++ b/winit/src/platform_specific/wayland/event_loop/state.rs @@ -1,10 +1,7 @@ use crate::{ Control, handlers::{ - activation::IcedRequestData, - ext_background_effect, - overlap::{OverlapNotificationV1, OverlapNotifyV1}, - text_input::{Preedit, TextInputManager}, + activation::IcedRequestData, ext_background_effect, overlap::{OverlapNotificationV1, OverlapNotifyV1}, shell::corner_radius::CornerRadiusWrapper, text_input::{Preedit, TextInputManager} }, platform_specific::{ Event, @@ -65,7 +62,7 @@ use cctk::{ wl_surface::{self, WlSurface}, wl_touch::WlTouch, }, - }, + }, protocols_wlr::layer_shell::v1::client::zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, }, registry::RegistryState, seat::{ @@ -341,22 +338,13 @@ pub struct SctkPopupData { pub(crate) grab: bool, } -#[derive(Debug)] -pub struct MyCosmicCornerRadiusToplevelV1(CosmicCornerRadiusToplevelV1); - -impl Drop for MyCosmicCornerRadiusToplevelV1 { - fn drop(&mut self) { - self.0.destroy(); - } -} #[derive(Debug, Clone)] -pub struct SctkCornerRadius(Arc); +pub struct SctkCornerRadius(Arc); pub struct SctkWindow { pub(crate) window: Arc, pub(crate) id: core::window::Id, - pub(crate) corner_radius: Option<(SctkCornerRadius, Option)>, } impl SctkWindow { @@ -444,6 +432,7 @@ pub struct SctkState { pub(crate) subsurfaces: Vec, pub(crate) lock_surfaces: Vec, pub(crate) blur_surfaces: HashMap>, + pub(crate) corner_radii: HashMap)>, pub(crate) touch_points: HashMap, /// Window updates, which are coming from SCTK or the compositor, which require @@ -1137,6 +1126,7 @@ impl SctkState { s.destroy(); } } + _ = self.corner_radii.remove(&id); let (removed, remaining): (Vec<_>, Vec<_>) = self .subsurfaces @@ -1396,6 +1386,8 @@ impl SctkState { s.destroy(); } } + _ = self.corner_radii.remove(&id); + let (removed, remaining): (Vec<_>, Vec<_>) = self .subsurfaces @@ -1524,6 +1516,8 @@ impl SctkState { s.destroy(); } } + _ = self.corner_radii.remove(&id); + let (removed, remaining): (Vec<_>, Vec<_>) = self .subsurfaces .drain(..) @@ -1609,6 +1603,8 @@ impl SctkState { s.destroy(); } } + _ = self.corner_radii.remove(&id); + if let Some((wl_surface, f)) = self.seats.iter_mut().find(|f| { f.kbd_focus.as_ref().is_some_and(|f| *f == destroyed) }).and_then(|f| Some((parent, &mut f.kbd_focus))) { @@ -1636,8 +1632,25 @@ impl SctkState { } Action::RoundedCorners(id, v) => { if let Some(manager) = self.corner_radius_manager.as_ref() { - if let Some(w) = self.windows.iter_mut().find(|w| w.id == id) { - let geo_size: LogicalSize = w.window.surface_size().cast::().to_logical(w.window.scale_factor()); + enum Surface { + Xdg(XdgSurface, Option), + 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()))) + } 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::())) + } else if let Some(l) = self.layer_surfaces.iter_mut().find(|l| l.id == id) { + let guard = l.common.lock().unwrap(); + match l.surface.kind() { + SurfaceKind::Wlr(l) => Some((Surface::Wlr(l.clone()), guard.size.cast::())), + _ => None + } + } else { + None + }; + 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 { @@ -1647,37 +1660,73 @@ impl SctkState { bottom_right: radii.bottom_right.min(half_min_dim), bottom_left: radii.bottom_left.min(half_min_dim), }; - if let Some((protocol_object, corner_radii)) = w.corner_radius.as_mut() { + if let Some((protocol_object, corner_radii)) = self.corner_radii.get_mut(&id) { if *corner_radii != Some(adjusted_radii) { - protocol_object.0.0.set_radius( + match protocol_object.0.as_ref() { + CornerRadiusWrapper::Xdg(protocol_object) => protocol_object.set_radius( + adjusted_radii.top_left, + adjusted_radii.top_right, + adjusted_radii.bottom_right, + adjusted_radii.bottom_left, + ), + CornerRadiusWrapper::Wlr(protocol_object) => protocol_object.set_radius( + adjusted_radii.top_left, + adjusted_radii.top_right, + adjusted_radii.bottom_right, + adjusted_radii.bottom_left, + ) + }; + *corner_radii = Some(adjusted_radii.clone()); + } + } else { + + let protocol_object = match s { + Surface::Xdg(s, w) => { + if manager.version() == 1 { + if let Some(w) = w { + CornerRadiusWrapper::Xdg(manager.get_corner_radius(&w, &self.queue_handle, ())) + } else { + log::error!("Corner radius is not supported for popups on xdg shell v1"); + return Ok(()); + } + } else { + CornerRadiusWrapper::Xdg(manager.get_corner_radius_surface(&s, &self.queue_handle, ()))} + } + Surface::Wlr(l) => { + if manager.version() == 1 { + return Ok(()); + } + CornerRadiusWrapper::Wlr(manager.get_corner_radius_layer(&l, &self.queue_handle, ()))} + }; + match &protocol_object { + CornerRadiusWrapper::Xdg(protocol_object) => protocol_object.set_radius( adjusted_radii.top_left, adjusted_radii.top_right, adjusted_radii.bottom_right, adjusted_radii.bottom_left, - ); - *corner_radii = Some(adjusted_radii.clone()); - } - } else { - let toplevel = w.xdg_toplevel(&self.connection); - - let protocol_object = manager.get_corner_radius(&toplevel, &self.queue_handle, ()); - - protocol_object.set_radius( - adjusted_radii.top_left, - adjusted_radii.top_right, - adjusted_radii.bottom_right, - adjusted_radii.bottom_left, - ); - w.corner_radius = Some((SctkCornerRadius(Arc::new(MyCosmicCornerRadiusToplevelV1( protocol_object))), Some(adjusted_radii.clone()))); + ), + CornerRadiusWrapper::Wlr(protocol_object) => protocol_object.set_radius( + adjusted_radii.top_left, + adjusted_radii.top_right, + adjusted_radii.bottom_right, + adjusted_radii.bottom_left, + ) + }; + _ = self.corner_radii.insert(id, (SctkCornerRadius(Arc::new(protocol_object)), Some(adjusted_radii.clone()))); } } else { - if let Some(old) = w.corner_radius.as_mut() { - old.0.0.as_ref().0.unset_radius(); + if let Some(old) = self.corner_radii.get_mut(&id) { + match old.0.0.as_ref() { + CornerRadiusWrapper::Xdg(protocol_object) => protocol_object.unset_radius(), + CornerRadiusWrapper::Wlr(protocol_object) => { + protocol_object.unset_radius() + } + }; old.1 = None; } } } else { - if let Some(v) = v{ + if let Some(v) = v { _ = self.pending_corner_radius.insert(id, v); } else { _ = self.pending_corner_radius.remove(&id); diff --git a/winit/src/platform_specific/wayland/handlers/shell/corner_radius.rs b/winit/src/platform_specific/wayland/handlers/shell/corner_radius.rs index bd7d2409..c4bdda88 100644 --- a/winit/src/platform_specific/wayland/handlers/shell/corner_radius.rs +++ b/winit/src/platform_specific/wayland/handlers/shell/corner_radius.rs @@ -1,17 +1,29 @@ -use cctk::{sctk, cosmic_protocols::{ - corner_radius::v1::client::{ +use cctk::{ + cosmic_protocols::corner_radius::v1::client::{ + cosmic_corner_radius_layer_v1::CosmicCornerRadiusLayerV1, cosmic_corner_radius_manager_v1::CosmicCornerRadiusManagerV1, cosmic_corner_radius_toplevel_v1::CosmicCornerRadiusToplevelV1, }, - overlap_notify::v1::client::zcosmic_overlap_notification_v1::ZcosmicOverlapNotificationV1, -}}; -use sctk::reexports::{ - client::{Connection, Dispatch, Proxy}, - + sctk, }; +use sctk::reexports::client::{Connection, Dispatch, Proxy}; use crate::event_loop::state::SctkState; -use crate::platform_specific::wayland::SctkEvent; + +#[derive(Debug)] +pub enum CornerRadiusWrapper { + Xdg(CosmicCornerRadiusToplevelV1), + Wlr(CosmicCornerRadiusLayerV1), +} + +impl Drop for CornerRadiusWrapper { + fn drop(&mut self) { + match self { + Self::Xdg(c) => c.destroy(), + Self::Wlr(c) => c.destroy(), + }; + } +} impl Dispatch for SctkState { fn event( @@ -21,15 +33,11 @@ impl Dispatch for SctkState { _data: &(), _conn: &Connection, _qhandle: &sctk::reexports::client::QueueHandle, - ) {} + ) { + } } -impl - Dispatch< - CosmicCornerRadiusToplevelV1, - (), - > for SctkState -{ +impl Dispatch for SctkState { fn event( state: &mut Self, _proxy: &CosmicCornerRadiusToplevelV1, @@ -39,7 +47,22 @@ impl _qhandle: &sctk::reexports::client::QueueHandle, ) { match event { - _ => unimplemented!() + _ => unimplemented!(), + } + } +} + +impl Dispatch for SctkState { + fn event( + state: &mut Self, + _proxy: &CosmicCornerRadiusLayerV1, + event: ::Event, + _data: &(), + _conn: &Connection, + _qhandle: &sctk::reexports::client::QueueHandle, + ) { + match event { + _ => unimplemented!(), } } } diff --git a/winit/src/platform_specific/wayland/mod.rs b/winit/src/platform_specific/wayland/mod.rs index 9b3a7ec0..bbbce8f1 100644 --- a/winit/src/platform_specific/wayland/mod.rs +++ b/winit/src/platform_specific/wayland/mod.rs @@ -128,7 +128,6 @@ impl PlatformSpecific { }; self.wayland.display_handle = Some(display); self.wayland.proxy = Some(raw); - // TODO remove this self.wayland.sender = crate::platform_specific::event_loop::SctkEventLoop::new( self.wayland.winit_event_sender.clone().unwrap(), From a63d57261f07b86f3237ce4be053efa94cb33dbe Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Fri, 17 Apr 2026 13:41:09 -0400 Subject: [PATCH 30/93] blur enabled event --- core/src/event/wayland/mod.rs | 2 ++ .../wayland/handlers/ext_background_effect.rs | 14 ++++++++--- .../platform_specific/wayland/sctk_event.rs | 25 ++++++------------- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/core/src/event/wayland/mod.rs b/core/src/event/wayland/mod.rs index 03e74407..5050ce66 100644 --- a/core/src/event/wayland/mod.rs +++ b/core/src/event/wayland/mod.rs @@ -46,4 +46,6 @@ pub enum Event { Subsurface(SubsurfaceEvent), /// Keyboard inhibit shortcuts ShortcutsInhibited(bool), + /// Blur Support Enabled + BlurEnabled, } diff --git a/winit/src/platform_specific/wayland/handlers/ext_background_effect.rs b/winit/src/platform_specific/wayland/handlers/ext_background_effect.rs index 03a80da9..2d0df67a 100644 --- a/winit/src/platform_specific/wayland/handlers/ext_background_effect.rs +++ b/winit/src/platform_specific/wayland/handlers/ext_background_effect.rs @@ -1,6 +1,7 @@ use std::collections::HashMap; use cctk::sctk; +use iced_futures::futures::SinkExt; use iced_runtime::core::Rectangle; use iced_runtime::platform_specific::wayland::Action; use sctk::globals::GlobalData; @@ -11,7 +12,7 @@ use wayland_protocols::ext::background_effect::v1::client::ext_background_effect use wayland_protocols::ext::background_effect::v1::client::ext_background_effect_surface_v1::ExtBackgroundEffectSurfaceV1; use crate::event_loop::state::SctkState; -use crate::window; +use crate::{platform_specific, window}; #[derive(Debug, Clone)] pub struct ExtBackgroundEffectManager { @@ -70,8 +71,15 @@ impl Dispatch state.ext_background_effect_manager.as_mut() { bg_effect_mgr.capabilities = capability; - queued_actions = - bg_effect_mgr.queued_blur_actions.drain().collect(); + if capability.contains(Capability::Blur) { + queued_actions = bg_effect_mgr + .queued_blur_actions + .drain() + .collect(); + state + .sctk_events + .push(crate::sctk_event::SctkEvent::Blur); + } } for (id, rects) in queued_actions { _ = state.handle_action(Action::BlurSurface(id, rects)); diff --git a/winit/src/platform_specific/wayland/sctk_event.rs b/winit/src/platform_specific/wayland/sctk_event.rs index 8845b0c9..2ac54bed 100755 --- a/winit/src/platform_specific/wayland/sctk_event.rs +++ b/winit/src/platform_specific/wayland/sctk_event.rs @@ -68,10 +68,8 @@ use cctk::{ xdg::{popup::PopupConfigure, window::WindowConfigure}, }, }, - wayland_client::protocol::wl_subsurface::WlSubsurface, }; use std::{ - any::Any, collections::HashMap, num::NonZeroU32, sync::{Arc, Mutex}, @@ -98,9 +96,7 @@ use super::{ #[derive(Debug, Clone)] pub enum SctkEvent { - // - // Input events - // + Blur, SeatEvent { variant: SeatEventVariant, id: WlSeat, @@ -122,11 +118,6 @@ pub enum SctkEvent { seat_id: WlSeat, surface: WlSurface, }, - // TODO data device & touch - - // - // Surface Events - // WindowEvent { variant: WindowEventVariant, id: WlSurface, @@ -167,10 +158,6 @@ pub enum SctkEvent { }, SubsurfaceEvent(SubsurfaceEventVariant), - - // - // output events - // NewOutput { id: WlOutput, info: Option, @@ -180,9 +167,7 @@ pub enum SctkEvent { info: OutputInfo, }, RemovedOutput(WlOutput), - // - // compositor events - // + ScaleFactorChanged { factor: f64, id: WlOutput, @@ -1738,6 +1723,12 @@ impl SctkEvent { ), ), )), + SctkEvent::Blur => events.push(( + None, + iced_runtime::core::Event::PlatformSpecific( + PlatformSpecific::Wayland(wayland::Event::BlurEnabled), + ), + )), } } } From e0c7d353aa3915a7543c253679f5038703f20436 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Fri, 17 Apr 2026 13:41:21 -0400 Subject: [PATCH 31/93] better handle pending corners --- .../wayland/event_loop/state.rs | 19 ++++++++++++++++++- 1 file changed, 18 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 11f987f9..ff6e892a 100644 --- a/winit/src/platform_specific/wayland/event_loop/state.rs +++ b/winit/src/platform_specific/wayland/event_loop/state.rs @@ -1099,6 +1099,12 @@ impl SctkState { id: wl_surface.clone(), } ); + if let Some(corners) = self.pending_corner_radius.remove(&id) { + self.handle_action(Action::RoundedCorners( + id, + Some(corners), + ))?; + } } } platform_specific::wayland::layer_surface::Action::Size { @@ -1318,6 +1324,12 @@ impl SctkState { SctkEvent::PopupEvent { variant: crate::platform_specific::wayland::sctk_event::PopupEventVariant::Created(queue_handle.clone(), surface, id, common, state.connection.display()), toplevel_id, parent_id, id: wl_surface }); + if let Some(corners) = state.pending_corner_radius.remove(&id) { + state.handle_action(Action::RoundedCorners ( + id, + Some(corners), + )); + } } Err(err) => { log::error!("Failed to create popup. {err:?}"); @@ -1327,7 +1339,6 @@ impl SctkState { } }); } - // log::error!("Invalid popup Id {:?}", popup.id); } else { self.pending_popup = None; match self.get_popup(settings) { @@ -1337,6 +1348,12 @@ impl SctkState { SctkEvent::PopupEvent { variant: crate::platform_specific::wayland::sctk_event::PopupEventVariant::Created(self.queue_handle.clone(), surface, id, common, self.connection.display()), toplevel_id, parent_id, id: wl_surface }); + if let Some(corners) = self.pending_corner_radius.remove(&id) { + self.handle_action(Action::RoundedCorners ( + id, + Some(corners), + )); + } } Err(err) => { log::error!("Failed to create popup. {err:?}"); From f6fa506f6cc60774fd8606125d005ba9f5074565 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Mon, 20 Apr 2026 15:33:26 -0400 Subject: [PATCH 32/93] chore(layer shell): add padding action --- .../wayland/layer_surface.rs | 43 ++++++++++++++----- .../wayland/commands/layer_surface.rs | 15 ++++++- .../wayland/event_loop/state.rs | 8 ++++ 3 files changed, 54 insertions(+), 12 deletions(-) diff --git a/runtime/src/platform_specific/wayland/layer_surface.rs b/runtime/src/platform_specific/wayland/layer_surface.rs index 4745ef67..6e5f3e9e 100644 --- a/runtime/src/platform_specific/wayland/layer_surface.rs +++ b/runtime/src/platform_specific/wayland/layer_surface.rs @@ -6,8 +6,8 @@ use cctk::sctk::{ }; use iced_core::layout::Limits; -use iced_core::window::Id; use iced_core::Rectangle; +use iced_core::window::Id; /// output for layer surface #[derive(Debug, Clone)] @@ -150,6 +150,13 @@ pub enum Action { /// layer of the layer surface layer: Layer, }, + /// padding of the surface geometry + Padding { + /// id of the layer surface + id: Id, + /// padding of the surface geometry + padding: IcedMargin, + }, } impl fmt::Debug for Action { @@ -162,35 +169,51 @@ impl fmt::Debug for Action { ), Action::Size { id, width, height } => write!( f, - "Action::LayerSurfaceAction::Size {{ id: {:#?}, width: {:?}, height: {:?} }}", id, width, height + "Action::LayerSurfaceAction::Size {{ id: {:#?}, width: {:?}, height: {:?} }}", + id, width, height ), Action::Destroy(id) => write!( f, - "Action::LayerSurfaceAction::Destroy {{ id: {:#?} }}", id + "Action::LayerSurfaceAction::Destroy {{ id: {:#?} }}", + id ), Action::Anchor { id, anchor } => write!( f, - "Action::LayerSurfaceAction::Anchor {{ id: {:#?}, anchor: {:?} }}", id, anchor + "Action::LayerSurfaceAction::Anchor {{ id: {:#?}, anchor: {:?} }}", + id, anchor ), Action::ExclusiveZone { id, exclusive_zone } => write!( f, - "Action::LayerSurfaceAction::ExclusiveZone {{ id: {:#?}, exclusive_zone: {exclusive_zone} }}", id + "Action::LayerSurfaceAction::ExclusiveZone {{ id: {:#?}, exclusive_zone: {exclusive_zone} }}", + id ), Action::Margin { id, margin } => write!( f, - "Action::LayerSurfaceAction::Margin {{ id: {:#?}, margin: {:?} }}", id, margin + "Action::LayerSurfaceAction::Margin {{ id: {:#?}, margin: {:?} }}", + id, margin ), - Action::KeyboardInteractivity { id, keyboard_interactivity } => write!( + Action::KeyboardInteractivity { + id, + keyboard_interactivity, + } => write!( f, - "Action::LayerSurfaceAction::KeyboardInteractivity {{ id: {:#?}, keyboard_interactivity: {:?} }}", id, keyboard_interactivity + "Action::LayerSurfaceAction::KeyboardInteractivity {{ id: {:#?}, keyboard_interactivity: {:?} }}", + id, keyboard_interactivity ), Action::InputZone { id, zone } => write!( f, - "Action::LayerSurfaceAction::InputZone {{ id: {:#?}, zone: {:?} }}", id, zone + "Action::LayerSurfaceAction::InputZone {{ id: {:#?}, zone: {:?} }}", + id, zone ), Action::Layer { id, layer } => write!( f, - "Action::LayerSurfaceAction::Layer {{ id: {:#?}, layer: {:?} }}", id, layer + "Action::LayerSurfaceAction::Layer {{ id: {:#?}, layer: {:?} }}", + id, layer + ), + Action::Padding { id, padding } => write!( + f, + "Action::LayerSurfaceAction::Padding {{ id: {:#?}, padding: {:?} }}", + id, padding ), } } diff --git a/winit/src/platform_specific/wayland/commands/layer_surface.rs b/winit/src/platform_specific/wayland/commands/layer_surface.rs index 839db95c..cdb4e93d 100644 --- a/winit/src/platform_specific/wayland/commands/layer_surface.rs +++ b/winit/src/platform_specific/wayland/commands/layer_surface.rs @@ -2,7 +2,7 @@ use crate::core::window::Id as SurfaceId; use iced_runtime::{ - self, + self, Action, Task, platform_specific::{ self, wayland::{ @@ -10,7 +10,7 @@ use iced_runtime::{ layer_surface::{IcedMargin, SctkLayerSurfaceSettings}, }, }, - task, Action, Task, + task, }; pub use cctk::sctk::shell::wlr_layer::{Anchor, KeyboardInteractivity, Layer}; @@ -114,3 +114,14 @@ pub fn set_layer(id: SurfaceId, layer: Layer) -> Task { )), )) } + +pub fn set_padding( + id: SurfaceId, + padding: IcedMargin, +) -> Task { + task::effect(Action::PlatformSpecific( + platform_specific::Action::Wayland(wayland::Action::LayerSurface( + wayland::layer_surface::Action::Padding { id, padding }, + )), + )) +} diff --git a/winit/src/platform_specific/wayland/event_loop/state.rs b/winit/src/platform_specific/wayland/event_loop/state.rs index ff6e892a..d0159a35 100644 --- a/winit/src/platform_specific/wayland/event_loop/state.rs +++ b/winit/src/platform_specific/wayland/event_loop/state.rs @@ -1229,6 +1229,14 @@ impl SctkState { } }, + platform_specific::wayland::layer_surface::Action::Padding { id, padding } => { + // corner radius padding + if let Some((protocol_object, _)) = self.corner_radii.get_mut(&id) { + if let CornerRadiusWrapper::Wlr(protocol_object) = protocol_object.0.as_ref() { + protocol_object.set_padding(padding.top, padding.right, padding.bottom, padding.left); + } + } + }, }, Action::Popup(action) => match action { platform_specific::wayland::popup::Action::Popup { popup: settings } => { From 6521f7fa20a891d61f1c8782f78e5435968f1f48 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Sun, 10 May 2026 22:36:29 -0400 Subject: [PATCH 33/93] fix: improved layer surface popup cleanup --- winit/src/platform_specific/wayland/event_loop/state.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/winit/src/platform_specific/wayland/event_loop/state.rs b/winit/src/platform_specific/wayland/event_loop/state.rs index d0159a35..dc793561 100644 --- a/winit/src/platform_specific/wayland/event_loop/state.rs +++ b/winit/src/platform_specific/wayland/event_loop/state.rs @@ -1124,6 +1124,12 @@ impl SctkState { } }, platform_specific::wayland::layer_surface::Action::Destroy(id) => { + if let Some(p) = self + .popups + .iter().find_map(|p| + self.layer_surfaces.iter().find_map(|l| if l.id == id && l.surface.wl_surface() == p.data.parent.wl_surface() {Some(p.data.id)} else {None})) { + _ = self.handle_action(Action::Popup(platform_specific::wayland::popup::Action::Destroy { id: p })); + } if let Some(i) = self.layer_surfaces.iter().position(|l| l.id == id) { let l = self.layer_surfaces.remove(i); @@ -1155,6 +1161,8 @@ impl SctkState { if let Some(destroyed) = self.id_map.remove(&l.surface.wl_surface().id()) { _ = self.destroyed.insert(destroyed); } + + send_event(&self.events_sender, &self.proxy, SctkEvent::LayerSurfaceEvent { variant: LayerSurfaceEventVariant::Done, id: l.surface.wl_surface().clone(), From b8b0804140e8ade4fb2058eff173b4cd450a7b83 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Tue, 19 May 2026 14:47:13 -0400 Subject: [PATCH 34/93] fix(overlap): fix check for disabling --- winit/src/platform_specific/wayland/event_loop/state.rs | 2 +- 1 file changed, 1 insertion(+), 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 dc793561..998a599a 100644 --- a/winit/src/platform_specific/wayland/event_loop/state.rs +++ b/winit/src/platform_specific/wayland/event_loop/state.rs @@ -1590,7 +1590,7 @@ impl SctkState { }; let notification = overlap_notify_state.notify.notify_on_overlap(wlr, &self.queue_handle, OverlapNotificationV1 { surface: layer_surface.surface.wl_surface().clone() }); _ = self.overlap_notifications.insert(my_id, notification); - } else { + } else if !enabled { _ = self.overlap_notifications.remove(&my_id); } } else { From 6be49cb530e76c78ac767e89cd9f869533409476 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Thu, 21 May 2026 14:10:28 -0400 Subject: [PATCH 35/93] blur command helper --- .../platform_specific/wayland/commands/blur.rs | 17 +++++++++++++++++ .../platform_specific/wayland/commands/mod.rs | 1 + 2 files changed, 18 insertions(+) create mode 100644 winit/src/platform_specific/wayland/commands/blur.rs diff --git a/winit/src/platform_specific/wayland/commands/blur.rs b/winit/src/platform_specific/wayland/commands/blur.rs new file mode 100644 index 00000000..e9a73646 --- /dev/null +++ b/winit/src/platform_specific/wayland/commands/blur.rs @@ -0,0 +1,17 @@ +use iced_futures::core::window; +use iced_runtime::{ + self, Action, Task, + platform_specific::{self, wayland}, + task, +}; + +pub fn blur( + id: window::Id, + blur: Option>, +) -> Task<()> { + task::oneshot(|_| { + Action::PlatformSpecific(platform_specific::Action::Wayland( + wayland::Action::BlurSurface(id, blur), + )) + }) +} diff --git a/winit/src/platform_specific/wayland/commands/mod.rs b/winit/src/platform_specific/wayland/commands/mod.rs index 191dc3a5..cd6832c7 100644 --- a/winit/src/platform_specific/wayland/commands/mod.rs +++ b/winit/src/platform_specific/wayland/commands/mod.rs @@ -1,6 +1,7 @@ //! Interact with the wayland objects of your application. pub mod activation; +pub mod blur; pub mod corner_radius; pub mod keyboard_shortcuts_inhibit; pub mod layer_surface; From 5cc9f8d621df536facf605adcee3a25c25666e9f Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Thu, 21 May 2026 14:11:20 -0400 Subject: [PATCH 36/93] fix: single blur surface per wl surface --- .../wayland/event_loop/state.rs | 72 ++++++------------- 1 file changed, 23 insertions(+), 49 deletions(-) diff --git a/winit/src/platform_specific/wayland/event_loop/state.rs b/winit/src/platform_specific/wayland/event_loop/state.rs index 998a599a..0fb1a132 100644 --- a/winit/src/platform_specific/wayland/event_loop/state.rs +++ b/winit/src/platform_specific/wayland/event_loop/state.rs @@ -431,7 +431,7 @@ pub struct SctkState { pub(crate) popups: Vec, pub(crate) subsurfaces: Vec, pub(crate) lock_surfaces: Vec, - pub(crate) blur_surfaces: HashMap>, + pub(crate) blur_surfaces: HashMap, pub(crate) corner_radii: HashMap)>, pub(crate) touch_points: HashMap, @@ -1134,9 +1134,7 @@ impl SctkState { let l = self.layer_surfaces.remove(i); if let Some(blurred) = self.blur_surfaces.remove(&l.id) { - for s in blurred { - s.destroy(); - } + blurred.destroy(); } _ = self.corner_radii.remove(&id); @@ -1415,9 +1413,7 @@ impl SctkState { } if let Some(blurred) = self.blur_surfaces.remove(&id) { - for s in blurred { - s.destroy(); - } + blurred.destroy(); } _ = self.corner_radii.remove(&id); @@ -1545,9 +1541,7 @@ impl SctkState { { let surface = self.lock_surfaces.remove(i); if let Some(blurred) = self.blur_surfaces.remove(&surface.id) { - for s in blurred { - s.destroy(); - } + blurred.destroy(); } _ = self.corner_radii.remove(&id); @@ -1632,9 +1626,7 @@ impl SctkState { } for (destroyed, parent, id) in destroyed { if let Some(blurred) = self.blur_surfaces.remove(&id) { - for s in blurred { - s.destroy(); - } + blurred.destroy(); } _ = self.corner_radii.remove(&id); @@ -1790,45 +1782,27 @@ impl SctkState { let existing_blur = self.blur_surfaces.entry(id); match (existing_blur, rectangles) { (Entry::Occupied(occupied_entry), None) => { - let blur_surfaces = occupied_entry.remove(); - for region in blur_surfaces { - region.destroy(); - } + let blur_surface = occupied_entry.remove(); + blur_surface.destroy(); }, (Entry::Occupied(mut occupied_entry), Some(rectangles)) => { - let blur_surfaces = occupied_entry.get_mut(); - let regions = rectangles.into_iter().map(|rect| { - let region = self + let blur_surface = occupied_entry.get_mut(); + let region = self .compositor_state .wl_compositor() .create_region(&self.queue_handle, ()); + for rect in rectangles.into_iter() { region.add( rect.x.round() as i32, rect.y.round() as i32, rect.width.round() as i32, rect.height.round() as i32, ); - region - }).collect::>(); - if regions.len() > blur_surfaces.len() { - // add extra blur surfaces if needed - for _ in blur_surfaces.len()..regions.len() { - let Some(extra_region) = self.ext_background_effect_manager.as_mut().map(|mgr| mgr.blur(s, &self.queue_handle)) else { - log::error!("Failed to create blur effect for surface"); - return Ok(()); - }; - blur_surfaces.push(extra_region); - } - } else if regions.len() < blur_surfaces.len() { - for surface in blur_surfaces.iter().skip(regions.len()) { - surface.destroy(); - } } - + // update existing blur surfaces - for (blur_surface, region) in blur_surfaces.iter().zip(regions.into_iter()) { - blur_surface.set_blur_region(Some(®ion)); - } + blur_surface.set_blur_region(Some(®ion)); + }, (Entry::Vacant(..), None) => { // nothing to remove @@ -1838,23 +1812,23 @@ impl SctkState { log::error!("Blur effect is not supported."); return Ok(()); } - let blur_surfaces = rectangles.into_iter().map(|rect| { let region = self .compositor_state .wl_compositor() .create_region(&self.queue_handle, ()); - region.add( - rect.x.round() as i32, - rect.y.round() as i32, - rect.width.round() as i32, - rect.height.round() as i32, - ); + for rect in rectangles { + region.add( + rect.x.round() as i32, + rect.y.round() as i32, + rect.width.round() as i32, + rect.height.round() as i32, + ); + } + let blur_manager = self.ext_background_effect_manager.as_mut().unwrap(); let blur_surface = blur_manager.blur(s, &self.queue_handle); blur_surface.set_blur_region(Some(®ion)); - blur_surface - }).collect::>(); - _ = vacant_entry.insert(blur_surfaces); + _ = vacant_entry.insert(blur_surface); }, } }, From 46781102fe38b1bc26e6486085ea5446230293f3 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Thu, 28 May 2026 19:21:54 -0400 Subject: [PATCH 37/93] fix: set blur and corners on creation --- .../wayland/event_loop/mod.rs | 1 + .../wayland/event_loop/state.rs | 180 ++++++++++-------- 2 files changed, 100 insertions(+), 81 deletions(-) diff --git a/winit/src/platform_specific/wayland/event_loop/mod.rs b/winit/src/platform_specific/wayland/event_loop/mod.rs index fea1c28c..b4589840 100644 --- a/winit/src/platform_specific/wayland/event_loop/mod.rs +++ b/winit/src/platform_specific/wayland/event_loop/mod.rs @@ -401,6 +401,7 @@ impl SctkEventLoop { preedit: None, pending_delete: None, pending_commit: None, + pending_blur: HashMap::new(), }, _features: Default::default(), }; diff --git a/winit/src/platform_specific/wayland/event_loop/state.rs b/winit/src/platform_specific/wayland/event_loop/state.rs index 0fb1a132..d66f99c5 100644 --- a/winit/src/platform_specific/wayland/event_loop/state.rs +++ b/winit/src/platform_specific/wayland/event_loop/state.rs @@ -39,15 +39,12 @@ use cctk::{ cosmic_protocols::{ corner_radius::v1::client::{ cosmic_corner_radius_manager_v1::CosmicCornerRadiusManagerV1, - cosmic_corner_radius_toplevel_v1::CosmicCornerRadiusToplevelV1, }, overlap_notify::v1::client::zcosmic_overlap_notification_v1::ZcosmicOverlapNotificationV1, - }, - sctk::{ + }, sctk::{ activation::{ActivationState, RequestData}, compositor::CompositorState, error::GlobalError, - globals::GlobalData, output::OutputState, reexports::{ calloop::{LoopHandle, timer::TimeoutAction}, @@ -87,9 +84,7 @@ use cctk::{ }, }, shm::{Shm, multi::MultiPool}, - }, - toplevel_info::ToplevelInfoState, - toplevel_management::ToplevelManagerState, + }, toplevel_info::ToplevelInfoState, toplevel_management::ToplevelManagerState }; use iced_runtime::{ core::{self, Point, touch}, @@ -104,7 +99,7 @@ use iced_runtime::{ }, }; use wayland_protocols::{ - ext::background_effect::v1::client::ext_background_effect_surface_v1::ExtBackgroundEffectSurfaceV1, + ext::background_effect::v1::client::{ext_background_effect_manager_v1, ext_background_effect_surface_v1::ExtBackgroundEffectSurfaceV1}, wp::{ fractional_scale::v1::client::wp_fractional_scale_v1::WpFractionalScaleV1, keyboard_shortcuts_inhibit::zv1::client::{ @@ -486,6 +481,7 @@ pub struct SctkState { pub(crate) corner_radius_manager: Option, pub(crate) pending_corner_radius: HashMap, + pub(crate) pending_blur: HashMap>, pub(crate) text_input_manager: Option, pub(crate) text_input: Option>, @@ -836,6 +832,7 @@ impl SctkState { ) } }; + let toplevel = toplevel.clone(); popup.xdg_surface().set_window_geometry( 0, @@ -868,6 +865,18 @@ impl SctkState { } _ = wl_surface.frame(&self.queue_handle, wl_surface.clone()); + if let Some(corners) = self.pending_corner_radius.remove(&settings.id) { + self.handle_action(Action::RoundedCorners ( + settings.id, + Some(corners), + )); + } + if let Some(blur) = self.pending_blur.remove(&settings.id) { + self.apply_blur(settings.id, Some(blur), &wl_surface); + } + + + wl_surface.commit(); let wp_viewport = self.viewporter_state.as_ref().map(|state| { @@ -996,6 +1005,15 @@ impl SctkState { layer_surface.set_input_region(Some(®ion)); region.destroy(); } + if let Some(blur) = self.pending_blur.remove(&id) { + self.apply_blur(id, Some(blur), &wl_surface); + } + if let Some(corners) = self.pending_corner_radius.remove(&id) { + _ = self.handle_action(Action::RoundedCorners( + id, + Some(corners), + )); + } layer_surface.commit(); let wp_viewport = self.viewporter_state.as_ref().map(|state| { @@ -1099,12 +1117,6 @@ impl SctkState { id: wl_surface.clone(), } ); - if let Some(corners) = self.pending_corner_radius.remove(&id) { - self.handle_action(Action::RoundedCorners( - id, - Some(corners), - ))?; - } } } platform_specific::wayland::layer_surface::Action::Size { @@ -1338,12 +1350,6 @@ impl SctkState { SctkEvent::PopupEvent { variant: crate::platform_specific::wayland::sctk_event::PopupEventVariant::Created(queue_handle.clone(), surface, id, common, state.connection.display()), toplevel_id, parent_id, id: wl_surface }); - if let Some(corners) = state.pending_corner_radius.remove(&id) { - state.handle_action(Action::RoundedCorners ( - id, - Some(corners), - )); - } } Err(err) => { log::error!("Failed to create popup. {err:?}"); @@ -1362,12 +1368,6 @@ impl SctkState { SctkEvent::PopupEvent { variant: crate::platform_specific::wayland::sctk_event::PopupEventVariant::Created(self.queue_handle.clone(), surface, id, common, self.connection.display()), toplevel_id, parent_id, id: wl_surface }); - if let Some(corners) = self.pending_corner_radius.remove(&id) { - self.handle_action(Action::RoundedCorners ( - id, - Some(corners), - )); - } } Err(err) => { log::error!("Failed to create popup. {err:?}"); @@ -1776,66 +1776,74 @@ impl SctkState { } else if let Some(subsurface) = self.subsurfaces.iter().find(|s| s.id == id) { &subsurface.instance.wl_surface } else { - log::error!("Failed to find surface for blur action"); + log::info!("Failed to find surface for blur action"); + if let Some(rectangles) = rectangles { + _ = self.pending_blur.insert(id, rectangles.clone()); + } return Ok(()); - }; - let existing_blur = self.blur_surfaces.entry(id); - match (existing_blur, rectangles) { - (Entry::Occupied(occupied_entry), None) => { - let blur_surface = occupied_entry.remove(); - blur_surface.destroy(); - }, - (Entry::Occupied(mut occupied_entry), Some(rectangles)) => { - let blur_surface = occupied_entry.get_mut(); - let region = self - .compositor_state - .wl_compositor() - .create_region(&self.queue_handle, ()); - for rect in rectangles.into_iter() { - region.add( - rect.x.round() as i32, - rect.y.round() as i32, - rect.width.round() as i32, - rect.height.round() as i32, - ); - } - - // update existing blur surfaces - blur_surface.set_blur_region(Some(®ion)); - - }, - (Entry::Vacant(..), None) => { - // nothing to remove - }, - (Entry::Vacant(vacant_entry), Some(rectangles)) => { - if self.ext_background_effect_manager.is_none() { - log::error!("Blur effect is not supported."); - return Ok(()); - } - let region = self - .compositor_state - .wl_compositor() - .create_region(&self.queue_handle, ()); - for rect in rectangles { - region.add( - rect.x.round() as i32, - rect.y.round() as i32, - rect.width.round() as i32, - rect.height.round() as i32, - ); - } - - let blur_manager = self.ext_background_effect_manager.as_mut().unwrap(); - let blur_surface = blur_manager.blur(s, &self.queue_handle); - blur_surface.set_blur_region(Some(®ion)); - _ = vacant_entry.insert(blur_surface); - }, - } + }.clone(); + self.apply_blur(id, rectangles, &s) }, }; Ok(()) } + fn apply_blur(&mut self, id: core::window::Id, rectangles: Option>, 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(); + blur_surface.destroy(); + }, + (Entry::Occupied(mut occupied_entry), Some(rectangles)) => { + let blur_surface = occupied_entry.get_mut(); + let region = self + .compositor_state + .wl_compositor() + .create_region(&self.queue_handle, ()); + for rect in rectangles.into_iter() { + region.add( + rect.x.round() as i32, + rect.y.round() as i32, + rect.width.round() as i32, + rect.height.round() as i32, + ); + } + + // update existing blur surfaces + blur_surface.set_blur_region(Some(®ion)); + + }, + (Entry::Vacant(..), None) => { + // nothing to remove + }, + (Entry::Vacant(vacant_entry), Some(rectangles)) => { + if self.ext_background_effect_manager.is_none() { + log::error!("Blur effect is not supported."); + return; + } + let region = self + .compositor_state + .wl_compositor() + .create_region(&self.queue_handle, ()); + for rect in rectangles { + region.add( + rect.x.round() as i32, + rect.y.round() as i32, + rect.width.round() as i32, + rect.height.round() as i32, + ); + } + + let blur_manager = self.ext_background_effect_manager.as_mut().unwrap(); + let blur_surface = blur_manager.blur(s, &self.queue_handle); + blur_surface.set_blur_region(Some(®ion)); + _ = vacant_entry.insert(blur_surface); + }, + } + + } + pub fn get_subsurface( &mut self, settings: SctkSubsurfaceSettings, @@ -1849,7 +1857,7 @@ impl SctkState { ), SubsurfaceCreationError, > { - let Some(subsurface_state) = self.subsurface_state.as_ref() else { + let Some(subsurface_state) = self.subsurface_state.clone() else { return Err(SubsurfaceCreationError::Unsupported); }; if self.layer_surfaces.iter().any(|s| s.id == settings.id) @@ -1965,6 +1973,16 @@ impl SctkState { region.destroy(); } + if let Some(blur) = self.pending_blur.remove(&settings.id) { + _ = self.apply_blur(settings.id, Some(blur), &wl_surface); + } + if let Some(corners) = self.pending_corner_radius.remove(&settings.id) { + self.handle_action(Action::RoundedCorners ( + settings.id, + Some(corners), + )); + } + wl_surface.commit(); let wp_viewport = subsurface_state.wp_viewporter.get_viewport( From 8e94441efad36dca2cef70fa3bc431dd5160871a Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Thu, 4 Jun 2026 19:59:01 -0400 Subject: [PATCH 38/93] fix: apply initial corner radius after adding surfaces to the state otherwise the corners won't be set. --- .../wayland/event_loop/state.rs | 49 ++++++++++--------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/winit/src/platform_specific/wayland/event_loop/state.rs b/winit/src/platform_specific/wayland/event_loop/state.rs index d66f99c5..4fdfd09d 100644 --- a/winit/src/platform_specific/wayland/event_loop/state.rs +++ b/winit/src/platform_specific/wayland/event_loop/state.rs @@ -865,19 +865,12 @@ impl SctkState { } _ = wl_surface.frame(&self.queue_handle, wl_surface.clone()); - if let Some(corners) = self.pending_corner_radius.remove(&settings.id) { - self.handle_action(Action::RoundedCorners ( - settings.id, - Some(corners), - )); - } + if let Some(blur) = self.pending_blur.remove(&settings.id) { self.apply_blur(settings.id, Some(blur), &wl_surface); } - - wl_surface.commit(); let wp_viewport = self.viewporter_state.as_ref().map(|state| { let viewport = @@ -909,7 +902,14 @@ impl SctkState { common: common.clone(), close_with_children: settings.close_with_children, }); - + + if let Some(corners) = self.pending_corner_radius.remove(&settings.id) { + self.handle_action(Action::RoundedCorners ( + settings.id, + Some(corners), + )); + } + wl_surface.commit(); Ok(( settings.id, parent.wl_surface().clone(), @@ -1008,13 +1008,7 @@ impl SctkState { if let Some(blur) = self.pending_blur.remove(&id) { self.apply_blur(id, Some(blur), &wl_surface); } - if let Some(corners) = self.pending_corner_radius.remove(&id) { - _ = self.handle_action(Action::RoundedCorners( - id, - Some(corners), - )); - } - layer_surface.commit(); + let wp_viewport = self.viewporter_state.as_ref().map(|state| { state.get_viewport(layer_surface.wl_surface(), &self.queue_handle) @@ -1048,6 +1042,13 @@ impl SctkState { wp_fractional_scale, common: common.clone(), }); + if let Some(corners) = self.pending_corner_radius.remove(&id) { + _ = self.handle_action(Action::RoundedCorners( + id, + Some(corners), + )); + } + layer_surface.commit(); Ok((id, CommonSurface::Layer(layer_surface), common)) } pub fn get_lock_surface( @@ -1976,14 +1977,7 @@ impl SctkState { if let Some(blur) = self.pending_blur.remove(&settings.id) { _ = self.apply_blur(settings.id, Some(blur), &wl_surface); } - if let Some(corners) = self.pending_corner_radius.remove(&settings.id) { - self.handle_action(Action::RoundedCorners ( - settings.id, - Some(corners), - )); - } - - wl_surface.commit(); + let wp_viewport = subsurface_state.wp_viewporter.get_viewport( &wl_surface, @@ -2059,7 +2053,14 @@ impl SctkState { // XXX subsurfaces need to be sorted by z in descending order self.subsurfaces .sort_by(|a, b| b.instance.z.cmp(&a.instance.z)); + if let Some(corners) = self.pending_corner_radius.remove(&id) { + self.handle_action(Action::RoundedCorners ( + id, + Some(corners), + )); + } + wl_surface.commit(); Ok(( id, parent.wl_surface().clone(), From da9d15b2e8a0c15934035a898b1c64dab7af4059 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Thu, 25 Jun 2026 13:44:29 -0400 Subject: [PATCH 39/93] chore: update cosmic-protocols --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index b5e1b8d7..555f7901 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -274,7 +274,7 @@ tiny-skia = { version = "0.11", default-features = false, features = [ "std", "simd", ] } -cctk = { git = "https://github.com/pop-os/cosmic-protocols", package = "cosmic-client-toolkit", rev = "a7d2d7a" } +cctk = { git = "https://github.com/pop-os/cosmic-protocols", package = "cosmic-client-toolkit", rev = "32283d7" } softbuffer = { git = "https://github.com/pop-os/softbuffer", tag = "cosmic-4.0" } syntect = "5.2" tokio = "1.0" From 633ed144110b5be8bf87c14326ea46a09260bab9 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Thu, 25 Jun 2026 15:25:36 -0400 Subject: [PATCH 40/93] feat: popup reposition --- .../src/platform_specific/wayland/popup.rs | 28 +++++++----- .../wayland/commands/popup.rs | 21 +++++++-- .../wayland/event_loop/state.rs | 43 +++++++++++++++++++ 3 files changed, 79 insertions(+), 13 deletions(-) diff --git a/runtime/src/platform_specific/wayland/popup.rs b/runtime/src/platform_specific/wayland/popup.rs index e0475eb8..27279ab6 100644 --- a/runtime/src/platform_specific/wayland/popup.rs +++ b/runtime/src/platform_specific/wayland/popup.rs @@ -124,26 +124,34 @@ pub enum Action { /// height height: u32, }, + /// set the size of the popup + Reposition { + /// id of the popup + id: Id, + /// positioner of the popup + positioner: SctkPositioner, + }, } impl fmt::Debug for Action { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Action::Popup { popup, .. } => write!( - f, - "Action::PopupAction::Popup {{ popup: {:?} }}", - popup - ), - Action::Destroy { id } => write!( - f, - "Action::PopupAction::Destroy {{ id: {:?} }}", - id - ), + Action::Popup { popup, .. } => { + write!(f, "Action::PopupAction::Popup {{ popup: {:?} }}", popup) + } + Action::Destroy { id } => { + write!(f, "Action::PopupAction::Destroy {{ id: {:?} }}", id) + } Action::Size { id, width, height } => write!( f, "Action::PopupAction::Size {{ id: {:?}, width: {:?}, height: {:?} }}", id, width, height ), + Action::Reposition { id, positioner } => write!( + f, + "Action::Reposition {{ id: {:?}, positioner: {:?} }}", + id, positioner + ), } } } diff --git a/winit/src/platform_specific/wayland/commands/popup.rs b/winit/src/platform_specific/wayland/commands/popup.rs index f70d97f4..c702f4f1 100644 --- a/winit/src/platform_specific/wayland/commands/popup.rs +++ b/winit/src/platform_specific/wayland/commands/popup.rs @@ -1,12 +1,15 @@ //! Interact with the popups of your application. use crate::core::window::Id as SurfaceId; use iced_runtime::{ - self, + self, Action, Task, platform_specific::{ self, - wayland::{self, popup::SctkPopupSettings}, + wayland::{ + self, + popup::{SctkPopupSettings, SctkPositioner}, + }, }, - task, Action, Task, + task, }; /// @@ -32,6 +35,18 @@ pub fn set_size( )) } +/// +pub fn reposition( + id: SurfaceId, + positioner: SctkPositioner, +) -> Task { + task::effect(Action::PlatformSpecific( + platform_specific::Action::Wayland(wayland::Action::Popup( + wayland::popup::Action::Reposition { id, positioner }, + )), + )) +} + /// pub fn destroy_popup(id: SurfaceId) -> Task { task::effect(Action::PlatformSpecific( diff --git a/winit/src/platform_specific/wayland/event_loop/state.rs b/winit/src/platform_specific/wayland/event_loop/state.rs index 4fdfd09d..8126e864 100644 --- a/winit/src/platform_specific/wayland/event_loop/state.rs +++ b/winit/src/platform_specific/wayland/event_loop/state.rs @@ -1454,6 +1454,49 @@ impl SctkState { SctkEvent::PopupEvent { variant: crate::sctk_event::PopupEventVariant::Size(width, height), toplevel_id: sctk_popup.data.parent.wl_surface().clone(), parent_id: sctk_popup.data.parent.wl_surface().clone(), id: surface }); } }, + platform_specific::wayland::popup::Action::Reposition { id, positioner } => { + if let Some(sctk_popup) = self + .popups + .iter_mut() + .find(|s| s.data.id == id) + { + sctk_popup.data.positioner.set_anchor(positioner.anchor); + sctk_popup.data.positioner.set_anchor_rect( + positioner.anchor_rect.x, + positioner.anchor_rect.y, + positioner.anchor_rect.width, + positioner.anchor_rect.height, + ); + if let Ok(constraint_adjustment) = + positioner.constraint_adjustment.try_into() + { + sctk_popup.data.positioner.set_constraint_adjustment(constraint_adjustment); + } + sctk_popup.data.positioner.set_gravity(positioner.gravity); + sctk_popup.data.positioner.set_offset( + positioner.offset.0, + positioner.offset.1, + ); + if positioner.reactive { + sctk_popup.data.positioner.set_reactive(); + } + let guard =sctk_popup.common.lock().unwrap(); + let w = guard.size.width; + let h = guard.size.height; + drop(guard); + let size = positioner.size.unwrap_or((w, h)); + sctk_popup.popup + .xdg_surface() + .set_window_geometry(0, 0, w as i32, h as i32); + sctk_popup.update_viewport(w, h); + // update positioner + sctk_popup.data.positioner.set_size(w as i32, h as i32); + sctk_popup.popup.reposition(&sctk_popup.data.positioner, TOKEN_CTR.fetch_add(1, std::sync::atomic::Ordering::Relaxed)); let surface = sctk_popup.popup.wl_surface().clone(); + dbg!("repositioning..."); + _ = send_event(&self.events_sender, &self.proxy, + SctkEvent::PopupEvent { variant: crate::sctk_event::PopupEventVariant::Size(size.0, size.1), toplevel_id: sctk_popup.data.parent.wl_surface().clone(), parent_id: sctk_popup.data.parent.wl_surface().clone(), id: surface }); + } + }, }, Action::Activation(activation_event) => match activation_event { platform_specific::wayland::activation::Action::RequestToken { app_id, window, channel } => { From c781ff6199715f5650411c7ac625d4e1929bfdfb Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Thu, 25 Jun 2026 15:27:31 -0400 Subject: [PATCH 41/93] chore: cargo fmt --- examples/counter/src/main.rs | 4 +- examples/sctk_drag/src/dnd_destination.rs | 10 +- examples/sctk_drag/src/dnd_source.rs | 40 +++---- examples/sctk_subsurface/src/main.rs | 2 +- runtime/src/dnd.rs | 2 +- .../platform_specific/wayland/activation.rs | 2 +- wgpu/src/window/compositor.rs | 11 +- widget/src/keyed/column.rs | 27 +++-- widget/src/text/rich.rs | 5 +- winit/src/lib.rs | 108 ++++++++--------- .../wayland/commands/activation.rs | 4 +- .../wayland/commands/corner_radius.rs | 4 +- .../commands/keyboard_shortcuts_inhibit.rs | 4 +- .../wayland/commands/overlap_notify.rs | 3 +- .../wayland/commands/session_lock.rs | 4 +- .../wayland/commands/subsurface.rs | 4 +- .../wayland/event_loop/proxy.rs | 2 +- .../wayland/event_loop/state.rs | 110 +++++++++--------- .../wayland/handlers/seat/touch.rs | 4 +- .../wayland/handlers/session_lock.rs | 3 +- .../wayland/handlers/shell/layer.rs | 4 +- .../wayland/handlers/shell/mod.rs | 2 +- .../wayland/handlers/wp_viewporter.rs | 4 +- winit/src/platform_specific/wayland/mod.rs | 1 + 24 files changed, 192 insertions(+), 172 deletions(-) diff --git a/examples/counter/src/main.rs b/examples/counter/src/main.rs index 5027afd7..cfae782a 100644 --- a/examples/counter/src/main.rs +++ b/examples/counter/src/main.rs @@ -1,5 +1,5 @@ +use iced::widget::{button, column, text, Column}; use iced::Center; -use iced::widget::{Column, button, column, text}; pub fn main() -> iced::Result { iced::run(Counter::update, Counter::view) @@ -42,7 +42,7 @@ impl Counter { #[cfg(test)] mod tests { use super::*; - use iced_test::{Error, simulator}; + use iced_test::{simulator, Error}; #[test] fn it_counts() -> Result<(), Error> { diff --git a/examples/sctk_drag/src/dnd_destination.rs b/examples/sctk_drag/src/dnd_destination.rs index 1081d8bb..d1b3374b 100644 --- a/examples/sctk_drag/src/dnd_destination.rs +++ b/examples/sctk_drag/src/dnd_destination.rs @@ -3,20 +3,20 @@ use std::{ sync::atomic::{AtomicU64, Ordering}, }; -use iced::{Element, id::Id}; use iced::{ - Event, Length, Rectangle, clipboard::{ dnd::{self, DndAction, DndDestinationRectangle, DndEvent, OfferEvent}, mime::AllowedMimeTypes, }, event, id::Internal, - mouse, overlay, + mouse, overlay, Event, Length, Rectangle, }; +use iced::{id::Id, Element}; use iced_core::{ - self, Clipboard, Layout, Shell, Widget, layout, - widget::{Tree, tree}, + self, layout, + widget::{tree, Tree}, + Clipboard, Layout, Shell, Widget, }; pub fn dnd_destination<'a, Message: 'static>( diff --git a/examples/sctk_drag/src/dnd_source.rs b/examples/sctk_drag/src/dnd_source.rs index 1d8b85c4..e93b925e 100644 --- a/examples/sctk_drag/src/dnd_source.rs +++ b/examples/sctk_drag/src/dnd_source.rs @@ -1,16 +1,16 @@ use std::any::Any; -use iced::Element; use iced::id::Id; use iced::widget::container; +use iced::Element; use iced::{ - Event, Length, Point, Rectangle, clipboard::dnd::{DndAction, DndEvent, SourceEvent}, - event, mouse, overlay, + event, mouse, overlay, Event, Length, Point, Rectangle, }; use iced_core::{ - Clipboard, Shell, layout, renderer, - widget::{Tree, tree}, + layout, renderer, + widget::{tree, Tree}, + Clipboard, Shell, }; use iced_core::{Layout, Widget}; @@ -37,11 +37,11 @@ pub struct DndSource<'a, Message, AppMessage, D> { } impl< - 'a, - Message: 'static, - AppMessage: 'static, - D: iced::clipboard::mime::AsMimeTypes + std::marker::Send + 'static, -> DndSource<'a, Message, AppMessage, D> + 'a, + Message: 'static, + AppMessage: 'static, + D: iced::clipboard::mime::AsMimeTypes + std::marker::Send + 'static, + > DndSource<'a, Message, AppMessage, D> { pub fn new(child: impl Into>) -> Self { Self { @@ -119,11 +119,11 @@ impl< } impl< - 'a, - Message: 'static, - AppMessage: 'static, - D: iced::clipboard::mime::AsMimeTypes + std::marker::Send + 'static, -> Widget + 'a, + Message: 'static, + AppMessage: 'static, + D: iced::clipboard::mime::AsMimeTypes + std::marker::Send + 'static, + > Widget for DndSource<'a, Message, AppMessage, D> { fn children(&self) -> Vec { @@ -357,11 +357,11 @@ impl< } impl< - 'a, - Message: 'static, - AppMessage: 'static, - D: iced::clipboard::mime::AsMimeTypes + std::marker::Send + 'static, -> From> for Element<'a, Message> + 'a, + Message: 'static, + AppMessage: 'static, + D: iced::clipboard::mime::AsMimeTypes + std::marker::Send + 'static, + > From> for Element<'a, Message> { fn from(e: DndSource<'a, Message, AppMessage, D>) -> Element<'a, Message> { Element::new(e) diff --git a/examples/sctk_subsurface/src/main.rs b/examples/sctk_subsurface/src/main.rs index c00f7225..a204572c 100644 --- a/examples/sctk_subsurface/src/main.rs +++ b/examples/sctk_subsurface/src/main.rs @@ -7,7 +7,6 @@ use cctk::sctk::reexports::{ use iced::platform_specific::shell::commands::subsurface::get_subsurface; use iced::{ - Element, Length, Subscription, Task, event::wayland::Event as WaylandEvent, platform_specific::{ runtime::wayland::subsurface::SctkSubsurfaceSettings, @@ -15,6 +14,7 @@ use iced::{ }, widget::{button, column, text, text_input}, window::{self, Id, Settings}, + Element, Length, Subscription, Task, }; use std::sync::{Arc, Mutex}; diff --git a/runtime/src/dnd.rs b/runtime/src/dnd.rs index e6f2b267..2a0db116 100644 --- a/runtime/src/dnd.rs +++ b/runtime/src/dnd.rs @@ -6,7 +6,7 @@ use dnd::{DndDestinationRectangle, DndSurface}; use iced_core::clipboard::DndSource; use window_clipboard::mime::{AllowedMimeTypes, AsMimeTypes}; -use crate::{oneshot, task, Action, Task}; +use crate::{Action, Task, oneshot, task}; /// An action to be performed on the system. pub enum DndAction { diff --git a/runtime/src/platform_specific/wayland/activation.rs b/runtime/src/platform_specific/wayland/activation.rs index 64d4dc4d..3f48f01c 100644 --- a/runtime/src/platform_specific/wayland/activation.rs +++ b/runtime/src/platform_specific/wayland/activation.rs @@ -36,7 +36,7 @@ impl fmt::Debug for Action { f, "Action::ActivationAction::Activate {{ window: {:?}, token: {:?} }}", window, token, - ) + ), } } } diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs index f0595f2b..58c7d713 100644 --- a/wgpu/src/window/compositor.rs +++ b/wgpu/src/window/compositor.rs @@ -296,11 +296,12 @@ impl Compositor { }); // Request SHADER_F16 only if the adapter supports it (e.g., not available in WebGL2) - let required_features = if adapter.features().contains(wgpu::Features::SHADER_F16) { - wgpu::Features::SHADER_F16 - } else { - wgpu::Features::empty() - }; + let required_features = + if adapter.features().contains(wgpu::Features::SHADER_F16) { + wgpu::Features::SHADER_F16 + } else { + wgpu::Features::empty() + }; let mut errors = Vec::new(); diff --git a/widget/src/keyed/column.rs b/widget/src/keyed/column.rs index baaee5c9..ef7d9d9a 100644 --- a/widget/src/keyed/column.rs +++ b/widget/src/keyed/column.rs @@ -293,9 +293,12 @@ where .zip(&mut tree.children) .zip(layout.children()) .for_each(|((child, state), c_layout)| { - child - .as_widget_mut() - .operate(state, c_layout.with_virtual_offset(layout.virtual_offset()), renderer, operation); + child.as_widget_mut().operate( + state, + c_layout.with_virtual_offset(layout.virtual_offset()), + renderer, + operation, + ); }); }); } @@ -318,7 +321,13 @@ where .zip(layout.children()) { child.as_widget_mut().update( - tree, event, c_layout.with_virtual_offset(layout.virtual_offset()), cursor, renderer, clipboard, shell, + tree, + event, + c_layout.with_virtual_offset(layout.virtual_offset()), + cursor, + renderer, + clipboard, + shell, viewport, ); } @@ -337,9 +346,13 @@ where .zip(&tree.children) .zip(layout.children()) .map(|((child, tree), c_layout)| { - child - .as_widget() - .mouse_interaction(tree, c_layout.with_virtual_offset(layout.virtual_offset()), cursor, viewport, renderer) + child.as_widget().mouse_interaction( + tree, + c_layout.with_virtual_offset(layout.virtual_offset()), + cursor, + viewport, + renderer, + ) }) .max() .unwrap_or_default() diff --git a/widget/src/text/rich.rs b/widget/src/text/rich.rs index 80abc8d5..ef44e2bf 100644 --- a/widget/src/text/rich.rs +++ b/widget/src/text/rich.rs @@ -179,7 +179,10 @@ where { let color = color.map(Into::into); - self.style(move |_theme| Style { color, ..Style::default() }) + self.style(move |_theme| Style { + color, + ..Style::default() + }) } /// Sets the default style class of the [`Rich`] text. diff --git a/winit/src/lib.rs b/winit/src/lib.rs index 410949ac..517eddbc 100644 --- a/winit/src/lib.rs +++ b/winit/src/lib.rs @@ -40,12 +40,6 @@ pub mod clipboard; pub mod conversion; pub mod platform_specific; -#[cfg(feature = "program")] -pub mod program; - -#[cfg(feature = "system")] -pub mod system; - mod error; mod proxy; mod window; @@ -193,10 +187,13 @@ where error: Option, system_theme: Option>, control_sender: mpsc::UnboundedSender, - + #[cfg(feature = "a11y")] - adapters: std::collections::HashMap, - + adapters: std::collections::HashMap< + window::Id, + (u64, iced_accessibility::accesskit_winit::Adapter), + >, + #[cfg(target_arch = "wasm32")] is_booted: std::rc::Rc>, #[cfg(target_arch = "wasm32")] @@ -501,9 +498,15 @@ where } }; } - let window: Arc = Arc::from(window); + let window: Arc< + dyn winit::window::Window + 'static, + > = Arc::from(window); #[cfg(feature = "a11y")] - self.init_adapter(event_loop, id, window.clone()); + self.init_adapter( + event_loop, + id, + window.clone(), + ); self.process_event( event_loop, @@ -572,11 +575,13 @@ where .expect("Send event"); } Control::Winit(id, e) => { - #[cfg(all(feature = "cctk", target_os = "linux"))] + #[cfg(all( + feature = "cctk", + target_os = "linux" + ))] { if matches!(e, WindowEvent::RedrawRequested) - { - + { for id in crate::subsurface_widget::subsurface_ids(id) { _ = self.sender .unbounded_send(Event::Winit( @@ -597,7 +602,7 @@ where } } } - + self.sender .start_send(Event::Winit(id, e)) .expect("Send event"); @@ -610,7 +615,7 @@ where #[cfg(feature = "a11y")] Control::InitAdapter(id, window) => { self.init_adapter(event_loop, id, window); - + self.process_event( event_loop, Some(Event::A11yAdapter(id)), @@ -618,8 +623,8 @@ where } #[cfg(feature = "a11y")] Control::Cleanup(id) => { - _ = self.adapters.remove(&id); - }, + _ = self.adapters.remove(&id); + } }, _ => { break; @@ -633,34 +638,35 @@ where } } - #[cfg(feature = "a11y")] - fn init_adapter(&mut self, event_loop: &(dyn winit::event_loop::ActiveEventLoop + 'static), id: core::window::Id, window: Arc) { + #[cfg(feature = "a11y")] + fn init_adapter( + &mut self, + event_loop: &(dyn winit::event_loop::ActiveEventLoop + 'static), + id: core::window::Id, + window: Arc, + ) { use crate::a11y::*; use iced_accessibility::accesskit::{ - ActivationHandler, Node, NodeId, Role, - Tree, TreeUpdate, + ActivationHandler, Node, NodeId, Role, Tree, TreeUpdate, }; use iced_accessibility::accesskit_winit::Adapter; - - let node_id = - iced_runtime::core::id::window_node_id(); - - let activation_handler = - WinitActivationHandler { - proxy: self.control_sender.clone(), - title: String::new(), - }; - + + let node_id = iced_runtime::core::id::window_node_id(); + + let activation_handler = WinitActivationHandler { + proxy: self.control_sender.clone(), + title: String::new(), + }; + let action_handler = WinitActionHandler { id, proxy: self.control_sender.clone(), }; - - let deactivation_handler = - WinitDeactivationHandler { - proxy: self.control_sender.clone(), - }; - + + let deactivation_handler = WinitDeactivationHandler { + proxy: self.control_sender.clone(), + }; + _ = self.adapters.insert( id, ( @@ -674,8 +680,6 @@ where ), ), ); - - } } @@ -879,9 +883,8 @@ async fn run_instance

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

( compositor, exit_on_close_request, system_theme, - resize_border + resize_border, ); window.raw.set_theme(conversion::window_theme( @@ -1034,7 +1037,7 @@ async fn run_instance

( continue; }; - let Some((id, mut window)) = + let Some((id, mut window)) = window_manager.get_mut_alias(window_id) else { continue; @@ -1049,12 +1052,12 @@ async fn run_instance

( )) .expect("Send redraw event"); continue; - } + } // XX must force update to corner radius before the surface is committed. #[cfg(all(feature = "cctk", target_os = "linux"))] if (window.surface_version != window.state.surface_version() - || window.logical_size() != window.state.logical_size() - ) && !crate::subsurface_widget::is_subsurface(window_id) + || window.logical_size() != window.state.logical_size()) + && !crate::subsurface_widget::is_subsurface(window_id) { platform_specific_handler.send_wayland( platform_specific::Action::ResizeWindow(id), @@ -1320,9 +1323,7 @@ async fn run_instance

( continue; }; // Initiates a drag resize window state when found. - if let Some(func) = - window.drag_resize_window_func.as_mut() - { + if let Some(func) = window.drag_resize_window_func.as_mut() { if func(window.raw.as_ref(), &event) { continue; } @@ -1348,7 +1349,9 @@ async fn run_instance

( if matches!(event, winit::event::WindowEvent::CloseRequested) && window.exit_on_close_request { - _ = run_action!(Action::Window(runtime::window::Action::Close(id))); + _ = run_action!(Action::Window( + runtime::window::Action::Close(id) + )); } else { window.state.update(&program, window.raw.as_ref(), &event); @@ -1736,7 +1739,6 @@ async fn run_instance

( }; // search windows for widget with operation - if result.is_none() { log::warn!( "start_dnd: widget {:?} not found; drag will fail", @@ -2113,7 +2115,7 @@ where on_open: channel, }) .expect("Send control action"); - + *is_window_opening = true; } window::Action::Close(id) => { diff --git a/winit/src/platform_specific/wayland/commands/activation.rs b/winit/src/platform_specific/wayland/commands/activation.rs index fa051031..442ee08c 100644 --- a/winit/src/platform_specific/wayland/commands/activation.rs +++ b/winit/src/platform_specific/wayland/commands/activation.rs @@ -1,8 +1,8 @@ use crate::core::window::Id as SurfaceId; use iced_runtime::{ - self, + self, Action, Task, platform_specific::{self, wayland}, - task, Action, Task, + task, }; pub fn request_token( diff --git a/winit/src/platform_specific/wayland/commands/corner_radius.rs b/winit/src/platform_specific/wayland/commands/corner_radius.rs index c5ba6016..4cc122dd 100644 --- a/winit/src/platform_specific/wayland/commands/corner_radius.rs +++ b/winit/src/platform_specific/wayland/commands/corner_radius.rs @@ -1,11 +1,11 @@ use iced_futures::core::window; use iced_runtime::{ - self, + self, Action, Task, platform_specific::{ self, wayland::{self, CornerRadius}, }, - task, Action, Task, + task, }; pub fn corner_radius( diff --git a/winit/src/platform_specific/wayland/commands/keyboard_shortcuts_inhibit.rs b/winit/src/platform_specific/wayland/commands/keyboard_shortcuts_inhibit.rs index 783b62c6..afc2e27b 100644 --- a/winit/src/platform_specific/wayland/commands/keyboard_shortcuts_inhibit.rs +++ b/winit/src/platform_specific/wayland/commands/keyboard_shortcuts_inhibit.rs @@ -1,7 +1,7 @@ use iced_runtime::{ - self, + self, Action, Task, platform_specific::{self, wayland}, - task, Action, Task, + task, }; pub fn inhibit_shortcuts(inhibit: bool) -> Task<()> { diff --git a/winit/src/platform_specific/wayland/commands/overlap_notify.rs b/winit/src/platform_specific/wayland/commands/overlap_notify.rs index 860838c3..417cfb24 100644 --- a/winit/src/platform_specific/wayland/commands/overlap_notify.rs +++ b/winit/src/platform_specific/wayland/commands/overlap_notify.rs @@ -1,7 +1,8 @@ use iced_futures::core::window::Id; use iced_runtime::{ + Action, Task, platform_specific::{self, wayland}, - task, Action, Task, + task, }; /// Request subscription for overlap notification events on the surface diff --git a/winit/src/platform_specific/wayland/commands/session_lock.rs b/winit/src/platform_specific/wayland/commands/session_lock.rs index 7f8748f7..a530c12e 100644 --- a/winit/src/platform_specific/wayland/commands/session_lock.rs +++ b/winit/src/platform_specific/wayland/commands/session_lock.rs @@ -1,9 +1,9 @@ use crate::core::window::Id as SurfaceId; use cctk::sctk::reexports::client::protocol::wl_output::WlOutput; use iced_runtime::{ - self, + self, Action, Task, platform_specific::{self, wayland}, - task, Action, Task, + task, }; pub fn lock() -> Task { diff --git a/winit/src/platform_specific/wayland/commands/subsurface.rs b/winit/src/platform_specific/wayland/commands/subsurface.rs index a76e3b4e..20c3cdb7 100644 --- a/winit/src/platform_specific/wayland/commands/subsurface.rs +++ b/winit/src/platform_specific/wayland/commands/subsurface.rs @@ -1,12 +1,12 @@ use crate::core::window::Id as SurfaceId; pub use cctk::sctk::shell::wlr_layer::{Anchor, KeyboardInteractivity, Layer}; use iced_runtime::{ - self, + self, Action, Task, platform_specific::{ self, wayland::{self, subsurface::SctkSubsurfaceSettings}, }, - task, Action, Task, + task, }; pub fn get_subsurface( diff --git a/winit/src/platform_specific/wayland/event_loop/proxy.rs b/winit/src/platform_specific/wayland/event_loop/proxy.rs index bdbc44a4..58229dc1 100644 --- a/winit/src/platform_specific/wayland/event_loop/proxy.rs +++ b/winit/src/platform_specific/wayland/event_loop/proxy.rs @@ -1,8 +1,8 @@ use cctk::sctk::reexports::calloop; use iced_futures::futures::{ + Sink, channel::mpsc, task::{Context, Poll}, - Sink, }; use std::pin::Pin; diff --git a/winit/src/platform_specific/wayland/event_loop/state.rs b/winit/src/platform_specific/wayland/event_loop/state.rs index 8126e864..b817e4d5 100644 --- a/winit/src/platform_specific/wayland/event_loop/state.rs +++ b/winit/src/platform_specific/wayland/event_loop/state.rs @@ -1,7 +1,11 @@ use crate::{ Control, handlers::{ - activation::IcedRequestData, ext_background_effect, overlap::{OverlapNotificationV1, OverlapNotifyV1}, shell::corner_radius::CornerRadiusWrapper, text_input::{Preedit, TextInputManager} + activation::IcedRequestData, + ext_background_effect, + overlap::{OverlapNotificationV1, OverlapNotifyV1}, + shell::corner_radius::CornerRadiusWrapper, + text_input::{Preedit, TextInputManager}, }, platform_specific::{ Event, @@ -37,11 +41,10 @@ use winit::{ use cctk::{ cosmic_protocols::{ - corner_radius::v1::client::{ - cosmic_corner_radius_manager_v1::CosmicCornerRadiusManagerV1, - }, + corner_radius::v1::client::cosmic_corner_radius_manager_v1::CosmicCornerRadiusManagerV1, overlap_notify::v1::client::zcosmic_overlap_notification_v1::ZcosmicOverlapNotificationV1, - }, sctk::{ + }, + sctk::{ activation::{ActivationState, RequestData}, compositor::CompositorState, error::GlobalError, @@ -59,7 +62,8 @@ use cctk::{ wl_surface::{self, WlSurface}, wl_touch::WlTouch, }, - }, protocols_wlr::layer_shell::v1::client::zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, + }, + protocols_wlr::layer_shell::v1::client::zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, }, registry::RegistryState, seat::{ @@ -84,7 +88,9 @@ use cctk::{ }, }, shm::{Shm, multi::MultiPool}, - }, toplevel_info::ToplevelInfoState, toplevel_management::ToplevelManagerState + }, + toplevel_info::ToplevelInfoState, + toplevel_management::ToplevelManagerState, }; use iced_runtime::{ core::{self, Point, touch}, @@ -99,7 +105,10 @@ use iced_runtime::{ }, }; use wayland_protocols::{ - ext::background_effect::v1::client::{ext_background_effect_manager_v1, ext_background_effect_surface_v1::ExtBackgroundEffectSurfaceV1}, + ext::background_effect::v1::client::{ + ext_background_effect_manager_v1, + ext_background_effect_surface_v1::ExtBackgroundEffectSurfaceV1, + }, wp::{ fractional_scale::v1::client::wp_fractional_scale_v1::WpFractionalScaleV1, keyboard_shortcuts_inhibit::zv1::client::{ @@ -333,7 +342,6 @@ pub struct SctkPopupData { pub(crate) grab: bool, } - #[derive(Debug, Clone)] pub struct SctkCornerRadius(Arc); @@ -865,13 +873,11 @@ impl SctkState { } _ = wl_surface.frame(&self.queue_handle, wl_surface.clone()); - + if let Some(blur) = self.pending_blur.remove(&settings.id) { self.apply_blur(settings.id, Some(blur), &wl_surface); } - - let wp_viewport = self.viewporter_state.as_ref().map(|state| { let viewport = state.get_viewport(popup.wl_surface(), &self.queue_handle); @@ -902,9 +908,9 @@ impl SctkState { common: common.clone(), close_with_children: settings.close_with_children, }); - + if let Some(corners) = self.pending_corner_radius.remove(&settings.id) { - self.handle_action(Action::RoundedCorners ( + self.handle_action(Action::RoundedCorners( settings.id, Some(corners), )); @@ -1008,7 +1014,6 @@ impl SctkState { if let Some(blur) = self.pending_blur.remove(&id) { self.apply_blur(id, Some(blur), &wl_surface); } - let wp_viewport = self.viewporter_state.as_ref().map(|state| { state.get_viewport(layer_surface.wl_surface(), &self.queue_handle) @@ -1043,10 +1048,7 @@ impl SctkState { common: common.clone(), }); if let Some(corners) = self.pending_corner_radius.remove(&id) { - _ = self.handle_action(Action::RoundedCorners( - id, - Some(corners), - )); + _ = self.handle_action(Action::RoundedCorners(id, Some(corners))); } layer_surface.commit(); Ok((id, CommonSurface::Layer(layer_surface), common)) @@ -1139,7 +1141,7 @@ impl SctkState { platform_specific::wayland::layer_surface::Action::Destroy(id) => { if let Some(p) = self .popups - .iter().find_map(|p| + .iter().find_map(|p| self.layer_surfaces.iter().find_map(|l| if l.id == id && l.surface.wl_surface() == p.data.parent.wl_surface() {Some(p.data.id)} else {None})) { _ = self.handle_action(Action::Popup(platform_specific::wayland::popup::Action::Destroy { id: p })); } @@ -1173,7 +1175,6 @@ impl SctkState { _ = self.destroyed.insert(destroyed); } - send_event(&self.events_sender, &self.proxy, SctkEvent::LayerSurfaceEvent { variant: LayerSurfaceEventVariant::Done, id: l.surface.wl_surface().clone(), @@ -1492,7 +1493,6 @@ impl SctkState { // update positioner sctk_popup.data.positioner.set_size(w as i32, h as i32); sctk_popup.popup.reposition(&sctk_popup.data.positioner, TOKEN_CTR.fetch_add(1, std::sync::atomic::Ordering::Relaxed)); let surface = sctk_popup.popup.wl_surface().clone(); - dbg!("repositioning..."); _ = send_event(&self.events_sender, &self.proxy, SctkEvent::PopupEvent { variant: crate::sctk_event::PopupEventVariant::Size(size.0, size.1), toplevel_id: sctk_popup.data.parent.wl_surface().clone(), parent_id: sctk_popup.data.parent.wl_surface().clone(), id: surface }); } @@ -1832,19 +1832,24 @@ impl SctkState { Ok(()) } - fn apply_blur(&mut self, id: core::window::Id, rectangles: Option>, s: &WlSurface) { + fn apply_blur( + &mut self, + id: core::window::Id, + rectangles: Option>, + 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(); blur_surface.destroy(); - }, + } (Entry::Occupied(mut occupied_entry), Some(rectangles)) => { let blur_surface = occupied_entry.get_mut(); let region = self - .compositor_state - .wl_compositor() - .create_region(&self.queue_handle, ()); + .compositor_state + .wl_compositor() + .create_region(&self.queue_handle, ()); for rect in rectangles.into_iter() { region.add( rect.x.round() as i32, @@ -1853,41 +1858,40 @@ impl SctkState { rect.height.round() as i32, ); } - + // update existing blur surfaces blur_surface.set_blur_region(Some(®ion)); - - }, + } (Entry::Vacant(..), None) => { // nothing to remove - }, + } (Entry::Vacant(vacant_entry), Some(rectangles)) => { if self.ext_background_effect_manager.is_none() { log::error!("Blur effect is not supported."); return; } - let region = self - .compositor_state - .wl_compositor() - .create_region(&self.queue_handle, ()); - for rect in rectangles { - region.add( - rect.x.round() as i32, - rect.y.round() as i32, - rect.width.round() as i32, - rect.height.round() as i32, - ); - } - - let blur_manager = self.ext_background_effect_manager.as_mut().unwrap(); - let blur_surface = blur_manager.blur(s, &self.queue_handle); - blur_surface.set_blur_region(Some(®ion)); + let region = self + .compositor_state + .wl_compositor() + .create_region(&self.queue_handle, ()); + for rect in rectangles { + region.add( + rect.x.round() as i32, + rect.y.round() as i32, + rect.width.round() as i32, + rect.height.round() as i32, + ); + } + + let blur_manager = + self.ext_background_effect_manager.as_mut().unwrap(); + let blur_surface = blur_manager.blur(s, &self.queue_handle); + blur_surface.set_blur_region(Some(®ion)); _ = vacant_entry.insert(blur_surface); - }, + } } - } - + pub fn get_subsurface( &mut self, settings: SctkSubsurfaceSettings, @@ -2020,7 +2024,6 @@ impl SctkState { if let Some(blur) = self.pending_blur.remove(&settings.id) { _ = self.apply_blur(settings.id, Some(blur), &wl_surface); } - let wp_viewport = subsurface_state.wp_viewporter.get_viewport( &wl_surface, @@ -2097,10 +2100,7 @@ impl SctkState { self.subsurfaces .sort_by(|a, b| b.instance.z.cmp(&a.instance.z)); if let Some(corners) = self.pending_corner_radius.remove(&id) { - self.handle_action(Action::RoundedCorners ( - id, - Some(corners), - )); + self.handle_action(Action::RoundedCorners(id, Some(corners))); } wl_surface.commit(); diff --git a/winit/src/platform_specific/wayland/handlers/seat/touch.rs b/winit/src/platform_specific/wayland/handlers/seat/touch.rs index f726fd93..a0b1cce0 100644 --- a/winit/src/platform_specific/wayland/handlers/seat/touch.rs +++ b/winit/src/platform_specific/wayland/handlers/seat/touch.rs @@ -9,12 +9,12 @@ use crate::{ use cctk::sctk::{ delegate_touch, reexports::client::{ - protocol::{wl_surface::WlSurface, wl_touch::WlTouch}, Connection, Proxy, QueueHandle, + protocol::{wl_surface::WlSurface, wl_touch::WlTouch}, }, seat::touch::TouchHandler, }; -use iced_runtime::core::{touch, Point}; +use iced_runtime::core::{Point, touch}; impl TouchHandler for SctkState { fn down( diff --git a/winit/src/platform_specific/wayland/handlers/session_lock.rs b/winit/src/platform_specific/wayland/handlers/session_lock.rs index 6c617a20..98eb5586 100644 --- a/winit/src/platform_specific/wayland/handlers/session_lock.rs +++ b/winit/src/platform_specific/wayland/handlers/session_lock.rs @@ -1,8 +1,7 @@ use crate::{ event_loop::state::CommonSurface, platform_specific::wayland::{ - event_loop::state::receive_frame, - handlers::SctkState, + event_loop::state::receive_frame, handlers::SctkState, sctk_event::SctkEvent, }, }; diff --git a/winit/src/platform_specific/wayland/handlers/shell/layer.rs b/winit/src/platform_specific/wayland/handlers/shell/layer.rs index 65e5724b..22fd6560 100644 --- a/winit/src/platform_specific/wayland/handlers/shell/layer.rs +++ b/winit/src/platform_specific/wayland/handlers/shell/layer.rs @@ -1,13 +1,13 @@ use crate::platform_specific::wayland::{ - event_loop::state::{receive_frame, SctkState}, + event_loop::state::{SctkState, receive_frame}, sctk_event::{LayerSurfaceEventVariant, SctkEvent}, }; use cctk::sctk::{ delegate_layer, reexports::client::Proxy, shell::{ - wlr_layer::{Anchor, KeyboardInteractivity, LayerShellHandler}, WaylandSurface, + wlr_layer::{Anchor, KeyboardInteractivity, LayerShellHandler}, }, }; use std::fmt::Debug; diff --git a/winit/src/platform_specific/wayland/handlers/shell/mod.rs b/winit/src/platform_specific/wayland/handlers/shell/mod.rs index af8b5961..c4117eb7 100644 --- a/winit/src/platform_specific/wayland/handlers/shell/mod.rs +++ b/winit/src/platform_specific/wayland/handlers/shell/mod.rs @@ -1,4 +1,4 @@ +pub mod corner_radius; pub mod layer; pub mod xdg_popup; pub mod xdg_window; -pub mod corner_radius; diff --git a/winit/src/platform_specific/wayland/handlers/wp_viewporter.rs b/winit/src/platform_specific/wayland/handlers/wp_viewporter.rs index 5cfe28d7..7bbd66d1 100644 --- a/winit/src/platform_specific/wayland/handlers/wp_viewporter.rs +++ b/winit/src/platform_specific/wayland/handlers/wp_viewporter.rs @@ -1,10 +1,10 @@ //! Handling of the wp-viewporter. +use cctk::sctk::reexports::client::Dispatch; use cctk::sctk::reexports::client::globals::{BindError, GlobalList}; use cctk::sctk::reexports::client::protocol::wl_surface::WlSurface; -use cctk::sctk::reexports::client::Dispatch; use cctk::sctk::reexports::client::{ - delegate_dispatch, Connection, Proxy, QueueHandle, + Connection, Proxy, QueueHandle, delegate_dispatch, }; use cctk::sctk::reexports::protocols::wp::viewporter::client::wp_viewport::WpViewport; use cctk::sctk::reexports::protocols::wp::viewporter::client::wp_viewporter::WpViewporter; diff --git a/winit/src/platform_specific/wayland/mod.rs b/winit/src/platform_specific/wayland/mod.rs index bbbce8f1..e98316ce 100644 --- a/winit/src/platform_specific/wayland/mod.rs +++ b/winit/src/platform_specific/wayland/mod.rs @@ -21,6 +21,7 @@ use iced_runtime::core::{Vector, window}; use raw_window_handle::{DisplayHandle, HasDisplayHandle, HasWindowHandle}; use raw_window_handle::{HasRawDisplayHandle, RawWindowHandle}; use sctk_event::SctkEvent; +use std::sync::OnceLock; use std::{collections::HashMap, sync::Arc}; use subsurface_widget::{SubsurfaceInstance, SubsurfaceState}; use wayland_backend::client::ObjectId; From a50a29b3905168b6c93cc48ae9bfa2205c59149a Mon Sep 17 00:00:00 2001 From: leyoda Date: Fri, 24 Apr 2026 06:00:03 +0200 Subject: [PATCH 42/93] yoda: drop x11 default on winit workspace dep MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Was pulling winit's full x11 backend (winit-x11 + x11-dl) unconditionally despite iced_winit's own x11 feature being disabled. Fixed by adding default-features=false on the workspace-level winit dep — iced_winit/wayland + wayland-dlopen propagate to winit/wayland + wayland-dlopen as needed. --- Cargo.toml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 555f7901..bf7bcfdf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -304,7 +304,11 @@ winapi = "0.3" window_clipboard = { git = "https://github.com/pop-os/window_clipboard.git", tag = "sctk-0.20" } dnd = { git = "https://github.com/pop-os/window_clipboard.git", tag = "sctk-0.20" } mime = { git = "https://github.com/pop-os/window_clipboard.git", tag = "sctk-0.20" } -winit = { git = "https://github.com/pop-os/winit.git", tag = "cosmic-0.14" } +# Yoda: default-features = false drops winit's x11 default, which otherwise +# pulls winit-x11, x11-dl, tiny-xlib, as-raw-xcb-connection. Our Wayland-only +# fork doesn't need any of that — the wayland + wayland-dlopen features are +# re-enabled via iced_winit's own feature propagation from libcosmic-yoda. +winit = { git = "https://github.com/pop-os/winit.git", tag = "cosmic-0.14", default-features = false } winit-core = { git = "https://github.com/pop-os/winit.git", tag = "cosmic-0.14" } cursor-icon = "1.1.0" From 702b6359a54a4eb4ff5cd31a1edc818a31233f19 Mon Sep 17 00:00:00 2001 From: leyoda Date: Fri, 24 Apr 2026 06:24:15 +0200 Subject: [PATCH 43/93] yoda: gate iced_wgpu x11 backend behind an opt-in feature MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit iced_wgpu's unix block unconditionally depended on as-raw-xcb-connection, tiny-xlib and x11rb for a DRI3 device-id fallback in window/compositor.rs that only fires when wayland can't determine the GPU. On a Wayland-only build this code path never runs, so the deps are pure bloat. Changes: - Cargo.toml: move the 3 x11 crates to optional + new feature `x11` (not in default — wayland-only is the yoda target; users who need X11 opt in). - window.rs: cfg-gate `mod x11;` on feature = "x11" - window/compositor.rs: cfg-gate `use super::x11::get_x11_device_ids` + the or_else fallback on feature = "x11" (wrapped in a let-binding so the non-x11 branch compiles cleanly). Result: iced_wgpu no longer pulls any x11 crate when built without the feature. --- wgpu/Cargo.toml | 11 ++++++++--- wgpu/src/window.rs | 2 +- wgpu/src/window/compositor.rs | 8 +++++--- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml index 48fca1b8..ffbcd293 100644 --- a/wgpu/Cargo.toml +++ b/wgpu/Cargo.toml @@ -25,6 +25,11 @@ svg = ["iced_graphics/svg", "resvg/text"] web-colors = ["iced_graphics/web-colors"] webgl = ["wgpu/webgl"] strict-assertions = [] +# Yoda: opt-in X11 backend. Pulls tiny-xlib/as-raw-xcb-connection/x11rb +# (which otherwise were unconditional direct deps on unix). Wayland-only +# builds just leave this off — window/x11.rs and the DRI3 device-id +# fallback in window/compositor.rs are cfg-gated on it. +x11 = ["dep:as-raw-xcb-connection", "dep:tiny-xlib", "dep:x11rb"] [dependencies] iced_debug.workspace = true @@ -57,9 +62,9 @@ wayland-protocols.workspace = true wayland-backend = { version = "0.3.3", features = ["client_system"] } wayland-client = { version = "0.31.2" } wayland-sys = { version = "0.31.1", features = ["dlopen"] } -as-raw-xcb-connection = "1.0.1" -tiny-xlib = "0.2.3" -x11rb = { version = "0.13.1", features = [ +as-raw-xcb-connection = { version = "1.0.1", optional = true } +tiny-xlib = { version = "0.2.3", optional = true } +x11rb = { version = "0.13.1", optional = true, features = [ "allow-unsafe-code", "dl-libxcb", "dri3", diff --git a/wgpu/src/window.rs b/wgpu/src/window.rs index b9ec54bd..f71b7d3f 100644 --- a/wgpu/src/window.rs +++ b/wgpu/src/window.rs @@ -7,7 +7,7 @@ pub mod compositor; not(target_os = "redox") ))] mod wayland; -#[cfg(all(unix, not(target_os = "macos"), not(target_os = "redox")))] +#[cfg(all(unix, feature = "x11", not(target_os = "macos"), not(target_os = "redox")))] mod x11; pub use compositor::Compositor; diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs index 58c7d713..d6186ab5 100644 --- a/wgpu/src/window/compositor.rs +++ b/wgpu/src/window/compositor.rs @@ -16,7 +16,7 @@ use crate::{Engine, Renderer}; not(target_os = "redox") ))] use super::wayland::get_wayland_device_ids; -#[cfg(all(unix, not(target_os = "macos"), not(target_os = "redox")))] +#[cfg(all(unix, feature = "x11", not(target_os = "macos"), not(target_os = "redox")))] use super::x11::get_x11_device_ids; use std::future::Future; @@ -72,8 +72,10 @@ impl Compositor { not(target_os = "redox") ))] let ids = compatible_window.as_ref().and_then(|window| { - get_wayland_device_ids(window) - .or_else(|| get_x11_device_ids(window)) + let w = get_wayland_device_ids(window); + #[cfg(feature = "x11")] + let w = w.or_else(|| get_x11_device_ids(window)); + w }); #[cfg(all( From f1f42f2bff0e1198c2f0b07d238f6b552df33717 Mon Sep 17 00:00:00 2001 From: leyoda Date: Fri, 24 Apr 2026 06:53:36 +0200 Subject: [PATCH 44/93] yoda: softbuffer + window_clipboard default-features=false Two one-line workspace-dep fixes that drop the last remaining X11 crates for Wayland-only builds: - softbuffer: its default = [kms, x11, x11-dlopen, wayland, wayland-dlopen] pulled tiny-xlib + as-raw-xcb-connection unconditionally even though iced_tiny_skia only needed softbuffer/wayland. Disabling the default lets iced_tiny_skia's own feature propagation ask for just wayland + wayland-dlopen. - window_clipboard: upstream pulled clipboard_x11 + clipboard_wayland unconditionally on unix. Our local fork (branch yoda-x11-optional) gates clipboard_x11 behind an opt-in feature, so default-features=false + features=["wayland"] drops ~500 x11 symbols (clipboard_x11, x11rb, x11rb-protocol). Combined with previous yoda-v4 cuts, cosmic-yoterm goes from 1526 -> 43 x11 symbols (-97%), and 55.4 MB -> 53.3 MB (-2.1 MB). --- Cargo.toml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index bf7bcfdf..f3d7b8f9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -275,7 +275,10 @@ tiny-skia = { version = "0.11", default-features = false, features = [ "simd", ] } cctk = { git = "https://github.com/pop-os/cosmic-protocols", package = "cosmic-client-toolkit", rev = "32283d7" } -softbuffer = { git = "https://github.com/pop-os/softbuffer", tag = "cosmic-4.0" } +# Yoda: default-features=false drops softbuffer's x11 / x11-dlopen (pulled +# tiny-xlib + as-raw-xcb-connection). The wayland + wayland-dlopen features +# are re-activated via iced_tiny_skia's own `wayland` feature propagation. +softbuffer = { git = "https://github.com/pop-os/softbuffer", tag = "cosmic-4.0", default-features = false } syntect = "5.2" tokio = "1.0" tracing = "0.1" @@ -301,7 +304,11 @@ wayland-client = { version = "0.31.5" } winapi = "0.3" # window_clipboard = "0.4.1" -window_clipboard = { git = "https://github.com/pop-os/window_clipboard.git", tag = "sctk-0.20" } +# Yoda: window_clipboard via git path = our local fork that has x11 gated +# behind an opt-in feature. default-features=false + features=["wayland"] +# drops clipboard_x11 + x11rb from the build. +# Kept at /home/lionel/Devels/window_clipboard branch yoda-x11-optional. +window_clipboard = { git = "https://github.com/pop-os/window_clipboard.git", tag = "sctk-0.20", default-features = false, features = ["wayland"] } dnd = { git = "https://github.com/pop-os/window_clipboard.git", tag = "sctk-0.20" } mime = { git = "https://github.com/pop-os/window_clipboard.git", tag = "sctk-0.20" } # Yoda: default-features = false drops winit's x11 default, which otherwise From ce5ea665e2d45042456232ee0cc989eef9a7c5e4 Mon Sep 17 00:00:00 2001 From: Votre Nom Date: Tue, 5 May 2026 08:27:03 +0200 Subject: [PATCH 45/93] Fix high-signal widget and Wayland warnings Avoid recursive operation traversal, execute visible list updates instead of leaving a lazy iterator unused, remove unreachable cfg-gated surface creation code, and handle subsurface buffer attachment failures. --- widget/src/container.rs | 2 +- winit/src/platform_specific/mod.rs | 7 +++++-- winit/src/platform_specific/wayland/subsurface_widget.rs | 5 ++++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/widget/src/container.rs b/widget/src/container.rs index c9a300c9..e4aeabf2 100644 --- a/widget/src/container.rs +++ b/widget/src/container.rs @@ -601,7 +601,7 @@ pub fn visible_bounds(id: Id) -> Task> { operate: &mut dyn FnMut(&mut dyn Operation>), ) { self.depth += 1; - self.traverse(operate); + operate(self); self.depth -= 1; } diff --git a/winit/src/platform_specific/mod.rs b/winit/src/platform_specific/mod.rs index 9b74ee9c..5e84d16a 100644 --- a/winit/src/platform_specific/mod.rs +++ b/winit/src/platform_specific/mod.rs @@ -153,9 +153,12 @@ impl PlatformSpecific { ) -> Option> { #[cfg(all(feature = "cctk", target_os = "linux"))] { - return self.wayland.create_surface(); + self.wayland.create_surface() + } + #[cfg(not(all(feature = "cctk", target_os = "linux")))] + { + None } - None } pub(crate) fn update_surface_shm( diff --git a/winit/src/platform_specific/wayland/subsurface_widget.rs b/winit/src/platform_specific/wayland/subsurface_widget.rs index dbecc52d..c3173fa9 100644 --- a/winit/src/platform_specific/wayland/subsurface_widget.rs +++ b/winit/src/platform_specific/wayland/subsurface_widget.rs @@ -409,7 +409,10 @@ impl SubsurfaceState { .unwrap(); canvas[0..width as usize * height as usize * 4].copy_from_slice(data); surface.damage_buffer(0, 0, width as i32, height as i32); - buffer.attach_to(&surface); + if let Err(err) = buffer.attach_to(&surface) { + log::warn!("failed to attach shm buffer to subsurface: {err}"); + return; + } surface.offset(offset.x as i32, offset.y as i32); wp_viewport.set_destination( (width as f64 / scale) as i32, From b90b1413a69acb3bdbed49d62c7a6e14d43170d3 Mon Sep 17 00:00:00 2001 From: Votre Nom Date: Tue, 5 May 2026 12:52:06 +0200 Subject: [PATCH 46/93] yoda: point window_clipboard at public Forgejo fork MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace pop-os/window_clipboard sctk-0.20 (no wayland feature) with forge.aditua.com/leyoda/window_clipboard branch yoda-x11-optional. This removes the need for cosmic-files' [patch] redirect to a local path and makes libcosmic build standalone again. Leyoda 2026 – GPLv3 --- Cargo.toml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f3d7b8f9..1a0b86f1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -304,13 +304,13 @@ wayland-client = { version = "0.31.5" } winapi = "0.3" # window_clipboard = "0.4.1" -# Yoda: window_clipboard via git path = our local fork that has x11 gated -# behind an opt-in feature. default-features=false + features=["wayland"] -# drops clipboard_x11 + x11rb from the build. -# Kept at /home/lionel/Devels/window_clipboard branch yoda-x11-optional. -window_clipboard = { git = "https://github.com/pop-os/window_clipboard.git", tag = "sctk-0.20", default-features = false, features = ["wayland"] } -dnd = { git = "https://github.com/pop-os/window_clipboard.git", tag = "sctk-0.20" } -mime = { git = "https://github.com/pop-os/window_clipboard.git", tag = "sctk-0.20" } +# Yoda: window_clipboard pinned to our public fork that has x11 gated behind +# an opt-in feature. default-features=false + features=["wayland"] drops +# clipboard_x11 + x11rb from the build. Branch yoda-x11-optional on +# https://forge.aditua.com/leyoda/window_clipboard. +window_clipboard = { git = "https://forge.aditua.com/leyoda/window_clipboard.git", branch = "yoda-x11-optional", default-features = false, features = ["wayland"] } +dnd = { git = "https://forge.aditua.com/leyoda/window_clipboard.git", branch = "yoda-x11-optional" } +mime = { git = "https://forge.aditua.com/leyoda/window_clipboard.git", branch = "yoda-x11-optional" } # Yoda: default-features = false drops winit's x11 default, which otherwise # pulls winit-x11, x11-dl, tiny-xlib, as-raw-xcb-connection. Our Wayland-only # fork doesn't need any of that — the wayland + wayland-dlopen features are From 4e2e58e03d5f01ce8a328a9128ac23fefd61ca39 Mon Sep 17 00:00:00 2001 From: Lionel DARNIS Date: Sat, 23 May 2026 20:55:59 +0200 Subject: [PATCH 47/93] chore: gate accessibility-only winit state --- winit/src/lib.rs | 2 ++ winit/src/window/state.rs | 1 + 2 files changed, 3 insertions(+) diff --git a/winit/src/lib.rs b/winit/src/lib.rs index 517eddbc..918f6c2a 100644 --- a/winit/src/lib.rs +++ b/winit/src/lib.rs @@ -186,6 +186,7 @@ where receiver: mpsc::UnboundedReceiver, error: Option, system_theme: Option>, + #[cfg(feature = "a11y")] control_sender: mpsc::UnboundedSender, #[cfg(feature = "a11y")] @@ -212,6 +213,7 @@ where id: settings.id, sender: event_sender, receiver: control_receiver, + #[cfg(feature = "a11y")] control_sender: control_sender.clone(), error: None, system_theme: Some(system_theme_sender), diff --git a/winit/src/window/state.rs b/winit/src/window/state.rs index 98fdf9ee..1e16fc51 100644 --- a/winit/src/window/state.rs +++ b/winit/src/window/state.rs @@ -97,6 +97,7 @@ where self.ready = ready; } + #[cfg(feature = "a11y")] pub(crate) fn set_a11y_ready(&mut self, ready: bool) { self.a11y_ready = ready; } From 3982e04aa2d876adfcdb5fbf3a7beecd18d5d63f Mon Sep 17 00:00:00 2001 From: Lionel DARNIS Date: Mon, 25 May 2026 18:09:40 +0200 Subject: [PATCH 48/93] chore: use local cctk and clipboard crates --- Cargo.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1a0b86f1..6496fc07 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -274,7 +274,7 @@ tiny-skia = { version = "0.11", default-features = false, features = [ "std", "simd", ] } -cctk = { git = "https://github.com/pop-os/cosmic-protocols", package = "cosmic-client-toolkit", rev = "32283d7" } +cctk = { path = "../../cosmic-protocols/client-toolkit", package = "cosmic-client-toolkit" } # Yoda: default-features=false drops softbuffer's x11 / x11-dlopen (pulled # tiny-xlib + as-raw-xcb-connection). The wayland + wayland-dlopen features # are re-activated via iced_tiny_skia's own `wayland` feature propagation. @@ -308,9 +308,9 @@ winapi = "0.3" # an opt-in feature. default-features=false + features=["wayland"] drops # clipboard_x11 + x11rb from the build. Branch yoda-x11-optional on # https://forge.aditua.com/leyoda/window_clipboard. -window_clipboard = { git = "https://forge.aditua.com/leyoda/window_clipboard.git", branch = "yoda-x11-optional", default-features = false, features = ["wayland"] } -dnd = { git = "https://forge.aditua.com/leyoda/window_clipboard.git", branch = "yoda-x11-optional" } -mime = { git = "https://forge.aditua.com/leyoda/window_clipboard.git", branch = "yoda-x11-optional" } +window_clipboard = { path = "../../window_clipboard", default-features = false, features = ["wayland"] } +dnd = { path = "../../window_clipboard/dnd" } +mime = { path = "../../window_clipboard/mime" } # Yoda: default-features = false drops winit's x11 default, which otherwise # pulls winit-x11, x11-dl, tiny-xlib, as-raw-xcb-connection. Our Wayland-only # fork doesn't need any of that — the wayland + wayland-dlopen features are From cf7828fb705bc1901dd9684d682c000b6ff66bc1 Mon Sep 17 00:00:00 2001 From: Lionel DARNIS Date: Mon, 25 May 2026 18:27:54 +0200 Subject: [PATCH 49/93] chore: use local glyphon and cosmic-text --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6496fc07..22151d21 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -238,8 +238,8 @@ async-std = "1.0" bitflags = "2.5" bytemuck = { version = "1.0", features = ["derive"] } bytes = "1.6" -cosmic-text = "0.19" -cryoglyph = { git = "https://github.com/iced-rs/cryoglyph.git", rev = "e429a025df36ab8145708acb309080ae3deec17a" } +cosmic-text = { path = "../../cosmic-text" } +cryoglyph = { package = "cryoglyph", path = "../../glyphon" } dark-light = "1.0" resvg = "0.45" web-sys = "0.3.69" From 362b4abb1558374686080db674b8f7c5868ae6ac Mon Sep 17 00:00:00 2001 From: Lionel DARNIS Date: Mon, 25 May 2026 19:36:22 +0200 Subject: [PATCH 50/93] chore: use local winit and softbuffer --- Cargo.lock | 14 -------------- Cargo.toml | 25 ++++++++++++++++++++++--- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 11a85d77..1f6f716f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1658,7 +1658,6 @@ dependencies = [ [[package]] name = "dpi" version = "0.1.2" -source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" [[package]] name = "drm" @@ -6275,7 +6274,6 @@ dependencies = [ [[package]] name = "smithay-clipboard" version = "0.8.0" -source = "git+https://github.com/pop-os/smithay-clipboard?tag=sctk-0.20#859b02c88f45c554049a67c6ddeec1692ce0e20b" dependencies = [ "libc", "raw-window-handle", @@ -6333,7 +6331,6 @@ dependencies = [ [[package]] name = "softbuffer" version = "0.4.1" -source = "git+https://github.com/pop-os/softbuffer?tag=cosmic-4.0#a3f77e251e7422803f693df6e3fc313c010c4dcb" dependencies = [ "as-raw-xcb-connection", "bytemuck", @@ -8517,7 +8514,6 @@ checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winit" version = "0.31.0-beta.2" -source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" dependencies = [ "bitflags 2.11.0", "cfg_aliases", @@ -8543,7 +8539,6 @@ dependencies = [ [[package]] name = "winit-android" version = "0.31.0-beta.2" -source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" dependencies = [ "android-activity", "bitflags 2.11.0", @@ -8558,7 +8553,6 @@ dependencies = [ [[package]] name = "winit-appkit" version = "0.31.0-beta.2" -source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" dependencies = [ "bitflags 2.11.0", "block2 0.6.2", @@ -8580,7 +8574,6 @@ dependencies = [ [[package]] name = "winit-common" version = "0.31.0-beta.2" -source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" dependencies = [ "memmap2 0.9.10", "objc2 0.6.4", @@ -8595,7 +8588,6 @@ dependencies = [ [[package]] name = "winit-core" version = "0.31.0-beta.2" -source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" dependencies = [ "bitflags 2.11.0", "cursor-icon", @@ -8609,7 +8601,6 @@ dependencies = [ [[package]] name = "winit-orbital" version = "0.31.0-beta.2" -source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" dependencies = [ "bitflags 2.11.0", "dpi", @@ -8625,7 +8616,6 @@ dependencies = [ [[package]] name = "winit-uikit" version = "0.31.0-beta.2" -source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" dependencies = [ "bitflags 2.11.0", "block2 0.6.2", @@ -8645,7 +8635,6 @@ dependencies = [ [[package]] name = "winit-wayland" version = "0.31.0-beta.2" -source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" dependencies = [ "ahash", "bitflags 2.11.0", @@ -8671,7 +8660,6 @@ dependencies = [ [[package]] name = "winit-web" version = "0.31.0-beta.2" -source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" dependencies = [ "atomic-waker", "bitflags 2.11.0", @@ -8693,7 +8681,6 @@ dependencies = [ [[package]] name = "winit-win32" version = "0.31.0-beta.2" -source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" dependencies = [ "bitflags 2.11.0", "cursor-icon", @@ -8709,7 +8696,6 @@ dependencies = [ [[package]] name = "winit-x11" version = "0.31.0-beta.2" -source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" dependencies = [ "bitflags 2.11.0", "bytemuck", diff --git a/Cargo.toml b/Cargo.toml index 22151d21..c49fcf92 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -278,7 +278,7 @@ cctk = { path = "../../cosmic-protocols/client-toolkit", package = "cosmic-clien # Yoda: default-features=false drops softbuffer's x11 / x11-dlopen (pulled # tiny-xlib + as-raw-xcb-connection). The wayland + wayland-dlopen features # are re-activated via iced_tiny_skia's own `wayland` feature propagation. -softbuffer = { git = "https://github.com/pop-os/softbuffer", tag = "cosmic-4.0", default-features = false } +softbuffer = { path = "../../softbuffer", default-features = false } syntect = "5.2" tokio = "1.0" tracing = "0.1" @@ -315,10 +315,29 @@ mime = { path = "../../window_clipboard/mime" } # pulls winit-x11, x11-dl, tiny-xlib, as-raw-xcb-connection. Our Wayland-only # fork doesn't need any of that — the wayland + wayland-dlopen features are # re-enabled via iced_winit's own feature propagation from libcosmic-yoda. -winit = { git = "https://github.com/pop-os/winit.git", tag = "cosmic-0.14", default-features = false } -winit-core = { git = "https://github.com/pop-os/winit.git", tag = "cosmic-0.14" } +winit = { path = "../../winit/winit", default-features = false } +winit-core = { path = "../../winit/winit-core" } cursor-icon = "1.1.0" +[patch.'https://github.com/pop-os/softbuffer'] +softbuffer = { path = "../../softbuffer" } + +[patch.'https://github.com/pop-os/smithay-clipboard'] +smithay-clipboard = { path = "../../smithay-clipboard" } + +[patch.'https://github.com/pop-os/winit.git'] +dpi = { path = "../../winit/dpi" } +winit = { path = "../../winit/winit" } +winit-android = { path = "../../winit/winit-android" } +winit-appkit = { path = "../../winit/winit-appkit" } +winit-common = { path = "../../winit/winit-common" } +winit-core = { path = "../../winit/winit-core" } +winit-orbital = { path = "../../winit/winit-orbital" } +winit-uikit = { path = "../../winit/winit-uikit" } +winit-wayland = { path = "../../winit/winit-wayland" } +winit-web = { path = "../../winit/winit-web" } +winit-win32 = { path = "../../winit/winit-win32" } +winit-x11 = { path = "../../winit/winit-x11" } [workspace.lints.rust] rust_2018_idioms = { level = "deny", priority = -1 } From 1a57634add6e820c299f1c59664cd98098a9c348 Mon Sep 17 00:00:00 2001 From: Lionel DARNIS Date: Thu, 2 Jul 2026 19:01:15 +0200 Subject: [PATCH 51/93] yoda: cargo fix sweep post-rebase (unused imports/vars) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Leyoda 2026 – GPLv3 --- Cargo.lock | 89 +++++++------------------- core/src/element.rs | 2 +- core/src/overlay/group.rs | 2 +- core/src/widget/operation/search_id.rs | 2 +- graphics/src/image.rs | 2 - runtime/src/dnd.rs | 4 +- runtime/src/lib.rs | 1 - widget/src/container.rs | 2 +- widget/src/keyed/column.rs | 1 - widget/src/list.rs | 2 +- widget/src/mouse_area.rs | 1 - widget/src/pane_grid/content.rs | 2 +- widget/src/scrollable.rs | 3 +- widget/src/stack.rs | 1 - widget/src/themer.rs | 1 - widget/src/toggler.rs | 5 +- 16 files changed, 32 insertions(+), 88 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1f6f716f..b5d874b8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1076,7 +1076,6 @@ dependencies = [ [[package]] name = "clipboard_macos" version = "0.1.0" -source = "git+https://github.com/pop-os/window_clipboard.git?tag=sctk-0.20#f68595ee0e62fbd6589f4709b5aaa5c3c7ea5f6c" dependencies = [ "objc", "objc-foundation", @@ -1086,22 +1085,12 @@ dependencies = [ [[package]] name = "clipboard_wayland" version = "0.2.2" -source = "git+https://github.com/pop-os/window_clipboard.git?tag=sctk-0.20#f68595ee0e62fbd6589f4709b5aaa5c3c7ea5f6c" dependencies = [ "dnd", "mime 0.1.0", "smithay-clipboard", ] -[[package]] -name = "clipboard_x11" -version = "0.4.2" -source = "git+https://github.com/pop-os/window_clipboard.git?tag=sctk-0.20#f68595ee0e62fbd6589f4709b5aaa5c3c7ea5f6c" -dependencies = [ - "thiserror 1.0.69", - "x11rb", -] - [[package]] name = "clock" version = "0.1.0" @@ -1294,7 +1283,6 @@ dependencies = [ [[package]] name = "cosmic-client-toolkit" version = "0.2.0" -source = "git+https://github.com/pop-os/cosmic-protocols?rev=a7d2d7a#a7d2d7a6188425f699eaddf7a025617ce56068ae" dependencies = [ "bitflags 2.11.0", "cosmic-protocols", @@ -1307,7 +1295,6 @@ dependencies = [ [[package]] name = "cosmic-protocols" version = "0.2.0" -source = "git+https://github.com/pop-os/cosmic-protocols?rev=a7d2d7a#a7d2d7a6188425f699eaddf7a025617ce56068ae" dependencies = [ "bitflags 2.11.0", "wayland-backend", @@ -1321,8 +1308,6 @@ dependencies = [ [[package]] name = "cosmic-text" version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be17b688510d934ce13f48a2beba700e11583e281e0fda99c22bb256a14eda73" dependencies = [ "bitflags 2.11.0", "fontdb", @@ -1340,6 +1325,7 @@ dependencies = [ "unicode-linebreak", "unicode-script", "unicode-segmentation", + "unicode-width", ] [[package]] @@ -1446,7 +1432,6 @@ checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "cryoglyph" version = "0.1.0" -source = "git+https://github.com/iced-rs/cryoglyph.git?rev=e429a025df36ab8145708acb309080ae3deec17a#e429a025df36ab8145708acb309080ae3deec17a" dependencies = [ "cosmic-text", "etagere", @@ -1623,7 +1608,6 @@ dependencies = [ [[package]] name = "dnd" version = "0.1.0" -source = "git+https://github.com/pop-os/window_clipboard.git?tag=sctk-0.20#f68595ee0e62fbd6589f4709b5aaa5c3c7ea5f6c" dependencies = [ "bitflags 2.11.0", "mime 0.1.0", @@ -1659,45 +1643,12 @@ dependencies = [ name = "dpi" version = "0.1.2" -[[package]] -name = "drm" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0f8a69e60d75ae7dab4ef26a59ca99f2a89d4c142089b537775ae0c198bdcde" -dependencies = [ - "bitflags 2.11.0", - "bytemuck", - "drm-ffi", - "drm-fourcc", - "rustix 0.38.44", -] - -[[package]] -name = "drm-ffi" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41334f8405792483e32ad05fbb9c5680ff4e84491883d2947a4757dc54cb2ac6" -dependencies = [ - "drm-sys", - "rustix 0.38.44", -] - [[package]] name = "drm-fourcc" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0aafbcdb8afc29c1a7ee5fbe53b5d62f4565b35a042a662ca9fecd0b54dae6f4" -[[package]] -name = "drm-sys" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d09ff881f92f118b11105ba5e34ff8f4adf27b30dae8f12e28c193af1c83176" -dependencies = [ - "libc", - "linux-raw-sys 0.6.5", -] - [[package]] name = "editor" version = "0.1.0" @@ -2420,7 +2371,7 @@ dependencies = [ "log", "presser", "thiserror 2.0.18", - "windows 0.57.0", + "windows 0.62.2", ] [[package]] @@ -3785,14 +3736,14 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libredox" -version = "0.1.16" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c" +checksum = "c943259e342f1e06ff2da7a83eabdfe7f92ce10262688dbf1895ff0b3e6e4652" dependencies = [ "bitflags 2.11.0", "libc", "plain", - "redox_syscall 0.7.4", + "redox_syscall 0.9.0", ] [[package]] @@ -3822,12 +3773,6 @@ version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" -[[package]] -name = "linux-raw-sys" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a385b1be4e5c3e362ad2ffa73c392e53f031eaa5b7d648e64cd87f27f6063d7" - [[package]] name = "linux-raw-sys" version = "0.12.1" @@ -4053,7 +3998,6 @@ dependencies = [ [[package]] name = "mime" version = "0.1.0" -source = "git+https://github.com/pop-os/window_clipboard.git?tag=sctk-0.20#f68595ee0e62fbd6589f4709b5aaa5c3c7ea5f6c" dependencies = [ "smithay-clipboard", ] @@ -5479,6 +5423,16 @@ dependencies = [ "font-types", ] +[[package]] +name = "redox_event" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5018d583d6d2f5499352aea8d177e9067d1eb03ab17c78169d5ba7a30001b15" +dependencies = [ + "bitflags 2.11.0", + "libredox", +] + [[package]] name = "redox_syscall" version = "0.5.18" @@ -5490,9 +5444,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.7.4" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f450ad9c3b1da563fb6948a8e0fb0fb9269711c9c73d9ea1de5058c79c8d643a" +checksum = "c5102a6aaa05aa011a238e178e6bca86d2cb56fc9f586d37cb80f5bca6e07759" dependencies = [ "bitflags 2.11.0", ] @@ -6337,7 +6291,6 @@ dependencies = [ "cfg_aliases", "cocoa", "core-graphics", - "drm", "fastrand", "foreign-types 0.5.0", "js-sys", @@ -8005,12 +7958,10 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "window_clipboard" version = "0.4.1" -source = "git+https://github.com/pop-os/window_clipboard.git?tag=sctk-0.20#f68595ee0e62fbd6589f4709b5aaa5c3c7ea5f6c" dependencies = [ "clipboard-win", "clipboard_macos", "clipboard_wayland", - "clipboard_x11", "dnd", "mime 0.1.0", "raw-window-handle", @@ -8607,7 +8558,7 @@ dependencies = [ "libredox", "orbclient", "raw-window-handle", - "redox_syscall 0.7.4", + "redox_event", "smol_str", "tracing", "winit-core", @@ -9240,3 +9191,7 @@ dependencies = [ "syn", "winnow 0.7.15", ] + +[[patch.unused]] +name = "cosmic-freedesktop-icons" +version = "0.4.0" diff --git a/core/src/element.rs b/core/src/element.rs index f97ed6bc..dbe449c5 100644 --- a/core/src/element.rs +++ b/core/src/element.rs @@ -1,4 +1,4 @@ -use crate::event::{self, Event}; +use crate::event::Event; use crate::id::Id; use crate::layout; use crate::mouse; diff --git a/core/src/overlay/group.rs b/core/src/overlay/group.rs index ec0906e7..1a4ce672 100644 --- a/core/src/overlay/group.rs +++ b/core/src/overlay/group.rs @@ -3,7 +3,7 @@ use crate::mouse; use crate::overlay; use crate::renderer; use crate::widget; -use crate::{Clipboard, Event, Layout, Overlay, Point, Rectangle, Shell, Size}; +use crate::{Clipboard, Event, Layout, Overlay, Shell, Size}; /// An [`Overlay`] container that displays multiple overlay [`overlay::Element`] /// children. diff --git a/core/src/widget/operation/search_id.rs b/core/src/widget/operation/search_id.rs index 1286abaf..e03fac8a 100644 --- a/core/src/widget/operation/search_id.rs +++ b/core/src/widget/operation/search_id.rs @@ -4,7 +4,7 @@ use super::Operation; use crate::{ Rectangle, id::Id, - widget::operation::{Outcome, focusable::Count}, + widget::operation::Outcome, }; /// Produces an [`Operation`] that searches for the Id diff --git a/graphics/src/image.rs b/graphics/src/image.rs index e5fe9281..d9b23216 100644 --- a/graphics/src/image.rs +++ b/graphics/src/image.rs @@ -2,8 +2,6 @@ #[cfg(feature = "image")] use crate::core::Bytes; -use crate::core::Color; -use crate::core::Radians; use crate::core::Rectangle; use crate::core::image; use crate::core::svg; diff --git a/runtime/src/dnd.rs b/runtime/src/dnd.rs index 2a0db116..2e526eb6 100644 --- a/runtime/src/dnd.rs +++ b/runtime/src/dnd.rs @@ -1,10 +1,8 @@ //! Access the clipboard. -use std::any::Any; use dnd::{DndDestinationRectangle, DndSurface}; -use iced_core::clipboard::DndSource; -use window_clipboard::mime::{AllowedMimeTypes, AsMimeTypes}; +use window_clipboard::mime::AllowedMimeTypes; use crate::{Action, Task, oneshot, task}; diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 22da3d66..68034bfc 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -28,7 +28,6 @@ pub use task::Task; pub use user_interface::UserInterface; pub use window::Window; -use crate::core::Color; use crate::futures::futures::channel::oneshot; use std::borrow::Cow; diff --git a/widget/src/container.rs b/widget/src/container.rs index e4aeabf2..a264007a 100644 --- a/widget/src/container.rs +++ b/widget/src/container.rs @@ -35,7 +35,7 @@ use crate::core::{ color, }; -use iced_runtime::{Action, Task, task}; +use iced_runtime::{Task, task}; /// A widget that aligns its contents inside of its boundaries. /// diff --git a/widget/src/keyed/column.rs b/widget/src/keyed/column.rs index ef7d9d9a..bb98d606 100644 --- a/widget/src/keyed/column.rs +++ b/widget/src/keyed/column.rs @@ -1,7 +1,6 @@ //! Keyed columns distribute content vertically while keeping continuity. //! Distribute content vertically. -use crate::core::event; use crate::core::layout; use crate::core::mouse; use crate::core::overlay; diff --git a/widget/src/list.rs b/widget/src/list.rs index d7cadd50..9f33244e 100644 --- a/widget/src/list.rs +++ b/widget/src/list.rs @@ -1,5 +1,5 @@ #![allow(missing_docs)] -use crate::core::event::{self, Event}; +use crate::core::event::Event; use crate::core::layout; use crate::core::mouse; use crate::core::overlay; diff --git a/widget/src/mouse_area.rs b/widget/src/mouse_area.rs index 3d355c52..4d808348 100644 --- a/widget/src/mouse_area.rs +++ b/widget/src/mouse_area.rs @@ -2,7 +2,6 @@ use iced_renderer::core::mouse::Click; -use crate::core::event; use crate::core::layout; use crate::core::mouse; use crate::core::overlay; diff --git a/widget/src/pane_grid/content.rs b/widget/src/pane_grid/content.rs index a76010e7..4c41e3a6 100644 --- a/widget/src/pane_grid/content.rs +++ b/widget/src/pane_grid/content.rs @@ -6,7 +6,7 @@ use crate::core::renderer; use crate::core::widget::{self, Tree}; use crate::core::{ self, Clipboard, Element, Event, Layout, Point, Rectangle, Shell, Size, - Vector, event, + Vector, }; use crate::pane_grid::{Draggable, TitleBar}; diff --git a/widget/src/scrollable.rs b/widget/src/scrollable.rs index e005a7b8..c906b66e 100644 --- a/widget/src/scrollable.rs +++ b/widget/src/scrollable.rs @@ -27,7 +27,6 @@ use iced_runtime::core::widget::Id; #[cfg(feature = "a11y")] use std::borrow::Cow; -use crate::core::event; use crate::core::keyboard; use crate::core::layout; use crate::core::mouse; @@ -933,7 +932,7 @@ where let had_input_method = shell.input_method().is_enabled(); - let mut c_event = match event.clone() { + let c_event = match event.clone() { Event::Dnd(dnd::DndEvent::Offer( id, dnd::OfferEvent::Enter { diff --git a/widget/src/stack.rs b/widget/src/stack.rs index e85bf2af..cd30a886 100644 --- a/widget/src/stack.rs +++ b/widget/src/stack.rs @@ -1,6 +1,5 @@ //! Display content on top of other content. -use crate::core::event; use crate::core::layout; use crate::core::mouse; use crate::core::overlay; diff --git a/widget/src/themer.rs b/widget/src/themer.rs index 306c8580..76448ae1 100644 --- a/widget/src/themer.rs +++ b/widget/src/themer.rs @@ -1,6 +1,5 @@ use crate::container; -use crate::core::event; use crate::core::layout; use crate::core::mouse; use crate::core::overlay; diff --git a/widget/src/toggler.rs b/widget/src/toggler.rs index 6709f1dc..b4e66887 100644 --- a/widget/src/toggler.rs +++ b/widget/src/toggler.rs @@ -37,7 +37,6 @@ use std::borrow::Cow; use iced_runtime::core::border::Radius; use crate::core::alignment; -use crate::core::border; use crate::core::layout; use crate::core::mouse; use crate::core::renderer; @@ -510,7 +509,7 @@ where let space = style.handle_margin; - let toggler_background_bounds = Rectangle { + let _toggler_background_bounds = Rectangle { x: bounds.x, y: bounds.y, width: bounds.width, @@ -530,7 +529,7 @@ where style.background, ); - let padding = (style.padding_ratio * bounds.height).round(); + let _padding = (style.padding_ratio * bounds.height).round(); let toggler_foreground_bounds = Rectangle { x: bounds.x + if self.is_toggled { From b5b2b2fcc3e58be793624ba3a7dd45485813935a Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Mon, 6 Jul 2026 18:44:30 -0400 Subject: [PATCH 52/93] 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 53/93] 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 54/93] 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 55/93] 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 56/93] 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 57/93] =?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 58/93] 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 59/93] 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 60/93] 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 61/93] 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 62/93] 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 63/93] 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 64/93] 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 65/93] 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 66/93] 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 67/93] 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 68/93] 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 69/93] 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 70/93] 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 71/93] 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(); } _ => {} } From c34af044311c986e5f8458cf61bab2508aca48fa Mon Sep 17 00:00:00 2001 From: Lionel DARNIS Date: Wed, 19 Aug 2026 21:53:10 +0200 Subject: [PATCH 72/93] fix: create_surface still gated on the removed cctk feature Upstream renamed the iced `cctk` features to `wayland` and moved the positive arm of create_surface() to the wayland_platform cfg alias, but left the negative arm on `feature = "cctk"`. That feature no longer exists, so its cfg was always true and both arms compiled at once, giving `expected (), found Option>`. Co-Authored-By: Claude Opus 5 (1M context) --- winit/src/platform_specific/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/winit/src/platform_specific/mod.rs b/winit/src/platform_specific/mod.rs index e66cf5f1..e1bfd9b9 100644 --- a/winit/src/platform_specific/mod.rs +++ b/winit/src/platform_specific/mod.rs @@ -151,7 +151,7 @@ impl PlatformSpecific { { self.wayland.create_surface() } - #[cfg(not(all(feature = "cctk", target_os = "linux")))] + #[cfg(not(wayland_platform))] { None } From 87c0358985cae50fefdcb15eabb0271e19ecf4a2 Mon Sep 17 00:00:00 2001 From: Frederic Laing Date: Thu, 13 Aug 2026 00:06:09 +0200 Subject: [PATCH 73/93] fix(scrollable): allow scrolling when children capture touch presses --- widget/src/lib.rs | 2 ++ widget/src/pane_grid.rs | 3 +- widget/src/scrollable.rs | 71 +++++++++++++++++++++++++++++++++++++--- 3 files changed, 71 insertions(+), 5 deletions(-) diff --git a/widget/src/lib.rs b/widget/src/lib.rs index d9bdf1f3..526f3576 100644 --- a/widget/src/lib.rs +++ b/widget/src/lib.rs @@ -9,6 +9,8 @@ pub use iced_renderer::graphics; pub use core::widget::Id; +pub(crate) const DRAG_DEADBAND_DISTANCE: f32 = 10.0; + mod action; mod mouse_area; mod pin; diff --git a/widget/src/pane_grid.rs b/widget/src/pane_grid.rs index d43c69bd..9358c0ad 100644 --- a/widget/src/pane_grid.rs +++ b/widget/src/pane_grid.rs @@ -92,7 +92,8 @@ use crate::core::{ }; use log::trace; -const DRAG_DEADBAND_DISTANCE: f32 = 10.0; +use crate::DRAG_DEADBAND_DISTANCE; + const THICKNESS_RATIO: f32 = 25.0; /// A collection of panes distributed using either vertical or horizontal splits diff --git a/widget/src/scrollable.rs b/widget/src/scrollable.rs index e005a7b8..61a18bd5 100644 --- a/widget/src/scrollable.rs +++ b/widget/src/scrollable.rs @@ -961,6 +961,16 @@ where y: y + translation.y as f64, }, )), + Event::Touch(touch::Event::FingerLifted { + id, + position, + }) if matches!( + state.interaction, + Interaction::TouchScrolling(_) + ) => + { + Event::Touch(touch::Event::FingerLost { id, position }) + } e => e, }; self.content.as_widget_mut().update( @@ -988,6 +998,14 @@ where } }; + if matches!( + event, + Event::Mouse(mouse::Event::CursorMoved { .. }) + | Event::Touch(touch::Event::FingerPressed { .. }) + ) { + state.suppress_touch_hover = false; + } + if matches!( event, Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left)) @@ -996,10 +1014,18 @@ where | touch::Event::FingerLost { .. } ) ) { + if matches!(state.interaction, Interaction::TouchScrolling(_)) { + state.suppress_touch_hover = true; + } state.interaction = Interaction::None; + state.touch_press_start = None; return; } + if let Event::Touch(touch::Event::FingerPressed { .. }) = event { + state.touch_press_start = cursor_over_scrollable; + } + if shell.is_event_captured() { return; } @@ -1093,14 +1119,31 @@ where Interaction::TouchScrolling(position); } touch::Event::FingerMoved { .. } => { - let Interaction::TouchScrolling( - scroll_box_touched_at, - ) = state.interaction + let Some(cursor_position) = cursor.position() else { return; }; - let Some(cursor_position) = cursor.position() + if !matches!( + state.interaction, + Interaction::TouchScrolling(_) + ) { + let Some(start) = state.touch_press_start + else { + return; + }; + if start.distance(cursor_position) + < crate::DRAG_DEADBAND_DISTANCE + { + return; + } + state.interaction = + Interaction::TouchScrolling(start); + } + + let Interaction::TouchScrolling( + scroll_box_touched_at, + ) = state.interaction else { return; }; @@ -1322,6 +1365,14 @@ where state.translation(self.direction, bounds, content_bounds); let cursor = match cursor_over_scrollable { + _ if state.suppress_touch_hover + || matches!( + state.interaction, + Interaction::TouchScrolling(_) + ) => + { + mouse::Cursor::Unavailable + } Some(cursor_position) if !(mouse_over_x_scrollbar || mouse_over_y_scrollbar) => { @@ -1497,6 +1548,14 @@ where state.translation(self.direction, bounds, content_bounds); let cursor = match cursor_over_scrollable { + _ if state.suppress_touch_hover + || matches!( + state.interaction, + Interaction::TouchScrolling(_) + ) => + { + cursor.levitate() + translation + } Some(cursor_position) if !(mouse_over_x_scrollbar || mouse_over_y_scrollbar) => { @@ -2022,6 +2081,8 @@ struct State { last_notified: Option, last_scrolled: Option, is_scrollbar_visible: bool, + touch_press_start: Option, + suppress_touch_hover: bool, } #[derive(Debug, Clone, Copy)] @@ -2047,6 +2108,8 @@ impl Default for State { last_notified: None, last_scrolled: None, is_scrollbar_visible: true, + touch_press_start: None, + suppress_touch_hover: false, } } } From 65e9faa43c330be854322357b52978a0636323a9 Mon Sep 17 00:00:00 2001 From: Hojjat Date: Thu, 27 Aug 2026 18:00:50 -0600 Subject: [PATCH 74/93] feat(wayland): let a layer surface change its input region --- .../wayland/commands/layer_surface.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/winit/src/platform_specific/wayland/commands/layer_surface.rs b/winit/src/platform_specific/wayland/commands/layer_surface.rs index cdb4e93d..5d8a4588 100644 --- a/winit/src/platform_specific/wayland/commands/layer_surface.rs +++ b/winit/src/platform_specific/wayland/commands/layer_surface.rs @@ -1,5 +1,6 @@ //! Interact with the window of your application. +use crate::core::Rectangle; use crate::core::window::Id as SurfaceId; use iced_runtime::{ self, Action, Task, @@ -125,3 +126,15 @@ pub fn set_padding( )), )) } + +/// +pub fn set_input_zone( + id: SurfaceId, + zone: Option>, +) -> Task { + task::effect(Action::PlatformSpecific( + platform_specific::Action::Wayland(wayland::Action::LayerSurface( + wayland::layer_surface::Action::InputZone { id, zone }, + )), + )) +} From aca94cf2af3b9c7efa748551abd2916f28d29058 Mon Sep 17 00:00:00 2001 From: Hojjat Date: Thu, 27 Aug 2026 19:26:19 -0600 Subject: [PATCH 75/93] feat(wayland): add ability to hide the cursor over a surface also now the surfaces say what the cursor over them should look like, previously one cursor shape was selected globally for the seat --- .../wayland/event_loop/mod.rs | 31 +++++++++++- .../wayland/event_loop/state.rs | 50 +++++++++++++++++++ .../wayland/handlers/seat/pointer.rs | 11 +++- .../wayland/handlers/seat/seat.rs | 2 + winit/src/platform_specific/wayland/mod.rs | 12 +++-- .../platform_specific/wayland/winit_window.rs | 10 +++- winit/src/window.rs | 4 +- 7 files changed, 111 insertions(+), 9 deletions(-) diff --git a/winit/src/platform_specific/wayland/event_loop/mod.rs b/winit/src/platform_specific/wayland/event_loop/mod.rs index b4589840..56911e42 100644 --- a/winit/src/platform_specific/wayland/event_loop/mod.rs +++ b/winit/src/platform_specific/wayland/event_loop/mod.rs @@ -177,13 +177,41 @@ impl SctkEventLoop { } } crate::platform_specific::Action::SetCursor( + surface, icon, ) => { - if let Some(seat) = state.seats.get_mut(0) { + state.record_cursor(surface.clone(), |r| { + r.icon = Some(icon); + r.hidden = false; + }); + if let Some(seat) = state + .seats + .get_mut(0) + .filter(|s| s.is_over(&surface)) + { seat.icon = Some(icon); + seat.hidden = false; seat.set_cursor(&state.connection, icon); } } + crate::platform_specific::Action::SetCursorVisible( + surface, + visible, + ) => { + state.record_cursor(surface.clone(), |r| { + r.hidden = !visible; + }); + if let Some(seat) = state + .seats + .get_mut(0) + .filter(|s| s.is_over(&surface)) + { + seat.set_cursor_visible( + &state.connection, + visible, + ); + } + } crate::platform_specific::Action::RequestRedraw( id, ) => { @@ -383,6 +411,7 @@ impl SctkEventLoop { touch_points: HashMap::new(), sctk_events: Vec::new(), frame_status: HashMap::new(), + cursor_requests: HashMap::new(), fractional_scaling_manager, viewporter_state, compositor_updates: Default::default(), diff --git a/winit/src/platform_specific/wayland/event_loop/state.rs b/winit/src/platform_specific/wayland/event_loop/state.rs index f4a8c5d7..a3a41ccd 100644 --- a/winit/src/platform_specific/wayland/event_loop/state.rs +++ b/winit/src/platform_specific/wayland/event_loop/state.rs @@ -123,6 +123,13 @@ use wayland_protocols::{ pub static TOKEN_CTR: AtomicU32 = AtomicU32::new(0); +/// The requested cursor for a surface +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +pub(crate) struct CursorRequest { + pub(crate) icon: Option, + pub(crate) hidden: bool, +} + #[derive(Debug)] pub(crate) struct SctkSeat { pub(crate) seat: WlSeat, @@ -139,6 +146,8 @@ pub(crate) struct SctkSeat { pub(crate) active_icon: Option, // Cursor icon set by application pub(crate) icon: Option, + // Application asked for cursor to hide + pub(crate) hidden: bool, } impl SctkSeat { @@ -148,6 +157,35 @@ impl SctkSeat { self.active_icon = Some(icon); } } + + /// Is the pointer currently over `surface`. + pub(crate) fn is_over(&self, surface: &ObjectId) -> bool { + self.ptr_focus.as_ref().is_some_and(|s| &s.id() == surface) + } + + /// Set cursor visibility over this surfaces. + pub(crate) fn set_cursor_visible( + &mut self, + conn: &Connection, + visible: bool, + ) { + let Some(ptr) = self.ptr.as_ref() else { + return; + }; + + self.hidden = !visible; + + if visible { + let icon = self.icon.unwrap_or(CursorIcon::Default); + _ = ptr.set_cursor(conn, icon); + self.active_icon = Some(icon); + } else { + // Ignoring the error + // It only fails when the pointer is not on our surface (due to serial error) + _ = ptr.hide_cursor(); + self.active_icon = None; + } + } } #[derive(Debug, Clone)] @@ -471,6 +509,7 @@ pub struct SctkState { pub(crate) session_lock_state: SessionLockState, pub(crate) session_lock: Option, pub(crate) id_map: HashMap, + pub(crate) cursor_requests: HashMap, pub(crate) to_commit: HashMap, pub(crate) destroyed: HashSet, pub(crate) pending_popup: Option<(SctkPopupSettings, usize)>, @@ -573,6 +612,17 @@ pub(crate) fn receive_frame( } impl SctkState { + /// What a surface wants the pointer over it to be. + pub(crate) fn record_cursor( + &mut self, + surface: ObjectId, + amend: impl FnOnce(&mut CursorRequest), + ) { + self.cursor_requests + .retain(|id, _| id == &surface || self.id_map.contains_key(id)); + amend(self.cursor_requests.entry(surface).or_default()); + } + pub fn request_redraw(&mut self, surface: &WlSurface) { let e = self .frame_status diff --git a/winit/src/platform_specific/wayland/handlers/seat/pointer.rs b/winit/src/platform_specific/wayland/handlers/seat/pointer.rs index b40912ec..ac0bd4a9 100644 --- a/winit/src/platform_specific/wayland/handlers/seat/pointer.rs +++ b/winit/src/platform_specific/wayland/handlers/seat/pointer.rs @@ -31,7 +31,7 @@ impl PointerHandler for SctkState { // track events, but only forward for the active seat for e in events { - if my_seat.active_icon != my_seat.icon { + if !my_seat.hidden && my_seat.active_icon != my_seat.icon { // Restore cursor that was set by appliction, or default my_seat.set_cursor( conn, @@ -60,10 +60,19 @@ impl PointerHandler for SctkState { match e.kind { PointerEventKind::Enter { .. } => { _ = my_seat.ptr_focus.replace(e.surface.clone()); + if let Some(want) = + self.cursor_requests.get(&e.surface.id()) + { + my_seat.icon = want.icon; + my_seat.set_cursor_visible(conn, !want.hidden); + } } PointerEventKind::Leave { .. } => { _ = my_seat.ptr_focus.take(); _ = my_seat.active_icon = None; + // The next surface the pointer lands on decides what it + // looks like there + my_seat.hidden = false; } PointerEventKind::Press { time, diff --git a/winit/src/platform_specific/wayland/handlers/seat/seat.rs b/winit/src/platform_specific/wayland/handlers/seat/seat.rs index ee6b0e6e..ec2b187c 100644 --- a/winit/src/platform_specific/wayland/handlers/seat/seat.rs +++ b/winit/src/platform_specific/wayland/handlers/seat/seat.rs @@ -38,6 +38,7 @@ impl SeatHandler for SctkState { last_touch_down: None, icon: None, active_icon: None, + hidden: false, }); } @@ -65,6 +66,7 @@ impl SeatHandler for SctkState { last_touch_down: None, icon: None, active_icon: None, + hidden: false, }); self.seats.last_mut().unwrap() } diff --git a/winit/src/platform_specific/wayland/mod.rs b/winit/src/platform_specific/wayland/mod.rs index e98316ce..289d410d 100644 --- a/winit/src/platform_specific/wayland/mod.rs +++ b/winit/src/platform_specific/wayland/mod.rs @@ -32,7 +32,8 @@ use winit::window::ImePurpose; pub(crate) enum Action { Action(iced_runtime::platform_specific::wayland::Action), - SetCursor(CursorIcon), + SetCursor(ObjectId, CursorIcon), + SetCursorVisible(ObjectId, bool), RequestRedraw(ObjectId), TrackWindow(Arc, window::Id), ResizeWindow(window::Id), @@ -48,9 +49,14 @@ impl std::fmt::Debug for Action { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Action(arg0) => f.debug_tuple("Action").field(arg0).finish(), - Self::SetCursor(arg0) => { - f.debug_tuple("SetCursor").field(arg0).finish() + Self::SetCursor(arg0, arg1) => { + f.debug_tuple("SetCursor").field(arg0).field(arg1).finish() } + Self::SetCursorVisible(arg0, arg1) => f + .debug_tuple("SetCursorVisible") + .field(arg0) + .field(arg1) + .finish(), Self::RequestRedraw(arg0) => { f.debug_tuple("RequestRedraw").field(arg0).finish() } diff --git a/winit/src/platform_specific/wayland/winit_window.rs b/winit/src/platform_specific/wayland/winit_window.rs index b33b7f9e..2751b31c 100644 --- a/winit/src/platform_specific/wayland/winit_window.rs +++ b/winit/src/platform_specific/wayland/winit_window.rs @@ -83,7 +83,10 @@ impl winit::window::Window for SctkWinitWindow { fn set_cursor(&self, cursor: winit_core::cursor::Cursor) { match cursor { winit_core::cursor::Cursor::Icon(icon) => { - _ = self.tx.send(Action::SetCursor(icon)); + _ = self.tx.send(Action::SetCursor( + self.surface.wl_surface().id(), + icon, + )); } winit_core::cursor::Cursor::Custom(_) => { // TODO @@ -92,7 +95,10 @@ impl winit::window::Window for SctkWinitWindow { } fn set_cursor_visible(&self, visible: bool) { - // TODO + _ = self.tx.send(Action::SetCursorVisible( + self.surface.wl_surface().id(), + visible, + )); } fn surface_size(&self) -> winit::dpi::PhysicalSize { diff --git a/winit/src/window.rs b/winit/src/window.rs index e56483f4..18f5f41f 100644 --- a/winit/src/window.rs +++ b/winit/src/window.rs @@ -291,11 +291,11 @@ where pub fn update_mouse(&mut self, interaction: mouse::Interaction) { if interaction != self.mouse_interaction { if let Some(icon) = conversion::mouse_interaction(interaction) { - self.raw.set_cursor(icon.into()); - if self.mouse_interaction == mouse::Interaction::Hidden { self.raw.set_cursor_visible(true); } + + self.raw.set_cursor(icon.into()); } else { self.raw.set_cursor_visible(false); } From 39d3c99d1315e9a3db76fa8b32aa91e439c38b32 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Thu, 27 Aug 2026 15:37:57 -0400 Subject: [PATCH 76/93] improv: allow multiple popup chains multiple grabs are still not allowed, but this seems to be working well with a tooltip, nested popup chains, and hopefully a context drawer popup --- Cargo.lock | 1 - .../wayland/event_loop/mod.rs | 8 +- .../wayland/event_loop/popup.rs | 158 ++++++ .../wayland/event_loop/state.rs | 519 ++++++++---------- .../wayland/handlers/shell/xdg_popup.rs | 42 +- 5 files changed, 387 insertions(+), 341 deletions(-) create mode 100644 winit/src/platform_specific/wayland/event_loop/popup.rs diff --git a/Cargo.lock b/Cargo.lock index b309db1d..c28424ee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3206,7 +3206,6 @@ 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/winit/src/platform_specific/wayland/event_loop/mod.rs b/winit/src/platform_specific/wayland/event_loop/mod.rs index 56911e42..1926e391 100644 --- a/winit/src/platform_specific/wayland/event_loop/mod.rs +++ b/winit/src/platform_specific/wayland/event_loop/mod.rs @@ -1,4 +1,5 @@ pub mod control_flow; +pub mod popup; pub mod proxy; pub mod state; @@ -6,6 +7,7 @@ pub mod state; use crate::platform_specific::SurfaceIdWrapper; use crate::{ Control, + event_loop::popup::PopupManager, futures::futures::channel::mpsc, handlers::{ ext_background_effect, overlap::OverlapNotifyV1, @@ -405,7 +407,7 @@ impl SctkEventLoop { blur_surfaces: HashMap::new(), corner_radii: HashMap::new(), layer_surfaces: Vec::new(), - popups: Vec::new(), + popmgr: PopupManager::default(), lock_surfaces: Vec::new(), subsurfaces: Vec::new(), touch_points: HashMap::new(), @@ -543,8 +545,8 @@ impl SctkEventLoop { .chain( state .state - .popups - .iter() + .popmgr + .popups() .map(|s| s.popup.wl_surface()), ) .chain( diff --git a/winit/src/platform_specific/wayland/event_loop/popup.rs b/winit/src/platform_specific/wayland/event_loop/popup.rs new file mode 100644 index 00000000..09cfe96c --- /dev/null +++ b/winit/src/platform_specific/wayland/event_loop/popup.rs @@ -0,0 +1,158 @@ +use std::sync::Mutex; +use std::sync::Arc; +use cctk::sctk::shell::xdg::popup::PopupConfigure; +use cctk::sctk::shell::xdg::popup::Popup; +use iced_runtime::{platform_specific, core::window::Id}; +use wayland_client::protocol::wl_surface::WlSurface; +use wayland_protocols::wp::fractional_scale::v1::client::wp_fractional_scale_v1::WpFractionalScaleV1; + +use crate::event_loop::state::Common; +use crate::event_loop::state::SctkPopupData; + +#[derive(Debug, Default)] +pub struct PopupManager { + chains: Vec>, +} + +impl PopupManager { + pub(crate) fn popups(&self) -> impl Iterator { + self.chains.iter().map(|c| c.iter()).flatten() + } + + pub(crate) fn chain_for_popup_mut( + &mut self, + id: &WlSurface, + ) -> Option<(&mut Vec, usize)> { + let pos = self.chains.iter().enumerate().find_map(move |(pos, c)| { + if let Some(pop_pos) = + c.into_iter().position(|p| p.popup.wl_surface() == id) + { + Some((pos, pop_pos)) + } else { + None + } + }); + + pos.map(|pos| (&mut self.chains[pos.0], pos.1)) + } + + pub(crate) fn popup(&self, id: &WlSurface) -> Option<&SctkPopup> { + self.chains.iter().find_map(move |c| { + c.into_iter().find(|p| p.popup.wl_surface() == id) + }) + } + + pub(crate) fn popup_mut( + &mut self, + id: &WlSurface, + ) -> Option<&mut SctkPopup> { + self.chains.iter_mut().find_map(move |c| { + c.into_iter().find(|p| p.popup.wl_surface() == id) + }) + } + + pub(crate) fn popup_id(&self, id: Id) -> Option<&SctkPopup> { + self.chains + .iter() + .find_map(move |c| c.into_iter().find(|p| p.data.id == id)) + } + + pub(crate) fn popup_id_mut(&mut self, id: Id) -> Option<&mut SctkPopup> { + self.chains + .iter_mut() + .find_map(move |c| c.into_iter().find(|p| p.data.id == id)) + } + + pub(crate) fn active_grab(&self) -> Option<&SctkPopup> { + self.chains + .iter() + .find_map(|c| c.into_iter().rev().find(|p| p.data.grab)) + } + + pub(crate) fn root_grab(&self) -> Option<&SctkPopup> { + self.chains + .iter() + .find_map(|c| c.into_iter().find(|p| p.data.grab)) + } + + pub(crate) fn push(&mut self, popup: SctkPopup) { + if let Some((chain, _pos)) = + self.chain_for_popup_mut(popup.data.parent.wl_surface()) + { + // TODO should we return an error if a popup is attempted to be added to a non-leaf popup of a chain? + chain.push(popup); + } else { + if let Some(empty) = self.chains.iter_mut().find(|c| c.is_empty()) { + empty.push(popup); + } else { + self.chains.push(vec![popup]); + } + } + } + + pub(crate) fn remove( + &mut self, + popup: &WlSurface, + ) -> Option> { + // must perform cleanup so that the popups are dropped in the correct order + let ret = if let Some((chain, mut pos)) = + self.chain_for_popup_mut(popup) + { + // TODO should we return an error if a popup is attempted to be added to a non-leaf popup of a chain? + while let Some(p) = pos.checked_sub(1).and_then(|p| chain.get(p)) { + if p.close_with_children { + pos -= 1; + } else { + break; + } + } + + Some(chain.drain(pos..).rev()) + } else { + None + }; + + return ret; + } +} + +#[derive(Debug)] +pub struct SctkPopup { + pub(crate) popup: Popup, + pub(crate) last_configure: Option, + pub(crate) _pending_requests: + Vec, + pub(crate) data: SctkPopupData, + pub(crate) common: Arc>, + pub(crate) wp_fractional_scale: Option, + pub(crate) close_with_children: bool, +} + +impl SctkPopup { + pub(crate) fn set_size(&mut self, w: u32, h: u32, token: u32) { + let guard = self.common.lock().unwrap(); + if guard.size.width == w && guard.size.height == h { + return; + } + drop(guard); + // update geometry + self.popup + .xdg_surface() + .set_window_geometry(0, 0, w as i32, h as i32); + self.update_viewport(w, h); + // update positioner + self.data.positioner.set_size(w as i32, h as i32); + self.popup.reposition(&self.data.positioner, token); + } + + pub(crate) fn update_viewport(&mut self, w: u32, h: u32) { + let common = self.common.lock().unwrap(); + if common.size.width == w && common.size.height == h { + return; + } + if let Some(viewport) = common.wp_viewport.as_ref() { + // Set inner size without the borders. + viewport.set_destination(w as i32, h as i32); + } + } +} diff --git a/winit/src/platform_specific/wayland/event_loop/state.rs b/winit/src/platform_specific/wayland/event_loop/state.rs index a3a41ccd..12bb75d0 100644 --- a/winit/src/platform_specific/wayland/event_loop/state.rs +++ b/winit/src/platform_specific/wayland/event_loop/state.rs @@ -1,5 +1,6 @@ use crate::{ Control, + event_loop::popup::{self, PopupManager}, handlers::{ activation::IcedRequestData, ext_background_effect, @@ -82,10 +83,7 @@ use cctk::{ Anchor, KeyboardInteractivity, Layer, LayerShell, LayerSurface, LayerSurfaceConfigure, SurfaceKind, }, - xdg::{ - XdgPositioner, XdgShell, - popup::{Popup, PopupConfigure}, - }, + xdg::{XdgPositioner, XdgShell, popup::Popup}, }, shm::{Shm, multi::MultiPool}, }, @@ -94,6 +92,7 @@ use cctk::{ }; use iced_runtime::{ core::{self, Point, touch}, + keyboard::key::Named::Settings, platform_specific::{ self, wayland::{ @@ -301,47 +300,6 @@ impl From> for Common { } } -#[derive(Debug)] -pub struct SctkPopup { - pub(crate) popup: Popup, - pub(crate) last_configure: Option, - pub(crate) _pending_requests: - Vec, - pub(crate) data: SctkPopupData, - pub(crate) common: Arc>, - pub(crate) wp_fractional_scale: Option, - pub(crate) close_with_children: bool, -} - -impl SctkPopup { - pub(crate) fn set_size(&mut self, w: u32, h: u32, token: u32) { - let guard = self.common.lock().unwrap(); - if guard.size.width == w && guard.size.height == h { - return; - } - drop(guard); - // update geometry - self.popup - .xdg_surface() - .set_window_geometry(0, 0, w as i32, h as i32); - self.update_viewport(w, h); - // update positioner - self.data.positioner.set_size(w as i32, h as i32); - self.popup.reposition(&self.data.positioner, token); - } - - pub(crate) fn update_viewport(&mut self, w: u32, h: u32) { - let common = self.common.lock().unwrap(); - if common.size.width == w && common.size.height == h { - return; - } - if let Some(viewport) = common.wp_viewport.as_ref() { - // Set inner size without the borders. - viewport.set_destination(w as i32, h as i32); - } - } -} - #[derive(Debug)] pub struct SctkLockSurface { pub(crate) id: core::window::Id, @@ -469,7 +427,7 @@ pub struct SctkState { /// `WindowUpdate` or buffer on the associated with it `WindowHandle`. pub(crate) windows: Vec, pub(crate) layer_surfaces: Vec, - pub(crate) popups: Vec, + pub(crate) popmgr: PopupManager, pub(crate) subsurfaces: Vec, pub(crate) lock_surfaces: Vec, pub(crate) blur_surfaces: HashMap, @@ -659,11 +617,7 @@ impl SctkState { } } - if let Some(popup) = self - .popups - .iter_mut() - .find(|p| p.popup.wl_surface() == surface) - { + if let Some(popup) = self.popmgr.popup(surface) { id = Some(popup.data.id); if legacy && popup.wp_fractional_scale.is_some() { return; @@ -739,7 +693,7 @@ impl SctkState { > { if self.layer_surfaces.iter().any(|s| s.id == settings.id) || self.windows.iter().any(|w| w.id == settings.id) - || self.popups.iter().any(|p| p.data.id == settings.id) + || self.popmgr.popup_id(settings.id).is_some() || self.subsurfaces.iter().any(|s| s.id == settings.id) { log::warn!( @@ -763,12 +717,7 @@ impl SctkState { PopupParent::Window(parent.wl_surface(&self.connection)), parent.wl_surface(&self.connection), ) - } else if let Some(i) = self - .popups - .iter() - .position(|p| p.data.id == settings.parent) - { - let parent = &self.popups[i]; + } else if let Some(parent) = self.popmgr.popup_id(settings.parent) { ( PopupParent::Popup(parent.popup.wl_surface().clone()), parent.data.toplevel.clone(), @@ -806,6 +755,7 @@ impl SctkState { if positioner.version() >= 3 && settings.positioner.reactive { positioner.set_reactive(); } + positioner.set_size(size.0 as i32, size.1 as i32); let grab = settings.grab; @@ -870,10 +820,9 @@ impl SctkState { ) } PopupParent::Popup(parent) => { - let Some(parent_xdg) = self.popups.iter().find_map(|p| { - (p.popup.wl_surface() == parent) - .then(|| p.popup.xdg_surface()) - }) else { + let Some(parent_xdg) = + self.popmgr.popup(parent).map(|p| p.popup.xdg_surface()) + else { return Err(PopupCreationError::ParentMissing); }; @@ -948,7 +897,7 @@ impl SctkState { let common = Arc::new(Mutex::new(common)); let positioner = Arc::new(positioner); - self.popups.push(SctkPopup { + self.popmgr.push(popup::SctkPopup { popup: popup.clone(), data: SctkPopupData { id: settings.id, @@ -1007,7 +956,7 @@ impl SctkState { if self.layer_surfaces.iter().any(|s| s.id == id) || self.windows.iter().any(|w| w.id == id) - || self.popups.iter().any(|p| p.data.id == id) + || self.popmgr.popup_id(id).is_some() || self.subsurfaces.iter().any(|s| s.id == id) { log::warn!("Layer surface with id {id:?} already exists"); @@ -1121,7 +1070,7 @@ impl SctkState { ) -> Option<(CommonSurface, Arc>)> { if self.layer_surfaces.iter().any(|s| s.id == id) || self.windows.iter().any(|w| w.id == id) - || self.popups.iter().any(|p| p.data.id == id) + || self.popmgr.popup_id(id).is_some() || self.subsurfaces.iter().any(|s| s.id == id) { log::warn!("Lock surface with id {id:?} already exists"); @@ -1200,12 +1149,9 @@ impl SctkState { } }, platform_specific::wayland::layer_surface::Action::Destroy(id) => { - if let Some(p) = self - .popups - .iter().find_map(|p| - self.layer_surfaces.iter().find_map(|l| if l.id == id && l.surface.wl_surface() == p.data.parent.wl_surface() {Some(p.data.id)} else {None})) { - _ = self.handle_action(Action::Popup(platform_specific::wayland::popup::Action::Destroy { id: p })); - } + if let Some(id) = self.layer_surfaces.iter().find_map(|l| if l.id == id {self.popmgr.popups().find_map(|p| (p.data.parent.wl_surface() == l.surface.wl_surface()).then(|| p.data.id))} else {None}).clone() { + _ = self.handle_action(Action::Popup(platform_specific::wayland::popup::Action::Destroy { id })); + } if let Some(i) = self.layer_surfaces.iter().position(|l| l.id == id) { let l = self.layer_surfaces.remove(i); @@ -1319,245 +1265,215 @@ impl SctkState { } }, }, - Action::Popup(action) => match action { - platform_specific::wayland::popup::Action::Popup { popup: settings } => { - // first check existing popup - if let Some(existing) = self.popups.iter().position(|p| p.data.id == settings.id - && ( - self.popups.iter().any(|parent| parent.popup.wl_surface() == p.data.parent.wl_surface() && parent.data.id == settings.parent) - || self.windows.iter().any(|w| w.id == settings.parent && *p.data.parent.wl_surface() == w.wl_surface(&self.connection)) - || 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 let Some(size) = settings.positioner.size { - size - } else { - 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 { - log::error!("Failed to create popup positioner"); - return Ok(()); - }; - positioner.set_anchor(settings.positioner.anchor); - positioner.set_anchor_rect( - settings.positioner.anchor_rect.x, - settings.positioner.anchor_rect.y, - settings.positioner.anchor_rect.width, - settings.positioner.anchor_rect.height, - ); - if let Ok(constraint_adjustment) = - settings.positioner.constraint_adjustment.try_into() + Action::Popup(action) => { + match action { + platform_specific::wayland::popup::Action::Popup { popup: settings } => { + // first check existing popup + // if an existing popup with the same id exists, we just update the positioner. + if let Some((chain, existing)) = self.popmgr.popup_id(settings.id).and_then(|p| + (p.data.grab == settings.grab && self.popmgr.popups().any(|parent| parent.popup.wl_surface() == p.data.parent.wl_surface() && parent.data.id == settings.parent) + || self.windows.iter().any(|w| w.id == settings.parent && *p.data.parent.wl_surface() == w.wl_surface(&self.connection)) + || self.layer_surfaces.iter().any(|l| l.id == settings.parent && p.data.parent.wl_surface() == l.surface.wl_surface())).then(|| + { + p.popup.wl_surface().clone() + })).and_then(|s| self.popmgr.chain_for_popup_mut(&s)) { - positioner.set_constraint_adjustment(constraint_adjustment); - } - positioner.set_gravity(settings.positioner.gravity); - positioner.set_offset( - settings.positioner.offset.0, - settings.positioner.offset.1, - ); - if settings.positioner.reactive { - positioner.set_reactive(); - } - positioner.set_size(size.0 as i32, size.1 as i32); - existing.data.positioner = Arc::new(positioner); - existing.set_size(size.0, size.1, TOKEN_CTR.fetch_add(1, std::sync::atomic::Ordering::Relaxed)); - _ = send_event(&self.events_sender, &self.proxy, - SctkEvent::PopupEvent { variant: crate::sctk_event::PopupEventVariant::Size(size.0, size.1), toplevel_id: existing.data.parent.wl_surface().clone(), parent_id: existing.data.parent.wl_surface().clone(), id: existing.popup.wl_surface().clone() }); - return Ok(()); - } - let mut parent_mismatch = !self.popups.is_empty(); - for p in &self.popups { - parent_mismatch = p.data.id != settings.parent; - } - if !self.destroyed.is_empty() || parent_mismatch { - if parent_mismatch { - let mut found = false; - for p in std::mem::take(&mut self.popups).into_iter().rev() { - let id = p.data.id; - self.popups.insert(0, p); - - found |= id == settings.parent; - if !found { - _ = self.handle_action(Action::Popup(platform_specific::wayland::popup::Action::Destroy{id})); - } - - } - } - if self.pending_popup.replace((settings, 0)).is_none() { - - let timer = cctk::sctk::reexports::calloop::timer::Timer::from_duration(Duration::from_millis(30)); - let queue_handle = self.queue_handle.clone(); - _ = self.loop_handle.insert_source(timer, move |_, _, state| { - let Some((mut popup, attempt)) = state.pending_popup.take() else { - return TimeoutAction::Drop; + let existing = &mut chain[existing]; + let size = if let Some(size) = settings.positioner.size { + size + } else { + 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 { + log::error!("Failed to create popup positioner"); + return Ok(()); }; - - if !state.destroyed.is_empty() || state.popups.last().is_some_and(|p| { - state.id_map.get(&p.popup.wl_surface().id()).map_or(true, |p| *p != popup.parent) - }) { - if attempt < 5 { - state.pending_popup = Some((popup, attempt+1)); - TimeoutAction::ToDuration(Duration::from_millis(30)) - } - else { + positioner.set_anchor(settings.positioner.anchor); + positioner.set_anchor_rect( + settings.positioner.anchor_rect.x, + settings.positioner.anchor_rect.y, + settings.positioner.anchor_rect.width, + settings.positioner.anchor_rect.height, + ); + if let Ok(constraint_adjustment) = + settings.positioner.constraint_adjustment.try_into() + { + positioner.set_constraint_adjustment(constraint_adjustment); + } + positioner.set_gravity(settings.positioner.gravity); + positioner.set_offset( + settings.positioner.offset.0, + settings.positioner.offset.1, + ); + if settings.positioner.reactive { + positioner.set_reactive(); + } + positioner.set_size(size.0 as i32, size.1 as i32); + existing.data.positioner = Arc::new(positioner); + existing.set_size(size.0, size.1, TOKEN_CTR.fetch_add(1, std::sync::atomic::Ordering::Relaxed)); + _ = send_event(&self.events_sender, &self.proxy, + SctkEvent::PopupEvent { variant: crate::sctk_event::PopupEventVariant::Size(size.0, size.1), toplevel_id: existing.data.parent.wl_surface().clone(), parent_id: existing.data.parent.wl_surface().clone(), id: existing.popup.wl_surface().clone() }); + return Ok(()); + } else if !self.destroyed.is_empty() || self.popmgr.popup_id(settings.id).is_some() || self.popmgr.active_grab().is_some() + { + let active_grab = self.popmgr.active_grab(); + if let Some(grab) = self.popmgr.root_grab().zip(active_grab).and_then(|(root, active)| (active.data.id != settings.parent).then_some(root.data.id)) { + let _ = self.handle_action(Action::Popup(platform_specific::wayland::popup::Action::Destroy { id: grab })); + } + if self.popmgr.popup_id(settings.id).is_some() { + let _ = self.handle_action(Action::Popup(platform_specific::wayland::popup::Action::Destroy { id: settings.id })); + } + if self.pending_popup.replace((settings, 0)).is_none() { + let timer = cctk::sctk::reexports::calloop::timer::Timer::from_duration(Duration::from_millis(30)); + let queue_handle = self.queue_handle.clone(); + _ = self.loop_handle.insert_source(timer, move |_, _, state| { + let Some((settings, attempt)) = state.pending_popup.take() else { + return TimeoutAction::Drop; + }; + // check if the mismatch still exists... + if !state.destroyed.is_empty() || state.popmgr.popup_id(settings.id).is_some_and(|p| + state.popmgr.popups().any(|parent| parent.popup.wl_surface() == p.data.parent.wl_surface() && parent.data.id == settings.parent)) + { + if attempt < 5 { + state.pending_popup = Some((settings, attempt+1)); + TimeoutAction::ToDuration(Duration::from_millis(30)) + } + else { + TimeoutAction::Drop + } + } else { + match state.get_popup(settings) { + Ok((id, parent_id, toplevel_id, surface, common)) => { + let wl_surface = surface.wl_surface().clone(); + receive_frame(&mut state.frame_status, &wl_surface); + send_event(&state.events_sender, &state.proxy, + SctkEvent::PopupEvent { + variant: crate::platform_specific::wayland::sctk_event::PopupEventVariant::Created(queue_handle.clone(), surface, id, common, state.connection.display()), + toplevel_id, parent_id, id: wl_surface }); + } + Err(err) => { + log::error!("Failed to create popup. {err:?}"); + } + }; TimeoutAction::Drop } - } else { - match state.get_popup(popup) { - Ok((id, parent_id, toplevel_id, surface, common)) => { - let wl_surface = surface.wl_surface().clone(); - receive_frame(&mut state.frame_status, &wl_surface); - send_event(&state.events_sender, &state.proxy, - SctkEvent::PopupEvent { - variant: crate::platform_specific::wayland::sctk_event::PopupEventVariant::Created(queue_handle.clone(), surface, id, common, state.connection.display()), - toplevel_id, parent_id, id: wl_surface }); - } - Err(err) => { - log::error!("Failed to create popup. {err:?}"); - } - }; - TimeoutAction::Drop + }); + } + } else { + match self.get_popup(settings) { + Ok((id, parent_id, toplevel_id, surface, common)) => { + let wl_surface = surface.wl_surface().clone(); + send_event(&self.events_sender, &self.proxy, + SctkEvent::PopupEvent { + variant: crate::platform_specific::wayland::sctk_event::PopupEventVariant::Created(self.queue_handle.clone(), surface, id, common, self.connection.display()), + toplevel_id, parent_id, id: wl_surface }); + } + Err(err) => { + log::error!("Failed to create popup. {err:?}"); } - }); - } - } else { - self.pending_popup = None; - match self.get_popup(settings) { - Ok((id, parent_id, toplevel_id, surface, common)) => { - let wl_surface = surface.wl_surface().clone(); - send_event(&self.events_sender, &self.proxy, - SctkEvent::PopupEvent { - variant: crate::platform_specific::wayland::sctk_event::PopupEventVariant::Created(self.queue_handle.clone(), surface, id, common, self.connection.display()), - toplevel_id, parent_id, id: wl_surface }); - } - Err(err) => { - log::error!("Failed to create popup. {err:?}"); } } - } - }, - // XXX popup destruction must be done carefully - // first destroy the uppermost popup, then work down to the requested popup - platform_specific::wayland::popup::Action::Destroy { id } => { - let sctk_popup = match self - .popups - .iter() - .position(|s| s.data.id == id) - { - Some(p) => self.popups.remove(p), - None => { - log::info!("No popup to destroy"); + }, + // XXX popup destruction must be done carefully + // first destroy the uppermost popup, then work down to the requested popup + platform_specific::wayland::popup::Action::Destroy { id } => { + let Some(to_destroy) = self.popmgr.popup_id(id) else { + log::warn!("Destroyed popup does not exist."); return Ok(()); - }, - }; - let mut to_destroy = vec![sctk_popup]; + }; + let s = to_destroy.popup.wl_surface().clone(); - while let Some(popup_to_destroy_last) = to_destroy.last().and_then(|popup| self - .popups - .iter() - .position(|p| popup.data.parent.wl_surface() == p.popup.wl_surface() && p.close_with_children)) { - let popup_to_destroy_last = self.popups.remove(popup_to_destroy_last); - to_destroy.push(popup_to_destroy_last); - } - to_destroy.reverse(); + let Some(to_destroy) = self.popmgr.remove(&s) else { + return Ok(()); + }; - while let Some(popup_to_destroy_first) = to_destroy.last().and_then(|popup| self - .popups - .iter() - .position(|p| p.data.parent.wl_surface() == popup.popup.wl_surface())) { - let popup_to_destroy_first = self.popups.remove(popup_to_destroy_first); - to_destroy.push(popup_to_destroy_first); - } - for popup in to_destroy.into_iter().rev() { - if let Some(id) = self.id_map.remove(&popup.popup.wl_surface().id()) { - _ = self.destroyed.insert(id); + for popup in to_destroy { + if let Some(id) = self.id_map.remove(&popup.popup.wl_surface().id()) { + _ = self.destroyed.insert(id); + } + + if let Some(blurred) = self.blur_surfaces.remove(&id) { + blurred.destroy(); + } + _ = self.corner_radii.remove(&id); + + + let (removed, remaining): (Vec<_>, Vec<_>) = self + .subsurfaces + .drain(..) + .partition(|s| { + s.instance.parent == *popup.popup.wl_surface() + }); + + self.subsurfaces = remaining; + for s in removed + { + crate::subsurface_widget::remove_iced_subsurface( + &s.instance.wl_surface, + ); + send_event(&self.events_sender, &self.proxy, + SctkEvent::SubsurfaceEvent( crate::sctk_event::SubsurfaceEventVariant::Destroyed(s.instance) ) + ); + } + _ = send_event(&self.events_sender, &self.proxy, + SctkEvent::PopupEvent { variant: crate::sctk_event::PopupEventVariant::Done, toplevel_id: popup.data.toplevel.clone(), parent_id: popup.data.parent.wl_surface().clone(), id: popup.popup.wl_surface().clone() }); } - - if let Some(blurred) = self.blur_surfaces.remove(&id) { - blurred.destroy(); - } - _ = self.corner_radii.remove(&id); - - - let (removed, remaining): (Vec<_>, Vec<_>) = self - .subsurfaces - .drain(..) - .partition(|s| { - s.instance.parent == *popup.popup.wl_surface() - }); - - self.subsurfaces = remaining; - for s in removed + }, + platform_specific::wayland::popup::Action::Size { id, width, height } => { + if let Some(sctk_popup) = self + .popmgr.popup_id_mut(id) { - crate::subsurface_widget::remove_iced_subsurface( - &s.instance.wl_surface, - ); - send_event(&self.events_sender, &self.proxy, - SctkEvent::SubsurfaceEvent( crate::sctk_event::SubsurfaceEventVariant::Destroyed(s.instance) ) - ); + // update geometry + // update positioner + sctk_popup.set_size(width, height, TOKEN_CTR.fetch_add(1, std::sync::atomic::Ordering::Relaxed)); + let surface = sctk_popup.popup.wl_surface().clone(); + _ = send_event(&self.events_sender, &self.proxy, + SctkEvent::PopupEvent { variant: crate::sctk_event::PopupEventVariant::Size(width, height), toplevel_id: sctk_popup.data.parent.wl_surface().clone(), parent_id: sctk_popup.data.parent.wl_surface().clone(), id: surface }); } - _ = send_event(&self.events_sender, &self.proxy, - SctkEvent::PopupEvent { variant: crate::sctk_event::PopupEventVariant::Done, toplevel_id: popup.data.toplevel.clone(), parent_id: popup.data.parent.wl_surface().clone(), id: popup.popup.wl_surface().clone() }); - } - }, - platform_specific::wayland::popup::Action::Size { id, width, height } => { - if let Some(sctk_popup) = self - .popups - .iter_mut() - .find(|s| s.data.id == id) - { - // update geometry - // update positioner - sctk_popup.set_size(width, height, TOKEN_CTR.fetch_add(1, std::sync::atomic::Ordering::Relaxed)); - let surface = sctk_popup.popup.wl_surface().clone(); - _ = send_event(&self.events_sender, &self.proxy, - SctkEvent::PopupEvent { variant: crate::sctk_event::PopupEventVariant::Size(width, height), toplevel_id: sctk_popup.data.parent.wl_surface().clone(), parent_id: sctk_popup.data.parent.wl_surface().clone(), id: surface }); - } - }, - platform_specific::wayland::popup::Action::Reposition { id, positioner } => { - if let Some(sctk_popup) = self - .popups - .iter_mut() - .find(|s| s.data.id == id) - { - sctk_popup.data.positioner.set_anchor(positioner.anchor); - sctk_popup.data.positioner.set_anchor_rect( - positioner.anchor_rect.x, - positioner.anchor_rect.y, - positioner.anchor_rect.width, - positioner.anchor_rect.height, - ); - if let Ok(constraint_adjustment) = - positioner.constraint_adjustment.try_into() + }, + platform_specific::wayland::popup::Action::Reposition { id, positioner } => { + if let Some(sctk_popup) = self + .popmgr.popup_id_mut(id) { - sctk_popup.data.positioner.set_constraint_adjustment(constraint_adjustment); + sctk_popup.data.positioner.set_anchor(positioner.anchor); + sctk_popup.data.positioner.set_anchor_rect( + positioner.anchor_rect.x, + positioner.anchor_rect.y, + positioner.anchor_rect.width, + positioner.anchor_rect.height, + ); + if let Ok(constraint_adjustment) = + positioner.constraint_adjustment.try_into() + { + sctk_popup.data.positioner.set_constraint_adjustment(constraint_adjustment); + } + sctk_popup.data.positioner.set_gravity(positioner.gravity); + sctk_popup.data.positioner.set_offset( + positioner.offset.0, + positioner.offset.1, + ); + if positioner.reactive { + sctk_popup.data.positioner.set_reactive(); + } + let guard =sctk_popup.common.lock().unwrap(); + let w = guard.size.width; + let h = guard.size.height; + drop(guard); + let size = positioner.size.unwrap_or((w, h)); + sctk_popup.popup + .xdg_surface() + .set_window_geometry(0, 0, w as i32, h as i32); + sctk_popup.update_viewport(w, h); + // update positioner + sctk_popup.data.positioner.set_size(w as i32, h as i32); + sctk_popup.popup.reposition(&sctk_popup.data.positioner, TOKEN_CTR.fetch_add(1, std::sync::atomic::Ordering::Relaxed)); let surface = sctk_popup.popup.wl_surface().clone(); + _ = send_event(&self.events_sender, &self.proxy, + SctkEvent::PopupEvent { variant: crate::sctk_event::PopupEventVariant::Size(size.0, size.1), toplevel_id: sctk_popup.data.parent.wl_surface().clone(), parent_id: sctk_popup.data.parent.wl_surface().clone(), id: surface }); } - sctk_popup.data.positioner.set_gravity(positioner.gravity); - sctk_popup.data.positioner.set_offset( - positioner.offset.0, - positioner.offset.1, - ); - if positioner.reactive { - sctk_popup.data.positioner.set_reactive(); - } - let guard =sctk_popup.common.lock().unwrap(); - let w = guard.size.width; - let h = guard.size.height; - drop(guard); - let size = positioner.size.unwrap_or((w, h)); - sctk_popup.popup - .xdg_surface() - .set_window_geometry(0, 0, w as i32, h as i32); - sctk_popup.update_viewport(w, h); - // update positioner - sctk_popup.data.positioner.set_size(w as i32, h as i32); - sctk_popup.popup.reposition(&sctk_popup.data.positioner, TOKEN_CTR.fetch_add(1, std::sync::atomic::Ordering::Relaxed)); let surface = sctk_popup.popup.wl_surface().clone(); - _ = send_event(&self.events_sender, &self.proxy, - SctkEvent::PopupEvent { variant: crate::sctk_event::PopupEventVariant::Size(size.0, size.1), toplevel_id: sctk_popup.data.parent.wl_surface().clone(), parent_id: sctk_popup.data.parent.wl_surface().clone(), id: surface }); - } - }, + }, + } }, Action::Activation(activation_event) => match activation_event { platform_specific::wayland::activation::Action::RequestToken { app_id, window, channel } => { @@ -1768,7 +1684,7 @@ impl SctkState { } 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()))) - } else if let Some(p) = self.popups.iter_mut().find(|w| w.data.id == id) { + } else if let Some(p) = self.popmgr.popup_id_mut(id) { 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) { @@ -1872,7 +1788,7 @@ impl SctkState { return Ok(()); } - let s = if let Some(s) = self.popups.iter().find(|s| s.data.id == id) { + let s = if let Some(s) = self.popmgr.popup_id(id) { s.popup.wl_surface() } else if let Some(s) = self.layer_surfaces.iter().find(|s| s.id == id) { s.surface.wl_surface() @@ -1972,7 +1888,7 @@ impl SctkState { }; if self.layer_surfaces.iter().any(|s| s.id == settings.id) || self.windows.iter().any(|w| w.id == settings.id) - || self.popups.iter().any(|p| p.data.id == settings.id) + || self.popmgr.popup_id(settings.id).is_some() || self.subsurfaces.iter().any(|s| s.id == settings.id) { log::warn!("Subsurface with id {:?} already exists", settings.id); @@ -2027,12 +1943,7 @@ impl SctkState { self.windows.iter().find(|w| w.id == settings.parent) { PopupParent::Window(parent.wl_surface(&self.connection)) - } else if let Some(i) = self - .popups - .iter() - .position(|p| p.data.id == settings.parent) - { - let parent = &self.popups[i]; + } else if let Some(parent) = self.popmgr.popup_id(settings.parent) { PopupParent::Popup(parent.popup.wl_surface().clone()) } else if let Some(i) = self .lock_surfaces 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 432f5bde..4266e196 100644 --- a/winit/src/platform_specific/wayland/handlers/shell/xdg_popup.rs +++ b/winit/src/platform_specific/wayland/handlers/shell/xdg_popup.rs @@ -1,6 +1,6 @@ use crate::event_loop::state::receive_frame; use crate::platform_specific::wayland::{ - event_loop::state::{self, PopupParent, SctkState}, + event_loop::state::{PopupParent, SctkState}, sctk_event::{PopupEventVariant, SctkEvent}, }; use cctk::sctk::{ @@ -18,11 +18,11 @@ impl PopupHandler for SctkState { configure: cctk::sctk::shell::xdg::popup::PopupConfigure, ) { self.request_redraw(popup.wl_surface()); - let sctk_popup = match self.popups.iter_mut().find(|s| { - s.popup.wl_surface().clone() == popup.wl_surface().clone() - }) { + let sctk_popup = match self.popmgr.popup_mut(popup.wl_surface()) { Some(p) => p, - None => return, + None => { + return; + } }; let first = sctk_popup.last_configure.is_none(); _ = sctk_popup.last_configure.replace(configure.clone()); @@ -53,35 +53,11 @@ impl PopupHandler for SctkState { _qh: &cctk::sctk::reexports::client::QueueHandle, popup: &cctk::sctk::shell::xdg::popup::Popup, ) { - let sctk_popup = match self.popups.iter().position(|s| { - s.popup.wl_surface().clone() == popup.wl_surface().clone() - }) { - Some(p) => self.popups.remove(p), - None => return, + let Some(to_destroy) = self.popmgr.remove(popup.wl_surface()) else { + return; }; - let mut to_destroy = vec![sctk_popup]; - while let Some(popup_to_destroy) = to_destroy.last() { - match popup_to_destroy.data.parent.clone() { - state::PopupParent::LayerSurface(_) - | state::PopupParent::Window(_) => { - break; - } - state::PopupParent::Popup(popup_to_destroy_first) => { - let Some(popup_to_destroy_first) = - self.popups.iter().position(|p| { - p.popup.wl_surface() == &popup_to_destroy_first - }) - else { - log::warn!("could not find popup to destroy first."); - return; - }; - let popup_to_destroy_first = - self.popups.remove(popup_to_destroy_first); - to_destroy.push(popup_to_destroy_first); - } - } - } - for popup in to_destroy.into_iter().rev() { + + for popup in to_destroy { if let Some(id) = self.id_map.remove(&popup.popup.wl_surface().id()) { if let Some(blurred) = self.blur_surfaces.remove(&id) { From cc5ca1ce29f2391376242010de6fd9326213e901 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Thu, 3 Sep 2026 12:16:45 -0400 Subject: [PATCH 77/93] fix: handling of grab chains and deletion of pending popups --- .../wayland/event_loop/popup.rs | 31 ++++ .../wayland/event_loop/state.rs | 142 ++++++++++++------ 2 files changed, 128 insertions(+), 45 deletions(-) diff --git a/winit/src/platform_specific/wayland/event_loop/popup.rs b/winit/src/platform_specific/wayland/event_loop/popup.rs index 09cfe96c..109e9af6 100644 --- a/winit/src/platform_specific/wayland/event_loop/popup.rs +++ b/winit/src/platform_specific/wayland/event_loop/popup.rs @@ -36,6 +36,23 @@ impl PopupManager { pos.map(|pos| (&mut self.chains[pos.0], pos.1)) } + pub(crate) fn chain_for_popup( + &self, + id: &WlSurface, + ) -> Option<(&Vec, usize)> { + let pos = self.chains.iter().enumerate().find_map(move |(pos, c)| { + if let Some(pop_pos) = + c.into_iter().position(|p| p.popup.wl_surface() == id) + { + Some((pos, pop_pos)) + } else { + None + } + }); + + pos.map(|pos| (&self.chains[pos.0], pos.1)) + } + pub(crate) fn popup(&self, id: &WlSurface) -> Option<&SctkPopup> { self.chains.iter().find_map(move |c| { c.into_iter().find(|p| p.popup.wl_surface() == id) @@ -114,6 +131,20 @@ impl PopupManager { return ret; } + + pub(crate) fn remove_ignore_children( + &mut self, + popup: &WlSurface, + ) -> Option> { + // must perform cleanup so that the popups are dropped in the correct order + let ret = if let Some((chain, pos)) = self.chain_for_popup_mut(popup) { + Some(chain.drain(pos..).rev()) + } else { + None + }; + + return ret; + } } #[derive(Debug)] diff --git a/winit/src/platform_specific/wayland/event_loop/state.rs b/winit/src/platform_specific/wayland/event_loop/state.rs index 12bb75d0..642da54c 100644 --- a/winit/src/platform_specific/wayland/event_loop/state.rs +++ b/winit/src/platform_specific/wayland/event_loop/state.rs @@ -1318,10 +1318,28 @@ impl SctkState { return Ok(()); } else if !self.destroyed.is_empty() || self.popmgr.popup_id(settings.id).is_some() || self.popmgr.active_grab().is_some() { - let active_grab = self.popmgr.active_grab(); - if let Some(grab) = self.popmgr.root_grab().zip(active_grab).and_then(|(root, active)| (active.data.id != settings.parent).then_some(root.data.id)) { - let _ = self.handle_action(Action::Popup(platform_specific::wayland::popup::Action::Destroy { id: grab })); + // must clean up popup chains so that there is just one grab chain... + let to_destroy = if settings.grab { + if let Some((grab_chain, p_i)) = self.popmgr.active_grab().and_then(|g| self.popmgr.chain_for_popup(g.popup.wl_surface())) { + + if let Some(pos) = grab_chain.iter().position(|p| p.data.id == settings.parent) { + // destroy children of parent + grab_chain.get(pos + 1).map(|g| g.data.id) + } + else { + // destroy whole chain... + grab_chain.get(0).map(|g| g.data.id) + } + } else { + None + } + } else { + None + }; + if let Some(to_destroy) = to_destroy { + _ = self.destroy_popup(to_destroy, true); } + if self.popmgr.popup_id(settings.id).is_some() { let _ = self.handle_action(Action::Popup(platform_specific::wayland::popup::Action::Destroy { id: settings.id })); } @@ -1367,8 +1385,11 @@ impl SctkState { let wl_surface = surface.wl_surface().clone(); send_event(&self.events_sender, &self.proxy, SctkEvent::PopupEvent { - variant: crate::platform_specific::wayland::sctk_event::PopupEventVariant::Created(self.queue_handle.clone(), surface, id, common, self.connection.display()), - toplevel_id, parent_id, id: wl_surface }); + variant: crate::platform_specific::wayland::sctk_event::PopupEventVariant::Created( + self.queue_handle.clone(), surface, id, common, self.connection.display() + ), + toplevel_id, parent_id, id: wl_surface } + ); } Err(err) => { log::error!("Failed to create popup. {err:?}"); @@ -1379,46 +1400,8 @@ impl SctkState { // XXX popup destruction must be done carefully // first destroy the uppermost popup, then work down to the requested popup platform_specific::wayland::popup::Action::Destroy { id } => { - let Some(to_destroy) = self.popmgr.popup_id(id) else { - log::warn!("Destroyed popup does not exist."); - return Ok(()); - }; - let s = to_destroy.popup.wl_surface().clone(); - - let Some(to_destroy) = self.popmgr.remove(&s) else { - return Ok(()); - }; - - for popup in to_destroy { - if let Some(id) = self.id_map.remove(&popup.popup.wl_surface().id()) { - _ = self.destroyed.insert(id); - } - - if let Some(blurred) = self.blur_surfaces.remove(&id) { - blurred.destroy(); - } - _ = self.corner_radii.remove(&id); - - - let (removed, remaining): (Vec<_>, Vec<_>) = self - .subsurfaces - .drain(..) - .partition(|s| { - s.instance.parent == *popup.popup.wl_surface() - }); - - self.subsurfaces = remaining; - for s in removed - { - crate::subsurface_widget::remove_iced_subsurface( - &s.instance.wl_surface, - ); - send_event(&self.events_sender, &self.proxy, - SctkEvent::SubsurfaceEvent( crate::sctk_event::SubsurfaceEventVariant::Destroyed(s.instance) ) - ); - } - _ = send_event(&self.events_sender, &self.proxy, - SctkEvent::PopupEvent { variant: crate::sctk_event::PopupEventVariant::Done, toplevel_id: popup.data.toplevel.clone(), parent_id: popup.data.parent.wl_surface().clone(), id: popup.popup.wl_surface().clone() }); + if let Some(value) = self.destroy_popup(id, false) { + return value; } }, platform_specific::wayland::popup::Action::Size { id, width, height } => { @@ -1809,6 +1792,75 @@ impl SctkState { Ok(()) } + fn destroy_popup( + &mut self, + id: core::window::Id, + ignore_children: bool, + ) -> Option> { + let Some(to_destroy) = self.popmgr.popup_id(id) else { + if self.pending_popup.take().is_none_or(|p_id| p_id.0.id != id) { + log::warn!( + "Destroyed popup does not exist. {id:?}, existing: {:?}", + self.popmgr.popups().map(|p| p.data.id).collect::>() + ); + } + return Some(Ok(())); + }; + let s = to_destroy.popup.wl_surface().clone(); + let d: Option> = if ignore_children { + self.popmgr.remove(&s).map(|v| v.collect()) + } else { + self.popmgr.remove_ignore_children(&s).map(|v| v.collect()) + }; + let Some(to_destroy) = d else { + return Some(Ok(())); + }; + + for popup in to_destroy { + if let Some(id) = self.id_map.remove(&popup.popup.wl_surface().id()) + { + _ = self.destroyed.insert(id); + } + + if let Some(blurred) = self.blur_surfaces.remove(&id) { + blurred.destroy(); + } + _ = self.corner_radii.remove(&id); + + let (removed, remaining): (Vec<_>, Vec<_>) = self + .subsurfaces + .drain(..) + .partition(|s| s.instance.parent == *popup.popup.wl_surface()); + + self.subsurfaces = remaining; + for s in removed { + crate::subsurface_widget::remove_iced_subsurface( + &s.instance.wl_surface, + ); + send_event( + &self.events_sender, + &self.proxy, + SctkEvent::SubsurfaceEvent( + crate::sctk_event::SubsurfaceEventVariant::Destroyed( + s.instance, + ), + ), + ); + } + _ = send_event( + &self.events_sender, + &self.proxy, + SctkEvent::PopupEvent { + variant: crate::sctk_event::PopupEventVariant::Done, + toplevel_id: popup.data.toplevel.clone(), + parent_id: popup.data.parent.wl_surface().clone(), + id: popup.popup.wl_surface().clone(), + }, + ); + } + None + } + fn apply_blur( &mut self, id: core::window::Id, From 511180679b3792387f9b5eabd6d11f4c1bc4ade6 Mon Sep 17 00:00:00 2001 From: Hojjat Date: Tue, 1 Sep 2026 18:02:37 -0600 Subject: [PATCH 78/93] feat: Lancsoz downsampler when target size is relatively too small --- graphics/src/image.rs | 104 ++++++++++++++++++++++++++++++++++++++++ tiny_skia/src/raster.rs | 68 +++++++++++++++++++++++++- wgpu/src/image/cache.rs | 55 +++++++++++++++++++++ wgpu/src/image/mod.rs | 8 +++- 4 files changed, 233 insertions(+), 2 deletions(-) diff --git a/graphics/src/image.rs b/graphics/src/image.rs index e5fe9281..eda89951 100644 --- a/graphics/src/image.rs +++ b/graphics/src/image.rs @@ -1,6 +1,8 @@ //! Load and operate on images. #[cfg(feature = "image")] use crate::core::Bytes; +#[cfg(feature = "image")] +use crate::core::Size; use crate::core::Color; use crate::core::Radians; @@ -180,3 +182,105 @@ fn to_error(error: ::image::ImageError) -> image::Error { error => image::Error::Invalid(Arc::new(error)), } } + +/// resample a raster image to this target +#[cfg(feature = "image")] +pub fn downsample_target( + native: Size, + bounds: Size, +) -> Option> { + if !(bounds.width >= 1.0 && bounds.height >= 1.0) { + return None; + } + + // Round up to 4px so an animated resize does not make a copy per pixel + // TODO: maybe find a better approach + let quantize = |length: f32| (length.ceil() as u32).div_ceil(4) * 4; + + let target = Size::new( + quantize(bounds.width).min(native.width), + quantize(bounds.height).min(native.height), + ); + + let minified = native.width as f32 >= target.width as f32 * 1.25 + || native.height as f32 >= target.height as f32 * 1.25; + + // If the target is big then Lanczos will be too expensive, and sampler is good enough + let small = u64::from(target.width) * u64::from(target.height) <= 1 << 18; + + (minified && small).then_some(target) +} + +/// Resamples premultiplied pixels down to `target`. +#[cfg(feature = "image")] +pub fn downsample_premultiplied( + pixels: &[u8], + size: Size, + target: Size, +) -> Vec { + let image = + ::image::RgbaImage::from_raw(size.width, size.height, pixels.to_vec()) + .expect("pixels hold width * height RGBA pixels"); + + resize(&image, target).into_raw() +} + +#[cfg(feature = "image")] +fn resize(image: &::image::RgbaImage, target: Size) -> ::image::RgbaImage { + use ::image::imageops::{self, FilterType}; + use std::borrow::Cow; + + // if image is too big compared to target, box average it to double the target + // and then do Lanczos. The final result is almost the same, but lanczos is too + // expensive on large images. + let image = if image.width() >= target.width * 4 + && image.height() >= target.height * 4 + { + Cow::Owned(imageops::thumbnail( + image, + target.width * 2, + target.height * 2, + )) + } else { + Cow::Borrowed(image) + }; + + imageops::resize(&*image, target.width, target.height, FilterType::Lanczos3) +} + +/// Resamples RGBA pixels down to `target`. +/// +/// Premultiplies the image, to avoid fringing the edges of an icon when interpolating +/// transparent pixels. +#[cfg(feature = "image")] +pub fn downsample(image: &Buffer, target: Size) -> ::image::RgbaImage { + let mut image = ::image::RgbaImage::from_raw( + image.width(), + image.height(), + image.as_raw().to_vec(), + ) + .expect("buffer holds width * height RGBA pixels"); + + for pixel in image.pixels_mut() { + let alpha = u32::from(pixel[3]); + + for channel in &mut pixel.0[..3] { + *channel = ((u32::from(*channel) * alpha + 127) / 255) as u8; + } + } + + let mut image = resize(&image, target); + + for pixel in image.pixels_mut() { + let alpha = u32::from(pixel[3]); + + if alpha > 0 { + for channel in &mut pixel.0[..3] { + *channel = ((u32::from(*channel) * 255 + alpha / 2) / alpha) + .min(255) as u8; + } + } + } + + image +} diff --git a/tiny_skia/src/raster.rs b/tiny_skia/src/raster.rs index 7c820917..0535158a 100644 --- a/tiny_skia/src/raster.rs +++ b/tiny_skia/src/raster.rs @@ -51,7 +51,21 @@ impl Pipeline { ) { let mut cache = self.cache.borrow_mut(); - let Ok(mut image) = cache.allocate(handle) else { + let target = { + let Ok(image) = cache.allocate(handle) else { + return; + }; + + graphics::image::downsample_target( + Size::new(image.width(), image.height()), + bounds.size(), + ) + }; + + let Ok(mut image) = (match target { + Some(target) => cache.allocate_resampled(handle, target), + None => cache.allocate(handle), + }) else { return; }; @@ -110,6 +124,8 @@ impl Pipeline { struct Cache { entries: FxHashMap>, hits: FxHashSet, + resampled: FxHashMap<(raster::Id, u32, u32), Entry>, + resampled_hits: FxHashSet<(raster::Id, u32, u32)>, } impl Cache { @@ -166,9 +182,59 @@ impl Cache { Ok(ret) } + /// Like [`Self::allocate`], resampled to `target`. Call after + /// [`Self::allocate`] has decoded the image. + pub fn allocate_resampled( + &mut self, + handle: &raster::Handle, + target: Size, + ) -> Result, raster::Error> { + let key = (handle.id(), target.width, target.height); + + if !self.resampled.contains_key(&key) { + let native = self + .entries + .get(&handle.id()) + .and_then(Option::as_ref) + .ok_or(raster::Error::Empty)?; + + // Stored pixels are already premultiplied, so resample them as is. + let pixels = graphics::image::downsample_premultiplied( + bytemuck::cast_slice(&native.pixels), + Size::new(native.width, native.height), + target, + ); + + let _ = self.resampled.insert( + key, + Entry { + width: target.width, + height: target.height, + pixels: pixels + .chunks_exact(4) + .map(|p| u32::from_ne_bytes([p[0], p[1], p[2], p[3]])) + .collect(), + }, + ); + } + + let _ = self.resampled_hits.insert(key); + let entry = &self.resampled[&key]; + + Ok(tiny_skia::PixmapRef::from_bytes( + bytemuck::cast_slice(&entry.pixels), + entry.width, + entry.height, + ) + .expect("Build pixmap from image bytes")) + } + fn trim(&mut self) { self.entries.retain(|key, _| self.hits.contains(key)); + self.resampled + .retain(|key, _| self.resampled_hits.contains(key)); self.hits.clear(); + self.resampled_hits.clear(); } } diff --git a/wgpu/src/image/cache.rs b/wgpu/src/image/cache.rs index 88a48640..37f1e33d 100644 --- a/wgpu/src/image/cache.rs +++ b/wgpu/src/image/cache.rs @@ -5,6 +5,8 @@ use crate::image::atlas::{self, Atlas}; #[cfg(all(feature = "image", not(target_arch = "wasm32")))] use worker::Worker; +#[cfg(feature = "image")] +use rustc_hash::{FxHashMap, FxHashSet}; #[cfg(feature = "image")] use std::collections::HashMap; @@ -38,6 +40,9 @@ impl Cache { raster: Raster { cache: crate::image::raster::Cache::default(), pending: HashMap::new(), + resampled: FxHashMap::default(), + resampled_hits: FxHashSet::default(), + should_trim: false, belt: wgpu::util::StagingBelt::new( device.clone(), 2 * 1024 * 1024, @@ -209,7 +214,9 @@ impl Cache { encoder: &mut wgpu::CommandEncoder, belt: &mut wgpu::util::StagingBelt, handle: &core::image::Handle, + bounds: Size, ) -> Option<(&atlas::Entry, &Arc)> { + use crate::graphics::image::{downsample, downsample_target, load}; use crate::image::raster::Memory; self.receive(); @@ -223,6 +230,34 @@ impl Cache { None, )?; + if let Some(target) = downsample_target(memory.dimensions(), bounds) { + let key = (handle.id(), target.width, target.height); + + if !self.raster.resampled.contains_key(&key) { + let image = memory.host().or_else(|| load(handle).ok())?; + let image = downsample(&image, target); + + let entry = self.atlas.upload( + device, + encoder, + belt, + target.width, + target.height, + &image, + )?; + + let _ = self.raster.resampled.insert(key, entry); + self.raster.should_trim = true; + } + + let _ = self.raster.resampled_hits.insert(key); + + return Some(( + self.raster.resampled.get(&key)?, + self.atlas.bind_group(), + )); + } + if let Memory::Device { entry, bind_group, .. } = memory @@ -303,6 +338,23 @@ impl Cache { #[cfg(not(target_arch = "wasm32"))] self.worker.drop(_bind_group); }); + + if self.raster.should_trim { + let hits = &self.raster.resampled_hits; + let atlas = &mut self.atlas; + + self.raster.resampled.retain(|key, entry| { + let retain = hits.contains(key); + + if !retain { + atlas.remove(entry); + } + + retain + }); + self.raster.resampled_hits.clear(); + self.raster.should_trim = false; + } } #[cfg(feature = "svg")] @@ -376,6 +428,9 @@ impl Drop for Cache { struct Raster { cache: crate::image::raster::Cache, pending: HashMap>, + resampled: FxHashMap<(core::image::Id, u32, u32), atlas::Entry>, + resampled_hits: FxHashSet<(core::image::Id, u32, u32)>, + should_trim: bool, belt: wgpu::util::StagingBelt, } diff --git a/wgpu/src/image/mod.rs b/wgpu/src/image/mod.rs index d0665ee4..2b5f7ade 100644 --- a/wgpu/src/image/mod.rs +++ b/wgpu/src/image/mod.rs @@ -267,7 +267,13 @@ impl State { clip_bounds, } => { if let Some((atlas_entry, bind_group)) = cache - .upload_raster(device, encoder, belt, &image.handle) + .upload_raster( + device, + encoder, + belt, + &image.handle, + bounds.size() * scale, + ) { match atlas.as_mut() { None => { From ffe1f1dbe3cbfd313f9b5fe8e36a4af462cae5d7 Mon Sep 17 00:00:00 2001 From: Hojjat Date: Tue, 8 Sep 2026 15:00:54 -0600 Subject: [PATCH 79/93] fix(wayland): deliver popup Done to the parent window's widgets too --- .../platform_specific/wayland/event_loop/state.rs | 15 ++++++++++----- .../wayland/handlers/shell/xdg_popup.rs | 2 ++ winit/src/platform_specific/wayland/sctk_event.rs | 6 ++++++ 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/winit/src/platform_specific/wayland/event_loop/state.rs b/winit/src/platform_specific/wayland/event_loop/state.rs index 642da54c..80914ffb 100644 --- a/winit/src/platform_specific/wayland/event_loop/state.rs +++ b/winit/src/platform_specific/wayland/event_loop/state.rs @@ -333,6 +333,7 @@ pub struct SctkSubsurface { pub struct SctkPopupData { pub(crate) id: core::window::Id, pub(crate) parent: PopupParent, + pub(crate) parent_window: core::window::Id, pub(crate) toplevel: WlSurface, pub(crate) positioner: Arc, pub(crate) grab: bool, @@ -902,6 +903,7 @@ impl SctkState { data: SctkPopupData { id: settings.id, parent: parent.clone(), + parent_window: settings.parent, toplevel: toplevel.clone(), positioner: positioner.clone(), grab: settings.grab, @@ -1314,7 +1316,7 @@ impl SctkState { existing.data.positioner = Arc::new(positioner); existing.set_size(size.0, size.1, TOKEN_CTR.fetch_add(1, std::sync::atomic::Ordering::Relaxed)); _ = send_event(&self.events_sender, &self.proxy, - SctkEvent::PopupEvent { variant: crate::sctk_event::PopupEventVariant::Size(size.0, size.1), toplevel_id: existing.data.parent.wl_surface().clone(), parent_id: existing.data.parent.wl_surface().clone(), id: existing.popup.wl_surface().clone() }); + SctkEvent::PopupEvent { variant: crate::sctk_event::PopupEventVariant::Size(size.0, size.1), toplevel_id: existing.data.parent.wl_surface().clone(), parent_id: existing.data.parent.wl_surface().clone(), id: existing.popup.wl_surface().clone(), parent_window: existing.data.parent_window }); return Ok(()); } else if !self.destroyed.is_empty() || self.popmgr.popup_id(settings.id).is_some() || self.popmgr.active_grab().is_some() { @@ -1362,6 +1364,7 @@ impl SctkState { TimeoutAction::Drop } } else { + let parent_window = settings.parent; match state.get_popup(settings) { Ok((id, parent_id, toplevel_id, surface, common)) => { let wl_surface = surface.wl_surface().clone(); @@ -1369,7 +1372,7 @@ impl SctkState { send_event(&state.events_sender, &state.proxy, SctkEvent::PopupEvent { variant: crate::platform_specific::wayland::sctk_event::PopupEventVariant::Created(queue_handle.clone(), surface, id, common, state.connection.display()), - toplevel_id, parent_id, id: wl_surface }); + toplevel_id, parent_id, id: wl_surface, parent_window }); } Err(err) => { log::error!("Failed to create popup. {err:?}"); @@ -1380,6 +1383,7 @@ impl SctkState { }); } } else { + let parent_window = settings.parent; match self.get_popup(settings) { Ok((id, parent_id, toplevel_id, surface, common)) => { let wl_surface = surface.wl_surface().clone(); @@ -1388,7 +1392,7 @@ impl SctkState { variant: crate::platform_specific::wayland::sctk_event::PopupEventVariant::Created( self.queue_handle.clone(), surface, id, common, self.connection.display() ), - toplevel_id, parent_id, id: wl_surface } + toplevel_id, parent_id, id: wl_surface, parent_window } ); } Err(err) => { @@ -1413,7 +1417,7 @@ impl SctkState { sctk_popup.set_size(width, height, TOKEN_CTR.fetch_add(1, std::sync::atomic::Ordering::Relaxed)); let surface = sctk_popup.popup.wl_surface().clone(); _ = send_event(&self.events_sender, &self.proxy, - SctkEvent::PopupEvent { variant: crate::sctk_event::PopupEventVariant::Size(width, height), toplevel_id: sctk_popup.data.parent.wl_surface().clone(), parent_id: sctk_popup.data.parent.wl_surface().clone(), id: surface }); + SctkEvent::PopupEvent { variant: crate::sctk_event::PopupEventVariant::Size(width, height), toplevel_id: sctk_popup.data.parent.wl_surface().clone(), parent_id: sctk_popup.data.parent.wl_surface().clone(), id: surface, parent_window: sctk_popup.data.parent_window }); } }, platform_specific::wayland::popup::Action::Reposition { id, positioner } => { @@ -1453,7 +1457,7 @@ impl SctkState { sctk_popup.data.positioner.set_size(w as i32, h as i32); sctk_popup.popup.reposition(&sctk_popup.data.positioner, TOKEN_CTR.fetch_add(1, std::sync::atomic::Ordering::Relaxed)); let surface = sctk_popup.popup.wl_surface().clone(); _ = send_event(&self.events_sender, &self.proxy, - SctkEvent::PopupEvent { variant: crate::sctk_event::PopupEventVariant::Size(size.0, size.1), toplevel_id: sctk_popup.data.parent.wl_surface().clone(), parent_id: sctk_popup.data.parent.wl_surface().clone(), id: surface }); + SctkEvent::PopupEvent { variant: crate::sctk_event::PopupEventVariant::Size(size.0, size.1), toplevel_id: sctk_popup.data.parent.wl_surface().clone(), parent_id: sctk_popup.data.parent.wl_surface().clone(), id: surface, parent_window: sctk_popup.data.parent_window }); } }, } @@ -1852,6 +1856,7 @@ impl SctkState { &self.proxy, SctkEvent::PopupEvent { variant: crate::sctk_event::PopupEventVariant::Done, + parent_window: popup.data.parent_window, toplevel_id: popup.data.toplevel.clone(), parent_id: popup.data.parent.wl_surface().clone(), id: popup.popup.wl_surface().clone(), 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 4266e196..4d11aac8 100644 --- a/winit/src/platform_specific/wayland/handlers/shell/xdg_popup.rs +++ b/winit/src/platform_specific/wayland/handlers/shell/xdg_popup.rs @@ -38,6 +38,7 @@ impl PopupHandler for SctkState { first, ), id: popup.wl_surface().clone(), + parent_window: sctk_popup.data.parent_window, toplevel_id: sctk_popup.data.toplevel.clone(), parent_id: match &sctk_popup.data.parent { PopupParent::LayerSurface(s) => s.clone(), @@ -70,6 +71,7 @@ impl PopupHandler for SctkState { self.sctk_events.push(SctkEvent::PopupEvent { variant: PopupEventVariant::Done, + parent_window: popup.data.parent_window, toplevel_id: popup.data.toplevel.clone(), parent_id: popup.data.parent.wl_surface().clone(), id: popup.popup.wl_surface().clone(), diff --git a/winit/src/platform_specific/wayland/sctk_event.rs b/winit/src/platform_specific/wayland/sctk_event.rs index 2ac54bed..64609b58 100755 --- a/winit/src/platform_specific/wayland/sctk_event.rs +++ b/winit/src/platform_specific/wayland/sctk_event.rs @@ -155,6 +155,9 @@ pub enum SctkEvent { parent_id: WlSurface, /// the id of this popup id: WlSurface, + /// Window id of the parent surface, as passed in the popup settings. Needed to route + /// `Done` to the parent's widgets. + parent_window: SurfaceId, }, SubsurfaceEvent(SubsurfaceEventVariant), @@ -920,6 +923,7 @@ impl SctkEvent { SctkEvent::PopupEvent { variant, id: surface, + parent_window, .. } => { match variant { @@ -958,6 +962,8 @@ impl SctkEvent { ) }) { + // tell the parent's widgets so menus can reset when the compositor dismisses them. + events.push((Some(parent_window), e.1.clone())); events.push(e) } } From d0f221c48b498d19a7a054d1f8f3b4d6a66eb92e Mon Sep 17 00:00:00 2001 From: Hojjat Date: Thu, 10 Sep 2026 13:44:45 -0600 Subject: [PATCH 80/93] feat(text): expose has_text and clipboard_has_text for context menus --- core/src/widget/text.rs | 34 +++++++++++++++++++++++++++++++++- widget/src/text_editor.rs | 14 ++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/core/src/widget/text.rs b/core/src/widget/text.rs index 2598b74e..c57fadbb 100644 --- a/core/src/widget/text.rs +++ b/core/src/widget/text.rs @@ -224,6 +224,7 @@ pub struct State { focused: bool, keyboard_focused: bool, context_menu_position: Option, + clipboard_has_text: bool, } impl Default for State

{ @@ -234,6 +235,7 @@ impl Default for State

{ focused: false, keyboard_focused: false, context_menu_position: None, + clipboard_has_text: false, } } } @@ -529,6 +531,7 @@ where Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Right)) => { if let Some(pos) = cursor.position_over(bounds) { state.context_menu_position = Some(pos); + state.clipboard_has_text = clipboard_has_text(clipboard); state.focused = true; state.keyboard_focused = false; shell.capture_event(); @@ -1023,6 +1026,13 @@ pub fn danger(theme: &Theme) -> Style { use crate::widget::tree::Tree as WidgetTree; +/// Returns `true` if the clipboard currently holds non-empty text. +pub fn clipboard_has_text(clipboard: &dyn Clipboard) -> bool { + clipboard + .read(crate::clipboard::Kind::Standard) + .is_some_and(|s| !s.is_empty()) +} + /// Implement this on a **widget** to enable context menu support for /// text selection (Copy, Select All, and optionally Cut / Paste) in libcosmic pub trait HasSelectableText { @@ -1032,11 +1042,23 @@ pub trait HasSelectableText { /// Selects all text. fn select_all(&self, tree: &mut WidgetTree); - /// Returns `true` if the widget is editable (enables Cut / Paste). + /// Returns `true` if the widget is editable (shows Cut / Paste). fn is_editable(&self) -> bool { false } + /// Returns `true` if the widget has any text (enables Select All). + fn has_text(&self, _tree: &WidgetTree) -> bool { + true + } + + /// Returns whether the clipboard held text when the context menu was + /// requested (enables Paste). Widgets cache this on right-click because + /// overlays have no clipboard access. + fn clipboard_has_text(&self, _tree: &WidgetTree) -> bool { + true + } + /// Returns `true` if the widget is currently focused. fn is_focused(&self, tree: &WidgetTree) -> bool; @@ -1106,6 +1128,16 @@ impl HasSelectableText sel.end = count; } + fn has_text(&self, tree: &WidgetTree) -> bool { + let state = tree.state.downcast_ref::>(); + !state.paragraph.content().is_empty() + } + + fn clipboard_has_text(&self, tree: &WidgetTree) -> bool { + let state = tree.state.downcast_ref::>(); + state.clipboard_has_text + } + fn is_focused(&self, tree: &WidgetTree) -> bool { let state = tree.state.downcast_ref::>(); state.is_focused() diff --git a/widget/src/text_editor.rs b/widget/src/text_editor.rs index 34a8825f..0681989b 100644 --- a/widget/src/text_editor.rs +++ b/widget/src/text_editor.rs @@ -545,6 +545,7 @@ pub struct State { highlighter_settings: Highlighter::Settings, highlighter_format_address: usize, context_menu_position: Option, + clipboard_has_text: bool, pending_edit: Option, } @@ -632,6 +633,7 @@ where highlighter_settings: self.highlighter_settings.clone(), highlighter_format_address: self.highlighter_format as usize, context_menu_position: None, + clipboard_has_text: false, pending_edit: None, }) } @@ -736,6 +738,8 @@ where state.focus = Some(Focus::now()); } state.context_menu_position = Some(pos); + state.clipboard_has_text = + widget::text::clipboard_has_text(clipboard); shell.capture_event(); return; } @@ -1649,6 +1653,16 @@ where self.on_edit.is_some() } + fn has_text(&self, _tree: &widget::Tree) -> bool { + !self.content.is_empty() + } + + fn clipboard_has_text(&self, tree: &widget::Tree) -> bool { + tree.state + .downcast_ref::>() + .clipboard_has_text + } + fn is_focused(&self, tree: &widget::Tree) -> bool { tree.state.downcast_ref::>().is_focused() } From 880f2c7565f719031cc53677000c9ba9f9d2117e Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Tue, 1 Sep 2026 23:18:45 -0400 Subject: [PATCH 81/93] improv: operation and select for directional navigation --- core/src/widget/operation.rs | 25 ++++++++++++++++++++- runtime/src/widget/selector.rs | 2 +- selector/src/find.rs | 12 ++++++++++ selector/src/lib.rs | 40 ++++++++++++++++++++++++++++++++++ widget/src/button.rs | 13 +++++++++-- widget/src/scrollable.rs | 16 +++++++------- winit/src/lib.rs | 2 ++ 7 files changed, 98 insertions(+), 12 deletions(-) diff --git a/core/src/widget/operation.rs b/core/src/widget/operation.rs index 40f01064..17948599 100644 --- a/core/src/widget/operation.rs +++ b/core/src/widget/operation.rs @@ -9,7 +9,7 @@ pub use scrollable::Scrollable; pub use text_input::TextInput; use crate::widget::Id; -use crate::{Rectangle, Vector}; +use crate::{Rectangle, Vector, window}; use std::any::Any; use std::fmt; @@ -75,6 +75,9 @@ pub trait Operation: Send { fn finish(&self) -> Outcome { Outcome::None } + + /// Track the active window id being processed if relevant to the operation + fn set_window_id(&mut self, _id: window::Id) {} } impl Operation for Box @@ -140,6 +143,10 @@ where fn finish(&self) -> Outcome { self.as_ref().finish() } + + fn set_window_id(&mut self, id: window::Id) { + self.as_mut().set_window_id(id); + } } /// The result of an [`Operation`]. @@ -243,6 +250,10 @@ where fn finish(&self) -> Outcome { Outcome::None } + + fn set_window_id(&mut self, id: window::Id) { + self.operation.set_window_id(id); + } } BlackBox { operation } @@ -410,6 +421,10 @@ where })), } } + + fn set_window_id(&mut self, id: window::Id) { + self.operation.set_window_id(id); + } } Map { @@ -515,6 +530,10 @@ where } } } + + fn set_window_id(&mut self, id: window::Id) { + self.operation.set_window_id(id); + } } Chain { @@ -566,6 +585,10 @@ pub fn scoped( outcome => outcome, } } + + fn set_window_id(&mut self, id: window::Id) { + self.operation.set_window_id(id); + } } ScopedOperation { diff --git a/runtime/src/widget/selector.rs b/runtime/src/widget/selector.rs index 77d4eb2d..82d7e838 100644 --- a/runtime/src/widget/selector.rs +++ b/runtime/src/widget/selector.rs @@ -1,6 +1,6 @@ //! Find and query widgets in your applications. pub use iced_selector::{ - Bounded, Candidate, Selector, Target, Text, id, is_focused, + Bounded, Candidate, Selector, Target, Text, focus, id, is_focused, }; use crate::Task; diff --git a/selector/src/find.rs b/selector/src/find.rs index cfdba7b3..06f85140 100644 --- a/selector/src/find.rs +++ b/selector/src/find.rs @@ -1,3 +1,5 @@ +use iced_core::window; + use crate::Selector; use crate::core::widget::operation::{ Focusable, Outcome, Scrollable, TextInput, @@ -100,6 +102,10 @@ where fn finish(&self) -> Self::Output { self.outputs.clone() } + + fn set_window_id(&mut self, id: window::Id) { + self.selector.set_window_id(id); + } } pub trait Strategy { @@ -110,6 +116,8 @@ pub trait Strategy { fn is_done(&self) -> bool; fn finish(&self) -> Self::Output; + + fn set_window_id(&mut self, _id: window::Id) {} } #[derive(Debug)] @@ -273,4 +281,8 @@ where fn finish(&self) -> Outcome { Outcome::Some(self.strategy.finish()) } + + fn set_window_id(&mut self, id: window::Id) { + self.strategy.set_window_id(id); + } } diff --git a/selector/src/lib.rs b/selector/src/lib.rs index 5c377276..99809a78 100644 --- a/selector/src/lib.rs +++ b/selector/src/lib.rs @@ -1,5 +1,6 @@ //! Select data from the widget tree. use iced_core as core; +use iced_core::window; mod find; mod target; @@ -48,6 +49,8 @@ pub trait Selector { { FindAll::new(find::All::new(self)) } + + fn set_window_id(&mut self, _id: window::Id) {} } impl Selector for &str { @@ -171,3 +174,40 @@ pub fn is_focused() -> impl Selector { IsFocused } + +/// Returns a [`Selector`] that matches widgets that are focusable. +pub fn focus() -> impl Selector { + struct Focus { + cur_window_id: window::Id, + } + + impl Selector for Focus { + type Output = (bool, Target, window::Id); + + fn select(&mut self, candidate: Candidate<'_>) -> Option { + if let Candidate::Focusable { state, .. } = candidate { + Some(( + state.is_focused(), + Target::from(candidate), + self.cur_window_id, + )) + } else if matches!(candidate, Candidate::Scrollable { .. }) { + Some((false, Target::from(candidate), self.cur_window_id)) + } else { + None + } + } + + fn description(&self) -> String { + "is focusable and focused".to_owned() + } + + fn set_window_id(&mut self, id: iced_core::window::Id) { + self.cur_window_id = id; + } + } + + Focus { + cur_window_id: window::Id::NONE, + } +} diff --git a/widget/src/button.rs b/widget/src/button.rs index f137221e..a99dd9e2 100644 --- a/widget/src/button.rs +++ b/widget/src/button.rs @@ -267,6 +267,7 @@ struct State { is_hovered: bool, is_pressed: bool, is_focused: bool, + needs_redraw: bool, } impl<'a, Message, Theme, Renderer> Widget @@ -368,6 +369,12 @@ where viewport, ); + let state = tree.state.downcast_mut::(); + if state.needs_redraw { + state.needs_redraw = false; + shell.request_redraw(); + } + if shell.is_event_captured() { return; } @@ -777,11 +784,11 @@ impl Default for Style { /// /// impl Catalog for MyTheme { /// type Class<'a> = ButtonClass; -/// +/// /// fn default<'a>() -> Self::Class<'a> { /// ButtonClass::default() /// } -/// +/// /// /// fn style(&self, class: &Self::Class<'_>, status: Status) -> Style { /// let mut style = Style::default(); @@ -1000,10 +1007,12 @@ impl operation::Focusable for State { } fn focus(&mut self) { + self.needs_redraw |= !self.is_focused; self.is_focused = true; } fn unfocus(&mut self) { + self.needs_redraw |= self.is_focused; self.is_focused = false; } } diff --git a/widget/src/scrollable.rs b/widget/src/scrollable.rs index 61a18bd5..8065bb8a 100644 --- a/widget/src/scrollable.rs +++ b/widget/src/scrollable.rs @@ -676,14 +676,6 @@ where let translation = state.translation(self.direction, bounds, content_bounds); - operation.scrollable( - Some(&self.id), - bounds, - content_bounds, - translation, - state, - ); - operation.traverse(&mut |operation| { self.content.as_widget_mut().operate( &mut tree.children[0], @@ -696,6 +688,14 @@ where operation, ); }); + // XXX must be done after traversing to perform DFS + operation.scrollable( + Some(&self.id), + bounds, + content_bounds, + translation, + state, + ); } fn update( diff --git a/winit/src/lib.rs b/winit/src/lib.rs index 21a2b38f..791bacff 100644 --- a/winit/src/lib.rs +++ b/winit/src/lib.rs @@ -2519,6 +2519,8 @@ where while let Some(mut operation) = current_operation.take() { for (id, ui) in interfaces.iter_mut() { if let Some(window) = window_manager.get_mut(*id) { + operation.as_mut().set_window_id(*id); + ui.operate(&window.renderer, operation.as_mut()); } } From 2e12eba5cd9ddf9995e113fbc9fa0ebf8f0f0f97 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Fri, 4 Sep 2026 14:31:46 -0400 Subject: [PATCH 82/93] improv: PreOperation for tracking children in selections --- core/src/widget/operation.rs | 27 +++++++++++++++++++++++++++ selector/src/find.rs | 4 ++++ selector/src/lib.rs | 2 ++ selector/src/target.rs | 15 ++++++++++++++- widget/src/scrollable.rs | 2 ++ 5 files changed, 49 insertions(+), 1 deletion(-) diff --git a/core/src/widget/operation.rs b/core/src/widget/operation.rs index 17948599..ff0c920d 100644 --- a/core/src/widget/operation.rs +++ b/core/src/widget/operation.rs @@ -78,6 +78,9 @@ pub trait Operation: Send { /// Track the active window id being processed if relevant to the operation fn set_window_id(&mut self, _id: window::Id) {} + + /// Used to mark the beginning of operations for a widget and its children + fn pre_operation(&mut self, _id: Option<&Id>) {} } impl Operation for Box @@ -147,6 +150,10 @@ where fn set_window_id(&mut self, id: window::Id) { self.as_mut().set_window_id(id); } + + fn pre_operation(&mut self, id: Option<&Id>) { + self.as_mut().pre_operation(id); + } } /// The result of an [`Operation`]. @@ -251,6 +258,10 @@ where Outcome::None } + fn pre_operation(&mut self, id: Option<&Id>) { + self.operation.pre_operation(id); + } + fn set_window_id(&mut self, id: window::Id) { self.operation.set_window_id(id); } @@ -352,6 +363,10 @@ where ) { self.operation.custom(id, bounds, state); } + + fn pre_operation(&mut self, id: Option<&Id>) { + self.operation.pre_operation(id); + } } self.operation.traverse(&mut |operation| { @@ -425,6 +440,10 @@ where fn set_window_id(&mut self, id: window::Id) { self.operation.set_window_id(id); } + + fn pre_operation(&mut self, id: Option<&Id>) { + self.operation.pre_operation(id); + } } Map { @@ -534,6 +553,10 @@ where fn set_window_id(&mut self, id: window::Id) { self.operation.set_window_id(id); } + + fn pre_operation(&mut self, id: Option<&Id>) { + self.operation.pre_operation(id); + } } Chain { @@ -586,6 +609,10 @@ pub fn scoped( } } + fn pre_operation(&mut self, id: Option<&Id>) { + self.operation.pre_operation(id); + } + fn set_window_id(&mut self, id: window::Id) { self.operation.set_window_id(id); } diff --git a/selector/src/find.rs b/selector/src/find.rs index 06f85140..e4b01e66 100644 --- a/selector/src/find.rs +++ b/selector/src/find.rs @@ -285,4 +285,8 @@ where fn set_window_id(&mut self, id: window::Id) { self.strategy.set_window_id(id); } + + fn pre_operation(&mut self, id: Option<&Id>) { + self.strategy.feed(Candidate::PreOperation { id }); + } } diff --git a/selector/src/lib.rs b/selector/src/lib.rs index 99809a78..e07d9262 100644 --- a/selector/src/lib.rs +++ b/selector/src/lib.rs @@ -193,6 +193,8 @@ pub fn focus() -> impl Selector { )) } else if matches!(candidate, Candidate::Scrollable { .. }) { Some((false, Target::from(candidate), self.cur_window_id)) + } else if matches!(candidate, Candidate::PreOperation { .. }) { + Some((false, Target::from(candidate), self.cur_window_id)) } else { None } diff --git a/selector/src/target.rs b/selector/src/target.rs index d2d20651..5aa29920 100644 --- a/selector/src/target.rs +++ b/selector/src/target.rs @@ -42,6 +42,9 @@ pub enum Target { bounds: Rectangle, visible_bounds: Option, }, + PreOperation { + id: Option, + }, } impl Target { @@ -54,6 +57,7 @@ impl Target { | Target::TextInput { bounds, .. } | Target::Text { bounds, .. } | Target::Custom { bounds, .. } => *bounds, + Target::PreOperation { .. } => Rectangle::default(), } } @@ -66,6 +70,7 @@ impl Target { | Target::TextInput { visible_bounds, .. } | Target::Text { visible_bounds, .. } | Target::Custom { visible_bounds, .. } => *visible_bounds, + Target::PreOperation { .. } => None, } } } @@ -138,6 +143,9 @@ impl From> for Target { bounds, visible_bounds, }, + Candidate::PreOperation { id } => { + Self::PreOperation { id: id.cloned() } + } } } } @@ -195,6 +203,8 @@ pub enum Candidate<'a> { visible_bounds: Option, state: &'a dyn Any, }, + /// Used to mark the beginning of operations for a widget and its children + PreOperation { id: Option<&'a Id> }, } impl<'a> Candidate<'a> { @@ -206,7 +216,8 @@ impl<'a> Candidate<'a> { | Candidate::Scrollable { id, .. } | Candidate::TextInput { id, .. } | Candidate::Text { id, .. } - | Candidate::Custom { id, .. } => *id, + | Candidate::Custom { id, .. } + | Candidate::PreOperation { id } => *id, } } @@ -219,6 +230,7 @@ impl<'a> Candidate<'a> { | Candidate::TextInput { bounds, .. } | Candidate::Text { bounds, .. } | Candidate::Custom { bounds, .. } => *bounds, + Candidate::PreOperation { .. } => Rectangle::default(), } } @@ -231,6 +243,7 @@ impl<'a> Candidate<'a> { | Candidate::TextInput { visible_bounds, .. } | Candidate::Text { visible_bounds, .. } | Candidate::Custom { visible_bounds, .. } => *visible_bounds, + Candidate::PreOperation { .. } => None, } } } diff --git a/widget/src/scrollable.rs b/widget/src/scrollable.rs index 8065bb8a..43782ea7 100644 --- a/widget/src/scrollable.rs +++ b/widget/src/scrollable.rs @@ -676,6 +676,8 @@ where let translation = state.translation(self.direction, bounds, content_bounds); + operation.pre_operation(Some(&self.id)); + operation.traverse(&mut |operation| { self.content.as_widget_mut().operate( &mut tree.children[0], From 9ef36c9604c8eb1d34a4e4f9df438a1da0f9e8a2 Mon Sep 17 00:00:00 2001 From: Hojjat Date: Fri, 11 Sep 2026 11:29:04 -0600 Subject: [PATCH 83/93] feat(text): add selected_text_color to the text style --- core/src/widget/text.rs | 91 ++++++++++++++++++++++++++--------------- 1 file changed, 58 insertions(+), 33 deletions(-) diff --git a/core/src/widget/text.rs b/core/src/widget/text.rs index c57fadbb..e57df01d 100644 --- a/core/src/widget/text.rs +++ b/core/src/widget/text.rs @@ -379,45 +379,65 @@ where let style = theme.style(&self.class); let bounds = layout.bounds(); let paragraph = state.paragraph.raw(); - if let Some(sel) = &state.selection { - let left = sel.anchor.min(sel.end); - let right = sel.anchor.max(sel.end); - let content: &str = self.fragment.as_ref(); + let anchor = bounds.anchor( + paragraph.min_bounds(), + paragraph.align_x(), + paragraph.align_y(), + ); - if left != right { - let lo_byte = grapheme_to_byte(content, left); - let hi_byte = grapheme_to_byte(content, right); + let rects: Vec = state + .selection + .as_ref() + .filter(|sel| sel.anchor != sel.end) + .map(|sel| { + let content: &str = self.fragment.as_ref(); + let lo_byte = + grapheme_to_byte(content, sel.anchor.min(sel.end)); + let hi_byte = + grapheme_to_byte(content, sel.anchor.max(sel.end)); - let anchor = bounds.anchor( - paragraph.min_bounds(), - paragraph.align_x(), - paragraph.align_y(), + paragraph + .highlight( + 0, + (lo_byte, text::Affinity::After), + (hi_byte, text::Affinity::Before), + ) + .into_iter() + .map(|r| Rectangle { + x: anchor.x + r.x, + y: anchor.y + r.y, + width: r.width, + height: r.height, + }) + .collect() + }) + .unwrap_or_default(); + + let fill_selection = |renderer: &mut Renderer| { + for r in &rects { + renderer.fill_quad( + renderer::Quad { + bounds: *r, + ..renderer::Quad::default() + }, + style.selected_fill, ); + } + }; - let rects = paragraph.highlight( - 0, - (lo_byte, text::Affinity::After), - (hi_byte, text::Affinity::Before), - ); - - for r in rects { - renderer.fill_quad( - renderer::Quad { - bounds: Rectangle { - x: anchor.x + r.x, - y: anchor.y + r.y, - width: r.width, - height: r.height, - }, - ..renderer::Quad::default() - }, - style.selected_fill, - ); - } + if style.selected_text_color.is_none() { + fill_selection(renderer); + } + draw(renderer, defaults, bounds, paragraph, style, viewport); + if let Some(color) = style.selected_text_color { + fill_selection(renderer); + for r in &rects { + renderer.with_layer(*r, |renderer| { + renderer + .fill_paragraph(paragraph, anchor, color, *viewport); + }); } } - - draw(renderer, defaults, bounds, paragraph, style, viewport); } fn update( @@ -931,6 +951,10 @@ pub struct Style { pub color: Option, /// The fill [`Color`] of the selection highlight. pub selected_fill: Color, + /// The [`Color`] of selected text. + /// + /// The default, `None`, keeps the regular text color. + pub selected_text_color: Option, } impl Default for Style { @@ -938,6 +962,7 @@ impl Default for Style { Self { color: None, selected_fill: DEFAULT_SELECTION_COLOR, + selected_text_color: None, } } } From 87e1787fbb9b924576e6f6ea2ef2f45d0729e63d Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Tue, 8 Sep 2026 14:10:18 -0700 Subject: [PATCH 84/93] `cosmic-session-lock-layer-v1` protocol --- Cargo.lock | 188 +++++++++--------- Cargo.toml | 2 +- .../wayland/layer_surface.rs | 10 + .../wayland/commands/layer_surface.rs | 11 + .../wayland/event_loop/mod.rs | 1 + .../wayland/event_loop/state.rs | 17 ++ 6 files changed, 134 insertions(+), 95 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c28424ee..4bb792f8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -170,7 +170,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f2a1bb052857d5dd49572219344a7332b31b76405648eabac5bc68978251bcd" dependencies = [ "android-properties", - "bitflags 2.11.0", + "bitflags 2.13.2", "cc", "jni 0.22.4", "libc", @@ -712,9 +712,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.11.0" +version = "2.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" +checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06" [[package]] name = "bitstream-io" @@ -856,7 +856,7 @@ version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fba7adb4dd5aa98e5553510223000e7148f621165ec5f9acd7113f6ca4995298" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "log", "polling", "rustix 0.38.44", @@ -870,7 +870,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "log", "polling", "rustix 0.38.44", @@ -884,7 +884,7 @@ version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dbf9978365bac10f54d1d4b04f7ce4427e51f71d61f2fe15e3fed5166474df7" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "polling", "rustix 1.1.4", "slab", @@ -1275,7 +1275,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "core-foundation 0.10.1", "libc", ] @@ -1301,9 +1301,9 @@ dependencies = [ [[package]] name = "cosmic-client-toolkit" version = "0.2.0" -source = "git+https://github.com/pop-os/cosmic-protocols?rev=32283d7#32283d76a8d0342da74c4cc022a533c52dcf378f" +source = "git+https://github.com/pop-os/cosmic-protocols?rev=c0cff4d#c0cff4db14c37ed954983158e4055aa94c7741d9" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "cosmic-protocols", "libc", "smithay-client-toolkit 0.20.0", @@ -1314,9 +1314,9 @@ dependencies = [ [[package]] name = "cosmic-protocols" version = "0.2.0" -source = "git+https://github.com/pop-os/cosmic-protocols?rev=32283d7#32283d76a8d0342da74c4cc022a533c52dcf378f" +source = "git+https://github.com/pop-os/cosmic-protocols?rev=c0cff4d#c0cff4db14c37ed954983158e4055aa94c7741d9" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "wayland-backend", "wayland-client", "wayland-protocols 0.32.12", @@ -1331,7 +1331,7 @@ version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be17b688510d934ce13f48a2beba700e11583e281e0fda99c22bb256a14eda73" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "fontdb", "harfrust", "linebender_resource_handle", @@ -1575,7 +1575,7 @@ dependencies = [ "libc", "option-ext", "redox_users 0.5.2", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -1601,7 +1601,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "block2 0.6.2", "libc", "objc2 0.6.4", @@ -1632,7 +1632,7 @@ name = "dnd" version = "0.1.0" source = "git+https://github.com/pop-os/window_clipboard.git?tag=sctk-0.20#f68595ee0e62fbd6589f4709b5aaa5c3c7ea5f6c" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "mime 0.1.0", "raw-window-handle", "smithay-client-toolkit 0.20.0", @@ -1673,7 +1673,7 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0f8a69e60d75ae7dab4ef26a59ca99f2a89d4c142089b537775ae0c198bdcde" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "bytemuck", "drm-ffi", "drm-fourcc", @@ -1803,7 +1803,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -2335,7 +2335,7 @@ version = "0.20.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffc4b6e352d4716d84d7dde562dd9aee2a7d48beb872dd9ece7f2d1515b2d683" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "futures-channel", "futures-core", "futures-executor", @@ -2437,7 +2437,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b89c83349105e3732062a895becfc71a8f921bb71ecbbdd8ff99263e3b53a0ca" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "gpu-descriptor-types", "hashbrown 0.15.5", ] @@ -2448,7 +2448,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", ] [[package]] @@ -2674,7 +2674,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9da2e5ae821f6e96664977bf974d6d6a2d6682f9ccee23e62ec1d134246845f9" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "bytemuck", "core_maths", "read-fonts", @@ -3015,7 +3015,7 @@ name = "iced_core" version = "0.14.0" dependencies = [ "approx", - "bitflags 2.11.0", + "bitflags 2.13.2", "build_helpers", "bytes", "cosmic-client-toolkit", @@ -3076,7 +3076,7 @@ dependencies = [ name = "iced_graphics" version = "0.14.0" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "bytemuck", "cosmic-text", "half", @@ -3190,7 +3190,7 @@ name = "iced_wgpu" version = "0.14.0" dependencies = [ "as-raw-xcb-connection", - "bitflags 2.11.0", + "bitflags 2.13.2", "build_helpers", "bytemuck", "cosmic-client-toolkit", @@ -3484,7 +3484,7 @@ checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" dependencies = [ "hermit-abi", "libc", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -3542,7 +3542,7 @@ dependencies = [ "portable-atomic", "portable-atomic-util", "serde_core", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -3682,7 +3682,7 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fbe853b403ae61a04233030ae8a79d94975281ed9770a1f9e246732b534b28d" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "serde", ] @@ -3803,7 +3803,7 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "libc", "plain", "redox_syscall 0.7.4", @@ -4055,7 +4055,7 @@ version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7047791b5bc903b8cd963014b355f71dc9864a9a0b727057676c1dcae5cbc15" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "block", "core-graphics-types 0.2.0", "foreign-types 0.5.0", @@ -4205,7 +4205,7 @@ checksum = "618f667225063219ddfc61251087db8a9aec3c3f0950c916b614e403486f1135" dependencies = [ "arrayvec", "bit-set", - "bitflags 2.11.0", + "bitflags 2.13.2", "cfg-if", "cfg_aliases", "codespan-reporting", @@ -4246,7 +4246,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "jni-sys 0.3.1", "log", "ndk-sys", @@ -4306,7 +4306,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -4439,7 +4439,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "block2 0.5.1", "libc", "objc2 0.5.2", @@ -4455,7 +4455,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "block2 0.6.2", "libc", "objc2 0.6.4", @@ -4476,7 +4476,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73ad74d880bb43877038da939b7427bba67e9dd42004a18b809ba7d87cee241c" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "objc2 0.6.4", "objc2-foundation 0.3.2", ] @@ -4487,7 +4487,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -4499,7 +4499,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b402a653efbb5e82ce4df10683b6b28027616a2715e90009947d50b8dd298fa" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "objc2 0.6.4", "objc2-foundation 0.3.2", ] @@ -4510,7 +4510,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "block2 0.6.2", "dispatch2", "objc2 0.6.4", @@ -4522,7 +4522,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "dispatch2", "libc", "objc2 0.6.4", @@ -4558,7 +4558,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "objc2 0.6.4", "objc2-core-foundation", "objc2-core-graphics", @@ -4570,7 +4570,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d425caf1df73233f29fd8a5c3e5edbc30d2d4307870f802d18f00d83dc5141a6" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "objc2 0.6.4", "objc2-core-foundation", "objc2-core-graphics", @@ -4589,7 +4589,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "block2 0.5.1", "libc", "objc2 0.5.2", @@ -4601,7 +4601,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "block2 0.6.2", "libc", "objc2 0.6.4", @@ -4614,7 +4614,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "objc2 0.6.4", "objc2-core-foundation", ] @@ -4625,7 +4625,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -4637,7 +4637,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -4650,7 +4650,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "objc2 0.6.4", "objc2-foundation 0.3.2", ] @@ -4661,7 +4661,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "objc2 0.6.4", "objc2-core-foundation", "objc2-foundation 0.3.2", @@ -4705,7 +4705,7 @@ version = "0.10.76" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "951c002c75e16ea2c65b8c7e4d3d51d5530d8dfa7d060b4776828c88cfb18ecf" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "cfg-if", "foreign-types 0.3.2", "libc", @@ -5074,7 +5074,7 @@ version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "crc32fast", "fdeflate", "flate2", @@ -5231,7 +5231,7 @@ version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f86ba2052aebccc42cbbb3ed234b8b13ce76f75c3551a303cb2bcffcff12bb14" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "getopts", "memchr", "pulldown-cmark-escape", @@ -5499,7 +5499,7 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", ] [[package]] @@ -5508,7 +5508,7 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f450ad9c3b1da563fb6948a8e0fb0fb9269711c9c73d9ea1de5058c79c8d643a" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", ] [[package]] @@ -5708,7 +5708,7 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "errno", "libc", "linux-raw-sys 0.4.15", @@ -5721,11 +5721,11 @@ version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "errno", "libc", "linux-raw-sys 0.12.1", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -5798,7 +5798,7 @@ version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd3c7c96f8a08ee34eff8857b11b49b07d71d1c3f4e88f8a88d4c9e9f90b1702" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "bytemuck", "core_maths", "log", @@ -5971,7 +5971,7 @@ version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "core-foundation 0.10.1", "core-foundation-sys", "libc", @@ -6233,7 +6233,7 @@ name = "smithay-client-toolkit" version = "0.18.0" source = "git+https://github.com/smithay/client-toolkit?rev=828b1eb#828b1eb469ad022eb3ac30be02bd5645b879922f" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "bytemuck", "calloop 0.12.4", "calloop-wayland-source 0.2.0", @@ -6261,7 +6261,7 @@ version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0512da38f5e2b31201a93524adb8d3136276fa4fe4aafab4e1f727a82b534cc0" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "bytemuck", "calloop 0.14.4", "calloop-wayland-source 0.4.1", @@ -6340,7 +6340,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -6394,7 +6394,7 @@ version = "0.3.0+sdk-1.3.268.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", ] [[package]] @@ -6583,7 +6583,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "core-foundation 0.9.4", "system-configuration-sys", ] @@ -6634,7 +6634,7 @@ dependencies = [ "getrandom 0.4.2", "once_cell", "rustix 1.1.4", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -7030,7 +7030,7 @@ version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "bytes", "futures-util", "http 1.4.0", @@ -7173,7 +7173,7 @@ checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e" dependencies = [ "memoffset", "tempfile", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -7562,7 +7562,7 @@ version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "hashbrown 0.15.5", "indexmap", "semver", @@ -7602,7 +7602,7 @@ version = "0.31.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "645c7c96bb74690c3189b5c9cb4ca1627062bb23693a4fad9d8c3de958260144" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "rustix 1.1.4", "wayland-backend", "wayland-scanner", @@ -7614,7 +7614,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "cursor-icon", "wayland-backend", ] @@ -7636,7 +7636,7 @@ version = "0.31.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f81f365b8b4a97f422ac0e8737c438024b5951734506b0e1d775c73030561f4" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "wayland-backend", "wayland-client", "wayland-scanner", @@ -7648,7 +7648,7 @@ version = "0.32.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "563a85523cade2429938e790815fd7319062103b9f4a2dc806e9b53b95982d8f" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "wayland-backend", "wayland-client", "wayland-scanner", @@ -7661,7 +7661,7 @@ version = "20250721.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40a1f863128dcaaec790d7b4b396cc9b9a7a079e878e18c47e6c2d2c5a8dcbb1" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "wayland-backend", "wayland-client", "wayland-protocols 0.32.12", @@ -7674,7 +7674,7 @@ version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e9567599ef23e09b8dad6e429e5738d4509dfc46b3b21f32841a304d16b29c8" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "wayland-backend", "wayland-client", "wayland-protocols 0.32.12", @@ -7687,7 +7687,7 @@ version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b6d8cf1eb2c1c31ed1f5643c88a6e53538129d4af80030c8cabd1f9fa884d91" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "wayland-backend", "wayland-client", "wayland-protocols 0.32.12", @@ -7700,7 +7700,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad1f61b76b6c2d8742e10f9ba5c3737f6530b4c243132c2a2ccc8aa96fe25cd6" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "wayland-backend", "wayland-client", "wayland-protocols 0.31.2", @@ -7713,7 +7713,7 @@ version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb04e52f7836d7c7976c78ca0250d61e33873c34156a2a1fc9474828ec268234" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "wayland-backend", "wayland-client", "wayland-protocols 0.32.12", @@ -7738,7 +7738,7 @@ version = "0.31.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc1846eb04c49182e04f4a099e2a830a2b745610bbc1d61246e206f29c7000a0" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "downcast-rs", "rustix 1.1.4", "wayland-backend", @@ -7834,7 +7834,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9cb534d5ffd109c7d1135f34cdae29e60eab94855a625dcfe1705f8bc7ad79f" dependencies = [ "arrayvec", - "bitflags 2.11.0", + "bitflags 2.13.2", "bytemuck", "cfg-if", "cfg_aliases", @@ -7866,7 +7866,7 @@ dependencies = [ "arrayvec", "bit-set", "bit-vec", - "bitflags 2.11.0", + "bitflags 2.13.2", "bytemuck", "cfg_aliases", "document-features", @@ -7936,7 +7936,7 @@ dependencies = [ "arrayvec", "ash", "bit-set", - "bitflags 2.11.0", + "bitflags 2.13.2", "block", "bytemuck", "cfg-if", @@ -7980,7 +7980,7 @@ version = "28.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e18308757e594ed2cd27dddbb16a139c42a683819d32a2e0b1b0167552f5840c" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "bytemuck", "js-sys", "log", @@ -8009,7 +8009,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -8532,7 +8532,7 @@ name = "winit" version = "0.31.0-beta.2" source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "cfg_aliases", "cursor-icon", "dpi", @@ -8559,7 +8559,7 @@ version = "0.31.0-beta.2" source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" dependencies = [ "android-activity", - "bitflags 2.11.0", + "bitflags 2.13.2", "dpi", "ndk", "raw-window-handle", @@ -8573,7 +8573,7 @@ name = "winit-appkit" version = "0.31.0-beta.2" source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "block2 0.6.2", "dispatch2", "dpi", @@ -8610,7 +8610,7 @@ name = "winit-core" version = "0.31.0-beta.2" source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "cursor-icon", "dpi", "keyboard-types", @@ -8624,7 +8624,7 @@ name = "winit-orbital" version = "0.31.0-beta.2" source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "dpi", "libredox", "orbclient", @@ -8640,7 +8640,7 @@ name = "winit-uikit" version = "0.31.0-beta.2" source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "block2 0.6.2", "dispatch2", "dpi", @@ -8661,7 +8661,7 @@ version = "0.31.0-beta.2" source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" dependencies = [ "ahash", - "bitflags 2.11.0", + "bitflags 2.13.2", "calloop 0.14.4", "cursor-icon", "dpi", @@ -8687,7 +8687,7 @@ version = "0.31.0-beta.2" source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" dependencies = [ "atomic-waker", - "bitflags 2.11.0", + "bitflags 2.13.2", "concurrent-queue", "cursor-icon", "dpi", @@ -8708,7 +8708,7 @@ name = "winit-win32" version = "0.31.0-beta.2" source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "cursor-icon", "dpi", "raw-window-handle", @@ -8724,7 +8724,7 @@ name = "winit-x11" version = "0.31.0-beta.2" source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "bytemuck", "calloop 0.14.4", "cursor-icon", @@ -8818,7 +8818,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" dependencies = [ "anyhow", - "bitflags 2.11.0", + "bitflags 2.13.2", "indexmap", "log", "serde", @@ -8921,7 +8921,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "dlib", "log", "once_cell", diff --git a/Cargo.toml b/Cargo.toml index 27ac2ca0..cf5abcbe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -278,7 +278,7 @@ tiny-skia = { version = "0.11", default-features = false, features = [ "std", "simd", ] } -cctk = { git = "https://github.com/pop-os/cosmic-protocols", package = "cosmic-client-toolkit", rev = "32283d7" } +cctk = { git = "https://github.com/pop-os/cosmic-protocols", package = "cosmic-client-toolkit", rev = "c0cff4d" } softbuffer = { git = "https://github.com/pop-os/softbuffer", tag = "cosmic-4.0" } syntect = "5.2" tokio = "1.0" diff --git a/runtime/src/platform_specific/wayland/layer_surface.rs b/runtime/src/platform_specific/wayland/layer_surface.rs index 6e5f3e9e..60e44caf 100644 --- a/runtime/src/platform_specific/wayland/layer_surface.rs +++ b/runtime/src/platform_specific/wayland/layer_surface.rs @@ -157,6 +157,11 @@ pub enum Action { /// padding of the surface geometry padding: IcedMargin, }, + ShowOnLock { + /// id of the layer surface + id: Id, + value: bool, + } } impl fmt::Debug for Action { @@ -215,6 +220,11 @@ impl fmt::Debug for Action { "Action::LayerSurfaceAction::Padding {{ id: {:#?}, padding: {:?} }}", id, padding ), + Action::ShowOnLock { id, value } => write!( + f, + "Action::LayerSurfaceAction::ShowOnLock {{ id: {:#?}, value: {:?} }}", + id, value + ), } } } diff --git a/winit/src/platform_specific/wayland/commands/layer_surface.rs b/winit/src/platform_specific/wayland/commands/layer_surface.rs index 5d8a4588..e7bbb3b5 100644 --- a/winit/src/platform_specific/wayland/commands/layer_surface.rs +++ b/winit/src/platform_specific/wayland/commands/layer_surface.rs @@ -138,3 +138,14 @@ pub fn set_input_zone( )), )) } + +pub fn set_show_on_lock( + id: SurfaceId, + value: bool, +) -> Task { + task::effect(Action::PlatformSpecific( + platform_specific::Action::Wayland(wayland::Action::LayerSurface( + wayland::layer_surface::Action::ShowOnLock { id, value }, + )), + )) +} diff --git a/winit/src/platform_specific/wayland/event_loop/mod.rs b/winit/src/platform_specific/wayland/event_loop/mod.rs index 1926e391..02f7eae7 100644 --- a/winit/src/platform_specific/wayland/event_loop/mod.rs +++ b/winit/src/platform_specific/wayland/event_loop/mod.rs @@ -392,6 +392,7 @@ impl SctkEventLoop { ).ok(), text_input_manager: TextInputManager::try_new(®istry_state, &qh), ext_background_effect_manager: ext_background_effect::ExtBackgroundEffectManager::new(&globals, &qh).ok(), + cosmic_session_lock_layer_manager: registry_state.bind_one(&qh, 1..=1, ()).ok(), registry_state, queue_handle: qh, diff --git a/winit/src/platform_specific/wayland/event_loop/state.rs b/winit/src/platform_specific/wayland/event_loop/state.rs index 80914ffb..e408159f 100644 --- a/winit/src/platform_specific/wayland/event_loop/state.rs +++ b/winit/src/platform_specific/wayland/event_loop/state.rs @@ -44,6 +44,7 @@ use cctk::{ cosmic_protocols::{ corner_radius::v1::client::cosmic_corner_radius_manager_v1::CosmicCornerRadiusManagerV1, overlap_notify::v1::client::zcosmic_overlap_notification_v1::ZcosmicOverlapNotificationV1, + session_lock_layer::v1::client::cosmic_session_lock_layer_manager_v1::CosmicSessionLockLayerManagerV1, }, sctk::{ activation::{ActivationState, RequestData}, @@ -477,6 +478,7 @@ pub struct SctkState { pub(crate) toplevel_manager: Option, pub(crate) subsurface_state: Option, pub(crate) ext_background_effect_manager: Option, + pub(crate) cosmic_session_lock_layer_manager: Option, pub(crate) activation_token_ctr: u32, pub(crate) token_senders: HashMap>>, @@ -1266,6 +1268,20 @@ impl SctkState { } } }, + platform_specific::wayland::layer_surface::Action::ShowOnLock { id, value } => { + if let Some(layer_surface) = self.layer_surfaces.iter_mut().find(|l| l.id == id) { + if let SurfaceKind::Wlr(wlr) = layer_surface.surface.kind() { + if let Some(manager) = &self.cosmic_session_lock_layer_manager { + if value { + manager.set_show_on_lock(wlr); + } else { + manager.unset_show_on_lock(wlr); + } + _ = self.to_commit.insert(id, layer_surface.surface.wl_surface().clone()); + } + } + } + } }, Action::Popup(action) => { match action { @@ -2165,3 +2181,4 @@ pub(crate) fn send_event( delegate_noop!(SctkState: ignore WlSubsurface); delegate_noop!(SctkState: ignore WlRegion); +delegate_noop!(SctkState: CosmicSessionLockLayerManagerV1); From 5fc4372d877ad2ca6eaab1c0ca5e424f238b9258 Mon Sep 17 00:00:00 2001 From: Hojjat Date: Fri, 11 Sep 2026 18:29:31 -0600 Subject: [PATCH 85/93] fix: do not report unfocused if focus moved to surface's own popup --- .../wayland/event_loop/mod.rs | 1 + .../wayland/event_loop/state.rs | 68 ++++++++++++++++++- .../wayland/handlers/seat/keyboard.rs | 39 ++++++++++- 3 files changed, 103 insertions(+), 5 deletions(-) diff --git a/winit/src/platform_specific/wayland/event_loop/mod.rs b/winit/src/platform_specific/wayland/event_loop/mod.rs index 02f7eae7..01bd7514 100644 --- a/winit/src/platform_specific/wayland/event_loop/mod.rs +++ b/winit/src/platform_specific/wayland/event_loop/mod.rs @@ -412,6 +412,7 @@ impl SctkEventLoop { lock_surfaces: Vec::new(), subsurfaces: Vec::new(), touch_points: HashMap::new(), + kbd_leave_to_own_popup: HashSet::new(), sctk_events: Vec::new(), frame_status: HashMap::new(), cursor_requests: HashMap::new(), diff --git a/winit/src/platform_specific/wayland/event_loop/state.rs b/winit/src/platform_specific/wayland/event_loop/state.rs index e408159f..7b1f65c0 100644 --- a/winit/src/platform_specific/wayland/event_loop/state.rs +++ b/winit/src/platform_specific/wayland/event_loop/state.rs @@ -435,6 +435,9 @@ pub struct SctkState { pub(crate) blur_surfaces: HashMap, pub(crate) corner_radii: HashMap)>, pub(crate) touch_points: HashMap, + /// List of layer surfaces whose keyboard leave was ignored because focus moved + /// to one of their own grabbing popups. Their next enter is swallowed too. + pub(crate) kbd_leave_to_own_popup: HashSet, /// Window updates, which are coming from SCTK or the compositor, which require /// calling back to the sctk's downstream. They are handled right in the event loop, @@ -681,6 +684,33 @@ impl SctkState { // TODO winit sets cursor size after handling the change for the window, so maybe that should be done as well. } + /// Popups can only be attached to xdg or layer surfaces. So for subsurfaces, we return the + /// parent, and adjust the offset. + pub(crate) fn subsurface_popup_parent( + &self, + id: core::window::Id, + ) -> Option<(WlSurface, (i32, i32))> { + let mut sub = self.subsurfaces.iter().find(|s| s.id == id)?; + let mut offset = (0, 0); + // bounded by the number of subsurfaces so a corrupt chain cannot spin forever + for _ in 0..=self.subsurfaces.len() { + if let Some(b) = sub.instance.bounds { + offset.0 += b.x as i32; + offset.1 += b.y as i32; + } + let parent = &sub.instance.parent; + match self + .subsurfaces + .iter() + .find(|s| s.instance.wl_surface == *parent) + { + Some(s) => sub = s, + None => return Some((parent.clone(), offset)), + } + } + None + } + pub fn get_popup( &mut self, settings: SctkPopupSettings, @@ -725,6 +755,27 @@ impl SctkState { PopupParent::Popup(parent.popup.wl_surface().clone()), parent.data.toplevel.clone(), ) + } else if let Some((surface, _)) = + self.subsurface_popup_parent(settings.parent) + { + if self + .layer_surfaces + .iter() + .any(|l| *l.surface.wl_surface() == surface) + { + (PopupParent::LayerSurface(surface.clone()), surface) + } else if self + .windows + .iter() + .any(|w| w.wl_surface(&self.connection) == surface) + { + (PopupParent::Window(surface.clone()), surface) + } else if let Some(p) = self.popmgr.popup(&surface) { + (PopupParent::Popup(surface), p.data.toplevel.clone()) + } else { + // e.g. a session lock surface, which cannot parent xdg popups + return Err(PopupCreationError::ParentMissing); + } } else { return Err(PopupCreationError::ParentMissing); }; @@ -1158,6 +1209,7 @@ impl SctkState { } if let Some(i) = self.layer_surfaces.iter().position(|l| l.id == id) { let l = self.layer_surfaces.remove(i); + _ = self.kbd_leave_to_own_popup.remove(&l.surface.wl_surface().id()); if let Some(blurred) = self.blur_surfaces.remove(&l.id) { blurred.destroy(); @@ -1285,13 +1337,19 @@ impl SctkState { }, Action::Popup(action) => { match action { - platform_specific::wayland::popup::Action::Popup { popup: settings } => { + platform_specific::wayland::popup::Action::Popup { popup: mut settings } => { + // anchor rects from widgets inside a subsurface are in that subsurface's coordinates + if let Some((_, (dx, dy))) = self.subsurface_popup_parent(settings.parent) { + settings.positioner.anchor_rect.x += dx; + settings.positioner.anchor_rect.y += dy; + } // first check existing popup // if an existing popup with the same id exists, we just update the positioner. if let Some((chain, existing)) = self.popmgr.popup_id(settings.id).and_then(|p| (p.data.grab == settings.grab && self.popmgr.popups().any(|parent| parent.popup.wl_surface() == p.data.parent.wl_surface() && parent.data.id == settings.parent) || self.windows.iter().any(|w| w.id == settings.parent && *p.data.parent.wl_surface() == w.wl_surface(&self.connection)) - || self.layer_surfaces.iter().any(|l| l.id == settings.parent && p.data.parent.wl_surface() == l.surface.wl_surface())).then(|| + || self.layer_surfaces.iter().any(|l| l.id == settings.parent && p.data.parent.wl_surface() == l.surface.wl_surface()) + || (p.data.parent_window == settings.parent && self.subsurfaces.iter().any(|s| s.id == settings.parent))).then(|| { p.popup.wl_surface().clone() })).and_then(|s| self.popmgr.chain_for_popup_mut(&s)) @@ -1662,9 +1720,13 @@ impl SctkState { } }, subsurface::Action::Reposition { id, x, y } => { - if let Some(subsurface) = self.subsurfaces.iter().find(|s| s.id == id) { + if let Some(subsurface) = self.subsurfaces.iter_mut().find(|s| s.id == id) { subsurface.instance.wl_subsurface.set_position(x, y); subsurface.instance.wl_surface.commit(); + if let Some(b) = subsurface.instance.bounds.as_mut() { + b.x = x as f32; + b.y = y as f32; + } } }, }, diff --git a/winit/src/platform_specific/wayland/handlers/seat/keyboard.rs b/winit/src/platform_specific/wayland/handlers/seat/keyboard.rs index f83e1180..30f9c7a6 100644 --- a/winit/src/platform_specific/wayland/handlers/seat/keyboard.rs +++ b/winit/src/platform_specific/wayland/handlers/seat/keyboard.rs @@ -1,12 +1,16 @@ use crate::platform_specific::wayland::{ - event_loop::state::SctkState, + event_loop::state::{PopupParent, SctkState}, sctk_event::{KeyboardEventVariant, SctkEvent}, }; use cctk::sctk::{ delegate_keyboard, seat::keyboard::{KeyboardHandler, Keysym, Modifiers}, }; -use cctk::sctk::{reexports::client::Proxy, seat::keyboard::RawModifiers}; +use cctk::sctk::{ + reexports::client::Proxy, + seat::keyboard::RawModifiers, + shell::{WaylandSurface, wlr_layer::KeyboardInteractivity}, +}; fn modifiers_from_keysyms( keysyms: &[Keysym], @@ -90,6 +94,11 @@ impl KeyboardHandler for SctkState { } self.request_redraw(&surface); + // Focus is coming back from our own grabbing popup + if self.kbd_leave_to_own_popup.remove(&surface.id()) { + return; + } + let surfaces = self.subsurfaces.iter().filter_map(|s| { (s.instance.parent == *surface).then(|| &s.instance.wl_surface) }); @@ -147,6 +156,32 @@ impl KeyboardHandler for SctkState { _ = my_seat.kbd_focus.take(); (is_active, seat, kbd) }; + + // A grabbing popup parented to this layer surface, or opened from one of + // its subsurfaces that holds focus, takes keyboard focus. + // Only swallow the leave when the layer surface has exclusive keyboard interactivity. + let focus_moved_to_own_popup = self.popmgr.popups().any(|p| { + p.data.grab + && match &p.data.parent { + PopupParent::LayerSurface(s) => { + (s == surface + || self.subsurfaces.iter().any(|sub| { + sub.id == p.data.parent_window + && sub.instance.wl_surface == *surface + })) + && self.layer_surfaces.iter().any(|l| { + l.surface.wl_surface() == s + && l.keyboard_interactivity + == KeyboardInteractivity::Exclusive + }) + } + _ => false, + } + }); + if focus_moved_to_own_popup { + _ = self.kbd_leave_to_own_popup.insert(surface.id()); + return; + } let surfaces = self.subsurfaces.iter().filter_map(|s| { (s.instance.parent == *surface).then(|| &s.instance.wl_surface) }); From 890a53fef1fbcba14ea31a3c718a4314a6e34c2e Mon Sep 17 00:00:00 2001 From: Hojjat Date: Tue, 4 Aug 2026 10:34:36 -0600 Subject: [PATCH 86/93] fix: add tablet support for toplevel windows --- winit/src/conversion.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/winit/src/conversion.rs b/winit/src/conversion.rs index 8ce3ed66..e10c633d 100644 --- a/winit/src/conversion.rs +++ b/winit/src/conversion.rs @@ -269,6 +269,13 @@ pub fn window_event( scale_factor, ))) } + winit::event::PointerSource::TabletTool { .. } => { + let position = position.to_logical::(scale_factor); + + Some(Event::Mouse(mouse::Event::CursorMoved { + position: Point::new(position.x as f32, position.y as f32), + })) + } _ => None, }, // TODO how to handle this for Touch? Is it different than a press? Need to double check winit impl @@ -306,6 +313,24 @@ pub fn window_event( } })) } + WindowEvent::PointerButton { + button: ButtonSource::TabletTool { button, .. }, + state, + .. + } => { + let button: Option = button.into(); + + button.map(mouse_button).map(|button| { + Event::Mouse(match state { + winit::event::ElementState::Pressed => { + mouse::Event::ButtonPressed(button) + } + winit::event::ElementState::Released => { + mouse::Event::ButtonReleased(button) + } + }) + }) + } WindowEvent::PointerButton { button: ButtonSource::Touch { finger_id, force }, state, From 85d4e4d5c24a88412798b1c28d88fd2ae7f076d6 Mon Sep 17 00:00:00 2001 From: Hojjat Date: Wed, 16 Sep 2026 10:30:01 -0600 Subject: [PATCH 87/93] chore: update winit to support moving windows with touchscreen --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index cf5abcbe..c818cad0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -308,8 +308,8 @@ winapi = "0.3" window_clipboard = { git = "https://github.com/pop-os/window_clipboard.git", tag = "sctk-0.20" } dnd = { git = "https://github.com/pop-os/window_clipboard.git", tag = "sctk-0.20" } mime = { git = "https://github.com/pop-os/window_clipboard.git", tag = "sctk-0.20" } -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" } +winit = { git = "https://github.com/pop-os/winit.git", rev = "9567503" } +winit-core = { git = "https://github.com/pop-os/winit.git", rev = "9567503" } cursor-icon = "1.1.0" [workspace.lints.rust] From ffc3ac317e725991f6d3ebcb0610f2a7b49a9584 Mon Sep 17 00:00:00 2001 From: Blake Gardner Date: Thu, 17 Sep 2026 21:07:46 -0500 Subject: [PATCH 88/93] fix(test): build `iced_test` against this fork's runtime and renderer style `iced_test` has not compiled here since it arrived from upstream: it matches `runtime::Action` exhaustively without the fork's `Dnd` and `PlatformSpecific` variants, and builds `renderer::Style` without the fork's `icon_color` and `scale_factor` fields. Nothing else in the workspace depends on it, so the errors only show up in `cargo test --workspace` and for anyone adding the crate to an application. The emulator ignores the two actions: drag and drop and platform surfaces need a windowing system, which it has none of. The style fields follow what the winit runtime passes: the icon color is the text color, and the scale factor is the one the emulator or simulator already renders its screenshot at. Co-Authored-By: Claude Fable 5.1 --- test/src/emulator.rs | 7 +++++++ test/src/simulator.rs | 6 ++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/test/src/emulator.rs b/test/src/emulator.rs index bdb2415c..20c52f59 100644 --- a/test/src/emulator.rs +++ b/test/src/emulator.rs @@ -273,6 +273,11 @@ impl Emulator

{ runtime::Action::Reload => { // TODO } + runtime::Action::Dnd(_) + | runtime::Action::PlatformSpecific(_) => { + // Drag and drop and platform surfaces need a + // windowing system, which an emulator has none of. + } }, } } @@ -474,7 +479,9 @@ impl Emulator

{ &mut self.renderer, theme, &renderer::Style { + icon_color: style.text_color, text_color: style.text_color, + scale_factor: f64::from(scale_factor), }, mouse::Cursor::Unavailable, ); diff --git a/test/src/simulator.rs b/test/src/simulator.rs index 63fbe3f7..20972088 100644 --- a/test/src/simulator.rs +++ b/test/src/simulator.rs @@ -209,17 +209,19 @@ where &mut self.messages, ); + let scale_factor = 2.0_f32; + self.raw.draw( &mut self.renderer, theme, &core::renderer::Style { + icon_color: base.text_color, text_color: base.text_color, + scale_factor: f64::from(scale_factor), }, self.cursor, ); - let scale_factor = 2.0; - let physical_size = Size::new( (self.size.width * scale_factor).round() as u32, (self.size.height * scale_factor).round() as u32, From 021cb93fa32dc33149e4add295d34a66787e6159 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vuka=C5=A1in=20Vojinovi=C4=87?= <150025636+git-f0x@users.noreply.github.com> Date: Fri, 18 Sep 2026 20:29:00 +0200 Subject: [PATCH 89/93] improv(scrollable): match padding impl to upstream --- widget/src/scrollable.rs | 104 +++++++++++++++------------------------ 1 file changed, 39 insertions(+), 65 deletions(-) diff --git a/widget/src/scrollable.rs b/widget/src/scrollable.rs index 43782ea7..9ac66998 100644 --- a/widget/src/scrollable.rs +++ b/widget/src/scrollable.rs @@ -248,64 +248,19 @@ where self } - /// Sets whether the user should be allowed to auto-scroll the [`Scrollable`] - /// with the middle mouse button. + /// Adds padding at the ends of the [`Scrollbar`]s of the [`Scrollable`]. /// - /// By default, it is disabled. - pub fn auto_scroll(mut self, auto_scroll: bool) -> Self { - self.auto_scroll = auto_scroll; - self - } - - /// Sets the scrollbar width of the [`Scrollbar`]. - pub fn scrollbar_width(mut self, width: impl Into) -> Self { - let width = width.into().0.max(0.0); + /// The `padding` provided will be used as space at the top and bottom of a + /// vertical [`Scrollbar`], and at the left and right ends of a horizontal + /// [`Scrollbar`], when they are visible. + /// + /// Unlike [`Self::spacing`], the padding does not affect the layout of the + /// [`Scrollable`]. + pub fn padding(mut self, new_padding: impl Into) -> Self { + let padding = new_padding.into().0; match &mut self.direction { - Direction::Horizontal(scrollbar) - | Direction::Vertical(scrollbar) => { - scrollbar.width = width; - } - Direction::Both { - horizontal, - vertical, - } => { - horizontal.width = width; - vertical.width = width; - } - } - - self - } - - /// Sets the scroller width of the [`Scrollbar`]. - pub fn scroller_width(mut self, width: impl Into) -> Self { - let width = width.into().0.max(0.0); - - match &mut self.direction { - Direction::Horizontal(scrollbar) - | Direction::Vertical(scrollbar) => { - scrollbar.scroller_width = width; - } - Direction::Both { - horizontal, - vertical, - } => { - horizontal.scroller_width = width; - vertical.scroller_width = width; - } - } - - self - } - - /// Sets the padding at the start and end of the [`Scrollbar`]. - pub fn scrollbar_padding(mut self, padding: impl Into) -> Self { - let padding = padding.into().0.max(0.0); - - match &mut self.direction { - Direction::Horizontal(scrollbar) - | Direction::Vertical(scrollbar) => { + Direction::Horizontal(scrollbar) | Direction::Vertical(scrollbar) => { scrollbar.padding = padding; } Direction::Both { @@ -320,6 +275,15 @@ where self } + /// Sets whether the user should be allowed to auto-scroll the [`Scrollable`] + /// with the middle mouse button. + /// + /// By default, it is disabled. + pub fn auto_scroll(mut self, auto_scroll: bool) -> Self { + self.auto_scroll = auto_scroll; + self + } + /// Sets the style of this [`Scrollable`]. #[must_use] pub fn style(mut self, style: impl Fn(&Theme, Status) -> Style + 'a) -> Self @@ -504,9 +468,15 @@ impl Scrollbar { self } - /// Sets the padding at the start and end of the [`Scrollbar`]. + /// Sets the padding of the [`Scrollbar`]. + /// + /// The padding is added at the top and bottom of the scrollbar (or at the + /// left and right ends for a horizontal [`Scrollbar`]) when it is visible. + /// + /// Unlike [`Self::margin`] and [`Self::spacing`], the padding does not + /// affect the layout of the [`Scrollable`]. pub fn padding(mut self, padding: impl Into) -> Self { - self.padding = padding.into().0.max(0.0); + self.padding = padding.into().0; self } } @@ -2414,13 +2384,16 @@ impl Scrollbars { let total_scrollbar_width = width.max(scroller_width) + 2.0 * margin; + // The padding is purely visual: it shrinks the top and bottom of the + // scrollbar without affecting the layout + let scrollbar_height = (bounds.height - x_scrollbar_height - 2.0 * padding).max(0.0); + // Total bounds of the scrollbar + margin + scroller width let total_scrollbar_bounds = Rectangle { x: bounds.x + bounds.width - total_scrollbar_width, y: bounds.y + padding, width: total_scrollbar_width, - height: (bounds.height - x_scrollbar_height - 2.0 * padding) - .max(0.0), + height: scrollbar_height, }; // Bounds of just the scrollbar @@ -2430,8 +2403,7 @@ impl Scrollbars { - width / 2.0, y: bounds.y + padding, width, - height: (bounds.height - x_scrollbar_height - 2.0 * padding) - .max(0.0), + height: scrollbar_height, }; let ratio = bounds.height / content_bounds.height; @@ -2488,12 +2460,15 @@ impl Scrollbars { let total_scrollbar_height = width.max(scroller_width) + 2.0 * margin; + // The padding is purely visual: it shrinks the left and right ends of + // the scrollbar without affecting the layout + let scrollbar_width = (bounds.width - scrollbar_y_width - 2.0 * padding).max(0.0); + // Total bounds of the scrollbar + margin + scroller width let total_scrollbar_bounds = Rectangle { x: bounds.x + padding, y: bounds.y + bounds.height - total_scrollbar_height, - width: (bounds.width - scrollbar_y_width - 2.0 * padding) - .max(0.0), + width: scrollbar_width, height: total_scrollbar_height, }; @@ -2503,8 +2478,7 @@ impl Scrollbars { y: bounds.y + bounds.height - total_scrollbar_height / 2.0 - width / 2.0, - width: (bounds.width - scrollbar_y_width - 2.0 * padding) - .max(0.0), + width: scrollbar_width, height: width, }; From 5e2b580791e994cb0132c94b32ba4b00bc9ced21 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Mon, 21 Sep 2026 11:10:19 -0400 Subject: [PATCH 90/93] chore: update accesskit --- Cargo.lock | 1979 ++++++++++++++++++-------------------- accessibility/Cargo.toml | 8 +- 2 files changed, 956 insertions(+), 1031 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4bb792f8..de62ab66 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21,7 +21,7 @@ checksum = "366ffbaa4442f4684d91e2cd7c5ea7c4ed8add41959a31447066e279e432b618" [[package]] name = "accesskit" version = "0.22.0" -source = "git+https://github.com/wash2/accesskit?tag=cosmic-0.14#f0599eed5f18111228266fe3f28991cc48b5964f" +source = "git+https://github.com/wash2/accesskit?rev=6c20249#6c20249d3b9fd45e7002efad9f6b6171a9257912" dependencies = [ "uuid", ] @@ -29,7 +29,7 @@ dependencies = [ [[package]] name = "accesskit_atspi_common" version = "0.15.0" -source = "git+https://github.com/wash2/accesskit?tag=cosmic-0.14#f0599eed5f18111228266fe3f28991cc48b5964f" +source = "git+https://github.com/wash2/accesskit?rev=6c20249#6c20249d3b9fd45e7002efad9f6b6171a9257912" dependencies = [ "accesskit", "accesskit_consumer", @@ -41,7 +41,7 @@ dependencies = [ [[package]] name = "accesskit_consumer" version = "0.32.0" -source = "git+https://github.com/wash2/accesskit?tag=cosmic-0.14#f0599eed5f18111228266fe3f28991cc48b5964f" +source = "git+https://github.com/wash2/accesskit?rev=6c20249#6c20249d3b9fd45e7002efad9f6b6171a9257912" dependencies = [ "accesskit", "hashbrown 0.16.1", @@ -50,7 +50,7 @@ dependencies = [ [[package]] name = "accesskit_macos" version = "0.23.0" -source = "git+https://github.com/wash2/accesskit?tag=cosmic-0.14#f0599eed5f18111228266fe3f28991cc48b5964f" +source = "git+https://github.com/wash2/accesskit?rev=6c20249#6c20249d3b9fd45e7002efad9f6b6171a9257912" dependencies = [ "accesskit", "accesskit_consumer", @@ -63,7 +63,7 @@ dependencies = [ [[package]] name = "accesskit_unix" version = "0.18.0" -source = "git+https://github.com/wash2/accesskit?tag=cosmic-0.14#f0599eed5f18111228266fe3f28991cc48b5964f" +source = "git+https://github.com/wash2/accesskit?rev=6c20249#6c20249d3b9fd45e7002efad9f6b6171a9257912" dependencies = [ "accesskit", "accesskit_atspi_common", @@ -82,7 +82,7 @@ dependencies = [ [[package]] name = "accesskit_windows" version = "0.30.0" -source = "git+https://github.com/wash2/accesskit?tag=cosmic-0.14#f0599eed5f18111228266fe3f28991cc48b5964f" +source = "git+https://github.com/wash2/accesskit?rev=6c20249#6c20249d3b9fd45e7002efad9f6b6171a9257912" dependencies = [ "accesskit", "accesskit_consumer", @@ -95,7 +95,7 @@ dependencies = [ [[package]] name = "accesskit_winit" version = "0.30.0" -source = "git+https://github.com/wash2/accesskit?tag=cosmic-0.14#f0599eed5f18111228266fe3f28991cc48b5964f" +source = "git+https://github.com/wash2/accesskit?rev=6c20249#6c20249d3b9fd45e7002efad9f6b6171a9257912" dependencies = [ "accesskit", "accesskit_macos", @@ -126,9 +126,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba" dependencies = [ "memchr", ] @@ -172,21 +172,21 @@ dependencies = [ "android-properties", "bitflags 2.13.2", "cc", - "jni 0.22.4", + "jni", "libc", "log", "ndk", "ndk-context", "ndk-sys", "num_enum", - "thiserror 2.0.18", + "thiserror 2.0.20", ] [[package]] name = "android-build" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cac4c64175d504608cf239756339c07f6384a476f97f20a7043f92920b0b8fd" +checksum = "f9fc9904ad2ad097c3c1cfe2eacaaf0fc24710936fa9ed941cb310b7c6ed2ab7" dependencies = [ "windows-sys 0.52.0", ] @@ -199,9 +199,9 @@ checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04" [[package]] name = "android_system_properties" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +checksum = "ae221649c9976a6f6c56ae1facf410f3ddb33cc661c4b7b61020a912d4237fbc" dependencies = [ "libc", ] @@ -220,9 +220,9 @@ checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" [[package]] name = "anyhow" -version = "1.0.102" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" [[package]] name = "approx" @@ -254,7 +254,7 @@ checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -265,9 +265,9 @@ checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] name = "arrayvec" -version = "0.7.6" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" [[package]] name = "as-raw-xcb-connection" @@ -304,14 +304,14 @@ dependencies = [ "enumflags2", "futures-channel", "futures-util", - "rand 0.9.2", + "rand 0.9.5", "raw-window-handle", "serde", "serde_repr", "url", "wayland-backend", "wayland-client", - "wayland-protocols 0.32.12", + "wayland-protocols 0.32.13", "zbus", ] @@ -321,7 +321,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" dependencies = [ - "event-listener 5.4.1", + "event-listener 5.4.2", "event-listener-strategy", "futures-core", "pin-project-lite", @@ -403,7 +403,7 @@ dependencies = [ "futures-lite", "parking", "polling", - "rustix 1.1.4", + "rustix 1.1.5", "slab", "windows-sys 0.61.2", ] @@ -414,7 +414,7 @@ version = "3.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" dependencies = [ - "event-listener 5.4.1", + "event-listener 5.4.2", "event-listener-strategy", "pin-project-lite", ] @@ -443,9 +443,9 @@ dependencies = [ "async-task", "blocking", "cfg-if", - "event-listener 5.4.1", + "event-listener 5.4.2", "futures-lite", - "rustix 1.1.4", + "rustix 1.1.5", ] [[package]] @@ -456,7 +456,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -471,7 +471,7 @@ dependencies = [ "cfg-if", "futures-core", "futures-io", - "rustix 1.1.4", + "rustix 1.1.5", "signal-hook-registry", "slab", "windows-sys 0.61.2", @@ -511,13 +511,13 @@ checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-trait" -version = "0.1.89" +version = "0.1.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +checksum = "82f6aeea286b8eb4dd3431a1be1b59d290ace00f5bfd8e2a159bc2a05e2c1667" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.6", ] [[package]] @@ -545,9 +545,9 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "atomic_refcell" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41e67cd8309bbd06cd603a9e693a784ac2e5d1e955f11286e355089fcab3047c" +checksum = "21e4227379beff4205943696e6c3e0cd809bacdf3f0edd6e3dd153e2269571a4" [[package]] name = "atspi" @@ -588,9 +588,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" [[package]] name = "av-scenechange" @@ -607,7 +607,7 @@ dependencies = [ "num-traits", "pastey", "rayon", - "thiserror 2.0.18", + "thiserror 2.0.20", "v_frame", "y4m", ] @@ -628,9 +628,9 @@ dependencies = [ [[package]] name = "avif-serialize" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "375082f007bd67184fb9c0374614b29f9aaa604ec301635f72338bb65386a53d" +checksum = "e7178fe5f7d460b13895ebb9dcb28a3a6216d2df2574a0806cb51b555d297f38" dependencies = [ "arrayvec", ] @@ -647,6 +647,12 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5" + [[package]] name = "bezier_tool" version = "0.1.0" @@ -718,11 +724,11 @@ checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06" [[package]] name = "bitstream-io" -version = "4.9.0" +version = "4.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60d4bd9d1db2c6bdf285e223a7fa369d5ce98ec767dec949c6ca62863ce61757" +checksum = "7eff00be299a18769011411c9def0d827e8f2d7bf0c3dbf53633147a8867fd1f" dependencies = [ - "core2", + "no_std_io2", ] [[package]] @@ -760,9 +766,9 @@ dependencies = [ [[package]] name = "blocking" -version = "1.6.2" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" +checksum = "a70e4329df6cb94385eed412ec92375c3cdd8a6e502493d1229b6414e4036dfa" dependencies = [ "async-channel 2.5.0", "async-task", @@ -779,9 +785,9 @@ checksum = "e79769241dcd44edf79a732545e8b5cec84c247ac060f5252cd51885d093a8fc" [[package]] name = "borsh" -version = "1.6.1" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfd1e3f8955a5d7de9fab72fc8373fade9fb8a703968cb200ae3dc6cf08e185a" +checksum = "553c5d846a6ba5150c65e3b1b8ec073bcf1abc20f9b7220de384a4443ea4e20a" dependencies = [ "bytes", "cfg_aliases", @@ -796,15 +802,15 @@ dependencies = [ [[package]] name = "built" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4ad8f11f288f48ca24471bbd51ac257aaeaaa07adae295591266b792902ae64" +checksum = "5c0e531d93d39c34eef561e929e8a7f86d77a5af08aac4f6d6e39976c51858e9" [[package]] name = "bumpalo" -version = "3.20.2" +version = "3.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" [[package]] name = "by_address" @@ -814,22 +820,22 @@ checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06" [[package]] name = "bytemuck" -version = "1.25.0" +version = "1.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" +checksum = "95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.10.2" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" +checksum = "6a1f896587b6f2c069c73d2f0913e2d590c3990285cd2f0b6aa02b786b4c679c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.6", ] [[package]] @@ -846,9 +852,9 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" [[package]] name = "bytes" -version = "1.11.1" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" [[package]] name = "calloop" @@ -886,7 +892,7 @@ checksum = "4dbf9978365bac10f54d1d4b04f7ce4427e51f71d61f2fe15e3fed5166474df7" dependencies = [ "bitflags 2.13.2", "polling", - "rustix 1.1.4", + "rustix 1.1.5", "slab", "tracing", ] @@ -910,7 +916,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "138efcf0940a02ebf0cc8d1eff41a1682a46b431630f4c52450d6265876021fa" dependencies = [ "calloop 0.14.4", - "rustix 1.1.4", + "rustix 1.1.5", "wayland-backend", "wayland-client", ] @@ -935,9 +941,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.60" +version = "1.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43c5703da9466b66a946814e1adf53ea2c90f10063b86290cc9eb67ce3478a20" +checksum = "54413ede23c2daf518f35156dfde027feb2374004d63bd497f983c8db9c0e313" dependencies = [ "find-msvc-tools", "jobserver", @@ -945,17 +951,11 @@ dependencies = [ "shlex", ] -[[package]] -name = "cesu8" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" - [[package]] name = "cfg-expr" -version = "0.20.7" +version = "0.20.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c6b04e07d8080154ed4ac03546d9a2b303cc2fe1901ba0b35b301516e289368" +checksum = "fe4ece8474b5f766c63426647e7b4b316b67431ade1036a8313cee24a03ae917" dependencies = [ "smallvec", "target-lexicon", @@ -963,25 +963,25 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600" [[package]] name = "cfg_aliases" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527" [[package]] name = "chacha20" -version = "0.10.0" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" +checksum = "65c35e4b699c7e15ccbe7ee35c005e4fc0a278d22238a2857e6ce2dadeda1b06" dependencies = [ "cfg-if", - "cpufeatures 0.3.0", - "rand_core 0.10.0", + "cpufeatures 0.3.1", + "rand_core 0.10.1", ] [[package]] @@ -993,7 +993,7 @@ dependencies = [ "log", "reqwest", "serde", - "thiserror 2.0.18", + "thiserror 2.0.20", "tokio", "tracing-subscriber", "webbrowser", @@ -1008,9 +1008,9 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.44" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" dependencies = [ "iana-time-zone", "js-sys", @@ -1048,18 +1048,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.6.0" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351" +checksum = "aa8876b300ab35ba921adea3dfd70157a46249b33f95c9084ae5709785478946" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.6.0" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" +checksum = "ec0797fb7aeb1406c84efac526901f7ec3ead2124f946b494e72879d4b54704d" dependencies = [ "anstyle", "clap_lex", @@ -1067,9 +1067,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" +checksum = "1c133bc6a41be0d194c306b5506d15e6feeea7b1d6604bd3f8310dfb2ca96486" [[package]] name = "clipboard-win" @@ -1175,9 +1175,9 @@ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" [[package]] name = "combine" -version = "4.6.7" +version = "4.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +checksum = "cfc320937d09e6de266b31b9afb480f197d7a861be86be7cb2ea7e5d1bfffc5e" dependencies = [ "bytes", "memchr", @@ -1211,9 +1211,9 @@ dependencies = [ [[package]] name = "console_log" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be8aed40e4edbf4d3b4431ab260b63fdc40f5780a4766824329ea0f1eefe3c0f" +checksum = "86919cef3e37b9356ccf54d4421208c17ecfda01beae61393e7ffd72916c0ef1" dependencies = [ "log", "web-sys", @@ -1281,13 +1281,10 @@ dependencies = [ ] [[package]] -name = "core2" -version = "0.4.0" +name = "core_detect" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505" -dependencies = [ - "memchr", -] +checksum = "7f8f80099a98041a3d1622845c271458a2d73e688351bf3cb999266764b81d48" [[package]] name = "core_maths" @@ -1308,7 +1305,7 @@ dependencies = [ "libc", "smithay-client-toolkit 0.20.0", "wayland-client", - "wayland-protocols 0.32.12", + "wayland-protocols 0.32.13", ] [[package]] @@ -1319,7 +1316,7 @@ dependencies = [ "bitflags 2.13.2", "wayland-backend", "wayland-client", - "wayland-protocols 0.32.12", + "wayland-protocols 0.32.13", "wayland-protocols-wlr 0.3.12", "wayland-scanner", "wayland-server", @@ -1337,9 +1334,9 @@ dependencies = [ "linebender_resource_handle", "log", "rangemap", - "rustc-hash 2.1.2", + "rustc-hash 2.1.3", "self_cell", - "skrifa", + "skrifa 0.40.0", "smol_str", "swash", "sys-locale", @@ -1367,18 +1364,18 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +checksum = "5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566" dependencies = [ "libc", ] [[package]] name = "crc32fast" -version = "1.5.0" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +checksum = "01a7799fd6b852db0e61728dde9a204c423b44d689dbd432522543614b490e78" dependencies = [ "cfg-if", ] @@ -1421,9 +1418,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +checksum = "622f3fc73690be383c7214310406f28a90e6edeadc3cea882f9d71e495b9711a" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -1431,18 +1428,18 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.18" +version = "0.9.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +checksum = "dc74980687109a3b14c72fd458107bf0baa1da1a1a805e178d15501ba9b86d9d" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.21" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6" [[package]] name = "crunchy" @@ -1458,7 +1455,7 @@ dependencies = [ "cosmic-text", "etagere", "lru", - "rustc-hash 2.1.2", + "rustc-hash 2.1.3", "wgpu", ] @@ -1473,10 +1470,13 @@ dependencies = [ ] [[package]] -name = "ctor-lite" -version = "0.1.2" +name = "ctor" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e162d0c2e2068eb736b71e5597eff0b9944e6b973cd9f37b6a288ab9bf20e300" +checksum = "83cf0d42651b16c6dfe68685716d18480d18a9c39c62d76e8cf3eb6ed5d8bcbf" +dependencies = [ + "dtor", +] [[package]] name = "cursor-icon" @@ -1499,7 +1499,7 @@ dependencies = [ "glam", "iced", "image", - "rand 0.8.5", + "rand 0.8.8", ] [[package]] @@ -1511,9 +1511,9 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.10.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" +checksum = "4583a4551df46e2792f82ceeac45e850d2e2d5debba0b91f102385cda5b11f06" [[package]] name = "data-url" @@ -1521,6 +1521,37 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be1e0bca6c3637f992fc1cc7cbc52a78c1ef6db076dbf1059c4323d6a2048376" +[[package]] +name = "defmt" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2953bfe4f93bbd20cc71198842756f77d161884c99ebbabc41d80231ded88d1" +dependencies = [ + "bitflags 1.3.2", + "defmt-macros", +] + +[[package]] +name = "defmt-macros" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bad9c72e7ca2137e0dc3813245a0d282fd6daad32fd800af018306a9169b5fe8" +dependencies = [ + "defmt-parser", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "defmt-parser" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" +dependencies = [ + "thiserror 2.0.20", +] + [[package]] name = "delineate" version = "0.1.0" @@ -1533,9 +1564,6 @@ name = "deranged" version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" -dependencies = [ - "powerfmt", -] [[package]] name = "digest" @@ -1574,8 +1602,8 @@ checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" dependencies = [ "libc", "option-ext", - "redox_users 0.5.2", - "windows-sys 0.59.0", + "redox_users 0.5.3", + "windows-sys 0.61.2", ] [[package]] @@ -1609,13 +1637,13 @@ dependencies = [ [[package]] name = "displaydoc" -version = "0.2.5" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.6", ] [[package]] @@ -1665,7 +1693,7 @@ dependencies = [ [[package]] name = "dpi" version = "0.1.2" -source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" +source = "git+https://github.com/pop-os/winit.git?rev=9567503#9567503d34130113e36b0167a2b8829c3756e429" [[package]] name = "drm" @@ -1706,6 +1734,12 @@ dependencies = [ "linux-raw-sys 0.6.5", ] +[[package]] +name = "dtor" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edf234dd1594d6dd434a8fb8cada51ddbbc593e40e4a01556a0b31c62da2775b" + [[package]] name = "editor" version = "0.1.0" @@ -1717,17 +1751,23 @@ dependencies = [ [[package]] name = "either" -version = "1.15.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +checksum = "252afb9ae5eaa683babdc6a068b3f5726eb19e05070c731f9b2a23a7c3e8ed34" [[package]] name = "encoding_rs" -version = "0.8.35" +version = "0.8.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +checksum = "7b5ef0006ac9ab233c38522f5ae99cae3625151de8f706cacee1cba4b8e2832a" dependencies = [ "cfg-if", + "core_detect", + "multiversion", + "multiversion_no_op", + "rustversion", + "scopeguard", + "simdutf8", ] [[package]] @@ -1754,7 +1794,7 @@ checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -1787,7 +1827,7 @@ checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -1803,14 +1843,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] name = "error-code" -version = "3.3.2" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59" +checksum = "0b5343afd4a8365a643ac588dab4cf234a190c7f6c88c9f6dd6ffe00837661b7" [[package]] name = "etagere" @@ -1839,11 +1879,10 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "event-listener" -version = "5.4.1" +version = "5.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +checksum = "5a23add41df1562121a9393cb065eab5146a1242410f23a644851e90cfd669d2" dependencies = [ - "concurrent-queue", "parking", "pin-project-lite", ] @@ -1854,7 +1893,7 @@ version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" dependencies = [ - "event-listener 5.4.1", + "event-listener 5.4.2", "pin-project-lite", ] @@ -1874,14 +1913,16 @@ dependencies = [ [[package]] name = "exr" -version = "1.74.0" +version = "1.74.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4300e043a56aa2cb633c01af81ca8f699a321879a7854d3896a0ba89056363be" +checksum = "711fe42c9964295e01ee3fba3f9fe0e1d24b98886950d68efe81b1c76e21adf3" dependencies = [ "bit_field", "half", "lebe", - "miniz_oxide", + "miniz_oxide 0.8.9", + "num-complex", + "pulp", "rayon-core", "smallvec", "zune-inflate", @@ -1898,37 +1939,17 @@ dependencies = [ "regex-syntax", ] -[[package]] -name = "fast-srgb8" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd2e7510819d6fbf51a5545c8f922716ecfb14df168a3242f7d33e0239efe6a1" - [[package]] name = "fastrand" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" +checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" [[package]] name = "fax" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f05de7d48f37cd6730705cbca900770cab77a89f413d23e100ad7fad7795a0ab" -dependencies = [ - "fax_derive", -] - -[[package]] -name = "fax_derive" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0aca10fb742cb43f9e7bb8467c91aa9bcb8e3ffbc6a6f7389bb93ffc920577d" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] +checksum = "caf1079563223d5d59d83c85886a56e586cfd5c1a26292e971a0fa266531ac5a" [[package]] name = "fdeflate" @@ -1948,18 +1969,19 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.9" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" +checksum = "ef25905e51abafe4dcea6c15fec58c57b601cdbd0ee53d22ea1d3016c587d39b" [[package]] name = "flate2" -version = "1.1.9" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +checksum = "6e634e2e0ebac1ee034020da1ca582e17ffe4e0f5e985823721e168928136dcb" dependencies = [ "crc32fast", - "miniz_oxide", + "miniz_oxide 0.9.1", + "zlib-rs", ] [[package]] @@ -1994,9 +2016,18 @@ checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" [[package]] name = "font-types" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d9237c6d82152100c691fb77ea18037b402bcc7257d2c876a4ffac81bc22a1c" +checksum = "5b38ad915f6dadd993ced50848a8291a543bd41ca62bc10740d5e64e2ab4cfd7" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "font-types" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8eb065f3251655b3c90e22e5e363f310fc5332fb3402e37bbc94752283248f6" dependencies = [ "bytemuck", ] @@ -2018,7 +2049,7 @@ checksum = "457e789b3d1202543297a350643cf459f836cade38934e7a4cf6a39e7cde2905" dependencies = [ "fontconfig-parser", "log", - "memmap2 0.9.10", + "memmap2 0.9.11", "slotmap", "tinyvec", "ttf-parser", @@ -2045,13 +2076,13 @@ dependencies = [ [[package]] name = "foreign-types-macros" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +checksum = "ea5190182e6915eb873ddbc16e23b711b6eb1f9c00a0d0a3a91b5f6228475225" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.6", ] [[package]] @@ -2077,9 +2108,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.32" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" +checksum = "9a31d2a3fbaaeb2af2368bbdd904aa8e812d3c04a1ee10d3171f52d556e5d0a3" dependencies = [ "futures-channel", "futures-core", @@ -2092,9 +2123,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.32" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +checksum = "b1f9e3d69d39e4862ffed03ed071a76f9a13ba1d9109d355b0f0aa6b15e393c4" dependencies = [ "futures-core", "futures-sink", @@ -2102,15 +2133,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.32" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" +checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" [[package]] name = "futures-executor" -version = "0.3.32" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" +checksum = "031b47cf1a3c6cc8bc2fc76cd437f521619387907d469316e7c0bc278f1f5432" dependencies = [ "futures-core", "futures-task", @@ -2119,9 +2150,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.32" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" +checksum = "53c0fa8157de1303bfffdaa1cc2a673bfffb60102f76b0ef4441659124373fed" [[package]] name = "futures-lite" @@ -2138,32 +2169,32 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.32" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" +checksum = "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.6", ] [[package]] name = "futures-sink" -version = "0.3.32" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" +checksum = "1944426bf7d03f1d14f708785e4b33efd750b36d48a157b836b3efc15ede8e1d" [[package]] name = "futures-task" -version = "0.3.32" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" +checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd" [[package]] name = "futures-util" -version = "0.3.32" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" dependencies = [ "futures-channel", "futures-core", @@ -2196,7 +2227,7 @@ version = "0.1.0" dependencies = [ "iced", "itertools 0.12.1", - "rustc-hash 2.1.2", + "rustc-hash 2.1.3", "tokio", "tracing-subscriber", ] @@ -2224,7 +2255,7 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8" dependencies = [ - "rustix 1.1.4", + "rustix 1.1.5", "windows-link 0.2.1", ] @@ -2264,16 +2295,14 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" dependencies = [ "cfg-if", "libc", "r-efi 6.0.0", - "rand_core 0.10.0", - "wasip2", - "wasip3", + "rand_core 0.10.1", ] [[package]] @@ -2360,7 +2389,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -2427,8 +2456,8 @@ dependencies = [ "hashbrown 0.16.1", "log", "presser", - "thiserror 2.0.18", - "windows 0.57.0", + "thiserror 2.0.20", + "windows 0.62.2", ] [[package]] @@ -2481,7 +2510,7 @@ dependencies = [ "paste", "pin-project-lite", "smallvec", - "thiserror 2.0.18", + "thiserror 2.0.20", ] [[package]] @@ -2591,7 +2620,7 @@ dependencies = [ "gstreamer-video-sys", "libc", "once_cell", - "thiserror 2.0.18", + "thiserror 2.0.20", ] [[package]] @@ -2639,16 +2668,16 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.13" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" +checksum = "ef8e5e5a340588f4452631496976cf8636d4a7ecf600239fdc27615d2530bc16" dependencies = [ "atomic-waker", "bytes", "fnv", "futures-core", "futures-sink", - "http 1.4.0", + "http 1.5.0", "indexmap", "slab", "tokio", @@ -2677,7 +2706,7 @@ dependencies = [ "bitflags 2.13.2", "bytemuck", "core_maths", - "read-fonts", + "read-fonts 0.37.0", "smallvec", ] @@ -2703,9 +2732,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.17.0" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" [[package]] name = "headers" @@ -2745,9 +2774,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" +checksum = "e17592d60ebacc7d5e169f4663c5f84f9161cc90328abcfe8456f41e4dfcb284" [[package]] name = "hex" @@ -2774,9 +2803,9 @@ dependencies = [ [[package]] name = "http" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +checksum = "918d3568bebf352712bc2ef3d46a8bcf1a75b373be6539de198e9105cbbf9ce0" dependencies = [ "bytes", "itoa", @@ -2795,24 +2824,24 @@ dependencies = [ [[package]] name = "http-body" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +checksum = "ca2a8f2913ee65f60facd6a5905613afaa448497a0230cc41ce022d93290bc2c" dependencies = [ "bytes", - "http 1.4.0", + "http 1.5.0", ] [[package]] name = "http-body-util" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +checksum = "23169fe34a5fbcdd3f3862e78fb9b6fccd5f02a6dc6f732547005d45631ce71c" dependencies = [ "bytes", "futures-core", - "http 1.4.0", - "http-body 1.0.1", + "http 1.5.0", + "http-body 1.1.0", "pin-project-lite", ] @@ -2830,9 +2859,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "humantime" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" +checksum = "15cdd26707701c53297e2fa6afb323d55fbc1d0810c3aec078ae3ef0424c3c15" [[package]] name = "hyper" @@ -2860,17 +2889,17 @@ dependencies = [ [[package]] name = "hyper" -version = "1.9.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca" +checksum = "27b501faa50e7a26c3d3560ca625132f4078a17771f4810baf70475ae48cbe43" dependencies = [ "atomic-waker", "bytes", "futures-channel", "futures-core", - "h2 0.4.13", - "http 1.4.0", - "http-body 1.0.1", + "h2 0.4.19", + "http 1.5.0", + "http-body 1.1.0", "httparse", "itoa", "pin-project-lite", @@ -2881,17 +2910,16 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.7" +version = "0.27.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +checksum = "dfa8e654703247911e29c23fbeaa261834bd9bb74efba2f9acddc37bfb127f53" dependencies = [ - "http 1.4.0", - "hyper 1.9.0", + "http 1.5.0", + "hyper 1.11.1", "hyper-util", - "rustls 0.23.37", - "rustls-pki-types", + "rustls 0.23.45", "tokio", - "tokio-rustls 0.26.4", + "tokio-rustls 0.26.5", "tower-service", ] @@ -2903,7 +2931,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper 1.9.0", + "hyper 1.11.1", "hyper-util", "native-tls", "tokio", @@ -2921,14 +2949,14 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.4.0", - "http-body 1.0.1", - "hyper 1.9.0", + "http 1.5.0", + "http-body 1.1.0", + "hyper 1.11.1", "ipnet", "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.3", + "socket2 0.6.5", "system-configuration", "tokio", "tower-service", @@ -2982,7 +3010,7 @@ dependencies = [ "iced_winit", "image", "mime 0.1.0", - "thiserror 2.0.18", + "thiserror 2.0.20", "window_clipboard", ] @@ -3006,7 +3034,7 @@ dependencies = [ "log", "semver", "serde", - "thiserror 2.0.18", + "thiserror 2.0.20", "tokio", ] @@ -3028,10 +3056,10 @@ dependencies = [ "num-traits", "palette", "raw-window-handle", - "rustc-hash 2.1.2", + "rustc-hash 2.1.3", "serde", "smol_str", - "thiserror 2.0.18", + "thiserror 2.0.20", "unicode-segmentation", "web-time", "window_clipboard", @@ -3065,7 +3093,7 @@ dependencies = [ "futures", "iced_core", "log", - "rustc-hash 2.1.2", + "rustc-hash 2.1.3", "smol", "tokio", "wasm-bindgen-futures", @@ -3087,8 +3115,8 @@ dependencies = [ "log", "lyon_path", "raw-window-handle", - "rustc-hash 2.1.2", - "thiserror 2.0.18", + "rustc-hash 2.1.3", + "thiserror 2.0.20", "unicode-segmentation", ] @@ -3116,7 +3144,7 @@ dependencies = [ "iced_tiny_skia", "iced_wgpu", "log", - "thiserror 2.0.18", + "thiserror 2.0.20", ] [[package]] @@ -3133,7 +3161,7 @@ dependencies = [ "iced_selector", "raw-window-handle", "sipper", - "thiserror 2.0.18", + "thiserror 2.0.20", "window_clipboard", ] @@ -3156,7 +3184,7 @@ dependencies = [ "nom", "png 0.18.1", "sha2", - "thiserror 2.0.18", + "thiserror 2.0.20", ] [[package]] @@ -3180,9 +3208,9 @@ dependencies = [ "kurbo 0.10.4", "log", "resvg", - "rustc-hash 2.1.2", + "rustc-hash 2.1.3", "softbuffer", - "tiny-skia", + "tiny-skia 0.11.4", ] [[package]] @@ -3204,13 +3232,13 @@ dependencies = [ "lyon", "raw-window-handle", "resvg", - "rustc-hash 2.1.2", + "rustc-hash 2.1.3", "rustix 0.38.44", - "thiserror 2.0.18", + "thiserror 2.0.20", "tiny-xlib", "wayland-backend", "wayland-client", - "wayland-protocols 0.32.12", + "wayland-protocols 0.32.13", "wayland-sys", "wgpu", "x11rb", @@ -3232,8 +3260,8 @@ dependencies = [ "ouroboros", "pulldown-cmark", "qrcode", - "rustc-hash 2.1.2", - "thiserror 2.0.18", + "rustc-hash 2.1.3", + "thiserror 2.0.20", "unicode-segmentation", "window_clipboard", ] @@ -3255,14 +3283,14 @@ dependencies = [ "log", "mundy", "raw-window-handle", - "rustc-hash 2.1.2", + "rustc-hash 2.1.3", "rustix 0.38.44", "sysinfo", - "thiserror 2.0.18", + "thiserror 2.0.20", "wasm-bindgen-futures", "wayland-backend", "wayland-client", - "wayland-protocols 0.32.12", + "wayland-protocols 0.32.13", "web-sys", "winapi", "window_clipboard", @@ -3275,9 +3303,9 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" +checksum = "fa68d21081c4a05d5a901a1c62add574c77048b6a1c67be3b50ce0b60d4ca513" dependencies = [ "displaydoc", "potential_utf", @@ -3289,9 +3317,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" +checksum = "d56e28588da92eee5c3201a6eff33fabdd49b62269c8938d4ff050ce4d900deb" dependencies = [ "displaydoc", "litemap", @@ -3302,9 +3330,9 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" +checksum = "12f9cf5f235641ed274641dd81c3f28d870e276763d0797aeeab72317b1c646f" dependencies = [ "icu_collections", "icu_normalizer_data", @@ -3316,16 +3344,17 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" +checksum = "1563da1ed3e0b3bf3d74c9b85917ac9c56464d2f57242270c09c9e752f8021a0" [[package]] name = "icu_properties" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" +checksum = "7e7ca276ad3145661a65914e6daf131ca5120cd3dcee8f8f3214b8875184a148" dependencies = [ + "displaydoc", "icu_collections", "icu_locale_core", "icu_properties_data", @@ -3336,15 +3365,15 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" +checksum = "e590f038c1464a96894fd6d10127e90a8be4509f56ff7ecef851b15cee0b7caa" [[package]] name = "icu_provider" -version = "2.2.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +checksum = "d27bbb9d3abbefac45d55f647c9de1d44aafcd1186eb91879afef17c396c3e73" dependencies = [ "displaydoc", "icu_locale_core", @@ -3355,12 +3384,6 @@ dependencies = [ "zerovec", ] -[[package]] -name = "id-arena" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" - [[package]] name = "idna" version = "1.1.0" @@ -3374,9 +3397,9 @@ dependencies = [ [[package]] name = "idna_adapter" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" dependencies = [ "icu_normalizer", "icu_properties", @@ -3402,7 +3425,7 @@ dependencies = [ "rayon", "rgb", "tiff", - "zune-core 0.5.1", + "zune-core 0.5.3", "zune-jpeg 0.5.15", ] @@ -3424,20 +3447,18 @@ checksum = "edcd27d72f2f071c64249075f42e205ff93c9a4c5f6c6da53e79ed9f9832c285" [[package]] name = "imgref" -version = "1.12.0" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7c5cedc30da3a610cac6b4ba17597bdf7152cf974e8aab3afb3d54455e371c8" +checksum = "6e44b0a4eaa4c82f441d50a963f2d5f05a787240aeee097597033e72accfd22f" [[package]] name = "indexmap" -version = "2.14.0" +version = "2.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" dependencies = [ "equivalent", - "hashbrown 0.17.0", - "serde", - "serde_core", + "hashbrown 0.17.1", ] [[package]] @@ -3448,24 +3469,14 @@ checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] name = "ipnet" -version = "2.12.0" +version = "2.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" - -[[package]] -name = "iri-string" -version = "0.7.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25e659a4bb38e810ebc252e53b5814ff908a8c58c2a9ce2fae1bbec24cbf4e20" -dependencies = [ - "memchr", - "serde", -] +checksum = "791930b43c0d5973160d90a8f3894509f2b273430f5c5c73b668636d0287c5c0" [[package]] name = "is-docker" @@ -3484,7 +3495,7 @@ checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" dependencies = [ "hermit-abi", "libc", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -3532,35 +3543,48 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "jiff" -version = "0.2.23" +version = "0.2.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a3546dc96b6d42c5f24902af9e2538e82e39ad350b0c766eb3fbf2d8f3d8359" +checksum = "0ab1baf72f08796de0260609515130699b890ac25f30e610ad894bc5856cafdb" dependencies = [ + "defmt", + "jiff-core", "jiff-static", "jiff-tzdb-platform", "log", "portable-atomic", "portable-atomic-util", "serde_core", - "windows-sys 0.52.0", + "windows-link 0.2.1", +] + +[[package]] +name = "jiff-core" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e52fe76043ccecc9005d2305ebaadf7d7fc0cc89ca6baa10a94d6bc68c7128c" +dependencies = [ + "defmt", + "log", ] [[package]] name = "jiff-static" -version = "0.2.23" +version = "0.2.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a8c8b344124222efd714b73bb41f8b5120b27a7cc1c75593a6ff768d9d05aa4" +checksum = "378268a1116ad67ae6228701118ac9f491d78fda38a40a1f1a9e1348de6f7212" dependencies = [ + "jiff-core", "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] name = "jiff-tzdb" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c900ef84826f1338a557697dc8fc601df9ca9af4ac137c7fb61d4c6f2dfd3076" +checksum = "142bd39932ad231f10513df9ab62661fead8719872150b7ad02a2df79f4e141e" [[package]] name = "jiff-tzdb-platform" @@ -3571,22 +3595,6 @@ dependencies = [ "jiff-tzdb", ] -[[package]] -name = "jni" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" -dependencies = [ - "cesu8", - "cfg-if", - "combine", - "jni-sys 0.3.1", - "log", - "thiserror 1.0.69", - "walkdir", - "windows-sys 0.45.0", -] - [[package]] name = "jni" version = "0.22.4" @@ -3599,7 +3607,7 @@ dependencies = [ "jni-sys 0.4.1", "log", "simd_cesu8", - "thiserror 2.0.18", + "thiserror 2.0.20", "walkdir", "windows-link 0.2.1", ] @@ -3614,7 +3622,7 @@ dependencies = [ "quote", "rustc_version", "simd_cesu8", - "syn", + "syn 2.0.119", ] [[package]] @@ -3642,28 +3650,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" dependencies = [ "quote", - "syn", + "syn 2.0.119", ] [[package]] name = "jobserver" -version = "0.1.34" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3" dependencies = [ - "getrandom 0.3.4", + "getrandom 0.4.3", "libc", ] [[package]] name = "js-sys" -version = "0.3.95" +version = "0.3.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2964e92d1d9dc3364cae4d718d93f227e3abb088e747d92e0395bfdedf1c12ca" +checksum = "ce57d20d1ea864ce2ac172ab472d409214f4fd359f0b2a2775abdf522e2af99e" dependencies = [ "cfg-if", "futures-util", - "once_cell", "wasm-bindgen", ] @@ -3753,12 +3760,6 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" -[[package]] -name = "leb128fmt" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" - [[package]] name = "lebe" version = "0.5.3" @@ -3767,15 +3768,15 @@ checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8" [[package]] name = "libc" -version = "0.2.184" +version = "0.2.189" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" [[package]] name = "libfuzzer-sys" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f12a681b7dd8ce12bff52488013ba614b869148d54dd79836ab85aafdd53f08d" +checksum = "a9fd2f41a1cba099f79a0b6b6c35656cf7c03351a7bae8ff0f28f25270f929d2" dependencies = [ "arbitrary", "cc", @@ -3799,21 +3800,21 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libredox" -version = "0.1.16" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c" +checksum = "61ff90caf6077a803a240f62fdbe88645a890bbca49ef8174c3cb0404362171d" dependencies = [ "bitflags 2.13.2", "libc", "plain", - "redox_syscall 0.7.4", + "redox_syscall 0.9.4", ] [[package]] name = "lilt" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f67562e5eff6b20553fa9be1c503356768420994e28f67e3eafe6f41910e57ad" +checksum = "337d4c256f7d9f2dbd633891d48ace853efa5b1554122d9220b172ad9c03c3a9" dependencies = [ "web-time", ] @@ -3857,9 +3858,9 @@ dependencies = [ [[package]] name = "litemap" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" +checksum = "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae" [[package]] name = "litrs" @@ -3886,9 +3887,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.29" +version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" dependencies = [ "value-bag", ] @@ -3911,9 +3912,9 @@ dependencies = [ [[package]] name = "lru" -version = "0.16.3" +version = "0.16.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1dc47f592c06f33f8e3aea9591776ec7c9f9e4124778ff8a3c3b87159f7e593" +checksum = "7f66e8d5d03f609abc3a39e6f08e4164ebf1447a732906d39eb9b99b7919ef39" [[package]] name = "lyon" @@ -3927,9 +3928,9 @@ dependencies = [ [[package]] name = "lyon_algorithms" -version = "1.0.19" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9815fac08e6fd96733a11dce4f9d15a3f338e96a2e2311ee21e1b738efc2bc0f" +checksum = "cdfa8785f95e57914ddb35e3b59994aeba6f5e79e9cfd03da1c269f010f36009" dependencies = [ "lyon_path", "num-traits", @@ -3958,9 +3959,9 @@ dependencies = [ [[package]] name = "lyon_tessellation" -version = "1.0.20" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e43b7e44161571868f5c931d12583592c223c5583eef86b08aa02b7048a3552" +checksum = "43b8dcf906637ecef61b3c0740c7a4e7f27caeb31257cfac0cc579ce15be6005" dependencies = [ "float_next_after", "lyon_path", @@ -4009,17 +4010,17 @@ dependencies = [ [[package]] name = "memchr" -version = "2.8.0" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" [[package]] name = "memfd" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad38eb12aea514a0466ea40a80fd8cc83637065948eb4a426e4aa46261175227" +checksum = "57804b2c9b69967f1536a56f86297e367a33b19e98852ed624b84551cdbc0d90" dependencies = [ - "rustix 1.1.4", + "rustix 1.1.5", ] [[package]] @@ -4033,9 +4034,9 @@ dependencies = [ [[package]] name = "memmap2" -version = "0.9.10" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3" +checksum = "d1219ed1b7f229ee7104d281dd01d6802fe28bb6e95d292942c4daacdeb798c0" dependencies = [ "libc", ] @@ -4099,10 +4100,20 @@ dependencies = [ ] [[package]] -name = "mio" -version = "1.2.0" +name = "miniz_oxide" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" +checksum = "b63fbc4a50860e98e7b2aa7804ded1db5cbc3aff9193adaff57a6931bf7c4b4c" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b18443e9c262bfe8fa82f51666e2642c53393f7e5c27b3e1aeab922cff5b9d8" dependencies = [ "libc", "wasi", @@ -4167,10 +4178,37 @@ dependencies = [ ] [[package]] -name = "mundy" -version = "0.2.2" +name = "multiversion" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523813c9e194ec43693805214eb112551f99382115b67f38600d724a692e7e8b" +checksum = "b4ca4bea16ffc3f443cf7d866912118196bfef4c6a1556ca00f9f9b00bb43f7c" +dependencies = [ + "multiversion-macros", +] + +[[package]] +name = "multiversion-macros" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d416831a7317ef4b08bee00b69cbbb9c8763da7959a7026244d6266869f9c83" +dependencies = [ + "proc-macro2", + "quote", + "rustversion", + "syn 3.0.6", +] + +[[package]] +name = "multiversion_no_op" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743fb55ba31b18fb1ecef6bdc9aa2743314978ac084044301a7eee33fb99a20d" + +[[package]] +name = "mundy" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f32eb0db40f2df2bcfb05c93b8f73938d4c26ce9ac8881f1df0c8d3296921a73" dependencies = [ "android-build", "async-io", @@ -4178,7 +4216,7 @@ dependencies = [ "dispatch", "futures-channel", "futures-lite", - "jni 0.21.1", + "jni", "ndk-context", "objc2 0.6.4", "objc2-app-kit 0.3.2", @@ -4219,7 +4257,7 @@ dependencies = [ "once_cell", "rustc-hash 1.1.0", "spirv", - "thiserror 2.0.18", + "thiserror 2.0.20", "unicode-ident", ] @@ -4276,6 +4314,15 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" +[[package]] +name = "no_std_io2" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418abd1b6d34fbf6cae440dc874771b0525a604428704c76e48b29a5e67b8003" +dependencies = [ + "memchr", +] + [[package]] name = "nom" version = "8.0.0" @@ -4306,24 +4353,34 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "num-bigint" -version = "0.4.6" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +checksum = "c89e69e7e0f03bea5ef08013795c25018e101932225a656383bd384495ecc367" dependencies = [ "num-integer", "num-traits", ] [[package]] -name = "num-conv" -version = "0.2.1" +name = "num-complex" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "bytemuck", + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" [[package]] name = "num-derive" @@ -4333,14 +4390,14 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] name = "num-integer" -version = "0.1.46" +version = "0.1.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +checksum = "7ce2d95d4b3734dc35aa2f45e1aa22cd416814592a4f9d9205e11affd5b8e10b" dependencies = [ "num-traits", ] @@ -4385,7 +4442,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -4690,26 +4747,24 @@ checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" [[package]] name = "open" -version = "5.3.3" +version = "5.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43bb73a7fa3799b198970490a51174027ba0d4ec504b03cd08caf513d40024bc" +checksum = "aa576c76302b7b808eecc68061e67336c47833ef9d22caa74dda10fa9675eebc" dependencies = [ "is-wsl", "libc", - "pathdiff", ] [[package]] name = "openssl" -version = "0.10.76" +version = "0.10.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "951c002c75e16ea2c65b8c7e4d3d51d5530d8dfa7d060b4776828c88cfb18ecf" +checksum = "77823a27f0babb03091cb9ed9ef80af3b39dbc82f97e8fa530374b7dafd87a45" dependencies = [ "bitflags 2.13.2", "cfg-if", "foreign-types 0.3.2", "libc", - "once_cell", "openssl-macros", "openssl-sys", ] @@ -4722,7 +4777,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -4733,9 +4788,9 @@ checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" [[package]] name = "openssl-sys" -version = "0.9.112" +version = "0.9.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57d55af3b3e226502be1526dfdba67ab0e9c96fc293004e79576b2b9edb0dbdb" +checksum = "b47e7e6bb2c38cd930d25a23b40fa52e068c10e85f3e03a7f5ba5aaca5713695" dependencies = [ "cc", "libc", @@ -4760,9 +4815,9 @@ dependencies = [ [[package]] name = "orbclient" -version = "0.3.51" +version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59aed3b33578edcfa1bc96a321d590d31832b6ad55a26f0313362ce687e9abd6" +checksum = "5df339f526ea9a60e371768d50efc2f2508c7203290731565d1f7a6f71d21747" dependencies = [ "libc", "libredox", @@ -4770,9 +4825,9 @@ dependencies = [ [[package]] name = "ordered-float" -version = "5.3.0" +version = "5.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7d950ca161dc355eaf28f82b11345ed76c6e1f6eb1f4f4479e0323b9e2fbd0e" +checksum = "8c7c9e0d9b23589f26070720bac724174bfec1083e82f7854cdd0267518343c0" dependencies = [ "num-traits", ] @@ -4808,7 +4863,7 @@ dependencies = [ "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -4822,28 +4877,34 @@ dependencies = [ [[package]] name = "palette" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cbf71184cc5ecc2e4e1baccdb21026c20e5fc3dcf63028a086131b3ab00b6e6" +checksum = "ddeed8580d347d2abf3dcf06a5f0b3dc020258338526b277847cd4248a70fc64" dependencies = [ "approx", - "fast-srgb8", "palette_derive", + "palette_math", "phf", ] [[package]] name = "palette_derive" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5030daf005bface118c096f510ffb781fc28f9ab6a32ab224d8631be6851d30" +checksum = "88537020289b719d81be994ccf1bbf4990f477e2f69ee52fe3e45f43a02e56be" dependencies = [ "by_address", "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] +[[package]] +name = "palette_math" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e6eb142958d64335fb0e345c5b9ead2ecd6fc438c307e9d7d3c4fd428dbaf12" + [[package]] name = "pane_grid" version = "0.1.0" @@ -4892,12 +4953,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35fb2e5f958ec131621fdd531e9fc186ed768cbe395337403ae56c17a74c68ec" -[[package]] -name = "pathdiff" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" - [[package]] name = "percent-encoding" version = "2.3.2" @@ -4906,42 +4961,18 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "phf" -version = "0.11.3" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" -dependencies = [ - "phf_macros", - "phf_shared", -] - -[[package]] -name = "phf_generator" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" dependencies = [ "phf_shared", - "rand 0.8.5", -] - -[[package]] -name = "phf_macros" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" -dependencies = [ - "phf_generator", - "phf_shared", - "proc-macro2", - "quote", - "syn", ] [[package]] name = "phf_shared" -version = "0.11.3" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" dependencies = [ "siphasher", ] @@ -4961,22 +4992,22 @@ checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" [[package]] name = "pin-project" -version = "1.1.11" +version = "1.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517" +checksum = "2466b2336ed02bcdca6b294417127b90ec92038d1d5c4fbeac971a922e0e0924" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.11" +version = "1.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6" +checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -5004,9 +5035,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.32" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +checksum = "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548" [[package]] name = "plain" @@ -5016,13 +5047,13 @@ checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" [[package]] name = "plist" -version = "1.8.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "740ebea15c5d1428f910cd1a5f52cebf8d25006245ed8ade92702f4943d91e07" +checksum = "2896bade328c13f7042a297ea5ac5b0951f6cf989dea5f32c2fd98da398195cb" dependencies = [ - "base64 0.22.1", + "base64 0.23.1", "indexmap", - "quick-xml 0.38.4", + "quick-xml 0.42.0", "serde", "time", ] @@ -5065,7 +5096,7 @@ dependencies = [ "crc32fast", "fdeflate", "flate2", - "miniz_oxide", + "miniz_oxide 0.8.9", ] [[package]] @@ -5078,7 +5109,7 @@ dependencies = [ "crc32fast", "fdeflate", "flate2", - "miniz_oxide", + "miniz_oxide 0.8.9", ] [[package]] @@ -5087,7 +5118,7 @@ version = "0.1.0" dependencies = [ "getrandom 0.2.17", "iced", - "rand 0.8.5", + "rand 0.8.8", "reqwest", "serde", "serde_json", @@ -5103,7 +5134,7 @@ dependencies = [ "concurrent-queue", "hermit-abi", "pin-project-lite", - "rustix 1.1.4", + "rustix 1.1.5", "windows-sys 0.61.2", ] @@ -5115,24 +5146,24 @@ checksum = "2f3a9f18d041e6d0e102a0a46750538147e5e8992d3b4873aaafee2520b00ce3" [[package]] name = "portable-atomic" -version = "1.13.1" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" +checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85" [[package]] name = "portable-atomic-util" -version = "0.2.6" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "091397be61a01d4be58e7841595bd4bfedb15f1cd54977d79b8271e94ed799a3" +checksum = "10ab3eb7f3becc3a1cbc4f2c6f20267996cfc1a6467a873763411b136a122715" dependencies = [ "portable-atomic", ] [[package]] name = "potential_utf" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +checksum = "d83eb9bc6d8e5cf568e7a1101d60ee05e81ed50ea106026f3d18deeb046d7661" dependencies = [ "zerovec", ] @@ -5158,16 +5189,6 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa" -[[package]] -name = "prettyplease" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" -dependencies = [ - "proc-macro2", - "syn", -] - [[package]] name = "proc-macro-crate" version = "3.5.0" @@ -5179,9 +5200,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.106" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" dependencies = [ "unicode-ident", ] @@ -5194,28 +5215,28 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", "version_check", "yansi", ] [[package]] name = "profiling" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773" +checksum = "3d595e54a326bc53c1c197b32d295e14b169e3cfeaa8dc82b529f947fba6bcf5" dependencies = [ "profiling-procmacros", ] [[package]] name = "profiling-procmacros" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b" +checksum = "4488a4a36b9a4ba6b9334a32a39971f77c1436ec82c38707bce707699cc3bbcb" dependencies = [ "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -5245,10 +5266,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "007d8adb5ddab6f8e3f491ac63566a7d5002cc7ed73901f72057943fa71ae1ae" [[package]] -name = "pxfm" -version = "0.1.28" +name = "pulp" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5a041e753da8b807c9255f28de81879c78c876392ff2469cde94799b2896b9d" +checksum = "046aa45b989642ec2e4717c8e72d677b13edd831a4d3b6cf37d9a3e54912496a" +dependencies = [ + "bytemuck", + "cfg-if", + "libm", + "num-complex", + "paste", + "pulp-wasm-simd-flag", + "raw-cpuid", + "reborrow", + "version_check", +] + +[[package]] +name = "pulp-wasm-simd-flag" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d8f70e07b9c3962945a74e59ca1c511bba65b6419468acc217c457d93f3c740" + +[[package]] +name = "pxfm" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d55d956fa96f5ec02be2e13af0e20391a5aa83d6a074e3ad368959d0fab299ea" [[package]] name = "qoi" @@ -5280,28 +5324,27 @@ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" [[package]] name = "quick-xml" -version = "0.38.4" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b66c2058c55a409d601666cffe35f04333cf1013010882cec174a7467cd4e21c" +checksum = "e660451e55124f798a69a5af3f49ccfbefbd41910eefd25caf2393e1f3473ec1" dependencies = [ "memchr", - "serde", ] [[package]] name = "quick-xml" -version = "0.39.2" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "958f21e8e7ceb5a1aa7fa87fab28e7c75976e0bfe7e23ff069e0a260f894067d" +checksum = "41b1177fdf999d2321d3fb46ff47159d9c1fb9ad66a4879f8c50a0b504615e9b" dependencies = [ "memchr", ] [[package]] name = "quote" -version = "1.0.45" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" dependencies = [ "proc-macro2", ] @@ -5320,9 +5363,9 @@ checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" [[package]] name = "rand" -version = "0.8.5" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "e058c7de0b26af77780c769414d6257830bb240f3c38477dbc2c16e5f54d6d4c" dependencies = [ "libc", "rand_chacha 0.3.1", @@ -5331,9 +5374,9 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.2" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.5", @@ -5341,13 +5384,13 @@ dependencies = [ [[package]] name = "rand" -version = "0.10.0" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc266eb313df6c5c09c1c7b1fbe2510961e5bcd3add930c1e31f7ed9da0feff8" +checksum = "65c9fb96cbc91e3478eaae79a69fcd3f1ae4ad052e471fe6732fff548984b4af" dependencies = [ "chacha20", - "getrandom 0.4.2", - "rand_core 0.10.0", + "getrandom 0.4.3", + "rand_core 0.10.1", ] [[package]] @@ -5390,9 +5433,9 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" [[package]] name = "range-alloc" @@ -5402,9 +5445,9 @@ checksum = "ca45419789ae5a7899559e9512e58ca889e41f04f1f2445e9f4b290ceccd1d08" [[package]] name = "rangemap" -version = "1.7.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "973443cf09a9c8656b574a866ab68dfa19f0867d0340648c7d2f6a71b8a8ea68" +checksum = "a611d15b50743feb4c76b7d03edcb0e64f399c26961e4efe6975bc398be6aa3d" [[package]] name = "rav1e" @@ -5433,10 +5476,10 @@ dependencies = [ "num-traits", "paste", "profiling", - "rand 0.9.2", + "rand 0.9.5", "rand_chacha 0.9.0", "simd_helpers", - "thiserror 2.0.18", + "thiserror 2.0.20", "v_frame", "wasm-bindgen", ] @@ -5456,6 +5499,15 @@ dependencies = [ "rgb", ] +[[package]] +name = "raw-cpuid" +version = "11.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" +dependencies = [ + "bitflags 2.13.2", +] + [[package]] name = "raw-window-handle" version = "0.6.2" @@ -5464,9 +5516,9 @@ checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" [[package]] name = "rayon" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" +checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" dependencies = [ "either", "rayon-core", @@ -5490,7 +5542,34 @@ checksum = "7b634fabf032fab15307ffd272149b622260f55974d9fad689292a5d33df02e5" dependencies = [ "bytemuck", "core_maths", - "font-types", + "font-types 0.11.3", +] + +[[package]] +name = "read-fonts" +version = "0.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046a7d674daf459825b32f5062056d6882db0d2f5a479fbd76ccfc870ac18709" +dependencies = [ + "bytemuck", + "font-types 0.12.5", + "once_cell", +] + +[[package]] +name = "reborrow" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03251193000f4bd3b042892be858ee50e8b3719f2b08e5833ac4353724632430" + +[[package]] +name = "redox_event" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5018d583d6d2f5499352aea8d177e9067d1eb03ab17c78169d5ba7a30001b15" +dependencies = [ + "bitflags 2.13.2", + "libredox", ] [[package]] @@ -5504,9 +5583,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.7.4" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f450ad9c3b1da563fb6948a8e0fb0fb9269711c9c73d9ea1de5058c79c8d643a" +checksum = "737970939a87c6fa31e7acad13307bccbb017a073b695b6089a2c484f929e20e" dependencies = [ "bitflags 2.13.2", ] @@ -5524,20 +5603,19 @@ dependencies = [ [[package]] name = "redox_users" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" +checksum = "60dc65c0ff1a7ae1294b0c67b9f14baf70b644404010370171787bfac1038fc0" dependencies = [ - "getrandom 0.2.17", "libredox", - "thiserror 2.0.18", + "thiserror 2.0.20", ] [[package]] name = "regex" -version = "1.12.3" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d" dependencies = [ "aho-corasick", "memchr", @@ -5547,9 +5625,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.14" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2" dependencies = [ "aho-corasick", "memchr", @@ -5558,9 +5636,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" [[package]] name = "renderdoc-sys" @@ -5579,11 +5657,11 @@ dependencies = [ "encoding_rs", "futures-core", "futures-util", - "h2 0.4.13", - "http 1.4.0", - "http-body 1.0.1", + "h2 0.4.19", + "http 1.5.0", + "http-body 1.1.0", "http-body-util", - "hyper 1.9.0", + "hyper 1.11.1", "hyper-rustls", "hyper-tls", "hyper-util", @@ -5623,7 +5701,7 @@ dependencies = [ "pico-args", "rgb", "svgtypes", - "tiny-skia", + "tiny-skia 0.11.4", "usvg", "zune-jpeg 0.4.21", ] @@ -5689,9 +5767,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc-hash" -version = "2.1.2" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" [[package]] name = "rustc_version" @@ -5717,15 +5795,15 @@ dependencies = [ [[package]] name = "rustix" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +checksum = "891efababe418670775f199f0d233d84843c227a0949a883ce15b37c78d6629d" dependencies = [ "bitflags 2.13.2", "errno", "libc", "linux-raw-sys 0.12.1", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -5744,22 +5822,22 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.37" +version = "0.23.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" +checksum = "0d41d731c7d2f962d1ccc364cec258de3c0e93b38c2fb3ba97ac74513048d634" dependencies = [ "once_cell", "rustls-pki-types", - "rustls-webpki 0.103.11", + "rustls-webpki 0.103.15", "subtle", "zeroize", ] [[package]] name = "rustls-pki-types" -version = "1.14.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" +checksum = "2f4925028c7eb5d1fcdaf196971378ed9d2c1c4efc7dc5d011256f76c99c0a96" dependencies = [ "zeroize", ] @@ -5777,9 +5855,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.11" +version = "0.103.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20a6af516fea4b20eccceaf166e8aa666ac996208e8a644ce3ef5aa783bc7cd4" +checksum = "f3c3cf1d8b1e7d4927e2d154c3fcb02979afb9939629c62cd9048d4f07b60ac2" dependencies = [ "ring", "rustls-pki-types", @@ -5788,9 +5866,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" [[package]] name = "rustybuzz" @@ -5865,15 +5943,15 @@ dependencies = [ [[package]] name = "sctk-adwaita" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd3accc0f3f4bbaf2c9e1957a030dc582028130c67660d44c0a0345a22ca69b" +checksum = "ea2a4360b9abcdcee43809e6fc11d6d61ca5d25734026a8fc46c2883eea3f13f" dependencies = [ "ab_glyph", "log", - "memmap2 0.9.10", + "memmap2 0.9.11", "smithay-client-toolkit 0.20.0", - "tiny-skia", + "tiny-skia 0.12.0", ] [[package]] @@ -5990,9 +6068,9 @@ dependencies = [ [[package]] name = "self_cell" -version = "1.2.2" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b12e76d157a900eb52e81bc6e9f3069344290341720e9178cde2407113ac8d89" +checksum = "2ab42ca02749e120097e328d91d415325bdf43b1c72c4c8badf37375fe40a813" [[package]] name = "semver" @@ -6006,9 +6084,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" dependencies = [ "serde_core", "serde_derive", @@ -6016,29 +6094,29 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.6", ] [[package]] name = "serde_json" -version = "1.0.149" +version = "1.0.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" dependencies = [ "itoa", "memchr", @@ -6049,13 +6127,13 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.20" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" +checksum = "8d3b1629de253c70a0508c3899572da79ca359fdab27c7920ff00406df418906" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.6", ] [[package]] @@ -6081,9 +6159,9 @@ dependencies = [ [[package]] name = "sha1" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +checksum = "a978451301f4db1d02937a4ab3ccce137717b81826e79b7d49ffe3244a13c3b8" dependencies = [ "cfg-if", "cpufeatures 0.2.17", @@ -6112,16 +6190,16 @@ dependencies = [ [[package]] name = "shlex" -version = "1.3.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" [[package]] name = "sierpinski_triangle" version = "0.1.0" dependencies = [ "iced", - "rand 0.8.5", + "rand 0.8.8", ] [[package]] @@ -6136,15 +6214,15 @@ dependencies = [ [[package]] name = "simd-adler32" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" +checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" [[package]] name = "simd_cesu8" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94f90157bb87cddf702797c5dadfa0be7d266cdf49e22da2fcaa32eff75b2c33" +checksum = "11031e251abf8611c80f460e19dbdeb54a66db918e49c65a7065b46ac7aec520" dependencies = [ "rustc_version", "simdutf8", @@ -6176,9 +6254,9 @@ dependencies = [ [[package]] name = "siphasher" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" +checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649" [[package]] name = "sipper" @@ -6197,7 +6275,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fbdfe3d2475fbd7ddd1f3e5cf8288a30eb3e5f95832829570cd88115a7434ac" dependencies = [ "bytemuck", - "read-fonts", + "read-fonts 0.37.0", +] + +[[package]] +name = "skrifa" +version = "0.44.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819ab7d62b1d3e72d9d9dea5650bac30424f9111364bb94928dbf5ecad1baa68" +dependencies = [ + "bytemuck", + "read-fonts 0.41.0", ] [[package]] @@ -6224,9 +6312,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.15.1" +version = "1.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +checksum = "ba467056f1b547ed52077911161fc86985becbc60e8e1857c8a144dab0def891" [[package]] name = "smithay-client-toolkit" @@ -6240,7 +6328,7 @@ dependencies = [ "cursor-icon", "libc", "log", - "memmap2 0.9.10", + "memmap2 0.9.11", "pkg-config", "rustix 0.38.44", "thiserror 1.0.69", @@ -6268,15 +6356,15 @@ dependencies = [ "cursor-icon", "libc", "log", - "memmap2 0.9.10", + "memmap2 0.9.11", "pkg-config", - "rustix 1.1.4", - "thiserror 2.0.18", + "rustix 1.1.5", + "thiserror 2.0.20", "wayland-backend", "wayland-client", "wayland-csd-frame", "wayland-cursor", - "wayland-protocols 0.32.12", + "wayland-protocols 0.32.13", "wayland-protocols-experimental", "wayland-protocols-misc", "wayland-protocols-wlr 0.3.12", @@ -6335,18 +6423,18 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.3" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" +checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] name = "softbuffer" version = "0.4.1" -source = "git+https://github.com/pop-os/softbuffer?tag=cosmic-4.0#a3f77e251e7422803f693df6e3fc313c010c4dcb" +source = "git+https://github.com/pop-os/softbuffer?tag=cosmic-4.0#c2b2c19ddb38ff17495643699f97cb1f2064a1be" dependencies = [ "as-raw-xcb-connection", "bytemuck", @@ -6358,7 +6446,7 @@ dependencies = [ "foreign-types 0.5.0", "js-sys", "log", - "memmap2 0.9.10", + "memmap2 0.9.11", "objc", "raw-window-handle", "redox_syscall 0.5.18", @@ -6378,15 +6466,15 @@ name = "solar_system" version = "0.1.0" dependencies = [ "iced", - "rand 0.8.5", + "rand 0.8.8", "tracing-subscriber", ] [[package]] name = "spin" -version = "0.9.8" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +checksum = "3763264f6b73151db08c50ff20d7d8a0b8796e021cdea7ceedad07b80155fa0e" [[package]] name = "spirv" @@ -6436,18 +6524,18 @@ dependencies = [ [[package]] name = "subsecond" -version = "0.7.4" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dbb9f2928b6654ccc28d4ddfef5213e97ed66afed4907774d049b376c62a838" +checksum = "d350d5788fa94d560d92269266a50efc77b036bfca6675e420b64df7b3211f37" dependencies = [ "js-sys", "libc", "libloading", "memfd", - "memmap2 0.9.10", + "memmap2 0.9.11", "serde", "subsecond-types", - "thiserror 2.0.18", + "thiserror 2.0.20", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", @@ -6455,9 +6543,9 @@ dependencies = [ [[package]] name = "subsecond-types" -version = "0.7.4" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388bb28e6ddbee717745963b8932d9a6e24a5d3c93350655f733e938de04d81f" +checksum = "dcf32d66269b5fbb8558334e8d22b657b2f7af0dd2ef56c231541099a862e464" dependencies = [ "serde", ] @@ -6493,20 +6581,31 @@ dependencies = [ [[package]] name = "swash" -version = "0.2.7" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "842f3cd369c2ba38966204f983eaa5e54a8e84a7d7159ed36ade2b6c335aae64" +checksum = "6c2499c2d826531388872b2268718aed907a39bd785ab0dcfe57fab26283f92e" dependencies = [ - "skrifa", + "skrifa 0.44.0", "yazi", "zeno", ] [[package]] name = "syn" -version = "2.0.117" +version = "2.0.119" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8593e8e72159ed2257d083c7a454a85cbf854f37a0966d8d483aff8c8a3ebcee" dependencies = [ "proc-macro2", "quote", @@ -6524,13 +6623,13 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.13.2" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +checksum = "901704edd0dfe137f1987838ee4f259e4e063c31371bdb423f7ae38ec6f77f02" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.6", ] [[package]] @@ -6549,7 +6648,7 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "thiserror 2.0.18", + "thiserror 2.0.20", "walkdir", "yaml-rust", ] @@ -6620,9 +6719,9 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.13.3" +version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df7f62577c25e07834649fc3b39fafdc597c0a3527dc1c60129201ccfcbaa50c" +checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca" [[package]] name = "tempfile" @@ -6631,10 +6730,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand", - "getrandom 0.4.2", + "getrandom 0.4.3", "once_cell", - "rustix 1.1.4", - "windows-sys 0.52.0", + "rustix 1.1.5", + "windows-sys 0.61.2", ] [[package]] @@ -6651,7 +6750,7 @@ name = "the_matrix" version = "0.1.0" dependencies = [ "iced", - "rand 0.8.5", + "rand 0.8.8", "tracing-subscriber", ] @@ -6666,11 +6765,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.18" +version = "2.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f" dependencies = [ - "thiserror-impl 2.0.18", + "thiserror-impl 2.0.20", ] [[package]] @@ -6681,25 +6780,25 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] name = "thiserror-impl" -version = "2.0.18" +version = "2.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.6", ] [[package]] name = "thread_local" -version = "1.1.9" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +checksum = "1ad99c4c6d32803332c548b1af0540b357b3f5fc0be8f6c6bfe8b2e6ae784070" dependencies = [ "cfg-if", ] @@ -6720,12 +6819,11 @@ dependencies = [ [[package]] name = "time" -version = "0.3.47" +version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +checksum = "cdb87b95ec50ddfa440816d227a17b2ccbdda963a316a727fda0fc4334f7d134" dependencies = [ "deranged", - "itoa", "num-conv", "powerfmt", "serde_core", @@ -6735,15 +6833,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" +checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" [[package]] name = "time-macros" -version = "0.2.27" +version = "0.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +checksum = "7e689342a48d2ea927c87ea50cabf8594854bf940e9310208848d680d668ed85" dependencies = [ "num-conv", "time-core", @@ -6761,7 +6859,21 @@ dependencies = [ "cfg-if", "log", "png 0.17.16", - "tiny-skia-path", + "tiny-skia-path 0.11.4", +] + +[[package]] +name = "tiny-skia" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47ffee5eaaf5527f630fb0e356b90ebdec84d5d18d937c5e440350f88c5a91ea" +dependencies = [ + "arrayref", + "arrayvec", + "bytemuck", + "cfg-if", + "log", + "tiny-skia-path 0.12.0", ] [[package]] @@ -6776,13 +6888,24 @@ dependencies = [ ] [[package]] -name = "tiny-xlib" -version = "0.2.4" +name = "tiny-skia-path" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0324504befd01cab6e0c994f34b2ffa257849ee019d3fb3b64fb2c858887d89e" +checksum = "edca365c3faccca67d06593c5980fa6c57687de727a03131735bb85f01fdeeb9" +dependencies = [ + "arrayref", + "bytemuck", + "strict-num", +] + +[[package]] +name = "tiny-xlib" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a90a0ca3ee6a69f2ad28fd11621a4c3f03b371f366be500b64df260c4ffbafb4" dependencies = [ "as-raw-xcb-connection", - "ctor-lite", + "ctor", "libloading", "pkg-config", "tracing", @@ -6790,9 +6913,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +checksum = "b1e27c91459209c2986af3dcf603a5a74a4368754ce37414f59acc971167f643" dependencies = [ "displaydoc", "zerovec", @@ -6810,18 +6933,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.11.0" +version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +checksum = "fd3ca314f692efd6c868f8408f53fe444634a845f96c028b97d35f6a1f79f0ee" [[package]] name = "toast" @@ -6848,29 +6962,29 @@ dependencies = [ [[package]] name = "tokio" -version = "1.51.1" +version = "1.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f66bf9585cda4b724d3e78ab34b73fb2bbaba9011b9bfdf69dc836382ea13b8c" +checksum = "202caea871b69668250d242070849eb495be178ed697a3e98aebce5bc81a0bed" dependencies = [ "bytes", "libc", "mio", "pin-project-lite", "signal-hook-registry", - "socket2 0.6.3", + "socket2 0.6.5", "tokio-macros", "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.7.0" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" +checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.6", ] [[package]] @@ -6896,19 +7010,19 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.26.4" +version = "0.26.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +checksum = "b0c85f2c3ef0b1cd58b36682f4b17aaa995f0e5db534d85692b4903abce21f67" dependencies = [ - "rustls 0.23.37", + "rustls 0.23.45", "tokio", ] [[package]] name = "tokio-stream" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" +checksum = "a3d06f0b082ba57c26b79407372e57cf2a1e28124f78e9479fe80322cf53420b" dependencies = [ "futures-core", "pin-project-lite", @@ -6929,22 +7043,23 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.18" +version = "0.7.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" +checksum = "494815d09bf52b5548659851081238f0ca39ff638363907596da739561c62c52" dependencies = [ "bytes", "futures-core", "futures-sink", + "libc", "pin-project-lite", "tokio", ] [[package]] name = "toml" -version = "1.1.2+spec-1.1.0" +version = "1.1.6+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee" +checksum = "920602543f0911ab71da12c50d59701da54c196d1a2bf5cb4b75667f137a406a" dependencies = [ "indexmap", "serde_core", @@ -6952,7 +7067,7 @@ dependencies = [ "toml_datetime", "toml_parser", "toml_writer", - "winnow 1.0.1", + "winnow", ] [[package]] @@ -6966,30 +7081,30 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.25.11+spec-1.1.0" +version = "0.25.15+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b" +checksum = "1340ea94a5856333492c9064b02c778b191dd2c853778d9609debdcdfea3a614" dependencies = [ "indexmap", "toml_datetime", "toml_parser", - "winnow 1.0.1", + "winnow", ] [[package]] name = "toml_parser" -version = "1.1.2+spec-1.1.0" +version = "1.1.3+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" +checksum = "1d38ac1cf9b95face32296c0a3ede1fdc270627c9d9c02a7274dd6d960dc4d56" dependencies = [ - "winnow 1.0.1", + "winnow", ] [[package]] name = "toml_writer" -version = "1.1.1+spec-1.1.0" +version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" +checksum = "7d56353a2a665ad0f41a421187180aab746c8c325620617ad883a99a1cbe66d2" [[package]] name = "tooltip" @@ -7026,20 +7141,20 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.8" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" +checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" dependencies = [ "bitflags 2.13.2", "bytes", "futures-util", - "http 1.4.0", - "http-body 1.0.1", - "iri-string", + "http 1.5.0", + "http-body 1.1.0", "pin-project-lite", "tower", "tower-layer", "tower-service", + "url", ] [[package]] @@ -7074,7 +7189,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -7136,10 +7251,10 @@ dependencies = [ "byteorder", "bytes", "data-encoding", - "http 1.4.0", + "http 1.5.0", "httparse", "log", - "rand 0.8.5", + "rand 0.8.8", "rustls 0.22.4", "rustls-pki-types", "sha1", @@ -7161,9 +7276,9 @@ dependencies = [ [[package]] name = "typenum" -version = "1.19.0" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" [[package]] name = "uds_windows" @@ -7173,7 +7288,7 @@ checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e" dependencies = [ "memoffset", "tempfile", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -7202,9 +7317,9 @@ checksum = "ce61d488bcdc9bc8b5d1772c404828b17fc481c0a582b5581e95fb233aef503e" [[package]] name = "unicode-ident" -version = "1.0.24" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954" [[package]] name = "unicode-linebreak" @@ -7226,9 +7341,9 @@ checksum = "383ad40bb927465ec0ce7720e033cb4ca06912855fc35db31b5755d0de75b1ee" [[package]] name = "unicode-segmentation" -version = "1.13.2" +version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" [[package]] name = "unicode-vo" @@ -7242,12 +7357,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" -[[package]] -name = "unicode-xid" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" - [[package]] name = "untrusted" version = "0.9.0" @@ -7299,7 +7408,7 @@ dependencies = [ "siphasher", "strict-num", "svgtypes", - "tiny-skia-path", + "tiny-skia-path 0.11.4", "unicode-bidi", "unicode-script", "unicode-vo", @@ -7320,13 +7429,13 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "uuid" -version = "1.23.0" +version = "1.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ac8b6f42ead25368cf5b098aeb3dc8a1a2c05a3eee8a9a1a68c640edbfc79d9" +checksum = "2ef6dac1e96601b4fb3acccccff2139741fcb757cb9a36089bf5be91cfb285ce" dependencies = [ - "getrandom 0.4.2", + "getrandom 0.4.3", "js-sys", - "rand 0.10.0", + "rand 0.10.3", "serde_core", "wasm-bindgen", ] @@ -7350,9 +7459,9 @@ checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" [[package]] name = "value-bag" -version = "1.12.0" +version = "1.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ba6f5989077681266825251a52748b8c1d8a4ad098cc37e440103d0ea717fc0" +checksum = "2799ffb329a792ecfd902b71306c8a815a6ef1c0470fa9953a6aa4d4cecbe511" [[package]] name = "vcpkg" @@ -7450,27 +7559,18 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" -version = "1.0.2+wasi-0.2.9" +version = "1.0.4+wasi-0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" -dependencies = [ - "wit-bindgen", -] - -[[package]] -name = "wasip3" -version = "0.4.0+wasi-0.3.0-rc-2026-01-06" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" dependencies = [ "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.118" +version = "0.2.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf938a0bacb0469e83c1e148908bd7d5a6010354cf4fb73279b7447422e3a89" +checksum = "aecb87a33d3b0c5e3b7aa46336eaf486cffafbd281b195e4c8b80d50df2351bf" dependencies = [ "cfg-if", "once_cell", @@ -7481,9 +7581,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.68" +version = "0.4.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f371d383f2fb139252e0bfac3b81b265689bf45b6874af544ffa4c975ac1ebf8" +checksum = "6ef4c5d3d2cdf5c54f4231181768f5510842e350db025faf1f7163b1030ed928" dependencies = [ "js-sys", "wasm-bindgen", @@ -7491,9 +7591,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.118" +version = "0.2.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eeff24f84126c0ec2db7a449f0c2ec963c6a49efe0698c4242929da037ca28ed" +checksum = "a690d511e3c1a8b3a55e33511e3c2c00c78415cd23650f32b808627f5696b9ed" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -7501,48 +7601,26 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.118" +version = "0.2.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d08065faf983b2b80a79fd87d8254c409281cf7de75fc4b773019824196c904" +checksum = "411e4887f0071ef2d2164a9d5fdf2d20efbef78fccd3a78b0c10a1dc5295e48a" dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn", + "syn 3.0.6", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.118" +version = "0.2.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd04d9e306f1907bd13c6361b5c6bfc7b3b3c095ed3f8a9246390f8dbdee129" +checksum = "81941cd78d0c92026c33e5e01312845a4cb1e9af3407f9134b100dd03144103e" dependencies = [ "unicode-ident", ] -[[package]] -name = "wasm-encoder" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" -dependencies = [ - "leb128fmt", - "wasmparser", -] - -[[package]] -name = "wasm-metadata" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" -dependencies = [ - "anyhow", - "indexmap", - "wasm-encoder", - "wasmparser", -] - [[package]] name = "wasm-streams" version = "0.4.2" @@ -7556,18 +7634,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "wasmparser" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" -dependencies = [ - "bitflags 2.13.2", - "hashbrown 0.15.5", - "indexmap", - "semver", -] - [[package]] name = "wasmtimer" version = "0.4.3" @@ -7584,13 +7650,13 @@ dependencies = [ [[package]] name = "wayland-backend" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2857dd20b54e916ec7253b3d6b4d5c4d7d4ca2c33c2e11c6c76a99bd8744755d" +checksum = "38a91b4eaddff87b1cd1074985e3713da4af2c49742d1b356b2c01670a67a078" dependencies = [ "cc", "downcast-rs", - "rustix 1.1.4", + "rustix 1.1.5", "scoped-tls", "smallvec", "wayland-sys", @@ -7598,12 +7664,12 @@ dependencies = [ [[package]] name = "wayland-client" -version = "0.31.14" +version = "0.31.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c7c96bb74690c3189b5c9cb4ca1627062bb23693a4fad9d8c3de958260144" +checksum = "e3c36a0f861ad76d0901f2800b46321410d9f73f2ea88aac0650d86c32688073" dependencies = [ "bitflags 2.13.2", - "rustix 1.1.4", + "rustix 1.1.5", "wayland-backend", "wayland-scanner", ] @@ -7625,7 +7691,7 @@ version = "0.31.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a52d18780be9b1314328a3de5f930b73d2200112e3849ca6cb11822793fb34d" dependencies = [ - "rustix 1.1.4", + "rustix 1.1.5", "wayland-client", "xcursor", ] @@ -7644,9 +7710,9 @@ dependencies = [ [[package]] name = "wayland-protocols" -version = "0.32.12" +version = "0.32.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "563a85523cade2429938e790815fd7319062103b9f4a2dc806e9b53b95982d8f" +checksum = "23d0c813de3daa2ed6520af85a3bd49b0e722a3078506899aa9686fea58dc4b6" dependencies = [ "bitflags 2.13.2", "wayland-backend", @@ -7664,7 +7730,7 @@ dependencies = [ "bitflags 2.13.2", "wayland-backend", "wayland-client", - "wayland-protocols 0.32.12", + "wayland-protocols 0.32.13", "wayland-scanner", ] @@ -7677,7 +7743,7 @@ dependencies = [ "bitflags 2.13.2", "wayland-backend", "wayland-client", - "wayland-protocols 0.32.12", + "wayland-protocols 0.32.13", "wayland-scanner", ] @@ -7690,7 +7756,7 @@ dependencies = [ "bitflags 2.13.2", "wayland-backend", "wayland-client", - "wayland-protocols 0.32.12", + "wayland-protocols 0.32.13", "wayland-scanner", ] @@ -7716,31 +7782,31 @@ dependencies = [ "bitflags 2.13.2", "wayland-backend", "wayland-client", - "wayland-protocols 0.32.12", + "wayland-protocols 0.32.13", "wayland-scanner", "wayland-server", ] [[package]] name = "wayland-scanner" -version = "0.31.10" +version = "0.31.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c324a910fd86ebdc364a3e61ec1f11737d3b1d6c273c0239ee8ff4bc0d24b4a" +checksum = "338e30461b3a2b67d70eb30a6d89f8e0c93a833e07d2ae89085cd070c4a00ac0" dependencies = [ "proc-macro2", - "quick-xml 0.39.2", + "quick-xml 0.41.0", "quote", ] [[package]] name = "wayland-server" -version = "0.31.13" +version = "0.31.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc1846eb04c49182e04f4a099e2a830a2b745610bbc1d61246e206f29c7000a0" +checksum = "0dde9c29be0f723a573977de51ee455bf3dfa03652730a74f9dd3b337e374d75" dependencies = [ "bitflags 2.13.2", "downcast-rs", - "rustix 1.1.4", + "rustix 1.1.5", "wayland-backend", "wayland-scanner", ] @@ -7759,9 +7825,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.95" +version = "0.3.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f2dfbb17949fa2088e5d39408c48368947b86f7834484e87b73de55bc14d97d" +checksum = "9fbddc4a036f00ec4f18c83445bd3115cb306a91da554919a099d9222fe4a7f8" dependencies = [ "js-sys", "wasm-bindgen", @@ -7779,15 +7845,15 @@ dependencies = [ [[package]] name = "webbrowser" -version = "1.2.0" +version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe985f41e291eecef5e5c0770a18d28390addb03331c043964d9e916453d6f16" +checksum = "62c35be770821a214dbc362fc26908c853e776c0004294d0b10b8a6bad582f94" dependencies = [ - "core-foundation 0.10.1", - "jni 0.22.4", + "jni", "log", "ndk-context", "objc2 0.6.4", + "objc2-app-kit 0.3.2", "objc2-foundation 0.3.2", "url", "web-sys", @@ -7799,14 +7865,14 @@ version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" dependencies = [ - "webpki-roots 1.0.6", + "webpki-roots 1.0.9", ] [[package]] name = "webpki-roots" -version = "1.0.6" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" +checksum = "7dcd9d09a39985f5344844e66b0c530a33843579125f23e21e9f0f220850f22a" dependencies = [ "rustls-pki-types", ] @@ -7881,7 +7947,7 @@ dependencies = [ "raw-window-handle", "rustc-hash 1.1.0", "smallvec", - "thiserror 2.0.18", + "thiserror 2.0.20", "wgpu-core-deps-apple", "wgpu-core-deps-emscripten", "wgpu-core-deps-wasm", @@ -7966,7 +8032,7 @@ dependencies = [ "raw-window-handle", "renderdoc-sys", "smallvec", - "thiserror 2.0.18", + "thiserror 2.0.20", "wasm-bindgen", "web-sys", "wgpu-types", @@ -8009,7 +8075,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -8154,7 +8220,7 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -8165,7 +8231,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -8176,7 +8242,7 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -8187,7 +8253,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -8278,15 +8344,6 @@ dependencies = [ "windows-link 0.2.1", ] -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - [[package]] name = "windows-sys" version = "0.52.0" @@ -8323,21 +8380,6 @@ dependencies = [ "windows-link 0.2.1", ] -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - [[package]] name = "windows-targets" version = "0.52.6" @@ -8389,12 +8431,6 @@ dependencies = [ "windows-link 0.2.1", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" @@ -8407,12 +8443,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" @@ -8425,12 +8455,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -8455,12 +8479,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - [[package]] name = "windows_i686_msvc" version = "0.52.6" @@ -8473,12 +8491,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" @@ -8491,12 +8503,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" @@ -8509,12 +8515,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -8530,7 +8530,7 @@ checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winit" version = "0.31.0-beta.2" -source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" +source = "git+https://github.com/pop-os/winit.git?rev=9567503#9567503d34130113e36b0167a2b8829c3756e429" dependencies = [ "bitflags 2.13.2", "cfg_aliases", @@ -8538,7 +8538,7 @@ dependencies = [ "dpi", "libc", "raw-window-handle", - "rustix 1.1.4", + "rustix 1.1.5", "smol_str", "tracing", "winit-android", @@ -8556,7 +8556,7 @@ dependencies = [ [[package]] name = "winit-android" version = "0.31.0-beta.2" -source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" +source = "git+https://github.com/pop-os/winit.git?rev=9567503#9567503d34130113e36b0167a2b8829c3756e429" dependencies = [ "android-activity", "bitflags 2.13.2", @@ -8571,7 +8571,7 @@ dependencies = [ [[package]] name = "winit-appkit" version = "0.31.0-beta.2" -source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" +source = "git+https://github.com/pop-os/winit.git?rev=9567503#9567503d34130113e36b0167a2b8829c3756e429" dependencies = [ "bitflags 2.13.2", "block2 0.6.2", @@ -8593,9 +8593,9 @@ dependencies = [ [[package]] name = "winit-common" version = "0.31.0-beta.2" -source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" +source = "git+https://github.com/pop-os/winit.git?rev=9567503#9567503d34130113e36b0167a2b8829c3756e429" dependencies = [ - "memmap2 0.9.10", + "memmap2 0.9.11", "objc2 0.6.4", "objc2-core-foundation", "smol_str", @@ -8608,7 +8608,7 @@ dependencies = [ [[package]] name = "winit-core" version = "0.31.0-beta.2" -source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" +source = "git+https://github.com/pop-os/winit.git?rev=9567503#9567503d34130113e36b0167a2b8829c3756e429" dependencies = [ "bitflags 2.13.2", "cursor-icon", @@ -8622,14 +8622,14 @@ dependencies = [ [[package]] name = "winit-orbital" version = "0.31.0-beta.2" -source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" +source = "git+https://github.com/pop-os/winit.git?rev=9567503#9567503d34130113e36b0167a2b8829c3756e429" dependencies = [ "bitflags 2.13.2", "dpi", "libredox", "orbclient", "raw-window-handle", - "redox_syscall 0.7.4", + "redox_event", "smol_str", "tracing", "winit-core", @@ -8638,7 +8638,7 @@ dependencies = [ [[package]] name = "winit-uikit" version = "0.31.0-beta.2" -source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" +source = "git+https://github.com/pop-os/winit.git?rev=9567503#9567503d34130113e36b0167a2b8829c3756e429" dependencies = [ "bitflags 2.13.2", "block2 0.6.2", @@ -8658,7 +8658,7 @@ dependencies = [ [[package]] name = "winit-wayland" version = "0.31.0-beta.2" -source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" +source = "git+https://github.com/pop-os/winit.git?rev=9567503#9567503d34130113e36b0167a2b8829c3756e429" dependencies = [ "ahash", "bitflags 2.13.2", @@ -8666,16 +8666,16 @@ dependencies = [ "cursor-icon", "dpi", "libc", - "memmap2 0.9.10", + "memmap2 0.9.11", "raw-window-handle", - "rustix 1.1.4", + "rustix 1.1.5", "sctk-adwaita", "smithay-client-toolkit 0.20.0", "smol_str", "tracing", "wayland-backend", "wayland-client", - "wayland-protocols 0.32.12", + "wayland-protocols 0.32.13", "wayland-protocols-plasma", "winit-common", "winit-core", @@ -8684,7 +8684,7 @@ dependencies = [ [[package]] name = "winit-web" version = "0.31.0-beta.2" -source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" +source = "git+https://github.com/pop-os/winit.git?rev=9567503#9567503d34130113e36b0167a2b8829c3756e429" dependencies = [ "atomic-waker", "bitflags 2.13.2", @@ -8706,7 +8706,7 @@ dependencies = [ [[package]] name = "winit-win32" version = "0.31.0-beta.2" -source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" +source = "git+https://github.com/pop-os/winit.git?rev=9567503#9567503d34130113e36b0167a2b8829c3756e429" dependencies = [ "bitflags 2.13.2", "cursor-icon", @@ -8722,7 +8722,7 @@ dependencies = [ [[package]] name = "winit-x11" version = "0.31.0-beta.2" -source = "git+https://github.com/pop-os/winit.git?tag=cosmic-0.14#261cda54017f98a12dc55569c864430fe6770366" +source = "git+https://github.com/pop-os/winit.git?rev=9567503#9567503d34130113e36b0167a2b8829c3756e429" dependencies = [ "bitflags 2.13.2", "bytemuck", @@ -8732,7 +8732,7 @@ dependencies = [ "libc", "percent-encoding", "raw-window-handle", - "rustix 1.1.4", + "rustix 1.1.5", "smol_str", "tracing", "winit-common", @@ -8744,115 +8744,24 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.15" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" -dependencies = [ - "memchr", -] - -[[package]] -name = "winnow" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09dac053f1cd375980747450bfc7250c264eaae0583872e845c0c7cd578872b5" +checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" dependencies = [ "memchr", ] [[package]] name = "wit-bindgen" -version = "0.51.0" +version = "0.57.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" -dependencies = [ - "wit-bindgen-rust-macro", -] - -[[package]] -name = "wit-bindgen-core" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" -dependencies = [ - "anyhow", - "heck 0.5.0", - "wit-parser", -] - -[[package]] -name = "wit-bindgen-rust" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" -dependencies = [ - "anyhow", - "heck 0.5.0", - "indexmap", - "prettyplease", - "syn", - "wasm-metadata", - "wit-bindgen-core", - "wit-component", -] - -[[package]] -name = "wit-bindgen-rust-macro" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" -dependencies = [ - "anyhow", - "prettyplease", - "proc-macro2", - "quote", - "syn", - "wit-bindgen-core", - "wit-bindgen-rust", -] - -[[package]] -name = "wit-component" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" -dependencies = [ - "anyhow", - "bitflags 2.13.2", - "indexmap", - "log", - "serde", - "serde_derive", - "serde_json", - "wasm-encoder", - "wasm-metadata", - "wasmparser", - "wit-parser", -] - -[[package]] -name = "wit-parser" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" -dependencies = [ - "anyhow", - "id-arena", - "indexmap", - "log", - "semver", - "serde", - "serde_derive", - "serde_json", - "unicode-xid", - "wasmparser", -] +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" [[package]] name = "writeable" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" +checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc" [[package]] name = "x11-dl" @@ -8876,7 +8785,7 @@ dependencies = [ "libc", "libloading", "once_cell", - "rustix 1.1.4", + "rustix 1.1.5", "x11rb-protocol", "xcursor", ] @@ -8889,9 +8798,9 @@ checksum = "ea6fc2961e4ef194dcbfe56bb845534d0dc8098940c7e5c012a258bfec6701bd" [[package]] name = "xcursor" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec9e4a500ca8864c5b47b8b482a73d62e4237670e5b5f1d6b9e3cae50f28f2b" +checksum = "163b33ed8786455e2fa5d72f554057ce3f3182425434f756cd39c99839d88e23" [[package]] name = "xkbcommon" @@ -8911,7 +8820,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d66ca9352cbd4eecbbc40871d8a11b4ac8107cfc528a6e14d7c19c69d0e1ac9" dependencies = [ "libc", - "memmap2 0.9.10", + "memmap2 0.9.11", "xkeysym", ] @@ -8939,9 +8848,9 @@ dependencies = [ [[package]] name = "xml-rs" -version = "0.8.28" +version = "0.8.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ae8337f8a065cfc972643663ea4279e04e7256de865aa66fe25cec5fb912d3f" +checksum = "e450f9b2ed1dff33c94c12589a87338689467b9c4f5d8a5710bd09a847d2c8a7" [[package]] name = "xmlwriter" @@ -8978,9 +8887,9 @@ checksum = "e01738255b5a16e78bbb83e7fbba0a1e7dd506905cfc53f4622d89015a03fbb5" [[package]] name = "yoke" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" dependencies = [ "stable_deref_trait", "yoke-derive", @@ -8989,21 +8898,21 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +checksum = "33811428bee40dbceb6d545e95754741d17a6aef9a4849f0fd62e2ba4f412a78" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.6", "synstructure", ] [[package]] name = "zbus" -version = "5.14.0" +version = "5.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca82f95dbd3943a40a53cfded6c2d0a2ca26192011846a1810c4256ef92c60bc" +checksum = "5db4be7c075cb421e4b7ee645541604239bd243ba7c357511f4ff3a74b555907" dependencies = [ "async-broadcast", "async-executor", @@ -9015,20 +8924,20 @@ dependencies = [ "async-trait", "blocking", "enumflags2", - "event-listener 5.4.1", + "event-listener 5.4.2", "futures-core", "futures-lite", "hex", "libc", "ordered-stream", - "rustix 1.1.4", + "rustix 1.1.5", "serde", "serde_repr", "tracing", "uds_windows", "uuid", "windows-sys 0.61.2", - "winnow 0.7.15", + "winnow", "zbus_macros", "zbus_names", "zvariant", @@ -9052,7 +8961,7 @@ checksum = "10da05367f3a7b7553c8cdf8fa91aee6b64afebe32b51c95177957efc47ca3a0" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", "zbus-lockstep", "zbus_xml", "zvariant", @@ -9060,14 +8969,14 @@ dependencies = [ [[package]] name = "zbus_macros" -version = "5.14.0" +version = "5.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897e79616e84aac4b2c46e9132a4f63b93105d54fe8c0e8f6bffc21fa8d49222" +checksum = "2990635d09ade6df1868f72f8cac69a876a90981e8bd3c40b1be413f8dc88f40" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 3.0.6", "zbus_names", "zvariant", "zvariant_utils", @@ -9075,27 +8984,36 @@ dependencies = [ [[package]] name = "zbus_names" -version = "4.3.1" +version = "4.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffd8af6d5b78619bab301ff3c560a5bd22426150253db278f164d6cf3b72c50f" +checksum = "d8bf88b4a3ff53e883001e0e0115b297a9d53c31b9c1edd2bfdd853e3428624e" dependencies = [ "serde", - "winnow 0.7.15", + "winnow", "zvariant", ] [[package]] name = "zbus_xml" -version = "5.1.0" +version = "5.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "441a0064125265655bccc3a6af6bef56814d9277ac83fce48b1cd7e160b80eac" +checksum = "d1586c021a01ca0a9216dcd874e546382e156a5cbab5fab6cb5f10087e22682a" dependencies = [ - "quick-xml 0.38.4", "serde", + "winnow", "zbus_names", "zvariant", ] +[[package]] +name = "zcheapstr" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1afec51604565183aeb5c54c20aeab286120d4e4460f7f76e3e8bb8c0d99473" +dependencies = [ + "serde", +] + [[package]] name = "zeno" version = "0.3.3" @@ -9104,56 +9022,56 @@ checksum = "6df3dc4292935e51816d896edcd52aa30bc297907c26167fec31e2b0c6a32524" [[package]] name = "zerocopy" -version = "0.8.48" +version = "0.8.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" +checksum = "d35102a9f36d089ccae9e4c6802bc118be4487b80aaffc0ab4e0cf5ce92d2873" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.48" +version = "0.8.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" +checksum = "146c01f5ab44258da43cf276c74a2763db2ff3969c9c652c3f2de07041d0b2bc" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] name = "zerofrom" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +checksum = "f75b4683f6c7f45248d4d64056a24298c6281e0993356d7d1b4a1a962ef10d4a" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.6", "synstructure", ] [[package]] name = "zeroize" -version = "1.8.2" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" +checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" [[package]] name = "zerotrie" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +checksum = "4ea269c3bd32f0a32c321907a2ae912ba6f4649bb0fc764a15627e99a7095a3f" dependencies = [ "displaydoc", "yoke", @@ -9162,9 +9080,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.6" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +checksum = "bb0464e17806c1d976d5cba29399c7f08e516e279e2ba493f63123b5fca67dd8" dependencies = [ "yoke", "zerofrom", @@ -9173,20 +9091,26 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.3" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" +checksum = "34df6fc39dbd26ddc9c10e6a2984476e13acce22e64e4487636ef494369225da" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.6", ] [[package]] -name = "zmij" -version = "1.0.21" +name = "zlib-rs" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" +checksum = "b268e58e7c693d7c271f93ffc4ba3b380412554231c85bf61ca7af91042a4112" + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" [[package]] name = "zune-core" @@ -9196,9 +9120,9 @@ checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" [[package]] name = "zune-core" -version = "0.5.1" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb8a0807f7c01457d0379ba880ba6322660448ddebc890ce29bb64da71fb40f9" +checksum = "d56377fd46368984a170bc5aac5567e52ca5da874caa60bea39fcbca78fb658b" [[package]] name = "zune-inflate" @@ -9224,46 +9148,47 @@ version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27bc9d5b815bc103f142aa054f561d9187d191692ec7c2d1e2b4737f8dbd7296" dependencies = [ - "zune-core 0.5.1", + "zune-core 0.5.3", ] [[package]] name = "zvariant" -version = "5.10.0" +version = "5.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5708299b21903bbe348e94729f22c49c55d04720a004aa350f1f9c122fd2540b" +checksum = "c1d34c27cc6cdd1f458427519dd6b8612f7b7e3f7b9a0b2355d041dda9869147" dependencies = [ "endi", "enumflags2", "serde", "url", - "winnow 0.7.15", + "winnow", + "zcheapstr", "zvariant_derive", "zvariant_utils", ] [[package]] name = "zvariant_derive" -version = "5.10.0" +version = "5.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b59b012ebe9c46656f9cc08d8da8b4c726510aef12559da3e5f1bf72780752c" +checksum = "864155e69b4352db0c7f374917bf45d1e0c8d17659c8b3dbf9795f3673f8c497" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 3.0.6", "zvariant_utils", ] [[package]] name = "zvariant_utils" -version = "3.3.0" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f75c23a64ef8f40f13a6989991e643554d9bef1d682a281160cf0c1bc389c5e9" +checksum = "bad0294361a320b694a328460dc73add56c306150f5cb6bfafc44446120008a3" dependencies = [ "proc-macro2", "quote", "serde", - "syn", - "winnow 0.7.15", + "syn 3.0.6", + "winnow", ] diff --git a/accessibility/Cargo.toml b/accessibility/Cargo.toml index 40188149..0882a480 100644 --- a/accessibility/Cargo.toml +++ b/accessibility/Cargo.toml @@ -10,10 +10,10 @@ async-io = ["accesskit_winit?/async-io"] tokio = ["accesskit_winit?/tokio"] [dependencies] -accesskit = { git = "https://github.com/wash2/accesskit", tag = "cosmic-0.14" } -accesskit_windows = { git = "https://github.com/wash2/accesskit", tag = "cosmic-0.14", optional = true } -accesskit_macos = { git = "https://github.com/wash2/accesskit", tag = "cosmic-0.14", optional = true } -accesskit_winit = { git = "https://github.com/wash2/accesskit", tag = "cosmic-0.14", optional = true, default-features = false, features = [ +accesskit = { git = "https://github.com/wash2/accesskit", rev = "6c20249" } +accesskit_windows = { git = "https://github.com/wash2/accesskit", rev = "6c20249", optional = true } +accesskit_macos = { git = "https://github.com/wash2/accesskit", rev = "6c20249", optional = true } +accesskit_winit = { git = "https://github.com/wash2/accesskit", rev = "6c20249", optional = true, default-features = false, features = [ "rwh_06", ] } # accesskit = { path = "../../../accesskit/common" } From 5716b9a691b400582cdbf364d96ed77d442d619f Mon Sep 17 00:00:00 2001 From: Hojjat Date: Mon, 21 Sep 2026 14:57:52 -0600 Subject: [PATCH 91/93] fix: build user interfaces in window id order --- winit/src/lib.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/winit/src/lib.rs b/winit/src/lib.rs index 791bacff..9a7a456a 100644 --- a/winit/src/lib.rs +++ b/winit/src/lib.rs @@ -69,6 +69,8 @@ use crate::runtime::user_interface::{self, UserInterface}; use crate::runtime::{Action, Task}; use program::Program; +#[cfg(feature = "program")] +pub use program::Program; use window::WindowManager; use rustc_hash::FxHashMap; @@ -2639,10 +2641,10 @@ where .and_then(|window| theme::Base::palette(window.state.theme())) }); - cached_user_interfaces - .drain() - .filter_map(|(id, cache)| { - let window = window_manager.get_mut(id)?; + window_manager + .iter_mut() + .filter_map(|(id, window)| { + let cache = cached_user_interfaces.remove(&id)?; Some(( id, @@ -2715,7 +2717,5 @@ fn system_information( graphics_backend: graphics.backend, } } -#[cfg(feature = "program")] -pub use program::Program; pub use platform_specific::*; From 6f1b3a71704c4074fad03b3bd6a4203f69556c9e Mon Sep 17 00:00:00 2001 From: Hojjat Date: Mon, 21 Sep 2026 15:02:24 -0600 Subject: [PATCH 92/93] fix(wayland): share a grabbing popup's modifiers with its toplevel --- winit/src/lib.rs | 11 +++++++ winit/src/platform_specific/mod.rs | 5 +++ .../wayland/handlers/seat/keyboard.rs | 25 ++++++++++++++ winit/src/platform_specific/wayland/mod.rs | 33 ++++++++++++++++++- .../platform_specific/wayland/sctk_event.rs | 17 ++++++++++ 5 files changed, 90 insertions(+), 1 deletion(-) diff --git a/winit/src/lib.rs b/winit/src/lib.rs index 9a7a456a..db1192fe 100644 --- a/winit/src/lib.rs +++ b/winit/src/lib.rs @@ -1328,6 +1328,17 @@ async fn run_instance

( continue; } } + // to avoid race with the reported modifier state from the popup of + // this window, don't empty the modifiers, on focus loss + #[cfg(wayland_platform)] + if let winit::event::WindowEvent::ModifiersChanged(modifiers) = + &event + && modifiers.state().is_empty() + && platform_specific_handler.has_popup(id) + { + continue; + } + match event { winit::event::WindowEvent::SurfaceResized(_) => { window.raw.request_redraw(); diff --git a/winit/src/platform_specific/mod.rs b/winit/src/platform_specific/mod.rs index 969c8299..f1cbf2e2 100644 --- a/winit/src/platform_specific/mod.rs +++ b/winit/src/platform_specific/mod.rs @@ -74,6 +74,11 @@ impl PlatformSpecific { } } + #[cfg(wayland_platform)] + pub(crate) fn has_popup(&self, toplevel: window::Id) -> bool { + self.wayland.has_popup(toplevel) + } + pub(crate) fn retain_subsurfaces bool>( &mut self, keep: F, diff --git a/winit/src/platform_specific/wayland/handlers/seat/keyboard.rs b/winit/src/platform_specific/wayland/handlers/seat/keyboard.rs index 30f9c7a6..e3ad792a 100644 --- a/winit/src/platform_specific/wayland/handlers/seat/keyboard.rs +++ b/winit/src/platform_specific/wayland/handlers/seat/keyboard.rs @@ -353,6 +353,31 @@ impl KeyboardHandler for SctkState { surface: surface.clone(), }); } + // A popup holds the seat's keyboard on behalf of its toplevel. Report + // the modifiers to the toplevel as well. + let toplevel = self.popmgr.popups().find_map(|p| { + (p.popup.wl_surface() == &surface) + .then(|| p.data.toplevel.clone()) + }); + if let Some(toplevel) = toplevel { + let id = self + .windows + .iter() + .find(|w| w.wl_surface(&self.connection) == toplevel) + .map(|w| w.id) + .or_else(|| { + self.layer_surfaces + .iter() + .find(|l| *l.surface.wl_surface() == toplevel) + .map(|l| l.id) + }); + if let Some(toplevel) = id { + self.sctk_events.push(SctkEvent::PopupModifiers { + toplevel, + modifiers, + }); + } + } } } } diff --git a/winit/src/platform_specific/wayland/mod.rs b/winit/src/platform_specific/wayland/mod.rs index 289d410d..5b41e1c5 100644 --- a/winit/src/platform_specific/wayland/mod.rs +++ b/winit/src/platform_specific/wayland/mod.rs @@ -20,7 +20,7 @@ use iced_graphics::{Compositor, compositor}; use iced_runtime::core::{Vector, window}; use raw_window_handle::{DisplayHandle, HasDisplayHandle, HasWindowHandle}; use raw_window_handle::{HasRawDisplayHandle, RawWindowHandle}; -use sctk_event::SctkEvent; +use sctk_event::{PopupEventVariant, SctkEvent}; use std::sync::OnceLock; use std::{collections::HashMap, sync::Arc}; use subsurface_widget::{SubsurfaceInstance, SubsurfaceState}; @@ -103,6 +103,7 @@ pub(crate) struct WaylandSpecific { surface_ids: HashMap, subsurface_state: Option, surface_subsurfaces: HashMap>, + popup_toplevels: HashMap, } impl PlatformSpecific { @@ -173,6 +174,11 @@ impl WaylandSpecific { self.conn.as_ref() } + /// Whether a popup opened from `toplevel` is alive. + pub(crate) fn has_popup(&self, toplevel: window::Id) -> bool { + self.popup_toplevels.values().any(|id| *id == toplevel) + } + pub(crate) async fn handle_event<'a, 'b, P>( &mut self, e: SctkEvent, @@ -201,8 +207,33 @@ impl WaylandSpecific { modifiers, subsurface_state, surface_subsurfaces, + popup_toplevels, } = self; + if let SctkEvent::PopupEvent { + variant, + parent_id, + parent_window, + id, + .. + } = &e + { + match variant { + PopupEventVariant::Created(..) => { + // A nested popup's parent is itself a popup so inhreit its toplevel + let toplevel = popup_toplevels + .get(&parent_id.id()) + .copied() + .unwrap_or(*parent_window); + _ = popup_toplevels.insert(id.id(), toplevel); + } + PopupEventVariant::Done => { + _ = popup_toplevels.remove(&id.id()); + } + _ => {} + } + } + match e { sctk_event => { let Some(sender) = sender.as_ref() else { diff --git a/winit/src/platform_specific/wayland/sctk_event.rs b/winit/src/platform_specific/wayland/sctk_event.rs index 64609b58..8e771f60 100755 --- a/winit/src/platform_specific/wayland/sctk_event.rs +++ b/winit/src/platform_specific/wayland/sctk_event.rs @@ -198,6 +198,10 @@ pub enum SctkEvent { SessionUnlocked, SurfaceScaleFactorChanged(f64, WlSurface, window::Id), Winit(WindowId, WindowEvent), + PopupModifiers { + toplevel: window::Id, + modifiers: cctk::sctk::seat::keyboard::Modifiers, + }, Subcompositor(SubsurfaceState), ShortcutsInhibited(bool), } @@ -1400,6 +1404,19 @@ impl SctkEvent { ), )), SctkEvent::Winit(_, _) => {} + SctkEvent::PopupModifiers { + toplevel, + modifiers, + } => { + events.push(( + Some(toplevel), + iced_runtime::core::Event::Keyboard( + keyboard::Event::ModifiersChanged(modifiers_to_native( + modifiers, + )), + ), + )); + } SctkEvent::SurfaceScaleFactorChanged(scale, _, id) => { if let Some(w) = window_manager.get_mut(id) { w.state.update_scale_factor(scale); From 0968a10fc165984080799551124a96adf6be1fb8 Mon Sep 17 00:00:00 2001 From: Hojjat Date: Mon, 21 Sep 2026 21:23:13 -0600 Subject: [PATCH 93/93] fix: arrow keys in text editor on a layer_surface --- winit/src/platform_specific/wayland/sctk_event.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/winit/src/platform_specific/wayland/sctk_event.rs b/winit/src/platform_specific/wayland/sctk_event.rs index 8e771f60..b96f1765 100755 --- a/winit/src/platform_specific/wayland/sctk_event.rs +++ b/winit/src/platform_specific/wayland/sctk_event.rs @@ -627,7 +627,12 @@ impl SctkEvent { keyboard::Event::KeyPressed { key: key.clone(), location: location, - text: ke.utf8.map(|s| s.into()), + // sctk reports keys without a text representation (e.g. arrows, Home) as + // Some("") but winit reports None. Widgets are written against winit's contract. + text: ke + .utf8 + .filter(|s| !s.is_empty()) + .map(|s| s.into()), modifiers: modifiers_to_native(*modifiers), physical_key, repeat: false, @@ -653,7 +658,9 @@ impl SctkEvent { keyboard::Event::KeyPressed { key: key.clone(), location: location, - text: utf8.map(|s| s.into()), + text: utf8 + .filter(|s| !s.is_empty()) + .map(|s| s.into()), modifiers: modifiers_to_native(*modifiers), physical_key, repeat: true,