git.lucas.co / cce-compositor
Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git

commit9a40ec57d5686b90914221d06dda30d6c3f634bf
parent81841a6516
authorIsaac Freund <[email protected]>
date2025-08-05 11:26
Window: send river_window_v1.show_window_menu_requested

 river/Window.zig      |  6 +++++-
 river/XdgToplevel.zig | 15 +++++++++++++++
 2 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/river/Window.zig b/river/Window.zig
index 50c5e52..a2dc489 100644
--- a/river/Window.zig
+++ b/river/Window.zig
@@ -149,6 +149,7 @@ popup_tree: *wlr.SceneTree,
 wm_scheduled: struct {
     dimensions_hint: DimensionsHint = .{},
     decoration_hint: river.WindowV1.DecorationHint = .only_supports_csd,
+    show_window_menu_requested: ?struct { x: i32, y: i32 } = null,
     /// Set back to no_request at the end of each update sequence
     fullscreen_requested: FullscreenRequest = .no_request,
     maximize_requested: enum {
@@ -382,7 +383,6 @@ pub fn manageStart(window: *Window) void {
             const scheduled = &window.wm_scheduled;
             const sent = &window.wm_sent;
 
-            // XXX send all dirty scheduled state
             if (new or !meta.eql(scheduled.dimensions_hint, sent.dimensions_hint)) {
                 window_v1.sendDimensionsHint(
                     scheduled.dimensions_hint.min_width,
@@ -397,6 +397,10 @@ pub fn manageStart(window: *Window) void {
                 sent.decoration_hint = scheduled.decoration_hint;
             }
 
+            if (scheduled.show_window_menu_requested) |offset| {
+                window_v1.sendShowWindowMenuRequested(offset.x, offset.y);
+                scheduled.show_window_menu_requested = null;
+            }
             switch (scheduled.fullscreen_requested) {
                 .no_request => {},
                 .fullscreen => |output_hint| {
diff --git a/river/XdgToplevel.zig b/river/XdgToplevel.zig
index a90d3ab..dbe43d6 100644
--- a/river/XdgToplevel.zig
+++ b/river/XdgToplevel.zig
@@ -65,6 +65,7 @@ map: wl.Listener(void) = .init(handleMap),
 unmap: wl.Listener(void) = .init(handleUnmap),
 commit: wl.Listener(*wlr.Surface) = .init(handleCommit),
 new_popup: wl.Listener(*wlr.XdgPopup) = .init(handleNewPopup),
+request_show_window_menu: wl.Listener(*wlr.XdgToplevel.event.ShowWindowMenu) = .init(handleRequestShowWindowMenu),
 request_fullscreen: wl.Listener(void) = .init(handleRequestFullscreen),
 request_maximize: wl.Listener(void) = .init(handleRequestMaximize),
 request_minimize: wl.Listener(void) = .init(handleRequestMinimize),
@@ -108,6 +109,7 @@ pub fn create(wlr_toplevel: *wlr.XdgToplevel) error{OutOfMemory}!void {
     wlr_toplevel.base.surface.events.map.add(&toplevel.map);
     wlr_toplevel.base.surface.events.commit.add(&toplevel.commit);
     wlr_toplevel.base.events.new_popup.add(&toplevel.new_popup);
+    wlr_toplevel.events.request_show_window_menu.add(&toplevel.request_show_window_menu);
     wlr_toplevel.events.request_fullscreen.add(&toplevel.request_fullscreen);
     wlr_toplevel.events.request_maximize.add(&toplevel.request_maximize);
     wlr_toplevel.events.request_minimize.add(&toplevel.request_minimize);
@@ -234,6 +236,7 @@ fn handleDestroy(listener: *wl.Listener(void)) void {
     toplevel.unmap.link.remove();
     toplevel.commit.link.remove();
     toplevel.new_popup.link.remove();
+    toplevel.request_show_window_menu.link.remove();
     toplevel.request_fullscreen.link.remove();
     toplevel.request_maximize.link.remove();
     toplevel.request_minimize.link.remove();
@@ -372,6 +375,18 @@ fn handleCommit(listener: *wl.Listener(*wlr.Surface), _: *wlr.Surface) void {
     }
 }
 
+fn handleRequestShowWindowMenu(
+    listener: *wl.Listener(*wlr.XdgToplevel.event.ShowWindowMenu),
+    event: *wlr.XdgToplevel.event.ShowWindowMenu,
+) void {
+    const toplevel: *XdgToplevel = @fieldParentPtr("request_show_window_menu", listener);
+    toplevel.window.wm_scheduled.show_window_menu_requested = .{
+        .x = event.x - toplevel.geometry.x,
+        .y = event.y - toplevel.geometry.y,
+    };
+    server.wm.dirtyWindowing();
+}
+
 fn handleRequestFullscreen(listener: *wl.Listener(void)) void {
     const toplevel: *XdgToplevel = @fieldParentPtr("request_fullscreen", listener);
     if (toplevel.wlr_toplevel.requested.fullscreen) {