X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Ftree.c;h=9c8f56026f7baf95a1d2e0405ca5efb8a4d3bc82;hb=617afc67a25c9bb7bf91a7659319e07fbe32d758;hp=657c8bfa757d8fbd1ed663defb705ba31b60cffc;hpb=064be457e59603e1d4a4b45b4bf138dcc231a849;p=i3%2Fi3 diff --git a/src/tree.c b/src/tree.c index 657c8bfa..9c8f5602 100644 --- a/src/tree.c +++ b/src/tree.c @@ -84,15 +84,15 @@ bool tree_restore(const char *path, xcb_get_geometry_reply_t *geometry) { }; focused = croot; - tree_append_json(globbed); + tree_append_json(focused, globbed, NULL); - printf("appended tree, using new root\n"); + DLOG("appended tree, using new root\n"); croot = TAILQ_FIRST(&(croot->nodes_head)); - printf("new root = %p\n", croot); + DLOG("new root = %p\n", croot); Con *out = TAILQ_FIRST(&(croot->nodes_head)); - printf("out = %p\n", out); + DLOG("out = %p\n", out); Con *ws = TAILQ_FIRST(&(out->nodes_head)); - printf("ws = %p\n", ws); + DLOG("ws = %p\n", ws); /* For in-place restarting into v4.2, we need to make sure the new * pseudo-output __i3 is present. */ @@ -200,6 +200,13 @@ bool tree_close(Con *con, kill_window_t kill_window, bool dont_kill_parent, bool was_mapped = _is_con_mapped(con); } + /* remove the urgency hint of the workspace (if set) */ + if (con->urgent) { + con->urgent = false; + con_update_parents_urgency(con); + workspace_update_urgent_flag(con_get_workspace(con)); + } + /* Get the container which is next focused */ Con *next = con_next_focused(con); DLOG("next = %p, focused = %p\n", next, focused); @@ -228,7 +235,12 @@ bool tree_close(Con *con, kill_window_t kill_window, bool dont_kill_parent, bool return false; } else { xcb_void_cookie_t cookie; - /* un-parent the window */ + /* Ignore any further events by clearing the event mask, + * unmap the window, + * then reparent it to the root window. */ + xcb_change_window_attributes(conn, con->window->id, + XCB_CW_EVENT_MASK, (uint32_t[]){ XCB_NONE }); + xcb_unmap_window(conn, con->window->id); cookie = xcb_reparent_window(conn, con->window->id, root, 0, 0); /* Ignore X11 errors for the ReparentWindow request. @@ -248,18 +260,32 @@ 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); i3string_free(con->window->name); - free(con->window); + FREE(con->window->ran_assignments); + 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(con_get_workspace(con)); + workspace_update_urgent_flag(ws); ev_timer_stop(main_loop, con->urgency_timer); FREE(con->urgency_timer); } @@ -270,21 +296,24 @@ bool tree_close(Con *con, kill_window_t kill_window, bool dont_kill_parent, bool 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); @@ -331,15 +360,24 @@ bool tree_close(Con *con, kill_window_t kill_window, bool dont_kill_parent, bool */ void tree_close_con(kill_window_t kill_window) { assert(focused != NULL); - if (focused->type == CT_WORKSPACE) { - LOG("Cannot close workspace\n"); - return; - } /* There *should* be no possibility to focus outputs / root container */ assert(focused->type != CT_OUTPUT); assert(focused->type != CT_ROOT); + if (focused->type == CT_WORKSPACE) { + DLOG("Workspaces cannot be close, closing all children instead\n"); + Con *child, *nextchild; + for (child = TAILQ_FIRST(&(focused->focus_head)); child; ) { + nextchild = TAILQ_NEXT(child, focused); + DLOG("killing child=%p\n", child); + tree_close(child, kill_window, false, false); + child = nextchild; + } + + return; + } + /* Kill con */ tree_close(focused, kill_window, false, false); } @@ -350,13 +388,23 @@ void tree_close_con(kill_window_t kill_window) { * */ 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->layout = (orientation == HORIZ) ? L_SPLITH : L_SPLITV; + if (con_is_floating(con)) { + DLOG("Floating containers can't be split.\n"); return; } + if (con->type == CT_WORKSPACE) { + if (con_num_children(con) < 2) { + DLOG("Just changing orientation of workspace\n"); + con->layout = (orientation == HORIZ) ? L_SPLITH : L_SPLITV; + return; + } else { + /* if there is more than one container on the workspace + * move them into a new container and handle this instead */ + con = workspace_encapsulate(con); + } + } + Con *parent = con->parent; /* Force re-rendering to make the indicator border visible. */ @@ -382,7 +430,6 @@ void tree_split(Con *con, orientation_t orientation) { TAILQ_REPLACE(&(parent->focus_head), con, new, focused); new->parent = parent; new->layout = (orientation == HORIZ) ? L_SPLITH : L_SPLITV; - new->split = true; /* 3: swap 'percent' (resize factor) */ new->percent = con->percent; @@ -397,9 +444,16 @@ 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) { ELOG("'focus parent': Focus is already on the workspace, cannot go higher than that.\n"); return false; @@ -416,9 +470,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; } @@ -463,9 +529,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; @@ -500,6 +577,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); @@ -529,7 +613,6 @@ static bool _tree_next(Con *con, char way, orientation_t orientation, bool wrap) if (!next) return false; - floating_raise_con(next); con_focus(con_descend_focused(next)); return true; } else { @@ -627,8 +710,10 @@ void tree_flatten(Con *con) { /* The child must have a different orientation than the con but the same as * the con’s parent to be redundant */ - if (!con->split || - !child->split || + if (!con_is_split(con) || + !con_is_split(child) || + (con->layout != L_SPLITH && con->layout != L_SPLITV) || + (child->layout != L_SPLITH && child->layout != L_SPLITV) || con_orientation(con) == con_orientation(child) || con_orientation(child) != con_orientation(parent)) goto recurse;