From 5ee627928d0cb017e59d796c71793c35d5b65d33 Mon Sep 17 00:00:00 2001 From: srdusr <99972264+srdusr@users.noreply.github.com> Date: Wed, 10 Sep 2025 11:24:00 +0200 Subject: Wayland backend: desktop icons v2, menu rebuild, layer-shell/scale fixes, XWayland stability, GPU rendering, and multi-cursor Phase 2 The bulk of a multi-session shift's real work landed in crates/wayland. Full root-cause/verification narrative for every item below lives in docs/TODO.md (each has its own dated entry); this is the summary: Desktop shell: - Real desktop icons v2 (state/desktop_icons.rs, desktop_icons.rs): fixed origin-baked-before-the-bar-connects, fixed-icon sort order, and a proper Rename/Delete-to-Trash menu (window_memory.rs backs the rename-persistence side). Rubber-band marquee multi-select. - icon_theme.rs: real freedesktop icon-theme lookup (inherits chain, hicolor fallback) rendering actual theme SVGs via resvg/tiny-skia, replacing the hand-drawn placeholder glyphs. - Context/desktop menus (decoration.rs, desktop_menu.rs, state/menu.rs) rebuilt to match the project's own AGS panel styling: rounded floating panel, tinted-fill row highlight, real separators, a much fuller titlebar window-menu action set. Layer-shell / multi-monitor: - Layer-shell hit-testing and render positioning (input/pointer.rs, udev/render.rs's element placement) now correctly convert LayerMap's logical geometry into physical pixels on a fractionally-scaled output - root cause of a bottom-anchored dock being unclickable and unpainted while a top-anchored bar on the same output worked. udev/outputs.rs's relayout_outputs gained the same physical/logical split for cross-output positioning, now backed by a real unit test (next_logical_x) built from the original measured incident numbers. - state/geometry.rs: a window's border/decoration no longer briefly clips when moved between differently-scaled monitors mid-drag. XWayland / stability: - xwayland.rs, udev/session.rs, udev/platform.rs: fixed a 100%- reproducible cold-start XKEYBOARD crash-loop (XWayland's own stdin inherited a real, already-owned VT; env passthrough and idle-callback spawn timing were both real, independent gaps) that had silently taken down all X11-app support and the global-menu registrar every session. - state/toplevel.rs, state/lifecycle.rs: XWayland dialog detection via WM_TRANSIENT_FOR, not just a native xdg_toplevel parent. Rendering: - udev/render.rs, decoration.rs: real GPU (GBM+EGL+DrmCompositor) window-content and cursor rendering on the udev backend, falling back to the untouched Pixman path automatically on any init failure. - decoration/tests.rs, state/mod.rs: rounded-corner/border fixes for interactive resize lag and cross-monitor moves. Multi-cursor Phase 2 (virtual_pointer.rs, new; state/mod.rs, udev/ platform.rs, winit/nested_platform.rs): pins a zwlr_virtual_pointer_ unstable_v1 object to a specific window, bypassing the shared seat/ focus/pointer_pos path entirely via hand-rolled wl_pointer.enter/motion/ button/frame/leave against every WlPointer the target client has bound (PointerHandle::client_pointers). Lets an agent operate one window while a human uses another, genuinely simultaneously, with zero client cooperation and no second wl_seat (confirmed a dead end: real clients only ever bind the first seat advertised). Full workspace build/test/clippy clean. --- crates/wayland/src/desktop_menu.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'crates/wayland/src/desktop_menu.rs') diff --git a/crates/wayland/src/desktop_menu.rs b/crates/wayland/src/desktop_menu.rs index bd0bf34..3cb90ed 100644 --- a/crates/wayland/src/desktop_menu.rs +++ b/crates/wayland/src/desktop_menu.rs @@ -20,6 +20,9 @@ pub(crate) enum DesktopMenuAction { /// convention as `Delete`. EmptyTrash, NewFolder, + /// "not even new file" - see `CompState::new_desktop_text_file`'s own + /// doc comment. + NewTextFile, /// Spawns a terminal with `~/Desktop` as its working directory -- /// `general.terminal`, or a common-binary fallback list if unset. OpenTerminalHere, @@ -28,6 +31,10 @@ pub(crate) enum DesktopMenuAction { /// paste, properties, ...), deliberately not reimplemented here. OpenInFileManager, Refresh, + /// A purely visual divider row - see `context_menu::MenuAction:: + /// Separator`'s own doc comment (same shape, same reason, separate + /// enum since this menu and the titlebar one don't share one). + Separator, } pub(crate) struct DesktopMenu { @@ -66,8 +73,11 @@ impl DesktopMenu { pub(crate) fn open_for_desktop(pos: (i32, i32)) -> Self { let items = vec![ ("New Folder", DesktopMenuAction::NewFolder), + ("New Text Document", DesktopMenuAction::NewTextFile), + ("\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}", DesktopMenuAction::Separator), ("Open Terminal Here", DesktopMenuAction::OpenTerminalHere), ("Open in File Manager", DesktopMenuAction::OpenInFileManager), + ("\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}\u{2500}", DesktopMenuAction::Separator), ("Refresh", DesktopMenuAction::Refresh), ]; Self { pos, width: MENU_WIDTH, row_height: ROW_HEIGHT, items } @@ -132,8 +142,9 @@ mod tests { #[test] fn desktop_menu_offers_the_full_set() { let menu = DesktopMenu::open_for_desktop((10, 10)); - let labels: Vec<&str> = menu.items.iter().map(|(l, _)| *l).collect(); - assert_eq!(labels, vec!["New Folder", "Open Terminal Here", "Open in File Manager", "Refresh"]); + let real_actions: Vec<&str> = + menu.items.iter().filter(|(_, a)| !matches!(a, DesktopMenuAction::Separator)).map(|(l, _)| *l).collect(); + assert_eq!(real_actions, vec!["New Folder", "New Text Document", "Open Terminal Here", "Open in File Manager", "Refresh"]); } #[test] -- cgit v1.2.3