i3
|
00001 /* 00002 * vim:ts=4:sw=4:expandtab 00003 */ 00004 00005 #include "all.h" 00006 #include "cmdparse.tab.h" 00007 00008 typedef enum { BEFORE, AFTER } position_t; 00009 00010 /* 00011 * This function detaches 'con' from its parent and inserts it either before or 00012 * after 'target'. 00013 * 00014 */ 00015 static void insert_con_into(Con *con, Con *target, position_t position) { 00016 Con *parent = target->parent; 00017 /* We need to preserve the old con->parent. While it might still be used to 00018 * insert the entry before/after it, we call the on_remove_child callback 00019 * afterwards which might then close the con if it is empty. */ 00020 Con *old_parent = con->parent; 00021 00022 con_detach(con); 00023 con_fix_percent(con->parent); 00024 00025 /* When moving to a workspace, we respect the user’s configured 00026 * workspace_layout */ 00027 if (parent->type == CT_WORKSPACE) { 00028 Con *split = workspace_attach_to(parent); 00029 if (split != parent) { 00030 DLOG("Got a new split con, using that one instead\n"); 00031 con->parent = split; 00032 con_attach(con, split, false); 00033 DLOG("attached\n"); 00034 con->percent = 0.0; 00035 con_fix_percent(split); 00036 con = split; 00037 DLOG("ok, continuing with con %p instead\n", con); 00038 con_detach(con); 00039 } 00040 } 00041 00042 con->parent = parent; 00043 00044 if (position == BEFORE) { 00045 TAILQ_INSERT_BEFORE(target, con, nodes); 00046 TAILQ_INSERT_HEAD(&(parent->focus_head), con, focused); 00047 } else if (position == AFTER) { 00048 TAILQ_INSERT_AFTER(&(parent->nodes_head), target, con, nodes); 00049 TAILQ_INSERT_HEAD(&(parent->focus_head), con, focused); 00050 } 00051 00052 /* Pretend the con was just opened with regards to size percent values. 00053 * Since the con is moved to a completely different con, the old value 00054 * does not make sense anyways. */ 00055 con->percent = 0.0; 00056 con_fix_percent(parent); 00057 00058 CALL(old_parent, on_remove_child); 00059 } 00060 00061 /* 00062 * This function detaches 'con' from its parent and inserts it at the given 00063 * workspace. 00064 * 00065 */ 00066 static void attach_to_workspace(Con *con, Con *ws) { 00067 con_detach(con); 00068 con_fix_percent(con->parent); 00069 00070 CALL(con->parent, on_remove_child); 00071 00072 con->parent = ws; 00073 00074 TAILQ_INSERT_TAIL(&(ws->nodes_head), con, nodes); 00075 TAILQ_INSERT_TAIL(&(ws->focus_head), con, focused); 00076 00077 /* Pretend the con was just opened with regards to size percent values. 00078 * Since the con is moved to a completely different con, the old value 00079 * does not make sense anyways. */ 00080 con->percent = 0.0; 00081 con_fix_percent(ws); 00082 } 00083 00084 /* 00085 * Moves the current container in the given direction (TOK_LEFT, TOK_RIGHT, 00086 * TOK_UP, TOK_DOWN from cmdparse.l) 00087 * 00088 */ 00089 void tree_move(int direction) { 00090 DLOG("Moving in direction %d\n", direction); 00091 /* 1: get the first parent with the same orientation */ 00092 Con *con = focused; 00093 00094 if (con->type == CT_WORKSPACE) { 00095 DLOG("Not moving workspace\n"); 00096 return; 00097 } 00098 00099 if (con->parent->type == CT_WORKSPACE && con_num_children(con->parent) == 1) { 00100 DLOG("This is the only con on this workspace, not doing anything\n"); 00101 return; 00102 } 00103 00104 orientation_t o = (direction == TOK_LEFT || direction == TOK_RIGHT ? HORIZ : VERT); 00105 00106 Con *same_orientation = con_parent_with_orientation(con, o); 00107 /* The do {} while is used to 'restart' at this point with a different 00108 * same_orientation, see the very last lines before the end of this block 00109 * */ 00110 do { 00111 /* There is no parent container with the same orientation */ 00112 if (!same_orientation) { 00113 if (con_is_floating(con)) { 00114 /* this is a floating con, we just disable floating */ 00115 floating_disable(con, true); 00116 return; 00117 } 00118 if (con_inside_floating(con)) { 00119 /* 'con' should be moved out of a floating container */ 00120 DLOG("Inside floating, moving to workspace\n"); 00121 attach_to_workspace(con, con_get_workspace(con)); 00122 goto end; 00123 } 00124 DLOG("Force-changing orientation\n"); 00125 ws_force_orientation(con_get_workspace(con), o); 00126 same_orientation = con_parent_with_orientation(con, o); 00127 } 00128 00129 /* easy case: the move is within this container */ 00130 if (same_orientation == con->parent) { 00131 DLOG("We are in the same container\n"); 00132 Con *swap; 00133 if ((swap = (direction == TOK_LEFT || direction == TOK_UP ? 00134 TAILQ_PREV(con, nodes_head, nodes) : 00135 TAILQ_NEXT(con, nodes)))) { 00136 if (!con_is_leaf(swap)) { 00137 insert_con_into(con, con_descend_focused(swap), AFTER); 00138 goto end; 00139 } 00140 if (direction == TOK_LEFT || direction == TOK_UP) 00141 TAILQ_SWAP(swap, con, &(swap->parent->nodes_head), nodes); 00142 else TAILQ_SWAP(con, swap, &(swap->parent->nodes_head), nodes); 00143 00144 TAILQ_REMOVE(&(con->parent->focus_head), con, focused); 00145 TAILQ_INSERT_HEAD(&(swap->parent->focus_head), con, focused); 00146 00147 DLOG("Swapped.\n"); 00148 return; 00149 } 00150 00151 /* If there was no con with which we could swap the current one, search 00152 * again, but starting one level higher. If we are on the workspace 00153 * level, don’t do that. The result would be a force change of 00154 * workspace orientation, which is not necessary. */ 00155 if (con->parent == con_get_workspace(con)) 00156 return; 00157 same_orientation = con_parent_with_orientation(con->parent, o); 00158 } 00159 } while (same_orientation == NULL); 00160 00161 /* this time, we have to move to another container */ 00162 /* This is the container *above* 'con' (an ancestor of con) which is inside 00163 * 'same_orientation' */ 00164 Con *above = con; 00165 while (above->parent != same_orientation) 00166 above = above->parent; 00167 00168 DLOG("above = %p\n", above); 00169 Con *next; 00170 position_t position; 00171 if (direction == TOK_UP || direction == TOK_LEFT) { 00172 position = BEFORE; 00173 next = TAILQ_PREV(above, nodes_head, nodes); 00174 } else { 00175 position = AFTER; 00176 next = TAILQ_NEXT(above, nodes); 00177 } 00178 00179 /* special case: there is a split container in the direction we are moving 00180 * to, so descend and append */ 00181 if (next && !con_is_leaf(next)) 00182 insert_con_into(con, con_descend_focused(next), AFTER); 00183 else 00184 insert_con_into(con, above, position); 00185 00186 end: 00187 /* We need to call con_focus() to fix the focus stack "above" the container 00188 * we just inserted the focused container into (otherwise, the parent 00189 * container(s) would still point to the old container(s)). */ 00190 con_focus(con); 00191 00192 tree_flatten(croot); 00193 }