From 5c93094574b31800caaa27255caac4a7253f24ad Mon Sep 17 00:00:00 2001 From: Victoria Brekenfeld Date: Wed, 19 Aug 2026 12:40:05 +0200 Subject: [PATCH 01/69] chore: update smithay --- Cargo.lock | 53 +++------- Cargo.toml | 2 +- src/config/mod.rs | 8 +- src/input/actions.rs | 5 +- src/input/mod.rs | 107 ++++++++++---------- src/shell/element/mod.rs | 4 +- src/shell/element/stack.rs | 6 +- src/shell/element/surface.rs | 3 +- src/shell/element/window.rs | 6 +- src/shell/focus/mod.rs | 5 +- src/shell/focus/target.rs | 15 +-- src/shell/grabs/menu/default.rs | 13 +-- src/shell/grabs/moving.rs | 4 +- src/shell/layout/tiling/grabs/resize.rs | 4 +- src/shell/layout/tiling/grabs/swap.rs | 4 +- src/shell/zoom.rs | 4 +- src/utils/iced/mod.rs | 6 +- src/wayland/handlers/compositor.rs | 17 ++-- src/wayland/handlers/pointer_constraints.rs | 52 ++++++---- src/wayland/handlers/pointer_warp.rs | 2 +- src/wayland/handlers/toplevel_management.rs | 3 +- src/xwayland.rs | 10 +- 22 files changed, 168 insertions(+), 165 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b8be66ca..859203e4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1189,7 +1189,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -1503,7 +1503,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -2690,7 +2690,7 @@ dependencies = [ "portable-atomic", "portable-atomic-util", "serde_core", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -2813,7 +2813,7 @@ version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a1886916523694cd6ea3d175f03a1e5010699a2a4cc13696d83d7bea1d80638" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -3429,7 +3429,7 @@ 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]] @@ -4167,20 +4167,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha 0.3.1", + "rand_chacha", "rand_core 0.6.4", ] -[[package]] -name = "rand" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" -dependencies = [ - "rand_chacha 0.9.0", - "rand_core 0.9.5", -] - [[package]] name = "rand" version = "0.10.0" @@ -4202,16 +4192,6 @@ dependencies = [ "rand_core 0.6.4", ] -[[package]] -name = "rand_chacha" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" -dependencies = [ - "ppv-lite86", - "rand_core 0.9.5", -] - [[package]] name = "rand_core" version = "0.6.4" @@ -4221,15 +4201,6 @@ dependencies = [ "getrandom 0.2.17", ] -[[package]] -name = "rand_core" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" -dependencies = [ - "getrandom 0.3.4", -] - [[package]] name = "rand_core" version = "0.10.0" @@ -4525,7 +4496,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.12.1", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -4820,7 +4791,7 @@ checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" [[package]] name = "smithay" version = "0.7.0" -source = "git+https://github.com/smithay/smithay.git?rev=5fb12b8#5fb12b87407b3680135c45d94214c5f1b1d0fbea" +source = "git+https://github.com/smithay/smithay.git?rev=e3d461a#e3d461a057ba244d213a8498ec372b0799cca103" dependencies = [ "aliasable", "appendlist", @@ -4849,7 +4820,7 @@ dependencies = [ "pkg-config", "portable-atomic", "profiling", - "rand 0.9.2", + "rand 0.10.0", "reis", "rustix 1.1.4", "scopeguard", @@ -5115,7 +5086,7 @@ dependencies = [ "getrandom 0.4.1", "once_cell", "rustix 1.1.4", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -5414,7 +5385,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5f7c95348f20c1c913d72157b3c6dee6ea3e30b3d19502c5a7f6d3f160dacbf" dependencies = [ "cc", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -6134,7 +6105,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.61.2", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index d807d369..23fe2775 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -146,4 +146,4 @@ lto = "fat" cosmic-protocols = { git = "https://github.com/pop-os//cosmic-protocols", branch = "main" } [patch.crates-io] -smithay = { git = "https://github.com/smithay/smithay.git", rev = "5fb12b8" } +smithay = { git = "https://github.com/smithay/smithay.git", rev = "e3d461a" } diff --git a/src/config/mod.rs b/src/config/mod.rs index 93b53374..abef562b 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -14,8 +14,11 @@ use cosmic_config::{ConfigGet, CosmicConfigEntry}; use cosmic_settings_config::window_rules::ApplicationException; use cosmic_settings_config::{Shortcuts, shortcuts, window_rules}; use serde::{Deserialize, Serialize}; -use smithay::utils::{Clock, Monotonic}; use smithay::wayland::xdg_activation::XdgActivationState; +use smithay::{ + backend::input::InputTime, + utils::{Clock, Monotonic}, +}; pub use smithay::{ backend::input::{self as smithay_input, KeyState}, input::keyboard::{Keysym, ModifiersState, keysyms as KeySyms}, @@ -770,13 +773,12 @@ pub fn change_modifier_state( const X11_KEYCODE_OFFSET: u32 = 8; let mut input = |key_state, scan_code| { - let time = state.common.clock.now().as_millis(); let _ = keyboard.input( state, smithay_input::Keycode::new(scan_code + X11_KEYCODE_OFFSET), key_state, SERIAL_COUNTER.next_serial(), - time, + InputTime::now(), |_, _, _| smithay::input::keyboard::FilterResult::<()>::Forward, ); }; diff --git a/src/input/actions.rs b/src/input/actions.rs index 8a5ef84c..8639ba62 100644 --- a/src/input/actions.rs +++ b/src/input/actions.rs @@ -18,6 +18,7 @@ use cosmic_config::ConfigSet; use cosmic_settings_config::shortcuts; use cosmic_settings_config::shortcuts::action::{Direction, FocusDirection}; use smithay::{ + backend::input::InputTime, input::{Seat, pointer::MotionEvent}, utils::{Point, Serial}, }; @@ -45,7 +46,7 @@ impl State { backend_id: &InputBackendId, seat: &Seat, serial: Serial, - time: u32, + time: InputTime, pattern: shortcuts::Binding, direction: Option, ) { @@ -150,7 +151,7 @@ impl State { backend_id: &InputBackendId, seat: &Seat, serial: Serial, - time: u32, + time: InputTime, pattern: shortcuts::Binding, direction: Option, propagate: bool, diff --git a/src/input/mod.rs b/src/input/mod.rs index 0e307079..d619a525 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -42,9 +42,9 @@ use smithay::{ backend::input::{ AbsolutePositionEvent, Axis, AxisRelativeDirection, AxisSource, Device, DeviceCapability, GestureBeginEvent, GestureEndEvent, GesturePinchUpdateEvent as _, - GestureSwipeUpdateEvent as _, InputBackend, InputEvent, KeyState, PointerAxisEvent, - ProximityState, TabletToolButtonEvent, TabletToolEvent, TabletToolProximityEvent, - TabletToolTipEvent, TabletToolTipState, TouchEvent, + GestureSwipeUpdateEvent as _, InputBackend, InputEvent, InputTime, KeyState, + PointerAxisEvent, ProximityState, TabletToolButtonEvent, TabletToolEvent, + TabletToolProximityEvent, TabletToolTipEvent, TabletToolTipState, TouchEvent, }, desktop::{PopupKeyboardGrab, WindowSurfaceType, utils::under_from_surface_tree}, input::{ @@ -271,7 +271,7 @@ impl State { trace!(?keycode, ?state, "key"); let serial = SERIAL_COUNTER.next_serial(); - let time = Event::time_msec(&event); + let time = Event::time(&event); let keyboard = seat.get_keyboard().unwrap(); let previous_modifiers = keyboard.modifier_state(); if let Some((action, pattern)) = keyboard @@ -397,7 +397,7 @@ impl State { &RelativeMotionEvent { delta: event.delta(), delta_unaccel: event.delta_unaccel(), - utime: event.time(), + time: event.time(), }, ); @@ -638,7 +638,7 @@ impl State { &MotionEvent { location: position.as_logical(), serial, - time: event.time_msec(), + time: event.time(), }, ); ptr.frame(self); @@ -753,7 +753,7 @@ impl State { &MotionEvent { location: position.as_logical(), serial, - time: event.time_msec(), + time: event.time(), }, ); ptr.frame(self); @@ -1005,7 +1005,7 @@ impl State { button, event.state(), serial, - event.time_msec(), + event.time(), ); } @@ -1017,12 +1017,12 @@ impl State { button, state: event.state(), serial, - time: event.time_msec(), + time: event.time(), }, ); ptr.frame(self); } else if event.state() == ButtonState::Released { - ptr.unset_grab(self, serial, event.time_msec()) + ptr.unset_grab(self, serial, event.time()) } } InputEvent::PointerAxis { event, .. } => { @@ -1073,7 +1073,7 @@ impl State { self.update_zoom(&seat, change, event.source() == AxisSource::Wheel); } } else { - let mut frame = AxisFrame::new(event.time_msec()).source(event.source()); + let mut frame = AxisFrame::new(event.time()).source(event.source()); let horizontal_amount = event .amount(Axis::Horizontal) .or_else(|| Some(event.amount_v120(Axis::Horizontal)? * 15.0 / 120.)); @@ -1142,7 +1142,7 @@ impl State { self, &GestureSwipeBeginEvent { serial, - time: event.time_msec(), + time: event.time(), fingers: event.fingers(), }, ); @@ -1163,7 +1163,7 @@ impl State { if let Some(ref mut gesture_state) = self.common.gesture_state { let first_update = gesture_state.update( event.delta(), - Duration::from_millis(event.time_msec() as u64), + Duration::from_millis(event.time().millis() as u64), ); // Decide on action if first update if first_update { @@ -1239,7 +1239,7 @@ impl State { pointer.gesture_swipe_update( self, &GestureSwipeUpdateEvent { - time: event.time_msec(), + time: event.time(), delta: event.delta(), }, ); @@ -1288,7 +1288,7 @@ impl State { self, &GestureSwipeEndEvent { serial, - time: event.time_msec(), + time: event.time(), cancelled: event.cancelled(), }, ); @@ -1311,7 +1311,7 @@ impl State { self, &GesturePinchBeginEvent { serial, - time: event.time_msec(), + time: event.time(), fingers: event.fingers(), }, ); @@ -1331,7 +1331,7 @@ impl State { pointer.gesture_pinch_update( self, &GesturePinchUpdateEvent { - time: event.time_msec(), + time: event.time(), delta: event.delta(), scale: event.scale(), rotation: event.rotation(), @@ -1355,7 +1355,7 @@ impl State { self, &GesturePinchEndEvent { serial, - time: event.time_msec(), + time: event.time(), cancelled: event.cancelled(), }, ); @@ -1377,7 +1377,7 @@ impl State { self, &GestureHoldBeginEvent { serial, - time: event.time_msec(), + time: event.time(), fingers: event.fingers(), }, ); @@ -1399,7 +1399,7 @@ impl State { self, &GestureHoldEndEvent { serial, - time: event.time_msec(), + time: event.time(), cancelled: event.cancelled(), }, ); @@ -1456,7 +1456,7 @@ impl State { slot: event.slot(), location: position.as_logical(), serial, - time: event.time_msec(), + time: event.time(), }, ); } @@ -1505,7 +1505,7 @@ impl State { &TouchMotionEvent { slot: event.slot(), location: position.as_logical(), - time: event.time_msec(), + time: event.time(), }, ); } @@ -1531,7 +1531,7 @@ impl State { self, &UpEvent { slot: event.slot(), - time: event.time_msec(), + time: event.time(), serial, }, ); @@ -1596,7 +1596,7 @@ impl State { &MotionEvent { location: position.as_logical(), serial: SERIAL_COUNTER.next_serial(), - time: self.common.clock.now().as_millis(), + time: InputTime::now(), }, ); @@ -1627,11 +1627,11 @@ impl State { &tool::MotionEvent { location: position.as_logical(), serial: SERIAL_COUNTER.next_serial(), - time: event.time_msec(), + time: event.time(), }, ); - tool.frame(self, event.time_msec()); + tool.frame(self, event.time()); } } } @@ -1665,7 +1665,7 @@ impl State { &MotionEvent { location: position.as_logical(), serial: SERIAL_COUNTER.next_serial(), - time: self.common.clock.now().as_millis(), + time: InputTime::now(), }, ); @@ -1706,7 +1706,7 @@ impl State { location: position.as_logical(), axis: Some(frame), serial: SERIAL_COUNTER.next_serial(), - time: event.time_msec(), + time: event.time(), }, ) } @@ -1714,12 +1714,12 @@ impl State { self, &tool::ProximityOutEvent { serial, - time: event.time_msec(), + time: event.time(), }, ), } - tool.frame(self, event.time_msec()); + tool.frame(self, event.time()); } } } @@ -1742,7 +1742,7 @@ impl State { self, &tool::DownEvent { serial, - time: event.time_msec(), + time: event.time(), }, ); } @@ -1751,13 +1751,13 @@ impl State { self, &tool::UpEvent { serial, - time: event.time_msec(), + time: event.time(), }, ); } } - tool.frame(self, event.time_msec()); + tool.frame(self, event.time()); } } } @@ -1779,11 +1779,11 @@ impl State { button: event.button(), state: event.button_state(), serial: SERIAL_COUNTER.next_serial(), - time: event.time_msec(), + time: event.time(), }, ); - tool.frame(self, event.time_msec()); + tool.frame(self, event.time()); } } } @@ -1886,7 +1886,7 @@ impl State { let Some(pointer) = seat.get_pointer() else { return; }; - let time = self.common.clock.now().as_millis(); + let time = InputTime::now(); for button in buttons { let serial = SERIAL_COUNTER.next_serial(); pointer.button( @@ -1948,7 +1948,7 @@ impl State { modifiers: &ModifiersState, handle: KeysymHandle<'_>, serial: Serial, - time: u32, + time: InputTime, keycode: Keycode, key_state: KeyState, previous_modifiers: ModifiersState, @@ -2008,7 +2008,7 @@ impl State { return; }; let serial = SERIAL_COUNTER.next_serial(); - let time = self.common.clock.now().as_millis(); + let time = InputTime::now(); let previous_modifiers = keyboard.modifier_state(); let result = keyboard .input_from_source( @@ -2157,7 +2157,7 @@ impl State { serial: Serial, keycode: Keycode, key_state: KeyState, - time: u32, + time: InputTime, ) -> FilterResult> { // Pre-compute for layout-agnostic shortcut matching let raw_syms = handle.raw_syms(); @@ -2322,7 +2322,9 @@ impl State { &backend_id_clone, &seat_clone, serial, - time.overflowing_add(duration as u32).0, + InputTime::from_millis( + time.millis().overflowing_add(duration as u32).0, + ), key_pattern_clone.clone(), None, ); @@ -2374,7 +2376,7 @@ impl State { self.common.event_loop_handle.insert_idle(move |state| { if let Some(keyboard) = seat.get_keyboard() { let serial = SERIAL_COUNTER.next_serial(); - let time = state.common.clock.now().as_millis(); + let time = InputTime::now(); keyboard.input( state, key_code, @@ -2900,6 +2902,7 @@ impl State { surface: &WlSurface, pointer: &PointerHandle, mut location: Point, + constraint: Option<&PointerConstraint>, ) { let Some(client) = surface.client() else { return; @@ -2924,15 +2927,13 @@ impl State { return false; } - with_pointer_constraint(surface, pointer, |constraint| { - if let Some(constraint) = constraint - && let Some(region) = constraint.region() - { - let point_in_surface = (p - surface_offset.to_f64()).to_i32_floor(); - return region.contains(point_in_surface); - } - true - }) + if let Some(constraint) = constraint + && let Some(region) = constraint.region() + { + let point_in_surface = (p - surface_offset.to_f64()).to_i32_floor(); + return region.contains(point_in_surface); + } + true }; let workspace_origin = output.geometry().loc.to_f64(); @@ -2956,14 +2957,14 @@ impl State { let serial = SERIAL_COUNTER.next_serial(); let under = State::surface_under(point, &output, &self.common.shell.write()) .map(|(target, pos)| (target, pos.as_logical())); - let time = self.common.clock.now(); + let time = InputTime::now(); pointer.relative_motion( self, under.clone(), &RelativeMotionEvent { delta: (0., 0.).into(), delta_unaccel: (0., 0.).into(), - utime: time.as_micros(), + time, }, ); pointer.motion( @@ -2972,7 +2973,7 @@ impl State { &MotionEvent { location: point.as_logical(), serial, - time: time.as_millis(), + time, }, ); pointer.frame(self); diff --git a/src/shell/element/mod.rs b/src/shell/element/mod.rs index 14736719..d4743b7f 100644 --- a/src/shell/element/mod.rs +++ b/src/shell/element/mod.rs @@ -12,7 +12,7 @@ use id_tree::NodeId; use smithay::{ backend::{ drm::DrmNode, - input::KeyState, + input::{InputTime, KeyState}, renderer::{ element::{ Element, Kind, RenderElement, UnderlyingStorage, @@ -1012,7 +1012,7 @@ impl KeyboardTarget for CosmicMapped { key: KeysymHandle<'_>, state: KeyState, serial: Serial, - time: u32, + time: InputTime, ) { match &self.element { CosmicMappedInternal::Stack(s) => { diff --git a/src/shell/element/stack.rs b/src/shell/element/stack.rs index d466f4e0..2fed0977 100644 --- a/src/shell/element/stack.rs +++ b/src/shell/element/stack.rs @@ -38,7 +38,7 @@ use shortcuts::action::{Direction, FocusDirection}; use smithay::{ backend::{ drm::DrmNode, - input::KeyState, + input::{InputTime, KeyState}, renderer::{ ImportAll, ImportMem, Renderer, element::{Element, Id as RendererId, Kind, RenderElement, UnderlyingStorage}, @@ -1557,7 +1557,7 @@ impl KeyboardTarget for CosmicStack { key: KeysymHandle<'_>, state: KeyState, serial: Serial, - time: u32, + time: InputTime, ) { let active = self.keyboard_leave_if_previous(seat, data, serial); self.0.with_program(|p| { @@ -1726,7 +1726,7 @@ impl PointerTarget for CosmicStack { } } - fn leave(&self, seat: &Seat, data: &mut State, serial: Serial, time: u32) { + fn leave(&self, seat: &Seat, data: &mut State, serial: Serial, time: InputTime) { self.0.with_program(|p| { let mut cursor_state = seat .user_data() diff --git a/src/shell/element/surface.rs b/src/shell/element/surface.rs index 99bb2f78..a7fd922d 100644 --- a/src/shell/element/surface.rs +++ b/src/shell/element/surface.rs @@ -21,6 +21,7 @@ use std::{ use smithay::{ backend::{ drm::DrmNode, + input::InputTime, renderer::{ ImportAll, Renderer, buffer_has_alpha, element::{Kind, RenderElementStates, surface::KindEvaluation}, @@ -1084,7 +1085,7 @@ impl KeyboardTarget for CosmicSurface { key: KeysymHandle<'_>, state: smithay::backend::input::KeyState, serial: smithay::utils::Serial, - time: u32, + time: InputTime, ) { match self.0.underlying_surface() { WindowSurface::Wayland(toplevel) => { diff --git a/src/shell/element/window.rs b/src/shell/element/window.rs index 86c2ce7f..53b2caee 100644 --- a/src/shell/element/window.rs +++ b/src/shell/element/window.rs @@ -21,7 +21,7 @@ use cosmic_comp_config::AppearanceConfig; use smithay::{ backend::{ drm::DrmNode, - input::KeyState, + input::{InputTime, KeyState}, renderer::{ ImportAll, ImportMem, Renderer, element::{Element, Id as RendererId, Kind, RenderElement, UnderlyingStorage}, @@ -985,7 +985,7 @@ impl KeyboardTarget for CosmicWindow { key: KeysymHandle<'_>, state: KeyState, serial: Serial, - time: u32, + time: InputTime, ) { self.0 .with_program(|p| KeyboardTarget::key(&p.window, seat, data, key, state, serial, time)) @@ -1124,7 +1124,7 @@ impl PointerTarget for CosmicWindow { } } - fn leave(&self, seat: &Seat, data: &mut State, serial: Serial, time: u32) { + fn leave(&self, seat: &Seat, data: &mut State, serial: Serial, time: InputTime) { self.0.with_program(|p| { let cursor_state = seat.user_data().get::().unwrap(); cursor_state.lock().unwrap().unset_shape(); diff --git a/src/shell/focus/mod.rs b/src/shell/focus/mod.rs index cab37a85..f631372e 100644 --- a/src/shell/focus/mod.rs +++ b/src/shell/focus/mod.rs @@ -6,6 +6,7 @@ use crate::{ }; use indexmap::IndexSet; use smithay::{ + backend::input::InputTime, desktop::{PopupUngrabStrategy, layer_map_for_output}, input::{Seat, pointer::MotionEvent}, output::Output, @@ -419,7 +420,7 @@ fn update_focus_state( &MotionEvent { location: new_pos.as_logical(), serial: SERIAL_COUNTER.next_serial(), - time: 0, + time: InputTime::now(), }, ); } @@ -768,7 +769,7 @@ fn update_pointer_focus(state: &mut State, seat: &Seat) { &MotionEvent { location: pointer.current_location(), serial: SERIAL_COUNTER.next_serial(), - time: state.common.clock.now().as_millis(), + time: InputTime::now(), }, ); } diff --git a/src/shell/focus/target.rs b/src/shell/focus/target.rs index 80b1a34f..56af0ccc 100644 --- a/src/shell/focus/target.rs +++ b/src/shell/focus/target.rs @@ -16,7 +16,7 @@ use crate::{ }; use id_tree::NodeId; use smithay::{ - backend::input::KeyState, + backend::input::{InputTime, KeyState}, desktop::{LayerSurface, PopupKind, WindowSurface, WindowSurfaceType, space::SpaceElement}, input::{ Seat, @@ -272,9 +272,10 @@ impl PointerFocusTarget { None }; - let cursor_hotspot = if let Some(CursorGeometry { hotspot, .. }) = - seat.cursor_geometry((0.0, 0.0), Duration::from_millis(event.time as u64).into()) - { + let cursor_hotspot = if let Some(CursorGeometry { hotspot, .. }) = seat.cursor_geometry( + (0.0, 0.0), + Duration::from_millis(event.time.millis() as u64).into(), + ) { hotspot } else { Point::from((0, 0)) @@ -417,7 +418,7 @@ impl PointerTarget for PointerFocusTarget { fn frame(&self, seat: &Seat, data: &mut State) { self.inner_pointer_target().frame(seat, data); } - fn leave(&self, seat: &Seat, data: &mut State, serial: Serial, time: u32) { + fn leave(&self, seat: &Seat, data: &mut State, serial: Serial, time: InputTime) { let toplevel = self.toplevel(&data.common.shell.read()); if let Some(element) = toplevel { for session in element.cursor_sessions() { @@ -593,7 +594,7 @@ impl DndFocus for PointerFocusTarget { offer: Option<&mut CosmicOfferData>, seat: &Seat, location: Point, - time: u32, + time: InputTime, ) { match self { PointerFocusTarget::WlSurface { surface, .. } => { @@ -695,7 +696,7 @@ impl KeyboardTarget for KeyboardFocusTarget { key: KeysymHandle<'_>, state: KeyState, serial: Serial, - time: u32, + time: InputTime, ) { if let Some(inner) = self.inner_keyboard_target() { inner.key(seat, data, key, state, serial, time); diff --git a/src/shell/grabs/menu/default.rs b/src/shell/grabs/menu/default.rs index c7418b6d..81673efd 100644 --- a/src/shell/grabs/menu/default.rs +++ b/src/shell/grabs/menu/default.rs @@ -1,7 +1,8 @@ use cosmic_settings_config::shortcuts::Action; use smithay::{ - input::pointer::MotionEvent, reexports::wayland_server::protocol::wl_surface::WlSurface, - utils::SERIAL_COUNTER, wayland::seat::WaylandFocus, + backend::input::InputTime, input::pointer::MotionEvent, + reexports::wayland_server::protocol::wl_surface::WlSurface, utils::SERIAL_COUNTER, + wayland::seat::WaylandFocus, }; use crate::{ @@ -398,7 +399,7 @@ pub fn window_items( &MotionEvent { location: loc.as_logical().to_f64(), serial, - time: state.common.clock.now().as_millis(), + time: InputTime::now(), }, ); pointer.frame(state); @@ -433,7 +434,7 @@ pub fn window_items( &MotionEvent { location: loc.as_logical().to_f64(), serial, - time: state.common.clock.now().as_millis(), + time: InputTime::now(), }, ); pointer.frame(state); @@ -468,7 +469,7 @@ pub fn window_items( &MotionEvent { location: loc.as_logical().to_f64(), serial, - time: state.common.clock.now().as_millis(), + time: InputTime::now(), }, ); pointer.frame(state); @@ -503,7 +504,7 @@ pub fn window_items( &MotionEvent { location: loc.as_logical().to_f64(), serial, - time: state.common.clock.now().as_millis(), + time: InputTime::now(), }, ); pointer.frame(state); diff --git a/src/shell/grabs/moving.rs b/src/shell/grabs/moving.rs index d8714830..05923bc7 100644 --- a/src/shell/grabs/moving.rs +++ b/src/shell/grabs/moving.rs @@ -20,7 +20,7 @@ use smallvec::SmallVec; use smithay::{ backend::{ drm::DrmNode, - input::ButtonState, + input::{ButtonState, InputTime}, renderer::{ ImportAll, ImportMem, element::{RenderElement, utils::RescaleRenderElement}, @@ -956,7 +956,7 @@ impl Drop for MoveGrab { &MotionEvent { location: pointer.current_location(), serial, - time: state.common.clock.now().as_millis(), + time: InputTime::now(), }, ); } diff --git a/src/shell/layout/tiling/grabs/resize.rs b/src/shell/layout/tiling/grabs/resize.rs index 9b135119..91873793 100644 --- a/src/shell/layout/tiling/grabs/resize.rs +++ b/src/shell/layout/tiling/grabs/resize.rs @@ -11,7 +11,7 @@ use crate::{ }; use id_tree::{NodeId, Tree}; use smithay::{ - backend::input::ButtonState, + backend::input::{ButtonState, InputTime}, input::{ Seat, pointer::{ @@ -65,7 +65,7 @@ impl PointerTarget for ResizeForkTarget { seat: &Seat, _data: &mut State, _serial: smithay::utils::Serial, - _time: u32, + _time: InputTime, ) { let user_data = seat.user_data(); let cursor_state = user_data.get::().unwrap(); diff --git a/src/shell/layout/tiling/grabs/swap.rs b/src/shell/layout/tiling/grabs/swap.rs index afe93cf0..9ac531d3 100644 --- a/src/shell/layout/tiling/grabs/swap.rs +++ b/src/shell/layout/tiling/grabs/swap.rs @@ -1,6 +1,6 @@ use cosmic_settings_config::shortcuts; use smithay::{ - backend::input::{KeyState, Keycode}, + backend::input::{InputTime, KeyState, Keycode}, input::{ Seat, SeatHandler, keyboard::{ @@ -38,7 +38,7 @@ impl KeyboardGrab for SwapWindowGrab { state: KeyState, modifiers: Option, serial: Serial, - time: u32, + time: InputTime, ) { if !matches!(&data.common.shell.read().overview_mode.active_trigger(), Some(Trigger::KeyboardSwap(_, d)) if d == &self.desc) { diff --git a/src/shell/zoom.rs b/src/shell/zoom.rs index 0c0e9340..cfe84f06 100644 --- a/src/shell/zoom.rs +++ b/src/shell/zoom.rs @@ -11,7 +11,7 @@ use cosmic_comp_config::{ZoomConfig, ZoomMovement}; use cosmic_config::ConfigSet; use keyframe::{ease, functions::Linear}; use smithay::{ - backend::renderer::ImportMem, + backend::{input::InputTime, renderer::ImportMem}, desktop::space::SpaceElement, input::{ Seat, @@ -1023,7 +1023,7 @@ impl PointerTarget for ZoomFocusTarget { } } - fn leave(&self, seat: &Seat, data: &mut State, serial: Serial, time: u32) { + fn leave(&self, seat: &Seat, data: &mut State, serial: Serial, time: InputTime) { match self { ZoomFocusTarget::Main(elem) => PointerTarget::leave(elem, seat, data, serial, time), ZoomFocusTarget::Menu(elem) => PointerTarget::leave(elem, seat, data, serial, time), diff --git a/src/utils/iced/mod.rs b/src/utils/iced/mod.rs index 2bfe888d..94b27ea7 100644 --- a/src/utils/iced/mod.rs +++ b/src/utils/iced/mod.rs @@ -31,7 +31,7 @@ use ordered_float::OrderedFloat; use smithay::{ backend::{ allocator::Fourcc, - input::{ButtonState, KeyState}, + input::{ButtonState, InputTime, KeyState}, renderer::{ ImportMem, element::{ @@ -581,7 +581,7 @@ impl PointerTarget for IcedEle _seat: &Seat, _data: &mut crate::state::State, _serial: Serial, - _time: u32, + _time: InputTime, ) { let mut internal = self.0.lock().unwrap(); internal @@ -784,7 +784,7 @@ impl KeyboardTarget for IcedEl _key: KeysymHandle<'_>, _state: KeyState, _serial: Serial, - _time: u32, + _time: InputTime, ) { // TODO convert keys } diff --git a/src/wayland/handlers/compositor.rs b/src/wayland/handlers/compositor.rs index 12bc2e56..ed40448b 100644 --- a/src/wayland/handlers/compositor.rs +++ b/src/wayland/handlers/compositor.rs @@ -3,9 +3,12 @@ use crate::{shell::grabs::SeatMoveGrabState, state::ClientState, utils::prelude::*}; use calloop::Interest; use smithay::{ - backend::renderer::{ - element::{Kind, surface::KindEvaluation}, - utils::{on_commit_buffer_handler, with_renderer_surface_state}, + backend::{ + input::InputTime, + renderer::{ + element::{Kind, surface::KindEvaluation}, + utils::{on_commit_buffer_handler, with_renderer_surface_state}, + }, }, desktop::{LayerSurface, PopupKind, WindowSurfaceType, layer_map_for_output}, reexports::wayland_server::{Client, Resource, protocol::wl_surface::WlSurface}, @@ -325,9 +328,11 @@ impl CompositorHandler for State { } } else { std::mem::drop(shell); - seat.get_pointer() - .unwrap() - .unset_grab(self, SERIAL_COUNTER.next_serial(), 0); + seat.get_pointer().unwrap().unset_grab( + self, + SERIAL_COUNTER.next_serial(), + InputTime::now(), + ); return; } } diff --git a/src/wayland/handlers/pointer_constraints.rs b/src/wayland/handlers/pointer_constraints.rs index 9ce5f63a..e024bb40 100644 --- a/src/wayland/handlers/pointer_constraints.rs +++ b/src/wayland/handlers/pointer_constraints.rs @@ -5,7 +5,10 @@ use smithay::{ input::pointer::PointerHandle, reexports::wayland_server::protocol::wl_surface::WlSurface, utils::{Logical, Point}, - wayland::{pointer_constraints::PointerConstraintsHandler, seat::WaylandFocus}, + wayland::{ + pointer_constraints::{ConstraintRemove, PointerConstraintsHandler}, + seat::WaylandFocus, + }, }; pub use smithay::wayland::pointer_constraints::{PointerConstraintRef, with_pointer_constraint}; @@ -76,23 +79,38 @@ impl PointerConstraintsHandler for State { } } - fn remove_constraint(&mut self, surface: &WlSurface, pointer: &PointerHandle) { - if with_pointer_constraint(surface, pointer, |constraint| constraint.is_none()) { - let seat = self - .common - .shell - .read() - .seats - .iter() - .find(|s| s.get_pointer().as_ref() == Some(pointer)) - .cloned(); + fn remove_constraint( + &mut self, + surface: &WlSurface, + pointer: &PointerHandle, + constraint_remove: ConstraintRemove, + ) { + match constraint_remove { + ConstraintRemove::PointerLeave(_) => { + // If the constraint was broken by the pointer forcibly leaving the surface, then it doesn't + // make much sense to warp it. + return; + } + ConstraintRemove::Destroyed(constraint) => { + let Some(seat) = self + .common + .shell + .read() + .seats + .iter() + .find(|s| s.get_pointer().as_ref() == Some(pointer)) + .cloned() + else { + return; + }; + let Some((hint_surface, hint_location)) = seat.pointer_constraint_hint() else { + return; + }; - if let Some(seat) = seat - && let Some((hint_surface, hint_location)) = seat.pointer_constraint_hint() - && hint_surface == *surface - { - self.apply_cursor_hint(surface, pointer, hint_location); - seat.set_pointer_constraint_hint(None); + if hint_surface == *surface { + self.apply_cursor_hint(surface, pointer, hint_location, Some(&constraint)); + seat.set_pointer_constraint_hint(None); + } } } } diff --git a/src/wayland/handlers/pointer_warp.rs b/src/wayland/handlers/pointer_warp.rs index 971ab583..634817cf 100644 --- a/src/wayland/handlers/pointer_warp.rs +++ b/src/wayland/handlers/pointer_warp.rs @@ -38,7 +38,7 @@ impl PointerWarpHandler for State { drop(shell); if let Some(pointer_handle) = pointer_handle { - self.apply_cursor_hint(&surface, &pointer_handle, pos); + self.apply_cursor_hint(&surface, &pointer_handle, pos, None); } } } diff --git a/src/wayland/handlers/toplevel_management.rs b/src/wayland/handlers/toplevel_management.rs index 3da39952..b1616bca 100644 --- a/src/wayland/handlers/toplevel_management.rs +++ b/src/wayland/handlers/toplevel_management.rs @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only use smithay::{ + backend::input::InputTime, desktop::{WindowSurfaceType, layer_map_for_output}, input::{Seat, pointer::MotionEvent}, output::Output, @@ -124,7 +125,7 @@ impl ToplevelManagementHandler for State { &MotionEvent { location: new_pos.to_f64().as_logical(), serial, - time: self.common.clock.now().as_millis(), + time: InputTime::now(), }, ); ptr.frame(self); diff --git a/src/xwayland.rs b/src/xwayland.rs index da3fb36b..68fb95b3 100644 --- a/src/xwayland.rs +++ b/src/xwayland.rs @@ -20,7 +20,7 @@ use smithay::{ backend::{ allocator::Fourcc, drm::DrmNode, - input::{ButtonState, KeyState, Keycode}, + input::{ButtonState, InputTime, KeyState, Keycode}, renderer::{ Bind, Frame, Offscreen, Renderer, element::{ @@ -396,7 +396,7 @@ impl Common { state: KeyState, modifiers: ModifiersState, serial: Serial, - time: u32, + time: InputTime, ) { let config = self.config.cosmic_conf.xwayland_eavesdropping.keyboard; if config == EavesdroppingKeyboardMode::None { @@ -458,7 +458,7 @@ impl Common { tracing::trace!("Forwaring key {} {:?} to xwayland", code.raw() - 8, state); for wl_keyboard in keyboard.client_keyboards(&xstate.client) { - wl_keyboard.key(serial.into(), time, code.raw() - 8, state.into()); + wl_keyboard.key(serial.into(), time.millis(), code.raw() - 8, state.into()); if xstate.last_modifier_state != Some(modifiers) { xstate.last_modifier_state = Some(modifiers); wl_keyboard.modifiers( @@ -478,7 +478,7 @@ impl Common { button: u32, state: ButtonState, serial: Serial, - time: u32, + time: InputTime, ) { if !self.config.cosmic_conf.xwayland_eavesdropping.pointer { return; @@ -518,7 +518,7 @@ impl Common { tracing::trace!("Forwaring ptr button {} {:?} to Xwayland", button, state); for wl_pointer in pointer.client_pointers(&xstate.client) { - wl_pointer.button(serial.into(), time, button, state.into()); + wl_pointer.button(serial.into(), time.millis(), button, state.into()); } } From 158e2b7f91e3e6b3a569a7ea26251182a1e40627 Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Tue, 25 Aug 2026 19:21:49 +0200 Subject: [PATCH 02/69] i18n: translation updates from weblate Co-authored-by: Kurt Harren Catindig --- resources/i18n/fil/cosmic_comp.ftl | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 resources/i18n/fil/cosmic_comp.ftl diff --git a/resources/i18n/fil/cosmic_comp.ftl b/resources/i18n/fil/cosmic_comp.ftl new file mode 100644 index 00000000..e69de29b From 94178034ddc3386bf256fcc952f72ddb55997d49 Mon Sep 17 00:00:00 2001 From: RipleyTom Date: Mon, 27 Jul 2026 20:53:57 +0200 Subject: [PATCH 03/69] feat: allow XWayland window to start minimized --- src/shell/mod.rs | 13 +++++++++++-- src/wayland/handlers/xdg_shell/mod.rs | 1 + src/xwayland.rs | 3 +++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 009c98dc..3fa863d3 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -254,6 +254,7 @@ pub struct PendingWindow { pub surface: CosmicSurface, pub seat: Seat, pub fullscreen: Option, + pub minimized: bool, pub maximized: bool, pub sticky: bool, } @@ -2856,6 +2857,7 @@ impl Shell { surface: window, seat, fullscreen: output, + minimized: should_be_minimized, maximized: should_be_maximized, sticky: mut should_be_sticky, } = self.pending_windows.remove(pos); @@ -2939,6 +2941,7 @@ impl Shell { if let Some(FocusTarget::Window(focused)) = maybe_focused && let Some(stack) = focused.stack_ref() && !is_dialog + && !should_be_minimized && !should_be_maximized && !(workspace.is_tiled(&focused.active_window()) && floating_exception) { @@ -2988,8 +2991,13 @@ impl Shell { self.maximize_request(&mapped, &seat, false, loop_handle); } - let new_target = if (workspace_output == seat.active_output() - && active_handle == workspace_handle) + if should_be_minimized { + self.minimize_request(&window); + } + + let new_target = if should_be_minimized { + None + } else if (workspace_output == seat.active_output() && active_handle == workspace_handle) || should_be_sticky { // TODO: enforce focus stealing prevention by also checking the same rules as for the else case. @@ -3113,6 +3121,7 @@ impl Shell { surface, seat: seat.clone(), fullscreen: None, + minimized: false, maximized: false, sticky: false, }); diff --git a/src/wayland/handlers/xdg_shell/mod.rs b/src/wayland/handlers/xdg_shell/mod.rs index b4f16c4c..c9fb926f 100644 --- a/src/wayland/handlers/xdg_shell/mod.rs +++ b/src/wayland/handlers/xdg_shell/mod.rs @@ -50,6 +50,7 @@ impl XdgShellHandler for State { surface, seat, fullscreen: None, + minimized: false, maximized: false, sticky: false, }) diff --git a/src/xwayland.rs b/src/xwayland.rs index 68fb95b3..78193d13 100644 --- a/src/xwayland.rs +++ b/src/xwayland.rs @@ -808,6 +808,7 @@ impl XwmHandler for State { ); } let fullscreen = window.is_fullscreen().then(|| seat.active_output()); + let minimized = window.is_hidden(); let maximized = window.is_maximized(); if let Some(pending) = shell .pending_windows @@ -816,6 +817,7 @@ impl XwmHandler for State { { pending.seat = seat; pending.fullscreen = fullscreen; + pending.minimized = minimized; pending.maximized = maximized; } else { let surface = CosmicSurface::from(window); @@ -823,6 +825,7 @@ impl XwmHandler for State { surface, seat, fullscreen, + minimized, maximized, sticky: false, }) From 9fe22c86b600ca13ac2d31fa4d5eb924b3443227 Mon Sep 17 00:00:00 2001 From: Hojjat Date: Thu, 27 Aug 2026 15:24:25 -0600 Subject: [PATCH 04/69] fix(corner-radius): use layer surface size for radius validation --- src/wayland/protocols/corner_radius.rs | 34 ++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/src/wayland/protocols/corner_radius.rs b/src/wayland/protocols/corner_radius.rs index 51dc1153..479f890a 100644 --- a/src/wayland/protocols/corner_radius.rs +++ b/src/wayland/protocols/corner_radius.rs @@ -5,16 +5,15 @@ use cosmic_protocols::corner_radius::v1::server::cosmic_corner_radius_toplevel_v use cosmic_protocols::corner_radius::v1::server::{ cosmic_corner_radius_manager_v1, cosmic_corner_radius_toplevel_v1, }; -use smithay::desktop::utils::bbox_from_surface_tree; use smithay::reexports::wayland_protocols::xdg::shell::server::xdg_popup::XdgPopup; use smithay::reexports::wayland_protocols_wlr::layer_shell::v1::server::zwlr_layer_surface_v1::ZwlrLayerSurfaceV1; use smithay::reexports::wayland_server::New; use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface; -use smithay::utils::{HookId, Logical, Point, Rectangle}; +use smithay::utils::{HookId, Logical, Rectangle}; use smithay::wayland::compositor::Cacheable; use smithay::wayland::compositor::add_pre_commit_hook; use smithay::wayland::compositor::with_states; -use smithay::wayland::shell::wlr_layer::WlrLayerShellHandler; +use smithay::wayland::shell::wlr_layer::{LayerSurfaceAttributes, WlrLayerShellHandler}; use smithay::wayland::shell::xdg::{SurfaceCachedState, XdgShellSurfaceUserData}; use smithay::{ reexports::{ @@ -655,7 +654,6 @@ fn pad_rect( } fn layer_radius_hook(_state: &mut D, _dh: &DisplayHandle, surface: &WlSurface) { - let bbox = bbox_from_surface_tree(surface, Point::default()); with_states(surface, |surface_data| { let corners = *surface_data .cached_state @@ -665,8 +663,34 @@ fn layer_radius_hook(_state: &mut D, _dh: &DisplayHandle, surface: & .cached_state .get::() .pending(); + + // The radius and padding is relative to the size of `zwlr_layer_surface_v1` (according to + // the protocol). That is the configure the client acked. + // + // `last_acked` is the becomes current as part of this commit, + // so it is staged consistently with the pending radius/padding above. + // + // Until the client acks a configure there is no defined size, and nothing to check. + let Some(size) = surface_data + .data_map + .get::>() + .and_then(|attrs| { + attrs + .lock() + .unwrap() + .last_acked + .as_ref() + .and_then(|configure| configure.state.size) + }) + else { + return; + }; + let empty = Padding::default(); - let Some(padded_box) = pad_rect(bbox, padding.0.as_ref().unwrap_or(&empty)) else { + let Some(padded_box) = pad_rect( + Rectangle::from_size(size), + padding.0.as_ref().unwrap_or(&empty), + ) else { if let Some(hook) = surface_data.data_map.get::() { let hook_ref = hook.lock().unwrap(); if let Some((_, obj)) = hook_ref.as_ref() From b407ed560a4ac179d0289d231095ff20739fb919 Mon Sep 17 00:00:00 2001 From: Victoria Brekenfeld Date: Fri, 14 Aug 2026 18:25:41 +0200 Subject: [PATCH 05/69] wayland/decoration: Make default decoration mode configurable --- cosmic-comp-config/src/lib.rs | 9 +++ src/config/mod.rs | 11 ++- src/wayland/handlers/decoration.rs | 108 +++++++++++++++++++++++++++-- 3 files changed, 120 insertions(+), 8 deletions(-) diff --git a/cosmic-comp-config/src/lib.rs b/cosmic-comp-config/src/lib.rs index 853ba447..510927f9 100644 --- a/cosmic-comp-config/src/lib.rs +++ b/cosmic-comp-config/src/lib.rs @@ -66,6 +66,13 @@ impl Default for AppearanceConfig { } } +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] +pub enum DecorationPreference { + #[default] + ClientSide, + ServerSide, +} + #[derive(Clone, Debug, PartialEq, CosmicConfigEntry)] #[version = 1] pub struct CosmicCompConfig { @@ -104,6 +111,7 @@ pub struct CosmicCompConfig { /// Briefly magnify the cursor when the pointer is shaken, to help locate it pub cursor_shake_to_find: bool, pub activation_policy: ActivationPolicy, + pub decoration_preference: DecorationPreference, } impl Default for CosmicCompConfig { @@ -143,6 +151,7 @@ impl Default for CosmicCompConfig { cursor_hide_timeout: None, cursor_shake_to_find: true, activation_policy: ActivationPolicy::default(), + decoration_preference: DecorationPreference::default(), } } } diff --git a/src/config/mod.rs b/src/config/mod.rs index abef562b..9db9a9bb 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -49,8 +49,8 @@ mod types; use cosmic::config::CosmicTk; pub use cosmic_comp_config::EdidProduct; use cosmic_comp_config::{ - ActivationPolicy, AppearanceConfig, CosmicCompConfig, KeyboardConfig, TileBehavior, XkbConfig, - XwaylandDescaling, XwaylandEavesdropping, ZoomConfig, + ActivationPolicy, AppearanceConfig, CosmicCompConfig, DecorationPreference, KeyboardConfig, + TileBehavior, XkbConfig, XwaylandDescaling, XwaylandEavesdropping, ZoomConfig, input::{DeviceState as InputDeviceState, InputConfig, TouchpadOverride}, output::comp::{ OutputConfig, OutputInfo, OutputState, OutputsConfig, TransformDef, load_outputs, @@ -1000,6 +1000,13 @@ fn config_changed(config: cosmic_config::Config, keys: Vec, state: &mut state.common.config.cosmic_conf.activation_policy = new; } } + "decoration_preference" => { + let new = get_config::(&config, "decoration_preference"); + if new != state.common.config.cosmic_conf.decoration_preference { + state.common.config.cosmic_conf.decoration_preference = new; + state.update_decorations(); + } + } _ => {} } } diff --git a/src/wayland/handlers/decoration.rs b/src/wayland/handlers/decoration.rs index 90ec5855..ae58d338 100644 --- a/src/wayland/handlers/decoration.rs +++ b/src/wayland/handlers/decoration.rs @@ -1,5 +1,6 @@ use std::{cell::RefCell, sync::Mutex}; +use cosmic_comp_config::DecorationPreference; use smithay::{ desktop::Window, reexports::{ @@ -20,7 +21,7 @@ use smithay::{ }; use wayland_backend::protocol::WEnum; -use crate::state::State; +use crate::{shell::CosmicMapped, state::State}; pub struct PreferredDecorationMode(RefCell>); @@ -29,7 +30,7 @@ impl PreferredDecorationMode { window .user_data() .get::() - .is_none() + .is_none_or(|mode| mode.0.borrow().is_none()) } pub fn mode(window: &Window) -> Option { @@ -53,6 +54,73 @@ impl PreferredDecorationMode { } } +impl State { + pub fn default_decoration(&self) -> DecorationPreference { + self.common.config.cosmic_conf.decoration_preference + } + + pub fn update_decorations(&self) { + let shell = self.common.shell.read(); + + let update = |mapped: &CosmicMapped| { + let mode = if mapped.is_stack() { + XdgMode::ServerSide + } else { + XdgMode::from_preference(self.default_decoration()) + }; + for (window, _) in mapped.windows() { + if PreferredDecorationMode::is_unset(&window.0) { + if let Some(toplevel) = window.0.toplevel() { + if toplevel.with_committed_state(|state| { + state.is_some_and(|state| state.decoration_mode.is_some()) + }) { + toplevel.with_pending_state(|state| { + state.decoration_mode = Some(mode); + }); + toplevel.send_configure(); + } + } + } + } + }; + + for set in shell.workspaces.sets.values() { + set.sticky_layer.mapped().for_each(update); + } + + for space in shell.workspaces.spaces() { + space.mapped().for_each(update); + space + .minimized_windows + .iter() + .filter_map(|m| m.mapped()) + .for_each(update); + } + } +} + +trait FromDecorationPreference { + fn from_preference(preference: DecorationPreference) -> Self; +} + +impl FromDecorationPreference for XdgMode { + fn from_preference(preference: DecorationPreference) -> Self { + match preference { + DecorationPreference::ClientSide => XdgMode::ClientSide, + DecorationPreference::ServerSide => XdgMode::ServerSide, + } + } +} + +impl FromDecorationPreference for KdeMode { + fn from_preference(preference: DecorationPreference) -> Self { + match preference { + DecorationPreference::ClientSide => KdeMode::Client, + DecorationPreference::ServerSide => KdeMode::Server, + } + } +} + pub type KdeDecorationData = Mutex; #[derive(Debug, Default)] pub struct KdeDecorationSurfaceState { @@ -67,7 +135,7 @@ impl XdgDecorationHandler for State { let mode = if mapped.is_stack() { XdgMode::ServerSide } else { - XdgMode::ClientSide + XdgMode::from_preference(self.default_decoration()) }; if let Some((window, _)) = mapped @@ -80,6 +148,10 @@ impl XdgDecorationHandler for State { }); toplevel.send_configure(); } + } else { + toplevel.with_pending_state(|state| { + state.decoration_mode = Some(XdgMode::from_preference(self.default_decoration())) + }) } } @@ -99,6 +171,13 @@ impl XdgDecorationHandler for State { } } else { toplevel.with_pending_state(|state| state.decoration_mode = Some(mode)); + if let Some(pending) = shell + .pending_windows + .iter() + .find(|pending| pending.surface.0.toplevel().is_some_and(|t| t == &toplevel)) + { + PreferredDecorationMode::update(&pending.surface.0, Some(mode)); + } } } @@ -110,11 +189,28 @@ impl XdgDecorationHandler for State { .find(|(window, _)| window.wl_surface().as_deref() == Some(toplevel.wl_surface())) && let Some(toplevel) = window.0.toplevel() { + let mode = if mapped.is_stack() { + XdgMode::ServerSide + } else { + XdgMode::from_preference(self.default_decoration()) + }; + PreferredDecorationMode::update(&window.0, None); toplevel.with_pending_state(|state| { - state.decoration_mode = None; + state.decoration_mode = Some(mode); }); toplevel.send_configure(); + } else { + toplevel.with_pending_state(|state| { + state.decoration_mode = Some(XdgMode::from_preference(self.default_decoration())) + }); + if let Some(pending) = shell + .pending_windows + .iter() + .find(|pending| pending.surface.0.toplevel().is_some_and(|t| t == &toplevel)) + { + PreferredDecorationMode::update(&pending.surface.0, None); + } } } } @@ -129,10 +225,10 @@ impl KdeDecorationHandler for State { if mapped.is_stack() { KdeMode::Server } else { - KdeMode::Client + KdeMode::from_preference(self.default_decoration()) } } else { - KdeMode::Client + KdeMode::from_preference(self.default_decoration()) }; with_states(surface, |states| { From a7d31a75d293e98fe75151c167451d5da50397a8 Mon Sep 17 00:00:00 2001 From: Victoria Brekenfeld Date: Fri, 24 Jul 2026 14:14:15 +0200 Subject: [PATCH 06/69] backend/kms: Check all connectors for primary gpu --- src/backend/kms/mod.rs | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/backend/kms/mod.rs b/src/backend/kms/mod.rs index 6da04aac..36c6407c 100644 --- a/src/backend/kms/mod.rs +++ b/src/backend/kms/mod.rs @@ -32,7 +32,11 @@ use smithay::{ calloop::{Dispatcher, EventLoop, LoopHandle}, drm::{ Device as _, - control::{Device as _, connector::Interface, crtc}, + control::{ + Device as _, + connector::{Interface, State as ConnectorState}, + crtc, + }, }, input::{self, Libinput}, wayland_protocols::wp::linux_dmabuf::zv1::server::zwp_linux_dmabuf_feedback_v1::TrancheFlags, @@ -250,13 +254,18 @@ fn determine_primary_gpu( // try to find builtin display for dev in drm_devices.values() { - if dev.inner.surfaces.values().any(|s| { - if let Ok(conn_info) = dev.drm.device().get_connector(s.connector, false) { - let i = conn_info.interface(); - i == Interface::EmbeddedDisplayPort || i == Interface::LVDS || i == Interface::DSI - } else { - false - } + let drm = dev.drm.device(); + let res_handles = drm.resource_handles()?; + let connectors = res_handles.connectors(); + if connectors.iter().any(|conn| { + let Ok(conn_info) = drm.get_connector(*conn, false) else { + return false; + }; + let i = conn_info.interface(); + conn_info.state() == ConnectorState::Connected + && (i == Interface::EmbeddedDisplayPort + || i == Interface::LVDS + || i == Interface::DSI) }) { return Ok(Some(dev.inner.render_node)); } From e93ec67a117126ce445abf1588a7d2f8180bf3b0 Mon Sep 17 00:00:00 2001 From: Shehriyar Qureshi Date: Tue, 1 Sep 2026 21:05:18 +0500 Subject: [PATCH 07/69] fix(kms): typo in log message --- src/backend/kms/device.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/kms/device.rs b/src/backend/kms/device.rs index 418a16f3..c58450bc 100644 --- a/src/backend/kms/device.rs +++ b/src/backend/kms/device.rs @@ -693,7 +693,7 @@ impl Device { ) .with_context(|| { format!( - "Failed to optain file descriptor for drm device: {}", + "Failed to obtain file descriptor for drm device: {}", path.display() ) })?, From 9059873c84c79c8d14f54464f2a126d8c9491ceb Mon Sep 17 00:00:00 2001 From: Konstantinos Date: Fri, 28 Aug 2026 22:22:53 +0300 Subject: [PATCH 08/69] fix: Do not magnify cursor when there is an active grab. --- src/input/mod.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/input/mod.rs b/src/input/mod.rs index d619a525..6055ad33 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -338,6 +338,9 @@ impl State { let current_output = seat.active_output(); if self.common.config.cosmic_conf.cursor_shake_to_find + && seat + .get_pointer() + .is_some_and(|pointer| !pointer.is_grabbed()) && let Some(cursor_state) = seat.user_data() .get::() From 86919566440fffbb437aff9c000774a7c32ce6b4 Mon Sep 17 00:00:00 2001 From: Hojjat Date: Wed, 2 Sep 2026 13:45:28 -0600 Subject: [PATCH 09/69] fix: validate layer radius against the pending surface size --- src/wayland/protocols/corner_radius.rs | 49 +++++++++++++++----------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/src/wayland/protocols/corner_radius.rs b/src/wayland/protocols/corner_radius.rs index 479f890a..5c1a200c 100644 --- a/src/wayland/protocols/corner_radius.rs +++ b/src/wayland/protocols/corner_radius.rs @@ -5,16 +5,19 @@ use cosmic_protocols::corner_radius::v1::server::cosmic_corner_radius_toplevel_v use cosmic_protocols::corner_radius::v1::server::{ cosmic_corner_radius_manager_v1, cosmic_corner_radius_toplevel_v1, }; +use smithay::backend::renderer::buffer_dimensions; +use smithay::backend::renderer::utils::RendererSurfaceStateUserData; use smithay::reexports::wayland_protocols::xdg::shell::server::xdg_popup::XdgPopup; use smithay::reexports::wayland_protocols_wlr::layer_shell::v1::server::zwlr_layer_surface_v1::ZwlrLayerSurfaceV1; use smithay::reexports::wayland_server::New; use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface; use smithay::utils::{HookId, Logical, Rectangle}; -use smithay::wayland::compositor::Cacheable; use smithay::wayland::compositor::add_pre_commit_hook; use smithay::wayland::compositor::with_states; -use smithay::wayland::shell::wlr_layer::{LayerSurfaceAttributes, WlrLayerShellHandler}; +use smithay::wayland::compositor::{BufferAssignment, Cacheable, SurfaceAttributes}; +use smithay::wayland::shell::wlr_layer::WlrLayerShellHandler; use smithay::wayland::shell::xdg::{SurfaceCachedState, XdgShellSurfaceUserData}; +use smithay::wayland::viewporter::ViewportCachedState; use smithay::{ reexports::{ wayland_protocols::xdg::shell::server::xdg_toplevel::XdgToplevel, @@ -664,25 +667,31 @@ fn layer_radius_hook(_state: &mut D, _dh: &DisplayHandle, surface: & .get::() .pending(); - // The radius and padding is relative to the size of `zwlr_layer_surface_v1` (according to - // the protocol). That is the configure the client acked. - // - // `last_acked` is the becomes current as part of this commit, - // so it is staged consistently with the pending radius/padding above. - // - // Until the client acks a configure there is no defined size, and nothing to check. - let Some(size) = surface_data - .data_map - .get::>() - .and_then(|attrs| { - attrs - .lock() - .unwrap() - .last_acked - .as_ref() - .and_then(|configure| configure.state.size) + // The wl_surface size after this commit is: + // - viewport destination if set + // - else the logical size of the buffer that will be current attached now + // - else existing + let size = surface_data + .cached_state + .get::() + .pending() + .size() + .or_else(|| { + let mut guard = surface_data.cached_state.get::(); + let attrs = guard.pending(); + match &attrs.buffer { + Some(BufferAssignment::NewBuffer(buffer)) => buffer_dimensions(buffer) + .map(|d| d.to_logical(attrs.buffer_scale, attrs.buffer_transform.into())), + _ => None, + } }) - else { + .or_else(|| { + surface_data + .data_map + .get::() + .and_then(|state| state.lock().unwrap().surface_size()) + }); + let Some(size) = size else { return; }; From e62e35e5cc6bfa5cd5ba9dee718245497667037d Mon Sep 17 00:00:00 2001 From: Frederic Laing Date: Mon, 31 Aug 2026 20:23:45 +0200 Subject: [PATCH 10/69] fix: keep Xwayland frame callbacks progressing --- src/state.rs | 41 ++++++++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/src/state.rs b/src/state.rs index 5ccc7a7b..76c4c098 100644 --- a/src/state.rs +++ b/src/state.rs @@ -139,6 +139,14 @@ struct Localizations; pub static LANG_LOADER: LazyLock = LazyLock::new(|| fluent_language_loader!()); +fn xwayland_frame_throttle(throttle: Option, is_xwayland: bool) -> Option { + if is_xwayland { + Some(Duration::ZERO) + } else { + throttle + } +} + #[macro_export] macro_rules! fl { ($message_id:literal) => {{ @@ -1365,7 +1373,9 @@ impl Common { && let Some(grab_state) = move_grab.lock().unwrap().as_ref() { for (window, _) in grab_state.element().windows() { - window.send_frame(output, time, throttle(&window), should_send); + let throttle = + xwayland_frame_throttle(throttle(&window), window.x11_surface().is_some()); + window.send_frame(output, time, throttle, should_send); } } @@ -1389,25 +1399,34 @@ impl Common { .mapped() .for_each(|mapped| { for (window, _) in mapped.windows() { - window.send_frame(output, time, throttle(&window), should_send); + let throttle = + xwayland_frame_throttle(throttle(&window), window.x11_surface().is_some()); + window.send_frame(output, time, throttle, should_send); } }); if let Some(active) = shell.active_space(output) { if let Some(fs) = active.get_fullscreen(shell.seats.last_active()) { - fs.surface - .send_frame(output, time, throttle(&fs.surface), should_send); + let throttle = xwayland_frame_throttle( + throttle(&fs.surface), + fs.surface.x11_surface().is_some(), + ); + fs.surface.send_frame(output, time, throttle, should_send); } active.mapped().for_each(|mapped| { for (window, _) in mapped.windows() { - window.send_frame(output, time, throttle(&window), should_send); + let throttle = + xwayland_frame_throttle(throttle(&window), window.x11_surface().is_some()); + window.send_frame(output, time, throttle, should_send); } }); // other (throttled) windows active.minimized_windows.iter().for_each(|m| { for window in m.windows() { - window.send_frame(output, time, throttle(&window), |_, _| None); + let throttle = + xwayland_frame_throttle(throttle(&window), window.x11_surface().is_some()); + window.send_frame(output, time, throttle, |_, _| None); } }); @@ -1418,17 +1437,25 @@ impl Common { { if let Some(fs) = space.get_fullscreen(shell.seats.last_active()) { let throttle = min(throttle(space), throttle(&fs.surface)); + let throttle = + xwayland_frame_throttle(throttle, fs.surface.x11_surface().is_some()); fs.surface.send_frame(output, time, throttle, |_, _| None); } space.mapped().for_each(|mapped| { for (window, _) in mapped.windows() { let throttle = min(throttle(space), throttle(&window)); + let throttle = + xwayland_frame_throttle(throttle, window.x11_surface().is_some()); window.send_frame(output, time, throttle, |_, _| None); } }); space.minimized_windows.iter().for_each(|m| { for window in m.windows() { - window.send_frame(output, time, throttle(&window), |_, _| None); + let throttle = xwayland_frame_throttle( + throttle(&window), + window.x11_surface().is_some(), + ); + window.send_frame(output, time, throttle, |_, _| None); } }) } From 0d7592857964fe1061440b2b4504dbc4d3ec826d Mon Sep 17 00:00:00 2001 From: Frederic Laing Date: Tue, 1 Sep 2026 21:04:55 +0200 Subject: [PATCH 11/69] chore: refactor throttle function --- src/state.rs | 52 ++++++++++++++++++++-------------------------------- 1 file changed, 20 insertions(+), 32 deletions(-) diff --git a/src/state.rs b/src/state.rs index 76c4c098..28ed8fd4 100644 --- a/src/state.rs +++ b/src/state.rs @@ -139,14 +139,6 @@ struct Localizations; pub static LANG_LOADER: LazyLock = LazyLock::new(|| fluent_language_loader!()); -fn xwayland_frame_throttle(throttle: Option, is_xwayland: bool) -> Option { - if is_xwayland { - Some(Duration::ZERO) - } else { - throttle - } -} - #[macro_export] macro_rules! fl { ($message_id:literal) => {{ @@ -1336,8 +1328,12 @@ impl Common { const THROTTLE: Option = Some(Duration::from_millis(995)); const SCREENCOPY_THROTTLE: Option = Some(Duration::from_nanos(16_666_666)); - fn throttle(session_holder: &impl SessionHolder) -> Option { - if session_holder.sessions().is_empty() && session_holder.cursor_sessions().is_empty() { + fn throttle(session_holder: &impl SessionHolder, is_xwayland: bool) -> Option { + if is_xwayland { + Some(Duration::ZERO) + } else if session_holder.sessions().is_empty() + && session_holder.cursor_sessions().is_empty() + { THROTTLE } else { SCREENCOPY_THROTTLE @@ -1373,8 +1369,7 @@ impl Common { && let Some(grab_state) = move_grab.lock().unwrap().as_ref() { for (window, _) in grab_state.element().windows() { - let throttle = - xwayland_frame_throttle(throttle(&window), window.x11_surface().is_some()); + let throttle = throttle(&window, window.x11_surface().is_some()); window.send_frame(output, time, throttle, should_send); } } @@ -1399,24 +1394,19 @@ impl Common { .mapped() .for_each(|mapped| { for (window, _) in mapped.windows() { - let throttle = - xwayland_frame_throttle(throttle(&window), window.x11_surface().is_some()); + let throttle = throttle(&window, window.x11_surface().is_some()); window.send_frame(output, time, throttle, should_send); } }); if let Some(active) = shell.active_space(output) { if let Some(fs) = active.get_fullscreen(shell.seats.last_active()) { - let throttle = xwayland_frame_throttle( - throttle(&fs.surface), - fs.surface.x11_surface().is_some(), - ); + let throttle = throttle(&fs.surface, fs.surface.x11_surface().is_some()); fs.surface.send_frame(output, time, throttle, should_send); } active.mapped().for_each(|mapped| { for (window, _) in mapped.windows() { - let throttle = - xwayland_frame_throttle(throttle(&window), window.x11_surface().is_some()); + let throttle = throttle(&window, window.x11_surface().is_some()); window.send_frame(output, time, throttle, should_send); } }); @@ -1424,8 +1414,7 @@ impl Common { // other (throttled) windows active.minimized_windows.iter().for_each(|m| { for window in m.windows() { - let throttle = - xwayland_frame_throttle(throttle(&window), window.x11_surface().is_some()); + let throttle = throttle(&window, window.x11_surface().is_some()); window.send_frame(output, time, throttle, |_, _| None); } }); @@ -1436,25 +1425,24 @@ impl Common { .filter(|w| w.handle != active.handle) { if let Some(fs) = space.get_fullscreen(shell.seats.last_active()) { - let throttle = min(throttle(space), throttle(&fs.surface)); - let throttle = - xwayland_frame_throttle(throttle, fs.surface.x11_surface().is_some()); + let throttle = min( + throttle(space, false), + throttle(&fs.surface, fs.surface.x11_surface().is_some()), + ); fs.surface.send_frame(output, time, throttle, |_, _| None); } space.mapped().for_each(|mapped| { for (window, _) in mapped.windows() { - let throttle = min(throttle(space), throttle(&window)); - let throttle = - xwayland_frame_throttle(throttle, window.x11_surface().is_some()); + let throttle = min( + throttle(space, false), + throttle(&window, window.x11_surface().is_some()), + ); window.send_frame(output, time, throttle, |_, _| None); } }); space.minimized_windows.iter().for_each(|m| { for window in m.windows() { - let throttle = xwayland_frame_throttle( - throttle(&window), - window.x11_surface().is_some(), - ); + let throttle = throttle(&window, window.x11_surface().is_some()); window.send_frame(output, time, throttle, |_, _| None); } }) From 8ec1ffb740dfbd02ccc6cdaa431dd3438ec51f68 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Wed, 2 Sep 2026 12:49:01 -0700 Subject: [PATCH 12/69] protocols/keyboard-layout: Send ei `modifiers` on group change This makes `cosmic-osk` show a group change on `super+space`. Previously a change like that wouldn't be sent until a keyboard input changed the modifier state, for instance releasing the shift key. --- src/config/mod.rs | 4 +++- src/input/mod.rs | 11 +++-------- src/libei.rs | 4 +++- src/wayland/handlers/keyboard_layout.rs | 6 ++++++ src/wayland/protocols/keyboard_layout.rs | 5 ++++- 5 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/config/mod.rs b/src/config/mod.rs index 9db9a9bb..d3d2919b 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -842,7 +842,9 @@ fn config_changed(config: cosmic_config::Config, keys: Vec, state: &mut } if !state.common.ei_seats.is_empty() { let seat = state.common.shell.read().seats.last_active().clone(); - state.broadcast_ei_keyboard_modifiers(&seat); + if let Some(keyboard) = seat.get_keyboard() { + state.broadcast_ei_keyboard_modifiers(&keyboard); + } } state.common.config.cosmic_conf.xkb_config = value; } diff --git a/src/input/mod.rs b/src/input/mod.rs index 6055ad33..0228d3cb 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -49,6 +49,7 @@ use smithay::{ desktop::{PopupKeyboardGrab, WindowSurfaceType, utils::under_from_surface_tree}, input::{ Seat, + keyboard::KeyboardHandle, keyboard::{FilterResult, KeyboardSource, KeysymHandle, ModifiersState}, pointer::{ AxisFrame, ButtonEvent, GestureHoldBeginEvent, GestureHoldEndEvent, @@ -1907,13 +1908,7 @@ impl State { /// Mirror the seat's current modifier state to every libei sender with a keyboard via /// `ei_keyboard.modifiers` - pub(crate) fn broadcast_ei_keyboard_modifiers(&self, seat: &Seat) { - if self.common.ei_seats.is_empty() { - return; - } - let Some(keyboard) = seat.get_keyboard() else { - return; - }; + pub(crate) fn broadcast_ei_keyboard_modifiers(&self, keyboard: &KeyboardHandle) { let s = keyboard.modifier_state().serialized; for ei_seat in self.common.ei_seats.values() { ei_seat.keyboard_modifiers(s.depressed, s.locked, s.latched, s.layout_effective); @@ -1958,7 +1953,7 @@ impl State { ) -> FilterResult> { if previous_modifiers != *modifiers { seat.set_last_modifier_change(backend_id, serial); - self.broadcast_ei_keyboard_modifiers(seat); + self.broadcast_ei_keyboard_modifiers(&seat.get_keyboard().unwrap()); } let current_focus = seat.get_keyboard().unwrap().current_focus(); diff --git a/src/libei.rs b/src/libei.rs index ad3a674d..487f0387 100644 --- a/src/libei.rs +++ b/src/libei.rs @@ -124,7 +124,9 @@ pub fn setup_ei( data.update_ei_input_method(); // Notify the remaining libei clients of the now-cleared modifier state let seat = data.common.shell.read().seats.last_active().clone(); - data.broadcast_ei_keyboard_modifiers(&seat); + if let Some(keyboard) = seat.get_keyboard() { + data.broadcast_ei_keyboard_modifiers(&keyboard); + } } EiInputEvent::Event(event) => { use smithay::backend::input::{InputEvent, KeyboardKeyEvent}; diff --git a/src/wayland/handlers/keyboard_layout.rs b/src/wayland/handlers/keyboard_layout.rs index ac1fda87..2477f93b 100644 --- a/src/wayland/handlers/keyboard_layout.rs +++ b/src/wayland/handlers/keyboard_layout.rs @@ -1,5 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only +use smithay::input::keyboard::KeyboardHandle; + use crate::state::State; use crate::wayland::protocols::keyboard_layout::{KeyboardLayoutHandler, KeyboardLayoutState}; @@ -7,4 +9,8 @@ impl KeyboardLayoutHandler for State { fn keyboard_layout_state(&mut self) -> &mut KeyboardLayoutState { &mut self.common.keyboard_layout_state } + + fn group_changed(&mut self, keyboard: &KeyboardHandle) { + self.broadcast_ei_keyboard_modifiers(keyboard); + } } diff --git a/src/wayland/protocols/keyboard_layout.rs b/src/wayland/protocols/keyboard_layout.rs index f3a44f0a..8a8840b6 100644 --- a/src/wayland/protocols/keyboard_layout.rs +++ b/src/wayland/protocols/keyboard_layout.rs @@ -17,8 +17,10 @@ use smithay::{ use std::mem; use wayland_backend::server::{ClientId, GlobalId}; -pub trait KeyboardLayoutHandler { +pub trait KeyboardLayoutHandler: SeatHandler { fn keyboard_layout_state(&mut self) -> &mut KeyboardLayoutState; + /// Group has been changed through the protocol + fn group_changed(&mut self, keyboard: &KeyboardHandle); } #[derive(Debug)] @@ -57,6 +59,7 @@ impl KeyboardLayoutState { let active_layout = handle.with_xkb_state(state, |context| { context.xkb().lock().unwrap().active_layout() }); + state.group_changed(handle); if *last_layout != Some(active_layout) { keyboard_layout.group(active_layout.0); *last_layout = Some(active_layout); From ca9dd27350635b95532821cfb00f2e826aa22fc8 Mon Sep 17 00:00:00 2001 From: Victoria Brekenfeld Date: Fri, 28 Aug 2026 14:42:17 +0200 Subject: [PATCH 13/69] chore: Fix debug feature by updating smithay-egui --- Cargo.lock | 26 ++------------------------ Cargo.toml | 1 + 2 files changed, 3 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 859203e4..d0a95294 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -121,15 +121,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f47b57fc4521e3cae26a4d45b5227f8fadee4c345be0fefd8d5d1711afb8aeb9" -[[package]] -name = "approx" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f2a05fd1bd10b2527e20a2cd32d8873d115b8b39fe219ee25f42a8aca6ba278" -dependencies = [ - "num-traits", -] - [[package]] name = "approx" version = "0.5.1" @@ -583,16 +574,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" -[[package]] -name = "cgmath" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a98d30140e3296250832bbaaff83b27dcd6fa3cc70fb6f1f3e5c9c0023b5317" -dependencies = [ - "approx 0.4.0", - "num-traits", -] - [[package]] name = "chacha20" version = "0.10.0" @@ -3737,7 +3718,7 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cbf71184cc5ecc2e4e1baccdb21026c20e5fc3dcf63028a086131b3ab00b6e6" dependencies = [ - "approx 0.5.1", + "approx", "fast-srgb8", "palette_derive", "phf 0.11.3", @@ -4884,16 +4865,13 @@ dependencies = [ [[package]] name = "smithay-egui" version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6794c95b83518f9f91ae8c2faee52302d521c0d541d016b4ed632374041d9c42" +source = "git+https://github.com/Smithay/smithay-egui.git?rev=6511552#65115521c756f356a7bcac8f1eeb715817a4666f" dependencies = [ - "cgmath", "egui", "egui_extras", "egui_glow", "image", "log", - "memoffset", "smithay", "xkbcommon 0.8.0", ] diff --git a/Cargo.toml b/Cargo.toml index 23fe2775..feb02259 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -147,3 +147,4 @@ cosmic-protocols = { git = "https://github.com/pop-os//cosmic-protocols", branch [patch.crates-io] smithay = { git = "https://github.com/smithay/smithay.git", rev = "e3d461a" } +smithay-egui = { git = "https://github.com/Smithay/smithay-egui.git", rev = "6511552" } From 6467f79025e2ffc32ed7df659c597beb4baa08b2 Mon Sep 17 00:00:00 2001 From: Victoria Brekenfeld Date: Tue, 11 Aug 2026 18:18:02 +0200 Subject: [PATCH 14/69] shell: Add tablet grabs --- src/input/mod.rs | 70 ++--- src/shell/element/stack.rs | 198 +++++++++++--- src/shell/element/window.rs | 153 +++++++++-- src/shell/focus/target.rs | 132 ++++++++- src/shell/grabs/delay.rs | 161 +++++++++-- src/shell/grabs/menu/default.rs | 216 +++++++++------ src/shell/grabs/menu/mod.rs | 304 +++++++++++++++++++-- src/shell/grabs/mod.rs | 315 ++++++++++++++++++++-- src/shell/grabs/moving.rs | 152 +++++++++-- src/shell/layout/floating/grabs/resize.rs | 150 +++++++++-- src/shell/layout/tiling/grabs/resize.rs | 284 ++++++++++++++++--- src/shell/layout/tiling/mod.rs | 20 +- src/shell/mod.rs | 12 +- src/shell/zoom.rs | 217 +++++++++++++-- src/utils/iced/mod.rs | 166 +++++++++++- src/wayland/handlers/tablet_manager.rs | 6 +- src/wayland/handlers/xdg_shell/mod.rs | 39 ++- src/xwayland.rs | 58 ++-- 18 files changed, 2262 insertions(+), 391 deletions(-) diff --git a/src/input/mod.rs b/src/input/mod.rs index 0228d3cb..cbf99cae 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -52,10 +52,11 @@ use smithay::{ keyboard::KeyboardHandle, keyboard::{FilterResult, KeyboardSource, KeysymHandle, ModifiersState}, pointer::{ - AxisFrame, ButtonEvent, GestureHoldBeginEvent, GestureHoldEndEvent, - GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent, - GestureSwipeBeginEvent, GestureSwipeEndEvent, GestureSwipeUpdateEvent, MotionEvent, - PointerGrab, PointerHandle, RelativeMotionEvent, + AxisFrame, ButtonEvent as PointerButtonEvent, GestureHoldBeginEvent, + GestureHoldEndEvent, GesturePinchBeginEvent, GesturePinchEndEvent, + GesturePinchUpdateEvent, GestureSwipeBeginEvent, GestureSwipeEndEvent, + GestureSwipeUpdateEvent, MotionEvent as PointerMotionEvent, PointerGrab, PointerHandle, + RelativeMotionEvent, }, tablet::{TabletDescriptor, TabletSeatTrait, tool}, touch::{DownEvent, MotionEvent as TouchMotionEvent, UpEvent}, @@ -326,7 +327,7 @@ impl State { } InputEvent::PointerMotion { event, .. } => { - use smithay::backend::input::PointerMotionEvent; + use smithay::backend::input::PointerMotionEvent as _; let shell = self.common.shell.write(); if let Some(seat) = shell @@ -639,7 +640,7 @@ impl State { ptr.motion( self, under, - &MotionEvent { + &PointerMotionEvent { location: position.as_logical(), serial, time: event.time(), @@ -754,7 +755,7 @@ impl State { ptr.motion( self, under, - &MotionEvent { + &PointerMotionEvent { location: position.as_logical(), serial, time: event.time(), @@ -781,9 +782,8 @@ impl State { } } InputEvent::PointerButton { event, .. } => { - use smithay::backend::input::{ButtonState, PointerButtonEvent}; + use smithay::backend::input::{ButtonState, PointerButtonEvent as _}; - // let Some(seat) = self .common .shell @@ -857,7 +857,7 @@ impl State { && !shortcuts_inhibited { let seat_clone = seat.clone(); - let mouse_button = PointerButtonEvent::button(&event); + let mouse_button = event.button(); let mut supress_button = || { // If the logo is held then the pointer event is @@ -1017,7 +1017,7 @@ impl State { if pass_event { ptr.button( self, - &ButtonEvent { + &PointerButtonEvent { button, state: event.state(), serial, @@ -1597,7 +1597,7 @@ impl State { pointer.motion( self, under.clone(), - &MotionEvent { + &PointerMotionEvent { location: position.as_logical(), serial: SERIAL_COUNTER.next_serial(), time: InputTime::now(), @@ -1626,8 +1626,7 @@ impl State { tool.motion( self, - under - .and_then(|(f, loc)| f.wl_surface().map(|s| (s.into_owned(), loc))), + under, &tool::MotionEvent { location: position.as_logical(), serial: SERIAL_COUNTER.next_serial(), @@ -1666,7 +1665,7 @@ impl State { pointer.motion( self, under.clone(), - &MotionEvent { + &PointerMotionEvent { location: position.as_logical(), serial: SERIAL_COUNTER.next_serial(), time: InputTime::now(), @@ -1698,22 +1697,17 @@ impl State { }; match event.state() { - ProximityState::In => { - let under = under.and_then(|(f, loc)| { - f.wl_surface().map(|s| (s.into_owned(), loc)) - }); - tool.proximity_in( - self, - under, - tablet, - &tool::ProximityInEvent { - location: position.as_logical(), - axis: Some(frame), - serial: SERIAL_COUNTER.next_serial(), - time: event.time(), - }, - ) - } + ProximityState::In => tool.proximity_in( + self, + under, + tablet, + &tool::ProximityInEvent { + location: position.as_logical(), + axis: Some(frame), + serial: SERIAL_COUNTER.next_serial(), + time: event.time(), + }, + ), ProximityState::Out => tool.proximity_out( self, &tool::ProximityOutEvent { @@ -1728,6 +1722,18 @@ impl State { } } InputEvent::TabletToolTip { event, .. } => { + { + let mut shell = self.common.shell.write(); + if let Some(Trigger::Tool(desc, trigger)) = + shell.overview_mode().0.active_trigger() + && event.tool() == *desc + && matches!(*trigger, tool::GrabTrigger::Tip) + && event.tip_state() == TabletToolTipState::Up + { + shell.set_overview_mode(None, self.common.event_loop_handle.clone()); + } + } + let maybe_seat = self .common .shell @@ -2968,7 +2974,7 @@ impl State { pointer.motion( self, under, - &MotionEvent { + &PointerMotionEvent { location: point.as_logical(), serial, time, diff --git a/src/shell/element/stack.rs b/src/shell/element/stack.rs index 2fed0977..34e6f876 100644 --- a/src/shell/element/stack.rs +++ b/src/shell/element/stack.rs @@ -11,7 +11,7 @@ use crate::{ shell::{ element::{CosmicMappedKey, CosmicMappedKeyInner}, focus::target::PointerFocusTarget, - grabs::{ReleaseMode, ResizeEdge}, + grabs::{GrabType, ReleaseMode, ResizeEdge}, layout::tiling::NodeDesc, }, state::State, @@ -38,7 +38,7 @@ use shortcuts::action::{Direction, FocusDirection}; use smithay::{ backend::{ drm::DrmNode, - input::{InputTime, KeyState}, + input::{InputTime, KeyState, TabletToolDescriptor}, renderer::{ ImportAll, ImportMem, Renderer, element::{Element, Id as RendererId, Kind, RenderElement, UnderlyingStorage}, @@ -52,14 +52,23 @@ use smithay::{ Seat, keyboard::{KeyboardTarget, KeysymHandle, ModifiersState}, pointer::{ - AxisFrame, ButtonEvent, CursorImageStatus, GestureHoldBeginEvent, GestureHoldEndEvent, - GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent, - GestureSwipeBeginEvent, GestureSwipeEndEvent, GestureSwipeUpdateEvent, MotionEvent, + AxisFrame as PointerAxisFrame, ButtonEvent as PointerButtonEvent, CursorImageStatus, + GestureHoldBeginEvent, GestureHoldEndEvent, GesturePinchBeginEvent, + GesturePinchEndEvent, GesturePinchUpdateEvent, GestureSwipeBeginEvent, + GestureSwipeEndEvent, GestureSwipeUpdateEvent, MotionEvent as PointerMotionEvent, PointerTarget, RelativeMotionEvent, }, + tablet::{ + Tablet, TabletSeatTrait, + tool::{ + AxisFrame as ToolAxisFrame, ButtonEvent as ToolButtonEvent, + DownEvent as ToolDownEvent, MotionEvent as ToolMotionEvent, TabletToolTarget, + UpEvent as ToolUpEvent, + }, + }, touch::{ - DownEvent, FrameMarker, MotionEvent as TouchMotionEvent, OrientationEvent, ShapeEvent, - TouchTarget, UpEvent, + DownEvent as TouchDownEvent, FrameMarker, MotionEvent as TouchMotionEvent, + OrientationEvent, ShapeEvent, TouchTarget, UpEvent as TouchUpEvent, }, }, output::Output, @@ -909,12 +918,19 @@ impl CosmicStack { false, ); if let Some((grab, focus)) = res { - if grab.is_touch_grab() { - seat.get_touch().unwrap().set_grab(state, grab, serial); - } else { - seat.get_pointer() + match grab.grab_type() { + GrabType::Touch => { + seat.get_touch().unwrap().set_grab(state, grab, serial) + } + GrabType::Pointer => seat + .get_pointer() .unwrap() - .set_grab(state, grab, serial, focus); + .set_grab(state, grab, serial, focus), + GrabType::TabletTool => seat + .tablet_seat() + .get_tool(grab.tool().unwrap()) + .unwrap() + .set_grab(state, grab, InputTime::now(), serial, focus), } } }); @@ -1089,12 +1105,19 @@ impl Program for CosmicStackInternal { false, ); if let Some((grab, focus)) = res { - if grab.is_touch_grab() { - seat.get_touch().unwrap().set_grab(state, grab, serial); - } else { - seat.get_pointer() + match grab.grab_type() { + GrabType::Touch => { + seat.get_touch().unwrap().set_grab(state, grab, serial) + } + GrabType::Pointer => seat + .get_pointer() .unwrap() - .set_grab(state, grab, serial, focus); + .set_grab(state, grab, serial, focus), + GrabType::TabletTool => seat + .tablet_seat() + .get_tool(grab.tool().unwrap()) + .unwrap() + .set_grab(state, grab, InputTime::now(), serial, focus), } } }); @@ -1597,7 +1620,7 @@ impl KeyboardTarget for CosmicStack { } impl PointerTarget for CosmicStack { - fn enter(&self, seat: &Seat, data: &mut State, event: &MotionEvent) { + fn enter(&self, seat: &Seat, data: &mut State, event: &PointerMotionEvent) { let mut event = event.clone(); self.0.with_program(|p| { let active_window = &p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)]; @@ -1625,7 +1648,7 @@ impl PointerTarget for CosmicStack { PointerTarget::enter(&self.0, seat, data, &event) } - fn motion(&self, seat: &Seat, data: &mut State, event: &MotionEvent) { + fn motion(&self, seat: &Seat, data: &mut State, event: &PointerMotionEvent) { let mut event = event.clone(); self.0.with_program(|p| { let active = p.active.load(Ordering::SeqCst); @@ -1668,7 +1691,7 @@ impl PointerTarget for CosmicStack { ) { } - fn button(&self, seat: &Seat, data: &mut State, event: &ButtonEvent) { + fn button(&self, seat: &Seat, data: &mut State, event: &PointerButtonEvent) { match self.0.with_program(|p| p.current_focus()) { Some(Focus::Header) => PointerTarget::button(&self.0, seat, data, event), Some(x) => { @@ -1700,12 +1723,19 @@ impl PointerTarget for CosmicStack { false, ); if let Some((grab, focus)) = res { - if grab.is_touch_grab() { - seat.get_touch().unwrap().set_grab(state, grab, serial); - } else { - seat.get_pointer() + match grab.grab_type() { + GrabType::Touch => { + seat.get_touch().unwrap().set_grab(state, grab, serial) + } + GrabType::Pointer => seat + .get_pointer() .unwrap() - .set_grab(state, grab, serial, focus); + .set_grab(state, grab, serial, focus), + GrabType::TabletTool => seat + .tablet_seat() + .get_tool(grab.tool().unwrap()) + .unwrap() + .set_grab(state, grab, InputTime::now(), serial, focus), } } }); @@ -1714,7 +1744,7 @@ impl PointerTarget for CosmicStack { } } - fn axis(&self, seat: &Seat, data: &mut State, frame: AxisFrame) { + fn axis(&self, seat: &Seat, data: &mut State, frame: PointerAxisFrame) { if let Some(Focus::Header) = self.0.with_program(|p| p.current_focus()) { PointerTarget::axis(&self.0, seat, data, frame) } @@ -1763,12 +1793,19 @@ impl PointerTarget for CosmicStack { false, ); if let Some((grab, focus)) = res { - if grab.is_touch_grab() { - seat.get_touch().unwrap().set_grab(state, grab, serial); - } else { - seat.get_pointer() + match grab.grab_type() { + GrabType::Touch => { + seat.get_touch().unwrap().set_grab(state, grab, serial) + } + GrabType::Pointer => seat + .get_pointer() .unwrap() - .set_grab(state, grab, serial, focus); + .set_grab(state, grab, serial, focus), + GrabType::TabletTool => seat + .tablet_seat() + .get_tool(grab.tool().unwrap()) + .unwrap() + .set_grab(state, grab, InputTime::now(), serial, focus), } } }); @@ -1842,7 +1879,7 @@ impl PointerTarget for CosmicStack { } impl TouchTarget for CosmicStack { - fn down(&self, seat: &Seat, data: &mut State, event: &DownEvent) { + fn down(&self, seat: &Seat, data: &mut State, event: &TouchDownEvent) { let mut event = event.clone(); let active_window_geo = self.0.with_program(|p| { p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)].geometry() @@ -1853,7 +1890,7 @@ impl TouchTarget for CosmicStack { TouchTarget::down(&self.0, seat, data, &event) } - fn up(&self, seat: &Seat, data: &mut State, event: &UpEvent) { + fn up(&self, seat: &Seat, data: &mut State, event: &TouchUpEvent) { TouchTarget::up(&self.0, seat, data, event) } @@ -1901,6 +1938,101 @@ impl TouchTarget for CosmicStack { } } +impl TabletToolTarget for CosmicStack { + fn proximity_in( + &self, + seat: &Seat, + data: &mut State, + tool_descriptor: &TabletToolDescriptor, + tablet: &Tablet, + serial: Serial, + ) { + TabletToolTarget::proximity_in(&self.0, seat, data, tool_descriptor, tablet, serial) + } + + fn proximity_out( + &self, + seat: &Seat, + data: &mut State, + tool_descriptor: &TabletToolDescriptor, + ) { + TabletToolTarget::proximity_out(&self.0, seat, data, tool_descriptor) + } + + fn down( + &self, + seat: &Seat, + data: &mut State, + tool_descriptor: &TabletToolDescriptor, + event: &ToolDownEvent, + ) { + TabletToolTarget::down(&self.0, seat, data, tool_descriptor, event) + } + + fn up( + &self, + seat: &Seat, + data: &mut State, + tool_descriptor: &TabletToolDescriptor, + event: &ToolUpEvent, + ) { + TabletToolTarget::up(&self.0, seat, data, tool_descriptor, event) + } + + fn motion( + &self, + seat: &Seat, + data: &mut State, + tool_descriptor: &TabletToolDescriptor, + event: &ToolMotionEvent, + ) { + let mut event = event.clone(); + let active_window_geo = self.0.with_program(|p| { + p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)].geometry() + }); + event.location -= active_window_geo.loc.to_f64(); + TabletToolTarget::motion(&self.0, seat, data, tool_descriptor, &event); + + if event.location.y < 0.0 + || event.location.y > TAB_HEIGHT as f64 + || event.location.x < 64.0 + || event.location.x > (active_window_geo.size.w as f64 - 64.0) + { + self.start_drag(data, seat, event.serial); + } + } + + fn axis( + &self, + seat: &Seat, + data: &mut State, + tool_descriptor: &TabletToolDescriptor, + frame: ToolAxisFrame, + ) { + TabletToolTarget::axis(&self.0, seat, data, tool_descriptor, frame) + } + + fn button( + &self, + seat: &Seat, + data: &mut State, + tool_descriptor: &TabletToolDescriptor, + event: &ToolButtonEvent, + ) { + TabletToolTarget::button(&self.0, seat, data, tool_descriptor, event) + } + + fn frame( + &self, + seat: &Seat, + data: &mut State, + tool_descriptor: &TabletToolDescriptor, + time: InputTime, + ) { + TabletToolTarget::frame(&self.0, seat, data, tool_descriptor, time) + } +} + pub enum CosmicStackRenderElement { Header(IcedRenderElement), Shadow(PixelShaderElement), diff --git a/src/shell/element/window.rs b/src/shell/element/window.rs index 53b2caee..846d9da4 100644 --- a/src/shell/element/window.rs +++ b/src/shell/element/window.rs @@ -7,7 +7,7 @@ use crate::{ shell::{ element::{CosmicMappedKey, CosmicMappedKeyInner}, focus::target::PointerFocusTarget, - grabs::{ReleaseMode, ResizeEdge}, + grabs::{GrabType, ReleaseMode, ResizeEdge}, }, state::State, utils::{ @@ -21,7 +21,7 @@ use cosmic_comp_config::AppearanceConfig; use smithay::{ backend::{ drm::DrmNode, - input::{InputTime, KeyState}, + input::{InputTime, KeyState, TabletToolDescriptor}, renderer::{ ImportAll, ImportMem, Renderer, element::{Element, Id as RendererId, Kind, RenderElement, UnderlyingStorage}, @@ -35,14 +35,23 @@ use smithay::{ Seat, keyboard::{KeyboardTarget, KeysymHandle, ModifiersState}, pointer::{ - AxisFrame, ButtonEvent, CursorIcon, CursorImageStatus, GestureHoldBeginEvent, - GestureHoldEndEvent, GesturePinchBeginEvent, GesturePinchEndEvent, - GesturePinchUpdateEvent, GestureSwipeBeginEvent, GestureSwipeEndEvent, - GestureSwipeUpdateEvent, MotionEvent, PointerTarget, RelativeMotionEvent, + AxisFrame as PointerAxisFrame, ButtonEvent as PointerButtonEvent, CursorIcon, + CursorImageStatus, GestureHoldBeginEvent, GestureHoldEndEvent, GesturePinchBeginEvent, + GesturePinchEndEvent, GesturePinchUpdateEvent, GestureSwipeBeginEvent, + GestureSwipeEndEvent, GestureSwipeUpdateEvent, MotionEvent as PointerMotionEvent, + PointerTarget, RelativeMotionEvent, + }, + tablet::{ + Tablet, TabletSeatTrait, + tool::{ + AxisFrame as ToolAxisFrame, ButtonEvent as ToolButtonEvent, + DownEvent as ToolDownEvent, MotionEvent as ToolMotionEvent, TabletToolTarget, + UpEvent as ToolUpEvent, + }, }, touch::{ - DownEvent, FrameMarker, MotionEvent as TouchMotionEvent, OrientationEvent, ShapeEvent, - TouchTarget, UpEvent, + DownEvent as TouchDownEvent, FrameMarker, MotionEvent as TouchMotionEvent, + OrientationEvent, ShapeEvent, TouchTarget, UpEvent as TouchUpEvent, }, }, output::Output, @@ -746,12 +755,19 @@ impl Program for CosmicWindowInternal { false, ); if let Some((grab, focus)) = res { - if grab.is_touch_grab() { - seat.get_touch().unwrap().set_grab(state, grab, serial); - } else { - seat.get_pointer() + match grab.grab_type() { + GrabType::Touch => { + seat.get_touch().unwrap().set_grab(state, grab, serial) + } + GrabType::Pointer => seat + .get_pointer() .unwrap() - .set_grab(state, grab, serial, focus); + .set_grab(state, grab, serial, focus), + GrabType::TabletTool => seat + .tablet_seat() + .get_tool(grab.tool().unwrap()) + .unwrap() + .set_grab(state, grab, InputTime::now(), serial, focus), } } }); @@ -1003,7 +1019,7 @@ impl KeyboardTarget for CosmicWindow { } impl PointerTarget for CosmicWindow { - fn enter(&self, seat: &Seat, data: &mut State, event: &MotionEvent) { + fn enter(&self, seat: &Seat, data: &mut State, event: &PointerMotionEvent) { let mut event = event.clone(); self.0.with_program(|p| { let has_ssd = p.has_ssd(false); @@ -1029,7 +1045,7 @@ impl PointerTarget for CosmicWindow { PointerTarget::enter(&self.0, seat, data, &event) } - fn motion(&self, seat: &Seat, data: &mut State, event: &MotionEvent) { + fn motion(&self, seat: &Seat, data: &mut State, event: &PointerMotionEvent) { let mut event = event.clone(); self.0.with_program(|p| { let has_ssd = p.has_ssd(false); @@ -1061,7 +1077,7 @@ impl PointerTarget for CosmicWindow { ) { } - fn button(&self, seat: &Seat, data: &mut State, event: &ButtonEvent) { + fn button(&self, seat: &Seat, data: &mut State, event: &PointerButtonEvent) { match self.0.with_program(|p| p.current_focus()) { Some(Focus::Header) => PointerTarget::button(&self.0, seat, data, event), Some(x) => { @@ -1098,12 +1114,19 @@ impl PointerTarget for CosmicWindow { ); if let Some((grab, focus)) = res { - if grab.is_touch_grab() { - seat.get_touch().unwrap().set_grab(state, grab, serial); - } else { - seat.get_pointer() + match grab.grab_type() { + GrabType::Touch => { + seat.get_touch().unwrap().set_grab(state, grab, serial) + } + GrabType::Pointer => seat + .get_pointer() .unwrap() - .set_grab(state, grab, serial, focus); + .set_grab(state, grab, serial, focus), + GrabType::TabletTool => seat + .tablet_seat() + .get_tool(grab.tool().unwrap()) + .unwrap() + .set_grab(state, grab, InputTime::now(), serial, focus), } } }); @@ -1112,7 +1135,7 @@ impl PointerTarget for CosmicWindow { } } - fn axis(&self, seat: &Seat, data: &mut State, frame: AxisFrame) { + fn axis(&self, seat: &Seat, data: &mut State, frame: PointerAxisFrame) { if let Some(Focus::Header) = self.0.with_program(|p| p.current_focus()) { PointerTarget::axis(&self.0, seat, data, frame) } @@ -1199,7 +1222,7 @@ impl PointerTarget for CosmicWindow { } impl TouchTarget for CosmicWindow { - fn down(&self, seat: &Seat, data: &mut State, event: &DownEvent) { + fn down(&self, seat: &Seat, data: &mut State, event: &TouchDownEvent) { let mut event = event.clone(); self.0.with_program(|p| { event.location -= p.window.geometry().loc.to_f64(); @@ -1207,7 +1230,7 @@ impl TouchTarget for CosmicWindow { TouchTarget::down(&self.0, seat, data, &event) } - fn up(&self, seat: &Seat, data: &mut State, event: &UpEvent) { + fn up(&self, seat: &Seat, data: &mut State, event: &TouchUpEvent) { TouchTarget::up(&self.0, seat, data, event) } @@ -1238,6 +1261,88 @@ impl TouchTarget for CosmicWindow { } } +impl TabletToolTarget for CosmicWindow { + fn proximity_in( + &self, + seat: &Seat, + data: &mut State, + tool_descriptor: &TabletToolDescriptor, + tablet: &Tablet, + serial: Serial, + ) { + TabletToolTarget::proximity_in(&self.0, seat, data, tool_descriptor, tablet, serial) + } + + fn proximity_out( + &self, + seat: &Seat, + data: &mut State, + tool_descriptor: &TabletToolDescriptor, + ) { + TabletToolTarget::proximity_out(&self.0, seat, data, tool_descriptor) + } + + fn down( + &self, + seat: &Seat, + data: &mut State, + tool_descriptor: &TabletToolDescriptor, + event: &ToolDownEvent, + ) { + TabletToolTarget::down(&self.0, seat, data, tool_descriptor, event) + } + + fn up( + &self, + seat: &Seat, + data: &mut State, + tool_descriptor: &TabletToolDescriptor, + event: &ToolUpEvent, + ) { + TabletToolTarget::up(&self.0, seat, data, tool_descriptor, event) + } + + fn motion( + &self, + seat: &Seat, + data: &mut State, + tool_descriptor: &TabletToolDescriptor, + event: &ToolMotionEvent, + ) { + TabletToolTarget::motion(&self.0, seat, data, tool_descriptor, event) + } + + fn axis( + &self, + seat: &Seat, + data: &mut State, + tool_descriptor: &TabletToolDescriptor, + frame: ToolAxisFrame, + ) { + TabletToolTarget::axis(&self.0, seat, data, tool_descriptor, frame) + } + + fn button( + &self, + seat: &Seat, + data: &mut State, + tool_descriptor: &TabletToolDescriptor, + event: &ToolButtonEvent, + ) { + TabletToolTarget::button(&self.0, seat, data, tool_descriptor, event) + } + + fn frame( + &self, + seat: &Seat, + data: &mut State, + tool_descriptor: &TabletToolDescriptor, + time: InputTime, + ) { + TabletToolTarget::frame(&self.0, seat, data, tool_descriptor, time) + } +} + impl WaylandFocus for CosmicWindow { fn wl_surface(&self) -> Option> { self.0.with_program(|p| { diff --git a/src/shell/focus/target.rs b/src/shell/focus/target.rs index 56af0ccc..6ca13279 100644 --- a/src/shell/focus/target.rs +++ b/src/shell/focus/target.rs @@ -16,21 +16,30 @@ use crate::{ }; use id_tree::NodeId; use smithay::{ - backend::input::{InputTime, KeyState}, + backend::input::{InputTime, KeyState, TabletToolDescriptor}, desktop::{LayerSurface, PopupKind, WindowSurface, WindowSurfaceType, space::SpaceElement}, input::{ Seat, dnd::{DndFocus, OfferData, Source}, keyboard::{KeyboardTarget, KeysymHandle, ModifiersState}, pointer::{ - AxisFrame, ButtonEvent, GestureHoldBeginEvent, GestureHoldEndEvent, - GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent, - GestureSwipeBeginEvent, GestureSwipeEndEvent, GestureSwipeUpdateEvent, - MotionEvent as PointerMotionEvent, PointerTarget, RelativeMotionEvent, + AxisFrame as PointerAxisFrame, ButtonEvent as PointerButtonEvent, + GestureHoldBeginEvent, GestureHoldEndEvent, GesturePinchBeginEvent, + GesturePinchEndEvent, GesturePinchUpdateEvent, GestureSwipeBeginEvent, + GestureSwipeEndEvent, GestureSwipeUpdateEvent, MotionEvent as PointerMotionEvent, + PointerTarget, RelativeMotionEvent, + }, + tablet::{ + Tablet, + tool::{ + AxisFrame as ToolAxisFrame, ButtonEvent as ToolButtonEvent, + DownEvent as ToolDownEvent, MotionEvent as ToolMotionEvent, TabletToolTarget, + UpEvent as ToolUpEvent, + }, }, touch::{ - DownEvent, FrameMarker, MotionEvent as TouchMotionEvent, OrientationEvent, ShapeEvent, - TouchTarget, UpEvent, + DownEvent as TouchDownEvent, FrameMarker, MotionEvent as TouchMotionEvent, + OrientationEvent, ShapeEvent, TouchTarget, UpEvent as TouchUpEvent, }, }, reexports::wayland_server::{ @@ -164,6 +173,17 @@ impl PointerFocusTarget { } } + fn inner_tablet_tool_target(&self) -> &dyn TabletToolTarget { + match self { + PointerFocusTarget::WlSurface { surface, .. } => surface, + PointerFocusTarget::X11Surface { surface, .. } => surface, + PointerFocusTarget::StackUI(u) => u, + PointerFocusTarget::WindowUI(u) => u, + PointerFocusTarget::ResizeFork(f) => f, + PointerFocusTarget::ZoomUI(e) => e, + } + } + pub fn under_surface>>( surface: &CosmicSurface, point: P, @@ -409,10 +429,10 @@ impl PointerTarget for PointerFocusTarget { self.inner_pointer_target() .relative_motion(seat, data, event); } - fn button(&self, seat: &Seat, data: &mut State, event: &ButtonEvent) { + fn button(&self, seat: &Seat, data: &mut State, event: &PointerButtonEvent) { self.inner_pointer_target().button(seat, data, event); } - fn axis(&self, seat: &Seat, data: &mut State, frame: AxisFrame) { + fn axis(&self, seat: &Seat, data: &mut State, frame: PointerAxisFrame) { self.inner_pointer_target().axis(seat, data, frame); } fn frame(&self, seat: &Seat, data: &mut State) { @@ -498,12 +518,102 @@ impl PointerTarget for PointerFocusTarget { } } +impl TabletToolTarget for PointerFocusTarget { + fn proximity_in( + &self, + seat: &Seat, + data: &mut State, + tool_descriptor: &TabletToolDescriptor, + tablet: &Tablet, + serial: Serial, + ) { + self.inner_tablet_tool_target() + .proximity_in(seat, data, tool_descriptor, tablet, serial); + } + + fn proximity_out( + &self, + seat: &Seat, + data: &mut State, + tool_descriptor: &TabletToolDescriptor, + ) { + self.inner_tablet_tool_target() + .proximity_out(seat, data, tool_descriptor); + } + + fn down( + &self, + seat: &Seat, + data: &mut State, + tool_descriptor: &TabletToolDescriptor, + event: &ToolDownEvent, + ) { + self.inner_tablet_tool_target() + .down(seat, data, tool_descriptor, event); + } + + fn up( + &self, + seat: &Seat, + data: &mut State, + tool_descriptor: &TabletToolDescriptor, + event: &ToolUpEvent, + ) { + self.inner_tablet_tool_target() + .up(seat, data, tool_descriptor, event); + } + + fn motion( + &self, + seat: &Seat, + data: &mut State, + tool_descriptor: &TabletToolDescriptor, + event: &ToolMotionEvent, + ) { + self.inner_tablet_tool_target() + .motion(seat, data, tool_descriptor, event); + } + + fn axis( + &self, + seat: &Seat, + data: &mut State, + tool_descriptor: &TabletToolDescriptor, + frame: ToolAxisFrame, + ) { + self.inner_tablet_tool_target() + .axis(seat, data, tool_descriptor, frame); + } + + fn button( + &self, + seat: &Seat, + data: &mut State, + tool_descriptor: &TabletToolDescriptor, + event: &ToolButtonEvent, + ) { + self.inner_tablet_tool_target() + .button(seat, data, tool_descriptor, event); + } + + fn frame( + &self, + seat: &Seat, + data: &mut State, + tool_descriptor: &TabletToolDescriptor, + time: InputTime, + ) { + self.inner_tablet_tool_target() + .frame(seat, data, tool_descriptor, time); + } +} + impl TouchTarget for PointerFocusTarget { - fn down(&self, seat: &Seat, data: &mut State, event: &DownEvent) { + fn down(&self, seat: &Seat, data: &mut State, event: &TouchDownEvent) { self.inner_touch_target().down(seat, data, event); } - fn up(&self, seat: &Seat, data: &mut State, event: &UpEvent) { + fn up(&self, seat: &Seat, data: &mut State, event: &TouchUpEvent) { self.inner_touch_target().up(seat, data, event); } diff --git a/src/shell/grabs/delay.rs b/src/shell/grabs/delay.rs index 96d33dc6..ca19e4cb 100644 --- a/src/shell/grabs/delay.rs +++ b/src/shell/grabs/delay.rs @@ -1,22 +1,34 @@ use smithay::{ + backend::input::{InputTime, TabletToolDescriptor}, input::{ Seat, SeatHandler, pointer::{ - AxisFrame, ButtonEvent, Focus, GestureHoldBeginEvent, GestureHoldEndEvent, - GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent, - GestureSwipeBeginEvent, GestureSwipeEndEvent, GestureSwipeUpdateEvent, - GrabStartData as PointerGrabStartData, MotionEvent as PointerMotionEvent, PointerGrab, - PointerInnerHandle, RelativeMotionEvent, + AxisFrame as PointerAxisFrame, ButtonEvent as PointerButtonEvent, Focus, + GestureHoldBeginEvent, GestureHoldEndEvent, GesturePinchBeginEvent, + GesturePinchEndEvent, GesturePinchUpdateEvent, GestureSwipeBeginEvent, + GestureSwipeEndEvent, GestureSwipeUpdateEvent, GrabStartData as PointerGrabStartData, + MotionEvent as PointerMotionEvent, PointerGrab, PointerInnerHandle, + RelativeMotionEvent, + }, + tablet::{ + TabletSeatHandler, TabletSeatTrait, + tool::{ + AxisFrame as TabletAxisFrame, ButtonEvent as TabletButtonEvent, + DownEvent as TabletDownEvent, GrabStartData as TabletGrabStartData, + MotionEvent as TabletMotionEvent, ProximityInEvent, ProximityOutEvent, + TabletToolGrab, TabletToolInnerHandle, UpEvent as TabletUpEvent, + }, }, touch::{ - DownEvent, GrabStartData as TouchGrabStartData, MotionEvent as TouchMotionEvent, - OrientationEvent, ShapeEvent, TouchGrab, TouchInnerHandle, UpEvent, + DownEvent as TouchDownEvent, GrabStartData as TouchGrabStartData, + MotionEvent as TouchMotionEvent, OrientationEvent, ShapeEvent, TouchGrab, + TouchInnerHandle, UpEvent as TouchUpEvent, }, }, utils::{Logical, Point, SERIAL_COUNTER, Serial}, }; -use crate::state::State; +use crate::{shell::grabs::GrabType, state::State}; use super::GrabStartData; @@ -44,10 +56,15 @@ impl DelayGrab { } } - pub fn is_touch_grab(&self) -> bool { - match self.start_data { - GrabStartData::Touch(_) => true, - GrabStartData::Pointer(_) => false, + pub fn grab_type(&self) -> GrabType { + self.start_data.type_() + } + + pub fn tool(&self) -> Option<&TabletToolDescriptor> { + if let GrabStartData::TabletTool { tool, .. } = &self.start_data { + Some(tool) + } else { + None } } } @@ -92,7 +109,7 @@ impl> PointerGrab for DelayGrab { &mut self, data: &mut State, handle: &mut PointerInnerHandle<'_, State>, - event: &ButtonEvent, + event: &PointerButtonEvent, ) { handle.button(data, event); if handle.current_pressed().is_empty() { @@ -104,7 +121,7 @@ impl> PointerGrab for DelayGrab { &mut self, data: &mut State, handle: &mut PointerInnerHandle<'_, State>, - details: AxisFrame, + details: PointerAxisFrame, ) { handle.axis(data, details); } @@ -201,12 +218,17 @@ impl> TouchGrab for DelayGrab { data: &mut State, handle: &mut TouchInnerHandle<'_, State>, focus: Option<(::TouchFocus, Point)>, - event: &DownEvent, + event: &TouchDownEvent, ) { handle.down(data, focus, event); } - fn up(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>, event: &UpEvent) { + fn up( + &mut self, + data: &mut State, + handle: &mut TouchInnerHandle<'_, State>, + event: &TouchUpEvent, + ) { handle.up(data, event); if event.slot == TouchGrab::start_data(self).slot { @@ -273,3 +295,110 @@ impl> TouchGrab for DelayGrab { fn unset(&mut self, _data: &mut State) {} } + +impl> TabletToolGrab for DelayGrab { + fn start_data(&self) -> &TabletGrabStartData { + match &self.start_data { + GrabStartData::TabletTool { data, .. } => data, + _ => unreachable!(), + } + } + + fn proximity_out( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + event: &ProximityOutEvent, + ) { + handle.proximity_out(data, event); + } + + fn motion( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + focus: Option<(::ToolFocus, Point)>, + event: &TabletMotionEvent, + ) { + handle.motion(data, focus, event); + + let distance = self.start_data.distance(event.location); + if distance >= 1. + && let Some(factory) = self.grab_factory.take() + { + let seat = self.seat.clone(); + let serial = self.serial.unwrap_or_else(|| SERIAL_COUNTER.next_serial()); + let time = InputTime::now(); + let Some(tool) = self.tool().cloned() else { + handle.unset_grab(self, data, serial, time, true); + return; + }; + data.common.event_loop_handle.insert_idle(move |data| { + if let Some((grab, focus)) = factory(data) { + seat.tablet_seat() + .get_tool(&tool) + .unwrap() + .set_grab(data, grab, time, serial, focus); + } + }); + } + } + + fn down( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + event: &TabletDownEvent, + ) { + handle.down(data, event) + } + + fn up( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + event: &TabletUpEvent, + ) { + handle.up(data, event); + handle.unset_grab(self, data, event.serial, event.time, false); + } + + fn button( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + event: &TabletButtonEvent, + ) { + handle.button(data, event); + } + + fn axis( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + frame: TabletAxisFrame, + ) { + handle.axis(data, frame) + } + + fn frame( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + time: InputTime, + ) { + handle.frame(data, time) + } + + fn unset(&mut self, _data: &mut State) {} + + fn proximity_in( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + focus: Option<(::ToolFocus, Point)>, + event: &ProximityInEvent, + ) { + handle.proximity_in(data, focus, event); + } +} diff --git a/src/shell/grabs/menu/default.rs b/src/shell/grabs/menu/default.rs index 81673efd..26cca2f5 100644 --- a/src/shell/grabs/menu/default.rs +++ b/src/shell/grabs/menu/default.rs @@ -1,7 +1,9 @@ use cosmic_settings_config::shortcuts::Action; use smithay::{ - backend::input::InputTime, input::pointer::MotionEvent, - reexports::wayland_server::protocol::wl_surface::WlSurface, utils::SERIAL_COUNTER, + backend::input::InputTime, + input::{pointer::MotionEvent, tablet::TabletSeatTrait}, + reexports::wayland_server::protocol::wl_surface::WlSurface, + utils::SERIAL_COUNTER, wayland::seat::WaylandFocus, }; @@ -11,7 +13,7 @@ use crate::{ shell::{ CosmicSurface, PointGlobalExt, Shell, element::{CosmicMapped, CosmicWindow}, - grabs::ReleaseMode, + grabs::{GrabType, ReleaseMode}, }, state::State, utils::{prelude::SeatExt, screenshot::screenshot_window}, @@ -353,19 +355,20 @@ pub fn window_items( std::mem::drop(shell); if let Some((grab, focus)) = res { - if grab.is_touch_grab() { - seat.get_touch().unwrap().set_grab( - state, - grab, - SERIAL_COUNTER.next_serial(), - ) - } else { - seat.get_pointer().unwrap().set_grab( - state, - grab, - SERIAL_COUNTER.next_serial(), - focus, - ); + let serial = SERIAL_COUNTER.next_serial(); + match grab.grab_type() { + GrabType::Touch => { + seat.get_touch().unwrap().set_grab(state, grab, serial) + } + GrabType::Pointer => seat + .get_pointer() + .unwrap() + .set_grab(state, grab, serial, focus), + GrabType::TabletTool => seat + .tablet_seat() + .get_tool(grab.tool().unwrap()) + .unwrap() + .set_grab(state, grab, InputTime::now(), serial, focus), } } } @@ -389,21 +392,29 @@ pub fn window_items( std::mem::drop(shell); if let Some(((target, loc), (grab, focus))) = res { let serial = SERIAL_COUNTER.next_serial(); - if grab.is_touch_grab() { - seat.get_touch().unwrap().set_grab(state, grab, serial); - } else { - let pointer = seat.get_pointer().unwrap(); - pointer.motion( - state, - target, - &MotionEvent { - location: loc.as_logical().to_f64(), - serial, - time: InputTime::now(), - }, - ); - pointer.frame(state); - pointer.set_grab(state, grab, serial, focus); + match grab.grab_type() { + GrabType::Touch => { + seat.get_touch().unwrap().set_grab(state, grab, serial) + } + GrabType::TabletTool => seat + .tablet_seat() + .get_tool(grab.tool().unwrap()) + .unwrap() + .set_grab(state, grab, InputTime::now(), serial, focus), + GrabType::Pointer => { + let pointer = seat.get_pointer().unwrap(); + pointer.motion( + state, + target, + &MotionEvent { + location: loc.as_logical().to_f64(), + serial, + time: InputTime::now(), + }, + ); + pointer.frame(state); + pointer.set_grab(state, grab, serial, focus); + } } } }); @@ -424,21 +435,30 @@ pub fn window_items( std::mem::drop(shell); if let Some(((target, loc), (grab, focus))) = res { let serial = SERIAL_COUNTER.next_serial(); - if grab.is_touch_grab() { - seat.get_touch().unwrap().set_grab(state, grab, serial); - } else { - let pointer = seat.get_pointer().unwrap(); - pointer.motion( - state, - target, - &MotionEvent { - location: loc.as_logical().to_f64(), - serial, - time: InputTime::now(), - }, - ); - pointer.frame(state); - pointer.set_grab(state, grab, serial, focus); + match grab.grab_type() { + GrabType::Touch => { + seat.get_touch().unwrap().set_grab(state, grab, serial) + } + GrabType::Pointer => { + let pointer = seat.get_pointer().unwrap(); + pointer.motion( + state, + target, + &MotionEvent { + location: loc.as_logical().to_f64(), + serial, + time: InputTime::now(), + }, + ); + pointer.frame(state); + pointer.set_grab(state, grab, serial, focus); + } + GrabType::TabletTool => { + seat.tablet_seat() + .get_tool(grab.tool().unwrap()) + .unwrap() + .set_grab(state, grab, InputTime::now(), serial, focus); + } } } }); @@ -459,21 +479,30 @@ pub fn window_items( std::mem::drop(shell); if let Some(((target, loc), (grab, focus))) = res { let serial = SERIAL_COUNTER.next_serial(); - if grab.is_touch_grab() { - seat.get_touch().unwrap().set_grab(state, grab, serial); - } else { - let pointer = seat.get_pointer().unwrap(); - pointer.motion( - state, - target, - &MotionEvent { - location: loc.as_logical().to_f64(), - serial, - time: InputTime::now(), - }, - ); - pointer.frame(state); - pointer.set_grab(state, grab, serial, focus); + match grab.grab_type() { + GrabType::Touch => { + seat.get_touch().unwrap().set_grab(state, grab, serial) + } + GrabType::Pointer => { + let pointer = seat.get_pointer().unwrap(); + pointer.motion( + state, + target, + &MotionEvent { + location: loc.as_logical().to_f64(), + serial, + time: InputTime::now(), + }, + ); + pointer.frame(state); + pointer.set_grab(state, grab, serial, focus); + } + GrabType::TabletTool => { + seat.tablet_seat() + .get_tool(grab.tool().unwrap()) + .unwrap() + .set_grab(state, grab, InputTime::now(), serial, focus); + } } } }); @@ -494,21 +523,29 @@ pub fn window_items( std::mem::drop(shell); if let Some(((target, loc), (grab, focus))) = res { let serial = SERIAL_COUNTER.next_serial(); - if grab.is_touch_grab() { - seat.get_touch().unwrap().set_grab(state, grab, serial); - } else { - let pointer = seat.get_pointer().unwrap(); - pointer.motion( - state, - target, - &MotionEvent { - location: loc.as_logical().to_f64(), - serial, - time: InputTime::now(), - }, - ); - pointer.frame(state); - pointer.set_grab(state, grab, serial, focus); + match grab.grab_type() { + GrabType::Touch => { + seat.get_touch().unwrap().set_grab(state, grab, serial) + } + GrabType::Pointer => { + let pointer = seat.get_pointer().unwrap(); + pointer.motion( + state, + target, + &MotionEvent { + location: loc.as_logical().to_f64(), + serial, + time: InputTime::now(), + }, + ); + pointer.frame(state); + pointer.set_grab(state, grab, serial, focus); + } + GrabType::TabletTool => seat + .tablet_seat() + .get_tool(grab.tool().unwrap()) + .unwrap() + .set_grab(state, grab, InputTime::now(), serial, focus), } } }); @@ -628,19 +665,20 @@ pub fn fullscreen_items(window: &CosmicSurface, config: &Config) -> impl Iterato std::mem::drop(shell); if let Some((grab, focus)) = res { - if grab.is_touch_grab() { - seat.get_touch().unwrap().set_grab( - state, - grab, - SERIAL_COUNTER.next_serial(), - ) - } else { - seat.get_pointer().unwrap().set_grab( - state, - grab, - SERIAL_COUNTER.next_serial(), - focus, - ); + let serial = SERIAL_COUNTER.next_serial(); + match grab.grab_type() { + GrabType::Touch => { + seat.get_touch().unwrap().set_grab(state, grab, serial) + } + GrabType::Pointer => seat + .get_pointer() + .unwrap() + .set_grab(state, grab, serial, focus), + GrabType::TabletTool => seat + .tablet_seat() + .get_tool(grab.tool().unwrap()) + .unwrap() + .set_grab(state, grab, InputTime::now(), serial, focus), } } } diff --git a/src/shell/grabs/menu/mod.rs b/src/shell/grabs/menu/mod.rs index 72ea065b..dafbd6cc 100644 --- a/src/shell/grabs/menu/mod.rs +++ b/src/shell/grabs/menu/mod.rs @@ -19,22 +19,33 @@ use cosmic::{ }; use smithay::{ backend::{ - input::{ButtonState, TouchSlot}, + input::{ButtonState, InputTime, TabletToolDescriptor, TouchSlot}, renderer::ImportMem, }, desktop::space::SpaceElement, input::{ Seat, pointer::{ - AxisFrame, ButtonEvent, GestureHoldBeginEvent, GestureHoldEndEvent, - GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent, - GestureSwipeBeginEvent, GestureSwipeEndEvent, GestureSwipeUpdateEvent, - GrabStartData as PointerGrabStartData, MotionEvent as PointerMotionEvent, PointerGrab, - PointerInnerHandle, PointerTarget, RelativeMotionEvent, + AxisFrame as PointerAxisFrame, ButtonEvent as PointerButtonEvent, + GestureHoldBeginEvent, GestureHoldEndEvent, GesturePinchBeginEvent, + GesturePinchEndEvent, GesturePinchUpdateEvent, GestureSwipeBeginEvent, + GestureSwipeEndEvent, GestureSwipeUpdateEvent, GrabStartData as PointerGrabStartData, + MotionEvent as PointerMotionEvent, PointerGrab, PointerInnerHandle, PointerTarget, + RelativeMotionEvent, + }, + tablet::{ + TabletSeatHandler, + tool::{ + AxisFrame as TabletAxisFrame, ButtonEvent as TabletButtonEvent, + DownEvent as TabletDownEvent, GrabStartData as TabletGrabStartData, + MotionEvent as TabletMotionEvent, ProximityInEvent, ProximityOutEvent, + TabletToolGrab, TabletToolInnerHandle, TabletToolTarget, UpEvent as TabletUpEvent, + }, }, touch::{ - DownEvent, GrabStartData as TouchGrabStartData, MotionEvent as TouchMotionEvent, - TouchGrab, TouchInnerHandle, TouchTarget, UpEvent, + DownEvent as TouchDownEvent, GrabStartData as TouchGrabStartData, + MotionEvent as TouchMotionEvent, TouchGrab, TouchInnerHandle, TouchTarget, + UpEvent as TouchUpEvent, }, }, output::Output, @@ -43,7 +54,7 @@ use smithay::{ use crate::{ backend::render::element::AsGlowRenderer, - shell::{SeatExt, focus::target::PointerFocusTarget}, + shell::{SeatExt, focus::target::PointerFocusTarget, grabs::GrabType}, state::State, utils::{ iced::{IcedElement, IcedRenderElement, Program}, @@ -350,6 +361,7 @@ impl Program for ContextMenu { position, pointer_entered: false, touch_entered: None, + tablet_entered: None, }) } }); @@ -508,6 +520,7 @@ pub struct Element { position: Point, pointer_entered: bool, touch_entered: Option, + tablet_entered: Option, } pub struct MenuGrab { @@ -516,6 +529,7 @@ pub struct MenuGrab { seat: Seat, screen_space_relative: Option, scale: Arc>, + last_tablet_idx: Option, } impl PointerGrab for MenuGrab { @@ -598,7 +612,7 @@ impl PointerGrab for MenuGrab { &mut self, state: &mut State, handle: &mut PointerInnerHandle<'_, State>, - event: &ButtonEvent, + event: &PointerButtonEvent, ) { let any_entered = self .elements @@ -632,7 +646,7 @@ impl PointerGrab for MenuGrab { &mut self, state: &mut State, handle: &mut PointerInnerHandle<'_, State>, - details: AxisFrame, + details: PointerAxisFrame, ) { handle.axis(state, details); } @@ -729,7 +743,7 @@ impl TouchGrab for MenuGrab { data: &mut State, handle: &mut TouchInnerHandle<'_, State>, _focus: Option<(PointerFocusTarget, Point)>, - event: &DownEvent, + event: &TouchDownEvent, ) { { let mut guard = self.elements.lock().unwrap(); @@ -757,7 +771,7 @@ impl TouchGrab for MenuGrab { }) { let element = &mut elements[i]; - let new_event = DownEvent { + let new_event = TouchDownEvent { slot: event.slot, location: event_location - element.position.as_logical().to_f64(), serial: event.serial, @@ -772,7 +786,12 @@ impl TouchGrab for MenuGrab { handle.down(data, None, event); } - fn up(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>, event: &UpEvent) { + fn up( + &mut self, + data: &mut State, + handle: &mut TouchInnerHandle<'_, State>, + event: &TouchUpEvent, + ) { { let elements = self.elements.lock().unwrap(); for element in elements.iter().filter(|elem| { @@ -848,6 +867,248 @@ impl TouchGrab for MenuGrab { fn unset(&mut self, _data: &mut State) {} } +impl TabletToolGrab for MenuGrab { + fn start_data(&self) -> &TabletGrabStartData { + match &self.start_data { + GrabStartData::TabletTool { data, .. } => data, + _ => unreachable!(), + } + } + + fn proximity_in( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + _focus: Option<(::ToolFocus, Point)>, + event: &ProximityInEvent, + ) { + { + let location = if let Some(output) = self.screen_space_relative.as_ref() { + if data.common.shell.read().zoom_state().is_some() { + event + .location + .as_global() + .to_zoomed(output) + .to_global(output) + .as_logical() + } else { + event.location + } + } else { + event.location + }; + + let mut elements = self.elements.lock().unwrap(); + if let Some(i) = elements.iter().position(|elem| { + let mut bbox = elem.iced.bbox(); + bbox.loc = elem.position.as_logical(); + + bbox.contains(location.to_i32_floor()) + }) { + let element = &mut elements[i]; + + let new_event = TabletMotionEvent { + location: location - element.position.as_logical().to_f64(), + serial: event.serial, + time: event.time, + }; + + TabletToolTarget::proximity_in( + &element.iced, + &self.seat, + data, + handle.descriptor(), + &handle.current_tablet(), + event.serial, + ); + element.tablet_entered = Some(handle.descriptor().clone()); + TabletToolTarget::motion( + &element.iced, + &self.seat, + data, + handle.descriptor(), + &new_event, + ); + self.last_tablet_idx = Some(i); + } + } + handle.proximity_in(data, None, event); + } + + fn proximity_out( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + event: &ProximityOutEvent, + ) { + { + let mut elements = self.elements.lock().unwrap(); + for element in elements.iter_mut().filter(|elem| { + elem.tablet_entered + .as_ref() + .is_some_and(|tool| tool == handle.descriptor()) + }) { + TabletToolTarget::proximity_out( + &element.iced, + &self.seat, + data, + handle.descriptor(), + ); + element.tablet_entered.take(); + } + self.last_tablet_idx.take(); + } + handle.unset_grab(self, data, event.serial, event.time, true); + } + + fn motion( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + _focus: Option<(::ToolFocus, Point)>, + event: &TabletMotionEvent, + ) { + { + let location = if let Some(output) = self.screen_space_relative.as_ref() { + if data.common.shell.read().zoom_state().is_some() { + event + .location + .as_global() + .to_zoomed(output) + .to_global(output) + .as_logical() + } else { + event.location + } + } else { + event.location + }; + + let mut elements = self.elements.lock().unwrap(); + if let Some(i) = elements.iter().position(|elem| { + let mut bbox = elem.iced.bbox(); + bbox.loc = elem.position.as_logical(); + + bbox.contains(location.to_i32_floor()) + }) { + let element = &mut elements[i]; + + let new_event = TabletMotionEvent { + location: location - element.position.as_logical().to_f64(), + serial: event.serial, + time: event.time, + }; + + if element.tablet_entered.is_none() { + TabletToolTarget::proximity_in( + &element.iced, + &self.seat, + data, + handle.descriptor(), + &handle.current_tablet(), + event.serial, + ); + element.tablet_entered = Some(handle.descriptor().clone()); + } + TabletToolTarget::motion( + &element.iced, + &self.seat, + data, + handle.descriptor(), + &new_event, + ); + self.last_tablet_idx = Some(i); + } else { + elements + .iter_mut() + .filter(|element| element.tablet_entered.is_some()) + .skip(1) + .for_each(|element| { + TabletToolTarget::proximity_out( + &element.iced, + &self.seat, + data, + handle.descriptor(), + ); + }); + self.last_tablet_idx.take(); + } + } + handle.motion(data, None, event); + } + + fn down( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + event: &TabletDownEvent, + ) { + let mut guard = self.elements.lock().unwrap(); + let elements = &mut *guard; + + if let Some(elem) = self.last_tablet_idx.and_then(|i| elements.get_mut(i)) + && elem + .tablet_entered + .as_ref() + .is_some_and(|desc| desc == handle.descriptor()) + { + TabletToolTarget::down(&elem.iced, &self.seat, data, handle.descriptor(), event); + } else { + handle.down(data, event); + } + } + + fn up( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + event: &TabletUpEvent, + ) { + let mut guard = self.elements.lock().unwrap(); + let elements = &mut *guard; + + if let Some(elem) = self.last_tablet_idx.and_then(|i| elements.get_mut(i)) + && elem + .tablet_entered + .as_ref() + .is_some_and(|desc| desc == handle.descriptor()) + { + TabletToolTarget::up(&elem.iced, &self.seat, data, handle.descriptor(), event); + } else { + handle.up(data, event); + } + } + + fn button( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + event: &TabletButtonEvent, + ) { + handle.button(data, event); + } + + fn axis( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + frame: TabletAxisFrame, + ) { + handle.axis(data, frame); + } + + fn frame( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + time: InputTime, + ) { + handle.frame(data, time); + } + + fn unset(&mut self, _data: &mut State) {} +} + #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct MenuAlignment { pub x: AxisAlignment, @@ -1051,6 +1312,7 @@ impl MenuGrab { position, pointer_entered: false, touch_entered: None, + tablet_entered: None, }])); let scale = Arc::new(Mutex::new(screen_space_relative.unwrap_or(1.))); @@ -1075,6 +1337,7 @@ impl MenuGrab { seat: seat.clone(), screen_space_relative, scale, + last_tablet_idx: None, } } @@ -1085,10 +1348,15 @@ impl MenuGrab { } } - pub fn is_touch_grab(&self) -> bool { - match self.start_data { - GrabStartData::Touch(_) => true, - GrabStartData::Pointer(_) => false, + pub fn grab_type(&self) -> GrabType { + self.start_data.type_() + } + + pub fn tool(&self) -> Option<&TabletToolDescriptor> { + if let GrabStartData::TabletTool { tool, .. } = &self.start_data { + Some(tool) + } else { + None } } } diff --git a/src/shell/grabs/mod.rs b/src/shell/grabs/mod.rs index 515916fd..9524f425 100644 --- a/src/shell/grabs/mod.rs +++ b/src/shell/grabs/mod.rs @@ -1,18 +1,26 @@ use calloop::LoopHandle; use cosmic_settings_config::shortcuts; use smithay::{ + backend::input::{InputTime, TabletToolDescriptor}, input::{ Seat, pointer::{ - AxisFrame, ButtonEvent, GestureHoldBeginEvent, GestureHoldEndEvent, - GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent, - GestureSwipeBeginEvent, GestureSwipeEndEvent, GestureSwipeUpdateEvent, - GrabStartData as PointerGrabStartData, MotionEvent, PointerGrab, PointerInnerHandle, - RelativeMotionEvent, + AxisFrame as PointerAxisFrame, ButtonEvent as PointerButtonEvent, + GestureHoldBeginEvent, GestureHoldEndEvent, GesturePinchBeginEvent, + GesturePinchEndEvent, GesturePinchUpdateEvent, GestureSwipeBeginEvent, + GestureSwipeEndEvent, GestureSwipeUpdateEvent, GrabStartData as PointerGrabStartData, + MotionEvent, PointerGrab, PointerInnerHandle, RelativeMotionEvent, + }, + tablet::tool::{ + AxisFrame as TabletAxisFrame, ButtonEvent as TabletButtonEvent, + DownEvent as TabletDownEvent, GrabStartData as TabletGrabStartData, + MotionEvent as TabletMotionEvent, ProximityOutEvent, TabletToolGrab, + TabletToolInnerHandle, UpEvent as TabletUpEvent, }, touch::{ - DownEvent, GrabStartData as TouchGrabStartData, MotionEvent as TouchMotionEvent, - OrientationEvent, ShapeEvent, TouchGrab, TouchInnerHandle, UpEvent, + DownEvent as TouchDownEvent, GrabStartData as TouchGrabStartData, + MotionEvent as TouchMotionEvent, OrientationEvent, ShapeEvent, TouchGrab, + TouchInnerHandle, UpEvent as TouchUpEvent, }, }, output::Output, @@ -39,6 +47,17 @@ use super::{ pub enum GrabStartData { Touch(TouchGrabStartData), Pointer(PointerGrabStartData), + TabletTool { + tool: TabletToolDescriptor, + data: TabletGrabStartData, + }, +} + +#[derive(Debug, Clone)] +pub enum GrabType { + Touch, + Pointer, + TabletTool, } impl GrabStartData { @@ -46,6 +65,7 @@ impl GrabStartData { match self { Self::Touch(touch) => touch.focus.as_ref(), Self::Pointer(pointer) => pointer.focus.as_ref(), + Self::TabletTool { data, .. } => data.focus.as_ref(), } } @@ -53,6 +73,7 @@ impl GrabStartData { match self { Self::Touch(touch) => touch.focus = focus, Self::Pointer(pointer) => pointer.focus = focus, + Self::TabletTool { data, .. } => data.focus = focus, } } @@ -60,6 +81,7 @@ impl GrabStartData { match self { Self::Touch(touch) => touch.location, Self::Pointer(pointer) => pointer.location, + Self::TabletTool { data, .. } => data.location, } } @@ -67,6 +89,7 @@ impl GrabStartData { match self { Self::Touch(touch) => touch.location = location, Self::Pointer(pointer) => pointer.location = location, + Self::TabletTool { data, .. } => data.location = location, } } @@ -76,6 +99,14 @@ impl GrabStartData { ((new.x - old.x).powi(2) + (new.y - old.y).powi(2)).sqrt() } + + pub fn type_(&self) -> GrabType { + match self { + Self::Pointer(_) => GrabType::Pointer, + Self::Touch(_) => GrabType::Touch, + Self::TabletTool { .. } => GrabType::TabletTool, + } + } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -203,10 +234,17 @@ impl From for ResizeGrab { } impl ResizeGrab { - pub fn is_touch_grab(&self) -> bool { + pub fn grab_type(&self) -> GrabType { match self { - ResizeGrab::Floating(grab) => grab.is_touch_grab(), - ResizeGrab::Tiling(grab) => grab.is_touch_grab(), + ResizeGrab::Floating(grab) => grab.grab_type(), + ResizeGrab::Tiling(grab) => grab.grab_type(), + } + } + + pub fn tool(&self) -> Option<&TabletToolDescriptor> { + match self { + ResizeGrab::Floating(grab) => grab.tool(), + ResizeGrab::Tiling(grab) => grab.tool(), } } } @@ -242,11 +280,11 @@ impl PointerGrab for ResizeGrab { &mut self, data: &mut State, handle: &mut PointerInnerHandle<'_, State>, - event: &ButtonEvent, + event: &PointerButtonEvent, ) { match self { - ResizeGrab::Floating(grab) => grab.button(data, handle, event), - ResizeGrab::Tiling(grab) => grab.button(data, handle, event), + ResizeGrab::Floating(grab) => PointerGrab::button(grab, data, handle, event), + ResizeGrab::Tiling(grab) => PointerGrab::button(grab, data, handle, event), } } @@ -254,11 +292,11 @@ impl PointerGrab for ResizeGrab { &mut self, data: &mut State, handle: &mut PointerInnerHandle<'_, State>, - details: AxisFrame, + details: PointerAxisFrame, ) { match self { - ResizeGrab::Floating(grab) => grab.axis(data, handle, details), - ResizeGrab::Tiling(grab) => grab.axis(data, handle, details), + ResizeGrab::Floating(grab) => PointerGrab::axis(grab, data, handle, details), + ResizeGrab::Tiling(grab) => PointerGrab::axis(grab, data, handle, details), } } @@ -386,7 +424,7 @@ impl TouchGrab for ResizeGrab { data: &mut State, handle: &mut TouchInnerHandle<'_, State>, focus: Option<(PointerFocusTarget, Point)>, - event: &DownEvent, + event: &TouchDownEvent, ) { match self { ResizeGrab::Floating(grab) => TouchGrab::down(grab, data, handle, focus, event), @@ -394,7 +432,12 @@ impl TouchGrab for ResizeGrab { } } - fn up(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>, event: &UpEvent) { + fn up( + &mut self, + data: &mut State, + handle: &mut TouchInnerHandle<'_, State>, + event: &TouchUpEvent, + ) { match self { ResizeGrab::Floating(grab) => TouchGrab::up(grab, data, handle, event), ResizeGrab::Tiling(grab) => TouchGrab::up(grab, data, handle, event), @@ -467,6 +510,107 @@ impl TouchGrab for ResizeGrab { } } +impl TabletToolGrab for ResizeGrab { + fn down( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + event: &TabletDownEvent, + ) { + match self { + ResizeGrab::Floating(grab) => TabletToolGrab::down(grab, data, handle, event), + ResizeGrab::Tiling(grab) => TabletToolGrab::down(grab, data, handle, event), + } + } + + fn up( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + event: &TabletUpEvent, + ) { + match self { + ResizeGrab::Floating(grab) => TabletToolGrab::up(grab, data, handle, event), + ResizeGrab::Tiling(grab) => TabletToolGrab::up(grab, data, handle, event), + } + } + + fn motion( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + focus: Option<(PointerFocusTarget, Point)>, + event: &TabletMotionEvent, + ) { + match self { + ResizeGrab::Floating(grab) => TabletToolGrab::motion(grab, data, handle, focus, event), + ResizeGrab::Tiling(grab) => TabletToolGrab::motion(grab, data, handle, focus, event), + } + } + + fn frame( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + serial: InputTime, + ) { + match self { + ResizeGrab::Floating(grab) => TabletToolGrab::frame(grab, data, handle, serial), + ResizeGrab::Tiling(grab) => TabletToolGrab::frame(grab, data, handle, serial), + } + } + + fn button( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + event: &TabletButtonEvent, + ) { + match self { + ResizeGrab::Floating(grab) => TabletToolGrab::button(grab, data, handle, event), + ResizeGrab::Tiling(grab) => TabletToolGrab::button(grab, data, handle, event), + } + } + + fn axis( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + details: TabletAxisFrame, + ) { + match self { + ResizeGrab::Floating(grab) => TabletToolGrab::axis(grab, data, handle, details), + ResizeGrab::Tiling(grab) => TabletToolGrab::axis(grab, data, handle, details), + } + } + + fn proximity_out( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + event: &ProximityOutEvent, + ) { + match self { + ResizeGrab::Floating(grab) => TabletToolGrab::proximity_out(grab, data, handle, event), + ResizeGrab::Tiling(grab) => TabletToolGrab::proximity_out(grab, data, handle, event), + } + } + + fn start_data(&self) -> &TabletGrabStartData { + match self { + ResizeGrab::Floating(grab) => TabletToolGrab::start_data(grab), + ResizeGrab::Tiling(grab) => TabletToolGrab::start_data(grab), + } + } + + fn unset(&mut self, data: &mut State) { + match self { + ResizeGrab::Floating(grab) => TabletToolGrab::unset(grab, data), + ResizeGrab::Tiling(grab) => TabletToolGrab::unset(grab, data), + } + } +} + pub enum MoveGrab { Move(moving::MoveGrab), Delayed(delay::DelayGrab), @@ -536,10 +680,17 @@ impl MoveGrab { } } - pub fn is_touch_grab(&self) -> bool { + pub fn grab_type(&self) -> GrabType { match self { - MoveGrab::Move(m) => m.is_touch_grab(), - MoveGrab::Delayed(d) => d.is_touch_grab(), + MoveGrab::Move(m) => m.grab_type(), + MoveGrab::Delayed(d) => d.grab_type(), + } + } + + pub fn tool(&self) -> Option<&TabletToolDescriptor> { + match self { + MoveGrab::Move(m) => m.tool(), + MoveGrab::Delayed(d) => d.tool(), } } } @@ -574,11 +725,11 @@ impl PointerGrab for MoveGrab { &mut self, data: &mut State, handle: &mut PointerInnerHandle<'_, State>, - event: &ButtonEvent, + event: &PointerButtonEvent, ) { match self { - MoveGrab::Move(grab) => grab.button(data, handle, event), - MoveGrab::Delayed(grab) => grab.button(data, handle, event), + MoveGrab::Move(grab) => PointerGrab::button(grab, data, handle, event), + MoveGrab::Delayed(grab) => PointerGrab::button(grab, data, handle, event), } } @@ -586,11 +737,11 @@ impl PointerGrab for MoveGrab { &mut self, data: &mut State, handle: &mut PointerInnerHandle<'_, State>, - details: AxisFrame, + details: PointerAxisFrame, ) { match self { - MoveGrab::Move(grab) => grab.axis(data, handle, details), - MoveGrab::Delayed(grab) => grab.axis(data, handle, details), + MoveGrab::Move(grab) => PointerGrab::axis(grab, data, handle, details), + MoveGrab::Delayed(grab) => PointerGrab::axis(grab, data, handle, details), } } @@ -718,7 +869,7 @@ impl TouchGrab for MoveGrab { data: &mut State, handle: &mut TouchInnerHandle<'_, State>, focus: Option<(PointerFocusTarget, Point)>, - event: &DownEvent, + event: &TouchDownEvent, ) { match self { MoveGrab::Move(grab) => TouchGrab::down(grab, data, handle, focus, event), @@ -726,7 +877,12 @@ impl TouchGrab for MoveGrab { } } - fn up(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>, event: &UpEvent) { + fn up( + &mut self, + data: &mut State, + handle: &mut TouchInnerHandle<'_, State>, + event: &TouchUpEvent, + ) { match self { MoveGrab::Move(grab) => TouchGrab::up(grab, data, handle, event), MoveGrab::Delayed(grab) => TouchGrab::up(grab, data, handle, event), @@ -798,3 +954,104 @@ impl TouchGrab for MoveGrab { } } } + +impl TabletToolGrab for MoveGrab { + fn down( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + event: &TabletDownEvent, + ) { + match self { + MoveGrab::Move(grab) => TabletToolGrab::down(grab, data, handle, event), + MoveGrab::Delayed(grab) => TabletToolGrab::down(grab, data, handle, event), + } + } + + fn up( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + event: &TabletUpEvent, + ) { + match self { + MoveGrab::Move(grab) => TabletToolGrab::up(grab, data, handle, event), + MoveGrab::Delayed(grab) => TabletToolGrab::up(grab, data, handle, event), + } + } + + fn motion( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + focus: Option<(PointerFocusTarget, Point)>, + event: &TabletMotionEvent, + ) { + match self { + MoveGrab::Move(grab) => TabletToolGrab::motion(grab, data, handle, focus, event), + MoveGrab::Delayed(grab) => TabletToolGrab::motion(grab, data, handle, focus, event), + } + } + + fn frame( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + serial: InputTime, + ) { + match self { + MoveGrab::Move(grab) => TabletToolGrab::frame(grab, data, handle, serial), + MoveGrab::Delayed(grab) => TabletToolGrab::frame(grab, data, handle, serial), + } + } + + fn button( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + event: &TabletButtonEvent, + ) { + match self { + MoveGrab::Move(grab) => TabletToolGrab::button(grab, data, handle, event), + MoveGrab::Delayed(grab) => TabletToolGrab::button(grab, data, handle, event), + } + } + + fn axis( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + details: TabletAxisFrame, + ) { + match self { + MoveGrab::Move(grab) => TabletToolGrab::axis(grab, data, handle, details), + MoveGrab::Delayed(grab) => TabletToolGrab::axis(grab, data, handle, details), + } + } + + fn proximity_out( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + event: &ProximityOutEvent, + ) { + match self { + MoveGrab::Move(grab) => TabletToolGrab::proximity_out(grab, data, handle, event), + MoveGrab::Delayed(grab) => TabletToolGrab::proximity_out(grab, data, handle, event), + } + } + + fn start_data(&self) -> &TabletGrabStartData { + match self { + MoveGrab::Move(grab) => TabletToolGrab::start_data(grab), + MoveGrab::Delayed(grab) => TabletToolGrab::start_data(grab), + } + } + + fn unset(&mut self, data: &mut State) { + match self { + MoveGrab::Move(grab) => TabletToolGrab::unset(grab, data), + MoveGrab::Delayed(grab) => TabletToolGrab::unset(grab, data), + } + } +} diff --git a/src/shell/grabs/moving.rs b/src/shell/grabs/moving.rs index 05923bc7..15225212 100644 --- a/src/shell/grabs/moving.rs +++ b/src/shell/grabs/moving.rs @@ -8,6 +8,7 @@ use crate::{ CosmicMapped, CosmicSurface, Direction, ManagedLayer, element::{CosmicMappedRenderElement, stack_hover::StackHover}, focus::target::{KeyboardFocusTarget, PointerFocusTarget}, + grabs::GrabType, layout::floating::TiledCorners, }, utils::prelude::*, @@ -20,7 +21,7 @@ use smallvec::SmallVec; use smithay::{ backend::{ drm::DrmNode, - input::{ButtonState, InputTime}, + input::{ButtonState, InputTime, TabletToolDescriptor}, renderer::{ ImportAll, ImportMem, element::{RenderElement, utils::RescaleRenderElement}, @@ -30,13 +31,27 @@ use smithay::{ input::{ Seat, pointer::{ - AxisFrame, ButtonEvent, CursorIcon, GestureHoldBeginEvent, GestureHoldEndEvent, - GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent, - GestureSwipeBeginEvent, GestureSwipeEndEvent, GestureSwipeUpdateEvent, - GrabStartData as PointerGrabStartData, MotionEvent, PointerGrab, PointerInnerHandle, + AxisFrame as PointerAxisFrame, ButtonEvent as PointerButtonEvent, CursorIcon, + GestureHoldBeginEvent, GestureHoldEndEvent, GesturePinchBeginEvent, + GesturePinchEndEvent, GesturePinchUpdateEvent, GestureSwipeBeginEvent, + GestureSwipeEndEvent, GestureSwipeUpdateEvent, GrabStartData as PointerGrabStartData, + MotionEvent as PointerMotionEvent, PointerGrab, PointerInnerHandle, RelativeMotionEvent, }, - touch::{self, GrabStartData as TouchGrabStartData, TouchGrab, TouchInnerHandle}, + tablet::{ + TabletSeatHandler, + tool::{ + AxisFrame as TabletAxisFrame, ButtonEvent as TabletButtonEvent, + DownEvent as TabletDownEvent, GrabStartData as TabletGrabStartData, + MotionEvent as TabletMotionEvent, ProximityInEvent, ProximityOutEvent, + TabletToolGrab, TabletToolInnerHandle, UpEvent as TabletUpEvent, + }, + }, + touch::{ + DownEvent as TouchDownEvent, GrabStartData as TouchGrabStartData, + MotionEvent as TouchMotionEvent, OrientationEvent, ShapeEvent, TouchGrab, + TouchInnerHandle, UpEvent as TouchUpEvent, + }, }, output::Output, utils::{IsAlive, Logical, Point, Rectangle, SERIAL_COUNTER, Scale}, @@ -503,7 +518,7 @@ impl PointerGrab for MoveGrab { state: &mut State, handle: &mut PointerInnerHandle<'_, State>, _focus: Option<(PointerFocusTarget, Point)>, - event: &MotionEvent, + event: &PointerMotionEvent, ) { self.update_location(state, event.location); @@ -529,7 +544,7 @@ impl PointerGrab for MoveGrab { &mut self, state: &mut State, handle: &mut PointerInnerHandle<'_, State>, - event: &ButtonEvent, + event: &PointerButtonEvent, ) { handle.button(state, event); match self.release { @@ -550,7 +565,7 @@ impl PointerGrab for MoveGrab { &mut self, state: &mut State, handle: &mut PointerInnerHandle<'_, State>, - details: AxisFrame, + details: PointerAxisFrame, ) { handle.axis(state, details); } @@ -647,7 +662,7 @@ impl TouchGrab for MoveGrab { data: &mut State, handle: &mut TouchInnerHandle<'_, State>, _focus: Option<(PointerFocusTarget, Point)>, - event: &touch::DownEvent, + event: &TouchDownEvent, ) { handle.down(data, None, event) } @@ -656,7 +671,7 @@ impl TouchGrab for MoveGrab { &mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>, - event: &touch::UpEvent, + event: &TouchUpEvent, ) { if event.slot == >::start_data(self).slot { handle.unset_grab(self, data); @@ -670,7 +685,7 @@ impl TouchGrab for MoveGrab { data: &mut State, handle: &mut TouchInnerHandle<'_, State>, _focus: Option<(PointerFocusTarget, Point)>, - event: &touch::MotionEvent, + event: &TouchMotionEvent, ) { if event.slot == >::start_data(self).slot { self.update_location(data, event.location); @@ -691,7 +706,7 @@ impl TouchGrab for MoveGrab { &mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>, - event: &touch::ShapeEvent, + event: &ShapeEvent, ) { handle.shape(data, event) } @@ -700,7 +715,7 @@ impl TouchGrab for MoveGrab { &mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>, - event: &touch::OrientationEvent, + event: &OrientationEvent, ) { handle.orientation(data, event) } @@ -715,6 +730,100 @@ impl TouchGrab for MoveGrab { fn unset(&mut self, _data: &mut State) {} } +impl TabletToolGrab for MoveGrab { + fn start_data(&self) -> &TabletGrabStartData { + match &self.start_data { + GrabStartData::TabletTool { data, .. } => data, + _ => unreachable!(), + } + } + + fn proximity_out( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + event: &ProximityOutEvent, + ) { + handle.proximity_out(data, event); + } + + fn motion( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + _focus: Option<(::ToolFocus, Point)>, + event: &TabletMotionEvent, + ) { + handle.motion(data, None, event); + + self.update_location(data, event.location); + if !self.window.alive() { + handle.unset_grab(self, data, event.serial, event.time, true); + } + } + + fn down( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + event: &TabletDownEvent, + ) { + handle.down(data, event) + } + + fn up( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + event: &TabletUpEvent, + ) { + if self.tool().is_some_and(|tool| tool == handle.descriptor()) { + handle.unset_grab(self, data, event.serial, event.time, false); + } + + handle.up(data, event); + } + + fn button( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + event: &TabletButtonEvent, + ) { + handle.button(data, event) + } + + fn axis( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + frame: TabletAxisFrame, + ) { + handle.axis(data, frame) + } + + fn frame( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + time: InputTime, + ) { + handle.frame(data, time) + } + + fn proximity_in( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + focus: Option<(::ToolFocus, Point)>, + event: &ProximityInEvent, + ) { + handle.proximity_in(data, focus, event); + } + + fn unset(&mut self, _data: &mut State) {} +} + impl MoveGrab { pub fn new( start_data: GrabStartData, @@ -778,10 +887,15 @@ impl MoveGrab { self.previous == ManagedLayer::Tiling } - pub fn is_touch_grab(&self) -> bool { - match self.start_data { - GrabStartData::Touch(_) => true, - GrabStartData::Pointer(_) => false, + pub fn grab_type(&self) -> GrabType { + self.start_data.type_() + } + + pub fn tool(&self) -> Option<&TabletToolDescriptor> { + if let GrabStartData::TabletTool { tool, .. } = &self.start_data { + Some(tool) + } else { + None } } } @@ -953,7 +1067,7 @@ impl Drop for MoveGrab { position.as_logical().to_f64() - window.geometry().loc.to_f64() + offset, )), - &MotionEvent { + &PointerMotionEvent { location: pointer.current_location(), serial, time: InputTime::now(), diff --git a/src/shell/layout/floating/grabs/resize.rs b/src/shell/layout/floating/grabs/resize.rs index f9e5cbfd..9d767671 100644 --- a/src/shell/layout/floating/grabs/resize.rs +++ b/src/shell/layout/floating/grabs/resize.rs @@ -7,25 +7,36 @@ use crate::{ shell::{ element::CosmicMapped, focus::target::PointerFocusTarget, - grabs::{GrabStartData, ReleaseMode, ResizeEdge}, + grabs::{GrabStartData, GrabType, ReleaseMode, ResizeEdge}, }, utils::prelude::*, }; use smithay::{ - backend::input::ButtonState, + backend::input::{ButtonState, InputTime, TabletToolDescriptor}, desktop::{WindowSurface, space::SpaceElement}, input::{ Seat, pointer::{ - AxisFrame, ButtonEvent, CursorIcon, GestureHoldBeginEvent, GestureHoldEndEvent, - GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent, - GestureSwipeBeginEvent, GestureSwipeEndEvent, GestureSwipeUpdateEvent, - GrabStartData as PointerGrabStartData, MotionEvent, PointerGrab, PointerInnerHandle, + AxisFrame as PointerAxisFrame, ButtonEvent as PointerButtonEvent, CursorIcon, + GestureHoldBeginEvent, GestureHoldEndEvent, GesturePinchBeginEvent, + GesturePinchEndEvent, GesturePinchUpdateEvent, GestureSwipeBeginEvent, + GestureSwipeEndEvent, GestureSwipeUpdateEvent, GrabStartData as PointerGrabStartData, + MotionEvent as PointerMotionEvent, PointerGrab, PointerInnerHandle, RelativeMotionEvent, }, + tablet::{ + TabletSeatHandler, + tool::{ + AxisFrame as TabletAxisFrame, ButtonEvent as TabletButtonEvent, + DownEvent as TabletDownEvent, GrabStartData as TabletGrabStartData, + MotionEvent as TabletMotionEvent, ProximityInEvent, ProximityOutEvent, + TabletToolGrab, TabletToolInnerHandle, UpEvent as TabletUpEvent, + }, + }, touch::{ - DownEvent, GrabStartData as TouchGrabStartData, MotionEvent as TouchMotionEvent, - OrientationEvent, ShapeEvent, TouchGrab, TouchInnerHandle, UpEvent, + DownEvent as TouchDownEvent, GrabStartData as TouchGrabStartData, + MotionEvent as TouchMotionEvent, OrientationEvent, ShapeEvent, TouchGrab, + TouchInnerHandle, UpEvent as TouchUpEvent, }, }, output::Output, @@ -170,10 +181,19 @@ impl ResizeSurfaceGrab { false } - pub fn is_touch_grab(&self) -> bool { + pub fn grab_type(&self) -> GrabType { match self.start_data { - GrabStartData::Touch(_) => true, - GrabStartData::Pointer(_) => false, + GrabStartData::Pointer(_) => GrabType::Pointer, + GrabStartData::Touch(_) => GrabType::Touch, + GrabStartData::TabletTool { .. } => GrabType::TabletTool, + } + } + + pub fn tool(&self) -> Option<&TabletToolDescriptor> { + if let GrabStartData::TabletTool { tool, .. } = &self.start_data { + Some(tool) + } else { + None } } } @@ -184,7 +204,7 @@ impl PointerGrab for ResizeSurfaceGrab { data: &mut State, handle: &mut PointerInnerHandle<'_, State>, _focus: Option<(PointerFocusTarget, Point)>, - event: &MotionEvent, + event: &PointerMotionEvent, ) { // While the grab is active, no client has pointer focus handle.motion(data, None, event); @@ -209,7 +229,7 @@ impl PointerGrab for ResizeSurfaceGrab { &mut self, data: &mut State, handle: &mut PointerInnerHandle<'_, State>, - event: &ButtonEvent, + event: &PointerButtonEvent, ) { handle.button(data, event); match self.release { @@ -230,7 +250,7 @@ impl PointerGrab for ResizeSurfaceGrab { &mut self, data: &mut State, handle: &mut PointerInnerHandle<'_, State>, - details: AxisFrame, + details: PointerAxisFrame, ) { handle.axis(data, details) } @@ -329,12 +349,17 @@ impl TouchGrab for ResizeSurfaceGrab { data: &mut State, handle: &mut TouchInnerHandle<'_, State>, _focus: Option<(PointerFocusTarget, Point)>, - event: &DownEvent, + event: &TouchDownEvent, ) { handle.down(data, None, event) } - fn up(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>, event: &UpEvent) { + fn up( + &mut self, + data: &mut State, + handle: &mut TouchInnerHandle<'_, State>, + event: &TouchUpEvent, + ) { if event.slot == >::start_data(self).slot { handle.unset_grab(self, data); } @@ -396,6 +421,99 @@ impl TouchGrab for ResizeSurfaceGrab { } } +impl TabletToolGrab for ResizeSurfaceGrab { + fn start_data(&self) -> &TabletGrabStartData { + match &self.start_data { + GrabStartData::TabletTool { data, .. } => data, + _ => unreachable!(), + } + } + + fn proximity_out( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + event: &ProximityOutEvent, + ) { + handle.unset_grab(self, data, event.serial, event.time, true); + handle.proximity_out(data, event); + } + + fn motion( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + _focus: Option<(::ToolFocus, Point)>, + event: &TabletMotionEvent, + ) { + if self.update_location(event.location.as_global()) { + handle.unset_grab(self, data, event.serial, event.time, true); + } + + handle.motion(data, None, event); + } + + fn down( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + event: &TabletDownEvent, + ) { + handle.down(data, event) + } + + fn up( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + event: &TabletUpEvent, + ) { + handle.unset_grab(self, data, event.serial, event.time, true); + handle.up(data, event); + } + + fn button( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + event: &TabletButtonEvent, + ) { + handle.button(data, event) + } + + fn axis( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + frame: TabletAxisFrame, + ) { + handle.axis(data, frame) + } + + fn frame( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + time: InputTime, + ) { + handle.frame(data, time) + } + + fn unset(&mut self, _data: &mut State) { + self.ungrab() + } + + fn proximity_in( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + _focus: Option<(::ToolFocus, Point)>, + event: &ProximityInEvent, + ) { + handle.proximity_in(data, None, event); + } +} + pub struct ResizeGrabMarker(AtomicBool); impl ResizeGrabMarker { diff --git a/src/shell/layout/tiling/grabs/resize.rs b/src/shell/layout/tiling/grabs/resize.rs index 91873793..b6452168 100644 --- a/src/shell/layout/tiling/grabs/resize.rs +++ b/src/shell/layout/tiling/grabs/resize.rs @@ -1,34 +1,47 @@ // SPDX-License-Identifier: GPL-3.0-only +use std::cell::Cell; + use crate::{ backend::render::cursor::CursorState, shell::{ focus::target::PointerFocusTarget, - grabs::{GrabStartData, ReleaseMode}, + grabs::{GrabStartData, GrabType, ReleaseMode}, layout::Orientation, }, utils::prelude::*, }; use id_tree::{NodeId, Tree}; use smithay::{ - backend::input::{ButtonState, InputTime}, + backend::input::{ButtonState, InputTime, TabletToolDescriptor}, input::{ Seat, pointer::{ - AxisFrame, ButtonEvent, CursorIcon, Focus, GestureHoldBeginEvent, GestureHoldEndEvent, - GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent, - GestureSwipeBeginEvent, GestureSwipeEndEvent, GestureSwipeUpdateEvent, - GrabStartData as PointerGrabStartData, MotionEvent, PointerGrab, PointerInnerHandle, - PointerTarget, RelativeMotionEvent, + AxisFrame as PointerAxisFrame, ButtonEvent as PointerButtonEvent, CursorIcon, Focus, + GestureHoldBeginEvent, GestureHoldEndEvent, GesturePinchBeginEvent, + GesturePinchEndEvent, GesturePinchUpdateEvent, GestureSwipeBeginEvent, + GestureSwipeEndEvent, GestureSwipeUpdateEvent, GrabStartData as PointerGrabStartData, + MotionEvent as PointerMotionEvent, PointerGrab, PointerInnerHandle, PointerTarget, + RelativeMotionEvent, + }, + tablet::{ + Tablet, TabletSeatHandler, TabletSeatTrait, + tool::{ + AxisFrame as TabletAxisFrame, ButtonEvent as TabletButtonEvent, + DownEvent as TabletDownEvent, GrabStartData as TabletToolGrabStartData, + GrabTrigger as TabletToolGrabTrigger, MotionEvent as TabletMotionEvent, + ProximityInEvent, ProximityOutEvent, TabletToolGrab, TabletToolInnerHandle, + TabletToolTarget, UpEvent as TabletUpEvent, + }, }, touch::{ - DownEvent, FrameMarker, GrabStartData as TouchGrabStartData, + DownEvent as TouchDownEvent, FrameMarker, GrabStartData as TouchGrabStartData, MotionEvent as TouchMotionEvent, OrientationEvent, ShapeEvent, TouchGrab, - TouchInnerHandle, TouchTarget, UpEvent, + TouchInnerHandle, TouchTarget, UpEvent as TouchUpEvent, }, }, output::WeakOutput, - utils::{IsAlive, Logical, Point}, + utils::{IsAlive, Logical, Point, Serial}, }; use super::super::{Data, TilingLayout}; @@ -39,6 +52,7 @@ pub struct ResizeForkTarget { pub output: WeakOutput, pub left_up_idx: usize, pub orientation: Orientation, + pub last_tablet_location: Cell>>, } impl IsAlive for ResizeForkTarget { @@ -48,7 +62,7 @@ impl IsAlive for ResizeForkTarget { } impl PointerTarget for ResizeForkTarget { - fn enter(&self, seat: &Seat, _data: &mut State, _event: &MotionEvent) { + fn enter(&self, seat: &Seat, _data: &mut State, _event: &PointerMotionEvent) { let user_data = seat.user_data(); let cursor_state = user_data.get::().unwrap(); cursor_state @@ -60,19 +74,13 @@ impl PointerTarget for ResizeForkTarget { }); } - fn leave( - &self, - seat: &Seat, - _data: &mut State, - _serial: smithay::utils::Serial, - _time: InputTime, - ) { + fn leave(&self, seat: &Seat, _data: &mut State, _serial: Serial, _time: InputTime) { let user_data = seat.user_data(); let cursor_state = user_data.get::().unwrap(); cursor_state.lock().unwrap().unset_shape(); } - fn button(&self, seat: &Seat, data: &mut State, event: &ButtonEvent) { + fn button(&self, seat: &Seat, data: &mut State, event: &PointerButtonEvent) { if event.button == 0x110 && event.state == ButtonState::Pressed { let seat = seat.clone(); let node = self.node.clone(); @@ -106,7 +114,7 @@ impl PointerTarget for ResizeForkTarget { } } - fn motion(&self, _seat: &Seat, _data: &mut State, _event: &MotionEvent) {} + fn motion(&self, _seat: &Seat, _data: &mut State, _event: &PointerMotionEvent) {} fn relative_motion( &self, _seat: &Seat, @@ -114,7 +122,7 @@ impl PointerTarget for ResizeForkTarget { _event: &RelativeMotionEvent, ) { } - fn axis(&self, _seat: &Seat, _data: &mut State, _frame: AxisFrame) {} + fn axis(&self, _seat: &Seat, _data: &mut State, _frame: PointerAxisFrame) {} fn frame(&self, _seat: &Seat, _data: &mut State) {} fn gesture_swipe_begin(&self, _: &Seat, _: &mut State, _: &GestureSwipeBeginEvent) {} fn gesture_swipe_update(&self, _: &Seat, _: &mut State, _: &GestureSwipeUpdateEvent) {} @@ -127,7 +135,7 @@ impl PointerTarget for ResizeForkTarget { } impl TouchTarget for ResizeForkTarget { - fn down(&self, seat: &Seat, data: &mut State, event: &DownEvent) { + fn down(&self, seat: &Seat, data: &mut State, event: &TouchDownEvent) { let seat = seat.clone(); let node = self.node.clone(); let output = self.output.clone(); @@ -158,7 +166,7 @@ impl TouchTarget for ResizeForkTarget { }); } - fn up(&self, _seat: &Seat, _data: &mut State, _event: &UpEvent) {} + fn up(&self, _seat: &Seat, _data: &mut State, _event: &TouchUpEvent) {} fn motion(&self, _seat: &Seat, _data: &mut State, _event: &TouchMotionEvent) {} fn frame(&self, _seat: &Seat, _data: &mut State, _frame: FrameMarker) {} fn cancel(&self, _seat: &Seat, _data: &mut State, _frame: FrameMarker) {} @@ -169,6 +177,113 @@ impl TouchTarget for ResizeForkTarget { } } +impl TabletToolTarget for ResizeForkTarget { + fn down( + &self, + seat: &Seat, + data: &mut State, + tool_descriptor: &TabletToolDescriptor, + event: &TabletDownEvent, + ) { + let seat = seat.clone(); + let node = self.node.clone(); + let output = self.output.clone(); + let left_up_idx = self.left_up_idx; + let orientation = self.orientation; + let serial = event.serial; + let time = event.time; + let tool = tool_descriptor.clone(); + let Some(location) = self.last_tablet_location.take() else { + return; + }; + data.common.event_loop_handle.insert_idle(move |state| { + let tablet = seat.tablet_seat().get_tool(&tool).unwrap(); + tablet.set_grab( + state, + ResizeForkGrab::new( + GrabStartData::TabletTool { + tool, + data: TabletToolGrabStartData { + focus: None, + location: location.as_logical(), + trigger: TabletToolGrabTrigger::Tip, + }, + }, + location, + node, + left_up_idx, + orientation, + output, + ReleaseMode::NoMouseButtons, + ), + time, + serial, + Focus::Keep, + ) + }); + } + fn motion( + &self, + _seat: &Seat, + _data: &mut State, + _tool_descriptor: &TabletToolDescriptor, + event: &TabletMotionEvent, + ) { + self.last_tablet_location + .set(Some(event.location.as_global())) + } + fn proximity_out( + &self, + _seat: &Seat, + _data: &mut State, + _tool_descriptor: &TabletToolDescriptor, + ) { + self.last_tablet_location.set(None); + } + + fn proximity_in( + &self, + _seat: &Seat, + _data: &mut State, + _tool_descriptor: &TabletToolDescriptor, + _tablet: &Tablet, + _serial: Serial, + ) { + } + fn up( + &self, + _seat: &Seat, + _data: &mut State, + _tool_descriptor: &TabletToolDescriptor, + _event: &TabletUpEvent, + ) { + } + fn axis( + &self, + _seat: &Seat, + _data: &mut State, + _tool_descriptor: &TabletToolDescriptor, + _frame: TabletAxisFrame, + ) { + } + fn button( + &self, + _seat: &Seat, + _data: &mut State, + _tool_descriptor: &TabletToolDescriptor, + _event: &TabletButtonEvent, + ) { + } + fn frame( + &self, + _seat: &Seat, + _data: &mut State, + _tool_descriptor: &TabletToolDescriptor, + _time: InputTime, + ) { + } +} + pub struct ResizeForkGrab { start_data: GrabStartData, last_loc: Point, @@ -338,10 +453,19 @@ impl ResizeForkGrab { false } - pub fn is_touch_grab(&self) -> bool { + pub fn grab_type(&self) -> GrabType { match self.start_data { - GrabStartData::Touch(_) => true, - GrabStartData::Pointer(_) => false, + GrabStartData::Pointer(_) => GrabType::Pointer, + GrabStartData::Touch(_) => GrabType::Touch, + GrabStartData::TabletTool { .. } => GrabType::TabletTool, + } + } + + pub fn tool(&self) -> Option<&TabletToolDescriptor> { + if let GrabStartData::TabletTool { tool, .. } = &self.start_data { + Some(tool) + } else { + None } } } @@ -352,7 +476,7 @@ impl PointerGrab for ResizeForkGrab { data: &mut State, handle: &mut PointerInnerHandle<'_, State>, _focus: Option<(PointerFocusTarget, Point)>, - event: &MotionEvent, + event: &PointerMotionEvent, ) { // While the grab is active, no client has pointer focus handle.motion(data, None, event); @@ -377,7 +501,7 @@ impl PointerGrab for ResizeForkGrab { &mut self, data: &mut State, handle: &mut PointerInnerHandle<'_, State>, - event: &ButtonEvent, + event: &PointerButtonEvent, ) { handle.button(data, event); match self.release { @@ -398,7 +522,7 @@ impl PointerGrab for ResizeForkGrab { &mut self, data: &mut State, handle: &mut PointerInnerHandle<'_, State>, - details: AxisFrame, + details: PointerAxisFrame, ) { handle.axis(data, details) } @@ -497,12 +621,17 @@ impl TouchGrab for ResizeForkGrab { data: &mut State, handle: &mut TouchInnerHandle<'_, State>, _focus: Option<(PointerFocusTarget, Point)>, - event: &DownEvent, + event: &TouchDownEvent, ) { handle.down(data, None, event) } - fn up(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>, event: &UpEvent) { + fn up( + &mut self, + data: &mut State, + handle: &mut TouchInnerHandle<'_, State>, + event: &TouchUpEvent, + ) { if event.slot == >::start_data(self).slot { handle.unset_grab(self, data); } @@ -563,3 +692,96 @@ impl TouchGrab for ResizeForkGrab { self.update_location(data, self.last_loc.as_logical(), true); } } + +impl TabletToolGrab for ResizeForkGrab { + fn start_data(&self) -> &TabletToolGrabStartData { + match &self.start_data { + GrabStartData::TabletTool { data, .. } => data, + _ => unreachable!(), + } + } + + fn proximity_out( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + event: &ProximityOutEvent, + ) { + handle.proximity_out(data, event); + handle.unset_grab(self, data, event.serial, event.time, true); + } + + fn motion( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + _focus: Option<(::ToolFocus, Point)>, + event: &TabletMotionEvent, + ) { + handle.motion(data, None, event); + + if self.update_location(data, event.location, false) { + handle.unset_grab(self, data, event.serial, event.time, true); + } + } + + fn down( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + event: &TabletDownEvent, + ) { + handle.down(data, event); + } + + fn up( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + event: &TabletUpEvent, + ) { + handle.up(data, event); + handle.unset_grab(self, data, event.serial, event.time, true); + } + + fn button( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + event: &TabletButtonEvent, + ) { + handle.button(data, event) + } + + fn axis( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + frame: TabletAxisFrame, + ) { + handle.axis(data, frame) + } + + fn frame( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + time: InputTime, + ) { + handle.frame(data, time) + } + + fn unset(&mut self, data: &mut State) { + self.update_location(data, self.last_loc.as_logical(), true); + } + + fn proximity_in( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + focus: Option<(::ToolFocus, Point)>, + event: &ProximityInEvent, + ) { + handle.proximity_in(data, focus, event); + } +} diff --git a/src/shell/layout/tiling/mod.rs b/src/shell/layout/tiling/mod.rs index 2d95cd27..2f694acd 100644 --- a/src/shell/layout/tiling/mod.rs +++ b/src/shell/layout/tiling/mod.rs @@ -67,6 +67,7 @@ use smithay::{ wayland::{compositor::add_blocker, seat::WaylandFocus}, }; use std::{ + cell::Cell, collections::{HashMap, VecDeque}, sync::{Arc, Weak}, time::{Duration, Instant}, @@ -3348,6 +3349,7 @@ impl TilingLayout { output: self.output.downgrade(), left_up_idx: idx, orientation, + last_tablet_location: Cell::new(None), } .into(), (last_geometry.loc @@ -3381,7 +3383,7 @@ impl TilingLayout { let Some(root) = tree.root_node_id() else { if matches!( overview.active_trigger(), - Some(Trigger::Pointer(_) | Trigger::Touch(_)) + Some(Trigger::Pointer(_) | Trigger::Touch(_) | Trigger::Tool(_, _)) ) && location_f64.is_some() { let mut tree = tree.copy_clone(); @@ -3414,7 +3416,7 @@ impl TilingLayout { if matches!( overview.active_trigger(), - Some(Trigger::Pointer(_) | Trigger::Touch(_)) + Some(Trigger::Pointer(_) | Trigger::Touch(_) | Trigger::Tool(_, _)) ) { let non_exclusive_zone = layer_map_for_output(&self.output) .non_exclusive_zone() @@ -4062,8 +4064,11 @@ impl TilingLayout { let draw_groups = overview.0.alpha(); let is_overview = !matches!(overview.0, OverviewMode::None); - let is_mouse_tiling = (matches!(overview.0.trigger(), Some(Trigger::Pointer(_)))) - .then(|| self.last_overview_hover.as_ref().map(|(_, zone)| zone)); + let is_mouse_tiling = (matches!( + overview.0.trigger(), + Some(Trigger::Pointer(_) | Trigger::Tool(_, _)) + )) + .then(|| self.last_overview_hover.as_ref().map(|(_, zone)| zone)); let swap_desc = if let Some(Trigger::KeyboardSwap(_, desc)) = overview.0.trigger() { Some(desc.clone()) } else { @@ -4216,8 +4221,11 @@ impl TilingLayout { }; let draw_groups = overview.0.alpha(); - let is_mouse_tiling = (matches!(overview.0.trigger(), Some(Trigger::Pointer(_)))) - .then(|| self.last_overview_hover.as_ref().map(|(_, zone)| zone)); + let is_mouse_tiling = (matches!( + overview.0.trigger(), + Some(Trigger::Pointer(_) | Trigger::Tool(_, _)) + )) + .then(|| self.last_overview_hover.as_ref().map(|(_, zone)| zone)); let swap_desc = if let Some(Trigger::KeyboardSwap(_, desc)) = overview.0.trigger() { Some(desc.clone()) } else { diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 3fa863d3..b10d9d63 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -32,7 +32,10 @@ use cosmic_settings_config::shortcuts::action::{Direction, FocusDirection, Resiz use cosmic_settings_config::{shortcuts, window_rules::ApplicationException}; use keyframe::{ease, functions::EaseInOutCubic}; use smithay::{ - backend::{input::TouchSlot, renderer::element::RenderElementStates}, + backend::{ + input::{TabletToolDescriptor, TouchSlot}, + renderer::element::RenderElementStates, + }, desktop::{ LayerSurface, PopupKind, WindowSurface, WindowSurfaceType, layer_map_for_output, space::SpaceElement, @@ -46,6 +49,7 @@ use smithay::{ pointer::{ CursorImageStatus, CursorImageSurfaceData, Focus, GrabStartData as PointerGrabStartData, }, + tablet::tool::GrabTrigger as TabletGrabTrigger, }, output::{Output, WeakOutput}, reexports::{ @@ -130,6 +134,7 @@ pub enum Trigger { KeyboardMove(shortcuts::Modifiers), Pointer(u32), Touch(TouchSlot), + Tool(TabletToolDescriptor, TabletGrabTrigger), } #[derive(Debug, Clone)] @@ -1755,7 +1760,7 @@ impl Shell { if let Some(set) = self.workspaces.sets.get_mut(output) { if matches!( self.overview_mode.active_trigger(), - Some(Trigger::Pointer(_) | Trigger::Touch(_)) + Some(Trigger::Pointer(_) | Trigger::Touch(_) | Trigger::Tool(_, _)) ) { set.workspaces[set.active].tiling_layer.cleanup_drag(); } @@ -1806,7 +1811,7 @@ impl Shell { if let Some(set) = self.workspaces.sets.get_mut(output) { if matches!( self.overview_mode.active_trigger(), - Some(Trigger::Pointer(_) | Trigger::Touch(_)) + Some(Trigger::Pointer(_) | Trigger::Touch(_) | Trigger::Tool(_, _)) ) { set.workspaces[set.active].tiling_layer.cleanup_drag(); } @@ -3840,6 +3845,7 @@ impl Shell { let trigger = match &start_data { GrabStartData::Pointer(start_data) => Trigger::Pointer(start_data.button), GrabStartData::Touch(start_data) => Trigger::Touch(start_data.slot), + GrabStartData::TabletTool { tool, data } => Trigger::Tool(tool.clone(), data.trigger), }; let active_hint = if config.cosmic_conf.active_hint { self.theme.cosmic().active_hint as u8 diff --git a/src/shell/zoom.rs b/src/shell/zoom.rs index cfe84f06..b3a795e7 100644 --- a/src/shell/zoom.rs +++ b/src/shell/zoom.rs @@ -11,19 +11,31 @@ use cosmic_comp_config::{ZoomConfig, ZoomMovement}; use cosmic_config::ConfigSet; use keyframe::{ease, functions::Linear}; use smithay::{ - backend::{input::InputTime, renderer::ImportMem}, + backend::{ + input::{InputTime, TabletToolDescriptor}, + renderer::ImportMem, + }, desktop::space::SpaceElement, input::{ Seat, pointer::{ - AxisFrame, ButtonEvent, Focus, GestureHoldBeginEvent, GestureHoldEndEvent, - GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent, - GestureSwipeBeginEvent, GestureSwipeEndEvent, GestureSwipeUpdateEvent, - MotionEvent as PointerMotionEvent, PointerTarget, RelativeMotionEvent, + AxisFrame as PointerAxisFrame, ButtonEvent as PointerButtonEvent, Focus, + GestureHoldBeginEvent, GestureHoldEndEvent, GesturePinchBeginEvent, + GesturePinchEndEvent, GesturePinchUpdateEvent, GestureSwipeBeginEvent, + GestureSwipeEndEvent, GestureSwipeUpdateEvent, MotionEvent as PointerMotionEvent, + PointerTarget, RelativeMotionEvent, + }, + tablet::{ + Tablet, TabletSeatTrait, + tool::{ + AxisFrame as TabletAxisFrame, ButtonEvent as TabletButtonEvent, + DownEvent as TabletDownEvent, MotionEvent as TabletMotionEvent, TabletToolTarget, + UpEvent as TabletUpEvent, + }, }, touch::{ - DownEvent, FrameMarker, MotionEvent as TouchMotionEvent, OrientationEvent, ShapeEvent, - TouchTarget, UpEvent, + DownEvent as TouchDownEvent, FrameMarker, MotionEvent as TouchMotionEvent, + OrientationEvent, ShapeEvent, TouchTarget, UpEvent as TouchUpEvent, }, }, output::Output, @@ -33,6 +45,7 @@ use tracing::error; use crate::{ backend::render::element::AsGlowRenderer, + shell::grabs::GrabType, state::State, utils::{ iced::{IcedElement, IcedRenderElement, Program}, @@ -698,15 +711,27 @@ impl Program for ZoomProgram { ); std::mem::drop(shell); - if grab.is_touch_grab() { - seat.get_touch().unwrap().set_grab(state, grab, serial); - } else { - seat.get_pointer().unwrap().set_grab( + match grab.grab_type() { + GrabType::Touch => { + seat.get_touch().unwrap().set_grab(state, grab, serial) + } + GrabType::Pointer => seat.get_pointer().unwrap().set_grab( state, grab, serial, Focus::Clear, - ); + ), + GrabType::TabletTool => seat + .tablet_seat() + .get_tool(grab.tool().unwrap()) + .unwrap() + .set_grab( + state, + grab, + InputTime::now(), + serial, + Focus::Clear, + ), } } } @@ -785,15 +810,27 @@ impl Program for ZoomProgram { ); std::mem::drop(shell); - if grab.is_touch_grab() { - seat.get_touch().unwrap().set_grab(state, grab, serial); - } else { - seat.get_pointer().unwrap().set_grab( + match grab.grab_type() { + GrabType::Touch => { + seat.get_touch().unwrap().set_grab(state, grab, serial) + } + GrabType::Pointer => seat.get_pointer().unwrap().set_grab( state, grab, serial, Focus::Clear, - ); + ), + GrabType::TabletTool => seat + .tablet_seat() + .get_tool(grab.tool().unwrap()) + .unwrap() + .set_grab( + state, + grab, + InputTime::now(), + serial, + Focus::Clear, + ), } } } @@ -883,14 +920,14 @@ impl PointerTarget for ZoomFocusTarget { } } - fn button(&self, seat: &Seat, data: &mut State, event: &ButtonEvent) { + fn button(&self, seat: &Seat, data: &mut State, event: &PointerButtonEvent) { match self { ZoomFocusTarget::Main(elem) => PointerTarget::button(elem, seat, data, event), ZoomFocusTarget::Menu(elem) => PointerTarget::button(elem, seat, data, event), } } - fn axis(&self, seat: &Seat, data: &mut State, frame: AxisFrame) { + fn axis(&self, seat: &Seat, data: &mut State, frame: PointerAxisFrame) { match self { ZoomFocusTarget::Main(elem) => PointerTarget::axis(elem, seat, data, frame), ZoomFocusTarget::Menu(elem) => PointerTarget::axis(elem, seat, data, frame), @@ -1032,14 +1069,14 @@ impl PointerTarget for ZoomFocusTarget { } impl TouchTarget for ZoomFocusTarget { - fn down(&self, seat: &Seat, data: &mut State, event: &DownEvent) { + fn down(&self, seat: &Seat, data: &mut State, event: &TouchDownEvent) { match self { ZoomFocusTarget::Main(elem) => TouchTarget::down(elem, seat, data, event), ZoomFocusTarget::Menu(elem) => TouchTarget::down(elem, seat, data, event), } } - fn up(&self, seat: &Seat, data: &mut State, event: &UpEvent) { + fn up(&self, seat: &Seat, data: &mut State, event: &TouchUpEvent) { match self { ZoomFocusTarget::Main(elem) => TouchTarget::up(elem, seat, data, event), ZoomFocusTarget::Menu(elem) => TouchTarget::up(elem, seat, data, event), @@ -1089,6 +1126,144 @@ impl TouchTarget for ZoomFocusTarget { } } +impl TabletToolTarget for ZoomFocusTarget { + fn proximity_in( + &self, + seat: &Seat, + data: &mut State, + tool_descriptor: &TabletToolDescriptor, + tablet: &Tablet, + serial: Serial, + ) { + match self { + ZoomFocusTarget::Main(elem) => { + TabletToolTarget::proximity_in(elem, seat, data, tool_descriptor, tablet, serial) + } + ZoomFocusTarget::Menu(elem) => { + TabletToolTarget::proximity_in(elem, seat, data, tool_descriptor, tablet, serial) + } + } + } + + fn proximity_out( + &self, + seat: &Seat, + data: &mut State, + tool_descriptor: &TabletToolDescriptor, + ) { + match self { + ZoomFocusTarget::Main(elem) => { + TabletToolTarget::proximity_out(elem, seat, data, tool_descriptor) + } + ZoomFocusTarget::Menu(elem) => { + TabletToolTarget::proximity_out(elem, seat, data, tool_descriptor) + } + } + } + + fn down( + &self, + seat: &Seat, + data: &mut State, + tool_descriptor: &TabletToolDescriptor, + event: &TabletDownEvent, + ) { + match self { + ZoomFocusTarget::Main(elem) => { + TabletToolTarget::down(elem, seat, data, tool_descriptor, event) + } + ZoomFocusTarget::Menu(elem) => { + TabletToolTarget::down(elem, seat, data, tool_descriptor, event) + } + } + } + + fn up( + &self, + seat: &Seat, + data: &mut State, + tool_descriptor: &TabletToolDescriptor, + event: &TabletUpEvent, + ) { + match self { + ZoomFocusTarget::Main(elem) => { + TabletToolTarget::up(elem, seat, data, tool_descriptor, event) + } + ZoomFocusTarget::Menu(elem) => { + TabletToolTarget::up(elem, seat, data, tool_descriptor, event) + } + } + } + + fn motion( + &self, + seat: &Seat, + data: &mut State, + tool_descriptor: &TabletToolDescriptor, + event: &TabletMotionEvent, + ) { + match self { + ZoomFocusTarget::Main(elem) => { + TabletToolTarget::motion(elem, seat, data, tool_descriptor, event) + } + ZoomFocusTarget::Menu(elem) => { + TabletToolTarget::motion(elem, seat, data, tool_descriptor, event) + } + } + } + + fn axis( + &self, + seat: &Seat, + data: &mut State, + tool_descriptor: &TabletToolDescriptor, + frame: TabletAxisFrame, + ) { + match self { + ZoomFocusTarget::Main(elem) => { + TabletToolTarget::axis(elem, seat, data, tool_descriptor, frame) + } + ZoomFocusTarget::Menu(elem) => { + TabletToolTarget::axis(elem, seat, data, tool_descriptor, frame) + } + } + } + + fn button( + &self, + seat: &Seat, + data: &mut State, + tool_descriptor: &TabletToolDescriptor, + event: &TabletButtonEvent, + ) { + match self { + ZoomFocusTarget::Main(elem) => { + TabletToolTarget::button(elem, seat, data, tool_descriptor, event) + } + ZoomFocusTarget::Menu(elem) => { + TabletToolTarget::button(elem, seat, data, tool_descriptor, event) + } + } + } + + fn frame( + &self, + seat: &Seat, + data: &mut State, + tool_descriptor: &TabletToolDescriptor, + time: InputTime, + ) { + match self { + ZoomFocusTarget::Main(elem) => { + TabletToolTarget::frame(elem, seat, data, tool_descriptor, time) + } + ZoomFocusTarget::Menu(elem) => { + TabletToolTarget::frame(elem, seat, data, tool_descriptor, time) + } + } + } +} + impl IsAlive for ZoomFocusTarget { fn alive(&self) -> bool { match self { diff --git a/src/utils/iced/mod.rs b/src/utils/iced/mod.rs index 94b27ea7..8680bed3 100644 --- a/src/utils/iced/mod.rs +++ b/src/utils/iced/mod.rs @@ -31,7 +31,7 @@ use ordered_float::OrderedFloat; use smithay::{ backend::{ allocator::Fourcc, - input::{ButtonState, InputTime, KeyState}, + input::{ButtonState, InputTime, KeyState, TabletToolDescriptor}, renderer::{ ImportMem, element::{ @@ -45,14 +45,23 @@ use smithay::{ Seat, keyboard::{KeyboardTarget, KeysymHandle, ModifiersState}, pointer::{ - AxisFrame, ButtonEvent, GestureHoldBeginEvent, GestureHoldEndEvent, - GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent, - GestureSwipeBeginEvent, GestureSwipeEndEvent, GestureSwipeUpdateEvent, MotionEvent, + AxisFrame as PointerAxisFrame, ButtonEvent as PointerButtonEvent, + GestureHoldBeginEvent, GestureHoldEndEvent, GesturePinchBeginEvent, + GesturePinchEndEvent, GesturePinchUpdateEvent, GestureSwipeBeginEvent, + GestureSwipeEndEvent, GestureSwipeUpdateEvent, MotionEvent as PointerMotionEvent, PointerTarget, RelativeMotionEvent, }, + tablet::{ + Tablet, + tool::{ + AxisFrame as ToolAxisFrame, ButtonEvent as ToolButtonEvent, + DownEvent as ToolDownEvent, MotionEvent as ToolMotionEvent, TabletToolTarget, + UpEvent as ToolUpEvent, + }, + }, touch::{ - DownEvent, FrameMarker, MotionEvent as TouchMotionEvent, OrientationEvent, ShapeEvent, - TouchTarget, UpEvent, + DownEvent as TouchDownEvent, FrameMarker, MotionEvent as TouchMotionEvent, + OrientationEvent, ShapeEvent, TouchTarget, UpEvent as TouchUpEvent, }, }, output::Output, @@ -189,6 +198,7 @@ pub(crate) struct IcedElementInternal { touch_map: HashMap, last_touch_frame: Option, last_touch_serial: Option, + last_tablet_serial: Option, // iced theme: Theme, @@ -240,6 +250,7 @@ impl Clone for IcedElementInternal

{ touch_map: self.touch_map.clone(), last_touch_frame: None, last_touch_serial: None, + last_tablet_serial: None, theme: self.theme.clone(), renderer, state, @@ -267,6 +278,7 @@ impl fmt::Debug for IcedElementInternal

{ .field("touch_map", &self.touch_map) .field("last_touch_frame", &self.last_touch_frame) .field("last_touch_serial", &self.last_touch_serial) + .field("last_tablet_serial", &self.last_tablet_serial) .field("theme", &"...") .field("renderer", &"...") .field("state", &"...") @@ -326,6 +338,7 @@ impl IcedElement

{ touch_map: HashMap::new(), last_touch_frame: None, last_touch_serial: None, + last_tablet_serial: None, theme, renderer, state, @@ -481,12 +494,141 @@ impl IcedElementInternal

{ } } +impl TabletToolTarget for IcedElement

{ + fn proximity_in( + &self, + _seat: &Seat, + _data: &mut crate::state::State, + _tool_descriptor: &TabletToolDescriptor, + _tablet: &Tablet, + _serial: Serial, + ) { + let mut internal = self.0.lock().unwrap(); + internal + .state + .queue_event(Event::Mouse(MouseEvent::CursorEntered)); + internal.update(false); + } + + fn proximity_out( + &self, + _seat: &Seat, + _data: &mut crate::state::State, + _tool_descriptor: &TabletToolDescriptor, + ) { + let mut internal = self.0.lock().unwrap(); + internal + .state + .queue_event(Event::Mouse(MouseEvent::CursorLeft)); + internal.update(false); + } + + fn down( + &self, + seat: &Seat, + _data: &mut crate::state::State, + _tool_descriptor: &TabletToolDescriptor, + event: &ToolDownEvent, + ) { + let mut internal = self.0.lock().unwrap(); + let id = Finger(0); + let Some(event_location) = internal.cursor_pos else { + return; + }; + let position = IcedPoint::new(event_location.x as f32, event_location.y as f32); + internal + .state + .queue_event(Event::Touch(TouchEvent::FingerPressed { id, position })); + internal.last_tablet_serial = Some(event.serial); + *internal.last_seat.lock().unwrap() = Some((seat.clone(), event.serial)); + internal.update(false); + } + + fn up( + &self, + seat: &Seat, + _data: &mut crate::state::State, + _tool_descriptor: &TabletToolDescriptor, + _event: &ToolUpEvent, + ) { + let mut internal = self.0.lock().unwrap(); + let id = Finger(0); + if let Some(event_location) = internal.cursor_pos { + *internal.last_seat.lock().unwrap() = + Some((seat.clone(), internal.last_tablet_serial.unwrap())); + let position = IcedPoint::new(event_location.x as f32, event_location.y as f32); + internal + .state + .queue_event(Event::Touch(TouchEvent::FingerLifted { id, position })); + internal.update(false); + } + } + + fn motion( + &self, + seat: &Seat, + _data: &mut crate::state::State, + _tool_descriptor: &TabletToolDescriptor, + event: &ToolMotionEvent, + ) { + let mut internal = self.0.lock().unwrap(); + let event_location = event.location.downscale(internal.additional_scale); + let position = IcedPoint::new(event_location.x as f32, event_location.y as f32); + internal + .state + .queue_event(Event::Mouse(MouseEvent::CursorMoved { position })); + internal.cursor_pos = Some(event_location); + *internal.last_seat.lock().unwrap() = Some((seat.clone(), event.serial)); + internal.update(false); + } + + fn axis( + &self, + _seat: &Seat, + _data: &mut crate::state::State, + _tool_descriptor: &TabletToolDescriptor, + _frame: ToolAxisFrame, + ) { + } + + fn button( + &self, + seat: &Seat, + _data: &mut crate::state::State, + _tool_descriptor: &TabletToolDescriptor, + event: &ToolButtonEvent, + ) { + let mut internal = self.0.lock().unwrap(); + let button = match event.button { + 0x110 => MouseButton::Left, + 0x111 => MouseButton::Right, + 0x112 => MouseButton::Middle, + x => MouseButton::Other(x as u16), + }; + internal.state.queue_event(Event::Mouse(match event.state { + ButtonState::Pressed => MouseEvent::ButtonPressed(button), + ButtonState::Released => MouseEvent::ButtonReleased(button), + })); + *internal.last_seat.lock().unwrap() = Some((seat.clone(), event.serial)); + internal.update(false); + } + + fn frame( + &self, + _seat: &Seat, + _data: &mut crate::state::State, + _tool_descriptor: &TabletToolDescriptor, + _time: InputTime, + ) { + } +} + impl PointerTarget for IcedElement

{ fn enter( &self, seat: &Seat, _data: &mut crate::state::State, - event: &MotionEvent, + event: &PointerMotionEvent, ) { let mut internal = self.0.lock().unwrap(); internal @@ -507,7 +649,7 @@ impl PointerTarget for IcedEle &self, seat: &Seat, _data: &mut crate::state::State, - event: &MotionEvent, + event: &PointerMotionEvent, ) { let mut internal = self.0.lock().unwrap(); let event_location = event.location.downscale(internal.additional_scale); @@ -532,7 +674,7 @@ impl PointerTarget for IcedEle &self, seat: &Seat, _data: &mut crate::state::State, - event: &ButtonEvent, + event: &PointerButtonEvent, ) { let mut internal = self.0.lock().unwrap(); let button = match event.button { @@ -553,7 +695,7 @@ impl PointerTarget for IcedEle &self, _seat: &Seat, _data: &mut crate::state::State, - frame: AxisFrame, + frame: PointerAxisFrame, ) { let mut internal = self.0.lock().unwrap(); internal @@ -653,7 +795,7 @@ impl TouchTarget for IcedEleme &self, seat: &Seat, _data: &mut crate::state::State, - event: &DownEvent, + event: &TouchDownEvent, ) { let mut internal = self.0.lock().unwrap(); let id = Finger(i32::from(event.slot) as u64); @@ -673,7 +815,7 @@ impl TouchTarget for IcedEleme &self, seat: &Seat, _data: &mut crate::state::State, - event: &UpEvent, + event: &TouchUpEvent, ) { let mut internal = self.0.lock().unwrap(); let id = Finger(i32::from(event.slot) as u64); diff --git a/src/wayland/handlers/tablet_manager.rs b/src/wayland/handlers/tablet_manager.rs index e4b84434..7cf2b8cb 100644 --- a/src/wayland/handlers/tablet_manager.rs +++ b/src/wayland/handlers/tablet_manager.rs @@ -1,13 +1,13 @@ // SPDX-License-Identifier: GPL-3.0-only -use crate::state::State; +use crate::{shell::focus::target::PointerFocusTarget, state::State}; use smithay::{ backend::input::TabletToolDescriptor, input::pointer::CursorImageStatus, - input::tablet::TabletSeatHandler, reexports::wayland_server::protocol::wl_surface, + input::tablet::TabletSeatHandler, }; impl TabletSeatHandler for State { - type ToolFocus = wl_surface::WlSurface; + type ToolFocus = PointerFocusTarget; fn tablet_tool_image(&mut self, _tool: &TabletToolDescriptor, _image: CursorImageStatus) { // TODO display cursor for each tablet tool diff --git a/src/wayland/handlers/xdg_shell/mod.rs b/src/wayland/handlers/xdg_shell/mod.rs index c9fb926f..be7084dd 100644 --- a/src/wayland/handlers/xdg_shell/mod.rs +++ b/src/wayland/handlers/xdg_shell/mod.rs @@ -1,11 +1,15 @@ // SPDX-License-Identifier: GPL-3.0-only use crate::{ - shell::{CosmicSurface, PendingWindow, focus::target::KeyboardFocusTarget, grabs::ReleaseMode}, + shell::{ + CosmicSurface, PendingWindow, + focus::target::KeyboardFocusTarget, + grabs::{GrabType, ReleaseMode}, + }, utils::prelude::*, }; -use smithay::desktop::layer_map_for_output; use smithay::{ + backend::input::InputTime, desktop::{ PopupGrab, PopupKeyboardGrab, PopupKind, PopupPointerGrab, PopupUngrabStrategy, WindowSurfaceType, find_popup_root_surface, @@ -26,6 +30,7 @@ use smithay::{ }, }, }; +use smithay::{desktop::layer_map_for_output, input::tablet::TabletSeatTrait}; use std::cell::Cell; use tracing::warn; @@ -190,12 +195,17 @@ impl XdgShellHandler for State { true, ) { std::mem::drop(shell); - if grab.is_touch_grab() { - seat.get_touch().unwrap().set_grab(self, grab, serial); - } else { - seat.get_pointer() + match grab.grab_type() { + GrabType::Touch => seat.get_touch().unwrap().set_grab(self, grab, serial), + GrabType::Pointer => seat + .get_pointer() .unwrap() - .set_grab(self, grab, serial, focus) + .set_grab(self, grab, serial, focus), + GrabType::TabletTool => seat + .tablet_seat() + .get_tool(grab.tool().unwrap()) + .unwrap() + .set_grab(self, grab, InputTime::now(), serial, focus), } } } @@ -218,12 +228,17 @@ impl XdgShellHandler for State { true, ) { std::mem::drop(shell); - if grab.is_touch_grab() { - seat.get_touch().unwrap().set_grab(self, grab, serial) - } else { - seat.get_pointer() + match grab.grab_type() { + GrabType::Touch => seat.get_touch().unwrap().set_grab(self, grab, serial), + GrabType::Pointer => seat + .get_pointer() .unwrap() - .set_grab(self, grab, serial, focus) + .set_grab(self, grab, serial, focus), + GrabType::TabletTool => seat + .tablet_seat() + .get_tool(grab.tool().unwrap()) + .unwrap() + .set_grab(self, grab, InputTime::now(), serial, focus), } } } diff --git a/src/xwayland.rs b/src/xwayland.rs index 78193d13..cc6be3b4 100644 --- a/src/xwayland.rs +++ b/src/xwayland.rs @@ -9,7 +9,9 @@ use std::{ use crate::{ backend::render::cursor::{Cursor, load_cursor_env, load_cursor_theme}, shell::{ - CosmicSurface, PendingWindow, Shell, focus::target::KeyboardFocusTarget, grabs::ReleaseMode, + CosmicSurface, PendingWindow, Shell, + focus::target::KeyboardFocusTarget, + grabs::{GrabType, ReleaseMode}, }, state::State, utils::prelude::*, @@ -32,7 +34,7 @@ use smithay::{ }, }, desktop::space::SpaceElement, - input::{keyboard::ModifiersState, pointer::CursorIcon}, + input::{keyboard::ModifiersState, pointer::CursorIcon, tablet::TabletSeatTrait}, reexports::{wayland_server::Client, x11rb::protocol::xproto::Window as X11Window}, utils::{ Buffer as BufferCoords, Logical, Point, Rectangle, SERIAL_COUNTER, Serial, Size, Transform, @@ -1045,17 +1047,29 @@ impl XwmHandler for State { true, ) { std::mem::drop(shell); - if grab.is_touch_grab() { - seat.get_touch() - .unwrap() - .set_grab(self, grab, SERIAL_COUNTER.next_serial()) - } else { - seat.get_pointer().unwrap().set_grab( + match grab.grab_type() { + GrabType::Touch => { + seat.get_touch() + .unwrap() + .set_grab(self, grab, SERIAL_COUNTER.next_serial()) + } + GrabType::Pointer => seat.get_pointer().unwrap().set_grab( self, grab, SERIAL_COUNTER.next_serial(), focus, - ) + ), + GrabType::TabletTool => seat + .tablet_seat() + .get_tool(grab.tool().unwrap()) + .unwrap() + .set_grab( + self, + grab, + InputTime::now(), + SERIAL_COUNTER.next_serial(), + focus, + ), } } } @@ -1076,17 +1090,29 @@ impl XwmHandler for State { true, ) { std::mem::drop(shell); - if grab.is_touch_grab() { - seat.get_touch() - .unwrap() - .set_grab(self, grab, SERIAL_COUNTER.next_serial()) - } else { - seat.get_pointer().unwrap().set_grab( + match grab.grab_type() { + GrabType::Touch => { + seat.get_touch() + .unwrap() + .set_grab(self, grab, SERIAL_COUNTER.next_serial()) + } + GrabType::Pointer => seat.get_pointer().unwrap().set_grab( self, grab, SERIAL_COUNTER.next_serial(), focus, - ) + ), + GrabType::TabletTool => seat + .tablet_seat() + .get_tool(grab.tool().unwrap()) + .unwrap() + .set_grab( + self, + grab, + InputTime::now(), + SERIAL_COUNTER.next_serial(), + focus, + ), } } } From 9125f8a2a73fc87a5697b07b71f54611e099b711 Mon Sep 17 00:00:00 2001 From: Victoria Brekenfeld Date: Tue, 18 Aug 2026 19:12:06 +0200 Subject: [PATCH 15/69] input: Add pointer-emulation grab for tablet tools --- src/input/mod.rs | 100 ++++++++++++--- src/input/tablet_emu.rs | 260 ++++++++++++++++++++++++++++++++++++++ src/shell/focus/target.rs | 14 +- 3 files changed, 351 insertions(+), 23 deletions(-) create mode 100644 src/input/tablet_emu.rs diff --git a/src/input/mod.rs b/src/input/mod.rs index cbf99cae..28877356 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -9,7 +9,10 @@ use crate::{ cosmic_modifiers_from_smithay, }, }, - input::gestures::{GestureState, SwipeAction}, + input::{ + gestures::{GestureState, SwipeAction}, + tablet_emu::PointerEmulationGrab, + }, shell::{ SeatExt, Trigger, focus::{ @@ -52,7 +55,7 @@ use smithay::{ keyboard::KeyboardHandle, keyboard::{FilterResult, KeyboardSource, KeysymHandle, ModifiersState}, pointer::{ - AxisFrame, ButtonEvent as PointerButtonEvent, GestureHoldBeginEvent, + AxisFrame, ButtonEvent as PointerButtonEvent, Focus, GestureHoldBeginEvent, GestureHoldEndEvent, GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent, GestureSwipeBeginEvent, GestureSwipeEndEvent, GestureSwipeUpdateEvent, MotionEvent as PointerMotionEvent, PointerGrab, PointerHandle, @@ -89,6 +92,7 @@ use std::{ pub mod actions; pub mod gestures; +pub mod tablet_emu; /// Identifies the input backend instance an event came from, used to disambiguate device ids /// (which are only unique within a single backend instance, see @@ -1609,6 +1613,26 @@ impl State { let tool = tablet_seat.get_tool(&event.tool()); if let Some(tool) = tool { + let serial = SERIAL_COUNTER.next_serial(); + if !tool.is_grabbed() + && under + .as_ref() + .is_some_and(|(target, _)| !target.supports_tool(&tool)) + { + let start_data = tool::GrabStartData { + focus: under.clone(), + trigger: tool::GrabTrigger::Proximity, + location: position.as_logical(), + }; + tool.set_grab( + self, + PointerEmulationGrab::new(start_data, seat.clone()), + event.time(), + serial, + Focus::Keep, + ); + } + let frame = tool::AxisFrame { pressure: event.pressure_has_changed().then(|| event.pressure()), distance: event.distance_has_changed().then(|| event.distance()), @@ -1629,7 +1653,7 @@ impl State { under, &tool::MotionEvent { location: position.as_logical(), - serial: SERIAL_COUNTER.next_serial(), + serial, time: event.time(), }, ); @@ -1683,6 +1707,25 @@ impl State { if let Some(tablet) = tablet { let serial = SERIAL_COUNTER.next_serial(); + if !tool.is_grabbed() + && under + .as_ref() + .is_some_and(|(target, _)| !target.supports_tool(&tool)) + { + let start_data = tool::GrabStartData { + focus: under.clone(), + trigger: tool::GrabTrigger::Proximity, + location: position.as_logical(), + }; + tool.set_grab( + self, + PointerEmulationGrab::new(start_data, seat.clone()), + event.time(), + serial, + Focus::Keep, + ); + } + let frame = tool::AxisFrame { pressure: event.pressure_has_changed().then(|| event.pressure()), distance: event.distance_has_changed().then(|| event.distance()), @@ -1697,24 +1740,39 @@ impl State { }; match event.state() { - ProximityState::In => tool.proximity_in( - self, - under, - tablet, - &tool::ProximityInEvent { - location: position.as_logical(), - axis: Some(frame), - serial: SERIAL_COUNTER.next_serial(), - time: event.time(), - }, - ), - ProximityState::Out => tool.proximity_out( - self, - &tool::ProximityOutEvent { - serial, - time: event.time(), - }, - ), + ProximityState::In => { + tool.proximity_in( + self, + under, + tablet, + &tool::ProximityInEvent { + location: position.as_logical(), + axis: Some(frame), + serial, + time: event.time(), + }, + ); + } + ProximityState::Out => { + tool.proximity_out( + self, + &tool::ProximityOutEvent { + serial, + time: event.time(), + }, + ); + if let Some(pointer) = seat.get_pointer() { + pointer.motion( + self, + None, + &PointerMotionEvent { + location: position.as_logical(), + serial, + time: event.time(), + }, + ); + } + } } tool.frame(self, event.time()); diff --git a/src/input/tablet_emu.rs b/src/input/tablet_emu.rs new file mode 100644 index 00000000..94d31d89 --- /dev/null +++ b/src/input/tablet_emu.rs @@ -0,0 +1,260 @@ +// SPDX-License-Identifier: GPL-3.0-only + +//! Pointer Emulating TabletTool grab. + +use crate::{shell::focus::target::PointerFocusTarget, state::State}; +use smithay::{ + backend::input::{ButtonState, InputTime, MouseButton}, + input::{ + Seat, pointer, + tablet::{ + self, + tool::{ + AxisFrame, ButtonEvent, DownEvent, GrabStartData, ProximityInEvent, + ProximityOutEvent, TabletToolGrab, TabletToolInnerHandle, UpEvent, + }, + }, + }, + utils::{Logical, Point, SERIAL_COUNTER}, +}; + +// from https://gitlab.freedesktop.org/libinput/libinput/-/blob/main/include/linux/linux/input-event-codes.h +const BTN_STYLUS: u32 = 0x14b; +const BTN_STYLUS_2: u32 = 0x14c; +const BTN_LEFT: u32 = 0x110; +const BTN_RIGHT: u32 = 0x111; +const BTN_MIDDLE: u32 = 0x112; +const BTN_FORWARD: u32 = 0x115; +const BTN_BACK: u32 = 0x116; + +pub struct PointerEmulationGrab { + start_data: GrabStartData, + seat: Seat, + + above_source: bool, + tip_down: bool, + button_down: Vec, +} + +impl PointerEmulationGrab { + pub fn new(start_data: GrabStartData, seat: Seat) -> Self { + Self { + start_data, + seat, + + above_source: true, + tip_down: false, + button_down: Vec::new(), + } + } + + fn button_to_mouse(&self, button: u32) -> Option { + // FIXME: This should be configurable. + if button == BTN_STYLUS { + Some(MouseButton::Right) + } else if button == BTN_STYLUS_2 { + Some(MouseButton::Middle) + } else { + None + } + } + + fn pointer_button(&self, data: &mut State, button: MouseButton, state: ButtonState) { + if let Some(pointer) = self.seat.get_pointer() { + let button = match button { + MouseButton::Left => BTN_LEFT, + MouseButton::Right => BTN_RIGHT, + MouseButton::Middle => BTN_MIDDLE, + MouseButton::Back => BTN_BACK, + MouseButton::Forward => BTN_FORWARD, + _ => return, + }; + + pointer.button( + data, + &pointer::ButtonEvent { + serial: SERIAL_COUNTER.next_serial(), + button, + state, + time: InputTime::now(), + }, + ); + + pointer.frame(data); + } + } +} + +type Type = tablet::tool::MotionEvent; + +impl TabletToolGrab for PointerEmulationGrab { + fn proximity_in( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + focus: Option<(PointerFocusTarget, Point)>, + event: &ProximityInEvent, + ) { + handle.proximity_in(data, focus.clone(), event); + + if !self.above_source && !self.tip_down && self.button_down.is_empty() { + handle.unset_grab( + self, + data, + SERIAL_COUNTER.next_serial(), + InputTime::now(), + true, + ); + } else { + if let Some(pointer) = self.seat.get_pointer() { + pointer.motion( + data, + focus, + &pointer::MotionEvent { + location: event.location, + serial: SERIAL_COUNTER.next_serial(), + time: InputTime::now(), + }, + ); + pointer.frame(data); + } + } + } + + fn proximity_out( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + event: &ProximityOutEvent, + ) { + handle.proximity_out(data, event); + + handle.unset_grab(self, data, event.serial, event.time, true); + } + + fn down( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + event: &DownEvent, + ) { + handle.down(data, event); + self.tip_down = true; + + self.pointer_button(data, MouseButton::Left, ButtonState::Pressed); + } + + fn up( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + event: &UpEvent, + ) { + handle.up(data, event); + + self.pointer_button(data, MouseButton::Left, ButtonState::Released); + self.tip_down = false; + + if !self.above_source && !self.tip_down && self.button_down.is_empty() { + handle.unset_grab(self, data, event.serial, event.time, true); + } + } + + fn motion( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + focus: Option<(PointerFocusTarget, Point)>, + event: &Type, + ) { + self.above_source = focus.as_ref().map(|(target, _)| target) + == self.start_data.focus.as_ref().map(|(target, _)| target); + handle.motion(data, self.start_data.focus.clone(), event); + + if !self.above_source && !self.tip_down && self.button_down.is_empty() { + handle.unset_grab( + self, + data, + SERIAL_COUNTER.next_serial(), + InputTime::now(), + true, + ); + } else { + if let Some(pointer) = self.seat.get_pointer() { + pointer.motion( + data, + focus, + &pointer::MotionEvent { + location: event.location, + serial: SERIAL_COUNTER.next_serial(), + time: InputTime::now(), + }, + ); + pointer.frame(data); + } + } + } + + fn button( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + event: &ButtonEvent, + ) { + handle.button(data, event); + + self.button_down.retain(|b| b != &event.button); + if matches!(event.state, ButtonState::Pressed) { + self.button_down.push(event.button); + } + + if let Some(button) = self.button_to_mouse(event.button) { + self.pointer_button(data, button, event.state); + } + + if !self.above_source && !self.tip_down && self.button_down.is_empty() { + handle.unset_grab( + self, + data, + SERIAL_COUNTER.next_serial(), + InputTime::now(), + true, + ); + } + } + + fn axis( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + frame: AxisFrame, + ) { + handle.axis(data, frame); + } + + fn frame( + &mut self, + data: &mut State, + handle: &mut TabletToolInnerHandle<'_, State>, + time: InputTime, + ) { + handle.frame(data, time); + } + + fn unset(&mut self, data: &mut State) { + if self.tip_down { + self.pointer_button(data, MouseButton::Left, ButtonState::Released); + } + + let buttons = std::mem::take(&mut self.button_down); + for button in buttons.into_iter() { + if let Some(button) = self.button_to_mouse(button) { + self.pointer_button(data, button, ButtonState::Released); + } + } + } + + fn start_data(&self) -> &GrabStartData { + &self.start_data + } +} diff --git a/src/shell/focus/target.rs b/src/shell/focus/target.rs index 6ca13279..c914e0fa 100644 --- a/src/shell/focus/target.rs +++ b/src/shell/focus/target.rs @@ -33,8 +33,8 @@ use smithay::{ Tablet, tool::{ AxisFrame as ToolAxisFrame, ButtonEvent as ToolButtonEvent, - DownEvent as ToolDownEvent, MotionEvent as ToolMotionEvent, TabletToolTarget, - UpEvent as ToolUpEvent, + DownEvent as ToolDownEvent, MotionEvent as ToolMotionEvent, TabletToolHandle, + TabletToolTarget, UpEvent as ToolUpEvent, }, }, touch::{ @@ -306,6 +306,16 @@ impl PointerFocusTarget { session.set_cursor_hotspot(cursor_hotspot); } } + + pub fn supports_tool(&self, tool_handle: &TabletToolHandle) -> bool { + match self { + Self::WlSurface { surface, .. } if surface.client().is_some() => tool_handle + .client_tools(&surface.client().unwrap()) + .next() + .is_some(), + _ => true, + } + } } impl KeyboardFocusTarget { From 67aa6a0c49ae818d10a3662362e9892c1fe9ac89 Mon Sep 17 00:00:00 2001 From: Victoria Brekenfeld Date: Tue, 18 Aug 2026 19:14:28 +0200 Subject: [PATCH 16/69] input: Don't send out pointer events for tool events --- src/input/mod.rs | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/src/input/mod.rs b/src/input/mod.rs index 28877356..8730e66b 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -1598,15 +1598,7 @@ impl State { std::mem::drop(shell); let pointer = seat.get_pointer().unwrap(); - pointer.motion( - self, - under.clone(), - &PointerMotionEvent { - location: position.as_logical(), - serial: SERIAL_COUNTER.next_serial(), - time: InputTime::now(), - }, - ); + pointer.set_location(position.as_logical()); let tablet_seat = seat.tablet_seat(); @@ -1686,15 +1678,7 @@ impl State { std::mem::drop(shell); let pointer = seat.get_pointer().unwrap(); - pointer.motion( - self, - under.clone(), - &PointerMotionEvent { - location: position.as_logical(), - serial: SERIAL_COUNTER.next_serial(), - time: InputTime::now(), - }, - ); + pointer.set_location(position.as_logical()); let tablet_seat = seat.tablet_seat(); From a66f629a4e59c8b2c2a17163bdca126a8dd12666 Mon Sep 17 00:00:00 2001 From: Victoria Brekenfeld Date: Tue, 18 Aug 2026 19:15:03 +0200 Subject: [PATCH 17/69] input: Make sure to update internal pointer position state on tool input --- src/input/mod.rs | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/input/mod.rs b/src/input/mod.rs index 8730e66b..fe210612 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -1590,6 +1590,7 @@ impl State { return; }; + let current_output = seat.active_output(); let position = transform_output_mapped_position(&output, &event, shell.zoom_state()); let under = State::surface_under(position, &output, &shell) @@ -1652,6 +1653,29 @@ impl State { tool.frame(self, event.time()); } + + let mut shell = self.common.shell.write(); + shell.update_pointer_position(position.to_local(&output), &output); + shell.update_focal_point( + &seat, + position, + self.common.config.cosmic_conf.accessibility_zoom.view_moves, + ); + + if output != current_output { + for session in cursor_sessions_for_output(&shell, ¤t_output) { + session.set_cursor_pos(None); + } + seat.set_active_output(&output); + } + + update_output_image_copy_cursor_position( + &shell, + &self.common.clock, + &output, + &seat, + position, + ); } } InputEvent::TabletToolProximity { event, .. } => { @@ -1670,6 +1694,7 @@ impl State { return; }; + let current_output = seat.active_output(); let position = transform_output_mapped_position(&output, &event, shell.zoom_state()); let under = State::surface_under(position, &output, &shell) @@ -1761,6 +1786,29 @@ impl State { tool.frame(self, event.time()); } + + let mut shell = self.common.shell.write(); + shell.update_pointer_position(position.to_local(&output), &output); + shell.update_focal_point( + &seat, + position, + self.common.config.cosmic_conf.accessibility_zoom.view_moves, + ); + + if output != current_output { + for session in cursor_sessions_for_output(&shell, ¤t_output) { + session.set_cursor_pos(None); + } + seat.set_active_output(&output); + } + + update_output_image_copy_cursor_position( + &shell, + &self.common.clock, + &output, + &seat, + position, + ); } } InputEvent::TabletToolTip { event, .. } => { From 85564f033699e6371600da552a7ee0e889d8114e Mon Sep 17 00:00:00 2001 From: Victoria Brekenfeld Date: Tue, 18 Aug 2026 19:15:27 +0200 Subject: [PATCH 18/69] input: Focus on tool tip down --- src/input/mod.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/input/mod.rs b/src/input/mod.rs index fe210612..11466266 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -1834,6 +1834,21 @@ impl State { if let Some(seat) = maybe_seat { self.common.idle_notifier_state.notify_activity(&seat); notify_cursor_activity(self, &seat); + + let serial = SERIAL_COUNTER.next_serial(); + let output = seat.active_output(); + let shell = self.common.shell.write(); + let position = + transform_output_mapped_position(&output, &event, shell.zoom_state()); + let under = State::element_under(position, &output, &shell, &seat); + drop(shell); + + if event.tip_state() == TabletToolTipState::Down + && let Some(target) = under.as_ref() + { + Shell::set_focus(self, Some(target), &seat, Some(serial), false); + } + if let Some(tool) = seat.tablet_seat().get_tool(&event.tool()) { let serial = SERIAL_COUNTER.next_serial(); match event.tip_state() { From e65f6608a46f5c8b1250623a9542c2a5214ed285 Mon Sep 17 00:00:00 2001 From: Victoria Brekenfeld Date: Tue, 18 Aug 2026 19:16:23 +0200 Subject: [PATCH 19/69] element: Remove unnecessary grab variants --- src/shell/element/stack.rs | 30 ++++++------------------------ src/shell/element/window.rs | 15 +++------------ 2 files changed, 9 insertions(+), 36 deletions(-) diff --git a/src/shell/element/stack.rs b/src/shell/element/stack.rs index 34e6f876..17397153 100644 --- a/src/shell/element/stack.rs +++ b/src/shell/element/stack.rs @@ -1723,19 +1723,10 @@ impl PointerTarget for CosmicStack { false, ); if let Some((grab, focus)) = res { - match grab.grab_type() { - GrabType::Touch => { - seat.get_touch().unwrap().set_grab(state, grab, serial) - } - GrabType::Pointer => seat - .get_pointer() + if let GrabType::Pointer = grab.grab_type() { + seat.get_pointer() .unwrap() - .set_grab(state, grab, serial, focus), - GrabType::TabletTool => seat - .tablet_seat() - .get_tool(grab.tool().unwrap()) - .unwrap() - .set_grab(state, grab, InputTime::now(), serial, focus), + .set_grab(state, grab, serial, focus); } } }); @@ -1793,19 +1784,10 @@ impl PointerTarget for CosmicStack { false, ); if let Some((grab, focus)) = res { - match grab.grab_type() { - GrabType::Touch => { - seat.get_touch().unwrap().set_grab(state, grab, serial) - } - GrabType::Pointer => seat - .get_pointer() + if let GrabType::Pointer = grab.grab_type() { + seat.get_pointer() .unwrap() - .set_grab(state, grab, serial, focus), - GrabType::TabletTool => seat - .tablet_seat() - .get_tool(grab.tool().unwrap()) - .unwrap() - .set_grab(state, grab, InputTime::now(), serial, focus), + .set_grab(state, grab, serial, focus); } } }); diff --git a/src/shell/element/window.rs b/src/shell/element/window.rs index 846d9da4..903a2c05 100644 --- a/src/shell/element/window.rs +++ b/src/shell/element/window.rs @@ -1114,19 +1114,10 @@ impl PointerTarget for CosmicWindow { ); if let Some((grab, focus)) = res { - match grab.grab_type() { - GrabType::Touch => { - seat.get_touch().unwrap().set_grab(state, grab, serial) - } - GrabType::Pointer => seat - .get_pointer() + if let GrabType::Pointer = grab.grab_type() { + seat.get_pointer() .unwrap() - .set_grab(state, grab, serial, focus), - GrabType::TabletTool => seat - .tablet_seat() - .get_tool(grab.tool().unwrap()) - .unwrap() - .set_grab(state, grab, InputTime::now(), serial, focus), + .set_grab(state, grab, serial, focus) } } }); From b8824128a041ebbf7ceaf660f9a86756cfb4052f Mon Sep 17 00:00:00 2001 From: Victoria Brekenfeld Date: Tue, 18 Aug 2026 19:17:27 +0200 Subject: [PATCH 20/69] element: Add cursor shape and resize handling on tool input --- src/shell/element/stack.rs | 77 +++++++++++++++++++++++++++++++++++-- src/shell/element/window.rs | 74 +++++++++++++++++++++++++++++++++-- 2 files changed, 144 insertions(+), 7 deletions(-) diff --git a/src/shell/element/stack.rs b/src/shell/element/stack.rs index 17397153..5ab022d9 100644 --- a/src/shell/element/stack.rs +++ b/src/shell/element/stack.rs @@ -1938,7 +1938,17 @@ impl TabletToolTarget for CosmicStack { data: &mut State, tool_descriptor: &TabletToolDescriptor, ) { - TabletToolTarget::proximity_out(&self.0, seat, data, tool_descriptor) + self.0.with_program(|p| { + let mut cursor_state = seat + .user_data() + .get::() + .unwrap() + .lock() + .unwrap(); + cursor_state.unset_shape(); + let _previous = p.swap_focus(None); + }); + TabletToolTarget::proximity_out(&self.0, seat, data, tool_descriptor); } fn down( @@ -1948,7 +1958,50 @@ impl TabletToolTarget for CosmicStack { tool_descriptor: &TabletToolDescriptor, event: &ToolDownEvent, ) { - TabletToolTarget::down(&self.0, seat, data, tool_descriptor, event) + match self.0.with_program(|p| p.current_focus()) { + Some(Focus::Header) => { + TabletToolTarget::down(&self.0, seat, data, tool_descriptor, event) + } + Some(x) => { + let serial = event.serial; + let seat = seat.clone(); + let Some(surface) = self.0.with_program(|p| { + let window = &p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)]; + window.wl_surface().map(Cow::into_owned) + }) else { + return; + }; + self.0.loop_handle().insert_idle(move |state| { + let res = state.common.shell.write().resize_request( + &surface, + &seat, + serial, + match x { + Focus::ResizeTop => ResizeEdge::TOP, + Focus::ResizeTopLeft => ResizeEdge::TOP_LEFT, + Focus::ResizeTopRight => ResizeEdge::TOP_RIGHT, + Focus::ResizeBottom => ResizeEdge::BOTTOM, + Focus::ResizeBottomLeft => ResizeEdge::BOTTOM_LEFT, + Focus::ResizeBottomRight => ResizeEdge::BOTTOM_RIGHT, + Focus::ResizeLeft => ResizeEdge::LEFT, + Focus::ResizeRight => ResizeEdge::RIGHT, + Focus::Header => unreachable!(), + }, + state.common.config.cosmic_conf.edge_snap_threshold, + false, + ); + if let Some((grab, focus)) = res { + if let GrabType::TabletTool = grab.grab_type() { + seat.tablet_seat() + .get_tool(grab.tool().unwrap()) + .unwrap() + .set_grab(state, grab, InputTime::now(), serial, focus); + } + } + }); + } + None => {} + } } fn up( @@ -1969,12 +2022,30 @@ impl TabletToolTarget for CosmicStack { event: &ToolMotionEvent, ) { let mut event = event.clone(); + self.0.with_program(|p| { + let active = p.active.load(Ordering::SeqCst); + let active_window = &p.windows.lock().unwrap()[active]; + let Some(next) = Focus::under(active_window, TAB_HEIGHT, event.location) else { + return; + }; + let _previous = p.swap_focus(Some(next)); + + let mut cursor_state = seat + .user_data() + .get::() + .unwrap() + .lock() + .unwrap(); + cursor_state.set_shape(next.cursor_shape()); + seat.set_cursor_image_status(CursorImageStatus::default_named()); + }); + let active_window_geo = self.0.with_program(|p| { p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)].geometry() }); event.location -= active_window_geo.loc.to_f64(); - TabletToolTarget::motion(&self.0, seat, data, tool_descriptor, &event); + TabletToolTarget::motion(&self.0, seat, data, tool_descriptor, &event); if event.location.y < 0.0 || event.location.y > TAB_HEIGHT as f64 || event.location.x < 64.0 diff --git a/src/shell/element/window.rs b/src/shell/element/window.rs index 903a2c05..6488ffa3 100644 --- a/src/shell/element/window.rs +++ b/src/shell/element/window.rs @@ -1032,8 +1032,7 @@ impl PointerTarget for CosmicWindow { return; }; - let old_focus = p.swap_focus(Some(next)); - assert_eq!(old_focus, None); + let _ = p.swap_focus(Some(next)); let cursor_state = seat.user_data().get::().unwrap(); cursor_state.lock().unwrap().set_shape(next.cursor_shape()); @@ -1270,6 +1269,11 @@ impl TabletToolTarget for CosmicWindow { data: &mut State, tool_descriptor: &TabletToolDescriptor, ) { + self.0.with_program(|p| { + let cursor_state = seat.user_data().get::().unwrap(); + cursor_state.lock().unwrap().unset_shape(); + let _previous = p.swap_focus(None); + }); TabletToolTarget::proximity_out(&self.0, seat, data, tool_descriptor) } @@ -1280,7 +1284,49 @@ impl TabletToolTarget for CosmicWindow { tool_descriptor: &TabletToolDescriptor, event: &ToolDownEvent, ) { - TabletToolTarget::down(&self.0, seat, data, tool_descriptor, event) + match self.0.with_program(|p| p.current_focus()) { + Some(Focus::Header) => { + TabletToolTarget::down(&self.0, seat, data, tool_descriptor, event) + } + Some(x) => { + let serial = event.serial; + let seat = seat.clone(); + let Some(surface) = self.wl_surface().map(Cow::into_owned) else { + return; + }; + + self.0.loop_handle().insert_idle(move |state| { + let res = state.common.shell.write().resize_request( + &surface, + &seat, + serial, + match x { + Focus::ResizeTop => ResizeEdge::TOP, + Focus::ResizeTopLeft => ResizeEdge::TOP_LEFT, + Focus::ResizeTopRight => ResizeEdge::TOP_RIGHT, + Focus::ResizeBottom => ResizeEdge::BOTTOM, + Focus::ResizeBottomLeft => ResizeEdge::BOTTOM_LEFT, + Focus::ResizeBottomRight => ResizeEdge::BOTTOM_RIGHT, + Focus::ResizeLeft => ResizeEdge::LEFT, + Focus::ResizeRight => ResizeEdge::RIGHT, + Focus::Header => unreachable!(), + }, + state.common.config.cosmic_conf.edge_snap_threshold, + false, + ); + + if let Some((grab, focus)) = res { + if let GrabType::TabletTool = grab.grab_type() { + seat.tablet_seat() + .get_tool(grab.tool().unwrap()) + .unwrap() + .set_grab(state, grab, InputTime::now(), serial, focus) + } + } + }); + } + None => {} + } } fn up( @@ -1300,7 +1346,27 @@ impl TabletToolTarget for CosmicWindow { tool_descriptor: &TabletToolDescriptor, event: &ToolMotionEvent, ) { - TabletToolTarget::motion(&self.0, seat, data, tool_descriptor, event) + let mut event = event.clone(); + self.0.with_program(|p| { + let has_ssd = p.has_ssd(false); + if has_ssd || p.has_tiled_state() { + let Some(next) = Focus::under( + &p.window, + if has_ssd { SSD_HEIGHT } else { 0 }, + event.location, + ) else { + return; + }; + let _previous = p.swap_focus(Some(next)); + + let cursor_state = seat.user_data().get::().unwrap(); + cursor_state.lock().unwrap().set_shape(next.cursor_shape()); + seat.set_cursor_image_status(CursorImageStatus::default_named()); + } + }); + + event.location -= self.0.with_program(|p| p.window.geometry().loc.to_f64()); + TabletToolTarget::motion(&self.0, seat, data, tool_descriptor, &event) } fn axis( From f00ff834c96f8154dbe11f983afc93b8b7d71c8d Mon Sep 17 00:00:00 2001 From: Victoria Brekenfeld Date: Tue, 18 Aug 2026 19:18:16 +0200 Subject: [PATCH 21/69] resize/tiling: Fix location for tablet tools --- src/shell/layout/tiling/grabs/resize.rs | 17 +++++------------ src/shell/layout/tiling/mod.rs | 2 -- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/src/shell/layout/tiling/grabs/resize.rs b/src/shell/layout/tiling/grabs/resize.rs index b6452168..6bb24929 100644 --- a/src/shell/layout/tiling/grabs/resize.rs +++ b/src/shell/layout/tiling/grabs/resize.rs @@ -1,7 +1,5 @@ // SPDX-License-Identifier: GPL-3.0-only -use std::cell::Cell; - use crate::{ backend::render::cursor::CursorState, shell::{ @@ -52,7 +50,6 @@ pub struct ResizeForkTarget { pub output: WeakOutput, pub left_up_idx: usize, pub orientation: Orientation, - pub last_tablet_location: Cell>>, } impl IsAlive for ResizeForkTarget { @@ -193,10 +190,9 @@ impl TabletToolTarget for ResizeForkTarget { let serial = event.serial; let time = event.time; let tool = tool_descriptor.clone(); - let Some(location) = self.last_tablet_location.take() else { - return; - }; data.common.event_loop_handle.insert_idle(move |state| { + let pointer = seat.get_pointer().unwrap(); + let location = pointer.current_location(); let tablet = seat.tablet_seat().get_tool(&tool).unwrap(); tablet.set_grab( state, @@ -205,11 +201,11 @@ impl TabletToolTarget for ResizeForkTarget { tool, data: TabletToolGrabStartData { focus: None, - location: location.as_logical(), + location: location, trigger: TabletToolGrabTrigger::Tip, }, }, - location, + location.as_global(), node, left_up_idx, orientation, @@ -227,10 +223,8 @@ impl TabletToolTarget for ResizeForkTarget { _seat: &Seat, _data: &mut State, _tool_descriptor: &TabletToolDescriptor, - event: &TabletMotionEvent, + _event: &TabletMotionEvent, ) { - self.last_tablet_location - .set(Some(event.location.as_global())) } fn proximity_out( &self, @@ -238,7 +232,6 @@ impl TabletToolTarget for ResizeForkTarget { _data: &mut State, _tool_descriptor: &TabletToolDescriptor, ) { - self.last_tablet_location.set(None); } fn proximity_in( diff --git a/src/shell/layout/tiling/mod.rs b/src/shell/layout/tiling/mod.rs index 2f694acd..8706dc59 100644 --- a/src/shell/layout/tiling/mod.rs +++ b/src/shell/layout/tiling/mod.rs @@ -67,7 +67,6 @@ use smithay::{ wayland::{compositor::add_blocker, seat::WaylandFocus}, }; use std::{ - cell::Cell, collections::{HashMap, VecDeque}, sync::{Arc, Weak}, time::{Duration, Instant}, @@ -3349,7 +3348,6 @@ impl TilingLayout { output: self.output.downgrade(), left_up_idx: idx, orientation, - last_tablet_location: Cell::new(None), } .into(), (last_geometry.loc From 87d73dbce32f9571b458f0934f40bff12eb665f5 Mon Sep 17 00:00:00 2001 From: Victoria Brekenfeld Date: Tue, 18 Aug 2026 19:23:22 +0200 Subject: [PATCH 22/69] resize/tiling: Set cursor icons on tool input --- src/shell/layout/tiling/grabs/resize.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/shell/layout/tiling/grabs/resize.rs b/src/shell/layout/tiling/grabs/resize.rs index 6bb24929..850545be 100644 --- a/src/shell/layout/tiling/grabs/resize.rs +++ b/src/shell/layout/tiling/grabs/resize.rs @@ -228,20 +228,32 @@ impl TabletToolTarget for ResizeForkTarget { } fn proximity_out( &self, - _seat: &Seat, + seat: &Seat, _data: &mut State, _tool_descriptor: &TabletToolDescriptor, ) { + let user_data = seat.user_data(); + let cursor_state = user_data.get::().unwrap(); + cursor_state.lock().unwrap().unset_shape(); } fn proximity_in( &self, - _seat: &Seat, + seat: &Seat, _data: &mut State, _tool_descriptor: &TabletToolDescriptor, _tablet: &Tablet, _serial: Serial, ) { + let user_data = seat.user_data(); + let cursor_state = user_data.get::().unwrap(); + cursor_state + .lock() + .unwrap() + .set_shape(match self.orientation { + Orientation::Horizontal => CursorIcon::RowResize, + Orientation::Vertical => CursorIcon::ColResize, + }); } fn up( &self, From bb95a57f5a59f594603cd62ba2df43f3ce713a95 Mon Sep 17 00:00:00 2001 From: Victoria Brekenfeld Date: Tue, 18 Aug 2026 19:24:02 +0200 Subject: [PATCH 23/69] move: Make sure to always unset tool grab --- src/shell/grabs/moving.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/shell/grabs/moving.rs b/src/shell/grabs/moving.rs index 15225212..50fc9740 100644 --- a/src/shell/grabs/moving.rs +++ b/src/shell/grabs/moving.rs @@ -745,6 +745,7 @@ impl TabletToolGrab for MoveGrab { event: &ProximityOutEvent, ) { handle.proximity_out(data, event); + handle.unset_grab(self, data, event.serial, event.time, false); } fn motion( @@ -777,11 +778,8 @@ impl TabletToolGrab for MoveGrab { handle: &mut TabletToolInnerHandle<'_, State>, event: &TabletUpEvent, ) { - if self.tool().is_some_and(|tool| tool == handle.descriptor()) { - handle.unset_grab(self, data, event.serial, event.time, false); - } - handle.up(data, event); + handle.unset_grab(self, data, event.serial, event.time, false); } fn button( From 6bf75e1c1006b4be39e473883385e5a9273862dc Mon Sep 17 00:00:00 2001 From: Victoria Brekenfeld Date: Tue, 18 Aug 2026 19:24:27 +0200 Subject: [PATCH 24/69] shell: Handle Tablet grabs --- src/shell/mod.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/shell/mod.rs b/src/shell/mod.rs index b10d9d63..5bccf797 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -49,7 +49,7 @@ use smithay::{ pointer::{ CursorImageStatus, CursorImageSurfaceData, Focus, GrabStartData as PointerGrabStartData, }, - tablet::tool::GrabTrigger as TabletGrabTrigger, + tablet::{TabletSeatTrait, tool::GrabTrigger as TabletGrabTrigger}, }, output::{Output, WeakOutput}, reexports::{ @@ -5164,10 +5164,19 @@ pub fn check_grab_preconditions( let pointer = seat.get_pointer().unwrap(); let touch = seat.get_touch().unwrap(); + let tablet = seat.tablet_seat(); + let tools = tablet.get_tools(); let start_data = if serial.is_some_and(|serial| touch.has_grab(serial)) { GrabStartData::Touch(touch.grab_start_data().unwrap()) + } else if let Some((desc, tool)) = + serial.and_then(|serial| tools.iter().find(|(_, tool)| tool.has_grab(serial))) + { + GrabStartData::TabletTool { + tool: desc.clone(), + data: tool.grab_start_data().unwrap(), + } } else { GrabStartData::Pointer(pointer.grab_start_data().unwrap_or_else(|| { PointerGrabStartData { From 0e15b14ab29f75da8023efe85a0e5b1e4a293af7 Mon Sep 17 00:00:00 2001 From: Victoria Brekenfeld Date: Tue, 18 Aug 2026 19:24:54 +0200 Subject: [PATCH 25/69] utils/iced: Fix tablet serials and buttons --- src/utils/iced/mod.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/utils/iced/mod.rs b/src/utils/iced/mod.rs index 8680bed3..4522644b 100644 --- a/src/utils/iced/mod.rs +++ b/src/utils/iced/mod.rs @@ -497,16 +497,18 @@ impl IcedElementInternal

{ impl TabletToolTarget for IcedElement

{ fn proximity_in( &self, - _seat: &Seat, + seat: &Seat, _data: &mut crate::state::State, _tool_descriptor: &TabletToolDescriptor, _tablet: &Tablet, - _serial: Serial, + serial: Serial, ) { let mut internal = self.0.lock().unwrap(); internal .state .queue_event(Event::Mouse(MouseEvent::CursorEntered)); + internal.last_tablet_serial = Some(serial); + *internal.last_seat.lock().unwrap() = Some((seat.clone(), serial)); internal.update(false); } @@ -578,7 +580,8 @@ impl TabletToolTarget for Iced .state .queue_event(Event::Mouse(MouseEvent::CursorMoved { position })); internal.cursor_pos = Some(event_location); - *internal.last_seat.lock().unwrap() = Some((seat.clone(), event.serial)); + *internal.last_seat.lock().unwrap() = + Some((seat.clone(), internal.last_tablet_serial.unwrap())); internal.update(false); } @@ -600,10 +603,9 @@ impl TabletToolTarget for Iced ) { let mut internal = self.0.lock().unwrap(); let button = match event.button { - 0x110 => MouseButton::Left, - 0x111 => MouseButton::Right, - 0x112 => MouseButton::Middle, - x => MouseButton::Other(x as u16), + 0x14b => MouseButton::Right, + 0x14c => MouseButton::Middle, + _ => return, }; internal.state.queue_event(Event::Mouse(match event.state { ButtonState::Pressed => MouseEvent::ButtonPressed(button), From 2a3b4dca5f0569b01e2daa52e928def4949eeb25 Mon Sep 17 00:00:00 2001 From: Victoria Brekenfeld Date: Wed, 19 Aug 2026 17:24:04 +0200 Subject: [PATCH 26/69] shell: fix client initiated tablet grabs --- src/shell/mod.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 5bccf797..47d78851 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -5190,8 +5190,16 @@ pub fn check_grab_preconditions( if let Some(surface) = client_initiated { // Check that this surface has a click or touch down grab. if !match serial { - Some(serial) => pointer.has_grab(serial) || touch.has_grab(serial), - None => pointer.is_grabbed() | touch.is_grabbed(), + Some(serial) => { + pointer.has_grab(serial) + || touch.has_grab(serial) + || tools.values().any(|tool| tool.has_grab(serial)) + } + None => { + pointer.is_grabbed() + || touch.is_grabbed() + || tools.values().any(|tool| tool.is_grabbed()) + } } { return None; } From e563dc85bf28f927db0241c1dc83fd4afce233b2 Mon Sep 17 00:00:00 2001 From: Victoria Brekenfeld Date: Wed, 19 Aug 2026 18:07:37 +0200 Subject: [PATCH 27/69] input: Don't update pointer position on proximity_out --- src/input/mod.rs | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/src/input/mod.rs b/src/input/mod.rs index 11466266..76d2c355 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -1787,28 +1787,30 @@ impl State { tool.frame(self, event.time()); } - let mut shell = self.common.shell.write(); - shell.update_pointer_position(position.to_local(&output), &output); - shell.update_focal_point( - &seat, - position, - self.common.config.cosmic_conf.accessibility_zoom.view_moves, - ); + if event.state() == ProximityState::In { + let mut shell = self.common.shell.write(); + shell.update_pointer_position(position.to_local(&output), &output); + shell.update_focal_point( + &seat, + position, + self.common.config.cosmic_conf.accessibility_zoom.view_moves, + ); - if output != current_output { - for session in cursor_sessions_for_output(&shell, ¤t_output) { - session.set_cursor_pos(None); + if output != current_output { + for session in cursor_sessions_for_output(&shell, ¤t_output) { + session.set_cursor_pos(None); + } + seat.set_active_output(&output); } - seat.set_active_output(&output); - } - update_output_image_copy_cursor_position( - &shell, - &self.common.clock, - &output, - &seat, - position, - ); + update_output_image_copy_cursor_position( + &shell, + &self.common.clock, + &output, + &seat, + position, + ); + } } } InputEvent::TabletToolTip { event, .. } => { From 1c8a0070c023d41326fe8cc8b9367231446492bc Mon Sep 17 00:00:00 2001 From: Victoria Brekenfeld Date: Wed, 19 Aug 2026 18:07:58 +0200 Subject: [PATCH 28/69] element/stack: Handle touch (and tablet) inputs on tabs --- src/shell/element/stack/tab.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/shell/element/stack/tab.rs b/src/shell/element/stack/tab.rs index f8fda525..4b2a3292 100644 --- a/src/shell/element/stack/tab.rs +++ b/src/shell/element/stack/tab.rs @@ -8,6 +8,7 @@ use cosmic::{ layout::{Layout, Limits, Node}, mouse, overlay, renderer, text::{Ellipsize, EllipsizeHeightLimit, Shaping, Wrapping}, + touch, widget::{Id, Widget, operation::Operation, tree::Tree}, }, widget::{self, container::draw_background, rule::FillMode, scrollable::AbsoluteOffset}, @@ -377,6 +378,7 @@ where if matches!( event, event::Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) + | event::Event::Touch(touch::Event::FingerPressed { .. }) ) && let Some(message) = self.press_message.clone() { shell.publish(message); @@ -395,6 +397,7 @@ where if matches!( event, event::Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left)) + | event::Event::Touch(touch::Event::FingerLifted { .. }) ) { shell.publish(Message::activate(self.idx)); shell.capture_event(); From bd0b83412890ec4e126e01c92cfbc87e6e2e78cd Mon Sep 17 00:00:00 2001 From: Victoria Brekenfeld Date: Wed, 19 Aug 2026 18:08:21 +0200 Subject: [PATCH 29/69] element/stack: Use correct serial for tablet grabs --- src/shell/element/stack.rs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/shell/element/stack.rs b/src/shell/element/stack.rs index 5ab022d9..a97f5778 100644 --- a/src/shell/element/stack.rs +++ b/src/shell/element/stack.rs @@ -121,6 +121,7 @@ pub struct CosmicStackInternal { previous_keyboard: AtomicUsize, pointer_entered: AtomicU8, touch_serial: AtomicU32, + tablet_serial: AtomicU32, reenter: AtomicBool, potential_drag: Mutex>, override_alive: AtomicBool, @@ -180,6 +181,7 @@ impl CosmicStack { previous_keyboard: AtomicUsize::new(0), pointer_entered: AtomicU8::new(0), touch_serial: AtomicU32::new(0), + tablet_serial: AtomicU32::new(0), reenter: AtomicBool::new(false), potential_drag: Mutex::new(None), override_alive: AtomicBool::new(true), @@ -1958,12 +1960,19 @@ impl TabletToolTarget for CosmicStack { tool_descriptor: &TabletToolDescriptor, event: &ToolDownEvent, ) { + self.0.with_program(|p| { + p.tablet_serial + .store(event.serial.into(), Ordering::Release) + }); match self.0.with_program(|p| p.current_focus()) { Some(Focus::Header) => { TabletToolTarget::down(&self.0, seat, data, tool_descriptor, event) } Some(x) => { - let serial = event.serial; + let serial = self + .0 + .with_program(|p| p.tablet_serial.load(Ordering::Acquire)) + .into(); let seat = seat.clone(); let Some(surface) = self.0.with_program(|p| { let window = &p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)]; @@ -2051,7 +2060,13 @@ impl TabletToolTarget for CosmicStack { || event.location.x < 64.0 || event.location.x > (active_window_geo.size.w as f64 - 64.0) { - self.start_drag(data, seat, event.serial); + self.start_drag( + data, + seat, + self.0 + .with_program(|p| p.tablet_serial.load(Ordering::Acquire)) + .into(), + ); } } From f8344126a16e7f8712fa123076fc34c9238493a7 Mon Sep 17 00:00:00 2001 From: Victoria Brekenfeld Date: Wed, 19 Aug 2026 18:12:11 +0200 Subject: [PATCH 30/69] input: Update the pointer state on absolute pointer events as well --- src/input/mod.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/input/mod.rs b/src/input/mod.rs index 76d2c355..45586b03 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -767,15 +767,25 @@ impl State { ); ptr.frame(self); + let mut shell = self.common.shell.write(); // Keep the seat's active output following the pointer. Click-to- // focus (PointerButton) resolves its target via // `seat.active_output()` let previous_output = seat.active_output(); if previous_output != output { + for session in cursor_sessions_for_output(&shell, &previous_output) { + session.set_cursor_pos(None); + } seat.set_active_output(&output); } - let shell = self.common.shell.read(); + shell.update_pointer_position(position.to_local(&output), &output); + shell.update_focal_point( + &seat, + position, + self.common.config.cosmic_conf.accessibility_zoom.view_moves, + ); + update_output_image_copy_cursor_position( &shell, &self.common.clock, From e8caf335b39a53c0193de005ef913258bcaaac03 Mon Sep 17 00:00:00 2001 From: Hojjat Date: Thu, 3 Sep 2026 11:50:50 -0600 Subject: [PATCH 31/69] refactor: align the corner radii order with the theme It's [TL, TR, BR, BL] everywhere now --- src/backend/render/mod.rs | 4 +-- src/backend/render/shadow.rs | 6 ---- src/backend/render/wayland/blur_effect.rs | 4 +-- src/backend/render/wayland/clipped_surface.rs | 10 +++---- src/shell/element/stack.rs | 8 +++--- src/shell/element/window.rs | 28 +++++++++---------- 6 files changed, 27 insertions(+), 33 deletions(-) diff --git a/src/backend/render/mod.rs b/src/backend/render/mod.rs index b348640f..1be5b9d4 100644 --- a/src/backend/render/mod.rs +++ b/src/backend/render/mod.rs @@ -286,10 +286,10 @@ impl IndicatorShader { Uniform::new( "radius", [ - outer_radius[3] as f32, - outer_radius[1] as f32, outer_radius[0] as f32, + outer_radius[1] as f32, outer_radius[2] as f32, + outer_radius[3] as f32, ], ), Uniform::new("scale", scale as f32), diff --git a/src/backend/render/shadow.rs b/src/backend/render/shadow.rs index 37b1fdec..87fdd2e3 100644 --- a/src/backend/render/shadow.rs +++ b/src/backend/render/shadow.rs @@ -86,12 +86,6 @@ impl ShadowShader { let offset = [0., 5.]; let color = [0., 0., 0., if dark_mode { 0.45 } else { 0.35 }]; let radius = radius.map(|r| ceil(r as f64)); - let radius = [ - radius[3], // top_left - radius[1], // top_right - radius[0], // bottom_right - radius[2], // bottom_left - ]; let width = softness; let sigma = width / 2.; diff --git a/src/backend/render/wayland/blur_effect.rs b/src/backend/render/wayland/blur_effect.rs index c4d27fac..b8a7935a 100644 --- a/src/backend/render/wayland/blur_effect.rs +++ b/src/backend/render/wayland/blur_effect.rs @@ -247,10 +247,10 @@ impl BlurElement { Uniform::new( "corner_radius", [ - radii[3] as f32, - radii[1] as f32, radii[0] as f32, + radii[1] as f32, radii[2] as f32, + radii[3] as f32, ], ), Uniform::new( diff --git a/src/backend/render/wayland/clipped_surface.rs b/src/backend/render/wayland/clipped_surface.rs index 8322079e..52535269 100644 --- a/src/backend/render/wayland/clipped_surface.rs +++ b/src/backend/render/wayland/clipped_surface.rs @@ -99,10 +99,10 @@ where Uniform::new( "corner_radius", [ - radius[3] as f32, - radius[1] as f32, radius[0] as f32, + radius[1] as f32, radius[2] as f32, + radius[3] as f32, ], ), Uniform::new( @@ -145,10 +145,10 @@ where geo: Rectangle, radius: [u8; 4], ) -> [Rectangle; 4] { - let top_left = radius[3] as f64; + let top_left = radius[0] as f64; let top_right = radius[1] as f64; - let bottom_right = radius[0] as f64; - let bottom_left = radius[2] as f64; + let bottom_right = radius[2] as f64; + let bottom_left = radius[3] as f64; [ Rectangle::new(geo.loc, Size::from((top_left, top_left))), diff --git a/src/shell/element/stack.rs b/src/shell/element/stack.rs index a97f5778..c973b189 100644 --- a/src/shell/element/stack.rs +++ b/src/shell/element/stack.rs @@ -842,7 +842,7 @@ impl CosmicStack { ))); }; - let radii = radii.map(|[a, _, c, _]| [a, 0, c, 0]); + let radii = radii.map(|[_, _, c, d]| [0, 0, c, d]); windows[active].push_render_elements( renderer, window_loc, @@ -1015,17 +1015,17 @@ impl CosmicStack { .corner_radius(geometry_size) .unwrap_or([default_radius; 4]); + corners[0] = 0; corners[1] = 0; - corners[3] = 0; corners } else { let mut corners = active_window.corner_radius(geometry_size).unwrap_or(radii); - corners[0] = radii[0].max(corners[0]); + corners[0] = radii[0]; corners[1] = radii[1]; corners[2] = radii[2].max(corners[2]); - corners[3] = radii[3]; + corners[3] = radii[3].max(corners[3]); corners } diff --git a/src/shell/element/window.rs b/src/shell/element/window.rs index 6488ffa3..91423ca5 100644 --- a/src/shell/element/window.rs +++ b/src/shell/element/window.rs @@ -438,12 +438,12 @@ impl CosmicWindow { .map(|x| (x * scale as f32).round() as u8); if has_ssd && !clip { // bottom corners - radii[0] = 0; radii[2] = 0; + radii[3] = 0; if is_tiled { // top corners + radii[0] = 0; radii[1] = 0; - radii[3] = 0; } } @@ -510,12 +510,12 @@ impl CosmicWindow { && !is_maximized; if has_ssd && !clip { // bottom corners - radii[0] = 0; radii[2] = 0; + radii[3] = 0; if is_tiled { // top corners + radii[0] = 0; radii[1] = 0; - radii[3] = 0; } } @@ -560,8 +560,8 @@ impl CosmicWindow { self.0.with_program(|p| { let mut radii = radii; if has_ssd { + radii[0] = 0; radii[1] = 0; - radii[3] = 0; } let theme = p.theme.lock().unwrap(); let frosted = if theme.cosmic().frosted_windows { @@ -585,8 +585,8 @@ impl CosmicWindow { }); if has_ssd { - radii[0] = 0; radii[2] = 0; + radii[3] = 0; let ssd_loc = location + self .0 @@ -691,26 +691,26 @@ impl CosmicWindow { (has_ssd, true) => { let mut corners = p.window.corner_radius(geometry_size).unwrap_or(radii); - corners[0] = radii[0].max(corners[0]); + corners[0] = if has_ssd { + radii[0] + } else { + radii[0].max(corners[0]) + }; corners[1] = if has_ssd { radii[1] } else { radii[1].max(corners[1]) }; corners[2] = radii[2].max(corners[2]); - corners[3] = if has_ssd { - radii[3] - } else { - radii[3].max(corners[3]) - }; + corners[3] = radii[3].max(corners[3]); corners } (true, false) => p .window .corner_radius(geometry_size) - .map(|[a, _, c, _]| [a, radii[1], c, radii[3]]) - .unwrap_or([default_radius, radii[1], default_radius, radii[3]]), + .map(|[_, _, c, d]| [radii[0], radii[1], c, d]) + .unwrap_or([radii[0], radii[1], default_radius, default_radius]), (false, false) => p .window .corner_radius(geometry_size) From 057e7b72cc0a1da4cbed73c51f30660255ba2ea9 Mon Sep 17 00:00:00 2001 From: Hojjat Date: Thu, 3 Sep 2026 11:51:49 -0600 Subject: [PATCH 32/69] chore: remove the gaurd against large paddings --- src/backend/render/mod.rs | 3 +-- src/wayland/handlers/corner_radius.rs | 11 ++--------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/backend/render/mod.rs b/src/backend/render/mod.rs index 1be5b9d4..9ad61588 100644 --- a/src/backend/render/mod.rs +++ b/src/backend/render/mod.rs @@ -899,8 +899,7 @@ where let geometry = geometry.to_local(output).as_logical(); let padded = with_states(layer.wl_surface(), |states| { - surface_padding(states, geometry.size) - .and_then(|padding| pad_rect(geometry, &padding)) + surface_padding(states).and_then(|padding| pad_rect(geometry, &padding)) }) .unwrap_or(geometry); let radii = with_states(layer.wl_surface(), |states| { diff --git a/src/wayland/handlers/corner_radius.rs b/src/wayland/handlers/corner_radius.rs index ded8d923..1a541938 100644 --- a/src/wayland/handlers/corner_radius.rs +++ b/src/wayland/handlers/corner_radius.rs @@ -45,18 +45,11 @@ pub fn surface_corners(states: &SurfaceData, size: Size) -> Option ]) } -pub fn surface_padding(states: &SurfaceData, size: Size) -> Option<[i32; 4]> { +pub fn surface_padding(states: &SurfaceData) -> Option<[i32; 4]> { let mut guard = states.cached_state.get::(); let padding = guard.current().0?; - - // guard against padding being too large - Some([ - padding.top.min(size.h / 2), - padding.right.min(size.w / 2), - padding.bottom.min(size.h / 2), - padding.left.min(size.w / 2), - ]) + Some([padding.top, padding.right, padding.bottom, padding.left]) } pub fn pad_rect( From 0f56d214b9ceaa53ca12ef6ce7043e07626bb42c Mon Sep 17 00:00:00 2001 From: Hojjat Date: Fri, 4 Sep 2026 07:46:03 -0600 Subject: [PATCH 33/69] chore: clippy fixes --- src/input/tablet_emu.rs | 48 ++++++++++----------- src/shell/element/stack.rs | 38 ++++++++-------- src/shell/element/window.rs | 26 +++++------ src/shell/grabs/moving.rs | 2 +- src/shell/layout/tiling/grabs/resize.rs | 2 +- src/wayland/handlers/decoration.rs | 21 +++++---- src/wayland/handlers/pointer_constraints.rs | 1 - 7 files changed, 66 insertions(+), 72 deletions(-) diff --git a/src/input/tablet_emu.rs b/src/input/tablet_emu.rs index 94d31d89..6ab17924 100644 --- a/src/input/tablet_emu.rs +++ b/src/input/tablet_emu.rs @@ -105,19 +105,17 @@ impl TabletToolGrab for PointerEmulationGrab { InputTime::now(), true, ); - } else { - if let Some(pointer) = self.seat.get_pointer() { - pointer.motion( - data, - focus, - &pointer::MotionEvent { - location: event.location, - serial: SERIAL_COUNTER.next_serial(), - time: InputTime::now(), - }, - ); - pointer.frame(data); - } + } else if let Some(pointer) = self.seat.get_pointer() { + pointer.motion( + data, + focus, + &pointer::MotionEvent { + location: event.location, + serial: SERIAL_COUNTER.next_serial(), + time: InputTime::now(), + }, + ); + pointer.frame(data); } } @@ -179,19 +177,17 @@ impl TabletToolGrab for PointerEmulationGrab { InputTime::now(), true, ); - } else { - if let Some(pointer) = self.seat.get_pointer() { - pointer.motion( - data, - focus, - &pointer::MotionEvent { - location: event.location, - serial: SERIAL_COUNTER.next_serial(), - time: InputTime::now(), - }, - ); - pointer.frame(data); - } + } else if let Some(pointer) = self.seat.get_pointer() { + pointer.motion( + data, + focus, + &pointer::MotionEvent { + location: event.location, + serial: SERIAL_COUNTER.next_serial(), + time: InputTime::now(), + }, + ); + pointer.frame(data); } } diff --git a/src/shell/element/stack.rs b/src/shell/element/stack.rs index c973b189..f4a37bfe 100644 --- a/src/shell/element/stack.rs +++ b/src/shell/element/stack.rs @@ -1724,12 +1724,12 @@ impl PointerTarget for CosmicStack { state.common.config.cosmic_conf.edge_snap_threshold, false, ); - if let Some((grab, focus)) = res { - if let GrabType::Pointer = grab.grab_type() { - seat.get_pointer() - .unwrap() - .set_grab(state, grab, serial, focus); - } + if let Some((grab, focus)) = res + && let GrabType::Pointer = grab.grab_type() + { + seat.get_pointer() + .unwrap() + .set_grab(state, grab, serial, focus); } }); } @@ -1785,12 +1785,12 @@ impl PointerTarget for CosmicStack { &state.common.event_loop_handle, false, ); - if let Some((grab, focus)) = res { - if let GrabType::Pointer = grab.grab_type() { - seat.get_pointer() - .unwrap() - .set_grab(state, grab, serial, focus); - } + if let Some((grab, focus)) = res + && let GrabType::Pointer = grab.grab_type() + { + seat.get_pointer() + .unwrap() + .set_grab(state, grab, serial, focus); } }); } @@ -1999,13 +1999,13 @@ impl TabletToolTarget for CosmicStack { state.common.config.cosmic_conf.edge_snap_threshold, false, ); - if let Some((grab, focus)) = res { - if let GrabType::TabletTool = grab.grab_type() { - seat.tablet_seat() - .get_tool(grab.tool().unwrap()) - .unwrap() - .set_grab(state, grab, InputTime::now(), serial, focus); - } + if let Some((grab, focus)) = res + && let GrabType::TabletTool = grab.grab_type() + { + seat.tablet_seat() + .get_tool(grab.tool().unwrap()) + .unwrap() + .set_grab(state, grab, InputTime::now(), serial, focus); } }); } diff --git a/src/shell/element/window.rs b/src/shell/element/window.rs index 91423ca5..fa4a1872 100644 --- a/src/shell/element/window.rs +++ b/src/shell/element/window.rs @@ -1112,12 +1112,12 @@ impl PointerTarget for CosmicWindow { false, ); - if let Some((grab, focus)) = res { - if let GrabType::Pointer = grab.grab_type() { - seat.get_pointer() - .unwrap() - .set_grab(state, grab, serial, focus) - } + if let Some((grab, focus)) = res + && let GrabType::Pointer = grab.grab_type() + { + seat.get_pointer() + .unwrap() + .set_grab(state, grab, serial, focus) } }); } @@ -1315,13 +1315,13 @@ impl TabletToolTarget for CosmicWindow { false, ); - if let Some((grab, focus)) = res { - if let GrabType::TabletTool = grab.grab_type() { - seat.tablet_seat() - .get_tool(grab.tool().unwrap()) - .unwrap() - .set_grab(state, grab, InputTime::now(), serial, focus) - } + if let Some((grab, focus)) = res + && let GrabType::TabletTool = grab.grab_type() + { + seat.tablet_seat() + .get_tool(grab.tool().unwrap()) + .unwrap() + .set_grab(state, grab, InputTime::now(), serial, focus) } }); } diff --git a/src/shell/grabs/moving.rs b/src/shell/grabs/moving.rs index 50fc9740..f1fbfa8a 100644 --- a/src/shell/grabs/moving.rs +++ b/src/shell/grabs/moving.rs @@ -905,7 +905,7 @@ impl Drop for MoveGrab { let seat = self.seat.clone(); // false-positive: `Output`s hash is based on it's inner ptr #[allow(clippy::mutable_key_type)] - let window_outputs = self.window_outputs.drain().collect::>(); + let window_outputs = std::mem::take(&mut self.window_outputs); let previous = self.previous; let window = self.window.clone(); let is_touch_grab = matches!(self.start_data, GrabStartData::Touch(_)); diff --git a/src/shell/layout/tiling/grabs/resize.rs b/src/shell/layout/tiling/grabs/resize.rs index 850545be..c6f202cf 100644 --- a/src/shell/layout/tiling/grabs/resize.rs +++ b/src/shell/layout/tiling/grabs/resize.rs @@ -201,7 +201,7 @@ impl TabletToolTarget for ResizeForkTarget { tool, data: TabletToolGrabStartData { focus: None, - location: location, + location, trigger: TabletToolGrabTrigger::Tip, }, }, diff --git a/src/wayland/handlers/decoration.rs b/src/wayland/handlers/decoration.rs index ae58d338..a1efbd0a 100644 --- a/src/wayland/handlers/decoration.rs +++ b/src/wayland/handlers/decoration.rs @@ -69,17 +69,16 @@ impl State { XdgMode::from_preference(self.default_decoration()) }; for (window, _) in mapped.windows() { - if PreferredDecorationMode::is_unset(&window.0) { - if let Some(toplevel) = window.0.toplevel() { - if toplevel.with_committed_state(|state| { - state.is_some_and(|state| state.decoration_mode.is_some()) - }) { - toplevel.with_pending_state(|state| { - state.decoration_mode = Some(mode); - }); - toplevel.send_configure(); - } - } + if PreferredDecorationMode::is_unset(&window.0) + && let Some(toplevel) = window.0.toplevel() + && toplevel.with_committed_state(|state| { + state.is_some_and(|state| state.decoration_mode.is_some()) + }) + { + toplevel.with_pending_state(|state| { + state.decoration_mode = Some(mode); + }); + toplevel.send_configure(); } } }; diff --git a/src/wayland/handlers/pointer_constraints.rs b/src/wayland/handlers/pointer_constraints.rs index e024bb40..743b3b0b 100644 --- a/src/wayland/handlers/pointer_constraints.rs +++ b/src/wayland/handlers/pointer_constraints.rs @@ -89,7 +89,6 @@ impl PointerConstraintsHandler for State { ConstraintRemove::PointerLeave(_) => { // If the constraint was broken by the pointer forcibly leaving the surface, then it doesn't // make much sense to warp it. - return; } ConstraintRemove::Destroyed(constraint) => { let Some(seat) = self From f61c0f9f76caa8640de4e2077ec31b6c37d12866 Mon Sep 17 00:00:00 2001 From: haydonryan Date: Tue, 1 Sep 2026 14:07:30 -0500 Subject: [PATCH 34/69] tabs: avoid two HashSet allocations in tab-change detection Replace the symmetric_difference over two freshly-materialized HashSets with direct contains_key lookups on the existing key sets. Semantically identical (set difference non-empty iff any key is in exactly one set) but removes two heap HashSet allocations plus hashing of every key on each widget update. Also drops the now-unused HashSet import. Implements compact-idiomatic-code-20 from the cosmic-comp optimization report. Created with the help of DeepSeek V4 Flash. --- src/shell/element/stack/tabs.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/shell/element/stack/tabs.rs b/src/shell/element/stack/tabs.rs index 86218db6..9dd5ef81 100644 --- a/src/shell/element/stack/tabs.rs +++ b/src/shell/element/stack/tabs.rs @@ -31,7 +31,7 @@ use keyframe::{ functions::{EaseInOutCubic, EaseOutCubic}, }; use std::{ - collections::{HashMap, HashSet, VecDeque}, + collections::{HashMap, VecDeque}, time::{Duration, Instant}, }; @@ -757,12 +757,10 @@ where state.last_state = Some(current_state.clone()); } let last_state = state.last_state.as_mut().unwrap(); - let unknown_keys = current_state - .keys() - .collect::>() - .symmetric_difference(&last_state.keys().collect::>()) - .next() - .is_some(); + let unknown_keys = current_state.len() != last_state.len() + || current_state + .keys() + .any(|key| !last_state.contains_key(key)); enum Difference { NewOrRemoved, From 8ad541dbe311ccef0e7be8b67df9f6d5f23039d0 Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Tue, 8 Sep 2026 16:51:34 +0200 Subject: [PATCH 35/69] i18n: translation updates from weblate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Quentin PAGÈS Translate-URL: https://hosted.weblate.org/projects/pop-os/cosmic-comp/oc/ Translation: Pop OS/COSMIC Comp --- resources/i18n/oc/cosmic_comp.ftl | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/resources/i18n/oc/cosmic_comp.ftl b/resources/i18n/oc/cosmic_comp.ftl index e69de29b..a1238332 100644 --- a/resources/i18n/oc/cosmic_comp.ftl +++ b/resources/i18n/oc/cosmic_comp.ftl @@ -0,0 +1,20 @@ +a11y-zoom-move-continuously = La vista bolega de contunh amb lo ponchador +a11y-zoom-move-onedge = La lista bolega quand lo ponchador atenh un caire +a11y-zoom-move-centered = La vista bolega per gardar lo ponchador al centre +a11y-zoom-settings = Paramètres de la lópia... +unknown-keybinding = +window-menu-tiled = Fenèstras bandejanta +window-menu-screenshot = Prendre una captura d’ecran +window-menu-resize = Redimensionar +window-menu-move-prev-workspace = Desplaçar a l’espaci de trabalh precedent +window-menu-move-next-workspace = Desplaçar a l'espaci de trabalh seguent +window-menu-stack = Crear una pila de fenèstras +window-menu-unstack-all = Desapilar totas las fenèstras +window-menu-unstack = Desapilar la fenèstra +window-menu-sticky = Fenèstra adesiva +window-menu-close = Tampar +window-menu-close-all = Tampar totas las fenèstras +window-menu-resize-edge-top = Amont +window-menu-resize-edge-left = Esquèrra +window-menu-resize-edge-right = Drecha +window-menu-resize-edge-bottom = Aval From 7d1daab7bc5db7ef0c4be64af1e35c8a24acfa9b Mon Sep 17 00:00:00 2001 From: Aleksandr Kosachev Date: Sun, 6 Sep 2026 19:36:12 +0300 Subject: [PATCH 36/69] fix: remove foreign toplevel handle too --- src/wayland/protocols/toplevel_info.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/wayland/protocols/toplevel_info.rs b/src/wayland/protocols/toplevel_info.rs index 2dc76347..3146adc3 100644 --- a/src/wayland/protocols/toplevel_info.rs +++ b/src/wayland/protocols/toplevel_info.rs @@ -418,6 +418,12 @@ where handle.closed(); } } + // Remove the foreign handle too, so new subscribers cannot + // discover a toplevel whose window has already been destroyed. + if let Some(handle) = state.foreign_handle.take() { + self.foreign_toplevel_list.remove_toplevel(&handle); + } + *state = Default::default(); dirty = true; false } From a55785993e8ef6aad38862cb1a9e1ccaad3c340d Mon Sep 17 00:00:00 2001 From: apassert <249084898+apassert@users.noreply.github.com> Date: Wed, 2 Sep 2026 21:09:51 +0200 Subject: [PATCH 37/69] config: sort outputs by connector for deterministic fallback layout When no saved configuration matches the current output set, positions were assigned in hotplug/registration order. On hotplug races (e.g. reconnecting monitors through a KVM switch) outputs can appear in arbitrary order, producing a swapped left/right layout that then gets persisted to outputs.ron, poisoning all future reconnects. Sort outputs by connector name before generating fallback positions so the layout is deterministic regardless of arrival order. AI disclosure: implemented with the assistance of an LLM coding agent, directed, reviewed, and tested by the author. Signed-off-by: apassert <249084898+apassert@users.noreply.github.com> --- src/config/mod.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/config/mod.rs b/src/config/mod.rs index d3d2919b..4d2fad9b 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -541,7 +541,13 @@ impl Config { primary.config_mut().xwayland_primary = true; } } - for output in outputs.iter().filter(|o| o.mirroring().is_none()) { + // sort by connector name for a deterministic layout independent of hotplug order + let mut sorted_outputs = outputs + .iter() + .filter(|o| o.mirroring().is_none()) + .collect::>(); + sorted_outputs.sort_by_key(|o| o.name()); + for output in sorted_outputs { { let mut config = output.config_mut(); config.position = (w, 0); From a103e7619b0a21b1c3c6b29debd6879d7d0bcc11 Mon Sep 17 00:00:00 2001 From: Lionel DARNIS Date: Thu, 10 Sep 2026 18:12:37 +0200 Subject: [PATCH 38/69] chore: fige Cargo.lock --- Cargo.lock | 1322 +++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 1061 insertions(+), 261 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d0a95294..a53353a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18,6 +18,61 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "366ffbaa4442f4684d91e2cd7c5ea7c4ed8add41959a31447066e279e432b618" +[[package]] +name = "accesskit" +version = "0.22.0" +source = "git+https://github.com/wash2/accesskit?tag=cosmic-0.14#f0599eed5f18111228266fe3f28991cc48b5964f" +dependencies = [ + "uuid", +] + +[[package]] +name = "accesskit_consumer" +version = "0.32.0" +source = "git+https://github.com/wash2/accesskit?tag=cosmic-0.14#f0599eed5f18111228266fe3f28991cc48b5964f" +dependencies = [ + "accesskit", + "hashbrown 0.16.1", +] + +[[package]] +name = "accesskit_macos" +version = "0.23.0" +source = "git+https://github.com/wash2/accesskit?tag=cosmic-0.14#f0599eed5f18111228266fe3f28991cc48b5964f" +dependencies = [ + "accesskit", + "accesskit_consumer", + "hashbrown 0.16.1", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "accesskit_windows" +version = "0.30.0" +source = "git+https://github.com/wash2/accesskit?tag=cosmic-0.14#f0599eed5f18111228266fe3f28991cc48b5964f" +dependencies = [ + "accesskit", + "accesskit_consumer", + "hashbrown 0.16.1", + "static_assertions", + "windows 0.61.3", + "windows-core 0.61.2", +] + +[[package]] +name = "accesskit_winit" +version = "0.30.0" +source = "git+https://github.com/wash2/accesskit?tag=cosmic-0.14#f0599eed5f18111228266fe3f28991cc48b5964f" +dependencies = [ + "accesskit", + "accesskit_macos", + "accesskit_windows", + "raw-window-handle", + "winit 0.31.0-beta.2", +] + [[package]] name = "addr2line" version = "0.25.1" @@ -61,6 +116,12 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + [[package]] name = "almost" version = "0.2.0" @@ -74,7 +135,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef6978589202a00cd7e118380c448a08b6ed394c3a8df3a430d0898e3a42d046" dependencies = [ "android-properties", - "bitflags 2.11.0", + "bitflags 2.13.2", "cc", "cesu8", "jni", @@ -166,6 +227,25 @@ dependencies = [ "libloading", ] +[[package]] +name = "ashpd" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33a3c86f3fd70c0ffa500ed189abfa90b5a52398a45d5dc372fcc38ebeb7a645" +dependencies = [ + "enumflags2", + "futures-channel", + "futures-util", + "rand 0.9.5", + "serde", + "serde_repr", + "url", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "zbus", +] + [[package]] name = "async-broadcast" version = "0.7.2" @@ -343,7 +423,7 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -390,9 +470,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" dependencies = [ "serde_core", ] @@ -412,13 +492,22 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block2" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" +dependencies = [ + "objc2 0.5.2", +] + [[package]] name = "block2" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" dependencies = [ - "objc2", + "objc2 0.6.4", ] [[package]] @@ -463,6 +552,13 @@ dependencies = [ "num-traits", ] +[[package]] +name = "build_helpers" +version = "0.14.0" +dependencies = [ + "cfg_aliases", +] + [[package]] name = "bumpalo" version = "3.20.2" @@ -514,7 +610,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dbf9978365bac10f54d1d4b04f7ce4427e51f71d61f2fe15e3fed5166474df7" dependencies = [ "async-task", - "bitflags 2.11.0", + "bitflags 2.13.2", "futures-core", "polling", "rustix 1.1.4", @@ -594,7 +690,7 @@ dependencies = [ "iana-time-zone", "num-traits", "serde", - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -615,7 +711,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", @@ -625,22 +720,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 = "cocoa" version = "0.25.0" @@ -650,7 +735,7 @@ dependencies = [ "bitflags 1.3.2", "block", "cocoa-foundation", - "core-foundation", + "core-foundation 0.9.4", "core-graphics", "foreign-types", "libc", @@ -665,8 +750,8 @@ checksum = "8c6234cbb2e4c785b456c0644748b1ac416dd045799740356f8363dfe00c93f7" dependencies = [ "bitflags 1.3.2", "block", - "core-foundation", - "core-graphics-types", + "core-foundation 0.9.4", + "core-graphics-types 0.1.3", "libc", "objc", ] @@ -677,7 +762,9 @@ version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe6d2e5af09e8c8ad56c969f2157a3d4238cebc7c55f0a517728c38f7b200f81" dependencies = [ - "unicode-width", + "serde", + "termcolor", + "unicode-width 0.1.14", ] [[package]] @@ -721,6 +808,16 @@ dependencies = [ "libc", ] +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -734,8 +831,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" dependencies = [ "bitflags 1.3.2", - "core-foundation", - "core-graphics-types", + "core-foundation 0.9.4", + "core-graphics-types 0.1.3", "foreign-types", "libc", ] @@ -747,7 +844,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" dependencies = [ "bitflags 1.3.2", - "core-foundation", + "core-foundation 0.9.4", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" +dependencies = [ + "bitflags 2.13.2", + "core-foundation 0.10.1", "libc", ] @@ -760,12 +868,24 @@ dependencies = [ "libm", ] +[[package]] +name = "cosmic-client-toolkit" +version = "0.2.0" +dependencies = [ + "bitflags 2.13.2", + "cosmic-protocols", + "libc", + "smithay-client-toolkit", + "wayland-client", + "wayland-protocols", +] + [[package]] name = "cosmic-comp" version = "1.0.0" dependencies = [ "anyhow", - "bitflags 2.11.0", + "bitflags 2.13.2", "calloop", "clap_lex", "cosmic-comp-config", @@ -787,7 +907,7 @@ dependencies = [ "indexmap 2.13.0", "jiff", "keyframe", - "libcosmic", + "libcosmic-yoda", "libdisplay-info", "libsystemd", "log-panics", @@ -809,7 +929,7 @@ dependencies = [ "smithay", "smithay-egui", "thiserror 2.0.18", - "tiny-skia", + "tiny-skia 0.11.4", "tracing", "tracing-journald", "tracing-subscriber", @@ -839,7 +959,6 @@ dependencies = [ [[package]] name = "cosmic-config" version = "1.0.0" -source = "git+https://github.com/pop-os/libcosmic#d922ac380134c00208d2acf93947d44fb217eec5" dependencies = [ "atomicwrites", "calloop", @@ -860,7 +979,6 @@ dependencies = [ [[package]] name = "cosmic-config-derive" version = "1.0.0" -source = "git+https://github.com/pop-os/libcosmic#d922ac380134c00208d2acf93947d44fb217eec5" dependencies = [ "quote", "syn", @@ -869,12 +987,11 @@ dependencies = [ [[package]] name = "cosmic-freedesktop-icons" version = "0.4.0" -source = "git+https://github.com/pop-os/freedesktop-icons#ab4c57b8e416c6af9297cb04d101889896fd9a92" dependencies = [ "bstr", "btoi", "memchr", - "memmap2", + "memmap2 0.9.10", "thiserror 2.0.18", "tracing", "xdg", @@ -883,10 +1000,10 @@ dependencies = [ [[package]] name = "cosmic-protocols" version = "0.2.0" -source = "git+https://github.com/pop-os//cosmic-protocols?branch=main#32283d76a8d0342da74c4cc022a533c52dcf378f" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "wayland-backend", + "wayland-client", "wayland-protocols", "wayland-protocols-wlr", "wayland-scanner", @@ -895,8 +1012,7 @@ dependencies = [ [[package]] name = "cosmic-randr-shell" -version = "0.1.0" -source = "git+https://github.com/pop-os/cosmic-randr/#6e8e795970fa06d434af22775e415b517f7552d3" +version = "1.3.0" dependencies = [ "kdl", "slotmap", @@ -906,7 +1022,6 @@ dependencies = [ [[package]] name = "cosmic-settings-config" version = "0.1.0" -source = "git+https://github.com/pop-os/cosmic-settings-daemon#e37160f14d1e7ee428f973cd2848b4e95f83dfe1" dependencies = [ "cosmic-config", "ron 0.11.0", @@ -918,8 +1033,7 @@ dependencies = [ [[package]] name = "cosmic-settings-daemon" -version = "0.1.0" -source = "git+https://github.com/pop-os/dbus-settings-bindings#eed01dd3609e90e3c8cd043656734c500956c793" +version = "0.1.1-yoda.1" dependencies = [ "zbus", ] @@ -927,7 +1041,6 @@ dependencies = [ [[package]] name = "cosmic-settings-daemon-config" version = "0.1.0" -source = "git+https://github.com/pop-os/cosmic-settings-daemon#e37160f14d1e7ee428f973cd2848b4e95f83dfe1" dependencies = [ "cosmic-config", "cosmic-theme", @@ -937,10 +1050,8 @@ 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", + "bitflags 2.13.2", "fontdb", "harfrust", "linebender_resource_handle", @@ -956,12 +1067,12 @@ dependencies = [ "unicode-linebreak", "unicode-script", "unicode-segmentation", + "unicode-width 0.2.2", ] [[package]] name = "cosmic-theme" version = "1.0.0" -source = "git+https://github.com/pop-os/libcosmic#d922ac380134c00208d2acf93947d44fb217eec5" dependencies = [ "almost", "configparser", @@ -1018,7 +1129,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", @@ -1179,8 +1289,8 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" dependencies = [ - "bitflags 2.11.0", - "objc2", + "bitflags 2.13.2", + "objc2 0.6.4", ] [[package]] @@ -1206,9 +1316,8 @@ 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", + "bitflags 2.13.2", "mime 0.1.0", "raw-window-handle", "smithay-client-toolkit", @@ -1233,21 +1342,12 @@ checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" [[package]] name = "dpi" version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76" [[package]] -name = "drm" -version = "0.11.1" +name = "dpi" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0f8a69e60d75ae7dab4ef26a59ca99f2a89d4c142089b537775ae0c198bdcde" -dependencies = [ - "bitflags 2.11.0", - "bytemuck", - "drm-ffi 0.7.1", - "drm-fourcc", - "rustix 0.38.44", -] +checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76" [[package]] name = "drm" @@ -1255,31 +1355,21 @@ version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80bc8c5c6c2941f70a55c15f8d9f00f9710ebda3ffda98075f996a0e6c92756f" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "bytemuck", - "drm-ffi 0.9.1", + "drm-ffi", "drm-fourcc", "libc", "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 0.6.1", - "rustix 0.38.44", -] - [[package]] name = "drm-ffi" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51a91c9b32ac4e8105dec255e849e0d66e27d7c34d184364fb93e469db08f690" dependencies = [ - "drm-sys 0.8.1", + "drm-sys", "rustix 1.1.4", ] @@ -1289,16 +1379,6 @@ 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 = "drm-sys" version = "0.8.1" @@ -1332,7 +1412,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25dd34cec49ab55d85ebf70139cb1ccd29c977ef6b6ba4fe85489d6877ee9ef3" dependencies = [ "ahash", - "bitflags 2.11.0", + "bitflags 2.13.2", "emath", "epaint", "nohash-hasher", @@ -1698,7 +1778,7 @@ checksum = "457e789b3d1202543297a350643cf459f836cade38934e7a4cf6a39e7cde2905" dependencies = [ "fontconfig-parser", "log", - "memmap2", + "memmap2 0.9.10", "slotmap", "tinyvec", "ttf-parser", @@ -1856,8 +1936,8 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce852e998d3ca5e4a97014fb31c940dc5ef344ec7d364984525fd11e8a547e6a" dependencies = [ - "bitflags 2.11.0", - "drm 0.14.1", + "bitflags 2.13.2", + "drm", "drm-fourcc", "gbm-sys", "libc", @@ -1883,8 +1963,8 @@ dependencies = [ "libc", "log", "rustversion", - "windows-link", - "windows-result", + "windows-link 0.2.1", + "windows-result 0.4.1", ] [[package]] @@ -1904,7 +1984,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8" dependencies = [ "rustix 1.1.4", - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -1995,6 +2075,49 @@ dependencies = [ "web-sys", ] +[[package]] +name = "glutin_wgl_sys" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c4ee00b289aba7a9e5306d57c2d05499b2e5dc427f84ac708bd2c090212cf3e" +dependencies = [ + "gl_generator", +] + +[[package]] +name = "gpu-allocator" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51255ea7cfaadb6c5f1528d43e92a82acb2b96c43365989a28b2d44ee38f8795" +dependencies = [ + "ash", + "hashbrown 0.16.1", + "log", + "presser", + "thiserror 2.0.18", + "windows 0.62.2", +] + +[[package]] +name = "gpu-descriptor" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b89c83349105e3732062a895becfc71a8f921bb71ecbbdd8ff99263e3b53a0ca" +dependencies = [ + "bitflags 2.13.2", + "gpu-descriptor-types", + "hashbrown 0.15.5", +] + +[[package]] +name = "gpu-descriptor-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91" +dependencies = [ + "bitflags 2.13.2", +] + [[package]] name = "grid" version = "1.0.0" @@ -2029,7 +2152,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4f9f40651a03bc0f7316bd75267ff5767e93017ef3cfffe76c6aa7252cc5a31c" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "bytemuck", "core_maths", "read-fonts 0.37.0", @@ -2057,6 +2180,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", ] @@ -2204,7 +2329,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core", + "windows-core 0.62.2", ] [[package]] @@ -2219,9 +2344,10 @@ dependencies = [ [[package]] name = "iced" version = "0.14.0" -source = "git+https://github.com/pop-os/libcosmic#d922ac380134c00208d2acf93947d44fb217eec5" dependencies = [ + "build_helpers", "dnd", + "iced_accessibility", "iced_core", "iced_debug", "iced_futures", @@ -2229,19 +2355,29 @@ dependencies = [ "iced_renderer", "iced_runtime", "iced_widget", + "iced_winit", "image", "mime 0.1.0", "thiserror 2.0.18", "window_clipboard", ] +[[package]] +name = "iced_accessibility" +version = "0.1.0" +dependencies = [ + "accesskit", + "accesskit_winit", +] + [[package]] name = "iced_core" version = "0.14.0" -source = "git+https://github.com/pop-os/libcosmic#d922ac380134c00208d2acf93947d44fb217eec5" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", + "build_helpers", "bytes", + "cosmic-client-toolkit", "dnd", "glam 0.25.0", "lilt", @@ -2262,7 +2398,6 @@ dependencies = [ [[package]] name = "iced_debug" version = "0.14.0" -source = "git+https://github.com/pop-os/libcosmic#d922ac380134c00208d2acf93947d44fb217eec5" dependencies = [ "iced_core", "iced_futures", @@ -2272,7 +2407,6 @@ dependencies = [ [[package]] name = "iced_futures" version = "0.14.0" -source = "git+https://github.com/pop-os/libcosmic#d922ac380134c00208d2acf93947d44fb217eec5" dependencies = [ "futures", "iced_core", @@ -2285,9 +2419,8 @@ dependencies = [ [[package]] name = "iced_graphics" version = "0.14.0" -source = "git+https://github.com/pop-os/libcosmic#d922ac380134c00208d2acf93947d44fb217eec5" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "bytemuck", "cosmic-text", "half", @@ -2306,7 +2439,6 @@ dependencies = [ [[package]] name = "iced_program" version = "0.14.0" -source = "git+https://github.com/pop-os/libcosmic#d922ac380134c00208d2acf93947d44fb217eec5" dependencies = [ "iced_graphics", "iced_runtime", @@ -2315,7 +2447,6 @@ dependencies = [ [[package]] name = "iced_renderer" version = "0.14.0" -source = "git+https://github.com/pop-os/libcosmic#d922ac380134c00208d2acf93947d44fb217eec5" dependencies = [ "iced_graphics", "iced_tiny_skia", @@ -2327,9 +2458,10 @@ dependencies = [ [[package]] name = "iced_runtime" version = "0.14.0" -source = "git+https://github.com/pop-os/libcosmic#d922ac380134c00208d2acf93947d44fb217eec5" dependencies = [ + "build_helpers", "bytes", + "cosmic-client-toolkit", "dnd", "iced_core", "iced_futures", @@ -2341,7 +2473,6 @@ dependencies = [ [[package]] name = "iced_tiny_skia" version = "0.14.0" -source = "git+https://github.com/pop-os/libcosmic#d922ac380134c00208d2acf93947d44fb217eec5" dependencies = [ "bytemuck", "cosmic-text", @@ -2352,17 +2483,17 @@ dependencies = [ "resvg 0.45.1", "rustc-hash 2.1.1", "softbuffer", - "tiny-skia", + "tiny-skia 0.11.4", ] [[package]] name = "iced_wgpu" version = "0.14.0" -source = "git+https://github.com/pop-os/libcosmic#d922ac380134c00208d2acf93947d44fb217eec5" dependencies = [ - "as-raw-xcb-connection", - "bitflags 2.11.0", + "bitflags 2.13.2", + "build_helpers", "bytemuck", + "cosmic-client-toolkit", "cryoglyph", "futures", "glam 0.25.0", @@ -2376,20 +2507,19 @@ dependencies = [ "rustc-hash 2.1.1", "rustix 0.38.44", "thiserror 2.0.18", - "tiny-xlib", "wayland-backend", "wayland-client", "wayland-protocols", "wayland-sys", "wgpu", - "x11rb", ] [[package]] name = "iced_widget" version = "0.14.2" -source = "git+https://github.com/pop-os/libcosmic#d922ac380134c00208d2acf93947d44fb217eec5" dependencies = [ + "build_helpers", + "cosmic-client-toolkit", "dnd", "iced_renderer", "iced_runtime", @@ -2402,6 +2532,38 @@ dependencies = [ "window_clipboard", ] +[[package]] +name = "iced_winit" +version = "0.14.0" +dependencies = [ + "build_helpers", + "cosmic-client-toolkit", + "cursor-icon", + "dnd", + "iced_debug", + "iced_futures", + "iced_graphics", + "iced_program", + "iced_runtime", + "log", + "raw-window-handle", + "rustc-hash 2.1.1", + "rustix 0.38.44", + "thiserror 2.0.18", + "wasm-bindgen-futures", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "web-sys", + "winapi", + "window_clipboard", + "winit 0.31.0-beta.2", + "winit-core 0.31.0-beta.2", + "xkbcommon 0.7.0", + "xkbcommon-dl", + "xkeysym", +] + [[package]] name = "icu_collections" version = "2.1.1" @@ -2590,7 +2752,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "inotify-sys", "libc", ] @@ -2610,7 +2772,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9793345a65d71317763a33066b5d8351f8760dde8d4930fe9e39b5f14a7959d" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "input-sys", "libc", "log", @@ -2768,7 +2930,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", ] @@ -2782,6 +2944,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "khronos-egl" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76" +dependencies = [ + "libc", + "libloading", + "pkg-config", +] + [[package]] name = "khronos_api" version = "3.1.0" @@ -2866,12 +3039,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" [[package]] -name = "libcosmic" -version = "1.0.0" -source = "git+https://github.com/pop-os/libcosmic#d922ac380134c00208d2acf93947d44fb217eec5" +name = "libcosmic-yoda" +version = "0.1.0-yoda.2" dependencies = [ "apply", + "ashpd", "auto_enums", + "build_helpers", + "cosmic-client-toolkit", "cosmic-config", "cosmic-freedesktop-icons", "cosmic-settings-daemon", @@ -2889,7 +3064,9 @@ dependencies = [ "iced_renderer", "iced_runtime", "iced_tiny_skia", + "iced_wgpu", "iced_widget", + "iced_winit", "image", "jiff", "log", @@ -2912,7 +3089,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59fd96dbb2381ff31f314f07accbdf8550febdcc5cd8761ecaf7c1763361c359" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "libc", "libdisplay-info-derive", "libdisplay-info-sys", @@ -2947,7 +3124,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" dependencies = [ "cfg-if", - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -2958,13 +3135,14 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libredox" -version = "0.1.12" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" +checksum = "8d8f1ea3f21fd3405dcaf6c9b5c1630af9afc422d9073ea39c5f6d6c772e08ed" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "libc", - "redox_syscall 0.7.2", + "plain", + "redox_syscall 0.9.4", ] [[package]] @@ -3036,12 +3214,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.9.4" @@ -3196,6 +3368,15 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +[[package]] +name = "memmap2" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a5a03cefb0d953ec0be133036f14e109412fa594edc2f77227249db66cc3ed" +dependencies = [ + "libc", +] + [[package]] name = "memmap2" version = "0.9.10" @@ -3214,6 +3395,21 @@ dependencies = [ "autocfg", ] +[[package]] +name = "metal" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7047791b5bc903b8cd963014b355f71dc9864a9a0b727057676c1dcae5cbc15" +dependencies = [ + "bitflags 2.13.2", + "block", + "core-graphics-types 0.2.0", + "foreign-types", + "log", + "objc", + "paste", +] + [[package]] name = "miette" version = "7.6.0" @@ -3221,13 +3417,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f98efec8807c63c752b5bd61f862c165c115b0a35685bdcfd9238c7aeb592b7" dependencies = [ "cfg-if", - "unicode-width", + "unicode-width 0.1.14", ] [[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", ] @@ -3302,7 +3497,7 @@ checksum = "618f667225063219ddfc61251087db8a9aec3c3f0950c916b614e403486f1135" dependencies = [ "arrayvec", "bit-set", - "bitflags 2.11.0", + "bitflags 2.13.2", "cfg-if", "cfg_aliases", "codespan-reporting", @@ -3315,6 +3510,7 @@ dependencies = [ "num-traits", "once_cell", "rustc-hash 1.1.0", + "spirv", "thiserror 2.0.18", "unicode-ident", ] @@ -3325,7 +3521,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", "log", "ndk-sys", @@ -3355,7 +3551,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "cfg-if", "cfg_aliases", "libc", @@ -3383,7 +3579,7 @@ version = "8.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d3d07927151ff8575b7087f245456e549fea62edf0ec4e565a5ee50c8402bc3" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "fsevent-sys", "inotify", "kqueue", @@ -3401,7 +3597,7 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42b8cfee0e339a0337359f3c88165702ac6e600dc01c0cc9579a92d62b08477a" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", ] [[package]] @@ -3535,6 +3731,22 @@ dependencies = [ "objc_id", ] +[[package]] +name = "objc-sys" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" + +[[package]] +name = "objc2" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" +dependencies = [ + "objc-sys", + "objc2-encode", +] + [[package]] name = "objc2" version = "0.6.4" @@ -3544,16 +3756,44 @@ dependencies = [ "objc2-encode", ] +[[package]] +name = "objc2-app-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" +dependencies = [ + "bitflags 2.13.2", + "block2 0.5.1", + "libc", + "objc2 0.5.2", + "objc2-core-data", + "objc2-core-image", + "objc2-foundation 0.2.2", + "objc2-quartz-core", +] + [[package]] name = "objc2-app-kit" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" dependencies = [ - "bitflags 2.11.0", - "objc2", + "bitflags 2.13.2", + "objc2 0.6.4", "objc2-core-foundation", - "objc2-foundation", + "objc2-foundation 0.3.2", +] + +[[package]] +name = "objc2-core-data" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" +dependencies = [ + "bitflags 2.13.2", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", ] [[package]] @@ -3562,10 +3802,10 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ - "bitflags 2.11.0", - "block2", + "bitflags 2.13.2", + "block2 0.6.2", "dispatch2", - "objc2", + "objc2 0.6.4", ] [[package]] @@ -3574,18 +3814,30 @@ 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", "libc", "objc2-core-foundation", ] +[[package]] +name = "objc2-core-image" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" +dependencies = [ + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", + "objc2-metal", +] + [[package]] name = "objc2-core-video" 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-core-foundation", "objc2-core-graphics", ] @@ -3596,28 +3848,65 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" +[[package]] +name = "objc2-foundation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" +dependencies = [ + "bitflags 2.13.2", + "block2 0.5.1", + "libc", + "objc2 0.5.2", +] + [[package]] name = "objc2-foundation" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ - "bitflags 2.11.0", - "block2", - "objc2", + "bitflags 2.13.2", + "block2 0.6.2", + "objc2 0.6.4", "objc2-core-foundation", ] +[[package]] +name = "objc2-metal" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" +dependencies = [ + "bitflags 2.13.2", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" +dependencies = [ + "bitflags 2.13.2", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", + "objc2-metal", +] + [[package]] name = "objc2-ui-kit" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22" dependencies = [ - "bitflags 2.11.0", - "objc2", + "bitflags 2.13.2", + "objc2 0.6.4", "objc2-core-foundation", - "objc2-foundation", + "objc2-foundation 0.3.2", ] [[package]] @@ -3763,7 +4052,7 @@ dependencies = [ "libc", "redox_syscall 0.5.18", "smallvec", - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -3940,6 +4229,12 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + [[package]] name = "png" version = "0.17.16" @@ -3959,7 +4254,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", @@ -4019,6 +4314,12 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "presser" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa" + [[package]] name = "prettyplease" version = "0.2.37" @@ -4148,10 +4449,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha", + "rand_chacha 0.3.1", "rand_core 0.6.4", ] +[[package]] +name = "rand" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.5", +] + [[package]] name = "rand" version = "0.10.0" @@ -4173,6 +4484,16 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", +] + [[package]] name = "rand_core" version = "0.6.4" @@ -4182,12 +4503,27 @@ dependencies = [ "getrandom 0.2.17", ] +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] + [[package]] name = "rand_core" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba" +[[package]] +name = "range-alloc" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca45419789ae5a7899559e9512e58ca889e41f04f1f2445e9f4b290ceccd1d08" + [[package]] name = "rangemap" version = "1.7.1" @@ -4227,22 +4563,32 @@ dependencies = [ "font-types 0.11.0", ] +[[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]] name = "redox_syscall" 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]] name = "redox_syscall" -version = "0.7.2" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d94dd2f7cd932d4dc02cc8b2b50dfd38bd079a4e5d79198b99743d7fcf9a4b4" +checksum = "737970939a87c6fa31e7acad13307bccbb017a073b695b6089a2c484f929e20e" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", ] [[package]] @@ -4333,7 +4679,7 @@ dependencies = [ "pico-args", "rgb", "svgtypes 0.13.0", - "tiny-skia", + "tiny-skia 0.11.4", "usvg 0.37.0", ] @@ -4349,7 +4695,7 @@ dependencies = [ "pico-args", "rgb", "svgtypes 0.15.3", - "tiny-skia", + "tiny-skia 0.11.4", "usvg 0.45.1", "zune-jpeg 0.4.21", ] @@ -4370,7 +4716,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db09040cc89e461f1a265139777a2bde7f8d8c67c4936f700c63ce3e2904d468" dependencies = [ "base64 0.22.1", - "bitflags 2.11.0", + "bitflags 2.13.2", "serde", "serde_derive", "unicode-ident", @@ -4382,7 +4728,7 @@ version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd490c5b18261893f14449cbd28cb9c0b637aebf161cd77900bfdedaff21ec32" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "once_cell", "serde", "serde_derive", @@ -4460,7 +4806,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", @@ -4473,7 +4819,7 @@ 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", @@ -4492,7 +4838,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", @@ -4558,6 +4904,19 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "sctk-adwaita" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2a4360b9abcdcee43809e6fc11d6d61ca5d25734026a8fc46c2883eea3f13f" +dependencies = [ + "ab_glyph", + "log", + "memmap2 0.9.10", + "smithay-client-toolkit", + "tiny-skia 0.12.0", +] + [[package]] name = "self_cell" version = "1.2.2" @@ -4777,15 +5136,15 @@ dependencies = [ "aliasable", "appendlist", "ash", - "bitflags 2.11.0", + "bitflags 2.13.2", "calloop", "cc", "cursor-icon", "downcast-rs", - "drm 0.14.1", - "drm-ffi 0.9.1", + "drm", + "drm-ffi", "drm-fourcc", - "drm-sys 0.8.1", + "drm-sys", "encoding_rs", "errno", "gbm", @@ -4819,7 +5178,7 @@ dependencies = [ "wayland-protocols-misc", "wayland-protocols-wlr", "wayland-server", - "winit", + "winit 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", "x11rb", "xkbcommon 0.9.0", ] @@ -4830,13 +5189,15 @@ 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", "calloop-wayland-source", "cursor-icon", "libc", "log", - "memmap2", + "memmap2 0.9.10", + "pkg-config", "rustix 1.1.4", "thiserror 2.0.18", "wayland-backend", @@ -4848,13 +5209,13 @@ dependencies = [ "wayland-protocols-misc", "wayland-protocols-wlr", "wayland-scanner", + "xkbcommon 0.8.0", "xkeysym", ] [[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", @@ -4895,22 +5256,20 @@ checksum = "27207bb65232eda1f588cf46db2fee75c0808d557f6b3cf19a75f5d6d7c94df1" [[package]] name = "softbuffer" version = "0.4.1" -source = "git+https://github.com/pop-os/softbuffer?tag=cosmic-4.0#c2b2c19ddb38ff17495643699f97cb1f2064a1be" dependencies = [ "as-raw-xcb-connection", "bytemuck", "cfg_aliases", "cocoa", "core-graphics", - "drm 0.11.1", "fastrand", "foreign-types", "js-sys", + "libredox", "log", - "memmap2", + "memmap2 0.9.10", "objc", "raw-window-handle", - "redox_syscall 0.5.18", "rustix 0.38.44", "tiny-xlib", "wasm-bindgen", @@ -4922,6 +5281,15 @@ dependencies = [ "x11rb", ] +[[package]] +name = "spirv" +version = "0.3.0+sdk-1.3.268.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" +dependencies = [ + "bitflags 2.13.2", +] + [[package]] name = "stable_deref_trait" version = "1.2.1" @@ -5067,6 +5435,15 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + [[package]] name = "thiserror" version = "1.0.69" @@ -5159,7 +5536,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]] @@ -5173,6 +5564,17 @@ dependencies = [ "strict-num", ] +[[package]] +name = "tiny-skia-path" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edca365c3faccca67d06593c5980fa6c57687de727a03131735bb85f01fdeeb9" +dependencies = [ + "arrayref", + "bytemuck", + "strict-num", +] + [[package]] name = "tiny-xlib" version = "0.2.4" @@ -5513,6 +5915,12 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + [[package]] name = "unicode-xid" version = "0.2.6" @@ -5529,6 +5937,7 @@ dependencies = [ "idna", "percent-encoding", "serde", + "serde_derive", ] [[package]] @@ -5565,7 +5974,7 @@ dependencies = [ "siphasher 1.0.2", "strict-num", "svgtypes 0.15.3", - "tiny-skia-path", + "tiny-skia-path 0.11.4", "unicode-bidi", "unicode-script", "unicode-vo", @@ -5599,7 +6008,7 @@ dependencies = [ "rctree", "strict-num", "svgtypes 0.13.0", - "tiny-skia-path", + "tiny-skia-path 0.11.4", ] [[package]] @@ -5758,7 +6167,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 2.13.0", "semver", @@ -5798,7 +6207,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", @@ -5810,7 +6219,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", ] @@ -5842,7 +6251,7 @@ version = "0.32.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23d0c813de3daa2ed6520af85a3bd49b0e722a3078506899aa9686fea58dc4b6" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "wayland-backend", "wayland-client", "wayland-scanner", @@ -5855,7 +6264,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", @@ -5868,7 +6277,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", @@ -5882,7 +6291,7 @@ version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa98634619300a535a9a97f338aed9a5ff1e01a461943e8346ff4ae26007306b" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "wayland-backend", "wayland-client", "wayland-protocols", @@ -5895,7 +6304,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", @@ -5920,7 +6329,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", @@ -5972,18 +6381,24 @@ 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", "document-features", "hashbrown 0.16.1", + "js-sys", "log", + "naga", + "parking_lot", "portable-atomic", "profiling", "raw-window-handle", "smallvec", "static_assertions", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", "wgpu-core", "wgpu-hal", "wgpu-types", @@ -5998,7 +6413,7 @@ dependencies = [ "arrayvec", "bit-set", "bit-vec", - "bitflags 2.11.0", + "bitflags 2.13.2", "bytemuck", "cfg_aliases", "document-features", @@ -6014,11 +6429,31 @@ dependencies = [ "rustc-hash 1.1.0", "smallvec", "thiserror 2.0.18", + "wgpu-core-deps-apple", + "wgpu-core-deps-emscripten", "wgpu-core-deps-windows-linux-android", "wgpu-hal", "wgpu-types", ] +[[package]] +name = "wgpu-core-deps-apple" +version = "28.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87b7b696b918f337c486bf93142454080a32a37832ba8a31e4f48221890047da" +dependencies = [ + "wgpu-hal", +] + +[[package]] +name = "wgpu-core-deps-emscripten" +version = "28.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34b251c331f84feac147de3c4aa3aa45112622a95dd7ee1b74384fa0458dbd79" +dependencies = [ + "wgpu-hal", +] + [[package]] name = "wgpu-core-deps-windows-linux-android" version = "28.0.0" @@ -6034,18 +6469,46 @@ version = "28.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44d6cb474beb218824dcc9e1ce679d973f719262789bfb27407da560cac20eeb" dependencies = [ - "bitflags 2.11.0", + "android_system_properties", + "arrayvec", + "ash", + "bit-set", + "bitflags 2.13.2", + "block", + "bytemuck", "cfg-if", "cfg_aliases", + "core-graphics-types 0.2.0", + "glow", + "glutin_wgl_sys", + "gpu-allocator", + "gpu-descriptor", + "hashbrown 0.16.1", + "js-sys", + "khronos-egl", + "libc", "libloading", "log", + "metal", "naga", + "ndk-sys", + "objc", + "once_cell", + "ordered-float", + "parking_lot", "portable-atomic", "portable-atomic-util", + "profiling", + "range-alloc", "raw-window-handle", "renderdoc-sys", + "smallvec", "thiserror 2.0.18", + "wasm-bindgen", + "web-sys", "wgpu-types", + "windows 0.62.2", + "windows-core 0.62.2", ] [[package]] @@ -6054,7 +6517,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", @@ -6095,18 +6558,72 @@ 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", "thiserror 1.0.69", ] +[[package]] +name = "windows" +version = "0.61.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" +dependencies = [ + "windows-collections 0.2.0", + "windows-core 0.61.2", + "windows-future 0.2.1", + "windows-link 0.1.3", + "windows-numerics 0.2.0", +] + +[[package]] +name = "windows" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580" +dependencies = [ + "windows-collections 0.3.2", + "windows-core 0.62.2", + "windows-future 0.3.2", + "windows-numerics 0.3.1", +] + +[[package]] +name = "windows-collections" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" +dependencies = [ + "windows-core 0.61.2", +] + +[[package]] +name = "windows-collections" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610" +dependencies = [ + "windows-core 0.62.2", +] + +[[package]] +name = "windows-core" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link 0.1.3", + "windows-result 0.3.4", + "windows-strings 0.4.2", +] + [[package]] name = "windows-core" version = "0.62.2" @@ -6115,9 +6632,31 @@ checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", - "windows-link", - "windows-result", - "windows-strings", + "windows-link 0.2.1", + "windows-result 0.4.1", + "windows-strings 0.5.1", +] + +[[package]] +name = "windows-future" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" +dependencies = [ + "windows-core 0.61.2", + "windows-link 0.1.3", + "windows-threading 0.1.0", +] + +[[package]] +name = "windows-future" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb" +dependencies = [ + "windows-core 0.62.2", + "windows-link 0.2.1", + "windows-threading 0.2.1", ] [[package]] @@ -6142,19 +6681,63 @@ dependencies = [ "syn", ] +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + [[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +[[package]] +name = "windows-numerics" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +dependencies = [ + "windows-core 0.61.2", + "windows-link 0.1.3", +] + +[[package]] +name = "windows-numerics" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26" +dependencies = [ + "windows-core 0.62.2", + "windows-link 0.2.1", +] + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link 0.1.3", +] + [[package]] name = "windows-result" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ - "windows-link", + "windows-link 0.2.1", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link 0.1.3", ] [[package]] @@ -6163,7 +6746,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -6217,7 +6800,7 @@ version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -6272,7 +6855,7 @@ version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ - "windows-link", + "windows-link 0.2.1", "windows_aarch64_gnullvm 0.53.1", "windows_aarch64_msvc 0.53.1", "windows_i686_gnu 0.53.1", @@ -6283,6 +6866,24 @@ dependencies = [ "windows_x86_64_msvc 0.53.1", ] +[[package]] +name = "windows-threading" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-threading" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37" +dependencies = [ + "windows-link 0.2.1", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.42.2" @@ -6466,30 +7067,68 @@ checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winit" version = "0.31.0-beta.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2879d2854d1a43e48f67322d4bd097afcb6eb8f8f775c8de0260a71aea1df1aa" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "cfg_aliases", "cursor-icon", - "dpi", + "dpi 0.1.2", "libc", "raw-window-handle", "rustix 1.1.4", "smol_str", "tracing", - "winit-android", - "winit-appkit", - "winit-common", - "winit-core", - "winit-orbital", - "winit-uikit", - "winit-wayland", - "winit-web", - "winit-win32", + "winit-android 0.31.0-beta.2", + "winit-appkit 0.31.0-beta.2", + "winit-common 0.31.0-beta.2", + "winit-core 0.31.0-beta.2", + "winit-orbital 0.31.0-beta.2", + "winit-uikit 0.31.0-beta.2", + "winit-wayland 0.31.0-beta.2", + "winit-web 0.31.0-beta.2", + "winit-win32 0.31.0-beta.2", +] + +[[package]] +name = "winit" +version = "0.31.0-beta.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2879d2854d1a43e48f67322d4bd097afcb6eb8f8f775c8de0260a71aea1df1aa" +dependencies = [ + "bitflags 2.13.2", + "cfg_aliases", + "cursor-icon", + "dpi 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "raw-window-handle", + "rustix 1.1.4", + "smol_str", + "tracing", + "winit-android 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winit-appkit 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winit-common 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winit-core 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winit-orbital 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winit-uikit 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winit-wayland 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winit-web 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winit-win32 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", "winit-x11", ] +[[package]] +name = "winit-android" +version = "0.31.0-beta.2" +dependencies = [ + "android-activity", + "bitflags 2.13.2", + "dpi 0.1.2", + "ndk", + "raw-window-handle", + "smol_str", + "tracing", + "winit-core 0.31.0-beta.2", +] + [[package]] name = "winit-android" version = "0.31.0-beta.2" @@ -6497,13 +7136,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d9c0d2cd93efec3a9f9ad819cfaf0834782403af7c0d248c784ec0c61761df" dependencies = [ "android-activity", - "bitflags 2.11.0", - "dpi", + "bitflags 2.13.2", + "dpi 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "ndk", "raw-window-handle", "smol_str", "tracing", - "winit-core", + "winit-core 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winit-appkit" +version = "0.31.0-beta.2" +dependencies = [ + "bitflags 2.13.2", + "block2 0.6.2", + "dispatch2", + "dpi 0.1.2", + "objc2 0.6.4", + "objc2-app-kit 0.3.2", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-core-video", + "objc2-foundation 0.3.2", + "raw-window-handle", + "smol_str", + "tracing", + "winit-common 0.31.0-beta.2", + "winit-core 0.31.0-beta.2", ] [[package]] @@ -6512,21 +7172,34 @@ version = "0.31.0-beta.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21310ca07851a49c348e0c2cc768e36b52ca65afda2c2354d78ed4b90074d8aa" dependencies = [ - "bitflags 2.11.0", - "block2", + "bitflags 2.13.2", + "block2 0.6.2", "dispatch2", - "dpi", - "objc2", - "objc2-app-kit", + "dpi 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "objc2 0.6.4", + "objc2-app-kit 0.3.2", "objc2-core-foundation", "objc2-core-graphics", "objc2-core-video", - "objc2-foundation", + "objc2-foundation 0.3.2", "raw-window-handle", "smol_str", "tracing", - "winit-common", - "winit-core", + "winit-common 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winit-core 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winit-common" +version = "0.31.0-beta.2" +dependencies = [ + "memmap2 0.9.10", + "objc2 0.6.4", + "objc2-core-foundation", + "smol_str", + "tracing", + "winit-core 0.31.0-beta.2", + "xkbcommon-dl", ] [[package]] @@ -6535,45 +7208,92 @@ version = "0.31.0-beta.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45375fbac4cbb77260d83a30b1f9d8105880dbac99a9ae97f56656694680ff69" dependencies = [ - "memmap2", - "objc2", + "memmap2 0.9.10", + "objc2 0.6.4", "objc2-core-foundation", "smol_str", "tracing", - "winit-core", + "winit-core 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", "x11-dl", "xkbcommon-dl", ] +[[package]] +name = "winit-core" +version = "0.31.0-beta.2" +dependencies = [ + "bitflags 2.13.2", + "cursor-icon", + "dpi 0.1.2", + "keyboard-types", + "raw-window-handle", + "smol_str", + "web-time", +] + [[package]] name = "winit-core" version = "0.31.0-beta.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4f0ccd7abb43740e2c6124ac7cae7d865ecec74eec63783e8922577ac232583" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "cursor-icon", - "dpi", + "dpi 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "keyboard-types", "raw-window-handle", "smol_str", "web-time", ] +[[package]] +name = "winit-orbital" +version = "0.31.0-beta.2" +dependencies = [ + "bitflags 2.13.2", + "dpi 0.1.2", + "libredox", + "orbclient", + "raw-window-handle", + "redox_event", + "smol_str", + "tracing", + "winit-core 0.31.0-beta.2", +] + [[package]] name = "winit-orbital" version = "0.31.0-beta.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51ea1fb262e7209f265f12bd0cc792c399b14355675e65531e9c8a87db287d46" dependencies = [ - "bitflags 2.11.0", - "dpi", + "bitflags 2.13.2", + "dpi 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "orbclient", "raw-window-handle", "redox_syscall 0.5.18", "smol_str", "tracing", - "winit-core", + "winit-core 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winit-uikit" +version = "0.31.0-beta.2" +dependencies = [ + "bitflags 2.13.2", + "block2 0.6.2", + "dispatch2", + "dpi 0.1.2", + "objc2 0.6.4", + "objc2-core-foundation", + "objc2-foundation 0.3.2", + "objc2-ui-kit", + "raw-window-handle", + "smol_str", + "tracing", + "winit-common 0.31.0-beta.2", + "winit-core 0.31.0-beta.2", ] [[package]] @@ -6582,19 +7302,44 @@ version = "0.31.0-beta.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "680a356e798837d8eb274d4556e83bceaf81698194e31aafc5cfb8a9f2fab643" dependencies = [ - "bitflags 2.11.0", - "block2", + "bitflags 2.13.2", + "block2 0.6.2", "dispatch2", - "dpi", - "objc2", + "dpi 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "objc2 0.6.4", "objc2-core-foundation", - "objc2-foundation", + "objc2-foundation 0.3.2", "objc2-ui-kit", "raw-window-handle", "smol_str", "tracing", - "winit-common", - "winit-core", + "winit-common 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winit-core 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winit-wayland" +version = "0.31.0-beta.2" +dependencies = [ + "ahash", + "bitflags 2.13.2", + "calloop", + "cursor-icon", + "dpi 0.1.2", + "libc", + "memmap2 0.9.10", + "raw-window-handle", + "rustix 1.1.4", + "sctk-adwaita", + "smithay-client-toolkit", + "smol_str", + "tracing", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-protocols-plasma", + "winit-common 0.31.0-beta.2", + "winit-core 0.31.0-beta.2", ] [[package]] @@ -6604,12 +7349,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ce5afb2ba07da603f84b722c95f9f9396d2cedae3944fb6c0cda4a6f88de545" dependencies = [ "ahash", - "bitflags 2.11.0", + "bitflags 2.13.2", "calloop", "cursor-icon", - "dpi", + "dpi 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc", - "memmap2", + "memmap2 0.9.10", "raw-window-handle", "rustix 1.1.4", "smithay-client-toolkit", @@ -6619,21 +7364,19 @@ dependencies = [ "wayland-client", "wayland-protocols", "wayland-protocols-plasma", - "winit-common", - "winit-core", + "winit-common 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winit-core 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "winit-web" version = "0.31.0-beta.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c2490a953fb776fbbd5e295d54f1c3847f4f15b6c3929ec53c09acda6487a92" dependencies = [ "atomic-waker", - "bitflags 2.11.0", + "bitflags 2.13.2", "concurrent-queue", "cursor-icon", - "dpi", + "dpi 0.1.2", "js-sys", "pin-project", "raw-window-handle", @@ -6643,7 +7386,45 @@ dependencies = [ "wasm-bindgen-futures", "web-sys", "web-time", - "winit-core", + "winit-core 0.31.0-beta.2", +] + +[[package]] +name = "winit-web" +version = "0.31.0-beta.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c2490a953fb776fbbd5e295d54f1c3847f4f15b6c3929ec53c09acda6487a92" +dependencies = [ + "atomic-waker", + "bitflags 2.13.2", + "concurrent-queue", + "cursor-icon", + "dpi 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "js-sys", + "pin-project", + "raw-window-handle", + "smol_str", + "tracing", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "web-time", + "winit-core 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winit-win32" +version = "0.31.0-beta.2" +dependencies = [ + "bitflags 2.13.2", + "cursor-icon", + "dpi 0.1.2", + "raw-window-handle", + "smol_str", + "tracing", + "unicode-segmentation", + "windows-sys 0.59.0", + "winit-core 0.31.0-beta.2", ] [[package]] @@ -6652,15 +7433,15 @@ version = "0.31.0-beta.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "644ea78af0e858aa3b092e5d1c67c41995a98220c81813f1353b28bc8bb91eaa" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "cursor-icon", - "dpi", + "dpi 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "raw-window-handle", "smol_str", "tracing", "unicode-segmentation", "windows-sys 0.59.0", - "winit-core", + "winit-core 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -6669,19 +7450,19 @@ version = "0.31.0-beta.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa5b600756534c7041aa93cd0d244d44b09fca1b89e202bd1cd80dd9f3636c46" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "bytemuck", "calloop", "cursor-icon", - "dpi", + "dpi 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc", "percent-encoding", "raw-window-handle", "rustix 1.1.4", "smol_str", "tracing", - "winit-common", - "winit-core", + "winit-common 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winit-core 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", "x11-dl", "x11rb", "xkbcommon-dl", @@ -6772,7 +7553,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" dependencies = [ "anyhow", - "bitflags 2.11.0", + "bitflags 2.13.2", "indexmap 2.13.0", "log", "serde", @@ -6863,6 +7644,17 @@ dependencies = [ "libc", ] +[[package]] +name = "xkbcommon" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13867d259930edc7091a6c41b4ce6eee464328c6ff9659b7e4c668ca20d4c91e" +dependencies = [ + "libc", + "memmap2 0.8.0", + "xkeysym", +] + [[package]] name = "xkbcommon" version = "0.8.0" @@ -6870,7 +7662,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d66ca9352cbd4eecbbc40871d8a11b4ac8107cfc528a6e14d7c19c69d0e1ac9" dependencies = [ "libc", - "memmap2", + "memmap2 0.9.10", "xkeysym", ] @@ -6881,7 +7673,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a974f48060a14e95705c01f24ad9c3345022f4d97441b8a36beb7ed5c4a02d" dependencies = [ "libc", - "memmap2", + "memmap2 0.9.10", "xkeysym", ] @@ -6891,7 +7683,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", @@ -6903,6 +7695,9 @@ name = "xkeysym" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" +dependencies = [ + "bytemuck", +] [[package]] name = "xml-rs" @@ -7138,6 +7933,7 @@ dependencies = [ "endi", "enumflags2", "serde", + "url", "winnow 1.0.3", "zvariant_derive", "zvariant_utils", @@ -7168,3 +7964,7 @@ dependencies = [ "syn", "winnow 1.0.3", ] + +[[patch.unused]] +name = "winit-x11" +version = "0.31.0-beta.2" From f9e02f4321f11998aa91ab86409692d0999aa626 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Tue, 8 Sep 2026 15:20:10 -0700 Subject: [PATCH 39/69] Add comments to functions that iterate over surfaces These should be kept in sync with `render_input_order_internal`. --- src/shell/focus/order.rs | 2 ++ src/shell/mod.rs | 2 ++ src/state.rs | 6 ++++++ 3 files changed, 10 insertions(+) diff --git a/src/shell/focus/order.rs b/src/shell/focus/order.rs index fb904c01..b439ba89 100644 --- a/src/shell/focus/order.rs +++ b/src/shell/focus/order.rs @@ -77,6 +77,8 @@ fn render_input_order_internal( element_filter: ElementFilter, mut callback: impl FnMut(Stage) -> ControlFlow, ()>, ) -> ControlFlow, ()> { + // NOTE: Keep in sync with other surface iteration functions + if shell .zoom_state .as_ref() diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 47d78851..63186afd 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -2046,6 +2046,8 @@ impl Shell { } pub fn visible_output_for_surface(&self, surface: &WlSurface) -> Option<&Output> { + // NOTE: Keep in sync with surface iteration in `render_input_order_internal` + if let Some(session_lock) = &self.session_lock { return session_lock .surfaces diff --git a/src/state.rs b/src/state.rs index 28ed8fd4..5c1109f8 100644 --- a/src/state.rs +++ b/src/state.rs @@ -968,6 +968,8 @@ impl Common { output: &Output, render_element_states: &RenderElementStates, ) { + // NOTE: Keep in sync with surface iteration in `render_input_order_internal` + let shell = self.shell.read(); let processor = |namespace: Option| { move |surface: &WlSurface, states: &SurfaceData| { @@ -1074,6 +1076,8 @@ impl Common { render_element_states: &RenderElementStates, mut dmabuf_feedback: impl FnMut(DrmNode) -> Option, ) { + // NOTE: Keep in sync with surface iteration in `render_input_order_internal` + let shell = self.shell.read(); if let Some(session_lock) = shell.session_lock.as_ref() @@ -1287,6 +1291,8 @@ impl Common { #[profiling::function] pub fn send_frames(&self, output: &Output, sequence: Option) { + // NOTE: Keep in sync with surface iteration in `render_input_order_internal` + let time = self.clock.now(); let should_send = |surface: &WlSurface, states: &SurfaceData| { // Do the standard primary scanout output check. For pointer surfaces it deduplicates From a7349b72e39fd91d7ed25eddb2fa24b900a615d5 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Fri, 28 Aug 2026 13:14:21 -0700 Subject: [PATCH 40/69] Add `cosmic-session-lock-layer-v1` protocol https://github.com/pop-os/cosmic-protocols/pull/88 --- Cargo.lock | 154 ++++++++++---------- src/shell/focus/mod.rs | 16 +- src/shell/focus/order.rs | 89 ++++++++++- src/shell/mod.rs | 22 ++- src/state.rs | 6 + src/wayland/protocols/mod.rs | 1 + src/wayland/protocols/session_lock_layer.rs | 136 +++++++++++++++++ 7 files changed, 339 insertions(+), 85 deletions(-) create mode 100644 src/wayland/protocols/session_lock_layer.rs diff --git a/Cargo.lock b/Cargo.lock index d0a95294..93ad9171 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -74,7 +74,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef6978589202a00cd7e118380c448a08b6ed394c3a8df3a430d0898e3a42d046" dependencies = [ "android-properties", - "bitflags 2.11.0", + "bitflags 2.13.2", "cc", "cesu8", "jni", @@ -390,9 +390,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" dependencies = [ "serde_core", ] @@ -514,7 +514,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dbf9978365bac10f54d1d4b04f7ce4427e51f71d61f2fe15e3fed5166474df7" dependencies = [ "async-task", - "bitflags 2.11.0", + "bitflags 2.13.2", "futures-core", "polling", "rustix 1.1.4", @@ -765,7 +765,7 @@ name = "cosmic-comp" version = "1.0.0" dependencies = [ "anyhow", - "bitflags 2.11.0", + "bitflags 2.13.2", "calloop", "clap_lex", "cosmic-comp-config", @@ -883,9 +883,9 @@ dependencies = [ [[package]] name = "cosmic-protocols" version = "0.2.0" -source = "git+https://github.com/pop-os//cosmic-protocols?branch=main#32283d76a8d0342da74c4cc022a533c52dcf378f" +source = "git+https://github.com/pop-os//cosmic-protocols?branch=main#c0cff4db14c37ed954983158e4055aa94c7741d9" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "wayland-backend", "wayland-protocols", "wayland-protocols-wlr", @@ -940,7 +940,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", @@ -1170,7 +1170,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -1179,7 +1179,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", "objc2", ] @@ -1208,7 +1208,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", @@ -1242,7 +1242,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 0.7.1", "drm-fourcc", @@ -1255,7 +1255,7 @@ version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80bc8c5c6c2941f70a55c15f8d9f00f9710ebda3ffda98075f996a0e6c92756f" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "bytemuck", "drm-ffi 0.9.1", "drm-fourcc", @@ -1332,7 +1332,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25dd34cec49ab55d85ebf70139cb1ccd29c977ef6b6ba4fe85489d6877ee9ef3" dependencies = [ "ahash", - "bitflags 2.11.0", + "bitflags 2.13.2", "emath", "epaint", "nohash-hasher", @@ -1484,7 +1484,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]] @@ -1856,7 +1856,7 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce852e998d3ca5e4a97014fb31c940dc5ef344ec7d364984525fd11e8a547e6a" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "drm 0.14.1", "drm-fourcc", "gbm-sys", @@ -2029,7 +2029,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4f9f40651a03bc0f7316bd75267ff5767e93017ef3cfffe76c6aa7252cc5a31c" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "bytemuck", "core_maths", "read-fonts 0.37.0", @@ -2240,7 +2240,7 @@ name = "iced_core" version = "0.14.0" source = "git+https://github.com/pop-os/libcosmic#d922ac380134c00208d2acf93947d44fb217eec5" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "bytes", "dnd", "glam 0.25.0", @@ -2287,7 +2287,7 @@ name = "iced_graphics" version = "0.14.0" source = "git+https://github.com/pop-os/libcosmic#d922ac380134c00208d2acf93947d44fb217eec5" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "bytemuck", "cosmic-text", "half", @@ -2361,7 +2361,7 @@ version = "0.14.0" source = "git+https://github.com/pop-os/libcosmic#d922ac380134c00208d2acf93947d44fb217eec5" dependencies = [ "as-raw-xcb-connection", - "bitflags 2.11.0", + "bitflags 2.13.2", "bytemuck", "cryoglyph", "futures", @@ -2590,7 +2590,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "inotify-sys", "libc", ] @@ -2610,7 +2610,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9793345a65d71317763a33066b5d8351f8760dde8d4930fe9e39b5f14a7959d" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "input-sys", "libc", "log", @@ -2671,7 +2671,7 @@ dependencies = [ "portable-atomic", "portable-atomic-util", "serde_core", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -2768,7 +2768,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", ] @@ -2794,7 +2794,7 @@ version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a1886916523694cd6ea3d175f03a1e5010699a2a4cc13696d83d7bea1d80638" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -2912,7 +2912,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59fd96dbb2381ff31f314f07accbdf8550febdcc5cd8761ecaf7c1763361c359" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "libc", "libdisplay-info-derive", "libdisplay-info-sys", @@ -2962,7 +2962,7 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "libc", "redox_syscall 0.7.2", ] @@ -3302,7 +3302,7 @@ checksum = "618f667225063219ddfc61251087db8a9aec3c3f0950c916b614e403486f1135" dependencies = [ "arrayvec", "bit-set", - "bitflags 2.11.0", + "bitflags 2.13.2", "cfg-if", "cfg_aliases", "codespan-reporting", @@ -3325,7 +3325,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", "log", "ndk-sys", @@ -3355,7 +3355,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "cfg-if", "cfg_aliases", "libc", @@ -3383,7 +3383,7 @@ version = "8.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d3d07927151ff8575b7087f245456e549fea62edf0ec4e565a5ee50c8402bc3" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "fsevent-sys", "inotify", "kqueue", @@ -3401,7 +3401,7 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42b8cfee0e339a0337359f3c88165702ac6e600dc01c0cc9579a92d62b08477a" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", ] [[package]] @@ -3410,7 +3410,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]] @@ -3550,7 +3550,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", "objc2", "objc2-core-foundation", "objc2-foundation", @@ -3562,7 +3562,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", "dispatch2", "objc2", @@ -3574,7 +3574,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", "libc", "objc2-core-foundation", ] @@ -3585,7 +3585,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-core-foundation", "objc2-core-graphics", ] @@ -3602,7 +3602,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", "objc2", "objc2-core-foundation", @@ -3614,7 +3614,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", "objc2-core-foundation", "objc2-foundation", @@ -3959,7 +3959,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", @@ -4233,7 +4233,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]] @@ -4242,7 +4242,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d94dd2f7cd932d4dc02cc8b2b50dfd38bd079a4e5d79198b99743d7fcf9a4b4" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", ] [[package]] @@ -4370,7 +4370,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db09040cc89e461f1a265139777a2bde7f8d8c67c4936f700c63ce3e2904d468" dependencies = [ "base64 0.22.1", - "bitflags 2.11.0", + "bitflags 2.13.2", "serde", "serde_derive", "unicode-ident", @@ -4382,7 +4382,7 @@ version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd490c5b18261893f14449cbd28cb9c0b637aebf161cd77900bfdedaff21ec32" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "once_cell", "serde", "serde_derive", @@ -4460,7 +4460,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", @@ -4473,11 +4473,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]] @@ -4492,7 +4492,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", @@ -4777,7 +4777,7 @@ dependencies = [ "aliasable", "appendlist", "ash", - "bitflags 2.11.0", + "bitflags 2.13.2", "calloop", "cc", "cursor-icon", @@ -4830,7 +4830,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", "calloop", "calloop-wayland-source", "cursor-icon", @@ -5064,7 +5064,7 @@ dependencies = [ "getrandom 0.4.1", "once_cell", "rustix 1.1.4", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -5758,7 +5758,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 2.13.0", "semver", @@ -5798,7 +5798,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", @@ -5810,7 +5810,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", ] @@ -5842,7 +5842,7 @@ version = "0.32.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23d0c813de3daa2ed6520af85a3bd49b0e722a3078506899aa9686fea58dc4b6" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "wayland-backend", "wayland-client", "wayland-scanner", @@ -5855,7 +5855,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", @@ -5868,7 +5868,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", @@ -5882,7 +5882,7 @@ version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa98634619300a535a9a97f338aed9a5ff1e01a461943e8346ff4ae26007306b" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "wayland-backend", "wayland-client", "wayland-protocols", @@ -5895,7 +5895,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", @@ -5920,7 +5920,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", @@ -5972,7 +5972,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", @@ -5998,7 +5998,7 @@ dependencies = [ "arrayvec", "bit-set", "bit-vec", - "bitflags 2.11.0", + "bitflags 2.13.2", "bytemuck", "cfg_aliases", "document-features", @@ -6034,7 +6034,7 @@ version = "28.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44d6cb474beb218824dcc9e1ce679d973f719262789bfb27407da560cac20eeb" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "cfg-if", "cfg_aliases", "libloading", @@ -6054,7 +6054,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", @@ -6083,7 +6083,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.48.0", ] [[package]] @@ -6469,7 +6469,7 @@ version = "0.31.0-beta.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2879d2854d1a43e48f67322d4bd097afcb6eb8f8f775c8de0260a71aea1df1aa" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "cfg_aliases", "cursor-icon", "dpi", @@ -6497,7 +6497,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d9c0d2cd93efec3a9f9ad819cfaf0834782403af7c0d248c784ec0c61761df" dependencies = [ "android-activity", - "bitflags 2.11.0", + "bitflags 2.13.2", "dpi", "ndk", "raw-window-handle", @@ -6512,7 +6512,7 @@ version = "0.31.0-beta.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21310ca07851a49c348e0c2cc768e36b52ca65afda2c2354d78ed4b90074d8aa" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "block2", "dispatch2", "dpi", @@ -6551,7 +6551,7 @@ version = "0.31.0-beta.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4f0ccd7abb43740e2c6124ac7cae7d865ecec74eec63783e8922577ac232583" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "cursor-icon", "dpi", "keyboard-types", @@ -6566,7 +6566,7 @@ version = "0.31.0-beta.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51ea1fb262e7209f265f12bd0cc792c399b14355675e65531e9c8a87db287d46" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "dpi", "orbclient", "raw-window-handle", @@ -6582,7 +6582,7 @@ version = "0.31.0-beta.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "680a356e798837d8eb274d4556e83bceaf81698194e31aafc5cfb8a9f2fab643" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "block2", "dispatch2", "dpi", @@ -6604,7 +6604,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ce5afb2ba07da603f84b722c95f9f9396d2cedae3944fb6c0cda4a6f88de545" dependencies = [ "ahash", - "bitflags 2.11.0", + "bitflags 2.13.2", "calloop", "cursor-icon", "dpi", @@ -6630,7 +6630,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c2490a953fb776fbbd5e295d54f1c3847f4f15b6c3929ec53c09acda6487a92" dependencies = [ "atomic-waker", - "bitflags 2.11.0", + "bitflags 2.13.2", "concurrent-queue", "cursor-icon", "dpi", @@ -6652,7 +6652,7 @@ version = "0.31.0-beta.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "644ea78af0e858aa3b092e5d1c67c41995a98220c81813f1353b28bc8bb91eaa" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "cursor-icon", "dpi", "raw-window-handle", @@ -6669,7 +6669,7 @@ version = "0.31.0-beta.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa5b600756534c7041aa93cd0d244d44b09fca1b89e202bd1cd80dd9f3636c46" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "bytemuck", "calloop", "cursor-icon", @@ -6772,7 +6772,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" dependencies = [ "anyhow", - "bitflags 2.11.0", + "bitflags 2.13.2", "indexmap 2.13.0", "log", "serde", @@ -6891,7 +6891,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/src/shell/focus/mod.rs b/src/shell/focus/mod.rs index f631372e..fe8f772a 100644 --- a/src/shell/focus/mod.rs +++ b/src/shell/focus/mod.rs @@ -2,12 +2,15 @@ use crate::{ shell::{CosmicSurface, MinimizedWindow, Shell, Trigger, element::CosmicMapped}, state::{Common, State}, utils::prelude::*, - wayland::handlers::{xdg_shell::PopupGrabData, xwayland_keyboard_grab::XWaylandGrabSeatData}, + wayland::{ + handlers::{xdg_shell::PopupGrabData, xwayland_keyboard_grab::XWaylandGrabSeatData}, + protocols::session_lock_layer::layer_show_on_lock, + }, }; use indexmap::IndexSet; use smithay::{ backend::input::InputTime, - desktop::{PopupUngrabStrategy, layer_map_for_output}, + desktop::{PopupUngrabStrategy, find_popup_root_surface, layer_map_for_output}, input::{Seat, pointer::MotionEvent}, output::Output, reexports::wayland_server::{Resource, protocol::wl_surface::WlSurface}, @@ -627,8 +630,15 @@ fn focus_target_is_valid( output: &Output, target: KeyboardFocusTarget, ) -> bool { - // If a session lock is active, only lock surfaces can be focused + // If a session lock is active, only lock surfaces and lock layers can be focused if shell.session_lock.is_some() { + if let KeyboardFocusTarget::LayerSurface(layer) = &target { + return layer_show_on_lock(layer.wl_surface()); + } else if let KeyboardFocusTarget::Popup(popup) = &target + && let Ok(root) = find_popup_root_surface(popup) + { + return layer_show_on_lock(&root); + } return matches!(target, KeyboardFocusTarget::LockSurface(_)); } diff --git a/src/shell/focus/order.rs b/src/shell/focus/order.rs index b439ba89..937fa311 100644 --- a/src/shell/focus/order.rs +++ b/src/shell/focus/order.rs @@ -22,7 +22,7 @@ use crate::{ prelude::OutputExt, quirks::{WORKSPACE_OVERVIEW_NAMESPACE, workspace_overview_is_open}, }, - wayland::protocols::workspace::WorkspaceHandle, + wayland::protocols::{session_lock_layer::layer_show_on_lock, workspace::WorkspaceHandle}, }; pub enum Stage<'a> { @@ -89,7 +89,92 @@ fn render_input_order_internal( // Session Lock if let Some(session_lock) = &shell.session_lock { - return callback(Stage::SessionLock(session_lock.surfaces.get(output))); + for (layer, popup, location) in layer_popups(output, Layer::Overlay, element_filter) { + if !layer_show_on_lock(layer.wl_surface()) { + continue; + } + callback(Stage::LayerPopup { + layer, + popup: &popup, + location, + workspace_idx: current.1, + })?; + } + for (layer, location) in layer_surfaces(output, Layer::Overlay, element_filter) { + if !layer_show_on_lock(layer.wl_surface()) { + continue; + } + callback(Stage::LayerSurface { + layer, + location, + workspace_idx: current.1, + })?; + } + for (layer, popup, location) in layer_popups(output, Layer::Top, element_filter) { + if !layer_show_on_lock(layer.wl_surface()) { + continue; + } + callback(Stage::LayerPopup { + layer, + popup: &popup, + location, + workspace_idx: current.1, + })?; + } + for (layer, location) in layer_surfaces(output, Layer::Top, element_filter) { + if !layer_show_on_lock(layer.wl_surface()) { + continue; + } + callback(Stage::LayerSurface { + layer, + location, + workspace_idx: current.1, + })?; + } + callback(Stage::SessionLock(session_lock.surfaces.get(output)))?; + for (layer, popup, location) in layer_popups(output, Layer::Bottom, element_filter) { + if !layer_show_on_lock(layer.wl_surface()) { + continue; + } + callback(Stage::LayerPopup { + layer, + popup: &popup, + location, + workspace_idx: current.1, + })?; + } + for (layer, popup, location) in layer_popups(output, Layer::Background, element_filter) { + if !layer_show_on_lock(layer.wl_surface()) { + continue; + } + callback(Stage::LayerPopup { + layer, + popup: &popup, + location, + workspace_idx: current.1, + })?; + } + for (layer, location) in layer_surfaces(output, Layer::Bottom, element_filter) { + if !layer_show_on_lock(layer.wl_surface()) { + continue; + } + callback(Stage::LayerSurface { + layer, + location, + workspace_idx: current.1, + })?; + } + for (layer, location) in layer_surfaces(output, Layer::Background, element_filter) { + if !layer_show_on_lock(layer.wl_surface()) { + continue; + } + callback(Stage::LayerSurface { + layer, + location, + workspace_idx: current.1, + })?; + } + return ControlFlow::Continue(()); } // Overlay-level layer shell diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 63186afd..8439b13f 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -19,7 +19,10 @@ use crate::{ utils, wayland::{ handlers::data_device::{self, get_dnd_icon}, - protocols::workspace::{State as WState, WorkspaceCapabilities}, + protocols::{ + session_lock_layer::layer_show_on_lock, + workspace::{State as WState, WorkspaceCapabilities}, + }, }, }; use cosmic_comp_config::{ @@ -2049,11 +2052,24 @@ impl Shell { // NOTE: Keep in sync with surface iteration in `render_input_order_internal` if let Some(session_lock) = &self.session_lock { - return session_lock + if let Some((output, _)) = session_lock .surfaces .iter() .find(|(_, v)| v.wl_surface() == surface) - .map(|(k, _)| k); + { + return Some(output); + } + for o in self.outputs() { + let map = layer_map_for_output(o); + if let Some(layer_surface) = map.layer_for_surface(surface, WindowSurfaceType::ALL) + { + if layer_show_on_lock(layer_surface.wl_surface()) { + return Some(o); + } else { + return None; + } + } + } } self.outputs() diff --git a/src/state.rs b/src/state.rs index 5c1109f8..d605c736 100644 --- a/src/state.rs +++ b/src/state.rs @@ -23,6 +23,7 @@ use crate::{ output_configuration::OutputConfigurationState, output_power::OutputPowerState, overlap_notify::OverlapNotifyState, + session_lock_layer::SessionLockLayerState, toplevel_info::ToplevelInfoState, toplevel_management::{ManagementCapabilities, ToplevelManagementState}, workspace::{WorkspaceState, WorkspaceUpdateGuard}, @@ -320,6 +321,7 @@ pub struct Common { pub xwayland_state: Option, pub xwayland_shell_state: XWaylandShellState, pub pointer_focus_state: Option, + pub session_lock_layer_state: SessionLockLayerState, #[cfg(feature = "logind")] pub inhibit_lid_fd: Option, @@ -763,6 +765,9 @@ impl State { let dbus_state = DBusState::init(&handle); + let session_lock_layer_state = + SessionLockLayerState::new::(dh, client_not_sandboxed); + State { common: Common { config, @@ -830,6 +835,7 @@ impl State { pointer_focus_state: None, dbus_state, keyboard_layout_state, + session_lock_layer_state, #[cfg(feature = "logind")] inhibit_lid_fd: None, diff --git a/src/wayland/protocols/mod.rs b/src/wayland/protocols/mod.rs index c6c0234a..48aa8337 100644 --- a/src/wayland/protocols/mod.rs +++ b/src/wayland/protocols/mod.rs @@ -8,6 +8,7 @@ pub mod keyboard_layout; pub mod output_configuration; pub mod output_power; pub mod overlap_notify; +pub mod session_lock_layer; pub mod toplevel_info; pub mod toplevel_management; pub mod workspace; diff --git a/src/wayland/protocols/session_lock_layer.rs b/src/wayland/protocols/session_lock_layer.rs new file mode 100644 index 00000000..85edda50 --- /dev/null +++ b/src/wayland/protocols/session_lock_layer.rs @@ -0,0 +1,136 @@ +use cosmic_protocols::session_lock_layer::v1::server::cosmic_session_lock_layer_manager_v1; +use smithay::{ + reexports::wayland_server::{ + Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New, backend::GlobalId, + protocol::wl_surface, + }, + wayland::{ + Dispatch2, GlobalDispatch2, + compositor::{Cacheable, with_states}, + shell::wlr_layer::WlrLayerShellHandler, + }, +}; + +struct SessionLockLayerData; + +#[derive(Debug)] +pub struct SessionLockLayerState { + global: GlobalId, +} + +impl SessionLockLayerState { + pub fn new(dh: &DisplayHandle, client_filter: F) -> Self + where + F: for<'a> Fn(&'a Client) -> bool + Clone + Send + Sync + 'static, + D: GlobalDispatch< + cosmic_session_lock_layer_manager_v1::CosmicSessionLockLayerManagerV1, + SessionLockLayerGlobalData, + > + 'static, + { + let global = dh + .create_global::( + 1, + SessionLockLayerGlobalData { + filter: Box::new(client_filter.clone()), + }, + ); + Self { global } + } + + pub fn global_id(&self) -> GlobalId { + self.global.clone() + } +} + +#[doc(hidden)] +pub struct SessionLockLayerGlobalData { + filter: Box Fn(&'a Client) -> bool + Send + Sync>, +} + +impl GlobalDispatch2 + for SessionLockLayerGlobalData +where + D: Dispatch< + cosmic_session_lock_layer_manager_v1::CosmicSessionLockLayerManagerV1, + SessionLockLayerData, + >, +{ + fn bind( + &self, + _state: &mut D, + _handle: &DisplayHandle, + _client: &Client, + resource: New, + data_init: &mut DataInit<'_, D>, + ) { + data_init.init(resource, SessionLockLayerData); + } + + fn can_view(&self, client: &Client) -> bool { + (self.filter)(client) + } +} + +#[derive(Clone, Copy, Default)] +struct SessionLockLayerSurfaceData { + show_on_lock: bool, +} + +impl Cacheable for SessionLockLayerSurfaceData { + fn commit(&mut self, _dh: &DisplayHandle) -> Self { + *self + } + + fn merge_into(self, into: &mut Self, _dh: &DisplayHandle) { + *into = self; + } +} + +pub fn layer_show_on_lock(wl_surface: &wl_surface::WlSurface) -> bool { + with_states(wl_surface, |states| { + if states.cached_state.has::() { + let mut state = states.cached_state.get::(); + state.current().show_on_lock + } else { + false + } + }) +} + +impl Dispatch2 + for SessionLockLayerData +where + D: WlrLayerShellHandler, +{ + fn request( + &self, + state: &mut D, + _: &Client, + _: &cosmic_session_lock_layer_manager_v1::CosmicSessionLockLayerManagerV1, + request: cosmic_session_lock_layer_manager_v1::Request, + _: &DisplayHandle, + _: &mut DataInit<'_, D>, + ) { + let (layer, value) = match request { + cosmic_session_lock_layer_manager_v1::Request::SetShowOnLock { layer } => (layer, true), + cosmic_session_lock_layer_manager_v1::Request::UnsetShowOnLock { layer } => { + (layer, false) + } + cosmic_session_lock_layer_manager_v1::Request::Destroy => { + return; + } + _ => unreachable!(), + }; + + if let Some(layer) = state + .shell_state() + .layer_surfaces() + .find(|surface| surface.shell_surface() == &layer) + { + with_states(layer.wl_surface(), |states| { + let mut state = states.cached_state.get::(); + state.pending().show_on_lock = value; + }); + } + } +} From 651f701f84e46d0262a129cb9ac30537d648cb08 Mon Sep 17 00:00:00 2001 From: Hojjat Date: Thu, 10 Sep 2026 15:08:32 -0600 Subject: [PATCH 41/69] shell/focus: Don't dismiss grabbing popups of exclusive layer surfaces --- src/shell/focus/mod.rs | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/shell/focus/mod.rs b/src/shell/focus/mod.rs index fe8f772a..dcfd55de 100644 --- a/src/shell/focus/mod.rs +++ b/src/shell/focus/mod.rs @@ -10,7 +10,10 @@ use crate::{ use indexmap::IndexSet; use smithay::{ backend::input::InputTime, - desktop::{PopupUngrabStrategy, find_popup_root_surface, layer_map_for_output}, + desktop::{ + LayerSurface, PopupUngrabStrategy, WindowSurfaceType, find_popup_root_surface, + layer_map_for_output, + }, input::{Seat, pointer::MotionEvent}, output::Output, reexports::wayland_server::{Resource, protocol::wl_surface::WlSurface}, @@ -644,12 +647,28 @@ fn focus_target_is_valid( // If an exclusive layer shell surface exists (on any output), only exclusive // shell surfaces can have focus, on the highest layer with exclusive surfaces. + // Popups are judged by their root surface, so an exclusive surface can + // still open grabbing popups (menus, dropdowns, context menus). if let Some(layer) = exclusive_layer_surface_layer(shell) { - return if let KeyboardFocusTarget::LayerSurface(layer_surface) = target { + let is_exclusive_on_layer = |layer_surface: &LayerSurface| { let data = layer_surface.cached_state(); (data.keyboard_interactivity, data.layer) == (KeyboardInteractivity::Exclusive, layer) - } else { - false + }; + return match target { + KeyboardFocusTarget::LayerSurface(layer_surface) => { + is_exclusive_on_layer(&layer_surface) + } + KeyboardFocusTarget::Popup(popup) => find_popup_root_surface(&popup) + .ok() + .and_then(|root| { + shell.outputs().find_map(|o| { + layer_map_for_output(o) + .layer_for_surface(&root, WindowSurfaceType::ALL) + .map(&is_exclusive_on_layer) + }) + }) + .unwrap_or(false), + _ => false, }; } From cd881a4df28f99bf1fefc5823f755ee646b9e12a Mon Sep 17 00:00:00 2001 From: Flori Ava Star Weber Date: Fri, 18 Sep 2026 17:09:07 +0200 Subject: [PATCH 42/69] cli: change incorrect text `-v` to `-V` --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index aa31a464..98bfa2a3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -289,7 +289,7 @@ Project home page: https://github.com/pop-os/cosmic-comp Options: -h, --help Show this message --no-xwayland Run without Xwayland - -v, --version Show the version of cosmic-comp"# + -V, --version Show the version of cosmic-comp"# ); } From 26daf75d93695d3ecd9418f4cfe8e0564ddc53db Mon Sep 17 00:00:00 2001 From: Hojjat Date: Thu, 10 Sep 2026 17:43:41 -0600 Subject: [PATCH 43/69] fix: forward release for modifier-only bindings --- src/input/mod.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/input/mod.rs b/src/input/mod.rs index 45586b03..c48fea8d 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -2096,6 +2096,21 @@ impl State { backend_id, seat, modifiers, handle, serial, keycode, key_state, time, ); + // A modifier-only binding fires on the modifier's release, but its press was already + // forwarded. Forward the release too. + if key_state == KeyState::Released + && matches!(&result, FilterResult::Intercept(Some((_, binding))) if binding.key.is_none()) + { + seat.get_keyboard().unwrap().input_forward( + self, + keycode, + key_state, + serial, + time, + previous_modifiers != *modifiers, + ); + } + if (matches!(result, FilterResult::Forward) && !seat.get_keyboard().unwrap().is_grabbed() && !shortcuts_inhibited From 50c170c355386f91415b7579b1342ad2e4a7f226 Mon Sep 17 00:00:00 2001 From: Hojjat Date: Tue, 15 Sep 2026 17:35:18 -0600 Subject: [PATCH 44/69] fix: only cancel grabs the compositor started for its own interactions --- src/input/mod.rs | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/input/mod.rs b/src/input/mod.rs index c48fea8d..af160ae2 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -19,7 +19,7 @@ use crate::{ Stage, render_input_order, target::{KeyboardFocusTarget, PointerFocusTarget}, }, - grabs::{ReleaseMode, ResizeEdge}, + grabs::{MenuGrab, MoveGrab, ReleaseMode, ResizeEdge, ResizeGrab}, layout::{ floating::ResizeGrabMarker, tiling::{NodeDesc, SwapWindowGrab, TilingLayout}, @@ -49,7 +49,7 @@ use smithay::{ PointerAxisEvent, ProximityState, TabletToolButtonEvent, TabletToolEvent, TabletToolProximityEvent, TabletToolTipEvent, TabletToolTipState, TouchEvent, }, - desktop::{PopupKeyboardGrab, WindowSurfaceType, utils::under_from_surface_tree}, + desktop::{WindowSurfaceType, utils::under_from_surface_tree}, input::{ Seat, keyboard::KeyboardHandle, @@ -2306,17 +2306,15 @@ impl State { let keyboard = seat.get_keyboard().unwrap(); let pointer = seat.get_pointer().unwrap(); - // We're only interested in filtering keyboard grabs if we initiated them. - // The easiest way to check that is to check the type of the grab. - let keyboard_grabbed = keyboard.with_grab(|_serial, grab| { - grab.is::() || grab.is::>() + // Escape only cancels grabs the compositor started for its own interactions + // For keyboard: SwapWindowGrab + // For pointer: MoveGrab, ResizeGrab, and MenuGrab + let keyboard_grabbed = + keyboard.with_grab(|_serial, grab| grab.is::()) == Some(true); + let pointer_grabbed = pointer.with_grab(|_serial, grab| { + grab.is::() || grab.is::() || grab.is::() }) == Some(true); - // A virtual-keyboard key can arrive while the seat's pointer is grabbed by that - // same on-screen keyboard's own button press (the implicit grab from clicking an OSK - // key). That pointer grab must not capture the injected key, otherwise e.g. - // pressing esc on a virtual keyboard gets swallowed here - let from_vk = matches!(backend_id, InputBackendId::VirtualKeyboard); - let is_grabbed = keyboard_grabbed || (pointer.is_grabbed() && !from_vk); + let is_grabbed = keyboard_grabbed || pointer_grabbed; let current_focus = keyboard.current_focus(); //this should fall back to active output since there may not be a focused output From d36480c1b5e39869259e6477fe8bc42bf900254f Mon Sep 17 00:00:00 2001 From: Hojjat Date: Thu, 17 Sep 2026 12:41:15 -0600 Subject: [PATCH 45/69] fix: only unmaximize on activation if `maximized != target` --- src/wayland/handlers/xdg_activation.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wayland/handlers/xdg_activation.rs b/src/wayland/handlers/xdg_activation.rs index ad8ce0d0..38ba6219 100644 --- a/src/wayland/handlers/xdg_activation.rs +++ b/src/wayland/handlers/xdg_activation.rs @@ -243,7 +243,7 @@ impl State { { for mapped in current_workspace .mapped() - .filter(|m| m.maximized_state.lock().unwrap().is_some()) + .filter(|m| m.maximized_state.lock().unwrap().is_some() && *m != &element) .cloned() .collect::>() .into_iter() From 0fbd4574ef4caf74769a617d205fd1fc909ac9b1 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Tue, 22 Sep 2026 14:41:11 -0400 Subject: [PATCH 46/69] fix: skip loading shortcuts for kiosk mode --- src/config/mod.rs | 70 ++++++++++++++++++++++++++--------------------- src/state.rs | 2 +- 2 files changed, 40 insertions(+), 32 deletions(-) diff --git a/src/config/mod.rs b/src/config/mod.rs index 4d2fad9b..f8a51585 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -172,7 +172,7 @@ pub enum ColorFilter { } impl Config { - pub fn load(loop_handle: &LoopHandle<'_, State>) -> Config { + pub fn load(loop_handle: &LoopHandle<'_, State>, kiosk_mode: bool) -> Config { let config = cosmic_config::Config::new("com.system76.CosmicComp", 1).unwrap(); let source = cosmic_config::calloop::ConfigWatchSource::new(&config).unwrap(); loop_handle @@ -248,40 +248,48 @@ impl Config { // Source key bindings from com.system76.CosmicSettings.Shortcuts let settings_context = shortcuts::context().expect("Failed to load shortcuts config"); - let system_actions = shortcuts::system_actions(&settings_context); - let shortcuts = shortcuts::shortcuts(&settings_context); + let mut system_actions = Default::default(); + let mut shortcuts = Default::default(); + // Kiosk mode disables shortcuts + if !kiosk_mode { + system_actions = shortcuts::system_actions(&settings_context); + shortcuts = shortcuts::shortcuts(&settings_context); - // Listen for updates to the keybindings config. - match cosmic_config::calloop::ConfigWatchSource::new(&settings_context) { - Ok(source) => { - if let Err(err) = loop_handle.insert_source(source, |(config, keys), (), state| { - for key in keys { - match key.as_str() { - // Reload the keyboard shortcuts config. - "custom" | "defaults" => { - state.common.config.shortcuts = shortcuts::shortcuts(&config); + // Listen for updates to the keybindings config. + match cosmic_config::calloop::ConfigWatchSource::new(&settings_context) { + Ok(source) => { + if let Err(err) = + loop_handle.insert_source(source, |(config, keys), (), state| { + for key in keys { + match key.as_str() { + // Reload the keyboard shortcuts config. + "custom" | "defaults" => { + state.common.config.shortcuts = + shortcuts::shortcuts(&config); + } + + "system_actions" => { + state.common.config.system_actions = + shortcuts::system_actions(&config); + } + + _ => (), + } } - - "system_actions" => { - state.common.config.system_actions = - shortcuts::system_actions(&config); - } - - _ => (), - } + }) + { + warn!( + ?err, + "Failed to watch com.system76.CosmicSettings.Shortcuts config" + ); } - }) { - warn!( - ?err, - "Failed to watch com.system76.CosmicSettings.Shortcuts config" - ); } - } - Err(err) => warn!( - ?err, - "failed to create config watch source for com.system76.CosmicSettings.Shortcuts" - ), - }; + Err(err) => warn!( + ?err, + "failed to create config watch source for com.system76.CosmicSettings.Shortcuts" + ), + }; + } let window_rules_context = window_rules::context().expect("Failed to load window rules config"); diff --git a/src/state.rs b/src/state.rs index d605c736..86f5e23e 100644 --- a/src/state.rs +++ b/src/state.rs @@ -667,7 +667,7 @@ impl State { .unwrap(); let clock = Clock::new(); - let config = Config::load(&handle); + let config = Config::load(&handle, kiosk_command.is_some()); let compositor_state = CompositorState::new::(dh); let corner_radius_state = CornerRadiusState::new::(dh); let data_device_state = DataDeviceState::new::(dh); From 6645edff6406eb7a28ec1457162e5883b269bfc6 Mon Sep 17 00:00:00 2001 From: Hojjat Date: Wed, 9 Sep 2026 14:57:29 -0600 Subject: [PATCH 47/69] fix: clear sticky windows, or floating windows focus hint if focus moves --- src/shell/element/mod.rs | 4 ++++ src/shell/focus/mod.rs | 13 +++++++++++-- src/shell/mod.rs | 7 +++++++ src/shell/workspace.rs | 26 ++++++++++++++++++-------- 4 files changed, 40 insertions(+), 10 deletions(-) diff --git a/src/shell/element/mod.rs b/src/shell/element/mod.rs index d4743b7f..c7e799be 100644 --- a/src/shell/element/mod.rs +++ b/src/shell/element/mod.rs @@ -430,6 +430,10 @@ impl CosmicMapped { } } + pub fn is_sticky(&self) -> bool { + self.active_window().is_sticky() + } + pub fn pending_size(&self) -> Option> { match &self.element { CosmicMappedInternal::Stack(s) => s.pending_size(), diff --git a/src/shell/focus/mod.rs b/src/shell/focus/mod.rs index dcfd55de..8b2348eb 100644 --- a/src/shell/focus/mod.rs +++ b/src/shell/focus/mod.rs @@ -255,8 +255,17 @@ impl Shell { let workspace = if let Some(workspace) = workspace { self.workspaces.space_for_handle_mut(&workspace.0).unwrap() } else { - //should this be the active output or the focused output? - self.active_space_mut(&seat.focused_or_active_output()) + let output = match &target { + FocusTarget::Window(mapped) => self + .workspaces + .sets + .iter() + .find(|(_, set)| set.sticky_layer.mapped().any(|m| m == mapped)) + .map(|(output, _)| output.clone()), + FocusTarget::Fullscreen(_) => None, + }; + + self.active_space_mut(&output.unwrap_or_else(|| seat.active_output())) .unwrap() }; diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 8439b13f..10b40b59 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -516,6 +516,12 @@ impl WorkspaceSet { } } + fn refresh_focus_stacks(&mut self) { + for workspace in &mut self.workspaces { + workspace.refresh_focus_stack(); + } + } + fn activate( &mut self, idx: usize, @@ -620,6 +626,7 @@ impl WorkspaceSet { self.workspaces[self.active].refresh(); } self.sticky_layer.refresh(); + self.refresh_focus_stacks(); } fn add_empty_workspace(&mut self, state: &mut WorkspaceUpdateGuard) { diff --git a/src/shell/workspace.rs b/src/shell/workspace.rs index 84a020ff..fd63dcb1 100644 --- a/src/shell/workspace.rs +++ b/src/shell/workspace.rs @@ -526,10 +526,16 @@ impl Workspace { .mapped() .chain(self.tiling_layer.mapped().map(|(w, _)| w)) .chain(move_mapped.iter()) + .chain( + self.minimized_windows + .iter() + .flat_map(MinimizedWindow::mapped), + ) }; stack.retain(|w| match w { FocusTarget::Fullscreen(s) => fullscreen_surfaces.contains(&s), - FocusTarget::Window(w) => mapped().any(|m| w == m), + // Sticky windows live in the `WorkspaceSet` but are shown on whichever workspace is current + FocusTarget::Window(w) => w.is_sticky() || mapped().any(|m| w == m), }); } } @@ -1767,13 +1773,17 @@ impl Workspace { self.floating_layer.render( renderer, - focused.as_ref().and_then(|target| { - if let FocusTarget::Window(mapped) = target { - Some(mapped) - } else { - None - } - }), + render_focus + .then(|| { + focused.as_ref().and_then(|target| { + if let FocusTarget::Window(mapped) = target { + Some(mapped) + } else { + None + } + }) + }) + .flatten(), resize_indicator.clone(), indicator_thickness, alpha, From 58837e27b8bcd022a7d8702c0a8de788777e42be Mon Sep 17 00:00:00 2001 From: Hojjat Date: Tue, 15 Sep 2026 17:03:49 -0600 Subject: [PATCH 48/69] fix: send pointer leave to root menu if no sub menu is open --- src/shell/grabs/menu/mod.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/shell/grabs/menu/mod.rs b/src/shell/grabs/menu/mod.rs index dafbd6cc..b9adf8f3 100644 --- a/src/shell/grabs/menu/mod.rs +++ b/src/shell/grabs/menu/mod.rs @@ -578,10 +578,12 @@ impl PointerGrab for MenuGrab { PointerTarget::motion(&element.iced, &self.seat, state, &new_event); } } else { + // Keep the root menu hovered while a submenu is open + let keep_root = usize::from(elements.len() > 1); elements .iter_mut() .filter(|element| element.pointer_entered) - .skip(1) + .skip(keep_root) .for_each(|element| { PointerTarget::leave( &element.iced, @@ -1019,10 +1021,11 @@ impl TabletToolGrab for MenuGrab { ); self.last_tablet_idx = Some(i); } else { + let keep_root = usize::from(elements.len() > 1); elements .iter_mut() .filter(|element| element.tablet_entered.is_some()) - .skip(1) + .skip(keep_root) .for_each(|element| { TabletToolTarget::proximity_out( &element.iced, From f60d2c84368d292be761fcaac744510359bd19c2 Mon Sep 17 00:00:00 2001 From: Hojjat Date: Tue, 15 Sep 2026 17:04:13 -0600 Subject: [PATCH 49/69] fix: remove the hovered state from menu item on pointer leave --- src/utils/iced/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/utils/iced/mod.rs b/src/utils/iced/mod.rs index 4522644b..8baf87f9 100644 --- a/src/utils/iced/mod.rs +++ b/src/utils/iced/mod.rs @@ -519,6 +519,7 @@ impl TabletToolTarget for Iced _tool_descriptor: &TabletToolDescriptor, ) { let mut internal = self.0.lock().unwrap(); + internal.cursor_pos = None; internal .state .queue_event(Event::Mouse(MouseEvent::CursorLeft)); @@ -728,6 +729,7 @@ impl PointerTarget for IcedEle _time: InputTime, ) { let mut internal = self.0.lock().unwrap(); + internal.cursor_pos = None; internal .state .queue_event(Event::Mouse(MouseEvent::CursorLeft)); From e5010c23c9f2091d0336ba870ebc84012f7fe399 Mon Sep 17 00:00:00 2001 From: dev-goalz <3825354+dev-goalz@users.noreply.github.com> Date: Mon, 21 Sep 2026 18:00:15 +0200 Subject: [PATCH 50/69] fix: don't wake displays on input device removal, count input wakes as activity A sleeping wireless keyboard relit blanked displays and idle never re-armed. Written with assistance from Claude Opus 5.0. Reviewed, built and tested by the author, who understands the changes in full. --- src/input/mod.rs | 11 ++++++++++- src/wayland/handlers/output_power.rs | 5 +++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/input/mod.rs b/src/input/mod.rs index af160ae2..7bf350a5 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -220,7 +220,16 @@ impl State { ) where ::Device: 'static, { - crate::wayland::handlers::output_power::set_all_surfaces_dpms_on(self); + // An input device going away is not user activity, e.g. a wireless keyboard + // dropping its link when it sleeps, so it must not power displays back on. + // Device additions still wake: after a system resume the re-enumerated + // devices may be the only input seen, and the wake resets idle anyway. + if !matches!( + &event, + InputEvent::DeviceRemoved { .. } | InputEvent::Special(_) + ) { + crate::wayland::handlers::output_power::set_all_surfaces_dpms_on(self); + } use smithay::backend::input::Event; match event { diff --git a/src/wayland/handlers/output_power.rs b/src/wayland/handlers/output_power.rs index 2675009a..333aacc6 100644 --- a/src/wayland/handlers/output_power.rs +++ b/src/wayland/handlers/output_power.rs @@ -21,6 +21,11 @@ pub fn set_all_surfaces_dpms_on(state: &mut State) { } if changed { + // Powering an output on because of input is activity. Without this the idle + // notifier stays idled, the idle daemon never sees `resumed`, and nothing + // powers the output off again until real input arrives. + let seat = state.common.shell.read().seats.last_active().clone(); + state.common.idle_notifier_state.notify_activity(&seat); OutputPowerState::refresh(state); } } From 30d8868cca9426e9f08e74e45a6a754908f102ec Mon Sep 17 00:00:00 2001 From: Lionel DARNIS Date: Thu, 24 Sep 2026 21:03:54 +0200 Subject: [PATCH 51/69] chore: fige Cargo.lock (epoch-1.9.0, [patch] locaux) Co-Authored-By: Claude Opus 5.5 (1M context) --- Cargo.lock | 1201 +++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 1001 insertions(+), 200 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 93ad9171..c27ed2cb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18,6 +18,61 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "366ffbaa4442f4684d91e2cd7c5ea7c4ed8add41959a31447066e279e432b618" +[[package]] +name = "accesskit" +version = "0.22.0" +source = "git+https://github.com/wash2/accesskit?rev=6c20249#6c20249d3b9fd45e7002efad9f6b6171a9257912" +dependencies = [ + "uuid", +] + +[[package]] +name = "accesskit_consumer" +version = "0.32.0" +source = "git+https://github.com/wash2/accesskit?rev=6c20249#6c20249d3b9fd45e7002efad9f6b6171a9257912" +dependencies = [ + "accesskit", + "hashbrown 0.16.1", +] + +[[package]] +name = "accesskit_macos" +version = "0.23.0" +source = "git+https://github.com/wash2/accesskit?rev=6c20249#6c20249d3b9fd45e7002efad9f6b6171a9257912" +dependencies = [ + "accesskit", + "accesskit_consumer", + "hashbrown 0.16.1", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "accesskit_windows" +version = "0.30.0" +source = "git+https://github.com/wash2/accesskit?rev=6c20249#6c20249d3b9fd45e7002efad9f6b6171a9257912" +dependencies = [ + "accesskit", + "accesskit_consumer", + "hashbrown 0.16.1", + "static_assertions", + "windows 0.61.3", + "windows-core 0.61.2", +] + +[[package]] +name = "accesskit_winit" +version = "0.30.0" +source = "git+https://github.com/wash2/accesskit?rev=6c20249#6c20249d3b9fd45e7002efad9f6b6171a9257912" +dependencies = [ + "accesskit", + "accesskit_macos", + "accesskit_windows", + "raw-window-handle", + "winit 0.31.0-beta.2", +] + [[package]] name = "addr2line" version = "0.25.1" @@ -61,6 +116,12 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + [[package]] name = "almost" version = "0.2.0" @@ -166,6 +227,25 @@ dependencies = [ "libloading", ] +[[package]] +name = "ashpd" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33a3c86f3fd70c0ffa500ed189abfa90b5a52398a45d5dc372fcc38ebeb7a645" +dependencies = [ + "enumflags2", + "futures-channel", + "futures-util", + "rand 0.9.5", + "serde", + "serde_repr", + "url", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "zbus", +] + [[package]] name = "async-broadcast" version = "0.7.2" @@ -343,7 +423,7 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -412,13 +492,22 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block2" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" +dependencies = [ + "objc2 0.5.2", +] + [[package]] name = "block2" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" dependencies = [ - "objc2", + "objc2 0.6.4", ] [[package]] @@ -463,6 +552,13 @@ dependencies = [ "num-traits", ] +[[package]] +name = "build_helpers" +version = "0.14.0" +dependencies = [ + "cfg_aliases", +] + [[package]] name = "bumpalo" version = "3.20.2" @@ -594,7 +690,7 @@ dependencies = [ "iana-time-zone", "num-traits", "serde", - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -615,7 +711,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", @@ -625,22 +720,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 = "cocoa" version = "0.25.0" @@ -650,7 +735,7 @@ dependencies = [ "bitflags 1.3.2", "block", "cocoa-foundation", - "core-foundation", + "core-foundation 0.9.4", "core-graphics", "foreign-types", "libc", @@ -665,8 +750,8 @@ checksum = "8c6234cbb2e4c785b456c0644748b1ac416dd045799740356f8363dfe00c93f7" dependencies = [ "bitflags 1.3.2", "block", - "core-foundation", - "core-graphics-types", + "core-foundation 0.9.4", + "core-graphics-types 0.1.3", "libc", "objc", ] @@ -677,7 +762,9 @@ version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe6d2e5af09e8c8ad56c969f2157a3d4238cebc7c55f0a517728c38f7b200f81" dependencies = [ - "unicode-width", + "serde", + "termcolor", + "unicode-width 0.1.14", ] [[package]] @@ -721,6 +808,16 @@ dependencies = [ "libc", ] +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -734,8 +831,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" dependencies = [ "bitflags 1.3.2", - "core-foundation", - "core-graphics-types", + "core-foundation 0.9.4", + "core-graphics-types 0.1.3", "foreign-types", "libc", ] @@ -747,7 +844,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" dependencies = [ "bitflags 1.3.2", - "core-foundation", + "core-foundation 0.9.4", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" +dependencies = [ + "bitflags 2.13.2", + "core-foundation 0.10.1", "libc", ] @@ -760,6 +868,18 @@ dependencies = [ "libm", ] +[[package]] +name = "cosmic-client-toolkit" +version = "0.2.0" +dependencies = [ + "bitflags 2.13.2", + "cosmic-protocols", + "libc", + "smithay-client-toolkit", + "wayland-client", + "wayland-protocols", +] + [[package]] name = "cosmic-comp" version = "1.0.0" @@ -787,7 +907,7 @@ dependencies = [ "indexmap 2.13.0", "jiff", "keyframe", - "libcosmic", + "libcosmic-yoda", "libdisplay-info", "libsystemd", "log-panics", @@ -809,7 +929,7 @@ dependencies = [ "smithay", "smithay-egui", "thiserror 2.0.18", - "tiny-skia", + "tiny-skia 0.11.4", "tracing", "tracing-journald", "tracing-subscriber", @@ -839,7 +959,6 @@ dependencies = [ [[package]] name = "cosmic-config" version = "1.0.0" -source = "git+https://github.com/pop-os/libcosmic#d922ac380134c00208d2acf93947d44fb217eec5" dependencies = [ "atomicwrites", "calloop", @@ -860,7 +979,6 @@ dependencies = [ [[package]] name = "cosmic-config-derive" version = "1.0.0" -source = "git+https://github.com/pop-os/libcosmic#d922ac380134c00208d2acf93947d44fb217eec5" dependencies = [ "quote", "syn", @@ -869,12 +987,11 @@ dependencies = [ [[package]] name = "cosmic-freedesktop-icons" version = "0.4.0" -source = "git+https://github.com/pop-os/freedesktop-icons#ab4c57b8e416c6af9297cb04d101889896fd9a92" dependencies = [ "bstr", "btoi", "memchr", - "memmap2", + "memmap2 0.9.10", "thiserror 2.0.18", "tracing", "xdg", @@ -883,10 +1000,10 @@ dependencies = [ [[package]] name = "cosmic-protocols" version = "0.2.0" -source = "git+https://github.com/pop-os//cosmic-protocols?branch=main#c0cff4db14c37ed954983158e4055aa94c7741d9" dependencies = [ "bitflags 2.13.2", "wayland-backend", + "wayland-client", "wayland-protocols", "wayland-protocols-wlr", "wayland-scanner", @@ -895,8 +1012,7 @@ dependencies = [ [[package]] name = "cosmic-randr-shell" -version = "0.1.0" -source = "git+https://github.com/pop-os/cosmic-randr/#6e8e795970fa06d434af22775e415b517f7552d3" +version = "1.3.0" dependencies = [ "kdl", "slotmap", @@ -905,8 +1021,7 @@ dependencies = [ [[package]] name = "cosmic-settings-config" -version = "0.1.0" -source = "git+https://github.com/pop-os/cosmic-settings-daemon#e37160f14d1e7ee428f973cd2848b4e95f83dfe1" +version = "1.9.0" dependencies = [ "cosmic-config", "ron 0.11.0", @@ -918,16 +1033,14 @@ dependencies = [ [[package]] name = "cosmic-settings-daemon" -version = "0.1.0" -source = "git+https://github.com/pop-os/dbus-settings-bindings#eed01dd3609e90e3c8cd043656734c500956c793" +version = "0.1.1-yoda.1" dependencies = [ "zbus", ] [[package]] name = "cosmic-settings-daemon-config" -version = "0.1.0" -source = "git+https://github.com/pop-os/cosmic-settings-daemon#e37160f14d1e7ee428f973cd2848b4e95f83dfe1" +version = "1.9.0" dependencies = [ "cosmic-config", "cosmic-theme", @@ -937,8 +1050,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.13.2", "fontdb", @@ -956,12 +1067,12 @@ dependencies = [ "unicode-linebreak", "unicode-script", "unicode-segmentation", + "unicode-width 0.2.2", ] [[package]] name = "cosmic-theme" version = "1.0.0" -source = "git+https://github.com/pop-os/libcosmic#d922ac380134c00208d2acf93947d44fb217eec5" dependencies = [ "almost", "configparser", @@ -1018,7 +1129,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", @@ -1170,7 +1280,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -1180,7 +1290,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" dependencies = [ "bitflags 2.13.2", - "objc2", + "objc2 0.6.4", ] [[package]] @@ -1206,7 +1316,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.13.2", "mime 0.1.0", @@ -1233,21 +1342,12 @@ checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" [[package]] name = "dpi" version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76" [[package]] -name = "drm" -version = "0.11.1" +name = "dpi" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0f8a69e60d75ae7dab4ef26a59ca99f2a89d4c142089b537775ae0c198bdcde" -dependencies = [ - "bitflags 2.13.2", - "bytemuck", - "drm-ffi 0.7.1", - "drm-fourcc", - "rustix 0.38.44", -] +checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76" [[package]] name = "drm" @@ -1257,29 +1357,19 @@ checksum = "80bc8c5c6c2941f70a55c15f8d9f00f9710ebda3ffda98075f996a0e6c92756f" dependencies = [ "bitflags 2.13.2", "bytemuck", - "drm-ffi 0.9.1", + "drm-ffi", "drm-fourcc", "libc", "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 0.6.1", - "rustix 0.38.44", -] - [[package]] name = "drm-ffi" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51a91c9b32ac4e8105dec255e849e0d66e27d7c34d184364fb93e469db08f690" dependencies = [ - "drm-sys 0.8.1", + "drm-sys", "rustix 1.1.4", ] @@ -1289,16 +1379,6 @@ 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 = "drm-sys" version = "0.8.1" @@ -1484,7 +1564,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]] @@ -1698,7 +1778,7 @@ checksum = "457e789b3d1202543297a350643cf459f836cade38934e7a4cf6a39e7cde2905" dependencies = [ "fontconfig-parser", "log", - "memmap2", + "memmap2 0.9.10", "slotmap", "tinyvec", "ttf-parser", @@ -1857,7 +1937,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce852e998d3ca5e4a97014fb31c940dc5ef344ec7d364984525fd11e8a547e6a" dependencies = [ "bitflags 2.13.2", - "drm 0.14.1", + "drm", "drm-fourcc", "gbm-sys", "libc", @@ -1883,8 +1963,8 @@ dependencies = [ "libc", "log", "rustversion", - "windows-link", - "windows-result", + "windows-link 0.2.1", + "windows-result 0.4.1", ] [[package]] @@ -1904,7 +1984,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8" dependencies = [ "rustix 1.1.4", - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -1995,6 +2075,49 @@ dependencies = [ "web-sys", ] +[[package]] +name = "glutin_wgl_sys" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c4ee00b289aba7a9e5306d57c2d05499b2e5dc427f84ac708bd2c090212cf3e" +dependencies = [ + "gl_generator", +] + +[[package]] +name = "gpu-allocator" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51255ea7cfaadb6c5f1528d43e92a82acb2b96c43365989a28b2d44ee38f8795" +dependencies = [ + "ash", + "hashbrown 0.16.1", + "log", + "presser", + "thiserror 2.0.18", + "windows 0.62.2", +] + +[[package]] +name = "gpu-descriptor" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b89c83349105e3732062a895becfc71a8f921bb71ecbbdd8ff99263e3b53a0ca" +dependencies = [ + "bitflags 2.13.2", + "gpu-descriptor-types", + "hashbrown 0.15.5", +] + +[[package]] +name = "gpu-descriptor-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91" +dependencies = [ + "bitflags 2.13.2", +] + [[package]] name = "grid" version = "1.0.0" @@ -2057,6 +2180,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", ] @@ -2204,7 +2329,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core", + "windows-core 0.62.2", ] [[package]] @@ -2219,9 +2344,10 @@ dependencies = [ [[package]] name = "iced" version = "0.14.0" -source = "git+https://github.com/pop-os/libcosmic#d922ac380134c00208d2acf93947d44fb217eec5" dependencies = [ + "build_helpers", "dnd", + "iced_accessibility", "iced_core", "iced_debug", "iced_futures", @@ -2229,19 +2355,29 @@ dependencies = [ "iced_renderer", "iced_runtime", "iced_widget", + "iced_winit", "image", "mime 0.1.0", "thiserror 2.0.18", "window_clipboard", ] +[[package]] +name = "iced_accessibility" +version = "0.1.0" +dependencies = [ + "accesskit", + "accesskit_winit", +] + [[package]] name = "iced_core" version = "0.14.0" -source = "git+https://github.com/pop-os/libcosmic#d922ac380134c00208d2acf93947d44fb217eec5" dependencies = [ "bitflags 2.13.2", + "build_helpers", "bytes", + "cosmic-client-toolkit", "dnd", "glam 0.25.0", "lilt", @@ -2262,7 +2398,6 @@ dependencies = [ [[package]] name = "iced_debug" version = "0.14.0" -source = "git+https://github.com/pop-os/libcosmic#d922ac380134c00208d2acf93947d44fb217eec5" dependencies = [ "iced_core", "iced_futures", @@ -2272,7 +2407,6 @@ dependencies = [ [[package]] name = "iced_futures" version = "0.14.0" -source = "git+https://github.com/pop-os/libcosmic#d922ac380134c00208d2acf93947d44fb217eec5" dependencies = [ "futures", "iced_core", @@ -2285,7 +2419,6 @@ dependencies = [ [[package]] name = "iced_graphics" version = "0.14.0" -source = "git+https://github.com/pop-os/libcosmic#d922ac380134c00208d2acf93947d44fb217eec5" dependencies = [ "bitflags 2.13.2", "bytemuck", @@ -2306,7 +2439,6 @@ dependencies = [ [[package]] name = "iced_program" version = "0.14.0" -source = "git+https://github.com/pop-os/libcosmic#d922ac380134c00208d2acf93947d44fb217eec5" dependencies = [ "iced_graphics", "iced_runtime", @@ -2315,7 +2447,6 @@ dependencies = [ [[package]] name = "iced_renderer" version = "0.14.0" -source = "git+https://github.com/pop-os/libcosmic#d922ac380134c00208d2acf93947d44fb217eec5" dependencies = [ "iced_graphics", "iced_tiny_skia", @@ -2327,9 +2458,10 @@ dependencies = [ [[package]] name = "iced_runtime" version = "0.14.0" -source = "git+https://github.com/pop-os/libcosmic#d922ac380134c00208d2acf93947d44fb217eec5" dependencies = [ + "build_helpers", "bytes", + "cosmic-client-toolkit", "dnd", "iced_core", "iced_futures", @@ -2341,7 +2473,6 @@ dependencies = [ [[package]] name = "iced_tiny_skia" version = "0.14.0" -source = "git+https://github.com/pop-os/libcosmic#d922ac380134c00208d2acf93947d44fb217eec5" dependencies = [ "bytemuck", "cosmic-text", @@ -2352,17 +2483,17 @@ dependencies = [ "resvg 0.45.1", "rustc-hash 2.1.1", "softbuffer", - "tiny-skia", + "tiny-skia 0.11.4", ] [[package]] name = "iced_wgpu" version = "0.14.0" -source = "git+https://github.com/pop-os/libcosmic#d922ac380134c00208d2acf93947d44fb217eec5" dependencies = [ - "as-raw-xcb-connection", "bitflags 2.13.2", + "build_helpers", "bytemuck", + "cosmic-client-toolkit", "cryoglyph", "futures", "glam 0.25.0", @@ -2376,20 +2507,19 @@ dependencies = [ "rustc-hash 2.1.1", "rustix 0.38.44", "thiserror 2.0.18", - "tiny-xlib", "wayland-backend", "wayland-client", "wayland-protocols", "wayland-sys", "wgpu", - "x11rb", ] [[package]] name = "iced_widget" version = "0.14.2" -source = "git+https://github.com/pop-os/libcosmic#d922ac380134c00208d2acf93947d44fb217eec5" dependencies = [ + "build_helpers", + "cosmic-client-toolkit", "dnd", "iced_renderer", "iced_runtime", @@ -2402,6 +2532,38 @@ dependencies = [ "window_clipboard", ] +[[package]] +name = "iced_winit" +version = "0.14.0" +dependencies = [ + "build_helpers", + "cosmic-client-toolkit", + "cursor-icon", + "dnd", + "iced_debug", + "iced_futures", + "iced_graphics", + "iced_program", + "iced_runtime", + "log", + "raw-window-handle", + "rustc-hash 2.1.1", + "rustix 0.38.44", + "thiserror 2.0.18", + "wasm-bindgen-futures", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "web-sys", + "winapi", + "window_clipboard", + "winit 0.31.0-beta.2", + "winit-core 0.31.0-beta.2", + "xkbcommon 0.7.0", + "xkbcommon-dl", + "xkeysym", +] + [[package]] name = "icu_collections" version = "2.1.1" @@ -2671,7 +2833,7 @@ dependencies = [ "portable-atomic", "portable-atomic-util", "serde_core", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -2782,6 +2944,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "khronos-egl" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76" +dependencies = [ + "libc", + "libloading", + "pkg-config", +] + [[package]] name = "khronos_api" version = "3.1.0" @@ -2794,7 +2967,7 @@ version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a1886916523694cd6ea3d175f03a1e5010699a2a4cc13696d83d7bea1d80638" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -2866,12 +3039,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" [[package]] -name = "libcosmic" -version = "1.0.0" -source = "git+https://github.com/pop-os/libcosmic#d922ac380134c00208d2acf93947d44fb217eec5" +name = "libcosmic-yoda" +version = "0.1.0-yoda.2" dependencies = [ "apply", + "ashpd", "auto_enums", + "build_helpers", + "cosmic-client-toolkit", "cosmic-config", "cosmic-freedesktop-icons", "cosmic-settings-daemon", @@ -2889,12 +3064,15 @@ dependencies = [ "iced_renderer", "iced_runtime", "iced_tiny_skia", + "iced_wgpu", "iced_widget", + "iced_winit", "image", "jiff", "log", "palette", "phf 0.13.1", + "roxmltree 0.20.0", "rust-embed", "serde", "slotmap", @@ -2947,7 +3125,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" dependencies = [ "cfg-if", - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -2958,13 +3136,14 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libredox" -version = "0.1.12" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" +checksum = "61ff90caf6077a803a240f62fdbe88645a890bbca49ef8174c3cb0404362171d" dependencies = [ "bitflags 2.13.2", "libc", - "redox_syscall 0.7.2", + "plain", + "redox_syscall 0.9.4", ] [[package]] @@ -3036,12 +3215,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.9.4" @@ -3196,6 +3369,15 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +[[package]] +name = "memmap2" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a5a03cefb0d953ec0be133036f14e109412fa594edc2f77227249db66cc3ed" +dependencies = [ + "libc", +] + [[package]] name = "memmap2" version = "0.9.10" @@ -3214,6 +3396,21 @@ dependencies = [ "autocfg", ] +[[package]] +name = "metal" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7047791b5bc903b8cd963014b355f71dc9864a9a0b727057676c1dcae5cbc15" +dependencies = [ + "bitflags 2.13.2", + "block", + "core-graphics-types 0.2.0", + "foreign-types", + "log", + "objc", + "paste", +] + [[package]] name = "miette" version = "7.6.0" @@ -3221,13 +3418,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f98efec8807c63c752b5bd61f862c165c115b0a35685bdcfd9238c7aeb592b7" dependencies = [ "cfg-if", - "unicode-width", + "unicode-width 0.1.14", ] [[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", ] @@ -3315,6 +3511,7 @@ dependencies = [ "num-traits", "once_cell", "rustc-hash 1.1.0", + "spirv", "thiserror 2.0.18", "unicode-ident", ] @@ -3410,7 +3607,7 @@ 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]] @@ -3535,6 +3732,22 @@ dependencies = [ "objc_id", ] +[[package]] +name = "objc-sys" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" + +[[package]] +name = "objc2" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" +dependencies = [ + "objc-sys", + "objc2-encode", +] + [[package]] name = "objc2" version = "0.6.4" @@ -3544,6 +3757,22 @@ dependencies = [ "objc2-encode", ] +[[package]] +name = "objc2-app-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" +dependencies = [ + "bitflags 2.13.2", + "block2 0.5.1", + "libc", + "objc2 0.5.2", + "objc2-core-data", + "objc2-core-image", + "objc2-foundation 0.2.2", + "objc2-quartz-core", +] + [[package]] name = "objc2-app-kit" version = "0.3.2" @@ -3551,9 +3780,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" dependencies = [ "bitflags 2.13.2", - "objc2", + "objc2 0.6.4", "objc2-core-foundation", - "objc2-foundation", + "objc2-foundation 0.3.2", +] + +[[package]] +name = "objc2-core-data" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" +dependencies = [ + "bitflags 2.13.2", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", ] [[package]] @@ -3563,9 +3804,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ "bitflags 2.13.2", - "block2", + "block2 0.6.2", "dispatch2", - "objc2", + "objc2 0.6.4", ] [[package]] @@ -3579,6 +3820,18 @@ dependencies = [ "objc2-core-foundation", ] +[[package]] +name = "objc2-core-image" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" +dependencies = [ + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", + "objc2-metal", +] + [[package]] name = "objc2-core-video" version = "0.3.2" @@ -3596,6 +3849,18 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" +[[package]] +name = "objc2-foundation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" +dependencies = [ + "bitflags 2.13.2", + "block2 0.5.1", + "libc", + "objc2 0.5.2", +] + [[package]] name = "objc2-foundation" version = "0.3.2" @@ -3603,11 +3868,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ "bitflags 2.13.2", - "block2", - "objc2", + "block2 0.6.2", + "objc2 0.6.4", "objc2-core-foundation", ] +[[package]] +name = "objc2-metal" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" +dependencies = [ + "bitflags 2.13.2", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" +dependencies = [ + "bitflags 2.13.2", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", + "objc2-metal", +] + [[package]] name = "objc2-ui-kit" version = "0.3.2" @@ -3615,9 +3905,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22" dependencies = [ "bitflags 2.13.2", - "objc2", + "objc2 0.6.4", "objc2-core-foundation", - "objc2-foundation", + "objc2-foundation 0.3.2", ] [[package]] @@ -3763,7 +4053,7 @@ dependencies = [ "libc", "redox_syscall 0.5.18", "smallvec", - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -3940,6 +4230,12 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + [[package]] name = "png" version = "0.17.16" @@ -4019,6 +4315,12 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "presser" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa" + [[package]] name = "prettyplease" version = "0.2.37" @@ -4148,10 +4450,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha", + "rand_chacha 0.3.1", "rand_core 0.6.4", ] +[[package]] +name = "rand" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.5", +] + [[package]] name = "rand" version = "0.10.0" @@ -4173,6 +4485,16 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", +] + [[package]] name = "rand_core" version = "0.6.4" @@ -4182,12 +4504,27 @@ dependencies = [ "getrandom 0.2.17", ] +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] + [[package]] name = "rand_core" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba" +[[package]] +name = "range-alloc" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca45419789ae5a7899559e9512e58ca889e41f04f1f2445e9f4b290ceccd1d08" + [[package]] name = "rangemap" version = "1.7.1" @@ -4227,6 +4564,16 @@ dependencies = [ "font-types 0.11.0", ] +[[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]] name = "redox_syscall" version = "0.5.18" @@ -4238,9 +4585,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.7.2" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d94dd2f7cd932d4dc02cc8b2b50dfd38bd079a4e5d79198b99743d7fcf9a4b4" +checksum = "737970939a87c6fa31e7acad13307bccbb017a073b695b6089a2c484f929e20e" dependencies = [ "bitflags 2.13.2", ] @@ -4333,7 +4680,7 @@ dependencies = [ "pico-args", "rgb", "svgtypes 0.13.0", - "tiny-skia", + "tiny-skia 0.11.4", "usvg 0.37.0", ] @@ -4349,7 +4696,7 @@ dependencies = [ "pico-args", "rgb", "svgtypes 0.15.3", - "tiny-skia", + "tiny-skia 0.11.4", "usvg 0.45.1", "zune-jpeg 0.4.21", ] @@ -4477,7 +4824,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.12.1", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -4558,6 +4905,19 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "sctk-adwaita" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2a4360b9abcdcee43809e6fc11d6d61ca5d25734026a8fc46c2883eea3f13f" +dependencies = [ + "ab_glyph", + "log", + "memmap2 0.9.10", + "smithay-client-toolkit", + "tiny-skia 0.12.0", +] + [[package]] name = "self_cell" version = "1.2.2" @@ -4782,10 +5142,10 @@ dependencies = [ "cc", "cursor-icon", "downcast-rs", - "drm 0.14.1", - "drm-ffi 0.9.1", + "drm", + "drm-ffi", "drm-fourcc", - "drm-sys 0.8.1", + "drm-sys", "encoding_rs", "errno", "gbm", @@ -4819,7 +5179,7 @@ dependencies = [ "wayland-protocols-misc", "wayland-protocols-wlr", "wayland-server", - "winit", + "winit 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", "x11rb", "xkbcommon 0.9.0", ] @@ -4831,12 +5191,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0512da38f5e2b31201a93524adb8d3136276fa4fe4aafab4e1f727a82b534cc0" dependencies = [ "bitflags 2.13.2", + "bytemuck", "calloop", "calloop-wayland-source", "cursor-icon", "libc", "log", - "memmap2", + "memmap2 0.9.10", + "pkg-config", "rustix 1.1.4", "thiserror 2.0.18", "wayland-backend", @@ -4848,13 +5210,13 @@ dependencies = [ "wayland-protocols-misc", "wayland-protocols-wlr", "wayland-scanner", + "xkbcommon 0.8.0", "xkeysym", ] [[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", @@ -4895,22 +5257,20 @@ checksum = "27207bb65232eda1f588cf46db2fee75c0808d557f6b3cf19a75f5d6d7c94df1" [[package]] name = "softbuffer" version = "0.4.1" -source = "git+https://github.com/pop-os/softbuffer?tag=cosmic-4.0#c2b2c19ddb38ff17495643699f97cb1f2064a1be" dependencies = [ "as-raw-xcb-connection", "bytemuck", "cfg_aliases", "cocoa", "core-graphics", - "drm 0.11.1", "fastrand", "foreign-types", "js-sys", + "libredox", "log", - "memmap2", + "memmap2 0.9.10", "objc", "raw-window-handle", - "redox_syscall 0.5.18", "rustix 0.38.44", "tiny-xlib", "wasm-bindgen", @@ -4922,6 +5282,15 @@ dependencies = [ "x11rb", ] +[[package]] +name = "spirv" +version = "0.3.0+sdk-1.3.268.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" +dependencies = [ + "bitflags 2.13.2", +] + [[package]] name = "stable_deref_trait" version = "1.2.1" @@ -5064,7 +5433,16 @@ dependencies = [ "getrandom 0.4.1", "once_cell", "rustix 1.1.4", - "windows-sys 0.52.0", + "windows-sys 0.61.2", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", ] [[package]] @@ -5159,7 +5537,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]] @@ -5173,6 +5565,17 @@ dependencies = [ "strict-num", ] +[[package]] +name = "tiny-skia-path" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edca365c3faccca67d06593c5980fa6c57687de727a03131735bb85f01fdeeb9" +dependencies = [ + "arrayref", + "bytemuck", + "strict-num", +] + [[package]] name = "tiny-xlib" version = "0.2.4" @@ -5513,6 +5916,12 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + [[package]] name = "unicode-xid" version = "0.2.6" @@ -5529,6 +5938,7 @@ dependencies = [ "idna", "percent-encoding", "serde", + "serde_derive", ] [[package]] @@ -5565,7 +5975,7 @@ dependencies = [ "siphasher 1.0.2", "strict-num", "svgtypes 0.15.3", - "tiny-skia-path", + "tiny-skia-path 0.11.4", "unicode-bidi", "unicode-script", "unicode-vo", @@ -5599,7 +6009,7 @@ dependencies = [ "rctree", "strict-num", "svgtypes 0.13.0", - "tiny-skia-path", + "tiny-skia-path 0.11.4", ] [[package]] @@ -5978,12 +6388,18 @@ dependencies = [ "cfg_aliases", "document-features", "hashbrown 0.16.1", + "js-sys", "log", + "naga", + "parking_lot", "portable-atomic", "profiling", "raw-window-handle", "smallvec", "static_assertions", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", "wgpu-core", "wgpu-hal", "wgpu-types", @@ -6014,11 +6430,31 @@ dependencies = [ "rustc-hash 1.1.0", "smallvec", "thiserror 2.0.18", + "wgpu-core-deps-apple", + "wgpu-core-deps-emscripten", "wgpu-core-deps-windows-linux-android", "wgpu-hal", "wgpu-types", ] +[[package]] +name = "wgpu-core-deps-apple" +version = "28.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87b7b696b918f337c486bf93142454080a32a37832ba8a31e4f48221890047da" +dependencies = [ + "wgpu-hal", +] + +[[package]] +name = "wgpu-core-deps-emscripten" +version = "28.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34b251c331f84feac147de3c4aa3aa45112622a95dd7ee1b74384fa0458dbd79" +dependencies = [ + "wgpu-hal", +] + [[package]] name = "wgpu-core-deps-windows-linux-android" version = "28.0.0" @@ -6034,18 +6470,46 @@ version = "28.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44d6cb474beb218824dcc9e1ce679d973f719262789bfb27407da560cac20eeb" dependencies = [ + "android_system_properties", + "arrayvec", + "ash", + "bit-set", "bitflags 2.13.2", + "block", + "bytemuck", "cfg-if", "cfg_aliases", + "core-graphics-types 0.2.0", + "glow", + "glutin_wgl_sys", + "gpu-allocator", + "gpu-descriptor", + "hashbrown 0.16.1", + "js-sys", + "khronos-egl", + "libc", "libloading", "log", + "metal", "naga", + "ndk-sys", + "objc", + "once_cell", + "ordered-float", + "parking_lot", "portable-atomic", "portable-atomic-util", + "profiling", + "range-alloc", "raw-window-handle", "renderdoc-sys", + "smallvec", "thiserror 2.0.18", + "wasm-bindgen", + "web-sys", "wgpu-types", + "windows 0.62.2", + "windows-core 0.62.2", ] [[package]] @@ -6083,7 +6547,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.61.2", ] [[package]] @@ -6095,18 +6559,72 @@ 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", "thiserror 1.0.69", ] +[[package]] +name = "windows" +version = "0.61.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" +dependencies = [ + "windows-collections 0.2.0", + "windows-core 0.61.2", + "windows-future 0.2.1", + "windows-link 0.1.3", + "windows-numerics 0.2.0", +] + +[[package]] +name = "windows" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580" +dependencies = [ + "windows-collections 0.3.2", + "windows-core 0.62.2", + "windows-future 0.3.2", + "windows-numerics 0.3.1", +] + +[[package]] +name = "windows-collections" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" +dependencies = [ + "windows-core 0.61.2", +] + +[[package]] +name = "windows-collections" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610" +dependencies = [ + "windows-core 0.62.2", +] + +[[package]] +name = "windows-core" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link 0.1.3", + "windows-result 0.3.4", + "windows-strings 0.4.2", +] + [[package]] name = "windows-core" version = "0.62.2" @@ -6115,9 +6633,31 @@ checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", - "windows-link", - "windows-result", - "windows-strings", + "windows-link 0.2.1", + "windows-result 0.4.1", + "windows-strings 0.5.1", +] + +[[package]] +name = "windows-future" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" +dependencies = [ + "windows-core 0.61.2", + "windows-link 0.1.3", + "windows-threading 0.1.0", +] + +[[package]] +name = "windows-future" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb" +dependencies = [ + "windows-core 0.62.2", + "windows-link 0.2.1", + "windows-threading 0.2.1", ] [[package]] @@ -6142,19 +6682,63 @@ dependencies = [ "syn", ] +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + [[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +[[package]] +name = "windows-numerics" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +dependencies = [ + "windows-core 0.61.2", + "windows-link 0.1.3", +] + +[[package]] +name = "windows-numerics" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26" +dependencies = [ + "windows-core 0.62.2", + "windows-link 0.2.1", +] + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link 0.1.3", +] + [[package]] name = "windows-result" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ - "windows-link", + "windows-link 0.2.1", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link 0.1.3", ] [[package]] @@ -6163,7 +6747,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -6217,7 +6801,7 @@ version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -6272,7 +6856,7 @@ version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ - "windows-link", + "windows-link 0.2.1", "windows_aarch64_gnullvm 0.53.1", "windows_aarch64_msvc 0.53.1", "windows_i686_gnu 0.53.1", @@ -6283,6 +6867,24 @@ dependencies = [ "windows_x86_64_msvc 0.53.1", ] +[[package]] +name = "windows-threading" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-threading" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37" +dependencies = [ + "windows-link 0.2.1", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.42.2" @@ -6463,6 +7065,30 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" +[[package]] +name = "winit" +version = "0.31.0-beta.2" +dependencies = [ + "bitflags 2.13.2", + "cfg_aliases", + "cursor-icon", + "dpi 0.1.2", + "libc", + "raw-window-handle", + "rustix 1.1.4", + "smol_str", + "tracing", + "winit-android 0.31.0-beta.2", + "winit-appkit 0.31.0-beta.2", + "winit-common 0.31.0-beta.2", + "winit-core 0.31.0-beta.2", + "winit-orbital 0.31.0-beta.2", + "winit-uikit 0.31.0-beta.2", + "winit-wayland 0.31.0-beta.2", + "winit-web 0.31.0-beta.2", + "winit-win32 0.31.0-beta.2", +] + [[package]] name = "winit" version = "0.31.0-beta.2" @@ -6472,24 +7098,38 @@ dependencies = [ "bitflags 2.13.2", "cfg_aliases", "cursor-icon", - "dpi", + "dpi 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc", "raw-window-handle", "rustix 1.1.4", "smol_str", "tracing", - "winit-android", - "winit-appkit", - "winit-common", - "winit-core", - "winit-orbital", - "winit-uikit", - "winit-wayland", - "winit-web", - "winit-win32", + "winit-android 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winit-appkit 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winit-common 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winit-core 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winit-orbital 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winit-uikit 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winit-wayland 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winit-web 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winit-win32 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", "winit-x11", ] +[[package]] +name = "winit-android" +version = "0.31.0-beta.2" +dependencies = [ + "android-activity", + "bitflags 2.13.2", + "dpi 0.1.2", + "ndk", + "raw-window-handle", + "smol_str", + "tracing", + "winit-core 0.31.0-beta.2", +] + [[package]] name = "winit-android" version = "0.31.0-beta.2" @@ -6498,12 +7138,33 @@ checksum = "51d9c0d2cd93efec3a9f9ad819cfaf0834782403af7c0d248c784ec0c61761df" dependencies = [ "android-activity", "bitflags 2.13.2", - "dpi", + "dpi 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "ndk", "raw-window-handle", "smol_str", "tracing", - "winit-core", + "winit-core 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winit-appkit" +version = "0.31.0-beta.2" +dependencies = [ + "bitflags 2.13.2", + "block2 0.6.2", + "dispatch2", + "dpi 0.1.2", + "objc2 0.6.4", + "objc2-app-kit 0.3.2", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-core-video", + "objc2-foundation 0.3.2", + "raw-window-handle", + "smol_str", + "tracing", + "winit-common 0.31.0-beta.2", + "winit-core 0.31.0-beta.2", ] [[package]] @@ -6513,20 +7174,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21310ca07851a49c348e0c2cc768e36b52ca65afda2c2354d78ed4b90074d8aa" dependencies = [ "bitflags 2.13.2", - "block2", + "block2 0.6.2", "dispatch2", - "dpi", - "objc2", - "objc2-app-kit", + "dpi 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "objc2 0.6.4", + "objc2-app-kit 0.3.2", "objc2-core-foundation", "objc2-core-graphics", "objc2-core-video", - "objc2-foundation", + "objc2-foundation 0.3.2", "raw-window-handle", "smol_str", "tracing", - "winit-common", - "winit-core", + "winit-common 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winit-core 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winit-common" +version = "0.31.0-beta.2" +dependencies = [ + "memmap2 0.9.10", + "objc2 0.6.4", + "objc2-core-foundation", + "smol_str", + "tracing", + "winit-core 0.31.0-beta.2", + "xkbcommon-dl", ] [[package]] @@ -6535,16 +7209,29 @@ version = "0.31.0-beta.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45375fbac4cbb77260d83a30b1f9d8105880dbac99a9ae97f56656694680ff69" dependencies = [ - "memmap2", - "objc2", + "memmap2 0.9.10", + "objc2 0.6.4", "objc2-core-foundation", "smol_str", "tracing", - "winit-core", + "winit-core 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", "x11-dl", "xkbcommon-dl", ] +[[package]] +name = "winit-core" +version = "0.31.0-beta.2" +dependencies = [ + "bitflags 2.13.2", + "cursor-icon", + "dpi 0.1.2", + "keyboard-types", + "raw-window-handle", + "smol_str", + "web-time", +] + [[package]] name = "winit-core" version = "0.31.0-beta.2" @@ -6553,13 +7240,28 @@ checksum = "e4f0ccd7abb43740e2c6124ac7cae7d865ecec74eec63783e8922577ac232583" dependencies = [ "bitflags 2.13.2", "cursor-icon", - "dpi", + "dpi 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "keyboard-types", "raw-window-handle", "smol_str", "web-time", ] +[[package]] +name = "winit-orbital" +version = "0.31.0-beta.2" +dependencies = [ + "bitflags 2.13.2", + "dpi 0.1.2", + "libredox", + "orbclient", + "raw-window-handle", + "redox_event", + "smol_str", + "tracing", + "winit-core 0.31.0-beta.2", +] + [[package]] name = "winit-orbital" version = "0.31.0-beta.2" @@ -6567,13 +7269,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51ea1fb262e7209f265f12bd0cc792c399b14355675e65531e9c8a87db287d46" dependencies = [ "bitflags 2.13.2", - "dpi", + "dpi 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "orbclient", "raw-window-handle", "redox_syscall 0.5.18", "smol_str", "tracing", - "winit-core", + "winit-core 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winit-uikit" +version = "0.31.0-beta.2" +dependencies = [ + "bitflags 2.13.2", + "block2 0.6.2", + "dispatch2", + "dpi 0.1.2", + "objc2 0.6.4", + "objc2-core-foundation", + "objc2-foundation 0.3.2", + "objc2-ui-kit", + "raw-window-handle", + "smol_str", + "tracing", + "winit-common 0.31.0-beta.2", + "winit-core 0.31.0-beta.2", ] [[package]] @@ -6583,18 +7304,43 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "680a356e798837d8eb274d4556e83bceaf81698194e31aafc5cfb8a9f2fab643" dependencies = [ "bitflags 2.13.2", - "block2", + "block2 0.6.2", "dispatch2", - "dpi", - "objc2", + "dpi 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "objc2 0.6.4", "objc2-core-foundation", - "objc2-foundation", + "objc2-foundation 0.3.2", "objc2-ui-kit", "raw-window-handle", "smol_str", "tracing", - "winit-common", - "winit-core", + "winit-common 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winit-core 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winit-wayland" +version = "0.31.0-beta.2" +dependencies = [ + "ahash", + "bitflags 2.13.2", + "calloop", + "cursor-icon", + "dpi 0.1.2", + "libc", + "memmap2 0.9.10", + "raw-window-handle", + "rustix 1.1.4", + "sctk-adwaita", + "smithay-client-toolkit", + "smol_str", + "tracing", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-protocols-plasma", + "winit-common 0.31.0-beta.2", + "winit-core 0.31.0-beta.2", ] [[package]] @@ -6607,9 +7353,9 @@ dependencies = [ "bitflags 2.13.2", "calloop", "cursor-icon", - "dpi", + "dpi 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc", - "memmap2", + "memmap2 0.9.10", "raw-window-handle", "rustix 1.1.4", "smithay-client-toolkit", @@ -6619,8 +7365,29 @@ dependencies = [ "wayland-client", "wayland-protocols", "wayland-protocols-plasma", - "winit-common", - "winit-core", + "winit-common 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winit-core 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winit-web" +version = "0.31.0-beta.2" +dependencies = [ + "atomic-waker", + "bitflags 2.13.2", + "concurrent-queue", + "cursor-icon", + "dpi 0.1.2", + "js-sys", + "pin-project", + "raw-window-handle", + "smol_str", + "tracing", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "web-time", + "winit-core 0.31.0-beta.2", ] [[package]] @@ -6633,7 +7400,7 @@ dependencies = [ "bitflags 2.13.2", "concurrent-queue", "cursor-icon", - "dpi", + "dpi 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "js-sys", "pin-project", "raw-window-handle", @@ -6643,7 +7410,22 @@ dependencies = [ "wasm-bindgen-futures", "web-sys", "web-time", - "winit-core", + "winit-core 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winit-win32" +version = "0.31.0-beta.2" +dependencies = [ + "bitflags 2.13.2", + "cursor-icon", + "dpi 0.1.2", + "raw-window-handle", + "smol_str", + "tracing", + "unicode-segmentation", + "windows-sys 0.59.0", + "winit-core 0.31.0-beta.2", ] [[package]] @@ -6654,13 +7436,13 @@ checksum = "644ea78af0e858aa3b092e5d1c67c41995a98220c81813f1353b28bc8bb91eaa" dependencies = [ "bitflags 2.13.2", "cursor-icon", - "dpi", + "dpi 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "raw-window-handle", "smol_str", "tracing", "unicode-segmentation", "windows-sys 0.59.0", - "winit-core", + "winit-core 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -6673,15 +7455,15 @@ dependencies = [ "bytemuck", "calloop", "cursor-icon", - "dpi", + "dpi 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc", "percent-encoding", "raw-window-handle", "rustix 1.1.4", "smol_str", "tracing", - "winit-common", - "winit-core", + "winit-common 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winit-core 0.31.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", "x11-dl", "x11rb", "xkbcommon-dl", @@ -6863,6 +7645,17 @@ dependencies = [ "libc", ] +[[package]] +name = "xkbcommon" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13867d259930edc7091a6c41b4ce6eee464328c6ff9659b7e4c668ca20d4c91e" +dependencies = [ + "libc", + "memmap2 0.8.0", + "xkeysym", +] + [[package]] name = "xkbcommon" version = "0.8.0" @@ -6870,7 +7663,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d66ca9352cbd4eecbbc40871d8a11b4ac8107cfc528a6e14d7c19c69d0e1ac9" dependencies = [ "libc", - "memmap2", + "memmap2 0.9.10", "xkeysym", ] @@ -6881,7 +7674,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a974f48060a14e95705c01f24ad9c3345022f4d97441b8a36beb7ed5c4a02d" dependencies = [ "libc", - "memmap2", + "memmap2 0.9.10", "xkeysym", ] @@ -6903,6 +7696,9 @@ name = "xkeysym" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" +dependencies = [ + "bytemuck", +] [[package]] name = "xml-rs" @@ -7138,6 +7934,7 @@ dependencies = [ "endi", "enumflags2", "serde", + "url", "winnow 1.0.3", "zvariant_derive", "zvariant_utils", @@ -7168,3 +7965,7 @@ dependencies = [ "syn", "winnow 1.0.3", ] + +[[patch.unused]] +name = "winit-x11" +version = "0.31.0-beta.2" From 9f746ea3ffe276aef7a98d82f431700a542b4417 Mon Sep 17 00:00:00 2001 From: Hojjat Date: Tue, 22 Sep 2026 18:50:34 -0600 Subject: [PATCH 52/69] fix: the logic for resize direction in tiling mode --- src/shell/layout/tiling/mod.rs | 45 ++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/src/shell/layout/tiling/mod.rs b/src/shell/layout/tiling/mod.rs index 8706dc59..20e11b71 100644 --- a/src/shell/layout/tiling/mod.rs +++ b/src/shell/layout/tiling/mod.rs @@ -3271,12 +3271,34 @@ impl TilingLayout { } } + let (_, inner) = self.gaps(); let mut result = None; + let mut fork = None; let mut lookup = Some(root.clone()); while let Some(node) = lookup { let data = tree.get(&node).unwrap().data(); if data.geometry().contains(location) { result = Some(node.clone()); + if let Data::Group { + orientation, + sizes, + last_geometry, + .. + } = data + { + let (pos, mut split) = match orientation { + Orientation::Vertical => (location.x, last_geometry.loc.x), + Orientation::Horizontal => (location.y, last_geometry.loc.y), + }; + for (idx, size) in + sizes.iter().take(sizes.len().saturating_sub(1)).enumerate() + { + split += size; + if (pos - split).abs() <= inner / 2 { + fork = Some((node.clone(), idx)); + } + } + } } lookup = None; @@ -3323,25 +3345,16 @@ impl TilingLayout { ) }) } - Some(( - id, - Data::Group { + Some((_, Data::Group { .. })) => { + let (id, idx) = fork?; + let Data::Group { orientation, last_geometry, .. - }, - )) => { - let idx = tree - .children(&id) - .unwrap() - .position(|node| { - let data = node.data(); - match orientation { - Orientation::Vertical => location.x < data.geometry().loc.x, - Orientation::Horizontal => location.y < data.geometry().loc.y, - } - }) - .and_then(|x| x.checked_sub(1))?; + } = tree.get(&id).unwrap().data().clone() + else { + unreachable!() + }; Some(( ResizeForkTarget { node: id.clone(), From 4d854ecb942615f9efd43722171052b9def6f18c Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 30 Sep 2026 09:55:29 -0600 Subject: [PATCH 53/69] COSMIC policy update Generated by cosmic-epoch scripts/policy-update.sh. Uses `policy_nobuild` branch to avoid package builds as it contains no code changes. --- .github/PULL_REQUEST_TEMPLATE.md | 16 +++++++++------- .github/workflows/require-checklist.yml | 14 ++++++++++++++ 2 files changed, 23 insertions(+), 7 deletions(-) create mode 100644 .github/workflows/require-checklist.yml diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index e6ca28bc..63abe526 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,8 +1,10 @@ -- [ ] I have disclosed use of any AI generated code in my commit messages. - - If you are using an LLM, and do not fully understand the changes it is making to the code base, do not create a PR. - - In our experience, AI generated code often results in overly complex code that lacks enough context for a proper fix or feature inclusion. This results in considerably longer code reviews. Due to this, AI authored or partially authored PRs may be closed without comment. -- [ ] I understand these changes in full and will be able to respond to review comments. -- [ ] My change is accurately described in the commit message. -- [ ] My contribution is tested and working as described. -- [ ] I have read the [Developer Certificate of Origin](https://developercertificate.org/) and certify my contribution under its conditions. +Replace this text with a description of your changes, and why these changes are important. Read and acknowledge the list below. PRs without a completed checkbox will be closed. +--- + +- I have not included any LLM (also known as AI) generated content in this PR, including code, comments, and descriptions. +- I understand these changes in full and will be able to respond to review comments. +- My change is accurately described in the commit message. +- My contribution is tested and working as described. +- I have read the [Developer Certificate of Origin](https://developercertificate.org/) and certify my contribution under its conditions. +- [ ] I have read and followed all of the above requirements. For more information, see our [contributor guide](https://github.com/pop-os/pop/blob/master/CONTRIBUTING.md). diff --git a/.github/workflows/require-checklist.yml b/.github/workflows/require-checklist.yml new file mode 100644 index 00000000..fd4ca8c6 --- /dev/null +++ b/.github/workflows/require-checklist.yml @@ -0,0 +1,14 @@ +# From https://github.com/mheap/require-checklist-action, license MIT +name: Require Checklist + +on: + pull_request: + types: [opened, edited, synchronize] + +jobs: + job1: + runs-on: ubuntu-latest + steps: + - uses: mheap/require-checklist-action@v2 + with: + requireChecklist: true From e7b65b1fc8cc2c6a1eb3284c4c468db3a6cd3216 Mon Sep 17 00:00:00 2001 From: Netflate Date: Sat, 26 Sep 2026 17:07:29 +0100 Subject: [PATCH 54/69] image-copy: Fix non-deterministic dmabuf format order --- src/wayland/handlers/image_copy_capture/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/wayland/handlers/image_copy_capture/mod.rs b/src/wayland/handlers/image_copy_capture/mod.rs index 85a01c9a..81f3a671 100644 --- a/src/wayland/handlers/image_copy_capture/mod.rs +++ b/src/wayland/handlers/image_copy_capture/mod.rs @@ -1,6 +1,8 @@ // SPDX-License-Identifier: GPL-3.0-only -use std::{borrow::Borrow, collections::HashMap, sync::Mutex}; +use std::{borrow::Borrow, sync::Mutex}; + +use indexmap::IndexMap; use smithay::{ backend::{ @@ -459,7 +461,7 @@ fn constraints_for_renderer( .dmabuf_render_formats() .iter() .fold( - HashMap::>::new(), + IndexMap::>::new(), |mut map, format| { map.entry(format.code).or_default().push(format.modifier); map From 467d1fbc7f1892d622415955186b7654b05fa259 Mon Sep 17 00:00:00 2001 From: Netflate Date: Wed, 30 Sep 2026 04:32:30 +0100 Subject: [PATCH 55/69] image-copy: Prioritize ARGB/XRGB dmabuf formats Co-authored-by: back-design <271796486+back-design@users.noreply.github.com> --- .../handlers/image_copy_capture/mod.rs | 37 +++++++++++-------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/src/wayland/handlers/image_copy_capture/mod.rs b/src/wayland/handlers/image_copy_capture/mod.rs index 81f3a671..57ef9500 100644 --- a/src/wayland/handlers/image_copy_capture/mod.rs +++ b/src/wayland/handlers/image_copy_capture/mod.rs @@ -454,23 +454,28 @@ fn constraints_for_renderer( .ok() .and_then(|device| device.try_get_render_node().ok().flatten()) { - constraints.dma = Some(DmabufConstraints { - node, - formats: renderer - .egl_context() - .dmabuf_render_formats() - .iter() - .fold( - IndexMap::>::new(), - |mut map, format| { - map.entry(format.code).or_default().push(format.modifier); - map - }, - ) - .into_iter() - .collect::>(), - }); + let mut formats = renderer + .egl_context() + .dmabuf_render_formats() + .iter() + .fold( + IndexMap::>::new(), + |mut map, format| { + map.entry(format.code).or_default().push(format.modifier); + map + }, + ) + .into_iter() + .collect::>(); + formats.sort_by_key(|(code, _)| !is_preferred_capture_format(*code)); + constraints.dma = Some(DmabufConstraints { node, formats }); } constraints } + +/// Formats most screencast consumers handle natively, offered first. WebRTC, for +/// example, swaps RGBA frames to BGRA on the CPU for every captured frame. +fn is_preferred_capture_format(code: Fourcc) -> bool { + matches!(code, Fourcc::Argb8888 | Fourcc::Xrgb8888) +} From ed7814e51e0328e5bab2b583595b71784a36130c Mon Sep 17 00:00:00 2001 From: Hojjat Date: Thu, 3 Sep 2026 21:36:24 -0600 Subject: [PATCH 56/69] fix: set keyboard focus on touch target (similar to tablet/pointer) --- src/input/mod.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/input/mod.rs b/src/input/mod.rs index 7bf350a5..bbc6a931 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -1471,11 +1471,18 @@ impl State { }; let under = State::surface_under(position, &output, &shell) .map(|(target, pos)| (target, pos.as_logical())); + let focus_target = State::element_under(position, &output, &shell, &seat); std::mem::drop(shell); let serial = SERIAL_COUNTER.next_serial(); let touch = seat.get_touch().unwrap(); + // change the keyboard focus unless the touch is grabbed, like pointer buttons + if !touch.is_grabbed() + && let Some(target) = focus_target.as_ref() + { + Shell::set_focus(self, Some(target), &seat, Some(serial), false); + } touch.down( self, under, From d8e4683be829d28743b323f891cf3059f87d15b6 Mon Sep 17 00:00:00 2001 From: Hojjat Date: Tue, 21 Apr 2026 16:16:01 -0600 Subject: [PATCH 57/69] fix(ci): use the correct toolchain version --- .github/workflows/ci.yml | 55 ++++++++++------------------------------ 1 file changed, 14 insertions(+), 41 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bc455356..e9277414 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,18 +13,12 @@ jobs: - name: Checkout sources uses: actions/checkout@v6 - name: Rust toolchain - uses: dtolnay/rust-toolchain@stable + uses: actions-rust-lang/setup-rust-toolchain@v1 with: components: rustfmt - - name: Cargo cache - uses: actions/cache@v5 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.toml') }} + rustflags: "" - name: Format - run: cargo +stable fmt --all -- --check + run: cargo fmt --all -- --check clippy-check: runs-on: ubuntu-latest @@ -32,20 +26,14 @@ jobs: - name: Checkout sources uses: actions/checkout@v6 - name: Rust toolchain - uses: dtolnay/rust-toolchain@stable + uses: actions-rust-lang/setup-rust-toolchain@v1 with: components: clippy - - name: Cargo cache - uses: actions/cache@v5 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.toml') }} + rustflags: "" - name: System dependencies run: sudo apt-get update; sudo apt-get install libudev-dev libgbm-dev libxkbcommon-dev libegl1-mesa-dev libwayland-dev libinput-dev libdbus-1-dev libsystemd-dev libseat-dev libdisplay-info-dev - name: Clippy - run: cargo +stable clippy --all-features -- -D warnings + run: cargo clippy --all-features -- -D warnings check-features: runs-on: ubuntu-latest @@ -53,20 +41,15 @@ jobs: - name: Checkout sources uses: actions/checkout@v6 - name: Rust toolchain - uses: dtolnay/rust-toolchain@stable - - name: Cargo cache - uses: actions/cache@v5 + uses: actions-rust-lang/setup-rust-toolchain@v1 with: - path: | - ~/.cargo/registry - ~/.cargo/git - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.toml') }} + rustflags: "" - name: System dependencies run: sudo apt-get update; sudo apt-get install libudev-dev libgbm-dev libxkbcommon-dev libegl1-mesa-dev libwayland-dev libinput-dev libdbus-1-dev libsystemd-dev libseat-dev libdisplay-info-dev - - run: cargo +stable check --no-default-features - - run: cargo +stable check --features debug - - run: cargo +stable check --features profile-with-tracy - - run: cargo +stable check --features profile-with-tracy-gpu + - run: cargo check --no-default-features + - run: cargo check --features debug + - run: cargo check --features profile-with-tracy + - run: cargo check --features profile-with-tracy-gpu test: runs-on: ubuntu-latest @@ -74,21 +57,11 @@ jobs: - name: Checkout sources uses: actions/checkout@v6 - name: Rust toolchain - uses: dtolnay/rust-toolchain@stable - - name: Cargo cache - uses: actions/cache@v5 + uses: actions-rust-lang/setup-rust-toolchain@v1 with: - path: | - ~/.cargo/registry - ~/.cargo/git - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.toml') }} + rustflags: "" - name: System dependencies run: sudo apt-get update; sudo apt-get install libudev-dev libgbm-dev libxkbcommon-dev libegl1-mesa-dev libwayland-dev libinput-dev libdbus-1-dev libsystemd-dev libdisplay-info-dev libpixman-1-dev meson ninja-build - - name: Build cache - uses: actions/cache@v5 - with: - path: target - key: ${{ runner.os }}-build-${{ hashFiles('**/Cargo.toml') }} - name: Build and install Libseat run: | wget https://git.sr.ht/~kennylevinsen/seatd/archive/0.9.1.tar.gz -O libseat-source.tar.gz From af025856c74939538e287c703ba3ea85c732d900 Mon Sep 17 00:00:00 2001 From: Frederic Laing Date: Tue, 23 Dec 2025 15:10:15 +0100 Subject: [PATCH 58/69] build: migrate from make to just --- Makefile | 67 ---------------------------------------------------- README.md | 31 ++++++++++++++++++++++++ cargo.just | 53 +++++++++++++++++++++++++++++++++++++++++ debian/rules | 12 +++++++--- justfile | 64 +++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 157 insertions(+), 70 deletions(-) delete mode 100644 Makefile create mode 100644 README.md create mode 100644 cargo.just create mode 100644 justfile diff --git a/Makefile b/Makefile deleted file mode 100644 index 16f59ee6..00000000 --- a/Makefile +++ /dev/null @@ -1,67 +0,0 @@ -export prefix ?= /usr -sysconfdir ?= /etc -bindir = $(prefix)/bin -libdir = $(prefix)/lib -sharedir = $(prefix)/share - -BINARY = cosmic-comp -CARGO_TARGET_DIR ?= target -TARGET = debug -DEBUG ?= 0 - -.PHONY = all clean install uninstall vendor - -ifeq ($(DEBUG),0) - TARGET = release - ARGS += --release -endif - -VENDOR ?= 0 -ifneq ($(VENDOR),0) - ARGS += --offline --locked -endif - -TARGET_BIN="$(DESTDIR)$(bindir)/$(BINARY)" - -KEYBINDINGS_CONF="$(DESTDIR)$(sharedir)/cosmic/com.system76.CosmicSettings.Shortcuts/v1/defaults" -TILING_EXCEPTIONS_CONF="$(DESTDIR)$(sharedir)/cosmic/com.system76.CosmicSettings.WindowRules/v1/tiling_exception_defaults" - -all: extract-vendor - cargo build $(ARGS) - -clean: - cargo clean - -distclean: - rm -rf .cargo vendor vendor.tar target - -vendor: - mkdir -p .cargo - cargo vendor | head -n -1 > .cargo/config - echo 'directory = "vendor"' >> .cargo/config - [ -n "$(SOURCE_GIT_HASH)" ] && printf '\n[env]\nGIT_HASH = "%s"\n' "$(SOURCE_GIT_HASH)" >> .cargo/config || true - tar pcf vendor.tar vendor - rm -rf vendor - -extract-vendor: -ifeq ($(VENDOR),1) - rm -rf vendor; tar pxf vendor.tar -endif - -install: - install -Dm0755 "$(CARGO_TARGET_DIR)/$(TARGET)/$(BINARY)" "$(TARGET_BIN)" - install -Dm0644 "data/keybindings.ron" "$(KEYBINDINGS_CONF)" - install -Dm0644 "data/tiling-exceptions.ron" "$(TILING_EXCEPTIONS_CONF)" - -install-bare-session: install - install -Dm0644 "data/cosmic.desktop" "$(DESTDIR)$(sharedir)/wayland-sessions/cosmic.desktop" - install -Dm0644 "data/cosmic-session.target" "$(DESTDIR)$(libdir)/systemd/user/cosmic-session.target" - install -Dm0644 "data/cosmic-session-pre.target" "$(DESTDIR)$(libdir)/systemd/user/cosmic-session-pre.target" - install -Dm0644 "data/cosmic-comp.service" "$(DESTDIR)$(libdir)/systemd/user/cosmic-comp.service" - install -Dm0755 "data/cosmic-service" "$(DESTDIR)/$(bindir)/cosmic-service" - -uninstall: - rm "$(TARGET_BIN)" "$(KEYBINDINGS_CONF)" - -uninstall-bare-session: - rm "$(DESTDIR)$(sharedir)/wayland-sessions/cosmic.desktop" diff --git a/README.md b/README.md new file mode 100644 index 00000000..0465d1a9 --- /dev/null +++ b/README.md @@ -0,0 +1,31 @@ +# cosmic-comp +Compositor for the COSMIC desktop environment + +## Development + +This project uses [just](https://github.com/casey/just) as a command runner. + +### Available Commands + +#### Building +- `just build-debug` - Compile with debug profile +- `just build-release` - Compile with release profile (default) +- `just build-vendored` - Compile release profile with vendored dependencies + - Requires vendoring first, which can be done with `just vendor` + +#### Code Quality +- `just check` - Run clippy linter with pedantic warnings + +#### Installation +- `just install` - Install binary and configuration files +- `just install-bare-session` - Install with bare session files (wayland session, systemd units) +- `just uninstall` - Remove installed files +- `just uninstall-bare-session` - Remove installed files including bare session files + +#### Cleanup +- `just clean` - Run `cargo clean` +- `just clean-dist` - Run `cargo clean` and remove vendored dependencies + +#### Vendoring +- `just vendor` - Vendor dependencies locally and create vendor.tar +- `just vendor-extract` - Extract vendored dependencies from vendor.tar diff --git a/cargo.just b/cargo.just new file mode 100644 index 00000000..c05f7fff --- /dev/null +++ b/cargo.just @@ -0,0 +1,53 @@ +cargo-target-dir := env('CARGO_TARGET_DIR', 'target') + +# Compile with debug profile +build-debug *args: + cargo build {{ args }} + +# Compile with release profile +build-release *args: (build-debug '--release' args) + +# Compile with a vendored tarball +build-vendored *args: vendor-extract (build-release '--frozen --offline' args) + +# Check for errors and linter warnings +check *args: + cargo clippy --all-features {{ args }} -- -W clippy::pedantic + +# Remove Cargo build artifacts +[no-cd] +clean: + cargo clean + +# Also remove .cargo and vendored dependencies +[no-cd] +clean-dist: clean + rm -rf .cargo vendor vendor.tar + +# Vendor Cargo dependencies locally +[no-cd] +vendor: + #!/usr/bin/env sh + mkdir -p .cargo + cargo vendor --sync Cargo.toml | head -n -1 > .cargo/config.toml + echo 'directory = "vendor"' >> .cargo/config.toml + echo >> .cargo/config.toml + echo '[env]' >> .cargo/config.toml + if [ -n "${SOURCE_DATE_EPOCH}" ] + then + source_date="$(date -d "@${SOURCE_DATE_EPOCH}" "+%Y-%m-%d")" + echo "VERGEN_GIT_COMMIT_DATE = \"${source_date}\"" >> .cargo/config.toml + fi + if [ -n "${SOURCE_GIT_HASH}" ] + then + echo "GIT_HASH = \"${SOURCE_GIT_HASH}\"" >> .cargo/config.toml + fi + tar pcf vendor.tar .cargo vendor + rm -rf .cargo vendor + +# Extracts vendored dependencies +[no-cd] +[private] +vendor-extract: + rm -rf vendor + tar pxf vendor.tar diff --git a/debian/rules b/debian/rules index 5a266947..8bd7c8d4 100755 --- a/debian/rules +++ b/debian/rules @@ -1,6 +1,6 @@ #!/usr/bin/make -f -export sysconfdir = "/usr/share" +DESTDIR = debian/cosmic-comp export VENDOR ?= 1 CLEAN ?= 1 @@ -9,12 +9,18 @@ CLEAN ?= 1 override_dh_auto_clean: ifeq ($(CLEAN),1) - ischroot && make clean || make distclean + ischroot && just clean || just clean-dist endif ifeq ($(VENDOR),1) - ischroot || make vendor + ischroot || just vendor endif +override_dh_auto_build: + just build-vendored + +override_dh_auto_install: + just rootdir=$(DESTDIR) install + override_dh_installinit: dh_installinit -r diff --git a/justfile b/justfile new file mode 100644 index 00000000..05db4b52 --- /dev/null +++ b/justfile @@ -0,0 +1,64 @@ +name := 'cosmic-comp' + +rootdir := '' +prefix := '/usr' +sysconfdir := '/etc' + +base-dir := absolute_path(clean(rootdir / prefix)) +sysconfdir-dir := absolute_path(clean(rootdir / sysconfdir)) + +bin-dir := base-dir / 'bin' +lib-dir := base-dir / 'lib' +share-dir := base-dir / 'share' + +bin-src := cargo-target-dir / 'release' / name +bin-dst := bin-dir / name + +keybindings-src := 'data' / 'keybindings.ron' +keybindings-dst := share-dir / 'cosmic' / 'com.system76.CosmicSettings.Shortcuts' / 'v1' / 'defaults' + +tiling-exceptions-src := 'data' / 'tiling-exceptions.ron' +tiling-exceptions-dst := share-dir / 'cosmic' / 'com.system76.CosmicSettings.WindowRules' / 'v1' / 'tiling_exception_defaults' + +session-desktop-src := 'data' / 'cosmic.desktop' +session-desktop-dst := share-dir / 'wayland-sessions' / 'cosmic.desktop' + +systemd-session-target-src := 'data' / 'cosmic-session.target' +systemd-session-target-dst := lib-dir / 'systemd' / 'user' / 'cosmic-session.target' + +systemd-session-pre-target-src := 'data' / 'cosmic-session-pre.target' +systemd-session-pre-target-dst := lib-dir / 'systemd' / 'user' / 'cosmic-session-pre.target' + +systemd-comp-service-src := 'data' / 'cosmic-comp.service' +systemd-comp-service-dst := lib-dir / 'systemd' / 'user' / 'cosmic-comp.service' + +cosmic-service-src := 'data' / 'cosmic-service' +cosmic-service-dst := bin-dir / 'cosmic-service' + +import 'cargo.just' + +# Default recipe which runs `just build-release` +[private] +default: build-release + +# Installs files +install: + install -Dm0755 {{bin-src}} {{bin-dst}} + install -Dm0644 {{keybindings-src}} {{keybindings-dst}} + install -Dm0644 {{tiling-exceptions-src}} {{tiling-exceptions-dst}} + +# Installs files including bare session files +install-bare-session: install + install -Dm0644 {{session-desktop-src}} {{session-desktop-dst}} + install -Dm0644 {{systemd-session-target-src}} {{systemd-session-target-dst}} + install -Dm0644 {{systemd-session-pre-target-src}} {{systemd-session-pre-target-dst}} + install -Dm0644 {{systemd-comp-service-src}} {{systemd-comp-service-dst}} + install -Dm0755 {{cosmic-service-src}} {{cosmic-service-dst}} + +# Uninstalls installed files +uninstall: + rm {{bin-dst}} {{keybindings-dst}} {{tiling-exceptions-dst}} + +# Uninstalls installed files including bare session files +uninstall-bare-session: uninstall + rm {{session-desktop-dst}} {{systemd-session-target-dst}} {{systemd-session-pre-target-dst}} {{systemd-comp-service-dst}} {{cosmic-service-dst}} From b97537096834751240378f3e4149ad950ad3d19c Mon Sep 17 00:00:00 2001 From: Frederic Laing Date: Tue, 30 Jun 2026 22:27:27 +0200 Subject: [PATCH 59/69] debian: add just to Build-Depends --- debian/control | 1 + 1 file changed, 1 insertion(+) diff --git a/debian/control b/debian/control index a3baf0eb..18c26482 100644 --- a/debian/control +++ b/debian/control @@ -6,6 +6,7 @@ Build-Depends: cargo, cmake, debhelper-compat (=10), + just, libegl1-mesa-dev, libfontconfig-dev, libgbm-dev, From 6e0aea0eb2832f4f92f46a26dbfc85f3a1235495 Mon Sep 17 00:00:00 2001 From: Niklas Herder Date: Sat, 12 Sep 2026 08:59:31 +0200 Subject: [PATCH 60/69] config: group cursor hiding into CursorHideConfig Replaces the flat cursor_hide_timeout key with a grouped cursor_hide key carrying the idle, fullscreen-idle, typing and touch triggers, plus the pure decision function the compositor's idle timer evaluates on fire. The fullscreen timeout shortens the global one rather than replacing it, so an unset fullscreen timeout cannot suppress an enabled global one. Drafted with Claude (Anthropic); reviewed and tested by the committer. --- cosmic-comp-config/src/lib.rs | 164 +++++++++++++++++++++++++++++++++- src/backend/render/cursor.rs | 2 +- src/config/mod.rs | 15 ++-- 3 files changed, 171 insertions(+), 10 deletions(-) diff --git a/cosmic-comp-config/src/lib.rs b/cosmic-comp-config/src/lib.rs index 510927f9..04415d5f 100644 --- a/cosmic-comp-config/src/lib.rs +++ b/cosmic-comp-config/src/lib.rs @@ -3,6 +3,7 @@ use cosmic_config::{CosmicConfigEntry, cosmic_config_derive::CosmicConfigEntry}; use serde::{Deserialize, Serialize}; use std::collections::HashMap; +use std::time::Duration; use crate::input::TouchpadOverride; @@ -106,8 +107,8 @@ pub struct CosmicCompConfig { pub edge_snap_threshold: u32, pub accessibility_zoom: ZoomConfig, pub appearance_settings: AppearanceConfig, - /// Hide the cursor after this many seconds of pointer inactivity (None disables) - pub cursor_hide_timeout: Option, + /// When the cursor hides itself: idle, fullscreen idle, typing, touch + pub cursor_hide: CursorHideConfig, /// Briefly magnify the cursor when the pointer is shaken, to help locate it pub cursor_shake_to_find: bool, pub activation_policy: ActivationPolicy, @@ -148,7 +149,7 @@ impl Default for CosmicCompConfig { edge_snap_threshold: 0, accessibility_zoom: ZoomConfig::default(), appearance_settings: AppearanceConfig::default(), - cursor_hide_timeout: None, + cursor_hide: CursorHideConfig::default(), cursor_shake_to_find: true, activation_policy: ActivationPolicy::default(), decoration_preference: DecorationPreference::default(), @@ -198,6 +199,74 @@ fn default_repeat_delay() -> u32 { 600 } +/// What the cursor idle timer should do when it fires. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum HideDecision { + /// Nothing applies in this context; drop the timer until the next activity. + Drop, + /// Hide the cursor now. + Hide, + /// Not yet — re-arm for this long. + RearmAfter(Duration), +} + +/// When the cursor hides itself. Every trigger is revealed by pointer input, so +/// these differ only in what arms the hide and after how long. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)] +pub struct CursorHideConfig { + /// Seconds of pointer inactivity before hiding, anywhere. `None` disables. + pub idle_timeout: Option, + /// Seconds of pointer inactivity before hiding over a fullscreen window. + /// Shortens `idle_timeout` in fullscreen; it never lengthens it. + pub fullscreen_idle_timeout: Option, + /// Hide as soon as a key is pressed. + pub while_typing: bool, + /// Hide on touch input, until the pointer next moves. + pub after_touch: bool, +} + +impl CursorHideConfig { + /// The shortest timeout that applies right now, if any. + pub fn effective_timeout(&self, fullscreen: bool) -> Option { + let secs = if fullscreen { + match (self.idle_timeout, self.fullscreen_idle_timeout) { + (Some(a), Some(b)) => Some(a.min(b)), + (a, b) => a.or(b), + } + } else { + self.idle_timeout + }?; + Some(Duration::from_secs(secs as u64)) + } + + /// What to do when the idle timer fires after `elapsed` without pointer input. + pub fn resolve(&self, elapsed: Duration, fullscreen: bool) -> HideDecision { + match self.effective_timeout(fullscreen) { + None => HideDecision::Drop, + Some(timeout) if elapsed >= timeout => HideDecision::Hide, + Some(timeout) => HideDecision::RearmAfter(timeout - elapsed), + } + } + + /// The delay to arm the timer with, before context is known. Callers on the + /// input path cannot read fullscreen state without deadlocking, so they arm + /// pessimistically and `resolve` corrects it on fire. + pub fn shortest_timeout(&self) -> Option { + self.effective_timeout(true) + } +} + +impl Default for CursorHideConfig { + fn default() -> Self { + CursorHideConfig { + idle_timeout: None, + fullscreen_idle_timeout: Some(3), + while_typing: false, + after_touch: true, + } + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)] pub struct ZoomConfig { pub start_on_login: bool, @@ -263,3 +332,92 @@ pub enum XwaylandDescaling { #[default] Fractional, } + +#[cfg(test)] +mod test { + use super::{CursorHideConfig, HideDecision}; + use std::time::Duration; + + const OFF: CursorHideConfig = CursorHideConfig { + idle_timeout: None, + fullscreen_idle_timeout: None, + while_typing: false, + after_touch: false, + }; + + fn secs(n: u64) -> Duration { + Duration::from_secs(n) + } + + #[test] + fn no_timeout_never_hides() { + assert_eq!(OFF.resolve(secs(600), false), HideDecision::Drop); + assert_eq!(OFF.resolve(secs(600), true), HideDecision::Drop); + } + + #[test] + fn global_timeout_applies_everywhere() { + let cfg = CursorHideConfig { + idle_timeout: Some(10), + ..OFF + }; + assert_eq!( + cfg.resolve(secs(4), false), + HideDecision::RearmAfter(secs(6)) + ); + assert_eq!(cfg.resolve(secs(10), false), HideDecision::Hide); + // A fullscreen window must not suppress an enabled global timeout. + assert_eq!(cfg.resolve(secs(10), true), HideDecision::Hide); + } + + #[test] + fn fullscreen_timeout_only_applies_in_fullscreen() { + let cfg = CursorHideConfig { + fullscreen_idle_timeout: Some(3), + ..OFF + }; + assert_eq!(cfg.resolve(secs(3), true), HideDecision::Hide); + assert_eq!(cfg.resolve(secs(600), false), HideDecision::Drop); + } + + #[test] + fn fullscreen_shortens_but_never_lengthens() { + let short_fs = CursorHideConfig { + idle_timeout: Some(10), + fullscreen_idle_timeout: Some(3), + ..OFF + }; + assert_eq!(short_fs.resolve(secs(3), true), HideDecision::Hide); + assert_eq!( + short_fs.resolve(secs(3), false), + HideDecision::RearmAfter(secs(7)) + ); + + let long_fs = CursorHideConfig { + idle_timeout: Some(3), + fullscreen_idle_timeout: Some(30), + ..OFF + }; + assert_eq!(long_fs.resolve(secs(3), true), HideDecision::Hide); + + // The arming delay is pessimistic: the shortest timeout that could + // apply in any context, because arm-time code cannot read the shell. + assert_eq!(short_fs.shortest_timeout(), Some(secs(3))); + assert_eq!(long_fs.shortest_timeout(), Some(secs(3))); + assert_eq!(OFF.shortest_timeout(), None); + } + + #[test] + fn boundary_is_inclusive() { + let cfg = CursorHideConfig { + idle_timeout: Some(5), + ..OFF + }; + assert_eq!( + cfg.resolve(Duration::from_millis(4999), false), + HideDecision::RearmAfter(Duration::from_millis(1)) + ); + assert_eq!(cfg.resolve(secs(5), false), HideDecision::Hide); + assert_eq!(cfg.resolve(secs(6), false), HideDecision::Hide); + } +} diff --git a/src/backend/render/cursor.rs b/src/backend/render/cursor.rs index 8e14d1be..97959c45 100644 --- a/src/backend/render/cursor.rs +++ b/src/backend/render/cursor.rs @@ -839,7 +839,7 @@ const ACTIVITY_THROTTLE: Duration = Duration::from_millis(100); /// Reveal the cursor and (re)arm the idle-hide timer; returns true if it was previously hidden pub fn notify_cursor_activity(state: &State, seat: &Seat) -> bool { - let timeout = state.common.config.cosmic_conf.cursor_hide_timeout; + let timeout = state.common.config.cosmic_conf.cursor_hide.idle_timeout; let loop_handle = &state.common.event_loop_handle; let cursor_state = seat.user_data().get::().unwrap(); let now = Instant::now(); diff --git a/src/config/mod.rs b/src/config/mod.rs index f8a51585..714dd29b 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -49,8 +49,8 @@ mod types; use cosmic::config::CosmicTk; pub use cosmic_comp_config::EdidProduct; use cosmic_comp_config::{ - ActivationPolicy, AppearanceConfig, CosmicCompConfig, DecorationPreference, KeyboardConfig, - TileBehavior, XkbConfig, XwaylandDescaling, XwaylandEavesdropping, ZoomConfig, + ActivationPolicy, AppearanceConfig, CosmicCompConfig, CursorHideConfig, DecorationPreference, + KeyboardConfig, TileBehavior, XkbConfig, XwaylandDescaling, XwaylandEavesdropping, ZoomConfig, input::{DeviceState as InputDeviceState, InputConfig, TouchpadOverride}, output::comp::{ OutputConfig, OutputInfo, OutputState, OutputsConfig, TransformDef, load_outputs, @@ -991,10 +991,13 @@ fn config_changed(config: cosmic_config::Config, keys: Vec, state: &mut let new = get_config::(&config, "cursor_shake_to_find"); state.common.config.cosmic_conf.cursor_shake_to_find = new; } - "cursor_hide_timeout" => { - let new = get_config::>(&config, "cursor_hide_timeout"); - if new != state.common.config.cosmic_conf.cursor_hide_timeout { - state.common.config.cosmic_conf.cursor_hide_timeout = new; + "cursor_hide" => { + let new = get_config::(&config, "cursor_hide"); + if new != state.common.config.cosmic_conf.cursor_hide { + state.common.config.cosmic_conf.cursor_hide = new; + // Reveal on every change: a visible cursor is the safe state, + // and it avoids stranding a hidden cursor when the trigger + // that hid it is switched off. let seats: Vec<_> = state.common.shell.read().seats.iter().cloned().collect(); let mut needs_render = false; for seat in seats { From 4e72d2ce982ba1e49f767d342cad7ef7c6423c04 Mon Sep 17 00:00:00 2001 From: Niklas Herder Date: Sat, 12 Sep 2026 09:03:34 +0200 Subject: [PATCH 61/69] config: migrate cursor_hide_timeout to the grouped cursor_hide key Reads the legacy key once at startup when the new one is absent, so the handful of people who set it by hand from the cosmic-settings#603 thread do not silently lose auto-hide. The old file is left on disk so a downgrade still finds it. Drafted with Claude (Anthropic); reviewed and tested by the committer. --- src/config/mod.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/config/mod.rs b/src/config/mod.rs index 714dd29b..24c579bc 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -10,7 +10,7 @@ use crate::{ }, }; use anyhow::Context; -use cosmic_config::{ConfigGet, CosmicConfigEntry}; +use cosmic_config::{ConfigGet, ConfigSet, CosmicConfigEntry}; use cosmic_settings_config::window_rules::ApplicationException; use cosmic_settings_config::{Shortcuts, shortcuts, window_rules}; use serde::{Deserialize, Serialize}; @@ -182,7 +182,7 @@ impl Config { .expect("Failed to add cosmic-config to the event loop"); let xdg = xdg::BaseDirectories::new(); - let cosmic_comp_config = + let mut cosmic_comp_config = CosmicCompConfig::get_entry(&config).unwrap_or_else(|(errs, c)| { if cfg!(debug_assertions) { for err in errs { @@ -192,6 +192,18 @@ impl Config { c }); + // `cursor_hide_timeout` was replaced by the grouped `cursor_hide` key. + // Seed the new key once so configs hand-edited before the rename keep + // working; the old file is left in place so a downgrade still reads it. + if config.get::("cursor_hide").is_err() + && let Ok(legacy) = config.get::>("cursor_hide_timeout") + { + cosmic_comp_config.cursor_hide.idle_timeout = legacy; + if let Err(err) = config.set("cursor_hide", cosmic_comp_config.cursor_hide) { + warn!(?err, "Failed to migrate cursor_hide_timeout to cursor_hide"); + } + } + // Listen for updates to the toolkit config if let Ok(tk_config) = cosmic_config::Config::new("com.system76.CosmicTk", 1) { fn handle_new_toolkit_config(config: CosmicTk, state: &mut State) { From 569cfa6442571c8d384a296a58f09b8956ad4616 Mon Sep 17 00:00:00 2001 From: Niklas Herder Date: Sat, 12 Sep 2026 09:13:02 +0200 Subject: [PATCH 62/69] cursor: re-evaluate the idle timer in context, add fullscreen hiding The timer now decides on fire rather than at arm time, so a shorter fullscreen timeout applies without hooking any of the six fullscreen transition sites in shell/mod.rs. Arming still touches no shell lock, which the PointerMotion call site requires. hidden becomes Option so the reveal rule can depend on why the cursor went away. Co-Authored-By: Claude Sonnet 5 Drafted with Claude (Anthropic); reviewed and tested by the committer. --- src/backend/render/cursor.rs | 194 +++++++++++++++++++++++++++++------ src/config/mod.rs | 7 +- src/input/mod.rs | 21 ++-- 3 files changed, 179 insertions(+), 43 deletions(-) diff --git a/src/backend/render/cursor.rs b/src/backend/render/cursor.rs index 97959c45..24ad5a60 100644 --- a/src/backend/render/cursor.rs +++ b/src/backend/render/cursor.rs @@ -5,9 +5,11 @@ use crate::{ element::AsGlowRenderer, wayland::{SurfaceRenderElement, push_render_elements_from_surface_tree}, }, + shell::focus::target::KeyboardFocusTarget, utils::prelude::*, wayland::handlers::compositor::FRAME_TIME_FILTER, }; +use cosmic_comp_config::HideDecision; use keyframe::{ease, functions::EaseInOutCubic}; use resvg::{tiny_skia, usvg}; use serde::Deserialize; @@ -451,6 +453,32 @@ pub fn draw_dnd_icon( ); } +/// Why the cursor is currently hidden. Determines what brings it back. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum HideReason { + /// No pointer activity for the configured timeout. + Idle, + /// A key was pressed while `while_typing` is enabled. + Typing, + /// Touch input arrived while `after_touch` is enabled. + Touch, +} + +/// Whether a pointer event carries movement. A touch-hidden cursor comes back +/// only on real movement, so the distinction has to reach the call site. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum PointerEventKind { + Motion, + Other, +} + +impl HideReason { + /// Whether an event of this kind should reveal the cursor. + fn revealed_by(self, kind: PointerEventKind) -> bool { + matches!(kind, PointerEventKind::Motion) || !matches!(self, HideReason::Touch) + } +} + pub type CursorState = Mutex; pub struct CursorStateInner { current_cursor: Option, @@ -462,9 +490,10 @@ pub struct CursorStateInner { current_image: Option, image_cache: Vec, - hidden: bool, + hidden: Option, idle_timer: Option, last_armed: Option, + last_pointer_activity: Instant, // shake-to-find shake_path: VecDeque, @@ -694,7 +723,8 @@ impl Default for CursorStateInner { current_image: None, image_cache: Vec::new(), - hidden: false, + hidden: None, + last_pointer_activity: Instant::now(), idle_timer: None, last_armed: None, @@ -747,7 +777,7 @@ pub fn draw_cursor( let mut state_ref = seat_userdata.get::().unwrap().lock().unwrap(); let state = &mut *state_ref; - if state.hidden { + if state.hidden.is_some() { return; } @@ -837,54 +867,130 @@ pub fn draw_cursor( const ACTIVITY_THROTTLE: Duration = Duration::from_millis(100); -/// Reveal the cursor and (re)arm the idle-hide timer; returns true if it was previously hidden -pub fn notify_cursor_activity(state: &State, seat: &Seat) -> bool { - let timeout = state.common.config.cosmic_conf.cursor_hide.idle_timeout; +/// Reveal the cursor if this event should, and (re)arm the idle-hide timer. +/// Returns true if the cursor was previously hidden and is now visible. +pub fn notify_cursor_activity(state: &State, seat: &Seat, kind: PointerEventKind) -> bool { + let cursor_state = seat.user_data().get::().unwrap(); + + let revealed = { + let mut inner = cursor_state.lock().unwrap(); + inner.last_pointer_activity = Instant::now(); + match inner.hidden { + Some(reason) if reason.revealed_by(kind) => { + inner.hidden = None; + true + } + // Still hidden on purpose: leave the timer alone. + Some(_) => return false, + None => false, + } + }; + + refresh_idle_timer(state, seat); + revealed +} + +/// (Re)arm the idle-hide timer without counting as pointer activity. +/// +/// Armed with the shortest timeout any context could want: the input that arms +/// the timer is usually what goes on to make a window fullscreen, so the +/// context is not yet knowable here. `on_idle_timer` evaluates it on fire and +/// re-arms for the remainder if nothing applied yet. +pub fn refresh_idle_timer(state: &State, seat: &Seat) { + let config = state.common.config.cosmic_conf.cursor_hide; let loop_handle = &state.common.event_loop_handle; let cursor_state = seat.user_data().get::().unwrap(); let now = Instant::now(); - let (was_hidden, old_token) = { + let old_token = { let mut inner = cursor_state.lock().unwrap(); - let was_hidden = inner.hidden; - inner.hidden = false; - - let throttled = timeout.is_some() - && !was_hidden - && inner.idle_timer.is_some() + if inner.hidden.is_some() { + return; + } + // Coalesce bursts from high-frequency pointers. + let throttled = inner.idle_timer.is_some() && inner .last_armed .is_some_and(|t| now.duration_since(t) < ACTIVITY_THROTTLE); if throttled { - return was_hidden; + return; } - - let old_token = inner.idle_timer.take(); inner.last_armed = None; - (was_hidden, old_token) + inner.idle_timer.take() }; if let Some(token) = old_token { loop_handle.remove(token); } - if let Some(secs) = timeout { - let timer = Timer::from_duration(Duration::from_secs(secs as u64)); - let seat = seat.clone(); - if let Ok(token) = loop_handle.insert_source(timer, move |_, _, state| { - hide_cursor(state, &seat); - TimeoutAction::Drop - }) { - let mut inner = cursor_state.lock().unwrap(); - inner.idle_timer = Some(token); - inner.last_armed = Some(now); - } - } + let Some(delay) = config.shortest_timeout() else { + return; + }; - was_hidden + let timer = Timer::from_duration(delay); + let timer_seat = seat.clone(); + if let Ok(token) = + loop_handle.insert_source(timer, move |_, _, state| on_idle_timer(state, &timer_seat)) + { + let mut inner = cursor_state.lock().unwrap(); + inner.idle_timer = Some(token); + inner.last_armed = Some(now); + } } -fn hide_cursor(state: &mut State, seat: &Seat) { +/// Whether the seat is focusing a fullscreen surface. A fullscreen window that +/// is not focused can be stacked behind others, so its presence on the output +/// says nothing about what the user is looking at. +fn fullscreen_focused(seat: &Seat) -> bool { + matches!( + seat.get_keyboard().and_then(|kbd| kbd.current_focus()), + Some(KeyboardFocusTarget::Fullscreen(_)) + ) +} + +fn on_idle_timer(state: &mut State, seat: &Seat) -> TimeoutAction { + let config = state.common.config.cosmic_conf.cursor_hide; + let fullscreen = fullscreen_focused(seat); + let cursor_state = seat.user_data().get::().unwrap(); + + let elapsed = { + let inner = cursor_state.lock().unwrap(); + Instant::now().duration_since(inner.last_pointer_activity) + }; + + match config.resolve(elapsed, fullscreen) { + HideDecision::Hide => { + hide_cursor(state, seat, HideReason::Idle); + TimeoutAction::Drop + } + HideDecision::Drop => { + let mut inner = cursor_state.lock().unwrap(); + inner.idle_timer = None; + inner.last_armed = None; + TimeoutAction::Drop + } + HideDecision::RearmAfter(delay) => { + cursor_state.lock().unwrap().last_armed = Some(Instant::now()); + TimeoutAction::ToDuration(delay) + } + } +} + +/// Hide the cursor immediately, for a trigger that does not wait on the timer. +pub fn hide_cursor_now(state: &mut State, seat: &Seat, reason: HideReason) { + let loop_handle = state.common.event_loop_handle.clone(); + let token = { + let cursor_state = seat.user_data().get::().unwrap(); + let mut inner = cursor_state.lock().unwrap(); + inner.idle_timer.take() + }; + if let Some(token) = token { + loop_handle.remove(token); + } + hide_cursor(state, seat, reason); +} + +fn hide_cursor(state: &mut State, seat: &Seat, reason: HideReason) { if let Some(ptr) = seat.get_pointer() && ptr.is_grabbed() { @@ -893,7 +999,10 @@ fn hide_cursor(state: &mut State, seat: &Seat) { let cursor_state = seat.user_data().get::().unwrap(); { let mut inner = cursor_state.lock().unwrap(); - inner.hidden = true; + if inner.hidden.is_some() { + return; + } + inner.hidden = Some(reason); inner.idle_timer = None; inner.last_armed = None; } @@ -902,3 +1011,24 @@ fn hide_cursor(state: &mut State, seat: &Seat) { state.backend.schedule_render(&output); } } + +#[cfg(test)] +mod test { + use super::{HideReason, PointerEventKind}; + + #[test] + fn touch_hidden_cursor_waits_for_movement() { + assert!(HideReason::Touch.revealed_by(PointerEventKind::Motion)); + assert!(!HideReason::Touch.revealed_by(PointerEventKind::Other)); + } + + #[test] + fn idle_and_typing_hidden_cursors_are_revealed_by_any_pointer_event() { + for reason in [HideReason::Idle, HideReason::Typing] { + assert!(reason.revealed_by(PointerEventKind::Motion)); + // A click or a scroll must rescue the cursor rather than forcing a + // blind click. + assert!(reason.revealed_by(PointerEventKind::Other)); + } + } +} diff --git a/src/config/mod.rs b/src/config/mod.rs index 24c579bc..9bdef7c1 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -1013,8 +1013,11 @@ fn config_changed(config: cosmic_config::Config, keys: Vec, state: &mut let seats: Vec<_> = state.common.shell.read().seats.iter().cloned().collect(); let mut needs_render = false; for seat in seats { - needs_render |= - crate::backend::render::cursor::notify_cursor_activity(state, &seat); + needs_render |= crate::backend::render::cursor::notify_cursor_activity( + state, + &seat, + crate::backend::render::cursor::PointerEventKind::Motion, + ); } if needs_render { let outputs: Vec<_> = diff --git a/src/input/mod.rs b/src/input/mod.rs index bbc6a931..05fa1205 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -1,7 +1,10 @@ // SPDX-License-Identifier: GPL-3.0-only use crate::{ - backend::render::{ElementFilter, cursor::notify_cursor_activity}, + backend::render::{ + ElementFilter, + cursor::{PointerEventKind, notify_cursor_activity}, + }, config::{ Action, Config, PrivateAction, key_bindings::{ @@ -349,7 +352,7 @@ impl State { .cloned() { self.common.idle_notifier_state.notify_activity(&seat); - notify_cursor_activity(self, &seat); + notify_cursor_activity(self, &seat, PointerEventKind::Motion); let current_output = seat.active_output(); if self.common.config.cosmic_conf.cursor_shake_to_find @@ -723,7 +726,7 @@ impl State { .cloned(); if let Some(seat) = maybe_seat { self.common.idle_notifier_state.notify_activity(&seat); - notify_cursor_activity(self, &seat); + notify_cursor_activity(self, &seat, PointerEventKind::Motion); let (output, position) = if matches!(&backend_id, InputBackendId::Ei(_)) { // EI absolute coordinates are in the compositor's *global* // logical space: each advertised region carries its output's @@ -818,7 +821,7 @@ impl State { return; }; self.common.idle_notifier_state.notify_activity(&seat); - notify_cursor_activity(self, &seat); + notify_cursor_activity(self, &seat, PointerEventKind::Other); let current_focus = seat.get_keyboard().unwrap().current_focus(); let shortcuts_inhibited = current_focus.as_ref().is_some_and(|f| { @@ -1069,7 +1072,7 @@ impl State { .cloned(); if let Some(seat) = maybe_seat { self.common.idle_notifier_state.notify_activity(&seat); - notify_cursor_activity(self, &seat); + notify_cursor_activity(self, &seat, PointerEventKind::Other); if self.source_modifiers(&backend_id, &seat).logo && self @@ -1608,7 +1611,7 @@ impl State { .cloned() { self.common.idle_notifier_state.notify_activity(&seat); - notify_cursor_activity(self, &seat); + notify_cursor_activity(self, &seat, PointerEventKind::Motion); let Some(output) = mapped_output_for_device(&self.common.config, &shell, &event.device()) .cloned() @@ -1712,7 +1715,7 @@ impl State { .cloned() { self.common.idle_notifier_state.notify_activity(&seat); - notify_cursor_activity(self, &seat); + notify_cursor_activity(self, &seat, PointerEventKind::Motion); let Some(output) = mapped_output_for_device(&self.common.config, &shell, &event.device()) .cloned() @@ -1861,7 +1864,7 @@ impl State { .cloned(); if let Some(seat) = maybe_seat { self.common.idle_notifier_state.notify_activity(&seat); - notify_cursor_activity(self, &seat); + notify_cursor_activity(self, &seat, PointerEventKind::Other); let serial = SERIAL_COUNTER.next_serial(); let output = seat.active_output(); @@ -1914,7 +1917,7 @@ impl State { .cloned(); if let Some(seat) = maybe_seat { self.common.idle_notifier_state.notify_activity(&seat); - notify_cursor_activity(self, &seat); + notify_cursor_activity(self, &seat, PointerEventKind::Other); if let Some(tool) = seat.tablet_seat().get_tool(&event.tool()) { tool.button( self, From 295eaa8f632618ca1b0b31bcee5766fd81caa689 Mon Sep 17 00:00:00 2001 From: Niklas Herder Date: Sat, 12 Sep 2026 09:22:50 +0200 Subject: [PATCH 63/69] cursor: hide while typing and after touch input MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Typing hides on a real keystroke only — a bare modifier press is excluded so Super+drag keeps its cursor. Touch hides until the pointer next moves, which the reveal rule enforces via HideReason::Touch. Drafted with Claude (Anthropic); reviewed and tested by the committer. --- src/input/mod.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/input/mod.rs b/src/input/mod.rs index 05fa1205..6cac7cdf 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -339,6 +339,26 @@ impl State { keyboard.modifier_state().num_lock; } } + + // A bare modifier press changes the modifier state; a real + // keystroke does not. Super+drag moves windows, so hiding on + // Super-down would take the cursor away exactly as the user + // reaches for it. Super+1 still counts as typing. + let bare_modifier = previous_modifiers != keyboard.modifier_state(); + if self.common.config.cosmic_conf.cursor_hide.while_typing + && state == KeyState::Pressed + && !bare_modifier + { + crate::backend::render::cursor::hide_cursor_now( + self, + &seat, + crate::backend::render::cursor::HideReason::Typing, + ); + } else { + // Still refresh: this is how entering fullscreen by + // keyboard arms the fullscreen timeout. + crate::backend::render::cursor::refresh_idle_timer(self, &seat); + } } } @@ -1496,6 +1516,14 @@ impl State { time: event.time(), }, ); + + if self.common.config.cosmic_conf.cursor_hide.after_touch { + crate::backend::render::cursor::hide_cursor_now( + self, + &seat, + crate::backend::render::cursor::HideReason::Touch, + ); + } } } InputEvent::TouchMotion { event, .. } => { From 7596cf7f2fe1919bf2320b09c1867272fd8db3eb Mon Sep 17 00:00:00 2001 From: Niklas Herder Date: Sat, 12 Sep 2026 09:47:19 +0200 Subject: [PATCH 64/69] config: deserialize cursor_hide with defaults for missing fields MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Serde ignores unknown fields but errors on missing ones, so adding a fifth trigger later would make every existing cursor_hide file fail to deserialize. get_entry would then substitute the struct default and Config::load swallows the error — its warn! loop is behind cfg!(debug_assertions) — silently resetting everyone's settings on upgrade. That is the exact failure this key was grouped to avoid. It also has a present-day effect: the migration shim cannot tell "absent" from "present but unparseable", so a partial hand-written cursor_hide was treated as absent and overwritten — and hand-editing is what the shim's audience does. Drafted with Claude (Anthropic); reviewed and tested by the committer. --- cosmic-comp-config/src/lib.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cosmic-comp-config/src/lib.rs b/cosmic-comp-config/src/lib.rs index 04415d5f..41b4dd2d 100644 --- a/cosmic-comp-config/src/lib.rs +++ b/cosmic-comp-config/src/lib.rs @@ -212,7 +212,10 @@ pub enum HideDecision { /// When the cursor hides itself. Every trigger is revealed by pointer input, so /// these differ only in what arms the hide and after how long. +// `default`: a trigger added later must not make every existing file fail to +// deserialize, which `get_entry` would swallow as "reset everyone to defaults". #[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)] +#[serde(default)] pub struct CursorHideConfig { /// Seconds of pointer inactivity before hiding, anywhere. `None` disables. pub idle_timeout: Option, From 115cdac039395d8a8f504006df6bae785f764986 Mon Sep 17 00:00:00 2001 From: Niklas Herder Date: Sat, 12 Sep 2026 09:48:09 +0200 Subject: [PATCH 65/69] cursor: measure the idle-hide deadline from the last pointer event MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit refresh_idle_timer armed for the full timeout measured from now, which is right only for notify_cursor_activity — it stamps activity immediately before arming. The other callers deliberately do not stamp, so with idle_timeout: Some(10) a user typing continuously never saw the cursor hide: every key press and release pushed the deadline out by a fresh ten seconds. That inverts the feature and regresses the shipped cursor_hide_timeout behaviour. resolve's RearmAfter cannot recover it — it only corrects a timer that fires too early. So the delay is now shortest_timeout minus the time already elapsed, extracted as CursorHideConfig::arm_delay and table tested; the arithmetic handed to Timer::from_duration was the one part of this path with no coverage. A zero delay is fine: the timer fires on the next loop iteration and resolve decides. Also rename fullscreen_focused to fullscreen_on_active_output, which is what seat.active_output() actually reports, and log an arming failure rather than silently disabling cursor hiding. Drafted with Claude (Anthropic); reviewed and tested by the committer. --- cosmic-comp-config/src/lib.rs | 43 ++++++++++++++++++++++++++--------- src/backend/render/cursor.rs | 25 ++++++++++++-------- 2 files changed, 48 insertions(+), 20 deletions(-) diff --git a/cosmic-comp-config/src/lib.rs b/cosmic-comp-config/src/lib.rs index 41b4dd2d..193fd0db 100644 --- a/cosmic-comp-config/src/lib.rs +++ b/cosmic-comp-config/src/lib.rs @@ -251,11 +251,15 @@ impl CursorHideConfig { } } - /// The delay to arm the timer with, before context is known. Callers on the - /// input path cannot read fullscreen state without deadlocking, so they arm - /// pessimistically and `resolve` corrects it on fire. - pub fn shortest_timeout(&self) -> Option { - self.effective_timeout(true) + /// How long to wait before the idle timer should next fire, given how long + /// it has been since the last pointer event. Pessimistic: fullscreen only + /// ever shortens a timeout, so arming as if fullscreen cannot fire too + /// late, and `resolve` corrects an early fire once the context is known. + pub fn arm_delay(&self, since_pointer_activity: Duration) -> Option { + Some( + self.effective_timeout(true)? + .saturating_sub(since_pointer_activity), + ) } } @@ -402,12 +406,6 @@ mod test { ..OFF }; assert_eq!(long_fs.resolve(secs(3), true), HideDecision::Hide); - - // The arming delay is pessimistic: the shortest timeout that could - // apply in any context, because arm-time code cannot read the shell. - assert_eq!(short_fs.shortest_timeout(), Some(secs(3))); - assert_eq!(long_fs.shortest_timeout(), Some(secs(3))); - assert_eq!(OFF.shortest_timeout(), None); } #[test] @@ -423,4 +421,27 @@ mod test { assert_eq!(cfg.resolve(secs(5), false), HideDecision::Hide); assert_eq!(cfg.resolve(secs(6), false), HideDecision::Hide); } + + #[test] + fn arm_delay_measures_from_the_last_pointer_event() { + let cfg = CursorHideConfig { + idle_timeout: Some(10), + ..OFF + }; + assert_eq!(cfg.arm_delay(Duration::ZERO), Some(secs(10))); + assert_eq!(cfg.arm_delay(secs(4)), Some(secs(6))); + // Exactly due, and past due: fire immediately rather than deferring. + assert_eq!(cfg.arm_delay(secs(10)), Some(Duration::ZERO)); + assert_eq!(cfg.arm_delay(secs(600)), Some(Duration::ZERO)); + + // Armed against the shortest timeout that any context could want. + let fs = CursorHideConfig { + idle_timeout: Some(10), + fullscreen_idle_timeout: Some(3), + ..OFF + }; + assert_eq!(fs.arm_delay(secs(1)), Some(secs(2))); + + assert_eq!(OFF.arm_delay(Duration::ZERO), None); + } } diff --git a/src/backend/render/cursor.rs b/src/backend/render/cursor.rs index 24ad5a60..95fb7500 100644 --- a/src/backend/render/cursor.rs +++ b/src/backend/render/cursor.rs @@ -892,6 +892,10 @@ pub fn notify_cursor_activity(state: &State, seat: &Seat, kind: PointerEv /// (Re)arm the idle-hide timer without counting as pointer activity. /// +/// The deadline is measured from the last *pointer* event, not from now, so a +/// caller that does not stamp activity — a keystroke, a config reload — cannot +/// postpone the hide by re-arming. +/// /// Armed with the shortest timeout any context could want: the input that arms /// the timer is usually what goes on to make a window fullscreen, so the /// context is not yet knowable here. `on_idle_timer` evaluates it on fire and @@ -902,7 +906,7 @@ pub fn refresh_idle_timer(state: &State, seat: &Seat) { let cursor_state = seat.user_data().get::().unwrap(); let now = Instant::now(); - let old_token = { + let (old_token, since_activity) = { let mut inner = cursor_state.lock().unwrap(); if inner.hidden.is_some() { return; @@ -915,26 +919,29 @@ pub fn refresh_idle_timer(state: &State, seat: &Seat) { if throttled { return; } + let since_activity = now.duration_since(inner.last_pointer_activity); inner.last_armed = None; - inner.idle_timer.take() + (inner.idle_timer.take(), since_activity) }; if let Some(token) = old_token { loop_handle.remove(token); } - let Some(delay) = config.shortest_timeout() else { + let Some(delay) = config.arm_delay(since_activity) else { return; }; let timer = Timer::from_duration(delay); let timer_seat = seat.clone(); - if let Ok(token) = - loop_handle.insert_source(timer, move |_, _, state| on_idle_timer(state, &timer_seat)) - { - let mut inner = cursor_state.lock().unwrap(); - inner.idle_timer = Some(token); - inner.last_armed = Some(now); + match loop_handle.insert_source(timer, move |_, _, state| on_idle_timer(state, &timer_seat)) { + Ok(token) => { + let mut inner = cursor_state.lock().unwrap(); + inner.idle_timer = Some(token); + inner.last_armed = Some(now); + } + // `idle_timer` stays `None`, so the next activity is unthrottled and retries. + Err(err) => warn!(?err, "Failed to arm the cursor idle-hide timer"), } } From 895ce91543450f6f45f6a60e097e9d294fa9809a Mon Sep 17 00:00:00 2001 From: Niklas Herder Date: Sat, 12 Sep 2026 09:48:29 +0200 Subject: [PATCH 66/69] cursor: let the hide reason tighten, and clear timer state when suppressed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hidden.is_some() guard dropped a hide-reason upgrade: an Idle-hidden cursor that received a touch stayed Idle, so a later click or scroll revealed it where the spec says a touch-hidden cursor waits for real movement. Reachable on the default config — fullscreen video, cursor idle-hidden after 3s, tap the screen, nudge the scroll wheel. The guard itself has to stay, or every keystroke with while_typing on reschedules a render on every output; so it now returns early only when the reason is unchanged or already Touch. hide_cursor also returned before clearing idle_timer and last_armed when the pointer was grabbed, leaving both stale while on_idle_timer's neighbouring Drop arm cleared them carefully. Clearing in hide_cursor before the grab check fixes both call sites at once — hide_cursor_now removes the source itself, and the Hide arm returns TimeoutAction::Drop — rather than restating the cleanup in one match arm. Drafted with Claude (Anthropic); reviewed and tested by the committer. --- src/backend/render/cursor.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/backend/render/cursor.rs b/src/backend/render/cursor.rs index 95fb7500..02da0685 100644 --- a/src/backend/render/cursor.rs +++ b/src/backend/render/cursor.rs @@ -998,20 +998,20 @@ pub fn hide_cursor_now(state: &mut State, seat: &Seat, reason: HideReason } fn hide_cursor(state: &mut State, seat: &Seat, reason: HideReason) { - if let Some(ptr) = seat.get_pointer() - && ptr.is_grabbed() - { - return; - } + let grabbed = seat.get_pointer().is_some_and(|ptr| ptr.is_grabbed()); let cursor_state = seat.user_data().get::().unwrap(); { let mut inner = cursor_state.lock().unwrap(); - if inner.hidden.is_some() { + // Every caller has already disposed of the timer source, so clear the + // bookkeeping before the grab check rather than only on success. + inner.idle_timer = None; + inner.last_armed = None; + // The reason only ever tightens: `Touch` waits for real movement, so a + // later trigger must not relax it back to click-or-scroll. + if grabbed || inner.hidden == Some(reason) || inner.hidden == Some(HideReason::Touch) { return; } inner.hidden = Some(reason); - inner.idle_timer = None; - inner.last_armed = None; } let outputs: Vec<_> = state.common.shell.read().outputs().cloned().collect(); for output in outputs { From 3d55cba06c9cf6f27609cdefb520f7857dba20af Mon Sep 17 00:00:00 2001 From: "Anthony T. Lannutti" Date: Sat, 13 Jun 2026 16:33:51 -0500 Subject: [PATCH 67/69] feat: make tracing-journald dependency optional Fixes #2466 --- Cargo.toml | 4 ++-- src/logger/mod.rs | 11 ++++++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index feb02259..288b4069 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -62,7 +62,7 @@ tracing = { version = "0.1.44", features = [ "max_level_debug", "release_max_level_info", ] } -tracing-journald = "0.3.2" +tracing-journald = { version = "0.3.2", optional = true } tracing-subscriber = { version = "0.3.22", features = [ "env-filter", "tracing-log", @@ -122,7 +122,7 @@ optional = true debug = ["egui", "egui_plot", "smithay-egui", "anyhow/backtrace"] default = ["systemd"] logind = ["logind-zbus"] -systemd = ["libsystemd", "logind"] +systemd = ["libsystemd", "logind", "tracing-journald"] profile-with-tracy = ["profiling/profile-with-tracy", "tracy-client/default"] profile-with-tracy-gpu = ["profile-with-tracy", "smithay/tracy_gpu_profiling"] diff --git a/src/logger/mod.rs b/src/logger/mod.rs index 3e5347df..34baf42d 100644 --- a/src/logger/mod.rs +++ b/src/logger/mod.rs @@ -4,7 +4,10 @@ use std::str::FromStr; use anyhow::Result; -use tracing::{debug, info, warn}; +#[cfg(feature = "systemd")] +use tracing::warn; +use tracing::{debug, info}; +#[cfg(feature = "systemd")] use tracing_journald as journald; use tracing_subscriber::{EnvFilter, filter::Directive, fmt, prelude::*}; @@ -29,6 +32,7 @@ pub fn init_logger() -> Result<()> { let fmt_layer = fmt::layer().compact(); + #[cfg(feature = "systemd")] match journald::layer() { Ok(journald_layer) => tracing_subscriber::registry() .with(fmt_layer) @@ -43,6 +47,11 @@ pub fn init_logger() -> Result<()> { warn!(?err, "Failed to init journald logging."); } }; + #[cfg(not(feature = "systemd"))] + tracing_subscriber::registry() + .with(fmt_layer) + .with(filter) + .init(); log_panics::init(); info!("Version: {}", std::env!("CARGO_PKG_VERSION")); From 41497b42d9744d9963c4c6d17e8add49489b45ee Mon Sep 17 00:00:00 2001 From: mikairyuu Date: Mon, 5 Oct 2026 20:39:33 +0900 Subject: [PATCH 68/69] backend: dmabuf: ensure primary render node is preffered --- src/backend/kms/mod.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/backend/kms/mod.rs b/src/backend/kms/mod.rs index 36c6407c..4dcffc75 100644 --- a/src/backend/kms/mod.rs +++ b/src/backend/kms/mod.rs @@ -615,7 +615,13 @@ impl State { .clone(); let mut feedback = - DmabufFeedbackBuilder::new(primary_node.dev_id(), primary_formats.clone()); + DmabufFeedbackBuilder::new(primary_node.dev_id(), primary_formats.clone()) + .add_preference_tranche( + primary_node.dev_id(), + TrancheFlags::Sampling, + primary_formats.iter().cloned(), + 3..=6, + ); for dev in kms .drm_devices .values() From 2f3a82beb4417e7e292631e6994c8c1e7735a9d8 Mon Sep 17 00:00:00 2001 From: Lionel DARNIS Date: Sun, 11 Oct 2026 07:02:21 +0200 Subject: [PATCH 69/69] chore: fige Cargo.lock (epoch-1.10.0, [patch] locaux) Co-Authored-By: Claude Opus 5.5 --- Cargo.lock | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c27ed2cb..715836fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1012,7 +1012,7 @@ dependencies = [ [[package]] name = "cosmic-randr-shell" -version = "1.3.0" +version = "1.10.0" dependencies = [ "kdl", "slotmap", @@ -1021,7 +1021,7 @@ dependencies = [ [[package]] name = "cosmic-settings-config" -version = "1.9.0" +version = "1.10.0" dependencies = [ "cosmic-config", "ron 0.11.0", @@ -1040,7 +1040,7 @@ dependencies = [ [[package]] name = "cosmic-settings-daemon-config" -version = "1.9.0" +version = "1.10.0" dependencies = [ "cosmic-config", "cosmic-theme", @@ -1564,7 +1564,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]] @@ -1963,8 +1963,8 @@ dependencies = [ "libc", "log", "rustversion", - "windows-link 0.2.1", - "windows-result 0.4.1", + "windows-link 0.1.3", + "windows-result 0.3.4", ] [[package]] @@ -2329,7 +2329,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.62.2", + "windows-core 0.61.2", ] [[package]] @@ -2833,7 +2833,7 @@ dependencies = [ "portable-atomic", "portable-atomic-util", "serde_core", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -4811,7 +4811,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.4.15", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -4824,7 +4824,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.12.1", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -5433,7 +5433,7 @@ dependencies = [ "getrandom 0.4.1", "once_cell", "rustix 1.1.4", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -6547,7 +6547,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]]