Implemented keyboard shortcut inhibit support.
authorArmin Novak <armin.novak@thincast.com>
Tue, 22 Jan 2019 12:46:46 +0000 (13:46 +0100)
committerArmin Novak <armin.novak@thincast.com>
Tue, 22 Jan 2019 13:27:12 +0000 (14:27 +0100)
client/Wayland/wlfreerdp.c
uwac/include/uwac/uwac.h
uwac/libuwac/CMakeLists.txt
uwac/libuwac/uwac-display.c
uwac/libuwac/uwac-input.c
uwac/libuwac/uwac-priv.h
uwac/libuwac/uwac-window.c
uwac/protocols/keyboard-shortcuts-inhibit-unstable-v1.xml [new file with mode: 0644]
uwac/protocols/xdg-decoration-unstable-v1.xml [new file with mode: 0644]

index 04a9c68..66f3ab1 100644 (file)
@@ -273,6 +273,8 @@ static BOOL handle_uwac_events(freerdp* instance, UwacDisplay* display)
                                break;
 
                        case UWAC_EVENT_KEYBOARD_ENTER:
+                               if (instance->context->settings->GrabKeyboard)
+                                       UwacSeatInhibitShortcuts(event.keyboard_enter_leave.seat, true);
                                if (!wlf_keyboard_enter(instance, &event.keyboard_enter_leave))
                                        return FALSE;
 
index 6a85bc7..710392a 100644 (file)
@@ -494,6 +494,16 @@ UWAC_API const char *UwacSeatGetName(const UwacSeat *seat);
  */
 UWAC_API UwacSeatId UwacSeatGetId(const UwacSeat *seat);
 
+/**
+ * Inhibits or restores keyboard shortcuts.
+ *
+ * @param seat    The UwacSeat to inhibit the shortcuts for
+ * @param inhibit Inhibit or restore keyboard shortcuts
+ *
+ * @return UWAC_SUCCESS or an appropriate error code.
+ */
+UWAC_API UwacReturnCode UwacSeatInhibitShortcuts(UwacSeat* seat, bool inhibit);
+
 #ifdef __cplusplus
 }
 #endif
index 255d0db..acbcb5a 100644 (file)
@@ -39,6 +39,7 @@ endmacro()
 generate_protocol_file(xdg-shell)
 generate_protocol_file(ivi-application)
 generate_protocol_file(fullscreen-shell-unstable-v1)
+generate_protocol_file(keyboard-shortcuts-inhibit-unstable-v1)
 
 if(FREEBSD)
        include_directories(${EPOLLSHIM_INCLUDE_DIR})
index ac2b49a..638aa1e 100644 (file)
@@ -215,21 +215,25 @@ static void registry_handle_global(void* data, struct wl_registry* registry, uin
        {
                d->xdg_base = wl_registry_bind(registry, id, &xdg_wm_base_interface, 1);
                xdg_wm_base_add_listener(d->xdg_base, &xdg_wm_base_listener, d);
-#if BUILD_IVI
        }
+       else if (strcmp(interface, "zwp_keyboard_shortcuts_inhibit_manager_v1") == 0)
+       {
+               d->keyboard_inhibit_manager = wl_registry_bind(registry, id, &zwp_keyboard_shortcuts_inhibit_manager_v1_interface, 1);
+       }
+#if BUILD_IVI
        else if (strcmp(interface, "ivi_application") == 0)
        {
                d->ivi_application = wl_registry_bind(registry, id, &ivi_application_interface, 1);
+       }
 #endif
 #if BUILD_FULLSCREEN_SHELL
-       }
        else if (strcmp(interface, "zwp_fullscreen_shell_v1") == 0)
        {
                d->fullscreen_shell = wl_registry_bind(registry, id, &zwp_fullscreen_shell_v1_interface, 1);
                zwp_fullscreen_shell_v1_add_listener(d->fullscreen_shell, &fullscreen_shell_listener, d);
+       }
 #endif
 #if 0
