aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKen Raeburn2015-11-07 03:06:32 -0500
committerKen Raeburn2015-11-12 03:58:10 -0500
commitaa17de9056ccce4f080b910bf5eede3df4a12d5c (patch)
tree3b5b0dc2064ff0831b081c9c92e13159190fddc9
parenta838c8331cf3f360d919a75cc8d92c72e6d900f0 (diff)
downloademacs-aa17de9056ccce4f080b910bf5eede3df4a12d5c.tar.gz
emacs-aa17de9056ccce4f080b910bf5eede3df4a12d5c.zip
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.
-rw-r--r--src/xfns.c217
1 files changed, 200 insertions, 17 deletions
diff --git a/src/xfns.c b/src/xfns.c
index c55e6fee168..9071b89acd9 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -181,24 +181,38 @@ x_real_pos_and_offsets (struct frame *f,
181 int *yptr, 181 int *yptr,
182 int *outer_border) 182 int *outer_border)
183{ 183{
184 int win_x, win_y, outer_x IF_LINT (= 0), outer_y IF_LINT (= 0); 184 int win_x = 0, win_y = 0, outer_x = 0, outer_y = 0;
185 int real_x = 0, real_y = 0; 185 int real_x = 0, real_y = 0;
186 bool had_errors = false; 186 bool had_errors = false;
187 Window win = f->output_data.x->parent_desc; 187 Window win = f->output_data.x->parent_desc;
188 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
189 long max_len = 400;
190 Atom target_type = XA_CARDINAL;
191 unsigned int ow = 0, oh = 0;
192 unsigned int fw = 0, fh = 0;
193 unsigned int bw = 0;
194 /* We resort to XCB if possible because there are several X calls
195 here which require responses from the server but do not have data
196 dependencies between them. Using XCB lets us pipeline requests,
197 whereas with Xlib we must wait for each answer before sending the
198 next request.
199
200 For a non-local display, the round-trip time could be a few tens
201 of milliseconds, depending on the network distance. It doesn't
202 take a lot of those to add up to a noticeable hesitation in
203 responding to user actions. */
204#ifdef USE_XCB
205 xcb_connection_t *xcb_conn = dpyinfo->xcb_connection;
206 xcb_get_property_cookie_t prop_cookie;
207 xcb_get_geometry_cookie_t outer_geom_cookie;
208 bool sent_requests = false;
209#else
188 Atom actual_type; 210 Atom actual_type;
189 unsigned long actual_size, bytes_remaining; 211 unsigned long actual_size, bytes_remaining;
190 int rc, actual_format; 212 int rc, actual_format;
191 struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
192 long max_len = 400;
193 Display *dpy = FRAME_X_DISPLAY (f); 213 Display *dpy = FRAME_X_DISPLAY (f);
194 unsigned char *tmp_data = NULL; 214 unsigned char *tmp_data = NULL;
195 Atom target_type = XA_CARDINAL; 215#endif
196 unsigned int ow IF_LINT (= 0), oh IF_LINT (= 0);
197 unsigned int fw, fh;
198
199 block_input ();
200
201 x_catch_errors (dpy);
202 216
203 if (x_pixels_diff) *x_pixels_diff = 0; 217 if (x_pixels_diff) *x_pixels_diff = 0;
204 if (y_pixels_diff) *y_pixels_diff = 0; 218 if (y_pixels_diff) *y_pixels_diff = 0;
@@ -213,6 +227,13 @@ x_real_pos_and_offsets (struct frame *f,
213 if (win == dpyinfo->root_window) 227 if (win == dpyinfo->root_window)
214 win = FRAME_OUTER_WINDOW (f); 228 win = FRAME_OUTER_WINDOW (f);
215 229
230 block_input ();
231
232#ifndef USE_XCB
233 /* If we're using XCB, all errors are checked for on each call. */
234 x_catch_errors (dpy);
235#endif
236
216 /* This loop traverses up the containment tree until we hit the root 237 /* This loop traverses up the containment tree until we hit the root
217 window. Window managers may intersect many windows between our window 238 window. Window managers may intersect many windows between our window
218 and the root window. The window we find just before the root window 239 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,
220 for (;;) 241 for (;;)
221 { 242 {
222 Window wm_window, rootw; 243 Window wm_window, rootw;
244
245#ifdef USE_XCB
246 xcb_query_tree_cookie_t query_tree_cookie;
247 xcb_query_tree_reply_t *query_tree;
248
249 query_tree_cookie = xcb_query_tree (xcb_conn, win);
250 query_tree = xcb_query_tree_reply (xcb_conn, query_tree_cookie, NULL);
251 if (query_tree == NULL)
252 had_errors = true;
253 else
254 {
255 wm_window = query_tree->parent;
256 rootw = query_tree->root;
257 free (query_tree);
258 }
259#else
223 Window *tmp_children; 260 Window *tmp_children;
224 unsigned int tmp_nchildren; 261 unsigned int tmp_nchildren;
225 int success; 262 int success;
@@ -234,6 +271,7 @@ x_real_pos_and_offsets (struct frame *f,
234 break; 271 break;
235 272
236 XFree (tmp_children); 273 XFree (tmp_children);
274#endif
237 275
238 if (wm_window == rootw || had_errors) 276 if (wm_window == rootw || had_errors)
239 break; 277 break;
@@ -243,15 +281,74 @@ x_real_pos_and_offsets (struct frame *f,
243 281
244 if (! had_errors) 282 if (! had_errors)
245 { 283 {
246 unsigned int bw, ign; 284#ifdef USE_XCB
285 xcb_get_geometry_cookie_t geom_cookie;
286 xcb_translate_coordinates_cookie_t trans_cookie;
287 xcb_translate_coordinates_cookie_t outer_trans_cookie;
288
289 xcb_translate_coordinates_reply_t *trans;
290 xcb_get_geometry_reply_t *geom;
291#else
247 Window child, rootw; 292 Window child, rootw;
293 unsigned int ign;
294#endif
295
296#ifdef USE_XCB
297 /* Fire off the requests that don't have data dependencies.
298
299 Once we've done this, we must collect the results for each
300 one before returning, even if other errors are detected,
301 making the other responses moot. */
302 geom_cookie = xcb_get_geometry (xcb_conn, win);
303
304 trans_cookie =
305 xcb_translate_coordinates (xcb_conn,
306 /* From-window, to-window. */
307 FRAME_DISPLAY_INFO (f)->root_window,
308 FRAME_X_WINDOW (f),
309
310 /* From-position. */
311 0, 0);
312 if (FRAME_X_WINDOW (f) != FRAME_OUTER_WINDOW (f))
313 outer_trans_cookie =
314 xcb_translate_coordinates (xcb_conn,
315 /* From-window, to-window. */
316 FRAME_DISPLAY_INFO (f)->root_window,
317 FRAME_OUTER_WINDOW (f),
318
319 /* From-position. */
320 0, 0);
321 if (right_offset_x || bottom_offset_y)
322 outer_geom_cookie = xcb_get_geometry (xcb_conn,
323 FRAME_OUTER_WINDOW (f));
324
325 if (dpyinfo->root_window == f->output_data.x->parent_desc)
326 /* Try _NET_FRAME_EXTENTS if our parent is the root window. */
327 prop_cookie = xcb_get_property (xcb_conn, 0, win,
328 dpyinfo->Xatom_net_frame_extents,
329 target_type, 0, max_len);
330
331 sent_requests = true;
332#endif
248 333
249 /* Get the real coordinates for the WM window upper left corner */ 334 /* Get the real coordinates for the WM window upper left corner */
335#ifdef USE_XCB
336 geom = xcb_get_geometry_reply (xcb_conn, geom_cookie, NULL);
337 if (geom)
338 {
339 real_x = geom->x;
340 real_y = geom->y;
341 ow = geom->width;
342 oh = geom->height;
343 bw = geom->border_width;
344 free (geom);
345 }
346 else
347 had_errors = true;
348#else
250 XGetGeometry (dpy, win, 349 XGetGeometry (dpy, win,
251 &rootw, &real_x, &real_y, &ow, &oh, &bw, &ign); 350 &rootw, &real_x, &real_y, &ow, &oh, &bw, &ign);
252 351#endif
253 if (outer_border)
254 *outer_border = bw;
255 352
256 /* Translate real coordinates to coordinates relative to our 353 /* Translate real coordinates to coordinates relative to our
257 window. For our window, the upper left corner is 0, 0. 354 window. For our window, the upper left corner is 0, 0.
@@ -262,7 +359,23 @@ x_real_pos_and_offsets (struct frame *f,
262 | title | 359 | title |
263 | ----------------- v y 360 | ----------------- v y
264 | | our window 361 | | our window
265 */ 362
363 Since we don't care about the child window corresponding to
364 the actual coordinates, we can send zero to get the offsets
365 and compute the resulting coordinates below. This reduces
366 the data dependencies between calls and lets us pipeline the
367 requests better in the XCB case. */
368#ifdef USE_XCB
369 trans = xcb_translate_coordinates_reply (xcb_conn, trans_cookie, NULL);
370 if (trans)
371 {
372 win_x = trans->dst_x;
373 win_y = trans->dst_y;
374 free (trans);
375 }
376 else
377 had_errors = true;
378#else
266 XTranslateCoordinates (dpy, 379 XTranslateCoordinates (dpy,
267 380
268 /* From-window, to-window. */ 381 /* From-window, to-window. */
@@ -274,6 +387,7 @@ x_real_pos_and_offsets (struct frame *f,
274 387
275 /* Child of win. */ 388 /* Child of win. */
276 &child); 389 &child);
390#endif
277 391
278 win_x += real_x; 392 win_x += real_x;
279 win_y += real_y; 393 win_y += real_y;
@@ -285,6 +399,21 @@ x_real_pos_and_offsets (struct frame *f,
285 } 399 }
286 else 400 else
287 { 401 {
402#ifdef USE_XCB
403 xcb_translate_coordinates_reply_t *outer_trans;
404
405 outer_trans = xcb_translate_coordinates_reply (xcb_conn,
406 outer_trans_cookie,
407 NULL);
408 if (outer_trans)
409 {
410 outer_x = outer_trans->dst_x;
411 outer_y = outer_trans->dst_y;
412 free (outer_trans);
413 }
414 else
415 had_errors = true;
416#else
288 XTranslateCoordinates (dpy, 417 XTranslateCoordinates (dpy,
289 418
290 /* From-window, to-window. */ 419 /* From-window, to-window. */
@@ -296,17 +425,46 @@ x_real_pos_and_offsets (struct frame *f,
296 425
297 /* Child of win. */ 426 /* Child of win. */
298 &child); 427 &child);
428#endif
299 429
300 outer_x += real_x; 430 outer_x += real_x;
301 outer_y += real_y; 431 outer_y += real_y;
302 } 432 }
303 433
434#ifndef USE_XCB
304 had_errors = x_had_errors_p (dpy); 435 had_errors = x_had_errors_p (dpy);
436#endif
305 } 437 }
306 438
307 if (!had_errors && dpyinfo->root_window == f->output_data.x->parent_desc) 439 if (dpyinfo->root_window == f->output_data.x->parent_desc)
308 { 440 {
309 /* Try _NET_FRAME_EXTENTS if our parent is the root window. */ 441 /* Try _NET_FRAME_EXTENTS if our parent is the root window. */
442#ifdef USE_XCB
443 /* Make sure we didn't get an X error early and skip sending the
444 request. */
445 if (sent_requests)
446 {
447 xcb_get_property_reply_t *prop;
448
449 prop = xcb_get_property_reply (xcb_conn, prop_cookie, NULL);
450 if (prop)
451 {
452 if (prop->type == target_type
453 && xcb_get_property_value_length (prop) == 4
454 && prop->format == 32)
455 {
456 long *fe = xcb_get_property_value (prop);
457
458 outer_x = -fe[0];
459 outer_y = -fe[2];
460 real_x -= fe[0];
461 real_y -= fe[2];
462 }
463 free (prop);
464 }
465 /* Xlib version doesn't set had_errors here. Intentional or bug? */
466 }
467#else
310 rc = XGetWindowProperty (dpy, win, dpyinfo->Xatom_net_frame_extents, 468 rc = XGetWindowProperty (dpy, win, dpyinfo->Xatom_net_frame_extents,
311 0, max_len, False, target_type, 469 0, max_len, False, target_type,
312 &actual_type, &actual_format, &actual_size, 470 &actual_type, &actual_format, &actual_size,
@@ -324,19 +482,42 @@ x_real_pos_and_offsets (struct frame *f,
324 } 482 }
325 483
326 if (tmp_data) XFree (tmp_data); 484 if (tmp_data) XFree (tmp_data);
485#endif
327 } 486 }
328 487
329 if (right_offset_x || bottom_offset_y) 488 if (right_offset_x || bottom_offset_y)
330 { 489 {
490#ifdef USE_XCB
491 /* Make sure we didn't get an X error early and skip sending the
492 request. */
493 if (sent_requests)
494 {
495 xcb_get_geometry_reply_t *outer_geom;
496
497 outer_geom = xcb_get_geometry_reply (xcb_conn, outer_geom_cookie,
498 NULL);
499 if (outer_geom)
500 {
501 fw = outer_geom->width;
502 fh = outer_geom->height;
503 free (outer_geom);
504 }
505 else
506 had_errors = true;
507 }
508#else
331 int xy_ign; 509 int xy_ign;
332 unsigned int ign; 510 unsigned int ign;
333 Window rootw; 511 Window rootw;
334 512
335 XGetGeometry (dpy, FRAME_OUTER_WINDOW (f), 513 XGetGeometry (dpy, FRAME_OUTER_WINDOW (f),
336 &rootw, &xy_ign, &xy_ign, &fw, &fh, &ign, &ign); 514 &rootw, &xy_ign, &xy_ign, &fw, &fh, &ign, &ign);
515#endif
337 } 516 }
338 517
518#ifndef USE_XCB
339 x_uncatch_errors (); 519 x_uncatch_errors ();
520#endif
340 521
341 unblock_input (); 522 unblock_input ();
342 523
@@ -351,6 +532,8 @@ x_real_pos_and_offsets (struct frame *f,
351 if (xptr) *xptr = real_x; 532 if (xptr) *xptr = real_x;
352 if (yptr) *yptr = real_y; 533 if (yptr) *yptr = real_y;
353 534
535 if (outer_border) *outer_border = bw;
536
354 if (right_offset_x) *right_offset_x = ow - fw + outer_x; 537 if (right_offset_x) *right_offset_x = ow - fw + outer_x;
355 if (bottom_offset_y) *bottom_offset_y = oh - fh + outer_y; 538 if (bottom_offset_y) *bottom_offset_y = oh - fh + outer_y;
356} 539}