Commit ed986a0b authored by runge's avatar runge

x11vnc options -vncconnect, -connect, -remap,

 -debug_pointer, and -debug_keyboard
 add reverse connections, keysym remapping,
 and debug output option
parent 74b9f7de
2004-03-10 Karl Runge <runge@karlrunge.com>
* x11vnc options -vncconnect, -connect, -remap,
-debug_pointer, and -debug_keyboard
* support reverse connections, vncconnect(1), etc.
* expt. with user supplied keysym remapping.
* debug output option for pointer and keyboard.
2004-02-29 Johannes E. Schindelin <Johannes.Schindelin@gmx.de> 2004-02-29 Johannes E. Schindelin <Johannes.Schindelin@gmx.de>
* fixed warning of valgrind for regiontest * fixed warning of valgrind for regiontest
......
2004-03-10 Karl Runge <runge@karlrunge.com>
* added reverse connection for vncconnect(1) and other means
-vncconnect, -connect host:port, and -connect watchfile
* added first pass at user keysym remapping feature via
-remap file. Ignores modifier state, need to generalize.
* debugging options for users -debug_pointer and -debug_keyboard
* clear -passwd from argv for privacy (if OS allows).
2004-02-19 Karl Runge <runge@karlrunge.com> 2004-02-19 Karl Runge <runge@karlrunge.com>
* added handling of clipboard/selection exchange to/from clients, * added handling of clipboard/selection exchange to/from clients,
even holds PRIMARY which Xvnc does not do. disable with -nosel. even holds PRIMARY which Xvnc does not do. disable with -nosel.
......
...@@ -180,8 +180,13 @@ int flash_cmap = 0; /* follow installed colormaps */ ...@@ -180,8 +180,13 @@ int flash_cmap = 0; /* follow installed colormaps */
int force_indexed_color = 0; /* whether to force indexed color for 8bpp */ int force_indexed_color = 0; /* whether to force indexed color for 8bpp */
int use_modifier_tweak = 0; /* use the altgr_keyboard modifier tweak */ int use_modifier_tweak = 0; /* use the altgr_keyboard modifier tweak */
char *remap_file = NULL; /* user supplied remapping file */
int nofb = 0; /* do not send any fb updates */ int nofb = 0; /* do not send any fb updates */
char *client_connect = NULL; /* strings for -connect option */
char *client_connect_file = NULL;
int vnc_connect = 0; /* -vncconnect option */
int local_cursor = 1; /* whether the viewer draws a local cursor */ int local_cursor = 1; /* whether the viewer draws a local cursor */
int show_mouse = 0; /* display a cursor for the real mouse */ int show_mouse = 0; /* display a cursor for the real mouse */
int show_root_cursor = 0; /* show X when on root background */ int show_root_cursor = 0; /* show X when on root background */
...@@ -213,7 +218,7 @@ VisualID visual_id = (VisualID) 0; ...@@ -213,7 +218,7 @@ VisualID visual_id = (VisualID) 0;
int visual_depth = 0; int visual_depth = 0;
int nap_ok = 0, nap_diff_count = 0; int nap_ok = 0, nap_diff_count = 0;
time_t last_event, last_input; time_t last_event, last_input, last_client = 0;
/* tile heuristics: */ /* tile heuristics: */
double fs_frac = 0.75; /* threshold tile fraction to do fullscreen updates. */ double fs_frac = 0.75; /* threshold tile fraction to do fullscreen updates. */
...@@ -241,6 +246,9 @@ int scan_in_progress = 0; ...@@ -241,6 +246,9 @@ int scan_in_progress = 0;
int fb_copy_in_progress = 0; int fb_copy_in_progress = 0;
int shut_down = 0; int shut_down = 0;
int debug_pointer = 0;
int debug_keyboard = 0;
int quiet = 0; int quiet = 0;
double dtime(double *); double dtime(double *);
...@@ -418,6 +426,197 @@ int check_access(char *addr) { ...@@ -418,6 +426,197 @@ int check_access(char *addr) {
return allowed; return allowed;
} }
/*
* For the -connect <file> option: periodically read the file looking for
* a connect string. If one is found set client_connect to it.
*/
void check_connect_file(char *file) {
FILE *in;
char line[512], host[512];
static int first_warn = 1, truncate_ok = 1;
static time_t last_time = 0;
time_t now = time(0);
if (now - last_time < 1) {
/* check only once a second */
return;
}
last_time = now;
if (! truncate_ok) {
/* check if permissions changed */
if (access(file, W_OK) == 0) {
truncate_ok = 1;
} else {
return;
}
}
in = fopen(file, "r");
if (in == NULL) {
if (first_warn) {
rfbLog("check_connect_file: fopen failure: %s\n", file);
perror("fopen");
first_warn = 0;
}
return;
}
if (fgets(line, 512, in) != NULL) {
if (sscanf(line, "%s", host) == 1) {
if (strlen(host) > 0) {
client_connect = strdup(host);
rfbLog("read connect file: %s\n", host);
}
}
}
fclose(in);
/* truncate file */
in = fopen(file, "w");
if (in != NULL) {
fclose(in);
} else {
/* disable if we cannot truncate */
rfbLog("check_connect_file: could not truncate %s, "
"disabling checking.\n", file);
truncate_ok = 0;
}
}
/* Do a reverse connect for a single "host" or "host:port" */
int do_reverse_connect(char *str) {
rfbClientPtr cl;
char *host, *p;
int port = 5500, len = strlen(str);
if (len < 1) {
return;
}
if (len > 512) {
rfbLog("reverse_connect: string too long: %d bytes\n", len);
return;
}
/* copy in to host */
host = (char *) malloc((size_t) len+1);
if (! host) {
rfbLog("reverse_connect: could not malloc string %d\n", len);
return;
}
strncpy(host, str, len);
host[len] = '\0';
/* extract port, if any */
if ((p = strchr(host, ':')) != NULL) {
port = atoi(p+1);
*p = '\0';
}
cl = rfbReverseConnection(screen, host, port);
free(host);
if (cl == NULL) {
rfbLog("reverse_connect: %s failed\n", str);
return 0;
} else {
rfbLog("reverse_connect: %s/%s OK\n", str, cl->host);
return 1;
}
}
void rfbPE(rfbScreenInfoPtr scr, long us) {
if (! use_threads) {
return rfbProcessEvents(scr, us);
}
}
/* break up comma separated list of hosts and call do_reverse_connect() */
void reverse_connect(char *str) {
char *p, *tmp = strdup(str);
int sleep_between_host = 300;
int sleep_min = 1500, sleep_max = 4500, n_max = 5;
int n, tot, t, dt = 100, cnt = 0;
p = strtok(tmp, ",");
while (p) {
if ((n = do_reverse_connect(p)) != 0) {
rfbPE(screen, -1);
}
cnt += n;
p = strtok(NULL, ",");
if (p) {
t = 0;
while (t < sleep_between_host) {
usleep(dt * 1000);
rfbPE(screen, -1);
t += dt;
}
}
}
free(tmp);
if (cnt == 0) {
return;
}
/*
* 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.
*/
n = cnt;
if (n >= n_max) {
n = n_max;
}
t = sleep_max - sleep_min;
tot = sleep_min + ((n-1) * t) / (n_max-1);
t = 0;
while (t < tot) {
rfbPE(screen, -1);
usleep(dt * 1000);
t += dt;
}
}
/* check if client_connect has been set, if so make the reverse connections. */
void send_client_connect() {
if (client_connect != NULL) {
reverse_connect(client_connect);
free(client_connect);
client_connect = NULL;
}
}
/* string for the VNC_CONNECT property */
#define VNC_CONNECT_MAX 512
char vnc_connect_str[VNC_CONNECT_MAX+1];
/* monitor the various input methods */
void check_connect_inputs() {
/* flush any already set: */
send_client_connect();
/* connect file: */
if (client_connect_file != NULL) {
check_connect_file(client_connect_file);
}
send_client_connect();
/* VNC_CONNECT property (vncconnect program) */
if (vnc_connect && *vnc_connect_str != '\0') {
client_connect = strdup(vnc_connect_str);
vnc_connect_str[0] = '\0';
}
send_client_connect();
}
/* /*
* libvncserver callback for when a new client connects * libvncserver callback for when a new client connects
*/ */
...@@ -446,6 +645,7 @@ enum rfbNewClientAction new_client(rfbClientPtr client) { ...@@ -446,6 +645,7 @@ enum rfbNewClientAction new_client(rfbClientPtr client) {
client->clientData = (void *) 0; client->clientData = (void *) 0;
} }
accepted_client = 1; accepted_client = 1;
last_client = time(0);
return(RFB_CLIENT_ACCEPT); return(RFB_CLIENT_ACCEPT);
} }
...@@ -460,7 +660,7 @@ char mod_state = 0; ...@@ -460,7 +660,7 @@ char mod_state = 0;
char modifiers[0x100]; char modifiers[0x100];
KeyCode keycodes[0x100], left_shift_code, right_shift_code, altgr_code; KeyCode keycodes[0x100], left_shift_code, right_shift_code, altgr_code;
void initialize_keycodes() { void initialize_modtweak() {
KeySym key, *keymap; KeySym key, *keymap;
int i, j, minkey, maxkey, syms_per_keycode; int i, j, minkey, maxkey, syms_per_keycode;
...@@ -508,25 +708,105 @@ void initialize_keycodes() { ...@@ -508,25 +708,105 @@ void initialize_keycodes() {
XFree ((void *) keymap); XFree ((void *) keymap);
} }
void DebugXTestFakeKeyEvent(Display* dpy, KeyCode keysym, Bool down, time_t cur_time) /*
* The following is for an experimental -remap option to allow the user
* to remap keystrokes. It is currently confusing wrt modifiers...
*/
typedef struct keyremap {
KeySym before;
KeySym after;
struct keyremap *next;
} keyremap_t;
keyremap_t *keyremaps = NULL;
void initialize_remap(char *infile) {
FILE *in;
char *p, line[256], str1[256], str2[256];
int i;
KeySym ksym1, ksym2;
keyremap_t *remap, *current;
in = fopen(infile, "r");
if (in == NULL) {
rfbLog("remap: cannot open: %s\n", infile);
perror("fopen");
clean_up_exit(1);
}
while (fgets(line, 256, in) != NULL) {
int blank = 1;
p = line;
while (*p) {
if (! isspace(*p)) {
blank = 0;
break;
}
p++;
}
if (blank) {
continue;
}
if (strchr(line, '#')) {
continue;
}
if (sscanf(line, "%s %s", str1, str2) != 2) {
rfbLog("remap: bad line: %s\n", line);
fclose(in);
clean_up_exit(1);
}
if (sscanf(str1, "0x%x", &i) == 1) {
ksym1 = (KeySym) i;
} else {
ksym1 = XStringToKeysym(str1);
}
if (sscanf(str2, "0x%x", &i) == 1) {
ksym2 = (KeySym) i;
} else {
ksym2 = XStringToKeysym(str2);
}
if (ksym1 == NoSymbol || ksym2 == NoSymbol) {
rfbLog("warning: skipping bad remap line: %s", line);
continue;
}
remap = (keyremap_t *) malloc((size_t) sizeof(keyremap_t));
remap->before = ksym1;
remap->after = ksym2;
remap->next = NULL;
rfbLog("remapping: (%s, 0x%x) -> (%s, 0x%x)\n", str1, ksym1,
str2, ksym2);
if (keyremaps == NULL) {
keyremaps = remap;
} else {
current->next = remap;
}
current = remap;
}
fclose(in);
}
void DebugXTestFakeKeyEvent(Display* dpy, KeyCode key, Bool down, time_t cur_time)
{ {
rfbLog("XTestFakeKeyEvent(dpy,%s(0x%x),%s,CurrentTime)\n", if (debug_keyboard) {
XKeysymToString(XKeycodeToKeysym(dpy,keysym,0)),keysym, rfbLog("XTestFakeKeyEvent(dpy, keycode=0x%x \"%s\", %s)\n",
down?"down":"up"); key, XKeysymToString(XKeycodeToKeysym(dpy, key, 0)),
XTestFakeKeyEvent(dpy,keysym,down,cur_time); down ? "down":"up");
}
XTestFakeKeyEvent(dpy, key, down, cur_time);
} }
/* /*
* Uncomment the two lines to aid in debugging keymapping problems. * This is to allow debug_keyboard option trap everything:
*/ */
/*
#define XTestFakeKeyEvent DebugXTestFakeKeyEvent #define XTestFakeKeyEvent DebugXTestFakeKeyEvent
#define DebugKeyEvent
*/
void tweak_mod(signed char mod, rfbBool down) { void tweak_mod(signed char mod, rfbBool down) {
rfbBool is_shift = mod_state & (LEFTSHIFT|RIGHTSHIFT); rfbBool is_shift = mod_state & (LEFTSHIFT|RIGHTSHIFT);
Bool dn = (Bool) down; Bool dn = (Bool) down;
if (debug_keyboard) {
rfbLog("tweak_mod: down=%d mod=0x%x\n", down, mod);
}
if (mod < 0) { if (mod < 0) {
return; return;
...@@ -556,6 +836,10 @@ void tweak_mod(signed char mod, rfbBool down) { ...@@ -556,6 +836,10 @@ void tweak_mod(signed char mod, rfbBool down) {
static void modifier_tweak_keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) { static void modifier_tweak_keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) {
KeyCode k; KeyCode k;
int tweak = 0; int tweak = 0;
if (debug_keyboard) {
rfbLog("modifier_tweak_keyboard: %s keysym=0x%x\n",
down ? "down" : "up", (int) keysym);
}
if (view_only) { if (view_only) {
return; return;
...@@ -601,17 +885,36 @@ static void modifier_tweak_keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr ...@@ -601,17 +885,36 @@ static void modifier_tweak_keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr
static void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) { static void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) {
KeyCode k; KeyCode k;
#ifdef DebugKeyEvent if (debug_keyboard) {
X_LOCK; X_LOCK;
rfbLog("keyboard(%s,%s(0x%x),client)\n", rfbLog("keyboard(%s, 0x%x \"%s\")\n", down ? "down":"up",
down?"down":"up",XKeysymToString(keysym),(int)keysym); (int) keysym, XKeysymToString(keysym));
X_UNLOCK; X_UNLOCK;
#endif }
if (view_only) { if (view_only) {
return; return;
} }
if (keyremaps) {
keyremap_t *remap = keyremaps;
while (remap != NULL) {
if (remap->before == keysym) {
keysym = remap->after;
if (debug_keyboard) {
rfbLog("keyboard(): remapping keysym: "
"0x%x \"%s\" -> 0x%x \"%s\"\n",
(int) remap->before,
XKeysymToString(remap->before),
(int) remap->after,
XKeysymToString(remap->after));
}
break;
}
remap = remap->next;
}
}
if (use_modifier_tweak) { if (use_modifier_tweak) {
modifier_tweak_keyboard(down, keysym, client); modifier_tweak_keyboard(down, keysym, client);
X_LOCK; X_LOCK;
...@@ -624,6 +927,11 @@ static void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) { ...@@ -624,6 +927,11 @@ static void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) {
k = XKeysymToKeycode(dpy, (KeySym) keysym); k = XKeysymToKeycode(dpy, (KeySym) keysym);
if (debug_keyboard) {
rfbLog("keyboard(): KeySym 0x%x \"%s\" -> KeyCode 0x%x\n",
(int) keysym, XKeysymToString(keysym), (int) k);
}
if ( k != NoSymbol ) { if ( k != NoSymbol ) {
XTestFakeKeyEvent(dpy, k, (Bool) down, CurrentTime); XTestFakeKeyEvent(dpy, k, (Bool) down, CurrentTime);
XFlush(dpy); XFlush(dpy);
...@@ -677,6 +985,10 @@ void init_pointer(void) { ...@@ -677,6 +985,10 @@ void init_pointer(void) {
n = atoi(p+1); n = atoi(p+1);
if (n < num_buttons || num_buttons == 0) { if (n < num_buttons || num_buttons == 0) {
num_buttons = n; num_buttons = n;
} else {
rfbLog("warning: increasing number of mouse "
"buttons from %d to %d\n", num_buttons, n);
num_buttons = n;
} }
} }
if ((q = strchr(pointer_remap, '-')) != NULL) { if ((q = strchr(pointer_remap, '-')) != NULL) {
...@@ -710,6 +1022,10 @@ void init_pointer(void) { ...@@ -710,6 +1022,10 @@ void init_pointer(void) {
*/ */
static void pointer(int mask, int x, int y, rfbClientPtr client) { static void pointer(int mask, int x, int y, rfbClientPtr client) {
if (debug_pointer && mask >= 0) {
rfbLog("pointer(mask: 0x%x, x:%4d, y:%4d)\n", mask, x, y);
}
if (view_only) { if (view_only) {
return; return;
} }
...@@ -777,12 +1093,19 @@ static void pointer(int mask, int x, int y, rfbClientPtr client) { ...@@ -777,12 +1093,19 @@ static void pointer(int mask, int x, int y, rfbClientPtr client) {
ev[i][1] = x; ev[i][1] = x;
ev[i][2] = y; ev[i][2] = y;
UNLOCK(pointerMutex); UNLOCK(pointerMutex);
if (debug_pointer) {
rfbLog("pointer(): deferring event "
"%d\n", i);
}
return; return;
} }
} }
/* time to send the queue */ /* time to send the queue */
for (i=0; i<nevents; i++) { for (i=0; i<nevents; i++) {
if (debug_pointer) {
rfbLog("pointer(): sending event %d\n", i+1);
}
update_pointer(ev[i][0], ev[i][1], ev[i][2]); update_pointer(ev[i][0], ev[i][1], ev[i][2]);
} }
if (nevents && dt > maxwait) { if (nevents && dt > maxwait) {
...@@ -798,6 +1121,9 @@ static void pointer(int mask, int x, int y, rfbClientPtr client) { ...@@ -798,6 +1121,9 @@ static void pointer(int mask, int x, int y, rfbClientPtr client) {
UNLOCK(pointerMutex); UNLOCK(pointerMutex);
} }
if (mask < 0) { /* -1 just means flush the event queue */ if (mask < 0) { /* -1 just means flush the event queue */
if (debug_pointer > 1) {
rfbLog("pointer(): flush only.\n");
}
return; return;
} }
...@@ -824,6 +1150,10 @@ void update_pointer(int mask, int x, int y) { ...@@ -824,6 +1150,10 @@ void update_pointer(int mask, int x, int y) {
for (i=0; i < MAX_BUTTONS; i++) { for (i=0; i < MAX_BUTTONS; i++) {
/* look for buttons that have be clicked or released: */ /* look for buttons that have be clicked or released: */
if ( (button_mask & (1<<i)) != (mask & (1<<i)) ) { if ( (button_mask & (1<<i)) != (mask & (1<<i)) ) {
if (debug_pointer) {
rfbLog("pointer(): mask change: mask: 0x%x -> "
"0x%x button: %d\n", button_mask, mask,i+1);
}
mb = pointer_map[i+1]; mb = pointer_map[i+1];
if (num_buttons && mb > num_buttons) { if (num_buttons && mb > num_buttons) {
rfbLog("ignoring mouse button out of bounds: %d" rfbLog("ignoring mouse button out of bounds: %d"
...@@ -1128,62 +1458,132 @@ void selection_send(XEvent *ev) { ...@@ -1128,62 +1458,132 @@ void selection_send(XEvent *ev) {
rfbSendServerCutText(screen, selection_str, newlen); rfbSendServerCutText(screen, selection_str, newlen);
} }
/*
* Routines for monitoring the VNC_CONNECT property for changes.
* The vncconnect(1) will set it on our X display.
*/
Atom vnc_connect_prop = None;
void read_vnc_connect_prop() {
Atom type;
int format, slen, dlen;
unsigned long nitems = 0, bytes_after = 0;
unsigned char* data = NULL;
vnc_connect_str[0] = '\0';
slen = 0;
if (! vnc_connect || vnc_connect_prop == None) {
/* not active or problem with VNC_CONNECT atom */
return;
}
/* read the property value into vnc_connect_str: */
do {
if (XGetWindowProperty(dpy, DefaultRootWindow(dpy),
vnc_connect_prop, nitems/4, VNC_CONNECT_MAX/16, False,
AnyPropertyType, &type, &format, &nitems, &bytes_after,
&data) == Success) {
dlen = nitems * (format/8);
if (slen + dlen > VNC_CONNECT_MAX) {
/* too big */
rfbLog("warning: truncating large VNC_CONNECT"
" string > %d bytes.\n", VNC_CONNECT_MAX);
XFree(data);
break;
}
memcpy(vnc_connect_str+slen, data, dlen);
slen += dlen;
vnc_connect_str[slen] = '\0';
XFree(data);
}
} while (bytes_after > 0);
vnc_connect_str[VNC_CONNECT_MAX] = '\0';
rfbLog("read property VNC_CONNECT: %s\n", vnc_connect_str);
}
/* /*
* This routine is periodically called to check for selection related * This routine is periodically called to check for selection related
* X11 events and respond to them as needed. * and other X11 events and respond to them as needed.
*/ */
void watch_selection_event() { void watch_xevents() {
XEvent xev; XEvent xev;
static int last_request = 0, first = 1, sent_sel = 0, starttime; static int first = 1, sent_sel = 0;
int have_clients = screen->rfbClientHead ? 1 : 0;
time_t last_request = 0, now = time(0);
X_LOCK; X_LOCK;
if (first) { if (first && (watch_selection || vnc_connect)) {
/* create fake window for our selection ownership, etc */
selwin = XCreateSimpleWindow(dpy, rootwin, 0, 0, 1, 1, 0, 0, 0);
/* /*
* register desired event(s) for notification. * register desired event(s) for notification.
* PropertyChangeMask is for CUT_BUFFER0 changes. * PropertyChangeMask is for CUT_BUFFER0 changes.
* TODO: does this cause a flood of other stuff? * TODO: does this cause a flood of other stuff?
*/ */
XSelectInput(dpy, rootwin, PropertyChangeMask); XSelectInput(dpy, rootwin, PropertyChangeMask);
starttime = time(0);
first = 0;
} }
if (first && watch_selection) {
/* create fake window for our selection ownership, etc */
selwin = XCreateSimpleWindow(dpy, rootwin, 0, 0, 1, 1, 0, 0, 0);
}
if (first && vnc_connect) {
vnc_connect_str[0] = '\0';
vnc_connect_prop = XInternAtom(dpy, "VNC_CONNECT", False);
}
first = 0;
/* /*
* There is a bug where we have to wait before sending text to * There is a bug where we have to wait before sending text to
* the client... so instead of sending right away we wait a * the client... so instead of sending right away we wait a
* the few seconds. * the few seconds.
*/ */
if (! sent_sel && time(0) > starttime + sel_waittime) { if (have_clients && watch_selection && ! sent_sel
&& now > last_client + sel_waittime) {
if (XGetSelectionOwner(dpy, XA_PRIMARY) == None) { if (XGetSelectionOwner(dpy, XA_PRIMARY) == None) {
cutbuffer_send(); cutbuffer_send();
} }
sent_sel = 1; sent_sel = 1;
} }
/* check for CUT_BUFFER0 change: */ /* check for CUT_BUFFER0 and VNC_CONNECT changes: */
if (XCheckTypedEvent(dpy, PropertyNotify, &xev)) { if (XCheckTypedEvent(dpy, PropertyNotify, &xev)) {
if (xev.type == PropertyNotify && if (xev.type == PropertyNotify) {
xev.xproperty.atom == XA_CUT_BUFFER0) { if (xev.xproperty.atom == XA_CUT_BUFFER0) {
/*
* Go retrieve CUT_BUFFER0 and send it.
*
* set_cutbuffer is a flag to try to avoid
* processing our own cutbuffer changes.
*/
if (have_clients && watch_selection
&& ! set_cutbuffer) {
cutbuffer_send();
sent_sel = 1;
}
set_cutbuffer = 0;
} else if (vnc_connect && vnc_connect_prop != None
&& xev.xproperty.atom == vnc_connect_prop) {
/* /*
* Go retrieve CUT_BUFFER0 and send it. * Go retrieve VNC_CONNECT string.
* */
* set_cutbuffer is a flag to try to avoid processing read_vnc_connect_prop();
* our own cutbuffer changes.
*/
if (! set_cutbuffer) {
cutbuffer_send();
sent_sel = 1;
} }
set_cutbuffer = 0;
} }
} }
if (! have_clients || ! watch_selection) {
/*
* no need to monitor selections if no current clients
* or -nosel.
*/
X_UNLOCK;
return;
}
/* check for our PRIMARY request notification: */ /* check for our PRIMARY request notification: */
if (watch_primary) { if (watch_primary) {
if (XCheckTypedEvent(dpy, SelectionNotify, &xev)) { if (XCheckTypedEvent(dpy, SelectionNotify, &xev)) {
...@@ -1194,20 +1594,20 @@ void watch_selection_event() { ...@@ -1194,20 +1594,20 @@ void watch_selection_event() {
xev.xselection.target == XA_STRING) { xev.xselection.target == XA_STRING) {
/* go retrieve PRIMARY and check it */ /* go retrieve PRIMARY and check it */
if (sent_sel || if (now > last_client + sel_waittime
time(0) > starttime + sel_waittime) { || sent_sel) {
selection_send(&xev); selection_send(&xev);
} }
} }
} }
if (time(0) > last_request + 1) { if (now > last_request + 1) {
/* /*
* Every second or two, request PRIMARY, unless we * Every second or two, request PRIMARY, unless we
* already own it or there is no owner. * already own it or there is no owner.
* TODO: even at this low rate we should look into * TODO: even at this low rate we should look into
* and performance problems in odds cases, etc. * and performance problems in odds cases, etc.
*/ */
last_request = time(0); last_request = now;
if (! own_selection && if (! own_selection &&
XGetSelectionOwner(dpy, XA_PRIMARY) != None) { XGetSelectionOwner(dpy, XA_PRIMARY) != None) {
XConvertSelection(dpy, XA_PRIMARY, XA_STRING, XConvertSelection(dpy, XA_PRIMARY, XA_STRING,
...@@ -3588,15 +3988,14 @@ void watch_loop(void) { ...@@ -3588,15 +3988,14 @@ void watch_loop(void) {
clean_up_exit(0); clean_up_exit(0);
} }
watch_xevents();
check_connect_inputs();
if (! screen->rfbClientHead) { /* waiting for a client */ if (! screen->rfbClientHead) { /* waiting for a client */
usleep(200 * 1000); usleep(200 * 1000);
continue; continue;
} }
if (watch_selection) {
watch_selection_event();
}
if (nofb) { /* no framebuffer polling needed */ if (nofb) { /* no framebuffer polling needed */
continue; continue;
} }
...@@ -3694,7 +4093,6 @@ int check_user_input(double dt, int *cnt) { ...@@ -3694,7 +4093,6 @@ int check_user_input(double dt, int *cnt) {
* likely they have all be sent already. * likely they have all be sent already.
*/ */
while (1) { while (1) {
//rfbProcessEvents(screen, 1000);
rfbCheckFds(screen, 1000); rfbCheckFds(screen, 1000);
XFlush(dpy); XFlush(dpy);
...@@ -3754,7 +4152,6 @@ int check_user_input(double dt, int *cnt) { ...@@ -3754,7 +4152,6 @@ int check_user_input(double dt, int *cnt) {
miss = 0; miss = 0;
for (i=0; i<split; i++) { for (i=0; i<split; i++) {
usleep(ms * 1000); usleep(ms * 1000);
//rfbProcessEvents(screen, 1000);
rfbCheckFds(screen, 1000); rfbCheckFds(screen, 1000);
spin += dtime(&tm); spin += dtime(&tm);
if (got_pointer_input > g) { if (got_pointer_input > g) {
...@@ -3822,6 +4219,12 @@ void print_help() { ...@@ -3822,6 +4219,12 @@ void print_help() {
"-shared VNC display is shared (default %s).\n" "-shared VNC display is shared (default %s).\n"
"-forever Keep listening for more connections rather than exiting\n" "-forever Keep listening for more connections rather than exiting\n"
" as soon as the first client(s) disconnect. Same as -many\n" " as soon as the first client(s) disconnect. Same as -many\n"
"-connect string For use with \"vncviewer -listen\" reverse connections. If\n"
" string has the form \"host\" or \"host:port\" the connection\n"
" is made once at startup. Use commas for a list. If string\n"
" contains \"/\" it is a file to periodically check for new\n"
" hosts. The first line is read and then file is truncated.\n"
"-vncconnect Monitor the VNC_CONNECT X property set by vncconnect(1).\n"
"-allow addr1[,addr2..] Only allow client connections from IP addresses matching\n" "-allow addr1[,addr2..] Only allow client connections from IP addresses matching\n"
" the comma separated list of numerical addresses. Can be\n" " the comma separated list of numerical addresses. Can be\n"
" a prefix, e.g. \"192.168.100.\" to match a simple subnet,\n" " a prefix, e.g. \"192.168.100.\" to match a simple subnet,\n"
...@@ -3845,10 +4248,13 @@ void print_help() { ...@@ -3845,10 +4248,13 @@ void print_help() {
"-modtweak Handle AltGr/Shift modifiers for differing languages\n" "-modtweak Handle AltGr/Shift modifiers for differing languages\n"
" between client and host (default %s).\n" " between client and host (default %s).\n"
"-nomodtweak Send the keysym directly to the X server.\n" "-nomodtweak Send the keysym directly to the X server.\n"
"-remap file Read keysym remappings from file. Format is one pair\n"
" of keysyms per line (can be string or the hex value).\n"
"-nobell Do not watch for XBell events.\n" "-nobell Do not watch for XBell events.\n"
"-nofb Ignore framebuffer: only process keyboard and pointer.\n" "-nofb Ignore framebuffer: only process keyboard and pointer.\n"
"-nosel Do not manage exchange of X selection/cutbuffer.\n" "-nosel Do not manage exchange of X selection/cutbuffer.\n"
"-noprimary Exchange X cutbuffer changes but not PRIMARY selection.\n" "-noprimary Do not poll the PRIMARY selection for changes and send\n"
" back to clients. PRIMARY is set for received changes.\n"
"\n" "\n"
"-nocursor Do not have the viewer show a local cursor.\n" "-nocursor Do not have the viewer show a local cursor.\n"
"-mouse Draw a 2nd cursor at the current X pointer position.\n" "-mouse Draw a 2nd cursor at the current X pointer position.\n"
...@@ -3865,6 +4271,8 @@ void print_help() { ...@@ -3865,6 +4271,8 @@ void print_help() {
" read n user input events before scanning display. n < 0\n" " read n user input events before scanning display. n < 0\n"
" means to act as though there is always user input.\n" " means to act as though there is always user input.\n"
"-old_copytile Do not use the new copy_tiles() framebuffer mechanism.\n" "-old_copytile Do not use the new copy_tiles() framebuffer mechanism.\n"
"-debug_pointer Print debugging output for every pointer event.\n"
"-debug_keyboard Print debugging output for every keyboard event.\n"
"\n" "\n"
"-defer time Time in ms to wait for updates before sending to\n" "-defer time Time in ms to wait for updates before sending to\n"
" client [rfbDeferUpdateTime] (default %d).\n" " client [rfbDeferUpdateTime] (default %d).\n"
...@@ -3959,6 +4367,7 @@ int main(int argc, char** argv) { ...@@ -3959,6 +4367,7 @@ int main(int argc, char** argv) {
int i, op, ev, er, maj, min; int i, op, ev, er, maj, min;
char *use_dpy = NULL; char *use_dpy = NULL;
char *visual_str = NULL; char *visual_str = NULL;
int pw_loc = -1;
int dt = 0; int dt = 0;
int bg = 0; int bg = 0;
int got_waitms = 0; int got_waitms = 0;
...@@ -3996,6 +4405,15 @@ int main(int argc, char** argv) { ...@@ -3996,6 +4405,15 @@ int main(int argc, char** argv) {
} else if (!strcmp(argv[i], "-many") } else if (!strcmp(argv[i], "-many")
|| !strcmp(argv[i], "-forever")) { || !strcmp(argv[i], "-forever")) {
connect_once = 0; connect_once = 0;
} else if (!strcmp(argv[i], "-connect")) {
i++;
if (strchr(argv[i], '/')) {
client_connect_file = argv[i];
} else {
client_connect = strdup(argv[i]);
}
} else if (!strcmp(argv[i], "-vncconnect")) {
vnc_connect = 1;
} else if (!strcmp(argv[i], "-inetd")) { } else if (!strcmp(argv[i], "-inetd")) {
inetd = 1; inetd = 1;
} else if (!strcmp(argv[i], "-noshm")) { } else if (!strcmp(argv[i], "-noshm")) {
...@@ -4006,6 +4424,8 @@ int main(int argc, char** argv) { ...@@ -4006,6 +4424,8 @@ int main(int argc, char** argv) {
use_modifier_tweak = 1; use_modifier_tweak = 1;
} else if (!strcmp(argv[i], "-nomodtweak")) { } else if (!strcmp(argv[i], "-nomodtweak")) {
use_modifier_tweak = 0; use_modifier_tweak = 0;
} else if (!strcmp(argv[i], "-remap")) {
remap_file = argv[++i];
} else if (!strcmp(argv[i], "-nobell")) { } else if (!strcmp(argv[i], "-nobell")) {
watch_bell = 0; watch_bell = 0;
} else if (!strcmp(argv[i], "-nofb")) { } else if (!strcmp(argv[i], "-nofb")) {
...@@ -4036,6 +4456,10 @@ int main(int argc, char** argv) { ...@@ -4036,6 +4456,10 @@ int main(int argc, char** argv) {
old_pointer = 1; old_pointer = 1;
} else if (!strcmp(argv[i], "-old_copytile")) { } else if (!strcmp(argv[i], "-old_copytile")) {
single_copytile = 1; single_copytile = 1;
} else if (!strcmp(argv[i], "-debug_pointer")) {
debug_pointer++;
} else if (!strcmp(argv[i], "-debug_keyboard")) {
debug_keyboard++;
} else if (!strcmp(argv[i], "-defer")) { } else if (!strcmp(argv[i], "-defer")) {
defer_update = atoi(argv[++i]); defer_update = atoi(argv[++i]);
} else if (!strcmp(argv[i], "-wait")) { } else if (!strcmp(argv[i], "-wait")) {
...@@ -4074,13 +4498,33 @@ int main(int argc, char** argv) { ...@@ -4074,13 +4498,33 @@ int main(int argc, char** argv) {
if (!strcmp(argv[i], "-desktop")) { if (!strcmp(argv[i], "-desktop")) {
dt = 1; dt = 1;
} }
if (!strcmp(argv[i], "-passwd")) {
pw_loc = i;
}
/* otherwise copy it for use below. */ /* otherwise copy it for use below. */
if (! quiet) { if (! quiet && i != pw_loc && i != pw_loc+1) {
fprintf(stderr, "passing arg to libvncserver: %s\n", fprintf(stderr, "passing arg to libvncserver: %s\n",
argv[i]); argv[i]);
} }
if (argc2 < 100) { if (argc2 < 100) {
argv2[argc2++] = argv[i]; argv2[argc2++] = strdup(argv[i]);
}
}
}
/*
* 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';
} }
} }
} }
...@@ -4312,7 +4756,10 @@ int main(int argc, char** argv) { ...@@ -4312,7 +4756,10 @@ int main(int argc, char** argv) {
set_signals(); set_signals();
if (use_modifier_tweak) { if (use_modifier_tweak) {
initialize_keycodes(); initialize_modtweak();
}
if (remap_file != NULL) {
initialize_remap(remap_file);
} }
if (screen->rfbPort) { if (screen->rfbPort) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment