Skip to content

Commit

Permalink
scene_graph: Arrange scene graph on transaction apply
Browse files Browse the repository at this point in the history
  • Loading branch information
Nefsen402 committed Feb 22, 2022
1 parent c975cfc commit c892965
Showing 1 changed file with 348 additions and 0 deletions.
348 changes: 348 additions & 0 deletions sway/desktop/transaction.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -250,6 +251,352 @@ static void apply_container_state(struct sway_container *container,
view_center_surface(view);
}
}

if (container_is_floating(container)) {
wlr_scene_node_reparent(container->scene_node, root->layers.floating);
}
}

static void layout_title_bar(struct sway_container *con,
int x, int y, int width, int height) {
container_update(con);

wlr_scene_node_set_enabled(con->title_bar.node, !!height);
if (height) {
int titlebar_border_thickness = config->titlebar_border_thickness;

wlr_scene_rect_set_size(con->title_bar.border, width, height);
wlr_scene_rect_set_size(con->title_bar.background,
width - titlebar_border_thickness * 2,
height - titlebar_border_thickness * 2);

wlr_scene_node_set_position(con->title_bar.node, x, y);
wlr_scene_node_set_position(&con->title_bar.background->node,
titlebar_border_thickness, titlebar_border_thickness);

container_layout_title_bar(con, width, height);
}
}

static void arrange_container(struct sway_container *con,
int width, int height, bool title_bar) {
// this container might have previously been in the scratchpad,
// make sure it's enabled for viewing
wlr_scene_node_set_enabled(con->scene_node, true);

// also make sure to disable the title bar if the parent is not managing it
// If we do actuall want to display it, layout_title_bar will re-enable it
if (title_bar && !con->view) {
wlr_scene_node_set_enabled(con->title_bar.node, false);
}

int content_x = 0, content_y = 0;
int title_bar_height = container_titlebar_height();

int gaps_inner = con->current.workspace->gaps_inner * title_bar;

if (con->current.layout == L_TABBED) {
wlr_scene_node_set_enabled(con->title_bar.node, true);
content_y = title_bar_height;

double w = (double) width / con->current.children->length;
for (int i = 0; i < con->current.children->length; i++) {
struct sway_container *child = con->current.children->items[i];
bool activated = child == con->current.focused_inactive_child;

layout_title_bar(child, w * i, -content_y, w, content_y);
wlr_scene_node_set_enabled(child->content.node, activated);
wlr_scene_node_set_position(child->scene_node, 0, 0);
wlr_scene_node_reparent(child->scene_node, con->content.node);

if (activated) {
arrange_container(child, width, height - title_bar_height, false);
}
}
} else if (con->current.layout == L_STACKED) {
wlr_scene_node_set_enabled(con->title_bar.node, true);
content_y = title_bar_height * con->current.children->length;

int y = 0;
for (int i = 0; i < con->current.children->length; i++) {
struct sway_container *child = con->current.children->items[i];
bool activated = child == con->current.focused_inactive_child;

layout_title_bar(child, 0, y - content_y, width, title_bar_height);
wlr_scene_node_set_enabled(child->content.node, activated);
wlr_scene_node_set_position(child->scene_node, 0, 0);
wlr_scene_node_reparent(child->scene_node, con->content.node);

if (activated) {
arrange_container(child, width, height - content_y, false);
}

y += title_bar_height;
}
} else if (con->current.layout == L_VERT) {
int off = 0;
for (int i = 0; i < con->current.children->length; i++) {
struct sway_container *child = con->current.children->items[i];
int cheight = child->current.height;

wlr_scene_node_set_enabled(child->content.node, true);
wlr_scene_node_set_position(child->scene_node, 0, off);
wlr_scene_node_reparent(child->scene_node, con->content.node);
arrange_container(child, width, cheight, true);
off += cheight + gaps_inner;
}
} else if (con->current.layout == L_HORIZ) {
int off = 0;
for (int i = 0; i < con->current.children->length; i++) {
struct sway_container *child = con->current.children->items[i];
int cwidth = child->current.width;

wlr_scene_node_set_enabled(child->content.node, true);
wlr_scene_node_set_position(child->scene_node, off, 0);
wlr_scene_node_reparent(child->scene_node, con->content.node);
arrange_container(child, cwidth, height, true);
off += cwidth + gaps_inner;
}
} else if (con->view) {
int border_width = con->current.border_thickness;

if (con->current.border == B_NORMAL) {
title_bar_height *= title_bar;

if (title_bar) {
layout_title_bar(con, 0, 0, width, title_bar_height);
}
} else if (con->current.border == B_PIXEL) {
container_update(con);
wlr_scene_node_set_enabled(con->title_bar.node, !title_bar);
title_bar_height = border_width * title_bar;
} else if (con->current.border == B_NONE) {
container_update(con);
title_bar_height = 0;
border_width = 0;
} else if (con->current.border == B_CSD) {
wlr_scene_node_set_enabled(con->title_bar.node, false);
title_bar_height = 0;
border_width = 0;
}

wlr_scene_node_set_enabled(&con->content.border_top->node,
con->current.border != B_NORMAL && title_bar);

wlr_scene_rect_set_size(con->content.border_top, width, border_width);
wlr_scene_rect_set_size(con->content.border_bottom, width, border_width);
wlr_scene_rect_set_size(con->content.border_left,
border_width, height - border_width - title_bar_height);
wlr_scene_rect_set_size(con->content.border_right,
border_width, height - border_width - title_bar_height);

wlr_scene_node_set_position(&con->content.border_top->node, -border_width, -border_width);
wlr_scene_node_set_position(&con->content.border_bottom->node, -border_width,
height - title_bar_height - border_width);
wlr_scene_node_set_position(&con->content.border_left->node, -border_width, 0);
wlr_scene_node_set_position(&con->content.border_right->node,
width - border_width * 2, 0);

// make sure to reparent, it's possible that the client just game out of fullscreen mode
// where the parent of the surface is not the container
wlr_scene_node_reparent(con->view->scene_node, con->content.node);

content_x = border_width;
content_y = title_bar_height;
} else {
sway_assert(false, "unreachable");
}

wlr_scene_node_set_position(con->content.node, content_x, content_y);
}

