Commit aa17de90 authored by Ken Raeburn's avatar Ken Raeburn

Speed up x_real_pos_and_offsets using XCB

* src/xfns.c (x_real_pos_and_offsets) [USE_XCB]: Add XCB flavors of
all X calls, and pipeline requests when possible, collecting results
later.  Eliminate use of x_catch_errors (and thus XSync) in XCB case.
parent a838c833
......@@ -181,24 +181,38 @@ x_real_pos_and_offsets (struct frame *f,
int *yptr,
int *outer_border)
{
int win_x, win_y, outer_x IF_LINT (= 0), outer_y IF_LINT (= 0);
int win_x = 0, win_y = 0, outer_x = 0, outer_y = 0;
int real_x = 0, real_y = 0;
bool had_errors = false;
Window win = f->output_data.x->parent_desc;
struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
long max_len = 400;
Atom target_type = XA_CARDINAL;
unsigned int ow = 0, oh = 0;
unsigned int fw = 0, fh = 0;
unsigned int bw = 0;
/* We resort to XCB if possible because there are several X calls
here which require responses from the server but do not have data
dependencies between them. Using XCB lets us pipeline requests,
whereas with Xlib we must wait for each answer before sending the
next request.
For a non-local display, the round-trip time could be a few tens
of milliseconds, depending on the network distance. It doesn't
take a lot of those to add up to a noticeable hesitation in
responding to user actions. */
#ifdef USE_XCB
xcb_connection_t *xcb_conn = dpyinfo->xcb_connection;
xcb_get_property_cookie_t prop_cookie;
xcb_get_geometry_cookie_t outer_geom_cookie;
bool sent_requests = false;
#else
Atom actual_type;
unsigned long actual_size, bytes_remaining;
int rc, actual_format;
struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
long max_len = 400;
Display *dpy = FRAME_X_DISPLAY (f);
unsigned char *tmp_data = NULL;
Atom target_type = XA_CARDINAL;
unsigned int ow IF_LINT (= 0), oh IF_LINT (= 0);
unsigned int fw, fh;
block_input ();
x_catch_errors (dpy);
#endif
if (x_pixels_diff) *x_pixels_diff = 0;
if (y_pixels_diff) *y_pixels_diff = 0;
......@@ -213,6 +227,13 @@ x_real_pos_and_offsets (struct frame *f,
if (win == dpyinfo->root_window)
win = FRAME_OUTER_WINDOW (f);
block_input ();
#ifndef USE_XCB
/* If we're using XCB, all errors are checked for on each call. */
x_catch_errors (dpy);
#endif
/* This loop traverses up the containment tree until we hit the root
window. Window managers may intersect many windows between our window
and the root window. The window we find just before the root window
......@@ -220,6 +241,22 @@ x_real_pos_and_offsets (struct frame *f,
for (;;)
{
Window wm_window, rootw;
#ifdef USE_XCB
xcb_query_tree_cookie_t query_tree_cookie;
xcb_query_tree_reply_t *query_tree;
query_tree_cookie = xcb_query_tree (xcb_conn, win);
query_tree = xcb_query_tree_reply (xcb_conn, query_tree_cookie, NULL);
if (query_tree == NULL)
had_errors = true;
else
{
wm_window = query_tree->parent;
rootw = query_tree->root;
free (query_tree);
}
#else
Window *tmp_children;
unsigned int tmp_nchildren;
int success;
......@@ -234,6 +271,7 @@ x_real_pos_and_offsets (struct frame *f,
break;
XFree (tmp_children);
#endif
if (wm_window == rootw || had_errors)
break;
......@@ -243,15 +281,74 @@ x_real_pos_and_offsets (struct frame *f,
if (! had_errors)
{
unsigned int bw, ign;
#ifdef USE_XCB
xcb_get_geometry_cookie_t geom_cookie;
xcb_translate_coordinates_cookie_t trans_cookie;
xcb_translate_coordinates_cookie_t outer_trans_cookie;
xcb_translate_coordinates_reply_t *trans;
xcb_get_geometry_reply_t *geom;
#else
Window child, rootw;
unsigned int ign;
#endif
#ifdef USE_XCB
/* Fire off the requests that don't have data dependencies.
Once we've done this, we must collect the results for each
one before returning, even if other errors are detected,
making the other responses moot. */
geom_cookie = xcb_get_geometry (xcb_conn, win);
trans_cookie =
xcb_translate_coordinates (xcb_conn,
/* From-window, to-window. */
FRAME_DISPLAY_INFO (f)->root_window,
FRAME_X_WINDOW (f),
/* From-position. */
0, 0);
if (FRAME_X_WINDOW (f) != FRAME_OUTER_WINDOW (f))
outer_trans_cookie =
xcb_translate_coordinates (xcb_conn,
/* From-window, to-window. */
FRAME_DISPLAY_INFO (f)->root_window,
FRAME_OUTER_WINDOW (f),
/* From-position. */
0, 0);
if (right_offset_x || bottom_offset_y)
outer_geom_cookie = xcb_get_geometry (xcb_conn,
FRAME_OUTER_WINDOW (f));
if (dpyinfo->root_window == f->output_data.x->parent_desc)
/* Try _NET_FRAME_EXTENTS if our parent is the root window. */
prop_cookie = xcb_get_property (xcb_conn, 0, win,
dpyinfo->Xatom_net_frame_extents,
target_type, 0, max_len);
sent_requests = true;
#endif
/* Get the real coordinates for the WM window upper left corner */
#ifdef USE_XCB
geom = xcb_get_geometry_reply (xcb_conn, geom_cookie, NULL);
if (geom)
{
real_x = geom->x;
real_y = geom->y;
ow = geom->width;
oh = geom->height;
bw = geom->border_width;
free (geom);
}
else
had_errors = true;
#else
XGetGeometry (dpy, win,
&rootw, &real_x, &real_y, &ow, &oh, &bw, &ign);
if (outer_border)
*outer_border = bw;
&rootw, &real_x, &real_y, &ow, &oh, &bw, &ign);
#endif
/* Translate real coordinates to coordinates relative to our
window. For our window, the upper left corner is 0, 0.
......@@ -262,7 +359,23 @@ x_real_pos_and_offsets (struct frame *f,
| title |
| ----------------- v y
| | our window
*/
Since we don't care about the child window corresponding to
the actual coordinates, we can send zero to get the offsets
and compute the resulting coordinates below. This reduces
the data dependencies between calls and lets us pipeline the
requests better in the XCB case. */
#ifdef USE_XCB
trans = xcb_translate_coordinates_reply (xcb_conn, trans_cookie, NULL);
if (trans)
{
win_x = trans->dst_x;
win_y = trans->dst_y;
free (trans);
}
else
had_errors = true;
#else
XTranslateCoordinates (dpy,
/* From-window, to-window. */
......@@ -274,6 +387,7 @@ x_real_pos_and_offsets (struct frame *f,
/* Child of win. */
&child);
#endif
win_x += real_x;
win_y += real_y;
......@@ -285,6 +399,21 @@ x_real_pos_and_offsets (struct frame *f,
}
else
{
#ifdef USE_XCB
xcb_translate_coordinates_reply_t *outer_trans;
outer_trans = xcb_translate_coordinates_reply (xcb_conn,
outer_trans_cookie,
NULL);
if (outer_trans)
{
outer_x = outer_trans->dst_x;
outer_y = outer_trans->dst_y;
free (outer_trans);
}
else
had_errors = true;
#else
XTranslateCoordinates (dpy,
/* From-window, to-window. */
......@@ -296,17 +425,46 @@ x_real_pos_and_offsets (struct frame *f,
/* Child of win. */
&child);
#endif
outer_x += real_x;
outer_y += real_y;
}
#ifndef USE_XCB
had_errors = x_had_errors_p (dpy);
#endif
}
if (!had_errors && dpyinfo->root_window == f->output_data.x->parent_desc)
if (dpyinfo->root_window == f->output_data.x->parent_desc)
{
/* Try _NET_FRAME_EXTENTS if our parent is the root window. */
#ifdef USE_XCB
/* Make sure we didn't get an X error early and skip sending the
request. */
if (sent_requests)
{
xcb_get_property_reply_t *prop;
prop = xcb_get_property_reply (xcb_conn, prop_cookie, NULL);
if (prop)
{
if (prop->type == target_type
&& xcb_get_property_value_length (prop) == 4
&& prop->format == 32)
{
long *fe = xcb_get_property_value (prop);
outer_x = -fe[0];
outer_y = -fe[2];
real_x -= fe[0];
real_y -= fe[2];
}
free (prop);
}
/* Xlib version doesn't set had_errors here. Intentional or bug? */
}
#else
rc = XGetWindowProperty (dpy, win, dpyinfo->Xatom_net_frame_extents,
0, max_len, False, target_type,
&actual_type, &actual_format, &actual_size,
......@@ -324,19 +482,42 @@ x_real_pos_and_offsets (struct frame *f,
}
if (tmp_data) XFree (tmp_data);
#endif
}
if (right_offset_x || bottom_offset_y)
{
#ifdef USE_XCB
/* Make sure we didn't get an X error early and skip sending the
request. */
if (sent_requests)
{
xcb_get_geometry_reply_t *outer_geom;
outer_geom = xcb_get_geometry_reply (xcb_conn, outer_geom_cookie,
NULL);
if (outer_geom)
{
fw = outer_geom->width;
fh = outer_geom->height;
free (outer_geom);
}
else
had_errors = true;
}
#else
int xy_ign;
unsigned int ign;
Window rootw;
XGetGeometry (dpy, FRAME_OUTER_WINDOW (f),
&rootw, &xy_ign, &xy_ign, &fw, &fh, &ign, &ign);
#endif
}
#ifndef USE_XCB
x_uncatch_errors ();
#endif
unblock_input ();
......@@ -351,6 +532,8 @@ x_real_pos_and_offsets (struct frame *f,
if (xptr) *xptr = real_x;
if (yptr) *yptr = real_y;
if (outer_border) *outer_border = bw;
if (right_offset_x) *right_offset_x = ow - fw + outer_x;
if (bottom_offset_y) *bottom_offset_y = oh - fh + outer_y;
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment