summaryrefslogtreecommitdiffstats
path: root/x11vnc/x11vnc.c
diff options
context:
space:
mode:
Diffstat (limited to 'x11vnc/x11vnc.c')
-rw-r--r--x11vnc/x11vnc.c6876
1 files changed, 5818 insertions, 1058 deletions
diff --git a/x11vnc/x11vnc.c b/x11vnc/x11vnc.c
index 5df5db3..c26db31 100644
--- a/x11vnc/x11vnc.c
+++ b/x11vnc/x11vnc.c
@@ -47,27 +47,33 @@
* gcc should be used on all platforms. To build a threaded version put
* "-D_REENTRANT -DX11VNC_THREADED" in the environment variable CFLAGS
* or CPPFLAGS (e.g. before running the libvncserver configure). The
- * threaded mode is a bit more responsive, but can be unstable.
+ * threaded mode is a bit more responsive, but can be unstable (e.g.
+ * if more than one client the same tight or zrle encoding).
*
* Known shortcomings:
*
* The screen updates are good, but of course not perfect since the X
* display must be continuously polled and read for changes (as opposed to
* receiving a change callback from the X server, if that were generally
- * possible...). So, e.g., opaque moves and similar window activity
- * can be very painful; one has to modify one's behavior a bit.
+ * possible... (Update: this seems to be handled now with the X DAMAGE
+ * extension, but unfortunately that doesn't seem to address the slow
+ * read from the video h/w). So, e.g., opaque moves and similar window
+ * activity can be very painful; one has to modify one's behavior a bit.
*
* General audio at the remote display is lost unless one separately
* sets up some audio side-channel such as esd.
*
* It does not appear possible to query the X server for the current
* cursor shape. We can use XTest to compare cursor to current window's
- * cursor, but we cannot extract what the cursor is...
+ * cursor, but we cannot extract what the cursor is... (Update: we now
+ * use XFIXES extension for this. Also on Solaris and IRIX Overlay
+ * extensions exists that allow drawing the mouse into the framebuffer)
*
- * Nevertheless, the current *position* of the remote X mouse pointer
- * 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...)
+ * The current *position* of the remote X mouse pointer 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...,
+ * currently -cursor some is a first hack at this)
*
* Windows using visuals other than the default X visual may have
* their colors messed up. When using 8bpp indexed color, the colormap
@@ -75,11 +81,11 @@
* -flashcmap option to have colormap flashing as the pointer moves
* windows with private colormaps (slow). Displays with mixed depth 8 and
* 24 visuals will incorrectly display windows using the non-default one.
- * On Sun hardware we try to work around this with -overlay.
+ * On Sun and Sgi hardware we can 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 -cursor, etc.
- * SaveUnders menus, popups, etc will not be seen.
+ * window not sufficiently mapped into server memory, etc. SaveUnders
+ * menus, popups, etc will not be seen.
*
* Occasionally, a few tile updates can be missed leaving a patch of
* color that needs to be refreshed. This may only be when threaded,
@@ -92,11 +98,11 @@
*/
/*
- * These ' -- filename -- ' comments represent a partial cleanup:
+ * These ' -- filename.[ch] -- ' comments represent a partial cleanup:
* they are an odd way to indicate how this huge file would be split up
* someday into multiple files. Not finished, externs and other things
- * would need to be done, but it indicates the breakup, including static
- * keyword for local items.
+ * would need to be done, but it indicates a breakup, including static
+ * keyword for some items.
*
* The primary reason we do not break up this file is for user
* convenience: those wanting to use the latest version download a single
@@ -105,52 +111,37 @@
/* -- x11vnc.h -- */
-#define NON_CVS 0
/*
- * 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.
+ * if you are inserting this file, x11vnc.c into an old CVS tree you
+ * may need to set OLD_TREE to 1.
*/
-#if NON_CVS
-#define LIBVNCSERVER_HAVE_XSHM
-#define LIBVNCSERVER_HAVE_XTEST
-#endif
+#define OLD_TREE 0
+#if OLD_TREE
/*
* 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
+ * x11vnc.c file using OLD_TREE=1 you may need to set some of these lines
+ * since your older libvncserver configure is not setting them.
*
+ * For the features LIBVNCSERVER_HAVE_LIBXINERAMA and
+ * LIBVNCSERVER_HAVE_XFIXES you may also need to add
+ * -lXinerama or -lXfixes, respectively, to the linking line, e.g.
+ * by setting them in LD_FLAGS before running configure.
*/
+#define LIBVNCSERVER_HAVE_XSHM
+#define LIBVNCSERVER_HAVE_XTEST
/*
- * This is another transient for building in older libvncserver trees.
+#define LIBVNCSERVER_HAVE_LIBXINERAMA
+#define LIBVNCSERVER_HAVE_XFIXES
+#define LIBVNCSERVER_HAVE_XDAMAGE
*/
-#if NON_CVS
-#define dontDisconnect rfbDontDisconnect
-#define neverShared rfbNeverShared
-#define alwaysShared rfbAlwaysShared
-#define clientHead rfbClientHead
-#define serverFormat rfbServerFormat
-#define port rfbPort
-#define listenSock rfbListenSock
-#define deferUpdateTime rfbDeferUpdateTime
-#define authPasswdData rfbAuthPasswdData
-#define rfbEncryptAndStorePasswd vncEncryptAndStorePasswd
#endif
#include <unistd.h>
#include <signal.h>
#include <sys/utsname.h>
-
#include <X11/Xlib.h>
#include <X11/Xutil.h>
@@ -164,6 +155,23 @@
#include <rfb/rfb.h>
#include <rfb/rfbregion.h>
+/*
+ * This is another transient for building in older libvncserver trees,
+ * due to the API change:
+ */
+#if OLD_TREE
+#define dontDisconnect rfbDontDisconnect
+#define neverShared rfbNeverShared
+#define alwaysShared rfbAlwaysShared
+#define clientHead rfbClientHead
+#define serverFormat rfbServerFormat
+#define port rfbPort
+#define listenSock rfbListenSock
+#define deferUpdateTime rfbDeferUpdateTime
+#define authPasswdData rfbAuthPasswdData
+#define rfbEncryptAndStorePasswd vncEncryptAndStorePasswd
+#endif
+
#ifdef LIBVNCSERVER_HAVE_XSHM
#include <sys/ipc.h>
#include <sys/shm.h>
@@ -182,23 +190,73 @@
#include <X11/extensions/Xinerama.h>
#endif
-#if defined (__SVR4) && defined (__sun)
-#define SOLARIS
-#include <X11/extensions/transovl.h>
-#endif
-
#ifdef LIBVNCSERVER_HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
+#include <netdb.h>
+extern int h_errno;
+
#ifdef LIBVNCSERVER_HAVE_NETINET_IN_H
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#endif
+/*
+ * overlay/multi-depth screen reading support
+ * undef SOLARIS_OVERLAY or IRIX_OVERLAY if there are problems building.
+ */
+
+/* solaris/sun */
+#if defined (__SVR4) && defined (__sun)
+#define SOLARIS
+#define SOLARIS_OVERLAY
+#define OVERLAY_OS
+#endif
+#ifdef SOLARIS_OVERLAY
+#include <X11/extensions/transovl.h>
+#endif
+
+/* irix/sgi */
+#if defined(__sgi)
+#define IRIX
+#define IRIX_OVERLAY
+#define OVERLAY_OS
+#endif
+#ifdef IRIX_OVERLAY
+#include <X11/extensions/readdisplay.h>
+#endif
+
+int overlay_present = 0;
+
+/*
+ * Ditto for librandr.
+ * (e.g. LDFLAGS=-lXrandr before configure).
+#define LIBVNCSERVER_HAVE_LIBXRANDR
+ */
+#ifdef LIBVNCSERVER_HAVE_LIBXRANDR
+#include <X11/extensions/Xrandr.h>
+static int xrandr_base_event_type;
+#endif
+
+int xfixes_present = 0;
+int use_xfixes = 1;
+int got_xfixes_cursor_notify = 0;
+
+#ifdef LIBVNCSERVER_HAVE_LIBXFIXES
+#include <X11/extensions/Xfixes.h>
+static int xfixes_base_event_type;
+#endif
+
+int xdamage_present = 0;
+#ifdef LIBVNCSERVER_HAVE_LIBXDAMAGE
+#include <X11/extensions/Xdamage.h>
+static int xdamage_base_event_type;
+#endif
+
/* date +'lastmod: %Y-%m-%d' */
-char lastmod[] = "0.6.3pre lastmod: 2004-08-31";
+char lastmod[] = "0.6.3pre lastmod: 2004-12-17";
/* X display info */
@@ -207,7 +265,7 @@ int scr;
Window window, rootwin; /* polled window, root window (usu. same) */
Visual *default_visual; /* the default visual (unless -visual) */
int bpp, depth;
-int indexed_colour = 0;
+int indexed_color = 0;
int dpy_x, dpy_y; /* size of display */
int off_x, off_y; /* offsets for -sid */
int button_mask = 0; /* button state and info */
@@ -217,10 +275,11 @@ int num_buttons = -1;
XImage *scanline;
XImage *fullscreen;
XImage **tile_row; /* for all possible row runs */
+XImage *fb0;
#ifndef LIBVNCSERVER_HAVE_XSHM
/*
- * for simplicity, define these since we'll never use them
+ * for simplicity, define this struct since we'll never use them
* under using_shm = 0.
*/
typedef struct {
@@ -234,16 +293,27 @@ XShmSegmentInfo fullscreen_shm;
XShmSegmentInfo *tile_row_shm; /* for all possible row runs */
/* rfb screen info */
-rfbScreenInfoPtr screen;
+rfbScreenInfoPtr screen = NULL;
+char *rfb_desktop_name = NULL;
+char vnc_desktop_name[256];
char *main_fb; /* our copy of the X11 fb */
char *rfb_fb; /* same as main_fb unless transformation */
+char *fake_fb = NULL; /* used under -padgeom */
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;
+/* we now have a struct with client specific data: */
+typedef struct _ClientData {
+ int had_cursor_shape_updates;
+ int had_cursor_pos_updates;
+ int uid;
+} ClientData;
+
/* scaling parameters */
+char *scale_str = NULL;
double scale_fac = 1.0;
int scaling = 0;
int scaling_noblend = 0; /* no blending option (very course) */
@@ -253,7 +323,6 @@ 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;
int tile_y = 32;
@@ -268,30 +337,46 @@ time_t last_event, last_input, last_client = 0;
/* last client to move pointer */
rfbClientPtr last_pointer_client = NULL;
+/* more transient kludge variables: */
int cursor_x, cursor_y; /* x and y from the viewer(s) */
int got_user_input = 0;
int got_pointer_input = 0;
int got_keyboard_input = 0;
int last_keyboard_input = 0;
int fb_copy_in_progress = 0;
+int drag_in_progress = 0;
int shut_down = 0;
+int do_copy_screen = 0;
+time_t damage_time = 0;
+int damage_delay = 0;
+
+char *program_name = NULL;
+char *program_cmdline = NULL;
/* string for the VNC_CONNECT property */
-#define VNC_CONNECT_MAX 512
+#define VNC_CONNECT_MAX 16384
char vnc_connect_str[VNC_CONNECT_MAX+1];
Atom vnc_connect_prop = None;
/* function prototypes (see filename comment above) */
int all_clients_initialized(void);
+void close_all_clients(void);
+void close_clients(char *);
void autorepeat(int restore);
-char *bitprint(unsigned int);
+char *bitprint(unsigned int, int);
void blackout_tiles(void);
void check_connect_inputs(void);
+void check_padded_fb(void);
void clean_up_exit(int);
void clear_modifiers(int init);
void clear_keys(void);
-void copy_screen(void);
+int copy_screen(void);
+void check_black_fb(void);
+void do_new_fb(int);
+void install_padded_fb(char *);
+void install_fake_fb(int, int, int);
+void remove_fake_fb(void);
int add_keysym(KeySym);
void delete_keycode(KeyCode);
@@ -299,16 +384,23 @@ void delete_added_keycodes(void);
double dtime(double *);
-void initialize_blackout(char *);
+void initialize_blackouts(char *);
+void initialize_blackouts_and_xinerama(void);
+void initialize_keyboard_and_pointer(void);
void initialize_modtweak(void);
void initialize_pointer_map(char *);
+void initialize_cursors_mode(void);
void initialize_remap(char *);
void initialize_screen(int *argc, char **argv, XImage *fb);
-void initialize_shm(void);
+void initialize_polling_images(void);
void initialize_signals(void);
void initialize_tiles(void);
+void free_tiles(void);
void initialize_watch_bell(void);
void initialize_xinerama(void);
+void initialize_xfixes(void);
+void initialize_xrandr(void);
+XImage *initialize_xdisplay_fb(void);
void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client);
@@ -335,14 +427,24 @@ void pointer(int mask, int x, int y, rfbClientPtr client);
void cursor_position(int, int);
void read_vnc_connect_prop(void);
+void set_vnc_connect_prop(char *);
+char *process_remote_cmd(char *, int);
void rfbPE(rfbScreenInfoPtr, long);
void rfbCFD(rfbScreenInfoPtr, long);
int scan_for_updates(void);
-void set_colormap(void);
+void set_colormap(int);
void set_offset(void);
+void set_rfb_cursor(int);
void set_visual(char *vstring);
void set_cursor(int, int, int);
+void set_no_cursor(void);
+void set_cursor_was_changed(rfbScreenInfoPtr);
int get_which_cursor(void);
+int get_xfixes_cursor(int);
+
+void disable_cursor_shape_updates(rfbScreenInfoPtr);
+void restore_cursor_shape_updates(rfbScreenInfoPtr);
+int new_fb_size_clients(rfbScreenInfoPtr);
void shm_clean(XShmSegmentInfo *, XImage *);
void shm_delete(XShmSegmentInfo *);
@@ -350,18 +452,40 @@ void shm_delete(XShmSegmentInfo *);
void check_x11_pointer(void);
void check_bell_event(void);
void check_xevents(void);
+char *this_host(void);
+
+int get_remote_port(int sock);
+int get_local_port(int sock);
+char *get_remote_host(int sock);
+char *get_local_host(int sock);
void xcut_receive(char *text, int len, rfbClientPtr client);
void zero_fb(int, int, int, int);
+void push_black_screen(int);
+void push_sleep(int);
+void refresh_screen(void);
/* -- options.h -- */
/*
* variables for the command line options
*/
+char *use_dpy = NULL;
+char *auth_file = NULL;
+char *visual_str = NULL;
+char *logfile = NULL;
+char *passwdfile = NULL;
+char *blackout_string = NULL;
+char *rc_rcfile = NULL;
+int rc_norc = 0;
+int opts_bg = 0;
int shared = 0; /* share vnc display. */
+int deny_all = 0; /* global locking of new clients */
+int accept_remote_cmds = 1; /* -noremote */
+int safe_remote_only = 0; /* -safer, -unsafe */
char *allow_list = NULL; /* for -allow and -localhost */
+char *allow_once = NULL; /* one time -allow */
char *accept_cmd = NULL; /* for -accept */
char *gone_cmd = NULL; /* for -gone */
int view_only = 0; /* clients can only watch. */
@@ -370,15 +494,26 @@ int inetd = 0; /* spawned from inetd(1) */
int connect_once = 1; /* disconnect after first connection session. */
int flash_cmap = 0; /* follow installed colormaps */
int force_indexed_color = 0; /* whether to force indexed color for 8bpp */
+int launch_gui = 0; /* -gui */
int use_modifier_tweak = 1; /* use the shift/altgr modifier tweak */
int use_iso_level3 = 0; /* ISO_Level3_Shift instead of Mode_switch */
int clear_mods = 0; /* -clear_mods (1) and -clear_keys (2) */
int nofb = 0; /* do not send any fb updates */
-int subwin = 0; /* -id */
+unsigned long subwin = 0x0; /* -id, -sid */
int xinerama = 0; /* -xinerama */
+int xrandr = 0; /* -xrandr */
+int xrandr_present = 0;
+int xrandr_width = -1;
+int xrandr_height = -1;
+int xrandr_rotation = -1;
+Time xrandr_timestamp = 0;
+Time xrandr_cfg_time = 0;
+char *xrandr_mode = NULL;
+char *pad_geometry = NULL;
+time_t pad_geometry_time;
char *client_connect = NULL; /* strings for -connect option */
char *client_connect_file = NULL;
@@ -386,21 +521,28 @@ int vnc_connect = 1; /* -vncconnect option */
int show_cursor = 1; /* show cursor shapes */
int show_multiple_cursors = 0; /* show X when on root background, etc */
-char *multiple_cursors_mode = "default";
+char *multiple_cursors_mode = NULL;
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_dragging = 1; /* process mouse movement events */
-int no_autorepeat = 0; /* turn off autorepeat with clients */
+int no_autorepeat = 1; /* turn off autorepeat with clients */
int watch_bell = 1; /* watch for the bell using XKEYBOARD */
+int sound_bell = 1; /* actually send it */
int xkbcompat = 0; /* ignore XKEYBOARD extension */
int use_xkb = 0; /* try to open Xkb connection (for bell or other) */
int use_xkb_modtweak = 0; /* -xkb */
char *skip_keycodes = NULL;
int add_keysyms = 0; /* automatically add keysyms to X server */
-int old_pointer = 0; /* use the old ways of updating the pointer */
+char *remap_file = NULL; /* -remap */
+char *pointer_remap = NULL;
+int pointer_mode = 2; /* use the various ways of updating pointer */
+int pointer_mode_max = 4;
int single_copytile = 0; /* use the old way copy_tiles() */
+int single_copytile_orig = 0;
+int single_copytile_count = 0;
+int tile_shm_count = 0;
int using_shm = 1; /* whether mit-shm is used */
int flip_byte_order = 0; /* sometimes needed when using_shm = 0 */
@@ -422,21 +564,33 @@ int ui_skip = 10; /* see watchloop. negative means ignore input */
int watch_selection = 1; /* normal selection/cutbuffer maintenance */
int watch_primary = 1; /* more dicey, poll for changes in PRIMARY */
-int sigpipe = 1; /* 0=skip, 1=ignore, 2=exit */
+char *sigpipe = NULL; /* skip, ignore, 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. */
+/* for -overlay mode on Solaris/IRIX. X server draws cursor correctly. */
int overlay = 0;
int overlay_cursor = 1;
+#ifdef LIBVNCSERVER_HAVE_XSHM
+int xshm_present = 1;
+#else
+int xshm_present = 0;
+#endif
#ifdef LIBVNCSERVER_HAVE_XTEST
int xtest_present = 1;
#else
int xtest_present = 0;
#endif
+#ifdef LIBVNCSERVER_HAVE_XKEYBOARD
+int xkb_present = 1;
+#else
+int xkb_present = 0;
+#endif
+int xinerama_present = 0;
+
/* tile heuristics: */
double fs_frac = 0.75; /* threshold tile fraction to do fullscreen updates. */
@@ -469,6 +623,7 @@ int got_nevershared = 0;
/* -- util.h -- */
+#define NONUL(x) ((x) ? (x) : "")
/* XXX usleep(3) is not thread safe on some older systems... */
struct timeval _mysleep;
@@ -497,7 +652,7 @@ MUTEX(x11Mutex);
#define X_UNLOCK UNLOCK(x11Mutex)
#define X_INIT INIT_MUTEX(x11Mutex)
-/* -- util.c -- ? */
+/* -- util.c -- */
/*
* routine to keep 0 <= i < n, should use in more places...
@@ -511,6 +666,14 @@ int nfix(int i, int n) {
return i;
}
+int nabs(int n) {
+ if (n < 0) {
+ return -n;
+ } else {
+ return n;
+ }
+}
+
void lowercase(char *str) {
char *p;
if (str == NULL) {
@@ -523,6 +686,235 @@ void lowercase(char *str) {
}
}
+int scan_hexdec(char *str, unsigned long *num) {
+ if (sscanf(str, "0x%lx", num) != 1) {
+ if (sscanf(str, "%ld", num) != 1) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+void set_env(char *name, char *value) {
+ char *str;
+ str = malloc(strlen(name)+strlen(value)+2);
+ sprintf(str, "%s=%s", name, value);
+ putenv(str);
+}
+
+int pick_windowid(unsigned long *num) {
+ char line[512];
+ int ok = 0, n = 0, msec = 10, secmax = 15;
+ FILE *p;
+
+ if (use_dpy) {
+ set_env("DISPLAY", use_dpy);
+ }
+ p = popen("xwininfo", "r");
+
+ if (! p) {
+ return 0;
+ }
+
+ fprintf(stderr, "\n");
+ fprintf(stderr, " Please select the window for x11vnc to poll\n");
+ fprintf(stderr, " by clicking the mouse in that window.\n");
+ fprintf(stderr, "\n");
+
+ while (msec * n++ < 1000 * secmax) {
+ unsigned long tmp;
+ char *q;
+ fd_set set;
+ struct timeval tv;
+
+ if (screen && screen->clientHead) {
+ /* they may be doing the pointer-pick thru vnc: */
+ tv.tv_sec = 0;
+ tv.tv_usec = msec * 1000;
+ FD_ZERO(&set);
+ FD_SET(fileno(p), &set);
+ if (select(fileno(p)+1, &set, NULL, NULL, &tv) == 0) {
+ /* note that rfbPE takes about 30ms too */
+ rfbPE(screen, -1);
+ continue;
+ }
+ }
+
+ if (fgets(line, 512, p) == NULL) {
+ break;
+ }
+ q = strstr(line, " id: 0x");
+ if (q) {
+ q += 5;
+ if (sscanf(q, "0x%lx ", &tmp) == 1) {
+ ok = 1;
+ *num = tmp;
+ fprintf(stderr, " Picked: 0x%lx\n\n", tmp);
+ break;
+ }
+ }
+ }
+ pclose(p);
+ return ok;
+}
+
+char *bitprint(unsigned int st, int nbits) {
+ static char str[33];
+ int i, mask;
+ if (nbits > 32) {
+ nbits = 32;
+ }
+ for (i=0; i<nbits; i++) {
+ str[i] = '0';
+ }
+ str[nbits] = '\0';
+ mask = 1;
+ for (i=nbits-1; i>=0; i--) {
+ if (st & mask) {
+ str[i] = '1';
+ }
+ mask = mask << 1;
+ }
+ return str; /* take care to use or copy immediately */
+}
+
+/*
+ * Simple utility to map host name to dotted IP address. Ignores aliases.
+ * Up to caller to free returned string.
+ */
+char *host2ip(char *host) {
+ struct hostent *hp;
+ struct sockaddr_in addr;
+ char *str;
+
+ hp = gethostbyname(host);
+ if (!hp) {
+ return NULL;
+ }
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = *(unsigned long *)hp->h_addr;
+ str = strdup(inet_ntoa(addr.sin_addr));
+ return str;
+}
+
+int dotted_ip(char *host) {
+ char *p = host;
+ while (*p != '\0') {
+ if (*p == '.' || isdigit(*p)) {
+ p++;
+ continue;
+ }
+ return 0;
+ }
+ return 1;
+}
+
+int get_remote_port(int sock) {
+ struct sockaddr_in saddr;
+ int saddr_len, saddr_port;
+
+ saddr_len = sizeof(saddr);
+ memset(&saddr, 0, sizeof(saddr));
+ saddr_port = -1;
+ if (!getpeername(sock, (struct sockaddr *)&saddr, &saddr_len)) {
+ saddr_port = ntohs(saddr.sin_port);
+ }
+ return saddr_port;
+}
+
+char *get_remote_host(int sock) {
+ struct sockaddr_in saddr;
+ int saddr_len, saddr_port;
+ char *saddr_ip_str = NULL;
+
+ saddr_len = sizeof(saddr);
+ memset(&saddr, 0, sizeof(saddr));
+ saddr_port = -1;
+ if (!getsockname(sock, (struct sockaddr *)&saddr, &saddr_len)) {
+#ifdef LIBVNCSERVER_HAVE_NETINET_IN_H
+ saddr_ip_str = inet_ntoa(saddr.sin_addr);
+#endif
+ }
+ if (! saddr_ip_str) {
+ saddr_ip_str = strdup("unknown");
+ }
+ return saddr_ip_str;
+}
+
+int get_local_port(int sock) {
+ struct sockaddr_in saddr;
+ int saddr_len, saddr_port;
+
+ saddr_len = sizeof(saddr);
+ memset(&saddr, 0, sizeof(saddr));
+ saddr_port = -1;
+ if (!getsockname(sock, (struct sockaddr *)&saddr, &saddr_len)) {
+ saddr_port = ntohs(saddr.sin_port);
+ }
+ return saddr_port;
+}
+
+char *get_local_host(int sock) {
+ struct sockaddr_in saddr;
+ int saddr_len, saddr_port;
+ char *saddr_ip_str = NULL;
+
+ saddr_len = sizeof(saddr);
+ memset(&saddr, 0, sizeof(saddr));
+ saddr_port = -1;
+ if (!getsockname(sock, (struct sockaddr *)&saddr, &saddr_len)) {
+#ifdef LIBVNCSERVER_HAVE_NETINET_IN_H
+ saddr_ip_str = inet_ntoa(saddr.sin_addr);
+#endif
+ }
+ if (! saddr_ip_str) {
+ saddr_ip_str = strdup("unknown");
+ }
+ return saddr_ip_str;
+}
+
+/*
+ * used in rfbGetScreen and rfbNewFramebuffer: and estimate to the number
+ * of bits per color, of course for some visuals, e.g. 565, the number
+ * is not the same for each color. This is just a sane default.
+ */
+int guess_bits_per_color(int bits_per_pixel) {
+ int bits_per_color;
+
+ /* first guess, spread them "evenly" over R, G, and B */
+ bits_per_color = bits_per_pixel/3;
+ if (bits_per_color < 1) {
+ bits_per_color = 1; /* 1bpp, 2bpp... */
+ }
+
+ /* choose safe values for usual cases: */
+ if (bits_per_pixel == 8) {
+ bits_per_color = 2;
+ } else if (bits_per_pixel == 15 || bits_per_pixel == 16) {
+ bits_per_color = 5;
+ } else if (bits_per_pixel == 24 || bits_per_pixel == 32) {
+ bits_per_color = 8;
+ }
+ return bits_per_color;
+}
+
+/* count number of clients supporting NewFBSize */
+int new_fb_size_clients(rfbScreenInfoPtr s) {
+ rfbClientIteratorPtr iter;
+ rfbClientPtr cl;
+ int count = 0;
+
+ iter = rfbGetClientIterator(s);
+ while( (cl = rfbClientIteratorNext(iter)) ) {
+ if (cl->useNewFBSize) {
+ count++;
+ }
+ }
+ rfbReleaseClientIterator(iter);
+ return count;
+}
+
/*
* Kludge to interpose image gets and limit to a subset rectangle of
* the rootwin. This is the -sid option trying to work around invisible
@@ -537,6 +929,8 @@ int rootshift = 0;
y += off_y; \
}
+/* -- ximage.c -- */
+
/*
* Wrappers for Image related X calls
*/
@@ -545,7 +939,7 @@ Status XShmGetImage_wr(Display *disp, Drawable d, XImage *image, int x, int y,
ADJUST_ROOTSHIFT
- /* The Solaris overlay stuff is all non-shm (using_shm = 0) */
+ /* Note: the Solaris overlay stuff is all non-shm (using_shm = 0) */
#ifdef LIBVNCSERVER_HAVE_XSHM
return XShmGetImage(disp, d, image, x, y, mask);
@@ -590,18 +984,39 @@ Bool XShmQueryExtension_wr(Display *disp) {
#endif
}
+/* wrapper for overlay screen reading: */
+
+XImage *xreadscreen(Display *disp, Drawable d, int x, int y,
+ unsigned int width, unsigned int height, Bool show_cursor) {
+#ifdef SOLARIS_OVERLAY
+ return XReadScreen(disp, d, x, y, width, height,
+ show_cursor);
+#endif
+#ifdef IRIX_OVERLAY
+ { unsigned long hints = 0, hints_ret;
+ if (show_cursor) hints |= XRD_READ_POINTER;
+ return XReadDisplay(disp, d, x, y, width, height,
+ hints, &hints_ret);
+ }
+#endif
+ return NULL;
+}
+
XImage *XGetSubImage_wr(Display *disp, Drawable d, int x, int y,
unsigned int width, unsigned int height, unsigned long plane_mask,
int format, XImage *dest_image, int dest_x, int dest_y) {
ADJUST_ROOTSHIFT
-#ifdef SOLARIS
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,
+ XImage *xi;
+
+ xi = xreadscreen(disp, d, x, y, width, height,
(Bool) overlay_cursor);
+ if (! xi) return NULL;
+
/*
* There is extra overhead from memcpy and free...
* this is not like the real XGetSubImage(). We hope
@@ -613,7 +1028,6 @@ XImage *XGetSubImage_wr(Display *disp, Drawable d, int x, int y,
XDestroyImage(xi);
return (dest_image);
}
-#endif
return XGetSubImage(disp, d, x, y, width, height, plane_mask,
format, dest_image, dest_x, dest_y);
}
@@ -624,28 +1038,26 @@ XImage *XGetImage_wr(Display *disp, Drawable d, int x, int y,
ADJUST_ROOTSHIFT
-#ifdef SOLARIS
if (overlay) {
- return XReadScreen(disp, d, x, y, width, height,
+ return xreadscreen(disp, d, x, y, width, height,
(Bool) overlay_cursor);
}
-#endif
return XGetImage(disp, d, x, y, width, height, plane_mask, format);
}
XImage *XCreateImage_wr(Display *disp, Visual *visual, unsigned int depth,
int format, int offset, char *data, unsigned int width,
unsigned int height, int bitmap_pad, int bytes_per_line) {
-/*
- * This is a kludge to get a created XImage to exactly match what
- * XReadScreen returns: we noticed the rgb masks are different from
- * XCreateImage with the high color visual (red mask <-> blue mask).
- * Note we read from the root window(!) then free the data.
- */
-#ifdef SOLARIS
+ /*
+ * This is a kludge to get a created XImage to exactly match what
+ * XReadScreen returns: we noticed the rgb masks are different
+ * from XCreateImage with the high color visual (red mask <->
+ * blue mask). Note we read from the root window(!) then free
+ * the data.
+ */
if (overlay) {
XImage *xi;
- xi = XReadScreen(disp, window, 0, 0, width, height, False);
+ xi = xreadscreen(disp, window, 0, 0, width, height, False);
if (xi == NULL) {
return xi;
}
@@ -655,7 +1067,6 @@ XImage *XCreateImage_wr(Display *disp, Visual *visual, unsigned int depth,
xi->data = data;
return xi;
}
-#endif
return XCreateImage(disp, visual, depth, format, offset, data,
width, height, bitmap_pad, bytes_per_line);
@@ -764,23 +1175,53 @@ void XTestDiscard_wr(Display *dpy) {
static int exit_flag = 0;
int exit_sig = 0;
+void clean_shm(int quick) {
+ int i, cnt = 0;
+
+ /*
+ * to avoid deadlock, etc, under quick=1 we just delete the shm
+ * areas and leave the X stuff hanging.
+ */
+ if (quick) {
+ shm_delete(&scanline_shm);
+ shm_delete(&fullscreen_shm);
+ } else {
+ shm_clean(&scanline_shm, scanline);
+ shm_clean(&fullscreen_shm, fullscreen);
+ }
+
+ /*
+ * Here we have to clean up quite a few shm areas for all
+ * the possible tile row runs (40 for 1280), not as robust
+ * as one might like... sometimes need to run ipcrm(1).
+ */
+ for(i=1; i<=ntiles_x; i++) {
+ if (i > tile_shm_count) {
+ break;
+ }
+ if (quick) {
+ shm_delete(&tile_row_shm[i]);
+ } else {
+ shm_clean(&tile_row_shm[i], tile_row[i]);
+ }
+ cnt++;
+ if (single_copytile_count && i >= single_copytile_count) {
+ break;
+ }
+ }
+ if (!quiet && !quick) {
+ rfbLog("deleted %d tile_row polling images.\n", cnt);
+ }
+}
+
/*
* Normal exiting
*/
void clean_up_exit (int ret) {
- int i;
exit_flag = 1;
/* remove the shm areas: */
- shm_clean(&scanline_shm, scanline);
- shm_clean(&fullscreen_shm, fullscreen);
-
- for(i=1; i<=ntiles_x; i++) {
- shm_clean(&tile_row_shm[i], tile_row[i]);
- if (single_copytile && i >= single_copytile) {
- break;
- }
- }
+ clean_shm(0);
/* X keyboard cleanups */
delete_added_keycodes();
@@ -807,7 +1248,6 @@ void clean_up_exit (int ret) {
* General problem handler
*/
static void interrupted (int sig) {
- int i;
exit_sig = sig;
if (exit_flag) {
exit_flag++;
@@ -828,24 +1268,11 @@ static void interrupted (int sig) {
shut_down = 1;
return;
}
- /*
- * to avoid deadlock, etc, just delete the shm areas and
- * leave the X stuff hanging.
- */
- shm_delete(&scanline_shm);
- shm_delete(&fullscreen_shm);
- /*
- * Here we have to clean up quite a few shm areas for all
- * the possible tile row runs (40 for 1280), not as robust
- * as one might like... sometimes need to run ipcrm(1).
- */
- for(i=1; i<=ntiles_x; i++) {
- shm_delete(&tile_row_shm[i]);
- if (single_copytile && i >= single_copytile) {
- break;
- }
- }
+ X_UNLOCK;
+
+ /* remove the shm areas with quick=1: */
+ clean_shm(1);
/* X keyboard cleanups */
delete_added_keycodes();
@@ -858,6 +1285,7 @@ static void interrupted (int sig) {
if (no_autorepeat) {
autorepeat(1);
}
+
if (sig) {
exit(2);
}
@@ -867,10 +1295,19 @@ static void interrupted (int sig) {
static XErrorHandler Xerror_def;
static XIOErrorHandler XIOerr_def;
+XErrorEvent *trapped_xerror_event;
int trapped_xerror = 0;
+int trapped_getimage_xerror = 0;
int trap_xerror(Display *d, XErrorEvent *error) {
trapped_xerror = 1;
+ trapped_xerror_event = error;
+ return 0;
+}
+
+int trap_getimage_xerror(Display *d, XErrorEvent *error) {
+ trapped_getimage_xerror = 1;
+ trapped_xerror_event = error;
return 0;
}
@@ -886,6 +1323,74 @@ static int XIOerr(Display *d) {
return (*XIOerr_def)(d);
}
+char *xerrors[] = {
+ "Success",
+ "BadRequest",
+ "BadValue",
+ "BadWindow",
+ "BadPixmap",
+ "BadAtom",
+ "BadCursor",
+ "BadFont",
+ "BadMatch",
+ "BadDrawable",
+ "BadAccess",
+ "BadAlloc",
+ "BadColor",
+ "BadGC",
+ "BadIDChoice",
+ "BadName",
+ "BadLength",
+ "BadImplementation",
+ "unknown"
+};
+int xerrors_max = BadImplementation;
+
+char *xerror_string(XErrorEvent *error) {
+ int index = -1;
+ if (error) {
+ index = (int) error->error_code;
+ }
+ if (0 <= index && index <= xerrors_max) {
+ return xerrors[index];
+ } else {
+ return xerrors[xerrors_max+1];
+ }
+}
+
+/* trapping utility to check for a valid window: */
+int valid_window(Window win) {
+ XErrorHandler old_handler;
+ XWindowAttributes attr;
+ int ok = 0;
+
+ trapped_xerror = 0;
+ old_handler = XSetErrorHandler(trap_xerror);
+ if (XGetWindowAttributes(dpy, win, &attr)) {
+ ok = 1;
+ }
+ if (trapped_xerror && trapped_xerror_event && ! quiet) {
+ rfbLog("trapped XError: %s (0x%lx)\n",
+ xerror_string(trapped_xerror_event), win);
+ }
+ XSetErrorHandler(old_handler);
+ trapped_xerror = 0;
+
+ return ok;
+}
+
+int get_window_size(Window win, int *x, int *y) {
+ XWindowAttributes attr;
+ /* valid_window? */
+ if (XGetWindowAttributes(dpy, win, &attr)) {
+ *x = attr.width;
+ *y = attr.height;
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
/* signal handlers */
void initialize_signals(void) {
signal(SIGHUP, interrupted);
@@ -897,11 +1402,13 @@ void initialize_signals(void) {
signal(SIGSEGV, interrupted);
signal(SIGFPE, interrupted);
- if (sigpipe == 1) {
+ if (!sigpipe || *sigpipe == '\0' || !strcmp(sigpipe, "skip")) {
+ ;
+ } else if (!strcmp(sigpipe, "ignore")) {
#ifdef SIG_IGN
signal(SIGPIPE, SIG_IGN);
#endif
- } else if (sigpipe == 2) {
+ } else if (!strcmp(sigpipe, "exit")) {
rfbLog("initialize_signals: will exit on SIGPIPE\n");
signal(SIGPIPE, interrupted);
}
@@ -919,6 +1426,7 @@ void initialize_signals(void) {
static int accepted_client = 0;
static int client_count = 0;
+static int clients_served = 0;
/*
* check that all clients are in RFB_NORMAL state
@@ -940,11 +1448,110 @@ int all_clients_initialized(void) {
return ok;
}
+char *list_clients(void) {
+ rfbClientIteratorPtr iter;
+ rfbClientPtr cl;
+ char *list, tmp[32];
+ int count = 0;
+
+ iter = rfbGetClientIterator(screen);
+ while( (cl = rfbClientIteratorNext(iter)) ) {
+ count++;
+ }
+ rfbReleaseClientIterator(iter);
+
+ list = (char *) malloc((count+1)*100);
+
+ list[0] = '\0';
+
+ iter = rfbGetClientIterator(screen);
+ while( (cl = rfbClientIteratorNext(iter)) ) {
+ ClientData *cd = (ClientData *) cl->clientData;
+ if (*list != '\0') {
+ strcat(list, ",");
+ }
+ strcat(list, cl->host);
+ sprintf(tmp, ":%d/0x%x", get_remote_port(cl->sock), cd->uid);
+ strcat(list, tmp);
+ if (cl->viewOnly) {
+ strcat(list, "-ro");
+ } else {
+ strcat(list, "-rw");
+ }
+ }
+ rfbReleaseClientIterator(iter);
+ return list;
+}
+
+void close_all_clients(void) {
+ rfbClientIteratorPtr iter;
+ rfbClientPtr cl;
+
+ iter = rfbGetClientIterator(screen);
+ while( (cl = rfbClientIteratorNext(iter)) ) {
+ rfbCloseClient(cl);
+ rfbClientConnectionGone(cl);
+ }
+ rfbReleaseClientIterator(iter);
+}
+
+void close_clients(char *str) {
+ rfbClientIteratorPtr iter;
+ rfbClientPtr cl;
+ int host_warn = 0, hex_warn = 0;
+
+ if (!strcmp(str, "all") || !strcmp(str, "*")) {
+ close_all_clients();
+ return;
+ }
+
+ iter = rfbGetClientIterator(screen);
+ while( (cl = rfbClientIteratorNext(iter)) ) {
+ if (strstr(str, "0x")) {
+ int id;
+ ClientData *cd = (ClientData *) cl->clientData;
+ if (sscanf(str, "0x%x", &id) != 1) {
+ if (hex_warn++) {
+ continue;
+ }
+ rfbLog("skipping bad client hex id: %s\n", str);
+ continue;
+ }
+ if ( cd->uid == id) {
+ rfbCloseClient(cl);
+ rfbClientConnectionGone(cl);
+ }
+ } else {
+ char *rstr = str;
+ if (! dotted_ip(str)) {
+ rstr = host2ip(str);
+ if (rstr == NULL) {
+ if (host_warn++) {
+ continue;
+ }
+ rfbLog("skipping bad lookup: \"%s\"\n",
+ str);
+ continue;
+ }
+ rfbLog("lookup: %s -> %s\n", str, rstr);
+ }
+ if (!strcmp(rstr, cl->host)) {
+ rfbCloseClient(cl);
+ rfbClientConnectionGone(cl);
+ }
+ if (rstr != str) {
+ free(rstr);
+ }
+ }
+ }
+ rfbReleaseClientIterator(iter);
+}
+
/*
* utility to run a user supplied command setting some RFB_ env vars.
* used by, e.g., accept_client() and client_gone()
*/
-static int run_user_command(char *cmd, rfbClientPtr client) {
+static int run_user_command(char *cmd, rfbClientPtr client, char *mode) {
char *dpystr = DisplayString(dpy);
static char *display_env = NULL;
static char env_rfb_client_id[100];
@@ -954,18 +1561,24 @@ static int run_user_command(char *cmd, rfbClientPtr client) {
static char env_rfb_server_port[100];
static char env_rfb_x11vnc_pid[100];
static char env_rfb_client_count[100];
+ static char env_rfb_mode[100];
char *addr = client->host;
- int rc;
- char *saddr_ip_str = NULL;
- int saddr_len, saddr_port;
- struct sockaddr_in saddr;
+ int rc, hport;
+ char *ip_str = NULL;
+ ClientData *cd = (ClientData *) client->clientData;
if (addr == NULL || addr[0] == '\0') {
addr = "unknown-host";
}
/* set RFB_CLIENT_ID to semi unique id for command to use */
- sprintf(env_rfb_client_id, "RFB_CLIENT_ID=%p", (void *) client);
+ if (cd && cd->uid) {
+ sprintf(env_rfb_client_id, "RFB_CLIENT_ID=0x%x", cd->uid);
+ } else {
+ /* not accepted yet: */
+ sprintf(env_rfb_client_id, "RFB_CLIENT_ID=0x%x",
+ clients_served);
+ }
putenv(env_rfb_client_id);
/* set RFB_CLIENT_IP to IP addr for command to use */
@@ -977,34 +1590,25 @@ static int run_user_command(char *cmd, rfbClientPtr client) {
putenv(env_rfb_x11vnc_pid);
/* set RFB_CLIENT_PORT to peer port for command to use */
- saddr_len = sizeof(saddr);
- memset(&saddr, 0, sizeof(saddr));
- saddr_port = -1;
- if (!getpeername(client->sock, (struct sockaddr *)&saddr, &saddr_len)) {
- saddr_port = ntohs(saddr.sin_port);
- }
- sprintf(env_rfb_client_port, "RFB_CLIENT_PORT=%d", saddr_port);
+ hport = get_remote_port(client->sock);
+ sprintf(env_rfb_client_port, "RFB_CLIENT_PORT=%d", hport);
putenv(env_rfb_client_port);
+ sprintf(env_rfb_mode, "RFB_MODE=%s", mode);
+ putenv(env_rfb_mode);
+
/*
* now do RFB_SERVER_IP and RFB_SERVER_PORT (i.e. us!)
* This will establish a 5-tuple (including tcp) the external
* program can potentially use to work out the virtual circuit
* for this connection.
*/
- saddr_len = sizeof(saddr);
- memset(&saddr, 0, sizeof(saddr));
- saddr_port = -1;
- saddr_ip_str = "unknown";
- if (!getsockname(client->sock, (struct sockaddr *)&saddr, &saddr_len)) {
- saddr_port = ntohs(saddr.sin_port);
-#ifdef LIBVNCSERVER_HAVE_NETINET_IN_H
- saddr_ip_str = inet_ntoa(saddr.sin_addr);
-#endif
- }
- sprintf(env_rfb_server_ip, "RFB_SERVER_IP=%s", saddr_ip_str);
+ ip_str = get_local_host(client->sock);
+ hport = get_local_port(client->sock);
+
+ sprintf(env_rfb_server_ip, "RFB_SERVER_IP=%s", ip_str);
putenv(env_rfb_server_ip);
- sprintf(env_rfb_server_port, "RFB_SERVER_PORT=%d", saddr_port);
+ sprintf(env_rfb_server_port, "RFB_SERVER_PORT=%d", hport);
putenv(env_rfb_server_port);
@@ -1039,7 +1643,6 @@ static int run_user_command(char *cmd, rfbClientPtr client) {
return rc;
}
-
/*
* callback for when a client disconnects
*/
@@ -1048,12 +1651,16 @@ static void client_gone(rfbClientPtr client) {
client_count--;
rfbLog("client_count: %d\n", client_count);
+ if (client->clientData) {
+ free(client->clientData);
+ }
+
if (no_autorepeat && client_count == 0) {
autorepeat(1);
}
- if (gone_cmd) {
+ if (gone_cmd && *gone_cmd != '\0') {
rfbLog("client_gone: using cmd for: %s\n", client->host);
- run_user_command(gone_cmd, client);
+ run_user_command(gone_cmd, client, "gone");
}
if (inetd) {
@@ -1074,6 +1681,11 @@ static void client_gone(rfbClientPtr client) {
accepted_client = 0;
return;
}
+ if (shared && client_count > 0) {
+ rfbLog("connect_once: other shared clients still "
+ "connected, not exiting.\n");
+ return;
+ }
rfbLog("viewer exited.\n");
clean_up_exit(0);
@@ -1088,8 +1700,19 @@ static int check_access(char *addr) {
int allowed = 0;
char *p, *list;
+ if (deny_all) {
+ rfbLog("check_access: new connections are currently "
+ "blocked.\n");
+ return 0;
+ }
+
if (allow_list == NULL || *allow_list == '\0') {
- return 1;
+ if (allow_once == NULL) {
+ return 1;
+ }
+ }
+ if (allow_list == NULL) {
+ allow_list = strdup("");
}
if (addr == NULL || *addr == '\0') {
rfbLog("check_access: denying empty host IP address string.\n");
@@ -1110,6 +1733,9 @@ static int check_access(char *addr) {
clean_up_exit(1);
}
len = sbuf.st_size + 1; /* 1 more for '\0' at end */
+ if (allow_once) {
+ len += strlen(allow_once) + 2;
+ }
list = malloc(len);
list[0] = '\0';
@@ -1129,17 +1755,46 @@ static int check_access(char *addr) {
strcat(list, line);
}
fclose(in);
+ if (allow_once) {
+ strcat(list, allow_once);
+ strcat(list, "\n");
+ }
} else {
- list = strdup(allow_list);
+ int len = strlen(allow_list);
+ if (allow_once) {
+ len += strlen(allow_once) + 2;
+ }
+ list = malloc(len);
+ list[0] = '\0';
+ strcat(list, allow_list);
+ if (allow_once) {
+ strcat(list, ",");
+ strcat(list, allow_once);
+ }
}
+ if (allow_once) {
+ free(allow_once);
+ allow_once = NULL;
+ }
p = strtok(list, ", \t\n\r");
while (p) {
- char *q;
+ char *q, *r = NULL;
if (*p == '\0') {
+ p = strtok(NULL, ", \t\n\r");
continue;
}
+ if (! dotted_ip(p)) {
+ r = host2ip(p);
+ if (r == NULL) {
+ rfbLog("check_access: bad lookup \"%s\"\n", p);
+ p = strtok(NULL, ", \t\n\r");
+ continue;
+ }
+ rfbLog("check_access: lookup %s -> %s\n", p, r);
+ p = r;
+ }
q = strstr(addr, p);
if (q == addr) {
rfbLog("check_access: client %s matches pattern %s\n",
@@ -1150,6 +1805,12 @@ static int check_access(char *addr) {
allowed = 1;
}
p = strtok(NULL, ", \t\n\r");
+ if (r) {
+ free(r);
+ }
+ if (allowed) {
+ break;
+ }
}
free(list);
return allowed;
@@ -1157,7 +1818,7 @@ static int check_access(char *addr) {
/*
* x11vnc's first (and only) visible widget: accept/reject dialog window.
- * We go through this pain to avoid dependency on libXt.
+ * We go through this pain to avoid dependency on libXt...
*/
static int ugly_accept_window(char *addr, int X, int Y, int timeout,
char *mode) {
@@ -1364,8 +2025,8 @@ static char t2x2_bits[] = {
strlen(str_v));
tw = (Vi_w - tw)/2;
if (tw < 0) tw = 1;
- XDrawString(dpy, awin, gc, Vi_x+tw, Vi_y+Vi_h-5,
- str_v, strlen(str_v));
+ XDrawString(dpy, awin, gc, Vi_x+tw,
+ Vi_y+Vi_h-5, str_v, strlen(str_v));
}
break;
@@ -1529,7 +2190,7 @@ static int accept_client(rfbClientPtr client) {
char *addr = client->host;
char *action = NULL;
- if (accept_cmd == NULL) {
+ if (accept_cmd == NULL || *accept_cmd == '\0') {
return 1; /* no command specified, so we accept */
}
@@ -1637,7 +2298,7 @@ static int accept_client(rfbClientPtr client) {
int rc;
rfbLog("accept_client: using cmd for: %s\n", addr);
- rc = run_user_command(cmd, client);
+ rc = run_user_command(cmd, client, "accept");
if (action) {
int result;
@@ -1689,6 +2350,9 @@ static void check_connect_file(char *file) {
static time_t last_time = 0;
time_t now = time(0);
+ if (last_time == 0) {
+ last_time = now;
+ }
if (now - last_time < 1) {
/* check only once a second */
return;
@@ -1717,8 +2381,9 @@ static void check_connect_file(char *file) {
if (fgets(line, 1024, in) != NULL) {
if (sscanf(line, "%s", host) == 1) {
if (strlen(host) > 0) {
- client_connect = strdup(host);
+ char *str = strdup(host);
rfbLog("read connect file: %s\n", host);
+ client_connect = str;
}
}
}
@@ -1836,6 +2501,11 @@ static void reverse_connect(char *str) {
* Routines for monitoring the VNC_CONNECT property for changes.
* The vncconnect(1) will set it on our X display.
*/
+void set_vnc_connect_prop(char *str) {
+ XChangeProperty(dpy, rootwin, vnc_connect_prop, XA_STRING, 8,
+ PropModeReplace, (unsigned char *)str, strlen(str));
+}
+
void read_vnc_connect_prop(void) {
Atom type;
int format, slen, dlen;
@@ -1873,7 +2543,15 @@ void read_vnc_connect_prop(void) {
} while (bytes_after > 0);
vnc_connect_str[VNC_CONNECT_MAX] = '\0';
- rfbLog("read property VNC_CONNECT: %s\n", vnc_connect_str);
+ if (strlen(vnc_connect_str) > 100) {
+ char trim[101];
+ trim[0] = '\0';
+ strncat(trim, vnc_connect_str, 100);
+ rfbLog("read X property VNC_CONNECT: %s ...\n", trim);
+
+ } else {
+ rfbLog("read X property VNC_CONNECT: %s\n", vnc_connect_str);
+ }
}
/*
@@ -1881,7 +2559,14 @@ void read_vnc_connect_prop(void) {
*/
static void send_client_connect(void) {
if (client_connect != NULL) {
- reverse_connect(client_connect);
+ char *str = client_connect;
+ if (strstr(str, "cmd=") == str || strstr(str, "qry=") == str) {
+ process_remote_cmd(client_connect, 0);
+ } else if (strstr(str, "ans=") || strstr(str, "aro=") == str) {
+ ;
+ } else {
+ reverse_connect(client_connect);
+ }
free(client_connect);
client_connect = NULL;
}
@@ -1913,6 +2598,7 @@ void check_connect_inputs(void) {
* libvncserver callback for when a new client connects
*/
enum rfbNewClientAction new_client(rfbClientPtr client) {
+ ClientData *cd;
last_event = last_input = time(0);
if (inetd) {
@@ -1923,6 +2609,8 @@ enum rfbNewClientAction new_client(rfbClientPtr client) {
client->clientGoneHook = client_gone;
}
+ clients_served++;
+
if (connect_once) {
if (screen->dontDisconnect && screen->neverShared) {
if (! shared && accepted_client) {
@@ -1946,11 +2634,12 @@ enum rfbNewClientAction new_client(rfbClientPtr client) {
}
if (view_only) {
- client->clientData = (void *) -1;
client->viewOnly = TRUE;
- } else {
- client->clientData = (void *) 0;
}
+ client->clientData = (void *) calloc(sizeof(ClientData), 1);
+ cd = (ClientData *) client->clientData;
+
+ cd->uid = clients_served;
client->clientGoneHook = client_gone;
client_count++;
@@ -1960,6 +2649,10 @@ enum rfbNewClientAction new_client(rfbClientPtr client) {
autorepeat(0);
}
+ if (pad_geometry) {
+ install_padded_fb(pad_geometry);
+ }
+
accepted_client = 1;
last_client = time(0);
@@ -2253,6 +2946,21 @@ void initialize_remap(char *infile) {
KeySym ksym1, ksym2;
keyremap_t *remap, *current;
+ if (keyremaps != NULL) {
+ /* free last remapping */
+ keyremap_t *next_remap, *curr_remap = keyremaps;
+ while (curr_remap != NULL) {
+ next_remap = curr_remap->next;
+ free(curr_remap);
+ curr_remap = next_remap;
+ }
+ keyremaps = NULL;
+ }
+ if (infile == NULL || *infile == '\0') {
+ /* just unset remapping */
+ return;
+ }
+
in = fopen(infile, "r");
if (in == NULL) {
/* assume cmd line key1-key2,key3-key4 */
@@ -2581,11 +3289,11 @@ xkbmodifiers[] For the KeySym bound to this (keycode,group,level) store
if (debug_keyboard > 1) {
fprintf(stderr, " %03d G%d L%d mod=%s ",
- kc, grp+1, lvl+1, bitprint(ms));
+ kc, grp+1, lvl+1, bitprint(ms, 8));
fprintf(stderr, "state=%s ",
- bitprint(xkbstate[kc][grp][lvl]));
+ bitprint(xkbstate[kc][grp][lvl], 8));
fprintf(stderr, "ignore=%s ",
- bitprint(xkbignore[kc][grp][lvl]));
+ bitprint(xkbignore[kc][grp][lvl], 8));
fprintf(stderr, " ks=0x%08lx \"%s\"\n",
ks, XKeysymToString(ks));
}
@@ -2688,9 +3396,9 @@ static void xkb_tweak_keyboard(rfbBool down, rfbKeySym keysym,
XKeysymToString(keysym), XKeysymToString(
XKeycodeToKeysym(dpy, kc, 0)));
fprintf(stderr, " need state: %s\n",
- bitprint(state));
+ bitprint(state, 8));
fprintf(stderr, " ignorable : %s\n",
- bitprint(xkbignore[kc][grp][lvl]));
+ bitprint(xkbignore[kc][grp][lvl], 8));
}
/* save it if state is OK and not told to skip */
@@ -2719,11 +3427,11 @@ static void xkb_tweak_keyboard(rfbBool down, rfbKeySym keysym,
#define PKBSTATE \
fprintf(stderr, " --- current mod state:\n"); \
- fprintf(stderr, " mods : %s\n", bitprint(kbstate.mods)); \
- fprintf(stderr, " base_mods : %s\n", bitprint(kbstate.base_mods)); \
- fprintf(stderr, " latch_mods: %s\n", bitprint(kbstate.latched_mods)); \
- fprintf(stderr, " lock_mods : %s\n", bitprint(kbstate.locked_mods)); \
- fprintf(stderr, " compat : %s\n", bitprint(kbstate.compat_state));
+ fprintf(stderr, " mods : %s\n", bitprint(kbstate.mods, 8)); \
+ fprintf(stderr, " base_mods : %s\n", bitprint(kbstate.base_mods, 8)); \
+ fprintf(stderr, " latch_mods: %s\n", bitprint(kbstate.latched_mods, 8)); \
+ fprintf(stderr, " lock_mods : %s\n", bitprint(kbstate.locked_mods, 8)); \
+ fprintf(stderr, " compat : %s\n", bitprint(kbstate.compat_state, 8));
/*
* Now get the current state of the keyboard from the X server.
@@ -2902,7 +3610,7 @@ static void xkb_tweak_keyboard(rfbBool down, rfbKeySym keysym,
if (debug_keyboard > 1) {
fprintf(stderr, " +++ needmods: mod=%d %s "
- "need it to be: %d %s\n", i, bitprint(b),
+ "need it to be: %d %s\n", i, bitprint(b, 8),
needmods[i], needmods[i] ? "down" : "up");
}
@@ -2958,7 +3666,7 @@ static void xkb_tweak_keyboard(rfbBool down, rfbKeySym keysym,
fprintf(stderr, " === for "
"mod=%s found kc=%03d/G%d"
"/L%d it is %d %s skip=%d "
- "(%s)\n", bitprint(b), kc,
+ "(%s)\n", bitprint(b,8), kc,
grp+1, lvl+1, kt, kt ?
"down" : "up ", skip,
str ? str : "null");
@@ -3104,21 +3812,41 @@ static char modifiers[0x100];
static KeyCode keycodes[0x100];
static KeyCode left_shift_code, right_shift_code, altgr_code, iso_level3_code;
-char *bitprint(unsigned int st) {
- static char str[9];
- int i, mask;
- for (i=0; i<8; i++) {
- str[i] = '0';
+/* workaround for X11R5, Latin 1 only */
+#ifndef XConvertCase
+#define XConvertCase(sym, lower, upper) \
+*(lower) = sym; \
+*(upper) = sym; \
+if (sym >> 8 == 0) { \
+ if ((sym >= XK_A) && (sym <= XK_Z)) \
+ *(lower) += (XK_a - XK_A); \
+ else if ((sym >= XK_a) && (sym <= XK_z)) \
+ *(upper) -= (XK_a - XK_A); \
+ else if ((sym >= XK_Agrave) && (sym <= XK_Odiaeresis)) \
+ *(lower) += (XK_agrave - XK_Agrave); \
+ else if ((sym >= XK_agrave) && (sym <= XK_odiaeresis)) \
+ *(upper) -= (XK_agrave - XK_Agrave); \
+ else if ((sym >= XK_Ooblique) && (sym <= XK_Thorn)) \
+ *(lower) += (XK_oslash - XK_Ooblique); \
+ else if ((sym >= XK_oslash) && (sym <= XK_thorn)) \
+ *(upper) -= (XK_oslash - XK_Ooblique); \
+}
+#endif
+
+void initialize_keyboard_and_pointer(void) {
+ if (use_modifier_tweak) {
+ initialize_modtweak();
}
- str[8] = '\0';
- mask = 1;
- for (i=7; i>=0; i--) {
- if (st & mask) {
- str[i] = '1';
- }
- mask = mask << 1;
+ if (remap_file != NULL) {
+ initialize_remap(remap_file);
+ }
+
+ initialize_pointer_map(pointer_remap);
+
+ clear_modifiers(1);
+ if (clear_mods == 1) {
+ clear_modifiers(0);
}
- return str;
}
void initialize_modtweak(void) {
@@ -3278,7 +4006,7 @@ static void modifier_tweak_keyboard(rfbBool down, rfbKeySym keysym,
if (view_only) {
return;
}
- if (client->viewOnly) {
+ if (client && client->viewOnly) {
return;
}
@@ -3348,7 +4076,7 @@ void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) {
if (view_only) {
return;
}
- if (client->viewOnly) {
+ if (client && client->viewOnly) {
return;
}
@@ -3641,7 +4369,7 @@ void initialize_pointer_map(char *pointer_remap) {
pointer_map[i][0].up = 0;
}
- if (pointer_remap) {
+ if (pointer_remap && *pointer_remap != '\0') {
/* -buttonmap, format is like: 12-21=2 */
char *p, *q, *remap = pointer_remap;
int n;
@@ -3843,7 +4571,7 @@ void pointer(int mask, int x, int y, rfbClientPtr client) {
* See check_user_input() for the more complicated things we do
* in the non-threaded case.
*/
- if (use_threads && old_pointer != 1) {
+ if (use_threads && pointer_mode != 1) {
# define NEV 32
/* storage for the event queue */
static int mutex_init = 0;
@@ -3940,22 +4668,24 @@ void initialize_xkb(void) {
int ir, reason;
int op, ev, er, maj, min;
- if (! use_xkb) {
- return;
- }
if (! XkbQueryExtension(dpy, &op, &ev, &er, &maj, &min)) {
- if (! quiet) {
- fprintf(stderr, "warning: XKEYBOARD"
- " extension not present.\n");
+ if (! quiet && use_xkb) {
+ rfbLog("warning: XKEYBOARD extension not present.\n");
}
+ xkb_present = 0;
use_xkb = 0;
return;
+ } else {
+ xkb_present = 1;
+ }
+ if (! use_xkb) {
+ return;
}
if (! XkbOpenDisplay(DisplayString(dpy), &xkb_base_event_type, &ir,
NULL, NULL, &reason) ) {
if (! quiet) {
- fprintf(stderr, "warning: disabling XKEYBOARD."
- " XkbOpenDisplay failed.\n");
+ rfbLog("warning: disabling XKEYBOARD. XkbOpenDisplay"
+ " failed.\n");
}
use_xkb = 0;
}
@@ -3964,8 +4694,8 @@ void initialize_xkb(void) {
void initialize_watch_bell(void) {
if (! use_xkb) {
if (! quiet) {
- fprintf(stderr, "warning: disabling bell."
- " XKEYBOARD ext. not present.\n");
+ rfbLog("warning: disabling bell. XKEYBOARD ext. "
+ "not present.\n");
}
watch_bell = 0;
return;
@@ -3973,8 +4703,8 @@ void initialize_watch_bell(void) {
if (! XkbSelectEvents(dpy, XkbUseCoreKbd, XkbBellNotifyMask,
XkbBellNotifyMask) ) {
if (! quiet) {
- fprintf(stderr, "warning: disabling bell."
- " XkbSelectEvents failed.\n");
+ rfbLog("warning: disabling bell. XkbSelectEvents"
+ " failed.\n");
}
watch_bell = 0;
}
@@ -3994,7 +4724,7 @@ void check_bell_event(void) {
}
X_LOCK;
- if (! XCheckTypedEvent(dpy, xkb_base_event_type , &xev)) {
+ if (! XCheckTypedEvent(dpy, xkb_base_event_type, &xev)) {
X_UNLOCK;
return;
}
@@ -4004,7 +4734,7 @@ void check_bell_event(void) {
}
X_UNLOCK;
- if (got_bell) {
+ if (got_bell && sound_bell) {
if (! all_clients_initialized()) {
rfbLog("check_bell_event: not sending bell: "
"uninitialized clients\n");
@@ -4017,6 +4747,260 @@ void check_bell_event(void) {
void check_bell_event(void) {}
#endif
+/* -- xrandr.h -- */
+
+time_t last_subwin_trap = 0;
+int subwin_trap_count = 0;
+
+XErrorHandler old_getimage_handler;
+#define XRANDR_SET_TRAP_RET(x,y) \
+ if (subwin || xrandr) { \
+ if (0) fprintf(stderr, " SET_TRAP: '%d' '%s'\n", x, y); \
+ trapped_getimage_xerror = 0; \
+ old_getimage_handler = XSetErrorHandler(trap_getimage_xerror); \
+ if (check_xrandr_event(y)) { \
+ trapped_getimage_xerror = 0; \
+ XSetErrorHandler(old_getimage_handler); \
+ return(x); \
+ } \
+ }
+#define XRANDR_CHK_TRAP_RET(x,y) \
+ if (subwin || xrandr) { \
+ if (0) fprintf(stderr, " CHK_TRAP: '%d' '%s'\n", x, y); \
+ if (trapped_getimage_xerror) { \
+ if (subwin) { \
+ static int last = 0; \
+ subwin_trap_count++; \
+ if (time(0) > last_subwin_trap + 60) { \
+ rfbLog("trapped GetImage xerror" \
+ " in SUBWIN mode. [%d]\n", \
+ subwin_trap_count); \
+ last_subwin_trap = time(0); \
+ last = subwin_trap_count; \
+ } \
+ if (subwin_trap_count - last > 30) { \
+ /* window probably iconified */ \
+ usleep(1000*1000); \
+ } \
+ } else { \
+ rfbLog("trapped GetImage xerror" \
+ " in XRANDR mode.\n"); \
+ } \
+ trapped_getimage_xerror = 0; \
+ XSetErrorHandler(old_getimage_handler); \
+ check_xrandr_event(y); \
+ X_UNLOCK; \
+ return(x); \
+ } \
+ }
+
+/* -- xrandr.c -- */
+
+void initialize_xrandr(void) {
+#ifdef LIBVNCSERVER_HAVE_LIBXRANDR
+ if (xrandr_present) {
+ Rotation rot;
+
+ xrandr_width = XDisplayWidth(dpy, scr);
+ xrandr_height = XDisplayHeight(dpy, scr);
+ XRRRotations(dpy, scr, &rot);
+ xrandr_rotation = (int) rot;
+ if (xrandr) {
+ XRRSelectInput(dpy, rootwin, RRScreenChangeNotifyMask);
+ } else {
+ XRRSelectInput(dpy, rootwin, 0);
+ }
+ }
+#endif
+}
+
+void handle_xrandr_change(int, int);
+
+int handle_subwin_resize(char *msg) {
+ int new_x, new_y;
+ int i, check = 10, ms = 250; /* 2.5 secs... */
+
+ if (0) fprintf(stderr, "IN handle_subwin_resize('%s')\n", msg);
+ if (! subwin) {
+ return 0; /* hmmm... */
+ }
+ if (! valid_window(subwin)) {
+ rfbLog("subwin 0x%lx went away!\n", subwin);
+ X_UNLOCK;
+ clean_up_exit(1);
+ }
+ if (! get_window_size(subwin, &new_x, &new_y)) {
+ rfbLog("could not get size of subwin 0x%lx\n", subwin);
+ X_UNLOCK;
+ clean_up_exit(1);
+ }
+ if (dpy_x == new_x && dpy_y == new_y) {
+ /* no change */
+ return 0;
+ }
+
+ /* window may still be changing (e.g. drag resize) */
+ for (i=0; i < check; i++) {
+ int newer_x, newer_y;
+ usleep(ms * 1000);
+
+ if (! get_window_size(subwin, &newer_x, &newer_y)) {
+ rfbLog("could not get size of subwin 0x%lx\n", subwin);
+ clean_up_exit(1);
+ }
+ if (new_x == newer_x && new_y == newer_y) {
+ /* go for it... */
+ break;
+ } else {
+ rfbLog("subwin 0x%lx still changing size...\n", subwin);
+ new_x = newer_x;
+ new_y = newer_y;
+ }
+ }
+
+ rfbLog("subwin 0x%lx new size: x: %d -> %d, y: %d -> %d\n",
+ subwin, dpy_x, new_x, dpy_y, new_y);
+ rfbLog("calling handle_xrandr_change() for resizing\n");
+
+ X_UNLOCK;
+ handle_xrandr_change(new_x, new_y);
+ return 1;
+}
+
+int known_xrandr_mode(char *);
+
+void handle_xrandr_change(int new_x, int new_y) {
+ rfbClientIteratorPtr iter;
+ rfbClientPtr cl;
+
+ /* sanity check xrandr_mode */
+ if (! xrandr_mode) {
+ xrandr_mode = strdup("default");
+ } else if (! known_xrandr_mode(xrandr_mode)) {
+ free(xrandr_mode);
+ xrandr_mode = strdup("default");
+ }
+ rfbLog("xrandr_mode: %s\n", xrandr_mode);
+ if (!strcmp(xrandr_mode, "exit")) {
+ close_all_clients();
+ rfbLog(" shutting down due to XRANDR event.\n");
+ clean_up_exit(0);
+ }
+ if (!strcmp(xrandr_mode, "newfbsize")) {
+ iter = rfbGetClientIterator(screen);
+ while( (cl = rfbClientIteratorNext(iter)) ) {
+ if (cl->useNewFBSize) {
+ continue;
+ }
+ rfbLog(" closing client %s (no useNewFBSize"
+ " support).\n", cl->host);
+ rfbCloseClient(cl);
+ rfbClientConnectionGone(cl);
+ }
+ rfbReleaseClientIterator(iter);
+ }
+
+ /* default, resize, and newfbsize create a new fb: */
+ rfbLog("check_xrandr_event: trying to create new framebuffer...\n");
+ if (new_x < dpy_x || new_y < dpy_y) {
+ check_black_fb();
+ }
+ do_new_fb(1);
+ rfbLog("check_xrandr_event: fb WxH: %dx%d\n", dpy_x, dpy_y);
+}
+
+int check_xrandr_event(char *msg) {
+ XEvent xev;
+ if (subwin) {
+ return handle_subwin_resize(msg);
+ }
+#ifdef LIBVNCSERVER_HAVE_LIBXRANDR
+ if (! xrandr || ! xrandr_present) {
+ return 0;
+ }
+ if (0) fprintf(stderr, "IN check_xrandr_event('%s')\n", msg);
+ if (XCheckTypedEvent(dpy, xrandr_base_event_type +
+ RRScreenChangeNotify, &xev)) {
+ int do_change;
+ XRRScreenChangeNotifyEvent *rev;
+
+ rev = (XRRScreenChangeNotifyEvent *) &xev;
+ rfbLog("check_xrandr_event():\n");
+ rfbLog("Detected XRANDR event at location '%s':\n", msg);
+ rfbLog(" serial: %d\n", (int) rev->serial);
+ rfbLog(" timestamp: %d\n", (int) rev->timestamp);
+ rfbLog(" cfg_timestamp: %d\n", (int) rev->config_timestamp);
+ rfbLog(" size_id: %d\n", (int) rev->size_index);
+ rfbLog(" sub_pixel: %d\n", (int) rev->subpixel_order);
+ rfbLog(" rotation: %d\n", (int) rev->rotation);
+ rfbLog(" width: %d\n", (int) rev->width);
+ rfbLog(" height: %d\n", (int) rev->height);
+ rfbLog(" mwidth: %d mm\n", (int) rev->mwidth);
+ rfbLog(" mheight: %d mm\n", (int) rev->mheight);
+ rfbLog("\n");
+ rfbLog("check_xrandr_event: previous WxH: %dx%d\n",
+ dpy_x, dpy_y);
+ if (dpy_x == rev->width && dpy_y == rev->height &&
+ xrandr_rotation == (int) rev->rotation) {
+ rfbLog("check_xrandr_event: no change detected.\n");
+ do_change = 0;
+ } else {
+ do_change = 1;
+ }
+
+ xrandr_width = rev->width;
+ xrandr_height = rev->height;
+ xrandr_timestamp = rev->timestamp;
+ xrandr_cfg_time = rev->config_timestamp;
+ xrandr_rotation = (int) rev->rotation;
+
+ rfbLog("check_xrandr_event: updating config...\n");
+ XRRUpdateConfiguration(&xev);
+
+ if (do_change) {
+ X_UNLOCK;
+ handle_xrandr_change(rev->width, rev->height);
+ }
+ rfbLog("check_xrandr_event: current WxH: %dx%d\n",
+ XDisplayWidth(dpy, scr), XDisplayHeight(dpy, scr));
+ rfbLog("check_xrandr_event(): returning control to"
+ " caller...\n");
+ if (0) fprintf(stderr, "OUT-%d check_xrandr_event('%s')\n",
+ do_change, msg);
+ return do_change;
+ }
+#endif
+ if (0) fprintf(stderr, "OUT-0 check_xrandr_event('%s')\n", msg);
+ return 0;
+}
+
+int known_xrandr_mode(char *s) {
+/*
+ * default:
+ * resize: the default
+ * exit: shutdown clients and exit.
+ * newfbsize: shutdown clients that do not support NewFBSize encoding.
+ */
+ if (strcmp(s, "default") && strcmp(s, "resize") &&
+ strcmp(s, "exit") && strcmp(s, "newfbsize")) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+int known_sigpipe_mode(char *s) {
+/*
+ * skip, ignore, exit
+ */
+ if (strcmp(s, "skip") && strcmp(s, "ignore") &&
+ strcmp(s, "exit")) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
/* -- selection.c -- */
/*
* Selection/Cutbuffer/Clipboard handlers.
@@ -4176,6 +5160,8 @@ static void cutbuffer_send(void) {
*
* TODO: if we were willing to use libXt, we could perhaps get selection
* timestamps to speed up the checking... XtGetSelectionValue().
+ *
+ * Also: XFIXES has XFixesSelectSelectionInput().
*/
#define CHKSZ 32
static void selection_send(XEvent *ev) {
@@ -4258,36 +5244,70 @@ static void selection_send(XEvent *ev) {
rfbSendServerCutText(screen, selection_str, newlen);
}
-/*
- * This routine is periodically called to check for selection related
- * and other X11 events and respond to them as needed.
- */
-void check_xevents(void) {
- XEvent xev;
- static int first = 1, sent_some_sel = 0;
- static time_t last_request = 0;
- time_t now = time(0);
- int have_clients = screen->clientHead ? 1 : 0;
+/* -- xevents.c -- */
+
+void initialize_vnc_connect_prop() {
+ vnc_connect_str[0] = '\0';
+ vnc_connect_prop = XInternAtom(dpy, "VNC_CONNECT", False);
+}
+
+void initialize_xevents(void) {
+ static int did_xselect_input = 0;
+ static int did_xcreate_simple_window = 0;
+ static int did_vnc_connect_prop = 0;
+ static int did_xfixes = 0;
+ static int did_xrandr = 0;
X_LOCK;
- if (first && (watch_selection || vnc_connect)) {
+ if ((watch_selection || vnc_connect) && !did_xselect_input) {
/*
* register desired event(s) for notification.
* PropertyChangeMask is for CUT_BUFFER0 changes.
- * TODO: does this cause a flood of other stuff?
+ * XXX: does this cause a flood of other stuff?
*/
XSelectInput(dpy, rootwin, PropertyChangeMask);
+ did_xselect_input = 1;
}
- if (first && watch_selection) {
+ if (watch_selection && !did_xcreate_simple_window) {
/* create fake window for our selection ownership, etc */
+
selwin = XCreateSimpleWindow(dpy, rootwin, 0, 0, 1, 1, 0, 0, 0);
+ did_xcreate_simple_window = 1;
}
- if (first && vnc_connect) {
- vnc_connect_str[0] = '\0';
- vnc_connect_prop = XInternAtom(dpy, "VNC_CONNECT", False);
+ X_UNLOCK;
+
+ if (xrandr && !did_xrandr) {
+ initialize_xrandr();
+ did_xrandr = 1;
+ }
+ if (vnc_connect && !did_vnc_connect_prop) {
+ initialize_vnc_connect_prop();
+ did_vnc_connect_prop = 1;
+ }
+ if (xfixes_present && use_xfixes && !did_xfixes) {
+ initialize_xfixes();
+ did_xfixes = 1;
+ }
+}
+
+/*
+ * This routine is periodically called to check for selection related
+ * and other X11 events and respond to them as needed.
+ */
+void check_xevents(void) {
+ XEvent xev;
+ static int first = 1, sent_some_sel = 0;
+ static time_t last_request = 0;
+ time_t now = time(0);
+ int have_clients = screen->clientHead ? 1 : 0;
+
+
+ if (first) {
+ initialize_xevents();
}
first = 0;
+ X_LOCK;
/*
* There is a bug where we have to wait before sending text to
* the client... so instead of sending right away we wait a
@@ -4337,6 +5357,18 @@ void check_xevents(void) {
}
}
+#ifdef LIBVNCSERVER_HAVE_LIBXRANDR
+ if (xrandr) {
+ check_xrandr_event("check_xevents");
+ }
+#endif
+#ifdef LIBVNCSERVER_HAVE_LIBXFIXES
+ if (XCheckTypedEvent(dpy, xfixes_base_event_type +
+ XFixesCursorNotify, &xev)) {
+ got_xfixes_cursor_notify++;
+ }
+#endif
+
/* check for our PRIMARY request notification: */
if (watch_primary) {
if (XCheckTypedEvent(dpy, SelectionNotify, &xev)) {
@@ -4400,7 +5432,7 @@ void check_xevents(void) {
*/
void xcut_receive(char *text, int len, rfbClientPtr cl) {
- if (cl->viewOnly) {
+ if (cl && cl->viewOnly) {
return;
}
if (text == NULL || len == 0) {
@@ -4436,6 +5468,1806 @@ void xcut_receive(char *text, int len, rfbClientPtr cl) {
set_cutbuffer = 1;
}
+/* -- remote.c -- */
+
+/*
+ * for the wild-n-crazy -remote/-R interface.
+ */
+int send_remote_cmd(char *cmd, int query) {
+ char *str;
+ FILE *in = NULL;
+
+ if (client_connect_file) {
+ in = fopen(client_connect_file, "w");
+ if (in == NULL) {
+ fprintf(stderr, "send_remote_cmd: could not open "
+ "connect file \"%s\" for writing\n",
+ client_connect_file);
+ perror("fopen");
+ return 1;
+ }
+ } else if (vnc_connect_prop == None) {
+ initialize_vnc_connect_prop();
+ if (vnc_connect_prop == None) {
+ fprintf(stderr, "send_remote_cmd: could not obtain "
+ "VNC_CONNECT X property\n");
+ return 1;
+ }
+ }
+ str = (char *) malloc((strlen(cmd)+5));
+ if (query) {
+ strcpy(str, "qry=");
+ } else {
+ strcpy(str, "cmd=");
+ }
+ strcat(str, cmd);
+
+ if (in != NULL) {
+ fprintf(stderr, "sending remote command: \"%s\"\nvia connect"
+ " file: %s\n", cmd, client_connect_file);
+ fprintf(in, "%s\n", str);
+ fclose(in);
+ } else {
+ fprintf(stderr, "sending remote command: \"%s\" via VNC_CONNECT"
+ " X property.\n", cmd);
+ set_vnc_connect_prop(str);
+ XFlush(dpy);
+ }
+
+ if (strstr(str, "qry=") == str) {
+ char line[VNC_CONNECT_MAX];
+ int rc=1, i=0, max=20, ms_sl=100;
+ for (i=0; i<max; i++) {
+ usleep(ms_sl * 1000);
+ if (client_connect_file) {
+ char *q;
+ in = fopen(client_connect_file, "r");
+ if (in == NULL) {
+ fprintf(stderr, "send_remote_cmd: could"
+ " not open connect file \"%s\" for"
+ " writing\n", client_connect_file);
+ perror("fopen");
+ return 1;
+ }
+ fgets(line, VNC_CONNECT_MAX, in);
+ fclose(in);
+ q = line;
+ while (*q != '\0') {
+ if (*q == '\n') *q = '\0';
+ q++;
+ }
+ } else {
+ read_vnc_connect_prop();
+ strncpy(line, vnc_connect_str, VNC_CONNECT_MAX);
+ }
+ if (strcmp(str, line)){
+ fprintf(stdout, "%s\n", line);
+ fflush(stdout);
+ rc = 0;
+ break;
+ }
+ }
+ free(str);
+ if (rc) {
+ fprintf(stderr, "error: could not connect to "
+ "an x11vnc server at %s (rc=%d)\n",
+ client_connect_file ? client_connect_file
+ : DisplayString(dpy), rc);
+ }
+ return rc;
+ }
+ free(str);
+ return 0;
+}
+
+char *add_item(char *instr, char *item) {
+ char *p, *str;
+ int len, saw_item = 0;
+
+ if (! instr) {
+ str = strdup(item);
+ return str;
+ }
+ len = strlen(instr) + strlen(item) + 2;
+ str = (char *)malloc(len);
+ str[0] = '\0';
+
+ p = strtok(instr, ",");
+ while (p) {
+ if (!strcmp(p, item)) {
+ if (saw_item) {
+ p = strtok(NULL, ",");
+ continue;
+ }
+ saw_item = 1;
+ } else if (*p == '\0') {
+ p = strtok(NULL, ",");
+ continue;
+ }
+ if (str[0]) {
+ strcat(str, ",");
+ }
+ strcat(str, p);
+ p = strtok(NULL, ",");
+ }
+ if (! saw_item) {
+ if (str[0]) {
+ strcat(str, ",");
+ }
+ strcat(str, item);
+
+ }
+ return str;
+}
+
+char *delete_item(char *instr, char *item) {
+ char *p, *str;
+ int len;
+
+ if (! instr) {
+ str = strdup("");
+ return str;
+ }
+ len = strlen(instr) + 1;
+ str = (char *)malloc(len);
+ str[0] = '\0';
+
+ p = strtok(instr, ",");
+ while (p) {
+ if (!strcmp(p, item) || *p == '\0') {
+ p = strtok(NULL, ",");
+ continue;
+ }
+ if (str[0]) {
+ strcat(str, ",");
+ }
+ strcat(str, p);
+ p = strtok(NULL, ",");
+ }
+ return str;
+}
+
+void if_8bpp_do_new_fb(void) {
+ if (bpp == 8) {
+ do_new_fb(0);
+ } else {
+ rfbLog(" bpp(%d) is not 8bpp, not resetting fb\n", bpp);
+ }
+}
+
+void check_black_fb(void) {
+ if (new_fb_size_clients(screen) != client_count) {
+ rfbLog("trying to send a black fb for non-newfbsize"
+ " clients %d != %d\n", client_count,
+ new_fb_size_clients(screen));
+ push_black_screen(4);
+ }
+}
+
+/*
+ * Huge, ugly switch to handle all remote commands and queries
+ * -remote/-R and -query/-Q.
+ */
+char *process_remote_cmd(char *cmd, int stringonly) {
+ char *p = cmd;
+ char *co = "";
+ char buf[VNC_CONNECT_MAX];
+ int do_vnc_connect = 0;
+ int query = 0;
+ static char *prev_cursors_mode = NULL;
+
+ if (! accept_remote_cmds) {
+ rfbLog("remote commands disabled: %s\n", cmd);
+ return NULL;
+ }
+
+ if (strstr(cmd, "cmd=") == cmd) {
+ p += strlen("cmd=");
+ } else if (strstr(cmd, "qry=") == cmd) {
+ query = 1;
+ if (strchr(cmd, ',')) {
+ /* comma separated batch mode */
+ char *s, *q, *res;
+ char tmp[512];
+ strcpy(buf, "");
+ s = strdup(cmd + strlen("qry="));
+ q = strtok(s, ",");
+ while (q) {
+ sprintf(tmp, "qry=%s", q);
+ res = process_remote_cmd(tmp, 1);
+ if (res) {
+ strcat(buf, res);
+ free(res);
+ }
+ q = strtok(NULL, ",");
+ if (q) {
+ strcat(buf, ",");
+ }
+ }
+ free(s);
+ goto qry;
+ }
+ p += strlen("qry=");
+ } else {
+ rfbLog("ignoring malformed command: %s\n", cmd);
+ return NULL;
+ }
+
+ if (!query && strstr(p, "file:") == p) {
+ /* process command from a script file */
+ FILE *in;
+ char line[VNC_CONNECT_MAX], cmd[VNC_CONNECT_MAX];
+ int sz = VNC_CONNECT_MAX - 6;
+ p += strlen("file:");
+ in = fopen(p, "r");
+ if (in == NULL) {
+ rfbLog("process_remote_cmd: could not open cmd file"
+ " '%s'\n", p);
+ return NULL;
+ }
+ rfbLog("process_remote_cmd: running command from '%s'\n", p);
+ while (fgets(line, sz, in) != NULL) {
+ char *q;
+ if (strlen(line)) {
+ q = line + strlen(line) - 1;
+ if (*q == '\n') {
+ *q = '\0';
+ }
+ while (q > line && isspace(*q)) {
+ *q = '\0';
+ q--;
+ }
+ }
+ q = line;
+ while (isspace(*q)) {
+ q++;
+ }
+ if ( *q == '#' || *q == '\0') {
+ continue;
+ }
+ strcpy(cmd, "cmd=");
+ strcat(cmd, q);
+ process_remote_cmd(cmd, 0);
+ }
+ fclose(in);
+ return NULL;
+ }
+
+ /* always call like: COLON_CHECK("foobar:") */
+#define COLON_CHECK(str) \
+ if (strstr(p, str) != p) { \
+ co = ":"; \
+ if (! query) { \
+ goto done; \
+ } \
+ } else { \
+ char *q = strchr(p, ':'); \
+ if (query && q != NULL) { \
+ *(q+1) = '\0'; \
+ } \
+ }
+
+#define NOTAPP \
+ if (query) { \
+ if (strchr(p, ':')) { \
+ sprintf(buf, "ans=%sN/A", p); \
+ } else { \
+ sprintf(buf, "ans=%s:N/A", p); \
+ } \
+ goto qry; \
+ }
+
+#define NOTAPPRO \
+ if (query) { \
+ if (strchr(p, ':')) { \
+ sprintf(buf, "aro=%sN/A", p); \
+ } else { \
+ sprintf(buf, "aro=%s:N/A", p); \
+ } \
+ goto qry; \
+ }
+
+/*
+ * Add: passwdfile logfile bg nofb rfbauth passwd noshm...
+ */
+ if (!strcmp(p, "stop") || !strcmp(p, "quit") ||
+ !strcmp(p, "exit") || !strcmp(p, "shutdown")) {
+ NOTAPP
+ close_all_clients();
+ rfbLog("process_remote_cmd: setting shut_down flag\n");
+ shut_down = 1;
+
+ } else if (!strcmp(p, "ping")) {
+ query = 1;
+ if (rfb_desktop_name) {
+ sprintf(buf, "ans=%s:%s", p, rfb_desktop_name);
+ } else {
+ sprintf(buf, "ans=%s:%s", p, "unknown");
+ }
+ goto qry;
+
+ } else if (!strcmp(p, "blacken") || !strcmp(p, "zero")) {
+ NOTAPP
+ push_black_screen(4);
+ } else if (!strcmp(p, "refresh")) {
+ NOTAPP
+ refresh_screen();
+ } else if (!strcmp(p, "reset")) {
+ NOTAPP
+ do_new_fb(1);
+ } else if (strstr(p, "zero:") == p) { /* skip-cmd-list */
+ int x1, y1, x2, y2;
+ NOTAPP
+ p += strlen("zero:");
+ if (sscanf(p, "%d,%d,%d,%d", &x1, &y1, &x2, &y2) == 4) {
+ int mark = 1;
+ rfbLog("zeroing rect: %s\n", p);
+ if (x1 < 0 || x2 < 0) {
+ x1 = nabs(x1);
+ x2 = nabs(x2);
+ mark = 0; /* hack for testing */
+ }
+
+ zero_fb(x1, y1, x2, y2);
+ if (mark) {
+ mark_rect_as_modified(x1, y1, x2, y2, 1);
+ }
+ push_sleep(4);
+ }
+ } else if (strstr(p, "damagefb:") == p) { /* skip-cmd-list */
+ int delay;
+ NOTAPP
+ p += strlen("damagefb:");
+ if (sscanf(p, "%d", &delay) == 1) {
+ rfbLog("damaging client fb's for %d secs "
+ "(by not marking rects.)\n", delay);
+ damage_time = time(0);
+ damage_delay = delay;
+ }
+
+ } else if (strstr(p, "close") == p) {
+ NOTAPP
+ COLON_CHECK("close:")
+ p += strlen("close:");
+ close_clients(p);
+ } else if (strstr(p, "disconnect") == p) {
+ NOTAPP
+ COLON_CHECK("disconnect:")
+ p += strlen("disconnect:");
+ close_clients(p);
+
+ } else if (strstr(p, "id") == p) {
+ int ok = 0;
+ Window twin;
+ COLON_CHECK("id:")
+ if (query) {
+ sprintf(buf, "ans=%s%s0x%lx", p, co, subwin);
+ goto qry;
+ }
+ p += strlen("id:");
+ if (*p == '\0' || !strcmp("root", p)) {
+ /* back to root win */
+ twin = 0x0;
+ ok = 1;
+ } else if (!strcmp("pick", p)) {
+ twin = 0x0;
+ if (safe_remote_only) {
+ rfbLog("unsafe: '-id pick'\n");
+ } else if (pick_windowid(&twin)) {
+ ok = 1;
+ }
+ } else if (! scan_hexdec(p, &twin)) {
+ rfbLog("-id: incorrect hex/dec number: %s\n", p);
+ } else {
+ ok = 1;
+ }
+ if (ok) {
+ if (twin && ! valid_window(twin)) {
+ rfbLog("skipping invalid sub-window: 0x%lx\n",
+ twin);
+ } else {
+ subwin = twin;
+ rootshift = 0;
+ check_black_fb();
+ do_new_fb(1);
+ }
+ }
+ } else if (strstr(p, "sid") == p) {
+ int ok = 0;
+ Window twin;
+ COLON_CHECK("sid:")
+ if (query) {
+ sprintf(buf, "ans=%s%s0x%lx", p, co, subwin);
+ goto qry;
+ }
+ p += strlen("sid:");
+ if (*p == '\0' || !strcmp("root", p)) {
+ /* back to root win */
+ twin = 0x0;
+ ok = 1;
+ } else if (!strcmp("pick", p)) {
+ twin = 0x0;
+ if (safe_remote_only) {
+ rfbLog("unsafe: '-sid pick'\n");
+ } else if (pick_windowid(&twin)) {
+ ok = 1;
+ }
+ } else if (! scan_hexdec(p, &twin)) {
+ rfbLog("-sid: incorrect hex/dec number: %s\n", p);
+ } else {
+ ok = 1;
+ }
+ if (ok) {
+ if (twin && ! valid_window(twin)) {
+ rfbLog("skipping invalid sub-window: 0x%lx\n",
+ twin);
+ } else {
+ subwin = twin;
+ rootshift = 1;
+ check_black_fb();
+ do_new_fb(1);
+ }
+ }
+
+ } else if (!strcmp(p, "flashcmap")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, flash_cmap);
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: turning on flashcmap mode.\n");
+ flash_cmap = 1;
+ } else if (!strcmp(p, "noflashcmap")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, !flash_cmap);
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: turning off flashcmap mode.\n");
+ flash_cmap = 0;
+
+ } else if (!strcmp(p, "truecolor")) {
+ int orig = force_indexed_color;
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, !force_indexed_color);
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: turning off notruecolor mode.\n");
+ force_indexed_color = 0;
+ if (orig != force_indexed_color) {
+ if_8bpp_do_new_fb();
+ }
+ } else if (!strcmp(p, "notruecolor")) {
+ int orig = force_indexed_color;
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, force_indexed_color);
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: turning on notruecolor mode.\n");
+ force_indexed_color = 1;
+ if (orig != force_indexed_color) {
+ if_8bpp_do_new_fb();
+ }
+
+ } else if (!strcmp(p, "overlay")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, overlay);
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: turning on -overlay mode.\n");
+ if (!overlay_present) {
+ rfbLog("skipping: overlay extension not present.\n");
+ } else if (overlay) {
+ rfbLog("skipping: already in -overlay mode.\n");
+ } else {
+ int reset_mem = 0;
+ /* here we go... */
+ if (using_shm) {
+ rfbLog("setting -noshm mode.\n");
+ using_shm = 0;
+ reset_mem = 1;
+ }
+ overlay = 1;
+ do_new_fb(reset_mem);
+ }
+ } else if (!strcmp(p, "nooverlay")) {
+ int orig = overlay;
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, !overlay);
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: turning off overlay mode\n");
+ overlay = 0;
+ if (!overlay_present) {
+ rfbLog("warning: overlay extension not present.\n");
+ } else if (!orig) {
+ rfbLog("skipping: already not in -overlay mode.\n");
+ } else {
+ /* here we go... */
+ do_new_fb(0);
+ }
+
+ } else if (!strcmp(p, "overlay_cursor") ||
+ !strcmp(p, "overlay_yescursor")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, overlay_cursor);
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: turning on overlay_cursor mode.\n");
+ overlay_cursor = 1;
+ if (!overlay_present) {
+ rfbLog("warning: overlay extension not present.\n");
+ } else if (!overlay) {
+ rfbLog("warning: not in -overlay mode.\n");
+ } else {
+ rfbLog("You may want to run -R noshow_cursor or\n");
+ rfbLog(" -R cursor:none to disable any extra "
+ "cursors.\n");
+ }
+ } else if (!strcmp(p, "nooverlay_cursor") ||
+ !strcmp(p, "overlay_nocursor")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, !overlay_cursor);
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: turning off overlay_cursor mode\n");
+ overlay_cursor = 0;
+ if (!overlay_present) {
+ rfbLog("warning: overlay extension not present.\n");
+ } else if (!overlay) {
+ rfbLog("warning: not in -overlay mode.\n");
+ } else {
+ rfbLog("You may want to run -R show_cursor or\n");
+ rfbLog(" -R cursor:... to re-enable any cursors.\n");
+ }
+
+ } else if (strstr(p, "visual") == p) {
+ COLON_CHECK("visual:")
+ if (query) {
+ sprintf(buf, "ans=%s%s%s", p, co, NONUL(visual_str));
+ goto qry;
+ }
+ p += strlen("visual:");
+ if (visual_str) free(visual_str);
+ visual_str = strdup(p);
+
+ /* OK, this requires a new fb... */
+ do_new_fb(0);
+
+ } else if (strstr(p, "scale") == p) {
+ COLON_CHECK("scale:")
+ if (query) {
+ sprintf(buf, "ans=%s%s%s", p, co, NONUL(scale_str));
+ goto qry;
+ }
+ p += strlen("scale:");
+ if (scale_str) free(scale_str);
+ scale_str = strdup(p);
+
+ /* OK, this requires a new fb... */
+ check_black_fb();
+ do_new_fb(0);
+
+ } else if (!strcmp(p, "viewonly")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, view_only); goto qry;
+ }
+ rfbLog("process_remote_cmd: enable viewonly mode.\n");
+ view_only = 1;
+ } else if (!strcmp(p, "noviewonly")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, !view_only); goto qry;
+ }
+ rfbLog("process_remote_cmd: disable viewonly mode.\n");
+ view_only = 0;
+
+ } else if (!strcmp(p, "shared")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, shared); goto qry;
+ }
+ rfbLog("process_remote_cmd: enable sharing.\n");
+ shared = 1;
+ screen->alwaysShared = TRUE;
+ screen->neverShared = FALSE;
+ } else if (!strcmp(p, "noshared")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, !shared); goto qry;
+ }
+ rfbLog("process_remote_cmd: disable sharing.\n");
+ shared = 0;
+ screen->alwaysShared = FALSE;
+ screen->neverShared = TRUE;
+
+ } else if (!strcmp(p, "forever")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, 1-connect_once); goto qry;
+ }
+ rfbLog("process_remote_cmd: enable -forever mode.\n");
+ connect_once = 0;
+ } else if (!strcmp(p, "noforever") || !strcmp(p, "once")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, connect_once); goto qry;
+ }
+ rfbLog("process_remote_cmd: disable -forever mode.\n");
+ connect_once = 1;
+
+ } else if (!strcmp(p, "deny") || !strcmp(p, "lock")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, deny_all); goto qry;
+ }
+ rfbLog("process_remote_cmd: denying new connections.\n");
+ deny_all = 1;
+ } else if (!strcmp(p, "nodeny") || !strcmp(p, "unlock")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, !deny_all); goto qry;
+ }
+ rfbLog("process_remote_cmd: allowing new connections.\n");
+ deny_all = 0;
+
+ } else if (strstr(p, "connect") == p) {
+ NOTAPP
+ COLON_CHECK("connect:")
+ p += strlen("connect:"); /* handled at end */
+ do_vnc_connect = 1;
+
+ } else if (strstr(p, "allowonce") == p) {
+ NOTAPP
+ COLON_CHECK("allowonce:")
+ p += strlen("allowonce:");
+ allow_once = strdup(p);
+ rfbLog("process_remote_cmd: set allow_once %s\n", allow_once);
+
+ } else if (strstr(p, "allow") == p) {
+ char *before, *old;
+ COLON_CHECK("allow:")
+ if (query) {
+ sprintf(buf, "ans=%s%s%s", p, co, NONUL(allow_list));
+ goto qry;
+ }
+ p += strlen("allow:");
+ if (allow_list && strchr(allow_list, '/')) {
+ rfbLog("process_remote_cmd: cannot use allow:host\n");
+ rfbLog("in '-allow %s' mode.\n", allow_list);
+ return NULL;
+ }
+ if (allow_list) {
+ before = strdup(allow_list);
+ } else {
+ before = strdup("");
+ }
+
+ old = allow_list;
+ if (*p == '+') {
+ p++;
+ allow_list = add_item(allow_list, p);
+ } else if (*p == '-') {
+ p++;
+ allow_list = delete_item(allow_list, p);
+ } else {
+ allow_list = strdup(p);
+ }
+
+ if (strcmp(before, allow_list)) {
+ rfbLog("process_remote_cmd: modified allow_list:\n");
+ rfbLog(" from: \"%s\"\n", before);
+ rfbLog(" to: \"%s\"\n", allow_list);
+ }
+ if (old) free(old);
+ free(before);
+
+ } else if (!strcmp(p, "localhost")) {
+ char *before, *old;
+ if (query) {
+ int state = 0;
+ if (allow_list && !strcmp(allow_list, "127.0.0.1")) {
+ state = 1;
+ }
+ sprintf(buf, "ans=%s:%d", p, state);
+ goto qry;
+ }
+ if (allow_list) {
+ before = strdup(allow_list);
+ } else {
+ before = strdup("");
+ }
+ old = allow_list;
+
+ allow_list = strdup("127.0.0.1");
+
+ if (strcmp(before, allow_list)) {
+ rfbLog("process_remote_cmd: modified allow_list:\n");
+ rfbLog(" from: \"%s\"\n", before);
+ rfbLog(" to: \"%s\"\n", allow_list);
+ }
+ if (old) free(old);
+ free(before);
+ } else if (!strcmp(p, "nolocalhost")) {
+ char *before, *old;
+ if (query) {
+ int state = 0;
+ if (allow_list && !strcmp(allow_list, "127.0.0.1")) {
+ state = 1;
+ }
+ sprintf(buf, "ans=%s:%d", p, !state);
+ goto qry;
+ }
+ if (allow_list) {
+ before = strdup(allow_list);
+ } else {
+ before = strdup("");
+ }
+ old = allow_list;
+
+ allow_list = strdup("");
+
+ if (strcmp(before, allow_list)) {
+ rfbLog("process_remote_cmd: modified allow_list:\n");
+ rfbLog(" from: \"%s\"\n", before);
+ rfbLog(" to: \"%s\"\n", allow_list);
+ }
+ if (old) free(old);
+ free(before);
+
+ } else if (strstr(p, "accept") == p) {
+ COLON_CHECK("accept:")
+ if (query) {
+ sprintf(buf, "ans=%s%s%s", p, co, NONUL(accept_cmd));
+ goto qry;
+ }
+ if (safe_remote_only) {
+ rfbLog("unsafe: %s\n", p);
+ } else {
+ p += strlen("accept:");
+ if (accept_cmd) free(accept_cmd);
+ accept_cmd = strdup(p);
+ }
+
+ } else if (strstr(p, "gone") == p) {
+ COLON_CHECK("gone:")
+ if (query) {
+ sprintf(buf, "ans=%s%s%s", p, co, NONUL(gone_cmd));
+ goto qry;
+ }
+ if (safe_remote_only) {
+ rfbLog("unsafe: %s\n", p);
+ } else {
+ p += strlen("gone:");
+ if (gone_cmd) free(gone_cmd);
+ gone_cmd = strdup(p);
+ }
+
+ } else if (!strcmp(p, "shm")) {
+ int orig = using_shm;
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, using_shm);
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: turning off noshm mode.\n");
+ using_shm = 1;
+ if (orig != using_shm) {
+ do_new_fb(1);
+ } else {
+ rfbLog(" already in shm mode.\n");
+ }
+ } else if (!strcmp(p, "noshm")) {
+ int orig = using_shm;
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, !using_shm);
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: turning on noshm mode.\n");
+ using_shm = 0;
+ if (orig != using_shm) {
+ do_new_fb(1);
+ } else {
+ rfbLog(" already in noshm mode.\n");
+ }
+
+ } else if (!strcmp(p, "flipbyteorder")) {
+ int orig = flip_byte_order;
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, flip_byte_order);
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: turning on flipbyteorder mode.\n");
+ flip_byte_order = 1;
+ if (orig != flip_byte_order) {
+ if (! using_shm) {
+ do_new_fb(1);
+ } else {
+ rfbLog(" using shm, not resetting fb\n");
+ }
+ }
+ } else if (!strcmp(p, "noflipbyteorder")) {
+ int orig = flip_byte_order;
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, !flip_byte_order);
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: turning off flipbyteorder mode.\n");
+ flip_byte_order = 0;
+ if (orig != flip_byte_order) {
+ if (! using_shm) {
+ do_new_fb(1);
+ } else {
+ rfbLog(" using shm, not resetting fb\n");
+ }
+ }
+
+ } else if (!strcmp(p, "onetile")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, single_copytile); goto qry;
+ }
+ rfbLog("process_remote_cmd: enable -onetile mode.\n");
+ single_copytile = 1;
+ } else if (!strcmp(p, "noonetile")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, !single_copytile);
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: disable -onetile mode.\n");
+ if (tile_shm_count < ntiles_x) {
+ rfbLog(" this has no effect: tile_shm_count=%d"
+ " ntiles_x=%d\n", tile_shm_count, ntiles_x);
+
+ }
+ single_copytile = 0;
+
+ } else if (strstr(p, "blackout") == p) {
+ char *before, *old;
+ COLON_CHECK("blackout:")
+ if (query) {
+ sprintf(buf, "ans=%s%s%s", p, co,
+ NONUL(blackout_string));
+ goto qry;
+ }
+ p += strlen("blackout:");
+ if (blackout_string) {
+ before = strdup(blackout_string);
+ } else {
+ before = strdup("");
+ }
+ old = blackout_string;
+ if (*p == '+') {
+ p++;
+ blackout_string = add_item(blackout_string, p);
+ } else if (*p == '-') {
+ p++;
+ blackout_string = delete_item(blackout_string, p);
+ } else {
+ blackout_string = strdup(p);
+ }
+ if (strcmp(before, blackout_string)) {
+ rfbLog("process_remote_cmd: changing -blackout\n");
+ rfbLog(" from: %s\n", before);
+ rfbLog(" to: %s\n", blackout_string);
+ if (0 && !strcmp(blackout_string, "") &&
+ single_copytile_orig != single_copytile) {
+ rfbLog("resetting single_copytile to: %d\n",
+ single_copytile_orig);
+ single_copytile = single_copytile_orig;
+ }
+ initialize_blackouts_and_xinerama();
+ }
+ if (old) free(old);
+ free(before);
+
+ } else if (!strcmp(p, "xinerama")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, xinerama); goto qry;
+ }
+ rfbLog("process_remote_cmd: enable xinerama mode."
+ "(if applicable).\n");
+ xinerama = 1;
+ initialize_blackouts_and_xinerama();
+ } else if (!strcmp(p, "noxinerama")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, !xinerama); goto qry;
+ }
+ rfbLog("process_remote_cmd: disable xinerama mode."
+ "(if applicable).\n");
+ xinerama = 0;
+ initialize_blackouts_and_xinerama();
+
+ } else if (!strcmp(p, "xrandr")) {
+ int orig = xrandr;
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, xrandr); goto qry;
+ }
+ if (xrandr_present) {
+ rfbLog("process_remote_cmd: enable xrandr mode.\n");
+ xrandr = 1;
+ if (! xrandr_mode) {
+ xrandr_mode = strdup("default");
+ }
+ if (orig != xrandr) {
+ initialize_xrandr();
+ }
+ } else {
+ rfbLog("process_remote_cmd: XRANDR ext. not "
+ "present.\n");
+ }
+ } else if (!strcmp(p, "noxrandr")) {
+ int orig = xrandr;
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, !xrandr); goto qry;
+ }
+ xrandr = 0;
+ if (xrandr_present) {
+ rfbLog("process_remote_cmd: disable xrandr mode.\n");
+ if (orig != xrandr) {
+ initialize_xrandr();
+ }
+ } else {
+ rfbLog("process_remote_cmd: XRANDR ext. not "
+ "present.\n");
+ }
+ } else if (strstr(p, "xrandr_mode") == p) {
+ int orig = xrandr;
+ COLON_CHECK("xrandr_mode:")
+ if (query) {
+ sprintf(buf, "ans=%s%s%s", p, co, NONUL(xrandr_mode));
+ goto qry;
+ }
+ p += strlen("xrandr_mode:");
+ if (!strcmp("none", p)) {
+ xrandr = 0;
+ } else {
+ if (known_xrandr_mode(p)) {
+ if (xrandr_mode) free(xrandr_mode);
+ xrandr_mode = strdup(p);
+ } else {
+ rfbLog("skipping unknown xrandr mode: %s\n", p);
+ return NULL;
+ }
+ xrandr = 1;
+ }
+ if (xrandr_present) {
+ if (xrandr) {
+ rfbLog("process_remote_cmd: enable xrandr"
+ " mode.\n");
+ } else {
+ rfbLog("process_remote_cmd: disable xrandr"
+ " mode.\n");
+ }
+ if (! xrandr_mode) {
+ xrandr_mode = strdup("default");
+ }
+ if (orig != xrandr) {
+ initialize_xrandr();
+ }
+ } else {
+ rfbLog("process_remote_cmd: XRANDR ext. not "
+ "present.\n");
+ }
+
+ } else if (strstr(p, "padgeom") == p) {
+ COLON_CHECK("padgeom:")
+ if (query) {
+ sprintf(buf, "ans=%s%s%s", p, co, NONUL(pad_geometry));
+ goto qry;
+ }
+ p += strlen("padgeom:");
+ if (!strcmp("force", p) || !strcmp("do",p) || !strcmp("go",p)) {
+ rfbLog("process_remote_cmd: invoking "
+ "install_padded_fb()\n");
+ install_padded_fb(pad_geometry);
+ } else {
+ if (pad_geometry) free(pad_geometry);
+ pad_geometry = strdup(p);
+ rfbLog("process_remote_cmd: set padgeom to: %s\n",
+ pad_geometry);
+ }
+
+ } else if (!strcmp(p, "quiet") || !strcmp(p, "q")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, quiet); goto qry;
+ }
+ rfbLog("process_remote_cmd: turning on quiet mode.\n");
+ quiet = 1;
+ } else if (!strcmp(p, "noquiet")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, !quiet); goto qry;
+ }
+ rfbLog("process_remote_cmd: turning off quiet mode.\n");
+ quiet = 0;
+
+ } else if (!strcmp(p, "modtweak")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, use_modifier_tweak);
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: enabling -modtweak mode.\n");
+ if (! use_modifier_tweak) {
+ use_modifier_tweak = 1;
+ initialize_modtweak();
+ }
+ use_modifier_tweak = 1;
+
+ } else if (!strcmp(p, "nomodtweak")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, !use_modifier_tweak);
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: enabling -nomodtweak mode.\n");
+ use_modifier_tweak = 0;
+
+ } else if (!strcmp(p, "xkb")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, use_xkb_modtweak);
+ goto qry;
+ }
+ if (! xkb_present) {
+ rfbLog("process_remote_cmd: cannot enable -xkb "
+ "modtweak mode (not supported on X display)\n");
+ return NULL;
+ }
+ rfbLog("process_remote_cmd: enabling -xkb modtweak mode"
+ " (if supported).\n");
+ if (! use_modifier_tweak || ! use_xkb_modtweak) {
+ use_modifier_tweak = 1;
+ use_xkb_modtweak = 1;
+ initialize_modtweak();
+ }
+ use_modifier_tweak = 1;
+ use_xkb_modtweak = 1;
+
+ } else if (!strcmp(p, "noxkb")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, !use_xkb_modtweak);
+ goto qry;
+ }
+ if (! xkb_present) {
+ rfbLog("process_remote_cmd: cannot disable -xkb "
+ "modtweak mode (not supported on X display)\n");
+ return NULL;
+ }
+ rfbLog("process_remote_cmd: disabling -xkb modtweak mode.\n");
+ use_xkb_modtweak = 0;
+
+ } else if (strstr(p, "skip_keycodes") == p) {
+ COLON_CHECK("skip_keycodes:")
+ if (query) {
+ sprintf(buf, "ans=%s%s%s", p, co, NONUL(skip_keycodes));
+ goto qry;
+ }
+ p += strlen("skip_keycodes:");
+ rfbLog("process_remote_cmd: setting xkb -skip_keycodes"
+ " to:\n\t'%s'\n", p);
+ if (! xkb_present) {
+ rfbLog("process_remote_cmd: warning xkb not present\n");
+ } else if (! use_xkb_modtweak) {
+ rfbLog("process_remote_cmd: turning on xkb.\n");
+ use_xkb_modtweak = 1;
+ if (! use_modifier_tweak) {
+ rfbLog("process_remote_cmd: turning on "
+ "modtweak.\n");
+ use_modifier_tweak = 1;
+ }
+ }
+ if (skip_keycodes) free(skip_keycodes);
+ skip_keycodes = strdup(p);
+ initialize_modtweak();
+
+ } else if (!strcmp(p, "add_keysyms")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, add_keysyms);
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: enabling -add_keysyms mode.\n");
+ add_keysyms = 1;
+
+ } else if (!strcmp(p, "noadd_keysyms")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, !add_keysyms);
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: disabling -add_keysyms mode.\n");
+ add_keysyms = 0;
+
+ } else if (!strcmp(p, "clear_mods")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, clear_mods == 1);
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: enabling -clear_mods mode.\n");
+ clear_mods = 1;
+ clear_modifiers(0);
+
+ } else if (!strcmp(p, "noclear_mods")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, !(clear_mods == 1));
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: disabling -clear_mods mode.\n");
+ clear_mods = 0;
+
+ } else if (!strcmp(p, "clear_keys")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, clear_mods == 2);
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: enabling -clear_keys mode.\n");
+ clear_mods = 2;
+ clear_keys();
+
+ } else if (!strcmp(p, "noclear_keys")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, !(clear_mods == 2));
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: disabling -clear_keys mode.\n");
+ clear_mods = 0;
+
+ } else if (strstr(p, "remap") == p) {
+ char *before, *old;
+ COLON_CHECK("remap:")
+ if (query) {
+ sprintf(buf, "ans=%s%s%s", p, co, NONUL(remap_file));
+ goto qry;
+ }
+ p += strlen("remap:");
+ if ((*p == '+' || *p == '-') && remap_file &&
+ strchr(remap_file, '/')) {
+ rfbLog("process_remote_cmd: cannot use remap:+/-\n");
+ rfbLog("in '-remap %s' mode.\n", remap_file);
+ return NULL;
+ }
+ if (remap_file) {
+ before = strdup(remap_file);
+ } else {
+ before = strdup("");
+ }
+ old = remap_file;
+ if (*p == '+') {
+ p++;
+ remap_file = add_item(remap_file, p);
+ } else if (*p == '-') {
+ p++;
+ remap_file = delete_item(remap_file, p);
+ if (! strchr(remap_file, '-')) {
+ *remap_file = '\0';
+ }
+ } else {
+ remap_file = strdup(p);
+ }
+ if (strcmp(before, remap_file)) {
+ rfbLog("process_remote_cmd: changed -remap\n");
+ rfbLog(" from: %s\n", before);
+ rfbLog(" to: %s\n", remap_file);
+ initialize_remap(remap_file);
+ }
+ if (old) free(old);
+ free(before);
+
+ } else if (!strcmp(p, "repeat")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, !no_autorepeat);
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: enabling -repeat mode.\n");
+ if (no_autorepeat) {
+ autorepeat(1);
+ }
+ no_autorepeat = 0;
+
+ } else if (!strcmp(p, "norepeat")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, no_autorepeat);
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: enabling -norepeat mode.\n");
+ if (! no_autorepeat && client_count) {
+ no_autorepeat = 1;
+ autorepeat(0);
+ }
+ no_autorepeat = 1;
+
+ } else if (!strcmp(p, "bell")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, sound_bell);
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: enabling bell (if supported).\n");
+ sound_bell = 1;
+
+ } else if (!strcmp(p, "nobell")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, !sound_bell);
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: disabling bell.\n");
+ sound_bell = 0;
+
+ } else if (!strcmp(p, "sel")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, watch_selection);
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: enabling watch_selection.\n");
+ watch_selection = 1;
+
+ } else if (!strcmp(p, "nosel")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, !watch_selection);
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: disabling watch_selection.\n");
+ watch_selection = 0;
+
+ } else if (!strcmp(p, "primary")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, watch_primary);
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: enabling watch_primary.\n");
+ watch_primary = 1;
+
+ } else if (!strcmp(p, "noprimary")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, !watch_primary);
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: disabling watch_primary.\n");
+ watch_primary = 0;
+
+ } else if (!strcmp(p, "set_no_cursor")) { /* skip-cmd-list */
+ rfbLog("process_remote_cmd: calling set_no_cursor()\n");
+ set_no_cursor();
+
+ } else if (!strcmp(p, "cursorshape")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, cursor_shape_updates);
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: turning on cursorshape mode.\n");
+
+ rfbUndrawCursor(screen);
+ set_no_cursor();
+ cursor_shape_updates = 1;
+ restore_cursor_shape_updates(screen);
+ } else if (!strcmp(p, "nocursorshape")) {
+ int i, max = 5;
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, !cursor_shape_updates);
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: turning off cursorshape mode.\n");
+
+ rfbUndrawCursor(screen);
+ set_no_cursor();
+ for (i=0; i<max; i++) {
+ /* XXX: try to force empty cursor back to client */
+ rfbPE(screen, -1);
+ }
+ cursor_shape_updates = 0;
+ disable_cursor_shape_updates(screen);
+
+ } else if (!strcmp(p, "cursorpos")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, cursor_pos_updates);
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: turning on cursorpos mode.\n");
+ cursor_pos_updates = 1;
+ } else if (!strcmp(p, "nocursorpos")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, !cursor_pos_updates);
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: turning off cursorpos mode.\n");
+ cursor_pos_updates = 0;
+
+ } else if (strstr(p, "cursor") == p) {
+ COLON_CHECK("cursor:")
+ if (query) {
+ sprintf(buf, "ans=%s%s%s", p, co,
+ NONUL(multiple_cursors_mode));
+ goto qry;
+ }
+ p += strlen("cursor:");
+ if (multiple_cursors_mode) {
+ if (prev_cursors_mode) free(prev_cursors_mode);
+ prev_cursors_mode = strdup(multiple_cursors_mode);
+ free(multiple_cursors_mode);
+ }
+ multiple_cursors_mode = strdup(p);
+
+ rfbLog("process_remote_cmd: changed -cursor mode "
+ "to: %s\n", multiple_cursors_mode);
+
+ if (strcmp(multiple_cursors_mode, "none") && !show_cursor) {
+ show_cursor = 1;
+ rfbLog("process_remote_cmd: changed show_cursor "
+ "to: %d\n", show_cursor);
+ }
+ initialize_cursors_mode();
+
+ } else if (!strcmp(p, "show_cursor")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, show_cursor);
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: enabling show_cursor.\n");
+ show_cursor = 1;
+ if (multiple_cursors_mode && !strcmp(multiple_cursors_mode,
+ "none")) {
+ free(multiple_cursors_mode);
+ if (prev_cursors_mode) {
+ multiple_cursors_mode =
+ strdup(prev_cursors_mode);
+ } else {
+ multiple_cursors_mode = strdup("default");
+ }
+ rfbLog("process_remote_cmd: changed -cursor mode "
+ "to: %s\n", multiple_cursors_mode);
+ }
+ initialize_cursors_mode();
+ } else if (!strcmp(p, "noshow_cursor") || !strcmp(p, "nocursor")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, !show_cursor);
+ goto qry;
+ }
+ if (prev_cursors_mode) free(prev_cursors_mode);
+ prev_cursors_mode = strdup(multiple_cursors_mode);
+
+ rfbLog("process_remote_cmd: disabling show_cursor.\n");
+ show_cursor = 0;
+ initialize_cursors_mode();
+
+ } else if (!strcmp(p, "xfixes")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, use_xfixes);
+ goto qry;
+ }
+ if (! xfixes_present) {
+ rfbLog("process_remote_cmd: cannot enable xfixes "
+ "(not supported on X display)\n");
+ return NULL;
+ }
+ rfbLog("process_remote_cmd: enabling -xfixes"
+ " (if supported).\n");
+ use_xfixes = 1;
+ initialize_xfixes();
+ } else if (!strcmp(p, "noxfixes")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, !use_xfixes);
+ goto qry;
+ }
+ if (! xfixes_present) {
+ rfbLog("process_remote_cmd: disabling xfixes "
+ "(but not supported on X display)\n");
+ return NULL;
+ }
+ rfbLog("process_remote_cmd: disabling -xfixes.\n");
+ use_xfixes = 0;
+ initialize_xfixes();
+
+ } else if (strstr(p, "xwarp") == p || strstr(p, "xwarppointer")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, use_xwarppointer);
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: turning on xwarppointer mode.\n");
+ use_xwarppointer = 1;
+ } else if (strstr(p, "noxwarp") == p || strstr(p, "noxwarppointer")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, !use_xwarppointer);
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: turning off xwarppointer mode.\n");
+ use_xwarppointer = 0;
+
+ } else if (strstr(p, "buttonmap") == p) {
+ COLON_CHECK("buttonmap:")
+ if (query) {
+ sprintf(buf, "ans=%s%s%s", p, co, NONUL(pointer_remap));
+ goto qry;
+ }
+ p += strlen("buttonmap:");
+ if (pointer_remap) free(pointer_remap);
+ pointer_remap = strdup(p);
+
+ rfbLog("process_remote_cmd: setting -buttonmap to:\n"
+ "\t'%s'\n", p);
+ initialize_pointer_map(p);
+
+ } else if (!strcmp(p, "dragging")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, show_dragging);
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: enabling mouse dragging mode.\n");
+ show_dragging = 1;
+ } else if (!strcmp(p, "nodragging")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, !show_dragging);
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: enabling mouse nodragging mode.\n");
+ show_dragging = 0;
+
+ } else if (strstr(p, "pointer_mode") == p) {
+ int pm;
+ COLON_CHECK("pointer_mode:")
+ if (query) {
+ sprintf(buf, "ans=%s%s%d", p, co, pointer_mode);
+ goto qry;
+ }
+ p += strlen("pointer_mode:");
+ pm = atoi(p);
+ if (pm < 1 || pm > pointer_mode_max) {
+ rfbLog("process_remote_cmd: pointer_mode out of range:"
+ " 1-%d: %d\n", pointer_mode_max, pm);
+ } else {
+ rfbLog("process_remote_cmd: setting pointer_mode %d\n",
+ pm);
+ pointer_mode = pm;
+ }
+ } else if (strstr(p, "input_skip") == p) {
+ int is;
+ COLON_CHECK("input_skip:")
+ if (query) {
+ sprintf(buf, "ans=%s%s%d", p, co, ui_skip);
+ goto qry;
+ }
+ p += strlen("input_skip:");
+ is = atoi(p);
+ rfbLog("process_remote_cmd: setting input_skip %d\n", is);
+ ui_skip = is;
+
+ } else if (!strcmp(p, "debug_pointer") || !strcmp(p, "dp")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, debug_pointer);
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: turning on debug_pointer.\n");
+ debug_pointer = 1;
+ } else if (!strcmp(p, "nodebug_pointer") || !strcmp(p, "nodp")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, !debug_pointer);
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: turning off debug_pointer.\n");
+ debug_pointer = 0;
+
+ } else if (!strcmp(p, "debug_keyboard") || !strcmp(p, "dk")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, debug_keyboard);
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: turning on debug_keyboard.\n");
+ debug_keyboard = 1;
+ } else if (!strcmp(p, "nodebug_keyboard") || !strcmp(p, "nodk")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, !debug_keyboard);
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: turning off debug_keyboard.\n");
+ debug_keyboard = 0;
+
+ } else if (strstr(p, "deferupdate") == p) {
+ int d;
+ COLON_CHECK("deferupdate:")
+ if (query) {
+ sprintf(buf, "ans=%s%s%d", p, co,
+ screen->deferUpdateTime);
+ goto qry;
+ }
+ p += strlen("deferupdate:");
+ d = atoi(p);
+ if (d < 0) d = 0;
+ rfbLog("process_remote_cmd: setting defer to %d ms.\n", d);
+ screen->deferUpdateTime = d;
+
+ } else if (strstr(p, "defer") == p) {
+ int d;
+ COLON_CHECK("defer:")
+ if (query) {
+ sprintf(buf, "ans=%s%s%d", p, co,
+ screen->deferUpdateTime);
+ goto qry;
+ }
+ p += strlen("defer:");
+ d = atoi(p);
+ if (d < 0) d = 0;
+ rfbLog("process_remote_cmd: setting defer to %d ms.\n", d);
+ /* XXX not part of API? */
+ screen->deferUpdateTime = d;
+
+ } else if (strstr(p, "wait") == p) {
+ int w;
+ COLON_CHECK("wait:")
+ if (query) {
+ sprintf(buf, "ans=%s%s%d", p, co, waitms);
+ goto qry;
+ }
+ p += strlen("wait:");
+ w = atoi(p);
+ if (w < 0) w = 0;
+ rfbLog("process_remote_cmd: setting wait %d -> %d ms.\n",
+ waitms, w);
+ waitms = w;
+
+ } else if (!strcmp(p, "nap")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, take_naps); goto qry;
+ }
+ rfbLog("process_remote_cmd: turning on nap mode.\n");
+ take_naps = 1;
+ } else if (!strcmp(p, "nonap")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, !take_naps); goto qry;
+ }
+ rfbLog("process_remote_cmd: turning off nap mode.\n");
+ take_naps = 0;
+
+ } else if (strstr(p, "sb") == p) {
+ int w;
+ COLON_CHECK("sb:")
+ if (query) {
+ sprintf(buf, "ans=%s%s%d", p, co, screen_blank);
+ goto qry;
+ }
+ p += strlen("sb:");
+ w = atoi(p);
+ if (w < 0) w = 0;
+ rfbLog("process_remote_cmd: setting screen_blank %d -> %d"
+ " sec.\n", screen_blank, w);
+ screen_blank = w;
+ } else if (strstr(p, "screen_blank") == p) {
+ int w;
+ COLON_CHECK("screen_blank:")
+ if (query) {
+ sprintf(buf, "ans=%s%s%d", p, co, screen_blank);
+ goto qry;
+ }
+ p += strlen("screen_blank:");
+ w = atoi(p);
+ if (w < 0) w = 0;
+ rfbLog("process_remote_cmd: setting screen_blank %d -> %d"
+ " sec.\n", screen_blank, w);
+ screen_blank = w;
+
+ } else if (strstr(p, "fs") == p) {
+ COLON_CHECK("fs:")
+ if (query) {
+ sprintf(buf, "ans=%s%s%f", p, co, fs_frac);
+ goto qry;
+ }
+ p += strlen("fs:");
+ fs_frac = atof(p);
+ rfbLog("process_remote_cmd: setting -fs frac to %f\n", fs_frac);
+
+ } else if (strstr(p, "gaps") == p) {
+ int g;
+ COLON_CHECK("gaps:")
+ if (query) {
+ sprintf(buf, "ans=%s%s%d", p, co, gaps_fill);
+ goto qry;
+ }
+ p += strlen("gaps:");
+ g = atoi(p);
+ if (g < 0) g = 0;
+ rfbLog("process_remote_cmd: setting gaps_fill %d -> %d.\n",
+ gaps_fill, g);
+ gaps_fill = g;
+ } else if (strstr(p, "grow") == p) {
+ int g;
+ COLON_CHECK("grow:")
+ if (query) {
+ sprintf(buf, "ans=%s%s%d", p, co, grow_fill);
+ goto qry;
+ }
+ p += strlen("grow:");
+ g = atoi(p);
+ if (g < 0) g = 0;
+ rfbLog("process_remote_cmd: setting grow_fill %d -> %d.\n",
+ grow_fill, g);
+ grow_fill = g;
+ } else if (strstr(p, "fuzz") == p) {
+ int f;
+ COLON_CHECK("fuzz:")
+ if (query) {
+ sprintf(buf, "ans=%s%s%d", p, co, tile_fuzz);
+ goto qry;
+ }
+ p += strlen("fuzz:");
+ f = atoi(p);
+ if (f < 0) f = 0;
+ rfbLog("process_remote_cmd: setting tile_fuzz %d -> %d.\n",
+ tile_fuzz, f);
+ grow_fill = f;
+
+ } else if (strstr(p, "progressive") == p) {
+ int f;
+ COLON_CHECK("progressive:")
+ if (query) {
+ sprintf(buf, "ans=%s%s%d", p, co,
+ screen->progressiveSliceHeight);
+ goto qry;
+ }
+ p += strlen("progressive:");
+ f = atoi(p);
+ if (f < 0) f = 0;
+ rfbLog("process_remote_cmd: setting progressive %d -> %d.\n",
+ screen->progressiveSliceHeight, f);
+ screen->progressiveSliceHeight = f;
+
+ } else if (!strcmp(p, "noremote")) {
+ if (query) {
+ sprintf(buf, "ans=%s:%d", p, !accept_remote_cmds);
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: disabling remote commands.\n");
+ accept_remote_cmds = 0; /* cannot be turned back on. */
+
+ } else if (query) {
+ /* read-only variables that can only be queried: */
+
+ if (!strcmp(p, "display")) {
+ char *d = DisplayString(dpy);
+ if (! d) d = "unknown";
+ if (*d == ':') {
+ sprintf(buf, "aro=%s:%s%s", p, this_host(), d);
+ } else {
+ sprintf(buf, "aro=%s:%s", p, d);
+ }
+ } else if (!strcmp(p, "vncdisplay")) {
+ sprintf(buf, "aro=%s:%s", p, NONUL(vnc_desktop_name));
+ } else if (!strcmp(p, "desktopname")) {
+ sprintf(buf, "aro=%s:%s", p, NONUL(rfb_desktop_name));
+ } else if (!strcmp(p, "desktop")) {
+ sprintf(buf, "aro=%s:%s", p, NONUL(rfb_desktop_name));
+ } else if (!strcmp(p, "auth")) {
+ sprintf(buf, "aro=%s:%s", p, NONUL(auth_file));
+ } else if (!strcmp(p, "rootshift")) {
+ sprintf(buf, "aro=%s:%d", p, rootshift);
+ } else if (!strcmp(p, "scale_str")) {
+ sprintf(buf, "aro=%s:%s", p, NONUL(scale_str));
+ } else if (!strcmp(p, "scaled_x")) {
+ sprintf(buf, "aro=%s:%d", p, scaled_x);
+ } else if (!strcmp(p, "scaled_y")) {
+ sprintf(buf, "aro=%s:%d", p, scaled_y);
+ } else if (!strcmp(p, "scale_numer")) {
+ sprintf(buf, "aro=%s:%d", p, scale_numer);
+ } else if (!strcmp(p, "scale_denom")) {
+ sprintf(buf, "aro=%s:%d", p, scale_denom);
+ } else if (!strcmp(p, "scale_fac")) {
+ sprintf(buf, "aro=%s:%f", p, scale_fac);
+ } else if (!strcmp(p, "scaling_noblend")) {
+ sprintf(buf, "aro=%s:%d", p, scaling_noblend);
+ } else if (!strcmp(p, "scaling_nomult4")) {
+ sprintf(buf, "aro=%s:%d", p, scaling_nomult4);
+ } else if (!strcmp(p, "scaling_pad")) {
+ sprintf(buf, "aro=%s:%d", p, scaling_pad);
+ } else if (!strcmp(p, "scaling_interpolate")) {
+ sprintf(buf, "aro=%s:%d", p, scaling_interpolate);
+ } else if (!strcmp(p, "inetd")) {
+ sprintf(buf, "aro=%s:%d", p, inetd);
+ } else if (!strcmp(p, "safer")) {
+ sprintf(buf, "aro=%s:%d", p, safe_remote_only);
+ } else if (!strcmp(p, "unsafe")) {
+ sprintf(buf, "aro=%s:%d", p, !safe_remote_only);
+ } else if (!strcmp(p, "passwdfile")) {
+ sprintf(buf, "aro=%s:%s", p, NONUL(passwdfile));
+ } else if (!strcmp(p, "using_shm")) {
+ sprintf(buf, "aro=%s:%d", p, !using_shm);
+ } else if (!strcmp(p, "logfile") || !strcmp(p, "o")) {
+ sprintf(buf, "aro=%s:%s", p, NONUL(logfile));
+ } else if (!strcmp(p, "rc")) {
+ sprintf(buf, "aro=%s:%s", p, NONUL(rc_rcfile));
+ } else if (!strcmp(p, "norc")) {
+ sprintf(buf, "aro=%s:%d", p, rc_norc);
+ } else if (!strcmp(p, "h") || !strcmp(p, "help") ||
+ !strcmp(p, "V") || !strcmp(p, "version") ||
+ !strcmp(p, "lastmod")) {
+ sprintf(buf, "aro=%s:%s", p, NONUL(lastmod));
+ } else if (!strcmp(p, "bg")) {
+ sprintf(buf, "aro=%s:%d", p, opts_bg);
+ } else if (!strcmp(p, "nofb")) {
+ sprintf(buf, "aro=%s:%d", p, nofb);
+ } else if (!strcmp(p, "sigpipe")) {
+ sprintf(buf, "aro=%s:%s", p, NONUL(sigpipe));
+ } else if (!strcmp(p, "threads")) {
+ sprintf(buf, "aro=%s:%d", p, use_threads);
+ } else if (!strcmp(p, "clients")) {
+ char *str = list_clients();
+ sprintf(buf, "aro=%s:%s", p, str);
+ free(str);
+ } else if (!strcmp(p, "client_count")) {
+ sprintf(buf, "aro=%s:%d", p, client_count);
+ } else if (!strcmp(p, "pid")) {
+ sprintf(buf, "aro=%s:%d", p, (int) getpid());
+ } else if (!strcmp(p, "ext_xtest")) {
+ sprintf(buf, "aro=%s:%d", p, xtest_present);
+ } else if (!strcmp(p, "ext_xkb")) {
+ sprintf(buf, "aro=%s:%d", p, xkb_present);
+ } else if (!strcmp(p, "ext_xshm")) {
+ sprintf(buf, "aro=%s:%d", p, xshm_present);
+ } else if (!strcmp(p, "ext_xinerama")) {
+ sprintf(buf, "aro=%s:%d", p, xinerama_present);
+ } else if (!strcmp(p, "ext_overlay")) {
+ sprintf(buf, "aro=%s:%d", p, overlay_present);
+ } else if (!strcmp(p, "ext_xfixes")) {
+ sprintf(buf, "aro=%s:%d", p, xfixes_present);
+ } else if (!strcmp(p, "ext_xdamage")) {
+ sprintf(buf, "aro=%s:%d", p, xdamage_present);
+ } else if (!strcmp(p, "ext_xrandr")) {
+ sprintf(buf, "aro=%s:%d", p, xrandr_present);
+ } else if (!strcmp(p, "rootwin")) {
+ sprintf(buf, "aro=%s:0x%x", p, (unsigned int) rootwin);
+ } else if (!strcmp(p, "num_buttons")) {
+ sprintf(buf, "aro=%s:%d", p, num_buttons);
+ } else if (!strcmp(p, "button_mask")) {
+ sprintf(buf, "aro=%s:%d", p, button_mask);
+ } else if (!strcmp(p, "mouse_x")) {
+ sprintf(buf, "aro=%s:%d", p, cursor_x);
+ } else if (!strcmp(p, "mouse_y")) {
+ sprintf(buf, "aro=%s:%d", p, cursor_y);
+ } else if (!strcmp(p, "bpp")) {
+ sprintf(buf, "aro=%s:%d", p, bpp);
+ } else if (!strcmp(p, "depth")) {
+ sprintf(buf, "aro=%s:%d", p, depth);
+ } else if (!strcmp(p, "indexed_color")) {
+ sprintf(buf, "aro=%s:%d", p, indexed_color);
+ } else if (!strcmp(p, "dpy_x")) {
+ sprintf(buf, "aro=%s:%d", p, dpy_x);
+ } else if (!strcmp(p, "dpy_y")) {
+ sprintf(buf, "aro=%s:%d", p, dpy_y);
+ } else if (!strcmp(p, "rfbport")) {
+ sprintf(buf, "aro=%s:%d", p, screen->port);
+ } else if (!strcmp(p, "rfbwait")) {
+ NOTAPPRO
+ } else if (!strcmp(p, "rfbauth")) {
+ NOTAPPRO
+ } else if (!strcmp(p, "passwd")) {
+ NOTAPPRO
+ } else if (!strcmp(p, "alwaysshared")) {
+ sprintf(buf, "aro=%s:%d", p, screen->alwaysShared);
+ } else if (!strcmp(p, "dontdisconnect")) {
+ sprintf(buf, "aro=%s:%d", p, screen->dontDisconnect);
+ } else if (!strcmp(p, "httpdir")) {
+ sprintf(buf, "aro=%s:%s", p, NONUL(screen->httpDir));
+ } else if (!strcmp(p, "enablehttpproxy")) {
+ sprintf(buf, "aro=%s:%d", p,
+ screen->httpEnableProxyConnect);
+ } else {
+ NOTAPP
+ }
+ goto qry;
+ } else {
+ NOTAPP
+ rfbLog("process_remote_cmd: warning unknown\n");
+ rfbLog("command \"%s\"\n", p);
+ return NULL;
+ }
+
+ if (*p != '\0' && do_vnc_connect) {
+ /* this is a reverse connection */
+ strncpy(vnc_connect_str, p, VNC_CONNECT_MAX);
+ vnc_connect_str[VNC_CONNECT_MAX] = '\0';
+ }
+
+ done:
+ return NULL;
+
+ qry:
+
+ if (stringonly) {
+ return strdup(buf);
+ } else if (client_connect_file) {
+ FILE *out = fopen(client_connect_file, "w");
+ if (out != NULL) {
+ fprintf(out, "%s\n", buf);
+ fclose(out);
+ usleep(200*1000);
+ }
+ } else {
+ set_vnc_connect_prop(buf);
+ XFlush(dpy);
+ }
+ return NULL;
+}
+
/* -- cursor.c -- */
/*
* Here begins a bit of a mess to experiment with multiple cursors
@@ -4450,6 +7282,26 @@ typedef struct cursor_info {
rfbCursorPtr rfb;
} cursor_info_t;
+/* empty cursor */
+static char* curs_empty_data =
+" "
+" ";
+
+static char* curs_empty_mask =
+" "
+" ";
+static cursor_info_t cur_empty = {NULL, NULL, 2, 2, 0, 0, 0, NULL};
+
+/* dot cursor */
+static char* curs_dot_data =
+" "
+" x";
+
+static char* curs_dot_mask =
+" "
+" x";
+static cursor_info_t cur_dot = {NULL, NULL, 2, 2, 0, 0, 0, NULL};
+
/* main cursor */
static char* curs_arrow_data =
" "
@@ -4642,18 +7494,107 @@ static char* curs_xterm_mask =
static cursor_info_t cur_xterm = {NULL, NULL, 16, 16, 8, 8, 1, NULL};
enum cursor_names {
- CURS_ARROW = 0,
+ CURS_EMPTY = 0,
+ CURS_DOT,
+
+ CURS_ARROW,
CURS_ROOT,
CURS_WM,
- CURS_TERM
+ CURS_TERM,
+
+ CURS_DYN1,
+ CURS_DYN2,
+ CURS_DYN3,
+ CURS_DYN4,
+ CURS_DYN5,
+ CURS_DYN6,
+ CURS_DYN7,
+ CURS_DYN8,
+ CURS_DYN9,
+ CURS_DYN10,
+ CURS_DYN11,
+ CURS_DYN12,
+ CURS_DYN13,
+ CURS_DYN14,
+ CURS_DYN15,
+ CURS_DYN16
};
-static cursor_info_t *cursors[10];
+#define CURS_DYN_MIN CURS_DYN1
+#define CURS_DYN_MAX CURS_DYN16
+#define CURS_DYN_NUM (CURS_DYN_MAX - CURS_DYN_MIN + 1)
+
+#define CURS_MAX 32
+static cursor_info_t *cursors[CURS_MAX];
static void setup_cursors(void) {
- /* TODO clean this up if we ever do more cursors... */
rfbCursorPtr rfb_curs;
int i, n = 0;
+ static int first = 1;
+
+ rfbLog("setting up %d cursors...\n", CURS_MAX);
+
+ if (first) {
+ for (i=0; i<CURS_MAX; i++) {
+ cursors[i] = NULL;
+ }
+ }
+ first = 0;
+
+ if (screen) {
+ rfbUndrawCursor(screen);
+ screen->cursor = NULL;
+ LOCK(screen->cursorMutex);
+ }
+
+ for (i=0; i<CURS_MAX; i++) {
+ cursor_info_t *ci;
+ if (cursors[i]) {
+ /* clear out any existing ones: */
+ ci = cursors[i];
+ if (ci->rfb) {
+ /* this is the rfbCursor part: */
+ if (ci->rfb->richSource) {
+ free(ci->rfb->richSource);
+ }
+ if (ci->rfb->source) {
+ free(ci->rfb->source);
+ }
+ if (ci->rfb->mask) {
+ free(ci->rfb->mask);
+ }
+ free(ci->rfb);
+ }
+ if (ci->data) {
+ free(ci->data);
+ }
+ if (ci->mask) {
+ free(ci->mask);
+ }
+ }
+
+ /* create new struct: */
+ ci = (cursor_info_t *) malloc(sizeof(cursor_info_t));
+ ci->data = NULL;
+ ci->mask = NULL;
+ ci->wx = 0;
+ ci->wy = 0;
+ ci->sx = 0;
+ ci->sy = 0;
+ ci->reverse = 0;
+ ci->rfb = NULL;
+ cursors[i] = ci;
+ }
+
+ /* clear any xfixes cursor cache (no freeing is done) */
+ get_xfixes_cursor(1);
+
+ /* manually fill in the data+masks: */
+ cur_empty.data = curs_empty_data;
+ cur_empty.mask = curs_empty_mask;
+
+ cur_dot.data = curs_dot_data;
+ cur_dot.mask = curs_dot_mask;
cur_arrow.data = curs_arrow_data;
cur_arrow.mask = curs_arrow_mask;
@@ -4670,12 +7611,16 @@ static void setup_cursors(void) {
cur_xterm.data = curs_xterm_data;
cur_xterm.mask = curs_xterm_mask;
+ cursors[CURS_EMPTY] = &cur_empty; n++;
+ cursors[CURS_DOT] = &cur_dot; n++;
cursors[CURS_ARROW] = &cur_arrow; n++;
cursors[CURS_ROOT] = &cur_root; n++;
cursors[CURS_WM] = &cur_fleur; n++;
cursors[CURS_TERM] = &cur_xterm; n++;
for (i=0; i<n; i++) {
+ /* create rfbCursors for the special cursors: */
+
cursor_info_t *ci = cursors[i];
ci->data = strdup(ci->data);
@@ -4698,8 +7643,49 @@ static void setup_cursors(void) {
rfb_curs->cleanupMask = FALSE;
rfb_curs->cleanupRichSource = FALSE;
+ if (bpp == 8 && indexed_color) {
+ /*
+ * use richsource in PseudoColor for better
+ * looking cursors (i.e. two-color).
+ */
+ int x, y, k = 0, bw;
+ char d, m;
+ int black = BlackPixel(dpy, scr);
+ int white = WhitePixel(dpy, scr);
+
+ rfb_curs->richSource
+ = (char *)calloc(ci->wx * ci->wy, 1);
+
+ for (y = 0; y < ci->wy; y++) {
+ for (x = 0; x < ci->wx; x++) {
+ d = *(ci->data + k);
+ m = *(ci->mask + k);
+ if (d == ' ' && m == ' ') {
+ k++;
+ continue;
+ } else if (m != ' ' && d == ' ') {
+ bw = black;
+ } else {
+ bw = white;
+ }
+ if (ci->reverse) {
+ if (bw == black) {
+ bw = white;
+ } else {
+ bw = black;
+ }
+ }
+ *(rfb_curs->richSource+k) = (unsigned char) bw;
+ k++;
+ }
+ }
+ }
ci->rfb = rfb_curs;
}
+ if (screen) {
+ UNLOCK(screen->cursorMutex);
+ }
+ rfbLog(" done.\n");
}
typedef struct win_str_info {
@@ -4722,15 +7708,14 @@ void tree_descend_cursor(int *depth, Window *w, win_str_info_t *winfo) {
unsigned int mask;
Window wins[10];
int descend, maxtries = 10;
- char *name, a;
+ char *name, *s = multiple_cursors_mode;
static XClassHint *classhint = NULL;
int nm_info = 1;
XErrorHandler old_handler;
X_LOCK;
- a = multiple_cursors_mode[0];
- if (a == 'd' || a == 'X') {
+ if (!strcmp(s, "default") || !strcmp(s, "X") || !strcmp(s, "arrow")) {
nm_info = 0;
}
@@ -4814,6 +7799,304 @@ void tree_descend_cursor(int *depth, Window *w, win_str_info_t *winfo) {
*w = wins[descend];
}
+void initialize_xfixes(void) {
+#ifdef LIBVNCSERVER_HAVE_LIBXFIXES
+ if (xfixes_present) {
+ if (use_xfixes) {
+ XFixesSelectCursorInput(dpy, rootwin,
+ XFixesDisplayCursorNotifyMask);
+ } else {
+ XFixesSelectCursorInput(dpy, rootwin, 0);
+ }
+ }
+#endif
+}
+
+int get_xfixes_cursor(int init) {
+ static unsigned long last_cursor = 0;
+ static int last_index = 0;
+ static time_t curs_times[CURS_MAX];
+ static unsigned long curs_index[CURS_MAX];
+ int which = CURS_ARROW;
+
+ if (init) {
+ /* zero out our cache (cursors are not freed) */
+ int i;
+ for (i=0; i<CURS_MAX; i++) {
+ curs_times[i] = 0;
+ curs_index[i] = 0;
+ }
+ last_cursor = 0;
+ last_index = 0;
+ return -1;
+ }
+
+ if (xfixes_present) {
+#ifdef LIBVNCSERVER_HAVE_LIBXFIXES
+ int use, oldest, i, x, y, w, h, len;
+ int Bpp = bpp/8;
+ time_t oldtime, now;
+ char *bitmap, *rich;
+ unsigned long black, white;
+ rfbCursorPtr c;
+ XFixesCursorImage *xfc;
+
+ if (! got_xfixes_cursor_notify) {
+ /* try again for XFixesCursorNotify event */
+ XEvent xev;
+ X_LOCK;
+ if (XCheckTypedEvent(dpy, xfixes_base_event_type +
+ XFixesCursorNotify, &xev)) {
+ got_xfixes_cursor_notify++;
+ }
+ X_UNLOCK;
+ }
+ if (! got_xfixes_cursor_notify) {
+ /* evidently no cursor change, just return last one */
+ if (last_index) {
+ return last_index;
+ } else {
+ return CURS_ARROW;
+ }
+ }
+ got_xfixes_cursor_notify = 0;
+
+ /* retrieve the cursor info + pixels from server: */
+ X_LOCK;
+ xfc = XFixesGetCursorImage(dpy);
+ X_UNLOCK;
+ if (! xfc) {
+ /* failure. */
+ return(which);
+ }
+
+ if (xfc->cursor_serial == last_cursor) {
+ /* same serial index: no change */
+ X_LOCK;
+ XFree(xfc);
+ X_UNLOCK;
+ if (last_index) {
+ return last_index;
+ } else {
+ return CURS_ARROW;
+ }
+ }
+
+ oldest = CURS_DYN_MIN;
+ oldtime = curs_times[oldest];
+ now = time(0);
+ for (i = CURS_DYN_MIN; i <= CURS_DYN_MAX; i++) {
+ if (curs_times[i] < oldtime) {
+ /* watch for oldest one to overwrite */
+ oldest = i;
+ oldtime = curs_times[i];
+ }
+ if (xfc->cursor_serial == curs_index[i]) {
+ /*
+ * got a hit with an existing cursor,
+ * use that one.
+ */
+ last_cursor = curs_index[i];
+ curs_times[i] = now;
+ last_index = i;
+ X_LOCK;
+ XFree(xfc);
+ X_UNLOCK;
+ return last_index;
+ }
+ }
+
+ if (screen) {
+ rfbUndrawCursor(screen);
+ }
+ /* we need to create the cursor and overwrite oldest */
+ use = oldest;
+ if (cursors[use]->rfb) {
+ /* clean up oldest if it exists */
+ if (cursors[use]->rfb->richSource) {
+ free(cursors[use]->rfb->richSource);
+ }
+ if (cursors[use]->rfb->source) {
+ free(cursors[use]->rfb->source);
+ }
+ if (cursors[use]->rfb->mask) {
+ free(cursors[use]->rfb->mask);
+ }
+ free(cursors[use]->rfb);
+ }
+
+ X_LOCK;
+ black = BlackPixel(dpy, scr);
+ white = WhitePixel(dpy, scr);
+ X_UNLOCK;
+
+ w = xfc->width;
+ h = xfc->height;
+ len = w * h;
+
+ /* for bitmap data */
+ bitmap = (char *)malloc(len+1);
+ bitmap[len] = '\0';
+
+ /* for rich cursor pixel data */
+ rich = (char *)calloc(Bpp*len, 1);
+
+ i = 0;
+ for (y = 0; y < h; y++) {
+ for (x = 0; x < w; x++) {
+ unsigned long r, g, b, a;
+ unsigned int ui;
+ char *p;
+
+ a = 0xff000000 & (*(xfc->pixels+i));
+ a = a >> 24; /* alpha channel */
+
+ if (a == 0) {
+ bitmap[i] = ' ';
+ i++;
+ continue;
+ } else {
+ bitmap[i] = 'x';
+ }
+
+ r = 0x00ff0000 & (*(xfc->pixels+i));
+ g = 0x0000ff00 & (*(xfc->pixels+i));
+ b = 0x000000ff & (*(xfc->pixels+i));
+ r = r >> 16; /* red */
+ g = g >> 8; /* green */
+ b = b >> 0; /* blue */
+
+ if (indexed_color) {
+ /*
+ * Choose black or white for
+ * PseudoColor case.
+ */
+ int value = (r+g+b)/3;
+ if (value > 127) {
+ ui = white;
+ } else {
+ ui = black;
+ }
+ } else {
+ /*
+ * Otherwise map the RGB data onto
+ * the framebuffer format:
+ */
+ r = (main_red_max * r)/255;
+ g = (main_green_max * g)/255;
+ b = (main_blue_max * b)/255;
+ ui = 0;
+ ui |= (r << main_red_shift);
+ ui |= (g << main_green_shift);
+ ui |= (b << main_blue_shift);
+ }
+
+ /* insert value into rich source: */
+ p = rich + Bpp*i;
+ if (Bpp == 1) {
+ *((unsigned char *)p)
+ = (unsigned char) ui;
+ } else if (Bpp == 2) {
+ *((unsigned short *)p)
+ = (unsigned short) ui;
+ } else if (Bpp == 4) {
+ *((unsigned int *)p)
+ = (unsigned int) ui;
+ }
+ i++;
+ }
+ }
+
+ /* create the cursor with the bitmap: */
+ c = rfbMakeXCursor(w, h, bitmap, bitmap);
+ free(bitmap);
+
+ /* set up the cursor parameters: */
+ c->xhot = xfc->xhot;
+ c->yhot = xfc->yhot;
+ c->cleanup = FALSE;
+ c->cleanupSource = FALSE;
+ c->cleanupMask = FALSE;
+ c->cleanupRichSource = FALSE;
+ c->richSource = rich;
+
+ /* place cursor into our collection */
+ cursors[use]->rfb = c;
+
+ /* update time and serial index: */
+ curs_times[use] = now;
+ curs_index[use] = xfc->cursor_serial;
+ last_index = use;
+ last_cursor = xfc->cursor_serial;
+
+ which = last_index;
+
+ X_LOCK;
+ XFree(xfc);
+ X_UNLOCK;
+#endif
+ }
+ return(which);
+}
+
+int known_cursors_mode(char *s) {
+/*
+ * default: see initialize_cursors_mode() for default behavior.
+ * arrow: unchanging white arrow.
+ * Xn*: show X on root background. Optional n sets treedepth.
+ * some: do the heuristics for root, wm, term detection.
+ * most: if display have overlay or xfixes, show all cursors,
+ * otherwise do the same as "some"
+ * none: show no cursor.
+ */
+ if (strcmp(s, "default") && strcmp(s, "arrow") && *s != 'X' &&
+ strcmp(s, "some") && strcmp(s, "most") && strcmp(s, "none")) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+void initialize_cursors_mode(void) {
+ char *s = multiple_cursors_mode;
+ if (!s || !known_cursors_mode(s)) {
+ rfbLog("unknown cursors mode: %s\n", s);
+ rfbLog("resetting cursors mode to \"default\"\n");
+ if (multiple_cursors_mode) free(multiple_cursors_mode);
+ multiple_cursors_mode = strdup("default");
+ s = multiple_cursors_mode;
+ }
+ if (!strcmp(s, "none")) {
+ show_cursor = 0;
+ } else {
+ /* we do NOT set show_cursor = 1, let the caller do that */
+ }
+
+ show_multiple_cursors = 0;
+ if (show_cursor) {
+ if (!strcmp(s, "default")) {
+ if(multiple_cursors_mode) free(multiple_cursors_mode);
+ multiple_cursors_mode = strdup("X");
+ s = multiple_cursors_mode;
+ }
+ if (*s == 'X' || !strcmp(s, "some") || !strcmp(s, "most")) {
+ show_multiple_cursors = 1;
+ } else {
+ show_multiple_cursors = 0;
+ /* hmmm, some bug going back to arrow mode.. */
+ set_rfb_cursor(CURS_ARROW);
+ }
+ if (screen) {
+ set_cursor_was_changed(screen);
+ }
+ } else {
+ if (screen) {
+ screen->cursor = NULL; /* dangerous? */
+ set_cursor_was_changed(screen);
+ }
+ }
+}
+
int get_which_cursor(void) {
int which = CURS_ARROW;
@@ -4824,14 +8107,26 @@ int get_which_cursor(void) {
Window win;
XErrorHandler old_handler;
int mode = 0;
- char a = multiple_cursors_mode[0];
- if (a == 'd') {
+ if (drag_in_progress) {
+ return -1;
+ }
+
+ if (!strcmp(multiple_cursors_mode, "arrow")) {
+ /* should not happen... */
+ return CURS_ARROW;
+ } else if (!strcmp(multiple_cursors_mode, "default")) {
mode = 0;
- } else if (a == 'X') {
+ } else if (!strcmp(multiple_cursors_mode, "X")) {
mode = 1;
- } else {
+ } else if (!strcmp(multiple_cursors_mode, "some")) {
mode = 2;
+ } else if (!strcmp(multiple_cursors_mode, "most")) {
+ mode = 3;
+ }
+
+ if (mode == 3 && xfixes_present && use_xfixes) {
+ return get_xfixes_cursor(0);
}
if (depth_cutoff < 0) {
@@ -4852,11 +8147,13 @@ int get_which_cursor(void) {
tree_descend_cursor(&depth, &win, &winfo);
- if (depth <= depth_cutoff) {
+ if (depth <= depth_cutoff && !subwin) {
which = CURS_ROOT;
- } else if (mode >= 2) {
+
+ } else if (mode == 2 || mode == 3) {
int which0 = which;
+ /* apply crude heuristics to choose a cursor... */
if (win) {
int ratio = 10, x, y;
unsigned int w, h, bw, d;
@@ -4864,6 +8161,8 @@ int get_which_cursor(void) {
trapped_xerror = 0;
old_handler = XSetErrorHandler(trap_xerror);
+
+ /* "narrow" windows are WM */
if (XGetGeometry(dpy, win, &r, &x, &y, &w, &h,
&bw, &d)) {
if (w > ratio * h || h > ratio * w) {
@@ -4874,12 +8173,17 @@ int get_which_cursor(void) {
trapped_xerror = 0;
}
if (which == which0) {
+ /* the string "term" mean I-beam. */
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;
+ } else if (strstr(winfo.res_name, "text")) {
+ which = CURS_TERM;
+ } else if (strstr(winfo.res_class, "text")) {
+ which = CURS_TERM;
}
}
}
@@ -4948,12 +8252,52 @@ void set_cursor_was_moved(rfbScreenInfoPtr s) {
rfbReleaseClientIterator(iter);
}
-void unset_cursor_shape_updates(rfbScreenInfoPtr s) {
+void restore_cursor_shape_updates(rfbScreenInfoPtr s) {
rfbClientIteratorPtr iter;
rfbClientPtr cl;
+ int count = 0;
iter = rfbGetClientIterator(s);
while( (cl = rfbClientIteratorNext(iter)) ) {
+ int changed = 0;
+ ClientData *cd = (ClientData *) cl->clientData;
+
+ if (cd->had_cursor_shape_updates) {
+ rfbLog("restoring enableCursorShapeUpdates for client"
+ " 0x%x\n", cl);
+ cl->enableCursorShapeUpdates = TRUE;
+ changed = 1;
+ }
+ if (cd->had_cursor_pos_updates) {
+ rfbLog("restoring enableCursorPosUpdates for client"
+ " 0x%x\n", cl);
+ cl->enableCursorPosUpdates = TRUE;
+ changed = 1;
+ }
+ if (changed) {
+ cl->cursorWasChanged = TRUE;
+ count++;
+ }
+ }
+ rfbReleaseClientIterator(iter);
+}
+
+void disable_cursor_shape_updates(rfbScreenInfoPtr s) {
+ rfbClientIteratorPtr iter;
+ rfbClientPtr cl;
+
+ iter = rfbGetClientIterator(s);
+ while( (cl = rfbClientIteratorNext(iter)) ) {
+ ClientData *cd;
+ cd = (ClientData *) cl->clientData;
+
+ if (cl->enableCursorShapeUpdates) {
+ cd->had_cursor_shape_updates = 1;
+ }
+ if (cl->enableCursorPosUpdates) {
+ cd->had_cursor_pos_updates = 1;
+ }
+
cl->enableCursorShapeUpdates = FALSE;
cl->enableCursorPosUpdates = FALSE;
cl->cursorWasChanged = FALSE;
@@ -4961,14 +8305,14 @@ void unset_cursor_shape_updates(rfbScreenInfoPtr s) {
rfbReleaseClientIterator(iter);
}
-int cursor_pos_updates_clients(rfbScreenInfoPtr s) {
+int cursor_shape_updates_clients(rfbScreenInfoPtr s) {
rfbClientIteratorPtr iter;
rfbClientPtr cl;
int count = 0;
iter = rfbGetClientIterator(s);
while( (cl = rfbClientIteratorNext(iter)) ) {
- if (cl->enableCursorPosUpdates) {
+ if (cl->enableCursorShapeUpdates) {
count++;
}
}
@@ -4976,14 +8320,14 @@ int cursor_pos_updates_clients(rfbScreenInfoPtr s) {
return count;
}
-int cursor_shape_updates_clients(rfbScreenInfoPtr s) {
+int cursor_pos_updates_clients(rfbScreenInfoPtr s) {
rfbClientIteratorPtr iter;
rfbClientPtr cl;
int count = 0;
iter = rfbGetClientIterator(s);
while( (cl = rfbClientIteratorNext(iter)) ) {
- if (cl->enableCursorShapeUpdates) {
+ if (cl->enableCursorPosUpdates) {
count++;
}
}
@@ -5074,7 +8418,7 @@ void cursor_position(int x, int y) {
}
void set_rfb_cursor(int which) {
- int workaround = 1; /* if rfbSetCursor does not mark modified */
+ int workaround = 2; /* if rfbSetCursor does not mark modified */
if (! show_cursor) {
return;
@@ -5101,12 +8445,21 @@ void set_rfb_cursor(int which) {
}
}
- rfbSetCursor(screen, cursors[which]->rfb, FALSE);
+ if (!cursors[which] || !cursors[which]->rfb) {
+ rfbLog("non-existent cursor: which=%d\n", which);
+ return;
+ } else {
+ rfbSetCursor(screen, cursors[which]->rfb, FALSE);
+ }
/* this is a 2nd workaround for rfbSetCursor() */
- if (screen->underCursorBuffer == NULL &&
- screen->underCursorBufferLen != 0) {
- screen->underCursorBufferLen = 0;
+ if (workaround > 1) {
+ if (screen->underCursorBuffer == NULL &&
+ screen->underCursorBufferLen != 0) {
+ LOCK(screen->cursorMutex);
+ screen->underCursorBufferLen = 0;
+ UNLOCK(screen->cursorMutex);
+ }
}
if (workaround) {
@@ -5114,8 +8467,15 @@ void set_rfb_cursor(int which) {
}
}
+void set_no_cursor(void) {
+ set_rfb_cursor(CURS_EMPTY);
+}
+
void set_cursor(int x, int y, int which) {
static int last = -1;
+ if (which < 0) {
+ which = last;
+ }
if (last < 0 || which != last) {
set_rfb_cursor(which);
}
@@ -5172,13 +8532,20 @@ void check_x11_pointer(void) {
* the clients and dynamically if -flashcmap is specified.
*/
#define NCOLOR 256
-void set_colormap(void) {
+void set_colormap(int reset) {
static int first = 1;
static XColor color[NCOLOR], prev[NCOLOR];
Colormap cmap;
Visual *vis;
int i, ncells, diffs = 0;
+ if (reset) {
+ first = 1;
+ if (screen->colourMap.data.shorts) {
+ free(screen->colourMap.data.shorts);
+ }
+ }
+
if (first) {
screen->colourMap.count = NCOLOR;
screen->serverFormat.trueColour = FALSE;
@@ -5300,8 +8667,13 @@ void set_visual(char *str) {
XVisualInfo vinfo;
char *p, *vstring = strdup(str);
- if (! quiet) {
- fprintf(stderr, "set_visual: %s\n", vstring);
+ visual_id = (VisualID) 0;
+ visual_depth = 0;
+
+ if (!strcmp(vstring, "ignore") || !strcmp(vstring, "default")
+ || !strcmp(vstring, "")) {
+ free(vstring);
+ return;
}
/* set visual depth */
@@ -5312,6 +8684,11 @@ void set_visual(char *str) {
} else {
vdepth = defdepth;
}
+ if (! quiet) {
+ fprintf(stderr, "\nVisual Info:\n");
+ fprintf(stderr, " set_visual(\"%s\")\n", str);
+ fprintf(stderr, " visual_depth: %d\n", vdepth);
+ }
/* set visual id number */
if (strcmp(vstring, "StaticGray") == 0) {
@@ -5333,21 +8710,22 @@ void set_visual(char *str) {
visual_id = (VisualID) v_in;
return;
}
- fprintf(stderr, "bad -visual arg: %s\n", vstring);
- exit(1);
+ rfbLog("bad -visual arg: %s\n", vstring);
+ clean_up_exit(1);
}
visual_id = (VisualID) v_in;
free(vstring);
return;
}
+ if (! quiet) fprintf(stderr, " visual: %d\n", vis);
if (XMatchVisualInfo(dpy, scr, visual_depth, vis, &vinfo)) {
;
} else if (XMatchVisualInfo(dpy, scr, defdepth, vis, &vinfo)) {
;
} else {
- fprintf(stderr, "could not find visual: %s\n", vstring);
- exit(1);
+ rfbLog("could not find visual: %s\n", vstring);
+ clean_up_exit(1);
}
free(vstring);
@@ -5369,6 +8747,7 @@ void nofb_hook(rfbClientPtr cl) {
return;
}
rfbLog("framebuffer requested in -nofb mode by client %s\n", cl->host);
+ /* ignore xrandr */
fb = XGetImage_wr(dpy, window, 0, 0, dpy_x, dpy_y, AllPlanes, ZPixmap);
main_fb = fb->data;
rfb_fb = main_fb;
@@ -5377,19 +8756,437 @@ void nofb_hook(rfbClientPtr cl) {
screen->displayHook = NULL;
}
+void do_new_fb(int reset_mem) {
+ XImage *fb;
+ char *old_main = main_fb;
+ char *old_rfb = rfb_fb;
+
+ /* for threaded we really should lock libvncserver out. */
+ if (use_threads) {
+ rfbLog("warning: changing framebuffers while threaded may\n");
+ rfbLog(" not work, do not use -threads if problems arise.\n");
+ }
+
+ if (reset_mem) {
+ clean_shm(0);
+ free_tiles();
+ }
+
+ fb = initialize_xdisplay_fb();
+
+ initialize_screen(NULL, NULL, fb);
+
+ if (reset_mem) {
+ initialize_tiles();
+ initialize_blackouts_and_xinerama();
+ initialize_polling_images();
+ }
+
+ if (old_main != old_rfb && old_main) {
+ free(old_main);
+ }
+ if (old_rfb) {
+ free(old_rfb);
+ }
+ fb0 = fb;
+}
+
+void remove_fake_fb(void) {
+ if (! screen) {
+ return;
+ }
+ rfbLog("removing fake fb: 0x%x\n", fake_fb);
+
+ do_new_fb(1);
+
+ /*
+ * fake_fb is freed in do_new_fb(), but we set to NULL here to
+ * indicate it is gone.
+ */
+ fake_fb = NULL;
+}
+
+void install_fake_fb(int w, int h, int bpp) {
+ int bpc;
+ if (! screen) {
+ return;
+ }
+ if (fake_fb) {
+ free(fake_fb);
+ }
+ fake_fb = (char *) calloc(w*h*bpp/8, 1);
+ if (! fake_fb) {
+ rfbLog("could not create fake fb: %dx%d %d\n", w, h, bpp);
+ return;
+ }
+ bpc = guess_bits_per_color(bpp);
+ rfbLog("installing fake fb: %dx%d %d\n", w, h, bpp);
+ rfbLog("rfbNewFramebuffer(0x%x, 0x%x, %d, %d, %d, %d, %d)\n",
+ screen, fake_fb, w, h, bpc, 1, bpp/8);
+
+ rfbNewFramebuffer(screen, fake_fb, w, h, bpc, 1, bpp/8);
+}
+
+void check_padded_fb(void) {
+ if (! fake_fb) {
+ return;
+ }
+ if (time(0) > pad_geometry_time+1 && all_clients_initialized()) {
+ remove_fake_fb();
+ }
+}
+
+void install_padded_fb(char *geom) {
+ int w, h;
+ int ok = 1;
+ if (! geom || *geom == '\0') {
+ ok = 0;
+ } else if (sscanf(geom, "%dx%d", &w, &h) != 2) {
+ ok = 0;
+ }
+ w = nabs(w);
+ h = nabs(h);
+
+ if (w < 5) w = 5;
+ if (h < 5) h = 5;
+
+ if (!ok) {
+ rfbLog("skipping invalid pad geometry: '%s'\n", NONUL(geom));
+ return;
+ }
+ install_fake_fb(w, h, bpp);
+ pad_geometry_time = time(0);
+}
+
/*
- * initialize the rfb framebuffer/screen
+ * initialize a fb for the X display
*/
-void initialize_screen(int *argc, char **argv, XImage *fb) {
- int have_masks = 0;
- int width = fb->width;
- int height = fb->height;
+XImage *initialize_xdisplay_fb(void) {
+ XImage *fb;
+ char *vis_str = visual_str;
+ int try = 0, subwin_tries = 3;
+ XErrorHandler old_handler;
+ int subwin_bs;
+
+ X_LOCK;
+ if (subwin && !valid_window((Window) subwin)) {
+ rfbLog("invalid sub-window: 0x%lx\n", subwin);
+ X_UNLOCK;
+ clean_up_exit(1);
+ }
- main_bytes_per_line = fb->bytes_per_line;
+ if (overlay) {
+ /*
+ * ideally we'd like to not have to cook up the
+ * visual variables but rather let it all come out
+ * of XReadScreen(), however there is no way to get
+ * a default visual out of it, so we pretend -visual
+ * TrueColor:NN was supplied with NN usually 24.
+ */
+ char str[32];
+ Window twin = subwin ? subwin : rootwin;
+ XImage *xi;
+
+ xi = xreadscreen(dpy, twin, 0, 0, 8, 8, False);
+ sprintf(str, "TrueColor:%d", xi->depth);
+ if (xi->depth != 24 && ! quiet) {
+ rfbLog("warning: overlay image has depth %d "
+ "instead of 24.\n", xi->depth);
+ }
+ XDestroyImage(xi);
+ if (visual_str != NULL && ! quiet) {
+ rfbLog("warning: replacing '-visual %s' by '%s' "
+ "for use with -overlay\n", visual_str, str);
+ }
+ vis_str = strdup(str);
+ }
+
+ if (vis_str != NULL) {
+ set_visual(vis_str);
+ if (vis_str != visual_str) {
+ free(vis_str);
+ }
+ }
+
+ /* set up parameters for subwin or non-subwin cases: */
+
+ if (! subwin) {
+ /* full screen */
+ window = rootwin;
+ dpy_x = DisplayWidth(dpy, scr);
+ dpy_y = DisplayHeight(dpy, scr);
+ off_x = 0;
+ off_y = 0;
+ /* this may be overridden via visual_id below */
+ default_visual = DefaultVisual(dpy, scr);
+ } else {
+ /* single window */
+ XWindowAttributes attr;
+
+ window = (Window) subwin;
+ if (! XGetWindowAttributes(dpy, window, &attr)) {
+ rfbLog("invalid window: 0x%lx\n", window);
+ X_UNLOCK;
+ clean_up_exit(1);
+ }
+ dpy_x = attr.width;
+ dpy_y = attr.height;
+
+ subwin_bs = attr.backing_store;
+
+ /* this may be overridden via visual_id below */
+ default_visual = attr.visual;
+
+ X_UNLOCK;
+ set_offset();
+ X_LOCK;
+ }
+
+ /* initialize depth to reasonable value, visual_id may override */
+ depth = DefaultDepth(dpy, scr);
+
+ if (visual_id) {
+ int n;
+ XVisualInfo vinfo_tmpl, *vinfo;
+
+ /*
+ * we are in here from -visual or -overlay options
+ * visual_id and visual_depth were set in set_visual().
+ */
+
+ vinfo_tmpl.visualid = visual_id;
+ vinfo = XGetVisualInfo(dpy, VisualIDMask, &vinfo_tmpl, &n);
+ if (vinfo == NULL || n == 0) {
+ rfbLog("could not match visual_id: 0x%x\n",
+ (int) visual_id);
+ X_UNLOCK;
+ clean_up_exit(1);
+ }
+ default_visual = vinfo->visual;
+ depth = vinfo->depth;
+ if (visual_depth) {
+ /* force it from -visual MooColor:NN */
+ depth = visual_depth;
+ }
+ if (! quiet) {
+ fprintf(stderr, " initialize_xdisplay_fb()\n");
+ fprintf(stderr, " Visual*: 0x%x\n",
+ (int) vinfo->visual);
+ fprintf(stderr, " visualid: 0x%x\n",
+ (int) vinfo->visualid);
+ fprintf(stderr, " screen: %d\n", vinfo->screen);
+ fprintf(stderr, " depth: %d\n", vinfo->depth);
+ fprintf(stderr, " class: %d\n", vinfo->class);
+ fprintf(stderr, " red_mask: 0x%08lx %s\n",
+ vinfo->red_mask, bitprint(vinfo->red_mask, 32));
+ fprintf(stderr, " green_mask: 0x%08lx %s\n",
+ vinfo->green_mask, bitprint(vinfo->green_mask, 32));
+ fprintf(stderr, " blue_mask: 0x%08lx %s\n",
+ vinfo->blue_mask, bitprint(vinfo->blue_mask, 32));
+ fprintf(stderr, " cmap_size: %d\n",
+ vinfo->colormap_size);
+ fprintf(stderr, " bits b/rgb: %d\n",
+ vinfo->bits_per_rgb);
+ fprintf(stderr, "\n");
+ }
+ XFree(vinfo);
+ }
+
+ if (! quiet) {
+ rfbLog("default visual ID: 0x%x\n",
+ (int) XVisualIDFromVisual(default_visual));
+ }
+
+ again:
+ if (subwin) {
+ int shift = 0;
+ int subwin_x, subwin_y;
+ int disp_x = DisplayWidth(dpy, scr);
+ int disp_y = DisplayHeight(dpy, scr);
+ Window twin;
+ /* subwins can be a dicey if they are changing size... */
+ XTranslateCoordinates(dpy, window, rootwin, 0, 0, &subwin_x,
+ &subwin_y, &twin);
+ if (subwin_x + dpy_x > disp_x) {
+ shift = 1;
+ subwin_x = disp_x - dpy_x - 3;
+ }
+ if (subwin_y + dpy_y > disp_y) {
+ shift = 1;
+ subwin_y = disp_y - dpy_y - 3;
+ }
+ if (subwin_x < 0) {
+ shift = 1;
+ subwin_x = 1;
+ }
+ if (subwin_y < 0) {
+ shift = 1;
+ subwin_y = 1;
+ }
+
+ trapped_xerror = 0;
+ old_handler = XSetErrorHandler(trap_xerror);
+ if (shift) {
+ XMoveWindow(dpy, window, subwin_x, subwin_y);
+ }
+ XMapRaised(dpy, window);
+ XRaiseWindow(dpy, window);
+ XFlush(dpy);
+ }
+ try++;
+
+ if (nofb) {
+ /*
+ * For -nofb we do not allocate the framebuffer, so we
+ * can save a few MB of memory.
+ */
+ fb = XCreateImage_wr(dpy, default_visual, depth, ZPixmap,
+ 0, NULL, dpy_x, dpy_y, BitmapPad(dpy), 0);
+
+ } else if (visual_id) {
+ /*
+ * we need to call XCreateImage to supply the visual
+ */
+ fb = XCreateImage_wr(dpy, default_visual, depth, ZPixmap,
+ 0, NULL, dpy_x, dpy_y, BitmapPad(dpy), 0);
+ fb->data = (char *) malloc(fb->bytes_per_line * fb->height);
- main_red_mask = fb->red_mask;
- main_green_mask = fb->green_mask;
- main_blue_mask = fb->blue_mask;
+ } else {
+ fb = XGetImage_wr(dpy, window, 0, 0, dpy_x, dpy_y, AllPlanes,
+ ZPixmap);
+ if (! quiet) {
+ rfbLog("Read initial data from X display into"
+ " framebuffer.\n");
+ }
+ }
+
+ if (subwin) {
+ XSetErrorHandler(old_handler);
+ if (trapped_xerror) {
+ rfbLog("trapped GetImage at SUBWIN creation.\n");
+ if (try < subwin_tries) {
+ usleep(250 * 1000);
+ if (!get_window_size(window, &dpy_x, &dpy_y)) {
+ rfbLog("could not get size of subwin "
+ "0x%lx\n", subwin);
+ X_UNLOCK;
+ clean_up_exit(1);
+ }
+ goto again;
+ }
+ }
+ trapped_xerror = 0;
+
+ } else if (! fb && try == 1) {
+ /* try once more */
+ usleep(250 * 1000);
+ goto again;
+ }
+ X_UNLOCK;
+
+ if (fb->bits_per_pixel == 24 && ! quiet) {
+ rfbLog("warning: 24 bpp may have poor performance.\n");
+ }
+ return fb;
+}
+
+void parse_scale_string(char *str) {
+ int m, n;
+ char *p;
+ double f;
+
+ scale_fac = 1.0;
+ scaling = 0;
+ scaling_noblend = 0;
+ scaling_nomult4 = 0;
+ scaling_pad = 0;
+ scaling_interpolate = 0;
+ scaled_x = 0, scaled_y = 0;
+ scale_numer = 0, scale_denom = 0;
+
+ if (str == NULL || str[0] == '\0') {
+ return;
+ }
+
+ if ( (p = strchr(str, ':')) != NULL) {
+ /* options */
+ if (strstr(p+1, "nb") != NULL) {
+ scaling_noblend = 1;
+ }
+ if (strstr(p+1, "n4") != NULL) {
+ scaling_nomult4 = 1;
+ }
+ if (strstr(p+1, "in") != NULL) {
+ scaling_interpolate = 1;
+ }
+ if (strstr(p+1, "pad") != NULL) {
+ scaling_pad = 1;
+ }
+ *p = '\0';
+ }
+ if (strchr(str, '.') != NULL) {
+ double test, diff, eps = 1.0e-7;
+ if (sscanf(str, "%lf", &f) != 1) {
+ rfbLog("bad -scale arg: %s\n", str);
+ clean_up_exit(1);
+ }
+ scale_fac = (double) f;
+ /* look for common fractions from small ints: */
+ for (n=2; n<=10; n++) {
+ for (m=1; m<n; m++) {
+ test = ((double) m)/ n;
+ diff = scale_fac - test;
+ if (-eps < diff && diff < eps) {
+ scale_numer = m;
+ scale_denom = n;
+ break;
+
+ }
+ }
+ if (scale_denom) {
+ break;
+ }
+ }
+ if (scale_fac < 0.01) {
+ rfbLog("-scale factor too small: %f\n", scale_fac);
+ clean_up_exit(1);
+ }
+ } else {
+ if (sscanf(str, "%d/%d", &m, &n) != 2) {
+ if (sscanf(str, "%d", &m) != 1) {
+ rfbLog("bad -scale arg: %s\n", str);
+ clean_up_exit(1);
+ } else {
+ /* e.g. -scale 1 or -scale 2 */
+ n = 1;
+ }
+ }
+ if (n <= 0 || m <=0) {
+ rfbLog("bad -scale arg: %s\n", str);
+ clean_up_exit(1);
+ }
+ scale_fac = ((double) m)/ n;
+ if (scale_fac < 0.01) {
+ rfbLog("-scale factor too small: %f\n", scale_fac);
+ clean_up_exit(1);
+ }
+ scale_numer = m;
+ scale_denom = n;
+ }
+ if (scale_fac == 1.0) {
+ if (! quiet) {
+ rfbLog("scaling disabled for factor %f\n", scale_fac);
+ }
+ } else {
+ scaling = 1;
+ }
+}
+
+void setup_scaling(int *width_in, int *height_in) {
+ int width = *width_in;
+ int height = *height_in;
+
+ parse_scale_string(scale_str);
if (scaling) {
double eps = 0.000001;
@@ -5439,20 +9236,60 @@ void initialize_screen(int *argc, char **argv, XImage *fb) {
}
scaled_x = width;
scaled_y = height;
- rfb_bytes_per_line = (main_bytes_per_line / fb->width) * width;
+
+ *width_in = width;
+ *height_in = height;
+ }
+}
+
+/*
+ * initialize the rfb framebuffer/screen
+ */
+void initialize_screen(int *argc, char **argv, XImage *fb) {
+ int have_masks = 0;
+ int width = fb->width;
+ int height = fb->height;
+ int create_screen = screen ? 0 : 1;
+ int bits_per_color;
+
+ main_bytes_per_line = fb->bytes_per_line;
+
+ setup_scaling(&width, &height);
+
+ if (scaling) {
rfbLog("scaling screen: %dx%d -> %dx%d scale_fac=%.5f\n",
fb->width, fb->height, scaled_x, scaled_y, scale_fac);
+
+ rfb_bytes_per_line = (main_bytes_per_line / fb->width) * width;
} else {
rfb_bytes_per_line = main_bytes_per_line;
}
- screen = rfbGetScreen(argc, argv, width, height, fb->bits_per_pixel,
- 8, fb->bits_per_pixel/8);
+ /*
+ * These are just hints wrt pixel format just to let
+ * rfbGetScreen/rfbNewFramebuffer proceed with reasonable
+ * defaults. We manually set them in painful detail
+ * below.
+ */
+ bits_per_color = guess_bits_per_color(fb->bits_per_pixel);
- if (! quiet) {
- fprintf(stderr, "\n");
- }
+ /* n.b. samplesPerPixel (set = 1 here) seems to be unused. */
+ if (create_screen) {
+ screen = rfbGetScreen(argc, argv, width, height,
+ bits_per_color, 1, (int) fb->bits_per_pixel/8);
+ } else {
+ /* set set frameBuffer member below. */
+ rfbLog("rfbNewFramebuffer(0x%x, 0x%x, %d, %d, %d, %d, %d)\n",
+ screen, NULL, width, height,
+ bits_per_color, 1, fb->bits_per_pixel/8);
+ /* these are probably overwritten, but just to be safe: */
+ screen->bitsPerPixel = fb->bits_per_pixel;
+ screen->depth = fb->depth;
+
+ rfbNewFramebuffer(screen, NULL, width, height,
+ bits_per_color, 1, (int) fb->bits_per_pixel/8);
+ }
if (! screen) {
int i;
rfbLog("\n");
@@ -5468,11 +9305,11 @@ void initialize_screen(int *argc, char **argv, XImage *fb) {
* 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".
*/
-#if NON_CVS && defined(LIBVNCSERVER_VERSION)
+#if OLD_TREE && defined(LIBVNCSERVER_VERSION)
if (strcmp(LIBVNCSERVER_VERSION, "0.6"))
#endif
{
- if (*argc != 1) {
+ if (create_screen && *argc != 1) {
int i;
rfbLog("*** unrecognized option(s) ***\n");
for (i=1; i< *argc; i++) {
@@ -5491,23 +9328,45 @@ void initialize_screen(int *argc, char **argv, XImage *fb) {
rfbLog("renamed: -mouseX, use -cursor X\n");
rfbLog("renamed: -X, use -cursor X\n");
rfbLog("renamed: -nomouse, use -nocursor\n");
+ rfbLog("renamed: -old_pointer, use -pointer_mode 1\n");
clean_up_exit(1);
}
}
+ /* set up format from scratch: */
screen->paddedWidthInBytes = rfb_bytes_per_line;
screen->serverFormat.bitsPerPixel = fb->bits_per_pixel;
screen->serverFormat.depth = fb->depth;
- screen->serverFormat.trueColour = (uint8_t) TRUE;
+ screen->serverFormat.trueColour = TRUE;
+
+ screen->serverFormat.redShift = 0;
+ screen->serverFormat.greenShift = 0;
+ screen->serverFormat.blueShift = 0;
+ screen->serverFormat.redMax = 0;
+ screen->serverFormat.greenMax = 0;
+ screen->serverFormat.blueMax = 0;
+
+ /* these main_* formats are use elsewhere by us. */
+ main_red_shift = 0;
+ main_green_shift = 0;
+ main_blue_shift = 0;
+ main_red_max = 0;
+ main_green_max = 0;
+ main_blue_max = 0;
+ main_red_mask = fb->red_mask;
+ main_green_mask = fb->green_mask;
+ main_blue_mask = fb->blue_mask;
+
+
have_masks = ((fb->red_mask|fb->green_mask|fb->blue_mask) != 0);
if (force_indexed_color) {
have_masks = 0;
}
- if ( ! have_masks && screen->serverFormat.bitsPerPixel == 8
- && CellsOfScreen(ScreenOfDisplay(dpy,scr)) ) {
- /* indexed colour */
+ if (! have_masks && screen->serverFormat.bitsPerPixel == 8
+ && CellsOfScreen(ScreenOfDisplay(dpy, scr))) {
+ /* indexed color */
if (!quiet) {
rfbLog("X display %s is 8bpp indexed color\n",
DisplayString(dpy));
@@ -5522,53 +9381,115 @@ void initialize_screen(int *argc, char **argv, XImage *fb) {
rfbLog("\n");
}
}
- indexed_colour = 1;
- set_colormap();
+ screen->serverFormat.trueColour = FALSE;
+ indexed_color = 1;
+ set_colormap(1);
} else {
- /* general case ... */
+ /*
+ * general case, we call it truecolor, but could be direct
+ * color, static color, etc....
+ */
if (! quiet) {
rfbLog("X display %s is %dbpp depth=%d true "
"color\n", DisplayString(dpy), fb->bits_per_pixel,
fb->depth);
}
+ indexed_color = 0;
+
/* convert masks to bit shifts and max # colors */
- screen->serverFormat.redShift = 0;
- if ( fb->red_mask ) {
- while ( ! (fb->red_mask
- & (1 << screen->serverFormat.redShift) ) ) {
+ if (fb->red_mask) {
+ while (! (fb->red_mask
+ & (1 << screen->serverFormat.redShift))) {
screen->serverFormat.redShift++;
}
}
- screen->serverFormat.greenShift = 0;
- if ( fb->green_mask ) {
- while ( ! (fb->green_mask
- & (1 << screen->serverFormat.greenShift) ) ) {
+ if (fb->green_mask) {
+ while (! (fb->green_mask
+ & (1 << screen->serverFormat.greenShift))) {
screen->serverFormat.greenShift++;
}
}
- screen->serverFormat.blueShift = 0;
- if ( fb->blue_mask ) {
- while ( ! (fb->blue_mask
- & (1 << screen->serverFormat.blueShift) ) ) {
+ if (fb->blue_mask) {
+ while (! (fb->blue_mask
+ & (1 << screen->serverFormat.blueShift))) {
screen->serverFormat.blueShift++;
}
}
screen->serverFormat.redMax
- = fb->red_mask >> screen->serverFormat.redShift;
+ = fb->red_mask >> screen->serverFormat.redShift;
screen->serverFormat.greenMax
= fb->green_mask >> screen->serverFormat.greenShift;
screen->serverFormat.blueMax
- = fb->blue_mask >> screen->serverFormat.blueShift;
+ = fb->blue_mask >> screen->serverFormat.blueShift;
- main_red_max = screen->serverFormat.redMax;
- main_green_max = screen->serverFormat.greenMax;
- main_blue_max = screen->serverFormat.blueMax;
+ main_red_max = screen->serverFormat.redMax;
+ main_green_max = screen->serverFormat.greenMax;
+ main_blue_max = screen->serverFormat.blueMax;
main_red_shift = screen->serverFormat.redShift;
main_green_shift = screen->serverFormat.greenShift;
main_blue_shift = screen->serverFormat.blueShift;
}
+
+ if (!quiet) {
+ fprintf(stderr, "\n");
+ fprintf(stderr, "FrameBuffer Info:\n");
+ fprintf(stderr, " width: %d\n", fb->width);
+ fprintf(stderr, " height: %d\n", fb->height);
+ fprintf(stderr, " scaled_width: %d\n", width);
+ fprintf(stderr, " scaled_height: %d\n", height);
+ fprintf(stderr, " indexed_color: %d\n", indexed_color);
+ fprintf(stderr, " bits_per_pixel: %d\n", fb->bits_per_pixel);
+ fprintf(stderr, " depth: %d\n", fb->depth);
+ fprintf(stderr, " red_mask: 0x%08lx %s\n", fb->red_mask,
+ bitprint(fb->red_mask, 32));
+ fprintf(stderr, " green_mask: 0x%08lx %s\n", fb->green_mask,
+ bitprint(fb->green_mask, 32));
+ fprintf(stderr, " blue_mask: 0x%08lx %s\n", fb->blue_mask,
+ bitprint(fb->blue_mask, 32));
+ fprintf(stderr, " red: max: %3d shift: %2d\n",
+ main_red_max, main_red_shift);
+ fprintf(stderr, " green: max: %3d shift: %2d\n",
+ main_green_max, main_green_shift);
+ fprintf(stderr, " blue: max: %3d shift: %2d\n",
+ main_blue_max, main_blue_shift);
+ fprintf(stderr, " mainfb_bytes_per_line: %d\n",
+ main_bytes_per_line);
+ fprintf(stderr, " rfb_fb_bytes_per_line: %d\n",
+ rfb_bytes_per_line);
+ switch(fb->format) {
+ case XYBitmap:
+ fprintf(stderr, " format: XYBitmap\n"); break;
+ case XYPixmap:
+ fprintf(stderr, " format: XYPixmap\n"); break;
+ case ZPixmap:
+ fprintf(stderr, " format: ZPixmap\n"); break;
+ default:
+ fprintf(stderr, " format: %d\n", fb->format); break;
+ }
+ switch(fb->byte_order) {
+ case LSBFirst:
+ fprintf(stderr, " byte_order: LSBFirst\n"); break;
+ case MSBFirst:
+ fprintf(stderr, " byte_order: MSBFirst\n"); break;
+ default:
+ fprintf(stderr, " byte_order: %d\n", fb->byte_order);
+ break;
+ }
+ fprintf(stderr, " bitmap_pad: %d\n", fb->bitmap_pad);
+ fprintf(stderr, " bitmap_unit: %d\n", fb->bitmap_unit);
+ switch(fb->bitmap_bit_order) {
+ case LSBFirst:
+ fprintf(stderr, " bitmap_bit_order: LSBFirst\n"); break;
+ case MSBFirst:
+ fprintf(stderr, " bitmap_bit_order: MSBFirst\n"); break;
+ default:
+ fprintf(stderr, " bitmap_bit_order: %d\n",
+ fb->bitmap_bit_order); break;
+ }
+ fprintf(stderr, "\n");
+ }
if (overlay && ! quiet) {
rfbLog("\n");
rfbLog("Overlay mode enabled: If you experience color\n");
@@ -5595,6 +9516,50 @@ void initialize_screen(int *argc, char **argv, XImage *fb) {
}
screen->frameBuffer = rfb_fb;
+ bpp = screen->serverFormat.bitsPerPixel;
+ depth = screen->serverFormat.depth;
+
+ setup_cursors();
+ if (! show_cursor) {
+ screen->cursor = NULL;
+ } else {
+ /* just set it to the arrow for now. */
+ if (0 && !quiet) rfbLog("calling set_rfb_cursor...\n");
+ set_rfb_cursor(CURS_ARROW);
+ if (0 && !quiet) rfbLog(" done.\n");
+ }
+
+ if (scaling) {
+ mark_rect_as_modified(0, 0, dpy_x, dpy_y, 0);
+ }
+
+ if (! create_screen) {
+ rfbClientIteratorPtr iter;
+ rfbClientPtr cl;
+
+ /*
+ * since bits_per_color above may have been approximate,
+ * try to reset the individual translation tables...
+ * we do not seem to need this with rfbGetScreen()...
+ */
+ if (!quiet) rfbLog("calling setTranslateFunction()...\n");
+ iter = rfbGetClientIterator(screen);
+ while ((cl = rfbClientIteratorNext(iter)) != NULL) {
+ screen->setTranslateFunction(cl);
+ }
+ rfbReleaseClientIterator(iter);
+ if (!quiet) rfbLog(" done.\n");
+ do_copy_screen = 1;
+
+ /* done for framebuffer change case */
+ return;
+ }
+
+ /*
+ * the rest is screen server initialization, etc, only needed
+ * at screen creation time.
+ */
+
/* called from inetd, we need to treat stdio as our socket */
if (inetd) {
int fd = dup(0);
@@ -5635,23 +9600,8 @@ void initialize_screen(int *argc, char **argv, XImage *fb) {
screen->setXCutText = xcut_receive;
}
- setup_cursors();
- if (! show_cursor) {
- screen->cursor = NULL;
- } else {
- screen->cursor = cursors[0]->rfb;
- }
-
rfbInitServer(screen);
-
- bpp = screen->serverFormat.bitsPerPixel;
- depth = screen->serverFormat.depth;
-
- if (scaling) {
- mark_rect_as_modified(0, 0, dpy_x, dpy_y, 0);
- }
-
if (viewonly_passwd) {
/* append the view only passwd after the normal passwd */
char **passwds_new = malloc(3*sizeof(char**));
@@ -5688,9 +9638,11 @@ int blackouts = 0;
* 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) {
+void initialize_blackouts(char *list) {
char *p, *blist = strdup(list);
- int x, y, X, Y, h, w;
+ int x, y, X, Y, h, w, t;
+
+ blackouts = 0;
p = strtok(blist, ", \t");
while (p) {
@@ -5698,10 +9650,14 @@ void initialize_blackout (char *list) {
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) {
+ w = nabs(w);
x = dpy_x - x - w;
} else if (sscanf(p, "%dx%d+%d-%d", &w, &h, &x, &y) == 4) {
+ h = nabs(h);
y = dpy_y - y - h;
} else if (sscanf(p, "%dx%d-%d-%d", &w, &h, &x, &y) == 4) {
+ w = nabs(w);
+ h = nabs(h);
x = dpy_x - x - w;
y = dpy_y - y - h;
} else {
@@ -5711,10 +9667,23 @@ void initialize_blackout (char *list) {
p = strtok(NULL, ", \t");
continue;
}
+ w = nabs(w);
+ h = nabs(h);
+ x = nfix(x, dpy_x);
+ y = nfix(y, dpy_y);
X = x + w;
Y = y + h;
+ X = nfix(X, dpy_x);
+ Y = nfix(Y, dpy_y);
+ if (x > X) {
+ t = X; X = x; x = t;
+ }
+ if (y > Y) {
+ t = Y; Y = y; y = t;
+ }
if (x < 0 || x > dpy_x || y < 0 || y > dpy_y ||
- X < 0 || X > dpy_x || Y < 0 || Y > dpy_y) {
+ X < 0 || X > dpy_x || Y < 0 || Y > dpy_y ||
+ x == X || y == 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 {
@@ -5748,9 +9717,13 @@ void initialize_blackout (char *list) {
*/
void blackout_tiles(void) {
int tx, ty;
+ int debug_bo = 0;
if (! blackouts) {
return;
}
+ if (getenv("DEBUG_BLACKOUT") != NULL) {
+ debug_bo = 1;
+ }
/*
* to simplify things drop down to single copy mode, no vcr, etc...
@@ -5836,8 +9809,18 @@ void blackout_tiles(void) {
if (rect.x1 == x1 && rect.y1 == y1 &&
rect.x2 == x2 && rect.y2 == y2) {
tile_blackout[n].cover = 2;
+ if (debug_bo) {
+ fprintf(stderr, "full: %d=%d,%d"
+ " (%d-%d) (%d-%d)\n",
+ n, tx, ty, x1, x2, y1, y2);
+ }
} else {
tile_blackout[n].cover = 1;
+ if (debug_bo) {
+ fprintf(stderr, "part: %d=%d,%d"
+ " (%d-%d) (%d-%d)\n",
+ n, tx, ty, x1, x2, y1, y2);
+ }
}
if (++cnt >= BO_MAX) {
@@ -5852,6 +9835,10 @@ void blackout_tiles(void) {
sraRgnDestroy(tile_reg);
tile_blackout[n].count = cnt;
+ if (debug_bo && cnt > 1) {
+ rfbLog("warning: multiple region overlaps[%d] "
+ "for tile %d=%d,%d.\n", cnt, n, tx, ty);
+ }
}
}
}
@@ -5872,14 +9859,17 @@ void initialize_xinerama (void) {
if (! XineramaQueryExtension(dpy, &ev, &er)) {
rfbLog("Xinerama: disabling: display does not support it.\n");
xinerama = 0;
+ xinerama_present = 0;
return;
}
if (! XineramaIsActive(dpy)) {
/* n.b. change to XineramaActive(dpy, window) someday */
rfbLog("Xinerama: disabling: not active on display.\n");
xinerama = 0;
+ xinerama_present = 0;
return;
- }
+ }
+ xinerama_present = 1;
/* n.b. change to XineramaGetData() someday */
xineramas = XineramaQueryScreens(dpy, &n);
@@ -5946,13 +9936,51 @@ void initialize_xinerama (void) {
sprintf(tstr, "%dx%d+%d+%d,", w, h, x, y);
strcat(bstr, tstr);
}
- initialize_blackout(bstr);
+ initialize_blackouts(bstr);
free(bstr);
free(tstr);
#endif
}
+void initialize_blackouts_and_xinerama(void) {
+ if (blackout_string != NULL) {
+ initialize_blackouts(blackout_string);
+ }
+ if (xinerama) {
+ initialize_xinerama();
+ }
+ if (blackouts) {
+ blackout_tiles();
+ /* schedule a copy_screen(), now is too early. */
+ do_copy_screen = 1;
+ }
+}
+
+void push_sleep(n) {
+ int i;
+ for (i=0; i<n; i++) {
+ rfbPE(screen, -1);
+ if (i != n-1 && defer_update) {
+ usleep(defer_update * 1000);
+ }
+ }
+}
+
+/*
+ * try to forcefully push a black screen to all connected clients
+ */
+void push_black_screen(int n) {
+ zero_fb(0, 0, dpy_x, dpy_y);
+ mark_rect_as_modified(0, 0, dpy_x, dpy_y, 1);
+ push_sleep(n);
+}
+
+void refresh_screen(void) {
+ mark_rect_as_modified(0, 0, dpy_x, dpy_y, 1);
+ rfbPE(screen, -1);
+}
+
/*
* Fill the framebuffer with zero for the prescribed rectangle
*/
@@ -6038,6 +10066,37 @@ void initialize_tiles(void) {
hint_list = (hint_t *) malloc((size_t) (ntiles * sizeof(hint_t)));
}
+void free_tiles(void) {
+ if (tile_has_diff) {
+ free(tile_has_diff);
+ tile_has_diff = NULL;
+ }
+ if (tile_tried) {
+ free(tile_tried);
+ tile_tried = NULL;
+ }
+ if (tile_blackout) {
+ free(tile_blackout);
+ tile_blackout = NULL;
+ }
+ if (tile_region) {
+ free(tile_region);
+ tile_region = NULL;
+ }
+ if (tile_row) {
+ free(tile_row);
+ tile_row = NULL;
+ }
+ if (tile_row_shm) {
+ free(tile_row_shm);
+ tile_row_shm = NULL;
+ }
+ if (hint_list) {
+ free(hint_list);
+ hint_list = NULL;
+ }
+}
+
/*
* silly function to factor dpy_y until fullscreen shm is not bigger than max.
* should always work unless dpy_y is a large prime or something... under
@@ -6191,38 +10250,32 @@ static int shm_create(XShmSegmentInfo *shm, XImage **ximg_ptr, int w, int h,
}
void shm_delete(XShmSegmentInfo *shm) {
- if (! using_shm) {
- return;
- }
#ifdef LIBVNCSERVER_HAVE_XSHM
- if (shm->shmaddr != (char *) -1) {
+ if (shm != NULL && shm->shmaddr != (char *) -1) {
shmdt(shm->shmaddr);
}
- if (shm->shmid != -1) {
+ if (shm != NULL && shm->shmid != -1) {
shmctl(shm->shmid, IPC_RMID, 0);
}
#endif
}
void shm_clean(XShmSegmentInfo *shm, XImage *xim) {
- if (! using_shm) {
- return;
- }
-#ifdef LIBVNCSERVER_HAVE_XSHM
X_LOCK;
- if (shm->shmid != -1) {
+#ifdef LIBVNCSERVER_HAVE_XSHM
+ if (shm != NULL && shm->shmid != -1) {
XShmDetach_wr(dpy, shm);
}
+#endif
if (xim != NULL) {
XDestroyImage(xim);
}
X_UNLOCK;
shm_delete(shm);
-#endif
}
-void initialize_shm(void) {
+void initialize_polling_images(void) {
int i;
/* set all shm areas to "none" before trying to create any */
@@ -6243,6 +10296,13 @@ void initialize_shm(void) {
if (! shm_create(&scanline_shm, &scanline, dpy_x, 1, "scanline")) {
clean_up_exit(1);
}
+ if (0 && !quiet) {
+ if (using_shm) {
+ rfbLog("created \"scanline\" shm polling image.\n");
+ } else {
+ rfbLog("created \"scanline\" polling image.\n");
+ }
+ }
/*
* the fullscreen (e.g. 1280x1024/fs_factor) shared memory area image:
@@ -6261,6 +10321,13 @@ void initialize_shm(void) {
dpy_y/fs_factor, "fullscreen")) {
clean_up_exit(1);
}
+ if (0 && !quiet) {
+ if (using_shm) {
+ rfbLog("created \"scanline\" shm polling image.\n");
+ } else {
+ rfbLog("created \"scanline\" polling image.\n");
+ }
+ }
}
/*
@@ -6269,6 +10336,7 @@ void initialize_shm(void) {
* and 40 for 1280x1024, etc.
*/
+ tile_shm_count = 0;
for (i=1; i<=ntiles_x; i++) {
if (! shm_create(&tile_row_shm[i], &tile_row[i], tile_x * i,
tile_y, "tile_row")) {
@@ -6284,14 +10352,23 @@ void initialize_shm(void) {
rfbLog("shm: shared memory usage, or run ipcrm(1)"
" to manually\n");
rfbLog("shm: delete unattached shm segments.\n");
- /* n.b.: "i" not "1", a kludge for cleanup */
- single_copytile = i;
+ single_copytile_count = i;
}
+ tile_shm_count++;
if (single_copytile && i >= 1) {
/* only need 1x1 tiles */
break;
}
}
+ if (!quiet) {
+ if (using_shm) {
+ rfbLog("created %d tile_row shm polling images.\n",
+ tile_shm_count);
+ } else {
+ rfbLog("created %d tile_row polling images.\n",
+ tile_shm_count);
+ }
+ }
}
/*
@@ -6895,6 +10972,23 @@ 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 (damage_time != 0) {
+ int debug = 0;
+ if (time(0) > damage_time + damage_delay) {
+ if (! quiet) {
+ rfbLog("damaging turned off.\n");
+ }
+ damage_time = 0;
+ damage_delay = 0;
+ } else {
+ if (debug) {
+ rfbLog("damaging viewer fb by not marking "
+ "rect: %d,%d,%d,%d\n", x1, y1, x2, y2);
+ }
+ return;
+ }
+ }
+
if (rfb_fb == main_fb || force) {
rfbMarkRectAsModified(screen, x1, y1, x2, y2);
} else if (scaling) {
@@ -6926,7 +11020,7 @@ void mark_hint(hint_t hint) {
static int *first_line = NULL, *last_line;
static unsigned short *left_diff, *right_diff;
-static void copy_tiles(int tx, int ty, int nt) {
+static int copy_tiles(int tx, int ty, int nt) {
int x, y, line;
int size_x, size_y, width1, width2;
int off, len, n, dw, dx, t;
@@ -6975,12 +11069,13 @@ static void copy_tiles(int tx, int ty, int nt) {
* n.b. we are int single copy_tile mode: nt=1
*/
tile_has_diff[n] = 0;
- return;
+ return(0);
}
X_LOCK;
+ XRANDR_SET_TRAP_RET(-1, "copy_tile-set");
/* read in the whole tile run at once: */
- if ( using_shm && size_x == tile_x * nt && size_y == tile_y ) {
+ if (using_shm && size_x == tile_x * nt && size_y == tile_y) {
/* general case: */
XShmGetImage_wr(dpy, window, tile_row[nt], x, y, AllPlanes);
} else {
@@ -6991,6 +11086,7 @@ static void copy_tiles(int tx, int ty, int nt) {
XGetSubImage_wr(dpy, window, x, y, size_x, size_y, AllPlanes,
ZPixmap, tile_row[nt], 0, 0);
}
+ XRANDR_CHK_TRAP_RET(-1, "copy_tile-chk");
X_UNLOCK;
if (blackouts && tile_blackout[n].cover == 1) {
@@ -7074,7 +11170,7 @@ static void copy_tiles(int tx, int ty, int nt) {
for (t=1; t <= nt; t++) {
tile_has_diff[n+(t-1)] = 0;
}
- return;
+ return(0);
} else {
/*
* at least one tile has a difference. make sure info
@@ -7224,6 +11320,7 @@ static void copy_tiles(int tx, int ty, int nt) {
tile_region[n+s].right_diff = right_diff[t];
}
+ return(1);
}
/*
@@ -7241,14 +11338,15 @@ static void copy_tiles(int tx, int ty, int nt) {
*/
static int copy_all_tiles(void) {
int x, y, n, m;
- int diffs = 0;
+ int diffs = 0, ct;
for (y=0; y < ntiles_y; y++) {
for (x=0; x < ntiles_x; x++) {
n = x + y * ntiles_x;
if (tile_has_diff[n]) {
- copy_tiles(x, y, 1);
+ ct = copy_tiles(x, y, 1);
+ if (ct < 0) return ct; /* fatal */
}
if (! tile_has_diff[n]) {
/*
@@ -7284,7 +11382,7 @@ static int copy_all_tiles(void) {
*/
static int copy_all_tile_runs(void) {
int x, y, n, m, i;
- int diffs = 0;
+ int diffs = 0, ct;
int in_run = 0, run = 0;
int ntave = 0, ntcnt = 0;
@@ -7301,7 +11399,8 @@ static int copy_all_tile_runs(void) {
run = 0;
continue;
}
- copy_tiles(x - run, y, run);
+ ct = copy_tiles(x - run, y, run);
+ if (ct < 0) return ct; /* fatal */
ntcnt++;
ntave += run;
@@ -7351,7 +11450,7 @@ static int copy_all_tile_runs(void) {
*/
static int copy_tiles_backward_pass(void) {
int x, y, n, m;
- int diffs = 0;
+ int diffs = 0, ct;
for (y = ntiles_y - 1; y >= 0; y--) {
for (x = ntiles_x - 1; x >= 0; x--) {
@@ -7366,7 +11465,8 @@ static int copy_tiles_backward_pass(void) {
if (y >= 1 && ! tile_has_diff[m] && tile_region[n].top_diff) {
if (! tile_tried[m]) {
tile_has_diff[m] = 2;
- copy_tiles(x, y-1, 1);
+ ct = copy_tiles(x, y-1, 1);
+ if (ct < 0) return ct; /* fatal */
}
}
@@ -7375,7 +11475,8 @@ static int copy_tiles_backward_pass(void) {
if (x >= 1 && ! tile_has_diff[m] && tile_region[n].left_diff) {
if (! tile_tried[m]) {
tile_has_diff[m] = 2;
- copy_tiles(x-1, y, 1);
+ ct = copy_tiles(x-1, y, 1);
+ if (ct < 0) return ct; /* fatal */
}
}
}
@@ -7388,8 +11489,8 @@ static int copy_tiles_backward_pass(void) {
return diffs;
}
-static void gap_try(int x, int y, int *run, int *saw, int along_x) {
- int n, m, i, xt, yt;
+static int gap_try(int x, int y, int *run, int *saw, int along_x) {
+ int n, m, i, xt, yt, ct;
n = x + y * ntiles_x;
@@ -7397,12 +11498,12 @@ static void gap_try(int x, int y, int *run, int *saw, int along_x) {
if (*saw) {
(*run)++; /* extend the gap run. */
}
- return;
+ return 0;
}
if (! *saw || *run == 0 || *run > gaps_fill) {
*run = 0; /* unacceptable run. */
*saw = 1;
- return;
+ return 0;
}
for (i=1; i <= *run; i++) { /* iterate thru the run. */
@@ -7419,10 +11520,12 @@ static void gap_try(int x, int y, int *run, int *saw, int along_x) {
continue;
}
- copy_tiles(xt, yt, 1);
+ ct = copy_tiles(xt, yt, 1);
+ if (ct < 0) return ct; /* fatal */
}
*run = 0;
*saw = 1;
+ return 1;
}
/*
@@ -7435,14 +11538,15 @@ static void gap_try(int x, int y, int *run, int *saw, int along_x) {
*/
static int fill_tile_gaps(void) {
int x, y, run, saw;
- int n, diffs = 0;
+ int n, diffs = 0, ct;
/* horizontal: */
for (y=0; y < ntiles_y; y++) {
run = 0;
saw = 0;
for (x=0; x < ntiles_x; x++) {
- gap_try(x, y, &run, &saw, 1);
+ ct = gap_try(x, y, &run, &saw, 1);
+ if (ct < 0) return ct; /* fatal */
}
}
@@ -7451,7 +11555,8 @@ static int fill_tile_gaps(void) {
run = 0;
saw = 0;
for (y=0; y < ntiles_y; y++) {
- gap_try(x, y, &run, &saw, 0);
+ ct = gap_try(x, y, &run, &saw, 0);
+ if (ct < 0) return ct; /* fatal */
}
}
@@ -7463,8 +11568,8 @@ static int fill_tile_gaps(void) {
return diffs;
}
-static void island_try(int x, int y, int u, int v, int *run) {
- int n, m;
+static int island_try(int x, int y, int u, int v, int *run) {
+ int n, m, ct;
n = x + y * ntiles_x;
m = u + v * ntiles_x;
@@ -7479,13 +11584,15 @@ static void island_try(int x, int y, int u, int v, int *run) {
/* found a discontinuity */
if (tile_tried[m]) {
- return;
+ return 0;
} else if (*run < grow_fill) {
- return;
+ return 0;
}
- copy_tiles(u, v, 1);
+ ct = copy_tiles(u, v, 1);
+ if (ct < 0) return ct; /* fatal */
}
+ return 1;
}
/*
@@ -7495,7 +11602,7 @@ static void island_try(int x, int y, int u, int v, int *run) {
*/
static int grow_islands(void) {
int x, y, n, run;
- int diffs = 0;
+ int diffs = 0, ct;
/*
* n.b. the way we scan here should keep an extension going,
@@ -7506,14 +11613,16 @@ static int grow_islands(void) {
for (y=0; y < ntiles_y; y++) {
run = 0;
for (x=0; x <= ntiles_x - 2; x++) {
- island_try(x, y, x+1, y, &run);
+ ct = island_try(x, y, x+1, y, &run);
+ if (ct < 0) return ct; /* fatal */
}
}
/* right to left: */
for (y=0; y < ntiles_y; y++) {
run = 0;
for (x = ntiles_x - 1; x >= 1; x--) {
- island_try(x, y, x-1, y, &run);
+ ct = island_try(x, y, x-1, y, &run);
+ if (ct < 0) return ct; /* fatal */
}
}
for (n=0; n < ntiles; n++) {
@@ -7540,11 +11649,15 @@ static void blackout_regions(void) {
* the info from the X server. Bandwidth to client and compression time
* are other issues... use -fs 1.0 to disable.
*/
-void copy_screen(void) {
+int copy_screen(void) {
int pixelsize = bpp >> 3;
char *fbp;
int i, y, block_size;
+ if (! fs_factor) {
+ return 0;
+ }
+
block_size = (dpy_x * (dpy_y/fs_factor) * pixelsize);
fbp = main_fb;
@@ -7554,6 +11667,7 @@ void copy_screen(void) {
/* screen may be too big for 1 shm area, so broken into fs_factor */
for (i=0; i < fs_factor; i++) {
+ XRANDR_SET_TRAP_RET(-1, "copy_screen-set");
if (using_shm) {
XShmGetImage_wr(dpy, window, fullscreen, 0, y,
AllPlanes);
@@ -7562,6 +11676,7 @@ void copy_screen(void) {
fullscreen->height, AllPlanes, ZPixmap, fullscreen,
0, 0);
}
+ XRANDR_CHK_TRAP_RET(-1, "copy_screen-chk");
memcpy(fbp, fullscreen->data, (size_t) block_size);
y += dpy_y / fs_factor;
@@ -7575,6 +11690,7 @@ void copy_screen(void) {
}
mark_rect_as_modified(0, 0, dpy_x, dpy_y, 0);
+ return 0;
}
@@ -7818,6 +11934,7 @@ static int scan_display(int ystart, int rescan) {
/* grab the horizontal scanline from the display: */
X_LOCK;
+ XRANDR_SET_TRAP_RET(-1, "scan_display-set");
if (using_shm) {
XShmGetImage_wr(dpy, window, scanline, 0, y, AllPlanes);
} else {
@@ -7825,6 +11942,7 @@ static int scan_display(int ystart, int rescan) {
scanline->height, AllPlanes, ZPixmap, scanline,
0, 0);
}
+ XRANDR_CHK_TRAP_RET(-1, "scan_display-chk");
X_UNLOCK;
/* for better memory i/o try the whole line at once */
@@ -7921,14 +12039,22 @@ int scan_for_updates(void) {
if (subwin) {
set_offset(); /* follow the subwindow */
}
- if (indexed_colour) { /* check for changed colormap */
- set_colormap();
+ if (indexed_color) { /* check for changed colormap */
+ set_colormap(0);
}
}
+#define SCAN_FATAL(x) \
+ if (x < 0) { \
+ scan_in_progress = 0; \
+ fb_copy_in_progress = 0; \
+ return 0; \
+ }
+
/* scan with the initial y to the jitter value from scanlines: */
scan_in_progress = 1;
tile_count = scan_display(scanlines[scan_count], 0);
+ SCAN_FATAL(tile_count);
nap_set(tile_count);
@@ -7951,11 +12077,13 @@ int scan_for_updates(void) {
cp = (NSCAN - scan_count) % NSCAN;
tile_count = scan_display(scanlines[cp], 1);
+ SCAN_FATAL(tile_count);
if (tile_count >= (1 + frac2) * tile_count_old) {
/* on a roll... do a 3rd scan */
cp = (NSCAN - scan_count + 7) % NSCAN;
tile_count = scan_display(scanlines[cp], 1);
+ SCAN_FATAL(tile_count);
}
}
scan_in_progress = 0;
@@ -7975,10 +12103,12 @@ int scan_for_updates(void) {
* Use -fs 1.0 to disable on slow links.
*/
if (fs_factor && tile_count > fs_frac * ntiles) {
+ int cs;
fb_copy_in_progress = 1;
- copy_screen();
+ cs = copy_screen();
fb_copy_in_progress = 0;
- if (use_threads && old_pointer != 1) {
+ SCAN_FATAL(cs);
+ if (use_threads && pointer_mode != 1) {
pointer(-1, 0, 0, NULL);
}
nap_check(tile_count);
@@ -7990,7 +12120,7 @@ int scan_for_updates(void) {
/* copy all tiles with differences from display to rfb framebuffer: */
fb_copy_in_progress = 1;
- if (single_copytile) {
+ if (single_copytile || tile_shm_count < ntiles_x) {
/*
* Old way, copy I/O one tile at a time.
*/
@@ -8003,25 +12133,29 @@ int scan_for_updates(void) {
*/
tile_diffs = copy_all_tile_runs();
}
+ SCAN_FATAL(tile_diffs);
/*
* This backward pass for upward and left tiles complements what
* was done in copy_all_tiles() for downward and right tiles.
*/
tile_diffs = copy_tiles_backward_pass();
+ SCAN_FATAL(tile_diffs);
/* Given enough tile diffs, try the islands: */
if (grow_fill && tile_diffs > 4) {
tile_diffs = grow_islands();
}
+ SCAN_FATAL(tile_diffs);
/* Given enough tile diffs, try the gaps: */
if (gaps_fill && tile_diffs > 4) {
tile_diffs = fill_tile_gaps();
}
+ SCAN_FATAL(tile_diffs);
fb_copy_in_progress = 0;
- if (use_threads && old_pointer != 1) {
+ if (use_threads && pointer_mode != 1) {
/*
* tell the pointer handler it can process any queued
* pointer events:
@@ -8054,6 +12188,220 @@ int scan_for_updates(void) {
return tile_diffs;
}
+/* -- gui.c -- */
+#if OLD_TREE
+char gui_code[] = "";
+#else
+#include "tkx11vnc.h"
+#endif
+
+void run_gui(char *gui_xdisplay, int connect_to_x11vnc) {
+ char *x11vnc_xdisplay = NULL;
+ char extra_path[] = ":/usr/local/bin:/usr/sfw/bin:/usr/X11R6/bin";
+ char cmd[100];
+ char *wish, *orig_path, *full_path, *tpath, *p;
+ int try_max = 9, sleep = 300;
+ FILE *pipe;
+
+
+ if (getenv("DISPLAY") != NULL) {
+ x11vnc_xdisplay = strdup(getenv("DISPLAY"));
+ }
+ if (use_dpy) {
+ x11vnc_xdisplay = strdup(use_dpy);
+ }
+ if (connect_to_x11vnc) {
+ int rc, i;
+ if (! client_connect_file) {
+ dpy = XOpenDisplay(x11vnc_xdisplay);
+ if (! dpy) {
+ fprintf(stderr, "could not open display: %s\n",
+ x11vnc_xdisplay);
+ exit(1);
+ }
+ scr = DefaultScreen(dpy);
+ rootwin = RootWindow(dpy, scr);
+ initialize_vnc_connect_prop();
+ }
+ for (i=0; i<try_max; i++) {
+ usleep(sleep*1000);
+ fprintf(stderr, "pinging %s ...\n",
+ NONUL(x11vnc_xdisplay));
+ rc = send_remote_cmd("ping", 1);
+ if (rc == 0) {
+ break;
+ }
+ }
+ if (rc == 0) {
+ fprintf(stderr, "success.\n");
+ set_env("X11VNC_XDISPLAY", x11vnc_xdisplay);
+ set_env("X11VNC_CONNECT", "1");
+ } else {
+ fprintf(stderr, "could not connect to: '%s', try again"
+ " in the gui.\n", x11vnc_xdisplay);
+ }
+ }
+
+ orig_path = getenv("PATH");
+ if (! orig_path) {
+ orig_path = strdup("/bin:/usr/bin:/usr/bin/X11");
+ }
+ full_path = (char *) malloc(strlen(orig_path)+strlen(extra_path)+1);
+ strcpy(full_path, orig_path);
+ strcat(full_path, extra_path);
+
+ tpath = strdup(full_path);
+ p = strtok(tpath, ":");
+
+ while (p) {
+ char *try;
+ struct stat sbuf;
+ char *wishes[] = {"wish", "wish8.3", "wish8.4"};
+ int nwishes = 3, i;
+
+ try = (char *)malloc(strlen(p) + 10);
+ for (i=0; i<nwishes; i++) {
+ sprintf(try, "%s/%s", p, wishes[i]);
+ if (stat(try, &sbuf)) {
+ wish = wishes[i];
+ break;
+ }
+ }
+ free(try);
+ if (wish) {
+ break;
+ }
+ p = strtok(NULL, ":");
+ }
+ free(tpath);
+ if (!wish) {
+ wish = strdup("wish");
+ }
+ set_env("PATH", full_path);
+ set_env("DISPLAY", gui_xdisplay);
+ set_env("X11VNC_PROG", program_name);
+ set_env("X11VNC_CMDLINE", program_cmdline);
+
+if (0) system("env");
+ sprintf(cmd, "%s -", wish);
+ pipe = popen(cmd, "w");
+ if (! pipe) {
+ fprintf(stderr, "could not run: %s\n", cmd);
+ perror("popen");
+ }
+ fprintf(pipe, "%s", gui_code);
+ pclose(pipe);
+ exit(0);
+}
+
+void do_gui(char *opts) {
+ char *s, *p;
+ char *old_xauth = NULL;
+ char *gui_xdisplay = NULL;
+ int start_x11vnc = 1;
+ int connect_to_x11vnc = 0;
+ Display *test_dpy;
+
+ if (*gui_code == '\0') {
+ rfbLog("gui not available in this program.\n");
+ clean_up_exit(1);
+ }
+ if (opts) {
+ s = strdup(opts);
+ } else {
+ s = strdup("");
+ }
+
+ if (use_dpy) {
+ /* worst case */
+ gui_xdisplay = strdup(use_dpy);
+
+ }
+ if (getenv("DISPLAY") != NULL) {
+ /* better */
+ gui_xdisplay = strdup(getenv("DISPLAY"));
+ }
+
+ p = strtok(s, ",");
+
+ while(p) {
+ if (*p == '\0') {
+ ;
+ } else if (strchr(p, ':') != NULL) {
+ /* best */
+ gui_xdisplay = strdup(p);
+ } else if (!strcmp(p, "wait")) {
+ start_x11vnc = 0;
+ connect_to_x11vnc = 0;
+ } else if (!strcmp(p, "conn") || !strcmp(p, "connect")) {
+ start_x11vnc = 0;
+ connect_to_x11vnc = 1;
+ } else {
+ fprintf(stderr, "unrecognized gui opt: %s\n", p);
+ }
+
+ p = strtok(NULL, ",");
+ }
+ free(s);
+ if (start_x11vnc) {
+ connect_to_x11vnc = 1;
+ }
+
+ if (! gui_xdisplay) {
+ fprintf(stderr, "error: cannot determine X DISPLAY for gui"
+ " to display on.\n");
+ exit(1);
+ }
+ test_dpy = XOpenDisplay(gui_xdisplay);
+ if (! test_dpy && auth_file) {
+ if (getenv("XAUTHORITY") != NULL) {
+ old_xauth = strdup(getenv("XAUTHORITY"));
+ }
+ set_env("XAUTHORITY", auth_file);
+ test_dpy = XOpenDisplay(gui_xdisplay);
+ }
+ if (! test_dpy) {
+ if (! old_xauth && getenv("XAUTHORITY") != NULL) {
+ old_xauth = strdup(getenv("XAUTHORITY"));
+ }
+ set_env("XAUTHORITY", "");
+ test_dpy = XOpenDisplay(gui_xdisplay);
+ }
+ if (! test_dpy) {
+ fprintf(stderr, "error: cannot connect to gui X DISPLAY: %s\n",
+ gui_xdisplay);
+ }
+ XCloseDisplay(test_dpy);
+
+ if (start_x11vnc) {
+#if defined(LIBVNCSERVER_HAVE_FORK)
+ /* fork into the background now */
+ int p;
+ if ((p = fork()) > 0) {
+ ; /* parent */
+ } else if (p == -1) {
+ fprintf(stderr, "could not fork\n");
+ perror("fork");
+ clean_up_exit(1);
+ } else {
+ run_gui(gui_xdisplay, connect_to_x11vnc);
+ exit(1);
+ }
+#else
+ fprintf(stderr, "system does not support fork: start "
+ "x11vnc in the gui.\n");
+ start_x11vnc = 0;
+#endif
+ }
+ if (!start_x11vnc) {
+ run_gui(gui_xdisplay, connect_to_x11vnc);
+ exit(1);
+ }
+ if (old_xauth) {
+ set_env("XAUTHORITY", old_xauth);
+ }
+}
+
/* -- x11vnc.c -- */
/*
* main routine for the x11vnc program
@@ -8077,43 +12425,143 @@ static int defer_update_nofb = 6; /* defer a shorter time under -nofb */
*
* return of 1 means watch_loop should short-circuit and reloop,
* return of 0 means watch_loop should proceed to scan_for_updates().
- * (this is for old_pointer == 1 mode, the others do it all internally,
+ * (this is for pointer_mode == 1 mode, the others do it all internally,
* cnt is also only for that mode).
*/
-static int check_user_input_old(double dt, int *cnt);
-static int check_user_input(double dt, int tile_diffs, int *cnt) {
+static void check_user_input2(double dt) {
- if (old_pointer == 1) {
- /* every n-th drops thru to scan */
- if ((got_user_input || ui_skip < 0) && *cnt % ui_skip != 0) {
- *cnt++;
+
+ if (got_pointer_input) {
+ int eaten = 0, miss = 0, max_eat = 50;
+ int g, g_in;
+ double spin = 0.0, tm = 0.0;
+ double quick_spin_fac = 0.40;
+ double grind_spin_time = 0.175;
+
+ dtime(&tm);
+ g = g_in = got_pointer_input;
+
+ /*
+ * Try for some "quick" pointer input processing.
+ *
+ * About as fast as we can, we try to process user input
+ * calling rfbProcessEvents or rfbCheckFds. We do this
+ * for a time on order of the last scan_for_updates() time,
+ * dt, but if we stop getting user input we break out.
+ * We will also break out if we have processed max_eat
+ * inputs.
+ *
+ * Note that rfbCheckFds() does not send any framebuffer
+ * updates, so is more what we want here, although it is
+ * likely they have all be sent already.
+ */
+ while (1) {
+ if (show_multiple_cursors) {
+ rfbPE(screen, 1000);
+ } else {
+ rfbCFD(screen, 1000);
+ }
XFlush(dpy);
- return 1; /* short circuit watch_loop */
- } else {
- return 0;
+
+ spin += dtime(&tm);
+
+ if (spin > quick_spin_fac * dt) {
+ /* get out if spin time comparable to last scan time */
+ break;
+ }
+ if (got_pointer_input > g) {
+ g = got_pointer_input;
+ if (eaten++ < max_eat) {
+ continue;
+ }
+ } else {
+ miss++;
+ }
+ if (miss > 1) { /* 1 means out on 2nd miss */
+ break;
+ }
}
- } else if (old_pointer == 2) {
- /* this older way is similar to the method below */
- return check_user_input_old(dt, cnt);
- }
- if (got_keyboard_input) {
- if (*cnt % ui_skip != 0) {
- *cnt++;
- return 1; /* short circuit watch_loop */
+
+ /*
+ * Probably grinding with a lot of fb I/O if dt is
+ * this large. (need to do this more elegantly)
+ *
+ * Current idea is to spin our wheels here *not* processing
+ * any fb I/O, but still processing the user input.
+ * This user input goes to the X display and changes it,
+ * but we don't poll it while we "rest" here for a time
+ * on order of dt, the previous scan_for_updates() time.
+ * We also break out if we miss enough user input.
+ */
+ if (dt > grind_spin_time) {
+ int i, ms, split = 30;
+ double shim;
+
+ /*
+ * Break up our pause into 'split' steps.
+ * We get at most one input per step.
+ */
+ shim = 0.75 * dt / split;
+
+ ms = (int) (1000 * shim);
+
+ /* cutoff how long the pause can be */
+ if (split * ms > 300) {
+ ms = 300 / split;
+ }
+
+ spin = 0.0;
+ tm = 0.0;
+ dtime(&tm);
+
+ g = got_pointer_input;
+ miss = 0;
+ for (i=0; i<split; i++) {
+ usleep(ms * 1000);
+ if (show_multiple_cursors) {
+ rfbPE(screen, 1000);
+ } else {
+ rfbCFD(screen, 1000);
+ }
+ spin += dtime(&tm);
+ if (got_pointer_input > g) {
+ XFlush(dpy);
+ miss = 0;
+ } else {
+ miss++;
+ }
+ g = got_pointer_input;
+ if (miss > 2) {
+ break;
+ }
+ if (1000 * spin > ms * split) {
+ break;
+ }
+ }
}
- /* otherwise continue with pointer input */
}
+}
+
+static void check_user_input3(double dt, int tile_diffs) {
if (got_pointer_input) {
int spun_out, missed_out, allowed_misses, g, g_in;
double spin, spin_max, tm, to, dtm, rpe_last;
static int rfb_wait_ms = 2;
- static double grind_spin_time = 0.30, dt_min = 0.15;
+ static double grind_spin_time = 0.30, dt_min = 0.075;
static double quick_spin_fac = 0.65, spin_max_fac = 2.0;
static double rpe_wait = 0.15;
int grinding, gcnt, ms, split = 200;
+ static int first = 1;
+ if (first) {
+ char *p = getenv("SPIN");
+ if (p) {
+ sscanf(p, "%lf,%lf,%lf", &grind_spin_time, &dt_min, &quick_spin_fac);
+ }
+ first = 0;
+ }
/*
@@ -8150,6 +12598,7 @@ static int check_user_input(double dt, int tile_diffs, int *cnt) {
rpe_last = to = tm; /* last time we did rfbPE() */
g = g_in = got_pointer_input;
+
while (1) {
int got_input = 0;
@@ -8161,6 +12610,10 @@ static int check_user_input(double dt, int tile_diffs, int *cnt) {
usleep(ms * 1000);
}
+ if (button_mask) {
+ drag_in_progress = 1;
+ }
+
if (show_multiple_cursors && tm > rpe_last + rpe_wait) {
rfbPE(screen, rfb_wait_ms * 1000);
rpe_last = tm;
@@ -8195,6 +12648,7 @@ static int check_user_input(double dt, int tile_diffs, int *cnt) {
wms = 1000 * (0.5 * (spin_max - spin));
} else if (button_mask) {
wms = 10;
+ } else {
}
if (wms) {
usleep(wms * 1000);
@@ -8219,7 +12673,7 @@ static int check_user_input(double dt, int tile_diffs, int *cnt) {
/* reset for second pass */
spun_out = 0;
missed_out = 0;
- allowed_misses = 5;
+ allowed_misses = 3;
g = got_pointer_input;
gcnt = 0;
} else if (spun_out && grinding) {
@@ -8231,129 +12685,39 @@ static int check_user_input(double dt, int tile_diffs, int *cnt) {
}
}
}
- return 0;
+ drag_in_progress = 0;
}
-/* this is the -old_pointer2 way */
-static int check_user_input_old(double dt, int *cnt) {
+static void check_user_input4(double dt, int tile_diffs) {
+ return;
+}
- if (got_keyboard_input) {
- if (*cnt % ui_skip != 0) {
+static int check_user_input(double dt, int tile_diffs, int *cnt) {
+ if (pointer_mode == 1) {
+ if ((got_user_input || ui_skip < 0) && *cnt % ui_skip != 0) {
+ /* every ui_skip-th drops thru to scan */
*cnt++;
+ XFlush(dpy);
return 1; /* short circuit watch_loop */
+ } else {
+ return 0;
}
- /* otherwise continue with pointer input */
}
-
- if (got_pointer_input) {
- int eaten = 0, miss = 0, max_eat = 50;
- int g, g_in;
- double spin = 0.0, tm = 0.0;
- double quick_spin_fac = 0.40;
- double grind_spin_time = 0.175;
-
- dtime(&tm);
- g = g_in = got_pointer_input;
-
- /*
- * Try for some "quick" pointer input processing.
- *
- * About as fast as we can, we try to process user input
- * calling rfbProcessEvents or rfbCheckFds. We do this
- * for a time on order of the last scan_for_updates() time,
- * dt, but if we stop getting user input we break out.
- * We will also break out if we have processed max_eat
- * inputs.
- *
- * Note that rfbCheckFds() does not send any framebuffer
- * updates, so is more what we want here, although it is
- * likely they have all be sent already.
- */
- while (1) {
- if (show_multiple_cursors) {
- rfbPE(screen, 1000);
- } else {
- rfbCFD(screen, 1000);
- }
- XFlush(dpy);
-
- spin += dtime(&tm);
-
- if (spin > quick_spin_fac * dt) {
- /* get out if spin time comparable to last scan time */
- break;
- }
- if (got_pointer_input > g) {
- g = got_pointer_input;
- if (eaten++ < max_eat) {
- continue;
- }
- } else {
- miss++;
- }
- if (miss > 1) { /* 1 means out on 2nd miss */
- break;
- }
- }
-
-
- /*
- * Probably grinding with a lot of fb I/O if dt is
- * this large. (need to do this more elegantly)
- *
- * Current idea is to spin our wheels here *not* processing
- * any fb I/O, but still processing the user input.
- * This user input goes to the X display and changes it,
- * but we don't poll it while we "rest" here for a time
- * on order of dt, the previous scan_for_updates() time.
- * We also break out if we miss enough user input.
- */
- if (dt > grind_spin_time) {
- int i, ms, split = 30;
- double shim;
-
- /*
- * Break up our pause into 'split' steps.
- * We get at most one input per step.
- */
- shim = 0.75 * dt / split;
-
- ms = (int) (1000 * shim);
-
- /* cutoff how long the pause can be */
- if (split * ms > 300) {
- ms = 300 / split;
- }
-
- spin = 0.0;
- tm = 0.0;
- dtime(&tm);
-
- g = got_pointer_input;
- miss = 0;
- for (i=0; i<split; i++) {
- usleep(ms * 1000);
- if (show_multiple_cursors) {
- rfbPE(screen, 1000);
- } else {
- rfbCFD(screen, 1000);
- }
- spin += dtime(&tm);
- if (got_pointer_input > g) {
- XFlush(dpy);
- miss = 0;
- } else {
- miss++;
- }
- g = got_pointer_input;
- if (miss > 2) {
- break;
- }
- if (1000 * spin > ms * split) {
- break;
- }
+ if (pointer_mode >= 2 && pointer_mode <= 4) {
+ if (got_keyboard_input) {
+ if (*cnt % ui_skip != 0) {
+ *cnt++;
+ return 1; /* short circuit watch_loop */
}
}
+ /* otherwise continue with pointer input */
+ }
+ if (pointer_mode == 2) {
+ check_user_input2(dt);
+ } else if (pointer_mode == 3) {
+ check_user_input3(dt, tile_diffs);
+ } else if (pointer_mode == 4) {
+ check_user_input4(dt, tile_diffs);
}
return 0;
}
@@ -8418,7 +12782,7 @@ static void watch_loop(void) {
rfbPE(screen, -1);
if (! cursor_shape_updates) {
/* undo any cursor shape requests */
- unset_cursor_shape_updates(screen);
+ disable_cursor_shape_updates(screen);
}
if (check_user_input(dt, tile_diffs, &cnt)) {
/* true means loop back for more input */
@@ -8430,8 +12794,14 @@ static void watch_loop(void) {
clean_up_exit(0);
}
+ if (do_copy_screen) {
+ do_copy_screen = 0;
+ copy_screen();
+ }
+
check_xevents();
check_connect_inputs();
+ check_padded_fb();
if (! screen->clientHead) { /* waiting for a client */
usleep(200 * 1000);
@@ -8497,15 +12867,17 @@ static void print_help(void) {
"\n"
" vncviewer far-host:0\n"
"\n"
-"Once x11vnc establishes connections with the X11 server and starts\n"
-"listening as a VNC server it will print out a string: PORT=XXXX where\n"
-"XXXX is typically 5900 (the default VNC port). One would next run something\n"
-"like this on the local machine: \"vncviewer host:N\" where N is XXXX - 5900,\n"
-"i.e. usually \"vncviewer host:0\"\n"
+"Once x11vnc establishes connections with the X11 server and starts listening\n"
+"as a VNC server it will print out a string: PORT=XXXX where XXXX is typically\n"
+"5900 (the default VNC server port). One would next run something like\n"
+"this on the local machine: \"vncviewer hostname:N\" where \"hostname\" is\n"
+"the name of the machine running x11vnc and N is XXXX - 5900, i.e. usually\n"
+"\"vncviewer hostname:0\".\n"
"\n"
-"By default x11vnc will not allow the screen to be shared and it will\n"
-"exit as soon as a client disconnects. See -shared and -forever below\n"
-"to override these protections.\n"
+"By default x11vnc will not allow the screen to be shared and it will exit\n"
+"as soon as a client disconnects. See -shared and -forever below to override\n"
+"these protections. See the FAQ on how to tunnel the VNC connection through\n"
+"an encrypted channel such as ssh(1).\n"
"\n"
"For additional info see: http://www.karlrunge.com/x11vnc/\n"
" and http://www.karlrunge.com/x11vnc/#faq\n"
@@ -8532,36 +12904,54 @@ static void print_help(void) {
"\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"
+" transient toplevels, etc, may not be seen or may be\n"
+" clipped. Disabling SaveUnders or BackingStore in the\n"
+" X server may help show them. x11vnc may crash if the\n"
+" window is initially partially obscured, changes size,\n"
+" is iconified, etc. Some steps are taken to avoid this\n"
+" and the -xrandr mechanism is used to track resizes. Use\n"
+" xwininfo(1) to get the window id, or use \"-id pick\"\n"
+" to have x11vnc run xwininfo(1) for you and extract\n"
+" the id. The -id option is useful for exporting very\n"
+" simple applications (e.g. the current view on a webcam).\n"
"-sid windowid As -id, but instead of using the window directly it\n"
-" shifts a root view to it: this shows saveUnders menus,\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"
"-notruecolor For 8bpp displays, force indexed color (i.e. a colormap)\n"
" even if it looks like 8bpp TrueColor. (rare problem)\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... (e.g. messes\n"
+" up colors or cause a crash). It is useful for testing\n"
+" and for some workarounds. n may be a decimal number,\n"
+" or 0x hex. Run xdpyinfo(1) for the values. One may\n"
+" also use \"TrueColor\", etc. see <X11/X.h> for a list.\n"
+" If the string ends in \":m\" for better or for worse\n"
+" the visual depth is forced to be m.\n"
"-overlay Handle multiple depth visuals on one screen, e.g. 8+24\n"
" and 24+8 overlay visuals (the 32 bits per pixel are\n"
" packed with 8 for PseudoColor and 24 for TrueColor).\n"
"\n"
-" Currently -overlay only works on Solaris (it uses\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"
+" Currently -overlay only works on Solaris via\n"
+" XReadScreen(3X11) and IRIX using XReadDisplay(3).\n"
+" On Solaris there is a problem with image \"bleeding\"\n"
+" around transient popup menus (but not for the menu\n"
+" itself): a workaround is to disable SaveUnders\n"
+" by passing the \"-su\" argument to Xsun (in\n"
+" /etc/dt/config/Xservers). Also note that the mouse\n"
+" 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"
+" Some legacy applications require the default visual to\n"
" be 8bpp (8+24), or they will use 8bpp PseudoColor even\n"
" when the default visual is depth 24 TrueColor (24+8).\n"
" In these cases colors in some windows will be messed\n"
-" up in x11vnc unless -overlay is used.\n"
+" up in x11vnc unless -overlay is used. Another use of\n"
+" -overlay is to enable showing the exact mouse cursor\n"
+" shape (details below).\n"
"\n"
" Under -overlay, performance will be somewhat degraded\n"
" due to the extra image transformations required.\n"
@@ -8571,22 +12961,15 @@ static void print_help(void) {
" 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"
-" testing and for some workarounds. n may be a decimal\n"
-" number, or 0x hex. Run xdpyinfo(1) for the values.\n"
-" One may also use \"TrueColor\", etc. see <X11/X.h>\n"
-" 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\".\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"
+"-scale fraction Scale the framebuffer by factor \"fraction\". Values\n"
+" less than 1 shrink the fb, larger ones expand it.\n"
+" Note: image may not be sharp and response may be\n"
+" slower. Currently the cursor shape is not scaled.\n"
+" If \"fraction\" contains a decimal point \".\" it\n"
+" is taken as a floating point number, alternatively\n"
+" the notation \"m/n\" may be used to denote fractions\n"
+" exactly, e.g. -scale 2/3.\n"
"\n"
" Scaling Options: can be added after \"fraction\" via\n"
" \":\", to supply multiple \":\" options use commas.\n"
@@ -8605,6 +12988,10 @@ static void print_help(void) {
" disconnects, opposite of -forever. This is the Default.\n"
"-forever Keep listening for more connections rather than exiting\n"
" as soon as the first client(s) disconnect. Same as -many\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"
+" -q option, otherwise the stderr goes to the viewer.\n"
"-connect string For use with \"vncviewer -listen\" reverse connections.\n"
" If \"string\" has the form \"host\" or \"host:port\"\n"
" the connection is made once at startup. Use commas\n"
@@ -8616,21 +13003,17 @@ static void print_help(void) {
"-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"
-" -q option.\n"
+" work (see the FAQ). Default: %s\n"
"\n"
-"-allow addr1[,addr2..] Only allow client connections from IP addresses matching\n"
-" the comma separated list of numerical addresses.\n"
-" Can be a prefix, e.g. \"192.168.100.\" to match a\n"
-" simple subnet, for more control build libvncserver\n"
-" with libwrap support. If the list contains a \"/\"\n"
-" it instead is a interpreted as a file containing\n"
-" addresses or prefixes that is re-read each time a new\n"
-" client connects. Lines can be commented out with the\n"
-" \"#\" character in the usual way.\n"
+"-allow host1[,host2..] Only allow client connections from hosts matching\n"
+" the comma separated list of hostnames or IP addresses.\n"
+" Can also be a numerical IP prefix, e.g. \"192.168.100.\"\n"
+" to match a simple subnet, for more control build\n"
+" libvncserver with libwrap support (See the FAQ). If the\n"
+" list contains a \"/\" it instead is a interpreted as a\n"
+" file containing addresses or prefixes that is re-read\n"
+" each time a new client connects. Lines can be commented\n"
+" out with the \"#\" character in the usual way.\n"
"-localhost Same as -allow 127.0.0.1\n"
"-viewpasswd string Supply a 2nd password for view-only logins. The -passwd\n"
" (full-access) password must also be supplied.\n"
@@ -8639,7 +13022,7 @@ static void print_help(void) {
" If a second non blank line exists in the file it is\n"
" taken as a view-only password (i.e. -viewpasswd) Note:\n"
" this is a simple plaintext passwd, see also -rfbauth\n"
-" and -storepasswd below.\n"
+" and -storepasswd below for obfuscated passwords.\n"
"-storepasswd pass file Store password \"pass\" as the VNC password in the\n"
" file \"file\". Once the password is stored the\n"
" program exits. Use the password via \"-rfbauth file\"\n"
@@ -8648,10 +13031,10 @@ static void print_help(void) {
" should be allowed to connect or not. \"string\" is\n"
" an external command run via system(3) or some special\n"
" cases described below. Be sure to quote \"string\"\n"
-" if it contains spaces, etc. If the external command\n"
-" returns 0 the client is accepted, otherwise the client\n"
-" is rejected. See below for an extension to accept a\n"
-" client view-only.\n"
+" if it contains spaces, shell characters, etc. If the\n"
+" external command returns 0 the client is accepted,\n"
+" otherwise the client is rejected. See below for an\n"
+" extension to accept a client view-only.\n"
"\n"
" Environment: The RFB_CLIENT_IP environment variable will\n"
" be set to the incoming client IP number and the port\n"
@@ -8661,7 +13044,7 @@ static void print_help(void) {
" of the tcp virtual circuit. The x11vnc process\n"
" id will be in RFB_X11VNC_PID, a client id number in\n"
" RFB_CLIENT_ID, and the number of other connected clients\n"
-" in RFB_CLIENT_COUNT.\n"
+" in RFB_CLIENT_COUNT. RFB_MODE will be \"accept\"\n"
"\n"
" If \"string\" is \"popup\" then a builtin popup window\n"
" is used. The popup will time out after 120 seconds,\n"
@@ -8669,7 +13052,8 @@ static void print_help(void) {
" (use 0 for no timeout)\n"
"\n"
" If \"string\" is \"xmessage\" then an xmessage(1)\n"
-" invocation is used for the command.\n"
+" invocation is used for the command. xmessage must be\n"
+" installed on the machine for this to work.\n"
"\n"
" Both \"popup\" and \"xmessage\" will present an option\n"
" for accepting the client \"View-Only\" (the client\n"
@@ -8685,19 +13069,23 @@ static void print_help(void) {
" the default action (in case the command returns an\n"
" unexpected value). E.g. \"no:*\" is a good choice.\n"
"\n"
-" Note that x11vnc blocks while the external command or\n"
+" Note that x11vnc blocks while the external command\n"
" or popup is running (other clients may see no updates\n"
" during this period).\n"
"\n"
" More -accept tricks: use \"popupmouse\" to only allow\n"
" mouse clicks in the builtin popup to be recognized.\n"
-" Similarly use \"popupkey\" to only recognize keystroke\n"
-" responses. All 3 of the popup keywords can be followed\n"
+" Similarly use \"popupkey\" to only recognize\n"
+" keystroke responses. These are to help avoid the\n"
+" user accidentally accepting a client by typing or\n"
+" clicking. All 3 of the popup keywords can be followed\n"
" by +N+M to supply a position for the popup window.\n"
" The default is to center the popup window.\n"
"-gone string As -accept, except to run a user supplied command when\n"
-" a client goes away (disconnects). Unlike -accept,\n"
-" the command return code is not interpreted by x11vnc.\n"
+" a client goes away (disconnects). RFB_MODE will be\n"
+" set to \"gone\" and the other RFB_* variables are as\n"
+" in -accept. Unlike -accept, the command return code\n"
+" is not interpreted by x11vnc. Example: -gone 'xlock &'\n"
"\n"
"-noshm Do not use the MIT-SHM extension for the polling.\n"
" Remote displays can be polled this way: be careful this\n"
@@ -8720,8 +13108,44 @@ static void print_help(void) {
" In general on XINERAMA displays you may need to use the\n"
" -xwarppointer option if the mouse pointer misbehaves.\n"
"\n"
+"-xrandr [mode] If the display supports the XRANDR (X Resize, Rotate\n"
+" and Reflection) extension, and you expect XRANDR events\n"
+" to occur to the display while x11vnc is running, this\n"
+" options indicates x11vnc should try to respond to\n"
+" them (as opposed to simply crashing by assuming the\n"
+" old screen size). See the xrandr(1) manpage and run\n"
+" 'xrandr -q' for more info. [mode] is optional and\n"
+" described below.\n"
+"\n"
+" Since watching for XRANDR events and errors increases\n"
+" polling overhead, only use this option if XRANDR changes\n"
+" are expected. For example on a rotatable screen PDA or\n"
+" laptop, or using a XRANDR-aware Desktop where you resize\n"
+" often. It is best to be viewing with a vncviewer that\n"
+" supports the NewFBSize encoding, since it knows how to\n"
+" react to screen size changes. Otherwise, libvncserver\n"
+" tries to do so something reasonable for viewers that\n"
+" cannot do this (portions of the screen may be clipped,\n"
+" unused, etc).\n"
+"\n"
+" \"mode\" defaults to \"resize\", which means create a\n"
+" new, resized, framebuffer and hope all viewers can cope\n"
+" with the change. \"newfbsize\" means first disconnect\n"
+" all viewers that do not support the NewFBSize VNC\n"
+" encoding, and then resize the framebuffer. \"exit\"\n"
+" means disconnect all viewer clients, and then terminate\n"
+" x11vnc.\n"
+"-padgeom WxH Whenever a new vncviewer connects, the framebuffer is\n"
+" replaced with a fake, solid black one of geometry WxH.\n"
+" Shortly afterwards the framebuffer is replaced with the\n"
+" real one. This is intended for use with vncviewers\n"
+" that do not support NewFBSize and one wants to make\n"
+" sure the initial viewer geometry will be big enough\n"
+" to handle all subsequent resizes (e.g. under -xrandr,\n"
+" -remote id:windowid, rescaling, etc.\n"
+"\n"
"-o logfile Write stderr messages to file \"logfile\" instead of\n"
-" to the terminal. Same as -logfile \"file\".\n"
+" to the terminal. Same as \"-logfile file\".\n"
"-rc filename Use \"filename\" instead of $HOME/.x11vncrc for rc file.\n"
"-norc Do not process any .x11vncrc file for options.\n"
"-h, -help Print this help text.\n"
@@ -8749,16 +13173,18 @@ static void print_help(void) {
"-isolevel3 When in modtweak mode, always send ISO_Level3_Shift to\n"
" 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. 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"
-" keycodes. Use this option to help x11vnc in the reverse\n"
-" problem it tries to solve: Keysym -> Keycode(s) when\n"
-" ambiguities exist. E.g. -skip_keycodes 94,114\n"
+"-xkb When in modtweak mode, use the XKEYBOARD extension (if\n"
+" the X display supports it) to do the modifier tweaking.\n"
+" This is powerful and should be tried if there are still\n"
+" keymapping problems when using -modtweak by itself.\n"
+"-skip_keycodes string Ignore the comma separated list of decimal keycodes.\n"
+" Perhaps these are keycodes not on your keyboard but\n"
+" your X server thinks exist. Currently only applies\n"
+" to -xkb mode. Use this option to help x11vnc in the\n"
+" reverse problem it tries to solve: Keysym -> Keycode(s)\n"
+" when ambiguities exist (more than one Keycode per\n"
+" Keysym). Run 'xmodmap -pk' to see your keymapping.\n"
+" E.g. \"-skip_keycodes 94,114\"\n"
"-add_keysyms If a Keysym is received from a VNC viewer and\n"
" that Keysym does not exist in the X server, then\n"
" add the Keysym to the X server's keyboard mapping.\n"
@@ -8785,8 +13211,8 @@ static void print_help(void) {
" form: key1-key2,key3-key4,... See <X11/keysymdef.h>\n"
" header file for a list of Keysym names, or use\n"
" xev(1). To map a key to a button click, use the\n"
-" fake Keysyms \"Button1\", ..., etc.\n"
-" E.g. -remap Super_R-Button2\n"
+" fake Keysyms \"Button1\", ..., etc. E.g. \"-remap\n"
+" Super_R-Button2\" (useful for pasting on a laptop)\n"
"-norepeat Option -norepeat disables X server key auto repeat\n"
"-repeat when VNC clients are connected. This works around a\n"
" repeating keystrokes bug (triggered by long processing\n"
@@ -8819,26 +13245,35 @@ static void print_help(void) {
" 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"
+" below to disable). For other viewers the cursor shape\n"
+" is written directly to the framebuffer every time the\n"
+" pointer is moved or changed and gets sent along with\n"
+" the other framebuffer updates. In this case, there\n"
+" will be some lag between the vnc viewer pointer and\n"
+" the remote 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"
+" information from the X server, then the default is\n"
+" to use that mode. On Solaris this can be done with\n"
+" the SUN_OVL extension using -overlay (see also the\n"
+" -overlay_nomouse option). A similar overlay scheme\n"
+" is used on IRIX. Xorg (e.g. Linux) and recent Solaris\n"
+" Xsun servers support the XFIXES extension to retrieve\n"
+" the exact cursor shape from the X server. If XFIXES\n"
+" is present it is preferred over Overlay and is used by\n"
+" default (see -noxfixes below). This can be disabled\n"
+" with -nocursor, and also some values of the \"mode\"\n"
+" 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 arrow\" - just show the standard arrow\n"
+" nothing more or nothing less.\n"
+"\n"
+" \"-cursor none\" - same as \"-nocursor\"\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"
@@ -8855,21 +13290,24 @@ static void print_help(void) {
" 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"
+" possible. Often this will only be the same as \"some\"\n"
+" unless the display has overlay visuals or XFIXES\n"
+" extensions available. On Solaris and IRIX if XFIXES\n"
+" is not available, -overlay mode will be attempted.\n"
"\n"
+"-noxfixes Do not use the XFIXES extension to draw the exact cursor\n"
+" shape even if it is available.\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. 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"
+"-xwarppointer Move the pointer with XWarpPointer(3X) instead of\n"
+" the XTEST extension. Use this as a workaround\n"
+" if the pointer motion behaves incorrectly, e.g.\n"
+" on touchscreens or other non-standard setups.\n"
+" Also sometimes needed on 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"
@@ -8899,14 +13337,24 @@ static void print_help(void) {
" improves response on slow setups, but you lose all\n"
" visual feedback for drags, text selection, and some\n"
" menu traversals.\n"
-"-old_pointer Use the original pointer input handling mechanism.\n"
-" See check_input() and pointer() in source file for\n"
-" details.\n"
-"-old_pointer2 The default pointer input handling algorithm was changed\n"
-" again, this option indicates to use the second one.\n"
-"-input_skip n For the old pointer handling when non-threaded: try to\n"
+"-pointer_mode n Various pointer update schemes. The problem is pointer\n"
+" motion can cause rapid changes on the screen, e.g. a\n"
+" window drag. Neither x11vnc nor the bandwidth to the\n"
+" vncviewers can keep up these rapid screen changes:\n"
+" everything bogs down when dragging or scrolling.\n"
+" Note that most video h/w is optimized for writing, not\n"
+" reading (a 50X rate difference is possible) and x11vnc\n"
+" is reading all the time. So a scheme has to be used to\n"
+" \"eat\" much of that pointer input before re-polling the\n"
+" screen. n can be 1 to %d. n=1 was the original scheme\n"
+" used to about Jan 2004. n=2 is an improved scheme.\n"
+" n=3 is basically a dynamic -nodragging mode: it detects\n"
+" if the mouse drag motion has paused and refreshes\n"
+" the display. n=4 is TBD. The default n is %d.\n"
+"-input_skip n For the 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"
+" Default: %d\n"
"\n"
"-debug_pointer Print debugging output for every pointer event.\n"
"-debug_keyboard Print debugging output for every keyboard event.\n"
@@ -8919,6 +13367,9 @@ static void print_help(void) {
" down on load. Default: %d\n"
"-nap Monitor activity and if low take longer naps between\n"
" polls to really cut down load when idle. Default: %s\n"
+"-sb time Time in seconds after NO activity (e.g. screen blank)\n"
+" to really throttle down the screen polls (i.e. sleep\n"
+" for about 1.5 secs). Use 0 to disable. Default: %d\n"
"\n"
"-sigpipe string Broken pipe (SIGPIPE) handling. \"string\" can be\n"
" \"ignore\" or \"exit\". For \"ignore\" libvncserver\n"
@@ -8937,6 +13388,313 @@ static void print_help(void) {
" by checking the tile near the boundary. Default: %d\n"
"-fuzz n Tolerance in pixels to mark a tiles edges as changed.\n"
" Default: %d\n"
+"\n"
+"-gui [gui-opts] Start up a simple tcl/tk gui based on the the remote\n"
+" control options -remote/-query described below.\n"
+" Requires the \"wish\" program to be installed on the\n"
+" machine. \"gui-opts\" is not required: the default is\n"
+" to start up both the gui and x11vnc with the gui showing\n"
+" up on the X display in the environment variable DISPLAY.\n"
+"\n"
+" \"gui-opts\" can be a comma separated list of items.\n"
+" Currently there are only two types of items: 1) a gui\n"
+" mode and 2) the X display the gui should display on.\n"
+" The gui mode can be \"start\", \"conn\", or \"wait\"\n"
+" \"start\" is the default mode above and is not required.\n"
+" \"conn\" means do not automatically start up x11vnc,\n"
+" but instead just try to connect to an existing x11vnc\n"
+" process. \"wait\" means just start the gui and nothing\n"
+" else (you will later instruct the gui to start x11vnc\n"
+" or connect to an existing one.)\n"
+"\n"
+" Note the possible confusion regarding the potentially\n"
+" two different X displays: x11vnc polls one, but you\n"
+" may want the gui to appear on another. For example, if\n"
+" you ssh in and x11vnc is not running yet you may want\n"
+" the gui to come back to you via your ssh redirected X\n"
+" display (e.g. localhost:10).\n"
+"\n"
+" Examples: \"x11vnc -gui\", \"x11vnc -gui localhost:10\",\n"
+" \"x11vnc -gui :10\", \"x11vnc -gui wait,:10\",\n"
+" \"x11vnc -gui <x11vnc-opts...>\"\n"
+"\n"
+" If you do not specify a gui X display in \"gui-opts\"\n"
+" then the DISPLAY environment variable and -display\n"
+" option are tried (in that order). Regarding the x11vnc\n"
+" X display the gui will try to connect to, it first\n"
+" tries -display and then DISPLAY. For example, \"x11vnc\n"
+" -display :0 -gui otherhost:0\", will remote control an\n"
+" x11vnc polling :0 and display the gui on otherhost:0\n"
+"\n"
+" If you do not intend to start x11vnc from the gui\n"
+" (i.e. just remote control an existing one), then the\n"
+" gui process can run on a different machine from the\n"
+" x11vnc server as long as X permissions, etc. permit\n"
+" communication between the two.\n"
+"\n"
+"-remote command Remotely control some aspects of an already running\n"
+" x11vnc server. \"-R\" and \"-r\" are aliases for\n"
+" \"-remote\". After the remote control command is\n"
+" sent to the running server the 'x11vnc -remote ...'\n"
+" command exits. You can often use the -query command\n"
+" (see below) to see if the x11vnc server processed your\n"
+" -remote command.\n"
+"\n"
+" The default communication channel is that of X\n"
+" properties (specifically VNC_CONNECT), and so this\n"
+" command must be run with correct settings for DISPLAY\n"
+" and possibly XAUTHORITY to connect to the X server\n"
+" and set the property. Alternatively, use the -display\n"
+" and -auth options to set them to the correct values.\n"
+" The running server cannot use the -novncconnect option\n"
+" because that disables the communication channel.\n"
+" See below for alternate channels.\n"
+"\n"
+" For example: 'x11vnc -remote stop' (which is the same as\n"
+" 'x11vnc -R stop') will close down the x11vnc server.\n"
+" 'x11vnc -R shared' will enable shared connections, and\n"
+" 'x11vnc -R scale:3/4' will rescale the desktop.\n"
+"\n"
+" Note: the more drastic the change induced by the -remote\n"
+" command, the bigger the chance for bugs or crashes.\n"
+" Please report reproducible bugs.\n"
+"\n"
+" The following -remote/-R commands are supported:\n"
+"\n"
+" stop terminate the server, same as \"quit\"\n"
+" \"exit\" or \"shutdown\"\n"
+" ping see if the x11vnc server responds.\n"
+" Return is: ans=ping:<xdisplay>\n"
+" blacken try to push a black fb update to all\n"
+" clients (due to timings a client\n"
+" could miss it). Same as \"zero\", also\n"
+" \"zero:x1,y1,x2,y2\" for a rectangle.\n"
+" refresh send the entire fb to all clients.\n"
+" reset recreate the fb, polling memory, etc.\n"
+" id:windowid set -id window to \"windowid\". empty\n"
+" or \"root\" to go back to root window\n"
+" sid:windowid set -sid window to \"windowid\"\n"
+" flashcmap enable -flashcmap mode.\n"
+" noflashcmap disable -flashcmap mode.\n"
+" notruecolor enable -notruecolor mode.\n"
+" truecolor disable -notruecolor mode.\n"
+" overlay enable -overlay mode (if applicable).\n"
+" nooverlay disable -overlay mode.\n"
+" overlay_cursor in -overlay mode, enable cursor drawing.\n"
+" overlay_nocursor disable cursor drawing. same as\n"
+" nooverlay_cursor.\n"
+" visual:vis set -visual to \"vis\"\n"
+" scale:frac set -scale to \"frac\"\n"
+" viewonly enable -viewonly mode.\n"
+" noviewonly disable -viewonly mode.\n"
+" shared enable -shared mode.\n"
+" noshared disable -shared mode.\n"
+" forever enable -forever mode.\n"
+" noforever disable -forever mode.\n"
+" deny deny any new connections, same as \"lock\"\n"
+" nodeny allow new connections, same as \"unlock\"\n"
+" connect:host do reverse connection to host, \"host\"\n"
+" may be a comma separated list of hosts\n"
+" or host:ports. See -connect.\n"
+" disconnect:host disconnect any clients from \"host\"\n"
+" same as \"close:host\". Use host\n"
+" \"all\" to close all current clients.\n"
+" If you know the client internal hex ID,\n"
+" e.g. 0x3 (returned by -query clients and\n"
+" RFB_CLIENT_ID), you can use that too.\n"
+" allowonce:host For the next connection only, allow\n"
+" connection from \"host\".\n"
+" allow:hostlist set -allow list to (comma separated)\n"
+" \"hostlist\". See -allow and -localhost.\n"
+" Do not use with -allow /path/to/file\n"
+" Use \"+host\" to add a single host, and\n"
+" use \"-host\" to delete a single host\n"
+" localhost enable -localhost mode\n"
+" nolocalhost disable -localhost mode\n"
+" accept:cmd set -accept \"cmd\" (empty to disable).\n"
+" gone:cmd set -gone \"cmd\" (empty to disable).\n"
+" noshm enable -noshm mode.\n"
+" shm disable -noshm mode (i.e. use shm).\n"
+" flipbyteorder enable -flipbyteorder mode, you may need\n"
+" to set noshm for this to do something.\n"
+" noflipbyteorder disable -flipbyteorder mode.\n"
+" onetile enable -onetile mode. (you may need to\n"
+" set shm for this to do something)\n"
+" noonetile disable -onetile mode.\n"
+" blackout:str set -blackout \"str\" (empty to disable).\n"
+" See -blackout for the form of \"str\"\n"
+" (basically: WxH+X+Y,...)\n"
+" Use \"+WxH+X+Y\" to append a single\n"
+" rectangle use \"-WxH+X+Y\" to delete one\n"
+" xinerama enable -xinerama mode. (if applicable)\n"
+" noxinerama disable -xinerama mode.\n"
+" xrandr enable -xrandr mode. (if applicable)\n"
+" noxrandr disable -xrandr mode.\n"
+" xrandr_mode:mode set the -xrandr mode to \"mode\".\n"
+" padgeom:WxH set -padgeom to WxH (empty to disable)\n"
+" If WxH is \"force\" or \"do\" the padded\n"
+" geometry fb is immediately applied.\n"
+" quiet enable -quiet mode.\n"
+" noquiet disable -quiet mode.\n"
+" modtweak enable -modtweak mode.\n"
+" nomodtweak enable -nomodtweak mode.\n"
+" xkb enable -xkb modtweak mode.\n"
+" noxkb disable -xkb modtweak mode.\n"
+" skip_keycodes:str enable -xkb -skip_keycodes \"str\".\n"
+" add_keysyms enable -add_keysyms mode.\n"
+" noadd_keysyms stop adding keysyms. those added will\n"
+" still be removed at exit.\n"
+" clear_mods enable -clear_mods mode and clear them.\n"
+" noclear_mods disable -clear_mods mode.\n"
+" clear_keys enable -clear_keys mode and clear them.\n"
+" noclear_keys disable -clear_keys mode.\n"
+" remap:str set -remap \"str\" (empty to disable).\n"
+" See -remap for the form of \"str\"\n"
+" (basically: key1-key2,key3-key4,...)\n"
+" Use \"+key1-key2\" to append a single\n"
+" keymapping, use \"-key1-key2\" to delete.\n"
+" norepeat enable -norepeat mode.\n"
+" repeat disable -norepeat mode.\n"
+" bell enable bell (if supported).\n"
+" nobell disable bell.\n"
+" sel disable -nosel mode.\n"
+" nosel enable -nosel mode.\n"
+" primary disable -noprimary mode.\n"
+" noprimary enable -noprimary mode.\n"
+" cursor:mode enable -cursor \"mode\".\n"
+" show_cursor enable showing a cursor.\n"
+" noshow_cursor disable showing a cursor. (same as\n"
+" \"nocursor\")\n"
+" xfixes enable xfixes cursor shape mode.\n"
+" noxfixes disable xfixes cursor shape mode.\n"
+" cursorshape disable -nocursorshape mode.\n"
+" nocursorshape enable -nocursorshape mode.\n"
+" cursorpos disable -nocursorpos mode.\n"
+" nocursorpos enable -nocursorpos mode.\n"
+" xwarp enable -xwarppointer mode.\n"
+" noxwarp disable -xwarppointer mode.\n"
+" buttonmap:str set -buttonmap \"str\", empty to disable\n"
+" dragging disable -nodragging mode.\n"
+" nodragging enable -nodragging mode.\n"
+" pointer_mode n set -pointer_mode to n.\n"
+" input_skip n set -input_skip to n.\n"
+" debug_pointer enable -debug_pointer, same as \"dp\"\n"
+" nodebug_pointer disable -debug_pointer, same as \"nodp\"\n"
+" debug_keyboard enable -debug_keyboard, same as \"dk\"\n"
+" nodebug_keyboard disable -debug_keyboard, same as \"nodk\"\n"
+" defer:n set -defer to n ms,same as deferupdate:n\n"
+" wait:n set -wait to n ms.\n"
+" nap enable -nap mode.\n"
+" nonap disable -nap mode.\n"
+" sb:n set -sb to n s, same as screen_blank:n\n"
+" fs:frac set -fs fraction to \"frac\", e.g. 0.5\n"
+" gaps:n set -gaps to n.\n"
+" grow:n set -grow to n.\n"
+" fuzz:n set -fuzz to n.\n"
+" progressive:n set libvncserver -progressive slice\n"
+" height parameter to n.\n"
+" file:name run -remote commands from file \"name\",\n"
+" one command per line,blank and # skipped\n"
+" noremote disable the -remote command processing,\n"
+" it cannot be turned back on.\n"
+"\n"
+" The vncconnect(1) command from standard VNC\n"
+" distributions may also be used if string is prefixed\n"
+" with \"cmd=\" E.g. 'vncconnect cmd=stop'. Under some\n"
+" circumstances xprop(1) can used if it supports -set\n"
+" (see the FAQ).\n"
+"\n"
+" If \"-connect /path/to/file\" has been supplied to the\n"
+" running x11vnc server then that file can be used as a\n"
+" communication channel (this is the only way to remote\n"
+" control one of many x11vnc's polling the same X display)\n"
+" Simply run: 'x11vnc -connect /path/to/file -remote ...'\n"
+" or you can directly write to the file via something\n"
+" like: \"echo cmd=stop > /path/to/file\", etc.\n"
+"\n"
+"-query variable Like -remote, except just query the value of\n"
+" \"variable\". \"-Q\" is an alias for \"-query\".\n"
+" Multiple queries can be done by separating variables\n"
+" by commas, e.g. -query var1,var2. The results come\n"
+" back in the form ans=var1:value1,ans=var2:value2,...\n"
+" to the standard output. If a variable is read-only,\n"
+" it comes back with prefix \"aro=\" instead of \"ans=\".\n"
+"\n"
+" Some -remote commands are pure actions that do not make\n"
+" sense as variables, e.g. \"stop\" or \"disconnect\",\n"
+" in these cases the value returned is \"N/A\". To direct\n"
+" a query straight to the VNC_CONNECT property or connect\n"
+" file use \"qry=...\" instead of \"cmd=...\"\n"
+"\n"
+" Here is the current list of \"variables\" that can\n"
+" be supplied to the -query command. This includes the\n"
+" \"N/A\" ones that return no useful info. For variables\n"
+" names that do not correspond to an x11vnc option or\n"
+" remote command, we hope the name makes it obvious what\n"
+" the returned value corresponds to (hint: the ext_*\n"
+" variables correspond to the presence of X extensions):\n"
+"\n"
+" ans= stop quit exit shutdown ping blacken zero refresh\n"
+" reset close disconnect id sid flashcmap noflashcmap\n"
+" truecolor notruecolor overlay nooverlay overlay_cursor\n"
+" overlay_yescursor nooverlay_cursor overlay_nocursor\n"
+" visual scale viewonly noviewonly shared noshared\n"
+" forever noforever once deny lock nodeny unlock connect\n"
+" allowonce allow localhost nolocalhost accept gone shm\n"
+" noshm flipbyteorder noflipbyteorder onetile noonetile\n"
+" blackout xinerama noxinerama xrandr noxrandr xrandr_mode\n"
+" padgeom quiet q noquiet modtweak nomodtweak xkb noxkb\n"
+" skip_keycodes add_keysyms noadd_keysyms clear_mods\n"
+" noclear_mods clear_keys noclear_keys remap repeat\n"
+" norepeat bell nobell sel nosel primary noprimary\n"
+" cursorshape nocursorshape cursorpos nocursorpos cursor\n"
+" show_cursor noshow_cursor nocursor xfixes noxfixes xwarp\n"
+" xwarppointer noxwarp noxwarppointer buttonmap dragging\n"
+" nodragging pointer_mode input_skip debug_pointer dp\n"
+" nodebug_pointer nodp debug_keyboard dk nodebug_keyboard\n"
+" nodk deferupdate defer wait nap nonap sb screen_blank\n"
+" fs gaps grow fuzz progressive noremote\n"
+"\n"
+" aro= display vncdisplay desktopname desktop auth\n"
+" rootshift scale_str scaled_x scaled_y scale_numer\n"
+" scale_denom scale_fac scaling_noblend scaling_nomult4\n"
+" scaling_pad scaling_interpolate inetd safer unsafe\n"
+" passwdfile using_shm logfile o rc norc h help V version\n"
+" lastmod bg nofb sigpipe threads clients client_count\n"
+" pid ext_xtest ext_xkb ext_xshm ext_xinerama ext_overlay\n"
+" ext_xfixes ext_xdamage ext_xrandr rootwin num_buttons\n"
+" button_mask mouse_x mouse_y bpp depth indexed_color\n"
+" dpy_x dpy_y rfbport rfbwait rfbauth passwd alwaysshared\n"
+" dontdisconnect httpdir enablehttpproxy\n"
+"\n"
+"-noremote Do not process any remote control commands or queries.\n"
+"\n"
+" A note about security wrt remote control commands.\n"
+" If someone can connect to the X display and change the\n"
+" property VNC_CONNECT, then they can remotely control\n"
+" x11vnc. Normally access to the X display is protected.\n"
+" Note that if they can modify VNC_CONNECT, they could\n"
+" also run their own x11vnc and have complete control\n"
+" of the desktop. If the \"-connect /path/to/file\"\n"
+" channel is being used, obviously anyone who can write\n"
+" to /path/to/file can remotely control x11vnc. So be\n"
+" sure to protect the X display and that file's write\n"
+" permissions.\n"
+"\n"
+"-unsafe If x11vnc is running as root (e.g. inetd or Xsetup for\n"
+" a display manager) a few remote commands are disabled\n"
+" (currently: id:pick, accept:<cmd>, and gone:<cmd>)\n"
+" because they are associated with running external\n"
+" programs. If you specify -unsafe, then these remote\n"
+" control commands are allowed when running as root.\n"
+" When running as non-root all commands are allowed.\n"
+" See -safer below.\n"
+"-safer Even if not running as root, disable the above unsafe\n"
+" remote control commands.\n"
+"\n"
+"-deny_all For use with -remote nodeny: start out denying all\n"
+" incoming clients until \"-remote nodeny\" is used to\n"
+" let them in.\n"
"%s\n"
"\n"
"These options are passed to libvncserver:\n"
@@ -8951,9 +13709,12 @@ static void print_help(void) {
use_modifier_tweak ? "-modtweak":"-nomodtweak",
no_autorepeat ? "-norepeat":"-repeat",
cursor_pos_updates ? "-cursorpos":"-nocursorpos",
+ pointer_mode_max, pointer_mode,
+ ui_skip,
defer_update,
waitms,
take_naps ? "on":"off",
+ screen_blank,
use_threads ? "-threads":"-nothreads",
fs_frac,
gaps_fill,
@@ -8971,7 +13732,7 @@ static void print_help(void) {
*/
#define MAXN 256
-static char *this_host(void) {
+char *this_host(void) {
char host[MAXN];
#ifdef LIBVNCSERVER_HAVE_GETHOSTNAME
if (gethostname(host, MAXN) == 0) {
@@ -9001,7 +13762,7 @@ static char *choose_title(char *display) {
}
}
strncat(title, display, MAXN - strlen(title));
- if (subwin) {
+ if (subwin && valid_window(subwin)) {
char *name;
if (XFetchName(dpy, subwin, &name)) {
strncat(title, " ", MAXN - strlen(title));
@@ -9036,6 +13797,7 @@ static int limit_shm(void) {
return limit;
}
+
/*
* quick-n-dirty ~/.x11vncrc: each line (except # comments) is a cmdline option.
*/
@@ -9043,7 +13805,7 @@ static int argc2 = 0;
static char **argv2;
static void check_rcfile(int argc, char **argv) {
- int i, norc = 0, argmax = 1024;
+ int i, pwlast, norc = 0, argmax = 1024;
char *infile = NULL;
char rcfile[1024];
FILE *rc;
@@ -9062,10 +13824,12 @@ static void check_rcfile(int argc, char **argv) {
}
}
}
+ rc_norc = norc;
if (norc) {
;
} else if (infile != NULL) {
rc = fopen(infile, "r");
+ rc_rcfile = strdup(infile);
if (rc == NULL) {
fprintf(stderr, "could not open rcfile: %s\n", infile);
perror("fopen");
@@ -9078,6 +13842,7 @@ static void check_rcfile(int argc, char **argv) {
strcat(rcfile, "/.x11vncrc");
infile = rcfile;
rc = fopen(rcfile, "r");
+ rc_rcfile = strdup(rcfile);
if (rc == NULL) {
norc = 1;
}
@@ -9188,8 +13953,21 @@ static void check_rcfile(int argc, char **argv) {
fclose(rc);
free(buf);
}
+ pwlast = 0;
for (i=1; i < argc; i++) {
argv2[argc2++] = strdup(argv[i]);
+
+ if (pwlast || !strcmp("-passwd", argv[i])
+ || !strcmp("-viewpasswd", argv[i])) {
+ char *p = argv[i];
+ if (pwlast) {
+ pwlast = 0;
+ } else {
+ pwlast = 1;
+ }
+ while (*p != '\0')
+ *p++ = '\0';
+ }
if (argc2 >= argmax) {
fprintf(stderr, "too many rcfile options\n");
exit(1);
@@ -9199,28 +13977,47 @@ static void check_rcfile(int argc, char **argv) {
int main(int argc, char* argv[]) {
- XImage *fb;
- int i;
+ int i, len;
int ev, er, maj, min;
- char *use_dpy = NULL;
- char *auth_file = NULL;
- char *arg, *visual_str = NULL;
- char *logfile = NULL;
- char *passwdfile = NULL;
- char *blackout_string = NULL;
- char *remap_file = NULL;
- char *pointer_remap = NULL;
+ char *arg;
+ char *remote_cmd = NULL;
+ char *gui_string = NULL;
+ int remote_query = 0;
int pw_loc = -1;
int vpw_loc = -1;
- int dt = 0;
- int bg = 0;
- int got_rfbwait = 0;
- int got_deferupdate = 0, got_defer = 0;
+ int dt = 0, bg = 0;
+ int got_rfbwait = 0, got_deferupdate = 0, got_defer = 0;
/* used to pass args we do not know about to rfbGetScreen(): */
int argc_vnc = 1; char *argv_vnc[128];
+ /* if we are root limit some remote commands: */
+ if (!getuid() || !geteuid()) {
+ safe_remote_only = 1;
+ }
+
argv_vnc[0] = strdup(argv[0]);
+ program_name = strdup(argv[0]);
+
+ len = 0;
+ for (i=1; i < argc; i++) {
+ len += strlen(argv[i]) + 4 + 1;
+ }
+ program_cmdline = (char *)malloc(len+1);
+ program_cmdline[0] = '\0';
+ for (i=1; i < argc; i++) {
+ char *s = argv[i];
+ if (program_cmdline[0]) {
+ strcat(program_cmdline, " ");
+ }
+ if (*s == '-') {
+ strcat(program_cmdline, s);
+ } else {
+ strcat(program_cmdline, "{{");
+ strcat(program_cmdline, s);
+ strcat(program_cmdline, "}}");
+ }
+ }
check_rcfile(argc, argv);
/* kludge for the new array argv2 set in check_rcfile() */
@@ -9241,110 +14038,83 @@ int main(int argc, char* argv[]) {
if (!strcmp(arg, "-display")) {
CHECK_ARGC
- use_dpy = argv[++i];
- } else if (!strcmp(arg, "-id")) {
+ use_dpy = strdup(argv[++i]);
+ } else if (!strcmp(arg, "-auth")) {
CHECK_ARGC
- if (sscanf(argv[++i], "0x%x", &subwin) != 1) {
- if (sscanf(argv[i], "%d", &subwin) != 1) {
- fprintf(stderr, "bad -id arg: %s\n",
- argv[i]);
- exit(1);
- }
- }
- } else if (!strcmp(arg, "-sid")) {
- rootshift = 1;
+ auth_file = strdup(argv[++i]);
+ } else if (!strcmp(arg, "-id") || !strcmp(arg, "-sid")) {
CHECK_ARGC
- if (sscanf(argv[++i], "0x%x", &subwin) != 1) {
- if (sscanf(argv[i], "%d", &subwin) != 1) {
- fprintf(stderr, "bad -id arg: %s\n",
- argv[i]);
- exit(1);
- }
- }
- } else if (!strcmp(arg, "-scale")) {
- int m, n;
- char *p;
- double f;
- CHECK_ARGC
- if ( (p = strchr(argv[++i], ':')) != NULL) {
- /* options */
- if (strstr(p+1, "nb") != NULL) {
- scaling_noblend = 1;
- }
- if (strstr(p+1, "n4") != NULL) {
- scaling_nomult4 = 1;
- }
- if (strstr(p+1, "in") != NULL) {
- scaling_interpolate = 1;
- }
- if (strstr(p+1, "pad") != NULL) {
- scaling_pad = 1;
- }
- *p = '\0';
+ if (!strcmp(arg, "-sid")) {
+ rootshift = 1;
+ } else {
+ rootshift = 0;
}
- if (strchr(argv[i], '.') != NULL) {
- double test, diff, eps = 1.0e-7;
- if (sscanf(argv[i], "%lf", &f) != 1) {
- fprintf(stderr, "bad -scale arg: %s\n",
- argv[i]);
+ i++;
+ if (!strcmp("pick", argv[i])) {
+ if (safe_remote_only) {
+ fprintf(stderr, "unsafe: %s pick\n",
+ arg);
exit(1);
- }
- scale_fac = (double) f;
- /* look for common fractions from small ints: */
- for (n=2; n<=10; n++) {
- for (m=1; m<n; m++) {
- test = ((double) m)/ n;
- diff = scale_fac - test;
- if (-eps < diff && diff < eps) {
- scale_numer = m;
- scale_denom = n;
- break;
-
- }
- }
- if (scale_denom) {
- break;
- }
- }
- } else {
- if (sscanf(argv[i], "%d/%d", &m, &n) != 2) {
- fprintf(stderr, "bad -scale arg: %s\n",
- argv[i]);
+ } else if (! pick_windowid(&subwin)) {
+ fprintf(stderr, "bad %s pick\n", arg);
exit(1);
}
- scale_fac = ((double) m)/ n;
- scale_numer = m;
- scale_denom = n;
- }
- if (scale_fac == 1.0) {
- if (! quiet) {
- rfbLog("scaling disabled for factor "
- " %f\n", scale_fac);
- }
- } else {
- scaling = 1;
+ } else if (! scan_hexdec(argv[i], &subwin)) {
+ fprintf(stderr, "bad %s arg: %s\n", arg,
+ argv[i]);
+ exit(1);
}
- } else if (!strcmp(arg, "-visual")) {
- CHECK_ARGC
- visual_str = argv[++i];
+ } else if (!strcmp(arg, "-flashcmap")) {
+ flash_cmap = 1;
+ } else if (!strcmp(arg, "-notruecolor")) {
+ force_indexed_color = 1;
} 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")) {
- force_indexed_color = 1;
+ } else if (!strcmp(arg, "-overlay_yescursor")) {
+ overlay = 1;
+ overlay_cursor = 2;
+ } else if (!strcmp(arg, "-visual")) {
+ CHECK_ARGC
+ visual_str = strdup(argv[++i]);
+ } else if (!strcmp(arg, "-scale")) {
+ CHECK_ARGC
+ scale_str = strdup(argv[++i]);
} else if (!strcmp(arg, "-viewonly")) {
view_only = 1;
+ } else if (!strcmp(arg, "-shared")) {
+ shared = 1;
+ } else if (!strcmp(arg, "-once")) {
+ connect_once = 1;
+ } else if (!strcmp(arg, "-many") || !strcmp(arg, "-forever")) {
+ connect_once = 0;
+ } else if (!strcmp(arg, "-inetd")) {
+ inetd = 1;
+ } else if (!strcmp(arg, "-connect")) {
+ CHECK_ARGC
+ if (strchr(argv[++i], '/')) {
+ client_connect_file = strdup(argv[i]);
+ } else {
+ client_connect = strdup(argv[i]);
+ }
+ } else if (!strcmp(arg, "-vncconnect")) {
+ vnc_connect = 1;
+ } else if (!strcmp(arg, "-novncconnect")) {
+ vnc_connect = 0;
+ } else if (!strcmp(arg, "-allow")) {
+ CHECK_ARGC
+ allow_list = strdup(argv[++i]);
+ } else if (!strcmp(arg, "-localhost")) {
+ allow_list = strdup("127.0.0.1");
} else if (!strcmp(arg, "-viewpasswd")) {
vpw_loc = i;
CHECK_ARGC
viewonly_passwd = strdup(argv[++i]);
} else if (!strcmp(arg, "-passwdfile")) {
CHECK_ARGC
- passwdfile = argv[++i];
+ passwdfile = strdup(argv[++i]);
} else if (!strcmp(arg, "-storepasswd")) {
if (i+2 >= argc || rfbEncryptAndStorePasswd(argv[i+1],
argv[i+2]) != 0) {
@@ -9355,44 +14125,58 @@ int main(int argc, char* argv[]) {
argv[i+2]);
exit(0);
}
- } else if (!strcmp(arg, "-shared")) {
- shared = 1;
- } else if (!strcmp(arg, "-auth")) {
- CHECK_ARGC
- auth_file = argv[++i];
- } else if (!strcmp(arg, "-allow")) {
- CHECK_ARGC
- allow_list = argv[++i];
- } else if (!strcmp(arg, "-localhost")) {
- allow_list = "127.0.0.1";
} else if (!strcmp(arg, "-accept")) {
CHECK_ARGC
- accept_cmd = argv[++i];
+ accept_cmd = strdup(argv[++i]);
} else if (!strcmp(arg, "-gone")) {
CHECK_ARGC
- gone_cmd = argv[++i];
- } else if (!strcmp(arg, "-once")) {
- connect_once = 1;
- } else if (!strcmp(arg, "-many")
- || !strcmp(arg, "-forever")) {
- connect_once = 0;
- } else if (!strcmp(arg, "-connect")) {
- CHECK_ARGC
- if (strchr(argv[++i], '/')) {
- client_connect_file = argv[i];
- } else {
- client_connect = strdup(argv[i]);
- }
- } else if (!strcmp(arg, "-vncconnect")) {
- vnc_connect = 1;
- } else if (!strcmp(arg, "-novncconnect")) {
- vnc_connect = 0;
- } else if (!strcmp(arg, "-inetd")) {
- inetd = 1;
+ gone_cmd = strdup(argv[++i]);
} else if (!strcmp(arg, "-noshm")) {
using_shm = 0;
} else if (!strcmp(arg, "-flipbyteorder")) {
flip_byte_order = 1;
+ } else if (!strcmp(arg, "-onetile")) {
+ single_copytile = 1;
+ } else if (!strcmp(arg, "-blackout")) {
+ CHECK_ARGC
+ blackout_string = strdup(argv[++i]);
+ } else if (!strcmp(arg, "-xinerama")) {
+ xinerama = 1;
+ } else if (!strcmp(arg, "-xrandr")) {
+ xrandr = 1;
+ if (i < argc-1) {
+ char *s = argv[i+1];
+ if (known_xrandr_mode(s)) {
+ xrandr_mode = strdup(s);
+ i++;
+ }
+ }
+ } else if (!strcmp(arg, "-padgeom")
+ || !strcmp(arg, "-padgeometry")) {
+ CHECK_ARGC
+ pad_geometry = strdup(argv[++i]);
+ } else if (!strcmp(arg, "-o") || !strcmp(arg, "-logfile")) {
+ CHECK_ARGC
+ logfile = strdup(argv[++i]);
+ } else if (!strcmp(arg, "-rc")) {
+ i++; /* done above */
+ } else if (!strcmp(arg, "-norc")) {
+ ; /* done above */
+ } else if (!strcmp(arg, "-h") || !strcmp(arg, "-help")
+ || !strcmp(arg, "-?")) {
+ print_help();
+ } else if (!strcmp(arg, "-V") || !strcmp(arg, "-version")) {
+ fprintf(stderr, "x11vnc: %s\n", lastmod);
+ exit(0);
+ } else if (!strcmp(arg, "-q") || !strcmp(arg, "-quiet")) {
+ quiet = 1;
+ } else if (!strcmp(arg, "-bg") || !strcmp(arg, "-background")) {
+#ifdef LIBVNCSERVER_HAVE_SETSID
+ bg = 1;
+ opts_bg = bg;
+#else
+ fprintf(stderr, "warning: -bg mode not supported.\n");
+#endif
} else if (!strcmp(arg, "-modtweak")) {
use_modifier_tweak = 1;
} else if (!strcmp(arg, "-nomodtweak")) {
@@ -9401,11 +14185,11 @@ int main(int argc, char* argv[]) {
use_iso_level3 = 1;
} else if (!strcmp(arg, "-xkb")) {
use_xkb_modtweak = 1;
- } else if (!strcmp(arg, "-skip_keycodes")) {
- CHECK_ARGC
- skip_keycodes = argv[++i];
} else if (!strcmp(arg, "-xkbcompat")) {
xkbcompat = 1;
+ } else if (!strcmp(arg, "-skip_keycodes")) {
+ CHECK_ARGC
+ skip_keycodes = strdup(argv[++i]);
} else if (!strcmp(arg, "-add_keysyms")) {
add_keysyms++;
} else if (!strcmp(arg, "-clear_mods")) {
@@ -9414,65 +14198,68 @@ int main(int argc, char* argv[]) {
clear_mods = 2;
} else if (!strcmp(arg, "-remap")) {
CHECK_ARGC
- remap_file = argv[++i];
- } else if (!strcmp(arg, "-blackout")) {
- CHECK_ARGC
- blackout_string = argv[++i];
- } else if (!strcmp(arg, "-xinerama")) {
- xinerama = 1;
- } else if (!strcmp(arg, "-norc")) {
- ; /* done above */
- } else if (!strcmp(arg, "-rc")) {
- i++; /* done above */
- } else if (!strcmp(arg, "-nobell")) {
- watch_bell = 0;
+ remap_file = strdup(argv[++i]);
+ } else if (!strcmp(arg, "-norepeat")) {
+ no_autorepeat = 1;
+ } else if (!strcmp(arg, "-repeat")) {
+ no_autorepeat = 0;
} else if (!strcmp(arg, "-nofb")) {
nofb = 1;
+ } else if (!strcmp(arg, "-nobell")) {
+ watch_bell = 0;
} else if (!strcmp(arg, "-nosel")) {
watch_selection = 0;
} else if (!strcmp(arg, "-noprimary")) {
watch_primary = 0;
} else if (!strcmp(arg, "-cursor")) {
show_cursor = 1;
- if (i >= argc-1) {
- ;
- } else {
+ if (i < argc-1) {
char *s = argv[i+1];
- if (*s == 'X' || !strcmp(s, "default") ||
- !strcmp(s, "some") || !strcmp(s, "most")) {
+ if (known_cursors_mode(s)) {
multiple_cursors_mode = strdup(s);
i++;
- }
+ if (!strcmp(s, "none")) {
+ show_cursor = 0;
+ }
+ }
}
} else if (!strcmp(arg, "-nocursor")) {
+ multiple_cursors_mode = strdup("none");
show_cursor = 0;
+ } else if (!strcmp(arg, "-noxfixes")) {
+ use_xfixes = 0;
+ } else if (!strcmp(arg, "-nocursorshape")) {
+ cursor_shape_updates = 0;
} else if (!strcmp(arg, "-cursorpos")) {
cursor_pos_updates = 1;
} else if (!strcmp(arg, "-nocursorpos")) {
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];
+ pointer_remap = strdup(argv[++i]);
} else if (!strcmp(arg, "-nodragging")) {
show_dragging = 0;
+ } else if (!strcmp(arg, "-pointer_mode")) {
+ char *p, *s;
+ CHECK_ARGC
+ s = argv[++i];
+ if ((p = strchr(s, ':')) != NULL) {
+ ui_skip = atoi(p+1);
+ if (! ui_skip) ui_skip = 1;
+ *p = '\0';
+ }
+ if (atoi(s) < 1 || atoi(s) > pointer_mode_max) {
+ rfbLog("pointer_mode out of range 1-%d: %d\n",
+ pointer_mode_max, atoi(s));
+ } else {
+ pointer_mode = atoi(s);
+ }
} else if (!strcmp(arg, "-input_skip")) {
CHECK_ARGC
ui_skip = atoi(argv[++i]);
if (! ui_skip) ui_skip = 1;
- } else if (!strcmp(arg, "-old_pointer")) {
- old_pointer = 1;
- } else if (!strcmp(arg, "-old_pointer2")) {
- old_pointer = 2;
- } else if (!strcmp(arg, "-norepeat")) {
- no_autorepeat = 1;
- } else if (!strcmp(arg, "-repeat")) {
- no_autorepeat = 0;
- } else if (!strcmp(arg, "-onetile")) {
- single_copytile = 1;
} else if (!strcmp(arg, "-debug_pointer")
|| !strcmp(arg, "-dp")) {
debug_pointer++;
@@ -9488,25 +14275,24 @@ int main(int argc, char* argv[]) {
waitms = atoi(argv[++i]);
} else if (!strcmp(arg, "-nap")) {
take_naps = 1;
-#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
- } else if (!strcmp(arg, "-threads")) {
- use_threads = 1;
- } else if (!strcmp(arg, "-nothreads")) {
- use_threads = 0;
-#endif
+ } else if (!strcmp(arg, "-sb")) {
+ CHECK_ARGC
+ screen_blank = atoi(argv[++i]);
} else if (!strcmp(arg, "-sigpipe")) {
CHECK_ARGC
- if (!strcmp(argv[++i], "ignore")) {
- sigpipe = 1;
- } else if (!strcmp(argv[i], "exit")) {
- sigpipe = 2;
- } else if (!strcmp(argv[i], "skip")) {
- sigpipe = 0;
+ if (known_sigpipe_mode(argv[++i])) {
+ sigpipe = strdup(argv[i]);
} else {
fprintf(stderr, "bad -sigpipe arg: %s, must "
"be \"ignore\" or \"exit\"\n", argv[i]);
exit(1);
}
+#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
+ } else if (!strcmp(arg, "-threads")) {
+ use_threads = 1;
+ } else if (!strcmp(arg, "-nothreads")) {
+ use_threads = 0;
+#endif
} else if (!strcmp(arg, "-fs")) {
CHECK_ARGC
fs_frac = atof(argv[++i]);
@@ -9519,24 +14305,42 @@ int main(int argc, char* argv[]) {
} else if (!strcmp(arg, "-fuzz")) {
CHECK_ARGC
tile_fuzz = atoi(argv[++i]);
- } else if (!strcmp(arg, "-h") || !strcmp(arg, "-help")
- || !strcmp(arg, "-?")) {
- print_help();
- } else if (!strcmp(arg, "-V") || !strcmp(arg, "-version")) {
- fprintf(stderr, "x11vnc: %s\n", lastmod);
- exit(0);
- } else if (!strcmp(arg, "-o") || !strcmp(arg, "-logfile")) {
+ } else if (!strcmp(arg, "-gui")) {
+ launch_gui = 1;
+ if (i < argc-1) {
+ char *s = argv[i+1];
+ if (*s != '-') {
+ gui_string = strdup(s);
+ i++;
+ }
+ }
+ } else if (!strcmp(arg, "-remote") || !strcmp(arg, "-R")
+ || !strcmp(arg, "-r")) {
CHECK_ARGC
- logfile = argv[++i];
- } else if (!strcmp(arg, "-q") || !strcmp(arg, "-quiet")) {
+ remote_cmd = strdup(argv[++i]);
+ if (!strcmp(remote_cmd, "ping")) {
+ remote_query = 1;
+ }
quiet = 1;
-#ifdef LIBVNCSERVER_HAVE_SETSID
- } else if (!strcmp(arg, "-bg") || !strcmp(arg, "-background")) {
- bg = 1;
-#endif
+ xkbcompat = 0;
+ } else if (!strcmp(arg, "-query") || !strcmp(arg, "-Q")) {
+ CHECK_ARGC
+ remote_cmd = strdup(argv[++i]);
+ remote_query = 1;
+ quiet = 1;
+ xkbcompat = 0;
+ } else if (!strcmp(arg, "-noremote")) {
+ accept_remote_cmds = 0;
+ } else if (!strcmp(arg, "-unsafe")) {
+ safe_remote_only = 0;
+ } else if (!strcmp(arg, "-safer")) {
+ safe_remote_only = 1;
+ } else if (!strcmp(arg, "-deny_all")) {
+ deny_all = 1;
} else {
- if (!strcmp(arg, "-desktop")) {
+ if (!strcmp(arg, "-desktop") && i < argc-1) {
dt = 1;
+ rfb_desktop_name = strdup(argv[i+1]);
}
if (!strcmp(arg, "-passwd")) {
pw_loc = i;
@@ -9562,6 +14366,10 @@ int main(int argc, char* argv[]) {
}
}
}
+
+ if (launch_gui) {
+ do_gui(gui_string);
+ }
if (logfile) {
int n;
if ((n = open(logfile, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) {
@@ -9588,20 +14396,27 @@ int main(int argc, char* argv[]) {
}
}
+ if (client_connect_file && remote_cmd) {
+ /* no need to open DISPLAY, just write it to the file now */
+ int rc = send_remote_cmd(remote_cmd, remote_query);
+ fflush(stderr);
+ fflush(stdout);
+ exit(rc);
+ }
+
/*
* If -passwd was used, clear it out of argv. This does not
* work on all UNIX, have to use execvp() in general...
*/
if (pw_loc > 0) {
- char *p = argv[pw_loc];
- while (*p != '\0') {
- *p++ = '\0';
- }
- if (pw_loc+1 < argc) {
- p = argv[pw_loc+1];
- while (*p != '\0') {
- *p++ = '\0';
+ int i;
+ for (i=pw_loc; i <= pw_loc+1; i++) {
+ if (i < argc) {
+ char *p = argv[i];
+ while (*p != '\0') {
+ *p++ = '\0';
+ }
}
}
} else if (passwdfile) {
@@ -9611,7 +14426,7 @@ int main(int argc, char* argv[]) {
in = fopen(passwdfile, "r");
if (in == NULL) {
rfbLog("cannot open passwdfile: %s\n", passwdfile);
- rfbLog("fopen");
+ rfbLogPerror("fopen");
exit(1);
}
if (fgets(line, 1024, in) != NULL) {
@@ -9619,7 +14434,7 @@ int main(int argc, char* argv[]) {
if (len > 0 && line[len-1] == '\n') {
line[len-1] = '\0';
}
- argv_vnc[argc_vnc++] = "-passwd";
+ argv_vnc[argc_vnc++] = strdup("-passwd");
argv_vnc[argc_vnc++] = strdup(line);
pw_loc = 100; /* just for pw_loc check below */
if (fgets(line, 1024, in) != NULL) {
@@ -9656,14 +14471,13 @@ int main(int argc, char* argv[]) {
fclose(in);
}
if (vpw_loc > 0) {
- char *p = argv[vpw_loc];
- while (*p != '\0') {
- *p++ = '\0';
- }
- if (vpw_loc+1 < argc) {
- p = argv[vpw_loc+1];
- while (*p != '\0') {
- *p++ = '\0';
+ int i;
+ for (i=vpw_loc; i <= vpw_loc+1; i++) {
+ if (i < argc) {
+ char *p = argv[i];
+ while (*p != '\0') {
+ *p++ = '\0';
+ }
}
}
}
@@ -9698,77 +14512,20 @@ int main(int argc, char* argv[]) {
/* 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) {
- rfbLog("warning: -flashcmap may be incompatible "
- "with -overlay\n");
- }
-
- 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) {
- 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;
- }
+ argv_vnc[argc_vnc++] = strdup("-rfbwait");
+ argv_vnc[argc_vnc++] = strdup("604800000"); /* one week... */
}
/* no framebuffer (Win2VNC) mode */
if (nofb) {
- /* disable things that do not make sense */
+ /* disable things that do not make sense with no fb */
using_shm = 0;
flash_cmap = 0;
show_cursor = 0;
show_multiple_cursors = 0;
overlay = 0;
+ overlay_cursor = 0;
if (! quiet) {
rfbLog("disabling -cursor, fb, shm, etc. in "
"-nofb mode.\n");
@@ -9780,18 +14537,11 @@ int main(int argc, char* argv[]) {
}
}
- /* check for OS with small shm limits */
- if (using_shm && ! single_copytile) {
- if (limit_shm()) {
- single_copytile = 1;
- }
- }
-
if (! got_deferupdate) {
char tmp[40];
/* XXX not working yet in libvncserver */
sprintf(tmp, "%d", defer_update);
- argv_vnc[argc_vnc++] = "-deferupdate";
+ argv_vnc[argc_vnc++] = strdup("-deferupdate");
argv_vnc[argc_vnc++] = strdup(tmp);
}
@@ -9809,24 +14559,26 @@ int main(int argc, char* argv[]) {
fprintf(stderr, "Settings:\n");
fprintf(stderr, " display: %s\n", use_dpy ? use_dpy
: "null");
- fprintf(stderr, " subwin: 0x%x\n", subwin);
+ fprintf(stderr, " authfile: %s\n", auth_file ? auth_file
+ : "null");
+ fprintf(stderr, " subwin: 0x%lx\n", subwin);
+ fprintf(stderr, " rootshift: %d\n", rootshift);
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_cursor: %d\n", overlay_cursor);
+ fprintf(stderr, " visual: %s\n", visual_str ? visual_str
+ : "null");
+ fprintf(stderr, " scaling: %d %.5f\n", scaling, scale_fac);
fprintf(stderr, " viewonly: %d\n", view_only);
fprintf(stderr, " shared: %d\n", shared);
fprintf(stderr, " conn_once: %d\n", connect_once);
+ fprintf(stderr, " inetd: %d\n", inetd);
fprintf(stderr, " connect: %s\n", client_connect
? client_connect : "null");
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
- : "null");
fprintf(stderr, " allow: %s\n", allow_list ? allow_list
: "null");
fprintf(stderr, " passfile: %s\n", passwdfile ? passwdfile
@@ -9835,14 +14587,20 @@ int main(int argc, char* argv[]) {
: "null");
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, " onetile: %d\n", single_copytile);
fprintf(stderr, " blackout: %s\n", blackout_string
? blackout_string : "null");
fprintf(stderr, " xinerama: %d\n", xinerama);
+ fprintf(stderr, " xrandr: %d\n", xrandr);
+ fprintf(stderr, " xrandrmode: %s\n", xrandr_mode ? xrandr_mode
+ : "null");
fprintf(stderr, " logfile: %s\n", logfile ? logfile
: "null");
+ fprintf(stderr, " rc_file: %s\n", rc_rcfile ? rc_rcfile
+ : "null");
+ fprintf(stderr, " norc: %d\n", rc_norc);
fprintf(stderr, " bg: %d\n", bg);
fprintf(stderr, " mod_tweak: %d\n", use_modifier_tweak);
fprintf(stderr, " isolevel3: %d\n", use_iso_level3);
@@ -9854,6 +14612,7 @@ int main(int argc, char* argv[]) {
fprintf(stderr, " clearmods: %d\n", clear_mods);
fprintf(stderr, " remap: %s\n", remap_file ? remap_file
: "null");
+ fprintf(stderr, " norepeat: %d\n", no_autorepeat);
fprintf(stderr, " nofb: %d\n", nofb);
fprintf(stderr, " watchbell: %d\n", watch_bell);
fprintf(stderr, " watchsel: %d\n", watch_selection);
@@ -9862,27 +14621,30 @@ int main(int argc, char* argv[]) {
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, " xfixes: %d\n", use_xfixes);
fprintf(stderr, " cursorshp: %d\n", cursor_shape_updates);
+ fprintf(stderr, " cursorpos: %d\n", cursor_pos_updates);
+ fprintf(stderr, " xwarpptr: %d\n", use_xwarppointer);
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, " ptr_mode: %d\n", pointer_mode);
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, " sb: %d\n", screen_blank);
+ fprintf(stderr, " sigpipe: %s\n", sigpipe
+ ? sigpipe : "null");
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, " deny_all: %d\n", deny_all);
+ fprintf(stderr, " noremote: %d\n", !accept_remote_cmds);
fprintf(stderr, "\n");
rfbLog("x11vnc version: %s\n", lastmod);
} else {
@@ -9946,21 +14708,140 @@ int main(int argc, char* argv[]) {
scr = DefaultScreen(dpy);
rootwin = RootWindow(dpy, scr);
+ if (remote_cmd) {
+ int rc = send_remote_cmd(remote_cmd, remote_query);
+ XFlush(dpy);
+ fflush(stderr);
+ usleep(30 * 1000); /* still needed? */
+ XCloseDisplay(dpy);
+ exit(rc);
+ }
+
if (! dt) {
static char str[] = "-desktop";
argv_vnc[argc_vnc++] = str;
argv_vnc[argc_vnc++] = choose_title(use_dpy);
+ rfb_desktop_name = strdup(argv_vnc[argc_vnc-1]);
+ }
+
+#ifdef LIBVNCSERVER_HAVE_LIBXFIXES
+ if (! XFixesQueryExtension(dpy, &xfixes_base_event_type, &er)) {
+ if (! quiet) {
+ rfbLog("disabling xfixes mode: display does not "
+ "support it.\n");
+ }
+ xfixes_present = 0;
+ } else {
+ xfixes_present = 1;
+ }
+#endif
+
+#ifdef LIBVNCSERVER_HAVE_LIBXDAMAGE
+ if (! XDamageQueryExtension(dpy, &xdamage_base_event_type, &er)) {
+ if (0 && ! quiet) {
+ rfbLog("disabling xdamage mode: display does not "
+ "support it.\n");
+ }
+ xdamage_present = 0;
+ } else {
+ xdamage_present = 1;
+ }
+#endif
+
+ overlay_present = 0;
+#ifdef SOLARIS_OVERLAY
+ if (! XQueryExtension(dpy, "SUN_OVL", &maj, &ev, &er)) {
+ if (! quiet && overlay) {
+ rfbLog("disabling -overlay: SUN_OVL "
+ "extension not available.\n");
+ }
+ } else {
+ overlay_present = 1;
+ }
+#endif
+#ifdef IRIX_OVERLAY
+ if (! XReadDisplayQueryExtension(dpy, &ev, &er)) {
+ if (! quiet && overlay) {
+ rfbLog("disabling -overlay: IRIX ReadDisplay "
+ "extension not available.\n");
+ }
+ } else {
+ overlay_present = 1;
+ }
+#endif
+ if (overlay && !overlay_present) {
+ overlay = 0;
+ overlay_cursor = 0;
+ }
+
+ /* cursor shapes setup */
+ if (! multiple_cursors_mode) {
+ multiple_cursors_mode = strdup("default");
+ }
+ if (show_cursor) {
+ if(!strcmp(multiple_cursors_mode, "default")
+ && xfixes_present && use_xfixes) {
+ free(multiple_cursors_mode);
+ multiple_cursors_mode = strdup("most");
+
+ if (! quiet) {
+ rfbLog("XFIXES available on display, resetting"
+ " cursor mode\n");
+ rfbLog(" to: '-cursor most'.\n");
+ rfbLog(" to disable this behavior use: "
+ "'-cursor arrow'.\n");
+ }
+ }
+ if(!strcmp(multiple_cursors_mode, "most")) {
+ if (xfixes_present && use_xfixes &&
+ overlay_cursor == 1) {
+ if (! quiet) {
+ rfbLog("using XFIXES for cursor "
+ "drawing.\n");
+ }
+ overlay_cursor = 0;
+ }
+ }
+ }
+
+ if (overlay) {
+ using_shm = 0;
+ if (flash_cmap && ! quiet) {
+ rfbLog("warning: -flashcmap may be "
+ "incompatible with -overlay\n");
+ }
+ if (show_cursor && overlay_cursor) {
+ char *s = multiple_cursors_mode;
+ if (*s == 'X' || !strcmp(s, "some") ||
+ !strcmp(s, "arrow")) {
+ /*
+ * 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;
+ }
+ }
}
+ initialize_cursors_mode();
+
/* check for XTEST */
if (! XTestQueryExtension_wr(dpy, &ev, &er, &maj, &min)) {
+ if (! quiet) {
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;
+ }
+ xtest_present = 0;
+ use_xwarppointer = 1;
}
/*
* Window managers will often grab the display during resize, etc.
@@ -9969,14 +14850,25 @@ int main(int argc, char* argv[]) {
*/
XTestGrabControl_wr(dpy, True);
+ /* check for OS with small shm limits */
+ if (using_shm && ! single_copytile) {
+ if (limit_shm()) {
+ single_copytile = 1;
+ }
+ }
+
+ single_copytile_orig = single_copytile;
+
/* check for MIT-SHM */
if (! nofb && ! XShmQueryExtension_wr(dpy)) {
+ xshm_present = 0;
if (! using_shm) {
if (! quiet) {
rfbLog("info: display does not support"
" XShm.\n");
}
} else {
+ if (! quiet) {
rfbLog("warning: XShm extension is not available.\n");
rfbLog("For best performance the X Display should be"
" local. (i.e.\n");
@@ -9985,46 +14877,16 @@ int main(int argc, char* argv[]) {
rfbLog("the same machine.)\n");
#ifdef LIBVNCSERVER_HAVE_XSHM
rfbLog("Restart with -noshm to override this.\n");
- exit(1);
+ }
+ exit(1);
#else
rfbLog("Switching to -noshm mode.\n");
- using_shm = 0;
+ }
+ using_shm = 0;
#endif
}
}
- if (overlay) {
- /*
- * ideally we'd like to not have to cook up the visual variables
- * but rather let it all come out of XReadScreen(), however
- * there is no way to get a default visual out of it, so we
- * pretend -visual TrueColor:NN was supplied with NN usually 24.
- */
-#ifdef SOLARIS
- char str[16];
- XImage *xi;
- Window twin = subwin ? subwin : rootwin;
-
- xi = XReadScreen(dpy, twin, 0, 0, 8, 8, False);
-
- sprintf(str, "TrueColor:%d", xi->depth);
- if (xi->depth != 24 && ! quiet) {
- fprintf(stderr, "warning XReadScreen() image has "
- "depth %d instead of 24.\n", xi->depth);
- }
- XDestroyImage(xi);
- if (visual_str != NULL && ! quiet) {
- fprintf(stderr, "warning: replacing '-visual %s' by "
- "'%s' for use with -overlay\n", visual_str, str);
- }
- visual_str = strdup(str);
-#endif
- }
-
- if (visual_str != NULL) {
- set_visual(visual_str);
- }
-
#ifdef LIBVNCSERVER_HAVE_XKEYBOARD
/* check for XKEYBOARD */
if (use_xkb) {
@@ -10033,163 +14895,51 @@ int main(int argc, char* argv[]) {
initialize_watch_bell();
if (!use_xkb && use_xkb_modtweak) {
if (! quiet) {
- fprintf(stderr, "warning: disabling xkb modtweak."
+ rfbLog("warning: disabling xkb modtweak."
" XKEYBOARD ext. not present.\n");
}
use_xkb_modtweak = 0;
}
#endif
- /* set up parameters for subwin or non-subwin cases: */
- if (! subwin) {
- window = rootwin;
- dpy_x = DisplayWidth(dpy, scr);
- dpy_y = DisplayHeight(dpy, scr);
- off_x = 0;
- off_y = 0;
- /* this may be overridden via visual_id below */
- default_visual = DefaultVisual(dpy, scr);
- } else {
- /* experiment to share just one window */
- XWindowAttributes attr;
-
- window = (Window) subwin;
- if ( ! XGetWindowAttributes(dpy, window, &attr) ) {
- fprintf(stderr, "bad window: 0x%lx\n", window);
- exit(1);
+#ifdef LIBVNCSERVER_HAVE_LIBXRANDR
+ if (! XRRQueryExtension(dpy, &xrandr_base_event_type, &er)) {
+ if (xrandr && ! quiet) {
+ rfbLog("disabling -xrandr mode: display does not"
+ " support it.\n");
}
- dpy_x = attr.width;
- dpy_y = attr.height;
-
- /* this may be overridden via visual_id below */
- default_visual = attr.visual;
-
- if (show_multiple_cursors) {
- show_multiple_cursors = 0;
- if (! quiet) {
- fprintf(stderr, "disabling root cursor drawing"
- " for subwindow\n");
- }
- }
- set_offset();
- }
-
- /* initialize depth to reasonable value, visual_id may override */
- depth = DefaultDepth(dpy, scr);
-
- if (visual_id) {
- int n;
- XVisualInfo vinfo_tmpl, *vinfo;
-
- /*
- * we are in here from -visual or -overlay options
- * visual_id and visual_depth were set in set_visual().
- */
-
- vinfo_tmpl.visualid = visual_id;
- vinfo = XGetVisualInfo(dpy, VisualIDMask, &vinfo_tmpl, &n);
- if (vinfo == NULL || n == 0) {
- fprintf(stderr, "could not match visual_id: 0x%x\n",
- (int) visual_id);
- exit(1);
- }
- default_visual = vinfo->visual;
- depth = vinfo->depth;
- if (visual_depth) {
- /* force it from -visual FooColor:NN */
- depth = visual_depth;
- }
- if (! quiet) {
- fprintf(stderr, "vis id: 0x%x\n",
- (int) vinfo->visualid);
- fprintf(stderr, "vis scr: %d\n", vinfo->screen);
- fprintf(stderr, "vis depth %d\n", vinfo->depth);
- fprintf(stderr, "vis class %d\n", vinfo->class);
- fprintf(stderr, "vis rmask 0x%lx\n", vinfo->red_mask);
- fprintf(stderr, "vis gmask 0x%lx\n", vinfo->green_mask);
- fprintf(stderr, "vis bmask 0x%lx\n", vinfo->blue_mask);
- fprintf(stderr, "vis cmap_sz %d\n", vinfo->colormap_size);
- fprintf(stderr, "vis b/rgb %d\n", vinfo->bits_per_rgb);
- }
-
- XFree(vinfo);
- }
-
- if (! quiet) {
- rfbLog("default visual ID: 0x%x\n",
- (int) XVisualIDFromVisual(default_visual));
+ xrandr = 0;
+ xrandr_present = 0;
+ } else {
+ xrandr_present = 1;
}
+#endif
- if (nofb) {
- /*
- * For -nofb we do not allocate the framebuffer, so we
- * can save a few MB of memory.
- */
- fb = XCreateImage_wr(dpy, default_visual, depth, ZPixmap,
- 0, NULL, dpy_x, dpy_y, BitmapPad(dpy), 0);
+ /*
+ * Create the XImage corresponding to the display framebuffer.
+ */
- } else if (visual_id) {
- /*
- * we need to call XCreateImage to supply the visual
- */
- fb = XCreateImage_wr(dpy, default_visual, depth, ZPixmap,
- 0, NULL, dpy_x, dpy_y, BitmapPad(dpy), 0);
- fb->data = (char *) malloc(fb->bytes_per_line * fb->height);
- } else {
- fb = XGetImage_wr(dpy, window, 0, 0, dpy_x, dpy_y, AllPlanes,
- ZPixmap);
- if (! quiet) {
- rfbLog("Read initial data from X display into"
- " framebuffer.\n");
- }
- }
- if (fb->bits_per_pixel == 24 && ! quiet) {
- fprintf(stderr, "warning: 24 bpp may have poor"
- " performance.\n");
- }
+ fb0 = initialize_xdisplay_fb();
/*
* n.b. we do not have to X_LOCK any X11 calls until watch_loop()
* is called since we are single-threaded until then.
*/
- initialize_screen(&argc_vnc, argv_vnc, fb);
+ initialize_screen(&argc_vnc, argv_vnc, fb0);
initialize_tiles();
/* rectangular blackout regions */
- if (blackout_string != NULL) {
- initialize_blackout(blackout_string);
- }
- if (xinerama) {
- initialize_xinerama();
- }
- if (blackouts) {
- blackout_tiles();
- }
+ initialize_blackouts_and_xinerama();
- initialize_shm(); /* also creates XImages when using_shm = 0 */
+ /* created shm or XImages when using_shm = 0 */
+ initialize_polling_images();
initialize_signals();
- if (blackouts) { /* blackout fb as needed. */
- copy_screen();
- }
-
- if (use_modifier_tweak) {
- initialize_modtweak();
- }
- if (remap_file != NULL) {
- initialize_remap(remap_file);
- }
-
- initialize_pointer_map(pointer_remap);
-
- clear_modifiers(1);
- if (clear_mods == 1) {
- clear_modifiers(0);
- }
+ initialize_keyboard_and_pointer();
if (! inetd) {
if (! screen->port || screen->listenSock < 0) {
@@ -10200,6 +14950,7 @@ int main(int argc, char* argv[]) {
if (! quiet) {
rfbLog("screen setup finished.\n");
}
+ sprintf(vnc_desktop_name, "unknown");
if (screen->port) {
char *host = this_host();
int lport = screen->port;
@@ -10209,22 +14960,31 @@ int main(int argc, char* argv[]) {
; /* should not occur (port) */
} else if (quiet) {
if (lport >= 5900) {
+ sprintf(vnc_desktop_name, "%s:%d",
+ host, lport - 5900);
fprintf(stderr, "The VNC desktop is "
- "%s:%d\n", host, lport - 5900);
+ "%s\n", vnc_desktop_name);
} else {
+ sprintf(vnc_desktop_name, "%s:%d",
+ host, lport);
fprintf(stderr, "The VNC desktop is "
- "%s:%d\n", host, lport);
+ "%s\n", vnc_desktop_name);
}
} else if (lport >= 5900) {
- rfbLog("The VNC desktop is %s:%d\n", host,
- lport - 5900);
+ sprintf(vnc_desktop_name, "%s:%d",
+ host, lport - 5900);
+ rfbLog("\n");
+ rfbLog("The VNC desktop is %s\n",
+ vnc_desktop_name);
if (lport >= 6000) {
rfbLog("possible aliases: %s:%d, "
"%s::%d\n", host, lport, host, lport);
}
} else {
- rfbLog("The VNC desktop is %s:%d\n", host,
- lport);
+ sprintf(vnc_desktop_name, "%s:%d", host, lport);
+ rfbLog("\n");
+ rfbLog("The VNC desktop is %s\n",
+ vnc_desktop_name);
rfbLog("possible alias: %s::%d\n",
host, lport);
}