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;
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
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;
break;
XFree (tmp_children);
+#endif
if (wm_window == rootw || had_errors)
break;
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.
| 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. */
/* Child of win. */
&child);
+#endif
win_x += real_x;
win_y += real_y;
}
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. */
/* 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,
}
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 ();
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;
}