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 /* -- userinput.c -- */ 34 35 #include "x11vnc.h" 36 #include "xwrappers.h" 37 #include "xdamage.h" 38 #include "xrecord.h" 39 #include "xinerama.h" 40 #include "win_utils.h" 41 #include "xevents.h" 42 #include "user.h" 43 #include "scan.h" 44 #include "cleanup.h" 45 #include "pointer.h" 46 #include "rates.h" 47 #include "keyboard.h" 48 #include "solid.h" 49 #include "xrandr.h" 50 #include "8to24.h" 51 #include "unixpw.h" 52 #include "macosx.h" 53 #include "macosxCGS.h" 54 #include "cursor.h" 55 #include "screen.h" 56 #include "connections.h" 57 58 /* 59 * user input handling heuristics 60 */ 61 int defer_update_nofb = 4; /* defer a shorter time under -nofb */ 62 int last_scroll_type = SCR_NONE; 63 64 65 int get_wm_frame_pos(int *px, int *py, int *x, int *y, int *w, int *h, 66 Window *frame, Window *win); 67 void parse_scroll_copyrect(void); 68 void parse_fixscreen(void); 69 void parse_wireframe(void); 70 71 void set_wirecopyrect_mode(char *str); 72 void set_scrollcopyrect_mode(char *str); 73 void initialize_scroll_keys(void); 74 void initialize_scroll_matches(void); 75 void initialize_scroll_term(void); 76 void initialize_max_keyrepeat(void); 77 78 int direct_fb_copy(int x1, int y1, int x2, int y2, int mark); 79 void fb_push(void); 80 int fb_push_wait(double max_wait, int flags); 81 void eat_viewonly_input(int max_eat, int keep); 82 83 void mark_for_xdamage(int x, int y, int w, int h); 84 void mark_region_for_xdamage(sraRegionPtr region); 85 void set_xdamage_mark(int x, int y, int w, int h); 86 int near_wm_edge(int x, int y, int w, int h, int px, int py); 87 int near_scrollbar_edge(int x, int y, int w, int h, int px, int py); 88 89 void check_fixscreen(void); 90 int check_xrecord(void); 91 int check_wireframe(void); 92 int fb_update_sent(int *count); 93 int check_user_input(double dt, double dtr, int tile_diffs, int *cnt); 94 void do_copyregion(sraRegionPtr region, int dx, int dy, int mode); 95 96 int check_ncache(int reset, int mode); 97 int find_rect(int idx, int x, int y, int w, int h); 98 int bs_restore(int idx, int *nbatch, sraRegionPtr rmask, XWindowAttributes *attr, int clip, int nopad, int *valid, int verb); 99 int try_to_fix_su(Window win, int idx, Window above, int *nbatch, char *mode); 100 int try_to_fix_resize_su(Window orig_frame, int orig_x, int orig_y, int orig_w, int orig_h, 101 int x, int y, int w, int h, int try_batch); 102 int lookup_win_index(Window); 103 void set_ncache_xrootpmap(void); 104 105 static void get_client_regions(int *req, int *mod, int *cpy, int *num) ; 106 static void parse_scroll_copyrect_str(char *scr); 107 static void parse_wireframe_str(char *wf); 108 static void destroy_str_list(char **list); 109 static void draw_box(int x, int y, int w, int h, int restore); 110 static int do_bdpush(Window wm_win, int x0, int y0, int w0, int h0, int bdx, 111 int bdy, int bdskinny); 112 static int set_ypad(void); 113 static void scale_mark(int x1, int y1, int x2, int y2, int mark); 114 static int push_scr_ev(double *age, int type, int bdpush, int bdx, int bdy, 115 int bdskinny, int first_push); 116 static int crfix(int x, int dx, int Lx); 117 static int scrollability(Window win, int set); 118 static int eat_pointer(int max_ptr_eat, int keep); 119 static void set_bdpush(int type, double *last_bdpush, int *pushit); 120 static int repeat_check(double last_key_scroll); 121 static int check_xrecord_keys(void); 122 static int check_xrecord_mouse(void); 123 static int try_copyrect(Window orig_frame, Window frame, int x, int y, int w, int h, 124 int dx, int dy, int *obscured, sraRegionPtr extra_clip, double max_wait, int *nbatch); 125 static int wireframe_mod_state(); 126 static void check_user_input2(double dt); 127 static void check_user_input3(double dt, double dtr, int tile_diffs); 128 static void check_user_input4(double dt, double dtr, int tile_diffs); 129 130 winattr_t *cache_list; 131 132 /* 133 * For -wireframe: find the direct child of rootwin that has the 134 * pointer, assume that is the WM frame that contains the application 135 * (i.e. wm reparents the app toplevel) return frame position and size 136 * if successful. 137 */ 138 int get_wm_frame_pos(int *px, int *py, int *x, int *y, int *w, int *h, 139 Window *frame, Window *win) { 140 #if !NO_X11 141 Window r, c; 142 XWindowAttributes attr; 143 Bool ret; 144 int rootx, rooty, wx, wy; 145 unsigned int mask; 146 #endif 147 148 #ifdef MACOSX 149 if (macosx_console) { 150 return macosx_get_wm_frame_pos(px, py, x, y, w, h, frame, win); 151 } 152 #endif 153 154 RAWFB_RET(0) 155 156 #if NO_X11 157 if (!px || !py || !x || !y || !w || !h || !frame || !win) {} 158 return 0; 159 #else 160 161 162 ret = XQueryPointer_wr(dpy, rootwin, &r, &c, &rootx, &rooty, &wx, &wy, 163 &mask); 164 165 *frame = c; 166 167 /* current pointer position is returned too */ 168 *px = rootx; 169 *py = rooty; 170 171 if (!ret || ! c || c == rootwin) { 172 /* no immediate child */ 173 return 0; 174 } 175 176 /* child window position and size */ 177 if (! valid_window(c, &attr, 1)) { 178 return 0; 179 } 180 181 *x = attr.x; 182 *y = attr.y; 183 *w = attr.width; 184 *h = attr.height; 185 186 #if 0 187 /* more accurate, but the animation is bogus anyway */ 188 if (attr.border_width > 0) { 189 *w += 2 * attr.border_width; 190 *h += 2 * attr.border_width; 191 } 192 #endif 193 194 if (win != NULL) { 195 *win = descend_pointer(5, c, NULL, 0); 196 } 197 198 return 1; 199 #endif /* NO_X11 */ 200 } 201 202 static int scrollcopyrect_top, scrollcopyrect_bot; 203 static int scrollcopyrect_left, scrollcopyrect_right; 204 static double scr_key_time, scr_key_persist; 205 static double scr_mouse_time, scr_mouse_persist, scr_mouse_maxtime; 206 static double scr_mouse_pointer_delay; 207 static double scr_key_bdpush_time, scr_mouse_bdpush_time; 208 209 static void parse_scroll_copyrect_str(char *scr) { 210 char *p, *str; 211 int i; 212 char *part[16]; 213 214 for (i=0; i<16; i++) { 215 part[i] = NULL; 216 } 217 218 if (scr == NULL || *scr == '\0') { 219 return; 220 } 221 222 str = strdup(scr); 223 224 p = strtok(str, ","); 225 i = 0; 226 while (p) { 227 part[i++] = strdup(p); 228 p = strtok(NULL, ","); 229 if (i >= 16) break; 230 } 231 free(str); 232 233 234 /* 235 * Top, Bottom, Left, Right tolerances for scrollbar locations. 236 */ 237 if ((str = part[0]) != NULL) { 238 int t, b, l, r; 239 if (sscanf(str, "%d+%d+%d+%d", &t, &b, &l, &r) == 4) { 240 scrollcopyrect_top = t; 241 scrollcopyrect_bot = b; 242 scrollcopyrect_left = l; 243 scrollcopyrect_right = r; 244 } 245 free(str); 246 } 247 248 /* key scrolling timing heuristics. */ 249 if ((str = part[1]) != NULL) { 250 double t1, t2, t3; 251 if (sscanf(str, "%lf+%lf+%lf", &t1, &t2, &t3) == 3) { 252 scr_key_time = t1; 253 scr_key_persist = t2; 254 scr_key_bdpush_time = t3; 255 } 256 free(str); 257 } 258 259 /* mouse scrolling timing heuristics. */ 260 if ((str = part[2]) != NULL) { 261 double t1, t2, t3, t4, t5; 262 if (sscanf(str, "%lf+%lf+%lf+%lf+%lf", &t1, &t2, &t3, &t4, 263 &t5) == 5) { 264 scr_mouse_time = t1; 265 scr_mouse_persist = t2; 266 scr_mouse_bdpush_time = t3; 267 scr_mouse_pointer_delay = t4; 268 scr_mouse_maxtime = t5; 269 } 270 free(str); 271 } 272 } 273 274 void parse_scroll_copyrect(void) { 275 parse_scroll_copyrect_str(SCROLL_COPYRECT_PARMS); 276 if (! scroll_copyrect_str) { 277 scroll_copyrect_str = strdup(SCROLL_COPYRECT_PARMS); 278 } 279 parse_scroll_copyrect_str(scroll_copyrect_str); 280 } 281 282 void parse_fixscreen(void) { 283 char *str, *p; 284 285 screen_fixup_V = 0.0; 286 screen_fixup_C = 0.0; 287 screen_fixup_X = 0.0; 288 screen_fixup_8 = 0.0; 289 290 if (! screen_fixup_str) { 291 return; 292 } 293 294 str = strdup(screen_fixup_str); 295 296 p = strtok(str, ","); 297 while (p) { 298 double t; 299 if (*p == 'V' && sscanf(p, "V=%lf", &t) == 1) { 300 screen_fixup_V = t; 301 } else if (*p == 'C' && sscanf(p, "C=%lf", &t) == 1) { 302 screen_fixup_C = t; 303 } else if (*p == 'X' && sscanf(p, "X=%lf", &t) == 1) { 304 screen_fixup_X = t; 305 } else if (*p == 'X' && sscanf(p, "8=%lf", &t) == 1) { 306 screen_fixup_8 = t; 307 } 308 p = strtok(NULL, ","); 309 } 310 free(str); 311 312 if (screen_fixup_V < 0.0) screen_fixup_V = 0.0; 313 if (screen_fixup_C < 0.0) screen_fixup_C = 0.0; 314 if (screen_fixup_X < 0.0) screen_fixup_X = 0.0; 315 if (screen_fixup_8 < 0.0) screen_fixup_8 = 0.0; 316 } 317 318 /* 319 WIREFRAME_PARMS "0xff,2,0,30+6+6+6,Alt,0.05+0.3+2.0,8" 320 0xff,2,0,32+8+8+8,all,0.15+0.30+5.0+0.125 321 shade,linewidth,percent,T+B+L+R,mods,t1+t2+t3+t4 322 */ 323 #define LW_MAX 8 324 static unsigned long wireframe_shade = 0xff; 325 static int wireframe_lw; 326 static double wireframe_frac; 327 static int wireframe_top, wireframe_bot, wireframe_left, wireframe_right; 328 static double wireframe_t1, wireframe_t2, wireframe_t3, wireframe_t4; 329 static char *wireframe_mods = NULL; 330 331 /* 332 * Parse the gory -wireframe string for parameters. 333 */ 334 static void parse_wireframe_str(char *wf) { 335 char *p, *str; 336 int i; 337 char *part[16]; 338 339 for (i=0; i<16; i++) { 340 part[i] = NULL; 341 } 342 343 if (wf == NULL || *wf == '\0') { 344 return; 345 } 346 347 str = strdup(wf); 348 349 /* leading ",", make it start with ignorable string "z" */ 350 if (*str == ',') { 351 char *tmp = (char *) malloc(strlen(str)+2); 352 strcpy(tmp, "z"); 353 strcat(tmp, str); 354 free(str); 355 str = tmp; 356 } 357 358 p = strtok(str, ","); 359 i = 0; 360 while (p) { 361 part[i++] = strdup(p); 362 p = strtok(NULL, ","); 363 if (i >= 16) break; 364 } 365 free(str); 366 367 368 /* Wireframe shade, color, RGB: */ 369 if ((str = part[0]) != NULL) { 370 unsigned long n; 371 int r, g, b, ok = 0; 372 XColor cdef; 373 Colormap cmap; 374 if (dpy && (bpp == 32 || bpp == 16)) { 375 #if !NO_X11 376 X_LOCK; 377 cmap = DefaultColormap (dpy, scr); 378 if (XParseColor(dpy, cmap, str, &cdef) && 379 XAllocColor(dpy, cmap, &cdef)) { 380 r = cdef.red >> 8; 381 g = cdef.green >> 8; 382 b = cdef.blue >> 8; 383 if (r == 0 && g == 0) { 384 g = 1; /* need to be > 255 */ 385 } 386 n = 0; 387 n |= (r << main_red_shift); 388 n |= (g << main_green_shift); 389 n |= (b << main_blue_shift); 390 wireframe_shade = n; 391 ok = 1; 392 } 393 X_UNLOCK; 394 #else 395 r = g = b = 0; 396 cmap = 0; 397 cdef.pixel = 0; 398 #endif 399 } 400 if (ok) { 401 ; 402 } else if (sscanf(str, "0x%lx", &n) == 1) { 403 wireframe_shade = n; 404 } else if (sscanf(str, "%lu", &n) == 1) { 405 wireframe_shade = n; 406 } else if (sscanf(str, "%lx", &n) == 1) { 407 wireframe_shade = n; 408 } 409 free(str); 410 } 411 412 /* linewidth: # of pixels wide for the wireframe lines */ 413 if ((str = part[1]) != NULL) { 414 int n; 415 if (sscanf(str, "%d", &n) == 1) { 416 wireframe_lw = n; 417 if (wireframe_lw < 1) { 418 wireframe_lw = 1; 419 } 420 if (wireframe_lw > LW_MAX) { 421 wireframe_lw = LW_MAX; 422 } 423 } 424 free(str); 425 } 426 427 /* percentage cutoff for opaque move/resize (like WM's) */ 428 if ((str = part[2]) != NULL) { 429 if (*str == '\0') { 430 ; 431 } else if (strchr(str, '.')) { 432 wireframe_frac = atof(str); 433 } else { 434 wireframe_frac = ((double) atoi(str))/100.0; 435 } 436 free(str); 437 } 438 439 /* 440 * Top, Bottom, Left, Right tolerances to guess the wm frame is 441 * being grabbed (Top is traditionally bigger, i.e. titlebar): 442 */ 443 if ((str = part[3]) != NULL) { 444 int t, b, l, r; 445 if (sscanf(str, "%d+%d+%d+%d", &t, &b, &l, &r) == 4) { 446 wireframe_top = t; 447 wireframe_bot = b; 448 wireframe_left = l; 449 wireframe_right = r; 450 } 451 free(str); 452 } 453 454 /* 455 * wireframe in interior with Modifier down. 456 * 0 => no mods 457 * 1 => all mods 458 * Shift,Alt,Control,Meta,Super,Hyper 459 */ 460 if (wireframe_mods) { 461 free(wireframe_mods); 462 } 463 wireframe_mods = NULL; 464 if ((str = part[4]) != NULL) { 465 if (*str == '0' || !strcmp(str, "none")) { 466 ; 467 } else if (*str == '1' || !strcmp(str, "all")) { 468 wireframe_mods = strdup("all"); 469 } else if (!strcmp(str, "Alt") || !strcmp(str, "Shift") 470 || !strcmp(str, "Control") || !strcmp(str, "Meta") 471 || !strcmp(str, "Super") || !strcmp(str, "Hyper")) { 472 wireframe_mods = strdup(str); 473 } 474 } 475 476 /* check_wireframe() timing heuristics. */ 477 if ((str = part[5]) != NULL) { 478 double t1, t2, t3, t4; 479 if (sscanf(str, "%lf+%lf+%lf+%lf", &t1, &t2, &t3, &t4) == 4) { 480 wireframe_t1 = t1; 481 wireframe_t2 = t2; 482 wireframe_t3 = t3; 483 wireframe_t4 = t4; 484 } 485 free(str); 486 } 487 } 488 489 /* 490 * First parse the defaults and apply any user supplied ones (may be a subset) 491 */ 492 void parse_wireframe(void) { 493 parse_wireframe_str(WIREFRAME_PARMS); 494 if (! wireframe_str) { 495 wireframe_str = strdup(WIREFRAME_PARMS); 496 } 497 parse_wireframe_str(wireframe_str); 498 } 499 500 /* 501 * Set wireframe_copyrect based on desired mode. 502 */ 503 void set_wirecopyrect_mode(char *str) { 504 char *orig = wireframe_copyrect; 505 if (str == NULL || *str == '\0') { 506 wireframe_copyrect = strdup(wireframe_copyrect_default); 507 } else if (!strcmp(str, "always") || !strcmp(str, "all")) { 508 wireframe_copyrect = strdup("always"); 509 } else if (!strcmp(str, "top")) { 510 wireframe_copyrect = strdup("top"); 511 } else if (!strcmp(str, "never") || !strcmp(str, "none")) { 512 wireframe_copyrect = strdup("never"); 513 } else { 514 if (! wireframe_copyrect) { 515 wireframe_copyrect = strdup(wireframe_copyrect_default); 516 } else { 517 orig = NULL; 518 } 519 rfbLog("unknown -wirecopyrect mode: %s, using: %s\n", str, 520 wireframe_copyrect); 521 } 522 if (orig) { 523 free(orig); 524 } 525 } 526 527 /* 528 * Set scroll_copyrect based on desired mode. 529 */ 530 void set_scrollcopyrect_mode(char *str) { 531 char *orig = scroll_copyrect; 532 if (str == NULL || *str == '\0') { 533 scroll_copyrect = strdup(scroll_copyrect_default); 534 } else if (!strcmp(str, "always") || !strcmp(str, "all") || 535 !strcmp(str, "both")) { 536 scroll_copyrect = strdup("always"); 537 } else if (!strcmp(str, "keys") || !strcmp(str, "keyboard")) { 538 scroll_copyrect = strdup("keys"); 539 } else if (!strcmp(str, "mouse") || !strcmp(str, "pointer")) { 540 scroll_copyrect = strdup("mouse"); 541 } else if (!strcmp(str, "never") || !strcmp(str, "none")) { 542 scroll_copyrect = strdup("never"); 543 } else { 544 if (! scroll_copyrect) { 545 scroll_copyrect = strdup(scroll_copyrect_default); 546 } else { 547 orig = NULL; 548 } 549 rfbLog("unknown -scrollcopyrect mode: %s, using: %s\n", str, 550 scroll_copyrect); 551 } 552 if (orig) { 553 free(orig); 554 } 555 } 556 557 void initialize_scroll_keys(void) { 558 char *str, *p; 559 int i, nkeys = 0, saw_builtin = 0; 560 int ks_max = 2 * 0xFFFF; 561 562 if (scroll_key_list) { 563 free(scroll_key_list); 564 scroll_key_list = NULL; 565 } 566 if (! scroll_key_list_str || *scroll_key_list_str == '\0') { 567 return; 568 } 569 570 if (strstr(scroll_key_list_str, "builtin")) { 571 int k; 572 /* add in number of keysyms builtin gives */ 573 for (k=1; k<ks_max; k++) { 574 if (xrecord_scroll_keysym((rfbKeySym) k)) { 575 nkeys++; 576 } 577 } 578 } 579 580 nkeys++; /* first key, i.e. no commas. */ 581 p = str = strdup(scroll_key_list_str); 582 while(*p) { 583 if (*p == ',') { 584 nkeys++; /* additional key. */ 585 } 586 p++; 587 } 588 589 nkeys++; /* exclude/include 0 element */ 590 nkeys++; /* trailing NoSymbol */ 591 592 scroll_key_list = (KeySym *) malloc(nkeys*sizeof(KeySym)); 593 for (i=0; i<nkeys; i++) { 594 scroll_key_list[i] = NoSymbol; 595 } 596 if (*str == '-') { 597 scroll_key_list[0] = 1; 598 p = strtok(str+1, ","); 599 } else { 600 p = strtok(str, ","); 601 } 602 i = 1; 603 while (p) { 604 if (!strcmp(p, "builtin")) { 605 int k; 606 if (saw_builtin) { 607 p = strtok(NULL, ","); 608 continue; 609 } 610 saw_builtin = 1; 611 for (k=1; k<ks_max; k++) { 612 if (xrecord_scroll_keysym((rfbKeySym) k)) { 613 scroll_key_list[i++] = (rfbKeySym) k; 614 } 615 } 616 } else { 617 unsigned int in; 618 if (sscanf(p, "%u", &in) == 1) { 619 scroll_key_list[i++] = (rfbKeySym) in; 620 } else if (sscanf(p, "0x%x", &in) == 1) { 621 scroll_key_list[i++] = (rfbKeySym) in; 622 } else if (XStringToKeysym(p) != NoSymbol) { 623 scroll_key_list[i++] = XStringToKeysym(p); 624 } else { 625 rfbLog("initialize_scroll_keys: skip unknown " 626 "keysym: %s\n", p); 627 } 628 } 629 p = strtok(NULL, ","); 630 } 631 free(str); 632 } 633 634 static void destroy_str_list(char **list) { 635 int i = 0; 636 if (! list) { 637 return; 638 } 639 while (list[i] != NULL) { 640 free(list[i++]); 641 } 642 free(list); 643 } 644 645 void initialize_scroll_matches(void) { 646 char *str, *imp = "__IMPOSSIBLE_STR__"; 647 int i, n, nkey, nmouse; 648 649 destroy_str_list(scroll_good_all); 650 scroll_good_all = NULL; 651 destroy_str_list(scroll_good_key); 652 scroll_good_key = NULL; 653 destroy_str_list(scroll_good_mouse); 654 scroll_good_mouse = NULL; 655 656 destroy_str_list(scroll_skip_all); 657 scroll_skip_all = NULL; 658 destroy_str_list(scroll_skip_key); 659 scroll_skip_key = NULL; 660 destroy_str_list(scroll_skip_mouse); 661 scroll_skip_mouse = NULL; 662 663 /* scroll_good: */ 664 if (scroll_good_str != NULL && *scroll_good_str != '\0') { 665 str = scroll_good_str; 666 } else { 667 str = scroll_good_str0; 668 } 669 scroll_good_all = create_str_list(str); 670 671 nkey = 0; 672 nmouse = 0; 673 n = 0; 674 while (scroll_good_all[n] != NULL) { 675 char *s = scroll_good_all[n++]; 676 if (strstr(s, "KEY:") == s) nkey++; 677 if (strstr(s, "MOUSE:") == s) nmouse++; 678 } 679 if (nkey++) { 680 scroll_good_key = (char **) malloc(nkey*sizeof(char *)); 681 for (i=0; i<nkey; i++) scroll_good_key[i] = NULL; 682 } 683 if (nmouse++) { 684 scroll_good_mouse = (char **) malloc(nmouse*sizeof(char *)); 685 for (i=0; i<nmouse; i++) scroll_good_mouse[i] = NULL; 686 } 687 nkey = 0; 688 nmouse = 0; 689 for (i=0; i<n; i++) { 690 char *s = scroll_good_all[i]; 691 if (strstr(s, "KEY:") == s) { 692 scroll_good_key[nkey++] = strdup(s+strlen("KEY:")); 693 free(s); 694 scroll_good_all[i] = strdup(imp); 695 } else if (strstr(s, "MOUSE:") == s) { 696 scroll_good_mouse[nmouse++]=strdup(s+strlen("MOUSE:")); 697 free(s); 698 scroll_good_all[i] = strdup(imp); 699 } 700 } 701 702 /* scroll_skip: */ 703 if (scroll_skip_str != NULL && *scroll_skip_str != '\0') { 704 str = scroll_skip_str; 705 } else { 706 str = scroll_skip_str0; 707 } 708 scroll_skip_all = create_str_list(str); 709 710 nkey = 0; 711 nmouse = 0; 712 n = 0; 713 while (scroll_skip_all[n] != NULL) { 714 char *s = scroll_skip_all[n++]; 715 if (strstr(s, "KEY:") == s) nkey++; 716 if (strstr(s, "MOUSE:") == s) nmouse++; 717 } 718 if (nkey++) { 719 scroll_skip_key = (char **) malloc(nkey*sizeof(char *)); 720 for (i=0; i<nkey; i++) scroll_skip_key[i] = NULL; 721 } 722 if (nmouse++) { 723 scroll_skip_mouse = (char **) malloc(nmouse*sizeof(char *)); 724 for (i=0; i<nmouse; i++) scroll_skip_mouse[i] = NULL; 725 } 726 nkey = 0; 727 nmouse = 0; 728 for (i=0; i<n; i++) { 729 char *s = scroll_skip_all[i]; 730 if (strstr(s, "KEY:") == s) { 731 scroll_skip_key[nkey++] = strdup(s+strlen("KEY:")); 732 free(s); 733 scroll_skip_all[i] = strdup(imp); 734 } else if (strstr(s, "MOUSE:") == s) { 735 scroll_skip_mouse[nmouse++]=strdup(s+strlen("MOUSE:")); 736 free(s); 737 scroll_skip_all[i] = strdup(imp); 738 } 739 } 740 } 741 742 void initialize_scroll_term(void) { 743 char *str; 744 int n; 745 746 destroy_str_list(scroll_term); 747 scroll_term = NULL; 748 749 if (scroll_term_str != NULL && *scroll_term_str != '\0') { 750 str = scroll_term_str; 751 } else { 752 str = scroll_term_str0; 753 } 754 if (!strcmp(str, "none")) { 755 return; 756 } 757 scroll_term = create_str_list(str); 758 759 n = 0; 760 while (scroll_term[n] != NULL) { 761 char *s = scroll_good_all[n++]; 762 /* pull parameters out at some point */ 763 s = NULL; 764 } 765 } 766 767 void initialize_max_keyrepeat(void) { 768 char *str; 769 int lo, hi; 770 771 if (max_keyrepeat_str != NULL && *max_keyrepeat_str != '\0') { 772 str = max_keyrepeat_str; 773 } else { 774 str = max_keyrepeat_str0; 775 } 776 777 if (sscanf(str, "%d-%d", &lo, &hi) != 2) { 778 rfbLog("skipping invalid -scr_keyrepeat string: %s\n", str); 779 sscanf(max_keyrepeat_str0, "%d-%d", &lo, &hi); 780 } 781 max_keyrepeat_lo = lo; 782 max_keyrepeat_hi = hi; 783 if (max_keyrepeat_lo < 1) { 784 max_keyrepeat_lo = 1; 785 } 786 if (max_keyrepeat_hi > 40) { 787 max_keyrepeat_hi = 40; 788 } 789 } 790 791 typedef struct saveline { 792 int x0, y0, x1, y1; 793 int shift; 794 int vert; 795 int saved; 796 char *data; 797 } saveline_t; 798 799 /* 800 * Draw the wireframe box onto the framebuffer. Saves the real 801 * framebuffer data to some storage lines. Restores previous lines. 802 * use restore = 1 to clean up (done with animation). 803 * This works with -scale. 804 */ 805 static void draw_box(int x, int y, int w, int h, int restore) { 806 int x0, y0, x1, y1, i, pixelsize = bpp/8; 807 char *dst, *src, *use_fb; 808 static saveline_t *save[4]; 809 static int first = 1, len = 0; 810 int max = dpy_x > dpy_y ? dpy_x : dpy_y; 811 int use_Bpl, lw = wireframe_lw; 812 unsigned long shade = wireframe_shade; 813 int color = 0; 814 unsigned short us = 0; 815 unsigned long ul = 0; 816 817 if (clipshift) { 818 x -= coff_x; 819 y -= coff_y; 820 } 821 822 /* handle -8to24 mode: use 2nd fb only */ 823 use_fb = main_fb; 824 use_Bpl = main_bytes_per_line; 825 826 if (cmap8to24 && cmap8to24_fb) { 827 use_fb = cmap8to24_fb; 828 pixelsize = 4; 829 if (depth <= 8) { 830 use_Bpl *= 4; 831 } else if (depth <= 16) { 832 use_Bpl *= 2; 833 } 834 } 835 836 if (max > len) { 837 /* create/resize storage lines: */ 838 for (i=0; i<4; i++) { 839 len = max; 840 if (! first && save[i]) { 841 if (save[i]->data) { 842 free(save[i]->data); 843 save[i]->data = NULL; 844 } 845 free(save[i]); 846 } 847 save[i] = (saveline_t *) malloc(sizeof(saveline_t)); 848 save[i]->saved = 0; 849 save[i]->data = (char *) malloc( (LW_MAX+1)*len*4 ); 850 851 /* 852 * Four types of lines: 853 * 0) top horizontal 854 * 1) bottom horizontal 855 * 2) left vertical 856 * 3) right vertical 857 * 858 * shift means shifted by width or height. 859 */ 860 if (i == 0) { 861 save[i]->vert = 0; 862 save[i]->shift = 0; 863 } else if (i == 1) { 864 save[i]->vert = 0; 865 save[i]->shift = 1; 866 } else if (i == 2) { 867 save[i]->vert = 1; 868 save[i]->shift = 0; 869 } else if (i == 3) { 870 save[i]->vert = 1; 871 save[i]->shift = 1; 872 } 873 } 874 } 875 first = 0; 876 877 /* 878 * restore any saved lines. see below for algorithm and 879 * how x0, etc. are used. we just reverse those steps. 880 */ 881 for (i=0; i<4; i++) { 882 int s = save[i]->shift; 883 int yu, y_min = -1, y_max = -1; 884 int y_start, y_stop, y_step; 885 886 if (! save[i]->saved) { 887 continue; 888 } 889 x0 = save[i]->x0; 890 y0 = save[i]->y0; 891 x1 = save[i]->x1; 892 y1 = save[i]->y1; 893 if (save[i]->vert) { 894 y_start = y0+lw; 895 y_stop = y1-lw; 896 y_step = lw*pixelsize; 897 } else { 898 y_start = y0 - s*lw; 899 y_stop = y_start + lw; 900 y_step = max*pixelsize; 901 } 902 for (yu = y_start; yu < y_stop; yu++) { 903 if (x0 == x1) { 904 continue; 905 } 906 if (yu < 0 || yu >= dpy_y) { 907 continue; 908 } 909 if (y_min < 0 || yu < y_min) { 910 y_min = yu; 911 } 912 if (y_max < 0 || yu > y_max) { 913 y_max = yu; 914 } 915 src = save[i]->data + (yu-y_start)*y_step; 916 dst = use_fb + yu*use_Bpl + x0*pixelsize; 917 memcpy(dst, src, (x1-x0)*pixelsize); 918 } 919 if (y_min >= 0) { 920 if (0) fprintf(stderr, "Mark-1 %d %d %d %d\n", x0, y_min, x1, y_max+1); 921 mark_rect_as_modified(x0, y_min, x1, y_max+1, 0); 922 } 923 save[i]->saved = 0; 924 } 925 926 if (0) fprintf(stderr, " DrawBox: %04dx%04d+%04d+%04d B=%d rest=%d lw=%d %.4f\n", w, h, x, y, 2*(w+h)*(2-restore)*pixelsize*lw, restore, lw, dnowx()); 927 928 if (restore) { 929 return; 930 } 931 932 933 /* 934 * work out shade/color for the wireframe line, could be a color 935 * for 16bpp or 24bpp. 936 */ 937 if (shade > 255) { 938 if (pixelsize == 2) { 939 us = (unsigned short) (shade & 0xffff); 940 color = 1; 941 } else if (pixelsize == 4) { 942 ul = (unsigned long) shade; 943 color = 1; 944 } else { 945 shade = shade % 256; 946 } 947 } 948 949 for (i=0; i<4; i++) { 950 int s = save[i]->shift; 951 int yu, y_min = -1, y_max = -1; 952 int yblack = -1, xblack1 = -1, xblack2 = -1; 953 int y_start, y_stop, y_step; 954 955 if (save[i]->vert) { 956 /* 957 * make the narrow x's be on the screen, let 958 * the y's hang off (not drawn). 959 */ 960 save[i]->x0 = x0 = nfix(x + s*w - s*lw, dpy_x); 961 save[i]->y0 = y0 = y; 962 save[i]->x1 = x1 = nfix(x + s*w - s*lw + lw, dpy_x); 963 save[i]->y1 = y1 = y + h; 964 965 /* 966 * start and stop a linewidth away from true edge, 967 * to avoid interfering with horizontal lines. 968 */ 969 y_start = y0+lw; 970 y_stop = y1-lw; 971 y_step = lw*pixelsize; 972 973 /* draw a black pixel for the border if lw > 1 */ 974 if (s) { 975 xblack1 = x1-1; 976 } else { 977 xblack1 = x0; 978 } 979 } else { 980 /* 981 * make the wide x's be on the screen, let the y's 982 * hang off (not drawn). 983 */ 984 save[i]->x0 = x0 = nfix(x, dpy_x); 985 save[i]->y0 = y0 = y + s*h; 986 save[i]->x1 = x1 = nfix(x + w, dpy_x); 987 save[i]->y1 = y1 = y0 + lw; 988 y_start = y0 - s*lw; 989 y_stop = y_start + lw; 990 y_step = max*pixelsize; 991 992 /* draw a black pixels for the border if lw > 1 */ 993 if (s) { 994 yblack = y_stop - 1; 995 } else { 996 yblack = y_start; 997 } 998 xblack1 = x0; 999 xblack2 = x1-1; 1000 } 1001 1002 /* now loop over the allowed y's for either case */ 1003 for (yu = y_start; yu < y_stop; yu++) { 1004 if (x0 == x1) { 1005 continue; 1006 } 1007 if (yu < 0 || yu >= dpy_y) { 1008 continue; 1009 } 1010 1011 /* record min and max y's for marking rectangle: */ 1012 if (y_min < 0 || yu < y_min) { 1013 y_min = yu; 1014 } 1015 if (y_max < 0 || yu > y_max) { 1016 y_max = yu; 1017 } 1018 1019 /* save fb data for this line: */ 1020 save[i]->saved = 1; 1021 src = use_fb + yu*use_Bpl + x0*pixelsize; 1022 dst = save[i]->data + (yu-y_start)*y_step; 1023 memcpy(dst, src, (x1-x0)*pixelsize); 1024 1025 /* apply the shade/color to make the wireframe line: */ 1026 if (! color) { 1027 memset(src, shade, (x1-x0)*pixelsize); 1028 } else { 1029 char *csrc = src; 1030 unsigned short *usp; 1031 unsigned long *ulp; 1032 int k; 1033 for (k=0; k < x1 - x0; k++) { 1034 if (pixelsize == 4) { 1035 ulp = (unsigned long *)csrc; 1036 *ulp = ul; 1037 } else if (pixelsize == 2) { 1038 usp = (unsigned short *)csrc; 1039 *usp = us; 1040 } 1041 csrc += pixelsize; 1042 } 1043 } 1044 1045 /* apply black border for lw >= 2 */ 1046 if (lw > 1) { 1047 if (yu == yblack) { 1048 memset(src, 0, (x1-x0)*pixelsize); 1049 } 1050 if (xblack1 >= 0) { 1051 src = src + (xblack1 - x0)*pixelsize; 1052 memset(src, 0, pixelsize); 1053 } 1054 if (xblack2 >= 0) { 1055 src = src + (xblack2 - x0)*pixelsize; 1056 memset(src, 0, pixelsize); 1057 } 1058 } 1059 } 1060 /* mark it for sending: */ 1061 if (save[i]->saved) { 1062 if (0) fprintf(stderr, "Mark-2 %d %d %d %d\n", x0, y_min, x1, y_max+1); 1063 mark_rect_as_modified(x0, y_min, x1, y_max+1, 0); 1064 } 1065 } 1066 } 1067 1068 int direct_fb_copy(int x1, int y1, int x2, int y2, int mark) { 1069 char *src, *dst; 1070 int y, pixelsize = bpp/8; 1071 int xmin = -1, xmax = -1, ymin = -1, ymax = -1; 1072 int do_cmp = 2; 1073 double tm; 1074 int db = 0; 1075 1076 if (db) dtime0(&tm); 1077 1078 x1 = nfix(x1, dpy_x); 1079 y1 = nfix(y1, dpy_y); 1080 x2 = nfix(x2, dpy_x+1); 1081 y2 = nfix(y2, dpy_y+1); 1082 1083 if (x1 == x2) { 1084 return 1; 1085 } 1086 if (y1 == y2) { 1087 return 1; 1088 } 1089 1090 X_LOCK; 1091 for (y = y1; y < y2; y++) { 1092 XRANDR_SET_TRAP_RET(0, "direct_fb_copy-set"); 1093 copy_image(scanline, x1, y, x2 - x1, 1); 1094 XRANDR_CHK_TRAP_RET(0, "direct_fb_copy-chk"); 1095 1096 src = scanline->data; 1097 dst = main_fb + y * main_bytes_per_line + x1 * pixelsize; 1098 1099 if (do_cmp == 0 || !mark) { 1100 memcpy(dst, src, (x2 - x1)*pixelsize); 1101 1102 } else if (do_cmp == 1) { 1103 if (memcmp(dst, src, (x2 - x1)*pixelsize)) { 1104 if (ymin == -1 || y < ymin) { 1105 ymin = y; 1106 } 1107 if (ymax == -1 || y > ymax) { 1108 ymax = y; 1109 } 1110 memcpy(dst, src, (x2 - x1)*pixelsize); 1111 } 1112 1113 } else if (do_cmp == 2) { 1114 int n, shift, xlo, xhi, k, block = 32; 1115 char *dst2, *src2; 1116 1117 for (k=0; k*block < (x2 - x1); k++) { 1118 shift = k*block; 1119 xlo = x1 + shift; 1120 xhi = xlo + block; 1121 if (xhi > x2) { 1122 xhi = x2; 1123 } 1124 n = xhi - xlo; 1125 if (n < 1) { 1126 continue; 1127 } 1128 src2 = src + shift*pixelsize; 1129 dst2 = dst + shift*pixelsize; 1130 if (memcmp(dst2, src2, n*pixelsize)) { 1131 if (ymin == -1 || y < ymin) { 1132 ymin = y; 1133 } 1134 if (ymax == -1 || y > ymax) { 1135 ymax = y; 1136 } 1137 if (xmin == -1 || xlo < xmin) { 1138 xmin = xlo; 1139 } 1140 if (xmax == -1 || xhi > xmax) { 1141 xmax = xhi; 1142 } 1143 memcpy(dst2, src2, n*pixelsize); 1144 } 1145 } 1146 } 1147 } 1148 X_UNLOCK; 1149 1150 if (do_cmp == 0) { 1151 xmin = x1; 1152 ymin = y1; 1153 xmax = x2; 1154 ymax = y2; 1155 } else if (do_cmp == 1) { 1156 xmin = x1; 1157 xmax = x2; 1158 } 1159 1160 if (xmin < 0 || ymin < 0 || xmax < 0 || xmin < 0) { 1161 /* no diffs */ 1162 return 1; 1163 } 1164 1165 if (xmax < x2) { 1166 xmax++; 1167 } 1168 if (ymax < y2) { 1169 ymax++; 1170 } 1171 1172 if (mark) { 1173 mark_rect_as_modified(xmin, ymin, xmax, ymax, 0); 1174 } 1175 1176 if (db) { 1177 fprintf(stderr, "direct_fb_copy: %dx%d+%d+%d - %d %.4f\n", 1178 x2 - x1, y2 - y1, x1, y1, mark, dtime(&tm)); 1179 } 1180 1181 return 1; 1182 } 1183 1184 static int do_bdpush(Window wm_win, int x0, int y0, int w0, int h0, int bdx, 1185 int bdy, int bdskinny) { 1186 1187 XWindowAttributes attr; 1188 sraRectangleIterator *iter; 1189 sraRect rect; 1190 sraRegionPtr frame, whole, tmpregion; 1191 int tx1, ty1, tx2, ty2; 1192 static Window last_wm_win = None; 1193 static int last_x, last_y, last_w, last_h; 1194 int do_fb_push = 0; 1195 int db = debug_scroll; 1196 1197 if (wm_win == last_wm_win) { 1198 attr.x = last_x; 1199 attr.y = last_y; 1200 attr.width = last_w; 1201 attr.height = last_h; 1202 } else { 1203 if (!valid_window(wm_win, &attr, 1)) { 1204 return do_fb_push; 1205 } 1206 last_wm_win = wm_win; 1207 last_x = attr.x; 1208 last_y = attr.y; 1209 last_w = attr.width; 1210 last_h = attr.height; 1211 } 1212 if (db > 1) fprintf(stderr, "BDP %d %d %d %d %d %d %d %d %d %d %d\n", 1213 x0, y0, w0, h0, bdx, bdy, bdskinny, last_x, last_y, last_w, last_h); 1214 1215 /* wm frame: */ 1216 tx1 = attr.x; 1217 ty1 = attr.y; 1218 tx2 = attr.x + attr.width; 1219 ty2 = attr.y + attr.height; 1220 1221 whole = sraRgnCreateRect(0, 0, dpy_x, dpy_y); 1222 if (clipshift) { 1223 sraRgnOffset(whole, coff_x, coff_y); 1224 } 1225 if (subwin) { 1226 sraRgnOffset(whole, off_x, off_y); 1227 } 1228 frame = sraRgnCreateRect(tx1, ty1, tx2, ty2); 1229 sraRgnAnd(frame, whole); 1230 1231 /* scrolling window: */ 1232 tmpregion = sraRgnCreateRect(x0, y0, x0 + w0, y0 + h0); 1233 sraRgnAnd(tmpregion, whole); 1234 1235 sraRgnSubtract(frame, tmpregion); 1236 sraRgnDestroy(tmpregion); 1237 1238 if (!sraRgnEmpty(frame)) { 1239 double dt = 0.0, dm; 1240 dtime0(&dm); 1241 iter = sraRgnGetIterator(frame); 1242 while (sraRgnIteratorNext(iter, &rect)) { 1243 tx1 = rect.x1; 1244 ty1 = rect.y1; 1245 tx2 = rect.x2; 1246 ty2 = rect.y2; 1247 1248 if (bdskinny > 0) { 1249 int ok = 0; 1250 if (nabs(ty2-ty1) <= bdskinny) { 1251 ok = 1; 1252 } 1253 if (nabs(tx2-tx1) <= bdskinny) { 1254 ok = 1; 1255 } 1256 if (! ok) { 1257 continue; 1258 } 1259 } 1260 1261 if (bdx >= 0) { 1262 if (bdx < tx1 || tx2 <= bdx) { 1263 continue; 1264 } 1265 } 1266 if (bdy >= 0) { 1267 if (bdy < ty1 || ty2 <= bdy) { 1268 continue; 1269 } 1270 } 1271 if (clipshift) { 1272 tx1 -= coff_x; 1273 ty1 -= coff_y; 1274 tx2 -= coff_x; 1275 ty2 -= coff_y; 1276 } 1277 if (subwin) { 1278 tx1 -= off_x; 1279 ty1 -= off_y; 1280 tx2 -= off_x; 1281 ty2 -= off_y; 1282 } 1283 1284 direct_fb_copy(tx1, ty1, tx2, ty2, 1); 1285 1286 do_fb_push++; 1287 dt += dtime(&dm); 1288 if (db > 1) fprintf(stderr, " BDP(%d,%d-%d,%d) dt: %.4f\n", tx1, ty1, tx2, ty2, dt); 1289 } 1290 sraRgnReleaseIterator(iter); 1291 } 1292 sraRgnDestroy(whole); 1293 sraRgnDestroy(frame); 1294 1295 return do_fb_push; 1296 } 1297 1298 static int set_ypad(void) { 1299 int ev, ev_tot = scr_ev_cnt; 1300 static Window last_win = None; 1301 static double last_time = 0.0; 1302 static int y_accum = 0, last_sign = 0; 1303 double now, cut = 0.1; 1304 int dy_sum = 0, ys = 0, sign; 1305 int font_size = 15; 1306 int win_y, scr_y, loc_cut = 4*font_size, y_cut = 10*font_size; 1307 1308 if (!xrecord_set_by_keys || !xrecord_name_info) { 1309 return 0; 1310 } 1311 if (xrecord_name_info[0] == '\0') { 1312 return 0; 1313 } 1314 if (! ev_tot) { 1315 return 0; 1316 } 1317 if (xrecord_keysym == NoSymbol) { 1318 return 0; 1319 } 1320 if (!xrecord_scroll_keysym(xrecord_keysym)) { 1321 return 0; 1322 } 1323 if (!scroll_term) { 1324 return 0; 1325 } 1326 if (!match_str_list(xrecord_name_info, scroll_term)) { 1327 return 0; 1328 } 1329 1330 for (ev=0; ev < ev_tot; ev++) { 1331 dy_sum += nabs(scr_ev[ev].dy); 1332 if (scr_ev[ev].dy < 0) { 1333 ys--; 1334 } else if (scr_ev[ev].dy > 0) { 1335 ys++; 1336 } else { 1337 ys = 0; 1338 break; 1339 } 1340 if (scr_ev[ev].win != scr_ev[0].win) { 1341 ys = 0; 1342 break; 1343 } 1344 if (scr_ev[ev].dx != 0) { 1345 ys = 0; 1346 break; 1347 } 1348 } 1349 if (ys != ev_tot && ys != -ev_tot) { 1350 return 0; 1351 } 1352 if (ys < 0) { 1353 sign = -1; 1354 } else { 1355 sign = 1; 1356 } 1357 1358 if (sign > 0) { 1359 /* 1360 * this case is not as useful as scrolling near the 1361 * bottom of a terminal. But there are problems for it too. 1362 */ 1363 return 0; 1364 } 1365 1366 win_y = scr_ev[0].win_y + scr_ev[0].win_h; 1367 scr_y = scr_ev[0].y + scr_ev[0].h; 1368 if (nabs(scr_y - win_y) > loc_cut) { 1369 /* require it to be near the bottom. */ 1370 return 0; 1371 } 1372 1373 now = dnow(); 1374 1375 if (now < last_time + cut) { 1376 int ok = 1; 1377 if (last_win && scr_ev[0].win != last_win) { 1378 ok = 0; 1379 } 1380 if (last_sign && sign != last_sign) { 1381 ok = 0; 1382 } 1383 if (! ok) { 1384 last_win = None; 1385 last_sign = 0; 1386 y_accum = 0; 1387 last_time = 0.0; 1388 return 0; 1389 } 1390 } else { 1391 last_win = None; 1392 last_sign = 0; 1393 last_time = 0.0; 1394 y_accum = 0; 1395 } 1396 1397 y_accum += sign * dy_sum; 1398 1399 if (4 * nabs(y_accum) > scr_ev[0].h && y_cut) { 1400 ; /* TBD */ 1401 } 1402 1403 last_sign = sign; 1404 last_win = scr_ev[0].win; 1405 last_time = now; 1406 1407 return y_accum; 1408 } 1409 1410 static void scale_mark(int x1, int y1, int x2, int y2, int mark) { 1411 int s = 2; 1412 x1 = nfix(x1 - s, dpy_x); 1413 y1 = nfix(y1 - s, dpy_y); 1414 x2 = nfix(x2 + s, dpy_x+1); 1415 y2 = nfix(y2 + s, dpy_y+1); 1416 scale_and_mark_rect(x1, y1, x2, y2, mark); 1417 } 1418 1419 #define PUSH_TEST(n) \ 1420 if (n) { \ 1421 double dt = 0.0, tm; dtime0(&tm); \ 1422 fprintf(stderr, "PUSH---\n"); \ 1423 while (dt < 2.0) { rfbPE(50000); dt += dtime(&tm); } \ 1424 fprintf(stderr, "---PUSH\n"); \ 1425 } 1426 1427 int batch_dxs[], batch_dys[]; 1428 sraRegionPtr batch_reg[]; 1429 void batch_push(int ncr, double delay); 1430 1431 static int push_scr_ev(double *age, int type, int bdpush, int bdx, int bdy, 1432 int bdskinny, int first_push) { 1433 Window frame, win, win0; 1434 int x, y, w, h, wx, wy, ww, wh, dx, dy; 1435 int x0, y0, w0, h0; 1436 int nx, ny, nw, nh; 1437 int dret = 1, do_fb_push = 0, obscured; 1438 int ev, ev_tot = scr_ev_cnt; 1439 double tm, dt, st, waittime = 0.125; 1440 double max_age = *age; 1441 int db = debug_scroll, rrate = get_read_rate(); 1442 sraRegionPtr backfill, whole, tmpregion, tmpregion2; 1443 int link, latency, netrate; 1444 int ypad = 0; 1445 double last_scroll_event_save = last_scroll_event; 1446 int fast_push = 0, rc; 1447 1448 /* we return the oldest one. */ 1449 *age = 0.0; 1450 1451 if (ev_tot == 0) { 1452 return dret; 1453 } 1454 1455 link = link_rate(&latency, &netrate); 1456 1457 if (link == LR_DIALUP) { 1458 waittime *= 5; 1459 } else if (link == LR_BROADBAND) { 1460 waittime *= 3; 1461 } else if (latency > 80 || netrate < 40) { 1462 waittime *= 3; 1463 } 1464 1465 backfill = sraRgnCreate(); 1466 whole = sraRgnCreateRect(0, 0, dpy_x, dpy_y); 1467 if (clipshift) { 1468 sraRgnOffset(whole, coff_x, coff_y); 1469 } 1470 if (subwin) { 1471 sraRgnOffset(whole, off_x, off_y); 1472 } 1473 1474 win0 = scr_ev[0].win; 1475 x0 = scr_ev[0].win_x; 1476 y0 = scr_ev[0].win_y; 1477 w0 = scr_ev[0].win_w; 1478 h0 = scr_ev[0].win_h; 1479 1480 ypad = set_ypad(); 1481 1482 if (db) fprintf(stderr, "ypad: %d dy[0]: %d ev_tot: %d\n", ypad, scr_ev[0].dy, ev_tot); 1483 1484 for (ev=0; ev < ev_tot; ev++) { 1485 double ag; 1486 1487 x = scr_ev[ev].x; 1488 y = scr_ev[ev].y; 1489 w = scr_ev[ev].w; 1490 h = scr_ev[ev].h; 1491 dx = scr_ev[ev].dx; 1492 dy = scr_ev[ev].dy; 1493 win = scr_ev[ev].win; 1494 wx = scr_ev[ev].win_x; 1495 wy = scr_ev[ev].win_y; 1496 ww = scr_ev[ev].win_w; 1497 wh = scr_ev[ev].win_h; 1498 nx = scr_ev[ev].new_x; 1499 ny = scr_ev[ev].new_y; 1500 nw = scr_ev[ev].new_w; 1501 nh = scr_ev[ev].new_h; 1502 st = scr_ev[ev].t; 1503 1504 ag = (dnow() - servertime_diff) - st; 1505 if (ag > *age) { 1506 *age = ag; 1507 } 1508 1509 if (dabs(ag) > max_age) { 1510 if (db) fprintf(stderr, "push_scr_ev: TOO OLD: %.4f :: (%.4f - %.4f) " 1511 "- %.4f \n", ag, dnow(), servertime_diff, st); 1512 dret = 0; 1513 break; 1514 } else { 1515 if (db) fprintf(stderr, "push_scr_ev: AGE: %.4f\n", ag); 1516 } 1517 if (win != win0) { 1518 if (db) fprintf(stderr, "push_scr_ev: DIFF WIN: 0x%lx != 0x%lx\n", win, win0); 1519 dret = 0; 1520 break; 1521 } 1522 if (wx != x0 || wy != y0) { 1523 if (db) fprintf(stderr, "push_scr_ev: WIN SHIFT: %d %d, %d %d", wx, x0, wy, y0); 1524 dret = 0; 1525 break; 1526 } 1527 if (ww != w0 || wh != h0) { 1528 if (db) fprintf(stderr, "push_scr_ev: WIN RESIZE: %d %d, %d %d", ww, w0, wh, h0); 1529 dret = 0; 1530 break; 1531 } 1532 if (w < 1 || h < 1 || ww < 1 || wh < 1) { 1533 if (db) fprintf(stderr, "push_scr_ev: NEGATIVE h/w: %d %d %d %d\n", w, h, ww, wh); 1534 dret = 0; 1535 break; 1536 } 1537 1538 if (db > 1) fprintf(stderr, "push_scr_ev: got: %d x: %4d y: %3d" 1539 " w: %4d h: %3d dx: %d dy: %d %dx%d+%d+%d win: 0x%lx\n", 1540 ev, x, y, w, h, dx, dy, w, h, x, y, win); 1541 1542 if (db > 1) fprintf(stderr, "------------ got: %d x: %4d y: %3d" 1543 " w: %4d h: %3d %dx%d+%d+%d\n", 1544 ev, wx, wy, ww, wh, ww, wh, wx, wy); 1545 1546 if (db > 1) fprintf(stderr, "------------ got: %d x: %4d y: %3d" 1547 " w: %4d h: %3d %dx%d+%d+%d\n", 1548 ev, nx, ny, nw, nh, nw, nh, nx, ny); 1549 1550 frame = None; 1551 if (xrecord_wm_window) { 1552 frame = xrecord_wm_window; 1553 } 1554 if (! frame) { 1555 X_LOCK; 1556 frame = query_pointer(rootwin); 1557 X_UNLOCK; 1558 } 1559 if (! frame) { 1560 frame = win; 1561 } 1562 1563 dtime0(&tm); 1564 1565 tmpregion = sraRgnCreateRect(0, 0, dpy_x, dpy_y); 1566 if (clipshift) { 1567 sraRgnOffset(tmpregion, coff_x, coff_y); 1568 } 1569 if (subwin) { 1570 sraRgnOffset(tmpregion, off_x, off_y); 1571 } 1572 tmpregion2 = sraRgnCreateRect(wx, wy, wx+ww, wy+wh); 1573 sraRgnAnd(tmpregion2, whole); 1574 sraRgnSubtract(tmpregion, tmpregion2); 1575 sraRgnDestroy(tmpregion2); 1576 1577 /* do the wm frame just incase the above is bogus too. */ 1578 if (frame && frame != win) { 1579 int k, gotk = -1; 1580 for (k = stack_list_num - 1; k >= 0; k--) { 1581 if (stack_list[k].win == frame && 1582 stack_list[k].fetched && 1583 stack_list[k].valid && 1584 stack_list[k].map_state == IsViewable) { 1585 gotk = k; 1586 break; 1587 } 1588 } 1589 if (gotk != -1) { 1590 int tx1, ty1, tx2, ty2; 1591 tx1 = stack_list[gotk].x; 1592 ty1 = stack_list[gotk].y; 1593 tx2 = tx1 + stack_list[gotk].width; 1594 ty2 = ty1 + stack_list[gotk].height; 1595 tmpregion2 = sraRgnCreateRect(tx1,ty1,tx2,ty2); 1596 sraRgnAnd(tmpregion2, whole); 1597 sraRgnSubtract(tmpregion, tmpregion2); 1598 sraRgnDestroy(tmpregion2); 1599 } 1600 } 1601 1602 /* 1603 * XXX Need to also clip: 1604 * children of win 1605 * siblings of win higher in stacking order. 1606 * ignore for now... probably will make some apps 1607 * act very strangely. 1608 */ 1609 if (ypad) { 1610 if (ypad < 0) { 1611 if (h > -ypad) { 1612 h += ypad; 1613 } else { 1614 ypad = 0; 1615 } 1616 } else { 1617 if (h > ypad) { 1618 y += ypad; 1619 } else { 1620 ypad = 0; 1621 } 1622 } 1623 } 1624 1625 if (fast_push) { 1626 int nbatch = 0; 1627 double delay, d1 = 0.1, d2 = 0.02; 1628 rc = try_copyrect(frame, frame, x, y, w, h, dx, dy, &obscured, 1629 tmpregion, waittime, &nbatch); 1630 1631 if (first_push) { 1632 delay = d1; 1633 } else { 1634 delay = d2; 1635 } 1636 1637 batch_push(nbatch, delay); 1638 fb_push(); 1639 } else { 1640 rc = try_copyrect(frame, frame, x, y, w, h, dx, dy, &obscured, 1641 tmpregion, waittime, NULL); 1642 if (rc) { 1643 last_scroll_type = type; 1644 dtime0(&last_scroll_event); 1645 1646 do_fb_push++; 1647 urgent_update = 1; 1648 sraRgnDestroy(tmpregion); 1649 PUSH_TEST(0); 1650 } 1651 } 1652 1653 if (! rc) { 1654 dret = 0; 1655 sraRgnDestroy(tmpregion); 1656 break; 1657 } 1658 dt = dtime(&tm); 1659 if (0) fprintf(stderr, " try_copyrect dt: %.4f\n", dt); 1660 1661 if (ev > 0) { 1662 sraRgnOffset(backfill, dx, dy); 1663 sraRgnAnd(backfill, whole); 1664 } 1665 1666 if (ypad) { 1667 if (ypad < 0) { 1668 ny += ypad; 1669 nh -= ypad; 1670 } else { 1671 ; 1672 } 1673 } 1674 1675 tmpregion = sraRgnCreateRect(nx, ny, nx + nw, ny + nh); 1676 sraRgnAnd(tmpregion, whole); 1677 sraRgnOr(backfill, tmpregion); 1678 sraRgnDestroy(tmpregion); 1679 } 1680 1681 /* try to update the backfill region (new window contents) */ 1682 if (dret != 0) { 1683 double est, win_area = 0.0, area = 0.0; 1684 sraRectangleIterator *iter; 1685 sraRect rect; 1686 int tx1, ty1, tx2, ty2; 1687 1688 tmpregion = sraRgnCreateRect(x0, y0, x0 + w0, y0 + h0); 1689 sraRgnAnd(tmpregion, whole); 1690 1691 sraRgnAnd(backfill, tmpregion); 1692 1693 iter = sraRgnGetIterator(tmpregion); 1694 while (sraRgnIteratorNext(iter, &rect)) { 1695 tx1 = rect.x1; 1696 ty1 = rect.y1; 1697 tx2 = rect.x2; 1698 ty2 = rect.y2; 1699 1700 win_area += (tx2 - tx1)*(ty2 - ty1); 1701 } 1702 sraRgnReleaseIterator(iter); 1703 1704 sraRgnDestroy(tmpregion); 1705 1706 1707 iter = sraRgnGetIterator(backfill); 1708 while (sraRgnIteratorNext(iter, &rect)) { 1709 tx1 = rect.x1; 1710 ty1 = rect.y1; 1711 tx2 = rect.x2; 1712 ty2 = rect.y2; 1713 1714 area += (tx2 - tx1)*(ty2 - ty1); 1715 } 1716 sraRgnReleaseIterator(iter); 1717 1718 est = (area * (bpp/8)) / (1000000.0 * rrate); 1719 if (db) fprintf(stderr, " area %.1f win_area %.1f est: %.4f", area, win_area, est); 1720 if (area > 0.90 * win_area) { 1721 if (db) fprintf(stderr, " AREA_TOO_MUCH"); 1722 dret = 0; 1723 } else if (est > 0.6) { 1724 if (db) fprintf(stderr, " EST_TOO_LARGE"); 1725 dret = 0; 1726 } else if (area <= 0.0) { 1727 ; 1728 } else { 1729 dtime0(&tm); 1730 iter = sraRgnGetIterator(backfill); 1731 while (sraRgnIteratorNext(iter, &rect)) { 1732 tx1 = rect.x1; 1733 ty1 = rect.y1; 1734 tx2 = rect.x2; 1735 ty2 = rect.y2; 1736 1737 if (clipshift) { 1738 tx1 -= coff_x; 1739 ty1 -= coff_y; 1740 tx2 -= coff_x; 1741 ty2 -= coff_y; 1742 } 1743 if (subwin) { 1744 tx1 -= off_x; 1745 ty1 -= off_y; 1746 tx2 -= off_x; 1747 ty2 -= off_y; 1748 } 1749 tx1 = nfix(tx1, dpy_x); 1750 ty1 = nfix(ty1, dpy_y); 1751 tx2 = nfix(tx2, dpy_x+1); 1752 ty2 = nfix(ty2, dpy_y+1); 1753 1754 dtime(&tm); 1755 if (db) fprintf(stderr, " DFC(%d,%d-%d,%d)", tx1, ty1, tx2, ty2); 1756 direct_fb_copy(tx1, ty1, tx2, ty2, 1); 1757 if (fast_push) { 1758 fb_push(); 1759 } 1760 do_fb_push++; 1761 PUSH_TEST(0); 1762 } 1763 sraRgnReleaseIterator(iter); 1764 1765 dt = dtime(&tm); 1766 if (db) fprintf(stderr, " dfc---- dt: %.4f", dt); 1767 1768 } 1769 if (db && dret) fprintf(stderr, " **** dret=%d", dret); 1770 if (db && !dret) fprintf(stderr, " ---- dret=%d", dret); 1771 if (db) fprintf(stderr, "\n"); 1772 } 1773 1774 if (db && bdpush) fprintf(stderr, "BDPUSH-TIME: 0x%lx\n", xrecord_wm_window); 1775 1776 if (bdpush && xrecord_wm_window != None) { 1777 int x, y, w, h; 1778 x = scr_ev[0].x; 1779 y = scr_ev[0].y; 1780 w = scr_ev[0].w; 1781 h = scr_ev[0].h; 1782 do_fb_push += do_bdpush(xrecord_wm_window, x, y, w, h, 1783 bdx, bdy, bdskinny); 1784 if (fast_push) { 1785 fb_push(); 1786 } 1787 } 1788 1789 if (do_fb_push) { 1790 dtime0(&tm); 1791 fb_push(); 1792 dt = dtime(&tm); 1793 if (0) fprintf(stderr, " fb_push dt: %.4f", dt); 1794 if (scaling) { 1795 static double last_time = 0.0; 1796 double now = dnow(), delay = 0.4, first_wait = 3.0; 1797 double trate; 1798 int repeating, lat, rate; 1799 int link = link_rate(&lat, &rate); 1800 int skip_first = 0; 1801 1802 if (link == LR_DIALUP || rate < 35) { 1803 delay *= 4; 1804 } else if (link != LR_LAN || rate < 100) { 1805 delay *= 2; 1806 } 1807 1808 trate = typing_rate(0.0, &repeating); 1809 1810 if (xrecord_set_by_mouse || repeating >= 3) { 1811 if (now > last_scroll_event_save + first_wait) { 1812 skip_first = 1; 1813 } 1814 } 1815 1816 if (skip_first) { 1817 /* 1818 * try not to send the first one, but a 1819 * single keystroke scroll would be OK. 1820 */ 1821 } else if (now > last_time + delay) { 1822 1823 scale_mark(x0, y0, x0 + w0, y0 + h0, 1); 1824 last_copyrect_fix = now; 1825 } 1826 last_time = now; 1827 } 1828 } 1829 1830 sraRgnDestroy(backfill); 1831 sraRgnDestroy(whole); 1832 return dret; 1833 } 1834 1835 static void get_client_regions(int *req, int *mod, int *cpy, int *num) { 1836 1837 rfbClientIteratorPtr i; 1838 rfbClientPtr cl; 1839 1840 *req = 0; 1841 *mod = 0; 1842 *cpy = 0; 1843 *num = 0; 1844 1845 i = rfbGetClientIterator(screen); 1846 while( (cl = rfbClientIteratorNext(i)) ) { 1847 if (use_threads) LOCK(cl->updateMutex); 1848 *req += sraRgnCountRects(cl->requestedRegion); 1849 *mod += sraRgnCountRects(cl->modifiedRegion); 1850 *cpy += sraRgnCountRects(cl->copyRegion); 1851 *num += 1; 1852 if (use_threads) UNLOCK(cl->updateMutex); 1853 } 1854 rfbReleaseClientIterator(i); 1855 } 1856 1857 /* 1858 * Wrapper to apply the rfbDoCopyRegion taking into account if scaling 1859 * is being done. Note that copyrect under the scaling case is often 1860 * only approximate. 1861 */ 1862 int DCR_Normal = 0; 1863 int DCR_FBOnly = 1; 1864 int DCR_Direct = 2; 1865 1866 void do_copyregion(sraRegionPtr region, int dx, int dy, int mode) { 1867 sraRectangleIterator *iter; 1868 sraRect rect; 1869 int Bpp0 = bpp/8, Bpp; 1870 int x1, y1, x2, y2, w, stride, stride0; 1871 int sx1, sy1, sx2, sy2, sdx, sdy; 1872 int req, mod, cpy, ncli; 1873 char *dst = NULL, *src = NULL; 1874 1875 last_copyrect = dnow(); 1876 1877 if (rfb_fb == main_fb && ! rotating && mode == DCR_Normal) { 1878 /* normal case, no -scale or -8to24 */ 1879 get_client_regions(&req, &mod, &cpy, &ncli); 1880 if (0 || debug_scroll > 1) fprintf(stderr, ">>>-rfbDoCopyRect req: %d mod: %d cpy: %d\n", req, mod, cpy); 1881 1882 rfbDoCopyRegion(screen, region, dx, dy); 1883 1884 get_client_regions(&req, &mod, &cpy, &ncli); 1885 if (0 || debug_scroll > 1) fprintf(stderr, "<<<-rfbDoCopyRect req: %d mod: %d cpy: %d\n", req, mod, cpy); 1886 1887 return; 1888 } 1889 1890 /* rarer case, we need to call rfbDoCopyRect with scaled xy */ 1891 stride0 = dpy_x * Bpp0; 1892 1893 iter = sraRgnGetReverseIterator(region, dx < 0, dy < 0); 1894 while(sraRgnIteratorNext(iter, &rect)) { 1895 int j, c, t; 1896 1897 x1 = rect.x1; 1898 y1 = rect.y1; 1899 x2 = rect.x2; 1900 y2 = rect.y2; 1901 1902 for (c= 0; c < 2; c++) { 1903 1904 Bpp = Bpp0; 1905 stride = stride0; 1906 1907 if (c == 0) { 1908 dst = main_fb + y1*stride + x1*Bpp; 1909 src = main_fb + (y1-dy)*stride + (x1-dx)*Bpp; 1910 1911 } else if (c == 1) { 1912 if (!cmap8to24 || !cmap8to24_fb) { 1913 continue; 1914 } 1915 if (cmap8to24_fb == rfb_fb) { 1916 if (mode == DCR_FBOnly) { 1917 ; 1918 } else if (mode == DCR_Direct) { 1919 ; 1920 } else if (mode == DCR_Normal) { 1921 continue; 1922 } 1923 } 1924 if (0) fprintf(stderr, "copyrect: cmap8to24_fb: mode=%d\n", mode); 1925 if (cmap8to24) { 1926 if (depth <= 8) { 1927 Bpp = 4 * Bpp0; 1928 stride = 4 * stride0; 1929 } else if (depth <= 16) { 1930 Bpp = 2 * Bpp0; 1931 stride = 2 * stride0; 1932 } 1933 } 1934 dst = cmap8to24_fb + y1*stride + x1*Bpp; 1935 src = cmap8to24_fb + (y1-dy)*stride + (x1-dx)*Bpp; 1936 } 1937 1938 w = (x2 - x1)*Bpp; 1939 1940 if (dy < 0) { 1941 for (j=y1; j<y2; j++) { 1942 memmove(dst, src, w); 1943 dst += stride; 1944 src += stride; 1945 } 1946 } else { 1947 dst += (y2 - y1 - 1)*stride; 1948 src += (y2 - y1 - 1)*stride; 1949 for (j=y2-1; j>=y1; j--) { 1950 memmove(dst, src, w); 1951 dst -= stride; 1952 src -= stride; 1953 } 1954 } 1955 } 1956 1957 if (mode == DCR_FBOnly) { 1958 continue; 1959 } 1960 1961 1962 if (scaling) { 1963 sx1 = ((double) x1 / dpy_x) * scaled_x; 1964 sy1 = ((double) y1 / dpy_y) * scaled_y; 1965 sx2 = ((double) x2 / dpy_x) * scaled_x; 1966 sy2 = ((double) y2 / dpy_y) * scaled_y; 1967 sdx = ((double) dx / dpy_x) * scaled_x; 1968 sdy = ((double) dy / dpy_y) * scaled_y; 1969 } else { 1970 sx1 = x1; 1971 sy1 = y1; 1972 sx2 = x2; 1973 sy2 = y2; 1974 sdx = dx; 1975 sdy = dy; 1976 } 1977 if (0) fprintf(stderr, "sa.. %d %d %d %d %d %d\n", sx1, sy1, sx2, sy2, sdx, sdy); 1978 1979 if (rotating) { 1980 rotate_coords(sx1, sy1, &sx1, &sy1, -1, -1); 1981 rotate_coords(sx2, sy2, &sx2, &sy2, -1, -1); 1982 if (rotating == ROTATE_X) { 1983 sdx = -sdx; 1984 } else if (rotating == ROTATE_Y) { 1985 sdy = -sdy; 1986 } else if (rotating == ROTATE_XY) { 1987 sdx = -sdx; 1988 sdy = -sdy; 1989 } else if (rotating == ROTATE_90) { 1990 t = sdx; 1991 sdx = -sdy; 1992 sdy = t; 1993 } else if (rotating == ROTATE_90X) { 1994 t = sdx; 1995 sdx = sdy; 1996 sdy = t; 1997 } else if (rotating == ROTATE_90Y) { 1998 t = sdx; 1999 sdx = -sdy; 2000 sdy = -t; 2001 } else if (rotating == ROTATE_270) { 2002 t = sdx; 2003 sdx = sdy; 2004 sdy = -t; 2005 } 2006 } 2007 2008 /* XXX -1? */ 2009 if (sx2 < 0) sx2 = 0; 2010 if (sy2 < 0) sy2 = 0; 2011 2012 if (sx2 < sx1) { 2013 t = sx1; 2014 sx1 = sx2; 2015 sx2 = t; 2016 } 2017 if (sy2 < sy1) { 2018 t = sy1; 2019 sy1 = sy2; 2020 sy2 = t; 2021 } 2022 if (0) fprintf(stderr, "sb.. %d %d %d %d %d %d\n", sx1, sy1, sx2, sy2, sdx, sdy); 2023 2024 if (mode == DCR_Direct) { 2025 rfbClientIteratorPtr i; 2026 rfbClientPtr cl; 2027 sraRegionPtr r = sraRgnCreateRect(sx1, sy1, sx2, sy2); 2028 2029 i = rfbGetClientIterator(screen); 2030 while( (cl = rfbClientIteratorNext(i)) ) { 2031 if (use_threads) LOCK(cl->updateMutex); 2032 rfbSendCopyRegion(cl, r, sdx, sdy); 2033 if (use_threads) UNLOCK(cl->updateMutex); 2034 } 2035 rfbReleaseClientIterator(i); 2036 sraRgnDestroy(r); 2037 2038 } else { 2039 rfbDoCopyRect(screen, sx1, sy1, sx2, sy2, sdx, sdy); 2040 } 2041 } 2042 sraRgnReleaseIterator(iter); 2043 } 2044 2045 void batch_copyregion(sraRegionPtr* region, int *dx, int *dy, int ncr, double delay) { 2046 rfbClientIteratorPtr i; 2047 rfbClientPtr cl; 2048 int k, direct, mode, nrects = 0, bad = 0; 2049 double t1, t2, start = dnow(); 2050 2051 for (k=0; k < ncr; k++) { 2052 sraRectangleIterator *iter; 2053 sraRect rect; 2054 2055 iter = sraRgnGetIterator(region[k]); 2056 while (sraRgnIteratorNext(iter, &rect)) { 2057 int x1 = rect.x1; 2058 int y1 = rect.y1; 2059 int x2 = rect.x2; 2060 int y2 = rect.y2; 2061 int ym = dpy_y * (ncache+1); 2062 int xm = dpy_x; 2063 if (x1 > xm || y1 > ym || x2 > xm || y2 > ym) { 2064 if (ncdb) fprintf(stderr, "batch_copyregion: BAD RECTANGLE: %d,%d %d,%d\n", x1, y1, x2, y2); 2065 bad = 1; 2066 } 2067 if (x1 < 0 || y1 < 0 || x2 < 0 || y2 < 0) { 2068 if (ncdb) fprintf(stderr, "batch_copyregion: BAD RECTANGLE: %d,%d %d,%d\n", x1, y1, x2, y2); 2069 bad = 1; 2070 } 2071 } 2072 sraRgnReleaseIterator(iter); 2073 nrects += sraRgnCountRects(region[k]); 2074 } 2075 if (bad || nrects == 0) { 2076 return; 2077 } 2078 2079 if (delay < 0.0) { 2080 delay = 0.1; 2081 } 2082 if (!fb_push_wait(delay, FB_COPY|FB_MOD)) { 2083 if (use_threads) usleep(100 * 1000); 2084 fb_push_wait(0.75, FB_COPY|FB_MOD); 2085 } 2086 2087 t1 = dnow(); 2088 2089 bad = 0; 2090 i = rfbGetClientIterator(screen); 2091 while( (cl = rfbClientIteratorNext(i)) ) { 2092 2093 if (use_threads) LOCK(cl->updateMutex); 2094 2095 if (cl->ublen != 0) { 2096 fprintf(stderr, "batch_copyregion: *** BAD ublen != 0: %d\n", cl->ublen); 2097 bad++; 2098 } 2099 2100 if (use_threads) UNLOCK(cl->updateMutex); 2101 } 2102 rfbReleaseClientIterator(i); 2103 2104 if (bad) { 2105 return; 2106 } 2107 2108 i = rfbGetClientIterator(screen); 2109 while( (cl = rfbClientIteratorNext(i)) ) { 2110 rfbFramebufferUpdateMsg *fu; 2111 2112 if (use_threads) LOCK(cl->updateMutex); 2113 2114 fu = (rfbFramebufferUpdateMsg *)cl->updateBuf; 2115 fu->nRects = Swap16IfLE((uint16_t)(nrects)); 2116 fu->type = rfbFramebufferUpdate; 2117 2118 if (cl->ublen != 0) fprintf(stderr, "batch_copyregion: *** BAD-2 ublen != 0: %d\n", cl->ublen); 2119 2120 cl->ublen = sz_rfbFramebufferUpdateMsg; 2121 2122 if (use_threads) UNLOCK(cl->updateMutex); 2123 } 2124 rfbReleaseClientIterator(i); 2125 2126 if (rfb_fb == main_fb && !rotating) { 2127 direct = 0; 2128 mode = DCR_FBOnly; 2129 } else { 2130 direct = 1; 2131 mode = DCR_Direct; 2132 } 2133 for (k=0; k < ncr; k++) { 2134 do_copyregion(region[k], dx[k], dy[k], mode); 2135 } 2136 2137 t2 = dnow(); 2138 2139 i = rfbGetClientIterator(screen); 2140 while( (cl = rfbClientIteratorNext(i)) ) { 2141 2142 if (use_threads) LOCK(cl->updateMutex); 2143 2144 if (!direct) { 2145 for (k=0; k < ncr; k++) { 2146 rfbSendCopyRegion(cl, region[k], dx[k], dy[k]); 2147 } 2148 } 2149 rfbSendUpdateBuf(cl); 2150 2151 if (use_threads) UNLOCK(cl->updateMutex); 2152 } 2153 rfbReleaseClientIterator(i); 2154 2155 last_copyrect = dnow(); 2156 2157 if (0) fprintf(stderr, "batch_copyregion: nrects: %d nregions: %d tot=%.4f t10=%.4f t21=%.4f t32=%.4f %.4f\n", 2158 nrects, ncr, last_copyrect - start, t1 - start, t2 - t1, last_copyrect - t2, dnowx()); 2159 2160 } 2161 2162 void batch_push(int nreg, double delay) { 2163 int k; 2164 batch_copyregion(batch_reg, batch_dxs, batch_dys, nreg, delay); 2165 /* XXX Y */ 2166 fb_push(); 2167 for (k=0; k < nreg; k++) { 2168 sraRgnDestroy(batch_reg[k]); 2169 } 2170 } 2171 2172 void fb_push(void) { 2173 int req0, mod0, cpy0, req1, mod1, cpy1, ncli; 2174 int db = (debug_scroll || debug_wireframe); 2175 rfbClientIteratorPtr i; 2176 rfbClientPtr cl; 2177 2178 if (use_threads) { 2179 return; 2180 } 2181 2182 if (db) get_client_regions(&req0, &mod0, &cpy0, &ncli); 2183 2184 i = rfbGetClientIterator(screen); 2185 while( (cl = rfbClientIteratorNext(i)) ) { 2186 if (use_threads) LOCK(cl->updateMutex); 2187 if (cl->sock >= 0 && !cl->onHold && FB_UPDATE_PENDING(cl) && 2188 !sraRgnEmpty(cl->requestedRegion)) { 2189 if (!rfbSendFramebufferUpdate(cl, cl->modifiedRegion)) { 2190 fprintf(stderr, "*** rfbSendFramebufferUpdate *FAILED* #1\n"); 2191 if (cl->ublen) fprintf(stderr, "*** fb_push ublen not zero: %d\n", cl->ublen); 2192 if (use_threads) UNLOCK(cl->updateMutex); 2193 break; 2194 } 2195 if (cl->ublen) fprintf(stderr, "*** fb_push ublen NOT ZERO: %d\n", cl->ublen); 2196 } 2197 if (use_threads) UNLOCK(cl->updateMutex); 2198 } 2199 rfbReleaseClientIterator(i); 2200 2201 if (db) { 2202 get_client_regions(&req1, &mod1, &cpy1, &ncli); 2203 fprintf(stderr, "\nFB_push: req: %d/%d mod: %d/%d cpy: %d/%d %.4f\n", 2204 req0, req1, mod0, mod1, cpy0, cpy1, dnowx()); 2205 } 2206 2207 } 2208 2209 int fb_push_wait(double max_wait, int flags) { 2210 double tm, dt = 0.0; 2211 int req, mod, cpy, ncli; 2212 int ok = 0, first = 1; 2213 2214 dtime0(&tm); 2215 while (dt < max_wait) { 2216 int done = 1; 2217 fb_push(); 2218 get_client_regions(&req, &mod, &cpy, &ncli); 2219 if (flags & FB_COPY && cpy) { 2220 done = 0; 2221 } 2222 if (flags & FB_MOD && mod) { 2223 done = 0; 2224 } 2225 if (flags & FB_REQ && req) { 2226 done = 0; 2227 } 2228 if (done) { 2229 ok = 1; 2230 break; 2231 } 2232 if (first) { 2233 first = 0; 2234 continue; 2235 } 2236 2237 rfbCFD(0); 2238 usleep(1000); 2239 dt += dtime(&tm); 2240 } 2241 return ok; 2242 } 2243 2244 /* 2245 * utility routine for CopyRect of the window (but not CopyRegion) 2246 */ 2247 static int crfix(int x, int dx, int Lx) { 2248 /* adjust x so that copy source is on screen */ 2249 if (dx > 0) { 2250 if (x-dx < 0) { 2251 /* off on the left */ 2252 x = dx; 2253 } 2254 } else { 2255 if (x-dx >= Lx) { 2256 /* off on the right */ 2257 x = Lx + dx - 1; 2258 } 2259 } 2260 return x; 2261 } 2262 2263 typedef struct scroll_result { 2264 Window win; 2265 double time; 2266 int result; 2267 } scroll_result_t; 2268 2269 #define SCR_RESULTS_MAX 256 2270 static scroll_result_t scroll_results[SCR_RESULTS_MAX]; 2271 2272 static int scrollability(Window win, int set) { 2273 double oldest = -1.0; 2274 int i, index = -1, next_index = -1; 2275 static int first = 1; 2276 2277 if (first) { 2278 for (i=0; i<SCR_RESULTS_MAX; i++) { 2279 scroll_results[i].win = None; 2280 scroll_results[i].time = 0.0; 2281 scroll_results[i].result = 0; 2282 } 2283 first = 0; 2284 } 2285 2286 if (win == None) { 2287 return 0; 2288 } 2289 if (set == SCR_NONE) { 2290 /* lookup case */ 2291 for (i=0; i<SCR_RESULTS_MAX; i++) { 2292 if (win == scroll_results[i].win) { 2293 return scroll_results[i].result; 2294 } 2295 if (scroll_results[i].win == None) { 2296 break; 2297 } 2298 } 2299 return 0; 2300 } 2301 2302 for (i=0; i<SCR_RESULTS_MAX; i++) { 2303 if (oldest == -1.0 || scroll_results[i].time < oldest) { 2304 next_index = i; 2305 oldest = scroll_results[i].time; 2306 } 2307 if (win == scroll_results[i].win) { 2308 index = i; 2309 break; 2310 } 2311 if (next_index >= 0 && scroll_results[i].win == None) { 2312 break; 2313 } 2314 } 2315 2316 if (set == SCR_SUCCESS) { 2317 set = 1; 2318 } else if (set == SCR_FAIL) { 2319 set = -1; 2320 } else { 2321 set = 0; 2322 } 2323 if (index == -1) { 2324 scroll_results[next_index].win = win; 2325 scroll_results[next_index].time = dnow(); 2326 scroll_results[next_index].result = set; 2327 } else { 2328 if (scroll_results[index].result == 1) { 2329 /* 2330 * once a success, always a success, until they 2331 * forget about us... 2332 */ 2333 set = 1; 2334 } else { 2335 scroll_results[index].result = set; 2336 } 2337 scroll_results[index].time = dnow(); 2338 } 2339 2340 return set; 2341 } 2342 2343 void eat_viewonly_input(int max_eat, int keep) { 2344 int i, gp, gk; 2345 2346 for (i=0; i<max_eat; i++) { 2347 int cont = 0; 2348 gp = got_pointer_calls; 2349 gk = got_keyboard_calls; 2350 rfbCFD(0); 2351 if (got_pointer_calls > gp) { 2352 if (debug_pointer) { 2353 rfbLog("eat_viewonly_input: pointer: %d\n", i); 2354 } 2355 cont++; 2356 } 2357 if (got_keyboard_calls > gk) { 2358 if (debug_keyboard) { 2359 rfbLog("eat_viewonly_input: keyboard: %d\n", i); 2360 } 2361 cont++; 2362 } 2363 if (i >= keep - 1 && ! cont) { 2364 break; 2365 } 2366 } 2367 } 2368 2369 static int eat_pointer(int max_ptr_eat, int keep) { 2370 int i, count = 0, gp = got_pointer_input; 2371 2372 for (i=0; i<max_ptr_eat; i++) { 2373 rfbCFD(0); 2374 if (got_pointer_input > gp) { 2375 count++; 2376 if (0) fprintf(stderr, "GP*-%d\n", i); 2377 gp = got_pointer_input; 2378 } else if (i > keep) { 2379 break; 2380 } 2381 } 2382 return count; 2383 } 2384 2385 static void set_bdpush(int type, double *last_bdpush, int *pushit) { 2386 double now, delay = 0.0; 2387 int link, latency, netrate; 2388 2389 *pushit = 0; 2390 2391 if (type == SCR_MOUSE) { 2392 delay = scr_mouse_bdpush_time; 2393 } else if (type == SCR_KEY) { 2394 delay = scr_key_bdpush_time; 2395 } 2396 2397 link = link_rate(&latency, &netrate); 2398 if (link == LR_DIALUP) { 2399 delay *= 1.5; 2400 } else if (link == LR_BROADBAND) { 2401 delay *= 1.25; 2402 } 2403 2404 dtime0(&now); 2405 if (delay > 0.0 && now > *last_bdpush + delay) { 2406 *pushit = 1; 2407 *last_bdpush = now; 2408 } 2409 } 2410 2411 void mark_for_xdamage(int x, int y, int w, int h) { 2412 int tx1, ty1, tx2, ty2; 2413 sraRegionPtr tmpregion; 2414 2415 if (! use_xdamage) { 2416 return; 2417 } 2418 2419 tx1 = nfix(x, dpy_x); 2420 ty1 = nfix(y, dpy_y); 2421 tx2 = nfix(x + w, dpy_x+1); 2422 ty2 = nfix(y + h, dpy_y+1); 2423 2424 tmpregion = sraRgnCreateRect(tx1, ty1, tx2, ty2); 2425 add_region_xdamage(tmpregion); 2426 sraRgnDestroy(tmpregion); 2427 } 2428 2429 void mark_region_for_xdamage(sraRegionPtr region) { 2430 sraRectangleIterator *iter; 2431 sraRect rect; 2432 iter = sraRgnGetIterator(region); 2433 while (sraRgnIteratorNext(iter, &rect)) { 2434 int x1 = rect.x1; 2435 int y1 = rect.y1; 2436 int x2 = rect.x2; 2437 int y2 = rect.y2; 2438 mark_for_xdamage(x1, y1, x2 - x1, y2 - y1); 2439 } 2440 sraRgnReleaseIterator(iter); 2441 } 2442 2443 void set_xdamage_mark(int x, int y, int w, int h) { 2444 sraRegionPtr region; 2445 2446 if (! use_xdamage) { 2447 return; 2448 } 2449 mark_for_xdamage(x, y, w, h); 2450 2451 if (xdamage_scheduled_mark == 0.0) { 2452 xdamage_scheduled_mark = dnow() + 2.0; 2453 } 2454 2455 if (xdamage_scheduled_mark_region == NULL) { 2456 xdamage_scheduled_mark_region = sraRgnCreate(); 2457 } 2458 region = sraRgnCreateRect(x, y, x + w, y + w); 2459 sraRgnOr(xdamage_scheduled_mark_region, region); 2460 sraRgnDestroy(region); 2461 } 2462 2463 static int repeat_check(double last_key_scroll) { 2464 int repeating; 2465 double rate = typing_rate(0.0, &repeating); 2466 double now = dnow(), delay = 0.5; 2467 if (rate > 2.0 && repeating && now > last_key_scroll + delay) { 2468 return 0; 2469 } else { 2470 return 1; 2471 } 2472 } 2473 2474 static int check_xrecord_keys(void) { 2475 static int last_wx, last_wy, last_ww, last_wh; 2476 double spin = 0.0, tm, tnow; 2477 int scr_cnt = 0, input = 0, scroll_rep; 2478 int get_out, got_one = 0, flush1 = 0, flush2 = 0; 2479 int gk, gk0, ret = 0, db = debug_scroll; 2480 int fail = 0; 2481 int link, latency, netrate; 2482 2483 static double last_key_scroll = 0.0; 2484 static double persist_start = 0.0; 2485 static double last_bdpush = 0.0; 2486 static int persist_count = 0; 2487 int scroll_keysym = 0; 2488 double last_scroll, scroll_persist = scr_key_persist; 2489 double spin_fac = 1.0, scroll_fac = 2.0, noscroll_fac = 0.75; 2490 double max_spin, max_long_spin = 0.3; 2491 double set_repeat_in; 2492 static double set_repeat = 0.0; 2493 2494 2495 RAWFB_RET(0) 2496 2497 if (unixpw_in_progress) return 0; 2498 2499 set_repeat_in = set_repeat; 2500 set_repeat = 0.0; 2501 2502 get_out = 1; 2503 if (got_keyboard_input) { 2504 get_out = 0; 2505 } 2506 2507 dtime0(&tnow); 2508 if (tnow < last_key_scroll + scroll_persist) { 2509 get_out = 0; 2510 } 2511 2512 if (set_repeat_in > 0.0 && tnow < last_key_scroll + set_repeat_in) { 2513 get_out = 0; 2514 } 2515 2516 if (get_out) { 2517 persist_start = 0.0; 2518 persist_count = 0; 2519 last_bdpush = 0.0; 2520 if (xrecording) { 2521 xrecord_watch(0, SCR_KEY); 2522 } 2523 return 0; 2524 } 2525 2526 #if 0 2527 /* not used for keyboard yet */ 2528 scroll_rep = scrollability(xrecord_ptr_window, SCR_NONE) + 1; 2529 if (scroll_rep == 1) { 2530 scroll_rep = 2; /* if no info, assume the best. */ 2531 } 2532 #endif 2533 2534 scroll_keysym = xrecord_scroll_keysym(last_rfb_keysym); 2535 2536 max_spin = scr_key_time; 2537 2538 if (set_repeat_in > 0.0 && tnow < last_key_scroll + 2*set_repeat_in) { 2539 max_spin = 2 * set_repeat_in; 2540 } else if (tnow < last_key_scroll + scroll_persist) { 2541 max_spin = 1.25*(tnow - last_key_scroll); 2542 } else if (tnow < last_key_to_button_remap_time + 1.5*scroll_persist) { 2543 /* mostly a hack I use for testing -remap key -> btn4/btn5 */ 2544 max_spin = scroll_persist; 2545 } else if (scroll_keysym) { 2546 if (repeat_check(last_key_scroll)) { 2547 spin_fac = scroll_fac; 2548 } else { 2549 spin_fac = noscroll_fac; 2550 } 2551 } 2552 if (max_spin > max_long_spin) { 2553 max_spin = max_long_spin; 2554 } 2555 2556 /* XXX use this somehow */ 2557 if (0) link = link_rate(&latency, &netrate); 2558 2559 gk = gk0 = got_keyboard_input; 2560 dtime0(&tm); 2561 2562 if (db) fprintf(stderr, "check_xrecord_keys: BEGIN LOOP: scr_ev_cnt: " 2563 "%d max: %.3f %.4f\n", scr_ev_cnt, max_spin, tm - x11vnc_start); 2564 2565 while (1) { 2566 2567 if (scr_ev_cnt) { 2568 got_one = 1; 2569 2570 scrollability(xrecord_ptr_window, SCR_SUCCESS); 2571 scroll_rep = 2; 2572 2573 dtime0(&last_scroll); 2574 last_key_scroll = last_scroll; 2575 scr_cnt++; 2576 break; 2577 } 2578 2579 X_LOCK; 2580 flush1 = 1; 2581 XFlush_wr(dpy); 2582 X_UNLOCK; 2583 2584 if (set_repeat_in > 0.0) { 2585 max_keyrepeat_time = set_repeat_in; 2586 } 2587 2588 if (use_threads) { 2589 usleep(1000); 2590 } else { 2591 rfbCFD(1000); 2592 } 2593 spin += dtime(&tm); 2594 2595 X_LOCK; 2596 if (got_keyboard_input > gk) { 2597 gk = got_keyboard_input; 2598 input++; 2599 if (set_repeat_in) { 2600 ; 2601 } else if (xrecord_scroll_keysym(last_rfb_keysym)) { 2602 if (repeat_check(last_key_scroll)) { 2603 spin_fac = scroll_fac; 2604 } else { 2605 spin_fac = noscroll_fac; 2606 } 2607 } 2608 if (0 || db) fprintf(stderr, "check_xrecord: more keys: %.3f 0x%x " 2609 " %.4f %s %s\n", spin, last_rfb_keysym, last_rfb_keytime - x11vnc_start, 2610 last_rfb_down ? "down":"up ", last_rfb_key_accepted ? "accept":"skip"); 2611 flush2 = 1; 2612 XFlush_wr(dpy); 2613 } 2614 #if LIBVNCSERVER_HAVE_RECORD 2615 SCR_LOCK; 2616 XRecordProcessReplies(rdpy_data); 2617 SCR_UNLOCK; 2618 #endif 2619 X_UNLOCK; 2620 2621 if (spin >= max_spin * spin_fac) { 2622 if (0 || db) fprintf(stderr, "check_xrecord: SPIN-OUT: %.3f/%.3f\n", spin, 2623 max_spin * spin_fac); 2624 fail = 1; 2625 break; 2626 } 2627 } 2628 2629 max_keyrepeat_time = 0.0; 2630 2631 if (scr_ev_cnt) { 2632 int dret, ev = scr_ev_cnt - 1; 2633 int bdx, bdy, bdskinny, bdpush = 0; 2634 double max_age = 0.25, age, tm, dt; 2635 static double last_scr_ev = 0.0; 2636 2637 last_wx = scr_ev[ev].win_x; 2638 last_wy = scr_ev[ev].win_y; 2639 last_ww = scr_ev[ev].win_w; 2640 last_wh = scr_ev[ev].win_h; 2641 2642 /* assume scrollbar on rhs: */ 2643 bdx = last_wx + last_ww + 3; 2644 bdy = last_wy + last_wh/2; 2645 bdskinny = 32; 2646 2647 if (persist_start == 0.0) { 2648 bdpush = 0; 2649 } else { 2650 set_bdpush(SCR_KEY, &last_bdpush, &bdpush); 2651 } 2652 2653 dtime0(&tm); 2654 age = max_age; 2655 dret = push_scr_ev(&age, SCR_KEY, bdpush, bdx, bdy, bdskinny, 1); 2656 dt = dtime(&tm); 2657 2658 ret = 1 + dret; 2659 scr_ev_cnt = 0; 2660 2661 if (ret == 2 && xrecord_scroll_keysym(last_rfb_keysym)) { 2662 int repeating; 2663 double time_lo = 1.0/max_keyrepeat_lo; 2664 double time_hi = 1.0/max_keyrepeat_hi; 2665 double rate = typing_rate(0.0, &repeating); 2666 if (0 || db) fprintf(stderr, "Typing: dt: %.4f rate: %.1f\n", dt, rate); 2667 if (repeating) { 2668 /* n.b. the "quantum" is about 1/30 sec. */ 2669 max_keyrepeat_time = 1.0*dt; 2670 if (max_keyrepeat_time > time_lo || 2671 max_keyrepeat_time < time_hi) { 2672 max_keyrepeat_time = 0.0; 2673 } else { 2674 set_repeat = max_keyrepeat_time; 2675 if (0 || db) fprintf(stderr, "set max_keyrepeat_time: %.2f\n", max_keyrepeat_time); 2676 } 2677 } 2678 } 2679 2680 last_scr_ev = dnow(); 2681 } 2682 2683 if ((got_one && ret < 2) || persist_count) { 2684 set_xdamage_mark(last_wx, last_wy, last_ww, last_wh); 2685 } 2686 2687 if (fail) { 2688 scrollability(xrecord_ptr_window, SCR_FAIL); 2689 } 2690 2691 if (xrecording) { 2692 if (ret < 2) { 2693 xrecord_watch(0, SCR_KEY); 2694 } 2695 } 2696 2697 if (ret == 2) { 2698 if (persist_start == 0.0) { 2699 dtime(&persist_start); 2700 last_bdpush = persist_start; 2701 } 2702 } else { 2703 persist_start = 0.0; 2704 last_bdpush = 0.0; 2705 } 2706 2707 /* since we've flushed it, we might as well avoid -input_skip */ 2708 if (flush1 || flush2) { 2709 got_keyboard_input = 0; 2710 got_pointer_input = 0; 2711 } 2712 2713 return ret; 2714 } 2715 2716 static int check_xrecord_mouse(void) { 2717 static int last_wx, last_wy, last_ww, last_wh; 2718 double spin = 0.0, tm, tnow; 2719 int i, scr_cnt = 0, input = 0, scroll_rep; 2720 int get_out, got_one = 0, flush1 = 0, flush2 = 0; 2721 int gp, gp0, ret = 0, db = debug_scroll; 2722 int gk, gk0; 2723 int fail = 0; 2724 int link, latency, netrate; 2725 2726 int start_x, start_y, last_x, last_y; 2727 static double last_mouse_scroll = 0.0; 2728 double last_scroll; 2729 double max_spin[3], max_long[3], persist[3]; 2730 double flush1_time = 0.01; 2731 static double last_flush = 0.0; 2732 double last_bdpush = 0.0, button_up_time = 0.0; 2733 int button_mask_save; 2734 int already_down = 0, max_ptr_eat = 20; 2735 static int want_back_in = 0; 2736 int came_back_in; 2737 int first_push = 1; 2738 2739 int scroll_wheel = 0; 2740 int btn4 = (1<<3); 2741 int btn5 = (1<<4); 2742 2743 RAWFB_RET(0) 2744 2745 get_out = 1; 2746 if (button_mask) { 2747 get_out = 0; 2748 } 2749 if (want_back_in) { 2750 get_out = 0; 2751 } 2752 dtime0(&tnow); 2753 if (0) fprintf(stderr, "check_xrecord_mouse: IN xrecording: %d\n", xrecording); 2754 2755 if (get_out) { 2756 if (xrecording) { 2757 xrecord_watch(0, SCR_MOUSE); 2758 } 2759 return 0; 2760 } 2761 2762 scroll_rep = scrollability(xrecord_ptr_window, SCR_NONE) + 1; 2763 if (scroll_rep == 1) { 2764 scroll_rep = 2; /* if no info, assume the best. */ 2765 } 2766 2767 if (button_mask_prev) { 2768 already_down = 1; 2769 } 2770 if (want_back_in) { 2771 came_back_in = 1; 2772 first_push = 0; 2773 } else { 2774 came_back_in = 0; 2775 } 2776 want_back_in = 0; 2777 2778 if (button_mask & (btn4|btn5)) { 2779 scroll_wheel = 1; 2780 } 2781 2782 /* 2783 * set up times for the various "reputations" 2784 * 2785 * 0 => -1, has been tried but never found a scroll. 2786 * 1 => 0, has not been tried. 2787 * 2 => +1, has been tried and found a scroll. 2788 */ 2789 2790 /* first spin-out time (no events) */ 2791 max_spin[0] = 1*scr_mouse_time; 2792 max_spin[1] = 2*scr_mouse_time; 2793 max_spin[2] = 4*scr_mouse_time; 2794 if (!already_down) { 2795 for (i=0; i<3; i++) { 2796 max_spin[i] *= 1.5; 2797 } 2798 } 2799 2800 /* max time between events */ 2801 persist[0] = 1*scr_mouse_persist; 2802 persist[1] = 2*scr_mouse_persist; 2803 persist[2] = 4*scr_mouse_persist; 2804 2805 /* absolute max time in the loop */ 2806 max_long[0] = scr_mouse_maxtime; 2807 max_long[1] = scr_mouse_maxtime; 2808 max_long[2] = scr_mouse_maxtime; 2809 2810 pointer_flush_delay = scr_mouse_pointer_delay; 2811 2812 /* slow links: */ 2813 link = link_rate(&latency, &netrate); 2814 if (link == LR_DIALUP) { 2815 for (i=0; i<3; i++) { 2816 max_spin[i] *= 2.0; 2817 } 2818 pointer_flush_delay *= 2; 2819 } else if (link == LR_BROADBAND) { 2820 pointer_flush_delay *= 2; 2821 } 2822 2823 gp = gp0 = got_pointer_input; 2824 gk = gk0 = got_keyboard_input; 2825 dtime0(&tm); 2826 2827 /* 2828 * this is used for border pushes (bdpush) to guess location 2829 * of scrollbar (region rects containing this point are pushed). 2830 */ 2831 last_x = start_x = cursor_x; 2832 last_y = start_y = cursor_y; 2833 2834 if (db) fprintf(stderr, "check_xrecord_mouse: BEGIN LOOP: scr_ev_cnt: " 2835 "%d max: %.3f %.4f\n", scr_ev_cnt, max_spin[scroll_rep], tm - x11vnc_start); 2836 2837 while (1) { 2838 double spin_check; 2839 if (scr_ev_cnt) { 2840 int dret, ev = scr_ev_cnt - 1; 2841 int bdpush = 0, bdx, bdy, bdskinny; 2842 double tm, dt, age = 0.35; 2843 2844 got_one = 1; 2845 scrollability(xrecord_ptr_window, SCR_SUCCESS); 2846 scroll_rep = 2; 2847 2848 scr_cnt++; 2849 2850 dtime0(&last_scroll); 2851 last_mouse_scroll = last_scroll; 2852 2853 if (last_bdpush == 0.0) { 2854 last_bdpush = last_scroll; 2855 } 2856 2857 bdx = start_x; 2858 bdy = start_y; 2859 if (clipshift) { 2860 bdx += coff_x; 2861 bdy += coff_y; 2862 } 2863 if (subwin) { 2864 bdx += off_x; 2865 bdy += off_y; 2866 } 2867 bdskinny = 32; 2868 2869 set_bdpush(SCR_MOUSE, &last_bdpush, &bdpush); 2870 2871 dtime0(&tm); 2872 2873 dret = push_scr_ev(&age, SCR_MOUSE, bdpush, bdx, 2874 bdy, bdskinny, first_push); 2875 if (first_push) first_push = 0; 2876 ret = 1 + dret; 2877 2878 dt = dtime(&tm); 2879 2880 if (db) fprintf(stderr, " dret: %d scr_ev_cnt: %d dt: %.4f\n", 2881 dret, scr_ev_cnt, dt); 2882 2883 last_wx = scr_ev[ev].win_x; 2884 last_wy = scr_ev[ev].win_y; 2885 last_ww = scr_ev[ev].win_w; 2886 last_wh = scr_ev[ev].win_h; 2887 scr_ev_cnt = 0; 2888 2889 if (! dret) { 2890 break; 2891 } 2892 if (0 && button_up_time > 0.0) { 2893 /* we only take 1 more event with button up */ 2894 if (db) fprintf(stderr, "check_xrecord: BUTTON_UP_SCROLL: %.3f\n", spin); 2895 break; 2896 } 2897 } 2898 2899 2900 if (! flush1) { 2901 if (! already_down || (!scr_cnt && spin>flush1_time)) { 2902 flush1 = 1; 2903 X_LOCK; 2904 XFlush_wr(dpy); 2905 X_UNLOCK; 2906 dtime0(&last_flush); 2907 } 2908 } 2909 2910 if (use_threads) { 2911 usleep(1000); 2912 } else { 2913 rfbCFD(1000); 2914 rfbCFD(0); 2915 } 2916 spin += dtime(&tm); 2917 2918 if (got_pointer_input > gp) { 2919 flush2 = 1; 2920 input += eat_pointer(max_ptr_eat, 1); 2921 gp = got_pointer_input; 2922 } 2923 if (got_keyboard_input > gk) { 2924 gk = got_keyboard_input; 2925 input++; 2926 } 2927 X_LOCK; 2928 #if LIBVNCSERVER_HAVE_RECORD 2929 SCR_LOCK; 2930 XRecordProcessReplies(rdpy_data); 2931 SCR_UNLOCK; 2932 #endif 2933 X_UNLOCK; 2934 2935 if (! input) { 2936 spin_check = 1.5 * max_spin[scroll_rep]; 2937 } else { 2938 spin_check = max_spin[scroll_rep]; 2939 } 2940 2941 if (button_up_time > 0.0) { 2942 if (tm > button_up_time + max_spin[scroll_rep]) { 2943 if (db) fprintf(stderr, "check_xrecord: SPIN-OUT-BUTTON_UP: %.3f/%.3f\n", spin, tm - button_up_time); 2944 break; 2945 } 2946 } else if (!scr_cnt) { 2947 if (spin >= spin_check) { 2948 2949 if (db) fprintf(stderr, "check_xrecord: SPIN-OUT-1: %.3f/%.3f\n", spin, spin_check); 2950 fail = 1; 2951 break; 2952 } 2953 } else { 2954 if (tm >= last_scroll + persist[scroll_rep]) { 2955 2956 if (db) fprintf(stderr, "check_xrecord: SPIN-OUT-2: %.3f/%.3f\n", spin, tm - last_scroll); 2957 break; 2958 } 2959 } 2960 if (spin >= max_long[scroll_rep]) { 2961 2962 if (db) fprintf(stderr, "check_xrecord: SPIN-OUT-3: %.3f/%.3f\n", spin, max_long[scroll_rep]); 2963 break; 2964 } 2965 2966 if (! button_mask) { 2967 int doflush = 0; 2968 if (button_up_time > 0.0) { 2969 ; 2970 } else if (came_back_in) { 2971 dtime0(&button_up_time); 2972 doflush = 1; 2973 } else if (scroll_wheel) { 2974 if (db) fprintf(stderr, "check_xrecord: SCROLL-WHEEL-BUTTON-UP-KEEP-GOING: %.3f/%.3f %d/%d %d/%d\n", spin, max_long[scroll_rep], last_x, last_y, cursor_x, cursor_y); 2975 doflush = 1; 2976 dtime0(&button_up_time); 2977 } else if (last_x == cursor_x && last_y == cursor_y) { 2978 if (db) fprintf(stderr, "check_xrecord: BUTTON-UP: %.3f/%.3f %d/%d %d/%d\n", spin, max_long[scroll_rep], last_x, last_y, cursor_x, cursor_y); 2979 break; 2980 } else { 2981 if (db) fprintf(stderr, "check_xrecord: BUTTON-UP-KEEP-GOING: %.3f/%.3f %d/%d %d/%d\n", spin, max_long[scroll_rep], last_x, last_y, cursor_x, cursor_y); 2982 doflush = 1; 2983 dtime0(&button_up_time); 2984 } 2985 if (doflush) { 2986 flush1 = 1; 2987 X_LOCK; 2988 XFlush_wr(dpy); 2989 X_UNLOCK; 2990 dtime0(&last_flush); 2991 } 2992 } 2993 2994 last_x = cursor_x; 2995 last_y = cursor_y; 2996 } 2997 2998 if (got_one) { 2999 set_xdamage_mark(last_wx, last_wy, last_ww, last_wh); 3000 } 3001 3002 if (fail) { 3003 scrollability(xrecord_ptr_window, SCR_FAIL); 3004 } 3005 3006 /* flush any remaining pointer events. */ 3007 button_mask_save = button_mask; 3008 pointer_queued_sent = 0; 3009 last_x = cursor_x; 3010 last_y = cursor_y; 3011 pointer_event(-1, 0, 0, NULL); 3012 pointer_flush_delay = 0.0; 3013 3014 if (xrecording && pointer_queued_sent && button_mask_save && 3015 (last_x != cursor_x || last_y != cursor_y) ) { 3016 if (db) fprintf(stderr, " pointer() push yields events on: ret=%d\n", ret); 3017 if (ret == 2) { 3018 if (db) fprintf(stderr, " we decide to send ret=3\n"); 3019 want_back_in = 1; 3020 ret = 3; 3021 flush2 = 1; 3022 } else { 3023 if (ret) { 3024 ret = 1; 3025 } else { 3026 ret = 0; 3027 } 3028 xrecord_watch(0, SCR_MOUSE); 3029 } 3030 } else { 3031 if (ret) { 3032 ret = 1; 3033 } else { 3034 ret = 0; 3035 } 3036 if (xrecording) { 3037 xrecord_watch(0, SCR_MOUSE); 3038 } 3039 } 3040 3041 if (flush2) { 3042 X_LOCK; 3043 XFlush_wr(dpy); 3044 XFlush_wr(rdpy_ctrl); 3045 X_UNLOCK; 3046 3047 flush2 = 1; 3048 dtime0(&last_flush); 3049 3050 if (db) fprintf(stderr, "FLUSH-2\n"); 3051 } 3052 3053 /* since we've flushed it, we might as well avoid -input_skip */ 3054 if (flush1 || flush2) { 3055 got_keyboard_input = 0; 3056 got_pointer_input = 0; 3057 } 3058 3059 if (ret) { 3060 return ret; 3061 } else if (scr_cnt) { 3062 return 1; 3063 } else { 3064 return 0; 3065 } 3066 } 3067 3068 int check_xrecord(void) { 3069 int watch_keys = 0, watch_mouse = 0, consider_mouse; 3070 static int mouse_wants_back_in = 0; 3071 3072 RAWFB_RET(0) 3073 3074 if (! use_xrecord) { 3075 return 0; 3076 } 3077 if (unixpw_in_progress) return 0; 3078 3079 if (skip_cr_when_scaling("scroll")) { 3080 return 0; 3081 } 3082 3083 if (0) fprintf(stderr, "check_xrecord: IN xrecording: %d\n", xrecording); 3084 3085 if (! xrecording) { 3086 return 0; 3087 } 3088 3089 if (!strcmp(scroll_copyrect, "always")) { 3090 watch_keys = 1; 3091 watch_mouse = 1; 3092 } else if (!strcmp(scroll_copyrect, "keys")) { 3093 watch_keys = 1; 3094 } else if (!strcmp(scroll_copyrect, "mouse")) { 3095 watch_mouse = 1; 3096 } 3097 3098 if (button_mask || mouse_wants_back_in) { 3099 consider_mouse = 1; 3100 } else { 3101 consider_mouse = 0; 3102 } 3103 if (0) fprintf(stderr, "check_xrecord: button_mask: %d mouse_wants_back_in: %d\n", button_mask, mouse_wants_back_in); 3104 3105 if (watch_mouse && consider_mouse && xrecord_set_by_mouse) { 3106 int ret = check_xrecord_mouse(); 3107 if (ret == 3) { 3108 mouse_wants_back_in = 1; 3109 } else { 3110 mouse_wants_back_in = 0; 3111 } 3112 return ret; 3113 } else if (watch_keys && xrecord_set_by_keys) { 3114 mouse_wants_back_in = 0; 3115 return check_xrecord_keys(); 3116 } else { 3117 mouse_wants_back_in = 0; 3118 return 0; 3119 } 3120 } 3121 3122 #define DB_SET \ 3123 int db = 0; \ 3124 int db2 = 0; \ 3125 if (debug_wireframe == 1) { \ 3126 db = 1; \ 3127 } \ 3128 if (debug_wireframe == 2) { \ 3129 db2 = 1; \ 3130 } \ 3131 if (debug_wireframe == 3) { \ 3132 db = 1; \ 3133 db2 = 1; \ 3134 } 3135 3136 #define NBATCHMAX 1024 3137 int batch_dxs[NBATCHMAX], batch_dys[NBATCHMAX]; 3138 sraRegionPtr batch_reg[NBATCHMAX]; 3139 3140 static int try_copyrect(Window orig_frame, Window frame, int x, int y, int w, int h, 3141 int dx, int dy, int *obscured, sraRegionPtr extra_clip, double max_wait, int *nbatch) { 3142 3143 static int dt_bad = 0; 3144 static time_t dt_bad_check = 0; 3145 int x1, y1, x2, y2, sent_copyrect = 0; 3146 int req, mod, cpy, ncli; 3147 double tm, dt; 3148 DB_SET 3149 3150 if (nbatch == NULL) { 3151 get_client_regions(&req, &mod, &cpy, &ncli); 3152 if (cpy) { 3153 /* one is still pending... try to force it out: */ 3154 if (!fb_push_wait(max_wait, FB_COPY)) { 3155 fb_push_wait(max_wait/2, FB_COPY); 3156 } 3157 3158 get_client_regions(&req, &mod, &cpy, &ncli); 3159 } 3160 if (cpy) { 3161 return 0; 3162 } 3163 } 3164 3165 *obscured = 0; 3166 /* 3167 * XXX KDE and xfce do some weird things with the 3168 * stacking, it does not match XQueryTree. Work around 3169 * it for now by CopyRect-ing the *whole* on-screen 3170 * rectangle (whether obscured or not!) 3171 */ 3172 if (time(NULL) > dt_bad_check + 5) { 3173 char *dt = guess_desktop(); 3174 if (!strcmp(dt, "kde_maybe_is_ok_now...")) { 3175 dt_bad = 1; 3176 } else if (!strcmp(dt, "xfce")) { 3177 dt_bad = 1; 3178 } else { 3179 dt_bad = 0; 3180 } 3181 dt_bad_check = time(NULL); 3182 } 3183 3184 if (clipshift) { 3185 x -= coff_x; 3186 y -= coff_y; 3187 } 3188 if (subwin) { 3189 x -= off_x; 3190 y -= off_y; 3191 } 3192 if (db2) fprintf(stderr, "try_copyrect: 0x%lx/0x%lx bad: %d stack_list_num: %d\n", orig_frame, frame, dt_bad, stack_list_num); 3193 3194 /* XXX Y dt_bad = 0 */ 3195 if (dt_bad && wireframe_in_progress) { 3196 sraRegionPtr rect; 3197 /* send the whole thing... */ 3198 x1 = crfix(nfix(x, dpy_x), dx, dpy_x); 3199 y1 = crfix(nfix(y, dpy_y), dy, dpy_y); 3200 x2 = crfix(nfix(x+w, dpy_x+1), dx, dpy_x+1); 3201 y2 = crfix(nfix(y+h, dpy_y+1), dy, dpy_y+1); 3202 3203 rect = sraRgnCreateRect(x1, y1, x2, y2); 3204 3205 if (blackouts) { 3206 int i; 3207 sraRegionPtr bo_rect; 3208 for (i=0; i<blackouts; i++) { 3209 bo_rect = sraRgnCreateRect(blackr[i].x1, 3210 blackr[i].y1, blackr[i].x2, blackr[i].y2); 3211 sraRgnSubtract(rect, bo_rect); 3212 sraRgnDestroy(bo_rect); 3213 } 3214 } 3215 if (!nbatch) { 3216 do_copyregion(rect, dx, dy, 0); 3217 } else { 3218 batch_dxs[*nbatch] = dx; 3219 batch_dys[*nbatch] = dy; 3220 batch_reg[*nbatch] = sraRgnCreateRgn(rect); 3221 (*nbatch)++; 3222 } 3223 sraRgnDestroy(rect); 3224 3225 sent_copyrect = 1; 3226 *obscured = 1; /* set to avoid an aggressive push */ 3227 3228 } else if (stack_list_num || dt_bad) { 3229 int k, tx1, tx2, ty1, ty2; 3230 sraRegionPtr moved_win, tmp_win, whole; 3231 sraRectangleIterator *iter; 3232 sraRect rect; 3233 int saw_me = 0; 3234 int orig_x, orig_y; 3235 int boff, bwin; 3236 XWindowAttributes attr; 3237 3238 orig_x = x - dx; 3239 orig_y = y - dy; 3240 3241 tx1 = nfix(orig_x, dpy_x); 3242 ty1 = nfix(orig_y, dpy_y); 3243 tx2 = nfix(orig_x+w, dpy_x+1); 3244 ty2 = nfix(orig_y+h, dpy_y+1); 3245 3246 if (db2) fprintf(stderr, "moved_win: %4d %3d, %4d %3d 0x%lx ---\n", 3247 tx1, ty1, tx2, ty2, frame); 3248 3249 moved_win = sraRgnCreateRect(tx1, ty1, tx2, ty2); 3250 3251 dtime0(&tm); 3252 3253 boff = get_boff(); 3254 bwin = get_bwin(); 3255 3256 X_LOCK; 3257 3258 /* 3259 * loop over the stack, top to bottom until we 3260 * find our wm frame: 3261 */ 3262 for (k = stack_list_num - 1; k >= 0; k--) { 3263 Window swin; 3264 3265 if (0 && dt_bad) { 3266 break; 3267 } 3268 3269 swin = stack_list[k].win; 3270 if (db2) fprintf(stderr, "sw: %d/%lx\n", k, swin); 3271 if (swin == frame || swin == orig_frame) { 3272 if (db2) { 3273 saw_me = 1; fprintf(stderr, " ----------\n"); 3274 } else { 3275 break; 3276 } 3277 } 3278 3279 /* skip some unwanted cases: */ 3280 #ifndef MACOSX 3281 if (swin == None) { 3282 continue; 3283 } 3284 #endif 3285 if (boff <= (int) swin && (int) swin < boff + bwin) { 3286 ; /* blackouts */ 3287 } else if (! stack_list[k].fetched || 3288 stack_list[k].time > tm + 2.0) { 3289 if (!valid_window(swin, &attr, 1)) { 3290 stack_list[k].valid = 0; 3291 } else { 3292 stack_list[k].valid = 1; 3293 stack_list[k].x = attr.x; 3294 stack_list[k].y = attr.y; 3295 stack_list[k].width = attr.width; 3296 stack_list[k].height = attr.height; 3297 stack_list[k].border_width = attr.border_width; 3298 stack_list[k].depth = attr.depth; 3299 stack_list[k].class = attr.class; 3300 stack_list[k].backing_store = 3301 attr.backing_store; 3302 stack_list[k].map_state = 3303 attr.map_state; 3304 } 3305 stack_list[k].fetched = 1; 3306 stack_list[k].time = tm; 3307 } 3308 if (!stack_list[k].valid) { 3309 continue; 3310 } 3311 3312 attr.x = stack_list[k].x; 3313 attr.y = stack_list[k].y; 3314 attr.depth = stack_list[k].depth; 3315 attr.width = stack_list[k].width; 3316 attr.height = stack_list[k].height; 3317 attr.border_width = stack_list[k].border_width; 3318 attr.map_state = stack_list[k].map_state; 3319 3320 if (attr.map_state != IsViewable) { 3321 continue; 3322 } 3323 if (db2) fprintf(stderr, "sw: %d/%lx %dx%d+%d+%d\n", k, swin, stack_list[k].width, stack_list[k].height, stack_list[k].x, stack_list[k].y); 3324 3325 if (clipshift) { 3326 attr.x -= coff_x; 3327 attr.y -= coff_y; 3328 } 3329 if (subwin) { 3330 attr.x -= off_x; 3331 attr.y -= off_y; 3332 } 3333 3334 /* 3335 * first subtract any overlap from the initial 3336 * window rectangle 3337 */ 3338 3339 /* clip the window to the visible screen: */ 3340 tx1 = nfix(attr.x, dpy_x); 3341 ty1 = nfix(attr.y, dpy_y); 3342 tx2 = nfix(attr.x + attr.width, dpy_x+1); 3343 ty2 = nfix(attr.y + attr.height, dpy_y+1); 3344 3345 if (db2) fprintf(stderr, " tmp_win-1: %4d %3d, %4d %3d 0x%lx\n", 3346 tx1, ty1, tx2, ty2, swin); 3347 if (db2 && saw_me) continue; 3348 3349 /* see if window clips us: */ 3350 tmp_win = sraRgnCreateRect(tx1, ty1, tx2, ty2); 3351 if (sraRgnAnd(tmp_win, moved_win)) { 3352 *obscured = 1; 3353 if (db2) fprintf(stderr, " : clips it.\n"); 3354 } 3355 sraRgnDestroy(tmp_win); 3356 3357 /* subtract it from our region: */ 3358 tmp_win = sraRgnCreateRect(tx1, ty1, tx2, ty2); 3359 sraRgnSubtract(moved_win, tmp_win); 3360 sraRgnDestroy(tmp_win); 3361 3362 /* 3363 * next, subtract from the initial window rectangle 3364 * anything that would clip it. 3365 */ 3366 3367 /* clip the window to the visible screen: */ 3368 tx1 = nfix(attr.x - dx, dpy_x); 3369 ty1 = nfix(attr.y - dy, dpy_y); 3370 tx2 = nfix(attr.x - dx + attr.width, dpy_x+1); 3371 ty2 = nfix(attr.y - dy + attr.height, dpy_y+1); 3372 3373 if (db2) fprintf(stderr, " tmp_win-2: %4d %3d, %4d %3d 0x%lx\n", 3374 tx1, ty1, tx2, ty2, swin); 3375 if (db2 && saw_me) continue; 3376 3377 /* subtract it from our region: */ 3378 tmp_win = sraRgnCreateRect(tx1, ty1, tx2, ty2); 3379 sraRgnSubtract(moved_win, tmp_win); 3380 sraRgnDestroy(tmp_win); 3381 } 3382 3383 X_UNLOCK; 3384 3385 if (extra_clip && ! sraRgnEmpty(extra_clip)) { 3386 whole = sraRgnCreateRect(0, 0, dpy_x, dpy_y); 3387 3388 if (clipshift) { 3389 sraRgnOffset(extra_clip, -coff_x, -coff_y); 3390 } 3391 if (subwin) { 3392 sraRgnOffset(extra_clip, -off_x, -off_y); 3393 } 3394 3395 iter = sraRgnGetIterator(extra_clip); 3396 while (sraRgnIteratorNext(iter, &rect)) { 3397 /* clip the window to the visible screen: */ 3398 tx1 = rect.x1; 3399 ty1 = rect.y1; 3400 tx2 = rect.x2; 3401 ty2 = rect.y2; 3402 tmp_win = sraRgnCreateRect(tx1, ty1, tx2, ty2); 3403 sraRgnAnd(tmp_win, whole); 3404 3405 /* see if window clips us: */ 3406 if (sraRgnAnd(tmp_win, moved_win)) { 3407 *obscured = 1; 3408 } 3409 sraRgnDestroy(tmp_win); 3410 3411 /* subtract it from our region: */ 3412 tmp_win = sraRgnCreateRect(tx1, ty1, tx2, ty2); 3413 sraRgnSubtract(moved_win, tmp_win); 3414 sraRgnDestroy(tmp_win); 3415 3416 /* 3417 * next, subtract from the initial window rectangle 3418 * anything that would clip it. 3419 */ 3420 tmp_win = sraRgnCreateRect(tx1, ty1, tx2, ty2); 3421 sraRgnOffset(tmp_win, -dx, -dy); 3422 3423 /* clip the window to the visible screen: */ 3424 sraRgnAnd(tmp_win, whole); 3425 3426 /* subtract it from our region: */ 3427 sraRgnSubtract(moved_win, tmp_win); 3428 sraRgnDestroy(tmp_win); 3429 } 3430 sraRgnReleaseIterator(iter); 3431 sraRgnDestroy(whole); 3432 } 3433 3434 dt = dtime(&tm); 3435 if (db2) fprintf(stderr, " stack_work dt: %.4f\n", dt); 3436 3437 if (*obscured && !strcmp(wireframe_copyrect, "top")) { 3438 ; /* cannot send CopyRegion */ 3439 } else if (! sraRgnEmpty(moved_win)) { 3440 sraRegionPtr whole, shifted_region; 3441 3442 whole = sraRgnCreateRect(0, 0, dpy_x, dpy_y); 3443 shifted_region = sraRgnCreateRgn(moved_win); 3444 sraRgnOffset(shifted_region, dx, dy); 3445 sraRgnAnd(shifted_region, whole); 3446 3447 sraRgnDestroy(whole); 3448 3449 /* now send the CopyRegion: */ 3450 if (! sraRgnEmpty(shifted_region)) { 3451 dtime0(&tm); 3452 if (!nbatch) { 3453 do_copyregion(shifted_region, dx, dy, 0); 3454 } else { 3455 batch_dxs[*nbatch] = dx; 3456 batch_dys[*nbatch] = dy; 3457 batch_reg[*nbatch] = sraRgnCreateRgn(shifted_region); 3458 (*nbatch)++; 3459 3460 } 3461 dt = dtime(&tm); 3462 if (0 || db2) fprintf(stderr, "do_copyregion: %d %d %d %d dx: %d dy: %d dt: %.4f\n", 3463 tx1, ty1, tx2, ty2, dx, dy, dt); 3464 sent_copyrect = 1; 3465 } 3466 sraRgnDestroy(shifted_region); 3467 } 3468 sraRgnDestroy(moved_win); 3469 } 3470 return sent_copyrect; 3471 } 3472 3473 int near_wm_edge(int x, int y, int w, int h, int px, int py) { 3474 /* heuristics: */ 3475 int wf_t = wireframe_top; 3476 int wf_b = wireframe_bot; 3477 int wf_l = wireframe_left; 3478 int wf_r = wireframe_right; 3479 3480 int near_edge = 0; 3481 3482 if (wf_t || wf_b || wf_l || wf_r) { 3483 if (nabs(y - py) < wf_t) { 3484 near_edge = 1; 3485 } 3486 if (nabs(y + h - py) < wf_b) { 3487 near_edge = 1; 3488 } 3489 if (nabs(x - px) < wf_l) { 3490 near_edge = 1; 3491 } 3492 if (nabs(x + w - px) < wf_r) { 3493 near_edge = 1; 3494 } 3495 } else { 3496 /* all zero; always "near" edge: */ 3497 near_edge = 1; 3498 } 3499 return near_edge; 3500 } 3501 3502 int near_scrollbar_edge(int x, int y, int w, int h, int px, int py) { 3503 /* heuristics: */ 3504 int sb_t = scrollcopyrect_top; 3505 int sb_b = scrollcopyrect_bot; 3506 int sb_l = scrollcopyrect_left; 3507 int sb_r = scrollcopyrect_right; 3508 3509 int near_edge = 0; 3510 3511 if (sb_t || sb_b || sb_l || sb_r) { 3512 if (nabs(y - py) < sb_t) { 3513 near_edge = 1; 3514 } 3515 if (nabs(y + h - py) < sb_b) { 3516 near_edge = 1; 3517 } 3518 if (nabs(x - px) < sb_l) { 3519 near_edge = 1; 3520 } 3521 if (nabs(x + w - px) < sb_r) { 3522 near_edge = 1; 3523 } 3524 } else { 3525 /* all zero; always "near" edge: */ 3526 near_edge = 1; 3527 } 3528 return near_edge; 3529 } 3530 3531 void check_fixscreen(void) { 3532 double now = dnow(); 3533 int didfull = 0, db = 0; 3534 3535 if (!client_count) { 3536 return; 3537 } 3538 if (unixpw_in_progress) return; 3539 3540 if (screen_fixup_X > 0.0) { 3541 static double last = 0.0; 3542 if (now > last + screen_fixup_X) { 3543 if (db) rfbLog("doing screen_fixup_X\n"); 3544 do_copy_screen = 1; 3545 last = now; 3546 didfull = 1; 3547 } 3548 3549 } 3550 if (screen_fixup_V > 0.0) { 3551 static double last = 0.0; 3552 if (now > last + screen_fixup_V) { 3553 if (! didfull) { 3554 refresh_screen(0); 3555 if (db) rfbLog("doing screen_fixup_V\n"); 3556 } 3557 last = now; 3558 didfull = 1; 3559 } 3560 } 3561 if (screen_fixup_C > 0.0) { 3562 static double last = 0.0; 3563 if (last_copyrect_fix < last_copyrect && 3564 now > last_copyrect + screen_fixup_C) { 3565 if (! didfull) { 3566 refresh_screen(0); 3567 if (db) rfbLog("doing screen_fixup_C\n"); 3568 } 3569 last_copyrect_fix = now; 3570 last = now; 3571 didfull = 1; 3572 } 3573 } 3574 if (scaling && last_copyrect_fix < last_copyrect) { 3575 static double last = 0.0; 3576 double delay = 3.0; 3577 if (now > last + delay) { 3578 if (! didfull) { 3579 scale_and_mark_rect(0, 0, dpy_x, dpy_y, 1); 3580 if (db) rfbLog("doing scale screen_fixup\n"); 3581 } 3582 last_copyrect_fix = now; 3583 last = now; 3584 didfull = 1; 3585 } 3586 } 3587 if (advertise_truecolor && advertise_truecolor_reset && indexed_color) { 3588 /* this will reset framebuffer to correct colors, if needed */ 3589 static double dlast = 0.0; 3590 now = dnow(); 3591 if (now > last_client + 1.0 && now < last_client + 3.0 && now > dlast + 5.0) { 3592 rfbLog("advertise truecolor reset framebuffer\n"); 3593 do_new_fb(1); 3594 dlast = dnow(); 3595 return; 3596 } 3597 } 3598 } 3599 3600 static int wireframe_mod_state() { 3601 if (! wireframe_mods) { 3602 return 0; 3603 } 3604 if (!strcmp(wireframe_mods, "all")) { 3605 if (track_mod_state(NoSymbol, FALSE, FALSE)) { 3606 return 1; 3607 } else { 3608 return 0; 3609 } 3610 3611 } else if (!strcmp(wireframe_mods, "Alt")) { 3612 if (track_mod_state(XK_Alt_L, FALSE, FALSE) == 1) { 3613 return 1; 3614 } else if (track_mod_state(XK_Alt_R, FALSE, FALSE) == 1) { 3615 return 1; 3616 } 3617 } else if (!strcmp(wireframe_mods, "Shift")) { 3618 if (track_mod_state(XK_Shift_L, FALSE, FALSE) == 1) { 3619 return 1; 3620 } else if (track_mod_state(XK_Shift_R, FALSE, FALSE) == 1) { 3621 return 1; 3622 } 3623 } else if (!strcmp(wireframe_mods, "Control")) { 3624 if (track_mod_state(XK_Control_L, FALSE, FALSE) == 1) { 3625 return 1; 3626 } else if (track_mod_state(XK_Control_R, FALSE, FALSE) == 1) { 3627 return 1; 3628 } 3629 } else if (!strcmp(wireframe_mods, "Meta")) { 3630 if (track_mod_state(XK_Meta_L, FALSE, FALSE) == 1) { 3631 return 1; 3632 } else if (track_mod_state(XK_Meta_R, FALSE, FALSE) == 1) { 3633 return 1; 3634 } 3635 } else if (!strcmp(wireframe_mods, "Super")) { 3636 if (track_mod_state(XK_Super_L, FALSE, FALSE) == 1) { 3637 return 1; 3638 } else if (track_mod_state(XK_Super_R, FALSE, FALSE) == 1) { 3639 return 1; 3640 } 3641 } else if (!strcmp(wireframe_mods, "Hyper")) { 3642 if (track_mod_state(XK_Hyper_L, FALSE, FALSE) == 1) { 3643 return 1; 3644 } else if (track_mod_state(XK_Hyper_R, FALSE, FALSE) == 1) { 3645 return 1; 3646 } 3647 } 3648 return 0; 3649 } 3650 3651 static int NPP_nreg = 0; 3652 static sraRegionPtr NPP_roffscreen = NULL; 3653 static sraRegionPtr NPP_r_bs_tmp = NULL; 3654 static Window NPP_nwin = None; 3655 3656 void clear_win_events(Window win, int vis) { 3657 #if !NO_X11 3658 if (dpy && win != None && ncache) { 3659 XEvent ev; 3660 XErrorHandler old_handler; 3661 old_handler = XSetErrorHandler(trap_xerror); 3662 trapped_xerror = 0; 3663 while (XCheckTypedWindowEvent(dpy, win, ConfigureNotify, &ev)) { 3664 if (ncdb) fprintf(stderr, "."); 3665 if (trapped_xerror) { 3666 break; 3667 } 3668 trapped_xerror = 0; 3669 } 3670 /* XXX Y */ 3671 if (vis) { 3672 while (XCheckTypedWindowEvent(dpy, win, VisibilityNotify, &ev)) { 3673 if (ncdb) fprintf(stderr, "+"); 3674 if (trapped_xerror) { 3675 break; 3676 } 3677 trapped_xerror = 0; 3678 } 3679 } 3680 XSetErrorHandler(old_handler); 3681 if (ncdb) fprintf(stderr, " 0x%lx\n", win); 3682 } 3683 #endif 3684 } 3685 3686 void push_borders(sraRect *rects, int nrect) { 3687 int i, s = 2; 3688 sraRegionPtr r0, r1, r2; 3689 3690 r0 = sraRgnCreate(); 3691 r1 = sraRgnCreateRect(0, 0, dpy_x, dpy_y); 3692 3693 for (i=0; i<nrect; i++) { 3694 int x = rects[i].x1; 3695 int y = rects[i].y1; 3696 int w = rects[i].x2; 3697 int h = rects[i].y2; 3698 3699 if (w > 0 && h > 0 && w * h > 64 * 64) { 3700 r2 = sraRgnCreateRect(x - s, y , x , y + h); 3701 sraRgnOr(r0, r2); 3702 sraRgnDestroy(r2); 3703 3704 r2 = sraRgnCreateRect(x + w, y , x + w + s, y + h); 3705 sraRgnOr(r0, r2); 3706 sraRgnDestroy(r2); 3707 3708 r2 = sraRgnCreateRect(x - s, y - s, x + w + s, y + s); 3709 sraRgnOr(r0, r2); 3710 sraRgnDestroy(r2); 3711 3712 r2 = sraRgnCreateRect(x - s, y , x + w + s, y + h + s); 3713 sraRgnOr(r0, r2); 3714 sraRgnDestroy(r2); 3715 } 3716 } 3717 3718 sraRgnAnd(r0, r1); 3719 3720 if (!sraRgnEmpty(r0)) { 3721 double d = dnow(); 3722 sraRectangleIterator *iter; 3723 sraRect rect; 3724 int db = 0; 3725 3726 if (db) fprintf(stderr, "SCALE_BORDER\n"); 3727 fb_push_wait(0.05, FB_MOD|FB_COPY); 3728 3729 iter = sraRgnGetIterator(r0); 3730 while (sraRgnIteratorNext(iter, &rect)) { 3731 /* clip the window to the visible screen: */ 3732 int tx1 = rect.x1; 3733 int ty1 = rect.y1; 3734 int tx2 = rect.x2; 3735 int ty2 = rect.y2; 3736 scale_and_mark_rect(tx1, ty1, tx2, ty2, 1); 3737 } 3738 sraRgnReleaseIterator(iter); 3739 3740 if (db) fprintf(stderr, "SCALE_BORDER %.4f\n", dnow() - d); 3741 fb_push_wait(0.1, FB_MOD|FB_COPY); 3742 if (db) fprintf(stderr, "SCALE_BORDER %.4f\n", dnow() - d); 3743 } 3744 sraRgnDestroy(r0); 3745 sraRgnDestroy(r1); 3746 } 3747 3748 void ncache_pre_portions(Window orig_frame, Window frame, int *nidx_in, int try_batch, int *use_batch, 3749 int orig_x, int orig_y, int orig_w, int orig_h, int x, int y, int w, int h, double ntim) { 3750 int nidx, np = ncache_pad; 3751 3752 if (!ntim) {} 3753 *use_batch = 0; 3754 *nidx_in = -1; 3755 NPP_nreg = 0; 3756 NPP_roffscreen = NULL; 3757 NPP_r_bs_tmp = NULL; 3758 NPP_nwin = None; 3759 3760 if (ncache <= 0) { 3761 return; 3762 } 3763 3764 if (rotating) { 3765 try_batch = 0; 3766 } 3767 3768 if (*nidx_in == -1) { 3769 nidx = lookup_win_index(orig_frame); 3770 NPP_nwin = orig_frame; 3771 if (nidx < 0) { 3772 nidx = lookup_win_index(frame); 3773 NPP_nwin = frame; 3774 } 3775 } else { 3776 nidx = *nidx_in; 3777 } 3778 if (nidx > 0) { 3779 sraRegionPtr r0, r1, r2; 3780 int dx, dy; 3781 int bs_x = cache_list[nidx].bs_x; 3782 int bs_y = cache_list[nidx].bs_y; 3783 int bs_w = cache_list[nidx].bs_w; 3784 int bs_h = cache_list[nidx].bs_h; 3785 3786 *nidx_in = nidx; 3787 3788 if (bs_x < 0) { 3789 if (!find_rect(nidx, x, y, w, h)) { 3790 nidx = -1; 3791 return; 3792 } 3793 bs_x = cache_list[nidx].bs_x; 3794 bs_y = cache_list[nidx].bs_y; 3795 bs_w = cache_list[nidx].bs_w; 3796 bs_h = cache_list[nidx].bs_h; 3797 } 3798 if (bs_x < 0) { 3799 nidx = -1; 3800 return; 3801 } 3802 3803 if (try_batch) { 3804 *use_batch = 1; 3805 } 3806 3807 if (ncache_pad) { 3808 orig_x -= np; 3809 orig_y -= np; 3810 orig_w += 2 * np; 3811 orig_h += 2 * np; 3812 x -= np; 3813 y -= np; 3814 w += 2 * np; 3815 h += 2 * np; 3816 } 3817 3818 if (clipshift) { 3819 orig_x -= coff_x; 3820 orig_y -= coff_y; 3821 x -= coff_x; 3822 y -= coff_y; 3823 } 3824 3825 r0 = sraRgnCreateRect(0, 0, dpy_x, dpy_y); 3826 3827 r2 = sraRgnCreateRect(orig_x, orig_y, orig_x + orig_w, orig_y + orig_h); 3828 sraRgnSubtract(r2, r0); 3829 if (! sraRgnEmpty(r2) && cache_list[nidx].bs_time > 0.0) { 3830 /* some is initially offscreen */ 3831 dx = bs_x - orig_x; 3832 dy = bs_y - orig_y; 3833 sraRgnOffset(r2, dx, dy); 3834 dx = 0; 3835 dy = dpy_y; 3836 sraRgnOffset(r2, dx, dy); 3837 if (ncdb) fprintf(stderr, "FB_COPY: %.4f 1) offscreen: dx, dy: %d, %d -> %d, %d orig %dx%d+%d+%d bs_xy: %d %d\n", 3838 dnow() - ntim, bs_x - orig_x, bs_y - orig_y, dx, dy, orig_w, orig_h, orig_x, orig_y, bs_x, bs_y); 3839 3840 /* 0) save it in the invalid (offscreen) SU portion */ 3841 if (! *use_batch) { 3842 do_copyregion(r2, dx, dy, 0); 3843 if (! fb_push_wait(0.2, FB_COPY)) { 3844 fb_push_wait(0.1, FB_COPY); 3845 } 3846 } else { 3847 batch_dxs[NPP_nreg] = dx; 3848 batch_dys[NPP_nreg] = dy; 3849 batch_reg[NPP_nreg++] = sraRgnCreateRgn(r2); 3850 } 3851 NPP_roffscreen = sraRgnCreateRgn(r2); 3852 } 3853 sraRgnDestroy(r2); 3854 3855 /* 1) use bs for temp storage of the new save under. */ 3856 r1 = sraRgnCreateRect(x, y, x + w, y + h); 3857 sraRgnAnd(r1, r0); 3858 3859 dx = bs_x - x; 3860 dy = bs_y - y; 3861 sraRgnOffset(r1, dx, dy); 3862 3863 if (ncdb) fprintf(stderr, "FB_COPY: %.4f 1) use tmp bs:\n", dnow() - ntim); 3864 if (! *use_batch) { 3865 do_copyregion(r1, dx, dy, 0); 3866 if (! fb_push_wait(0.2, FB_COPY)) { 3867 if (ncdb) fprintf(stderr, "FB_COPY: %.4f 1) FAILED.\n", dnow() - ntim); 3868 fb_push_wait(0.1, FB_COPY); 3869 } 3870 } else { 3871 batch_dxs[NPP_nreg] = dx; 3872 batch_dys[NPP_nreg] = dy; 3873 batch_reg[NPP_nreg++] = sraRgnCreateRgn(r1); 3874 } 3875 NPP_r_bs_tmp = sraRgnCreateRgn(r1); 3876 sraRgnDestroy(r0); 3877 sraRgnDestroy(r1); 3878 } 3879 } 3880 3881 void ncache_post_portions(int nidx, int use_batch, int orig_x, int orig_y, int orig_w, int orig_h, 3882 int x, int y, int w, int h, double batch_delay, double ntim) { 3883 int np = ncache_pad; 3884 int db = 0; 3885 3886 if (ncache > 0 && nidx >= 0) { 3887 sraRegionPtr r0, r1, r2, r3; 3888 int dx, dy; 3889 int su_x = cache_list[nidx].su_x; 3890 int su_y = cache_list[nidx].su_y; 3891 int su_w = cache_list[nidx].su_w; 3892 int su_h = cache_list[nidx].su_h; 3893 int bs_x = cache_list[nidx].bs_x; 3894 int bs_y = cache_list[nidx].bs_y; 3895 int bs_w = cache_list[nidx].bs_w; 3896 int bs_h = cache_list[nidx].bs_h; 3897 int some_su = 0; 3898 3899 if (db) fprintf(stderr, "su: %dx%d+%d+%d bs: %dx%d+%d+%d\n", su_w, su_h, su_x, su_y, bs_w, bs_h, bs_x, bs_y); 3900 3901 if (bs_x < 0) { 3902 if (!find_rect(nidx, x, y, w, h)) { 3903 return; 3904 } 3905 su_x = cache_list[nidx].su_x; 3906 su_y = cache_list[nidx].su_y; 3907 su_w = cache_list[nidx].su_w; 3908 su_h = cache_list[nidx].su_h; 3909 bs_x = cache_list[nidx].bs_x; 3910 bs_y = cache_list[nidx].bs_y; 3911 bs_w = cache_list[nidx].bs_w; 3912 bs_h = cache_list[nidx].bs_h; 3913 } 3914 if (bs_x < 0) { 3915 return; 3916 } 3917 3918 if (ncache_pad) { 3919 orig_x -= np; 3920 orig_y -= np; 3921 orig_w += 2 * np; 3922 orig_h += 2 * np; 3923 x -= np; 3924 y -= np; 3925 w += 2 * np; 3926 h += 2 * np; 3927 } 3928 3929 if (clipshift) { 3930 orig_x -= coff_x; 3931 orig_y -= coff_y; 3932 x -= coff_x; 3933 y -= coff_y; 3934 } 3935 3936 r0 = sraRgnCreateRect(0, 0, dpy_x, dpy_y); 3937 3938 /* 0b) copy this bs part stored in saveunder */ 3939 if (NPP_roffscreen != NULL) { 3940 dx = x - su_x; 3941 dy = y - su_y; 3942 sraRgnOffset(NPP_roffscreen, dx, dy); 3943 sraRgnAnd(NPP_roffscreen, r0); 3944 3945 if (! use_batch) { 3946 do_copyregion(NPP_roffscreen, dx, dy, 0); 3947 if (!fb_push_wait(0.2, FB_COPY)) { 3948 fb_push_wait(0.1, FB_COPY); 3949 } 3950 } else { 3951 batch_dxs[NPP_nreg] = dx; 3952 batch_dys[NPP_nreg] = dy; 3953 batch_reg[NPP_nreg++] = sraRgnCreateRgn(NPP_roffscreen); 3954 } 3955 sraRgnDestroy(NPP_roffscreen); 3956 } 3957 3958 /* 3) copy from the saveunder to where orig win was */ 3959 r1 = sraRgnCreateRect(orig_x, orig_y, orig_x + orig_w, orig_y + orig_h); 3960 sraRgnAnd(r1, r0); 3961 r2 = sraRgnCreateRect(x+np, y+np, x + w-np, y + h-np); 3962 sraRgnAnd(r2, r0); 3963 sraRgnSubtract(r1, r2); 3964 3965 dx = orig_x - su_x; 3966 dy = orig_y - su_y; 3967 if (db && ncdb) fprintf(stderr, "FB_COPY: %.4f 3) sent_copyrect: su_restore: %d %d\n", dnow() - ntim, dx, dy); 3968 if (cache_list[nidx].su_time == 0.0) { 3969 ; 3970 } else if (! use_batch) { 3971 do_copyregion(r1, dx, dy, 0); 3972 if (!fb_push_wait(0.2, FB_COPY)) { 3973 if (db && ncdb) fprintf(stderr, "FB_COPY: %.4f 3) FAILED.\n", dnow() - ntim); 3974 fb_push_wait(0.1, FB_COPY); 3975 } 3976 } else { 3977 batch_dxs[NPP_nreg] = dx; 3978 batch_dys[NPP_nreg] = dy; 3979 batch_reg[NPP_nreg++] = sraRgnCreateRgn(r1); 3980 } 3981 if (db && ncdb) fprintf(stderr, "sent_copyrect: %.4f su_restore: done.\n", dnow() - ntim); 3982 sraRgnDestroy(r0); 3983 sraRgnDestroy(r1); 3984 sraRgnDestroy(r2); 3985 3986 /* 4) if overlap between orig and displaced, move the corner that will still be su: */ 3987 r0 = sraRgnCreateRect(0, 0, dpy_x, dpy_y); 3988 3989 r1 = sraRgnCreateRect(orig_x, orig_y, orig_x + orig_w, orig_y + orig_h); 3990 sraRgnAnd(r1, r0); 3991 r2 = sraRgnCreateRect(x, y, x + w, y + h); 3992 sraRgnAnd(r2, r0); 3993 r3 = NULL; 3994 if (sraRgnAnd(r2, r1) && cache_list[nidx].su_time > 0.0) { 3995 int dx2 = su_x - orig_x; 3996 int dy2 = su_y - orig_y; 3997 3998 r3 = sraRgnCreateRgn(r2); 3999 sraRgnOffset(r2, dx2, dy2); 4000 4001 dx = su_x - x; 4002 dy = su_y - y; 4003 sraRgnOffset(r3, dx, dy); 4004 4005 dx = dx - dx2; 4006 dy = dy - dy2; 4007 4008 if (db && ncdb) fprintf(stderr, "FB_COPY: %.4f 4) move overlap inside su:\n", dnow() - ntim); 4009 if (! use_batch) { 4010 do_copyregion(r3, dx, dy, 0); 4011 if (!fb_push_wait(0.2, FB_COPY)) { 4012 if (db) fprintf(stderr, "FB_COPY: %.4f 4) FAILED.\n", dnow() - ntim); 4013 fb_push_wait(0.1, FB_COPY); 4014 } 4015 } else { 4016 batch_dxs[NPP_nreg] = dx; 4017 batch_dys[NPP_nreg] = dy; 4018 batch_reg[NPP_nreg++] = sraRgnCreateRgn(r3); 4019 } 4020 } 4021 sraRgnDestroy(r0); 4022 sraRgnDestroy(r1); 4023 sraRgnDestroy(r2); 4024 4025 /* 5) copy our temporary stuff from bs to su: */ 4026 dx = su_x - bs_x; 4027 dy = su_y - bs_y; 4028 if (NPP_r_bs_tmp == NULL) { 4029 r1 = sraRgnCreateRect(su_x, su_y, su_x + su_w, su_y + su_h); 4030 } else { 4031 r1 = sraRgnCreateRgn(NPP_r_bs_tmp); 4032 sraRgnOffset(r1, dx, dy); 4033 sraRgnDestroy(NPP_r_bs_tmp); 4034 } 4035 if (r3 != NULL) { 4036 sraRgnSubtract(r1, r3); 4037 sraRgnDestroy(r3); 4038 } 4039 if (db) fprintf(stderr, "FB_COPY: %.4f 5) move tmp bs to su:\n", dnow() - ntim); 4040 if (! use_batch) { 4041 do_copyregion(r1, dx, dy, 0); 4042 if (!fb_push_wait(0.2, FB_COPY)) { 4043 if (db) fprintf(stderr, "FB_COPY: %.4f 5) FAILED.\n", dnow() - ntim); 4044 fb_push_wait(0.1, FB_COPY); 4045 } 4046 } else { 4047 batch_dxs[NPP_nreg] = dx; 4048 batch_dys[NPP_nreg] = dy; 4049 batch_reg[NPP_nreg++] = sraRgnCreateRgn(r1); 4050 } 4051 if (! sraRgnEmpty(r1)) { 4052 some_su = 1; 4053 } 4054 sraRgnDestroy(r1); 4055 4056 /* 6) not really necessary, update bs with current view: */ 4057 r0 = sraRgnCreateRect(0, 0, dpy_x, dpy_y); 4058 r1 = sraRgnCreateRect(x, y, x + w, y + h); 4059 sraRgnAnd(r1, r0); 4060 dx = bs_x - x; 4061 dy = bs_y - y; 4062 sraRgnOffset(r1, dx, dy); 4063 if (db) fprintf(stderr, "FB_COPY: %.4f 6) snapshot bs:\n", dnow() - ntim); 4064 if (! use_batch) { 4065 do_copyregion(r1, dx, dy, 0); 4066 if (!fb_push_wait(0.2, FB_COPY)) { 4067 if (db) fprintf(stderr, "FB_COPY: %.4f 6) FAILED.\n", dnow() - ntim); 4068 fb_push_wait(0.1, FB_COPY); 4069 } 4070 } else { 4071 batch_dxs[NPP_nreg] = dx; 4072 batch_dys[NPP_nreg] = dy; 4073 batch_reg[NPP_nreg++] = sraRgnCreateRgn(r1); 4074 } 4075 sraRgnDestroy(r0); 4076 sraRgnDestroy(r1); 4077 4078 if (use_batch) { 4079 batch_push(NPP_nreg, batch_delay); 4080 if (ncdb) fprintf(stderr, "FB_COPY: %.4f XX did batch 0x%x %3d su: %dx%d+%d+%d bs: %dx%d+%d+%d\n", dnow() - ntim, 4081 (unsigned int) cache_list[nidx].win, nidx, su_w, su_h, su_x, su_y, bs_w, bs_h, bs_x, bs_y); 4082 } 4083 cache_list[nidx].x = x + np; 4084 cache_list[nidx].y = y + np; 4085 4086 /* XXX Y */ 4087 cache_list[nidx].bs_time = dnow(); 4088 if (some_su) { 4089 cache_list[nidx].su_time = dnow(); 4090 } 4091 } else { 4092 if (use_batch) { 4093 batch_push(NPP_nreg, batch_delay); 4094 } 4095 } 4096 4097 if (scaling) { 4098 sraRect rects[2]; 4099 4100 rects[0].x1 = orig_x; 4101 rects[0].y1 = orig_y; 4102 rects[0].x2 = orig_w; 4103 rects[0].y2 = orig_h; 4104 4105 rects[1].x1 = x; 4106 rects[1].y1 = y; 4107 rects[1].x2 = w; 4108 rects[1].y2 = h; 4109 push_borders(rects, 2); 4110 } 4111 } 4112 4113 void do_copyrect_drag_move(Window orig_frame, Window frame, int *nidx, int try_batch, 4114 int now_x, int now_y, int orig_w, int orig_h, int x, int y, int w, int h, double batch_delay) { 4115 4116 int sent_copyrect = 1, obscured = 0; 4117 int dx, dy; 4118 int use_batch = 0; 4119 double ntim = dnow(); 4120 static int nob = -1; 4121 sraRegionPtr r0, r1; 4122 4123 if (nob < 0) { 4124 if (getenv("NOCRBATCH")) { 4125 nob = 1; 4126 } else { 4127 nob = 0; 4128 } 4129 } 4130 if (nob) { 4131 try_batch = 0; 4132 } 4133 4134 dx = x - now_x; 4135 dy = y - now_y; 4136 if (dx == 0 && dy == 0) { 4137 return; 4138 } 4139 if (ncdb) fprintf(stderr, "do_COPY: now_xy: %d %d, orig_wh: %d %d, xy: %d %d, wh: %d %d\n",now_x, now_y, orig_w, orig_h, x, y, w, h); 4140 4141 ncache_pre_portions(orig_frame, frame, nidx, try_batch, &use_batch, 4142 now_x, now_y, orig_w, orig_h, x, y, w, h, ntim); 4143 4144 r0 = sraRgnCreateRect(0, 0, dpy_x, dpy_y); 4145 r1 = sraRgnCreateRect(x, y, x + w, y + h); 4146 sraRgnAnd(r1, r0); 4147 4148 dx = x - now_x; 4149 dy = y - now_y; 4150 4151 /* make sure the source is on-screen too */ 4152 sraRgnOffset(r1, -dx, -dy); 4153 sraRgnAnd(r1, r0); 4154 sraRgnOffset(r1, +dx, +dy); 4155 sraRgnAnd(r1, r0); /* just to be sure, problably not needed */ 4156 4157 if (! use_batch) { 4158 do_copyregion(r1, dx, dy, 0); 4159 if (!fb_push_wait(0.2, FB_COPY)) { 4160 if (ncdb) fprintf(stderr, "FB_COPY: %.4f 3) *FAILED*\n", dnow() - ntim); 4161 fb_push_wait(0.1, FB_COPY); 4162 } 4163 } else { 4164 batch_dxs[NPP_nreg] = dx; 4165 batch_dys[NPP_nreg] = dy; 4166 batch_reg[NPP_nreg++] = sraRgnCreateRgn(r1); 4167 } 4168 sraRgnDestroy(r0); 4169 sraRgnDestroy(r1); 4170 4171 if (sent_copyrect) { 4172 if (use_batch) { 4173 ; 4174 } else if (! obscured) { 4175 fb_push_wait(0.1, FB_COPY); 4176 } else { 4177 /* no diff for now... */ 4178 fb_push_wait(0.1, FB_COPY); 4179 } 4180 ncache_post_portions(*nidx, use_batch, 4181 now_x, now_y, orig_w, orig_h, x, y, w, h, batch_delay, ntim); 4182 } 4183 if (ncdb) fprintf(stderr, "do_COPY: %.4f -- post_portion done.\n", dnow() - ntim); 4184 } 4185 4186 void check_macosx_iconify(Window orig_frame, Window frame, int flush) { 4187 #ifdef MACOSX 4188 static double last = 0.0; 4189 double now; 4190 int j, m = 5, idx = -1, ok = 0, unmapped = 0; 4191 4192 if (! macosx_console) { 4193 return; 4194 } 4195 4196 now = dnow(); 4197 if (now < last + 0.3) { 4198 return; 4199 } 4200 last = now; 4201 4202 if (ncache > 0 && orig_frame != None) { 4203 idx = lookup_win_index(orig_frame); 4204 if (idx >= 0) { 4205 if (cache_list[idx].map_state == IsUnmapped) { 4206 if (0) fprintf(stderr, "FAW orig_frame unmapped.\n"); 4207 unmapped = 1; 4208 m = 3; 4209 } 4210 } 4211 } 4212 4213 if (unmapped) { 4214 ; 4215 } else if (orig_frame && macosxCGS_follow_animation_win(orig_frame, -1, 0)) { 4216 if (0) fprintf(stderr, "FAW orig_frame %d\n", (int) orig_frame); 4217 } else if (0 && frame && macosxCGS_follow_animation_win(frame, -1, 0)) { 4218 if (0) fprintf(stderr, "FAW frame %d\n", (int) frame); 4219 } 4220 for (j=0; j<m; j++) { 4221 macosxCGS_get_all_windows(); 4222 if (macosx_checkevent(NULL)) { 4223 ok = 1; 4224 if (0) fprintf(stderr, "Check Event 1\n"); 4225 } else { 4226 if (0) fprintf(stderr, "Check Event 0\n"); 4227 } 4228 if (ok) { 4229 break; 4230 } 4231 usleep(10 * 1000); 4232 } 4233 if (ok) { 4234 if (flush) { 4235 fb_push_wait(0.1, FB_COPY|FB_MOD); 4236 } 4237 check_ncache(0, 2); 4238 } 4239 #else 4240 if (!orig_frame || !frame || !flush) {} 4241 #endif 4242 } 4243 4244 void check_macosx_click_frame(void) { 4245 #ifdef MACOSX 4246 if (macosx_console) { 4247 if (0) fprintf(stderr, "macosx_click_frame: 0x%x\n", macosx_click_frame); 4248 check_macosx_iconify(macosx_click_frame, None, 0); 4249 macosx_click_frame = None; 4250 if (button_mask && !macosx_checkevent(NULL)) { 4251 check_macosx_iconify(None, None, 0); 4252 } 4253 } 4254 #endif 4255 } 4256 4257 int clipped(int idx); 4258 void snap_old(void); 4259 4260 int check_copyrect_raise(int idx, Window orig_frame, int try_batch) { 4261 char *no = "none"; 4262 int doraise = 1; 4263 int valid; 4264 XWindowAttributes attr; 4265 4266 if (! ncache_wf_raises) { 4267 doraise = 0; 4268 no = "ncache_wf_raises"; 4269 } else if (cache_list[idx].bs_time == 0.0) { 4270 doraise = 0; 4271 no = "bs_time"; 4272 } else if (0 && cache_list[idx].vis_state == VisibilityUnobscured) { 4273 doraise = 0; 4274 no = "VisibilityUnobscured"; 4275 } else if (!clipped(idx)) { 4276 doraise = 0; 4277 no = "!clipped()"; 4278 } 4279 if (doraise) { 4280 int nr = 0, *nb = NULL; 4281 if (ncdb) fprintf(stderr, "--YES, wf_raise\n"); 4282 if (try_batch) { 4283 nb = &nr; 4284 } 4285 valid = 1; 4286 bs_restore(idx, nb, NULL, &attr, 0, 1, &valid, 1); 4287 try_to_fix_su(orig_frame, idx, 0x1, nb, NULL); 4288 if (nb && nr) { 4289 batch_push(nr, -1.0); 4290 } 4291 fb_push(); /* XXX Y */ 4292 } else { 4293 if (ncdb && no) fprintf(stderr, "--NO, wf_raise: %s\n", no); 4294 } 4295 if (ncache_wf_raises) { 4296 snapshot_stack_list(0, 0.0); 4297 snap_old(); 4298 } 4299 return 1; 4300 } 4301 4302 int set_copyrect_drag(int idx, Window orig_frame, int try_batch) { 4303 if (idx < 0) { 4304 return 0; 4305 } 4306 if (cache_list[idx].su_time > 0.0) { 4307 check_copyrect_raise(idx, orig_frame, try_batch); 4308 return 1; 4309 } 4310 return 0; 4311 } 4312 4313 /* 4314 * Applied just before any check_user_input() modes. Look for a 4315 * ButtonPress; find window it happened in; find the wm frame window 4316 * for it; watch for that window moving or resizing. If it does, do the 4317 * wireframe animation. Do this until ButtonRelease or timeouts occur. 4318 * Remove wireframe. 4319 * 4320 * Under -nowirecopyrect, return control to base scheme 4321 * (check_user_input() ...) that will repaint the screen with the window 4322 * in the new postion or size. Under -wirecopyrect, apply rfbDoCopyRect 4323 * or rfbDoCopyRegion: this "pollutes" our framebuffer, but the normal 4324 * polling will quickly repair it. Under happy circumstances, this 4325 * reduces actual XShmGetImage work (i.e. if we correctly predicted how 4326 * the X fb has changed. 4327 * 4328 * -scale doesn't always work under -wirecopyrect, but the wireframe does. 4329 * 4330 * testing of this mode under -threads is incomplete. 4331 * 4332 * returns 1 if it did an animation, 0 if no move/resize triggers 4333 * went off. 4334 * 4335 * TBD: see if we can select StructureNotify ConfigureNotify events for 4336 * the toplevel windows to get better info on moves and resizes. 4337 */ 4338 int check_wireframe(void) { 4339 Window frame = None, orig_frame = None; 4340 XWindowAttributes attr; 4341 int dx, dy; 4342 4343 int orig_px, orig_py, orig_x, orig_y, orig_w, orig_h; 4344 int px, py, x, y, w, h; 4345 int box_x, box_y, box_w, box_h; 4346 int orig_cursor_x, orig_cursor_y, g, gd; 4347 int already_down = 0, win_gone = 0, win_unmapped = 0; 4348 double spin = 0.0, tm, last_ptr = 0.0, last_draw; 4349 4350 int frame_changed = 0, drew_box = 0, got_2nd_pointer = 0; 4351 int try_copyrect_drag = 1, do_copyrect_drag = -1; 4352 int now_x = 0, now_y = 0, nidx = -1; 4353 double copyrect_drag_delay = -1.0; 4354 int try_batch = 1; /* XXX Y */ 4355 int mac_skip = 0; 4356 4357 int special_t1 = 0, break_reason = 0, last_draw_cnt = 0, gpi = 0; 4358 static double first_dt_ave = 0.0; 4359 static int first_dt_cnt = 0; 4360 static time_t last_save_stacklist = 0; 4361 int bdown0, bdown, gotui, cnt = 0; 4362 4363 /* heuristics: */ 4364 double first_event_spin = wireframe_t1; 4365 double frame_changed_spin = wireframe_t2; 4366 double max_spin = wireframe_t3; 4367 double min_draw = wireframe_t4; 4368 int try_it = 0; 4369 DB_SET 4370 4371 if (unixpw_in_progress) return 0; 4372 if (copyrect_drag_delay) {} 4373 4374 #ifdef MACOSX 4375 if (macosx_console) { 4376 ; 4377 } else { 4378 RAWFB_RET(0) 4379 } 4380 #else 4381 RAWFB_RET(0) 4382 #endif 4383 4384 if (nofb) { 4385 return 0; 4386 } 4387 if (subwin) { 4388 return 0; /* don't even bother for -id case */ 4389 } 4390 4391 if (db > 1 && button_mask) fprintf(stderr, "check_wireframe: bm: %d gpi: %d\n", button_mask, got_pointer_input); 4392 4393 bdown0 = 0; 4394 if (button_mask) { 4395 bdown0 = 1; 4396 } else if (wireframe_local && display_button_mask) { 4397 bdown0 = 2; 4398 } 4399 if (! bdown0) { 4400 return 0; /* no button pressed down */ 4401 } 4402 4403 gotui = 0; 4404 if (got_pointer_input) { 4405 gotui = 1; 4406 } else if (wireframe_local && display_button_mask) { 4407 gotui = 2; 4408 } 4409 if (!use_threads && !gotui) { 4410 return 0; /* need ptr input, e.g. button down, motion */ 4411 } 4412 4413 if (db > 1) fprintf(stderr, "check_wireframe: %d\n", db); 4414 4415 if (db) fprintf(stderr, "\n*** button down!! x: %d y: %d\n", cursor_x, cursor_y); 4416 4417 /* 4418 * Query where the pointer is and which child of the root 4419 * window. We will assume this is the frame the window manager 4420 * makes when it reparents the toplevel window. 4421 */ 4422 X_LOCK; 4423 if (! get_wm_frame_pos(&px, &py, &x, &y, &w, &h, &frame, NULL)) { 4424 if (db) fprintf(stderr, "NO get_wm_frame_pos-1: 0x%lx\n", frame); 4425 X_UNLOCK; 4426 #ifdef MACOSX 4427 check_macosx_click_frame(); 4428 #endif 4429 return 0; 4430 } 4431 X_UNLOCK; 4432 4433 last_get_wm_frame_time = dnow(); 4434 last_get_wm_frame = frame; 4435 4436 if (db) fprintf(stderr, "a: %d wf: %.3f A: %d origfrm: 0x%lx\n", w*h, wireframe_frac, (dpy_x*dpy_y), frame); 4437 4438 /* 4439 * apply the percentage size criterion (allow opaque moves for 4440 * small windows) 4441 */ 4442 if ((double) w*h < wireframe_frac * (dpy_x * dpy_y)) { 4443 if (db) fprintf(stderr, "small window %.3f\n", ((double) w*h)/(dpy_x * dpy_y)); 4444 return 0; 4445 } 4446 if (db) fprintf(stderr, " frame: x: %d y: %d w: %d h: %d px: %d py: %d fr: 0x%lx\n", x, y, w, h, px, py, frame); 4447 4448 /* 4449 * see if the pointer is within range of the assumed wm frame 4450 * decorations on the edge of the window. 4451 */ 4452 4453 try_it = near_wm_edge(x, y, w, h, px, py); 4454 4455 /* Often Alt+ButtonDown starts a window move: */ 4456 if (! try_it && wireframe_mod_state()) { 4457 try_it = 1; 4458 } 4459 if (try_it && clipshift) { 4460 sraRegionPtr r1, r2; 4461 int xc = off_x + coff_x; 4462 int yc = off_y + coff_y; 4463 r1 = sraRgnCreateRect(x, y, x+w, y+h); 4464 r2 = sraRgnCreateRect(xc, yc, xc+dpy_x, yc+dpy_y); 4465 if (!sraRgnAnd(r1, r2)) { 4466 if (db) fprintf(stderr, "OUTSIDE CLIPSHIFT\n"); 4467 try_it = 0; 4468 } 4469 sraRgnDestroy(r1); 4470 sraRgnDestroy(r2); 4471 } 4472 if (! try_it) { 4473 if (db) fprintf(stderr, "INTERIOR\n"); 4474 #ifdef MACOSX 4475 check_macosx_click_frame(); 4476 #endif 4477 return 0; 4478 } 4479 4480 wireframe_in_progress = 1; 4481 4482 if (button_mask_prev) { 4483 already_down = 1; 4484 } 4485 4486 if (! wireframe_str || !strcmp(wireframe_str, WIREFRAME_PARMS)) { 4487 int link, latency, netrate; 4488 static int didmsg = 0; 4489 4490 link = link_rate(&latency, &netrate); 4491 if (link == LR_DIALUP || link == LR_BROADBAND) { 4492 /* slow link, e.g. dialup, increase timeouts: */ 4493 first_event_spin *= 2.0; 4494 frame_changed_spin *= 2.0; 4495 max_spin *= 2.0; 4496 min_draw *= 1.5; 4497 if (link == LR_DIALUP) { 4498 max_spin *= 1.2; 4499 min_draw *= 1.7; 4500 } 4501 if (! didmsg) { 4502 rfbLog("increased wireframe timeouts for " 4503 "slow network connection.\n"); 4504 rfbLog("netrate: %d KB/sec, latency: %d ms\n", 4505 netrate, latency); 4506 didmsg = 1; 4507 } 4508 } 4509 } 4510 4511 /* 4512 * pointer() should have snapped the stacking list for us, if 4513 * not, do it now (if the XFakeButtonEvent has been flushed by 4514 * now the stacking order may be incorrect). 4515 */ 4516 if (strcmp(wireframe_copyrect, "never")) { 4517 if (already_down) { 4518 double age = 0.0; 4519 /* 4520 * see if we can reuse the stack list (pause 4521 * with button down) 4522 */ 4523 if (stack_list_num) { 4524 int k, got_me = 0; 4525 for (k = stack_list_num -1; k >=0; k--) { 4526 if (frame == stack_list[k].win) { 4527 got_me = 1; 4528 break; 4529 } 4530 } 4531 if (got_me) { 4532 age = 1.0; 4533 } 4534 snapshot_stack_list(0, age); 4535 } 4536 } 4537 if (! stack_list_num) { 4538 snapshot_stack_list(0, 0.0); 4539 } 4540 } 4541 4542 4543 /* store initial parameters, we look for changes in them */ 4544 orig_frame = frame; 4545 orig_px = px; /* pointer position */ 4546 orig_py = py; 4547 orig_x = x; /* frame position */ 4548 orig_y = y; 4549 orig_w = w; /* frame size */ 4550 orig_h = h; 4551 4552 orig_cursor_x = cursor_x; 4553 orig_cursor_y = cursor_y; 4554 4555 /* this is the box frame we would draw */ 4556 box_x = x; 4557 box_y = y; 4558 box_w = w; 4559 box_h = h; 4560 4561 dtime0(&tm); 4562 4563 last_draw = spin; 4564 4565 /* -threads support for check_wireframe() is rough... crash? */ 4566 if (use_threads) { 4567 /* purge any stored up pointer events: */ 4568 pointer_event(-1, 0, 0, NULL); 4569 } 4570 4571 if (cursor_noshape_updates_clients(screen)) { 4572 try_batch = 0; 4573 } 4574 if (rotating) { 4575 try_batch = 0; 4576 } 4577 if (use_threads && ncache > 0 && ncache_copyrect) { 4578 try_batch = 0; 4579 } 4580 4581 g = got_pointer_input; 4582 gd = got_local_pointer_input; 4583 4584 while (1) { 4585 4586 X_LOCK; 4587 XFlush_wr(dpy); 4588 X_UNLOCK; 4589 4590 /* try to induce/waitfor some more user input */ 4591 if (use_threads) { 4592 usleep(1000); 4593 } else if (drew_box && do_copyrect_drag != 1) { 4594 rfbPE(1000); 4595 } else { 4596 rfbCFD(1000); 4597 } 4598 if (bdown0 == 2) { 4599 /* 4600 * This is to just update display_button_mask 4601 * which will also update got_local_pointer_input. 4602 */ 4603 check_x11_pointer(); 4604 #if 0 4605 /* what was this for? */ 4606 Window frame; 4607 int px, py, x, y, w, h; 4608 #ifdef MACOSX 4609 if (macosx_console) { 4610 macosx_get_cursor_pos(&x, &y); 4611 } 4612 else 4613 #endif 4614 get_wm_frame_pos(&px, &py, &x, &y, &w, &h, &frame, NULL); 4615 #endif 4616 } 4617 4618 cnt++; 4619 spin += dtime(&tm); 4620 4621 if (0) fprintf(stderr, "wf-spin: %.3f\n", spin); 4622 4623 /* check for any timeouts: */ 4624 if (frame_changed) { 4625 double delay; 4626 /* max time we play this game: */ 4627 if (spin > max_spin) { 4628 if (db || db2) fprintf(stderr, " SPIN-OUT-MAX: %.3f\n", spin); 4629 break_reason = 1; 4630 break; 4631 } 4632 /* watch for pointer events slowing down: */ 4633 if (special_t1) { 4634 delay = max_spin; 4635 } else { 4636 delay = 2.0* frame_changed_spin; 4637 if (spin > 3.0 * frame_changed_spin) { 4638 delay = 1.5 * delay; 4639 } 4640 } 4641 if (spin > last_ptr + delay) { 4642 if (db || db2) fprintf(stderr, " SPIN-OUT-NOT-FAST: %.3f\n", spin); 4643 break_reason = 2; 4644 break; 4645 } 4646 } else if (got_2nd_pointer) { 4647 /* 4648 * pointer is moving, max time we wait for wm 4649 * move or resize to be detected 4650 */ 4651 if (spin > frame_changed_spin) { 4652 if (db || db2) fprintf(stderr, " SPIN-OUT-NOFRAME-SPIN: %.3f\n", spin); 4653 break_reason = 3; 4654 break; 4655 } 4656 } else { 4657 /* max time we wait for any pointer input */ 4658 if (spin > first_event_spin) { 4659 if (db || db2) fprintf(stderr, " SPIN-OUT-NO2ND_PTR: %.3f\n", spin); 4660 break_reason = 4; 4661 break; 4662 } 4663 } 4664 4665 gpi = 0; 4666 /* see if some pointer input occurred: */ 4667 if (got_pointer_input > g || 4668 (wireframe_local && (got_local_pointer_input > gd))) { 4669 4670 if (db) fprintf(stderr, " ++pointer event!! [%02d] dt: %.3f x: %d y: %d mask: %d\n", 4671 got_2nd_pointer+1, spin, cursor_x, cursor_y, button_mask); 4672 4673 g = got_pointer_input; 4674 gd = got_local_pointer_input; 4675 gpi = 1; 4676 4677 X_LOCK; 4678 XFlush_wr(dpy); 4679 X_UNLOCK; 4680 4681 /* periodically try to let the wm get moving: */ 4682 if (!frame_changed && got_2nd_pointer % 4 == 0) { 4683 if (got_2nd_pointer == 0) { 4684 usleep(50 * 1000); 4685 } else { 4686 usleep(25 * 1000); 4687 } 4688 } 4689 got_2nd_pointer++; 4690 last_ptr = spin; 4691 4692 /* 4693 * see where the pointer currently is. It may 4694 * not be our starting frame (i.e. mouse now 4695 * outside of the moving window). 4696 */ 4697 frame = 0x0; 4698 X_LOCK; 4699 4700 if (! get_wm_frame_pos(&px, &py, &x, &y, &w, &h, 4701 &frame, NULL)) { 4702 frame = 0x0; 4703 if (db) fprintf(stderr, "NO get_wm_frame_pos-2: 0x%lx\n", frame); 4704 } 4705 4706 if (frame != orig_frame) { 4707 /* see if our original frame is still there */ 4708 if (!valid_window(orig_frame, &attr, 1)) { 4709 X_UNLOCK; 4710 /* our window frame went away! */ 4711 win_gone = 1; 4712 if (db) fprintf(stderr, "FRAME-GONE: 0x%lx\n", orig_frame); 4713 break_reason = 5; 4714 break; 4715 } 4716 if (attr.map_state == IsUnmapped) { 4717 X_UNLOCK; 4718 /* our window frame is now unmapped! */ 4719 win_unmapped = 1; 4720 if (db) fprintf(stderr, "FRAME-UNMAPPED: 0x%lx\n", orig_frame); 4721 break_reason = 5; 4722 break; 4723 } 4724 4725 if (db) fprintf(stderr, "OUT-OF-FRAME: old: x: %d y: %d px: %d py: %d 0x%lx\n", x, y, px, py, frame); 4726 4727 /* new parameters for our frame */ 4728 x = attr.x; /* n.b. rootwin is parent */ 4729 y = attr.y; 4730 w = attr.width; 4731 h = attr.height; 4732 } 4733 X_UNLOCK; 4734 4735 if (db) fprintf(stderr, " frame: x: %d y: %d w: %d h: %d px: %d py: %d fr: 0x%lx\n", x, y, w, h, px, py, frame); 4736 if (db) fprintf(stderr, " MO,PT,FR: %d/%d %d/%d %d/%d\n", cursor_x - orig_cursor_x, cursor_y - orig_cursor_y, px - orig_px, py - orig_py, x - orig_x, y - orig_y); 4737 4738 if (frame_changed && frame != orig_frame) { 4739 if (db) fprintf(stderr, "CHANGED and window switch: 0x%lx\n", frame); 4740 } 4741 if (frame_changed && px - orig_px != x - orig_x) { 4742 if (db) fprintf(stderr, "MOVED and diff DX\n"); 4743 } 4744 if (frame_changed && py - orig_py != y - orig_y) { 4745 if (db) fprintf(stderr, "MOVED and diff DY\n"); 4746 } 4747 4748 /* check and see if our frame has been resized: */ 4749 if (!frame_changed && (w != orig_w || h != orig_h)) { 4750 int n; 4751 if (!already_down) { 4752 first_dt_ave += spin; 4753 first_dt_cnt++; 4754 } 4755 n = first_dt_cnt ? first_dt_cnt : 1; 4756 frame_changed = 2; 4757 4758 if (db) fprintf(stderr, "WIN RESIZE 1st-dt: %.3f\n", first_dt_ave/n); 4759 } 4760 4761 /* check and see if our frame has been moved: */ 4762 if (!frame_changed && (x != orig_x || y != orig_y)) { 4763 int n; 4764 if (!already_down) { 4765 first_dt_ave += spin; 4766 first_dt_cnt++; 4767 } 4768 n = first_dt_cnt ? first_dt_cnt : 1; 4769 frame_changed = 1; 4770 if (db) fprintf(stderr, "FRAME MOVE 1st-dt: %.3f\n", first_dt_ave/n); 4771 } 4772 } 4773 4774 /* 4775 * see if it is time to draw any or a new wireframe box 4776 */ 4777 4778 if (frame_changed) { 4779 int drawit = 0; 4780 if (x != box_x || y != box_y) { 4781 /* moved since last */ 4782 if (0) fprintf(stderr, "DRAW1 %d %d\n", x - box_x, y - box_y); 4783 drawit = 1; 4784 } else if (w != box_w || h != box_h) { 4785 /* resize since last */ 4786 drawit = 1; 4787 } 4788 if (drawit) { 4789 int doit = 0; 4790 /* 4791 * check time (to avoid too much 4792 * animations on slow machines 4793 * or links). 4794 */ 4795 if (gpi) { 4796 if (spin > last_draw + min_draw || ! drew_box) { 4797 doit = 1; 4798 } 4799 if (macosx_console && doit && !mac_skip) { 4800 if (x != box_x && y != box_y && w != box_w && h != box_h) { 4801 doit = 0; 4802 } else if (!button_mask) { 4803 doit = 0; 4804 } 4805 mac_skip++; 4806 } 4807 } else { 4808 if (drew_box && cnt > last_draw_cnt) { 4809 doit = 1; 4810 if (0) fprintf(stderr, "*** NO GPI DRAW_BOX\n"); 4811 } 4812 } 4813 4814 if (doit) { 4815 if (try_copyrect_drag && ncache > 0) { 4816 if (!ncache_copyrect) { 4817 do_copyrect_drag = 0; 4818 } else if (w != box_w || h != box_h) { 4819 do_copyrect_drag = 0; 4820 } else if (do_copyrect_drag < 0) { 4821 Window fr = orig_frame; 4822 int idx = lookup_win_index(fr); 4823 if (idx < 0) { 4824 fr = frame; 4825 idx = lookup_win_index(fr); 4826 } 4827 if (idx >= 0) { 4828 do_copyrect_drag = set_copyrect_drag(idx, fr, try_batch); 4829 if (do_copyrect_drag) { 4830 min_draw *= 0.66; 4831 } 4832 nidx = idx; 4833 } else { 4834 do_copyrect_drag = 0; 4835 } 4836 now_x = orig_x; 4837 now_y = orig_y; 4838 } 4839 if (do_copyrect_drag) { 4840 if (orig_w != w || orig_h != h) { 4841 do_copyrect_drag = 0; 4842 } 4843 } 4844 } 4845 4846 if (do_copyrect_drag <= 0) { 4847 if (ncache <= 0) { 4848 ; 4849 } else if (!drew_box && ncache_wf_raises) { 4850 Window fr = orig_frame; 4851 int idx = lookup_win_index(fr); 4852 if (idx < 0) { 4853 fr = frame; 4854 idx = lookup_win_index(fr); 4855 } 4856 if (idx >= 0) { 4857 check_copyrect_raise(idx, fr, try_batch); 4858 } 4859 } 4860 draw_box(x, y, w, h, 0); 4861 fb_push(); /* XXX Y */ 4862 rfbPE(1000); 4863 } else { 4864 #ifndef NO_NCACHE 4865 int tb = use_threads ? 0 : try_batch; 4866 do_copyrect_drag_move(orig_frame, frame, &nidx, 4867 tb, now_x, now_y, orig_w, orig_h, x, y, w, h, 4868 copyrect_drag_delay); 4869 now_x = x; 4870 now_y = y; 4871 if (copyrect_drag_delay == -1.0) { 4872 copyrect_drag_delay = 0.04; 4873 } 4874 #endif 4875 } 4876 drew_box = 1; 4877 last_wireframe = dnow(); 4878 4879 last_draw = spin; 4880 last_draw_cnt = cnt; 4881 } 4882 } 4883 box_x = x; 4884 box_y = y; 4885 box_w = w; 4886 box_h = h; 4887 } 4888 4889 /* 4890 * Now (not earlier) check if the button has come back up. 4891 * we check here to get a better location and size of 4892 * the final window. 4893 */ 4894 bdown = 0; 4895 if (button_mask) { 4896 bdown = 1; 4897 } else if (wireframe_local && display_button_mask) { 4898 bdown = 2; 4899 } 4900 if (! bdown) { 4901 if (db || db2) fprintf(stderr, "NO button_mask\n"); 4902 break_reason = 6; 4903 break; 4904 } 4905 } 4906 4907 if (! drew_box) { 4908 /* nice try, but no move or resize detected. cleanup. */ 4909 if (stack_list_num) { 4910 stack_list_num = 0; 4911 } 4912 wireframe_in_progress = 0; 4913 if (macosx_console && (break_reason == 6 || break_reason == 5)) { 4914 check_macosx_iconify(orig_frame, frame, drew_box); 4915 } 4916 return 0; 4917 } 4918 4919 /* remove the wireframe */ 4920 if (do_copyrect_drag <= 0) { 4921 draw_box(0, 0, 0, 0, 1); 4922 fb_push(); /* XXX Y */ 4923 } else { 4924 int tb = use_threads ? 0 : try_batch; 4925 do_copyrect_drag_move(orig_frame, frame, &nidx, 4926 tb, now_x, now_y, orig_w, orig_h, x, y, w, h, -1.0); 4927 fb_push_wait(0.15, FB_COPY|FB_MOD); 4928 } 4929 4930 dx = x - orig_x; 4931 dy = y - orig_y; 4932 4933 /* 4934 * see if we can apply CopyRect or CopyRegion to the change: 4935 */ 4936 if (!strcmp(wireframe_copyrect, "never")) { 4937 ; 4938 } else if (win_gone || win_unmapped) { 4939 ; 4940 } else if (skip_cr_when_scaling("wireframe")) { 4941 ; 4942 } else if (w != orig_w || h != orig_h) { 4943 if (ncache > 0) { 4944 try_to_fix_resize_su(orig_frame, orig_x, orig_y, orig_w, orig_h, x, y, w, h, try_batch); 4945 X_LOCK; 4946 clear_win_events(orig_frame, 1); 4947 if (frame != orig_frame) { 4948 clear_win_events(frame, 1); 4949 } 4950 X_UNLOCK; 4951 } 4952 } else if (dx == 0 && dy == 0) { 4953 ; 4954 } else if (do_copyrect_drag > 0) { 4955 X_LOCK; 4956 clear_win_events(NPP_nwin, 0); 4957 X_UNLOCK; 4958 } else { 4959 int spin_ms = (int) (spin * 1000 * 1000); 4960 int obscured, sent_copyrect = 0; 4961 4962 int nidx = -1; 4963 int use_batch = 0; 4964 double ntim; 4965 4966 /* 4967 * set a timescale comparable to the spin time, 4968 * but not too short or too long. 4969 */ 4970 if (spin_ms < 30) { 4971 spin_ms = 30; 4972 } else if (spin_ms > 400) { 4973 spin_ms = 400; 4974 } 4975 ntim = dnow(); 4976 4977 /* try to flush the wireframe removal: */ 4978 if (ncdb && ncache) fprintf(stderr, "\nSEND_COPYRECT %.4f %.4f\n", dnowx(), dnow() - ntim); 4979 4980 if (! fb_push_wait(0.15, FB_COPY|FB_MOD)) { 4981 4982 if (ncdb && ncache) fprintf(stderr, "FB_COPY *FAILED*, try one more... %.4f", dnow() - ntim); 4983 4984 if (! fb_push_wait(0.15, FB_COPY|FB_MOD)) { 4985 4986 if (ncdb && ncache) fprintf(stderr, "FB_COPY *FAILED* again! %.4f", dnow() - ntim); 4987 4988 } 4989 } 4990 4991 ncache_pre_portions(orig_frame, frame, &nidx, try_batch, &use_batch, 4992 orig_x, orig_y, orig_w, orig_h, x, y, w, h, ntim); 4993 4994 /* 2) try to send a clipped copyrect of translation: */ 4995 4996 if (! try_batch) { 4997 sent_copyrect = try_copyrect(orig_frame, frame, x, y, w, h, dx, dy, 4998 &obscured, NULL, 0.15, NULL); 4999 } else { 5000 try_copyrect(orig_frame, frame, x, y, w, h, dx, dy, 5001 &obscured, NULL, 0.15, &NPP_nreg); /* XXX */ 5002 sent_copyrect = 1; 5003 use_batch = 1; 5004 } 5005 5006 if ((ncache || db) && ncdb) fprintf(stderr, "sent_copyrect: %d - obs: %d frame: 0x%lx\n", sent_copyrect, obscured, frame); 5007 if (sent_copyrect) { 5008 /* try to push the changes to viewers: */ 5009 if (use_batch) { 5010 ; 5011 } else if (! obscured) { 5012 fb_push_wait(0.1, FB_COPY); 5013 } else { 5014 /* no diff for now... */ 5015 fb_push_wait(0.1, FB_COPY); 5016 } 5017 ncache_post_portions(nidx, use_batch, 5018 orig_x, orig_y, orig_w, orig_h, x, y, w, h, -1.0, ntim); 5019 X_LOCK; 5020 clear_win_events(NPP_nwin, 0); 5021 X_UNLOCK; 5022 5023 if (scaling && !use_batch) { 5024 static double last_time = 0.0; 5025 double now = dnow(), delay = 0.35; 5026 5027 fb_push_wait(0.1, FB_COPY); 5028 5029 if (now > last_time + delay) { 5030 int xt = x, yt = y; 5031 5032 if (clipshift) { 5033 xt -= coff_x; 5034 yt -= coff_y; 5035 } 5036 if (subwin) { 5037 xt -= off_x; 5038 yt -= off_y; 5039 } 5040 5041 scale_mark(xt, yt, xt+w, yt+h, 1); 5042 last_time = now; 5043 last_copyrect_fix = now; 5044 } 5045 } 5046 } 5047 } 5048 5049 if (stack_list_num) { 5050 /* clean up stack_list for next time: */ 5051 if (break_reason == 1 || break_reason == 2) { 5052 /* 5053 * save the stack list, perhaps the user has 5054 * paused with button down. 5055 */ 5056 last_save_stacklist = time(NULL); 5057 } else { 5058 stack_list_num = 0; 5059 } 5060 } 5061 5062 /* final push (for -nowirecopyrect) */ 5063 rfbPE(1000); 5064 wireframe_in_progress = 0; 5065 5066 if (1) { 5067 /* In principle no longer needed... see draw_box() */ 5068 if (frame_changed && cmap8to24 /* && multivis_count */) { 5069 /* handle -8to24 kludge, mark area and check 8bpp... */ 5070 int x1, x2, y1, y2, f = 16; 5071 x1 = nmin(box_x, orig_x) - f; 5072 y1 = nmin(box_y, orig_y) - f; 5073 x2 = nmax(box_x + box_w, orig_x + orig_w) + f; 5074 y2 = nmax(box_y + box_h, orig_y + orig_h) + f; 5075 x1 = nfix(x1, dpy_x); 5076 x2 = nfix(x2, dpy_x+1); 5077 y1 = nfix(y1, dpy_y); 5078 y2 = nfix(y2, dpy_y+1); 5079 if (0) { 5080 check_for_multivis(); 5081 mark_rect_as_modified(x1, y1, x2, y2, 0); 5082 } else { 5083 if (1) { 5084 bpp8to24(x1, y1, x2, y2); 5085 } else { 5086 bpp8to24(0, 0, dpy_x, dpy_y); 5087 } 5088 } 5089 } 5090 } 5091 5092 urgent_update = 1; 5093 if (use_xdamage) { 5094 /* DAMAGE can queue ~1000 rectangles for a move */ 5095 clear_xdamage_mark_region(NULL, 1); 5096 xdamage_scheduled_mark = dnow() + 2.0; 5097 } 5098 5099 if (macosx_console && (break_reason == 6 || break_reason == 5)) { 5100 check_macosx_iconify(orig_frame, frame, drew_box); 5101 } 5102 5103 return 1; 5104 } 5105 5106 /* 5107 * We need to handle user input, particularly pointer input, carefully. 5108 * This function is only called when non-threaded. Note that 5109 * rfbProcessEvents() only processes *one* pointer event per call, 5110 * so if we interlace it with scan_for_updates(), we can get swamped 5111 * with queued up pointer inputs. And if the pointer inputs are inducing 5112 * large changes on the screen (e.g. window drags), the whole thing 5113 * bogs down miserably and only comes back to life at some time after 5114 * one stops moving the mouse. So, to first approximation, we are trying 5115 * to eat as much user input here as we can using some hints from the 5116 * duration of the previous scan_for_updates() call (in dt). 5117 * 5118 * note: we do this even under -nofb 5119 * 5120 * return of 1 means watch_loop should short-circuit and reloop, 5121 * return of 0 means watch_loop should proceed to scan_for_updates(). 5122 * (this is for pointer_mode == 1 mode, the others do it all internally, 5123 * cnt is also only for that mode). 5124 */ 5125 5126 static void check_user_input2(double dt) { 5127 5128 int eaten = 0, miss = 0, max_eat = 50, do_flush = 1; 5129 int g, g_in; 5130 double spin = 0.0, tm; 5131 double quick_spin_fac = 0.40; 5132 double grind_spin_time = 0.175; 5133 5134 dtime0(&tm); 5135 g = g_in = got_pointer_input; 5136 if (!got_pointer_input) { 5137 return; 5138 } 5139 /* 5140 * Try for some "quick" pointer input processing. 5141 * 5142 * About as fast as we can, we try to process user input calling 5143 * rfbProcessEvents or rfbCheckFds. We do this for a time on 5144 * order of the last scan_for_updates() time, dt, but if we stop 5145 * getting user input we break out. We will also break out if 5146 * we have processed max_eat inputs. 5147 * 5148 * Note that rfbCheckFds() does not send any framebuffer updates, 5149 * so is more what we want here, although it is likely they have 5150 * all be sent already. 5151 */ 5152 while (1) { 5153 if (show_multiple_cursors) { 5154 rfbPE(1000); 5155 } else { 5156 rfbCFD(1000); 5157 } 5158 rfbCFD(0); 5159 5160 spin += dtime(&tm); 5161 5162 if (spin > quick_spin_fac * dt) { 5163 /* get out if spin time comparable to last scan time */ 5164 break; 5165 } 5166 if (got_pointer_input > g) { 5167 int i, max_extra = max_eat / 2; 5168 g = got_pointer_input; 5169 eaten++; 5170 for (i=0; i<max_extra; i++) { 5171 rfbCFD(0); 5172 if (got_pointer_input > g) { 5173 g = got_pointer_input; 5174 eaten++; 5175 } else if (i > 1) { 5176 break; 5177 } 5178 } 5179 X_LOCK; 5180 do_flush = 0; 5181 if (0) fprintf(stderr, "check_user_input2-A: XFlush %.4f\n", tm); 5182 XFlush_wr(dpy); 5183 X_UNLOCK; 5184 if (eaten < max_eat) { 5185 continue; 5186 } 5187 } else { 5188 miss++; 5189 } 5190 if (miss > 1) { /* 1 means out on 2nd miss */ 5191 break; 5192 } 5193 } 5194 if (do_flush) { 5195 X_LOCK; 5196 if (0) fprintf(stderr, "check_user_input2-B: XFlush %.4f\n", tm); 5197 XFlush_wr(dpy); 5198 X_UNLOCK; 5199 } 5200 5201 5202 /* 5203 * Probably grinding with a lot of fb I/O if dt is this large. 5204 * (need to do this more elegantly) 5205 * 5206 * Current idea is to spin our wheels here *not* processing any 5207 * fb I/O, but still processing the user input. This user input 5208 * goes to the X display and changes it, but we don't poll it 5209 * while we "rest" here for a time on order of dt, the previous 5210 * scan_for_updates() time. We also break out if we miss enough 5211 * user input. 5212 */ 5213 if (dt > grind_spin_time) { 5214 int i, ms, split = 30; 5215 double shim; 5216 5217 /* 5218 * Break up our pause into 'split' steps. We get at 5219 * most one input per step. 5220 */ 5221 shim = 0.75 * dt / split; 5222 5223 ms = (int) (1000 * shim); 5224 5225 /* cutoff how long the pause can be */ 5226 if (split * ms > 300) { 5227 ms = 300 / split; 5228 } 5229 5230 spin = 0.0; 5231 dtime0(&tm); 5232 5233 g = got_pointer_input; 5234 miss = 0; 5235 for (i=0; i<split; i++) { 5236 usleep(ms * 1000); 5237 if (show_multiple_cursors) { 5238 rfbPE(1000); 5239 } else { 5240 rfbCFD(1000); 5241 } 5242 spin += dtime(&tm); 5243 if (got_pointer_input > g) { 5244 int i, max_extra = max_eat / 2; 5245 for (i=0; i<max_extra; i++) { 5246 rfbCFD(0); 5247 if (got_pointer_input > g) { 5248 g = got_pointer_input; 5249 } else if (i > 1) { 5250 break; 5251 } 5252 } 5253 X_LOCK; 5254 if (0) fprintf(stderr, "check_user_input2-C: XFlush %.4f\n", tm); 5255 XFlush_wr(dpy); 5256 X_UNLOCK; 5257 miss = 0; 5258 } else { 5259 miss++; 5260 } 5261 g = got_pointer_input; 5262 if (miss > 2) { 5263 break; 5264 } 5265 if (1000 * spin > ms * split) { 5266 break; 5267 } 5268 } 5269 } 5270 } 5271 5272 static void check_user_input3(double dt, double dtr, int tile_diffs) { 5273 5274 int allowed_misses, miss_tweak, i, g, g_in; 5275 int last_was_miss, consecutive_misses; 5276 double spin, spin_max, tm, to, dtm; 5277 int rfb_wait_ms = 2; 5278 static double dt_cut = 0.075; 5279 int gcnt, ginput; 5280 static int first = 1; 5281 5282 if (dtr || tile_diffs) {} /* unused vars warning: */ 5283 5284 if (first) { 5285 char *p = getenv("SPIN"); 5286 if (p) { 5287 double junk; 5288 sscanf(p, "%lf,%lf", &dt_cut, &junk); 5289 } 5290 first = 0; 5291 } 5292 5293 if (!got_pointer_input) { 5294 return; 5295 } 5296 5297 5298 if (dt < dt_cut) { 5299 dt = dt_cut; /* this is to try to avoid early exit */ 5300 } 5301 spin_max = 0.5; 5302 5303 spin = 0.0; /* amount of time spinning */ 5304 allowed_misses = 10; /* number of ptr inputs we can miss */ 5305 miss_tweak = 8; 5306 last_was_miss = 0; 5307 consecutive_misses = 1; 5308 gcnt = 0; 5309 ginput = 0; 5310 5311 dtime0(&tm); 5312 to = tm; /* last time we did rfbPE() */ 5313 5314 g = g_in = got_pointer_input; 5315 5316 while (1) { 5317 int got_input = 0; 5318 5319 gcnt++; 5320 5321 if (button_mask) { 5322 drag_in_progress = 1; 5323 } 5324 5325 rfbCFD(rfb_wait_ms * 1000); 5326 5327 dtm = dtime(&tm); 5328 spin += dtm; 5329 5330 if (got_pointer_input == g) { 5331 if (last_was_miss) { 5332 consecutive_misses++; 5333 } 5334 last_was_miss = 1; 5335 } else { 5336 ginput++; 5337 if (ginput % miss_tweak == 0) { 5338 allowed_misses++; 5339 } 5340 consecutive_misses = 1; 5341 last_was_miss = 0; 5342 } 5343 5344 if (spin > spin_max) { 5345 /* get out if spin time over limit */ 5346 break; 5347 5348 } else if (got_pointer_input > g) { 5349 /* received some input, flush to display. */ 5350 got_input = 1; 5351 g = got_pointer_input; 5352 X_LOCK; 5353 XFlush_wr(dpy); 5354 X_UNLOCK; 5355 } else if (--allowed_misses <= 0) { 5356 /* too many misses */ 5357 break; 5358 } else if (consecutive_misses >=3) { 5359 /* too many misses */ 5360 break; 5361 } else { 5362 /* these are misses */ 5363 int wms = 0; 5364 if (gcnt == 1 && button_mask) { 5365 /* 5366 * missed our first input, wait 5367 * for a defer time. (e.g. on 5368 * slow link) hopefully client 5369 * will batch them. 5370 */ 5371 wms = 50; 5372 } else if (button_mask) { 5373 wms = 10; 5374 } else { 5375 } 5376 if (wms) { 5377 usleep(wms * 1000); 5378 } 5379 } 5380 } 5381 5382 if (ginput >= 2) { 5383 /* try for a couple more quick ones */ 5384 for (i=0; i<2; i++) { 5385 rfbCFD(rfb_wait_ms * 1000); 5386 } 5387 } 5388 5389 drag_in_progress = 0; 5390 } 5391 5392 int fb_update_sent(int *count) { 5393 static int last_count = 0; 5394 int sent = 0, rc = 0; 5395 rfbClientIteratorPtr i; 5396 rfbClientPtr cl; 5397 5398 if (nofb) { 5399 return 0; 5400 } 5401 5402 i = rfbGetClientIterator(screen); 5403 while( (cl = rfbClientIteratorNext(i)) ) { 5404 #if 0 5405 sent += cl->framebufferUpdateMessagesSent; 5406 #else 5407 #if LIBVNCSERVER_HAS_STATS 5408 sent += rfbStatGetMessageCountSent(cl, rfbFramebufferUpdate); 5409 #endif 5410 #endif 5411 } 5412 rfbReleaseClientIterator(i); 5413 if (sent != last_count) { 5414 rc = 1; 5415 } 5416 if (count != NULL) { 5417 *count = sent; 5418 } 5419 last_count = sent; 5420 return rc; 5421 } 5422 5423 static void check_user_input4(double dt, double dtr, int tile_diffs) { 5424 5425 int g, g_in, i, ginput, gcnt, tmp; 5426 int last_was_miss, consecutive_misses; 5427 int min_frame_size = 10; /* 10 tiles */ 5428 double spin, tm, to, tc, dtm, rpe_last; 5429 int rfb_wait_ms = 2; 5430 static double dt_cut = 0.050; 5431 static int first = 1; 5432 5433 int Btile = tile_x * tile_y * bpp/8; /* Bytes per tile */ 5434 double Ttile, dt_use; 5435 double screen_rate = 6000000.; /* 5 MB/sec */ 5436 double vnccpu_rate = 80 * 100000.; /* 20 KB/sec @ 80X compression */ 5437 double net_rate = 50000.; 5438 static double Tfac_r = 1.0, Tfac_v = 1.0, Tfac_n = 1.0, Tdelay = 0.001; 5439 static double dt_min = -1.0, dt_max = -1.0; 5440 double dt_min_fallback = 0.050; 5441 static int ssec = 0, total_calls = 0; 5442 static int push_frame = 0, update_count = 0; 5443 5444 if (first) { 5445 char *p = getenv("SPIN"); 5446 if (p) { 5447 sscanf(p, "%lf,%lf,%lf,%lf", &dt_cut, &Tfac_r, &Tfac_v, &Tfac_n); 5448 } 5449 first = 0; 5450 ssec = time(NULL); 5451 5452 if (dtr) {} /* unused vars warning: */ 5453 } 5454 5455 total_calls++; 5456 5457 if (dt_min < 0.0 || dt < dt_min) { 5458 if (dt > 0.0) { 5459 dt_min = dt; 5460 } 5461 } 5462 if (dt_min < 0.0) { 5463 /* sensible value for the very 1st call if dt = 0.0 */ 5464 dt_min = dt_min_fallback; 5465 } 5466 if (dt_max < 0.0 || dt > dt_max) { 5467 dt_max = dt; 5468 } 5469 5470 if (total_calls > 30 && dt_min > 0.0) { 5471 static int first = 1; 5472 /* 5473 * dt_min will soon be the quickest time to do 5474 * one scan_for_updates with no tiles copied. 5475 * use this (instead of copy_tiles) to estimate 5476 * screen read rate. 5477 */ 5478 screen_rate = (main_bytes_per_line * ntiles_y) / dt_min; 5479 if (first) { 5480 rfbLog("measured screen read rate: %.2f Bytes/sec\n", 5481 screen_rate); 5482 } 5483 first = 0; 5484 } 5485 5486 dtime0(&tm); 5487 5488 if (dt < dt_cut) { 5489 dt_use = dt_cut; 5490 } else { 5491 dt_use = dt; 5492 } 5493 5494 if (push_frame) { 5495 int cnt, iter = 0; 5496 double tp, push_spin = 0.0; 5497 dtime0(&tp); 5498 while (push_spin < dt_use * 0.5) { 5499 fb_update_sent(&cnt); 5500 if (cnt != update_count) { 5501 break; 5502 } 5503 /* damn, they didn't push our frame! */ 5504 iter++; 5505 rfbPE(rfb_wait_ms * 1000); 5506 5507 push_spin += dtime(&tp); 5508 } 5509 if (iter) { 5510 X_LOCK; 5511 XFlush_wr(dpy); 5512 X_UNLOCK; 5513 } 5514 push_frame = 0; 5515 update_count = 0; 5516 } 5517 5518 /* 5519 * when we first enter we require some pointer input 5520 */ 5521 if (!got_pointer_input) { 5522 return; 5523 } 5524 5525 vnccpu_rate = get_raw_rate(); 5526 5527 if ((tmp = get_read_rate()) != 0) { 5528 screen_rate = (double) tmp; 5529 } 5530 if ((tmp = get_net_rate()) != 0) { 5531 net_rate = (double) tmp; 5532 } 5533 net_rate = (vnccpu_rate/get_cmp_rate()) * net_rate; 5534 5535 if ((tmp = get_net_latency()) != 0) { 5536 Tdelay = 0.5 * ((double) tmp)/1000.; 5537 } 5538 5539 Ttile = Btile * (Tfac_r/screen_rate + Tfac_v/vnccpu_rate + Tfac_n/net_rate); 5540 5541 spin = 0.0; /* amount of time spinning */ 5542 last_was_miss = 0; 5543 consecutive_misses = 1; 5544 gcnt = 0; 5545 ginput = 0; 5546 5547 rpe_last = to = tc = tm; /* last time we did rfbPE() */ 5548 g = g_in = got_pointer_input; 5549 5550 tile_diffs = 0; /* reset our knowlegde of tile_diffs to zero */ 5551 5552 while (1) { 5553 int got_input = 0; 5554 5555 gcnt++; 5556 5557 if (button_mask) { 5558 /* this varible is used by our pointer handler */ 5559 drag_in_progress = 1; 5560 } 5561 5562 /* turn libvncserver crank to process events: */ 5563 rfbCFD(rfb_wait_ms * 1000); 5564 5565 dtm = dtime(&tm); 5566 spin += dtm; 5567 5568 if ( (gcnt == 1 && got_pointer_input > g) || tm-tc > 2*dt_min) { 5569 tile_diffs = scan_for_updates(1); 5570 tc = tm; 5571 } 5572 5573 if (got_pointer_input == g) { 5574 if (last_was_miss) { 5575 consecutive_misses++; 5576 } 5577 last_was_miss = 1; 5578 } else { 5579 ginput++; 5580 consecutive_misses = 1; 5581 last_was_miss = 0; 5582 } 5583 5584 if (tile_diffs > min_frame_size && spin > Ttile * tile_diffs + Tdelay) { 5585 /* we think we can push the frame */ 5586 push_frame = 1; 5587 fb_update_sent(&update_count); 5588 break; 5589 5590 } else if (got_pointer_input > g) { 5591 /* received some input, flush it to display. */ 5592 got_input = 1; 5593 g = got_pointer_input; 5594 X_LOCK; 5595 XFlush_wr(dpy); 5596 X_UNLOCK; 5597 5598 } else if (consecutive_misses >= 2) { 5599 /* too many misses in a row */ 5600 break; 5601 5602 } else { 5603 /* these are pointer input misses */ 5604 int wms; 5605 if (gcnt == 1 && button_mask) { 5606 /* 5607 * missed our first input, wait for 5608 * a defer time. (e.g. on slow link) 5609 * hopefully client will batch many 5610 * of them for the next read. 5611 */ 5612 wms = 50; 5613 5614 } else if (button_mask) { 5615 wms = 10; 5616 } else { 5617 wms = 0; 5618 } 5619 if (wms) { 5620 usleep(wms * 1000); 5621 } 5622 } 5623 } 5624 if (ginput >= 2) { 5625 /* try for a couple more quick ones */ 5626 for (i=0; i<2; i++) { 5627 rfbCFD(rfb_wait_ms * 1000); 5628 } 5629 } 5630 drag_in_progress = 0; 5631 } 5632 5633 int check_user_input(double dt, double dtr, int tile_diffs, int *cnt) { 5634 5635 if (rawfb_vnc_reflect) { 5636 if (got_user_input) { 5637 if (0) vnc_reflect_process_client(); 5638 } 5639 if (got_user_input && *cnt % ui_skip != 0) { 5640 /* every n-th drops thru to scan */ 5641 *cnt = *cnt + 1; 5642 return 1; /* short circuit watch_loop */ 5643 } 5644 } 5645 #ifdef MACOSX 5646 if (! macosx_console) { 5647 RAWFB_RET(0) 5648 } 5649 #else 5650 RAWFB_RET(0) 5651 #endif 5652 5653 if (use_xrecord) { 5654 int rc = check_xrecord(); 5655 /* 5656 * 0: nothing found, proceed to other user input schemes. 5657 * 1: events found, want to do a screen update now. 5658 * 2: events found, want to loop back for some more. 5659 * 3: events found, want to loop back for some more, 5660 * and not have rfbPE() called. 5661 * 5662 * For 0, we precede below, otherwise return rc-1. 5663 */ 5664 if (debug_scroll && rc > 1) fprintf(stderr, " CXR: check_user_input ret %d\n", rc - 1); 5665 if (rc == 0) { 5666 ; /* proceed below. */ 5667 } else { 5668 return rc - 1; 5669 } 5670 } 5671 5672 if (wireframe) { 5673 if (check_wireframe()) { 5674 return 0; 5675 } 5676 } 5677 5678 if (pointer_mode == 1) { 5679 if ((got_user_input || ui_skip < 0) && *cnt % ui_skip != 0) { 5680 /* every ui_skip-th drops thru to scan */ 5681 *cnt = *cnt + 1; 5682 X_LOCK; 5683 XFlush_wr(dpy); 5684 X_UNLOCK; 5685 return 1; /* short circuit watch_loop */ 5686 } else { 5687 return 0; 5688 } 5689 } 5690 if (pointer_mode >= 2 && pointer_mode <= 4) { 5691 if (got_keyboard_input) { 5692 /* 5693 * for these modes, short circuit watch_loop on 5694 * *keyboard* input. 5695 */ 5696 if (*cnt % ui_skip != 0) { 5697 *cnt = *cnt + 1; 5698 return 1; 5699 } 5700 } 5701 /* otherwise continue below with pointer input method */ 5702 } 5703 5704 if (pointer_mode == 2) { 5705 check_user_input2(dt); 5706 } else if (pointer_mode == 3) { 5707 check_user_input3(dt, dtr, tile_diffs); 5708 } else if (pointer_mode == 4) { 5709 check_user_input4(dt, dtr, tile_diffs); 5710 } 5711 return 0; 5712 } 5713 5714 #if defined(NO_NCACHE) || (NO_X11 && !defined(MACOSX)) 5715 int check_ncache(int a, int b) { 5716 if (!a || !b) {} 5717 ncache = 0; 5718 return 0; 5719 } 5720 int lookup_win_index(Window win) { 5721 if (!win) {} 5722 return -1; 5723 } 5724 int find_rect(int idx, int x, int y, int w, int h) { 5725 if (!idx || !x || !y || !w || !h) {} 5726 return 0; 5727 } 5728 void snap_old(void) { 5729 return; 5730 } 5731 int clipped(int idx) { 5732 if (!idx) {} 5733 return 0; 5734 } 5735 int bs_restore(int idx, int *nbatch, sraRegionPtr rmask, XWindowAttributes *attr, int clip, int nopad, int *valid, int verb) { 5736 if (!idx || !nbatch || !rmask || !attr || !clip || !nopad || !valid || !verb) {} 5737 return 0; 5738 } 5739 int try_to_fix_su(Window win, int idx, Window above, int *nbatch, char *mode) { 5740 if (!win || !idx || !above || !nbatch || !mode) {} 5741 return 0; 5742 } 5743 int try_to_fix_resize_su(Window orig_frame, int orig_x, int orig_y, int orig_w, int orig_h, 5744 int x, int y, int w, int h, int try_batch) { 5745 if (!orig_frame || !orig_x || !orig_y || !orig_w || !orig_h || !x || !y || !w || !h || !try_batch) {} 5746 return 0; 5747 } 5748 void set_ncache_xrootpmap(void) { 5749 return; 5750 } 5751 #else 5752 /* maybe ncache.c it if works */ 5753 5754 winattr_t* cache_list = NULL; 5755 int cache_list_num = 0; 5756 int cache_list_len = 0; 5757 5758 void snapshot_cache_list(int free_only, double allowed_age) { 5759 static double last_snap = 0.0, last_free = 0.0; 5760 double now; 5761 int num, rc, i; 5762 unsigned int ui; 5763 Window r, w; 5764 Window *list; 5765 int start = 512; 5766 5767 if (! cache_list) { 5768 cache_list = (winattr_t *) calloc(start*sizeof(winattr_t), 1); 5769 cache_list_num = 0; 5770 cache_list_len = start; 5771 } 5772 5773 dtime0(&now); 5774 if (free_only) { 5775 /* we really don't free it, just reset to zero windows */ 5776 cache_list_num = 0; 5777 last_free = now; 5778 return; 5779 } 5780 5781 if (cache_list_num && now < last_snap + allowed_age) { 5782 return; 5783 } 5784 5785 cache_list_num = 0; 5786 last_free = now; 5787 5788 #ifdef MACOSX 5789 if (! macosx_console) { 5790 RAWFB_RET_VOID 5791 } 5792 #else 5793 RAWFB_RET_VOID 5794 #endif 5795 5796 5797 #if NO_X11 && !defined(MACOSX) 5798 num = rc = i = 0; /* compiler warnings */ 5799 ui = 0; 5800 r = w = None; 5801 list = NULL; 5802 return; 5803 #else 5804 5805 X_LOCK; 5806 /* no need to trap error since rootwin */ 5807 rc = XQueryTree_wr(dpy, rootwin, &r, &w, &list, &ui); 5808 X_UNLOCK; 5809 num = (int) ui; 5810 5811 if (! rc) { 5812 cache_list_num = 0; 5813 last_free = now; 5814 last_snap = 0.0; 5815 return; 5816 } 5817 5818 last_snap = now; 5819 if (num > cache_list_len) { 5820 int n = 2*num; 5821 n = num + 3; 5822 free(cache_list); 5823 cache_list = (winattr_t *) calloc(n*sizeof(winattr_t), 1); 5824 cache_list_len = n; 5825 } 5826 for (i=0; i<num; i++) { 5827 cache_list[i].win = list[i]; 5828 cache_list[i].fetched = 0; 5829 cache_list[i].valid = 0; 5830 cache_list[i].time = now; 5831 cache_list[i].selectinput = 0; 5832 cache_list[i].vis_cnt = 0; 5833 cache_list[i].map_cnt = 0; 5834 cache_list[i].unmap_cnt = 0; 5835 cache_list[i].create_cnt = 0; 5836 cache_list[i].vis_state = -1; 5837 cache_list[i].above = None; 5838 } 5839 if (num == 0) { 5840 cache_list[0].win = None; 5841 cache_list[0].fetched = 0; 5842 cache_list[0].valid = 0; 5843 cache_list[0].time = now; 5844 cache_list[0].selectinput = 0; 5845 cache_list[0].vis_cnt = 0; 5846 cache_list[0].map_cnt = 0; 5847 cache_list[0].unmap_cnt = 0; 5848 cache_list[0].create_cnt = 0; 5849 cache_list[0].vis_state = -1; 5850 cache_list[0].above = None; 5851 num++; 5852 } 5853 5854 cache_list_num = num; 5855 5856 if (num) { 5857 X_LOCK; 5858 XFree_wr(list); 5859 X_UNLOCK; 5860 } 5861 #endif /* NO_X11 */ 5862 } 5863 5864 void quick_snap(Window *wins, int *size) { 5865 int num, rc, i; 5866 unsigned int ui; 5867 Window r, w; 5868 Window *list; 5869 5870 #ifdef MACOSX 5871 if (1 || ! macosx_console) { 5872 RAWFB_RET_VOID 5873 } 5874 #else 5875 RAWFB_RET_VOID 5876 #endif 5877 5878 5879 #if NO_X11 && !defined(MACOSX) 5880 num = rc = i = 0; /* compiler warnings */ 5881 ui = 0; 5882 r = w = None; 5883 list = NULL; 5884 return; 5885 #else 5886 5887 X_LOCK; 5888 /* no need to trap error since rootwin */ 5889 rc = XQueryTree_wr(dpy, rootwin, &r, &w, &list, &ui); 5890 X_UNLOCK; 5891 num = (int) ui; 5892 5893 if (! rc || num == 0) { 5894 *size = 0; 5895 return; 5896 } else { 5897 int m = *size; 5898 if (num < m) { 5899 m = num; 5900 } 5901 for (i=0; i < m; i++) { 5902 wins[i] = list[i]; 5903 } 5904 if (num) { 5905 X_LOCK; 5906 XFree_wr(list); 5907 X_UNLOCK; 5908 } 5909 *size = m; 5910 } 5911 #endif /* NO_X11 */ 5912 } 5913 5914 int get_bs_n(int y) { 5915 int n; 5916 for (n = 1; n < ncache; n += 2) { 5917 if (n*dpy_y <= y && y < (n+1)*dpy_y) { 5918 return n; 5919 } 5920 } 5921 return -1; 5922 } 5923 5924 #define NRECENT 32 5925 Window recent[NRECENT]; 5926 int recidx[NRECENT]; 5927 int rlast, rfree; 5928 5929 int lookup_win_index(Window win) { 5930 int k, idx = -1; 5931 int foundfree = 0; 5932 static int s1 = 0, s2 = 0, s3 = 0; 5933 5934 if (win == rootwin || win == None) { 5935 return -1; 5936 } 5937 for (k = 0; k < NRECENT; k++) { 5938 if (recent[k] == win) { 5939 int k2 = recidx[k]; 5940 if (cache_list[k2].win == win) { 5941 idx = k2; 5942 if (0) fprintf(stderr, "recentA(shortcut): %d 0x%lx\n", idx, win); 5943 s1++; 5944 break; 5945 } 5946 } 5947 } 5948 if (idx < 0) { 5949 for(k=0; k<cache_list_num; k++) { 5950 if (!foundfree && cache_list[k].win == None) { 5951 rfree = k; 5952 foundfree = 1; 5953 } 5954 if (cache_list[k].win == win) { 5955 idx = k; 5956 if (0) fprintf(stderr, "recentB(normal): %d 0x%lx\n", idx, win); 5957 s2++; 5958 break; 5959 } 5960 } 5961 if (idx >= 0) { 5962 recent[rlast] = win; 5963 recidx[rlast++] = idx; 5964 rlast = rlast % NRECENT; 5965 } 5966 } 5967 if (idx < 0) { 5968 if (ncdb) fprintf(stderr, "recentC(fail): %d 0x%lx\n", idx, win); 5969 s3++; 5970 } 5971 if (s1 + s2 + s3 >= 1000) { 5972 if (ncdb) fprintf(stderr, "lookup_win_index recent hit stats: %d/%d/%d\n", s1, s2, s3); 5973 s1 = s2 = s3 = 0; 5974 } 5975 return idx; 5976 } 5977 5978 int lookup_free_index(void) { 5979 int k; 5980 5981 if (rfree >= 0) { 5982 if (cache_list[rfree].win == None) { 5983 if (ncdb) fprintf(stderr, "lookup_freeA: %d\n", rfree); 5984 return rfree; 5985 } 5986 } 5987 rfree = -1; 5988 for(k=0; k<cache_list_num; k++) { 5989 if (cache_list[k].win == None) { 5990 rfree = k; 5991 break; 5992 } 5993 } 5994 if (rfree < 0) { 5995 if (ncdb) fprintf(stderr, "*** LOOKUP_FREE_INDEX: incrementing cache_list_num %d/%d\n", cache_list_num, cache_list_len); 5996 5997 rfree = cache_list_num++; 5998 if (rfree >= cache_list_len) { 5999 int i, n = 2*cache_list_len; 6000 winattr_t *cache_new; 6001 6002 if (ncdb) fprintf(stderr, "lookup_free_index: growing cache_list_len: %d -> %d\n", cache_list_len, n); 6003 6004 cache_new = (winattr_t *) calloc(n*sizeof(winattr_t), 1); 6005 for (i=0; i<cache_list_num-1; i++) { 6006 cache_new[i] = cache_list[i]; 6007 } 6008 cache_list_len = n; 6009 free(cache_list); 6010 cache_list = cache_new; 6011 } 6012 cache_list[rfree].win = None; 6013 cache_list[rfree].fetched = 0; 6014 cache_list[rfree].valid = 0; 6015 cache_list[rfree].time = 0.0; 6016 cache_list[rfree].selectinput = 0; 6017 cache_list[rfree].vis_cnt = 0; 6018 cache_list[rfree].map_cnt = 0; 6019 cache_list[rfree].unmap_cnt = 0; 6020 cache_list[rfree].create_cnt = 0; 6021 cache_list[rfree].vis_state = -1; 6022 cache_list[rfree].above = None; 6023 } 6024 6025 if (ncdb) fprintf(stderr, "lookup_freeB: %d\n", rfree); 6026 return rfree; 6027 } 6028 6029 #define STACKMAX 4096 6030 Window old_stack[STACKMAX]; 6031 Window new_stack[STACKMAX]; 6032 Window old_stack_map[STACKMAX]; 6033 Window new_stack_map[STACKMAX]; 6034 int old_stack_index[STACKMAX]; 6035 int old_stack_mapped[STACKMAX]; 6036 int old_stack_n = 0; 6037 int new_stack_n = 0; 6038 int old_stack_map_n = 0; 6039 int new_stack_map_n = 0; 6040 6041 void snap_old(void) { 6042 int i; 6043 old_stack_n = STACKMAX; 6044 quick_snap(old_stack, &old_stack_n); 6045 if (0) fprintf(stderr, "snap_old: %d %.4f\n", old_stack_n, dnowx()); 6046 #if 0 6047 for (i= old_stack_n - 1; i >= 0; i--) { 6048 int idx = lookup_win_index(old_stack[i]); 6049 if (idx >= 0) { 6050 if (cache_list[idx].map_state == IsViewable) { 6051 if (ncdb) fprintf(stderr, " %03d 0x%x\n", i, old_stack[i]); 6052 } 6053 } 6054 } 6055 #endif 6056 for (i=0; i < old_stack_n; i++) { 6057 old_stack_mapped[i] = -1; 6058 } 6059 } 6060 6061 void snap_old_index(void) { 6062 int i, idx; 6063 for (i=0; i < old_stack_n; i++) { 6064 idx = lookup_win_index(old_stack[i]); 6065 old_stack_index[i] = idx; 6066 if (idx >= 0) { 6067 if (cache_list[idx].map_state == IsViewable) { 6068 old_stack_mapped[i] = 1; 6069 } else { 6070 old_stack_mapped[i] = 0; 6071 } 6072 } 6073 } 6074 } 6075 6076 int lookup_old_stack_index(int ic) { 6077 int idx = old_stack_index[ic]; 6078 6079 if (idx < 0) { 6080 return -1; 6081 } 6082 if (cache_list[idx].win != old_stack[ic]) { 6083 snap_old_index(); 6084 } 6085 idx = old_stack_index[ic]; 6086 if (idx < 0 || cache_list[idx].win != old_stack[ic]) { 6087 return -1; 6088 } 6089 if (cache_list[idx].map_state == IsViewable) { 6090 old_stack_mapped[ic] = 1; 6091 } else { 6092 old_stack_mapped[ic] = 0; 6093 } 6094 return idx; 6095 } 6096 6097 #define STORE(k, w, attr) \ 6098 if (0) fprintf(stderr, "STORE(%d) = 0x%lx\n", k, w); \ 6099 cache_list[k].win = w; \ 6100 cache_list[k].fetched = 1; \ 6101 cache_list[k].valid = 1; \ 6102 cache_list[k].x = attr.x; \ 6103 cache_list[k].y = attr.y; \ 6104 cache_list[k].width = attr.width; \ 6105 cache_list[k].height = attr.height; \ 6106 cache_list[k].border_width = attr.border_width; \ 6107 cache_list[k].map_state = attr.map_state; \ 6108 cache_list[k].time = dnow(); 6109 6110 #if 0 6111 cache_list[k].width = attr.width + 2*attr.border_width; \ 6112 cache_list[k].height = attr.height + 2*attr.border_width; \ 6113 6114 #endif 6115 6116 #define CLEAR(k) \ 6117 if (0) fprintf(stderr, "CLEAR(%d)\n", k); \ 6118 cache_list[k].bs_x = -1; \ 6119 cache_list[k].bs_y = -1; \ 6120 cache_list[k].bs_w = -1; \ 6121 cache_list[k].bs_h = -1; \ 6122 cache_list[k].su_x = -1; \ 6123 cache_list[k].su_y = -1; \ 6124 cache_list[k].su_w = -1; \ 6125 cache_list[k].su_h = -1; \ 6126 cache_list[k].time = 0.0; \ 6127 cache_list[k].bs_time = 0.0; \ 6128 cache_list[k].su_time = 0.0; \ 6129 cache_list[k].vis_obs_time = 0.0; \ 6130 cache_list[k].vis_unobs_time = 0.0; 6131 6132 #define DELETE(k) \ 6133 if (0) fprintf(stderr, "DELETE(%d) = 0x%lx\n", k, cache_list[k].win); \ 6134 cache_list[k].win = None; \ 6135 cache_list[k].fetched = 0; \ 6136 cache_list[k].valid = 0; \ 6137 cache_list[k].selectinput = 0; \ 6138 cache_list[k].vis_cnt = 0; \ 6139 cache_list[k].map_cnt = 0; \ 6140 cache_list[k].unmap_cnt = 0; \ 6141 cache_list[k].create_cnt = 0; \ 6142 cache_list[k].vis_state = -1; \ 6143 cache_list[k].above = None; \ 6144 free_rect(k); /* does CLEAR(k) */ 6145 6146 static char unk[32]; 6147 6148 char *Etype(int type) { 6149 if (type == KeyPress) return "KeyPress"; 6150 if (type == KeyRelease) return "KeyRelease"; 6151 if (type == ButtonPress) return "ButtonPress"; 6152 if (type == ButtonRelease) return "ButtonRelease"; 6153 if (type == MotionNotify) return "MotionNotify"; 6154 if (type == EnterNotify) return "EnterNotify"; 6155 if (type == LeaveNotify) return "LeaveNotify"; 6156 if (type == FocusIn) return "FocusIn"; 6157 if (type == FocusOut) return "FocusOut"; 6158 if (type == KeymapNotify) return "KeymapNotify"; 6159 if (type == Expose) return "Expose"; 6160 if (type == GraphicsExpose) return "GraphicsExpose"; 6161 if (type == NoExpose) return "NoExpose"; 6162 if (type == VisibilityNotify) return "VisibilityNotify"; 6163 if (type == CreateNotify) return "CreateNotify"; 6164 if (type == DestroyNotify) return "DestroyNotify"; 6165 if (type == UnmapNotify) return "UnmapNotify"; 6166 if (type == MapNotify) return "MapNotify"; 6167 if (type == MapRequest) return "MapRequest"; 6168 if (type == ReparentNotify) return "ReparentNotify"; 6169 if (type == ConfigureNotify) return "ConfigureNotify"; 6170 if (type == ConfigureRequest) return "ConfigureRequest"; 6171 if (type == GravityNotify) return "GravityNotify"; 6172 if (type == ResizeRequest) return "ResizeRequest"; 6173 if (type == CirculateNotify) return "CirculateNotify"; 6174 if (type == CirculateRequest) return "CirculateRequest"; 6175 if (type == PropertyNotify) return "PropertyNotify"; 6176 if (type == SelectionClear) return "SelectionClear"; 6177 if (type == SelectionRequest) return "SelectionRequest"; 6178 if (type == SelectionNotify) return "SelectionNotify"; 6179 if (type == ColormapNotify) return "ColormapNotify"; 6180 if (type == ClientMessage) return "ClientMessage"; 6181 if (type == MappingNotify) return "MappingNotify"; 6182 if (type == LASTEvent) return "LASTEvent"; 6183 sprintf(unk, "Unknown %d", type); 6184 return unk; 6185 } 6186 char *VState(int state) { 6187 if (state == VisibilityFullyObscured) return "VisibilityFullyObscured"; 6188 if (state == VisibilityPartiallyObscured) return "VisibilityPartiallyObscured"; 6189 if (state == VisibilityUnobscured) return "VisibilityUnobscured"; 6190 sprintf(unk, "Unknown %d", state); 6191 return unk; 6192 } 6193 char *MState(int state) { 6194 if (state == IsViewable) return "IsViewable"; 6195 if (state == IsUnmapped) return "IsUnmapped"; 6196 sprintf(unk, "Unknown %d", state); 6197 return unk; 6198 } 6199 sraRegionPtr rect_reg[64]; 6200 sraRegionPtr zero_rects = NULL; 6201 6202 int free_rect(int idx) { 6203 int n, ok = 0; 6204 sraRegionPtr r1, r2; 6205 int x, y, w, h; 6206 6207 if (idx < 0 || idx >= cache_list_num) { 6208 if (0) fprintf(stderr, "free_rect: bad index: %d\n", idx); 6209 clean_up_exit(1); 6210 } 6211 6212 x = cache_list[idx].bs_x; 6213 y = cache_list[idx].bs_y; 6214 w = cache_list[idx].bs_w; 6215 h = cache_list[idx].bs_h; 6216 6217 if (x < 0) { 6218 CLEAR(idx); 6219 if (dnow() > last_client + 5 && ncdb) fprintf(stderr, "free_rect: already bs_x invalidated: %d bs_x: %d\n", idx, x); 6220 return 1; 6221 } 6222 6223 r2 = sraRgnCreateRect(x, y, x+w, y+h); 6224 6225 n = get_bs_n(y); 6226 if (n >= 0) { 6227 r1 = rect_reg[n]; 6228 sraRgnOr(r1, r2); 6229 ok = 1; 6230 } 6231 6232 if (zero_rects) { 6233 sraRgnOr(zero_rects, r2); 6234 x = cache_list[idx].su_x; 6235 y = cache_list[idx].su_y; 6236 w = cache_list[idx].su_w; 6237 h = cache_list[idx].su_h; 6238 if (x >= 0) { 6239 sraRgnDestroy(r2); 6240 r2 = sraRgnCreateRect(x, y, x+w, y+h); 6241 sraRgnOr(zero_rects, r2); 6242 } 6243 } 6244 sraRgnDestroy(r2); 6245 6246 CLEAR(idx); 6247 if (! ok && ncdb) fprintf(stderr, "**** free_rect: not-found %d\n", idx); 6248 return ok; 6249 } 6250 6251 int fr_BIG1 = 0; 6252 int fr_BIG2 = 0; 6253 int fr_REGION = 0; 6254 int fr_GRID = 0; 6255 int fr_EXPIRE = 0; 6256 int fr_FORCE = 0; 6257 int fr_FAIL = 0; 6258 int fr_BIG1t = 0; 6259 int fr_BIG2t = 0; 6260 int fr_REGIONt = 0; 6261 int fr_GRIDt = 0; 6262 int fr_EXPIREt = 0; 6263 int fr_FORCEt = 0; 6264 int fr_FAILt = 0; 6265 6266 void expire_rects1(int idx, int w, int h, int *x_hit, int *y_hit, int big1, int big2, int cram) { 6267 sraRegionPtr r1, r2, r3; 6268 int x = -1, y = -1, n; 6269 6270 if (*x_hit < 0) { 6271 int i, k, old[10], N = 4; 6272 double dold[10], fa, d, d1, d2, d3; 6273 int a0 = w * h, a1; 6274 6275 for (k=1; k<=N; k++) { 6276 old[k] = -1; 6277 dold[k] = -1.0; 6278 } 6279 for (i=0; i<cache_list_num; i++) { 6280 int wb = cache_list[i].bs_w; 6281 int hb = cache_list[i].bs_h; 6282 if (cache_list[i].bs_x < 0) { 6283 continue; 6284 } 6285 if (w > wb || h > hb) { 6286 continue; 6287 } 6288 if (wb == 0 || hb == 0) { 6289 continue; 6290 } 6291 if (a0 == 0) { 6292 continue; 6293 } 6294 if (i == idx) { 6295 continue; 6296 } 6297 a1 = wb * hb; 6298 fa = ((double) a1) / a0; 6299 k = (int) fa; 6300 6301 if (k < 1) k = 1; 6302 if (k > N) continue; 6303 6304 d1 = cache_list[i].time; 6305 d2 = cache_list[i].bs_time; 6306 d3 = cache_list[i].su_time; 6307 6308 d = d1; 6309 if (d2 > d) d = d2; 6310 if (d3 > d) d = d3; 6311 6312 if (dold[k] == -1.0 || d < dold[k]) { 6313 old[k] = i; 6314 dold[k] = d; 6315 } 6316 } 6317 6318 for (k=1; k<=N; k++) { 6319 if (old[k] >= 0) { 6320 int ik = old[k]; 6321 int k_x = cache_list[ik].bs_x; 6322 int k_y = cache_list[ik].bs_y; 6323 int k_w = cache_list[ik].bs_w; 6324 int k_h = cache_list[ik].bs_h; 6325 6326 if (ncdb) fprintf(stderr, ">>**--**>> found rect via EXPIRE: %d 0x%lx -- %dx%d+%d+%d %d %d -- %dx%d+%d+%d A: %d/%d\n", 6327 ik, cache_list[ik].win, w, h, x, y, *x_hit, *y_hit, k_w, k_h, k_x, k_y, k_w * k_h, w * h); 6328 6329 free_rect(ik); 6330 fr_EXPIRE++; 6331 fr_EXPIREt++; 6332 *x_hit = k_x; 6333 *y_hit = k_y; 6334 n = get_bs_n(*y_hit); 6335 if (n >= 0) { 6336 r1 = rect_reg[n]; 6337 r2 = sraRgnCreateRect(*x_hit, *y_hit, *x_hit + w, *y_hit + h); 6338 sraRgnSubtract(r1, r2); 6339 sraRgnDestroy(r2); 6340 } else { 6341 fprintf(stderr, "failure to find y n in find_rect\n"); 6342 clean_up_exit(1); 6343 } 6344 break; 6345 } 6346 } 6347 } 6348 6349 /* next, force ourselves into some corner, expiring many */ 6350 if (*x_hit < 0) { 6351 int corner_x = (int) (2 * rfac()); 6352 int corner_y = (int) (2 * rfac()); 6353 int x0 = 0, y0 = 0, i, nrand, nr = ncache/2; 6354 if (nr == 1) { 6355 nrand = 1; 6356 } else { 6357 if (! big1) { 6358 nrand = 1; 6359 } else { 6360 if (big2 && nr > 2) { 6361 nrand = 1 + (int) ((nr - 2) * rfac()); 6362 nrand += 2; 6363 } else { 6364 nrand = 1 + (int) ((nr - 1) * rfac()); 6365 nrand += 1; 6366 } 6367 } 6368 } 6369 if (nrand < 0 || nrand > nr) { 6370 nrand = nr; 6371 } 6372 if (cram && big1) { 6373 corner_x = 1; 6374 } 6375 6376 y0 += dpy_y; 6377 if (nrand > 1) { 6378 y0 += 2 * (nrand - 1) * dpy_y; 6379 } 6380 if (corner_y) { 6381 y0 += dpy_y - h; 6382 } 6383 if (corner_x) { 6384 x0 += dpy_x - w; 6385 } 6386 r1 = sraRgnCreateRect(x0, y0, x0+w, y0+h); 6387 6388 for (i=0; i<cache_list_num; i++) { 6389 int xb = cache_list[i].bs_x; 6390 int yb = cache_list[i].bs_y; 6391 int wb = cache_list[i].bs_w; 6392 int hb = cache_list[i].bs_h; 6393 if (xb < 0) { 6394 continue; 6395 } 6396 if (nabs(yb - y0) > dpy_y) { 6397 continue; 6398 } 6399 r2 = sraRgnCreateRect(xb, yb, xb+wb, yb+hb); 6400 if (sraRgnAnd(r2, r1)) { 6401 free_rect(i); 6402 } 6403 sraRgnDestroy(r2); 6404 } 6405 *x_hit = x0; 6406 *y_hit = y0; 6407 r3 = rect_reg[2*nrand-1]; 6408 sraRgnSubtract(r3, r1); 6409 sraRgnDestroy(r1); 6410 6411 if (ncdb) fprintf(stderr, ">>**--**>> found rect via FORCE: %dx%d+%d+%d -- %d %d\n", w, h, x, y, *x_hit, *y_hit); 6412 6413 fr_FORCE++; 6414 fr_FORCEt++; 6415 } 6416 } 6417 6418 void expire_rects2(int idx, int w, int h, int *x_hit, int *y_hit, int big1, int big2, int cram) { 6419 sraRegionPtr r1, r2, r3; 6420 int x = -1, y = -1, n, i, j, k; 6421 int nwgt_max = 128, nwgt = 0; 6422 int type[128]; 6423 int val[4][128]; 6424 double wgt[128], norm; 6425 int Expire = 1, Force = 2; 6426 int do_expire = 1; 6427 int do_force = 1; 6428 double now = dnow(), r; 6429 double newest = -1.0, oldest = -1.0, basetime; 6430 double map_factor = 0.25; 6431 6432 for (i=0; i<cache_list_num; i++) { 6433 double d, d1, d2; 6434 6435 d1 = cache_list[i].bs_time; 6436 d2 = cache_list[i].su_time; 6437 6438 d = d1; 6439 if (d2 > d) d = d2; 6440 6441 if (d == 0.0) { 6442 continue; 6443 } 6444 6445 if (oldest == -1.0 || d < oldest) { 6446 oldest = d; 6447 } 6448 if (newest == -1.0 || d > newest) { 6449 newest = d; 6450 } 6451 } 6452 if (newest == -1.0) { 6453 newest = now; 6454 } 6455 if (oldest == -1.0) { 6456 oldest = newest - 1800; 6457 } 6458 6459 basetime = newest + 0.1 * (newest - oldest); 6460 6461 if (do_expire) { 6462 int old[10], N = 4; 6463 double dold[10], fa, d, d1, d2; 6464 int a0 = w * h, a1; 6465 6466 for (k=1; k<=N; k++) { 6467 old[k] = -1; 6468 dold[k] = -1.0; 6469 } 6470 for (i=0; i<cache_list_num; i++) { 6471 int wb = cache_list[i].bs_w; 6472 int hb = cache_list[i].bs_h; 6473 if (cache_list[i].bs_x < 0) { 6474 continue; 6475 } 6476 if (w > wb || h > hb) { 6477 continue; 6478 } 6479 if (wb == 0 || hb == 0) { 6480 continue; 6481 } 6482 if (a0 == 0) { 6483 continue; 6484 } 6485 if (i == idx) { 6486 continue; 6487 } 6488 6489 a1 = wb * hb; 6490 fa = ((double) a1) / a0; 6491 k = (int) fa; 6492 6493 if (k < 1) k = 1; 6494 if (k > N) continue; 6495 6496 d1 = cache_list[i].bs_time; 6497 d2 = cache_list[i].su_time; 6498 6499 d = d1; 6500 if (d2 > d) d = d2; 6501 if (d == 0.0) d = oldest; 6502 6503 if (dold[k] == -1.0 || d < dold[k]) { 6504 old[k] = i; 6505 dold[k] = d; 6506 } 6507 } 6508 6509 for (k=1; k<=N; k++) { 6510 if (old[k] >= 0) { 6511 int ik = old[k]; 6512 int k_w = cache_list[ik].bs_w; 6513 int k_h = cache_list[ik].bs_h; 6514 6515 wgt[nwgt] = (basetime - dold[k]) / (k_w * k_h); 6516 if (cache_list[ik].map_state == IsViewable) { 6517 wgt[nwgt] *= map_factor; 6518 } 6519 type[nwgt] = Expire; 6520 val[0][nwgt] = ik; 6521 if (ncdb) fprintf(stderr, "Expire[%02d] %9.5f age=%9.4f area=%8d need=%8d\n", nwgt, 10000 * wgt[nwgt], basetime - dold[k], k_w * k_h, w*h); 6522 nwgt++; 6523 if (nwgt >= nwgt_max) { 6524 break; 6525 } 6526 } 6527 } 6528 } 6529 6530 /* next, force ourselves into some corner, expiring many rect */ 6531 if (do_force) { 6532 int corner_x, corner_y; 6533 int x0, y0; 6534 6535 for (n = 1; n < ncache; n += 2) { 6536 if (big1 && ncache > 2 && n == 1) { 6537 continue; 6538 } 6539 if (big2 && ncache > 4 && n <= 3) { 6540 continue; 6541 } 6542 for (corner_x = 0; corner_x < 2; corner_x++) { 6543 if (cram && big1 && corner_x == 0) { 6544 continue; 6545 } 6546 for (corner_y = 0; corner_y < 2; corner_y++) { 6547 double age = 0.0, area = 0.0, amap = 0.0, a; 6548 double d, d1, d2, score; 6549 int nc = 0; 6550 6551 x0 = 0; 6552 y0 = 0; 6553 y0 += n * dpy_y; 6554 6555 if (corner_y) { 6556 y0 += dpy_y - h; 6557 } 6558 if (corner_x) { 6559 x0 += dpy_x - w; 6560 } 6561 r1 = sraRgnCreateRect(x0, y0, x0+w, y0+h); 6562 6563 for (i=0; i<cache_list_num; i++) { 6564 int xb = cache_list[i].bs_x; 6565 int yb = cache_list[i].bs_y; 6566 int wb = cache_list[i].bs_w; 6567 int hb = cache_list[i].bs_h; 6568 6569 if (xb < 0) { 6570 continue; 6571 } 6572 if (nabs(yb - y0) > dpy_y) { 6573 continue; 6574 } 6575 6576 r2 = sraRgnCreateRect(xb, yb, xb+wb, yb+hb); 6577 if (! sraRgnAnd(r2, r1)) { 6578 sraRgnDestroy(r2); 6579 continue; 6580 } 6581 sraRgnDestroy(r2); 6582 6583 a = wb * hb; 6584 6585 d1 = cache_list[i].bs_time; 6586 d2 = cache_list[i].su_time; 6587 6588 d = d1; 6589 if (d2 > d) d = d2; 6590 if (d == 0.0) d = oldest; 6591 6592 if (cache_list[i].map_state == IsViewable) { 6593 amap += a; 6594 } 6595 area += a; 6596 age += (basetime - d) * a; 6597 nc++; 6598 } 6599 if (nc == 0) { 6600 score = 999999.9; 6601 } else { 6602 double fac; 6603 age = age / area; 6604 score = age / area; 6605 fac = 1.0 * (1.0 - amap/area) + map_factor * (amap/area); 6606 score *= fac; 6607 } 6608 6609 wgt[nwgt] = score; 6610 type[nwgt] = Force; 6611 val[0][nwgt] = n; 6612 val[1][nwgt] = x0; 6613 val[2][nwgt] = y0; 6614 if (ncdb) fprintf(stderr, "Force [%02d] %9.5f age=%9.4f area=%8d amap=%8d need=%8d\n", nwgt, 10000 * wgt[nwgt], age, (int) area, (int) amap, w*h); 6615 nwgt++; 6616 if (nwgt >= nwgt_max) break; 6617 sraRgnDestroy(r1); 6618 } 6619 if (nwgt >= nwgt_max) break; 6620 } 6621 if (nwgt >= nwgt_max) break; 6622 } 6623 } 6624 6625 if (nwgt == 0) { 6626 if (ncdb) fprintf(stderr, "nwgt=0\n"); 6627 *x_hit = -1; 6628 return; 6629 } 6630 6631 norm = 0.0; 6632 for (i=0; i < nwgt; i++) { 6633 norm += wgt[i]; 6634 } 6635 for (i=0; i < nwgt; i++) { 6636 wgt[i] /= norm; 6637 } 6638 6639 r = rfac(); 6640 6641 norm = 0.0; 6642 for (j=0; j < nwgt; j++) { 6643 norm += wgt[j]; 6644 if (ncdb) fprintf(stderr, "j=%2d acc=%.6f r=%.6f\n", j, norm, r); 6645 if (r < norm) { 6646 break; 6647 } 6648 } 6649 if (j >= nwgt) { 6650 j = nwgt - 1; 6651 } 6652 6653 if (type[j] == Expire) { 6654 int ik = val[0][j]; 6655 int k_x = cache_list[ik].bs_x; 6656 int k_y = cache_list[ik].bs_y; 6657 int k_w = cache_list[ik].bs_w; 6658 int k_h = cache_list[ik].bs_h; 6659 6660 if (ncdb) fprintf(stderr, ">>**--**>> found rect [%d] via RAN EXPIRE: %d 0x%lx -- %dx%d+%d+%d %d %d -- %dx%d+%d+%d A: %d/%d\n", 6661 get_bs_n(*y_hit), ik, cache_list[ik].win, w, h, x, y, *x_hit, *y_hit, k_w, k_h, k_x, k_y, k_w * k_h, w * h); 6662 6663 free_rect(ik); 6664 fr_EXPIRE++; 6665 fr_EXPIREt++; 6666 *x_hit = k_x; 6667 *y_hit = k_y; 6668 n = get_bs_n(*y_hit); 6669 if (n >= 0) { 6670 r1 = rect_reg[n]; 6671 r2 = sraRgnCreateRect(*x_hit, *y_hit, *x_hit + w, *y_hit + h); 6672 sraRgnSubtract(r1, r2); 6673 sraRgnDestroy(r2); 6674 } else { 6675 fprintf(stderr, "failure to find y n in find_rect\n"); 6676 clean_up_exit(1); 6677 } 6678 6679 } else if (type[j] == Force) { 6680 6681 int x0 = val[1][j]; 6682 int y0 = val[2][j]; 6683 n = val[0][j]; 6684 6685 r1 = sraRgnCreateRect(x0, y0, x0+w, y0+h); 6686 6687 for (i=0; i<cache_list_num; i++) { 6688 int xb = cache_list[i].bs_x; 6689 int yb = cache_list[i].bs_y; 6690 int wb = cache_list[i].bs_w; 6691 int hb = cache_list[i].bs_h; 6692 if (xb < 0) { 6693 continue; 6694 } 6695 if (nabs(yb - y0) > dpy_y) { 6696 continue; 6697 } 6698 r2 = sraRgnCreateRect(xb, yb, xb+wb, yb+hb); 6699 if (sraRgnAnd(r2, r1)) { 6700 free_rect(i); 6701 } 6702 sraRgnDestroy(r2); 6703 } 6704 *x_hit = x0; 6705 *y_hit = y0; 6706 r3 = rect_reg[2*n-1]; 6707 sraRgnSubtract(r3, r1); 6708 sraRgnDestroy(r1); 6709 6710 if (ncdb) fprintf(stderr, ">>**--**>> found rect [%d] via RAN FORCE: %dx%d+%d+%d -- %d %d\n", n, w, h, x, y, *x_hit, *y_hit); 6711 6712 fr_FORCE++; 6713 fr_FORCEt++; 6714 } 6715 } 6716 6717 void expire_rects(int idx, int w, int h, int *x_hit, int *y_hit, int big1, int big2, int cram) { 6718 int method = 2; 6719 if (method == 1) { 6720 expire_rects1(idx, w, h, x_hit, y_hit, big1, big2, cram); 6721 } else if (method == 2) { 6722 expire_rects2(idx, w, h, x_hit, y_hit, big1, big2, cram); 6723 } 6724 } 6725 6726 int find_rect(int idx, int x, int y, int w, int h) { 6727 sraRegionPtr r1, r2; 6728 sraRectangleIterator *iter; 6729 sraRect rt; 6730 int n, x_hit = -1, y_hit = -1; 6731 int big1 = 0, big2 = 0, cram = 0; 6732 double fac1 = 0.1, fac2 = 0.25; 6733 double last_clean = 0.0; 6734 double now = dnow(); 6735 static int nobigs = -1; 6736 6737 if (rect_reg[1] == NULL) { 6738 for (n = 1; n <= ncache; n++) { 6739 rect_reg[n] = sraRgnCreateRect(0, n * dpy_y, dpy_x, (n+1) * dpy_y); 6740 } 6741 } else if (now > last_clean + 60) { 6742 last_clean = now; 6743 for (n = 1; n < ncache; n += 2) { 6744 int i, n2 = n+1; 6745 6746 /* n */ 6747 sraRgnDestroy(rect_reg[n]); 6748 r1 = sraRgnCreateRect(0, n * dpy_y, dpy_x, (n+1) * dpy_y); 6749 for (i=0; i<cache_list_num; i++) { 6750 int bs_x = cache_list[i].bs_x; 6751 int bs_y = cache_list[i].bs_y; 6752 int bs_w = cache_list[i].bs_w; 6753 int bs_h = cache_list[i].bs_h; 6754 if (bs_x < 0) { 6755 continue; 6756 } 6757 if (get_bs_n(bs_y) != n) { 6758 continue; 6759 } 6760 r2 = sraRgnCreateRect(bs_x, bs_y, bs_x+bs_w, bs_y+bs_h); 6761 sraRgnSubtract(r1, r2); 6762 } 6763 rect_reg[n] = r1; 6764 6765 /* n+1 */ 6766 sraRgnDestroy(rect_reg[n2]); 6767 r1 = sraRgnCreateRect(0, n2 * dpy_y, dpy_x, (n2+1) * dpy_y); 6768 for (i=0; i<cache_list_num; i++) { 6769 int bs_x = cache_list[i].bs_x; 6770 int su_x = cache_list[i].su_x; 6771 int su_y = cache_list[i].su_y; 6772 int su_w = cache_list[i].su_w; 6773 int su_h = cache_list[i].su_h; 6774 if (bs_x < 0) { 6775 continue; 6776 } 6777 if (get_bs_n(su_y) != n2) { 6778 continue; 6779 } 6780 r2 = sraRgnCreateRect(su_x, su_y, su_x+su_w, su_y+su_h); 6781 sraRgnSubtract(r1, r2); 6782 } 6783 rect_reg[n2] = r1; 6784 } 6785 } 6786 6787 if (idx < 0 || idx >= cache_list_num) { 6788 if (ncdb) fprintf(stderr, "free_rect: bad index: %d\n", idx); 6789 clean_up_exit(1); 6790 } 6791 6792 cache_list[idx].bs_x = -1; 6793 cache_list[idx].su_x = -1; 6794 cache_list[idx].bs_time = 0.0; 6795 cache_list[idx].su_time = 0.0; 6796 6797 if (ncache_pad) { 6798 x -= ncache_pad; 6799 y -= ncache_pad; 6800 w += 2 * ncache_pad; 6801 h += 2 * ncache_pad; 6802 } 6803 6804 if (ncache <= 2) { 6805 cram = 1; 6806 fac2 = 0.45; 6807 } else if (ncache <= 4) { 6808 fac1 = 0.18; 6809 fac2 = 0.35; 6810 } 6811 if (macosx_console && !macosx_ncache_macmenu) { 6812 if (cram) { 6813 fac1 *= 1.5; 6814 fac2 *= 1.5; 6815 } else { 6816 fac1 *= 2.5; 6817 fac2 *= 2.5; 6818 } 6819 } 6820 if (w * h > fac1 * (dpy_x * dpy_y)) { 6821 big1 = 1; 6822 } 6823 if (w * h > fac2 * (dpy_x * dpy_y)) { 6824 big2 = 1; 6825 } 6826 6827 if (nobigs < 0) { 6828 if (getenv("NOBIGS")) { 6829 nobigs = 1; 6830 } else { 6831 nobigs = 0; 6832 } 6833 } 6834 if (nobigs) { 6835 big1 = big2 = 0; 6836 } 6837 6838 if (w > dpy_x || h > dpy_y) { 6839 if (ncdb) fprintf(stderr, ">>**--**>> BIG1 rect: %dx%d+%d+%d -- %d %d\n", w, h, x, y, x_hit, y_hit); 6840 fr_BIG1++; 6841 fr_BIG1t++; 6842 return 0; 6843 } 6844 if (w == dpy_x && h == dpy_y) { 6845 if (ncdb) fprintf(stderr, ">>**--**>> BIG1 rect: %dx%d+%d+%d -- %d %d (FULL DISPLAY)\n", w, h, x, y, x_hit, y_hit); 6846 fr_BIG1++; 6847 fr_BIG1t++; 6848 return 0; 6849 } 6850 if (cram && big2) { 6851 if (ncdb) fprintf(stderr, ">>**--**>> BIG2 rect: %dx%d+%d+%d -- %d %d\n", w, h, x, y, x_hit, y_hit); 6852 fr_BIG2++; 6853 fr_BIG2t++; 6854 return 0; 6855 } 6856 6857 /* first try individual rects of unused region */ 6858 for (n = 1; n < ncache; n += 2) { 6859 r1 = rect_reg[n]; 6860 r2 = NULL; 6861 if (big1 && n == 1 && ncache > 2) { 6862 continue; 6863 } 6864 if (big2 && n <= 3 && ncache > 4) { 6865 continue; 6866 } 6867 iter = sraRgnGetIterator(r1); 6868 while (sraRgnIteratorNext(iter, &rt)) { 6869 int rw = rt.x2 - rt.x1; 6870 int rh = rt.y2 - rt.y1; 6871 if (cram && big1 && rt.x1 < dpy_x/4) { 6872 continue; 6873 } 6874 if (rw >= w && rh >= h) { 6875 x_hit = rt.x1; 6876 y_hit = rt.y1; 6877 if (cram && big1) { 6878 x_hit = rt.x2 - w; 6879 } 6880 r2 = sraRgnCreateRect(x_hit, y_hit, x_hit + w, y_hit + h); 6881 break; 6882 } 6883 } 6884 sraRgnReleaseIterator(iter); 6885 if (r2 != NULL) { 6886 if (ncdb) fprintf(stderr, ">>**--**>> found rect via REGION: %dx%d+%d+%d -- %d %d\n", w, h, x, y, x_hit, y_hit); 6887 fr_REGION++; 6888 fr_REGIONt++; 6889 sraRgnSubtract(r1, r2); 6890 sraRgnDestroy(r2); 6891 break; 6892 } 6893 } 6894 6895 6896 /* next try moving corner to grid points */ 6897 if (x_hit < 0) { 6898 for (n = 1; n < ncache; n += 2) { 6899 int rx, ry, Nx = 48, Ny = 24, ny = n * dpy_y; 6900 6901 if (big1 && n == 1 && ncache > 2) { 6902 continue; 6903 } 6904 if (big2 && n == 3 && ncache > 4) { 6905 continue; 6906 } 6907 6908 r1 = sraRgnCreateRect(0, n * dpy_y, dpy_x, (n+1) * dpy_y); 6909 sraRgnSubtract(r1, rect_reg[n]); 6910 r2 = NULL; 6911 6912 rx = 0; 6913 while (rx + w <= dpy_x) { 6914 ry = 0; 6915 if (cram && big1 && rx < dpy_x/4) { 6916 rx += dpy_x/Nx; 6917 continue; 6918 } 6919 while (ry + h <= dpy_y) { 6920 r2 = sraRgnCreateRect(rx, ry+ny, rx + w, ry+ny + h); 6921 if (sraRgnAnd(r2, r1)) { 6922 sraRgnDestroy(r2); 6923 r2 = NULL; 6924 } else { 6925 sraRgnDestroy(r2); 6926 r2 = sraRgnCreateRect(rx, ry+ny, rx + w, ry+ny + h); 6927 x_hit = rx; 6928 y_hit = ry+ny; 6929 } 6930 ry += dpy_y/Ny; 6931 if (r2) break; 6932 } 6933 rx += dpy_x/Nx; 6934 if (r2) break; 6935 } 6936 sraRgnDestroy(r1); 6937 if (r2 != NULL) { 6938 sraRgnSubtract(rect_reg[n], r2); 6939 sraRgnDestroy(r2); 6940 if (ncdb) fprintf(stderr, ">>**--**>> found rect via GRID: %dx%d+%d+%d -- %d %d\n", w, h, x, y, x_hit, y_hit); 6941 fr_GRID++; 6942 fr_GRIDt++; 6943 break; 6944 } 6945 } 6946 } 6947 6948 /* next, try expiring the oldest/smallest used bs/su rectangle we fit in */ 6949 6950 if (x_hit < 0) { 6951 expire_rects(idx, w, h, &x_hit, &y_hit, big1, big2, cram); 6952 } 6953 6954 cache_list[idx].bs_x = x_hit; 6955 cache_list[idx].bs_y = y_hit; 6956 cache_list[idx].bs_w = w; 6957 cache_list[idx].bs_h = h; 6958 6959 cache_list[idx].su_x = x_hit; 6960 cache_list[idx].su_y = y_hit + dpy_y; 6961 cache_list[idx].su_w = w; 6962 cache_list[idx].su_h = h; 6963 6964 if (x_hit < 0) { 6965 /* bad news, can it still happen? */ 6966 if (ncdb) fprintf(stderr, ">>**--**>> *FAIL rect: %dx%d+%d+%d -- %d %d\n", w, h, x, y, x_hit, y_hit); 6967 fr_FAIL++; 6968 fr_FAILt++; 6969 return 0; 6970 } else { 6971 if (0) fprintf(stderr, ">>**--**>> found rect: %dx%d+%d+%d -- %d %d\n", w, h, x, y, x_hit, y_hit); 6972 } 6973 6974 if (zero_rects) { 6975 r1 = sraRgnCreateRect(x_hit, y_hit, x_hit+w, y_hit+h); 6976 sraRgnSubtract(zero_rects, r1); 6977 sraRgnDestroy(r1); 6978 r1 = sraRgnCreateRect(x_hit, y_hit+dpy_y, x_hit+w, y_hit+dpy_y+h); 6979 sraRgnSubtract(zero_rects, r1); 6980 sraRgnDestroy(r1); 6981 } 6982 6983 return 1; 6984 } 6985 6986 static void cache_cr(sraRegionPtr r, int dx, int dy, double d0, double d1, int *nbatch) { 6987 if (sraRgnEmpty(r)) { 6988 return; 6989 } 6990 if (nbatch == NULL) { 6991 if (!fb_push_wait(d0, FB_COPY)) { 6992 fb_push_wait(d0/2, FB_COPY); 6993 } 6994 do_copyregion(r, dx, dy, 0); 6995 if (!fb_push_wait(d1, FB_COPY)) { 6996 fb_push_wait(d1/2, FB_COPY); 6997 } 6998 } else { 6999 batch_dxs[*nbatch] = dx; 7000 batch_dys[*nbatch] = dy; 7001 batch_reg[*nbatch] = sraRgnCreateRgn(r); 7002 (*nbatch)++; 7003 } 7004 } 7005 7006 double save_delay0 = 0.02; 7007 double restore_delay0 = 0.02; 7008 double save_delay1 = 0.05; 7009 double restore_delay1 = 0.05; 7010 static double dtA, dtB; 7011 7012 int valid_wr(int idx, Window win, XWindowAttributes *attr) { 7013 #ifdef MACOSX 7014 if (macosx_console) { 7015 /* this is all to avoid animation changing WxH+X+Y... */ 7016 if (idx >= 0) { 7017 int rc = valid_window(win, attr, 1); 7018 attr->x = cache_list[idx].x; 7019 attr->y = cache_list[idx].y; 7020 attr->width = cache_list[idx].width; 7021 attr->height = cache_list[idx].height; 7022 return rc; 7023 } else { 7024 return valid_window(win, attr, 1); 7025 } 7026 } 7027 #else 7028 if (!idx) {} 7029 #endif 7030 return valid_window(win, attr, 1); 7031 } 7032 7033 int clipped(int idx) { 7034 int ic; 7035 sraRegionPtr r0, r1, r2; 7036 int x1, y1, w1, h1; 7037 Window win; 7038 int clip = 0; 7039 7040 if (idx < 0) { 7041 return 0; 7042 } 7043 r0 = sraRgnCreateRect(0, 0, dpy_x, dpy_y); 7044 7045 x1 = cache_list[idx].x; 7046 y1 = cache_list[idx].y; 7047 w1 = cache_list[idx].width; 7048 h1 = cache_list[idx].height; 7049 7050 win = cache_list[idx].win; 7051 7052 r1 = sraRgnCreateRect(x1, y1, x1+w1, y1+h1); 7053 sraRgnAnd(r1, r0); 7054 7055 for (ic = old_stack_n - 1; ic >= 0; ic--) { 7056 int xc, yc, wc, hc, idx2; 7057 7058 if (old_stack[ic] == win) { 7059 break; 7060 } 7061 if (old_stack_mapped[ic] == 0) { 7062 continue; 7063 } 7064 idx2 = lookup_old_stack_index(ic); 7065 if (idx2 < 0) { 7066 continue; 7067 } 7068 if (cache_list[idx2].win == win) { 7069 break; 7070 } 7071 if (cache_list[idx2].map_state != IsViewable) { 7072 continue; 7073 } 7074 xc = cache_list[idx2].x; 7075 yc = cache_list[idx2].y; 7076 wc = cache_list[idx2].width; 7077 hc = cache_list[idx2].height; 7078 7079 r2 = sraRgnCreateRect(xc, yc, xc+wc, yc+hc); 7080 sraRgnAnd(r2, r0); 7081 if (sraRgnAnd(r2, r1)) { 7082 if (0) fprintf(stderr, "clip[0x%lx]: 0x%lx, %d/%d\n", win, cache_list[idx2].win, ic, idx2); 7083 clip = 1; 7084 } 7085 sraRgnDestroy(r2); 7086 if (clip) { 7087 break; 7088 } 7089 } 7090 sraRgnDestroy(r0); 7091 sraRgnDestroy(r1); 7092 if (0) fprintf(stderr, "clip[0x%lx]: %s\n", win, clip ? "clipped" : "no-clipped"); 7093 return clip; 7094 } 7095 7096 void clip_region(sraRegionPtr r, Window win) { 7097 int ic, idx2; 7098 sraRegionPtr r1; 7099 for (ic = old_stack_n - 1; ic >= 0; ic--) { 7100 int xc, yc, wc, hc; 7101 7102 if (0) fprintf(stderr, "----[0x%lx]: 0x%lx, %d %d\n", win, old_stack[ic], ic, old_stack_mapped[ic]); 7103 if (old_stack[ic] == win) { 7104 break; 7105 } 7106 if (old_stack_mapped[ic] == 0) { 7107 continue; 7108 } 7109 idx2 = lookup_old_stack_index(ic); 7110 if (idx2 < 0) { 7111 continue; 7112 } 7113 if (cache_list[idx2].win == win) { 7114 break; 7115 } 7116 if (cache_list[idx2].map_state != IsViewable) { 7117 continue; 7118 } 7119 xc = cache_list[idx2].x; 7120 yc = cache_list[idx2].y; 7121 wc = cache_list[idx2].width; 7122 hc = cache_list[idx2].height; 7123 r1 = sraRgnCreateRect(xc, yc, xc+wc, yc+hc); 7124 if (sraRgnAnd(r1, r)) { 7125 sraRgnSubtract(r, r1); 7126 if (0) fprintf(stderr, "clip[0x%lx]: 0x%lx, %d/%d\n", win, cache_list[idx2].win, ic, idx2); 7127 } 7128 sraRgnDestroy(r1); 7129 } 7130 } 7131 7132 int bs_save(int idx, int *nbatch, XWindowAttributes *attr, int clip, int only_if_tracking, int *valid, int verb) { 7133 Window win = cache_list[idx].win; 7134 int x1, y1, w1, h1; 7135 int x2, y2, w2, h2; 7136 int x, y, w, h; 7137 int dx, dy, rc = 1; 7138 sraRegionPtr r, r0; 7139 7140 x1 = cache_list[idx].x; 7141 y1 = cache_list[idx].y; 7142 w1 = cache_list[idx].width; 7143 h1 = cache_list[idx].height; 7144 7145 if (ncdb && verb) fprintf(stderr, "backingstore save: 0x%lx %3d clip=%d\n", win, idx, clip); 7146 7147 X_LOCK; 7148 if (*valid) { 7149 attr->x = x1; 7150 attr->y = y1; 7151 attr->width = w1; 7152 attr->height = h1; 7153 } else if (! valid_wr(idx, win, attr)) { 7154 if (ncdb) fprintf(stderr, "bs_save: not a valid X window: 0x%lx\n", win); 7155 X_UNLOCK; 7156 *valid = 0; 7157 cache_list[idx].valid = 0; 7158 return 0; 7159 } else { 7160 *valid = 1; 7161 } 7162 X_UNLOCK; 7163 7164 if (only_if_tracking && cache_list[idx].bs_x < 0) { 7165 return 0; 7166 } 7167 7168 x2 = attr->x; 7169 y2 = attr->y; 7170 w2 = attr->width; 7171 h2 = attr->height; 7172 7173 if (cache_list[idx].bs_x < 0) { 7174 rc = find_rect(idx, x2, y2, w2, h2); 7175 } else if (w2 > cache_list[idx].bs_w || h2 > cache_list[idx].bs_h) { 7176 free_rect(idx); 7177 rc = find_rect(idx, x2, y2, w2, h2); 7178 } 7179 7180 x = cache_list[idx].bs_x; 7181 y = cache_list[idx].bs_y; 7182 w = cache_list[idx].bs_w; 7183 h = cache_list[idx].bs_h; 7184 7185 if (x < 0 || ! rc) { 7186 if (ncdb) fprintf(stderr, "BS_save: FAIL FOR: %d\n", idx); 7187 return 0; 7188 } 7189 7190 if (ncache_pad) { 7191 x2 -= ncache_pad; 7192 y2 -= ncache_pad; 7193 w2 += 2 * ncache_pad; 7194 h2 += 2 * ncache_pad; 7195 } 7196 7197 if (clipshift) { 7198 x2 -= coff_x; 7199 y2 -= coff_y; 7200 } 7201 7202 r0 = sraRgnCreateRect(0, 0, dpy_x, dpy_y); 7203 r = sraRgnCreateRect(x2, y2, x2+w2, y2+h2); 7204 sraRgnAnd(r, r0); 7205 7206 if (clip) { 7207 clip_region(r, win); 7208 } 7209 7210 if (sraRgnEmpty(r)) { 7211 if (ncdb && verb) fprintf(stderr, "BS_save: Region Empty: %d\n", idx); 7212 sraRgnDestroy(r0); 7213 sraRgnDestroy(r); 7214 return 0; 7215 } 7216 7217 dx = x - x2; 7218 dy = y - y2; 7219 7220 sraRgnOffset(r, dx, dy); 7221 7222 dtA = dnowx(); 7223 if (ncdb && verb) fprintf(stderr, "BS_save: %.4f %d dx=%d dy=%d\n", dtA, idx, dx, dy); 7224 if (w2 > 0 && h2 > 0) { 7225 cache_cr(r, dx, dy, save_delay0, save_delay1, nbatch); 7226 } 7227 dtB = dnowx(); 7228 if (ncdb && verb) fprintf(stderr, "BS_save: %.4f %.2f %d done. %dx%d+%d+%d %dx%d+%d+%d %.2f %.2f\n", dtB, dtB-dtA, idx, w1, h1, x1, y1, w2, h2, x2, y2, cache_list[idx].bs_time - x11vnc_start, dnowx()); 7229 7230 sraRgnDestroy(r0); 7231 sraRgnDestroy(r); 7232 7233 last_bs_save = cache_list[idx].bs_time = dnow(); 7234 7235 return 1; 7236 } 7237 7238 int su_save(int idx, int *nbatch, XWindowAttributes *attr, int clip, int *valid, int verb) { 7239 Window win = cache_list[idx].win; 7240 int x1, y1, w1, h1; 7241 int x2, y2, w2, h2; 7242 int x, y, w, h; 7243 int dx, dy, rc = 1; 7244 sraRegionPtr r, r0; 7245 7246 if (ncdb && verb) fprintf(stderr, "save-unders save: 0x%lx %3d \n", win, idx); 7247 7248 x1 = cache_list[idx].x; 7249 y1 = cache_list[idx].y; 7250 w1 = cache_list[idx].width; 7251 h1 = cache_list[idx].height; 7252 7253 X_LOCK; 7254 if (*valid) { 7255 attr->x = x1; 7256 attr->y = y1; 7257 attr->width = w1; 7258 attr->height = h1; 7259 } else if (! valid_wr(idx, win, attr)) { 7260 if (ncdb) fprintf(stderr, "su_save: not a valid X window: 0x%lx\n", win); 7261 X_UNLOCK; 7262 *valid = 0; 7263 cache_list[idx].valid = 0; 7264 return 0; 7265 } else { 7266 *valid = 1; 7267 } 7268 X_UNLOCK; 7269 7270 x2 = attr->x; 7271 y2 = attr->y; 7272 w2 = attr->width; 7273 h2 = attr->height; 7274 7275 if (cache_list[idx].bs_x < 0) { 7276 rc = find_rect(idx, x2, y2, w2, h2); 7277 } else if (w2 > cache_list[idx].su_w || h2 > cache_list[idx].su_h) { 7278 free_rect(idx); 7279 rc = find_rect(idx, x2, y2, w2, h2); 7280 } 7281 x = cache_list[idx].su_x; 7282 y = cache_list[idx].su_y; 7283 w = cache_list[idx].su_w; 7284 h = cache_list[idx].su_h; 7285 7286 if (x < 0 || ! rc) { 7287 if (ncdb) fprintf(stderr, "SU_save: FAIL FOR: %d\n", idx); 7288 return 0; 7289 } 7290 7291 if (ncache_pad) { 7292 x2 -= ncache_pad; 7293 y2 -= ncache_pad; 7294 w2 += 2 * ncache_pad; 7295 h2 += 2 * ncache_pad; 7296 } 7297 7298 if (clipshift) { 7299 x2 -= coff_x; 7300 y2 -= coff_y; 7301 } 7302 7303 r0 = sraRgnCreateRect(0, 0, dpy_x, dpy_y); 7304 r = sraRgnCreateRect(x2, y2, x2+w2, y2+h2); 7305 sraRgnAnd(r, r0); 7306 7307 if (clip) { 7308 clip_region(r, win); 7309 } 7310 7311 if (sraRgnEmpty(r)) { 7312 if (ncdb && verb) fprintf(stderr, "SU_save: Region Empty: %d\n", idx); 7313 sraRgnDestroy(r0); 7314 sraRgnDestroy(r); 7315 return 0; 7316 } 7317 7318 7319 dx = x - x2; 7320 dy = y - y2; 7321 7322 sraRgnOffset(r, dx, dy); 7323 7324 dtA = dnowx(); 7325 if (ncdb && verb) fprintf(stderr, "SU_save: %.4f %d dx=%d dy=%d\n", dtA, idx, dx, dy); 7326 if (w2 > 0 && h2 > 0) { 7327 cache_cr(r, dx, dy, save_delay0, save_delay1, nbatch); 7328 } 7329 dtB = dnowx(); 7330 if (ncdb && verb) fprintf(stderr, "SU_save: %.4f %.2f %d done. %dx%d+%d+%d %dx%d+%d+%d %.2f %.2f\n", dtB, dtB-dtA, idx, w1, h1, x1, y1, w2, h2, x2, y2, cache_list[idx].su_time - x11vnc_start, dnowx()); 7331 7332 sraRgnDestroy(r0); 7333 sraRgnDestroy(r); 7334 7335 last_su_save = cache_list[idx].su_time = dnow(); 7336 7337 return 1; 7338 } 7339 7340 int bs_restore(int idx, int *nbatch, sraRegionPtr rmask, XWindowAttributes *attr, int clip, int nopad, int *valid, int verb) { 7341 Window win = cache_list[idx].win; 7342 int x1, y1, w1, h1; 7343 int x2, y2, w2, h2; 7344 int x, y, w, h; 7345 int dx, dy; 7346 sraRegionPtr r, r0; 7347 7348 if (ncdb && verb) fprintf(stderr, "backingstore restore: 0x%lx %3d \n", win, idx); 7349 7350 x1 = cache_list[idx].x; 7351 y1 = cache_list[idx].y; 7352 w1 = cache_list[idx].width; 7353 h1 = cache_list[idx].height; 7354 7355 X_LOCK; 7356 if (*valid) { 7357 attr->x = x1; 7358 attr->y = y1; 7359 attr->width = w1; 7360 attr->height = h1; 7361 } else if (! valid_wr(idx, win, attr)) { 7362 if (ncdb) fprintf(stderr, "BS_restore: not a valid X window: 0x%lx\n", win); 7363 *valid = 0; 7364 X_UNLOCK; 7365 return 0; 7366 } else { 7367 *valid = 1; 7368 } 7369 X_UNLOCK; 7370 7371 x2 = attr->x; 7372 y2 = attr->y; 7373 w2 = attr->width; 7374 h2 = attr->height; 7375 7376 x = cache_list[idx].bs_x; 7377 y = cache_list[idx].bs_y; 7378 w = cache_list[idx].bs_w; 7379 h = cache_list[idx].bs_h; 7380 7381 if (x < 0 || cache_list[idx].bs_time == 0.0) { 7382 return 0; 7383 } 7384 7385 if (ncache_pad) { 7386 if (nopad) { 7387 x += ncache_pad; 7388 y += ncache_pad; 7389 w -= 2 * ncache_pad; 7390 h -= 2 * ncache_pad; 7391 } else { 7392 x2 -= ncache_pad; 7393 y2 -= ncache_pad; 7394 w2 += 2 * ncache_pad; 7395 h2 += 2 * ncache_pad; 7396 } 7397 } 7398 7399 if (clipshift) { 7400 x2 -= coff_x; 7401 y2 -= coff_y; 7402 } 7403 7404 if (w2 > w) { 7405 w2 = w; 7406 } 7407 if (h2 > h) { 7408 h2 = h; 7409 } 7410 7411 r0 = sraRgnCreateRect(0, 0, dpy_x, dpy_y); 7412 r = sraRgnCreateRect(x, y, x+w2, y+h2); 7413 7414 dx = x2 - x; 7415 dy = y2 - y; 7416 7417 sraRgnOffset(r, dx, dy); 7418 sraRgnAnd(r, r0); 7419 7420 if (clip) { 7421 clip_region(r, win); 7422 } 7423 if (rmask != NULL) { 7424 sraRgnAnd(r, rmask); 7425 } 7426 7427 dtA = dnowx(); 7428 if (ncdb && verb) fprintf(stderr, "BS_rest: %.4f %d dx=%d dy=%d\n", dtA, idx, dx, dy); 7429 if (w2 > 0 && h2 > 0) { 7430 cache_cr(r, dx, dy, restore_delay0, restore_delay1, nbatch); 7431 } 7432 dtB = dnowx(); 7433 if (ncdb && verb) fprintf(stderr, "BS_rest: %.4f %.2f %d done. %dx%d+%d+%d %dx%d+%d+%d %.2f %.2f\n", dtB, dtB-dtA, idx, w1, h1, x1, y1, w2, h2, x2, y2, cache_list[idx].bs_time - x11vnc_start, dnowx()); 7434 7435 sraRgnDestroy(r0); 7436 sraRgnDestroy(r); 7437 7438 last_bs_restore = dnow(); 7439 7440 return 1; 7441 } 7442 7443 int su_restore(int idx, int *nbatch, sraRegionPtr rmask, XWindowAttributes *attr, int clip, int nopad, int *valid, int verb) { 7444 Window win = cache_list[idx].win; 7445 int x1, y1, w1, h1; 7446 int x2 = 0, y2 = 0, w2 = 0, h2 = 0; 7447 int x, y, w, h; 7448 int dx, dy; 7449 sraRegionPtr r, r0; 7450 7451 if (ncdb && verb) fprintf(stderr, "save-unders restore: 0x%lx %3d \n", win, idx); 7452 7453 x1 = cache_list[idx].x; 7454 y1 = cache_list[idx].y; 7455 w1 = cache_list[idx].width; 7456 h1 = cache_list[idx].height; 7457 7458 X_LOCK; 7459 if (*valid) { 7460 attr->x = x1; 7461 attr->y = y1; 7462 attr->width = w1; 7463 attr->height = h1; 7464 x2 = attr->x; 7465 y2 = attr->y; 7466 w2 = attr->width; 7467 h2 = attr->height; 7468 } else if (! valid_wr(idx, win, attr)) { 7469 if (ncdb) fprintf(stderr, "SU_restore: not a valid X window: 0x%lx\n", win); 7470 *valid = 0; 7471 x2 = x1; 7472 y2 = y1; 7473 w2 = w1; 7474 h2 = h1; 7475 } else { 7476 x2 = attr->x; 7477 y2 = attr->y; 7478 w2 = attr->width; 7479 h2 = attr->height; 7480 *valid = 1; 7481 } 7482 X_UNLOCK; 7483 7484 x = cache_list[idx].su_x; 7485 y = cache_list[idx].su_y; 7486 w = cache_list[idx].su_w; 7487 h = cache_list[idx].su_h; 7488 7489 if (x < 0 || cache_list[idx].bs_x < 0 || cache_list[idx].su_time == 0.0) { 7490 if (ncdb) fprintf(stderr, "SU_rest: su_x/bs_x/su_time: %d %d %.3f\n", x, cache_list[idx].bs_x, cache_list[idx].su_time); 7491 return 0; 7492 } 7493 7494 if (ncache_pad) { 7495 if (nopad) { 7496 x += ncache_pad; 7497 y += ncache_pad; 7498 w -= 2 * ncache_pad; 7499 h -= 2 * ncache_pad; 7500 } else { 7501 x2 -= ncache_pad; 7502 y2 -= ncache_pad; 7503 w2 += 2 * ncache_pad; 7504 h2 += 2 * ncache_pad; 7505 } 7506 } 7507 7508 if (clipshift) { 7509 x2 -= coff_x; 7510 y2 -= coff_y; 7511 } 7512 7513 if (w2 > w) { 7514 w2 = w; 7515 } 7516 if (h2 > h) { 7517 h2 = h; 7518 } 7519 7520 r0 = sraRgnCreateRect(0, 0, dpy_x, dpy_y); 7521 r = sraRgnCreateRect(x, y, x+w2, y+h2); 7522 7523 dx = x2 - x; 7524 dy = y2 - y; 7525 7526 sraRgnOffset(r, dx, dy); 7527 sraRgnAnd(r, r0); 7528 7529 if (clip) { 7530 clip_region(r, win); 7531 } 7532 if (rmask != NULL) { 7533 sraRgnAnd(r, rmask); 7534 } 7535 7536 dtA = dnowx(); 7537 if (ncdb && verb) fprintf(stderr, "SU_rest: %.4f %d dx=%d dy=%d\n", dtA, idx, dx, dy); 7538 if (w2 > 0 && h2 > 0) { 7539 cache_cr(r, dx, dy, restore_delay0, restore_delay1, nbatch); 7540 } 7541 dtB = dnowx(); 7542 if (ncdb && verb) fprintf(stderr, "SU_rest: %.4f %.2f %d done. %dx%d+%d+%d %dx%d+%d+%d %.2f %.2f\n", dtB, dtB-dtA, idx, w1, h1, x1, y1, w2, h2, x2, y2, cache_list[idx].su_time - x11vnc_start, dnowx()); 7543 7544 sraRgnDestroy(r0); 7545 sraRgnDestroy(r); 7546 7547 last_su_restore = dnow(); 7548 7549 return 1; 7550 } 7551 7552 void check_zero_rects(void) { 7553 sraRect rt; 7554 sraRectangleIterator *iter; 7555 if (! zero_rects) { 7556 zero_rects = sraRgnCreate(); 7557 } 7558 if (sraRgnEmpty(zero_rects)) { 7559 return; 7560 } 7561 7562 iter = sraRgnGetIterator(zero_rects); 7563 while (sraRgnIteratorNext(iter, &rt)) { 7564 zero_fb(rt.x1, rt.y1, rt.x2, rt.y2); 7565 mark_rect_as_modified(rt.x1, rt.y1, rt.x2, rt.y2, 0); 7566 } 7567 sraRgnReleaseIterator(iter); 7568 sraRgnMakeEmpty(zero_rects); 7569 } 7570 7571 void block_stats(void) { 7572 int n, k, s1, s2; 7573 static int t = -1; 7574 int vcnt, icnt, tcnt, vtot = 0, itot = 0, ttot = 0; 7575 t++; 7576 for (n = 1; n < ncache+1; n += 2) { 7577 double area = 0.0, frac; 7578 vcnt = 0; 7579 icnt = 0; 7580 tcnt = 0; 7581 for(k=0; k<cache_list_num; k++) { 7582 XWindowAttributes attr; 7583 int x = cache_list[k].bs_x; 7584 int y = cache_list[k].bs_y; 7585 int w = cache_list[k].bs_w; 7586 int h = cache_list[k].bs_h; 7587 int rc = 0; 7588 Window win = cache_list[k].win; 7589 7590 if (win == None) { 7591 continue; 7592 } 7593 if (n == 1) { 7594 X_LOCK; 7595 rc = valid_window(win, &attr, 1); 7596 X_UNLOCK; 7597 if (rc) { 7598 vtot++; 7599 } else { 7600 itot++; 7601 } 7602 if (x >= 0) { 7603 ttot++; 7604 } 7605 } 7606 if (y < n*dpy_y || y > (n+1)*dpy_y) { 7607 continue; 7608 } 7609 if (n != 1) { 7610 X_LOCK; 7611 rc = valid_window(win, &attr, 1); 7612 X_UNLOCK; 7613 } 7614 if (rc) { 7615 vcnt++; 7616 } else { 7617 icnt++; 7618 } 7619 if (x >= 0) { 7620 tcnt++; 7621 } 7622 if (x < 0) { 7623 continue; 7624 } 7625 area += cache_list[k].width * cache_list[k].height; 7626 if (! rc && ! macosx_console) { 7627 char *u = getenv("USER"); 7628 if (u && !strcmp(u, "runge")) fprintf(stderr, "\a"); 7629 if (ncdb) fprintf(stderr, "\n *** UNRECLAIMED WINDOW: 0x%lx %dx%d+%d+%d\n\n", win, w, h, x, y); 7630 DELETE(k); 7631 } 7632 if (t < 3 || (t % 4) == 0 || hack_val || macosx_console) { 7633 double t1 = cache_list[k].su_time; 7634 double t2 = cache_list[k].bs_time; 7635 if (t1 > 0.0) {t1 = dnow() - t1;} else {t1 = -1.0;} 7636 if (t2 > 0.0) {t2 = dnow() - t2;} else {t2 = -1.0;} 7637 if (ncdb) fprintf(stderr, " [%02d] %04d 0x%08lx bs: %04dx%04d+%04d+%05d vw: %04dx%04d+%04d+%04d cl: %04dx%04d+%04d+%04d map=%d su=%9.3f bs=%9.3f cnt=%d/%d\n", 7638 n, k, win, w, h, x, y, attr.width, attr.height, attr.x, attr.y, 7639 cache_list[k].width, cache_list[k].height, cache_list[k].x, cache_list[k].y, 7640 attr.map_state == IsViewable, t1, t2, cache_list[k].create_cnt, cache_list[k].map_cnt); 7641 } 7642 } 7643 frac = area /(dpy_x * dpy_y); 7644 if (ncdb) fprintf(stderr, "block[%02d] %.3f %8d trak/val/inval: %d/%d/%d of %d\n", n, frac, (int) area, tcnt, vcnt, icnt, vcnt+icnt); 7645 } 7646 7647 if (ncdb) fprintf(stderr, "\n"); 7648 if (ncdb) fprintf(stderr, "block: trak/val/inval %d/%d/%d of %d\n", ttot, vtot, itot, vtot+itot); 7649 7650 s1 = fr_REGION + fr_GRID + fr_EXPIRE + fr_FORCE + fr_BIG1 + fr_BIG2 + fr_FAIL; 7651 s2 = fr_REGIONt + fr_GRIDt + fr_EXPIREt + fr_FORCEt + fr_BIG1t + fr_BIG2t + fr_FAILt; 7652 if (ncdb) fprintf(stderr, "\n"); 7653 if (ncdb) fprintf(stderr, "find_rect: REGION/GRID/EXPIRE/FORCE - BIG1/BIG2/FAIL %d/%d/%d/%d - %d/%d/%d of %d\n", 7654 fr_REGION, fr_GRID, fr_EXPIRE, fr_FORCE, fr_BIG1, fr_BIG2, fr_FAIL, s1); 7655 if (ncdb) fprintf(stderr, " totals: %d/%d/%d/%d - %d/%d/%d of %d\n", 7656 fr_REGIONt, fr_GRIDt, fr_EXPIREt, fr_FORCEt, fr_BIG1t, fr_BIG2t, fr_FAILt, s2); 7657 7658 fr_BIG1 = 0; 7659 fr_BIG2 = 0; 7660 fr_REGION = 0; 7661 fr_GRID = 0; 7662 fr_EXPIRE = 0; 7663 fr_FORCE = 0; 7664 fr_FAIL = 0; 7665 if (ncdb) fprintf(stderr, "\n"); 7666 } 7667 7668 #define NSCHED 128 7669 Window sched_bs[NSCHED]; 7670 double sched_tm[NSCHED]; 7671 double last_sched_bs = 0.0; 7672 7673 #define SCHED(w, v) \ 7674 { \ 7675 int k, save = -1, empty = 1; \ 7676 for (k=0; k < NSCHED; k++) { \ 7677 if (sched_bs[k] == None) { \ 7678 save = k; \ 7679 } \ 7680 if (sched_bs[k] == w) { \ 7681 save = k; \ 7682 empty = 0; \ 7683 break; \ 7684 } \ 7685 } \ 7686 if (save >= 0) { \ 7687 sched_bs[save] = w; \ 7688 if (empty) { \ 7689 sched_tm[save] = dnow(); \ 7690 if (v && ncdb) fprintf(stderr, "SCHED: %d %f\n", save, dnowx()); \ 7691 } \ 7692 } \ 7693 } 7694 7695 void xselectinput(Window w, unsigned long evmask, int sync) { 7696 #if NO_X11 7697 trapped_xerror = 0; 7698 trapped_xioerror = 0; 7699 if (!evmask) {} 7700 #else 7701 XErrorHandler old_handler1; 7702 XIOErrorHandler old_handler2; 7703 7704 if (macosx_console || !dpy) { 7705 return; 7706 } 7707 7708 old_handler1 = XSetErrorHandler(trap_xerror); 7709 old_handler2 = XSetIOErrorHandler(trap_xioerror); 7710 trapped_xerror = 0; 7711 trapped_xioerror = 0; 7712 7713 XSelectInput(dpy, w, evmask); 7714 7715 /* 7716 * We seem to need to synchronize right away since the window 7717 * might go away quickly. 7718 */ 7719 if (sync) { 7720 XSync(dpy, False); 7721 } else { 7722 XFlush_wr(dpy); 7723 } 7724 7725 XSetErrorHandler(old_handler1); 7726 XSetIOErrorHandler(old_handler2); 7727 #endif 7728 7729 if (trapped_xerror) { 7730 if (ncdb) fprintf(stderr, "XSELECTINPUT: trapped X Error."); 7731 } 7732 if (trapped_xioerror) { 7733 if (ncdb) fprintf(stderr, "XSELECTINPUT: trapped XIO Error."); 7734 } 7735 if (sync && ncdb) fprintf(stderr, "XSELECTINPUT: 0x%lx sync=%d err=%d/%d\n", w, sync, trapped_xerror, trapped_xioerror); 7736 } 7737 7738 Bool xcheckmaskevent(Display *d, long mask, XEvent *ev) { 7739 #ifdef MACOSX 7740 if (macosx_console) { 7741 if (macosx_checkevent(ev)) { 7742 return True; 7743 } else { 7744 return False; 7745 } 7746 } 7747 #endif 7748 RAWFB_RET(False); 7749 7750 #if NO_X11 7751 if (!d || !mask) {} 7752 return False; 7753 #else 7754 return XCheckMaskEvent(d, mask, ev); 7755 #endif 7756 } 7757 7758 #include <rfb/default8x16.h> 7759 7760 #define EVMAX 2048 7761 XEvent Ev[EVMAX]; 7762 int Ev_done[EVMAX]; 7763 int Ev_order[EVMAX]; 7764 int Ev_area[EVMAX]; 7765 int Ev_tmp[EVMAX]; 7766 int Ev_tmp2[EVMAX]; 7767 Window Ev_tmpwin[EVMAX]; 7768 Window Ev_win[EVMAX]; 7769 Window Ev_map[EVMAX]; 7770 Window Ev_unmap[EVMAX]; 7771 sraRect Ev_rects[EVMAX]; 7772 7773 int tmp_stack[STACKMAX]; 7774 sraRegionPtr tmp_reg[STACKMAX]; 7775 7776 #define CLEAN_OUT \ 7777 for (i=0; i < n; i++) { \ 7778 sraRgnDestroy(tmp_reg[i]); \ 7779 } \ 7780 if (r1) sraRgnDestroy(r1); \ 7781 if (r0) sraRgnDestroy(r0); 7782 7783 int try_to_fix_resize_su(Window orig_frame, int orig_x, int orig_y, int orig_w, int orig_h, 7784 int x, int y, int w, int h, int try_batch) { 7785 7786 int idx = lookup_win_index(orig_frame); 7787 sraRegionPtr r0, r1, r2, r3; 7788 int sx1, sy1, sw1, sh1, dx, dy; 7789 int bx1, by1, bw1, bh1; 7790 int nr = 0, *nbat = NULL; 7791 7792 if (idx < 0) { 7793 return 0; 7794 } 7795 if (cache_list[idx].bs_x < 0 || cache_list[idx].su_time == 0.0) { 7796 return 0; 7797 } 7798 7799 r0 = sraRgnCreateRect(0, 0, dpy_x, dpy_y); 7800 r1 = sraRgnCreateRect(orig_x, orig_y, orig_x+orig_w, orig_y+orig_h); 7801 r2 = sraRgnCreateRect(x, y, x+w, y+h); 7802 7803 sraRgnAnd(r1, r0); 7804 sraRgnAnd(r2, r0); 7805 7806 if (try_batch) { 7807 nbat = &nr; 7808 } 7809 7810 if (orig_w >= w && orig_h >= h) { 7811 7812 if (0) fprintf(stderr, "Shrinking resize %d %dx%d+%d+%d -> %dx%d+%d+%d\n", idx, orig_w, orig_h, orig_x, orig_y, w, h, x, y); 7813 r3 = sraRgnCreateRgn(r1); 7814 sraRgnSubtract(r3, r2); 7815 7816 sx1 = cache_list[idx].su_x; 7817 sy1 = cache_list[idx].su_y; 7818 sw1 = cache_list[idx].su_w; 7819 sh1 = cache_list[idx].su_h; 7820 7821 dx = orig_x - sx1; 7822 dy = orig_y - sy1; 7823 7824 cache_cr(r3, dx, dy, 0.075, 0.05, nbat); 7825 sraRgnDestroy(r3); 7826 7827 r3 = sraRgnCreateRgn(r1); 7828 sraRgnAnd(r3, r2); 7829 7830 dx = sx1 - orig_x; 7831 dy = sy1 - orig_y; 7832 sraRgnOffset(r3, dx, dy); 7833 7834 dx = orig_x - x; 7835 dy = orig_y - y; 7836 sraRgnOffset(r3, dx, dy); 7837 7838 cache_cr(r3, dx, dy, 0.075, 0.05, nbat); 7839 sraRgnDestroy(r3); 7840 7841 if (nr) { 7842 batch_push(nr, -1.0); 7843 } 7844 7845 cache_list[idx].x = x; 7846 cache_list[idx].y = y; 7847 cache_list[idx].width = w; 7848 cache_list[idx].height = h; 7849 7850 cache_list[idx].bs_w = w; 7851 cache_list[idx].bs_h = h; 7852 cache_list[idx].su_w = w; 7853 cache_list[idx].su_h = h; 7854 7855 cache_list[idx].bs_time = 0.0; 7856 /* XXX Y */ 7857 if (0) cache_list[idx].su_time = dnow(); 7858 } else { 7859 if (0) fprintf(stderr, "Growing resize %d %dx%d+%d+%d -> %dx%d+%d+%d\n", idx, orig_w, orig_h, orig_x, orig_y, w, h, x, y); 7860 7861 sx1 = cache_list[idx].su_x; 7862 sy1 = cache_list[idx].su_y; 7863 sw1 = cache_list[idx].su_w; 7864 sh1 = cache_list[idx].su_h; 7865 7866 bx1 = cache_list[idx].bs_x; 7867 by1 = cache_list[idx].bs_y; 7868 bw1 = cache_list[idx].bs_w; 7869 bh1 = cache_list[idx].bs_h; 7870 7871 if (find_rect(idx, x, y, w, h)) { 7872 r3 = sraRgnCreateRgn(r2); 7873 sraRgnAnd(r3, r1); 7874 7875 dx = cache_list[idx].su_x - x; 7876 dy = cache_list[idx].su_y - y; 7877 7878 sraRgnOffset(r3, dx, dy); 7879 7880 dx = dx - (sx1 - orig_x); 7881 dy = dy - (sy1 - orig_y); 7882 7883 cache_cr(r3, dx, dy, 0.075, 0.05, nbat); 7884 sraRgnDestroy(r3); 7885 7886 r3 = sraRgnCreateRgn(r2); 7887 sraRgnSubtract(r3, r1); 7888 7889 dx = cache_list[idx].su_x - x; 7890 dy = cache_list[idx].su_y - y; 7891 7892 sraRgnOffset(r3, dx, dy); 7893 7894 cache_cr(r3, dx, dy, 0.075, 0.05, nbat); 7895 sraRgnDestroy(r3); 7896 7897 if (nr) { 7898 batch_push(nr, -1.0); 7899 } 7900 7901 cache_list[idx].bs_time = 0.0; 7902 /* XXX Y */ 7903 if (0) cache_list[idx].su_time = dnow(); 7904 } 7905 } 7906 7907 sraRgnDestroy(r0); 7908 sraRgnDestroy(r1); 7909 sraRgnDestroy(r2); 7910 7911 return 1; 7912 } 7913 7914 int try_to_fix_su(Window win, int idx, Window above, int *nbatch, char *mode) { 7915 int i, idx2, n = 0, found = 0, found_above = 0; 7916 sraRegionPtr r0, r1, r2; 7917 Window win2; 7918 int x, y, w, h, on = 0; 7919 int x0, y0, w0, h0; 7920 int x1, y1, w1, h1; 7921 int x2, y2, w2, h2; 7922 int unmapped = 0; 7923 int moved = 0; 7924 7925 7926 if (mode && !strcmp(mode, "unmapped")) { 7927 unmapped = 1; 7928 } else if (mode && !strcmp(mode, "moved")) { 7929 moved = 1; 7930 } 7931 if (idx < 0) { 7932 return 0; 7933 } 7934 if (ncdb) fprintf(stderr, "TRY_TO_FIX_SU(%d) 0x%lx 0x%lx was_unmapped=%d map_state=%s\n", idx, win, above, unmapped, MState(cache_list[idx].map_state)); 7935 7936 if (cache_list[idx].map_state != IsViewable && !unmapped) { 7937 return 0; 7938 } 7939 if (cache_list[idx].su_time == 0.0) { 7940 return 0; 7941 } 7942 if (cache_list[idx].bs_x < 0) { 7943 return 0; 7944 } 7945 7946 r0 = sraRgnCreateRect(0, 0, dpy_x, dpy_y); 7947 7948 x = cache_list[idx].x; 7949 y = cache_list[idx].y; 7950 w = cache_list[idx].width; 7951 h = cache_list[idx].height; 7952 7953 r1 = sraRgnCreateRect(x, y, x+w, y+h); 7954 7955 sraRgnAnd(r1, r0); 7956 7957 if (sraRgnEmpty(r1)) { 7958 CLEAN_OUT 7959 return 0; 7960 } 7961 7962 if (unmapped) { 7963 on = 1; 7964 } 7965 if (above == 0x1) { 7966 on = 1; 7967 } 7968 for (i = old_stack_n - 1; i >= 0; i--) { 7969 win2 = old_stack[i]; 7970 if (win2 == above) { 7971 if (0) fprintf(stderr, "0x%lx turn on: 0x%lx i=%d\n", win, win2, i); 7972 on = 1; 7973 found_above = 1; 7974 } 7975 if (win2 == win) { 7976 if (0) fprintf(stderr, "0x%lx turn off: 0x%lx i=%d\n", win, win2, i); 7977 found = 1; 7978 on = 0; 7979 break; 7980 } 7981 if (! on) { 7982 continue; 7983 } 7984 idx2 = lookup_win_index(win2); 7985 if (idx2 < 0) { 7986 continue; 7987 } 7988 if (cache_list[idx2].map_state != IsViewable) { 7989 continue; 7990 } 7991 if (cache_list[idx2].bs_x < 0) { 7992 continue; 7993 } 7994 /* XXX Invalidate? */ 7995 7996 x2 = cache_list[idx2].x; 7997 y2 = cache_list[idx2].y; 7998 w2 = cache_list[idx2].width; 7999 h2 = cache_list[idx2].height; 8000 8001 r2 = sraRgnCreateRect(x2, y2, x2+w2, y2+h2); 8002 sraRgnAnd(r2, r0); 8003 if (! sraRgnAnd(r2, r1)) { 8004 sraRgnDestroy(r2); 8005 continue; 8006 } 8007 8008 tmp_reg[n] = r2; 8009 tmp_stack[n++] = idx2; 8010 } 8011 8012 if (! found) { 8013 CLEAN_OUT 8014 return 0; 8015 } 8016 8017 for (i = n - 1; i >= 0; i--) { 8018 int i2; 8019 r2 = sraRgnCreateRgn(tmp_reg[i]); 8020 for (i2 = i + 1; i2 < n; i2++) { 8021 sraRgnSubtract(r2, tmp_reg[i2]); 8022 } 8023 idx2 = tmp_stack[i]; 8024 if (!sraRgnEmpty(r2)) { 8025 int dx, dy; 8026 int dx2, dy2; 8027 8028 x0 = cache_list[idx2].x; 8029 y0 = cache_list[idx2].y; 8030 w0 = cache_list[idx2].width; 8031 h0 = cache_list[idx2].height; 8032 8033 x1 = cache_list[idx].su_x; /* SU -> SU */ 8034 y1 = cache_list[idx].su_y; 8035 w1 = cache_list[idx].su_w; 8036 h1 = cache_list[idx].su_h; 8037 8038 x2 = cache_list[idx2].su_x; 8039 y2 = cache_list[idx2].su_y; 8040 w2 = cache_list[idx2].su_w; 8041 h2 = cache_list[idx2].su_h; 8042 8043 dx = x2 - x0; 8044 dy = y2 - y0; 8045 sraRgnOffset(r2, dx, dy); 8046 8047 dx2 = x1 - x; 8048 dy2 = y1 - y; 8049 dx = dx - dx2; 8050 dy = dy - dy2; 8051 cache_cr(r2, dx, dy, save_delay0, save_delay1, nbatch); 8052 } 8053 sraRgnDestroy(r2); 8054 } 8055 8056 if (unmapped) { 8057 CLEAN_OUT 8058 return found_above; 8059 } 8060 8061 for (i = n - 1; i >= 0; i--) { 8062 r2 = sraRgnCreateRgn(tmp_reg[i]); 8063 idx2 = tmp_stack[i]; 8064 if (!sraRgnEmpty(r2)) { 8065 int dx, dy; 8066 int dx2, dy2; 8067 8068 x0 = cache_list[idx2].x; 8069 y0 = cache_list[idx2].y; 8070 w0 = cache_list[idx2].width; 8071 h0 = cache_list[idx2].height; 8072 8073 x1 = cache_list[idx].su_x; /* BS -> SU */ 8074 y1 = cache_list[idx].su_y; 8075 w1 = cache_list[idx].su_w; 8076 h1 = cache_list[idx].su_h; 8077 8078 x2 = cache_list[idx2].bs_x; 8079 y2 = cache_list[idx2].bs_y; 8080 w2 = cache_list[idx2].bs_w; 8081 h2 = cache_list[idx2].bs_h; 8082 8083 dx = x1 - x; 8084 dy = y1 - y; 8085 sraRgnOffset(r2, dx, dy); 8086 8087 dx2 = x2 - x0; 8088 dy2 = y2 - y0; 8089 dx = dx - dx2; 8090 dy = dy - dy2; 8091 cache_cr(r2, dx, dy, save_delay0, save_delay1, nbatch); 8092 } 8093 sraRgnDestroy(r2); 8094 } 8095 8096 CLEAN_OUT 8097 return found_above; 8098 } 8099 8100 void idx_add_rgn(sraRegionPtr r, sraRegionPtr r0, int idx) { 8101 int x, y, w, h; 8102 sraRegionPtr rtmp; 8103 8104 if (idx < 0) { 8105 return; 8106 } 8107 x = cache_list[idx].x; 8108 y = cache_list[idx].y; 8109 w = cache_list[idx].width; 8110 h = cache_list[idx].height; 8111 8112 rtmp = sraRgnCreateRect(x, y, w, h); 8113 if (r0) { 8114 sraRgnAnd(rtmp, r0); 8115 } 8116 sraRgnOr(r, rtmp); 8117 sraRgnDestroy(rtmp); 8118 } 8119 8120 sraRegionPtr idx_create_rgn(sraRegionPtr r0, int idx) { 8121 int x, y, w, h; 8122 sraRegionPtr rtmp; 8123 8124 if (idx < 0) { 8125 return NULL; 8126 } 8127 x = cache_list[idx].x; 8128 y = cache_list[idx].y; 8129 w = cache_list[idx].width; 8130 h = cache_list[idx].height; 8131 8132 rtmp = sraRgnCreateRect(x, y, w, h); 8133 if (r0) { 8134 sraRgnAnd(rtmp, r0); 8135 } 8136 return rtmp; 8137 } 8138 8139 void scale_mark_xrootpmap(void) { 8140 char *dst_fb, *src_fb = main_fb; 8141 int dst_bpl, Bpp = bpp/8, fac = 1; 8142 int yn = (ncache+1) * dpy_y; 8143 int yfac = (ncache+2); 8144 int mark = 1; 8145 8146 if (!scaling || !rfb_fb || rfb_fb == main_fb) { 8147 mark_rect_as_modified(0, yn, dpy_x, yn + dpy_y, 0); 8148 return; 8149 } 8150 8151 if (cmap8to24 && cmap8to24_fb) { 8152 src_fb = cmap8to24_fb; 8153 if (scaling) { 8154 if (depth <= 8) { 8155 fac = 4; 8156 } else if (depth <= 16) { 8157 fac = 2; 8158 } 8159 } 8160 } 8161 dst_fb = rfb_fb; 8162 dst_bpl = rfb_bytes_per_line; 8163 8164 scale_rect(scale_fac_x, scale_fac_y, scaling_blend, scaling_interpolate, fac * Bpp, 8165 src_fb, fac * main_bytes_per_line, dst_fb, dst_bpl, dpy_x, yfac * dpy_y, 8166 scaled_x, yfac * scaled_y, 0, yn, dpy_x, yn + dpy_y, mark); 8167 } 8168 8169 void set_ncache_xrootpmap(void) { 8170 Atom pmap, type; 8171 int format; 8172 unsigned long length, after; 8173 XImage *image = NULL; 8174 XErrorHandler old_handler; 8175 8176 RAWFB_RET_VOID 8177 #if !NO_X11 8178 if (!ncache) { 8179 return; 8180 } 8181 X_LOCK; 8182 old_handler = XSetErrorHandler(trap_xerror); 8183 trapped_xerror = 0; 8184 pmap = XInternAtom(dpy, "_XROOTPMAP_ID", True); 8185 8186 if (use_solid_bg) { 8187 image = solid_image(NULL); 8188 if (!quiet) { 8189 rfbLog("set_ncache_xrootpmap: solid_image\n"); 8190 } 8191 } else if (pmap != None) { 8192 Pixmap pixmap = None; 8193 unsigned char *d_pmap; 8194 8195 XGetWindowProperty(dpy, rootwin, pmap, 0L, 1L, False, 8196 AnyPropertyType, &type, &format, &length, &after, &d_pmap); 8197 8198 if (length != 0) { 8199 pixmap = *((Pixmap *) d_pmap); 8200 if (pixmap != None) { 8201 image = XGetImage(dpy, pixmap, 0, 0, dpy_x, dpy_y, AllPlanes, ZPixmap); 8202 } 8203 } 8204 if (!quiet) { 8205 rfbLog("set_ncache_xrootpmap: loading background pixmap: 0x%lx\n", pixmap); 8206 } 8207 } else { 8208 if (!quiet) { 8209 rfbLog("set_ncache_xrootpmap: trying root background\n"); 8210 } 8211 } 8212 if (image == NULL) { 8213 image = solid_root((char *) 0x1); 8214 } 8215 if (image != NULL) { 8216 char *src, *dst; 8217 int line; 8218 int pixelsize = bpp/8; 8219 int y1 = dpy_y * (ncache+1); 8220 8221 src = image->data; 8222 dst = main_fb + y1 * main_bytes_per_line; 8223 line = 0; 8224 while (line++ < dpy_y) { 8225 memcpy(dst, src, dpy_x * pixelsize); 8226 src += image->bytes_per_line; 8227 dst += main_bytes_per_line; 8228 } 8229 XDestroyImage(image); 8230 X_UNLOCK; 8231 scale_mark_xrootpmap(); 8232 X_LOCK; 8233 } else { 8234 int yn = (ncache+1) * dpy_y; 8235 zero_fb(0, yn, dpy_x, yn + dpy_y); 8236 } 8237 XSetErrorHandler(old_handler); 8238 X_UNLOCK; 8239 #endif 8240 } 8241 8242 #define EVLISTMAX 256 8243 #define EV_RESET 0 8244 #define EV_CREATE 1 8245 #define EV_DESTROY 2 8246 #define EV_UNMAP 3 8247 #define EV_MAP 4 8248 #define EV_REPARENT 5 8249 #define EV_CONFIGURE 6 8250 #define EV_CONFIGURE_SIZE 7 8251 #define EV_CONFIGURE_POS 8 8252 #define EV_CONFIGURE_STACK 9 8253 #define EV_VISIBILITY_UNOBS 10 8254 #define EV_VISIBILITY_OBS 11 8255 #define EV_PROPERTY 12 8256 #define EV_OLD_WM_MAP 13 8257 #define EV_OLD_WM_UNMAP 14 8258 #define EV_OLD_WM_OFF 15 8259 #define EV_OLD_WM_NOTMAPPED 16 8260 Window _ev_list[EVLISTMAX]; 8261 int _ev_case[EVLISTMAX]; 8262 int _ev_list_cnt; 8263 8264 int n_CN = 0, n_RN = 0, n_DN = 0, n_ON = 0, n_MN = 0, n_UN = 0; 8265 int n_VN = 0, n_VN_p = 0, n_VN_u = 0, n_ST = 0, n_PN = 0, n_DC = 0; 8266 int n_ON_sz = 0, n_ON_po = 0, n_ON_st = 0; 8267 8268 int ev_store(Window win, int type) { 8269 if (type == EV_RESET) { 8270 n_CN = 0; n_RN = 0; n_DN = 0; n_ON = 0; n_MN = 0; n_UN = 0; 8271 n_VN = 0; n_VN_p = 0; n_VN_u = 0; n_ST = 0; n_PN = 0; n_DC = 0; 8272 n_ON_sz = 0; n_ON_po = 0; n_ON_st = 0; 8273 _ev_list_cnt = 0; 8274 return 1; 8275 } 8276 if (_ev_list_cnt >= EVLISTMAX) { 8277 return 0; 8278 } 8279 _ev_list[_ev_list_cnt] = win; 8280 _ev_case[_ev_list_cnt++] = type; 8281 return 1; 8282 } 8283 8284 int ev_lookup(Window win, int type) { 8285 int i; 8286 for(i=0; i < _ev_list_cnt; i++) { 8287 if (_ev_list[i] == win && _ev_case[i] == type) { 8288 return 1; 8289 } 8290 } 8291 return 0; 8292 } 8293 8294 unsigned long all_ev = SubstructureNotifyMask|StructureNotifyMask|VisibilityChangeMask; 8295 unsigned long win_ev = StructureNotifyMask|VisibilityChangeMask; 8296 8297 void read_events(int *n_in) { 8298 int n = *n_in; 8299 Window win, win2; 8300 XEvent ev; 8301 8302 while (xcheckmaskevent(dpy, all_ev, &Ev[n])) { 8303 int cfg_size = 0; 8304 int cfg_pos = 0; 8305 int cfg_stack = 0; 8306 int type = Ev[n].type; 8307 Window w = None; 8308 8309 win = Ev[n].xany.window; 8310 Ev_done[n] = 0; 8311 Ev_area[n] = 0; 8312 Ev_win[n] = win; 8313 Ev_map[n] = None; 8314 Ev_unmap[n] = None; 8315 Ev_order[n] = n; 8316 8317 ev = Ev[n]; 8318 8319 if (type == DestroyNotify) w = Ev[n].xcreatewindow.window; 8320 if (type == CreateNotify) w = Ev[n].xdestroywindow.window; 8321 if (type == ReparentNotify) w = Ev[n].xreparent.window; 8322 if (type == UnmapNotify) w = Ev[n].xunmap.window; 8323 if (type == MapNotify) w = Ev[n].xmap.window; 8324 if (type == Expose) w = Ev[n].xexpose.window; 8325 if (type == ConfigureNotify) w = Ev[n].xconfigure.window; 8326 if (type == VisibilityNotify) w = win; 8327 if (n == *n_in && ncdb) fprintf(stderr, "\n"); 8328 if (1) { 8329 char *msg = ""; 8330 int idx = -1, x = 0, y = 0, wd = 0, ht = 0; 8331 if (w != None) { 8332 idx = lookup_win_index(w); 8333 if (idx >= 0) { 8334 x = cache_list[idx].x; 8335 y = cache_list[idx].y; 8336 wd = cache_list[idx].width; 8337 ht = cache_list[idx].height; 8338 } 8339 } 8340 if (type == VisibilityNotify) { 8341 msg = VState(Ev[n].xvisibility.state); 8342 } else if (type == ConfigureNotify) { 8343 int x_new = Ev[n].xconfigure.x; 8344 int y_new = Ev[n].xconfigure.y; 8345 int w_new = Ev[n].xconfigure.width; 8346 int h_new = Ev[n].xconfigure.height; 8347 if (idx >= 0) { 8348 if (w_new != wd || h_new != ht) { 8349 msg = "change size"; 8350 cfg_size = 1; 8351 } 8352 if (x_new != x || y_new != y) { 8353 if (!strcmp(msg, "")) { 8354 msg = "change position"; 8355 } 8356 cfg_pos = 1; 8357 } else if (! cfg_size) { 8358 msg = "change stacking"; 8359 cfg_stack = 1; 8360 } 8361 } 8362 } 8363 8364 if (ncdb) fprintf(stderr, "----- %02d inputev 0x%08lx w: 0x%08lx %04dx%04d+%04d+%04d %s %s\n", n, win, w, wd, ht, x, y, Etype(type), msg); 8365 } 8366 8367 if (win == rootwin) { 8368 if (type == CreateNotify) { 8369 win2 = ev.xcreatewindow.window; 8370 ev_store(win2, EV_CREATE); 8371 n++; 8372 n_CN++; 8373 } else if (type == ReparentNotify) { 8374 if (ev.xreparent.parent != rootwin) { 8375 win2 = ev.xreparent.window; 8376 if (win2 != rootwin) { 8377 ev_store(win2, EV_REPARENT); 8378 } 8379 } 8380 n++; 8381 n_RN++; 8382 } else if (type == PropertyNotify) { 8383 set_prop_atom(Ev[n].xproperty.atom); 8384 n++; 8385 n_PN++; 8386 } else if (type == MapNotify) { 8387 win2 = ev.xmap.window; 8388 ev_store(win2, EV_MAP); 8389 n++; 8390 n_CN++; 8391 } else { 8392 /* skip rest */ 8393 #if 0 8394 Window w = None; 8395 if (type == DestroyNotify) w = Ev[n].xdestroywindow.window; 8396 if (type == UnmapNotify) w = Ev[n].xunmap.window; 8397 if (type == MapNotify) w = Ev[n].xmap.window; 8398 if (type == Expose) w = Ev[n].xexpose.window; 8399 if (type == ConfigureNotify) w = Ev[n].xconfigure.window; 8400 if (type != ConfigureNotify) fprintf(stderr, "root: skip %s for 0x%lx\n", Etype(type), w); 8401 #endif 8402 8403 } 8404 } else { 8405 if (type == ReparentNotify) { 8406 ev_store(win, EV_REPARENT); 8407 n++; 8408 n_RN++; 8409 } else if (type == DestroyNotify) { 8410 ev_store(win, EV_DESTROY); 8411 n++; 8412 n_DN++; 8413 } else if (type == ConfigureNotify) { 8414 ev_store(win, EV_CONFIGURE); 8415 if (cfg_size) { 8416 ev_store(win, EV_CONFIGURE_SIZE); 8417 n_ON_sz++; 8418 } 8419 if (cfg_pos) { 8420 ev_store(win, EV_CONFIGURE_POS); 8421 n_ON_po++; 8422 } 8423 if (cfg_stack) { 8424 ev_store(win, EV_CONFIGURE_STACK); 8425 n_ON_st++; 8426 } 8427 n++; 8428 n_ON++; 8429 } else if (type == VisibilityNotify) { 8430 if (Ev[n].xvisibility.state == VisibilityUnobscured) { 8431 ev_store(win, EV_VISIBILITY_UNOBS); 8432 n_VN_u++; 8433 } else { 8434 ev_store(win, EV_VISIBILITY_OBS); 8435 n_VN_p++; 8436 } 8437 n++; 8438 n_VN++; 8439 } else if (type == MapNotify) { 8440 ev_store(win, EV_MAP); 8441 Ev_map[n] = win; 8442 n++; 8443 n_MN++; 8444 } else if (type == UnmapNotify) { 8445 ev_store(win, EV_UNMAP); 8446 Ev_unmap[n] = win; 8447 n++; 8448 n_UN++; 8449 } else { 8450 /* skip rest */ 8451 if (ncdb) fprintf(stderr, "----- skip %s\n", Etype(type)); 8452 } 8453 } 8454 if (n >= EVMAX) { 8455 break; 8456 } 8457 } 8458 *n_in = n; 8459 } 8460 8461 int try_to_synthesize_su(int force, int urgent, int *nbatch) { 8462 int i, idx, idx2, n = 0; 8463 sraRegionPtr r0, r1, r2; 8464 Window win = None; 8465 int x0, y0, w0, h0; 8466 int x1, y1, w1, h1; 8467 int x2, y2, w2, h2; 8468 int x3, y3, w3, h3; 8469 XWindowAttributes attr; 8470 8471 r0 = sraRgnCreateRect(0, 0, dpy_x, dpy_y); 8472 8473 snap_old(); 8474 8475 X_LOCK; 8476 for (i = old_stack_n - 1; i >= 0; i--) { 8477 win = old_stack[i]; 8478 if (urgent) { /* XXX Y resp */ 8479 if (!valid_window(win, &attr, 1)) { 8480 continue; 8481 } 8482 idx = lookup_win_index(win); 8483 if (idx >= 0) { 8484 STORE(idx, win, attr); 8485 } 8486 } else { 8487 idx = lookup_win_index(win); 8488 if (idx >= 0) { 8489 attr.map_state = cache_list[idx].map_state; 8490 attr.x = cache_list[idx].x; 8491 attr.y = cache_list[idx].y; 8492 attr.width = cache_list[idx].width; 8493 attr.height = cache_list[idx].height; 8494 } else { 8495 attr.map_state = IsUnmapped; 8496 attr.x = 0; 8497 attr.y = 0; 8498 attr.width = 0; 8499 attr.height = 0; 8500 } 8501 8502 } 8503 if (attr.map_state != IsViewable) { 8504 continue; 8505 } 8506 if (0) fprintf(stderr, "win: 0x%lx %d idx=%d\n", win, i, idx); 8507 8508 x2 = attr.x; 8509 y2 = attr.y; 8510 w2 = attr.width; 8511 h2 = attr.height; 8512 8513 r2 = sraRgnCreateRect(x2, y2, x2+w2, y2+h2); 8514 sraRgnAnd(r2, r0); 8515 8516 tmp_reg[n] = r2; 8517 tmp_stack[n++] = idx; 8518 } 8519 X_UNLOCK; 8520 8521 if (! n) { 8522 r1 = NULL; 8523 CLEAN_OUT 8524 return 0; 8525 } 8526 8527 for (i = 0; i < n; i++) { 8528 int i2, cnt = 0; 8529 idx = tmp_stack[i]; 8530 if (idx < 0 || cache_list[idx].bs_x < 0) { 8531 continue; 8532 } 8533 r1 = tmp_reg[i]; 8534 if (r1 == NULL || sraRgnEmpty(r1)) { 8535 continue; 8536 } 8537 if (cache_list[idx].su_time > 0.0) { 8538 if (force) { 8539 if (ncdb) fprintf(stderr, "forcing synth: 0x%lx %d\n", cache_list[idx].win, idx); 8540 } else { 8541 continue; 8542 } 8543 } 8544 if (ncache_xrootpmap) { 8545 int dx, dy; 8546 8547 x0 = cache_list[idx].x; 8548 y0 = cache_list[idx].y; 8549 w0 = cache_list[idx].width; 8550 h0 = cache_list[idx].height; 8551 8552 x1 = cache_list[idx].su_x; 8553 y1 = cache_list[idx].su_y; 8554 w1 = cache_list[idx].su_w; 8555 h1 = cache_list[idx].su_h; 8556 8557 r2 = sraRgnCreateRgn(tmp_reg[i]); 8558 dx = x1 - x0; 8559 dy = y1 - y0; 8560 8561 sraRgnOffset(r2, dx, dy); 8562 8563 x2 = x0; 8564 y2 = y0 + (ncache+1) * dpy_y; 8565 8566 dx = x1 - x2; 8567 dy = y1 - y2; 8568 cache_cr(r2, dx, dy, save_delay0, save_delay1, nbatch); 8569 cnt++; 8570 8571 sraRgnDestroy(r2); 8572 } 8573 8574 for (i2 = n - 1; i2 > i; i2--) { 8575 r2 = sraRgnCreateRgn(tmp_reg[i2]); 8576 if (sraRgnAnd(r2, r1)) { 8577 int dx, dy; 8578 int dx2, dy2; 8579 8580 idx2 = tmp_stack[i2]; 8581 /* XXX Y */ 8582 if (idx2 < 0 || cache_list[idx2].bs_x < 0 || cache_list[idx2].bs_time == 0.0) { 8583 continue; 8584 } 8585 8586 x0 = cache_list[idx].x; 8587 y0 = cache_list[idx].y; 8588 w0 = cache_list[idx].width; 8589 h0 = cache_list[idx].height; 8590 8591 x1 = cache_list[idx].su_x; 8592 y1 = cache_list[idx].su_y; 8593 w1 = cache_list[idx].su_w; 8594 h1 = cache_list[idx].su_h; 8595 8596 x2 = cache_list[idx2].x; 8597 y2 = cache_list[idx2].y; 8598 w2 = cache_list[idx2].width; 8599 h2 = cache_list[idx2].height; 8600 8601 x3 = cache_list[idx2].bs_x; 8602 y3 = cache_list[idx2].bs_y; 8603 w3 = cache_list[idx2].bs_w; 8604 h3 = cache_list[idx2].bs_h; 8605 8606 dx = x1 - x0; 8607 dy = y1 - y0; 8608 sraRgnOffset(r2, dx, dy); 8609 8610 dx2 = x3 - x2; 8611 dy2 = y3 - y2; 8612 dx = dx - dx2; 8613 dy = dy - dy2; 8614 cache_cr(r2, dx, dy, save_delay0, save_delay1, nbatch); 8615 cnt++; 8616 } 8617 sraRgnDestroy(r2); 8618 } 8619 if (cnt) { 8620 cache_list[idx].su_time = dnow(); 8621 } 8622 if (ncdb) fprintf(stderr, " try_to_synth_su: 0x%lx %d idx=%d cnt=%d\n", win, i, idx, cnt); 8623 } 8624 8625 r1 = NULL; 8626 CLEAN_OUT 8627 return 1; 8628 } 8629 8630 static double last_vis_unobs_time = 0.0; 8631 static double last_vis_obs_time = 0.0; 8632 8633 static int saw_desktop_change = 0; 8634 8635 void check_sched(int try_batch, int *did_sched) { 8636 static double last_root = 0.0; 8637 static double last_pixmap = 0.0; 8638 double refresh = 60.0; 8639 int i, k, valid; 8640 Window win; 8641 XWindowAttributes attr; 8642 double now = dnow(); 8643 8644 if (now > last_root + refresh) { 8645 8646 if (ncdb) fprintf(stderr, "\n**** checking cache_list[%d]\n\n", cache_list_num); 8647 block_stats(); 8648 8649 for(k=0; k<cache_list_num; k++) { 8650 valid = 0; 8651 win = cache_list[k].win; 8652 X_LOCK; 8653 if (win == None) { 8654 ; 8655 } else if (cache_list[k].selectinput && cache_list[k].time > now - refresh) { 8656 valid = 1; 8657 } else if (valid_window(win, &attr, 1)) { 8658 STORE(k, win, attr); 8659 if (! cache_list[k].selectinput) { 8660 xselectinput(win, win_ev, 0); 8661 CLEAR(k); 8662 cache_list[k].selectinput = 1; 8663 } 8664 valid = 1; 8665 } else { 8666 if (ncdb) fprintf(stderr, "DELETE(%d) %dx%d+%d+%d\n", k, cache_list[k].width, cache_list[k].height, cache_list[k].x, cache_list[k].y); 8667 DELETE(k); 8668 } 8669 X_UNLOCK; 8670 /* XXX Y */ 8671 if (valid) { 8672 if (cache_list[k].create_cnt && cache_list[k].map_state != IsViewable && cache_list[k].map_cnt == 0) { 8673 if (cache_list[k].bs_x >= 0) { 8674 if (ncdb) fprintf(stderr, "Created window never mapped: freeing(%d) 0x%lx\n", k, win); 8675 free_rect(k); 8676 } 8677 } 8678 } 8679 } 8680 last_root = dnow(); 8681 } 8682 8683 if (now > last_sched_bs + 0.30) { 8684 static double last_sched_vis = 0.0; 8685 int nr = 0, *bat = NULL; 8686 8687 if (try_batch) { 8688 bat = &nr; 8689 } 8690 if (now < last_wireframe + 2.0) { 8691 for (i=0; i < NSCHED; i++) { 8692 sched_bs[i] = None; 8693 } 8694 } 8695 if (now < last_get_wm_frame_time + 1.0) { 8696 if (last_get_wm_frame != None) { 8697 int idx = lookup_win_index(last_get_wm_frame); 8698 if (idx >= 0) { 8699 if (cache_list[idx].bs_x < 0) { 8700 int x = cache_list[idx].x; 8701 int y = cache_list[idx].y; 8702 int w = cache_list[idx].width; 8703 int h = cache_list[idx].height; 8704 if (find_rect(idx, x, y, w, h)) { 8705 SCHED(last_get_wm_frame, 1); 8706 } 8707 } 8708 } 8709 } 8710 } 8711 8712 for (i=0; i < NSCHED; i++) { 8713 if (sched_bs[i] != None) { 8714 int idx; 8715 win = sched_bs[i]; 8716 if (now < sched_tm[i] + 0.55) { 8717 continue; 8718 } 8719 if (n_MN || n_UN || n_ST || n_DC) { 8720 sched_tm[i] = now; 8721 continue; 8722 } 8723 idx = lookup_win_index(win); 8724 if (idx >= 0) { 8725 int aw = cache_list[idx].width; 8726 int ah = cache_list[idx].height; 8727 if (cache_list[idx].map_state != IsViewable) { 8728 ; 8729 } else if (cache_list[idx].vis_state != VisibilityUnobscured) { 8730 ; 8731 } else if (aw * ah < 64 * 64) { 8732 ; 8733 } else { 8734 if (ncdb) fprintf(stderr, "*SNAP BS_save: 0x%lx %d %d %d\n", win, aw, ah, cache_list[idx].map_state); 8735 valid = 0; 8736 bs_save(idx, bat, &attr, 1, 0, &valid, 0); 8737 if (valid) { 8738 STORE(idx, win, attr); 8739 } else { 8740 DELETE(idx); 8741 } 8742 } 8743 } else { 8744 if (ncdb) fprintf(stderr, "*SCHED LOOKUP FAIL: i=%d 0x%lx\n", i, win); 8745 } 8746 } 8747 sched_bs[i] = None; 8748 } 8749 *did_sched = 1; 8750 8751 if (n_MN || n_UN || n_ST || n_DC) { 8752 if (last_sched_vis < now) { 8753 last_sched_vis += 1.0; 8754 } 8755 } else if (now > last_sched_vis + 3.0 && now > last_wireframe + 2.0) { 8756 static double last_vis = 0.0; 8757 int vis_now[32], top_now[32]; 8758 static int vis_prev[32], freq = 0; 8759 int diff, nv = 32, vis_now_n = 0; 8760 Window win; 8761 8762 freq++; 8763 8764 for (i=0; i < cache_list_num; i++) { 8765 int ok = 0; 8766 int top_only = 1; 8767 int aw = cache_list[i].width; 8768 int ah = cache_list[i].height; 8769 int map_prev = cache_list[i].map_state; 8770 8771 win = cache_list[i].win; 8772 8773 if (saw_desktop_change) { 8774 top_only = 0; 8775 } 8776 8777 if (win == None) { 8778 continue; 8779 } 8780 /* XXX Y resp */ 8781 if (saw_desktop_change || freq % 5 == 0) { 8782 int vret = 0; 8783 X_LOCK; 8784 vret = valid_window(win, &attr, 1); 8785 X_UNLOCK; 8786 if (!vret) { 8787 continue; 8788 } 8789 STORE(i, win, attr); 8790 } 8791 if (!cache_list[i].valid) { 8792 continue; 8793 } 8794 if (cache_list[i].map_state != IsViewable) { 8795 continue; 8796 } 8797 if (cache_list[i].vis_state == VisibilityFullyObscured) { 8798 continue; 8799 } 8800 if (map_prev != IsViewable) { 8801 /* we hope to catch it below in the normal event processing */ 8802 continue; 8803 } 8804 if (aw * ah < 64 * 64) { 8805 continue; 8806 } 8807 if (top_only) { 8808 if (cache_list[i].vis_state == VisibilityUnobscured) { 8809 ok = 1; 8810 } else if (!clipped(i)) { 8811 ok = 1; 8812 } 8813 } else { 8814 ok = 1; 8815 } 8816 if (ok) { 8817 if (vis_now_n < nv) { 8818 vis_now[vis_now_n] = i; 8819 top_now[vis_now_n++] = top_only; 8820 } 8821 } 8822 } 8823 diff = 0; 8824 for (k = 0; k < vis_now_n; k++) { 8825 if (vis_now[k] != vis_prev[k]) { 8826 diff = 1; 8827 } 8828 } 8829 if (diff == 0) { 8830 if (now > last_vis + 45.0) { 8831 diff = 1; 8832 } 8833 } 8834 if (diff) { 8835 if (ncdb && vis_now_n) fprintf(stderr, "*VIS snapshot all %.4f\n", dnowx()); 8836 for (k = 0; k < vis_now_n; k++) { 8837 i = vis_now[k]; 8838 win = cache_list[i].win; 8839 valid = 0; 8840 if (ncdb) fprintf(stderr, "*VIS BS_save: 0x%lx %d %d %d\n", win, cache_list[i].width, cache_list[i].height, cache_list[i].map_state); 8841 if (now < cache_list[i].vis_unobs_time + 0.75 && now < cache_list[i].vis_obs_time + 0.75) { 8842 continue; 8843 } 8844 bs_save(i, bat, &attr, !top_now[k], 0, &valid, 1); 8845 if (valid) { 8846 STORE(i, win, attr); 8847 } else { 8848 DELETE(i); 8849 } 8850 vis_prev[k] = vis_now[k]; 8851 } 8852 last_vis = dnow(); 8853 } 8854 last_sched_vis = dnow(); 8855 if (! n_DC) { 8856 saw_desktop_change = 0; 8857 } 8858 /* XXX Y */ 8859 try_to_synthesize_su(0, 0, bat); 8860 } 8861 8862 if (nr) { 8863 batch_push(nr, -1.0); 8864 } 8865 last_sched_bs = dnow(); 8866 } 8867 #if !NO_X11 8868 if (dpy && atom_XROOTPMAP_ID == None && now > last_pixmap + 5.0) { 8869 atom_XROOTPMAP_ID = XInternAtom(dpy, "_XROOTPMAP_ID", True); 8870 last_pixmap = now; 8871 } 8872 #endif 8873 if (got_XROOTPMAP_ID > 0.0) { 8874 if (ncdb) fprintf(stderr, "got_XROOTPMAP_ID\n"); 8875 if (ncache_xrootpmap) { 8876 set_ncache_xrootpmap(); 8877 } 8878 got_XROOTPMAP_ID = 0.0; 8879 } 8880 } 8881 8882 int check_ncache(int reset, int mode) { 8883 static int first = 1; 8884 static int last_client_count = -1; 8885 int i, k, n; 8886 int did_sched = 0; 8887 8888 Window win, win2; 8889 XWindowAttributes attr; 8890 int valid; 8891 int try_batch = 1; /* XXX Y */ 8892 int use_batch = 0; 8893 int nreg = 0, *nbatch; 8894 int create_cnt; 8895 int su_fix_cnt; 8896 int pixels = 0, ttot; 8897 int desktop_change = 0, n1, n2; 8898 int desktop_change_old_wm = 0; 8899 int missed_su_restore = 0; 8900 int missed_bs_restore = 0; 8901 sraRegionPtr r0, r; 8902 sraRegionPtr missed_su_restore_rgn; 8903 sraRegionPtr missed_bs_restore_rgn; 8904 sraRegionPtr unmapped_rgn; 8905 8906 int nrects = 0; 8907 int nsave, nxsel; 8908 double now; 8909 8910 int skipwins_n = 0; 8911 int skipwins_max = 256; 8912 Window skipwins[256]; 8913 8914 static char *dt_guess = NULL; 8915 static double dt_last = 0.0; 8916 int dt_gnome = 0, gnome_animation = 0; 8917 int dt_kde = 0; 8918 8919 if (unixpw_in_progress) return -1; 8920 8921 #ifdef MACOSX 8922 if (! macosx_console) { 8923 RAWFB_RET(-1) 8924 } 8925 if (! screen) { 8926 return -1; 8927 } 8928 #else 8929 RAWFB_RET(-1) 8930 if (! screen || ! dpy) { 8931 return -1; 8932 } 8933 #endif 8934 8935 now = dnow(); 8936 8937 #ifdef NO_NCACHE 8938 ncache = 0; 8939 #endif 8940 8941 if (reset && (first || cache_list_len == 0)) { 8942 return -1; 8943 } 8944 if (use_threads) { 8945 try_batch = 0; 8946 } 8947 8948 if (ncache0) { 8949 if (reset) { 8950 ; 8951 } else if (!client_count || !ncache || nofb) { 8952 static double last_purge = 0.0; 8953 double delay = client_count ? 0.5 : 2.0; 8954 if (now > last_purge + delay) { 8955 int c = 0; 8956 XEvent ev; 8957 X_LOCK; 8958 while (xcheckmaskevent(dpy, all_ev, &ev)) { 8959 c++; 8960 } 8961 X_UNLOCK; 8962 last_purge = dnow(); 8963 if (ncdb && c) fprintf(stderr, "check_ncache purged %d events\n", c); 8964 } 8965 if (!client_count && last_client_count >= 0 && 8966 client_count != last_client_count) { 8967 /* this should use less RAM when no clients */ 8968 do_new_fb(1); 8969 } 8970 last_client_count = client_count; 8971 return -1; 8972 } 8973 } 8974 last_client_count = client_count; 8975 8976 if (ncache && ! ncache0) { 8977 ncache0 = ncache; 8978 } 8979 8980 if (! ncache || ! ncache0) { 8981 return -1; 8982 } 8983 if (subwin) { 8984 return -1; 8985 } 8986 if (nofb) { 8987 return -1; 8988 } 8989 if (now < last_client + 4) { 8990 return -1; 8991 } 8992 if (! all_clients_initialized()) { 8993 /* play it safe */ 8994 return -1; 8995 } 8996 8997 8998 8999 if (reset) { 9000 rfbLog("check_ncache: resetting cache: %d/%d %d %d\n", cache_list_num, cache_list_len, ncache, first); 9001 for (i=0; i < cache_list_num; i++) { 9002 free_rect(i); 9003 } 9004 for (n = 1; n <= ncache; n++) { 9005 if (rect_reg[n] != NULL) { 9006 sraRgnDestroy(rect_reg[n]); 9007 rect_reg[n] = NULL; 9008 } 9009 } 9010 zero_fb(0, dpy_y, dpy_x, (ncache+1)*dpy_y); 9011 mark_rect_as_modified(0, dpy_y, dpy_x, (ncache+1)*dpy_y, 0); 9012 9013 if (ncache_xrootpmap) { 9014 set_ncache_xrootpmap(); 9015 } 9016 9017 snap_old(); 9018 return -1; 9019 } 9020 9021 if (first) { 9022 int dx = 10, dy = 24, ds = 0; 9023 int Dx = dpy_x, Dy = dpy_y; 9024 first = 0; 9025 for (i=0; i < NRECENT; i++) { 9026 recent[i] = None; 9027 } 9028 for (i=0; i < NSCHED; i++) { 9029 sched_bs[i] = None; 9030 } 9031 rlast = 0; 9032 9033 X_LOCK; 9034 /* event leak with client_count == 0 */ 9035 xselectinput_rootwin |= SubstructureNotifyMask; 9036 XSelectInput_wr(dpy, rootwin, xselectinput_rootwin); 9037 X_UNLOCK; 9038 9039 if (scaling) { 9040 Dx = scaled_x; 9041 Dy = scaled_y; 9042 } 9043 if (!rotating_same) { 9044 int t = Dx; 9045 Dx = Dy; 9046 Dy = t; 9047 } 9048 9049 for (i = 0; i < 3; i++) { 9050 rfbDrawString(screen, &default8x16Font, dx, ds + Dy+1*dy, 9051 "This is the Pixel buffer cache region. Your VNC Viewer is not hiding it from you.", 9052 white_pixel()); 9053 rfbDrawString(screen, &default8x16Font, dx, ds + Dy+2*dy, 9054 "Try resizing your VNC Viewer so you don't see it!!", 9055 white_pixel()); 9056 rfbDrawString(screen, &default8x16Font, dx, ds + Dy+3*dy, 9057 "Pay no attention to the man behind the curtain...", 9058 white_pixel()); 9059 rfbDrawString(screen, &default8x16Font, dx, ds + Dy+4*dy, 9060 "To disable caching run the server with: x11vnc -noncache ...", 9061 white_pixel()); 9062 rfbDrawString(screen, &default8x16Font, dx, ds + Dy+5*dy, 9063 "If there are painting errors press 3 Alt_L's (Left \"Alt\" key) in a row to repaint the screen.", 9064 white_pixel()); 9065 rfbDrawString(screen, &default8x16Font, dx, ds + Dy+6*dy, 9066 "More info: http://www.karlrunge.com/x11vnc/faq.html#faq-client-caching", 9067 white_pixel()); 9068 9069 ds += 11 * dy; 9070 } 9071 9072 snapshot_cache_list(0, 100.0); 9073 for (i=0; i < cache_list_num; i++) { 9074 CLEAR(i); 9075 } 9076 for (n = 1; n <= ncache; n++) { 9077 rect_reg[n] = NULL; 9078 } 9079 9080 if (ncache_xrootpmap) { 9081 set_ncache_xrootpmap(); 9082 } 9083 9084 snap_old(); 9085 } 9086 9087 check_zero_rects(); 9088 9089 if (hack_val == 2) { 9090 block_stats(); 9091 hack_val = 1; 9092 } 9093 #ifdef MACOSX 9094 if (macosx_console) { 9095 static double last_all_windows = 0.0; 9096 if (! macosx_checkevent(NULL)) { 9097 if (now > last_all_windows + 0.05) { 9098 macosxCGS_get_all_windows(); 9099 last_all_windows = dnow(); 9100 } 9101 } 9102 /* XXX Y */ 9103 rootwin = -1; 9104 } 9105 #endif 9106 9107 n = 0; 9108 ttot = 0; 9109 9110 if (dt_guess == NULL || now > dt_last + 60) { 9111 static char *dt_prev = NULL; 9112 dt_prev = dt_guess; 9113 dt_guess = strdup(guess_desktop()); 9114 if (ncache_xrootpmap && dt_prev && dt_guess) { 9115 if (strcmp(dt_prev, dt_guess)) { 9116 set_ncache_xrootpmap(); 9117 } 9118 } 9119 dt_last = now; 9120 if (dt_prev) { 9121 free(dt_prev); 9122 } 9123 } 9124 if (dt_guess && !strcmp(dt_guess, "gnome")) { 9125 dt_gnome = 1; 9126 } else if (dt_guess && !strcmp(dt_guess, "kde")) { 9127 dt_kde = 1; 9128 } 9129 if (dt_kde) { 9130 kde_no_animate(0); 9131 } 9132 9133 ev_store(None, EV_RESET); 9134 9135 X_LOCK; 9136 for (k = 1; k <= 3; k++) { 9137 int j, retry = 0; 9138 9139 if (retry) {} 9140 9141 nsave = n; 9142 9143 if (k > 1 && ncdb) fprintf(stderr, "read_events-%d\n", k); 9144 read_events(&n); 9145 9146 #if 0 9147 if (dt_gnome && (n_MN || n_UN)) { 9148 retry = 1; 9149 } else if (ncache_old_wm && n_ON_po >= 2) { 9150 retry = 1; 9151 } else if (n > nsave) { 9152 /* XXX Y */ 9153 retry = 1; 9154 } 9155 9156 if (retry) { 9157 int n0 = n; 9158 usleep(25 * 1000); 9159 XFlush_wr(dpy); 9160 read_events(&n); 9161 if (ncdb) fprintf(stderr, "read_events retry: %d -> %d\n", n0, n); 9162 } 9163 #endif 9164 9165 if (n > nsave) { 9166 int n0 = n; 9167 9168 for (j=0; j<4; j++) { 9169 if (j < 2) { 9170 usleep(30 * 1000); 9171 } else { 9172 usleep(10 * 1000); 9173 } 9174 XFlush_wr(dpy); 9175 read_events(&n); 9176 if (ncdb) fprintf(stderr, "read_events retry: %d -> %d\n", n0, n); 9177 if (n == n0) { 9178 break; 9179 } 9180 n0 = n; 9181 } 9182 } 9183 9184 nxsel = 0; 9185 9186 /* handle creates and reparenting: */ 9187 for (n1 = nsave; n1 < n; n1++) { 9188 Window win2; 9189 int idx; 9190 XEvent ev = Ev[n1]; 9191 win = Ev_win[n1]; 9192 if (ev.type == CreateNotify) { 9193 win2 = ev.xcreatewindow.window; 9194 if (ev_lookup(win2, EV_REPARENT) || ev_lookup(win2, EV_DESTROY)) { 9195 if (skipwins_n < skipwins_max) { 9196 if (ncdb) fprintf(stderr, "SKIPWINS: CreateNotify: 0x%lx %d\n", win2, n1); 9197 skipwins[skipwins_n++] = win2; 9198 } 9199 } else { 9200 idx = lookup_win_index(win); 9201 if (idx < 0) { 9202 idx = lookup_free_index(); 9203 if (idx < 0) { 9204 continue; 9205 } 9206 CLEAR(idx); 9207 } 9208 if (ncdb) fprintf(stderr, "PRELOOP: CreateNotify: 0x%lx %d valid_window\n", win2, n1); 9209 if (valid_window(win2, &attr, 1)) { 9210 STORE(idx, win2, attr); 9211 CLEAR(idx); 9212 cache_list[idx].selectinput = 1; 9213 cache_list[idx].create_cnt = 1; 9214 if (ncdb) fprintf(stderr, "PRELOOP: CreateNotify: 0x%lx %d xselectinput\n", win2, n1); 9215 xselectinput(win2, win_ev, 1); 9216 nxsel++; 9217 } else { 9218 DELETE(idx); 9219 } 9220 nxsel++; 9221 } 9222 } else if (ev.type == ReparentNotify) { 9223 if (ev.xreparent.parent != rootwin) { 9224 win2 = ev.xreparent.window; 9225 if (win2 != rootwin) { 9226 idx = lookup_win_index(win2); 9227 if (ncdb) fprintf(stderr, "PRELOOP: RepartNotify: 0x%lx %d idx=%d\n", win2, n1, idx); 9228 if (idx >= 0) { 9229 DELETE(idx); 9230 } 9231 if (! ev_lookup(win2, EV_CREATE)) { 9232 xselectinput(win2, 0, 1); 9233 nxsel++; 9234 } 9235 } 9236 } 9237 } 9238 } 9239 if (nxsel == 0) { 9240 break; 9241 } 9242 } 9243 9244 X_UNLOCK; 9245 9246 if (got_NET_CURRENT_DESKTOP > 0.0) { 9247 if (dnow() < got_NET_CURRENT_DESKTOP + 0.25) { 9248 if (ncdb) fprintf(stderr, "***got_NET_CURRENT_DESKTOP n=%d\n", n); 9249 desktop_change = 1; 9250 n_DC++; 9251 } else { 9252 if (ncdb) fprintf(stderr, "***got_NET_CURRENT_DESKTOP n=%d STALE\n", n); 9253 } 9254 got_NET_CURRENT_DESKTOP = 0.0; 9255 } 9256 9257 if (n == 0) { 9258 check_sched(try_batch, &did_sched); 9259 return 0; 9260 } 9261 if (ncdb) fprintf(stderr, "\n"); if (ncdb) rfbLog("IN check_ncache() %d events. %.4f\n", n, now - x11vnc_start); 9262 9263 if (try_batch) { 9264 use_batch = 1; 9265 } 9266 9267 if (rotating) { 9268 use_batch = 0; 9269 } 9270 if (cursor_noshape_updates_clients(screen)) { 9271 use_batch = 0; 9272 } 9273 9274 if (! use_batch) { 9275 nbatch = NULL; 9276 } else { 9277 nreg = 0; 9278 nbatch = &nreg; 9279 } 9280 9281 /* XXX Y */ 9282 for (n1 = 0; n1 < n; n1++) { 9283 Window twin = Ev_map[n1]; 9284 if (twin == None || twin == rootwin) { 9285 continue; 9286 } 9287 for (n2 = 0; n2 < n; n2++) { 9288 if (Ev_unmap[n2] == twin) { 9289 if (skipwins_n < skipwins_max) { 9290 if (ncdb) fprintf(stderr, "SKIPWINS: Ev_unmap/map: 0x%lx %d\n", twin, n2); 9291 skipwins[skipwins_n++] = twin; 9292 break; 9293 } 9294 } 9295 } 9296 } 9297 9298 if (!desktop_change) { 9299 if (skipwins_n) { 9300 if (n_MN + n_UN >= 2 + 2*skipwins_n) { 9301 desktop_change = 1; 9302 n_DC++; 9303 } 9304 } else { 9305 if (n_MN + n_UN >= 3) { 9306 desktop_change = 1; 9307 n_DC++; 9308 } 9309 } 9310 } 9311 if (ncache_old_wm) { 9312 int shifts = 0; 9313 for (i=0; i < n; i++) { 9314 XEvent ev; 9315 int type, idx = -1; 9316 int ik = Ev_order[i]; 9317 int x_new, y_new, w_new, h_new; 9318 int x_old, y_old, w_old, h_old; 9319 int old_wm = 0; 9320 9321 if (Ev_done[ik]) continue; 9322 win = Ev_win[ik]; 9323 9324 ev = Ev[ik]; 9325 type = ev.type; 9326 if (type != ConfigureNotify) { 9327 continue; 9328 } 9329 if (ev_lookup(win, EV_MAP)) { 9330 continue; 9331 } else if (ev_lookup(win, EV_UNMAP)) { 9332 continue; 9333 } else if (ev_lookup(win, EV_DESTROY)) { 9334 continue; 9335 } 9336 9337 idx = lookup_win_index(win); 9338 if (idx < 0) { 9339 continue; 9340 } 9341 x_new = ev.xconfigure.x; 9342 y_new = ev.xconfigure.y; 9343 w_new = ev.xconfigure.width; 9344 h_new = ev.xconfigure.height; 9345 9346 x_old = cache_list[idx].x; 9347 y_old = cache_list[idx].y; 9348 w_old = cache_list[idx].width; 9349 h_old = cache_list[idx].height; 9350 9351 if (w_new == w_old && h_new == h_old) { 9352 if (nabs(x_new - x_old) >= dpy_x || nabs(y_new - y_old) >= dpy_y) { 9353 sraRegionPtr r_old, r_new, r0; 9354 r0 = sraRgnCreateRect(0, 0, dpy_x, dpy_y); 9355 r_old = sraRgnCreateRect(x_old, y_old, x_old+w_old, y_old+h_old); 9356 sraRgnAnd(r_old, r0); 9357 r_new = sraRgnCreateRect(x_new, y_new, x_new+w_new, y_new+h_new); 9358 sraRgnAnd(r_new, r0); 9359 if (cache_list[idx].map_state != IsViewable) { 9360 ev_store(win, EV_OLD_WM_NOTMAPPED); 9361 } else if (sraRgnEmpty(r_old) && !sraRgnEmpty(r_new)) { 9362 old_wm = 1; 9363 ev_store(win, EV_OLD_WM_MAP); 9364 Ev_map[i] = win; 9365 } else if (!sraRgnEmpty(r_old) && sraRgnEmpty(r_new)) { 9366 ev_store(win, EV_OLD_WM_UNMAP); 9367 old_wm = -1; 9368 Ev_unmap[i] = win; 9369 } else { 9370 ev_store(win, EV_OLD_WM_OFF); 9371 } 9372 sraRgnDestroy(r_old); 9373 sraRgnDestroy(r_new); 9374 sraRgnDestroy(r0); 9375 shifts++; 9376 if (ncdb) fprintf(stderr, "old_wm[%d] +%04d+%04d +%04d+%04d old_wm: %d\n", i, x_old, y_old, x_new, y_new, old_wm); 9377 } 9378 } 9379 } 9380 if (shifts >= 3) { 9381 if (ncdb) fprintf(stderr, "DESKTOP_CHANGE_OLD_WM: %d\n", shifts); 9382 desktop_change = 1; 9383 desktop_change_old_wm = 1; 9384 } 9385 } 9386 9387 #define SKIPUMS \ 9388 ok = 1; \ 9389 if (twin == None || twin == rootwin) { \ 9390 continue; \ 9391 } \ 9392 for (ns = 0; ns < skipwins_n; ns++) { \ 9393 if (skipwins[ns] == twin) { \ 9394 ok = 0; \ 9395 break; \ 9396 } \ 9397 } 9398 9399 if (desktop_change) { 9400 Window twin; 9401 int ok, s, k, add, cnt, ns; 9402 9403 cnt = 0; 9404 add = 0; 9405 for (i=0; i < n; i++) { 9406 twin = Ev_unmap[i]; 9407 SKIPUMS 9408 if (ok) { 9409 if (ncdb) fprintf(stderr, "U Ev_tmp[%d] = %d\n", cnt, i); 9410 Ev_tmp[cnt++] = i; 9411 } 9412 } 9413 for (i=0; i < n; i++) { 9414 twin = Ev_map[i]; 9415 SKIPUMS 9416 if (ok) { 9417 if (ncdb) fprintf(stderr, "M Ev_tmp[%d] = %d\n", cnt, i); 9418 Ev_tmp[cnt++] = i; 9419 } 9420 } 9421 for (k = 0; k < cnt; k++) { 9422 Ev_tmp2[k] = -1; 9423 } 9424 /* unmap from top to bottom */ 9425 for (s = old_stack_n - 1; s >= 0; s--) { 9426 twin = old_stack[s]; 9427 if (twin == None || twin == rootwin) { 9428 continue; 9429 } 9430 for (k = 0; k < cnt; k++) { 9431 i = Ev_tmp[k]; 9432 if (twin == Ev_unmap[i]) { 9433 if (ncdb) fprintf(stderr, "U Ev_tmp2[%d] = %d\n", add, i); 9434 Ev_tmp2[add++] = i; 9435 break; 9436 } 9437 } 9438 } 9439 /* map from bottom to top */ 9440 for (s = 0; s < old_stack_n; s++) { 9441 twin = old_stack[s]; 9442 if (twin == None || twin == rootwin) { 9443 continue; 9444 } 9445 for (k = 0; k < cnt; k++) { 9446 i = Ev_tmp[k]; 9447 if (twin == Ev_map[i]) { 9448 if (ncdb) fprintf(stderr, "M Ev_tmp2[%d] = %d\n", add, i); 9449 Ev_tmp2[add++] = i; 9450 break; 9451 } 9452 } 9453 } 9454 k = 0; 9455 for (i=0; i < n; i++) { 9456 Window wu, wm; 9457 int j; 9458 int oku = 0, okm = 0; 9459 wu = Ev_unmap[i]; 9460 wm = Ev_map[i]; 9461 ok = 0; 9462 if (wu != None && wu != rootwin) oku = 1; 9463 if (wm != None && wm != rootwin) okm = 1; 9464 if (!oku && !okm) { 9465 continue; 9466 } 9467 if (oku) { 9468 twin = wu; 9469 SKIPUMS 9470 if (!ok) { 9471 oku = 0; 9472 } 9473 } 9474 if (okm) { 9475 twin = wm; 9476 SKIPUMS 9477 if (!ok) { 9478 okm = 0; 9479 } 9480 } 9481 if (!oku && !okm) { 9482 continue; 9483 } 9484 j = Ev_tmp2[k++]; 9485 if (j >= 0) { 9486 if (ncdb) fprintf(stderr, "UM Ev_order[%d] = %d oku=%d okm=%d\n", i, j, oku, okm); 9487 Ev_order[i] = j; 9488 } 9489 } 9490 } 9491 9492 #if 0 9493 if (desktop_change) { 9494 Window twin; 9495 int ok, s, k, add, cnt, ns; 9496 9497 cnt = 0; 9498 add = 0; 9499 for (i=0; i < n; i++) { 9500 twin = Ev_unmap[i]; 9501 SKIPUMS 9502 if (ok) { 9503 Ev_tmp[cnt++] = i; 9504 } 9505 } 9506 for (k = 0; k < cnt; k++) { 9507 Ev_tmp2[k] = -1; 9508 } 9509 /* unmap from top to bottom */ 9510 for (s = old_stack_n - 1; s >= 0; s--) { 9511 twin = old_stack[s]; 9512 for (k = 0; k < cnt; k++) { 9513 i = Ev_tmp[k]; 9514 if (twin == Ev_unmap[i]) { 9515 Ev_tmp2[add++] = i; 9516 break; 9517 } 9518 } 9519 } 9520 k = 0; 9521 for (i=0; i < n; i++) { 9522 int j; 9523 twin = Ev_unmap[i]; 9524 SKIPUMS 9525 if (ok) { 9526 j = Ev_tmp2[k++]; 9527 if (j >= 0) { 9528 Ev_order[i] = j; 9529 } 9530 } 9531 } 9532 9533 cnt = 0; 9534 add = 0; 9535 for (i=0; i < n; i++) { 9536 twin = Ev_map[i]; 9537 SKIPUMS 9538 if (ok) { 9539 Ev_tmp[cnt++] = i; 9540 } 9541 } 9542 for (k = 0; k < cnt; k++) { 9543 Ev_tmp2[k] = -1; 9544 } 9545 /* map from bottom to top */ 9546 for (s = 0; s < old_stack_n; s++) { 9547 twin = old_stack[s]; 9548 for (k = 0; k < cnt; k++) { 9549 i = Ev_tmp[k]; 9550 if (twin == Ev_map[i]) { 9551 Ev_tmp2[add++] = i; 9552 break; 9553 } 9554 } 9555 } 9556 k = 0; 9557 for (i=0; i < n; i++) { 9558 int j; 9559 twin = Ev_map[i]; 9560 SKIPUMS 9561 if (ok) { 9562 j = Ev_tmp2[k++]; 9563 if (j >= 0) { 9564 Ev_order[i] = j; 9565 } 9566 } 9567 } 9568 } 9569 #endif 9570 9571 if (!desktop_change && (n_VN_p && !n_UN && (n_MN || n_ON_st))) { 9572 if (now < last_vis_unobs_time + 0.75 || now < last_vis_obs_time + 0.75) { 9573 ; 9574 } else if (n_MN <= 2 && n_ON_st <= 1) { 9575 for (i=0; i < n; i++) { 9576 XEvent ev; 9577 int type, idx = -1, state, valid; 9578 int ik = Ev_order[i]; 9579 9580 if (Ev_done[ik]) continue; 9581 win = Ev_win[ik]; 9582 9583 ev = Ev[ik]; 9584 type = ev.type; 9585 if (type != VisibilityNotify) { 9586 continue; 9587 } 9588 9589 state = ev.xvisibility.state; 9590 if (state == VisibilityUnobscured) { 9591 continue; 9592 } 9593 if (ev_lookup(win, EV_MAP)) { 9594 continue; 9595 } else if (ev_lookup(win, EV_UNMAP)) { 9596 continue; 9597 } else if (ev_lookup(win, EV_DESTROY)) { 9598 continue; 9599 } 9600 idx = lookup_win_index(win); 9601 9602 if (idx < 0) { 9603 continue; 9604 } 9605 if (cache_list[idx].vis_state == VisibilityFullyObscured) { 9606 continue; 9607 } 9608 if (now < cache_list[idx].vis_unobs_time + 3.00 || now < cache_list[idx].vis_obs_time + 3.00) { 9609 continue; 9610 } 9611 9612 if (ncdb) fprintf(stderr, "----%02d: VisibilityNotify 0x%lx %3d (*PRELOOP*) state: %s U/P %d/%d\n", ik, win, idx, VState(state), n_VN_u, n_VN_p); 9613 valid = 0; 9614 bs_save(idx, nbatch, &attr, 1, 0, &valid, 1); 9615 if (valid) { 9616 STORE(idx, win, attr); 9617 } else { 9618 DELETE(idx); 9619 } 9620 9621 cache_list[idx].vis_state = state; 9622 cache_list[idx].vis_obs_time = last_vis_obs_time = dnow(); 9623 Ev_done[ik] = 1; 9624 } 9625 } 9626 } 9627 if (desktop_change) { 9628 if (ncache_dt_change) { 9629 if (ncdb) fprintf(stderr, "GUESSED DESKTOP CHANGE.\n"); 9630 saw_desktop_change = 1; 9631 } else { 9632 if (ncdb) fprintf(stderr, "GUESSED DESKTOP CHANGE. Skipping.\n"); 9633 desktop_change = 0; 9634 } 9635 } 9636 9637 9638 create_cnt = 0; 9639 missed_su_restore = 0; 9640 missed_bs_restore = 0; 9641 missed_su_restore_rgn = sraRgnCreate(); 9642 missed_bs_restore_rgn = sraRgnCreate(); 9643 r0 = sraRgnCreateRect(0, 0, dpy_x, dpy_y); 9644 unmapped_rgn = sraRgnCreate(); 9645 su_fix_cnt = 0; 9646 9647 for (k = 0; k < skipwins_n; k++) { 9648 if (ncdb) fprintf(stderr, "skipwins[%d] 0x%lx\n", k, skipwins[k]); 9649 } 9650 9651 X_LOCK; 9652 for (i=0; i < n; i++) { 9653 XEvent ev; 9654 int ns, skip = 0, type, idx = -1; 9655 int ik = Ev_order[i]; 9656 9657 if (Ev_done[ik]) continue; 9658 win = Ev_win[ik]; 9659 9660 ev = Ev[ik]; 9661 type = ev.type; 9662 Ev_done[ik] = 1; 9663 9664 win2 = win; 9665 if (win == rootwin) { 9666 if (type == CreateNotify) { 9667 win2 = ev.xcreatewindow.window; 9668 } else if (type == ReparentNotify) { 9669 win2 = ev.xreparent.window; 9670 } 9671 } 9672 for (ns = 0; ns < skipwins_n; ns++) { 9673 if (win2 == skipwins[ns]) { 9674 skip = 1; 9675 break; 9676 } 9677 } 9678 if (skip) { 9679 if (ncdb) fprintf(stderr, "skip%02d: ** SpecialSkip 0x%lx/0x%lx type: %s\n", ik, win, win2, Etype(type)); 9680 continue; 9681 } 9682 9683 if (win == rootwin) { 9684 if (type == CreateNotify) { 9685 int x=0, y=0, w=0, h=0; 9686 valid = 0; 9687 win2 = ev.xcreatewindow.window; 9688 idx = lookup_win_index(win2); 9689 if (idx < 0) { 9690 continue; 9691 } 9692 if (cache_list[idx].valid) { 9693 valid = 1; 9694 x=cache_list[idx].x; 9695 y=cache_list[idx].y; 9696 w=cache_list[idx].width; 9697 h=cache_list[idx].height; 9698 if (w*h > 64 * 64 && ev_lookup(win2, EV_MAP)) { 9699 X_UNLOCK; 9700 valid = 1; 9701 su_save(idx, nbatch, &attr, 0, &valid, 1); 9702 STORE(idx, win2, attr); 9703 9704 X_LOCK; 9705 9706 if (! desktop_change) { 9707 SCHED(win2, 1) 9708 } 9709 create_cnt++; 9710 } 9711 } 9712 if (ncdb) fprintf(stderr, "root%02d: ** CreateNotify 0x%lx %3d -- %dx%d+%d+%d valid=%d\n", ik, win2, idx, w, h, x, y, valid); 9713 9714 } else if (type == ReparentNotify) { 9715 if (ev.xreparent.parent != rootwin) { 9716 win2 = ev.xreparent.window; 9717 idx = lookup_win_index(win2); 9718 if (ncdb) fprintf(stderr, "root%02d: ReparentNotifyRM 0x%lx %3d\n", ik, win2, idx); 9719 } 9720 } else { 9721 if (ncdb) fprintf(stderr, "root%02d: ** IgnoringRoot 0x%lx type: %s\n", ik, win, Etype(type)); 9722 } 9723 } else { 9724 if (type == ConfigureNotify) { 9725 int x_new, y_new, w_new, h_new; 9726 int x_old, y_old, w_old, h_old; 9727 int stack_change, old_wm = 0; 9728 Window oabove = None; 9729 9730 idx = lookup_win_index(win); 9731 9732 if (idx >= 0) { 9733 oabove = cache_list[idx].above; 9734 } 9735 9736 if (ncdb) fprintf(stderr, "----%02d: ConfigureNotify 0x%lx %3d -- above: 0x%lx -> 0x%lx %dx%d+%d+%d\n", ik, win, idx, 9737 oabove, ev.xconfigure.above, ev.xconfigure.width, ev.xconfigure.height, ev.xconfigure.x, ev.xconfigure.y); 9738 9739 if (idx < 0) { 9740 continue; 9741 } 9742 9743 x_new = ev.xconfigure.x; 9744 y_new = ev.xconfigure.y; 9745 w_new = ev.xconfigure.width; 9746 h_new = ev.xconfigure.height; 9747 9748 x_old = cache_list[idx].x; 9749 y_old = cache_list[idx].y; 9750 w_old = cache_list[idx].width; 9751 h_old = cache_list[idx].height; 9752 9753 if (desktop_change_old_wm) { 9754 if (ev_lookup(win, EV_OLD_WM_MAP)) { 9755 if (Ev_map[ik] == win) { 9756 old_wm = 1; 9757 } else { 9758 old_wm = 2; 9759 } 9760 } else if (ev_lookup(win, EV_OLD_WM_UNMAP)) { 9761 if (Ev_unmap[ik] == win) { 9762 old_wm = -1; 9763 } else { 9764 old_wm = 2; 9765 } 9766 } else if (ev_lookup(win, EV_OLD_WM_OFF)) { 9767 old_wm = 2; 9768 } else if (ev_lookup(win, EV_OLD_WM_NOTMAPPED)) { 9769 old_wm = 3; 9770 } 9771 } 9772 9773 if (!old_wm) { 9774 if (x_old != x_new || y_old != y_new) { 9775 /* invalidate su */ 9776 cache_list[idx].su_time = 0.0; 9777 if (ncdb) fprintf(stderr, " INVALIDATE su: 0x%lx xy: +%d+%d +%d+%d \n", win, x_old, y_old, x_new, y_new); 9778 } 9779 if (w_old != w_new || h_old != h_new) { 9780 /* invalidate bs */ 9781 cache_list[idx].bs_time = 0.0; 9782 if (ncdb) fprintf(stderr, " INVALIDATE bs: 0x%lx wh: %dx%d %dx%d \n", win, w_old, h_old, w_new, h_new); 9783 } 9784 } else { 9785 int valid; 9786 X_UNLOCK; 9787 if (old_wm == 1) { 9788 /* XXX Y */ 9789 if (ncdb) fprintf(stderr, " OLD_WM_MAP: 0x%lx wh: %dx%d+%d+%d %dx%d+%d+%d \n", win, w_old, h_old, x_old, y_old, w_new, h_new, x_new, y_new); 9790 valid = 0; 9791 bs_restore(idx, nbatch, NULL, &attr, 0, 0, &valid, 1); 9792 9793 } else if (old_wm == -1) { 9794 if (ncdb) fprintf(stderr, " OLD_WM_UNMAP: 0x%lx wh: %dx%d+%d+%d %dx%d+%d+%d \n", win, w_old, h_old, x_old, y_old, w_new, h_new, x_new, y_new); 9795 valid = 1; 9796 su_restore(idx, nbatch, NULL, &attr, 1, 0, &valid, 1); 9797 } else { 9798 if (ncdb) fprintf(stderr, " OLD_WM_OFF:: 0x%lx wh: %dx%d+%d+%d %dx%d+%d+%d old_wm=%d\n", win, w_old, h_old, x_old, y_old, w_new, h_new, x_new, y_new, old_wm); 9799 } 9800 X_LOCK; 9801 } 9802 9803 stack_change = 0; 9804 if (old_wm) { 9805 ; 9806 } else if (cache_list[idx].above != ev.xconfigure.above) { 9807 stack_change = 1; 9808 } else if (x_new == x_old && y_new == y_old && w_new == w_old && h_new == h_old) { 9809 stack_change = 1; 9810 } 9811 if (stack_change) { 9812 int i2, ok = 1; 9813 for (i2=0; i2 < n; i2++) { 9814 if (Ev_map[i2] == win) { 9815 ok = 0; 9816 break; 9817 } 9818 } 9819 if (ok) { 9820 if (n_MN == 0 && n_UN == 0) { 9821 if (su_fix_cnt > 0) { 9822 ok = 0; 9823 if (ncdb) fprintf(stderr, " CONF_IGNORE: Too many stacking changes: 0x%lx\n", win); 9824 } 9825 } 9826 9827 } 9828 if (ok) { 9829 if (ev_lookup(ev.xconfigure.above, EV_UNMAP)) { 9830 if (ncdb) fprintf(stderr, " skip try_to_fix_su for GNOME deiconify #1\n"); 9831 if (dt_gnome) { 9832 gnome_animation = 1; 9833 } 9834 ok = 0; 9835 } 9836 } 9837 if (ok && dt_gnome) { 9838 if (valid_window(ev.xconfigure.above, &attr, 1)) { 9839 if (attr.map_state != IsViewable) { 9840 if (ncdb) fprintf(stderr, " skip try_to_fix_su for GNOME deiconify #2\n"); 9841 gnome_animation = 1; 9842 ok = 0; 9843 } 9844 } 9845 } 9846 if (ok) { 9847 int rc = try_to_fix_su(win, idx, ev.xconfigure.above, nbatch, NULL); 9848 if (rc == 0 && su_fix_cnt == 0 && n_MN == 0 && n_UN == 0) { 9849 X_UNLOCK; 9850 try_to_synthesize_su(1, 1, nbatch); 9851 X_LOCK; 9852 } 9853 n_ST++; 9854 su_fix_cnt++; 9855 } 9856 } 9857 9858 cache_list[idx].x = x_new; 9859 cache_list[idx].y = y_new; 9860 cache_list[idx].width = w_new; 9861 cache_list[idx].height = h_new; 9862 9863 cache_list[idx].above = ev.xconfigure.above; 9864 cache_list[idx].time = dnow(); 9865 9866 } else if (type == VisibilityNotify) { 9867 int state = ev.xvisibility.state; 9868 idx = lookup_win_index(win); 9869 if (ncdb) fprintf(stderr, "----%02d: VisibilityNotify 0x%lx %3d state: %s U/P %d/%d\n", ik, win, idx, VState(state), n_VN_u, n_VN_p); 9870 9871 if (idx < 0) { 9872 continue; 9873 } 9874 if (desktop_change) { 9875 ; 9876 } else if (macosx_console && n_VN_p == 0) { 9877 ; /* XXXX not working well yet with UnmapNotify ... */ 9878 } else if (state == VisibilityUnobscured) { 9879 int ok = 1; 9880 if (ncache <= 2) { 9881 ok = 0; 9882 } else if (ev_lookup(win, EV_MAP)) { 9883 ok = 0; 9884 } else if (ev_lookup(win, EV_UNMAP)) { 9885 ok = 0; 9886 } else if (ev_lookup(win, EV_DESTROY)) { 9887 ok = 0; 9888 } else if (gnome_animation) { 9889 ok = 0; 9890 } else { 9891 /* this is for gnome iconify */ 9892 int i2; 9893 for (i2=i+1; i2 < n; i2++) { 9894 int idx2, ik2 = Ev_order[i2]; 9895 sraRegionPtr ro1, ro2; 9896 Window win2 = Ev_unmap[ik2]; 9897 9898 if (win2 == None) { 9899 continue; 9900 } 9901 idx2 = lookup_win_index(win2); 9902 if (idx2 < 0) { 9903 continue; 9904 } 9905 9906 ro1 = idx_create_rgn(r0, idx); 9907 ro2 = idx_create_rgn(r0, idx2); 9908 9909 if (sraRgnAnd(ro1, ro2)) { 9910 if (ncdb) fprintf(stderr, " skip VisibilityUnobscured for GNOME iconify.\n"); 9911 ok = 0; 9912 } 9913 sraRgnDestroy(ro1); 9914 sraRgnDestroy(ro2); 9915 if (! ok) { 9916 break; 9917 } 9918 } 9919 } 9920 if (ok) { 9921 int x2, y2, w2, h2; 9922 sraRegionPtr rmask = NULL; 9923 valid = 0; 9924 if (dnow() < cache_list[idx].vis_unobs_time + 3.00 && !sraRgnEmpty(unmapped_rgn)) { 9925 x2 = cache_list[idx].x; 9926 y2 = cache_list[idx].y; 9927 w2 = cache_list[idx].width; 9928 h2 = cache_list[idx].height; 9929 rmask = sraRgnCreateRect(x2, y2, x2+w2, y2+h2); 9930 sraRgnAnd(rmask, unmapped_rgn); 9931 if (sraRgnEmpty(rmask)) { 9932 sraRgnDestroy(rmask); 9933 rmask = NULL; 9934 } 9935 } 9936 if (ev_lookup(win, EV_CONFIGURE_SIZE)) { 9937 valid = valid_window(win, &attr, 1); 9938 } else { 9939 X_UNLOCK; 9940 bs_restore(idx, nbatch, rmask, &attr, 0, 1, &valid, 1); 9941 X_LOCK; 9942 } 9943 if (rmask != NULL) { 9944 sraRgnDestroy(rmask); 9945 } 9946 if (valid) { 9947 STORE(idx, win, attr); 9948 9949 cache_list[idx].time = dnow(); 9950 cache_list[idx].vis_cnt++; 9951 Ev_map[ik] = win; 9952 Ev_rects[nrects].x1 = cache_list[idx].x; 9953 Ev_rects[nrects].y1 = cache_list[idx].y; 9954 Ev_rects[nrects].x2 = cache_list[idx].width; 9955 Ev_rects[nrects].y2 = cache_list[idx].height; 9956 nrects++; 9957 SCHED(win, 1) 9958 } else { 9959 DELETE(idx); 9960 } 9961 } 9962 } 9963 if (state == VisibilityUnobscured) { 9964 cache_list[idx].vis_unobs_time = last_vis_unobs_time = dnow(); 9965 } else if (cache_list[idx].vis_state == VisibilityUnobscured) { 9966 cache_list[idx].vis_obs_time = last_vis_obs_time = dnow(); 9967 } 9968 cache_list[idx].vis_state = state; 9969 9970 } else if (type == MapNotify) { 9971 idx = lookup_win_index(win); 9972 if (ncdb) fprintf(stderr, "----%02d: MapNotify 0x%lx %3d\n", ik, win, idx); 9973 9974 if (idx < 0) { 9975 continue; 9976 } 9977 9978 #if 0 9979 /* 9980 if (cache_list[idx].map_state == IsUnmapped || desktop_change || macosx_console) 9981 */ 9982 #endif 9983 if (1) { 9984 X_UNLOCK; 9985 if (desktop_change) { 9986 /* XXX Y */ 9987 int save = 1; 9988 sraRegionPtr r; 9989 if (cache_list[idx].su_time != 0.0) { 9990 save = 0; 9991 } else if (missed_su_restore) { 9992 r = idx_create_rgn(r0, idx); 9993 if (sraRgnAnd(r, missed_su_restore_rgn)) { 9994 save = 0; 9995 } 9996 sraRgnDestroy(r); 9997 } 9998 if (missed_bs_restore) { 9999 r = idx_create_rgn(r0, idx); 10000 if (sraRgnAnd(r, missed_bs_restore_rgn)) { 10001 save = 0; 10002 } 10003 sraRgnDestroy(r); 10004 } 10005 if (save) { 10006 valid = 0; 10007 su_save(idx, nbatch, &attr, 1, &valid, 1); 10008 if (valid) { 10009 STORE(idx, win, attr); 10010 } 10011 } 10012 } else { 10013 valid = 0; 10014 su_save(idx, nbatch, &attr, 0, &valid, 1); 10015 if (valid) { 10016 STORE(idx, win, attr); 10017 } 10018 } 10019 valid = 0; 10020 if (ev_lookup(win, EV_CONFIGURE_SIZE)) { 10021 X_LOCK; 10022 valid = valid_window(win, &attr, 1); 10023 X_UNLOCK; 10024 idx_add_rgn(missed_bs_restore_rgn, r0, idx); 10025 missed_bs_restore++; 10026 } else if (bs_restore(idx, nbatch, NULL, &attr, 0, 0, &valid, 1)) { /* XXX clip? */ 10027 ; 10028 } else { 10029 idx_add_rgn(missed_bs_restore_rgn, r0, idx); 10030 missed_bs_restore++; 10031 } 10032 if (valid) { 10033 STORE(idx, win, attr); 10034 } 10035 10036 if (macosx_console) { 10037 #ifdef MACOSX 10038 macosxCGS_follow_animation_win(win, -1, 1); 10039 if (valid_window(win, &attr, 1)) { 10040 STORE(idx, win, attr); 10041 SCHED(win, 1); 10042 } 10043 /* XXX Y */ 10044 if (cache_list[idx].vis_state == -1) { 10045 cache_list[idx].vis_state = VisibilityUnobscured; 10046 } 10047 #endif 10048 } 10049 X_LOCK; 10050 pixels += cache_list[idx].width * cache_list[idx].height; 10051 cache_list[idx].time = dnow(); 10052 cache_list[idx].map_cnt++; 10053 Ev_map[ik] = win; 10054 Ev_rects[nrects].x1 = cache_list[idx].x; 10055 Ev_rects[nrects].y1 = cache_list[idx].y; 10056 Ev_rects[nrects].x2 = cache_list[idx].width; 10057 Ev_rects[nrects].y2 = cache_list[idx].height; 10058 nrects++; 10059 10060 if (! valid) { 10061 DELETE(idx); 10062 } 10063 } 10064 cache_list[idx].map_state = IsViewable; 10065 10066 } else if (type == UnmapNotify) { 10067 int x2, y2, w2, h2; 10068 idx = lookup_win_index(win); 10069 if (ncdb) fprintf(stderr, "----%02d: UnmapNotify 0x%lx %3d\n", ik, win, idx); 10070 10071 if (idx < 0) { 10072 continue; 10073 } 10074 if (macosx_console) { 10075 if (mode == 2) { 10076 cache_list[idx].map_state = IsViewable; 10077 } 10078 } 10079 10080 #if 0 10081 /* 10082 if (cache_list[idx].map_state == IsViewable || desktop_change || macosx_console) 10083 */ 10084 #endif 10085 if (1) { 10086 X_UNLOCK; 10087 if (desktop_change) { 10088 int save = 1; 10089 sraRegionPtr r; 10090 if (cache_list[idx].bs_time > 0.0) { 10091 save = 0; 10092 } else if (missed_su_restore) { 10093 r = idx_create_rgn(r0, idx); 10094 if (sraRgnAnd(r, missed_su_restore_rgn)) { 10095 save = 0; 10096 } 10097 sraRgnDestroy(r); 10098 } 10099 if (missed_bs_restore) { 10100 r = idx_create_rgn(r0, idx); 10101 if (sraRgnAnd(r, missed_bs_restore_rgn)) { 10102 save = 0; 10103 } 10104 sraRgnDestroy(r); 10105 } 10106 if (save) { 10107 valid = 0; 10108 bs_save(idx, nbatch, &attr, 1, 0, &valid, 1); 10109 } 10110 } else { 10111 valid = 0; 10112 bs_save(idx, nbatch, &attr, 1, 0, &valid, 1); 10113 } 10114 valid = 0; 10115 if (su_restore(idx, nbatch, NULL, &attr, 1, 0, &valid, 1)) { 10116 try_to_fix_su(win, idx, None, nbatch, "unmapped"); 10117 if (valid) { 10118 STORE(idx, win, attr); 10119 } else { 10120 DELETE(idx); 10121 } 10122 } else { 10123 idx_add_rgn(missed_su_restore_rgn, r0, idx); 10124 missed_su_restore++; 10125 } 10126 X_LOCK; 10127 10128 pixels += cache_list[idx].width * cache_list[idx].height; 10129 cache_list[idx].time = dnow(); 10130 cache_list[idx].unmap_cnt++; 10131 Ev_unmap[ik] = win; 10132 Ev_rects[nrects].x1 = cache_list[idx].x; 10133 Ev_rects[nrects].y1 = cache_list[idx].y; 10134 Ev_rects[nrects].x2 = cache_list[idx].width; 10135 Ev_rects[nrects].y2 = cache_list[idx].height; 10136 nrects++; 10137 } 10138 10139 x2 = cache_list[idx].x; 10140 y2 = cache_list[idx].y; 10141 w2 = cache_list[idx].width; 10142 h2 = cache_list[idx].height; 10143 r = sraRgnCreateRect(x2, y2, x2+w2, y2+h2); 10144 sraRgnAnd(r, r0); 10145 sraRgnOr(unmapped_rgn, r); 10146 sraRgnDestroy(r); 10147 10148 cache_list[idx].map_state = IsUnmapped; 10149 10150 } else if (type == ReparentNotify) { 10151 if (ev.xreparent.parent != rootwin) { 10152 win2 = ev.xreparent.window; 10153 if (win2 != rootwin) { 10154 idx = lookup_win_index(win2); 10155 if (ncdb) fprintf(stderr, "----%02d: ReparentNotifyRM 0x%lx %3d\n", ik, win2, idx); 10156 } 10157 } 10158 10159 } else if (type == DestroyNotify) { 10160 win2 = ev.xdestroywindow.window; 10161 idx = lookup_win_index(win2); 10162 if (ncdb) fprintf(stderr, "----%02d: DestroyNotify 0x%lx %3d\n", ik, win2, idx); 10163 10164 if (idx >= 0) { 10165 DELETE(idx); 10166 } 10167 } else { 10168 if (ncdb) fprintf(stderr, "igno%02d: ** Ignoring 0x%lx type: %s\n", ik, win, Etype(type)); 10169 } 10170 10171 } 10172 } 10173 X_UNLOCK; 10174 10175 if (use_batch && nreg) { 10176 batch_push(nreg, -1.0); 10177 } 10178 if (nrects) { 10179 if (scaling) { 10180 push_borders(Ev_rects, nrects); 10181 } 10182 } 10183 10184 check_sched(try_batch, &did_sched); 10185 10186 if (n_CN || n_RN || n_DN || n_MN || n_UN || n_ST || n_DC || did_sched) { 10187 snap_old(); 10188 } 10189 10190 sraRgnDestroy(r0); 10191 sraRgnDestroy(missed_su_restore_rgn); 10192 sraRgnDestroy(missed_bs_restore_rgn); 10193 10194 if (ncdb) rfbLog("OUT check_ncache(): %.4f %.6f events: %d pixels: %d\n", dnowx(), dnow() - now, n, pixels); 10195 if (ncdb) fprintf(stderr, "\n"); 10196 return pixels; 10197 } 10198 #endif 10199 10200