forked from enlightenment/enlightenment
tiling: Implemented tiling window position manipulation
Summary: This implements the possibility to "break out" a node in the tree which means that the node will be appended or prependen to the parent in the grandparent. The other function "joins" the node to the node before or after. Basically it will be added as a child, and if necessarry the client of this node will be added in a new Window Tree and also added as a child. With the new actions you can move the focused window right/left/up/down with keybindings. If the window will "break out" or "join" depends on the parent split type. Sample: 1|4|6 2|4|6 3|5|6 (Same Number means same Window) 1 is focused. Left Key is pressed. 1 is in a vertical split so the window will "break out". Result: 2|1|4|6 2|1|5|6 Now another key: Down Key is pressed. 1 is in a vertical split so the window will "join". Result: 1|2|4|6 3 3|5|6 @feature Fixes T1350 Reviewers: tasn Subscribers: cedric Differential Revision: https://phab.enlightenment.org/D1382
This commit is contained in:
parent
310c10bca8
commit
4c0f0c638f
|
@ -786,7 +786,7 @@ _e_mod_menu_border_cb(void *data, E_Menu *m EINA_UNUSED,
|
|||
/* {{{ Move windows */
|
||||
|
||||
static void
|
||||
_action_swap(int cross_edge)
|
||||
_action_move(int cross_edge)
|
||||
{
|
||||
E_Desk *desk;
|
||||
E_Client *focused_ec;
|
||||
|
@ -807,7 +807,7 @@ _action_swap(int cross_edge)
|
|||
|
||||
if (item)
|
||||
{
|
||||
tiling_window_tree_node_move(item, cross_edge);
|
||||
tiling_window_tree_node_change_pos(item, cross_edge);
|
||||
|
||||
_reapply_tree();
|
||||
}
|
||||
|
@ -817,28 +817,28 @@ static void
|
|||
_e_mod_action_move_left_cb(E_Object *obj EINA_UNUSED,
|
||||
const char *params EINA_UNUSED)
|
||||
{
|
||||
_action_swap(TILING_WINDOW_TREE_EDGE_LEFT);
|
||||
_action_move(TILING_WINDOW_TREE_EDGE_LEFT);
|
||||
}
|
||||
|
||||
static void
|
||||
_e_mod_action_move_right_cb(E_Object *obj EINA_UNUSED,
|
||||
const char *params EINA_UNUSED)
|
||||
{
|
||||
_action_swap(TILING_WINDOW_TREE_EDGE_RIGHT);
|
||||
_action_move(TILING_WINDOW_TREE_EDGE_RIGHT);
|
||||
}
|
||||
|
||||
static void
|
||||
_e_mod_action_move_up_cb(E_Object *obj EINA_UNUSED,
|
||||
const char *params EINA_UNUSED)
|
||||
{
|
||||
_action_swap(TILING_WINDOW_TREE_EDGE_TOP);
|
||||
_action_move(TILING_WINDOW_TREE_EDGE_TOP);
|
||||
}
|
||||
|
||||
static void
|
||||
_e_mod_action_move_down_cb(E_Object *obj EINA_UNUSED,
|
||||
const char *params EINA_UNUSED)
|
||||
{
|
||||
_action_swap(TILING_WINDOW_TREE_EDGE_BOTTOM);
|
||||
_action_move(TILING_WINDOW_TREE_EDGE_BOTTOM);
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
|
|
|
@ -43,9 +43,8 @@ _tiling_window_tree_split_add(Window_Tree *parent, Window_Tree *new_node)
|
|||
parent->children =
|
||||
eina_inlist_append(parent->children, EINA_INLIST_GET(new_node));
|
||||
}
|
||||
|
||||
static void
|
||||
_tiling_window_tree_parent_add(Window_Tree *parent, Window_Tree *new_node, Window_Tree *rel)
|
||||
_tiling_window_tree_parent_add(Window_Tree *parent, Window_Tree *new_node, Window_Tree *rel, Eina_Bool append)
|
||||
{
|
||||
/* Adjust existing children's weights */
|
||||
Window_Tree *itr;
|
||||
|
@ -60,10 +59,19 @@ _tiling_window_tree_parent_add(Window_Tree *parent, Window_Tree *new_node, Windo
|
|||
{
|
||||
itr->weight *= weight;
|
||||
}
|
||||
|
||||
parent->children =
|
||||
eina_inlist_append_relative(parent->children, EINA_INLIST_GET(new_node),
|
||||
if (append)
|
||||
{
|
||||
parent->children = eina_inlist_append_relative(parent->children,
|
||||
EINA_INLIST_GET(new_node),
|
||||
EINA_INLIST_GET(rel));
|
||||
}
|
||||
else
|
||||
{
|
||||
parent->children = eina_inlist_prepend_relative(parent->children,
|
||||
EINA_INLIST_GET(new_node),
|
||||
EINA_INLIST_GET(rel));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -116,7 +124,7 @@ tiling_window_tree_add(Window_Tree *root, Window_Tree *parent,
|
|||
{
|
||||
if (parent->children)
|
||||
{
|
||||
_tiling_window_tree_parent_add(parent, new_node, NULL);
|
||||
_tiling_window_tree_parent_add(parent, new_node, NULL, EINA_TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -129,7 +137,7 @@ tiling_window_tree_add(Window_Tree *root, Window_Tree *parent,
|
|||
|
||||
if (grand_parent && grand_parent->children)
|
||||
{
|
||||
_tiling_window_tree_parent_add(grand_parent, new_node, orig_parent);
|
||||
_tiling_window_tree_parent_add(grand_parent, new_node, orig_parent, EINA_TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -145,20 +153,14 @@ tiling_window_tree_add(Window_Tree *root, Window_Tree *parent,
|
|||
return root;
|
||||
}
|
||||
|
||||
Window_Tree *
|
||||
tiling_window_tree_remove(Window_Tree *root, Window_Tree *item)
|
||||
static Window_Tree *
|
||||
tiling_window_tree_unref(Window_Tree *root, Window_Tree *item)
|
||||
{
|
||||
if (root == item)
|
||||
if (!item->client)
|
||||
{
|
||||
free(item);
|
||||
ERR("Tried to unref node %p that doesn't have a client.", item);
|
||||
return NULL;
|
||||
}
|
||||
else if (!item->client)
|
||||
{
|
||||
ERR("Tried deleting node %p that doesn't have a client.", item);
|
||||
return root;
|
||||
}
|
||||
|
||||
Window_Tree *parent = item->parent;
|
||||
int children_count = eina_inlist_count(item->parent->children);
|
||||
|
||||
|
@ -167,30 +169,24 @@ tiling_window_tree_remove(Window_Tree *root, Window_Tree *item)
|
|||
Window_Tree *grand_parent = parent->parent;
|
||||
Window_Tree *item_keep = NULL;
|
||||
|
||||
/* Adjust existing children's weights */
|
||||
EINA_INLIST_FOREACH(parent->children, item_keep)
|
||||
{
|
||||
if (item_keep != item)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!item_keep)
|
||||
{
|
||||
/* Special case of deleting the last vertical split item. */
|
||||
free(item);
|
||||
free(root);
|
||||
return NULL;
|
||||
parent->children =eina_inlist_remove(parent->children, EINA_INLIST_GET(item));
|
||||
return parent;
|
||||
}
|
||||
else if (!item_keep->children)
|
||||
else if (!item_keep->children && (parent != root))
|
||||
{
|
||||
parent->client = item_keep->client;
|
||||
parent->children = NULL;
|
||||
|
||||
free(item_keep);
|
||||
return grand_parent; //we must have a grand_parent here, case the parent is not root
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
parent->children =
|
||||
eina_inlist_remove(parent->children, EINA_INLIST_GET(item));
|
||||
if (grand_parent)
|
||||
|
@ -216,12 +212,14 @@ tiling_window_tree_remove(Window_Tree *root, Window_Tree *item)
|
|||
EINA_INLIST_GET(parent));
|
||||
free(parent);
|
||||
}
|
||||
return grand_parent;
|
||||
}
|
||||
else
|
||||
else if(item_keep)
|
||||
{
|
||||
/* This is fine, as this is a child of the root so we allow
|
||||
* two levels. */
|
||||
item_keep->weight = 1.0;
|
||||
return item_keep->parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -238,9 +236,34 @@ tiling_window_tree_remove(Window_Tree *root, Window_Tree *item)
|
|||
{
|
||||
itr->weight /= weight;
|
||||
}
|
||||
return parent;
|
||||
}
|
||||
ERR("This is a state where we should never come to.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Window_Tree *
|
||||
tiling_window_tree_remove(Window_Tree *root, Window_Tree *item)
|
||||
{
|
||||
if (root == item)
|
||||
{
|
||||
free(item);
|
||||
return NULL;
|
||||
}
|
||||
else if (!item->client)
|
||||
{
|
||||
ERR("Tried deleting node %p that doesn't have a client.", item);
|
||||
return root;
|
||||
}
|
||||
tiling_window_tree_unref(root, item);
|
||||
free(item);
|
||||
if (eina_inlist_count(root->children) == 0)
|
||||
{
|
||||
//the last possible client was closed so we remove root
|
||||
free(root);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
free(item);
|
||||
return root;
|
||||
}
|
||||
|
||||
|
@ -511,103 +534,125 @@ tiling_window_tree_edges_get(Window_Tree *node)
|
|||
}
|
||||
|
||||
/* Node move */
|
||||
static struct _Node_Move_Context
|
||||
/**
|
||||
* - break would mean that the node will be breaked out in the parent node and
|
||||
* put into the grand parent node.
|
||||
*
|
||||
* - join would mean that the node will be put together with the next/previous
|
||||
* child into a new split.
|
||||
*
|
||||
* - The eina_bool dir is the flag in which direction the node will be added ,
|
||||
* appended or prependet, or joined with the previous child or the next child
|
||||
*/
|
||||
void
|
||||
_tiling_window_tree_node_break_out(Window_Tree *root, Window_Tree *node, Eina_Bool dir)
|
||||
{
|
||||
Window_Tree *node;
|
||||
Window_Tree *ret;
|
||||
int cross_edge;
|
||||
int best_match;
|
||||
} _node_move_ctx;
|
||||
Window_Tree *res, *grand_parent;
|
||||
|
||||
#define CNODE (_node_move_ctx.node)
|
||||
|
||||
#define IF_MATCH_SET_LR(node) _tiling_window_tree_node_move_if_match_set(node, \
|
||||
CNODE->client->y, CNODE->client->h, node->client->y, node->client->h)
|
||||
#define IF_MATCH_SET_TB(node) _tiling_window_tree_node_move_if_match_set(node, \
|
||||
CNODE->client->x, CNODE->client->w, node->client->x, node->client->w)
|
||||
|
||||
static void
|
||||
_tiling_window_tree_node_move_if_match_set(Window_Tree *node, Evas_Coord cx,
|
||||
Evas_Coord cw, Evas_Coord ox, Evas_Coord ow)
|
||||
{
|
||||
Evas_Coord leftx, rightx;
|
||||
int match;
|
||||
|
||||
leftx = _TILE_MAX(cx, ox);
|
||||
rightx = _TILE_MIN(cx + cw, ox + ow);
|
||||
match = rightx - leftx;
|
||||
|
||||
if (match > _node_move_ctx.best_match)
|
||||
if (dir)
|
||||
{
|
||||
_node_move_ctx.best_match = match;
|
||||
_node_move_ctx.ret = node;
|
||||
res = _inlist_next(node->parent);
|
||||
if (res)
|
||||
dir = EINA_FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = _inlist_prev(node->parent);
|
||||
if (res)
|
||||
dir = EINA_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_tiling_window_tree_node_move_walker(void *_node)
|
||||
{
|
||||
Window_Tree *node = _node;
|
||||
int p = tiling_g.config->window_padding;
|
||||
/* We are only interested in nodes with clients. */
|
||||
if (!node->client)
|
||||
grand_parent = node->parent->parent;
|
||||
if (!grand_parent)
|
||||
return;
|
||||
|
||||
switch (_node_move_ctx.cross_edge)
|
||||
tiling_window_tree_unref(root, node);
|
||||
|
||||
_tiling_window_tree_parent_add(grand_parent, node, res, dir);
|
||||
}
|
||||
|
||||
void
|
||||
_tiling_window_tree_node_join(Window_Tree *root, Window_Tree *node, Eina_Bool dir)
|
||||
{
|
||||
Window_Tree *pn, *pl, *wts, *par;
|
||||
|
||||
if (dir)
|
||||
pn = _inlist_next(node);
|
||||
else
|
||||
pn = _inlist_prev(node);
|
||||
|
||||
if (!pn)
|
||||
return;
|
||||
|
||||
par = node->parent;
|
||||
if ((eina_inlist_count(par->children) == 2) && /* swap if there are just 2 */
|
||||
par->parent && (eina_inlist_count(par->parent->children) > 1)) /* do not swap if we are in the first level */
|
||||
{
|
||||
case TILING_WINDOW_TREE_EDGE_LEFT:
|
||||
if ((node->client->x + node->client->w + p) == CNODE->client->x)
|
||||
IF_MATCH_SET_LR(node);
|
||||
break;
|
||||
|
||||
case TILING_WINDOW_TREE_EDGE_RIGHT:
|
||||
if (node->client->x == (CNODE->client->x + CNODE->client->w + p))
|
||||
IF_MATCH_SET_LR(node);
|
||||
break;
|
||||
|
||||
case TILING_WINDOW_TREE_EDGE_TOP:
|
||||
if ((node->client->y + node->client->h + p) == CNODE->client->y)
|
||||
IF_MATCH_SET_TB(node);
|
||||
break;
|
||||
|
||||
case TILING_WINDOW_TREE_EDGE_BOTTOM:
|
||||
if (node->client->y == (CNODE->client->y + CNODE->client->h + p))
|
||||
IF_MATCH_SET_TB(node);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
par->children = eina_inlist_demote(par->children, eina_inlist_first(par->children));
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
pl = tiling_window_tree_unref(root, node);
|
||||
if (pl == node->parent)
|
||||
{
|
||||
//unref has not changed the tree
|
||||
if (!pn->children)
|
||||
_tiling_window_tree_split_add(pn, node);
|
||||
else
|
||||
_tiling_window_tree_parent_add(pn, node, NULL, EINA_TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
//unref changed the position of pn in the tree, result of unref
|
||||
//will be the new parent
|
||||
//we need to search the e_client ptr to get the corret relative pos
|
||||
wts = pn->parent;
|
||||
while(wts->client != pn->client)
|
||||
wts = _inlist_next(wts);
|
||||
_tiling_window_tree_parent_add(pl, node, wts, EINA_TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef CNODE
|
||||
#undef IF_MATCH_SET_LR
|
||||
#undef IF_MATCH_SET_TB
|
||||
|
||||
void
|
||||
tiling_window_tree_node_move(Window_Tree *node, int cross_edge)
|
||||
tiling_window_tree_node_change_pos(Window_Tree *node, int key)
|
||||
{
|
||||
Window_Tree *root = node;
|
||||
if (!node->parent)
|
||||
return;
|
||||
|
||||
/* FIXME: This is very slow and possibly buggy. Can be done much better, but
|
||||
* is very easy to implement. */
|
||||
Tiling_Split_Type parent_split_type =
|
||||
_tiling_window_tree_split_type_get(node->parent);
|
||||
|
||||
while (root->parent)
|
||||
Window_Tree *root = node->parent;
|
||||
while(root->parent)
|
||||
root = root->parent;
|
||||
|
||||
_node_move_ctx.node = node;
|
||||
_node_move_ctx.cross_edge = cross_edge;
|
||||
_node_move_ctx.ret = NULL;
|
||||
_node_move_ctx.best_match = 0;
|
||||
|
||||
tiling_window_tree_walk(root, _tiling_window_tree_node_move_walker);
|
||||
|
||||
if (_node_move_ctx.ret)
|
||||
switch(key)
|
||||
{
|
||||
E_Client *ec = node->client;
|
||||
|
||||
node->client = _node_move_ctx.ret->client;
|
||||
_node_move_ctx.ret->client = ec;
|
||||
case TILING_WINDOW_TREE_EDGE_LEFT:
|
||||
if (parent_split_type == TILING_SPLIT_HORIZONTAL)
|
||||
_tiling_window_tree_node_join(root, node, EINA_FALSE);
|
||||
else if(parent_split_type == TILING_SPLIT_VERTICAL)
|
||||
_tiling_window_tree_node_break_out(root, node, EINA_FALSE);
|
||||
break;
|
||||
case TILING_WINDOW_TREE_EDGE_RIGHT:
|
||||
if (parent_split_type == TILING_SPLIT_HORIZONTAL)
|
||||
_tiling_window_tree_node_join(root, node, EINA_TRUE);
|
||||
else if(parent_split_type == TILING_SPLIT_VERTICAL)
|
||||
_tiling_window_tree_node_break_out(root, node, EINA_TRUE);
|
||||
break;
|
||||
case TILING_WINDOW_TREE_EDGE_TOP:
|
||||
if (parent_split_type == TILING_SPLIT_HORIZONTAL)
|
||||
_tiling_window_tree_node_break_out(root, node, EINA_FALSE);
|
||||
else if(parent_split_type == TILING_SPLIT_VERTICAL)
|
||||
_tiling_window_tree_node_join(root, node, EINA_FALSE);
|
||||
break;
|
||||
case TILING_WINDOW_TREE_EDGE_BOTTOM:
|
||||
if (parent_split_type == TILING_SPLIT_HORIZONTAL)
|
||||
_tiling_window_tree_node_break_out(root, node, EINA_TRUE);
|
||||
else if(parent_split_type == TILING_SPLIT_VERTICAL)
|
||||
_tiling_window_tree_node_join(root, node, EINA_TRUE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -48,6 +48,5 @@ void tiling_window_tree_apply(Window_Tree *root, Evas_Coord x, Evas_Coor
|
|||
Eina_Bool tiling_window_tree_node_resize(Window_Tree *node, int w_dir,
|
||||
double w_diff, int h_dir, double h_diff);
|
||||
|
||||
void tiling_window_tree_node_move(Window_Tree *node, int cross_edge);
|
||||
|
||||
void tiling_window_tree_node_change_pos(Window_Tree *node, int key);
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue