mirror of
https://github.com/labwc/labwc.git
synced 2026-03-31 07:11:19 -04:00
layer: improve keyboard-interactivity
- Process layer-shell keyboard interactivity in the map and commit handlers only, rather than in layers_arrange(). This allows handling of the layer-surface that emitted the event rather than iterating over all surfaces in the output layer-tree, and therefore avoids having to guess which surface should have keyboard preference (and it might not be the last one added to the list which was the assumption previously). - Prevent seat_focus_surface() from setting keyboard focus if a layer-shell surface with exclusive keyboard-interactivity has the focus. - Set cursor_context type for layer-surfaces without node-descriptors in order to set keyboard focus correctly in cursor_button_press(). Tested satisfactorily with xfce4-panel and gtk-layer-demo. Fixes #725 and #704
This commit is contained in:
parent
4dc99e2f38
commit
6f3043b08d
3 changed files with 72 additions and 35 deletions
|
|
@ -323,6 +323,7 @@ get_cursor_context(struct server *server)
|
||||||
ret.type = LAB_SSD_ROOT;
|
ret.type = LAB_SSD_ROOT;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if HAVE_XWAYLAND
|
#if HAVE_XWAYLAND
|
||||||
if (node->type == WLR_SCENE_NODE_BUFFER) {
|
if (node->type == WLR_SCENE_NODE_BUFFER) {
|
||||||
struct wlr_surface *surface = lab_wlr_surface_from_node(node);
|
struct wlr_surface *surface = lab_wlr_surface_from_node(node);
|
||||||
|
|
@ -382,6 +383,9 @@ get_cursor_context(struct server *server)
|
||||||
if (node->type == WLR_SCENE_NODE_BUFFER) {
|
if (node->type == WLR_SCENE_NODE_BUFFER) {
|
||||||
struct wlr_surface *surface = lab_wlr_surface_from_node(node);
|
struct wlr_surface *surface = lab_wlr_surface_from_node(node);
|
||||||
if (surface) {
|
if (surface) {
|
||||||
|
if (wlr_surface_is_layer_surface(surface)) {
|
||||||
|
ret.type = LAB_SSD_LAYER_SURFACE;
|
||||||
|
}
|
||||||
if (is_layer_descendant(node)) {
|
if (is_layer_descendant(node)) {
|
||||||
/*
|
/*
|
||||||
* layer-shell subsurfaces need to be
|
* layer-shell subsurfaces need to be
|
||||||
|
|
|
||||||
86
src/layers.c
86
src/layers.c
|
|
@ -75,38 +75,6 @@ layers_arrange(struct output *output)
|
||||||
}
|
}
|
||||||
|
|
||||||
output->usable_area = usable_area;
|
output->usable_area = usable_area;
|
||||||
|
|
||||||
/* Find topmost keyboard interactive layer, if such a layer exists */
|
|
||||||
uint32_t layers_above_views[] = {
|
|
||||||
ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY,
|
|
||||||
ZWLR_LAYER_SHELL_V1_LAYER_TOP,
|
|
||||||
};
|
|
||||||
size_t nlayers = sizeof(layers_above_views) / sizeof(layers_above_views[0]);
|
|
||||||
struct lab_layer_surface *topmost = NULL;
|
|
||||||
struct wlr_scene_node *node;
|
|
||||||
for (size_t i = 0; i < nlayers; ++i) {
|
|
||||||
struct wlr_scene_tree *tree = output->layer_tree[layers_above_views[i]];
|
|
||||||
/* Iterate in reverse to give most recent node preference */
|
|
||||||
wl_list_for_each_reverse(node, &tree->children, link) {
|
|
||||||
struct lab_layer_surface *surface = node_layer_surface_from_node(node);
|
|
||||||
struct wlr_scene_layer_surface_v1 *scene = surface->scene_layer_surface;
|
|
||||||
if (scene->layer_surface->current.keyboard_interactive) {
|
|
||||||
topmost = surface;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (topmost) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
struct seat *seat = &output->server->seat;
|
|
||||||
if (topmost) {
|
|
||||||
seat_set_focus_layer(seat,
|
|
||||||
topmost->scene_layer_surface->layer_surface);
|
|
||||||
} else if (seat->focused_layer &&
|
|
||||||
!seat->focused_layer->current.keyboard_interactive) {
|
|
||||||
seat_set_focus_layer(seat, NULL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -118,6 +86,48 @@ handle_output_destroy(struct wl_listener *listener, void *data)
|
||||||
wlr_layer_surface_v1_destroy(layer->scene_layer_surface->layer_surface);
|
wlr_layer_surface_v1_destroy(layer->scene_layer_surface->layer_surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
process_keyboard_interactivity(struct lab_layer_surface *layer)
|
||||||
|
{
|
||||||
|
struct wlr_layer_surface_v1 *layer_surface = layer->scene_layer_surface->layer_surface;
|
||||||
|
struct seat *seat = &layer->server->seat;
|
||||||
|
|
||||||
|
if (layer_surface->current.keyboard_interactive
|
||||||
|
&& layer_surface->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP) {
|
||||||
|
/*
|
||||||
|
* Give keyboard focus to surface if
|
||||||
|
* - keyboard-interactivity is 'exclusive' or 'on-demand'; and
|
||||||
|
* - surface is in top/overlay layers; and
|
||||||
|
* - currently focused layer has a lower precedence
|
||||||
|
*
|
||||||
|
* In other words, when dealing with two surfaces with
|
||||||
|
* exclusive/on-demand keyboard-interactivity (firstly the
|
||||||
|
* currently focused 'focused_layer' and secondly the
|
||||||
|
* 'layer_surface' for which we're just responding to a
|
||||||
|
* map/commit event), the following logic applies:
|
||||||
|
*
|
||||||
|
* | focused_layer | layer_surface | who gets keyboard focus |
|
||||||
|
* |---------------|---------------|-------------------------|
|
||||||
|
* | overlay | top | focused_layer |
|
||||||
|
* | overlay | overlay | layer_surface |
|
||||||
|
* | top | top | layer_surface |
|
||||||
|
* | top | overlay | layer_surface |
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!seat->focused_layer || seat->focused_layer->current.layer
|
||||||
|
<= layer_surface->current.layer) {
|
||||||
|
seat_set_focus_layer(seat, layer_surface);
|
||||||
|
}
|
||||||
|
} else if (seat->focused_layer
|
||||||
|
&& !seat->focused_layer->current.keyboard_interactive) {
|
||||||
|
/*
|
||||||
|
* Clear focus if keyboard-interactivity has been set to
|
||||||
|
* ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE
|
||||||
|
*/
|
||||||
|
seat_set_focus_layer(seat, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
handle_surface_commit(struct wl_listener *listener, void *data)
|
handle_surface_commit(struct wl_listener *listener, void *data)
|
||||||
{
|
{
|
||||||
|
|
@ -140,6 +150,10 @@ handle_surface_commit(struct wl_listener *listener, void *data)
|
||||||
wlr_scene_node_reparent(&layer->scene_layer_surface->tree->node,
|
wlr_scene_node_reparent(&layer->scene_layer_surface->tree->node,
|
||||||
output->layer_tree[layer_surface->current.layer]);
|
output->layer_tree[layer_surface->current.layer]);
|
||||||
}
|
}
|
||||||
|
/* Process keyboard-interactivity change */
|
||||||
|
if (committed & WLR_LAYER_SURFACE_V1_STATE_KEYBOARD_INTERACTIVITY) {
|
||||||
|
process_keyboard_interactivity(layer);
|
||||||
|
}
|
||||||
|
|
||||||
if (committed || layer->mapped != layer_surface->mapped) {
|
if (committed || layer->mapped != layer_surface->mapped) {
|
||||||
layer->mapped = layer_surface->mapped;
|
layer->mapped = layer_surface->mapped;
|
||||||
|
|
@ -158,6 +172,12 @@ handle_node_destroy(struct wl_listener *listener, void *data)
|
||||||
struct lab_layer_surface *layer =
|
struct lab_layer_surface *layer =
|
||||||
wl_container_of(listener, layer, node_destroy);
|
wl_container_of(listener, layer, node_destroy);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: Determine if this layer is being used by an exclusive client.
|
||||||
|
* If it is, try and find another layer owned by this client to pass
|
||||||
|
* focus to.
|
||||||
|
*/
|
||||||
|
|
||||||
wl_list_remove(&layer->map.link);
|
wl_list_remove(&layer->map.link);
|
||||||
wl_list_remove(&layer->unmap.link);
|
wl_list_remove(&layer->unmap.link);
|
||||||
wl_list_remove(&layer->surface_commit.link);
|
wl_list_remove(&layer->surface_commit.link);
|
||||||
|
|
@ -197,6 +217,8 @@ handle_map(struct wl_listener *listener, void *data)
|
||||||
* automatically based on the position of the surface and outputs in
|
* automatically based on the position of the surface and outputs in
|
||||||
* the scene. See wlr_scene_surface_create() documentation.
|
* the scene. See wlr_scene_surface_create() documentation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
process_keyboard_interactivity(layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
||||||
17
src/seat.c
17
src/seat.c
|
|
@ -440,8 +440,8 @@ seat_reconfigure(struct server *server)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
seat_focus_surface(struct seat *seat, struct wlr_surface *surface)
|
seat_focus(struct seat *seat, struct wlr_surface *surface)
|
||||||
{
|
{
|
||||||
if (!surface) {
|
if (!surface) {
|
||||||
wlr_seat_keyboard_notify_clear_focus(seat->seat);
|
wlr_seat_keyboard_notify_clear_focus(seat->seat);
|
||||||
|
|
@ -469,6 +469,17 @@ seat_focus_surface(struct seat *seat, struct wlr_surface *surface)
|
||||||
constrain_cursor(server, constraint);
|
constrain_cursor(server, constraint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
seat_focus_surface(struct seat *seat, struct wlr_surface *surface)
|
||||||
|
{
|
||||||
|
/* Respect layer-shell exlusive keyboard-interactivity. */
|
||||||
|
if (seat->focused_layer && seat->focused_layer->current.keyboard_interactive
|
||||||
|
== ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
seat_focus(seat, surface);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
seat_set_focus_layer(struct seat *seat, struct wlr_layer_surface_v1 *layer)
|
seat_set_focus_layer(struct seat *seat, struct wlr_layer_surface_v1 *layer)
|
||||||
{
|
{
|
||||||
|
|
@ -477,7 +488,7 @@ seat_set_focus_layer(struct seat *seat, struct wlr_layer_surface_v1 *layer)
|
||||||
desktop_focus_topmost_mapped_view(seat->server);
|
desktop_focus_topmost_mapped_view(seat->server);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
seat_focus_surface(seat, layer->surface);
|
seat_focus(seat, layer->surface);
|
||||||
if (layer->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP) {
|
if (layer->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP) {
|
||||||
seat->focused_layer = layer;
|
seat->focused_layer = layer;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue