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

commitdcd8c66f50f522e134244dd83f34787347cbd71f
parent6b9d21b65f
authorIsaac Freund <[email protected]>
date2025-07-20 22:16
rwm: add missing protocol errors

 protocol/river-window-management-v1.xml | 21 ++++++++++++---------
 river/Output.zig                        |  5 +----
 river/Seat.zig                          |  1 -
 river/Window.zig                        |  9 +++------
 river/WindowManager.zig                 |  7 +------
 river/XkbBinding.zig                    |  2 +-
 6 files changed, 18 insertions(+), 27 deletions(-)

diff --git a/protocol/river-window-management-v1.xml b/protocol/river-window-management-v1.xml
index 736a995..345f570 100644
--- a/protocol/river-window-management-v1.xml
+++ b/protocol/river-window-management-v1.xml
@@ -315,6 +315,10 @@
     <enum name="error">
       <entry name="node_exists" value="0"
         summary="window already has a node object"/>
+      <entry name="invalid_dimensions" value="1"
+        summary="proposed dimensions out of bounds"/>
+      <entry name="invalid_border" value="2"
+        summary="invalid arg to set_borders"/>
     </enum>
 
     <request name="destroy" type="destructor">
@@ -1571,8 +1575,8 @@
       This object allows the window manager to configure a xkbcommon key binding
       and receive events when the key binding is triggered.
 
-      The new key binding is not enabled until initial configuration is
-      completed and the enable request is made during a manage sequence.
+      The new key binding is not enabled until the enable request is made during
+      a manage sequence.
 
       Normally, all key events are sent to the surface with keyboard focus by
       the compositor. Key events that trigger a key binding are not sent to the
@@ -1605,12 +1609,11 @@
         The layout argument is a 0-indexed xkbcommon layout number for the
         keyboard that generated the key event.
 
-        If this request is not made before the enable request the currently
-        active xkb layout of the keyboard that generated the key event will be
-        used.
+        If this request is never made, the currently active xkb layout of the
+        keyboard that generated the key event will be used.
 
-        It is a protocol error to make this request after the first enable
-        request.
+        This request modifies window management state and may only be made as
+        part of a manage sequence, see the river_window_manager_v1 description.
       </description>
       <arg name="layout" type="uint" summary="0-indexed xkbcommon layout"/>
     </request>
@@ -1681,8 +1684,8 @@
       This object allows the window manager to configure a pointer binding and
       receive events when the binding is triggered.
 
-      The new pointer binding is not enabled until initial configuration is
-      completed and the enable request is made during a manage sequence.
+      The new pointer binding is not enabled until the enable request is made
+      during a manage sequence.
 
       Normally, all pointer button events are sent to the surface with pointer
       focus by the compositor. Pointer button events that trigger a pointer
diff --git a/river/Output.zig b/river/Output.zig
index a05b7ff..2695631 100644
--- a/river/Output.zig
+++ b/river/Output.zig
@@ -316,10 +316,7 @@ fn handleRequest(
 ) void {
     assert(output.object == output_v1);
     switch (request) {
-        .destroy => {
-            // XXX send protocol error
-            output_v1.destroy();
-        },
+        .destroy => output_v1.destroy(),
     }
 }
 
diff --git a/river/Seat.zig b/river/Seat.zig
index 660c0f3..b17bce1 100644
--- a/river/Seat.zig
+++ b/river/Seat.zig
@@ -421,7 +421,6 @@ fn handleRequest(
     assert(seat.object == seat_v1);
     switch (request) {
         .destroy => {
-            // XXX send protocol error
             seat_v1.destroy();
         },
 
diff --git a/river/Window.zig b/river/Window.zig
index fb2eaae..6ce8e6a 100644
--- a/river/Window.zig
+++ b/river/Window.zig
@@ -447,10 +447,7 @@ fn handleRequest(
     const wm_requested = &window.wm_requested;
     const rendering_requested = &window.rendering_requested;
     switch (request) {
-        .destroy => {
-            // XXX send protocol error
-            window_v1.destroy();
-        },
+        .destroy => window_v1.destroy(),
         .close => {
             if (!server.wm.ensureWindowing()) return;
             wm_requested.close = true;
@@ -465,7 +462,7 @@ fn handleRequest(
         .propose_dimensions => |args| {
             if (!server.wm.ensureWindowing()) return;
             if (args.width < 0 or args.height < 0) {
-                // XXX send protocol error
+                window_v1.postError(.invalid_dimensions, "dimensions must be greater than or equal to 0 ");
             }
             wm_requested.dimensions = .{
                 .width = @intCast(args.width),
@@ -491,7 +488,7 @@ fn handleRequest(
         .set_borders => |args| {
             if (!server.wm.ensureRendering()) return;
             if (args.width < 0) {
-                // XXX send protocol error
+                window_v1.postError(.invalid_border, "border width must be greater than or equal to 0 ");
             }
             rendering_requested.border = .{
                 .edges = args.edges,
diff --git a/river/WindowManager.zig b/river/WindowManager.zig
index 4c1e74b..65894e2 100644
--- a/river/WindowManager.zig
+++ b/river/WindowManager.zig
@@ -164,10 +164,7 @@ fn handleRequest(
             wm_v1.sendFinished();
             wm_v1.setHandler(?*anyopaque, handleRequestInert, null, null);
         },
-        .destroy => {
-            // XXX send protocol error
-            wm_v1.destroy();
-        },
+        .destroy => wm_v1.destroy(),
         .manage_finish => {
             if (wm.state != .manage) {
                 wm_v1.postError(.sequence_order,
@@ -296,7 +293,6 @@ fn manageStart(wm: *WindowManager) void {
     wm.state = .manage;
 
     if (wm.object) |wm_v1| {
-        // TODO kill the WM on a very long timeout?
         wm_v1.sendManageStart();
     } else {
         wm.manageFinish();
@@ -388,7 +384,6 @@ fn renderStart(wm: *WindowManager) void {
     wm.rendering_scheduled.dirty = false;
 
     if (wm.object) |wm_v1| {
-        // TODO kill the WM on a very long timeout?
         wm_v1.sendRenderStart();
     } else {
         wm.renderFinish();
diff --git a/river/XkbBinding.zig b/river/XkbBinding.zig
index b76bc18..3568cda 100644
--- a/river/XkbBinding.zig
+++ b/river/XkbBinding.zig
@@ -120,7 +120,7 @@ fn handleRequest(
     switch (request) {
         .destroy => xkb_binding_v1.destroy(),
         .set_layout_override => |args| {
-            // XXX protocol error?
+            if (!server.wm.ensureWindowing()) return;
             binding.wm_requested.layout = args.layout;
         },
         .enable => {