From 78ffe3a93d7b4302be23345e7d7246af4edab010 Mon Sep 17 00:00:00 2001 From: Victoria Brekenfeld Date: Mon, 16 Jan 2023 20:31:43 +0100 Subject: [PATCH] shell/wayland: Enable xdg/kde-decoration protocols --- src/shell/element/mod.rs | 14 +++ src/shell/element/window.rs | 55 +++++------ src/shell/mod.rs | 4 +- src/state.rs | 19 +++- src/wayland/handlers/decoration.rs | 141 +++++++++++++++++++++++++++++ src/wayland/handlers/mod.rs | 1 + 6 files changed, 195 insertions(+), 39 deletions(-) create mode 100644 src/wayland/handlers/decoration.rs diff --git a/src/shell/element/mod.rs b/src/shell/element/mod.rs index e2d50992..1b87dee5 100644 --- a/src/shell/element/mod.rs +++ b/src/shell/element/mod.rs @@ -422,6 +422,20 @@ impl CosmicMapped { window.close(); } + pub fn is_window(&self) -> bool { + match &self.element { + CosmicMappedInternal::Window(_) => true, + _ => false, + } + } + + pub fn is_stack(&self) -> bool { + match &self.element { + CosmicMappedInternal::Stack(_) => true, + _ => false, + } + } + #[cfg(feature = "debug")] pub fn set_debug(&self, flag: bool) { let mut debug = self.debug.lock().unwrap(); diff --git a/src/shell/element/window.rs b/src/shell/element/window.rs index 8a963933..72e15a08 100644 --- a/src/shell/element/window.rs +++ b/src/shell/element/window.rs @@ -58,7 +58,7 @@ impl fmt::Debug for CosmicWindow { #[derive(Debug, Clone)] pub struct CosmicWindowInternal { pub(super) window: CosmicSurface, - pointer_entered: Option>, + pointer_entered: Arc, } #[repr(u8)] @@ -71,27 +71,19 @@ pub enum Focus { impl CosmicWindowInternal { pub fn swap_focus(&self, focus: Focus) -> Focus { - if let Some(pointer_entered) = self.pointer_entered.as_ref() { - unsafe { - std::mem::transmute::( - pointer_entered.swap(focus as u8, Ordering::SeqCst), - ) - } - } else { - Focus::Window + unsafe { + std::mem::transmute::( + self.pointer_entered.swap(focus as u8, Ordering::SeqCst), + ) } } pub fn current_focus(&self) -> Focus { - if let Some(pointer_entered) = self.pointer_entered.as_ref() { - unsafe { std::mem::transmute::(pointer_entered.load(Ordering::SeqCst)) } - } else { - Focus::Window - } + unsafe { std::mem::transmute::(self.pointer_entered.load(Ordering::SeqCst)) } } pub fn has_ssd(&self) -> bool { - self.pointer_entered.is_some() + !self.window.is_decorated() } } @@ -101,16 +93,11 @@ impl CosmicWindow { handle: LoopHandle<'static, crate::state::Data>, ) -> CosmicWindow { let window = window.into(); - let needs_ssd = !window.is_decorated(); let width = window.geometry().size.w; CosmicWindow(IcedElement::new( CosmicWindowInternal { window, - pointer_entered: if needs_ssd { - Some(Arc::new(AtomicU8::new(Focus::None as u8))) - } else { - None - }, + pointer_entered: Arc::new(AtomicU8::new(Focus::None as u8)), }, (width, SSD_HEIGHT), handle, @@ -382,6 +369,7 @@ impl PointerTarget for CosmicWindow { Some((previous, Focus::Window)) } } else { + p.swap_focus(Focus::Window); PointerTarget::motion(&p.window, seat, data, event); None } @@ -427,7 +415,6 @@ impl PointerTarget for CosmicWindow { p.swap_focus(Focus::None) }); - assert!(previous != Focus::None); match previous { Focus::Header => PointerTarget::leave(&self.0, seat, data, serial, time), Focus::Window => self @@ -453,27 +440,27 @@ where fn render_elements>( &self, renderer: &mut R, - mut location: Point, + location: Point, scale: Scale, ) -> Vec { let has_ssd = self.0.with_program(|p| p.has_ssd()); - let mut elements = if has_ssd { - let elements = AsRenderElements::::render_elements::>( - &self.0, renderer, location, scale, - ); - location.y += SSD_HEIGHT; - elements + let window_loc = if has_ssd { + location + Point::from((0, (SSD_HEIGHT as f64 * scale.y) as i32)) } else { - Vec::new() + location }; - elements.extend(self.0.with_program(|p| { + let mut elements = self.0.with_program(|p| { AsRenderElements::::render_elements::>( - &p.window, renderer, location, scale, + &p.window, renderer, window_loc, scale, ) - .into_iter() - })); + }); + if has_ssd { + elements.extend(AsRenderElements::::render_elements::< + CosmicWindowRenderElement, + >(&self.0, renderer, location, scale)) + } elements.into_iter().map(C::from).collect() } diff --git a/src/shell/mod.rs b/src/shell/mod.rs index d61fd240..d734a903 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -37,10 +37,10 @@ pub mod focus; pub mod grabs; pub mod layout; mod workspace; -pub use self::element::{CosmicMappedRenderElement, CosmicSurface}; +pub use self::element::{CosmicMapped, CosmicMappedRenderElement, CosmicSurface}; pub use self::workspace::*; use self::{ - element::{CosmicMapped, CosmicWindow}, + element::CosmicWindow, focus::target::KeyboardFocusTarget, layout::{floating::FloatingLayout, tiling::TilingLayout}, }; diff --git a/src/state.rs b/src/state.rs index c155bcf8..e4cab952 100644 --- a/src/state.rs +++ b/src/state.rs @@ -29,6 +29,7 @@ use smithay::{ output::{Mode as OutputMode, Output, Scale}, reexports::{ calloop::{LoopHandle, LoopSignal}, + wayland_protocols_misc::server_decoration::server::org_kde_kwin_server_decoration_manager::Mode, wayland_server::{ backend::{ClientData, ClientId, DisconnectReason}, protocol::wl_shm, @@ -37,9 +38,15 @@ use smithay::{ }, utils::{Clock, Monotonic}, wayland::{ - compositor::CompositorState, data_device::DataDeviceState, dmabuf::DmabufState, - keyboard_shortcuts_inhibit::KeyboardShortcutsInhibitState, output::OutputManagerState, - presentation::PresentationState, primary_selection::PrimarySelectionState, shm::ShmState, + compositor::CompositorState, + data_device::DataDeviceState, + dmabuf::DmabufState, + keyboard_shortcuts_inhibit::KeyboardShortcutsInhibitState, + output::OutputManagerState, + presentation::PresentationState, + primary_selection::PrimarySelectionState, + shell::{kde::decoration::KdeDecorationState, xdg::decoration::XdgDecorationState}, + shm::ShmState, viewporter::ViewporterState, }, }; @@ -101,6 +108,8 @@ pub struct Common { pub shm_state: ShmState, pub wl_drm_state: WlDrmState, pub viewporter_state: ViewporterState, + pub kde_decoration_state: KdeDecorationState, + pub xdg_decoration_state: XdgDecorationState, } pub enum BackendData { @@ -229,6 +238,8 @@ impl State { let seat_state = SeatState::::new(); let viewporter_state = ViewporterState::new::(dh, None); let wl_drm_state = WlDrmState; + let kde_decoration_state = KdeDecorationState::new::(&dh, Mode::Client, None); + let xdg_decoration_state = XdgDecorationState::new::(&dh, None); let shell = Shell::new(&config, dh); @@ -264,6 +275,8 @@ impl State { primary_selection_state, viewporter_state, wl_drm_state, + kde_decoration_state, + xdg_decoration_state, }, backend: BackendData::Unset, } diff --git a/src/wayland/handlers/decoration.rs b/src/wayland/handlers/decoration.rs new file mode 100644 index 00000000..4dff1650 --- /dev/null +++ b/src/wayland/handlers/decoration.rs @@ -0,0 +1,141 @@ +use smithay::{ + delegate_kde_decoration, delegate_xdg_decoration, + reexports::{ + wayland_protocols::xdg::decoration::zv1::server::zxdg_toplevel_decoration_v1::Mode as XdgMode, + wayland_protocols_misc::server_decoration::server::org_kde_kwin_server_decoration::{ + Mode as KdeMode, OrgKdeKwinServerDecoration, + }, + wayland_server::protocol::wl_surface::WlSurface, + }, + wayland::{ + seat::WaylandFocus, + shell::{ + kde::decoration::{KdeDecorationHandler, KdeDecorationState}, + xdg::{decoration::XdgDecorationHandler, ToplevelSurface}, + }, + }, +}; +use wayland_backend::protocol::WEnum; + +use crate::{ + shell::{CosmicMapped, CosmicSurface}, + state::State, +}; + +impl State { + pub fn new_decoration(mapped: &CosmicMapped, surface: &WlSurface) -> KdeMode { + if mapped.is_stack() { + if let Some((CosmicSurface::Wayland(window), _)) = mapped + .windows() + .find(|(window, _)| window.wl_surface().as_ref() == Some(surface)) + { + window + .toplevel() + .with_pending_state(|state| state.decoration_mode = Some(XdgMode::ServerSide)); + window.toplevel().send_configure(); + } + KdeMode::Server + } else { + if let Some((CosmicSurface::Wayland(window), _)) = mapped + .windows() + .find(|(window, _)| window.wl_surface().as_ref() == Some(surface)) + { + window + .toplevel() + .with_pending_state(|state| state.decoration_mode = Some(XdgMode::ClientSide)); + window.toplevel().send_configure(); + } + KdeMode::Client + } + } + + pub fn request_mode(mapped: &CosmicMapped, surface: &WlSurface, mode: XdgMode) { + if let Some((CosmicSurface::Wayland(window), _)) = mapped + .windows() + .find(|(window, _)| window.wl_surface().as_ref() == Some(surface)) + { + window.toplevel().with_pending_state(|state| { + state.decoration_mode = dbg!(Some(mode)); + }); + window.toplevel().send_configure(); + } + } + + pub fn unset_mode(mapped: &CosmicMapped, surface: &WlSurface) { + if let Some((CosmicSurface::Wayland(window), _)) = mapped + .windows() + .find(|(window, _)| window.wl_surface().as_ref() == Some(surface)) + { + window.toplevel().with_pending_state(|state| { + state.decoration_mode = None; + }); + window.toplevel().send_configure(); + } + } +} + +impl XdgDecorationHandler for State { + fn new_decoration(&mut self, toplevel: ToplevelSurface) { + if let Some(mapped) = self.common.shell.element_for_surface(toplevel.wl_surface()) { + State::new_decoration(mapped, toplevel.wl_surface()); + } + } + + fn request_mode(&mut self, toplevel: ToplevelSurface, mode: XdgMode) { + if let Some(mapped) = self.common.shell.element_for_surface(toplevel.wl_surface()) { + State::request_mode(mapped, toplevel.wl_surface(), mode); + } else { + toplevel.with_pending_state(|state| state.decoration_mode = Some(mode)); + } + } + + fn unset_mode(&mut self, toplevel: ToplevelSurface) { + if let Some(mapped) = self.common.shell.element_for_surface(toplevel.wl_surface()) { + State::unset_mode(mapped, toplevel.wl_surface()) + } + } +} + +impl KdeDecorationHandler for State { + fn kde_decoration_state(&self) -> &KdeDecorationState { + &self.common.kde_decoration_state + } + + fn new_decoration(&mut self, surface: &WlSurface, decoration: &OrgKdeKwinServerDecoration) { + if let Some(mapped) = self.common.shell.element_for_surface(surface) { + let mode = State::new_decoration(mapped, surface); + decoration.mode(mode); + } + } + + fn request_mode( + &mut self, + surface: &WlSurface, + decoration: &OrgKdeKwinServerDecoration, + mode: WEnum, + ) { + if let WEnum::Value(mode) = mode { + // TODO: We need to store this value until it gets mapped and apply it then, if it is not mapped yet. + if let Some(mapped) = self.common.shell.element_for_surface(surface) { + State::request_mode( + mapped, + surface, + match mode { + KdeMode::Server => XdgMode::ServerSide, + _ => XdgMode::ClientSide, + }, + ); + decoration.mode(mode); + } + } + } + + fn release(&mut self, _decoration: &OrgKdeKwinServerDecoration, surface: &WlSurface) { + if let Some(mapped) = self.common.shell.element_for_surface(surface) { + State::unset_mode(mapped, surface) + } + } +} + +delegate_xdg_decoration!(State); +delegate_kde_decoration!(State); diff --git a/src/wayland/handlers/mod.rs b/src/wayland/handlers/mod.rs index 6b6028d5..5ab68521 100644 --- a/src/wayland/handlers/mod.rs +++ b/src/wayland/handlers/mod.rs @@ -3,6 +3,7 @@ pub mod buffer; pub mod compositor; pub mod data_device; +pub mod decoration; pub mod dmabuf; pub mod keyboard_shortcuts_inhibit; pub mod layer_shell;