diff options
Diffstat (limited to 'x11vnc/screen.c')
-rw-r--r-- | x11vnc/screen.c | 1929 |
1 files changed, 1929 insertions, 0 deletions
diff --git a/x11vnc/screen.c b/x11vnc/screen.c new file mode 100644 index 0000000..ac4bf7b --- /dev/null +++ b/x11vnc/screen.c @@ -0,0 +1,1929 @@ +/* -- 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" + +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 check_padded_fb(void); +void install_padded_fb(char *geom); +XImage *initialize_xdisplay_fb(void); +void parse_scale_string(char *str, double *factor, int *scaling, int *blend, + int *nomult4, int *pad, int *interpolate, int *numer, int *denom); +int scale_round(int len, double fac); +void initialize_screen(int *argc, char **argv, XImage *fb); +void set_vnc_desktop_name(void); + + +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); +static XImage *initialize_raw_fb(void); +static void initialize_clipshift(void); +static int wait_until_mapped(Window win); +static void setup_scaling(int *width_in, int *height_in); + + +/* + * 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 +void set_colormap(int reset) { + static int first = 1; + static XColor color[NCOLOR], prev[NCOLOR]; + Colormap cmap; + Visual *vis; + int i, ncells, diffs = 0; + + if (reset) { + first = 1; + if (screen->colourMap.data.shorts) { + free(screen->colourMap.data.shorts); + screen->colourMap.data.shorts = NULL; + } + } + + if (first) { + 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++) { + prev[i].red = color[i].red; + prev[i].green = color[i].green; + prev[i].blue = color[i].blue; + } + + 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 (first && ! quiet) { + rfbLog("set_colormap: number of cells is %d " + "instead of %d.\n", ncells, NCOLOR); + } + if (! shift_cmap) { + screen->colourMap.count = ncells; + } + } + + if (flash_cmap && ! first) { + 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 && ! first) { + 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); + } + } + + first = 0; +} + +static void debug_colormap(XImage *fb) { + static int debug_cmap = -1; + int i, k, histo[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 > 8) { + return; + } + + 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"); + } + } + 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) { + int vis, vdepth, defdepth = DefaultDepth(dpy, scr); + XVisualInfo vinfo; + char *p, *vstring = strdup(str); + + 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; +} + +void set_nofb_params(int restore) { + static int first = 1; + static int save[100]; + 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; + } + 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++]; + + 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; + } + + if (! quiet) { + rfbLog("disabling: xfixes, xdamage, solid, overlay, shm,\n"); + rfbLog(" wireframe, scrollcopyrect,\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, wb0, na0, tn0; + static int xr0, sb0; + 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; + wb0 = watch_bell; + na0 = no_autorepeat; + sb0 = use_solid_bg; + + us0 = use_snapfb; + sm0 = using_shm; + tn0 = take_naps; + xr0 = xrandr; + mc0 = multiple_cursors_mode; + + first = 0; + } + + if (restore) { + view_only = vo0; + watch_selection = ws0; + watch_primary = wp0; + watch_bell = wb0; + no_autorepeat = na0; + use_solid_bg = sb0; + + use_snapfb = us0; + using_shm = sm0; + take_naps = tn0; + xrandr = xr0; + multiple_cursors_mode = mc0; + + if (! dpy && raw_fb_orig_dpy) { + dpy = XOpenDisplay(raw_fb_orig_dpy); + if (dpy) { + if (! quiet) rfbLog("reopened DISPLAY: %s\n", + raw_fb_orig_dpy); + } else { + if (! quiet) rfbLog("WARNING: failed to reopen " + "DISPLAY: %s\n", raw_fb_orig_dpy); + } + } + return; + } + + if (! quiet) { + 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 (! quiet) { + rfbLog("rawfb: -noviewonly mode: still sending mouse and\n"); + rfbLog("rawfb: keyboard input to the X DISPLAY!!\n"); + } + } else { + /* Normal case: */ + if (! view_only) { + if (! quiet) rfbLog("rawfb: setting view_only\n"); + view_only = 1; + } + if (watch_selection) { + if (! quiet) rfbLog("rawfb: turning off " + "watch_selection\n"); + watch_selection = 0; + } + if (watch_primary) { + if (! quiet) rfbLog("rawfb: turning off " + "watch_primary\n"); + watch_primary = 0; + } + if (watch_bell) { + if (! quiet) rfbLog("rawfb: turning off watch_bell\n"); + watch_bell = 0; + } + if (no_autorepeat) { + if (! quiet) rfbLog("rawfb: turning off " + "no_autorepeat\n"); + no_autorepeat = 0; + } + if (use_solid_bg) { + if (! quiet) rfbLog("rawfb: turning off " + "use_solid_bg\n"); + use_solid_bg = 0; + } + multiple_cursors_mode = strdup("arrow"); + } + if (use_snapfb) { + if (! quiet) rfbLog("rawfb: turning off use_snapfb\n"); + use_snapfb = 0; + } + if (using_shm) { + if (! quiet) rfbLog("rawfb: turning off using_shm\n"); + using_shm = 0; + } + if (take_naps) { + if (! quiet) rfbLog("rawfb: turning off take_naps\n"); + take_naps = 0; + } + if (xrandr) { + if (! quiet) rfbLog("rawfb: turning off xrandr\n"); + xrandr = 0; + } +} + +/* + * 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; + rfbLog("framebuffer requested in -nofb mode by client %s\n", cl->host); + /* ignore xrandr */ + fb = XGetImage_wr(dpy, window, 0, 0, dpy_x, dpy_y, AllPlanes, ZPixmap); + main_fb = fb->data; + rfb_fb = main_fb; + screen->frameBuffer = rfb_fb; + screen->displayHook = NULL; +} + +void do_new_fb(int reset_mem) { + XImage *fb; + char *old_main = main_fb; + char *old_rfb = rfb_fb; + + /* for threaded we really should lock libvncserver out. */ + if (use_threads) { + rfbLog("warning: changing framebuffers while threaded may\n"); + rfbLog(" not work, do not use -threads if problems arise.\n"); + } + + if (reset_mem == 1) { + /* reset_mem == 2 is a hack for changing users... */ + clean_shm(0); + free_tiles(); + } + + fb = initialize_xdisplay_fb(); + + initialize_screen(NULL, NULL, fb); + + if (reset_mem) { + initialize_tiles(); + initialize_blackouts_and_xinerama(); + initialize_polling_images(); + } + + if (old_main != old_rfb && old_main) { + free(old_main); + } + if (old_rfb) { + free(old_rfb); + } + fb0 = fb; +} + +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 install_fake_fb(int w, int h, int bpp) { + int bpc; + if (! screen) { + return; + } + 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); + 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); + + rfbNewFramebuffer(screen, fake_fb, w, h, bpc, 1, bpp/8); +} + +void check_padded_fb(void) { + if (! fake_fb) { + return; + } + if (time(0) > 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(0); +} + +static void initialize_snap_fb(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 XImage *initialize_raw_fb(void) { + char *str, *q; + int w, h, b, shmid = 0; + unsigned long rm = 0, gm = 0, bm = 0; + static XImage ximage_struct; /* n.b.: not (XImage *) */ + int closedpy = 1, i, m; + + 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); + } +#endif + } else if (raw_fb_seek) { + if (raw_fb_fd >= 0) { + close(raw_fb_fd); + } + } + raw_fb_addr = NULL; + } + if (! raw_fb_str) { + return NULL; + } + + + if ( (q = strstr(raw_fb_str, "setup:")) == raw_fb_str) { + FILE *pipe; + char line[1024], *t; + + set_child_info(); + q += strlen("setup:"); + if (no_external_cmds) { + 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); + 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(raw_fb_str); + } + + /* + * uppercase means do not close the display (e.g. for remote control) + */ + if (strstr(str, "SHM:") == str) { + closedpy = 0; + str[0] = 's'; str[1] = 'h'; str[2] = 'm'; + } else if (strstr(str, "MAP:") == str) { + closedpy = 0; + str[0] = 'm'; str[1] = 'a'; str[2] = 'p'; + } else if (strstr(str, "MMAP:") == str) { + closedpy = 0; + str[0] = 'm'; str[1] = 'm'; str[2] = 'a'; str[3] = 'p'; + } else if (strstr(str, "FILE:") == str) { + str[0] = 'f'; str[1] = 'i'; str[2] = 'l'; str[3] = 'e'; + closedpy = 0; + } + + 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(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 + */ + + raw_fb_offset = 0; + + /* +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); + } + /* @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 (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 *new; + 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); + new = (char *) malloc(len); + strcpy(new, "map:"); + strcat(new, str); + free(str); + str = new; + } + } + + dpy_x = wdpy_x = w; + dpy_y = wdpy_y = h; + off_x = 0; + off_y = 0; + + raw_fb_shm = 0; + raw_fb_mmap = 0; + raw_fb_seek = 0; + raw_fb_fd = -1; + raw_fb_addr = NULL; + + if (sscanf(str, "shm:%d", &shmid) == 1) { + /* shm:N */ +#if LIBVNCSERVER_HAVE_XSHM + 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); +#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++; + + fd = open(q, O_RDONLY); + if (fd < 0) { + rfbLogEnable(1); + rfbLog("failed to open file: %s, %s\n", q, str); + rfbLogPerror("open"); + clean_up_exit(1); + } + raw_fb_fd = fd; + + 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_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"); + clean_up_exit(1); + } + 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); +#else + rfbLog("mmap(2) not supported on system, using" + " slower lseek(2)\n"); + raw_fb_seek = size; +#endif + } else { + raw_fb_seek = size; + + 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 (! raw_fb_image) { + raw_fb_image = &ximage_struct; + } + + initialize_clipshift(); + + raw_fb = (char *) malloc(dpy_x * dpy_y * 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->bytes_per_line = dpy_x*b/8; + + 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; + } + } + + 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_image->depth) { + raw_fb_image->depth = (b == 32) ? 24 : b; + } + + if (clipshift) { + memset(raw_fb, 0xff, dpy_x * dpy_y * b/8); + } else if (raw_fb_addr) { + memcpy(raw_fb, raw_fb_addr + raw_fb_offset, dpy_x*dpy_y*b/8); + } else { + memset(raw_fb, 0xff, dpy_x * dpy_y * b/8); + } + + rfbLog("rawfb: raw_fb %p\n", raw_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("skipping 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) { + int ms = 50, waittime = 30; + time_t start = time(0); + XWindowAttributes attr; + + while (1) { + if (! valid_window(win, NULL, 0)) { + if (time(0) > start + waittime) { + break; + } + usleep(ms * 1000); + continue; + } + if (! XGetWindowAttributes(dpy, win, &attr)) { + return 0; + } + if (attr.map_state == IsViewable) { + return 1; + } + usleep(ms * 1000); + } + return 0; +} + +/* + * initialize a fb for the X display + */ +XImage *initialize_xdisplay_fb(void) { + XImage *fb; + char *vis_str = visual_str; + int try = 0, subwin_tries = 3; + XErrorHandler old_handler; + int subwin_bs; + + if (raw_fb_str) { + return initialize_raw_fb(); + } + + 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 (vis_str != NULL) { + set_visual(vis_str); + if (vis_str != visual_str) { + free(vis_str); + } + } + + /* set up parameters for subwin or non-subwin cases: */ + + 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 (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(vinfo); + } + + if (! quiet) { + rfbLog("Default visual ID: 0x%x\n", + (int) XVisualIDFromVisual(default_visual)); + } + + again: + if (subwin) { + int shift = 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); + XTranslateCoordinates(dpy, window, rootwin, 0, 0, &subwin_x, + &subwin_y, &twin); + + 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 (shift) { + XMoveWindow(dpy, window, subwin_x, subwin_y); + } + XMapRaised(dpy, window); + XRaiseWindow(dpy, window); + XFlush(dpy); + } + 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); + 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) { + 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 && try == 1) { + /* try once more */ + usleep(250 * 1000); + 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; +} + +void parse_scale_string(char *str, double *factor, int *scaling, int *blend, + int *nomult4, int *pad, int *interpolate, int *numer, int *denom) { + + int m, n; + char *p, *tstr; + double f; + + *factor = 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, "%lf", &f) != 1) { + rfbLogEnable(1); + rfbLog("invalid -scale arg: %s\n", tstr); + clean_up_exit(1); + } + *factor = (double) f; + /* look for common fractions from small ints: */ + for (n=2; n<=10; n++) { + for (m=1; m<n; m++) { + test = ((double) m)/ n; + diff = *factor - test; + if (-eps < diff && diff < eps) { + *numer = m; + *denom = n; + break; + + } + } + if (*denom) { + break; + } + } + if (*factor < 0.01) { + rfbLogEnable(1); + rfbLog("-scale factor too small: %f\n", scale_fac); + clean_up_exit(1); + } + } 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 = ((double) m)/ n; + if (*factor < 0.01) { + rfbLogEnable(1); + rfbLog("-scale factor too small: %f\n", *factor); + clean_up_exit(1); + } + *numer = m; + *denom = n; + } + if (*factor == 1.0) { + if (! quiet) { + rfbLog("scaling disabled for factor %f\n", *factor); + } + } else { + *scaling = 1; + } + free(tstr); +} + +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, &scaling, &scaling_blend, + &scaling_nomult4, &scaling_pad, &scaling_interpolate, + &scale_numer, &scale_denom); + + if (scaling) { + width = scale_round(width, scale_fac); + height = scale_round(height, scale_fac); + 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; + } +} + +/* + * 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; + + main_bytes_per_line = fb->bytes_per_line; + + setup_scaling(&width, &height); + + + if (scaling) { + rfbLog("scaling screen: %dx%d -> %dx%d scale_fac=%.5f\n", + fb->width, fb->height, scaled_x, scaled_y, scale_fac); + + rfb_bytes_per_line = (main_bytes_per_line / fb->width) * width; + } else { + rfb_bytes_per_line = main_bytes_per_line; + } + + /* + * 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->bits_per_pixel); + + /* n.b. samplesPerPixel (set = 1 here) seems to be unused. */ + if (create_screen) { + screen = rfbGetScreen(argc, argv, width, height, + bits_per_color, 1, (int) fb->bits_per_pixel/8); + if (screen && http_dir) { + http_connections(1); + } + } 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->bits_per_pixel/8); + + /* these are probably overwritten, but just to be safe: */ + screen->bitsPerPixel = fb->bits_per_pixel; + screen->depth = fb->depth; + + rfbNewFramebuffer(screen, NULL, width, height, + bits_per_color, 1, (int) fb->bits_per_pixel/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("\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: */ + screen->paddedWidthInBytes = rfb_bytes_per_line; + screen->serverFormat.bitsPerPixel = fb->bits_per_pixel; + 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 (! have_masks && screen->serverFormat.bitsPerPixel == 8 + && dpy && CellsOfScreen(ScreenOfDisplay(dpy, scr))) { + /* indexed color */ + if (!quiet) { + rfbLog("X display %s is 8bpp indexed color\n", + DisplayString(dpy)); + 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"); + } + } + 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("Raw fb at addr %p is %dbpp depth=%d " + "true color\n", raw_fb_addr, + fb->bits_per_pixel, fb->depth); + } else { + rfbLog("X display %s is %dbpp depth=%d true " + "color\n", DisplayString(dpy), + fb->bits_per_pixel, fb->depth); + } + } + + indexed_color = 0; + + /* convert masks to bit shifts and max # colors */ + if (fb->red_mask) { + while (! (fb->red_mask + & (1 << screen->serverFormat.redShift))) { + screen->serverFormat.redShift++; + } + } + if (fb->green_mask) { + while (! (fb->green_mask + & (1 << screen->serverFormat.greenShift))) { + screen->serverFormat.greenShift++; + } + } + if (fb->blue_mask) { + while (! (fb->blue_mask + & (1 << screen->serverFormat.blueShift))) { + screen->serverFormat.blueShift++; + } + } + screen->serverFormat.redMax + = fb->red_mask >> screen->serverFormat.redShift; + screen->serverFormat.greenMax + = fb->green_mask >> screen->serverFormat.greenShift; + screen->serverFormat.blueMax + = fb->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 (!quiet) { + 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)); + 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); + 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; + screen->displayHook = nofb_hook; + } else { + main_fb = fb->data; + if (scaling) { + rfb_fb = (char *) malloc(rfb_bytes_per_line * height); + memset(rfb_fb, 0, rfb_bytes_per_line * height); + } else { + rfb_fb = main_fb; + } + } + screen->frameBuffer = rfb_fb; + if (!quiet) { + fprintf(stderr, " main_fb: %p\n", main_fb); + fprintf(stderr, " rfb_fb: %p\n", rfb_fb); + fprintf(stderr, "\n"); + } + + bpp = screen->serverFormat.bitsPerPixel; + depth = screen->serverFormat.depth; + + /* may need, bpp, main_red_max, etc. */ + parse_wireframe(); + parse_scroll_copyrect(); + + setup_cursors_and_push(); + + if (scaling) { + 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"); + do_copy_screen = 1; + + /* done for framebuffer change case */ + return; + } + + /* + * the rest is screen server initialization, etc, only needed + * at screen creation time. + */ + + /* called from inetd, we need to treat stdio as our socket */ + 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) { + screen->autoPort = TRUE; + } + + if (! got_nevershared && ! got_alwaysshared) { + if (shared) { + screen->alwaysShared = TRUE; + } else { + screen->neverShared = TRUE; + } + screen->dontDisconnect = TRUE; + } + if (! got_deferupdate) { + screen->deferUpdateTime = defer_update; + } + + /* event callbacks: */ + screen->newClientHook = new_client; + screen->kbdAddEvent = keyboard; + screen->ptrAddEvent = pointer; + screen->setXCutText = xcut_receive; + + rfbInitServer(screen); + + install_passwds(); +} + +void set_vnc_desktop_name(void) { + int sz = 256; + sprintf(vnc_desktop_name, "unknown"); + if (inetd) { + sprintf(vnc_desktop_name, "inetd-no-further-clients"); + } + if (screen->port) { + char *host = this_host(); + int lport = screen->port; + char *iface = listen_str; + + if (iface != NULL && *iface != '\0' && strcmp(iface, "any")) { + host = iface; + } + if (host != NULL) { + /* note that vncviewer special cases 5900-5999 */ + if (inetd) { + ; /* should not occur (port) */ + } else if (quiet) { + if (lport >= 5900) { + snprintf(vnc_desktop_name, sz, "%s:%d", + host, lport - 5900); + fprintf(stderr, "The VNC desktop is " + "%s\n", vnc_desktop_name); + } else { + snprintf(vnc_desktop_name, sz, "%s:%d", + host, lport); + fprintf(stderr, "The VNC desktop is " + "%s\n", vnc_desktop_name); + } + } else if (lport >= 5900) { + snprintf(vnc_desktop_name, sz, "%s:%d", + host, lport - 5900); + rfbLog("\n"); + rfbLog("The VNC desktop is %s\n", + 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); + rfbLog("\n"); + rfbLog("The VNC desktop is %s\n", + vnc_desktop_name); + rfbLog("possible alias: %s::%d\n", + host, lport); + } + } + fflush(stderr); + if (inetd) { + ; /* should not occur (port != 0) */ + } else { + fprintf(stdout, "PORT=%d\n", screen->port); + fflush(stdout); + if (flagfile) { + FILE *flag = fopen(flagfile, "w"); + if (flag) { + fprintf(flag, "PORT=%d\n",screen->port); + fflush(flag); + fclose(flag); + } else { + rfbLog("could not open flag file: %s\n", + flagfile); + } + } + } + fflush(stdout); + } +} + + |