diff options
-rw-r--r-- | include/sway/input/seat.h | 3 | ||||
-rw-r--r-- | include/sway/layers.h | 4 | ||||
-rw-r--r-- | sway/desktop/layer_shell.c | 40 | ||||
-rw-r--r-- | sway/input/seat.c | 20 | ||||
-rw-r--r-- | sway/input/seatop_default.c | 24 | ||||
-rw-r--r-- | sway/server.c | 2 |
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 | ||
57 | struct sway_output; | 57 | struct sway_output; |
58 | |||
59 | struct wlr_layer_surface_v1 *toplevel_layer_surface_from_surface( | ||
60 | struct wlr_surface *surface); | ||
61 | |||
58 | void arrange_layers(struct sway_output *output); | 62 | void arrange_layers(struct sway_output *output); |
59 | 63 | ||
60 | struct sway_layer_surface *layer_from_wlr_layer_surface_v1( | 64 | struct 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 | ||
20 | struct 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 | |||
20 | static void apply_exclusive(struct wlr_box *usable_area, | 53 | static 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 | ||
1297 | void seat_set_focus(struct sway_seat *seat, struct sway_node *node) { | 1297 | void 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 | ||
1360 | void seat_set_exclusive_client(struct sway_seat *seat, | 1370 | void 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 |
61 | static void handle_drm_lease_request(struct wl_listener *listener, void *data) { | 61 | static void handle_drm_lease_request(struct wl_listener *listener, void *data) { |