diff options
Diffstat (limited to 'x11vnc/x11vnc.c')
-rw-r--r-- | x11vnc/x11vnc.c | 2010 |
1 files changed, 1297 insertions, 713 deletions
diff --git a/x11vnc/x11vnc.c b/x11vnc/x11vnc.c index 436d5a1..a21cb6b 100644 --- a/x11vnc/x11vnc.c +++ b/x11vnc/x11vnc.c @@ -65,14 +65,10 @@ * cursor, but we cannot extract what the cursor is... * * Nevertheless, the current *position* of the remote X mouse pointer - * is shown with the -mouse option. Further, if -mouseX or -X is used, a + * is shown with the -cursor option. Further, if -cursorX or -X is used, a * trick is done to at least show the root window cursor vs non-root cursor. * (perhaps some heuristic can be done to further distinguish cases...) * - * With -mouse there are occasionally some repainting errors involving - * big areas near the cursor. The mouse painting is in general a bit - * ragged and not very pleasant. - * * Windows using visuals other than the default X visual may have * their colors messed up. When using 8bpp indexed color, the colormap * is attempted to be followed, but may become out of date. Use the @@ -82,7 +78,7 @@ * On Sun hardware we try to work around this with -overlay. * * Feature -id <windowid> can be picky: it can crash for things like the - * window not sufficiently mapped into server memory, use of -mouse, etc. + * window not sufficiently mapped into server memory, use of -cursor, etc. * SaveUnders menus, popups, etc will not be seen. * * Occasionally, a few tile updates can be missed leaving a patch of @@ -90,7 +86,8 @@ * which is no longer the default. * * There seems to be a serious bug with simultaneous clients when - * threaded, currently the only workaround in this case is -nothreads. + * threaded, currently the only workaround in this case is -nothreads + * (which is now the default). * */ @@ -108,17 +105,46 @@ /* -- x11vnc.h -- */ +/* + * At some point beyond 0.7pre remove these two definitions since we + * have them set in configure (for all users of this x11vnc.c file). + * Then move them to the comment below. + */ +#define LIBVNCSERVER_HAVE_XSHM +#define LIBVNCSERVER_HAVE_XTEST + +/* + * If you are building in an older libvncserver tree with this newer + * x11vnc.c file you may need to uncomment some of these lines since + * your older libvncserver configure is not setting them. + * + * For LIBVNCSERVER_HAVE_LIBXINERAMA you may also need to add to the + * linking -lXinerama (by setting LDFLAGS=-lXinerama before configure). + * +#define LIBVNCSERVER_HAVE_LIBXINERAMA +#define LIBVNCSERVER_HAVE_XFIXES +#define LIBVNCSERVER_HAVE_XDAMAGE + * + */ + #include <unistd.h> #include <signal.h> #include <sys/utsname.h> -#include <sys/ipc.h> -#include <sys/shm.h> #include <X11/Xlib.h> #include <X11/Xutil.h> + +#ifdef LIBVNCSERVER_HAVE_XSHM +#include <sys/ipc.h> +#include <sys/shm.h> #include <X11/extensions/XShm.h> +#endif + +#ifdef LIBVNCSERVER_HAVE_XTEST #include <X11/extensions/XTest.h> +#endif + #include <X11/keysym.h> #include <X11/Xatom.h> @@ -147,22 +173,12 @@ #include <X11/extensions/transovl.h> #endif -/* - * Temporary kludge: to run with -xinerama define the following - * macro (uncomment) 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, but it won't be in users' build trees for a while, - * so one can do it manually here. - -#define LIBVNCSERVER_HAVE_LIBXINERAMA - */ #ifdef LIBVNCSERVER_HAVE_LIBXINERAMA #include <X11/extensions/Xinerama.h> #endif /* date +'lastmod: %Y-%m-%d' */ -char lastmod[] = "0.6.3pre lastmod: 2004-08-15"; +char lastmod[] = "0.6.3pre lastmod: 2004-08-29"; /* X display info */ @@ -182,31 +198,41 @@ XImage *scanline; XImage *fullscreen; XImage **tile_row; /* for all possible row runs */ +#ifndef LIBVNCSERVER_HAVE_XSHM +/* + * for simplicity, define these since we'll never use them + * under using_shm = 0. + */ +typedef struct { + int shmid; char *shmaddr; Bool readOnly; +} XShmSegmentInfo; +#endif + /* corresponding shm structures */ XShmSegmentInfo scanline_shm; XShmSegmentInfo fullscreen_shm; XShmSegmentInfo *tile_row_shm; /* for all possible row runs */ -/* rfb info */ +/* rfb screen info */ rfbScreenInfoPtr screen; -rfbCursorPtr cursor; char *main_fb; /* our copy of the X11 fb */ char *rfb_fb; /* same as main_fb unless transformation */ +int rfb_bytes_per_line; int main_bytes_per_line; unsigned long main_red_mask, main_green_mask, main_blue_mask; unsigned short main_red_max, main_green_max, main_blue_max; unsigned short main_red_shift, main_green_shift, main_blue_shift; -int rfb_bytes_per_line; -/* scaling info */ -int scaling = 0; -int scaling_noblend = 0; -int scaling_nomult4 = 0; -int scaling_pad = 0; -int scaling_interpolate = 0; +/* scaling parameters */ double scale_fac = 1.0; -int scaled_x = 0, scaled_y = 0; -int scale_numer = 0, scale_denom = 0; +int scaling = 0; +int scaling_noblend = 0; /* no blending option (very course) */ +int scaling_nomult4 = 0; /* do not require width = n * 4 */ +int scaling_pad = 0; /* pad out scaled sizes to fit denominator */ +int scaling_interpolate = 0; /* use interpolation scheme when shrinking */ +int scaled_x = 0, scaled_y = 0; /* dimensions of scaled display */ +int scale_numer = 0, scale_denom = 0; /* n/m */ + /* size of the basic tile unit that is polled for changes: */ int tile_x = 32; @@ -216,25 +242,6 @@ int ntiles, ntiles_x, ntiles_y; /* arrays that indicate changed or checked tiles. */ unsigned char *tile_has_diff, *tile_tried; -/* blacked-out region (-blackout, -xinerama) */ -typedef struct bout { - int x1, y1, x2, y2; -} blackout_t; -#define BO_MAX 16 -typedef struct tbout { - blackout_t bo[BO_MAX]; /* hardwired max rectangles. */ - int cover; - int count; -} tile_blackout_t; - -#define BLACKR_MAX 100 -blackout_t blackr[BLACKR_MAX]; /* hardwired max blackouts */ -int blackouts = 0; -tile_blackout_t *tile_blackout; - -/* saved cursor */ -int cur_save_x, cur_save_y, cur_save_w, cur_save_h, cur_saved = 0; - /* times of recent events */ time_t last_event, last_input, last_client = 0; @@ -254,7 +261,6 @@ int shut_down = 0; char vnc_connect_str[VNC_CONNECT_MAX+1]; Atom vnc_connect_prop = None; - /* function prototypes (see filename comment above) */ int all_clients_initialized(void); @@ -286,7 +292,14 @@ void initialize_xinerama(void); void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client); -void myXTestFakeKeyEvent(Display*, KeyCode, Bool, time_t); +void XTestFakeKeyEvent_wr(Display*, KeyCode, Bool, unsigned long); +void XTestFakeButtonEvent_wr(Display*, unsigned int, Bool, unsigned long); +void XTestFakeMotionEvent_wr(Display*, int, int, int, unsigned long); +int XTestGrabControl_wr(Display*, Bool); +Bool XTestCompareCurrentCursorWithWindow_wr(Display*, Window); +Bool XTestCompareCursorWithWindow_wr(Display*, Window, Cursor); +Bool XTestQueryExtension_wr(Display*, int*, int*, int*, int*); +void XTestDiscard_wr(Display*); typedef struct hint { /* location x, y, height, and width of a change-rectangle */ @@ -299,22 +312,24 @@ void mark_rect_as_modified(int x1, int y1, int x2, int y2, int force); enum rfbNewClientAction new_client(rfbClientPtr client); void nofb_hook(rfbClientPtr client); void pointer(int mask, int x, int y, rfbClientPtr client); +void cursor_position(int, int); void read_vnc_connect_prop(void); -void redraw_mouse(void); -void restore_mouse_patch(void); void rfbPE(rfbScreenInfoPtr, long); +void rfbCFD(rfbScreenInfoPtr, long); void scan_for_updates(void); void set_colormap(void); void set_offset(void); void set_visual(char *vstring); +void set_cursor(int, int, int); +int get_which_cursor(void); void shm_clean(XShmSegmentInfo *, XImage *); void shm_delete(XShmSegmentInfo *); -void update_mouse(void); -void watch_bell_event(void); -void watch_xevents(void); +void check_x11_pointer(void); +void check_bell_event(void); +void check_xevents(void); void xcut_receive(char *text, int len, rfbClientPtr client); @@ -347,13 +362,14 @@ int xinerama = 0; /* -xinerama */ char *client_connect = NULL; /* strings for -connect option */ char *client_connect_file = NULL; -int vnc_connect = 0; /* -vncconnect option */ +int vnc_connect = 1; /* -vncconnect option */ -int local_cursor = 1; /* whether the viewer draws a local cursor */ -int cursor_pos = 1; /* cursor position updates -cursorpos */ -int show_mouse = 0; /* display a cursor for the real mouse */ +int show_cursor = 1; /* show cursor shapes */ +int show_multiple_cursors = 0; /* show X when on root background, etc */ +char *multiple_cursors_mode = "default"; +int cursor_pos_updates = 1; /* cursor position updates -cursorpos */ +int cursor_shape_updates = 1; /* cursor shape updates -nocursorshape */ 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 no_autorepeat = 0; /* turn off autorepeat with clients */ int watch_bell = 1; /* watch for the bell using XKEYBOARD */ @@ -391,8 +407,16 @@ int sigpipe = 1; /* 0=skip, 1=ignore, 2=exit */ /* visual stuff for -visual override or -overlay */ VisualID visual_id = (VisualID) 0; int visual_depth = 0; + +/* for -overlay mode on Solaris. X server draws cursor correctly. */ int overlay = 0; -int overlay_mouse = 0; +int overlay_cursor = 1; + +#ifdef LIBVNCSERVER_HAVE_XTEST +int xtest_present = 1; +#else +int xtest_present = 0; +#endif /* tile heuristics: */ double fs_frac = 0.75; /* threshold tile fraction to do fullscreen updates. */ @@ -467,6 +491,18 @@ int nfix(int i, int n) { return i; } +void lowercase(char *str) { + char *p; + if (str == NULL) { + return; + } + p = str; + while (*p != '\0') { + *p = tolower(*p); + p++; + } +} + /* * Kludge to interpose image gets and limit to a subset rectangle of * the rootwin. This is the -sid option trying to work around invisible @@ -481,7 +517,9 @@ int rootshift = 0; y += off_y; \ } -/* Wrappers for Image related X calls */ +/* + * Wrappers for Image related X calls + */ Status XShmGetImage_wr(Display *disp, Drawable d, XImage *image, int x, int y, unsigned long mask) { @@ -489,7 +527,47 @@ Status XShmGetImage_wr(Display *disp, Drawable d, XImage *image, int x, int y, /* The Solaris overlay stuff is all non-shm (using_shm = 0) */ +#ifdef LIBVNCSERVER_HAVE_XSHM return XShmGetImage(disp, d, image, x, y, mask); +#else + return (Status) 0; +#endif +} + +XImage *XShmCreateImage_wr(Display* disp, Visual* vis, unsigned int depth, + int format, char* data, XShmSegmentInfo* shminfo, unsigned int width, + unsigned int height) { + +#ifdef LIBVNCSERVER_HAVE_XSHM + return XShmCreateImage(disp, vis, depth, format, data, shminfo, + width, height); +#else + return (XImage *) 0; +#endif +} + +Status XShmAttach_wr(Display *disp, XShmSegmentInfo *shminfo) { +#ifdef LIBVNCSERVER_HAVE_XSHM + return XShmAttach(disp, shminfo); +#else + return (Status) 0; +#endif +} + +Status XShmDetach_wr(Display *disp, XShmSegmentInfo *shminfo) { +#ifdef LIBVNCSERVER_HAVE_XSHM + return XShmDetach(disp, shminfo); +#else + return (Status) 0; +#endif +} + +Bool XShmQueryExtension_wr(Display *disp) { +#ifdef LIBVNCSERVER_HAVE_XSHM + return XShmQueryExtension(disp); +#else + return False; +#endif } XImage *XGetSubImage_wr(Display *disp, Drawable d, int x, int y, @@ -502,7 +580,7 @@ XImage *XGetSubImage_wr(Display *disp, Drawable d, int x, int y, if (overlay && dest_x == 0 && dest_y == 0) { size_t size = dest_image->height * dest_image->bytes_per_line; XImage *xi = XReadScreen(disp, d, x, y, width, height, - (Bool) overlay_mouse); + (Bool) overlay_cursor); /* * There is extra overhead from memcpy and free... @@ -529,7 +607,7 @@ XImage *XGetImage_wr(Display *disp, Drawable d, int x, int y, #ifdef SOLARIS if (overlay) { return XReadScreen(disp, d, x, y, width, height, - (Bool) overlay_mouse); + (Bool) overlay_cursor); } #endif return XGetImage(disp, d, x, y, width, height, plane_mask, format); @@ -563,6 +641,100 @@ XImage *XCreateImage_wr(Display *disp, Visual *visual, unsigned int depth, width, height, bitmap_pad, bytes_per_line); } +/* + * wrappers for XTestFakeKeyEvent, etc.. + */ +void XTestFakeKeyEvent_wr(Display* dpy, KeyCode key, Bool down, + unsigned long delay) { + if (debug_keyboard) { + rfbLog("XTestFakeKeyEvent(dpy, keycode=0x%x \"%s\", %s)\n", + key, XKeysymToString(XKeycodeToKeysym(dpy, key, 0)), + down ? "down":"up"); + } + if (! xtest_present) { + return; + } + if (down) { + last_keyboard_input = -key; + } else { + last_keyboard_input = key; + } +#ifdef LIBVNCSERVER_HAVE_XTEST + XTestFakeKeyEvent(dpy, key, down, delay); +#endif +} + +void XTestFakeButtonEvent_wr(Display* dpy, unsigned int button, Bool is_press, + unsigned long delay) { + if (! xtest_present) { + return; + } +#ifdef LIBVNCSERVER_HAVE_XTEST + XTestFakeButtonEvent(dpy, button, is_press, delay); +#endif +} + +void XTestFakeMotionEvent_wr(Display* dpy, int screen, int x, int y, + unsigned long delay) { + if (! xtest_present) { + return; + } +#ifdef LIBVNCSERVER_HAVE_XTEST + XTestFakeMotionEvent(dpy, screen, x, y, delay); +#endif +} + +Bool XTestCompareCurrentCursorWithWindow_wr(Display* dpy, Window w) { + if (! xtest_present) { + return False; + } +#ifdef LIBVNCSERVER_HAVE_XTEST + return XTestCompareCurrentCursorWithWindow(dpy, w); +#else + return False; +#endif +} + +Bool XTestCompareCursorWithWindow_wr(Display* dpy, Window w, Cursor cursor) { + if (! xtest_present) { + return False; + } +#ifdef LIBVNCSERVER_HAVE_XTEST + return XTestCompareCursorWithWindow(dpy, w, cursor); +#else + return False; +#endif +} + +int XTestGrabControl_wr(Display* dpy, Bool impervious) { + if (! xtest_present) { + return 0; + } +#ifdef LIBVNCSERVER_HAVE_XTEST + return XTestGrabControl(dpy, impervious); +#else + return 0; +#endif +} + +Bool XTestQueryExtension_wr(Display *dpy, int *ev, int *er, int *maj, + int *min) { +#ifdef LIBVNCSERVER_HAVE_XTEST + return XTestQueryExtension(dpy, ev, er, maj, min); +#else + return False; +#endif +} + +void XTestDiscard_wr(Display *dpy) { + if (! xtest_present) { + return; + } +#ifdef LIBVNCSERVER_HAVE_XTEST + XTestDiscard(dpy); +#endif +} + /* -- cleanup.c -- */ /* @@ -603,7 +775,7 @@ void clean_up_exit (int ret) { autorepeat(1); } X_LOCK; - XTestDiscard(dpy); + XTestDiscard_wr(dpy); XCloseDisplay(dpy); X_UNLOCK; @@ -847,54 +1019,6 @@ static int run_user_command(char *cmd, rfbClientPtr client) { return rc; } -/* - * Kludge for -norepeat option: we turn off keystroke autorepeat in - * the X server when clients are connected. This may annoy people at - * the physical display. We do this because 'key down' and 'key up' - * user input events may be separated by 100s of ms due to screen fb - * processing or link latency, thereby inducing the X server to apply - * autorepeat when it should not. Since the *client* is likely doing - * keystroke autorepeating as well, it kind of makes sense to shut it - * off if no one is at the physical display... - */ -void autorepeat(int restore) { - XKeyboardState kstate; - XKeyboardControl kctrl; - static int save_auto_repeat = -1; - - if (restore) { - if (save_auto_repeat < 0) { - return; /* nothing to restore */ - } - X_LOCK; - /* read state and skip restore if equal (e.g. no clients) */ - XGetKeyboardControl(dpy, &kstate); - if (kstate.global_auto_repeat == save_auto_repeat) { - X_UNLOCK; - return; - } - - kctrl.auto_repeat_mode = save_auto_repeat; - XChangeKeyboardControl(dpy, KBAutoRepeatMode, &kctrl); - XFlush(dpy); - X_UNLOCK; - - rfbLog("Restored X server key autorepeat to: %d\n", - save_auto_repeat); - } else { - X_LOCK; - XGetKeyboardControl(dpy, &kstate); - save_auto_repeat = kstate.global_auto_repeat; - - kctrl.auto_repeat_mode = AutoRepeatModeOff; - XChangeKeyboardControl(dpy, KBAutoRepeatMode, &kctrl); - XFlush(dpy); - X_UNLOCK; - - rfbLog("Disabled X server key autorepeat. (you can run the\n"); - rfbLog("command: 'xset r on' to force it back on)\n"); - } -} /* * callback for when a client disconnects @@ -1907,7 +2031,7 @@ void clear_modifiers(int init) { rfbLog("clear_modifiers: up: %-10s (0x%x) " "keycode=0x%x\n", keystrs[i], keysym, keycode); } - myXTestFakeKeyEvent(dpy, keycode, False, CurrentTime); + XTestFakeKeyEvent_wr(dpy, keycode, False, CurrentTime); } XFlush(dpy); } @@ -1925,12 +2049,61 @@ void clear_keys(void) { if (keystate[k]) { KeyCode keycode = (KeyCode) k; rfbLog("clear_keys: keycode=%d\n", keycode); - myXTestFakeKeyEvent(dpy, keycode, False, CurrentTime); + XTestFakeKeyEvent_wr(dpy, keycode, False, CurrentTime); } } XFlush(dpy); } +/* + * Kludge for -norepeat option: we turn off keystroke autorepeat in + * the X server when clients are connected. This may annoy people at + * the physical display. We do this because 'key down' and 'key up' + * user input events may be separated by 100s of ms due to screen fb + * processing or link latency, thereby inducing the X server to apply + * autorepeat when it should not. Since the *client* is likely doing + * keystroke autorepeating as well, it kind of makes sense to shut it + * off if no one is at the physical display... + */ +void autorepeat(int restore) { + XKeyboardState kstate; + XKeyboardControl kctrl; + static int save_auto_repeat = -1; + + if (restore) { + if (save_auto_repeat < 0) { + return; /* nothing to restore */ + } + X_LOCK; + /* read state and skip restore if equal (e.g. no clients) */ + XGetKeyboardControl(dpy, &kstate); + if (kstate.global_auto_repeat == save_auto_repeat) { + X_UNLOCK; + return; + } + + kctrl.auto_repeat_mode = save_auto_repeat; + XChangeKeyboardControl(dpy, KBAutoRepeatMode, &kctrl); + XFlush(dpy); + X_UNLOCK; + + rfbLog("Restored X server key autorepeat to: %d\n", + save_auto_repeat); + } else { + X_LOCK; + XGetKeyboardControl(dpy, &kstate); + save_auto_repeat = kstate.global_auto_repeat; + + kctrl.auto_repeat_mode = AutoRepeatModeOff; + XChangeKeyboardControl(dpy, KBAutoRepeatMode, &kctrl); + XFlush(dpy); + X_UNLOCK; + + rfbLog("Disabled X server key autorepeat. (you can run the\n"); + rfbLog("command: 'xset r on' to force it back on)\n"); + } +} + static KeySym added_keysyms[0x100]; int add_keysym(KeySym keysym) { @@ -2148,25 +2321,6 @@ void initialize_remap(char *infile) { } /* - * debugging wrapper for XTestFakeKeyEvent() - */ -void myXTestFakeKeyEvent(Display* dpy, KeyCode key, Bool down, - time_t cur_time) { - if (debug_keyboard) { - rfbLog("XTestFakeKeyEvent(dpy, keycode=0x%x \"%s\", %s)\n", - key, XKeysymToString(XKeycodeToKeysym(dpy, key, 0)), - down ? "down":"up"); - } - if (down) { - last_keyboard_input = -key; - } else { - last_keyboard_input = key; - } - XTestFakeKeyEvent(dpy, key, down, cur_time); -} - - -/* * preliminary support for using the Xkb (XKEYBOARD) extension for handling * user input. inelegant, slow, and incomplete currently... but initial * tests show it is useful for some setups. @@ -2847,7 +3001,7 @@ static void xkb_tweak_keyboard(rfbBool down, rfbKeySym keysym, "inadvertent Multi_key from Shift " "(doing %03d up now)\n", shift_is_down); } - myXTestFakeKeyEvent(dpy, shift_is_down, False, + XTestFakeKeyEvent_wr(dpy, shift_is_down, False, CurrentTime); } else { involves_multi_key = 0; @@ -2859,7 +3013,7 @@ static void xkb_tweak_keyboard(rfbBool down, rfbKeySym keysym, if (sentmods[i] == 0) continue; dn = (Bool) needmods[i]; if (dn) continue; - myXTestFakeKeyEvent(dpy, sentmods[i], dn, CurrentTime); + XTestFakeKeyEvent_wr(dpy, sentmods[i], dn, CurrentTime); } for (j=0; j<8; j++) { /* next, do the Mod downs */ @@ -2867,7 +3021,7 @@ static void xkb_tweak_keyboard(rfbBool down, rfbKeySym keysym, if (sentmods[i] == 0) continue; dn = (Bool) needmods[i]; if (!dn) continue; - myXTestFakeKeyEvent(dpy, sentmods[i], dn, CurrentTime); + XTestFakeKeyEvent_wr(dpy, sentmods[i], dn, CurrentTime); } if (involves_multi_key) { @@ -2879,14 +3033,14 @@ static void xkb_tweak_keyboard(rfbBool down, rfbKeySym keysym, "inadvertent Multi_key from Shift " "(doing %03d down now)\n", shift_is_down); } - myXTestFakeKeyEvent(dpy, shift_is_down, True, + XTestFakeKeyEvent_wr(dpy, shift_is_down, True, CurrentTime); } /* * With the above modifier work done, send the actual keycode: */ - myXTestFakeKeyEvent(dpy, Kc_f, (Bool) down, CurrentTime); + XTestFakeKeyEvent_wr(dpy, Kc_f, (Bool) down, CurrentTime); /* * Now undo the modifier work: @@ -2897,7 +3051,8 @@ static void xkb_tweak_keyboard(rfbBool down, rfbKeySym keysym, if (sentmods[i] == 0) continue; dn = (Bool) needmods[i]; if (!dn) continue; - myXTestFakeKeyEvent(dpy, sentmods[i], !dn, CurrentTime); + XTestFakeKeyEvent_wr(dpy, sentmods[i], !dn, + CurrentTime); } for (j=7; j>=0; j--) { /* finally reverse the Mod ups we did */ @@ -2905,12 +3060,13 @@ static void xkb_tweak_keyboard(rfbBool down, rfbKeySym keysym, if (sentmods[i] == 0) continue; dn = (Bool) needmods[i]; if (dn) continue; - myXTestFakeKeyEvent(dpy, sentmods[i], !dn, CurrentTime); + XTestFakeKeyEvent_wr(dpy, sentmods[i], !dn, + CurrentTime); } } else { /* for up case, hopefully just need to pop it up: */ - myXTestFakeKeyEvent(dpy, Kc_f, (Bool) down, CurrentTime); + XTestFakeKeyEvent_wr(dpy, Kc_f, (Bool) down, CurrentTime); } X_UNLOCK; } @@ -3059,20 +3215,20 @@ static void tweak_mod(signed char mod, rfbBool down) { X_LOCK; if (is_shift && mod != 1) { if (mod_state & LEFTSHIFT) { - myXTestFakeKeyEvent(dpy, left_shift_code, !dn, CurrentTime); + XTestFakeKeyEvent_wr(dpy, left_shift_code, !dn, CurrentTime); } if (mod_state & RIGHTSHIFT) { - myXTestFakeKeyEvent(dpy, right_shift_code, !dn, CurrentTime); + XTestFakeKeyEvent_wr(dpy, right_shift_code, !dn, CurrentTime); } } if ( ! is_shift && mod == 1 ) { - myXTestFakeKeyEvent(dpy, left_shift_code, dn, CurrentTime); + XTestFakeKeyEvent_wr(dpy, left_shift_code, dn, CurrentTime); } if ( altgr && (mod_state & ALTGR) && mod != 2 ) { - myXTestFakeKeyEvent(dpy, altgr, !dn, CurrentTime); + XTestFakeKeyEvent_wr(dpy, altgr, !dn, CurrentTime); } if ( altgr && ! (mod_state & ALTGR) && mod == 2 ) { - myXTestFakeKeyEvent(dpy, altgr, dn, CurrentTime); + XTestFakeKeyEvent_wr(dpy, altgr, dn, CurrentTime); } X_UNLOCK; if (debug_keyboard) { @@ -3141,7 +3297,7 @@ static void modifier_tweak_keyboard(rfbBool down, rfbKeySym keysym, } if ( k != NoSymbol ) { X_LOCK; - myXTestFakeKeyEvent(dpy, k, (Bool) down, CurrentTime); + XTestFakeKeyEvent_wr(dpy, k, (Bool) down, CurrentTime); X_UNLOCK; } @@ -3219,8 +3375,8 @@ void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) { return; } X_LOCK; - XTestFakeButtonEvent(dpy, button, True, CurrentTime); - XTestFakeButtonEvent(dpy, button, False, CurrentTime); + XTestFakeButtonEvent_wr(dpy, button, True, CurrentTime); + XTestFakeButtonEvent_wr(dpy, button, False, CurrentTime); XFlush(dpy); X_UNLOCK; return; @@ -3252,7 +3408,7 @@ void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) { } if ( k != NoSymbol ) { - myXTestFakeKeyEvent(dpy, k, (Bool) down, CurrentTime); + XTestFakeKeyEvent_wr(dpy, k, (Bool) down, CurrentTime); XFlush(dpy); } @@ -3261,7 +3417,7 @@ void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) { /* -- pointer.c -- */ /* - * pointer event handling routines. + * pointer event (motion and button click) handling routines. */ typedef struct ptrremap { KeySym keysym; @@ -3325,7 +3481,9 @@ static void buttonparse(int from, char **s) { if (sscanf(t, "0x%x", &i) == 1) { ksym = (KeySym) i; /* hex value */ } else { + X_LOCK; ksym = XStringToKeysym(t); /* string value */ + X_UNLOCK; } if (ksym == NoSymbol) { /* see if Button<N> "keysym" was used: */ @@ -3348,6 +3506,7 @@ static void buttonparse(int from, char **s) { /* * XXX may not work with -modtweak or -xkb */ + X_LOCK; kcode = XKeysymToKeycode(dpy, ksym); pointer_map[from][n].keysym = ksym; @@ -3374,6 +3533,7 @@ static void buttonparse(int from, char **s) { XKeysymToString(ksym), ksym, kcode, pointer_map[from][n].down, pointer_map[from][n].up); + X_UNLOCK; } t = strtok(NULL, "+"); n++; @@ -3442,6 +3602,7 @@ void initialize_pointer_map(char *pointer_remap) { X_LOCK; num_buttons = XGetPointerMapping(dpy, map, MAX_BUTTONS); + X_UNLOCK; if (num_buttons < 0) { num_buttons = 0; @@ -3500,30 +3661,37 @@ void initialize_pointer_map(char *pointer_remap) { } } } - X_UNLOCK; } /* * Send a pointer event to the X server. */ -static void update_pointer(int mask, int x, int y) { +static void update_x11_pointer(int mask, int x, int y) { int i, mb; X_LOCK; - - if (! use_xwarppointer) { - XTestFakeMotionEvent(dpy, scr, x+off_x, y+off_y, CurrentTime); + if (use_xwarppointer) { + XWarpPointer(dpy, None, window, 0, 0, 0, 0, x+off_x, y+off_y); } else { - XWarpPointer(dpy, None, window, 0, 0, 0, 0, x+off_x, y+off_y); + XTestFakeMotionEvent_wr(dpy, scr, x+off_x, y+off_y, + CurrentTime); } + X_UNLOCK; 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 */ + set_cursor(x, y, get_which_cursor()); + last_event = last_input = time(0); + X_LOCK; + /* look for buttons that have be clicked or released: */ for (i=0; i < MAX_BUTTONS; i++) { - /* look for buttons that have be clicked or released: */ if ( (button_mask & (1<<i)) != (mask & (1<<i)) ) { int k; if (debug_pointer) { @@ -3552,7 +3720,7 @@ static void update_pointer(int mask, int x, int y) { " %s (event %d)\n", mb, bmask ? "down" : "up", k+1); } - XTestFakeButtonEvent(dpy, mb, (mask & (1<<i)) + XTestFakeButtonEvent_wr(dpy, mb, (mask & (1<<i)) ? True : False, CurrentTime); } else { /* sent keysym up or down */ @@ -3574,11 +3742,11 @@ static void update_pointer(int mask, int x, int y) { dpy, key, 0))); } if (down) { - myXTestFakeKeyEvent(dpy, key, True, + XTestFakeKeyEvent_wr(dpy, key, True, CurrentTime); } if (up) { - myXTestFakeKeyEvent(dpy, key, False, + XTestFakeKeyEvent_wr(dpy, key, False, CurrentTime); } } @@ -3605,24 +3773,38 @@ static void update_pointer(int mask, int x, int y) { /* * Actual callback from libvncserver when it gets a pointer event. + * This may queue pointer events rather than sending them immediately + * to the X server. (see update_x11_pointer()) */ void pointer(int mask, int x, int y, rfbClientPtr client) { if (debug_pointer && mask >= 0) { - rfbLog("pointer(mask: 0x%x, x:%4d, y:%4d)\n", mask, x, y); + static int show_motion = -1; + if (show_motion == -1) { + if (getenv("X11VNC_DB_NOMOTION")) { + show_motion = 0; + } else { + show_motion = 1; + } + } + if (show_motion) { + rfbLog("pointer(mask: 0x%x, x:%4d, y:%4d)\n", + mask, x, y); + } } if (view_only) { return; } - if (client->viewOnly) { + if (client && client->viewOnly) { return; } if (scaling) { + /* map from rfb size to X11 size: */ x = ((double) x / scaled_x) * dpy_x; - if (x >= dpy_x) x = dpy_x - 1; + x = nfix(x, dpy_x); y = ((double) y / scaled_y) * dpy_y; - if (y >= dpy_y) y = dpy_y - 1; + y = nfix(y, dpy_y); } if (mask >= 0) { @@ -3698,7 +3880,7 @@ void pointer(int mask, int x, int y, rfbClientPtr client) { if (debug_pointer) { rfbLog("pointer(): sending event %d\n", i+1); } - update_pointer(ev[i][0], ev[i][1], ev[i][2]); + update_x11_pointer(ev[i][0], ev[i][1], ev[i][2]); } if (nevents && dt > maxwait) { X_LOCK; @@ -3720,7 +3902,7 @@ void pointer(int mask, int x, int y, rfbClientPtr client) { } /* update the X display with the event: */ - update_pointer(mask, x, y); + update_x11_pointer(mask, x, y); } /* -- xkb_bell.c -- */ @@ -3782,7 +3964,7 @@ void initialize_watch_bell(void) { * We call this periodically to process any bell events that have * taken place. */ -void watch_bell_event(void) { +void check_bell_event(void) { XEvent xev; XkbAnyEvent *xkb_ev; int got_bell = 0; @@ -3804,7 +3986,7 @@ void watch_bell_event(void) { if (got_bell) { if (! all_clients_initialized()) { - rfbLog("watch_bell_event: not sending bell: " + rfbLog("check_bell_event: not sending bell: " "uninitialized clients\n"); } else { rfbSendBell(screen); @@ -3812,7 +3994,7 @@ void watch_bell_event(void) { } } #else -void watch_bell_event(void) {} +void check_bell_event(void) {} #endif /* -- selection.c -- */ @@ -4060,7 +4242,7 @@ static void selection_send(XEvent *ev) { * This routine is periodically called to check for selection related * and other X11 events and respond to them as needed. */ -void watch_xevents(void) { +void check_xevents(void) { XEvent xev; static int first = 1, sent_some_sel = 0; static time_t last_request = 0; @@ -4245,10 +4427,11 @@ typedef struct cursor_info { int wx, wy; /* size of cursor */ int sx, sy; /* shift to its centering point */ int reverse; /* swap black and white */ + rfbCursorPtr rfb; } cursor_info_t; /* main cursor */ -static char* cur_data = +static char* curs_arrow_data = " " " x " " xx " @@ -4268,7 +4451,7 @@ static char* cur_data = " " " "; -static char* cur_mask = +static char* curs_arrow_mask = "xx " "xxx " "xxxx " @@ -4287,16 +4470,13 @@ static char* cur_mask = " xx " " " " "; -#define CUR_SIZE 18 -#define CUR_DATA cur_data -#define CUR_MASK cur_mask -static cursor_info_t cur0 = {NULL, NULL, CUR_SIZE, CUR_SIZE, 0, 0, 0}; +static cursor_info_t cur_arrow = {NULL, NULL, 18, 18, 0, 0, 0, NULL}; /* * It turns out we can at least detect mouse is on the root window so - * show it (under -mouseX or -X) with this familiar cursor... + * show it (under -cursorX or -X) with this familiar cursor... */ -static char* root_data = +static char* curs_root_data = " " " " " xxx xxx " @@ -4316,7 +4496,7 @@ static char* root_data = " " " "; -static char* root_mask = +static char* curs_root_mask = " " " xxxx xxxx " " xxxxx xxxxx " @@ -4335,75 +4515,179 @@ static char* root_mask = " xxxxx xxxxx " " xxxx xxxx " " "; -static cursor_info_t cur1 = {NULL, NULL, 18, 18, 8, 8, 1}; +static cursor_info_t cur_root = {NULL, NULL, 18, 18, 8, 8, 1, NULL}; + +static char* curs_fleur_data = +" " +" xx " +" xxxx " +" xxxxxx " +" xx " +" x xx x " +" xx xx xx " +" xxxxxxxxxxxxxx " +" xxxxxxxxxxxxxx " +" xx xx xx " +" x xx x " +" xx " +" xxxxxx " +" xxxx " +" xx " +" "; + +static char* curs_fleur_mask = +" xxxx " +" xxxxx " +" xxxxxx " +" xxxxxxxx " +" x xxxxxx x " +" xxx xxxx xxx " +"xxxxxxxxxxxxxxxx" +"xxxxxxxxxxxxxxxx" +"xxxxxxxxxxxxxxxx" +"xxxxxxxxxxxxxxxx" +" xxx xxxx xxx " +" x xxxxxx x " +" xxxxxxxx " +" xxxxxx " +" xxxx " +" xxxx "; + +static cursor_info_t cur_fleur = {NULL, NULL, 16, 16, 8, 8, 1, NULL}; + +static char* curs_plus_data = +" " +" xx " +" xx " +" xx " +" xx " +" xxxxxxxxxx " +" xxxxxxxxxx " +" xx " +" xx " +" xx " +" xx " +" "; + +static char* curs_plus_mask = +" xxxx " +" xxxx " +" xxxx " +" xxxx " +"xxxxxxxxxxxx" +"xxxxxxxxxxxx" +"xxxxxxxxxxxx" +"xxxxxxxxxxxx" +" xxxx " +" xxxx " +" xxxx " +" xxxx "; +static cursor_info_t cur_plus = {NULL, NULL, 12, 12, 5, 6, 1, NULL}; + +static char* curs_xterm_data = +" " +" xxx xxx " +" xxx " +" x " +" x " +" x " +" x " +" x " +" x " +" x " +" x " +" x " +" x " +" xxx " +" xxx xxx " +" "; + +static char* curs_xterm_mask = +" xxxx xxxx " +" xxxxxxxxx " +" xxxxxxxxx " +" xxxxx " +" xxx " +" xxx " +" xxx " +" xxx " +" xxx " +" xxx " +" xxx " +" xxx " +" xxxxx " +" xxxxxxxxx " +" xxxxxxxxx " +" xxxx xxxx "; +static cursor_info_t cur_xterm = {NULL, NULL, 16, 16, 8, 8, 1, NULL}; + +enum cursor_names { + CURS_ARROW = 0, + CURS_ROOT, + CURS_WM, + CURS_TERM +}; -static cursor_info_t *cursors[2]; +static cursor_info_t *cursors[10]; static void setup_cursors(void) { /* TODO clean this up if we ever do more cursors... */ + rfbCursorPtr rfb_curs; + int i, n = 0; - cur0.data = cur_data; - cur0.mask = cur_mask; + cur_arrow.data = curs_arrow_data; + cur_arrow.mask = curs_arrow_mask; - cur1.data = root_data; - cur1.mask = root_mask; + cur_root.data = curs_root_data; + cur_root.mask = curs_root_mask; - cursors[0] = &cur0; - cursors[1] = &cur1; -} + cur_plus.data = curs_plus_data; + cur_plus.mask = curs_plus_mask; -/* - * data and functions for -mouse real pointer position updates - */ -static char cur_save[(4 * CUR_SIZE * CUR_SIZE)]; -static int cur_save_cx, cur_save_cy, cur_save_which; - -/* - * save current cursor info and the patch of non-cursor data it covers - */ -static void save_mouse_patch(int x, int y, int w, int h, int cx, int cy, - int which) { - int pixelsize = bpp >> 3; - char *fbp = main_fb; - int ly, i = 0; + cur_fleur.data = curs_fleur_data; + cur_fleur.mask = curs_fleur_mask; - for (ly = y; ly < y + h; ly++) { - memcpy(cur_save+i, fbp + ly * main_bytes_per_line - + x * pixelsize, w * pixelsize); + cur_xterm.data = curs_xterm_data; + cur_xterm.mask = curs_xterm_mask; - i += w * pixelsize; - } - cur_save_x = x; /* patch geometry */ - cur_save_y = y; - cur_save_w = w; - cur_save_h = h; + cursors[CURS_ARROW] = &cur_arrow; n++; + cursors[CURS_ROOT] = &cur_root; n++; + cursors[CURS_WM] = &cur_fleur; n++; + cursors[CURS_TERM] = &cur_xterm; n++; - cur_save_which = which; /* which cursor and its position */ - cur_save_cx = cx; - cur_save_cy = cy; + for (i=0; i<n; i++) { + cursor_info_t *ci = cursors[i]; - cur_saved = 1; -} + ci->data = strdup(ci->data); + ci->mask = strdup(ci->mask); -/* - * put the non-cursor patch back in the rfb fb - */ -void restore_mouse_patch(void) { - int pixelsize = bpp >> 3; - char *fbp = main_fb; - int ly, i = 0; + rfb_curs = rfbMakeXCursor(ci->wx, ci->wy, ci->data, ci->mask); - if (! cur_saved) { - return; /* not yet saved */ - } + if (ci->reverse) { + rfb_curs->foreRed = 0x0000; + rfb_curs->foreGreen = 0x0000; + rfb_curs->foreBlue = 0x0000; + rfb_curs->backRed = 0xffff; + rfb_curs->backGreen = 0xffff; + rfb_curs->backBlue = 0xffff; + } + rfb_curs->xhot = ci->sx; + rfb_curs->yhot = ci->sy; + rfb_curs->cleanup = FALSE; + rfb_curs->cleanupSource = FALSE; + rfb_curs->cleanupMask = FALSE; + rfb_curs->cleanupRichSource = FALSE; - for (ly = cur_save_y; ly < cur_save_y + cur_save_h; ly++) { - memcpy(fbp + ly * main_bytes_per_line + cur_save_x * pixelsize, - cur_save+i, cur_save_w * pixelsize); - i += cur_save_w * pixelsize; + ci->rfb = rfb_curs; } } +typedef struct win_str_info { + char *wm_name; + char *res_name; + char *res_class; +} win_str_info_t; + /* * Descends window tree at pointer until the window cursor matches the current * cursor. So far only used to detect if mouse is on root background or not. @@ -4412,95 +4696,306 @@ void restore_mouse_patch(void) { * It seems impossible to do, but if the actual cursor could ever be * determined we might want to hash that info on window ID or something... */ -static int tree_descend_cursor(void) { +void tree_descend_cursor(int *depth, Window *w, win_str_info_t *winfo) { Window r, c; - int rx, ry, wx, wy; + int i, rx, ry, wx, wy; unsigned int mask; - int descend = 0, tries = 0, maxtries = 1; + Window wins[10]; + int descend, maxtries = 10; + char *name, a; + static XClassHint *classhint = NULL; + int nm_info = 1; + XErrorHandler old_handler; X_LOCK; + + a = multiple_cursors_mode[0]; + if (a == 'd' || a == 'X') { + nm_info = 0; + } + + *(winfo->wm_name) = '\0'; + *(winfo->res_name) = '\0'; + *(winfo->res_class) = '\0'; + + + /* some times a window can go away before we get to it */ + trapped_xerror = 0; + old_handler = XSetErrorHandler(trap_xerror); + c = window; + descend = -1; + while (c) { - if (++tries > maxtries) { - descend = maxtries; + wins[++descend] = c; + if (descend >= maxtries - 1) { break; } - if ( XTestCompareCurrentCursorWithWindow(dpy, c) ) { + if ( XTestCompareCurrentCursorWithWindow_wr(dpy, c) ) { break; } XQueryPointer(dpy, c, &r, &c, &rx, &ry, &wx, &wy, &mask); - descend++; } + + if (nm_info) { + int got_wm_name = 0, got_res_name = 0, got_res_class = 0; + + if (! classhint) { + classhint = XAllocClassHint(); + } + + for (i = descend; i >=0; i--) { + c = wins[i]; + if (! c) { + continue; + } + + if (! got_wm_name && XFetchName(dpy, c, &name)) { + if (name) { + if (*name != '\0') { + strcpy(winfo->wm_name, name); + got_wm_name = 1; + } + XFree(name); + } + } + if (classhint && (! got_res_name || ! got_res_class)) { + if (XGetClassHint(dpy, c, classhint)) { + char *p; + p = classhint->res_name; + if (p) { + if (*p != '\0' && ! got_res_name) { + strcpy(winfo->res_name, p); + got_res_name = 1; + } + XFree(p); + classhint->res_name = NULL; + } + p = classhint->res_class; + if (p) { + if (*p != '\0' && ! got_res_class) { + strcpy(winfo->res_class, p); + got_res_class = 1; + } + XFree(p); + classhint->res_class = NULL; + } + } + } + } + } + + XSetErrorHandler(old_handler); + trapped_xerror = 0; + X_UNLOCK; - return descend; + + *depth = descend; + *w = wins[descend]; +} + +int get_which_cursor(void) { + int which = CURS_ARROW; + + if (show_multiple_cursors) { + int depth; + static win_str_info_t winfo; + static int first = 1, depth_cutoff = -1; + Window win; + XErrorHandler old_handler; + int mode = 0; + char a = multiple_cursors_mode[0]; + + if (a == 'd') { + mode = 0; + } else if (a == 'X') { + mode = 1; + } else { + mode = 2; + } + + if (depth_cutoff < 0) { + int din; + if (sscanf(multiple_cursors_mode, "X%d", &din) == 1) { + depth_cutoff = din; + } else { + depth_cutoff = 0; + } + } + + if (first) { + winfo.wm_name = (char *) malloc(1024); + winfo.res_name = (char *) malloc(1024); + winfo.res_class = (char *) malloc(1024); + } + first = 0; + + tree_descend_cursor(&depth, &win, &winfo); + + if (depth <= depth_cutoff) { + which = CURS_ROOT; + } else if (mode >= 2) { + int which0 = which; + + if (win) { + int ratio = 10, x, y; + unsigned int w, h, bw, d; + Window r; + + trapped_xerror = 0; + old_handler = XSetErrorHandler(trap_xerror); + if (XGetGeometry(dpy, win, &r, &x, &y, &w, &h, + &bw, &d)) { + if (w > ratio * h || h > ratio * w) { + which = CURS_WM; + } + } + XSetErrorHandler(old_handler); + trapped_xerror = 0; + } + if (which == which0) { + lowercase(winfo.res_name); + lowercase(winfo.res_class); + if (strstr(winfo.res_name, "term")) { + which = CURS_TERM; + } else if (strstr(winfo.res_class, "term")) { + which = CURS_TERM; + } + } + } + } + return which; } /* - * This is for mouse patch drawing under -xinerama or -blackout + * Some utilities for marking the little cursor patch region as + * modified, etc. */ -static void blackout_nearby_tiles(int x, int y, int dt) { - int sx, sy, n, b; - int tx = x/tile_x; - int ty = y/tile_y; - - if (! blackouts) { +void mark_cursor_patch_modified(rfbScreenInfoPtr s, int old) { + int curx, cury, xhot, yhot, w, h; + int x1, x2, y1, y2; + + if (! s->cursor) { return; } - if (dt < 1) { - dt = 1; + + if (old) { + /* use oldCursor pos */ + curx = s->oldCursorX; + cury = s->oldCursorY; + } else { + curx = s->cursorX; + cury = s->cursorY; } - /* loop over a range of tiles, blacking out as needed */ + + xhot = s->cursor->xhot; + yhot = s->cursor->yhot; + w = s->cursor->width; + h = s->cursor->height; + + x1 = curx - xhot; + x2 = x1 + w; + x1 = nfix(x1, s->width); + x2 = nfix(x2, s->width); + + y1 = cury - yhot; + y2 = y1 + h; + y1 = nfix(y1, s->height); + y2 = nfix(y2, s->height); + + rfbMarkRectAsModified(s, x1, y1, x1+x2, y1+y2); +} - for (sx = tx - dt; sx <= tx + dt; sx++) { - if (sx < 0 || sx >= tile_x) { - continue; +void set_cursor_was_changed(rfbScreenInfoPtr s) { + rfbClientIteratorPtr iter; + rfbClientPtr cl; + + iter = rfbGetClientIterator(s); + while( (cl = rfbClientIteratorNext(iter)) ) { + cl->cursorWasChanged = TRUE; + } + rfbReleaseClientIterator(iter); +} + +void set_cursor_was_moved(rfbScreenInfoPtr s) { + rfbClientIteratorPtr iter; + rfbClientPtr cl; + + iter = rfbGetClientIterator(s); + while( (cl = rfbClientIteratorNext(iter)) ) { + cl->cursorWasMoved = TRUE; + } + rfbReleaseClientIterator(iter); +} + +void unset_cursor_shape_updates(rfbScreenInfoPtr s) { + rfbClientIteratorPtr iter; + rfbClientPtr cl; + + iter = rfbGetClientIterator(s); + while( (cl = rfbClientIteratorNext(iter)) ) { + cl->enableCursorShapeUpdates = FALSE; + cl->enableCursorPosUpdates = FALSE; + cl->cursorWasChanged = FALSE; + } + rfbReleaseClientIterator(iter); +} + +int cursor_pos_updates_clients(rfbScreenInfoPtr s) { + rfbClientIteratorPtr iter; + rfbClientPtr cl; + int count = 0; + + iter = rfbGetClientIterator(s); + while( (cl = rfbClientIteratorNext(iter)) ) { + if (cl->enableCursorPosUpdates) { + count++; } - 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); - } + } + rfbReleaseClientIterator(iter); + return count; +} + +int cursor_shape_updates_clients(rfbScreenInfoPtr s) { + rfbClientIteratorPtr iter; + rfbClientPtr cl; + int count = 0; + + iter = rfbGetClientIterator(s); + while( (cl = rfbClientIteratorNext(iter)) ) { + if (cl->enableCursorShapeUpdates) { + count++; } } + rfbReleaseClientIterator(iter); + return count; } /* - * Send rfbCursorPosUpdates back to clients that understand them. This - * seems to be TightVNC specific. + * Record rfb cursor position screen->cursorX, etc (a la defaultPtrAddEvent()) + * Then set up for sending rfbCursorPosUpdates back + * to clients that understand them. This seems to be TightVNC specific. */ -static void cursor_pos_updates(int x, int y) { +void cursor_position(int x, int y) { rfbClientIteratorPtr iter; rfbClientPtr cl; - int cnt = 0; - int x_in = x, y_in = y; - - if (! cursor_pos) { - return; - } + int cnt = 0, nonCursorPosUpdates_clients = 0; + int x_old, y_old, x_in = x, y_in = y; /* x and y are current positions of X11 pointer on the X11 display */ if (scaling) { x = ((double) x / dpy_x) * scaled_x; - if (x >= scaled_x) x = scaled_x - 1; + x = nfix(x, scaled_x); y = ((double) y / dpy_y) * scaled_y; - if (y >= scaled_y) y = scaled_y - 1; + y = nfix(y, scaled_y); } if (x == screen->cursorX && y == screen->cursorY) { return; } + x_old = screen->oldCursorX; + y_old = screen->oldCursorY; if (screen->cursorIsDrawn) { rfbUndrawCursor(screen); @@ -4516,6 +5011,10 @@ static void cursor_pos_updates(int x, int y) { iter = rfbGetClientIterator(screen); while( (cl = rfbClientIteratorNext(iter)) ) { if (! cl->enableCursorPosUpdates) { + nonCursorPosUpdates_clients++; + continue; + } + if (! cursor_pos_updates) { continue; } if (cl == last_pointer_client) { @@ -4528,7 +5027,7 @@ static void cursor_pos_updates(int x, int y) { } else { /* an X11 app evidently warped the pointer */ if (debug_pointer) { - rfbLog("cursor_pos_updates: warp " + rfbLog("cursor_position: warp " "detected dx=%3d dy=%3d\n", cursor_x - x, cursor_y - y); } @@ -4542,190 +5041,76 @@ static void cursor_pos_updates(int x, int y) { } rfbReleaseClientIterator(iter); + if (nonCursorPosUpdates_clients && show_cursor) { + if (x_old != x || y_old != y) { + mark_cursor_patch_modified(screen, 0); + } + } + if (debug_pointer && cnt) { - rfbLog("cursor_pos_updates: sent position x=%3d y=%3d to %d" + rfbLog("cursor_position: sent position x=%3d y=%3d to %d" " clients\n", x, y, cnt); } } -/* - * draw one of the mouse cursors into the rfb fb - */ -static void draw_mouse(int x, int y, int which, int update) { - int px, py, i, offset; - int pixelsize = bpp >> 3; - char *fbp = main_fb; - char cdata, cmask; - char *data, *mask; - int white = 255, black = 0, shade; - int x0, x1, x2, y0, y1, y2; - int cur_x, cur_y, cur_sx, cur_sy, reverse; - static int first = 1; +void set_rfb_cursor(int which) { + int workaround = 1; /* if rfbSetCursor does not mark modified */ - if (! show_mouse) { + if (! show_cursor) { return; } - if (first) { - first = 0; - setup_cursors(); - } - - data = cursors[which]->data; /* pattern data */ - mask = cursors[which]->mask; - cur_x = cursors[which]->wx; /* widths */ - cur_y = cursors[which]->wy; - cur_sx = cursors[which]->sx; /* shifts */ - cur_sy = cursors[which]->sy; - reverse = cursors[which]->reverse; /* reverse video */ - - if (indexed_colour) { - black = BlackPixel(dpy, scr) % 256; - white = WhitePixel(dpy, scr) % 256; - } - if (reverse) { - int tmp = black; - black = white; - white = tmp; - } - - /* - * notation: - * x0, y0: position after cursor shift (no edge corrections) - * x1, y1: corrected for lower boundary < 0 - * x2, y2: position + cursor width and corrected for upper boundary - */ - - x0 = x1 = x - cur_sx; /* apply shift */ - if (x1 < 0) x1 = 0; - - y0 = y1 = y - cur_sy; - if (y1 < 0) y1 = 0; - - x2 = x0 + cur_x; /* apply width for upper endpoints */ - if (x2 >= dpy_x) x2 = dpy_x - 1; - - y2 = y0 + cur_y; - if (y2 >= dpy_y) y2 = dpy_y - 1; - - /* save the patch and info about which cursor will overwrite it */ - save_mouse_patch(x1, y1, x2 - x1, y2 - y1, x, y, which); - - for (py = 0; py < cur_y; py++) { - if (y0 + py < 0 || y0 + py >= dpy_y) { - continue; /* off screen */ - } - for (px = 0; px < cur_x; px++) { - if (x0 + px < 0 || x0 + px >= dpy_x){ - continue; /* off screen */ - } - cdata = data[px + py * cur_x]; - cmask = mask[px + py * cur_x]; - - if (cmask != 'x') { - continue; /* transparent */ - } + + if (workaround && screen->cursor) { + int all_are_cursor_pos = 1; + rfbClientIteratorPtr iter; + rfbClientPtr cl; - shade = white; - if (cdata != cmask) { - shade = black; + iter = rfbGetClientIterator(screen); + while( (cl = rfbClientIteratorNext(iter)) ) { + if (! cl->enableCursorPosUpdates) { + all_are_cursor_pos = 0; } - - offset = (y0 + py)*main_bytes_per_line + (x0 + px)*pixelsize; - - /* fill in each color byte in the fb */ - for (i=0; i < pixelsize; i++) { - fbp[offset+i] = (char) shade; + if (! cl->enableCursorShapeUpdates) { + all_are_cursor_pos = 0; } } - } + rfbReleaseClientIterator(iter); - 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 (! all_are_cursor_pos) { + mark_cursor_patch_modified(screen, 1); } } - if (update) { - /* x and y of the real (X server) mouse */ - static int mouse_x = -1; - static int mouse_y = -1; - - if (x != mouse_x || y != mouse_y) { - hint_t hint; - - hint.x = x1; - hint.y = y2; - hint.w = x2 - x1; - hint.h = y2 - y1; - - mark_hint(hint); - - if (mouse_x < 0) { - mouse_x = 0; - } - if (mouse_y < 0) { - mouse_y = 0; - } - - /* XXX this ignores change of shift... */ - x1 = mouse_x - cur_sx; - if (x1 < 0) x1 = 0; - - y1 = mouse_y - cur_sy; - if (y1 < 0) y1 = 0; - - x2 = mouse_x - cur_sx + cur_x; - if (x2 >= dpy_x) x2 = dpy_x - 1; - - y2 = mouse_y - cur_sy + cur_y; - if (y2 >= dpy_y) y2 = dpy_y - 1; + rfbSetCursor(screen, cursors[which]->rfb, FALSE); - hint.x = x1; - hint.y = y2; - hint.w = x2 - x1; - hint.h = y2 - y1; - - mark_hint(hint); + /* this is a 2nd workaround for rfbSetCursor() */ + if (screen->underCursorBuffer == NULL && + screen->underCursorBufferLen != 0) { + screen->underCursorBufferLen = 0; + } - mouse_x = x; - mouse_y = y; - } + if (workaround) { + set_cursor_was_changed(screen); } } -/* - * wrapper to redraw the mouse patch - */ -void redraw_mouse(void) { - if (cur_saved) { - /* redraw saved mouse from info (save_mouse_patch) */ - draw_mouse(cur_save_cx, cur_save_cy, cur_save_which, 0); +void set_cursor(int x, int y, int which) { + static int last = -1; + if (last < 0 || which != last) { + set_rfb_cursor(which); } + last = which; } /* - * routine called periodically to update the mouse aspects (drawn & - * cursorpos updates) + * routine called periodically to update cursor aspects, this catches + * warps and cursor shape changes. */ -void update_mouse(void) { +void check_x11_pointer(void) { Window root_w, child_w; rfbBool ret; - int root_x, root_y, win_x, win_y, which = 0; + int root_x, root_y, win_x, win_y; + int x, y; unsigned int mask; X_LOCK; @@ -4736,18 +5121,25 @@ void update_mouse(void) { if (! ret) { return; } - - if (show_root_cursor) { - int descend; - if ( (descend = tree_descend_cursor()) ) { - which = 0; - } else { - which = 1; + if (debug_pointer) { + static int last_x = -1, last_y = -1; + if (root_x != last_x || root_y != last_y) { + rfbLog("XQueryPointer: x:%4d, y:%4d)\n", + root_x, root_y); } + last_x = root_x; + last_y = root_y; } - cursor_pos_updates(root_x - off_x, root_y - off_y); - draw_mouse(root_x - off_x, root_y - off_y, which, 1); + /* offset subtracted since XQueryPointer relative to rootwin */ + x = root_x - off_x; + y = root_y - off_y; + + /* record the cursor position in the rfb screen */ + cursor_position(x, y); + + /* change the cursor shape if necessary */ + set_cursor(x, y, get_which_cursor()); } /* -- screen.c -- */ @@ -4945,7 +5337,7 @@ void set_visual(char *str) { /* * Presumably under -nofb the clients will never request the framebuffer. - * But we have gotten such a request... so let's just give them + * 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. @@ -5065,7 +5457,20 @@ void initialize_screen(int *argc, char **argv, XImage *fb) { for (i=1; i< *argc; i++) { rfbLog("\t[%d] %s\n", i, argv[i]); } - rfbLog("for a list of options run: x11vnc -help\n"); + rfbLog("For a list of options run: 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"); + clean_up_exit(1); } } @@ -5083,14 +5488,28 @@ void initialize_screen(int *argc, char **argv, XImage *fb) { if ( ! have_masks && screen->rfbServerFormat.bitsPerPixel == 8 && CellsOfScreen(ScreenOfDisplay(dpy,scr)) ) { /* indexed colour */ - if (!quiet) rfbLog("Using X display with 8bpp indexed color\n"); + 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"); + } + } indexed_colour = 1; set_colormap(); } else { /* general case ... */ if (! quiet) { - rfbLog("Using X display with %dbpp depth=%d true " - "color\n", fb->bits_per_pixel, fb->depth); + rfbLog("X display %s is %dbpp depth=%d true " + "color\n", DisplayString(dpy), fb->bits_per_pixel, + fb->depth); } /* convert masks to bit shifts and max # colors */ @@ -5130,6 +5549,15 @@ void initialize_screen(int *argc, char **argv, XImage *fb) { main_green_shift = screen->rfbServerFormat.greenShift; main_blue_shift = screen->rfbServerFormat.blueShift; } + 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"); + } /* nofb is for pointer/keyboard only handling. */ if (nofb) { @@ -5187,11 +5615,11 @@ void initialize_screen(int *argc, char **argv, XImage *fb) { screen->setXCutText = xcut_receive; } - if (local_cursor) { - cursor = rfbMakeXCursor(CUR_SIZE, CUR_SIZE, CUR_DATA, CUR_MASK); - screen->cursor = cursor; - } else { + setup_cursors(); + if (! show_cursor) { screen->cursor = NULL; + } else { + screen->cursor = cursors[0]->rfb; } rfbInitServer(screen); @@ -5220,6 +5648,22 @@ void initialize_screen(int *argc, char **argv, XImage *fb) { * routines related to xinerama and blacking out rectangles */ +/* blacked-out region (-blackout, -xinerama) */ +typedef struct bout { + int x1, y1, x2, y2; +} blackout_t; +#define BO_MAX 16 +typedef struct tbout { + blackout_t bo[BO_MAX]; /* hardwired max rectangles. */ + int cover; + int count; +} tile_blackout_t; + +#define BLACKR_MAX 100 +blackout_t blackr[BLACKR_MAX]; /* hardwired max blackouts */ +tile_blackout_t *tile_blackout; +int blackouts = 0; + /* * Take a comma separated list of geometries: WxH+X+Y and register them as * rectangles to black out from the screen. @@ -5292,10 +5736,6 @@ void blackout_tiles(void) { * 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++) { @@ -5604,6 +6044,20 @@ static void set_fs_factor(int max) { } } +char *flip_ximage_byte_order(XImage *xim) { + char *order; + if (xim->byte_order == LSBFirst) { + order = "MSBFirst"; + xim->byte_order = MSBFirst; + xim->bitmap_bit_order = MSBFirst; + } else { + order = "LSBFirst"; + xim->byte_order = LSBFirst; + xim->bitmap_bit_order = LSBFirst; + } + return order; +} + /* * set up an XShm image, or if not using shm just create the XImage. */ @@ -5611,6 +6065,7 @@ static int shm_create(XShmSegmentInfo *shm, XImage **ximg_ptr, int w, int h, char *name) { XImage *xim; + static int reported_flip = 0; shm->shmid = -1; shm->shmaddr = (char *) -1; @@ -5639,21 +6094,11 @@ static int shm_create(XShmSegmentInfo *shm, XImage **ximg_ptr, int w, int h, return 0; } if (flip_byte_order) { - static int reported = 0; - char *bo; - if (xim->byte_order == LSBFirst) { - bo = "MSBFirst"; - xim->byte_order = MSBFirst; - xim->bitmap_bit_order = MSBFirst; - } else { - bo = "LSBFirst"; - xim->byte_order = LSBFirst; - xim->bitmap_bit_order = LSBFirst; - } - if (! reported && ! quiet) { - rfbLog("changing XImage byte order" - " to %s\n", bo); - reported = 1; + char *order = flip_ximage_byte_order(xim); + if (! reported_flip && ! quiet) { + rfbLog("Changing XImage byte order" + " to %s\n", order); + reported_flip = 1; } } @@ -5661,7 +6106,7 @@ static int shm_create(XShmSegmentInfo *shm, XImage **ximg_ptr, int w, int h, return 1; } - xim = XShmCreateImage(dpy, default_visual, depth, ZPixmap, NULL, + xim = XShmCreateImage_wr(dpy, default_visual, depth, ZPixmap, NULL, shm, w, h); if (xim == NULL) { @@ -5672,6 +6117,7 @@ static int shm_create(XShmSegmentInfo *shm, XImage **ximg_ptr, int w, int h, *ximg_ptr = xim; +#ifdef LIBVNCSERVER_HAVE_XSHM shm->shmid = shmget(IPC_PRIVATE, xim->bytes_per_line * xim->height, IPC_CREAT | 0777); @@ -5704,7 +6150,7 @@ static int shm_create(XShmSegmentInfo *shm, XImage **ximg_ptr, int w, int h, shm->readOnly = False; - if (! XShmAttach(dpy, shm)) { + if (! XShmAttach_wr(dpy, shm)) { rfbErr("XShmAttach(%s) failed.\n", name); XDestroyImage(xim); *ximg_ptr = NULL; @@ -5718,6 +6164,7 @@ static int shm_create(XShmSegmentInfo *shm, XImage **ximg_ptr, int w, int h, X_UNLOCK; return 0; } +#endif X_UNLOCK; return 1; @@ -5727,21 +6174,24 @@ void shm_delete(XShmSegmentInfo *shm) { if (! using_shm) { return; } +#ifdef LIBVNCSERVER_HAVE_XSHM if (shm->shmaddr != (char *) -1) { shmdt(shm->shmaddr); } if (shm->shmid != -1) { shmctl(shm->shmid, IPC_RMID, 0); } +#endif } void shm_clean(XShmSegmentInfo *shm, XImage *xim) { - if (! using_shm || nofb) { + if (! using_shm) { return; } +#ifdef LIBVNCSERVER_HAVE_XSHM X_LOCK; if (shm->shmid != -1) { - XShmDetach(dpy, shm); + XShmDetach_wr(dpy, shm); } if (xim != NULL) { XDestroyImage(xim); @@ -5749,6 +6199,7 @@ void shm_clean(XShmSegmentInfo *shm, XImage *xim) { X_UNLOCK; shm_delete(shm); +#endif } void initialize_shm(void) { @@ -6423,7 +6874,7 @@ static void scale_and_mark_rect(int X1, int Y1, int X2, int Y2) { } void mark_rect_as_modified(int x1, int y1, int x2, int y2, int force) { - + if (rfb_fb == main_fb || force) { rfbMarkRectAsModified(screen, x1, y1, x2, y2); } else if (scaling) { @@ -6446,12 +6897,11 @@ void mark_hint(hint_t hint) { /* * 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 - * some cases it can be up to 2X. Even more on a SunRay where no - * graphics hardware is involved in the read. Generally, graphics - * devices are optimized for write, not read, so we are limited by - * the read bandwidth, sometimes only 5 MB/sec on otherwise fast - * hardware. + * due to contiguous memory access. Not a great speedup, but in some + * cases it can be up to 2X. Even more on a SunRay or ShadowFB where + * no graphics hardware is involved in the read. Generally, graphics + * devices are optimized for write, not read, so we are limited by the + * read bandwidth, sometimes only 5 MB/sec on otherwise fast hardware. */ static int *first_line = NULL, *last_line; static unsigned short *left_diff, *right_diff; @@ -6464,8 +6914,6 @@ static void copy_tiles(int tx, int ty, int nt) { int pixelsize = bpp >> 3; int first_min, last_max; - int restored_patch = 0; /* for show_mouse */ - char *src, *dst, *s_src, *s_dst, *m_src, *m_dst; char *h_src, *h_dst; if (! first_line) { @@ -6554,24 +7002,6 @@ static void copy_tiles(int tx, int ty, int nt) { } } - /* - * 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_row[nt]->data; dst = main_fb + y * main_bytes_per_line + x * pixelsize; @@ -6624,9 +7054,6 @@ static void copy_tiles(int tx, int ty, int nt) { for (t=1; t <= nt; t++) { tile_has_diff[n+(t-1)] = 0; } - if (restored_patch) { - redraw_mouse(); - } return; } else { /* @@ -6753,10 +7180,6 @@ static void copy_tiles(int tx, int ty, int nt) { s_dst += main_bytes_per_line; } - if (restored_patch) { - redraw_mouse(); - } - /* record all the info in the region array for this tile: */ for (t=1; t <= nt; t++) { int s = t - 1; @@ -7150,7 +7573,7 @@ static void nap_set(int tile_cnt) { nap_diff_count = 0; } - if (show_mouse) { + if (show_cursor) { /* kludge for the up to 4 tiles the mouse patch could occupy */ if ( tile_cnt > 4) { last_event = time(0); @@ -7169,7 +7592,7 @@ static void nap_sleep(int ms, int split) { for (i=0; i<split; i++) { usleep(ms * 1000 / split); if (! use_threads && i != split - 1) { - rfbProcessEvents(screen, -1); + rfbPE(screen, -1); } if (input != got_user_input) { break; @@ -7482,11 +7905,6 @@ void scan_for_updates(void) { } } - if (show_mouse && ! use_threads) { - /* single-thread is safe to do it here for all scanning */ - restore_mouse_patch(); - } - /* scan with the initial y to the jitter value from scanlines: */ scan_in_progress = 1; tile_count = scan_display(scanlines[scan_count], 0); @@ -7538,12 +7956,6 @@ void scan_for_updates(void) { if (fs_factor && tile_count > fs_frac * ntiles) { fb_copy_in_progress = 1; copy_screen(); - if (show_mouse || cursor_pos) { - if (show_mouse && ! use_threads) { - redraw_mouse(); - } - update_mouse(); - } fb_copy_in_progress = 0; if (use_threads && ! old_pointer) { pointer(-1, 0, 0, NULL); @@ -7616,13 +8028,6 @@ void scan_for_updates(void) { ping_clients(tile_diffs); } - /* Handle the remote mouse pointer */ - if (show_mouse || cursor_pos) { - if (show_mouse && ! use_threads) { - redraw_mouse(); - } - update_mouse(); - } nap_check(tile_diffs); } @@ -7698,7 +8103,11 @@ static int check_user_input(double dt, int *cnt) { * likely they have all be sent already. */ while (1) { - rfbCheckFds(screen, 1000); + if (show_multiple_cursors) { + rfbPE(screen, 1000); + } else { + rfbCFD(screen, 1000); + } XFlush(dpy); spin += dtime(&tm); @@ -7757,7 +8166,11 @@ static int check_user_input(double dt, int *cnt) { miss = 0; for (i=0; i<split; i++) { usleep(ms * 1000); - rfbCheckFds(screen, 1000); + if (show_multiple_cursors) { + rfbPE(screen, 1000); + } else { + rfbCFD(screen, 1000); + } spin += dtime(&tm); if (got_pointer_input > g) { XFlush(dpy); @@ -7803,10 +8216,17 @@ double dtime(double *t_old) { /* * utility wrapper to call rfbProcessEvents + * checks that we are not in threaded mode. */ -void rfbPE(rfbScreenInfoPtr scr, long us) { +void rfbPE(rfbScreenInfoPtr scr, long usec) { if (! use_threads) { - rfbProcessEvents(scr, us); + rfbProcessEvents(scr, usec); + } +} + +void rfbCFD(rfbScreenInfoPtr scr, long usec) { + if (! use_threads) { + rfbCheckFds(scr, usec); } } @@ -7828,7 +8248,10 @@ static void watch_loop(void) { got_keyboard_input = 0; if (! use_threads) { - rfbProcessEvents(screen, -1); + rfbPE(screen, -1); + if (! cursor_shape_updates) { + unset_cursor_shape_updates(screen); + } if (check_user_input(dt, &cnt)) { /* true means loop back for more input */ continue; @@ -7839,7 +8262,7 @@ static void watch_loop(void) { clean_up_exit(0); } - watch_xevents(); + check_xevents(); check_connect_inputs(); if (! screen->rfbClientHead) { /* waiting for a client */ @@ -7847,9 +8270,11 @@ static void watch_loop(void) { continue; } - if (nofb) { /* no framebuffer polling needed */ - if (cursor_pos) { - update_mouse(); + if (nofb) { + /* no framebuffer polling needed */ + if (cursor_pos_updates) { + /* -nofb -cursorpos usage is rare */ + check_x11_pointer(); } continue; } @@ -7859,7 +8284,7 @@ static void watch_loop(void) { * check for any bell events. * n.b. assumes -nofb folks do not want bell... */ - watch_bell_event(); + check_bell_event(); } if (! show_dragging && button_mask) { /* if any button is pressed do not update screen */ @@ -7874,6 +8299,7 @@ static void watch_loop(void) { rfbUndrawCursor(screen); scan_for_updates(); + check_x11_pointer(); dt = dtime(&tm); } @@ -7936,11 +8362,15 @@ static void print_help(void) { " setting the XAUTHORITY environment varirable to \"file\"\n" " before startup. See Xsecurity(7), xauth(1) man pages.\n" "\n" -"-id windowid Show the window corresponding to \"windowid\" not the\n" -" entire display. Warning: bugs! new toplevels missed!...\n" +"-id windowid Show the window corresponding to \"windowid\" not\n" +" the entire display. New windows like popup menus,\n" +" etc may not be seen, or will be clipped. x11vnc may\n" +" crash if the window changes size, is iconified, etc.\n" +" Use xwininfo(1) to get the window id. Primarily useful\n" +" for exporting very simple applications.\n" "-sid windowid As -id, but instead of using the window directly it\n" -" shifts a root view to it: shows saveUnders menus, etc,\n" -" although they will be clipped if they extend beyond\n" +" shifts a root view to it: this shows saveUnders menus,\n" +" etc, although they will be clipped if they extend beyond\n" " the window.\n" "-flashcmap In 8bpp indexed color, let the installed colormap flash\n" " as the pointer moves from window to window (slow).\n" @@ -7951,11 +8381,12 @@ static void print_help(void) { " packed with 8 for PseudoColor and 24 for TrueColor).\n" "\n" " Currently -overlay only works on Solaris (it uses\n" -" XReadScreen(3X11)). There are still some problems with\n" -" surrounding-region painting for popup menus (but not\n" -" for the popup menu itself); a workaround is to disable\n" -" SaveUnders (pass -su to Xsun). Amusingly, if -overlay\n" -" is used with -mouse, the mouse cursor shape is correct.\n" +" XReadScreen(3X11)). There is a problem with image\n" +" \"bleeding\" around transient popup menus (but not\n" +" for the menu itself): a workaround is to disable\n" +" SaveUnders by passing the \"-su\" argument to Xsun\n" +" (in /etc/dt/config/Xservers, say). Also note that,\n" +" the mouse cursor shape is exactly correct in this mode.\n" "\n" " Use -overlay as a workaround for situations like these:\n" " Some legacy applications require the default visual\n" @@ -7968,7 +8399,10 @@ static void print_help(void) { " due to the extra image transformations required.\n" " For optimal performance do not use -overlay, but rather\n" " configure the X server so that the default visual is\n" -" depth 24 TrueColor and have all apps use that visual.\n" +" depth 24 TrueColor and try to have all apps use that\n" +" visual (some apps have -use24 or -visual options).\n" +"-overlay_nocursor Sets -overlay, but does not try to draw the exact mouse\n" +" cursor shape using the overlay mechanism.\n" "-visual n Experimental option: probably does not do what you\n" " think. It simply *forces* the visual used for the\n" " framebuffer; this may be a bad thing... It is useful for\n" @@ -7978,9 +8412,10 @@ static void print_help(void) { " for a list. If the string ends in \":m\" for better\n" " or for worse the visual depth is forced to be m.\n" "\n" -"-scale fraction Scale the framebuffer by factor \"fraction\". Values\n" -" less than 1 shrink the fb. Note: image may not be sharp\n" -" and response may be slower. If \"fraction\" contains\n" +"-scale fraction Scale the framebuffer by factor \"fraction\".\n" +" Values less than 1 shrink the fb. Note: image may not\n" +" be sharp and response may be slower. Currently the\n" +" cursor shape is not scaled. If \"fraction\" contains\n" " a decimal point \".\" it is taken as a floating point\n" " number, alternatively the notation \"m/n\" may be used\n" " to denote fractions exactly, e.g. -scale 2/3.\n" @@ -7990,7 +8425,7 @@ static void print_help(void) { " If you just want a quick, rough scaling without\n" " blending, append \":nb\" to \"fraction\" (e.g. -scale\n" " 1/3:nb). For compatibility with vncviewers the scaled\n" -" width is adjusted to be a multiple of 4, to disable\n" +" width is adjusted to be a multiple of 4: to disable\n" " this use \":n4\". More esoteric options: \":in\" use\n" " interpolation scheme even when shrinking, \":pad\",\n" " pad scaled width and height to be multiples of scaling\n" @@ -8010,9 +8445,10 @@ static void print_help(void) { " periodically check for new hosts. The first line is\n" " read and then the file is truncated.\n" "-vncconnect Monitor the VNC_CONNECT X property set by the standard\n" -" VNC program vncconnect(1). When the property is set\n" -" to host or host:port establish a reverse connection.\n" -" Using xprop(1) instead of vncconnect may work, see FAQ.\n" +"-novncconnect VNC program vncconnect(1). When the property is\n" +" set to \"host\" or \"host:port\" establish a reverse\n" +" connection. Using xprop(1) instead of vncconnect may\n" +" work, see the FAQ. Default: %s\n" "-inetd Launched by inetd(1): stdio instead of listening socket.\n" " Note: if you are not redirecting stderr to a log file\n" " (via shell 2> or -o option) you must also specify the\n" @@ -8103,16 +8539,18 @@ static void print_help(void) { "-flipbyteorder Sometimes needed if remotely polled host has different\n" " endianness. Ignored unless -noshm is set.\n" "-onetile Do not use the new copy_tiles() framebuffer mechanism,\n" -" just use 1 shm tile for polling. Same as -old_copytile.\n" -" Limits shm segments used to 3.\n" +" just use 1 shm tile for polling. Limits shm segments\n" +" used to 3.\n" "\n" "-blackout string Black out rectangles on the screen. \"string\" is a\n" " comma separated list of WxH+X+Y type geometries for\n" " each rectangle.\n" "-xinerama If your screen is composed of multiple monitors\n" " glued together via XINERAMA, and that screen is\n" -" non-rectangular this option will try to guess the areas\n" -" to black out (if your system has libXinerama).\n" +" non-rectangular this option will try to guess the\n" +" areas to black out (if your system has libXinerama).\n" +" In general on XINERAMA displays you may need to use the\n" +" -xwarppointer option if the mouse pointer misbehaves.\n" "\n" "-o logfile Write stderr messages to file \"logfile\" instead of\n" " to the terminal. Same as -logfile \"file\".\n" @@ -8144,7 +8582,9 @@ static void print_help(void) { " the X server instead of Mode_switch (AltGr).\n" #endif "-xkb When in modtweak mode, use the XKEYBOARD extension\n" -" (if it exists) to do the modifier tweaking.\n" +" (if it exists) to do the modifier tweaking. This is\n" +" powerful and should be tried if there are still\n" +" keymapping problems when using the simpler -modtweak.\n" "-skip_keycodes string Skip keycodes not on your keyboard but your X server\n" " thinks exist. Currently only applies to -xkb mode.\n" " \"string\" is a comma separated list of decimal\n" @@ -8199,17 +8639,70 @@ static void print_help(void) { " back to clients. (PRIMARY is still set on received\n" " changes, however).\n" "\n" -"-nocursor Do not have the VNC viewer show a local cursor.\n" -"-mouse Draw a 2nd cursor at the current X pointer position.\n" -"-mouseX As -mouse, but also draw an \"X\" when pointer is on\n" -" 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" +"-cursor [mode] Sets how the pointer cursor shape (little icon at the\n" +"-nocursor mouse pointer) should be handled. The \"mode\" string\n" +" is optional and is described below. The default\n" +" is to show some sort of cursor shape(s). How this\n" +" is done depends on the VNC viewer and the X server.\n" +" Use -nocursor to disable cursor shapes completely.\n" +"\n" +" Some VNC viewers support the TightVNC CursorPosUpdates\n" +" and CursorShapeUpdates extensions (cuts down on\n" +" network traffic by not having to send the cursor image\n" +" every time the pointer is moved), in which case these\n" +" extensions are used (see -nocursorshape and -nocursorpos\n" +" below). For other viewers the cursor shape is written\n" +" directly to the framebuffer every time the pointer is\n" +" moved or changed and gets sent along with the other\n" +" framebuffer updates. In this case, there will be\n" +" some lag between the vnc viewer pointer and the remote\n" +" cursor position.\n" +"\n" +" If the X display supports retrieving the cursor shape\n" +" information from the X server, then the default\n" +" is to use that mode. On Solaris this requires\n" +" the SUN_OVL extension and the -overlay option to be\n" +" supplied. (see also the -overlay_nomouse option). (Soon)\n" +" on XFree86/Xorg the XFIXES extension is required.\n" +" Either can be disabled with -nocursor, and also some\n" +" values of the \"mode\" option below.\n" +"\n" +" The \"mode\" string can be used to fine-tune the\n" +" displaying of cursor shapes. It can be used the\n" +" following ways:\n" +"\n" +" \"-cursor X\" - when the cursor appears to be on the\n" +" root window, draw the familiar X shape. Some desktops\n" +" such as GNOME cover up the root window completely,\n" +" and so this will not work, try \"X1\", etc, to try to\n" +" shift the tree depth. On high latency links or slow\n" +" machines there will be a time lag between expected and\n" +" the actual cursor shape.\n" +"\n" +" \"-cursor some\" - like \"X\" but use additional\n" +" heuristics to try to guess if the window should have\n" +" a windowmanager-like resizer cursor or a text input\n" +" I-beam cursor. This is a complete hack, but may be\n" +" useful in some situations because it provides a little\n" +" more feedback about the cursor shape.\n" +"\n" +" \"-cursor most\" - try to show as many cursors as\n" +" possible. Often this will only be the same as \"some\".\n" +" On Solaris if XFIXES is not available, -overlay mode\n" +" will be used.\n" +"\n" +"-nocursorshape Do not use the TightVNC CursorShapeUpdates extension\n" +" even if clients support it. See -cursor above.\n" "-cursorpos Option -cursorpos enables sending the X cursor position\n" "-nocursorpos back to all vnc clients that support the TightVNC\n" -" CursorPosUpdates extension. Default: %s\n" +" CursorPosUpdates extension. Other clients will be able\n" +" to see the pointer motions. Default: %s\n" +"-xwarppointer Move the pointer with XWarpPointer(3X) instead of XTEST\n" +" extension. Use this as a workaround if the pointer\n" +" motion behaves incorrectly, e.g. on touchscreens or\n" +" other non-standard setups. Also sometimes needed on\n" +" XINERAMA displays.\n" +"\n" "-buttonmap string String to remap mouse buttons. Format: IJK-LMN, this\n" " maps buttons I -> L, etc., e.g. -buttonmap 13-31\n" "\n" @@ -8284,9 +8777,10 @@ static void print_help(void) { fprintf(stderr, help, lastmod, view_only ? "on":"off", shared ? "on":"off", + vnc_connect ? "-vncconnect":"-novncconnect", use_modifier_tweak ? "-modtweak":"-nomodtweak", no_autorepeat ? "-norepeat":"-repeat", - cursor_pos ? "-cursorpos":"-nocursorpos", + cursor_pos_updates ? "-cursorpos":"-nocursorpos", defer_update, waitms, take_naps ? "on":"off", @@ -8536,7 +9030,8 @@ static void check_rcfile(int argc, char **argv) { int main(int argc, char* argv[]) { XImage *fb; - int i, ev, er, maj, min; + int i; + int ev, er, maj, min; char *use_dpy = NULL; char *auth_file = NULL; char *arg, *visual_str = NULL; @@ -8652,8 +9147,10 @@ int main(int argc, char* argv[]) { scale_denom = n; } if (scale_fac == 1.0) { - fprintf(stderr, "scaling disabled for factor " - "%f\n", scale_fac); + if (! quiet) { + rfbLog("scaling disabled for factor " + " %f\n", scale_fac); + } } else { scaling = 1; } @@ -8662,6 +9159,9 @@ int main(int argc, char* argv[]) { visual_str = argv[++i]; } else if (!strcmp(arg, "-overlay")) { overlay = 1; + } else if (!strcmp(arg, "-overlay_nocursor")) { + overlay = 1; + overlay_cursor = 0; } else if (!strcmp(arg, "-flashcmap")) { flash_cmap = 1; } else if (!strcmp(arg, "-notruecolor")) { @@ -8715,6 +9215,8 @@ int main(int argc, char* argv[]) { } } else if (!strcmp(arg, "-vncconnect")) { vnc_connect = 1; + } else if (!strcmp(arg, "-novncconnect")) { + vnc_connect = 0; } else if (!strcmp(arg, "-inetd")) { inetd = 1; } else if (!strcmp(arg, "-noshm")) { @@ -8760,23 +9262,28 @@ int main(int argc, char* argv[]) { watch_selection = 0; } else if (!strcmp(arg, "-noprimary")) { watch_primary = 0; - } else if (!strcmp(arg, "-nocursor")) { - local_cursor = 0; - } else if (!strcmp(arg, "-mouse")) { - show_mouse = 1; - } else if (!strcmp(arg, "-mouseX")) { - show_mouse = 1; - show_root_cursor = 1; - } else if (!strcmp(arg, "-X")) { - show_mouse = 1; - show_root_cursor = 1; - local_cursor = 0; - } else if (!strcmp(arg, "-xwarppointer")) { - use_xwarppointer = 1; + } else if (!strcmp(arg, "-cursor")) { + show_cursor = 1; + if (i >= argc-1) { + ; + } else { + char *s = argv[i+1]; + if (*s == 'X' || !strcmp(s, "default") || + !strcmp(s, "some") || !strcmp(s, "most")) { + multiple_cursors_mode = strdup(s); + i++; + } + } + } else if (!strcmp(arg, "-nocursor")) { + show_cursor = 0; } else if (!strcmp(arg, "-cursorpos")) { - cursor_pos = 1; + cursor_pos_updates = 1; } else if (!strcmp(arg, "-nocursorpos")) { - cursor_pos = 0; + cursor_pos_updates = 0; + } else if (!strcmp(arg, "-nocursorshape")) { + cursor_shape_updates = 0; + } else if (!strcmp(arg, "-xwarppointer")) { + use_xwarppointer = 1; } else if (!strcmp(arg, "-buttonmap")) { CHECK_ARGC pointer_remap = argv[++i]; @@ -8792,10 +9299,8 @@ int main(int argc, char* argv[]) { no_autorepeat = 1; } else if (!strcmp(arg, "-repeat")) { no_autorepeat = 0; - } else if (!strcmp(arg, "-onetile") - || !strcmp(arg, "-old_copytile")) { + } else if (!strcmp(arg, "-onetile")) { single_copytile = 1; - } else if (!strcmp(arg, "-debug_pointer")) { } else if (!strcmp(arg, "-debug_pointer") || !strcmp(arg, "-dp")) { debug_pointer++; @@ -8842,9 +9347,6 @@ int main(int argc, char* argv[]) { } else if (!strcmp(arg, "-fuzz")) { CHECK_ARGC tile_fuzz = atoi(argv[++i]); - } else if (!strcmp(arg, "-hints") || !strcmp(arg, "-nohints")) { - fprintf(stderr, "warning: -hints/-nohints option " - "has been removed.\n"); } else if (!strcmp(arg, "-h") || !strcmp(arg, "-help") || !strcmp(arg, "-?")) { print_help(); @@ -8907,8 +9409,7 @@ int main(int argc, char* argv[]) { if (! quiet && ! inetd) { int i; for (i=1; i < argc_vnc; i++) { - fprintf(stderr, "passing arg to libvncserver: %s\n", - argv_vnc[i]); + rfbLog("passing arg to libvncserver: %s\n", argv_vnc[i]); if (!strcmp(argv_vnc[i], "-passwd")) { i++; } @@ -8937,9 +9438,8 @@ int main(int argc, char* argv[]) { FILE *in; in = fopen(passwdfile, "r"); if (in == NULL) { - fprintf(stderr, "cannot open passwdfile: %s\n", - passwdfile); - perror("fopen"); + rfbLog("cannot open passwdfile: %s\n", passwdfile); + rfbLog("fopen"); exit(1); } if (fgets(line, 1024, in) != NULL) { @@ -8970,15 +9470,15 @@ int main(int argc, char* argv[]) { if (ok) { viewonly_passwd = strdup(line); } else { - fprintf(stderr, "*** not setting" + rfbLog("*** not setting" " viewonly password to the 2nd" " line of %s. (blank or other" " problem)\n", passwdfile); } } } else { - fprintf(stderr, "cannot read a line from " - "passwdfile: %s\n", passwdfile); + rfbLog("cannot read a line from passwdfile: %s\n", + passwdfile); exit(1); } fclose(in); @@ -8996,17 +9496,15 @@ int main(int argc, char* argv[]) { } } if (viewonly_passwd && pw_loc < 0) { - fprintf(stderr, "-passwd must be supplied when using " - "-viewpasswd\n"); + rfbLog("-passwd must be supplied when using -viewpasswd\n"); exit(1); } /* fixup settings that do not make sense */ - if (use_threads && nofb && cursor_pos) { + if (use_threads && nofb && cursor_pos_updates) { if (! quiet) { - fprintf(stderr, "disabling -threads under -nofb " - "-cursorpos\n"); + rfbLog("disabling -threads under -nofb -cursorpos\n"); } use_threads = 0; } @@ -9022,34 +9520,94 @@ int main(int argc, char* argv[]) { bg = 0; } + if (flip_byte_order && using_shm && ! quiet) { + rfbLog("warning: -flipbyte order only works with -noshm\n"); + } + /* increase rfbwait if threaded */ if (use_threads && ! got_rfbwait) { argv_vnc[argc_vnc++] = "-rfbwait"; argv_vnc[argc_vnc++] = "604800000"; /* one week... */ } + /* cursor shapes setup */ + +#ifdef SOLARIS + if (show_cursor && ! overlay && overlay_cursor && + !strcmp(multiple_cursors_mode, "most")) { + overlay = 1; + if (! quiet) { + rfbLog("enabling -overlay mode to achieve " + "'-cursor most'\n"); + rfbLog("disable with: -overlay_nocursor.\n"); + } + } +#endif + if (overlay) { #ifdef SOLARIS using_shm = 0; if (flash_cmap && ! quiet) { - fprintf(stderr, "warning: -flashcmap may be " - "incompatible with -overlay\n"); + rfbLog("warning: -flashcmap may be incompatible " + "with -overlay\n"); } - if (show_mouse) { - show_mouse = 0; - overlay_mouse = 1; + if (show_cursor && overlay_cursor) { + char *s = multiple_cursors_mode; + if (*s == 'X' || !strcmp(s, "some")) { + /* + * user wants these modes, so disable fb cursor + */ + overlay_cursor = 0; + } else { + /* + * "default" and "most", we turn off + * show_cursor since it will automatically + * be in the framebuffer. + */ + show_cursor = 0; + } } #else if (! quiet) { - fprintf(stderr, "disabling -overlay: currently only " - "available on Solaris Xsun.\n"); + rfbLog("disabling -overlay: only available on " + "Solaris Xsun.\n"); } overlay = 0; #endif } + if (show_cursor) { + char *s = multiple_cursors_mode; + if (*s == 'X' || !strcmp(s, "some")) { + show_multiple_cursors = 1; + } else if (!strcmp(s, "most")) { + /* later check for XFIXES, for now "some" */ + show_multiple_cursors = 1; + } + } + + /* no framebuffer (Win2VNC) mode */ + + if (nofb) { + /* disable things that do not make sense */ + using_shm = 0; + flash_cmap = 0; + show_cursor = 0; + show_multiple_cursors = 0; + overlay = 0; + if (! quiet) { + rfbLog("disabling -cursor, fb, shm, etc. in " + "-nofb mode.\n"); + } + + if (! got_deferupdate && ! got_defer) { + /* reduce defer time under -nofb */ + defer_update = defer_update_nofb; + } + } + /* check for OS with small shm limits */ if (using_shm && ! single_copytile) { if (limit_shm()) { @@ -9057,10 +9615,6 @@ int main(int argc, char* argv[]) { } } - if (nofb && ! got_deferupdate && ! got_defer) { - /* reduce defer time under -nofb */ - defer_update = defer_update_nofb; - } if (! got_deferupdate) { char tmp[40]; /* XXX not working yet in libvncserver */ @@ -9068,9 +9622,10 @@ int main(int argc, char* argv[]) { argv_vnc[argc_vnc++] = "-deferupdate"; argv_vnc[argc_vnc++] = strdup(tmp); } + if (debug_pointer || debug_keyboard) { if (bg || quiet) { - fprintf(stderr, "disabling -bg/-q under -debug_pointer" + rfbLog("disabling -bg/-q under -debug_pointer" "/-debug_keyboard\n"); bg = 0; quiet = 0; @@ -9079,81 +9634,85 @@ int main(int argc, char* argv[]) { if (! quiet) { fprintf(stderr, "\n"); - fprintf(stderr, "display: %s\n", use_dpy ? use_dpy + fprintf(stderr, "Settings:\n"); + fprintf(stderr, " display: %s\n", use_dpy ? use_dpy : "null"); - fprintf(stderr, "subwin: 0x%x\n", subwin); - fprintf(stderr, "flashcmap: %d\n", flash_cmap); - fprintf(stderr, "force_idx: %d\n", force_indexed_color); - fprintf(stderr, "scaling: %d %.5f\n", scaling, scale_fac); - fprintf(stderr, "visual: %s\n", visual_str ? visual_str + fprintf(stderr, " subwin: 0x%x\n", subwin); + fprintf(stderr, " flashcmap: %d\n", flash_cmap); + fprintf(stderr, " force_idx: %d\n", force_indexed_color); + fprintf(stderr, " scaling: %d %.5f\n", scaling, scale_fac); + fprintf(stderr, " visual: %s\n", visual_str ? visual_str : "null"); - fprintf(stderr, "overlay: %d\n", overlay); - fprintf(stderr, "ovl_mouse: %d\n", overlay_mouse); - fprintf(stderr, "viewonly: %d\n", view_only); - fprintf(stderr, "shared: %d\n", shared); - fprintf(stderr, "conn_once: %d\n", connect_once); - fprintf(stderr, "connect: %s\n", client_connect + fprintf(stderr, " overlay: %d\n", overlay); + fprintf(stderr, " ovl_cursor: %d\n", overlay_cursor); + fprintf(stderr, " viewonly: %d\n", view_only); + fprintf(stderr, " shared: %d\n", shared); + fprintf(stderr, " conn_once: %d\n", connect_once); + fprintf(stderr, " connect: %s\n", client_connect ? client_connect : "null"); - fprintf(stderr, "connectfile %s\n", client_connect_file + fprintf(stderr, " connectfile %s\n", client_connect_file ? client_connect_file : "null"); - fprintf(stderr, "vnc_conn: %d\n", vnc_connect); - fprintf(stderr, "authfile: %s\n", auth_file ? auth_file + fprintf(stderr, " vnc_conn: %d\n", vnc_connect); + fprintf(stderr, " authfile: %s\n", auth_file ? auth_file : "null"); - fprintf(stderr, "allow: %s\n", allow_list ? allow_list + fprintf(stderr, " allow: %s\n", allow_list ? allow_list : "null"); - fprintf(stderr, "passfile: %s\n", passwdfile ? passwdfile + fprintf(stderr, " passfile: %s\n", passwdfile ? passwdfile : "null"); - fprintf(stderr, "accept: %s\n", accept_cmd ? accept_cmd + fprintf(stderr, " accept: %s\n", accept_cmd ? accept_cmd : "null"); - fprintf(stderr, "gone: %s\n", gone_cmd ? gone_cmd + fprintf(stderr, " gone: %s\n", gone_cmd ? gone_cmd : "null"); - fprintf(stderr, "inetd: %d\n", inetd); - fprintf(stderr, "using_shm: %d\n", using_shm); - fprintf(stderr, "flipbytes: %d\n", flip_byte_order); - fprintf(stderr, "blackout: %s\n", blackout_string + fprintf(stderr, " inetd: %d\n", inetd); + fprintf(stderr, " using_shm: %d\n", using_shm); + fprintf(stderr, " flipbytes: %d\n", flip_byte_order); + fprintf(stderr, " blackout: %s\n", blackout_string ? blackout_string : "null"); - fprintf(stderr, "xinerama: %d\n", xinerama); - fprintf(stderr, "logfile: %s\n", logfile ? logfile + fprintf(stderr, " xinerama: %d\n", xinerama); + fprintf(stderr, " logfile: %s\n", logfile ? logfile : "null"); - fprintf(stderr, "bg: %d\n", bg); - fprintf(stderr, "mod_tweak: %d\n", use_modifier_tweak); - fprintf(stderr, "isolevel3: %d\n", use_iso_level3); - fprintf(stderr, "xkb: %d\n", use_xkb_modtweak); - fprintf(stderr, "skipkeys: %s\n", skip_keycodes ? skip_keycodes + fprintf(stderr, " bg: %d\n", bg); + fprintf(stderr, " mod_tweak: %d\n", use_modifier_tweak); + fprintf(stderr, " isolevel3: %d\n", use_iso_level3); + fprintf(stderr, " xkb: %d\n", use_xkb_modtweak); + fprintf(stderr, " skipkeys: %s\n", + skip_keycodes ? skip_keycodes : "null"); + fprintf(stderr, " addkeysyms: %d\n", add_keysyms); + fprintf(stderr, " xkbcompat: %d\n", xkbcompat); + fprintf(stderr, " clearmods: %d\n", clear_mods); + fprintf(stderr, " remap: %s\n", remap_file ? remap_file : "null"); - fprintf(stderr, "addkeysyms: %d\n", add_keysyms); - fprintf(stderr, "xkbcompat: %d\n", xkbcompat); - fprintf(stderr, "clearmods: %d\n", clear_mods); - fprintf(stderr, "remap: %s\n", remap_file ? remap_file - : "null"); - fprintf(stderr, "nofb: %d\n", nofb); - fprintf(stderr, "watchbell: %d\n", watch_bell); - fprintf(stderr, "watchsel: %d\n", watch_selection); - fprintf(stderr, "watchprim: %d\n", watch_primary); - fprintf(stderr, "loc_curs: %d\n", local_cursor); - fprintf(stderr, "mouse: %d\n", show_mouse); - fprintf(stderr, "root_curs: %d\n", show_root_cursor); - fprintf(stderr, "xwarpptr: %d\n", use_xwarppointer); - fprintf(stderr, "cursorpos: %d\n", cursor_pos); - fprintf(stderr, "buttonmap: %s\n", pointer_remap + fprintf(stderr, " nofb: %d\n", nofb); + fprintf(stderr, " watchbell: %d\n", watch_bell); + fprintf(stderr, " watchsel: %d\n", watch_selection); + fprintf(stderr, " watchprim: %d\n", watch_primary); + fprintf(stderr, " cursor: %d\n", show_cursor); + fprintf(stderr, " root_curs: %d\n", show_multiple_cursors); + fprintf(stderr, " curs_mode: %s\n", multiple_cursors_mode + ? multiple_cursors_mode : "null"); + fprintf(stderr, " xwarpptr: %d\n", use_xwarppointer); + fprintf(stderr, " cursorpos: %d\n", cursor_pos_updates); + fprintf(stderr, " cursorshp: %d\n", cursor_shape_updates); + fprintf(stderr, " buttonmap: %s\n", pointer_remap ? pointer_remap : "null"); - fprintf(stderr, "dragging: %d\n", show_dragging); - fprintf(stderr, "old_ptr: %d\n", old_pointer); - fprintf(stderr, "inputskip: %d\n", ui_skip); - fprintf(stderr, "norepeat: %d\n", no_autorepeat); - fprintf(stderr, "debug_ptr: %d\n", debug_pointer); - fprintf(stderr, "debug_key: %d\n", debug_keyboard); - fprintf(stderr, "defer: %d\n", defer_update); - fprintf(stderr, "waitms: %d\n", waitms); - fprintf(stderr, "take_naps: %d\n", take_naps); - fprintf(stderr, "sigpipe: %d\n", sigpipe); - fprintf(stderr, "threads: %d\n", use_threads); - fprintf(stderr, "fs_frac: %.2f\n", fs_frac); - fprintf(stderr, "onetile: %d\n", single_copytile); - fprintf(stderr, "gaps_fill: %d\n", gaps_fill); - fprintf(stderr, "grow_fill: %d\n", grow_fill); - fprintf(stderr, "tile_fuzz: %d\n", tile_fuzz); - fprintf(stderr, "version: %s\n", lastmod); + fprintf(stderr, " dragging: %d\n", show_dragging); + fprintf(stderr, " old_ptr: %d\n", old_pointer); + fprintf(stderr, " inputskip: %d\n", ui_skip); + fprintf(stderr, " norepeat: %d\n", no_autorepeat); + fprintf(stderr, " debug_ptr: %d\n", debug_pointer); + fprintf(stderr, " debug_key: %d\n", debug_keyboard); + fprintf(stderr, " defer: %d\n", defer_update); + fprintf(stderr, " waitms: %d\n", waitms); + fprintf(stderr, " take_naps: %d\n", take_naps); + fprintf(stderr, " sigpipe: %d\n", sigpipe); + fprintf(stderr, " threads: %d\n", use_threads); + fprintf(stderr, " fs_frac: %.2f\n", fs_frac); + fprintf(stderr, " onetile: %d\n", single_copytile); + fprintf(stderr, " gaps_fill: %d\n", gaps_fill); + fprintf(stderr, " grow_fill: %d\n", grow_fill); + fprintf(stderr, " tile_fuzz: %d\n", tile_fuzz); + fprintf(stderr, "\n"); + rfbLog("x11vnc version: %s\n", lastmod); } else { rfbLogEnable(0); } @@ -9182,11 +9741,11 @@ int main(int argc, char* argv[]) { if (xkbcompat) { Bool rc = XkbIgnoreExtension(True); if (! quiet) { - fprintf(stderr, "disabling xkb extension. rc=%d\n", rc); - if (watch_bell) { - watch_bell = 0; - fprintf(stderr, "disabling bell.\n"); - } + rfbLog("disabling xkb extension. rc=%d\n", rc); + } + if (watch_bell) { + watch_bell = 0; + if (! quiet) rfbLog("disabling bell.\n"); } } #else @@ -9194,6 +9753,7 @@ int main(int argc, char* argv[]) { watch_bell = 0; use_xkb_modtweak = 0; #endif + if (use_dpy) { dpy = XOpenDisplay(use_dpy); } else if ( (use_dpy = getenv("DISPLAY")) ) { @@ -9203,13 +9763,12 @@ int main(int argc, char* argv[]) { } if (! dpy) { - fprintf(stderr, "XOpenDisplay failed (%s)\n", - use_dpy ? use_dpy:"null"); + rfbLog("XOpenDisplay failed (%s)\n", use_dpy ? use_dpy:"null"); exit(1); } else if (use_dpy) { - if (! quiet) fprintf(stderr, "Using X display %s\n", use_dpy); + if (! quiet) rfbLog("Using X display %s\n", use_dpy); } else { - if (! quiet) fprintf(stderr, "Using default X display.\n"); + if (! quiet) rfbLog("Using default X display.\n"); } scr = DefaultScreen(dpy); @@ -9222,28 +9781,43 @@ int main(int argc, char* argv[]) { } /* check for XTEST */ - if (! XTestQueryExtension(dpy, &ev, &er, &maj, &min)) { - fprintf(stderr, "Display does not support XTest extension.\n"); - exit(1); + if (! XTestQueryExtension_wr(dpy, &ev, &er, &maj, &min)) { + rfbLog("warning: XTest extension not available, most user" + " input\n"); + rfbLog("(pointer and keyboard) will be discarded.\n"); + xtest_present = 0; + rfbLog("no XTest extension, switching to -xwarppointer mode\n"); + rfbLog("for pointer motion input.\n"); + use_xwarppointer = 1; } /* * Window managers will often grab the display during resize, etc. * To avoid deadlock (our user resize input is not processed) * we tell the server to process our requests during all grabs: */ - XTestGrabControl(dpy, True); + XTestGrabControl_wr(dpy, True); /* check for MIT-SHM */ - if (! nofb && ! XShmQueryExtension(dpy)) { + if (! nofb && ! XShmQueryExtension_wr(dpy)) { if (! using_shm) { if (! quiet) { - fprintf(stderr, "info: display does not " - "support XShm.\n"); + rfbLog("info: display does not support" + " XShm.\n"); } } else { - fprintf(stderr, "Display does not support XShm " - "extension (must be local).\n"); + rfbLog("warning: XShm extension is not available.\n"); + rfbLog("For best performance the X Display should be" + " local. (i.e.\n"); + rfbLog("the x11vnc and X server processes should be" + " running on\n"); + rfbLog("the same machine.)\n"); +#ifdef LIBVNCSERVER_HAVE_XSHM + rfbLog("Restart with -noshm to override this.\n"); exit(1); +#else + rfbLog("Switching to -noshm mode.\n"); + using_shm = 0; +#endif } } @@ -9286,8 +9860,10 @@ int main(int argc, char* argv[]) { } initialize_watch_bell(); if (!use_xkb && use_xkb_modtweak) { - fprintf(stderr, "warning: disabling xkb modtweak." - " XKEYBOARD ext. not present.\n"); + if (! quiet) { + fprintf(stderr, "warning: disabling xkb modtweak." + " XKEYBOARD ext. not present.\n"); + } use_xkb_modtweak = 0; } #endif @@ -9316,9 +9892,8 @@ int main(int argc, char* argv[]) { /* this may be overridden via visual_id below */ default_visual = attr.visual; - /* show_mouse has some segv crashes as well */ - if (show_root_cursor) { - show_root_cursor = 0; + if (show_multiple_cursors) { + show_multiple_cursors = 0; if (! quiet) { fprintf(stderr, "disabling root cursor drawing" " for subwindow\n"); @@ -9368,6 +9943,10 @@ int main(int argc, char* argv[]) { XFree(vinfo); } + if (! quiet) { + rfbLog("default visual ID: 0x%x\n", + (int) XVisualIDFromVisual(default_visual)); + } if (nofb) { /* @@ -9388,7 +9967,7 @@ int main(int argc, char* argv[]) { fb = XGetImage_wr(dpy, window, 0, 0, dpy_x, dpy_y, AllPlanes, ZPixmap); if (! quiet) { - fprintf(stderr, "Read initial data from X display into" + rfbLog("Read initial data from X display into" " framebuffer.\n"); } } @@ -9432,6 +10011,7 @@ int main(int argc, char* argv[]) { if (remap_file != NULL) { initialize_remap(remap_file); } + initialize_pointer_map(pointer_remap); clear_modifiers(1); @@ -9454,7 +10034,7 @@ int main(int argc, char* argv[]) { if (host != NULL) { /* note that vncviewer special cases 5900-5999 */ if (inetd) { - ; /* should not occur */ + ; /* should not occur (rfbPort) */ } else if (quiet) { if (port >= 5900) { fprintf(stderr, "The VNC desktop is " @@ -9478,7 +10058,11 @@ int main(int argc, char* argv[]) { } } fflush(stderr); - fprintf(stdout, "PORT=%d\n", screen->rfbPort); + if (inetd) { + ; /* should not occur (rfbPort) */ + } else { + fprintf(stdout, "PORT=%d\n", screen->rfbPort); + } fflush(stdout); } |