wayland/decorations: Fix early requests with kde-protocol

This commit is contained in:
Victoria Brekenfeld 2025-05-27 19:45:53 +02:00 committed by Victoria Brekenfeld
parent 359c3ad899
commit c5708cd607
2 changed files with 80 additions and 9 deletions

View file

@ -33,6 +33,7 @@ use smithay::{
shell::server::xdg_toplevel::State as ToplevelState, shell::server::xdg_toplevel::State as ToplevelState,
}, },
}, },
wayland_protocols_misc::server_decoration::server::org_kde_kwin_server_decoration::Mode as KdeMode,
wayland_server::protocol::wl_surface::WlSurface, wayland_server::protocol::wl_surface::WlSurface,
}, },
utils::{ utils::{
@ -50,7 +51,7 @@ use tracing::trace;
use crate::{ use crate::{
state::{State, SurfaceDmabufFeedback}, state::{State, SurfaceDmabufFeedback},
utils::prelude::*, utils::prelude::*,
wayland::handlers::decoration::PreferredDecorationMode, wayland::handlers::decoration::{KdeDecorationData, PreferredDecorationMode},
}; };
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
@ -216,20 +217,29 @@ impl CosmicSurface {
pub fn is_decorated(&self, pending: bool) -> bool { pub fn is_decorated(&self, pending: bool) -> bool {
match self.0.underlying_surface() { match self.0.underlying_surface() {
WindowSurface::Wayland(toplevel) => { WindowSurface::Wayland(toplevel) => {
if pending { let xdg_state = if pending {
toplevel.with_pending_state(|pending| { toplevel.with_pending_state(|pending| {
pending pending
.decoration_mode .decoration_mode
.map(|mode| mode == DecorationMode::ClientSide) .map(|mode| mode == DecorationMode::ClientSide)
.unwrap_or(true)
}) })
} else { } else {
toplevel toplevel
.current_state() .current_state()
.decoration_mode .decoration_mode
.map(|mode| mode == DecorationMode::ClientSide) .map(|mode| mode == DecorationMode::ClientSide)
.unwrap_or(true) };
}
xdg_state
.or_else(|| {
with_states(toplevel.wl_surface(), |states| {
states
.data_map
.get::<KdeDecorationData>()
.map(|data| data.lock().unwrap().mode != KdeMode::Server)
})
})
.unwrap_or(true)
} }
WindowSurface::X11(surface) => surface.is_decorated(), WindowSurface::X11(surface) => surface.is_decorated(),
} }
@ -247,11 +257,25 @@ impl CosmicSurface {
toplevel.with_pending_state(|pending| { toplevel.with_pending_state(|pending| {
pending.decoration_mode = Some(DecorationMode::ServerSide); pending.decoration_mode = Some(DecorationMode::ServerSide);
}); });
with_states(toplevel.wl_surface(), |data| {
if let Some(kde_data) = data.data_map.get::<KdeDecorationData>() {
for obj in kde_data.lock().unwrap().objs.iter() {
obj.mode(KdeMode::Server);
}
}
})
} else { } else {
let previous_mode = PreferredDecorationMode::mode(&self.0); let previous_mode = PreferredDecorationMode::mode(&self.0);
toplevel.with_pending_state(|pending| { toplevel.with_pending_state(|pending| {
pending.decoration_mode = previous_mode; pending.decoration_mode = previous_mode;
}); });
with_states(toplevel.wl_surface(), |data| {
if let Some(kde_data) = data.data_map.get::<KdeDecorationData>() {
for obj in kde_data.lock().unwrap().objs.iter() {
obj.mode(KdeMode::Server);
}
}
})
} }
} }
WindowSurface::X11(_surface) => {} WindowSurface::X11(_surface) => {}

View file

@ -1,4 +1,4 @@
use std::cell::RefCell; use std::{cell::RefCell, sync::Mutex};
use smithay::{ use smithay::{
delegate_kde_decoration, delegate_xdg_decoration, delegate_kde_decoration, delegate_xdg_decoration,
@ -11,6 +11,7 @@ use smithay::{
wayland_server::protocol::wl_surface::WlSurface, wayland_server::protocol::wl_surface::WlSurface,
}, },
wayland::{ wayland::{
compositor::with_states,
seat::WaylandFocus, seat::WaylandFocus,
shell::{ shell::{
kde::decoration::{KdeDecorationHandler, KdeDecorationState}, kde::decoration::{KdeDecorationHandler, KdeDecorationState},
@ -54,6 +55,22 @@ impl PreferredDecorationMode {
} }
} }
pub type KdeDecorationData = Mutex<KdeDecorationSurfaceState>;
#[derive(Debug)]
pub struct KdeDecorationSurfaceState {
pub mode: KdeMode,
pub objs: Vec<OrgKdeKwinServerDecoration>,
}
impl Default for KdeDecorationSurfaceState {
fn default() -> Self {
KdeDecorationSurfaceState {
mode: KdeMode::Client,
objs: Vec::new(),
}
}
}
pub fn new_decoration(mapped: &CosmicMapped, surface: &WlSurface) -> KdeMode { pub fn new_decoration(mapped: &CosmicMapped, surface: &WlSurface) -> KdeMode {
if mapped.is_stack() { if mapped.is_stack() {
if let Some((window, _)) = mapped if let Some((window, _)) = mapped
@ -143,10 +160,22 @@ impl KdeDecorationHandler for State {
} }
fn new_decoration(&mut self, surface: &WlSurface, decoration: &OrgKdeKwinServerDecoration) { fn new_decoration(&mut self, surface: &WlSurface, decoration: &OrgKdeKwinServerDecoration) {
with_states(surface, |states| {
states
.data_map
.get_or_insert::<KdeDecorationData, _>(Default::default)
.lock()
.unwrap()
.objs
.push(decoration.clone())
});
let shell = self.common.shell.read(); let shell = self.common.shell.read();
if let Some(mapped) = shell.element_for_surface(surface) { if let Some(mapped) = shell.element_for_surface(surface) {
let mode = new_decoration(mapped, surface); let mode = new_decoration(mapped, surface);
decoration.mode(mode); decoration.mode(mode);
} else {
decoration.mode(KdeMode::Client);
} }
} }
@ -157,8 +186,16 @@ impl KdeDecorationHandler for State {
mode: WEnum<KdeMode>, mode: WEnum<KdeMode>,
) { ) {
if let WEnum::Value(mode) = mode { if let WEnum::Value(mode) = mode {
with_states(surface, |states| {
states
.data_map
.get_or_insert::<KdeDecorationData, _>(Default::default)
.lock()
.unwrap()
.mode = mode
});
let shell = self.common.shell.read(); let shell = self.common.shell.read();
// 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) { if let Some(mapped) = shell.element_for_surface(surface) {
request_mode( request_mode(
mapped, mapped,
@ -168,12 +205,22 @@ impl KdeDecorationHandler for State {
_ => XdgMode::ClientSide, _ => XdgMode::ClientSide,
}, },
); );
decoration.mode(mode);
} }
decoration.mode(mode);
} }
} }
fn release(&mut self, _decoration: &OrgKdeKwinServerDecoration, surface: &WlSurface) { fn release(&mut self, decoration: &OrgKdeKwinServerDecoration, surface: &WlSurface) {
with_states(surface, |states| {
states
.data_map
.get_or_insert::<KdeDecorationData, _>(Default::default)
.lock()
.unwrap()
.objs
.retain(|obj| obj != decoration);
});
let shell = self.common.shell.read(); let shell = self.common.shell.read();
if let Some(mapped) = shell.element_for_surface(surface) { if let Some(mapped) = shell.element_for_surface(surface) {
unset_mode(mapped, surface) unset_mode(mapped, surface)