diff options
author | runge <runge> | 2004-04-08 20:07:29 +0000 |
---|---|---|
committer | runge <runge> | 2004-04-08 20:07:29 +0000 |
commit | 782c6e7a15ce1870f1e3d6d450a119f444b6b1e8 (patch) | |
tree | 4a1ccd6a59a7ec202cd01d7e768aad70f6509379 /contrib | |
parent | e68063f2467951e72832a31d54f8c35cdfdcbd26 (diff) | |
download | libtdevnc-782c6e7a15ce1870f1e3d6d450a119f444b6b1e8.tar.gz libtdevnc-782c6e7a15ce1870f1e3d6d450a119f444b6b1e8.zip |
x11vnc options -blackout, -xinerama, -xwarppointer. check cargs.
modify configure.ac to pick up -lXinerama
Diffstat (limited to 'contrib')
-rw-r--r-- | contrib/ChangeLog | 9 | ||||
-rw-r--r-- | contrib/x11vnc.c | 1065 |
2 files changed, 814 insertions, 260 deletions
diff --git a/contrib/ChangeLog b/contrib/ChangeLog index 4f0c67c..5ac9f10 100644 --- a/contrib/ChangeLog +++ b/contrib/ChangeLog @@ -1,3 +1,12 @@ +2004-04-08 Karl Runge <runge@karlrunge.com> + * added support for blacking out regions of the screen, primarily + for Xinerama usage, options: -blackout -xinerama + * Xinerama workaround mouse problem on 'embedded' system, + option -xwarppointer (XWarpPointer instead of XTEST) + * let -remap option take key remappings on cmdline as well as file. + * use cargs fix to test for invalid cmdline options. Add --option. + * remove copy_tile, use copy_tiles(..., 1) instead. + 2004-03-10 Karl Runge <runge@karlrunge.com> * added reverse connection for vncconnect(1) and other means -vncconnect, -connect host:port, and -connect watchfile diff --git a/contrib/x11vnc.c b/contrib/x11vnc.c index c094147..06505b4 100644 --- a/contrib/x11vnc.c +++ b/contrib/x11vnc.c @@ -108,11 +108,24 @@ #include <fcntl.h> #include <rfb/rfb.h> +#include <rfb/rfbregion.h> #ifdef LIBVNCSERVER_HAVE_XKEYBOARD #include <X11/XKBlib.h> #endif +/* + * Temporary kludge: to run with -xinerama define the following macro + * and be sure to link with * -lXinerama (e.g. LDFLAGS=-lXinerama before + * configure). Support for this is being added to libvncserver 'configure.ac' + * so it will all be done automatically. + +#define LIBVNCSERVER_HAVE_LIBXINERAMA + */ +#ifdef LIBVNCSERVER_HAVE_LIBXINERAMA +#include <X11/extensions/Xinerama.h> +#endif + /* X and rfb framebuffer */ Display *dpy = 0; @@ -132,7 +145,9 @@ XImage *scanline; XImage *fullscreen; int fs_factor = 0; +#ifdef SINGLE_TILE_SHM XShmSegmentInfo tile_shm; +#endif XShmSegmentInfo *tile_row_shm; /* for all possible row runs */ XShmSegmentInfo scanline_shm; XShmSegmentInfo fullscreen_shm; @@ -149,6 +164,20 @@ int ntiles, ntiles_x, ntiles_y; /* arrays that indicate changed or checked tiles. */ unsigned char *tile_has_diff, *tile_tried; +/* blacked-out region things */ +typedef struct bout { + int x1, y1, x2, y2; +} blackout_t; +typedef struct tbout { + blackout_t bo[10]; /* hardwired max rectangles. */ + int cover; + int count; +} tile_blackout_t; +blackout_t black[100]; /* hardwired max blackouts */ +int blackouts = 0; +tile_blackout_t *tile_blackout; + + typedef struct tile_change_region { /* start and end lines, along y, of the changed area inside a tile. */ unsigned short first_line, last_line; @@ -180,21 +209,25 @@ int flash_cmap = 0; /* follow installed colormaps */ int force_indexed_color = 0; /* whether to force indexed color for 8bpp */ int use_modifier_tweak = 0; /* use the altgr_keyboard modifier tweak */ -char *remap_file = NULL; /* user supplied remapping file */ +char *remap_file = NULL; /* user supplied remapping file or list */ int nofb = 0; /* do not send any fb updates */ +char *blackout_string = NULL; /* -blackout */ +int xinerama = 0; /* -xinerama */ + char *client_connect = NULL; /* strings for -connect option */ char *client_connect_file = NULL; int vnc_connect = 0; /* -vncconnect option */ int local_cursor = 1; /* whether the viewer draws a local cursor */ int show_mouse = 0; /* display a cursor for the real mouse */ +int use_xwarppointer = 0; /* use XWarpPointer instead of XTestFake... */ int show_root_cursor = 0; /* show X when on root background */ int show_dragging = 1; /* process mouse movement events */ int watch_bell = 1; /* watch for the bell using XKEYBOARD */ int old_pointer = 0; /* use the old way of updating the pointer */ -int single_copytile = 0; /* use the old way copy_tile() */ +int single_copytile = 0; /* use the old way copy_tiles() */ int using_shm = 1; /* whether mit-shm is used */ int flip_byte_order = 0; /* sometimes needed when using_shm = 0 */ @@ -252,6 +285,8 @@ int debug_keyboard = 0; int quiet = 0; double dtime(double *); +void zero_fb(int, int, int, int); + #if defined(LIBVNCSERVER_X11VNC_THREADED) && ! defined(X11VNC_THREADED) #define X11VNC_THREADED #endif @@ -294,7 +329,9 @@ void clean_up_exit (int ret) { exit_flag = 1; /* remove the shm areas: */ +#ifdef SINGLE_TILE_SHM shm_clean(&tile_shm, tile); +#endif shm_clean(&scanline_shm, scanline); shm_clean(&fullscreen_shm, fullscreen); @@ -336,7 +373,9 @@ void interrupted (int sig) { * to avoid deadlock, etc, just delete the shm areas and * leave the X stuff hanging. */ +#ifdef SINGLE_TILE_SHM shm_delete(&tile_shm); +#endif shm_delete(&scanline_shm); shm_delete(&fullscreen_shm); @@ -387,7 +426,7 @@ void set_signals(void) { void client_gone(rfbClientPtr client) { if (connect_once) { - fprintf(stderr, "viewer exited.\n"); + rfbLog("viewer exited.\n"); clean_up_exit(0); } } @@ -729,9 +768,26 @@ void initialize_remap(char *infile) { in = fopen(infile, "r"); if (in == NULL) { - rfbLog("remap: cannot open: %s\n", infile); - perror("fopen"); - clean_up_exit(1); + /* assume cmd line key1:key2,key3:key4 */ + if (! strchr(infile, ':') || (in = tmpfile()) == NULL) { + rfbLog("remap: cannot open: %s\n", infile); + perror("fopen"); + clean_up_exit(1); + } + p = infile; + while (*p) { + if (*p == ':') { + fprintf(in, " "); + } else if (*p == ',') { + fprintf(in, "\n"); + } else { + fprintf(in, "%c", *p); + } + p++; + } + fprintf(in, "\n"); + fflush(in); + rewind(in); } while (fgets(line, 256, in) != NULL) { int blank = 1; @@ -804,13 +860,19 @@ void DebugXTestFakeKeyEvent(Display* dpy, KeyCode key, Bool down, time_t cur_tim void tweak_mod(signed char mod, rfbBool down) { rfbBool is_shift = mod_state & (LEFTSHIFT|RIGHTSHIFT); Bool dn = (Bool) down; - if (debug_keyboard) { - rfbLog("tweak_mod: down=%d mod=0x%x\n", down, mod); - } if (mod < 0) { + if (debug_keyboard) { + rfbLog("tweak_mod: Skip: down=%d mod=0x%x\n", down, + (int) mod); + } return; } + if (debug_keyboard) { + rfbLog("tweak_mod: Start: down=%d mod=0x%x mod_state=0x%x" + " is_shift=%d\n", down, (int) mod, (int) mod_state, + is_shift); + } X_LOCK; if (is_shift && mod != 1) { @@ -831,6 +893,11 @@ void tweak_mod(signed char mod, rfbBool down) { XTestFakeKeyEvent(dpy, altgr_code, dn, CurrentTime); } X_UNLOCK; + if (debug_keyboard) { + rfbLog("tweak_mod: Finish: down=%d mod=0x%x mod_state=0x%x" + " is_shift=%d\n", down, (int) mod, (int) mod_state, + is_shift); + } } static void modifier_tweak_keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) { @@ -867,11 +934,16 @@ static void modifier_tweak_keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr k = XKeysymToKeycode(dpy, (KeySym) keysym); X_UNLOCK; } + if (debug_keyboard) { + rfbLog("modifier_tweak_keyboard: KeySym 0x%x \"%s\" -> " + "KeyCode 0x%x%s\n", (int) keysym, XKeysymToString(keysym), + (int) k, k ? "" : " *ignored*"); + } if ( k != NoSymbol ) { X_LOCK; XTestFakeKeyEvent(dpy, k, (Bool) down, CurrentTime); X_UNLOCK; - } + } if ( tweak ) { tweak_mod(modifiers[keysym], False); @@ -928,8 +1000,9 @@ static void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) { k = XKeysymToKeycode(dpy, (KeySym) keysym); if (debug_keyboard) { - rfbLog("keyboard(): KeySym 0x%x \"%s\" -> KeyCode 0x%x\n", - (int) keysym, XKeysymToString(keysym), (int) k); + rfbLog("keyboard(): KeySym 0x%x \"%s\" -> KeyCode 0x%x%s\n", + (int) keysym, XKeysymToString(keysym), (int) k, + k ? "" : " *ignored*"); } if ( k != NoSymbol ) { @@ -1140,7 +1213,11 @@ void update_pointer(int mask, int x, int y) { X_LOCK; - XTestFakeMotionEvent(dpy, scr, x + off_x, y + off_y, CurrentTime); + if (! use_xwarppointer) { + XTestFakeMotionEvent(dpy, scr, x+off_x, y+off_y, CurrentTime); + } else { + XWarpPointer(dpy, None, window, 0, 0, 0, 0, x+off_x, y+off_y); + } cursor_x = x; cursor_y = y; @@ -1812,7 +1889,7 @@ int cur_save_x, cur_save_y, cur_save_w, cur_save_h; int cur_save_cx, cur_save_cy, cur_save_which, cur_saved = 0; /* - * save current cursor info and the patch of data it covers + * save current cursor info and the patch of non-cursor data it covers */ void save_mouse_patch(int x, int y, int w, int h, int cx, int cy, int which) { int pixelsize = bpp >> 3; @@ -1887,6 +1964,43 @@ int tree_descend_cursor(void) { return descend; } +void blackout_nearby_tiles(x, y, dt) { + int sx, sy, n, b; + int tx = x/tile_x; + int ty = y/tile_y; + + if (! blackouts) { + return; + } + if (dt < 1) { + dt = 1; + } + /* loop over a range of tiles, blacking out as needed */ + + for (sx = tx - dt; sx <= tx + dt; sx++) { + if (sx < 0 || sx >= tile_x) { + continue; + } + for (sy = ty - dt; sy <= ty + dt; sy++) { + if (sy < 0 || sy >= tile_y) { + continue; + } + n = sx + sy * ntiles_x; + if (tile_blackout[n].cover == 0) { + continue; + } + for (b=0; b <= tile_blackout[n].count; b++) { + int x1, y1, x2, y2; + x1 = tile_blackout[n].bo[b].x1; + y1 = tile_blackout[n].bo[b].y1; + x2 = tile_blackout[n].bo[b].x2; + y2 = tile_blackout[n].bo[b].y2; + zero_fb(x1, y1, x2, y2); + } + } + } +} + /* * draw one of the mouse cursors into the rfb fb */ @@ -1975,6 +2089,27 @@ void draw_mouse(int x, int y, int which, int update) { } } + if (blackouts) { + /* + * loop over a range of tiles, blacking out as needed + * note we currently disable mouse drawing under blackouts. + */ + static int mx = -1, my = -1; + int skip = 0; + if (mx < 0) { + mx = x; + my = y; + } else if (mx == x && my == y) { + skip = 1; + } + mx = x; + my = y; + + if (! skip) { + blackout_nearby_tiles(x, y, 2); + } + } + if (update) { /* x and y of the real (X server) mouse */ static int mouse_x = -1; @@ -2260,10 +2395,42 @@ void nofb_hook(rfbClientPtr cl) { */ void initialize_screen(int *argc, char **argv, XImage *fb) { int have_masks = 0; + int argc_orig = *argc; screen = rfbGetScreen(argc, argv, fb->width, fb->height, fb->bits_per_pixel, 8, fb->bits_per_pixel/8); + fprintf(stderr, "\n"); + + if (! screen) { + int i; + 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); + } + +/* + * This ifdef is a transient for source compatibility for people who download + * the x11vnc.c file by itself and plop it down into their libvncserver tree. + * Remove at some point. BTW, this assumes no usage of earlier "0.7pre". + */ +#ifdef LIBVNCSERVER_VERSION +if (strcmp(LIBVNCSERVER_VERSION, "0.5") && strcmp(LIBVNCSERVER_VERSION, "0.6")) { + if (*argc != 1) { + int i; + 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 -help\n"); + clean_up_exit(1); + } +} +#endif + screen->paddedWidthInBytes = fb->bytes_per_line; screen->rfbServerFormat.bitsPerPixel = fb->bits_per_pixel; screen->rfbServerFormat.depth = fb->depth; @@ -2276,14 +2443,14 @@ void initialize_screen(int *argc, char **argv, XImage *fb) { if ( ! have_masks && screen->rfbServerFormat.bitsPerPixel == 8 && CellsOfScreen(ScreenOfDisplay(dpy,scr)) ) { /* indexed colour */ - if (! quiet) fprintf(stderr, "using 8bpp indexed colour\n"); + if (!quiet) rfbLog("Using X display with 8bpp indexed color\n"); indexed_colour = 1; set_colormap(); } else { /* general case ... */ if (! quiet) { - fprintf(stderr, "using %dbpp depth=%d true colour\n", - fb->bits_per_pixel, fb->depth); + rfbLog("Using X display with %dbpp depth=%d true " + "color\n", fb->bits_per_pixel, fb->depth); } /* convert masks to bit shifts and max # colors */ @@ -2378,6 +2545,316 @@ void initialize_screen(int *argc, char **argv, XImage *fb) { } /* + * Take a comma separated list of geometries: WxH+X+Y and register them as + * rectangles to black out from the screen. + */ +void initialize_blackout (char *list) { + char *p, *blist = strdup(list); + int x, y, X, Y, h, w; + int tx, ty; + + p = strtok(blist, ","); + while (p) { + /* handle +/-x and +/-y */ + if (sscanf(p, "%dx%d+%d+%d", &w, &h, &x, &y) == 4) { + ; + } else if (sscanf(p, "%dx%d-%d+%d", &w, &h, &x, &y) == 4) { + x = dpy_x - x - w; + } else if (sscanf(p, "%dx%d+%d-%d", &w, &h, &x, &y) == 4) { + y = dpy_y - y - h; + } else if (sscanf(p, "%dx%d-%d-%d", &w, &h, &x, &y) == 4) { + x = dpy_x - x - w; + y = dpy_y - y - h; + } else { + if (*p != '\0') { + rfbLog("skipping invalid geometry: %s\n", p); + } + p = strtok(NULL, ","); + continue; + } + X = x + w; + Y = y + h; + if (x < 0 || x > dpy_x || y < 0 || y > dpy_y || + X < 0 || X > dpy_x || Y < 0 || Y > dpy_y) { + rfbLog("skipping invalid blackout geometry: %s x=" + "%d-%d,y=%d-%d,w=%d,h=%d\n", p, x, X, y, Y, w, h); + } else { + rfbLog("blackout rect: %s: x=%d-%d y=%d-%d\n", p, + x, X, y, Y); + + /* + * note that the black out is x1 <= x but x < x2 + * for the region. i.e. the x2, y2 are outside + * by 1 pixel. + */ + black[blackouts].x1 = x; + black[blackouts].y1 = y; + black[blackouts].x2 = X; + black[blackouts].y2 = Y; + blackouts++; + if (blackouts >= 100) { + rfbLog("too many blackouts: %d\n", blackouts); + break; + } + } + p = strtok(NULL, ","); + } + free(blist); +} + +/* + * Now that all blackout rectangles have been constructed, see what overlap + * they have with the tiles in the system. If a tile is touched by a + * blackout, record information. + */ +void blackout_tiles() { + int tx, ty; + if (! blackouts) { + return; + } + + /* + * to simplify things drop down to single copy mode, no vcr, etc... + */ + single_copytile = 1; + if (show_mouse) { + rfbLog("disabling remote mouse drawing due to blackouts\n"); + show_mouse = 0; + } + + /* loop over all tiles. */ + for (ty=0; ty < ntiles_y; ty++) { + for (tx=0; tx < ntiles_x; tx++) { + sraRegionPtr tile_reg, black_reg; + sraRect rect; + sraRectangleIterator *iter; + int n, b, x1, y1, x2, y2, cnt; + + /* tile number and coordinates: */ + n = tx + ty * ntiles_x; + x1 = tx * tile_x; + y1 = ty * tile_y; + x2 = x1 + tile_x; + y2 = y1 + tile_y; + if (x2 > dpy_x) { + x2 = dpy_x; + } + if (y2 > dpy_y) { + y2 = dpy_y; + } + + /* make regions for the tile and the blackouts: */ + black_reg = (sraRegionPtr) sraRgnCreate(); + tile_reg = (sraRegionPtr) sraRgnCreateRect(x1, y1, + x2, y2); + + tile_blackout[n].cover = 0; + tile_blackout[n].count = 0; + + /* union of blackouts */ + for (b=0; b < blackouts; b++) { + sraRegionPtr tmp_reg = (sraRegionPtr) + sraRgnCreateRect(black[b].x1, black[b].y1, + black[b].x2, black[b].y2); + + sraRgnOr(black_reg, tmp_reg); + sraRgnDestroy(tmp_reg); + } + + if (! sraRgnAnd(black_reg, tile_reg)) { + /* + * no intersection for this tile, so we + * are done. + */ + sraRgnDestroy(black_reg); + sraRgnDestroy(tile_reg); + continue; + } + + /* + * loop over rectangles that make up the blackout + * region: + */ + cnt = 0; + iter = sraRgnGetIterator(black_reg); + while (sraRgnIteratorNext(iter, &rect)) { + + /* make sure x1 < x2 and y1 < y2 */ + if (rect.x1 > rect.x2) { + int tmp = rect.x2; + rect.x2 = rect.x1; + rect.x1 = tmp; + } + if (rect.y1 > rect.y2) { + int tmp = rect.y2; + rect.y2 = rect.y1; + rect.y1 = tmp; + } + + /* store coordinates */ + tile_blackout[n].bo[cnt].x1 = rect.x1; + tile_blackout[n].bo[cnt].y1 = rect.y1; + tile_blackout[n].bo[cnt].x2 = rect.x2; + tile_blackout[n].bo[cnt].y2 = rect.y2; + + /* note if the tile is completely obscured */ + if (rect.x1 == x1 && rect.y1 == y1 && + rect.x2 == x2 && rect.y2 == y2) { + tile_blackout[n].cover = 2; + } else { + tile_blackout[n].cover = 1; + } + + if (++cnt >= 10) { + rfbLog("too many blackout rectangles " + "for tile %d=%d,%d.\n", n, tx, ty); + break; + } + } + + sraRgnReleaseIterator(iter); + sraRgnDestroy(black_reg); + sraRgnDestroy(tile_reg); + + tile_blackout[n].count = cnt; + } + } +} + +void initialize_xinerama () { +#ifdef LIBVNCSERVER_HAVE_LIBXINERAMA + XineramaScreenInfo *sc, *xineramas; +#endif + sraRegionPtr black_region, tmp_region; + sraRectangleIterator *iter; + sraRect rect; + char *bstr, *tstr; + int ev, er, i, n, rcnt; + +#ifndef LIBVNCSERVER_HAVE_LIBXINERAMA + rfbLog("Xinerama: Library libXinerama is not available to determine\n"); + rfbLog("Xinerama: the head geometries, consider using -blackout\n"); + rfbLog("Xinerama: if the screen is non-rectangular.\n"); +#else + if (! XineramaQueryExtension(dpy, &ev, &er)) { + rfbLog("Xinerama: disabling: display does not support it.\n"); + xinerama = 0; + return; + } + if (! XineramaIsActive(dpy)) { + /* n.b. change to XineramaActive(dpy, window) someday */ + rfbLog("Xinerama: disabling: not active on display.\n"); + xinerama = 0; + return; + } + + /* n.b. change to XineramaGetData() someday */ + xineramas = XineramaQueryScreens(dpy, &n); + rfbLog("Xinerama: number of sub-screens: %d\n", n); + + if (n == 1) { + rfbLog("Xinerama: no blackouts needed (only one" + " sub-screen)\n"); + XFree(xineramas); + return; /* must be OK w/o change */ + } + + black_region = sraRgnCreateRect(0, 0, dpy_x, dpy_y); + + sc = xineramas; + for (i=0; i<n; i++) { + int x, y, w, h; + + x = sc->x_org; + y = sc->y_org; + w = sc->width; + h = sc->height; + + tmp_region = sraRgnCreateRect(x, y, x + w, y + h); + + sraRgnSubtract(black_region, tmp_region); + sraRgnDestroy(tmp_region); + sc++; + } + XFree(xineramas); + + if (sraRgnEmpty(black_region)) { + rfbLog("Xinerama: no blackouts needed (screen fills" + " rectangle)\n"); + sraRgnDestroy(black_region); + return; + } + + /* max len is 10000x10000+10000+10000 (23 chars) per geometry */ + rcnt = (int) sraRgnCountRects(black_region); + bstr = (char *) malloc(30 * rcnt * sizeof(char)); + tstr = (char *) malloc(30 * sizeof(char)); + bstr[0] = '\0'; + + iter = sraRgnGetIterator(black_region); + while (sraRgnIteratorNext(iter, &rect)) { + int x, y, w, h; + + /* make sure x1 < x2 and y1 < y2 */ + if (rect.x1 > rect.x2) { + int tmp = rect.x2; + rect.x2 = rect.x1; + rect.x1 = tmp; + } + if (rect.y1 > rect.y2) { + int tmp = rect.y2; + rect.y2 = rect.y1; + rect.y1 = tmp; + } + x = rect.x1; + y = rect.y1; + w = rect.x2 - x; + h = rect.y2 - y; + sprintf(tstr, "%dx%d+%d+%d,", w, h, x, y); + strcat(bstr, tstr); + } + initialize_blackout(bstr); + + free(bstr); + free(tstr); +#endif + +} + +/* + * Fill the framebuffer with zero for the prescribed rectangle + */ +void zero_fb(x1, y1, x2, y2) { + int pixelsize = bpp >> 3; + int line, fill = 0; + char *dst; + + if (x1 < 0 || x2 <= x1 || x2 > dpy_x) { + return; + } + if (y1 < 0 || y2 <= y1 || y2 > dpy_y) { + return; + } + + dst = screen->frameBuffer + y1 * bytes_per_line + x1 * pixelsize; + line = y1; + while (line++ < y2) { + memset(dst, fill, (size_t) (x2 - x1) * pixelsize); + dst += bytes_per_line; + } +} + +/* + * Fill the framebuffer with zeros for each blackout region + */ +void blackout_regions() { + int i; + for (i=0; i < blackouts; i++) { + zero_fb(black[i].x1, black[i].y1, black[i].x2, black[i].y2); + } +} + +/* * setup tile numbers and allocate the tile and hint arrays: */ void initialize_tiles() { @@ -2390,6 +2867,8 @@ void initialize_tiles() { malloc((size_t) (ntiles * sizeof(unsigned char))); tile_tried = (unsigned char *) malloc((size_t) (ntiles * sizeof(unsigned char))); + tile_blackout = (tile_blackout_t *) + malloc((size_t) (ntiles * sizeof(tile_blackout_t))); tile_region = (region_t *) malloc((size_t) (ntiles * sizeof(region_t))); tile_row = (XImage **) @@ -2472,7 +2951,7 @@ int shm_create(XShmSegmentInfo *shm, XImage **ximg_ptr, int w, int h, xim->bitmap_bit_order = LSBFirst; } if (! reported && ! quiet) { - fprintf(stderr, "changing XImage byte order" + rfbLog("changing XImage byte order" " to %s\n", bo); reported = 1; } @@ -2575,9 +3054,11 @@ void initialize_shm() { int i; /* set all shm areas to "none" before trying to create any */ +#ifdef SINGLE_TILE_SHM tile_shm.shmid = -1; tile_shm.shmaddr = (char *) -1; tile = NULL; +#endif scanline_shm.shmid = -1; scanline_shm.shmaddr = (char *) -1; scanline = NULL; @@ -2590,11 +3071,13 @@ void initialize_shm() { tile_row[i] = NULL; } +#ifdef SINGLE_TILE_SHM /* the tile (e.g. 32x32) shared memory area image: */ if (! shm_create(&tile_shm, &tile, tile_x, tile_y, "tile")) { clean_up_exit(1); } +#endif /* the scanline (e.g. 1280x1) shared memory area image: */ @@ -2608,8 +3091,12 @@ void initialize_shm() { * limits, e.g. the default 1MB on Solaris) */ set_fs_factor(1024 * 1024); + if (fs_frac >= 1.0) { + fs_frac = 1.1; + fs_factor = 0; + } if (! fs_factor) { - fprintf(stderr, "warning: fullscreen updates are disabled.\n"); + rfbLog("warning: fullscreen updates are disabled.\n"); } else { if (! shm_create(&fullscreen_shm, &fullscreen, dpy_x, dpy_y/fs_factor, "fullscreen")) { @@ -2800,168 +3287,6 @@ void tile_updates() { /* - * copy_tile() is called on a tile with a known change (from a scanline - * diff) or a suspected change (from our various heuristics). - * - * Examine the whole tile for the y-range of difference, copy that - * image difference to the rfb framebuffer, and do bookkeepping wrt - * the y-range and edge differences. - * - * This call is somewhat costly, maybe 1-2 ms. Primarily the XShmGetImage - * and then the memcpy/memcmp. - */ - -void copy_tile(int tx, int ty) { - int x, y, line, first_line, last_line; - int size_x, size_y, n, dw, dx; - int pixelsize = bpp >> 3; - unsigned short l_diff = 0, r_diff = 0; - - int restored_patch = 0; /* for show_mouse */ - - char *src, *dst, *s_src, *s_dst, *m_src, *m_dst; - char *h_src, *h_dst; - - x = tx * tile_x; - y = ty * tile_y; - - size_x = dpy_x - x; - if ( size_x > tile_x ) size_x = tile_x; - - size_y = dpy_y - y; - if ( size_y > tile_y ) size_y = tile_y; - - n = tx + ty * ntiles_x; /* number of the tile */ - - X_LOCK; - if ( using_shm && size_x == tile_x && size_y == tile_y ) { - /* general case: */ - XShmGetImage(dpy, window, tile, x, y, AllPlanes); - } else { - /* - * No shm or near bottom/rhs edge case: - * (but only if tile size does not divide screen size) - */ - XGetSubImage(dpy, window, x, y, size_x, size_y, AllPlanes, - ZPixmap, tile, 0, 0); - } - X_UNLOCK; - - /* - * Some awkwardness wrt the little remote mouse patch we display. - * When threaded we want to have as small a window of time - * as possible when the mouse image is not in the fb, otherwise - * a libvncserver thread may send the uncorrected patch to the - * clients. - */ - if (show_mouse && use_threads && cur_saved) { - /* check for overlap */ - if (cur_save_x + cur_save_w > x && x + size_x > cur_save_x && - cur_save_y + cur_save_h > y && y + size_y > cur_save_y) { - - /* restore the real data to the rfb fb */ - restore_mouse_patch(); - restored_patch = 1; - } - } - - src = tile->data; - dst = screen->frameBuffer + y * bytes_per_line + x * pixelsize; - - s_src = src; - s_dst = dst; - - first_line = -1; - - /* find the first line with difference: */ - for (line = 0; line < size_y; line++) { - if ( memcmp(s_dst, s_src, size_x * pixelsize) ) { - first_line = line; - break; - } - s_src += tile->bytes_per_line; - s_dst += bytes_per_line; - } - - tile_tried[n] = 1; - if (first_line == -1) { - /* tile has no difference, note it and get out: */ - tile_has_diff[n] = 0; - if (restored_patch) { - redraw_mouse(); - } - return; - } else { - /* - * make sure it is recorded (e.g. sometimes we guess tiles - * and they came in with tile_has_diff 0) - */ - tile_has_diff[n] = 1; - } - - m_src = src + (tile->bytes_per_line * size_y); - m_dst = dst + (bytes_per_line * size_y); - last_line = first_line; - - /* find the last line with difference: */ - for (line = size_y - 1; line > first_line; line--) { - m_src -= tile->bytes_per_line; - m_dst -= bytes_per_line; - if ( memcmp(m_dst, m_src, size_x * pixelsize) ) { - last_line = line; - break; - } - } - - /* look for differences on left and right hand edges: */ - dx = (size_x - tile_fuzz) * pixelsize; - dw = tile_fuzz * pixelsize; - - h_src = src; - h_dst = dst; - for (line = 0; line < size_y; line++) { - if (! l_diff && memcmp(h_dst, h_src, dw) ) { - l_diff = 1; - } - if (! r_diff && memcmp(h_dst + dx, h_src + dx, dw) ) { - r_diff = 1; - } - if (l_diff && r_diff) { - break; - } - h_src += tile->bytes_per_line; - h_dst += bytes_per_line; - } - - /* now copy the difference to the rfb framebuffer: */ - for (line = first_line; line <= last_line; line++) { - memcpy(s_dst, s_src, size_x * pixelsize); - s_src += tile->bytes_per_line; - s_dst += bytes_per_line; - } - - if (restored_patch) { - redraw_mouse(); - } - - /* record all the info in the region array for this tile: */ - tile_region[n].first_line = first_line; - tile_region[n].last_line = last_line; - tile_region[n].left_diff = l_diff; - tile_region[n].right_diff = r_diff; - - tile_region[n].top_diff = 0; - tile_region[n].bot_diff = 0; - if ( first_line < tile_fuzz ) { - tile_region[n].top_diff = 1; - } - if ( last_line > (size_y - 1) - tile_fuzz ) { - tile_region[n].bot_diff = 1; - } -} - - -/* * copy_tiles() gives a slight improvement over copy_tile() since * adjacent runs of tiles are done all at once there is some savings * due to contiguous memory access. Not a great speedup, but in @@ -3019,6 +3344,16 @@ void copy_tiles(int tx, int ty, int nt) { n = tx + ty * ntiles_x; /* number of the first tile */ + if (blackouts && tile_blackout[n].cover == 2) { + /* + * If there are blackouts and this tile is completely covered + * no need to poll screen or do anything else.. + * n.b. we are int single copy_tile mode: nt=1 + */ + tile_has_diff[n] = 0; + return; + } + X_LOCK; /* read in the whole tile run at once: */ if ( using_shm && size_x == tile_x * nt && size_y == tile_y ) { @@ -3034,6 +3369,35 @@ void copy_tiles(int tx, int ty, int nt) { } X_UNLOCK; + if (blackouts && tile_blackout[n].cover == 1) { + /* + * If there are blackouts and this tile is partially covered + * we should re-black-out the portion. + * n.b. we are int single copy_tile mode: nt=1 + */ + int x1, x2, y1, y2, b; + int w, s, fill = 0; + + for (b=0; b < tile_blackout[n].count; b++) { + char *b_dst = tile_row[nt]->data; + + x1 = tile_blackout[n].bo[b].x1 - x; + y1 = tile_blackout[n].bo[b].y1 - y; + x2 = tile_blackout[n].bo[b].x2 - x; + y2 = tile_blackout[n].bo[b].y2 - y; + + w = (x2 - x1) * pixelsize; + s = x1 * pixelsize; + + for (line = 0; line < size_y; line++) { + if (y1 <= line && line < y2) { + memset(b_dst + s, fill, (size_t) w); + } + b_dst += tile_row[nt]->bytes_per_line; + } + } + } + /* * Some awkwardness wrt the little remote mouse patch we display. * When threaded we want to have as small a window of time @@ -3285,12 +3649,11 @@ int copy_all_tiles() { n = x + y * ntiles_x; if (tile_has_diff[n]) { - copy_tile(x, y); - /* later: copy_tiles(x, y, 1); */ + copy_tiles(x, y, 1); } if (! tile_has_diff[n]) { /* - * n.b. copy_tile() may have detected + * n.b. copy_tiles() may have detected * no change and reset tile_has_diff to 0. */ continue; @@ -3404,7 +3767,7 @@ int copy_tiles_backward_pass() { if (y >= 1 && ! tile_has_diff[m] && tile_region[n].top_diff) { if (! tile_tried[m]) { tile_has_diff[m] = 2; - copy_tile(x, y-1); + copy_tiles(x, y-1, 1); } } @@ -3413,7 +3776,7 @@ int copy_tiles_backward_pass() { if (x >= 1 && ! tile_has_diff[m] && tile_region[n].left_diff) { if (! tile_tried[m]) { tile_has_diff[m] = 2; - copy_tile(x-1, y); + copy_tiles(x-1, y, 1); } } } @@ -3457,7 +3820,7 @@ void gap_try(int x, int y, int *run, int *saw, int along_x) { continue; } - copy_tile(xt, yt); + copy_tiles(xt, yt, 1); } *run = 0; *saw = 1; @@ -3522,7 +3885,7 @@ void island_try(int x, int y, int u, int v, int *run) { return; } - copy_tile(u, v); + copy_tiles(u, v, 1); } } @@ -3597,6 +3960,10 @@ void copy_screen() { X_UNLOCK; + if (blackouts) { + blackout_regions(); + } + rfbMarkRectAsModified(screen, 0, 0, dpy_x, dpy_y); } @@ -3704,7 +4071,7 @@ void ping_clients(int tile_cnt) { if (rfbMaxClientWait <= 3000) { rfbMaxClientWait = 3000; - fprintf(stderr, "reset rfbMaxClientWait to %d ms.\n", + rfbLog("reset rfbMaxClientWait to %d ms.\n", rfbMaxClientWait); } if (tile_cnt) { @@ -3717,6 +4084,114 @@ void ping_clients(int tile_cnt) { } /* + * scan_display() wants to know if this tile can be skipped due to + * blackout regions: (no data compare is done, just a quick geometric test) + */ +int blackout_line_skip(int n, int x, int y, int rescan, int *tile_count) { + + if (tile_blackout[n].cover == 2) { + tile_has_diff[n] = 0; + return 1; /* skip it */ + + } else if (tile_blackout[n].cover == 1) { + int w, x1, y1, x2, y2, b, hit = 0; + if (x + NSCAN > dpy_x) { + w = dpy_x - x; + } else { + w = NSCAN; + } + + for (b=0; b < tile_blackout[n].count; b++) { + + /* n.b. these coords are in full display space: */ + x1 = tile_blackout[n].bo[b].x1; + x2 = tile_blackout[n].bo[b].x2; + y1 = tile_blackout[n].bo[b].y1; + y2 = tile_blackout[n].bo[b].y2; + + if (x2 - x1 < w) { + /* need to cover full width */ + continue; + } + if (y1 <= y && y < y2) { + hit = 1; + break; + } + } + if (hit) { + if (! rescan) { + tile_has_diff[n] = 0; + } else { + *tile_count += tile_has_diff[n]; + } + return 1; /* skip */ + } + } + return 0; /* do not skip */ +} + +/* + * scan_display() wants to know if this changed tile can be skipped due + * to blackout regions (we do an actual compare to find the changed region). + */ +int blackout_line_cmpskip(int n, int x, int y, char *dst, char *src, + int w, int pixelsize) { + + int i, x1, y1, x2, y2, b, hit = 0; + int beg = -1, end = -1; + + if (tile_blackout[n].cover == 0) { + return 0; /* 0 means do not skip it. */ + } else if (tile_blackout[n].cover == 2) { + return 1; /* 1 means skip it. */ + } + + /* tile has partial coverage: */ + + for (i=0; i < w * pixelsize; i++) { + if (*(dst+i) != *(src+i)) { + beg = i/pixelsize; /* beginning difference */ + break; + } + } + for (i = w * pixelsize - 1; i >= 0; i--) { + if (*(dst+i) != *(src+i)) { + end = i/pixelsize; /* ending difference */ + break; + } + } + if (beg < 0 || end < 0) { + /* problem finding range... */ + return 0; + } + + /* loop over blackout rectangles: */ + for (b=0; b < tile_blackout[n].count; b++) { + + /* y in full display space: */ + y1 = tile_blackout[n].bo[b].y1; + y2 = tile_blackout[n].bo[b].y2; + + /* x relative to tile origin: */ + x1 = tile_blackout[n].bo[b].x1 - x; + x2 = tile_blackout[n].bo[b].x2 - x; + + if (y1 > y || y >= y2) { + continue; + } + if (x1 <= beg && end <= x2) { + hit = 1; + break; + } + } + if (hit) { + return 1; + } else { + return 0; + } +} + +/* * Loop over 1-pixel tall horizontal scanlines looking for changes. * Record the changes in tile_has_diff[]. Scanlines in the loop are * equally spaced along y by NSCAN pixels, but have a slightly random @@ -3727,7 +4202,7 @@ int scan_display(int ystart, int rescan) { int pixelsize = bpp >> 3; int x, y, w, n; int tile_count = 0; - int whole_line = 1, nodiffs; + int whole_line = 1, nodiffs = 0; y = ystart; @@ -3748,7 +4223,6 @@ int scan_display(int ystart, int rescan) { src = scanline->data; dst = screen->frameBuffer + y * bytes_per_line; - nodiffs = 0; if (whole_line && ! memcmp(dst, src, bytes_per_line)) { /* no changes anywhere in scan line */ nodiffs = 1; @@ -3762,6 +4236,14 @@ int scan_display(int ystart, int rescan) { while (x < dpy_x) { n = (x/tile_x) + (y/tile_y) * ntiles_x; + if (blackouts) { + if (blackout_line_skip(n, x, y, rescan, + &tile_count)) { + x += NSCAN; + continue; + } + } + if (rescan) { if (nodiffs || tile_has_diff[n]) { tile_count += tile_has_diff[n]; @@ -3784,8 +4266,18 @@ int scan_display(int ystart, int rescan) { if (memcmp(dst, src, w * pixelsize)) { /* found a difference, record it: */ - tile_has_diff[n] = 1; - tile_count++; + if (! blackouts) { + tile_has_diff[n] = 1; + tile_count++; + } else { + if (blackout_line_cmpskip(n, x, y, + dst, src, w, pixelsize)) { + tile_has_diff[n] = 0; + } else { + tile_has_diff[n] = 1; + tile_count++; + } + } } x += NSCAN; } @@ -3844,7 +4336,7 @@ void scan_for_updates() { if (tile_count > frac1 * ntiles) { /* * many tiles have changed, so try a rescan (since it should - * be short compared to the many upcoming copy_tile() calls) + * be short compared to the many upcoming copy_tiles() calls) */ /* this check is done to skip the extra scan_display() call */ @@ -3867,7 +4359,7 @@ void scan_for_updates() { /* * At some number of changed tiles it is better to just * copy the full screen at once. I.e. time = c1 + m * r1 - * where m is number of tiles, r1 is the copy_tile() + * where m is number of tiles, r1 is the copy_tiles() * time, and c1 is the scan_display() time: for some m * it crosses the full screen update time. * @@ -3939,6 +4431,19 @@ void scan_for_updates() { pointer(-1, 0, 0, NULL); } + if (blackouts) { + /* ignore any diffs in completely covered tiles */ + int x, y, n; + for (y=0; y < ntiles_y; y++) { + for (x=0; x < ntiles_x; x++) { + n = x + y * ntiles_x; + if (tile_blackout[n].cover == 2) { + tile_has_diff[n] = 0; + } + } + } + } + if (use_hints) { hint_updates(); /* use krfb/x0rfbserver hints algorithm */ } else { @@ -4231,11 +4736,17 @@ void print_help() { " for more control build libvncserver with libwrap support.\n" "-localhost Same as -allow 127.0.0.1\n" "-inetd Launched by inetd(1): stdio instead of listening socket.\n" +"\n" "-noshm Do not use the MIT-SHM extension for the polling.\n" " remote displays can be polled this way: be careful\n" " this can use large amounts of network bandwidth.\n" "-flipbyteorder Sometimes needed if remotely polled host has different\n" " endianness. Ignored unless -noshm is set.\n" +"-blackout string Black out rectangles on the screen. string is a comma\n" +" separated list of WxH+X+Y type geometries for each rect.\n" +"-xinerama If your screen is composed of multiple monitors glued\n" +" together via XINERAMA, and that screen is non-rectangular\n" +" this option will try to guess the areas to black out.\n" "\n" "-q Be quiet by printing less informational output.\n" "-bg Go into the background after screen setup.\n" @@ -4248,8 +4759,9 @@ void print_help() { "-modtweak Handle AltGr/Shift modifiers for differing languages\n" " between client and host (default %s).\n" "-nomodtweak Send the keysym directly to the X server.\n" -"-remap file Read keysym remappings from file. Format is one pair\n" -" of keysyms per line (can be string or the hex value).\n" +"-remap string Read keysym remappings from file \"string\". Format is\n" +" one pair of keysyms per line (can be name or hex value).\n" +" \"string\" can also be of form: key1:key2,key3:key4...\n" "-nobell Do not watch for XBell events.\n" "-nofb Ignore framebuffer: only process keyboard and pointer.\n" "-nosel Do not manage exchange of X selection/cutbuffer.\n" @@ -4260,6 +4772,9 @@ void print_help() { "-mouse Draw a 2nd cursor at the current X pointer position.\n" "-mouseX As -mouse, but also draw an X on root background.\n" "-X Shorthand for -mouseX -nocursor.\n" +"-xwarppointer Move the pointer with XWarpPointer instead of XTEST\n" +" (try as a workaround if pointer behaves poorly, e.g.\n" +" on touchscreens or other non-standard setups).\n" "-buttonmap str String to remap mouse buttons. Format: IJK-LMN, this\n" " maps buttons I -> L, etc., e.g. -buttonmap 13-31\n" "-nodragging Do not update the display during mouse dragging events.\n" @@ -4270,7 +4785,6 @@ void print_help() { "-input_skip n For the old pointer handling when non-threaded: try to\n" " read n user input events before scanning display. n < 0\n" " means to act as though there is always user input.\n" -"-old_copytile Do not use the new copy_tiles() framebuffer mechanism.\n" "-debug_pointer Print debugging output for every pointer event.\n" "-debug_keyboard Print debugging output for every keyboard event.\n" "\n" @@ -4287,6 +4801,8 @@ void print_help() { "\n" "-fs f If the fraction of changed tiles in a poll is greater\n" " than f, the whole screen is updated (default %.2f).\n" +"-onetile Do not use the new copy_tiles() framebuffer mechanism,\n" +" just use 1 shm tile for polling. Same as -old_copytile.\n" "-gaps n Heuristic to fill in gaps in rows or cols of n or less\n" " tiles. Used to improve text paging (default %d).\n" "-grow n Heuristic to grow islands of changed tiles n or wider\n" @@ -4366,7 +4882,7 @@ int main(int argc, char** argv) { XImage *fb; int i, op, ev, er, maj, min; char *use_dpy = NULL; - char *visual_str = NULL; + char *arg, *visual_str = NULL; int pw_loc = -1; int dt = 0; int bg = 0; @@ -4375,12 +4891,18 @@ int main(int argc, char** argv) { /* used to pass args we do not know about to rfbGetScreen(): */ int argc2 = 1; char *argv2[100]; - argv2[0] = argv[0]; + argv2[0] = strdup(argv[0]); for (i=1; i < argc; i++) { - if (!strcmp(argv[i], "-display")) { + /* quick-n-dirty --option handling. */ + arg = argv[i]; + if (strstr(arg, "--") == arg) { + arg++; + } + + if (!strcmp(arg, "-display")) { use_dpy = argv[++i]; - } else if (!strcmp(argv[i], "-id")) { + } else if (!strcmp(arg, "-id")) { if (sscanf(argv[++i], "0x%x", &subwin) != 1) { if (sscanf(argv[i], "%d", &subwin) != 1) { fprintf(stderr, "bad -id arg: %s\n", @@ -4388,126 +4910,133 @@ int main(int argc, char** argv) { exit(1); } } - } else if (!strcmp(argv[i], "-visual")) { + } else if (!strcmp(arg, "-visual")) { visual_str = argv[++i]; - } else if (!strcmp(argv[i], "-flashcmap")) { + } else if (!strcmp(arg, "-flashcmap")) { flash_cmap = 1; - } else if (!strcmp(argv[i], "-notruecolor")) { + } else if (!strcmp(arg, "-notruecolor")) { force_indexed_color = 1; - } else if (!strcmp(argv[i], "-viewonly")) { + } else if (!strcmp(arg, "-viewonly")) { view_only = 1; - } else if (!strcmp(argv[i], "-shared")) { + } else if (!strcmp(arg, "-shared")) { shared = 1; - } else if (!strcmp(argv[i], "-allow")) { + } else if (!strcmp(arg, "-allow")) { allow_list = argv[++i]; - } else if (!strcmp(argv[i], "-localhost")) { + } else if (!strcmp(arg, "-localhost")) { allow_list = "127.0.0.1"; - } else if (!strcmp(argv[i], "-many") - || !strcmp(argv[i], "-forever")) { + } else if (!strcmp(arg, "-many") + || !strcmp(arg, "-forever")) { connect_once = 0; - } else if (!strcmp(argv[i], "-connect")) { + } else if (!strcmp(arg, "-connect")) { i++; - if (strchr(argv[i], '/')) { - client_connect_file = argv[i]; + if (strchr(arg, '/')) { + client_connect_file = arg; } else { - client_connect = strdup(argv[i]); + client_connect = strdup(arg); } - } else if (!strcmp(argv[i], "-vncconnect")) { + } else if (!strcmp(arg, "-vncconnect")) { vnc_connect = 1; - } else if (!strcmp(argv[i], "-inetd")) { + } else if (!strcmp(arg, "-inetd")) { inetd = 1; - } else if (!strcmp(argv[i], "-noshm")) { + } else if (!strcmp(arg, "-noshm")) { using_shm = 0; - } else if (!strcmp(argv[i], "-flipbyteorder")) { + } else if (!strcmp(arg, "-flipbyteorder")) { flip_byte_order = 1; - } else if (!strcmp(argv[i], "-modtweak")) { + } else if (!strcmp(arg, "-modtweak")) { use_modifier_tweak = 1; - } else if (!strcmp(argv[i], "-nomodtweak")) { + } else if (!strcmp(arg, "-nomodtweak")) { use_modifier_tweak = 0; - } else if (!strcmp(argv[i], "-remap")) { + } else if (!strcmp(arg, "-remap")) { remap_file = argv[++i]; - } else if (!strcmp(argv[i], "-nobell")) { + } else if (!strcmp(arg, "-blackout")) { + blackout_string = argv[++i]; + } else if (!strcmp(arg, "-xinerama")) { + xinerama = 1; + } else if (!strcmp(arg, "-nobell")) { watch_bell = 0; - } else if (!strcmp(argv[i], "-nofb")) { + } else if (!strcmp(arg, "-nofb")) { nofb = 1; - } else if (!strcmp(argv[i], "-nosel")) { + } else if (!strcmp(arg, "-nosel")) { watch_selection = 0; - } else if (!strcmp(argv[i], "-noprimary")) { + } else if (!strcmp(arg, "-noprimary")) { watch_primary = 0; - } else if (!strcmp(argv[i], "-nocursor")) { + } else if (!strcmp(arg, "-nocursor")) { local_cursor = 0; - } else if (!strcmp(argv[i], "-mouse")) { + } else if (!strcmp(arg, "-mouse")) { show_mouse = 1; - } else if (!strcmp(argv[i], "-mouseX")) { + } else if (!strcmp(arg, "-mouseX")) { show_mouse = 1; show_root_cursor = 1; - } else if (!strcmp(argv[i], "-X")) { + } else if (!strcmp(arg, "-X")) { show_mouse = 1; show_root_cursor = 1; local_cursor = 0; - } else if (!strcmp(argv[i], "-buttonmap")) { + } else if (!strcmp(arg, "-xwarppointer")) { + use_xwarppointer = 1; + } else if (!strcmp(arg, "-buttonmap")) { pointer_remap = argv[++i]; - } else if (!strcmp(argv[i], "-nodragging")) { + } else if (!strcmp(arg, "-nodragging")) { show_dragging = 0; - } else if (!strcmp(argv[i], "-input_skip")) { + } else if (!strcmp(arg, "-input_skip")) { ui_skip = atoi(argv[++i]); if (! ui_skip) ui_skip = 1; - } else if (!strcmp(argv[i], "-old_pointer")) { + } else if (!strcmp(arg, "-old_pointer")) { old_pointer = 1; - } else if (!strcmp(argv[i], "-old_copytile")) { + } else if (!strcmp(arg, "-onetile") + || !strcmp(arg, "-old_copytile")) { single_copytile = 1; - } else if (!strcmp(argv[i], "-debug_pointer")) { + } else if (!strcmp(arg, "-debug_pointer")) { debug_pointer++; - } else if (!strcmp(argv[i], "-debug_keyboard")) { + } else if (!strcmp(arg, "-debug_keyboard")) { debug_keyboard++; - } else if (!strcmp(argv[i], "-defer")) { + } else if (!strcmp(arg, "-defer")) { defer_update = atoi(argv[++i]); - } else if (!strcmp(argv[i], "-wait")) { + } else if (!strcmp(arg, "-wait")) { waitms = atoi(argv[++i]); got_waitms = 1; - } else if (!strcmp(argv[i], "-nap")) { + } else if (!strcmp(arg, "-nap")) { take_naps = 1; #ifdef LIBVNCSERVER_HAVE_LIBPTHREAD - } else if (!strcmp(argv[i], "-threads")) { + } else if (!strcmp(arg, "-threads")) { use_threads = 1; - } else if (!strcmp(argv[i], "-nothreads")) { + } else if (!strcmp(arg, "-nothreads")) { use_threads = 0; #endif - } else if (!strcmp(argv[i], "-fs")) { + } else if (!strcmp(arg, "-fs")) { fs_frac = atof(argv[++i]); - } else if (!strcmp(argv[i], "-gaps")) { + } else if (!strcmp(arg, "-gaps")) { gaps_fill = atoi(argv[++i]); - } else if (!strcmp(argv[i], "-grow")) { + } else if (!strcmp(arg, "-grow")) { grow_fill = atoi(argv[++i]); - } else if (!strcmp(argv[i], "-fuzz")) { + } else if (!strcmp(arg, "-fuzz")) { tile_fuzz = atoi(argv[++i]); - } else if (!strcmp(argv[i], "-hints")) { + } else if (!strcmp(arg, "-hints")) { use_hints = 1; - } else if (!strcmp(argv[i], "-nohints")) { + } else if (!strcmp(arg, "-nohints")) { use_hints = 0; - } else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "-help") - || !strcmp(argv[i], "-?")) { + } else if (!strcmp(arg, "-h") || !strcmp(arg, "-help") + || !strcmp(arg, "-?")) { print_help(); - } else if (!strcmp(argv[i], "-q")) { + } else if (!strcmp(arg, "-q") || !strcmp(arg, "-quiet")) { quiet = 1; #ifdef LIBVNCSERVER_HAVE_SETSID - } else if (!strcmp(argv[i], "-bg")) { + } else if (!strcmp(arg, "-bg") || !strcmp(arg, "-background")) { bg = 1; #endif } else { - if (!strcmp(argv[i], "-desktop")) { + if (!strcmp(arg, "-desktop")) { dt = 1; } - if (!strcmp(argv[i], "-passwd")) { + if (!strcmp(arg, "-passwd")) { pw_loc = i; } /* otherwise copy it for use below. */ if (! quiet && i != pw_loc && i != pw_loc+1) { fprintf(stderr, "passing arg to libvncserver: %s\n", - argv[i]); + arg); } if (argc2 < 100) { - argv2[argc2++] = strdup(argv[i]); + argv2[argc2++] = strdup(arg); } } } @@ -4548,6 +5077,7 @@ int main(int argc, char** argv) { } if (! quiet) { + fprintf(stderr, "\n"); fprintf(stderr, "viewonly: %d\n", view_only); fprintf(stderr, "shared: %d\n", shared); fprintf(stderr, "allow: %s\n", allow_list ? allow_list @@ -4594,9 +5124,9 @@ int main(int argc, char** argv) { use_dpy ? use_dpy:"null"); exit(1); } else if (use_dpy) { - if (! quiet) fprintf(stderr, "Using display %s\n", use_dpy); + if (! quiet) fprintf(stderr, "Using X display %s\n", use_dpy); } else { - if (! quiet) fprintf(stderr, "Using default display.\n"); + if (! quiet) fprintf(stderr, "Using default X display.\n"); } /* check for XTEST */ @@ -4727,7 +5257,7 @@ int main(int argc, char** argv) { fb = XGetImage(dpy, window, 0, 0, dpy_x, dpy_y, AllPlanes, ZPixmap); if (! quiet) { - fprintf(stderr, "Read initial data from display into" + fprintf(stderr, "Read initial data from X display into" " framebuffer.\n"); } } @@ -4751,10 +5281,25 @@ int main(int argc, char** argv) { initialize_tiles(); + /* rectangular blackout regions */ + if (blackout_string != NULL) { + initialize_blackout(blackout_string); + } + if (xinerama) { + initialize_xinerama(); + } + if (blackouts) { + blackout_tiles(); + } + initialize_shm(); /* also creates XImages when using_shm = 0 */ set_signals(); + if (blackouts) { /* blackout fb as needed. */ + copy_screen(); + } + if (use_modifier_tweak) { initialize_modtweak(); } @@ -4767,7 +5312,7 @@ int main(int argc, char** argv) { fflush(stdout); } if (! quiet) { - fprintf(stderr, "screen setup finished.\n"); + rfbLog("screen setup finished.\n"); } #if defined(LIBVNCSERVER_HAVE_FORK) && defined(LIBVNCSERVER_HAVE_SETSID) |