X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Ftree.c;h=0c301209e7ec6efdf6afe9767ddabb7cb7d85c25;hb=refs%2Fpull%2F2203%2Fhead;hp=bbd5e6a472f39f736ccf8a61c10534335ec1c666;hpb=01a2c5a3f16be97f1afe9cb40d802c4f8deed86c;p=i3%2Fi3 diff --git a/src/tree.c b/src/tree.c index bbd5e6a4..0c301209 100644 --- a/src/tree.c +++ b/src/tree.c @@ -4,7 +4,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * tree.c: Everything that primarily modifies the layout tree data structure. * @@ -76,7 +76,7 @@ bool tree_restore(const char *path, xcb_get_geometry_reply_t *geometry) { /* TODO: refactor the following */ croot = con_new(NULL, NULL); - croot->rect = (Rect) { + croot->rect = (Rect){ geometry->x, geometry->y, geometry->width, @@ -84,6 +84,7 @@ bool tree_restore(const char *path, xcb_get_geometry_reply_t *geometry) { focused = croot; tree_append_json(focused, globbed, NULL); + free(globbed); DLOG("appended tree, using new root\n"); croot = TAILQ_FIRST(&(croot->nodes_head)); @@ -104,6 +105,8 @@ bool tree_restore(const char *path, xcb_get_geometry_reply_t *geometry) { TAILQ_INSERT_HEAD(&(croot->nodes_head), __i3, nodes); } + restore_open_placeholder_windows(croot); + return true; } @@ -118,7 +121,7 @@ void tree_init(xcb_get_geometry_reply_t *geometry) { croot->name = "root"; croot->type = CT_ROOT; croot->layout = L_SPLITH; - croot->rect = (Rect) { + croot->rect = (Rect){ geometry->x, geometry->y, geometry->width, @@ -183,11 +186,11 @@ static bool _is_con_mapped(Con *con) { * recursively while deleting a containers children. * * The force_set_focus flag is specified in the case of killing a floating - * window: tree_close() will be invoked for the CT_FLOATINGCON (the parent + * window: tree_close_internal() will be invoked for the CT_FLOATINGCON (the parent * container) and focus should be set there. * */ -bool tree_close(Con *con, kill_window_t kill_window, bool dont_kill_parent, bool force_set_focus) { +bool tree_close_internal(Con *con, kill_window_t kill_window, bool dont_kill_parent, bool force_set_focus) { bool was_mapped = con->mapped; Con *parent = con->parent; @@ -200,7 +203,7 @@ bool tree_close(Con *con, kill_window_t kill_window, bool dont_kill_parent, bool /* remove the urgency hint of the workspace (if set) */ if (con->urgent) { - con->urgent = false; + con_set_urgency(con, false); con_update_parents_urgency(con); workspace_update_urgent_flag(con_get_workspace(con)); } @@ -217,7 +220,7 @@ bool tree_close(Con *con, kill_window_t kill_window, bool dont_kill_parent, bool for (child = TAILQ_FIRST(&(con->nodes_head)); child;) { nextchild = TAILQ_NEXT(child, nodes); DLOG("killing child=%p\n", child); - if (!tree_close(child, kill_window, true, false)) + if (!tree_close_internal(child, kill_window, true, false)) abort_kill = true; child = nextchild; } @@ -237,7 +240,7 @@ bool tree_close(Con *con, kill_window_t kill_window, bool dont_kill_parent, bool * 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_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); @@ -251,16 +254,20 @@ bool tree_close(Con *con, kill_window_t kill_window, bool dont_kill_parent, bool cookie = xcb_change_property(conn, XCB_PROP_MODE_REPLACE, con->window->id, A_WM_STATE, A_WM_STATE, 32, 2, data); + /* Remove the window from the save set. All windows in the save set + * will be mapped when i3 closes its connection (e.g. when + * restarting). This is not what we want, since some apps keep + * unmapped windows around and don’t expect them to suddenly be + * mapped. See http://bugs.i3wm.org/1617 */ + xcb_change_save_set(conn, XCB_SET_MODE_DELETE, con->window->id); + /* Ignore X11 errors for the ReparentWindow request. * X11 Errors are returned when the window was already destroyed */ add_ignore_event(cookie.sequence, 0); } ipc_send_window_event("close", con); - FREE(con->window->class_class); - FREE(con->window->class_instance); - i3string_free(con->window->name); - FREE(con->window->ran_assignments); - FREE(con->window); + window_free(con->window); + con->window = NULL; } Con *ws = con_get_workspace(con); @@ -301,7 +308,7 @@ bool tree_close(Con *con, kill_window_t kill_window, bool dont_kill_parent, bool * 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 + * tree_close_internal calls itself recursively) because the tree is in a * non-renderable state during that time. */ if (!dont_kill_parent) tree_render(); @@ -311,13 +318,19 @@ bool tree_close(Con *con, kill_window_t kill_window, bool dont_kill_parent, bool if (con_is_floating(con)) { DLOG("Container was floating, killing floating container\n"); - tree_close(parent, DONT_KILL_WINDOW, false, (con == focused)); + tree_close_internal(parent, DONT_KILL_WINDOW, false, (con == focused)); DLOG("parent container killed\n"); } free(con->name); FREE(con->deco_render_params); TAILQ_REMOVE(&all_cons, con, all_cons); + while (!TAILQ_EMPTY(&(con->swallow_head))) { + Match *match = TAILQ_FIRST(&(con->swallow_head)); + TAILQ_REMOVE(&(con->swallow_head), match, matches); + match_free(match); + free(match); + } free(con); /* in the case of floating windows, we already focused another container @@ -353,34 +366,6 @@ bool tree_close(Con *con, kill_window_t kill_window, bool dont_kill_parent, bool return true; } -/* - * Closes the current container using tree_close(). - * - */ -void tree_close_con(kill_window_t kill_window) { - assert(focused != NULL); - - /* 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); -} - /* * Splits (horizontally or vertically) the given container by creating a new * container which contains the old one and the future ones. @@ -407,8 +392,7 @@ void tree_split(Con *con, orientation_t orientation) { Con *parent = con->parent; /* Force re-rendering to make the indicator border visible. */ - FREE(con->deco_render_params); - FREE(parent->deco_render_params); + con_force_split_parents_redraw(con); /* if we are in a container whose parent contains only one * child (its split functionality is unused so far), we just change the @@ -599,33 +583,38 @@ static bool _tree_next(Con *con, char way, orientation_t orientation, bool wrap) Con *parent = con->parent; if (con->type == CT_FLOATING_CON) { + if (orientation != HORIZ) + return false; + /* left/right focuses the previous/next floating container */ - if (orientation == HORIZ) { - Con *next; + Con *next; + if (way == 'n') + next = TAILQ_NEXT(con, floating_windows); + else + next = TAILQ_PREV(con, floating_head, floating_windows); + + /* If there is no next/previous container, wrap */ + if (!next) { if (way == 'n') - next = TAILQ_NEXT(con, floating_windows); + next = TAILQ_FIRST(&(parent->floating_head)); else - next = TAILQ_PREV(con, floating_head, floating_windows); - - /* If there is no next/previous container, wrap */ - if (!next) { - if (way == 'n') - next = TAILQ_FIRST(&(parent->floating_head)); - else - next = TAILQ_LAST(&(parent->floating_head), floating_head); - } - - /* Still no next/previous container? bail out */ - if (!next) - return false; + next = TAILQ_LAST(&(parent->floating_head), floating_head); + } - con_focus(con_descend_focused(next)); - return true; - } else { - /* up/down cycles through the Z-index */ - /* TODO: implement cycling through the z-index */ + /* Still no next/previous container? bail out */ + if (!next) return false; + + /* Raise the floating window on top of other windows preserving + * relative stack order */ + while (TAILQ_LAST(&(parent->floating_head), floating_head) != next) { + Con *last = TAILQ_LAST(&(parent->floating_head), floating_head); + TAILQ_REMOVE(&(parent->floating_head), last, floating_windows); + TAILQ_INSERT_HEAD(&(parent->floating_head), last, floating_windows); } + + con_focus(con_descend_focused(next)); + return true; } /* If the orientation does not match or there is no other con to focus, we @@ -760,7 +749,7 @@ void tree_flatten(Con *con) { /* 4: close the redundant cons */ DLOG("closing redundant cons\n"); - tree_close(con, DONT_KILL_WINDOW, true, false); + tree_close_internal(con, DONT_KILL_WINDOW, true, false); /* Well, we got to abort the recursion here because we destroyed the * container. However, if tree_flatten() is called sufficiently often,