mirror of
https://github.com/cage-kiosk/cage.git
synced 2026-02-07 04:06:41 -05:00
layer-shell: initial layer shell v1 implementation
This commit is contained in:
parent
0e946d5a4f
commit
8a11a66d87
8 changed files with 538 additions and 24 deletions
1
cage.c
1
cage.c
|
|
@ -617,6 +617,7 @@ main(int argc, char *argv[])
|
|||
|
||||
wl_list_remove(&server.new_virtual_pointer.link);
|
||||
wl_list_remove(&server.new_virtual_keyboard.link);
|
||||
wl_list_remove(&server.new_layer_shell_v1_surface.link);
|
||||
wl_list_remove(&server.output_manager_apply.link);
|
||||
wl_list_remove(&server.output_manager_test.link);
|
||||
wl_list_remove(&server.xdg_toplevel_decoration.link);
|
||||
|
|
|
|||
310
layer_shell_v1.c
310
layer_shell_v1.c
|
|
@ -6,13 +6,263 @@
|
|||
* See the LICENSE file accompanying this file.
|
||||
*/
|
||||
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
|
||||
#include "layer_shell_v1.h"
|
||||
#include "output.h"
|
||||
#include "seat.h"
|
||||
#include "server.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <wayland-server-core.h>
|
||||
#include <wlr/types/wlr_fractional_scale_v1.h>
|
||||
#include <wlr/types/wlr_layer_shell_v1.h>
|
||||
#include <wlr/types/wlr_output_layout.h>
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
#include <wlr/types/wlr_xdg_shell.h>
|
||||
#include <wlr/util/log.h>
|
||||
|
||||
static struct wlr_scene_tree *
|
||||
get_layer_scene(struct cg_output *output, enum zwlr_layer_shell_v1_layer type)
|
||||
{
|
||||
switch (type) {
|
||||
case ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND:
|
||||
return output->layers.shell_background;
|
||||
case ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM:
|
||||
return output->layers.shell_bottom;
|
||||
case ZWLR_LAYER_SHELL_V1_LAYER_TOP:
|
||||
return output->layers.shell_top;
|
||||
case ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY:
|
||||
return output->layers.shell_overlay;
|
||||
}
|
||||
|
||||
wlr_log(WLR_ERROR, "Invalid layer shell layer: %d", type);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void popup_handle_destroy(struct wl_listener *listener, void *data);
|
||||
static void popup_handle_new_popup(struct wl_listener *listener, void *data);
|
||||
static void popup_handle_commit(struct wl_listener *listener, void *data);
|
||||
|
||||
static void
|
||||
popup_unconstrain(struct cg_layer_popup *popup)
|
||||
{
|
||||
struct wlr_xdg_popup *wlr_popup = popup->wlr_popup;
|
||||
struct cg_output *output = popup->toplevel->output;
|
||||
|
||||
if (!output) {
|
||||
return;
|
||||
}
|
||||
|
||||
int lx, ly;
|
||||
wlr_scene_node_coords(&popup->toplevel->scene->tree->node, &lx, &ly);
|
||||
|
||||
struct wlr_box output_box;
|
||||
wlr_output_layout_get_box(output->server->output_layout, output->wlr_output, &output_box);
|
||||
|
||||
struct wlr_box output_toplevel_sx_box = {
|
||||
.x = output_box.x - lx,
|
||||
.y = output_box.y - ly,
|
||||
.width = output->wlr_output->width,
|
||||
.height = output->wlr_output->height,
|
||||
};
|
||||
|
||||
wlr_xdg_popup_unconstrain_from_box(wlr_popup, &output_toplevel_sx_box);
|
||||
}
|
||||
|
||||
static void
|
||||
popup_handle_commit(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct cg_layer_popup *popup = wl_container_of(listener, popup, commit);
|
||||
if (popup->wlr_popup->base->initial_commit) {
|
||||
popup_unconstrain(popup);
|
||||
}
|
||||
}
|
||||
|
||||
static struct cg_layer_popup *
|
||||
create_popup(struct wlr_xdg_popup *wlr_popup, struct cg_layer_surface *toplevel, struct wlr_scene_tree *parent)
|
||||
{
|
||||
struct cg_layer_popup *popup = calloc(1, sizeof(*popup));
|
||||
if (popup == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
popup->toplevel = toplevel;
|
||||
popup->wlr_popup = wlr_popup;
|
||||
popup->scene = wlr_scene_xdg_surface_create(parent, wlr_popup->base);
|
||||
|
||||
if (!popup->scene) {
|
||||
free(popup);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
popup->destroy.notify = popup_handle_destroy;
|
||||
wl_signal_add(&wlr_popup->base->events.destroy, &popup->destroy);
|
||||
popup->new_popup.notify = popup_handle_new_popup;
|
||||
wl_signal_add(&wlr_popup->base->events.new_popup, &popup->new_popup);
|
||||
popup->commit.notify = popup_handle_commit;
|
||||
wl_signal_add(&wlr_popup->base->surface->events.commit, &popup->commit);
|
||||
|
||||
return popup;
|
||||
}
|
||||
|
||||
static void
|
||||
popup_handle_destroy(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct cg_layer_popup *popup = wl_container_of(listener, popup, destroy);
|
||||
|
||||
wl_list_remove(&popup->destroy.link);
|
||||
wl_list_remove(&popup->new_popup.link);
|
||||
wl_list_remove(&popup->commit.link);
|
||||
free(popup);
|
||||
}
|
||||
|
||||
static void
|
||||
popup_handle_new_popup(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct cg_layer_popup *popup = wl_container_of(listener, popup, new_popup);
|
||||
struct wlr_xdg_popup *wlr_popup = data;
|
||||
create_popup(wlr_popup, popup->toplevel, popup->scene);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_new_popup(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct cg_layer_surface *layer_surface = wl_container_of(listener, layer_surface, new_popup);
|
||||
struct wlr_xdg_popup *wlr_popup = data;
|
||||
create_popup(wlr_popup, layer_surface, layer_surface->popups);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_surface_commit(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct cg_layer_surface *surface = wl_container_of(listener, surface, surface_commit);
|
||||
struct wlr_layer_surface_v1 *layer_surface = surface->layer_surface;
|
||||
uint32_t committed = layer_surface->current.committed;
|
||||
|
||||
if (!surface->output) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (layer_surface->initial_commit) {
|
||||
wlr_fractional_scale_v1_notify_scale(layer_surface->surface, layer_surface->output->scale);
|
||||
wlr_surface_set_preferred_buffer_scale(layer_surface->surface, ceil(layer_surface->output->scale));
|
||||
}
|
||||
|
||||
if (layer_surface->initialized && committed & WLR_LAYER_SURFACE_V1_STATE_LAYER) {
|
||||
enum zwlr_layer_shell_v1_layer layer_type = layer_surface->current.layer;
|
||||
struct wlr_scene_tree *output_layer = get_layer_scene(surface->output, layer_type);
|
||||
if (output_layer) {
|
||||
wlr_scene_node_reparent(&surface->scene->tree->node, output_layer);
|
||||
wlr_scene_node_reparent(&surface->popups->node, &surface->output->server->scene->tree);
|
||||
}
|
||||
}
|
||||
|
||||
bool mapped_changed = layer_surface->surface->mapped != surface->mapped;
|
||||
if (!layer_surface->initial_commit && !committed && !mapped_changed) {
|
||||
return;
|
||||
}
|
||||
|
||||
surface->mapped = layer_surface->surface->mapped;
|
||||
arrange_layers(surface->output);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_map(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct cg_layer_surface *surface = wl_container_of(listener, surface, map);
|
||||
struct wlr_layer_surface_v1 *layer_surface = surface->scene->layer_surface;
|
||||
|
||||
if (!surface->output) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct cg_seat *seat = surface->output->server->seat;
|
||||
|
||||
wlr_scene_node_set_enabled(&surface->scene->tree->node, true);
|
||||
|
||||
if (layer_surface->current.keyboard_interactive &&
|
||||
(layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY ||
|
||||
layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP)) {
|
||||
if (!seat->focused_layer || seat->focused_layer->current.layer >= layer_surface->current.layer) {
|
||||
seat_set_focus_layer(seat, layer_surface);
|
||||
}
|
||||
}
|
||||
|
||||
arrange_layers(surface->output);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_unmap(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct cg_layer_surface *surface = wl_container_of(listener, surface, unmap);
|
||||
|
||||
wlr_scene_node_set_enabled(&surface->scene->tree->node, false);
|
||||
|
||||
if (!surface->output) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct cg_seat *seat = surface->output->server->seat;
|
||||
|
||||
if (seat->focused_layer == surface->layer_surface) {
|
||||
seat_set_focus_layer(seat, NULL);
|
||||
}
|
||||
|
||||
arrange_layers(surface->output);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_node_destroy(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct cg_layer_surface *layer = wl_container_of(listener, layer, node_destroy);
|
||||
|
||||
if (layer->output) {
|
||||
arrange_layers(layer->output);
|
||||
}
|
||||
|
||||
wlr_scene_node_destroy(&layer->popups->node);
|
||||
|
||||
wl_list_remove(&layer->map.link);
|
||||
wl_list_remove(&layer->unmap.link);
|
||||
wl_list_remove(&layer->surface_commit.link);
|
||||
wl_list_remove(&layer->node_destroy.link);
|
||||
wl_list_remove(&layer->new_popup.link);
|
||||
|
||||
layer->layer_surface->data = NULL;
|
||||
|
||||
wl_list_remove(&layer->link);
|
||||
free(layer);
|
||||
}
|
||||
|
||||
static struct cg_layer_surface *
|
||||
create_layer_surface(struct wlr_scene_layer_surface_v1 *scene, struct cg_output *output)
|
||||
{
|
||||
struct cg_layer_surface *surface = calloc(1, sizeof(*surface));
|
||||
if (!surface) {
|
||||
wlr_log(WLR_ERROR, "Could not allocate a layer surface");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct wlr_scene_tree *popups = wlr_scene_tree_create(&output->server->scene->tree);
|
||||
if (!popups) {
|
||||
wlr_log(WLR_ERROR, "Could not allocate a layer popup node");
|
||||
free(surface);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
surface->tree = scene->tree;
|
||||
surface->scene = scene;
|
||||
surface->layer_surface = scene->layer_surface;
|
||||
surface->popups = popups;
|
||||
surface->layer_surface->data = surface;
|
||||
surface->output = output;
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
void
|
||||
handle_layer_shell_v1_surface_new(struct wl_listener *listener, void *data)
|
||||
{
|
||||
|
|
@ -24,4 +274,64 @@ handle_layer_shell_v1_surface_new(struct wl_listener *listener, void *data)
|
|||
layer_surface->pending.desired_width, layer_surface->pending.desired_height,
|
||||
layer_surface->pending.margin.top, layer_surface->pending.margin.right,
|
||||
layer_surface->pending.margin.bottom, layer_surface->pending.margin.left);
|
||||
|
||||
if (!layer_surface->output) {
|
||||
struct cg_seat *seat = server->seat;
|
||||
if (seat && seat->focused_output) {
|
||||
layer_surface->output = seat->focused_output;
|
||||
} else if (!wl_list_empty(&server->outputs)) {
|
||||
struct cg_output *output = wl_container_of(server->outputs.next, output, link);
|
||||
layer_surface->output = output->wlr_output;
|
||||
} else {
|
||||
wlr_log(WLR_ERROR, "No output to assign layer surface '%s' to", layer_surface->namespace);
|
||||
wlr_layer_surface_v1_destroy(layer_surface);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
struct cg_output *output = layer_surface->output->data;
|
||||
if (!output) {
|
||||
wlr_log(WLR_ERROR, "Layer surface has no output data");
|
||||
wlr_layer_surface_v1_destroy(layer_surface);
|
||||
return;
|
||||
}
|
||||
|
||||
enum zwlr_layer_shell_v1_layer layer_type = layer_surface->pending.layer;
|
||||
struct wlr_scene_tree *output_layer = get_layer_scene(output, layer_type);
|
||||
if (!output_layer) {
|
||||
wlr_log(WLR_ERROR, "Invalid layer %d for layer surface '%s'", layer_type, layer_surface->namespace);
|
||||
wlr_layer_surface_v1_destroy(layer_surface);
|
||||
return;
|
||||
}
|
||||
|
||||
struct wlr_scene_layer_surface_v1 *scene_surface =
|
||||
wlr_scene_layer_surface_v1_create(output_layer, layer_surface);
|
||||
if (!scene_surface) {
|
||||
wlr_log(WLR_ERROR, "Could not allocate a layer_surface_v1");
|
||||
return;
|
||||
}
|
||||
|
||||
struct cg_layer_surface *surface = create_layer_surface(scene_surface, output);
|
||||
if (!surface) {
|
||||
wlr_layer_surface_v1_destroy(layer_surface);
|
||||
wlr_log(WLR_ERROR, "Could not allocate a layer surface");
|
||||
return;
|
||||
}
|
||||
|
||||
wl_list_insert(&output->layer_surfaces, &surface->link);
|
||||
|
||||
wlr_fractional_scale_v1_notify_scale(surface->layer_surface->surface, layer_surface->output->scale);
|
||||
wlr_surface_set_preferred_buffer_scale(surface->layer_surface->surface, ceil(layer_surface->output->scale));
|
||||
|
||||
surface->surface_commit.notify = handle_surface_commit;
|
||||
wl_signal_add(&layer_surface->surface->events.commit, &surface->surface_commit);
|
||||
surface->map.notify = handle_map;
|
||||
wl_signal_add(&layer_surface->surface->events.map, &surface->map);
|
||||
surface->unmap.notify = handle_unmap;
|
||||
wl_signal_add(&layer_surface->surface->events.unmap, &surface->unmap);
|
||||
surface->new_popup.notify = handle_new_popup;
|
||||
wl_signal_add(&layer_surface->events.new_popup, &surface->new_popup);
|
||||
|
||||
surface->node_destroy.notify = handle_node_destroy;
|
||||
wl_signal_add(&scene_surface->tree->node.events.destroy, &surface->node_destroy);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,41 @@
|
|||
#ifndef CG_LAYER_SHELL_V1_H
|
||||
#define CG_LAYER_SHELL_V1_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <wayland-server-core.h>
|
||||
#include <wlr/types/wlr_layer_shell_v1.h>
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
|
||||
struct cg_output;
|
||||
|
||||
struct cg_layer_surface {
|
||||
struct wl_listener map;
|
||||
struct wl_listener unmap;
|
||||
struct wl_listener surface_commit;
|
||||
struct wl_listener node_destroy;
|
||||
struct wl_listener new_popup;
|
||||
|
||||
bool mapped;
|
||||
|
||||
struct wlr_scene_tree *popups;
|
||||
|
||||
struct cg_output *output;
|
||||
struct wl_list link; // cg_output::layer_surfaces
|
||||
|
||||
struct wlr_scene_layer_surface_v1 *scene;
|
||||
struct wlr_scene_tree *tree;
|
||||
struct wlr_layer_surface_v1 *layer_surface;
|
||||
};
|
||||
|
||||
struct cg_layer_popup {
|
||||
struct wlr_xdg_popup *wlr_popup;
|
||||
struct wlr_scene_tree *scene;
|
||||
struct cg_layer_surface *toplevel;
|
||||
|
||||
struct wl_listener destroy;
|
||||
struct wl_listener new_popup;
|
||||
struct wl_listener commit;
|
||||
};
|
||||
|
||||
void handle_layer_shell_v1_surface_new(struct wl_listener *listener, void *data);
|
||||
|
||||
|
|
|
|||
120
output.c
120
output.c
|
|
@ -21,6 +21,11 @@
|
|||
#if WLR_HAS_X11_BACKEND
|
||||
#include <wlr/backend/x11.h>
|
||||
#endif
|
||||
#include "layer_shell_v1.h"
|
||||
#include "output.h"
|
||||
#include "seat.h"
|
||||
#include "server.h"
|
||||
#include "view.h"
|
||||
#include <wlr/render/swapchain.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/types/wlr_compositor.h>
|
||||
|
|
@ -33,11 +38,6 @@
|
|||
#include <wlr/types/wlr_xdg_shell.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include <wlr/util/region.h>
|
||||
|
||||
#include "output.h"
|
||||
#include "seat.h"
|
||||
#include "server.h"
|
||||
#include "view.h"
|
||||
#if CAGE_HAS_XWAYLAND
|
||||
#include "xwayland.h"
|
||||
#endif
|
||||
|
|
@ -205,12 +205,23 @@ output_destroy(struct cg_output *output)
|
|||
|
||||
output->wlr_output->data = NULL;
|
||||
|
||||
struct cg_layer_surface *layer, *layer_tmp;
|
||||
wl_list_for_each_safe (layer, layer_tmp, &output->layer_surfaces, link) {
|
||||
layer->output = NULL;
|
||||
wlr_layer_surface_v1_destroy(layer->layer_surface);
|
||||
}
|
||||
|
||||
wl_list_remove(&output->destroy.link);
|
||||
wl_list_remove(&output->commit.link);
|
||||
wl_list_remove(&output->request_state.link);
|
||||
wl_list_remove(&output->frame.link);
|
||||
wl_list_remove(&output->link);
|
||||
|
||||
wlr_scene_node_destroy(&output->layers.shell_background->node);
|
||||
wlr_scene_node_destroy(&output->layers.shell_bottom->node);
|
||||
wlr_scene_node_destroy(&output->layers.shell_top->node);
|
||||
wlr_scene_node_destroy(&output->layers.shell_overlay->node);
|
||||
|
||||
output_layout_remove(output);
|
||||
|
||||
free(output);
|
||||
|
|
@ -231,6 +242,18 @@ handle_output_destroy(struct wl_listener *listener, void *data)
|
|||
output_destroy(output);
|
||||
}
|
||||
|
||||
static struct wlr_scene_tree *
|
||||
create_layer_for_output(struct cg_output *output)
|
||||
{
|
||||
struct cg_server *server = output->server;
|
||||
struct wlr_scene_tree *layer = wlr_scene_tree_create(&server->scene->tree);
|
||||
if (layer == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
layer->node.data = output->wlr_output;
|
||||
return layer;
|
||||
}
|
||||
|
||||
void
|
||||
handle_new_output(struct wl_listener *listener, void *data)
|
||||
{
|
||||
|
|
@ -252,6 +275,7 @@ handle_new_output(struct wl_listener *listener, void *data)
|
|||
wlr_output->data = output;
|
||||
output->server = server;
|
||||
|
||||
wl_list_init(&output->layer_surfaces);
|
||||
wl_list_insert(&server->outputs, &output->link);
|
||||
|
||||
output->commit.notify = handle_output_commit;
|
||||
|
|
@ -296,6 +320,11 @@ handle_new_output(struct wl_listener *listener, void *data)
|
|||
output_disable(next);
|
||||
}
|
||||
|
||||
output->layers.shell_background = create_layer_for_output(output);
|
||||
output->layers.shell_bottom = create_layer_for_output(output);
|
||||
output->layers.shell_top = create_layer_for_output(output);
|
||||
output->layers.shell_overlay = create_layer_for_output(output);
|
||||
|
||||
if (!wlr_xcursor_manager_load(server->seat->xcursor_manager, wlr_output->scale)) {
|
||||
wlr_log(WLR_ERROR, "Cannot load XCursor theme for output '%s' with scale %f", wlr_output->name,
|
||||
wlr_output->scale);
|
||||
|
|
@ -391,6 +420,87 @@ out:
|
|||
return ok;
|
||||
}
|
||||
|
||||
static void
|
||||
arrange_surface(struct cg_output *output, const struct wlr_box *full_area, struct wlr_box *usable_area,
|
||||
enum zwlr_layer_shell_v1_layer layer, bool exclusive)
|
||||
{
|
||||
struct cg_layer_surface *surface;
|
||||
wl_list_for_each (surface, &output->layer_surfaces, link) {
|
||||
struct wlr_layer_surface_v1 *layer_surface = surface->layer_surface;
|
||||
|
||||
if (layer_surface->current.layer != layer) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!layer_surface->initialized) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((layer_surface->current.exclusive_zone > 0) != exclusive) {
|
||||
continue;
|
||||
}
|
||||
|
||||
wlr_scene_layer_surface_v1_configure(surface->scene, full_area, usable_area);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
arrange_layers(struct cg_output *output)
|
||||
{
|
||||
struct wlr_box usable_area = {0};
|
||||
wlr_output_effective_resolution(output->wlr_output, &usable_area.width, &usable_area.height);
|
||||
const struct wlr_box full_area = usable_area;
|
||||
|
||||
arrange_surface(output, &full_area, &usable_area, ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, true);
|
||||
arrange_surface(output, &full_area, &usable_area, ZWLR_LAYER_SHELL_V1_LAYER_TOP, true);
|
||||
arrange_surface(output, &full_area, &usable_area, ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM, true);
|
||||
arrange_surface(output, &full_area, &usable_area, ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND, true);
|
||||
|
||||
arrange_surface(output, &full_area, &usable_area, ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, false);
|
||||
arrange_surface(output, &full_area, &usable_area, ZWLR_LAYER_SHELL_V1_LAYER_TOP, false);
|
||||
arrange_surface(output, &full_area, &usable_area, ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM, false);
|
||||
arrange_surface(output, &full_area, &usable_area, ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND, false);
|
||||
|
||||
if (!wlr_box_equal(&usable_area, &output->usable_area)) {
|
||||
wlr_log(WLR_DEBUG, "Usable area changed, rearranging output");
|
||||
output->usable_area = usable_area;
|
||||
view_position_all(output->server);
|
||||
}
|
||||
|
||||
enum zwlr_layer_shell_v1_layer layers_above_shell[] = {
|
||||
ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY,
|
||||
ZWLR_LAYER_SHELL_V1_LAYER_TOP,
|
||||
};
|
||||
size_t nlayers = sizeof(layers_above_shell) / sizeof(layers_above_shell[0]);
|
||||
struct cg_layer_surface *topmost = NULL;
|
||||
for (size_t i = 0; i < nlayers; ++i) {
|
||||
struct cg_layer_surface *surface;
|
||||
wl_list_for_each_reverse (surface, &output->layer_surfaces, link) {
|
||||
struct wlr_layer_surface_v1 *layer_surface = surface->layer_surface;
|
||||
if (layer_surface->current.layer != layers_above_shell[i]) {
|
||||
continue;
|
||||
}
|
||||
if (layer_surface->current.keyboard_interactive ==
|
||||
ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE &&
|
||||
layer_surface->surface->mapped) {
|
||||
topmost = surface;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (topmost != NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct cg_seat *seat = output->server->seat;
|
||||
if (topmost != NULL) {
|
||||
seat_set_focus_layer(seat, topmost->layer_surface);
|
||||
} else if (seat->focused_layer && seat->focused_layer->current.keyboard_interactive !=
|
||||
ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) {
|
||||
seat_set_focus_layer(seat, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
handle_output_manager_apply(struct wl_listener *listener, void *data)
|
||||
{
|
||||
|
|
|
|||
12
output.h
12
output.h
|
|
@ -17,6 +17,17 @@ struct cg_output {
|
|||
struct wl_listener destroy;
|
||||
struct wl_listener frame;
|
||||
|
||||
struct {
|
||||
struct wlr_scene_tree *shell_background;
|
||||
struct wlr_scene_tree *shell_bottom;
|
||||
struct wlr_scene_tree *shell_top;
|
||||
struct wlr_scene_tree *shell_overlay;
|
||||
} layers;
|
||||
|
||||
struct wlr_box usable_area;
|
||||
|
||||
struct wl_list layer_surfaces; // cg_layer_surface::link
|
||||
|
||||
struct wl_list link; // cg_server::outputs
|
||||
};
|
||||
|
||||
|
|
@ -25,5 +36,6 @@ void handle_output_manager_test(struct wl_listener *listener, void *data);
|
|||
void handle_output_layout_change(struct wl_listener *listener, void *data);
|
||||
void handle_new_output(struct wl_listener *listener, void *data);
|
||||
void output_set_window_title(struct cg_output *output, const char *title);
|
||||
void arrange_layers(struct cg_output *output);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
59
seat.c
59
seat.c
|
|
@ -74,17 +74,23 @@ desktop_view_at(struct cg_server *server, double lx, double ly, struct wlr_surfa
|
|||
|
||||
/* Walk up the tree until we find a node with a data pointer. When done,
|
||||
* we've found the node representing the view. */
|
||||
while (!node->data) {
|
||||
while (node) {
|
||||
if (node->data) {
|
||||
struct cg_view *candidate = node->data;
|
||||
struct cg_view *view;
|
||||
wl_list_for_each (view, &server->views, link) {
|
||||
if (view == candidate) {
|
||||
return view;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!node->parent) {
|
||||
node = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
node = &node->parent->node;
|
||||
}
|
||||
|
||||
assert(node != NULL);
|
||||
return node->data;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -104,7 +110,7 @@ press_cursor_button(struct cg_seat *seat, struct wlr_input_device *device, uint3
|
|||
|
||||
/* Focus that client if the button was pressed and
|
||||
it has no open dialogs. */
|
||||
if (view && !view_is_transient_for(current, view)) {
|
||||
if (view && (!current || !view_is_transient_for(current, view))) {
|
||||
seat_set_focus(seat, view);
|
||||
}
|
||||
}
|
||||
|
|
@ -625,8 +631,8 @@ process_cursor_motion(struct cg_seat *seat, uint32_t time_msec, double dx, doubl
|
|||
struct wlr_seat *wlr_seat = seat->seat;
|
||||
struct wlr_surface *surface = NULL;
|
||||
|
||||
struct cg_view *view = desktop_view_at(seat->server, seat->cursor->x, seat->cursor->y, &surface, &sx, &sy);
|
||||
if (!view) {
|
||||
desktop_view_at(seat->server, seat->cursor->x, seat->cursor->y, &surface, &sx, &sy);
|
||||
if (!surface) {
|
||||
wlr_seat_pointer_clear_focus(wlr_seat);
|
||||
} else {
|
||||
wlr_seat_pointer_notify_enter(wlr_seat, surface, sx, sy);
|
||||
|
|
@ -787,8 +793,7 @@ handle_destroy(struct wl_listener *listener, void *data)
|
|||
|
||||
struct cg_keyboard_group *group, *group_tmp;
|
||||
wl_list_for_each_safe (group, group_tmp, &seat->keyboard_groups, link) {
|
||||
wlr_keyboard_group_destroy(group->wlr_group);
|
||||
free(group);
|
||||
keyboard_group_destroy(group);
|
||||
}
|
||||
struct cg_pointer *pointer, *pointer_tmp;
|
||||
wl_list_for_each_safe (pointer, pointer_tmp, &seat->pointers, link) {
|
||||
|
|
@ -910,6 +915,7 @@ seat_destroy(struct cg_seat *seat)
|
|||
|
||||
// Destroying the wlr seat will trigger the destroy handler on our seat,
|
||||
// which will in turn free it.
|
||||
|
||||
wlr_seat_destroy(seat->seat);
|
||||
}
|
||||
|
||||
|
|
@ -920,6 +926,11 @@ seat_get_focus(struct cg_seat *seat)
|
|||
if (!prev_surface) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (seat->focused_layer && seat->focused_layer->surface == prev_surface) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return view_from_wlr_surface(prev_surface);
|
||||
}
|
||||
|
||||
|
|
@ -973,6 +984,34 @@ seat_set_focus(struct cg_seat *seat, struct cg_view *view)
|
|||
process_cursor_motion(seat, -1, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
void
|
||||
seat_set_focus_layer(struct cg_seat *seat, struct wlr_layer_surface_v1 *layer)
|
||||
{
|
||||
if (seat->focused_layer == layer) {
|
||||
return;
|
||||
}
|
||||
|
||||
seat->focused_layer = layer;
|
||||
|
||||
if (!layer) {
|
||||
struct cg_view *view = seat_get_focus(seat);
|
||||
if (view) {
|
||||
seat_set_focus(seat, view);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (layer->current.keyboard_interactive != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE) {
|
||||
struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->seat);
|
||||
if (keyboard) {
|
||||
wlr_seat_keyboard_notify_enter(seat->seat, layer->surface, keyboard->keycodes,
|
||||
keyboard->num_keycodes, &keyboard->modifiers);
|
||||
} else {
|
||||
wlr_seat_keyboard_notify_enter(seat->seat, layer->surface, NULL, 0, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
seat_center_cursor(struct cg_seat *seat)
|
||||
{
|
||||
|
|
|
|||
5
seat.h
5
seat.h
|
|
@ -5,6 +5,7 @@
|
|||
#include <wlr/types/wlr_cursor.h>
|
||||
#include <wlr/types/wlr_data_device.h>
|
||||
#include <wlr/types/wlr_input_device.h>
|
||||
#include <wlr/types/wlr_layer_shell_v1.h>
|
||||
#include <wlr/types/wlr_seat.h>
|
||||
#include <wlr/types/wlr_xcursor_manager.h>
|
||||
|
||||
|
|
@ -48,6 +49,9 @@ struct cg_seat {
|
|||
struct wl_listener request_set_cursor;
|
||||
struct wl_listener request_set_selection;
|
||||
struct wl_listener request_set_primary_selection;
|
||||
|
||||
struct wlr_layer_surface_v1 *focused_layer;
|
||||
struct wlr_output *focused_output;
|
||||
};
|
||||
|
||||
struct cg_keyboard_group {
|
||||
|
|
@ -91,6 +95,7 @@ struct cg_seat *seat_create(struct cg_server *server, struct wlr_backend *backen
|
|||
void seat_destroy(struct cg_seat *seat);
|
||||
struct cg_view *seat_get_focus(struct cg_seat *seat);
|
||||
void seat_set_focus(struct cg_seat *seat, struct cg_view *view);
|
||||
void seat_set_focus_layer(struct cg_seat *seat, struct wlr_layer_surface_v1 *layer);
|
||||
void seat_center_cursor(struct cg_seat *seat);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
21
view.c
21
view.c
|
|
@ -115,8 +115,6 @@ view_unmap(struct cg_view *view)
|
|||
{
|
||||
wl_list_remove(&view->link);
|
||||
|
||||
wlr_scene_node_destroy(&view->scene_tree->node);
|
||||
|
||||
view->wlr_surface->data = NULL;
|
||||
view->wlr_surface = NULL;
|
||||
}
|
||||
|
|
@ -124,12 +122,16 @@ view_unmap(struct cg_view *view)
|
|||
void
|
||||
view_map(struct cg_view *view, struct wlr_surface *surface)
|
||||
{
|
||||
view->scene_tree = wlr_scene_subsurface_tree_create(&view->server->scene->tree, surface);
|
||||
if (!view->scene_tree) {
|
||||
wl_resource_post_no_memory(surface->resource);
|
||||
return;
|
||||
view->scene_tree = wlr_scene_subsurface_tree_create(&view->server->scene->tree, surface);
|
||||
if (!view->scene_tree) {
|
||||
wl_resource_post_no_memory(surface->resource);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (view->scene_tree) {
|
||||
view->scene_tree->node.data = view;
|
||||
}
|
||||
view->scene_tree->node.data = view;
|
||||
|
||||
view->wlr_surface = surface;
|
||||
surface->data = view;
|
||||
|
|
@ -137,11 +139,12 @@ view_map(struct cg_view *view, struct wlr_surface *surface)
|
|||
#if CAGE_HAS_XWAYLAND
|
||||
/* We shouldn't position override-redirect windows. They set
|
||||
their own (x,y) coordinates in handle_wayland_surface_map. */
|
||||
if (view->type != CAGE_XWAYLAND_VIEW || xwayland_view_should_manage(view))
|
||||
#endif
|
||||
{
|
||||
if (view->type != CAGE_XWAYLAND_VIEW || xwayland_view_should_manage(view)) {
|
||||
view_position(view);
|
||||
}
|
||||
#else
|
||||
view_position(view);
|
||||
#endif
|
||||
|
||||
wl_list_insert(&view->server->views, &view->link);
|
||||
seat_set_focus(view->server->seat, view);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue