mirror of
https://github.com/swaywm/sway.git
synced 2024-11-25 17:31:28 +00:00
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.
This commit is contained in:
parent
7ab8cb2ee6
commit
913a7679cb
|
@ -104,8 +104,9 @@ struct sway_seat {
|
||||||
struct sway_workspace *workspace;
|
struct sway_workspace *workspace;
|
||||||
char *prev_workspace_name; // for workspace back_and_forth
|
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;
|
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
|
// If exclusive_client is set, no other clients will receive input events
|
||||||
struct wl_client *exclusive_client;
|
struct wl_client *exclusive_client;
|
||||||
|
|
|
@ -55,6 +55,10 @@ struct sway_layer_subsurface {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sway_output;
|
struct sway_output;
|
||||||
|
|
||||||
|
struct wlr_layer_surface_v1 *toplevel_layer_surface_from_surface(
|
||||||
|
struct wlr_surface *surface);
|
||||||
|
|
||||||
void arrange_layers(struct sway_output *output);
|
void arrange_layers(struct sway_output *output);
|
||||||
|
|
||||||
struct sway_layer_surface *layer_from_wlr_layer_surface_v1(
|
struct sway_layer_surface *layer_from_wlr_layer_surface_v1(
|
||||||
|
|
|
@ -17,6 +17,39 @@
|
||||||
#include "sway/tree/arrange.h"
|
#include "sway/tree/arrange.h"
|
||||||
#include "sway/tree/workspace.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,
|
static void apply_exclusive(struct wlr_box *usable_area,
|
||||||
uint32_t anchor, int32_t exclusive,
|
uint32_t anchor, int32_t exclusive,
|
||||||
int32_t margin_top, int32_t margin_right,
|
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) {
|
for (size_t i = 0; i < nlayers; ++i) {
|
||||||
wl_list_for_each_reverse(layer,
|
wl_list_for_each_reverse(layer,
|
||||||
&output->layers[layers_above_shell[i]], link) {
|
&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) {
|
layer->layer_surface->surface->mapped) {
|
||||||
topmost = layer;
|
topmost = layer;
|
||||||
break;
|
break;
|
||||||
|
@ -231,10 +265,12 @@ void arrange_layers(struct sway_output *output) {
|
||||||
|
|
||||||
struct sway_seat *seat;
|
struct sway_seat *seat;
|
||||||
wl_list_for_each(seat, &server.input->seats, link) {
|
wl_list_for_each(seat, &server.input->seats, link) {
|
||||||
|
seat->has_exclusive_layer = false;
|
||||||
if (topmost != NULL) {
|
if (topmost != NULL) {
|
||||||
seat_set_focus_layer(seat, topmost->layer_surface);
|
seat_set_focus_layer(seat, topmost->layer_surface);
|
||||||
} else if (seat->focused_layer &&
|
} 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);
|
seat_set_focus_layer(seat, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
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;
|
struct wlr_layer_surface_v1 *layer = seat->focused_layer;
|
||||||
seat_set_focus_layer(seat, NULL);
|
seat_set_focus_layer(seat, NULL);
|
||||||
seat_set_workspace_focus(seat, node);
|
seat_set_workspace_focus(seat, node);
|
||||||
seat_set_focus_layer(seat, layer);
|
seat_set_focus_layer(seat, layer);
|
||||||
|
} else if (seat->focused_layer) {
|
||||||
|
seat_set_focus_layer(seat, NULL);
|
||||||
|
seat_set_workspace_focus(seat, node);
|
||||||
} else {
|
} else {
|
||||||
seat_set_workspace_focus(seat, node);
|
seat_set_workspace_focus(seat, node);
|
||||||
}
|
}
|
||||||
|
@ -1347,14 +1351,20 @@ void seat_set_focus_layer(struct sway_seat *seat,
|
||||||
seat_set_focus(seat, previous);
|
seat_set_focus(seat, previous);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
} else if (!layer || seat->focused_layer == layer) {
|
} else if (!layer) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
assert(layer->surface->mapped);
|
assert(layer->surface->mapped);
|
||||||
seat_set_focus_surface(seat, layer->surface, true);
|
if (layer->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP &&
|
||||||
if (layer->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP) {
|
layer->current.keyboard_interactive
|
||||||
seat->focused_layer = layer;
|
== 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,
|
void seat_set_exclusive_client(struct sway_seat *seat,
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
#include <libevdev/libevdev.h>
|
#include <libevdev/libevdev.h>
|
||||||
#include <wlr/types/wlr_cursor.h>
|
#include <wlr/types/wlr_cursor.h>
|
||||||
|
#include <wlr/types/wlr_subcompositor.h>
|
||||||
#include <wlr/types/wlr_tablet_v2.h>
|
#include <wlr/types/wlr_tablet_v2.h>
|
||||||
#include <wlr/types/wlr_xcursor_manager.h>
|
#include <wlr/types/wlr_xcursor_manager.h>
|
||||||
#include "gesture.h"
|
#include "gesture.h"
|
||||||
|
@ -9,6 +10,7 @@
|
||||||
#include "sway/input/cursor.h"
|
#include "sway/input/cursor.h"
|
||||||
#include "sway/input/seat.h"
|
#include "sway/input/seat.h"
|
||||||
#include "sway/input/tablet.h"
|
#include "sway/input/tablet.h"
|
||||||
|
#include "sway/layers.h"
|
||||||
#include "sway/output.h"
|
#include "sway/output.h"
|
||||||
#include "sway/tree/view.h"
|
#include "sway/tree/view.h"
|
||||||
#include "sway/tree/workspace.h"
|
#include "sway/tree/workspace.h"
|
||||||
|
@ -365,10 +367,9 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle clicking a layer surface
|
// Handle clicking a layer surface and its popups/subsurfaces
|
||||||
struct wlr_layer_surface_v1 *layer;
|
struct wlr_layer_surface_v1 *layer = NULL;
|
||||||
if (surface &&
|
if ((layer = toplevel_layer_surface_from_surface(surface))) {
|
||||||
(layer = wlr_layer_surface_v1_try_from_wlr_surface(surface))) {
|
|
||||||
if (layer->current.keyboard_interactive) {
|
if (layer->current.keyboard_interactive) {
|
||||||
seat_set_focus_layer(seat, layer);
|
seat_set_focus_layer(seat, layer);
|
||||||
transaction_commit_dirty();
|
transaction_commit_dirty();
|
||||||
|
@ -544,6 +545,21 @@ static void check_focus_follows_mouse(struct sway_seat *seat,
|
||||||
if (wlr_output == NULL) {
|
if (wlr_output == NULL) {
|
||||||
return;
|
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;
|
struct sway_output *hovered_output = wlr_output->data;
|
||||||
if (focus && hovered_output != node_get_output(focus)) {
|
if (focus && hovered_output != node_get_output(focus)) {
|
||||||
struct sway_workspace *ws = output_get_active_workspace(hovered_output);
|
struct sway_workspace *ws = output_get_active_workspace(hovered_output);
|
||||||
|
|
|
@ -55,7 +55,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define SWAY_XDG_SHELL_VERSION 2
|
#define SWAY_XDG_SHELL_VERSION 2
|
||||||
#define SWAY_LAYER_SHELL_VERSION 3
|
#define SWAY_LAYER_SHELL_VERSION 4
|
||||||
|
|
||||||
#if WLR_HAS_DRM_BACKEND
|
#if WLR_HAS_DRM_BACKEND
|
||||||
static void handle_drm_lease_request(struct wl_listener *listener, void *data) {
|
static void handle_drm_lease_request(struct wl_listener *listener, void *data) {
|
||||||
|
|
Loading…
Reference in a new issue