From bb5be480e71dbe776afbebcdc033319f103733bd Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ingo=20B=C3=BCrk?= Date: Thu, 10 Sep 2015 20:49:14 +0200 Subject: [PATCH] Move rendering the root node into a separate function. --- src/render.c | 344 ++++++++++++++++++++++++++------------------------- 1 file changed, 174 insertions(+), 170 deletions(-) diff --git a/src/render.c b/src/render.c index 94814220..f8c49c38 100644 --- a/src/render.c +++ b/src/render.c @@ -14,6 +14,8 @@ /* Forward declarations */ static int *precalculate_sizes(Con *con, render_params *p); +static void render_root(Con *con, Con *fullscreen); +static void render_output(Con *con); static void render_con_split(Con *con, Con *child, render_params *p, int i); static void render_con_stacked(Con *con, Con *child, render_params *p, int i); static void render_con_tabbed(Con *con, Con *child, render_params *p, int i); @@ -33,95 +35,6 @@ int render_deco_height(void) { return deco_height; } -/* - * Renders a container with layout L_OUTPUT. In this layout, all CT_DOCKAREAs - * get the height of their content and the remaining CT_CON gets the rest. - * - */ -static void render_l_output(Con *con) { - Con *child, *dockchild; - - int x = con->rect.x; - int y = con->rect.y; - int height = con->rect.height; - - /* Find the content container and ensure that there is exactly one. Also - * check for any non-CT_DOCKAREA clients. */ - Con *content = NULL; - TAILQ_FOREACH(child, &(con->nodes_head), nodes) { - if (child->type == CT_CON) { - if (content != NULL) { - DLOG("More than one CT_CON on output container\n"); - assert(false); - } - content = child; - } else if (child->type != CT_DOCKAREA) { - DLOG("Child %p of type %d is inside the OUTPUT con\n", child, child->type); - assert(false); - } - } - - if (content == NULL) { - DLOG("Skipping this output because it is currently being destroyed.\n"); - return; - } - - /* We need to find out if there is a fullscreen con on the current workspace - * and take the short-cut to render it directly (the user does not want to - * see the dockareas in that case) */ - Con *ws = con_get_fullscreen_con(content, CF_OUTPUT); - if (!ws) { - DLOG("Skipping this output because it is currently being destroyed.\n"); - return; - } - Con *fullscreen = con_get_fullscreen_con(ws, CF_OUTPUT); - if (fullscreen) { - fullscreen->rect = con->rect; - x_raise_con(fullscreen); - render_con(fullscreen, true); - return; - } - - /* First pass: determine the height of all CT_DOCKAREAs (the sum of their - * children) and figure out how many pixels we have left for the rest */ - TAILQ_FOREACH(child, &(con->nodes_head), nodes) { - if (child->type != CT_DOCKAREA) - continue; - - child->rect.height = 0; - TAILQ_FOREACH(dockchild, &(child->nodes_head), nodes) - child->rect.height += dockchild->geometry.height; - - height -= child->rect.height; - } - - /* Second pass: Set the widths/heights */ - TAILQ_FOREACH(child, &(con->nodes_head), nodes) { - if (child->type == CT_CON) { - child->rect.x = x; - child->rect.y = y; - child->rect.width = con->rect.width; - child->rect.height = height; - } - - child->rect.x = x; - child->rect.y = y; - child->rect.width = con->rect.width; - - child->deco_rect.x = 0; - child->deco_rect.y = 0; - child->deco_rect.width = 0; - child->deco_rect.height = 0; - - y += child->rect.height; - - DLOG("child at (%d, %d) with (%d x %d)\n", - child->rect.x, child->rect.y, child->rect.width, child->rect.height); - x_raise_con(child); - render_con(child, false); - } -} - /* * "Renders" the given container (and its children), meaning that all rects are * updated correctly. Note that this function does not call any xcb_* @@ -175,8 +88,7 @@ void render_con(Con *con, bool render_fullscreen) { * * Ignoring aspect ratio during fullscreen was necessary to fix MPlayer * subtitle rendering, see http://bugs.i3wm.org/594 */ - if (!render_fullscreen && - con->window->aspect_ratio > 0.0) { + if (!render_fullscreen && con->window->aspect_ratio > 0.0) { DLOG("aspect_ratio = %f, current width/height are %d/%d\n", con->window->aspect_ratio, inset->width, inset->height); double new_height = inset->height + 1; @@ -235,84 +147,9 @@ void render_con(Con *con, bool render_fullscreen) { /* Skip i3-internal outputs */ if (con_is_internal(con)) goto free_params; - render_l_output(con); + render_output(con); } else if (con->type == CT_ROOT) { - Con *output; - if (!fullscreen) { - TAILQ_FOREACH(output, &(con->nodes_head), nodes) { - render_con(output, false); - } - } - - /* We need to render floating windows after rendering all outputs’ - * tiling windows because they need to be on top of *every* output at - * all times. This is important when the user places floating - * windows/containers so that they overlap on another output. */ - DLOG("Rendering floating windows:\n"); - TAILQ_FOREACH(output, &(con->nodes_head), nodes) { - if (con_is_internal(output)) - continue; - /* Get the active workspace of that output */ - Con *content = output_get_content(output); - if (!content || TAILQ_EMPTY(&(content->focus_head))) { - DLOG("Skipping this output because it is currently being destroyed.\n"); - continue; - } - Con *workspace = TAILQ_FIRST(&(content->focus_head)); - Con *fullscreen = con_get_fullscreen_con(workspace, CF_OUTPUT); - Con *child; - TAILQ_FOREACH(child, &(workspace->floating_head), floating_windows) { - /* Don’t render floating windows when there is a fullscreen window - * on that workspace. Necessary to make floating fullscreen work - * correctly (ticket #564). */ - /* If there is no fullscreen->window, this cannot be a - * transient window, so we _know_ we need to skip it. This - * happens during restarts where the container already exists, - * but the window was not yet associated. */ - if (fullscreen != NULL && fullscreen->window == NULL) - continue; - if (fullscreen != NULL && fullscreen->window != NULL) { - Con *floating_child = con_descend_focused(child); - Con *transient_con = floating_child; - bool is_transient_for = false; - /* Exception to the above rule: smart - * popup_during_fullscreen handling (popups belonging to - * the fullscreen app will be rendered). */ - while (transient_con != NULL && - transient_con->window != NULL && - transient_con->window->transient_for != XCB_NONE) { - DLOG("transient_con = 0x%08x, transient_con->window->transient_for = 0x%08x, fullscreen_id = 0x%08x\n", - transient_con->window->id, transient_con->window->transient_for, fullscreen->window->id); - if (transient_con->window->transient_for == fullscreen->window->id) { - is_transient_for = true; - break; - } - Con *next_transient = con_by_window_id(transient_con->window->transient_for); - if (next_transient == NULL) - break; - /* Some clients (e.g. x11-ssh-askpass) actually set - * WM_TRANSIENT_FOR to their own window id, so break instead of - * looping endlessly. */ - if (transient_con == next_transient) - break; - transient_con = next_transient; - } - - if (!is_transient_for) - continue; - else { - DLOG("Rendering floating child even though in fullscreen mode: " - "floating->transient_for (0x%08x) --> fullscreen->id (0x%08x)\n", - floating_child->window->transient_for, fullscreen->window->id); - } - } - DLOG("floating child at (%d,%d) with %d x %d\n", - child->rect.x, child->rect.y, child->rect.width, child->rect.height); - x_raise_con(child); - render_con(child, false); - } - } - + render_root(con, fullscreen); } else { Con *child; TAILQ_FOREACH(child, &(con->nodes_head), nodes) { @@ -373,8 +210,8 @@ static int *precalculate_sizes(Con *con, render_params *p) { assigned += sizes[i++] = percentage * total; } assert(assigned == total || - (assigned > total && assigned - total <= p->children * 2) || - (assigned < total && total - assigned <= p->children * 2)); + (assigned > total && assigned - total <= p->children * 2) || + (assigned < total && total - assigned <= p->children * 2)); int signal = assigned < total ? 1 : -1; while (assigned != total) { for (i = 0; i < p->children && assigned != total; ++i) { @@ -387,6 +224,173 @@ static int *precalculate_sizes(Con *con, render_params *p) { return sizes; } +static void render_root(Con *con, Con *fullscreen) { + Con *output; + if (!fullscreen) { + TAILQ_FOREACH(output, &(con->nodes_head), nodes) { + render_con(output, false); + } + } + + /* We need to render floating windows after rendering all outputs’ + * tiling windows because they need to be on top of *every* output at + * all times. This is important when the user places floating + * windows/containers so that they overlap on another output. */ + DLOG("Rendering floating windows:\n"); + TAILQ_FOREACH(output, &(con->nodes_head), nodes) { + if (con_is_internal(output)) + continue; + /* Get the active workspace of that output */ + Con *content = output_get_content(output); + if (!content || TAILQ_EMPTY(&(content->focus_head))) { + DLOG("Skipping this output because it is currently being destroyed.\n"); + continue; + } + Con *workspace = TAILQ_FIRST(&(content->focus_head)); + Con *fullscreen = con_get_fullscreen_con(workspace, CF_OUTPUT); + Con *child; + TAILQ_FOREACH(child, &(workspace->floating_head), floating_windows) { + /* Don’t render floating windows when there is a fullscreen window + * on that workspace. Necessary to make floating fullscreen work + * correctly (ticket #564). */ + /* If there is no fullscreen->window, this cannot be a + * transient window, so we _know_ we need to skip it. This + * happens during restarts where the container already exists, + * but the window was not yet associated. */ + if (fullscreen != NULL && fullscreen->window == NULL) + continue; + if (fullscreen != NULL && fullscreen->window != NULL) { + Con *floating_child = con_descend_focused(child); + Con *transient_con = floating_child; + bool is_transient_for = false; + /* Exception to the above rule: smart + * popup_during_fullscreen handling (popups belonging to + * the fullscreen app will be rendered). */ + while (transient_con != NULL && + transient_con->window != NULL && + transient_con->window->transient_for != XCB_NONE) { + DLOG("transient_con = 0x%08x, transient_con->window->transient_for = 0x%08x, fullscreen_id = 0x%08x\n", + transient_con->window->id, transient_con->window->transient_for, fullscreen->window->id); + if (transient_con->window->transient_for == fullscreen->window->id) { + is_transient_for = true; + break; + } + Con *next_transient = con_by_window_id(transient_con->window->transient_for); + if (next_transient == NULL) + break; + /* Some clients (e.g. x11-ssh-askpass) actually set + * WM_TRANSIENT_FOR to their own window id, so break instead of + * looping endlessly. */ + if (transient_con == next_transient) + break; + transient_con = next_transient; + } + + if (!is_transient_for) + continue; + else { + DLOG("Rendering floating child even though in fullscreen mode: " + "floating->transient_for (0x%08x) --> fullscreen->id (0x%08x)\n", + floating_child->window->transient_for, fullscreen->window->id); + } + } + DLOG("floating child at (%d,%d) with %d x %d\n", + child->rect.x, child->rect.y, child->rect.width, child->rect.height); + x_raise_con(child); + render_con(child, false); + } + } +} + +/* + * Renders a container with layout L_OUTPUT. In this layout, all CT_DOCKAREAs + * get the height of their content and the remaining CT_CON gets the rest. + * + */ +static void render_output(Con *con) { + Con *child, *dockchild; + + int x = con->rect.x; + int y = con->rect.y; + int height = con->rect.height; + + /* Find the content container and ensure that there is exactly one. Also + * check for any non-CT_DOCKAREA clients. */ + Con *content = NULL; + TAILQ_FOREACH(child, &(con->nodes_head), nodes) { + if (child->type == CT_CON) { + if (content != NULL) { + DLOG("More than one CT_CON on output container\n"); + assert(false); + } + content = child; + } else if (child->type != CT_DOCKAREA) { + DLOG("Child %p of type %d is inside the OUTPUT con\n", child, child->type); + assert(false); + } + } + + if (content == NULL) { + DLOG("Skipping this output because it is currently being destroyed.\n"); + return; + } + + /* We need to find out if there is a fullscreen con on the current workspace + * and take the short-cut to render it directly (the user does not want to + * see the dockareas in that case) */ + Con *ws = con_get_fullscreen_con(content, CF_OUTPUT); + if (!ws) { + DLOG("Skipping this output because it is currently being destroyed.\n"); + return; + } + Con *fullscreen = con_get_fullscreen_con(ws, CF_OUTPUT); + if (fullscreen) { + fullscreen->rect = con->rect; + x_raise_con(fullscreen); + render_con(fullscreen, true); + return; + } + + /* First pass: determine the height of all CT_DOCKAREAs (the sum of their + * children) and figure out how many pixels we have left for the rest */ + TAILQ_FOREACH(child, &(con->nodes_head), nodes) { + if (child->type != CT_DOCKAREA) + continue; + + child->rect.height = 0; + TAILQ_FOREACH(dockchild, &(child->nodes_head), nodes) + child->rect.height += dockchild->geometry.height; + + height -= child->rect.height; + } + + /* Second pass: Set the widths/heights */ + TAILQ_FOREACH(child, &(con->nodes_head), nodes) { + if (child->type == CT_CON) { + child->rect.x = x; + child->rect.y = y; + child->rect.width = con->rect.width; + child->rect.height = height; + } + + child->rect.x = x; + child->rect.y = y; + child->rect.width = con->rect.width; + + child->deco_rect.x = 0; + child->deco_rect.y = 0; + child->deco_rect.width = 0; + child->deco_rect.height = 0; + + y += child->rect.height; + + DLOG("child at (%d, %d) with (%d x %d)\n", + child->rect.x, child->rect.y, child->rect.width, child->rect.height); + x_raise_con(child); + render_con(child, false); + } +} + static void render_con_split(Con *con, Con *child, render_params *p, int i) { assert(con->layout == L_SPLITH || con->layout == L_SPLITV); -- 2.39.5