layer-shell: initial layer shell v1 implementation

This commit is contained in:
Sungjoon Moon 2025-10-22 16:13:00 +09:00
parent 0e946d5a4f
commit 8a11a66d87
8 changed files with 538 additions and 24 deletions

1
cage.c
View file

@ -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);

View file

@ -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);
}

View file

@ -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
View file

@ -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)
{

View file

@ -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
View file

@ -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
View file

@ -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
View file

@ -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);