srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/crates/wayland/src/protocols.rs
diff options
context:
space:
mode:
authorsrdusr <[email protected]>2024-12-24 20:44:00 +0200
committersrdusr <[email protected]>2024-12-24 20:44:00 +0200
commit3d73ed0f057a555ded67ad58dbe02b36cd4d2d1f (patch)
tree71e9bab462b9073444183e2a969ba512cb94559f /crates/wayland/src/protocols.rs
parent331a1a1d3a0d8dfd4c285b755c2e13785c95ee2a (diff)
downloadsrdwm-3d73ed0f057a555ded67ad58dbe02b36cd4d2d1f.tar.gz
srdwm-3d73ed0f057a555ded67ad58dbe02b36cd4d2d1f.zip
Accumulate wayland-crate additions: capture rendering, focus/Space sync, VT resume, plumbing
Bundles the remaining wayland-crate changes built up here, touching both backends (udev and winit) and the shared input/rendering code: - udev/capture.rs: off-screen Pixman render of an arbitrary (not necessarily on-screen) workspace's window content to a PPM file -- what crates/core's capture-request queue drives, for a workspace switcher's thumbnail previews. wlr-screencopy structurally can't do this (it can only see what an output is presenting), which is why this exists as a separate render path rather than reusing it. - input::focus_window now also raises the window in smithay's own Space, not just core's stacking order - Space is what actually renders on top and what pointer hit-testing reads, so any focus path that skipped this (an IPC "focus" dispatch, concretely) left a window genuinely focused while still rendering, and receiving clicks, underneath whatever was already topmost. Both backends' poll loops now re-sync this after any IPC mutation. - udev/session.rs's VT-switch resume fix (drains a stale pending page flip before reasserting CRTCs) already has its own earlier, cleanly isolated commit - not duplicated here. - Assorted decoration/cursor/rounded-corners/output-management/ screencopy/XWayland changes and their cross-backend wiring. Coarser than the repo's usual one-purpose-per-commit convention, deliberately - see the core-crate sweep commit's own message for why.
Diffstat (limited to 'crates/wayland/src/protocols.rs')
-rw-r--r--crates/wayland/src/protocols.rs64
1 files changed, 52 insertions, 12 deletions
diff --git a/crates/wayland/src/protocols.rs b/crates/wayland/src/protocols.rs
index bf14d5b..94075c2 100644
--- a/crates/wayland/src/protocols.rs
+++ b/crates/wayland/src/protocols.rs
@@ -131,6 +131,12 @@ impl CompositorHandler for CompState {
*self.content_epoch.entry(id).or_insert(0) += 1;
crate::state::sync_toplevel_metadata(self, id, surface);
}
+ // Before `ensure_layer_initial_configure`: if this commit just
+ // hid or re-showed a layer surface, `sync_layer_visibility` needs
+ // to unmap/re-map it first, so the lookup that function does via
+ // `layer_for_surface` sees the corrected state rather than acting
+ // on stale membership in `LayerMap`'s own list.
+ self.sync_layer_visibility(surface);
self.ensure_layer_initial_configure(surface);
// Advances a just-created popup from unmapped to mapped (needed for
// `PopupManager::popups_for_surface`, which `popup_render_elements`
@@ -173,9 +179,18 @@ impl XdgShellHandler for CompState {
/// needed here at all, just the same start call from a different
/// trigger.
fn move_request(&mut self, surface: ToplevelSurface, _seat: wl_seat::WlSeat, _serial: Serial) {
- if let Some(&id) = self.surface_to_id.get(surface.wl_surface()) {
- let pos = crate::input::last_pointer_pos(self);
- self.wm.borrow_mut().start_drag(id, pos.x as i32, pos.y as i32);
+ // Temporary: added to trace a live report that dragging a CSD
+ // window (Firefox) by its own tab strip/header bar does nothing --
+ // this is the only way to tell "the client never sent xdg_toplevel
+ // ::move at all" apart from "it sent it and something downstream
+ // of here didn't follow through." Remove once that's settled.
+ match self.surface_to_id.get(surface.wl_surface()) {
+ Some(&id) => {
+ let pos = crate::input::last_pointer_pos(self);
+ log::info!("move_request: window {id:?} at pointer {pos:?}");
+ self.wm.borrow_mut().start_drag(id, pos.x as i32, pos.y as i32);
+ }
+ None => log::warn!("move_request: surface has no tracked window id"),
}
}
@@ -356,9 +371,17 @@ impl XdgShellHandler for CompState {
}
impl XdgDecorationHandler for CompState {
+ /// Offers whichever mode `theme.decorations.default_mode`/`srd set
+ /// decoration_mode` currently prefers - a client with a real opinion
+ /// of its own still overrides this via `request_mode` below regardless
+ /// of what's offered here; this only decides what a client with *no*
+ /// preference ends up with. See `srdwm_core::ThemeConfig::
+ /// default_decorated`'s own doc comment for why this is configurable
+ /// rather than hardcoded to one mode.
fn new_decoration(&mut self, toplevel: ToplevelSurface) {
+ let offer = if self.wm.borrow().theme.default_decorated { DecorationMode::ServerSide } else { DecorationMode::ClientSide };
toplevel.with_pending_state(|state| {
- state.decoration_mode = Some(DecorationMode::ServerSide);
+ state.decoration_mode = Some(offer);
});
}
@@ -386,17 +409,19 @@ impl XdgDecorationHandler for CompState {
}
/// The client dropped its decoration-mode preference. `new_decoration`
- /// already offered `ServerSide` as the default the next configure will
- /// carry, so mirror that same default here rather than leaving
- /// whatever mode was negotiated before this - otherwise a client that
- /// requests `ClientSide`, then later unsets it expecting the default
- /// back, would stay undecorated by us forever.
+ /// already offers the configured default as the mode the next
+ /// configure will carry, so mirror that same default here rather than
+ /// leaving whatever mode was negotiated before this - otherwise a
+ /// client that requests one mode, then later unsets it expecting the
+ /// default back, would stay stuck in that mode forever.
fn unset_mode(&mut self, toplevel: ToplevelSurface) {
+ let default_decorated = self.wm.borrow().theme.default_decorated;
+ let mode = if default_decorated { DecorationMode::ServerSide } else { DecorationMode::ClientSide };
toplevel.with_pending_state(|state| {
- state.decoration_mode = Some(DecorationMode::ServerSide);
+ state.decoration_mode = Some(mode);
});
toplevel.send_configure();
- self.set_decorated_from_mode(toplevel.wl_surface(), true);
+ self.set_decorated_from_mode(toplevel.wl_surface(), default_decorated);
}
}
@@ -667,8 +692,23 @@ impl WlrLayerShellHandler for CompState {
// A lock/launcher surface holding exclusive keyboard focus just
// vanished (crash, or a normal close) - don't leave focus dangling
// on a dead surface.
+ //
+ // `sync_keyboard_focus`, not a bare `set_keyboard_focus(None)`: an
+ // `OnDemand` layer surface (a launcher/quicksettings/datemenu
+ // popup, per `wlr-layer-shell`) claiming focus on click
+ // (`input.rs`'s `on_demand` branch) goes straight through
+ // `set_keyboard_focus` without ever touching `WindowManager::
+ // focused` - core has no concept of a layer surface to focus, so
+ // it still correctly points at whatever real toplevel was focused
+ // before the popup opened. Hardcoding `None` here threw that away
+ // regardless, leaving nothing focused until the user happened to
+ // click a window again - reported live (an AGS peer session's
+ // user) as "focus never returns after using the bar". `sync_
+ // keyboard_focus` reads that still-correct core state and restores
+ // real Wayland focus to it, falling through to `None` only if core
+ // genuinely has nothing focused either.
if self.seat.get_keyboard().and_then(|k| k.current_focus()).as_ref() == Some(surface.wl_surface()) {
- self.set_keyboard_focus(None);
+ crate::input::sync_keyboard_focus(self);
}
}
}