aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Erik Reider <35975961+ErikReider@users.noreply.github.com>2023-06-05 15:31:16 +0200
committerLibravatar Kenny Levinsen <kl@kl.wtf>2023-06-06 09:07:05 +0200
commit913a7679cbde98df0722b326d8c3cfc0f0576f6d (patch)
tree752fea000515bcd93a40fc175dbbace5221ee9c4
parentchase wlroots wlr_renderer_begin_buffer_pass change (diff)
downloadsway-913a7679cbde98df0722b326d8c3cfc0f0576f6d.tar.gz
sway-913a7679cbde98df0722b326d8c3cfc0f0576f6d.tar.zst
sway-913a7679cbde98df0722b326d8c3cfc0f0576f6d.zip
Add support for wlr-layer-shell ON_DEMAND keyboard interactivity
This allows for layer shell surfaces to receive focus while the surface is explicitly focused, i.e allowing text fields to receive keyboard input just like a regular surface.
-rw-r--r--include/sway/input/seat.h3
-rw-r--r--include/sway/layers.h4
-rw-r--r--sway/desktop/layer_shell.c40
-rw-r--r--sway/input/seat.c20
-rw-r--r--sway/input/seatop_default.c24
-rw-r--r--sway/server.c2
6 files changed, 80 insertions, 13 deletions
diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h
index 5ef8e2f3..35a96ace 100644
--- a/include/sway/input/seat.h
+++ b/include/sway/input/seat.h
@@ -104,8 +104,9 @@ struct sway_seat {
104 struct sway_workspace *workspace; 104 struct sway_workspace *workspace;
105 char *prev_workspace_name; // for workspace back_and_forth 105 char *prev_workspace_name; // for workspace back_and_forth
106 106
107 // If the focused layer is set, views cannot receive keyboard focus
108 struct wlr_layer_surface_v1 *focused_layer; 107 struct wlr_layer_surface_v1 *focused_layer;
108 // If the exclusive layer is set, views cannot receive keyboard focus
109 bool has_exclusive_layer;
109 110
110 // If exclusive_client is set, no other clients will receive input events 111 // If exclusive_client is set, no other clients will receive input events
111 struct wl_client *exclusive_client; 112 struct wl_client *exclusive_client;
diff --git a/include/sway/layers.h b/include/sway/layers.h
index f8508493..9220bdb5 100644
--- a/include/sway/layers.h
+++ b/include/sway/layers.h
@@ -55,6 +55,10 @@ struct sway_layer_subsurface {
55}; 55};
56 56
57struct sway_output; 57struct sway_output;
58
59struct wlr_layer_surface_v1 *toplevel_layer_surface_from_surface(
60 struct wlr_surface *surface);
61
58void arrange_layers(struct sway_output *output); 62void arrange_layers(struct sway_output *output);
59 63
60struct sway_layer_surface *layer_from_wlr_layer_surface_v1( 64struct sway_layer_surface *layer_from_wlr_layer_surface_v1(
diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c
index 50aa6938..d990d92a 100644
--- a/sway/desktop/layer_shell.c
+++ b/sway/desktop/layer_shell.c
@@ -17,6 +17,39 @@
17#include "sway/tree/arrange.h" 17#include "sway/tree/arrange.h"
18#include "sway/tree/workspace.h" 18#include "sway/tree/workspace.h"
19 19
20struct wlr_layer_surface_v1 *toplevel_layer_surface_from_surface(
21 struct wlr_surface *surface) {
22 struct wlr_layer_surface_v1 *layer;
23 do {
24 if (!surface) {
25 return NULL;
26 }
27 // Topmost layer surface
28 if ((layer = wlr_layer_surface_v1_try_from_wlr_surface(surface))) {
29 return layer;
30 }
31 // Layer subsurface
32 if (wlr_subsurface_try_from_wlr_surface(surface)) {
33 surface = wlr_surface_get_root_surface(surface);
34 continue;
35 }
36
37 // Layer surface popup
38 struct wlr_xdg_surface * xdg_popup = NULL;
39 if ((xdg_popup = wlr_xdg_surface_try_from_wlr_surface(surface)) &&
40 xdg_popup->role == WLR_XDG_SURFACE_ROLE_POPUP) {
41 if (!xdg_popup->popup->parent) {
42 return NULL;
43 }
44 surface = wlr_surface_get_root_surface(xdg_popup->popup->parent);
45 continue;
46 }
47
48 // Return early if the surface is not a layer/xdg_popup/sub surface
49 return NULL;
50 } while (true);
51}
52
20static void apply_exclusive(struct wlr_box *usable_area, 53static void apply_exclusive(struct wlr_box *usable_area,
21 uint32_t anchor, int32_t exclusive, 54 uint32_t anchor, int32_t exclusive,
22 int32_t margin_top, int32_t margin_right, 55 int32_t margin_top, int32_t margin_right,
@@ -218,7 +251,8 @@ void arrange_layers(struct sway_output *output) {
218 for (size_t i = 0; i < nlayers; ++i) { 251 for (size_t i = 0; i < nlayers; ++i) {
219 wl_list_for_each_reverse(layer, 252 wl_list_for_each_reverse(layer,
220 &output->layers[layers_above_shell[i]], link) { 253 &output->layers[layers_above_shell[i]], link) {
221 if (layer->layer_surface->current.keyboard_interactive && 254 if (layer->layer_surface->current.keyboard_interactive
255 == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE &&
222 layer->layer_surface->surface->mapped) { 256 layer->layer_surface->surface->mapped) {
223 topmost = layer; 257 topmost = layer;
224 break; 258 break;
@@ -231,10 +265,12 @@ void arrange_layers(struct sway_output *output) {
231 265
232 struct sway_seat *seat; 266 struct sway_seat *seat;
233 wl_list_for_each(seat, &server.input->seats, link) { 267 wl_list_for_each(seat, &server.input->seats, link) {
268 seat->has_exclusive_layer = false;
234 if (topmost != NULL) { 269 if (topmost != NULL) {
235 seat_set_focus_layer(seat, topmost->layer_surface); 270 seat_set_focus_layer(seat, topmost->layer_surface);
236 } else if (seat->focused_layer && 271 } else if (seat->focused_layer &&
237 !seat->focused_layer->current.keyboard_interactive) { 272 seat->focused_layer->current.keyboard_interactive
273 != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) {
238 seat_set_focus_layer(seat, NULL); 274 seat_set_focus_layer(seat, NULL);
239 } 275 }
240 } 276 }
diff --git a/sway/input/seat.c b/sway/input/seat.c
index 5795f40f..fdd21057 100644
--- a/sway/input/seat.c
+++ b/sway/input/seat.c
@@ -1295,11 +1295,15 @@ static void seat_set_workspace_focus(struct sway_seat *seat, struct sway_node *n
1295} 1295}
1296 1296
1297void seat_set_focus(struct sway_seat *seat, struct sway_node *node) { 1297void seat_set_focus(struct sway_seat *seat, struct sway_node *node) {
1298 if (seat->focused_layer) { 1298 // Prevents the layer from losing focus if it has keyboard exclusivity
1299 if (seat->has_exclusive_layer) {
1299 struct wlr_layer_surface_v1 *layer = seat->focused_layer; 1300 struct wlr_layer_surface_v1 *layer = seat->focused_layer;
1300 seat_set_focus_layer(seat, NULL); 1301 seat_set_focus_layer(seat, NULL);
1301 seat_set_workspace_focus(seat, node); 1302 seat_set_workspace_focus(seat, node);
1302 seat_set_focus_layer(seat, layer); 1303 seat_set_focus_layer(seat, layer);
1304 } else if (seat->focused_layer) {
1305 seat_set_focus_layer(seat, NULL);
1306 seat_set_workspace_focus(seat, node);
1303 } else { 1307 } else {
1304 seat_set_workspace_focus(seat, node); 1308 seat_set_workspace_focus(seat, node);
1305 } 1309 }
@@ -1347,14 +1351,20 @@ void seat_set_focus_layer(struct sway_seat *seat,
1347 seat_set_focus(seat, previous); 1351 seat_set_focus(seat, previous);
1348 } 1352 }
1349 return; 1353 return;
1350 } else if (!layer || seat->focused_layer == layer) { 1354 } else if (!layer) {
1351 return; 1355 return;
1352 } 1356 }
1353 assert(layer->surface->mapped); 1357 assert(layer->surface->mapped);
1354 seat_set_focus_surface(seat, layer->surface, true); 1358 if (layer->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP &&
1355 if (layer->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP) { 1359 layer->current.keyboard_interactive
1356 seat->focused_layer = layer; 1360 == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) {
1361 seat->has_exclusive_layer = true;
1362 }
1363 if (seat->focused_layer == layer) {
1364 return;
1357 } 1365 }
1366 seat_set_focus_surface(seat, layer->surface, true);
1367 seat->focused_layer = layer;
1358} 1368}
1359 1369
1360void seat_set_exclusive_client(struct sway_seat *seat, 1370void seat_set_exclusive_client(struct sway_seat *seat,
diff --git a/sway/input/seatop_default.c b/sway/input/seatop_default.c
index 5a55c186..f4c63808 100644
--- a/sway/input/seatop_default.c
+++ b/sway/input/seatop_default.c
@@ -2,6 +2,7 @@
2#include <float.h> 2#include <float.h>
3#include <libevdev/libevdev.h> 3#include <libevdev/libevdev.h>
4#include <wlr/types/wlr_cursor.h> 4#include <wlr/types/wlr_cursor.h>
5#include <wlr/types/wlr_subcompositor.h>
5#include <wlr/types/wlr_tablet_v2.h> 6#include <wlr/types/wlr_tablet_v2.h>
6#include <wlr/types/wlr_xcursor_manager.h> 7#include <wlr/types/wlr_xcursor_manager.h>
7#include "gesture.h" 8#include "gesture.h"
@@ -9,6 +10,7 @@
9#include "sway/input/cursor.h" 10#include "sway/input/cursor.h"
10#include "sway/input/seat.h" 11#include "sway/input/seat.h"
11#include "sway/input/tablet.h" 12#include "sway/input/tablet.h"
13#include "sway/layers.h"
12#include "sway/output.h" 14#include "sway/output.h"
13#include "sway/tree/view.h" 15#include "sway/tree/view.h"
14#include "sway/tree/workspace.h" 16#include "sway/tree/workspace.h"
@@ -365,10 +367,9 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
365 return; 367 return;
366 } 368 }
367 369
368 // Handle clicking a layer surface 370 // Handle clicking a layer surface and its popups/subsurfaces
369 struct wlr_layer_surface_v1 *layer; 371 struct wlr_layer_surface_v1 *layer = NULL;
370 if (surface && 372 if ((layer = toplevel_layer_surface_from_surface(surface))) {
371 (layer = wlr_layer_surface_v1_try_from_wlr_surface(surface))) {
372 if (layer->current.keyboard_interactive) { 373 if (layer->current.keyboard_interactive) {
373 seat_set_focus_layer(seat, layer); 374 seat_set_focus_layer(seat, layer);
374 transaction_commit_dirty(); 375 transaction_commit_dirty();
@@ -544,6 +545,21 @@ static void check_focus_follows_mouse(struct sway_seat *seat,
544 if (wlr_output == NULL) { 545 if (wlr_output == NULL) {
545 return; 546 return;
546 } 547 }
548
549 struct wlr_surface *surface = NULL;
550 double sx, sy;
551 node_at_coords(seat, seat->cursor->cursor->x, seat->cursor->cursor->y,
552 &surface, &sx, &sy);
553
554 // Focus topmost layer surface
555 struct wlr_layer_surface_v1 *layer = NULL;
556 if ((layer = toplevel_layer_surface_from_surface(surface)) &&
557 layer->current.keyboard_interactive) {
558 seat_set_focus_layer(seat, layer);
559 transaction_commit_dirty();
560 return;
561 }
562
547 struct sway_output *hovered_output = wlr_output->data; 563 struct sway_output *hovered_output = wlr_output->data;
548 if (focus && hovered_output != node_get_output(focus)) { 564 if (focus && hovered_output != node_get_output(focus)) {
549 struct sway_workspace *ws = output_get_active_workspace(hovered_output); 565 struct sway_workspace *ws = output_get_active_workspace(hovered_output);
diff --git a/sway/server.c b/sway/server.c
index 0cf767b7..c87e30fd 100644
--- a/sway/server.c
+++ b/sway/server.c
@@ -55,7 +55,7 @@
55#endif 55#endif
56 56
57#define SWAY_XDG_SHELL_VERSION 2 57#define SWAY_XDG_SHELL_VERSION 2
58#define SWAY_LAYER_SHELL_VERSION 3 58#define SWAY_LAYER_SHELL_VERSION 4
59 59
60#if WLR_HAS_DRM_BACKEND 60#if WLR_HAS_DRM_BACKEND
61static void handle_drm_lease_request(struct wl_listener *listener, void *data) { 61static void handle_drm_lease_request(struct wl_listener *listener, void *data) {