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

commit2e17940dd37efae7dd9841a2923af6a6c872a77d
parentb3b470341d
authorIsaac Freund <[email protected]>
date2024-12-30 11:24
river: implement river_window_v1.hide

Also ensure proposed dimensions are sent to the window even if the
window is hidden or if the dimensions are redundant.

 river/Window.zig               | 12 ++++++------
 river/WindowManager.zig        |  4 ++--
 river/XdgToplevel.zig          |  5 +++--
 rivercompat/PointerBinding.zig |  9 ++++-----
 rivercompat/Seat.zig           | 27 +++++++++++++++++++++++++--
 rivercompat/XkbBinding.zig     |  7 ++++---
 6 files changed, 44 insertions(+), 20 deletions(-)

diff --git a/river/Window.zig b/river/Window.zig
index 462ebfb..1af33e3 100644
--- a/river/Window.zig
+++ b/river/Window.zig
@@ -675,6 +675,12 @@ pub fn configure(window: *Window) bool {
         .resizing = false, // XXX
     };
 
+    const track_configure = switch (window.impl) {
+        .toplevel => |*toplevel| toplevel.configure(committed.proposed != null),
+        .xwayland => |*xwindow| xwindow.configure(),
+        .none => unreachable,
+    };
+
     // Ensure a dimensions event is sent if the window manager has proposed dimensions
     // even if the actual dimensions commited by the window do not change.
     if (committed.proposed != null) {
@@ -683,12 +689,6 @@ pub fn configure(window: *Window) bool {
         committed.proposed = null;
     }
 
-    const track_configure = switch (window.impl) {
-        .toplevel => |*toplevel| toplevel.configure(),
-        .xwayland => |*xwindow| xwindow.configure(),
-        .none => unreachable,
-    };
-
     if (track_configure and window.mapped) {
         window.saveSurfaceTree();
         window.sendFrameDone();
diff --git a/river/WindowManager.zig b/river/WindowManager.zig
index 3f8fd10..763ac3b 100644
--- a/river/WindowManager.zig
+++ b/river/WindowManager.zig
@@ -421,8 +421,8 @@ fn commitTransaction(wm: *WindowManager) void {
 
                     window.tree.node.reparent(server.scene.layers.wm);
                     window.tree.node.raiseToTop();
-                    window.tree.node.setEnabled(true);
-                    window.popup_tree.node.setEnabled(true);
+                    window.tree.node.setEnabled(!window.current.hidden);
+                    window.popup_tree.node.setEnabled(!window.current.hidden);
                 },
             }
         }
diff --git a/river/XdgToplevel.zig b/river/XdgToplevel.zig
index 840eed7..5466438 100644
--- a/river/XdgToplevel.zig
+++ b/river/XdgToplevel.zig
@@ -116,7 +116,8 @@ pub fn create(wlr_toplevel: *wlr.XdgToplevel) error{OutOfMemory}!void {
 }
 
 /// Send a configure event, applying the inflight state of the window.
