x11vnc: -appshare mode for sharing an application windows instead of the

entire desktop. map port + 5500 in reverse connect.  Add id_cmd remote
control functions for id (and other) windows.  Allow zero port in SSL
reverse connections.  Adjust delays between multiple reverse connections;
X11VNC_REVERSE_SLEEP_MAX env var.  Add some missing mutex locks; add
INPUT_LOCK and threads_drop_input.  More safety in -threads mode for
new framebuffer change.  Fix some stderr leaking in -inetd mode.
pull/1/head
runge 15 years ago
parent f40b011182
commit 00a9a0ea4d

@ -1,3 +1,13 @@
2009-12-02 Karl Runge <runge@karlrunge.com>
* x11vnc: -appshare mode for sharing an application windows intead
of the entire desktop. map port + 5500 in reverse connect.
Add id_cmd remote control functions for id (and other) windows.
Allow zero port in SSL reverse connections. Adjust delays
between multiple reverse connections; X11VNC_REVERSE_SLEEP_MAX
env var. Add some missing mutex locks; add INPUT_LOCK and
threads_drop_input. More safety in -threads mode for new
framebuffer change. Fix some stderr leaking in -inetd mode.
2009-11-18 Karl Runge <runge@karlrunge.com>
* x11vnc: use -timeout setting for reverse connections too.
Delay calling xfixes at the beginning of 1st connection to avoid

