1 /* 2 Copyright (C) 2002-2010 Karl J. Runge <runge (at) karlrunge.com> 3 All rights reserved. 4 5 This file is part of x11vnc. 6 7 x11vnc is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 2 of the License, or (at 10 your option) any later version. 11 12 x11vnc is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with x11vnc; if not, write to the Free Software 19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA 20 or see <http://www.gnu.org/licenses/>. 21 22 In addition, as a special exception, Karl J. Runge 23 gives permission to link the code of its release of x11vnc with the 24 OpenSSL project's "OpenSSL" library (or with modified versions of it 25 that use the same license as the "OpenSSL" library), and distribute 26 the linked executables. You must obey the GNU General Public License 27 in all respects for all of the code used other than "OpenSSL". If you 28 modify this file, you may extend this exception to your version of the 29 file, but you are not obligated to do so. If you do not wish to do 30 so, delete this exception statement from your version. 31 */ 32 33 /* -- xdamage.c -- */ 34 35 #include "x11vnc.h" 36 #include "xwrappers.h" 37 #include "userinput.h" 38 #include "unixpw.h" 39 40 #if LIBVNCSERVER_HAVE_LIBXDAMAGE 41 Damage xdamage = 0; 42 #endif 43 44 #ifndef XDAMAGE 45 #define XDAMAGE 1 46 #endif 47 int use_xdamage = XDAMAGE; /* use the xdamage rects for scanline hints */ 48 int xdamage_present = 0; 49 50 #ifdef MACOSX 51 int xdamage_max_area = 50000; 52 #else 53 int xdamage_max_area = 20000; /* pixels */ 54 #endif 55 56 double xdamage_memory = 1.0; /* in units of NSCAN */ 57 int xdamage_tile_count = 0, xdamage_direct_count = 0; 58 double xdamage_scheduled_mark = 0.0; 59 double xdamage_crazy_time = 0.0; 60 double xdamage_crazy_delay = 300.0; 61 sraRegionPtr xdamage_scheduled_mark_region = NULL; 62 sraRegionPtr *xdamage_regions = NULL; 63 int xdamage_ticker = 0; 64 int XD_skip = 0, XD_tot = 0, XD_des = 0; /* for stats */ 65 66 void add_region_xdamage(sraRegionPtr new_region); 67 void clear_xdamage_mark_region(sraRegionPtr markregion, int flush); 68 int collect_non_X_xdamage(int x_in, int y_in, int w_in, int h_in, int call); 69 int collect_xdamage(int scancnt, int call); 70 int xdamage_hint_skip(int y); 71 void initialize_xdamage(void); 72 void create_xdamage_if_needed(int force); 73 void destroy_xdamage_if_needed(void); 74 void check_xdamage_state(void); 75 76 static void record_desired_xdamage_rect(int x, int y, int w, int h); 77 78 79 static void record_desired_xdamage_rect(int x, int y, int w, int h) { 80 /* 81 * Unfortunately we currently can't trust an xdamage event 82 * to correspond to real screen damage. E.g. focus-in for 83 * mozilla (depending on wm) will mark the whole toplevel 84 * area as damaged, when only the border has changed. 85 * Similar things for terminal windows. 86 * 87 * This routine uses some heuristics to detect small enough 88 * damage regions that we will not have a performance problem 89 * if we believe them even though they are wrong. We record 90 * the corresponding tiles the damage regions touch. 91 */ 92 int dt_x, dt_y, nt_x1, nt_y1, nt_x2, nt_y2, nt; 93 int ix, iy, cnt = 0; 94 int area = w*h, always_accept = 0; 95 /* 96 * XXX: not working yet, slow and overlaps with scan_display() 97 * probably slow because tall skinny rectangles very inefficient 98 * in general and in direct_fb_copy() (100X slower then horizontal). 99 */ 100 int use_direct_fb_copy = 0; 101 int wh_min, wh_max; 102 static int first = 1, udfb = 0; 103 104 /* compiler warning: */ 105 nt_x1 = 0; nt_y1 = 0; nt_x2 = 0; nt_y2 = 0; 106 107 if (first) { 108 if (getenv("XD_DFC")) { 109 udfb = 1; 110 } 111 first = 0; 112 } 113 if (udfb) { 114 use_direct_fb_copy = 1; 115 } 116 117 if (xdamage_max_area <= 0) { 118 always_accept = 1; 119 } 120 121 if (!always_accept && area > xdamage_max_area) { 122 return; 123 } 124 125 dt_x = w / tile_x; 126 dt_y = h / tile_y; 127 128 if (w < h) { 129 wh_min = w; 130 wh_max = h; 131 } else { 132 wh_min = h; 133 wh_max = w; 134 } 135 136 if (!always_accept && dt_y >= 3 && area > 4000) { 137 /* 138 * if it is real it should be caught by a normal scanline 139 * poll, but we might as well keep if small (tall line?). 140 */ 141 return; 142 } 143 144 if (use_direct_fb_copy) { 145 X_UNLOCK; 146 direct_fb_copy(x, y, x + w, y + h, 1); 147 xdamage_direct_count++; 148 X_LOCK; 149 } else if (0 && wh_min < tile_x/4 && wh_max > 30 * wh_min) { 150 /* try it for long, skinny rects, XXX still no good */ 151 X_UNLOCK; 152 direct_fb_copy(x, y, x + w, y + h, 1); 153 xdamage_direct_count++; 154 X_LOCK; 155 } else { 156 157 if (ntiles_x == 0 || ntiles_y == 0) { 158 /* too early. */ 159 return; 160 } 161 nt_x1 = nfix( (x)/tile_x, ntiles_x); 162 nt_x2 = nfix((x+w)/tile_x, ntiles_x); 163 nt_y1 = nfix( (y)/tile_y, ntiles_y); 164 nt_y2 = nfix((y+h)/tile_y, ntiles_y); 165 166 /* 167 * loop over the rectangle of tiles (1 tile for a small 168 * input rect). 169 */ 170 for (ix = nt_x1; ix <= nt_x2; ix++) { 171 for (iy = nt_y1; iy <= nt_y2; iy++) { 172 nt = ix + iy * ntiles_x; 173 cnt++; 174 if (! tile_has_xdamage_diff[nt]) { 175 XD_des++; 176 tile_has_xdamage_diff[nt] = 1; 177 } 178 /* not used: */ 179 tile_row_has_xdamage_diff[iy] = 1; 180 xdamage_tile_count++; 181 } 182 } 183 } 184 if (debug_xdamage > 1) { 185 fprintf(stderr, "xdamage: desired: %dx%d+%d+%d\tA: %6d tiles=" 186 "%02d-%02d/%02d-%02d tilecnt: %d\n", w, h, x, y, 187 w * h, nt_x1, nt_x2, nt_y1, nt_y2, cnt); 188 } 189 } 190 191 void add_region_xdamage(sraRegionPtr new_region) { 192 sraRegionPtr reg; 193 int prev_tick, nreg; 194 195 if (! xdamage_regions) { 196 return; 197 } 198 199 nreg = (xdamage_memory * NSCAN) + 1; 200 prev_tick = xdamage_ticker - 1; 201 if (prev_tick < 0) { 202 prev_tick = nreg - 1; 203 } 204 205 reg = xdamage_regions[prev_tick]; 206 if (reg != NULL && new_region != NULL) { 207 if (debug_xdamage > 1) fprintf(stderr, "add_region_xdamage: prev_tick: %d reg %p new_region %p\n", prev_tick, (void *)reg, (void *)new_region); 208 sraRgnOr(reg, new_region); 209 } 210 } 211 212 void clear_xdamage_mark_region(sraRegionPtr markregion, int flush) { 213 #if LIBVNCSERVER_HAVE_LIBXDAMAGE 214 XEvent ev; 215 sraRegionPtr tmpregion; 216 int count = 0; 217 218 RAWFB_RET_VOID 219 220 if (! xdamage_present || ! use_xdamage) { 221 return; 222 } 223 if (! xdamage) { 224 return; 225 } 226 if (! xdamage_base_event_type) { 227 return; 228 } 229 if (unixpw_in_progress) return; 230 231 X_LOCK; 232 if (flush) { 233 XFlush_wr(dpy); 234 } 235 while (XCheckTypedEvent(dpy, xdamage_base_event_type+XDamageNotify, &ev)) { 236 count++; 237 } 238 /* clear the whole damage region */ 239 XDamageSubtract(dpy, xdamage, None, None); 240 X_UNLOCK; 241 242 if (debug_tiles || debug_xdamage) { 243 fprintf(stderr, "clear_xdamage_mark_region: %d\n", count); 244 } 245 246 if (! markregion) { 247 /* NULL means mark the whole display */ 248 tmpregion = sraRgnCreateRect(0, 0, dpy_x, dpy_y); 249 add_region_xdamage(tmpregion); 250 sraRgnDestroy(tmpregion); 251 } else { 252 add_region_xdamage(markregion); 253 } 254 #else 255 if (0) flush++; /* compiler warnings */ 256 if (0) markregion = NULL; 257 #endif 258 } 259 260 int collect_non_X_xdamage(int x_in, int y_in, int w_in, int h_in, int call) { 261 sraRegionPtr tmpregion; 262 sraRegionPtr reg; 263 static int rect_count = 0; 264 int nreg, ccount = 0, dcount = 0, ecount = 0; 265 static time_t last_rpt = 0; 266 time_t now; 267 double tm, dt; 268 int x, y, w, h, x2, y2; 269 270 if (call && debug_xdamage > 1) fprintf(stderr, "collect_non_X_xdamage: %d %d %d %d - %d / %d\n", x_in, y_in, w_in, h_in, call, use_xdamage); 271 272 if (! use_xdamage) { 273 return 0; 274 } 275 if (! xdamage_regions) { 276 return 0; 277 } 278 279 dtime0(&tm); 280 281 nreg = (xdamage_memory * NSCAN) + 1; 282 283 if (call == 0) { 284 xdamage_ticker = (xdamage_ticker+1) % nreg; 285 xdamage_direct_count = 0; 286 reg = xdamage_regions[xdamage_ticker]; 287 if (reg != NULL) { 288 sraRgnMakeEmpty(reg); 289 } 290 } else { 291 if (xdamage_ticker < 0) { 292 xdamage_ticker = 0; 293 } 294 reg = xdamage_regions[xdamage_ticker]; 295 } 296 if (reg == NULL) { 297 return 0; 298 } 299 300 if (x_in < 0) { 301 return 0; 302 } 303 304 305 x = x_in; 306 y = y_in; 307 w = w_in; 308 h = h_in; 309 310 /* translate if needed */ 311 if (clipshift) { 312 /* set coords relative to fb origin */ 313 if (0 && rootshift) { 314 /* 315 * Note: not needed because damage is 316 * relative to subwin, not rootwin. 317 */ 318 x = x - off_x; 319 y = y - off_y; 320 } 321 if (clipshift) { 322 x = x - coff_x; 323 y = y - coff_y; 324 } 325 326 x2 = x + w; /* upper point */ 327 x = nfix(x, dpy_x); /* place both in fb area */ 328 x2 = nfix(x2, dpy_x+1); 329 w = x2 - x; /* recompute w */ 330 331 y2 = y + h; 332 y = nfix(y, dpy_y); 333 y2 = nfix(y2, dpy_y+1); 334 h = y2 - y; 335 336 if (w <= 0 || h <= 0) { 337 return 0; 338 } 339 } 340 if (debug_xdamage > 2) { 341 fprintf(stderr, "xdamage: -> event %dx%d+%d+%d area:" 342 " %d dups: %d %s reg: %p\n", w, h, x, y, w*h, dcount, 343 (w*h > xdamage_max_area) ? "TOO_BIG" : "", (void *)reg); 344 } 345 346 record_desired_xdamage_rect(x, y, w, h); 347 348 tmpregion = sraRgnCreateRect(x, y, x + w, y + h); 349 sraRgnOr(reg, tmpregion); 350 sraRgnDestroy(tmpregion); 351 rect_count++; 352 ccount++; 353 354 if (0 && xdamage_direct_count) { 355 fb_push(); 356 } 357 358 dt = dtime(&tm); 359 if ((debug_tiles > 1 && ecount) || (debug_tiles && ecount > 200) 360 || debug_xdamage > 1) { 361 fprintf(stderr, "collect_non_X_xdamage(%d): %.4f t: %.4f ev/dup/accept" 362 "/direct %d/%d/%d/%d\n", call, dt, tm - x11vnc_start, ecount, 363 dcount, ccount, xdamage_direct_count); 364 } 365 now = time(NULL); 366 if (! last_rpt) { 367 last_rpt = now; 368 } 369 if (now > last_rpt + 15) { 370 double rat = -1.0; 371 372 if (XD_tot) { 373 rat = ((double) XD_skip)/XD_tot; 374 } 375 if (debug_tiles || debug_xdamage) { 376 fprintf(stderr, "xdamage: == scanline skip/tot: " 377 "%04d/%04d =%.3f rects: %d desired: %d\n", 378 XD_skip, XD_tot, rat, rect_count, XD_des); 379 } 380 381 XD_skip = 0; 382 XD_tot = 0; 383 XD_des = 0; 384 rect_count = 0; 385 last_rpt = now; 386 } 387 return 0; 388 } 389 390 int collect_xdamage(int scancnt, int call) { 391 #if LIBVNCSERVER_HAVE_LIBXDAMAGE 392 XDamageNotifyEvent *dev; 393 XEvent ev; 394 sraRegionPtr tmpregion; 395 sraRegionPtr reg; 396 static int rect_count = 0; 397 int nreg, ccount = 0, dcount = 0, ecount = 0; 398 static time_t last_rpt = 0; 399 time_t now; 400 int x, y, w, h, x2, y2; 401 int i, dup, next = 0, dup_max = 0; 402 #define DUPSZ 32 403 int dup_x[DUPSZ], dup_y[DUPSZ], dup_w[DUPSZ], dup_h[DUPSZ]; 404 double tm, dt; 405 int mark_all = 0, retries = 0, too_many = 1000, tot_ev = 0; 406 407 RAWFB_RET(0) 408 409 if (scancnt) {} /* unused vars warning: */ 410 411 if (! xdamage_present || ! use_xdamage) { 412 return 0; 413 } 414 if (! xdamage) { 415 return 0; 416 } 417 if (! xdamage_base_event_type) { 418 return 0; 419 } 420 if (! xdamage_regions) { 421 return 0; 422 } 423 424 dtime0(&tm); 425 426 nreg = (xdamage_memory * NSCAN) + 1; 427 428 if (call == 0) { 429 xdamage_ticker = (xdamage_ticker+1) % nreg; 430 xdamage_direct_count = 0; 431 reg = xdamage_regions[xdamage_ticker]; 432 if (reg != NULL) { 433 sraRgnMakeEmpty(reg); 434 } 435 } else { 436 if (xdamage_ticker < 0) { 437 xdamage_ticker = 0; 438 } 439 reg = xdamage_regions[xdamage_ticker]; 440 } 441 if (reg == NULL) { 442 return 0; 443 } 444 445 446 X_LOCK; 447 if (0) XFlush_wr(dpy); 448 if (0) XEventsQueued(dpy, QueuedAfterFlush); 449 450 come_back_for_more: 451 452 while (XCheckTypedEvent(dpy, xdamage_base_event_type+XDamageNotify, &ev)) { 453 /* 454 * TODO max cut off time in this loop? 455 * Could check QLength and if huge just mark the whole 456 * screen. 457 */ 458 ecount++; 459 tot_ev++; 460 461 if (mark_all) { 462 continue; 463 } 464 if (ecount == too_many) { 465 int nqa = XEventsQueued(dpy, QueuedAlready); 466 if (nqa >= too_many) { 467 static double last_msg = 0.0; 468 tmpregion = sraRgnCreateRect(0, 0, dpy_x, dpy_y); 469 sraRgnOr(reg, tmpregion); 470 sraRgnDestroy(tmpregion); 471 if (dnow() > last_msg + xdamage_crazy_delay) { 472 rfbLog("collect_xdamage: too many xdamage events %d+%d\n", ecount, nqa); 473 last_msg = dnow(); 474 } 475 mark_all = 1; 476 } 477 } 478 479 if (ev.type != xdamage_base_event_type + XDamageNotify) { 480 break; 481 } 482 dev = (XDamageNotifyEvent *) &ev; 483 if (dev->damage != xdamage) { 484 continue; /* not ours! */ 485 } 486 487 x = dev->area.x; 488 y = dev->area.y; 489 w = dev->area.width; 490 h = dev->area.height; 491 492 /* 493 * we try to manually remove some duplicates because 494 * certain activities can lead to many 10's of dups 495 * in a row. The region work can be costly and reg is 496 * later used in xdamage_hint_skip loops, so it is good 497 * to skip them if possible. 498 */ 499 dup = 0; 500 for (i=0; i < dup_max; i++) { 501 if (dup_x[i] == x && dup_y[i] == y && dup_w[i] == w && 502 dup_h[i] == h) { 503 dup = 1; 504 break; 505 } 506 } 507 if (dup) { 508 dcount++; 509 continue; 510 } 511 if (dup_max < DUPSZ) { 512 next = dup_max; 513 dup_max++; 514 } else { 515 next = (next+1) % DUPSZ; 516 } 517 dup_x[next] = x; 518 dup_y[next] = y; 519 dup_w[next] = w; 520 dup_h[next] = h; 521 522 /* translate if needed */ 523 if (clipshift) { 524 /* set coords relative to fb origin */ 525 if (0 && rootshift) { 526 /* 527 * Note: not needed because damage is 528 * relative to subwin, not rootwin. 529 */ 530 x = x - off_x; 531 y = y - off_y; 532 } 533 if (clipshift) { 534 x = x - coff_x; 535 y = y - coff_y; 536 } 537 538 x2 = x + w; /* upper point */ 539 x = nfix(x, dpy_x); /* place both in fb area */ 540 x2 = nfix(x2, dpy_x+1); 541 w = x2 - x; /* recompute w */ 542 543 y2 = y + h; 544 y = nfix(y, dpy_y); 545 y2 = nfix(y2, dpy_y+1); 546 h = y2 - y; 547 548 if (w <= 0 || h <= 0) { 549 continue; 550 } 551 } 552 if (debug_xdamage > 2) { 553 fprintf(stderr, "xdamage: -> event %dx%d+%d+%d area:" 554 " %d dups: %d %s\n", w, h, x, y, w*h, dcount, 555 (w*h > xdamage_max_area) ? "TOO_BIG" : ""); 556 } 557 558 record_desired_xdamage_rect(x, y, w, h); 559 560 tmpregion = sraRgnCreateRect(x, y, x + w, y + h); 561 sraRgnOr(reg, tmpregion); 562 sraRgnDestroy(tmpregion); 563 rect_count++; 564 ccount++; 565 } 566 567 if (mark_all) { 568 if (ecount + XEventsQueued(dpy, QueuedAlready) >= 3 * too_many && retries < 3) { 569 retries++; 570 XFlush_wr(dpy); 571 usleep(20 * 1000); 572 XFlush_wr(dpy); 573 ecount = 0; 574 goto come_back_for_more; 575 } 576 } 577 578 /* clear the whole damage region for next time. XXX check */ 579 if (call == 1) { 580 XDamageSubtract(dpy, xdamage, None, None); 581 } 582 X_UNLOCK; 583 584 if (tot_ev > 20 * too_many) { 585 rfbLog("collect_xdamage: xdamage has gone crazy (screensaver or game?) ev: %d ret: %d\n", tot_ev, retries); 586 rfbLog("collect_xdamage: disabling xdamage for %d seconds.\n", (int) xdamage_crazy_delay); 587 destroy_xdamage_if_needed(); 588 X_LOCK; 589 XSync(dpy, False); 590 while (XCheckTypedEvent(dpy, xdamage_base_event_type+XDamageNotify, &ev)) { 591 ; 592 } 593 X_UNLOCK; 594 xdamage_crazy_time = dnow(); 595 } 596 597 if (0 && xdamage_direct_count) { 598 fb_push(); 599 } 600 601 dt = dtime(&tm); 602 if ((debug_tiles > 1 && ecount) || (debug_tiles && ecount > 200) 603 || debug_xdamage > 1) { 604 fprintf(stderr, "collect_xdamage(%d): %.4f t: %.4f ev/dup/accept" 605 "/direct %d/%d/%d/%d\n", call, dt, tm - x11vnc_start, ecount, 606 dcount, ccount, xdamage_direct_count); 607 } 608 now = time(NULL); 609 if (! last_rpt) { 610 last_rpt = now; 611 } 612 if (now > last_rpt + 15) { 613 double rat = -1.0; 614 615 if (XD_tot) { 616 rat = ((double) XD_skip)/XD_tot; 617 } 618 if (debug_tiles || debug_xdamage) { 619 fprintf(stderr, "xdamage: == scanline skip/tot: " 620 "%04d/%04d =%.3f rects: %d desired: %d\n", 621 XD_skip, XD_tot, rat, rect_count, XD_des); 622 } 623 624 XD_skip = 0; 625 XD_tot = 0; 626 XD_des = 0; 627 rect_count = 0; 628 last_rpt = now; 629 } 630 #else 631 if (0) scancnt++; /* compiler warnings */ 632 if (0) call++; 633 if (0) record_desired_xdamage_rect(0, 0, 0, 0); 634 #endif 635 return 0; 636 } 637 638 int xdamage_hint_skip(int y) { 639 static sraRegionPtr scanline = NULL; 640 static sraRegionPtr tmpl_y = NULL; 641 int fast_tmpl = 1; 642 sraRegionPtr reg, tmpl; 643 int ret, i, n, nreg; 644 #ifndef NO_NCACHE 645 static int ncache_no_skip = 0; 646 static double last_ncache_no_skip = 0.0; 647 static double last_ncache_no_skip_long = 0.0, ncache_fac = 0.25; 648 #endif 649 650 if (! xdamage_present || ! use_xdamage) { 651 return 0; /* cannot skip */ 652 } 653 if (! xdamage_regions) { 654 return 0; /* cannot skip */ 655 } 656 657 if (! scanline) { 658 /* keep it around to avoid malloc etc, recreate */ 659 scanline = sraRgnCreate(); 660 } 661 if (! tmpl_y) { 662 tmpl_y = sraRgnCreateRect(0, 0, dpy_x, 1); 663 } 664 665 nreg = (xdamage_memory * NSCAN) + 1; 666 667 #ifndef NO_NCACHE 668 if (ncache > 0) { 669 if (ncache_no_skip == 0) { 670 double now = g_now; 671 if (now > last_ncache_no_skip + 8.0) { 672 ncache_no_skip = 1; 673 } else if (now < last_bs_restore + 0.5) { 674 ncache_no_skip = 1; 675 } else if (now < last_su_restore + 0.5) { 676 ncache_no_skip = 1; 677 } else if (now < last_copyrect + 0.5) { 678 ncache_no_skip = 1; 679 } 680 if (ncache_no_skip) { 681 last_ncache_no_skip = dnow(); 682 if (now > last_ncache_no_skip_long + 60.0) { 683 ncache_fac = 2.0; 684 last_ncache_no_skip_long = now; 685 } else { 686 ncache_fac = 0.25; 687 } 688 return 0; 689 } 690 } else { 691 if (ncache_no_skip++ >= ncache_fac*nreg + 4) { 692 ncache_no_skip = 0; 693 } else { 694 return 0; 695 } 696 } 697 } 698 #endif 699 700 if (fast_tmpl) { 701 sraRgnOffset(tmpl_y, 0, y); 702 tmpl = tmpl_y; 703 } else { 704 tmpl = sraRgnCreateRect(0, y, dpy_x, y+1); 705 } 706 707 ret = 1; 708 for (i=0; i<nreg; i++) { 709 /* go back thru the history starting at most recent */ 710 n = (xdamage_ticker + nreg - i) % nreg; 711 reg = xdamage_regions[n]; 712 if (reg == NULL) { 713 continue; 714 } 715 if (sraRgnEmpty(reg)) { 716 /* checking for emptiness is very fast */ 717 continue; 718 } 719 sraRgnMakeEmpty(scanline); 720 sraRgnOr(scanline, tmpl); 721 if (sraRgnAnd(scanline, reg)) { 722 ret = 0; 723 break; 724 } 725 } 726 if (fast_tmpl) { 727 sraRgnOffset(tmpl_y, 0, -y); 728 } else { 729 sraRgnDestroy(tmpl); 730 } 731 if (0) fprintf(stderr, "xdamage_hint_skip: %d -> %d\n", y, ret); 732 733 return ret; 734 } 735 736 void initialize_xdamage(void) { 737 sraRegionPtr *ptr; 738 int i, nreg; 739 740 if (! xdamage_present) { 741 use_xdamage = 0; 742 } 743 if (xdamage_regions) { 744 ptr = xdamage_regions; 745 while (*ptr != NULL) { 746 sraRgnDestroy(*ptr); 747 ptr++; 748 } 749 free(xdamage_regions); 750 xdamage_regions = NULL; 751 } 752 if (use_xdamage) { 753 nreg = (xdamage_memory * NSCAN) + 2; 754 xdamage_regions = (sraRegionPtr *) 755 malloc(nreg * sizeof(sraRegionPtr)); 756 for (i = 0; i < nreg; i++) { 757 ptr = xdamage_regions+i; 758 if (i == nreg - 1) { 759 *ptr = NULL; 760 } else { 761 *ptr = sraRgnCreate(); 762 sraRgnMakeEmpty(*ptr); 763 } 764 } 765 /* set so will be 0 in first collect_xdamage call */ 766 xdamage_ticker = -1; 767 } 768 } 769 770 void create_xdamage_if_needed(int force) { 771 772 RAWFB_RET_VOID 773 774 if (force) {} 775 776 #if LIBVNCSERVER_HAVE_LIBXDAMAGE 777 if (! xdamage || force) { 778 X_LOCK; 779 xdamage = XDamageCreate(dpy, window, XDamageReportRawRectangles); 780 XDamageSubtract(dpy, xdamage, None, None); 781 X_UNLOCK; 782 rfbLog("created xdamage object: 0x%lx\n", xdamage); 783 } 784 #endif 785 } 786 787 void destroy_xdamage_if_needed(void) { 788 789 RAWFB_RET_VOID 790 791 #if LIBVNCSERVER_HAVE_LIBXDAMAGE 792 if (xdamage) { 793 XEvent ev; 794 X_LOCK; 795 XDamageDestroy(dpy, xdamage); 796 XFlush_wr(dpy); 797 if (xdamage_base_event_type) { 798 while (XCheckTypedEvent(dpy, 799 xdamage_base_event_type+XDamageNotify, &ev)) { 800 ; 801 } 802 } 803 X_UNLOCK; 804 rfbLog("destroyed xdamage object: 0x%lx\n", xdamage); 805 xdamage = 0; 806 } 807 #endif 808 } 809 810 void check_xdamage_state(void) { 811 if (! xdamage_present) { 812 return; 813 } 814 /* 815 * Create or destroy the Damage object as needed, we don't want 816 * one if no clients are connected. 817 */ 818 if (xdamage_crazy_time > 0.0 && dnow() < xdamage_crazy_time + xdamage_crazy_delay) { 819 return; 820 } 821 if (client_count && use_xdamage) { 822 create_xdamage_if_needed(0); 823 if (xdamage_scheduled_mark > 0.0 && dnow() > 824 xdamage_scheduled_mark) { 825 if (xdamage_scheduled_mark_region) { 826 mark_region_for_xdamage( 827 xdamage_scheduled_mark_region); 828 sraRgnDestroy(xdamage_scheduled_mark_region); 829 xdamage_scheduled_mark_region = NULL; 830 } else { 831 mark_for_xdamage(0, 0, dpy_x, dpy_y); 832 } 833 xdamage_scheduled_mark = 0.0; 834 } 835 } else { 836 destroy_xdamage_if_needed(); 837 } 838 } 839 840 841