use std::cell::RefCell; use smithay::{ delegate_kde_decoration, delegate_xdg_decoration, desktop::Window, 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, state::State}; pub struct PreferredDecorationMode(RefCell>); impl PreferredDecorationMode { pub fn is_unset(window: &Window) -> bool { window .user_data() .get::() .is_none() } pub fn mode(window: &Window) -> Option { let user_data = window.user_data(); user_data.insert_if_missing(|| PreferredDecorationMode(RefCell::new(None))); user_data .get::() .unwrap() .0 .borrow() .clone() } pub fn update(window: &Window, update: Option) { let user_data = window.user_data(); user_data.insert_if_missing(|| PreferredDecorationMode(RefCell::new(None))); *user_data .get::() .unwrap() .0 .borrow_mut() = update; } } pub fn new_decoration(mapped: &CosmicMapped, surface: &WlSurface) -> KdeMode { if mapped.is_stack() { if let Some((window, _)) = mapped .windows() .find(|(window, _)| window.wl_surface().as_deref() == Some(surface)) { if let Some(toplevel) = window.0.toplevel() { toplevel .with_pending_state(|state| state.decoration_mode = Some(XdgMode::ServerSide)); toplevel.send_configure(); } } KdeMode::Server } else { if let Some((window, _)) = mapped .windows() .find(|(window, _)| window.wl_surface().as_deref() == Some(surface)) { if let Some(toplevel) = window.0.toplevel() { toplevel .with_pending_state(|state| state.decoration_mode = Some(XdgMode::ClientSide)); toplevel.send_configure(); } } KdeMode::Client } } pub fn request_mode(mapped: &CosmicMapped, surface: &WlSurface, mode: XdgMode) { if let Some((window, _)) = mapped .windows() .find(|(window, _)| window.wl_surface().as_deref() == Some(surface)) { if let Some(toplevel) = window.0.toplevel() { PreferredDecorationMode::update(&window.0, Some(mode)); toplevel.with_pending_state(|state| { state.decoration_mode = Some(mode); }); toplevel.send_configure(); } } } pub fn unset_mode(mapped: &CosmicMapped, surface: &WlSurface) { if let Some((window, _)) = mapped .windows() .find(|(window, _)| window.wl_surface().as_deref() == Some(surface)) { if let Some(toplevel) = window.0.toplevel() { PreferredDecorationMode::update(&window.0, None); toplevel.with_pending_state(|state| { state.decoration_mode = None; }); toplevel.send_configure(); } } } impl XdgDecorationHandler for State { fn new_decoration(&mut self, toplevel: ToplevelSurface) { let shell = self.common.shell.read().unwrap(); if let Some(mapped) = shell.element_for_surface(toplevel.wl_surface()) { new_decoration(mapped, toplevel.wl_surface()); } } fn request_mode(&mut self, toplevel: ToplevelSurface, mode: XdgMode) { let shell = self.common.shell.read().unwrap(); if let Some(mapped) = shell.element_for_surface(toplevel.wl_surface()) { 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) { let shell = self.common.shell.read().unwrap(); if let Some(mapped) = shell.element_for_surface(toplevel.wl_surface()) { 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) { let shell = self.common.shell.read().unwrap(); if let Some(mapped) = shell.element_for_surface(surface) { let mode = new_decoration(mapped, surface); decoration.mode(mode); } } fn request_mode( &mut self, surface: &WlSurface, decoration: &OrgKdeKwinServerDecoration, mode: WEnum, ) { if let WEnum::Value(mode) = mode { let shell = self.common.shell.read().unwrap(); // 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) = shell.element_for_surface(surface) { request_mode( mapped, surface, match mode { KdeMode::Server => XdgMode::ServerSide, _ => XdgMode::ClientSide, }, ); decoration.mode(mode); } } } fn release(&mut self, _decoration: &OrgKdeKwinServerDecoration, surface: &WlSurface) { let shell = self.common.shell.read().unwrap(); if let Some(mapped) = shell.element_for_surface(surface) { unset_mode(mapped, surface) } } } delegate_xdg_decoration!(State); delegate_kde_decoration!(State);