Skip to content

Commit

Permalink
Adds support for ON_DEMAND layer surface keyboard interactivity
Browse files Browse the repository at this point in the history
  • Loading branch information
ErikReider committed May 21, 2023
1 parent 6d523ed commit 49fd0f4
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 20 deletions.
3 changes: 2 additions & 1 deletion include/sway/input/seat.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
struct wlr_layer_surface_v1 *exclusive_layer;

// If exclusive_client is set, no other clients will receive input events
struct wl_client *exclusive_client;
Expand Down
7 changes: 5 additions & 2 deletions sway/desktop/layer_shell.c
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,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->mapped) {
topmost = layer;
break;
Expand All @@ -234,7 +235,9 @@ void arrange_layers(struct sway_output *output) {
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->exclusive_layer = NULL;
seat_set_focus_layer(seat, NULL);
}
}
Expand Down
14 changes: 10 additions & 4 deletions sway/input/seat.c
Original file line number Diff line number Diff line change
Expand Up @@ -1347,14 +1347,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->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->exclusive_layer = layer;
}
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,
Expand Down
102 changes: 90 additions & 12 deletions sway/input/seatop_default.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -235,6 +236,7 @@ static void handle_tablet_tool_tip(struct sway_seat *seat,
if ((layer = wlr_layer_surface_v1_try_from_wlr_surface(surface)) &&
layer->current.keyboard_interactive) {
// Handle tapping a layer surface
seat_set_focus(seat, NULL);
seat_set_focus_layer(seat, layer);
transaction_commit_dirty();
} else if (cont) {
Expand Down Expand Up @@ -366,17 +368,48 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
}

// Handle clicking a layer surface
struct wlr_surface *layer_surface = surface;
struct wlr_layer_surface_v1 *layer;
if (surface &&
(layer = wlr_layer_surface_v1_try_from_wlr_surface(surface))) {
if (layer->current.keyboard_interactive
|| !(seat->focused_layer
&& seat->focused_layer->current.keyboard_interactive
&& seat->focused_layer != layer)) {
if (layer_surface &&
(layer = wlr_layer_surface_v1_try_from_wlr_surface(layer_surface))) {
if (layer->current.keyboard_interactive) {
seat_set_focus(seat, NULL);
seat_set_focus_layer(seat, layer);
transaction_commit_dirty();
}
if (state == WLR_BUTTON_PRESSED) {
seatop_begin_down_on_surface(seat, layer_surface, sx, sy);
}
seat_pointer_notify_button(seat, time_msec, button, state);
return;
}
// Handle clicking a layer subsurface
struct wlr_subsurface * subsurface = NULL;
if (surface &&
(subsurface = wlr_subsurface_try_from_wlr_surface(surface)) &&
(layer_surface = subsurface->parent) &&
(layer = wlr_layer_surface_v1_try_from_wlr_surface(layer_surface)) &&
layer->current.keyboard_interactive) {
seat_set_focus(seat, NULL);
seat_set_focus_layer(seat, layer);
transaction_commit_dirty();
if (state == WLR_BUTTON_PRESSED) {
seatop_begin_down_on_surface(seat, surface, sx, sy);
}
seat_pointer_notify_button(seat, time_msec, button, state);
return;
}
// Handle clicking a layer surface popup
struct wlr_xdg_surface * xdg_popup = NULL;
if (surface &&
(xdg_popup = wlr_xdg_surface_try_from_wlr_surface(surface)) &&
xdg_popup->role == WLR_XDG_SURFACE_ROLE_POPUP &&
(layer_surface = xdg_popup->popup->parent) &&
(layer = wlr_layer_surface_v1_try_from_wlr_surface(layer_surface)) &&
layer->current.keyboard_interactive) {
seat_set_focus(seat, NULL);
seat_set_focus_layer(seat, layer);
transaction_commit_dirty();
if (state == WLR_BUTTON_PRESSED) {
seatop_begin_down_on_surface(seat, surface, sx, sy);
}
Expand All @@ -386,7 +419,8 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,

// Don't change focus and don't send any inputs if there's a focused layer
// with keyboard exclusivity
if (seat->focused_layer && seat->focused_layer->current.keyboard_interactive) {
if (seat->exclusive_layer) {
seat_set_focus_layer(seat, seat->exclusive_layer);
return;
}

Expand Down Expand Up @@ -557,6 +591,49 @@ 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_surface *layer_surface = surface;
struct wlr_layer_surface_v1 *layer;
if (layer_surface &&
(layer = wlr_layer_surface_v1_try_from_wlr_surface(layer_surface))
&& layer->current.keyboard_interactive) {
seat_set_focus(seat, NULL);
seat_set_focus_layer(seat, layer);
transaction_commit_dirty();
return;
}
// Focus topmost layer subsurface
struct wlr_subsurface * subsurface = NULL;
if (surface &&
(subsurface = wlr_subsurface_try_from_wlr_surface(surface)) &&
(layer_surface = subsurface->parent) &&
(layer = wlr_layer_surface_v1_try_from_wlr_surface(layer_surface)) &&
layer->current.keyboard_interactive) {
seat_set_focus(seat, NULL);
seat_set_focus_layer(seat, layer);
transaction_commit_dirty();
return;
}
// Focus topmost layer surface popup
struct wlr_xdg_surface * xdg_popup = NULL;
if (surface &&
(xdg_popup = wlr_xdg_surface_try_from_wlr_surface(surface)) &&
xdg_popup->role == WLR_XDG_SURFACE_ROLE_POPUP &&
(layer_surface = xdg_popup->popup->parent) &&
(layer = wlr_layer_surface_v1_try_from_wlr_surface(layer_surface)) &&
layer->current.keyboard_interactive) {
seat_set_focus(seat, NULL);
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);
Expand All @@ -566,6 +643,12 @@ static void check_focus_follows_mouse(struct sway_seat *seat,
return;
}

// Prevents the layer from losing focus if it has keyboard exclusivity
if (seat->exclusive_layer) {
seat_set_focus_layer(seat, seat->exclusive_layer);
return;
}

// If a workspace node is hovered (eg. in the gap area), only set focus if
// the workspace is on a different output to the previous focus.
if (focus && hovered_node->type == N_WORKSPACE) {
Expand All @@ -578,11 +661,6 @@ static void check_focus_follows_mouse(struct sway_seat *seat,
return;
}

// Prevents the layer from losing focus if it has keyboard exclusivity
if (seat->focused_layer && seat->focused_layer->current.keyboard_interactive) {
return;
}

// This is where we handle the common case. We don't want to focus inactive
// tabs, hence the view_is_visible check.
if (node_is_view(hovered_node) &&
Expand Down
2 changes: 1 addition & 1 deletion sway/server.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down

0 comments on commit 49fd0f4

Please sign in to comment.