|  | /* | 
|  | Copyright (C) 2002-2010 Karl J. Runge <[email protected]> | 
|  | All rights reserved. | 
|  |  | 
|  | This file is part of x11vnc. | 
|  |  | 
|  | x11vnc is free software; you can redistribute it and/or modify | 
|  | it under the terms of the GNU General Public License as published by | 
|  | the Free Software Foundation; either version 2 of the License, or (at | 
|  | your option) any later version. | 
|  |  | 
|  | x11vnc is distributed in the hope that it will be useful, | 
|  | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | GNU General Public License for more details. | 
|  |  | 
|  | You should have received a copy of the GNU General Public License | 
|  | along with x11vnc; if not, write to the Free Software | 
|  | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA | 
|  | or see <http://www.gnu.org/licenses/>. | 
|  |  | 
|  | In addition, as a special exception, Karl J. Runge | 
|  | gives permission to link the code of its release of x11vnc with the | 
|  | OpenSSL project's "OpenSSL" library (or with modified versions of it | 
|  | that use the same license as the "OpenSSL" library), and distribute | 
|  | the linked executables.  You must obey the GNU General Public License | 
|  | in all respects for all of the code used other than "OpenSSL".  If you | 
|  | modify this file, you may extend this exception to your version of the | 
|  | file, but you are not obligated to do so.  If you do not wish to do | 
|  | so, delete this exception statement from your version. | 
|  | */ | 
|  |  | 
|  | /* -- screen.c -- */ | 
|  |  | 
|  | #include "x11vnc.h" | 
|  | #include "xevents.h" | 
|  | #include "xwrappers.h" | 
|  | #include "xinerama.h" | 
|  | #include "xdamage.h" | 
|  | #include "win_utils.h" | 
|  | #include "cleanup.h" | 
|  | #include "userinput.h" | 
|  | #include "scan.h" | 
|  | #include "user.h" | 
|  | #include "rates.h" | 
|  | #include "pointer.h" | 
|  | #include "keyboard.h" | 
|  | #include "cursor.h" | 
|  | #include "connections.h" | 
|  | #include "remote.h" | 
|  | #include "unixpw.h" | 
|  | #include "sslcmds.h" | 
|  | #include "sslhelper.h" | 
|  | #include "v4l.h" | 
|  | #include "linuxfb.h" | 
|  | #include "macosx.h" | 
|  | #include "macosxCG.h" | 
|  | #include "avahi.h" | 
|  | #include "solid.h" | 
|  | #include "inet.h" | 
|  | #include "xrandr.h" | 
|  | #include "xrecord.h" | 
|  | #include "pm.h" | 
|  |  | 
|  | #include <rfb/rfbclient.h> | 
|  |  | 
|  | void set_greyscale_colormap(void); | 
|  | void set_hi240_colormap(void); | 
|  | void unset_colormap(void); | 
|  | void set_colormap(int reset); | 
|  | void set_nofb_params(int restore); | 
|  | void set_raw_fb_params(int restore); | 
|  | void do_new_fb(int reset_mem); | 
|  | void free_old_fb(void); | 
|  | void check_padded_fb(void); | 
|  | void install_padded_fb(char *geom); | 
|  | XImage *initialize_xdisplay_fb(void); | 
|  | void parse_scale_string(char *str, double *factor_x, double *factor_y, int *scaling, int *blend, | 
|  | int *nomult4, int *pad, int *interpolate, int *numer, int *denom, int w_in, int h_in); | 
|  | int parse_rotate_string(char *str, int *mode); | 
|  | int scale_round(int len, double fac); | 
|  | void initialize_screen(int *argc, char **argv, XImage *fb); | 
|  | void set_vnc_desktop_name(void); | 
|  | void announce(int lport, int ssl, char *iface); | 
|  |  | 
|  | char *vnc_reflect_guess(char *str, char **raw_fb_addr); | 
|  | void vnc_reflect_process_client(void); | 
|  | rfbBool vnc_reflect_send_pointer(int x, int y, int mask); | 
|  | rfbBool vnc_reflect_send_key(uint32_t key, rfbBool down); | 
|  | rfbBool vnc_reflect_send_cuttext(char *str, int len); | 
|  |  | 
|  | static void debug_colormap(XImage *fb); | 
|  | static void set_visual(char *str); | 
|  | static void nofb_hook(rfbClientPtr cl); | 
|  | static void remove_fake_fb(void); | 
|  | static void install_fake_fb(int w, int h, int bpp); | 
|  | static void initialize_snap_fb(void); | 
|  | XImage *initialize_raw_fb(int); | 
|  | static void initialize_clipshift(void); | 
|  | static int wait_until_mapped(Window win); | 
|  | static void setup_scaling(int *width_in, int *height_in); | 
|  |  | 
|  | static void check_filexfer(void); | 
|  | static void record_last_fb_update(void); | 
|  | static void check_cursor_changes(void); | 
|  | static int choose_delay(double dt); | 
|  |  | 
|  | int rawfb_reset = -1; | 
|  | int rawfb_dev_video = 0; | 
|  | int rawfb_vnc_reflect = 0; | 
|  |  | 
|  | /* | 
|  | * X11 and rfb display/screen related routines | 
|  | */ | 
|  |  | 
|  | /* | 
|  | * Some handling of 8bpp PseudoColor colormaps.  Called for initializing | 
|  | * the clients and dynamically if -flashcmap is specified. | 
|  | */ | 
|  | #define NCOLOR 256 | 
|  |  | 
|  | /* this is only for rawfb */ | 
|  | void set_greyscale_colormap(void) { | 
|  | int i; | 
|  | if (! screen) { | 
|  | return; | 
|  | } | 
|  | /* mutex */ | 
|  | if (screen->colourMap.data.shorts) { | 
|  | free(screen->colourMap.data.shorts); | 
|  | screen->colourMap.data.shorts = NULL; | 
|  | } | 
|  |  | 
|  | if (0) fprintf(stderr, "set_greyscale_colormap: %s\n", raw_fb_pixfmt); | 
|  | screen->colourMap.count = NCOLOR; | 
|  | screen->serverFormat.trueColour = FALSE; | 
|  | screen->colourMap.is16 = TRUE; | 
|  | screen->colourMap.data.shorts = (unsigned short *) | 
|  | malloc(3*sizeof(unsigned short) * NCOLOR); | 
|  |  | 
|  | for(i = 0; i < NCOLOR; i++) { | 
|  | unsigned short lvl = i * 256; | 
|  |  | 
|  | screen->colourMap.data.shorts[i*3+0] = lvl; | 
|  | screen->colourMap.data.shorts[i*3+1] = lvl; | 
|  | screen->colourMap.data.shorts[i*3+2] = lvl; | 
|  | } | 
|  |  | 
|  | rfbSetClientColourMaps(screen, 0, NCOLOR); | 
|  | } | 
|  |  | 
|  | /* this is specific to bttv rf tuner card */ | 
|  | void set_hi240_colormap(void) { | 
|  | int i; | 
|  | if (! screen) { | 
|  | return; | 
|  | } | 
|  | /* mutex */ | 
|  | if (0) fprintf(stderr, "set_hi240_colormap: %s\n", raw_fb_pixfmt); | 
|  | if (screen->colourMap.data.shorts) { | 
|  | free(screen->colourMap.data.shorts); | 
|  | screen->colourMap.data.shorts = NULL; | 
|  | } | 
|  |  | 
|  | screen->colourMap.count = 256; | 
|  | screen->serverFormat.trueColour = FALSE; | 
|  | screen->colourMap.is16 = TRUE; | 
|  | screen->colourMap.data.shorts = (unsigned short *) | 
|  | calloc(3*sizeof(unsigned short) * 256, 1); | 
|  |  | 
|  | for(i = 0; i < 225; i++) { | 
|  | int r, g, b; | 
|  |  | 
|  | r = ( (i/5) % 5 ) * 255.0 / 4 + 0.5; | 
|  | g = ( (i/25)    ) * 255.0 / 8 + 0.5; | 
|  | b = ( i % 5     ) * 255.0 / 4 + 0.5; | 
|  |  | 
|  | screen->colourMap.data.shorts[(i+16)*3+0] = (unsigned short) (r * 256); | 
|  | screen->colourMap.data.shorts[(i+16)*3+1] = (unsigned short) (g * 256); | 
|  | screen->colourMap.data.shorts[(i+16)*3+2] = (unsigned short) (b * 256); | 
|  | } | 
|  |  | 
|  | rfbSetClientColourMaps(screen, 0, 256); | 
|  | } | 
|  |  | 
|  | /* this is only for rawfb */ | 
|  | void unset_colormap(void) { | 
|  | if (! screen) { | 
|  | return; | 
|  | } | 
|  | if (screen->colourMap.data.shorts) { | 
|  | free(screen->colourMap.data.shorts); | 
|  | screen->colourMap.data.shorts = NULL; | 
|  | } | 
|  | screen->serverFormat.trueColour = TRUE; | 
|  | if (0) fprintf(stderr, "unset_colormap: %s\n", raw_fb_pixfmt); | 
|  | } | 
|  |  | 
|  | /* this is X11 case */ | 
|  | void set_colormap(int reset) { | 
|  |  | 
|  | #if NO_X11 | 
|  | if (!reset) {} | 
|  | return; | 
|  | #else | 
|  | static int init = 1; | 
|  | static XColor *color = NULL, *prev = NULL; | 
|  | static int ncolor = 0; | 
|  | Colormap cmap; | 
|  | Visual *vis; | 
|  | int i, ncells, diffs = 0; | 
|  |  | 
|  | if (reset) { | 
|  | init = 1; | 
|  | ncolor = 0; | 
|  | /* mutex */ | 
|  | if (screen->colourMap.data.shorts) { | 
|  | free(screen->colourMap.data.shorts); | 
|  | screen->colourMap.data.shorts = NULL; | 
|  | } | 
|  | if (color) { | 
|  | free(color); | 
|  | color = NULL; | 
|  | } | 
|  | if (prev) { | 
|  | free(prev); | 
|  | prev = NULL; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (init) { | 
|  | if (depth > 16) { | 
|  | ncolor = NCOLOR; | 
|  | } else if (depth > 8) { | 
|  | ncolor = 1 << depth; | 
|  | } else { | 
|  | ncolor = NCOLOR; | 
|  | } | 
|  | /* mutex */ | 
|  | screen->colourMap.count = ncolor; | 
|  | screen->serverFormat.trueColour = FALSE; | 
|  | screen->colourMap.is16 = TRUE; | 
|  | screen->colourMap.data.shorts = (unsigned short *) | 
|  | malloc(3*sizeof(unsigned short) * ncolor); | 
|  | } | 
|  | if (color == NULL) { | 
|  | color = (XColor *) calloc(ncolor * sizeof(XColor), 1); | 
|  | prev  = (XColor *) calloc(ncolor * sizeof(XColor), 1); | 
|  | } | 
|  |  | 
|  | for (i=0; i < ncolor; i++) { | 
|  | prev[i].red   = color[i].red; | 
|  | prev[i].green = color[i].green; | 
|  | prev[i].blue  = color[i].blue; | 
|  | } | 
|  |  | 
|  | RAWFB_RET_VOID | 
|  |  | 
|  | X_LOCK; | 
|  |  | 
|  | cmap = DefaultColormap(dpy, scr); | 
|  | ncells = CellsOfScreen(ScreenOfDisplay(dpy, scr)); | 
|  | vis = default_visual; | 
|  |  | 
|  | if (subwin) { | 
|  | XWindowAttributes attr; | 
|  |  | 
|  | if (XGetWindowAttributes(dpy, window, &attr)) { | 
|  | cmap = attr.colormap; | 
|  | vis = attr.visual; | 
|  | ncells = vis->map_entries; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (ncells != ncolor) { | 
|  | if (! shift_cmap) { | 
|  | screen->colourMap.count = ncells; | 
|  | } | 
|  | } | 
|  | if (init && ! quiet) { | 
|  | rfbLog("set_colormap: number of cells: %d, " | 
|  | "ncolor(%d) is %d.\n", ncells, depth, ncolor); | 
|  | } | 
|  |  | 
|  | if (flash_cmap && ! init) { | 
|  | XWindowAttributes attr; | 
|  | Window c; | 
|  | int tries = 0; | 
|  |  | 
|  | c = window; | 
|  | while (c && tries++ < 16) { | 
|  | c = query_pointer(c); | 
|  | if (valid_window(c, &attr, 0)) { | 
|  | if (attr.colormap && attr.map_installed) { | 
|  | cmap = attr.colormap; | 
|  | vis = attr.visual; | 
|  | ncells = vis->map_entries; | 
|  | break; | 
|  | } | 
|  | } else { | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  | if (ncells > ncolor && ! quiet) { | 
|  | rfbLog("set_colormap: big problem: ncells=%d > %d\n", | 
|  | ncells, ncolor); | 
|  | } | 
|  |  | 
|  | if (vis->class == TrueColor || vis->class == DirectColor) { | 
|  | /* | 
|  | * Kludge to make 8bpp TrueColor & DirectColor be like | 
|  | * the StaticColor map.  The ncells = 8 is "8 per subfield" | 
|  | * mentioned in xdpyinfo.  Looks OK... perhaps fortuitously. | 
|  | */ | 
|  | if (ncells == 8 && ! shift_cmap) { | 
|  | ncells = ncolor; | 
|  | } | 
|  | } | 
|  |  | 
|  | for (i=0; i < ncells; i++) { | 
|  | color[i].pixel = i; | 
|  | color[i].pad = 0; | 
|  | } | 
|  |  | 
|  | XQueryColors(dpy, cmap, color, ncells); | 
|  |  | 
|  | X_UNLOCK; | 
|  |  | 
|  | for(i = ncells - 1; i >= 0; i--) { | 
|  | int k = i + shift_cmap; | 
|  |  | 
|  | screen->colourMap.data.shorts[i*3+0] = color[i].red; | 
|  | screen->colourMap.data.shorts[i*3+1] = color[i].green; | 
|  | screen->colourMap.data.shorts[i*3+2] = color[i].blue; | 
|  |  | 
|  | if (prev[i].red   != color[i].red || | 
|  | prev[i].green != color[i].green || | 
|  | prev[i].blue  != color[i].blue ) { | 
|  | diffs++; | 
|  | } | 
|  |  | 
|  | if (shift_cmap && k >= 0 && k < ncolor) { | 
|  | /* kludge to copy the colors to higher pixel values */ | 
|  | screen->colourMap.data.shorts[k*3+0] = color[i].red; | 
|  | screen->colourMap.data.shorts[k*3+1] = color[i].green; | 
|  | screen->colourMap.data.shorts[k*3+2] = color[i].blue; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (diffs && ! init) { | 
|  | if (! all_clients_initialized()) { | 
|  | rfbLog("set_colormap: warning: sending cmap " | 
|  | "with uninitialized clients.\n"); | 
|  | } | 
|  | if (shift_cmap) { | 
|  | rfbSetClientColourMaps(screen, 0, ncolor); | 
|  | } else { | 
|  | rfbSetClientColourMaps(screen, 0, ncells); | 
|  | } | 
|  | } | 
|  |  | 
|  | init = 0; | 
|  | #endif	/* NO_X11 */ | 
|  | } | 
|  |  | 
|  | static void debug_colormap(XImage *fb) { | 
|  | static int debug_cmap = -1; | 
|  | int i, k, *histo; | 
|  | int ncolor; | 
|  |  | 
|  | if (debug_cmap < 0) { | 
|  | if (getenv("DEBUG_CMAP") != NULL) { | 
|  | debug_cmap = 1; | 
|  | } else { | 
|  | debug_cmap = 0; | 
|  | } | 
|  | } | 
|  | if (! debug_cmap) { | 
|  | return; | 
|  | } | 
|  | if (! fb) { | 
|  | return; | 
|  | } | 
|  | if (fb->bits_per_pixel > 16) { | 
|  | return; | 
|  | } | 
|  | ncolor = screen->colourMap.count; | 
|  | histo = (int *) calloc(ncolor * sizeof(int), 1); | 
|  |  | 
|  | for (i=0; i < ncolor; i++) { | 
|  | histo[i] = 0; | 
|  | } | 
|  | for (k = 0; k < fb->width * fb->height; k++) { | 
|  | unsigned char n; | 
|  | char c = *(fb->data + k); | 
|  |  | 
|  | n = (unsigned char) c; | 
|  | histo[n]++; | 
|  | } | 
|  | fprintf(stderr, "\nColormap histogram for current screen contents:\n"); | 
|  | for (i=0; i < ncolor; i++) { | 
|  | unsigned short r = screen->colourMap.data.shorts[i*3+0]; | 
|  | unsigned short g = screen->colourMap.data.shorts[i*3+1]; | 
|  | unsigned short b = screen->colourMap.data.shorts[i*3+2]; | 
|  |  | 
|  | fprintf(stderr, "   %03d: %7d %04x/%04x/%04x", i, histo[i], | 
|  | r, g, b); | 
|  | if ((i+1) % 2 == 0)  { | 
|  | fprintf(stderr, "\n"); | 
|  | } | 
|  | } | 
|  | free(histo); | 
|  | fprintf(stderr, "\n"); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Experimental mode to force the visual of the window instead of querying | 
|  | * it.  Used for testing, overriding some rare cases (win2vnc), and for | 
|  | * -overlay .  Input string can be a decimal or 0x hex or something like | 
|  | * TrueColor or TrueColor:24 to force a depth as well. | 
|  | * | 
|  | * visual_id and possibly visual_depth are set. | 
|  | */ | 
|  | static void set_visual(char *str) { | 
|  | #if NO_X11 | 
|  | RAWFB_RET_VOID | 
|  | if (!str) {} | 
|  | return; | 
|  | #else | 
|  | int vis, vdepth, defdepth; | 
|  | XVisualInfo vinfo; | 
|  | char *p, *vstring = strdup(str); | 
|  |  | 
|  | RAWFB_RET_VOID | 
|  |  | 
|  | defdepth = DefaultDepth(dpy, scr); | 
|  | visual_id = (VisualID) 0; | 
|  | visual_depth = 0; | 
|  |  | 
|  | if (!strcmp(vstring, "ignore") || !strcmp(vstring, "default") | 
|  | || !strcmp(vstring, "")) { | 
|  | free(vstring); | 
|  | return; | 
|  | } | 
|  |  | 
|  | /* set visual depth */ | 
|  | if ((p = strchr(vstring, ':')) != NULL) { | 
|  | visual_depth = atoi(p+1); | 
|  | *p = '\0'; | 
|  | vdepth = visual_depth; | 
|  | } else { | 
|  | vdepth = defdepth; | 
|  | } | 
|  | if (! quiet) { | 
|  | fprintf(stderr, "\nVisual Info:\n"); | 
|  | fprintf(stderr, " set_visual(\"%s\")\n", str); | 
|  | fprintf(stderr, " visual_depth: %d\n", vdepth); | 
|  | } | 
|  |  | 
|  | /* set visual id number */ | 
|  | if (strcmp(vstring, "StaticGray") == 0) { | 
|  | vis = StaticGray; | 
|  | } else if (strcmp(vstring, "GrayScale") == 0) { | 
|  | vis = GrayScale; | 
|  | } else if (strcmp(vstring, "StaticColor") == 0) { | 
|  | vis = StaticColor; | 
|  | } else if (strcmp(vstring, "PseudoColor") == 0) { | 
|  | vis = PseudoColor; | 
|  | } else if (strcmp(vstring, "TrueColor") == 0) { | 
|  | vis = TrueColor; | 
|  | } else if (strcmp(vstring, "DirectColor") == 0) { | 
|  | vis = DirectColor; | 
|  | } else { | 
|  | unsigned int v_in; | 
|  | if (sscanf(vstring, "0x%x", &v_in) != 1) { | 
|  | if (sscanf(vstring, "%u", &v_in) == 1) { | 
|  | visual_id = (VisualID) v_in; | 
|  | return; | 
|  | } | 
|  | rfbLogEnable(1); | 
|  | rfbLog("invalid -visual arg: %s\n", vstring); | 
|  | X_UNLOCK; | 
|  | clean_up_exit(1); | 
|  | } | 
|  | visual_id = (VisualID) v_in; | 
|  | free(vstring); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (! quiet) fprintf(stderr, " visual: %d\n", vis); | 
|  | if (XMatchVisualInfo(dpy, scr, visual_depth, vis, &vinfo)) { | 
|  | ; | 
|  | } else if (XMatchVisualInfo(dpy, scr, defdepth, vis, &vinfo)) { | 
|  | ; | 
|  | } else { | 
|  | rfbLogEnable(1); | 
|  | rfbLog("could not find visual: %s\n", vstring); | 
|  | X_UNLOCK; | 
|  | clean_up_exit(1); | 
|  | } | 
|  | free(vstring); | 
|  |  | 
|  | /* set numerical visual id. */ | 
|  | visual_id = vinfo.visualid; | 
|  | #endif	/* NO_X11 */ | 
|  | } | 
|  |  | 
|  | void set_nofb_params(int restore) { | 
|  | static int first = 1; | 
|  | static int save[100]; | 
|  | static char *scroll = NULL; | 
|  | int i = 0; | 
|  |  | 
|  | if (first) { | 
|  | first = 0; | 
|  | save[i++] = use_xfixes; | 
|  | save[i++] = use_xdamage; | 
|  | save[i++] = use_xrecord; | 
|  | save[i++] = wireframe; | 
|  | save[i++] = use_solid_bg; | 
|  | save[i++] = overlay; | 
|  | save[i++] = overlay_cursor; | 
|  | save[i++] = using_shm; | 
|  | save[i++] = single_copytile; | 
|  | save[i++] = take_naps; | 
|  | save[i++] = measure_speeds; | 
|  | save[i++] = grab_buster; | 
|  | save[i++] = show_cursor; | 
|  | save[i++] = cursor_shape_updates; | 
|  | save[i++] = cursor_pos_updates; | 
|  | save[i++] = ncache; | 
|  |  | 
|  | scroll = scroll_copyrect; | 
|  | } | 
|  | if (restore) { | 
|  | i = 0; | 
|  | use_xfixes            = save[i++]; | 
|  | use_xdamage           = save[i++]; | 
|  | use_xrecord           = save[i++]; | 
|  | wireframe             = save[i++]; | 
|  | use_solid_bg          = save[i++]; | 
|  | overlay               = save[i++]; | 
|  | overlay_cursor        = save[i++]; | 
|  | using_shm             = save[i++]; | 
|  | single_copytile       = save[i++]; | 
|  | take_naps             = save[i++]; | 
|  | measure_speeds        = save[i++]; | 
|  | grab_buster           = save[i++]; | 
|  | show_cursor           = save[i++]; | 
|  | cursor_shape_updates  = save[i++]; | 
|  | cursor_pos_updates    = save[i++]; | 
|  | ncache                = save[i++]; | 
|  |  | 
|  | scroll_copyrect = scroll; | 
|  |  | 
|  | if (cursor_shape_updates) { | 
|  | restore_cursor_shape_updates(screen); | 
|  | } | 
|  | initialize_cursors_mode(); | 
|  |  | 
|  | return; | 
|  | } | 
|  |  | 
|  | use_xfixes = 0; | 
|  | use_xdamage = 0; | 
|  | use_xrecord = 0; | 
|  | wireframe = 0; | 
|  |  | 
|  | use_solid_bg = 0; | 
|  | overlay = 0; | 
|  | overlay_cursor = 0; | 
|  |  | 
|  | using_shm = 0; | 
|  | single_copytile = 1; | 
|  |  | 
|  | take_naps = 0; | 
|  | measure_speeds = 0; | 
|  |  | 
|  | /* got_grab_buster? */ | 
|  | grab_buster = 0; | 
|  |  | 
|  | show_cursor = 0; | 
|  | show_multiple_cursors = 0; | 
|  | cursor_shape_updates = 0; | 
|  | if (! got_cursorpos) { | 
|  | cursor_pos_updates = 0; | 
|  | } | 
|  |  | 
|  | ncache = 0; | 
|  |  | 
|  | scroll_copyrect = "never"; | 
|  |  | 
|  | if (! quiet) { | 
|  | rfbLog("disabling: xfixes, xdamage, solid, overlay, shm,\n"); | 
|  | rfbLog("  wireframe, scrollcopyrect, ncache,\n"); | 
|  | rfbLog("  noonetile, nap, cursor, %scursorshape\n", | 
|  | got_cursorpos ? "" : "cursorpos, " ); | 
|  | rfbLog("  in -nofb mode.\n"); | 
|  | } | 
|  | } | 
|  |  | 
|  | static char *raw_fb_orig_dpy = NULL; | 
|  |  | 
|  | void set_raw_fb_params(int restore) { | 
|  | static int first = 1; | 
|  | static int vo0, us0, sm0, ws0, wp0, wc0, wb0, na0, tn0; | 
|  | static int xr0, xrm0, sb0, re0; | 
|  | static char *mc0; | 
|  |  | 
|  | /* | 
|  | * set turn off a bunch of parameters not compatible with | 
|  | * -rawfb mode: 1) ignoring the X server 2) ignoring user input. | 
|  | */ | 
|  |  | 
|  | if (first) { | 
|  | /* at least save the initial settings... */ | 
|  | vo0 = view_only; | 
|  | ws0 = watch_selection; | 
|  | wp0 = watch_primary; | 
|  | wc0 = watch_clipboard; | 
|  | wb0 = watch_bell; | 
|  | na0 = no_autorepeat; | 
|  | sb0 = use_solid_bg; | 
|  |  | 
|  | us0 = use_snapfb; | 
|  | sm0 = using_shm; | 
|  | tn0 = take_naps; | 
|  | xr0 = xrandr; | 
|  | xrm0 = xrandr_maybe; | 
|  | re0 = noxrecord; | 
|  | mc0 = multiple_cursors_mode; | 
|  |  | 
|  | first = 0; | 
|  | } | 
|  |  | 
|  | if (restore) { | 
|  | view_only = vo0; | 
|  | watch_selection = ws0; | 
|  | watch_primary = wp0; | 
|  | watch_clipboard = wc0; | 
|  | watch_bell = wb0; | 
|  | no_autorepeat = na0; | 
|  | use_solid_bg = sb0; | 
|  |  | 
|  | use_snapfb = us0; | 
|  | using_shm = sm0; | 
|  | take_naps = tn0; | 
|  | xrandr = xr0; | 
|  | xrandr_maybe = xrm0; | 
|  | noxrecord = re0; | 
|  | multiple_cursors_mode = mc0; | 
|  |  | 
|  | if (! dpy && raw_fb_orig_dpy) { | 
|  | dpy = XOpenDisplay_wr(raw_fb_orig_dpy); | 
|  | last_open_xdisplay = time(NULL); | 
|  | if (dpy) { | 
|  | if (! quiet) rfbLog("reopened DISPLAY: %s\n", | 
|  | raw_fb_orig_dpy); | 
|  | scr = DefaultScreen(dpy); | 
|  | rootwin = RootWindow(dpy, scr); | 
|  | check_xevents(1); | 
|  | } else { | 
|  | if (! quiet) rfbLog("WARNING: failed to reopen " | 
|  | "DISPLAY: %s\n", raw_fb_orig_dpy); | 
|  | } | 
|  | } | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (verbose) { | 
|  | rfbLog("set_raw_fb_params: modifying settings for " | 
|  | "-rawfb mode.\n"); | 
|  | } | 
|  |  | 
|  | if (got_noviewonly) { | 
|  | /* | 
|  | * The user input parameters are not unset under | 
|  | * -noviewonly... this usage should be very rare | 
|  | * (i.e. rawfb but also send user input to the X | 
|  | * display, most likely using /dev/fb0 for some reason...) | 
|  | */ | 
|  | if (verbose) { | 
|  | rfbLog("rawfb: -noviewonly mode: still sending mouse and\n"); | 
|  | rfbLog("rawfb:   keyboard input to the X DISPLAY!!\n"); | 
|  | } | 
|  | } else { | 
|  | /* Normal case: */ | 
|  | #if 0 | 
|  | if (! view_only && ! pipeinput_str) { | 
|  | if (! quiet) rfbLog("  rawfb: setting view_only\n"); | 
|  | view_only = 1; | 
|  | } | 
|  | #endif | 
|  | if (raw_fb_str && strstr(raw_fb_str, "vnc") == raw_fb_str) { | 
|  | ; | 
|  | } else if (watch_selection) { | 
|  | if (verbose) rfbLog("  rawfb: turning off " | 
|  | "watch_selection\n"); | 
|  | watch_selection = 0; | 
|  | } | 
|  | if (watch_primary) { | 
|  | if (verbose) rfbLog("  rawfb: turning off " | 
|  | "watch_primary\n"); | 
|  | watch_primary = 0; | 
|  | } | 
|  | if (watch_clipboard) { | 
|  | if (verbose) rfbLog("  rawfb: turning off " | 
|  | "watch_clipboard\n"); | 
|  | watch_clipboard = 0; | 
|  | } | 
|  | if (watch_bell) { | 
|  | if (verbose) rfbLog("  rawfb: turning off watch_bell\n"); | 
|  | watch_bell = 0; | 
|  | } | 
|  | if (no_autorepeat) { | 
|  | if (verbose) rfbLog("  rawfb: turning off " | 
|  | "no_autorepeat\n"); | 
|  | no_autorepeat = 0; | 
|  | } | 
|  | if (use_solid_bg) { | 
|  | if (verbose) rfbLog("  rawfb: turning off " | 
|  | "use_solid_bg\n"); | 
|  | use_solid_bg = 0; | 
|  | } | 
|  | #ifndef MACOSX | 
|  | if (raw_fb_str && strstr(raw_fb_str, "vnc") == raw_fb_str) { | 
|  | ; | 
|  | } else { | 
|  | multiple_cursors_mode = strdup("arrow"); | 
|  | } | 
|  | #endif | 
|  | } | 
|  | if (using_shm) { | 
|  | if (verbose) rfbLog("  rawfb: turning off using_shm\n"); | 
|  | using_shm = 0; | 
|  | } | 
|  | if (take_naps) { | 
|  | if (verbose) rfbLog("  rawfb: turning off take_naps\n"); | 
|  | take_naps = 0; | 
|  | } | 
|  | if (xrandr) { | 
|  | if (verbose) rfbLog("  rawfb: turning off xrandr\n"); | 
|  | xrandr = 0; | 
|  | } | 
|  | if (xrandr_maybe) { | 
|  | if (verbose) rfbLog("  rawfb: turning off xrandr_maybe\n"); | 
|  | xrandr_maybe = 0; | 
|  | } | 
|  | if (! noxrecord) { | 
|  | if (verbose) rfbLog("  rawfb: turning off xrecord\n"); | 
|  | noxrecord = 1; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Presumably under -nofb the clients will never request the framebuffer. | 
|  | * However, we have gotten such a request... so let's just give them | 
|  | * the current view on the display.  n.b. x2vnc and perhaps win2vnc | 
|  | * requests a 1x1 pixel for some workaround so sadly this evidently | 
|  | * nearly always happens. | 
|  | */ | 
|  | static void nofb_hook(rfbClientPtr cl) { | 
|  | XImage *fb; | 
|  | XImage raw; | 
|  |  | 
|  | rfbLog("framebuffer requested in -nofb mode by client %s\n", cl->host); | 
|  | /* ignore xrandr */ | 
|  |  | 
|  | if (raw_fb && ! dpy) { | 
|  | fb = &raw; | 
|  | fb->data = (char *)malloc(32); | 
|  | } else { | 
|  | int use_real_ximage = 0; | 
|  | if (use_real_ximage) { | 
|  | fb = XGetImage_wr(dpy, window, 0, 0, dpy_x, dpy_y, AllPlanes, ZPixmap); | 
|  | } else { | 
|  | fb = &raw; | 
|  | fb->data = (char *) calloc(dpy_x*dpy_y*bpp/8, 1); | 
|  | } | 
|  | } | 
|  | main_fb = fb->data; | 
|  | rfb_fb = main_fb; | 
|  | /* mutex */ | 
|  | screen->frameBuffer = rfb_fb; | 
|  | screen->displayHook = NULL; | 
|  | } | 
|  |  | 
|  | void free_old_fb(void) { | 
|  | char *fbs[16]; | 
|  | int i, j, nfb = 0, db = 0; | 
|  |  | 
|  | fbs[nfb++] = main_fb;		main_fb = NULL; | 
|  | fbs[nfb++] = rfb_fb;		rfb_fb = NULL; | 
|  | fbs[nfb++] = cmap8to24_fb;	cmap8to24_fb = NULL; | 
|  | fbs[nfb++] = snap_fb;		snap_fb = NULL; | 
|  | fbs[nfb++] = rot_fb;		rot_fb = NULL; | 
|  | fbs[nfb++] = raw_fb;		raw_fb = NULL; | 
|  |  | 
|  | for (i=0; i < nfb; i++) { | 
|  | char *fb = fbs[i]; | 
|  | int freeit = 1; | 
|  | if (! fb || fb < (char *) 0x10) { | 
|  | continue; | 
|  | } | 
|  | for (j=0; j < i; j++) { | 
|  | if (fb == fbs[j]) { | 
|  | freeit = 0; | 
|  | break; | 
|  | } | 
|  | } | 
|  | if (freeit) { | 
|  | if (db) fprintf(stderr, "free: %i %p\n", i, fb); | 
|  | free(fb); | 
|  | } else { | 
|  | if (db) fprintf(stderr, "skip: %i %p\n", i, fb); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static char _lcs_tmp[128]; | 
|  | static int _bytes0_size = 128, _bytes0[128]; | 
|  |  | 
|  | static char *lcs(rfbClientPtr cl) { | 
|  | sprintf(_lcs_tmp, "%d/%d/%d/%d/%d-%d/%d/%d", | 
|  | !!(cl->newFBSizePending), | 
|  | !!(cl->cursorWasChanged), | 
|  | !!(cl->cursorWasMoved), | 
|  | !!(cl->reverseConnection), | 
|  | cl->state, | 
|  | cl->modifiedRegion  ? !!(sraRgnEmpty(cl->modifiedRegion))  : 2, | 
|  | cl->requestedRegion ? !!(sraRgnEmpty(cl->requestedRegion)) : 2, | 
|  | cl->copyRegion      ? !!(sraRgnEmpty(cl->copyRegion))      : 2 | 
|  | ); | 
|  | return _lcs_tmp; | 
|  | } | 
|  |  | 
|  | static int lock_client_sends(int lock) { | 
|  | static rfbClientPtr *cls = NULL; | 
|  | static int cls_len = 0; | 
|  | static int blocked = 0; | 
|  | static int state = 0; | 
|  | rfbClientIteratorPtr iter; | 
|  | rfbClientPtr cl; | 
|  | char *s; | 
|  |  | 
|  | if (!use_threads || !screen) { | 
|  | return 0; | 
|  | } | 
|  | if (lock < 0) { | 
|  | return state; | 
|  | } | 
|  | state = lock; | 
|  |  | 
|  | if (lock) { | 
|  | if (cls_len < client_count + 128) { | 
|  | if (cls != NULL) { | 
|  | free(cls); | 
|  | } | 
|  | cls_len = client_count + 256; | 
|  | cls = (rfbClientPtr *) calloc(cls_len * sizeof(rfbClientPtr), 1); | 
|  | } | 
|  |  | 
|  | iter = rfbGetClientIterator(screen); | 
|  | blocked = 0; | 
|  | while ((cl = rfbClientIteratorNext(iter)) != NULL) { | 
|  | s = lcs(cl); | 
|  | SEND_LOCK(cl); | 
|  | rfbLog("locked client:   %p  %.6f %s\n", cl, dnowx(), s); | 
|  | cls[blocked++] = cl; | 
|  | } | 
|  | rfbReleaseClientIterator(iter); | 
|  | } else { | 
|  | int i; | 
|  | for (i=0; i < blocked; i++) { | 
|  | cl = cls[i]; | 
|  | if (cl != NULL) { | 
|  | s = lcs(cl); | 
|  | SEND_UNLOCK(cl) | 
|  | rfbLog("unlocked client: %p  %.6f %s\n", cl, dnowx(), s); | 
|  | } | 
|  | cls[i] = NULL; | 
|  | } | 
|  | blocked = 0; | 
|  | } | 
|  | return state; | 
|  | } | 
|  |  | 
|  | static void settle_clients(int init) { | 
|  | rfbClientIteratorPtr iter; | 
|  | rfbClientPtr cl; | 
|  | int fb_pend, i, ms = 1000; | 
|  | char *s; | 
|  |  | 
|  | if (!use_threads || !screen) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (init) { | 
|  | iter = rfbGetClientIterator(screen); | 
|  | i = 0; | 
|  | while ((cl = rfbClientIteratorNext(iter)) != NULL) { | 
|  | if (i < _bytes0_size) { | 
|  | _bytes0[i] = rfbStatGetSentBytesIfRaw(cl); | 
|  | } | 
|  | i++; | 
|  | } | 
|  | rfbReleaseClientIterator(iter); | 
|  |  | 
|  | if (getenv("X11VNC_THREADS_NEW_FB_SLEEP")) { | 
|  | ms = atoi(getenv("X11VNC_THREADS_NEW_FB_SLEEP")); | 
|  | } else if (subwin) { | 
|  | ms = 250; | 
|  | } else { | 
|  | ms = 500; | 
|  | } | 
|  | usleep(ms * 1000); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (getenv("X11VNC_THREADS_NEW_FB_SLEEP")) { | 
|  | ms = atoi(getenv("X11VNC_THREADS_NEW_FB_SLEEP")); | 
|  | } else if (subwin) { | 
|  | ms = 500; | 
|  | } else { | 
|  | ms = 1000; | 
|  | } | 
|  | usleep(ms * 1000); | 
|  |  | 
|  | for (i=0; i < 5; i++) { | 
|  | fb_pend = 0; | 
|  | iter = rfbGetClientIterator(screen); | 
|  | while ((cl = rfbClientIteratorNext(iter)) != NULL) { | 
|  | s = lcs(cl); | 
|  | if (cl->newFBSizePending) { | 
|  | fb_pend++; | 
|  | rfbLog("pending fb size: %p  %.6f %s\n", cl, dnowx(), s); | 
|  | } | 
|  | } | 
|  | rfbReleaseClientIterator(iter); | 
|  | if (fb_pend > 0) { | 
|  | rfbLog("do_new_fb: newFBSizePending extra -threads sleep (%d)\n", i+1); | 
|  | usleep(ms * 1000); | 
|  | } else { | 
|  | break; | 
|  | } | 
|  | } | 
|  | for (i=0; i < 5; i++) { | 
|  | int stuck = 0, tot = 0, j = 0; | 
|  | iter = rfbGetClientIterator(screen); | 
|  | while ((cl = rfbClientIteratorNext(iter)) != NULL) { | 
|  | if (j < _bytes0_size) { | 
|  | int db = rfbStatGetSentBytesIfRaw(cl) - _bytes0[j]; | 
|  | int Bpp = cl->format.bitsPerPixel / 8; | 
|  |  | 
|  | s = lcs(cl); | 
|  | rfbLog("addl bytes sent: %p  %.6f %s  %d  %d\n", | 
|  | cl, dnowx(), s, db, _bytes0[j]); | 
|  |  | 
|  | if (i==0) { | 
|  | if (db < Bpp * dpy_x * dpy_y) { | 
|  | stuck++; | 
|  | } | 
|  | } else if (i==1) { | 
|  | if (db < 0.5 * Bpp * dpy_x * dpy_y) { | 
|  | stuck++; | 
|  | } | 
|  | } else { | 
|  | if (db <= 0) { | 
|  | stuck++; | 
|  | } | 
|  | } | 
|  | } | 
|  | tot++; | 
|  | j++; | 
|  | } | 
|  | rfbReleaseClientIterator(iter); | 
|  | if (stuck > 0) { | 
|  | rfbLog("clients stuck:  %d/%d  sleep(%d)\n", stuck, tot, i); | 
|  | usleep(2 * ms * 1000); | 
|  | } else { | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static void prep_clients_for_new_fb(void) { | 
|  | rfbClientIteratorPtr iter; | 
|  | rfbClientPtr cl; | 
|  |  | 
|  | if (!use_threads || !screen) { | 
|  | return; | 
|  | } | 
|  | iter = rfbGetClientIterator(screen); | 
|  | while ((cl = rfbClientIteratorNext(iter)) != NULL) { | 
|  | if (!cl->newFBSizePending) { | 
|  | rfbLog("** set_new_fb_size_pending client:   %p\n", cl); | 
|  | cl->newFBSizePending = TRUE; | 
|  | } | 
|  | cl->cursorWasChanged = FALSE; | 
|  | cl->cursorWasMoved = FALSE; | 
|  | } | 
|  | rfbReleaseClientIterator(iter); | 
|  | } | 
|  |  | 
|  | void do_new_fb(int reset_mem) { | 
|  | XImage *fb; | 
|  |  | 
|  | /* for threaded we really should lock libvncserver out. */ | 
|  | if (use_threads) { | 
|  | int ms = 1000; | 
|  | if (getenv("X11VNC_THREADS_NEW_FB_SLEEP")) { | 
|  | ms = atoi(getenv("X11VNC_THREADS_NEW_FB_SLEEP")); | 
|  | } else if (subwin) { | 
|  | ms = 500; | 
|  | } else { | 
|  | ms = 1000; | 
|  | } | 
|  | rfbLog("Warning: changing framebuffers in threaded mode may be unstable.\n"); | 
|  | threads_drop_input = 1; | 
|  | usleep(ms * 1000); | 
|  | } | 
|  |  | 
|  | INPUT_LOCK; | 
|  | lock_client_sends(1); | 
|  |  | 
|  | if (use_threads) { | 
|  | settle_clients(1); | 
|  | } | 
|  |  | 
|  | #ifdef MACOSX | 
|  | if (macosx_console) { | 
|  | macosxCG_fini(); | 
|  | } | 
|  | #endif | 
|  | if (reset_mem == 1) { | 
|  | /* reset_mem == 2 is a hack for changing users... */ | 
|  | clean_shm(0); | 
|  | free_tiles(); | 
|  | } | 
|  |  | 
|  | free_old_fb(); | 
|  |  | 
|  | fb = initialize_xdisplay_fb(); | 
|  |  | 
|  | initialize_screen(NULL, NULL, fb); | 
|  |  | 
|  | if (reset_mem) { | 
|  | initialize_tiles(); | 
|  | initialize_blackouts_and_xinerama(); | 
|  | initialize_polling_images(); | 
|  | } | 
|  | if (ncache) { | 
|  | check_ncache(1, 0); | 
|  | } | 
|  |  | 
|  | prep_clients_for_new_fb(); | 
|  | lock_client_sends(0); | 
|  | INPUT_UNLOCK; | 
|  |  | 
|  | if (use_threads) { | 
|  | /* need to let things settle... */ | 
|  | settle_clients(0); | 
|  | threads_drop_input = 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | static void remove_fake_fb(void) { | 
|  | if (! screen) { | 
|  | return; | 
|  | } | 
|  | rfbLog("removing fake fb: 0x%x\n", fake_fb); | 
|  |  | 
|  | do_new_fb(1); | 
|  |  | 
|  | /* | 
|  | * fake_fb is freed in do_new_fb(), but we set to NULL here to | 
|  | * indicate it is gone. | 
|  | */ | 
|  | fake_fb = NULL; | 
|  | } | 
|  |  | 
|  | static void rfb_new_framebuffer(rfbScreenInfoPtr rfbScreen, char *framebuffer, | 
|  | int width,int height, int bitsPerSample,int samplesPerPixel, | 
|  | int bytesPerPixel) { | 
|  |  | 
|  | rfbNewFramebuffer(rfbScreen, framebuffer, width, height, bitsPerSample, | 
|  | samplesPerPixel, bytesPerPixel); | 
|  |  | 
|  | } | 
|  |  | 
|  | static void install_fake_fb(int w, int h, int bpp) { | 
|  | int bpc; | 
|  | if (! screen) { | 
|  | return; | 
|  | } | 
|  | lock_client_sends(1); | 
|  | if (fake_fb) { | 
|  | free(fake_fb); | 
|  | } | 
|  | fake_fb = (char *) calloc(w*h*bpp/8, 1); | 
|  | if (! fake_fb) { | 
|  | rfbLog("could not create fake fb: %dx%d %d\n", w, h, bpp); | 
|  | lock_client_sends(0); | 
|  | return; | 
|  | } | 
|  | bpc = guess_bits_per_color(bpp); | 
|  | rfbLog("installing fake fb: %dx%d %d\n", w, h, bpp); | 
|  | rfbLog("rfbNewFramebuffer(0x%x, 0x%x, %d, %d, %d, %d, %d)\n", | 
|  | screen, fake_fb, w, h, bpc, 1, bpp/8); | 
|  |  | 
|  | rfb_new_framebuffer(screen, fake_fb, w, h, bpc, 1, bpp/8); | 
|  | lock_client_sends(0); | 
|  | } | 
|  |  | 
|  | void check_padded_fb(void) { | 
|  | if (! fake_fb) { | 
|  | return; | 
|  | } | 
|  | if (unixpw_in_progress) return; | 
|  |  | 
|  | if (time(NULL) > pad_geometry_time+1 && all_clients_initialized()) { | 
|  | remove_fake_fb(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void install_padded_fb(char *geom) { | 
|  | int w, h; | 
|  | int ok = 1; | 
|  | if (! geom || *geom == '\0') { | 
|  | ok = 0; | 
|  | } else if (sscanf(geom, "%dx%d", &w, &h) != 2)  { | 
|  | ok = 0; | 
|  | } | 
|  | w = nabs(w); | 
|  | h = nabs(h); | 
|  |  | 
|  | if (w < 5) w = 5; | 
|  | if (h < 5) h = 5; | 
|  |  | 
|  | if (!ok) { | 
|  | rfbLog("skipping invalid pad geometry: '%s'\n", NONUL(geom)); | 
|  | return; | 
|  | } | 
|  | install_fake_fb(w, h, bpp); | 
|  | pad_geometry_time = time(NULL); | 
|  | } | 
|  |  | 
|  | static void initialize_snap_fb(void) { | 
|  | RAWFB_RET_VOID | 
|  | if (snap_fb) { | 
|  | free(snap_fb); | 
|  | } | 
|  | snap = XGetImage_wr(dpy, window, 0, 0, dpy_x, dpy_y, AllPlanes, | 
|  | ZPixmap); | 
|  | snap_fb = snap->data; | 
|  | } | 
|  |  | 
|  | static rfbClient* client = NULL; | 
|  |  | 
|  | void vnc_reflect_bell(rfbClient *cl) { | 
|  | if (cl) {} | 
|  | if (sound_bell) { | 
|  | if (unixpw_in_progress) { | 
|  | return; | 
|  | } | 
|  | if (! all_clients_initialized()) { | 
|  | rfbLog("vnc_reflect_bell: not sending bell: " | 
|  | "uninitialized clients\n"); | 
|  | } else { | 
|  | if (screen && client_count) { | 
|  | rfbSendBell(screen); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void vnc_reflect_recv_cuttext(rfbClient *cl, const char *str, int len) { | 
|  | if (cl) {} | 
|  | if (unixpw_in_progress) { | 
|  | return; | 
|  | } | 
|  | if (! watch_selection) { | 
|  | return; | 
|  | } | 
|  | if (! all_clients_initialized()) { | 
|  | rfbLog("vnc_reflect_recv_cuttext: no send: uninitialized clients\n"); | 
|  | return; /* some clients initializing, cannot send */ | 
|  | } | 
|  | rfbSendServerCutText(screen, (char *)str, len); | 
|  | } | 
|  |  | 
|  | void vnc_reflect_got_update(rfbClient *cl, int x, int y, int w, int h) { | 
|  | if (cl) {} | 
|  | if (use_xdamage) { | 
|  | static int first = 1; | 
|  | if (first) { | 
|  | collect_non_X_xdamage(-1, -1, -1, -1, 0); | 
|  | first = 0; | 
|  | } | 
|  | collect_non_X_xdamage(x, y, w, h, 1); | 
|  | } | 
|  | } | 
|  |  | 
|  | void vnc_reflect_got_cursorshape(rfbClient *cl, int xhot, int yhot, int width, int height, int bytesPerPixel) { | 
|  | static int serial = 1; | 
|  | int i, j; | 
|  | char *pixels = NULL; | 
|  | unsigned long r, g, b; | 
|  | unsigned int ui = 0; | 
|  | unsigned long red_mask, green_mask, blue_mask; | 
|  |  | 
|  | if (cl) {} | 
|  | if (unixpw_in_progress) { | 
|  | return; | 
|  | } | 
|  | if (! all_clients_initialized()) { | 
|  | rfbLog("vnc_reflect_got_copyshape: no send: uninitialized clients\n"); | 
|  | return; /* some clients initializing, cannot send */ | 
|  | } | 
|  | if (! client->rcSource) { | 
|  | return; | 
|  | } | 
|  | if (bytesPerPixel != 1 && bytesPerPixel != 2 && bytesPerPixel != 4) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | red_mask   = (client->format.redMax   << client->format.redShift); | 
|  | green_mask = (client->format.greenMax << client->format.greenShift); | 
|  | blue_mask  = (client->format.blueMax  << client->format.blueShift); | 
|  |  | 
|  | pixels = (char *)malloc(4*width*height); | 
|  | for (j=0; j<height; j++) { | 
|  | for (i=0; i<width; i++) { | 
|  | unsigned int* uip; | 
|  | unsigned char* uic; | 
|  | int m; | 
|  | if (bytesPerPixel == 1) { | 
|  | unsigned char* p = (unsigned char *) client->rcSource; | 
|  | ui = (unsigned long) *(p + j * width + i); | 
|  | } else if (bytesPerPixel == 2) { | 
|  | unsigned short* p = (unsigned short *) client->rcSource; | 
|  | ui = (unsigned long) *(p + j * width + i); | 
|  | } else if (bytesPerPixel == 4) { | 
|  | unsigned int* p = (unsigned int *) client->rcSource; | 
|  | ui = (unsigned long) *(p + j * width + i); | 
|  | } | 
|  | r = (red_mask   & ui) >> client->format.redShift; | 
|  | g = (green_mask & ui) >> client->format.greenShift; | 
|  | b = (blue_mask  & ui) >> client->format.blueShift; | 
|  |  | 
|  | r = (255 * r) / client->format.redMax; | 
|  | g = (255 * g) / client->format.greenMax; | 
|  | b = (255 * b) / client->format.blueMax; | 
|  |  | 
|  | ui = (r << 16 | g << 8 | b << 0) ; | 
|  |  | 
|  | uic = (unsigned char *)client->rcMask; | 
|  | m = (int) *(uic + j * width + i); | 
|  | if (m) { | 
|  | ui |= 0xff000000; | 
|  | } | 
|  | uip = (unsigned int *)pixels; | 
|  | *(uip + j * width + i) = ui; | 
|  | } | 
|  | } | 
|  |  | 
|  | store_cursor(serial++, (unsigned long*) pixels, width, height, 32, xhot, yhot); | 
|  | free(pixels); | 
|  | set_cursor(cursor_x, cursor_y, get_which_cursor()); | 
|  | } | 
|  |  | 
|  | rfbBool vnc_reflect_cursor_pos(rfbClient *cl, int x, int y) { | 
|  | if (cl) {} | 
|  | if (debug_pointer) { | 
|  | rfbLog("vnc_reflect_cursor_pos: %d %d\n", x, y); | 
|  | } | 
|  | if (unixpw_in_progress) { | 
|  | if (debug_pointer) { | 
|  | rfbLog("vnc_reflect_cursor_pos: unixpw_in_progress%d\n", unixpw_in_progress); | 
|  | } | 
|  | return TRUE; | 
|  | } | 
|  | if (! all_clients_initialized()) { | 
|  | rfbLog("vnc_reflect_cursor_pos: no send: uninitialized clients\n"); | 
|  | return TRUE; /* some clients initializing, cannot send */ | 
|  | } | 
|  |  | 
|  | cursor_position(x, y); | 
|  | set_cursor(x, y, get_which_cursor()); | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | static void from_libvncclient_CopyRectangleFromRectangle(rfbClient* client, int src_x, int src_y, int w, int h, int dest_x, int dest_y) { | 
|  | int i,j; | 
|  |  | 
|  | #define COPY_RECT_FROM_RECT(BPP) \ | 
|  | { \ | 
|  | uint##BPP##_t* _buffer=((uint##BPP##_t*)client->frameBuffer)+(src_y-dest_y)*client->width+src_x-dest_x; \ | 
|  | if (dest_y < src_y) { \ | 
|  | for(j = dest_y*client->width; j < (dest_y+h)*client->width; j += client->width) { \ | 
|  | if (dest_x < src_x) { \ | 
|  | for(i = dest_x; i < dest_x+w; i++) { \ | 
|  | ((uint##BPP##_t*)client->frameBuffer)[j+i]=_buffer[j+i]; \ | 
|  | } \ | 
|  | } else { \ | 
|  | for(i = dest_x+w-1; i >= dest_x; i--) { \ | 
|  | ((uint##BPP##_t*)client->frameBuffer)[j+i]=_buffer[j+i]; \ | 
|  | } \ | 
|  | } \ | 
|  | } \ | 
|  | } else { \ | 
|  | for(j = (dest_y+h-1)*client->width; j >= dest_y*client->width; j-=client->width) { \ | 
|  | if (dest_x < src_x) { \ | 
|  | for(i = dest_x; i < dest_x+w; i++) { \ | 
|  | ((uint##BPP##_t*)client->frameBuffer)[j+i]=_buffer[j+i]; \ | 
|  | } \ | 
|  | } else { \ | 
|  | for(i = dest_x+w-1; i >= dest_x; i--) { \ | 
|  | ((uint##BPP##_t*)client->frameBuffer)[j+i]=_buffer[j+i]; \ | 
|  | } \ | 
|  | } \ | 
|  | } \ | 
|  | } \ | 
|  | } | 
|  |  | 
|  | switch(client->format.bitsPerPixel) { | 
|  | case  8: COPY_RECT_FROM_RECT(8);  break; | 
|  | case 16: COPY_RECT_FROM_RECT(16); break; | 
|  | case 32: COPY_RECT_FROM_RECT(32); break; | 
|  | default: | 
|  | rfbClientLog("Unsupported bitsPerPixel: %d\n",client->format.bitsPerPixel); | 
|  | } | 
|  | } | 
|  |  | 
|  | void vnc_reflect_got_copyrect(rfbClient *cl, int src_x, int src_y, int w, int h, int dest_x, int dest_y) { | 
|  | sraRegionPtr reg; | 
|  | int dx, dy, rc = -1; | 
|  | static int last_dx = 0, last_dy = 0; | 
|  | if (cl) {} | 
|  | if (unixpw_in_progress) { | 
|  | return; | 
|  | } | 
|  | if (! all_clients_initialized()) { | 
|  | rfbLog("vnc_reflect_got_copyrect: no send: uninitialized clients\n"); | 
|  | return; /* some clients initializing, cannot send */ | 
|  | } | 
|  | dx = dest_x - src_x; | 
|  | dy = dest_y - src_y; | 
|  | if (dx != last_dx || dy != last_dy) { | 
|  | rc = fb_push_wait(0.05, FB_COPY|FB_MOD); | 
|  | } | 
|  | 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); | 
|  | reg = sraRgnCreateRect(dest_x, dest_y, dest_x + w, dest_y + h); | 
|  | do_copyregion(reg, dx, dy, 0); | 
|  | sraRgnDestroy(reg); | 
|  |  | 
|  | last_dx = dx; | 
|  | last_dy = dy; | 
|  |  | 
|  | from_libvncclient_CopyRectangleFromRectangle(cl, src_x, src_y, w, h, dest_x, dest_y); | 
|  | } | 
|  |  | 
|  | rfbBool vnc_reflect_resize(rfbClient *cl)  { | 
|  | static int first = 1; | 
|  | if(cl->frameBuffer) { | 
|  | free(cl->frameBuffer); | 
|  | } | 
|  | cl->frameBuffer= malloc(cl->width * cl->height * cl->format.bitsPerPixel/8); | 
|  | rfbLog("vnc_reflect_resize: %dx%dx%d first=%d\n", cl->width, cl->height, | 
|  | cl->format.bitsPerPixel, first); | 
|  | if (!first) { | 
|  | do_new_fb(1); | 
|  | } | 
|  | first = 0; | 
|  | return cl->frameBuffer ? TRUE : FALSE; | 
|  | } | 
|  |  | 
|  | #ifdef rfbCredentialTypeX509 | 
|  | static rfbCredential* vnc_reflect_get_credential(rfbClient* client, int type) { | 
|  | char *pass = getenv("X11VNC_REFLECT_PASSWORD"); | 
|  | char *user = getenv("X11VNC_REFLECT_USER"); | 
|  | char *cert = getenv("X11VNC_REFLECT_CACERT"); | 
|  | char *ccrl = getenv("X11VNC_REFLECT_CACRL"); | 
|  | char *clic = getenv("X11VNC_REFLECT_CLIENTCERT"); | 
|  | char *clik = getenv("X11VNC_REFLECT_CLIENTKEY"); | 
|  | int db = 0; | 
|  | if (client) {} | 
|  | if (db) fprintf(stderr, "type: %d\n", type); | 
|  | #ifdef rfbCredentialTypeUser | 
|  | if (type == rfbCredentialTypeUser) { | 
|  | if (!pass && !user) { | 
|  | return NULL; | 
|  | } else { | 
|  | rfbCredential *rc = (rfbCredential *) calloc(sizeof(rfbCredential), 1); | 
|  | rc->userCredential.username = (user ? strdup(user) : NULL); | 
|  | rc->userCredential.password = (pass ? strdup(pass) : NULL); | 
|  | return rc; | 
|  | } | 
|  | } | 
|  | #endif | 
|  | if (type == rfbCredentialTypeX509) { | 
|  | if (db) fprintf(stderr, "cert: %s\n", cert); | 
|  | if (db) fprintf(stderr, "ccrl: %s\n", ccrl); | 
|  | if (db) fprintf(stderr, "clic: %s\n", clic); | 
|  | if (db) fprintf(stderr, "clik: %s\n", clik); | 
|  | if (!cert && !ccrl && !clic && !clik) { | 
|  | return NULL; | 
|  | } else { | 
|  | rfbCredential *rc = (rfbCredential *) calloc(sizeof(rfbCredential), 1); | 
|  | rc->x509Credential.x509CACertFile     = (cert ? strdup(cert) : NULL); | 
|  | rc->x509Credential.x509CACrlFile      = (ccrl ? strdup(ccrl) : NULL); | 
|  | rc->x509Credential.x509ClientCertFile = (clic ? strdup(clic) : NULL); | 
|  | rc->x509Credential.x509ClientKeyFile  = (clik ? strdup(clik) : NULL); | 
|  | return rc; | 
|  | } | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | static char* vnc_reflect_get_password(rfbClient* client) { | 
|  | char *q, *p, *str = getenv("X11VNC_REFLECT_PASSWORD"); | 
|  | int len = 110; | 
|  |  | 
|  | if (client) {} | 
|  |  | 
|  | if (str) { | 
|  | len += 2*strlen(str); | 
|  | } | 
|  | p = (char *) calloc(len, 1); | 
|  | if (!str || strlen(str) == 0) { | 
|  | fprintf(stderr, "VNC Reflect Password: "); | 
|  | fgets(p, 100, stdin); | 
|  | } else { | 
|  | if (strstr(str, "file:") == str) { | 
|  | FILE *f = fopen(str + strlen("file:"), "r"); | 
|  | if (f) { | 
|  | fgets(p, 100, f); | 
|  | fclose(f); | 
|  | } | 
|  | } | 
|  | if (p[0] == '\0') { | 
|  | strncpy(p, str, 100); | 
|  | } | 
|  | } | 
|  | q = p; | 
|  | while (*q != '\0') { | 
|  | if (*q == '\n') { | 
|  | *q = '\0'; | 
|  | } | 
|  | q++; | 
|  | } | 
|  | return p; | 
|  | } | 
|  |  | 
|  | char *vnc_reflect_guess(char *str, char **raw_fb_addr) { | 
|  |  | 
|  | static int first = 1; | 
|  | char *hp = str + strlen("vnc:"); | 
|  | char *at = NULL; | 
|  | int argc = 0, i; | 
|  | char *argv[16]; | 
|  | char str2[256]; | 
|  | char *str0 = strdup(str); | 
|  |  | 
|  | if (client == NULL) { | 
|  | int bitsPerSample = 8; | 
|  | int samplesPerPixel = 3; | 
|  | int bytesPerPixel = 4; | 
|  | char *s; | 
|  | s = getenv("X11VNC_REFLECT_bitsPerSample"); | 
|  | if (s) bitsPerSample = atoi(s); | 
|  | s = getenv("X11VNC_REFLECT_samplesPerPixel"); | 
|  | if (s) samplesPerPixel = atoi(s); | 
|  | s = getenv("X11VNC_REFLECT_bytesPerPixel"); | 
|  | if (s) bytesPerPixel = atoi(s); | 
|  | rfbLog("rfbGetClient(bitsPerSample=%d, samplesPerPixel=%d, bytesPerPixel=%d)\n", | 
|  | bitsPerSample, samplesPerPixel, bytesPerPixel); | 
|  | client = rfbGetClient(bitsPerSample, samplesPerPixel, bytesPerPixel); | 
|  | } | 
|  |  | 
|  | rfbLog("rawfb: %s\n", str); | 
|  |  | 
|  | at = strchr(hp, '@'); | 
|  | if (at) { | 
|  | *at = '\0'; | 
|  | at++; | 
|  | } | 
|  |  | 
|  | client->appData.useRemoteCursor = TRUE; | 
|  | client->canHandleNewFBSize = TRUE; | 
|  |  | 
|  | client->HandleCursorPos = vnc_reflect_cursor_pos; | 
|  | client->GotFrameBufferUpdate = vnc_reflect_got_update; | 
|  | client->MallocFrameBuffer = vnc_reflect_resize; | 
|  | client->Bell = vnc_reflect_bell; | 
|  | #if 0 | 
|  | client->SoftCursorLockArea = NULL; | 
|  | client->SoftCursorUnlockScreen = NULL; | 
|  | client->FinishedFrameBufferUpdate = NULL; | 
|  | client->HandleKeyboardLedState = NULL; | 
|  | client->HandleTextChat = NULL; | 
|  | #endif | 
|  | client->GotXCutText = vnc_reflect_recv_cuttext; | 
|  | client->GotCursorShape = vnc_reflect_got_cursorshape; | 
|  | client->GotCopyRect = vnc_reflect_got_copyrect; | 
|  |  | 
|  | if (getenv("X11VNC_REFLECT_PASSWORD")) { | 
|  | client->GetPassword = vnc_reflect_get_password; | 
|  | } | 
|  | #ifdef rfbCredentialTypeX509 | 
|  | client->GetCredential = NULL; | 
|  | if (0 || getenv("LIBVNCCLIENT_GET_CREDENTIAL")) { | 
|  | client->GetCredential = vnc_reflect_get_credential; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | if (first) { | 
|  | argv[argc++] = "x11vnc_rawfb_vnc"; | 
|  | if (strstr(hp, "listen") == hp) { | 
|  | char *q = strrchr(hp, ':'); | 
|  | argv[argc++] = strdup("-listen"); | 
|  | if (q) { | 
|  | client->listenPort = atoi(q+1); | 
|  | } else { | 
|  | client->listenPort = LISTEN_PORT_OFFSET; | 
|  | } | 
|  | } else { | 
|  | argv[argc++] = strdup(hp); | 
|  | } | 
|  |  | 
|  | if (! rfbInitClient(client, &argc, argv)) { | 
|  | rfbLog("vnc_reflector failed for: %s\n", str0); | 
|  | clean_up_exit(1); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (at) { | 
|  | sprintf(str2, "map:/dev/null@%s", at); | 
|  | } else { | 
|  | unsigned long red_mask, green_mask, blue_mask; | 
|  | red_mask   = (client->format.redMax   << client->format.redShift); | 
|  | green_mask = (client->format.greenMax << client->format.greenShift); | 
|  | blue_mask  = (client->format.blueMax  << client->format.blueShift); | 
|  | sprintf(str2, "map:/dev/null@%dx%dx%d:0x%lx/0x%lx/0x%lx", | 
|  | client->width, client->height, client->format.bitsPerPixel, | 
|  | red_mask, green_mask, blue_mask); | 
|  | } | 
|  | *raw_fb_addr = (char *) client->frameBuffer; | 
|  | free(str0); | 
|  |  | 
|  | if (first) { | 
|  | setup_cursors_and_push(); | 
|  |  | 
|  | for (i=0; i<10; i++) { | 
|  | vnc_reflect_process_client(); | 
|  | } | 
|  | } | 
|  | first = 0; | 
|  |  | 
|  | return strdup(str2); | 
|  | } | 
|  |  | 
|  | rfbBool vnc_reflect_send_pointer(int x, int y, int mask) { | 
|  | int rc; | 
|  | if (mask >= 0) { | 
|  | got_user_input++; | 
|  | got_pointer_input++; | 
|  | last_pointer_time = time(NULL); | 
|  | } | 
|  |  | 
|  | if (clipshift) { | 
|  | x += coff_x; | 
|  | y += coff_y; | 
|  | } | 
|  |  | 
|  | if (cursor_x != x || cursor_y != y) { | 
|  | last_pointer_motion_time = dnow(); | 
|  | } | 
|  |  | 
|  | cursor_x = x; | 
|  | cursor_y = y; | 
|  |  | 
|  | /* record the x, y position for the rfb screen as well. */ | 
|  | cursor_position(x, y); | 
|  |  | 
|  | /* change the cursor shape if necessary */ | 
|  | rc = set_cursor(x, y, get_which_cursor()); | 
|  | cursor_changes += rc; | 
|  |  | 
|  | return SendPointerEvent(client, x, y, mask); | 
|  | } | 
|  |  | 
|  | rfbBool vnc_reflect_send_key(uint32_t key, rfbBool down) { | 
|  | return SendKeyEvent(client, key, down); | 
|  | } | 
|  |  | 
|  | rfbBool vnc_reflect_send_cuttext(char *str, int len) { | 
|  | return SendClientCutText(client, str, len); | 
|  | } | 
|  |  | 
|  | void vnc_reflect_process_client(void) { | 
|  | int num; | 
|  | if (client == NULL) { | 
|  | return; | 
|  | } | 
|  | num = WaitForMessage(client, 1000); | 
|  | if (num > 0) { | 
|  | if (!HandleRFBServerMessage(client)) { | 
|  | rfbLog("vnc_reflect_process_client: read failure to server\n"); | 
|  | shut_down = 1; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void linux_dev_fb_msg(char* q) { | 
|  | if (strstr(q, "/dev/fb") && strstr(UT.sysname, "Linux")) { | 
|  | rfbLog("\n"); | 
|  | rfbLog("On Linux you may need to load a kernel module to enable\n"); | 
|  | rfbLog("the framebuffer device /dev/fb*; e.g.:\n"); | 
|  | rfbLog("   vga=0x303 (and others) kernel boot parameter\n"); | 
|  | rfbLog("   modprobe uvesafb\n"); | 
|  | rfbLog("   modprobe radeonfb (card specific)\n"); | 
|  | rfbLog("   modprobe nvidiafb (card specific, others)\n"); | 
|  | rfbLog("   modprobe vesafb (?)\n"); | 
|  | rfbLog("   modprobe vga16fb\n"); | 
|  | rfbLog("\n"); | 
|  | rfbLog("You may also need root permission to open /dev/fb*\n"); | 
|  | rfbLog("and/or /dev/tty*.\n"); | 
|  | rfbLog("\n"); | 
|  | } | 
|  | } | 
|  |  | 
|  | #define RAWFB_MMAP 1 | 
|  | #define RAWFB_FILE 2 | 
|  | #define RAWFB_SHM  3 | 
|  |  | 
|  | XImage *initialize_raw_fb(int reset) { | 
|  | char *str, *rstr, *q; | 
|  | int w, h, b, shmid = 0; | 
|  | unsigned long rm = 0, gm = 0, bm = 0, tm; | 
|  | static XImage ximage_struct;	/* n.b.: not (XImage *) */ | 
|  | static XImage ximage_struct_snap; | 
|  | int closedpy = 1, i, m, db = 0; | 
|  | int do_macosx = 0; | 
|  | int do_reflect = 0; | 
|  | char *unlink_me = NULL; | 
|  |  | 
|  | static char *last_file = NULL; | 
|  | static int last_mode = 0; | 
|  |  | 
|  | if (reset && last_mode) { | 
|  | int fd; | 
|  | if (last_mode != RAWFB_MMAP && last_mode != RAWFB_FILE) { | 
|  | return NULL; | 
|  | } | 
|  | if (last_mode == RAWFB_MMAP) { | 
|  | munmap(raw_fb_addr, raw_fb_mmap); | 
|  | } | 
|  | if (raw_fb_fd >= 0) { | 
|  | close(raw_fb_fd); | 
|  | } | 
|  | raw_fb_fd = -1; | 
|  | if (db) fprintf(stderr, "initialize_raw_fb reset\n"); | 
|  |  | 
|  | fd = -1; | 
|  | if (rawfb_dev_video) { | 
|  | fd = open(last_file, O_RDWR); | 
|  | } | 
|  | if (fd < 0) { | 
|  | fd = open(last_file, O_RDONLY); | 
|  | } | 
|  | if (fd < 0) { | 
|  | rfbLogEnable(1); | 
|  | rfbLog("failed to rawfb file: %s\n", last_file); | 
|  | rfbLogPerror("open"); | 
|  | clean_up_exit(1); | 
|  | } | 
|  | raw_fb_fd = fd; | 
|  | if (last_mode == RAWFB_MMAP) { | 
|  | raw_fb_addr = mmap(0, raw_fb_mmap, PROT_READ, | 
|  | MAP_SHARED, fd, 0); | 
|  |  | 
|  | if (raw_fb_addr == MAP_FAILED || raw_fb_addr == NULL) { | 
|  | rfbLogEnable(1); | 
|  | rfbLog("failed to mmap file: %s\n", last_file); | 
|  | rfbLog("   raw_fb_addr: %p\n", raw_fb_addr); | 
|  | rfbLogPerror("mmap"); | 
|  | clean_up_exit(1); | 
|  | } | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | #ifdef MACOSX | 
|  | if (raw_fb_addr != NULL && macosx_console && raw_fb_addr == macosx_get_fb_addr()) { | 
|  | raw_fb_addr = NULL; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | if (raw_fb_addr || raw_fb_seek) { | 
|  | if (raw_fb_shm) { | 
|  | shmdt(raw_fb_addr); | 
|  | #if LIBVNCSERVER_HAVE_MMAP | 
|  | } else if (raw_fb_mmap) { | 
|  | munmap(raw_fb_addr, raw_fb_mmap); | 
|  | if (raw_fb_fd >= 0) { | 
|  | close(raw_fb_fd); | 
|  | } | 
|  | raw_fb_fd = -1; | 
|  | #endif | 
|  | } else if (raw_fb_seek) { | 
|  | if (raw_fb_fd >= 0) { | 
|  | close(raw_fb_fd); | 
|  | } | 
|  | raw_fb_fd = -1; | 
|  | } | 
|  | raw_fb_addr = NULL; | 
|  | raw_fb_mmap = 0; | 
|  | raw_fb_seek = 0; | 
|  | } | 
|  | if (! raw_fb_str) { | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | if (raw_fb_str[0] == '+') { | 
|  | rstr = strdup(raw_fb_str+1); | 
|  | closedpy = 0; | 
|  | if (! window) { | 
|  | window = rootwin; | 
|  | } | 
|  | } else { | 
|  | rstr = strdup(raw_fb_str); | 
|  | } | 
|  |  | 
|  | /* testing aliases */ | 
|  | if (!strcasecmp(rstr, "NULL") || !strcasecmp(rstr, "ZERO") | 
|  | || !strcasecmp(rstr, "NONE")) { | 
|  | rstr = strdup("map:/dev/zero@640x480x32"); | 
|  | } else if (!strcasecmp(rstr, "NULLBIG") || !strcasecmp(rstr, "NONEBIG")) { | 
|  | rstr = strdup("map:/dev/zero@1024x768x32"); | 
|  | } | 
|  | if (!strcasecmp(rstr, "RAND")) { | 
|  | rstr = strdup("file:/dev/urandom@128x128x16"); | 
|  | } else if (!strcasecmp(rstr, "RANDBIG")) { | 
|  | rstr = strdup("file:/dev/urandom@640x480x16"); | 
|  | } else if (!strcasecmp(rstr, "RANDHUGE")) { | 
|  | rstr = strdup("file:/dev/urandom@1024x768x16"); | 
|  | } | 
|  | if (strstr(rstr, "solid=") == rstr) { | 
|  | char *n = rstr + strlen("solid="); | 
|  | char tmp[] = "/tmp/rawfb_solid.XXXXXX"; | 
|  | char str[100]; | 
|  | unsigned int vals[1024], val; | 
|  | int x, y, fd, w = 1024, h = 768; | 
|  | if (strstr(n, "0x")) { | 
|  | if (sscanf(n, "0x%x", &val) != 1) { | 
|  | val = 0; | 
|  | } | 
|  | } | 
|  | if (val == 0) { | 
|  | val = get_pixel(n); | 
|  | } | 
|  | if (val == 0) { | 
|  | val = 0xFF00FF; | 
|  | } | 
|  | fd = mkstemp(tmp); | 
|  | for (y = 0; y < h; y++) { | 
|  | for (x = 0; x < w; x++) { | 
|  | vals[x] = val; | 
|  | } | 
|  | write(fd, (char *)vals, 4 * w); | 
|  | } | 
|  | close(fd); | 
|  | fd = open(tmp, O_WRONLY); | 
|  | unlink_me = strdup(tmp); | 
|  | sprintf(str, "map:%s@%dx%dx32", tmp, w, h); | 
|  | rstr = strdup(str); | 
|  | } else if (strstr(rstr, "swirl") == rstr) { | 
|  | char tmp[] = "/tmp/rawfb_swirl.XXXXXX"; | 
|  | char str[100]; | 
|  | unsigned int val[1024]; | 
|  | unsigned int c1, c2, c3, c4; | 
|  | int x, y, fd, w = 1024, h = 768; | 
|  | fd = mkstemp(tmp); | 
|  | for (y = 0; y < h; y++) { | 
|  | for (x = 0; x < w; x++) { | 
|  | c1 = 0; | 
|  | c2 = ((x+y)*128)/(w+h); | 
|  | c3 = (x*128)/w; | 
|  | c4 = (y*256)/h; | 
|  | val[x] = (c1 << 24) | (c2 << 16) | (c3 << 8) | (c4 << 0); | 
|  | } | 
|  | write(fd, (char *)val, 4 * w); | 
|  | } | 
|  | close(fd); | 
|  | fd = open(tmp, O_WRONLY); | 
|  | unlink_me = strdup(tmp); | 
|  | sprintf(str, "map:%s@%dx%dx32", tmp, w, h); | 
|  | rstr = strdup(str); | 
|  | } | 
|  |  | 
|  |  | 
|  | if ( (q = strstr(rstr, "setup:")) == rstr) { | 
|  | FILE *pipe; | 
|  | char line[1024], *t; | 
|  |  | 
|  | set_child_info(); | 
|  | q += strlen("setup:"); | 
|  | /* rawfb-setup */ | 
|  | if (no_external_cmds || !cmd_ok("rawfb-setup")) { | 
|  | rfbLogEnable(1); | 
|  | rfbLog("cannot run external commands in -nocmds " | 
|  | "mode:\n"); | 
|  | rfbLog("   \"%s\"\n", q); | 
|  | rfbLog("   exiting.\n"); | 
|  | clean_up_exit(1); | 
|  | } | 
|  | rfbLog("running command to setup rawfb: %s\n", q); | 
|  | close_exec_fds(); | 
|  | pipe = popen(q, "r"); | 
|  | if (! pipe) { | 
|  | rfbLogEnable(1); | 
|  | rfbLog("popen of setup command failed.\n"); | 
|  | rfbLogPerror("popen"); | 
|  | clean_up_exit(1); | 
|  | } | 
|  | line[0] = '\0'; | 
|  | if (fgets(line, 1024, pipe) == NULL) { | 
|  | rfbLogEnable(1); | 
|  | rfbLog("read of setup command failed.\n"); | 
|  | clean_up_exit(1); | 
|  | } | 
|  | pclose(pipe); | 
|  | str = strdup(line); | 
|  | t = str; | 
|  | while (*t != '\0') { | 
|  | if (*t == '\n') { | 
|  | *t = '\0'; | 
|  | } | 
|  | t++; | 
|  | } | 
|  | rfbLog("setup command returned: %s\n", str); | 
|  |  | 
|  | } else { | 
|  | str = strdup(rstr); | 
|  | } | 
|  |  | 
|  | raw_fb_shm = 0; | 
|  | raw_fb_mmap = 0; | 
|  | raw_fb_seek = 0; | 
|  | raw_fb_fd = -1; | 
|  | raw_fb_addr = NULL; | 
|  | raw_fb_offset = 0; | 
|  | raw_fb_bytes_per_line = 0; | 
|  | rawfb_vnc_reflect = 0; | 
|  |  | 
|  | last_mode = 0; | 
|  | if (last_file) { | 
|  | free(last_file); | 
|  | last_file = NULL; | 
|  | } | 
|  | if (strstr(str, "Video") == str) { | 
|  | if (pipeinput_str != NULL) { | 
|  | free(pipeinput_str); | 
|  | } | 
|  | pipeinput_str = strdup("VID"); | 
|  | initialize_pipeinput(); | 
|  | str[0] = 'v'; | 
|  | } | 
|  |  | 
|  | if (strstr(str, "video") == str || strstr(str, "/dev/video") == str) { | 
|  | char *str2 = v4l_guess(str, &raw_fb_fd); | 
|  | if (str2 == NULL) { | 
|  | rfbLog("v4l_guess failed for: %s\n", str); | 
|  | clean_up_exit(1); | 
|  | } | 
|  | str = str2; | 
|  | rfbLog("v4l_guess returned: %s\n", str); | 
|  | rawfb_dev_video = 1; | 
|  | } else if (strstr(str, "dev/video")) { | 
|  | rawfb_dev_video = 1; | 
|  | } else if (strstr(str, "console") == str || strstr(str, "fb") == str || | 
|  | strstr(str, "/dev/fb") == str || strstr(str, "vt") == str) { | 
|  | char *str2 = console_guess(str, &raw_fb_fd); | 
|  | if (str2 == NULL) { | 
|  | rfbLog("console_guess failed for: %s\n", str); | 
|  | clean_up_exit(1); | 
|  | } | 
|  | str = str2; | 
|  | rfbLog("console_guess returned: %s\n", str); | 
|  | } else if (strstr(str, "vnc:") == str) { | 
|  | char *str2 = vnc_reflect_guess(str, &raw_fb_addr); | 
|  |  | 
|  | rawfb_vnc_reflect = 1; | 
|  | do_reflect = 1; | 
|  |  | 
|  | str = str2; | 
|  | rfbLog("vnc_reflector set rawfb str to: %s\n", str); | 
|  | if (pipeinput_str == NULL) { | 
|  | pipeinput_str = strdup("VNC"); | 
|  | } | 
|  | initialize_pipeinput(); | 
|  | } | 
|  |  | 
|  | if (closedpy && !view_only && got_noviewonly) { | 
|  | rfbLog("not closing X DISPLAY under -noviewonly option.\n"); | 
|  | closedpy = 0; | 
|  | if (! window) { | 
|  | window = rootwin; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (! raw_fb_orig_dpy && dpy) { | 
|  | raw_fb_orig_dpy = strdup(DisplayString(dpy)); | 
|  | } | 
|  | #ifndef BOLDLY_CLOSE_DISPLAY | 
|  | #define BOLDLY_CLOSE_DISPLAY 1 | 
|  | #endif | 
|  | #if BOLDLY_CLOSE_DISPLAY | 
|  | if (closedpy) { | 
|  | if (dpy) { | 
|  | rfbLog("closing X DISPLAY: %s in rawfb mode.\n", | 
|  | DisplayString(dpy)); | 
|  | XCloseDisplay_wr(dpy);	/* yow! */ | 
|  | } | 
|  | dpy = NULL; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | /* | 
|  | * -rawfb shm:163938442@640x480x32:ff/ff00/ff0000+3000 | 
|  | * -rawfb map:/path/to/file@640x480x32:ff/ff00/ff0000 | 
|  | * -rawfb file:/path/to/file@640x480x32:ff/ff00/ff0000 | 
|  | */ | 
|  |  | 
|  | if (raw_fb_full_str) { | 
|  | free(raw_fb_full_str); | 
|  | } | 
|  | raw_fb_full_str = strdup(str); | 
|  |  | 
|  |  | 
|  | /* +O offset */ | 
|  | if ((q = strrchr(str, '+')) != NULL) { | 
|  | if (sscanf(q, "+%d", &raw_fb_offset) == 1) { | 
|  | *q = '\0'; | 
|  | } else { | 
|  | raw_fb_offset = 0; | 
|  | } | 
|  | } | 
|  | /* :R/G/B masks */ | 
|  | if ((q = strrchr(str, ':')) != NULL) { | 
|  | if (sscanf(q, ":%lx/%lx/%lx", &rm, &gm, &bm) == 3) { | 
|  | *q = '\0'; | 
|  | } else if (sscanf(q, ":0x%lx/0x%lx/0x%lx", &rm, &gm, &bm)== 3) { | 
|  | *q = '\0'; | 
|  | } else if (sscanf(q, ":%lu/%lu/%lu", &rm, &gm, &bm) == 3) { | 
|  | *q = '\0'; | 
|  | } else { | 
|  | rm = 0; | 
|  | gm = 0; | 
|  | bm = 0; | 
|  | } | 
|  | } | 
|  | if ((q = strrchr(str, '@')) == NULL) { | 
|  | rfbLogEnable(1); | 
|  | rfbLog("invalid rawfb str: %s\n", str); | 
|  | clean_up_exit(1); | 
|  | } | 
|  |  | 
|  | if (strrchr(q, '-')) { | 
|  | char *q2 = strrchr(q, '-'); | 
|  | raw_fb_bytes_per_line = atoi(q2+1); | 
|  | *q2 = '\0'; | 
|  | } | 
|  | /* @WxHxB */ | 
|  | if (sscanf(q, "@%dx%dx%d", &w, &h, &b) != 3) { | 
|  | rfbLogEnable(1); | 
|  | rfbLog("invalid rawfb str: %s\n", str); | 
|  | clean_up_exit(1); | 
|  | } | 
|  | *q = '\0'; | 
|  |  | 
|  | if (rm == 0 && gm == 0 && bm == 0) { | 
|  | /* guess masks... */ | 
|  | if (b == 24 || b == 32) { | 
|  | rm = 0xff0000; | 
|  | gm = 0x00ff00; | 
|  | bm = 0x0000ff; | 
|  | } else if (b == 16) { | 
|  | rm = 0xf800; | 
|  | gm = 0x07e0; | 
|  | bm = 0x001f; | 
|  | } else if (b == 8) { | 
|  | rm = 0x07; | 
|  | gm = 0x38; | 
|  | bm = 0xc0; | 
|  | } | 
|  | } | 
|  | /* we can fake -flipbyteorder to some degree... */ | 
|  | if (flip_byte_order) { | 
|  | if (b == 24 || b == 32) { | 
|  | tm = rm; | 
|  | rm = bm; | 
|  | bm = tm; | 
|  | } else if (b == 16) { | 
|  | unsigned short s1, s2; | 
|  | s1 = (unsigned short) rm; | 
|  | s2 = ((0xff & s1) << 8) | ((0xff00 & s1) >> 8); | 
|  | rm = (unsigned long) s2; | 
|  | s1 = (unsigned short) gm; | 
|  | s2 = ((0xff & s1) << 8) | ((0xff00 & s1) >> 8); | 
|  | gm = (unsigned long) s2; | 
|  | s1 = (unsigned short) bm; | 
|  | s2 = ((0xff & s1) << 8) | ((0xff00 & s1) >> 8); | 
|  | bm = (unsigned long) s2; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* native fb stuff for bpp < 8 only */ | 
|  | raw_fb_native_bpp = b; | 
|  | raw_fb_native_red_mask = rm; | 
|  | raw_fb_native_green_mask = gm; | 
|  | raw_fb_native_blue_mask = bm; | 
|  | raw_fb_native_red_shift = 100; | 
|  | raw_fb_native_green_shift = 100; | 
|  | raw_fb_native_blue_shift = 100; | 
|  | raw_fb_native_red_max = 1; | 
|  | raw_fb_native_green_max = 1; | 
|  | raw_fb_native_blue_max = 1; | 
|  | m = 1; | 
|  | for (i=0; i<32; i++)  { | 
|  | if (raw_fb_native_red_mask & m) { | 
|  | if (raw_fb_native_red_shift == 100) { | 
|  | raw_fb_native_red_shift = i; | 
|  | } | 
|  | raw_fb_native_red_max *= 2; | 
|  | } | 
|  | if (raw_fb_native_green_mask & m) { | 
|  | if (raw_fb_native_green_shift == 100) { | 
|  | raw_fb_native_green_shift = i; | 
|  | } | 
|  | raw_fb_native_green_max *= 2; | 
|  | } | 
|  | if (raw_fb_native_blue_mask & m) { | 
|  | if (raw_fb_native_blue_shift == 100) { | 
|  | raw_fb_native_blue_shift = i; | 
|  | } | 
|  | raw_fb_native_blue_max *= 2; | 
|  | } | 
|  | m = m << 1; | 
|  | } | 
|  | raw_fb_native_red_max -= 1; | 
|  | raw_fb_native_green_max -= 1; | 
|  | raw_fb_native_blue_max -= 1; | 
|  |  | 
|  | if (b < 8) { | 
|  | /* e.g. VGA16 */ | 
|  | rfbLog("raw_fb_native_bpp: %d 0x%02lx 0x%02lx 0x%02lx %d/%d/%d %d/%d/%d\n", raw_fb_native_bpp, | 
|  | raw_fb_native_red_mask, raw_fb_native_green_mask, raw_fb_native_blue_mask, | 
|  | raw_fb_native_red_max, raw_fb_native_green_max, raw_fb_native_blue_max, | 
|  | raw_fb_native_red_shift, raw_fb_native_green_shift, raw_fb_native_blue_shift); | 
|  | raw_fb_expand_bytes = 1; | 
|  | b = 8; | 
|  | rm = 0x07; | 
|  | gm = 0x38; | 
|  | bm = 0xc0; | 
|  | } | 
|  | /* end of stuff for bpp < 8 */ | 
|  |  | 
|  | dpy_x = wdpy_x = w; | 
|  | dpy_y = wdpy_y = h; | 
|  | off_x = 0; | 
|  | off_y = 0; | 
|  |  | 
|  | if (rawfb_dev_video) { | 
|  | if (b == 24) { | 
|  | rfbLog("enabling -24to32 for 24bpp video\n"); | 
|  | xform24to32 = 1; | 
|  | } else { | 
|  | if (xform24to32) { | 
|  | rfbLog("disabling -24to32 for 24bpp video\n"); | 
|  | } | 
|  | xform24to32 = 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (xform24to32) { | 
|  | if (b != 24) { | 
|  | rfbLog("warning: -24to32 mode and bpp=%d\n", b); | 
|  | } | 
|  | b = 32; | 
|  | } | 
|  | if (strstr(str, "snap:") == str) { | 
|  | use_snapfb = 1; | 
|  | str[0] = 'f'; str[1] = 'i'; str[2] = 'l'; str[3] = 'e'; | 
|  | } | 
|  |  | 
|  | if (strstr(str, "shm:") != str && strstr(str, "mmap:") != str && | 
|  | strstr(str, "map:") != str && strstr(str, "file:") != str) { | 
|  | /* hmmm, not following directions, see if map: applies */ | 
|  | struct stat sbuf; | 
|  | if (stat(str, &sbuf) == 0) { | 
|  | char *newstr; | 
|  | int len = strlen("map:") + strlen(str) + 1; | 
|  | rfbLog("no type prefix: %s\n", raw_fb_str); | 
|  | rfbLog("  but file exists, so assuming: map:%s\n", | 
|  | raw_fb_str); | 
|  | newstr = (char *) malloc(len); | 
|  | strcpy(newstr, "map:"); | 
|  | strcat(newstr, str); | 
|  | free(str); | 
|  | str = newstr; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (sscanf(str, "shm:%d", &shmid) == 1) { | 
|  | /* shm:N */ | 
|  | #if LIBVNCSERVER_HAVE_XSHM || LIBVNCSERVER_HAVE_SHMAT | 
|  | raw_fb_addr = (char *) shmat(shmid, 0, SHM_RDONLY); | 
|  | if (! raw_fb_addr) { | 
|  | rfbLogEnable(1); | 
|  | rfbLog("failed to attach to shm: %d, %s\n", shmid, str); | 
|  | rfbLogPerror("shmat"); | 
|  | clean_up_exit(1); | 
|  | } | 
|  | raw_fb_shm = 1; | 
|  | rfbLog("rawfb: shm: %d W: %d H: %d B: %d addr: %p\n", | 
|  | shmid, w, h, b, raw_fb_addr); | 
|  | last_mode = RAWFB_SHM; | 
|  | #else | 
|  | rfbLogEnable(1); | 
|  | rfbLog("x11vnc was compiled without shm support.\n"); | 
|  | rfbLogPerror("shmat"); | 
|  | clean_up_exit(1); | 
|  | #endif | 
|  | } else if (strstr(str, "map:") == str || strstr(str, "mmap:") == str | 
|  | || strstr(str, "file:") == str) { | 
|  | /* map:/path/... or file:/path  */ | 
|  | int fd, do_mmap = 1, size; | 
|  | struct stat sbuf; | 
|  |  | 
|  | if (*str == 'f') { | 
|  | do_mmap = 0; | 
|  | } | 
|  | q = strchr(str, ':'); | 
|  | q++; | 
|  |  | 
|  | macosx_console = 0; | 
|  | if (strstr(q, "macosx:") == q) { | 
|  | /* mmap:macosx:/dev/null@... */ | 
|  | q += strlen("macosx:"); | 
|  | do_macosx = 1; | 
|  | do_mmap = 0; | 
|  | macosx_console = 1; | 
|  | } | 
|  |  | 
|  | last_file = strdup(q); | 
|  |  | 
|  | fd = raw_fb_fd; | 
|  | if (fd < 0 && rawfb_dev_video) { | 
|  | fd = open(q, O_RDWR); | 
|  | } | 
|  | if (fd < 0) { | 
|  | fd = open(q, O_RDONLY); | 
|  | } | 
|  | if (fd < 0) { | 
|  | rfbLogEnable(1); | 
|  | rfbLog("failed to open file: %s, %s\n", q, str); | 
|  | rfbLogPerror("open"); | 
|  | linux_dev_fb_msg(q); | 
|  | clean_up_exit(1); | 
|  | } | 
|  | raw_fb_fd = fd; | 
|  |  | 
|  | if (raw_fb_native_bpp < 8) { | 
|  | size = w*h*raw_fb_native_bpp/8 + raw_fb_offset; | 
|  | } else if (xform24to32) { | 
|  | size = w*h*24/8 + raw_fb_offset; | 
|  | } else { | 
|  | size = w*h*b/8 + raw_fb_offset; | 
|  | } | 
|  | if (fstat(fd, &sbuf) == 0) { | 
|  | if (S_ISREG(sbuf.st_mode)) { | 
|  | if (0) size = sbuf.st_size; | 
|  | } else { | 
|  | rfbLog("raw fb is non-regular file: %s\n", q); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (do_macosx) { | 
|  | raw_fb_addr = macosx_get_fb_addr(); | 
|  | raw_fb_mmap = size; | 
|  | rfbLog("rawfb: macosx fb: %s\n", q); | 
|  | rfbLog("   w: %d h: %d b: %d addr: %p sz: %d\n", w, h, | 
|  | b, raw_fb_addr, size); | 
|  | last_mode = 0; | 
|  | } else if (do_reflect) { | 
|  | raw_fb_mmap = size; | 
|  | rfbLog("rawfb: vnc fb: %s\n", q); | 
|  | rfbLog("   w: %d h: %d b: %d addr: %p sz: %d\n", w, h, | 
|  | b, raw_fb_addr, size); | 
|  | last_mode = 0; | 
|  |  | 
|  | } else if (do_mmap) { | 
|  | #if LIBVNCSERVER_HAVE_MMAP | 
|  | raw_fb_addr = mmap(0, size, PROT_READ, MAP_SHARED, | 
|  | fd, 0); | 
|  |  | 
|  | if (raw_fb_addr == MAP_FAILED || raw_fb_addr == NULL) { | 
|  | rfbLogEnable(1); | 
|  | rfbLog("failed to mmap file: %s, %s\n", q, str); | 
|  | rfbLog("   raw_fb_addr: %p\n", raw_fb_addr); | 
|  | rfbLogPerror("mmap"); | 
|  |  | 
|  | raw_fb_addr = NULL; | 
|  | rfbLog("mmap(2) failed, trying slower lseek(2)\n"); | 
|  | raw_fb_seek = size; | 
|  | last_mode = RAWFB_FILE; | 
|  |  | 
|  | } else { | 
|  | raw_fb_mmap = size; | 
|  |  | 
|  | rfbLog("rawfb: mmap file: %s\n", q); | 
|  | rfbLog("   w: %d h: %d b: %d addr: %p sz: %d\n", w, h, | 
|  | b, raw_fb_addr, size); | 
|  | last_mode = RAWFB_MMAP; | 
|  | } | 
|  | #else | 
|  | rfbLog("mmap(2) not supported on system, using" | 
|  | " slower lseek(2)\n"); | 
|  | raw_fb_seek = size; | 
|  | last_mode = RAWFB_FILE; | 
|  | #endif | 
|  | } else { | 
|  | raw_fb_seek = size; | 
|  | last_mode = RAWFB_FILE; | 
|  |  | 
|  | rfbLog("rawfb: seek file: %s\n", q); | 
|  | rfbLog("   W: %d H: %d B: %d sz: %d\n", w, h, b, size); | 
|  | } | 
|  | } else { | 
|  | rfbLogEnable(1); | 
|  | rfbLog("invalid rawfb str: %s\n", str); | 
|  | clean_up_exit(1); | 
|  | } | 
|  |  | 
|  | if (unlink_me) { | 
|  | unlink(unlink_me); | 
|  | } | 
|  |  | 
|  | if (! raw_fb_image) { | 
|  | raw_fb_image = &ximage_struct; | 
|  | } | 
|  |  | 
|  | initialize_clipshift(); | 
|  |  | 
|  | if (raw_fb_bytes_per_line == 0) { | 
|  | raw_fb_bytes_per_line = dpy_x*b/8; | 
|  |  | 
|  | /* | 
|  | * Put cases here were we can determine that | 
|  | * raw_bytes_per_line != dpy_x*b/8 | 
|  | */ | 
|  | #ifdef MACOSX | 
|  | if (do_macosx) { | 
|  | raw_fb_bytes_per_line = macosxCG_CGDisplayBytesPerRow(); | 
|  | } | 
|  | #endif | 
|  | } | 
|  |  | 
|  | raw_fb_image->bytes_per_line = dpy_x * b/8; | 
|  | raw_fb = (char *) malloc(dpy_y * dpy_x * b/8); | 
|  | raw_fb_image->data = raw_fb; | 
|  | raw_fb_image->format = ZPixmap; | 
|  | raw_fb_image->width  = dpy_x; | 
|  | raw_fb_image->height = dpy_y; | 
|  | raw_fb_image->bits_per_pixel = b; | 
|  | raw_fb_image->bitmap_unit = -1; | 
|  |  | 
|  |  | 
|  | if (use_snapfb && (raw_fb_seek || raw_fb_mmap)) { | 
|  | int b_use = b; | 
|  | if (snap_fb) { | 
|  | free(snap_fb); | 
|  | } | 
|  | if (b_use == 32 && xform24to32) { | 
|  | /* | 
|  | * The actual framebuffer (e.g. mapped addr) and | 
|  | * snap fb must be the same bpp.  E.g. both 24bpp. | 
|  | * Reading FROM snap to utility image will be | 
|  | * transformed 24->32 in copy_raw_fb_24_to_32. | 
|  | * | 
|  | * addr -> snap -> (scanline, fullscreen, ...) | 
|  | */ | 
|  | b_use = 24; | 
|  | raw_fb_bytes_per_line = dpy_x * b_use/8; | 
|  | } | 
|  | snap_fb = (char *) malloc(dpy_y * dpy_x * b_use/8); | 
|  | snap = &ximage_struct_snap; | 
|  | snap->data = snap_fb; | 
|  | snap->format = ZPixmap; | 
|  | snap->width  = dpy_x; | 
|  | snap->height = dpy_y; | 
|  | snap->bits_per_pixel = b_use; | 
|  | snap->bytes_per_line = dpy_x * b_use/8; | 
|  | snap->bitmap_unit = -1; | 
|  | } | 
|  |  | 
|  |  | 
|  | raw_fb_image->red_mask = rm; | 
|  | raw_fb_image->green_mask = gm; | 
|  | raw_fb_image->blue_mask = bm; | 
|  |  | 
|  | raw_fb_image->depth = 0; | 
|  | m = 1; | 
|  | for (i=0; i<32; i++)  { | 
|  | if (rm & m) { | 
|  | raw_fb_image->depth++; | 
|  | } | 
|  | if (gm & m) { | 
|  | raw_fb_image->depth++; | 
|  | } | 
|  | if (bm & m) { | 
|  | raw_fb_image->depth++; | 
|  | } | 
|  | m = m << 1; | 
|  | } | 
|  | if (raw_fb_native_bpp < 8) { | 
|  | raw_fb_image->depth = raw_fb_expand_bytes * 8; | 
|  | } | 
|  | if (! raw_fb_image->depth) { | 
|  | raw_fb_image->depth = (b == 32) ? 24 : b; | 
|  | } | 
|  |  | 
|  | depth = raw_fb_image->depth; | 
|  |  | 
|  | if (raw_fb_image->depth == 15) { | 
|  | /* unresolved bug with RGB555... */ | 
|  | depth++; | 
|  | } | 
|  |  | 
|  | if (clipshift || raw_fb_native_bpp < 8) { | 
|  | memset(raw_fb, 0xff, dpy_y * raw_fb_image->bytes_per_line); | 
|  | } else if (raw_fb_addr && ! xform24to32) { | 
|  | memcpy(raw_fb, raw_fb_addr + raw_fb_offset, dpy_y * raw_fb_image->bytes_per_line); | 
|  | } else { | 
|  | memset(raw_fb, 0xff, dpy_y * raw_fb_image->bytes_per_line); | 
|  | } | 
|  |  | 
|  | if (verbose) { | 
|  | rfbLog("\n"); | 
|  | rfbLog("rawfb:  raw_fb  %p\n", raw_fb); | 
|  | rfbLog("        format  %d\n", raw_fb_image->format); | 
|  | rfbLog("        width   %d\n", raw_fb_image->width); | 
|  | rfbLog("        height  %d\n", raw_fb_image->height); | 
|  | rfbLog("        bpp     %d\n", raw_fb_image->bits_per_pixel); | 
|  | rfbLog("        depth   %d\n", raw_fb_image->depth); | 
|  | rfbLog("        bpl     %d\n", raw_fb_image->bytes_per_line); | 
|  | if (use_snapfb && snap_fb) { | 
|  | rfbLog("        snap_fb %p\n", snap_fb); | 
|  | } | 
|  | } | 
|  |  | 
|  | free(str); | 
|  |  | 
|  | return raw_fb_image; | 
|  | } | 
|  |  | 
|  | static void initialize_clipshift(void) { | 
|  | clipshift = 0; | 
|  | cdpy_x = cdpy_y = coff_x = coff_y = 0; | 
|  | if (clip_str) { | 
|  | int w, h, x, y, bad = 0; | 
|  | if (parse_geom(clip_str, &w, &h, &x, &y, wdpy_x, wdpy_y)) { | 
|  | if (x < 0) { | 
|  | x = 0; | 
|  | } | 
|  | if (y < 0) { | 
|  | y = 0; | 
|  | } | 
|  | if (x + w > wdpy_x) { | 
|  | w = wdpy_x - x; | 
|  | } | 
|  | if (y + h > wdpy_y) { | 
|  | h = wdpy_y - y; | 
|  | } | 
|  | if (w <= 0 || h <= 0) { | 
|  | bad = 1; | 
|  | } | 
|  | } else { | 
|  | bad = 1; | 
|  | } | 
|  | if (bad) { | 
|  | rfbLog("*** ignoring invalid -clip WxH+X+Y: %s\n", | 
|  | clip_str); | 
|  | } else { | 
|  | /* OK, change geom behind everyone's back... */ | 
|  | cdpy_x = w; | 
|  | cdpy_y = h; | 
|  | coff_x = x; | 
|  | coff_y = y; | 
|  |  | 
|  | clipshift = 1; | 
|  |  | 
|  | dpy_x = cdpy_x; | 
|  | dpy_y = cdpy_y; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static int wait_until_mapped(Window win) { | 
|  | #if NO_X11 | 
|  | if (!win) {} | 
|  | return 0; | 
|  | #else | 
|  | int ms = 50, waittime = 30; | 
|  | time_t start = time(NULL); | 
|  | XWindowAttributes attr; | 
|  |  | 
|  | while (1) { | 
|  | if (! valid_window(win, NULL, 0)) { | 
|  | if (time(NULL) > start + waittime) { | 
|  | break; | 
|  | } | 
|  | usleep(ms * 1000); | 
|  | continue; | 
|  | } | 
|  | if (dpy && ! XGetWindowAttributes(dpy, win, &attr)) { | 
|  | return 0; | 
|  | } | 
|  | if (attr.map_state == IsViewable) { | 
|  | return 1; | 
|  | } | 
|  | usleep(ms * 1000); | 
|  | } | 
|  | return 0; | 
|  | #endif	/* NO_X11 */ | 
|  | } | 
|  |  | 
|  | /* | 
|  | * initialize a fb for the X display | 
|  | */ | 
|  | XImage *initialize_xdisplay_fb(void) { | 
|  | #if NO_X11 | 
|  | if (raw_fb_str) { | 
|  | return initialize_raw_fb(0); | 
|  | } | 
|  | return NULL; | 
|  | #else | 
|  | XImage *fb; | 
|  | char *vis_str = visual_str; | 
|  | int try = 0, subwin_tries = 3; | 
|  | XErrorHandler old_handler = NULL; | 
|  | int subwin_bs; | 
|  |  | 
|  | if (raw_fb_str) { | 
|  | return initialize_raw_fb(0); | 
|  | } | 
|  |  | 
|  | X_LOCK; | 
|  | if (subwin) { | 
|  | if (subwin_wait_mapped) { | 
|  | wait_until_mapped(subwin); | 
|  | } | 
|  | if (!valid_window((Window) subwin, NULL, 0)) { | 
|  | rfbLogEnable(1); | 
|  | rfbLog("invalid sub-window: 0x%lx\n", subwin); | 
|  | X_UNLOCK; | 
|  | clean_up_exit(1); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (overlay) { | 
|  | /* | 
|  | * ideally we'd like to not have to cook up the | 
|  | * visual variables but rather let it all come out | 
|  | * of XReadScreen(), however there is no way to get | 
|  | * a default visual out of it, so we pretend -visual | 
|  | * TrueColor:NN was supplied with NN usually 24. | 
|  | */ | 
|  | char str[32]; | 
|  | Window twin = subwin ? subwin : rootwin; | 
|  | XImage *xi; | 
|  |  | 
|  | xi = xreadscreen(dpy, twin, 0, 0, 8, 8, False); | 
|  | sprintf(str, "TrueColor:%d", xi->depth); | 
|  | if (xi->depth != 24 && ! quiet) { | 
|  | rfbLog("warning: overlay image has depth %d " | 
|  | "instead of 24.\n", xi->depth); | 
|  | } | 
|  | XDestroyImage(xi); | 
|  | if (visual_str != NULL && ! quiet) { | 
|  | rfbLog("warning: replacing '-visual %s' by '%s' " | 
|  | "for use with -overlay\n", visual_str, str); | 
|  | } | 
|  | vis_str = strdup(str); | 
|  | } | 
|  |  | 
|  | if (xform24to32) { | 
|  | if (DefaultDepth(dpy, scr) == 24) { | 
|  | vis_str = strdup("TrueColor:32"); | 
|  | rfbLog("initialize_xdisplay_fb: vis_str set to: %s\n", | 
|  | vis_str); | 
|  | visual_id = (VisualID) 0; | 
|  | visual_depth = 0; | 
|  | set_visual_str_to_something = 1; | 
|  | } | 
|  | } else if (DefaultDepth(dpy, scr) < 8) { | 
|  | /* check very low bpp case, e.g. mono or vga16 */ | 
|  | Screen *s = DefaultScreenOfDisplay(dpy); | 
|  | XImage *xi = XGetImage_wr(dpy, DefaultRootWindow(dpy), 0, 0, 2, 2, AllPlanes, | 
|  | ZPixmap); | 
|  | if (xi && xi->bits_per_pixel < 8) { | 
|  | int lowbpp = xi->bits_per_pixel; | 
|  | if (!vis_str) { | 
|  | char tmp[32]; | 
|  | sprintf(tmp, "0x%x:8", (int) s->root_visual->visualid); | 
|  | vis_str = strdup(tmp); | 
|  | rfbLog("initialize_xdisplay_fb: low bpp[%d], vis_str " | 
|  | "set to: %s\n", lowbpp, vis_str); | 
|  | } | 
|  | if (using_shm) { | 
|  | using_shm = 0; | 
|  | rfbLog("initialize_xdisplay_fb: low bpp[%d], " | 
|  | "disabling shm\n", lowbpp); | 
|  | } | 
|  | visual_id = (VisualID) 0; | 
|  | visual_depth = 0; | 
|  | set_visual_str_to_something = 1; | 
|  | } | 
|  | if (xi) { | 
|  | XDestroyImage(xi); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (vis_str != NULL) { | 
|  | set_visual(vis_str); | 
|  | if (vis_str != visual_str) { | 
|  | free(vis_str); | 
|  | } | 
|  | } | 
|  | if (0) fprintf(stderr, "vis_str %s\n", vis_str ? vis_str : "notset"); | 
|  |  | 
|  | /* set up parameters for subwin or non-subwin cases: */ | 
|  |  | 
|  | again: | 
|  |  | 
|  | if (! subwin) { | 
|  | /* full screen */ | 
|  | window = rootwin; | 
|  | dpy_x = wdpy_x = DisplayWidth(dpy, scr); | 
|  | dpy_y = wdpy_y = DisplayHeight(dpy, scr); | 
|  | off_x = 0; | 
|  | off_y = 0; | 
|  | /* this may be overridden via visual_id below */ | 
|  | default_visual = DefaultVisual(dpy, scr); | 
|  | } else { | 
|  | /* single window */ | 
|  | XWindowAttributes attr; | 
|  |  | 
|  | window = (Window) subwin; | 
|  | if (! XGetWindowAttributes(dpy, window, &attr)) { | 
|  | rfbLogEnable(1); | 
|  | rfbLog("invalid window: 0x%lx\n", window); | 
|  | X_UNLOCK; | 
|  | clean_up_exit(1); | 
|  | } | 
|  | dpy_x = wdpy_x = attr.width; | 
|  | dpy_y = wdpy_y = attr.height; | 
|  |  | 
|  | subwin_bs = attr.backing_store; | 
|  |  | 
|  | /* this may be overridden via visual_id below */ | 
|  | default_visual = attr.visual; | 
|  |  | 
|  | X_UNLOCK; | 
|  | set_offset(); | 
|  | X_LOCK; | 
|  | } | 
|  |  | 
|  | initialize_clipshift(); | 
|  |  | 
|  | /* initialize depth to reasonable value, visual_id may override */ | 
|  | depth = DefaultDepth(dpy, scr); | 
|  |  | 
|  | if (0) fprintf(stderr, "DefaultDepth: %d  visial_id: %d\n", depth, (int) visual_id); | 
|  |  | 
|  | if (visual_id) { | 
|  | int n; | 
|  | XVisualInfo vinfo_tmpl, *vinfo; | 
|  |  | 
|  | /* | 
|  | * we are in here from -visual or -overlay options | 
|  | * visual_id and visual_depth were set in set_visual(). | 
|  | */ | 
|  |  | 
|  | vinfo_tmpl.visualid = visual_id; | 
|  | vinfo = XGetVisualInfo(dpy, VisualIDMask, &vinfo_tmpl, &n); | 
|  | if (vinfo == NULL || n == 0) { | 
|  | rfbLogEnable(1); | 
|  | rfbLog("could not match visual_id: 0x%x\n", | 
|  | (int) visual_id); | 
|  | X_UNLOCK; | 
|  | clean_up_exit(1); | 
|  | } | 
|  | default_visual = vinfo->visual; | 
|  | depth = vinfo->depth; | 
|  | if (visual_depth) { | 
|  | /* force it from -visual MooColor:NN */ | 
|  | depth = visual_depth; | 
|  | } | 
|  | if (! quiet) { | 
|  | fprintf(stderr, " initialize_xdisplay_fb()\n"); | 
|  | fprintf(stderr, " Visual*:    %p\n", | 
|  | (void *) vinfo->visual); | 
|  | fprintf(stderr, " visualid:   0x%x\n", | 
|  | (int) vinfo->visualid); | 
|  | fprintf(stderr, " screen:     %d\n", vinfo->screen); | 
|  | fprintf(stderr, " depth:      %d\n", vinfo->depth); | 
|  | fprintf(stderr, " class:      %d\n", vinfo->class); | 
|  | fprintf(stderr, " red_mask:   0x%08lx  %s\n", | 
|  | vinfo->red_mask, bitprint(vinfo->red_mask, 32)); | 
|  | fprintf(stderr, " green_mask: 0x%08lx  %s\n", | 
|  | vinfo->green_mask, bitprint(vinfo->green_mask, 32)); | 
|  | fprintf(stderr, " blue_mask:  0x%08lx  %s\n", | 
|  | vinfo->blue_mask, bitprint(vinfo->blue_mask, 32)); | 
|  | fprintf(stderr, " cmap_size:  %d\n", | 
|  | vinfo->colormap_size); | 
|  | fprintf(stderr, " bits b/rgb: %d\n", | 
|  | vinfo->bits_per_rgb); | 
|  | fprintf(stderr, "\n"); | 
|  | } | 
|  | XFree_wr(vinfo); | 
|  | } | 
|  |  | 
|  | if (! quiet) { | 
|  | rfbLog("Default visual ID: 0x%x\n", | 
|  | (int) XVisualIDFromVisual(default_visual)); | 
|  | } | 
|  |  | 
|  | if (subwin) { | 
|  | int shift = 0, resize = 0; | 
|  | int subwin_x, subwin_y; | 
|  | int disp_x = DisplayWidth(dpy, scr); | 
|  | int disp_y = DisplayHeight(dpy, scr); | 
|  | Window twin; | 
|  | /* subwins can be a dicey if they are changing size... */ | 
|  | trapped_xerror = 0; | 
|  | old_handler = XSetErrorHandler(trap_xerror);	/* reset in if(subwin) block below */ | 
|  | XTranslateCoordinates(dpy, window, rootwin, 0, 0, &subwin_x, | 
|  | &subwin_y, &twin); | 
|  |  | 
|  | if (wdpy_x > disp_x) { | 
|  | resize = 1; | 
|  | dpy_x = wdpy_x = disp_x - 4; | 
|  | } | 
|  | if (wdpy_y > disp_y) { | 
|  | resize = 1; | 
|  | dpy_y = wdpy_y = disp_y - 4; | 
|  | } | 
|  |  | 
|  | if (subwin_x + wdpy_x > disp_x) { | 
|  | shift = 1; | 
|  | subwin_x = disp_x - wdpy_x - 3; | 
|  | } | 
|  | if (subwin_y + wdpy_y > disp_y) { | 
|  | shift = 1; | 
|  | subwin_y = disp_y - wdpy_y - 3; | 
|  | } | 
|  | if (subwin_x < 0) { | 
|  | shift = 1; | 
|  | subwin_x = 1; | 
|  | } | 
|  | if (subwin_y < 0) { | 
|  | shift = 1; | 
|  | subwin_y = 1; | 
|  | } | 
|  |  | 
|  | if (resize) { | 
|  | XResizeWindow(dpy, window, wdpy_x, wdpy_y); | 
|  | } | 
|  | if (shift) { | 
|  | XMoveWindow(dpy, window, subwin_x, subwin_y); | 
|  | off_x = subwin_x; | 
|  | off_y = subwin_y; | 
|  | } | 
|  | XMapRaised(dpy, window); | 
|  | XRaiseWindow(dpy, window); | 
|  | XSync(dpy, False); | 
|  | } | 
|  | try++; | 
|  |  | 
|  | if (nofb) { | 
|  | /* | 
|  | * For -nofb we do not allocate the framebuffer, so we | 
|  | * can save a few MB of memory. | 
|  | */ | 
|  | fb = XCreateImage_wr(dpy, default_visual, depth, ZPixmap, | 
|  | 0, NULL, dpy_x, dpy_y, BitmapPad(dpy), 0); | 
|  |  | 
|  | } else if (visual_id) { | 
|  | /* | 
|  | * we need to call XCreateImage to supply the visual | 
|  | */ | 
|  | fb = XCreateImage_wr(dpy, default_visual, depth, ZPixmap, | 
|  | 0, NULL, dpy_x, dpy_y, BitmapPad(dpy), 0); | 
|  | if (fb) { | 
|  | fb->data = (char *) malloc(fb->bytes_per_line * fb->height); | 
|  | } | 
|  |  | 
|  | } else { | 
|  | fb = XGetImage_wr(dpy, window, 0, 0, dpy_x, dpy_y, AllPlanes, | 
|  | ZPixmap); | 
|  | if (! quiet) { | 
|  | rfbLog("Read initial data from X display into" | 
|  | " framebuffer.\n"); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (subwin) { | 
|  | XSetErrorHandler(old_handler); | 
|  | if (trapped_xerror || fb == NULL) { | 
|  | rfbLog("trapped GetImage at SUBWIN creation.\n"); | 
|  | if (try < subwin_tries) { | 
|  | usleep(250 * 1000); | 
|  | if (!get_window_size(window, &wdpy_x, &wdpy_y)) { | 
|  | rfbLogEnable(1); | 
|  | rfbLog("could not get size of subwin " | 
|  | "0x%lx\n", subwin); | 
|  | X_UNLOCK; | 
|  | clean_up_exit(1); | 
|  | } | 
|  | goto again; | 
|  | } | 
|  | } | 
|  | trapped_xerror = 0; | 
|  |  | 
|  | } else if (fb == NULL) { | 
|  | XEvent xev; | 
|  | rfbLog("initialize_xdisplay_fb: *** fb creation failed: 0x%x try: %d\n", fb, try); | 
|  | #if LIBVNCSERVER_HAVE_LIBXRANDR | 
|  | if (xrandr_present && xrandr_base_event_type) { | 
|  | int cnt = 0; | 
|  | while (XCheckTypedEvent(dpy, xrandr_base_event_type + RRScreenChangeNotify, &xev)) { | 
|  | XRRScreenChangeNotifyEvent *rev; | 
|  | rev = (XRRScreenChangeNotifyEvent *) &xev; | 
|  |  | 
|  | rfbLog("initialize_xdisplay_fb: XRANDR event while redoing fb[%d]:\n", cnt++); | 
|  | rfbLog("  serial:          %d\n", (int) rev->serial); | 
|  | rfbLog("  timestamp:       %d\n", (int) rev->timestamp); | 
|  | rfbLog("  cfg_timestamp:   %d\n", (int) rev->config_timestamp); | 
|  | rfbLog("  size_id:         %d\n", (int) rev->size_index); | 
|  | rfbLog("  sub_pixel:       %d\n", (int) rev->subpixel_order); | 
|  | rfbLog("  rotation:        %d\n", (int) rev->rotation); | 
|  | rfbLog("  width:           %d\n", (int) rev->width); | 
|  | rfbLog("  height:          %d\n", (int) rev->height); | 
|  | rfbLog("  mwidth:          %d mm\n", (int) rev->mwidth); | 
|  | rfbLog("  mheight:         %d mm\n", (int) rev->mheight); | 
|  | rfbLog("\n"); | 
|  | rfbLog("previous WxH: %dx%d\n", wdpy_x, wdpy_y); | 
|  |  | 
|  | xrandr_width  = rev->width; | 
|  | xrandr_height = rev->height; | 
|  | xrandr_timestamp = rev->timestamp; | 
|  | xrandr_cfg_time  = rev->config_timestamp; | 
|  | xrandr_rotation = (int) rev->rotation; | 
|  |  | 
|  | rfbLog("initialize_xdisplay_fb: updating XRANDR config...\n"); | 
|  | XRRUpdateConfiguration(&xev); | 
|  | } | 
|  | } | 
|  | #endif | 
|  | if (try < 5)  { | 
|  | XFlush_wr(dpy); | 
|  | usleep(250 * 1000); | 
|  | if (try < 3) { | 
|  | XSync(dpy, False); | 
|  | } else if (try >= 3) { | 
|  | XSync(dpy, True); | 
|  | } | 
|  | goto again; | 
|  | } | 
|  | } | 
|  | if (use_snapfb) { | 
|  | initialize_snap_fb(); | 
|  | } | 
|  |  | 
|  | X_UNLOCK; | 
|  |  | 
|  | if (fb->bits_per_pixel == 24 && ! quiet) { | 
|  | rfbLog("warning: 24 bpp may have poor performance.\n"); | 
|  | } | 
|  | return fb; | 
|  | #endif	/* NO_X11 */ | 
|  | } | 
|  |  | 
|  | void parse_scale_string(char *str, double *factor_x, double *factor_y, int *scaling, int *blend, | 
|  | int *nomult4, int *pad, int *interpolate, int *numer, int *denom, int w_in, int h_in) { | 
|  |  | 
|  | int m, n; | 
|  | char *p, *tstr; | 
|  | double f, f2; | 
|  |  | 
|  | *factor_x = 1.0; | 
|  | *factor_y = 1.0; | 
|  | *scaling = 0; | 
|  | *blend = 1; | 
|  | *nomult4 = 0; | 
|  | *pad = 0; | 
|  | *interpolate = 0; | 
|  | *numer = 0, *denom = 0; | 
|  |  | 
|  | if (str == NULL || str[0] == '\0') { | 
|  | return; | 
|  | } | 
|  | tstr = strdup(str); | 
|  |  | 
|  | if ( (p = strchr(tstr, ':')) != NULL) { | 
|  | /* options */ | 
|  | if (strstr(p+1, "nb") != NULL) { | 
|  | *blend = 0; | 
|  | } | 
|  | if (strstr(p+1, "fb") != NULL) { | 
|  | *blend = 2; | 
|  | } | 
|  | if (strstr(p+1, "n4") != NULL) { | 
|  | *nomult4 = 1; | 
|  | } | 
|  | if (strstr(p+1, "in") != NULL) { | 
|  | *interpolate = 1; | 
|  | } | 
|  | if (strstr(p+1, "pad") != NULL) { | 
|  | *pad = 1; | 
|  | } | 
|  | if (strstr(p+1, "nocr") != NULL) { | 
|  | /* global */ | 
|  | scaling_copyrect = 0; | 
|  | } else if (strstr(p+1, "cr") != NULL) { | 
|  | /* global */ | 
|  | scaling_copyrect = 1; | 
|  | } | 
|  | *p = '\0'; | 
|  | } | 
|  |  | 
|  | if (strchr(tstr, '.') != NULL) { | 
|  | double test, diff, eps = 1.0e-7; | 
|  | if (sscanf(tstr, "%lfx%lf", &f, &f2) == 2) { | 
|  | *factor_x = (double) f; | 
|  | *factor_y = (double) f2; | 
|  | } else if (sscanf(tstr, "%lf", &f) != 1) { | 
|  | rfbLogEnable(1); | 
|  | rfbLog("invalid -scale arg: %s\n", tstr); | 
|  | clean_up_exit(1); | 
|  | } else { | 
|  | *factor_x = (double) f; | 
|  | *factor_y = (double) f; | 
|  | } | 
|  | /* look for common fractions from small ints: */ | 
|  | if (*factor_x == *factor_y) { | 
|  | for (n=2; n<=10; n++) { | 
|  | for (m=1; m<n; m++) { | 
|  | test = ((double) m)/ n; | 
|  | diff = *factor_x - test; | 
|  | if (-eps < diff && diff < eps) { | 
|  | *numer = m; | 
|  | *denom = n; | 
|  | break; | 
|  |  | 
|  | } | 
|  | } | 
|  | if (*denom) { | 
|  | break; | 
|  | } | 
|  | } | 
|  | if (*factor_x < 0.01) { | 
|  | rfbLogEnable(1); | 
|  | rfbLog("-scale factor too small: %f\n", *factor_x); | 
|  | clean_up_exit(1); | 
|  | } | 
|  | } | 
|  | } else if (sscanf(tstr, "%dx%d", &m, &n) == 2 && w_in > 0 && h_in > 0) { | 
|  | *factor_x = ((double) m) / ((double) w_in); | 
|  | *factor_y = ((double) n) / ((double) h_in); | 
|  | } else { | 
|  | if (sscanf(tstr, "%d/%d", &m, &n) != 2) { | 
|  | if (sscanf(tstr, "%d", &m) != 1) { | 
|  | rfbLogEnable(1); | 
|  | rfbLog("invalid -scale arg: %s\n", tstr); | 
|  | clean_up_exit(1); | 
|  | } else { | 
|  | /* e.g. -scale 1 or -scale 2 */ | 
|  | n = 1; | 
|  | } | 
|  | } | 
|  | if (n <= 0 || m <=0) { | 
|  | rfbLogEnable(1); | 
|  | rfbLog("invalid -scale arg: %s\n", tstr); | 
|  | clean_up_exit(1); | 
|  | } | 
|  | *factor_x = ((double) m)/ n; | 
|  | *factor_y = ((double) m)/ n; | 
|  | if (*factor_x < 0.01) { | 
|  | rfbLogEnable(1); | 
|  | rfbLog("-scale factor too small: %f\n", *factor_x); | 
|  | clean_up_exit(1); | 
|  | } | 
|  | *numer = m; | 
|  | *denom = n; | 
|  | } | 
|  | if (*factor_x == 1.0 && *factor_y == 1.0) { | 
|  | if (! quiet) { | 
|  | rfbLog("scaling disabled for factor %f %f\n", *factor_x, *factor_y); | 
|  | } | 
|  | } else { | 
|  | *scaling = 1; | 
|  | } | 
|  | free(tstr); | 
|  | } | 
|  |  | 
|  | int parse_rotate_string(char *str, int *mode) { | 
|  | int m = ROTATE_NONE; | 
|  | if (str == NULL || !strcmp(str, "") || !strcmp(str, "0")) { | 
|  | m = ROTATE_NONE; | 
|  | } else if (!strcmp(str, "x")) { | 
|  | m = ROTATE_X; | 
|  | } else if (!strcmp(str, "y")) { | 
|  | m = ROTATE_Y; | 
|  | } else if (!strcmp(str, "xy") || !strcmp(str, "yx") || | 
|  | !strcmp(str,"+180") || !strcmp(str,"-180") || !strcmp(str,"180")) { | 
|  | m = ROTATE_XY; | 
|  | } else if (!strcmp(str, "+90") || !strcmp(str, "90")) { | 
|  | m = ROTATE_90; | 
|  | } else if (!strcmp(str, "+90x") || !strcmp(str, "90x")) { | 
|  | m = ROTATE_90X; | 
|  | } else if (!strcmp(str, "+90y") || !strcmp(str, "90y")) { | 
|  | m = ROTATE_90Y; | 
|  | } else if (!strcmp(str, "-90") || !strcmp(str, "270") || | 
|  | !strcmp(str, "+270")) { | 
|  | m = ROTATE_270; | 
|  | } else { | 
|  | rfbLog("invalid -rotate mode: %s\n", str); | 
|  | } | 
|  | if (mode) { | 
|  | *mode = m; | 
|  | } | 
|  | return m; | 
|  | } | 
|  |  | 
|  | int scale_round(int len, double fac) { | 
|  | double eps = 0.000001; | 
|  |  | 
|  | len = (int) (len * fac + eps); | 
|  | if (len < 1) { | 
|  | len = 1; | 
|  | } | 
|  | return len; | 
|  | } | 
|  |  | 
|  | static void setup_scaling(int *width_in, int *height_in) { | 
|  | int width  = *width_in; | 
|  | int height = *height_in; | 
|  |  | 
|  | parse_scale_string(scale_str, &scale_fac_x, &scale_fac_y, &scaling, &scaling_blend, | 
|  | &scaling_nomult4, &scaling_pad, &scaling_interpolate, | 
|  | &scale_numer, &scale_denom, *width_in, *height_in); | 
|  |  | 
|  | if (scaling) { | 
|  | width  = scale_round(width,  scale_fac_x); | 
|  | height = scale_round(height, scale_fac_y); | 
|  | if (scale_denom && scaling_pad) { | 
|  | /* it is not clear this padding is useful anymore */ | 
|  | rfbLog("width  %% denom: %d %% %d = %d\n", width, | 
|  | scale_denom, width  % scale_denom); | 
|  | rfbLog("height %% denom: %d %% %d = %d\n", height, | 
|  | scale_denom, height % scale_denom); | 
|  | if (width % scale_denom != 0) { | 
|  | int w = width; | 
|  | w += scale_denom - (w % scale_denom); | 
|  | if (!scaling_nomult4 && w % 4 != 0) { | 
|  | /* need to make mult of 4 as well */ | 
|  | int c = 0; | 
|  | while (w % 4 != 0 && c++ <= 5) { | 
|  | w += scale_denom; | 
|  | } | 
|  | } | 
|  | width = w; | 
|  | rfbLog("padded width  to: %d (mult of %d%s\n", | 
|  | width, scale_denom, !scaling_nomult4 ? | 
|  | " and 4)" : ")"); | 
|  | } | 
|  | if (height % scale_denom != 0) { | 
|  | height += scale_denom - (height % scale_denom); | 
|  | rfbLog("padded height to: %d (mult of %d)\n", | 
|  | height, scale_denom); | 
|  | } | 
|  | } | 
|  | if (!scaling_nomult4 && width % 4 != 0 && width > 2) { | 
|  | /* reset width to be multiple of 4 */ | 
|  | int width0 = width; | 
|  | if ((width+1) % 4 == 0) { | 
|  | width = width+1; | 
|  | } else if ((width-1) % 4 == 0) { | 
|  | width = width-1; | 
|  | } else if ((width+2) % 4 == 0) { | 
|  | width = width+2; | 
|  | } | 
|  | rfbLog("reset scaled width %d -> %d to be a multiple of" | 
|  | " 4 (to\n", width0, width); | 
|  | rfbLog("make vncviewers happy). use -scale m/n:n4 to " | 
|  | "disable.\n"); | 
|  | } | 
|  | scaled_x = width; | 
|  | scaled_y = height; | 
|  |  | 
|  | *width_in  = width; | 
|  | *height_in = height; | 
|  | } | 
|  | } | 
|  |  | 
|  | static void setup_rotating(void) { | 
|  | char *rs = rotating_str; | 
|  |  | 
|  | rotating_cursors = 1; | 
|  | if (rs && strstr(rs, "nc:") == rs) { | 
|  | rs += strlen("nc:"); | 
|  | rotating_cursors = 0; | 
|  | } | 
|  |  | 
|  | rotating = parse_rotate_string(rs, NULL); | 
|  | if (! rotating) { | 
|  | rotating_cursors = 0; | 
|  | } | 
|  |  | 
|  | if (rotating == ROTATE_90  || rotating == ROTATE_90X || | 
|  | rotating == ROTATE_90Y || rotating == ROTATE_270) { | 
|  | rotating_same = 0; | 
|  | } else { | 
|  | rotating_same = 1; | 
|  | } | 
|  | } | 
|  |  | 
|  | static rfbBool set_xlate_wrapper(rfbClientPtr cl) { | 
|  | static int first = 1; | 
|  | if (first) { | 
|  | first = 0; | 
|  | } else if (ncache) { | 
|  | int save = ncache_xrootpmap; | 
|  | rfbLog("set_xlate_wrapper: clearing -ncache for new pixel format.\n"); | 
|  | INPUT_LOCK; | 
|  | ncache_xrootpmap = 0; | 
|  | check_ncache(1, 0); | 
|  | ncache_xrootpmap = save; | 
|  | INPUT_UNLOCK; | 
|  | } | 
|  | return rfbSetTranslateFunction(cl); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * initialize the rfb framebuffer/screen | 
|  | */ | 
|  | void initialize_screen(int *argc, char **argv, XImage *fb) { | 
|  | int have_masks = 0; | 
|  | int width  = fb->width; | 
|  | int height = fb->height; | 
|  | int create_screen = screen ? 0 : 1; | 
|  | int bits_per_color; | 
|  | int fb_bpp, fb_Bpl, fb_depth; | 
|  | int locked_sends = 0; | 
|  |  | 
|  | bpp = fb->bits_per_pixel; | 
|  |  | 
|  | fb_bpp   = (int) fb->bits_per_pixel; | 
|  | fb_Bpl   = (int) fb->bytes_per_line; | 
|  | fb_depth = (int) fb->depth; | 
|  |  | 
|  | rfbLog("initialize_screen: fb_depth/fb_bpp/fb_Bpl %d/%d/%d\n", fb_depth, | 
|  | fb_bpp, fb_Bpl); | 
|  |  | 
|  | main_bytes_per_line = fb->bytes_per_line; | 
|  |  | 
|  | if (cmap8to24) { | 
|  | if (raw_fb) { | 
|  | if (!quiet) rfbLog("disabling -8to24 mode" | 
|  | " in raw_fb mode.\n"); | 
|  | cmap8to24 = 0; | 
|  | } else if (depth == 24) { | 
|  | if (fb_bpp != 32)  { | 
|  | if (!quiet) rfbLog("disabling -8to24 mode:" | 
|  | " bpp != 32 with depth == 24\n"); | 
|  | cmap8to24 = 0; | 
|  | } | 
|  | } else if (depth <= 16) { | 
|  | /* need to cook up the screen fb to be depth 24 */ | 
|  | fb_bpp = 32; | 
|  | fb_depth = 24; | 
|  | } else { | 
|  | if (!quiet) rfbLog("disabling -8to24 mode:" | 
|  | " default depth not 16 or less\n"); | 
|  | cmap8to24 = 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | setup_scaling(&width, &height); | 
|  |  | 
|  | if (scaling) { | 
|  | rfbLog("scaling screen: %dx%d -> %dx%d\n", fb->width, fb->height, scaled_x, scaled_y); | 
|  | rfbLog("scaling screen: scale_fac_x=%.5f scale_fac_y=%.5f\n", scale_fac_x, scale_fac_y); | 
|  |  | 
|  | rfb_bytes_per_line = (main_bytes_per_line / fb->width) * width; | 
|  | } else { | 
|  | rfb_bytes_per_line = main_bytes_per_line; | 
|  | } | 
|  |  | 
|  | setup_rotating(); | 
|  |  | 
|  | if (rotating) { | 
|  | if (! rotating_same) { | 
|  | int t, b = main_bytes_per_line / fb->width; | 
|  | if (scaling) { | 
|  | rot_bytes_per_line = b * height; | 
|  | } else { | 
|  | rot_bytes_per_line = b * fb->height; | 
|  | } | 
|  | t = width; | 
|  | width = height;		/* The big swap... */ | 
|  | height = t; | 
|  | } else { | 
|  | rot_bytes_per_line = rfb_bytes_per_line; | 
|  | } | 
|  | } | 
|  |  | 
|  | #ifndef NO_NCACHE | 
|  | if (ncache > 0 && !nofb) { | 
|  | # ifdef MACOSX | 
|  | if (! raw_fb_str || macosx_console) { | 
|  | # else | 
|  | if (! raw_fb_str) { | 
|  | # endif | 
|  |  | 
|  | char *new_fb; | 
|  | int sz = fb->height * fb->bytes_per_line; | 
|  | int ns = 1+ncache; | 
|  |  | 
|  | if (ncache_xrootpmap) { | 
|  | ns++; | 
|  | } | 
|  |  | 
|  | new_fb = (char *) calloc((size_t) (sz * ns), 1); | 
|  | if (fb->data) { | 
|  | memcpy(new_fb, fb->data, sz); | 
|  | free(fb->data); | 
|  | } | 
|  | fb->data = new_fb; | 
|  | fb->height *= (ns); | 
|  | height *= (ns); | 
|  | ncache0 = ncache; | 
|  | } | 
|  | } | 
|  | #endif | 
|  |  | 
|  | if (cmap8to24) { | 
|  | if (depth <= 8) { | 
|  | rfb_bytes_per_line *= 4; | 
|  | rot_bytes_per_line *= 4; | 
|  | } else if (depth <= 16) { | 
|  | rfb_bytes_per_line *= 2; | 
|  | rot_bytes_per_line *= 2; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* | 
|  | * These are just hints wrt pixel format just to let | 
|  | * rfbGetScreen/rfbNewFramebuffer proceed with reasonable | 
|  | * defaults.  We manually set them in painful detail below. | 
|  | */ | 
|  | bits_per_color = guess_bits_per_color(fb_bpp); | 
|  |  | 
|  | if (lock_client_sends(-1) == 0) { | 
|  | lock_client_sends(1); | 
|  | locked_sends = 1; | 
|  | } | 
|  |  | 
|  | /* n.b. samplesPerPixel (set = 1 here) seems to be unused. */ | 
|  | if (create_screen) { | 
|  | if (use_stunnel) { | 
|  | setup_stunnel(0, argc, argv); | 
|  | } | 
|  | if (use_openssl) { | 
|  | if (use_stunnel && enc_str && !strcmp(enc_str, "none")) { | 
|  | /* emulating HTTPS oneport */ | 
|  | ; | 
|  | } else { | 
|  | openssl_init(0); | 
|  | } | 
|  | } | 
|  | screen = rfbGetScreen(argc, argv, width, height, | 
|  | bits_per_color, 1, fb_bpp/8); | 
|  | if (screen && http_dir) { | 
|  | http_connections(1); | 
|  | } | 
|  | if (unix_sock) { | 
|  | unix_sock_fd = listen_unix(unix_sock); | 
|  | } | 
|  | } else { | 
|  | /* set set frameBuffer member below. */ | 
|  | rfbLog("rfbNewFramebuffer(0x%x, 0x%x, %d, %d, %d, %d, %d)\n", | 
|  | screen, NULL, width, height, bits_per_color, 1, fb_bpp/8); | 
|  |  | 
|  | /* these are probably overwritten, but just to be safe: */ | 
|  | screen->bitsPerPixel = fb_bpp; | 
|  | screen->depth = fb_depth; | 
|  |  | 
|  | rfb_new_framebuffer(screen, NULL, width, height, | 
|  | bits_per_color, 1, (int) fb_bpp/8); | 
|  | } | 
|  | if (! screen) { | 
|  | int i; | 
|  | rfbLogEnable(1); | 
|  | rfbLog("\n"); | 
|  | rfbLog("failed to create rfb screen.\n"); | 
|  | for (i=0; i< *argc; i++)  { | 
|  | rfbLog("\t[%d]  %s\n", i, argv[i]); | 
|  | } | 
|  | clean_up_exit(1); | 
|  | } | 
|  |  | 
|  | if (create_screen && *argc != 1) { | 
|  | int i; | 
|  | rfbLogEnable(1); | 
|  | rfbLog("*** unrecognized option(s) ***\n"); | 
|  | for (i=1; i< *argc; i++)  { | 
|  | rfbLog("\t[%d]  %s\n", i, argv[i]); | 
|  | } | 
|  | rfbLog("For a list of options run: x11vnc -opts\n"); | 
|  | rfbLog("or for the full help: x11vnc -help\n"); | 
|  | rfbLog("\n"); | 
|  | rfbLog("Here is a list of removed or obsolete" | 
|  | " options:\n"); | 
|  | rfbLog("\n"); | 
|  | rfbLog("removed: -hints, -nohints\n"); | 
|  | rfbLog("removed: -cursorposall\n"); | 
|  | rfbLog("removed: -nofilexfer, now the default.\n"); | 
|  | rfbLog("\n"); | 
|  | rfbLog("renamed: -old_copytile, use -onetile\n"); | 
|  | rfbLog("renamed: -mouse,   use -cursor\n"); | 
|  | rfbLog("renamed: -mouseX,  use -cursor X\n"); | 
|  | rfbLog("renamed: -X,       use -cursor X\n"); | 
|  | rfbLog("renamed: -nomouse, use -nocursor\n"); | 
|  | rfbLog("renamed: -old_pointer, use -pointer_mode 1\n"); | 
|  |  | 
|  | clean_up_exit(1); | 
|  | } | 
|  |  | 
|  | /* set up format from scratch: */ | 
|  | if (rotating && ! rotating_same) { | 
|  | screen->paddedWidthInBytes = rot_bytes_per_line; | 
|  | } else { | 
|  | screen->paddedWidthInBytes = rfb_bytes_per_line; | 
|  | } | 
|  | screen->serverFormat.bitsPerPixel = fb_bpp; | 
|  | screen->serverFormat.depth = fb_depth; | 
|  | screen->serverFormat.trueColour = TRUE; | 
|  |  | 
|  | screen->serverFormat.redShift   = 0; | 
|  | screen->serverFormat.greenShift = 0; | 
|  | screen->serverFormat.blueShift  = 0; | 
|  | screen->serverFormat.redMax     = 0; | 
|  | screen->serverFormat.greenMax   = 0; | 
|  | screen->serverFormat.blueMax    = 0; | 
|  |  | 
|  | /* these main_* formats are used generally. */ | 
|  | main_red_shift   = 0; | 
|  | main_green_shift = 0; | 
|  | main_blue_shift  = 0; | 
|  | main_red_max     = 0; | 
|  | main_green_max   = 0; | 
|  | main_blue_max    = 0; | 
|  | main_red_mask    = fb->red_mask; | 
|  | main_green_mask  = fb->green_mask; | 
|  | main_blue_mask   = fb->blue_mask; | 
|  |  | 
|  | have_masks = ((fb->red_mask|fb->green_mask|fb->blue_mask) != 0); | 
|  | if (force_indexed_color) { | 
|  | have_masks = 0; | 
|  | } | 
|  |  | 
|  | if (cmap8to24 && depth <= 16 && dpy) { | 
|  | XVisualInfo vinfo; | 
|  | vinfo.red_mask = 0; | 
|  | vinfo.green_mask = 0; | 
|  | vinfo.blue_mask = 0; | 
|  | /* more cooking up... */ | 
|  | have_masks = 2; | 
|  | /* need to fetch TrueColor visual */ | 
|  | X_LOCK; | 
|  | if (dpy | 
|  | #if !NO_X11 | 
|  | && XMatchVisualInfo(dpy, scr, 24, TrueColor, &vinfo) | 
|  | #endif | 
|  | ) { | 
|  | main_red_mask   = vinfo.red_mask; | 
|  | main_green_mask = vinfo.green_mask; | 
|  | main_blue_mask  = vinfo.blue_mask; | 
|  | } else if (fb->byte_order == LSBFirst) { | 
|  | main_red_mask   = 0x00ff0000; | 
|  | main_green_mask = 0x0000ff00; | 
|  | main_blue_mask  = 0x000000ff; | 
|  | } else { | 
|  | main_red_mask   = 0x000000ff; | 
|  | main_green_mask = 0x0000ff00; | 
|  | main_blue_mask  = 0x00ff0000; | 
|  | } | 
|  | X_UNLOCK; | 
|  | } | 
|  |  | 
|  | if (raw_fb_str && raw_fb_pixfmt) { | 
|  | char *fmt = strdup(raw_fb_pixfmt); | 
|  | uppercase(fmt); | 
|  | if (strstr(fmt, "GREY")) { | 
|  | set_greyscale_colormap(); | 
|  | } else if (strstr(fmt, "HI240")) { | 
|  | set_hi240_colormap(); | 
|  | } else { | 
|  | unset_colormap(); | 
|  | } | 
|  | free(fmt); | 
|  | } | 
|  |  | 
|  | if (! have_masks && screen->serverFormat.bitsPerPixel <= 16 | 
|  | && dpy && CellsOfScreen(ScreenOfDisplay(dpy, scr))) { | 
|  | /* indexed color. we let 1 <= bpp <= 16, but it is normally 8 */ | 
|  | if (!quiet) { | 
|  | rfbLog("\n"); | 
|  | rfbLog("X display %s is %dbpp indexed color, depth=%d\n", | 
|  | DisplayString(dpy), screen->serverFormat.bitsPerPixel, | 
|  | screen->serverFormat.depth); | 
|  | if (! flash_cmap && ! overlay) { | 
|  | rfbLog("\n"); | 
|  | rfbLog("In 8bpp PseudoColor mode if you " | 
|  | "experience color\n"); | 
|  | rfbLog("problems you may want to enable " | 
|  | "following the\n"); | 
|  | rfbLog("changing colormap by using the " | 
|  | "-flashcmap option.\n"); | 
|  | rfbLog("\n"); | 
|  | } | 
|  | } | 
|  | if (screen->serverFormat.depth < 8) { | 
|  | rfbLog("resetting serverFormat.depth %d -> 8.\n", | 
|  | screen->serverFormat.depth); | 
|  | rfbLog("resetting serverFormat.bpp   %d -> 8.\n", | 
|  | screen->serverFormat.bitsPerPixel); | 
|  | screen->serverFormat.depth = 8; | 
|  | screen->serverFormat.bitsPerPixel = 8; | 
|  | } | 
|  | if (screen->serverFormat.depth > 8) { | 
|  | rfbLog("WARNING: indexed color depth > 8, Tight encoding will crash.\n"); | 
|  | } | 
|  |  | 
|  | screen->serverFormat.trueColour = FALSE; | 
|  | indexed_color = 1; | 
|  | set_colormap(1); | 
|  | debug_colormap(fb); | 
|  | } else { | 
|  | /* | 
|  | * general case, we call it truecolor, but could be direct | 
|  | * color, static color, etc.... | 
|  | */ | 
|  | if (! quiet) { | 
|  | if (raw_fb) { | 
|  | rfbLog("\n"); | 
|  | rfbLog("Raw fb at addr %p is %dbpp depth=%d " | 
|  | "true color\n", raw_fb_addr, | 
|  | fb_bpp, fb_depth); | 
|  | } else if (! dpy) { | 
|  | ; | 
|  | } else if (have_masks == 2) { | 
|  | rfbLog("\n"); | 
|  | rfbLog("X display %s is %dbpp depth=%d indexed " | 
|  | "color (-8to24 mode)\n", DisplayString(dpy), | 
|  | fb->bits_per_pixel, fb->depth); | 
|  | } else { | 
|  | rfbLog("\n"); | 
|  | rfbLog("X display %s is %dbpp depth=%d true " | 
|  | "color\n", DisplayString(dpy), | 
|  | fb_bpp, fb_depth); | 
|  | } | 
|  | } | 
|  |  | 
|  | indexed_color = 0; | 
|  |  | 
|  | if (!have_masks) { | 
|  | int M, B = bits_per_color; | 
|  |  | 
|  | if (3*B > fb_bpp) B--; | 
|  | if (B < 1) B = 1; | 
|  | M = (1 << B) - 1; | 
|  |  | 
|  | rfbLog("WARNING: all TrueColor RGB masks are zero!\n"); | 
|  | rfbLog("WARNING: cooking something up for VNC fb...  B=%d M=%d\n", B, M); | 
|  | main_red_mask   = M; | 
|  | main_green_mask = M; | 
|  | main_blue_mask  = M; | 
|  | main_red_mask   = main_red_mask   << (2*B); | 
|  | main_green_mask = main_green_mask << (1*B); | 
|  | main_blue_mask  = main_blue_mask  << (0*B); | 
|  | fprintf(stderr, " red_mask:   0x%08lx  %s\n", main_red_mask, | 
|  | bitprint(main_red_mask, 32)); | 
|  | fprintf(stderr, " green_mask: 0x%08lx  %s\n", main_green_mask, | 
|  | bitprint(main_green_mask, 32)); | 
|  | fprintf(stderr, " blue_mask:  0x%08lx  %s\n", main_blue_mask, | 
|  | bitprint(main_blue_mask, 32)); | 
|  | } | 
|  |  | 
|  | /* convert masks to bit shifts and max # colors */ | 
|  | if (main_red_mask) { | 
|  | while (! (main_red_mask | 
|  | & (1 << screen->serverFormat.redShift))) { | 
|  | screen->serverFormat.redShift++; | 
|  | } | 
|  | } | 
|  | if (main_green_mask) { | 
|  | while (! (main_green_mask | 
|  | & (1 << screen->serverFormat.greenShift))) { | 
|  | screen->serverFormat.greenShift++; | 
|  | } | 
|  | } | 
|  | if (main_blue_mask) { | 
|  | while (! (main_blue_mask | 
|  | & (1 << screen->serverFormat.blueShift))) { | 
|  | screen->serverFormat.blueShift++; | 
|  | } | 
|  | } | 
|  | screen->serverFormat.redMax | 
|  | = main_red_mask   >> screen->serverFormat.redShift; | 
|  | screen->serverFormat.greenMax | 
|  | = main_green_mask >> screen->serverFormat.greenShift; | 
|  | screen->serverFormat.blueMax | 
|  | = main_blue_mask  >> screen->serverFormat.blueShift; | 
|  |  | 
|  | main_red_max     = screen->serverFormat.redMax; | 
|  | main_green_max   = screen->serverFormat.greenMax; | 
|  | main_blue_max    = screen->serverFormat.blueMax; | 
|  |  | 
|  | main_red_shift   = screen->serverFormat.redShift; | 
|  | main_green_shift = screen->serverFormat.greenShift; | 
|  | main_blue_shift  = screen->serverFormat.blueShift; | 
|  | } | 
|  |  | 
|  | #if !SMALL_FOOTPRINT | 
|  | if (verbose) { | 
|  | fprintf(stderr, "\n"); | 
|  | fprintf(stderr, "FrameBuffer Info:\n"); | 
|  | fprintf(stderr, " width:            %d\n", fb->width); | 
|  | fprintf(stderr, " height:           %d\n", fb->height); | 
|  | fprintf(stderr, " scaled_width:     %d\n", width); | 
|  | fprintf(stderr, " scaled_height:    %d\n", height); | 
|  | fprintf(stderr, " indexed_color:    %d\n", indexed_color); | 
|  | fprintf(stderr, " bits_per_pixel:   %d\n", fb->bits_per_pixel); | 
|  | fprintf(stderr, " depth:            %d\n", fb->depth); | 
|  | fprintf(stderr, " red_mask:   0x%08lx  %s\n", fb->red_mask, | 
|  | bitprint(fb->red_mask, 32)); | 
|  | fprintf(stderr, " green_mask: 0x%08lx  %s\n", fb->green_mask, | 
|  | bitprint(fb->green_mask, 32)); | 
|  | fprintf(stderr, " blue_mask:  0x%08lx  %s\n", fb->blue_mask, | 
|  | bitprint(fb->blue_mask, 32)); | 
|  | if (cmap8to24) { | 
|  | fprintf(stderr, " 8to24 info:\n"); | 
|  | fprintf(stderr, " fb_bpp:           %d\n", fb_bpp); | 
|  | fprintf(stderr, " fb_depth:         %d\n", fb_depth); | 
|  | fprintf(stderr, " red_mask:   0x%08lx  %s\n", main_red_mask, | 
|  | bitprint(main_red_mask, 32)); | 
|  | fprintf(stderr, " green_mask: 0x%08lx  %s\n", main_green_mask, | 
|  | bitprint(main_green_mask, 32)); | 
|  | fprintf(stderr, " blue_mask:  0x%08lx  %s\n", main_blue_mask, | 
|  | bitprint(main_blue_mask, 32)); | 
|  | } | 
|  | fprintf(stderr, " red:   max: %3d  shift: %2d\n", | 
|  | main_red_max, main_red_shift); | 
|  | fprintf(stderr, " green: max: %3d  shift: %2d\n", | 
|  | main_green_max, main_green_shift); | 
|  | fprintf(stderr, " blue:  max: %3d  shift: %2d\n", | 
|  | main_blue_max, main_blue_shift); | 
|  | fprintf(stderr, " mainfb_bytes_per_line: %d\n", | 
|  | main_bytes_per_line); | 
|  | fprintf(stderr, " rfb_fb_bytes_per_line: %d\n", | 
|  | rfb_bytes_per_line); | 
|  | fprintf(stderr, " rot_fb_bytes_per_line: %d\n", | 
|  | rot_bytes_per_line); | 
|  | fprintf(stderr, " raw_fb_bytes_per_line: %d\n", | 
|  | raw_fb_bytes_per_line); | 
|  | switch(fb->format) { | 
|  | case XYBitmap: | 
|  | fprintf(stderr, " format:     XYBitmap\n"); break; | 
|  | case XYPixmap: | 
|  | fprintf(stderr, " format:     XYPixmap\n"); break; | 
|  | case ZPixmap: | 
|  | fprintf(stderr, " format:     ZPixmap\n"); break; | 
|  | default: | 
|  | fprintf(stderr, " format:     %d\n", fb->format); break; | 
|  | } | 
|  | switch(fb->byte_order) { | 
|  | case LSBFirst: | 
|  | fprintf(stderr, " byte_order: LSBFirst\n"); break; | 
|  | case MSBFirst: | 
|  | fprintf(stderr, " byte_order: MSBFirst\n"); break; | 
|  | default: | 
|  | fprintf(stderr, " byte_order: %d\n", fb->byte_order); | 
|  | break; | 
|  | } | 
|  | fprintf(stderr, " bitmap_pad:  %d\n", fb->bitmap_pad); | 
|  | fprintf(stderr, " bitmap_unit: %d\n", fb->bitmap_unit); | 
|  | switch(fb->bitmap_bit_order) { | 
|  | case LSBFirst: | 
|  | fprintf(stderr, " bitmap_bit_order: LSBFirst\n"); break; | 
|  | case MSBFirst: | 
|  | fprintf(stderr, " bitmap_bit_order: MSBFirst\n"); break; | 
|  | default: | 
|  | fprintf(stderr, " bitmap_bit_order: %d\n", | 
|  | fb->bitmap_bit_order); break; | 
|  | } | 
|  | } | 
|  | if (overlay && ! quiet) { | 
|  | rfbLog("\n"); | 
|  | rfbLog("Overlay mode enabled:  If you experience color\n"); | 
|  | rfbLog("problems when popup menus are on the screen, try\n"); | 
|  | rfbLog("disabling SaveUnders in your X server, one way is\n"); | 
|  | rfbLog("to start the X server with the '-su' option, e.g.:\n"); | 
|  | rfbLog("Xsun -su ... see Xserver(1), xinit(1) for more info.\n"); | 
|  | rfbLog("\n"); | 
|  | } | 
|  | #endif | 
|  | /* nofb is for pointer/keyboard only handling.  */ | 
|  | if (nofb) { | 
|  | main_fb = NULL; | 
|  | rfb_fb = main_fb; | 
|  | cmap8to24_fb = NULL; | 
|  | rot_fb = NULL; | 
|  | screen->displayHook = nofb_hook; | 
|  | } else { | 
|  | main_fb = fb->data; | 
|  | rfb_fb = NULL; | 
|  | cmap8to24_fb = NULL; | 
|  | rot_fb = NULL; | 
|  |  | 
|  | if (cmap8to24) { | 
|  | int n = main_bytes_per_line * fb->height; | 
|  | if (depth <= 8) { | 
|  | n *= 4; | 
|  | } else if (depth <= 16) { | 
|  | n *= 2; | 
|  | } | 
|  | cmap8to24_fb = (char *) malloc(n); | 
|  | memset(cmap8to24_fb, 0, n); | 
|  | } | 
|  |  | 
|  | if (rotating) { | 
|  | int n = rot_bytes_per_line * height; | 
|  | rot_fb = (char *) malloc(n); | 
|  | memset(rot_fb, 0, n); | 
|  | } | 
|  |  | 
|  | if (scaling) { | 
|  | int n = rfb_bytes_per_line * height; | 
|  |  | 
|  | if (rotating && ! rotating_same) { | 
|  | n = rot_bytes_per_line * height; | 
|  | } | 
|  |  | 
|  | rfb_fb = (char *) malloc(n); | 
|  | memset(rfb_fb, 0, n); | 
|  |  | 
|  | } else if (cmap8to24) { | 
|  | rfb_fb = cmap8to24_fb; | 
|  | } else { | 
|  | rfb_fb = main_fb; | 
|  | } | 
|  | } | 
|  | if (rot_fb) { | 
|  | screen->frameBuffer = rot_fb; | 
|  | } else { | 
|  | screen->frameBuffer = rfb_fb; | 
|  | } | 
|  | if (verbose) { | 
|  | fprintf(stderr, " rfb_fb:      %p\n", rfb_fb); | 
|  | fprintf(stderr, " main_fb:     %p\n", main_fb); | 
|  | fprintf(stderr, " 8to24_fb:    %p\n", cmap8to24_fb); | 
|  | fprintf(stderr, " rot_fb:      %p\n", rot_fb); | 
|  | fprintf(stderr, " snap_fb:     %p\n", snap_fb); | 
|  | fprintf(stderr, " raw_fb:      %p\n", raw_fb); | 
|  | fprintf(stderr, " fake_fb:     %p\n", fake_fb); | 
|  | fprintf(stderr, "\n"); | 
|  | } | 
|  |  | 
|  | /* may need, bpp, main_red_max, etc. */ | 
|  | parse_wireframe(); | 
|  | parse_scroll_copyrect(); | 
|  | setup_cursors_and_push(); | 
|  |  | 
|  | if (scaling || rotating || cmap8to24) { | 
|  | mark_rect_as_modified(0, 0, dpy_x, dpy_y, 0); | 
|  | } | 
|  |  | 
|  | if (! create_screen) { | 
|  | rfbClientIteratorPtr iter; | 
|  | rfbClientPtr cl; | 
|  |  | 
|  | /* | 
|  | * since bits_per_color above may have been approximate, | 
|  | * try to reset the individual translation tables... | 
|  | * we do not seem to need this with rfbGetScreen()... | 
|  | */ | 
|  | if (!quiet) rfbLog("calling setTranslateFunction()...\n"); | 
|  | iter = rfbGetClientIterator(screen); | 
|  | while ((cl = rfbClientIteratorNext(iter)) != NULL) { | 
|  | screen->setTranslateFunction(cl); | 
|  | } | 
|  | rfbReleaseClientIterator(iter); | 
|  | if (!quiet) rfbLog("  done.\n"); | 
|  |  | 
|  | /* done for framebuffer change case */ | 
|  | if (locked_sends) { | 
|  | lock_client_sends(0); | 
|  | } | 
|  |  | 
|  | do_copy_screen = 1; | 
|  | return; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * the rest is screen server initialization, etc, only needed | 
|  | * at screen creation time. | 
|  | */ | 
|  |  | 
|  | /* event callbacks: */ | 
|  | screen->newClientHook = new_client; | 
|  | screen->kbdAddEvent = keyboard; | 
|  | screen->ptrAddEvent = pointer_event; | 
|  | screen->setXCutText = xcut_receive; | 
|  | screen->setTranslateFunction = set_xlate_wrapper; | 
|  |  | 
|  | screen->kbdReleaseAllKeys = kbd_release_all_keys; | 
|  | screen->setSingleWindow = set_single_window; | 
|  | screen->setServerInput = set_server_input; | 
|  | screen->setTextChat = set_text_chat; | 
|  | screen->getFileTransferPermission = get_file_transfer_permitted; | 
|  |  | 
|  | /* called from inetd, we need to treat stdio as our socket */ | 
|  | if (inetd && use_openssl) { | 
|  | /* accept_openssl() called later */ | 
|  | screen->port = 0; | 
|  | } else if (inetd) { | 
|  | int fd = dup(0); | 
|  | if (fd < 0) { | 
|  | rfbLogEnable(1); | 
|  | rfbErr("dup(0) = %d failed.\n", fd); | 
|  | rfbLogPerror("dup"); | 
|  | clean_up_exit(1); | 
|  | } | 
|  | fclose(stdin); | 
|  | fclose(stdout); | 
|  | /* we keep stderr for logging */ | 
|  | screen->inetdSock = fd; | 
|  | screen->port = 0; | 
|  |  | 
|  | } else if (! got_rfbport && auto_port > 0) { | 
|  | int lport = find_free_port(auto_port, auto_port+200); | 
|  | screen->autoPort = FALSE; | 
|  | screen->port = lport; | 
|  | } else if (! got_rfbport) { | 
|  | screen->autoPort = TRUE; | 
|  | } else if (got_rfbport && got_rfbport_val == 0) { | 
|  | screen->autoPort = FALSE; | 
|  | screen->port = 0; | 
|  | } | 
|  |  | 
|  | if (! got_nevershared && ! got_alwaysshared) { | 
|  | if (shared) { | 
|  | screen->alwaysShared = TRUE; | 
|  | } else { | 
|  | screen->neverShared = TRUE; | 
|  | } | 
|  | screen->dontDisconnect = TRUE; | 
|  | } | 
|  | if (! got_deferupdate) { | 
|  | screen->deferUpdateTime = defer_update; | 
|  | } else { | 
|  | defer_update = screen->deferUpdateTime; | 
|  | } | 
|  |  | 
|  | if (noipv4 || getenv("IPV4_FAILS")) { | 
|  | rfbBool ap = screen->autoPort; | 
|  | int port = screen->port; | 
|  |  | 
|  | if (getenv("IPV4_FAILS")) { | 
|  | rfbLog("TESTING: IPV4_FAILS for rfbInitServer()\n"); | 
|  | } | 
|  |  | 
|  | screen->autoPort = FALSE; | 
|  | screen->port = 0; | 
|  |  | 
|  | rfbInitServer(screen); | 
|  |  | 
|  | screen->autoPort = ap; | 
|  | screen->port = port; | 
|  |  | 
|  | } else { | 
|  | rfbInitServer(screen); | 
|  | } | 
|  |  | 
|  | if (use_openssl) { | 
|  | openssl_port(0); | 
|  | if (https_port_num >= 0) { | 
|  | https_port(0); | 
|  | } | 
|  | } else { | 
|  | if (ipv6_listen) { | 
|  | int fd = -1; | 
|  | if (screen->port <= 0) { | 
|  | if (got_rfbport) { | 
|  | screen->port = got_rfbport_val; | 
|  | } else { | 
|  | int ap = 5900; | 
|  | if (auto_port > 0) { | 
|  | ap = auto_port; | 
|  | } | 
|  | screen->port = find_free_port6(ap, ap+200); | 
|  | } | 
|  | } | 
|  | fd = listen6(screen->port); | 
|  | if (fd < 0) { | 
|  | ipv6_listen = 0; | 
|  | rfbLog("Not listening on IPv6 interface.\n"); | 
|  | } else { | 
|  | rfbLog("Listening %s on IPv6 port %d (socket %d)\n", | 
|  | screen->listenSock < 0 ? "only" : "also", | 
|  | screen->port, fd); | 
|  | ipv6_listen_fd = fd; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | install_passwds(); | 
|  |  | 
|  | if (locked_sends) { | 
|  | lock_client_sends(0); | 
|  | } | 
|  | return; | 
|  | } | 
|  |  | 
|  | #define DO_AVAHI \ | 
|  | if (avahi) { \ | 
|  | avahi_initialise(); \ | 
|  | avahi_advertise(vnc_desktop_name, host, lport); \ | 
|  | usleep(1000*1000); \ | 
|  | } | 
|  |  | 
|  | void announce(int lport, int ssl, char *iface) { | 
|  |  | 
|  | char *host = this_host(); | 
|  | char *tvdt; | 
|  |  | 
|  | if (remote_direct) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (! ssl) { | 
|  | tvdt = "The VNC desktop is:     "; | 
|  | } else { | 
|  | if (enc_str && !strcmp(enc_str, "none")) { | 
|  | tvdt = "The VNC desktop is:     "; | 
|  | } else if (enc_str) { | 
|  | tvdt = "The ENC VNC desktop is: "; | 
|  | } else { | 
|  | tvdt = "The SSL VNC desktop is: "; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (iface != NULL && *iface != '\0' && strcmp(iface, "any")) { | 
|  | host = iface; | 
|  | } | 
|  | if (host != NULL) { | 
|  | /* note that vncviewer special cases 5900-5999 */ | 
|  | int sz = 256; | 
|  | if (inetd) { | 
|  | ;	/* should not occur (port) */ | 
|  | } else if (quiet) { | 
|  | if (lport >= 5900) { | 
|  | snprintf(vnc_desktop_name, sz, "%s:%d", | 
|  | host, lport - 5900); | 
|  | DO_AVAHI | 
|  | fprintf(stderr, "\n%s %s\n", tvdt, | 
|  | vnc_desktop_name); | 
|  | } else { | 
|  | snprintf(vnc_desktop_name, sz, "%s:%d", | 
|  | host, lport); | 
|  | DO_AVAHI | 
|  | fprintf(stderr, "\n%s %s\n", tvdt, | 
|  | vnc_desktop_name); | 
|  | } | 
|  | } else if (lport >= 5900) { | 
|  | snprintf(vnc_desktop_name, sz, "%s:%d", | 
|  | host, lport - 5900); | 
|  | DO_AVAHI | 
|  | fprintf(stderr, "\n%s %s\n", tvdt, vnc_desktop_name); | 
|  | if (lport >= 6000) { | 
|  | rfbLog("possible aliases:  %s:%d, " | 
|  | "%s::%d\n", host, lport, | 
|  | host, lport); | 
|  | } | 
|  | } else { | 
|  | snprintf(vnc_desktop_name, sz, "%s:%d", | 
|  | host, lport); | 
|  | DO_AVAHI | 
|  | fprintf(stderr, "\n%s %s\n", tvdt, vnc_desktop_name); | 
|  | rfbLog("possible alias:    %s::%d\n", | 
|  | host, lport); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static void announce_http(int lport, int ssl, char *iface, char *extra) { | 
|  |  | 
|  | char *host = this_host(); | 
|  | char *jvu; | 
|  | int http = 0; | 
|  |  | 
|  | if (enc_str && !strcmp(enc_str, "none") && !use_stunnel) { | 
|  | jvu = "Java viewer URL:         http"; | 
|  | http = 1; | 
|  | } else if (ssl == 1) { | 
|  | jvu = "Java SSL viewer URL:     https"; | 
|  | } else if (ssl == 2) { | 
|  | jvu = "Java SSL viewer URL:     http"; | 
|  | http = 1; | 
|  | } else { | 
|  | jvu = "Java viewer URL:         http"; | 
|  | http = 1; | 
|  | } | 
|  |  | 
|  | if (iface != NULL && *iface != '\0' && strcmp(iface, "any")) { | 
|  | host = iface; | 
|  | } | 
|  | if (http && getenv("X11VNC_HTTP_LISTEN_LOCALHOST")) { | 
|  | host = "localhost"; | 
|  | } | 
|  | if (host != NULL) { | 
|  | if (! inetd) { | 
|  | fprintf(stderr, "%s://%s:%d/%s\n", jvu, host, lport, extra); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void do_announce_http(void) { | 
|  | if (!screen) { | 
|  | return; | 
|  | } | 
|  | if (remote_direct) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | /* XXX ipv6? */ | 
|  | if ((screen->httpListenSock > -1 || ipv6_http_fd > -1) && screen->httpPort) { | 
|  | int enc_none = (enc_str && !strcmp(enc_str, "none")); | 
|  | char *SPORT = "   (single port)"; | 
|  | if (use_openssl && ! enc_none) { | 
|  | announce_http(screen->port, 1, listen_str, SPORT); | 
|  | if (https_port_num >= 0) { | 
|  | announce_http(https_port_num, 1, | 
|  | listen_str, ""); | 
|  | } | 
|  | announce_http(screen->httpPort, 2, listen_str, ""); | 
|  | } else if (use_stunnel) { | 
|  | char pmsg[100]; | 
|  | pmsg[0] = '\0'; | 
|  | if (stunnel_port) { | 
|  | sprintf(pmsg, "?PORT=%d", stunnel_port); | 
|  | } | 
|  | announce_http(screen->httpPort, 2, listen_str, pmsg); | 
|  | if (stunnel_http_port > 0) { | 
|  | announce_http(stunnel_http_port, 1, NULL, pmsg); | 
|  | } | 
|  | if (enc_none) { | 
|  | strcat(pmsg, SPORT); | 
|  | announce_http(stunnel_port, 1, NULL, pmsg); | 
|  | } | 
|  | } else { | 
|  | announce_http(screen->httpPort, 0, listen_str, ""); | 
|  | if (enc_none) { | 
|  | announce_http(screen->port, 1, NULL, SPORT); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void do_mention_java_urls(void) { | 
|  | if (! quiet && screen) { | 
|  | /* XXX ipv6? */ | 
|  | if (screen->httpListenSock > -1 && screen->httpPort) { | 
|  | rfbLog("\n"); | 
|  | rfbLog("The URLs printed out below ('Java ... viewer URL') can\n"); | 
|  | rfbLog("be used for Java enabled Web browser connections.\n"); | 
|  | if (!stunnel_port && enc_str && !strcmp(enc_str, "none")) { | 
|  | ; | 
|  | } else if (use_openssl || stunnel_port) { | 
|  | rfbLog("Here are some additional possibilities:\n"); | 
|  | rfbLog("\n"); | 
|  | rfbLog("https://host:port/proxy.vnc (MUST be used if Web Proxy used)\n"); | 
|  | rfbLog("\n"); | 
|  | rfbLog("https://host:port/ultra.vnc (Use UltraVNC Java Viewer)\n"); | 
|  | rfbLog("https://host:port/ultraproxy.vnc (Web Proxy with UltraVNC)\n"); | 
|  | rfbLog("https://host:port/ultrasigned.vnc (Signed UltraVNC Filexfer)\n"); | 
|  | rfbLog("\n"); | 
|  | rfbLog("Where you replace \"host:port\" with that printed below, or\n"); | 
|  | rfbLog("whatever is needed to reach the host e.g. Internet IP number\n"); | 
|  | rfbLog("\n"); | 
|  | rfbLog("Append ?GET=1 to a URL for faster loading or supply:\n"); | 
|  | rfbLog("-env X11VNC_EXTRA_HTTPS_PARAMS='?GET=1' to cmdline.\n"); | 
|  | } | 
|  | } | 
|  | rfbLog("\n"); | 
|  | } | 
|  | } | 
|  |  | 
|  | void set_vnc_desktop_name(void) { | 
|  | sprintf(vnc_desktop_name, "unknown"); | 
|  | if (inetd) { | 
|  | sprintf(vnc_desktop_name, "%s/inetd-no-further-clients", | 
|  | this_host()); | 
|  | } | 
|  | if (remote_direct) { | 
|  | return; | 
|  | } | 
|  | if (screen->port) { | 
|  |  | 
|  | do_mention_java_urls(); | 
|  |  | 
|  | if (use_openssl) { | 
|  | announce(screen->port, 1, listen_str); | 
|  | } else { | 
|  | announce(screen->port, 0, listen_str); | 
|  | } | 
|  | if (stunnel_port) { | 
|  | announce(stunnel_port, 1, NULL); | 
|  | } | 
|  |  | 
|  | do_announce_http(); | 
|  |  | 
|  | fflush(stderr); | 
|  | if (inetd) { | 
|  | ;	/* should not occur (port != 0) */ | 
|  | } else { | 
|  | fprintf(stdout, "PORT=%d\n", screen->port); | 
|  | if (stunnel_port) { | 
|  | fprintf(stdout, "SSLPORT=%d\n", stunnel_port); | 
|  | } else if (use_openssl) { | 
|  | if (enc_str && !strcmp(enc_str, "none")) { | 
|  | ; | 
|  | } else if (enc_str) { | 
|  | fprintf(stdout, "ENCPORT=%d\n", screen->port); | 
|  | } else { | 
|  | fprintf(stdout, "SSLPORT=%d\n", screen->port); | 
|  | } | 
|  | } | 
|  | fflush(stdout); | 
|  | if (flagfile) { | 
|  | FILE *flag = fopen(flagfile, "w"); | 
|  | if (flag) { | 
|  | fprintf(flag, "PORT=%d\n",screen->port); | 
|  | if (stunnel_port) { | 
|  | fprintf(flag, "SSL_PORT=%d\n", | 
|  | stunnel_port); | 
|  | } | 
|  | fflush(flag); | 
|  | fclose(flag); | 
|  | } else { | 
|  | rfbLog("could not open flag file: %s\n", | 
|  | flagfile); | 
|  | } | 
|  | } | 
|  | if (rm_flagfile) { | 
|  | int create = 0; | 
|  | struct stat sb; | 
|  | if (strstr(rm_flagfile, "create:") == rm_flagfile) { | 
|  | char *s = rm_flagfile; | 
|  | create = 1; | 
|  | rm_flagfile = strdup(rm_flagfile + strlen("create:")); | 
|  | free(s); | 
|  | } | 
|  | if (strstr(rm_flagfile, "nocreate:") == rm_flagfile) { | 
|  | char *s = rm_flagfile; | 
|  | create = 0; | 
|  | rm_flagfile = strdup(rm_flagfile + strlen("nocreate:")); | 
|  | free(s); | 
|  | } else if (stat(rm_flagfile, &sb) != 0) { | 
|  | create = 1; | 
|  | } | 
|  | if (create) { | 
|  | FILE *flag = fopen(rm_flagfile, "w"); | 
|  | if (flag) { | 
|  | fprintf(flag, "%d\n", getpid()); | 
|  | fclose(flag); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | fflush(stdout); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void check_cursor_changes(void) { | 
|  | static double last_push = 0.0; | 
|  |  | 
|  | if (unixpw_in_progress) return; | 
|  |  | 
|  | cursor_changes += check_x11_pointer(); | 
|  |  | 
|  | if (cursor_changes) { | 
|  | double tm, max_push = 0.125, multi_push = 0.01, wait = 0.02; | 
|  | int cursor_shape, dopush = 0, link, latency, netrate; | 
|  |  | 
|  | if (! all_clients_initialized()) { | 
|  | /* play it safe */ | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (0) cursor_shape = cursor_shape_updates_clients(screen); | 
|  |  | 
|  | dtime0(&tm); | 
|  | link = link_rate(&latency, &netrate); | 
|  | if (link == LR_DIALUP) { | 
|  | max_push = 0.2; | 
|  | wait = 0.05; | 
|  | } else if (link == LR_BROADBAND) { | 
|  | max_push = 0.075; | 
|  | wait = 0.05; | 
|  | } else if (link == LR_LAN) { | 
|  | max_push = 0.01; | 
|  | } else if (latency < 5 && netrate > 200) { | 
|  | max_push = 0.01; | 
|  | } | 
|  |  | 
|  | if (tm > last_push + max_push) { | 
|  | dopush = 1; | 
|  | } else if (cursor_changes > 1 && tm > last_push + multi_push) { | 
|  | dopush = 1; | 
|  | } | 
|  |  | 
|  | if (dopush) { | 
|  | mark_rect_as_modified(0, 0, 1, 1, 1); | 
|  | fb_push_wait(wait, FB_MOD); | 
|  | last_push = tm; | 
|  | } else { | 
|  | rfbPE(0); | 
|  | } | 
|  | } | 
|  | cursor_changes = 0; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * These watch_loop() releated were moved from x11vnc.c so we could try | 
|  | * to remove -O2 from its compilation.  TDB new file, e.g. watch.c. | 
|  | */ | 
|  |  | 
|  | static void check_filexfer(void) { | 
|  | static time_t last_check = 0; | 
|  | rfbClientIteratorPtr iter; | 
|  | rfbClientPtr cl; | 
|  | int transferring = 0; | 
|  |  | 
|  | if (time(NULL) <= last_check) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | #if 0 | 
|  | if (getenv("NOFT")) { | 
|  | return; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | iter = rfbGetClientIterator(screen); | 
|  | while( (cl = rfbClientIteratorNext(iter)) ) { | 
|  | if (cl->fileTransfer.receiving) { | 
|  | transferring = 1; | 
|  | break; | 
|  | } | 
|  | if (cl->fileTransfer.sending) { | 
|  | transferring = 1; | 
|  | break; | 
|  | } | 
|  | } | 
|  | rfbReleaseClientIterator(iter); | 
|  |  | 
|  | if (transferring) { | 
|  | double start = dnow(); | 
|  | while (dnow() < start + 0.5) { | 
|  | rfbCFD(5000); | 
|  | rfbCFD(1000); | 
|  | rfbCFD(0); | 
|  | } | 
|  | } else { | 
|  | last_check = time(NULL); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void record_last_fb_update(void) { | 
|  | static int rbs0 = -1; | 
|  | static time_t last_call = 0; | 
|  | time_t now = time(NULL); | 
|  | int rbs = -1; | 
|  | rfbClientIteratorPtr iter; | 
|  | rfbClientPtr cl; | 
|  |  | 
|  | if (last_fb_bytes_sent == 0) { | 
|  | last_fb_bytes_sent = now; | 
|  | last_call = now; | 
|  | } | 
|  |  | 
|  | if (now <= last_call + 1) { | 
|  | /* check every second or so */ | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (unixpw_in_progress) return; | 
|  |  | 
|  | last_call = now; | 
|  |  | 
|  | if (! screen) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | iter = rfbGetClientIterator(screen); | 
|  | while( (cl = rfbClientIteratorNext(iter)) ) { | 
|  | #if 0 | 
|  | rbs += cl->rawBytesEquivalent; | 
|  | #else | 
|  | #if LIBVNCSERVER_HAS_STATS | 
|  | rbs += rfbStatGetSentBytesIfRaw(cl); | 
|  | #endif | 
|  | #endif | 
|  | } | 
|  | rfbReleaseClientIterator(iter); | 
|  |  | 
|  | if (rbs != rbs0) { | 
|  | rbs0 = rbs; | 
|  | if (debug_tiles > 1) { | 
|  | fprintf(stderr, "record_last_fb_update: %d %d\n", | 
|  | (int) now, (int) last_fb_bytes_sent); | 
|  | } | 
|  | last_fb_bytes_sent = now; | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | static int choose_delay(double dt) { | 
|  | static double t0 = 0.0, t1 = 0.0, t2 = 0.0, now; | 
|  | static int x0, y0, x1, y1, x2, y2, first = 1; | 
|  | int dx0, dy0, dx1, dy1, dm, i, msec = waitms; | 
|  | double cut1 = 0.15, cut2 = 0.075, cut3 = 0.25; | 
|  | double bogdown_time = 0.25, bave = 0.0; | 
|  | int bogdown = 1, bcnt = 0; | 
|  | int ndt = 8, nave = 3; | 
|  | double fac = 1.0; | 
|  | static int db = 0, did_set_defer = 0; | 
|  | static double dts[8]; | 
|  | static int link = LR_UNSET, latency = -1, netrate = -1; | 
|  | static double last_link = 0.0; | 
|  |  | 
|  | if (screen && did_set_defer) { | 
|  | /* reset defer in case we changed it */ | 
|  | screen->deferUpdateTime = defer_update; | 
|  | } | 
|  | if (waitms == 0) { | 
|  | return waitms; | 
|  | } | 
|  | if (nofb) { | 
|  | return waitms; | 
|  | } | 
|  |  | 
|  | if (first) { | 
|  | for(i=0; i<ndt; i++) { | 
|  | dts[i] = 0.0; | 
|  | } | 
|  | if (getenv("DEBUG_DELAY")) { | 
|  | db = atoi(getenv("DEBUG_DELAY")); | 
|  | } | 
|  | if (getenv("SET_DEFER")) { | 
|  | set_defer = atoi(getenv("SET_DEFER")); | 
|  | } | 
|  | first = 0; | 
|  | } | 
|  |  | 
|  | now = dnow(); | 
|  |  | 
|  | if (now > last_link + 30.0 || link == LR_UNSET) { | 
|  | link = link_rate(&latency, &netrate); | 
|  | last_link = now; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * first check for bogdown, e.g. lots of activity, scrolling text | 
|  | * from command output, etc. | 
|  | */ | 
|  | if (nap_ok) { | 
|  | dt = 0.0; | 
|  | } | 
|  | if (! wait_bog) { | 
|  | bogdown = 0; | 
|  |  | 
|  | } else if (button_mask || now < last_keyboard_time + 2*bogdown_time) { | 
|  | /* | 
|  | * let scrolls & keyboard input through the normal way | 
|  | * otherwise, it will likely just annoy them. | 
|  | */ | 
|  | bogdown = 0; | 
|  |  | 
|  | } else if (dt > 0.0) { | 
|  | /* | 
|  | * inspect recent dt's: | 
|  | * 0 1 2 3 4 5 6 7 dt | 
|  | *             ^ ^ ^ | 
|  | */ | 
|  | for (i = ndt - (nave - 1); i < ndt; i++) { | 
|  | bave += dts[i]; | 
|  | bcnt++; | 
|  | if (dts[i] < bogdown_time) { | 
|  | bogdown = 0; | 
|  | break; | 
|  | } | 
|  | } | 
|  | bave += dt; | 
|  | bcnt++; | 
|  | bave = bave / bcnt; | 
|  | if (dt < bogdown_time) { | 
|  | bogdown = 0; | 
|  | } | 
|  | } else { | 
|  | bogdown = 0; | 
|  | } | 
|  | /* shift for next time */ | 
|  | for (i = 0; i < ndt-1; i++) { | 
|  | dts[i] = dts[i+1]; | 
|  | } | 
|  | dts[ndt-1] = dt; | 
|  |  | 
|  | if (0 && dt > 0.0) fprintf(stderr, "dt: %.5f %.4f\n", dt, dnowx()); | 
|  | if (bogdown) { | 
|  | if (use_xdamage) { | 
|  | /* DAMAGE can queue ~1000 rectangles for a scroll */ | 
|  | clear_xdamage_mark_region(NULL, 0); | 
|  | } | 
|  | msec = (int) (1000 * 1.75 * bave); | 
|  | if (dts[ndt - nave - 1] > 0.75 * bave) { | 
|  | msec = 1.5 * msec; | 
|  | set_xdamage_mark(0, 0, dpy_x, dpy_y); | 
|  | } | 
|  | if (msec > 1500) { | 
|  | msec = 1500; | 
|  | } | 
|  | if (msec < waitms) { | 
|  | msec = waitms; | 
|  | } | 
|  | db = (db || debug_tiles); | 
|  | if (db) fprintf(stderr, "bogg[%d] %.3f %.3f %.3f %.3f\n", | 
|  | msec, dts[ndt-4], dts[ndt-3], dts[ndt-2], dts[ndt-1]); | 
|  |  | 
|  | return msec; | 
|  | } | 
|  |  | 
|  | /* next check for pointer motion, keystrokes, to speed up */ | 
|  | t2 = dnow(); | 
|  | x2 = cursor_x; | 
|  | y2 = cursor_y; | 
|  |  | 
|  | dx0 = nabs(x1 - x0); | 
|  | dy0 = nabs(y1 - y0); | 
|  | dx1 = nabs(x2 - x1); | 
|  | dy1 = nabs(y2 - y1); | 
|  |  | 
|  | /* bigger displacement for most recent dt: */ | 
|  | if (dx1 > dy1) { | 
|  | dm = dx1; | 
|  | } else { | 
|  | dm = dy1; | 
|  | } | 
|  |  | 
|  | if ((dx0 || dy0) && (dx1 || dy1)) { | 
|  | /* if mouse moved the previous two times: */ | 
|  | if (t2 < t0 + cut1 || t2 < t1 + cut2 || dm > 20) { | 
|  | /* | 
|  | * if within 0.15s(0) or 0.075s(1) or mouse | 
|  | * moved > 20pixels, set and bump up the cut | 
|  | * down factor. | 
|  | */ | 
|  | fac = wait_ui * 1.5; | 
|  | } else if ((dx1 || dy1) && dm > 40) { | 
|  | fac = wait_ui; | 
|  | } else { | 
|  | /* still 1.0? */ | 
|  | if (db > 1) fprintf(stderr, "wait_ui: still 1.0\n"); | 
|  | } | 
|  | } else if ((dx1 || dy1) && dm > 40) { | 
|  | /* if mouse moved > 40 last time: */ | 
|  | fac = wait_ui; | 
|  | } | 
|  |  | 
|  | if (fac == 1.0 && t2 < last_keyboard_time + cut3) { | 
|  | /* if typed in last 0.25s set wait_ui */ | 
|  | fac = wait_ui; | 
|  | } | 
|  | if (fac != 1.0) { | 
|  | if (link == LR_LAN || latency <= 3) { | 
|  | fac *= 1.5; | 
|  | } | 
|  | } | 
|  |  | 
|  | msec = (int) (((double) waitms) / fac); | 
|  | if (msec == 0) { | 
|  | msec = 1; | 
|  | } | 
|  |  | 
|  | if (set_defer && fac != 1.0 && screen) { | 
|  | /* this is wait_ui mode, set defer to match wait: */ | 
|  | if (set_defer >= 1) { | 
|  | screen->deferUpdateTime = msec; | 
|  | } else if (set_defer <= -1) { | 
|  | screen->deferUpdateTime = 0; | 
|  | } | 
|  | if (nabs(set_defer) == 2) { | 
|  | urgent_update = 1; | 
|  | } | 
|  | did_set_defer = 1; | 
|  | } | 
|  |  | 
|  | x0 = x1; | 
|  | y0 = y1; | 
|  | t0 = t1; | 
|  |  | 
|  | x1 = x2; | 
|  | y1 = y2; | 
|  | t1 = t2; | 
|  |  | 
|  | if (db > 1) fprintf(stderr, "wait: %2d defer[%02d]: %2d\n", msec, defer_update, screen->deferUpdateTime); | 
|  |  | 
|  | return msec; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * main x11vnc loop: polls, checks for events, iterate libvncserver, etc. | 
|  | */ | 
|  | void watch_loop(void) { | 
|  | int cnt = 0, tile_diffs = 0, skip_pe = 0, wait; | 
|  | double tm, dtr, dt = 0.0; | 
|  | time_t start = time(NULL); | 
|  |  | 
|  | if (use_threads && !started_rfbRunEventLoop) { | 
|  | started_rfbRunEventLoop = 1; | 
|  | rfbRunEventLoop(screen, -1, TRUE); | 
|  | } | 
|  |  | 
|  | while (1) { | 
|  | char msg[] = "new client: %s taking unixpw client off hold.\n"; | 
|  | int skip_scan_for_updates = 0; | 
|  |  | 
|  | got_user_input = 0; | 
|  | got_pointer_input = 0; | 
|  | got_local_pointer_input = 0; | 
|  | got_pointer_calls = 0; | 
|  | got_keyboard_input = 0; | 
|  | got_keyboard_calls = 0; | 
|  | urgent_update = 0; | 
|  |  | 
|  | x11vnc_current = dnow(); | 
|  |  | 
|  | if (! use_threads) { | 
|  | dtime0(&tm); | 
|  | if (! skip_pe) { | 
|  | if (unixpw_in_progress) { | 
|  | rfbClientPtr cl = unixpw_client; | 
|  | if (cl && cl->onHold) { | 
|  | rfbLog(msg, cl->host); | 
|  | unixpw_client->onHold = FALSE; | 
|  | } | 
|  | } else { | 
|  | measure_send_rates(1); | 
|  | } | 
|  |  | 
|  | unixpw_in_rfbPE = 1; | 
|  |  | 
|  | /* | 
|  | * do a few more since a key press may | 
|  | * have induced a small change we want to | 
|  | * see quickly (just 1 rfbPE will likely | 
|  | * only process the subsequent "up" event) | 
|  | */ | 
|  | if (tm < last_keyboard_time + 0.20) { | 
|  | rfbPE(0); | 
|  | rfbPE(0); | 
|  | rfbPE(-1); | 
|  | rfbPE(0); | 
|  | rfbPE(0); | 
|  | } else { | 
|  | if (extra_fbur > 0) { | 
|  | int i; | 
|  | for (i=0; i < extra_fbur; i++) { | 
|  | rfbPE(0); | 
|  | } | 
|  | } | 
|  | rfbPE(-1); | 
|  | } | 
|  | if (x11vnc_current < last_new_client + 0.5) { | 
|  | urgent_update = 1; | 
|  | } | 
|  |  | 
|  | unixpw_in_rfbPE = 0; | 
|  |  | 
|  | if (unixpw_in_progress) { | 
|  | /* rfbPE loop until logged in. */ | 
|  | skip_pe = 0; | 
|  | check_new_clients(); | 
|  | continue; | 
|  | } else { | 
|  | measure_send_rates(0); | 
|  | fb_update_sent(NULL); | 
|  | } | 
|  | } else { | 
|  | if (unixpw_in_progress) { | 
|  | skip_pe = 0; | 
|  | check_new_clients(); | 
|  | continue; | 
|  | } | 
|  | } | 
|  | dtr = dtime(&tm); | 
|  |  | 
|  | if (! cursor_shape_updates) { | 
|  | /* undo any cursor shape requests */ | 
|  | disable_cursor_shape_updates(screen); | 
|  | } | 
|  | if (screen && screen->clientHead) { | 
|  | int ret = check_user_input(dt, dtr, tile_diffs, &cnt); | 
|  | /* true: loop back for more input */ | 
|  | if (ret == 2) { | 
|  | skip_pe = 1; | 
|  | } | 
|  | if (ret) { | 
|  | if (debug_scroll) fprintf(stderr, "watch_loop: LOOP-BACK: %d\n", ret); | 
|  | continue; | 
|  | } | 
|  | } | 
|  | /* watch for viewonly input piling up: */ | 
|  | if ((got_pointer_calls > got_pointer_input) || | 
|  | (got_keyboard_calls > got_keyboard_input)) { | 
|  | eat_viewonly_input(10, 3); | 
|  | } | 
|  | } else { | 
|  | /* -threads here. */ | 
|  | if (unixpw_in_progress) { | 
|  | rfbClientPtr cl = unixpw_client; | 
|  | if (cl && cl->onHold) { | 
|  | rfbLog(msg, cl->host); | 
|  | unixpw_client->onHold = FALSE; | 
|  | } | 
|  | } | 
|  | if (use_xrecord) { | 
|  | check_xrecord(); | 
|  | } | 
|  | if (wireframe && button_mask) { | 
|  | check_wireframe(); | 
|  | } | 
|  | } | 
|  | skip_pe = 0; | 
|  |  | 
|  | if (shut_down) { | 
|  | clean_up_exit(0); | 
|  | } | 
|  |  | 
|  | if (unixpw_in_progress) { | 
|  | check_new_clients(); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if (! urgent_update) { | 
|  | if (do_copy_screen) { | 
|  | do_copy_screen = 0; | 
|  | copy_screen(); | 
|  | } | 
|  |  | 
|  | check_new_clients(); | 
|  | check_ncache(0, 0); | 
|  | check_xevents(0); | 
|  | check_autorepeat(); | 
|  | check_pm(); | 
|  | check_filexfer(); | 
|  | check_keycode_state(); | 
|  | check_connect_inputs(); | 
|  | check_gui_inputs(); | 
|  | check_stunnel(); | 
|  | check_openssl(); | 
|  | check_https(); | 
|  | record_last_fb_update(); | 
|  | check_padded_fb(); | 
|  | check_fixscreen(); | 
|  | check_xdamage_state(); | 
|  | check_xrecord_reset(0); | 
|  | check_add_keysyms(); | 
|  | check_new_passwds(0); | 
|  | #ifdef ENABLE_GRABLOCAL | 
|  | if (grab_local) { | 
|  | check_local_grab(); | 
|  | } | 
|  | #endif | 
|  | if (started_as_root) { | 
|  | check_switched_user(); | 
|  | } | 
|  |  | 
|  | if (first_conn_timeout < 0) { | 
|  | start = time(NULL); | 
|  | first_conn_timeout = -first_conn_timeout; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (rawfb_vnc_reflect) { | 
|  | static time_t lastone = 0; | 
|  | if (time(NULL) > lastone + 10) { | 
|  | lastone = time(NULL); | 
|  | vnc_reflect_process_client(); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (first_conn_timeout) { | 
|  | int t = first_conn_timeout; | 
|  | if (!clients_served) { | 
|  | if (time(NULL) - start > first_conn_timeout) { | 
|  | rfbLog("No client after %d secs.\n", t); | 
|  | shut_down = 1; | 
|  | } | 
|  | } else { | 
|  | if (!client_normal_count) { | 
|  | if (time(NULL) - start > t + 3) { | 
|  | rfbLog("No valid client after %d secs.\n", t + 3); | 
|  | shut_down = 1; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if (! screen || ! screen->clientHead) { | 
|  | /* waiting for a client */ | 
|  | usleep(200 * 1000); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if (first_conn_timeout && all_clients_initialized()) { | 
|  | first_conn_timeout = 0; | 
|  | } | 
|  |  | 
|  | if (nofb) { | 
|  | /* no framebuffer polling needed */ | 
|  | if (cursor_pos_updates) { | 
|  | check_x11_pointer(); | 
|  | } | 
|  | #ifdef MACOSX | 
|  | else check_x11_pointer(); | 
|  | #endif | 
|  | continue; | 
|  | } | 
|  | if (x11vnc_current < last_new_client + 0.5 && !all_clients_initialized()) { | 
|  | continue; | 
|  | } | 
|  | if (subwin && freeze_when_obscured) { | 
|  | /* XXX not working */ | 
|  | X_LOCK; | 
|  | XFlush_wr(dpy); | 
|  | X_UNLOCK; | 
|  | check_xevents(0); | 
|  | if (subwin_obscured) { | 
|  | skip_scan_for_updates = 1; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (skip_scan_for_updates) { | 
|  | ; | 
|  | } else if (button_mask && (!show_dragging || pointer_mode == 0)) { | 
|  | /* | 
|  | * if any button is pressed in this mode do | 
|  | * not update rfb screen, but do flush the | 
|  | * X11 display. | 
|  | */ | 
|  | X_LOCK; | 
|  | XFlush_wr(dpy); | 
|  | X_UNLOCK; | 
|  | dt = 0.0; | 
|  | } else { | 
|  | static double last_dt = 0.0; | 
|  | double xdamage_thrash = 0.4; | 
|  | static int tilecut = -1; | 
|  |  | 
|  | check_cursor_changes(); | 
|  |  | 
|  | /* for timing the scan to try to detect thrashing */ | 
|  |  | 
|  | if (use_xdamage && last_dt > xdamage_thrash)  { | 
|  | clear_xdamage_mark_region(NULL, 0); | 
|  | } | 
|  |  | 
|  | if (unixpw_in_progress) continue; | 
|  |  | 
|  | if (rawfb_vnc_reflect) { | 
|  | vnc_reflect_process_client(); | 
|  | } | 
|  |  | 
|  | dtime0(&tm); | 
|  |  | 
|  | #if !NO_X11 | 
|  | if (xrandr_present && !xrandr && xrandr_maybe) { | 
|  | int delay = 180; | 
|  | /*  there may be xrandr right after xsession start */ | 
|  | if (tm < x11vnc_start + delay || tm < last_client + delay) { | 
|  | int tw = 20; | 
|  | if (auth_file != NULL) { | 
|  | tw = 120; | 
|  | } | 
|  | X_LOCK; | 
|  | if (tm < x11vnc_start + tw || tm < last_client + tw) { | 
|  | XSync(dpy, False); | 
|  | } else { | 
|  | XFlush_wr(dpy); | 
|  | } | 
|  | X_UNLOCK; | 
|  | } | 
|  | X_LOCK; | 
|  | check_xrandr_event("before-scan"); | 
|  | X_UNLOCK; | 
|  | } | 
|  | #endif | 
|  | if (use_snapfb) { | 
|  | int t, tries = 3; | 
|  | copy_snap(); | 
|  | for (t=0; t < tries; t++) { | 
|  | tile_diffs = scan_for_updates(0); | 
|  | } | 
|  | } else { | 
|  | tile_diffs = scan_for_updates(0); | 
|  | } | 
|  | dt = dtime(&tm); | 
|  | if (! nap_ok) { | 
|  | last_dt = dt; | 
|  | } | 
|  |  | 
|  | if (tilecut < 0) { | 
|  | if (getenv("TILECUT")) { | 
|  | tilecut = atoi(getenv("TILECUT")); | 
|  | } | 
|  | if (tilecut < 0) tilecut = 4; | 
|  | } | 
|  |  | 
|  | if ((debug_tiles || debug_scroll > 1 || debug_wireframe > 1) | 
|  | && (tile_diffs > tilecut || debug_tiles > 1)) { | 
|  | double rate = (tile_x * tile_y * bpp/8 * tile_diffs) / dt; | 
|  | fprintf(stderr, "============================= TILES: %d  dt: %.4f" | 
|  | "  t: %.4f  %.2f MB/s nap_ok: %d\n", tile_diffs, dt, | 
|  | tm - x11vnc_start, rate/1000000.0, nap_ok); | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | /* sleep a bit to lessen load */ | 
|  | wait = choose_delay(dt); | 
|  |  | 
|  | if (urgent_update) { | 
|  | ; | 
|  | } else if (wait > 2*waitms) { | 
|  | /* bog case, break it up */ | 
|  | nap_sleep(wait, 10); | 
|  | } else { | 
|  | double t1, t2; | 
|  | int idt; | 
|  | if (extra_fbur > 0) { | 
|  | int i; | 
|  | for (i=0; i <= extra_fbur; i++) { | 
|  | int r = rfbPE(0); | 
|  | if (!r) break; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* sometimes the sleep is too short, so measure it: */ | 
|  | t1 = dnow(); | 
|  | usleep(wait * 1000); | 
|  | t2 = dnow(); | 
|  |  | 
|  | idt = (int) (1000. * (t2 - t1)); | 
|  | if (idt > 0 && idt < wait) { | 
|  | /* try to sleep the remainder */ | 
|  | usleep((wait - idt) * 1000); | 
|  | } | 
|  | } | 
|  |  | 
|  | cnt++; | 
|  | } | 
|  | } | 
|  |  | 
|  |  |