<commit_before>/*
 * vim:ts=4:sw=4:expandtab
 */

#include "all.h"

struct Con *croot;
struct Con *focused;

struct all_cons_head all_cons = TAILQ_HEAD_INITIALIZER(all_cons);

/*
 * Loads tree from ~/.i3/_restart.json (used for in-place restarts).
 *
 */
bool tree_restore(const char *path) {
    char *globbed = resolve_tilde(path);

    if (!path_exists(globbed)) {
        LOG("%s does not exist, not restoring tree\n", globbed);
        free(globbed);
        return false;
    }

    /* TODO: refactor the following */
    croot = con_new(NULL);
    focused = croot;

    tree_append_json(globbed);

    printf("appended tree, using new root\n");
    croot = TAILQ_FIRST(&(croot->nodes_head));
    printf("new root = %p\n", croot);
    Con *out = TAILQ_FIRST(&(croot->nodes_head));
    printf("out = %p\n", out);
    Con *ws = TAILQ_FIRST(&(out->nodes_head));
    printf("ws = %p\n", ws);

    return true;
}

/*
 * Initializes the tree by creating the root node. The CT_OUTPUT Cons below the
 * root node are created in randr.c for each Output.
 *
 */
void tree_init() {
    croot = con_new(NULL);
    FREE(croot->name);
    croot->name = "root";
    croot->type = CT_ROOT;
}

/*
 * Opens an empty container in the current container
 *
 */
Con *tree_open_con(Con *con) {
    if (con == NULL) {
        /* every focusable Con has a parent (outputs have parent root) */
        con = focused->parent;
        /* If the parent is an output, we are on a workspace. In this case,
         * the new container needs to be opened as a leaf of the workspace. */
        if (con->type == CT_OUTPUT)
            con = focused;
        /* If the currently focused container is a floating container, we
         * attach the new container to the workspace */
        if (con->type == CT_FLOATING_CON)
            con = con->parent;
    }

    assert(con != NULL);

    /* 3. create the container and attach it to its parent */
    Con *new = con_new(con);

    /* 4: re-calculate child->percent for each child */
    con_fix_percent(con);

    /* 5: focus the new container */
    con_focus(new);

    return new;
}

static bool _is_con_mapped(Con *con) {
    Con *child;

    TAILQ_FOREACH(child, &(con->nodes_head), nodes)
        if (_is_con_mapped(child))
            return true;

    return con->mapped;
}

/*
 * Closes the given container including all children
 *
 */
