mirror of
https://github.com/swaywm/sway.git
synced 2024-11-22 07:51:28 +00:00
scene_graph: Maintain wlr_scene_node
s for the sway tree.
This commit is contained in:
parent
dbd2fbf430
commit
1eb16d1367
|
@ -5,6 +5,7 @@
|
|||
#include <wayland-server-core.h>
|
||||
#include <wlr/types/wlr_damage_ring.h>
|
||||
#include <wlr/types/wlr_output.h>
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
#include "config.h"
|
||||
#include "sway/tree/node.h"
|
||||
#include "sway/tree/view.h"
|
||||
|
@ -19,7 +20,21 @@ struct sway_output_state {
|
|||
|
||||
struct sway_output {
|
||||
struct sway_node node;
|
||||
|
||||
struct {
|
||||
struct wlr_scene_tree *tiling;
|
||||
struct wlr_scene_tree *fullscreen;
|
||||
} layers;
|
||||
|
||||
// when a container is fullscreen, in case the fullscreen surface is
|
||||
// translucent (can see behind) we must make sure that the background is a
|
||||
// solid color in order to conform to the wayland protocol. This rect
|
||||
// ensures that when looking through a surface, all that will be seen
|
||||
// is black.
|
||||
struct wlr_scene_rect *fullscreen_background;
|
||||
|
||||
struct wlr_output *wlr_output;
|
||||
struct wlr_scene_output *scene_output;
|
||||
struct sway_server *server;
|
||||
struct wl_list link;
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <wlr/types/wlr_compositor.h>
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
#include "list.h"
|
||||
#include "sway/tree/node.h"
|
||||
|
||||
|
@ -68,6 +69,26 @@ struct sway_container {
|
|||
struct sway_node node;
|
||||
struct sway_view *view;
|
||||
|
||||
struct wlr_scene_tree *scene_tree;
|
||||
|
||||
struct {
|
||||
struct wlr_scene_tree *tree;
|
||||
|
||||
struct wlr_scene_tree *border;
|
||||
struct wlr_scene_tree *background;
|
||||
} title_bar;
|
||||
|
||||
struct {
|
||||
struct wlr_scene_tree *tree;
|
||||
|
||||
struct wlr_scene_rect *top;
|
||||
struct wlr_scene_rect *bottom;
|
||||
struct wlr_scene_rect *left;
|
||||
struct wlr_scene_rect *right;
|
||||
} border;
|
||||
|
||||
struct wlr_scene_tree *content_tree;
|
||||
|
||||
struct sway_container_state current;
|
||||
struct sway_container_state pending;
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define _SWAY_NODE_H
|
||||
#include <wayland-server-core.h>
|
||||
#include <stdbool.h>
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
#include "list.h"
|
||||
|
||||
#define MIN_SANE_W 100
|
||||
|
@ -75,4 +76,15 @@ list_t *node_get_children(struct sway_node *node);
|
|||
|
||||
bool node_has_ancestor(struct sway_node *node, struct sway_node *ancestor);
|
||||
|
||||
// when destroying a sway tree, it's not known which order the tree will be
|
||||
// destroyed. To prevent freeing of scene_nodes recursing up the tree,
|
||||
// let's use this helper function to disown them to the staging node.
|
||||
void scene_node_disown_children(struct wlr_scene_tree *tree);
|
||||
|
||||
// a helper function used to allocate tree nodes. If an allocation failure
|
||||
// occurs a flag is flipped that can be checked later to destroy a parent
|
||||
// of this scene node preventing memory leaks.
|
||||
struct wlr_scene_tree *alloc_scene_tree(struct wlr_scene_tree *parent,
|
||||
bool *failed);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <wayland-server-core.h>
|
||||
#include <wayland-util.h>
|
||||
#include <wlr/types/wlr_output_layout.h>
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
#include <wlr/render/wlr_texture.h>
|
||||
#include "sway/tree/container.h"
|
||||
#include "sway/tree/node.h"
|
||||
|
@ -16,6 +17,31 @@ struct sway_root {
|
|||
struct wlr_output_layout *output_layout;
|
||||
|
||||
struct wl_listener output_layout_change;
|
||||
|
||||
// scene node layout:
|
||||
// - root
|
||||
// - staging
|
||||
// - layer shell stuff
|
||||
// - tiling
|
||||
// - floating
|
||||
// - fullscreen stuff
|
||||
// - seat stuff
|
||||
// - ext_session_lock
|
||||
struct wlr_scene *root_scene;
|
||||
|
||||
// since wlr_scene nodes can't be orphaned and must always
|
||||
// have a parent, use this staging scene_tree so that a
|
||||
// node always have a valid parent. Nothing in this
|
||||
// staging node will be visible.
|
||||
struct wlr_scene_tree *staging;
|
||||
|
||||
struct {
|
||||
struct wlr_scene_tree *tiling;
|
||||
struct wlr_scene_tree *floating;
|
||||
struct wlr_scene_tree *fullscreen;
|
||||
struct wlr_scene_tree *fullscreen_global;
|
||||
} layers;
|
||||
|
||||
#if HAVE_XWAYLAND
|
||||
struct wl_list xwayland_unmanaged; // sway_xwayland_unmanaged::link
|
||||
#endif
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define _SWAY_VIEW_H
|
||||
#include <wayland-server-core.h>
|
||||
#include <wlr/types/wlr_compositor.h>
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
#include "sway/config.h"
|
||||
#if HAVE_XWAYLAND
|
||||
#include <wlr/xwayland.h>
|
||||
|
@ -69,6 +70,9 @@ struct sway_view {
|
|||
enum sway_view_type type;
|
||||
const struct sway_view_impl *impl;
|
||||
|
||||
struct wlr_scene_tree *scene_tree;
|
||||
struct wlr_scene_tree *content_tree;
|
||||
|
||||
struct sway_container *container; // NULL if unmapped and transactions finished
|
||||
struct wlr_surface *surface; // NULL for unmapped views
|
||||
struct sway_xdg_decoration *xdg_decoration;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define _SWAY_WORKSPACE_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
#include "sway/config.h"
|
||||
#include "sway/tree/container.h"
|
||||
#include "sway/tree/node.h"
|
||||
|
@ -23,6 +24,12 @@ struct sway_workspace_state {
|
|||
|
||||
struct sway_workspace {
|
||||
struct sway_node node;
|
||||
|
||||
struct {
|
||||
struct wlr_scene_tree *tiling;
|
||||
struct wlr_scene_tree *fullscreen;
|
||||
} layers;
|
||||
|
||||
struct sway_container *fullscreen;
|
||||
|
||||
char *name;
|
||||
|
|
|
@ -856,9 +856,6 @@ void output_damage_whole_container(struct sway_output *output,
|
|||
.height = con->current.height + 2,
|
||||
};
|
||||
scale_box(&box, output->wlr_output->scale);
|
||||
if (wlr_damage_ring_add_box(&output->damage_ring, &box)) {
|
||||
wlr_output_schedule_frame(output->wlr_output);
|
||||
}
|
||||
// Damage subsurfaces as well, which may extend outside the box
|
||||
if (con->view) {
|
||||
damage_child_views_iterator(con, output);
|
||||
|
@ -914,6 +911,8 @@ static void begin_destroy(struct sway_output *output) {
|
|||
|
||||
wlr_damage_ring_finish(&output->damage_ring);
|
||||
|
||||
wlr_scene_output_destroy(output->scene_output);
|
||||
output->scene_output = NULL;
|
||||
output->wlr_output->data = NULL;
|
||||
output->wlr_output = NULL;
|
||||
|
||||
|
@ -1039,11 +1038,24 @@ void handle_new_output(struct wl_listener *listener, void *data) {
|
|||
return;
|
||||
}
|
||||
|
||||
struct sway_output *output = output_create(wlr_output);
|
||||
if (!output) {
|
||||
// Create the scene output here so we're not accidentally creating one for
|
||||
// the fallback output
|
||||
struct wlr_scene_output *scene_output =
|
||||
wlr_scene_output_create(root->root_scene, wlr_output);
|
||||
if (!scene_output) {
|
||||
sway_log(SWAY_ERROR, "Failed to create a scene output");
|
||||
return;
|
||||
}
|
||||
|
||||
struct sway_output *output = output_create(wlr_output);
|
||||
if (!output) {
|
||||
sway_log(SWAY_ERROR, "Failed to create a sway output");
|
||||
wlr_scene_output_destroy(scene_output);
|
||||
return;
|
||||
}
|
||||
|
||||
output->server = server;
|
||||
output->scene_output = scene_output;
|
||||
wlr_damage_ring_init(&output->damage_ring);
|
||||
|
||||
wl_signal_add(&root->output_layout->events.destroy, &output->layout_destroy);
|
||||
|
|
|
@ -27,6 +27,24 @@
|
|||
#include "log.h"
|
||||
#include "stringop.h"
|
||||
|
||||
static struct wlr_scene_rect *alloc_rect_node(struct wlr_scene_tree *parent,
|
||||
bool *failed) {
|
||||
if (*failed) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// just pass in random values. These will be overwritten when
|
||||
// they need to be used.
|
||||
struct wlr_scene_rect *rect = wlr_scene_rect_create(
|
||||
parent, 0, 0, (float[4]){0.f, 0.f, 0.f, 1.f});
|
||||
if (!rect) {
|
||||
sway_log(SWAY_ERROR, "Failed to allocate a wlr_scene_rect");
|
||||
*failed = true;
|
||||
}
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
struct sway_container *container_create(struct sway_view *view) {
|
||||
struct sway_container *c = calloc(1, sizeof(struct sway_container));
|
||||
if (!c) {
|
||||
|
@ -34,14 +52,62 @@ struct sway_container *container_create(struct sway_view *view) {
|
|||
return NULL;
|
||||
}
|
||||
node_init(&c->node, N_CONTAINER, c);
|
||||
c->pending.layout = L_NONE;
|
||||
c->view = view;
|
||||
c->alpha = 1.0f;
|
||||
|
||||
// Container tree structure
|
||||
// - scene tree
|
||||
// - title bar
|
||||
// - border
|
||||
// - background
|
||||
// - title text
|
||||
// - marks text
|
||||
// - border
|
||||
// - border top/bottom/left/right
|
||||
// - content_tree (we put the content node here so when we disable the
|
||||
// border everything gets disabled. We only render the content iff there
|
||||
// is a border as well)
|
||||
bool failed = false;
|
||||
c->scene_tree = alloc_scene_tree(root->staging, &failed);
|
||||
|
||||
c->title_bar.tree = alloc_scene_tree(c->scene_tree, &failed);
|
||||
c->title_bar.border = alloc_scene_tree(c->title_bar.tree, &failed);
|
||||
c->title_bar.background = alloc_scene_tree(c->title_bar.tree, &failed);
|
||||
|
||||
// for opacity purposes we need to carfully create the scene such that
|
||||
// none of our rect nodes as well as text buffers don't overlap. To do
|
||||
// this we have to create rects such that they go around text buffers
|
||||
for (int i = 0; i < 4; i++) {
|
||||
alloc_rect_node(c->title_bar.border, &failed);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
alloc_rect_node(c->title_bar.background, &failed);
|
||||
}
|
||||
|
||||
c->border.tree = alloc_scene_tree(c->scene_tree, &failed);
|
||||
c->content_tree = alloc_scene_tree(c->border.tree, &failed);
|
||||
|
||||
if (view) {
|
||||
// only containers with views can have borders
|
||||
c->border.top = alloc_rect_node(c->border.tree, &failed);
|
||||
c->border.bottom = alloc_rect_node(c->border.tree, &failed);
|
||||
c->border.left = alloc_rect_node(c->border.tree, &failed);
|
||||
c->border.right = alloc_rect_node(c->border.tree, &failed);
|
||||
}
|
||||
|
||||
if (failed) {
|
||||
wlr_scene_node_destroy(&c->scene_tree->node);
|
||||
free(c);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!view) {
|
||||
c->pending.children = create_list();
|
||||
c->current.children = create_list();
|
||||
}
|
||||
|
||||
c->pending.layout = L_NONE;
|
||||
c->view = view;
|
||||
c->alpha = 1.0f;
|
||||
c->marks = create_list();
|
||||
c->outputs = create_list();
|
||||
|
||||
|
@ -85,6 +151,8 @@ void container_destroy(struct sway_container *con) {
|
|||
}
|
||||
}
|
||||
|
||||
scene_node_disown_children(con->content_tree);
|
||||
wlr_scene_node_destroy(&con->scene_tree->node);
|
||||
free(con);
|
||||
}
|
||||
|
||||
|
|
|
@ -159,3 +159,32 @@ bool node_has_ancestor(struct sway_node *node, struct sway_node *ancestor) {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void scene_node_disown_children(struct wlr_scene_tree *tree) {
|
||||
// this function can be called as part of destruction code that will be invoked
|
||||
// upon an allocation failure. Let's not crash on NULL due to an allocation error.
|
||||
if (!tree) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct wlr_scene_node *child, *tmp_child;
|
||||
wl_list_for_each_safe(child, tmp_child, &tree->children, link) {
|
||||
wlr_scene_node_reparent(child, root->staging);
|
||||
}
|
||||
}
|
||||
|
||||
struct wlr_scene_tree *alloc_scene_tree(struct wlr_scene_tree *parent,
|
||||
bool *failed) {
|
||||
// fallthrough
|
||||
if (*failed) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct wlr_scene_tree *tree = wlr_scene_tree_create(parent);
|
||||
if (!tree) {
|
||||
sway_log(SWAY_ERROR, "Failed to allocate a scene node");
|
||||
*failed = true;
|
||||
}
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
|
|
@ -87,9 +87,41 @@ static void restore_workspaces(struct sway_output *output) {
|
|||
output_sort_workspaces(output);
|
||||
}
|
||||
|
||||
static void destroy_scene_layers(struct sway_output *output) {
|
||||
wlr_scene_node_destroy(&output->fullscreen_background->node);
|
||||
|
||||
scene_node_disown_children(output->layers.tiling);
|
||||
scene_node_disown_children(output->layers.fullscreen);
|
||||
|
||||
wlr_scene_node_destroy(&output->layers.tiling->node);
|
||||
wlr_scene_node_destroy(&output->layers.fullscreen->node);
|
||||
}
|
||||
|
||||
struct sway_output *output_create(struct wlr_output *wlr_output) {
|
||||
struct sway_output *output = calloc(1, sizeof(struct sway_output));
|
||||
node_init(&output->node, N_OUTPUT, output);
|
||||
|
||||
bool failed = false;
|
||||
output->layers.tiling = alloc_scene_tree(root->staging, &failed);
|
||||
output->layers.fullscreen = alloc_scene_tree(root->staging, &failed);
|
||||
|
||||
if (!failed) {
|
||||
output->fullscreen_background = wlr_scene_rect_create(
|
||||
output->layers.fullscreen, 0, 0, (float[4]){0.f, 0.f, 0.f, 1.f});
|
||||
|
||||
if (!output->fullscreen_background) {
|
||||
sway_log(SWAY_ERROR, "Unable to allocate a background rect");
|
||||
failed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (failed) {
|
||||
destroy_scene_layers(output);
|
||||
wlr_scene_output_destroy(output->scene_output);
|
||||
free(output);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
output->wlr_output = wlr_output;
|
||||
wlr_output->data = output;
|
||||
output->detected_subpixel = wlr_output->subpixel;
|
||||
|
@ -238,6 +270,8 @@ void output_destroy(struct sway_output *output) {
|
|||
"which is still referenced by transactions")) {
|
||||
return;
|
||||
}
|
||||
|
||||
destroy_scene_layers(output);
|
||||
list_free(output->workspaces);
|
||||
list_free(output->current.workspaces);
|
||||
wl_event_source_remove(output->repaint_timer);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wlr/types/wlr_output_layout.h>
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
#include <wlr/util/transform.h>
|
||||
#include "sway/desktop/transaction.h"
|
||||
#include "sway/input/seat.h"
|
||||
|
@ -30,7 +31,33 @@ struct sway_root *root_create(struct wl_display *wl_display) {
|
|||
sway_log(SWAY_ERROR, "Unable to allocate sway_root");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct wlr_scene *root_scene = wlr_scene_create();
|
||||
if (!root_scene) {
|
||||
sway_log(SWAY_ERROR, "Unable to allocate root scene node");
|
||||
free(root);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node_init(&root->node, N_ROOT, root);
|
||||
root->root_scene = root_scene;
|
||||
|
||||
bool failed = false;
|
||||
root->staging = alloc_scene_tree(&root_scene->tree, &failed);
|
||||
|
||||
root->layers.tiling = alloc_scene_tree(&root_scene->tree, &failed);
|
||||
root->layers.floating = alloc_scene_tree(&root_scene->tree, &failed);
|
||||
root->layers.fullscreen = alloc_scene_tree(&root_scene->tree, &failed);
|
||||
root->layers.fullscreen_global = alloc_scene_tree(&root_scene->tree, &failed);
|
||||
|
||||
if (failed) {
|
||||
wlr_scene_node_destroy(&root_scene->tree.node);
|
||||
free(root);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wlr_scene_node_set_enabled(&root->staging->node, false);
|
||||
|
||||
root->output_layout = wlr_output_layout_create(wl_display);
|
||||
wl_list_init(&root->all_outputs);
|
||||
#if HAVE_XWAYLAND
|
||||
|
@ -53,6 +80,7 @@ void root_destroy(struct sway_root *root) {
|
|||
list_free(root->scratchpad);
|
||||
list_free(root->non_desktop_outputs);
|
||||
list_free(root->outputs);
|
||||
wlr_scene_node_destroy(&root->root_scene->tree.node);
|
||||
free(root);
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,14 @@
|
|||
|
||||
bool view_init(struct sway_view *view, enum sway_view_type type,
|
||||
const struct sway_view_impl *impl) {
|
||||
bool failed = false;
|
||||
view->scene_tree = alloc_scene_tree(root->staging, &failed);
|
||||
view->content_tree = alloc_scene_tree(view->scene_tree, &failed);
|
||||
if (failed) {
|
||||
wlr_scene_node_destroy(&view->scene_tree->node);
|
||||
return false;
|
||||
}
|
||||
|
||||
view->type = type;
|
||||
view->impl = impl;
|
||||
view->executed_criteria = create_list();
|
||||
|
@ -67,7 +75,7 @@ void view_destroy(struct sway_view *view) {
|
|||
list_free(view->executed_criteria);
|
||||
|
||||
view_assign_ctx(view, NULL);
|
||||
|
||||
wlr_scene_node_destroy(&view->scene_tree->node);
|
||||
free(view->title_format);
|
||||
|
||||
if (view->impl->destroy) {
|
||||
|
|
|
@ -71,6 +71,18 @@ struct sway_workspace *workspace_create(struct sway_output *output,
|
|||
return NULL;
|
||||
}
|
||||
node_init(&ws->node, N_WORKSPACE, ws);
|
||||
|
||||
bool failed = false;
|
||||
ws->layers.tiling = alloc_scene_tree(root->staging, &failed);
|
||||
ws->layers.fullscreen = alloc_scene_tree(root->staging, &failed);
|
||||
|
||||
if (failed) {
|
||||
wlr_scene_node_destroy(&ws->layers.tiling->node);
|
||||
wlr_scene_node_destroy(&ws->layers.fullscreen->node);
|
||||
free(ws);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ws->name = strdup(name);
|
||||
ws->prev_split_layout = L_NONE;
|
||||
ws->layout = output_get_default_layout(output);
|
||||
|
@ -131,6 +143,11 @@ void workspace_destroy(struct sway_workspace *workspace) {
|
|||
return;
|
||||
}
|
||||
|
||||
scene_node_disown_children(workspace->layers.tiling);
|
||||
scene_node_disown_children(workspace->layers.fullscreen);
|
||||
wlr_scene_node_destroy(&workspace->layers.tiling->node);
|
||||
wlr_scene_node_destroy(&workspace->layers.fullscreen->node);
|
||||
|
||||
free(workspace->name);
|
||||
free(workspace->representation);
|
||||
list_free_items_and_destroy(workspace->output_priority);
|
||||
|
|
Loading…
Reference in a new issue