aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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 {
struct sway_workspace *workspace;
char *prev_workspace_name; // for workspace back_and_forth
- // If the focused layer is set, views cannot receive keyboard focus
struct wlr_layer_surface_v1 *focused_layer;
+ // If the exclusive layer is set, views cannot receive keyboard focus
+ bool has_exclusive_layer;
// If exclusive_client is set, no other clients will receive input events
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 {
};
struct sway_output;
+
+struct wlr_layer_surface_v1 *toplevel_layer_surface_from_surface(
+ struct wlr_surface *surface);
+
void arrange_layers(struct sway_output *output);
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 @@
#include "sway/tree/arrange.h"
#include "sway/tree/workspace.h"
+struct wlr_layer_surface_v1 *toplevel_layer_surface_from_surface(
+ struct wlr_surface *surface) {
+ struct wlr_layer_surface_v1 *layer;
+ do {
+ if (!surface) {
+ return NULL;
+ }
+ // Topmost layer surface
+ if ((layer = wlr_layer_surface_v1_try_from_wlr_surface(surface))) {
+ return layer;
+ }
+ // Layer subsurface
+ if (wlr_subsurface_try_from_wlr_surface(surface)) {
+ surface = wlr_surface_get_root_surface(surface);
+ continue;
+ }
+
+ // Layer surface popup
+ struct wlr_xdg_surface * xdg_popup = NULL;
+ if ((xdg_popup = wlr_xdg_surface_try_from_wlr_surface(surface)) &&
+ xdg_popup->role == WLR_XDG_SURFACE_ROLE_POPUP) {
+ if (!xdg_popup->popup->parent) {
+ return NULL;
+ }
+ surface = wlr_surface_get_root_surface(xdg_popup->popup->parent);
+ continue;
+ }
+
+ // Return early if the surface is not a layer/xdg_popup/sub surface
+ return NULL;
+ } while (true);
+}
+
static void apply_exclusive(struct wlr_box *usable_area,
uint32_t anchor, int32_t exclusive,
int32_t margin_top, int32_t margin_right,
@@ -218,7 +251,8 @@ void arrange_layers(struct sway_output *output) {
for (size_t i = 0; i < nlayers; ++i) {
wl_list_for_each_reverse(layer,
&output->layers[layers_above_shell[i]], link) {
- if (layer->layer_surface->current.keyboard_interactive &&
+ if (layer->layer_surface->current.keyboard_interactive
+ == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE &&
layer->layer_surface->surface->mapped) {
topmost = layer;
break;
@@ -231,10 +265,12 @@ void arrange_layers(struct sway_output *output) {
struct sway_seat *seat;
wl_list_for_each(seat, &server.input->seats, link) {
+ seat->has_exclusive_layer = false;
if (topmost != NULL) {
seat_set_focus_layer(seat, topmost->layer_surface);
} else if (seat->focused_layer &&
- !seat->focused_layer->current.keyboard_interactive) {
+ seat->focused_layer->current.keyboard_interactive
+ != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) {
seat_set_focus_layer(seat, NULL);
}
}
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
}
void seat_set_focus(struct sway_seat *seat, struct sway_node *node) {
- if (seat->focused_layer) {
+ // Prevents the layer from losing focus if it has keyboard exclusivity
+ if (seat->has_exclusive_layer) {
struct wlr_layer_surface_v1 *layer = seat->focused_layer;
seat_set_focus_layer(seat, NULL);
seat_set_workspace_focus(seat, node);
seat_set_focus_layer(seat, layer);
+ } else if (seat->focused_layer) {
+ seat_set_focus_layer(seat, NULL);
+ seat_set_workspace_focus(seat, node);
} else {
seat_set_workspace_focus(seat, node);
}
@@ -1347,14 +1351,20 @@ void seat_set_focus_layer(struct sway_seat *seat,
seat_set_focus(seat, previous);
}
return;
- } else if (!layer || seat->focused_layer == layer) {
+ } else if (!layer) {
return;
}
assert(layer->surface->mapped);
- seat_set_focus_surface(seat, layer->surface, true);
- if (layer->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP) {
- seat->focused_layer = layer;
+ if (layer->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP &&
+ layer->current.keyboard_interactive
+ == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) {
+ seat->has_exclusive_layer = true;
+ }
+ if (seat->focused_layer == layer) {
+ return;
}
+ seat_set_focus_surface(seat, layer->surface, true);
+ seat->focused_layer = layer;
}
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 @@
#include <float.h>
#include <libevdev/libevdev.h>
#include <wlr/types/wlr_cursor.h>
+#include <wlr/types/wlr_subcompositor.h>
#include <wlr/types/wlr_tablet_v2.h>
#include <wlr/types/wlr_xcursor_manager.h>
#include "gesture.h"
@@ -9,6 +10,7 @@
#include "sway/input/cursor.h"
#include "sway/input/seat.h"
#include "sway/input/tablet.h"
+#include "sway/layers.h"
#include "sway/output.h"
#include "sway/tree/view.h"
#include "sway/tree/workspace.h"
@@ -365,10 +367,9 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
return;
}
- // Handle clicking a layer surface
- struct wlr_layer_surface_v1 *layer;
- if (surface &&
- (layer = wlr_layer_surface_v1_try_from_wlr_surface(surface))) {
+ // Handle clicking a layer surface and its popups/subsurfaces
+ struct wlr_layer_surface_v1 *layer = NULL;
+ if ((layer = toplevel_layer_surface_from_surface(surface))) {
if (layer->current.keyboard_interactive) {
seat_set_focus_layer(seat, layer);
transaction_commit_dirty();
@@ -544,6 +545,21 @@ static void check_focus_follows_mouse(struct sway_seat *seat,
if (wlr_output == NULL) {
return;
}
+
+ struct wlr_surface *surface = NULL;
+ double sx, sy;
+ node_at_coords(seat, seat->cursor->cursor->x, seat->cursor->cursor->y,
+ &surface, &sx, &sy);
+
+ // Focus topmost layer surface
+ struct wlr_layer_surface_v1 *layer = NULL;
+ if ((layer = toplevel_layer_surface_from_surface(surface)) &&
+ layer->current.keyboard_interactive) {
+ seat_set_focus_layer(seat, layer);
+ transaction_commit_dirty();
+ return;
+ }
+
struct sway_output *hovered_output = wlr_output->data;
if (focus && hovered_output != node_get_output(focus)) {
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 @@
#endif
#define SWAY_XDG_SHELL_VERSION 2
-#define SWAY_LAYER_SHELL_VERSION 3
+#define SWAY_LAYER_SHELL_VERSION 4
#if WLR_HAS_DRM_BACKEND
static void handle_drm_lease_request(struct wl_listener *listener, void *data) {