diff options
Diffstat (limited to 'crates/wayland')
| -rw-r--r-- | crates/wayland/src/protocols.rs | 1 | ||||
| -rw-r--r-- | crates/wayland/src/protocols/kde_decoration.rs | 74 | ||||
| -rw-r--r-- | crates/wayland/src/state/mod.rs | 6 | ||||
| -rw-r--r-- | crates/wayland/src/udev/platform.rs | 8 | ||||
| -rw-r--r-- | crates/wayland/src/winit/connect.rs | 8 |
5 files changed, 97 insertions, 0 deletions
diff --git a/crates/wayland/src/protocols.rs b/crates/wayland/src/protocols.rs index 664e889..bd8307a 100644 --- a/crates/wayland/src/protocols.rs +++ b/crates/wayland/src/protocols.rs @@ -23,6 +23,7 @@ mod misc; mod seat; mod selection; mod xdg_activation; +mod kde_decoration; mod xdg_decoration; mod xdg_shell; diff --git a/crates/wayland/src/protocols/kde_decoration.rs b/crates/wayland/src/protocols/kde_decoration.rs new file mode 100644 index 0000000..2448a39 --- /dev/null +++ b/crates/wayland/src/protocols/kde_decoration.rs @@ -0,0 +1,74 @@ +//! `org_kde_kwin_server_decoration`: KDE's older decoration protocol, and +//! the only decoration protocol GTK actually speaks. +//! +//! GTK has never implemented `xdg-decoration`. It does implement this one: +//! `org_kde_kwin_server_decoration_manager` is present in libgtk-4 on this +//! machine (confirmed by reading the library's own symbol strings), and it +//! is how a KDE session gets GTK applications to stop drawing their own +//! frame. A compositor that advertises only `xdg-decoration` is invisible +//! to those clients, which is why "set the decoration once and every +//! application follows" stopped at srdwm's own titlebars. +//! +//! Both protocols are advertised, and both answer with the same policy +//! (`theme.default_decorated`, `theme.force_server_side`), so a client is +//! told the same thing whichever one it asks through. +//! +//! The protocol's own warning applies here: a client may ignore the mode +//! the compositor suggests and ask for its own. That is honoured the same +//! way `xdg_decoration.rs` honours it, and for the same reason - a client +//! that draws its own titlebar regardless (Firefox with its system-titlebar +//! setting off) would otherwise get srdwm's row on top of its own. + +use smithay::reexports::wayland_protocols_misc::server_decoration::server::org_kde_kwin_server_decoration::{ + Mode, OrgKdeKwinServerDecoration, +}; +use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface; +use smithay::reexports::wayland_server::WEnum; +use smithay::wayland::shell::kde::decoration::{KdeDecorationHandler, KdeDecorationState}; + +use crate::state::CompState; + +impl KdeDecorationHandler for CompState { + fn kde_decoration_state(&self) -> &KdeDecorationState { + &self.kde_decoration_state + } + + /// Tells a client, the moment it asks, which mode this compositor + /// wants - the same answer `XdgDecorationHandler::new_decoration` + /// gives through the other protocol. + /// + /// The manager's own default mode (set once, at startup) is what a + /// client sees before it creates a decoration object at all; this is + /// what it sees afterward, and it has to agree, or a client that reads + /// both ends up with two different answers. + fn new_decoration(&mut self, surface: &WlSurface, decoration: &OrgKdeKwinServerDecoration) { + let server = self.wm.borrow().theme.default_decorated; + decoration.mode(if server { Mode::Server } else { Mode::Client }); + self.set_decorated_from_mode(surface, server); + } + + /// Honours what the client asked for, unless `force_server_side` says + /// otherwise - identical policy to the xdg-decoration path, and the + /// mode is echoed back either way because the protocol requires the + /// compositor to confirm what it decided. + fn request_mode(&mut self, surface: &WlSurface, decoration: &OrgKdeKwinServerDecoration, mode: WEnum<Mode>) { + let WEnum::Value(requested) = mode else { return }; + let forced = self.wm.borrow().theme.force_server_side; + // `Mode::None` means no decoration at all, which for srdwm's + // purposes is a client saying it wants nothing drawn around it -- + // treated as client-side, the same as `Mode::Client`, rather than + // as a request for a titlebar. + let server = forced || requested == Mode::Server; + let granted = if server { Mode::Server } else { requested }; + decoration.mode(granted); + self.set_decorated_from_mode(surface, server); + } + + /// The client is going away, or has dropped its decoration object. + /// Nothing to undo: `remove_window` already clears everything keyed on + /// this surface, and a surface with no decoration object keeps + /// whatever mode it last negotiated, exactly as before. + fn release(&mut self, _decoration: &OrgKdeKwinServerDecoration, _surface: &WlSurface) {} +} + +smithay::delegate_kde_decoration!(CompState); diff --git a/crates/wayland/src/state/mod.rs b/crates/wayland/src/state/mod.rs index 64990c3..6382ee3 100644 --- a/crates/wayland/src/state/mod.rs +++ b/crates/wayland/src/state/mod.rs @@ -173,6 +173,12 @@ pub(crate) struct CompState { pub(crate) compositor_state: CompositorState, pub(crate) xdg_shell_state: XdgShellState, pub(crate) _xdg_decoration_state: XdgDecorationState, + /// KDE's older decoration protocol - see `protocols/kde_decoration.rs` + /// for why it is advertised alongside `xdg-decoration` rather than + /// instead of it. Read by `KdeDecorationHandler`, so unlike the + /// xdg-decoration state above this one is not an underscore-prefixed + /// keep-alive. + pub(crate) kde_decoration_state: smithay::wayland::shell::kde::decoration::KdeDecorationState, pub(crate) shm_state: ShmState, /// `zwp_linux_dmabuf_v1` - see `protocols.rs`'s `DmabufHandler` impl. /// Without this global, no client can hand the compositor a GPU buffer diff --git a/crates/wayland/src/udev/platform.rs b/crates/wayland/src/udev/platform.rs index d3c091c..45def0a 100644 --- a/crates/wayland/src/udev/platform.rs +++ b/crates/wayland/src/udev/platform.rs @@ -178,6 +178,14 @@ impl UdevPlatform { compositor_state, xdg_shell_state, _xdg_decoration_state: xdg_decoration_state, + // Default mode advertised before a client creates a decoration + // object at all - see `protocols/kde_decoration.rs`. Server, + // so a GTK application that reads only this protocol is told + // srdwm decorates, which is the whole point of advertising it. + kde_decoration_state: smithay::wayland::shell::kde::decoration::KdeDecorationState::new::<CompState>( + &display_handle, + smithay::reexports::wayland_protocols_misc::server_decoration::server::org_kde_kwin_server_decoration_manager::Mode::Server, + ), shm_state, dmabuf_state, xdg_activation_state: XdgActivationState::new::<CompState>(&display_handle), diff --git a/crates/wayland/src/winit/connect.rs b/crates/wayland/src/winit/connect.rs index 1f2f876..e320cb8 100644 --- a/crates/wayland/src/winit/connect.rs +++ b/crates/wayland/src/winit/connect.rs @@ -91,6 +91,14 @@ impl WaylandPlatform { compositor_state, xdg_shell_state, _xdg_decoration_state: xdg_decoration_state, + // Default mode advertised before a client creates a decoration + // object at all - see `protocols/kde_decoration.rs`. Server, + // so a GTK application that reads only this protocol is told + // srdwm decorates, which is the whole point of advertising it. + kde_decoration_state: smithay::wayland::shell::kde::decoration::KdeDecorationState::new::<CompState>( + &dh, + smithay::reexports::wayland_protocols_misc::server_decoration::server::org_kde_kwin_server_decoration_manager::Mode::Server, + ), shm_state, dmabuf_state, xdg_activation_state: XdgActivationState::new::<CompState>(&dh), |