blob: d0851f63979fe39370a595cd2ad43897925d4e1b [file] [log] [blame]
San Mehata430b2b2014-09-23 08:30:51 -07001/*
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