static void arrange_fullscreen(struct wlr_scene_node *scene_node,
struct sway_container *fs, int width, int height) {
if (fs->view) {
wlr_scene_node_reparent(fs->view->scene_node, scene_node);
}else{
wlr_scene_node_reparent(fs->scene_node, scene_node);
arrange_container(fs, width, height, true);
}

// transient containers
struct wlr_scene_node *node, *node_tmp;
wl_list_for_each_safe(node, node_tmp,
&root->layers.floating->state.children, state.link) {
struct sway_scene_descriptor *desc = node->data;

if (desc->type == SWAY_SCENE_DESC_NODE) {
struct sway_container *floater = desc->data;
bool trans = container_is_transient_for(floater, fs);
wlr_scene_node_set_enabled(floater->scene_node, trans);

if (trans) {
wlr_scene_node_set_position(floater->scene_node,
floater->current.x, floater->current.y);
wlr_scene_node_reparent(floater->scene_node, scene_node);

arrange_container(floater,
floater->current.width, floater->current.height, true);
}
}
}
}

static void arrange_workspace(struct sway_workspace *ws, int width, int height) {
struct sway_container *fs = ws->current.fullscreen;
wlr_scene_node_set_enabled(ws->layers.tiling, !fs);

if (fs) {
arrange_fullscreen(ws->layers.fullscreen, fs, width, height);
} else {
if (ws->current.layout == L_VERT) {
int off = 0;
for (int i = 0; i < ws->current.tiling->length; i++) {
struct sway_container *child = ws->current.tiling->items[i];
int cheight = child->current.height;

wlr_scene_node_reparent(child->scene_node, ws->layers.tiling);
wlr_scene_node_set_enabled(child->content.node, true);
wlr_scene_node_set_position(child->scene_node, 0, off);

arrange_container(child, width, cheight, true);
off += cheight + ws->gaps_inner;
}
} else if (ws->current.layout == L_HORIZ) {
int off = 0;
for (int i = 0; i < ws->current.tiling->length; i++) {
struct sway_container *child = ws->current.tiling->items[i];
int cwidth = child->current.width;

wlr_scene_node_reparent(child->scene_node, ws->layers.tiling);
wlr_scene_node_set_enabled(child->content.node, true);
wlr_scene_node_set_position(child->scene_node, off, 0);

arrange_container(child, cwidth, height, true);
off += cwidth + ws->gaps_inner;
}
}

for (int i = 0; i < ws->current.floating->length; i++) {
struct sway_container *child = ws->current.floating->items[i];

wlr_scene_node_set_enabled(child->scene_node, true);
wlr_scene_node_reparent(child->scene_node, root->layers.floating);
wlr_scene_node_set_position(child->scene_node, child->current.x, child->current.y);

arrange_container(child, child->current.width, child->current.height, true);
}
}
}

