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

commita9f40ab92780dd581b690a9e70b10a17d60b7d28
parent8b3e58945e
authorLucas Galante <[email protected]>
date2026-06-19 02:49
Replace river-window-management-v1 with cce-window-management-v1

 build.rs                                |    2 -
 protocol/cce-window-management-v1.xml   | 1496 +++++++++++++++++++++++-
 protocol/river-layer-shell-v1.xml       |    4 +-
 protocol/river-window-management-v1.xml | 1897 -------------------------------
 protocol/river-xkb-bindings-v1.xml      |    6 +-
 src/server/cce_window_management.rs     |   77 +-
 src/server/output.rs                    |   32 +-
 src/server/output_manager.rs            |    2 +-
 src/server/pointer_binding.rs           |    6 +-
 src/server/seat.rs                      |   10 +-
 src/server/shell_surface.rs             |   16 +-
 src/server/window.rs                    |  102 +-
 src/server/window_manager.rs            |   42 +-
 src/server/wm_node.rs                   |    8 +-
 src/server/xdg_toplevel.rs              |    8 +-
 src/server/xwayland_window.rs           |    4 +-
 wrapper.h                               |    1 -
 17 files changed, 1611 insertions(+), 2102 deletions(-)

diff --git a/build.rs b/build.rs
index 5e919a7..319daaf 100644
--- a/build.rs
+++ b/build.rs
@@ -4,7 +4,6 @@ use std::path::PathBuf;
 fn main() {
     println!("cargo:rerun-if-changed=src/server/wlroots_log_wrapper.c");
     println!("cargo:rerun-if-changed=wrapper.h");
-    println!("cargo:rerun-if-changed=protocol/river-window-management-v1.xml");
     println!("cargo:rerun-if-changed=protocol/river-xkb-bindings-v1.xml");
     println!("cargo:rerun-if-changed=protocol/river-layer-shell-v1.xml");
     println!("cargo:rerun-if-changed=protocol/river-input-management-v1.xml");
@@ -80,7 +79,6 @@ fn main() {
 
     // Generate custom river protocol headers and private-code C files
     let custom_protocols = vec![
-        ("river-window-management-v1.xml", "protocol/river-window-management-v1.xml"),
         ("river-xkb-bindings-v1.xml", "protocol/river-xkb-bindings-v1.xml"),
         ("river-layer-shell-v1.xml", "protocol/river-layer-shell-v1.xml"),
         ("river-input-management-v1.xml", "protocol/river-input-management-v1.xml"),
diff --git a/protocol/cce-window-management-v1.xml b/protocol/cce-window-management-v1.xml
index b05c51f..858451b 100644
--- a/protocol/cce-window-management-v1.xml
+++ b/protocol/cce-window-management-v1.xml
@@ -1,19 +1,255 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <protocol name="cce_window_management_v1">
   <copyright>
-    Copyright © 2026 Antigravity
+    SPDX-FileCopyrightText: © 2024 Isaac Freund
+    SPDX-License-Identifier: MIT
+    Permission is hereby granted, free of charge, to any person obtaining a copy
+    of this software and associated documentation files (the "Software"), to
+    deal in the Software without restriction, including without limitation the
+    rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+    sell copies of the Software, and to permit persons to whom the Software is
+    furnished to do so, subject to the following conditions:
+    The above copyright notice and this permission notice shall be included in
+    all copies or substantial portions of the Software.
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+    IN THE SOFTWARE.
   </copyright>
-
-  <interface name="zcce_window_manager_v1" version="1">
-    <description summary="cce window management interface">
-      This global interface allows clients to obtain custom window management
-      controls for their surfaces.
+  <description summary="frame-perfect window management">
+    This protocol allows a single "window manager" client to determine the
+    window management policy of the compositor. State is globally
+    double-buffered allowing for frame perfect state changes involving multiple
+    windows.
+    The key words "must", "must not", "required", "shall", "shall not",
+    "should", "should not", "recommended", "may", and "optional" in this
+    document are to be interpreted as described in IETF RFC 2119.
+  </description>
+  <interface name="zcce_window_manager_v1" version="4">
+    <description summary="window manager global interface">
+      This global interface should only be advertised to the window manager
+      process. Only one window management client may be active at a time. The
+      compositor should use the unavailable event if necessary to enforce this.
+      There are two disjoint categories of state managed by this protocol:
+      Window management state influences the communication between the
+      compositor and individual windows (e.g. xdg_toplevels). Window management
+      state includes window dimensions, fullscreen state, keyboard focus,
+      keyboard bindings, and more.
+      Rendering state only affects the rendered output of the compositor and
+      does not influence communication between the compositor and individual
+      windows. Rendering state includes the position and rendering order of
+      windows, shell surfaces, decoration surfaces, borders, and more.
+      Window management state may only be modified by the window manager as part
+      of a manage sequence. A manage sequence is started with the manage_start
+      event and ended with the manage_finish request. It is a protocol error to
+      modify window management state outside of a manage sequence.
+      A manage sequence is always followed by at least one render sequence. A
+      render sequence is started with the render_start event and ended with the
+      render_finish request.
+      Rendering state may be modified by the window manager during a manage
+      sequence or a render sequence. Regardless of when the rendering state is
+      modified, it is applied with the next render_finish request. It is a
+      protocol error to modify rendering state outside of a manage or render
+      sequence.
+      The server will start a manage sequence by sending new state and the
+      manage_start event as soon as possible whenever there is a change in state
+      that must be communicated with the window manager.
+      If the window manager client needs to ensure a manage sequence is started
+      due to a state change the compositor is not aware of, it may send the
+      manage_dirty request.
+      The server will start a render sequence by sending new state and the
+      render_start event as soon as possible whenever there is a change in
+      window dimensions that must be communicated with the window manager.
+      Multiple render sequences may be made consecutively without a manage
+      sequence in between, for example if a window independently changes its own
+      dimensions.
+      To summarize, the main loop of this protocol is as follows:
+      1. The server sends events indicating all changes since the last
+         manage sequence followed by the manage_start event.
+      2. The client sends requests modifying window management state or
+         rendering state (as defined above) followed by the manage_finish
+         request.
+      3. The server sends new state to windows and waits for responses.
+      4. The server sends new window dimensions to the client followed by the
+         render_start event.
+      5. The client sends requests modifying rendering state (as defined above)
+         followed by the render_finish request.
+      6. If window dimensions change, loop back to step 4.
+         If state that requires a manage sequence changes or if the client makes
+         a manage_dirty request, loop back to step 1.
+      For the purposes of frame perfection, the server may delay rendering new
+      state committed by the windows in step 3 until after step 5 is finished.
+      It is a protocol error for the client to make a manage_finish or
+      render_finish request that violates this ordering.
     </description>
-
+    <enum name="error">
+      <entry name="sequence_order" value="0" summary="request violates manage/render sequence ordering"/>
+      <entry name="role" value="1" summary="given wl_surface already has a role"/>
+      <entry name="unresponsive" value="2" summary="window manager unresponsive"/>
+    </enum>
+    <event name="unavailable">
+      <description summary="window management unavailable">
+        This event indicates that window management is not available to the
+        client, perhaps due to another window management client already running.
+        The circumstances causing this event to be sent are compositor policy.
+        If sent, this event is guaranteed to be the first and only event sent by
+        the server.
+        The server will send no further events on this object. The client should
+        destroy this object and all objects created through this interface.
+      </description>
+    </event>
+    <request name="stop">
+      <description summary="stop sending events">
+        This request indicates that the client no longer wishes to receive
+        events on this object.
+        The Wayland protocol is asynchronous, which means the server may send
+        further events until the stop request is processed. The client must wait
+        for a cce_window_manager_v1.finished event before destroying this
+        object.
+      </description>
+    </request>
+    <event name="finished">
+      <description summary="the server has finished with the window manager">
+        This event indicates that the server will send no further events on this
+        object. The client should destroy the object. See
+        cce_window_manager_v1.destroy for more information.
+      </description>
+    </event>
     <request name="destroy" type="destructor">
-      <description summary="destroy the window manager object"/>
+      <description summary="destroy the cce_window_manager_v1 object">
+        This request should be called after the finished event has been received
+        to complete destruction of the object.
+        If a client wishes to destroy this object it should send a
+        cce_window_manager_v1.stop request and wait for a
+        cce_window_manager_v1.finished event. Once the finished event is
+        received it is safe to destroy this object and any other objects created
+        through this interface.
+      </description>
+    </request>
+    <event name="manage_start">
+      <description summary="start a manage sequence">
+        This event indicates that the server has sent events indicating all
+        state changes since the last manage sequence.
+        In response to this event, the client should make requests modifying
+        window management state as it chooses. Then, the client must make the
+        manage_finish request.
+        See the description of the cce_window_manager_v1 interface for a
+        complete overview of the manage/render sequence loop.
+      </description>
+    </event>
+    <request name="manage_finish">
+      <description summary="finish a manage sequence">
+        This request indicates that the client has made all changes to window
+        management state it wishes to include in the current manage sequence and
+        that the server should atomically send these state changes to the
+        windows and continue with the manage sequence.
+        After sending this request, it is a protocol error for the client to
+        make further changes to window management state until the next
+        manage_start event is received.
+        See the description of the cce_window_manager_v1 interface for a
+        complete overview of the manage/render sequence loop.
+      </description>
+    </request>
+    <request name="manage_dirty">
+      <description summary="ensure a manage sequence is started">
+        This request ensures a manage sequence is started and that a
+        manage_start event is sent by the server. If this request is made during
+        an ongoing manage sequence, a new manage sequence will be started as
+        soon as the current one is completed.
+        The client may want to use this request due to an internal state change
+        that the compositor is not aware of (e.g. a dbus event) which should
+        affect window management or rendering state.
+      </description>
+    </request>
+    <event name="render_start">
+      <description summary="start a render sequence">
+        This event indicates that the server has sent all
+        cce_window_v1.dimensions events necessary.
+        In response to this event, the client should make requests modifying
+        rendering state as it chooses. Then, the client must make the
+        render_finish request.
+        See the description of the cce_window_manager_v1 interface for a
+        complete overview of the manage/render sequence loop.
+      </description>
+    </event>
+    <request name="render_finish">
+      <description summary="finish a render sequence">
+        This request indicates that the client has made all changes to rendering
+        state it wishes to include in the current manage sequence and that the
+        server should atomically apply and display these state changes to the
+        user.
+        After sending this request, it is a protocol error for the client to
+        make further changes to rendering state until the next manage_start or
+        render_start event is received, whichever comes first.
+        See the description of the cce_window_manager_v1 interface for a
+        complete overview of the manage/render sequence loop.
+      </description>
+    </request>
+    <event name="session_locked">
+      <description summary="the session has been locked">
+        This event indicates that the session has been locked.
+        The window manager may wish to restrict which key bindings are available
+        while locked or otherwise use this information.
+        This event will be followed by a manage_start event after all other new
+        state has been sent by the server.
+      </description>
+    </event>
+    <event name="session_unlocked">
+      <description summary="the session has been unlocked">
+        This event indicates that the session has been unlocked.
+        This event will be followed by a manage_start event after all other new
+        state has been sent by the server.
+      </description>
+    </event>
+    <event name="window">
+      <description summary="new window">
+        A new window has been created.
+        This event will be followed by a manage_start event after all other new
+        state has been sent by the server.
+      </description>
+      <arg name="id" type="new_id" interface="zcce_window_v1" summary="new window"/>
+    </event>
+    <event name="output">
+      <description summary="new output">
+        A new logical output has been created, perhaps due to a new physical
+        monitor being plugged in or perhaps due to a change in configuration.
+        This event will be followed by cce_output_v1.position and dimensions
+        events as well as a manage_start event after all other new state has
+        been sent by the server.
+      </description>
+      <arg name="id" type="new_id" interface="zcce_output_v1" summary="new output"/>
+    </event>
+    <event name="seat">
+      <description summary="new seat">
+        A new seat has been created.
+        This event will be followed by a manage_start event after all other new
+        state has been sent by the server.
+      </description>
+      <arg name="id" type="new_id" interface="zcce_seat_v1" summary="new seat"/>
+    </event>
+    <request name="get_shell_surface">
+      <description summary="assign the cce_shell_surface_v1 surface role">
+        Create a new shell surface for window manager UI and assign the
+        cce_shell_surface_v1 role to the surface.
+        Providing a wl_surface which already has a role or already has a buffer
+        attached or committed is a protocol error.
+      </description>
+      <arg name="id" type="new_id" interface="zcce_shell_surface_v1" summary="new river shell surface"/>
+      <arg name="surface" type="object" interface="wl_surface" summary="base surface"/>
+    </request>
+    <request name="exit_session" since="4">
+      <description summary="exit the Wayland session">
+        End the current Wayland session and exit the compositor.
+        All Wayland clients running in the current session, including
+        the window manager, will be disconnected.
+        Window managers should only make this request if the user explicitly
+        asks to exit the Wayland session, not for example on normal window
+        manager termination.
+      </description>
     </request>
-
     <request name="get_cce_toplevel">
       <description summary="get a cce toplevel for a surface">
         Create a zcce_toplevel_v1 object for a given wl_surface.
@@ -22,49 +258,1271 @@
       <arg name="surface" type="object" interface="wl_surface"/>
     </request>
   </interface>
-
+  <interface name="zcce_window_v1" version="4">
+    <description summary="a logical window">
+      This represents a logical window. For example, a window may correspond to
+      an xdg_toplevel or Xwayland window.
+      A newly created window will not be displayed until the window manager
+      makes a propose_dimensions or fullscreen request as part of a manage
+      sequence, the server replies with a dimensions event as part of a render
+      sequence, and that render sequence is finished.
+    </description>
+    <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"/>
+      <entry name="invalid_clip_box" value="3" summary="invalid arg to set_clip_box"/>
+    </enum>
+    <request name="destroy" type="destructor">
+      <description summary="destroy the window object">
+        This request indicates that the client will no longer use the window
+        object and that it may be safely destroyed.
+        This request should be made after the cce_window_v1.closed event or
+        cce_window_manager_v1.finished is received to complete destruction of
+        the window.
+      </description>
+    </request>
+    <event name="closed">
+      <description summary="the window has been closed">
+        The window has been closed by the server, perhaps due to an
+        xdg_toplevel.close request or similar.
+        The server will send no further events on this object and ignore any
+        request other than cce_window_v1.destroy made after this event is
+        sent. The client should destroy this object with the
+        cce_window_v1.destroy request to free up resources.
+        This event will be followed by a manage_start event after all other new
+        state has been sent by the server.
+      </description>
+    </event>
+    <request name="close">
+      <description summary="request that the window be closed">
+        Request that the window be closed. The window may ignore this request or
+        only close after some delay, perhaps opening a dialog asking the user to
+        save their work or similar.
+        The server will send a cce_window_v1.closed event if/when the window
+        has been closed.
+        This request modifies window management state and may only be made as
+        part of a manage sequence, see the cce_window_manager_v1 description.
+      </description>
+    </request>
+    <request name="get_node">
+      <description summary="get the window's render list node">
+        Get the node in the render list corresponding to the window.
+        It is a protocol error to make this request more than once for a single
+        window.
+      </description>
+      <arg name="id" type="new_id" interface="zcce_node_v1" summary="new node"/>
+    </request>
+    <event name="dimensions_hint">
+      <description summary="the window's preferred min/max dimensions">
+        This event informs the window manager of the window's preferred min/max
+        dimensions. These preferences are a hint, and the window manager is free
+        to propose dimensions outside of these bounds.
+        All min/max width/height values must be strictly greater than or equal
+        to 0. A value of 0 indicates that the window has no preference for that
+        value.
+        The min_width/min_height must be strictly less than or equal to the
+        max_width/max_height.
+        This event will be followed by a manage_start event after all other new
+        state has been sent by the server.
+      </description>
+      <arg name="min_width" type="int" summary="minimum width"/>
+      <arg name="min_height" type="int" summary="minimum height"/>
+      <arg name="max_width" type="int" summary="maximum width"/>
+      <arg name="max_height" type="int" summary="maximum height"/>
+    </event>
+    <event name="dimensions">
+      <description summary="window dimensions">
+        This event indicates the dimensions of the window in the compositor's
+        logical coordinate space. The width and height must be strictly greater
+        than zero.
+        Note that the dimensions of a cce_window_v1 refer to the dimensions of
+        the window content and are unaffected by the presence of borders or
+        decoration surfaces.
+        This event is sent as part of a render sequence before the render_start
+        event.
+        It may be sent due to a propose_dimensions or fullscreen request in a
+        previous manage sequence or because a window independently decides to
+        change its dimensions.
+        The window will not be displayed until the first dimensions event is
+        received and the render sequence is finished.
+      </description>
+      <arg name="width" type="int" summary="window content width"/>
+      <arg name="height" type="int" summary="window content height"/>
+    </event>
+    <request name="propose_dimensions">
+      <description summary="propose window dimensions">
+        This request proposes dimensions for the window in the compositor's
+        logical coordinate space.
+        The width and height must be greater than or equal to zero. If the width
+        or height is zero the window will be allowed to decide its own
+        dimensions.
+        The window may not take the exact dimensions proposed. The actual
+        dimensions taken by the window will be sent in a subsequent
+        cce_window_v1.dimensions event. For example, a terminal emulator may
+        only allow dimensions that are multiple of the cell size.
+        When a propose_dimensions request is made, the server must send a
+        dimensions event in response as soon as possible. It may not be possible
+        to send a dimensions event in the very next render sequence if, for
+        example, the window takes too long to respond to the proposed
+        dimensions. In this case, the server will send the dimensions event in a
+        future render sequence.
+        Note that the dimensions of a cce_window_v1 refer to the dimensions of
+        the window content and are unaffected by the presence of borders or
+        decoration surfaces.
+        This request modifies window management state and may only be made as
+        part of a manage sequence, see the cce_window_manager_v1 description.
+      </description>
+      <arg name="width" type="int" summary="proposed content width"/>
+      <arg name="height" type="int" summary="proposed content height"/>
+    </request>
+    <request name="hide">
+      <description summary="request that the window be hidden">
+        Request that the window be hidden. Has no effect if the window is
+        already hidden. Hides any window borders and decorations as well.
+        Newly created windows are considered shown unless explicitly hidden with
+        the hide request.
+        This request modifies rendering state and may only be made as part of a
+        render sequence, see the cce_window_manager_v1 description.
+      </description>
+    </request>
+    <request name="show">
+      <description summary="request that the window be shown">
+        Request that the window be shown. Has no effect if the window is not
+        hidden. Does not guarantee that the window is visible as it may be
+        completely obscured by other windows placed above it for example.
+        Newly created windows are considered shown unless explicitly hidden with
+        the hide request.
+        This request modifies rendering state and may only be made as part of a
+        render sequence, see the cce_window_manager_v1 description.
+      </description>
+    </request>
+    <event name="app_id">
+      <description summary="the window set an application ID">
+        The window set an application ID.
+        The app_id argument will be null if the window has never set an
+        application ID or if the window cleared its application ID. (Xwayland
+        windows may do this for example, though xdg-toplevels may not.)
+        This event will be followed by a manage_start event after all other new
+        state has been sent by the server.
+      </description>
+      <arg name="app_id" type="string" allow-null="true" summary="window application ID"/>
+    </event>
+    <event name="title">
+      <description summary="the window set a title">
+        The window set a title.
+        The title argument will be null if the window has never set a title or
+        if the window cleared its title. (Xwayland windows may do this for
+        example, though xdg-toplevels may not.)
+        This event will be followed by a manage_start event after all other new
+        state has been sent by the server.
+      </description>
+      <arg name="title" type="string" allow-null="true" summary="window title"/>
+    </event>
+    <event name="parent">
+      <description summary="the window set a parent">
+        The window set a parent window. If this event is never received or if
+        the parent argument is null then the window has no parent.
+        A surface with a parent set might be a dialog, file picker, or similar
+        for the parent window.
+        Child windows should generally be rendered directly above their parent.
+        The compositor must guarantee that there are no loops in the window
+        tree: a parent must not be the descendant of one of its children.
+        This event will be followed by a manage_start event after all other new
+        state has been sent by the server.
+      </description>
+      <arg name="parent" type="object" allow-null="true" interface="zcce_window_v1" summary="parent window, if any"/>
+    </event>
+    <enum name="decoration_hint">
+      <entry name="only_supports_csd" value="0" summary="only supports client side decoration"/>
+      <entry name="prefers_csd" value="1" summary="client side decoration preferred, both CSD and SSD supported"/>
+      <entry name="prefers_ssd" value="2" summary="server side decoration preferred, both CSD and SSD supported"/>
+      <entry name="no_preference" value="3" summary="no preference, both CSD and SSD supported"/>
+    </enum>
+    <event name="decoration_hint">
+      <description summary="supported/preferred decoration style">
+        Information from the window about the supported and preferred client
+        side/server side decoration options.
+        This event may be sent multiple times over the lifetime of the window if
+        the window changes its preferences.
+        This event will be followed by a manage_start event after all other new
+        state has been sent by the server.
+      </description>
+      <arg name="hint" type="uint" enum="decoration_hint" summary="decoration hint"/>
+    </event>
+    <request name="use_csd">
+      <description summary="tell the client to use CSD">
+        Tell the client to use client side decoration and draw its own title
+        bar, borders, etc.
+        This is the default if neither this request nor the use_ssd request is
+        ever made.
+        This request modifies window management state and may only be made as
+        part of a manage sequence, see the cce_window_manager_v1 description.
+      </description>
+    </request>
+    <request name="use_ssd">
+      <description summary="tell the client to use SSD">
+        Tell the client to use server side decoration and not draw any client
+        side decorations.
+        This request will have no effect if the client only supports client side
+        decoration, see the decoration_hint event.
+        This request modifies window management state and may only be made as
+        part of a manage sequence, see the cce_window_manager_v1 description.
+      </description>
+    </request>
+    <enum name="edges" bitfield="true">
+      <entry name="none" value="0"/>
+      <entry name="top" value="1"/>
+      <entry name="bottom" value="2"/>
+      <entry name="left" value="4"/>
+      <entry name="right" value="8"/>
+    </enum>
+    <request name="set_borders">
+      <description summary="set window borders">
+        This request decorates the window with borders drawn by the compositor
+        on the specified edges of the window. Borders are drawn above the window
+        content.
+        Corners are drawn only between borders on adjacent edges. If e.g. the
+        left edge has a border and the top edge does not, the border drawn on
+        the left edge will not extend vertically beyond the top edge of the
+        window.
+        Borders are not drawn while the window is fullscreen.
+        The color is defined by four 32-bit RGBA values. Unless specified in
+        another protocol extension, the RGBA values use pre-multiplied alpha.
+        The valid range for the RGBA values is from 0x00000000 to 0xffffffff.
+        These values are interpreted as a percentage:
+        - 0x00000000 means 0% of the given color component
+        - 0xffffffff means 100% of the given color component
+        Setting the edges to none or the width to 0 disables the borders.
+        Setting a negative width is a protocol error.
+        This request completely overrides all previous set_borders requests.
+        Only the most recent set_borders request has an effect.
+        Note that the position/dimensions of a cce_window_v1 refer to the
+        position/dimensions of the window content and are unaffected by the
+        presence of borders or decoration surfaces.
+        This request modifies rendering state and may only be made as part of a
+        render sequence, see the cce_window_manager_v1 description.
+      </description>
+      <arg name="edges" type="uint" enum="edges" summary="border edges"/>
+      <arg name="width" type="int" summary="border width"/>
+      <arg name="r" type="uint" summary="32-bit red value"/>
+      <arg name="g" type="uint" summary="32-bit green value"/>
+      <arg name="b" type="uint" summary="32-bit blue value"/>
+      <arg name="a" type="uint" summary="32-bit alpha value"/>
+    </request>
+    <request name="set_tiled">
+      <description summary="set window tiled state">
+        Inform the window that it is part of a tiled layout and adjacent to
+        other elements in the tiled layout on the given edges.
+        The window should use this information to change the style of its client
+        side decorations and avoid drawing e.g. drop shadows outside of the
+        window dimensions on the tiled edges.
+        Setting the edges argument to none informs the window that it is not
+        part of a tiled layout. If this request is never made, the window is
+        informed that it is not part of a tiled layout.
+        This request modifies window management state and may only be made as
+        part of a manage sequence, see the cce_window_manager_v1 description.
+      </description>
+      <arg name="edges" type="uint" enum="edges" summary="tiled edges"/>
+    </request>
+    <request name="get_decoration_above">
+      <description summary="create a decoration above the window in z-order">
+        Create a decoration surface and assign the cce_decoration_v1 role to
+        the surface. The created decoration is placed above the window in
+        rendering order, see the description of cce_decoration_v1.
+        Providing a wl_surface which already has a role or already has a buffer
+        attached or committed is a protocol error.
+      </description>
+      <arg name="id" type="new_id" interface="zcce_decoration_v1" summary="new decoration surface"/>
+      <arg name="surface" type="object" interface="wl_surface" summary="base surface"/>
+    </request>
+    <request name="get_decoration_below">
+      <description summary="create a decoration below the window in z-order">
+        Create a decoration surface and assign the cce_decoration_v1 role to
+        the surface. The created decoration is placed below the window in
+        rendering order, see the description of cce_decoration_v1.
+        Providing a wl_surface which already has a role or already has a buffer
+        attached or committed is a protocol error.
+      </description>
+      <arg name="id" type="new_id" interface="zcce_decoration_v1" summary="new decoration surface"/>
+      <arg name="surface" type="object" interface="wl_surface" summary="base surface"/>
+    </request>
+    <event name="pointer_move_requested">
+      <description summary="window requested interactive pointer move">
+        This event informs the window manager that the window has requested to
+        be interactively moved using the pointer. The seat argument indicates the
+        seat for the move.
+        The xdg-shell protocol for example allows windows to request that an
+        interactive move be started, perhaps when a client-side rendered
+        titlebar is dragged.
+        The window manager may use the cce_seat_v1.op_start_pointer request to
+        interactively move the window or ignore this event entirely.
+        This event will be followed by a manage_start event after all other new
+        state has been sent by the server.
+      </description>
+      <arg name="seat" type="object" interface="zcce_seat_v1" summary="requested seat"/>
+    </event>
+    <event name="pointer_resize_requested">
+      <description summary="window requested interactive pointer resize">
+        This event informs the window manager that the window has requested to
+        be interactively resized using the pointer. The seat argument indicates
+        the seat for the resize.
+        The edges argument indicates which edges the window has requested to be
+        resized from. The edges argument will never be none and will never have
+        both top and bottom or both left and right edges set.
+        The xdg-shell protocol for example allows windows to request that an
+        interactive resize be started, perhaps when the corner of client-side
+        rendered decorations is dragged.
+        The window manager may use the cce_seat_v1.op_start_pointer request to
+        interactively resize the window or ignore this event entirely.
+        This event will be followed by a manage_start event after all other new
+        state has been sent by the server.
+      </description>
+      <arg name="seat" type="object" interface="zcce_seat_v1" summary="requested seat"/>
+      <arg name="edges" type="uint" enum="edges" summary="requested edges"/>
+    </event>
+    <request name="inform_resize_start">
+      <description summary="inform the window it is being resized">
+        Inform the window that it is being resized. The window manager should
+        use this request to inform windows that are the target of an interactive
+        resize for example.
+        The window manager remains responsible for handling the position and
+        dimensions of the window while it is resizing.
+        This request modifies window management state and may only be made as
+        part of a manage sequence, see the cce_window_manager_v1 description.
+      </description>
+    </request>
+    <request name="inform_resize_end">
+      <description summary="inform the window it no longer being resized">
+        Inform the window that it is no longer being resized. The window manager
+        should use this request to inform windows that are the target of an
+        interactive resize that the interactive resize has ended for example.
+        This request modifies window management state and may only be made as
+        part of a manage sequence, see the cce_window_manager_v1 description.
+      </description>
+    </request>
+    <enum name="capabilities" bitfield="true">
+      <entry name="window_menu" value="1"/>
+      <entry name="maximize" value="2"/>
+      <entry name="fullscreen" value="4"/>
+      <entry name="minimize" value="8"/>
+    </enum>
+    <request name="set_capabilities">
+      <description summary="inform window of supported capabilities">
+        This request informs the window of the capabilities supported by the
+        window manager. If the window manager, for example, ignores requests to
+        be maximized from the window it should not tell the window that it
+        supports the maximize capability.
+        The window might use this information to, for example, only show a
+        maximize button if the window manager supports the maximize capability.
+        The window manager client should use this request to set capabilities
+        for all new windows. If this request is never made, the compositor will
+        inform windows that all capabilities are supported.
+        This request modifies window management state and may only be made as
+        part of a manage sequence, see the cce_window_manager_v1 description.
+      </description>
+      <arg name="caps" type="uint" enum="capabilities" summary="supported capabilities"/>
+    </request>
+    <event name="show_window_menu_requested">
+      <description summary="window requested that the window menu be shown">
+        The xdg-shell protocol for example allows windows to request that a
+        window menu be shown, for example when the user right clicks on client
+        side window decorations.
+        A window menu might include options to maximize or minimize the window.
+        The window manager is free to ignore this request and decide what the
+        window menu contains if it does choose to show one.
+        The x and y arguments indicate where the window requested that the
+        window menu be shown.
+        This event will be followed by a manage_start event after all other new
+        state has been sent by the server.
+      </description>
+      <arg name="x" type="int" summary="x offset from top left corner"/>
+      <arg name="y" type="int" summary="y offset from top left corner"/>
+    </event>
+    <event name="maximize_requested">
+      <description summary="the window requested to be maximized">
+        The xdg-shell protocol for example allows windows to request to be
+        maximized.
+        The window manager is free to honor this request using
+        cce_window_v1.inform_maximized or ignore it.
+        This event will be followed by a manage_start event after all other new
+        state has been sent by the server.
+      </description>
+    </event>
+    <event name="unmaximize_requested">
+      <description summary="the window requested to be unmaximized">
+        The xdg-shell protocol for example allows windows to request to be
+        unmaximized.
+        The window manager is free to honor this request using
+        cce_window_v1.inform_unmaximized or ignore it.
+        This event will be followed by a manage_start event after all other new
+        state has been sent by the server.
+      </description>
+    </event>
+    <request name="inform_maximized">
+      <description summary="inform the window that it is maximized">
+        Inform the window that it is maximized. The window might use this
+        information to adapt the style of its client-side window decorations for
+        example.
+        The window manager remains responsible for handling the position and
+        dimensions of the window while it is maximized.
+        This request modifies window management state and may only be made as
+        part of a manage sequence, see the cce_window_manager_v1 description.
+      </description>
+    </request>
+    <request name="inform_unmaximized">
+      <description summary="inform the window that it is unmaximized">
+        Inform the window that it is unmaximized. The window might use this
+        information to adapt the style of its client-side window decorations for
+        example.
+        This request modifies window management state and may only be made as
+        part of a manage sequence, see the cce_window_manager_v1 description.
+      </description>
+    </request>
+    <event name="fullscreen_requested">
+      <description summary="the window requested to be fullscreen">
+        The xdg-shell protocol for example allows windows to request that they
+        be made fullscreen and allows them to provide an optional output hint.
+        If the output argument is null, the window has no preference and the
+        window manager should choose an output.
+        The window manager is free to honor this request using
+        cce_window_v1.fullscreen or ignore it.
+        This event will be followed by a manage_start event after all other new
+        state has been sent by the server.
+      </description>
+      <arg name="output" type="object" allow-null="true" interface="zcce_output_v1" summary="fullscreen output requested"/>
+    </event>
+    <event name="exit_fullscreen_requested">
+      <description summary="the window requested to exit fullscreen">
+        The xdg-shell protocol for example allows windows to request to exit
+        fullscreen.
+        The window manager is free to honor this request using
+        cce_window_v1.exit_fullscreen or ignore it.
+        This event will be followed by a manage_start event after all other new
+        state has been sent by the server.
+      </description>
+    </event>
+    <request name="inform_fullscreen">
+      <description summary="inform the window that it is fullscreen">
+        Inform the window that it is fullscreen. The window might use this
+        information to adapt the style of its client-side window decorations for
+        example.
+        This request does not affect the size/position of the window or cause it
+        to become the only window rendered, see the cce_window_v1.fullscreen
+        and exit_fullscreen requests for that.
+        This request modifies window management state and may only be made as
+        part of a manage sequence, see the cce_window_manager_v1 description.
+      </description>
+    </request>
+    <request name="inform_not_fullscreen">
+      <description summary="inform the window that it is not fullscreen">
+        Inform the window that it is not fullscreen. The window might use this
+        information to adapt the style of its client-side window decorations for
+        example.
+        This request does not affect the size/position of the window or cause it
+        to become the only window rendered, see the cce_window_v1.fullscreen
+        and exit_fullscreen requests for that.
+        This request modifies window management state and may only be made as
+        part of a manage sequence, see the cce_window_manager_v1 description.
+      </description>
+    </request>
+    <request name="fullscreen">
+      <description summary="make the window fullscreen">
+        Make the window fullscreen on the given output. If multiple windows are
+        fullscreen on the same output at the same time only the "top" window in
+        rendering order shall be displayed.
+        All cce_shell_surface_v1 objects above the top fullscreen window in
+        the rendering order will continue to be rendered.
+        The compositor will handle the position and dimensions of the window
+        while it is fullscreen. The set_position and propose_dimensions requests
+        shall not affect the current position and dimensions of a fullscreen
+        window.
+        When a fullscreen request is made, the server must send a dimensions
+        event in response as soon as possible. It may not be possible to send a
+        dimensions event in the very next render sequence if, for example, the
+        window takes too long to respond. In this case, the server will send the
+        dimensions event in a future render sequence.
+        The compositor will clip window content, decoration surfaces, and
+        borders to the given output's dimensions while the window is fullscreen.
+        The effects of set_clip_box and set_content_clip_box are ignored while
+        the window is fullscreen.
+        If the output on which a window is currently fullscreen is removed, the
+        windowing state is modified as if there were an exit_fullscreen request
+        made in the same manage sequence as the cce_output_v1.removed event.
+        This request does not inform the window that it is fullscreen, see the
+        cce_window_v1.inform_fullscreen and inform_not_fullscreen requests.
+        This request modifies window management state and may only be made as
+        part of a manage sequence, see the cce_window_manager_v1 description.
+      </description>
+      <arg name="output" type="object" interface="zcce_output_v1" summary="fullscreen output"/>
+    </request>
+    <request name="exit_fullscreen">
+      <description summary="make the window not fullscreen">
+        Make the window not fullscreen.
+        The position and dimensions are undefined after this request is made
+        until a manage sequence in which the window manager makes the
+        propose_dimensions and set_position requests is completed.
+        The window manager should make propose_dimensions and set_position
+        requests in the same manage sequence as the exit_fullscreen request for
+        frame perfection.
+        This request does not inform the window that it is fullscreen, see the
+        cce_window_v1.inform_fullscreen and inform_not_fullscreen requests.
+        This request modifies window management state and may only be made as
+        part of a manage sequence, see the cce_window_manager_v1 description.
+      </description>
+    </request>
+    <event name="minimize_requested">
+      <description summary="the window requested to be minimized">
+        The xdg-shell protocol for example allows windows to request to be
+        minimized.
+        The window manager is free to ignore this request, hide the window, or
+        do whatever else it chooses.
+        This event will be followed by a manage_start event after all other new
+        state has been sent by the server.
+      </description>
+    </event>
+    <request name="set_clip_box" since="2">
+      <description summary="clip the window to a given box">
+        Clip the window, including borders and decoration surfaces, to the box
+        specified by the x, y, width, and height arguments. The x/y position of
+        the box is relative to the top left corner of the window.
+        The width and height arguments must be greater than or equal to 0.
+        Setting a clip box with 0 width or height disables clipping.
+        The clip box is ignored while the window is fullscreen.
+        Both set_clip_box and set_content_clip_box may be enabled simultaneously.
+        This request modifies rendering state and may only be made as part of a
+        render sequence, see the cce_window_manager_v1 description.
+      </description>
+      <arg name="x" type="int" summary="x relative to top left window corner"/>
+      <arg name="y" type="int" summary="y relative to top left window corner"/>
+      <arg name="width" type="int" summary="clip box width"/>
+      <arg name="height" type="int" summary="clip box height"/>
+    </request>
+    <event name="unreliable_pid" since="2">
+      <description summary="unreliable PID of the window's creator">
+        This event gives an unreliable PID of the process that created the
+        window. Obtaining this information is inherently racy due to PID reuse.
+        Therefore, this PID must not be used for anything security sensitive.
+        Note also that a single process may create multiple windows, so there is
+        not necessarily a 1-to-1 mapping from PID to window. Multiple windows
+        may have the same PID.
+        This event is sent once when the cce_window_v1 is created and never
+        sent again.
+      </description>
+      <arg name="unreliable_pid" type="int" summary="unreliable PID"/>
+    </event>
+    <request name="set_content_clip_box" since="3">
+      <description summary="clip the window content to a given box">
+        Clip the content of the window, excluding borders and decoration
+        surfaces, to the box specified by the x, y, width, and height arguments.
+        The x/y position of the box is relative to the top left corner of the
+        window.
+        Borders drawn by the compositor (see set_borders) are placed around the
+        intersection of the window content (as defined by the dimensions event)
+        and the content clip box when content clipping is enabled.
+        The width and height arguments must be greater than or equal to 0.
+        Setting a box with 0 width or height disables content clipping.
+        The content clip box is ignored while the window is fullscreen.
+        Both set_clip_box and set_content_clip_box may be enabled simultaneously.
+        This request modifies rendering state and may only be made as part of a
+        render sequence, see the cce_window_manager_v1 description.
+      </description>
+      <arg name="x" type="int" summary="x relative to top left window corner"/>
+      <arg name="y" type="int" summary="y relative to top left window corner"/>
+      <arg name="width" type="int" summary="clip box width"/>
+      <arg name="height" type="int" summary="clip box height"/>
+    </request>
+    <event name="presentation_hint" since="4">
+      <description summary="presentation hint set by the window">
+        This event communicates the window's preferred presentation mode.
+        This event will be followed by a render_start event after all other new
+        state has been sent by the server.
+      </description>
+      <arg name="hint" type="uint" enum="river_output_v1.presentation_mode" summary="presentation hint"/>
+    </event>
+    <event name="identifier" since="4">
+      <description summary="unique window identifier">
+        The identifier is a string that contains up to 32 printable ASCII bytes.
+        The identifier must not be an empty string.
+        It is compositor policy how the identifier is generated, but the following
+        properties must be upheld:
+        1. The identifier must uniquely identify the window. Two windows must not
+           share the same identifier.
+        2. The identifier must not be reused. This avoids races around window
+           creation/destruction when identifiers are used in out-of-band IPC.
+        If the compositor implements the ext-foreign-toplevel-list-v1 protocol,
+        the cce_window_v1.identifier event must match the corresponding
+        ext_foreign_toplevel_handle_v1.identifier event.
+        This event is sent once when the cce_window_v1 is created and never
+        sent again.
+      </description>
+      <arg name="identifier" type="string" summary="unique identifier"/>
+    </event>
+    <request name="set_dimension_bounds" since="4">
+      <description summary="recommend maximum dimensions to the window">
+        Recommend that the window keep its dimensions within a given
+        maximum width/height. This recommendation is only a hint and the window
+        may ignore it.
+        Setting the width and height to 0 indicates that there are no bounds
+        and is equivalent to having never made this request.
+        Setting width or height to a negative value is a protocol error.
+        The server should communicate this hint to an xdg_toplevel window with
+        the xdg_toplevel.configure_bounds event for example.
+        This request modifies window management state and may only be made as
+        part of a manage sequence, see the cce_window_manager_v1 description.
+      </description>
+      <arg name="max_width" type="int" summary="maximum width"/>
+      <arg name="max_height" type="int" summary="maximum height"/>
+    </request>
+    <request name="set_opacity" since="4">
+      <description summary="set the window opacity">
+        Set the window opacity, from 0 (fully transparent) to 0xffffffff (fully opaque).
+        This request modifies rendering state and may only be made as part of a
+        render sequence, see the cce_window_manager_v1 description.
+      </description>
+      <arg name="opacity" type="uint" summary="opacity value from 0 to 0xffffffff"/>
+    </request>
+    <request name="set_circular" since="4">
+      <description summary="set whether the window is circular">
+        Set whether the window is circular (1 for circular, 0 for rectangular).
+        This request modifies rendering state and may only be made as part of a
+        render sequence, see the cce_window_manager_v1 description.
+      </description>
+      <arg name="circular" type="uint" summary="1 if circular, 0 otherwise"/>
+    </request>
+    <request name="set_blur" since="4">
+      <description summary="set whether backdrop blur is enabled">
+        Set whether backdrop blur should be enabled for this window.
+        1 to enable, 0 to disable.
+        This request modifies rendering state and may only be made as part of a
+        render sequence, see the cce_window_manager_v1 description.
+      </description>
+      <arg name="blur" type="uint" summary="1 to enable, 0 to disable"/>
+    </request>
+  </interface>
+  <interface name="zcce_decoration_v1" version="4">
+    <description summary="a window decoration">
+      The rendering order of windows with decorations is follows:
+      1. Decorations created with get_decoration_below at the bottom
+      2. Window content
+      3. Borders configured with cce_window_v1.set_borders
+      4. Decorations created with get_decoration_above at the top
+      The relative ordering of decoration surfaces above/below a window is
+      undefined by this protocol and left up to the compositor.
+    </description>
+    <enum name="error">
+      <entry name="no_commit" value="0" summary="failed to commit the surface before the window manager commit"/>
+    </enum>
+    <request name="destroy" type="destructor">
+      <description summary="destroy the decoration object">
+        This request indicates that the client will no longer use the decoration
+        object and that it may be safely destroyed.
+      </description>
+    </request>
+    <request name="set_offset">
+      <description summary="set offset from the window's top left corner">
+        This request sets the offset of the decoration surface from the top left
+        corner of the window.
+        If this request is never sent, the x and y offsets are undefined by this
+        protocol and left up to the compositor.
+        This request modifies rendering state and may only be made as part of a
+        render sequence, see the cce_window_manager_v1 description.
+      </description>
+      <arg name="x" type="int" summary="x relative to top left window corner"/>
+      <arg name="y" type="int" summary="y relative to top left window corner"/>
+    </request>
+    <request name="sync_next_commit">
+      <description summary="sync next commit with other rendering state">
+        Synchronize application of the next wl_surface.commit request on the
+        decoration surface with rest of the state atomically applied with the
+        next cce_window_manager_v1.render_finish request.
+        The client must make a wl_surface.commit request on the decoration
+        surface after this request and before the render_finish request, failure
+        to do so is a protocol error.
+        This request modifies rendering state and may only be made as part of a
+        render sequence, see the cce_window_manager_v1 description.
+      </description>
+    </request>
+    <request name="set_blur" since="4">
+      <description summary="set whether backdrop blur is enabled">
+        Set whether backdrop blur should be enabled for this decoration.
+        1 to enable, 0 to disable.
+        This request modifies rendering state and may only be made as part of a
+        render sequence, see the cce_window_manager_v1 description.
+      </description>
+      <arg name="blur" type="uint" summary="1 to enable, 0 to disable"/>
+    </request>
+  </interface>
+  <interface name="zcce_shell_surface_v1" version="4">
+    <description summary="a surface for window manager UI">
+      The window manager might use a shell surface to display a status bar,
+      background image, desktop notifications, launcher, desktop menu, or
+      whatever else it wants.
+    </description>
+    <enum name="error">
+      <entry name="node_exists" value="0" summary="shell surface already has a node object"/>
+      <entry name="no_commit" value="1" summary="failed to commit the surface before the window manager commit"/>
+    </enum>
+    <request name="destroy" type="destructor">
+      <description summary="destroy the shell surface object">
+        This request indicates that the client will no longer use the shell
+        surface object and that it may be safely destroyed.
+      </description>
+    </request>
+    <request name="get_node">
+      <description summary="get the shell surface's render list node">
+        Get the node in the render list corresponding to the shell surface.
+        It is a protocol error to make this request more than once for a single
+        shell surface.
+      </description>
+      <arg name="id" type="new_id" interface="zcce_node_v1" summary="new node"/>
+    </request>
+    <request name="sync_next_commit">
+      <description summary="sync next surface commit to window manager commit">
+        Synchronize application of the next wl_surface.commit request on the
+        shell surface with rest of the rendering state atomically applied with
+        the next cce_window_manager_v1.render_finish request.
+        The client must make a wl_surface.commit request on the shell surface
+        after this request and before the render_finish request, failure to do
+        so is a protocol error.
+        This request modifies rendering state and may only be made as part of a
+        render sequence, see the cce_window_manager_v1 description.
+      </description>
+    </request>
+  </interface>
+  <interface name="zcce_node_v1" version="4">
+    <description summary="a node in the render list">
+      The render list is a list of nodes that determines the rendering order of
+      the compositor. Nodes may correspond to windows or shell surfaces. The
+      relative ordering of nodes may be changed with the place_above and
+      place_below requests, changing the rendering order.
+      The initial position of a node in the render list is undefined, the window
+      manager client must use the place_above or place_below request to
+      guarantee a specific rendering order.
+    </description>
+    <request name="destroy" type="destructor">
+      <description summary="destroy the decoration object">
+        This request indicates that the client will no longer use the node
+        object and that it may be safely destroyed.
+      </description>
+    </request>
+    <request name="set_position">
+      <description summary="set absolute position of the node">
+        Set the absolute position of the node in the compositor's logical
+        coordinate space. The x and y coordinates may be positive or negative.
+        Note that the position of a cce_window_v1 refers to the position of
+        the window content and is unaffected by the presence of borders or
+        decoration surfaces.
+        If this request is never sent, the position of the node is undefined by
+        this protocol and left up to the compositor.
+        This request modifies rendering state and may only be made as part of a
+        render sequence, see the cce_window_manager_v1 description.
+      </description>
+      <arg name="x" type="int" summary="global x coordinate"/>
+      <arg name="y" type="int" summary="global y coordinate"/>
+    </request>
+    <request name="place_top">
+      <description summary="place node above all other nodes">
+        This request places the node above all other nodes in the compositor's
+        render list.
+        This request modifies rendering state and may only be made as part of a
+        render sequence, see the cce_window_manager_v1 description.
+      </description>
+    </request>
+    <request name="place_bottom">
+      <description summary="place node below all other nodes">
+        This request places the node below all other nodes in the compositor's
+        render list.
+        This request modifies rendering state and may only be made as part of a
+        render sequence, see the cce_window_manager_v1 description.
+      </description>
+    </request>
+    <request name="place_above">
+      <description summary="place node above another node">
+        This request places the node directly above another node in the
+        compositor's render list.
+        Attempting to place a node above itself has no effect.
+        This request modifies rendering state and may only be made as part of a
+        render sequence, see the cce_window_manager_v1 description.
+      </description>
+      <arg name="other" type="object" interface="zcce_node_v1" summary="other node"/>
+    </request>
+    <request name="place_below">
+      <description summary="place node below another node">
+        This request places the node directly below another node in the
+        compositor's render list.
+        Attempting to place a node below itself has no effect.
+        This request modifies rendering state and may only be made as part of a
+        render sequence, see the cce_window_manager_v1 description.
+      </description>
+      <arg name="other" type="object" interface="zcce_node_v1" summary="other node"/>
+    </request>
+  </interface>
+  <interface name="zcce_output_v1" version="4">
+    <description summary="a logical output">
+      An area in the compositor's logical coordinate space that should be
+      treated as a single output for window management purposes. This area may
+      correspond to a single physical output or multiple physical outputs in the
+      case of mirroring or tiled monitors depending on the hardware and
+      compositor configuration.
+    </description>
+    <request name="destroy" type="destructor">
+      <description summary="destroy the output object">
+        This request indicates that the client will no longer use the output
+        object and that it may be safely destroyed.
+        This request should be made after the cce_output_v1.removed event is
+        received to complete destruction of the output.
+      </description>
+    </request>
+    <event name="removed">
+      <description summary="the output is removed">
+        This event indicates that the logical output is no longer conceptually
+        part of window management space.
+        The server will send no further events on this object and ignore any
+        request (other than cce_output_v1.destroy) made after this event is
+        sent. The client should destroy this object with the
+        cce_output_v1.destroy request to free up resources.
+        This event may be sent because a corresponding physical output has been
+        physically unplugged or because some output configuration has changed.
+        This event will be followed by a manage_start event after all other new
+        state has been sent by the server.
+      </description>
+    </event>
+    <event name="wl_output">
+      <description summary="corresponding wl_output">
+        The wl_output object corresponding to the cce_output_v1. The argument
+        is the global name of the wl_output advertised with wl_registry.global.
+        It is guaranteed that the corresponding wl_output is advertised before
+        this event is sent.
+        This event is sent exactly once. The wl_output associated with a
+        cce_output_v1 cannot change. It is guaranteed that there is a 1-to-1
+        mapping between wl_output and cce_output_v1 objects.
+        The global_remove event for the corresponding wl_output may be sent
+        before the cce_output_v1.removed event. This is due to the fact that
+        cce_output_v1 state changes are synced to the cce window management
+        manage sequence while changes to globals are not.
+        Rationale: The window manager may need information provided by the
+        wl_output interface such as the name/description. It also may need the
+        wl_output object to start screencopy for example.
+      </description>
+      <arg name="name" type="uint" summary="name of the wl_output global"/>
+    </event>
+    <event name="position">
+      <description summary="output position">
+        This event indicates the position of the output in the compositor's
+        logical coordinate space. The x and y coordinates may be positive or
+        negative.
+        This event is sent once when the cce_output_v1 is created and again
+        whenever the position changes.
+        This event will be followed by a manage_start event after all other new
+        state has been sent by the server.
+        The server must guarantee that the position and dimensions events do not
+        cause the areas of multiple logical outputs to overlap when the
+        corresponding manage_start event is received.
+      </description>
+      <arg name="x" type="int" summary="global x coordinate"/>
+      <arg name="y" type="int" summary="global y coordinate"/>
+    </event>
+    <event name="dimensions">
+      <description summary="output dimensions">
+        This event indicates the dimensions of the output in the compositor's
+        logical coordinate space. The width and height will always be strictly
+        greater than zero.
+        This event is sent once when the cce_output_v1 is created and again
+        whenever the dimensions change.
+        This event will be followed by a manage_start event after all other new
+        state has been sent by the server.
+        The server must guarantee that the position and dimensions events do not
+        cause the areas of multiple logical outputs to overlap when the
+        corresponding manage_start event is received.
+      </description>
+      <arg name="width" type="int" summary="output width"/>
+      <arg name="height" type="int" summary="output height"/>
+    </event>
+    <enum name="error" since="4">
+      <entry name="invalid_presentation_mode" value="0" since="4" summary="invalid presentation mode enum value"/>
+    </enum>
+    <enum name="presentation_mode" since="4">
+      <entry name="vsync" value="0">
+        <description summary="tearing-free presentation">
+          Output page-flips should be synchronized to the vertical blanking
+          period, eliminating tearing. This is the default presentation mode.
+        </description>
+      </entry>
+      <entry name="async" value="1">
+        <description summary="asynchronous presentation">
+          Output page-flips should not be synchronized to the vertical blanking
+          period, visual screen tearing may occur.
+        </description>
+      </entry>
+    </enum>
+    <request name="set_presentation_mode" since="4">
+      <description summary="set the preferred presentation mode">
+        Set the preferred presentation mode of the output. The compositor should
+        always respect the preference of the window manager if possible. If this
+        request is never made, the preferred presentation mode is vsync.
+        This request modifies rendering state and may only be made as part of a
+        render sequence, see the cce_window_manager_v1 description.
+      </description>
+      <arg name="mode" type="uint" enum="presentation_mode" summary="preferred presentation mode"/>
+    </request>
+  </interface>
+  <interface name="zcce_seat_v1" version="4">
+    <description summary="a window management seat">
+      This object represents a single user's collection of input devices. It
+      allows the window manager to route keyboard input to windows, get
+      high-level information about pointer input, define pointer bindings, etc.
+      For keyboard bindings, see the cce-xkb-bindings-v1 protocol.
+      Since version 4: The cursor surface/shape set by the window manager on the
+      wl_pointer of this seat is used when no client has pointer focus, for
+      example during a pointer operation. Since the window manager is allowed to
+      set cursor surface/shape even when it does not have pointer focus, the
+      compositor must ignore the serial argument of wl_pointer.set_cursor and
+      wp_cursor_shape_device_v1.set_shape requests made by the window manager.
+      The most recent cursor surface/shape set by the window manager is
+      remembered by the compositor and restored whenever no client has pointer
+      focus. If the window manager never sets a cursor surface/shape, the
+      "default" shape is used.
+    </description>
+    <request name="destroy" type="destructor">
+      <description summary="destroy the seat object">
+        This request indicates that the client will no longer use the seat
+        object and that it may be safely destroyed.
+        This request should be made after the cce_seat_v1.removed event is
+        received to complete destruction of the seat.
+      </description>
+    </request>
+    <event name="removed">
+      <description summary="the seat is removed">
+        This event indicates that seat is no longer in use and should be
+        destroyed.
+        The server will send no further events on this object and ignore any
+        request (other than cce_seat_v1.destroy) made after this event is
+        sent.  The client should destroy this object with the
+        cce_seat_v1.destroy request to free up resources.
+        This event will be followed by a manage_start event after all other new
+        state has been sent by the server.
+      </description>
+    </event>
+    <event name="wl_seat">
+      <description summary="corresponding wl_seat">
+        The wl_seat object corresponding to the cce_seat_v1. The argument is
+        the global name of the wl_seat advertised with wl_registry.global.
+        It is guaranteed that the corresponding wl_seat is advertised before
+        this event is sent.
+        This event is sent exactly once. The wl_seat associated with a
+        cce_seat_v1 cannot change. It is guaranteed that there is a 1-to-1
+        mapping between wl_seat and cce_seat_v1 objects.
+        The global_remove event for the corresponding wl_seat may be sent before
+        the cce_seat_v1.removed event. This is due to the fact that
+        cce_seat_v1 state changes are synced to the cce window management
+        manage sequence while changes to globals are not.
+        Rationale: The window manager may want to trigger window management
+        state changes based on normal input events received by its shell
+        surfaces for example.
+      </description>
+      <arg name="name" type="uint" summary="name of the wl_seat global"/>
+    </event>
+    <request name="focus_window">
+      <description summary="give keyboard focus to a window">
+        Request that the compositor send keyboard input to the given window.
+        This request modifies window management state and may only be made as
+        part of a manage sequence, see the cce_window_manager_v1 description.
+      </description>
+      <arg name="window" type="object" interface="zcce_window_v1" summary="window to focus"/>
+    </request>
+    <request name="focus_shell_surface">
+      <description summary="give keyboard focus to a shell_surface">
+        Request that the compositor send keyboard input to the given shell
+        surface.
+        This request modifies window management state and may only be made as
+        part of a manage sequence, see the cce_window_manager_v1 description.
+      </description>
+      <arg name="shell_surface" type="object" interface="zcce_shell_surface_v1" summary="shell surface to focus"/>
+    </request>
+    <request name="clear_focus">
+      <description summary="clear keyboard focus">
+        Request that the compositor not send keyboard input to any client.
+        This request modifies window management state and may only be made as
+        part of a manage sequence, see the cce_window_manager_v1 description.
+      </description>
+    </request>
+    <event name="pointer_enter">
+      <description summary="pointer entered a window">
+        The seat's pointer entered the given window's area.
+        The area of a window is defined to include the area defined by the
+        window dimensions, borders configured using cce_window_v1.set_borders,
+        and the input regions of decoration surfaces. In particular, it does not
+        include input regions of surfaces belonging to the window that extend
+        outside the window dimensions.
+        The pointer of a seat may only enter a single window at a time. When the
+        pointer moves between windows, the pointer_leave event for the old
+        window must be sent before the pointer_enter event for the new window.
+        This event will be followed by a manage_start event after all other new
+        state has been sent by the server.
+      </description>
+      <arg name="window" type="object" interface="zcce_window_v1" summary="window entered"/>
+    </event>
+    <event name="pointer_leave">
+      <description summary="pointer left the entered window">
+        The seat's pointer left the window for which pointer_enter was most
+        recently sent. See pointer_enter for details.
+        This event will be followed by a manage_start event after all other new
+        state has been sent by the server.
+      </description>
+    </event>
+    <event name="window_interaction">
+      <description summary="a window has been interacted with">
+        A window has been interacted with beyond the pointer merely passing over
+        it. This event might be sent due to a pointer button press or due to a
+        touch/tablet tool interaction with the window.
+        There are no guarantees regarding how this event is sent in relation to
+        the pointer_enter and pointer_leave events as the interaction may use
+        touch or tablet tool input.
+        Rationale: this event gives window managers necessary information to
+        determine when to send keyboard focus, raise a window that already has
+        keyboard focus, etc. Rather than expose all pointer, touch, and tablet
+        events to window managers, a policy over mechanism approach is taken.
+        This event will be followed by a manage_start event after all other new
+        state has been sent by the server.
+      </description>
+      <arg name="window" type="object" interface="zcce_window_v1" summary="window interacted with"/>
+    </event>
+    <event name="shell_surface_interaction">
+      <description summary="a shell surface has been interacted with">
+        A shell surface has been interacted with beyond the pointer merely
+        passing over it. This event might be sent due to a pointer button press
+        or due to a touch/tablet tool interaction with the shell_surface.
+        There are no guarantees regarding how this event is sent in relation to
+        the pointer_enter and pointer_leave events as the interaction may use
+        touch or tablet tool input.
+        Rationale: While the shell surface does receive all wl_pointer,
+        wl_touch, etc. input events for the surface directly, these events do
+        not necessarily trigger a manage sequence and therefore do not allow the
+        window manager to update focus or perform other actions in response to
+        the input in a race-free way.
+        This event will be followed by a manage_start event after all other new
+        state has been sent by the server.
+      </description>
+      <arg name="shell_surface" type="object" interface="zcce_shell_surface_v1" summary="shell surface interacted with"/>
+    </event>
+    <request name="op_start_pointer">
+      <description summary="start an interactive pointer operation">
+        Start an interactive pointer operation. During the operation, op_delta
+        events will be sent based on pointer input.
+        When all pointer buttons are released, the op_release event is sent.
+        The pointer operation continues until the op_end request is made during
+        a manage sequence and that manage sequence is finished.
+        The window manager may use this operation to implement interactive
+        move/resize of windows by setting the position of windows and proposing
+        dimensions based off of the op_delta events.
+        This request is ignored if an operation is already in progress.
+        The compositor must ensure that no client has pointer focus from this
+        seat during the pointer operation. This means that the window manager
+        has control over the pointer's cursor surface/shape during the pointer
+        operation. See the cce_seat_v1 description.
+        This request modifies window management state and may only be made as
+        part of a manage sequence, see the cce_window_manager_v1 description.
+      </description>
+    </request>
+    <event name="op_delta">
+      <description summary="total cumulative motion since op start">
+        This event indicates the total change in position since the start of the
+        operation of the pointer/touch point/etc.
+        This event will be followed by a manage_start event after all other new
+        state has been sent by the server.
+      </description>
+      <arg name="dx" type="int" summary="total change in x"/>
+      <arg name="dy" type="int" summary="total change in y"/>
+    </event>
+    <event name="op_release">
+      <description summary="operation input has been released">
+        The input driving the current interactive operation has been released.
+        For a pointer op for example, all pointer buttons have been released.
+        Depending on the op type, op_delta events may continue to be sent until
+        the op is ended with the op_end request.
+        This event is sent at most once during an interactive operation.
+        This event will be followed by a manage_start event after all other new
+        state has been sent by the server.
+      </description>
+    </event>
+    <request name="op_end">
+      <description summary="end an interactive operation">
+        End an interactive operation.
+        This request is ignored if there is no operation in progress.
+        This request modifies window management state and may only be made as
+        part of a manage sequence, see the cce_window_manager_v1 description.
+      </description>
+    </request>
+    <enum name="modifiers" bitfield="true">
+      <description summary="a set of keyboard modifiers">
+        This enum is used to describe the keyboard modifiers that must be held
+        down to trigger a key binding or pointer binding.
+        Note that cce and wlroots use the values 2 and 16 for capslock and
+        numlock internally. It doesn't make sense to use locked modifiers for
+        bindings however so these values are not included in this enum.
+      </description>
+      <entry name="none" value="0"/>
+      <entry name="shift" value="1"/>
+      <entry name="ctrl" value="4"/>
+      <entry name="mod1" value="8" summary="commonly called alt"/>
+      <entry name="mod3" value="32"/>
+      <entry name="mod4" value="64" summary="commonly called super or logo"/>
+      <entry name="mod5" value="128"/>
+    </enum>
+    <request name="get_pointer_binding">
+      <description summary="define a new pointer binding">
+        Define a pointer binding in terms of a pointer button, keyboard
+        modifiers, and other configurable properties.
+        The button argument is a Linux input event code defined in the
+        linux/input-event-codes.h header file (e.g. BTN_RIGHT).
+        The new pointer binding is not enabled until initial configuration is
+        completed and the enable request is made during a manage sequence.
+      </description>
+      <arg name="id" type="new_id" interface="zcce_pointer_binding_v1" summary="new pointer binding"/>
+      <arg name="button" type="uint" summary="a Linux input event code"/>
+      <arg name="modifiers" type="uint" enum="modifiers" summary="keyboard modifiers"/>
+    </request>
+    <request name="set_xcursor_theme" since="2">
+      <description summary="set the xcursor theme for the seat">
+        Set the XCursor theme for the seat. This theme is used for cursors
+        rendered by the compositor, but not necessarily for cursors rendered by
+        clients.
+        Note: The window manager may also wish to set the XCURSOR_THEME and
+        XCURSOR_SIZE environment variable for programs it starts.
+      </description>
+      <arg name="name" type="string" summary="xcursor theme name"/>
+      <arg name="size" type="uint" summary="cursor size"/>
+    </request>
+    <event name="pointer_position" since="2">
+      <description summary="The current position of the pointer">
+        The current position of the pointer in the compositor's logical
+        coordinate space.
+        This state is special in that a change in pointer position alone must
+        not cause the compositor to start a manage sequence.
+        Assuming the seat has a pointer, this event must be sent in every manage
+        sequence unless there is no change in x/y position since the last time this
+        event was sent.
+      </description>
+      <arg name="x" type="int" summary="global x coordinate"/>
+      <arg name="y" type="int" summary="global y coordinate"/>
+    </event>
+    <request name="pointer_warp" since="3">
+      <description summary="warp the pointer to a given position">
+        Warp the pointer to the given position in the compositor's logical
+        coordinate space.
+        If the given position is outside the bounds of all outputs, the pointer
+        will be warped to the closest point inside an output instead.
+        This request modifies window management state and may only be made as
+        part of a manage sequence, see the cce_window_manager_v1 description.
+      </description>
+      <arg name="x" type="int" summary="global x coordinate"/>
+      <arg name="y" type="int" summary="global y coordinate"/>
+    </request>
+  </interface>
+  <interface name="zcce_pointer_binding_v1" version="4">
+    <description summary="configure a pointer binding, receive trigger events">
+      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 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
+      binding are not sent to the surface with pointer focus.
+      If multiple pointer bindings would be triggered by a single physical
+      pointer event on the compositor side, it is compositor policy which
+      pointer binding(s) will receive press/release events or if all of the
+      matched pointer bindings receive press/release events.
+    </description>
+    <request name="destroy" type="destructor">
+      <description summary="destroy the pointer binding object">
+        This request indicates that the client will no longer use the pointer
+        binding object and that it may be safely destroyed.
+      </description>
+    </request>
+    <request name="enable">
+      <description summary="enable the pointer binding">
+        This request should be made after all initial configuration has been
+        completed and the window manager wishes the pointer binding to be able
+        to be triggered.
+        This request modifies window management state and may only be made as
+        part of a manage sequence, see the cce_window_manager_v1 description.
+      </description>
+    </request>
+    <request name="disable">
+      <description summary="disable the pointer binding">
+        This request may be used to temporarily disable the pointer binding. It
+        may be later re-enabled with the enable request.
+        This request modifies window management state and may only be made as
+        part of a manage sequence, see the cce_window_manager_v1 description.
+      </description>
+    </request>
+    <event name="pressed">
+      <description summary="the bound pointer button has been pressed">
+        This event indicates that the pointer button triggering the binding has
+        been pressed.
+        This event will be followed by a manage_start event after all other new
+        state has been sent by the server.
+        The compositor should wait for the manage sequence to complete before
+        processing further input events. This allows the window manager client
+        to, for example, modify key bindings and keyboard focus without racing
+        against future input events. The window manager should of course respond
+        as soon as possible as the capacity of the compositor to buffer incoming
+        input events is finite.
+      </description>
+    </event>
+    <event name="released">
+      <description summary="the bound pointer button has been released">
+        This event indicates that the pointer button triggering the binding has
+        been released.
+        Releasing the modifiers for the binding without releasing the pointer
+        button does not trigger the release event. This event is sent when the
+        pointer button is released, even if the modifiers have changed since the
+        pressed event.
+        This event will be followed by a manage_start event after all other new
+        state has been sent by the server.
+        The compositor should wait for the manage sequence to complete before
+        processing further input events. This allows the window manager client
+        to, for example, modify key bindings and keyboard focus without racing
+        against future input events. The window manager should of course respond
+        as soon as possible as the capacity of the compositor to buffer incoming
+        input events is finite.
+      </description>
+    </event>
+  </interface>
   <interface name="zcce_toplevel_v1" version="1">
     <description summary="toplevel window management controls">
       An interface to control and listen to CCE-specific window management states
       for a client surface.
     </description>
-
     <request name="destroy" type="destructor">
       <description summary="destroy the cce toplevel object"/>
     </request>
-
     <request name="set_floating">
       <description summary="request floating mode">
         Explicitly request the compositor to place the window in floating mode.
       </description>
     </request>
-
     <request name="unset_floating">
       <description summary="unset floating mode">
         Request the compositor to return the window to normal tiling mode.
       </description>
     </request>
-
     <request name="set_maximized">
       <description summary="request maximized state"/>
     </request>
-
     <request name="unset_maximized">
       <description summary="unset maximized state"/>
     </request>
-
     <request name="set_fullscreen">
       <description summary="request fullscreen state"/>
     </request>
-
     <request name="unset_fullscreen">
       <description summary="unset fullscreen state"/>
     </request>
-
     <request name="set_minimized">
       <description summary="request minimized state"/>
     </request>
-
     <event name="floating_state">
       <description summary="floating status event">
         Sent by the compositor to inform the client of its current floating status.
diff --git a/protocol/river-layer-shell-v1.xml b/protocol/river-layer-shell-v1.xml
index 0167e9d..b2f2cbb 100644
--- a/protocol/river-layer-shell-v1.xml
+++ b/protocol/river-layer-shell-v1.xml
@@ -61,7 +61,7 @@
         river_output_v1 object.
       </description>
       <arg name="id" type="new_id" interface="river_layer_shell_output_v1"/>
-      <arg name="output" type="object" interface="river_output_v1"/>
+      <arg name="output" type="object" interface="zcce_output_v1"/>
     </request>
 
     <request name="get_seat">
@@ -70,7 +70,7 @@
         river_seat_v1 object.
       </description>
       <arg name="id" type="new_id" interface="river_layer_shell_seat_v1"/>
-      <arg name="seat" type="object" interface="river_seat_v1"/>
+      <arg name="seat" type="object" interface="zcce_seat_v1"/>
     </request>
   </interface>
 
diff --git a/protocol/river-window-management-v1.xml b/protocol/river-window-management-v1.xml
deleted file mode 100644
index cbc1015..0000000
--- a/protocol/river-window-management-v1.xml
+++ /dev/null
@@ -1,1897 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<protocol name="river_window_management_v1">
-  <copyright>
-    SPDX-FileCopyrightText: © 2024 Isaac Freund
-    SPDX-License-Identifier: MIT
-
-    Permission is hereby granted, free of charge, to any person obtaining a copy
-    of this software and associated documentation files (the "Software"), to
-    deal in the Software without restriction, including without limitation the
-    rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-    sell copies of the Software, and to permit persons to whom the Software is
-    furnished to do so, subject to the following conditions:
-
-    The above copyright notice and this permission notice shall be included in
-    all copies or substantial portions of the Software.
-
-    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-    IN THE SOFTWARE.
-  </copyright>
-
-  <description summary="frame-perfect window management">
-    This protocol allows a single "window manager" client to determine the
-    window management policy of the compositor. State is globally
-    double-buffered allowing for frame perfect state changes involving multiple
-    windows.
-
-    The key words "must", "must not", "required", "shall", "shall not",
-    "should", "should not", "recommended", "may", and "optional" in this
-    document are to be interpreted as described in IETF RFC 2119.
-  </description>
-
-  <interface name="river_window_manager_v1" version="4">
-    <description summary="window manager global interface">
-      This global interface should only be advertised to the window manager
-      process. Only one window management client may be active at a time. The
-      compositor should use the unavailable event if necessary to enforce this.
-
-      There are two disjoint categories of state managed by this protocol:
-
-      Window management state influences the communication between the
-      compositor and individual windows (e.g. xdg_toplevels). Window management
-      state includes window dimensions, fullscreen state, keyboard focus,
-      keyboard bindings, and more.
-
-      Rendering state only affects the rendered output of the compositor and
-      does not influence communication between the compositor and individual
-      windows. Rendering state includes the position and rendering order of
-      windows, shell surfaces, decoration surfaces, borders, and more.
-
-      Window management state may only be modified by the window manager as part
-      of a manage sequence. A manage sequence is started with the manage_start
-      event and ended with the manage_finish request. It is a protocol error to
-      modify window management state outside of a manage sequence.
-
-      A manage sequence is always followed by at least one render sequence. A
-      render sequence is started with the render_start event and ended with the
-      render_finish request.
-
-      Rendering state may be modified by the window manager during a manage
-      sequence or a render sequence. Regardless of when the rendering state is
-      modified, it is applied with the next render_finish request. It is a
-      protocol error to modify rendering state outside of a manage or render
-      sequence.
-
-      The server will start a manage sequence by sending new state and the
-      manage_start event as soon as possible whenever there is a change in state
-      that must be communicated with the window manager.
-
-      If the window manager client needs to ensure a manage sequence is started
-      due to a state change the compositor is not aware of, it may send the
-      manage_dirty request.
-
-      The server will start a render sequence by sending new state and the
-      render_start event as soon as possible whenever there is a change in
-      window dimensions that must be communicated with the window manager.
-      Multiple render sequences may be made consecutively without a manage
-      sequence in between, for example if a window independently changes its own
-      dimensions.
-
-      To summarize, the main loop of this protocol is as follows:
-
-      1. The server sends events indicating all changes since the last
-         manage sequence followed by the manage_start event.
-
-      2. The client sends requests modifying window management state or
-         rendering state (as defined above) followed by the manage_finish
-         request.
-
-      3. The server sends new state to windows and waits for responses.
-
-      4. The server sends new window dimensions to the client followed by the
-         render_start event.
-
-      5. The client sends requests modifying rendering state (as defined above)
-         followed by the render_finish request.
-
-      6. If window dimensions change, loop back to step 4.
-         If state that requires a manage sequence changes or if the client makes
-         a manage_dirty request, loop back to step 1.
-
-      For the purposes of frame perfection, the server may delay rendering new
-      state committed by the windows in step 3 until after step 5 is finished.
-
-      It is a protocol error for the client to make a manage_finish or
-      render_finish request that violates this ordering.
-    </description>
-
-    <enum name="error">
-      <entry name="sequence_order" value="0"
-        summary="request violates manage/render sequence ordering"/>
-      <entry name="role" value="1"
-        summary="given wl_surface already has a role"/>
-      <entry name="unresponsive" value="2"
-        summary="window manager unresponsive"/>
-    </enum>
-
-    <event name="unavailable">
-      <description summary="window management unavailable">
-        This event indicates that window management is not available to the
-        client, perhaps due to another window management client already running.
-        The circumstances causing this event to be sent are compositor policy.
-
-        If sent, this event is guaranteed to be the first and only event sent by
-        the server.
-
-        The server will send no further events on this object. The client should
-        destroy this object and all objects created through this interface.
-      </description>
-    </event>
-
-    <request name="stop">
-      <description summary="stop sending events">
-        This request indicates that the client no longer wishes to receive
-        events on this object.
-
-        The Wayland protocol is asynchronous, which means the server may send
-        further events until the stop request is processed. The client must wait
-        for a river_window_manager_v1.finished event before destroying this
-        object.
-      </description>
-    </request>
-
-    <event name="finished">
-      <description summary="the server has finished with the window manager">
-        This event indicates that the server will send no further events on this
-        object. The client should destroy the object. See
-        river_window_manager_v1.destroy for more information.
-      </description>
-    </event>
-
-    <request name="destroy" type="destructor">
-      <description summary="destroy the river_window_manager_v1 object">
-        This request should be called after the finished event has been received
-        to complete destruction of the object.
-
-        If a client wishes to destroy this object it should send a
-        river_window_manager_v1.stop request and wait for a
-        river_window_manager_v1.finished event. Once the finished event is
-        received it is safe to destroy this object and any other objects created
-        through this interface.
-      </description>
-    </request>
-
-    <event name="manage_start">
-      <description summary="start a manage sequence">
-        This event indicates that the server has sent events indicating all
-        state changes since the last manage sequence.
-
-        In response to this event, the client should make requests modifying
-        window management state as it chooses. Then, the client must make the
-        manage_finish request.
-
-        See the description of the river_window_manager_v1 interface for a
-        complete overview of the manage/render sequence loop.
-      </description>
-    </event>
-
-    <request name="manage_finish">
-      <description summary="finish a manage sequence">
-        This request indicates that the client has made all changes to window
-        management state it wishes to include in the current manage sequence and
-        that the server should atomically send these state changes to the
-        windows and continue with the manage sequence.
-
-        After sending this request, it is a protocol error for the client to
-        make further changes to window management state until the next
-        manage_start event is received.
-
-        See the description of the river_window_manager_v1 interface for a
-        complete overview of the manage/render sequence loop.
-      </description>
-    </request>
-
-    <request name="manage_dirty">
-      <description summary="ensure a manage sequence is started">
-        This request ensures a manage sequence is started and that a
-        manage_start event is sent by the server. If this request is made during
-        an ongoing manage sequence, a new manage sequence will be started as
-        soon as the current one is completed.
-
-        The client may want to use this request due to an internal state change
-        that the compositor is not aware of (e.g. a dbus event) which should
-        affect window management or rendering state.
-      </description>
-    </request>
-
-    <event name="render_start">
-      <description summary="start a render sequence">
-        This event indicates that the server has sent all
-        river_window_v1.dimensions events necessary.
-
-        In response to this event, the client should make requests modifying
-        rendering state as it chooses. Then, the client must make the
-        render_finish request.
-
-        See the description of the river_window_manager_v1 interface for a
-        complete overview of the manage/render sequence loop.
-      </description>
-    </event>
-
-    <request name="render_finish">
-      <description summary="finish a render sequence">
-        This request indicates that the client has made all changes to rendering
-        state it wishes to include in the current manage sequence and that the
-        server should atomically apply and display these state changes to the
-        user.
-
-        After sending this request, it is a protocol error for the client to
-        make further changes to rendering state until the next manage_start or
-        render_start event is received, whichever comes first.
-
-        See the description of the river_window_manager_v1 interface for a
-        complete overview of the manage/render sequence loop.
-      </description>
-    </request>
-
-    <event name="session_locked">
-      <description summary="the session has been locked">
-        This event indicates that the session has been locked.
-
-        The window manager may wish to restrict which key bindings are available
-        while locked or otherwise use this information.
-
-        This event will be followed by a manage_start event after all other new
-        state has been sent by the server.
-      </description>
-    </event>
-
-    <event name="session_unlocked">
-      <description summary="the session has been unlocked">
-        This event indicates that the session has been unlocked.
-
-        This event will be followed by a manage_start event after all other new
-        state has been sent by the server.
-      </description>
-    </event>
-
-    <event name="window">
-      <description summary="new window">
-        A new window has been created.
-
-        This event will be followed by a manage_start event after all other new
-        state has been sent by the server.
-      </description>
-      <arg name="id" type="new_id" interface="river_window_v1" summary="new window"/>
-    </event>
-
-    <event name="output">
-      <description summary="new output">
-        A new logical output has been created, perhaps due to a new physical
-        monitor being plugged in or perhaps due to a change in configuration.
-
-        This event will be followed by river_output_v1.position and dimensions
-        events as well as a manage_start event after all other new state has
-        been sent by the server.
-      </description>
-      <arg name="id" type="new_id" interface="river_output_v1" summary="new output"/>
-    </event>
-
-    <event name="seat">
-      <description summary="new seat">
-        A new seat has been created.
-
-        This event will be followed by a manage_start event after all other new
-        state has been sent by the server.
-      </description>
-      <arg name="id" type="new_id" interface="river_seat_v1" summary="new seat"/>
-    </event>
-
-    <request name="get_shell_surface">
-      <description summary="assign the river_shell_surface_v1 surface role">
-        Create a new shell surface for window manager UI and assign the
-        river_shell_surface_v1 role to the surface.
-
-        Providing a wl_surface which already has a role or already has a buffer
-        attached or committed is a protocol error.
-      </description>
-      <arg name="id" type="new_id" interface="river_shell_surface_v1"
-        summary="new river shell surface"/>
-      <arg name="surface" type="object" interface="wl_surface"
-        summary="base surface"/>
-    </request>
-
-    <request name="exit_session" since="4">
-      <description summary="exit the Wayland session">
-        End the current Wayland session and exit the compositor.
-        All Wayland clients running in the current session, including
-        the window manager, will be disconnected.
-
-        Window managers should only make this request if the user explicitly
-        asks to exit the Wayland session, not for example on normal window
-        manager termination.
-      </description>
-    </request>
-  </interface>
-
-  <interface name="river_window_v1" version="4">
-    <description summary="a logical window">
-      This represents a logical window. For example, a window may correspond to
-      an xdg_toplevel or Xwayland window.
-
-      A newly created window will not be displayed until the window manager
-      makes a propose_dimensions or fullscreen request as part of a manage
-      sequence, the server replies with a dimensions event as part of a render
-      sequence, and that render sequence is finished.
-    </description>
-
-    <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"/>
-      <entry name="invalid_clip_box" value="3"
-        summary="invalid arg to set_clip_box"/>
-    </enum>
-
-    <request name="destroy" type="destructor">
-      <description summary="destroy the window object">
-        This request indicates that the client will no longer use the window
-        object and that it may be safely destroyed.
-
-        This request should be made after the river_window_v1.closed event or
-        river_window_manager_v1.finished is received to complete destruction of
-        the window.
-      </description>
-    </request>
-
-    <event name="closed">
-      <description summary="the window has been closed">
-        The window has been closed by the server, perhaps due to an
-        xdg_toplevel.close request or similar.
-
-        The server will send no further events on this object and ignore any
-        request other than river_window_v1.destroy made after this event is
-        sent. The client should destroy this object with the
-        river_window_v1.destroy request to free up resources.
-
-        This event will be followed by a manage_start event after all other new
-        state has been sent by the server.
-      </description>
-    </event>
-
-    <request name="close">
-      <description summary="request that the window be closed">
-        Request that the window be closed. The window may ignore this request or
-        only close after some delay, perhaps opening a dialog asking the user to
-        save their work or similar.
-
-        The server will send a river_window_v1.closed event if/when the window
-        has been closed.
-
-        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>
-    </request>
-
-    <request name="get_node">
-      <description summary="get the window's render list node">
-        Get the node in the render list corresponding to the window.
-
-        It is a protocol error to make this request more than once for a single
-        window.
-      </description>
-      <arg name="id" type="new_id" interface="river_node_v1" summary="new node"/>
-    </request>
-
-    <event name="dimensions_hint">
-      <description summary="the window's preferred min/max dimensions">
-        This event informs the window manager of the window's preferred min/max
-        dimensions. These preferences are a hint, and the window manager is free
-        to propose dimensions outside of these bounds.
-
-        All min/max width/height values must be strictly greater than or equal
-        to 0. A value of 0 indicates that the window has no preference for that
-        value.
-
-        The min_width/min_height must be strictly less than or equal to the
-        max_width/max_height.
-
-        This event will be followed by a manage_start event after all other new
-        state has been sent by the server.
-      </description>
-      <arg name="min_width" type="int" summary="minimum width"/>
-      <arg name="min_height" type="int" summary="minimum height"/>
-      <arg name="max_width" type="int" summary="maximum width"/>
-      <arg name="max_height" type="int" summary="maximum height"/>
-    </event>
-
-    <event name="dimensions">
-      <description summary="window dimensions">
-        This event indicates the dimensions of the window in the compositor's
-        logical coordinate space. The width and height must be strictly greater
-        than zero.
-
-        Note that the dimensions of a river_window_v1 refer to the dimensions of
-        the window content and are unaffected by the presence of borders or
-        decoration surfaces.
-
-        This event is sent as part of a render sequence before the render_start
-        event.
-
-        It may be sent due to a propose_dimensions or fullscreen request in a
-        previous manage sequence or because a window independently decides to
-        change its dimensions.
-
-        The window will not be displayed until the first dimensions event is
-        received and the render sequence is finished.
-      </description>
-      <arg name="width" type="int" summary="window content width"/>
-      <arg name="height" type="int" summary="window content height"/>
-    </event>
-
-    <request name="propose_dimensions">
-      <description summary="propose window dimensions">
-        This request proposes dimensions for the window in the compositor's
-        logical coordinate space.
-
-        The width and height must be greater than or equal to zero. If the width
-        or height is zero the window will be allowed to decide its own
-        dimensions.
-
-        The window may not take the exact dimensions proposed. The actual
-        dimensions taken by the window will be sent in a subsequent
-        river_window_v1.dimensions event. For example, a terminal emulator may
-        only allow dimensions that are multiple of the cell size.
-
-        When a propose_dimensions request is made, the server must send a
-        dimensions event in response as soon as possible. It may not be possible
-        to send a dimensions event in the very next render sequence if, for
-        example, the window takes too long to respond to the proposed
-        dimensions. In this case, the server will send the dimensions event in a
-        future render sequence.
-
-        Note that the dimensions of a river_window_v1 refer to the dimensions of
-        the window content and are unaffected by the presence of borders or
-        decoration surfaces.
-
-        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="width" type="int" summary="proposed content width"/>
-      <arg name="height" type="int" summary="proposed content height"/>
-    </request>
-
-    <request name="hide">
-      <description summary="request that the window be hidden">
-        Request that the window be hidden. Has no effect if the window is
-        already hidden. Hides any window borders and decorations as well.
-
-        Newly created windows are considered shown unless explicitly hidden with
-        the hide request.
-
-        This request modifies rendering state and may only be made as part of a
-        render sequence, see the river_window_manager_v1 description.
-      </description>
-    </request>
-
-    <request name="show">
-      <description summary="request that the window be shown">
-        Request that the window be shown. Has no effect if the window is not
-        hidden. Does not guarantee that the window is visible as it may be
-        completely obscured by other windows placed above it for example.
-
-        Newly created windows are considered shown unless explicitly hidden with
-        the hide request.
-
-        This request modifies rendering state and may only be made as part of a
-        render sequence, see the river_window_manager_v1 description.
-      </description>
-    </request>
-
-    <event name="app_id">
-      <description summary="the window set an application ID">
-        The window set an application ID.
-
-        The app_id argument will be null if the window has never set an
-        application ID or if the window cleared its application ID. (Xwayland
-        windows may do this for example, though xdg-toplevels may not.)
-
-        This event will be followed by a manage_start event after all other new
-        state has been sent by the server.
-      </description>
-      <arg name="app_id" type="string" allow-null="true"
-        summary="window application ID"/>
-    </event>
-
-    <event name="title">
-      <description summary="the window set a title">
-        The window set a title.
-
-        The title argument will be null if the window has never set a title or
-        if the window cleared its title. (Xwayland windows may do this for
-        example, though xdg-toplevels may not.)
-
-        This event will be followed by a manage_start event after all other new
-        state has been sent by the server.
-      </description>
-      <arg name="title" type="string" allow-null="true" summary="window title"/>
-    </event>
-
-    <event name="parent">
-      <description summary="the window set a parent">
-        The window set a parent window. If this event is never received or if
-        the parent argument is null then the window has no parent.
-
-        A surface with a parent set might be a dialog, file picker, or similar
-        for the parent window.
-
-        Child windows should generally be rendered directly above their parent.
-
-        The compositor must guarantee that there are no loops in the window
-        tree: a parent must not be the descendant of one of its children.
-
-        This event will be followed by a manage_start event after all other new
-        state has been sent by the server.
-      </description>
-      <arg name="parent" type="object" allow-null="true"
-        interface="river_window_v1" summary="parent window, if any"/>
-    </event>
-
-    <enum name="decoration_hint">
-      <entry name="only_supports_csd" value="0"
-        summary="only supports client side decoration"/>
-      <entry name="prefers_csd" value="1"
-        summary="client side decoration preferred, both CSD and SSD supported"/>
-      <entry name="prefers_ssd" value="2"
-        summary="server side decoration preferred, both CSD and SSD supported"/>
-      <entry name="no_preference" value="3"
-        summary="no preference, both CSD and SSD supported"/>
-    </enum>
-
-    <event name="decoration_hint">
-      <description summary="supported/preferred decoration style">
-        Information from the window about the supported and preferred client
-        side/server side decoration options.
-
-        This event may be sent multiple times over the lifetime of the window if
-        the window changes its preferences.
-
-        This event will be followed by a manage_start event after all other new
-        state has been sent by the server.
-      </description>
-      <arg name="hint" type="uint" enum="decoration_hint" summary="decoration hint"/>
-    </event>
-
-    <request name="use_csd">
-      <description summary="tell the client to use CSD">
-        Tell the client to use client side decoration and draw its own title
-        bar, borders, etc.
-
-        This is the default if neither this request nor the use_ssd request is
-        ever made.
-
-        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>
-    </request>
-
-    <request name="use_ssd">
-      <description summary="tell the client to use SSD">
-        Tell the client to use server side decoration and not draw any client
-        side decorations.
-
-        This request will have no effect if the client only supports client side
-        decoration, see the decoration_hint event.
-
-        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>
-    </request>
-
-    <enum name="edges" bitfield="true">
-      <entry name="none" value="0"/>
-      <entry name="top" value="1"/>
-      <entry name="bottom" value="2"/>
-      <entry name="left" value="4"/>
-      <entry name="right" value="8"/>
-    </enum>
-
-    <request name="set_borders">
-      <description summary="set window borders">
-        This request decorates the window with borders drawn by the compositor
-        on the specified edges of the window. Borders are drawn above the window
-        content.
-
-        Corners are drawn only between borders on adjacent edges. If e.g. the
-        left edge has a border and the top edge does not, the border drawn on
-        the left edge will not extend vertically beyond the top edge of the
-        window.
-
-        Borders are not drawn while the window is fullscreen.
-
-        The color is defined by four 32-bit RGBA values. Unless specified in
-        another protocol extension, the RGBA values use pre-multiplied alpha.
-
-        The valid range for the RGBA values is from 0x00000000 to 0xffffffff.
-        These values are interpreted as a percentage:
-        - 0x00000000 means 0% of the given color component
-        - 0xffffffff means 100% of the given color component
-
-        Setting the edges to none or the width to 0 disables the borders.
-        Setting a negative width is a protocol error.
-
-        This request completely overrides all previous set_borders requests.
-        Only the most recent set_borders request has an effect.
-
-        Note that the position/dimensions of a river_window_v1 refer to the
-        position/dimensions of the window content and are unaffected by the
-        presence of borders or decoration surfaces.
-
-        This request modifies rendering state and may only be made as part of a
-        render sequence, see the river_window_manager_v1 description.
-      </description>
-      <arg name="edges" type="uint" enum="edges" summary="border edges"/>
-      <arg name="width" type="int" summary="border width"/>
-      <arg name="r" type="uint" summary="32-bit red value"/>
-      <arg name="g" type="uint" summary="32-bit green value"/>
-      <arg name="b" type="uint" summary="32-bit blue value"/>
-      <arg name="a" type="uint" summary="32-bit alpha value"/>
-    </request>
-
-    <request name="set_tiled">
-      <description summary="set window tiled state">
-        Inform the window that it is part of a tiled layout and adjacent to
-        other elements in the tiled layout on the given edges.
-
-        The window should use this information to change the style of its client
-        side decorations and avoid drawing e.g. drop shadows outside of the
-        window dimensions on the tiled edges.
-
-        Setting the edges argument to none informs the window that it is not
-        part of a tiled layout. If this request is never made, the window is
-        informed that it is not part of a tiled layout.
-
-        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="edges" type="uint" enum="edges" summary="tiled edges"/>
-    </request>
-
-    <request name="get_decoration_above">
-      <description summary="create a decoration above the window in z-order">
-        Create a decoration surface and assign the river_decoration_v1 role to
-        the surface. The created decoration is placed above the window in
-        rendering order, see the description of river_decoration_v1.
-
-        Providing a wl_surface which already has a role or already has a buffer
-        attached or committed is a protocol error.
-      </description>
-      <arg name="id" type="new_id" interface="river_decoration_v1"
-        summary="new decoration surface"/>
-      <arg name="surface" type="object" interface="wl_surface"
-        summary="base surface"/>
-    </request>
-
-    <request name="get_decoration_below">
-      <description summary="create a decoration below the window in z-order">
-        Create a decoration surface and assign the river_decoration_v1 role to
-        the surface. The created decoration is placed below the window in
-        rendering order, see the description of river_decoration_v1.
-
-        Providing a wl_surface which already has a role or already has a buffer
-        attached or committed is a protocol error.
-      </description>
-      <arg name="id" type="new_id" interface="river_decoration_v1"
-        summary="new decoration surface"/>
-      <arg name="surface" type="object" interface="wl_surface"
-        summary="base surface"/>
-    </request>
-
-    <event name="pointer_move_requested">
-      <description summary="window requested interactive pointer move">
-        This event informs the window manager that the window has requested to
-        be interactively moved using the pointer. The seat argument indicates the
-        seat for the move.
-
-        The xdg-shell protocol for example allows windows to request that an
-        interactive move be started, perhaps when a client-side rendered
-        titlebar is dragged.
-
-        The window manager may use the river_seat_v1.op_start_pointer request to
-        interactively move the window or ignore this event entirely.
-
-        This event will be followed by a manage_start event after all other new
-        state has been sent by the server.
-      </description>
-      <arg name="seat" type="object" interface="river_seat_v1"
-        summary="requested seat"/>
-    </event>
-
-    <event name="pointer_resize_requested">
-      <description summary="window requested interactive pointer resize">
-        This event informs the window manager that the window has requested to
-        be interactively resized using the pointer. The seat argument indicates
-        the seat for the resize.
-
-        The edges argument indicates which edges the window has requested to be
-        resized from. The edges argument will never be none and will never have
-        both top and bottom or both left and right edges set.
-
-        The xdg-shell protocol for example allows windows to request that an
-        interactive resize be started, perhaps when the corner of client-side
-        rendered decorations is dragged.
-
-        The window manager may use the river_seat_v1.op_start_pointer request to
-        interactively resize the window or ignore this event entirely.
-
-        This event will be followed by a manage_start event after all other new
-        state has been sent by the server.
-      </description>
-      <arg name="seat" type="object" interface="river_seat_v1"
-        summary="requested seat"/>
-      <arg name="edges" type="uint" enum="edges"
-        summary="requested edges"/>
-    </event>
-
-    <request name="inform_resize_start">
-      <description summary="inform the window it is being resized">
-        Inform the window that it is being resized. The window manager should
-        use this request to inform windows that are the target of an interactive
-        resize for example.
-
-        The window manager remains responsible for handling the position and
-        dimensions of the window while it is resizing.
-
-        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>
-    </request>
-
-    <request name="inform_resize_end">
-      <description summary="inform the window it no longer being resized">
-        Inform the window that it is no longer being resized. The window manager
-        should use this request to inform windows that are the target of an
-        interactive resize that the interactive resize has ended for example.
-
-        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>
-    </request>
-
-    <enum name="capabilities" bitfield="true">
-      <entry name="window_menu" value="1"/>
-      <entry name="maximize" value="2"/>
-      <entry name="fullscreen" value="4"/>
-      <entry name="minimize" value="8"/>
-    </enum>
-
-    <request name="set_capabilities">
-      <description summary="inform window of supported capabilities">
-        This request informs the window of the capabilities supported by the
-        window manager. If the window manager, for example, ignores requests to
-        be maximized from the window it should not tell the window that it
-        supports the maximize capability.
-
-        The window might use this information to, for example, only show a
-        maximize button if the window manager supports the maximize capability.
-
-        The window manager client should use this request to set capabilities
-        for all new windows. If this request is never made, the compositor will
-        inform windows that all capabilities are supported.
-
-        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="caps" type="uint" enum="capabilities"
-        summary="supported capabilities"/>
-    </request>
-
-    <event name="show_window_menu_requested">
-      <description summary="window requested that the window menu be shown">
-        The xdg-shell protocol for example allows windows to request that a
-        window menu be shown, for example when the user right clicks on client
-        side window decorations.
-
-        A window menu might include options to maximize or minimize the window.
-
-        The window manager is free to ignore this request and decide what the
-        window menu contains if it does choose to show one.
-
-        The x and y arguments indicate where the window requested that the
-        window menu be shown.
-
-        This event will be followed by a manage_start event after all other new
-        state has been sent by the server.
-      </description>
-      <arg name="x" type="int" summary="x offset from top left corner"/>
-      <arg name="y" type="int" summary="y offset from top left corner"/>
-    </event>
-
-    <event name="maximize_requested">
-      <description summary="the window requested to be maximized">
-        The xdg-shell protocol for example allows windows to request to be
-        maximized.
-
-        The window manager is free to honor this request using
-        river_window_v1.inform_maximized or ignore it.
-
-        This event will be followed by a manage_start event after all other new
-        state has been sent by the server.
-      </description>
-    </event>
-
-    <event name="unmaximize_requested">
-      <description summary="the window requested to be unmaximized">
-        The xdg-shell protocol for example allows windows to request to be
-        unmaximized.
-
-        The window manager is free to honor this request using
-        river_window_v1.inform_unmaximized or ignore it.
-
-        This event will be followed by a manage_start event after all other new
-        state has been sent by the server.
-      </description>
-    </event>
-
-    <request name="inform_maximized">
-      <description summary="inform the window that it is maximized">
-        Inform the window that it is maximized. The window might use this
-        information to adapt the style of its client-side window decorations for
-        example.
-
-        The window manager remains responsible for handling the position and
-        dimensions of the window while it is maximized.
-
-        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>
-    </request>
-
-    <request name="inform_unmaximized">
-      <description summary="inform the window that it is unmaximized">
-        Inform the window that it is unmaximized. The window might use this
-        information to adapt the style of its client-side window decorations for
-        example.
-
-        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>
-    </request>
-
-    <event name="fullscreen_requested">
-      <description summary="the window requested to be fullscreen">
-        The xdg-shell protocol for example allows windows to request that they
-        be made fullscreen and allows them to provide an optional output hint.
-
-        If the output argument is null, the window has no preference and the
-        window manager should choose an output.
-
-        The window manager is free to honor this request using
-        river_window_v1.fullscreen or ignore it.
-
-        This event will be followed by a manage_start event after all other new
-        state has been sent by the server.
-      </description>
-      <arg name="output" type="object" allow-null="true"
-        interface="river_output_v1" summary="fullscreen output requested"/>
-    </event>
-
-    <event name="exit_fullscreen_requested">
-      <description summary="the window requested to exit fullscreen">
-        The xdg-shell protocol for example allows windows to request to exit
-        fullscreen.
-
-        The window manager is free to honor this request using
-        river_window_v1.exit_fullscreen or ignore it.
-
-        This event will be followed by a manage_start event after all other new
-        state has been sent by the server.
-      </description>
-    </event>
-
-    <request name="inform_fullscreen">
-      <description summary="inform the window that it is fullscreen">
-        Inform the window that it is fullscreen. The window might use this
-        information to adapt the style of its client-side window decorations for
-        example.
-
-        This request does not affect the size/position of the window or cause it
-        to become the only window rendered, see the river_window_v1.fullscreen
-        and exit_fullscreen requests for that.
-
-        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>
-    </request>
-
-    <request name="inform_not_fullscreen">
-      <description summary="inform the window that it is not fullscreen">
-        Inform the window that it is not fullscreen. The window might use this
-        information to adapt the style of its client-side window decorations for
-        example.
-
-        This request does not affect the size/position of the window or cause it
-        to become the only window rendered, see the river_window_v1.fullscreen
-        and exit_fullscreen requests for that.
-
-        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>
-    </request>
-
-    <request name="fullscreen">
-      <description summary="make the window fullscreen">
-        Make the window fullscreen on the given output. If multiple windows are
-        fullscreen on the same output at the same time only the "top" window in
-        rendering order shall be displayed.
-
-        All river_shell_surface_v1 objects above the top fullscreen window in
-        the rendering order will continue to be rendered.
-
-        The compositor will handle the position and dimensions of the window
-        while it is fullscreen. The set_position and propose_dimensions requests
-        shall not affect the current position and dimensions of a fullscreen
-        window.
-
-        When a fullscreen request is made, the server must send a dimensions
-        event in response as soon as possible. It may not be possible to send a
-        dimensions event in the very next render sequence if, for example, the
-        window takes too long to respond. In this case, the server will send the
-        dimensions event in a future render sequence.
-
-        The compositor will clip window content, decoration surfaces, and
-        borders to the given output's dimensions while the window is fullscreen.
-        The effects of set_clip_box and set_content_clip_box are ignored while
-        the window is fullscreen.
-
-        If the output on which a window is currently fullscreen is removed, the
-        windowing state is modified as if there were an exit_fullscreen request
-        made in the same manage sequence as the river_output_v1.removed event.
-
-        This request does not inform the window that it is fullscreen, see the
-        river_window_v1.inform_fullscreen and inform_not_fullscreen requests.
-
-        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="output" type="object" interface="river_output_v1"
-        summary="fullscreen output"/>
-    </request>
-
-    <request name="exit_fullscreen">
-      <description summary="make the window not fullscreen">
-        Make the window not fullscreen.
-
-        The position and dimensions are undefined after this request is made
-        until a manage sequence in which the window manager makes the
-        propose_dimensions and set_position requests is completed.
-
-        The window manager should make propose_dimensions and set_position
-        requests in the same manage sequence as the exit_fullscreen request for
-        frame perfection.
-
-        This request does not inform the window that it is fullscreen, see the
-        river_window_v1.inform_fullscreen and inform_not_fullscreen requests.
-
-        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>
-    </request>
-
-    <event name="minimize_requested">
-      <description summary="the window requested to be minimized">
-        The xdg-shell protocol for example allows windows to request to be
-        minimized.
-
-        The window manager is free to ignore this request, hide the window, or
-        do whatever else it chooses.
-
-        This event will be followed by a manage_start event after all other new
-        state has been sent by the server.
-      </description>
-    </event>
-
-    <request name="set_clip_box" since="2">
-      <description summary="clip the window to a given box">
-        Clip the window, including borders and decoration surfaces, to the box
-        specified by the x, y, width, and height arguments. The x/y position of
-        the box is relative to the top left corner of the window.
-
-        The width and height arguments must be greater than or equal to 0.
-
-        Setting a clip box with 0 width or height disables clipping.
-
-        The clip box is ignored while the window is fullscreen.
-
-        Both set_clip_box and set_content_clip_box may be enabled simultaneously.
-
-        This request modifies rendering state and may only be made as part of a
-        render sequence, see the river_window_manager_v1 description.
-      </description>
-      <arg name="x" type="int" summary="x relative to top left window corner"/>
-      <arg name="y" type="int" summary="y relative to top left window corner"/>
-      <arg name="width" type="int" summary="clip box width"/>
-      <arg name="height" type="int" summary="clip box height"/>
-    </request>
-
-    <event name="unreliable_pid" since="2">
-      <description summary="unreliable PID of the window's creator">
-        This event gives an unreliable PID of the process that created the
-        window. Obtaining this information is inherently racy due to PID reuse.
-        Therefore, this PID must not be used for anything security sensitive.
-
-        Note also that a single process may create multiple windows, so there is
-        not necessarily a 1-to-1 mapping from PID to window. Multiple windows
-        may have the same PID.
-
-        This event is sent once when the river_window_v1 is created and never
-        sent again.
-      </description>
-      <arg name="unreliable_pid" type="int" summary="unreliable PID"/>
-    </event>
-
-    <request name="set_content_clip_box" since="3">
-      <description summary="clip the window content to a given box">
-        Clip the content of the window, excluding borders and decoration
-        surfaces, to the box specified by the x, y, width, and height arguments.
-        The x/y position of the box is relative to the top left corner of the
-        window.
-
-        Borders drawn by the compositor (see set_borders) are placed around the
-        intersection of the window content (as defined by the dimensions event)
-        and the content clip box when content clipping is enabled.
-
-        The width and height arguments must be greater than or equal to 0.
-
-        Setting a box with 0 width or height disables content clipping.
-
-        The content clip box is ignored while the window is fullscreen.
-
-        Both set_clip_box and set_content_clip_box may be enabled simultaneously.
-
-        This request modifies rendering state and may only be made as part of a
-        render sequence, see the river_window_manager_v1 description.
-      </description>
-      <arg name="x" type="int" summary="x relative to top left window corner"/>
-      <arg name="y" type="int" summary="y relative to top left window corner"/>
-      <arg name="width" type="int" summary="clip box width"/>
-      <arg name="height" type="int" summary="clip box height"/>
-    </request>
-
-    <event name="presentation_hint" since="4">
-      <description summary="presentation hint set by the window">
-        This event communicates the window's preferred presentation mode.
-
-        This event will be followed by a render_start event after all other new
-        state has been sent by the server.
-      </description>
-      <arg name="hint" type="uint" enum="river_output_v1.presentation_mode"
-        summary="presentation hint"/>
-    </event>
-
-    <event name="identifier" since="4">
-      <description summary="unique window identifier">
-        The identifier is a string that contains up to 32 printable ASCII bytes.
-        The identifier must not be an empty string.
-
-        It is compositor policy how the identifier is generated, but the following
-        properties must be upheld:
-
-        1. The identifier must uniquely identify the window. Two windows must not
-           share the same identifier.
-
-        2. The identifier must not be reused. This avoids races around window
-           creation/destruction when identifiers are used in out-of-band IPC.
-
-        If the compositor implements the ext-foreign-toplevel-list-v1 protocol,
-        the river_window_v1.identifier event must match the corresponding
-        ext_foreign_toplevel_handle_v1.identifier event.
-
-        This event is sent once when the river_window_v1 is created and never
-        sent again.
-      </description>
-      <arg name="identifier" type="string" summary="unique identifier"/>
-    </event>
-
-    <request name="set_dimension_bounds" since="4">
-      <description summary="recommend maximum dimensions to the window">
-        Recommend that the window keep its dimensions within a given
-        maximum width/height. This recommendation is only a hint and the window
-        may ignore it.
-
-        Setting the width and height to 0 indicates that there are no bounds
-        and is equivalent to having never made this request.
-
-        Setting width or height to a negative value is a protocol error.
-
-        The server should communicate this hint to an xdg_toplevel window with
-        the xdg_toplevel.configure_bounds event for example.
-
-        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="max_width" type="int" summary="maximum width"/>
-      <arg name="max_height" type="int" summary="maximum height"/>
-    </request>
-
-    <request name="set_opacity" since="4">
-      <description summary="set the window opacity">
-        Set the window opacity, from 0 (fully transparent) to 0xffffffff (fully opaque).
-        This request modifies rendering state and may only be made as part of a
-        render sequence, see the river_window_manager_v1 description.
-      </description>
-      <arg name="opacity" type="uint" summary="opacity value from 0 to 0xffffffff"/>
-    </request>
-
-    <request name="set_circular" since="4">
-      <description summary="set whether the window is circular">
-        Set whether the window is circular (1 for circular, 0 for rectangular).
-        This request modifies rendering state and may only be made as part of a
-        render sequence, see the river_window_manager_v1 description.
-      </description>
-      <arg name="circular" type="uint" summary="1 if circular, 0 otherwise"/>
-    </request>
-
-    <request name="set_blur" since="4">
-      <description summary="set whether backdrop blur is enabled">
-        Set whether backdrop blur should be enabled for this window.
-        1 to enable, 0 to disable.
-        This request modifies rendering state and may only be made as part of a
-        render sequence, see the river_window_manager_v1 description.
-      </description>
-      <arg name="blur" type="uint" summary="1 to enable, 0 to disable"/>
-    </request>
-  </interface>
-
-  <interface name="river_decoration_v1" version="4">
-    <description summary="a window decoration">
-      The rendering order of windows with decorations is follows:
-
-      1. Decorations created with get_decoration_below at the bottom
-      2. Window content
-      3. Borders configured with river_window_v1.set_borders
-      4. Decorations created with get_decoration_above at the top
-
-      The relative ordering of decoration surfaces above/below a window is
-      undefined by this protocol and left up to the compositor.
-    </description>
-
-    <enum name="error">
-      <entry name="no_commit" value="0"
-        summary="failed to commit the surface before the window manager commit"/>
-    </enum>
-
-    <request name="destroy" type="destructor">
-      <description summary="destroy the decoration object">
-        This request indicates that the client will no longer use the decoration
-        object and that it may be safely destroyed.
-      </description>
-    </request>
-
-    <request name="set_offset">
-      <description summary="set offset from the window's top left corner">
-        This request sets the offset of the decoration surface from the top left
-        corner of the window.
-
-        If this request is never sent, the x and y offsets are undefined by this
-        protocol and left up to the compositor.
-
-        This request modifies rendering state and may only be made as part of a
-        render sequence, see the river_window_manager_v1 description.
-      </description>
-      <arg name="x" type="int" summary="x relative to top left window corner"/>
-      <arg name="y" type="int" summary="y relative to top left window corner"/>
-    </request>
-
-    <request name="sync_next_commit">
-      <description summary="sync next commit with other rendering state">
-        Synchronize application of the next wl_surface.commit request on the
-        decoration surface with rest of the state atomically applied with the
-        next river_window_manager_v1.render_finish request.
-
-        The client must make a wl_surface.commit request on the decoration
-        surface after this request and before the render_finish request, failure
-        to do so is a protocol error.
-
-        This request modifies rendering state and may only be made as part of a
-        render sequence, see the river_window_manager_v1 description.
-      </description>
-    </request>
-
-    <request name="set_blur" since="4">
-      <description summary="set whether backdrop blur is enabled">
-        Set whether backdrop blur should be enabled for this decoration.
-        1 to enable, 0 to disable.
-        This request modifies rendering state and may only be made as part of a
-        render sequence, see the river_window_manager_v1 description.
-      </description>
-      <arg name="blur" type="uint" summary="1 to enable, 0 to disable"/>
-    </request>
-  </interface>
-
-  <interface name="river_shell_surface_v1" version="4">
-    <description summary="a surface for window manager UI">
-      The window manager might use a shell surface to display a status bar,
-      background image, desktop notifications, launcher, desktop menu, or
-      whatever else it wants.
-    </description>
-
-    <enum name="error">
-      <entry name="node_exists" value="0"
-        summary="shell surface already has a node object"/>
-      <entry name="no_commit" value="1"
-        summary="failed to commit the surface before the window manager commit"/>
-    </enum>
-
-    <request name="destroy" type="destructor">
-      <description summary="destroy the shell surface object">
-        This request indicates that the client will no longer use the shell
-        surface object and that it may be safely destroyed.
-      </description>
-    </request>
-
-    <request name="get_node">
-      <description summary="get the shell surface's render list node">
-        Get the node in the render list corresponding to the shell surface.
-
-        It is a protocol error to make this request more than once for a single
-        shell surface.
-      </description>
-      <arg name="id" type="new_id" interface="river_node_v1" summary="new node"/>
-    </request>
-
-    <request name="sync_next_commit">
-      <description summary="sync next surface commit to window manager commit">
-        Synchronize application of the next wl_surface.commit request on the
-        shell surface with rest of the rendering state atomically applied with
-        the next river_window_manager_v1.render_finish request.
-
-        The client must make a wl_surface.commit request on the shell surface
-        after this request and before the render_finish request, failure to do
-        so is a protocol error.
-
-        This request modifies rendering state and may only be made as part of a
-        render sequence, see the river_window_manager_v1 description.
-      </description>
-    </request>
-  </interface>
-
-  <interface name="river_node_v1" version="4">
-    <description summary="a node in the render list">
-      The render list is a list of nodes that determines the rendering order of
-      the compositor. Nodes may correspond to windows or shell surfaces. The
-      relative ordering of nodes may be changed with the place_above and
-      place_below requests, changing the rendering order.
-
-      The initial position of a node in the render list is undefined, the window
-      manager client must use the place_above or place_below request to
-      guarantee a specific rendering order.
-    </description>
-
-    <request name="destroy" type="destructor">
-      <description summary="destroy the decoration object">
-        This request indicates that the client will no longer use the node
-        object and that it may be safely destroyed.
-      </description>
-    </request>
-
-    <request name="set_position">
-      <description summary="set absolute position of the node">
-        Set the absolute position of the node in the compositor's logical
-        coordinate space. The x and y coordinates may be positive or negative.
-
-        Note that the position of a river_window_v1 refers to the position of
-        the window content and is unaffected by the presence of borders or
-        decoration surfaces.
-
-        If this request is never sent, the position of the node is undefined by
-        this protocol and left up to the compositor.
-
-        This request modifies rendering state and may only be made as part of a
-        render sequence, see the river_window_manager_v1 description.
-      </description>
-      <arg name="x" type="int" summary="global x coordinate"/>
-      <arg name="y" type="int" summary="global y coordinate"/>
-    </request>
-
-    <request name="place_top">
-      <description summary="place node above all other nodes">
-        This request places the node above all other nodes in the compositor's
-        render list.
-
-        This request modifies rendering state and may only be made as part of a
-        render sequence, see the river_window_manager_v1 description.
-      </description>
-    </request>
-
-    <request name="place_bottom">
-      <description summary="place node below all other nodes">
-        This request places the node below all other nodes in the compositor's
-        render list.
-
-        This request modifies rendering state and may only be made as part of a
-        render sequence, see the river_window_manager_v1 description.
-      </description>
-    </request>
-
-    <request name="place_above">
-      <description summary="place node above another node">
-        This request places the node directly above another node in the
-        compositor's render list.
-
-        Attempting to place a node above itself has no effect.
-
-        This request modifies rendering state and may only be made as part of a
-        render sequence, see the river_window_manager_v1 description.
-      </description>
-      <arg name="other" type="object" interface="river_node_v1"
-        summary="other node"/>
-    </request>
-
-    <request name="place_below">
-      <description summary="place node below another node">
-        This request places the node directly below another node in the
-        compositor's render list.
-
-        Attempting to place a node below itself has no effect.
-
-        This request modifies rendering state and may only be made as part of a
-        render sequence, see the river_window_manager_v1 description.
-      </description>
-      <arg name="other" type="object" interface="river_node_v1"
-        summary="other node"/>
-    </request>
-  </interface>
-
-  <interface name="river_output_v1" version="4">
-    <description summary="a logical output">
-      An area in the compositor's logical coordinate space that should be
-      treated as a single output for window management purposes. This area may
-      correspond to a single physical output or multiple physical outputs in the
-      case of mirroring or tiled monitors depending on the hardware and
-      compositor configuration.
-    </description>
-
-    <request name="destroy" type="destructor">
-      <description summary="destroy the output object">
-        This request indicates that the client will no longer use the output
-        object and that it may be safely destroyed.
-
-        This request should be made after the river_output_v1.removed event is
-        received to complete destruction of the output.
-      </description>
-    </request>
-
-    <event name="removed">
-      <description summary="the output is removed">
-        This event indicates that the logical output is no longer conceptually
-        part of window management space.
-
-        The server will send no further events on this object and ignore any
-        request (other than river_output_v1.destroy) made after this event is
-        sent. The client should destroy this object with the
-        river_output_v1.destroy request to free up resources.
-
-        This event may be sent because a corresponding physical output has been
-        physically unplugged or because some output configuration has changed.
-
-        This event will be followed by a manage_start event after all other new
-        state has been sent by the server.
-      </description>
-    </event>
-
-    <event name="wl_output">
-      <description summary="corresponding wl_output">
-        The wl_output object corresponding to the river_output_v1. The argument
-        is the global name of the wl_output advertised with wl_registry.global.
-
-        It is guaranteed that the corresponding wl_output is advertised before
-        this event is sent.
-
-        This event is sent exactly once. The wl_output associated with a
-        river_output_v1 cannot change. It is guaranteed that there is a 1-to-1
-        mapping between wl_output and river_output_v1 objects.
-
-        The global_remove event for the corresponding wl_output may be sent
-        before the river_output_v1.removed event. This is due to the fact that
-        river_output_v1 state changes are synced to the river window management
-        manage sequence while changes to globals are not.
-
-        Rationale: The window manager may need information provided by the
-        wl_output interface such as the name/description. It also may need the
-        wl_output object to start screencopy for example.
-      </description>
-      <arg name="name" type="uint" summary="name of the wl_output global"/>
-    </event>
-
-    <event name="position">
-      <description summary="output position">
-        This event indicates the position of the output in the compositor's
-        logical coordinate space. The x and y coordinates may be positive or
-        negative.
-
-        This event is sent once when the river_output_v1 is created and again
-        whenever the position changes.
-
-        This event will be followed by a manage_start event after all other new
-        state has been sent by the server.
-
-        The server must guarantee that the position and dimensions events do not
-        cause the areas of multiple logical outputs to overlap when the
-        corresponding manage_start event is received.
-      </description>
-      <arg name="x" type="int" summary="global x coordinate"/>
-      <arg name="y" type="int" summary="global y coordinate"/>
-    </event>
-
-    <event name="dimensions">
-      <description summary="output dimensions">
-        This event indicates the dimensions of the output in the compositor's
-        logical coordinate space. The width and height will always be strictly
-        greater than zero.
-
-        This event is sent once when the river_output_v1 is created and again
-        whenever the dimensions change.
-
-        This event will be followed by a manage_start event after all other new
-        state has been sent by the server.
-
-        The server must guarantee that the position and dimensions events do not
-        cause the areas of multiple logical outputs to overlap when the
-        corresponding manage_start event is received.
-      </description>
-      <arg name="width" type="int" summary="output width"/>
-      <arg name="height" type="int" summary="output height"/>
-    </event>
-
-    <enum name="error" since="4">
-      <entry name="invalid_presentation_mode" value="0" since="4"
-        summary="invalid presentation mode enum value"/>
-    </enum>
-
-    <enum name="presentation_mode" since="4">
-      <entry name="vsync" value="0">
-        <description summary="tearing-free presentation">
-          Output page-flips should be synchronized to the vertical blanking
-          period, eliminating tearing. This is the default presentation mode.
-        </description>
-      </entry>
-      <entry name="async" value="1">
-        <description summary="asynchronous presentation">
-          Output page-flips should not be synchronized to the vertical blanking
-          period, visual screen tearing may occur.
-        </description>
-      </entry>
-    </enum>
-
-    <request name="set_presentation_mode" since="4">
-      <description summary="set the preferred presentation mode">
-        Set the preferred presentation mode of the output. The compositor should
-        always respect the preference of the window manager if possible. If this
-        request is never made, the preferred presentation mode is vsync.
-
-        This request modifies rendering state and may only be made as part of a
-        render sequence, see the river_window_manager_v1 description.
-      </description>
-      <arg name="mode" type="uint" enum="presentation_mode"
-        summary="preferred presentation mode"/>
-    </request>
-  </interface>
-
-  <interface name="river_seat_v1" version="4">
-    <description summary="a window management seat">
-      This object represents a single user's collection of input devices. It
-      allows the window manager to route keyboard input to windows, get
-      high-level information about pointer input, define pointer bindings, etc.
-
-      For keyboard bindings, see the river-xkb-bindings-v1 protocol.
-
-      Since version 4: The cursor surface/shape set by the window manager on the
-      wl_pointer of this seat is used when no client has pointer focus, for
-      example during a pointer operation. Since the window manager is allowed to
-      set cursor surface/shape even when it does not have pointer focus, the
-      compositor must ignore the serial argument of wl_pointer.set_cursor and
-      wp_cursor_shape_device_v1.set_shape requests made by the window manager.
-
-      The most recent cursor surface/shape set by the window manager is
-      remembered by the compositor and restored whenever no client has pointer
-      focus. If the window manager never sets a cursor surface/shape, the
-      "default" shape is used.
-    </description>
-
-    <request name="destroy" type="destructor">
-      <description summary="destroy the seat object">
-        This request indicates that the client will no longer use the seat
-        object and that it may be safely destroyed.
-
-        This request should be made after the river_seat_v1.removed event is
-        received to complete destruction of the seat.
-      </description>
-    </request>
-
-    <event name="removed">
-      <description summary="the seat is removed">
-        This event indicates that seat is no longer in use and should be
-        destroyed.
-
-        The server will send no further events on this object and ignore any
-        request (other than river_seat_v1.destroy) made after this event is
-        sent.  The client should destroy this object with the
-        river_seat_v1.destroy request to free up resources.
-
-        This event will be followed by a manage_start event after all other new
-        state has been sent by the server.
-      </description>
-    </event>
-
-    <event name="wl_seat">
-      <description summary="corresponding wl_seat">
-        The wl_seat object corresponding to the river_seat_v1. The argument is
-        the global name of the wl_seat advertised with wl_registry.global.
-
-        It is guaranteed that the corresponding wl_seat is advertised before
-        this event is sent.
-
-        This event is sent exactly once. The wl_seat associated with a
-        river_seat_v1 cannot change. It is guaranteed that there is a 1-to-1
-        mapping between wl_seat and river_seat_v1 objects.
-
-        The global_remove event for the corresponding wl_seat may be sent before
-        the river_seat_v1.removed event. This is due to the fact that
-        river_seat_v1 state changes are synced to the river window management
-        manage sequence while changes to globals are not.
-
-        Rationale: The window manager may want to trigger window management
-        state changes based on normal input events received by its shell
-        surfaces for example.
-      </description>
-      <arg name="name" type="uint" summary="name of the wl_seat global"/>
-    </event>
-
-    <request name="focus_window">
-      <description summary="give keyboard focus to a window">
-        Request that the compositor send keyboard input to the given window.
-
-        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="window" type="object" interface="river_window_v1"
-        summary="window to focus"/>
-    </request>
-
-    <request name="focus_shell_surface">
-      <description summary="give keyboard focus to a shell_surface">
-        Request that the compositor send keyboard input to the given shell
-        surface.
-
-        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="shell_surface" type="object" interface="river_shell_surface_v1"
-        summary="shell surface to focus"/>
-    </request>
-
-    <request name="clear_focus">
-      <description summary="clear keyboard focus">
-        Request that the compositor not send keyboard input to any client.
-
-        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>
-    </request>
-
-    <event name="pointer_enter">
-      <description summary="pointer entered a window">
-        The seat's pointer entered the given window's area.
-
-        The area of a window is defined to include the area defined by the
-        window dimensions, borders configured using river_window_v1.set_borders,
-        and the input regions of decoration surfaces. In particular, it does not
-        include input regions of surfaces belonging to the window that extend
-        outside the window dimensions.
-
-        The pointer of a seat may only enter a single window at a time. When the
-        pointer moves between windows, the pointer_leave event for the old
-        window must be sent before the pointer_enter event for the new window.
-
-        This event will be followed by a manage_start event after all other new
-        state has been sent by the server.
-      </description>
-      <arg name="window" type="object" interface="river_window_v1"
-        summary="window entered"/>
-    </event>
-
-    <event name="pointer_leave">
-      <description summary="pointer left the entered window">
-        The seat's pointer left the window for which pointer_enter was most
-        recently sent. See pointer_enter for details.
-
-        This event will be followed by a manage_start event after all other new
-        state has been sent by the server.
-      </description>
-    </event>
-
-    <event name="window_interaction">
-      <description summary="a window has been interacted with">
-        A window has been interacted with beyond the pointer merely passing over
-        it. This event might be sent due to a pointer button press or due to a
-        touch/tablet tool interaction with the window.
-
-        There are no guarantees regarding how this event is sent in relation to
-        the pointer_enter and pointer_leave events as the interaction may use
-        touch or tablet tool input.
-
-        Rationale: this event gives window managers necessary information to
-        determine when to send keyboard focus, raise a window that already has
-        keyboard focus, etc. Rather than expose all pointer, touch, and tablet
-        events to window managers, a policy over mechanism approach is taken.
-
-        This event will be followed by a manage_start event after all other new
-        state has been sent by the server.
-      </description>
-      <arg name="window" type="object" interface="river_window_v1"
-        summary="window interacted with"/>
-    </event>
-
-    <event name="shell_surface_interaction">
-      <description summary="a shell surface has been interacted with">
-        A shell surface has been interacted with beyond the pointer merely
-        passing over it. This event might be sent due to a pointer button press
-        or due to a touch/tablet tool interaction with the shell_surface.
-
-        There are no guarantees regarding how this event is sent in relation to
-        the pointer_enter and pointer_leave events as the interaction may use
-        touch or tablet tool input.
-
-        Rationale: While the shell surface does receive all wl_pointer,
-        wl_touch, etc. input events for the surface directly, these events do
-        not necessarily trigger a manage sequence and therefore do not allow the
-        window manager to update focus or perform other actions in response to
-        the input in a race-free way.
-
-        This event will be followed by a manage_start event after all other new
-        state has been sent by the server.
-      </description>
-      <arg name="shell_surface" type="object" interface="river_shell_surface_v1"
-        summary="shell surface interacted with"/>
-    </event>
-
-    <request name="op_start_pointer">
-      <description summary="start an interactive pointer operation">
-        Start an interactive pointer operation. During the operation, op_delta
-        events will be sent based on pointer input.
-
-        When all pointer buttons are released, the op_release event is sent.
-
-        The pointer operation continues until the op_end request is made during
-        a manage sequence and that manage sequence is finished.
-
-        The window manager may use this operation to implement interactive
-        move/resize of windows by setting the position of windows and proposing
-        dimensions based off of the op_delta events.
-
-        This request is ignored if an operation is already in progress.
-
-        The compositor must ensure that no client has pointer focus from this
-        seat during the pointer operation. This means that the window manager
-        has control over the pointer's cursor surface/shape during the pointer
-        operation. See the river_seat_v1 description.
-
-        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>
-    </request>
-
-    <event name="op_delta">
-      <description summary="total cumulative motion since op start">
-        This event indicates the total change in position since the start of the
-        operation of the pointer/touch point/etc.
-
-        This event will be followed by a manage_start event after all other new
-        state has been sent by the server.
-      </description>
-      <arg name="dx" type="int" summary="total change in x"/>
-      <arg name="dy" type="int" summary="total change in y"/>
-    </event>
-
-    <event name="op_release">
-      <description summary="operation input has been released">
-        The input driving the current interactive operation has been released.
-        For a pointer op for example, all pointer buttons have been released.
-
-        Depending on the op type, op_delta events may continue to be sent until
-        the op is ended with the op_end request.
-
-        This event is sent at most once during an interactive operation.
-
-        This event will be followed by a manage_start event after all other new
-        state has been sent by the server.
-      </description>
-    </event>
-
-    <request name="op_end">
-      <description summary="end an interactive operation">
-        End an interactive operation.
-
-        This request is ignored if there is no operation in progress.
-
-        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>
-    </request>
-
-    <enum name="modifiers" bitfield="true">
-      <description summary="a set of keyboard modifiers">
-        This enum is used to describe the keyboard modifiers that must be held
-        down to trigger a key binding or pointer binding.
-
-        Note that river and wlroots use the values 2 and 16 for capslock and
-        numlock internally. It doesn't make sense to use locked modifiers for
-        bindings however so these values are not included in this enum.
-      </description>
-      <entry name="none" value="0"/>
-      <entry name="shift" value="1"/>
-      <entry name="ctrl" value="4"/>
-      <entry name="mod1" value="8" summary="commonly called alt"/>
-      <entry name="mod3" value="32"/>
-      <entry name="mod4" value="64" summary="commonly called super or logo"/>
-      <entry name="mod5" value="128"/>
-    </enum>
-
-    <request name="get_pointer_binding">
-      <description summary="define a new pointer binding">
-        Define a pointer binding in terms of a pointer button, keyboard
-        modifiers, and other configurable properties.
-
-        The button argument is a Linux input event code defined in the
-        linux/input-event-codes.h header file (e.g. BTN_RIGHT).
-
-        The new pointer binding is not enabled until initial configuration is
-        completed and the enable request is made during a manage sequence.
-      </description>
-      <arg name="id" type="new_id" interface="river_pointer_binding_v1"
-        summary="new pointer binding"/>
-      <arg name="button" type="uint" summary="a Linux input event code"/>
-      <arg name="modifiers" type="uint" enum="modifiers"
-        summary="keyboard modifiers"/>
-    </request>
-
-    <request name="set_xcursor_theme" since="2">
-      <description summary="set the xcursor theme for the seat">
-        Set the XCursor theme for the seat. This theme is used for cursors
-        rendered by the compositor, but not necessarily for cursors rendered by
-        clients.
-
-        Note: The window manager may also wish to set the XCURSOR_THEME and
-        XCURSOR_SIZE environment variable for programs it starts.
-      </description>
-      <arg name="name" type="string" summary="xcursor theme name"/>
-      <arg name="size" type="uint" summary="cursor size"/>
-    </request>
-
-    <event name="pointer_position" since="2">
-      <description summary="The current position of the pointer">
-        The current position of the pointer in the compositor's logical
-        coordinate space.
-
-        This state is special in that a change in pointer position alone must
-        not cause the compositor to start a manage sequence.
-
-        Assuming the seat has a pointer, this event must be sent in every manage
-        sequence unless there is no change in x/y position since the last time this
-        event was sent.
-      </description>
-      <arg name="x" type="int" summary="global x coordinate"/>
-      <arg name="y" type="int" summary="global y coordinate"/>
-    </event>
-
-    <request name="pointer_warp" since="3">
-      <description summary="warp the pointer to a given position">
-        Warp the pointer to the given position in the compositor's logical
-        coordinate space.
-
-        If the given position is outside the bounds of all outputs, the pointer
-        will be warped to the closest point inside an output instead.
-
-        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="x" type="int" summary="global x coordinate"/>
-      <arg name="y" type="int" summary="global y coordinate"/>
-    </request>
-  </interface>
-
-  <interface name="river_pointer_binding_v1" version="4">
-    <description summary="configure a pointer binding, receive trigger events">
-      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 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
-      binding are not sent to the surface with pointer focus.
-
-      If multiple pointer bindings would be triggered by a single physical
-      pointer event on the compositor side, it is compositor policy which
-      pointer binding(s) will receive press/release events or if all of the
-      matched pointer bindings receive press/release events.
-    </description>
-
-    <request name="destroy" type="destructor">
-      <description summary="destroy the pointer binding object">
-        This request indicates that the client will no longer use the pointer
-        binding object and that it may be safely destroyed.
-      </description>
-    </request>
-
-    <request name="enable">
-      <description summary="enable the pointer binding">
-        This request should be made after all initial configuration has been
-        completed and the window manager wishes the pointer binding to be able
-        to be triggered.
-
-        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>
-    </request>
-
-    <request name="disable">
-      <description summary="disable the pointer binding">
-        This request may be used to temporarily disable the pointer binding. It
-        may be later re-enabled with the 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>
-    </request>
-
-    <event name="pressed">
-      <description summary="the bound pointer button has been pressed">
-        This event indicates that the pointer button triggering the binding has
-        been pressed.
-
-        This event will be followed by a manage_start event after all other new
-        state has been sent by the server.
-
-        The compositor should wait for the manage sequence to complete before
-        processing further input events. This allows the window manager client
-        to, for example, modify key bindings and keyboard focus without racing
-        against future input events. The window manager should of course respond
-        as soon as possible as the capacity of the compositor to buffer incoming
-        input events is finite.
-      </description>
-    </event>
-
-    <event name="released">
-      <description summary="the bound pointer button has been released">
-        This event indicates that the pointer button triggering the binding has
-        been released.
-
-        Releasing the modifiers for the binding without releasing the pointer
-        button does not trigger the release event. This event is sent when the
-        pointer button is released, even if the modifiers have changed since the
-        pressed event.
-
-        This event will be followed by a manage_start event after all other new
-        state has been sent by the server.
-
-        The compositor should wait for the manage sequence to complete before
-        processing further input events. This allows the window manager client
-        to, for example, modify key bindings and keyboard focus without racing
-        against future input events. The window manager should of course respond
-        as soon as possible as the capacity of the compositor to buffer incoming
-        input events is finite.
-      </description>
-    </event>
-  </interface>
-</protocol>
diff --git a/protocol/river-xkb-bindings-v1.xml b/protocol/river-xkb-bindings-v1.xml
index 55fb72f..8b3c65e 100644
--- a/protocol/river-xkb-bindings-v1.xml
+++ b/protocol/river-xkb-bindings-v1.xml
@@ -58,10 +58,10 @@
         The new key binding is not enabled until initial configuration is
         completed and the enable request is made during a manage sequence.
       </description>
-      <arg name="seat" type="object" interface="river_seat_v1"/>
+      <arg name="seat" type="object" interface="zcce_seat_v1"/>
       <arg name="id" type="new_id" interface="river_xkb_binding_v1"/>
       <arg name="keysym" type="uint" summary="an xkbcommon keysym"/>
-      <arg name="modifiers" type="uint" enum="river_seat_v1.modifiers"/>
+      <arg name="modifiers" type="uint" enum="zcce_seat_v1.modifiers"/>
     </request>
 
     <request name="get_seat" since="2">
@@ -72,7 +72,7 @@
         river_seat_v1 object.
       </description>
       <arg name="id" type="new_id" interface="river_xkb_bindings_seat_v1"/>
-      <arg name="seat" type="object" interface="river_seat_v1"/>
+      <arg name="seat" type="object" interface="zcce_seat_v1"/>
     </request>
   </interface>
 
diff --git a/src/server/cce_window_management.rs b/src/server/cce_window_management.rs
index 6623f45..e78d92d 100644
--- a/src/server/cce_window_management.rs
+++ b/src/server/cce_window_management.rs
@@ -5,7 +5,6 @@ use crate::slotmap::Key as SlotMapKey;
 
 pub struct CceWindowManagement {
     pub server: *mut Server,
-    pub global: *mut ffi::wl_global,
     pub toplevels: Vec<*mut ffi::wl_resource>,
 }
 
@@ -13,7 +12,6 @@ impl CceWindowManagement {
     pub fn new() -> Self {
         Self {
             server: std::ptr::null_mut(),
-            global: std::ptr::null_mut(),
             toplevels: Vec::new(),
         }
     }
@@ -21,58 +19,9 @@ impl CceWindowManagement {
     pub unsafe fn init(&mut self, server: *mut Server) -> Result<(), &'static str> {
         self.server = server;
         self.toplevels = Vec::new();
-
-        self.global = ffi::wl_global_create(
-            (*server).wl_server,
-            &ffi::zcce_window_manager_v1_interface,
-            1,
-            self as *mut CceWindowManagement as *mut _,
-            Some(bind_wm),
-        );
-
-        if self.global.is_null() {
-            return Err("Failed to create zcce_window_manager_v1 global");
-        }
-
-        log::info!("zcce_window_manager_v1 protocol global initialized successfully");
+        log::info!("CceWindowManagement initialized successfully");
         Ok(())
     }
-
-    pub unsafe fn deinit(&mut self) {
-        if !self.global.is_null() {
-            ffi::wl_global_destroy(self.global);
-            self.global = std::ptr::null_mut();
-        }
-    }
-}
-
-unsafe extern "C" fn bind_wm(
-    client: *mut ffi::wl_client,
-    data: *mut std::ffi::c_void,
-    version: u32,
-    id: u32,
-) {
-    let wm = data as *mut CceWindowManagement;
-    if wm.is_null() {
-        return;
-    }
-
-    let resource = ffi::wl_resource_create(client, &ffi::zcce_window_manager_v1_interface, version as i32, id);
-    if resource.is_null() {
-        ffi::wl_client_post_no_memory(client);
-        return;
-    }
-
-    ffi::wl_resource_set_implementation(
-        resource,
-        &CCE_WM_INTERFACE as *const _ as *const _,
-        wm as *mut _,
-        None,
-    );
-}
-
-unsafe extern "C" fn wm_destroy(_client: *mut ffi::wl_client, resource: *mut ffi::wl_resource) {
-    ffi::wl_resource_destroy(resource);
 }
 
 struct CceToplevelData {
@@ -81,26 +30,31 @@ struct CceToplevelData {
     _resource: *mut ffi::wl_resource,
 }
 
-unsafe extern "C" fn wm_get_cce_toplevel(
+pub unsafe extern "C" fn cce_wm_get_cce_toplevel(
     client: *mut ffi::wl_client,
     resource: *mut ffi::wl_resource,
     id: u32,
     surface_resource: *mut ffi::wl_resource,
 ) {
-    let wm = ffi::wl_resource_get_user_data(resource) as *mut CceWindowManagement;
+    let wm = ffi::wl_resource_get_user_data(resource) as *mut crate::window_manager::WindowManager;
     if wm.is_null() {
         return;
     }
+    let server = (*wm).server;
+    if server.is_null() {
+        return;
+    }
+    let cce_wm = &mut (*server).cce_window_management as *mut CceWindowManagement;
 
     let surface = ffi::wlr_surface_from_resource(surface_resource);
     if surface.is_null() {
-        log::error!("wm_get_cce_toplevel: surface is null");
+        log::error!("cce_wm_get_cce_toplevel: surface is null");
         return;
     }
 
     // Find the Window corresponding to the surface
     let mut target_window = std::ptr::null_mut();
-    for &window in (*(*wm).server).wm.windows.iter() {
+    for &window in (*server).wm.windows.iter() {
         if !window.is_null() && (*window).root_surface() == surface {
             target_window = window;
             break;
@@ -108,7 +62,7 @@ unsafe extern "C" fn wm_get_cce_toplevel(
     }
 
     if target_window.is_null() {
-        log::error!("wm_get_cce_toplevel: no Window structure found for surface");
+        log::error!("cce_wm_get_cce_toplevel: no Window structure found for surface");
         return;
     }
 
@@ -120,7 +74,7 @@ unsafe extern "C" fn wm_get_cce_toplevel(
     }
 
     let data = Box::into_raw(Box::new(CceToplevelData {
-        server: (*wm).server,
+        server,
         window_key: (*target_window).ref_key,
         _resource: toplevel_res,
     }));
@@ -132,7 +86,7 @@ unsafe extern "C" fn wm_get_cce_toplevel(
         Some(handle_destroy_toplevel_resource),
     );
 
-    (*wm).toplevels.push(toplevel_res);
+    (*cce_wm).toplevels.push(toplevel_res);
 
     // Initial event: send current floating state
     let state = if (*target_window).tiling_mode == crate::tiling::TilingMode::Floating { 1 } else { 0 };
@@ -147,11 +101,6 @@ unsafe extern "C" fn handle_destroy_toplevel_resource(resource: *mut ffi::wl_res
     }
 }
 
-static CCE_WM_INTERFACE: ffi::zcce_window_manager_v1_interface = ffi::zcce_window_manager_v1_interface {
-    destroy: Some(wm_destroy),
-    get_cce_toplevel: Some(wm_get_cce_toplevel),
-};
-
 unsafe extern "C" fn toplevel_destroy(_client: *mut ffi::wl_client, resource: *mut ffi::wl_resource) {
     ffi::wl_resource_destroy(resource);
 }
diff --git a/src/server/output.rs b/src/server/output.rs
index 573e9f2..14e683f 100644
--- a/src/server/output.rs
+++ b/src/server/output.rs
@@ -142,7 +142,7 @@ pub struct Output {
     pub wlr_output: *mut ffi::wlr_output,
     pub scene_output: *mut ffi::wlr_scene_output,
     pub background_rect: *mut ffi::wlr_scene_rect,
-    pub object: *mut ffi::wl_resource, // river_output_v1 resource
+    pub object: *mut ffi::wl_resource, // zcce_output_v1 resource
     pub layer_shell: LayerShellOutput,
     pub lock_render_state: LockRenderState,
     pub link: ffi::wl_list,
@@ -188,28 +188,28 @@ unsafe extern "C" fn output_set_presentation_mode(
         return;
     }
     match mode {
-        ffi::river_output_v1_presentation_mode_RIVER_OUTPUT_V1_PRESENTATION_MODE_VSYNC => {
+        ffi::zcce_output_v1_presentation_mode_ZCCE_OUTPUT_V1_PRESENTATION_MODE_VSYNC => {
             (*output).rendering_requested.tearing = false;
         }
-        ffi::river_output_v1_presentation_mode_RIVER_OUTPUT_V1_PRESENTATION_MODE_ASYNC => {
+        ffi::zcce_output_v1_presentation_mode_ZCCE_OUTPUT_V1_PRESENTATION_MODE_ASYNC => {
             (*output).rendering_requested.tearing = true;
         }
         _ => {
             ffi::wl_resource_post_error(
                 resource,
-                ffi::river_output_v1_error_RIVER_OUTPUT_V1_ERROR_INVALID_PRESENTATION_MODE,
+                ffi::zcce_output_v1_error_ZCCE_OUTPUT_V1_ERROR_INVALID_PRESENTATION_MODE,
                 b"invalid presentation mode enum value\0".as_ptr() as *const _,
             );
         }
     }
 }
 
-static OUTPUT_INTERFACE: ffi::river_output_v1_interface = ffi::river_output_v1_interface {
+static OUTPUT_INTERFACE: ffi::zcce_output_v1_interface = ffi::zcce_output_v1_interface {
     destroy: Some(output_destroy),
     set_presentation_mode: Some(output_set_presentation_mode),
 };
 
-static INERT_OUTPUT_INTERFACE: ffi::river_output_v1_interface = ffi::river_output_v1_interface {
+static INERT_OUTPUT_INTERFACE: ffi::zcce_output_v1_interface = ffi::zcce_output_v1_interface {
     destroy: Some(output_destroy),
     set_presentation_mode: None,
 };
@@ -217,7 +217,7 @@ static INERT_OUTPUT_INTERFACE: ffi::river_output_v1_interface = ffi::river_outpu
 impl Output {
     pub unsafe fn make_inert(&mut self) {
         if !self.object.is_null() {
-            ffi::wl_resource_post_event(self.object, 0); // river_output.removed
+            ffi::wl_resource_post_event(self.object, 0); // zcce_output.removed
             ffi::wl_resource_set_implementation(
                 self.object,
                 &INERT_OUTPUT_INTERFACE as *const _ as *const _,
@@ -247,7 +247,7 @@ impl Output {
                         let client = ffi::wl_resource_get_client(wm_v1);
                         let res = ffi::wl_resource_create(
                             client,
-                            &ffi::river_output_v1_interface,
+                            &ffi::zcce_output_v1_interface,
                             ffi::wl_resource_get_version(wm_v1),
                             0,
                         );
@@ -262,7 +262,7 @@ impl Output {
                             self as *mut Output as *mut _,
                             Some(handle_destroy_resource),
                         );
-                        ffi::wl_resource_post_event(wm_v1, ffi::RIVER_WINDOW_MANAGER_V1_OUTPUT, res); // river_window_manager_v1.output
+                        ffi::wl_resource_post_event(wm_v1, ffi::ZCCE_WINDOW_MANAGER_V1_OUTPUT, res); // zcce_window_manager_v1.output
                         res
                     } else {
                         self.object
@@ -273,7 +273,7 @@ impl Output {
                         if !global.is_null() {
                             let client = ffi::wl_resource_get_client(output_v1);
                             let wl_output_name = ffi::wl_global_get_name(global, client);
-                            river_output_send_wl_output(output_v1, wl_output_name);
+                            zcce_output_send_wl_output(output_v1, wl_output_name);
                             self.sent_wl_output = true;
                         }
                     }
@@ -282,10 +282,10 @@ impl Output {
                     let (sent_width, sent_height) = self.sent.dimensions();
 
                     if new || scheduled_width != sent_width || scheduled_height != sent_height {
-                        river_output_send_dimensions(output_v1, scheduled_width, scheduled_height);
+                        zcce_output_send_dimensions(output_v1, scheduled_width, scheduled_height);
                     }
                     if new || self.scheduled.x != self.sent.x || self.scheduled.y != self.sent.y {
-                        river_output_send_position(output_v1, self.scheduled.x, self.scheduled.y);
+                        zcce_output_send_position(output_v1, self.scheduled.x, self.scheduled.y);
                     }
                 }
 
@@ -588,18 +588,18 @@ unsafe extern "C" fn handle_present(listener: *mut ffi::wl_listener, data: *mut
 }
 
 // Helpers for raw Wayland FFI protocol events
-pub unsafe fn river_output_send_removed(resource: *mut ffi::wl_resource) {
+pub unsafe fn zcce_output_send_removed(resource: *mut ffi::wl_resource) {
     ffi::wl_resource_post_event(resource, 0);
 }
 
-pub unsafe fn river_output_send_wl_output(resource: *mut ffi::wl_resource, name: u32) {
+pub unsafe fn zcce_output_send_wl_output(resource: *mut ffi::wl_resource, name: u32) {
     ffi::wl_resource_post_event(resource, 1, name);
 }
 
-pub unsafe fn river_output_send_position(resource: *mut ffi::wl_resource, x: i32, y: i32) {
+pub unsafe fn zcce_output_send_position(resource: *mut ffi::wl_resource, x: i32, y: i32) {
     ffi::wl_resource_post_event(resource, 2, x, y);
 }
 
-pub unsafe fn river_output_send_dimensions(resource: *mut ffi::wl_resource, width: i32, height: i32) {
+pub unsafe fn zcce_output_send_dimensions(resource: *mut ffi::wl_resource, width: i32, height: i32) {
     ffi::wl_resource_post_event(resource, 3, width, height);
 }
diff --git a/src/server/output_manager.rs b/src/server/output_manager.rs
index 043d76f..0e8f9a0 100644
--- a/src/server/output_manager.rs
+++ b/src/server/output_manager.rs
@@ -397,7 +397,7 @@ impl OutputManager {
                 if !global.is_null() {
                     if !output.object.is_null() {
                         let name = ffi::wl_global_get_name(global, ffi::wl_resource_get_client(output.object));
-                        crate::output::river_output_send_wl_output(output.object, name);
+                        crate::output::zcce_output_send_wl_output(output.object, name);
                         output.sent_wl_output = true;
                     }
                 }
diff --git a/src/server/pointer_binding.rs b/src/server/pointer_binding.rs
index 4d10910..64fee87 100644
--- a/src/server/pointer_binding.rs
+++ b/src/server/pointer_binding.rs
@@ -54,7 +54,7 @@ impl PointerBinding {
             link: std::mem::zeroed(),
         }));
 
-        let resource = ffi::wl_resource_create(client, &ffi::river_pointer_binding_v1_interface, version as i32, id);
+        let resource = ffi::wl_resource_create(client, &ffi::zcce_pointer_binding_v1_interface, version as i32, id);
         if resource.is_null() {
             let _ = Box::from_raw(binding_ptr);
             return Err("wl_resource_create failed");
@@ -72,7 +72,7 @@ impl PointerBinding {
         crate::server::wl_list_insert((*pointer_bindings_list).prev, &mut (*binding_ptr).link as *mut ffi::wl_list as *mut crate::server::WlList);
 
         log::debug!(
-            "new river_pointer_binding_v1: button: {} modifiers: {}",
+            "new zcce_pointer_binding_v1: button: {} modifiers: {}",
             button,
             modifiers
         );
@@ -124,7 +124,7 @@ unsafe extern "C" fn handle_binding_resource_destroy(resource: *mut ffi::wl_reso
     }
 }
 
-static POINTER_BINDING_INTERFACE: ffi::river_pointer_binding_v1_interface = ffi::river_pointer_binding_v1_interface {
+static POINTER_BINDING_INTERFACE: ffi::zcce_pointer_binding_v1_interface = ffi::zcce_pointer_binding_v1_interface {
     destroy: Some(pointer_binding_destroy),
     enable: Some(pointer_binding_enable),
     disable: Some(pointer_binding_disable),
diff --git a/src/server/seat.rs b/src/server/seat.rs
index 2a2acb5..4848264 100644
--- a/src/server/seat.rs
+++ b/src/server/seat.rs
@@ -562,9 +562,9 @@ impl Seat {
             if new {
                 let client = ffi::wl_resource_get_client(wm_v1);
                 let version = ffi::wl_resource_get_version(wm_v1);
-                let seat_v1 = ffi::wl_resource_create(client, &ffi::river_seat_v1_interface, version, 0);
+                let seat_v1 = ffi::wl_resource_create(client, &ffi::zcce_seat_v1_interface, version, 0);
                 if seat_v1.is_null() {
-                    log::error!("out of memory creating river_seat_v1");
+                    log::error!("out of memory creating zcce_seat_v1");
                     return;
                 }
                 self.object = seat_v1;
@@ -576,7 +576,7 @@ impl Seat {
                     Some(handle_destroy_resource),
                 );
                 
-                ffi::wl_resource_post_event(wm_v1, ffi::RIVER_WINDOW_MANAGER_V1_SEAT, seat_v1); // river_window_manager_v1.seat
+                ffi::wl_resource_post_event(wm_v1, ffi::ZCCE_WINDOW_MANAGER_V1_SEAT, seat_v1); // zcce_window_manager_v1.seat
 
                 crate::server::wl_list_remove(&mut self.link_sent as *mut ffi::wl_list as *mut crate::server::WlList);
                 let sent_seats = &mut (*self.server).wm.sent.seats as *mut ffi::wl_list as *mut crate::server::WlList;
@@ -1192,7 +1192,7 @@ unsafe extern "C" fn seat_pointer_warp(
     ffi::wlr_cursor_warp_absolute(cursor.wlr_cursor, std::ptr::null_mut(), x as f64, y as f64);
 }
 
-static SEAT_INTERFACE: ffi::river_seat_v1_interface = ffi::river_seat_v1_interface {
+static SEAT_INTERFACE: ffi::zcce_seat_v1_interface = ffi::zcce_seat_v1_interface {
     destroy: Some(seat_destroy),
     focus_window: Some(seat_focus_window),
     focus_shell_surface: Some(seat_focus_shell_surface),
@@ -1253,7 +1253,7 @@ unsafe extern "C" fn seat_inert_pointer_warp(
     _y: i32,
 ) {}
 
-static INERT_SEAT_INTERFACE: ffi::river_seat_v1_interface = ffi::river_seat_v1_interface {
+static INERT_SEAT_INTERFACE: ffi::zcce_seat_v1_interface = ffi::zcce_seat_v1_interface {
     destroy: Some(seat_destroy),
     focus_window: Some(seat_inert_focus_window),
     focus_shell_surface: Some(seat_inert_focus_shell_surface),
diff --git a/src/server/shell_surface.rs b/src/server/shell_surface.rs
index 1041dbf..2f2f5e4 100644
--- a/src/server/shell_surface.rs
+++ b/src/server/shell_surface.rs
@@ -13,7 +13,7 @@ pub struct ShellSurfaceRenderingRequested {
 
 pub struct ShellSurface {
     pub server: *mut Server,
-    pub object: *mut ffi::wl_resource, // river_shell_surface_v1
+    pub object: *mut ffi::wl_resource, // zcce_shell_surface_v1
     pub surface: *mut ffi::wlr_surface,
     pub tree: *mut ffi::wlr_scene_tree,
     pub surfaces: crate::scene::SaveableSurfaces,
@@ -30,9 +30,9 @@ impl ShellSurface {
         surface: *mut ffi::wlr_surface,
         server: *mut Server,
     ) -> Result<(), &'static str> {
-        log::debug!("new river_shell_surface_v1");
+        log::debug!("new zcce_shell_surface_v1");
 
-        let shell_surface_v1 = ffi::wl_resource_create(client, &ffi::river_shell_surface_v1_interface, version as i32, id);
+        let shell_surface_v1 = ffi::wl_resource_create(client, &ffi::zcce_shell_surface_v1_interface, version as i32, id);
         if shell_surface_v1.is_null() {
             ffi::wl_client_post_no_memory(client);
             return Err("wl_resource_create failed");
@@ -42,7 +42,7 @@ impl ShellSurface {
             surface,
             &SHELL_SURFACE_ROLE,
             shell_surface_v1,
-            ffi::river_window_manager_v1_error_RIVER_WINDOW_MANAGER_V1_ERROR_ROLE,
+            ffi::zcce_window_manager_v1_error_ZCCE_WINDOW_MANAGER_V1_ERROR_ROLE,
         ) {
             return Err("wlr_surface_set_role failed");
         }
@@ -129,7 +129,7 @@ impl ShellSurface {
             if !self.surfaces.saved {
                 ffi::wl_resource_post_error(
                     self.object,
-                    ffi::river_shell_surface_v1_error_RIVER_SHELL_SURFACE_V1_ERROR_NO_COMMIT,
+                    ffi::zcce_shell_surface_v1_error_ZCCE_SHELL_SURFACE_V1_ERROR_NO_COMMIT,
                     b"no wl_surface.commit after sync_next_commit and before update_rendering_finish\0".as_ptr() as *const _,
                 );
             }
@@ -241,7 +241,7 @@ unsafe extern "C" fn shell_surface_get_node(
     if !(*shell_surface).node.object.is_null() {
         ffi::wl_resource_post_error(
             resource,
-            ffi::river_shell_surface_v1_error_RIVER_SHELL_SURFACE_V1_ERROR_NODE_EXISTS,
+            ffi::zcce_shell_surface_v1_error_ZCCE_SHELL_SURFACE_V1_ERROR_NODE_EXISTS,
             b"shell surface already has a node object\0".as_ptr() as *const _,
         );
         return;
@@ -271,7 +271,7 @@ unsafe extern "C" fn shell_surface_sync_next_commit(
     (*shell_surface).rendering_requested.sync_next_commit = true;
 }
 
-static SHELL_SURFACE_INTERFACE: ffi::river_shell_surface_v1_interface = ffi::river_shell_surface_v1_interface {
+static SHELL_SURFACE_INTERFACE: ffi::zcce_shell_surface_v1_interface = ffi::zcce_shell_surface_v1_interface {
     destroy: Some(shell_surface_destroy),
     get_node: Some(shell_surface_get_node),
     sync_next_commit: Some(shell_surface_sync_next_commit),
@@ -279,7 +279,7 @@ static SHELL_SURFACE_INTERFACE: ffi::river_shell_surface_v1_interface = ffi::riv
 
 #[no_mangle]
 pub static mut SHELL_SURFACE_ROLE: ffi::wlr_surface_role = ffi::wlr_surface_role {
-    name: b"river_shell_surface_v1\0".as_ptr() as *const _,
+    name: b"zcce_shell_surface_v1\0".as_ptr() as *const _,
     no_object: false,
     client_commit: Some(client_commit),
     commit: Some(commit),
diff --git a/src/server/window.rs b/src/server/window.rs
index fe5f98d..8417584 100644
--- a/src/server/window.rs
+++ b/src/server/window.rs
@@ -101,7 +101,7 @@ pub struct PointerResizeRequest {
 
 pub struct WmScheduledState {
     pub dimensions_hint: DimensionsHint,
-    pub decoration_hint: ffi::river_window_v1_decoration_hint,
+    pub decoration_hint: ffi::zcce_window_v1_decoration_hint,
     pub show_window_menu_requested: Option<ShowWindowMenuRequest>,
     pub fullscreen_requested: FullscreenRequest,
     pub maximize_requested: MaximizeRequest,
@@ -114,7 +114,7 @@ pub struct WmScheduledState {
 
 pub struct WmSentState {
     pub dimensions_hint: DimensionsHint,
-    pub decoration_hint: ffi::river_window_v1_decoration_hint,
+    pub decoration_hint: ffi::zcce_window_v1_decoration_hint,
     pub parent: Option<crate::slotmap::Key>,
 }
 
@@ -171,7 +171,7 @@ pub struct WindowRenderingScheduled {
 pub struct WindowRenderingSent {
     pub width: u32,
     pub height: u32,
-    pub presentation_hint: ffi::river_output_v1_presentation_mode,
+    pub presentation_hint: ffi::zcce_output_v1_presentation_mode,
 }
 
 pub struct WindowRenderingRequested {
@@ -189,7 +189,7 @@ pub struct WindowRenderingRequested {
 pub struct Window {
     pub ref_key: crate::slotmap::Key,
     pub server: *mut Server,
-    pub object: *mut ffi::wl_resource, // river_window_v1
+    pub object: *mut ffi::wl_resource, // zcce_window_v1
     pub node: WmNode,
     pub state: WindowState,
     pub impl_type: WindowImpl,
@@ -342,7 +342,7 @@ impl Window {
             commit: std::mem::zeroed(),
             wm_scheduled: WmScheduledState {
                 dimensions_hint: DimensionsHint { min_width: 0, min_height: 0, max_width: 0, max_height: 0 },
-                decoration_hint: ffi::river_window_v1_decoration_hint_RIVER_WINDOW_V1_DECORATION_HINT_ONLY_SUPPORTS_CSD,
+                decoration_hint: ffi::zcce_window_v1_decoration_hint_ZCCE_WINDOW_V1_DECORATION_HINT_ONLY_SUPPORTS_CSD,
                 show_window_menu_requested: None,
                 fullscreen_requested: FullscreenRequest::NoRequest,
                 maximize_requested: MaximizeRequest::NoRequest,
@@ -354,7 +354,7 @@ impl Window {
             },
             wm_sent: WmSentState {
                 dimensions_hint: DimensionsHint { min_width: 0, min_height: 0, max_width: 0, max_height: 0 },
-                decoration_hint: ffi::river_window_v1_decoration_hint_RIVER_WINDOW_V1_DECORATION_HINT_ONLY_SUPPORTS_CSD,
+                decoration_hint: ffi::zcce_window_v1_decoration_hint_ZCCE_WINDOW_V1_DECORATION_HINT_ONLY_SUPPORTS_CSD,
                 parent: None,
             },
             wm_requested: WmRequestedState {
@@ -379,7 +379,7 @@ impl Window {
             rendering_sent: WindowRenderingSent {
                 width: 0,
                 height: 0,
-                presentation_hint: ffi::river_output_v1_presentation_mode_RIVER_OUTPUT_V1_PRESENTATION_MODE_VSYNC,
+                presentation_hint: ffi::zcce_output_v1_presentation_mode_ZCCE_OUTPUT_V1_PRESENTATION_MODE_VSYNC,
             },
             rendering_requested: WindowRenderingRequested {
                 x: 0,
@@ -715,7 +715,7 @@ impl Window {
         }
     }
 
-    pub unsafe fn set_decoration_hint(&mut self, hint: ffi::river_window_v1_decoration_hint) {
+    pub unsafe fn set_decoration_hint(&mut self, hint: ffi::zcce_window_v1_decoration_hint) {
         self.wm_scheduled.decoration_hint = hint;
         if hint != self.wm_sent.decoration_hint {
             (*self.server).wm.dirty_windowing();
@@ -790,7 +790,7 @@ impl Window {
                 self.state = WindowState::Init;
                 self.wm_sent = WmSentState {
                     dimensions_hint: DimensionsHint { min_width: 0, min_height: 0, max_width: 0, max_height: 0 },
-                    decoration_hint: ffi::river_window_v1_decoration_hint_RIVER_WINDOW_V1_DECORATION_HINT_ONLY_SUPPORTS_CSD,
+                    decoration_hint: ffi::zcce_window_v1_decoration_hint_ZCCE_WINDOW_V1_DECORATION_HINT_ONLY_SUPPORTS_CSD,
                     parent: None,
                 };
                 self.wm_requested = WmRequestedState {
@@ -808,7 +808,7 @@ impl Window {
                 self.rendering_sent = WindowRenderingSent {
                     width: 0,
                     height: 0,
-                    presentation_hint: ffi::river_output_v1_presentation_mode_RIVER_OUTPUT_V1_PRESENTATION_MODE_VSYNC,
+                    presentation_hint: ffi::zcce_output_v1_presentation_mode_ZCCE_OUTPUT_V1_PRESENTATION_MODE_VSYNC,
                 };
                 self.rendering_requested = WindowRenderingRequested {
                     x: 0,
@@ -874,7 +874,7 @@ impl Window {
                 let new_resource = self.object.is_null();
                 let window_v1 = if new_resource {
                     let client = ffi::wl_resource_get_client(wm_v1);
-                    let res = ffi::wl_resource_create(client, &ffi::river_window_v1_interface, ffi::wl_resource_get_version(wm_v1), 0);
+                    let res = ffi::wl_resource_create(client, &ffi::zcce_window_v1_interface, ffi::wl_resource_get_version(wm_v1), 0);
                     if res.is_null() {
                         log::error!("out of memory");
                         return;
@@ -889,7 +889,7 @@ impl Window {
                     );
                     
                     // Send window to manager
-                    ffi::wl_resource_post_event(wm_v1, ffi::RIVER_WINDOW_MANAGER_V1_WINDOW, res); // river_window_manager_v1.window
+                    ffi::wl_resource_post_event(wm_v1, ffi::ZCCE_WINDOW_MANAGER_V1_WINDOW, res); // zcce_window_manager_v1.window
 
                     wl_list_remove(&mut self.node.link as *mut ffi::wl_list as *mut WlList);
                     let rendering_list = &mut (*self.server).wm.rendering_requested.list as *mut ffi::wl_list as *mut WlList;
@@ -934,12 +934,12 @@ impl Window {
                 if new_resource {
                     let version = ffi::wl_resource_get_version(window_v1);
                     if version >= 2 {
-                        ffi::wl_resource_post_event(window_v1, ffi::RIVER_WINDOW_V1_UNRELIABLE_PID, self.unreliable_pid()); // sendUnreliablePid
+                        ffi::wl_resource_post_event(window_v1, ffi::ZCCE_WINDOW_V1_UNRELIABLE_PID, self.unreliable_pid()); // sendUnreliablePid
                     }
                     if version >= 4 {
                         if !self.foreign_toplevel_handle.is_null() {
                             let identifier = (*self.foreign_toplevel_handle).identifier;
-                            ffi::wl_resource_post_event(window_v1, ffi::RIVER_WINDOW_V1_IDENTIFIER, identifier);
+                            ffi::wl_resource_post_event(window_v1, ffi::ZCCE_WINDOW_V1_IDENTIFIER, identifier);
                         }
                     }
                 }
@@ -947,7 +947,7 @@ impl Window {
                 if new_resource || self.wm_scheduled.dimensions_hint != self.wm_sent.dimensions_hint {
                     ffi::wl_resource_post_event(
                         window_v1,
-                        ffi::RIVER_WINDOW_V1_DIMENSIONS_HINT, // sendDimensionsHint
+                        ffi::ZCCE_WINDOW_V1_DIMENSIONS_HINT, // sendDimensionsHint
                         self.wm_scheduled.dimensions_hint.min_width as i32,
                         self.wm_scheduled.dimensions_hint.min_height as i32,
                         self.wm_scheduled.dimensions_hint.max_width as i32,
@@ -957,12 +957,12 @@ impl Window {
                 }
 
                 if new_resource || self.wm_scheduled.decoration_hint != self.wm_sent.decoration_hint {
-                    ffi::wl_resource_post_event(window_v1, ffi::RIVER_WINDOW_V1_DECORATION_HINT, self.wm_scheduled.decoration_hint); // sendDecorationHint
+                    ffi::wl_resource_post_event(window_v1, ffi::ZCCE_WINDOW_V1_DECORATION_HINT, self.wm_scheduled.decoration_hint); // sendDecorationHint
                     self.wm_sent.decoration_hint = self.wm_scheduled.decoration_hint;
                 }
 
                 if let Some(ref offset) = self.wm_scheduled.show_window_menu_requested {
-                    ffi::wl_resource_post_event(window_v1, ffi::RIVER_WINDOW_V1_SHOW_WINDOW_MENU_REQUESTED, offset.x, offset.y); // sendShowWindowMenuRequested
+                    ffi::wl_resource_post_event(window_v1, ffi::ZCCE_WINDOW_V1_SHOW_WINDOW_MENU_REQUESTED, offset.x, offset.y); // sendShowWindowMenuRequested
                     self.wm_scheduled.show_window_menu_requested = None;
                 }
 
@@ -982,10 +982,10 @@ impl Window {
                                 out_resource = std::ptr::null_mut();
                             }
                         }
-                        ffi::wl_resource_post_event(window_v1, ffi::RIVER_WINDOW_V1_FULLSCREEN_REQUESTED, out_resource); // sendFullscreenRequested
+                        ffi::wl_resource_post_event(window_v1, ffi::ZCCE_WINDOW_V1_FULLSCREEN_REQUESTED, out_resource); // sendFullscreenRequested
                     }
                     FullscreenRequest::Exit => {
-                        ffi::wl_resource_post_event(window_v1, ffi::RIVER_WINDOW_V1_EXIT_FULLSCREEN_REQUESTED); // sendExitFullscreenRequested
+                        ffi::wl_resource_post_event(window_v1, ffi::ZCCE_WINDOW_V1_EXIT_FULLSCREEN_REQUESTED); // sendExitFullscreenRequested
                     }
                 }
                 self.wm_scheduled.fullscreen_requested = FullscreenRequest::NoRequest;
@@ -993,16 +993,16 @@ impl Window {
                 match self.wm_scheduled.maximize_requested {
                     MaximizeRequest::NoRequest => {}
                     MaximizeRequest::Maximize => {
-                        ffi::wl_resource_post_event(window_v1, ffi::RIVER_WINDOW_V1_MAXIMIZE_REQUESTED); // sendMaximizeRequested
+                        ffi::wl_resource_post_event(window_v1, ffi::ZCCE_WINDOW_V1_MAXIMIZE_REQUESTED); // sendMaximizeRequested
                     }
                     MaximizeRequest::Unmaximize => {
-                        ffi::wl_resource_post_event(window_v1, ffi::RIVER_WINDOW_V1_UNMAXIMIZE_REQUESTED); // sendUnmaximizeRequested
+                        ffi::wl_resource_post_event(window_v1, ffi::ZCCE_WINDOW_V1_UNMAXIMIZE_REQUESTED); // sendUnmaximizeRequested
                     }
                 }
                 self.wm_scheduled.maximize_requested = MaximizeRequest::NoRequest;
 
                 if self.wm_scheduled.minimize_requested {
-                    ffi::wl_resource_post_event(window_v1, ffi::RIVER_WINDOW_V1_MINIMIZE_REQUESTED); // sendMinimizeRequested
+                    ffi::wl_resource_post_event(window_v1, ffi::ZCCE_WINDOW_V1_MINIMIZE_REQUESTED); // sendMinimizeRequested
                 }
                 self.wm_scheduled.minimize_requested = false;
 
@@ -1011,29 +1011,29 @@ impl Window {
                     let parent_ref = Some((*parent).ref_key);
                     if self.wm_sent.parent.is_none() || self.wm_sent.parent != parent_ref {
                         let parent_obj = (*parent).object;
-                        ffi::wl_resource_post_event(window_v1, ffi::RIVER_WINDOW_V1_PARENT, parent_obj); // sendParent
+                        ffi::wl_resource_post_event(window_v1, ffi::ZCCE_WINDOW_V1_PARENT, parent_obj); // sendParent
                         self.wm_sent.parent = parent_ref;
                     }
                 } else if self.wm_sent.parent.is_some() {
-                    ffi::wl_resource_post_event(window_v1, ffi::RIVER_WINDOW_V1_PARENT, std::ptr::null_mut::<ffi::wl_resource>()); // sendParent
+                    ffi::wl_resource_post_event(window_v1, ffi::ZCCE_WINDOW_V1_PARENT, std::ptr::null_mut::<ffi::wl_resource>()); // sendParent
                     self.wm_sent.parent = None;
                 }
 
                 if new_resource || self.wm_scheduled.dirty_app_id {
                     let app_id = self.get_app_id();
-                    ffi::wl_resource_post_event(window_v1, ffi::RIVER_WINDOW_V1_APP_ID, app_id); // sendAppId
+                    ffi::wl_resource_post_event(window_v1, ffi::ZCCE_WINDOW_V1_APP_ID, app_id); // sendAppId
                     self.wm_scheduled.dirty_app_id = false;
                 }
 
                 if new_resource || self.wm_scheduled.dirty_title {
                     let title = self.get_title();
-                    ffi::wl_resource_post_event(window_v1, ffi::RIVER_WINDOW_V1_TITLE, title); // sendTitle
+                    ffi::wl_resource_post_event(window_v1, ffi::ZCCE_WINDOW_V1_TITLE, title); // sendTitle
                     self.wm_scheduled.dirty_title = false;
                 }
 
                 if let Some(seat) = self.wm_scheduled.pointer_move_requested.as_mut() {
                     if !seat.object.is_null() {
-                        ffi::wl_resource_post_event(window_v1, ffi::RIVER_WINDOW_V1_POINTER_MOVE_REQUESTED, seat.object); // sendPointerMoveRequested
+                        ffi::wl_resource_post_event(window_v1, ffi::ZCCE_WINDOW_V1_POINTER_MOVE_REQUESTED, seat.object); // sendPointerMoveRequested
                     }
                 }
                 self.wm_scheduled.pointer_move_requested = std::ptr::null_mut();
@@ -1041,7 +1041,7 @@ impl Window {
                 if let Some(ref data) = self.wm_scheduled.pointer_resize_requested {
                     if let Some(seat) = unsafe { data.seat.as_ref() } {
                         if !seat.object.is_null() {
-                            ffi::wl_resource_post_event(window_v1, ffi::RIVER_WINDOW_V1_POINTER_RESIZE_REQUESTED, seat.object, data.edges); // sendPointerResizeRequested
+                            ffi::wl_resource_post_event(window_v1, ffi::ZCCE_WINDOW_V1_POINTER_RESIZE_REQUESTED, seat.object, data.edges); // sendPointerResizeRequested
                         }
                     }
                 }
@@ -1052,7 +1052,7 @@ impl Window {
 
     pub unsafe fn make_inert(&mut self) {
         if !self.object.is_null() {
-            ffi::wl_resource_post_event(self.object, ffi::RIVER_WINDOW_V1_CLOSED); // sendClosed
+            ffi::wl_resource_post_event(self.object, ffi::ZCCE_WINDOW_V1_CLOSED); // sendClosed // sendClosed
             ffi::wl_resource_set_implementation(
                 self.object,
                 &INERT_WINDOW_INTERFACE as *const _ as *const _,
@@ -1241,7 +1241,7 @@ impl Window {
            (scheduled.resend_dimensions ||
             scheduled.width != sent.width || scheduled.height != sent.height) {
             if !self.object.is_null() {
-                ffi::wl_resource_post_event(self.object, ffi::RIVER_WINDOW_V1_DIMENSIONS, scheduled.width as i32, scheduled.height as i32); // sendDimensions
+                ffi::wl_resource_post_event(self.object, ffi::ZCCE_WINDOW_V1_DIMENSIONS, scheduled.width as i32, scheduled.height as i32); // sendDimensions
                 scheduled.resend_dimensions = false;
             }
         }
@@ -1251,17 +1251,17 @@ impl Window {
             if !self.object.is_null() {
                 let version = ffi::wl_resource_get_version(self.object);
                 if version >= 4 {
-                    ffi::wl_resource_post_event(self.object, ffi::RIVER_WINDOW_V1_PRESENTATION_HINT, presentation_hint); // sendPresentationHint
+                    ffi::wl_resource_post_event(self.object, ffi::ZCCE_WINDOW_V1_PRESENTATION_HINT, presentation_hint); // sendPresentationHint
                 }
             }
             sent.presentation_hint = presentation_hint;
         }
     }
 
-    pub unsafe fn presentation_hint(&self) -> ffi::river_output_v1_presentation_mode {
+    pub unsafe fn presentation_hint(&self) -> ffi::zcce_output_v1_presentation_mode {
         let root = self.root_surface();
         if root.is_null() {
-            return ffi::river_output_v1_presentation_mode_RIVER_OUTPUT_V1_PRESENTATION_MODE_VSYNC;
+            return ffi::zcce_output_v1_presentation_mode_ZCCE_OUTPUT_V1_PRESENTATION_MODE_VSYNC;
         }
         
         // tearing control check stub:
@@ -1270,7 +1270,7 @@ impl Window {
         //     .vsync => .vsync,
         // }
         // For now, return VSYNC by default.
-        ffi::river_output_v1_presentation_mode_RIVER_OUTPUT_V1_PRESENTATION_MODE_VSYNC
+        ffi::zcce_output_v1_presentation_mode_ZCCE_OUTPUT_V1_PRESENTATION_MODE_VSYNC
     }
 
     pub unsafe fn notify_title(&mut self) {
@@ -1737,7 +1737,7 @@ unsafe extern "C" fn window_get_node(
     if !(*window).node.object.is_null() {
         ffi::wl_resource_post_error(
             resource,
-            ffi::river_window_v1_error_RIVER_WINDOW_V1_ERROR_NODE_EXISTS,
+            ffi::zcce_window_v1_error_ZCCE_WINDOW_V1_ERROR_NODE_EXISTS,
             b"window already has a node object\0".as_ptr() as *const _,
         );
         return;
@@ -1762,7 +1762,7 @@ unsafe extern "C" fn window_propose_dimensions(
     if width < 0 || height < 0 {
         ffi::wl_resource_post_error(
             resource,
-            ffi::river_window_v1_error_RIVER_WINDOW_V1_ERROR_INVALID_DIMENSIONS,
+            ffi::zcce_window_v1_error_ZCCE_WINDOW_V1_ERROR_INVALID_DIMENSIONS,
             b"dimensions must be greater than or equal to 0\0".as_ptr() as *const _,
         );
         return;
@@ -1846,7 +1846,7 @@ unsafe extern "C" fn window_set_borders(
     if width < 0 {
         ffi::wl_resource_post_error(
             resource,
-            ffi::river_window_v1_error_RIVER_WINDOW_V1_ERROR_INVALID_BORDER,
+            ffi::zcce_window_v1_error_ZCCE_WINDOW_V1_ERROR_INVALID_BORDER,
             b"border width must be greater than or equal to 0\0".as_ptr() as *const _,
         );
         return;
@@ -2103,7 +2103,7 @@ unsafe extern "C" fn window_set_clip_box(
     if width < 0 || height < 0 {
         ffi::wl_resource_post_error(
             resource,
-            ffi::river_window_v1_error_RIVER_WINDOW_V1_ERROR_INVALID_CLIP_BOX,
+            ffi::zcce_window_v1_error_ZCCE_WINDOW_V1_ERROR_INVALID_CLIP_BOX,
             b"width/height must be greater than or equal to 0\0".as_ptr() as *const _,
         );
         return;
@@ -2135,7 +2135,7 @@ unsafe extern "C" fn window_set_content_clip_box(
     if width < 0 || height < 0 {
         ffi::wl_resource_post_error(
             resource,
-            ffi::river_window_v1_error_RIVER_WINDOW_V1_ERROR_INVALID_CLIP_BOX,
+            ffi::zcce_window_v1_error_ZCCE_WINDOW_V1_ERROR_INVALID_CLIP_BOX,
             b"width/height must be greater than or equal to 0\0".as_ptr() as *const _,
         );
         return;
@@ -2165,7 +2165,7 @@ unsafe extern "C" fn window_set_dimension_bounds(
     if max_width < 0 || max_height < 0 {
         ffi::wl_resource_post_error(
             resource,
-            ffi::river_window_v1_error_RIVER_WINDOW_V1_ERROR_INVALID_DIMENSIONS,
+            ffi::zcce_window_v1_error_ZCCE_WINDOW_V1_ERROR_INVALID_DIMENSIONS,
             b"dimensions must be greater than or equal to 0\0".as_ptr() as *const _,
         );
         return;
@@ -2225,8 +2225,8 @@ unsafe extern "C" fn window_set_blur(
     (*window).rendering_requested.blur = blur != 0;
 }
 
-// river_window_v1 implementation
-static WINDOW_INTERFACE: ffi::river_window_v1_interface = ffi::river_window_v1_interface {
+// zcce_window_v1 implementation
+static WINDOW_INTERFACE: ffi::zcce_window_v1_interface = ffi::zcce_window_v1_interface {
     destroy: Some(window_destroy),
     close: Some(window_close),
     get_node: Some(window_get_node),
@@ -2256,7 +2256,7 @@ static WINDOW_INTERFACE: ffi::river_window_v1_interface = ffi::river_window_v1_i
     set_blur: Some(window_set_blur),
 };
 
-static INERT_WINDOW_INTERFACE: ffi::river_window_v1_interface = ffi::river_window_v1_interface {
+static INERT_WINDOW_INTERFACE: ffi::zcce_window_v1_interface = ffi::zcce_window_v1_interface {
     destroy: Some(window_destroy),
     close: None,
     get_node: None,
@@ -2308,7 +2308,7 @@ unsafe extern "C" fn handle_destroy_resource(resource: *mut ffi::wl_resource) {
     }
 }
 
-// river_decoration_v1 implementation
+// zcce_decoration_v1 implementation
 pub struct DecorationRenderingRequested {
     pub offset_x: i32,
     pub offset_y: i32,
@@ -2317,7 +2317,7 @@ pub struct DecorationRenderingRequested {
 }
 
 pub struct Decoration {
-    pub object: *mut ffi::wl_resource, // river_decoration_v1
+    pub object: *mut ffi::wl_resource, // zcce_decoration_v1
     pub surface: *mut ffi::wlr_surface,
     pub tree: *mut ffi::wlr_scene_tree,
     pub surfaces: crate::scene::SaveableSurfaces,
@@ -2335,7 +2335,7 @@ impl Decoration {
         parent: *mut ffi::wlr_scene_tree,
         window: *mut Window,
     ) -> Result<*mut Self, &'static str> {
-        let decoration_v1 = ffi::wl_resource_create(client, &ffi::river_decoration_v1_interface, version as i32, id);
+        let decoration_v1 = ffi::wl_resource_create(client, &ffi::zcce_decoration_v1_interface, version as i32, id);
         if decoration_v1.is_null() {
             ffi::wl_client_post_no_memory(client);
             return Err("wl_resource_create failed");
@@ -2345,7 +2345,7 @@ impl Decoration {
             surface,
             &DECORATION_ROLE,
             decoration_v1,
-            ffi::river_window_manager_v1_error_RIVER_WINDOW_MANAGER_V1_ERROR_ROLE,
+            ffi::zcce_window_manager_v1_error_ZCCE_WINDOW_MANAGER_V1_ERROR_ROLE,
         ) {
             return Err("wlr_surface_set_role failed");
         }
@@ -2420,7 +2420,7 @@ impl Decoration {
                 if !self.object.is_null() {
                     ffi::wl_resource_post_error(
                         self.object,
-                        ffi::river_decoration_v1_error_RIVER_DECORATION_V1_ERROR_NO_COMMIT,
+                        ffi::zcce_decoration_v1_error_ZCCE_DECORATION_V1_ERROR_NO_COMMIT,
                         b"no wl_surface.commit after sync_next_commit and before update_rendering_finish\0".as_ptr() as *const _,
                     );
                 }
@@ -2571,14 +2571,14 @@ unsafe extern "C" fn dec_set_blur(
     (*dec).rendering_requested.blur = blur != 0;
 }
 
-static DECORATION_INTERFACE: ffi::river_decoration_v1_interface = ffi::river_decoration_v1_interface {
+static DECORATION_INTERFACE: ffi::zcce_decoration_v1_interface = ffi::zcce_decoration_v1_interface {
     destroy: Some(dec_destroy),
     set_offset: Some(dec_set_offset),
     sync_next_commit: Some(dec_sync_next_commit),
     set_blur: Some(dec_set_blur),
 };
 
-static INERT_DECORATION_INTERFACE: ffi::river_decoration_v1_interface = ffi::river_decoration_v1_interface {
+static INERT_DECORATION_INTERFACE: ffi::zcce_decoration_v1_interface = ffi::zcce_decoration_v1_interface {
     destroy: Some(dec_destroy),
     set_offset: None,
     sync_next_commit: None,
@@ -2610,7 +2610,7 @@ unsafe extern "C" fn dec_role_destroy(surface: *mut ffi::wlr_surface) {
 
 #[no_mangle]
 pub static mut DECORATION_ROLE: ffi::wlr_surface_role = ffi::wlr_surface_role {
-    name: b"river_decoration_v1\0".as_ptr() as *const _,
+    name: b"zcce_decoration_v1\0".as_ptr() as *const _,
     no_object: false,
     client_commit: Some(dec_client_commit),
     commit: Some(dec_commit),
diff --git a/src/server/window_manager.rs b/src/server/window_manager.rs
index c49d87a..f33e1a8 100644
--- a/src/server/window_manager.rs
+++ b/src/server/window_manager.rs
@@ -150,14 +150,14 @@ impl WindowManager {
 
         self.global = ffi::wl_global_create(
             (*server).wl_server,
-            &ffi::river_window_manager_v1_interface,
+            &ffi::zcce_window_manager_v1_interface,
             4,
             self as *mut WindowManager as *mut _,
             Some(bind),
         );
         if self.global.is_null() {
             ffi::wl_event_source_remove(self.timeout);
-            return Err("Failed to create river_window_manager_v1 global");
+            return Err("Failed to create zcce_window_manager_v1 global");
         }
 
         let server_destroy_ptr = &mut self.server_destroy as *mut ffi::wl_listener as *mut WlListener;
@@ -193,7 +193,7 @@ impl WindowManager {
                 if !self.object.is_null() {
                     ffi::wl_resource_post_error(
                         self.object,
-                        ffi::river_window_manager_v1_error_RIVER_WINDOW_MANAGER_V1_ERROR_SEQUENCE_ORDER,
+                        ffi::zcce_window_manager_v1_error_ZCCE_WINDOW_MANAGER_V1_ERROR_SEQUENCE_ORDER,
                         b"invalid modification of window management state\0".as_ptr() as *const _,
                     );
                 }
@@ -209,7 +209,7 @@ impl WindowManager {
                 if !self.object.is_null() {
                     ffi::wl_resource_post_error(
                         self.object,
-                        ffi::river_window_manager_v1_error_RIVER_WINDOW_MANAGER_V1_ERROR_SEQUENCE_ORDER,
+                        ffi::zcce_window_manager_v1_error_ZCCE_WINDOW_MANAGER_V1_ERROR_SEQUENCE_ORDER,
                         b"invalid modification of rendering state\0".as_ptr() as *const _,
                     );
                 }
@@ -279,9 +279,9 @@ impl WindowManager {
         if session_locked != self.sent.session_locked {
             if !self.object.is_null() {
                 if session_locked {
-                    ffi::wl_resource_post_event(self.object, ffi::RIVER_WINDOW_MANAGER_V1_SESSION_LOCKED);
+                    ffi::wl_resource_post_event(self.object, ffi::ZCCE_WINDOW_MANAGER_V1_SESSION_LOCKED);
                 } else {
-                    ffi::wl_resource_post_event(self.object, ffi::RIVER_WINDOW_MANAGER_V1_SESSION_UNLOCKED);
+                    ffi::wl_resource_post_event(self.object, ffi::ZCCE_WINDOW_MANAGER_V1_SESSION_UNLOCKED);
                 }
             }
             self.sent.session_locked = session_locked;
@@ -323,7 +323,7 @@ impl WindowManager {
         self.arrange_views();
 
         if !self.object.is_null() {
-            ffi::wl_resource_post_event(self.object, ffi::RIVER_WINDOW_MANAGER_V1_MANAGE_START);
+            ffi::wl_resource_post_event(self.object, ffi::ZCCE_WINDOW_MANAGER_V1_MANAGE_START);
             self.start_timeout_timer(3000);
         } else {
             self.manage_finish();
@@ -420,7 +420,7 @@ impl WindowManager {
         }
 
         if !self.object.is_null() {
-            ffi::wl_resource_post_event(self.object, ffi::RIVER_WINDOW_MANAGER_V1_RENDER_START);
+            ffi::wl_resource_post_event(self.object, ffi::ZCCE_WINDOW_MANAGER_V1_RENDER_START);
             self.start_timeout_timer(3000);
         } else {
             self.render_finish();
@@ -1969,7 +1969,7 @@ unsafe extern "C" fn handle_timeout(data: *mut std::ffi::c_void) -> std::os::raw
                 log::error!("window manager unresponsive for more than 3 seconds, disconnecting");
                 ffi::wl_resource_post_error(
                     (*wm).object,
-                    ffi::river_window_manager_v1_error_RIVER_WINDOW_MANAGER_V1_ERROR_UNRESPONSIVE,
+                    ffi::zcce_window_manager_v1_error_ZCCE_WINDOW_MANAGER_V1_ERROR_UNRESPONSIVE,
                     b"unresponsive for more than 3 seconds\0".as_ptr() as *const _,
                 );
                 let client = ffi::wl_resource_get_client((*wm).object);
@@ -1994,7 +1994,7 @@ unsafe extern "C" fn wm_stop(client: *mut ffi::wl_client, resource: *mut ffi::wl
     let wm = ffi::wl_resource_get_user_data(resource) as *mut WindowManager;
     if !wm.is_null() {
         (*wm).object = std::ptr::null_mut();
-        ffi::wl_resource_post_event(resource, ffi::RIVER_WINDOW_MANAGER_V1_FINISHED);
+        ffi::wl_resource_post_event(resource, ffi::ZCCE_WINDOW_MANAGER_V1_FINISHED);
         ffi::wl_resource_set_implementation(
             resource,
             &INERT_WM_INTERFACE as *const _ as *const _,
@@ -2016,7 +2016,7 @@ unsafe extern "C" fn wm_manage_finish(client: *mut ffi::wl_client, resource: *mu
     if !matches!((*wm).state, WindowManagerState::Manage) {
         ffi::wl_resource_post_error(
             resource,
-            ffi::river_window_manager_v1_error_RIVER_WINDOW_MANAGER_V1_ERROR_SEQUENCE_ORDER,
+            ffi::zcce_window_manager_v1_error_ZCCE_WINDOW_MANAGER_V1_ERROR_SEQUENCE_ORDER,
             b"manage_finish request does not match manage_start\0".as_ptr() as *const _,
         );
         return;
@@ -2041,7 +2041,7 @@ unsafe extern "C" fn wm_render_finish(client: *mut ffi::wl_client, resource: *mu
     if !matches!((*wm).state, WindowManagerState::Render) {
         ffi::wl_resource_post_error(
             resource,
-            ffi::river_window_manager_v1_error_RIVER_WINDOW_MANAGER_V1_ERROR_SEQUENCE_ORDER,
+            ffi::zcce_window_manager_v1_error_ZCCE_WINDOW_MANAGER_V1_ERROR_SEQUENCE_ORDER,
             b"render_finish request does not match render_start\0".as_ptr() as *const _,
         );
         return;
@@ -2076,7 +2076,7 @@ unsafe extern "C" fn wm_exit_session(client: *mut ffi::wl_client, resource: *mut
     ffi::wl_display_terminate((*(*wm).server).wl_server);
 }
 
-static WM_INTERFACE: ffi::river_window_manager_v1_interface = ffi::river_window_manager_v1_interface {
+static WM_INTERFACE: ffi::zcce_window_manager_v1_interface = ffi::zcce_window_manager_v1_interface {
     stop: Some(wm_stop),
     destroy: Some(wm_destroy),
     manage_finish: Some(wm_manage_finish),
@@ -2084,9 +2084,10 @@ static WM_INTERFACE: ffi::river_window_manager_v1_interface = ffi::river_window_
     render_finish: Some(wm_render_finish),
     get_shell_surface: Some(wm_get_shell_surface),
     exit_session: Some(wm_exit_session),
+    get_cce_toplevel: Some(crate::cce_window_management::cce_wm_get_cce_toplevel),
 };
 
-static INERT_WM_INTERFACE: ffi::river_window_manager_v1_interface = ffi::river_window_manager_v1_interface {
+static INERT_WM_INTERFACE: ffi::zcce_window_manager_v1_interface = ffi::zcce_window_manager_v1_interface {
     stop: None,
     destroy: Some(wm_destroy),
     manage_finish: None,
@@ -2094,6 +2095,7 @@ static INERT_WM_INTERFACE: ffi::river_window_manager_v1_interface = ffi::river_w
     render_finish: None,
     get_shell_surface: None,
     exit_session: None,
+    get_cce_toplevel: None,
 };
 
 unsafe extern "C" fn bind(
@@ -2114,18 +2116,18 @@ unsafe extern "C" fn bind(
     let cmdline = std::fs::read_to_string(format!("/proc/{}/cmdline", pid))
         .unwrap_or_default()
         .replace('\0', " ");
-    log::info!("Client binding river_window_manager_v1: PID={}, cmdline='{}'", pid, cmdline);
+    log::info!("Client binding zcce_window_manager_v1: PID={}, cmdline='{}'", pid, cmdline);
 
-    let resource = ffi::wl_resource_create(client, &ffi::river_window_manager_v1_interface, version as i32, id);
+    let resource = ffi::wl_resource_create(client, &ffi::zcce_window_manager_v1_interface, version as i32, id);
     if resource.is_null() {
         ffi::wl_client_post_no_memory(client);
-        log::error!("out of memory binding river_window_manager_v1");
+        log::error!("out of memory binding zcce_window_manager_v1");
         return;
     }
 
     if !(*wm).object.is_null() {
-        log::warn!("river_window_manager_v1 already bound, rejecting new client PID={}", pid);
-        ffi::wl_resource_post_event(resource, ffi::RIVER_WINDOW_MANAGER_V1_UNAVAILABLE);
+        log::warn!("zcce_window_manager_v1 already bound, rejecting new client PID={}", pid);
+        ffi::wl_resource_post_event(resource, ffi::ZCCE_WINDOW_MANAGER_V1_UNAVAILABLE);
         ffi::wl_resource_set_implementation(
             resource,
             &INERT_WM_INTERFACE as *const _ as *const _,
@@ -2153,7 +2155,7 @@ unsafe extern "C" fn handle_destroy_wm_resource(resource: *mut ffi::wl_resource)
     if (*wm).object != resource {
         return;
     }
-    log::debug!("active river_window_manager_v1 destroyed");
+    log::debug!("active zcce_window_manager_v1 destroyed");
     (*wm).object = std::ptr::null_mut();
 
     let server = (*wm).server;
diff --git a/src/server/wm_node.rs b/src/server/wm_node.rs
index de11417..3c9454e 100644
--- a/src/server/wm_node.rs
+++ b/src/server/wm_node.rs
@@ -14,7 +14,7 @@ pub enum WmNodeTag {
 
 pub struct WmNode {
     pub tag: WmNodeTag,
-    pub object: *mut ffi::wl_resource, // river_node_v1
+    pub object: *mut ffi::wl_resource, // zcce_node_v1
     pub link: ffi::wl_list,
 }
 
@@ -53,7 +53,7 @@ impl WmNode {
 
     pub unsafe fn create_object(&mut self, client: *mut ffi::wl_client, version: u32, id: u32) {
         assert!(self.object.is_null());
-        let resource = ffi::wl_resource_create(client, &ffi::river_node_v1_interface, version as i32, id);
+        let resource = ffi::wl_resource_create(client, &ffi::zcce_node_v1_interface, version as i32, id);
         if resource.is_null() {
             log::error!("out of memory");
             ffi::wl_client_post_no_memory(client);
@@ -231,7 +231,7 @@ unsafe extern "C" fn node_place_below(
     );
 }
 
-static NODE_INTERFACE: ffi::river_node_v1_interface = ffi::river_node_v1_interface {
+static NODE_INTERFACE: ffi::zcce_node_v1_interface = ffi::zcce_node_v1_interface {
     destroy: Some(node_destroy),
     set_position: Some(node_set_position),
     place_top: Some(node_place_top),
@@ -240,7 +240,7 @@ static NODE_INTERFACE: ffi::river_node_v1_interface = ffi::river_node_v1_interfa
     place_below: Some(node_place_below),
 };
 
-static INERT_NODE_INTERFACE: ffi::river_node_v1_interface = ffi::river_node_v1_interface {
+static INERT_NODE_INTERFACE: ffi::zcce_node_v1_interface = ffi::zcce_node_v1_interface {
     destroy: Some(node_destroy),
     set_position: None,
     place_top: None,
diff --git a/src/server/xdg_toplevel.rs b/src/server/xdg_toplevel.rs
index efc2e98..a3f5ce4 100644
--- a/src/server/xdg_toplevel.rs
+++ b/src/server/xdg_toplevel.rs
@@ -690,15 +690,15 @@ unsafe extern "C" fn handle_decoration_request_mode(listener: *mut ffi::wl_liste
 
     let hint = match (*(*decoration).wlr_decoration).requested_mode {
         ffi::wlr_xdg_toplevel_decoration_v1_mode_WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_NONE => {
-            ffi::river_window_v1_decoration_hint_RIVER_WINDOW_V1_DECORATION_HINT_NO_PREFERENCE
+            ffi::zcce_window_v1_decoration_hint_ZCCE_WINDOW_V1_DECORATION_HINT_NO_PREFERENCE
         }
         ffi::wlr_xdg_toplevel_decoration_v1_mode_WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE => {
-            ffi::river_window_v1_decoration_hint_RIVER_WINDOW_V1_DECORATION_HINT_PREFERS_CSD
+            ffi::zcce_window_v1_decoration_hint_ZCCE_WINDOW_V1_DECORATION_HINT_PREFERS_CSD
         }
         ffi::wlr_xdg_toplevel_decoration_v1_mode_WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE => {
-            ffi::river_window_v1_decoration_hint_RIVER_WINDOW_V1_DECORATION_HINT_PREFERS_SSD
+            ffi::zcce_window_v1_decoration_hint_ZCCE_WINDOW_V1_DECORATION_HINT_PREFERS_SSD
         }
-        _ => ffi::river_window_v1_decoration_hint_RIVER_WINDOW_V1_DECORATION_HINT_NO_PREFERENCE,
+        _ => ffi::zcce_window_v1_decoration_hint_ZCCE_WINDOW_V1_DECORATION_HINT_NO_PREFERENCE,
     };
     (*window).set_decoration_hint(hint);
 }
diff --git a/src/server/xwayland_window.rs b/src/server/xwayland_window.rs
index a19cf74..4c2e952 100644
--- a/src/server/xwayland_window.rs
+++ b/src/server/xwayland_window.rs
@@ -542,9 +542,9 @@ unsafe extern "C" fn handle_set_decorations(listener: *mut ffi::wl_listener, _da
         != 0;
 
     let hint = if prefers_csd {
-        ffi::river_window_v1_decoration_hint_RIVER_WINDOW_V1_DECORATION_HINT_PREFERS_CSD
+        ffi::zcce_window_v1_decoration_hint_ZCCE_WINDOW_V1_DECORATION_HINT_PREFERS_CSD
     } else {
-        ffi::river_window_v1_decoration_hint_RIVER_WINDOW_V1_DECORATION_HINT_PREFERS_SSD
+        ffi::zcce_window_v1_decoration_hint_ZCCE_WINDOW_V1_DECORATION_HINT_PREFERS_SSD
     };
     (*(*xwindow).window).set_decoration_hint(hint);
 }
diff --git a/wrapper.h b/wrapper.h
index ff6ef6a..19e6311 100644
--- a/wrapper.h
+++ b/wrapper.h
@@ -91,7 +91,6 @@
 #include <pixman.h>
 
 // Custom and upstream protocols generated via wayland-scanner
-#include "river-window-management-v1-protocol.h"
 #include "river-xkb-bindings-v1-protocol.h"
 #include "river-layer-shell-v1-protocol.h"
 #include "river-input-management-v1-protocol.h"