-pub fn configure(toplevel: *XdgToplevel) bool {
+/// If force is true, a configure will always be sent but not necessarily tracked.
+pub fn configure(toplevel: *XdgToplevel, force: bool) bool {
     switch (toplevel.configure_state) {
         .idle, .timed_out, .timed_out_acked => {},
         .inflight, .acked, .committed => unreachable,
@@ -130,7 +131,7 @@ pub fn configure(toplevel: *XdgToplevel) bool {
     const inflight = &toplevel.window.inflight;
     const current = &toplevel.window.current;
 
-    if (!toplevel.needsConfigure()) {
+    if (!force and !toplevel.needsConfigure()) {
         // If no new configure is required, continue to track a timed out configure
         // from the previous transaction if any.
         switch (toplevel.configure_state) {
diff --git a/rivercompat/PointerBinding.zig b/rivercompat/PointerBinding.zig
index 5cdf0fb..2d51a3b 100644
--- a/rivercompat/PointerBinding.zig
+++ b/rivercompat/PointerBinding.zig
@@ -29,17 +29,20 @@ const gpa = std.heap.c_allocator;
 
 seat: *Seat,
 pointer_binding_v1: *river.PointerBindingV1,
+action: Seat.Action,
 
 pub fn create(
     seat: *Seat,
     button: u32,
     modifiers: river.SeatV1.Modifiers,
+    action: Seat.Action,
 ) void {
     const pointer_binding_v1 = seat.seat_v1.getPointerBinding(button, modifiers) catch @panic("OOM");
     const binding = gpa.create(PointerBinding) catch @panic("OOM");
     binding.* = .{
         .seat = seat,
         .pointer_binding_v1 = pointer_binding_v1,
+        .action = action,
     };
     pointer_binding_v1.setListener(*PointerBinding, handleEvent, binding);
     pointer_binding_v1.enable();
@@ -48,11 +51,7 @@ pub fn create(
 fn handleEvent(pointer_binding_v1: *river.PointerBindingV1, event: river.PointerBindingV1.Event, binding: *PointerBinding) void {
     assert(binding.pointer_binding_v1 == pointer_binding_v1);
     switch (event) {
-        .pressed => {
-            if (binding.seat.focused) |window| {
-                window.window_v1.close();
-            }
-        },
+        .pressed => binding.seat.execute(binding.action),
         .released => {},
     }
 }
diff --git a/rivercompat/Seat.zig b/rivercompat/Seat.zig
index bd90e29..938414a 100644
--- a/rivercompat/Seat.zig
+++ b/rivercompat/Seat.zig
@@ -48,8 +48,10 @@ pub fn create(wm: *WindowManager, seat_v1: *river.SeatV1) void {
 
     seat_v1.setListener(*Seat, handleEvent, seat);
 
-    XkbBinding.create(seat, xkb.Keysym.n, .{ .mod4 = true });
-    PointerBinding.create(seat, c.BTN_RIGHT, .{ .mod4 = true });
+    XkbBinding.create(seat, xkb.Keysym.n, .{ .mod4 = true }, .focus_next);
+    XkbBinding.create(seat, xkb.Keysym.h, .{ .mod4 = true }, .hide_focused);
+    XkbBinding.create(seat, xkb.Keysym.s, .{ .mod4 = true }, .show_all);
+    PointerBinding.create(seat, c.BTN_RIGHT, .{ .mod4 = true }, .close_focused);
 }
 
 pub fn focus(seat: *Seat, target: ?*Window) void {
@@ -93,3 +95,24 @@ fn handleEvent(seat_v1: *river.SeatV1, event: river.SeatV1.Event, seat: *Seat) v
         },
     }
 }
+
+pub const Action = enum {
+    focus_next,
+    close_focused,
+    hide_focused,
+    show_all,
+};
+
+pub fn execute(seat: *Seat, action: Action) void {
+    switch (action) {
+        .focus_next => seat.focusNext(),
+        .close_focused => if (seat.focused) |window| window.window_v1.close(),
+        .hide_focused => if (seat.focused) |window| window.window_v1.hide(),
+        .show_all => {
+            var it = seat.wm.windows.iterator(.forward);
+            while (it.next()) |window| {
+                window.window_v1.show();
+            }
+        },
+    }
+}
diff --git a/rivercompat/XkbBinding.zig b/rivercompat/XkbBinding.zig
index 6bdf856..0abbf2b 100644
--- a/rivercompat/XkbBinding.zig
+++ b/rivercompat/XkbBinding.zig
@@ -29,17 +29,20 @@ const gpa = std.heap.c_allocator;
 
 seat: *Seat,
 xkb_binding_v1: *river.XkbBindingV1,
+action: Seat.Action,
 
 pub fn create(
     seat: *Seat,
     keysym: u32,
     modifiers: river.SeatV1.Modifiers,
+    action: Seat.Action,
 ) void {
     const xkb_binding_v1 = seat.seat_v1.getXkbBinding(keysym, modifiers) catch @panic("OOM");
     const binding = gpa.create(XkbBinding) catch @panic("OOM");
     binding.* = .{
         .seat = seat,
         .xkb_binding_v1 = xkb_binding_v1,
+        .action = action,
     };
     xkb_binding_v1.setListener(*XkbBinding, handleEvent, binding);
     xkb_binding_v1.enable();
@@ -48,9 +51,7 @@ pub fn create(
 fn handleEvent(xkb_binding_v1: *river.XkbBindingV1, event: river.XkbBindingV1.Event, binding: *XkbBinding) void {
     assert(binding.xkb_binding_v1 == xkb_binding_v1);
     switch (event) {
-        .pressed => {
-            binding.seat.focusNext();
-        },
+        .pressed => binding.seat.execute(binding.action),
         .released => {},
     }
 }