1 /*
2 Copyright (C) 2002-2010 Karl J. Runge <runge@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
record_desired_xdamage_rect(int x,int y,int w,int h)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
add_region_xdamage(sraRegionPtr new_region)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
clear_xdamage_mark_region(sraRegionPtr markregion,int flush)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
collect_non_X_xdamage(int x_in,int y_in,int w_in,int h_in,int call)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
collect_xdamage(int scancnt,int call)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
xdamage_hint_skip(int y)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
initialize_xdamage(void)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
create_xdamage_if_needed(int force)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
destroy_xdamage_if_needed(void)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
check_xdamage_state(void)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