mirror of
https://github.com/swaywm/sway.git
synced 2024-11-25 17:31:28 +00:00
scene_graph: Arrange scene graph on transaction apply
This commit is contained in:
parent
5f0801b6f2
commit
2e53de80bb
|
@ -5,6 +5,7 @@
|
|||
#include <time.h>
|
||||
#include <wlr/types/wlr_buffer.h>
|
||||
#include "sway/config.h"
|
||||
#include "sway/scene_descriptor.h"
|
||||
#include "sway/desktop/idle_inhibit_v1.h"
|
||||
#include "sway/desktop/transaction.h"
|
||||
#include "sway/input/cursor.h"
|
||||
|
@ -252,6 +253,431 @@ static void apply_container_state(struct sway_container *container,
|
|||
}
|
||||
}
|
||||
|
||||
static void arrange_title_bar(struct sway_container *con,
|
||||
int x, int y, int width, int height) {
|
||||
container_update(con);
|
||||
|
||||
bool has_title_bar = height > 0;
|
||||
wlr_scene_node_set_enabled(&con->title_bar.tree->node, has_title_bar);
|
||||
if (!has_title_bar) {
|
||||
return;
|
||||
}
|
||||
|
||||
wlr_scene_node_set_position(&con->title_bar.tree->node, x, y);
|
||||
|
||||
con->title_width = width;
|
||||
container_arrange_title_bar(con);
|
||||
}
|
||||
|
||||
static void disable_container(struct sway_container *con) {
|
||||
if (con->view) {
|
||||
wlr_scene_node_reparent(&con->view->scene_tree->node, con->content_tree);
|
||||
} else {
|
||||
for (int i = 0; i < con->current.children->length; i++) {
|
||||
struct sway_container *child = con->current.children->items[i];
|
||||
|
||||
wlr_scene_node_reparent(&child->scene_tree->node, con->content_tree);
|
||||
|
||||
disable_container(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void arrange_container(struct sway_container *con,
|
||||
int width, int height, bool title_bar, int gaps);
|
||||
|
||||
static void arrange_children(enum sway_container_layout layout, list_t *children,
|
||||
struct sway_container *active, struct wlr_scene_tree *content,
|
||||
int width, int height, int gaps) {
|
||||
int title_bar_height = container_titlebar_height();
|
||||
|
||||
if (layout == L_TABBED) {
|
||||
struct sway_container *first = children->length == 1 ?
|
||||
((struct sway_container *)children->items[0]) : NULL;
|
||||
if (config->hide_lone_tab && first && first->view &&
|
||||
first->current.border != B_NORMAL) {
|
||||
title_bar_height = 0;
|
||||
}
|
||||
|
||||
double w = (double) width / children->length;
|
||||
int title_offset = 0;
|
||||
for (int i = 0; i < children->length; i++) {
|
||||
struct sway_container *child = children->items[i];
|
||||
bool activated = child == active;
|
||||
int next_title_offset = round(w * i + w);
|
||||
|
||||
arrange_title_bar(child, title_offset, -title_bar_height,
|
||||
next_title_offset - title_offset, title_bar_height);
|
||||
wlr_scene_node_set_enabled(&child->border.tree->node, activated);
|
||||
wlr_scene_node_set_position(&child->scene_tree->node, 0, title_bar_height);
|
||||
wlr_scene_node_reparent(&child->scene_tree->node, content);
|
||||
|
||||
if (activated) {
|
||||
arrange_container(child, width, height - title_bar_height,
|
||||
false, 0);
|
||||
} else {
|
||||
disable_container(child);
|
||||
}
|
||||
|
||||
title_offset = next_title_offset;
|
||||
}
|
||||
} else if (layout == L_STACKED) {
|
||||
struct sway_container *first = children->length == 1 ?
|
||||
((struct sway_container *)children->items[0]) : NULL;
|
||||
if (config->hide_lone_tab && first && first->view &&
|
||||
first->current.border != B_NORMAL) {
|
||||
title_bar_height = 0;
|
||||
}
|
||||
|
||||
int title_height = title_bar_height * children->length;
|
||||
|
||||
int y = 0;
|
||||
for (int i = 0; i < children->length; i++) {
|
||||
struct sway_container *child = children->items[i];
|
||||
bool activated = child == active;
|
||||
|
||||
arrange_title_bar(child, 0, y - title_height, width, title_bar_height);
|
||||
wlr_scene_node_set_enabled(&child->border.tree->node, activated);
|
||||
wlr_scene_node_set_position(&child->scene_tree->node, 0, title_height);
|
||||
wlr_scene_node_reparent(&child->scene_tree->node, content);
|
||||
|
||||
if (activated) {
|
||||
arrange_container(child, width, height - title_height,
|
||||
false, 0);
|
||||
} else {
|
||||
disable_container(child);
|
||||
}
|
||||
|
||||
y += title_bar_height;
|
||||
}
|
||||
} else if (layout == L_VERT) {
|
||||
int off = 0;
|
||||
for (int i = 0; i < children->length; i++) {
|
||||
struct sway_container *child = children->items[i];
|
||||
int cheight = child->current.height;
|
||||
|
||||
wlr_scene_node_set_enabled(&child->border.tree->node, true);
|
||||
wlr_scene_node_set_position(&child->scene_tree->node, 0, off);
|
||||
wlr_scene_node_reparent(&child->scene_tree->node, content);
|
||||
arrange_container(child, width, cheight, true, gaps);
|
||||
off += cheight + gaps;
|
||||
}
|
||||
} else if (layout == L_HORIZ) {
|
||||
int off = 0;
|
||||
for (int i = 0; i < children->length; i++) {
|
||||
struct sway_container *child = children->items[i];
|
||||
int cwidth = child->current.width;
|
||||
|
||||
wlr_scene_node_set_enabled(&child->border.tree->node, true);
|
||||
wlr_scene_node_set_position(&child->scene_tree->node, off, 0);
|
||||
wlr_scene_node_reparent(&child->scene_tree->node, content);
|
||||
arrange_container(child, cwidth, height, true, gaps);
|
||||
off += cwidth + gaps;
|
||||
}
|
||||
} else {
|
||||
sway_assert(false, "unreachable");
|
||||
}
|
||||
}
|
||||
|
||||
static void arrange_container(struct sway_container *con,
|
||||
int width, int height, bool title_bar, int gaps) {
|
||||
// this container might have previously been in the scratchpad,
|
||||
// make sure it's enabled for viewing
|
||||
wlr_scene_node_set_enabled(&con->scene_tree->node, true);
|
||||
|
||||
if (con->view) {
|
||||
int border_top = container_titlebar_height();
|
||||
int border_width = con->current.border_thickness;
|
||||
|
||||
if (title_bar && con->current.border != B_NORMAL) {
|
||||
wlr_scene_node_set_enabled(&con->title_bar.tree->node, false);
|
||||
wlr_scene_node_set_enabled(&con->border.top->node, true);
|
||||
} else {
|
||||
wlr_scene_node_set_enabled(&con->border.top->node, false);
|
||||
}
|
||||
|
||||
if (con->current.border == B_NORMAL) {
|
||||
if (title_bar) {
|
||||
arrange_title_bar(con, 0, 0, width, border_top);
|
||||
} else {
|
||||
border_top = 0;
|
||||
// should be handled by the parent container
|
||||
}
|
||||
} else if (con->current.border == B_PIXEL) {
|
||||
container_update(con);
|
||||
border_top = title_bar && con->current.border_top ? border_width : 0;
|
||||
} else if (con->current.border == B_NONE) {
|
||||
container_update(con);
|
||||
border_top = 0;
|
||||
border_width = 0;
|
||||
} else if (con->current.border == B_CSD) {
|
||||
border_top = 0;
|
||||
border_width = 0;
|
||||
} else {
|
||||
sway_assert(false, "unreachable");
|
||||
}
|
||||
|
||||
int border_bottom = con->current.border_bottom ? border_width : 0;
|
||||
int border_left = con->current.border_left ? border_width : 0;
|
||||
int border_right = con->current.border_right ? border_width : 0;
|
||||
|
||||
wlr_scene_rect_set_size(con->border.top, width, border_top);
|
||||
wlr_scene_rect_set_size(con->border.bottom, width, border_bottom);
|
||||
wlr_scene_rect_set_size(con->border.left,
|
||||
border_left, height - border_top - border_bottom);
|
||||
wlr_scene_rect_set_size(con->border.right,
|
||||
border_right, height - border_top - border_bottom);
|
||||
|
||||
wlr_scene_node_set_position(&con->border.top->node, 0, 0);
|
||||
wlr_scene_node_set_position(&con->border.bottom->node,
|
||||
0, height - border_bottom);
|
||||
wlr_scene_node_set_position(&con->border.left->node,
|
||||
0, border_top);
|
||||
wlr_scene_node_set_position(&con->border.right->node,
|
||||
width - border_right, border_top);
|
||||
|
||||
// make sure to reparent, it's possible that the client just came out of
|
||||
// fullscreen mode where the parent of the surface is not the container
|
||||
wlr_scene_node_reparent(&con->view->scene_tree->node, con->content_tree);
|
||||
wlr_scene_node_set_position(&con->view->scene_tree->node,
|
||||
border_left, border_top);
|
||||
} else {
|
||||
// make sure to disable the title bar if the parent is not managing it
|
||||
if (title_bar) {
|
||||
wlr_scene_node_set_enabled(&con->title_bar.tree->node, false);
|
||||
}
|
||||
|
||||
arrange_children(con->current.layout, con->current.children,
|
||||
con->current.focused_inactive_child, con->content_tree,
|
||||
width, height, gaps);
|
||||
}
|
||||
}
|
||||
|
||||
static int container_get_gaps(struct sway_container *con) {
|
||||
struct sway_workspace *ws = con->current.workspace;
|
||||
struct sway_container *temp = con;
|
||||
while (temp) {
|
||||
enum sway_container_layout layout;
|
||||
if (temp->current.parent) {
|
||||
layout = temp->current.parent->current.layout;
|
||||
} else {
|
||||
layout = ws->current.layout;
|
||||
}
|
||||
if (layout == L_TABBED || layout == L_STACKED) {
|
||||
return 0;
|
||||
}
|
||||
temp = temp->pending.parent;
|
||||
}
|
||||
return ws->gaps_inner;
|
||||
}
|
||||
|
||||
static void arrange_fullscreen(struct wlr_scene_tree *tree,
|
||||
struct sway_container *fs, struct sway_workspace *ws,
|
||||
int width, int height) {
|
||||
struct wlr_scene_node *fs_node;
|
||||
if (fs->view) {
|
||||
fs_node = &fs->view->scene_tree->node;
|
||||
|
||||
// if we only care about the view, disable any decorations
|
||||
wlr_scene_node_set_enabled(&fs->scene_tree->node, false);
|
||||
} else {
|
||||
fs_node = &fs->scene_tree->node;
|
||||
arrange_container(fs, width, height, true, container_get_gaps(fs));
|
||||
}
|
||||
|
||||
wlr_scene_node_reparent(fs_node, tree);
|
||||
wlr_scene_node_lower_to_bottom(fs_node);
|
||||
wlr_scene_node_set_position(fs_node, 0, 0);
|
||||
}
|
||||
|
||||
static void arrange_workspace_floating(struct sway_workspace *ws) {
|
||||
for (int i = 0; i < ws->current.floating->length; i++) {
|
||||
struct sway_container *floater = ws->current.floating->items[i];
|
||||
struct wlr_scene_tree *layer = root->layers.floating;
|
||||
|
||||
if (floater->current.fullscreen_mode != FULLSCREEN_NONE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (root->fullscreen_global) {
|
||||
if (container_is_transient_for(floater, root->fullscreen_global)) {
|
||||
layer = root->layers.fullscreen_global;
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < root->outputs->length; i++) {
|
||||
struct sway_output *output = root->outputs->items[i];
|
||||
struct sway_workspace *active = output->current.active_workspace;
|
||||
|
||||
if (active && active->fullscreen &&
|
||||
container_is_transient_for(floater, active->fullscreen)) {
|
||||
layer = root->layers.fullscreen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wlr_scene_node_reparent(&floater->scene_tree->node, layer);
|
||||
wlr_scene_node_set_position(&floater->scene_tree->node,
|
||||
floater->current.x, floater->current.y);
|
||||
wlr_scene_node_set_enabled(&floater->scene_tree->node, true);
|
||||
|
||||
arrange_container(floater, floater->current.width, floater->current.height,
|
||||
true, ws->gaps_inner);
|
||||
}
|
||||
}
|
||||
|
||||
static void arrange_workspace_tiling(struct sway_workspace *ws,
|
||||
int width, int height) {
|
||||
arrange_children(ws->current.layout, ws->current.tiling,
|
||||
ws->current.focused_inactive_child, ws->layers.tiling,
|
||||
width, height, ws->gaps_inner);
|
||||
}
|
||||
|
||||
static void disable_workspace(struct sway_workspace *ws) {
|
||||
// if any containers were just moved to a disabled workspace it will
|
||||
// have the parent of the old workspace. Move the workspace so that it won't
|
||||
// be shown.
|
||||
for (int i = 0; i < ws->current.tiling->length; i++) {
|
||||
struct sway_container *child = ws->current.tiling->items[i];
|
||||
|
||||
wlr_scene_node_reparent(&child->scene_tree->node, ws->layers.tiling);
|
||||
disable_container(child);
|
||||
}
|
||||
|
||||
for (int i = 0; i < ws->current.floating->length; i++) {
|
||||
struct sway_container *floater = ws->current.floating->items[i];
|
||||
wlr_scene_node_reparent(&floater->scene_tree->node, root->layers.floating);
|
||||
disable_container(floater);
|
||||
wlr_scene_node_set_enabled(&floater->scene_tree->node, false);
|
||||
}
|
||||
}
|
||||
|
||||
static void arrange_output(struct sway_output *output, int width, int height) {
|
||||
for (int i = 0; i < output->current.workspaces->length; i++) {
|
||||
struct sway_workspace *child = output->current.workspaces->items[i];
|
||||
|
||||
bool activated = output->current.active_workspace == child;
|
||||
|
||||
wlr_scene_node_reparent(&child->layers.tiling->node, output->layers.tiling);
|
||||
wlr_scene_node_reparent(&child->layers.fullscreen->node, output->layers.fullscreen);
|
||||
|
||||
for (int i = 0; i < child->current.floating->length; i++) {
|
||||
struct sway_container *floater = child->current.floating->items[i];
|
||||
wlr_scene_node_reparent(&floater->scene_tree->node, root->layers.floating);
|
||||
wlr_scene_node_set_enabled(&floater->scene_tree->node, activated);
|
||||
}
|
||||
|
||||
if (activated) {
|
||||
struct sway_container *fs = child->current.fullscreen;
|
||||
wlr_scene_node_set_enabled(&child->layers.tiling->node, !fs);
|
||||
wlr_scene_node_set_enabled(&child->layers.fullscreen->node, fs);
|
||||
|
||||
arrange_workspace_floating(child);
|
||||
|
||||
wlr_scene_node_set_enabled(&output->layers.shell_background->node, !fs);
|
||||
wlr_scene_node_set_enabled(&output->layers.shell_bottom->node, !fs);
|
||||
wlr_scene_node_set_enabled(&output->layers.fullscreen->node, fs);
|
||||
|
||||
if (fs) {
|
||||
wlr_scene_rect_set_size(output->fullscreen_background, width, height);
|
||||
|
||||
arrange_fullscreen(child->layers.fullscreen, fs, child,
|
||||
width, height);
|
||||
} else {
|
||||
struct wlr_box *area = &output->usable_area;
|
||||
struct side_gaps *gaps = &child->current_gaps;
|
||||
|
||||
wlr_scene_node_set_position(&child->layers.tiling->node,
|
||||
gaps->left + area->x, gaps->top + area->y);
|
||||
|
||||
arrange_workspace_tiling(child,
|
||||
area->width - gaps->left - gaps->right,
|
||||
area->height - gaps->top - gaps->bottom);
|
||||
}
|
||||
} else {
|
||||
wlr_scene_node_set_enabled(&child->layers.tiling->node, false);
|
||||
wlr_scene_node_set_enabled(&child->layers.fullscreen->node, false);
|
||||
|
||||
disable_workspace(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void arrange_popup(struct wlr_scene_tree *popup) {
|
||||
struct wlr_scene_node *node;
|
||||
wl_list_for_each(node, &popup->children, link) {
|
||||
struct sway_xdg_popup *popup = scene_descriptor_try_get(node,
|
||||
SWAY_SCENE_DESC_POPUP);
|
||||
|
||||
// the popup layer may have popups from layer_shell surfaces, in this
|
||||
// case those don't have a scene descriptor, so lets skip those here.
|
||||
if (popup) {
|
||||
struct wlr_scene_tree *tree = popup->view->content_tree;
|
||||
|
||||
int lx, ly;
|
||||
wlr_scene_node_coords(&tree->node, &lx, &ly);
|
||||
wlr_scene_node_set_position(&popup->scene_tree->node, lx, ly);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void arrange_root(struct sway_root *root) {
|
||||
struct sway_container *fs = root->fullscreen_global;
|
||||
|
||||
wlr_scene_node_set_enabled(&root->layers.shell_background->node, !fs);
|
||||
wlr_scene_node_set_enabled(&root->layers.shell_bottom->node, !fs);
|
||||
wlr_scene_node_set_enabled(&root->layers.tiling->node, !fs);
|
||||
wlr_scene_node_set_enabled(&root->layers.floating->node, !fs);
|
||||
wlr_scene_node_set_enabled(&root->layers.shell_top->node, !fs);
|
||||
wlr_scene_node_set_enabled(&root->layers.fullscreen->node, !fs);
|
||||
|
||||
// hide all contents in the scratchpad
|
||||
for (int i = 0; i < root->scratchpad->length; i++) {
|
||||
struct sway_container *con = root->scratchpad->items[i];
|
||||
|
||||
wlr_scene_node_set_enabled(&con->scene_tree->node, false);
|
||||
}
|
||||
|
||||
if (fs) {
|
||||
for (int i = 0; i < root->outputs->length; i++) {
|
||||
struct sway_output *output = root->outputs->items[i];
|
||||
struct sway_workspace *ws = output->current.active_workspace;
|
||||
|
||||
if (ws) {
|
||||
arrange_workspace_floating(ws);
|
||||
}
|
||||
}
|
||||
|
||||
arrange_fullscreen(root->layers.fullscreen_global, fs, NULL,
|
||||
root->width, root->height);
|
||||
} else {
|
||||
for (int i = 0; i < root->outputs->length; i++) {
|
||||
struct sway_output *output = root->outputs->items[i];
|
||||
|
||||
wlr_scene_output_set_position(output->scene_output, output->lx, output->ly);
|
||||
|
||||
wlr_scene_node_reparent(&output->layers.shell_background->node, root->layers.shell_background);
|
||||
wlr_scene_node_reparent(&output->layers.shell_bottom->node, root->layers.shell_bottom);
|
||||
wlr_scene_node_reparent(&output->layers.tiling->node, root->layers.tiling);
|
||||
wlr_scene_node_reparent(&output->layers.shell_top->node, root->layers.shell_top);
|
||||
wlr_scene_node_reparent(&output->layers.shell_overlay->node, root->layers.shell_overlay);
|
||||
wlr_scene_node_reparent(&output->layers.fullscreen->node, root->layers.fullscreen);
|
||||
wlr_scene_node_reparent(&output->layers.session_lock->node, root->layers.session_lock);
|
||||
|
||||
wlr_scene_node_set_position(&output->layers.shell_background->node, output->lx, output->ly);
|
||||
wlr_scene_node_set_position(&output->layers.shell_bottom->node, output->lx, output->ly);
|
||||
wlr_scene_node_set_position(&output->layers.tiling->node, output->lx, output->ly);
|
||||
wlr_scene_node_set_position(&output->layers.fullscreen->node, output->lx, output->ly);
|
||||
wlr_scene_node_set_position(&output->layers.shell_top->node, output->lx, output->ly);
|
||||
wlr_scene_node_set_position(&output->layers.shell_overlay->node, output->lx, output->ly);
|
||||
wlr_scene_node_set_position(&output->layers.session_lock->node, output->lx, output->ly);
|
||||
|
||||
arrange_output(output, output->width, output->height);
|
||||
}
|
||||
}
|
||||
|
||||
arrange_popup(root->layers.popup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a transaction to the "current" state of the tree.
|
||||
*/
|
||||
|
@ -291,8 +717,6 @@ static void transaction_apply(struct sway_transaction *transaction) {
|
|||
|
||||
node->instruction = NULL;
|
||||
}
|
||||
|
||||
cursor_rebase_all();
|
||||
}
|
||||
|
||||
static void transaction_commit_pending(void);
|
||||
|
@ -305,6 +729,8 @@ static void transaction_progress(void) {
|
|||
return;
|
||||
}
|
||||
transaction_apply(server.queued_transaction);
|
||||
arrange_root(root);
|
||||
cursor_rebase_all();
|
||||
transaction_destroy(server.queued_transaction);
|
||||
server.queued_transaction = NULL;
|
||||
|
||||
|
|
Loading…
Reference in a new issue