void tree_close(Con *con, bool kill_window, bool dont_kill_parent) {
    bool was_mapped = con->mapped;
    Con *parent = con->parent;

    if (!was_mapped) {
        /* Even if the container itself is not mapped, its children may be
         * mapped (for example split containers don't have a mapped window on
         * their own but usually contain mapped children). */
        was_mapped = _is_con_mapped(con);
    }

    /* Get the container which is next focused */
    Con *next = con_next_focused(con);
    DLOG("next = %p, focused = %p\n", next, focused);

    DLOG("closing %p, kill_window = %d\n", con, kill_window);
    Con *child;
    /* We cannot use TAILQ_FOREACH because the children get deleted
     * in their parent’s nodes_head */
    while (!TAILQ_EMPTY(&(con->nodes_head))) {
        child = TAILQ_FIRST(&(con->nodes_head));
        DLOG("killing child=%p\n", child);
        tree_close(child, kill_window, true);
    }

    if (con->window != NULL) {
        if (kill_window)
            x_window_kill(con->window->id);
        else {
            /* un-parent the window */
            xcb_reparent_window(conn, con->window->id, root, 0, 0);
            /* TODO: client_unmap to set state to withdrawn */

        }
        FREE(con->window->class_class);
        FREE(con->window->class_instance);
        FREE(con->window->name_x);
        FREE(con->window->name_json);
        free(con->window);
    }

    /* kill the X11 part of this container */
    x_con_kill(con);

    con_detach(con);
    if (con->type != CT_FLOATING_CON) {
        /* If the container is *not* floating, we might need to re-distribute
         * percentage values for the resized containers. */
        con_fix_percent(parent);
    }

    if (con_is_floating(con)) {
        Con *ws = con_get_workspace(con);
        DLOG("Container was floating, killing floating container\n");
        tree_close(parent, false, false);
        DLOG("parent container killed\n");
        if (con == focused) {
            DLOG("This is the focused container, i need to find another one to focus. I start looking at ws = %p\n", ws);
            /* go down the focus stack as far as possible */
            next = con_descend_focused(ws);

            dont_kill_parent = true;
            DLOG("Alright, focusing %p\n", next);
        } else {
            next = NULL;
        }
    }

    free(con->name);
    TAILQ_REMOVE(&all_cons, con, all_cons);
    free(con);

    /* in the case of floating windows, we already focused another container
     * when closing the parent, so we can exit now. */
    if (!next) {
        DLOG("No next container, i will just exit now\n");
        return;
    }

    if (was_mapped || con == focused) {
        if (kill_window || !dont_kill_parent) {
            DLOG("focusing %p / %s\n", next, next->name);
            /* TODO: check if the container (or one of its children) was focused */
            con_focus(next);
        }
        else {
            DLOG("not focusing because we're not killing anybody");
        }
    } else {
        DLOG("not focusing, was not mapped\n");
    }

    /* check if the parent container is empty now and close it */
    if (!dont_kill_parent &&
        parent->type != CT_WORKSPACE &&
        TAILQ_EMPTY(&(parent->nodes_head))) {
        DLOG("Closing empty parent container\n");
        /* TODO: check if this container would swallow any other client and
         * don’t close it automatically. */
        tree_close(parent, false, false);
    }
}<commit_msg>Bugfix: When the container which was just closed is focused, we *do* need to focus another one (Thanks mseed)<commit_after>/*
 * vim:ts=4:sw=4:expandtab
 */

#include "all.h"

struct Con *croot;
struct Con *focused;

struct all_cons_head all_cons = TAILQ_HEAD_INITIALIZER(all_cons);

/*
 * Loads tree from ~/.i3/_restart.json (used for in-place restarts).
 *
 */
bool tree_restore(const char *path) {
    char *globbed = resolve_tilde(path);

    if (!path_exists(globbed)) {
        LOG("%s does not exist, not restoring tree\n", globbed);
        free(globbed);
        return false;
    }

    /* TODO: refactor the following */
    croot = con_new(NULL);
    focused = croot;

    tree_append_json(globbed);

    printf("appended tree, using new root\n");
    croot = TAILQ_FIRST(&(croot->nodes_head));
    printf("new root = %p\n", croot);
    Con *out = TAILQ_FIRST(&(croot->nodes_head));
    printf("out = %p\n", out);
    Con *ws = TAILQ_FIRST(&(out->nodes_head));
    printf("ws = %p\n", ws);

    return true;
}

/*
 * Initializes the tree by creating the root node. The CT_OUTPUT Cons below the
 * root node are created in randr.c for each Output.
 *
 */
void tree_init() {
    croot = con_new(NULL);
    FREE(croot->name);
    croot->name = "root";
    croot->type = CT_ROOT;
}

/*
 * Opens an empty container in the current container
 *
 */
Con *tree_open_con(Con *con) {
    if (con == NULL) {
        /* every focusable Con has a parent (outputs have parent root) */
        con = focused->parent;
        /* If the parent is an output, we are on a workspace. In this case,
         * the new container needs to be opened as a leaf of the workspace. */
        if (con->type == CT_OUTPUT)
            con = focused;
        /* If the currently focused container is a floating container, we
         * attach the new container to the workspace */
        if (con->type == CT_FLOATING_CON)
            con = con->parent;
    }

    assert(con != NULL);

    /* 3. create the container and attach it to its parent */
    Con *new = con_new(con);

    /* 4: re-calculate child->percent for each child */
    con_fix_percent(con);

    /* 5: focus the new container */
    con_focus(new);

    return new;
}

