1/*
2   Copyright (C) 2002-2010 Karl J. Runge <runge@karlrunge.com>
3   All rights reserved.
4
5This file is part of x11vnc.
6
7x11vnc is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2 of the License, or (at
10your option) any later version.
11
12x11vnc is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with x11vnc; if not, write to the Free Software
19Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
20or see <http://www.gnu.org/licenses/>.
21
22In addition, as a special exception, Karl J. Runge
23gives permission to link the code of its release of x11vnc with the
24OpenSSL project's "OpenSSL" library (or with modified versions of it
25that use the same license as the "OpenSSL" library), and distribute
26the linked executables.  You must obey the GNU General Public License
27in all respects for all of the code used other than "OpenSSL".  If you
28modify this file, you may extend this exception to your version of the
29file, but you are not obligated to do so.  If you do not wish to do
30so, 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
67void set_greyscale_colormap(void);
68void set_hi240_colormap(void);
69void unset_colormap(void);
70void set_colormap(int reset);
71void set_nofb_params(int restore);
72void set_raw_fb_params(int restore);
73void do_new_fb(int reset_mem);
74void free_old_fb(void);
75void check_padded_fb(void);
76void install_padded_fb(char *geom);
77XImage *initialize_xdisplay_fb(void);
78void 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);
80int parse_rotate_string(char *str, int *mode);
81int scale_round(int len, double fac);
82void initialize_screen(int *argc, char **argv, XImage *fb);
83void set_vnc_desktop_name(void);
84void announce(int lport, int ssl, char *iface);
85
86char *vnc_reflect_guess(char *str, char **raw_fb_addr);
87void vnc_reflect_process_client(void);
88rfbBool vnc_reflect_send_pointer(int x, int y, int mask);
89rfbBool vnc_reflect_send_key(uint32_t key, rfbBool down);
90rfbBool vnc_reflect_send_cuttext(char *str, int len);
91
92static void debug_colormap(XImage *fb);
93static void set_visual(char *str);
94static void nofb_hook(rfbClientPtr cl);
95static void remove_fake_fb(void);
96static void install_fake_fb(int w, int h, int bpp);
97static void initialize_snap_fb(void);
98XImage *initialize_raw_fb(int);
99static void initialize_clipshift(void);
100static int wait_until_mapped(Window win);
101static void setup_scaling(int *width_in, int *height_in);
102
103static void check_filexfer(void);
104static void record_last_fb_update(void);
105static void check_cursor_changes(void);
106static int choose_delay(double dt);
107
108int rawfb_reset = -1;
109int rawfb_dev_video = 0;
110int 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 */
123void 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
134if (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 */
153void set_hi240_colormap(void) {
154	int i;
155	if (! screen) {
156		return;
157	}
158	/* mutex */
159if (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 */
187void 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;
196if (0) fprintf(stderr, "unset_colormap: %s\n", raw_fb_pixfmt);
197}
198
199/* this is X11 case */
200void 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
367static 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 */
425static 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
509void 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
603static char *raw_fb_orig_dpy = NULL;
604
605void 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 */
763static 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
789void 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
821static char _lcs_tmp[128];
822static int _bytes0_size = 128, _bytes0[128];
823
824static 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
838static 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
889static 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
987static 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
1006void 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
1068static 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
1083static 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
1092static 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
1116void 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
1127void 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
1149static 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
1159static rfbClient* client = NULL;
1160
1161void 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
1178void 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
1193void 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
1205void 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
1273rfbBool 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
1295static 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
1337void 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
1365rfbBool 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
1381static 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) {}
1390if (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) {
1404if (db) fprintf(stderr, "cert: %s\n", cert);
1405if (db) fprintf(stderr, "ccrl: %s\n", ccrl);
1406if (db) fprintf(stderr, "clic: %s\n", clic);
1407if (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
1423static 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
1458char *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
1566rfbBool 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
1596rfbBool vnc_reflect_send_key(uint32_t key, rfbBool down) {
1597	return SendKeyEvent(client, key, down);
1598}
1599
1600rfbBool vnc_reflect_send_cuttext(char *str, int len) {
1601	return SendClientCutText(client, str, len);
1602}
1603
1604void 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
1618void 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
1640XImage *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;
1666if (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
2372static 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
2414static 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 */
2446XImage *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	}
2545if (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
2589if (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
2800void 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
2923int 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
2952int 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
2962static 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
3023static 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
3045static 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 */
3064void 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
3761void 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
3825static 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
3857void 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
3899void 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
3928void 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
4014static 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
4068static 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
4109static 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
4158static 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
4249if (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 */
4354void 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