X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Ftree.c;h=c398ee1d36f6722a35fe4b77fb569ea3350d86d4;hb=24aa857a89876474bac5209428abb389bc1a9a75;hp=3ed392ac125b9462699638978e5df83afa85ce4b;hpb=1f682eb9c83535fba90d5f1864a921e72bc9f9b0;p=i3%2Fi3 diff --git a/src/tree.c b/src/tree.c index 3ed392ac..c398ee1d 100644 --- a/src/tree.c +++ b/src/tree.c @@ -1,3 +1,5 @@ +#undef I3__FILE__ +#define I3__FILE__ "tree.c" /* * vim:ts=4:sw=4:expandtab * @@ -29,7 +31,9 @@ static Con *_create___i3(void) { x_set_name(__i3, "[i3 con] pseudo-output __i3"); /* For retaining the correct position/size of a scratchpad window, the * dimensions of the real outputs should be multiples of the __i3 - * pseudo-output. */ + * pseudo-output. Ensuring that is the job of scratchpad_fix_resolution() + * which gets called after this function and after detecting all the + * outputs (or whenever an output changes). */ __i3->rect.width = 1280; __i3->rect.height = 1024; @@ -39,6 +43,7 @@ static Con *_create___i3(void) { content->type = CT_CON; FREE(content->name); content->name = sstrdup("content"); + content->layout = L_SPLITH; x_set_name(content, "[i3 con] content __i3"); con_attach(content, __i3, false); @@ -48,6 +53,7 @@ static Con *_create___i3(void) { ws->type = CT_WORKSPACE; ws->num = -1; ws->name = sstrdup("__i3_scratch"); + ws->layout = L_SPLITH; con_attach(ws, content, false); x_set_name(ws, "[i3 con] workspace __i3_scratch"); ws->fullscreen_mode = CF_OUTPUT; @@ -112,6 +118,7 @@ void tree_init(xcb_get_geometry_reply_t *geometry) { FREE(croot->name); croot->name = "root"; croot->type = CT_ROOT; + croot->layout = L_SPLITH; croot->rect = (Rect){ geometry->x, geometry->y, @@ -151,6 +158,7 @@ Con *tree_open_con(Con *con, i3Window *window) { /* 3. create the container and attach it to its parent */ Con *new = con_new(con, window); + new->layout = L_SPLITH; /* 4: re-calculate child->percent for each child */ con_fix_percent(con); @@ -239,36 +247,60 @@ bool tree_close(Con *con, kill_window_t kill_window, bool dont_kill_parent, bool } FREE(con->window->class_class); FREE(con->window->class_instance); - FREE(con->window->name_x); - FREE(con->window->name_json); + i3string_free(con->window->name); free(con->window); } - /* kill the X11 part of this container */ - x_con_kill(con); + Con *ws = con_get_workspace(con); + + /* Figure out which container to focus next before detaching 'con'. */ + if (con_is_floating(con)) { + 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); + next = con_next_focused(parent); + dont_kill_parent = true; + DLOG("Alright, focusing %p\n", next); + } else { + next = NULL; + } + } + + /* Detach the container so that it will not be rendered anymore. */ con_detach(con); + + /* disable urgency timer, if needed */ + if (con->urgency_timer != NULL) { + DLOG("Removing urgency timer of con %p\n", con); + workspace_update_urgent_flag(ws); + ev_timer_stop(main_loop, con->urgency_timer); + FREE(con->urgency_timer); + } + 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); } + /* Render the tree so that the surrounding containers take up the space + * which 'con' does no longer occupy. If we don’t render here, there will + * be a gap in our containers and that could trigger an EnterNotify for an + * underlying container, see ticket #660. + * + * Rendering has to be avoided when dont_kill_parent is set (when + * tree_close calls itself recursively) because the tree is in a + * non-renderable state during that time. */ + if (!dont_kill_parent) + tree_render(); + + /* kill the X11 part of this container */ + x_con_kill(con); + if (con_is_floating(con)) { - Con *ws = con_get_workspace(con); DLOG("Container was floating, killing floating container\n"); tree_close(parent, DONT_KILL_WINDOW, false, (con == focused)); 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); @@ -296,7 +328,7 @@ bool tree_close(Con *con, kill_window_t kill_window, bool dont_kill_parent, bool } } else { - DLOG("not focusing because we're not killing anybody"); + DLOG("not focusing because we're not killing anybody\n"); } } else { DLOG("not focusing, was not mapped\n"); @@ -337,7 +369,11 @@ void tree_split(Con *con, orientation_t orientation) { /* for a workspace, we just need to change orientation */ if (con->type == CT_WORKSPACE) { DLOG("Workspace, simply changing orientation to %d\n", orientation); - con->orientation = orientation; + con->layout = (orientation == HORIZ) ? L_SPLITH : L_SPLITV; + return; + } + else if (con->type == CT_FLOATING_CON) { + DLOG("Floating containers can't be split.\n"); return; } @@ -351,8 +387,9 @@ void tree_split(Con *con, orientation_t orientation) { * child (its split functionality is unused so far), we just change the * orientation (more intuitive than splitting again) */ if (con_num_children(parent) == 1 && - parent->layout == L_DEFAULT) { - parent->orientation = orientation; + (parent->layout == L_SPLITH || + parent->layout == L_SPLITV)) { + parent->layout = (orientation == HORIZ) ? L_SPLITH : L_SPLITV; DLOG("Just changing orientation of existing container\n"); return; } @@ -364,7 +401,7 @@ void tree_split(Con *con, orientation_t orientation) { TAILQ_REPLACE(&(parent->nodes_head), con, new, nodes); TAILQ_REPLACE(&(parent->focus_head), con, new, focused); new->parent = parent; - new->orientation = orientation; + new->layout = (orientation == HORIZ) ? L_SPLITH : L_SPLITV; /* 3: swap 'percent' (resize factor) */ new->percent = con->percent; @@ -379,11 +416,18 @@ void tree_split(Con *con, orientation_t orientation) { * */ bool level_up(void) { + /* Skip over floating containers and go directly to the grandparent + * (which should always be a workspace) */ + if (focused->parent->type == CT_FLOATING_CON) { + con_focus(focused->parent->parent); + return true; + } + /* We can focus up to the workspace, but not any higher in the tree */ if ((focused->parent->type != CT_CON && - focused->parent->type != CT_WORKSPACE) || + focused->parent->type != CT_WORKSPACE) || focused->type == CT_WORKSPACE) { - LOG("Cannot go up any further\n"); + ELOG("'focus parent': Focus is already on the workspace, cannot go higher than that.\n"); return false; } con_focus(focused->parent); @@ -398,9 +442,21 @@ bool level_down(void) { /* Go down the focus stack of the current node */ Con *next = TAILQ_FIRST(&(focused->focus_head)); if (next == TAILQ_END(&(focused->focus_head))) { - printf("cannot go down\n"); + DLOG("cannot go down\n"); return false; } + else if (next->type == CT_FLOATING_CON) { + /* Floating cons shouldn't be directly focused; try immediately + * going to the grandchild of the focused con. */ + Con *child = TAILQ_FIRST(&(next->focus_head)); + if (child == TAILQ_END(&(next->focus_head))) { + DLOG("cannot go down\n"); + return false; + } + else + next = TAILQ_FIRST(&(next->focus_head)); + } + con_focus(next); return true; } @@ -445,9 +501,20 @@ void tree_render(void) { * */ static bool _tree_next(Con *con, char way, orientation_t orientation, bool wrap) { + /* When dealing with fullscreen containers, it's necessary to go up to the + * workspace level, because 'focus $dir' will start at the con's real + * position in the tree, and it may not be possible to get to the edge + * normally due to fullscreen focusing restrictions. */ + if (con->fullscreen_mode == CF_OUTPUT && con->type != CT_WORKSPACE) + con = con_get_workspace(con); + /* Stop recursing at workspaces after attempting to switch to next * workspace if possible. */ if (con->type == CT_WORKSPACE) { + if (con_get_fullscreen_con(con, CF_GLOBAL)) { + DLOG("Cannot change workspace while in global fullscreen mode.\n"); + return false; + } Output *current_output = get_output_containing(con->rect.x, con->rect.y); Output *next_output; @@ -468,7 +535,7 @@ static bool _tree_next(Con *con, char way, orientation_t orientation, bool wrap) else return false; - next_output = get_output_next(direction, current_output); + next_output = get_output_next(direction, current_output, CLOSEST_OUTPUT); if (!next_output) return false; DLOG("Next output is %s\n", next_output->name); @@ -482,6 +549,13 @@ static bool _tree_next(Con *con, char way, orientation_t orientation, bool wrap) return false; workspace_show(workspace); + + /* If a workspace has an active fullscreen container, one of its + * children should always be focused. The above workspace_show() + * should be adequate for that, so return. */ + if (con_get_fullscreen_con(workspace, CF_OUTPUT)) + return true; + Con *focus = con_descend_direction(workspace, direction); if (focus) { con_focus(focus); @@ -594,7 +668,9 @@ void tree_flatten(Con *con) { DLOG("Checking if I can flatten con = %p / %s\n", con, con->name); /* We only consider normal containers without windows */ - if (con->type != CT_CON || con->window != NULL) + if (con->type != CT_CON || + parent->layout == L_OUTPUT || /* con == "content" */ + con->window != NULL) goto recurse; /* Ensure it got only one child */ @@ -602,12 +678,14 @@ void tree_flatten(Con *con) { if (child == NULL || TAILQ_NEXT(child, nodes) != NULL) goto recurse; + DLOG("child = %p, con = %p, parent = %p\n", child, con, parent); + /* The child must have a different orientation than the con but the same as * the con’s parent to be redundant */ - if (con->orientation == NO_ORIENTATION || - child->orientation == NO_ORIENTATION || - con->orientation == child->orientation || - child->orientation != parent->orientation) + if (!con_is_split(con) || + !con_is_split(child) || + con_orientation(con) == con_orientation(child) || + con_orientation(child) != con_orientation(parent)) goto recurse; DLOG("Alright, I have to flatten this situation now. Stay calm.\n");