improve xdnd performance by thousdands of times. it was HORRID. note the

comments in the code.


SVN revision: 32694
This commit is contained in:
Carsten Haitzler 2007-11-15 04:48:36 +00:00
parent 0c97103851
commit c9c3ca7f1d
6 changed files with 114 additions and 12 deletions

View File

@ -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);

View File

@ -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))

View File

@ -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);
}

View File

@ -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 */

View File

@ -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

View File

@ -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;