srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/crates/wayland/src/winit
diff options
context:
space:
mode:
Diffstat (limited to 'crates/wayland/src/winit')
-rw-r--r--crates/wayland/src/winit/connect.rs7
-rw-r--r--crates/wayland/src/winit/platform.rs38
-rw-r--r--crates/wayland/src/winit/render.rs44
3 files changed, 86 insertions, 3 deletions
diff --git a/crates/wayland/src/winit/connect.rs b/crates/wayland/src/winit/connect.rs
index d771d1f..0f3a6d3 100644
--- a/crates/wayland/src/winit/connect.rs
+++ b/crates/wayland/src/winit/connect.rs
@@ -112,6 +112,7 @@ impl WaylandPlatform {
session_lock_state: SessionLockManagerState::new::<CompState, _>(&dh, |_| true),
_screencopy_state: screencopy::ScreencopyState::new::<CompState>(&dh),
screencopy_pending: Vec::new(),
+ _appmenu_state: crate::appmenu::AppmenuManagerState::new::<CompState>(&dh),
_foreign_toplevel_state: crate::foreign_toplevel::ForeignToplevelState::new::<CompState>(&dh),
foreign_toplevel_managers: Vec::new(),
foreign_toplevel_handles: HashMap::new(),
@@ -141,15 +142,20 @@ impl WaylandPlatform {
cursor_status: smithay::input::pointer::CursorImageStatus::default_named(),
cursor_buffers: crate::cursor::make_buffers(),
last_titlebar_click: None,
+ gesture_swipe: None,
context_menu: None,
context_menu_buffer: None,
+ snap_flyout: None,
+ snap_flyout_buffer: None,
wm: wm.clone(),
surface_to_id: HashMap::new(),
id_to_window: HashMap::new(),
dead_layer_surfaces: HashSet::new(),
+ hidden_layer_surfaces: HashMap::new(),
decorations: HashMap::new(),
border_top_decorations: HashMap::new(),
border_bottom_decorations: HashMap::new(),
+ decoration_signatures: HashMap::new(),
shadow_buffers: HashMap::new(),
rounded_corners_program,
content_epoch: HashMap::new(),
@@ -167,6 +173,7 @@ impl WaylandPlatform {
xwayland_windows: HashMap::new(),
xwayland_pending: Vec::new(),
ewmh: None,
+ appmenu_registrar: None,
};
let listener = ListeningSocket::bind_auto("wayland", 0..32).map_err(err)?;
diff --git a/crates/wayland/src/winit/platform.rs b/crates/wayland/src/winit/platform.rs
index 23387b7..96adde8 100644
--- a/crates/wayland/src/winit/platform.rs
+++ b/crates/wayland/src/winit/platform.rs
@@ -43,8 +43,26 @@ impl Platform for WaylandPlatform {
if let Some(ipc) = self.ipc.as_mut() {
if ipc.poll(&self.wm) {
self.pending.borrow_mut().push(CoreEvent::WorkspaceChanged);
+ // Same re-sync as `udev/platform.rs`'s matching block - see
+ // its own comment. `handle_request` only ever touches core's
+ // `WindowManager`, never `state.space`, so an IPC focus
+ // change left rendering/hit-testing on the stale topmost
+ // window until something else happened to raise it.
+ let focused = self.wm.borrow().focused_id();
+ if let Some(id) = focused {
+ crate::input::focus_window(&mut self.state, id);
+ }
}
}
+ // Same lock-request draining as `udev/platform.rs`'s matching
+ // block - see its own comment. Exercised here too (not just on
+ // the real udev backend) specifically so a native lock can be
+ // tested against this nested dev session without ever touching
+ // the live tty1 one.
+ if self.wm.borrow_mut().drain_lock_request() {
+ self.state.begin_native_lock();
+ }
+ self.state.poll_native_lock_auth();
let wait = TARGET_FRAME_TIME.saturating_sub(self.last_frame.elapsed());
let _ = self.idle_event_loop.dispatch(Some(wait), &mut self.state);
self.last_frame = Instant::now();
@@ -69,6 +87,7 @@ impl Platform for WaylandPlatform {
// "usable, shrunk rect" `toggle_maximize` targets.
let full = self.backend.window_size();
m.full_geometry = srdwm_core::Rect::new(0, 0, full.w as u32, full.h as u32);
+ m.maximize_geometry = crate::input::maximize_geometry_for(&self.output, m.full_geometry);
m.primary = true;
m
}])
@@ -145,4 +164,23 @@ impl Platform for WaylandPlatform {
fn ungrab_keyboard(&mut self) -> PlatformResult<()> {
Ok(())
}
+
+ fn keyboard_layout(&mut self) -> PlatformResult<String> {
+ let Some(keyboard) = self.state.seat.get_keyboard() else { return Ok(String::new()) };
+ Ok(keyboard.with_xkb_state(&mut self.state, |ctx| {
+ let xkb = ctx.xkb().lock().unwrap();
+ let layout = xkb.active_layout();
+ xkb.layout_name(layout).to_string()
+ }))
+ }
+
+ fn cycle_keyboard_layout(&mut self) -> PlatformResult<String> {
+ let Some(keyboard) = self.state.seat.get_keyboard() else { return Ok(String::new()) };
+ Ok(keyboard.with_xkb_state(&mut self.state, |mut ctx| {
+ ctx.cycle_next_layout();
+ let xkb = ctx.xkb().lock().unwrap();
+ let layout = xkb.active_layout();
+ xkb.layout_name(layout).to_string()
+ }))
+ }
}
diff --git a/crates/wayland/src/winit/render.rs b/crates/wayland/src/winit/render.rs
index 3ab3354..735ff34 100644
--- a/crates/wayland/src/winit/render.rs
+++ b/crates/wayland/src/winit/render.rs
@@ -22,8 +22,22 @@ impl WaylandPlatform {
let age = self.backend.buffer_age().unwrap_or(0);
let (renderer, mut framebuffer) = self.backend.bind().map_err(err)?;
- // Locked: the lock surface over an opaque black clear, and nothing
- // else - no windows, no decorations, no layer surfaces.
+ // Locked: srdwm's own native lock UI, or an external locker's
+ // surface, over an opaque black clear - nothing else, no windows,
+ // no decorations, no layer surfaces, either way.
+ if self.state.lock.locked && self.state.lock.native.is_some() {
+ let name = self.output.name();
+ let bg = self.state.native_lock_background(&name).cloned();
+ let ui = self.state.native_lock_ui().map(|(buf, s)| (buf.clone(), s));
+ let elements = crate::native_lock::native_lock_render_elements(bg.as_ref(), ui.as_ref().map(|(b, s)| (b, *s)), (size.w, size.h), renderer);
+ self.damage_tracker
+ .render_output(renderer, &mut framebuffer, age, &elements, [0.0, 0.0, 0.0, 1.0])
+ .map_err(err)?;
+ drop(framebuffer);
+ self.backend.submit(None).map_err(err)?;
+ screencopy::fail_pending(std::mem::take(&mut self.state.screencopy_pending));
+ return Ok(());
+ }
if self.state.lock.locked {
let lock_surface = self.state.lock_surface_for(&self.output).cloned();
let elements = lock_render_elements(lock_surface.as_ref(), renderer);
@@ -58,6 +72,14 @@ impl WaylandPlatform {
Err(e) => log::warn!("failed to import context menu buffer: {e}"),
}
}
+ // The Snap-Layouts flyout, if open - same topmost placement.
+ if let (Some(flyout), Some(buffer)) = (self.state.snap_flyout.as_ref(), self.state.snap_flyout_buffer.as_ref()) {
+ let pos = (flyout.pos.0 as f64, flyout.pos.1 as f64);
+ match MemoryRenderBufferRenderElement::from_buffer(renderer, pos, buffer, None, None, None, Kind::Unspecified) {
+ Ok(elem) => custom_elements.push(crate::rounded_corners::WinitElement::Base(crate::elements::OverlayElement::Memory(elem))),
+ Err(e) => log::warn!("failed to import snap flyout buffer: {e}"),
+ }
+ }
// Content now renders here too, one window at a time, not through
// `render_output`'s own `spaces` argument - see this function's
// own call to `damage_tracker.render_output` further down for why,
@@ -228,7 +250,7 @@ impl WaylandPlatform {
let pos = (geom.x, geom.y + band);
let rounded = rounded_corners_enabled.then_some(self.state.rounded_corners_program.as_ref()).flatten().and_then(|program| {
let corners = if w.decorated { crate::rounded_corners::RoundedCorners::BOTTOM_ONLY } else { crate::rounded_corners::RoundedCorners::ALL };
- crate::rounded_corners::rounded_content_element(renderer, program, &surface, pos, w.opacity, crate::decoration::CORNER_RADIUS as f32, corners)
+ crate::rounded_corners::rounded_content_element(renderer, program, &surface, pos, w.opacity, w.corner_radius as f32, corners)
});
match rounded {
Some(elem) => custom_elements.push(crate::rounded_corners::WinitElement::Rounded(elem)),
@@ -257,6 +279,22 @@ impl WaylandPlatform {
.map_err(err)?;
let damage_rects: Vec<Rectangle<i32, Physical>> = result.damage.cloned().unwrap_or_default();
let has_damage = !damage_rects.is_empty();
+ // A native lock is waiting on this output's background - same
+ // capture hook as `udev/render.rs`'s matching point, exercised
+ // here too so a native lock can be tested against this nested dev
+ // session without ever touching the live tty1 one. `self.state.
+ // lock.locked` is still `false` at this point (`begin_native_lock`
+ // doesn't flip it until every output has a background - see its
+ // own doc comment), so the frame just rendered into `framebuffer`
+ // is the ordinary desktop scene, not a lock scene.
+ if self.state.native_lock_needs_capture(&self.output.name()) {
+ let name = self.output.name();
+ let blur_radius = self.state.wm.borrow().lock.blur_radius;
+ match crate::native_lock::capture_and_blur(renderer, &framebuffer, size.into(), blur_radius) {
+ Ok(blurred) => self.state.capture_output(&name, blurred),
+ Err(e) => log::warn!("native lock: capture failed for output {name}: {e}"),
+ }
+ }
drop(framebuffer);
// Both the buffer swap and the frame-callback notification are
// conditional on real damage now - this used to run