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

commit7b92f113f6f00ad50e4881241e920ec1d8ba1e61
parent9a17cd83fa
authorIsaac Freund <[email protected]>
date2024-06-17 12:56
rwm: add key bindings and pointer bindings

I don't see a good way to avoid a roundtrip with the window manager
every time a binding is triggered. Without the roundtrip, changing
keyboard focus for example is racy.

Since we already need the roundtrip, we can take advantage of the fact
that it allows the wm to modify the set of enabled bindings in a race
free way. This means that modes and other complex key binding features
can be implemented in the wm.

 protocol/river-window-management-v1.xml | 258 +++++++++++++++++++++++++++++++-
 1 file changed, 257 insertions(+), 1 deletion(-)

diff --git a/protocol/river-window-management-v1.xml b/protocol/river-window-management-v1.xml
index 2df8893..86be8b3 100644
--- a/protocol/river-window-management-v1.xml
+++ b/protocol/river-window-management-v1.xml
@@ -38,6 +38,18 @@
         - fill in missing bits (maximize, fullscreen, etc)
     </description>
 
+    <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.
+
+        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
@@ -705,7 +717,7 @@
     <request name="pointer_resize_window">
       <description summary="start interactive pointer resize of a window">
         This request causes the a window to be resized from the specified edges,
-        updatiag the position/dimensions of the window as the pointer is moved.
+        updating the position/dimensions of the window as the pointer is moved.
         Multiple windows may be interactively resized at the same time.
 
         The interactive resize is ended when all pointer buttons are released.
@@ -722,5 +734,249 @@
       <arg name="window" type="object" interface="river_window_v1"/>
       <arg name="edges" type="uint" enum="river_window_v1.edges"/>
     </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="define_xkb_binding">
+      <description summary="define a new xkbcommon key binding">
+        Define a key binding in terms of an xkbcommon keysym and other
+        configurable properties.
+
+        The new key binding is not enabled until initial configuration is
+        completed, the enable request is made, and the change is committed with
+        a river_window_manager_v1.commit request.
+      </description>
+      <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="modifiers"/>
+    </request>
+
+    <request name="define_pointer_binding">
+      <description summary="define a new pointer binding">
+        Define a pointer binding in terms of a pointer button, 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 key binding is not enabled until initial configuration is
+        completed, the enable request is made, and the change is committed with
+        a river_window_manager_v1.commit request.
+      </description>
+      <arg name="id" type="new_id" interface="river_pointer_binding_v1"/>
+      <arg name="button" type="uint" summary="a Linux input event code"/>
+      <arg name="modifiers" type="uint" enum="modifiers"/>
+    </request>
+  </interface>
+
+  <interface name="river_xkb_binding_v1" version="1">
+    <description summary="configure a xkb key binding, receive trigger events">
+      This object allows the window manager to configure a xkbcommon key binding
+      and receive events when the key binding is triggered.
+
+      The new key binding is not enabled until initial configuration is
+      completed, the enable request is made, and the change is committed with a
+      river_window_manager_v1.commit request.
+
+      Normally, all key events are sent to the surface with keyboard focus by
+      the compositor. Key events that trigger a key binding are not sent to the
+      surface with keyboard focus.
+
+      If multiple key bindings would be triggered by a single physical key event
+      on the compositor side, it is compositor policy which key binding(s) will
+      receive press/release events or if all of the matched key bindings receive
+      press/release events.
+
+      Key bindings might be matched by the same physical key event due to shared
+      keysym and modifiers. The layout override feature may also cause the same
+      physical key event to trigger two key bindings with different keysyms and
+      different layout overrides configured.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the xkb binding object">
+        This request indicates that the client will no longer use the xkb key
+        binding object and that it may be safely destroyed.
+      </description>
+    </request>
+
+    <request name="set_layout_override">
+      <description summary="override currently active xkb layout">
+        Specify an xkb layout that should be used to translate key events for
+        the purpose of triggering this key binding irrespective of the currently
+        active xkb layout.
+
+        The layout argument is a 0-indexed xkbcommon layout number for the
+        keyboard that generated the key event.
+
+        If this request is not made before the enable request the currently
+        active xkb layout of the keyboard that generated the key event will be
+        used.
+
+        It is a protocol error to make this request after the first enable
+        request.
+      </description>
+      <arg name="layout" type="uint" summary="0-indexed xkbcommon layout"/>
+    </request>
+
+    <request name="enable">
+      <description summary="enable the key binding">
+        This request should be made after all initial configuration has been
+        completed and the window manager wishes the key binding to be able to be
+        triggered.
+
+        This request is double-buffered state and will not be applied until the
+        next river_window_manager_v1.commit request.
+      </description>
+    </request>
+
+    <request name="disable">
+      <description summary="disable the key binding">
+        This request may be used to temporarily disable the key binding. It may
+        be later re-enabled with the enable request.
+
+        This request is double-buffered state and will not be applied until the
+        next river_window_manager_v1.commit request.
+      </description>
+    </request>
+
+    <event name="pressed">
+      <description summary="the key triggering the binding has been pressed">
+        This event indicates that the physical key triggering the binding has
+        been pressed.
+
+        This event is double-buffered state and will be followed by a
+        river_window_manager_v1.update event.
+
+        The compositor should wait for the window manager to ack the update and
+        commit in response 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 ack and commit 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 key triggering the binding has been released">
+        This event indicates that the physical key triggering the binding has
+        been released.
+
+        Releasing the modifiers for the binding without releasing the "main"
+        physical key that produces the bound keysym does not trigger the release
+        event. This event is not sent until the "main" key is released.
+
+        This event is double-buffered state and will be followed by a
+        river_window_manager_v1.update event.
+
+        The compositor should wait for the window manager to ack the update and
+        commit in response 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 ack and commit as soon as possible as the capacity of the
+        compositor to buffer incoming input events is finite.
+      </description>
+    </event>
+  </interface>
+
+  <interface name="river_pointer_binding_v1" version="1">
+    <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 initial configuration is
+      completed, the enable request is made, and the change is committed with a
+      river_window_manager_v1.commit request.
+
+      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 is double-buffered state and will not be applied until the
+        next river_window_manager_v1.commit request.
+      </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 is double-buffered state and will not be applied until the
+        next river_window_manager_v1.commit request.
+      </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 is double-buffered state and will be followed by a
+        river_window_manager_v1.update event.
+
+        The compositor should wait for the window manager to ack the update and
+        commit in response before processing further input events. This allows
+        the window manager client to, for example, modify pointer bindings
+        without racing against future input events. The window manager should
+        ack and commit 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 not sent until
+        the pointer button is released.
+
+        This event is double-buffered state and will be followed by a
+        river_window_manager_v1.update event.
+
+        The compositor should wait for the window manager to ack the update and
+        commit in response before processing further input events. This allows
+        the window manager client to, for example, modify pointer bindings
+        without racing against future input events. The window manager should
+        ack and commit as soon as possible as the capacity of the compositor to
+        buffer incoming input events is finite.
+      </description>
   </interface>
 </protocol>