diff --git a/include/wlr/types/wlr_input_inhibitor.h b/include/wlr/types/wlr_input_inhibitor.h new file mode 100644 index 00000000..4416c18f --- /dev/null +++ b/include/wlr/types/wlr_input_inhibitor.h @@ -0,0 +1,25 @@ +#ifndef WLR_TYPES_INPUT_INHIBITOR_H +#define WLR_TYPES_INPUT_INHIBITOR_H +#include + +struct wlr_input_inhibit_manager { + struct wl_global *wl_global; + struct wl_client *active_client; + struct wl_resource *active_inhibitor; + + struct wl_listener display_destroy; + + struct { + struct wl_signal activate; // struct wlr_input_inhibit_manager * + struct wl_signal deactivate; // struct wlr_input_inhibit_manager * + } events; + + void *data; +}; + +struct wlr_input_inhibit_manager *wlr_input_inhibit_manager_create( + struct wl_display *display); +void wlr_input_inhibit_manager_destroy( + struct wlr_input_inhibit_manager *manager); + +#endif diff --git a/protocol/meson.build b/protocol/meson.build index a41fdec3..b88b4b77 100644 --- a/protocol/meson.build +++ b/protocol/meson.build @@ -31,6 +31,7 @@ protocols = [ 'screenshooter.xml', 'server-decoration.xml', 'wlr-layer-shell-unstable-v1.xml', + 'wlr-input-inhibitor-unstable-v1.xml', ] client_protocols = [ @@ -40,6 +41,7 @@ client_protocols = [ 'idle.xml', 'screenshooter.xml', 'wlr-layer-shell-unstable-v1.xml', + 'wlr-input-inhibitor-unstable-v1.xml', ] wl_protos_src = [] diff --git a/protocol/wlr-input-inhibitor-unstable-v1.xml b/protocol/wlr-input-inhibitor-unstable-v1.xml new file mode 100644 index 00000000..b62d1bb4 --- /dev/null +++ b/protocol/wlr-input-inhibitor-unstable-v1.xml @@ -0,0 +1,67 @@ + + + + Copyright © 2018 Drew DeVault + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that copyright notice and this permission + notice appear in supporting documentation, and that the name of + the copyright holders not be used in advertising or publicity + pertaining to distribution of the software without specific, + written prior permission. The copyright holders make no + representations about the suitability of this software for any + purpose. It is provided "as is" without express or implied + warranty. + + THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF + THIS SOFTWARE. + + + + + Clients can use this interface to prevent input events from being sent to + any surfaces but its own, which is useful for example in lock screen + software. It is assumed that access to this interface will be locked down + to whitelisted clients by the compositor. + + + + + Activates the input inhibitor. As long as the inhibitor is active, the + compositor will not send input events to other clients. + + + + + + + + + + + + While this resource exists, input to clients other than the owner of the + inhibitor resource will not receive input events. The client that owns + this resource will receive all input events normally. The compositor will + also disable all of its own input processing (such as keyboard shortcuts) + while the inhibitor is active. + + The compositor may continue to send input events to selected clients, + such as an on-screen keyboard (via the input-method protocol). + + + + + Destroy the inhibitor and allow other clients to receive input. + + + + diff --git a/types/meson.build b/types/meson.build index 198563b1..eda5f4e4 100644 --- a/types/meson.build +++ b/types/meson.build @@ -10,6 +10,7 @@ lib_wlr_types = static_library( 'wlr_idle.c', 'wlr_idle_inhibit_v1.c', 'wlr_input_device.c', + 'wlr_input_inhibitor.c', 'wlr_keyboard.c', 'wlr_layer_shell.c', 'wlr_linux_dmabuf.c', diff --git a/types/wlr_input_inhibitor.c b/types/wlr_input_inhibitor.c new file mode 100644 index 00000000..d42a5c0c --- /dev/null +++ b/types/wlr_input_inhibitor.c @@ -0,0 +1,130 @@ +#include +#include +#include +#include +#include "wlr/types/wlr_input_inhibitor.h" +#include "wlr-input-inhibitor-unstable-v1-protocol.h" + +static const struct zwlr_input_inhibit_manager_v1_interface inhibit_manager_implementation; + +static struct wlr_input_inhibit_manager *input_inhibit_manager_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &zwlr_input_inhibit_manager_v1_interface, + &inhibit_manager_implementation)); + return wl_resource_get_user_data(resource); +} + +static void input_inhibitor_destroy(struct wl_client *client, + struct wl_resource *resource) { + struct wlr_input_inhibit_manager *manager = + input_inhibit_manager_from_resource(resource); + manager->active_client = NULL; + manager->active_inhibitor = NULL; + wl_resource_destroy(resource); + wl_signal_emit(&manager->events.deactivate, manager); +} + +static struct zwlr_input_inhibitor_v1_interface input_inhibitor_implementation = { + .destroy = input_inhibitor_destroy, +}; + +static void inhibit_manager_get_inhibitor(struct wl_client *client, + struct wl_resource *resource, uint32_t id) { + struct wlr_input_inhibit_manager *manager = + input_inhibit_manager_from_resource(resource); + if (manager->active_client || manager->active_inhibitor) { + wl_resource_post_error(resource, + ZWLR_INPUT_INHIBIT_MANAGER_V1_ERROR_ALREADY_INHIBITED, + "this compositor already has input inhibited"); + return; + } + + struct wl_resource *wl_resource = wl_resource_create(client, + &zwlr_input_inhibitor_v1_interface, + wl_resource_get_version(resource), id); + if (!wl_resource) { + wl_client_post_no_memory(client); + } + wl_resource_set_implementation(wl_resource, &input_inhibitor_implementation, + manager, NULL); + + manager->active_client = client; + manager->active_inhibitor = wl_resource; + + wl_signal_emit(&manager->events.activate, manager); +} + +static const struct zwlr_input_inhibit_manager_v1_interface inhibit_manager_implementation = { + .get_inhibitor = inhibit_manager_get_inhibitor +}; + +static void input_manager_client_destroy(struct wl_resource *resource) { + struct wlr_input_inhibit_manager *manager = + input_inhibit_manager_from_resource(resource); + if (manager->active_client == wl_resource_get_client(resource)) { + input_inhibitor_destroy(manager->active_client, resource); + } +} + +static void inhibit_manager_bind(struct wl_client *wl_client, void *data, + uint32_t version, uint32_t id) { + struct wlr_input_inhibit_manager *manager = data; + assert(wl_client && manager); + + struct wl_resource *wl_resource = wl_resource_create(wl_client, + &zwlr_input_inhibit_manager_v1_interface, version, id); + if (wl_resource == NULL) { + wl_client_post_no_memory(wl_client); + return; + } + wl_resource_set_implementation(wl_resource, + &inhibit_manager_implementation, manager, + input_manager_client_destroy); +} + +void wlr_input_inhibit_manager_destroy( + struct wlr_input_inhibit_manager *manager) { + if (!manager) { + return; + } + if (manager->active_client) { + input_inhibitor_destroy(manager->active_client, + manager->active_inhibitor); + } + wl_list_remove(&manager->display_destroy.link); + wl_global_destroy(manager->wl_global); + free(manager); +} + +static void handle_display_destroy(struct wl_listener *listener, void *data) { + struct wlr_input_inhibit_manager *manager = + wl_container_of(listener, manager, display_destroy); + wlr_input_inhibit_manager_destroy(manager); +} + +struct wlr_input_inhibit_manager *wlr_input_inhibit_manager_create( + struct wl_display *display) { + // TODO: Client destroy + struct wlr_input_inhibit_manager *manager = + calloc(1, sizeof(struct wlr_input_inhibit_manager)); + if (!manager) { + return NULL; + } + + manager->wl_global = wl_global_create(display, + &zwlr_input_inhibit_manager_v1_interface, + 1, manager, inhibit_manager_bind); + if (manager->wl_global == NULL){ + wl_list_remove(&manager->display_destroy.link); + free(manager); + return NULL; + } + + wl_signal_init(&manager->events.activate); + wl_signal_init(&manager->events.deactivate); + + manager->display_destroy.notify = handle_display_destroy; + wl_display_add_destroy_listener(display, &manager->display_destroy); + + return manager; +}