diff --git a/Cargo.toml b/Cargo.toml index 7a58d330..37ac23c2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -278,7 +278,7 @@ tiny-skia = { version = "0.11", default-features = false, features = [ "std", "simd", ] } -cctk = { git = "https://github.com/pop-os/cosmic-protocols", package = "cosmic-client-toolkit", rev = "178eb0b" } +cctk = { git = "https://github.com/pop-os/cosmic-protocols", package = "cosmic-client-toolkit", rev = "160b086" } softbuffer = { git = "https://github.com/pop-os/softbuffer", tag = "cosmic-4.0" } syntect = "5.2" tokio = "1.0" diff --git a/runtime/src/platform_specific/wayland/mod.rs b/runtime/src/platform_specific/wayland/mod.rs index ff4662a3..752ca49a 100644 --- a/runtime/src/platform_specific/wayland/mod.rs +++ b/runtime/src/platform_specific/wayland/mod.rs @@ -33,6 +33,16 @@ pub enum Action { Subsurface(subsurface::Action), /// Keyboard inhibit shortcuts InhibitShortcuts(bool), + /// Rounded corners in logical space + RoundedCorners(iced_core::window::Id, Option), +} + +#[derive(Debug, Clone, Copy, PartialEq, Default)] +pub struct CornerRadius { + pub top_left: u32, + pub top_right: u32, + pub bottom_left: u32, + pub bottom_right: u32, } impl Debug for Action { @@ -57,6 +67,9 @@ impl Debug for Action { Action::InhibitShortcuts(v) => { f.debug_tuple("InhibitShortcuts").field(v).finish() } + Action::RoundedCorners(id, v) => { + f.debug_tuple("RoundedCorners").field(id).field(v).finish() + } } } } diff --git a/winit/src/platform_specific/wayland/commands/corner_radius.rs b/winit/src/platform_specific/wayland/commands/corner_radius.rs new file mode 100644 index 00000000..cf16961b --- /dev/null +++ b/winit/src/platform_specific/wayland/commands/corner_radius.rs @@ -0,0 +1,20 @@ +use iced_futures::core::{border::Radius, window}; +use iced_runtime::{ + self, + platform_specific::{ + self, + wayland::{self, CornerRadius}, + }, + task, Action, Task, +}; + +pub fn corner_radius( + id: window::Id, + corners: Option, +) -> Task<()> { + task::oneshot(|_| { + Action::PlatformSpecific(platform_specific::Action::Wayland( + wayland::Action::RoundedCorners(id, corners), + )) + }) +} diff --git a/winit/src/platform_specific/wayland/commands/mod.rs b/winit/src/platform_specific/wayland/commands/mod.rs index 38b22e42..191dc3a5 100644 --- a/winit/src/platform_specific/wayland/commands/mod.rs +++ b/winit/src/platform_specific/wayland/commands/mod.rs @@ -1,6 +1,7 @@ //! Interact with the wayland objects of your application. pub mod activation; +pub mod corner_radius; pub mod keyboard_shortcuts_inhibit; pub mod layer_surface; pub mod overlap_notify; diff --git a/winit/src/platform_specific/wayland/event_loop/mod.rs b/winit/src/platform_specific/wayland/event_loop/mod.rs index cdef9ff6..f1420989 100644 --- a/winit/src/platform_specific/wayland/event_loop/mod.rs +++ b/winit/src/platform_specific/wayland/event_loop/mod.rs @@ -18,7 +18,9 @@ use crate::{ subsurface_widget::SubsurfaceState, }; -use cctk::sctk::reexports::calloop_wayland_source::WaylandSource; +use cctk::{ + cosmic_protocols::corner_radius::v1::client::cosmic_corner_radius_manager_v1::CosmicCornerRadiusManagerV1, sctk::reexports::calloop_wayland_source::WaylandSource, toplevel_info::ToplevelInfoState +}; use cctk::{ sctk::{ activation::ActivationState, @@ -37,7 +39,6 @@ use cctk::{ shell::{WaylandSurface, wlr_layer::LayerShell, xdg::XdgShell}, shm::Shm, }, - toplevel_info::ToplevelInfoState, toplevel_management::ToplevelManagerState, }; use raw_window_handle::HasDisplayHandle; @@ -126,7 +127,10 @@ impl SctkEventLoop { window, id, ) => { - state.windows.push(SctkWindow { window, id }); + state.windows.push(SctkWindow { window, id, corner_radius: Default::default() }); + if let Some(v) = state.pending_corner_radius.remove(&id) { + _ = state.handle_action(iced_runtime::platform_specific::wayland::Action::RoundedCorners(id, Some(v))); + } } crate::platform_specific::Action::RemoveWindow( id, @@ -201,7 +205,7 @@ impl SctkEventLoop { let half_h = size.height / 2.; match settings.gravity { wayland_protocols::xdg::shell::client::xdg_positioner::Gravity::None => { - // center on + // center on loc.x -= half_w; loc.y -= half_h; }, @@ -306,6 +310,11 @@ impl SctkEventLoop { ®istry_state, &qh, ), + corner_radius_manager: registry_state.bind_one::( + &qh, + 1..=1, + (), + ).ok(), toplevel_manager: ToplevelManagerState::try_new( ®istry_state, &qh, @@ -348,6 +357,7 @@ impl SctkEventLoop { token_senders: HashMap::new(), overlap_notifications: HashMap::new(), subsurface_state: None, + pending_corner_radius: HashMap::new(), }, _features: Default::default(), }; diff --git a/winit/src/platform_specific/wayland/event_loop/state.rs b/winit/src/platform_specific/wayland/event_loop/state.rs index d5f4f0bc..549d1b77 100644 --- a/winit/src/platform_specific/wayland/event_loop/state.rs +++ b/winit/src/platform_specific/wayland/event_loop/state.rs @@ -1,8 +1,5 @@ use crate::{ Control, - sctk_event::KeyboardEventVariant, - subsurface_widget::SubsurfaceState, - wayland::SubsurfaceInstance, handlers::{ activation::IcedRequestData, overlap::{OverlapNotificationV1, OverlapNotifyV1}, @@ -17,6 +14,9 @@ use crate::{ sctk_event::{LayerSurfaceEventVariant, SctkEvent}, }, }, + sctk_event::KeyboardEventVariant, + subsurface_widget::SubsurfaceState, + wayland::SubsurfaceInstance, }; use iced_futures::{ core::{Rectangle, Size}, @@ -27,7 +27,7 @@ use std::{ collections::{HashMap, HashSet}, convert::Infallible, fmt::Debug, - sync::{atomic::AtomicU32, Arc, Mutex}, + sync::{Arc, Mutex, atomic::AtomicU32}, thread::panicking, time::Duration, }; @@ -37,66 +37,85 @@ use winit::{ platform::wayland::WindowExtWayland, }; +use cctk::{ + cosmic_protocols::{ + corner_radius::v1::client::{ + cosmic_corner_radius_manager_v1::CosmicCornerRadiusManagerV1, + cosmic_corner_radius_toplevel_v1::CosmicCornerRadiusToplevelV1, + }, + overlap_notify::v1::client::zcosmic_overlap_notification_v1::ZcosmicOverlapNotificationV1, + }, + sctk::{ + activation::{ActivationState, RequestData}, + compositor::CompositorState, + error::GlobalError, + globals::GlobalData, + output::OutputState, + reexports::{ + calloop::{LoopHandle, timer::TimeoutAction}, + client::{ + Connection, Proxy, QueueHandle, delegate_noop, + protocol::{ + wl_keyboard::WlKeyboard, + wl_output::WlOutput, + wl_region::WlRegion, + wl_seat::WlSeat, + wl_subsurface::WlSubsurface, + wl_surface::{self, WlSurface}, + wl_touch::WlTouch, + }, + }, + }, + registry::RegistryState, + seat::{ + SeatState, + keyboard::KeyEvent, + pointer::{CursorIcon, PointerData, ThemedPointer}, + touch::TouchData, + }, + session_lock::{ + SessionLock, SessionLockState, SessionLockSurface, + SessionLockSurfaceConfigure, + }, + shell::{ + WaylandSurface, + wlr_layer::{ + Anchor, KeyboardInteractivity, Layer, LayerShell, LayerSurface, + LayerSurfaceConfigure, SurfaceKind, + }, + xdg::{ + XdgPositioner, XdgShell, + popup::{Popup, PopupConfigure}, + }, + }, + shm::{Shm, multi::MultiPool}, + }, + toplevel_info::ToplevelInfoState, + toplevel_management::ToplevelManagerState, +}; use iced_runtime::{ core::{self, Point, touch}, keyboard::Modifiers, platform_specific::{ self, wayland::{ - layer_surface::{IcedMargin, IcedOutput, SctkLayerSurfaceSettings}, popup::SctkPopupSettings, subsurface::{self, SctkSubsurfaceSettings}, Action + Action, CornerRadius, + layer_surface::{IcedMargin, IcedOutput, SctkLayerSurfaceSettings}, + popup::SctkPopupSettings, + subsurface::{self, SctkSubsurfaceSettings}, }, }, }; -use cctk::{cosmic_protocols::overlap_notify::v1::client::zcosmic_overlap_notification_v1::ZcosmicOverlapNotificationV1, sctk::{ - activation::{ActivationState, RequestData}, - compositor::CompositorState, - error::GlobalError, - globals::GlobalData, - output::OutputState, - reexports::{ - calloop::{LoopHandle, timer::TimeoutAction}, - client::{ - Connection, Proxy, QueueHandle, delegate_noop, - protocol::{ - wl_keyboard::WlKeyboard, - wl_output::WlOutput, - wl_region::WlRegion, - wl_seat::WlSeat, - wl_subsurface::WlSubsurface, - wl_surface::{self, WlSurface}, - wl_touch::WlTouch, - }, - }, - }, - registry::RegistryState, - seat::{ - SeatState, - keyboard::KeyEvent, - pointer::{CursorIcon, PointerData, ThemedPointer}, - touch::TouchData, - }, - session_lock::{ - SessionLock, SessionLockState, SessionLockSurface, - SessionLockSurfaceConfigure, - }, - shell::{ - WaylandSurface, - wlr_layer::{ - Anchor, KeyboardInteractivity, Layer, LayerShell, LayerSurface, - LayerSurfaceConfigure, SurfaceKind, - }, - xdg::{ - XdgPositioner, XdgShell, - popup::{Popup, PopupConfigure}, - }, - }, - shm::{multi::MultiPool, Shm}, -}, toplevel_info::ToplevelInfoState, toplevel_management::ToplevelManagerState}; use wayland_protocols::{ wp::{ - fractional_scale::v1::client::wp_fractional_scale_v1::WpFractionalScaleV1, keyboard_shortcuts_inhibit::zv1::client::{zwp_keyboard_shortcuts_inhibit_manager_v1, zwp_keyboard_shortcuts_inhibitor_v1}, viewporter::client::wp_viewport::WpViewport + fractional_scale::v1::client::wp_fractional_scale_v1::WpFractionalScaleV1, + keyboard_shortcuts_inhibit::zv1::client::{ + zwp_keyboard_shortcuts_inhibit_manager_v1, + zwp_keyboard_shortcuts_inhibitor_v1, + }, + viewporter::client::wp_viewport::WpViewport, }, - xdg::shell::client::xdg_surface::XdgSurface, + xdg::shell::client::{xdg_surface::XdgSurface, xdg_toplevel::XdgToplevel}, }; pub static TOKEN_CTR: AtomicU32 = AtomicU32::new(0); @@ -311,9 +330,22 @@ pub struct SctkPopupData { pub(crate) grab: bool, } +#[derive(Debug)] +pub struct MyCosmicCornerRadiusToplevelV1(CosmicCornerRadiusToplevelV1); + +impl Drop for MyCosmicCornerRadiusToplevelV1 { + fn drop(&mut self) { + self.0.destroy(); + } +} + +#[derive(Debug, Clone)] +pub struct SctkCornerRadius(Arc); + pub struct SctkWindow { pub(crate) window: Arc, pub(crate) id: core::window::Id, + pub(crate) corner_radius: Option<(SctkCornerRadius, CornerRadius)>, } impl SctkWindow { @@ -348,6 +380,19 @@ impl SctkWindow { .unwrap(); XdgSurface::from_id(conn, id).unwrap() } + + pub fn xdg_toplevel(&self, conn: &Connection) -> XdgToplevel { + let window_handle = self.window.xdg_toplevel().unwrap(); + + let id = unsafe { + ObjectId::from_ptr( + XdgToplevel::interface(), + window_handle.as_ptr().cast(), + ) + } + .unwrap(); + XdgToplevel::from_id(conn, id).unwrap() + } } pub(crate) enum FrameStatus { @@ -436,6 +481,9 @@ pub struct SctkState { pub(crate) inhibitor: Option, pub(crate) inhibited: bool, pub(crate) inhibitor_manager: Option, + + pub(crate) corner_radius_manager: Option, + pub(crate) pending_corner_radius: HashMap } /// An error that occurred while running an application. @@ -722,6 +770,7 @@ impl SctkState { else { return Err(PopupCreationError::ParentMissing); }; + ( &parent_window.wl_surface(&self.connection), Popup::from_surface( @@ -1468,7 +1517,7 @@ impl SctkState { Action::InhibitShortcuts(v) => { if let Some(manager) = self.inhibitor_manager.as_ref() { if let Some(inhibit) = self.inhibitor.take() { - inhibit.destroy(); + inhibit.destroy(); } if v { self.inhibitor = self.seats.iter().next() @@ -1476,6 +1525,45 @@ impl SctkState { } } } + Action::RoundedCorners(id, v) => { + if let Some(manager) = self.corner_radius_manager.as_ref() { + if let Some(w) = self.windows.iter_mut().find(|w| w.id == id) { + if let Some(radii) = v { + if let Some((protocol_object, corner_radii)) = w.corner_radius.as_mut() { + if *corner_radii != radii { + protocol_object.0.0.set_radius(radii.top_left, + radii.top_right, + radii.bottom_right, + radii.bottom_left,); + *corner_radii = radii.clone(); + } + } else { + let toplevel = w.xdg_toplevel(&self.connection); + + let protocol_object = manager.get_corner_radius(&toplevel, &self.queue_handle, ()); + protocol_object.set_radius( + radii.top_left, + radii.top_right, + radii.bottom_right, + radii.bottom_left, + ); + w.corner_radius = Some((SctkCornerRadius(Arc::new(MyCosmicCornerRadiusToplevelV1( protocol_object))), radii.clone())); + } + } else { + if let Some(old) = w.corner_radius.take() { + old.0.0.as_ref().0.unset_radius(); + } + w.corner_radius = None; + } + } else { + if let Some(v) = v{ + _ = self.pending_corner_radius.insert(id, v); + } else { + _ = self.pending_corner_radius.remove(&id); + } + } + } + } }; Ok(()) } diff --git a/winit/src/platform_specific/wayland/handlers/mod.rs b/winit/src/platform_specific/wayland/handlers/mod.rs index 0079299f..856c5c32 100644 --- a/winit/src/platform_specific/wayland/handlers/mod.rs +++ b/winit/src/platform_specific/wayland/handlers/mod.rs @@ -11,14 +11,14 @@ pub mod toplevel; pub mod wp_fractional_scaling; pub mod wp_viewporter; -use cctk::sctk::{ +use cctk::{sctk::{ delegate_registry, delegate_shm, output::OutputState, registry::{ProvidesRegistryState, RegistryState}, registry_handlers, seat::SeatState, shm::{Shm, ShmHandler}, -}; +}}; use crate::platform_specific::wayland::event_loop::state::SctkState; diff --git a/winit/src/platform_specific/wayland/handlers/seat/keyboard.rs b/winit/src/platform_specific/wayland/handlers/seat/keyboard.rs index b587a365..5ff7fb4b 100644 --- a/winit/src/platform_specific/wayland/handlers/seat/keyboard.rs +++ b/winit/src/platform_specific/wayland/handlers/seat/keyboard.rs @@ -2,11 +2,11 @@ use crate::platform_specific::wayland::{ event_loop::state::SctkState, sctk_event::{KeyboardEventVariant, SctkEvent}, }; -use cctk::sctk::reexports::client::Proxy; use cctk::sctk::{ delegate_keyboard, seat::keyboard::{KeyboardHandler, Keysym}, }; +use cctk::sctk::{reexports::client::Proxy, seat::keyboard::RawModifiers}; impl KeyboardHandler for SctkState { fn enter( @@ -232,7 +232,8 @@ impl KeyboardHandler for SctkState { keyboard: &cctk::sctk::reexports::client::protocol::wl_keyboard::WlKeyboard, _serial: u32, modifiers: cctk::sctk::seat::keyboard::Modifiers, - layout: u32, + _raw_modifiers: RawModifiers, + _layout: u32, ) { let (is_active, my_seat) = match self.seats.iter_mut().enumerate().find_map(|(i, s)| { @@ -268,6 +269,17 @@ impl KeyboardHandler for SctkState { } } } + + fn repeat_key( + &mut self, + _conn: &wayland_client::Connection, + _qh: &wayland_client::QueueHandle, + _keyboard: &wayland_client::protocol::wl_keyboard::WlKeyboard, + _serial: u32, + _event: cctk::sctk::seat::keyboard::KeyEvent, + ) { + // TODO + } } delegate_keyboard!(SctkState); diff --git a/winit/src/platform_specific/wayland/handlers/shell/corner_radius.rs b/winit/src/platform_specific/wayland/handlers/shell/corner_radius.rs new file mode 100644 index 00000000..bd7d2409 --- /dev/null +++ b/winit/src/platform_specific/wayland/handlers/shell/corner_radius.rs @@ -0,0 +1,45 @@ +use cctk::{sctk, cosmic_protocols::{ + corner_radius::v1::client::{ + cosmic_corner_radius_manager_v1::CosmicCornerRadiusManagerV1, + cosmic_corner_radius_toplevel_v1::CosmicCornerRadiusToplevelV1, + }, + overlap_notify::v1::client::zcosmic_overlap_notification_v1::ZcosmicOverlapNotificationV1, +}}; +use sctk::reexports::{ + client::{Connection, Dispatch, Proxy}, + +}; + +use crate::event_loop::state::SctkState; +use crate::platform_specific::wayland::SctkEvent; + +impl Dispatch for SctkState { + fn event( + _state: &mut Self, + _proxy: &CosmicCornerRadiusManagerV1, + _event: ::Event, + _data: &(), + _conn: &Connection, + _qhandle: &sctk::reexports::client::QueueHandle, + ) {} +} + +impl + Dispatch< + CosmicCornerRadiusToplevelV1, + (), + > for SctkState +{ + fn event( + state: &mut Self, + _proxy: &CosmicCornerRadiusToplevelV1, + event: ::Event, + _data: &(), + _conn: &Connection, + _qhandle: &sctk::reexports::client::QueueHandle, + ) { + match event { + _ => unimplemented!() + } + } +} diff --git a/winit/src/platform_specific/wayland/handlers/shell/mod.rs b/winit/src/platform_specific/wayland/handlers/shell/mod.rs index 5556c08d..af8b5961 100644 --- a/winit/src/platform_specific/wayland/handlers/shell/mod.rs +++ b/winit/src/platform_specific/wayland/handlers/shell/mod.rs @@ -1,3 +1,4 @@ pub mod layer; pub mod xdg_popup; pub mod xdg_window; +pub mod corner_radius;