static bool _is_con_mapped(Con *con) {
    Con *child;

    TAILQ_FOREACH(child, &(con->nodes_head), nodes)
        if (_is_con_mapped(child))
            return true;

    return con->mapped;
}

/*
 * Closes the given container including all children
 *
 */
void tree_close(Con *con, bool kill_window, bool dont_kill_parent) {
    bool was_mapped = con->mapped;
    Con *parent = con->parent;

    if (!was_mapped) {
        /* Even if the container itself is not mapped, its children may be
         * mapped (for example split containers don't have a mapped window on
         * their own but usually contain mapped children). */
        was_mapped = _is_con_mapped(con);
    }

    /* Get the container which is next focused */
    Con *next = con_next_focused(con);
    DLOG("next = %p, focused = %p\n", next, focused);

    DLOG("closing %p, kill_window = %d\n", con, kill_window);
    Con *child;
    /* We cannot use TAILQ_FOREACH because the children get deleted
     * in their parent’s nodes_head */
    while (!TAILQ_EMPTY(&(con->nodes_head))) {
        child = TAILQ_FIRST(&(con->nodes_head));
        DLOG("killing child=%p\n", child);
        tree_close(child, kill_window, true);
    }

    if (con->window != NULL) {
        if (kill_window)
            x_window_kill(con->window->id);
        else {
            /* un-parent the window */
            xcb_reparent_window(conn, con->window->id, root, 0, 0);
            /* TODO: client_unmap to set state to withdrawn */

        }
        FREE(con->window->class_class);
        FREE(con->window->class_instance);
        FREE(con->window->name_x);
        FREE(con->window->name_json);
        free(con->window);
    }

    /* kill the X11 part of this container */
    x_con_kill(con);

    con_detach(con);
    if (con->type != CT_FLOATING_CON) {
        /* If the container is *not* floating, we might need to re-distribute
         * percentage values for the resized containers. */
        con_fix_percent(parent);
    }

    if (con_is_floating(con)) {
        Con *ws = con_get_workspace(con);
        DLOG("Container was floating, killing floating container\n");
        tree_close(parent, false, false);
        DLOG("parent container killed\n");
        if (con == focused) {
            DLOG("This is the focused container, i need to find another one to focus. I start looking at ws = %p\n", ws);
            /* go down the focus stack as far as possible */
            next = con_descend_focused(ws);

            dont_kill_parent = true;
            DLOG("Alright, focusing %p\n", next);
        } else {
            next = NULL;
        }
    }

    free(con->name);
    TAILQ_REMOVE(&all_cons, con, all_cons);
    free(con);

    /* in the case of floating windows, we already focused another container
     * when closing the parent, so we can exit now. */
    if (!next) {
        DLOG("No next container, i will just exit now\n");
        return;
    }

    if (was_mapped || con == focused) {
        if (kill_window || !dont_kill_parent || con == focused) {
            DLOG("focusing %p / %s\n", next, next->name);
            /* TODO: check if the container (or one of its children) was focused */
            con_focus(next);
        }
        else {
            DLOG("not focusing because we're not killing anybody");
        }
    } else {
        DLOG("not focusing, was not mapped\n");
    }

    /* check if the parent container is empty now and close it */
    if (!dont_kill_parent &&
        parent->type != CT_WORKSPACE &&
        TAILQ_EMPTY(&(parent->nodes_head))) {
        DLOG("Closing empty parent container\n");
        /* TODO: check if this container would swallow any other client and
         * don’t close it automatically. */
        tree_close(parent, false, false);
    }
}
{'fraction_non_alphanumeric': 0.12283649806755167, 'fraction_numerical': 0.0016803898504453034, 'mean_word_length': 2.3539025077486615, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 75, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '590618', 'n_tokens_mistral': 3748, 'n_tokens_neox': 3658, 'n_words': 1148}