diff --git a/legacy/ecore/src/lib/ecore_x/Ecore_X.h b/legacy/ecore/src/lib/ecore_x/Ecore_X.h index 9a06c075ed..c0d2d3810f 100644 --- a/legacy/ecore/src/lib/ecore_x/Ecore_X.h +++ b/legacy/ecore/src/lib/ecore_x/Ecore_X.h @@ -1090,6 +1090,7 @@ EAPI void ecore_x_window_cursor_show(Ecore_X_Window win, int show); EAPI void ecore_x_window_defaults_set(Ecore_X_Window win); EAPI int ecore_x_window_visible_get(Ecore_X_Window win); EAPI Ecore_X_Window ecore_x_window_shadow_tree_at_xy_with_skip_get(Ecore_X_Window base, int x, int y, Ecore_X_Window *skip, int skip_num); +EAPI Ecore_X_Window ecore_x_window_shadow_parent_get(Ecore_X_Window root, Ecore_X_Window win); EAPI void ecore_x_window_shadow_tree_flush(void); EAPI Ecore_X_Window ecore_x_window_root_get(Ecore_X_Window win); EAPI Ecore_X_Window ecore_x_window_at_xy_get(int x, int y); diff --git a/legacy/ecore/src/lib/ecore_x/ecore_x_dnd.c b/legacy/ecore/src/lib/ecore_x/ecore_x_dnd.c index 8645863064..6b2f75a424 100644 --- a/legacy/ecore/src/lib/ecore_x/ecore_x_dnd.c +++ b/legacy/ecore/src/lib/ecore_x/ecore_x_dnd.c @@ -43,6 +43,14 @@ static Ecore_X_DND_Source *_source = NULL; static Ecore_X_DND_Target *_target = NULL; static int _ecore_x_dnd_init_count = 0; +typedef struct _Version_Cache_Item +{ + Ecore_X_Window win; + int ver; +} Version_Cache_Item; +static Version_Cache_Item *_version_cache = NULL; +static int _version_cache_num = 0, _version_cache_alloc = 0; + void _ecore_x_dnd_init(void) { @@ -163,15 +171,50 @@ ecore_x_dnd_version_get(Ecore_X_Window win) unsigned char *prop_data; int num; + // this looks hacky - and it is, but we need a way of caching info about + // a window while dragging, because we literally query this every mouse + // move and going to and from x multiple times per move is EXPENSIVE + // and slows things down, puts lots of load on x etc. + if (_source->state == ECORE_X_DND_SOURCE_DRAGGING) + { + if (_version_cache) + { + int i; + + for (i = 0; i < _version_cache_num; i++) + { + if (_version_cache[i].win == win) + return _version_cache[i].ver; + } + } + } + if (ecore_x_window_prop_property_get(win, ECORE_X_ATOM_XDND_AWARE, XA_ATOM, 32, &prop_data, &num)) { int version = (int) *prop_data; free(prop_data); + if (_source->state == ECORE_X_DND_SOURCE_DRAGGING) + { + _version_cache_num++; + if (_version_cache_num > _version_cache_alloc) + _version_cache_alloc += 16; + _version_cache = realloc(_version_cache, _version_cache_alloc * sizeof(Version_Cache_Item)); + _version_cache[_version_cache_num - 1].win = win; + _version_cache[_version_cache_num - 1].ver = version; + } return version; } - else - return 0; + if (_source->state == ECORE_X_DND_SOURCE_DRAGGING) + { + _version_cache_num++; + if (_version_cache_num > _version_cache_alloc) + _version_cache_alloc += 16; + _version_cache = realloc(_version_cache, _version_cache_alloc * sizeof(Version_Cache_Item)); + _version_cache[_version_cache_num - 1].win = win; + _version_cache[_version_cache_num - 1].ver = 0; + } + return 0; } EAPI int @@ -331,6 +374,15 @@ ecore_x_dnd_begin(Ecore_X_Window source, unsigned char *data, int size) if (!ecore_x_selection_xdnd_set(source, data, size)) return 0; + if (_version_cache) + { + free(_version_cache); + _version_cache = NULL; + _version_cache_num = 0; + _version_cache_alloc = 0; + } + ecore_x_window_shadow_tree_flush(); + _source->win = source; ecore_x_window_ignore_set(_source->win, 1); _source->state = ECORE_X_DND_SOURCE_DRAGGING; @@ -462,7 +514,7 @@ ecore_x_dnd_send_finished(void) } void -_ecore_x_dnd_drag(int x, int y) +_ecore_x_dnd_drag(Ecore_X_Window root, int x, int y) { XEvent xev; Ecore_X_Window win; @@ -480,9 +532,17 @@ _ecore_x_dnd_drag(int x, int y) /* Attempt to find a DND-capable window under the cursor */ skip = ecore_x_window_ignore_list(&num); - win = ecore_x_window_at_xy_with_skip_get(x, y, skip, num); +// WARNING - this function is HEAVY. it goes to and from x a LOT walking the +// window tree - use the SHADOW version - makes a 1-off tree copy, then uses +// that instead. +// win = ecore_x_window_at_xy_with_skip_get(x, y, skip, num); + win = ecore_x_window_shadow_tree_at_xy_with_skip_get(root, x, y, skip, num); + +// NOTE: This now uses the shadow version to find parent windows +// while ((win) && !(ecore_x_dnd_version_get(win))) +// win = ecore_x_window_parent_get(win); while ((win) && !(ecore_x_dnd_version_get(win))) - win = ecore_x_window_parent_get(win); + win = ecore_x_window_shadow_parent_get(root, win); /* Send XdndLeave to current destination window if we have left it */ if ((_source->dest) && (win != _source->dest)) diff --git a/legacy/ecore/src/lib/ecore_x/ecore_x_events.c b/legacy/ecore/src/lib/ecore_x/ecore_x_events.c index 2eeae34faf..0593095cff 100644 --- a/legacy/ecore/src/lib/ecore_x/ecore_x_events.c +++ b/legacy/ecore/src/lib/ecore_x/ecore_x_events.c @@ -568,7 +568,7 @@ _ecore_x_event_handle_motion_notify(XEvent *xevent) _ecore_x_event_last_root_y = e->root.y; /* Xdnd handling */ - _ecore_x_dnd_drag(e->root.x, e->root.y); + _ecore_x_dnd_drag(xevent->xmotion.root, e->root.x, e->root.y); ecore_event_add(ECORE_X_EVENT_MOUSE_MOVE, e, NULL, NULL); } diff --git a/legacy/ecore/src/lib/ecore_x/ecore_x_private.h b/legacy/ecore/src/lib/ecore_x/ecore_x_private.h index 6d27b41358..c16e0726fb 100644 --- a/legacy/ecore/src/lib/ecore_x/ecore_x_private.h +++ b/legacy/ecore/src/lib/ecore_x/ecore_x_private.h @@ -217,7 +217,7 @@ void _ecore_x_key_grab_remove(Ecore_X_Window win); void _ecore_x_dnd_init(void); Ecore_X_DND_Source *_ecore_x_dnd_source_get(void); Ecore_X_DND_Target *_ecore_x_dnd_target_get(void); -void _ecore_x_dnd_drag(int x, int y); +void _ecore_x_dnd_drag(Ecore_X_Window root, int x, int y); void _ecore_x_dnd_shutdown(void); /* from netwm */ diff --git a/legacy/ecore/src/lib/ecore_x/ecore_x_window.c b/legacy/ecore/src/lib/ecore_x/ecore_x_window.c index 1855435059..1fc232d781 100644 --- a/legacy/ecore/src/lib/ecore_x/ecore_x_window.c +++ b/legacy/ecore/src/lib/ecore_x/ecore_x_window.c @@ -713,6 +713,7 @@ ecore_x_window_visible_get(Ecore_X_Window win) typedef struct _Shadow Shadow; struct _Shadow { + Shadow *parent; Shadow **children; Window win; int children_num; @@ -753,7 +754,10 @@ _ecore_x_window_tree_walk(Window win) { s->children_num = num; for (i = 0; i < num; i++) - s->children[i] = _ecore_x_window_tree_walk(list[i]); + { + s->children[i] = _ecore_x_window_tree_walk(list[i]); + if (s->children[i]) s->children[i]->parent = s; + } /* compress list down */ j = 0; for (i = 0; i < num; i++) @@ -935,8 +939,11 @@ _ecore_x_window_shadow_tree_at_xy_get(Window base, int bx, int by, int x, int y, { Shadow *s; - if (!shadow_base) _ecore_x_window_tree_shadow_populate(); - if (!shadow_base) return 0; + if (!shadow_base) + { + _ecore_x_window_tree_shadow_populate(); + if (!shadow_base) return 0; + } s = _ecore_x_window_shadow_tree_find(base); if (!s) return 0; return _ecore_x_window_shadow_tree_at_xy_get_shadow(s, bx, by, x, y, skip, skip_num); @@ -960,6 +967,38 @@ ecore_x_window_shadow_tree_at_xy_with_skip_get(Ecore_X_Window base, int x, int y return _ecore_x_window_shadow_tree_at_xy_get(base, 0, 0, x, y, skip, skip_num); } +/** + * Retrieves the parent window a given window has. This uses the shadow window + * tree. + * @param root The root window of @p win - if 0, this will be automatically determined with extra processing overhead + * @param win The window to get the parent window of + * @return The parent window of @p win + * @ingroup Ecore_X_Window_Geometry_Group + */ +EAPI Ecore_X_Window +ecore_x_window_shadow_parent_get(Ecore_X_Window root, Ecore_X_Window win) +{ + Shadow *s; + int i; + + if (!shadow_base) + { + _ecore_x_window_tree_shadow_populate(); + if (!shadow_base) return 0; + } + for (i = 0; i < shadow_num; i++) + { + if (!shadow_base[i]) continue; + s = _ecore_x_window_shadow_tree_find_shadow(shadow_base[i], win); + if (s) + { + if (!s->parent) return 0; + return s->parent->win; + } + } + return 0; +} + /** * Flushes the window shadow tree so nothing is stored. * @ingroup Ecore_X_Window_Geometry_Group diff --git a/legacy/ecore/src/lib/ecore_x/ecore_xcb_dnd.c b/legacy/ecore/src/lib/ecore_x/ecore_xcb_dnd.c index c0324b8eff..ae2ca7a3b4 100644 --- a/legacy/ecore/src/lib/ecore_x/ecore_xcb_dnd.c +++ b/legacy/ecore/src/lib/ecore_x/ecore_xcb_dnd.c @@ -611,7 +611,8 @@ ecore_x_dnd_send_finished(void) } void -_ecore_x_dnd_drag(int x, +_ecore_x_dnd_drag(Ecore_X_Window root, + int x, int y) { xcb_client_message_event_t ev; @@ -627,7 +628,8 @@ _ecore_x_dnd_drag(int x, /* Attempt to find a DND-capable window under the cursor */ skip = ecore_x_window_ignore_list(&num); - win = ecore_x_window_at_xy_with_skip_get(x, y, skip, num); +// win = ecore_x_window_at_xy_with_skip_get(x, y, skip, num); + win = ecore_x_window_shadow_tree_at_xy_with_skip_get(root, x, y, skip, num); while (win) { xcb_query_tree_cookie_t cookie_tree;