From 35e729f9411581926e54cc25e18455cd0ec46803 Mon Sep 17 00:00:00 2001 From: Marcel Hollerbach Date: Thu, 9 Mar 2017 11:14:44 +0100 Subject: [PATCH] tiling: make windows placable by dragging them arround If someone starts to drag a client arround, then the client will shrink into a icon, that now is always at the position of the mouse cursor, if the drag ends, the client will be placed in the client currently below it. The client will be placed in a place where the mouse cursor was currently closer to. --- src/modules/tiling/e-module-tiling.edj | Bin 12690 -> 13752 bytes src/modules/tiling/e_mod_tiling.c | 279 +++++++++++++++++++++---- src/modules/tiling/window_tree.c | 46 +++- src/modules/tiling/window_tree.h | 3 + 4 files changed, 282 insertions(+), 46 deletions(-) diff --git a/src/modules/tiling/e-module-tiling.edj b/src/modules/tiling/e-module-tiling.edj index ae6f2553e57d26b3775450a33e24cf0efeb05c6a..cdeeddf1bd9b525b930ec73c4326faa7805b780b 100644 GIT binary patch delta 8649 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 CPKBEQ delta 7587 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 diff --git a/src/modules/tiling/e_mod_tiling.c b/src/modules/tiling/e_mod_tiling.c index 021651f6b..f09be8fd2 100644 --- a/src/modules/tiling/e_mod_tiling.c +++ b/src/modules/tiling/e_mod_tiling.c @@ -18,9 +18,18 @@ typedef struct geom_t int x, y, w, h; } geom_t; +typedef enum { + POSITION_TOP = 0, + POSITION_RIGHT = 1, + POSITION_BOTTOM = 2, + POSITION_LEFT = 3 +} Position_On_Client; + typedef struct Client_Extra { E_Client *client; + Evas_Object *drag_object; + Evas_Object *hint_object; geom_t expected; struct { @@ -79,8 +88,10 @@ static struct tiling_mod_main_g E_Config_DD *config_edd, *vdesk_edd; Ecore_Event_Handler *handler_client_resize, *handler_client_move, *handler_client_iconify, *handler_client_uniconify, - *handler_desk_set, *handler_compositor_resize; - E_Client_Hook *handler_client_resize_begin, *handler_client_add; + *handler_desk_set, *handler_compositor_resize, + *mouse_up; + E_Client_Hook *handler_client_resize_begin, *handler_client_add, + *handler_move_begin, *handler_move_end; E_Client_Menu_Hook *client_menu_hook; Tiling_Info *tinfo; @@ -584,6 +595,96 @@ _tilable_client(int x, int y) return NULL; } +static Position_On_Client +_calculate_position_preference(E_Client *ec) +{ + int x,y; + float bounded_x, bounded_y; + Eina_Rectangle rect; + evas_pointer_canvas_xy_get(e_comp->evas, &x, &y); + + evas_object_geometry_get(ec->frame, &rect.x, &rect.y, &rect.w, &rect.h); + + if (!eina_rectangle_coords_inside(&ec->client, x, y)) + { + ERR("Coorinates are not in there"); + return -1; + } + + //for the calculation we think of a X cross in the rectangle + bounded_x = ((float)x - rect.x)/((float)rect.w); + bounded_y = ((float)y - rect.y)/((float)rect.h); + + if (bounded_y < bounded_x) + { + //right upper part + if (bounded_y < (1.0 - bounded_x)) + { + //left upper + return POSITION_TOP; + } + else + { + //right lower + return POSITION_RIGHT; + } + } + else + { + //lower left part + if (bounded_y < (1.0 - bounded_x)) + { + //left upper + return POSITION_LEFT; + } + else + { + //right lower + return POSITION_BOTTOM; + } + } + + +} + +static void +_insert_client_prefered(E_Client *ec) +{ + Window_Tree *parent; + Tiling_Split_Type type = TILING_SPLIT_VERTICAL; + Window_Tree *item; + Eina_Bool before; + int x,y; + + evas_pointer_canvas_xy_get(e_comp->evas, &x, &y); + parent = _tilable_client(x,y); + + if (parent) + { + //calculate a good position where we would like to stay + Position_On_Client c; + + c = _calculate_position_preference(parent->client); + if (c == POSITION_TOP || c == POSITION_BOTTOM) + { + before = (c == POSITION_TOP); + type = TILING_SPLIT_VERTICAL; + } + else + { + before = (c == POSITION_LEFT); + type = TILING_SPLIT_HORIZONTAL; + } + + item = tiling_window_tree_client_find(_G.tinfo->tree, ec); + _G.tinfo->tree = tiling_window_tree_insert(_G.tinfo->tree, parent, ec, type, before); + } + else + { + _G.tinfo->tree = tiling_window_tree_add(_G.tinfo->tree, NULL, ec, _G.split_type); + } +} + static void _insert_client(E_Client *ec, Tiling_Split_Type type) { @@ -592,23 +693,17 @@ _insert_client(E_Client *ec, Tiling_Split_Type type) if (ec_focused == ec) { - //if we are placing the currently focused client, search for client under the focused client - Eina_Rectangle c; - - e_client_geometry_get(ec, &c.x, &c.y, &c.w, &c.h); - - place = _tilable_client(c.x + c.w/2, c.y + c.h/2); + _insert_client_prefered(ec); } else { //otherwise place next to the given client place = tiling_window_tree_client_find(_G.tinfo->tree, ec_focused); + _G.tinfo->tree = tiling_window_tree_add(_G.tinfo->tree, place, ec, type); } - _G.tinfo->tree = - tiling_window_tree_add(_G.tinfo->tree, place, ec, type); } static Eina_Bool @@ -1168,32 +1263,6 @@ _resize_hook(void *data EINA_UNUSED, int type EINA_UNUSED, return true; } -static Eina_Bool -_move_hook(void *data EINA_UNUSED, int type EINA_UNUSED, E_Event_Client *event) -{ - E_Client *ec = event->ec; - Client_Extra *extra = tiling_entry_func(ec); - - if (!extra || !extra->tiled) - { - return true; - } - - /* A hack because e doesn't trigger events for all property changes */ - if (!is_tilable(ec)) - { - toggle_floating(ec); - - return true; - } - - e_client_act_move_end(event->ec, NULL); - - _reapply_tree(); - - return true; -} - static void _frame_del_cb(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) @@ -1434,6 +1503,140 @@ E_API E_Module_Api e_modapi = { "Tiling" }; +static void +_center_on_mouse(Evas_Object *obj) +{ + Evas *e; + int x,y,w,h; + + e = evas_object_evas_get(obj); + evas_pointer_canvas_xy_get(e, &x, &y); + evas_object_geometry_get(obj, NULL, NULL, &w, &h); + evas_object_move(obj, x-w/2, y-h/2); +} + +static void +_client_drag_mouse_move(void *data, Evas *e EINA_UNUSED, void *event_info EINA_UNUSED) +{ + Window_Tree *client; + int x,y; + Client_Extra *extra = tiling_entry_func(data); + + //move the drag object to the center of the object + _center_on_mouse(extra->drag_object); + + //now check if we can hint somehow + evas_pointer_canvas_xy_get(e_comp->evas, &x, &y); + client = _tilable_client(x, y); + + //if there is nothing below, we cannot hint to anything + if (!client) return; + Position_On_Client c = _calculate_position_preference(client->client); + + if (!extra->hint_object) + { + extra->hint_object = edje_object_add(e_comp->evas); + if (!e_theme_edje_object_set(extra->hint_object, + "base/theme/modules/tiling", + "modules/tiling/indicator")) + edje_object_file_set(extra->hint_object, _G.edj_path, "modules/tiling/indicator"); + evas_object_layer_set(extra->hint_object, E_LAYER_CLIENT_DRAG); + evas_object_show(extra->hint_object); + } + + //set the geometry on the hint object + Eina_Rectangle pos = client->client->client; + if (c == POSITION_LEFT) + evas_object_geometry_set(extra->hint_object, pos.x, pos.y, pos.w/2, pos.h); + else if (c == POSITION_RIGHT) + evas_object_geometry_set(extra->hint_object, pos.x+pos.w/2, pos.y, pos.w/2, pos.h); + else if (c == POSITION_BOTTOM) + evas_object_geometry_set(extra->hint_object, pos.x, pos.y + pos.h/2, pos.w, pos.h/2); + else if (c == POSITION_TOP) + evas_object_geometry_set(extra->hint_object, pos.x, pos.y, pos.w, pos.h/2); +} + +static unsigned char +_client_drag_mouse_up(void *data, int event EINA_UNUSED, void *event_info EINA_UNUSED) +{ + E_Client *ec = data; + Client_Extra *extra = tiling_entry_func(ec); + + if (!extra) + { + return ECORE_CALLBACK_PASS_ON; + } + + //we grappend the comp when we started the drag + e_comp_ungrab_input(EINA_TRUE, EINA_FALSE); + + //insert the client at the position where the up was + _insert_client_prefered(ec); + + //remove the hint object + evas_object_del(extra->hint_object); + extra->hint_object = NULL; + + //delete the icon on the screen + evas_object_del(extra->drag_object); + evas_event_callback_del_full(evas_object_evas_get(e_comp->elm), EVAS_CALLBACK_MOUSE_MOVE, _client_drag_mouse_move, ec); + extra->drag_object = NULL; + + //bring up the client again + ec->hidden = EINA_FALSE; + e_client_comp_hidden_set(ec, EINA_FALSE); + evas_object_show(ec->frame); + + //remove the mouse up + ecore_event_handler_del(_G.mouse_up); + _G.mouse_up = NULL; + + _reapply_tree(); + + evas_object_focus_set(ec->frame, EINA_TRUE); + + return ECORE_CALLBACK_PASS_ON; +} + +static void +_client_move_begin(void *data EINA_UNUSED, E_Client *ec) +{ + Client_Extra *extra = tiling_entry_func(ec); + Window_Tree *item; + + if (!extra || !extra->tiled) + { + return; + } + + item = tiling_window_tree_client_find(_G.tinfo->tree, ec); + _G.tinfo->tree = tiling_window_tree_remove(_G.tinfo->tree, item); + + e_comp_grab_input(EINA_TRUE, EINA_FALSE); + + //create the drag object + extra->drag_object = e_client_icon_add(ec, evas_object_evas_get(e_comp->elm)); + evas_object_resize(extra->drag_object, 40, 40); + evas_object_show(extra->drag_object); + evas_object_layer_set(extra->drag_object, E_LAYER_CLIENT_DRAG); + + //listen for mouse moves + evas_event_callback_add(evas_object_evas_get(e_comp->elm), EVAS_CALLBACK_MOUSE_MOVE, _client_drag_mouse_move, ec); + + //the up will terminate the whole operation and destroy the drag and restore the client + //we cannot use the move_end hook since the move is ending when we are hiding the client + _G.mouse_up = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP, _client_drag_mouse_up, ec); + + //center the drag object on the mouse + _center_on_mouse(extra->drag_object); + + ec->hidden = EINA_TRUE; + e_client_comp_hidden_set(ec, EINA_TRUE); + evas_object_hide(ec->frame); + + _reapply_tree(); +} + E_API void * e_modapi_init(E_Module *m) { @@ -1461,6 +1664,9 @@ e_modapi_init(E_Module *m) _G.handler_client_resize_begin = e_client_hook_add(E_CLIENT_HOOK_RESIZE_BEGIN, _resize_begin_hook, NULL); + _G.handler_move_begin = + e_client_hook_add(E_CLIENT_HOOK_MOVE_BEGIN, _client_move_begin, NULL); + if (e_comp->comp_type == E_PIXMAP_TYPE_X) _G.handler_client_add = e_client_hook_add(E_CLIENT_HOOK_EVAL_PRE_FRAME_ASSIGN, _add_hook, NULL); @@ -1468,7 +1674,6 @@ e_modapi_init(E_Module *m) _G.handler_client_add = e_client_hook_add(E_CLIENT_HOOK_UNIGNORE, _add_hook, NULL); HANDLER(_G.handler_client_resize, CLIENT_RESIZE, _resize_hook); - HANDLER(_G.handler_client_move, CLIENT_MOVE, _move_hook); HANDLER(_G.handler_client_iconify, CLIENT_ICONIFY, _iconify_hook); HANDLER(_G.handler_client_uniconify, CLIENT_UNICONIFY, _iconify_hook); diff --git a/src/modules/tiling/window_tree.c b/src/modules/tiling/window_tree.c index 94b11d7a6..e99074333 100644 --- a/src/modules/tiling/window_tree.c +++ b/src/modules/tiling/window_tree.c @@ -3,6 +3,8 @@ #include "window_tree.h" #include "e_mod_tiling.h" +void tiling_window_tree_dump(Window_Tree *root, int level); + void tiling_window_tree_walk(Window_Tree *root, void (*func)(void *)) { @@ -26,7 +28,7 @@ tiling_window_tree_free(Window_Tree *root) } static void -_tiling_window_tree_split_add(Window_Tree *parent, Window_Tree *new_node) +_tiling_window_tree_split_add(Window_Tree *parent, Window_Tree *new_node, Eina_Bool append) { /* Make a new node for the parent client and split the weights in half. */ Window_Tree *new_parent_client = calloc(1, sizeof(*new_node)); @@ -38,10 +40,13 @@ _tiling_window_tree_split_add(Window_Tree *parent, Window_Tree *new_node) new_parent_client->weight = 0.5; new_node->weight = 0.5; - parent->children = - eina_inlist_append(parent->children, EINA_INLIST_GET(new_parent_client)); - parent->children = - eina_inlist_append(parent->children, EINA_INLIST_GET(new_node)); + parent->children = eina_inlist_append(parent->children, EINA_INLIST_GET(new_parent_client)); + + if (append) + parent->children = eina_inlist_append(parent->children, EINA_INLIST_GET(new_node)); + else + parent->children = eina_inlist_prepend(parent->children, EINA_INLIST_GET(new_node)); + } static void _tiling_window_tree_parent_add(Window_Tree *parent, Window_Tree *new_node, Window_Tree *rel, Eina_Bool append) @@ -88,6 +93,29 @@ _tiling_window_tree_split_type_get(Window_Tree *node) return ret % 2; } + +Window_Tree * +tiling_window_tree_insert(Window_Tree *root, Window_Tree *buddy, + E_Client *client, Tiling_Split_Type split_type, Eina_Bool before) +{ + Window_Tree *new_node = calloc(1, sizeof(*new_node)); + Window_Tree *parent = buddy->parent; + Tiling_Split_Type parent_split_type = _tiling_window_tree_split_type_get(parent); + + new_node->client = client; + + if (parent_split_type == split_type) + { + _tiling_window_tree_parent_add(parent, new_node, buddy, !before); + } + else + { + _tiling_window_tree_split_add(buddy, new_node, !before); + } + + return root; +} + Window_Tree * tiling_window_tree_add(Window_Tree *root, Window_Tree *parent, E_Client *client, Tiling_Split_Type split_type) @@ -128,7 +156,7 @@ tiling_window_tree_add(Window_Tree *root, Window_Tree *parent, } else { - _tiling_window_tree_split_add(parent, new_node); + _tiling_window_tree_split_add(parent, new_node, EINA_TRUE); } } else @@ -142,7 +170,7 @@ tiling_window_tree_add(Window_Tree *root, Window_Tree *parent, else { root = calloc(1, sizeof(*root)); - _tiling_window_tree_split_add(parent, new_node); + _tiling_window_tree_split_add(parent, new_node, EINA_TRUE); root->weight = 1.0; root->children = eina_inlist_append(root->children, EINA_INLIST_GET(parent)); @@ -640,7 +668,7 @@ _tiling_window_tree_node_join(Window_Tree *root, Window_Tree *node, Eina_Bool di //unref has not changed the tree if (!pn->children) { - _tiling_window_tree_split_add(pn, node); + _tiling_window_tree_split_add(pn, node, EINA_TRUE); } else { @@ -728,4 +756,4 @@ tiling_window_tree_dump(Window_Tree *root, int level) { tiling_window_tree_dump(itr, level + 1); } -} \ No newline at end of file +} diff --git a/src/modules/tiling/window_tree.h b/src/modules/tiling/window_tree.h index 8e59792c9..95198db03 100644 --- a/src/modules/tiling/window_tree.h +++ b/src/modules/tiling/window_tree.h @@ -37,6 +37,9 @@ void tiling_window_tree_walk(Window_Tree *root, void (*func)(void *)); Window_Tree *tiling_window_tree_add(Window_Tree *root, Window_Tree *parent, E_Client *client, Tiling_Split_Type split_type); +Window_Tree *tiling_window_tree_insert(Window_Tree *root, Window_Tree *buddy, + E_Client *client, Tiling_Split_Type split_type, Eina_Bool before); + Window_Tree *tiling_window_tree_remove(Window_Tree *root, Window_Tree *item); Window_Tree *tiling_window_tree_client_find(Window_Tree *root,