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 /* -- screen.c -- */
     34 
     35 #include "x11vnc.h"
     36 #include "xevents.h"
     37 #include "xwrappers.h"
     38 #include "xinerama.h"
     39 #include "xdamage.h"
     40 #include "win_utils.h"
     41 #include "cleanup.h"
     42 #include "userinput.h"
     43 #include "scan.h"
     44 #include "user.h"
     45 #include "rates.h"
     46 #include "pointer.h"
     47 #include "keyboard.h"
     48 #include "cursor.h"
     49 #include "connections.h"
     50 #include "remote.h"
     51 #include "unixpw.h"
     52 #include "sslcmds.h"
     53 #include "sslhelper.h"
     54 #include "v4l.h"
     55 #include "linuxfb.h"
     56 #include "macosx.h"
     57 #include "macosxCG.h"
     58 #include "avahi.h"
     59 #include "solid.h"
     60 #include "inet.h"
     61 #include "xrandr.h"
     62 #include "xrecord.h"
     63 #include "pm.h"
     64 
     65 #include <rfb/rfbclient.h>
     66 
     67 void set_greyscale_colormap(void);
     68 void set_hi240_colormap(void);
     69 void unset_colormap(void);
     70 void set_colormap(int reset);
     71 void set_nofb_params(int restore);
     72 void set_raw_fb_params(int restore);
     73 void do_new_fb(int reset_mem);
     74 void free_old_fb(void);
     75 void check_padded_fb(void);
     76 void install_padded_fb(char *geom);
     77 XImage *initialize_xdisplay_fb(void);
     78 void parse_scale_string(char *str, double *factor_x, double *factor_y, int *scaling, int *blend,
     79     int *nomult4, int *pad, int *interpolate, int *numer, int *denom, int w_in, int h_in);
     80 int parse_rotate_string(char *str, int *mode);
     81 int scale_round(int len, double fac);
     82 void initialize_screen(int *argc, char **argv, XImage *fb);
     83 void set_vnc_desktop_name(void);
     84 void announce(int lport, int ssl, char *iface);
     85 
     86 char *vnc_reflect_guess(char *str, char **raw_fb_addr);
     87 void vnc_reflect_process_client(void);
     88 rfbBool vnc_reflect_send_pointer(int x, int y, int mask);
     89 rfbBool vnc_reflect_send_key(uint32_t key, rfbBool down);
     90 rfbBool vnc_reflect_send_cuttext(char *str, int len);
     91 
     92 static void debug_colormap(XImage *fb);
     93 static void set_visual(char *str);
     94 static void nofb_hook(rfbClientPtr cl);
     95 static void remove_fake_fb(void);
     96 static void install_fake_fb(int w, int h, int bpp);
     97 static void initialize_snap_fb(void);
     98 XImage *initialize_raw_fb(int);
     99 static void initialize_clipshift(void);
    100 static int wait_until_mapped(Window win);
    101 static void setup_scaling(int *width_in, int *height_in);
    102 
    103 static void check_filexfer(void);
    104 static void record_last_fb_update(void);
    105 static void check_cursor_changes(void);
    106 static int choose_delay(double dt);
    107 
    108 int rawfb_reset = -1;
    109 int rawfb_dev_video = 0;
    110 int rawfb_vnc_reflect = 0;
    111 
    112 /*
    113  * X11 and rfb display/screen related routines
    114  */
    115 
    116 /*
    117  * Some handling of 8bpp PseudoColor colormaps.  Called for initializing
    118  * the clients and dynamically if -flashcmap is specified.
    119  */
    120 #define NCOLOR 256
    121 
    122 /* this is only for rawfb */
    123 void set_greyscale_colormap(void) {
    124 	int i;
    125 	if (! screen) {
    126 		return;
    127 	}
    128 	/* mutex */
    129 	if (screen->colourMap.data.shorts) {
    130 		free(screen->colourMap.data.shorts);
    131 		screen->colourMap.data.shorts = NULL;
    132 	}
    133 
    134 if (0) fprintf(stderr, "set_greyscale_colormap: %s\n", raw_fb_pixfmt);
    135 	screen->colourMap.count = NCOLOR;
    136 	screen->serverFormat.trueColour = FALSE;
    137 	screen->colourMap.is16 = TRUE;
    138 	screen->colourMap.data.shorts = (unsigned short *)
    139 		malloc(3*sizeof(unsigned short) * NCOLOR);
    140 
    141 	for(i = 0; i < NCOLOR; i++) {
    142 		unsigned short lvl = i * 256;
    143 
    144 		screen->colourMap.data.shorts[i*3+0] = lvl;
    145 		screen->colourMap.data.shorts[i*3+1] = lvl;
    146 		screen->colourMap.data.shorts[i*3+2] = lvl;
    147 	}
    148 
    149 	rfbSetClientColourMaps(screen, 0, NCOLOR);
    150 }
    151 
    152 /* this is specific to bttv rf tuner card */
    153 void set_hi240_colormap(void) {
    154 	int i;
    155 	if (! screen) {
    156 		return;
    157 	}
    158 	/* mutex */
    159 if (0) fprintf(stderr, "set_hi240_colormap: %s\n", raw_fb_pixfmt);
    160 	if (screen->colourMap.data.shorts) {
    161 		free(screen->colourMap.data.shorts);
    162 		screen->colourMap.data.shorts = NULL;
    163 	}
    164 
    165 	screen->colourMap.count = 256;
    166 	screen->serverFormat.trueColour = FALSE;
    167 	screen->colourMap.is16 = TRUE;
    168 	screen->colourMap.data.shorts = (unsigned short *)
    169 		calloc(3*sizeof(unsigned short) * 256, 1);
    170 
    171 	for(i = 0; i < 225; i++) {
    172 		int r, g, b;
    173 
    174 		r = ( (i/5) % 5 ) * 255.0 / 4 + 0.5;
    175 		g = ( (i/25)    ) * 255.0 / 8 + 0.5;
    176 		b = ( i % 5     ) * 255.0 / 4 + 0.5;
    177 
    178 		screen->colourMap.data.shorts[(i+16)*3+0] = (unsigned short) (r * 256);
    179 		screen->colourMap.data.shorts[(i+16)*3+1] = (unsigned short) (g * 256);
    180 		screen->colourMap.data.shorts[(i+16)*3+2] = (unsigned short) (b * 256);
    181 	}
    182 
    183 	rfbSetClientColourMaps(screen, 0, 256);
    184 }
    185 
    186 /* this is only for rawfb */
    187 void unset_colormap(void) {
    188 	if (! screen) {
    189 		return;
    190 	}
    191 	if (screen->colourMap.data.shorts) {
    192 		free(screen->colourMap.data.shorts);
    193 		screen->colourMap.data.shorts = NULL;
    194 	}
    195 	screen->serverFormat.trueColour = TRUE;
    196 if (0) fprintf(stderr, "unset_colormap: %s\n", raw_fb_pixfmt);
    197 }
    198 
    199 /* this is X11 case */
    200 void set_colormap(int reset) {
    201 
    202 #if NO_X11
    203 	if (!reset) {}
    204 	return;
    205 #else
    206 	static int init = 1;
    207 	static XColor *color = NULL, *prev = NULL;
    208 	static int ncolor = 0;
    209 	Colormap cmap;
    210 	Visual *vis;
    211 	int i, ncells, diffs = 0;
    212 
    213 	if (reset) {
    214 		init = 1;
    215 		ncolor = 0;
    216 		/* mutex */
    217 		if (screen->colourMap.data.shorts) {
    218 			free(screen->colourMap.data.shorts);
    219 			screen->colourMap.data.shorts = NULL;
    220 		}
    221 		if (color) {
    222 			free(color);
    223 			color = NULL;
    224 		}
    225 		if (prev) {
    226 			free(prev);
    227 			prev = NULL;
    228 		}
    229 	}
    230 
    231 	if (init) {
    232 		if (depth > 16) {
    233 			ncolor = NCOLOR;
    234 		} else if (depth > 8) {
    235 			ncolor = 1 << depth;
    236 		} else {
    237 			ncolor = NCOLOR;
    238 		}
    239 		/* mutex */
    240 		screen->colourMap.count = ncolor;
    241 		screen->serverFormat.trueColour = FALSE;
    242 		screen->colourMap.is16 = TRUE;
    243 		screen->colourMap.data.shorts = (unsigned short *)
    244 			malloc(3*sizeof(unsigned short) * ncolor);
    245 	}
    246 	if (color == NULL) {
    247 		color = (XColor *) calloc(ncolor * sizeof(XColor), 1);
    248 		prev  = (XColor *) calloc(ncolor * sizeof(XColor), 1);
    249 	}
    250 
    251 	for (i=0; i < ncolor; i++) {
    252 		prev[i].red   = color[i].red;
    253 		prev[i].green = color[i].green;
    254 		prev[i].blue  = color[i].blue;
    255 	}
    256 
    257 	RAWFB_RET_VOID
    258 
    259 	X_LOCK;
    260 
    261 	cmap = DefaultColormap(dpy, scr);
    262 	ncells = CellsOfScreen(ScreenOfDisplay(dpy, scr));
    263 	vis = default_visual;
    264 
    265 	if (subwin) {
    266 		XWindowAttributes attr;
    267 
    268 		if (XGetWindowAttributes(dpy, window, &attr)) {
    269 			cmap = attr.colormap;
    270 			vis = attr.visual;
    271 			ncells = vis->map_entries;
    272 		}
    273 	}
    274 
    275 	if (ncells != ncolor) {
    276 		if (! shift_cmap) {
    277 			screen->colourMap.count = ncells;
    278 		}
    279 	}
    280 	if (init && ! quiet) {
    281 		rfbLog("set_colormap: number of cells: %d, "
    282 		    "ncolor(%d) is %d.\n", ncells, depth, ncolor);
    283 	}
    284 
    285 	if (flash_cmap && ! init) {
    286 		XWindowAttributes attr;
    287 		Window c;
    288 		int tries = 0;
    289 
    290 		c = window;
    291 		while (c && tries++ < 16) {
    292 			c = query_pointer(c);
    293 			if (valid_window(c, &attr, 0)) {
    294 				if (attr.colormap && attr.map_installed) {
    295 					cmap = attr.colormap;
    296 					vis = attr.visual;
    297 					ncells = vis->map_entries;
    298 					break;
    299 				}
    300 			} else {
    301 				break;
    302 			}
    303 		}
    304 	}
    305 	if (ncells > ncolor && ! quiet) {
    306 		rfbLog("set_colormap: big problem: ncells=%d > %d\n",
    307 		    ncells, ncolor);
    308 	}
    309 
    310 	if (vis->class == TrueColor || vis->class == DirectColor) {
    311 		/*
    312 		 * Kludge to make 8bpp TrueColor & DirectColor be like
    313 		 * the StaticColor map.  The ncells = 8 is "8 per subfield"
    314 		 * mentioned in xdpyinfo.  Looks OK... perhaps fortuitously.
    315 		 */
    316 		if (ncells == 8 && ! shift_cmap) {
    317 			ncells = ncolor;
    318 		}
    319 	}
    320 
    321 	for (i=0; i < ncells; i++) {
    322 		color[i].pixel = i;
    323 		color[i].pad = 0;
    324 	}
    325 
    326 	XQueryColors(dpy, cmap, color, ncells);
    327 
    328 	X_UNLOCK;
    329 
    330 	for(i = ncells - 1; i >= 0; i--) {
    331 		int k = i + shift_cmap;
    332 
    333 		screen->colourMap.data.shorts[i*3+0] = color[i].red;
    334 		screen->colourMap.data.shorts[i*3+1] = color[i].green;
    335 		screen->colourMap.data.shorts[i*3+2] = color[i].blue;
    336 
    337 		if (prev[i].red   != color[i].red ||
    338 		    prev[i].green != color[i].green ||
    339 		    prev[i].blue  != color[i].blue ) {
    340 			diffs++;
    341 		}
    342 
    343 		if (shift_cmap && k >= 0 && k < ncolor) {
    344 			/* kludge to copy the colors to higher pixel values */
    345 			screen->colourMap.data.shorts[k*3+0] = color[i].red;
    346 			screen->colourMap.data.shorts[k*3+1] = color[i].green;
    347 			screen->colourMap.data.shorts[k*3+2] = color[i].blue;
    348 		}
    349 	}
    350 
    351 	if (diffs && ! init) {
    352 		if (! all_clients_initialized()) {
    353 			rfbLog("set_colormap: warning: sending cmap "
    354 			    "with uninitialized clients.\n");
    355 		}
    356 		if (shift_cmap) {
    357 			rfbSetClientColourMaps(screen, 0, ncolor);
    358 		} else {
    359 			rfbSetClientColourMaps(screen, 0, ncells);
    360 		}
    361 	}
    362 
    363 	init = 0;
    364 #endif	/* NO_X11 */
    365 }
    366 
    367 static void debug_colormap(XImage *fb) {
    368 	static int debug_cmap = -1;
    369 	int i, k, *histo;
    370 	int ncolor;
    371 
    372 	if (debug_cmap < 0) {
    373 		if (getenv("DEBUG_CMAP") != NULL) {
    374 			debug_cmap = 1;
    375 		} else {
    376 			debug_cmap = 0;
    377 		}
    378 	}
    379 	if (! debug_cmap) {
    380 		return;
    381 	}
    382 	if (! fb) {
    383 		return;
    384 	}
    385 	if (fb->bits_per_pixel > 16) {
    386 		return;
    387 	}
    388 	ncolor = screen->colourMap.count;
    389 	histo = (int *) calloc(ncolor * sizeof(int), 1);
    390 
    391 	for (i=0; i < ncolor; i++) {
    392 		histo[i] = 0;
    393 	}
    394 	for (k = 0; k < fb->width * fb->height; k++) {
    395 		unsigned char n;
    396 		char c = *(fb->data + k);
    397 
    398 		n = (unsigned char) c;
    399 		histo[n]++;
    400 	}
    401 	fprintf(stderr, "\nColormap histogram for current screen contents:\n");
    402 	for (i=0; i < ncolor; i++) {
    403 		unsigned short r = screen->colourMap.data.shorts[i*3+0];
    404 		unsigned short g = screen->colourMap.data.shorts[i*3+1];
    405 		unsigned short b = screen->colourMap.data.shorts[i*3+2];
    406 
    407 		fprintf(stderr, "   %03d: %7d %04x/%04x/%04x", i, histo[i],
    408 		    r, g, b);
    409 		if ((i+1) % 2 == 0)  {
    410 			fprintf(stderr, "\n");
    411 		}
    412 	}
    413 	free(histo);
    414 	fprintf(stderr, "\n");
    415 }
    416 
    417 /*
    418  * Experimental mode to force the visual of the window instead of querying
    419  * it.  Used for testing, overriding some rare cases (win2vnc), and for
    420  * -overlay .  Input string can be a decimal or 0x hex or something like
    421  * TrueColor or TrueColor:24 to force a depth as well.
    422  *
    423  * visual_id and possibly visual_depth are set.
    424  */
    425 static void set_visual(char *str) {
    426 #if NO_X11
    427 	RAWFB_RET_VOID
    428 	if (!str) {}
    429 	return;
    430 #else
    431 	int vis, vdepth, defdepth;
    432 	XVisualInfo vinfo;
    433 	char *p, *vstring = strdup(str);
    434 
    435 	RAWFB_RET_VOID
    436 
    437 	defdepth = DefaultDepth(dpy, scr);
    438 	visual_id = (VisualID) 0;
    439 	visual_depth = 0;
    440 
    441 	if (!strcmp(vstring, "ignore") || !strcmp(vstring, "default")
    442 	    || !strcmp(vstring, "")) {
    443 		free(vstring);
    444 		return;
    445 	}
    446 
    447 	/* set visual depth */
    448 	if ((p = strchr(vstring, ':')) != NULL) {
    449 		visual_depth = atoi(p+1);
    450 		*p = '\0';
    451 		vdepth = visual_depth;
    452 	} else {
    453 		vdepth = defdepth;
    454 	}
    455 	if (! quiet) {
    456 		fprintf(stderr, "\nVisual Info:\n");
    457 		fprintf(stderr, " set_visual(\"%s\")\n", str);
    458 		fprintf(stderr, " visual_depth: %d\n", vdepth);
    459 	}
    460 
    461 	/* set visual id number */
    462 	if (strcmp(vstring, "StaticGray") == 0) {
    463 		vis = StaticGray;
    464 	} else if (strcmp(vstring, "GrayScale") == 0) {
    465 		vis = GrayScale;
    466 	} else if (strcmp(vstring, "StaticColor") == 0) {
    467 		vis = StaticColor;
    468 	} else if (strcmp(vstring, "PseudoColor") == 0) {
    469 		vis = PseudoColor;
    470 	} else if (strcmp(vstring, "TrueColor") == 0) {
    471 		vis = TrueColor;
    472 	} else if (strcmp(vstring, "DirectColor") == 0) {
    473 		vis = DirectColor;
    474 	} else {
    475 		unsigned int v_in;
    476 		if (sscanf(vstring, "0x%x", &v_in) != 1) {
    477 			if (sscanf(vstring, "%u", &v_in) == 1) {
    478 				visual_id = (VisualID) v_in;
    479 				return;
    480 			}
    481 			rfbLogEnable(1);
    482 			rfbLog("invalid -visual arg: %s\n", vstring);
    483 			X_UNLOCK;
    484 			clean_up_exit(1);
    485 		}
    486 		visual_id = (VisualID) v_in;
    487 		free(vstring);
    488 		return;
    489 	}
    490 
    491 	if (! quiet) fprintf(stderr, " visual: %d\n", vis);
    492 	if (XMatchVisualInfo(dpy, scr, visual_depth, vis, &vinfo)) {
    493 		;
    494 	} else if (XMatchVisualInfo(dpy, scr, defdepth, vis, &vinfo)) {
    495 		;
    496 	} else {
    497 		rfbLogEnable(1);
    498 		rfbLog("could not find visual: %s\n", vstring);
    499 		X_UNLOCK;
    500 		clean_up_exit(1);
    501 	}
    502 	free(vstring);
    503 
    504 	/* set numerical visual id. */
    505 	visual_id = vinfo.visualid;
    506 #endif	/* NO_X11 */
    507 }
    508 
    509 void set_nofb_params(int restore) {
    510 	static int first = 1;
    511 	static int save[100];
    512 	static char *scroll = NULL;
    513 	int i = 0;
    514 
    515 	if (first) {
    516 		first = 0;
    517 		save[i++] = use_xfixes;
    518 		save[i++] = use_xdamage;
    519 		save[i++] = use_xrecord;
    520 		save[i++] = wireframe;
    521 		save[i++] = use_solid_bg;
    522 		save[i++] = overlay;
    523 		save[i++] = overlay_cursor;
    524 		save[i++] = using_shm;
    525 		save[i++] = single_copytile;
    526 		save[i++] = take_naps;
    527 		save[i++] = measure_speeds;
    528 		save[i++] = grab_buster;
    529 		save[i++] = show_cursor;
    530 		save[i++] = cursor_shape_updates;
    531 		save[i++] = cursor_pos_updates;
    532 		save[i++] = ncache;
    533 
    534 		scroll = scroll_copyrect;
    535 	}
    536 	if (restore) {
    537 		i = 0;
    538 		use_xfixes            = save[i++];
    539 		use_xdamage           = save[i++];
    540 		use_xrecord           = save[i++];
    541 		wireframe             = save[i++];
    542 		use_solid_bg          = save[i++];
    543 		overlay               = save[i++];
    544 		overlay_cursor        = save[i++];
    545 		using_shm             = save[i++];
    546 		single_copytile       = save[i++];
    547 		take_naps             = save[i++];
    548 		measure_speeds        = save[i++];
    549 		grab_buster           = save[i++];
    550 		show_cursor           = save[i++];
    551 		cursor_shape_updates  = save[i++];
    552 		cursor_pos_updates    = save[i++];
    553 		ncache                = save[i++];
    554 
    555 		scroll_copyrect = scroll;
    556 
    557 		if (cursor_shape_updates) {
    558 			restore_cursor_shape_updates(screen);
    559 		}
    560 		initialize_cursors_mode();
    561 
    562 		return;
    563 	}
    564 
    565 	use_xfixes = 0;
    566 	use_xdamage = 0;
    567 	use_xrecord = 0;
    568 	wireframe = 0;
    569 
    570 	use_solid_bg = 0;
    571 	overlay = 0;
    572 	overlay_cursor = 0;
    573 
    574 	using_shm = 0;
    575 	single_copytile = 1;
    576 
    577 	take_naps = 0;
    578 	measure_speeds = 0;
    579 
    580 	/* got_grab_buster? */
    581 	grab_buster = 0;
    582 
    583 	show_cursor = 0;
    584 	show_multiple_cursors = 0;
    585 	cursor_shape_updates = 0;
    586 	if (! got_cursorpos) {
    587 		cursor_pos_updates = 0;
    588 	}
    589 
    590 	ncache = 0;
    591 
    592 	scroll_copyrect = "never";
    593 
    594 	if (! quiet) {
    595 		rfbLog("disabling: xfixes, xdamage, solid, overlay, shm,\n");
    596 		rfbLog("  wireframe, scrollcopyrect, ncache,\n");
    597 		rfbLog("  noonetile, nap, cursor, %scursorshape\n",
    598 		    got_cursorpos ? "" : "cursorpos, " );
    599 		rfbLog("  in -nofb mode.\n");
    600 	}
    601 }
    602 
    603 static char *raw_fb_orig_dpy = NULL;
    604 
    605 void set_raw_fb_params(int restore) {
    606 	static int first = 1;
    607 	static int vo0, us0, sm0, ws0, wp0, wc0, wb0, na0, tn0;
    608 	static int xr0, xrm0, sb0, re0;
    609 	static char *mc0;
    610 
    611 	/*
    612 	 * set turn off a bunch of parameters not compatible with
    613 	 * -rawfb mode: 1) ignoring the X server 2) ignoring user input.
    614 	 */
    615 
    616 	if (first) {
    617 		/* at least save the initial settings... */
    618 		vo0 = view_only;
    619 		ws0 = watch_selection;
    620 		wp0 = watch_primary;
    621 		wc0 = watch_clipboard;
    622 		wb0 = watch_bell;
    623 		na0 = no_autorepeat;
    624 		sb0 = use_solid_bg;
    625 
    626 		us0 = use_snapfb;
    627 		sm0 = using_shm;
    628 		tn0 = take_naps;
    629 		xr0 = xrandr;
    630 		xrm0 = xrandr_maybe;
    631 		re0 = noxrecord;
    632 		mc0 = multiple_cursors_mode;
    633 
    634 		first = 0;
    635 	}
    636 
    637 	if (restore) {
    638 		view_only = vo0;
    639 		watch_selection = ws0;
    640 		watch_primary = wp0;
    641 		watch_clipboard = wc0;
    642 		watch_bell = wb0;
    643 		no_autorepeat = na0;
    644 		use_solid_bg = sb0;
    645 
    646 		use_snapfb = us0;
    647 		using_shm = sm0;
    648 		take_naps = tn0;
    649 		xrandr = xr0;
    650 		xrandr_maybe = xrm0;
    651 		noxrecord = re0;
    652 		multiple_cursors_mode = mc0;
    653 
    654 		if (! dpy && raw_fb_orig_dpy) {
    655 			dpy = XOpenDisplay_wr(raw_fb_orig_dpy);
    656 			last_open_xdisplay = time(NULL);
    657 			if (dpy) {
    658 				if (! quiet) rfbLog("reopened DISPLAY: %s\n",
    659 				    raw_fb_orig_dpy);
    660 				scr = DefaultScreen(dpy);
    661 				rootwin = RootWindow(dpy, scr);
    662 				check_xevents(1);
    663 			} else {
    664 				if (! quiet) rfbLog("WARNING: failed to reopen "
    665 				    "DISPLAY: %s\n", raw_fb_orig_dpy);
    666 			}
    667 		}
    668 		return;
    669 	}
    670 
    671 	if (verbose) {
    672 		rfbLog("set_raw_fb_params: modifying settings for "
    673 		    "-rawfb mode.\n");
    674 	}
    675 
    676 	if (got_noviewonly) {
    677 		/*
    678 		 * The user input parameters are not unset under
    679 		 * -noviewonly... this usage should be very rare
    680 		 * (i.e. rawfb but also send user input to the X
    681 		 * display, most likely using /dev/fb0 for some reason...)
    682 		 */
    683 		if (verbose) {
    684 		   rfbLog("rawfb: -noviewonly mode: still sending mouse and\n");
    685 		   rfbLog("rawfb:   keyboard input to the X DISPLAY!!\n");
    686 		}
    687 	} else {
    688 		/* Normal case: */
    689 #if 0
    690 		if (! view_only && ! pipeinput_str) {
    691 			if (! quiet) rfbLog("  rawfb: setting view_only\n");
    692 			view_only = 1;
    693 		}
    694 #endif
    695 		if (raw_fb_str && strstr(raw_fb_str, "vnc") == raw_fb_str) {
    696 			;
    697 		} else if (watch_selection) {
    698 			if (verbose) rfbLog("  rawfb: turning off "
    699 			    "watch_selection\n");
    700 			watch_selection = 0;
    701 		}
    702 		if (watch_primary) {
    703 			if (verbose) rfbLog("  rawfb: turning off "
    704 			    "watch_primary\n");
    705 			watch_primary = 0;
    706 		}
    707 		if (watch_clipboard) {
    708 			if (verbose) rfbLog("  rawfb: turning off "
    709 			    "watch_clipboard\n");
    710 			watch_clipboard = 0;
    711 		}
    712 		if (watch_bell) {
    713 			if (verbose) rfbLog("  rawfb: turning off watch_bell\n");
    714 			watch_bell = 0;
    715 		}
    716 		if (no_autorepeat) {
    717 			if (verbose) rfbLog("  rawfb: turning off "
    718 			    "no_autorepeat\n");
    719 			no_autorepeat = 0;
    720 		}
    721 		if (use_solid_bg) {
    722 			if (verbose) rfbLog("  rawfb: turning off "
    723 			    "use_solid_bg\n");
    724 			use_solid_bg = 0;
    725 		}
    726 #ifndef MACOSX
    727 		if (raw_fb_str && strstr(raw_fb_str, "vnc") == raw_fb_str) {
    728 			;
    729 		} else {
    730 			multiple_cursors_mode = strdup("arrow");
    731 		}
    732 #endif
    733 	}
    734 	if (using_shm) {
    735 		if (verbose) rfbLog("  rawfb: turning off using_shm\n");
    736 		using_shm = 0;
    737 	}
    738 	if (take_naps) {
    739 		if (verbose) rfbLog("  rawfb: turning off take_naps\n");
    740 		take_naps = 0;
    741 	}
    742 	if (xrandr) {
    743 		if (verbose) rfbLog("  rawfb: turning off xrandr\n");
    744 		xrandr = 0;
    745 	}
    746 	if (xrandr_maybe) {
    747 		if (verbose) rfbLog("  rawfb: turning off xrandr_maybe\n");
    748 		xrandr_maybe = 0;
    749 	}
    750 	if (! noxrecord) {
    751 		if (verbose) rfbLog("  rawfb: turning off xrecord\n");
    752 		noxrecord = 1;
    753 	}
    754 }
    755 
    756 /*
    757  * Presumably under -nofb the clients will never request the framebuffer.
    758  * However, we have gotten such a request... so let's just give them
    759  * the current view on the display.  n.b. x2vnc and perhaps win2vnc
    760  * requests a 1x1 pixel for some workaround so sadly this evidently
    761  * nearly always happens.
    762  */
    763 static void nofb_hook(rfbClientPtr cl) {
    764 	XImage *fb;
    765 	XImage raw;
    766 
    767 	rfbLog("framebuffer requested in -nofb mode by client %s\n", cl->host);
    768 	/* ignore xrandr */
    769 
    770 	if (raw_fb && ! dpy) {
    771 		fb = &raw;
    772 		fb->data = (char *)malloc(32);
    773 	} else {
    774 		int use_real_ximage = 0;
    775 		if (use_real_ximage) {
    776 			fb = XGetImage_wr(dpy, window, 0, 0, dpy_x, dpy_y, AllPlanes, ZPixmap);
    777 		} else {
    778 			fb = &raw;
    779 			fb->data = (char *) calloc(dpy_x*dpy_y*bpp/8, 1);
    780 		}
    781 	}
    782 	main_fb = fb->data;
    783 	rfb_fb = main_fb;
    784 	/* mutex */
    785 	screen->frameBuffer = rfb_fb;
    786 	screen->displayHook = NULL;
    787 }
    788 
    789 void free_old_fb(void) {
    790 	char *fbs[16];
    791 	int i, j, nfb = 0, db = 0;
    792 
    793 	fbs[nfb++] = main_fb;		main_fb = NULL;
    794 	fbs[nfb++] = rfb_fb;		rfb_fb = NULL;
    795 	fbs[nfb++] = cmap8to24_fb;	cmap8to24_fb = NULL;
    796 	fbs[nfb++] = snap_fb;		snap_fb = NULL;
    797 	fbs[nfb++] = rot_fb;		rot_fb = NULL;
    798 	fbs[nfb++] = raw_fb;		raw_fb = NULL;
    799 
    800 	for (i=0; i < nfb; i++) {
    801 		char *fb = fbs[i];
    802 		int freeit = 1;
    803 		if (! fb || fb < (char *) 0x10) {
    804 			continue;
    805 		}
    806 		for (j=0; j < i; j++) {
    807 			if (fb == fbs[j]) {
    808 				freeit = 0;
    809 				break;
    810 			}
    811 		}
    812 		if (freeit) {
    813 			if (db) fprintf(stderr, "free: %i %p\n", i, fb);
    814 			free(fb);
    815 		} else {
    816 			if (db) fprintf(stderr, "skip: %i %p\n", i, fb);
    817 		}
    818 	}
    819 }
    820 
    821 static char _lcs_tmp[128];
    822 static int _bytes0_size = 128, _bytes0[128];
    823 
    824 static char *lcs(rfbClientPtr cl) {
    825 	sprintf(_lcs_tmp, "%d/%d/%d/%d/%d-%d/%d/%d",
    826 		!!(cl->newFBSizePending),
    827 		!!(cl->cursorWasChanged),
    828 		!!(cl->cursorWasMoved),
    829 		!!(cl->reverseConnection),
    830 		cl->state,
    831 		cl->modifiedRegion  ? !!(sraRgnEmpty(cl->modifiedRegion))  : 2,
    832 		cl->requestedRegion ? !!(sraRgnEmpty(cl->requestedRegion)) : 2,
    833 		cl->copyRegion      ? !!(sraRgnEmpty(cl->copyRegion))      : 2
    834 	);
    835 	return _lcs_tmp;
    836 }
    837 
    838 static int lock_client_sends(int lock) {
    839 	static rfbClientPtr *cls = NULL;
    840 	static int cls_len = 0;
    841 	static int blocked = 0;
    842 	static int state = 0;
    843 	rfbClientIteratorPtr iter;
    844 	rfbClientPtr cl;
    845 	char *s;
    846 
    847 	if (!use_threads || !screen) {
    848 		return 0;
    849 	}
    850 	if (lock < 0) {
    851 		return state;
    852 	}
    853 	state = lock;
    854 
    855 	if (lock) {
    856 		if (cls_len < client_count + 128) {
    857 			if (cls != NULL) {
    858 				free(cls);
    859 			}
    860 			cls_len = client_count + 256;
    861 			cls = (rfbClientPtr *) calloc(cls_len * sizeof(rfbClientPtr), 1);
    862 		}
    863 
    864 		iter = rfbGetClientIterator(screen);
    865 		blocked = 0;
    866 		while ((cl = rfbClientIteratorNext(iter)) != NULL) {
    867 			s = lcs(cl);
    868 			SEND_LOCK(cl);
    869 			rfbLog("locked client:   %p  %.6f %s\n", cl, dnowx(), s);
    870 			cls[blocked++] = cl;
    871 		}
    872 		rfbReleaseClientIterator(iter);
    873 	} else {
    874 		int i;
    875 		for (i=0; i < blocked; i++) {
    876 			cl = cls[i];
    877 			if (cl != NULL) {
    878 				s = lcs(cl);
    879 				SEND_UNLOCK(cl)
    880 				rfbLog("unlocked client: %p  %.6f %s\n", cl, dnowx(), s);
    881 			}
    882 			cls[i] = NULL;
    883 		}
    884 		blocked = 0;
    885 	}
    886 	return state;
    887 }
    888 
    889 static void settle_clients(int init) {
    890 	rfbClientIteratorPtr iter;
    891 	rfbClientPtr cl;
    892 	int fb_pend, i, ms = 1000;
    893 	char *s;
    894 
    895 	if (!use_threads || !screen) {
    896 		return;
    897 	}
    898 
    899 	if (init) {
    900 		iter = rfbGetClientIterator(screen);
    901 		i = 0;
    902 		while ((cl = rfbClientIteratorNext(iter)) != NULL) {
    903 			if (i < _bytes0_size) {
    904 				_bytes0[i] = rfbStatGetSentBytesIfRaw(cl);
    905 			}
    906 			i++;
    907 		}
    908 		rfbReleaseClientIterator(iter);
    909 
    910 		if (getenv("X11VNC_THREADS_NEW_FB_SLEEP")) {
    911 			ms = atoi(getenv("X11VNC_THREADS_NEW_FB_SLEEP"));
    912 		} else if (subwin) {
    913 			ms = 250;
    914 		} else {
    915 			ms = 500;
    916 		}
    917 		usleep(ms * 1000);
    918 		return;
    919 	}
    920 
    921 	if (getenv("X11VNC_THREADS_NEW_FB_SLEEP")) {
    922 		ms = atoi(getenv("X11VNC_THREADS_NEW_FB_SLEEP"));
    923 	} else if (subwin) {
    924 		ms = 500;
    925 	} else {
    926 		ms = 1000;
    927 	}
    928 	usleep(ms * 1000);
    929 
    930 	for (i=0; i < 5; i++) {
    931 		fb_pend = 0;
    932 		iter = rfbGetClientIterator(screen);
    933 		while ((cl = rfbClientIteratorNext(iter)) != NULL) {
    934 			s = lcs(cl);
    935 			if (cl->newFBSizePending) {
    936 				fb_pend++;
    937 				rfbLog("pending fb size: %p  %.6f %s\n", cl, dnowx(), s);
    938 			}
    939 		}
    940 		rfbReleaseClientIterator(iter);
    941 		if (fb_pend > 0) {
    942 			rfbLog("do_new_fb: newFBSizePending extra -threads sleep (%d)\n", i+1);
    943 			usleep(ms * 1000);
    944 		} else {
    945 			break;
    946 		}
    947 	}
    948 	for (i=0; i < 5; i++) {
    949 		int stuck = 0, tot = 0, j = 0;
    950 		iter = rfbGetClientIterator(screen);
    951 		while ((cl = rfbClientIteratorNext(iter)) != NULL) {
    952 			if (j < _bytes0_size) {
    953 				int db = rfbStatGetSentBytesIfRaw(cl) - _bytes0[j];
    954 				int Bpp = cl->format.bitsPerPixel / 8;
    955 
    956 				s = lcs(cl);
    957 				rfbLog("addl bytes sent: %p  %.6f %s  %d  %d\n",
    958 				    cl, dnowx(), s, db, _bytes0[j]);
    959 
    960 				if (i==0) {
    961 					if (db < Bpp * dpy_x * dpy_y) {
    962 						stuck++;
    963 					}
    964 				} else if (i==1) {
    965 					if (db < 0.5 * Bpp * dpy_x * dpy_y) {
    966 						stuck++;
    967 					}
    968 				} else {
    969 					if (db <= 0) {
    970 						stuck++;
    971 					}
    972 				}
    973 			}
    974 			tot++;
    975 			j++;
    976 		}
    977 		rfbReleaseClientIterator(iter);
    978 		if (stuck > 0) {
    979 			rfbLog("clients stuck:  %d/%d  sleep(%d)\n", stuck, tot, i);
    980 			usleep(2 * ms * 1000);
    981 		} else {
    982 			break;
    983 		}
    984 	}
    985 }
    986 
    987 static void prep_clients_for_new_fb(void) {
    988 	rfbClientIteratorPtr iter;
    989 	rfbClientPtr cl;
    990 
    991 	if (!use_threads || !screen) {
    992 		return;
    993 	}
    994 	iter = rfbGetClientIterator(screen);
    995 	while ((cl = rfbClientIteratorNext(iter)) != NULL) {
    996 		if (!cl->newFBSizePending) {
    997 			rfbLog("** set_new_fb_size_pending client:   %p\n", cl);
    998 			cl->newFBSizePending = TRUE;
    999 		}
   1000 		cl->cursorWasChanged = FALSE;
   1001 		cl->cursorWasMoved = FALSE;
   1002 	}
   1003 	rfbReleaseClientIterator(iter);
   1004 }
   1005 
   1006 void do_new_fb(int reset_mem) {
   1007 	XImage *fb;
   1008 
   1009 	/* for threaded we really should lock libvncserver out. */
   1010 	if (use_threads) {
   1011 		int ms = 1000;
   1012 		if (getenv("X11VNC_THREADS_NEW_FB_SLEEP")) {
   1013 			ms = atoi(getenv("X11VNC_THREADS_NEW_FB_SLEEP"));
   1014 		} else if (subwin) {
   1015 			ms = 500;
   1016 		} else {
   1017 			ms = 1000;
   1018 		}
   1019 		rfbLog("Warning: changing framebuffers in threaded mode may be unstable.\n");
   1020 		threads_drop_input = 1;
   1021 		usleep(ms * 1000);
   1022 	}
   1023 
   1024 	INPUT_LOCK;
   1025 	lock_client_sends(1);
   1026 
   1027 	if (use_threads) {
   1028 		settle_clients(1);
   1029 	}
   1030 
   1031 #ifdef MACOSX
   1032 	if (macosx_console) {
   1033 		macosxCG_fini();
   1034 	}
   1035 #endif
   1036 	if (reset_mem == 1) {
   1037 		/* reset_mem == 2 is a hack for changing users... */
   1038 		clean_shm(0);
   1039 		free_tiles();
   1040 	}
   1041 
   1042 	free_old_fb();
   1043 
   1044 	fb = initialize_xdisplay_fb();
   1045 
   1046 	initialize_screen(NULL, NULL, fb);
   1047 
   1048 	if (reset_mem) {
   1049 		initialize_tiles();
   1050 		initialize_blackouts_and_xinerama();
   1051 		initialize_polling_images();
   1052 	}
   1053 	if (ncache) {
   1054 		check_ncache(1, 0);
   1055 	}
   1056 
   1057 	prep_clients_for_new_fb();
   1058 	lock_client_sends(0);
   1059 	INPUT_UNLOCK;
   1060 
   1061 	if (use_threads) {
   1062 		/* need to let things settle... */
   1063 		settle_clients(0);
   1064 		threads_drop_input = 0;
   1065 	}
   1066 }
   1067 
   1068 static void remove_fake_fb(void) {
   1069 	if (! screen) {
   1070 		return;
   1071 	}
   1072 	rfbLog("removing fake fb: 0x%x\n", fake_fb);
   1073 
   1074 	do_new_fb(1);
   1075 
   1076 	/*
   1077 	 * fake_fb is freed in do_new_fb(), but we set to NULL here to
   1078 	 * indicate it is gone.
   1079 	 */
   1080 	fake_fb = NULL;
   1081 }
   1082 
   1083 static void rfb_new_framebuffer(rfbScreenInfoPtr rfbScreen, char *framebuffer,
   1084     int width,int height, int bitsPerSample,int samplesPerPixel,
   1085     int bytesPerPixel) {
   1086 
   1087 	rfbNewFramebuffer(rfbScreen, framebuffer, width, height, bitsPerSample,
   1088 	    samplesPerPixel, bytesPerPixel);
   1089 
   1090 }
   1091 
   1092 static void install_fake_fb(int w, int h, int bpp) {
   1093 	int bpc;
   1094 	if (! screen) {
   1095 		return;
   1096 	}
   1097 	lock_client_sends(1);
   1098 	if (fake_fb) {
   1099 		free(fake_fb);
   1100 	}
   1101 	fake_fb = (char *) calloc(w*h*bpp/8, 1);
   1102 	if (! fake_fb) {
   1103 		rfbLog("could not create fake fb: %dx%d %d\n", w, h, bpp);
   1104 		lock_client_sends(0);
   1105 		return;
   1106 	}
   1107 	bpc = guess_bits_per_color(bpp);
   1108 	rfbLog("installing fake fb: %dx%d %d\n", w, h, bpp);
   1109 	rfbLog("rfbNewFramebuffer(0x%x, 0x%x, %d, %d, %d, %d, %d)\n",
   1110 	    screen, fake_fb, w, h, bpc, 1, bpp/8);
   1111 
   1112 	rfb_new_framebuffer(screen, fake_fb, w, h, bpc, 1, bpp/8);
   1113 	lock_client_sends(0);
   1114 }
   1115 
   1116 void check_padded_fb(void) {
   1117 	if (! fake_fb) {
   1118 		return;
   1119 	}
   1120 	if (unixpw_in_progress) return;
   1121 
   1122 	if (time(NULL) > pad_geometry_time+1 && all_clients_initialized()) {
   1123 		remove_fake_fb();
   1124 	}
   1125 }
   1126 
   1127 void install_padded_fb(char *geom) {
   1128 	int w, h;
   1129 	int ok = 1;
   1130 	if (! geom || *geom == '\0') {
   1131 		ok = 0;
   1132 	} else if (sscanf(geom, "%dx%d", &w, &h) != 2)  {
   1133 		ok = 0;
   1134 	}
   1135 	w = nabs(w);
   1136 	h = nabs(h);
   1137 
   1138 	if (w < 5) w = 5;
   1139 	if (h < 5) h = 5;
   1140 
   1141 	if (!ok) {
   1142 		rfbLog("skipping invalid pad geometry: '%s'\n", NONUL(geom));
   1143 		return;
   1144 	}
   1145 	install_fake_fb(w, h, bpp);
   1146 	pad_geometry_time = time(NULL);
   1147 }
   1148 
   1149 static void initialize_snap_fb(void) {
   1150 	RAWFB_RET_VOID
   1151 	if (snap_fb) {
   1152 		free(snap_fb);
   1153 	}
   1154 	snap = XGetImage_wr(dpy, window, 0, 0, dpy_x, dpy_y, AllPlanes,
   1155 	    ZPixmap);
   1156 	snap_fb = snap->data;
   1157 }
   1158 
   1159 static rfbClient* client = NULL;
   1160 
   1161 void vnc_reflect_bell(rfbClient *cl) {
   1162 	if (cl) {}
   1163 	if (sound_bell) {
   1164 		if (unixpw_in_progress) {
   1165 			return;
   1166 		}
   1167 		if (! all_clients_initialized()) {
   1168 			rfbLog("vnc_reflect_bell: not sending bell: "
   1169 			    "uninitialized clients\n");
   1170 		} else {
   1171 			if (screen && client_count) {
   1172 				rfbSendBell(screen);
   1173 			}
   1174 		}
   1175 	}
   1176 }
   1177 
   1178 void vnc_reflect_recv_cuttext(rfbClient *cl, const char *str, int len) {
   1179 	if (cl) {}
   1180 	if (unixpw_in_progress) {
   1181 		return;
   1182 	}
   1183 	if (! watch_selection) {
   1184 		return;
   1185 	}
   1186 	if (! all_clients_initialized()) {
   1187 		rfbLog("vnc_reflect_recv_cuttext: no send: uninitialized clients\n");
   1188 		return; /* some clients initializing, cannot send */
   1189 	}
   1190 	rfbSendServerCutText(screen, (char *)str, len);
   1191 }
   1192 
   1193 void vnc_reflect_got_update(rfbClient *cl, int x, int y, int w, int h) {
   1194 	if (cl) {}
   1195 	if (use_xdamage) {
   1196 		static int first = 1;
   1197 		if (first) {
   1198 			collect_non_X_xdamage(-1, -1, -1, -1, 0);
   1199 			first = 0;
   1200 		}
   1201 		collect_non_X_xdamage(x, y, w, h, 1);
   1202 	}
   1203 }
   1204 
   1205 void vnc_reflect_got_cursorshape(rfbClient *cl, int xhot, int yhot, int width, int height, int bytesPerPixel) {
   1206 	static int serial = 1;
   1207 	int i, j;
   1208 	char *pixels = NULL;
   1209 	unsigned long r, g, b;
   1210 	unsigned int ui = 0;
   1211 	unsigned long red_mask, green_mask, blue_mask;
   1212 
   1213 	if (cl) {}
   1214 	if (unixpw_in_progress) {
   1215 		return;
   1216 	}
   1217 	if (! all_clients_initialized()) {
   1218 		rfbLog("vnc_reflect_got_copyshape: no send: uninitialized clients\n");
   1219 		return; /* some clients initializing, cannot send */
   1220 	}
   1221 	if (! client->rcSource) {
   1222 		return;
   1223 	}
   1224 	if (bytesPerPixel != 1 && bytesPerPixel != 2 && bytesPerPixel != 4) {
   1225 		return;
   1226 	}
   1227 
   1228 	red_mask   = (client->format.redMax   << client->format.redShift);
   1229 	green_mask = (client->format.greenMax << client->format.greenShift);
   1230 	blue_mask  = (client->format.blueMax  << client->format.blueShift);
   1231 
   1232 	pixels = (char *)malloc(4*width*height);
   1233 	for (j=0; j<height; j++) {
   1234 		for (i=0; i<width; i++) {
   1235 			unsigned int* uip;
   1236 			unsigned char* uic;
   1237 			int m;
   1238 			if (bytesPerPixel == 1) {
   1239 				unsigned char* p = (unsigned char *) client->rcSource;
   1240 				ui = (unsigned long) *(p + j * width + i);
   1241 			} else if (bytesPerPixel == 2) {
   1242 				unsigned short* p = (unsigned short *) client->rcSource;
   1243 				ui = (unsigned long) *(p + j * width + i);
   1244 			} else if (bytesPerPixel == 4) {
   1245 				unsigned int* p = (unsigned int *) client->rcSource;
   1246 				ui = (unsigned long) *(p + j * width + i);
   1247 			}
   1248 			r = (red_mask   & ui) >> client->format.redShift;
   1249 			g = (green_mask & ui) >> client->format.greenShift;
   1250 			b = (blue_mask  & ui) >> client->format.blueShift;
   1251 
   1252 			r = (255 * r) / client->format.redMax;
   1253 			g = (255 * g) / client->format.greenMax;
   1254 			b = (255 * b) / client->format.blueMax;
   1255 
   1256 			ui = (r << 16 | g << 8 | b << 0) ;
   1257 
   1258 			uic = (unsigned char *)client->rcMask;
   1259 			m = (int) *(uic + j * width + i);
   1260 			if (m) {
   1261 				ui |= 0xff000000;
   1262 			}
   1263 			uip = (unsigned int *)pixels;
   1264 			*(uip + j * width + i) = ui;
   1265 		}
   1266 	}
   1267 
   1268 	store_cursor(serial++, (unsigned long*) pixels, width, height, 32, xhot, yhot);
   1269 	free(pixels);
   1270 	set_cursor(cursor_x, cursor_y, get_which_cursor());
   1271 }
   1272 
   1273 rfbBool vnc_reflect_cursor_pos(rfbClient *cl, int x, int y) {
   1274 	if (cl) {}
   1275 	if (debug_pointer) {
   1276 		rfbLog("vnc_reflect_cursor_pos: %d %d\n", x, y);
   1277 	}
   1278 	if (unixpw_in_progress) {
   1279 		if (debug_pointer) {
   1280 			rfbLog("vnc_reflect_cursor_pos: unixpw_in_progress%d\n", unixpw_in_progress);
   1281 		}
   1282 		return TRUE;
   1283 	}
   1284 	if (! all_clients_initialized()) {
   1285 		rfbLog("vnc_reflect_cursor_pos: no send: uninitialized clients\n");
   1286 		return TRUE; /* some clients initializing, cannot send */
   1287 	}
   1288 
   1289 	cursor_position(x, y);
   1290 	set_cursor(x, y, get_which_cursor());
   1291 
   1292 	return TRUE;
   1293 }
   1294 
   1295 static void from_libvncclient_CopyRectangleFromRectangle(rfbClient* client, int src_x, int src_y, int w, int h, int dest_x, int dest_y) {
   1296   int i,j;
   1297 
   1298 #define COPY_RECT_FROM_RECT(BPP) \
   1299   { \
   1300     uint##BPP##_t* _buffer=((uint##BPP##_t*)client->frameBuffer)+(src_y-dest_y)*client->width+src_x-dest_x; \
   1301     if (dest_y < src_y) { \
   1302       for(j = dest_y*client->width; j < (dest_y+h)*client->width; j += client->width) { \
   1303         if (dest_x < src_x) { \
   1304           for(i = dest_x; i < dest_x+w; i++) { \
   1305             ((uint##BPP##_t*)client->frameBuffer)[j+i]=_buffer[j+i]; \
   1306           } \
   1307         } else { \
   1308           for(i = dest_x+w-1; i >= dest_x; i--) { \
   1309             ((uint##BPP##_t*)client->frameBuffer)[j+i]=_buffer[j+i]; \
   1310           } \
   1311         } \
   1312       } \
   1313     } else { \
   1314       for(j = (dest_y+h-1)*client->width; j >= dest_y*client->width; j-=client->width) { \
   1315         if (dest_x < src_x) { \
   1316           for(i = dest_x; i < dest_x+w; i++) { \
   1317             ((uint##BPP##_t*)client->frameBuffer)[j+i]=_buffer[j+i]; \
   1318           } \
   1319         } else { \
   1320           for(i = dest_x+w-1; i >= dest_x; i--) { \
   1321             ((uint##BPP##_t*)client->frameBuffer)[j+i]=_buffer[j+i]; \
   1322           } \
   1323         } \
   1324       } \
   1325     } \
   1326   }
   1327 
   1328   switch(client->format.bitsPerPixel) {
   1329   case  8: COPY_RECT_FROM_RECT(8);  break;
   1330   case 16: COPY_RECT_FROM_RECT(16); break;
   1331   case 32: COPY_RECT_FROM_RECT(32); break;
   1332   default:
   1333     rfbClientLog("Unsupported bitsPerPixel: %d\n",client->format.bitsPerPixel);
   1334   }
   1335 }
   1336 
   1337 void vnc_reflect_got_copyrect(rfbClient *cl, int src_x, int src_y, int w, int h, int dest_x, int dest_y) {
   1338 	sraRegionPtr reg;
   1339 	int dx, dy, rc = -1;
   1340 	static int last_dx = 0, last_dy = 0;
   1341 	if (cl) {}
   1342 	if (unixpw_in_progress) {
   1343 		return;
   1344 	}
   1345 	if (! all_clients_initialized()) {
   1346 		rfbLog("vnc_reflect_got_copyrect: no send: uninitialized clients\n");
   1347 		return; /* some clients initializing, cannot send */
   1348 	}
   1349 	dx = dest_x - src_x;
   1350 	dy = dest_y - src_y;
   1351 	if (dx != last_dx || dy != last_dy) {
   1352 		rc = fb_push_wait(0.05, FB_COPY|FB_MOD);
   1353 	}
   1354 	if (0) fprintf(stderr, "vnc_reflect_got_copyrect: %03dx%03d+%03d+%03d   %3d %3d  rc=%d\n", dest_x, dest_y, w, h, dx, dy, rc);
   1355 	reg = sraRgnCreateRect(dest_x, dest_y, dest_x + w, dest_y + h);
   1356 	do_copyregion(reg, dx, dy, 0);
   1357 	sraRgnDestroy(reg);
   1358 
   1359 	last_dx = dx;
   1360 	last_dy = dy;
   1361 
   1362 	from_libvncclient_CopyRectangleFromRectangle(cl, src_x, src_y, w, h, dest_x, dest_y);
   1363 }
   1364 
   1365 rfbBool vnc_reflect_resize(rfbClient *cl)  {
   1366 	static int first = 1;
   1367 	if(cl->frameBuffer) {
   1368 		free(cl->frameBuffer);
   1369 	}
   1370 	cl->frameBuffer= malloc(cl->width * cl->height * cl->format.bitsPerPixel/8);
   1371 	rfbLog("vnc_reflect_resize: %dx%dx%d first=%d\n", cl->width, cl->height,
   1372 	    cl->format.bitsPerPixel, first);
   1373 	if (!first) {
   1374 		do_new_fb(1);
   1375 	}
   1376 	first = 0;
   1377 	return cl->frameBuffer ? TRUE : FALSE;
   1378 }
   1379 
   1380 #ifdef rfbCredentialTypeX509
   1381 static rfbCredential* vnc_reflect_get_credential(rfbClient* client, int type) {
   1382 	char *pass = getenv("X11VNC_REFLECT_PASSWORD");
   1383 	char *user = getenv("X11VNC_REFLECT_USER");
   1384 	char *cert = getenv("X11VNC_REFLECT_CACERT");
   1385 	char *ccrl = getenv("X11VNC_REFLECT_CACRL");
   1386 	char *clic = getenv("X11VNC_REFLECT_CLIENTCERT");
   1387 	char *clik = getenv("X11VNC_REFLECT_CLIENTKEY");
   1388 	int db = 0;
   1389 	if (client) {}
   1390 if (db) fprintf(stderr, "type: %d\n", type);
   1391 #ifdef rfbCredentialTypeUser
   1392 	if (type == rfbCredentialTypeUser) {
   1393 		if (!pass && !user) {
   1394 			return NULL;
   1395 		} else {
   1396 			rfbCredential *rc = (rfbCredential *) calloc(sizeof(rfbCredential), 1);
   1397 			rc->userCredential.username = (user ? strdup(user) : NULL);
   1398 			rc->userCredential.password = (pass ? strdup(pass) : NULL);
   1399 			return rc;
   1400 		}
   1401 	}
   1402 #endif
   1403 	if (type == rfbCredentialTypeX509) {
   1404 if (db) fprintf(stderr, "cert: %s\n", cert);
   1405 if (db) fprintf(stderr, "ccrl: %s\n", ccrl);
   1406 if (db) fprintf(stderr, "clic: %s\n", clic);
   1407 if (db) fprintf(stderr, "clik: %s\n", clik);
   1408 		if (!cert && !ccrl && !clic && !clik) {
   1409 			return NULL;
   1410 		} else {
   1411 			rfbCredential *rc = (rfbCredential *) calloc(sizeof(rfbCredential), 1);
   1412 			rc->x509Credential.x509CACertFile     = (cert ? strdup(cert) : NULL);
   1413 			rc->x509Credential.x509CACrlFile      = (ccrl ? strdup(ccrl) : NULL);
   1414 			rc->x509Credential.x509ClientCertFile = (clic ? strdup(clic) : NULL);
   1415 			rc->x509Credential.x509ClientKeyFile  = (clik ? strdup(clik) : NULL);
   1416 			return rc;
   1417 		}
   1418 	}
   1419 	return NULL;
   1420 }
   1421 #endif
   1422 
   1423 static char* vnc_reflect_get_password(rfbClient* client) {
   1424 	char *q, *p, *str = getenv("X11VNC_REFLECT_PASSWORD");
   1425 	int len = 110;
   1426 
   1427 	if (client) {}
   1428 
   1429 	if (str) {
   1430 		len += 2*strlen(str);
   1431 	}
   1432 	p = (char *) calloc(len, 1);
   1433 	if (!str || strlen(str) == 0) {
   1434 		fprintf(stderr, "VNC Reflect Password: ");
   1435 		fgets(p, 100, stdin);
   1436 	} else {
   1437 		if (strstr(str, "file:") == str) {
   1438 			FILE *f = fopen(str + strlen("file:"), "r");
   1439 			if (f) {
   1440 				fgets(p, 100, f);
   1441 				fclose(f);
   1442 			}
   1443 		}
   1444 		if (p[0] == '\0') {
   1445 			strncpy(p, str, 100);
   1446 		}
   1447 	}
   1448 	q = p;
   1449 	while (*q != '\0') {
   1450 		if (*q == '\n') {
   1451 			*q = '\0';
   1452 		}
   1453 		q++;
   1454 	}
   1455 	return p;
   1456 }
   1457 
   1458 char *vnc_reflect_guess(char *str, char **raw_fb_addr) {
   1459 
   1460 	static int first = 1;
   1461 	char *hp = str + strlen("vnc:");
   1462 	char *at = NULL;
   1463 	int argc = 0, i;
   1464 	char *argv[16];
   1465 	char str2[256];
   1466 	char *str0 = strdup(str);
   1467 
   1468 	if (client == NULL) {
   1469 		int bitsPerSample = 8;
   1470 		int samplesPerPixel = 3;
   1471 		int bytesPerPixel = 4;
   1472 		char *s;
   1473 		s = getenv("X11VNC_REFLECT_bitsPerSample");
   1474 		if (s) bitsPerSample = atoi(s);
   1475 		s = getenv("X11VNC_REFLECT_samplesPerPixel");
   1476 		if (s) samplesPerPixel = atoi(s);
   1477 		s = getenv("X11VNC_REFLECT_bytesPerPixel");
   1478 		if (s) bytesPerPixel = atoi(s);
   1479 		rfbLog("rfbGetClient(bitsPerSample=%d, samplesPerPixel=%d, bytesPerPixel=%d)\n",
   1480 		    bitsPerSample, samplesPerPixel, bytesPerPixel);
   1481 		client = rfbGetClient(bitsPerSample, samplesPerPixel, bytesPerPixel);
   1482 	}
   1483 
   1484 	rfbLog("rawfb: %s\n", str);
   1485 
   1486 	at = strchr(hp, '@');
   1487 	if (at) {
   1488 		*at = '\0';
   1489 		at++;
   1490 	}
   1491 
   1492 	client->appData.useRemoteCursor = TRUE;
   1493 	client->canHandleNewFBSize = TRUE;
   1494 
   1495 	client->HandleCursorPos = vnc_reflect_cursor_pos;
   1496 	client->GotFrameBufferUpdate = vnc_reflect_got_update;
   1497 	client->MallocFrameBuffer = vnc_reflect_resize;
   1498 	client->Bell = vnc_reflect_bell;
   1499 #if 0
   1500 	client->SoftCursorLockArea = NULL;
   1501 	client->SoftCursorUnlockScreen = NULL;
   1502 	client->FinishedFrameBufferUpdate = NULL;
   1503 	client->HandleKeyboardLedState = NULL;
   1504 	client->HandleTextChat = NULL;
   1505 #endif
   1506 	client->GotXCutText = vnc_reflect_recv_cuttext;
   1507 	client->GotCursorShape = vnc_reflect_got_cursorshape;
   1508 	client->GotCopyRect = vnc_reflect_got_copyrect;
   1509 
   1510 	if (getenv("X11VNC_REFLECT_PASSWORD")) {
   1511 		client->GetPassword = vnc_reflect_get_password;
   1512 	}
   1513 #ifdef rfbCredentialTypeX509
   1514 	client->GetCredential = NULL;
   1515 	if (0 || getenv("LIBVNCCLIENT_GET_CREDENTIAL")) {
   1516 		client->GetCredential = vnc_reflect_get_credential;
   1517 	}
   1518 #endif
   1519 
   1520 	if (first) {
   1521 		argv[argc++] = "x11vnc_rawfb_vnc";
   1522 		if (strstr(hp, "listen") == hp) {
   1523 			char *q = strrchr(hp, ':');
   1524 			argv[argc++] = strdup("-listen");
   1525 			if (q) {
   1526 				client->listenPort = atoi(q+1);
   1527 			} else {
   1528 				client->listenPort = LISTEN_PORT_OFFSET;
   1529 			}
   1530 		} else {
   1531 			argv[argc++] = strdup(hp);
   1532 		}
   1533 
   1534 		if (! rfbInitClient(client, &argc, argv)) {
   1535 			rfbLog("vnc_reflector failed for: %s\n", str0);
   1536 			clean_up_exit(1);
   1537 		}
   1538 	}
   1539 
   1540 	if (at) {
   1541 		sprintf(str2, "map:/dev/null@%s", at);
   1542 	} else {
   1543 		unsigned long red_mask, green_mask, blue_mask;
   1544 		red_mask   = (client->format.redMax   << client->format.redShift);
   1545 		green_mask = (client->format.greenMax << client->format.greenShift);
   1546 		blue_mask  = (client->format.blueMax  << client->format.blueShift);
   1547 		sprintf(str2, "map:/dev/null@%dx%dx%d:0x%lx/0x%lx/0x%lx",
   1548 		    client->width, client->height, client->format.bitsPerPixel,
   1549 		    red_mask, green_mask, blue_mask);
   1550 	}
   1551 	*raw_fb_addr = (char *) client->frameBuffer;
   1552 	free(str0);
   1553 
   1554 	if (first) {
   1555 		setup_cursors_and_push();
   1556 
   1557 		for (i=0; i<10; i++) {
   1558 			vnc_reflect_process_client();
   1559 		}
   1560 	}
   1561 	first = 0;
   1562 
   1563 	return strdup(str2);
   1564 }
   1565 
   1566 rfbBool vnc_reflect_send_pointer(int x, int y, int mask) {
   1567 	int rc;
   1568 	if (mask >= 0) {
   1569 		got_user_input++;
   1570 		got_pointer_input++;
   1571 		last_pointer_time = time(NULL);
   1572 	}
   1573 
   1574 	if (clipshift) {
   1575 		x += coff_x;
   1576 		y += coff_y;
   1577 	}
   1578 
   1579 	if (cursor_x != x || cursor_y != y) {
   1580 		last_pointer_motion_time = dnow();
   1581 	}
   1582 
   1583 	cursor_x = x;
   1584 	cursor_y = y;
   1585 
   1586 	/* record the x, y position for the rfb screen as well. */
   1587 	cursor_position(x, y);
   1588 
   1589 	/* change the cursor shape if necessary */
   1590 	rc = set_cursor(x, y, get_which_cursor());
   1591 	cursor_changes += rc;
   1592 
   1593 	return SendPointerEvent(client, x, y, mask);
   1594 }
   1595 
   1596 rfbBool vnc_reflect_send_key(uint32_t key, rfbBool down) {
   1597 	return SendKeyEvent(client, key, down);
   1598 }
   1599 
   1600 rfbBool vnc_reflect_send_cuttext(char *str, int len) {
   1601 	return SendClientCutText(client, str, len);
   1602 }
   1603 
   1604 void vnc_reflect_process_client(void) {
   1605 	int num;
   1606 	if (client == NULL) {
   1607 		return;
   1608 	}
   1609 	num = WaitForMessage(client, 1000);
   1610 	if (num > 0) {
   1611 		if (!HandleRFBServerMessage(client)) {
   1612 			rfbLog("vnc_reflect_process_client: read failure to server\n");
   1613 			shut_down = 1;
   1614 		}
   1615 	}
   1616 }
   1617 
   1618 void linux_dev_fb_msg(char* q) {
   1619 	if (strstr(q, "/dev/fb") && strstr(UT.sysname, "Linux")) {
   1620 		rfbLog("\n");
   1621 		rfbLog("On Linux you may need to load a kernel module to enable\n");
   1622 		rfbLog("the framebuffer device /dev/fb*; e.g.:\n");
   1623 		rfbLog("   vga=0x303 (and others) kernel boot parameter\n");
   1624 		rfbLog("   modprobe uvesafb\n");
   1625 		rfbLog("   modprobe radeonfb (card specific)\n");
   1626 		rfbLog("   modprobe nvidiafb (card specific, others)\n");
   1627 		rfbLog("   modprobe vesafb (?)\n");
   1628 		rfbLog("   modprobe vga16fb\n");
   1629 		rfbLog("\n");
   1630 		rfbLog("You may also need root permission to open /dev/fb*\n");
   1631 		rfbLog("and/or /dev/tty*.\n");
   1632 		rfbLog("\n");
   1633 	}
   1634 }
   1635 
   1636 #define RAWFB_MMAP 1
   1637 #define RAWFB_FILE 2
   1638 #define RAWFB_SHM  3
   1639 
   1640 XImage *initialize_raw_fb(int reset) {
   1641 	char *str, *rstr, *q;
   1642 	int w, h, b, shmid = 0;
   1643 	unsigned long rm = 0, gm = 0, bm = 0, tm;
   1644 	static XImage ximage_struct;	/* n.b.: not (XImage *) */
   1645 	static XImage ximage_struct_snap;
   1646 	int closedpy = 1, i, m, db = 0;
   1647 	int do_macosx = 0;
   1648 	int do_reflect = 0;
   1649 	char *unlink_me = NULL;
   1650 
   1651 	static char *last_file = NULL;
   1652 	static int last_mode = 0;
   1653 
   1654 	if (reset && last_mode) {
   1655 		int fd;
   1656 		if (last_mode != RAWFB_MMAP && last_mode != RAWFB_FILE) {
   1657 			return NULL;
   1658 		}
   1659 		if (last_mode == RAWFB_MMAP) {
   1660 			munmap(raw_fb_addr, raw_fb_mmap);
   1661 		}
   1662 		if (raw_fb_fd >= 0) {
   1663 			close(raw_fb_fd);
   1664 		}
   1665 		raw_fb_fd = -1;
   1666 if (db) fprintf(stderr, "initialize_raw_fb reset\n");
   1667 
   1668 		fd = -1;
   1669 		if (rawfb_dev_video) {
   1670 			fd = open(last_file, O_RDWR);
   1671 		}
   1672 		if (fd < 0) {
   1673 			fd = open(last_file, O_RDONLY);
   1674 		}
   1675 		if (fd < 0) {
   1676 			rfbLogEnable(1);
   1677 			rfbLog("failed to rawfb file: %s\n", last_file);
   1678 			rfbLogPerror("open");
   1679 			clean_up_exit(1);
   1680 		}
   1681 		raw_fb_fd = fd;
   1682 		if (last_mode == RAWFB_MMAP) {
   1683 			raw_fb_addr = mmap(0, raw_fb_mmap, PROT_READ,
   1684 			    MAP_SHARED, fd, 0);
   1685 
   1686 			if (raw_fb_addr == MAP_FAILED || raw_fb_addr == NULL) {
   1687 				rfbLogEnable(1);
   1688 				rfbLog("failed to mmap file: %s\n", last_file);
   1689 				rfbLog("   raw_fb_addr: %p\n", raw_fb_addr);
   1690 				rfbLogPerror("mmap");
   1691 				clean_up_exit(1);
   1692 			}
   1693 		}
   1694 		return NULL;
   1695 	}
   1696 
   1697 #ifdef MACOSX
   1698 	if (raw_fb_addr != NULL && macosx_console && raw_fb_addr == macosx_get_fb_addr()) {
   1699 		raw_fb_addr = NULL;
   1700 	}
   1701 #endif
   1702 
   1703 	if (raw_fb_addr || raw_fb_seek) {
   1704 		if (raw_fb_shm) {
   1705 			shmdt(raw_fb_addr);
   1706 #if LIBVNCSERVER_HAVE_MMAP
   1707 		} else if (raw_fb_mmap) {
   1708 			munmap(raw_fb_addr, raw_fb_mmap);
   1709 			if (raw_fb_fd >= 0) {
   1710 				close(raw_fb_fd);
   1711 			}
   1712 			raw_fb_fd = -1;
   1713 #endif
   1714 		} else if (raw_fb_seek) {
   1715 			if (raw_fb_fd >= 0) {
   1716 				close(raw_fb_fd);
   1717 			}
   1718 			raw_fb_fd = -1;
   1719 		}
   1720 		raw_fb_addr = NULL;
   1721 		raw_fb_mmap = 0;
   1722 		raw_fb_seek = 0;
   1723 	}
   1724 	if (! raw_fb_str) {
   1725 		return NULL;
   1726 	}
   1727 
   1728 	if (raw_fb_str[0] == '+') {
   1729 		rstr = strdup(raw_fb_str+1);
   1730 		closedpy = 0;
   1731 		if (! window) {
   1732 			window = rootwin;
   1733 		}
   1734 	} else {
   1735 		rstr = strdup(raw_fb_str);
   1736 	}
   1737 
   1738 	/* testing aliases */
   1739 	if (!strcasecmp(rstr, "NULL") || !strcasecmp(rstr, "ZERO")
   1740 	    || !strcasecmp(rstr, "NONE")) {
   1741 		rstr = strdup("map:/dev/zero@640x480x32");
   1742 	} else if (!strcasecmp(rstr, "NULLBIG") || !strcasecmp(rstr, "NONEBIG")) {
   1743 		rstr = strdup("map:/dev/zero@1024x768x32");
   1744 	}
   1745 	if (!strcasecmp(rstr, "RAND")) {
   1746 		rstr = strdup("file:/dev/urandom@128x128x16");
   1747 	} else if (!strcasecmp(rstr, "RANDBIG")) {
   1748 		rstr = strdup("file:/dev/urandom@640x480x16");
   1749 	} else if (!strcasecmp(rstr, "RANDHUGE")) {
   1750 		rstr = strdup("file:/dev/urandom@1024x768x16");
   1751 	}
   1752 	if (strstr(rstr, "solid=") == rstr) {
   1753 		char *n = rstr + strlen("solid=");
   1754 		char tmp[] = "/tmp/rawfb_solid.XXXXXX";
   1755 		char str[100];
   1756 		unsigned int vals[1024], val;
   1757 		int x, y, fd, w = 1024, h = 768;
   1758 		if (strstr(n, "0x")) {
   1759 			if (sscanf(n, "0x%x", &val) != 1) {
   1760 				val = 0;
   1761 			}
   1762 		}
   1763 		if (val == 0) {
   1764 			val = get_pixel(n);
   1765 		}
   1766 		if (val == 0) {
   1767 			val = 0xFF00FF;
   1768 		}
   1769 		fd = mkstemp(tmp);
   1770 		for (y = 0; y < h; y++) {
   1771 			for (x = 0; x < w; x++) {
   1772 				vals[x] = val;
   1773 			}
   1774 			write(fd, (char *)vals, 4 * w);
   1775 		}
   1776 		close(fd);
   1777 		fd = open(tmp, O_WRONLY);
   1778 		unlink_me = strdup(tmp);
   1779 		sprintf(str, "map:%s@%dx%dx32", tmp, w, h);
   1780 		rstr = strdup(str);
   1781 	} else if (strstr(rstr, "swirl") == rstr) {
   1782 		char tmp[] = "/tmp/rawfb_swirl.XXXXXX";
   1783 		char str[100];
   1784 		unsigned int val[1024];
   1785 		unsigned int c1, c2, c3, c4;
   1786 		int x, y, fd, w = 1024, h = 768;
   1787 		fd = mkstemp(tmp);
   1788 		for (y = 0; y < h; y++) {
   1789 			for (x = 0; x < w; x++) {
   1790 				c1 = 0;
   1791 				c2 = ((x+y)*128)/(w+h);
   1792 				c3 = (x*128)/w;
   1793 				c4 = (y*256)/h;
   1794 				val[x] = (c1 << 24) | (c2 << 16) | (c3 << 8) | (c4 << 0);
   1795 			}
   1796 			write(fd, (char *)val, 4 * w);
   1797 		}
   1798 		close(fd);
   1799 		fd = open(tmp, O_WRONLY);
   1800 		unlink_me = strdup(tmp);
   1801 		sprintf(str, "map:%s@%dx%dx32", tmp, w, h);
   1802 		rstr = strdup(str);
   1803 	}
   1804 
   1805 
   1806 	if ( (q = strstr(rstr, "setup:")) == rstr) {
   1807 		FILE *pipe;
   1808 		char line[1024], *t;
   1809 
   1810 		set_child_info();
   1811 		q += strlen("setup:");
   1812 		/* rawfb-setup */
   1813 		if (no_external_cmds || !cmd_ok("rawfb-setup")) {
   1814 			rfbLogEnable(1);
   1815 			rfbLog("cannot run external commands in -nocmds "
   1816 			    "mode:\n");
   1817 			rfbLog("   \"%s\"\n", q);
   1818 			rfbLog("   exiting.\n");
   1819 			clean_up_exit(1);
   1820 		}
   1821 		rfbLog("running command to setup rawfb: %s\n", q);
   1822 		close_exec_fds();
   1823 		pipe = popen(q, "r");
   1824 		if (! pipe) {
   1825 			rfbLogEnable(1);
   1826 			rfbLog("popen of setup command failed.\n");
   1827 			rfbLogPerror("popen");
   1828 			clean_up_exit(1);
   1829 		}
   1830 		line[0] = '\0';
   1831 		if (fgets(line, 1024, pipe) == NULL) {
   1832 			rfbLogEnable(1);
   1833 			rfbLog("read of setup command failed.\n");
   1834 			clean_up_exit(1);
   1835 		}
   1836 		pclose(pipe);
   1837 		str = strdup(line);
   1838 		t = str;
   1839 		while (*t != '\0') {
   1840 			if (*t == '\n') {
   1841 				*t = '\0';
   1842 			}
   1843 			t++;
   1844 		}
   1845 		rfbLog("setup command returned: %s\n", str);
   1846 
   1847 	} else {
   1848 		str = strdup(rstr);
   1849 	}
   1850 
   1851 	raw_fb_shm = 0;
   1852 	raw_fb_mmap = 0;
   1853 	raw_fb_seek = 0;
   1854 	raw_fb_fd = -1;
   1855 	raw_fb_addr = NULL;
   1856 	raw_fb_offset = 0;
   1857 	raw_fb_bytes_per_line = 0;
   1858 	rawfb_vnc_reflect = 0;
   1859 
   1860 	last_mode = 0;
   1861 	if (last_file) {
   1862 		free(last_file);
   1863 		last_file = NULL;
   1864 	}
   1865 	if (strstr(str, "Video") == str) {
   1866 		if (pipeinput_str != NULL) {
   1867 			free(pipeinput_str);
   1868 		}
   1869 		pipeinput_str = strdup("VID");
   1870 		initialize_pipeinput();
   1871 		str[0] = 'v';
   1872 	}
   1873 
   1874 	if (strstr(str, "video") == str || strstr(str, "/dev/video") == str) {
   1875 		char *str2 = v4l_guess(str, &raw_fb_fd);
   1876 		if (str2 == NULL) {
   1877 			rfbLog("v4l_guess failed for: %s\n", str);
   1878 			clean_up_exit(1);
   1879 		}
   1880 		str = str2;
   1881 		rfbLog("v4l_guess returned: %s\n", str);
   1882 		rawfb_dev_video = 1;
   1883 	} else if (strstr(str, "dev/video")) {
   1884 		rawfb_dev_video = 1;
   1885 	} else if (strstr(str, "console") == str || strstr(str, "fb") == str ||
   1886 	    strstr(str, "/dev/fb") == str || strstr(str, "vt") == str) {
   1887 		char *str2 = console_guess(str, &raw_fb_fd);
   1888 		if (str2 == NULL) {
   1889 			rfbLog("console_guess failed for: %s\n", str);
   1890 			clean_up_exit(1);
   1891 		}
   1892 		str = str2;
   1893 		rfbLog("console_guess returned: %s\n", str);
   1894 	} else if (strstr(str, "vnc:") == str) {
   1895 		char *str2 = vnc_reflect_guess(str, &raw_fb_addr);
   1896 
   1897 		rawfb_vnc_reflect = 1;
   1898 		do_reflect = 1;
   1899 
   1900 		str = str2;
   1901 		rfbLog("vnc_reflector set rawfb str to: %s\n", str);
   1902 		if (pipeinput_str == NULL) {
   1903 			pipeinput_str = strdup("VNC");
   1904 		}
   1905 		initialize_pipeinput();
   1906 	}
   1907 
   1908 	if (closedpy && !view_only && got_noviewonly) {
   1909 		rfbLog("not closing X DISPLAY under -noviewonly option.\n");
   1910 		closedpy = 0;
   1911 		if (! window) {
   1912 			window = rootwin;
   1913 		}
   1914 	}
   1915 
   1916 	if (! raw_fb_orig_dpy && dpy) {
   1917 		raw_fb_orig_dpy = strdup(DisplayString(dpy));
   1918 	}
   1919 #ifndef BOLDLY_CLOSE_DISPLAY
   1920 #define BOLDLY_CLOSE_DISPLAY 1
   1921 #endif
   1922 #if BOLDLY_CLOSE_DISPLAY
   1923 	if (closedpy) {
   1924 		if (dpy) {
   1925 			rfbLog("closing X DISPLAY: %s in rawfb mode.\n",
   1926 			    DisplayString(dpy));
   1927 			XCloseDisplay_wr(dpy);	/* yow! */
   1928 		}
   1929 		dpy = NULL;
   1930 	}
   1931 #endif
   1932 
   1933 	/*
   1934 	 * -rawfb shm:163938442@640x480x32:ff/ff00/ff0000+3000
   1935 	 * -rawfb map:/path/to/file@640x480x32:ff/ff00/ff0000
   1936 	 * -rawfb file:/path/to/file@640x480x32:ff/ff00/ff0000
   1937 	 */
   1938 
   1939 	if (raw_fb_full_str) {
   1940 		free(raw_fb_full_str);
   1941 	}
   1942 	raw_fb_full_str = strdup(str);
   1943 
   1944 
   1945 	/* +O offset */
   1946 	if ((q = strrchr(str, '+')) != NULL) {
   1947 		if (sscanf(q, "+%d", &raw_fb_offset) == 1) {
   1948 			*q = '\0';
   1949 		} else {
   1950 			raw_fb_offset = 0;
   1951 		}
   1952 	}
   1953 	/* :R/G/B masks */
   1954 	if ((q = strrchr(str, ':')) != NULL) {
   1955 		if (sscanf(q, ":%lx/%lx/%lx", &rm, &gm, &bm) == 3) {
   1956 			*q = '\0';
   1957 		} else if (sscanf(q, ":0x%lx/0x%lx/0x%lx", &rm, &gm, &bm)== 3) {
   1958 			*q = '\0';
   1959 		} else if (sscanf(q, ":%lu/%lu/%lu", &rm, &gm, &bm) == 3) {
   1960 			*q = '\0';
   1961 		} else {
   1962 			rm = 0;
   1963 			gm = 0;
   1964 			bm = 0;
   1965 		}
   1966 	}
   1967 	if ((q = strrchr(str, '@')) == NULL) {
   1968 		rfbLogEnable(1);
   1969 		rfbLog("invalid rawfb str: %s\n", str);
   1970 		clean_up_exit(1);
   1971 	}
   1972 
   1973 	if (strrchr(q, '-')) {
   1974 		char *q2 = strrchr(q, '-');
   1975 		raw_fb_bytes_per_line = atoi(q2+1);
   1976 		*q2 = '\0';
   1977 	}
   1978 	/* @WxHxB */
   1979 	if (sscanf(q, "@%dx%dx%d", &w, &h, &b) != 3) {
   1980 		rfbLogEnable(1);
   1981 		rfbLog("invalid rawfb str: %s\n", str);
   1982 		clean_up_exit(1);
   1983 	}
   1984 	*q = '\0';
   1985 
   1986 	if (rm == 0 && gm == 0 && bm == 0) {
   1987 		/* guess masks... */
   1988 		if (b == 24 || b == 32) {
   1989 			rm = 0xff0000;
   1990 			gm = 0x00ff00;
   1991 			bm = 0x0000ff;
   1992 		} else if (b == 16) {
   1993 			rm = 0xf800;
   1994 			gm = 0x07e0;
   1995 			bm = 0x001f;
   1996 		} else if (b == 8) {
   1997 			rm = 0x07;
   1998 			gm = 0x38;
   1999 			bm = 0xc0;
   2000 		}
   2001 	}
   2002 	/* we can fake -flipbyteorder to some degree... */
   2003 	if (flip_byte_order) {
   2004 		if (b == 24 || b == 32) {
   2005 			tm = rm;
   2006 			rm = bm;
   2007 			bm = tm;
   2008 		} else if (b == 16) {
   2009 			unsigned short s1, s2;
   2010 			s1 = (unsigned short) rm;
   2011 			s2 = ((0xff & s1) << 8) | ((0xff00 & s1) >> 8);
   2012 			rm = (unsigned long) s2;
   2013 			s1 = (unsigned short) gm;
   2014 			s2 = ((0xff & s1) << 8) | ((0xff00 & s1) >> 8);
   2015 			gm = (unsigned long) s2;
   2016 			s1 = (unsigned short) bm;
   2017 			s2 = ((0xff & s1) << 8) | ((0xff00 & s1) >> 8);
   2018 			bm = (unsigned long) s2;
   2019 		}
   2020 	}
   2021 
   2022 	/* native fb stuff for bpp < 8 only */
   2023 	raw_fb_native_bpp = b;
   2024 	raw_fb_native_red_mask = rm;
   2025 	raw_fb_native_green_mask = gm;
   2026 	raw_fb_native_blue_mask = bm;
   2027 	raw_fb_native_red_shift = 100;
   2028 	raw_fb_native_green_shift = 100;
   2029 	raw_fb_native_blue_shift = 100;
   2030 	raw_fb_native_red_max = 1;
   2031 	raw_fb_native_green_max = 1;
   2032 	raw_fb_native_blue_max = 1;
   2033 	m = 1;
   2034 	for (i=0; i<32; i++)  {
   2035 		if (raw_fb_native_red_mask & m) {
   2036 			if (raw_fb_native_red_shift == 100) {
   2037 				raw_fb_native_red_shift = i;
   2038 			}
   2039 			raw_fb_native_red_max *= 2;
   2040 		}
   2041 		if (raw_fb_native_green_mask & m) {
   2042 			if (raw_fb_native_green_shift == 100) {
   2043 				raw_fb_native_green_shift = i;
   2044 			}
   2045 			raw_fb_native_green_max *= 2;
   2046 		}
   2047 		if (raw_fb_native_blue_mask & m) {
   2048 			if (raw_fb_native_blue_shift == 100) {
   2049 				raw_fb_native_blue_shift = i;
   2050 			}
   2051 			raw_fb_native_blue_max *= 2;
   2052 		}
   2053 		m = m << 1;
   2054 	}
   2055 	raw_fb_native_red_max -= 1;
   2056 	raw_fb_native_green_max -= 1;
   2057 	raw_fb_native_blue_max -= 1;
   2058 
   2059 	if (b < 8) {
   2060 		/* e.g. VGA16 */
   2061 		rfbLog("raw_fb_native_bpp: %d 0x%02lx 0x%02lx 0x%02lx %d/%d/%d %d/%d/%d\n", raw_fb_native_bpp,
   2062 		    raw_fb_native_red_mask, raw_fb_native_green_mask, raw_fb_native_blue_mask,
   2063 		    raw_fb_native_red_max, raw_fb_native_green_max, raw_fb_native_blue_max,
   2064 		    raw_fb_native_red_shift, raw_fb_native_green_shift, raw_fb_native_blue_shift);
   2065 		raw_fb_expand_bytes = 1;
   2066 		b = 8;
   2067 		rm = 0x07;
   2068 		gm = 0x38;
   2069 		bm = 0xc0;
   2070 	}
   2071 	/* end of stuff for bpp < 8 */
   2072 
   2073 	dpy_x = wdpy_x = w;
   2074 	dpy_y = wdpy_y = h;
   2075 	off_x = 0;
   2076 	off_y = 0;
   2077 
   2078 	if (rawfb_dev_video) {
   2079 		if (b == 24) {
   2080 			rfbLog("enabling -24to32 for 24bpp video\n");
   2081 			xform24to32 = 1;
   2082 		} else {
   2083 			if (xform24to32) {
   2084 				rfbLog("disabling -24to32 for 24bpp video\n");
   2085 			}
   2086 			xform24to32 = 0;
   2087 		}
   2088 	}
   2089 
   2090 	if (xform24to32) {
   2091 		if (b != 24) {
   2092 			rfbLog("warning: -24to32 mode and bpp=%d\n", b);
   2093 		}
   2094 		b = 32;
   2095 	}
   2096 	if (strstr(str, "snap:") == str) {
   2097 		use_snapfb = 1;
   2098 		str[0] = 'f'; str[1] = 'i'; str[2] = 'l'; str[3] = 'e';
   2099 	}
   2100 
   2101 	if (strstr(str, "shm:") != str && strstr(str, "mmap:") != str &&
   2102 	    strstr(str, "map:") != str && strstr(str, "file:") != str) {
   2103 		/* hmmm, not following directions, see if map: applies */
   2104 		struct stat sbuf;
   2105 		if (stat(str, &sbuf) == 0) {
   2106 			char *newstr;
   2107 			int len = strlen("map:") + strlen(str) + 1;
   2108 			rfbLog("no type prefix: %s\n", raw_fb_str);
   2109 			rfbLog("  but file exists, so assuming: map:%s\n",
   2110 			    raw_fb_str);
   2111 			newstr = (char *) malloc(len);
   2112 			strcpy(newstr, "map:");
   2113 			strcat(newstr, str);
   2114 			free(str);
   2115 			str = newstr;
   2116 		}
   2117 	}
   2118 
   2119 	if (sscanf(str, "shm:%d", &shmid) == 1) {
   2120 		/* shm:N */
   2121 #if LIBVNCSERVER_HAVE_XSHM || LIBVNCSERVER_HAVE_SHMAT
   2122 		raw_fb_addr = (char *) shmat(shmid, 0, SHM_RDONLY);
   2123 		if (! raw_fb_addr) {
   2124 			rfbLogEnable(1);
   2125 			rfbLog("failed to attach to shm: %d, %s\n", shmid, str);
   2126 			rfbLogPerror("shmat");
   2127 			clean_up_exit(1);
   2128 		}
   2129 		raw_fb_shm = 1;
   2130 		rfbLog("rawfb: shm: %d W: %d H: %d B: %d addr: %p\n",
   2131 		    shmid, w, h, b, raw_fb_addr);
   2132 		last_mode = RAWFB_SHM;
   2133 #else
   2134 		rfbLogEnable(1);
   2135 		rfbLog("x11vnc was compiled without shm support.\n");
   2136 		rfbLogPerror("shmat");
   2137 		clean_up_exit(1);
   2138 #endif
   2139 	} else if (strstr(str, "map:") == str || strstr(str, "mmap:") == str
   2140 	    || strstr(str, "file:") == str) {
   2141 		/* map:/path/... or file:/path  */
   2142 		int fd, do_mmap = 1, size;
   2143 		struct stat sbuf;
   2144 
   2145 		if (*str == 'f') {
   2146 			do_mmap = 0;
   2147 		}
   2148 		q = strchr(str, ':');
   2149 		q++;
   2150 
   2151 		macosx_console = 0;
   2152 		if (strstr(q, "macosx:") == q) {
   2153 			/* mmap:macosx:/dev/null@... */
   2154 			q += strlen("macosx:");
   2155 			do_macosx = 1;
   2156 			do_mmap = 0;
   2157 			macosx_console = 1;
   2158 		}
   2159 
   2160 		last_file = strdup(q);
   2161 
   2162 		fd = raw_fb_fd;
   2163 		if (fd < 0 && rawfb_dev_video) {
   2164 			fd = open(q, O_RDWR);
   2165 		}
   2166 		if (fd < 0) {
   2167 			fd = open(q, O_RDONLY);
   2168 		}
   2169 		if (fd < 0) {
   2170 			rfbLogEnable(1);
   2171 			rfbLog("failed to open file: %s, %s\n", q, str);
   2172 			rfbLogPerror("open");
   2173 			linux_dev_fb_msg(q);
   2174 			clean_up_exit(1);
   2175 		}
   2176 		raw_fb_fd = fd;
   2177 
   2178 		if (raw_fb_native_bpp < 8) {
   2179 			size = w*h*raw_fb_native_bpp/8 + raw_fb_offset;
   2180 		} else if (xform24to32) {
   2181 			size = w*h*24/8 + raw_fb_offset;
   2182 		} else {
   2183 			size = w*h*b/8 + raw_fb_offset;
   2184 		}
   2185 		if (fstat(fd, &sbuf) == 0) {
   2186 			if (S_ISREG(sbuf.st_mode)) {
   2187 				if (0) size = sbuf.st_size;
   2188 			} else {
   2189 				rfbLog("raw fb is non-regular file: %s\n", q);
   2190 			}
   2191 		}
   2192 
   2193 		if (do_macosx) {
   2194 			raw_fb_addr = macosx_get_fb_addr();
   2195 			raw_fb_mmap = size;
   2196 			rfbLog("rawfb: macosx fb: %s\n", q);
   2197 			rfbLog("   w: %d h: %d b: %d addr: %p sz: %d\n", w, h,
   2198 			    b, raw_fb_addr, size);
   2199 			last_mode = 0;
   2200 		} else if (do_reflect) {
   2201 			raw_fb_mmap = size;
   2202 			rfbLog("rawfb: vnc fb: %s\n", q);
   2203 			rfbLog("   w: %d h: %d b: %d addr: %p sz: %d\n", w, h,
   2204 			    b, raw_fb_addr, size);
   2205 			last_mode = 0;
   2206 
   2207 		} else if (do_mmap) {
   2208 #if LIBVNCSERVER_HAVE_MMAP
   2209 			raw_fb_addr = mmap(0, size, PROT_READ, MAP_SHARED,
   2210 			    fd, 0);
   2211 
   2212 			if (raw_fb_addr == MAP_FAILED || raw_fb_addr == NULL) {
   2213 				rfbLogEnable(1);
   2214 				rfbLog("failed to mmap file: %s, %s\n", q, str);
   2215 				rfbLog("   raw_fb_addr: %p\n", raw_fb_addr);
   2216 				rfbLogPerror("mmap");
   2217 
   2218 				raw_fb_addr = NULL;
   2219 				rfbLog("mmap(2) failed, trying slower lseek(2)\n");
   2220 				raw_fb_seek = size;
   2221 				last_mode = RAWFB_FILE;
   2222 
   2223 			} else {
   2224 				raw_fb_mmap = size;
   2225 
   2226 				rfbLog("rawfb: mmap file: %s\n", q);
   2227 				rfbLog("   w: %d h: %d b: %d addr: %p sz: %d\n", w, h,
   2228 				    b, raw_fb_addr, size);
   2229 				last_mode = RAWFB_MMAP;
   2230 			}
   2231 #else
   2232 			rfbLog("mmap(2) not supported on system, using"
   2233 			    " slower lseek(2)\n");
   2234 			raw_fb_seek = size;
   2235 			last_mode = RAWFB_FILE;
   2236 #endif
   2237 		} else {
   2238 			raw_fb_seek = size;
   2239 			last_mode = RAWFB_FILE;
   2240 
   2241 			rfbLog("rawfb: seek file: %s\n", q);
   2242 			rfbLog("   W: %d H: %d B: %d sz: %d\n", w, h, b, size);
   2243 		}
   2244 	} else {
   2245 		rfbLogEnable(1);
   2246 		rfbLog("invalid rawfb str: %s\n", str);
   2247 		clean_up_exit(1);
   2248 	}
   2249 
   2250 	if (unlink_me) {
   2251 		unlink(unlink_me);
   2252 	}
   2253 
   2254 	if (! raw_fb_image) {
   2255 		raw_fb_image = &ximage_struct;
   2256 	}
   2257 
   2258 	initialize_clipshift();
   2259 
   2260 	if (raw_fb_bytes_per_line == 0) {
   2261 		raw_fb_bytes_per_line = dpy_x*b/8;
   2262 
   2263 		/*
   2264 		 * Put cases here were we can determine that
   2265 		 * raw_bytes_per_line != dpy_x*b/8
   2266 		 */
   2267 #ifdef MACOSX
   2268 		if (do_macosx) {
   2269 			raw_fb_bytes_per_line = macosxCG_CGDisplayBytesPerRow();
   2270 		}
   2271 #endif
   2272 	}
   2273 
   2274 	raw_fb_image->bytes_per_line = dpy_x * b/8;
   2275 	raw_fb = (char *) malloc(dpy_y * dpy_x * b/8);
   2276 	raw_fb_image->data = raw_fb;
   2277 	raw_fb_image->format = ZPixmap;
   2278 	raw_fb_image->width  = dpy_x;
   2279 	raw_fb_image->height = dpy_y;
   2280 	raw_fb_image->bits_per_pixel = b;
   2281 	raw_fb_image->bitmap_unit = -1;
   2282 
   2283 
   2284 	if (use_snapfb && (raw_fb_seek || raw_fb_mmap)) {
   2285 		int b_use = b;
   2286 		if (snap_fb) {
   2287 			free(snap_fb);
   2288 		}
   2289 		if (b_use == 32 && xform24to32) {
   2290 			/*
   2291 			 * The actual framebuffer (e.g. mapped addr) and
   2292 			 * snap fb must be the same bpp.  E.g. both 24bpp.
   2293 			 * Reading FROM snap to utility image will be
   2294 			 * transformed 24->32 in copy_raw_fb_24_to_32.
   2295 			 *
   2296 			 * addr -> snap -> (scanline, fullscreen, ...)
   2297 			 */
   2298 			b_use = 24;
   2299 			raw_fb_bytes_per_line = dpy_x * b_use/8;
   2300 		}
   2301 		snap_fb = (char *) malloc(dpy_y * dpy_x * b_use/8);
   2302 		snap = &ximage_struct_snap;
   2303 		snap->data = snap_fb;
   2304 		snap->format = ZPixmap;
   2305 		snap->width  = dpy_x;
   2306 		snap->height = dpy_y;
   2307 		snap->bits_per_pixel = b_use;
   2308 		snap->bytes_per_line = dpy_x * b_use/8;
   2309 		snap->bitmap_unit = -1;
   2310 	}
   2311 
   2312 
   2313 	raw_fb_image->red_mask = rm;
   2314 	raw_fb_image->green_mask = gm;
   2315 	raw_fb_image->blue_mask = bm;
   2316 
   2317 	raw_fb_image->depth = 0;
   2318 	m = 1;
   2319 	for (i=0; i<32; i++)  {
   2320 		if (rm & m) {
   2321 			raw_fb_image->depth++;
   2322 		}
   2323 		if (gm & m) {
   2324 			raw_fb_image->depth++;
   2325 		}
   2326 		if (bm & m) {
   2327 			raw_fb_image->depth++;
   2328 		}
   2329 		m = m << 1;
   2330 	}
   2331 	if (raw_fb_native_bpp < 8) {
   2332 		raw_fb_image->depth = raw_fb_expand_bytes * 8;
   2333 	}
   2334 	if (! raw_fb_image->depth) {
   2335 		raw_fb_image->depth = (b == 32) ? 24 : b;
   2336 	}
   2337 
   2338 	depth = raw_fb_image->depth;
   2339 
   2340 	if (raw_fb_image->depth == 15) {
   2341 		/* unresolved bug with RGB555... */
   2342 		depth++;
   2343 	}
   2344 
   2345 	if (clipshift || raw_fb_native_bpp < 8) {
   2346 		memset(raw_fb, 0xff, dpy_y * raw_fb_image->bytes_per_line);
   2347 	} else if (raw_fb_addr && ! xform24to32) {
   2348 		memcpy(raw_fb, raw_fb_addr + raw_fb_offset, dpy_y * raw_fb_image->bytes_per_line);
   2349 	} else {
   2350 		memset(raw_fb, 0xff, dpy_y * raw_fb_image->bytes_per_line);
   2351 	}
   2352 
   2353 	if (verbose) {
   2354 		rfbLog("\n");
   2355 		rfbLog("rawfb:  raw_fb  %p\n", raw_fb);
   2356 		rfbLog("        format  %d\n", raw_fb_image->format);
   2357 		rfbLog("        width   %d\n", raw_fb_image->width);
   2358 		rfbLog("        height  %d\n", raw_fb_image->height);
   2359 		rfbLog("        bpp     %d\n", raw_fb_image->bits_per_pixel);
   2360 		rfbLog("        depth   %d\n", raw_fb_image->depth);
   2361 		rfbLog("        bpl     %d\n", raw_fb_image->bytes_per_line);
   2362 		if (use_snapfb && snap_fb) {
   2363 			rfbLog("        snap_fb %p\n", snap_fb);
   2364 		}
   2365 	}
   2366 
   2367 	free(str);
   2368 
   2369 	return raw_fb_image;
   2370 }
   2371 
   2372 static void initialize_clipshift(void) {
   2373 	clipshift = 0;
   2374 	cdpy_x = cdpy_y = coff_x = coff_y = 0;
   2375 	if (clip_str) {
   2376 		int w, h, x, y, bad = 0;
   2377 		if (parse_geom(clip_str, &w, &h, &x, &y, wdpy_x, wdpy_y)) {
   2378 			if (x < 0) {
   2379 				x = 0;
   2380 			}
   2381 			if (y < 0) {
   2382 				y = 0;
   2383 			}
   2384 			if (x + w > wdpy_x) {
   2385 				w = wdpy_x - x;
   2386 			}
   2387 			if (y + h > wdpy_y) {
   2388 				h = wdpy_y - y;
   2389 			}
   2390 			if (w <= 0 || h <= 0) {
   2391 				bad = 1;
   2392 			}
   2393 		} else {
   2394 			bad = 1;
   2395 		}
   2396 		if (bad) {
   2397 			rfbLog("*** ignoring invalid -clip WxH+X+Y: %s\n",
   2398 			    clip_str);
   2399 		} else {
   2400 			/* OK, change geom behind everyone's back... */
   2401 			cdpy_x = w;
   2402 			cdpy_y = h;
   2403 			coff_x = x;
   2404 			coff_y = y;
   2405 
   2406 			clipshift = 1;
   2407 
   2408 			dpy_x = cdpy_x;
   2409 			dpy_y = cdpy_y;
   2410 		}
   2411 	}
   2412 }
   2413 
   2414 static int wait_until_mapped(Window win) {
   2415 #if NO_X11
   2416 	if (!win) {}
   2417 	return 0;
   2418 #else
   2419 	int ms = 50, waittime = 30;
   2420 	time_t start = time(NULL);
   2421 	XWindowAttributes attr;
   2422 
   2423 	while (1) {
   2424 		if (! valid_window(win, NULL, 0)) {
   2425 			if (time(NULL) > start + waittime) {
   2426 				break;
   2427 			}
   2428 			usleep(ms * 1000);
   2429 			continue;
   2430 		}
   2431 		if (dpy && ! XGetWindowAttributes(dpy, win, &attr)) {
   2432 			return 0;
   2433 		}
   2434 		if (attr.map_state == IsViewable) {
   2435 			return 1;
   2436 		}
   2437 		usleep(ms * 1000);
   2438 	}
   2439 	return 0;
   2440 #endif	/* NO_X11 */
   2441 }
   2442 
   2443 /*
   2444  * initialize a fb for the X display
   2445  */
   2446 XImage *initialize_xdisplay_fb(void) {
   2447 #if NO_X11
   2448 	if (raw_fb_str) {
   2449 		return initialize_raw_fb(0);
   2450 	}
   2451 	return NULL;
   2452 #else
   2453 	XImage *fb;
   2454 	char *vis_str = visual_str;
   2455 	int try = 0, subwin_tries = 3;
   2456 	XErrorHandler old_handler = NULL;
   2457 	int subwin_bs;
   2458 
   2459 	if (raw_fb_str) {
   2460 		return initialize_raw_fb(0);
   2461 	}
   2462 
   2463 	X_LOCK;
   2464 	if (subwin) {
   2465 		if (subwin_wait_mapped) {
   2466 			wait_until_mapped(subwin);
   2467 		}
   2468 		if (!valid_window((Window) subwin, NULL, 0)) {
   2469 			rfbLogEnable(1);
   2470 			rfbLog("invalid sub-window: 0x%lx\n", subwin);
   2471 			X_UNLOCK;
   2472 			clean_up_exit(1);
   2473 		}
   2474 	}
   2475 
   2476 	if (overlay) {
   2477 		/*
   2478 		 * ideally we'd like to not have to cook up the
   2479 		 * visual variables but rather let it all come out
   2480 		 * of XReadScreen(), however there is no way to get
   2481 		 * a default visual out of it, so we pretend -visual
   2482 		 * TrueColor:NN was supplied with NN usually 24.
   2483 		 */
   2484 		char str[32];
   2485 		Window twin = subwin ? subwin : rootwin;
   2486 		XImage *xi;
   2487 
   2488 		xi = xreadscreen(dpy, twin, 0, 0, 8, 8, False);
   2489 		sprintf(str, "TrueColor:%d", xi->depth);
   2490 		if (xi->depth != 24 && ! quiet) {
   2491 			rfbLog("warning: overlay image has depth %d "
   2492 			    "instead of 24.\n", xi->depth);
   2493 		}
   2494 		XDestroyImage(xi);
   2495 		if (visual_str != NULL && ! quiet) {
   2496 			rfbLog("warning: replacing '-visual %s' by '%s' "
   2497 			    "for use with -overlay\n", visual_str, str);
   2498 		}
   2499 		vis_str = strdup(str);
   2500 	}
   2501 
   2502 	if (xform24to32) {
   2503 		if (DefaultDepth(dpy, scr) == 24) {
   2504 			vis_str = strdup("TrueColor:32");
   2505 			rfbLog("initialize_xdisplay_fb: vis_str set to: %s\n",
   2506 			    vis_str);
   2507 			visual_id = (VisualID) 0;
   2508 			visual_depth = 0;
   2509 			set_visual_str_to_something = 1;
   2510 		}
   2511 	} else if (DefaultDepth(dpy, scr) < 8) {
   2512 		/* check very low bpp case, e.g. mono or vga16 */
   2513 		Screen *s = DefaultScreenOfDisplay(dpy);
   2514 		XImage *xi = XGetImage_wr(dpy, DefaultRootWindow(dpy), 0, 0, 2, 2, AllPlanes,
   2515 		    ZPixmap);
   2516 		if (xi && xi->bits_per_pixel < 8) {
   2517 			int lowbpp = xi->bits_per_pixel;
   2518 			if (!vis_str) {
   2519 				char tmp[32];
   2520 				sprintf(tmp, "0x%x:8", (int) s->root_visual->visualid);
   2521 				vis_str = strdup(tmp);
   2522 				rfbLog("initialize_xdisplay_fb: low bpp[%d], vis_str "
   2523 				    "set to: %s\n", lowbpp, vis_str);
   2524 			}
   2525 			if (using_shm) {
   2526 				using_shm = 0;
   2527 				rfbLog("initialize_xdisplay_fb: low bpp[%d], "
   2528 				    "disabling shm\n", lowbpp);
   2529 			}
   2530 			visual_id = (VisualID) 0;
   2531 			visual_depth = 0;
   2532 			set_visual_str_to_something = 1;
   2533 		}
   2534 		if (xi) {
   2535 			XDestroyImage(xi);
   2536 		}
   2537 	}
   2538 
   2539 	if (vis_str != NULL) {
   2540 		set_visual(vis_str);
   2541 		if (vis_str != visual_str) {
   2542 			free(vis_str);
   2543 		}
   2544 	}
   2545 if (0) fprintf(stderr, "vis_str %s\n", vis_str ? vis_str : "notset");
   2546 
   2547 	/* set up parameters for subwin or non-subwin cases: */
   2548 
   2549 	again:
   2550 
   2551 	if (! subwin) {
   2552 		/* full screen */
   2553 		window = rootwin;
   2554 		dpy_x = wdpy_x = DisplayWidth(dpy, scr);
   2555 		dpy_y = wdpy_y = DisplayHeight(dpy, scr);
   2556 		off_x = 0;
   2557 		off_y = 0;
   2558 		/* this may be overridden via visual_id below */
   2559 		default_visual = DefaultVisual(dpy, scr);
   2560 	} else {
   2561 		/* single window */
   2562 		XWindowAttributes attr;
   2563 
   2564 		window = (Window) subwin;
   2565 		if (! XGetWindowAttributes(dpy, window, &attr)) {
   2566 			rfbLogEnable(1);
   2567 			rfbLog("invalid window: 0x%lx\n", window);
   2568 			X_UNLOCK;
   2569 			clean_up_exit(1);
   2570 		}
   2571 		dpy_x = wdpy_x = attr.width;
   2572 		dpy_y = wdpy_y = attr.height;
   2573 
   2574 		subwin_bs = attr.backing_store;
   2575 
   2576 		/* this may be overridden via visual_id below */
   2577 		default_visual = attr.visual;
   2578 
   2579 		X_UNLOCK;
   2580 		set_offset();
   2581 		X_LOCK;
   2582 	}
   2583 
   2584 	initialize_clipshift();
   2585 
   2586 	/* initialize depth to reasonable value, visual_id may override */
   2587 	depth = DefaultDepth(dpy, scr);
   2588 
   2589 if (0) fprintf(stderr, "DefaultDepth: %d  visial_id: %d\n", depth, (int) visual_id);
   2590 
   2591 	if (visual_id) {
   2592 		int n;
   2593 		XVisualInfo vinfo_tmpl, *vinfo;
   2594 
   2595 		/*
   2596 		 * we are in here from -visual or -overlay options
   2597 		 * visual_id and visual_depth were set in set_visual().
   2598 		 */
   2599 
   2600 		vinfo_tmpl.visualid = visual_id;
   2601 		vinfo = XGetVisualInfo(dpy, VisualIDMask, &vinfo_tmpl, &n);
   2602 		if (vinfo == NULL || n == 0) {
   2603 			rfbLogEnable(1);
   2604 			rfbLog("could not match visual_id: 0x%x\n",
   2605 			    (int) visual_id);
   2606 			X_UNLOCK;
   2607 			clean_up_exit(1);
   2608 		}
   2609 		default_visual = vinfo->visual;
   2610 		depth = vinfo->depth;
   2611 		if (visual_depth) {
   2612 			/* force it from -visual MooColor:NN */
   2613 			depth = visual_depth;
   2614 		}
   2615 		if (! quiet) {
   2616 			fprintf(stderr, " initialize_xdisplay_fb()\n");
   2617 			fprintf(stderr, " Visual*:    %p\n",
   2618 			    (void *) vinfo->visual);
   2619 			fprintf(stderr, " visualid:   0x%x\n",
   2620 			    (int) vinfo->visualid);
   2621 			fprintf(stderr, " screen:     %d\n", vinfo->screen);
   2622 			fprintf(stderr, " depth:      %d\n", vinfo->depth);
   2623 			fprintf(stderr, " class:      %d\n", vinfo->class);
   2624 			fprintf(stderr, " red_mask:   0x%08lx  %s\n",
   2625 			    vinfo->red_mask, bitprint(vinfo->red_mask, 32));
   2626 			fprintf(stderr, " green_mask: 0x%08lx  %s\n",
   2627 			    vinfo->green_mask, bitprint(vinfo->green_mask, 32));
   2628 			fprintf(stderr, " blue_mask:  0x%08lx  %s\n",
   2629 			    vinfo->blue_mask, bitprint(vinfo->blue_mask, 32));
   2630 			fprintf(stderr, " cmap_size:  %d\n",
   2631 			    vinfo->colormap_size);
   2632 			fprintf(stderr, " bits b/rgb: %d\n",
   2633 			    vinfo->bits_per_rgb);
   2634 			fprintf(stderr, "\n");
   2635 		}
   2636 		XFree_wr(vinfo);
   2637 	}
   2638 
   2639 	if (! quiet) {
   2640 		rfbLog("Default visual ID: 0x%x\n",
   2641 		    (int) XVisualIDFromVisual(default_visual));
   2642 	}
   2643 
   2644 	if (subwin) {
   2645 		int shift = 0, resize = 0;
   2646 		int subwin_x, subwin_y;
   2647 		int disp_x = DisplayWidth(dpy, scr);
   2648 		int disp_y = DisplayHeight(dpy, scr);
   2649 		Window twin;
   2650 		/* subwins can be a dicey if they are changing size... */
   2651 		trapped_xerror = 0;
   2652 		old_handler = XSetErrorHandler(trap_xerror);	/* reset in if(subwin) block below */
   2653 		XTranslateCoordinates(dpy, window, rootwin, 0, 0, &subwin_x,
   2654 		    &subwin_y, &twin);
   2655 
   2656 		if (wdpy_x > disp_x) {
   2657 			resize = 1;
   2658 			dpy_x = wdpy_x = disp_x - 4;
   2659 		}
   2660 		if (wdpy_y > disp_y) {
   2661 			resize = 1;
   2662 			dpy_y = wdpy_y = disp_y - 4;
   2663 		}
   2664 
   2665 		if (subwin_x + wdpy_x > disp_x) {
   2666 			shift = 1;
   2667 			subwin_x = disp_x - wdpy_x - 3;
   2668 		}
   2669 		if (subwin_y + wdpy_y > disp_y) {
   2670 			shift = 1;
   2671 			subwin_y = disp_y - wdpy_y - 3;
   2672 		}
   2673 		if (subwin_x < 0) {
   2674 			shift = 1;
   2675 			subwin_x = 1;
   2676 		}
   2677 		if (subwin_y < 0) {
   2678 			shift = 1;
   2679 			subwin_y = 1;
   2680 		}
   2681 
   2682 		if (resize) {
   2683 			XResizeWindow(dpy, window, wdpy_x, wdpy_y);
   2684 		}
   2685 		if (shift) {
   2686 			XMoveWindow(dpy, window, subwin_x, subwin_y);
   2687 			off_x = subwin_x;
   2688 			off_y = subwin_y;
   2689 		}
   2690 		XMapRaised(dpy, window);
   2691 		XRaiseWindow(dpy, window);
   2692 		XSync(dpy, False);
   2693 	}
   2694 	try++;
   2695 
   2696 	if (nofb) {
   2697 		/*
   2698 		 * For -nofb we do not allocate the framebuffer, so we
   2699 		 * can save a few MB of memory.
   2700 		 */
   2701 		fb = XCreateImage_wr(dpy, default_visual, depth, ZPixmap,
   2702 		    0, NULL, dpy_x, dpy_y, BitmapPad(dpy), 0);
   2703 
   2704 	} else if (visual_id) {
   2705 		/*
   2706 		 * we need to call XCreateImage to supply the visual
   2707 		 */
   2708 		fb = XCreateImage_wr(dpy, default_visual, depth, ZPixmap,
   2709 		    0, NULL, dpy_x, dpy_y, BitmapPad(dpy), 0);
   2710 		if (fb) {
   2711 			fb->data = (char *) malloc(fb->bytes_per_line * fb->height);
   2712 		}
   2713 
   2714 	} else {
   2715 		fb = XGetImage_wr(dpy, window, 0, 0, dpy_x, dpy_y, AllPlanes,
   2716 		    ZPixmap);
   2717 		if (! quiet) {
   2718 			rfbLog("Read initial data from X display into"
   2719 			    " framebuffer.\n");
   2720 		}
   2721 	}
   2722 
   2723 	if (subwin) {
   2724 		XSetErrorHandler(old_handler);
   2725 		if (trapped_xerror || fb == NULL) {
   2726 		    rfbLog("trapped GetImage at SUBWIN creation.\n");
   2727 		    if (try < subwin_tries) {
   2728 			usleep(250 * 1000);
   2729 			if (!get_window_size(window, &wdpy_x, &wdpy_y)) {
   2730 				rfbLogEnable(1);
   2731 				rfbLog("could not get size of subwin "
   2732 				    "0x%lx\n", subwin);
   2733 				X_UNLOCK;
   2734 				clean_up_exit(1);
   2735 			}
   2736 			goto again;
   2737 		    }
   2738 		}
   2739 		trapped_xerror = 0;
   2740 
   2741 	} else if (fb == NULL) {
   2742 		XEvent xev;
   2743 		rfbLog("initialize_xdisplay_fb: *** fb creation failed: 0x%x try: %d\n", fb, try);
   2744 #if LIBVNCSERVER_HAVE_LIBXRANDR
   2745 		if (xrandr_present && xrandr_base_event_type) {
   2746 			int cnt = 0;
   2747 			while (XCheckTypedEvent(dpy, xrandr_base_event_type + RRScreenChangeNotify, &xev)) {
   2748 				XRRScreenChangeNotifyEvent *rev;
   2749 				rev = (XRRScreenChangeNotifyEvent *) &xev;
   2750 
   2751 				rfbLog("initialize_xdisplay_fb: XRANDR event while redoing fb[%d]:\n", cnt++);
   2752 				rfbLog("  serial:          %d\n", (int) rev->serial);
   2753 				rfbLog("  timestamp:       %d\n", (int) rev->timestamp);
   2754 				rfbLog("  cfg_timestamp:   %d\n", (int) rev->config_timestamp);
   2755 				rfbLog("  size_id:         %d\n", (int) rev->size_index);
   2756 				rfbLog("  sub_pixel:       %d\n", (int) rev->subpixel_order);
   2757 				rfbLog("  rotation:        %d\n", (int) rev->rotation);
   2758 				rfbLog("  width:           %d\n", (int) rev->width);
   2759 				rfbLog("  height:          %d\n", (int) rev->height);
   2760 				rfbLog("  mwidth:          %d mm\n", (int) rev->mwidth);
   2761 				rfbLog("  mheight:         %d mm\n", (int) rev->mheight);
   2762 				rfbLog("\n");
   2763 				rfbLog("previous WxH: %dx%d\n", wdpy_x, wdpy_y);
   2764 
   2765 				xrandr_width  = rev->width;
   2766 				xrandr_height = rev->height;
   2767 				xrandr_timestamp = rev->timestamp;
   2768 				xrandr_cfg_time  = rev->config_timestamp;
   2769 				xrandr_rotation = (int) rev->rotation;
   2770 
   2771 				rfbLog("initialize_xdisplay_fb: updating XRANDR config...\n");
   2772 				XRRUpdateConfiguration(&xev);
   2773 			}
   2774 		}
   2775 #endif
   2776 		if (try < 5)  {
   2777 			XFlush_wr(dpy);
   2778 			usleep(250 * 1000);
   2779 			if (try < 3) {
   2780 				XSync(dpy, False);
   2781 			} else if (try >= 3) {
   2782 				XSync(dpy, True);
   2783 			}
   2784 			goto again;
   2785 		}
   2786 	}
   2787 	if (use_snapfb) {
   2788 		initialize_snap_fb();
   2789 	}
   2790 
   2791 	X_UNLOCK;
   2792 
   2793 	if (fb->bits_per_pixel == 24 && ! quiet) {
   2794 		rfbLog("warning: 24 bpp may have poor performance.\n");
   2795 	}
   2796 	return fb;
   2797 #endif	/* NO_X11 */
   2798 }
   2799 
   2800 void parse_scale_string(char *str, double *factor_x, double *factor_y, int *scaling, int *blend,
   2801     int *nomult4, int *pad, int *interpolate, int *numer, int *denom, int w_in, int h_in) {
   2802 
   2803 	int m, n;
   2804 	char *p, *tstr;
   2805 	double f, f2;
   2806 
   2807 	*factor_x = 1.0;
   2808 	*factor_y = 1.0;
   2809 	*scaling = 0;
   2810 	*blend = 1;
   2811 	*nomult4 = 0;
   2812 	*pad = 0;
   2813 	*interpolate = 0;
   2814 	*numer = 0, *denom = 0;
   2815 
   2816 	if (str == NULL || str[0] == '\0') {
   2817 		return;
   2818 	}
   2819 	tstr = strdup(str);
   2820 
   2821 	if ( (p = strchr(tstr, ':')) != NULL) {
   2822 		/* options */
   2823 		if (strstr(p+1, "nb") != NULL) {
   2824 			*blend = 0;
   2825 		}
   2826 		if (strstr(p+1, "fb") != NULL) {
   2827 			*blend = 2;
   2828 		}
   2829 		if (strstr(p+1, "n4") != NULL) {
   2830 			*nomult4 = 1;
   2831 		}
   2832 		if (strstr(p+1, "in") != NULL) {
   2833 			*interpolate = 1;
   2834 		}
   2835 		if (strstr(p+1, "pad") != NULL) {
   2836 			*pad = 1;
   2837 		}
   2838 		if (strstr(p+1, "nocr") != NULL) {
   2839 			/* global */
   2840 			scaling_copyrect = 0;
   2841 		} else if (strstr(p+1, "cr") != NULL) {
   2842 			/* global */
   2843 			scaling_copyrect = 1;
   2844 		}
   2845 		*p = '\0';
   2846 	}
   2847 
   2848 	if (strchr(tstr, '.') != NULL) {
   2849 		double test, diff, eps = 1.0e-7;
   2850 		if (sscanf(tstr, "%lfx%lf", &f, &f2) == 2) {
   2851 			*factor_x = (double) f;
   2852 			*factor_y = (double) f2;
   2853 		} else if (sscanf(tstr, "%lf", &f) != 1) {
   2854 			rfbLogEnable(1);
   2855 			rfbLog("invalid -scale arg: %s\n", tstr);
   2856 			clean_up_exit(1);
   2857 		} else {
   2858 			*factor_x = (double) f;
   2859 			*factor_y = (double) f;
   2860 		}
   2861 		/* look for common fractions from small ints: */
   2862 		if (*factor_x == *factor_y) {
   2863 			for (n=2; n<=10; n++) {
   2864 				for (m=1; m<n; m++) {
   2865 					test = ((double) m)/ n;
   2866 					diff = *factor_x - test;
   2867 					if (-eps < diff && diff < eps) {
   2868 						*numer = m;
   2869 						*denom = n;
   2870 						break;
   2871 
   2872 					}
   2873 				}
   2874 				if (*denom) {
   2875 					break;
   2876 				}
   2877 			}
   2878 			if (*factor_x < 0.01) {
   2879 				rfbLogEnable(1);
   2880 				rfbLog("-scale factor too small: %f\n", *factor_x);
   2881 				clean_up_exit(1);
   2882 			}
   2883 		}
   2884 	} else if (sscanf(tstr, "%dx%d", &m, &n) == 2 && w_in > 0 && h_in > 0) {
   2885 		*factor_x = ((double) m) / ((double) w_in);
   2886 		*factor_y = ((double) n) / ((double) h_in);
   2887 	} else {
   2888 		if (sscanf(tstr, "%d/%d", &m, &n) != 2) {
   2889 			if (sscanf(tstr, "%d", &m) != 1) {
   2890 				rfbLogEnable(1);
   2891 				rfbLog("invalid -scale arg: %s\n", tstr);
   2892 				clean_up_exit(1);
   2893 			} else {
   2894 				/* e.g. -scale 1 or -scale 2 */
   2895 				n = 1;
   2896 			}
   2897 		}
   2898 		if (n <= 0 || m <=0) {
   2899 			rfbLogEnable(1);
   2900 			rfbLog("invalid -scale arg: %s\n", tstr);
   2901 			clean_up_exit(1);
   2902 		}
   2903 		*factor_x = ((double) m)/ n;
   2904 		*factor_y = ((double) m)/ n;
   2905 		if (*factor_x < 0.01) {
   2906 			rfbLogEnable(1);
   2907 			rfbLog("-scale factor too small: %f\n", *factor_x);
   2908 			clean_up_exit(1);
   2909 		}
   2910 		*numer = m;
   2911 		*denom = n;
   2912 	}
   2913 	if (*factor_x == 1.0 && *factor_y == 1.0) {
   2914 		if (! quiet) {
   2915 			rfbLog("scaling disabled for factor %f %f\n", *factor_x, *factor_y);
   2916 		}
   2917 	} else {
   2918 		*scaling = 1;
   2919 	}
   2920 	free(tstr);
   2921 }
   2922 
   2923 int parse_rotate_string(char *str, int *mode) {
   2924 	int m = ROTATE_NONE;
   2925 	if (str == NULL || !strcmp(str, "") || !strcmp(str, "0")) {
   2926 		m = ROTATE_NONE;
   2927 	} else if (!strcmp(str, "x")) {
   2928 		m = ROTATE_X;
   2929 	} else if (!strcmp(str, "y")) {
   2930 		m = ROTATE_Y;
   2931 	} else if (!strcmp(str, "xy") || !strcmp(str, "yx") ||
   2932 	    !strcmp(str,"+180") || !strcmp(str,"-180") || !strcmp(str,"180")) {
   2933 		m = ROTATE_XY;
   2934 	} else if (!strcmp(str, "+90") || !strcmp(str, "90")) {
   2935 		m = ROTATE_90;
   2936 	} else if (!strcmp(str, "+90x") || !strcmp(str, "90x")) {
   2937 		m = ROTATE_90X;
   2938 	} else if (!strcmp(str, "+90y") || !strcmp(str, "90y")) {
   2939 		m = ROTATE_90Y;
   2940 	} else if (!strcmp(str, "-90") || !strcmp(str, "270") ||
   2941 	    !strcmp(str, "+270")) {
   2942 		m = ROTATE_270;
   2943 	} else {
   2944 		rfbLog("invalid -rotate mode: %s\n", str);
   2945 	}
   2946 	if (mode) {
   2947 		*mode = m;
   2948 	}
   2949 	return m;
   2950 }
   2951 
   2952 int scale_round(int len, double fac) {
   2953 	double eps = 0.000001;
   2954 
   2955 	len = (int) (len * fac + eps);
   2956 	if (len < 1) {
   2957 		len = 1;
   2958 	}
   2959 	return len;
   2960 }
   2961 
   2962 static void setup_scaling(int *width_in, int *height_in) {
   2963 	int width  = *width_in;
   2964 	int height = *height_in;
   2965 
   2966 	parse_scale_string(scale_str, &scale_fac_x, &scale_fac_y, &scaling, &scaling_blend,
   2967 	    &scaling_nomult4, &scaling_pad, &scaling_interpolate,
   2968 	    &scale_numer, &scale_denom, *width_in, *height_in);
   2969 
   2970 	if (scaling) {
   2971 		width  = scale_round(width,  scale_fac_x);
   2972 		height = scale_round(height, scale_fac_y);
   2973 		if (scale_denom && scaling_pad) {
   2974 			/* it is not clear this padding is useful anymore */
   2975 			rfbLog("width  %% denom: %d %% %d = %d\n", width,
   2976 			    scale_denom, width  % scale_denom);
   2977 			rfbLog("height %% denom: %d %% %d = %d\n", height,
   2978 			    scale_denom, height % scale_denom);
   2979 			if (width % scale_denom != 0) {
   2980 				int w = width;
   2981 				w += scale_denom - (w % scale_denom);
   2982 				if (!scaling_nomult4 && w % 4 != 0) {
   2983 					/* need to make mult of 4 as well */
   2984 					int c = 0;
   2985 					while (w % 4 != 0 && c++ <= 5) {
   2986 						w += scale_denom;
   2987 					}
   2988 				}
   2989 				width = w;
   2990 				rfbLog("padded width  to: %d (mult of %d%s\n",
   2991 				    width, scale_denom, !scaling_nomult4 ?
   2992 				    " and 4)" : ")");
   2993 			}
   2994 			if (height % scale_denom != 0) {
   2995 				height += scale_denom - (height % scale_denom);
   2996 				rfbLog("padded height to: %d (mult of %d)\n",
   2997 				    height, scale_denom);
   2998 			}
   2999 		}
   3000 		if (!scaling_nomult4 && width % 4 != 0 && width > 2) {
   3001 			/* reset width to be multiple of 4 */
   3002 			int width0 = width;
   3003 			if ((width+1) % 4 == 0) {
   3004 				width = width+1;
   3005 			} else if ((width-1) % 4 == 0) {
   3006 				width = width-1;
   3007 			} else if ((width+2) % 4 == 0) {
   3008 				width = width+2;
   3009 			}
   3010 			rfbLog("reset scaled width %d -> %d to be a multiple of"
   3011 			    " 4 (to\n", width0, width);
   3012 			rfbLog("make vncviewers happy). use -scale m/n:n4 to "
   3013 			    "disable.\n");
   3014 		}
   3015 		scaled_x = width;
   3016 		scaled_y = height;
   3017 
   3018 		*width_in  = width;
   3019 		*height_in = height;
   3020 	}
   3021 }
   3022 
   3023 static void setup_rotating(void) {
   3024 	char *rs = rotating_str;
   3025 
   3026 	rotating_cursors = 1;
   3027 	if (rs && strstr(rs, "nc:") == rs) {
   3028 		rs += strlen("nc:");
   3029 		rotating_cursors = 0;
   3030 	}
   3031 
   3032 	rotating = parse_rotate_string(rs, NULL);
   3033 	if (! rotating) {
   3034 		rotating_cursors = 0;
   3035 	}
   3036 
   3037 	if (rotating == ROTATE_90  || rotating == ROTATE_90X ||
   3038 	    rotating == ROTATE_90Y || rotating == ROTATE_270) {
   3039 		rotating_same = 0;
   3040 	} else {
   3041 		rotating_same = 1;
   3042 	}
   3043 }
   3044 
   3045 static rfbBool set_xlate_wrapper(rfbClientPtr cl) {
   3046 	static int first = 1;
   3047 	if (first) {
   3048 		first = 0;
   3049 	} else if (ncache) {
   3050 		int save = ncache_xrootpmap;
   3051 		rfbLog("set_xlate_wrapper: clearing -ncache for new pixel format.\n");
   3052 		INPUT_LOCK;
   3053 		ncache_xrootpmap = 0;
   3054 		check_ncache(1, 0);
   3055 		ncache_xrootpmap = save;
   3056 		INPUT_UNLOCK;
   3057 	}
   3058 	return rfbSetTranslateFunction(cl);
   3059 }
   3060 
   3061 /*
   3062  * initialize the rfb framebuffer/screen
   3063  */
   3064 void initialize_screen(int *argc, char **argv, XImage *fb) {
   3065 	int have_masks = 0;
   3066 	int width  = fb->width;
   3067 	int height = fb->height;
   3068 	int create_screen = screen ? 0 : 1;
   3069 	int bits_per_color;
   3070 	int fb_bpp, fb_Bpl, fb_depth;
   3071 	int locked_sends = 0;
   3072 
   3073 	bpp = fb->bits_per_pixel;
   3074 
   3075 	fb_bpp   = (int) fb->bits_per_pixel;
   3076 	fb_Bpl   = (int) fb->bytes_per_line;
   3077 	fb_depth = (int) fb->depth;
   3078 
   3079 	rfbLog("initialize_screen: fb_depth/fb_bpp/fb_Bpl %d/%d/%d\n", fb_depth,
   3080 	    fb_bpp, fb_Bpl);
   3081 
   3082 	main_bytes_per_line = fb->bytes_per_line;
   3083 
   3084 	if (cmap8to24) {
   3085 		if (raw_fb) {
   3086 			if (!quiet) rfbLog("disabling -8to24 mode"
   3087 			    " in raw_fb mode.\n");
   3088 			cmap8to24 = 0;
   3089 		} else if (depth == 24) {
   3090 			if (fb_bpp != 32)  {
   3091 				if (!quiet) rfbLog("disabling -8to24 mode:"
   3092 				    " bpp != 32 with depth == 24\n");
   3093 				cmap8to24 = 0;
   3094 			}
   3095 		} else if (depth <= 16) {
   3096 			/* need to cook up the screen fb to be depth 24 */
   3097 			fb_bpp = 32;
   3098 			fb_depth = 24;
   3099 		} else {
   3100 			if (!quiet) rfbLog("disabling -8to24 mode:"
   3101 			    " default depth not 16 or less\n");
   3102 			cmap8to24 = 0;
   3103 		}
   3104 	}
   3105 
   3106 	setup_scaling(&width, &height);
   3107 
   3108 	if (scaling) {
   3109 		rfbLog("scaling screen: %dx%d -> %dx%d\n", fb->width, fb->height, scaled_x, scaled_y);
   3110 		rfbLog("scaling screen: scale_fac_x=%.5f scale_fac_y=%.5f\n", scale_fac_x, scale_fac_y);
   3111 
   3112 		rfb_bytes_per_line = (main_bytes_per_line / fb->width) * width;
   3113 	} else {
   3114 		rfb_bytes_per_line = main_bytes_per_line;
   3115 	}
   3116 
   3117 	setup_rotating();
   3118 
   3119 	if (rotating) {
   3120 		if (! rotating_same) {
   3121 			int t, b = main_bytes_per_line / fb->width;
   3122 			if (scaling) {
   3123 				rot_bytes_per_line = b * height;
   3124 			} else {
   3125 				rot_bytes_per_line = b * fb->height;
   3126 			}
   3127 			t = width;
   3128 			width = height;		/* The big swap... */
   3129 			height = t;
   3130 		} else {
   3131 			rot_bytes_per_line = rfb_bytes_per_line;
   3132 		}
   3133 	}
   3134 
   3135 #ifndef NO_NCACHE
   3136 	if (ncache > 0 && !nofb) {
   3137 # ifdef MACOSX
   3138 		if (! raw_fb_str || macosx_console) {
   3139 # else
   3140 		if (! raw_fb_str) {
   3141 # endif
   3142 
   3143 			char *new_fb;
   3144 			int sz = fb->height * fb->bytes_per_line;
   3145 			int ns = 1+ncache;
   3146 
   3147 			if (ncache_xrootpmap) {
   3148 				ns++;
   3149 			}
   3150 
   3151 			new_fb = (char *) calloc((size_t) (sz * ns), 1);
   3152 			if (fb->data) {
   3153 				memcpy(new_fb, fb->data, sz);
   3154 				free(fb->data);
   3155 			}
   3156 			fb->data = new_fb;
   3157 			fb->height *= (ns);
   3158 			height *= (ns);
   3159 			ncache0 = ncache;
   3160 		}
   3161 	}
   3162 #endif
   3163 
   3164 	if (cmap8to24) {
   3165 		if (depth <= 8) {
   3166 			rfb_bytes_per_line *= 4;
   3167 			rot_bytes_per_line *= 4;
   3168 		} else if (depth <= 16) {
   3169 			rfb_bytes_per_line *= 2;
   3170 			rot_bytes_per_line *= 2;
   3171 		}
   3172 	}
   3173 
   3174 	/*
   3175 	 * These are just hints wrt pixel format just to let
   3176 	 * rfbGetScreen/rfbNewFramebuffer proceed with reasonable
   3177 	 * defaults.  We manually set them in painful detail below.
   3178 	 */
   3179 	bits_per_color = guess_bits_per_color(fb_bpp);
   3180 
   3181 	if (lock_client_sends(-1) == 0) {
   3182 		lock_client_sends(1);
   3183 		locked_sends = 1;
   3184 	}
   3185 
   3186 	/* n.b. samplesPerPixel (set = 1 here) seems to be unused. */
   3187 	if (create_screen) {
   3188 		if (use_stunnel) {
   3189 			setup_stunnel(0, argc, argv);
   3190 		}
   3191 		if (use_openssl) {
   3192 			if (use_stunnel && enc_str && !strcmp(enc_str, "none")) {
   3193 				/* emulating HTTPS oneport */
   3194 				;
   3195 			} else {
   3196 				openssl_init(0);
   3197 			}
   3198 		}
   3199 		screen = rfbGetScreen(argc, argv, width, height,
   3200 		    bits_per_color, 1, fb_bpp/8);
   3201 		if (screen && http_dir) {
   3202 			http_connections(1);
   3203 		}
   3204 		if (unix_sock) {
   3205 			unix_sock_fd = listen_unix(unix_sock);
   3206 		}
   3207 	} else {
   3208 		/* set set frameBuffer member below. */
   3209 		rfbLog("rfbNewFramebuffer(0x%x, 0x%x, %d, %d, %d, %d, %d)\n",
   3210 		    screen, NULL, width, height, bits_per_color, 1, fb_bpp/8);
   3211 
   3212 		/* these are probably overwritten, but just to be safe: */
   3213 		screen->bitsPerPixel = fb_bpp;
   3214 		screen->depth = fb_depth;
   3215 
   3216 		rfb_new_framebuffer(screen, NULL, width, height,
   3217 		    bits_per_color, 1, (int) fb_bpp/8);
   3218 	}
   3219 	if (! screen) {
   3220 		int i;
   3221 		rfbLogEnable(1);
   3222 		rfbLog("\n");
   3223 		rfbLog("failed to create rfb screen.\n");
   3224 		for (i=0; i< *argc; i++)  {
   3225 			rfbLog("\t[%d]  %s\n", i, argv[i]);
   3226 		}
   3227 		clean_up_exit(1);
   3228 	}
   3229 
   3230 	if (create_screen && *argc != 1) {
   3231 		int i;
   3232 		rfbLogEnable(1);
   3233 		rfbLog("*** unrecognized option(s) ***\n");
   3234 		for (i=1; i< *argc; i++)  {
   3235 			rfbLog("\t[%d]  %s\n", i, argv[i]);
   3236 		}
   3237 		rfbLog("For a list of options run: x11vnc -opts\n");
   3238 		rfbLog("or for the full help: x11vnc -help\n");
   3239 		rfbLog("\n");
   3240 		rfbLog("Here is a list of removed or obsolete"
   3241 		    " options:\n");
   3242 		rfbLog("\n");
   3243 		rfbLog("removed: -hints, -nohints\n");
   3244 		rfbLog("removed: -cursorposall\n");
   3245 		rfbLog("removed: -nofilexfer, now the default.\n");
   3246 		rfbLog("\n");
   3247 		rfbLog("renamed: -old_copytile, use -onetile\n");
   3248 		rfbLog("renamed: -mouse,   use -cursor\n");
   3249 		rfbLog("renamed: -mouseX,  use -cursor X\n");
   3250 		rfbLog("renamed: -X,       use -cursor X\n");
   3251 		rfbLog("renamed: -nomouse, use -nocursor\n");
   3252 		rfbLog("renamed: -old_pointer, use -pointer_mode 1\n");
   3253 
   3254 		clean_up_exit(1);
   3255 	}
   3256 
   3257 	/* set up format from scratch: */
   3258 	if (rotating && ! rotating_same) {
   3259 		screen->paddedWidthInBytes = rot_bytes_per_line;
   3260 	} else {
   3261 		screen->paddedWidthInBytes = rfb_bytes_per_line;
   3262 	}
   3263 	screen->serverFormat.bitsPerPixel = fb_bpp;
   3264 	screen->serverFormat.depth = fb_depth;
   3265 	screen->serverFormat.trueColour = TRUE;
   3266 
   3267 	screen->serverFormat.redShift   = 0;
   3268 	screen->serverFormat.greenShift = 0;
   3269 	screen->serverFormat.blueShift  = 0;
   3270 	screen->serverFormat.redMax     = 0;
   3271 	screen->serverFormat.greenMax   = 0;
   3272 	screen->serverFormat.blueMax    = 0;
   3273 
   3274 	/* these main_* formats are used generally. */
   3275 	main_red_shift   = 0;
   3276 	main_green_shift = 0;
   3277 	main_blue_shift  = 0;
   3278 	main_red_max     = 0;
   3279 	main_green_max   = 0;
   3280 	main_blue_max    = 0;
   3281 	main_red_mask    = fb->red_mask;
   3282 	main_green_mask  = fb->green_mask;
   3283 	main_blue_mask   = fb->blue_mask;
   3284 
   3285 	have_masks = ((fb->red_mask|fb->green_mask|fb->blue_mask) != 0);
   3286 	if (force_indexed_color) {
   3287 		have_masks = 0;
   3288 	}
   3289 
   3290 	if (cmap8to24 && depth <= 16 && dpy) {
   3291 		XVisualInfo vinfo;
   3292 		vinfo.red_mask = 0;
   3293 		vinfo.green_mask = 0;
   3294 		vinfo.blue_mask = 0;
   3295 		/* more cooking up... */
   3296 		have_masks = 2;
   3297 		/* need to fetch TrueColor visual */
   3298 		X_LOCK;
   3299 		if (dpy
   3300 #if !NO_X11
   3301 		    && XMatchVisualInfo(dpy, scr, 24, TrueColor, &vinfo)
   3302 #endif
   3303 		    ) {
   3304 			main_red_mask   = vinfo.red_mask;
   3305 			main_green_mask = vinfo.green_mask;
   3306 			main_blue_mask  = vinfo.blue_mask;
   3307 		} else if (fb->byte_order == LSBFirst) {
   3308 			main_red_mask   = 0x00ff0000;
   3309 			main_green_mask = 0x0000ff00;
   3310 			main_blue_mask  = 0x000000ff;
   3311 		} else {
   3312 			main_red_mask   = 0x000000ff;
   3313 			main_green_mask = 0x0000ff00;
   3314 			main_blue_mask  = 0x00ff0000;
   3315 		}
   3316 		X_UNLOCK;
   3317 	}
   3318 
   3319 	if (raw_fb_str && raw_fb_pixfmt) {
   3320 		char *fmt = strdup(raw_fb_pixfmt);
   3321 		uppercase(fmt);
   3322 		if (strstr(fmt, "GREY")) {
   3323 			set_greyscale_colormap();
   3324 		} else if (strstr(fmt, "HI240")) {
   3325 			set_hi240_colormap();
   3326 		} else {
   3327 			unset_colormap();
   3328 		}
   3329 		free(fmt);
   3330 	}
   3331 
   3332 	if (! have_masks && screen->serverFormat.bitsPerPixel <= 16
   3333 	    && dpy && CellsOfScreen(ScreenOfDisplay(dpy, scr))) {
   3334 		/* indexed color. we let 1 <= bpp <= 16, but it is normally 8 */
   3335 		if (!quiet) {
   3336 			rfbLog("\n");
   3337 			rfbLog("X display %s is %dbpp indexed color, depth=%d\n",
   3338 			    DisplayString(dpy), screen->serverFormat.bitsPerPixel,
   3339 			    screen->serverFormat.depth);
   3340 			if (! flash_cmap && ! overlay) {
   3341 				rfbLog("\n");
   3342 				rfbLog("In 8bpp PseudoColor mode if you "
   3343 				    "experience color\n");
   3344 				rfbLog("problems you may want to enable "
   3345 				    "following the\n");
   3346 				rfbLog("changing colormap by using the "
   3347 				    "-flashcmap option.\n");
   3348 				rfbLog("\n");
   3349 			}
   3350 		}
   3351 		if (screen->serverFormat.depth < 8) {
   3352 			rfbLog("resetting serverFormat.depth %d -> 8.\n",
   3353 			    screen->serverFormat.depth);
   3354 			rfbLog("resetting serverFormat.bpp   %d -> 8.\n",
   3355 			    screen->serverFormat.bitsPerPixel);
   3356 			screen->serverFormat.depth = 8;
   3357 			screen->serverFormat.bitsPerPixel = 8;
   3358 		}
   3359 		if (screen->serverFormat.depth > 8) {
   3360 			rfbLog("WARNING: indexed color depth > 8, Tight encoding will crash.\n");
   3361 		}
   3362 
   3363 		screen->serverFormat.trueColour = FALSE;
   3364 		indexed_color = 1;
   3365 		set_colormap(1);
   3366 		debug_colormap(fb);
   3367 	} else {
   3368 		/*
   3369 		 * general case, we call it truecolor, but could be direct
   3370 		 * color, static color, etc....
   3371 		 */
   3372 		if (! quiet) {
   3373 			if (raw_fb) {
   3374 				rfbLog("\n");
   3375 				rfbLog("Raw fb at addr %p is %dbpp depth=%d "
   3376 				    "true color\n", raw_fb_addr,
   3377 				    fb_bpp, fb_depth);
   3378 			} else if (! dpy) {
   3379 				;
   3380 			} else if (have_masks == 2) {
   3381 				rfbLog("\n");
   3382 				rfbLog("X display %s is %dbpp depth=%d indexed "
   3383 				    "color (-8to24 mode)\n", DisplayString(dpy),
   3384 				    fb->bits_per_pixel, fb->depth);
   3385 			} else {
   3386 				rfbLog("\n");
   3387 				rfbLog("X display %s is %dbpp depth=%d true "
   3388 				    "color\n", DisplayString(dpy),
   3389 				    fb_bpp, fb_depth);
   3390 			}
   3391 		}
   3392 
   3393 		indexed_color = 0;
   3394 
   3395 		if (!have_masks) {
   3396 			int M, B = bits_per_color;
   3397 
   3398 			if (3*B > fb_bpp) B--;
   3399 			if (B < 1) B = 1;
   3400 			M = (1 << B) - 1;
   3401 
   3402 			rfbLog("WARNING: all TrueColor RGB masks are zero!\n");
   3403 			rfbLog("WARNING: cooking something up for VNC fb...  B=%d M=%d\n", B, M);
   3404 			main_red_mask   = M;
   3405 			main_green_mask = M;
   3406 			main_blue_mask  = M;
   3407 			main_red_mask   = main_red_mask   << (2*B);
   3408 			main_green_mask = main_green_mask << (1*B);
   3409 			main_blue_mask  = main_blue_mask  << (0*B);
   3410 			fprintf(stderr, " red_mask:   0x%08lx  %s\n", main_red_mask,
   3411 			    bitprint(main_red_mask, 32));
   3412 			fprintf(stderr, " green_mask: 0x%08lx  %s\n", main_green_mask,
   3413 			    bitprint(main_green_mask, 32));
   3414 			fprintf(stderr, " blue_mask:  0x%08lx  %s\n", main_blue_mask,
   3415 			    bitprint(main_blue_mask, 32));
   3416 		}
   3417 
   3418 		/* convert masks to bit shifts and max # colors */
   3419 		if (main_red_mask) {
   3420 			while (! (main_red_mask
   3421 			    & (1 << screen->serverFormat.redShift))) {
   3422 				    screen->serverFormat.redShift++;
   3423 			}
   3424 		}
   3425 		if (main_green_mask) {
   3426 			while (! (main_green_mask
   3427 			    & (1 << screen->serverFormat.greenShift))) {
   3428 				    screen->serverFormat.greenShift++;
   3429 			}
   3430 		}
   3431 		if (main_blue_mask) {
   3432 			while (! (main_blue_mask
   3433 			    & (1 << screen->serverFormat.blueShift))) {
   3434 				    screen->serverFormat.blueShift++;
   3435 			}
   3436 		}
   3437 		screen->serverFormat.redMax
   3438 		    = main_red_mask   >> screen->serverFormat.redShift;
   3439 		screen->serverFormat.greenMax
   3440 		    = main_green_mask >> screen->serverFormat.greenShift;
   3441 		screen->serverFormat.blueMax
   3442 		    = main_blue_mask  >> screen->serverFormat.blueShift;
   3443 
   3444 		main_red_max     = screen->serverFormat.redMax;
   3445 		main_green_max   = screen->serverFormat.greenMax;
   3446 		main_blue_max    = screen->serverFormat.blueMax;
   3447 
   3448 		main_red_shift   = screen->serverFormat.redShift;
   3449 		main_green_shift = screen->serverFormat.greenShift;
   3450 		main_blue_shift  = screen->serverFormat.blueShift;
   3451 	}
   3452 
   3453 #if !SMALL_FOOTPRINT
   3454 	if (verbose) {
   3455 		fprintf(stderr, "\n");
   3456 		fprintf(stderr, "FrameBuffer Info:\n");
   3457 		fprintf(stderr, " width:            %d\n", fb->width);
   3458 		fprintf(stderr, " height:           %d\n", fb->height);
   3459 		fprintf(stderr, " scaled_width:     %d\n", width);
   3460 		fprintf(stderr, " scaled_height:    %d\n", height);
   3461 		fprintf(stderr, " indexed_color:    %d\n", indexed_color);
   3462 		fprintf(stderr, " bits_per_pixel:   %d\n", fb->bits_per_pixel);
   3463 		fprintf(stderr, " depth:            %d\n", fb->depth);
   3464 		fprintf(stderr, " red_mask:   0x%08lx  %s\n", fb->red_mask,
   3465 		    bitprint(fb->red_mask, 32));
   3466 		fprintf(stderr, " green_mask: 0x%08lx  %s\n", fb->green_mask,
   3467 		    bitprint(fb->green_mask, 32));
   3468 		fprintf(stderr, " blue_mask:  0x%08lx  %s\n", fb->blue_mask,
   3469 		    bitprint(fb->blue_mask, 32));
   3470 		if (cmap8to24) {
   3471 			fprintf(stderr, " 8to24 info:\n");
   3472 			fprintf(stderr, " fb_bpp:           %d\n", fb_bpp);
   3473 			fprintf(stderr, " fb_depth:         %d\n", fb_depth);
   3474 			fprintf(stderr, " red_mask:   0x%08lx  %s\n", main_red_mask,
   3475 			    bitprint(main_red_mask, 32));
   3476 			fprintf(stderr, " green_mask: 0x%08lx  %s\n", main_green_mask,
   3477 			    bitprint(main_green_mask, 32));
   3478 			fprintf(stderr, " blue_mask:  0x%08lx  %s\n", main_blue_mask,
   3479 			    bitprint(main_blue_mask, 32));
   3480 		}
   3481 		fprintf(stderr, " red:   max: %3d  shift: %2d\n",
   3482 			main_red_max, main_red_shift);
   3483 		fprintf(stderr, " green: max: %3d  shift: %2d\n",
   3484 			main_green_max, main_green_shift);
   3485 		fprintf(stderr, " blue:  max: %3d  shift: %2d\n",
   3486 			main_blue_max, main_blue_shift);
   3487 		fprintf(stderr, " mainfb_bytes_per_line: %d\n",
   3488 			main_bytes_per_line);
   3489 		fprintf(stderr, " rfb_fb_bytes_per_line: %d\n",
   3490 			rfb_bytes_per_line);
   3491 		fprintf(stderr, " rot_fb_bytes_per_line: %d\n",
   3492 			rot_bytes_per_line);
   3493 		fprintf(stderr, " raw_fb_bytes_per_line: %d\n",
   3494 			raw_fb_bytes_per_line);
   3495 		switch(fb->format) {
   3496 		case XYBitmap:
   3497 			fprintf(stderr, " format:     XYBitmap\n"); break;
   3498 		case XYPixmap:
   3499 			fprintf(stderr, " format:     XYPixmap\n"); break;
   3500 		case ZPixmap:
   3501 			fprintf(stderr, " format:     ZPixmap\n"); break;
   3502 		default:
   3503 			fprintf(stderr, " format:     %d\n", fb->format); break;
   3504 		}
   3505 		switch(fb->byte_order) {
   3506 		case LSBFirst:
   3507 			fprintf(stderr, " byte_order: LSBFirst\n"); break;
   3508 		case MSBFirst:
   3509 			fprintf(stderr, " byte_order: MSBFirst\n"); break;
   3510 		default:
   3511 			fprintf(stderr, " byte_order: %d\n", fb->byte_order);
   3512 			break;
   3513 		}
   3514 		fprintf(stderr, " bitmap_pad:  %d\n", fb->bitmap_pad);
   3515 		fprintf(stderr, " bitmap_unit: %d\n", fb->bitmap_unit);
   3516 		switch(fb->bitmap_bit_order) {
   3517 		case LSBFirst:
   3518 			fprintf(stderr, " bitmap_bit_order: LSBFirst\n"); break;
   3519 		case MSBFirst:
   3520 			fprintf(stderr, " bitmap_bit_order: MSBFirst\n"); break;
   3521 		default:
   3522 			fprintf(stderr, " bitmap_bit_order: %d\n",
   3523 			fb->bitmap_bit_order); break;
   3524 		}
   3525 	}
   3526 	if (overlay && ! quiet) {
   3527 		rfbLog("\n");
   3528 		rfbLog("Overlay mode enabled:  If you experience color\n");
   3529 		rfbLog("problems when popup menus are on the screen, try\n");
   3530 		rfbLog("disabling SaveUnders in your X server, one way is\n");
   3531 		rfbLog("to start the X server with the '-su' option, e.g.:\n");
   3532 		rfbLog("Xsun -su ... see Xserver(1), xinit(1) for more info.\n");
   3533 		rfbLog("\n");
   3534 	}
   3535 #endif
   3536 	/* nofb is for pointer/keyboard only handling.  */
   3537 	if (nofb) {
   3538 		main_fb = NULL;
   3539 		rfb_fb = main_fb;
   3540 		cmap8to24_fb = NULL;
   3541 		rot_fb = NULL;
   3542 		screen->displayHook = nofb_hook;
   3543 	} else {
   3544 		main_fb = fb->data;
   3545 		rfb_fb = NULL;
   3546 		cmap8to24_fb = NULL;
   3547 		rot_fb = NULL;
   3548 
   3549 		if (cmap8to24) {
   3550 			int n = main_bytes_per_line * fb->height;
   3551 			if (depth <= 8) {
   3552 				n *= 4;
   3553 			} else if (depth <= 16) {
   3554 				n *= 2;
   3555 			}
   3556 			cmap8to24_fb = (char *) malloc(n);
   3557 			memset(cmap8to24_fb, 0, n);
   3558 		}
   3559 
   3560 		if (rotating) {
   3561 			int n = rot_bytes_per_line * height;
   3562 			rot_fb = (char *) malloc(n);
   3563 			memset(rot_fb, 0, n);
   3564 		}
   3565 
   3566 		if (scaling) {
   3567 			int n = rfb_bytes_per_line * height;
   3568 
   3569 			if (rotating && ! rotating_same) {
   3570 				n = rot_bytes_per_line * height;
   3571 			}
   3572 
   3573 			rfb_fb = (char *) malloc(n);
   3574 			memset(rfb_fb, 0, n);
   3575 
   3576 		} else if (cmap8to24) {
   3577 			rfb_fb = cmap8to24_fb;
   3578 		} else {
   3579 			rfb_fb = main_fb;
   3580 		}
   3581 	}
   3582 	if (rot_fb) {
   3583 		screen->frameBuffer = rot_fb;
   3584 	} else {
   3585 		screen->frameBuffer = rfb_fb;
   3586 	}
   3587 	if (verbose) {
   3588 		fprintf(stderr, " rfb_fb:      %p\n", rfb_fb);
   3589 		fprintf(stderr, " main_fb:     %p\n", main_fb);
   3590 		fprintf(stderr, " 8to24_fb:    %p\n", cmap8to24_fb);
   3591 		fprintf(stderr, " rot_fb:      %p\n", rot_fb);
   3592 		fprintf(stderr, " snap_fb:     %p\n", snap_fb);
   3593 		fprintf(stderr, " raw_fb:      %p\n", raw_fb);
   3594 		fprintf(stderr, " fake_fb:     %p\n", fake_fb);
   3595 		fprintf(stderr, "\n");
   3596 	}
   3597 
   3598 	/* may need, bpp, main_red_max, etc. */
   3599 	parse_wireframe();
   3600 	parse_scroll_copyrect();
   3601 	setup_cursors_and_push();
   3602 
   3603 	if (scaling || rotating || cmap8to24) {
   3604 		mark_rect_as_modified(0, 0, dpy_x, dpy_y, 0);
   3605 	}
   3606 
   3607 	if (! create_screen) {
   3608 		rfbClientIteratorPtr iter;
   3609 		rfbClientPtr cl;
   3610 
   3611 		/*
   3612 		 * since bits_per_color above may have been approximate,
   3613 		 * try to reset the individual translation tables...
   3614 		 * we do not seem to need this with rfbGetScreen()...
   3615 		 */
   3616 		if (!quiet) rfbLog("calling setTranslateFunction()...\n");
   3617 		iter = rfbGetClientIterator(screen);
   3618 		while ((cl = rfbClientIteratorNext(iter)) != NULL) {
   3619 			screen->setTranslateFunction(cl);
   3620 		}
   3621 		rfbReleaseClientIterator(iter);
   3622 		if (!quiet) rfbLog("  done.\n");
   3623 
   3624 		/* done for framebuffer change case */
   3625 		if (locked_sends) {
   3626 			lock_client_sends(0);
   3627 		}
   3628 
   3629 		do_copy_screen = 1;
   3630 		return;
   3631 	}
   3632 
   3633 	/*
   3634 	 * the rest is screen server initialization, etc, only needed
   3635 	 * at screen creation time.
   3636 	 */
   3637 
   3638 	/* event callbacks: */
   3639 	screen->newClientHook = new_client;
   3640 	screen->kbdAddEvent = keyboard;
   3641 	screen->ptrAddEvent = pointer_event;
   3642 	screen->setXCutText = xcut_receive;
   3643 	screen->setTranslateFunction = set_xlate_wrapper;
   3644 
   3645 	screen->kbdReleaseAllKeys = kbd_release_all_keys;
   3646 	screen->setSingleWindow = set_single_window;
   3647 	screen->setServerInput = set_server_input;
   3648 	screen->setTextChat = set_text_chat;
   3649 	screen->getFileTransferPermission = get_file_transfer_permitted;
   3650 
   3651 	/* called from inetd, we need to treat stdio as our socket */
   3652 	if (inetd && use_openssl) {
   3653 		/* accept_openssl() called later */
   3654 		screen->port = 0;
   3655 	} else if (inetd) {
   3656 		int fd = dup(0);
   3657 		if (fd < 0) {
   3658 			rfbLogEnable(1);
   3659 			rfbErr("dup(0) = %d failed.\n", fd);
   3660 			rfbLogPerror("dup");
   3661 			clean_up_exit(1);
   3662 		}
   3663 		fclose(stdin);
   3664 		fclose(stdout);
   3665 		/* we keep stderr for logging */
   3666 		screen->inetdSock = fd;
   3667 		screen->port = 0;
   3668 
   3669 	} else if (! got_rfbport && auto_port > 0) {
   3670 		int lport = find_free_port(auto_port, auto_port+200);
   3671 		screen->autoPort = FALSE;
   3672 		screen->port = lport;
   3673 	} else if (! got_rfbport) {
   3674 		screen->autoPort = TRUE;
   3675 	} else if (got_rfbport && got_rfbport_val == 0) {
   3676 		screen->autoPort = FALSE;
   3677 		screen->port = 0;
   3678 	}
   3679 
   3680 	if (! got_nevershared && ! got_alwaysshared) {
   3681 		if (shared) {
   3682 			screen->alwaysShared = TRUE;
   3683 		} else {
   3684 			screen->neverShared = TRUE;
   3685 		}
   3686 		screen->dontDisconnect = TRUE;
   3687 	}
   3688 	if (! got_deferupdate) {
   3689 		screen->deferUpdateTime = defer_update;
   3690 	} else {
   3691 		defer_update = screen->deferUpdateTime;
   3692 	}
   3693 
   3694 	if (noipv4 || getenv("IPV4_FAILS")) {
   3695 		rfbBool ap = screen->autoPort;
   3696 		int port = screen->port;
   3697 
   3698 		if (getenv("IPV4_FAILS")) {
   3699 			rfbLog("TESTING: IPV4_FAILS for rfbInitServer()\n");
   3700 		}
   3701 
   3702 		screen->autoPort = FALSE;
   3703 		screen->port = 0;
   3704 
   3705 		rfbInitServer(screen);
   3706 
   3707 		screen->autoPort = ap;
   3708 		screen->port = port;
   3709 
   3710 	} else {
   3711 		rfbInitServer(screen);
   3712 	}
   3713 
   3714 	if (use_openssl) {
   3715 		openssl_port(0);
   3716 		if (https_port_num >= 0) {
   3717 			https_port(0);
   3718 		}
   3719 	} else {
   3720 		if (ipv6_listen) {
   3721 			int fd = -1;
   3722 			if (screen->port <= 0) {
   3723 				if (got_rfbport) {
   3724 					screen->port = got_rfbport_val;
   3725 				} else {
   3726 					int ap = 5900;
   3727 					if (auto_port > 0) {
   3728 						ap = auto_port;
   3729 					}
   3730 					screen->port = find_free_port6(ap, ap+200);
   3731 				}
   3732 			}
   3733 			fd = listen6(screen->port);
   3734 			if (fd < 0) {
   3735 				ipv6_listen = 0;
   3736 				rfbLog("Not listening on IPv6 interface.\n");
   3737 			} else {
   3738 				rfbLog("Listening %s on IPv6 port %d (socket %d)\n",
   3739 				    screen->listenSock < 0 ? "only" : "also",
   3740 				    screen->port, fd);
   3741 				ipv6_listen_fd = fd;
   3742 			}
   3743 		}
   3744 	}
   3745 
   3746 	install_passwds();
   3747 
   3748 	if (locked_sends) {
   3749 		lock_client_sends(0);
   3750 	}
   3751 	return;
   3752 }
   3753 
   3754 #define DO_AVAHI \
   3755 	if (avahi) { \
   3756 		avahi_initialise(); \
   3757 		avahi_advertise(vnc_desktop_name, host, lport); \
   3758 		usleep(1000*1000); \
   3759 	}
   3760 
   3761 void announce(int lport, int ssl, char *iface) {
   3762 
   3763 	char *host = this_host();
   3764 	char *tvdt;
   3765 
   3766 	if (remote_direct) {
   3767 		return;
   3768 	}
   3769 
   3770 	if (! ssl) {
   3771 		tvdt = "The VNC desktop is:     ";
   3772 	} else {
   3773 		if (enc_str && !strcmp(enc_str, "none")) {
   3774 			tvdt = "The VNC desktop is:     ";
   3775 		} else if (enc_str) {
   3776 			tvdt = "The ENC VNC desktop is: ";
   3777 		} else {
   3778 			tvdt = "The SSL VNC desktop is: ";
   3779 		}
   3780 	}
   3781 
   3782 	if (iface != NULL && *iface != '\0' && strcmp(iface, "any")) {
   3783 		host = iface;
   3784 	}
   3785 	if (host != NULL) {
   3786 		/* note that vncviewer special cases 5900-5999 */
   3787 		int sz = 256;
   3788 		if (inetd) {
   3789 			;	/* should not occur (port) */
   3790 		} else if (quiet) {
   3791 			if (lport >= 5900) {
   3792 				snprintf(vnc_desktop_name, sz, "%s:%d",
   3793 				    host, lport - 5900);
   3794 				DO_AVAHI
   3795 				fprintf(stderr, "\n%s %s\n", tvdt,
   3796 				    vnc_desktop_name);
   3797 			} else {
   3798 				snprintf(vnc_desktop_name, sz, "%s:%d",
   3799 				    host, lport);
   3800 				DO_AVAHI
   3801 				fprintf(stderr, "\n%s %s\n", tvdt,
   3802 				    vnc_desktop_name);
   3803 			}
   3804 		} else if (lport >= 5900) {
   3805 			snprintf(vnc_desktop_name, sz, "%s:%d",
   3806 			    host, lport - 5900);
   3807 			DO_AVAHI
   3808 			fprintf(stderr, "\n%s %s\n", tvdt, vnc_desktop_name);
   3809 			if (lport >= 6000) {
   3810 				rfbLog("possible aliases:  %s:%d, "
   3811 				    "%s::%d\n", host, lport,
   3812 				    host, lport);
   3813 			}
   3814 		} else {
   3815 			snprintf(vnc_desktop_name, sz, "%s:%d",
   3816 			    host, lport);
   3817 			DO_AVAHI
   3818 			fprintf(stderr, "\n%s %s\n", tvdt, vnc_desktop_name);
   3819 			rfbLog("possible alias:    %s::%d\n",
   3820 			    host, lport);
   3821 		}
   3822 	}
   3823 }
   3824 
   3825 static void announce_http(int lport, int ssl, char *iface, char *extra) {
   3826 
   3827 	char *host = this_host();
   3828 	char *jvu;
   3829 	int http = 0;
   3830 
   3831 	if (enc_str && !strcmp(enc_str, "none") && !use_stunnel) {
   3832 		jvu = "Java viewer URL:         http";
   3833 		http = 1;
   3834 	} else if (ssl == 1) {
   3835 		jvu = "Java SSL viewer URL:     https";
   3836 	} else if (ssl == 2) {
   3837 		jvu = "Java SSL viewer URL:     http";
   3838 		http = 1;
   3839 	} else {
   3840 		jvu = "Java viewer URL:         http";
   3841 		http = 1;
   3842 	}
   3843 
   3844 	if (iface != NULL && *iface != '\0' && strcmp(iface, "any")) {
   3845 		host = iface;
   3846 	}
   3847 	if (http && getenv("X11VNC_HTTP_LISTEN_LOCALHOST")) {
   3848 		host = "localhost";
   3849 	}
   3850 	if (host != NULL) {
   3851 		if (! inetd) {
   3852 			fprintf(stderr, "%s://%s:%d/%s\n", jvu, host, lport, extra);
   3853 		}
   3854 	}
   3855 }
   3856 
   3857 void do_announce_http(void) {
   3858 	if (!screen) {
   3859 		return;
   3860 	}
   3861 	if (remote_direct) {
   3862 		return;
   3863 	}
   3864 
   3865 	/* XXX ipv6? */
   3866 	if ((screen->httpListenSock > -1 || ipv6_http_fd > -1) && screen->httpPort) {
   3867 		int enc_none = (enc_str && !strcmp(enc_str, "none"));
   3868 		char *SPORT = "   (single port)";
   3869 		if (use_openssl && ! enc_none) {
   3870 			announce_http(screen->port, 1, listen_str, SPORT);
   3871 			if (https_port_num >= 0) {
   3872 				announce_http(https_port_num, 1,
   3873 				    listen_str, "");
   3874 			}
   3875 			announce_http(screen->httpPort, 2, listen_str, "");
   3876 		} else if (use_stunnel) {
   3877 			char pmsg[100];
   3878 			pmsg[0] = '\0';
   3879 			if (stunnel_port) {
   3880 				sprintf(pmsg, "?PORT=%d", stunnel_port);
   3881 			}
   3882 			announce_http(screen->httpPort, 2, listen_str, pmsg);
   3883 			if (stunnel_http_port > 0) {
   3884 				announce_http(stunnel_http_port, 1, NULL, pmsg);
   3885 			}
   3886 			if (enc_none) {
   3887 				strcat(pmsg, SPORT);
   3888 				announce_http(stunnel_port, 1, NULL, pmsg);
   3889 			}
   3890 		} else {
   3891 			announce_http(screen->httpPort, 0, listen_str, "");
   3892 			if (enc_none) {
   3893 				announce_http(screen->port, 1, NULL, SPORT);
   3894 			}
   3895 		}
   3896 	}
   3897 }
   3898 
   3899 void do_mention_java_urls(void) {
   3900 	if (! quiet && screen) {
   3901 		/* XXX ipv6? */
   3902 		if (screen->httpListenSock > -1 && screen->httpPort) {
   3903 			rfbLog("\n");
   3904 			rfbLog("The URLs printed out below ('Java ... viewer URL') can\n");
   3905 			rfbLog("be used for Java enabled Web browser connections.\n");
   3906 			if (!stunnel_port && enc_str && !strcmp(enc_str, "none")) {
   3907 				;
   3908 			} else if (use_openssl || stunnel_port) {
   3909 				rfbLog("Here are some additional possibilities:\n");
   3910 				rfbLog("\n");
   3911 				rfbLog("https://host:port/proxy.vnc (MUST be used if Web Proxy used)\n");
   3912 				rfbLog("\n");
   3913 				rfbLog("https://host:port/ultra.vnc (Use UltraVNC Java Viewer)\n");
   3914 				rfbLog("https://host:port/ultraproxy.vnc (Web Proxy with UltraVNC)\n");
   3915 				rfbLog("https://host:port/ultrasigned.vnc (Signed UltraVNC Filexfer)\n");
   3916 				rfbLog("\n");
   3917 				rfbLog("Where you replace \"host:port\" with that printed below, or\n");
   3918 				rfbLog("whatever is needed to reach the host e.g. Internet IP number\n");
   3919 				rfbLog("\n");
   3920 				rfbLog("Append ?GET=1 to a URL for faster loading or supply:\n");
   3921 				rfbLog("-env X11VNC_EXTRA_HTTPS_PARAMS='?GET=1' to cmdline.\n");
   3922 			}
   3923 		}
   3924 		rfbLog("\n");
   3925 	}
   3926 }
   3927 
   3928 void set_vnc_desktop_name(void) {
   3929 	sprintf(vnc_desktop_name, "unknown");
   3930 	if (inetd) {
   3931 		sprintf(vnc_desktop_name, "%s/inetd-no-further-clients",
   3932 		    this_host());
   3933 	}
   3934 	if (remote_direct) {
   3935 		return;
   3936 	}
   3937 	if (screen->port) {
   3938 
   3939 		do_mention_java_urls();
   3940 
   3941 		if (use_openssl) {
   3942 			announce(screen->port, 1, listen_str);
   3943 		} else {
   3944 			announce(screen->port, 0, listen_str);
   3945 		}
   3946 		if (stunnel_port) {
   3947 			announce(stunnel_port, 1, NULL);
   3948 		}
   3949 
   3950 		do_announce_http();
   3951 
   3952 		fflush(stderr);
   3953 		if (inetd) {
   3954 			;	/* should not occur (port != 0) */
   3955 		} else {
   3956 			fprintf(stdout, "PORT=%d\n", screen->port);
   3957 			if (stunnel_port) {
   3958 				fprintf(stdout, "SSLPORT=%d\n", stunnel_port);
   3959 			} else if (use_openssl) {
   3960 				if (enc_str && !strcmp(enc_str, "none")) {
   3961 					;
   3962 				} else if (enc_str) {
   3963 					fprintf(stdout, "ENCPORT=%d\n", screen->port);
   3964 				} else {
   3965 					fprintf(stdout, "SSLPORT=%d\n", screen->port);
   3966 				}
   3967 			}
   3968 			fflush(stdout);
   3969 			if (flagfile) {
   3970 				FILE *flag = fopen(flagfile, "w");
   3971 				if (flag) {
   3972 					fprintf(flag, "PORT=%d\n",screen->port);
   3973 					if (stunnel_port) {
   3974 						fprintf(flag, "SSL_PORT=%d\n",
   3975 						    stunnel_port);
   3976 					}
   3977 					fflush(flag);
   3978 					fclose(flag);
   3979 				} else {
   3980 					rfbLog("could not open flag file: %s\n",
   3981 					    flagfile);
   3982 				}
   3983 			}
   3984 			if (rm_flagfile) {
   3985 				int create = 0;
   3986 				struct stat sb;
   3987 				if (strstr(rm_flagfile, "create:") == rm_flagfile) {
   3988 					char *s = rm_flagfile;
   3989 					create = 1;
   3990 					rm_flagfile = strdup(rm_flagfile + strlen("create:"));
   3991 					free(s);
   3992 				}
   3993 				if (strstr(rm_flagfile, "nocreate:") == rm_flagfile) {
   3994 					char *s = rm_flagfile;
   3995 					create = 0;
   3996 					rm_flagfile = strdup(rm_flagfile + strlen("nocreate:"));
   3997 					free(s);
   3998 				} else if (stat(rm_flagfile, &sb) != 0) {
   3999 					create = 1;
   4000 				}
   4001 				if (create) {
   4002 					FILE *flag = fopen(rm_flagfile, "w");
   4003 					if (flag) {
   4004 						fprintf(flag, "%d\n", getpid());
   4005 						fclose(flag);
   4006 					}
   4007 				}
   4008 			}
   4009 		}
   4010 		fflush(stdout);
   4011 	}
   4012 }
   4013 
   4014 static void check_cursor_changes(void) {
   4015 	static double last_push = 0.0;
   4016 
   4017 	if (unixpw_in_progress) return;
   4018 
   4019 	cursor_changes += check_x11_pointer();
   4020 
   4021 	if (cursor_changes) {
   4022 		double tm, max_push = 0.125, multi_push = 0.01, wait = 0.02;
   4023 		int cursor_shape, dopush = 0, link, latency, netrate;
   4024 
   4025 		if (! all_clients_initialized()) {
   4026 			/* play it safe */
   4027 			return;
   4028 		}
   4029 
   4030 		if (0) cursor_shape = cursor_shape_updates_clients(screen);
   4031 
   4032 		dtime0(&tm);
   4033 		link = link_rate(&latency, &netrate);
   4034 		if (link == LR_DIALUP) {
   4035 			max_push = 0.2;
   4036 			wait = 0.05;
   4037 		} else if (link == LR_BROADBAND) {
   4038 			max_push = 0.075;
   4039 			wait = 0.05;
   4040 		} else if (link == LR_LAN) {
   4041 			max_push = 0.01;
   4042 		} else if (latency < 5 && netrate > 200) {
   4043 			max_push = 0.01;
   4044 		}
   4045 
   4046 		if (tm > last_push + max_push) {
   4047 			dopush = 1;
   4048 		} else if (cursor_changes > 1 && tm > last_push + multi_push) {
   4049 			dopush = 1;
   4050 		}
   4051 
   4052 		if (dopush) {
   4053 			mark_rect_as_modified(0, 0, 1, 1, 1);
   4054 			fb_push_wait(wait, FB_MOD);
   4055 			last_push = tm;
   4056 		} else {
   4057 			rfbPE(0);
   4058 		}
   4059 	}
   4060 	cursor_changes = 0;
   4061 }
   4062 
   4063 /*
   4064  * These watch_loop() releated were moved from x11vnc.c so we could try
   4065  * to remove -O2 from its compilation.  TDB new file, e.g. watch.c.
   4066  */
   4067 
   4068 static void check_filexfer(void) {
   4069 	static time_t last_check = 0;
   4070 	rfbClientIteratorPtr iter;
   4071 	rfbClientPtr cl;
   4072 	int transferring = 0;
   4073 
   4074 	if (time(NULL) <= last_check) {
   4075 		return;
   4076 	}
   4077 
   4078 #if 0
   4079 	if (getenv("NOFT")) {
   4080 		return;
   4081 	}
   4082 #endif
   4083 
   4084 	iter = rfbGetClientIterator(screen);
   4085 	while( (cl = rfbClientIteratorNext(iter)) ) {
   4086 		if (cl->fileTransfer.receiving) {
   4087 			transferring = 1;
   4088 			break;
   4089 		}
   4090 		if (cl->fileTransfer.sending) {
   4091 			transferring = 1;
   4092 			break;
   4093 		}
   4094 	}
   4095 	rfbReleaseClientIterator(iter);
   4096 
   4097 	if (transferring) {
   4098 		double start = dnow();
   4099 		while (dnow() < start + 0.5) {
   4100 			rfbCFD(5000);
   4101 			rfbCFD(1000);
   4102 			rfbCFD(0);
   4103 		}
   4104 	} else {
   4105 		last_check = time(NULL);
   4106 	}
   4107 }
   4108 
   4109 static void record_last_fb_update(void) {
   4110 	static int rbs0 = -1;
   4111 	static time_t last_call = 0;
   4112 	time_t now = time(NULL);
   4113 	int rbs = -1;
   4114 	rfbClientIteratorPtr iter;
   4115 	rfbClientPtr cl;
   4116 
   4117 	if (last_fb_bytes_sent == 0) {
   4118 		last_fb_bytes_sent = now;
   4119 		last_call = now;
   4120 	}
   4121 
   4122 	if (now <= last_call + 1) {
   4123 		/* check every second or so */
   4124 		return;
   4125 	}
   4126 
   4127 	if (unixpw_in_progress) return;
   4128 
   4129 	last_call = now;
   4130 
   4131 	if (! screen) {
   4132 		return;
   4133 	}
   4134 
   4135 	iter = rfbGetClientIterator(screen);
   4136 	while( (cl = rfbClientIteratorNext(iter)) ) {
   4137 #if 0
   4138 		rbs += cl->rawBytesEquivalent;
   4139 #else
   4140 #if LIBVNCSERVER_HAS_STATS
   4141 		rbs += rfbStatGetSentBytesIfRaw(cl);
   4142 #endif
   4143 #endif
   4144 	}
   4145 	rfbReleaseClientIterator(iter);
   4146 
   4147 	if (rbs != rbs0) {
   4148 		rbs0 = rbs;
   4149 		if (debug_tiles > 1) {
   4150 			fprintf(stderr, "record_last_fb_update: %d %d\n",
   4151 			    (int) now, (int) last_fb_bytes_sent);
   4152 		}
   4153 		last_fb_bytes_sent = now;
   4154 	}
   4155 }
   4156 
   4157 
   4158 static int choose_delay(double dt) {
   4159 	static double t0 = 0.0, t1 = 0.0, t2 = 0.0, now;
   4160 	static int x0, y0, x1, y1, x2, y2, first = 1;
   4161 	int dx0, dy0, dx1, dy1, dm, i, msec = waitms;
   4162 	double cut1 = 0.15, cut2 = 0.075, cut3 = 0.25;
   4163 	double bogdown_time = 0.25, bave = 0.0;
   4164 	int bogdown = 1, bcnt = 0;
   4165 	int ndt = 8, nave = 3;
   4166 	double fac = 1.0;
   4167 	static int db = 0, did_set_defer = 0;
   4168 	static double dts[8];
   4169 	static int link = LR_UNSET, latency = -1, netrate = -1;
   4170 	static double last_link = 0.0;
   4171 
   4172 	if (screen && did_set_defer) {
   4173 		/* reset defer in case we changed it */
   4174 		screen->deferUpdateTime = defer_update;
   4175 	}
   4176 	if (waitms == 0) {
   4177 		return waitms;
   4178 	}
   4179 	if (nofb) {
   4180 		return waitms;
   4181 	}
   4182 
   4183 	if (first) {
   4184 		for(i=0; i<ndt; i++) {
   4185 			dts[i] = 0.0;
   4186 		}
   4187 		if (getenv("DEBUG_DELAY")) {
   4188 			db = atoi(getenv("DEBUG_DELAY"));
   4189 		}
   4190 		if (getenv("SET_DEFER")) {
   4191 			set_defer = atoi(getenv("SET_DEFER"));
   4192 		}
   4193 		first = 0;
   4194 	}
   4195 
   4196 	now = dnow();
   4197 
   4198 	if (now > last_link + 30.0 || link == LR_UNSET) {
   4199 		link = link_rate(&latency, &netrate);
   4200 		last_link = now;
   4201 	}
   4202 
   4203 	/*
   4204 	 * first check for bogdown, e.g. lots of activity, scrolling text
   4205 	 * from command output, etc.
   4206 	 */
   4207 	if (nap_ok) {
   4208 		dt = 0.0;
   4209 	}
   4210 	if (! wait_bog) {
   4211 		bogdown = 0;
   4212 
   4213 	} else if (button_mask || now < last_keyboard_time + 2*bogdown_time) {
   4214 		/*
   4215 		 * let scrolls & keyboard input through the normal way
   4216 		 * otherwise, it will likely just annoy them.
   4217 		 */
   4218 		bogdown = 0;
   4219 
   4220 	} else if (dt > 0.0) {
   4221 		/*
   4222 		 * inspect recent dt's:
   4223 		 * 0 1 2 3 4 5 6 7 dt
   4224 		 *             ^ ^ ^
   4225 		 */
   4226 		for (i = ndt - (nave - 1); i < ndt; i++) {
   4227 			bave += dts[i];
   4228 			bcnt++;
   4229 			if (dts[i] < bogdown_time) {
   4230 				bogdown = 0;
   4231 				break;
   4232 			}
   4233 		}
   4234 		bave += dt;
   4235 		bcnt++;
   4236 		bave = bave / bcnt;
   4237 		if (dt < bogdown_time) {
   4238 			bogdown = 0;
   4239 		}
   4240 	} else {
   4241 		bogdown = 0;
   4242 	}
   4243 	/* shift for next time */
   4244 	for (i = 0; i < ndt-1; i++) {
   4245 		dts[i] = dts[i+1];
   4246 	}
   4247 	dts[ndt-1] = dt;
   4248 
   4249 if (0 && dt > 0.0) fprintf(stderr, "dt: %.5f %.4f\n", dt, dnowx());
   4250 	if (bogdown) {
   4251 		if (use_xdamage) {
   4252 			/* DAMAGE can queue ~1000 rectangles for a scroll */
   4253 			clear_xdamage_mark_region(NULL, 0);
   4254 		}
   4255 		msec = (int) (1000 * 1.75 * bave);
   4256 		if (dts[ndt - nave - 1] > 0.75 * bave) {
   4257 			msec = 1.5 * msec;
   4258 			set_xdamage_mark(0, 0, dpy_x, dpy_y);
   4259 		}
   4260 		if (msec > 1500) {
   4261 			msec = 1500;
   4262 		}
   4263 		if (msec < waitms) {
   4264 			msec = waitms;
   4265 		}
   4266 		db = (db || debug_tiles);
   4267 		if (db) fprintf(stderr, "bogg[%d] %.3f %.3f %.3f %.3f\n",
   4268 		    msec, dts[ndt-4], dts[ndt-3], dts[ndt-2], dts[ndt-1]);
   4269 
   4270 		return msec;
   4271 	}
   4272 
   4273 	/* next check for pointer motion, keystrokes, to speed up */
   4274 	t2 = dnow();
   4275 	x2 = cursor_x;
   4276 	y2 = cursor_y;
   4277 
   4278 	dx0 = nabs(x1 - x0);
   4279 	dy0 = nabs(y1 - y0);
   4280 	dx1 = nabs(x2 - x1);
   4281 	dy1 = nabs(y2 - y1);
   4282 
   4283 	/* bigger displacement for most recent dt: */
   4284 	if (dx1 > dy1) {
   4285 		dm = dx1;
   4286 	} else {
   4287 		dm = dy1;
   4288 	}
   4289 
   4290 	if ((dx0 || dy0) && (dx1 || dy1)) {
   4291 		/* if mouse moved the previous two times: */
   4292 		if (t2 < t0 + cut1 || t2 < t1 + cut2 || dm > 20) {
   4293 			/*
   4294 			 * if within 0.15s(0) or 0.075s(1) or mouse
   4295 			 * moved > 20pixels, set and bump up the cut
   4296 			 * down factor.
   4297 			 */
   4298 			fac = wait_ui * 1.5;
   4299 		} else if ((dx1 || dy1) && dm > 40) {
   4300 			fac = wait_ui;
   4301 		} else {
   4302 			/* still 1.0? */
   4303 			if (db > 1) fprintf(stderr, "wait_ui: still 1.0\n");
   4304 		}
   4305 	} else if ((dx1 || dy1) && dm > 40) {
   4306 		/* if mouse moved > 40 last time: */
   4307 		fac = wait_ui;
   4308 	}
   4309 
   4310 	if (fac == 1.0 && t2 < last_keyboard_time + cut3) {
   4311 		/* if typed in last 0.25s set wait_ui */
   4312 		fac = wait_ui;
   4313 	}
   4314 	if (fac != 1.0) {
   4315 		if (link == LR_LAN || latency <= 3) {
   4316 			fac *= 1.5;
   4317 		}
   4318 	}
   4319 
   4320 	msec = (int) (((double) waitms) / fac);
   4321 	if (msec == 0) {
   4322 		msec = 1;
   4323 	}
   4324 
   4325 	if (set_defer && fac != 1.0 && screen) {
   4326 		/* this is wait_ui mode, set defer to match wait: */
   4327 		if (set_defer >= 1) {
   4328 			screen->deferUpdateTime = msec;
   4329 		} else if (set_defer <= -1) {
   4330 			screen->deferUpdateTime = 0;
   4331 		}
   4332 		if (nabs(set_defer) == 2) {
   4333 			urgent_update = 1;
   4334 		}
   4335 		did_set_defer = 1;
   4336 	}
   4337 
   4338 	x0 = x1;
   4339 	y0 = y1;
   4340 	t0 = t1;
   4341 
   4342 	x1 = x2;
   4343 	y1 = y2;
   4344 	t1 = t2;
   4345 
   4346 	if (db > 1) fprintf(stderr, "wait: %2d defer[%02d]: %2d\n", msec, defer_update, screen->deferUpdateTime);
   4347 
   4348 	return msec;
   4349 }
   4350 
   4351 /*
   4352  * main x11vnc loop: polls, checks for events, iterate libvncserver, etc.
   4353  */
   4354 void watch_loop(void) {
   4355 	int cnt = 0, tile_diffs = 0, skip_pe = 0, wait;
   4356 	double tm, dtr, dt = 0.0;
   4357 	time_t start = time(NULL);
   4358 
   4359 	if (use_threads && !started_rfbRunEventLoop) {
   4360 		started_rfbRunEventLoop = 1;
   4361 		rfbRunEventLoop(screen, -1, TRUE);
   4362 	}
   4363 
   4364 	while (1) {
   4365 		char msg[] = "new client: %s taking unixpw client off hold.\n";
   4366 		int skip_scan_for_updates = 0;
   4367 
   4368 		got_user_input = 0;
   4369 		got_pointer_input = 0;
   4370 		got_local_pointer_input = 0;
   4371 		got_pointer_calls = 0;
   4372 		got_keyboard_input = 0;
   4373 		got_keyboard_calls = 0;
   4374 		urgent_update = 0;
   4375 
   4376 		x11vnc_current = dnow();
   4377 
   4378 		if (! use_threads) {
   4379 			dtime0(&tm);
   4380 			if (! skip_pe) {
   4381 				if (unixpw_in_progress) {
   4382 					rfbClientPtr cl = unixpw_client;
   4383 					if (cl && cl->onHold) {
   4384 						rfbLog(msg, cl->host);
   4385 						unixpw_client->onHold = FALSE;
   4386 					}
   4387 				} else {
   4388 					measure_send_rates(1);
   4389 				}
   4390 
   4391 				unixpw_in_rfbPE = 1;
   4392 
   4393 				/*
   4394 				 * do a few more since a key press may
   4395 				 * have induced a small change we want to
   4396 				 * see quickly (just 1 rfbPE will likely
   4397 				 * only process the subsequent "up" event)
   4398 				 */
   4399 				if (tm < last_keyboard_time + 0.20) {
   4400 					rfbPE(0);
   4401 					rfbPE(0);
   4402 					rfbPE(-1);
   4403 					rfbPE(0);
   4404 					rfbPE(0);
   4405 				} else {
   4406 					if (extra_fbur > 0) {
   4407 						int i;
   4408 						for (i=0; i < extra_fbur; i++) {
   4409 							rfbPE(0);
   4410 						}
   4411 					}
   4412 					rfbPE(-1);
   4413 				}
   4414 				if (x11vnc_current < last_new_client + 0.5) {
   4415 					urgent_update = 1;
   4416 				}
   4417 
   4418 				unixpw_in_rfbPE = 0;
   4419 
   4420 				if (unixpw_in_progress) {
   4421 					/* rfbPE loop until logged in. */
   4422 					skip_pe = 0;
   4423 					check_new_clients();
   4424 					continue;
   4425 				} else {
   4426 					measure_send_rates(0);
   4427 					fb_update_sent(NULL);
   4428 				}
   4429 			} else {
   4430 				if (unixpw_in_progress) {
   4431 					skip_pe = 0;
   4432 					check_new_clients();
   4433 					continue;
   4434 				}
   4435 			}
   4436 			dtr = dtime(&tm);
   4437 
   4438 			if (! cursor_shape_updates) {
   4439 				/* undo any cursor shape requests */
   4440 				disable_cursor_shape_updates(screen);
   4441 			}
   4442 			if (screen && screen->clientHead) {
   4443 				int ret = check_user_input(dt, dtr, tile_diffs, &cnt);
   4444 				/* true: loop back for more input */
   4445 				if (ret == 2) {
   4446 					skip_pe = 1;
   4447 				}
   4448 				if (ret) {
   4449 					if (debug_scroll) fprintf(stderr, "watch_loop: LOOP-BACK: %d\n", ret);
   4450 					continue;
   4451 				}
   4452 			}
   4453 			/* watch for viewonly input piling up: */
   4454 			if ((got_pointer_calls > got_pointer_input) ||
   4455 			    (got_keyboard_calls > got_keyboard_input)) {
   4456 				eat_viewonly_input(10, 3);
   4457 			}
   4458 		} else {
   4459 			/* -threads here. */
   4460 			if (unixpw_in_progress) {
   4461 				rfbClientPtr cl = unixpw_client;
   4462 				if (cl && cl->onHold) {
   4463 					rfbLog(msg, cl->host);
   4464 					unixpw_client->onHold = FALSE;
   4465 				}
   4466 			}
   4467 			if (use_xrecord) {
   4468 				check_xrecord();
   4469 			}
   4470 			if (wireframe && button_mask) {
   4471 				check_wireframe();
   4472 			}
   4473 		}
   4474 		skip_pe = 0;
   4475 
   4476 		if (shut_down) {
   4477 			clean_up_exit(0);
   4478 		}
   4479 
   4480 		if (unixpw_in_progress) {
   4481 			check_new_clients();
   4482 			continue;
   4483 		}
   4484 
   4485 		if (! urgent_update) {
   4486 			if (do_copy_screen) {
   4487 				do_copy_screen = 0;
   4488 				copy_screen();
   4489 			}
   4490 
   4491 			check_new_clients();
   4492 			check_ncache(0, 0);
   4493 			check_xevents(0);
   4494 			check_autorepeat();
   4495 			check_pm();
   4496 			check_filexfer();
   4497 			check_keycode_state();
   4498 			check_connect_inputs();
   4499 			check_gui_inputs();
   4500 			check_stunnel();
   4501 			check_openssl();
   4502 			check_https();
   4503 			record_last_fb_update();
   4504 			check_padded_fb();
   4505 			check_fixscreen();
   4506 			check_xdamage_state();
   4507 			check_xrecord_reset(0);
   4508 			check_add_keysyms();
   4509 			check_new_passwds(0);
   4510 #ifdef ENABLE_GRABLOCAL
   4511 			if (grab_local) {
   4512 				check_local_grab();
   4513 			}
   4514 #endif
   4515 			if (started_as_root) {
   4516 				check_switched_user();
   4517 			}
   4518 
   4519 			if (first_conn_timeout < 0) {
   4520 				start = time(NULL);
   4521 				first_conn_timeout = -first_conn_timeout;
   4522 			}
   4523 		}
   4524 
   4525 		if (rawfb_vnc_reflect) {
   4526 			static time_t lastone = 0;
   4527 			if (time(NULL) > lastone + 10) {
   4528 				lastone = time(NULL);
   4529 				vnc_reflect_process_client();
   4530 			}
   4531 		}
   4532 
   4533 		if (first_conn_timeout) {
   4534 			int t = first_conn_timeout;
   4535 			if (!clients_served) {
   4536 				if (time(NULL) - start > first_conn_timeout) {
   4537 					rfbLog("No client after %d secs.\n", t);
   4538 					shut_down = 1;
   4539 				}
   4540 			} else {
   4541 				if (!client_normal_count) {
   4542 					if (time(NULL) - start > t + 3) {
   4543 						rfbLog("No valid client after %d secs.\n", t + 3);
   4544 						shut_down = 1;
   4545 					}
   4546 				}
   4547 			}
   4548 		}
   4549 
   4550 		if (! screen || ! screen->clientHead) {
   4551 			/* waiting for a client */
   4552 			usleep(200 * 1000);
   4553 			continue;
   4554 		}
   4555 
   4556 		if (first_conn_timeout && all_clients_initialized()) {
   4557 			first_conn_timeout = 0;
   4558 		}
   4559 
   4560 		if (nofb) {
   4561 			/* no framebuffer polling needed */
   4562 			if (cursor_pos_updates) {
   4563 				check_x11_pointer();
   4564 			}
   4565 #ifdef MACOSX
   4566 			else check_x11_pointer();
   4567 #endif
   4568 			continue;
   4569 		}
   4570 		if (x11vnc_current < last_new_client + 0.5 && !all_clients_initialized()) {
   4571 			continue;
   4572 		}
   4573 		if (subwin && freeze_when_obscured) {
   4574 			/* XXX not working */
   4575 			X_LOCK;
   4576 			XFlush_wr(dpy);
   4577 			X_UNLOCK;
   4578 			check_xevents(0);
   4579 			if (subwin_obscured) {
   4580 				skip_scan_for_updates = 1;
   4581 			}
   4582 		}
   4583 
   4584 		if (skip_scan_for_updates) {
   4585 			;
   4586 		} else if (button_mask && (!show_dragging || pointer_mode == 0)) {
   4587 			/*
   4588 			 * if any button is pressed in this mode do
   4589 			 * not update rfb screen, but do flush the
   4590 			 * X11 display.
   4591 			 */
   4592 			X_LOCK;
   4593 			XFlush_wr(dpy);
   4594 			X_UNLOCK;
   4595 			dt = 0.0;
   4596 		} else {
   4597 			static double last_dt = 0.0;
   4598 			double xdamage_thrash = 0.4;
   4599 			static int tilecut = -1;
   4600 
   4601 			check_cursor_changes();
   4602 
   4603 			/* for timing the scan to try to detect thrashing */
   4604 
   4605 			if (use_xdamage && last_dt > xdamage_thrash)  {
   4606 				clear_xdamage_mark_region(NULL, 0);
   4607 			}
   4608 
   4609 			if (unixpw_in_progress) continue;
   4610 
   4611 			if (rawfb_vnc_reflect) {
   4612 				vnc_reflect_process_client();
   4613 			}
   4614 
   4615 			dtime0(&tm);
   4616 
   4617 #if !NO_X11
   4618 			if (xrandr_present && !xrandr && xrandr_maybe) {
   4619 				int delay = 180;
   4620 				/*  there may be xrandr right after xsession start */
   4621 				if (tm < x11vnc_start + delay || tm < last_client + delay) {
   4622 					int tw = 20;
   4623 					if (auth_file != NULL) {
   4624 						tw = 120;
   4625 					}
   4626 					X_LOCK;
   4627 					if (tm < x11vnc_start + tw || tm < last_client + tw) {
   4628 						XSync(dpy, False);
   4629 					} else {
   4630 						XFlush_wr(dpy);
   4631 					}
   4632 					X_UNLOCK;
   4633 				}
   4634 				X_LOCK;
   4635 				check_xrandr_event("before-scan");
   4636 				X_UNLOCK;
   4637 			}
   4638 #endif
   4639 			if (use_snapfb) {
   4640 				int t, tries = 3;
   4641 				copy_snap();
   4642 				for (t=0; t < tries; t++) {
   4643 					tile_diffs = scan_for_updates(0);
   4644 				}
   4645 			} else {
   4646 				tile_diffs = scan_for_updates(0);
   4647 			}
   4648 			dt = dtime(&tm);
   4649 			if (! nap_ok) {
   4650 				last_dt = dt;
   4651 			}
   4652 
   4653 			if (tilecut < 0) {
   4654 				if (getenv("TILECUT")) {
   4655 					tilecut = atoi(getenv("TILECUT"));
   4656 				}
   4657 				if (tilecut < 0) tilecut = 4;
   4658 			}
   4659 
   4660 			if ((debug_tiles || debug_scroll > 1 || debug_wireframe > 1)
   4661 			    && (tile_diffs > tilecut || debug_tiles > 1)) {
   4662 				double rate = (tile_x * tile_y * bpp/8 * tile_diffs) / dt;
   4663 				fprintf(stderr, "============================= TILES: %d  dt: %.4f"
   4664 				    "  t: %.4f  %.2f MB/s nap_ok: %d\n", tile_diffs, dt,
   4665 				    tm - x11vnc_start, rate/1000000.0, nap_ok);
   4666 			}
   4667 
   4668 		}
   4669 
   4670 		/* sleep a bit to lessen load */
   4671 		wait = choose_delay(dt);
   4672 
   4673 		if (urgent_update) {
   4674 			;
   4675 		} else if (wait > 2*waitms) {
   4676 			/* bog case, break it up */
   4677 			nap_sleep(wait, 10);
   4678 		} else {
   4679 			double t1, t2;
   4680 			int idt;
   4681 			if (extra_fbur > 0) {
   4682 				int i;
   4683 				for (i=0; i <= extra_fbur; i++) {
   4684 					int r = rfbPE(0);
   4685 					if (!r) break;
   4686 				}
   4687 			}
   4688 
   4689 			/* sometimes the sleep is too short, so measure it: */
   4690 			t1 = dnow();
   4691 			usleep(wait * 1000);
   4692 			t2 = dnow();
   4693 
   4694 			idt = (int) (1000. * (t2 - t1));
   4695 			if (idt > 0 && idt < wait) {
   4696 				/* try to sleep the remainder */
   4697 				usleep((wait - idt) * 1000);
   4698 			}
   4699 		}
   4700 
   4701 		cnt++;
   4702 	}
   4703 }
   4704 
   4705 
   4706