diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index cdfa3f8c51..e71e3f6e66 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c @@ -5,6 +5,7 @@ #include #include #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" @@ -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); } /** @@ -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;