-       }
        else if (strcmp(interface, "text_cursor_position") == 0)
        {
                d->text_cursor_position = wl_registry_bind(registry, id, &text_cursor_position_interface, 1);
@@ -242,7 +246,6 @@ static void registry_handle_global(void* data, struct wl_registry* registry, uin
        {
                d->subcompositor = wl_registry_bind(registry, id, &wl_subcompositor_interface, 1);
 #endif
-       }
 }
 
 static void registry_handle_global_remove(void* data, struct wl_registry* registry, uint32_t name)
@@ -512,6 +515,9 @@ UwacReturnCode UwacCloseDisplay(UwacDisplay** pdisplay)
        if (display->compositor)
                wl_compositor_destroy(display->compositor);
 
+       if (display->keyboard_inhibit_manager)
+               zwp_keyboard_shortcuts_inhibit_manager_v1_destroy(display->keyboard_inhibit_manager);
+
 #ifdef BUILD_FULLSCREEN_SHELL
 
        if (display->fullscreen_shell)
index 16edb4b..5adb62d 100644 (file)
@@ -130,6 +130,7 @@ static void keyboard_handle_enter(void *data, struct wl_keyboard *keyboard, uint
                return;
 
        event->window = input->keyboard_focus = (UwacWindow *)wl_surface_get_user_data(surface);
+       event->seat = input;
 
        /* look for keys that have been released */
        found = false;
@@ -819,6 +820,7 @@ error_xkb_context:
 }
 
 void UwacSeatDestroy(UwacSeat *s) {
+       UwacSeatInhibitShortcuts(s, false);
        if (s->seat) {
 #ifdef WL_SEAT_RELEASE_SINCE_VERSION
                if (s->seat_version >= WL_SEAT_RELEASE_SINCE_VERSION)
@@ -873,3 +875,19 @@ const char *UwacSeatGetName(const UwacSeat *seat) {
 UwacSeatId UwacSeatGetId(const UwacSeat *seat) {
        return seat->seat_id;
 }
+
+UwacReturnCode UwacSeatInhibitShortcuts(UwacSeat* s, bool inhibit)
+{
+       if (!s)
+               return UWAC_ERROR_CLOSED;
+
+       if (s->keyboard_inhibitor)
+               zwp_keyboard_shortcuts_inhibitor_v1_destroy(s->keyboard_inhibitor);
+       if (inhibit && s->display && s->display->keyboard_inhibit_manager)
+               s->keyboard_inhibitor = zwp_keyboard_shortcuts_inhibit_manager_v1_inhibit_shortcuts(s->display->keyboard_inhibit_manager,
+                                                                                                   s->keyboard_focus->surface, s->seat);
+
+       if (!s->keyboard_inhibitor)
+               return UWAC_ERROR_INTERNAL;
+       return UWAC_SUCCESS;
+}
index a30c0cb..655c12f 100644 (file)
@@ -28,6 +28,8 @@
 #include <stdbool.h>
 #include <wayland-client.h>
 #include "xdg-shell-client-protocol.h"
+#include "keyboard-shortcuts-inhibit-unstable-v1-client-protocol.h"
+
 #ifdef BUILD_IVI
 #include "ivi-application-client-protocol.h"
 #endif
@@ -86,6 +88,7 @@ struct uwac_display {
        struct wl_shell *shell;
        struct xdg_toplevel *xdg_toplevel;
        struct xdg_wm_base *xdg_base;
+       struct zwp_keyboard_shortcuts_inhibit_manager_v1 *keyboard_inhibit_manager;
 #ifdef BUILD_IVI
        struct ivi_application *ivi_application;
 #endif
@@ -151,6 +154,7 @@ struct uwac_seat {
        struct wl_keyboard *keyboard;
        struct wl_touch *touch;
        struct xkb_context *xkb_context;
+       struct zwp_keyboard_shortcuts_inhibitor_v1 *keyboard_inhibitor;
 
        struct {
                struct xkb_keymap *keymap;
index 04927fc..694ac12 100644 (file)
@@ -449,22 +449,22 @@ UwacWindow* UwacCreateWindowShm(UwacDisplay* display, uint32_t width, uint32_t h
 
                assert(w->xdg_surface);
                xdg_toplevel_add_listener(w->xdg_toplevel, &xdg_toplevel_listener, w);
-#if BUILD_IVI
        }
+#if BUILD_IVI
        else if (display->ivi_application)
        {
                w->ivi_surface = ivi_application_surface_create(display->ivi_application, 1, w->surface);
                assert(w->ivi_surface);
                ivi_surface_add_listener(w->ivi_surface, &ivi_surface_listener, w);
+       }
 #endif
 #if BUILD_FULLSCREEN_SHELL
-       }
        else if (display->fullscreen_shell)
        {
                zwp_fullscreen_shell_v1_present_surface(display->fullscreen_shell, w->surface,
                                                     ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_CENTER, NULL);
-#endif
        }
+#endif
        else
        {
                w->shell_surface = wl_shell_get_shell_surface(display->shell, w->surface);
diff --git a/uwac/protocols/keyboard-shortcuts-inhibit-unstable-v1.xml b/uwac/protocols/keyboard-shortcuts-inhibit-unstable-v1.xml
new file mode 100644 (file)
index 0000000..2774876
--- /dev/null
@@ -0,0 +1,143 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="keyboard_shortcuts_inhibit_unstable_v1">
+
+  <copyright>
+    Copyright © 2017 Red Hat Inc.
+
+    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 (including the next
+    paragraph) 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="Protocol for inhibiting the compositor keyboard shortcuts">
+    This protocol specifies a way for a client to request the compositor
+    to ignore its own keyboard shortcuts for a given seat, so that all
+    key events from that seat get forwarded to a surface.
+
+    Warning! The protocol described in this file is experimental and
+    backward incompatible changes may be made. Backward compatible
+    changes may be added together with the corresponding interface
+    version bump.
+    Backward incompatible changes are done by bumping the version
+    number in the protocol and interface names and resetting the
+    interface version. Once the protocol is to be declared stable,
+    the 'z' prefix and the version number in the protocol and
+    interface names are removed and the interface version number is
+    reset.
+  </description>
+
+  <interface name="zwp_keyboard_shortcuts_inhibit_manager_v1" version="1">
+    <description summary="context object for keyboard grab_manager">
+      A global interface used for inhibiting the compositor keyboard shortcuts.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the keyboard shortcuts inhibitor object">
+       Destroy the keyboard shortcuts inhibitor manager.
+      </description>
+    </request>
+
+    <request name="inhibit_shortcuts">
+      <description summary="create a new keyboard shortcuts inhibitor object">
+       Create a new keyboard shortcuts inhibitor object associated with
+       the given surface for the given seat.
+
+       If shortcuts are already inhibited for the specified seat and surface,
+       a protocol error "already_inhibited" is raised by the compositor.
+      </description>
+      <arg name="id" type="new_id" interface="zwp_keyboard_shortcuts_inhibitor_v1"/>
+      <arg name="surface" type="object" interface="wl_surface"
+          summary="the surface that inhibits the keyboard shortcuts behavior"/>
+      <arg name="seat" type="object" interface="wl_seat"
+          summary="the wl_seat for which keyboard shortcuts should be disabled"/>
+    </request>
+
+    <enum name="error">
+      <entry name="already_inhibited"
+            value="0"
+            summary="the shortcuts are already inhibited for this surface"/>
+    </enum>
+  </interface>
+
+  <interface name="zwp_keyboard_shortcuts_inhibitor_v1" version="1">
+    <description summary="context object for keyboard shortcuts inhibitor">
+      A keyboard shortcuts inhibitor instructs the compositor to ignore
+      its own keyboard shortcuts when the associated surface has keyboard
+      focus. As a result, when the surface has keyboard focus on the given
+      seat, it will receive all key events originating from the specified
+      seat, even those which would normally be caught by the compositor for
+      its own shortcuts.
+
+      The Wayland compositor is however under no obligation to disable
+      all of its shortcuts, and may keep some special key combo for its own
+      use, including but not limited to one allowing the user to forcibly
+      restore normal keyboard events routing in the case of an unwilling
+      client. The compositor may also use the same key combo to reactivate
+      an existing shortcut inhibitor that was previously deactivated on
+      user request.
+
+      When the compositor restores its own keyboard shortcuts, an
+      "inactive" event is emitted to notify the client that the keyboard
+      shortcuts inhibitor is not effectively active for the surface and
+      seat any more, and the client should not expect to receive all
+      keyboard events.
+
+      When the keyboard shortcuts inhibitor is inactive, the client has
+      no way to forcibly reactivate the keyboard shortcuts inhibitor.
+
+      The user can chose to re-enable a previously deactivated keyboard
+      shortcuts inhibitor using any mechanism the compositor may offer,
+      in which case the compositor will send an "active" event to notify
+      the client.
+
+      If the surface is destroyed, unmapped, or loses the seat's keyboard
+      focus, the keyboard shortcuts inhibitor becomes irrelevant and the
+      compositor will restore its own keyboard shortcuts but no "inactive"
+      event is emitted in this case.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the keyboard shortcuts inhibitor object">
+       Remove the keyboard shortcuts inhibitor from the associated wl_surface.
+      </description>
+    </request>
+
+    <event name="active">
+      <description summary="shortcuts are inhibited">
+       This event indicates that the shortcut inhibitor is active.
+
+       The compositor sends this event every time compositor shortcuts
+       are inhibited on behalf of the surface. When active, the client
+       may receive input events normally reserved by the compositor
+       (see zwp_keyboard_shortcuts_inhibitor_v1).
+
+       This occurs typically when the initial request "inhibit_shortcuts"
+       first becomes active or when the user instructs the compositor to
+       re-enable and existing shortcuts inhibitor using any mechanism
+       offered by the compositor.
+      </description>
+    </event>
+
+    <event name="inactive">
+      <description summary="shortcuts are restored">
+       This event indicates that the shortcuts inhibitor is inactive,
+       normal shortcuts processing is restored by the compositor.
+       </description>
+    </event>
+  </interface>
+</protocol>
diff --git a/uwac/protocols/xdg-decoration-unstable-v1.xml b/uwac/protocols/xdg-decoration-unstable-v1.xml
new file mode 100644 (file)
index 0000000..378e8ff
--- /dev/null
@@ -0,0 +1,156 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="xdg_decoration_unstable_v1">
+  <copyright>
+    Copyright © 2018 Simon Ser
+
+    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 (including the next
+    paragraph) 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="zxdg_decoration_manager_v1" version="1">
+    <description summary="window decoration manager">
+      This interface allows a compositor to announce support for server-side
+      decorations.
+
+      A window decoration is a set of window controls as deemed appropriate by
+      the party managing them, such as user interface components used to move,
+      resize and change a window's state.
+
+      A client can use this protocol to request being decorated by a supporting
+      compositor.
+
+      If compositor and client do not negotiate the use of a server-side
+      decoration using this protocol, clients continue to self-decorate as they
+      see fit.
+
+      Warning! The protocol described in this file is experimental and
+      backward incompatible changes may be made. Backward compatible changes
+      may be added together with the corresponding interface version bump.
+      Backward incompatible changes are done by bumping the version number in
+      the protocol and interface names and resetting the interface version.
+      Once the protocol is to be declared stable, the 'z' prefix and the
+      version number in the protocol and interface names are removed and the
+      interface version number is reset.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the decoration manager object">
+        Destroy the decoration manager. This doesn't destroy objects created
+        with the manager.
+      </description>
+    </request>
+
+    <request name="get_toplevel_decoration">
+      <description summary="create a new toplevel decoration object">
+        Create a new decoration object associated with the given toplevel.
+
+        Creating an xdg_toplevel_decoration from an xdg_toplevel which has a
+        buffer attached or committed is a client error, and any attempts by a
+        client to attach or manipulate a buffer prior to the first
+        xdg_toplevel_decoration.configure event must also be treated as
+        errors.
+      </description>
+      <arg name="id" type="new_id" interface="zxdg_toplevel_decoration_v1"/>
+      <arg name="toplevel" type="object" interface="xdg_toplevel"/>
+    </request>
+  </interface>
+
+  <interface name="zxdg_toplevel_decoration_v1" version="1">
+    <description summary="decoration object for a toplevel surface">
+      The decoration object allows the compositor to toggle server-side window
+      decorations for a toplevel surface. The client can request to switch to
+      another mode.
+
+      The xdg_toplevel_decoration object must be destroyed before its
+      xdg_toplevel.
+    </description>
+
+    <enum name="error">
+      <entry name="unconfigured_buffer" value="0"
+        summary="xdg_toplevel has a buffer attached before configure"/>
+      <entry name="already_constructed" value="1"
+        summary="xdg_toplevel already has a decoration object"/>
+      <entry name="orphaned" value="2"
+        summary="xdg_toplevel destroyed before the decoration object"/>
+    </enum>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the decoration object">
+        Switch back to a mode without any server-side decorations at the next
+        commit.
+      </description>
+    </request>
+
+    <enum name="mode">
+      <description summary="window decoration modes">
+        These values describe window decoration modes.
+      </description>
+      <entry name="client_side" value="1"
+        summary="no server-side window decoration"/>
+      <entry name="server_side" value="2"
+        summary="server-side window decoration"/>
+    </enum>
+
+    <request name="set_mode">
+      <description summary="set the decoration mode">
+        Set the toplevel surface decoration mode. This informs the compositor
+        that the client prefers the provided decoration mode.
+
+        After requesting a decoration mode, the compositor will respond by
+        emitting a xdg_surface.configure event. The client should then update
+        its content, drawing it without decorations if the received mode is
+        server-side decorations. The client must also acknowledge the configure
+        when committing the new content (see xdg_surface.ack_configure).
+
+        The compositor can decide not to use the client's mode and enforce a
+        different mode instead.
+
+        Clients whose decoration mode depend on the xdg_toplevel state may send
+        a set_mode request in response to a xdg_surface.configure event and wait
+        for the next xdg_surface.configure event to prevent unwanted state.
+        Such clients are responsible for preventing configure loops and must
+        make sure not to send multiple successive set_mode requests with the
+        same decoration mode.
+      </description>
+      <arg name="mode" type="uint" enum="mode" summary="the decoration mode"/>
+    </request>
+
+    <request name="unset_mode">
+      <description summary="unset the decoration mode">
+        Unset the toplevel surface decoration mode. This informs the compositor
+        that the client doesn't prefer a particular decoration mode.
+
+        This request has the same semantics as set_mode.
+      </description>
+    </request>
+
+    <event name="configure">
+      <description summary="suggest a surface change">
+        The configure event asks the client to change its decoration mode. The
+        configured state should not be applied immediately. Clients must send an
+        ack_configure in response to this event. See xdg_surface.configure and
+        xdg_surface.ack_configure for details.
+
+        A configure event can be sent at any time. The specified mode must be
+        obeyed by the client.
+      </description>
+      <arg name="mode" type="uint" enum="mode" summary="the decoration mode"/>
+    </event>
+  </interface>
+</protocol>