@ -23,7 +23,7 @@ LD_CYGIPC=-lcygipc
endif
bin_PROGRAMS=x11vnc
x11vnc_SOURCES = 8to24.c avahi.c cleanup.c connections.c cursor.c gui.c help.c inet.c keyboard.c linuxfb.c macosx.c macosxCG.c macosxCGP.c macosxCGS.c options.c pm.c pointer.c rates.c remote.c scan.c screen.c selection.c solid.c sslcmds.c sslhelper.c uinput.c unixpw.c user.c userinput.c util.c v4l.c win_utils.c x11vnc.c x11vnc_defs.c xdamage.c xevents.c xinerama.c xkb_bell.c xrandr.c xrecord.c xwrappers.c 8to24.h allowed_input_t.h avahi.h blackout_t.h cleanup.h connections.h cursor.h enc.h enums.h gui.h help.h inet.h keyboard.h linuxfb.h macosx.h macosxCG.h macosxCGP.h macosxCGS.h nox11.h nox11_funcs.h options.h params.h pm.h pointer.h rates.h remote.h scan.h screen.h scrollevent_t.h selection.h solid.h sslcmds.h sslhelper.h ssltools.h tkx11vnc.h uinput.h unixpw.h user.h userinput.h util.h v4l.h win_utils.h winattr_t.h x11vnc.h xdamage.h xevents.h xinerama.h xkb_bell.h xrandr.h xrecord.h xwrappers.h
x11vnc_SOURCES = 8to24.c appshare.c avahi.c cleanup.c connections.c cursor.c gui.c help.c inet.c keyboard.c linuxfb.c macosx.c macosxCG.c macosxCGP.c macosxCGS.c options.c pm.c pointer.c rates.c remote.c scan.c screen.c selection.c solid.c sslcmds.c sslhelper.c uinput.c unixpw.c user.c userinput.c util.c v4l.c win_utils.c x11vnc.c x11vnc_defs.c xdamage.c xevents.c xinerama.c xkb_bell.c xrandr.c xrecord.c xwrappers.c 8to24.h allowed_input_t.h avahi.h blackout_t.h cleanup.h connections.h cursor.h enc.h enums.h gui.h help.h inet.h keyboard.h linuxfb.h macosx.h macosxCG.h macosxCGP.h macosxCGS.h nox11.h nox11_funcs.h options.h params.h pm.h pointer.h rates.h remote.h scan.h screen.h scrollevent_t.h selection.h solid.h sslcmds.h sslhelper.h ssltools.h tkx11vnc.h uinput.h unixpw.h user.h userinput.h util.h v4l.h win_utils.h winattr_t.h x11vnc.h xdamage.h xevents.h xinerama.h xkb_bell.h xrandr.h xrecord.h xwrappers.h
if HAVE_SYSTEM_LIBVNCSERVER
INCLUDES_LIBVNCSERVER = @SYSTEM_LIBVNCSERVER_CFLAGS@

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -53,6 +53,7 @@ so, delete this exception statement from your version.
#include "macosxCG.h"
#include "userinput.h"
#include "pointer.h"
#include "xrandr.h"
/*
* routines for handling incoming, outgoing, etc connections
@ -257,10 +258,10 @@ static rfbClientPtr *client_match(char *str) {
i = 0;
iter = rfbGetClientIterator(screen);
while( (cl = rfbClientIteratorNext(iter)) ) {
ClientData *cd = (ClientData *) cl->clientData;
if (strstr(str, "0x") == str) {
unsigned int in;
int id;
ClientData *cd = (ClientData *) cl->clientData;
if (! cd) {
continue;
}
@ -277,25 +278,52 @@ static rfbClientPtr *client_match(char *str) {
cl_list[i++] = cl;
}
} else {
char *rstr = str;
int port = -1;
char *rstr = strdup(str);
char *q = strrchr(rstr, ':');
if (q) {
port = atoi(q+1);
*q = '\0';
if (port == 0 && q[1] != '0') {
port = -1;
} else if (port < 0) {
port = -port;
} else if (port < 200) {
port = 5500 + port;
}
}
if (! dotted_ip(str)) {
rstr = host2ip(str);
char *orig = rstr;
rstr = host2ip(rstr);
free(orig);
if (rstr == NULL || *rstr == '\0') {
if (host_warn++) {
continue;
}
rfbLog("skipping bad lookup: \"%s\"\n",
str);
rfbLog("skipping bad lookup: \"%s\"\n", str);
continue;
}
rfbLog("lookup: %s -> %s\n", str, rstr);
rfbLog("lookup: %s -> %s port=%d\n", str, rstr, port);
}
if (!strcmp(rstr, cl->host)) {
cl_list[i++] = cl;
}
if (rstr != str) {
free(rstr);
int ok = 1;
if (port > 0) {
if (cd != NULL && cd->client_port > 0) {
if (cd->client_port != port) {
ok = 0;
}
} else {
int cport = get_remote_port(cl->sock);
if (cport != port) {
ok = 0;
}
}
}
if (ok) {
cl_list[i++] = cl;
}
}
free(rstr);
}
if (i >= n - 1) {
break;
@ -766,6 +794,7 @@ void client_gone(rfbClientPtr client) {
if (unixpw_in_progress && unixpw_client) {
if (client == unixpw_client) {
unixpw_in_progress = 0;
/* mutex */
screen->permitFileTransfer = unixpw_file_xfer_save;
if ((tightfilexfer = unixpw_tightvnc_xfer_save)) {
#ifdef LIBVNCSERVER_WITH_TIGHTVNC_FILETRANSFER
@ -1670,14 +1699,20 @@ static void check_connect_file(char *file) {
FILE *in;
char line[VNC_CONNECT_MAX], host[VNC_CONNECT_MAX];
static int first_warn = 1, truncate_ok = 1;
static time_t last_time = 0;
time_t now = time(NULL);
if (last_time == 0) {
last_time = now;
static double last_time = 0.0, delay = 0.5;
double now = dnow();
struct stat sbuf;
if (last_time == 0.0) {
if (!getenv("X11VNC_APPSHARE_ACTIVE")) {
/* skip first */
last_time = now;
} else {
delay = 0.25;
}
}
if (now - last_time < 1) {
/* check only once a second */
if (now - last_time < delay) {
/* check only about once a second */
return;
}
last_time = now;
@ -1691,6 +1726,13 @@ static void check_connect_file(char *file) {
}
}
if (stat(file, &sbuf) == 0) {
/* skip empty file directly */
if (sbuf.st_size == 0) {
return;
}
}
in = fopen(file, "r");
if (in == NULL) {
if (first_warn) {
@ -2567,6 +2609,12 @@ void reverse_connect(char *str) {
int nclients0 = client_count;
int lcnt, j;
char **list;
int do_appshare = 0;
if (!getenv("X11VNC_REVERSE_USE_OLD_SLEEP")) {
sleep_min = 500;
sleep_max = 2500;
}
if (unixpw_in_progress) return;
@ -2582,19 +2630,56 @@ void reverse_connect(char *str) {
}
free(tmp);
if (subwin && getenv("X11VNC_APPSHARE_ACTIVE")) {
do_appshare = 1;
sleep_between_host = 0; /* too agressive??? */
}
if (getenv("X11VNC_REVERSE_SLEEP_BETWEEN_HOST")) {
sleep_between_host = atoi(getenv("X11VNC_REVERSE_SLEEP_BETWEEN_HOST"));
}
if (do_appshare) {
if (screen && dpy) {
char *s = choose_title(DisplayString(dpy));
/* mutex */
screen->desktopName = s;
if (rfb_desktop_name) {
free(rfb_desktop_name);
}
rfb_desktop_name = strdup(s);
}
}
for (j = 0; j < lcnt; j++) {
p = list[j];
if ((n = do_reverse_connect(p)) != 0) {
int i;
progress_client();
rfbPE(-1);
for (i=0; i < 3; i++) {
rfbPE(-1);
}
}
cnt += n;
if (list[j+1] != NULL) {
t = 0;
while (t < sleep_between_host) {
double t1, t2;
int i;
t1 = dnow();
for (i=0; i < 8; i++) {
rfbPE(-1);
if (do_appshare && t == 0) {
rfbPE(-1);
}
}
t2 = dnow();
t += (int) (1000 * (t2 - t1));
if (t >= sleep_between_host) {
break;
}
usleep(dt * 1000);
rfbPE(-1);
t += dt;
}
}
@ -2616,6 +2701,9 @@ void reverse_connect(char *str) {
}
clean_up_exit(0);
}
if (xrandr || xrandr_maybe) {
check_xrandr_event("reverse_connect1");
}
return;
}
@ -2623,6 +2711,8 @@ void reverse_connect(char *str) {
* XXX: we need to process some of the initial handshaking
* events, otherwise the client can get messed up (why??)
* so we send rfbProcessEvents() all over the place.
*
* How much is this still needed?
*/
n = cnt;
@ -2632,17 +2722,42 @@ void reverse_connect(char *str) {
t = sleep_max - sleep_min;
tot = sleep_min + ((n-1) * t) / (n_max-1);
if (do_appshare) {
tot /= 3;
if (tot < dt) {
tot = dt;
}
tot = 0; /* too agressive??? */
}
if (getenv("X11VNC_REVERSE_SLEEP_MAX")) {
tot = atoi(getenv("X11VNC_REVERSE_SLEEP_MAX"));
}
t = 0;
while (t < tot) {
rfbPE(-1);
rfbPE(-1);
int i;
double t1, t2;
t1 = dnow();
for (i=0; i < 8; i++) {
rfbPE(-1);
if (t == 0) rfbPE(-1);
}
t2 = dnow();
t += (int) (1000 * (t2 - t1));
if (t >= tot) {
break;
}
usleep(dt * 1000);
t += dt;
}
if (connect_or_exit) {
if (client_count <= nclients0) {
for (t = 0; t < 10; t++) {
rfbPE(-1);
int i;
for (i=0; i < 3; i++) {
rfbPE(-1);
}
usleep(100 * 1000);
}
}
@ -2656,6 +2771,9 @@ void reverse_connect(char *str) {
clean_up_exit(0);
}
}
if (xrandr || xrandr_maybe) {
check_xrandr_event("reverse_connect2");
}
}
/*
@ -2857,7 +2975,9 @@ static void pmove(int x, int y) {
}
rfbLog("pmove: x y: %d %d\n", x, y);
pointer(0, x, y, NULL);
X_LOCK;
XFlush_wr(dpy);
X_UNLOCK;
}
@ -3472,6 +3592,7 @@ static void turn_off_truecolor_ad(rfbClientPtr client) {
if (client) {}
if (turn_off_truecolor) {
rfbLog("turning off truecolor advertising.\n");
/* mutex */
screen->serverFormat.trueColour = FALSE;
screen->displayHook = NULL;
screen->serverFormat.redShift = 0;
@ -3639,6 +3760,7 @@ enum rfbNewClientAction new_client(rfbClientPtr client) {
}
} else if (strstr(passwdfile, "custom:") == passwdfile) {
if (screen) {
/* mutex */
screen->passwordCheck = custom_passwd_check;
}
}
@ -3683,8 +3805,9 @@ enum rfbNewClientAction new_client(rfbClientPtr client) {
cd->cmp_bytes_sent = 0;
cd->raw_bytes_sent = 0;
rfbLog("incr accepted_client for %s:%d sock=%d\n", client->host, get_remote_port(client->sock), client->sock);
accepted_client++;
rfbLog("incr accepted_client=%d for %s:%d sock=%d\n", accepted_client,
client->host, get_remote_port(client->sock), client->sock);
last_client = time(NULL);
if (ncache) {
@ -3720,6 +3843,7 @@ enum rfbNewClientAction new_client(rfbClientPtr client) {
rfbSetTranslateFunction(client);
/* mutex */
screen->serverFormat.trueColour = TRUE;
screen->serverFormat.redShift = rs;
screen->serverFormat.greenShift = gs;

@ -576,7 +576,9 @@ void first_cursor(void) {
return;
}
if (! show_cursor) {
LOCK(screen->cursorMutex);
screen->cursor = NULL;
UNLOCK(screen->cursorMutex);
} else {
got_xfixes_cursor_notify++;
set_rfb_cursor(get_which_cursor());
@ -591,7 +593,7 @@ static void setup_cursors(void) {
int w_in = 0, h_in = 0;
static int first = 1;
if (verbose) {
if (verbose || use_threads) {
rfbLog("setting up %d cursors...\n", CURS_MAX);
}
@ -603,8 +605,8 @@ static void setup_cursors(void) {
first = 0;
if (screen) {
screen->cursor = NULL;
LOCK(screen->cursorMutex);
screen->cursor = NULL;
}
for (i=0; i<CURS_MAX; i++) {
@ -985,7 +987,6 @@ static void tree_descend_cursor(int *depth, Window *w, win_str_info_t *winfo) {
void initialize_xfixes(void) {
#if LIBVNCSERVER_HAVE_LIBXFIXES
if (xfixes_present) {
xfixes_first_initialized = 1;
X_LOCK;
if (use_xfixes) {
XFixesSelectCursorInput(dpy, rootwin,
@ -994,6 +995,7 @@ void initialize_xfixes(void) {
XFixesSelectCursorInput(dpy, rootwin, 0);
}
X_UNLOCK;
xfixes_first_initialized = 1;
}
#endif
}
@ -1325,24 +1327,23 @@ static int get_exact_cursor(int init) {
return which;
}
X_LOCK;
if (! got_xfixes_cursor_notify && xfixes_base_event_type) {
/* 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 */
X_UNLOCK;
return which;
}
got_xfixes_cursor_notify = 0;
/* retrieve the cursor info + pixels from server: */
X_LOCK;
xfc = XFixesGetCursorImage(dpy);
X_UNLOCK;
if (! xfc) {
@ -1512,7 +1513,9 @@ void initialize_cursors_mode(void) {
}
} else {
if (screen) {
LOCK(screen->cursorMutex);
screen->cursor = NULL;
UNLOCK(screen->cursorMutex);
set_cursor_was_changed(screen);
}
}
@ -1656,9 +1659,11 @@ static void set_cursor_was_changed(rfbScreenInfoPtr s) {
return;
}
iter = rfbGetClientIterator(s);
LOCK(screen->cursorMutex);
while( (cl = rfbClientIteratorNext(iter)) ) {
cl->cursorWasChanged = TRUE;
}
UNLOCK(screen->cursorMutex);
rfbReleaseClientIterator(iter);
}

@ -176,6 +176,21 @@ void print_help(int mode) {
" 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"
"\n"
"-appshare Simple application sharing based on the -id/-sid\n"
" mechanism. Every new toplevel window that the\n"
" application creates induces a new viewer window via\n"
" a reverse connection. The -id/-sid and -connect\n"
" options are required. Run 'x11vnc -appshare -help'\n"
" for more info.\n"
"\n"
#if 0
"-freeze_when_obscured Probably only of use in -appshare mode: if the -id/-sid\n"
" window is partially or fully obscured by other windows,\n"
" stop checking for framebuffer updates. Mouse and\n"
" keyboard events are still processed and injected.\n"
"\n"
#endif
"-clip WxH+X+Y Only show the sub-region of the full display that\n"
" corresponds to the rectangle geometry with size WxH and\n"
" offset +X+Y. The VNC display has size WxH (i.e. smaller\n"
@ -2779,7 +2794,7 @@ void print_help(int mode) {
" \"debug crash shell\" when fatal errors are trapped.\n"
"\n"
"-q, -quiet Be quiet by printing less informational output to\n"
" stderr.\n"
" stderr. (use -noquiet to undo an earlier -quiet.)\n"
"-v, -verbose Print out more information to stderr.\n"
"\n"
"-bg Go into the background after screen setup. Messages to\n"
@ -3175,7 +3190,7 @@ void print_help(int mode) {
" (an integer) times that of the full display is allocated\n"
" below the actual framebuffer to cache screen contents\n"
" for rapid retrieval. So a W x H frambuffer is expanded\n"
" to a W x (n+1)*H one. Use 0 to disable. Default: XXX.\n"
" to a W x (n+1)*H one. Use 0 to disable.\n"
"\n"
" The \"n\" is actually optional, the default is 10.\n"
"\n"
@ -3183,13 +3198,17 @@ void print_help(int mode) {
" abbreviate \"-ncache\" with \"-nc\". Also, \"-nonc\"\n"
" is the same as \"-ncache 0\"\n"
"\n"
" This is an experimental option, currently implemented\n"
" in an awkward way in that in the VNC Viewer you can\n"
" see the cache contents if you scroll down, etc. So you\n"
" This is an experimental option, currently implemented in\n"
" an awkward way in that in the VNC Viewer you can see the\n"
" pixel cache contents if you scroll down, etc. So you\n"
" will have to set things up so you can't see that region.\n"
" If this method is successful, the changes required for\n"
" clients to do this less awkwardly will be investigated.\n"
"\n"
" The SSVNC viewer does a good job at automatically hiding\n"
" the pixel cache region. Or use SSVNC's -ycrop option\n"
" to explicitly hide the region.\n"
"\n"
" Note that this mode consumes a huge amount of memory,\n"
" both on the x11vnc server side and on the VNC Viewer\n"
" side. If n=2 then the amount of RAM used is roughly\n"
@ -3896,10 +3915,7 @@ void print_help(int mode) {
" for output) are created to handle each new client.\n"
" Default: %s.\n"
"\n"
" NOTE: The -threads mode may be disabled due to its\n"
" unstable behavior. If it is disabled, a warning is\n"
" printed out. Stability has been improved in version\n"
" 0.9.8 and so the feature has been re-enabled.\n"
" Thread stability is much improved in version 0.9.8.\n"
"\n"
" Multiple clients in threaded mode should be stable\n"
" for the ZRLE encoding on all platforms. The Tight and\n"
@ -3907,9 +3923,14 @@ void print_help(int mode) {
" multiple clients. Compile with -DTLS=__thread if your\n"
" OS and compiler and linker support it.\n"
"\n"
" For resizes (randr, etc.) set this env. var. to the number\n"
" of milliseconds to sleep: X11VNC_THREADS_NEW_FB_SLEEP\n"
" at various places in the do_new_fb() action. This is to\n"
" let various activities settle. Default is about 500ms.\n"
"\n"
" Multiple clients in threaded mode could yield better\n"
" performance for 'class-room' broadcasting usage.\n"
" See also the -reflect option.\n"
" performance for 'class-room' broadcasting usage; also in\n"
" -appshare broadcast mode. See also the -reflect option.\n"
"\n"
"-fs f If the fraction of changed tiles in a poll is greater\n"
" than f, the whole screen is updated. Default: %.2f\n"
@ -4599,6 +4620,12 @@ void print_help(int mode) {
" 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"
" id_cmd:cmd cmds: raise, lower, map, unmap, iconify,\n"
" move:dXdY, resize:dWdH, geom:WxH+X+Y. dX\n"
" dY, dW, and dH must have a leading \"+\"\n"
" or \"-\" e.g.: move:-30+10 resize:+20+35\n"
" also: wm_delete, wm_name:string and\n"
" icon_name:string. Also id_cmd:win=N:cmd\n"
" waitmapped wait until subwin is mapped.\n"
" nowaitmapped do not wait until subwin is mapped.\n"
" clip:WxH+X+Y set -clip mode to \"WxH+X+Y\"\n"
@ -5081,8 +5108,8 @@ void print_help(int mode) {
" file use \"qry=...\" instead of \"cmd=...\"\n"
"\n"
" ans= stop quit exit shutdown ping resend_cutbuffer\n"
" resend_clipboard resend_primary blacken zero\n"
" refresh reset close disconnect id sid waitmapped\n"
" resend_clipboard resend_primary blacken zero refresh\n"
" reset close disconnect id_cmd id sid waitmapped\n"
" nowaitmapped clip flashcmap noflashcmap shiftcmap\n"
" truecolor notruecolor overlay nooverlay overlay_cursor\n"
" overlay_yescursor nooverlay_nocursor nooverlay_cursor\n"
@ -5224,6 +5251,10 @@ void print_help(int mode) {
" The returned output is also prefixed with \"str\".\n"
" Example: -remote_prefix DO_THIS:\n"
"\n"
" Note that enabling -remote_prefix allows the remote\n"
" VNC viewers to run x11vnc -remote commands. Do not\n"
" use this option if they are not to be trusted.\n"
"\n"
"-noremote Do not process any remote control commands or queries.\n"
"-yesremote Do process remote control commands or queries.\n"
" Default: %s\n"

@ -3056,6 +3056,10 @@ void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) {
static double max_keyrepeat_last_time = 0.0;
static double max_keyrepeat_always = -1.0;
if (threads_drop_input) {
return;
}
dtime0(&tnow);
got_keyboard_calls++;
@ -3125,6 +3129,8 @@ void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) {
}
}
INPUT_LOCK;
last_down = down;
last_keysym = keysym;
last_keyboard_time = tnow;
@ -3215,6 +3221,7 @@ void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) {
if (db) rfbLog("--- scroll keyrate skipping 0x%lx %s "
"%.4f %.4f\n", keysym, down ? "down":"up ",
tnow - x11vnc_start, tnow - max_keyrepeat_last_time);
INPUT_UNLOCK;
return;
}
}
@ -3237,6 +3244,7 @@ void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) {
tnow - x11vnc_start, tnow - max_keyrepeat_last_time);
max_keyrepeat_last_keysym = keysym;
skipped_last_down = 1;
INPUT_UNLOCK;
return;
} else {
if (db) rfbLog("--- scroll keyrate KEEPING 0x%lx %s "
@ -3267,15 +3275,18 @@ void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) {
got_user_input++;
got_keyboard_input++;
}
INPUT_UNLOCK;
return;
}
}
if (view_only) {
INPUT_UNLOCK;
return;
}
get_allowed_input(client, &input);
if (! input.keystroke) {
INPUT_UNLOCK;
return;
}
@ -3327,6 +3338,7 @@ void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) {
char *b, bstr[32];
if (! down) {
INPUT_UNLOCK;
return; /* nothing to send */
}
if (debug_keyboard) {
@ -3360,6 +3372,7 @@ void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) {
}
XFlush_wr(dpy);
X_UNLOCK;
INPUT_UNLOCK;
return;
}
@ -3368,6 +3381,7 @@ void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) {
X_LOCK;
XFlush_wr(dpy);
X_UNLOCK;
INPUT_UNLOCK;
return;
}
@ -3394,6 +3408,7 @@ void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) {
}
X_UNLOCK;
INPUT_UNLOCK;
}

@ -206,6 +206,8 @@ int macosx_icon_anim_time = 450;
unsigned long subwin = 0x0; /* -id, -sid */
int subwin_wait_mapped = 0;
int freeze_when_obscured = 0;
int subwin_obscured = 0;
int debug_xevents = 0; /* -R debug_xevents:1 */
int debug_xdamage = 0; /* -R debug_xdamage:1 or 2 ... */
@ -472,6 +474,7 @@ int verbose = 0;
/* threaded vs. non-threaded (default) */
int use_threads = 0;
int started_rfbRunEventLoop = 0;
int threads_drop_input = 0;
/* info about command line opts */
int got_noxwarppointer = 0;

@ -178,6 +178,8 @@ extern int macosx_icon_anim_time;
extern unsigned long subwin;
extern int subwin_wait_mapped;
extern int freeze_when_obscured;
extern int subwin_obscured;
extern int debug_xevents;
extern int debug_xdamage;
@ -367,6 +369,7 @@ extern int verbose;
extern int use_threads;
extern int started_rfbRunEventLoop;
extern int threads_drop_input;
extern int got_noxwarppointer;
extern int got_rfbport;

@ -49,6 +49,16 @@ static void check_dpms(void);
#endif
void check_pm(void) {
static int skip = -1;
if (skip < 0) {
skip = 0;
if (getenv("X11VNC_NO_CHECK_PM")) {
skip = 1;
}
}
if (skip) {
return;
}
check_fbpm();
check_dpms();
/* someday dpms activities? */

@ -76,9 +76,6 @@ typedef struct ptrremap {
int up;
} prtremap_t;
#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
MUTEX(pointerMutex);
#endif
#define MAX_BUTTON_EVENTS 50
static prtremap_t pointer_map[MAX_BUTTONS+1][MAX_BUTTON_EVENTS];
@ -674,6 +671,10 @@ void pointer(int mask, int x, int y, rfbClientPtr client) {
int sent = 0, buffer_it = 0;
double now;
if (threads_drop_input) {
return;
}
if (mask >= 0) {
got_pointer_calls++;
}
@ -721,6 +722,8 @@ void pointer(int mask, int x, int y, rfbClientPtr client) {
y = nfix(y, dpy_y);
}
INPUT_LOCK;
if ((pipeinput_fh != NULL || pipeinput_int) && mask >= 0) {
pipe_pointer(mask, x, y, client); /* MACOSX here. */
if (! pipeinput_tee) {
@ -739,11 +742,13 @@ void pointer(int mask, int x, int y, rfbClientPtr client) {
if (!view_only && (input.motion || input.button)) {
last_rfb_ptr_injected = dnow();
}
INPUT_UNLOCK;
return;
}
}
if (view_only) {
INPUT_UNLOCK;
return;
}
@ -755,6 +760,7 @@ void pointer(int mask, int x, int y, rfbClientPtr client) {
* to flush the event queue; there is no real pointer event.
*/
if (! input.motion && ! input.button) {
INPUT_UNLOCK;
return;
}
@ -786,6 +792,7 @@ void pointer(int mask, int x, int y, rfbClientPtr client) {
blackr[b].x1, blackr[b].y1,
blackr[b].x2, blackr[b].y2);
}
INPUT_UNLOCK;
return;
}
}
@ -800,18 +807,12 @@ void pointer(int mask, int x, int y, rfbClientPtr client) {
if ((use_threads && pointer_mode != 1) || pointer_flush_delay > 0.0) {
# define NEV 32
/* storage for the event queue */
static int mutex_init = 0;
static int nevents = 0;
static int ev[NEV][3];
int i;
/* timer things */
static double dt = 0.0, tmr = 0.0, maxwait = 0.4;
if (! mutex_init) {
INIT_MUTEX(pointerMutex);
mutex_init = 1;
}
if (pointer_flush_delay > 0.0) {
maxwait = pointer_flush_delay;
}
@ -821,7 +822,7 @@ void pointer(int mask, int x, int y, rfbClientPtr client) {
}
}
LOCK(pointerMutex);
POINTER_LOCK;
/*
* If the framebuffer is being copied in another thread
@ -856,11 +857,12 @@ void pointer(int mask, int x, int y, rfbClientPtr client) {
ev[i][1] = -1;
ev[i][2] = -1;
}
UNLOCK(pointerMutex);
if (debug_pointer) {
rfbLog("pointer(): deferring event %d"
" %.4f\n", i, tmr - x11vnc_start);
}
POINTER_UNLOCK;
INPUT_UNLOCK;
return;
}
}
@ -912,13 +914,14 @@ void pointer(int mask, int x, int y, rfbClientPtr client) {
dt = 0.0;
dtime0(&tmr);
UNLOCK(pointerMutex);
POINTER_UNLOCK;
}
if (mask < 0) { /* -1 just means flush the event queue */
if (debug_pointer) {
rfbLog("pointer(): flush only. %.4f\n",
dnowx());
}
INPUT_UNLOCK;
return;
}
@ -955,6 +958,7 @@ void pointer(int mask, int x, int y, rfbClientPtr client) {
XFlush_wr(dpy);
X_UNLOCK;
}
INPUT_UNLOCK;
}
void initialize_pipeinput(void) {

@ -484,6 +484,7 @@ void http_connections(int on) {
if (screen->httpPort == 0) {
int port = find_free_port(5800, 5850);
if (port) {
/* mutex */
screen->httpPort = port;
}
}
@ -517,6 +518,7 @@ static void reset_httpport(int old, int new) {
rfbLog("reset_httpport: cannot set httpport: %d"
" in inetd.\n", hp);
} else if (screen) {
/* mutex */
screen->httpPort = hp;
screen->httpInitDone = FALSE;
if (screen->httpListenSock > -1) {
@ -544,6 +546,7 @@ static void reset_rfbport(int old, int new) {
rfbClientIteratorPtr iter;
rfbClientPtr cl;
int maxfd;
/* mutex */
if (rp == 0) {
screen->autoPort = TRUE;
} else {
@ -655,7 +658,9 @@ int remote_control_access_ok(void) {
}
}
X_LOCK;
xha = XListHosts(dpy, &n, &enabled);
X_UNLOCK;
if (! enabled) {
rfbLog("X access control is disabled, X clients can\n");
rfbLog(" connect from any host. Run 'xhost -'\n");
@ -1055,6 +1060,13 @@ char *process_remote_cmd(char *cmd, int stringonly) {
close_clients(p);
goto done;
}
if (strstr(p, "id_cmd") == p) {
NOTAPP
COLON_CHECK("id_cmd:")
p += strlen("id_cmd:");
id_cmd(p);
goto done;
}
if (strstr(p, "id") == p) {
int ok = 0;
Window twin;
@ -1465,6 +1477,7 @@ char *process_remote_cmd(char *cmd, int stringonly) {
rfbLog("remote_cmd: enable sharing.\n");
shared = 1;
if (screen) {
/* mutex */
screen->alwaysShared = TRUE;
screen->neverShared = FALSE;
}
@ -1477,6 +1490,7 @@ char *process_remote_cmd(char *cmd, int stringonly) {
rfbLog("remote_cmd: disable sharing.\n");
shared = 0;
if (screen) {
/* mutex */
screen->alwaysShared = FALSE;
screen->neverShared = TRUE;
}
@ -1562,6 +1576,7 @@ char *process_remote_cmd(char *cmd, int stringonly) {
}
if (! screen->permitFileTransfer) {
rfbLog("remote_cmd: enabling -ultrafilexfer for clients.\n");
/* mutex */
screen->permitFileTransfer = TRUE;
}
goto done;
@ -1577,6 +1592,7 @@ char *process_remote_cmd(char *cmd, int stringonly) {
}
if (screen->permitFileTransfer) {
rfbLog("remote_cmd: disabling -ultrafilexfer for clients.\n");
/* mutex */
screen->permitFileTransfer = FALSE;
}
goto done;
@ -1595,6 +1611,7 @@ char *process_remote_cmd(char *cmd, int stringonly) {
p += strlen("rfbversion:");
if (sscanf(p, "%d.%d", &maj, &min) == 2) {
/* mutex */
screen->protocolMajorVersion = maj;
screen->protocolMinorVersion = min;
rfbLog("remote_cmd: set rfbversion to: %d.%d\n", maj, min);
@ -1766,6 +1783,7 @@ char *process_remote_cmd(char *cmd, int stringonly) {
}
listen_str = strdup("localhost");
/* mutex */
screen->listenInterface = htonl(INADDR_LOOPBACK);
rfbLog("listening on loopback network only.\n");
rfbLog("allow list is: '%s'\n", NONUL(allow_list));
@ -1813,6 +1831,7 @@ char *process_remote_cmd(char *cmd, int stringonly) {
}
listen_str = NULL;
/* mutex */
screen->listenInterface = htonl(INADDR_ANY);
rfbLog("listening on ALL network interfaces.\n");
rfbLog("allow list is: '%s'\n", NONUL(allow_list));
@ -1853,6 +1872,7 @@ char *process_remote_cmd(char *cmd, int stringonly) {
}
ok = 1;
/* mutex */
if (listen_str == NULL || *listen_str == '\0' ||
!strcmp(listen_str, "any")) {
screen->listenInterface = htonl(INADDR_ANY);
@ -4134,6 +4154,7 @@ char *process_remote_cmd(char *cmd, int stringonly) {
}
#endif
} else {
X_LOCK;
if (down == -1) {
XTestFakeKeyEvent_wr(dpy, kc, 1, CurrentTime);
usleep(50*1000);
@ -4141,6 +4162,7 @@ char *process_remote_cmd(char *cmd, int stringonly) {
} else {
XTestFakeKeyEvent_wr(dpy, kc, down, CurrentTime);
}
X_UNLOCK;
}
goto done;
}
@ -4340,8 +4362,9 @@ char *process_remote_cmd(char *cmd, int stringonly) {
rfbLog("bcx_xattach: failed grab check for '%s': %s. Retrying[%d]...\n", p, res, try);
free(res);
pointer(0, dpy_x/2 + try, dpy_y/2 + try, NULL);
XFlush_wr(dpy);
#if !NO_X11
X_LOCK;
XFlush_wr(dpy);
if (dpy) {
if (try == 2) {
XSync(dpy, False);
@ -4349,6 +4372,7 @@ char *process_remote_cmd(char *cmd, int stringonly) {
XSync(dpy, True);
}
}
X_UNLOCK;
#endif
if (try == 1) {
usleep(250*1000);
@ -4382,6 +4406,7 @@ char *process_remote_cmd(char *cmd, int stringonly) {
if (d < 0) d = 0;
rfbLog("remote_cmd: setting defer to %d ms.\n", d);
defer_update = d;
/* mutex */
screen->deferUpdateTime = d;
got_defer = 1;
goto done;
@ -4403,6 +4428,7 @@ char *process_remote_cmd(char *cmd, int stringonly) {
if (d < 0) d = 0;
rfbLog("remote_cmd: setting defer to %d ms.\n", d);
defer_update = d;
/* mutex */
screen->deferUpdateTime = d;
got_defer = 1;
goto done;
@ -4907,6 +4933,7 @@ char *process_remote_cmd(char *cmd, int stringonly) {
if (f < 0) f = 0;
rfbLog("remote_cmd: setting progressive %d -> %d.\n",
screen->progressiveSliceHeight, f);
/* mutex */
screen->progressiveSliceHeight = f;
goto done;
}
@ -4995,6 +5022,7 @@ char *process_remote_cmd(char *cmd, int stringonly) {
goto qry;
}
rfbLog("turning on enablehttpproxy.\n");
/* mutex */
screen->httpEnableProxyConnect = 1;
goto done;
}
@ -5081,6 +5109,7 @@ char *process_remote_cmd(char *cmd, int stringonly) {
free(rfb_desktop_name);
}
rfb_desktop_name = strdup(p);
/* mutex */
screen->desktopName = rfb_desktop_name;
rfbLog("remote_cmd: setting desktop name to %s\n",
rfb_desktop_name);
@ -5449,6 +5478,7 @@ char *process_remote_cmd(char *cmd, int stringonly) {
passwds_new[0] = strdup(p);
/* mutex */
if (screen->authPasswdData &&
screen->passwordCheck == rfbCheckPasswordByList) {
passwds_new[1] = passwds_old[1];
@ -5984,8 +6014,10 @@ char *process_remote_cmd(char *cmd, int stringonly) {
}
} else {
if (dpy) { /* raw_fb hack */
X_LOCK;
set_x11vnc_remote_prop(buf);
XFlush_wr(dpy);
X_UNLOCK;
}
}
#endif /* REMOTE_CONTROL */

@ -125,6 +125,7 @@ void set_greyscale_colormap(void) {
if (! screen) {
return;
}
/* mutex */
if (screen->colourMap.data.shorts) {
free(screen->colourMap.data.shorts);
screen->colourMap.data.shorts = NULL;
@ -154,6 +155,7 @@ void set_hi240_colormap(void) {
if (! screen) {
return;
}
/* mutex */
if (0) fprintf(stderr, "set_hi240_colormap: %s\n", raw_fb_pixfmt);
if (screen->colourMap.data.shorts) {
free(screen->colourMap.data.shorts);
@ -211,6 +213,7 @@ void set_colormap(int reset) {
if (reset) {
init = 1;
ncolor = 0;
/* mutex */
if (screen->colourMap.data.shorts) {
free(screen->colourMap.data.shorts);
screen->colourMap.data.shorts = NULL;
@ -233,6 +236,7 @@ void set_colormap(int reset) {
} else {
ncolor = NCOLOR;
}
/* mutex */
screen->colourMap.count = ncolor;
screen->serverFormat.trueColour = FALSE;
screen->colourMap.is16 = TRUE;
@ -777,6 +781,7 @@ static void nofb_hook(rfbClientPtr cl) {
}
main_fb = fb->data;
rfb_fb = main_fb;
/* mutex */
screen->frameBuffer = rfb_fb;
screen->displayHook = NULL;
}
@ -813,13 +818,214 @@ void free_old_fb(void) {
}
}
static char _lcs_tmp[128];
static int _bytes0_size = 128, _bytes0[128];
static char *lcs(rfbClientPtr cl) {
sprintf(_lcs_tmp, "%d/%d/%d/%d/%d-%d/%d/%d",
!!(cl->newFBSizePending),
!!(cl->cursorWasChanged),
!!(cl->cursorWasMoved),
!!(cl->reverseConnection),
cl->state,
cl->modifiedRegion ? !!(sraRgnEmpty(cl->modifiedRegion)) : 2,
cl->requestedRegion ? !!(sraRgnEmpty(cl->requestedRegion)) : 2,
cl->copyRegion ? !!(sraRgnEmpty(cl->copyRegion)) : 2
);
return _lcs_tmp;
}
static int lock_client_sends(int lock) {
static rfbClientPtr *cls = NULL;
static int cls_len = 0;
static int blocked = 0;
static int state = 0;
rfbClientIteratorPtr iter;
rfbClientPtr cl;
char *s;
if (!use_threads || !screen) {
return 0;
}
if (lock < 0) {
return state;
}
state = lock;
if (lock) {
if (cls_len < client_count + 128) {
if (cls != NULL) {
free(cls);
}
cls_len = client_count + 256;
cls = (rfbClientPtr *) calloc(cls_len * sizeof(rfbClientPtr), 1);
}
iter = rfbGetClientIterator(screen);
blocked = 0;
while ((cl = rfbClientIteratorNext(iter)) != NULL) {
s = lcs(cl);
SEND_LOCK(cl);
rfbLog("locked client: %p %.6f %s\n", cl, dnowx(), s);
cls[blocked++] = cl;
}
rfbReleaseClientIterator(iter);
} else {
int i;
for (i=0; i < blocked; i++) {
cl = cls[i];
if (cl != NULL) {
s = lcs(cl);
SEND_UNLOCK(cl)
rfbLog("unlocked client: %p %.6f %s\n", cl, dnowx(), s);
}
cls[i] = NULL;
}
blocked = 0;
}
return state;
}
static void settle_clients(int init) {
rfbClientIteratorPtr iter;
rfbClientPtr cl;
int fb_pend, i, ms = 1000;
char *s;
if (!use_threads || !screen) {
return;
}
if (init) {
iter = rfbGetClientIterator(screen);
i = 0;
while ((cl = rfbClientIteratorNext(iter)) != NULL) {
if (i < _bytes0_size) {
_bytes0[i] = rfbStatGetSentBytesIfRaw(cl);
}
i++;
}
rfbReleaseClientIterator(iter);
if (getenv("X11VNC_THREADS_NEW_FB_SLEEP")) {
ms = atoi(getenv("X11VNC_THREADS_NEW_FB_SLEEP"));
} else if (subwin) {
ms = 250;
} else {
ms = 500;
}
usleep(ms * 1000);
return;
}
if (getenv("X11VNC_THREADS_NEW_FB_SLEEP")) {
ms = atoi(getenv("X11VNC_THREADS_NEW_FB_SLEEP"));
} else if (subwin) {
ms = 500;
} else {
ms = 1000;
}
usleep(ms * 1000);
for (i=0; i < 5; i++) {
fb_pend = 0;
iter = rfbGetClientIterator(screen);
while ((cl = rfbClientIteratorNext(iter)) != NULL) {
s = lcs(cl);
if (cl->newFBSizePending) {
fb_pend++;
rfbLog("pending fb size: %p %.6f %s\n", cl, dnowx(), s);
}
}
rfbReleaseClientIterator(iter);
if (fb_pend > 0) {
rfbLog("do_new_fb: newFBSizePending extra -threads sleep (%d)\n", i+1);
usleep(ms * 1000);
} else {
break;
}
}
for (i=0; i < 5; i++) {
int stuck = 0, tot = 0, j = 0;
iter = rfbGetClientIterator(screen);
while ((cl = rfbClientIteratorNext(iter)) != NULL) {
if (j < _bytes0_size) {
int db = rfbStatGetSentBytesIfRaw(cl) - _bytes0[j];
int Bpp = cl->format.bitsPerPixel / 8;
s = lcs(cl);
rfbLog("addl bytes sent: %p %.6f %s %d %d\n",
cl, dnowx(), s, db, _bytes0[j]);
if (i==0) {
if (db < Bpp * dpy_x * dpy_y) {
stuck++;
}
} else if (i==1) {
if (db < 0.5 * Bpp * dpy_x * dpy_y) {
stuck++;
}
} else {
if (db <= 0) {
stuck++;
}
}
}
tot++;
j++;
}
rfbReleaseClientIterator(iter);
if (stuck > 0) {
rfbLog("clients stuck: %d/%d sleep(%d)\n", stuck, tot, i);
usleep(2 * ms * 1000);
} else {
break;
}
}
}
static void prep_clients_for_new_fb(void) {
rfbClientIteratorPtr iter;
rfbClientPtr cl;
if (!use_threads || !screen) {
return;
}
iter = rfbGetClientIterator(screen);
while ((cl = rfbClientIteratorNext(iter)) != NULL) {
if (!cl->newFBSizePending) {
rfbLog("** set_new_fb_size_pending client: %p\n", cl);
cl->newFBSizePending = TRUE;
}
cl->cursorWasChanged = FALSE;
cl->cursorWasMoved = FALSE;
}
rfbReleaseClientIterator(iter);
}
void do_new_fb(int reset_mem) {
XImage *fb;
/* for threaded we really should lock libvncserver out. */
if (use_threads) {
rfbLog("warning: changing framebuffers while threaded may\n");
rfbLog(" not work, do not use -threads if problems arise.\n");
int ms = 1000;
if (getenv("X11VNC_THREADS_NEW_FB_SLEEP")) {
ms = atoi(getenv("X11VNC_THREADS_NEW_FB_SLEEP"));
} else if (subwin) {
ms = 500;
} else {
ms = 1000;
}
rfbLog("Warning: changing framebuffers in threaded mode may be unstable.\n");
threads_drop_input = 1;
usleep(ms * 1000);
}
INPUT_LOCK;
lock_client_sends(1);
if (use_threads) {
settle_clients(1);
}
if (reset_mem == 1) {
@ -842,6 +1048,16 @@ void do_new_fb(int reset_mem) {
if (ncache) {
check_ncache(1, 0);
}
prep_clients_for_new_fb();
lock_client_sends(0);
INPUT_UNLOCK;
if (use_threads) {
/* need to let things settle... */
settle_clients(0);
threads_drop_input = 0;
}
}
static void remove_fake_fb(void) {
@ -859,51 +1075,6 @@ static void remove_fake_fb(void) {
fake_fb = NULL;
}
static void lock_client_sends(int lock) {
static rfbClientPtr *cls = NULL;
static int cls_len = 0;
static int blocked = 0;
rfbClientIteratorPtr iter;
rfbClientPtr cl;
if (!use_threads) {
return;
}
if (!screen) {
return;
}
if (lock) {
if (cls_len < client_count + 128) {
if (cls != NULL) {
free(cls);
}
cls_len = client_count + 128;
cls = (rfbClientPtr *) calloc(cls_len * sizeof(rfbClientPtr), 1);
}
iter = rfbGetClientIterator(screen);
blocked = 0;
while ((cl = rfbClientIteratorNext(iter)) != NULL) {
SEND_LOCK(cl);
rfbLog("locked client: %p\n", cl);
cls[blocked++] = cl;
}
rfbReleaseClientIterator(iter);
} else {
int i;
for (i=0; i < blocked; i++) {
cl = cls[i];
if (cl != NULL) {
SEND_UNLOCK(cl)
rfbLog("unlocked client: %p\n", cl);
}
cls[i] = NULL;
}
blocked = 0;
}
}
static void rfb_new_framebuffer(rfbScreenInfoPtr rfbScreen, char *framebuffer,
int width,int height, int bitsPerSample,int samplesPerPixel,
int bytesPerPixel) {
@ -918,12 +1089,14 @@ static void install_fake_fb(int w, int h, int bpp) {
if (! screen) {
return;
}
lock_client_sends(1);
if (fake_fb) {
free(fake_fb);
}
fake_fb = (char *) calloc(w*h*bpp/8, 1);
if (! fake_fb) {
rfbLog("could not create fake fb: %dx%d %d\n", w, h, bpp);
lock_client_sends(0);
return;
}
bpc = guess_bits_per_color(bpp);
@ -931,7 +1104,6 @@ static void install_fake_fb(int w, int h, int bpp) {
rfbLog("rfbNewFramebuffer(0x%x, 0x%x, %d, %d, %d, %d, %d)\n",
screen, fake_fb, w, h, bpc, 1, bpp/8);
lock_client_sends(1);
rfb_new_framebuffer(screen, fake_fb, w, h, bpc, 1, bpp/8);
lock_client_sends(0);
}
@ -2275,6 +2447,8 @@ if (0) fprintf(stderr, "vis_str %s\n", vis_str ? vis_str : "notset");
/* set up parameters for subwin or non-subwin cases: */
again:
if (! subwin) {
/* full screen */
window = rootwin;
@ -2368,7 +2542,6 @@ if (0) fprintf(stderr, "DefaultDepth: %d visial_id: %d\n", depth, (int) visual_
(int) XVisualIDFromVisual(default_visual));
}
again:
if (subwin) {
int shift = 0, resize = 0;
int subwin_x, subwin_y;
@ -2435,7 +2608,9 @@ if (0) fprintf(stderr, "DefaultDepth: %d visial_id: %d\n", depth, (int) 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);
if (fb) {
fb->data = (char *) malloc(fb->bytes_per_line * fb->height);
}
} else {
fb = XGetImage_wr(dpy, window, 0, 0, dpy_x, dpy_y, AllPlanes,
@ -2448,7 +2623,7 @@ if (0) fprintf(stderr, "DefaultDepth: %d visial_id: %d\n", depth, (int) visual_
if (subwin) {
XSetErrorHandler(old_handler);
if (trapped_xerror) {
if (trapped_xerror || fb == NULL) {
rfbLog("trapped GetImage at SUBWIN creation.\n");
if (try < subwin_tries) {
usleep(250 * 1000);
@ -2464,10 +2639,51 @@ if (0) fprintf(stderr, "DefaultDepth: %d visial_id: %d\n", depth, (int) visual_
}
trapped_xerror = 0;
} else if (! fb && try == 1) {
/* try once more */
usleep(250 * 1000);
goto again;
} else if (fb == NULL) {
XEvent xev;
rfbLog("initialize_xdisplay_fb: *** fb creation failed: 0x%x try: %d\n", fb, try);
#if LIBVNCSERVER_HAVE_LIBXRANDR
if (xrandr_present && xrandr_base_event_type) {
int cnt = 0;
while (XCheckTypedEvent(dpy, xrandr_base_event_type + RRScreenChangeNotify, &xev)) {
XRRScreenChangeNotifyEvent *rev;
rev = (XRRScreenChangeNotifyEvent *) &xev;
rfbLog("initialize_xdisplay_fb: XRANDR event while redoing fb[%d]:\n", cnt++);
rfbLog(" serial: %d\n", (int) rev->serial);
rfbLog(" timestamp: %d\n", (int) rev->timestamp);
rfbLog(" cfg_timestamp: %d\n", (int) rev->config_timestamp);
rfbLog(" size_id: %d\n", (int) rev->size_index);
rfbLog(" sub_pixel: %d\n", (int) rev->subpixel_order);
rfbLog(" rotation: %d\n", (int) rev->rotation);
rfbLog(" width: %d\n", (int) rev->width);
rfbLog(" height: %d\n", (int) rev->height);
rfbLog(" mwidth: %d mm\n", (int) rev->mwidth);
rfbLog(" mheight: %d mm\n", (int) rev->mheight);
rfbLog("\n");
rfbLog("previous WxH: %dx%d\n", wdpy_x, wdpy_y);
xrandr_width = rev->width;
xrandr_height = rev->height;
xrandr_timestamp = rev->timestamp;
xrandr_cfg_time = rev->config_timestamp;
xrandr_rotation = (int) rev->rotation;
rfbLog("initialize_xdisplay_fb: updating XRANDR config...\n");
XRRUpdateConfiguration(&xev);
}
}
#endif
if (try < 5) {
XFlush_wr(dpy);
usleep(250 * 1000);
if (try < 3) {
XSync(dpy, False);
} else if (try >= 3) {
XSync(dpy, True);
}
goto again;
}
}
if (use_snapfb) {
initialize_snap_fb();
@ -2734,9 +2950,11 @@ static rfbBool set_xlate_wrapper(rfbClientPtr cl) {
} else if (ncache) {
int save = ncache_xrootpmap;
rfbLog("set_xlate_wrapper: clearing -ncache for new pixel format.\n");
INPUT_LOCK;
ncache_xrootpmap = 0;
check_ncache(1, 0);
ncache_xrootpmap = save;
INPUT_UNLOCK;
}
return rfbSetTranslateFunction(cl);
}
@ -2751,7 +2969,8 @@ void initialize_screen(int *argc, char **argv, XImage *fb) {
int create_screen = screen ? 0 : 1;
int bits_per_color;
int fb_bpp, fb_Bpl, fb_depth;
int locked_sends = 0;
bpp = fb->bits_per_pixel;
fb_bpp = (int) fb->bits_per_pixel;
@ -2860,7 +3079,10 @@ void initialize_screen(int *argc, char **argv, XImage *fb) {
*/
bits_per_color = guess_bits_per_color(fb_bpp);
lock_client_sends(1);
if (lock_client_sends(-1) == 0) {
lock_client_sends(1);
locked_sends = 1;
}
/* n.b. samplesPerPixel (set = 1 here) seems to be unused. */
if (create_screen) {
@ -3274,7 +3496,6 @@ void initialize_screen(int *argc, char **argv, XImage *fb) {
/* may need, bpp, main_red_max, etc. */
parse_wireframe();
parse_scroll_copyrect();
setup_cursors_and_push();
if (scaling || rotating || cmap8to24) {
@ -3297,10 +3518,13 @@ void initialize_screen(int *argc, char **argv, XImage *fb) {
}
rfbReleaseClientIterator(iter);
if (!quiet) rfbLog(" done.\n");
do_copy_screen = 1;
/* done for framebuffer change case */
lock_client_sends(0);
if (locked_sends) {
lock_client_sends(0);
}
do_copy_screen = 1;
return;
}
@ -3376,7 +3600,10 @@ void initialize_screen(int *argc, char **argv, XImage *fb) {
install_passwds();
lock_client_sends(0);
if (locked_sends) {
lock_client_sends(0);
}
return;
}
#define DO_AVAHI \
@ -3981,6 +4208,7 @@ void watch_loop(void) {
while (1) {
char msg[] = "new client: %s taking unixpw client off hold.\n";
int skip_scan_for_updates = 0;
got_user_input = 0;
got_pointer_input = 0;
@ -4187,8 +4415,20 @@ void watch_loop(void) {
if (x11vnc_current < last_new_client + 0.5 && !all_clients_initialized()) {
continue;
}
if (subwin && freeze_when_obscured) {
/* XXX not working */
X_LOCK;
XFlush_wr(dpy);
X_UNLOCK;
check_xevents(0);
if (subwin_obscured) {
skip_scan_for_updates = 1;
}
}
if (button_mask && (!show_dragging || pointer_mode == 0)) {
if (skip_scan_for_updates) {
;
} else if (button_mask && (!show_dragging || pointer_mode == 0)) {
/*
* if any button is pressed in this mode do
* not update rfb screen, but do flush the
@ -4216,6 +4456,7 @@ void watch_loop(void) {
if (rawfb_vnc_reflect) {
vnc_reflect_process_client();
}
dtime0(&tm);
#if !NO_X11
@ -4235,7 +4476,9 @@ void watch_loop(void) {
}
X_UNLOCK;
}
X_LOCK;
check_xrandr_event("before-scan");
X_UNLOCK;
}
#endif
if (use_snapfb) {

@ -2666,8 +2666,8 @@ void check_https(void) {
}
void openssl_port(void) {
int sock, shutdown = 0;
static int port = 0;
int sock = -1, shutdown = 0;
static int port = -1;
static in_addr_t iface = INADDR_ANY;
int db = 0;
@ -2683,6 +2683,8 @@ void openssl_port(void) {
if (screen->listenSock > -1 && screen->port > 0) {
port = screen->port;
shutdown = 1;
} else if (screen->port == 0) {
port = screen->port;
}
if (screen->listenInterface) {
iface = screen->listenInterface;
@ -2696,14 +2698,18 @@ void openssl_port(void) {
#endif
}
if (port <= 0) {
if (port < 0) {
rfbLog("openssl_port: could not obtain listening port %d\n", port);
clean_up_exit(1);
}
sock = rfbListenOnTCPPort(port, iface);
if (sock < 0) {
rfbLog("openssl_port: could not reopen port %d\n", port);
clean_up_exit(1);
} else if (port == 0) {
/* no listen case, i.e. -connect */
sock = -1;
} else {
sock = rfbListenOnTCPPort(port, iface);
if (sock < 0) {
rfbLog("openssl_port: could not reopen port %d\n", port);
clean_up_exit(1);
}
}
rfbLog("openssl_port: listen on port/sock %d/%d\n", port, sock);
if (!quiet) {
@ -3852,6 +3858,7 @@ void accept_openssl(int mode, int presock) {
if (screen->port == 0) {
int fd = fileno(stdin);
if (getenv("X11VNC_INETD_PORT")) {
/* mutex */
screen->port = atoi(getenv(
"X11VNC_INETD_PORT"));
} else {

@ -176,6 +176,7 @@ Screen
=GAL SubWindow::
id:
sid:
=RA id_cmd:
=GAL LOFF
=GAL ResizeRotate::
= xrandr

@ -187,6 +187,7 @@ char gui_code[] = "";
" =GAL SubWindow::\n"
" id:\n"
" sid:\n"
" =RA id_cmd:\n"
" =GAL LOFF\n"
" =GAL ResizeRotate::\n"
" = xrandr\n"

@ -2033,6 +2033,7 @@ void unixpw_accept(char *user) {
unixpw_client->viewOnly = TRUE;
}
unixpw_in_progress = 0;
/* mutex */
screen->permitFileTransfer = unixpw_file_xfer_save;
if ((tightfilexfer = unixpw_tightvnc_xfer_save)) {
/* this doesn't work: the current client is never registered! */
@ -2078,6 +2079,7 @@ void unixpw_deny(void) {
}
unixpw_in_progress = 0;
/* mutex */
screen->permitFileTransfer = unixpw_file_xfer_save;
if ((tightfilexfer = unixpw_tightvnc_xfer_save)) {
#ifdef LIBVNCSERVER_WITH_TIGHTVNC_FILETRANSFER

@ -1085,6 +1085,7 @@ void install_passwds(void) {
passwds_new[0] = passwds_old[0];
passwds_new[1] = viewonly_passwd;
passwds_new[2] = NULL;
/* mutex */
screen->authPasswdData = (void*) passwds_new;
} else if (passwd_list) {
int i = 0;
@ -1094,6 +1095,7 @@ void install_passwds(void) {
if (begin_viewonly < 0) {
begin_viewonly = i+1;
}
/* mutex */
screen->authPasswdData = (void*) passwd_list;
screen->authPasswdFirstViewOnly = begin_viewonly;
}
@ -1167,6 +1169,7 @@ static void handle_one_http_request(void) {
if (inetd || screen->httpPort == 0) {
int port = find_free_port(5800, 5860);
if (port) {
/* mutex */
screen->httpPort = port;
} else {
rfbLog("handle_one_http_request: no http port.\n");
@ -1703,6 +1706,7 @@ static void vnc_redirect_loop(char *vnc_redirect_test, int *vnc_redirect_cnt) {
#if LIBVNCSERVER_HAVE_FORK
if ((pid = fork()) > 0) {
close(screen->httpListenSock);
/* mutex */
screen->httpListenSock = -2;
usleep(500 * 1000);
} else {

@ -373,6 +373,7 @@ static void parse_wireframe_str(char *wf) {
Colormap cmap;
if (dpy && (bpp == 32 || bpp == 16)) {
#if !NO_X11
X_LOCK;
cmap = DefaultColormap (dpy, scr);
if (XParseColor(dpy, cmap, str, &cdef) &&
XAllocColor(dpy, cmap, &cdef)) {
@ -389,6 +390,7 @@ static void parse_wireframe_str(char *wf) {
wireframe_shade = n;
ok = 1;
}
X_UNLOCK;
#else
r = g = b = 0;
cmap = 0;

@ -471,6 +471,7 @@ double rfac(void) {
void check_allinput_rate(void) {
static double last_all_input_check = 0.0;
static int set = 0, verb = -1;
if (use_threads) {
return;
}
@ -703,7 +704,7 @@ double rect_overlap(int x1, int y1, int x2, int y2, int X1, int Y1,
char *choose_title(char *display) {
static char title[(MAXN+10)];
memset(title, 0, MAXN+10);
memset(title, 0, sizeof(title));
strcpy(title, "x11vnc");
if (display == NULL) {
@ -724,13 +725,33 @@ char *choose_title(char *display) {
if (subwin && dpy && valid_window(subwin, NULL, 0)) {
#if !NO_X11
char *name = NULL;
int do_appshare = getenv("X11VNC_APPSHARE_ACTIVE") ? 1 : 0;
if (0 && do_appshare) {
title[0] = '\0';
}
if (XFetchName(dpy, subwin, &name)) {
if (name) {
strncat(title, " ", MAXN - strlen(title));
if (title[0] != '\0') {
strncat(title, " ", MAXN - strlen(title));
}
strncat(title, name, MAXN - strlen(title));
free(name);
}
}
if (do_appshare) {
Window c;
int x, y;
if (xtranslate(subwin, rootwin, 0, 0, &x, &y, &c, 1)) {
char tmp[32];
if (scaling) {
x *= scale_fac_x;
y *= scale_fac_y;
}
sprintf(tmp, " XY=%d,%d", x, y);
strncat(title, tmp, MAXN - strlen(title));
}
rfbLog("appshare title: %s\n", title);
}
#endif /* NO_X11 */
}
X_UNLOCK;

@ -72,6 +72,11 @@ extern char *choose_title(char *display);
#define NONUL(x) ((x) ? (x) : "")
/*
Put this in usleep2() for debug printout.
fprintf(stderr, "_mysleep: %08d %10.6f %s:%d\n", (x), dnow() - x11vnc_start, __FILE__, __LINE__); \
*/
/* XXX usleep(3) is not thread safe on some older systems... */
extern struct timeval _mysleep;
#define usleep2(x) \
@ -96,6 +101,10 @@ extern struct timeval _mysleep;
*/
#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
extern MUTEX(x11Mutex);
extern MUTEX(scrollMutex);
MUTEX(clientMutex);
MUTEX(inputMutex);
MUTEX(pointerMutex);
#endif
#define X_INIT INIT_MUTEX(x11Mutex)
@ -105,26 +114,33 @@ extern MUTEX(x11Mutex);
#define X_UNLOCK UNLOCK(x11Mutex)
#else
extern int hxl;
#define X_LOCK fprintf(stderr, "*** X_LOCK**[%05d] %d%s\n", \
__LINE__, hxl, hxl ? " BAD-PRE-LOCK":""); LOCK(x11Mutex); hxl = 1;
#define X_UNLOCK fprintf(stderr, " x_unlock[%05d] %d%s\n", \
__LINE__, hxl, !hxl ? " BAD-PRE-UNLOCK":""); UNLOCK(x11Mutex); hxl = 0;
#define X_LOCK fprintf(stderr, "*** X_LOCK** %d%s %s:%d\n", \
hxl, hxl ? " BAD-PRE-LOCK":"", __FILE__, __LINE__); LOCK(x11Mutex); hxl = 1;
#define X_UNLOCK fprintf(stderr, " x_unlock %d%s %s:%d\n", \
hxl, !hxl ? " BAD-PRE-UNLOCK":"", __FILE__, __LINE__); UNLOCK(x11Mutex); hxl = 0;
#endif
#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
extern MUTEX(scrollMutex);
#endif
#define SCR_LOCK if (use_threads) {LOCK(scrollMutex);}
#define SCR_UNLOCK if (use_threads) {UNLOCK(scrollMutex);}
#define SCR_INIT INIT_MUTEX(scrollMutex)
#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
MUTEX(clientMutex);
#endif
#define CLIENT_LOCK if (use_threads) {LOCK(clientMutex);}
#define CLIENT_UNLOCK if (use_threads) {UNLOCK(clientMutex);}
#define CLIENT_INIT INIT_MUTEX(clientMutex)
#if 1
#define INPUT_LOCK if (use_threads) {LOCK(inputMutex);}
#define INPUT_UNLOCK if (use_threads) {UNLOCK(inputMutex);}
#else
#define INPUT_LOCK
#define INPUT_UNLOCK
#endif
#define INPUT_INIT INIT_MUTEX(inputMutex)
#define POINTER_LOCK if (use_threads) {LOCK(pointerMutex);}
#define POINTER_UNLOCK if (use_threads) {UNLOCK(pointerMutex);}
#define POINTER_INIT INIT_MUTEX(pointerMutex)
/*
* The sendMutex member was added to libvncserver 0.9.8
* rfb/rfb.h sets LIBVNCSERVER_SEND_MUTEX if present.

@ -38,6 +38,7 @@ so, delete this exception statement from your version.
#include "cleanup.h"
#include "xwrappers.h"
#include "connections.h"
#include "xrandr.h"
#include "macosx.h"
winattr_t *stack_list = NULL;
@ -49,7 +50,7 @@ Window parent_window(Window win, char **name);
int valid_window(Window win, XWindowAttributes *attr_ret, int bequiet);
Bool xtranslate(Window src, Window dst, int src_x, int src_y, int *dst_x,
int *dst_y, Window *child, int bequiet);
int get_window_size(Window win, int *x, int *y);
int get_window_size(Window win, int *w, int *h);
void snapshot_stack_list(int free_only, double allowed_age);
int get_boff(void);
int get_bwin(void);
@ -58,6 +59,7 @@ Window query_pointer(Window start);
unsigned int mask_state(void);
int pick_windowid(unsigned long *num);
Window descend_pointer(int depth, Window start, char *name_info, int len);
void id_cmd(char *cmd);
Window parent_window(Window win, char **name) {
@ -184,12 +186,12 @@ Bool xtranslate(Window src, Window dst, int src_x, int src_y, int *dst_x,
#endif /* NO_X11 */
}
int get_window_size(Window win, int *x, int *y) {
int get_window_size(Window win, int *w, int *h) {
XWindowAttributes attr;
/* valid_window? */
if (valid_window(win, &attr, 1)) {
*x = attr.width;
*y = attr.height;
*w = attr.width;
*h = attr.height;
return 1;
} else {
return 0;
@ -609,3 +611,161 @@ Window descend_pointer(int depth, Window start, char *name_info, int len) {
#endif /* NO_X11 */
}
void id_cmd(char *cmd) {
int rc, dx = 0, dy = 0, dw = 0, dh = 0;
int x0, y0, w0, h0;
int x, y, w, h, do_move = 0, do_resize = 0;
int disp_x = DisplayWidth(dpy, scr);
int disp_y = DisplayHeight(dpy, scr);
Window win = subwin;
XWindowAttributes attr;
XErrorHandler old_handler = NULL;
Window twin;
if (!cmd || !strcmp(cmd, "")) {
return;
}
if (strstr(cmd, "win=") == cmd) {
if (! scan_hexdec(cmd + strlen("win="), &win)) {
rfbLog("id_cmd: incorrect win= hex/dec number: %s\n", cmd);
return;
} else {
char *q = strchr(cmd, ':');
if (!q) {
rfbLog("id_cmd: incorrect win=...: hex/dec number: %s\n", cmd);
return;
}
rfbLog("id_cmd:%s set window id to 0x%lx\n", cmd, win);
cmd = q+1;
}
}
if (!win) {
rfbLog("id_cmd:%s not in sub-window mode or no win=0xNNNN.\n", cmd);
return;
}
#if !NO_X11
X_LOCK;
if (!valid_window(win, &attr, 1)) {
X_UNLOCK;
return;
}
w0 = w = attr.width;
h0 = h = attr.height;
old_handler = XSetErrorHandler(trap_xerror);
trapped_xerror = 0;
XTranslateCoordinates(dpy, win, rootwin, 0, 0, &x, &y, &twin);
x0 = x;
y0 = y;
if (strstr(cmd, "move:") == cmd) {
if (sscanf(cmd, "move:%d%d", &dx, &dy) == 2) {
x = x + dx;
y = y + dy;
do_move = 1;
}
} else if (strstr(cmd, "resize:") == cmd) {
if (sscanf(cmd, "resize:%d%d", &dw, &dh) == 2) {
w = w + dw;
h = h + dh;
do_move = 1;
do_resize = 1;
}
} else if (strstr(cmd, "geom:") == cmd) {
if (parse_geom(cmd+strlen("geom:"), &w, &h, &x, &y, disp_x, disp_y)) {
do_move = 1;
do_resize = 1;
if (w <= 0) {
w = w0;
}
if (h <= 0) {
h = h0;
}
if (scaling && getenv("X11VNC_APPSHARE_ACTIVE")) {
x /= scale_fac_x;
y /= scale_fac_y;
}
}
} else if (!strcmp(cmd, "raise")) {
rc = XRaiseWindow(dpy, win);
rfbLog("id_cmd:%s rc=%d\n", cmd, rc);
} else if (!strcmp(cmd, "lower")) {
rc = XLowerWindow(dpy, win);
rfbLog("id_cmd:%s rc=%d\n", cmd, rc);
} else if (!strcmp(cmd, "map")) {
rc= XMapRaised(dpy, win);
rfbLog("id_cmd:%s rc=%d\n", cmd, rc);
} else if (!strcmp(cmd, "unmap")) {
rc= XUnmapWindow(dpy, win);
rfbLog("id_cmd:%s rc=%d\n", cmd, rc);
} else if (!strcmp(cmd, "iconify")) {
rc= XIconifyWindow(dpy, win, scr);
rfbLog("id_cmd:%s rc=%d\n", cmd, rc);
} else if (strstr(cmd, "wm_name:") == cmd) {
rc= XStoreName(dpy, win, cmd+strlen("wm_name:"));
rfbLog("id_cmd:%s rc=%d\n", cmd, rc);
} else if (strstr(cmd, "icon_name:") == cmd) {
rc= XSetIconName(dpy, win, cmd+strlen("icon_name:"));
rfbLog("id_cmd:%s rc=%d\n", cmd, rc);
} else if (!strcmp(cmd, "wm_delete")) {
XClientMessageEvent ev;
memset(&ev, 0, sizeof(ev));
ev.type = ClientMessage;
ev.send_event = True;
ev.display = dpy;
ev.window = win;
ev.message_type = XInternAtom(dpy, "WM_PROTOCOLS", False);
ev.format = 32;
ev.data.l[0] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
rc = XSendEvent(dpy, win, False, 0, (XEvent *) &ev);
rfbLog("id_cmd:%s rc=%d\n", cmd, rc);
} else {
rfbLog("id_cmd:%s unrecognized command.\n", cmd);
}
if (do_move || do_resize) {
if (w >= disp_x) {
w = disp_x - 4;
}
if (h >= disp_y) {
h = disp_y - 4;
}
if (w < 1) {
w = 1;
}
if (h < 1) {
h = 1;
}
if (x + w > disp_x) {
x = disp_x - w - 1;
}
if (y + h > disp_y) {
y = disp_y - h - 1;
}
if (x < 0) {
x = 1;
}
if (y < 0) {
y = 1;
}
rc = 0;
rc += XMoveWindow(dpy, win, x, y);
off_x = x;
off_y = y;
rc += XResizeWindow(dpy, win, w, h);
rfbLog("id_cmd:%s rc=%d dx=%d dy=%d dw=%d dh=%d %dx%d+%d+%d -> %dx%d+%d+%d\n",
cmd, rc, dx, dy, dw, dh, w0, h0, x0, y0, w, h, x, h);
}
XSync(dpy, False);
XSetErrorHandler(old_handler);
if (trapped_xerror) {
rfbLog("id_cmd:%s trapped_xerror.\n", cmd);
}
trapped_xerror = 0;
if (do_resize) {
rfbLog("id_cmd:%s calling check_xrandr_event.\n", cmd);
check_xrandr_event("id_cmd");
}
X_UNLOCK;
#endif
}

@ -45,7 +45,7 @@ extern Window parent_window(Window win, char **name);
extern int valid_window(Window win, XWindowAttributes *attr_ret, int bequiet);
extern Bool xtranslate(Window src, Window dst, int src_x, int src_y, int *dst_x,
int *dst_y, Window *child, int bequiet);
extern int get_window_size(Window win, int *x, int *y);
extern int get_window_size(Window win, int *w, int *h);
extern void snapshot_stack_list(int free_only, double allowed_age);
extern int get_boff(void);
extern int get_bwin(void);
@ -54,5 +54,6 @@ extern Window query_pointer(Window start);
extern unsigned int mask_state(void);
extern int pick_windowid(unsigned long *num);
extern Window descend_pointer(int depth, Window start, char *name_info, int len);
extern void id_cmd(char *cmd);
#endif /* _X11VNC_WIN_UTILS_H */

@ -1,8 +1,8 @@
.\" This file was automatically generated from x11vnc -help output.
.TH X11VNC "1" "November 2009" "x11vnc " "User Commands"
.TH X11VNC "1" "December 2009" "x11vnc " "User Commands"
.SH NAME
x11vnc - allow VNC connections to real X11 displays
version: 0.9.9, lastmod: 2009-11-18
version: 0.9.9, lastmod: 2009-12-02
.SH SYNOPSIS
.B x11vnc
[OPTION]...
@ -158,6 +158,15 @@ shifts a root view to it: this shows SaveUnders menus,
etc, although they will be clipped if they extend beyond
the window.
.PP
\fB-appshare\fR
.IP
Simple application sharing based on the \fB-id/-sid\fR
mechanism. Every new toplevel window that the
application creates induces a new viewer window via
a reverse connection. The \fB-id/-sid\fR and \fB-connect\fR
options are required. Run 'x11vnc \fB-appshare\fR \fB-help'\fR
for more info.
.PP
\fB-clip\fR \fIWxH+X+Y\fR
.IP
Only show the sub-region of the full display that
@ -3110,7 +3119,7 @@ Instead of exiting after cleaning up, run a simple
\fB-q,\fR \fB-quiet\fR
.IP
Be quiet by printing less informational output to
stderr.
stderr. (use \fB-noquiet\fR to undo an earlier \fB-quiet.)\fR
.PP
\fB-v,\fR \fB-verbose\fR
.IP
@ -3611,7 +3620,7 @@ Client-side caching scheme. Framebuffer memory \fIn\fR
(an integer) times that of the full display is allocated
below the actual framebuffer to cache screen contents
for rapid retrieval. So a W x H frambuffer is expanded
to a W x (n+1)*H one. Use 0 to disable. Default: XXX.
to a W x (n+1)*H one. Use 0 to disable.
.IP
The \fIn\fR is actually optional, the default is 10.
.IP
@ -3619,13 +3628,17 @@ For this and the other \fB-ncache*\fR options below you can
abbreviate "\fB-ncache\fR" with "\fB-nc\fR". Also, "\fB-nonc\fR"
is the same as "\fB-ncache\fR \fI0\fR"
.IP
This is an experimental option, currently implemented
in an awkward way in that in the VNC Viewer you can
see the cache contents if you scroll down, etc. So you
This is an experimental option, currently implemented in
an awkward way in that in the VNC Viewer you can see the
pixel cache contents if you scroll down, etc. So you
will have to set things up so you can't see that region.
If this method is successful, the changes required for
clients to do this less awkwardly will be investigated.
.IP
The SSVNC viewer does a good job at automatically hiding
the pixel cache region. Or use SSVNC's \fB-ycrop\fR option
to explicitly hide the region.
.IP
Note that this mode consumes a huge amount of memory,
both on the x11vnc server side and on the VNC Viewer
side. If n=2 then the amount of RAM used is roughly
@ -4465,10 +4478,7 @@ In this mode new threads (one for input and one
for output) are created to handle each new client.
Default: \fB-nothreads.\fR
.IP
NOTE: The \fB-threads\fR mode may be disabled due to its
unstable behavior. If it is disabled, a warning is
printed out. Stability has been improved in version
0.9.8 and so the feature has been re-enabled.
Thread stability is much improved in version 0.9.8.
.IP
Multiple clients in threaded mode should be stable
for the ZRLE encoding on all platforms. The Tight and
@ -4476,9 +4486,14 @@ Zlib encodings are currently only stable on Linux for
multiple clients. Compile with \fB-DTLS=__thread\fR if your
OS and compiler and linker support it.
.IP
For resizes (randr, etc.) set this env. var. to the number
of milliseconds to sleep: X11VNC_THREADS_NEW_FB_SLEEP
at various places in the do_new_fb() action. This is to
let various activities settle. Default is about 500ms.
.IP
Multiple clients in threaded mode could yield better
performance for 'class-room' broadcasting usage.
See also the \fB-reflect\fR option.
performance for 'class-room' broadcasting usage; also in
\fB-appshare\fR broadcast mode. See also the \fB-reflect\fR option.
.PP
\fB-fs\fR \fIf\fR
.IP
@ -5252,6 +5267,13 @@ or "root" to go back to root window
.IP
sid:windowid set \fB-sid\fR window to "windowid"
.IP
id_cmd:cmd cmds: raise, lower, map, unmap, iconify,
move:dXdY, resize:dWdH, geom:WxH+X+Y. dX
dY, dW, and dH must have a leading "+"
or "-" e.g.: move:-30+10 resize:+20+35
also: wm_delete, wm_name:string and
icon_name:string. Also id_cmd:win=N:cmd
.IP
waitmapped wait until subwin is mapped.
.IP
nowaitmapped do not wait until subwin is mapped.
@ -6035,8 +6057,8 @@ query straight to the X11VNC_REMOTE property or connect
file use "qry=..." instead of "cmd=..."
.IP
ans= stop quit exit shutdown ping resend_cutbuffer
resend_clipboard resend_primary blacken zero
refresh reset close disconnect id sid waitmapped
resend_clipboard resend_primary blacken zero refresh
reset close disconnect id_cmd id sid waitmapped
nowaitmapped clip flashcmap noflashcmap shiftcmap
truecolor notruecolor overlay nooverlay overlay_cursor
overlay_yescursor nooverlay_nocursor nooverlay_cursor
@ -6185,6 +6207,10 @@ Any corresponding output text for that remote control
command is sent back to all client as rfbCutText.
The returned output is also prefixed with \fIstr\fR.
Example: \fB-remote_prefix\fR DO_THIS:
.IP
Note that enabling \fB-remote_prefix\fR allows the remote
VNC viewers to run x11vnc \fB-remote\fR commands. Do not
use this option if they are not to be trusted.
.PP
\fB-noremote,\fR \fB-yesremote\fR
.IP

@ -172,6 +172,7 @@ static void check_rcfile(int argc, char **argv);
static void immediate_switch_user(int argc, char* argv[]);
static void print_settings(int try_http, int bg, char *gui_str);
static void check_loop_mode(int argc, char* argv[], int force);
static void check_appshare_mode(int argc, char* argv[]);
static int tsdo_timeout_flag;
@ -1702,6 +1703,24 @@ static void check_loop_mode(int argc, char* argv[], int force) {
#endif
}
}
extern int appshare_main(int argc, char* argv[]);
static void check_appshare_mode(int argc, char* argv[]) {
int i;
for (i=1; i < argc; i++) {
char *p = argv[i];
if (strstr(p, "--") == p) {
p++;
}
if (strstr(p, "-appshare") == p) {
appshare_main(argc, argv);
exit(0);
}
}
}
static void store_homedir_passwd(char *file) {
char str1[32], str2[32], *p, *h, *f;
struct stat sbuf;
@ -1992,21 +2011,32 @@ int main(int argc, char* argv[]) {
char *got_rfbport_str = NULL;
int got_rfbport_pos = -1;
int got_tls = 0;
int got_inetd = 0;
int got_noxrandr = 0;
/* used to pass args we do not know about to rfbGetScreen(): */
int argc_vnc_max = 1024;
int argc_vnc = 1; char *argv_vnc[2048];
/* check for -loop mode: */
check_loop_mode(argc, argv, 0);
/* check for -appshare mode: */
check_appshare_mode(argc, argv);
dtime0(&x11vnc_start);
for (i=1; i < argc; i++) {
if (!strcmp(argv[i], "-inetd")) {
got_inetd = 1;
}
}
if (!getuid() || !geteuid()) {
started_as_root = 1;
rfbLog("getuid: %d geteuid: %d\n", getuid(), geteuid());
if (0 && !got_inetd) {
rfbLog("getuid: %d geteuid: %d\n", getuid(), geteuid());
}
/* check for '-users =bob' */
immediate_switch_user(argc, argv);
@ -2363,6 +2393,14 @@ int main(int argc, char* argv[]) {
; /* handled above */
continue;
}
if (strstr(arg, "-appshare") == arg) {
; /* handled above */
continue;
}
if (strstr(arg, "-freeze_when_obscured") == arg) {
freeze_when_obscured = 1;
continue;
}
if (!strcmp(arg, "-timeout")) {
CHECK_ARGC
first_conn_timeout = atoi(argv[++i]);
@ -2955,6 +2993,7 @@ int main(int argc, char* argv[]) {
if (!strcmp(arg, "-noxrandr")) {
xrandr = 0;
xrandr_maybe = 0;
got_noxrandr = 1;
continue;
}
if (!strcmp(arg, "-rotate")) {
@ -3040,6 +3079,10 @@ int main(int argc, char* argv[]) {
quiet = 1;
continue;
}
if (!strcmp(arg, "-noquiet")) {
quiet = 0;
continue;
}
if (!strcmp(arg, "-v") || !strcmp(arg, "-verbose")) {
verbose = 1;
continue;
@ -3049,7 +3092,9 @@ int main(int argc, char* argv[]) {
bg = 1;
opts_bg = bg;
#else
fprintf(stderr, "warning: -bg mode not supported.\n");
if (!got_inetd) {
fprintf(stderr, "warning: -bg mode not supported.\n");
}
#endif
continue;
}
@ -3446,8 +3491,10 @@ int main(int argc, char* argv[]) {
*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));
if (!got_inetd) {
rfbLog("pointer_mode out of range 1-%d: %d\n",
pointer_mode_max, atoi(s));
}
} else {
pointer_mode = atoi(s);
got_pointer_mode = pointer_mode;
@ -3591,7 +3638,9 @@ int main(int argc, char* argv[]) {
if (!strcmp(arg, "-chatwindow")) {
chat_window = 1;
if (argc_vnc + 1 < argc_vnc_max) {
rfbLog("setting '-rfbversion 3.6' for -chatwindow.\n");
if (!got_inetd) {
rfbLog("setting '-rfbversion 3.6' for -chatwindow.\n");
}
argv_vnc[argc_vnc++] = strdup("-rfbversion");
argv_vnc[argc_vnc++] = strdup("3.6");
}
@ -3645,14 +3694,16 @@ int main(int argc, char* argv[]) {
/* we re-enable it due to threaded mode bugfixes. */
use_threads = 1;
} else {
rfbLog("\n");
rfbLog("The -threads mode is unstable and not tested or maintained.\n");
rfbLog("It is disabled in the source code. If you really need\n");
rfbLog("the feature you can reenable it at build time by setting\n");
rfbLog("-DX11VNC_THREADED in CPPFLAGS. Or set X11VNC_THREADED=1\n");
rfbLog("in your runtime environment.\n");
rfbLog("\n");
usleep(500*1000);
if (!got_inetd) {
rfbLog("\n");
rfbLog("The -threads mode is unstable and not tested or maintained.\n");
rfbLog("It is disabled in the source code. If you really need\n");
rfbLog("the feature you can reenable it at build time by setting\n");
rfbLog("-DX11VNC_THREADED in CPPFLAGS. Or set X11VNC_THREADED=1\n");
rfbLog("in your runtime environment.\n");
rfbLog("\n");
usleep(500*1000);
}
}
#endif
continue;
@ -3931,9 +3982,11 @@ int main(int argc, char* argv[]) {
if (!strcasecmp(argv[i+1], "prompt")) {
;
} else if (!is_decimal(argv[i+1])) {
rfbLog("Invalid -rfbport value: '%s'\n", argv[i+1]);
rfbLog("setting it to '-1' to induce failure.\n");
argv[i+1] = strdup("-1");
if (!got_inetd) {
rfbLog("Invalid -rfbport value: '%s'\n", argv[i+1]);
rfbLog("setting it to '-1' to induce failure.\n");
argv[i+1] = strdup("-1");
}
}
got_rfbport_str = strdup(argv[i+1]);
got_rfbport_pos = argc_vnc+1;
@ -4032,7 +4085,9 @@ int main(int argc, char* argv[]) {
client_connect_file = str;
}
if (client_connect_file) {
rfbLog("MacOS X: set -connect file to %s\n", client_connect_file);
if (!got_inetd) {
rfbLog("MacOS X: set -connect file to %s\n", client_connect_file);
}
}
}
}
@ -4053,7 +4108,9 @@ int main(int argc, char* argv[]) {
rfbLog("Port prompt indicated cancel.\n");
clean_up_exit(1);
}
rfbLog("Port prompt selected: %d\n", got_rfbport_val);
if (!got_inetd) {
rfbLog("Port prompt selected: %d\n", got_rfbport_val);
}
sprintf(tport, "%d", got_rfbport_val);
argv_vnc[got_rfbport_pos] = strdup(tport);
free(opts);
@ -4117,8 +4174,9 @@ int main(int argc, char* argv[]) {
q = t + strlen(pstr);
}
logfile = new;
if (!quiet) {
if (!quiet && !got_inetd) {
rfbLog("Expanded logfile to '%s'\n", new);
}
free(s);
}
@ -4152,7 +4210,7 @@ int main(int argc, char* argv[]) {
q = t + strlen(pstr);
}
logfile = new;
if (!quiet) {
if (!quiet && !got_inetd) {
rfbLog("Expanded logfile to '%s'\n", new);
}
free(s);
@ -4389,7 +4447,7 @@ int main(int argc, char* argv[]) {
if (1) {
/* mix things up a little bit */
unsigned char buf[CHALLENGESIZE];
int k, kmax = (int) (500 * rfac()) + 100;
int k, kmax = (int) (50 * rfac()) + 10;
for (k=0; k < kmax; k++) {
rfbRandomBytes(buf);
}
@ -4550,6 +4608,13 @@ int main(int argc, char* argv[]) {
exit(1);
}
if (use_threads && !got_noxrandr) {
xrandr = 1;
if (! quiet) {
rfbLog("enabling -xrandr in -threads mode.\n");
}
}
/* fixup settings that do not make sense */
if (use_threads && nofb && cursor_pos_updates) {
@ -4626,6 +4691,7 @@ int main(int argc, char* argv[]) {
/* increase rfbwait if threaded */
if (use_threads && ! got_rfbwait) {
/* ??? lower this ??? */
rfbMaxClientWait = 604800000;
}
@ -4712,6 +4778,8 @@ int main(int argc, char* argv[]) {
X_INIT;
SCR_INIT;
CLIENT_INIT;
INPUT_INIT;
POINTER_INIT;
/* open the X display: */
@ -5331,9 +5399,7 @@ int main(int argc, char* argv[]) {
}
#endif
if (!getenv("X11VNC_NO_CHECK_PM")) {
check_pm();
}
check_pm();
if (! quiet && ! raw_fb_str) {
rfbLog("--------------------------------------------------------\n");
@ -5644,4 +5710,3 @@ int main(int argc, char* argv[]) {
}

@ -47,7 +47,7 @@ int xtrap_base_event_type = 0;
int xdamage_base_event_type = 0;
/* date +'lastmod: %Y-%m-%d' */
char lastmod[] = "0.9.9 lastmod: 2009-11-18";
char lastmod[] = "0.9.9 lastmod: 2009-12-02";
/* X display info */

@ -340,6 +340,10 @@ static void initialize_xevents(int reset) {
X_LOCK;
xselectinput_rootwin |= PropertyChangeMask;
XSelectInput_wr(dpy, rootwin, xselectinput_rootwin);
if (subwin && freeze_when_obscured) {
XSelectInput_wr(dpy, subwin, VisibilityChangeMask);
}
X_UNLOCK;
did_xselect_input = 1;
}
@ -1284,6 +1288,22 @@ void check_xevents(int reset) {
last_call = now;
}
if (freeze_when_obscured) {
if (XCheckTypedEvent(dpy, VisibilityNotify, &xev)) {
if (xev.type == VisibilityNotify && xev.xany.window == subwin) {
int prev = subwin_obscured;
if (xev.xvisibility.state == VisibilityUnobscured) {
subwin_obscured = 0;
} else if (xev.xvisibility.state == VisibilityPartiallyObscured) {
subwin_obscured = 1;
} else {
subwin_obscured = 2;
}
rfbLog("subwin_obscured: %d -> %d\n", prev, subwin_obscured);
}
}
}
/* check for CUT_BUFFER0, VNC_CONNECT, X11VNC_REMOTE changes: */
if (XCheckTypedEvent(dpy, PropertyNotify, &xev)) {
int got_cutbuffer = 0;
@ -1622,6 +1642,10 @@ extern int rawfb_vnc_reflect;
void xcut_receive(char *text, int len, rfbClientPtr cl) {
allowed_input_t input;
if (threads_drop_input) {
return;
}
if (unixpw_in_progress) {
rfbLog("xcut_receive: unixpw_in_progress, skipping.\n");
return;
@ -1640,6 +1664,7 @@ void xcut_receive(char *text, int len, rfbClientPtr cl) {
if (!input.clipboard) {
return;
}
INPUT_LOCK;
if (remote_prefix != NULL && strstr(text, remote_prefix) == text) {
char *result, *rcmd = text + strlen(remote_prefix);
@ -1649,9 +1674,29 @@ void xcut_receive(char *text, int len, rfbClientPtr cl) {
strcat(tmp, "qry=");
}
strncat(tmp, rcmd, len - strlen(remote_prefix));
rfbLog("remote_prefix command: '%s'\n", tmp);
if (use_threads) {
if (client_connect_file) {
FILE *f = fopen(client_connect_file, "w");
if (f) {
fprintf(f, "%s\n", tmp);
fclose(f);
free(tmp);
INPUT_UNLOCK;
return;
}
}
if (vnc_connect) {
sprintf(x11vnc_remote_str, "%s", tmp);
free(tmp);
INPUT_UNLOCK;
return;
}
}
INPUT_UNLOCK;
result = process_remote_cmd(tmp, 1);
if (result == NULL ) {
result = strdup("null");
@ -1675,24 +1720,28 @@ void xcut_receive(char *text, int len, rfbClientPtr cl) {
}
if (! check_sel_direction("recv", "xcut_receive", text, len)) {
INPUT_UNLOCK;
return;
}
#ifdef MACOSX
if (macosx_console) {
macosx_set_sel(text, len);
INPUT_UNLOCK;
return;
}
#endif
if (rawfb_vnc_reflect) {
vnc_reflect_send_cuttext(text, len);
INPUT_UNLOCK;
return;
}
RAWFB_RET_VOID
#if NO_X11
INPUT_UNLOCK;
return;
#else
@ -1751,6 +1800,7 @@ void xcut_receive(char *text, int len, rfbClientPtr cl) {
XFlush_wr(dpy);
X_UNLOCK;
INPUT_UNLOCK;
set_cutbuffer = 1;
#endif /* NO_X11 */
@ -1956,6 +2006,7 @@ static void try_local_chat_window(void) {
return;
}
/* mutex */
new_save = screen->newClientHook;
screen->newClientHook = new_client_chat_helper;

@ -344,12 +344,14 @@ static void initialize_xinerama (void) {
RAWFB_RET_VOID
X_LOCK;
if (! XineramaQueryExtension(dpy, &ev, &er)) {
if (verbose) {
rfbLog("Xinerama: disabling: display does not support it.\n");
}
xinerama = 0;
xinerama_present = 0;
X_UNLOCK;
return;
}
if (! XineramaIsActive(dpy)) {
@ -359,6 +361,7 @@ static void initialize_xinerama (void) {
}
xinerama = 0;
xinerama_present = 0;
X_UNLOCK;
return;
}
xinerama_present = 1;
@ -385,6 +388,7 @@ static void initialize_xinerama (void) {
rfbLog("\n");
}
XFree_wr(xineramas);
X_UNLOCK;
return; /* must be OK w/o change */
}
@ -406,6 +410,7 @@ static void initialize_xinerama (void) {
sc++;
}
XFree_wr(xineramas);
X_UNLOCK;
if (sraRgnEmpty(black_region)) {

@ -143,6 +143,8 @@ static void handle_xrandr_change(int new_x, int new_y) {
RAWFB_RET_VOID
/* assumes no X_LOCK */
/* sanity check xrandr_mode */
if (! xrandr_mode) {
xrandr_mode = strdup("default");
@ -184,6 +186,8 @@ int check_xrandr_event(char *msg) {
RAWFB_RET(0)
/* it is assumed that X_LOCK is on at this point. */
if (subwin) {
return handle_subwin_resize(msg);
}
@ -235,8 +239,13 @@ int check_xrandr_event(char *msg) {
if (wdpy_x == rev->width && wdpy_y == rev->height &&
xrandr_rotation == (int) rev->rotation) {
rfbLog("check_xrandr_event: no change detected.\n");
rfbLog("check_xrandr_event: no change detected.\n");
do_change = 0;
if (! xrandr) {
rfbLog("check_xrandr_event: "
"enabling full XRANDR trapping anyway.\n");
xrandr = 1;
}
} else {
do_change = 1;
if (! xrandr) {
@ -256,6 +265,7 @@ int check_xrandr_event(char *msg) {
XRRUpdateConfiguration(&xev);
if (do_change) {
/* under do_change caller normally returns before its X_UNLOCK */
X_UNLOCK;
handle_xrandr_change(rev->width, rev->height);
}

Loading…
Cancel
Save