static void workspace_disable(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_node, ws->layers.tiling);
}

// if this fullscreen node was coming from an enabled output, the view
// parent would be of the old workspace.
if (ws->fullscreen) {
wlr_scene_node_reparent(ws->fullscreen->view->scene_node,
ws->fullscreen->content.node);
}

for (int i = 0; i < ws->current.floating->length; i++) {
struct sway_container *child = ws->current.floating->items[i];

wlr_scene_node_set_enabled(child->scene_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, output->layers.tiling);
wlr_scene_node_reparent(child->layers.fullscreen, output->layers.fullscreen);
wlr_scene_node_set_enabled(child->layers.tiling, activated);
wlr_scene_node_set_enabled(child->layers.fullscreen, activated);

// don't recurse if the workspace is invisible
if (activated) {
struct side_gaps *gaps = &child->current_gaps;
struct wlr_box *area = &output->usable_area;

wlr_scene_node_set_position(child->layers.tiling,
gaps->left + area->x, gaps->top + area->y);

arrange_workspace(child,
area->width - gaps->left - gaps->right,
area->height - gaps->top - gaps->bottom);
}else{
workspace_disable(child);
}
}
}

static void arrange_popups(struct wlr_scene_node *popups) {
struct wlr_scene_node *node;
wl_list_for_each(node, &popups->state.children, state.link) {
struct sway_scene_descriptor *desc = node->data;
if (desc->type == SWAY_SCENE_DESC_POPUP) {
struct sway_xdg_popup *popup = desc->data;

int lx, ly;
wlr_scene_node_coords(popup->child.view->xdg_surface_node, &lx, &ly);
wlr_scene_node_set_position(popup->child.scene_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, !fs);
wlr_scene_node_set_enabled(root->layers.shell_bottom, !fs);
wlr_scene_node_set_enabled(root->layers.tiling, !fs);
wlr_scene_node_set_enabled(root->layers.floating, !fs);
wlr_scene_node_set_enabled(root->layers.shell_top, !fs);
wlr_scene_node_set_enabled(root->layers.shell_overlay, !fs);

// hide all contains 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_node, false);
}

if (fs) {
arrange_fullscreen(root->layers.fullscreen, fs, 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, root->layers.shell_background);
wlr_scene_node_reparent(output->layers.shell_bottom, root->layers.shell_bottom);
wlr_scene_node_reparent(output->layers.tiling, root->layers.tiling);
wlr_scene_node_reparent(output->layers.shell_top, root->layers.shell_top);
wlr_scene_node_reparent(output->layers.shell_overlay, root->layers.shell_overlay);
wlr_scene_node_reparent(output->layers.fullscreen, root->layers.fullscreen);

wlr_scene_node_set_position(output->layers.shell_background, output->lx, output->ly);
wlr_scene_node_set_position(output->layers.shell_bottom, output->lx, output->ly);
wlr_scene_node_set_position(output->layers.tiling, output->lx, output->ly);
wlr_scene_node_set_position(output->layers.fullscreen, output->lx, output->ly);
wlr_scene_node_set_position(output->layers.shell_top, output->lx, output->ly);
wlr_scene_node_set_position(output->layers.shell_overlay, output->lx, output->ly);

arrange_output(output, output->width, output->height);
}

arrange_popups(root->layers.popups);
}

/**
Expand Down Expand Up @@ -305,6 +652,7 @@ static void transaction_progress(void) {
return;
}
transaction_apply(server.queued_transaction);
arrange_root(root);
transaction_destroy(server.queued_transaction);
server.queued_transaction = NULL;

Expand Down

0 comments on commit c892965

Please sign in to comment.