aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Drew DeVault <sir@cmpwn.com>2018-04-03 17:03:29 -0400
committerLibravatar Drew DeVault <sir@cmpwn.com>2018-04-04 18:47:48 -0400
commitb7e779491232b825f6edc0b199e7564e93f1e332 (patch)
tree00457213fa57ec07692bb093392a83203e0e9960
parentAdd input inhibitor to input manager (diff)
downloadsway-b7e779491232b825f6edc0b199e7564e93f1e332.tar.gz
sway-b7e779491232b825f6edc0b199e7564e93f1e332.tar.zst
sway-b7e779491232b825f6edc0b199e7564e93f1e332.zip
Implement input-inhibit in sway, swaylock
-rw-r--r--include/sway/input/seat.h5
-rw-r--r--include/swaylock/swaylock.h1
-rw-r--r--protocols/meson.build6
-rw-r--r--protocols/wlr-input-inhibitor-unstable-v1.xml67
-rw-r--r--sway/input/cursor.c6
-rw-r--r--sway/input/input-manager.c8
-rw-r--r--sway/input/seat.c68
-rw-r--r--swaylock/main.c10
8 files changed, 160 insertions, 11 deletions
diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h
index 53031d70..4b0fc3c1 100644
--- a/include/sway/input/seat.h
+++ b/include/sway/input/seat.h
@@ -32,6 +32,9 @@ struct sway_seat {
32 // If the focused layer is set, views cannot receive keyboard focus 32 // If the focused layer is set, views cannot receive keyboard focus
33 struct wlr_layer_surface *focused_layer; 33 struct wlr_layer_surface *focused_layer;
34 34
35 // If exclusive_client is set, no other clients will receive input events
36 struct wl_client *exclusive_client;
37
35 struct wl_listener focus_destroy; 38 struct wl_listener focus_destroy;
36 struct wl_listener new_container; 39 struct wl_listener new_container;
37 40
@@ -88,4 +91,6 @@ void seat_apply_config(struct sway_seat *seat, struct seat_config *seat_config);
88 91
89struct seat_config *seat_get_config(struct sway_seat *seat); 92struct seat_config *seat_get_config(struct sway_seat *seat);
90 93
94bool seat_allow_input(struct sway_seat *seat, struct wlr_surface *surface);
95
91#endif 96#endif
diff --git a/include/swaylock/swaylock.h b/include/swaylock/swaylock.h
index ddca633d..06c94ead 100644
--- a/include/swaylock/swaylock.h
+++ b/include/swaylock/swaylock.h
@@ -33,6 +33,7 @@ struct swaylock_state {
33 struct wl_display *display; 33 struct wl_display *display;
34 struct wl_compositor *compositor; 34 struct wl_compositor *compositor;
35 struct zwlr_layer_shell_v1 *layer_shell; 35 struct zwlr_layer_shell_v1 *layer_shell;
36 struct zwlr_input_inhibit_manager_v1 *input_inhibit_manager;
36 struct wl_shm *shm; 37 struct wl_shm *shm;
37 struct wl_list surfaces; 38 struct wl_list surfaces;
38 struct swaylock_args args; 39 struct swaylock_args args;
diff --git a/protocols/meson.build b/protocols/meson.build
index 0887cf86..7f83b16b 100644
--- a/protocols/meson.build
+++ b/protocols/meson.build
@@ -22,12 +22,14 @@ wayland_scanner_server = generator(
22 22
23client_protocols = [ 23client_protocols = [
24 [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'], 24 [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'],
25 ['wlr-layer-shell-unstable-v1.xml'] 25 ['wlr-layer-shell-unstable-v1.xml'],
26 ['wlr-input-inhibitor-unstable-v1.xml']
26] 27]
27 28
28server_protocols = [ 29server_protocols = [
29 [wl_protocol_dir, 'unstable/xdg-shell/xdg-shell-unstable-v6.xml'], 30 [wl_protocol_dir, 'unstable/xdg-shell/xdg-shell-unstable-v6.xml'],
30 ['wlr-layer-shell-unstable-v1.xml'] 31 ['wlr-layer-shell-unstable-v1.xml'],
32 ['wlr-input-inhibitor-unstable-v1.xml']
31] 33]
32 34
33client_protos_src = [] 35client_protos_src = []
diff --git a/protocols/wlr-input-inhibitor-unstable-v1.xml b/protocols/wlr-input-inhibitor-unstable-v1.xml
new file mode 100644
index 00000000..b62d1bb4
--- /dev/null
+++ b/protocols/wlr-input-inhibitor-unstable-v1.xml
@@ -0,0 +1,67 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<protocol name="wlr_input_inhibit_unstable_v1">
3 <copyright>
4 Copyright © 2018 Drew DeVault
5
6 Permission to use, copy, modify, distribute, and sell this
7 software and its documentation for any purpose is hereby granted
8 without fee, provided that the above copyright notice appear in
9 all copies and that both that copyright notice and this permission
10 notice appear in supporting documentation, and that the name of
11 the copyright holders not be used in advertising or publicity
12 pertaining to distribution of the software without specific,
13 written prior permission. The copyright holders make no
14 representations about the suitability of this software for any
15 purpose. It is provided "as is" without express or implied
16 warranty.
17
18 THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
19 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
21 SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
22 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
23 AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
24 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
25 THIS SOFTWARE.
26 </copyright>
27
28 <interface name="zwlr_input_inhibit_manager_v1" version="1">
29 <description summary="inhibits input events to other clients">
30 Clients can use this interface to prevent input events from being sent to
31 any surfaces but its own, which is useful for example in lock screen
32 software. It is assumed that access to this interface will be locked down
33 to whitelisted clients by the compositor.
34 </description>
35
36 <request name="get_inhibitor">
37 <description summary="inhibit input to other clients">
38 Activates the input inhibitor. As long as the inhibitor is active, the
39 compositor will not send input events to other clients.
40 </description>
41 <arg name="id" type="new_id" interface="zwlr_input_inhibitor_v1"/>
42 </request>
43
44 <enum name="error">
45 <entry name="already_inhibited" value="0" summary="an input inhibitor is already in use on the compositor"/>
46 </enum>
47 </interface>
48
49 <interface name="zwlr_input_inhibitor_v1" version="1">
50 <description summary="inhibits input to other clients">
51 While this resource exists, input to clients other than the owner of the
52 inhibitor resource will not receive input events. The client that owns
53 this resource will receive all input events normally. The compositor will
54 also disable all of its own input processing (such as keyboard shortcuts)
55 while the inhibitor is active.
56
57 The compositor may continue to send input events to selected clients,
58 such as an on-screen keyboard (via the input-method protocol).
59 </description>
60
61 <request name="destroy" type="destructor">
62 <description summary="destroy the input inhibitor object">
63 Destroy the inhibitor and allow other clients to receive input.
64 </description>
65 </request>
66 </interface>
67</protocol>
diff --git a/sway/input/cursor.c b/sway/input/cursor.c
index 9229e92d..c56445eb 100644
--- a/sway/input/cursor.c
+++ b/sway/input/cursor.c
@@ -146,8 +146,10 @@ static void cursor_send_pointer_motion(struct sway_cursor *cursor,
146 146
147 // send pointer enter/leave 147 // send pointer enter/leave
148 if (surface != NULL) { 148 if (surface != NULL) {
149 wlr_seat_pointer_notify_enter(seat, surface, sx, sy); 149 if (seat_allow_input(cursor->seat, surface)) {
150 wlr_seat_pointer_notify_motion(seat, time, sx, sy); 150 wlr_seat_pointer_notify_enter(seat, surface, sx, sy);
151 wlr_seat_pointer_notify_motion(seat, time, sx, sy);
152 }
151 } else { 153 } else {
152 wlr_seat_pointer_clear_focus(seat); 154 wlr_seat_pointer_clear_focus(seat);
153 } 155 }
diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c
index 3b2d1d55..f71a06e4 100644
--- a/sway/input/input-manager.c
+++ b/sway/input/input-manager.c
@@ -279,6 +279,14 @@ static void handle_inhibit_deactivate(struct wl_listener *listener, void *data)
279 struct sway_seat *seat; 279 struct sway_seat *seat;
280 wl_list_for_each(seat, &input_manager->seats, link) { 280 wl_list_for_each(seat, &input_manager->seats, link) {
281 seat_set_exclusive_client(seat, NULL); 281 seat_set_exclusive_client(seat, NULL);
282 struct sway_container *previous = seat_get_focus(seat);
283 if (previous) {
284 wlr_log(L_DEBUG, "Returning focus to %p %s '%s'", previous,
285 container_type_to_str(previous->type), previous->name);
286 // Hack to get seat to re-focus the return value of get_focus
287 seat_set_focus(seat, previous->parent);
288 seat_set_focus(seat, previous);
289 }
282 } 290 }
283} 291}
284 292
diff --git a/sway/input/seat.c b/sway/input/seat.c
index 318fa9f6..0e26dde4 100644
--- a/sway/input/seat.c
+++ b/sway/input/seat.c
@@ -1,5 +1,7 @@
1#define _XOPEN_SOURCE 700 1#define _XOPEN_SOURCE 700
2#define _POSIX_C_SOURCE 199309L
2#include <assert.h> 3#include <assert.h>
4#include <time.h>
3#include <wlr/types/wlr_cursor.h> 5#include <wlr/types/wlr_cursor.h>
4#include <wlr/types/wlr_output_layout.h> 6#include <wlr/types/wlr_output_layout.h>
5#include <wlr/types/wlr_xcursor_manager.h> 7#include <wlr/types/wlr_xcursor_manager.h>
@@ -9,6 +11,7 @@
9#include "sway/input/input-manager.h" 11#include "sway/input/input-manager.h"
10#include "sway/input/keyboard.h" 12#include "sway/input/keyboard.h"
11#include "sway/ipc-server.h" 13#include "sway/ipc-server.h"
14#include "sway/layers.h"
12#include "sway/output.h" 15#include "sway/output.h"
13#include "sway/tree/container.h" 16#include "sway/tree/container.h"
14#include "sway/tree/view.h" 17#include "sway/tree/view.h"
@@ -350,6 +353,11 @@ void seat_configure_xcursor(struct sway_seat *seat) {
350 seat->cursor->cursor->y); 353 seat->cursor->cursor->y);
351} 354}
352 355
356bool seat_allow_input(struct sway_seat *seat, struct wlr_surface *surface) {
357 struct wl_client *client = wl_resource_get_client(surface->resource);
358 return !seat->exclusive_client || seat->exclusive_client == client;
359}
360
353void seat_set_focus_warp(struct sway_seat *seat, 361void seat_set_focus_warp(struct sway_seat *seat,
354 struct sway_container *container, bool warp) { 362 struct sway_container *container, bool warp) {
355 if (seat->focused_layer) { 363 if (seat->focused_layer) {
@@ -371,6 +379,12 @@ void seat_set_focus_warp(struct sway_seat *seat,
371 wl_list_remove(&seat_con->link); 379 wl_list_remove(&seat_con->link);
372 wl_list_insert(&seat->focus_stack, &seat_con->link); 380 wl_list_insert(&seat->focus_stack, &seat_con->link);
373 381
382 if (container->type == C_VIEW && !seat_allow_input(
383 seat, container->sway_view->surface)) {
384 wlr_log(L_DEBUG, "Refusing to set focus, input is inhibited");
385 return;
386 }
387
374 if (container->type == C_VIEW) { 388 if (container->type == C_VIEW) {
375 seat_send_focus(seat, container); 389 seat_send_focus(seat, container);
376 } 390 }
@@ -426,13 +440,13 @@ void seat_set_focus_layer(struct sway_seat *seat,
426 struct wlr_layer_surface *layer) { 440 struct wlr_layer_surface *layer) {
427 if (!layer && seat->focused_layer) { 441 if (!layer && seat->focused_layer) {
428 seat->focused_layer = NULL; 442 seat->focused_layer = NULL;
429 struct sway_container *c = seat_get_focus(seat); 443 struct sway_container *previous = seat_get_focus(seat);
430 if (c) { 444 if (previous) {
431 wlr_log(L_DEBUG, "Returning focus to %p %s '%s'", c, 445 wlr_log(L_DEBUG, "Returning focus to %p %s '%s'", previous,
432 container_type_to_str(c->type), c->name); 446 container_type_to_str(previous->type), previous->name);
433 // Hack to get seat to re-focus the return value of get_focus 447 // Hack to get seat to re-focus the return value of get_focus
434 seat_set_focus(seat, c->parent); 448 seat_set_focus(seat, previous->parent);
435 seat_set_focus(seat, c); 449 seat_set_focus(seat, previous);
436 } 450 }
437 return; 451 return;
438 } else if (!layer || seat->focused_layer == layer) { 452 } else if (!layer || seat->focused_layer == layer) {
@@ -462,7 +476,47 @@ void seat_set_focus_layer(struct sway_seat *seat,
462 476
463void seat_set_exclusive_client(struct sway_seat *seat, 477void seat_set_exclusive_client(struct sway_seat *seat,
464 struct wl_client *client) { 478 struct wl_client *client) {
465 // TODO 479 if (!client) {
480 seat->exclusive_client = client;
481 // Triggers a refocus of the topmost surface layer if necessary
482 // TODO: Make layer surface focus per-output based on cursor position
483 for (int i = 0; i < root_container.children->length; ++i) {
484 struct sway_container *output = root_container.children->items[i];
485 if (!sway_assert(output->type == C_OUTPUT,
486 "root container has non-output child")) {
487 continue;
488 }
489 arrange_layers(output->sway_output);
490 }
491 return;
492 }
493 if (seat->focused_layer) {
494 if (wl_resource_get_client(seat->focused_layer->resource) != client) {
495 seat_set_focus_layer(seat, NULL);
496 }
497 }
498 if (seat->has_focus) {
499 struct sway_container *focus = seat_get_focus(seat);
500 if (focus->type == C_VIEW && wl_resource_get_client(
501 focus->sway_view->surface->resource) != client) {
502 seat_set_focus(seat, NULL);
503 }
504 }
505 if (seat->wlr_seat->pointer_state.focused_client) {
506 if (seat->wlr_seat->pointer_state.focused_client->client != client) {
507 wlr_seat_pointer_clear_focus(seat->wlr_seat);
508 }
509 }
510 struct timespec now;
511 clock_gettime(CLOCK_MONOTONIC, &now);
512 struct wlr_touch_point *point;
513 wl_list_for_each(point, &seat->wlr_seat->touch_state.touch_points, link) {
514 if (point->client->client != client) {
515 wlr_seat_touch_point_clear_focus(seat->wlr_seat,
516 now.tv_nsec / 1000, point->touch_id);
517 }
518 }
519 seat->exclusive_client = client;
466} 520}
467 521
468struct sway_container *seat_get_focus_inactive(struct sway_seat *seat, 522struct sway_container *seat_get_focus_inactive(struct sway_seat *seat,
diff --git a/swaylock/main.c b/swaylock/main.c
index 7f502eb1..6cd4e41d 100644
--- a/swaylock/main.c
+++ b/swaylock/main.c
@@ -19,6 +19,7 @@
19#include "pool-buffer.h" 19#include "pool-buffer.h"
20#include "cairo.h" 20#include "cairo.h"
21#include "util.h" 21#include "util.h"
22#include "wlr-input-inhibitor-unstable-v1-client-protocol.h"
22#include "wlr-layer-shell-unstable-v1-client-protocol.h" 23#include "wlr-layer-shell-unstable-v1-client-protocol.h"
23 24
24static void daemonize() { 25static void daemonize() {
@@ -71,6 +72,9 @@ static void handle_global(void *data, struct wl_registry *registry,
71 } else if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) { 72 } else if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) {
72 state->layer_shell = wl_registry_bind( 73 state->layer_shell = wl_registry_bind(
73 registry, name, &zwlr_layer_shell_v1_interface, 1); 74 registry, name, &zwlr_layer_shell_v1_interface, 1);
75 } else if (strcmp(interface, zwlr_input_inhibit_manager_v1_interface.name) == 0) {
76 state->input_inhibit_manager = wl_registry_bind(
77 registry, name, &zwlr_input_inhibit_manager_v1_interface, 1);
74 } else if (strcmp(interface, wl_output_interface.name) == 0) { 78 } else if (strcmp(interface, wl_output_interface.name) == 0) {
75 struct swaylock_surface *surface = 79 struct swaylock_surface *surface =
76 calloc(1, sizeof(struct swaylock_surface)); 80 calloc(1, sizeof(struct swaylock_surface));
@@ -187,6 +191,10 @@ int main(int argc, char **argv) {
187 wl_registry_add_listener(registry, &registry_listener, &state); 191 wl_registry_add_listener(registry, &registry_listener, &state);
188 wl_display_roundtrip(state.display); 192 wl_display_roundtrip(state.display);
189 assert(state.compositor && state.layer_shell && state.shm); 193 assert(state.compositor && state.layer_shell && state.shm);
194 if (!state.input_inhibit_manager) {
195 wlr_log(L_ERROR, "Compositor does not support the input inhibitor "
196 "protocol, refusing to run insecurely");
197 }
190 198
191 if (wl_list_empty(&state.surfaces)) { 199 if (wl_list_empty(&state.surfaces)) {
192 wlr_log(L_DEBUG, "Exiting - no outputs to show on."); 200 wlr_log(L_DEBUG, "Exiting - no outputs to show on.");
@@ -220,6 +228,8 @@ int main(int argc, char **argv) {
220 wl_display_roundtrip(state.display); 228 wl_display_roundtrip(state.display);
221 } 229 }
222 230
231 zwlr_input_inhibit_manager_v1_get_inhibitor(state.input_inhibit_manager);
232
223 state.run_display = true; 233 state.run_display = true;
224 while (wl_display_dispatch(state.display) != -1 && state.run_display) { 234 while (wl_display_dispatch(state.display) != -1 && state.run_display) {
225 // This space intentionally left blank 235 // This space intentionally left blank