Home | History | Annotate | Download | only in x11vnc
      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 /* -- scan.c -- */
     34 
     35 #include "x11vnc.h"
     36 #include "xinerama.h"
     37 #include "xwrappers.h"
     38 #include "xdamage.h"
     39 #include "xrandr.h"
     40 #include "win_utils.h"
     41 #include "8to24.h"
     42 #include "screen.h"
     43 #include "pointer.h"
     44 #include "cleanup.h"
     45 #include "unixpw.h"
     46 #include "screen.h"
     47 #include "macosx.h"
     48 #include "userinput.h"
     49 
     50 /*
     51  * routines for scanning and reading the X11 display for changes, and
     52  * for doing all the tile work (shm, etc).
     53  */
     54 void initialize_tiles(void);
     55 void free_tiles(void);
     56 void shm_delete(XShmSegmentInfo *shm);
     57 void shm_clean(XShmSegmentInfo *shm, XImage *xim);
     58 void initialize_polling_images(void);
     59 void scale_rect(double factor_x, double factor_y, int blend, int interpolate, int Bpp,
     60     char *src_fb, int src_bytes_per_line, char *dst_fb, int dst_bytes_per_line,
     61     int Nx, int Ny, int nx, int ny, int X1, int Y1, int X2, int Y2, int mark);
     62 void scale_and_mark_rect(int X1, int Y1, int X2, int Y2, int mark);
     63 void mark_rect_as_modified(int x1, int y1, int x2, int y2, int force);
     64 int copy_screen(void);
     65 int copy_snap(void);
     66 void nap_sleep(int ms, int split);
     67 void set_offset(void);
     68 int scan_for_updates(int count_only);
     69 void rotate_curs(char *dst_0, char *src_0, int Dx, int Dy, int Bpp);
     70 void rotate_coords(int x, int y, int *xo, int *yo, int dxi, int dyi);
     71 void rotate_coords_inverse(int x, int y, int *xo, int *yo, int dxi, int dyi);
     72 
     73 static void set_fs_factor(int max);
     74 static char *flip_ximage_byte_order(XImage *xim);
     75 static int shm_create(XShmSegmentInfo *shm, XImage **ximg_ptr, int w, int h,
     76     char *name);
     77 static void create_tile_hint(int x, int y, int tw, int th, hint_t *hint);
     78 static void extend_tile_hint(int x, int y, int tw, int th, hint_t *hint);
     79 static void save_hint(hint_t hint, int loc);
     80 static void hint_updates(void);
     81 static void mark_hint(hint_t hint);
     82 static int copy_tiles(int tx, int ty, int nt);
     83 static int copy_all_tiles(void);
     84 static int copy_all_tile_runs(void);
     85 static int copy_tiles_backward_pass(void);
     86 static int copy_tiles_additional_pass(void);
     87 static int gap_try(int x, int y, int *run, int *saw, int along_x);
     88 static int fill_tile_gaps(void);
     89 static int island_try(int x, int y, int u, int v, int *run);
     90 static int grow_islands(void);
     91 static void blackout_regions(void);
     92 static void nap_set(int tile_cnt);
     93 static void nap_check(int tile_cnt);
     94 static void ping_clients(int tile_cnt);
     95 static int blackout_line_skip(int n, int x, int y, int rescan,
     96     int *tile_count);
     97 static int blackout_line_cmpskip(int n, int x, int y, char *dst, char *src,
     98     int w, int pixelsize);
     99 static int scan_display(int ystart, int rescan);
    100 
    101 
    102 /* array to hold the hints: */
    103 static hint_t *hint_list;
    104 
    105 /* nap state */
    106 int nap_ok = 0;
    107 static int nap_diff_count = 0;
    108 
    109 static int scan_count = 0;	/* indicates which scan pattern we are on  */
    110 static int scan_in_progress = 0;
    111 
    112 
    113 typedef struct tile_change_region {
    114 	/* start and end lines, along y, of the changed area inside a tile. */
    115 	unsigned short first_line, last_line;
    116 	short first_x, last_x;
    117 	/* info about differences along edges. */
    118 	unsigned short left_diff, right_diff;
    119 	unsigned short top_diff,  bot_diff;
    120 } region_t;
    121 
    122 /* array to hold the tiles region_t-s. */
    123 static region_t *tile_region;
    124 
    125 
    126 
    127 
    128 /*
    129  * setup tile numbers and allocate the tile and hint arrays:
    130  */
    131 void initialize_tiles(void) {
    132 
    133 	ntiles_x = (dpy_x - 1)/tile_x + 1;
    134 	ntiles_y = (dpy_y - 1)/tile_y + 1;
    135 	ntiles = ntiles_x * ntiles_y;
    136 
    137 	tile_has_diff = (unsigned char *)
    138 		calloc((size_t) (ntiles * sizeof(unsigned char)), 1);
    139 	tile_has_xdamage_diff = (unsigned char *)
    140 		calloc((size_t) (ntiles * sizeof(unsigned char)), 1);
    141 	tile_row_has_xdamage_diff = (unsigned char *)
    142 		calloc((size_t) (ntiles_y * sizeof(unsigned char)), 1);
    143 	tile_tried    = (unsigned char *)
    144 		calloc((size_t) (ntiles * sizeof(unsigned char)), 1);
    145 	tile_copied   = (unsigned char *)
    146 		calloc((size_t) (ntiles * sizeof(unsigned char)), 1);
    147 	tile_blackout    = (tile_blackout_t *)
    148 		calloc((size_t) (ntiles * sizeof(tile_blackout_t)), 1);
    149 	tile_region = (region_t *) calloc((size_t) (ntiles * sizeof(region_t)), 1);
    150 
    151 	tile_row = (XImage **)
    152 		calloc((size_t) ((ntiles_x + 1) * sizeof(XImage *)), 1);
    153 	tile_row_shm = (XShmSegmentInfo *)
    154 		calloc((size_t) ((ntiles_x + 1) * sizeof(XShmSegmentInfo)), 1);
    155 
    156 	/* there will never be more hints than tiles: */
    157 	hint_list = (hint_t *) calloc((size_t) (ntiles * sizeof(hint_t)), 1);
    158 }
    159 
    160 void free_tiles(void) {
    161 	if (tile_has_diff) {
    162 		free(tile_has_diff);
    163 		tile_has_diff = NULL;
    164 	}
    165 	if (tile_has_xdamage_diff) {
    166 		free(tile_has_xdamage_diff);
    167 		tile_has_xdamage_diff = NULL;
    168 	}
    169 	if (tile_row_has_xdamage_diff) {
    170 		free(tile_row_has_xdamage_diff);
    171 		tile_row_has_xdamage_diff = NULL;
    172 	}
    173 	if (tile_tried) {
    174 		free(tile_tried);
    175 		tile_tried = NULL;
    176 	}
    177 	if (tile_copied) {
    178 		free(tile_copied);
    179 		tile_copied = NULL;
    180 	}
    181 	if (tile_blackout) {
    182 		free(tile_blackout);
    183 		tile_blackout = NULL;
    184 	}
    185 	if (tile_region) {
    186 		free(tile_region);
    187 		tile_region = NULL;
    188 	}
    189 	if (tile_row) {
    190 		free(tile_row);
    191 		tile_row = NULL;
    192 	}
    193 	if (tile_row_shm) {
    194 		free(tile_row_shm);
    195 		tile_row_shm = NULL;
    196 	}
    197 	if (hint_list) {
    198 		free(hint_list);
    199 		hint_list = NULL;
    200 	}
    201 }
    202 
    203 /*
    204  * silly function to factor dpy_y until fullscreen shm is not bigger than max.
    205  * should always work unless dpy_y is a large prime or something... under
    206  * failure fs_factor remains 0 and no fullscreen updates will be tried.
    207  */
    208 static int fs_factor = 0;
    209 
    210 static void set_fs_factor(int max) {
    211 	int f, fac = 1, n = dpy_y;
    212 
    213 	fs_factor = 0;
    214 	if ((bpp/8) * dpy_x * dpy_y <= max)  {
    215 		fs_factor = 1;
    216 		return;
    217 	}
    218 	for (f=2; f <= 101; f++) {
    219 		while (n % f == 0) {
    220 			n = n / f;
    221 			fac = fac * f;
    222 			if ( (bpp/8) * dpy_x * (dpy_y/fac) <= max )  {
    223 				fs_factor = fac;
    224 				return;
    225 			}
    226 		}
    227 	}
    228 }
    229 
    230 static char *flip_ximage_byte_order(XImage *xim) {
    231 	char *order;
    232 	if (xim->byte_order == LSBFirst) {
    233 		order = "MSBFirst";
    234 		xim->byte_order = MSBFirst;
    235 		xim->bitmap_bit_order = MSBFirst;
    236 	} else {
    237 		order = "LSBFirst";
    238 		xim->byte_order = LSBFirst;
    239 		xim->bitmap_bit_order = LSBFirst;
    240 	}
    241 	return order;
    242 }
    243 
    244 /*
    245  * set up an XShm image, or if not using shm just create the XImage.
    246  */
    247 static int shm_create(XShmSegmentInfo *shm, XImage **ximg_ptr, int w, int h,
    248     char *name) {
    249 
    250 	XImage *xim;
    251 	static int reported_flip = 0;
    252 	int db = 0;
    253 
    254 	shm->shmid = -1;
    255 	shm->shmaddr = (char *) -1;
    256 	*ximg_ptr = NULL;
    257 
    258 	if (nofb) {
    259 		return 1;
    260 	}
    261 
    262 	X_LOCK;
    263 
    264 	if (! using_shm || xform24to32 || raw_fb) {
    265 		/* we only need the XImage created */
    266 		xim = XCreateImage_wr(dpy, default_visual, depth, ZPixmap,
    267 		    0, NULL, w, h, raw_fb ? 32 : BitmapPad(dpy), 0);
    268 
    269 		X_UNLOCK;
    270 
    271 		if (xim == NULL) {
    272 			rfbErr("XCreateImage(%s) failed.\n", name);
    273 			if (quiet) {
    274 				fprintf(stderr, "XCreateImage(%s) failed.\n",
    275 				    name);
    276 			}
    277 			return 0;
    278 		}
    279 		if (db) fprintf(stderr, "shm_create simple %d %d\t%p %s\n", w, h, (void *)xim, name);
    280 		xim->data = (char *) malloc(xim->bytes_per_line * xim->height);
    281 		if (xim->data == NULL) {
    282 			rfbErr("XCreateImage(%s) data malloc failed.\n", name);
    283 			if (quiet) {
    284 				fprintf(stderr, "XCreateImage(%s) data malloc"
    285 				    " failed.\n", name);
    286 			}
    287 			return 0;
    288 		}
    289 		if (flip_byte_order) {
    290 			char *order = flip_ximage_byte_order(xim);
    291 			if (! reported_flip && ! quiet) {
    292 				rfbLog("Changing XImage byte order"
    293 				    " to %s\n", order);
    294 				reported_flip = 1;
    295 			}
    296 		}
    297 
    298 		*ximg_ptr = xim;
    299 		return 1;
    300 	}
    301 
    302 	if (! dpy) {
    303 		X_UNLOCK;
    304 		return 0;
    305 	}
    306 
    307 	xim = XShmCreateImage_wr(dpy, default_visual, depth, ZPixmap, NULL,
    308 	    shm, w, h);
    309 
    310 	if (xim == NULL) {
    311 		rfbErr("XShmCreateImage(%s) failed.\n", name);
    312 		if (quiet) {
    313 			fprintf(stderr, "XShmCreateImage(%s) failed.\n", name);
    314 		}
    315 		X_UNLOCK;
    316 		return 0;
    317 	}
    318 
    319 	*ximg_ptr = xim;
    320 
    321 #if LIBVNCSERVER_HAVE_XSHM
    322 	shm->shmid = shmget(IPC_PRIVATE,
    323 	    xim->bytes_per_line * xim->height, IPC_CREAT | 0777);
    324 
    325 	if (shm->shmid == -1) {
    326 		rfbErr("shmget(%s) failed.\n", name);
    327 		rfbLogPerror("shmget");
    328 
    329 		XDestroyImage(xim);
    330 		*ximg_ptr = NULL;
    331 
    332 		X_UNLOCK;
    333 		return 0;
    334 	}
    335 
    336 	shm->shmaddr = xim->data = (char *) shmat(shm->shmid, 0, 0);
    337 
    338 	if (shm->shmaddr == (char *)-1) {
    339 		rfbErr("shmat(%s) failed.\n", name);
    340 		rfbLogPerror("shmat");
    341 
    342 		XDestroyImage(xim);
    343 		*ximg_ptr = NULL;
    344 
    345 		shmctl(shm->shmid, IPC_RMID, 0);
    346 		shm->shmid = -1;
    347 
    348 		X_UNLOCK;
    349 		return 0;
    350 	}
    351 
    352 	shm->readOnly = False;
    353 
    354 	if (! XShmAttach_wr(dpy, shm)) {
    355 		rfbErr("XShmAttach(%s) failed.\n", name);
    356 		XDestroyImage(xim);
    357 		*ximg_ptr = NULL;
    358 
    359 		shmdt(shm->shmaddr);
    360 		shm->shmaddr = (char *) -1;
    361 
    362 		shmctl(shm->shmid, IPC_RMID, 0);
    363 		shm->shmid = -1;
    364 
    365 		X_UNLOCK;
    366 		return 0;
    367 	}
    368 #endif
    369 
    370 	X_UNLOCK;
    371 	return 1;
    372 }
    373 
    374 void shm_delete(XShmSegmentInfo *shm) {
    375 #if LIBVNCSERVER_HAVE_XSHM
    376 	if (getenv("X11VNC_SHM_DEBUG")) fprintf(stderr, "shm_delete:    %p\n", (void *) shm);
    377 	if (shm != NULL && shm->shmaddr != (char *) -1) {
    378 		shmdt(shm->shmaddr);
    379 	}
    380 	if (shm != NULL && shm->shmid != -1) {
    381 		shmctl(shm->shmid, IPC_RMID, 0);
    382 	}
    383 	if (shm != NULL) {
    384 		shm->shmaddr = (char *) -1;
    385 		shm->shmid = -1;
    386 	}
    387 #else
    388 	if (!shm) {}
    389 #endif
    390 }
    391 
    392 void shm_clean(XShmSegmentInfo *shm, XImage *xim) {
    393 	int db = 0;
    394 
    395 	if (db) fprintf(stderr, "shm_clean: called:  %p\n", (void *)xim);
    396 	X_LOCK;
    397 #if LIBVNCSERVER_HAVE_XSHM
    398 	if (shm != NULL && shm->shmid != -1 && dpy) {
    399 		if (db) fprintf(stderr, "shm_clean: XShmDetach_wr\n");
    400 		XShmDetach_wr(dpy, shm);
    401 	}
    402 #endif
    403 	if (xim != NULL) {
    404 		if (! raw_fb_back_to_X) {	/* raw_fb hack */
    405 			if (xim->bitmap_unit != -1) {
    406 				if (db) fprintf(stderr, "shm_clean: XDestroyImage  %p\n", (void *)xim);
    407 				XDestroyImage(xim);
    408 			} else {
    409 				if (xim->data) {
    410 					if (db) fprintf(stderr, "shm_clean: free xim->data  %p %p\n", (void *)xim, (void *)(xim->data));
    411 					free(xim->data);
    412 					xim->data = NULL;
    413 				}
    414 			}
    415 		}
    416 		xim = NULL;
    417 	}
    418 	X_UNLOCK;
    419 
    420 	shm_delete(shm);
    421 }
    422 
    423 void initialize_polling_images(void) {
    424 	int i, MB = 1024 * 1024;
    425 
    426 	/* set all shm areas to "none" before trying to create any */
    427 	scanline_shm.shmid	= -1;
    428 	scanline_shm.shmaddr	= (char *) -1;
    429 	scanline		= NULL;
    430 	fullscreen_shm.shmid	= -1;
    431 	fullscreen_shm.shmaddr	= (char *) -1;
    432 	fullscreen		= NULL;
    433 	snaprect_shm.shmid	= -1;
    434 	snaprect_shm.shmaddr	= (char *) -1;
    435 	snaprect		= NULL;
    436 	for (i=1; i<=ntiles_x; i++) {
    437 		tile_row_shm[i].shmid	= -1;
    438 		tile_row_shm[i].shmaddr	= (char *) -1;
    439 		tile_row[i]		= NULL;
    440 	}
    441 
    442 	/* the scanline (e.g. 1280x1) shared memory area image: */
    443 
    444 	if (! shm_create(&scanline_shm, &scanline, dpy_x, 1, "scanline")) {
    445 		clean_up_exit(1);
    446 	}
    447 
    448 	/*
    449 	 * the fullscreen (e.g. 1280x1024/fs_factor) shared memory area image:
    450 	 * (we cut down the size of the shm area to try avoid and shm segment
    451 	 * limits, e.g. the default 1MB on Solaris)
    452 	 */
    453 	if (UT.sysname && strstr(UT.sysname, "Linux")) {
    454 		set_fs_factor(10 * MB);
    455 	} else {
    456 		set_fs_factor(1 * MB);
    457 	}
    458 	if (fs_frac >= 1.0) {
    459 		fs_frac = 1.1;
    460 		fs_factor = 0;
    461 	}
    462 	if (! fs_factor) {
    463 		rfbLog("warning: fullscreen updates are disabled.\n");
    464 	} else {
    465 		if (! shm_create(&fullscreen_shm, &fullscreen, dpy_x,
    466 		    dpy_y/fs_factor, "fullscreen")) {
    467 			clean_up_exit(1);
    468 		}
    469 	}
    470 	if (use_snapfb) {
    471 		if (! fs_factor) {
    472 			rfbLog("warning: disabling -snapfb mode.\n");
    473 			use_snapfb = 0;
    474 		} else if (! shm_create(&snaprect_shm, &snaprect, dpy_x,
    475 		    dpy_y/fs_factor, "snaprect")) {
    476 			clean_up_exit(1);
    477 		}
    478 	}
    479 
    480 	/*
    481 	 * for copy_tiles we need a lot of shared memory areas, one for
    482 	 * each possible run length of changed tiles.  32 for 1024x768
    483 	 * and 40 for 1280x1024, etc.
    484 	 */
    485 
    486 	tile_shm_count = 0;
    487 	for (i=1; i<=ntiles_x; i++) {
    488 		if (! shm_create(&tile_row_shm[i], &tile_row[i], tile_x * i,
    489 		    tile_y, "tile_row")) {
    490 			if (i == 1) {
    491 				clean_up_exit(1);
    492 			}
    493 			rfbLog("shm: Error creating shared memory tile-row for"
    494 			    " len=%d,\n", i);
    495 			rfbLog("shm: reverting to -onetile mode. If this"
    496 			    " problem persists\n");
    497 			rfbLog("shm: try using the -onetile or -noshm options"
    498 			    " to limit\n");
    499 			rfbLog("shm: shared memory usage, or run ipcrm(1)"
    500 			    " to manually\n");
    501 			rfbLog("shm: delete unattached shm segments.\n");
    502 			single_copytile_count = i;
    503 			single_copytile = 1;
    504 		}
    505 		tile_shm_count++;
    506 		if (single_copytile && i >= 1) {
    507 			/* only need 1x1 tiles */
    508 			break;
    509 		}
    510 	}
    511 	if (verbose) {
    512 		if (using_shm && ! xform24to32) {
    513 			rfbLog("created %d tile_row shm polling images.\n",
    514 			    tile_shm_count);
    515 		} else {
    516 			rfbLog("created %d tile_row polling images.\n",
    517 			    tile_shm_count);
    518 		}
    519 	}
    520 }
    521 
    522 /*
    523  * A hint is a rectangular region built from 1 or more adjacent tiles
    524  * glued together.  Ultimately, this information in a single hint is sent
    525  * to libvncserver rather than sending each tile separately.
    526  */
    527 static void create_tile_hint(int x, int y, int tw, int th, hint_t *hint) {
    528 	int w = dpy_x - x;
    529 	int h = dpy_y - y;
    530 
    531 	if (w > tw) {
    532 		w = tw;
    533 	}
    534 	if (h > th) {
    535 		h = th;
    536 	}
    537 
    538 	hint->x = x;
    539 	hint->y = y;
    540 	hint->w = w;
    541 	hint->h = h;
    542 }
    543 
    544 static void extend_tile_hint(int x, int y, int tw, int th, hint_t *hint) {
    545 	int w = dpy_x - x;
    546 	int h = dpy_y - y;
    547 
    548 	if (w > tw) {
    549 		w = tw;
    550 	}
    551 	if (h > th) {
    552 		h = th;
    553 	}
    554 
    555 	if (hint->x > x) {			/* extend to the left */
    556 		hint->w += hint->x - x;
    557 		hint->x = x;
    558 	}
    559 	if (hint->y > y) {			/* extend upward */
    560 		hint->h += hint->y - y;
    561 		hint->y = y;
    562 	}
    563 
    564 	if (hint->x + hint->w < x + w) {	/* extend to the right */
    565 		hint->w = x + w - hint->x;
    566 	}
    567 	if (hint->y + hint->h < y + h) {	/* extend downward */
    568 		hint->h = y + h - hint->y;
    569 	}
    570 }
    571 
    572 static void save_hint(hint_t hint, int loc) {
    573 	/* simply copy it to the global array for later use. */
    574 	hint_list[loc].x = hint.x;
    575 	hint_list[loc].y = hint.y;
    576 	hint_list[loc].w = hint.w;
    577 	hint_list[loc].h = hint.h;
    578 }
    579 
    580 /*
    581  * Glue together horizontal "runs" of adjacent changed tiles into one big
    582  * rectangle change "hint" to be passed to the vnc machinery.
    583  */
    584 static void hint_updates(void) {
    585 	hint_t hint;
    586 	int x, y, i, n, ty, th, tx, tw;
    587 	int hint_count = 0, in_run = 0;
    588 
    589 	hint.x = hint.y = hint.w = hint.h = 0;
    590 
    591 	for (y=0; y < ntiles_y; y++) {
    592 		for (x=0; x < ntiles_x; x++) {
    593 			n = x + y * ntiles_x;
    594 
    595 			if (tile_has_diff[n]) {
    596 				ty = tile_region[n].first_line;
    597 				th = tile_region[n].last_line - ty + 1;
    598 
    599 				tx = tile_region[n].first_x;
    600 				tw = tile_region[n].last_x - tx + 1;
    601 				if (tx < 0) {
    602 					tx = 0;
    603 					tw = tile_x;
    604 				}
    605 
    606 				if (! in_run) {
    607 					create_tile_hint( x * tile_x + tx,
    608 					    y * tile_y + ty, tw, th, &hint);
    609 					in_run = 1;
    610 				} else {
    611 					extend_tile_hint( x * tile_x + tx,
    612 					    y * tile_y + ty, tw, th, &hint);
    613 				}
    614 			} else {
    615 				if (in_run) {
    616 					/* end of a row run of altered tiles: */
    617 					save_hint(hint, hint_count++);
    618 					in_run = 0;
    619 				}
    620 			}
    621 		}
    622 		if (in_run) {	/* save the last row run */
    623 			save_hint(hint, hint_count++);
    624 			in_run = 0;
    625 		}
    626 	}
    627 
    628 	for (i=0; i < hint_count; i++) {
    629 		/* pass update info to vnc: */
    630 		mark_hint(hint_list[i]);
    631 	}
    632 }
    633 
    634 /*
    635  * kludge, simple ceil+floor for non-negative doubles:
    636  */
    637 #define CEIL(x)  ( (double) ((int) (x)) == (x) ? \
    638 	(double) ((int) (x)) : (double) ((int) (x) + 1) )
    639 #define FLOOR(x) ( (double) ((int) (x)) )
    640 
    641 /*
    642  * Scaling:
    643  *
    644  * For shrinking, a destination (scaled) pixel will correspond to more
    645  * than one source (i.e. main fb) pixel.  Think of an x-y plane made with
    646  * graph paper.  Each unit square in the graph paper (i.e. collection of
    647  * points (x,y) such that N < x < N+1 and M < y < M+1, N and M integers)
    648  * corresponds to one pixel in the unscaled fb.  There is a solid
    649  * color filling the inside of such a square.  A scaled pixel has width
    650  * 1/scale_fac, e.g. for "-scale 3/4" the width of the scaled pixel
    651  * is 1.333.  The area of this scaled pixel is 1.333 * 1.333 (so it
    652  * obviously overlaps more than one source pixel, each which have area 1).
    653  *
    654  * We take the weight an unscaled pixel (source) contributes to a
    655  * scaled pixel (destination) as simply proportional to the overlap area
    656  * between the two pixels.  One can then think of the value of the scaled
    657  * pixel as an integral over the portion of the graph paper it covers.
    658  * The thing being integrated is the color value of the unscaled source.
    659  * That color value is constant over a graph paper square (source pixel),
    660  * and changes discontinuously from one unit square to the next.
    661  *
    662 
    663 Here is an example for -scale 3/4, the solid lines are the source pixels
    664 (graph paper unit squares), while the dotted lines denote the scaled
    665 pixels (destination pixels):
    666 
    667             0         1 4/3     2     8/3 3         4=12/3
    668             |---------|--.------|------.--|---------|.
    669             |         |  .      |      .  |         |.
    670             |    A    |  . B    |      .  |         |.
    671             |         |  .      |      .  |         |.
    672             |         |  .      |      .  |         |.
    673           1 |---------|--.------|------.--|---------|.
    674          4/3|.........|.........|.........|.........|.
    675             |         |  .      |      .  |         |.
    676             |    C    |  . D    |      .  |         |.
    677             |         |  .      |      .  |         |.
    678           2 |---------|--.------|------.--|---------|.
    679             |         |  .      |      .  |         |.
    680             |         |  .      |      .  |         |.
    681          8/3|.........|.........|.........|.........|.
    682             |         |  .      |      .  |         |.
    683           3 |---------|--.------|------.--|---------|.
    684 
    685 So we see the first scaled pixel (0 < x < 4/3 and 0 < y < 4/3) mostly
    686 overlaps with unscaled source pixel "A".  The integration (averaging)
    687 weights for this scaled pixel are:
    688 
    689 			A	 1
    690 			B	1/3
    691 			C	1/3
    692 			D	1/9
    693 
    694  *
    695  * The Red, Green, and Blue color values must be averaged over separately
    696  * otherwise you can get a complete mess (except in solid regions),
    697  * because high order bits are averaged differently from the low order bits.
    698  *
    699  * So the algorithm is roughly:
    700  *
    701  *   - Given as input a rectangle in the unscaled source fb with changes,
    702  *     find the rectangle of pixels this affects in the scaled destination fb.
    703  *
    704  *   - For each of the affected scaled (dest) pixels, determine all of the
    705  *     unscaled (source) pixels it overlaps with.
    706  *
    707  *   - Average those unscaled source values together, weighted by the area
    708  *     overlap with the destination pixel.  Average R, G, B separately.
    709  *
    710  *   - Take this average value and convert to a valid pixel value if
    711  *     necessary (e.g. rounding, shifting), and then insert it into the
    712  *     destination framebuffer as the pixel value.
    713  *
    714  *   - On to the next destination pixel...
    715  *
    716  * ========================================================================
    717  *
    718  * For expanding, e.g. -scale 1.1 (which we don't think people will do
    719  * very often... or at least so we hope, the framebuffer can become huge)
    720  * the situation is reversed and the destination pixel is smaller than a
    721  * "graph paper" unit square (source pixel).  Some destination pixels
    722  * will be completely within a single unscaled source pixel.
    723  *
    724  * What we do here is a simple 4 point interpolation scheme:
    725  *
    726  * Let P00 be the source pixel closest to the destination pixel but with
    727  * x and y values less than or equal to those of the destination pixel.
    728  * (for simplicity, think of the upper left corner of a pixel defining the
    729  * x,y location of the pixel, the center would work just as well).  So it
    730  * is the source pixel immediately to the upper left of the destination
    731  * pixel.  Let P10 be the source pixel one to the right of P00.  Let P01
    732  * be one down from P00.  And let P11 be one down and one to the right
    733  * of P00.  They form a 2x2 square we will interpolate inside of.
    734  *
    735  * Let V00, V10, V01, and V11 be the color values of those 4 source
    736  * pixels.  Let dx be the displacement along x the destination pixel is
    737  * from P00.  Note: 0 <= dx < 1 by definition of P00.  Similarly let
    738  * dy be the displacement along y.  The weighted average for the
    739  * interpolation is:
    740  *
    741  * 	V_ave = V00 * (1 - dx) * (1 - dy)
    742  * 	      + V10 *      dx  * (1 - dy)
    743  * 	      + V01 * (1 - dx) *      dy
    744  * 	      + V11 *      dx  *      dy
    745  *
    746  * Note that the weights (1-dx)*(1-dy) + dx*(1-dy) + (1-dx)*dy + dx*dy
    747  * automatically add up to 1.  It is also nice that all the weights are
    748  * positive (unsigned char stays unsigned char).  The above formula can
    749  * be motivated by doing two 1D interpolations along x:
    750  *
    751  * 	VA = V00 * (1 - dx) + V10 * dx
    752  * 	VB = V01 * (1 - dx) + V11 * dx
    753  *
    754  * and then interpolating VA and VB along y:
    755  *
    756  * 	V_ave = VA * (1 - dy) + VB * dy
    757  *
    758  *                      VA
    759  *           v   |<-dx->|
    760  *           -- V00 ------ V10
    761  *           dy  |          |
    762  *           --  |      o...|...    "o" denotes the position of the desired
    763  *           ^   |      .   |  .    destination pixel relative to the P00
    764  *               |      .   |  .    source pixel.
    765  *              V10 ----.- V11 .
    766  *                      ........
    767  *                      |
    768  *                      VB
    769  *
    770  *
    771  * Of course R, G, B averages are done separately as in the shrinking
    772  * case.  This gives reasonable results, and the implementation for
    773  * shrinking can simply be used with different choices for weights for
    774  * the loop over the 4 pixels.
    775  */
    776 
    777 void scale_rect(double factor_x, double factor_y, int blend, int interpolate, int Bpp,
    778     char *src_fb, int src_bytes_per_line, char *dst_fb, int dst_bytes_per_line,
    779     int Nx, int Ny, int nx, int ny, int X1, int Y1, int X2, int Y2, int mark) {
    780 /*
    781  * Notation:
    782  * "i" an x pixel index in the destination (scaled) framebuffer
    783  * "j" a  y pixel index in the destination (scaled) framebuffer
    784  * "I" an x pixel index in the source (un-scaled, i.e. main) framebuffer
    785  * "J" a  y pixel index in the source (un-scaled, i.e. main) framebuffer
    786  *
    787  *  Similarly for nx, ny, Nx, Ny, etc.  Lowercase: dest, Uppercase: source.
    788  */
    789 	int i, j, i1, i2, j1, j2;	/* indices for scaled fb (dest) */
    790 	int I, J, I1, I2, J1, J2;	/* indices for main fb   (source) */
    791 
    792 	double w, wx, wy, wtot;	/* pixel weights */
    793 
    794 	double x1, y1, x2, y2;	/* x-y coords for destination pixels edges */
    795 	double dx, dy;		/* size of destination pixel */
    796 	double ddx=0, ddy=0;	/* for interpolation expansion */
    797 
    798 	char *src, *dest;	/* pointers to the two framebuffers */
    799 
    800 
    801 	unsigned short us = 0;
    802 	unsigned char  uc = 0;
    803 	unsigned int   ui = 0;
    804 
    805 	int use_noblend_shortcut = 1;
    806 	int shrink;		/* whether shrinking or expanding */
    807 	static int constant_weights = -1, mag_int = -1;
    808 	static int last_Nx = -1, last_Ny = -1, cnt = 0;
    809 	static double last_factor = -1.0;
    810 	int b, k;
    811 	double pixave[4];	/* for averaging pixel values */
    812 
    813 	if (factor_x <= 1.0 && factor_y <= 1.0) {
    814 		shrink = 1;
    815 	} else {
    816 		shrink = 0;
    817 	}
    818 
    819 	/*
    820 	 * N.B. width and height (real numbers) of a scaled pixel.
    821 	 * both are > 1   (e.g. 1.333 for -scale 3/4)
    822 	 * they should also be equal but we don't assume it.
    823 	 *
    824 	 * This new way is probably the best we can do, take the inverse
    825 	 * of the scaling factor to double precision.
    826 	 */
    827 	dx = 1.0/factor_x;
    828 	dy = 1.0/factor_y;
    829 
    830 	/*
    831 	 * There is some speedup if the pixel weights are constant, so
    832 	 * let's special case these.
    833 	 *
    834 	 * If scale = 1/n and n divides Nx and Ny, the pixel weights
    835 	 * are constant (e.g. 1/2 => equal on 2x2 square).
    836 	 */
    837 	if (factor_x != last_factor || Nx != last_Nx || Ny != last_Ny) {
    838 		constant_weights = -1;
    839 		mag_int = -1;
    840 		last_Nx = Nx;
    841 		last_Ny = Ny;
    842 		last_factor = factor_x;
    843 	}
    844 	if (constant_weights < 0 && factor_x != factor_y) {
    845 		constant_weights = 0;
    846 		mag_int = 0;
    847 
    848 	} else if (constant_weights < 0) {
    849 		int n = 0;
    850 
    851 		constant_weights = 0;
    852 		mag_int = 0;
    853 
    854 		for (i = 2; i<=128; i++) {
    855 			double test = ((double) 1)/ i;
    856 			double diff, eps = 1.0e-7;
    857 			diff = factor_x - test;
    858 			if (-eps < diff && diff < eps) {
    859 				n = i;
    860 				break;
    861 			}
    862 		}
    863 		if (! blend || ! shrink || interpolate) {
    864 			;
    865 		} else if (n != 0) {
    866 			if (Nx % n == 0 && Ny % n == 0) {
    867 				static int didmsg = 0;
    868 				if (mark && ! didmsg) {
    869 					didmsg = 1;
    870 					rfbLog("scale_and_mark_rect: using "
    871 					    "constant pixel weight speedup "
    872 					    "for 1/%d\n", n);
    873 				}
    874 				constant_weights = 1;
    875 			}
    876 		}
    877 
    878 		n = 0;
    879 		for (i = 2; i<=32; i++) {
    880 			double test = (double) i;
    881 			double diff, eps = 1.0e-7;
    882 			diff = factor_x - test;
    883 			if (-eps < diff && diff < eps) {
    884 				n = i;
    885 				break;
    886 			}
    887 		}
    888 		if (! blend && factor_x > 1.0 && n) {
    889 			mag_int = n;
    890 		}
    891 	}
    892 
    893 	if (mark && factor_x > 1.0 && blend) {
    894 		/*
    895 		 * kludge: correct for interpolating blurring leaking
    896 		 * up or left 1 destination pixel.
    897 		 */
    898 		if (X1 > 0) X1--;
    899 		if (Y1 > 0) Y1--;
    900 	}
    901 
    902 	/*
    903 	 * find the extent of the change the input rectangle induces in
    904 	 * the scaled framebuffer.
    905 	 */
    906 
    907 	/* Left edges: find largest i such that i * dx <= X1  */
    908 	i1 = FLOOR(X1/dx);
    909 
    910 	/* Right edges: find smallest i such that (i+1) * dx >= X2+1  */
    911 	i2 = CEIL( (X2+1)/dx ) - 1;
    912 
    913 	/* To be safe, correct any overflows: */
    914 	i1 = nfix(i1, nx);
    915 	i2 = nfix(i2, nx) + 1;	/* add 1 to make a rectangle upper boundary */
    916 
    917 	/* Repeat above for y direction: */
    918 	j1 = FLOOR(Y1/dy);
    919 	j2 = CEIL( (Y2+1)/dy ) - 1;
    920 
    921 	j1 = nfix(j1, ny);
    922 	j2 = nfix(j2, ny) + 1;
    923 
    924 	/*
    925 	 * special case integer magnification with no blending.
    926 	 * vision impaired magnification usage is interested in this case.
    927 	 */
    928 	if (mark && ! blend && mag_int && Bpp != 3) {
    929 		int jmin, jmax, imin, imax;
    930 
    931 		/* outer loop over *source* pixels */
    932 		for (J=Y1; J < Y2; J++) {
    933 		    jmin = J * mag_int;
    934 		    jmax = jmin + mag_int;
    935 		    for (I=X1; I < X2; I++) {
    936 			/* extract value */
    937 			src = src_fb + J*src_bytes_per_line + I*Bpp;
    938 			if (Bpp == 4) {
    939 				ui = *((unsigned int *)src);
    940 			} else if (Bpp == 2) {
    941 				us = *((unsigned short *)src);
    942 			} else if (Bpp == 1) {
    943 				uc = *((unsigned char *)src);
    944 			}
    945 			imin = I * mag_int;
    946 			imax = imin + mag_int;
    947 			/* inner loop over *dest* pixels */
    948 			for (j=jmin; j<jmax; j++) {
    949 			    dest = dst_fb + j*dst_bytes_per_line + imin*Bpp;
    950 			    for (i=imin; i<imax; i++) {
    951 				if (Bpp == 4) {
    952 					*((unsigned int *)dest) = ui;
    953 				} else if (Bpp == 2) {
    954 					*((unsigned short *)dest) = us;
    955 				} else if (Bpp == 1) {
    956 					*((unsigned char *)dest) = uc;
    957 				}
    958 				dest += Bpp;
    959 			    }
    960 			}
    961 		    }
    962 		}
    963 		goto markit;
    964 	}
    965 
    966 	/* set these all to 1.0 to begin with */
    967 	wx = 1.0;
    968 	wy = 1.0;
    969 	w  = 1.0;
    970 
    971 	/*
    972 	 * Loop over destination pixels in scaled fb:
    973 	 */
    974 	for (j=j1; j<j2; j++) {
    975 		y1 =  j * dy;	/* top edge */
    976 		if (y1 > Ny - 1) {
    977 			/* can go over with dy = 1/scale_fac */
    978 			y1 = Ny - 1;
    979 		}
    980 		y2 = y1 + dy;	/* bottom edge */
    981 
    982 		/* Find main fb indices covered by this dest pixel: */
    983 		J1 = (int) FLOOR(y1);
    984 		J1 = nfix(J1, Ny);
    985 
    986 		if (shrink && ! interpolate) {
    987 			J2 = (int) CEIL(y2) - 1;
    988 			J2 = nfix(J2, Ny);
    989 		} else {
    990 			J2 = J1 + 1;	/* simple interpolation */
    991 			ddy = y1 - J1;
    992 		}
    993 
    994 		/* destination char* pointer: */
    995 		dest = dst_fb + j*dst_bytes_per_line + i1*Bpp;
    996 
    997 		for (i=i1; i<i2; i++) {
    998 
    999 			x1 =  i * dx;	/* left edge */
   1000 			if (x1 > Nx - 1) {
   1001 				/* can go over with dx = 1/scale_fac */
   1002 				x1 = Nx - 1;
   1003 			}
   1004 			x2 = x1 + dx;	/* right edge */
   1005 
   1006 			cnt++;
   1007 
   1008 			/* Find main fb indices covered by this dest pixel: */
   1009 			I1 = (int) FLOOR(x1);
   1010 			if (I1 >= Nx) I1 = Nx - 1;
   1011 
   1012 			if (! blend && use_noblend_shortcut) {
   1013 				/*
   1014 				 * The noblend case involves no weights,
   1015 				 * and 1 pixel, so just copy the value
   1016 				 * directly.
   1017 				 */
   1018 				src = src_fb + J1*src_bytes_per_line + I1*Bpp;
   1019 				if (Bpp == 4) {
   1020 					*((unsigned int *)dest)
   1021 					    = *((unsigned int *)src);
   1022 				} else if (Bpp == 2) {
   1023 					*((unsigned short *)dest)
   1024 					    = *((unsigned short *)src);
   1025 				} else if (Bpp == 1) {
   1026 					*(dest) = *(src);
   1027 				} else if (Bpp == 3) {
   1028 					/* rare case */
   1029 					for (k=0; k<=2; k++) {
   1030 						*(dest+k) = *(src+k);
   1031 					}
   1032 				}
   1033 				dest += Bpp;
   1034 				continue;
   1035 			}
   1036 
   1037 			if (shrink && ! interpolate) {
   1038 				I2 = (int) CEIL(x2) - 1;
   1039 				if (I2 >= Nx) I2 = Nx - 1;
   1040 			} else {
   1041 				I2 = I1 + 1;	/* simple interpolation */
   1042 				ddx = x1 - I1;
   1043 			}
   1044 
   1045 			/* Zero out accumulators for next pixel average: */
   1046 			for (b=0; b<4; b++) {
   1047 				pixave[b] = 0.0; /* for RGB weighted sums */
   1048 			}
   1049 
   1050 			/*
   1051 			 * wtot is for accumulating the total weight.
   1052 			 * It should always sum to 1/(scale_fac * scale_fac).
   1053 			 */
   1054 			wtot = 0.0;
   1055 
   1056 			/*
   1057 			 * Loop over source pixels covered by this dest pixel.
   1058 			 *
   1059 			 * These "extra" loops over "J" and "I" make
   1060 			 * the cache/cacheline performance unclear.
   1061 			 * For example, will the data brought in from
   1062 			 * src for j, i, and J=0 still be in the cache
   1063 			 * after the J > 0 data have been accessed and
   1064 			 * we are at j, i+1, J=0?  The stride in J is
   1065 			 * main_bytes_per_line, and so ~4 KB.
   1066 			 *
   1067 			 * Typical case when shrinking are 2x2 loop, so
   1068 			 * just two lines to worry about.
   1069 			 */
   1070 			for (J=J1; J<=J2; J++) {
   1071 			    /* see comments for I, x1, x2, etc. below */
   1072 			    if (constant_weights) {
   1073 				;
   1074 			    } else if (! blend) {
   1075 				if (J != J1) {
   1076 					continue;
   1077 				}
   1078 				wy = 1.0;
   1079 
   1080 				/* interpolation scheme: */
   1081 			    } else if (! shrink || interpolate) {
   1082 				if (J >= Ny) {
   1083 					continue;
   1084 				} else if (J == J1) {
   1085 					wy = 1.0 - ddy;
   1086 				} else if (J != J1) {
   1087 					wy = ddy;
   1088 				}
   1089 
   1090 				/* integration scheme: */
   1091 			    } else if (J < y1) {
   1092 				wy = J+1 - y1;
   1093 			    } else if (J+1 > y2) {
   1094 				wy = y2 - J;
   1095 			    } else {
   1096 				wy = 1.0;
   1097 			    }
   1098 
   1099 			    src = src_fb + J*src_bytes_per_line + I1*Bpp;
   1100 
   1101 			    for (I=I1; I<=I2; I++) {
   1102 
   1103 				/* Work out the weight: */
   1104 
   1105 				if (constant_weights) {
   1106 					;
   1107 				} else if (! blend) {
   1108 					/*
   1109 					 * Ugh, PseudoColor colormap is
   1110 					 * bad news, to avoid random
   1111 					 * colors just take the first
   1112 					 * pixel.  Or user may have
   1113 					 * specified :nb to fraction.
   1114 					 * The :fb will force blending
   1115 					 * for this case.
   1116 					 */
   1117 					if (I != I1) {
   1118 						continue;
   1119 					}
   1120 					wx = 1.0;
   1121 
   1122 					/* interpolation scheme: */
   1123 				} else if (! shrink || interpolate) {
   1124 					if (I >= Nx) {
   1125 						continue;	/* off edge */
   1126 					} else if (I == I1) {
   1127 						wx = 1.0 - ddx;
   1128 					} else if (I != I1) {
   1129 						wx = ddx;
   1130 					}
   1131 
   1132 					/* integration scheme: */
   1133 				} else if (I < x1) {
   1134 					/*
   1135 					 * source left edge (I) to the
   1136 					 * left of dest left edge (x1):
   1137 					 * fractional weight
   1138 					 */
   1139 					wx = I+1 - x1;
   1140 				} else if (I+1 > x2) {
   1141 					/*
   1142 					 * source right edge (I+1) to the
   1143 					 * right of dest right edge (x2):
   1144 					 * fractional weight
   1145 					 */
   1146 					wx = x2 - I;
   1147 				} else {
   1148 					/*
   1149 					 * source edges (I and I+1) completely
   1150 					 * inside dest edges (x1 and x2):
   1151 					 * full weight
   1152 					 */
   1153 					wx = 1.0;
   1154 				}
   1155 
   1156 				w = wx * wy;
   1157 				wtot += w;
   1158 
   1159 				/*
   1160 				 * We average the unsigned char value
   1161 				 * instead of char value: otherwise
   1162 				 * the minimum (char 0) is right next
   1163 				 * to the maximum (char -1)!  This way
   1164 				 * they are spread between 0 and 255.
   1165 				 */
   1166 				if (Bpp == 4) {
   1167 					/* unroll the loops, can give 20% */
   1168 					pixave[0] += w * ((unsigned char) *(src  ));
   1169 					pixave[1] += w * ((unsigned char) *(src+1));
   1170 					pixave[2] += w * ((unsigned char) *(src+2));
   1171 					pixave[3] += w * ((unsigned char) *(src+3));
   1172 				} else if (Bpp == 2) {
   1173 					/*
   1174 					 * 16bpp: trickier with green
   1175 					 * split over two bytes, so we
   1176 					 * use the masks:
   1177 					 */
   1178 					us = *((unsigned short *) src);
   1179 					pixave[0] += w*(us & main_red_mask);
   1180 					pixave[1] += w*(us & main_green_mask);
   1181 					pixave[2] += w*(us & main_blue_mask);
   1182 				} else if (Bpp == 1) {
   1183 					pixave[0] += w *
   1184 					    ((unsigned char) *(src));
   1185 				} else {
   1186 					for (b=0; b<Bpp; b++) {
   1187 						pixave[b] += w *
   1188 						    ((unsigned char) *(src+b));
   1189 					}
   1190 				}
   1191 				src += Bpp;
   1192 			    }
   1193 			}
   1194 
   1195 			if (wtot <= 0.0) {
   1196 				wtot = 1.0;
   1197 			}
   1198 			wtot = 1.0/wtot;	/* normalization factor */
   1199 
   1200 			/* place weighted average pixel in the scaled fb: */
   1201 			if (Bpp == 4) {
   1202 				*(dest  ) = (char) (wtot * pixave[0]);
   1203 				*(dest+1) = (char) (wtot * pixave[1]);
   1204 				*(dest+2) = (char) (wtot * pixave[2]);
   1205 				*(dest+3) = (char) (wtot * pixave[3]);
   1206 			} else if (Bpp == 2) {
   1207 				/* 16bpp / 565 case: */
   1208 				pixave[0] *= wtot;
   1209 				pixave[1] *= wtot;
   1210 				pixave[2] *= wtot;
   1211 				us =  (main_red_mask   & (int) pixave[0])
   1212 				    | (main_green_mask & (int) pixave[1])
   1213 				    | (main_blue_mask  & (int) pixave[2]);
   1214 				*( (unsigned short *) dest ) = us;
   1215 			} else if (Bpp == 1) {
   1216 				*(dest) = (char) (wtot * pixave[0]);
   1217 			} else {
   1218 				for (b=0; b<Bpp; b++) {
   1219 					*(dest+b) = (char) (wtot * pixave[b]);
   1220 				}
   1221 			}
   1222 			dest += Bpp;
   1223 		}
   1224 	}
   1225 	markit:
   1226 	if (mark) {
   1227 		mark_rect_as_modified(i1, j1, i2, j2, 1);
   1228 	}
   1229 }
   1230 
   1231 /*
   1232  Framebuffers data flow:
   1233 
   1234  General case:
   1235                 --------       --------       --------        --------
   1236     -----      |8to24_fb|     |main_fb |     |snap_fb |      | X      |
   1237    |rfbfb| <== |        | <== |        | <== |        | <==  | Server |
   1238     -----       --------       --------       --------        --------
   1239    (to vnc)    (optional)    (usu = rfbfb)   (optional)      (read only)
   1240 
   1241  8to24_fb mode will create side fbs: poll24_fb and poll8_fb for
   1242  bookkeepping the different regions (merged into 8to24_fb).
   1243 
   1244  Normal case:
   1245     --------        --------
   1246    |main_fb |      | X      |
   1247    |= rfb_fb| <==  | Server |
   1248     --------        --------
   1249 
   1250  Scaling case:
   1251                 --------        --------
   1252     -----      |main_fb |      | X      |
   1253    |rfbfb| <== |        | <==  | Server |
   1254     -----       --------        --------
   1255 
   1256  Webcam/video case:
   1257     --------        --------        --------
   1258    |main_fb |      |snap_fb |      | Video  |
   1259    |        | <==  |        | <==  | device |
   1260     --------        --------        --------
   1261 
   1262 If we ever do a -rr rotation/reflection tran, it probably should
   1263 be done after any scaling (need a rr_fb for intermediate results)
   1264 
   1265 -rr option:		transformation:
   1266 
   1267 	none		x -> x;
   1268 			y -> y;
   1269 
   1270 	x		x -> w - x - 1;
   1271 			y -> y;
   1272 
   1273 	y		x -> x;
   1274 			x -> h - y - 1;
   1275 
   1276 	xy		x -> w - x - 1;
   1277 			y -> h - y - 1;
   1278 
   1279 	+90		x -> h - y - 1;
   1280 			y -> x;
   1281 
   1282 	+90x		x -> y;
   1283 			y -> x;
   1284 
   1285 	+90y		x -> h - y - 1;
   1286 			y -> w - x - 1;
   1287 
   1288 	-90		x -> y;
   1289 			y -> w - x - 1;
   1290 
   1291 some aliases:
   1292 
   1293 	xy:	yx, +180, -180, 180
   1294 	+90:	90
   1295 	+90x:	90x
   1296 	+90y:	90y
   1297 	-90:	+270, 270
   1298  */
   1299 
   1300 void scale_and_mark_rect(int X1, int Y1, int X2, int Y2, int mark) {
   1301 	char *dst_fb, *src_fb = main_fb;
   1302 	int dst_bpl, Bpp = bpp/8, fac = 1;
   1303 
   1304 	if (!screen || !rfb_fb || !main_fb) {
   1305 		return;
   1306 	}
   1307 	if (! screen->serverFormat.trueColour) {
   1308 		/*
   1309 		 * PseudoColor colormap... blending leads to random colors.
   1310 		 * User can override with ":fb"
   1311 		 */
   1312 		if (scaling_blend == 1) {
   1313 			/* :fb option sets it to 2 */
   1314 			if (default_visual->class == StaticGray) {
   1315 				/*
   1316 				 * StaticGray can be blended OK, otherwise
   1317 				 * user can disable with :nb
   1318 				 */
   1319 				;
   1320 			} else {
   1321 				scaling_blend = 0;
   1322 			}
   1323 		}
   1324 	}
   1325 
   1326 	if (cmap8to24 && cmap8to24_fb) {
   1327 		src_fb = cmap8to24_fb;
   1328 		if (scaling) {
   1329 			if (depth <= 8) {
   1330 				fac = 4;
   1331 			} else if (depth <= 16) {
   1332 				fac = 2;
   1333 			}
   1334 		}
   1335 	}
   1336 	dst_fb = rfb_fb;
   1337 	dst_bpl = rfb_bytes_per_line;
   1338 
   1339 	scale_rect(scale_fac_x, scale_fac_y, scaling_blend, scaling_interpolate, fac * Bpp,
   1340 	    src_fb, fac * main_bytes_per_line, dst_fb, dst_bpl, dpy_x, dpy_y,
   1341 	    scaled_x, scaled_y, X1, Y1, X2, Y2, mark);
   1342 }
   1343 
   1344 void rotate_coords(int x, int y, int *xo, int *yo, int dxi, int dyi) {
   1345 	int xi = x, yi = y;
   1346 	int Dx, Dy;
   1347 
   1348 	if (dxi >= 0) {
   1349 		Dx = dxi;
   1350 		Dy = dyi;
   1351 	} else if (scaling) {
   1352 		Dx = scaled_x;
   1353 		Dy = scaled_y;
   1354 	} else {
   1355 		Dx = dpy_x;
   1356 		Dy = dpy_y;
   1357 	}
   1358 
   1359 	/* ncache?? */
   1360 
   1361 	if (rotating == ROTATE_NONE) {
   1362 		*xo = xi;
   1363 		*yo = yi;
   1364 	} else if (rotating == ROTATE_X) {
   1365 		*xo = Dx - xi - 1;
   1366 		*yo = yi;
   1367 	} else if (rotating == ROTATE_Y) {
   1368 		*xo = xi;
   1369 		*yo = Dy - yi - 1;
   1370 	} else if (rotating == ROTATE_XY) {
   1371 		*xo = Dx - xi - 1;
   1372 		*yo = Dy - yi - 1;
   1373 	} else if (rotating == ROTATE_90) {
   1374 		*xo = Dy - yi - 1;
   1375 		*yo = xi;
   1376 	} else if (rotating == ROTATE_90X) {
   1377 		*xo = yi;
   1378 		*yo = xi;
   1379 	} else if (rotating == ROTATE_90Y) {
   1380 		*xo = Dy - yi - 1;
   1381 		*yo = Dx - xi - 1;
   1382 	} else if (rotating == ROTATE_270) {
   1383 		*xo = yi;
   1384 		*yo = Dx - xi - 1;
   1385 	}
   1386 }
   1387 
   1388 void rotate_coords_inverse(int x, int y, int *xo, int *yo, int dxi, int dyi) {
   1389 	int xi = x, yi = y;
   1390 
   1391 	int Dx, Dy;
   1392 
   1393 	if (dxi >= 0) {
   1394 		Dx = dxi;
   1395 		Dy = dyi;
   1396 	} else if (scaling) {
   1397 		Dx = scaled_x;
   1398 		Dy = scaled_y;
   1399 	} else {
   1400 		Dx = dpy_x;
   1401 		Dy = dpy_y;
   1402 	}
   1403 	if (! rotating_same) {
   1404 		int t = Dx;
   1405 		Dx = Dy;
   1406 		Dy = t;
   1407 	}
   1408 
   1409 	if (rotating == ROTATE_NONE) {
   1410 		*xo = xi;
   1411 		*yo = yi;
   1412 	} else if (rotating == ROTATE_X) {
   1413 		*xo = Dx - xi - 1;
   1414 		*yo = yi;
   1415 	} else if (rotating == ROTATE_Y) {
   1416 		*xo = xi;
   1417 		*yo = Dy - yi - 1;
   1418 	} else if (rotating == ROTATE_XY) {
   1419 		*xo = Dx - xi - 1;
   1420 		*yo = Dy - yi - 1;
   1421 	} else if (rotating == ROTATE_90) {
   1422 		*xo = yi;
   1423 		*yo = Dx - xi - 1;
   1424 	} else if (rotating == ROTATE_90X) {
   1425 		*xo = yi;
   1426 		*yo = xi;
   1427 	} else if (rotating == ROTATE_90Y) {
   1428 		*xo = Dy - yi - 1;
   1429 		*yo = Dx - xi - 1;
   1430 	} else if (rotating == ROTATE_270) {
   1431 		*xo = Dy - yi - 1;
   1432 		*yo = xi;
   1433 	}
   1434 }
   1435 
   1436 	/* unroll the Bpp loop to be used in each case: */
   1437 #define ROT_COPY \
   1438 	src = src_0 + fbl*y  + Bpp*x;  \
   1439 	dst = dst_0 + rbl*yn + Bpp*xn; \
   1440 	if (Bpp == 1) { \
   1441 		*(dst) = *(src);	 \
   1442 	} else if (Bpp == 2) { \
   1443 		*(dst+0) = *(src+0);	 \
   1444 		*(dst+1) = *(src+1);	 \
   1445 	} else if (Bpp == 3) { \
   1446 		*(dst+0) = *(src+0);	 \
   1447 		*(dst+1) = *(src+1);	 \
   1448 		*(dst+2) = *(src+2);	 \
   1449 	} else if (Bpp == 4) { \
   1450 		*(dst+0) = *(src+0);	 \
   1451 		*(dst+1) = *(src+1);	 \
   1452 		*(dst+2) = *(src+2);	 \
   1453 		*(dst+3) = *(src+3);	 \
   1454 	}
   1455 
   1456 void rotate_fb(int x1, int y1, int x2, int y2) {
   1457 	int x, y, xn, yn, r_x1, r_y1, r_x2, r_y2, Bpp = bpp/8;
   1458 	int fbl = rfb_bytes_per_line;
   1459 	int rbl = rot_bytes_per_line;
   1460 	int Dx, Dy;
   1461 	char *src, *dst;
   1462 	char *src_0 = rfb_fb;
   1463 	char *dst_0 = rot_fb;
   1464 
   1465 	if (! rotating || ! rot_fb) {
   1466 		return;
   1467 	}
   1468 
   1469 	if (scaling) {
   1470 		Dx = scaled_x;
   1471 		Dy = scaled_y;
   1472 	} else {
   1473 		Dx = dpy_x;
   1474 		Dy = dpy_y;
   1475 	}
   1476 	rotate_coords(x1, y1, &r_x1, &r_y1, -1, -1);
   1477 	rotate_coords(x2, y2, &r_x2, &r_y2, -1, -1);
   1478 
   1479 	dst = rot_fb;
   1480 
   1481 	if (rotating == ROTATE_X) {
   1482 		for (y = y1; y < y2; y++)  {
   1483 			for (x = x1; x < x2; x++)  {
   1484 				xn = Dx - x - 1;
   1485 				yn = y;
   1486 				ROT_COPY
   1487 			}
   1488 		}
   1489 	} else if (rotating == ROTATE_Y) {
   1490 		for (y = y1; y < y2; y++)  {
   1491 			for (x = x1; x < x2; x++)  {
   1492 				xn = x;
   1493 				yn = Dy - y - 1;
   1494 				ROT_COPY
   1495 			}
   1496 		}
   1497 	} else if (rotating == ROTATE_XY) {
   1498 		for (y = y1; y < y2; y++)  {
   1499 			for (x = x1; x < x2; x++)  {
   1500 				xn = Dx - x - 1;
   1501 				yn = Dy - y - 1;
   1502 				ROT_COPY
   1503 			}
   1504 		}
   1505 	} else if (rotating == ROTATE_90) {
   1506 		for (y = y1; y < y2; y++)  {
   1507 			for (x = x1; x < x2; x++)  {
   1508 				xn = Dy - y - 1;
   1509 				yn = x;
   1510 				ROT_COPY
   1511 			}
   1512 		}
   1513 	} else if (rotating == ROTATE_90X) {
   1514 		for (y = y1; y < y2; y++)  {
   1515 			for (x = x1; x < x2; x++)  {
   1516 				xn = y;
   1517 				yn = x;
   1518 				ROT_COPY
   1519 			}
   1520 		}
   1521 	} else if (rotating == ROTATE_90Y) {
   1522 		for (y = y1; y < y2; y++)  {
   1523 			for (x = x1; x < x2; x++)  {
   1524 				xn = Dy - y - 1;
   1525 				yn = Dx - x - 1;
   1526 				ROT_COPY
   1527 			}
   1528 		}
   1529 	} else if (rotating == ROTATE_270) {
   1530 		for (y = y1; y < y2; y++)  {
   1531 			for (x = x1; x < x2; x++)  {
   1532 				xn = y;
   1533 				yn = Dx - x - 1;
   1534 				ROT_COPY
   1535 			}
   1536 		}
   1537 	}
   1538 }
   1539 
   1540 void rotate_curs(char *dst_0, char *src_0, int Dx, int Dy, int Bpp) {
   1541 	int x, y, xn, yn;
   1542 	char *src, *dst;
   1543 	int fbl, rbl;
   1544 
   1545 	if (! rotating) {
   1546 		return;
   1547 	}
   1548 
   1549 	fbl = Dx * Bpp;
   1550 	if (rotating_same) {
   1551 		rbl = Dx * Bpp;
   1552 	} else {
   1553 		rbl = Dy * Bpp;
   1554 	}
   1555 
   1556 	if (rotating == ROTATE_X) {
   1557 		for (y = 0; y < Dy; y++)  {
   1558 			for (x = 0; x < Dx; x++)  {
   1559 				xn = Dx - x - 1;
   1560 				yn = y;
   1561 				ROT_COPY
   1562 if (0) fprintf(stderr, "rcurs: %d %d  %d %d\n", x, y, xn, yn);
   1563 			}
   1564 		}
   1565 	} else if (rotating == ROTATE_Y) {
   1566 		for (y = 0; y < Dy; y++)  {
   1567 			for (x = 0; x < Dx; x++)  {
   1568 				xn = x;
   1569 				yn = Dy - y - 1;
   1570 				ROT_COPY
   1571 			}
   1572 		}
   1573 	} else if (rotating == ROTATE_XY) {
   1574 		for (y = 0; y < Dy; y++)  {
   1575 			for (x = 0; x < Dx; x++)  {
   1576 				xn = Dx - x - 1;
   1577 				yn = Dy - y - 1;
   1578 				ROT_COPY
   1579 			}
   1580 		}
   1581 	} else if (rotating == ROTATE_90) {
   1582 		for (y = 0; y < Dy; y++)  {
   1583 			for (x = 0; x < Dx; x++)  {
   1584 				xn = Dy - y - 1;
   1585 				yn = x;
   1586 				ROT_COPY
   1587 			}
   1588 		}
   1589 	} else if (rotating == ROTATE_90X) {
   1590 		for (y = 0; y < Dy; y++)  {
   1591 			for (x = 0; x < Dx; x++)  {
   1592 				xn = y;
   1593 				yn = x;
   1594 				ROT_COPY
   1595 			}
   1596 		}
   1597 	} else if (rotating == ROTATE_90Y) {
   1598 		for (y = 0; y < Dy; y++)  {
   1599 			for (x = 0; x < Dx; x++)  {
   1600 				xn = Dy - y - 1;
   1601 				yn = Dx - x - 1;
   1602 				ROT_COPY
   1603 			}
   1604 		}
   1605 	} else if (rotating == ROTATE_270) {
   1606 		for (y = 0; y < Dy; y++)  {
   1607 			for (x = 0; x < Dx; x++)  {
   1608 				xn = y;
   1609 				yn = Dx - x - 1;
   1610 				ROT_COPY
   1611 			}
   1612 		}
   1613 	}
   1614 }
   1615 
   1616 void mark_wrapper(int x1, int y1, int x2, int y2) {
   1617 	int t, r_x1 = x1, r_y1 = y1, r_x2 = x2, r_y2 = y2;
   1618 
   1619 	if (rotating) {
   1620 		/* well we hope rot_fb will always be the last one... */
   1621 		rotate_coords(x1, y1, &r_x1, &r_y1, -1, -1);
   1622 		rotate_coords(x2, y2, &r_x2, &r_y2, -1, -1);
   1623 		rotate_fb(x1, y1, x2, y2);
   1624 		if (r_x1 > r_x2) {
   1625 			t = r_x1;
   1626 			r_x1 = r_x2;
   1627 			r_x2 = t;
   1628 		}
   1629 		if (r_y1 > r_y2) {
   1630 			t = r_y1;
   1631 			r_y1 = r_y2;
   1632 			r_y2 = t;
   1633 		}
   1634 		/* painting errors  */
   1635 		r_x1--;
   1636 		r_x2++;
   1637 		r_y1--;
   1638 		r_y2++;
   1639 	}
   1640 	rfbMarkRectAsModified(screen, r_x1, r_y1, r_x2, r_y2);
   1641 }
   1642 
   1643 void mark_rect_as_modified(int x1, int y1, int x2, int y2, int force) {
   1644 
   1645 	if (damage_time != 0) {
   1646 		/*
   1647 		 * This is not XDAMAGE, rather a hack for testing
   1648 		 * where we allow the framebuffer to be corrupted for
   1649 		 * damage_delay seconds.
   1650 		 */
   1651 		int debug = 0;
   1652 		if (time(NULL) > damage_time + damage_delay) {
   1653 			if (! quiet) {
   1654 				rfbLog("damaging turned off.\n");
   1655 			}
   1656 			damage_time = 0;
   1657 			damage_delay = 0;
   1658 		} else {
   1659 			if (debug) {
   1660 				rfbLog("damaging viewer fb by not marking "
   1661 				    "rect: %d,%d,%d,%d\n", x1, y1, x2, y2);
   1662 			}
   1663 			return;
   1664 		}
   1665 	}
   1666 
   1667 
   1668 	if (rfb_fb == main_fb || force) {
   1669 		mark_wrapper(x1, y1, x2, y2);
   1670 		return;
   1671 	}
   1672 
   1673 	if (cmap8to24) {
   1674 		bpp8to24(x1, y1, x2, y2);
   1675 	}
   1676 
   1677 	if (scaling) {
   1678 		scale_and_mark_rect(x1, y1, x2, y2, 1);
   1679 	} else {
   1680 		mark_wrapper(x1, y1, x2, y2);
   1681 	}
   1682 }
   1683 
   1684 /*
   1685  * Notifies libvncserver of a changed hint rectangle.
   1686  */
   1687 static void mark_hint(hint_t hint) {
   1688 	int x = hint.x;
   1689 	int y = hint.y;
   1690 	int w = hint.w;
   1691 	int h = hint.h;
   1692 
   1693 	mark_rect_as_modified(x, y, x + w, y + h, 0);
   1694 }
   1695 
   1696 /*
   1697  * copy_tiles() gives a slight improvement over copy_tile() since
   1698  * adjacent runs of tiles are done all at once there is some savings
   1699  * due to contiguous memory access.  Not a great speedup, but in some
   1700  * cases it can be up to 2X.  Even more on a SunRay or ShadowFB where
   1701  * no graphics hardware is involved in the read.  Generally, graphics
   1702  * devices are optimized for write, not read, so we are limited by the
   1703  * read bandwidth, sometimes only 5 MB/sec on otherwise fast hardware.
   1704  */
   1705 static int *first_line = NULL, *last_line = NULL;
   1706 static unsigned short *left_diff = NULL, *right_diff = NULL;
   1707 
   1708 static int copy_tiles(int tx, int ty, int nt) {
   1709 	int x, y, line;
   1710 	int size_x, size_y, width1, width2;
   1711 	int off, len, n, dw, dx, t;
   1712 	int w1, w2, dx1, dx2;	/* tmps for normal and short tiles */
   1713 	int pixelsize = bpp/8;
   1714 	int first_min, last_max;
   1715 	int first_x = -1, last_x = -1;
   1716 	static int prev_ntiles_x = -1;
   1717 
   1718 	char *src, *dst, *s_src, *s_dst, *m_src, *m_dst;
   1719 	char *h_src, *h_dst;
   1720 	if (unixpw_in_progress) return 0;
   1721 
   1722 	if (ntiles_x != prev_ntiles_x && first_line != NULL) {
   1723 		free(first_line);	first_line = NULL;
   1724 		free(last_line);	last_line = NULL;
   1725 		free(left_diff);	left_diff = NULL;
   1726 		free(right_diff);	right_diff = NULL;
   1727 	}
   1728 
   1729 	if (first_line == NULL) {
   1730 		/* allocate arrays first time in. */
   1731 		int n = ntiles_x + 1;
   1732 		rfbLog("copy_tiles: allocating first_line at size %d\n", n);
   1733 		first_line = (int *) malloc((size_t) (n * sizeof(int)));
   1734 		last_line  = (int *) malloc((size_t) (n * sizeof(int)));
   1735 		left_diff  = (unsigned short *)
   1736 			malloc((size_t) (n * sizeof(unsigned short)));
   1737 		right_diff = (unsigned short *)
   1738 			malloc((size_t) (n * sizeof(unsigned short)));
   1739 	}
   1740 	prev_ntiles_x = ntiles_x;
   1741 
   1742 	x = tx * tile_x;
   1743 	y = ty * tile_y;
   1744 
   1745 	size_x = dpy_x - x;
   1746 	if ( size_x > tile_x * nt ) {
   1747 		size_x = tile_x * nt;
   1748 		width1 = tile_x;
   1749 		width2 = tile_x;
   1750 	} else {
   1751 		/* short tile */
   1752 		width1 = tile_x;	/* internal tile */
   1753 		width2 = size_x - (nt - 1) * tile_x;	/* right hand tile */
   1754 	}
   1755 
   1756 	size_y = dpy_y - y;
   1757 	if ( size_y > tile_y ) {
   1758 		size_y = tile_y;
   1759 	}
   1760 
   1761 	n = tx + ty * ntiles_x;		/* number of the first tile */
   1762 
   1763 	if (blackouts && tile_blackout[n].cover == 2) {
   1764 		/*
   1765 		 * If there are blackouts and this tile is completely covered
   1766 		 * no need to poll screen or do anything else..
   1767 		 * n.b. we are in single copy_tile mode: nt=1
   1768 		 */
   1769 		tile_has_diff[n] = 0;
   1770 		return(0);
   1771 	}
   1772 
   1773 	X_LOCK;
   1774 	XRANDR_SET_TRAP_RET(-1, "copy_tile-set");
   1775 	/* read in the whole tile run at once: */
   1776 	copy_image(tile_row[nt], x, y, size_x, size_y);
   1777 	XRANDR_CHK_TRAP_RET(-1, "copy_tile-chk");
   1778 
   1779 
   1780 	X_UNLOCK;
   1781 
   1782 	if (blackouts && tile_blackout[n].cover == 1) {
   1783 		/*
   1784 		 * If there are blackouts and this tile is partially covered
   1785 		 * we should re-black-out the portion.
   1786 		 * n.b. we are in single copy_tile mode: nt=1
   1787 		 */
   1788 		int x1, x2, y1, y2, b;
   1789 		int w, s, fill = 0;
   1790 
   1791 		for (b=0; b < tile_blackout[n].count; b++) {
   1792 			char *b_dst = tile_row[nt]->data;
   1793 
   1794 			x1 = tile_blackout[n].bo[b].x1 - x;
   1795 			y1 = tile_blackout[n].bo[b].y1 - y;
   1796 			x2 = tile_blackout[n].bo[b].x2 - x;
   1797 			y2 = tile_blackout[n].bo[b].y2 - y;
   1798 
   1799 			w = (x2 - x1) * pixelsize;
   1800 			s = x1 * pixelsize;
   1801 
   1802 			for (line = 0; line < size_y; line++) {
   1803 				if (y1 <= line && line < y2) {
   1804 					memset(b_dst + s, fill, (size_t) w);
   1805 				}
   1806 				b_dst += tile_row[nt]->bytes_per_line;
   1807 			}
   1808 		}
   1809 	}
   1810 
   1811 	src = tile_row[nt]->data;
   1812 	dst = main_fb + y * main_bytes_per_line + x * pixelsize;
   1813 
   1814 	s_src = src;
   1815 	s_dst = dst;
   1816 
   1817 	for (t=1; t <= nt; t++) {
   1818 		first_line[t] = -1;
   1819 	}
   1820 
   1821 	/* find the first line with difference: */
   1822 	w1 = width1 * pixelsize;
   1823 	w2 = width2 * pixelsize;
   1824 
   1825 	/* foreach line: */
   1826 	for (line = 0; line < size_y; line++) {
   1827 		/* foreach horizontal tile: */
   1828 		for (t=1; t <= nt; t++) {
   1829 			if (first_line[t] != -1) {
   1830 				continue;
   1831 			}
   1832 
   1833 			off = (t-1) * w1;
   1834 			if (t == nt) {
   1835 				len = w2;	/* possible short tile */
   1836 			} else {
   1837 				len = w1;
   1838 			}
   1839 
   1840 			if (memcmp(s_dst + off, s_src + off, len)) {
   1841 				first_line[t] = line;
   1842 			}
   1843 		}
   1844 		s_src += tile_row[nt]->bytes_per_line;
   1845 		s_dst += main_bytes_per_line;
   1846 	}
   1847 
   1848 	/* see if there were any differences for any tile: */
   1849 	first_min = -1;
   1850 	for (t=1; t <= nt; t++) {
   1851 		tile_tried[n+(t-1)] = 1;
   1852 		if (first_line[t] != -1) {
   1853 			if (first_min == -1 || first_line[t] < first_min) {
   1854 				first_min = first_line[t];
   1855 			}
   1856 		}
   1857 	}
   1858 	if (first_min == -1) {
   1859 		/* no tile has a difference, note this and get out: */
   1860 		for (t=1; t <= nt; t++) {
   1861 			tile_has_diff[n+(t-1)] = 0;
   1862 		}
   1863 		return(0);
   1864 	} else {
   1865 		/*
   1866 		 * at least one tile has a difference.  make sure info
   1867 		 * is recorded (e.g. sometimes we guess tiles and they
   1868 		 * came in with tile_has_diff 0)
   1869 		 */
   1870 		for (t=1; t <= nt; t++) {
   1871 			if (first_line[t] == -1) {
   1872 				tile_has_diff[n+(t-1)] = 0;
   1873 			} else {
   1874 				tile_has_diff[n+(t-1)] = 1;
   1875 			}
   1876 		}
   1877 	}
   1878 
   1879 	m_src = src + (tile_row[nt]->bytes_per_line * size_y);
   1880 	m_dst = dst + (main_bytes_per_line * size_y);
   1881 
   1882 	for (t=1; t <= nt; t++) {
   1883 		last_line[t] = first_line[t];
   1884 	}
   1885 
   1886 	/* find the last line with difference: */
   1887 	w1 = width1 * pixelsize;
   1888 	w2 = width2 * pixelsize;
   1889 
   1890 	/* foreach line: */
   1891 	for (line = size_y - 1; line > first_min; line--) {
   1892 
   1893 		m_src -= tile_row[nt]->bytes_per_line;
   1894 		m_dst -= main_bytes_per_line;
   1895 
   1896 		/* foreach tile: */
   1897 		for (t=1; t <= nt; t++) {
   1898 			if (first_line[t] == -1
   1899 			    || last_line[t] != first_line[t]) {
   1900 				/* tile has no changes or already done */
   1901 				continue;
   1902 			}
   1903 
   1904 			off = (t-1) * w1;
   1905 			if (t == nt) {
   1906 				len = w2;	/* possible short tile */
   1907 			} else {
   1908 				len = w1;
   1909 			}
   1910 			if (memcmp(m_dst + off, m_src + off, len)) {
   1911 				last_line[t] = line;
   1912 			}
   1913 		}
   1914 	}
   1915 
   1916 	/*
   1917 	 * determine the farthest down last changed line
   1918 	 * will be used below to limit our memcpy() to the framebuffer.
   1919 	 */
   1920 	last_max = -1;
   1921 	for (t=1; t <= nt; t++) {
   1922 		if (first_line[t] == -1) {
   1923 			continue;
   1924 		}
   1925 		if (last_max == -1 || last_line[t] > last_max) {
   1926 			last_max = last_line[t];
   1927 		}
   1928 	}
   1929 
   1930 	/* look for differences on left and right hand edges: */
   1931 	for (t=1; t <= nt; t++) {
   1932 		left_diff[t] = 0;
   1933 		right_diff[t] = 0;
   1934 	}
   1935 
   1936 	h_src = src;
   1937 	h_dst = dst;
   1938 
   1939 	w1 = width1 * pixelsize;
   1940 	w2 = width2 * pixelsize;
   1941 
   1942 	dx1 = (width1 - tile_fuzz) * pixelsize;
   1943 	dx2 = (width2 - tile_fuzz) * pixelsize;
   1944 	dw = tile_fuzz * pixelsize;
   1945 
   1946 	/* foreach line: */
   1947 	for (line = 0; line < size_y; line++) {
   1948 		/* foreach tile: */
   1949 		for (t=1; t <= nt; t++) {
   1950 			if (first_line[t] == -1) {
   1951 				/* tile has no changes at all */
   1952 				continue;
   1953 			}
   1954 
   1955 			off = (t-1) * w1;
   1956 			if (t == nt) {
   1957 				dx = dx2;	/* possible short tile */
   1958 				if (dx <= 0) {
   1959 					break;
   1960 				}
   1961 			} else {
   1962 				dx = dx1;
   1963 			}
   1964 
   1965 			if (! left_diff[t] && memcmp(h_dst + off,
   1966 			    h_src + off, dw)) {
   1967 				left_diff[t] = 1;
   1968 			}
   1969 			if (! right_diff[t] && memcmp(h_dst + off + dx,
   1970 			    h_src + off + dx, dw) ) {
   1971 				right_diff[t] = 1;
   1972 			}
   1973 		}
   1974 		h_src += tile_row[nt]->bytes_per_line;
   1975 		h_dst += main_bytes_per_line;
   1976 	}
   1977 
   1978 	/* now finally copy the difference to the rfb framebuffer: */
   1979 	s_src = src + tile_row[nt]->bytes_per_line * first_min;
   1980 	s_dst = dst + main_bytes_per_line * first_min;
   1981 
   1982 	for (line = first_min; line <= last_max; line++) {
   1983 		/* for I/O speed we do not do this tile by tile */
   1984 		memcpy(s_dst, s_src, size_x * pixelsize);
   1985 		if (nt == 1) {
   1986 			/*
   1987 			 * optimization for tall skinny lines, e.g. wm
   1988 			 * frame. try to find first_x and last_x to limit
   1989 			 * the size of the hint.  could help for a slow
   1990 			 * link.  Unfortunately we spent a lot of time
   1991 			 * reading in the many tiles.
   1992 			 *
   1993 			 * BTW, we like to think the above memcpy leaves
   1994 			 * the data we use below in the cache... (but
   1995 			 * it could be two 128 byte segments at 32bpp)
   1996 			 * so this inner loop is not as bad as it seems.
   1997 			 */
   1998 			int k, kx;
   1999 			kx = pixelsize;
   2000 			for (k=0; k<size_x; k++) {
   2001 				if (memcmp(s_dst + k*kx, s_src + k*kx, kx))  {
   2002 					if (first_x == -1 || k < first_x) {
   2003 						first_x = k;
   2004 					}
   2005 					if (last_x == -1 || k > last_x) {
   2006 						last_x = k;
   2007 					}
   2008 				}
   2009 			}
   2010 		}
   2011 		s_src += tile_row[nt]->bytes_per_line;
   2012 		s_dst += main_bytes_per_line;
   2013 	}
   2014 
   2015 	/* record all the info in the region array for this tile: */
   2016 	for (t=1; t <= nt; t++) {
   2017 		int s = t - 1;
   2018 
   2019 		if (first_line[t] == -1) {
   2020 			/* tile unchanged */
   2021 			continue;
   2022 		}
   2023 		tile_region[n+s].first_line = first_line[t];
   2024 		tile_region[n+s].last_line  = last_line[t];
   2025 
   2026 		tile_region[n+s].first_x = first_x;
   2027 		tile_region[n+s].last_x  = last_x;
   2028 
   2029 		tile_region[n+s].top_diff = 0;
   2030 		tile_region[n+s].bot_diff = 0;
   2031 		if ( first_line[t] < tile_fuzz ) {
   2032 			tile_region[n+s].top_diff = 1;
   2033 		}
   2034 		if ( last_line[t] > (size_y - 1) - tile_fuzz ) {
   2035 			tile_region[n+s].bot_diff = 1;
   2036 		}
   2037 
   2038 		tile_region[n+s].left_diff  = left_diff[t];
   2039 		tile_region[n+s].right_diff = right_diff[t];
   2040 
   2041 		tile_copied[n+s] = 1;
   2042 	}
   2043 
   2044 	return(1);
   2045 }
   2046 
   2047 /*
   2048  * The copy_tile() call in the loop below copies the changed tile into
   2049  * the rfb framebuffer.  Note that copy_tile() sets the tile_region
   2050  * struct to have info about the y-range of the changed region and also
   2051  * whether the tile edges contain diffs (within distance tile_fuzz).
   2052  *
   2053  * We use this tile_region info to try to guess if the downward and right
   2054  * tiles will have diffs.  These tiles will be checked later in the loop
   2055  * (since y+1 > y and x+1 > x).
   2056  *
   2057  * See copy_tiles_backward_pass() for analogous checking upward and
   2058  * left tiles.
   2059  */
   2060 static int copy_all_tiles(void) {
   2061 	int x, y, n, m;
   2062 	int diffs = 0, ct;
   2063 
   2064 	if (unixpw_in_progress) return 0;
   2065 
   2066 	for (y=0; y < ntiles_y; y++) {
   2067 		for (x=0; x < ntiles_x; x++) {
   2068 			n = x + y * ntiles_x;
   2069 
   2070 			if (tile_has_diff[n]) {
   2071 				ct = copy_tiles(x, y, 1);
   2072 				if (ct < 0) return ct;	/* fatal */
   2073 			}
   2074 			if (! tile_has_diff[n]) {
   2075 				/*
   2076 				 * n.b. copy_tiles() may have detected
   2077 				 * no change and reset tile_has_diff to 0.
   2078 				 */
   2079 				continue;
   2080 			}
   2081 			diffs++;
   2082 
   2083 			/* neighboring tile downward: */
   2084 			if ( (y+1) < ntiles_y && tile_region[n].bot_diff) {
   2085 				m = x + (y+1) * ntiles_x;
   2086 				if (! tile_has_diff[m]) {
   2087 					tile_has_diff[m] = 2;
   2088 				}
   2089 			}
   2090 			/* neighboring tile to right: */
   2091 			if ( (x+1) < ntiles_x && tile_region[n].right_diff) {
   2092 				m = (x+1) + y * ntiles_x;
   2093 				if (! tile_has_diff[m]) {
   2094 					tile_has_diff[m] = 2;
   2095 				}
   2096 			}
   2097 		}
   2098 	}
   2099 	return diffs;
   2100 }
   2101 
   2102 /*
   2103  * Routine analogous to copy_all_tiles() above, but for horizontal runs
   2104  * of adjacent changed tiles.
   2105  */
   2106 static int copy_all_tile_runs(void) {
   2107 	int x, y, n, m, i;
   2108 	int diffs = 0, ct;
   2109 	int in_run = 0, run = 0;
   2110 	int ntave = 0, ntcnt = 0;
   2111 
   2112 	if (unixpw_in_progress) return 0;
   2113 
   2114 	for (y=0; y < ntiles_y; y++) {
   2115 		for (x=0; x < ntiles_x + 1; x++) {
   2116 			n = x + y * ntiles_x;
   2117 
   2118 			if (x != ntiles_x && tile_has_diff[n]) {
   2119 				in_run = 1;
   2120 				run++;
   2121 			} else {
   2122 				if (! in_run) {
   2123 					in_run = 0;
   2124 					run = 0;
   2125 					continue;
   2126 				}
   2127 				ct = copy_tiles(x - run, y, run);
   2128 				if (ct < 0) return ct;	/* fatal */
   2129 
   2130 				ntcnt++;
   2131 				ntave += run;
   2132 				diffs += run;
   2133 
   2134 				/* neighboring tile downward: */
   2135 				for (i=1; i <= run; i++) {
   2136 					if ((y+1) < ntiles_y
   2137 					    && tile_region[n-i].bot_diff) {
   2138 						m = (x-i) + (y+1) * ntiles_x;
   2139 						if (! tile_has_diff[m]) {
   2140 							tile_has_diff[m] = 2;
   2141 						}
   2142 					}
   2143 				}
   2144 
   2145 				/* neighboring tile to right: */
   2146 				if (((x-1)+1) < ntiles_x
   2147 				    && tile_region[n-1].right_diff) {
   2148 					m = ((x-1)+1) + y * ntiles_x;
   2149 					if (! tile_has_diff[m]) {
   2150 						tile_has_diff[m] = 2;
   2151 					}
   2152 
   2153 					/* note that this starts a new run */
   2154 					in_run = 1;
   2155 					run = 1;
   2156 				} else {
   2157 					in_run = 0;
   2158 					run = 0;
   2159 				}
   2160 			}
   2161 		}
   2162 		/*
   2163 		 * Could some activity go here, to emulate threaded
   2164 		 * behavior by servicing some libvncserver tasks?
   2165 		 */
   2166 	}
   2167 	return diffs;
   2168 }
   2169 
   2170 /*
   2171  * Here starts a bunch of heuristics to guess/detect changed tiles.
   2172  * They are:
   2173  *   copy_tiles_backward_pass, fill_tile_gaps/gap_try, grow_islands/island_try
   2174  */
   2175 
   2176 /*
   2177  * Try to predict whether the upward and/or leftward tile has been modified.
   2178  * copy_all_tiles() has already done downward and rightward tiles.
   2179  */
   2180 static int copy_tiles_backward_pass(void) {
   2181 	int x, y, n, m;
   2182 	int diffs = 0, ct;
   2183 
   2184 	if (unixpw_in_progress) return 0;
   2185 
   2186 	for (y = ntiles_y - 1; y >= 0; y--) {
   2187 	    for (x = ntiles_x - 1; x >= 0; x--) {
   2188 		n = x + y * ntiles_x;		/* number of this tile */
   2189 
   2190 		if (! tile_has_diff[n]) {
   2191 			continue;
   2192 		}
   2193 
   2194 		m = x + (y-1) * ntiles_x;	/* neighboring tile upward */
   2195 
   2196 		if (y >= 1 && ! tile_has_diff[m] && tile_region[n].top_diff) {
   2197 			if (! tile_tried[m]) {
   2198 				tile_has_diff[m] = 2;
   2199 				ct = copy_tiles(x, y-1, 1);
   2200 				if (ct < 0) return ct;	/* fatal */
   2201 			}
   2202 		}
   2203 
   2204 		m = (x-1) + y * ntiles_x;	/* neighboring tile to left */
   2205 
   2206 		if (x >= 1 && ! tile_has_diff[m] && tile_region[n].left_diff) {
   2207 			if (! tile_tried[m]) {
   2208 				tile_has_diff[m] = 2;
   2209 				ct = copy_tiles(x-1, y, 1);
   2210 				if (ct < 0) return ct;	/* fatal */
   2211 			}
   2212 		}
   2213 	    }
   2214 	}
   2215 	for (n=0; n < ntiles; n++) {
   2216 		if (tile_has_diff[n]) {
   2217 			diffs++;
   2218 		}
   2219 	}
   2220 	return diffs;
   2221 }
   2222 
   2223 static int copy_tiles_additional_pass(void) {
   2224 	int x, y, n;
   2225 	int diffs = 0, ct;
   2226 
   2227 	if (unixpw_in_progress) return 0;
   2228 
   2229 	for (y=0; y < ntiles_y; y++) {
   2230 		for (x=0; x < ntiles_x; x++) {
   2231 			n = x + y * ntiles_x;		/* number of this tile */
   2232 
   2233 			if (! tile_has_diff[n]) {
   2234 				continue;
   2235 			}
   2236 			if (tile_copied[n]) {
   2237 				continue;
   2238 			}
   2239 
   2240 			ct = copy_tiles(x, y, 1);
   2241 			if (ct < 0) return ct;	/* fatal */
   2242 		}
   2243 	}
   2244 	for (n=0; n < ntiles; n++) {
   2245 		if (tile_has_diff[n]) {
   2246 			diffs++;
   2247 		}
   2248 	}
   2249 	return diffs;
   2250 }
   2251 
   2252 static int gap_try(int x, int y, int *run, int *saw, int along_x) {
   2253 	int n, m, i, xt, yt, ct;
   2254 
   2255 	n = x + y * ntiles_x;
   2256 
   2257 	if (! tile_has_diff[n]) {
   2258 		if (*saw) {
   2259 			(*run)++;	/* extend the gap run. */
   2260 		}
   2261 		return 0;
   2262 	}
   2263 	if (! *saw || *run == 0 || *run > gaps_fill) {
   2264 		*run = 0;		/* unacceptable run. */
   2265 		*saw = 1;
   2266 		return 0;
   2267 	}
   2268 
   2269 	for (i=1; i <= *run; i++) {	/* iterate thru the run. */
   2270 		if (along_x) {
   2271 			xt = x - i;
   2272 			yt = y;
   2273 		} else {
   2274 			xt = x;
   2275 			yt = y - i;
   2276 		}
   2277 
   2278 		m = xt + yt * ntiles_x;
   2279 		if (tile_tried[m]) {	/* do not repeat tiles */
   2280 			continue;
   2281 		}
   2282 
   2283 		ct = copy_tiles(xt, yt, 1);
   2284 		if (ct < 0) return ct;	/* fatal */
   2285 	}
   2286 	*run = 0;
   2287 	*saw = 1;
   2288 	return 1;
   2289 }
   2290 
   2291 /*
   2292  * Look for small gaps of unchanged tiles that may actually contain changes.
   2293  * E.g. when paging up and down in a web broswer or terminal there can
   2294  * be a distracting delayed filling in of such gaps.  gaps_fill is the
   2295  * tweak parameter that sets the width of the gaps that are checked.
   2296  *
   2297  * BTW, grow_islands() is actually pretty successful at doing this too...
   2298  */
   2299 static int fill_tile_gaps(void) {
   2300 	int x, y, run, saw;
   2301 	int n, diffs = 0, ct;
   2302 
   2303 	/* horizontal: */
   2304 	for (y=0; y < ntiles_y; y++) {
   2305 		run = 0;
   2306 		saw = 0;
   2307 		for (x=0; x < ntiles_x; x++) {
   2308 			ct = gap_try(x, y, &run, &saw, 1);
   2309 			if (ct < 0) return ct;	/* fatal */
   2310 		}
   2311 	}
   2312 
   2313 	/* vertical: */
   2314 	for (x=0; x < ntiles_x; x++) {
   2315 		run = 0;
   2316 		saw = 0;
   2317 		for (y=0; y < ntiles_y; y++) {
   2318 			ct = gap_try(x, y, &run, &saw, 0);
   2319 			if (ct < 0) return ct;	/* fatal */
   2320 		}
   2321 	}
   2322 
   2323 	for (n=0; n < ntiles; n++) {
   2324 		if (tile_has_diff[n]) {
   2325 			diffs++;
   2326 		}
   2327 	}
   2328 	return diffs;
   2329 }
   2330 
   2331 static int island_try(int x, int y, int u, int v, int *run) {
   2332 	int n, m, ct;
   2333 
   2334 	n = x + y * ntiles_x;
   2335 	m = u + v * ntiles_x;
   2336 
   2337 	if (tile_has_diff[n]) {
   2338 		(*run)++;
   2339 	} else {
   2340 		*run = 0;
   2341 	}
   2342 
   2343 	if (tile_has_diff[n] && ! tile_has_diff[m]) {
   2344 		/* found a discontinuity */
   2345 
   2346 		if (tile_tried[m]) {
   2347 			return 0;
   2348 		} else if (*run < grow_fill) {
   2349 			return 0;
   2350 		}
   2351 
   2352 		ct = copy_tiles(u, v, 1);
   2353 		if (ct < 0) return ct;	/* fatal */
   2354 	}
   2355 	return 1;
   2356 }
   2357 
   2358 /*
   2359  * Scan looking for discontinuities in tile_has_diff[].  Try to extend
   2360  * the boundary of the discontinuity (i.e. make the island larger).
   2361  * Vertical scans are skipped since they do not seem to yield much...
   2362  */
   2363 static int grow_islands(void) {
   2364 	int x, y, n, run;
   2365 	int diffs = 0, ct;
   2366 
   2367 	/*
   2368 	 * n.b. the way we scan here should keep an extension going,
   2369 	 * and so also fill in gaps effectively...
   2370 	 */
   2371 
   2372 	/* left to right: */
   2373 	for (y=0; y < ntiles_y; y++) {
   2374 		run = 0;
   2375 		for (x=0; x <= ntiles_x - 2; x++) {
   2376 			ct = island_try(x, y, x+1, y, &run);
   2377 			if (ct < 0) return ct;	/* fatal */
   2378 		}
   2379 	}
   2380 	/* right to left: */
   2381 	for (y=0; y < ntiles_y; y++) {
   2382 		run = 0;
   2383 		for (x = ntiles_x - 1; x >= 1; x--) {
   2384 			ct = island_try(x, y, x-1, y, &run);
   2385 			if (ct < 0) return ct;	/* fatal */
   2386 		}
   2387 	}
   2388 	for (n=0; n < ntiles; n++) {
   2389 		if (tile_has_diff[n]) {
   2390 			diffs++;
   2391 		}
   2392 	}
   2393 	return diffs;
   2394 }
   2395 
   2396 /*
   2397  * Fill the framebuffer with zeros for each blackout region
   2398  */
   2399 static void blackout_regions(void) {
   2400 	int i;
   2401 	for (i=0; i < blackouts; i++) {
   2402 		zero_fb(blackr[i].x1, blackr[i].y1, blackr[i].x2, blackr[i].y2);
   2403 	}
   2404 }
   2405 
   2406 /*
   2407  * copy the whole X screen to the rfb framebuffer.  For a large enough
   2408  * number of changed tiles, this is faster than tiles scheme at retrieving
   2409  * the info from the X server.  Bandwidth to client and compression time
   2410  * are other issues...  use -fs 1.0 to disable.
   2411  */
   2412 int copy_screen(void) {
   2413 	char *fbp;
   2414 	int i, y, block_size;
   2415 
   2416 	if (! fs_factor) {
   2417 		return 0;
   2418 	}
   2419 	if (debug_tiles) fprintf(stderr, "copy_screen\n");
   2420 
   2421 	if (unixpw_in_progress) return 0;
   2422 
   2423 
   2424 	if (! main_fb) {
   2425 		return 0;
   2426 	}
   2427 
   2428 	block_size = ((dpy_y/fs_factor) * main_bytes_per_line);
   2429 
   2430 	fbp = main_fb;
   2431 	y = 0;
   2432 
   2433 	X_LOCK;
   2434 
   2435 	/* screen may be too big for 1 shm area, so broken into fs_factor */
   2436 	for (i=0; i < fs_factor; i++) {
   2437 		XRANDR_SET_TRAP_RET(-1, "copy_screen-set");
   2438 		copy_image(fullscreen, 0, y, 0, 0);
   2439 		XRANDR_CHK_TRAP_RET(-1, "copy_screen-chk");
   2440 
   2441 		memcpy(fbp, fullscreen->data, (size_t) block_size);
   2442 
   2443 		y += dpy_y / fs_factor;
   2444 		fbp += block_size;
   2445 	}
   2446 
   2447 	X_UNLOCK;
   2448 
   2449 	if (blackouts) {
   2450 		blackout_regions();
   2451 	}
   2452 
   2453 	mark_rect_as_modified(0, 0, dpy_x, dpy_y, 0);
   2454 	return 0;
   2455 }
   2456 
   2457 #include <rfb/default8x16.h>
   2458 
   2459 /*
   2460  * Color values from the vcsadump program.
   2461  * void dumpcss(FILE *fp, char *attribs_used)
   2462  * char *colormap[] = {
   2463  *    "#000000", "#0000AA", "#00AA00", "#00AAAA", "#AA0000", "#AA00AA", "#AA5500", "#AAAAAA",
   2464  *    "#555555", "#5555AA", "#55FF55", "#55FFFF", "#FF5555", "#FF55FF", "#FFFF00", "#FFFFFF" };
   2465  */
   2466 
   2467 static unsigned char console_cmap[16*3]={
   2468 /*  0 */	0x00, 0x00, 0x00,
   2469 /*  1 */	0x00, 0x00, 0xAA,
   2470 /*  2 */	0x00, 0xAA, 0x00,
   2471 /*  3 */	0x00, 0xAA, 0xAA,
   2472 /*  4 */	0xAA, 0x00, 0x00,
   2473 /*  5 */	0xAA, 0x00, 0xAA,
   2474 /*  6 */	0xAA, 0x55, 0x00,
   2475 /*  7 */	0xAA, 0xAA, 0xAA,
   2476 /*  8 */	0x55, 0x55, 0x55,
   2477 /*  9 */	0x55, 0x55, 0xAA,
   2478 /* 10 */	0x55, 0xFF, 0x55,
   2479 /* 11 */	0x55, 0xFF, 0xFF,
   2480 /* 12 */	0xFF, 0x55, 0x55,
   2481 /* 13 */	0xFF, 0x55, 0xFF,
   2482 /* 14 */	0xFF, 0xFF, 0x00,
   2483 /* 15 */	0xFF, 0xFF, 0xFF
   2484 };
   2485 
   2486 static void snap_vcsa_rawfb(void) {
   2487 	int n;
   2488 	char *dst;
   2489 	char buf[32];
   2490 	int i, len, del;
   2491 	unsigned char rows, cols, xpos, ypos;
   2492 	static int prev_rows = -1, prev_cols = -1;
   2493 	static unsigned char prev_xpos = -1, prev_ypos = -1;
   2494 	static char *vcsabuf  = NULL;
   2495 	static char *vcsabuf0 = NULL;
   2496 	static unsigned int color_tab[16];
   2497 	static int Cw = 8, Ch = 16;
   2498 	static int db = -1, first = 1;
   2499 	int created = 0;
   2500 	rfbScreenInfo s;
   2501 	rfbScreenInfoPtr fake_screen = &s;
   2502 	int Bpp = raw_fb_native_bpp / 8;
   2503 
   2504 	if (db < 0) {
   2505 		if (getenv("X11VNC_DEBUG_VCSA")) {
   2506 			db = atoi(getenv("X11VNC_DEBUG_VCSA"));
   2507 		} else {
   2508 			db = 0;
   2509 		}
   2510 	}
   2511 
   2512 	if (first) {
   2513 		unsigned int rm = raw_fb_native_red_mask;
   2514 		unsigned int gm = raw_fb_native_green_mask;
   2515 		unsigned int bm = raw_fb_native_blue_mask;
   2516 		unsigned int rs = raw_fb_native_red_shift;
   2517 		unsigned int gs = raw_fb_native_green_shift;
   2518 		unsigned int bs = raw_fb_native_blue_shift;
   2519 		unsigned int rx = raw_fb_native_red_max;
   2520 		unsigned int gx = raw_fb_native_green_max;
   2521 		unsigned int bx = raw_fb_native_blue_max;
   2522 
   2523 		for (i=0; i < 16; i++) {
   2524 			int r = console_cmap[3*i+0];
   2525 			int g = console_cmap[3*i+1];
   2526 			int b = console_cmap[3*i+2];
   2527 			r = rx * r / 255;
   2528 			g = gx * g / 255;
   2529 			b = bx * b / 255;
   2530 			color_tab[i] = (r << rs) | (g << gs) | (b << bs);
   2531 			if (db) fprintf(stderr, "cmap[%02d] 0x%08x  %04d %04d %04d\n", i, color_tab[i], r, g, b);
   2532 			if (i != 0 && getenv("RAWFB_VCSA_BW")) {
   2533 				color_tab[i] = rm | gm | bm;
   2534 			}
   2535 		}
   2536 	}
   2537 	first = 0;
   2538 
   2539 	lseek(raw_fb_fd, 0, SEEK_SET);
   2540 	len = 4;
   2541 	del = 0;
   2542 	memset(buf, 0, sizeof(buf));
   2543 	while (len > 0) {
   2544 		n = read(raw_fb_fd, buf + del, len);
   2545 		if (n > 0) {
   2546 			del += n;
   2547 			len -= n;
   2548 		} else if (n == 0) {
   2549 			break;
   2550 		} else if (errno != EINTR && errno != EAGAIN) {
   2551 			break;
   2552 		}
   2553 	}
   2554 
   2555 	rows = (unsigned char) buf[0];
   2556 	cols = (unsigned char) buf[1];
   2557 	xpos = (unsigned char) buf[2];
   2558 	ypos = (unsigned char) buf[3];
   2559 
   2560 	if (db) fprintf(stderr, "rows=%d cols=%d xpos=%d ypos=%d Bpp=%d\n", rows, cols, xpos, ypos, Bpp);
   2561 	if (rows == 0 || cols == 0) {
   2562 		usleep(100 * 1000);
   2563 		return;
   2564 	}
   2565 
   2566 	if (vcsabuf == NULL || prev_rows != rows || prev_cols != cols) {
   2567 		if (vcsabuf) {
   2568 			free(vcsabuf);
   2569 			free(vcsabuf0);
   2570 		}
   2571 		vcsabuf  = (char *) calloc(2 * rows * cols, 1);
   2572 		vcsabuf0 = (char *) calloc(2 * rows * cols, 1);
   2573 		created = 1;
   2574 
   2575 		if (prev_rows != -1 && prev_cols != -1) {
   2576 			do_new_fb(1);
   2577 		}
   2578 
   2579 		prev_rows = rows;
   2580 		prev_cols = cols;
   2581 	}
   2582 
   2583 	if (!rfbEndianTest) {
   2584 		unsigned char tc = rows;
   2585 		rows = cols;
   2586 		cols = tc;
   2587 
   2588 		tc = xpos;
   2589 		xpos = ypos;
   2590 		ypos = tc;
   2591 	}
   2592 
   2593 	len = 2 * rows * cols;
   2594 	del = 0;
   2595 	memset(vcsabuf, 0, len);
   2596 	while (len > 0) {
   2597 		n = read(raw_fb_fd, vcsabuf + del, len);
   2598 		if (n > 0) {
   2599 			del += n;
   2600 			len -= n;
   2601 		} else if (n == 0) {
   2602 			break;
   2603 		} else if (errno != EINTR && errno != EAGAIN) {
   2604 			break;
   2605 		}
   2606 	}
   2607 
   2608 	fake_screen->frameBuffer = snap->data;
   2609 	fake_screen->paddedWidthInBytes = snap->bytes_per_line;
   2610 	fake_screen->serverFormat.bitsPerPixel = raw_fb_native_bpp;
   2611 	fake_screen->width = snap->width;
   2612 	fake_screen->height = snap->height;
   2613 
   2614 	for (i=0; i < rows * cols; i++) {
   2615 		int ix, iy, x, y, w, h;
   2616 		unsigned char chr = 0;
   2617 		unsigned char attr;
   2618 		unsigned int fore, back;
   2619 		unsigned short *usp;
   2620 		unsigned int *uip;
   2621 		chr  = (unsigned char) vcsabuf[2*i];
   2622 		attr = vcsabuf[2*i+1];
   2623 
   2624 		iy = i / cols;
   2625 		ix = i - iy * cols;
   2626 
   2627 		if (ix == prev_xpos && iy == prev_ypos) {
   2628 			;
   2629 		} else if (ix == xpos && iy == ypos) {
   2630 			;
   2631 		} else if (!created && chr == vcsabuf0[2*i] && attr == vcsabuf0[2*i+1]) {
   2632 			continue;
   2633 		}
   2634 
   2635 		if (!rfbEndianTest) {
   2636 			unsigned char tc = chr;
   2637 			chr = attr;
   2638 			attr = tc;
   2639 		}
   2640 
   2641 		y = iy * Ch;
   2642 		x = ix * Cw;
   2643 		dst = snap->data + y * snap->bytes_per_line + x * Bpp;
   2644 
   2645 		fore = color_tab[attr & 0xf];
   2646 		back = color_tab[(attr >> 4) & 0x7];
   2647 
   2648 		if (ix == xpos && iy == ypos) {
   2649 			unsigned int ti = fore;
   2650 			fore = back;
   2651 			back = ti;
   2652 		}
   2653 
   2654 		for (h = 0; h < Ch; h++) {
   2655 			if (Bpp == 1) {
   2656 				memset(dst, back, Cw);
   2657 			} else if (Bpp == 2) {
   2658 				for (w = 0; w < Cw; w++) {
   2659 					usp = (unsigned short *) (dst + w*Bpp);
   2660 					*usp = (unsigned short) back;
   2661 				}
   2662 			} else if (Bpp == 4) {
   2663 				for (w = 0; w < Cw; w++) {
   2664 					uip = (unsigned int *) (dst + w*Bpp);
   2665 					*uip = (unsigned int) back;
   2666 				}
   2667 			}
   2668 			dst += snap->bytes_per_line;
   2669 		}
   2670 		rfbDrawChar(fake_screen, &default8x16Font, x, y + Ch, chr, fore);
   2671 	}
   2672 	memcpy(vcsabuf0, vcsabuf, 2 * rows * cols);
   2673 	prev_xpos = xpos;
   2674 	prev_ypos = ypos;
   2675 }
   2676 
   2677 static void snap_all_rawfb(void) {
   2678 	int pixelsize = bpp/8;
   2679 	int n, sz;
   2680 	char *dst;
   2681 	static char *unclipped_dst = NULL;
   2682 	static int unclipped_len = 0;
   2683 
   2684 	dst = snap->data;
   2685 
   2686 	if (xform24to32 && bpp == 32) {
   2687 		pixelsize = 3;
   2688 	}
   2689 	sz = dpy_y * snap->bytes_per_line;
   2690 
   2691 	if (wdpy_x > dpy_x || wdpy_y > dpy_y) {
   2692 		sz = wdpy_x * wdpy_y * pixelsize;
   2693 		if (sz > unclipped_len || unclipped_dst == NULL) {
   2694 			if (unclipped_dst) {
   2695 				free(unclipped_dst);
   2696 			}
   2697 			unclipped_dst = (char *) malloc(sz+4);
   2698 			unclipped_len = sz;
   2699 		}
   2700 		dst = unclipped_dst;
   2701 	}
   2702 
   2703 	if (! raw_fb_seek) {
   2704 		memcpy(dst, raw_fb_addr + raw_fb_offset, sz);
   2705 
   2706 	} else {
   2707 		int len = sz, del = 0;
   2708 		off_t off = (off_t) raw_fb_offset;
   2709 
   2710 		lseek(raw_fb_fd, off, SEEK_SET);
   2711 		while (len > 0) {
   2712 			n = read(raw_fb_fd, dst + del, len);
   2713 			if (n > 0) {
   2714 				del += n;
   2715 				len -= n;
   2716 			} else if (n == 0) {
   2717 				break;
   2718 			} else if (errno != EINTR && errno != EAGAIN) {
   2719 				break;
   2720 			}
   2721 		}
   2722 	}
   2723 
   2724 	if (dst == unclipped_dst) {
   2725 		char *src;
   2726 		int h;
   2727 		int x = off_x + coff_x;
   2728 		int y = off_y + coff_y;
   2729 
   2730 		src = unclipped_dst + y * wdpy_x * pixelsize +
   2731 		    x * pixelsize;
   2732 		dst = snap->data;
   2733 
   2734 		for (h = 0; h < dpy_y; h++) {
   2735 			memcpy(dst, src, dpy_x * pixelsize);
   2736 			src += wdpy_x * pixelsize;
   2737 			dst += snap->bytes_per_line;
   2738 		}
   2739 	}
   2740 }
   2741 
   2742 int copy_snap(void) {
   2743 	int db = 1;
   2744 	char *fbp;
   2745 	int i, y, block_size;
   2746 	double dt;
   2747 	static int first = 1, snapcnt = 0;
   2748 
   2749 	if (raw_fb_str) {
   2750 		int read_all_at_once = 1;
   2751 		double start = dnow();
   2752 		if (rawfb_reset < 0) {
   2753 			if (getenv("SNAPFB_RAWFB_RESET")) {
   2754 				rawfb_reset = 1;
   2755 			} else {
   2756 				rawfb_reset = 0;
   2757 			}
   2758 		}
   2759 		if (snap_fb == NULL || snap == NULL) {
   2760 			rfbLog("copy_snap: rawfb mode and null snap fb\n");
   2761 			clean_up_exit(1);
   2762 		}
   2763 		if (rawfb_reset) {
   2764 			initialize_raw_fb(1);
   2765 		}
   2766 		if (raw_fb_bytes_per_line != snap->bytes_per_line) {
   2767 			read_all_at_once = 0;
   2768 		}
   2769 		if (raw_fb_full_str && strstr(raw_fb_full_str, "/dev/vcsa")) {
   2770 			snap_vcsa_rawfb();
   2771 		} else if (read_all_at_once) {
   2772 			snap_all_rawfb();
   2773 		} else {
   2774 			/* this goes line by line, XXX not working for video */
   2775 			copy_raw_fb(snap, 0, 0, dpy_x, dpy_y);
   2776 		}
   2777 if (db && snapcnt++ < 5) rfbLog("rawfb copy_snap took: %.5f secs\n", dnow() - start);
   2778 
   2779 		return 0;
   2780 	}
   2781 
   2782 	if (! fs_factor) {
   2783 		return 0;
   2784 	}
   2785 
   2786 
   2787 	if (! snap_fb || ! snap || ! snaprect) {
   2788 		return 0;
   2789 	}
   2790 	block_size = ((dpy_y/fs_factor) * snap->bytes_per_line);
   2791 
   2792 	fbp = snap_fb;
   2793 	y = 0;
   2794 
   2795 
   2796 	dtime0(&dt);
   2797 	X_LOCK;
   2798 
   2799 	/* screen may be too big for 1 shm area, so broken into fs_factor */
   2800 	for (i=0; i < fs_factor; i++) {
   2801 		XRANDR_SET_TRAP_RET(-1, "copy_snap-set");
   2802 		copy_image(snaprect, 0, y, 0, 0);
   2803 		XRANDR_CHK_TRAP_RET(-1, "copy_snap-chk");
   2804 
   2805 		memcpy(fbp, snaprect->data, (size_t) block_size);
   2806 
   2807 		y += dpy_y / fs_factor;
   2808 		fbp += block_size;
   2809 	}
   2810 
   2811 	X_UNLOCK;
   2812 
   2813 	dt = dtime(&dt);
   2814 	if (first) {
   2815 		rfbLog("copy_snap: time for -snapfb snapshot: %.3f sec\n", dt);
   2816 		first = 0;
   2817 	}
   2818 
   2819 	return 0;
   2820 }
   2821 
   2822 
   2823 /*
   2824  * debugging: print out a picture of the tiles.
   2825  */
   2826 static void print_tiles(void) {
   2827 	/* hack for viewing tile diffs on the screen. */
   2828 	static char *prev = NULL;
   2829 	int n, x, y, ms = 1500;
   2830 
   2831 	ms = 1;
   2832 
   2833 	if (! prev) {
   2834 		prev = (char *) malloc((size_t) ntiles);
   2835 		for (n=0; n < ntiles; n++) {
   2836 			prev[n] = 0;
   2837 		}
   2838 	}
   2839 	fprintf(stderr, "   ");
   2840 	for (x=0; x < ntiles_x; x++) {
   2841 		fprintf(stderr, "%1d", x % 10);
   2842 	}
   2843 	fprintf(stderr, "\n");
   2844 	n = 0;
   2845 	for (y=0; y < ntiles_y; y++) {
   2846 		fprintf(stderr, "%2d ", y);
   2847 		for (x=0; x < ntiles_x; x++) {
   2848 			if (tile_has_diff[n]) {
   2849 				fprintf(stderr, "X");
   2850 			} else if (prev[n]) {
   2851 				fprintf(stderr, "o");
   2852 			} else {
   2853 				fprintf(stderr, ".");
   2854 			}
   2855 			n++;
   2856 		}
   2857 		fprintf(stderr, "\n");
   2858 	}
   2859 	for (n=0; n < ntiles; n++) {
   2860 		prev[n] = tile_has_diff[n];
   2861 	}
   2862 	usleep(ms * 1000);
   2863 }
   2864 
   2865 /*
   2866  * Utilities for managing the "naps" to cut down on amount of polling.
   2867  */
   2868 static void nap_set(int tile_cnt) {
   2869 	int nap_in = nap_ok;
   2870 	time_t now = time(NULL);
   2871 
   2872 	if (scan_count == 0) {
   2873 		/* roll up check for all NSCAN scans */
   2874 		nap_ok = 0;
   2875 		if (naptile && nap_diff_count < 2 * NSCAN * naptile) {
   2876 			/* "2" is a fudge to permit a bit of bg drawing */
   2877 			nap_ok = 1;
   2878 		}
   2879 		nap_diff_count = 0;
   2880 	}
   2881 	if (nap_ok && ! nap_in && use_xdamage) {
   2882 		if (XD_skip > 0.8 * XD_tot) 	{
   2883 			/* X DAMAGE is keeping load low, so skip nap */
   2884 			nap_ok = 0;
   2885 		}
   2886 	}
   2887 	if (! nap_ok && client_count) {
   2888 		if(now > last_fb_bytes_sent + no_fbu_blank) {
   2889 			if (debug_tiles > 1) {
   2890 				fprintf(stderr, "nap_set: nap_ok=1: now: %d last: %d\n",
   2891 				    (int) now, (int) last_fb_bytes_sent);
   2892 			}
   2893 			nap_ok = 1;
   2894 		}
   2895 	}
   2896 
   2897 	if (show_cursor) {
   2898 		/* kludge for the up to 4 tiles the mouse patch could occupy */
   2899 		if ( tile_cnt > 4) {
   2900 			last_event = now;
   2901 		}
   2902 	} else if (tile_cnt != 0) {
   2903 		last_event = now;
   2904 	}
   2905 }
   2906 
   2907 /*
   2908  * split up a long nap to improve the wakeup time
   2909  */
   2910 void nap_sleep(int ms, int split) {
   2911 	int i, input = got_user_input;
   2912 	int gd = got_local_pointer_input;
   2913 
   2914 	for (i=0; i<split; i++) {
   2915 		usleep(ms * 1000 / split);
   2916 		if (! use_threads && i != split - 1) {
   2917 			rfbPE(-1);
   2918 		}
   2919 		if (input != got_user_input) {
   2920 			break;
   2921 		}
   2922 		if (gd != got_local_pointer_input) {
   2923 			break;
   2924 		}
   2925 	}
   2926 }
   2927 
   2928 static char *get_load(void) {
   2929 	static char tmp[64];
   2930 	static int count = 0;
   2931 
   2932 	if (count++ % 5 == 0) {
   2933 		struct stat sb;
   2934 		memset(tmp, 0, sizeof(tmp));
   2935 		if (stat("/proc/loadavg", &sb) == 0) {
   2936 			int d = open("/proc/loadavg", O_RDONLY);
   2937 			if (d >= 0) {
   2938 				read(d, tmp, 60);
   2939 				close(d);
   2940 			}
   2941 		}
   2942 		if (tmp[0] == '\0') {
   2943 			strcat(tmp, "unknown");
   2944 		}
   2945 	}
   2946 	return tmp;
   2947 }
   2948 
   2949 /*
   2950  * see if we should take a nap of some sort between polls
   2951  */
   2952 static void nap_check(int tile_cnt) {
   2953 	time_t now;
   2954 
   2955 	nap_diff_count += tile_cnt;
   2956 
   2957 	if (! take_naps) {
   2958 		return;
   2959 	}
   2960 
   2961 	now = time(NULL);
   2962 
   2963 	if (screen_blank > 0) {
   2964 		int dt_ev, dt_fbu;
   2965 		static int ms = 0;
   2966 		if (ms == 0) {
   2967 			ms = 2000;
   2968 			if (getenv("X11VNC_SB_FACTOR")) {
   2969 				ms = ms * atof(getenv("X11VNC_SB_FACTOR"));
   2970 			}
   2971 			if (ms <= 0) {
   2972 				ms = 2000;
   2973 			}
   2974 		}
   2975 
   2976 		/* if no activity, pause here for a second or so. */
   2977 		dt_ev  = (int) (now - last_event);
   2978 		dt_fbu = (int) (now - last_fb_bytes_sent);
   2979 		if (dt_fbu > screen_blank) {
   2980 			/* sleep longer for no fb requests */
   2981 			if (debug_tiles > 1) {
   2982 				fprintf(stderr, "screen blank sleep1: %d ms / 16, load: %s\n", 2 * ms, get_load());
   2983 			}
   2984 			nap_sleep(2 * ms, 16);
   2985 			return;
   2986 		}
   2987 		if (dt_ev > screen_blank) {
   2988 			if (debug_tiles > 1) {
   2989 				fprintf(stderr, "screen blank sleep2: %d ms / 8, load: %s\n", ms, get_load());
   2990 			}
   2991 			nap_sleep(ms, 8);
   2992 			return;
   2993 		}
   2994 	}
   2995 	if (naptile && nap_ok && tile_cnt < naptile) {
   2996 		int ms = napfac * waitms;
   2997 		ms = ms > napmax ? napmax : ms;
   2998 		if (now - last_input <= 3) {
   2999 			nap_ok = 0;
   3000 		} else if (now - last_local_input <= 3) {
   3001 			nap_ok = 0;
   3002 		} else {
   3003 			if (debug_tiles > 1) {
   3004 				fprintf(stderr, "nap_check sleep: %d ms / 1, load: %s\n", ms, get_load());
   3005 			}
   3006 			nap_sleep(ms, 1);
   3007 		}
   3008 	}
   3009 }
   3010 
   3011 /*
   3012  * This is called to avoid a ~20 second timeout in libvncserver.
   3013  * May no longer be needed.
   3014  */
   3015 static void ping_clients(int tile_cnt) {
   3016 	static time_t last_send = 0;
   3017 	time_t now = time(NULL);
   3018 
   3019 	if (rfbMaxClientWait < 20000) {
   3020 		rfbMaxClientWait = 20000;
   3021 		rfbLog("reset rfbMaxClientWait to %d msec.\n",
   3022 		    rfbMaxClientWait);
   3023 	}
   3024 	if (tile_cnt > 0) {
   3025 		last_send = now;
   3026 	} else if (tile_cnt < 0) {
   3027 		/* negative tile_cnt is -ping case */
   3028 		if (now >= last_send - tile_cnt) {
   3029 			mark_rect_as_modified(0, 0, 1, 1, 1);
   3030 			last_send = now;
   3031 		}
   3032 	} else if (now - last_send > 5) {
   3033 		/* Send small heartbeat to client */
   3034 		mark_rect_as_modified(0, 0, 1, 1, 1);
   3035 		last_send = now;
   3036 	}
   3037 }
   3038 
   3039 /*
   3040  * scan_display() wants to know if this tile can be skipped due to
   3041  * blackout regions: (no data compare is done, just a quick geometric test)
   3042  */
   3043 static int blackout_line_skip(int n, int x, int y, int rescan,
   3044     int *tile_count) {
   3045 
   3046 	if (tile_blackout[n].cover == 2) {
   3047 		tile_has_diff[n] = 0;
   3048 		return 1;	/* skip it */
   3049 
   3050 	} else if (tile_blackout[n].cover == 1) {
   3051 		int w, x1, y1, x2, y2, b, hit = 0;
   3052 		if (x + NSCAN > dpy_x) {
   3053 			w = dpy_x - x;
   3054 		} else {
   3055 			w = NSCAN;
   3056 		}
   3057 
   3058 		for (b=0; b < tile_blackout[n].count; b++) {
   3059 
   3060 			/* n.b. these coords are in full display space: */
   3061 			x1 = tile_blackout[n].bo[b].x1;
   3062 			x2 = tile_blackout[n].bo[b].x2;
   3063 			y1 = tile_blackout[n].bo[b].y1;
   3064 			y2 = tile_blackout[n].bo[b].y2;
   3065 
   3066 			if (x2 - x1 < w) {
   3067 				/* need to cover full width */
   3068 				continue;
   3069 			}
   3070 			if (y1 <= y && y < y2) {
   3071 				hit = 1;
   3072 				break;
   3073 			}
   3074 		}
   3075 		if (hit) {
   3076 			if (! rescan) {
   3077 				tile_has_diff[n] = 0;
   3078 			} else {
   3079 				*tile_count += tile_has_diff[n];
   3080 			}
   3081 			return 1;	/* skip */
   3082 		}
   3083 	}
   3084 	return 0;	/* do not skip */
   3085 }
   3086 
   3087 static int blackout_line_cmpskip(int n, int x, int y, char *dst, char *src,
   3088     int w, int pixelsize) {
   3089 
   3090 	int i, x1, y1, x2, y2, b, hit = 0;
   3091 	int beg = -1, end = -1;
   3092 
   3093 	if (tile_blackout[n].cover == 0) {
   3094 		return 0;	/* 0 means do not skip it. */
   3095 	} else if (tile_blackout[n].cover == 2) {
   3096 		return 1;	/* 1 means skip it. */
   3097 	}
   3098 
   3099 	/* tile has partial coverage: */
   3100 
   3101 	for (i=0; i < w * pixelsize; i++)  {
   3102 		if (*(dst+i) != *(src+i)) {
   3103 			beg = i/pixelsize;	/* beginning difference */
   3104 			break;
   3105 		}
   3106 	}
   3107 	for (i = w * pixelsize - 1; i >= 0; i--)  {
   3108 		if (*(dst+i) != *(src+i)) {
   3109 			end = i/pixelsize;	/* ending difference */
   3110 			break;
   3111 		}
   3112 	}
   3113 	if (beg < 0 || end < 0) {
   3114 		/* problem finding range... */
   3115 		return 0;
   3116 	}
   3117 
   3118 	/* loop over blackout rectangles: */
   3119 	for (b=0; b < tile_blackout[n].count; b++) {
   3120 
   3121 		/* y in full display space: */
   3122 		y1 = tile_blackout[n].bo[b].y1;
   3123 		y2 = tile_blackout[n].bo[b].y2;
   3124 
   3125 		/* x relative to tile origin: */
   3126 		x1 = tile_blackout[n].bo[b].x1 - x;
   3127 		x2 = tile_blackout[n].bo[b].x2 - x;
   3128 
   3129 		if (y1 > y || y >= y2) {
   3130 			continue;
   3131 		}
   3132 		if (x1 <= beg && end <= x2) {
   3133 			hit = 1;
   3134 			break;
   3135 		}
   3136 	}
   3137 	if (hit) {
   3138 		return 1;
   3139 	} else {
   3140 		return 0;
   3141 	}
   3142 }
   3143 
   3144 /*
   3145  * For the subwin case follows the window if it is moved.
   3146  */
   3147 void set_offset(void) {
   3148 	Window w;
   3149 	if (! subwin) {
   3150 		return;
   3151 	}
   3152 	X_LOCK;
   3153 	xtranslate(window, rootwin, 0, 0, &off_x, &off_y, &w, 0);
   3154 	X_UNLOCK;
   3155 }
   3156 
   3157 static int xd_samples = 0, xd_misses = 0, xd_do_check = 0;
   3158 
   3159 /*
   3160  * Loop over 1-pixel tall horizontal scanlines looking for changes.
   3161  * Record the changes in tile_has_diff[].  Scanlines in the loop are
   3162  * equally spaced along y by NSCAN pixels, but have a slightly random
   3163  * starting offset ystart ( < NSCAN ) from scanlines[].
   3164  */
   3165 
   3166 static int scan_display(int ystart, int rescan) {
   3167 	char *src, *dst;
   3168 	int pixelsize = bpp/8;
   3169 	int x, y, w, n;
   3170 	int tile_count = 0;
   3171 	int nodiffs = 0, diff_hint;
   3172 	int xd_check = 0, xd_freq = 1;
   3173 	static int xd_tck = 0;
   3174 
   3175 	y = ystart;
   3176 
   3177 	g_now = dnow();
   3178 
   3179 	if (! main_fb) {
   3180 		rfbLog("scan_display: no main_fb!\n");
   3181 		return 0;
   3182 	}
   3183 
   3184 	X_LOCK;
   3185 
   3186 	while (y < dpy_y) {
   3187 
   3188 		if (use_xdamage) {
   3189 			XD_tot++;
   3190 			xd_check = 0;
   3191 			if (xdamage_hint_skip(y)) {
   3192 				if (xd_do_check && dpy && use_xdamage == 1) {
   3193 					xd_tck++;
   3194 					xd_tck = xd_tck % xd_freq;
   3195 					if (xd_tck == 0) {
   3196 						xd_check = 1;
   3197 						xd_samples++;
   3198 					}
   3199 				}
   3200 				if (!xd_check) {
   3201 					XD_skip++;
   3202 					y += NSCAN;
   3203 					continue;
   3204 				}
   3205 			} else {
   3206 				if (xd_do_check && 0) {
   3207 					fprintf(stderr, "ns y=%d\n", y);
   3208 				}
   3209 			}
   3210 		}
   3211 
   3212 		/* grab the horizontal scanline from the display: */
   3213 
   3214 #ifndef NO_NCACHE
   3215 /* XXX Y test */
   3216 if (ncache > 0) {
   3217 	int gotone = 0;
   3218 	if (macosx_console) {
   3219 		if (macosx_checkevent(NULL)) {
   3220 			gotone = 1;
   3221 		}
   3222 	} else {
   3223 #if !NO_X11
   3224 		XEvent ev;
   3225 		if (raw_fb_str) {
   3226 			;
   3227 		} else if (XEventsQueued(dpy, QueuedAlready) == 0) {
   3228 			;	/* XXX Y resp */
   3229 		} else if (XCheckTypedEvent(dpy, MapNotify, &ev)) {
   3230 			gotone = 1;
   3231 		} else if (XCheckTypedEvent(dpy, UnmapNotify, &ev)) {
   3232 			gotone = 2;
   3233 		} else if (XCheckTypedEvent(dpy, CreateNotify, &ev)) {
   3234 			gotone = 3;
   3235 		} else if (XCheckTypedEvent(dpy, ConfigureNotify, &ev)) {
   3236 			gotone = 4;
   3237 		} else if (XCheckTypedEvent(dpy, VisibilityNotify, &ev)) {
   3238 			gotone = 5;
   3239 		}
   3240 		if (gotone) {
   3241 			XPutBackEvent(dpy, &ev);
   3242 		}
   3243 #endif
   3244 	}
   3245 	if (gotone) {
   3246 		static int nomsg = 1;
   3247 		if (nomsg) {
   3248 			if (dnowx() > 20) {
   3249 				nomsg = 0;
   3250 			}
   3251 		} else {
   3252 if (ncdb) fprintf(stderr, "\n*** SCAN_DISPLAY CHECK_NCACHE/%d *** %d rescan=%d\n", gotone, y, rescan);
   3253 		}
   3254 		X_UNLOCK;
   3255 		check_ncache(0, 1);
   3256 		X_LOCK;
   3257 	}
   3258 }
   3259 #endif
   3260 
   3261 		XRANDR_SET_TRAP_RET(-1, "scan_display-set");
   3262 		copy_image(scanline, 0, y, 0, 0);
   3263 		XRANDR_CHK_TRAP_RET(-1, "scan_display-chk");
   3264 
   3265 		/* for better memory i/o try the whole line at once */
   3266 		src = scanline->data;
   3267 		dst = main_fb + y * main_bytes_per_line;
   3268 
   3269 		if (! memcmp(dst, src, main_bytes_per_line)) {
   3270 			/* no changes anywhere in scan line */
   3271 			nodiffs = 1;
   3272 			if (! rescan) {
   3273 				y += NSCAN;
   3274 				continue;
   3275 			}
   3276 		}
   3277 		if (xd_check) {
   3278 			xd_misses++;
   3279 		}
   3280 
   3281 		x = 0;
   3282 		while (x < dpy_x) {
   3283 			n = (x/tile_x) + (y/tile_y) * ntiles_x;
   3284 			diff_hint = 0;
   3285 
   3286 			if (blackouts) {
   3287 				if (blackout_line_skip(n, x, y, rescan,
   3288 				    &tile_count)) {
   3289 					x += NSCAN;
   3290 					continue;
   3291 				}
   3292 			}
   3293 
   3294 			if (rescan) {
   3295 				if (nodiffs || tile_has_diff[n]) {
   3296 					tile_count += tile_has_diff[n];
   3297 					x += NSCAN;
   3298 					continue;
   3299 				}
   3300 			} else if (xdamage_tile_count &&
   3301 			    tile_has_xdamage_diff[n]) {
   3302 				tile_has_xdamage_diff[n] = 2;
   3303 				diff_hint = 1;
   3304 			}
   3305 
   3306 			/* set ptrs to correspond to the x offset: */
   3307 			src = scanline->data + x * pixelsize;
   3308 			dst = main_fb + y * main_bytes_per_line + x * pixelsize;
   3309 
   3310 			/* compute the width of data to be compared: */
   3311 			if (x + NSCAN > dpy_x) {
   3312 				w = dpy_x - x;
   3313 			} else {
   3314 				w = NSCAN;
   3315 			}
   3316 
   3317 			if (diff_hint || memcmp(dst, src, w * pixelsize)) {
   3318 				/* found a difference, record it: */
   3319 				if (! blackouts) {
   3320 					tile_has_diff[n] = 1;
   3321 					tile_count++;
   3322 				} else {
   3323 					if (blackout_line_cmpskip(n, x, y,
   3324 					    dst, src, w, pixelsize)) {
   3325 						tile_has_diff[n] = 0;
   3326 					} else {
   3327 						tile_has_diff[n] = 1;
   3328 						tile_count++;
   3329 					}
   3330 				}
   3331 			}
   3332 			x += NSCAN;
   3333 		}
   3334 		y += NSCAN;
   3335 	}
   3336 
   3337 	X_UNLOCK;
   3338 
   3339 	return tile_count;
   3340 }
   3341 
   3342 
   3343 int scanlines[NSCAN] = {
   3344 	 0, 16,  8, 24,  4, 20, 12, 28,
   3345 	10, 26, 18,  2, 22,  6, 30, 14,
   3346 	 1, 17,  9, 25,  7, 23, 15, 31,
   3347 	19,  3, 27, 11, 29, 13,  5, 21
   3348 };
   3349 
   3350 /*
   3351  * toplevel for the scanning, rescanning, and applying the heuristics.
   3352  * returns number of changed tiles.
   3353  */
   3354 int scan_for_updates(int count_only) {
   3355 	int i, tile_count, tile_diffs;
   3356 	int old_copy_tile;
   3357 	double frac1 = 0.1;   /* tweak parameter to try a 2nd scan_display() */
   3358 	double frac2 = 0.35;  /* or 3rd */
   3359 	double frac3 = 0.02;  /* do scan_display() again after copy_tiles() */
   3360 	static double last_poll = 0.0;
   3361 	double dtmp = 0.0;
   3362 
   3363 	if (unixpw_in_progress) return 0;
   3364 
   3365 	if (slow_fb > 0.0) {
   3366 		double now = dnow();
   3367 		if (now < last_poll + slow_fb) {
   3368 			return 0;
   3369 		}
   3370 		last_poll = now;
   3371 	}
   3372 
   3373 	for (i=0; i < ntiles; i++) {
   3374 		tile_has_diff[i] = 0;
   3375 		tile_has_xdamage_diff[i] = 0;
   3376 		tile_tried[i] = 0;
   3377 		tile_copied[i] = 0;
   3378 	}
   3379 	for (i=0; i < ntiles_y; i++) {
   3380 		/* could be useful, currently not used */
   3381 		tile_row_has_xdamage_diff[i] = 0;
   3382 	}
   3383 	xdamage_tile_count = 0;
   3384 
   3385 	/*
   3386 	 * n.b. this program has only been tested so far with
   3387 	 * tile_x = tile_y = NSCAN = 32!
   3388 	 */
   3389 
   3390 	if (!count_only) {
   3391 		scan_count++;
   3392 		scan_count %= NSCAN;
   3393 
   3394 		/* some periodic maintenance */
   3395 		if (subwin && scan_count % 4 == 0) {
   3396 			set_offset();	/* follow the subwindow */
   3397 		}
   3398 		if (indexed_color && scan_count % 4 == 0) {
   3399 			/* check for changed colormap */
   3400 			set_colormap(0);
   3401 		}
   3402 		if (cmap8to24 && scan_count % 1 == 0) {
   3403 			check_for_multivis();
   3404 		}
   3405 #ifdef MACOSX
   3406 		if (macosx_console) {
   3407 			macosx_event_loop();
   3408 		}
   3409 #endif
   3410 		if (use_xdamage) {
   3411 			/* first pass collecting DAMAGE events: */
   3412 #ifdef MACOSX
   3413 			if (macosx_console) {
   3414 				collect_non_X_xdamage(-1, -1, -1, -1, 0);
   3415 			} else
   3416 #endif
   3417 			{
   3418 				if (rawfb_vnc_reflect) {
   3419 					collect_non_X_xdamage(-1, -1, -1, -1, 0);
   3420 				} else {
   3421 					collect_xdamage(scan_count, 0);
   3422 				}
   3423 			}
   3424 		}
   3425 	}
   3426 
   3427 #define SCAN_FATAL(x) \
   3428 	if (x < 0) { \
   3429 		scan_in_progress = 0; \
   3430 		fb_copy_in_progress = 0; \
   3431 		return 0; \
   3432 	}
   3433 
   3434 	/* scan with the initial y to the jitter value from scanlines: */
   3435 	scan_in_progress = 1;
   3436 	tile_count = scan_display(scanlines[scan_count], 0);
   3437 	SCAN_FATAL(tile_count);
   3438 
   3439 	/*
   3440 	 * we do the XDAMAGE here too since after scan_display()
   3441 	 * there is a better chance we have received the events from
   3442 	 * the X server (otherwise the DAMAGE events will be processed
   3443 	 * in the *next* call, usually too late and wasteful since
   3444 	 * the unchanged tiles are read in again).
   3445 	 */
   3446 	if (use_xdamage) {
   3447 #ifdef MACOSX
   3448 		if (macosx_console) {
   3449 			;
   3450 		} else
   3451 #endif
   3452 		{
   3453 			if (rawfb_vnc_reflect) {
   3454 				;
   3455 			} else {
   3456 				collect_xdamage(scan_count, 1);
   3457 			}
   3458 		}
   3459 	}
   3460 	if (count_only) {
   3461 		scan_in_progress = 0;
   3462 		fb_copy_in_progress = 0;
   3463 		return tile_count;
   3464 	}
   3465 
   3466 	if (xdamage_tile_count) {
   3467 		/* pick up "known" damaged tiles we missed in scan_display() */
   3468 		for (i=0; i < ntiles; i++) {
   3469 			if (tile_has_diff[i]) {
   3470 				continue;
   3471 			}
   3472 			if (tile_has_xdamage_diff[i]) {
   3473 				tile_has_diff[i] = 1;
   3474 				if (tile_has_xdamage_diff[i] == 1) {
   3475 					tile_has_xdamage_diff[i] = 2;
   3476 					tile_count++;
   3477 				}
   3478 			}
   3479 		}
   3480 	}
   3481 	if (dpy && use_xdamage == 1) {
   3482 		static time_t last_xd_check = 0;
   3483 		if (time(NULL) > last_xd_check + 2) {
   3484 			int cp = (scan_count + 3) % NSCAN;
   3485 			xd_do_check = 1;
   3486 			tile_count = scan_display(scanlines[cp], 0);
   3487 			xd_do_check = 0;
   3488 			SCAN_FATAL(tile_count);
   3489 			last_xd_check = time(NULL);
   3490 			if (xd_samples > 200) {
   3491 				static int bad = 0;
   3492 				if (xd_misses > (20 * xd_samples) / 100) {
   3493 					rfbLog("XDAMAGE is not working well... misses: %d/%d\n", xd_misses, xd_samples);
   3494 					rfbLog("Maybe an OpenGL app like Beryl or Compiz is the problem?\n");
   3495 					rfbLog("Use x11vnc -noxdamage or disable the Beryl/Compiz app.\n");
   3496 					rfbLog("To disable this check and warning specify -xdamage twice.\n");
   3497 					if (++bad >= 10) {
   3498 						rfbLog("XDAMAGE appears broken (OpenGL app?), turning it off.\n");
   3499 						use_xdamage = 0;
   3500 						initialize_xdamage();
   3501 						destroy_xdamage_if_needed();
   3502 					}
   3503 				}
   3504 				xd_samples = 0;
   3505 				xd_misses = 0;
   3506 			}
   3507 		}
   3508 	}
   3509 
   3510 	nap_set(tile_count);
   3511 
   3512 	if (fs_factor && frac1 >= fs_frac) {
   3513 		/* make frac1 < fs_frac if fullscreen updates are enabled */
   3514 		frac1 = fs_frac/2.0;
   3515 	}
   3516 
   3517 	if (tile_count > frac1 * ntiles) {
   3518 		/*
   3519 		 * many tiles have changed, so try a rescan (since it should
   3520 		 * be short compared to the many upcoming copy_tiles() calls)
   3521 		 */
   3522 
   3523 		/* this check is done to skip the extra scan_display() call */
   3524 		if (! fs_factor || tile_count <= fs_frac * ntiles) {
   3525 			int cp, tile_count_old = tile_count;
   3526 
   3527 			/* choose a different y shift for the 2nd scan: */
   3528 			cp = (NSCAN - scan_count) % NSCAN;
   3529 
   3530 			tile_count = scan_display(scanlines[cp], 1);
   3531 			SCAN_FATAL(tile_count);
   3532 
   3533 			if (tile_count >= (1 + frac2) * tile_count_old) {
   3534 				/* on a roll... do a 3rd scan */
   3535 				cp = (NSCAN - scan_count + 7) % NSCAN;
   3536 				tile_count = scan_display(scanlines[cp], 1);
   3537 				SCAN_FATAL(tile_count);
   3538 			}
   3539 		}
   3540 		scan_in_progress = 0;
   3541 
   3542 		/*
   3543 		 * At some number of changed tiles it is better to just
   3544 		 * copy the full screen at once.  I.e. time = c1 + m * r1
   3545 		 * where m is number of tiles, r1 is the copy_tiles()
   3546 		 * time, and c1 is the scan_display() time: for some m
   3547 		 * it crosses the full screen update time.
   3548 		 *
   3549 		 * We try to predict that crossover with the fs_frac
   3550 		 * fudge factor... seems to be about 1/2 the total number
   3551 		 * of tiles.  n.b. this ignores network bandwidth,
   3552 		 * compression time etc...
   3553 		 *
   3554 		 * Use -fs 1.0 to disable on slow links.
   3555 		 */
   3556 		if (fs_factor && tile_count > fs_frac * ntiles) {
   3557 			int cs;
   3558 			fb_copy_in_progress = 1;
   3559 			cs = copy_screen();
   3560 			fb_copy_in_progress = 0;
   3561 			SCAN_FATAL(cs);
   3562 			if (use_threads && pointer_mode != 1) {
   3563 				pointer_event(-1, 0, 0, NULL);
   3564 			}
   3565 			nap_check(tile_count);
   3566 			return tile_count;
   3567 		}
   3568 	}
   3569 	scan_in_progress = 0;
   3570 
   3571 	/* copy all tiles with differences from display to rfb framebuffer: */
   3572 	fb_copy_in_progress = 1;
   3573 
   3574 	if (single_copytile || tile_shm_count < ntiles_x) {
   3575 		/*
   3576 		 * Old way, copy I/O one tile at a time.
   3577 		 */
   3578 		old_copy_tile = 1;
   3579 	} else {
   3580 		/*
   3581 		 * New way, does runs of horizontal tiles at once.
   3582 		 * Note that below, for simplicity, the extra tile finding
   3583 		 * (e.g. copy_tiles_backward_pass) is done the old way.
   3584 		 */
   3585 		old_copy_tile = 0;
   3586 	}
   3587 
   3588 	if (unixpw_in_progress) return 0;
   3589 
   3590 /* XXX Y */
   3591 if (0 && tile_count > 20) print_tiles();
   3592 #if 0
   3593 dtmp = dnow();
   3594 #else
   3595 dtmp = 0.0;
   3596 #endif
   3597 
   3598 	if (old_copy_tile) {
   3599 		tile_diffs = copy_all_tiles();
   3600 	} else {
   3601 		tile_diffs = copy_all_tile_runs();
   3602 	}
   3603 	SCAN_FATAL(tile_diffs);
   3604 
   3605 #if 0
   3606 if (tile_count) fprintf(stderr, "XX copytile: %.4f  tile_count: %d\n", dnow() - dtmp, tile_count);
   3607 #endif
   3608 
   3609 	/*
   3610 	 * This backward pass for upward and left tiles complements what
   3611 	 * was done in copy_all_tiles() for downward and right tiles.
   3612 	 */
   3613 	tile_diffs = copy_tiles_backward_pass();
   3614 	SCAN_FATAL(tile_diffs);
   3615 
   3616 	if (tile_diffs > frac3 * ntiles) {
   3617 		/*
   3618 		 * we spent a lot of time in those copy_tiles, run
   3619 		 * another scan, maybe more of the screen changed.
   3620 		 */
   3621 		int cp = (NSCAN - scan_count + 13) % NSCAN;
   3622 
   3623 		scan_in_progress = 1;
   3624 		tile_count = scan_display(scanlines[cp], 1);
   3625 		SCAN_FATAL(tile_count);
   3626 		scan_in_progress = 0;
   3627 
   3628 		tile_diffs = copy_tiles_additional_pass();
   3629 		SCAN_FATAL(tile_diffs);
   3630 	}
   3631 
   3632 	/* Given enough tile diffs, try the islands: */
   3633 	if (grow_fill && tile_diffs > 4) {
   3634 		tile_diffs = grow_islands();
   3635 	}
   3636 	SCAN_FATAL(tile_diffs);
   3637 
   3638 	/* Given enough tile diffs, try the gaps: */
   3639 	if (gaps_fill && tile_diffs > 4) {
   3640 		tile_diffs = fill_tile_gaps();
   3641 	}
   3642 	SCAN_FATAL(tile_diffs);
   3643 
   3644 	fb_copy_in_progress = 0;
   3645 	if (use_threads && pointer_mode != 1) {
   3646 		/*
   3647 		 * tell the pointer handler it can process any queued
   3648 		 * pointer events:
   3649 		 */
   3650 		pointer_event(-1, 0, 0, NULL);
   3651 	}
   3652 
   3653 	if (blackouts) {
   3654 		/* ignore any diffs in completely covered tiles */
   3655 		int x, y, n;
   3656 		for (y=0; y < ntiles_y; y++) {
   3657 			for (x=0; x < ntiles_x; x++) {
   3658 				n = x + y * ntiles_x;
   3659 				if (tile_blackout[n].cover == 2) {
   3660 					tile_has_diff[n] = 0;
   3661 				}
   3662 			}
   3663 		}
   3664 	}
   3665 
   3666 	hint_updates();	/* use x0rfbserver hints algorithm */
   3667 
   3668 	/* Work around threaded rfbProcessClientMessage() calls timeouts */
   3669 	if (use_threads) {
   3670 		ping_clients(tile_diffs);
   3671 	} else if (saw_ultra_chat || saw_ultra_file) {
   3672 		ping_clients(-1);
   3673 	} else if (use_openssl && !tile_diffs) {
   3674 		ping_clients(0);
   3675 	}
   3676 	/* -ping option: */
   3677 	if (ping_interval) {
   3678 		int td = ping_interval > 0 ? ping_interval : -ping_interval;
   3679 		ping_clients(-td);
   3680 	}
   3681 
   3682 
   3683 	nap_check(tile_diffs);
   3684 	return tile_diffs;
   3685 }
   3686 
   3687 
   3688