diff options
| author | Ken Raeburn | 2015-11-07 03:06:32 -0500 |
|---|---|---|
| committer | Ken Raeburn | 2015-11-12 03:58:10 -0500 |
| commit | aa17de9056ccce4f080b910bf5eede3df4a12d5c (patch) | |
| tree | 3b5b0dc2064ff0831b081c9c92e13159190fddc9 | |
| parent | a838c8331cf3f360d919a75cc8d92c72e6d900f0 (diff) | |
| download | emacs-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.c | 217 |
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 | } |