x11vnc: the big split.

pull/1/head
runge 19 years ago
parent def3012663
commit 71f2ec7918

@ -1,3 +1,7 @@
2006-01-08 Karl Runge <runge@karlrunge.com>
* x11vnc: the big split. (and -afteraccept and -passwdfile read:..)
* examples/pnmshow24.c: fix typo.
2006-01-08 Karl Runge <runge@karlrunge.com>
* libvncclient/vncviewer.c: fix non-jpeg/libz builds.
* examples/pnmshow24.c: fix non-ALLOW24BPP builds.

@ -4,7 +4,8 @@
#ifndef LIBVNCSERVER_ALLOW24BPP
int main() {
printf("I need the ALLOW24BPP LibVNCSever flag to work\n");
printf("I need the ALLOW24BPP LibVNCServer flag to work\n");
exit(1);
}
#else

@ -1,3 +1,6 @@
2006-01-08 Karl Runge <runge@karlrunge.com>
* x11vnc: the big split. opts: -afteraccept and -passwdfile read:
2005-12-24 Karl Runge <runge@karlrunge.com>
* x11vnc: enhance -passwdfile features, filetransfer on by default,
call rfbRegisterTightVNCFileTransferExtension() earlier.

@ -13,7 +13,7 @@ endif
if HAVE_X
bin_PROGRAMS=x11vnc
x11vnc_SOURCES=x11vnc.c tkx11vnc.h
x11vnc_SOURCES = cleanup.c connections.c cursor.c gui.c help.c inet.c keyboard.c options.c pointer.c rates.c remote.c scan.c screen.c selection.c solid.c user.c userinput.c util.c win_utils.c x11vnc.c x11vnc_defs.c xdamage.c xevents.c xinerama.c xkb_bell.c xrandr.c xrecord.c xwrappers.c allowed_input_t.h blackout_t.h cleanup.h connections.h cursor.h enums.h gui.h help.h inet.h keyboard.h options.h params.h pointer.h rates.h remote.h scan.h screen.h scrollevent_t.h selection.h solid.h tkx11vnc.h user.h userinput.h util.h win_utils.h winattr_t.h x11vnc.h xdamage.h xevents.h xinerama.h xkb_bell.h xrandr.h xrecord.h xwrappers.h
INCLUDES=@X_CFLAGS@
x11vnc_LDADD=@X_LIBS@ $(LD_CYGIPC) $(LDADD)
endif

File diff suppressed because it is too large Load Diff

@ -0,0 +1,12 @@
#ifndef _X11VNC_ALLOWED_INPUT_T_H
#define _X11VNC_ALLOWED_INPUT_T_H
/* -- allowed_input_t.h -- */
typedef struct allowed_input {
int keystroke;
int motion;
int button;
} allowed_input_t;
#endif /* _X11VNC_ALLOWED_INPUT_T_H */

@ -0,0 +1,17 @@
#ifndef _X11VNC_BLACKOUT_T_H
#define _X11VNC_BLACKOUT_T_H
/* -- blackout_t.h -- */
typedef struct bout {
int x1, y1, x2, y2;
} blackout_t;
#define BO_MAX 32
typedef struct tbout {
blackout_t bo[BO_MAX]; /* hardwired max rectangles. */
int cover;
int count;
} tile_blackout_t;
#endif /* _X11VNC_BLACKOUT_T_H */

@ -0,0 +1,427 @@
/* -- cleanup.c -- */
#include "x11vnc.h"
#include "xwrappers.h"
#include "xdamage.h"
#include "remote.h"
#include "keyboard.h"
#include "scan.h"
#include "gui.h"
#include "solid.h"
/*
* Exiting and error handling routines
*/
int trapped_xerror = 0;
int trapped_xioerror = 0;
int trapped_getimage_xerror = 0;
int trapped_record_xerror = 0;
XErrorEvent *trapped_xerror_event;
/* XXX CHECK BEFORE RELEASE */
int crash_debug = 0;
void clean_shm(int quick);
void clean_up_exit (int ret);
int trap_xerror(Display *d, XErrorEvent *error);
int trap_xioerror(Display *d);
int trap_getimage_xerror(Display *d, XErrorEvent *error);
char *xerror_string(XErrorEvent *error);
void initialize_crash_handler(void);
void initialize_signals(void);
int known_sigpipe_mode(char *s);
static int exit_flag = 0;
static int exit_sig = 0;
static void clean_icon_mode(void);
static int Xerror(Display *d, XErrorEvent *error);
static int XIOerr(Display *d);
static void crash_shell_help(void);
static void crash_shell(void);
static void interrupted (int sig);
void clean_shm(int quick) {
int i, cnt = 0;
if (raw_fb) quick = 1; /* raw_fb hack */
/*
* to avoid deadlock, etc, under quick=1 we just delete the shm
* areas and leave the X stuff hanging.
*/
if (quick) {
shm_delete(&scanline_shm);
shm_delete(&fullscreen_shm);
shm_delete(&snaprect_shm);
} else {
shm_clean(&scanline_shm, scanline);
shm_clean(&fullscreen_shm, fullscreen);
shm_clean(&snaprect_shm, snaprect);
}
/*
* Here we have to clean up quite a few shm areas for all
* the possible tile row runs (40 for 1280), not as robust
* as one might like... sometimes need to run ipcrm(1).
*/
for(i=1; i<=ntiles_x; i++) {
if (i > tile_shm_count) {
break;
}
if (quick) {
shm_delete(&tile_row_shm[i]);
} else {
shm_clean(&tile_row_shm[i], tile_row[i]);
}
cnt++;
if (single_copytile_count && i >= single_copytile_count) {
break;
}
}
if (!quiet) {
rfbLog("deleted %d tile_row polling images.\n", cnt);
}
}
static void clean_icon_mode(void) {
if (icon_mode && icon_mode_fh) {
fprintf(icon_mode_fh, "quit\n");
fflush(icon_mode_fh);
fclose(icon_mode_fh);
icon_mode_fh = NULL;
if (icon_mode_file) {
unlink(icon_mode_file);
icon_mode_file = NULL;
}
}
}
/*
* Normal exiting
*/
void clean_up_exit (int ret) {
exit_flag = 1;
if (icon_mode) {
clean_icon_mode();
}
/* remove the shm areas: */
clean_shm(0);
if (! dpy) exit(ret); /* raw_rb hack */
/* X keyboard cleanups */
delete_added_keycodes(0);
if (clear_mods == 1) {
clear_modifiers(0);
} else if (clear_mods == 2) {
clear_keys();
}
if (no_autorepeat) {
autorepeat(1, 0);
}
if (use_solid_bg) {
solid_bg(1);
}
X_LOCK;
XTestDiscard_wr(dpy);
#if LIBVNCSERVER_HAVE_LIBXDAMAGE
if (xdamage) {
XDamageDestroy(dpy, xdamage);
}
#endif
#if LIBVNCSERVER_HAVE_LIBXTRAP
if (trap_ctx) {
XEFreeTC(trap_ctx);
}
#endif
/* XXX rdpy_ctrl, etc. cannot close w/o blocking */
XCloseDisplay(dpy);
X_UNLOCK;
fflush(stderr);
exit(ret);
}
/* X11 error handlers */
static XErrorHandler Xerror_def;
static XIOErrorHandler XIOerr_def;
int trap_xerror(Display *d, XErrorEvent *error) {
trapped_xerror = 1;
trapped_xerror_event = error;
if (d) {} /* unused vars warning: */
return 0;
}
int trap_xioerror(Display *d) {
trapped_xioerror = 1;
if (d) {} /* unused vars warning: */
return 0;
}
int trap_getimage_xerror(Display *d, XErrorEvent *error) {
trapped_getimage_xerror = 1;
trapped_xerror_event = error;
if (d) {} /* unused vars warning: */
return 0;
}
static int Xerror(Display *d, XErrorEvent *error) {
X_UNLOCK;
interrupted(0);
if (d) {} /* unused vars warning: */
return (*Xerror_def)(d, error);
}
static int XIOerr(Display *d) {
X_UNLOCK;
interrupted(-1);
if (d) {} /* unused vars warning: */
return (*XIOerr_def)(d);
}
static char *xerrors[] = {
"Success",
"BadRequest",
"BadValue",
"BadWindow",
"BadPixmap",
"BadAtom",
"BadCursor",
"BadFont",
"BadMatch",
"BadDrawable",
"BadAccess",
"BadAlloc",
"BadColor",
"BadGC",
"BadIDChoice",
"BadName",
"BadLength",
"BadImplementation",
"unknown"
};
static int xerrors_max = BadImplementation;
char *xerror_string(XErrorEvent *error) {
int index = -1;
if (error) {
index = (int) error->error_code;
}
if (0 <= index && index <= xerrors_max) {
return xerrors[index];
} else {
return xerrors[xerrors_max+1];
}
}
static char *crash_stack_command1 = NULL;
static char *crash_stack_command2 = NULL;
static char *crash_debug_command = NULL;
void initialize_crash_handler(void) {
int pid = program_pid;
crash_stack_command1 = (char *) malloc(1000);
crash_stack_command2 = (char *) malloc(1000);
crash_debug_command = (char *) malloc(1000);
snprintf(crash_stack_command1, 500, "echo where > /tmp/gdb.%d;"
" env PATH=$PATH:/usr/local/bin:/usr/sfw/bin:/usr/bin"
" gdb -x /tmp/gdb.%d -batch -n %s %d;"
" rm -f /tmp/gdb.%d", pid, pid, program_name, pid, pid);
snprintf(crash_stack_command2, 500, "pstack %d", program_pid);
snprintf(crash_debug_command, 500, "gdb %s %d", program_name, pid);
}
static void crash_shell_help(void) {
int pid = program_pid;
fprintf(stderr, "\n");
fprintf(stderr, " *** Welcome to the x11vnc crash shell! ***\n");
fprintf(stderr, "\n");
fprintf(stderr, "PROGRAM: %s PID: %d\n", program_name, pid);
fprintf(stderr, "\n");
fprintf(stderr, "POSSIBLE DEBUGGER COMMAND:\n");
fprintf(stderr, "\n");
fprintf(stderr, " %s\n", crash_debug_command);
fprintf(stderr, "\n");
fprintf(stderr, "Press \"q\" to quit.\n");
fprintf(stderr, "Press \"h\" or \"?\" for this help.\n");
fprintf(stderr, "Press \"s\" to try to run some commands to"
" show a stack trace (gdb/pstack).\n");
fprintf(stderr, "\n");
fprintf(stderr, "Anything else is passed to -Q query function.\n");
fprintf(stderr, "\n");
}
static void crash_shell(void) {
char qry[1000], cmd[1000], line[1000];
char *str, *p;
crash_shell_help();
fprintf(stderr, "\ncrash> ");
while (fgets(line, 1000, stdin) != NULL) {
str = lblanks(line);
p = str;
while(*p) {
if (*p == '\n') {
*p = '\0';
}
p++;
}
if (*str == 'q' && *(str+1) == '\0') {
fprintf(stderr, "quiting.\n");
return;
} else if (*str == 'h' && *(str+1) == '\0') {
crash_shell_help();
} else if (*str == '?' && *(str+1) == '\0') {
crash_shell_help();
} else if (*str == 's' && *(str+1) == '\0') {
sprintf(cmd, "sh -c '(%s) &'", crash_stack_command1);
fprintf(stderr, "\nrunning:\n\t%s\n\n",
crash_stack_command1);
system(cmd);
usleep(1000*1000);
sprintf(cmd, "sh -c '(%s) &'", crash_stack_command2);
fprintf(stderr, "\nrunning:\n\t%s\n\n",
crash_stack_command2);
system(cmd);
usleep(1000*1000);
} else {
snprintf(qry, 1000, "qry=%s", str);
p = process_remote_cmd(qry, 1);
fprintf(stderr, "\n\nresult:\n%s\n", p);
free(p);
}
fprintf(stderr, "crash> ");
}
}
/*
* General problem handler
*/
static void interrupted (int sig) {
exit_sig = sig;
if (exit_flag) {
exit_flag++;
if (use_threads) {
usleep2(250 * 1000);
} else if (exit_flag <= 2) {
return;
}
exit(4);
}
exit_flag++;
if (sig == 0) {
fprintf(stderr, "caught X11 error:\n");
} else if (sig == -1) {
fprintf(stderr, "caught XIO error:\n");
} else {
fprintf(stderr, "caught signal: %d\n", sig);
}
if (sig == SIGINT) {
shut_down = 1;
return;
}
X_UNLOCK;
if (icon_mode) {
clean_icon_mode();
}
/* remove the shm areas with quick=1: */
clean_shm(1);
if (sig == -1) {
/* not worth trying any more cleanup, X server probably gone */
exit(3);
}
/* X keyboard cleanups */
delete_added_keycodes(0);
if (clear_mods == 1) {
clear_modifiers(0);
} else if (clear_mods == 2) {
clear_keys();
}
if (no_autorepeat) {
autorepeat(1, 0);
}
if (use_solid_bg) {
solid_bg(1);
}
if (crash_debug) {
crash_shell();
}
if (sig) {
exit(2);
}
}
/* signal handlers */
void initialize_signals(void) {
signal(SIGHUP, interrupted);
signal(SIGINT, interrupted);
signal(SIGQUIT, interrupted);
signal(SIGABRT, interrupted);
signal(SIGTERM, interrupted);
signal(SIGBUS, interrupted);
signal(SIGSEGV, interrupted);
signal(SIGFPE, interrupted);
if (!sigpipe || *sigpipe == '\0' || !strcmp(sigpipe, "skip")) {
;
} else if (!strcmp(sigpipe, "ignore")) {
#ifdef SIG_IGN
signal(SIGPIPE, SIG_IGN);
#endif
} else if (!strcmp(sigpipe, "exit")) {
rfbLog("initialize_signals: will exit on SIGPIPE\n");
signal(SIGPIPE, interrupted);
}
X_LOCK;
Xerror_def = XSetErrorHandler(Xerror);
XIOerr_def = XSetIOErrorHandler(XIOerr);
X_UNLOCK;
}
int known_sigpipe_mode(char *s) {
/*
* skip, ignore, exit
*/
if (strcmp(s, "skip") && strcmp(s, "ignore") &&
strcmp(s, "exit")) {
return 0;
} else {
return 1;
}
}

@ -0,0 +1,25 @@
#ifndef _X11VNC_CLEANUP_H
#define _X11VNC_CLEANUP_H
/* -- cleanup.h -- */
extern int trapped_xerror;
extern int trapped_xioerror;
extern int trapped_getimage_xerror;
extern int trapped_record_xerror;
extern XErrorEvent *trapped_xerror_event;
extern int crash_debug;
extern void clean_shm(int quick);
extern void clean_up_exit (int ret);
extern int trap_xerror(Display *d, XErrorEvent *error);
extern int trap_xioerror(Display *d);
extern int trap_getimage_xerror(Display *d, XErrorEvent *error);
extern char *xerror_string(XErrorEvent *error);
extern void initialize_crash_handler(void);
extern void initialize_signals(void);
extern int known_sigpipe_mode(char *s);
#endif /* _X11VNC_CLEANUP_H */

File diff suppressed because it is too large Load Diff

@ -0,0 +1,26 @@
#ifndef _X11VNC_CONNECTIONS_H
#define _X11VNC_CONNECTIONS_H
/* -- connections.h -- */
extern char vnc_connect_str[];
extern Atom vnc_connect_prop;
extern int all_clients_initialized(void);
extern char *list_clients(void);
extern int new_fb_size_clients(rfbScreenInfoPtr s);
extern void close_all_clients(void);
extern void close_clients(char *str);
extern void set_client_input(char *str);
extern void set_child_info(void);
extern void reverse_connect(char *str);
extern void set_vnc_connect_prop(char *str);
extern void read_vnc_connect_prop(void);
extern void check_connect_inputs(void);
extern void check_gui_inputs(void);
extern enum rfbNewClientAction new_client(rfbClientPtr client);
extern void start_client_info_sock(char *host_port_cookie);
extern void send_client_info(char *str);
extern void check_new_clients(void);
#endif /* _X11VNC_CONNECTIONS_H */

File diff suppressed because it is too large Load Diff

@ -0,0 +1,33 @@
#ifndef _X11VNC_CURSOR_H
#define _X11VNC_CURSOR_H
/* -- cursor.h -- */
extern int xfixes_present;
extern int use_xfixes;
extern int got_xfixes_cursor_notify;
extern int cursor_changes;
extern int alpha_threshold;
extern double alpha_frac;
extern int alpha_remove;
extern int alpha_blend;
extern int alt_arrow;
extern int alt_arrow_max;
extern void first_cursor(void);
extern void setup_cursors_and_push(void);
extern void initialize_xfixes(void);
extern int known_cursors_mode(char *s);
extern void initialize_cursors_mode(void);
extern int get_which_cursor(void);
extern void restore_cursor_shape_updates(rfbScreenInfoPtr s);
extern void disable_cursor_shape_updates(rfbScreenInfoPtr s);
extern int cursor_shape_updates_clients(rfbScreenInfoPtr s);
extern int cursor_pos_updates_clients(rfbScreenInfoPtr s);
extern void cursor_position(int x, int y);
extern void set_no_cursor(void);
extern int set_cursor(int x, int y, int which);
extern int check_x11_pointer(void);
#endif /* _X11VNC_CURSOR_H */

@ -0,0 +1,22 @@
#ifndef _X11VNC_ENUMS_H
#define _X11VNC_ENUMS_H
/* -- enums.h -- */
enum {
LR_UNSET = 0,
LR_UNKNOWN,
LR_DIALUP,
LR_BROADBAND,
LR_LAN
};
enum scroll_types {
SCR_NONE = 0,
SCR_MOUSE,
SCR_KEY,
SCR_FAIL,
SCR_SUCCESS
};
#endif /* _X11VNC_ENUMS_H */

@ -0,0 +1,638 @@
/* -- gui.c -- */
#include "x11vnc.h"
#include "xevents.h"
#include "win_utils.h"
#include "remote.h"
#include "cleanup.h"
#include "tkx11vnc.h"
#define SYSTEM_TRAY_REQUEST_DOCK 0
#define SYSTEM_TRAY_BEGIN_MESSAGE 1
#define SYSTEM_TRAY_CANCEL_MESSAGE 2
#define XEMBED_VERSION 0
#define XEMBED_MAPPED (1 << 0)
int icon_mode = 0; /* hack for -gui tray */
char *icon_mode_file = NULL;
FILE *icon_mode_fh = NULL;
int icon_mode_socks[ICON_MODE_SOCKS];
int tray_manager_ok = 0;
Window tray_request = None;
Window tray_window = None;
int tray_unembed = 0;
char *get_gui_code(void);
int tray_embed(Window iconwin, int remove);
void do_gui(char *opts, int sleep);
static Window tweak_tk_window_id(Window win);
static int tray_manager_running(Display *d, Window *manager);
static void run_gui(char *gui_xdisplay, int connect_to_x11vnc, int start_x11vnc,
int simple_gui, pid_t parent, char *gui_opts);
char *get_gui_code(void) {
return gui_code;
}
static Window tweak_tk_window_id(Window win) {
char *name = NULL;
Window parent, new;
/* hack for tk, does not report outermost window */
new = win;
parent = parent_window(win, &name);
if (parent && name != NULL) {
lowercase(name);
if (strstr(name, "wish") || strstr(name, "x11vnc")) {
new = parent;
rfbLog("tray_embed: using parent: %s\n", name);
}
}
if (name != NULL) {
XFree(name);
}
return new;
}
int tray_embed(Window iconwin, int remove) {
XEvent ev;
XErrorHandler old_handler;
Window manager;
Atom xembed_info;
Atom tatom;
XWindowAttributes attr;
long info[2] = {XEMBED_VERSION, XEMBED_MAPPED};
long data = 0;
if (remove) {
if (!valid_window(iconwin, &attr, 1)) {
return 0;
}
iconwin = tweak_tk_window_id(iconwin);
trapped_xerror = 0;
old_handler = XSetErrorHandler(trap_xerror);
/*
* unfortunately no desktops seem to obey this
* part of the XEMBED spec yet...
*/
XReparentWindow(dpy, iconwin, rootwin, 0, 0);
XSetErrorHandler(old_handler);
if (trapped_xerror) {
trapped_xerror = 0;
return 0;
}
trapped_xerror = 0;
return 1;
}
xembed_info = XInternAtom(dpy, "_XEMBED_INFO", False);
if (xembed_info == None) {
return 0;
}
if (!tray_manager_running(dpy, &manager)) {
return 0;
}
memset(&ev, 0, sizeof(ev));
ev.xclient.type = ClientMessage;
ev.xclient.window = manager;
ev.xclient.message_type = XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE",
False);
ev.xclient.format = 32;
ev.xclient.data.l[0] = CurrentTime;
ev.xclient.data.l[1] = SYSTEM_TRAY_REQUEST_DOCK;
ev.xclient.data.l[2] = iconwin;
ev.xclient.data.l[3] = 0;
ev.xclient.data.l[4] = 0;
if (!valid_window(iconwin, &attr, 1)) {
return 0;
}
iconwin = tweak_tk_window_id(iconwin);
ev.xclient.data.l[2] = iconwin;
XUnmapWindow(dpy, iconwin);
trapped_xerror = 0;
old_handler = XSetErrorHandler(trap_xerror);
XSendEvent(dpy, manager, False, NoEventMask, &ev);
XSync(dpy, False);
if (trapped_xerror) {
XSetErrorHandler(old_handler);
trapped_xerror = 0;
return 0;
}
XChangeProperty(dpy, iconwin, xembed_info, xembed_info, 32,
PropModeReplace, (unsigned char *)&info, 2);
/* kludge for KDE evidently needed... */
tatom = XInternAtom(dpy, "KWM_DOCKWINDOW", False);
XChangeProperty(dpy, iconwin, tatom, tatom, 32, PropModeReplace,
(unsigned char *)&data, 1);
tatom = XInternAtom(dpy, "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR", False);
XChangeProperty(dpy, iconwin, tatom, XA_WINDOW, 32, PropModeReplace,
(unsigned char *)&data, 1);
XSetErrorHandler(old_handler);
trapped_xerror = 0;
return 1;
}
static int tray_manager_running(Display *d, Window *manager) {
char tray_string[100];
Atom tray_manager;
Window tray_win;
if (manager) {
*manager = None;
}
sprintf(tray_string, "_NET_SYSTEM_TRAY_S%d", scr);
tray_manager = XInternAtom(d, tray_string, True);
if (tray_manager == None) {
return 0;
}
tray_win = XGetSelectionOwner(d, tray_manager);
if (manager) {
*manager = tray_win;
}
if (tray_win == None) {
return 0;
} else {
return 1;
}
}
static char *gui_geometry = NULL;
static int icon_in_tray = 0;
static char *icon_mode_embed_id = NULL;
static char *icon_mode_font = NULL;
static char *icon_mode_params = NULL;
static void run_gui(char *gui_xdisplay, int connect_to_x11vnc, int start_x11vnc,
int simple_gui, pid_t parent, char *gui_opts) {
char *x11vnc_xdisplay = NULL;
char extra_path[] = ":/usr/local/bin:/usr/bin/X11:/usr/sfw/bin"
":/usr/X11R6/bin:/usr/openwin/bin:/usr/dt/bin";
char cmd[100];
char *wish = NULL, *orig_path, *full_path, *tpath, *p;
char *old_xauth = NULL;
int try_max = 4, sleep = 300;
pid_t mypid = getpid();
FILE *pipe, *tmpf;
if (*gui_code == '\0') {
rfbLog("gui: gui not compiled into this program.\n");
exit(0);
}
if (getenv("DISPLAY") != NULL) {
/* worst case */
x11vnc_xdisplay = strdup(getenv("DISPLAY"));
}
if (use_dpy) {
/* better */
x11vnc_xdisplay = strdup(use_dpy);
}
if (connect_to_x11vnc) {
int rc, i;
rfbLogEnable(1);
if (! client_connect_file) {
if (getenv("XAUTHORITY") != NULL) {
old_xauth = strdup(getenv("XAUTHORITY"));
} else {
old_xauth = strdup("");
}
dpy = XOpenDisplay(x11vnc_xdisplay);
if (! dpy && auth_file) {
set_env("XAUTHORITY", auth_file);
dpy = XOpenDisplay(x11vnc_xdisplay);
}
if (! dpy && ! x11vnc_xdisplay) {
/* worstest case */
x11vnc_xdisplay = strdup(":0");
dpy = XOpenDisplay(x11vnc_xdisplay);
}
if (! dpy) {
rfbLog("gui: could not open x11vnc "
"display: %s\n", NONUL(x11vnc_xdisplay));
exit(1);
}
scr = DefaultScreen(dpy);
rootwin = RootWindow(dpy, scr);
initialize_vnc_connect_prop();
}
usleep(2200*1000);
fprintf(stderr, "\n");
if (!quiet) {
rfbLog("gui: trying to contact a x11vnc server at X"
" display %s ...\n", NONUL(x11vnc_xdisplay));
}
for (i=0; i<try_max; i++) {
usleep(sleep*1000);
if (!quiet) {
rfbLog("gui: pinging %s try=%d ...\n",
NONUL(x11vnc_xdisplay), i+1);
}
rc = send_remote_cmd("qry=ping", 1, 1);
if (rc == 0) {
break;
}
if (parent && mypid != parent && kill(parent, 0) != 0) {
rfbLog("gui: parent process %d has gone"
" away: bailing out.\n", parent);
rc = 1;
break;
}
}
set_env("X11VNC_XDISPLAY", x11vnc_xdisplay);
if (getenv("XAUTHORITY") != NULL) {
set_env("X11VNC_AUTH_FILE", getenv("XAUTHORITY"));
}
if (rc == 0) {
rfbLog("gui: ping succeeded.\n");
set_env("X11VNC_CONNECT", "1");
} else {
rfbLog("gui: could not connect to: '%s', try"
" again manually.\n", x11vnc_xdisplay);
}
if (client_connect_file) {
set_env("X11VNC_CONNECT_FILE", client_connect_file);
}
if (dpy) {
XCloseDisplay(dpy);
dpy = NULL;
}
if (old_xauth) {
if (*old_xauth == '\0') {
/* wasn't set, hack it out if it is now */
char *xauth = getenv("XAUTHORITY");
if (xauth) {
*(xauth-2) = '_'; /* yow */
}
} else {
set_env("XAUTHORITY", old_xauth);
}
free(old_xauth);
}
rfbLogEnable(0);
}
orig_path = getenv("PATH");
if (! orig_path) {
orig_path = strdup("/bin:/usr/bin:/usr/bin/X11");
}
full_path = (char *) malloc(strlen(orig_path)+strlen(extra_path)+1);
strcpy(full_path, orig_path);
strcat(full_path, extra_path);
tpath = strdup(full_path);
p = strtok(tpath, ":");
while (p) {
char *try;
struct stat sbuf;
char *wishes[] = {"wish", "wish8.3", "wish8.4", "wish8.5",
"wish8.0"};
int nwishes = 3, i;
try = (char *) malloc(strlen(p) + 1 + strlen("wish8.4") + 1);
for (i=0; i<nwishes; i++) {
sprintf(try, "%s/%s", p, wishes[i]);
if (stat(try, &sbuf) == 0) {
/* assume executable, should check mode */
wish = wishes[i];
}
}
free(try);
if (wish) {
break;
}
p = strtok(NULL, ":");
}
free(tpath);
if (!wish) {
wish = strdup("wish");
}
set_env("PATH", full_path);
set_env("DISPLAY", gui_xdisplay);
set_env("X11VNC_PROG", program_name);
set_env("X11VNC_CMDLINE", program_cmdline);
set_env("X11VNC_WISHCMD", wish);
if (simple_gui) {
set_env("X11VNC_SIMPLE_GUI", "1");
}
if (gui_opts) {
set_env("X11VNC_GUI_PARAMS", gui_opts);
}
if (gui_geometry) {
set_env("X11VNC_GUI_GEOM", gui_geometry);
}
if (start_x11vnc) {
set_env("X11VNC_STARTED", "1");
}
if (icon_mode) {
set_env("X11VNC_ICON_MODE", "1");
if (icon_mode_file) {
set_env("X11VNC_CLIENT_FILE", icon_mode_file);
}
if (icon_in_tray) {
if (tray_manager_ok) {
set_env("X11VNC_ICON_MODE", "TRAY:RUNNING");
} else {
set_env("X11VNC_ICON_MODE", "TRAY");
}
} else {
set_env("X11VNC_ICON_MODE", "ICON");
}
if (icon_mode_params) {
char *p, *str = strdup(icon_mode_params);
p = strtok(str, ":-/,.+");
while (p) {
if(strstr(p, "setp") == p) {
set_env("X11VNC_ICON_SETPASS", "1");
} else if(strstr(p, "noadvanced") == p) {
set_env("X11VNC_ICON_NOADVANCED", "1");
} else if(strstr(p, "minimal") == p) {
set_env("X11VNC_ICON_MINIMAL", "1");
} else if (strstr(p, "0x") == p) {
set_env("X11VNC_ICON_EMBED_ID", p);
icon_mode_embed_id = strdup(p);
}
p = strtok(NULL, ":-/,.+");
}
free(str);
}
}
if (icon_mode_font) {
set_env("X11VNC_ICON_FONT", icon_mode_font);
}
if (no_external_cmds) {
fprintf(stderr, "cannot run external commands in -nocmds "
"mode:\n");
fprintf(stderr, " \"%s\"\n", "gui + wish");
fprintf(stderr, " exiting.\n");
fflush(stderr);
exit(1);
}
tmpf = tmpfile();
if (tmpf == NULL) {
/* if no tmpfile, use a pipe */
if (icon_mode_embed_id) {
if (strlen(icon_mode_embed_id) < 20) {
strcat(cmd, " -use ");
strcat(cmd, icon_mode_embed_id);
}
}
pipe = popen(cmd, "w");
if (! pipe) {
fprintf(stderr, "could not run: %s\n", cmd);
perror("popen");
}
fprintf(pipe, "%s", gui_code);
pclose(pipe);
} else {
/*
* we prefer a tmpfile since then this x11vnc process
* will then be gone, otherwise the x11vnc program text
* will still be in use.
*/
int n = fileno(tmpf);
fprintf(tmpf, "%s", gui_code);
fflush(tmpf);
rewind(tmpf);
dup2(n, 0);
close(n);
if (icon_mode_embed_id) {
execlp(wish, wish, "-", "-use", icon_mode_embed_id,
(char *) NULL);
} else {
execlp(wish, wish, "-", (char *) NULL);
}
fprintf(stderr, "could not exec wish: %s -\n", wish);
perror("execlp");
}
exit(0);
}
void do_gui(char *opts, int sleep) {
char *s, *p;
char *old_xauth = NULL;
char *gui_xdisplay = NULL;
int got_gui_xdisplay = 0;
int start_x11vnc = 1;
int connect_to_x11vnc = 0;
int simple_gui = 0, none_gui = 0;
Display *test_dpy;
if (opts) {
s = strdup(opts);
} else {
s = strdup("");
}
if (use_dpy) {
/* worst case */
gui_xdisplay = strdup(use_dpy);
}
if (getenv("DISPLAY") != NULL) {
/* better */
gui_xdisplay = strdup(getenv("DISPLAY"));
}
p = strtok(s, ",");
while(p) {
if (*p == '\0') {
;
} else if (strchr(p, ':') != NULL) {
/* best */
if (gui_xdisplay) {
free(gui_xdisplay);
}
gui_xdisplay = strdup(p);
got_gui_xdisplay = 1;
} else if (!strcmp(p, "wait")) {
start_x11vnc = 0;
connect_to_x11vnc = 0;
} else if (!strcmp(p, "none")) {
none_gui = 1;
} else if (!strcmp(p, "conn") || !strcmp(p, "connect")) {
start_x11vnc = 0;
connect_to_x11vnc = 1;
} else if (!strcmp(p, "ez") || !strcmp(p, "simple")) {
simple_gui = 1;
} else if (strstr(p, "iconfont") == p) {
char *q;
if ((q = strchr(p, '=')) != NULL) {
icon_mode_font = strdup(q+1);
}
} else if (!strcmp(p, "full")) {
;
} else if (strstr(p, "tray") == p || strstr(p, "icon") == p) {
char *q;
icon_mode = 1;
if ((q = strchr(p, '=')) != NULL) {
icon_mode_params = strdup(q+1);
if (strstr(icon_mode_params, "setp")) {
deny_all = 1;
}
}
if (strstr(p, "tray") == p) {
icon_in_tray = 1;
}
} else if (strstr(p, "geom") == p) {
char *q;
if ((q = strchr(p, '=')) != NULL) {
gui_geometry = strdup(q+1);
}
} else {
fprintf(stderr, "unrecognized gui opt: %s\n", p);
}
p = strtok(NULL, ",");
}
free(s);
if (none_gui) {
if (!start_x11vnc) {
exit(0);
}
return;
}
if (start_x11vnc) {
connect_to_x11vnc = 1;
}
if (icon_mode && !got_gui_xdisplay) {
/* for tray mode, prefer the polled DISPLAY */
if (use_dpy) {
if (gui_xdisplay) {
free(gui_xdisplay);
}
gui_xdisplay = strdup(use_dpy);
}
}
if (! gui_xdisplay) {
fprintf(stderr, "error: cannot determine X DISPLAY for gui"
" to display on.\n");
exit(1);
}
if (!quiet) {
fprintf(stderr, "starting gui, trying display: %s\n",
gui_xdisplay);
}
test_dpy = XOpenDisplay(gui_xdisplay);
if (! test_dpy && auth_file) {
if (getenv("XAUTHORITY") != NULL) {
old_xauth = strdup(getenv("XAUTHORITY"));
}
set_env("XAUTHORITY", auth_file);
test_dpy = XOpenDisplay(gui_xdisplay);
}
if (! test_dpy) {
if (! old_xauth && getenv("XAUTHORITY") != NULL) {
old_xauth = strdup(getenv("XAUTHORITY"));
}
set_env("XAUTHORITY", "");
test_dpy = XOpenDisplay(gui_xdisplay);
}
if (! test_dpy) {
fprintf(stderr, "error: cannot connect to gui X DISPLAY: %s\n",
gui_xdisplay);
exit(1);
}
if (icon_mode && icon_in_tray) {
if (tray_manager_running(test_dpy, NULL)) {
tray_manager_ok = 1;
} else {
tray_manager_ok = 0;
}
}
XCloseDisplay(test_dpy);
if (start_x11vnc) {
#if LIBVNCSERVER_HAVE_FORK
/* fork into the background now */
int p;
pid_t parent = getpid();
if (icon_mode) {
char tf[100];
double dn = dnow();
struct stat sbuf;
/* FIXME */
dn = dn - ((int) dn);
sprintf(tf, "/tmp/x11vnc.tray%d%d", (int) (1000000*dn),
(int) getpid());
unlink(tf);
/* race begins.. */
if (stat(tf, &sbuf) == 0) {
icon_mode = 0;
} else {
icon_mode_fh = fopen(tf, "w");
if (! icon_mode_fh) {
icon_mode = 0;
} else {
chmod(tf, 0400);
icon_mode_file = strdup(tf);
fprintf(icon_mode_fh, "none\n");
fprintf(icon_mode_fh, "none\n");
fflush(icon_mode_fh);
if (! got_connect_once) {
/* want -forever for tray */
connect_once = 0;
}
}
}
}
if ((p = fork()) > 0) {
; /* parent */
} else if (p == -1) {
fprintf(stderr, "could not fork\n");
perror("fork");
clean_up_exit(1);
} else {
if (sleep > 0) {
usleep(sleep * 1000 * 1000);
}
run_gui(gui_xdisplay, connect_to_x11vnc, start_x11vnc,
simple_gui, parent, opts);
exit(1);
}
#else
fprintf(stderr, "system does not support fork: start "
"x11vnc in the gui.\n");
start_x11vnc = 0;
#endif
}
if (!start_x11vnc) {
run_gui(gui_xdisplay, connect_to_x11vnc, start_x11vnc,
simple_gui, 0, opts);
exit(1);
}
if (old_xauth) {
set_env("XAUTHORITY", old_xauth);
}
}

@ -0,0 +1,19 @@
#ifndef _X11VNC_GUI_H
#define _X11VNC_GUI_H
/* -- gui.h -- */
extern int icon_mode;
extern char *icon_mode_file;
extern FILE *icon_mode_fh;
extern int icon_mode_socks[];
extern int tray_manager_ok;
extern Window tray_request;
extern Window tray_window;
extern int tray_unembed;
extern char *get_gui_code(void);
extern int tray_embed(Window iconwin, int remove);
extern void do_gui(char *opts, int sleep);
#endif /* _X11VNC_GUI_H */

File diff suppressed because it is too large Load Diff

@ -0,0 +1,10 @@
#ifndef _X11VNC_HELP_H
#define _X11VNC_HELP_H
/* -- help.h -- */
extern void print_help(int mode);
extern void xopen_display_fail_message(char *disp);
extern void nopassword_warning_msg(int gotloc);
#endif /* _X11VNC_HELP_H */

@ -0,0 +1,259 @@
/* -- inet.c -- */
#include "x11vnc.h"
/*
* Simple utility to map host name to dotted IP address. Ignores aliases.
* Up to caller to free returned string.
*/
char *host2ip(char *host);
char *raw2host(char *raw, int len);
char *raw2ip(char *raw);
char *ip2host(char *ip);
int dotted_ip(char *host);
int get_remote_port(int sock);
int get_local_port(int sock);
char *get_remote_host(int sock);
char *get_local_host(int sock);
char *ident_username(rfbClientPtr client);
static int get_port(int sock, int remote);
static char *get_host(int sock, int remote);
char *host2ip(char *host) {
struct hostent *hp;
struct sockaddr_in addr;
char *str;
if (! host_lookup) {
return NULL;
}
hp = gethostbyname(host);
if (!hp) {
return NULL;
}
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = *(unsigned long *)hp->h_addr;
str = strdup(inet_ntoa(addr.sin_addr));
return str;
}
char *raw2host(char *raw, int len) {
char *str;
#if LIBVNCSERVER_HAVE_NETDB_H && LIBVNCSERVER_HAVE_NETINET_IN_H
struct hostent *hp;
if (! host_lookup) {
return strdup("unknown");
}
hp = gethostbyaddr(raw, len, AF_INET);
if (!hp) {
return strdup(inet_ntoa(*((struct in_addr *)raw)));
}
str = strdup(hp->h_name);
#else
str = strdup("unknown");
#endif
return str;
}
char *raw2ip(char *raw) {
return strdup(inet_ntoa(*((struct in_addr *)raw)));
}
char *ip2host(char *ip) {
char *str;
#if LIBVNCSERVER_HAVE_NETDB_H && LIBVNCSERVER_HAVE_NETINET_IN_H
struct hostent *hp;
in_addr_t iaddr;
if (! host_lookup) {
return strdup("unknown");
}
iaddr = inet_addr(ip);
if (iaddr == htonl(INADDR_NONE)) {
return strdup("unknown");
}
hp = gethostbyaddr((char *)&iaddr, sizeof(in_addr_t), AF_INET);
if (!hp) {
return strdup("unknown");
}
str = strdup(hp->h_name);
#else
str = strdup("unknown");
#endif
return str;
}
int dotted_ip(char *host) {
char *p = host;
while (*p != '\0') {
if (*p == '.' || isdigit(*p)) {
p++;
continue;
}
return 0;
}
return 1;
}
static int get_port(int sock, int remote) {
struct sockaddr_in saddr;
unsigned int saddr_len;
int saddr_port;
saddr_len = sizeof(saddr);
memset(&saddr, 0, sizeof(saddr));
saddr_port = -1;
if (remote) {
if (!getpeername(sock, (struct sockaddr *)&saddr, &saddr_len)) {
saddr_port = ntohs(saddr.sin_port);
}
} else {
if (!getsockname(sock, (struct sockaddr *)&saddr, &saddr_len)) {
saddr_port = ntohs(saddr.sin_port);
}
}
return saddr_port;
}
int get_remote_port(int sock) {
return get_port(sock, 1);
}
int get_local_port(int sock) {
return get_port(sock, 0);
}
static char *get_host(int sock, int remote) {
struct sockaddr_in saddr;
unsigned int saddr_len;
int saddr_port;
char *saddr_ip_str = NULL;
saddr_len = sizeof(saddr);
memset(&saddr, 0, sizeof(saddr));
saddr_port = -1;
#if LIBVNCSERVER_HAVE_NETINET_IN_H
if (remote) {
if (!getpeername(sock, (struct sockaddr *)&saddr, &saddr_len)) {
saddr_ip_str = inet_ntoa(saddr.sin_addr);
}
} else {
if (!getsockname(sock, (struct sockaddr *)&saddr, &saddr_len)) {
saddr_ip_str = inet_ntoa(saddr.sin_addr);
}
}
#endif
if (! saddr_ip_str) {
saddr_ip_str = "unknown";
}
return strdup(saddr_ip_str);
}
char *get_remote_host(int sock) {
return get_host(sock, 1);
}
char *get_local_host(int sock) {
return get_host(sock, 0);
}
char *ident_username(rfbClientPtr client) {
ClientData *cd = (ClientData *) client->clientData;
char *str, *newhost, *user = NULL, *newuser = NULL;
int len;
if (cd) {
user = cd->username;
}
if (!user || *user == '\0') {
char msg[128];
int n, sock, ok = 0;
if ((sock = rfbConnectToTcpAddr(client->host, 113)) < 0) {
rfbLog("could not connect to ident: %s:%d\n",
client->host, 113);
} else {
int ret;
fd_set rfds;
struct timeval tv;
int rport = get_remote_port(client->sock);
int lport = get_local_port(client->sock);
sprintf(msg, "%d, %d\r\n", rport, lport);
n = write(sock, msg, strlen(msg));
FD_ZERO(&rfds);
FD_SET(sock, &rfds);
tv.tv_sec = 4;
tv.tv_usec = 0;
ret = select(sock+1, &rfds, NULL, NULL, &tv);
if (ret > 0) {
int i;
char *q, *p;
for (i=0; i<128; i++) {
msg[i] = '\0';
}
usleep(250*1000);
n = read(sock, msg, 127);
close(sock);
if (n <= 0) goto badreply;
/* 32782 , 6000 : USERID : UNIX :runge */
q = strstr(msg, "USERID");
if (!q) goto badreply;
q = strstr(q, ":");
if (!q) goto badreply;
q++;
q = strstr(q, ":");
if (!q) goto badreply;
q++;
q = lblanks(q);
p = q;
while (*p) {
if (*p == '\r' || *p == '\n') {
*p = '\0';
}
p++;
}
ok = 1;
if (strlen(q) > 24) {
*(q+24) = '\0';
}
newuser = strdup(q);
badreply:
n = 0; /* avoid syntax error */
} else {
close(sock);
}
}
if (! ok || !newuser) {
newuser = strdup("unknown-user");
}
if (cd) {
if (cd->username) {
free(cd->username);
}
cd->username = newuser;
}
user = newuser;
}
newhost = ip2host(client->host);
len = strlen(user) + 1 + strlen(newhost) + 1;
str = (char *) malloc(len);
sprintf(str, "%s@%s", user, newhost);
free(newhost);
return str;
}

@ -0,0 +1,17 @@
#ifndef _X11VNC_INET_H
#define _X11VNC_INET_H
/* -- inet.h -- */
extern char *host2ip(char *host);
extern char *raw2host(char *raw, int len);
extern char *raw2ip(char *raw);
extern char *ip2host(char *ip);
extern int dotted_ip(char *host);
extern int get_remote_port(int sock);
extern int get_local_port(int sock);
extern char *get_remote_host(int sock);
extern char *get_local_host(int sock);
extern char *ident_username(rfbClientPtr client);
#endif /* _X11VNC_INET_H */

File diff suppressed because it is too large Load Diff

@ -0,0 +1,29 @@
#ifndef _X11VNC_KEYBOARD_H
#define _X11VNC_KEYBOARD_H
/* -- keyboard.h -- */
#include "allowed_input_t.h"
extern void get_keystate(int *keystate);
extern void clear_modifiers(int init);
extern int track_mod_state(rfbKeySym keysym, rfbBool down, rfbBool set);
extern void clear_keys(void);
extern int get_autorepeat_state(void);
extern int get_initial_autorepeat_state(void);
extern void autorepeat(int restore, int bequiet);
extern void check_add_keysyms(void);
extern int add_keysym(KeySym keysym);
extern void delete_added_keycodes(int bequiet);
extern void initialize_remap(char *infile);
extern int sloppy_key_check(int key, rfbBool down, rfbKeySym keysym, int *new);
extern void switch_to_xkb_if_better(void);
extern char *short_kmb(char *str);
extern void initialize_allowed_input(void);
extern void initialize_modtweak(void);
extern void initialize_keyboard_and_pointer(void);
extern void get_allowed_input(rfbClientPtr client, allowed_input_t *input);
extern double typing_rate(double time_window, int *repeating);
extern int skip_cr_when_scaling(char *mode);
extern void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client);
#endif /* _X11VNC_KEYBOARD_H */

@ -0,0 +1,310 @@
/* -- options.c -- */
#define _X11VNC_OPTIONS_H
#include "x11vnc.h"
/*
* variables for the command line options
*/
int debug = 0;
char *use_dpy = NULL; /* -display */
char *auth_file = NULL; /* -auth/-xauth */
char *visual_str = NULL; /* -visual */
char *logfile = NULL; /* -o, -logfile */
int logfile_append = 0;
char *flagfile = NULL; /* -flag */
char *passwdfile = NULL; /* -passwdfile */
char *blackout_str = NULL; /* -blackout */
int blackout_ptr = 0;
char *clip_str = NULL; /* -clip */
int use_solid_bg = 0; /* -solid */
char *solid_str = NULL;
char *solid_default = "cyan4";
char *wmdt_str = NULL; /* -wmdt */
char *speeds_str = NULL; /* -speeds TBD */
char *rc_rcfile = NULL; /* -rc */
int rc_rcfile_default = 0;
int rc_norc = 0;
int got_norc = 0;
int opts_bg = 0;
#ifndef VNCSHARED
int shared = 0; /* share vnc display. */
#else
int shared = 1;
#endif
#ifndef FOREVER
int connect_once = 1; /* disconnect after first connection session. */
#else
int connect_once = 0;
#endif
int got_connect_once = 0;
int deny_all = 0; /* global locking of new clients */
#ifndef REMOTE_DEFAULT
#define REMOTE_DEFAULT 1
#endif
int accept_remote_cmds = REMOTE_DEFAULT; /* -noremote */
int query_default = 0;
int safe_remote_only = 1; /* -unsafe */
int priv_remote = 0; /* -privremote */
int more_safe = 0; /* -safer */
#ifndef EXTERNAL_COMMANDS
#define EXTERNAL_COMMANDS 1
#endif
#if EXTERNAL_COMMANDS
int no_external_cmds = 0; /* -nocmds */
#else
int no_external_cmds = 1; /* cannot be turned back on. */
#endif
int started_as_root = 0;
int host_lookup = 1;
char *users_list = NULL; /* -users */
char *allow_list = NULL; /* for -allow and -localhost */
char *listen_str = NULL;
char *allow_once = NULL; /* one time -allow */
char *accept_cmd = NULL; /* for -accept */
char *afteraccept_cmd = NULL; /* for -afteraccept */
char *gone_cmd = NULL; /* for -gone */
#ifndef VIEWONLY
#define VIEWONLY 0
#endif
int view_only = VIEWONLY; /* clients can only watch. */
char *allowed_input_view_only = NULL;
char *allowed_input_normal = NULL;
char *allowed_input_str = NULL;
char *viewonly_passwd = NULL; /* view only passwd. */
char **passwd_list = NULL; /* for -passwdfile */
int begin_viewonly = -1;
int inetd = 0; /* spawned from inetd(1) */
#ifndef FILEXFER
#define FILEXFER 1
#endif
int filexfer = FILEXFER;
int first_conn_timeout = 0; /* -timeout */
int flash_cmap = 0; /* follow installed colormaps */
int shift_cmap = 0; /* ncells < 256 and needs shift of pixel values */
int force_indexed_color = 0; /* whether to force indexed color for 8bpp */
int launch_gui = 0; /* -gui */
int use_modifier_tweak = 1; /* use the shift/altgr modifier tweak */
int use_iso_level3 = 0; /* ISO_Level3_Shift instead of Mode_switch */
int clear_mods = 0; /* -clear_mods (1) and -clear_keys (2) */
int nofb = 0; /* do not send any fb updates */
char *raw_fb_str = NULL; /* used under -rawfb */
char *pipeinput_str = NULL; /* -pipeinput [tee,reopen,keycodes:]cmd */
char *pipeinput_opts = NULL;
FILE *pipeinput_fh = NULL;
int pipeinput_tee = 0;
unsigned long subwin = 0x0; /* -id, -sid */
int subwin_wait_mapped = 0;
int debug_xevents = 0; /* -R debug_xevents:1 */
int debug_xdamage = 0; /* -R debug_xdamage:1 or 2 ... */
int debug_wireframe = 0;
int debug_tiles = 0;
int debug_grabs = 0;
int xtrap_input = 0; /* -xtrap for user input insertion */
int xinerama = 0; /* -xinerama */
int xrandr = 0; /* -xrandr */
char *xrandr_mode = NULL;
char *pad_geometry = NULL;
time_t pad_geometry_time = 0;
int use_snapfb = 0;
int use_xrecord = 0;
int noxrecord = 0;
char *client_connect = NULL; /* strings for -connect option */
char *client_connect_file = NULL;
int vnc_connect = 1; /* -vncconnect option */
int show_cursor = 1; /* show cursor shapes */
int show_multiple_cursors = 0; /* show X when on root background, etc */
char *multiple_cursors_mode = NULL;
int cursor_pos_updates = 1; /* cursor position updates -cursorpos */
int cursor_shape_updates = 1; /* cursor shape updates -nocursorshape */
int use_xwarppointer = 0; /* use XWarpPointer instead of XTestFake... */
int show_dragging = 1; /* process mouse movement events */
#ifndef WIREFRAME
#define WIREFRAME 1
#endif
int wireframe = WIREFRAME; /* try to emulate wireframe wm moves */
/* shade,linewidth,percent,T+B+L+R,t1+t2+t3+t4 */
char *wireframe_str = NULL;
char *wireframe_copyrect = NULL;
#ifndef WIREFRAME_COPYRECT
#define WIREFRAME_COPYRECT 1
#endif
#if WIREFRAME_COPYRECT
char *wireframe_copyrect_default = "always";
#else
char *wireframe_copyrect_default = "never";
#endif
int wireframe_in_progress = 0;
/* T+B+L+R,tkey+presist_key,tmouse+persist_mouse */
char *scroll_copyrect_str = NULL;
#ifndef SCROLL_COPYRECT
#define SCROLL_COPYRECT 1
#endif
char *scroll_copyrect = NULL;
#if SCROLL_COPYRECT
#if 1
char *scroll_copyrect_default = "always"; /* -scrollcopyrect */
#else
char *scroll_copyrect_default = "keys";
#endif
#else
char *scroll_copyrect_default = "never";
#endif
char *scroll_key_list_str = NULL;
KeySym *scroll_key_list = NULL;
#ifndef SCALING_COPYRECT
#define SCALING_COPYRECT 1
#endif
int scaling_copyrect0 = SCALING_COPYRECT;
int scaling_copyrect = SCALING_COPYRECT;
int scrollcopyrect_min_area = 60000; /* minimum rectangle area */
int debug_scroll = 0;
double pointer_flush_delay = 0.0;
double last_scroll_event = 0.0;
int max_scroll_keyrate = 0;
double max_keyrepeat_time = 0.0;
char *max_keyrepeat_str = NULL;
char *max_keyrepeat_str0 = "4-20";
int max_keyrepeat_lo = 1, max_keyrepeat_hi = 40;
char **scroll_good_all = NULL;
char **scroll_good_key = NULL;
char **scroll_good_mouse = NULL;
char *scroll_good_str = NULL;
char *scroll_good_str0 = "##Nomatch";
/* "##Firefox-bin," */
/* "##Gnome-terminal," */
/* "##XTerm", */
char **scroll_skip_all = NULL;
char **scroll_skip_key = NULL;
char **scroll_skip_mouse = NULL;
char *scroll_skip_str = NULL;
char *scroll_skip_str0 = "##Soffice.bin,##StarOffice";
/* "##Konsole," * no problems, known heuristics do not work */
char **scroll_term = NULL;
char *scroll_term_str = NULL;
char *scroll_term_str0 = "term";
char* screen_fixup_str = NULL;
double screen_fixup_V = 0.0;
double screen_fixup_C = 0.0;
double screen_fixup_X = 0.0;
#ifndef NOREPEAT
#define NOREPEAT 1
#endif
int no_autorepeat = NOREPEAT; /* turn off autorepeat with clients */
int no_repeat_countdown = 2;
int watch_bell = 1; /* watch for the bell using XKEYBOARD */
int sound_bell = 1; /* actually send it */
int xkbcompat = 0; /* ignore XKEYBOARD extension */
int use_xkb_modtweak = 0; /* -xkb */
#ifndef SKIPDUPS
#define SKIPDUPS 0
#endif
int skip_duplicate_key_events = SKIPDUPS;
char *skip_keycodes = NULL;
int sloppy_keys = 0;
#ifndef ADDKEYSYMS
#define ADDKEYSYMS 1
#endif
int add_keysyms = ADDKEYSYMS; /* automatically add keysyms to X server */
char *remap_file = NULL; /* -remap */
char *pointer_remap = NULL;
/* use the various ways of updating pointer */
#ifndef POINTER_MODE_DEFAULT
#define POINTER_MODE_DEFAULT 2
#endif
int pointer_mode = POINTER_MODE_DEFAULT;
int pointer_mode_max = 4;
int single_copytile = 0; /* use the old way copy_tiles() */
int single_copytile_orig = 0;
int single_copytile_count = 0;
int tile_shm_count = 0;
int using_shm = 1; /* whether mit-shm is used */
int flip_byte_order = 0; /* sometimes needed when using_shm = 0 */
/*
* waitms is the msec to wait between screen polls. Not too old h/w shows
* poll times of 10-35ms, so maybe this value cuts the idle load by 2 or so.
*/
int waitms = 30;
double wait_ui = 2.0;
double slow_fb = 0.0;
int wait_bog = 1;
int defer_update = 30; /* deferUpdateTime ms to wait before sends. */
int got_defer = 0;
int got_deferupdate = 0;
int screen_blank = 60; /* number of seconds of no activity to throttle */
/* down the screen polls. zero to disable. */
int no_fbu_blank = 30; /* nap if no client updates in this many secs. */
int take_naps = 1; /* -nap/-nonap */
int naptile = 4; /* tile change threshold per poll to take a nap */
int napfac = 4; /* time = napfac*waitms, cut load with extra waits */
int napmax = 1500; /* longest nap in ms. */
int ui_skip = 10; /* see watchloop. negative means ignore input */
int watch_selection = 1; /* normal selection/cutbuffer maintenance */
int watch_primary = 1; /* more dicey, poll for changes in PRIMARY */
char *sel_direction = NULL; /* "send" or "recv" for one-way */
char *sigpipe = NULL; /* skip, ignore, exit */
/* visual stuff for -visual override or -overlay */
VisualID visual_id = (VisualID) 0;
int visual_depth = 0;
/* for -overlay mode on Solaris/IRIX. X server draws cursor correctly. */
int overlay = 0;
int overlay_cursor = 1;
/* tile heuristics: */
double fs_frac = 0.75; /* threshold tile fraction to do fullscreen updates. */
int tile_fuzz = 2; /* tolerance for suspecting changed tiles touching */
/* a known changed tile. */
int grow_fill = 3; /* do the grow islands heuristic with this width. */
int gaps_fill = 4; /* do a final pass to try to fill gaps between tiles. */
int debug_pointer = 0;
int debug_keyboard = 0;
int quiet = 0;
/* threaded vs. non-threaded (default) */
#if LIBVNCSERVER_HAVE_LIBPTHREAD && defined(X11VNC_THREADED)
int use_threads = 1;
#else
int use_threads = 0;
#endif
/* info about command line opts */
int got_rfbport = 0;
int got_alwaysshared = 0;
int got_nevershared = 0;
int got_cursorpos = 0;
int got_pointer_mode = -1;
int got_noviewonly = 0;
int got_wirecopyrect = 0;
int got_scrollcopyrect = 0;
int got_noxkb = 0;
int got_nomodtweak = 0;

@ -0,0 +1,231 @@
#ifndef _X11VNC_OPTIONS_H
#define _X11VNC_OPTIONS_H
/* -- options.h -- */
/*
* variables for the command line options
*/
extern int debug;
extern char *use_dpy;
extern char *auth_file;
extern char *visual_str;
extern char *logfile;
extern int logfile_append;
extern char *flagfile;
extern char *passwdfile;
extern char *blackout_str;
extern int blackout_ptr;
extern char *clip_str;
extern int use_solid_bg;
extern char *solid_str;
extern char *solid_default;
extern char *wmdt_str;
extern char *speeds_str;
extern char *rc_rcfile;
extern int rc_rcfile_default;
extern int rc_norc;
extern int got_norc;
extern int opts_bg;
extern int shared;
extern int connect_once;
extern int got_connect_once;
extern int deny_all;
extern int accept_remote_cmds;
extern int query_default;
extern int safe_remote_only;
extern int priv_remote;
extern int more_safe;
extern int no_external_cmds;
extern int started_as_root;
extern int host_lookup;
extern char *users_list;
extern char *allow_list;
extern char *listen_str;
extern char *allow_once;
extern char *accept_cmd;
extern char *afteraccept_cmd;
extern char *gone_cmd;
extern int view_only;
extern char *allowed_input_view_only;
extern char *allowed_input_normal;
extern char *allowed_input_str;
extern char *viewonly_passwd;
extern char **passwd_list;
extern int begin_viewonly;
extern int inetd;
extern int filexfer;
extern int first_conn_timeout;
extern int flash_cmap;
extern int shift_cmap;
extern int force_indexed_color;
extern int launch_gui;
extern int use_modifier_tweak;
extern int use_iso_level3;
extern int clear_mods;
extern int nofb;
extern char *raw_fb_str;
extern char *pipeinput_str;
extern char *pipeinput_opts;
extern FILE *pipeinput_fh;
extern int pipeinput_tee;
extern unsigned long subwin;
extern int subwin_wait_mapped;
extern int debug_xevents;
extern int debug_xdamage;
extern int debug_wireframe;
extern int debug_tiles;
extern int debug_grabs;
extern int xtrap_input;
extern int xinerama;
extern int xrandr;
extern char *xrandr_mode;
extern char *pad_geometry;
extern time_t pad_geometry_time;
extern int use_snapfb;
extern int use_xrecord;
extern int noxrecord;
extern char *client_connect;
extern char *client_connect_file;
extern int vnc_connect;
extern int show_cursor;
extern int show_multiple_cursors;
extern char *multiple_cursors_mode;
extern int cursor_pos_updates;
extern int cursor_shape_updates;
extern int use_xwarppointer;
extern int show_dragging;
extern int wireframe;
extern char *wireframe_str;
extern char *wireframe_copyrect;
extern char *wireframe_copyrect_default;
extern int wireframe_in_progress;
extern char *scroll_copyrect_str;
extern char *scroll_copyrect;
extern char *scroll_copyrect_default;
extern char *scroll_key_list_str;
extern KeySym *scroll_key_list;
extern int scaling_copyrect0;
extern int scaling_copyrect;
extern int scrollcopyrect_min_area;
extern int debug_scroll;
extern double pointer_flush_delay;
extern double last_scroll_event;
extern int max_scroll_keyrate;
extern double max_keyrepeat_time;
extern char *max_keyrepeat_str;
extern char *max_keyrepeat_str0;
extern int max_keyrepeat_lo, max_keyrepeat_hi;
extern char **scroll_good_all;
extern char **scroll_good_key;
extern char **scroll_good_mouse;
extern char *scroll_good_str;
extern char *scroll_good_str0;
extern char **scroll_skip_all;
extern char **scroll_skip_key;
extern char **scroll_skip_mouse;
extern char *scroll_skip_str;
extern char *scroll_skip_str0;
extern char **scroll_term;
extern char *scroll_term_str;
extern char *scroll_term_str0;
extern char* screen_fixup_str;
extern double screen_fixup_V;
extern double screen_fixup_C;
extern double screen_fixup_X;
extern int no_autorepeat;
extern int no_repeat_countdown;
extern int watch_bell;
extern int sound_bell;
extern int xkbcompat;
extern int use_xkb_modtweak;
extern int skip_duplicate_key_events;
extern char *skip_keycodes;
extern int sloppy_keys;
extern int add_keysyms;
extern char *remap_file;
extern char *pointer_remap;
extern int pointer_mode;
extern int pointer_mode_max;
extern int single_copytile;
extern int single_copytile_orig;
extern int single_copytile_count;
extern int tile_shm_count;
extern int using_shm;
extern int flip_byte_order;
extern int waitms;
extern double wait_ui;
extern double slow_fb;
extern int wait_bog;
extern int defer_update;
extern int got_defer;
extern int got_deferupdate;
extern int screen_blank;
extern int no_fbu_blank;
extern int take_naps;
extern int naptile;
extern int napfac;
extern int napmax;
extern int ui_skip;
extern int watch_selection;
extern int watch_primary;
extern char *sel_direction;
extern char *sigpipe;
extern VisualID visual_id;
extern int visual_depth;
extern int overlay;
extern int overlay_cursor;
extern double fs_frac;
extern int tile_fuzz;
extern int grow_fill;
extern int gaps_fill;
extern int debug_pointer;
extern int debug_keyboard;
extern int quiet;
extern int use_threads;
extern int got_rfbport;
extern int got_alwaysshared;
extern int got_nevershared;
extern int got_cursorpos;
extern int got_pointer_mode;
extern int got_noviewonly;
extern int got_wirecopyrect;
extern int got_scrollcopyrect;
extern int got_noxkb;
extern int got_nomodtweak;
#endif /* _X11VNC_OPTIONS_H */

@ -0,0 +1,33 @@
#ifndef _X11VNC_PARAMS_H
#define _X11VNC_PARAMS_H
/* -- params.h -- */
#define ICON_MODE_SOCKS 16
#ifndef WIREFRAME_PARMS
#define WIREFRAME_PARMS "0xff,3,0,32+8+8+8,all,0.15+0.30+5.0+0.125"
#endif
#ifndef SCROLL_COPYRECT_PARMS
#define SCROLL_COPYRECT_PARMS "0+64+32+32,0.02+0.10+0.9,0.03+0.06+0.5+0.1+5.0"
#endif
#define LATENCY0 20 /* 20ms */
#define NETRATE0 20 /* 20KB/sec */
#define POINTER_MODE_NOFB 2
/* scan pattern jitter from x0rfbserver */
#define NSCAN 32
#define FB_COPY 0x1
#define FB_MOD 0x2
#define FB_REQ 0x4
#define VNC_CONNECT_MAX 16384
#define PROP_MAX (131072L)
#define MAXN 256
#endif /* _X11VNC_PARAMS_H */

File diff suppressed because it is too large Load Diff

@ -0,0 +1,14 @@
#ifndef _X11VNC_POINTER_H
#define _X11VNC_POINTER_H
/* -- pointer.h -- */
extern int pointer_queued_sent;
extern void initialize_pointer_map(char *pointer_remap);
extern void do_button_mask_change(int mask, int button);
extern void pointer(int mask, int x, int y, rfbClientPtr client);
extern int check_pipeinput(void);
extern void initialize_pipeinput(void);
#endif /* _X11VNC_POINTER_H */

@ -0,0 +1,595 @@
/* -- rates.c -- */
#include "x11vnc.h"
#include "xwrappers.h"
#include "scan.h"
int measure_speeds = 1;
int speeds_net_rate = 0;
int speeds_net_rate_measured = 0;
int speeds_net_latency = 0;
int speeds_net_latency_measured = 0;
int speeds_read_rate = 0;
int speeds_read_rate_measured = 0;
int get_cmp_rate(void);
int get_raw_rate(void);
void initialize_speeds(void);
int get_read_rate(void);
int link_rate(int *latency, int *netrate);
int get_net_rate(void);
int get_net_latency(void);
void measure_send_rates(int init);
static void measure_display_hook(rfbClientPtr cl);
static int get_rate(int which);
static int get_latency(void);
static void measure_display_hook(rfbClientPtr cl) {
ClientData *cd = (ClientData *) cl->clientData;
dtime0(&cd->timer);
}
static int get_rate(int which) {
rfbClientIteratorPtr iter;
rfbClientPtr cl;
int irate, irate_min = 1; /* 1 KB/sec */
int irate_max = 100000; /* 100 MB/sec */
int count = 0;
double slowest = -1.0, rate;
static double save_rate = 1000 * NETRATE0;
if (!screen) {
return 0;
}
iter = rfbGetClientIterator(screen);
while( (cl = rfbClientIteratorNext(iter)) ) {
ClientData *cd = (ClientData *) cl->clientData;
if (cl->state != RFB_NORMAL) {
continue;
}
if (cd->send_cmp_rate == 0.0 || cd->send_raw_rate == 0.0) {
continue;
}
count++;
if (which == 0) {
rate = cd->send_cmp_rate;
} else {
rate = cd->send_raw_rate;
}
if (slowest == -1.0 || rate < slowest) {
slowest = rate;
}
}
rfbReleaseClientIterator(iter);
if (! count) {
return NETRATE0;
}
if (slowest == -1.0) {
slowest = save_rate;
} else {
save_rate = slowest;
}
irate = (int) (slowest/1000.0);
if (irate < irate_min) {
irate = irate_min;
}
if (irate > irate_max) {
irate = irate_max;
}
if (0) fprintf(stderr, "get_rate(%d) %d %.3f/%.3f\n", which, irate, save_rate, slowest);
return irate;
}
static int get_latency(void) {
rfbClientIteratorPtr iter;
rfbClientPtr cl;
int ilat, ilat_min = 1; /* 1 ms */
int ilat_max = 2000; /* 2 sec */
double slowest = -1.0, lat;
static double save_lat = ((double) LATENCY0)/1000.0;
int count = 0;
if (!screen) {
return 0;
}
iter = rfbGetClientIterator(screen);
while( (cl = rfbClientIteratorNext(iter)) ) {
ClientData *cd = (ClientData *) cl->clientData;
if (cl->state != RFB_NORMAL) {
continue;
}
if (cd->latency == 0.0) {
continue;
}
count++;
lat = cd->latency;
if (slowest == -1.0 || lat > slowest) {
slowest = lat;
}
}
rfbReleaseClientIterator(iter);
if (! count) {
return LATENCY0;
}
if (slowest == -1.0) {
slowest = save_lat;
} else {
save_lat = slowest;
}
ilat = (int) (slowest * 1000.0);
if (ilat < ilat_min) {
ilat = ilat_min;
}
if (ilat > ilat_max) {
ilat = ilat_max;
}
return ilat;
}
int get_cmp_rate(void) {
return get_rate(0);
}
int get_raw_rate(void) {
return get_rate(1);
}
void initialize_speeds(void) {
char *s, *s_in, *p;
int i;
speeds_read_rate = 0;
speeds_net_rate = 0;
speeds_net_latency = 0;
if (! speeds_str || *speeds_str == '\0') {
s_in = strdup("");
} else {
s_in = strdup(speeds_str);
}
if (!strcmp(s_in, "modem")) {
s = strdup("6,4,200");
} else if (!strcmp(s_in, "dsl")) {
s = strdup("6,100,50");
} else if (!strcmp(s_in, "lan")) {
s = strdup("6,5000,1");
} else {
s = strdup(s_in);
}
p = strtok(s, ",");
i = 0;
while (p) {
double val;
if (*p != '\0') {
val = atof(p);
if (i==0) {
speeds_read_rate = (int) 1000000 * val;
} else if (i==1) {
speeds_net_rate = (int) 1000 * val;
} else if (i==2) {
speeds_net_latency = (int) val;
}
}
i++;
p = strtok(NULL, ",");
}
free(s);
free(s_in);
if (! speeds_read_rate) {
int n = 0;
double dt, timer;
dtime0(&timer);
if (fullscreen) {
copy_image(fullscreen, 0, 0, 0, 0);
n = fullscreen->bytes_per_line * fullscreen->height;
} else if (scanline) {
copy_image(scanline, 0, 0, 0, 0);
n = scanline->bytes_per_line * scanline->height;
}
dt = dtime(&timer);
if (n && dt > 0.0) {
double rate = ((double) n) / dt;
speeds_read_rate_measured = (int) (rate/1000000.0);
if (speeds_read_rate_measured < 1) {
speeds_read_rate_measured = 1;
} else {
rfbLog("fb read rate: %d MB/sec\n",
speeds_read_rate_measured);
}
}
}
}
int get_read_rate(void) {
if (speeds_read_rate) {
return speeds_read_rate;
}
if (speeds_read_rate_measured) {
return speeds_read_rate_measured;
}
return 0;
}
int link_rate(int *latency, int *netrate) {
*latency = get_net_latency();
*netrate = get_net_rate();
if (speeds_str) {
if (!strcmp(speeds_str, "modem")) {
return LR_DIALUP;
} else if (!strcmp(speeds_str, "dsl")) {
return LR_BROADBAND;
} else if (!strcmp(speeds_str, "lan")) {
return LR_LAN;
}
}
if (*latency == LATENCY0 && *netrate == NETRATE0) {
return LR_UNSET;
} else if (*latency > 150 || *netrate < 20) {
return LR_DIALUP;
} else if (*latency > 50 || *netrate < 150) {
return LR_BROADBAND;
} else if (*latency < 10 && *netrate > 300) {
return LR_LAN;
} else {
return LR_UNKNOWN;
}
}
int get_net_rate(void) {
int spm = speeds_net_rate_measured;
if (speeds_net_rate) {
return speeds_net_rate;
}
if (! spm || spm == NETRATE0) {
speeds_net_rate_measured = get_cmp_rate();
}
if (speeds_net_rate_measured) {
return speeds_net_rate_measured;
}
return 0;
}
int get_net_latency(void) {
int spm = speeds_net_latency_measured;
if (speeds_net_latency) {
return speeds_net_latency;
}
if (! spm || spm == LATENCY0) {
speeds_net_latency_measured = get_latency();
}
if (speeds_net_latency_measured) {
return speeds_net_latency_measured;
}
return 0;
}
void measure_send_rates(int init) {
double cmp_rate, raw_rate;
static double now, start = 0.0;
static rfbDisplayHookPtr orig_display_hook = NULL;
double cmp_max = 1.0e+08; /* 100 MB/sec */
double cmp_min = 1000.0; /* 9600baud */
double lat_max = 5.0; /* 5 sec */
double lat_min = .0005; /* 0.5 ms */
int min_cmp = 10000, nclients;
rfbClientIteratorPtr iter;
rfbClientPtr cl;
int db = 0, msg = 0;
db = 0;
if (! measure_speeds) {
return;
}
if (speeds_net_rate && speeds_net_latency) {
return;
}
if (! orig_display_hook) {
orig_display_hook = screen->displayHook;
}
if (start == 0.0) {
dtime(&start);
}
dtime0(&now);
now = now - start;
nclients = 0;
if (!screen) {
return;
}
iter = rfbGetClientIterator(screen);
while( (cl = rfbClientIteratorNext(iter)) ) {
int defer, i, cbs, rbs;
char *httpdir;
double dt, dt1 = 0.0, dt2, dt3;
double tm, spin_max = 15.0, spin_lat_max = 1.5;
int got_t2 = 0, got_t3 = 0;
ClientData *cd = (ClientData *) cl->clientData;
if (cd->send_cmp_rate > 0.0) {
continue;
}
nclients++;
cbs = 0;
for (i=0; i<MAX_ENCODINGS; i++) {
cbs += cl->bytesSent[i];
}
rbs = cl->rawBytesEquivalent;
if (init) {
if (db) fprintf(stderr, "%d client num rects req: %d mod: %d cbs: %d "
"rbs: %d dt1: %.3f t: %.3f\n", init,
(int) sraRgnCountRects(cl->requestedRegion),
(int) sraRgnCountRects(cl->modifiedRegion), cbs, rbs, dt1, now);
cd->timer = dnow();
cd->cmp_bytes_sent = cbs;
cd->raw_bytes_sent = rbs;
continue;
}
/* first part of the bulk transfer of initial screen */
dt1 = dtime(&cd->timer);
if (db) fprintf(stderr, "%d client num rects req: %d mod: %d cbs: %d "
"rbs: %d dt1: %.3f t: %.3f\n", init,
(int) sraRgnCountRects(cl->requestedRegion),
(int) sraRgnCountRects(cl->modifiedRegion), cbs, rbs, dt1, now);
if (dt1 <= 0.0) {
continue;
}
cbs = cbs - cd->cmp_bytes_sent;
rbs = rbs - cd->raw_bytes_sent;
if (cbs < min_cmp) {
continue;
}
rfbPE(1000);
if (sraRgnCountRects(cl->modifiedRegion)) {
rfbPE(1000);
}
defer = screen->deferUpdateTime;
httpdir = screen->httpDir;
screen->deferUpdateTime = 0;
screen->httpDir = NULL;
/* mark a small rectangle: */
mark_rect_as_modified(0, 0, 16, 16, 1);
dtime0(&tm);
dt2 = 0.0;
dt3 = 0.0;
if (dt1 < 0.25) {
/* try to cut it down to avoid long pauses. */
spin_max = 5.0;
}
/* when req1 = 1 mod1 == 0, end of 2nd part of bulk transfer */
while (1) {
int req0, req1, mod0, mod1;
req0 = sraRgnCountRects(cl->requestedRegion);
mod0 = sraRgnCountRects(cl->modifiedRegion);
if (use_threads) {
usleep(1000);
} else {
if (mod0) {
rfbPE(1000);
} else {
rfbCFD(1000);
}
}
dt = dtime(&tm);
dt2 += dt;
if (dt2 > spin_max) {
break;
}
req1 = sraRgnCountRects(cl->requestedRegion);
mod1 = sraRgnCountRects(cl->modifiedRegion);
if (db) fprintf(stderr, "dt2 calc: num rects req: %d/%d mod: %d/%d "
"fbu-sent: %d dt: %.4f dt2: %.4f tm: %.4f\n",
req0, req1, mod0, mod1, cl->framebufferUpdateMessagesSent, dt, dt2, tm);
if (req1 != 0 && mod1 == 0) {
got_t2 = 1;
break;
}
}
if (! got_t2) {
dt2 = 0.0;
} else {
int tr, trm = 3;
double dts[10];
/*
* Note: since often select(2) cannot sleep
* less than 1/HZ (e.g. 10ms), the resolution
* of the latency may be messed up by something
* of this order. Effect may occur on both ends,
* i.e. the viewer may not respond immediately.
*/
for (tr = 0; tr < trm; tr++) {
usleep(5000);
/* mark a 2nd small rectangle: */
mark_rect_as_modified(0, 0, 16, 16, 1);
i = 0;
dtime0(&tm);
dt3 = 0.0;
/*
* when req1 > 0 and mod1 == 0, we say
* that is the "ping" time.
*/
while (1) {
int req0, req1, mod0, mod1;
req0 = sraRgnCountRects(
cl->requestedRegion);
mod0 = sraRgnCountRects(
cl->modifiedRegion);
if (i == 0) {
rfbPE(0);
} else {
if (use_threads) {
usleep(1000);
} else {
/* try to get it all */
rfbCFD(1000*1000);
}
}
dt = dtime(&tm);
i++;
dt3 += dt;
if (dt3 > spin_lat_max) {
break;
}
req1 = sraRgnCountRects(
cl->requestedRegion);
mod1 = sraRgnCountRects(
cl->modifiedRegion);
if (db) fprintf(stderr, "dt3 calc: num rects req: %d/%d mod: %d/%d "
"fbu-sent: %d dt: %.4f dt3: %.4f tm: %.4f\n",
req0, req1, mod0, mod1, cl->framebufferUpdateMessagesSent, dt, dt3, tm);
if (req1 != 0 && mod1 == 0) {
dts[got_t3++] = dt3;
break;
}
}
}
if (! got_t3) {
dt3 = 0.0;
} else {
if (got_t3 == 1) {
dt3 = dts[0];
} else if (got_t3 == 2) {
dt3 = dts[1];
} else {
if (dts[2] >= 0.0) {
double rat = dts[1]/dts[2];
if (rat > 0.5 && rat < 2.0) {
dt3 = dts[1]+dts[2];
dt3 *= 0.5;
} else {
dt3 = dts[1];
}
} else {
dt3 = dts[1];
}
}
}
}
screen->deferUpdateTime = defer;
screen->httpDir = httpdir;
dt = dt1 + dt2;
if (dt3 <= dt2/2.0) {
/* guess only 1/2 a ping for reply... */
dt = dt - dt3/2.0;
}
cmp_rate = cbs/dt;
raw_rate = rbs/dt;
if (cmp_rate > cmp_max) {
cmp_rate = cmp_max;
}
if (cmp_rate <= cmp_min) {
cmp_rate = cmp_min;
}
cd->send_cmp_rate = cmp_rate;
cd->send_raw_rate = raw_rate;
if (dt3 > lat_max) {
dt3 = lat_max;
}
if (dt3 <= lat_min) {
dt3 = lat_min;
}
cd->latency = dt3;
rfbLog("client %d network rate %.1f KB/sec (%.1f eff KB/sec)\n",
cd->uid, cmp_rate/1000.0, raw_rate/1000.0);
rfbLog("client %d latency: %.1f ms\n", cd->uid, 1000.0*dt3);
rfbLog("dt1: %.4f, dt2: %.4f dt3: %.4f bytes: %d\n",
dt1, dt2, dt3, cbs);
msg = 1;
}
rfbReleaseClientIterator(iter);
if (msg) {
int link, latency, netrate;
char *str = "error";
link = link_rate(&latency, &netrate);
if (link == LR_UNSET) {
str = "LR_UNSET";
} else if (link == LR_UNKNOWN) {
str = "LR_UNKNOWN";
} else if (link == LR_DIALUP) {
str = "LR_DIALUP";
} else if (link == LR_BROADBAND) {
str = "LR_BROADBAND";
} else if (link == LR_LAN) {
str = "LR_LAN";
}
rfbLog("link_rate: %s - %d ms, %d KB/s\n", str, latency,
netrate);
}
if (init) {
if (nclients) {
screen->displayHook = measure_display_hook;
}
} else {
screen->displayHook = orig_display_hook;
}
}

@ -0,0 +1,23 @@
#ifndef _X11VNC_RATES_H
#define _X11VNC_RATES_H
/* -- rates.h -- */
extern int measure_speeds;
extern int speeds_net_rate;
extern int speeds_net_rate_measured;
extern int speeds_net_latency;
extern int speeds_net_latency_measured;
extern int speeds_read_rate;
extern int speeds_read_rate_measured;
extern int get_cmp_rate(void);
extern int get_raw_rate(void);
extern void initialize_speeds(void);
extern int get_read_rate(void);
extern int link_rate(int *latency, int *netrate);
extern int get_net_rate(void);
extern int get_net_latency(void);
extern void measure_send_rates(int init);
#endif /* _X11VNC_RATES_H */

File diff suppressed because it is too large Load Diff

@ -0,0 +1,15 @@
#ifndef _X11VNC_REMOTE_H
#define _X11VNC_REMOTE_H
/* -- remote.h -- */
extern int send_remote_cmd(char *cmd, int query, int wait);
extern int do_remote_query(char *remote_cmd, char *query_cmd, int remote_sync,
int qdefault);
extern void check_black_fb(void);
extern int check_httpdir(void);
extern void http_connections(int on);
extern int remote_control_access_ok(void);
extern char *process_remote_cmd(char *cmd, int stringonly);
#endif /* _X11VNC_REMOTE_H */

File diff suppressed because it is too large Load Diff

@ -0,0 +1,24 @@
#ifndef _X11VNC_SCAN_H
#define _X11VNC_SCAN_H
/* -- scan.h -- */
extern int nap_ok;
extern void initialize_tiles(void);
extern void free_tiles(void);
extern void shm_delete(XShmSegmentInfo *shm);
extern void shm_clean(XShmSegmentInfo *shm, XImage *xim);
extern void initialize_polling_images(void);
extern void scale_rect(double factor, int blend, int interpolate, int Bpp,
char *src_fb, int src_bytes_per_line, char *dst_fb, int dst_bytes_per_line,
int Nx, int Ny, int nx, int ny, int X1, int Y1, int X2, int Y2, int mark);
extern void scale_and_mark_rect(int X1, int Y1, int X2, int Y2);
extern void mark_rect_as_modified(int x1, int y1, int x2, int y2, int force);
extern int copy_screen(void);
extern int copy_snap(void);
extern void nap_sleep(int ms, int split);
extern void set_offset(void);
extern int scan_for_updates(int count_only);
#endif /* _X11VNC_SCAN_H */

File diff suppressed because it is too large Load Diff

@ -0,0 +1,19 @@
#ifndef _X11VNC_SCREEN_H
#define _X11VNC_SCREEN_H
/* -- screen.h -- */
extern void set_colormap(int reset);
extern void set_nofb_params(int restore);
extern void set_raw_fb_params(int restore);
extern void do_new_fb(int reset_mem);
extern void check_padded_fb(void);
extern void install_padded_fb(char *geom);
extern XImage *initialize_xdisplay_fb(void);
extern void parse_scale_string(char *str, double *factor, int *scaling, int *blend,
int *nomult4, int *pad, int *interpolate, int *numer, int *denom);
extern int scale_round(int len, double fac);
extern void initialize_screen(int *argc, char **argv, XImage *fb);
extern void set_vnc_desktop_name(void);
#endif /* _X11VNC_SCREEN_H */

@ -0,0 +1,15 @@
#ifndef _X11VNC_SCROLLEVENT_T_H
#define _X11VNC_SCROLLEVENT_T_H
/* -- scrollevent_t.h -- */
typedef struct scroll_event {
Window win, frame;
int dx, dy;
int x, y, w, h;
double t;
int win_x, win_y, win_w, win_h;
int new_x, new_y, new_w, new_h;
} scroll_event_t;
#endif /* _X11VNC_SCROLLEVENT_T_H */

@ -0,0 +1,298 @@
/* -- selection.c -- */
#include "x11vnc.h"
#include "cleanup.h"
#include "connections.h"
/*
* Selection/Cutbuffer/Clipboard handlers.
*/
int own_selection = 0; /* whether we currently own PRIMARY or not */
int set_cutbuffer = 0; /* to avoid bouncing the CutText right back */
int sel_waittime = 15; /* some seconds to skip before first send */
Window selwin; /* special window for our selection */
/*
* This is where we keep our selection: the string sent TO us from VNC
* clients, and the string sent BY us to requesting X11 clients.
*/
char *xcut_str = NULL;
void selection_request(XEvent *ev);
int check_sel_direction(char *dir, char *label, char *sel, int len);
void cutbuffer_send(void);
void selection_send(XEvent *ev);
/*
* Our callbacks instruct us to check for changes in the cutbuffer
* and PRIMARY selection on the local X11 display.
*
* We store the new cutbuffer and/or PRIMARY selection data in this
* constant sized array selection_str[].
* TODO: check if malloc does not cause performance issues (esp. WRT
* SelectionNotify handling).
*/
static char selection_str[PROP_MAX+1];
/*
* An X11 (not VNC) client on the local display has requested the selection
* from us (because we are the current owner).
*
* n.b.: our caller already has the X_LOCK.
*/
void selection_request(XEvent *ev) {
XSelectionEvent notify_event;
XSelectionRequestEvent *req_event;
XErrorHandler old_handler;
unsigned int length;
unsigned char *data;
#ifndef XA_LENGTH
unsigned long XA_LENGTH = XInternAtom(dpy, "LENGTH", True);
#endif
req_event = &(ev->xselectionrequest);
notify_event.type = SelectionNotify;
notify_event.display = req_event->display;
notify_event.requestor = req_event->requestor;
notify_event.selection = req_event->selection;
notify_event.target = req_event->target;
notify_event.time = req_event->time;
if (req_event->property == None) {
notify_event.property = req_event->target;
} else {
notify_event.property = req_event->property;
}
if (xcut_str) {
length = strlen(xcut_str);
} else {
length = 0;
}
/* the window may have gone away, so trap errors */
trapped_xerror = 0;
old_handler = XSetErrorHandler(trap_xerror);
if (ev->xselectionrequest.target == XA_LENGTH) {
/* length request */
XChangeProperty(ev->xselectionrequest.display,
ev->xselectionrequest.requestor,
ev->xselectionrequest.property,
ev->xselectionrequest.target, 32, PropModeReplace,
(unsigned char *) &length, sizeof(unsigned int));
} else {
/* data request */
data = (unsigned char *)xcut_str;
XChangeProperty(ev->xselectionrequest.display,
ev->xselectionrequest.requestor,
ev->xselectionrequest.property,
ev->xselectionrequest.target, 8, PropModeReplace,
data, length);
}
if (! trapped_xerror) {
XSendEvent(req_event->display, req_event->requestor, False, 0,
(XEvent *)&notify_event);
}
if (trapped_xerror) {
rfbLog("selection_request: ignored XError while sending "
"PRIMARY selection to 0x%x.\n", req_event->requestor);
}
XSetErrorHandler(old_handler);
trapped_xerror = 0;
XFlush(dpy);
}
int check_sel_direction(char *dir, char *label, char *sel, int len) {
int db = 0, ok = 1;
if (sel_direction) {
if (strstr(sel_direction, "debug")) {
db = 1;
}
if (strcmp(sel_direction, "debug")) {
if (strstr(sel_direction, dir) == NULL) {
ok = 0;
}
}
}
if (db) {
char str[40];
int n = 40;
strncpy(str, sel, n);
str[n-1] = '\0';
if (len < n) {
str[len] = '\0';
}
rfbLog("%s: %s...\n", label, str);
if (ok) {
rfbLog("%s: %s-ing it.\n", label, dir);
} else {
rfbLog("%s: NOT %s-ing it.\n", label, dir);
}
}
return ok;
}
/*
* CUT_BUFFER0 property on the local display has changed, we read and
* store it and send it out to any connected VNC clients.
*
* n.b.: our caller already has the X_LOCK.
*/
void cutbuffer_send(void) {
Atom type;
int format, slen, dlen, len;
unsigned long nitems = 0, bytes_after = 0;
unsigned char* data = NULL;
selection_str[0] = '\0';
slen = 0;
/* read the property value into selection_str: */
do {
if (XGetWindowProperty(dpy, DefaultRootWindow(dpy),
XA_CUT_BUFFER0, nitems/4, PROP_MAX/16, False,
AnyPropertyType, &type, &format, &nitems, &bytes_after,
&data) == Success) {
dlen = nitems * (format/8);
if (slen + dlen > PROP_MAX) {
/* too big */
rfbLog("warning: truncating large CUT_BUFFER0"
" selection > %d bytes.\n", PROP_MAX);
XFree(data);
break;
}
memcpy(selection_str+slen, data, dlen);
slen += dlen;
selection_str[slen] = '\0';
XFree(data);
}
} while (bytes_after > 0);
selection_str[PROP_MAX] = '\0';
if (! all_clients_initialized()) {
rfbLog("cutbuffer_send: no send: uninitialized clients\n");
return; /* some clients initializing, cannot send */
}
/* now send it to any connected VNC clients (rfbServerCutText) */
if (!screen) {
return;
}
len = strlen(selection_str);
if (check_sel_direction("send", "cutbuffer_send", selection_str, len)) {
rfbSendServerCutText(screen, selection_str, len);
}
}
/*
* "callback" for our SelectionNotify polling. We try to determine if
* the PRIMARY selection has changed (checking length and first CHKSZ bytes)
* and if it has we store it and send it off to any connected VNC clients.
*
* n.b.: our caller already has the X_LOCK.
*
* TODO: if we were willing to use libXt, we could perhaps get selection
* timestamps to speed up the checking... XtGetSelectionValue().
*
* Also: XFIXES has XFixesSelectSelectionInput().
*/
#define CHKSZ 32
void selection_send(XEvent *ev) {
Atom type;
int format, slen, dlen, oldlen, newlen, toobig = 0, len;
static int err = 0, sent_one = 0;
char before[CHKSZ], after[CHKSZ];
unsigned long nitems = 0, bytes_after = 0;
unsigned char* data = NULL;
/*
* remember info about our last value of PRIMARY (or CUT_BUFFER0)
* so we can check for any changes below.
*/
oldlen = strlen(selection_str);
strncpy(before, selection_str, CHKSZ);
selection_str[0] = '\0';
slen = 0;
/* read in the current value of PRIMARY: */
do {
if (XGetWindowProperty(dpy, ev->xselection.requestor,
ev->xselection.property, nitems/4, PROP_MAX/16, True,
AnyPropertyType, &type, &format, &nitems, &bytes_after,
&data) == Success) {
dlen = nitems * (format/8);
if (slen + dlen > PROP_MAX) {
/* too big */
toobig = 1;
XFree(data);
if (err) { /* cut down on messages */
break;
} else {
err = 5;
}
rfbLog("warning: truncating large PRIMARY"
" selection > %d bytes.\n", PROP_MAX);
break;
}
memcpy(selection_str+slen, data, dlen);
slen += dlen;
selection_str[slen] = '\0';
XFree(data);
}
} while (bytes_after > 0);
if (! toobig) {
err = 0;
} else if (err) {
err--;
}
if (! sent_one) {
/* try to force a send first time in */
oldlen = -1;
sent_one = 1;
}
/* look for changes in the new value */
newlen = strlen(selection_str);
strncpy(after, selection_str, CHKSZ);
if (oldlen == newlen && strncmp(before, after, CHKSZ) == 0) {
/* evidently no change */
return;
}
if (newlen == 0) {
/* do not bother sending a null string out */
return;
}
if (! all_clients_initialized()) {
rfbLog("selection_send: no send: uninitialized clients\n");
return; /* some clients initializing, cannot send */
}
/* now send it to any connected VNC clients (rfbServerCutText) */
if (!screen) {
return;
}
len = newlen;
if (check_sel_direction("send", "selection_send", selection_str, len)) {
rfbSendServerCutText(screen, selection_str, len);
}
}

@ -0,0 +1,17 @@
#ifndef _X11VNC_SELECTION_H
#define _X11VNC_SELECTION_H
/* -- selection.h -- */
extern char *xcut_str;
extern int own_selection;
extern int set_cutbuffer;
extern int sel_waittime;
extern Window selwin;
extern void selection_request(XEvent *ev);
extern int check_sel_direction(char *dir, char *label, char *sel, int len);
extern void cutbuffer_send(void);
extern void selection_send(XEvent *ev);
#endif /* _X11VNC_SELECTION_H */

@ -0,0 +1,722 @@
/* -- solid.c -- */
#include "x11vnc.h"
#include "win_utils.h"
char *guess_desktop(void);
void solid_bg(int restore);
static void usr_bin_path(int restore);
static int dt_cmd(char *cmd);
static char *cmd_output(char *cmd);
static void solid_root(char *color);
static void solid_cde(char *color);
static void solid_gnome(char *color);
static void solid_kde(char *color);
static void usr_bin_path(int restore) {
static char *oldpath = NULL;
char *newpath;
char addpath[] = "/usr/bin:/bin:";
if (restore) {
if (oldpath) {
set_env("PATH", oldpath);
free(oldpath);
oldpath = NULL;
}
return;
}
if (getenv("PATH")) {
oldpath = strdup(getenv("PATH"));
} else {
oldpath = strdup("/usr/bin");
}
newpath = (char *) malloc(strlen(oldpath) + strlen(addpath) + 1);
newpath[0] = '\0';
strcat(newpath, addpath);
strcat(newpath, oldpath);
set_env("PATH", newpath);
free(newpath);
}
static int dt_cmd(char *cmd) {
int rc;
if (!cmd || *cmd == '\0') {
return 0;
}
if (no_external_cmds) {
rfbLog("cannot run external commands in -nocmds mode:\n");
rfbLog(" \"%s\"\n", cmd);
rfbLog(" dt_cmd: returning 1\n");
return 1;
}
if (getenv("DISPLAY") == NULL) {
set_env("DISPLAY", DisplayString(dpy));
}
rfbLog("running command:\n %s\n", cmd);
usr_bin_path(0);
rc = system(cmd);
usr_bin_path(1);
if (rc >= 256) {
rc = rc/256;
}
return rc;
}
static char *cmd_output(char *cmd) {
FILE *p;
static char output[50000];
char line[1024];
int rc;
if (!cmd || *cmd == '\0') {
return "";
}
if (no_external_cmds) {
rfbLog("cannot run external commands in -nocmds mode:\n");
rfbLog(" \"%s\"\n", cmd);
rfbLog(" cmd_output: null string.\n");
return "";
}
rfbLog("running pipe:\n %s\n", cmd);
usr_bin_path(0);
p = popen(cmd, "r");
usr_bin_path(1);
output[0] = '\0';
while (fgets(line, 1024, p) != NULL) {
if (strlen(output) + strlen(line) + 1 < 50000) {
strcat(output, line);
}
}
rc = pclose(p);
return(output);
}
static void solid_root(char *color) {
Window expose;
static XImage *image = NULL;
Pixmap pixmap;
XGCValues gcv;
GC gc;
XSetWindowAttributes swa;
Visual visual;
unsigned long mask, pixel;
XColor cdef;
Colormap cmap;
if (subwin || window != rootwin) {
rfbLog("cannot set subwin to solid color, must be rootwin\n");
return;
}
/* create the "clear" window just for generating exposures */
swa.override_redirect = True;
swa.backing_store = NotUseful;
swa.save_under = False;
swa.background_pixmap = None;
visual.visualid = CopyFromParent;
mask = (CWOverrideRedirect|CWBackingStore|CWSaveUnder|CWBackPixmap);
expose = XCreateWindow(dpy, window, 0, 0, wdpy_x, wdpy_y, 0, depth,
InputOutput, &visual, mask, &swa);
if (! color) {
/* restore the root window from the XImage snapshot */
pixmap = XCreatePixmap(dpy, window, wdpy_x, wdpy_y, depth);
if (! image) {
/* whoops */
XDestroyWindow(dpy, expose);
rfbLog("no root snapshot available.\n");
return;
}
/* draw the image to a pixmap: */
gcv.function = GXcopy;
gcv.plane_mask = AllPlanes;
gc = XCreateGC(dpy, window, GCFunction|GCPlaneMask, &gcv);
XPutImage(dpy, pixmap, gc, image, 0, 0, 0, 0, wdpy_x, wdpy_y);
gcv.foreground = gcv.background = BlackPixel(dpy, scr);
gc = XCreateGC(dpy, window, GCForeground|GCBackground, &gcv);
rfbLog("restoring root snapshot...\n");
/* set the pixmap as the bg: */
XSetWindowBackgroundPixmap(dpy, window, pixmap);
XFreePixmap(dpy, pixmap);
XClearWindow(dpy, window);
XFlush(dpy);
/* generate exposures */
XMapWindow(dpy, expose);
XSync(dpy, False);
XDestroyWindow(dpy, expose);
return;
}
if (! image) {
/* need to retrieve a snapshot of the root background: */
Window iwin;
XSetWindowAttributes iswa;
/* create image window: */
iswa.override_redirect = True;
iswa.backing_store = NotUseful;
iswa.save_under = False;
iswa.background_pixmap = ParentRelative;
iwin = XCreateWindow(dpy, window, 0, 0, wdpy_x, wdpy_y, 0,
depth, InputOutput, &visual, mask, &iswa);
rfbLog("snapshotting background...\n");
XMapWindow(dpy, iwin);
XSync(dpy, False);
image = XGetImage(dpy, iwin, 0, 0, wdpy_x, wdpy_y, AllPlanes,
ZPixmap);
XSync(dpy, False);
XDestroyWindow(dpy, iwin);
}
/* use black for low colors or failure */
pixel = BlackPixel(dpy, scr);
if (depth > 8 || strcmp(color, solid_default)) {
cmap = DefaultColormap (dpy, scr);
if (XParseColor(dpy, cmap, color, &cdef) &&
XAllocColor(dpy, cmap, &cdef)) {
pixel = cdef.pixel;
} else {
rfbLog("error parsing/allocing color: %s\n", color);
}
}
rfbLog("setting solid background...\n");
XSetWindowBackground(dpy, window, pixel);
XMapWindow(dpy, expose);
XSync(dpy, False);
XDestroyWindow(dpy, expose);
}
static void solid_cde(char *color) {
int wsmax = 16;
static XImage *image[16];
static Window ws_wins[16];
static int nws = -1;
Window expose;
Pixmap pixmap;
XGCValues gcv;
GC gc;
XSetWindowAttributes swa;
Visual visual;
unsigned long mask, pixel;
XColor cdef;
Colormap cmap;
int n;
if (subwin || window != rootwin) {
rfbLog("cannot set subwin to solid color, must be rootwin\n");
return;
}
/* create the "clear" window just for generating exposures */
swa.override_redirect = True;
swa.backing_store = NotUseful;
swa.save_under = False;
swa.background_pixmap = None;
visual.visualid = CopyFromParent;
mask = (CWOverrideRedirect|CWBackingStore|CWSaveUnder|CWBackPixmap);
expose = XCreateWindow(dpy, window, 0, 0, wdpy_x, wdpy_y, 0, depth,
InputOutput, &visual, mask, &swa);
if (! color) {
/* restore the backdrop windows from the XImage snapshots */
for (n=0; n < nws; n++) {
Window twin;
if (! image[n]) {
continue;
}
twin = ws_wins[n];
if (! twin) {
twin = rootwin;
}
if (! valid_window(twin, NULL, 0)) {
continue;
}
pixmap = XCreatePixmap(dpy, twin, wdpy_x, wdpy_y,
depth);
/* draw the image to a pixmap: */
gcv.function = GXcopy;
gcv.plane_mask = AllPlanes;
gc = XCreateGC(dpy, twin, GCFunction|GCPlaneMask, &gcv);
XPutImage(dpy, pixmap, gc, image[n], 0, 0, 0, 0,
wdpy_x, wdpy_y);
gcv.foreground = gcv.background = BlackPixel(dpy, scr);
gc = XCreateGC(dpy, twin, GCForeground|GCBackground,
&gcv);
rfbLog("restoring CDE ws%d snapshot to 0x%lx\n",
n, twin);
/* set the pixmap as the bg: */
XSetWindowBackgroundPixmap(dpy, twin, pixmap);
XFreePixmap(dpy, pixmap);
XClearWindow(dpy, twin);
XFlush(dpy);
}
/* generate exposures */
XMapWindow(dpy, expose);
XSync(dpy, False);
XDestroyWindow(dpy, expose);
return;
}
if (nws < 0) {
/* need to retrieve snapshots of the ws backgrounds: */
Window iwin, wm_win;
XSetWindowAttributes iswa;
Atom dt_list, wm_info, type;
int format;
unsigned long length, after;
unsigned char *data;
unsigned int * dp;
nws = 0;
/* extract the hidden wm properties about backdrops: */
wm_info = XInternAtom(dpy, "_MOTIF_WM_INFO", True);
if (wm_info == None) {
return;
}
XGetWindowProperty(dpy, rootwin, wm_info, 0L, 10L, False,
AnyPropertyType, &type, &format, &length, &after, &data);
/*
* xprop -notype -root _MOTIF_WM_INFO
* _MOTIF_WM_INFO = 0x2, 0x580028
*/
if (length < 2 || format != 32 || after != 0) {
return;
}
dp = (unsigned int *) data;
wm_win = (Window) *(dp+1); /* 2nd item. */
dt_list = XInternAtom(dpy, "_DT_WORKSPACE_LIST", True);
if (dt_list == None) {
return;
}
XGetWindowProperty(dpy, wm_win, dt_list, 0L, 10L, False,
AnyPropertyType, &type, &format, &length, &after, &data);
nws = length;
if (nws > wsmax) {
nws = wsmax;
}
if (nws < 0) {
nws = 0;
}
rfbLog("special CDE win: 0x%lx, %d workspaces\n", wm_win, nws);
if (nws == 0) {
return;
}
for (n=0; n<nws; n++) {
Atom ws_atom;
char tmp[32];
Window twin;
XWindowAttributes attr;
int i, cnt;
image[n] = NULL;
ws_wins[n] = 0x0;
sprintf(tmp, "_DT_WORKSPACE_INFO_ws%d", n);
ws_atom = XInternAtom(dpy, tmp, False);
if (ws_atom == None) {
continue;
}
XGetWindowProperty(dpy, wm_win, ws_atom, 0L, 100L,
False, AnyPropertyType, &type, &format, &length,
&after, &data);
if (format != 8 || after != 0) {
continue;
}
/*
* xprop -notype -id wm_win
* _DT_WORKSPACE_INFO_ws0 = "One", "3", "0x2f2f4a",
* "0x63639c", "0x103", "1", "0x58044e"
*/
cnt = 0;
twin = 0x0;
for (i=0; i< (int) length; i++) {
if (*(data+i) != '\0') {
continue;
}
cnt++; /* count nulls to indicate field */
if (cnt == 6) {
/* one past the null: */
char *q = (char *) (data+i+1);
unsigned long in;
if (sscanf(q, "0x%lx", &in) == 1) {
twin = (Window) in;
break;
}
}
}
ws_wins[n] = twin;
if (! twin) {
twin = rootwin;
}
XGetWindowAttributes(dpy, twin, &attr);
if (twin != rootwin) {
if (attr.map_state != IsViewable) {
XMapWindow(dpy, twin);
}
XRaiseWindow(dpy, twin);
}
XSync(dpy, False);
/* create image window: */
iswa.override_redirect = True;
iswa.backing_store = NotUseful;
iswa.save_under = False;
iswa.background_pixmap = ParentRelative;
visual.visualid = CopyFromParent;
iwin = XCreateWindow(dpy, twin, 0, 0, wdpy_x, wdpy_y,
0, depth, InputOutput, &visual, mask, &iswa);
rfbLog("snapshotting CDE backdrop ws%d 0x%lx -> "
"0x%lx ...\n", n, twin, iwin);
XMapWindow(dpy, iwin);
XSync(dpy, False);
image[n] = XGetImage(dpy, iwin, 0, 0, wdpy_x, wdpy_y,
AllPlanes, ZPixmap);
XSync(dpy, False);
XDestroyWindow(dpy, iwin);
if (twin != rootwin) {
XLowerWindow(dpy, twin);
if (attr.map_state != IsViewable) {
XUnmapWindow(dpy, twin);
}
}
}
}
if (nws == 0) {
return;
}
/* use black for low colors or failure */
pixel = BlackPixel(dpy, scr);
if (depth > 8 || strcmp(color, solid_default)) {
cmap = DefaultColormap (dpy, scr);
if (XParseColor(dpy, cmap, color, &cdef) &&
XAllocColor(dpy, cmap, &cdef)) {
pixel = cdef.pixel;
} else {
rfbLog("error parsing/allocing color: %s\n", color);
}
}
rfbLog("setting solid backgrounds...\n");
for (n=0; n < nws; n++) {
Window twin = ws_wins[n];
if (image[n] == NULL) {
continue;
}
if (! twin) {
twin = rootwin;
}
XSetWindowBackground(dpy, twin, pixel);
}
XMapWindow(dpy, expose);
XSync(dpy, False);
XDestroyWindow(dpy, expose);
}
static void solid_gnome(char *color) {
char get_color[] = "gconftool-2 --get "
"/desktop/gnome/background/primary_color";
char set_color[] = "gconftool-2 --set "
"/desktop/gnome/background/primary_color --type string '%s'";
char get_option[] = "gconftool-2 --get "
"/desktop/gnome/background/picture_options";
char set_option[] = "gconftool-2 --set "
"/desktop/gnome/background/picture_options --type string '%s'";
static char *orig_color = NULL;
static char *orig_option = NULL;
char *cmd;
if (! color) {
if (! orig_color) {
orig_color = strdup("#FFFFFF");
}
if (! orig_option) {
orig_option = strdup("stretched");
}
if (strstr(orig_color, "'") != NULL) {
rfbLog("invalid color: %s\n", orig_color);
return;
}
if (strstr(orig_option, "'") != NULL) {
rfbLog("invalid option: %s\n", orig_option);
return;
}
cmd = (char *) malloc(strlen(set_option) - 2 +
strlen(orig_option) + 1);
sprintf(cmd, set_option, orig_option);
dt_cmd(cmd);
free(cmd);
cmd = (char *) malloc(strlen(set_color) - 2 +
strlen(orig_color) + 1);
sprintf(cmd, set_color, orig_color);
dt_cmd(cmd);
free(cmd);
return;
}
if (! orig_color) {
char *q;
orig_color = strdup(cmd_output(get_color));
if (*orig_color == '\0') {
orig_color = strdup("#FFFFFF");
}
if ((q = strchr(orig_color, '\n')) != NULL) {
*q = '\0';
}
}
if (! orig_option) {
char *q;
orig_option = strdup(cmd_output(get_option));
if (*orig_option == '\0') {
orig_option = strdup("stretched");
}
if ((q = strchr(orig_option, '\n')) != NULL) {
*q = '\0';
}
}
if (strstr(color, "'") != NULL) {
rfbLog("invalid color: %s\n", color);
return;
}
cmd = (char *) malloc(strlen(set_color) + strlen(color) + 1);
sprintf(cmd, set_color, color);
dt_cmd(cmd);
free(cmd);
cmd = (char *) malloc(strlen(set_option) + strlen("none") + 1);
sprintf(cmd, set_option, "none");
dt_cmd(cmd);
free(cmd);
}
static void solid_kde(char *color) {
char set_color[] =
"dcop --user '%s' kdesktop KBackgroundIface setColor '%s' 1";
char bg_off[] =
"dcop --user '%s' kdesktop KBackgroundIface setBackgroundEnabled 0";
char bg_on[] =
"dcop --user '%s' kdesktop KBackgroundIface setBackgroundEnabled 1";
char *cmd, *user = NULL;
int len;
user = get_user_name();
if (strstr(user, "'") != NULL) {
rfbLog("invalid user: %s\n", user);
free(user);
return;
}
if (! color) {
len = strlen(bg_on) + strlen(user) + 1;
cmd = (char *) malloc(len);
sprintf(cmd, bg_on, user);
dt_cmd(cmd);
free(cmd);
free(user);
return;
}
if (strstr(color, "'") != NULL) {
rfbLog("invalid color: %s\n", color);
return;
}
len = strlen(set_color) + strlen(user) + strlen(color) + 1;
cmd = (char *) malloc(len);
sprintf(cmd, set_color, user, color);
dt_cmd(cmd);
free(cmd);
len = strlen(bg_off) + strlen(user) + 1;
cmd = (char *) malloc(len);
sprintf(cmd, bg_off, user);
dt_cmd(cmd);
free(cmd);
free(user);
}
char *guess_desktop(void) {
Atom prop;
if (wmdt_str && *wmdt_str != '\0') {
char *s = wmdt_str;
lowercase(s);
if (strstr(s, "xfce")) {
return "xfce";
}
if (strstr(s, "gnome") || strstr(s, "metacity")) {
return "gnome";
}
if (strstr(s, "kde") || strstr(s, "kwin")) {
return "kde";
}
if (strstr(s, "cde")) {
return "cde";
}
return "root";
}
if (! dpy) {
return "";
}
prop = XInternAtom(dpy, "XFCE_DESKTOP_WINDOW", True);
if (prop != None) return "xfce";
/* special case windowmaker */
prop = XInternAtom(dpy, "_WINDOWMAKER_WM_PROTOCOLS", True);
if (prop != None) return "root";
prop = XInternAtom(dpy, "_WINDOWMAKER_COMMAND", True);
if (prop != None) return "root";
prop = XInternAtom(dpy, "NAUTILUS_DESKTOP_WINDOW_ID", True);
if (prop != None) return "gnome";
prop = XInternAtom(dpy, "KWIN_RUNNING", True);
if (prop != None) return "kde";
prop = XInternAtom(dpy, "_MOTIF_WM_INFO", True);
if (prop != None) {
prop = XInternAtom(dpy, "_DT_WORKSPACE_LIST", True);
if (prop != None) return "cde";
}
return "root";
}
void solid_bg(int restore) {
static int desktop = -1;
static int solid_on = 0;
static char *prev_str;
char *dtname, *color;
if (started_as_root == 1 && users_list) {
/* we are still root, don't try. */
return;
}
if (restore) {
if (! solid_on) {
return;
}
if (desktop == 0) {
solid_root(NULL);
} else if (desktop == 1) {
solid_gnome(NULL);
} else if (desktop == 2) {
solid_kde(NULL);
} else if (desktop == 3) {
solid_cde(NULL);
}
solid_on = 0;
return;
}
if (! solid_str) {
return;
}
if (solid_on && !strcmp(prev_str, solid_str)) {
return;
}
if (strstr(solid_str, "guess:") == solid_str
|| !strchr(solid_str, ':')) {
dtname = guess_desktop();
rfbLog("guessed desktop: %s\n", dtname);
} else {
if (strstr(solid_str, "gnome:") == solid_str) {
dtname = "gnome";
} else if (strstr(solid_str, "kde:") == solid_str) {
dtname = "kde";
} else if (strstr(solid_str, "cde:") == solid_str) {
dtname = "cde";
} else {
dtname = "root";
}
}
color = strchr(solid_str, ':');
if (! color) {
color = solid_str;
} else {
color++;
if (*color == '\0') {
color = solid_default;
}
}
if (!strcmp(dtname, "gnome")) {
desktop = 1;
solid_gnome(color);
} else if (!strcmp(dtname, "kde")) {
desktop = 2;
solid_kde(color);
} else if (!strcmp(dtname, "cde")) {
desktop = 3;
solid_cde(color);
} else {
desktop = 0;
solid_root(color);
}
if (prev_str) {
free(prev_str);
}
prev_str = strdup(solid_str);
solid_on = 1;
}

@ -0,0 +1,9 @@
#ifndef _X11VNC_SOLID_H
#define _X11VNC_SOLID_H
/* -- solid.h -- */
extern char *guess_desktop(void);
extern void solid_bg(int restore);
#endif /* _X11VNC_SOLID_H */

@ -90,6 +90,7 @@ Clients
=DRQA disconnect:
--
accept:
afteraccept:
gone:
vncconnect
-- D
@ -5951,6 +5952,11 @@ if {$tk_version < 8.4} {
if {"$argv" == "-spit"} {
set fh [open $argv0 r]
puts "#ifndef _TKX11VNC_H"
puts "#define _TKX11VNC_H"
puts "#ifdef NOGUI"
puts "char gui_code[] = \"\";"
puts "#else"
puts "/*"
puts " * tkx11vnc.h: generated by 'tkx11vnc -spit'"
puts " * Abandon all hope, ye who enter here..."
@ -5962,6 +5968,10 @@ if {"$argv" == "-spit"} {
regsub -all {"} $line {\\"} line
puts "\"$line\\n\""
}
puts "#endif"
puts "/* ifdef NOGUI */"
puts "#endif"
puts "/* ifndef _TKX11VNC_H */"
close $fh
puts ";"
exit 0

@ -1,3 +1,8 @@
#ifndef _TKX11VNC_H
#define _TKX11VNC_H
#ifdef NOGUI
char gui_code = "";
#else
/*
* tkx11vnc.h: generated by 'tkx11vnc -spit'
* Abandon all hope, ye who enter here...
@ -96,6 +101,7 @@
" =DRQA disconnect:\n"
" --\n"
" accept:\n"
" afteraccept:\n"
" gone:\n"
" vncconnect\n"
" -- D\n"
@ -5957,6 +5963,11 @@
"\n"
"if {\"$argv\" == \"-spit\"} {\n"
" set fh [open $argv0 r]\n"
" puts \"#ifndef _TKX11VNC_H\"\n"
" puts \"#define _TKX11VNC_H\"\n"
" puts \"#ifdef NOGUI\"\n"
" puts \"char gui_code[] = \\\"\\\";\"\n"
" puts \"#else\"\n"
" puts \"/*\"\n"
" puts \" * tkx11vnc.h: generated by 'tkx11vnc -spit'\"\n"
" puts \" * Abandon all hope, ye who enter here...\"\n"
@ -5968,6 +5979,10 @@
" regsub -all {\"} $line {\\\\\"} line\n"
" puts \"\\\"$line\\\\n\\\"\"\n"
" }\n"
" puts \"#endif\"\n"
" puts \"/* ifdef NOGUI */\"\n"
" puts \"#endif\"\n"
" puts \"/* ifndef _TKX11VNC_H */\"\n"
" close $fh\n"
" puts \";\"\n"
" exit 0\n"
@ -6170,4 +6185,8 @@
"}\n"
"\n"
"# main loop.\n"
#endif
/* ifdef NOGUI */
#endif
/* ifndef _TKX11VNC_H */
;

@ -0,0 +1,930 @@
/* -- user.c -- */
#include "x11vnc.h"
#include "solid.h"
#include "cleanup.h"
#include "scan.h"
#include "screen.h"
void check_switched_user(void);
void lurk_loop(char *str);
int switch_user(char *user, int fb_mode);
int read_passwds(char *passfile);
void install_passwds(void);
void check_new_passwds(void);
static void switch_user_task_dummy(void);
static void switch_user_task_solid_bg(void);
static char *get_login_list(int with_display);
static char **user_list(char *user_str);
static void user2uid(char *user, uid_t *uid, char **name, char **home);
static int lurk(char **users);
static int guess_user_and_switch(char *str, int fb_mode);
static int try_user_and_display(uid_t uid, char *dpystr);
static int switch_user_env(uid_t uid, char *name, char *home, int fb_mode);
static void try_to_switch_users(void);
/* tasks for after we switch */
static void switch_user_task_dummy(void) {
; /* dummy does nothing */
}
static void switch_user_task_solid_bg(void) {
/* we have switched users, some things to do. */
if (use_solid_bg && client_count) {
solid_bg(0);
}
}
void check_switched_user(void) {
static time_t sched_switched_user = 0;
static int did_solid = 0;
static int did_dummy = 0;
int delay = 15;
time_t now = time(0);
if (started_as_root == 1 && users_list) {
try_to_switch_users();
if (started_as_root == 2) {
/*
* schedule the switch_user_tasks() call
* 15 secs is for piggy desktops to start up.
* might not be enough for slow machines...
*/
sched_switched_user = now;
did_dummy = 0;
did_solid = 0;
/* add other activities */
}
}
if (! sched_switched_user) {
return;
}
if (! did_dummy) {
switch_user_task_dummy();
did_dummy = 1;
}
if (! did_solid) {
int doit = 0;
char *ss = solid_str;
if (now >= sched_switched_user + delay) {
doit = 1;
} else if (ss && strstr(ss, "root:") == ss) {
if (now >= sched_switched_user + 3) {
doit = 1;
}
} else if (strcmp("root", guess_desktop())) {
usleep(1000 * 1000);
doit = 1;
}
if (doit) {
switch_user_task_solid_bg();
did_solid = 1;
}
}
if (did_dummy && did_solid) {
sched_switched_user = 0;
}
}
/* utilities for switching users */
static char *get_login_list(int with_display) {
char *out;
#if LIBVNCSERVER_HAVE_UTMPX_H
int i, cnt, max = 200, ut_namesize = 32;
int dpymax = 1000, sawdpy[1000];
struct utmpx *utx;
/* size based on "username:999," * max */
out = (char *) malloc(max * (ut_namesize+1+3+1) + 1);
out[0] = '\0';
for (i=0; i<dpymax; i++) {
sawdpy[i] = 0;
}
setutxent();
cnt = 0;
while (1) {
char *user, *line, *host, *id;
char tmp[10];
int d = -1;
utx = getutxent();
if (! utx) {
break;
}
if (utx->ut_type != USER_PROCESS) {
continue;
}
user = lblanks(utx->ut_user);
if (*user == '\0') {
continue;
}
if (strchr(user, ',')) {
continue; /* unlikely, but comma is our sep. */
}
line = lblanks(utx->ut_line);
host = lblanks(utx->ut_host);
id = lblanks(utx->ut_id);
if (with_display) {
if (0 && line[0] != ':' && strcmp(line, "dtlocal")) {
/* XXX useful? */
continue;
}
if (line[0] == ':') {
if (sscanf(line, ":%d", &d) != 1) {
d = -1;
}
}
if (d < 0 && host[0] == ':') {
if (sscanf(host, ":%d", &d) != 1) {
d = -1;
}
}
if (d < 0 && id[0] == ':') {
if (sscanf(id, ":%d", &d) != 1) {
d = -1;
}
}
if (d < 0 || d >= dpymax || sawdpy[d]) {
continue;
}
sawdpy[d] = 1;
sprintf(tmp, ":%d", d);
} else {
/* try to eliminate repeats */
int repeat = 0;
char *q;
q = out;
while ((q = strstr(q, user)) != NULL) {
char *p = q + strlen(user) + strlen(":DPY");
if (q == out || *(q-1) == ',') {
/* bounded on left. */
if (*p == ',' || *p == '\0') {
/* bounded on right. */
repeat = 1;
break;
}
}
q = p;
}
if (repeat) {
continue;
}
sprintf(tmp, ":DPY");
}
if (*out) {
strcat(out, ",");
}
strcat(out, user);
strcat(out, tmp);
cnt++;
if (cnt >= max) {
break;
}
}
endutxent();
#else
out = strdup("");
#endif
return out;
}
static char **user_list(char *user_str) {
int n, i;
char *p, **list;
p = user_str;
n = 1;
while (*p++) {
if (*p == ',') {
n++;
}
}
list = (char **) malloc((n+1)*sizeof(char *));
p = strtok(user_str, ",");
i = 0;
while (p) {
list[i++] = p;
p = strtok(NULL, ",");
}
list[i] = NULL;
return list;
}
static void user2uid(char *user, uid_t *uid, char **name, char **home) {
int numerical = 1;
char *q;
*uid = (uid_t) -1;
*name = NULL;
*home = NULL;
q = user;
while (*q) {
if (! isdigit(*q++)) {
numerical = 0;
break;
}
}
if (numerical) {
int u = atoi(user);
if (u < 0) {
return;
}
*uid = (uid_t) u;
}
#if LIBVNCSERVER_HAVE_PWD_H
if (1) {
struct passwd *pw;
if (numerical) {
pw = getpwuid(*uid);
} else {
pw = getpwnam(user);
}
if (pw) {
*uid = pw->pw_uid;
*name = pw->pw_name; /* n.b. use immediately */
*home = pw->pw_dir;
}
}
#endif
}
static int lurk(char **users) {
uid_t uid;
int success = 0, dmin = -1, dmax = -1;
char *p, *logins, **u;
if ((u = users) != NULL && *u != NULL && *(*u) == ':') {
int len;
char *tmp;
/* extract min and max display numbers */
tmp = *u;
if (strchr(tmp, '-')) {
if (sscanf(tmp, ":%d-%d", &dmin, &dmax) != 2) {
dmin = -1;
dmax = -1;
}
}
if (dmin < 0) {
if (sscanf(tmp, ":%d", &dmin) != 1) {
dmin = -1;
dmax = -1;
} else {
dmax = dmin;
}
}
if ((dmin < 0 || dmax < 0) || dmin > dmax || dmax > 10000) {
dmin = -1;
dmax = -1;
}
/* get user logins regardless of having a display: */
logins = get_login_list(0);
/*
* now we append the list in users (might as well try
* them) this will probably allow weird ways of starting
* xservers to work.
*/
len = strlen(logins);
u++;
while (*u != NULL) {
len += strlen(*u) + strlen(":DPY,");
u++;
}
tmp = (char *) malloc(len+1);
strcpy(tmp, logins);
/* now concatenate them: */
u = users+1;
while (*u != NULL) {
char *q, chk[100];
snprintf(chk, 100, "%s:DPY", *u);
q = strstr(tmp, chk);
if (q) {
char *p = q + strlen(chk);
if (q == tmp || *(q-1) == ',') {
/* bounded on left. */
if (*p == ',' || *p == '\0') {
/* bounded on right. */
u++;
continue;
}
}
}
if (*tmp) {
strcat(tmp, ",");
}
strcat(tmp, *u);
strcat(tmp, ":DPY");
u++;
}
free(logins);
logins = tmp;
} else {
logins = get_login_list(1);
}
p = strtok(logins, ",");
while (p) {
char *user, *name, *home, dpystr[10];
char *q, *t;
int ok = 1, dn;
t = strdup(p); /* bob:0 */
q = strchr(t, ':');
if (! q) {
free(t);
break;
}
*q = '\0';
user = t;
snprintf(dpystr, 10, ":%s", q+1);
if (users) {
u = users;
ok = 0;
while (*u != NULL) {
if (*(*u) == ':') {
u++;
continue;
}
if (!strcmp(user, *u++)) {
ok = 1;
break;
}
}
}
user2uid(user, &uid, &name, &home);
free(t);
if (! uid) {
ok = 0;
}
if (! ok) {
p = strtok(NULL, ",");
continue;
}
for (dn = dmin; dn <= dmax; dn++) {
if (dn >= 0) {
sprintf(dpystr, ":%d", dn);
}
if (try_user_and_display(uid, dpystr)) {
if (switch_user_env(uid, name, home, 0)) {
rfbLog("lurk: now user: %s @ %s\n",
name, dpystr);
started_as_root = 2;
success = 1;
}
set_env("DISPLAY", dpystr);
break;
}
}
if (success) {
break;
}
p = strtok(NULL, ",");
}
free(logins);
return success;
}
void lurk_loop(char *str) {
char *tstr = NULL, **users = NULL;
if (strstr(str, "lurk=") != str) {
exit(1);
}
rfbLog("lurking for logins using: '%s'\n", str);
if (strlen(str) > strlen("lurk=")) {
char *q = strchr(str, '=');
tstr = strdup(q+1);
users = user_list(tstr);
}
while (1) {
if (lurk(users)) {
break;
}
sleep(3);
}
if (tstr) {
free(tstr);
}
if (users) {
free(users);
}
}
static int guess_user_and_switch(char *str, int fb_mode) {
char *dstr, *d = DisplayString(dpy);
char *p, *tstr = NULL, *allowed = NULL, *logins, **users = NULL;
int dpy1, ret = 0;
/* pick out ":N" */
dstr = strchr(d, ':');
if (! dstr) {
return 0;
}
if (sscanf(dstr, ":%d", &dpy1) != 1) {
return 0;
}
if (dpy1 < 0) {
return 0;
}
if (strstr(str, "guess=") == str && strlen(str) > strlen("guess=")) {
allowed = strchr(str, '=');
allowed++;
tstr = strdup(allowed);
users = user_list(tstr);
}
/* loop over the utmpx entries looking for this display */
logins = get_login_list(1);
p = strtok(logins, ",");
while (p) {
char *user, *q, *t;
int dpy2, ok = 1;
t = strdup(p);
q = strchr(t, ':');
if (! q) {
free(t);
break;
}
*q = '\0';
user = t;
dpy2 = atoi(q+1);
if (users) {
char **u = users;
ok = 0;
while (*u != NULL) {
if (!strcmp(user, *u++)) {
ok = 1;
break;
}
}
}
if (dpy1 != dpy2) {
ok = 0;
}
if (! ok) {
free(t);
p = strtok(NULL, ",");
continue;
}
if (switch_user(user, fb_mode)) {
rfbLog("switched to guessed user: %s\n", user);
free(t);
ret = 1;
break;
}
p = strtok(NULL, ",");
}
if (tstr) {
free(tstr);
}
if (users) {
free(users);
}
if (logins) {
free(logins);
}
return ret;
}
static int try_user_and_display(uid_t uid, char *dpystr) {
/* NO strtoks */
#if LIBVNCSERVER_HAVE_FORK && LIBVNCSERVER_HAVE_SYS_WAIT_H && LIBVNCSERVER_HAVE_PWD_H
pid_t pid, pidw;
char *home, *name;
int st;
struct passwd *pw;
pw = getpwuid(uid);
if (pw) {
name = pw->pw_name;
home = pw->pw_dir;
} else {
return 0;
}
/*
* We fork here and try to open the display again as the
* new user. Unreadable XAUTHORITY could be a problem...
* This is not really needed since we have DISPLAY open but:
* 1) is a good indicator this user owns the session and 2)
* some activities do spawn new X apps, e.g. xmessage(1), etc.
*/
if ((pid = fork()) > 0) {
;
} else if (pid == -1) {
fprintf(stderr, "could not fork\n");
rfbLogPerror("fork");
return 0;
} else {
/* child */
Display *dpy2 = NULL;
int rc;
rc = switch_user_env(uid, name, home, 0);
if (! rc) {
exit(1);
}
fclose(stderr);
dpy2 = XOpenDisplay(dpystr);
if (dpy2) {
XCloseDisplay(dpy2);
exit(0); /* success */
} else {
exit(2); /* fail */
}
}
/* see what the child says: */
pidw = waitpid(pid, &st, 0);
if (pidw == pid && WIFEXITED(st) && WEXITSTATUS(st) == 0) {
return 1;
}
#endif /* LIBVNCSERVER_HAVE_FORK ... */
return 0;
}
int switch_user(char *user, int fb_mode) {
/* NO strtoks */
int doit = 0;
uid_t uid = 0;
char *name, *home;
if (*user == '+') {
doit = 1;
user++;
}
if (strstr(user, "guess=") == user) {
return guess_user_and_switch(user, fb_mode);
}
user2uid(user, &uid, &name, &home);
if (uid == (uid_t) -1 || uid == 0) {
return 0;
}
if (! doit && dpy) {
/* see if this display works: */
char *dstr = DisplayString(dpy);
doit = try_user_and_display(uid, dstr);
}
if (doit) {
int rc = switch_user_env(uid, name, home, fb_mode);
if (rc) {
started_as_root = 2;
}
return rc;
} else {
return 0;
}
}
static int switch_user_env(uid_t uid, char *name, char *home, int fb_mode) {
/* NO strtoks */
char *xauth;
int reset_fb = 0;
#if !LIBVNCSERVER_HAVE_SETUID
return 0;
#else
/*
* OK tricky here, we need to free the shm... otherwise
* we won't be able to delete it as the other user...
*/
if (fb_mode == 1 && using_shm) {
reset_fb = 1;
clean_shm(0);
free_tiles();
}
if (setuid(uid) != 0) {
if (reset_fb) {
/* 2 means we did clean_shm and free_tiles */
do_new_fb(2);
}
return 0;
}
#endif
if (reset_fb) {
do_new_fb(2);
}
xauth = getenv("XAUTHORITY");
if (xauth && access(xauth, R_OK) != 0) {
*(xauth-2) = '_'; /* yow */
}
set_env("USER", name);
set_env("LOGNAME", name);
set_env("HOME", home);
return 1;
}
static void try_to_switch_users(void) {
static time_t last_try = 0;
time_t now = time(0);
char *users, *p;
if (getuid() && geteuid()) {
rfbLog("try_to_switch_users: not root\n");
started_as_root = 2;
return;
}
if (!last_try) {
last_try = now;
} else if (now <= last_try + 2) {
/* try every 3 secs or so */
return;
}
last_try = now;
users = strdup(users_list);
if (strstr(users, "guess=") == users) {
if (switch_user(users, 1)) {
started_as_root = 2;
}
free(users);
return;
}
p = strtok(users, ",");
while (p) {
if (switch_user(p, 1)) {
started_as_root = 2;
rfbLog("try_to_switch_users: now %s\n", p);
break;
}
p = strtok(NULL, ",");
}
free(users);
}
int read_passwds(char *passfile) {
char line[1024];
char *filename;
char **old_passwd_list = passwd_list;
int remove = 0;
int read_mode = 0;
int begin_vo = -1;
struct stat sbuf;
int linecount = 0, i, max;
FILE *in;
static time_t last_read = 0;
static int read_cnt = 0;
int db_passwd = 0;
filename = passfile;
if (strstr(filename, "rm:") == filename) {
filename += strlen("rm:");
remove = 1;
} else if (strstr(filename, "read:") == filename) {
filename += strlen("read:");
read_mode = 1;
if (stat(filename, &sbuf) == 0) {
if (sbuf.st_mtime <= last_read) {
return 0;
}
last_read = sbuf.st_mtime;
}
}
if (stat(filename, &sbuf) == 0) {
/* (poor...) upper bound to number of lines */
max = (int) sbuf.st_size;
last_read = sbuf.st_mtime;
} else {
max = 64;
}
/* create 1 more than max to have it be the ending NULL */
passwd_list = (char **) malloc( (max+1) * (sizeof(char *)) );
for (i=0; i<max+1; i++) {
passwd_list[i] = NULL;
}
in = fopen(filename, "r");
if (in == NULL) {
rfbLog("cannot open passwdfile: %s\n", passfile);
rfbLogPerror("fopen");
if (remove) {
unlink(filename);
}
clean_up_exit(1);
}
if (getenv("DEBUG_PASSWDFILE") != NULL) {
db_passwd = 1;
}
while (fgets(line, 1024, in) != NULL) {
char *p;
int blank = 1;
int len = strlen(line);
if (db_passwd) {
fprintf(stderr, "read_passwds: raw line: %s\n", line);
}
if (len == 0) {
continue;
} else if (line[len-1] == '\n') {
line[len-1] = '\0';
}
if (line[0] == '\0') {
continue;
}
if (strstr(line, "__SKIP__") != NULL) {
continue;
}
if (strstr(line, "__COMM__") == line) {
continue;
}
if (!strcmp(line, "__BEGIN_VIEWONLY__")) {
if (begin_vo < 0) {
begin_vo = linecount;
}
continue;
}
if (line[0] == '#') {
/* commented out, cannot have password beginning with # */
continue;
}
p = line;
while (*p != '\0') {
if (! isspace(*p)) {
blank = 0;
break;
}
p++;
}
if (blank) {
continue;
}
passwd_list[linecount++] = strdup(line);
if (db_passwd) {
fprintf(stderr, "read_passwds: keepline: %s\n", line);
fprintf(stderr, "read_passwds: begin_vo: %d\n", begin_vo);
}
if (linecount >= max) {
break;
}
}
fclose(in);
for (i=0; i<1024; i++) {
line[i] = '\0';
}
if (remove) {
unlink(filename);
}
if (! linecount) {
rfbLog("cannot read a valid line from passwdfile: %s\n",
passfile);
if (read_cnt == 0) {
clean_up_exit(1);
} else {
return 0;
}
}
read_cnt++;
for (i=0; i<linecount; i++) {
char *q, *p = passwd_list[i];
if (!strcmp(p, "__EMPTY__")) {
*p = '\0';
} else if ((q = strstr(p, "__COMM__")) != NULL) {
*q = '\0';
}
passwd_list[i] = strdup(p);
if (db_passwd) {
fprintf(stderr, "read_passwds: trimline: %s\n", p);
}
strzero(p);
}
begin_viewonly = begin_vo;
if (read_mode && read_cnt > 1) {
if (viewonly_passwd) {
free(viewonly_passwd);
viewonly_passwd = NULL;
}
}
if (begin_viewonly < 0 && linecount == 2) {
/* for compatibility with previous 2-line usage: */
viewonly_passwd = strdup(passwd_list[1]);
if (db_passwd) {
fprintf(stderr, "read_passwds: linecount is 2.\n");
}
if (screen) {
char **apd = (char **) screen->authPasswdData;
if (apd) {
if (apd[0] != NULL) {
strzero(apd[0]);
}
apd[0] = strdup(passwd_list[0]);
}
}
begin_viewonly = 1;
}
if (old_passwd_list != NULL) {
char *p;
i = 0;
while (old_passwd_list[i] != NULL) {
p = old_passwd_list[i];
strzero(p);
free(old_passwd_list[i]);
i++;
}
free(old_passwd_list);
}
return 1;
}
void install_passwds(void) {
if (viewonly_passwd) {
/* append the view only passwd after the normal passwd */
char **passwds_new = (char **) malloc(3*sizeof(char *));
char **passwds_old = (char **) screen->authPasswdData;
passwds_new[0] = passwds_old[0];
passwds_new[1] = viewonly_passwd;
passwds_new[2] = NULL;
screen->authPasswdData = (void*) passwds_new;
} else if (passwd_list) {
int i = 0;
while(passwd_list[i] != NULL) {
i++;
}
if (begin_viewonly < 0) {
begin_viewonly = i+1;
}
screen->authPasswdData = (void*) passwd_list;
screen->authPasswdFirstViewOnly = begin_viewonly;
}
}
void check_new_passwds(void) {
static time_t last_check = 0;
time_t now;
if (! passwdfile) {
return;
}
if (strstr(passwdfile, "read:") != passwdfile) {
return;
}
now = time(0);
if (now > last_check + 1) {
if (read_passwds(passwdfile)) {
install_passwds();
}
last_check = now;
}
}

@ -0,0 +1,13 @@
#ifndef _X11VNC_USER_H
#define _X11VNC_USER_H
/* -- user.h -- */
extern void check_switched_user(void);
extern void lurk_loop(char *str);
extern int switch_user(char *, int);
extern int read_passwds(char *passfile);
extern void install_passwds(void);
extern void check_new_passwds(void);
#endif /* _X11VNC_USER_H */

File diff suppressed because it is too large Load Diff

@ -0,0 +1,39 @@
#ifndef _X11VNC_USERINPUT_H
#define _X11VNC_USERINPUT_H
/* -- userinput.h -- */
extern int defer_update_nofb;
extern int last_scroll_type;
extern int get_wm_frame_pos(int *px, int *py, int *x, int *y, int *w, int *h,
Window *frame, Window *win);
extern void parse_scroll_copyrect(void);
extern void parse_fixscreen(void);
extern void parse_wireframe(void);
extern void set_wirecopyrect_mode(char *str);
extern void set_scrollcopyrect_mode(char *str);
extern void initialize_scroll_keys(void);
extern void initialize_scroll_matches(void);
extern void initialize_scroll_term(void);
extern void initialize_max_keyrepeat(void);
extern int direct_fb_copy(int x1, int y1, int x2, int y2, int mark);
extern void fb_push(void);
extern void fb_push_wait(double max_wait, int flags);
extern void eat_viewonly_input(int max_eat, int keep);
extern void mark_for_xdamage(int x, int y, int w, int h);
extern void mark_region_for_xdamage(sraRegionPtr region);
extern void set_xdamage_mark(int x, int y, int w, int h);
extern int near_wm_edge(int x, int y, int w, int h, int px, int py);
extern int near_scrollbar_edge(int x, int y, int w, int h, int px, int py);
extern void check_fixscreen(void);
extern int check_xrecord(void);
extern int check_wireframe(void);
extern int fb_update_sent(int *count);
extern int check_user_input(double dt, double dtr, int tile_diffs, int *cnt);
#endif /* _X11VNC_USERINPUT_H */

@ -0,0 +1,397 @@
/* -- util.c -- */
#include "x11vnc.h"
#include "cleanup.h"
struct timeval _mysleep;
/* this is only for debugging mutexes. see util.h */
int hxl = 0;
#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
MUTEX(x11Mutex);
MUTEX(scrollMutex);
#endif
int nfix(int i, int n);
int nabs(int n);
double dabs(double x);
void lowercase(char *str);
void uppercase(char *str);
char *lblanks(char *str);
void strzero(char *str);
int scan_hexdec(char *str, unsigned long *num);
int parse_geom(char *str, int *wp, int *hp, int *xp, int *yp, int W, int H);
void set_env(char *name, char *value);
char *bitprint(unsigned int st, int nbits);
char *get_user_name(void);
char *get_home_dir(void);
char *get_shell(void);
char *this_host(void);
int match_str_list(char *str, char **list);
char **create_str_list(char *cslist);
double dtime(double *);
double dtime0(double *);
double dnow(void);
double dnowx(void);
double rnow(void);
double rfac(void);
void rfbPE(long usec);
void rfbCFD(long usec);
/*
* routine to keep 0 <= i < n, should use in more places...
*/
int nfix(int i, int n) {
if (i < 0) {
i = 0;
} else if (i >= n) {
i = n - 1;
}
return i;
}
int nabs(int n) {
if (n < 0) {
return -n;
} else {
return n;
}
}
double dabs(double x) {
if (x < 0.0) {
return -x;
} else {
return x;
}
}
void lowercase(char *str) {
char *p;
if (str == NULL) {
return;
}
p = str;
while (*p != '\0') {
*p = tolower(*p);
p++;
}
}
void uppercase(char *str) {
char *p;
if (str == NULL) {
return;
}
p = str;
while (*p != '\0') {
*p = toupper(*p);
p++;
}
}
char *lblanks(char *str) {
char *p = str;
while (*p) {
if (! isspace(*p)) {
break;
}
p++;
}
return p;
}
void strzero(char *str) {
char *p = str;
if (p != NULL) {
while (*p != '\0') {
*p = '\0';
p++;
}
}
}
int scan_hexdec(char *str, unsigned long *num) {
if (sscanf(str, "0x%lx", num) != 1) {
if (sscanf(str, "%lu", num) != 1) {
return 0;
}
}
return 1;
}
int parse_geom(char *str, int *wp, int *hp, int *xp, int *yp, int W, int H) {
int w, h, x, y;
/* handle +/-x and +/-y */
if (sscanf(str, "%dx%d+%d+%d", &w, &h, &x, &y) == 4) {
;
} else if (sscanf(str, "%dx%d-%d+%d", &w, &h, &x, &y) == 4) {
w = nabs(w);
x = W - x - w;
} else if (sscanf(str, "%dx%d+%d-%d", &w, &h, &x, &y) == 4) {
h = nabs(h);
y = H - y - h;
} else if (sscanf(str, "%dx%d-%d-%d", &w, &h, &x, &y) == 4) {
w = nabs(w);
h = nabs(h);
x = W - x - w;
y = H - y - h;
} else {
return 0;
}
*wp = w;
*hp = h;
*xp = x;
*yp = y;
return 1;
}
void set_env(char *name, char *value) {
char *str;
if (!value) {
value = "";
}
str = (char *) malloc(strlen(name)+strlen(value)+2);
sprintf(str, "%s=%s", name, value);
putenv(str);
}
char *bitprint(unsigned int st, int nbits) {
static char str[33];
int i, mask;
if (nbits > 32) {
nbits = 32;
}
for (i=0; i<nbits; i++) {
str[i] = '0';
}
str[nbits] = '\0';
mask = 1;
for (i=nbits-1; i>=0; i--) {
if (st & mask) {
str[i] = '1';
}
mask = mask << 1;
}
return str; /* take care to use or copy immediately */
}
char *get_user_name(void) {
char *user = NULL;
user = getenv("USER");
if (user == NULL) {
user = getenv("LOGNAME");
}
#if LIBVNCSERVER_HAVE_PWD_H
if (user == NULL) {
struct passwd *pw = getpwuid(getuid());
if (pw) {
user = pw->pw_name;
}
}
#endif
if (user) {
return(strdup(user));
} else {
return(strdup("unknown-user"));
}
}
char *get_home_dir(void) {
char *home = NULL;
home = getenv("HOME");
#if LIBVNCSERVER_HAVE_PWD_H
if (home == NULL) {
struct passwd *pw = getpwuid(getuid());
if (pw) {
home = pw->pw_dir;
}
}
#endif
if (home) {
return(strdup(home));
} else {
return(strdup("/"));
}
}
char *get_shell(void) {
char *shell = NULL;
shell = getenv("SHELL");
#if LIBVNCSERVER_HAVE_PWD_H
if (shell == NULL) {
struct passwd *pw = getpwuid(getuid());
if (pw) {
shell = pw->pw_shell;
}
}
#endif
if (shell) {
return(strdup(shell));
} else {
return(strdup("/bin/sh"));
}
}
/*
* utility to get the current host name
*/
char *this_host(void) {
char host[MAXN];
#if LIBVNCSERVER_HAVE_GETHOSTNAME
if (gethostname(host, MAXN) == 0) {
return strdup(host);
}
#endif
return NULL;
}
int match_str_list(char *str, char **list) {
int i = 0, matched = 0;
if (! list) {
return matched;
}
while (list[i] != NULL) {
if (!strcmp(list[i], "*")) {
matched = 1;
break;
} else if (strstr(str, list[i])) {
matched = 1;
break;
}
i++;
}
return matched;
}
char **create_str_list(char *cslist) {
int i, n;
char *p, *str = strdup(cslist);
char **list = NULL;
n = 1;
p = str;
while (*p != '\0') {
if (*p == ',') {
n++;
}
p++;
}
list = (char **) malloc((n+1)*sizeof(char *));
for(i=0; i < n+1; i++) {
list[i] = NULL;
}
p = strtok(str, ",");
i = 0;
while (p && i < n) {
list[i++] = strdup(p);
p = strtok(NULL, ",");
}
free(str);
return list;
}
/*
* simple function for measuring sub-second time differences, using
* a double to hold the value.
*/
double dtime(double *t_old) {
/*
* usage: call with 0.0 to initialize, subsequent calls give
* the time difference since last call.
*/
double t_now, dt;
struct timeval now;
gettimeofday(&now, NULL);
t_now = now.tv_sec + ( (double) now.tv_usec/1000000. );
if (*t_old == 0.0) {
*t_old = t_now;
return t_now;
}
dt = t_now - *t_old;
*t_old = t_now;
return(dt);
}
/* common dtime() activities: */
double dtime0(double *t_old) {
*t_old = 0.0;
return dtime(t_old);
}
double dnow(void) {
double t;
return dtime0(&t);
}
double dnowx(void) {
return dnow() - x11vnc_start;
}
double rnow(void) {
double t = dnowx();
t = t - ((int) t);
if (t > 1.0) {
t = 1.0;
} else if (t < 0.0) {
t = 0.0;
}
return t;
}
double rfac(void) {
double f = (double) rand();
f = f / ((double) RAND_MAX);
return f;
}
/*
* utility wrapper to call rfbProcessEvents
* checks that we are not in threaded mode.
*/
#define USEC_MAX 999999 /* libvncsever assumes < 1 second */
void rfbPE(long usec) {
if (! screen) {
return;
}
if (usec > USEC_MAX) {
usec = USEC_MAX;
}
if (! use_threads) {
rfbProcessEvents(screen, usec);
}
}
void rfbCFD(long usec) {
if (! screen) {
return;
}
if (usec > USEC_MAX) {
usec = USEC_MAX;
}
if (! use_threads) {
rfbCheckFds(screen, usec);
}
}

@ -0,0 +1,84 @@
#ifndef _X11VNC_UTIL_H
#define _X11VNC_UTIL_H
/* -- util.h -- */
extern int nfix(int i, int n);
extern int nabs(int n);
extern double dabs(double x);
extern void lowercase(char *str);
extern void uppercase(char *str);
extern char *lblanks(char *str);
extern void strzero(char *str);
extern int scan_hexdec(char *str, unsigned long *num);
extern int parse_geom(char *str, int *wp, int *hp, int *xp, int *yp, int W, int H);
extern void set_env(char *name, char *value);
extern char *bitprint(unsigned int st, int nbits);
extern char *get_user_name(void);
extern char *get_home_dir(void);
extern char *get_shell(void);
extern char *this_host(void);
extern int match_str_list(char *str, char **list);
extern char **create_str_list(char *cslist);
extern double dtime(double *);
extern double dtime0(double *);
extern double dnow(void);
extern double dnowx(void);
extern double rnow(void);
extern double rfac(void);
extern void rfbPE(long usec);
extern void rfbCFD(long usec);
#define NONUL(x) ((x) ? (x) : "")
/* XXX usleep(3) is not thread safe on some older systems... */
extern struct timeval _mysleep;
#define usleep2(x) \
_mysleep.tv_sec = (x) / 1000000; \
_mysleep.tv_usec = (x) % 1000000; \
select(0, NULL, NULL, NULL, &_mysleep);
#if !defined(X11VNC_USLEEP)
#undef usleep
#define usleep usleep2
#endif
/*
* following is based on IsModifierKey in Xutil.h
*/
#define ismodkey(keysym) \
((((KeySym)(keysym) >= XK_Shift_L) && ((KeySym)(keysym) <= XK_Hyper_R) && \
((KeySym)(keysym) != XK_Caps_Lock) && ((KeySym)(keysym) != XK_Shift_Lock)))
/*
* Not sure why... but when threaded we have to mutex our X11 calls to
* avoid XIO crashes.
*/
#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
extern MUTEX(x11Mutex);
#endif
#define X_INIT INIT_MUTEX(x11Mutex)
#if 1
#define X_LOCK LOCK(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;
#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)
#endif /* _X11VNC_UTIL_H */

@ -0,0 +1,444 @@
/* -- win_utils.c -- */
#include "x11vnc.h"
#include "xinerama.h"
#include "winattr_t.h"
#include "cleanup.h"
winattr_t *stack_list = NULL;
int stack_list_len = 0;
int stack_list_num = 0;
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);
void snapshot_stack_list(int free_only, double allowed_age);
void update_stack_list(void);
Window query_pointer(Window start);
int pick_windowid(unsigned long *num);
Window descend_pointer(int depth, Window start, char *name_info, int len);
Window parent_window(Window win, char **name) {
Window r, parent;
Window *list;
unsigned int nchild;
if (name != NULL) {
*name = NULL;
}
if (! XQueryTree(dpy, win, &r, &parent, &list, &nchild)) {
return None;
}
if (list) {
XFree(list);
}
if (parent && name) {
XFetchName(dpy, parent, name);
}
return parent;
}
/* trapping utility to check for a valid window: */
int valid_window(Window win, XWindowAttributes *attr_ret, int bequiet) {
XErrorHandler old_handler;
XWindowAttributes attr, *pattr;
int ok = 0;
if (attr_ret == NULL) {
pattr = &attr;
} else {
pattr = attr_ret;
}
if (win == None) {
return 0;
}
trapped_xerror = 0;
old_handler = XSetErrorHandler(trap_xerror);
if (XGetWindowAttributes(dpy, win, pattr)) {
ok = 1;
}
if (trapped_xerror && trapped_xerror_event) {
if (! quiet && ! bequiet) {
rfbLog("valid_window: trapped XError: %s (0x%lx)\n",
xerror_string(trapped_xerror_event), win);
}
ok = 0;
}
XSetErrorHandler(old_handler);
trapped_xerror = 0;
return ok;
}
Bool xtranslate(Window src, Window dst, int src_x, int src_y, int *dst_x,
int *dst_y, Window *child, int bequiet) {
XErrorHandler old_handler;
Bool ok = False;
trapped_xerror = 0;
old_handler = XSetErrorHandler(trap_xerror);
if (XTranslateCoordinates(dpy, src, dst, src_x, src_y, dst_x,
dst_y, child)) {
ok = True;
}
if (trapped_xerror && trapped_xerror_event) {
if (! quiet && ! bequiet) {
rfbLog("xtranslate: trapped XError: %s (0x%lx)\n",
xerror_string(trapped_xerror_event), src);
}
ok = False;
}
XSetErrorHandler(old_handler);
trapped_xerror = 0;
return ok;
}
int get_window_size(Window win, int *x, int *y) {
XWindowAttributes attr;
/* valid_window? */
if (valid_window(win, &attr, 1)) {
*x = attr.width;
*y = attr.height;
return 1;
} else {
return 0;
}
}
/*
* For use in the -wireframe stuff, save the stacking order of the direct
* children of the root window. Ideally done before we send ButtonPress
* to the X server.
*/
void snapshot_stack_list(int free_only, double allowed_age) {
static double last_snap = 0.0, last_free = 0.0;
double now;
int num, rc, i, j;
unsigned int ui;
Window r, w;
Window *list;
if (! stack_list) {
stack_list = (winattr_t *) malloc(256*sizeof(winattr_t));
stack_list_num = 0;
stack_list_len = 256;
}
dtime0(&now);
if (free_only) {
/* we really don't free it, just reset to zero windows */
stack_list_num = 0;
last_free = now;
return;
}
if (stack_list_num && now < last_snap + allowed_age) {
return;
}
stack_list_num = 0;
last_free = now;
X_LOCK;
rc = XQueryTree(dpy, rootwin, &r, &w, &list, &ui);
num = (int) ui;
if (! rc) {
stack_list_num = 0;
last_free = now;
last_snap = 0.0;
X_UNLOCK;
return;
}
last_snap = now;
if (num > stack_list_len + blackouts) {
int n = 2*num;
free(stack_list);
stack_list = (winattr_t *) malloc(n*sizeof(winattr_t));
stack_list_len = n;
}
j = 0;
for (i=0; i<num; i++) {
stack_list[j].win = list[i];
stack_list[j].fetched = 0;
stack_list[j].valid = 0;
stack_list[j].time = now;
j++;
}
for (i=0; i<blackouts; i++) {
stack_list[j].win = 0x1;
stack_list[j].fetched = 1;
stack_list[j].valid = 1;
stack_list[j].x = blackr[i].x1;
stack_list[j].y = blackr[i].y1;
stack_list[j].width = blackr[i].x2 - blackr[i].x1;
stack_list[j].height = blackr[i].y2 - blackr[i].y1;
stack_list[j].time = now;
stack_list[j].map_state = IsViewable;
stack_list[j].rx = -1;
stack_list[j].ry = -1;
j++;
if (0) fprintf(stderr, "blackr: %d %dx%d+%d+%d\n", i,
stack_list[j-1].width, stack_list[j-1].height,
stack_list[j-1].x, stack_list[j-1].y);
}
stack_list_num = num + blackouts;
if (debug_wireframe > 1) {
fprintf(stderr, "snapshot_stack_list: num=%d len=%d\n",
stack_list_num, stack_list_len);
}
XFree(list);
X_UNLOCK;
}
void update_stack_list(void) {
int k;
double now;
XWindowAttributes attr;
if (! stack_list) {
return;
}
if (! stack_list_num) {
return;
}
dtime0(&now);
for (k=0; k < stack_list_num; k++) {
Window win = stack_list[k].win;
if (win != None && win < 10) {
; /* special, blackout */
} else if (!valid_window(win, &attr, 1)) {
stack_list[k].valid = 0;
} else {
stack_list[k].valid = 1;
stack_list[k].x = attr.x;
stack_list[k].y = attr.y;
stack_list[k].width = attr.width;
stack_list[k].height = attr.height;
stack_list[k].depth = attr.depth;
stack_list[k].class = attr.class;
stack_list[k].backing_store = attr.backing_store;
stack_list[k].map_state = attr.map_state;
/* root_x, root_y not used for stack_list usage: */
stack_list[k].rx = -1;
stack_list[k].ry = -1;
}
stack_list[k].fetched = 1;
stack_list[k].time = now;
}
if (0) fprintf(stderr, "update_stack_list[%d]: %.4f %.4f\n", stack_list_num, now - x11vnc_start, dtime(&now));
}
Window query_pointer(Window start) {
Window r, c;
int rx, ry, wx, wy;
unsigned int mask;
if (start == None) {
start = rootwin;
}
if (XQueryPointer(dpy, start, &r, &c, &rx, &ry, &wx, &wy, &mask)) {
return c;
} else {
return None;
}
}
int pick_windowid(unsigned long *num) {
char line[512];
int ok = 0, n = 0, msec = 10, secmax = 15;
FILE *p;
if (use_dpy) {
set_env("DISPLAY", use_dpy);
}
if (no_external_cmds) {
rfbLogEnable(1);
rfbLog("cannot run external commands in -nocmds mode:\n");
rfbLog(" \"%s\"\n", "xwininfo");
rfbLog(" exiting.\n");
clean_up_exit(1);
}
p = popen("xwininfo", "r");
if (! p) {
return 0;
}
fprintf(stderr, "\n");
fprintf(stderr, " Please select the window for x11vnc to poll\n");
fprintf(stderr, " by clicking the mouse in that window.\n");
fprintf(stderr, "\n");
while (msec * n++ < 1000 * secmax) {
unsigned long tmp;
char *q;
fd_set set;
struct timeval tv;
if (screen && screen->clientHead) {
/* they may be doing the pointer-pick thru vnc: */
int nfds;
tv.tv_sec = 0;
tv.tv_usec = msec * 1000;
FD_ZERO(&set);
FD_SET(fileno(p), &set);
nfds = select(fileno(p)+1, &set, NULL, NULL, &tv);
if (nfds == 0 || nfds < 0) {
/*
* select timedout or error.
* note this rfbPE takes about 30ms too:
*/
rfbPE(-1);
XFlush(dpy);
continue;
}
}
if (fgets(line, 512, p) == NULL) {
break;
}
q = strstr(line, " id: 0x");
if (q) {
q += 5;
if (sscanf(q, "0x%lx ", &tmp) == 1) {
ok = 1;
*num = tmp;
fprintf(stderr, " Picked: 0x%lx\n\n", tmp);
break;
}
}
}
pclose(p);
return ok;
}
Window descend_pointer(int depth, Window start, char *name_info, int len) {
Window r, c, clast;
int i, rx, ry, wx, wy;
int written = 0, filled = 0;
char *store = NULL;
unsigned int m;
static XClassHint *classhint = NULL;
static char *nm_cache = NULL;
static int nm_cache_len = 0;
static Window prev_start = None;
if (! classhint) {
classhint = XAllocClassHint();
}
if (! nm_cache) {
nm_cache = (char *) malloc(1024);
nm_cache_len = 1024;
nm_cache[0] = '\0';
}
if (name_info && nm_cache_len < len) {
if (nm_cache) {
free(nm_cache);
}
nm_cache_len = 2*len;
nm_cache = (char *) malloc(nm_cache_len);
}
if (name_info) {
if (start != None && start == prev_start) {
store = NULL;
strncpy(name_info, nm_cache, len);
} else {
store = name_info;
name_info[0] = '\0';
}
}
if (start != None) {
c = start;
if (name_info) {
prev_start = start;
}
} else {
c = rootwin;
}
for (i=0; i<depth; i++) {
clast = c;
if (store && ! filled) {
char *name;
if (XFetchName(dpy, clast, &name) && name != NULL) {
int l = strlen(name);
if (written + l+2 < len) {
strcat(store, "^^");
written += 2;
strcat(store, name);
written += l;
} else {
filled = 1;
}
XFree(name);
}
}
if (store && classhint && ! filled) {
classhint->res_name = NULL;
classhint->res_class = NULL;
if (XGetClassHint(dpy, clast, classhint)) {
int l = 0;
if (classhint->res_class) {
l += strlen(classhint->res_class);
}
if (classhint->res_name) {
l += strlen(classhint->res_name);
}
if (written + l+4 < len) {
strcat(store, "##");
if (classhint->res_class) {
strcat(store,
classhint->res_class);
}
strcat(store, "++");
if (classhint->res_name) {
strcat(store,
classhint->res_name);
}
written += l+4;
} else {
filled = 1;
}
if (classhint->res_class) {
XFree(classhint->res_class);
}
if (classhint->res_name) {
XFree(classhint->res_name);
}
}
}
if (! XQueryPointer(dpy, c, &r, &c, &rx, &ry, &wx, &wy, &m)) {
break;
}
if (! c) {
break;
}
}
if (start != None && name_info) {
strncpy(nm_cache, name_info, nm_cache_len);
}
return clast;
}

@ -0,0 +1,23 @@
#ifndef _X11VNC_WIN_UTILS_H
#define _X11VNC_WIN_UTILS_H
/* -- win_utils.h -- */
#include "xinerama.h"
#include "winattr_t.h"
extern winattr_t *stack_list;
extern int stack_list_len;
extern int stack_list_num;
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 void snapshot_stack_list(int free_only, double allowed_age);
extern void update_stack_list(void);
extern Window query_pointer(Window start);
extern int pick_windowid(unsigned long *num);
extern Window descend_pointer(int depth, Window start, char *name_info, int len);
#endif /* _X11VNC_WIN_UTILS_H */

@ -0,0 +1,20 @@
#ifndef _X11VNC_WINATTR_T_H
#define _X11VNC_WINATTR_T_H
/* -- winattr_t.h -- */
typedef struct winattr {
Window win;
int fetched;
int valid;
int x, y;
int width, height;
int depth;
int class;
int backing_store;
int map_state;
int rx, ry;
double time;
} winattr_t;
#endif /* _X11VNC_WINATTR_T_H */

@ -1,8 +1,8 @@
.\" This file was automatically generated from x11vnc -help output.
.TH X11VNC "1" "December 2005" "x11vnc " "User Commands"
.TH X11VNC "1" "January 2006" "x11vnc " "User Commands"
.SH NAME
x11vnc - allow VNC connections to real X11 displays
version: 0.7.3, lastmod: 2005-12-24
version: 0.7.3, lastmod: 2006-01-08
.SH SYNOPSIS
.B x11vnc
[OPTION]...
@ -372,11 +372,17 @@ of the file \fIfilename\fR (instead of via \fB-passwd\fR on
the command line where others might see it via
.IR ps (1)
).
See below for how to supply multiple passwords.
.IP
If the filename is prefixed with "rm:" it will be
removed after being read. In general, the password file
should not be readable by untrusted users (BTW: neither
should the VNC \fB-rfbauth\fR file: it is NOT encrypted).
removed after being read. Perhaps this is useful in
limiting the readability of the file. In general,
the password file should not be readable by untrusted
users (BTW: neither should the VNC \fB-rfbauth\fR file:
it is NOT encrypted).
.IP
If the filename is prefixed with "read:" it will
periodically be checked for changes and reread.
.IP
Note that only the first 8 characters of a password
are used.
@ -396,9 +402,10 @@ line by itself, the remaining passwords are used for
viewonly access. For compatibility, as a special case
if the file contains only two password lines the 2nd
one is automatically taken as the viewonly password.
Otherwise the "__BEGIN_VIEWONLY__" token must be used
to have viewonly passwords. (tip: make it the 3rd and
last line to have 2 full-access passwords)
Otherwise the "__BEGIN_VIEWONLY__" token must be
used to have viewonly passwords. (tip: make the 3rd
and last line be "__BEGIN_VIEWONLY__" to have 2
full-access passwords)
.PP
\fB-nopw\fR
.IP
@ -444,7 +451,13 @@ of the connection), are set to allow identification
of the tcp virtual circuit. The x11vnc process
id will be in RFB_X11VNC_PID, a client id number in
RFB_CLIENT_ID, and the number of other connected clients
in RFB_CLIENT_COUNT. RFB_MODE will be "accept"
in RFB_CLIENT_COUNT. RFB_MODE will be "accept".
RFB_STATE will be PROTOCOL_VERSION, SECURITY_TYPE,
AUTHENTICATION, INITIALISATION, NORMAL, or UNKNOWN
indicating up to which state the client has acheived.
RFB_LOGIN_VIEWONLY will be 0, 1, or -1 (unknown).
RFB_USERNAME, RFB_LOGIN_TIME, and RFB_CURRENT_TIME may
also be set.
.IP
If \fIstring\fR is "popup" then a builtin popup window
is used. The popup will time out after 120 seconds,
@ -485,6 +498,15 @@ clicking. All 3 of the popup keywords can be followed
by +N+M to supply a position for the popup window.
The default is to center the popup window.
.PP
\fB-afteraccept\fR \fIstring\fR
.IP
As \fB-accept,\fR except to run a user supplied command after
a client has been accepted and authenticated. RFB_MODE
will be set to "afteraccept" and the other RFB_*
variables are as in \fB-accept.\fR Unlike \fB-accept,\fR the
command return code is not interpreted by x11vnc.
Example: \fB-afteraccept\fR 'killall xlock &'
.PP
\fB-gone\fR \fIstring\fR
.IP
As \fB-accept,\fR except to run a user supplied command when
@ -2026,6 +2048,8 @@ or client_input:0x2:K
.IP
accept:cmd set \fB-accept\fR "cmd" (empty to disable).
.IP
afteraccept:cmd set \fB-afteraccept\fR (empty to disable).
.IP
gone:cmd set \fB-gone\fR "cmd" (empty to disable).
.IP
noshm enable \fB-noshm\fR mode.
@ -2395,20 +2419,21 @@ truecolor notruecolor overlay nooverlay overlay_cursor
overlay_yescursor nooverlay_nocursor nooverlay_cursor
nooverlay_yescursor overlay_nocursor visual scale
scale_cursor viewonly noviewonly shared noshared
forever noforever once timeout deny lock nodeny unlock
connect allowonce allow localhost nolocalhost listen
lookup nolookup accept gone shm noshm flipbyteorder
noflipbyteorder onetile noonetile solid_color solid
nosolid blackout xinerama noxinerama xtrap noxtrap
xrandr noxrandr xrandr_mode padgeom quiet q noquiet
modtweak nomodtweak xkb noxkb skip_keycodes sloppy_keys
nosloppy_keys skip_dups noskip_dups add_keysyms
noadd_keysyms clear_mods noclear_mods clear_keys
noclear_keys remap repeat norepeat fb nofb bell
nobell sel nosel primary noprimary seldir cursorshape
nocursorshape cursorpos nocursorpos cursor show_cursor
noshow_cursor nocursor arrow xfixes noxfixes xdamage
noxdamage xd_area xd_mem alphacut alphafrac alpharemove
forever noforever once timeout filexfer deny lock
nodeny unlock connect allowonce allow localhost
nolocalhost listen lookup nolookup accept afteraccept
gone shm noshm flipbyteorder noflipbyteorder onetile
noonetile solid_color solid nosolid blackout xinerama
noxinerama xtrap noxtrap xrandr noxrandr xrandr_mode
padgeom quiet q noquiet modtweak nomodtweak xkb
noxkb skip_keycodes sloppy_keys nosloppy_keys
skip_dups noskip_dups add_keysyms noadd_keysyms
clear_mods noclear_mods clear_keys noclear_keys
remap repeat norepeat fb nofb bell nobell sel nosel
primary noprimary seldir cursorshape nocursorshape
cursorpos nocursorpos cursor show_cursor noshow_cursor
nocursor arrow xfixes noxfixes xdamage noxdamage
xd_area xd_mem alphacut alphafrac alpharemove
noalpharemove alphablend noalphablend xwarppointer
xwarp noxwarppointer noxwarp buttonmap dragging
nodragging wireframe_mode wireframe wf nowireframe

File diff suppressed because it is too large Load Diff

@ -0,0 +1,434 @@
#ifndef _X11VNC_X11VNC_H
#define _X11VNC_X11VNC_H
/* -- x11vnc.h -- */
/*
* These ' -- filename.[ch] -- ' comments represent a partial cleanup:
* they are an odd way to indicate how this huge file would be split up
* someday into multiple files.
*
* The primary reason we have not broken up this file is for user
* convenience: those wanting to use the latest version download a single
* file, x11vnc.c, and off they go...
*/
/****************************************************************************/
/* Standard includes and libvncserver */
#include <unistd.h>
#include <signal.h>
#include <sys/utsname.h>
#include <time.h>
#include <errno.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include <X11/Xatom.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <ctype.h>
#include <rfb/rfb.h>
#include <rfb/rfbregion.h>
/****************************************************************************/
/* Build-time customization via CPPFLAGS. */
/*
* Summary of options to include in CPPFLAGS for custom builds:
*
* -DVNCSHARED to have the vnc display shared by default.
* -DFOREVER to have -forever on by default.
* -DNOREPEAT=0 to have -repeat on by default.
* -DADDKEYSYMS=0 to have -noadd_keysyms the default.
*
* -DREMOTE_DEFAULT=0 to disable remote-control on by default (-yesremote).
* -DREMOTE_CONTROL=0 to disable remote-control mechanism completely.
* -DEXTERNAL_COMMANDS=0 to disable the running of all external commands.
* -DFILEXFER=0 disable filexfer.
*
* -DHARDWIRE_PASSWD=... hardwired passwords, quoting necessary.
* -DHARDWIRE_VIEWPASSWD=...
* -DNOPW=1 make -nopw the default (skip warning)
* -DPASSWD_REQUIRED=1 exit unless a password is supplied.
* -DPASSWD_UNLESS_NOPW=1 exit unless a password is supplied and no -nopw.
*
* -DWIREFRAME=0 to have -nowireframe as the default.
* -DWIREFRAME_COPYRECT=0 to have -nowirecopyrect as the default.
* -DWIREFRAME_PARMS=... set default -wirecopyrect parameters.
* -DSCROLL_COPYRECT=0 to have -noscrollcopyrect as the default.
* -DSCROLL_COPYRECT_PARMS=... set default -scrollcopyrect parameters.
* -DXDAMAGE=0 to have -noxdamage as the default.
* -DSKIPDUPS=0 to have -noskip_dups as the default or vice versa.
*
* -DPOINTER_MODE_DEFAULT={0,1,2,3,4} set default -pointer_mode.
* -DBOLDLY_CLOSE_DISPLAY=0 to not close X DISPLAY under -rawfb.
* -DSMALL_FOOTPRINT=1 for smaller binary size (no help, no gui, etc)
* use 2 or 3 for even smaller footprint.
* -DNOGUI do not include the gui tkx11vnc.
*
* Set these in CPPFLAGS before running configure. E.g.:
*
* % env CPPFLAGS="-DFOREVER -DREMOTE_CONTROL=0" ./configure
* % make
*/
/*
* This can be used to disable the remote control mechanism.
*/
#ifndef REMOTE_CONTROL
#define REMOTE_CONTROL 1
#endif
#ifndef NOPW
#define NOPW 0
#endif
#ifndef PASSWD_REQUIRED
#define PASSWD_REQUIRED 0
#endif
#ifndef PASSWD_UNLESS_NOPW
#define PASSWD_UNLESS_NOPW 0
#endif
/*
* Beginning of support for small binary footprint build for embedded
* systems, PDA's etc. It currently just cuts out the low-hanging
* fruit (large text passages). Set to 2, 3 to cut out some of the
* more esoteric extensions. More tedious is to modify LDFLAGS in the
* Makefile to not link against the extension libraries... but that
* should be done too (manually for now).
*
* If there is interest more of the bloat can be removed... Currently
* these shrink the binary from 500K to about 270K.
*/
#ifndef SMALL_FOOTPRINT
#define SMALL_FOOTPRINT 0
#endif
#if SMALL_FOOTPRINT
#define NOGUI
#endif
#if (SMALL_FOOTPRINT > 1)
#define LIBVNCSERVER_HAVE_XKEYBOARD 0
#define LIBVNCSERVER_HAVE_LIBXINERAMA 0
#define LIBVNCSERVER_HAVE_LIBXRANDR 0
#define LIBVNCSERVER_HAVE_LIBXFIXES 0
#define LIBVNCSERVER_HAVE_LIBXDAMAGE 0
#endif
#if (SMALL_FOOTPRINT > 2)
#define LIBVNCSERVER_HAVE_UTMPX_H 0
#define LIBVNCSERVER_HAVE_PWD_H 0
#define REMOTE_CONTROL 0
#endif
/*
* Not recommended unless you know what you are getting into, but if you
* define the HARDWIRE_PASSWD or HARDWIRE_VIEWPASSWD variables here or in
* CPPFLAGS you can set a default -passwd and -viewpasswd string values,
* perhaps this would be better than nothing on an embedded system, etc.
* These default values will be overridden by the command line.
* We don't even give an example ;-)
*/
/****************************************************************************/
/* Extensions and related includes: */
#if LIBVNCSERVER_HAVE_XSHM
# if defined(__hpux) && defined(__ia64) /* something weird on hp/itanic */
# undef _INCLUDE_HPUX_SOURCE
# endif
#include <sys/ipc.h>
#include <sys/shm.h>
#include <X11/extensions/XShm.h>
#endif
#if LIBVNCSERVER_HAVE_XTEST
#include <X11/extensions/XTest.h>
#endif
extern int xtest_base_event_type;
#if LIBVNCSERVER_HAVE_LIBXTRAP
#define NEED_EVENTS
#define NEED_REPLIES
#include <X11/extensions/xtraplib.h>
#include <X11/extensions/xtraplibp.h>
extern XETC *trap_ctx;
#endif
extern int xtrap_base_event_type;
#if LIBVNCSERVER_HAVE_RECORD
#include <X11/Xproto.h>
#include <X11/extensions/record.h>
#endif
#if LIBVNCSERVER_HAVE_XKEYBOARD
#include <X11/XKBlib.h>
#endif
#if LIBVNCSERVER_HAVE_LIBXINERAMA
#include <X11/extensions/Xinerama.h>
#endif
#if LIBVNCSERVER_HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#include <netdb.h>
extern int h_errno;
#if LIBVNCSERVER_HAVE_NETINET_IN_H
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#endif
/* XXX autoconf */
#if LIBVNCSERVER_HAVE_PWD_H
#include <pwd.h>
#endif
#if LIBVNCSERVER_HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
#if LIBVNCSERVER_HAVE_UTMPX_H
#include <utmpx.h>
#endif
#if LIBVNCSERVER_HAVE_MMAP
#include <sys/mman.h>
#endif
/*
* overlay/multi-depth screen reading support
* undef SOLARIS_OVERLAY or IRIX_OVERLAY if there are problems building.
*/
/* solaris/sun */
#if defined (__SVR4) && defined (__sun)
# define SOLARIS
# ifdef LIBVNCSERVER_HAVE_SOLARIS_XREADSCREEN
# define SOLARIS_OVERLAY
# define OVERLAY_OS
# endif
#endif
#ifdef SOLARIS_OVERLAY
#include <X11/extensions/transovl.h>
#endif
/* irix/sgi */
#if defined(__sgi)
# define IRIX
# ifdef LIBVNCSERVER_HAVE_IRIX_XREADDISPLAY
# define IRIX_OVERLAY
# define OVERLAY_OS
# endif
#endif
#ifdef IRIX_OVERLAY
#include <X11/extensions/readdisplay.h>
#endif
extern int overlay_present;
#if LIBVNCSERVER_HAVE_LIBXRANDR
#include <X11/extensions/Xrandr.h>
#endif
extern int xrandr_base_event_type;
#if LIBVNCSERVER_HAVE_LIBXFIXES
#include <X11/extensions/Xfixes.h>
#endif
extern int xfixes_base_event_type;
#if LIBVNCSERVER_HAVE_LIBXDAMAGE
#include <X11/extensions/Xdamage.h>
#endif
extern int xdamage_base_event_type;
extern char lastmod[];
/* X display info */
extern Display *dpy; /* the single display screen we connect to */
extern int scr;
extern Window window, rootwin; /* polled window, root window (usu. same) */
extern Visual *default_visual; /* the default visual (unless -visual) */
extern int bpp, depth;
extern int indexed_color;
extern int dpy_x, dpy_y; /* size of display */
extern int off_x, off_y; /* offsets for -sid */
extern int wdpy_x, wdpy_y; /* for actual sizes in case of -clip */
extern int cdpy_x, cdpy_y, coff_x, coff_y; /* the -clip params */
extern int button_mask; /* button state and info */
extern int button_mask_prev;
extern int num_buttons;
/* image structures */
extern XImage *scanline;
extern XImage *fullscreen;
extern XImage **tile_row; /* for all possible row runs */
extern XImage *fb0;
extern XImage *snaprect; /* for XShmGetImage (fs_factor) */
extern XImage *snap; /* the full snap fb */
extern XImage *raw_fb_image; /* the raw fb */
#if !LIBVNCSERVER_HAVE_XSHM
/*
* for simplicity, define this struct since we'll never use them
* under using_shm = 0.
*/
typedef struct {
int shmid; char *shmaddr; Bool readOnly;
} XShmSegmentInfo;
#endif
/* corresponding shm structures */
extern XShmSegmentInfo scanline_shm;
extern XShmSegmentInfo fullscreen_shm;
extern XShmSegmentInfo *tile_row_shm; /* for all possible row runs */
extern XShmSegmentInfo snaprect_shm;
/* rfb screen info */
extern rfbScreenInfoPtr screen;
extern char *rfb_desktop_name;
extern char *http_dir;
extern char vnc_desktop_name[];
extern char *main_fb; /* our copy of the X11 fb */
extern char *rfb_fb; /* same as main_fb unless transformation */
extern char *fake_fb; /* used under -padgeom */
extern char *snap_fb; /* used under -snapfb */
extern char *raw_fb;
extern char *raw_fb_addr;
extern int raw_fb_offset;
extern int raw_fb_shm;
extern int raw_fb_mmap;
extern int raw_fb_seek;
extern int raw_fb_fd;
extern int rfb_bytes_per_line;
extern int main_bytes_per_line;
extern unsigned long main_red_mask, main_green_mask, main_blue_mask;
extern unsigned short main_red_max, main_green_max, main_blue_max;
extern unsigned short main_red_shift, main_green_shift, main_blue_shift;
/* scaling parameters */
extern char *scale_str;
extern double scale_fac;
extern int scaling;
extern int scaling_blend; /* for no blending option (very course) */
extern int scaling_nomult4; /* do not require width = n * 4 */
extern int scaling_pad; /* pad out scaled sizes to fit denominator */
extern int scaling_interpolate; /* use interpolation scheme when shrinking */
extern int scaled_x, scaled_y; /* dimensions of scaled display */
extern int scale_numer, scale_denom; /* n/m */
/* scale cursor */
extern char *scale_cursor_str;
extern double scale_cursor_fac;
extern int scaling_cursor;
extern int scaling_cursor_blend;
extern int scaling_cursor_interpolate;
extern int scale_cursor_numer, scale_cursor_denom;
/* size of the basic tile unit that is polled for changes: */
extern int tile_x;
extern int tile_y;
extern int ntiles, ntiles_x, ntiles_y;
/* arrays that indicate changed or checked tiles. */
extern unsigned char *tile_has_diff, *tile_tried, *tile_copied;
extern unsigned char *tile_has_xdamage_diff, *tile_row_has_xdamage_diff;
/* times of recent events */
extern time_t last_event, last_input, last_client;
extern time_t last_keyboard_input, last_pointer_input;
extern time_t last_fb_bytes_sent;
extern double last_keyboard_time;
extern double last_pointer_time;
extern double last_pointer_click_time;
extern double last_pointer_motion_time;
extern double last_key_to_button_remap_time;
extern double last_copyrect;
extern double last_copyrect_fix;
extern double servertime_diff;
extern double x11vnc_start;
/* last client to move pointer */
extern rfbClientPtr last_pointer_client;
extern int client_count;
extern int clients_served;
/* more transient kludge variables: */
extern int cursor_x, cursor_y; /* x and y from the viewer(s) */
extern int button_change_x, button_change_y;
extern int got_user_input;
extern int got_pointer_input;
extern int got_pointer_calls;
extern int got_keyboard_input;
extern int got_keyboard_calls;
extern int urgent_update;
extern int last_keyboard_keycode;
extern rfbBool last_rfb_down;
extern rfbBool last_rfb_key_accepted;
extern rfbKeySym last_rfb_keysym;
extern double last_rfb_keytime;
extern int fb_copy_in_progress;
extern int drag_in_progress;
extern int shut_down;
extern int do_copy_screen;
extern time_t damage_time;
extern int damage_delay;
extern int program_pid;
extern char *program_name;
extern char *program_cmdline;
extern struct utsname UT;
typedef struct hint {
/* location x, y, height, and width of a change-rectangle */
/* (grows as adjacent horizontal tiles are glued together) */
int x, y, w, h;
} hint_t;
/* struct with client specific data: */
#define CILEN 10
typedef struct _ClientData {
int uid;
char *hostname;
char *username;
int client_port;
int server_port;
char *server_ip;
char input[CILEN];
int login_viewonly;
time_t login_time;
int had_cursor_shape_updates;
int had_cursor_pos_updates;
double timer;
double send_cmp_rate;
double send_raw_rate;
double latency;
int cmp_bytes_sent;
int raw_bytes_sent;
} ClientData;
#include "params.h"
#include "enums.h"
#include "options.h"
#include "util.h"
#endif /* _X11VNC_X11VNC_H */

@ -0,0 +1,150 @@
/* -- x11vnc_defs.c -- */
#include "x11vnc.h"
int overlay_present = 0;
int xrandr_base_event_type = 0;
int xfixes_base_event_type = 0;
int xtest_base_event_type = 0;
#if LIBVNCSERVER_HAVE_LIBXTRAP
XETC *trap_ctx = NULL;
#endif
int xtrap_base_event_type = 0;
int xdamage_base_event_type = 0;
/* date +'lastmod: %Y-%m-%d' */
char lastmod[] = "0.7.3 lastmod: 2006-01-08";
/* X display info */
Display *dpy = NULL; /* the single display screen we connect to */
int scr = 0;
Window window = None, rootwin = None; /* polled window, root window (usu. same) */
Visual *default_visual = NULL; /* the default visual (unless -visual) */
int bpp = 0, depth = 0;
int indexed_color = 0;
int dpy_x, dpy_y; /* size of display */
int off_x, off_y; /* offsets for -sid */
int wdpy_x, wdpy_y; /* for actual sizes in case of -clip */
int cdpy_x, cdpy_y, coff_x, coff_y; /* the -clip params */
int button_mask = 0; /* button state and info */
int button_mask_prev = 0;
int num_buttons = -1;
/* image structures */
XImage *scanline = NULL;
XImage *fullscreen = NULL;
XImage **tile_row = NULL; /* for all possible row runs */
XImage *fb0 = NULL;
XImage *snaprect = NULL; /* for XShmGetImage (fs_factor) */
XImage *snap = NULL; /* the full snap fb */
XImage *raw_fb_image = NULL; /* the raw fb */
/* corresponding shm structures */
XShmSegmentInfo scanline_shm;
XShmSegmentInfo fullscreen_shm;
XShmSegmentInfo *tile_row_shm; /* for all possible row runs */
XShmSegmentInfo snaprect_shm;
/* rfb screen info */
rfbScreenInfoPtr screen = NULL;
char *rfb_desktop_name = NULL;
char *http_dir = NULL;
char vnc_desktop_name[256];
char *main_fb = NULL; /* our copy of the X11 fb */
char *rfb_fb = NULL; /* same as main_fb unless transformation */
char *fake_fb = NULL; /* used under -padgeom */
char *snap_fb = NULL; /* used under -snapfb */
char *raw_fb = NULL;
char *raw_fb_addr = NULL;
int raw_fb_offset = 0;
int raw_fb_shm = 0;
int raw_fb_mmap = 0;
int raw_fb_seek = 0;
int raw_fb_fd = -1;
int rfb_bytes_per_line;
int main_bytes_per_line;
unsigned long main_red_mask, main_green_mask, main_blue_mask;
unsigned short main_red_max, main_green_max, main_blue_max;
unsigned short main_red_shift, main_green_shift, main_blue_shift;
/* scaling parameters */
char *scale_str = NULL;
double scale_fac = 1.0;
int scaling = 0;
int scaling_blend = 1; /* for no blending option (very course) */
int scaling_nomult4 = 0; /* do not require width = n * 4 */
int scaling_pad = 0; /* pad out scaled sizes to fit denominator */
int scaling_interpolate = 0; /* use interpolation scheme when shrinking */
int scaled_x = 0, scaled_y = 0; /* dimensions of scaled display */
int scale_numer = 0, scale_denom = 0; /* n/m */
/* scale cursor */
char *scale_cursor_str = NULL;
double scale_cursor_fac = 1.0;
int scaling_cursor = 0;
int scaling_cursor_blend = 1;
int scaling_cursor_interpolate = 0;
int scale_cursor_numer = 0, scale_cursor_denom = 0;
/* size of the basic tile unit that is polled for changes: */
int tile_x = 32;
int tile_y = 32;
int ntiles, ntiles_x, ntiles_y;
/* arrays that indicate changed or checked tiles. */
unsigned char *tile_has_diff = NULL, *tile_tried = NULL, *tile_copied = NULL;
unsigned char *tile_has_xdamage_diff = NULL, *tile_row_has_xdamage_diff = NULL;
/* times of recent events */
time_t last_event, last_input = 0, last_client = 0;
time_t last_keyboard_input = 0, last_pointer_input = 0;
time_t last_fb_bytes_sent = 0;
double last_keyboard_time = 0.0;
double last_pointer_time = 0.0;
double last_pointer_click_time = 0.0;
double last_pointer_motion_time = 0.0;
double last_key_to_button_remap_time = 0.0;
double last_copyrect = 0.0;
double last_copyrect_fix = 0.0;
double servertime_diff = 0.0;
double x11vnc_start = 0.0;
/* last client to move pointer */
rfbClientPtr last_pointer_client = NULL;
int client_count = 0;
int clients_served = 0;
/* more transient kludge variables: */
int cursor_x, cursor_y; /* x and y from the viewer(s) */
int button_change_x, button_change_y;
int got_user_input = 0;
int got_pointer_input = 0;
int got_pointer_calls = 0;
int got_keyboard_input = 0;
int got_keyboard_calls = 0;
int urgent_update = 0;
int last_keyboard_keycode = 0;
rfbBool last_rfb_down = FALSE;
rfbBool last_rfb_key_accepted = FALSE;
rfbKeySym last_rfb_keysym = 0;
double last_rfb_keytime = 0.0;
int fb_copy_in_progress = 0;
int drag_in_progress = 0;
int shut_down = 0;
int do_copy_screen = 0;
time_t damage_time = 0;
int damage_delay = 0;
int program_pid = 0;
char *program_name = NULL;
char *program_cmdline = NULL;
struct utsname UT;

@ -0,0 +1,532 @@
/* -- xdamage.c -- */
#include "x11vnc.h"
#include "xwrappers.h"
#include "userinput.h"
#if LIBVNCSERVER_HAVE_LIBXDAMAGE
Damage xdamage = 0;
#endif
#ifndef XDAMAGE
#define XDAMAGE 1
#endif
int use_xdamage = XDAMAGE; /* use the xdamage rects for scanline hints */
int xdamage_present = 0;
int xdamage_max_area = 20000; /* pixels */
double xdamage_memory = 1.0; /* in units of NSCAN */
int xdamage_tile_count = 0, xdamage_direct_count = 0;
double xdamage_scheduled_mark = 0.0;
sraRegionPtr xdamage_scheduled_mark_region = NULL;
sraRegionPtr *xdamage_regions = NULL;
int xdamage_ticker = 0;
int XD_skip = 0, XD_tot = 0, XD_des = 0; /* for stats */
void add_region_xdamage(sraRegionPtr new_region);
void clear_xdamage_mark_region(sraRegionPtr markregion, int flush);
int collect_xdamage(int scancnt, int call);
int xdamage_hint_skip(int y);
void initialize_xdamage(void);
void create_xdamage_if_needed(void);
void destroy_xdamage_if_needed(void);
void check_xdamage_state(void);
static void record_desired_xdamage_rect(int x, int y, int w, int h);
static void record_desired_xdamage_rect(int x, int y, int w, int h) {
/*
* Unfortunately we currently can't trust an xdamage event
* to correspond to real screen damage. E.g. focus-in for
* mozilla (depending on wm) will mark the whole toplevel
* area as damaged, when only the border has changed.
* Similar things for terminal windows.
*
* This routine uses some heuristics to detect small enough
* damage regions that we will not have a performance problem
* if we believe them even though they are wrong. We record
* the corresponding tiles the damage regions touch.
*/
int dt_x, dt_y, nt_x1, nt_y1, nt_x2, nt_y2, nt;
int ix, iy, cnt = 0;
int area = w*h, always_accept = 0;
/*
* XXX: not working yet, slow and overlaps with scan_display()
* probably slow because tall skinny rectangles very inefficient
* in general and in direct_fb_copy() (100X slower then horizontal).
*/
int use_direct_fb_copy = 0;
int wh_min, wh_max;
static int first = 1, udfb = 0;
if (first) {
if (getenv("XD_DFC")) {
udfb = 1;
}
first = 0;
}
if (udfb) {
use_direct_fb_copy = 1;
}
if (xdamage_max_area <= 0) {
always_accept = 1;
}
if (!always_accept && area > xdamage_max_area) {
return;
}
dt_x = w / tile_x;
dt_y = h / tile_y;
if (w < h) {
wh_min = w;
wh_max = h;
} else {
wh_min = h;
wh_max = w;
}
if (!always_accept && dt_y >= 3 && area > 4000) {
/*
* if it is real it should be caught by a normal scanline
* poll, but we might as well keep if small (tall line?).
*/
return;
}
if (use_direct_fb_copy) {
X_UNLOCK;
direct_fb_copy(x, y, x + w, y + h, 1);
xdamage_direct_count++;
X_LOCK;
} else if (0 && wh_min < tile_x/4 && wh_max > 30 * wh_min) {
/* try it for long, skinny rects, XXX still no good */
X_UNLOCK;
direct_fb_copy(x, y, x + w, y + h, 1);
xdamage_direct_count++;
X_LOCK;
} else {
nt_x1 = nfix( (x)/tile_x, ntiles_x);
nt_x2 = nfix((x+w)/tile_x, ntiles_x);
nt_y1 = nfix( (y)/tile_y, ntiles_y);
nt_y2 = nfix((y+h)/tile_y, ntiles_y);
/*
* loop over the rectangle of tiles (1 tile for a small
* input rect).
*/
for (ix = nt_x1; ix <= nt_x2; ix++) {
for (iy = nt_y1; iy <= nt_y2; iy++) {
nt = ix + iy * ntiles_x;
cnt++;
if (! tile_has_xdamage_diff[nt]) {
XD_des++;
tile_has_xdamage_diff[nt] = 1;
}
/* not used: */
tile_row_has_xdamage_diff[iy] = 1;
xdamage_tile_count++;
}
}
}
if (debug_xdamage > 1) {
fprintf(stderr, "xdamage: desired: %dx%d+%d+%d\tA: %6d tiles="
"%02d-%02d/%02d-%02d tilecnt: %d\n", w, h, x, y,
w * h, nt_x1, nt_x2, nt_y1, nt_y2, cnt);
}
}
void add_region_xdamage(sraRegionPtr new_region) {
sraRegionPtr reg;
int prev_tick, nreg;
if (! xdamage_regions) {
return;
}
nreg = (xdamage_memory * NSCAN) + 1;
prev_tick = xdamage_ticker - 1;
if (prev_tick < 0) {
prev_tick = nreg - 1;
}
reg = xdamage_regions[prev_tick];
if (reg != NULL) {
if (0) fprintf(stderr, "add_region_xdamage: prev_tick: %d reg %p\n", prev_tick, (void *)reg);
sraRgnOr(reg, new_region);
}
}
void clear_xdamage_mark_region(sraRegionPtr markregion, int flush) {
#if LIBVNCSERVER_HAVE_LIBXDAMAGE
XEvent ev;
sraRegionPtr tmpregion;
int count = 0;
if (! xdamage_present || ! use_xdamage) {
return;
}
if (! xdamage) {
return;
}
if (! xdamage_base_event_type) {
return;
}
X_LOCK;
if (flush) {
XFlush(dpy);
}
while (XCheckTypedEvent(dpy, xdamage_base_event_type+XDamageNotify, &ev)) {
count++;
}
/* clear the whole damage region */
XDamageSubtract(dpy, xdamage, None, None);
X_UNLOCK;
if (debug_tiles || debug_xdamage) {
fprintf(stderr, "clear_xdamage_mark_region: %d\n", count);
}
if (! markregion) {
/* NULL means mark the whole display */
tmpregion = sraRgnCreateRect(0, 0, dpy_x, dpy_y);
add_region_xdamage(tmpregion);
sraRgnDestroy(tmpregion);
} else {
add_region_xdamage(markregion);
}
#else
if (0) flush++; /* compiler warnings */
if (0) markregion = NULL;
#endif
}
int collect_xdamage(int scancnt, int call) {
#if LIBVNCSERVER_HAVE_LIBXDAMAGE
XDamageNotifyEvent *dev;
XEvent ev;
sraRegionPtr tmpregion;
sraRegionPtr reg;
static int rect_count = 0;
int nreg, ccount = 0, dcount = 0, ecount = 0;
static time_t last_rpt = 0;
time_t now;
int x, y, w, h, x2, y2;
int i, dup, next, dup_max = 0;
#define DUPSZ 32
int dup_x[DUPSZ], dup_y[DUPSZ], dup_w[DUPSZ], dup_h[DUPSZ];
double tm, dt;
if (scancnt) {} /* unused vars warning: */
if (! xdamage_present || ! use_xdamage) {
return 0;
}
if (! xdamage) {
return 0;
}
if (! xdamage_base_event_type) {
return 0;
}
dtime0(&tm);
nreg = (xdamage_memory * NSCAN) + 1;
if (call == 0) {
xdamage_ticker = (xdamage_ticker+1) % nreg;
xdamage_direct_count = 0;
reg = xdamage_regions[xdamage_ticker];
sraRgnMakeEmpty(reg);
} else {
reg = xdamage_regions[xdamage_ticker];
}
X_LOCK;
if (0) XFlush(dpy);
if (0) XEventsQueued(dpy, QueuedAfterFlush);
while (XCheckTypedEvent(dpy, xdamage_base_event_type+XDamageNotify, &ev)) {
/*
* TODO max cut off time in this loop?
* Could check QLength and if huge just mark the whole
* screen.
*/
ecount++;
if (ev.type != xdamage_base_event_type + XDamageNotify) {
break;
}
dev = (XDamageNotifyEvent *) &ev;
if (dev->damage != xdamage) {
continue; /* not ours! */
}
x = dev->area.x;
y = dev->area.y;
w = dev->area.width;
h = dev->area.height;
/*
* we try to manually remove some duplicates because
* certain activities can lead to many 10's of dups
* in a row. The region work can be costly and reg is
* later used in xdamage_hint_skip loops, so it is good
* to skip them if possible.
*/
dup = 0;
for (i=0; i < dup_max; i++) {
if (dup_x[i] == x && dup_y[i] == y && dup_w[i] == w &&
dup_h[i] == h) {
dup = 1;
break;
}
}
if (dup) {
dcount++;
continue;
}
if (dup_max < DUPSZ) {
next = dup_max;
dup_max++;
} else {
next = (next+1) % DUPSZ;
}
dup_x[next] = x;
dup_y[next] = y;
dup_w[next] = w;
dup_h[next] = h;
/* translate if needed */
if (clipshift) {
/* set coords relative to fb origin */
if (0 && rootshift) {
/*
* Note: not needed because damage is
* relative to subwin, not rootwin.
*/
x = x - off_x;
y = y - off_y;
}
if (clipshift) {
x = x - coff_x;
y = y - coff_y;
}
x2 = x + w; /* upper point */
x = nfix(x, dpy_x); /* place both in fb area */
x2 = nfix(x2, dpy_x+1);
w = x2 - x; /* recompute w */
y2 = y + h;
y = nfix(y, dpy_y);
y2 = nfix(y2, dpy_y+1);
h = y2 - y;
if (w <= 0 || h <= 0) {
continue;
}
}
if (debug_xdamage > 2) {
fprintf(stderr, "xdamage: -> event %dx%d+%d+%d area:"
" %d dups: %d %s\n", w, h, x, y, w*h, dcount,
(w*h > xdamage_max_area) ? "TOO_BIG" : "");
}
record_desired_xdamage_rect(x, y, w, h);
tmpregion = sraRgnCreateRect(x, y, x + w, y + h);
sraRgnOr(reg, tmpregion);
sraRgnDestroy(tmpregion);
rect_count++;
ccount++;
}
/* clear the whole damage region for next time. XXX check */
if (call == 1) {
XDamageSubtract(dpy, xdamage, None, None);
}
X_UNLOCK;
if (0 && xdamage_direct_count) {
fb_push();
}
dt = dtime(&tm);
if ((debug_tiles > 1 && ecount) || (debug_tiles && ecount > 200)
|| debug_xdamage > 1) {
fprintf(stderr, "collect_xdamage(%d): %.4f t: %.4f ev/dup/accept"
"/direct %d/%d/%d/%d\n", call, dt, tm - x11vnc_start, ecount,
dcount, ccount, xdamage_direct_count);
}
now = time(0);
if (! last_rpt) {
last_rpt = now;
}
if (now > last_rpt + 15) {
double rat = -1.0;
if (XD_tot) {
rat = ((double) XD_skip)/XD_tot;
}
if (debug_tiles || debug_xdamage) {
fprintf(stderr, "xdamage: == scanline skip/tot: "
"%04d/%04d =%.3f rects: %d desired: %d\n",
XD_skip, XD_tot, rat, rect_count, XD_des);
}
XD_skip = 0;
XD_tot = 0;
XD_des = 0;
rect_count = 0;
last_rpt = now;
}
#else
if (0) scancnt++; /* compiler warnings */
if (0) call++;
if (0) record_desired_xdamage_rect(0, 0, 0, 0);
#endif
return 0;
}
int xdamage_hint_skip(int y) {
static sraRegionPtr scanline = NULL;
sraRegionPtr reg, tmpl;
int ret, i, n, nreg;
if (! xdamage_present || ! use_xdamage) {
return 0; /* cannot skip */
}
if (! xdamage_regions) {
return 0; /* cannot skip */
}
if (! scanline) {
/* keep it around to avoid malloc etc, recreate */
scanline = sraRgnCreate();
}
tmpl = sraRgnCreateRect(0, y, dpy_x, y+1);
nreg = (xdamage_memory * NSCAN) + 1;
ret = 1;
for (i=0; i<nreg; i++) {
/* go back thru the history starting at most recent */
n = (xdamage_ticker + nreg - i) % nreg;
reg = xdamage_regions[n];
if (sraRgnEmpty(reg)) {
/* checking for emptiness is very fast */
continue;
}
sraRgnMakeEmpty(scanline);
sraRgnOr(scanline, tmpl);
if (sraRgnAnd(scanline, reg)) {
ret = 0;
break;
}
}
sraRgnDestroy(tmpl);
return ret;
}
void initialize_xdamage(void) {
sraRegionPtr *ptr;
int i, nreg;
if (! xdamage_present) {
use_xdamage = 0;
}
if (xdamage_regions) {
ptr = xdamage_regions;
while (*ptr != NULL) {
sraRgnDestroy(*ptr);
ptr++;
}
free(xdamage_regions);
xdamage_regions = NULL;
}
if (use_xdamage) {
nreg = (xdamage_memory * NSCAN) + 2;
xdamage_regions = (sraRegionPtr *)
malloc(nreg * sizeof(sraRegionPtr));
for (i = 0; i < nreg; i++) {
ptr = xdamage_regions+i;
if (i == nreg - 1) {
*ptr = NULL;
} else {
*ptr = sraRgnCreate();
sraRgnMakeEmpty(*ptr);
}
}
/* set so will be 0 in first collect_xdamage call */
xdamage_ticker = -1;
}
}
void create_xdamage_if_needed(void) {
if (raw_fb && ! dpy) return; /* raw_fb hack */
#if LIBVNCSERVER_HAVE_LIBXDAMAGE
if (! xdamage) {
X_LOCK;
xdamage = XDamageCreate(dpy, window, XDamageReportRawRectangles);
XDamageSubtract(dpy, xdamage, None, None);
X_UNLOCK;
rfbLog("created xdamage object: 0x%lx\n", xdamage);
}
#endif
}
void destroy_xdamage_if_needed(void) {
if (raw_fb && ! dpy) return; /* raw_fb hack */
#if LIBVNCSERVER_HAVE_LIBXDAMAGE
if (xdamage) {
XEvent ev;
X_LOCK;
XDamageDestroy(dpy, xdamage);
XFlush(dpy);
if (xdamage_base_event_type) {
while (XCheckTypedEvent(dpy,
xdamage_base_event_type+XDamageNotify, &ev)) {
;
}
}
X_UNLOCK;
rfbLog("destroyed xdamage object: 0x%lx\n", xdamage);
xdamage = 0;
}
#endif
}
void check_xdamage_state(void) {
if (! xdamage_present) {
return;
}
/*
* Create or destroy the Damage object as needed, we don't want
* one if no clients are connected.
*/
if (client_count && use_xdamage) {
create_xdamage_if_needed();
if (xdamage_scheduled_mark > 0.0 && dnow() >
xdamage_scheduled_mark) {
if (xdamage_scheduled_mark_region) {
mark_region_for_xdamage(
xdamage_scheduled_mark_region);
sraRgnDestroy(xdamage_scheduled_mark_region);
xdamage_scheduled_mark_region = NULL;
} else {
mark_for_xdamage(0, 0, dpy_x, dpy_y);
}
xdamage_scheduled_mark = 0.0;
}
} else {
destroy_xdamage_if_needed();
}
}

@ -0,0 +1,29 @@
#ifndef _X11VNC_XDAMAGE_H
#define _X11VNC_XDAMAGE_H
/* -- xdamage.h -- */
#if LIBVNCSERVER_HAVE_LIBXDAMAGE
extern Damage xdamage;
#endif
extern int use_xdamage;
extern int xdamage_present;
extern int xdamage_max_area;
extern double xdamage_memory;
extern int xdamage_tile_count, xdamage_direct_count;
extern double xdamage_scheduled_mark;
extern sraRegionPtr xdamage_scheduled_mark_region;
extern sraRegionPtr *xdamage_regions;
extern int xdamage_ticker;
extern int XD_skip, XD_tot, XD_des;
extern void add_region_xdamage(sraRegionPtr new_region);
extern void clear_xdamage_mark_region(sraRegionPtr markregion, int flush);
extern int collect_xdamage(int scancnt, int call);
extern int xdamage_hint_skip(int y);
extern void initialize_xdamage(void);
extern void create_xdamage_if_needed(void);
extern void destroy_xdamage_if_needed(void);
extern void check_xdamage_state(void);
#endif /* _X11VNC_XDAMAGE_H */

@ -0,0 +1,981 @@
/* -- xevents.c -- */
#include "x11vnc.h"
#include "xwrappers.h"
#include "xkb_bell.h"
#include "xrandr.h"
#include "xdamage.h"
#include "xrecord.h"
#include "selection.h"
#include "keyboard.h"
#include "cursor.h"
#include "gui.h"
#include "connections.h"
/* XXX CHECK BEFORE RELEASE */
int grab_buster = 0;
int sync_tod_delay = 3;
void initialize_vnc_connect_prop(void);
void spawn_grab_buster(void);
void sync_tod_with_servertime(void);
void check_keycode_state(void);
void check_autorepeat(void);
void check_xevents(void);
void xcut_receive(char *text, int len, rfbClientPtr cl);
static void initialize_xevents(void);
static void print_xevent_bases(void);
static void get_prop(char *str, int len, Atom prop);
static void bust_grab(int reset);
static int process_watch(char *str, int parent, int db);
static void grab_buster_watch(int parent, char *dstr);
void initialize_vnc_connect_prop(void) {
vnc_connect_str[0] = '\0';
vnc_connect_prop = XInternAtom(dpy, "VNC_CONNECT", False);
}
static void initialize_xevents(void) {
static int did_xselect_input = 0;
static int did_xcreate_simple_window = 0;
static int did_vnc_connect_prop = 0;
static int did_xfixes = 0;
static int did_xdamage = 0;
static int did_xrandr = 0;
if ((watch_selection || vnc_connect) && !did_xselect_input) {
/*
* register desired event(s) for notification.
* PropertyChangeMask is for CUT_BUFFER0 changes.
* XXX: does this cause a flood of other stuff?
*/
X_LOCK;
XSelectInput(dpy, rootwin, PropertyChangeMask);
X_UNLOCK;
did_xselect_input = 1;
}
if (watch_selection && !did_xcreate_simple_window) {
/* create fake window for our selection ownership, etc */
X_LOCK;
selwin = XCreateSimpleWindow(dpy, rootwin, 0, 0, 1, 1, 0, 0, 0);
X_UNLOCK;
did_xcreate_simple_window = 1;
}
if (xrandr && !did_xrandr) {
initialize_xrandr();
did_xrandr = 1;
}
if (vnc_connect && !did_vnc_connect_prop) {
initialize_vnc_connect_prop();
did_vnc_connect_prop = 1;
}
if (xfixes_present && use_xfixes && !did_xfixes) {
initialize_xfixes();
did_xfixes = 1;
}
if (xdamage_present && !did_xdamage) {
initialize_xdamage();
did_xdamage = 1;
}
}
static void print_xevent_bases(void) {
fprintf(stderr, "X event bases: xkb=%d, xtest=%d, xrandr=%d, "
"xfixes=%d, xdamage=%d, xtrap=%d\n", xkb_base_event_type,
xtest_base_event_type, xrandr_base_event_type,
xfixes_base_event_type, xdamage_base_event_type,
xtrap_base_event_type);
fprintf(stderr, " MapNotify=%d, ClientMsg=%d PropNotify=%d "
"SelNotify=%d, SelRequest=%d\n", MappingNotify, ClientMessage,
PropertyNotify, SelectionNotify, SelectionRequest);
fprintf(stderr, " SelClear=%d, Expose=%d\n", SelectionClear, Expose);
}
static void get_prop(char *str, int len, Atom prop) {
Atom type;
int format, slen, dlen, i;
unsigned long nitems = 0, bytes_after = 0;
unsigned char* data = NULL;
for (i=0; i<len; i++) {
str[i] = '\0';
}
if (prop == None) {
return;
}
slen = 0;
do {
if (XGetWindowProperty(dpy, DefaultRootWindow(dpy),
prop, nitems/4, len/16, False,
AnyPropertyType, &type, &format, &nitems, &bytes_after,
&data) == Success) {
dlen = nitems * (format/8);
if (slen + dlen > len) {
/* too big */
XFree(data);
break;
}
memcpy(str+slen, data, dlen);
slen += dlen;
str[slen] = '\0';
XFree(data);
}
} while (bytes_after > 0);
}
static void bust_grab(int reset) {
static int bust_count = 0;
static time_t last_bust = 0;
time_t now = time(0);
KeyCode key;
int button, x, y, nb;
if (now > last_bust + 180) {
bust_count = 0;
}
if (reset) {
bust_count = 0;
return;
}
x = 0;
y = 0;
button = 0;
key = NoSymbol;
nb = 8;
if (bust_count >= 3 * nb) {
fprintf(stderr, "too many bust_grab's %d for me\n", bust_count);
exit(0);
}
if (bust_count % nb == 0) {
button = 1;
} else if (bust_count % nb == 1) {
button = 1;
} else if (bust_count % nb == 2) {
key = XKeysymToKeycode(dpy, XK_Escape);
} else if (bust_count % nb == 3) {
button = 3;
} else if (bust_count % nb == 4) {
key = XKeysymToKeycode(dpy, XK_space);
} else if (bust_count % nb == 5) {
x = bust_count * 23;
y = bust_count * 17;
} else if (bust_count % nb == 5) {
button = 2;
} else if (bust_count % nb == 6) {
key = XKeysymToKeycode(dpy, XK_a);
}
if (key == NoSymbol) {
key = XKeysymToKeycode(dpy, XK_a);
if (key == NoSymbol) {
button = 1;
}
}
bust_count++;
if (button) {
/* try button press+release */
fprintf(stderr, "**bust_grab: button%d %.4f\n",
button, dnowx());
XTestFakeButtonEvent_wr(dpy, button, True, CurrentTime);
XFlush(dpy);
usleep(50 * 1000);
XTestFakeButtonEvent_wr(dpy, button, False, CurrentTime);
} else if (x > 0) {
/* try button motion*/
int scr = DefaultScreen(dpy);
fprintf(stderr, "**bust_grab: x=%d y=%d %.4f\n", x, y,
dnowx());
XTestFakeMotionEvent_wr(dpy, scr, x, y, CurrentTime);
XFlush(dpy);
usleep(50 * 1000);
/* followed by button press */
button = 1;
fprintf(stderr, "**bust_grab: button%d\n", button);
XTestFakeButtonEvent_wr(dpy, button, True, CurrentTime);
XFlush(dpy);
usleep(50 * 1000);
XTestFakeButtonEvent_wr(dpy, button, False, CurrentTime);
} else {
/* try Escape or Space press+release */
fprintf(stderr, "**bust_grab: keycode: %d %.4f\n",
(int) key, dnowx());
XTestFakeKeyEvent_wr(dpy, key, True, CurrentTime);
XFlush(dpy);
usleep(50 * 1000);
XTestFakeKeyEvent_wr(dpy, key, False, CurrentTime);
}
XFlush(dpy);
last_bust = time(0);
}
typedef struct _grabwatch {
int pid;
int tick;
unsigned long time;
time_t change;
} grabwatch_t;
#define GRABWATCH 16
static int grab_buster_delay = 20;
static pid_t grab_buster_pid = 0;
static int grab_npids = 1;
static int process_watch(char *str, int parent, int db) {
int i, pid, ticker, npids;
char diff[128];
unsigned long xtime;
static grabwatch_t watches[GRABWATCH];
static int first = 1;
time_t now = time(0);
static time_t last_bust = 0;
int too_long, problems = 0;
if (first) {
for (i=0; i < GRABWATCH; i++) {
watches[i].pid = 0;
watches[i].tick = 0;
watches[i].time = 0;
watches[i].change = 0;
}
first = 0;
}
/* record latest value of prop */
if (str && *str != '\0') {
if (sscanf(str, "%d/%d/%lu/%s", &pid, &ticker, &xtime, diff)
== 4) {
int got = -1, free = -1;
if (db) fprintf(stderr, "grab_buster %d - %d - %lu - %s"
"\n", pid, ticker, xtime, diff);
if (pid == parent && !strcmp(diff, "QUIT")) {
/* that's it. */
return 0;
}
if (pid == 0 || ticker == 0 || xtime == 0) {
/* bad prop read. */
goto badtickerstr;
}
for (i=0; i < GRABWATCH; i++) {
if (watches[i].pid == pid) {
got = i;
break;
}
if (free == -1 && watches[i].pid == 0) {
free = i;
}
}
if (got == -1) {
if (free == -1) {
/* bad news */;
free = GRABWATCH - 1;
}
watches[free].pid = pid;
watches[free].tick = ticker;
watches[free].time = xtime;
watches[free].change = now;
if (db) fprintf(stderr, "grab_buster free slot: %d\n", free);
} else {
if (db) fprintf(stderr, "grab_buster got slot: %d\n", got);
if (watches[got].tick != ticker) {
watches[got].change = now;
}
if (watches[got].time != xtime) {
watches[got].change = now;
}
watches[got].tick = ticker;
watches[got].time = xtime;
}
} else {
if (db) fprintf(stderr, "grab_buster bad prop str: %s\n", str);
}
}
badtickerstr:
too_long = grab_buster_delay;
if (too_long < 3 * sync_tod_delay) {
too_long = 3 * sync_tod_delay;
}
npids = 0;
for (i=0; i < GRABWATCH; i++) {
if (watches[i].pid) {
npids++;
}
}
grab_npids = npids;
if (npids > 4) {
npids = 4;
}
/* now check everyone we are tracking */
for (i=0; i < GRABWATCH; i++) {
int fac = 1;
if (!watches[i].pid) {
continue;
}
if (watches[i].change == 0) {
watches[i].change = now; /* just to be sure */
continue;
}
pid = watches[i].pid;
if (pid != parent) {
fac = 2;
}
if (npids > 0) {
fac *= npids;
}
if (now > watches[i].change + fac*too_long) {
int process_alive = 1;
fprintf(stderr, "grab_buster: problem with pid: "
"%d - %d/%d/%d\n", pid, (int) now,
(int) watches[i].change, too_long);
if (kill((pid_t) pid, 0) != 0) {
if (1 || errno == ESRCH) {
process_alive = 0;
}
}
if (!process_alive) {
watches[i].pid = 0;
watches[i].tick = 0;
watches[i].time = 0;
watches[i].change = 0;
fprintf(stderr, "grab_buster: pid gone: %d\n",
pid);
if (pid == parent) {
/* that's it */
return 0;
}
} else {
int sleep = sync_tod_delay * 1000 * 1000;
bust_grab(0);
problems++;
last_bust = now;
usleep(1 * sleep);
break;
}
}
}
if (!problems) {
bust_grab(1);
}
return 1;
}
static void grab_buster_watch(int parent, char *dstr) {
Atom ticker_atom = None;
int sleep = sync_tod_delay * 921 * 1000;
char propval[200];
int ev, er, maj, min;
int db = 0;
if (grab_buster > 1) {
db = 1;
}
/* overwrite original dpy, we let orig connection sit unused. */
dpy = XOpenDisplay(dstr);
if (!dpy) {
fprintf(stderr, "grab_buster_watch: could not reopen: %s\n",
dstr);
return;
}
rfbLogEnable(0);
/* check for XTEST, etc, and then disable grabs for us */
if (! XTestQueryExtension_wr(dpy, &ev, &er, &maj, &min)) {
xtest_present = 0;
} else {
xtest_present = 1;
}
if (! XETrapQueryExtension_wr(dpy, &ev, &er, &maj)) {
xtrap_present = 0;
} else {
xtrap_present = 1;
}
if (! xtest_present && ! xtrap_present) {
fprintf(stderr, "grab_buster_watch: no grabserver "
"protection on display: %s\n", dstr);
return;
}
disable_grabserver(dpy, 0);
usleep(3 * sleep);
ticker_atom = XInternAtom(dpy, "X11VNC_TICKER", False);
if (! ticker_atom) {
fprintf(stderr, "grab_buster_watch: no ticker atom\n");
return;
}
while(1) {
int slp = sleep;
if (grab_npids > 1) {
slp = slp / 8;
}
usleep(slp);
usleep((int) (0.60 * rfac() * slp));
if (kill((pid_t) parent, 0) != 0) {
break;
}
get_prop(propval, 128, ticker_atom);
if (db) fprintf(stderr, "got_prop: %s\n", propval);
if (!process_watch(propval, parent, db)) {
break;
}
}
}
void spawn_grab_buster(void) {
#if LIBVNCSERVER_HAVE_FORK
pid_t pid;
int parent = (int) getpid();
char *dstr = strdup(DisplayString(dpy));
XCloseDisplay(dpy);
dpy = NULL;
if ((pid = fork()) > 0) {
grab_buster_pid = pid;
if (! quiet) {
rfbLog("grab_buster pid is: %d\n", (int) pid);
}
} else if (pid == -1) {
fprintf(stderr, "spawn_grab_buster: could not fork\n");
rfbLogPerror("fork");
} else {
grab_buster_watch(parent, dstr);
exit(0);
}
dpy = XOpenDisplay(dstr);
if (!dpy) {
rfbLog("failed to reopen display %s in spawn_grab_buster\n",
dstr);
exit(1);
}
#endif
}
void sync_tod_with_servertime(void) {
static Atom ticker_atom = None;
XEvent xev;
char diff[128];
static int seq = 0;
static unsigned long xserver_ticks = 1;
int i, db = 0;
if (! ticker_atom) {
ticker_atom = XInternAtom(dpy, "X11VNC_TICKER", False);
}
if (! ticker_atom) {
return;
}
XSync(dpy, False);
while (XCheckTypedEvent(dpy, PropertyNotify, &xev)) {
;
}
snprintf(diff, 128, "%d/%08d/%lu/%.6f", (int) getpid(), seq++,
xserver_ticks, servertime_diff);
XChangeProperty(dpy, rootwin, ticker_atom, XA_STRING, 8,
PropModeReplace, (unsigned char *) diff, strlen(diff));
XSync(dpy, False);
for (i=0; i < 10; i++) {
int k, got = 0;
for (k=0; k < 5; k++) {
while (XCheckTypedEvent(dpy, PropertyNotify, &xev)) {
if (xev.xproperty.atom == ticker_atom) {
double stime;
xserver_ticks = xev.xproperty.time;
stime = (double) xev.xproperty.time;
stime = stime/1000.0;
servertime_diff = dnow() - stime;
if (db) rfbLog("set servertime_diff: "
"%.6f\n", servertime_diff);
got = 1;
}
}
}
if (got) {
break;
}
usleep(1000);
}
}
void check_keycode_state(void) {
static time_t last_check = 0;
int delay = 10, noinput = 3;
time_t now = time(0);
if (! client_count) {
return;
}
if (raw_fb && ! dpy) return; /* raw_fb hack */
/*
* periodically update our model of the keycode_state[]
* by correlating with the Xserver. wait for a pause in
* keyboard input to be on the safe side. the idea here
* is to remove stale keycode state, not to be perfectly
* in sync with the Xserver at every instant of time.
*/
if (now > last_check + delay && now > last_keyboard_input + noinput) {
init_track_keycode_state();
last_check = now;
}
}
void check_autorepeat(void) {
static time_t last_check = 0;
time_t now = time(0);
int autorepeat_is_on, autorepeat_initially_on, idle_timeout = 300;
static int idle_reset = 0;
if (! no_autorepeat || ! client_count) {
return;
}
if (now <= last_check + 1) {
return;
}
last_check = now;
autorepeat_is_on = get_autorepeat_state();
autorepeat_initially_on = get_initial_autorepeat_state();
if (view_only) {
if (! autorepeat_is_on) {
autorepeat(1, 1);
}
return;
}
if (now > last_keyboard_input + idle_timeout) {
/* autorepeat should be on when idle */
if (! autorepeat_is_on && autorepeat_initially_on) {
static time_t last_msg = 0;
static int cnt = 0;
if (now > last_msg + idle_timeout && cnt++ < 5) {
rfbLog("idle keyboard: turning X autorepeat"
" back on.\n");
last_msg = now;
}
autorepeat(1, 1);
idle_reset = 1;
}
} else {
if (idle_reset) {
static time_t last_msg = 0;
static int cnt = 0;
if (now > last_msg + idle_timeout && cnt++ < 5) {
rfbLog("active keyboard: turning X autorepeat"
" off.\n");
last_msg = now;
}
autorepeat(0, 1);
idle_reset = 0;
} else if (no_repeat_countdown && autorepeat_is_on) {
int n = no_repeat_countdown - 1;
if (n >= 0) {
rfbLog("Battling with something for "
"-norepeat!! (%d resets left)\n", n);
} else {
rfbLog("Battling with something for "
"-norepeat!!\n");
}
if (no_repeat_countdown > 0) {
no_repeat_countdown--;
}
autorepeat(1, 0);
autorepeat(0, 0);
}
}
}
/*
* This routine is periodically called to check for selection related
* and other X11 events and respond to them as needed.
*/
void check_xevents(void) {
XEvent xev;
int tmp, have_clients = 0;
static int sent_some_sel = 0;
static time_t last_request = 0;
static time_t last_call = 0;
static time_t last_bell = 0;
static time_t last_init_check = 0;
static time_t last_sync = 0;
static time_t last_time_sync = 0;
time_t now = time(0);
if (raw_fb && ! dpy) return; /* raw_fb hack */
if (now > last_init_check+1) {
last_init_check = now;
initialize_xevents();
}
if (screen && screen->clientHead) {
have_clients = 1;
}
X_LOCK;
/*
* There is a bug where we have to wait before sending text to
* the client... so instead of sending right away we wait a
* the few seconds.
*/
if (have_clients && watch_selection && !sent_some_sel
&& now > last_client + sel_waittime) {
if (XGetSelectionOwner(dpy, XA_PRIMARY) == None) {
cutbuffer_send();
}
sent_some_sel = 1;
}
if (! have_clients) {
/*
* If we don't have clients we can miss the X server
* going away until a client connects.
*/
static time_t last_X_ping = 0;
if (now > last_X_ping + 5) {
last_X_ping = now;
XGetSelectionOwner(dpy, XA_PRIMARY);
}
}
if (now > last_call+1) {
/* we only check these once a second or so. */
int n = 0;
while (XCheckTypedEvent(dpy, MappingNotify, &xev)) {
XRefreshKeyboardMapping((XMappingEvent *) &xev);
n++;
}
if (n && use_modifier_tweak) {
X_UNLOCK;
initialize_modtweak();
X_LOCK;
}
if (xtrap_base_event_type) {
int base = xtrap_base_event_type;
while (XCheckTypedEvent(dpy, base, &xev)) {
;
}
}
if (xtest_base_event_type) {
int base = xtest_base_event_type;
while (XCheckTypedEvent(dpy, base, &xev)) {
;
}
}
/*
* we can get ClientMessage from our XSendEvent() call in
* selection_request().
*/
while (XCheckTypedEvent(dpy, ClientMessage, &xev)) {
;
}
}
/* check for CUT_BUFFER0 and VNC_CONNECT changes: */
if (XCheckTypedEvent(dpy, PropertyNotify, &xev)) {
if (xev.type == PropertyNotify) {
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_some_sel = 1;
}
set_cutbuffer = 0;
} else if (vnc_connect && vnc_connect_prop != None
&& xev.xproperty.atom == vnc_connect_prop) {
/*
* Go retrieve VNC_CONNECT string.
*/
read_vnc_connect_prop();
}
}
}
/* do this now that we have just cleared PropertyNotify */
tmp = 0;
if (rfac() < 0.6) {
tmp = 1;
}
if (now > last_time_sync + sync_tod_delay + tmp) {
sync_tod_with_servertime();
last_time_sync = now;
}
#if LIBVNCSERVER_HAVE_LIBXRANDR
if (xrandr) {
check_xrandr_event("check_xevents");
}
#endif
#if LIBVNCSERVER_HAVE_LIBXFIXES
if (xfixes_present && use_xfixes && xfixes_base_event_type) {
if (XCheckTypedEvent(dpy, xfixes_base_event_type +
XFixesCursorNotify, &xev)) {
got_xfixes_cursor_notify++;
}
}
#endif
/* check for our PRIMARY request notification: */
if (watch_primary) {
if (XCheckTypedEvent(dpy, SelectionNotify, &xev)) {
if (xev.type == SelectionNotify &&
xev.xselection.requestor == selwin &&
xev.xselection.selection == XA_PRIMARY &&
xev.xselection.property != None &&
xev.xselection.target == XA_STRING) {
/* go retrieve PRIMARY and check it */
if (now > last_client + sel_waittime
|| sent_some_sel) {
selection_send(&xev);
}
}
}
if (now > last_request) {
/*
* Every second or two, request PRIMARY, unless we
* already own it or there is no owner or we have
* no clients.
* TODO: even at this low rate we should look into
* and performance problems in odds cases, etc.
*/
last_request = now;
if (! own_selection && have_clients &&
XGetSelectionOwner(dpy, XA_PRIMARY) != None) {
XConvertSelection(dpy, XA_PRIMARY, XA_STRING,
XA_STRING, selwin, CurrentTime);
}
}
}
if (own_selection) {
/* we own PRIMARY, see if someone requested it: */
if (XCheckTypedEvent(dpy, SelectionRequest, &xev)) {
if (xev.type == SelectionRequest &&
xev.xselectionrequest.selection == XA_PRIMARY) {
selection_request(&xev);
}
}
/* we own PRIMARY, see if we no longer own it: */
if (XCheckTypedEvent(dpy, SelectionClear, &xev)) {
if (xev.type == SelectionClear &&
xev.xselectionclear.selection == XA_PRIMARY) {
own_selection = 0;
if (xcut_str) {
free(xcut_str);
xcut_str = NULL;
}
}
}
}
if (watch_bell || now > last_bell+1) {
last_bell = now;
check_bell_event();
}
if (tray_request != None) {
static time_t last_tray_request = 0;
if (now > last_tray_request + 2) {
last_tray_request = now;
if (tray_embed(tray_request, tray_unembed)) {
tray_window = tray_request;
tray_request = None;
}
}
}
#ifndef DEBUG_XEVENTS
#define DEBUG_XEVENTS 1
#endif
#if DEBUG_XEVENTS
if (debug_xevents) {
static time_t last_check = 0;
static time_t reminder = 0;
static int freq = 0;
if (! freq) {
if (getenv("X11VNC_REMINDER_RATE")) {
freq = atoi(getenv("X11VNC_REMINDER_RATE"));
} else {
freq = 300;
}
}
if (now > last_check + 1) {
int ev_type_max = 300, ev_size = 400;
XEvent xevs[400];
int i, tot = XEventsQueued(dpy, QueuedAlready);
if (reminder == 0 || (tot && now > reminder + freq)) {
print_xevent_bases();
reminder = now;
}
last_check = now;
if (tot) {
fprintf(stderr, "Total events queued: %d\n",
tot);
}
for (i=1; i<ev_type_max; i++) {
int k, n = 0;
while (XCheckTypedEvent(dpy, i, xevs+n)) {
if (++n >= ev_size) {
break;
}
}
if (n) {
fprintf(stderr, " %d%s events of type"
" %d queued\n", n,
(n >= ev_size) ? "+" : "", i);
}
for (k=n-1; k >= 0; k--) {
XPutBackEvent(dpy, xevs+k);
}
}
}
}
#endif
if (now > last_sync + 1200) {
/* kludge for any remaining event leaks */
int bugout = use_xdamage ? 500 : 50;
int qlen, i;
if (last_sync != 0) {
qlen = XEventsQueued(dpy, QueuedAlready);
if (qlen >= bugout) {
rfbLog("event leak: %d queued, "
" calling XSync(dpy, True)\n", qlen);
rfbLog(" for diagnostics run: 'x11vnc -R"
" debug_xevents:1'\n");
XSync(dpy, True);
}
}
last_sync = now;
/* clear these, we don't want any events on them */
if (rdpy_ctrl) {
qlen = XEventsQueued(rdpy_ctrl, QueuedAlready);
for (i=0; i<qlen; i++) {
XNextEvent(rdpy_ctrl, &xev);
}
}
if (gdpy_ctrl) {
qlen = XEventsQueued(gdpy_ctrl, QueuedAlready);
for (i=0; i<qlen; i++) {
XNextEvent(gdpy_ctrl, &xev);
}
}
}
X_UNLOCK;
last_call = now;
}
/*
* hook called when a VNC client sends us some "XCut" text (rfbClientCutText).
*/
void xcut_receive(char *text, int len, rfbClientPtr cl) {
allowed_input_t input;
if (raw_fb && ! dpy) return; /* raw_fb hack */
if (!watch_selection) {
return;
}
if (view_only) {
return;
}
if (text == NULL || len == 0) {
return;
}
get_allowed_input(cl, &input);
if (!input.keystroke && !input.motion && !input.button) {
/* maybe someday KMBC for cut text... */
return;
}
if (! check_sel_direction("recv", "xcut_receive", text, len)) {
return;
}
X_LOCK;
/* associate this text with PRIMARY (and SECONDARY...) */
if (! own_selection) {
own_selection = 1;
/* we need to grab the PRIMARY selection */
XSetSelectionOwner(dpy, XA_PRIMARY, selwin, CurrentTime);
XFlush(dpy);
}
/* duplicate the text string for our own use. */
if (xcut_str != NULL) {
free(xcut_str);
xcut_str = NULL;
}
xcut_str = (char *) malloc((size_t) (len+1));
strncpy(xcut_str, text, len);
xcut_str[len] = '\0'; /* make sure null terminated */
/* copy this text to CUT_BUFFER0 as well: */
XChangeProperty(dpy, rootwin, XA_CUT_BUFFER0, XA_STRING, 8,
PropModeReplace, (unsigned char *) text, len);
XFlush(dpy);
X_UNLOCK;
set_cutbuffer = 1;
}

@ -0,0 +1,17 @@
#ifndef _X11VNC_XEVENTS_H
#define _X11VNC_XEVENTS_H
/* -- xevents.h -- */
extern int grab_buster;
extern int sync_tod_delay;
extern void initialize_vnc_connect_prop(void);
extern void spawn_grab_buster(void);
extern void sync_tod_with_servertime(void);
extern void check_keycode_state(void);
extern void check_autorepeat(void);
extern void check_xevents(void);
extern void xcut_receive(char *text, int len, rfbClientPtr cl);
#endif /* _X11VNC_XEVENTS_H */

@ -0,0 +1,409 @@
/* -- xinerama.c -- */
#include "x11vnc.h"
#include "xwrappers.h"
#include "blackout_t.h"
#include "scan.h"
/*
* routines related to xinerama and blacking out rectangles
*/
/* blacked-out region (-blackout, -xinerama) */
#define BLACKR_MAX 100
blackout_t blackr[BLACKR_MAX]; /* hardwired max blackouts */
tile_blackout_t *tile_blackout;
int blackouts = 0;
void initialize_blackouts_and_xinerama(void);
void push_sleep(int n);
void push_black_screen(int n);
void refresh_screen(int push);
void zero_fb(int x1, int y1, int x2, int y2);
static void initialize_blackouts(char *list);
static void blackout_tiles(void);
static void initialize_xinerama (void);
/*
* Take a comma separated list of geometries: WxH+X+Y and register them as
* rectangles to black out from the screen.
*/
static void initialize_blackouts(char *list) {
char *p, *blist = strdup(list);
int x, y, X, Y, h, w, t;
p = strtok(blist, ", \t");
while (p) {
if (!strcmp("noptr", p)) {
blackout_ptr = 1;
rfbLog("pointer will be blocked from blackout "
"regions\n");
p = strtok(NULL, ", \t");
continue;
}
if (! parse_geom(p, &w, &h, &x, &y, dpy_x, dpy_y)) {
if (*p != '\0') {
rfbLog("skipping invalid geometry: %s\n", p);
}
p = strtok(NULL, ", \t");
continue;
}
w = nabs(w);
h = nabs(h);
x = nfix(x, dpy_x);
y = nfix(y, dpy_y);
X = x + w;
Y = y + h;
X = nfix(X, dpy_x+1);
Y = nfix(Y, dpy_y+1);
if (x > X) {
t = X; X = x; x = t;
}
if (y > Y) {
t = Y; Y = y; y = t;
}
if (x < 0 || x > dpy_x || y < 0 || y > dpy_y ||
X < 0 || X > dpy_x || Y < 0 || Y > dpy_y ||
x == X || y == Y) {
rfbLog("skipping invalid blackout geometry: %s x="
"%d-%d,y=%d-%d,w=%d,h=%d\n", p, x, X, y, Y, w, h);
} else {
rfbLog("blackout rect: %s: x=%d-%d y=%d-%d\n", p,
x, X, y, Y);
/*
* note that the black out is x1 <= x but x < x2
* for the region. i.e. the x2, y2 are outside
* by 1 pixel.
*/
blackr[blackouts].x1 = x;
blackr[blackouts].y1 = y;
blackr[blackouts].x2 = X;
blackr[blackouts].y2 = Y;
blackouts++;
if (blackouts >= BLACKR_MAX) {
rfbLog("too many blackouts: %d\n", blackouts);
break;
}
}
p = strtok(NULL, ", \t");
}
free(blist);
}
/*
* Now that all blackout rectangles have been constructed, see what overlap
* they have with the tiles in the system. If a tile is touched by a
* blackout, record information.
*/
static void blackout_tiles(void) {
int tx, ty;
int debug_bo = 0;
if (! blackouts) {
return;
}
if (getenv("DEBUG_BLACKOUT") != NULL) {
debug_bo = 1;
}
/*
* to simplify things drop down to single copy mode, etc...
*/
single_copytile = 1;
/* loop over all tiles. */
for (ty=0; ty < ntiles_y; ty++) {
for (tx=0; tx < ntiles_x; tx++) {
sraRegionPtr tile_reg, black_reg;
sraRect rect;
sraRectangleIterator *iter;
int n, b, x1, y1, x2, y2, cnt;
/* tile number and coordinates: */
n = tx + ty * ntiles_x;
x1 = tx * tile_x;
y1 = ty * tile_y;
x2 = x1 + tile_x;
y2 = y1 + tile_y;
if (x2 > dpy_x) {
x2 = dpy_x;
}
if (y2 > dpy_y) {
y2 = dpy_y;
}
/* make regions for the tile and the blackouts: */
black_reg = (sraRegionPtr) sraRgnCreate();
tile_reg = (sraRegionPtr) sraRgnCreateRect(x1, y1,
x2, y2);
tile_blackout[n].cover = 0;
tile_blackout[n].count = 0;
/* union of blackouts */
for (b=0; b < blackouts; b++) {
sraRegionPtr tmp_reg = (sraRegionPtr)
sraRgnCreateRect(blackr[b].x1,
blackr[b].y1, blackr[b].x2, blackr[b].y2);
sraRgnOr(black_reg, tmp_reg);
sraRgnDestroy(tmp_reg);
}
if (! sraRgnAnd(black_reg, tile_reg)) {
/*
* no intersection for this tile, so we
* are done.
*/
sraRgnDestroy(black_reg);
sraRgnDestroy(tile_reg);
continue;
}
/*
* loop over rectangles that make up the blackout
* region:
*/
cnt = 0;
iter = sraRgnGetIterator(black_reg);
while (sraRgnIteratorNext(iter, &rect)) {
/* make sure x1 < x2 and y1 < y2 */
if (rect.x1 > rect.x2) {
int tmp = rect.x2;
rect.x2 = rect.x1;
rect.x1 = tmp;
}
if (rect.y1 > rect.y2) {
int tmp = rect.y2;
rect.y2 = rect.y1;
rect.y1 = tmp;
}
/* store coordinates */
tile_blackout[n].bo[cnt].x1 = rect.x1;
tile_blackout[n].bo[cnt].y1 = rect.y1;
tile_blackout[n].bo[cnt].x2 = rect.x2;
tile_blackout[n].bo[cnt].y2 = rect.y2;
/* note if the tile is completely obscured */
if (rect.x1 == x1 && rect.y1 == y1 &&
rect.x2 == x2 && rect.y2 == y2) {
tile_blackout[n].cover = 2;
if (debug_bo) {
fprintf(stderr, "full: %d=%d,%d"
" (%d-%d) (%d-%d)\n",
n, tx, ty, x1, x2, y1, y2);
}
} else {
tile_blackout[n].cover = 1;
if (debug_bo) {
fprintf(stderr, "part: %d=%d,%d"
" (%d-%d) (%d-%d)\n",
n, tx, ty, x1, x2, y1, y2);
}
}
if (++cnt >= BO_MAX) {
rfbLog("too many blackout rectangles "
"for tile %d=%d,%d.\n", n, tx, ty);
break;
}
}
sraRgnReleaseIterator(iter);
sraRgnDestroy(black_reg);
sraRgnDestroy(tile_reg);
tile_blackout[n].count = cnt;
if (debug_bo && cnt > 1) {
rfbLog("warning: multiple region overlaps[%d] "
"for tile %d=%d,%d.\n", cnt, n, tx, ty);
}
}
}
}
static void initialize_xinerama (void) {
#if !LIBVNCSERVER_HAVE_LIBXINERAMA
rfbLog("Xinerama: Library libXinerama is not available to determine\n");
rfbLog("Xinerama: the head geometries, consider using -blackout\n");
rfbLog("Xinerama: if the screen is non-rectangular.\n");
#else
XineramaScreenInfo *sc, *xineramas;
sraRegionPtr black_region, tmp_region;
sraRectangleIterator *iter;
sraRect rect;
char *bstr, *tstr;
int ev, er, i, n, rcnt;
if (raw_fb && ! dpy) return; /* raw_fb hack */
if (! XineramaQueryExtension(dpy, &ev, &er)) {
rfbLog("Xinerama: disabling: display does not support it.\n");
xinerama = 0;
xinerama_present = 0;
return;
}
if (! XineramaIsActive(dpy)) {
/* n.b. change to XineramaActive(dpy, window) someday */
rfbLog("Xinerama: disabling: not active on display.\n");
xinerama = 0;
xinerama_present = 0;
return;
}
xinerama_present = 1;
/* n.b. change to XineramaGetData() someday */
xineramas = XineramaQueryScreens(dpy, &n);
rfbLog("Xinerama: number of sub-screens: %d\n", n);
if (n == 1) {
rfbLog("Xinerama: no blackouts needed (only one"
" sub-screen)\n");
XFree(xineramas);
return; /* must be OK w/o change */
}
black_region = sraRgnCreateRect(0, 0, dpy_x, dpy_y);
sc = xineramas;
for (i=0; i<n; i++) {
int x, y, w, h;
x = sc->x_org;
y = sc->y_org;
w = sc->width;
h = sc->height;
tmp_region = sraRgnCreateRect(x, y, x + w, y + h);
sraRgnSubtract(black_region, tmp_region);
sraRgnDestroy(tmp_region);
sc++;
}
XFree(xineramas);
if (sraRgnEmpty(black_region)) {
rfbLog("Xinerama: no blackouts needed (screen fills"
" rectangle)\n");
sraRgnDestroy(black_region);
return;
}
/* max len is 10000x10000+10000+10000 (23 chars) per geometry */
rcnt = (int) sraRgnCountRects(black_region);
bstr = (char *) malloc(30 * (rcnt+1));
tstr = (char *) malloc(30);
bstr[0] = '\0';
iter = sraRgnGetIterator(black_region);
while (sraRgnIteratorNext(iter, &rect)) {
int x, y, w, h;
/* make sure x1 < x2 and y1 < y2 */
if (rect.x1 > rect.x2) {
int tmp = rect.x2;
rect.x2 = rect.x1;
rect.x1 = tmp;
}
if (rect.y1 > rect.y2) {
int tmp = rect.y2;
rect.y2 = rect.y1;
rect.y1 = tmp;
}
x = rect.x1;
y = rect.y1;
w = rect.x2 - x;
h = rect.y2 - y;
sprintf(tstr, "%dx%d+%d+%d,", w, h, x, y);
strcat(bstr, tstr);
}
initialize_blackouts(bstr);
free(bstr);
free(tstr);
#endif
}
void initialize_blackouts_and_xinerama(void) {
blackouts = 0;
blackout_ptr = 0;
if (blackout_str != NULL) {
initialize_blackouts(blackout_str);
}
if (xinerama) {
initialize_xinerama();
}
if (blackouts) {
blackout_tiles();
/* schedule a copy_screen(), now is too early. */
do_copy_screen = 1;
}
}
void push_sleep(int n) {
int i;
for (i=0; i<n; i++) {
rfbPE(-1);
if (i != n-1 && defer_update) {
usleep(defer_update * 1000);
}
}
}
/*
* try to forcefully push a black screen to all connected clients
*/
void push_black_screen(int n) {
if (!screen) {
return;
}
zero_fb(0, 0, dpy_x, dpy_y);
mark_rect_as_modified(0, 0, dpy_x, dpy_y, 0);
push_sleep(n);
}
void refresh_screen(int push) {
int i;
if (!screen) {
return;
}
mark_rect_as_modified(0, 0, dpy_x, dpy_y, 0);
for (i=0; i<push; i++) {
rfbPE(-1);
}
}
/*
* Fill the framebuffer with zero for the prescribed rectangle
*/
void zero_fb(int x1, int y1, int x2, int y2) {
int pixelsize = bpp/8;
int line, fill = 0;
char *dst;
if (x1 < 0 || x2 <= x1 || x2 > dpy_x) {
return;
}
if (y1 < 0 || y2 <= y1 || y2 > dpy_y) {
return;
}
if (! main_fb) {
return;
}
dst = main_fb + y1 * main_bytes_per_line + x1 * pixelsize;
line = y1;
while (line++ < y2) {
memset(dst, fill, (size_t) (x2 - x1) * pixelsize);
dst += main_bytes_per_line;
}
}

@ -0,0 +1,17 @@
#ifndef _X11VNC_XINERAMA_H
#define _X11VNC_XINERAMA_H
/* -- xinerama.h -- */
#include "blackout_t.h"
extern blackout_t blackr[];
extern tile_blackout_t *tile_blackout;
extern int blackouts;
extern void initialize_blackouts_and_xinerama(void);
extern void push_sleep(int n);
extern void push_black_screen(int n);
extern void refresh_screen(int push);
extern void zero_fb(int x1, int y1, int x2, int y2);
#endif /* _X11VNC_XINERAMA_H */

@ -0,0 +1,125 @@
/* -- xkb_bell.c -- */
#include "x11vnc.h"
#include "xwrappers.h"
#include "connections.h"
/*
* Bell event handling. Requires XKEYBOARD extension.
*/
int xkb_base_event_type = 0;
void initialize_xkb(void);
void initialize_watch_bell(void);
void check_bell_event(void);
#if LIBVNCSERVER_HAVE_XKEYBOARD
/*
* check for XKEYBOARD, set up xkb_base_event_type
*/
void initialize_xkb(void) {
int ir, reason;
int op, ev, er, maj, min;
if (xkbcompat) {
xkb_present = 0;
} else if (! XkbQueryExtension(dpy, &op, &ev, &er, &maj, &min)) {
if (! quiet) {
rfbLog("warning: XKEYBOARD extension not present.\n");
}
xkb_present = 0;
} else {
xkb_present = 1;
}
if (! xkb_present) {
return;
}
if (! XkbOpenDisplay(DisplayString(dpy), &xkb_base_event_type, &ir,
NULL, NULL, &reason) ) {
if (! quiet) {
rfbLog("warning: disabling XKEYBOARD. XkbOpenDisplay"
" failed.\n");
}
xkb_base_event_type = 0;
xkb_present = 0;
}
}
void initialize_watch_bell(void) {
if (! xkb_present) {
if (! quiet) {
rfbLog("warning: disabling bell. XKEYBOARD ext. "
"not present.\n");
}
watch_bell = 0;
sound_bell = 0;
return;
}
XkbSelectEvents(dpy, XkbUseCoreKbd, XkbBellNotifyMask, 0);
if (! watch_bell) {
return;
}
if (! XkbSelectEvents(dpy, XkbUseCoreKbd, XkbBellNotifyMask,
XkbBellNotifyMask) ) {
if (! quiet) {
rfbLog("warning: disabling bell. XkbSelectEvents"
" failed.\n");
}
watch_bell = 0;
sound_bell = 0;
}
}
/*
* We call this periodically to process any bell events that have
* taken place.
*/
void check_bell_event(void) {
XEvent xev;
XkbAnyEvent *xkb_ev;
int got_bell = 0;
if (! xkb_base_event_type) {
return;
}
/* caller does X_LOCK */
if (! XCheckTypedEvent(dpy, xkb_base_event_type, &xev)) {
return;
}
if (! watch_bell) {
/* we return here to avoid xkb events piling up */
return;
}
xkb_ev = (XkbAnyEvent *) &xev;
if (xkb_ev->xkb_type == XkbBellNotify) {
got_bell = 1;
}
if (got_bell && sound_bell) {
if (! all_clients_initialized()) {
rfbLog("check_bell_event: not sending bell: "
"uninitialized clients\n");
} else {
if (screen && client_count) {
rfbSendBell(screen);
}
}
}
}
#else
void initialize_watch_bell(void) {
watch_bell = 0;
sound_bell = 0;
}
void check_bell_event(void) {}
#endif

@ -0,0 +1,12 @@
#ifndef _X11VNC_XKB_BELL_H
#define _X11VNC_XKB_BELL_H
/* -- xkb_bell.h -- */
extern int xkb_base_event_type;
extern void initialize_xkb(void);
extern void initialize_watch_bell(void);
extern void check_bell_event(void);
#endif /* _X11VNC_XKB_BELL_H */

@ -0,0 +1,225 @@
/* -- xrandr.c -- */
#include "x11vnc.h"
#include "cleanup.h"
#include "connections.h"
#include "remote.h"
#include "screen.h"
#include "win_utils.h"
time_t last_subwin_trap = 0;
int subwin_trap_count = 0;
XErrorHandler old_getimage_handler;
int xrandr_present = 0;
int xrandr_width = -1;
int xrandr_height = -1;
int xrandr_rotation = -1;
Time xrandr_timestamp = 0;
Time xrandr_cfg_time = 0;
void initialize_xrandr(void);
int check_xrandr_event(char *msg);
int known_xrandr_mode(char *s);
static int handle_subwin_resize(char *msg);
static void handle_xrandr_change(int new_x, int new_y);
void initialize_xrandr(void) {
if (xrandr_present) {
#if LIBVNCSERVER_HAVE_LIBXRANDR
Rotation rot;
X_LOCK;
xrandr_width = XDisplayWidth(dpy, scr);
xrandr_height = XDisplayHeight(dpy, scr);
XRRRotations(dpy, scr, &rot);
xrandr_rotation = (int) rot;
if (xrandr) {
XRRSelectInput(dpy, rootwin, RRScreenChangeNotifyMask);
} else {
XRRSelectInput(dpy, rootwin, 0);
}
X_UNLOCK;
#endif
} else if (xrandr) {
rfbLog("-xrandr mode specified, but no RANDR support on\n");
rfbLog(" display or in client library. Disabling -xrandr "
"mode.\n");
xrandr = 0;
}
}
static int handle_subwin_resize(char *msg) {
int new_x, new_y;
int i, check = 10, ms = 250; /* 2.5 secs total... */
if (msg) {} /* unused vars warning: */
if (! subwin) {
return 0; /* hmmm... */
}
if (! valid_window(subwin, NULL, 0)) {
rfbLogEnable(1);
rfbLog("subwin 0x%lx went away!\n", subwin);
X_UNLOCK;
clean_up_exit(1);
}
if (! get_window_size(subwin, &new_x, &new_y)) {
rfbLogEnable(1);
rfbLog("could not get size of subwin 0x%lx\n", subwin);
X_UNLOCK;
clean_up_exit(1);
}
if (wdpy_x == new_x && wdpy_y == new_y) {
/* no change */
return 0;
}
/* window may still be changing (e.g. drag resize) */
for (i=0; i < check; i++) {
int newer_x, newer_y;
usleep(ms * 1000);
if (! get_window_size(subwin, &newer_x, &newer_y)) {
rfbLogEnable(1);
rfbLog("could not get size of subwin 0x%lx\n", subwin);
clean_up_exit(1);
}
if (new_x == newer_x && new_y == newer_y) {
/* go for it... */
break;
} else {
rfbLog("subwin 0x%lx still changing size...\n", subwin);
new_x = newer_x;
new_y = newer_y;
}
}
rfbLog("subwin 0x%lx new size: x: %d -> %d, y: %d -> %d\n",
subwin, wdpy_x, new_x, wdpy_y, new_y);
rfbLog("calling handle_xrandr_change() for resizing\n");
X_UNLOCK;
handle_xrandr_change(new_x, new_y);
return 1;
}
static void handle_xrandr_change(int new_x, int new_y) {
rfbClientIteratorPtr iter;
rfbClientPtr cl;
/* sanity check xrandr_mode */
if (! xrandr_mode) {
xrandr_mode = strdup("default");
} else if (! known_xrandr_mode(xrandr_mode)) {
free(xrandr_mode);
xrandr_mode = strdup("default");
}
rfbLog("xrandr_mode: %s\n", xrandr_mode);
if (!strcmp(xrandr_mode, "exit")) {
close_all_clients();
rfbLog(" shutting down due to XRANDR event.\n");
clean_up_exit(0);
}
if (!strcmp(xrandr_mode, "newfbsize") && screen) {
iter = rfbGetClientIterator(screen);
while( (cl = rfbClientIteratorNext(iter)) ) {
if (cl->useNewFBSize) {
continue;
}
rfbLog(" closing client %s (no useNewFBSize"
" support).\n", cl->host);
rfbCloseClient(cl);
rfbClientConnectionGone(cl);
}
rfbReleaseClientIterator(iter);
}
/* default, resize, and newfbsize create a new fb: */
rfbLog("check_xrandr_event: trying to create new framebuffer...\n");
if (new_x < wdpy_x || new_y < wdpy_y) {
check_black_fb();
}
do_new_fb(1);
rfbLog("check_xrandr_event: fb WxH: %dx%d\n", wdpy_x, wdpy_y);
}
int check_xrandr_event(char *msg) {
XEvent xev;
if (subwin) {
return handle_subwin_resize(msg);
}
#if LIBVNCSERVER_HAVE_LIBXRANDR
if (! xrandr || ! xrandr_present) {
return 0;
}
if (xrandr_base_event_type && XCheckTypedEvent(dpy,
xrandr_base_event_type + RRScreenChangeNotify, &xev)) {
int do_change;
XRRScreenChangeNotifyEvent *rev;
rev = (XRRScreenChangeNotifyEvent *) &xev;
rfbLog("check_xrandr_event():\n");
rfbLog("Detected XRANDR event at location '%s':\n", msg);
rfbLog(" serial: %d\n", (int) rev->serial);
rfbLog(" timestamp: %d\n", (int) rev->timestamp);
rfbLog(" cfg_timestamp: %d\n", (int) rev->config_timestamp);
rfbLog(" size_id: %d\n", (int) rev->size_index);
rfbLog(" sub_pixel: %d\n", (int) rev->subpixel_order);
rfbLog(" rotation: %d\n", (int) rev->rotation);
rfbLog(" width: %d\n", (int) rev->width);
rfbLog(" height: %d\n", (int) rev->height);
rfbLog(" mwidth: %d mm\n", (int) rev->mwidth);
rfbLog(" mheight: %d mm\n", (int) rev->mheight);
rfbLog("\n");
rfbLog("check_xrandr_event: previous WxH: %dx%d\n",
wdpy_x, wdpy_y);
if (wdpy_x == rev->width && wdpy_y == rev->height &&
xrandr_rotation == (int) rev->rotation) {
rfbLog("check_xrandr_event: no change detected.\n");
do_change = 0;
} else {
do_change = 1;
}
xrandr_width = rev->width;
xrandr_height = rev->height;
xrandr_timestamp = rev->timestamp;
xrandr_cfg_time = rev->config_timestamp;
xrandr_rotation = (int) rev->rotation;
rfbLog("check_xrandr_event: updating config...\n");
XRRUpdateConfiguration(&xev);
if (do_change) {
X_UNLOCK;
handle_xrandr_change(rev->width, rev->height);
}
rfbLog("check_xrandr_event: current WxH: %dx%d\n",
XDisplayWidth(dpy, scr), XDisplayHeight(dpy, scr));
rfbLog("check_xrandr_event(): returning control to"
" caller...\n");
return do_change;
}
#endif
return 0;
}
int known_xrandr_mode(char *s) {
/*
* default:
* resize: the default
* exit: shutdown clients and exit.
* newfbsize: shutdown clients that do not support NewFBSize encoding.
*/
if (strcmp(s, "default") && strcmp(s, "resize") &&
strcmp(s, "exit") && strcmp(s, "newfbsize")) {
return 0;
} else {
return 1;
}
}

@ -0,0 +1,60 @@
#ifndef _X11VNC_XRANDR_H
#define _X11VNC_XRANDR_H
/* -- xrandr.h -- */
extern time_t last_subwin_trap;
extern int subwin_trap_count;
extern XErrorHandler old_getimage_handler;
extern int xrandr_present;
extern int xrandr_width;
extern int xrandr_height;
extern int xrandr_rotation;
extern Time xrandr_timestamp;
extern Time xrandr_cfg_time;
extern void initialize_xrandr(void);
extern int check_xrandr_event(char *msg);
extern int known_xrandr_mode(char *s);
#define XRANDR_SET_TRAP_RET(x,y) \
if (subwin || xrandr) { \
trapped_getimage_xerror = 0; \
old_getimage_handler = XSetErrorHandler(trap_getimage_xerror); \
if (check_xrandr_event(y)) { \
trapped_getimage_xerror = 0; \
XSetErrorHandler(old_getimage_handler); \
return(x); \
} \
}
#define XRANDR_CHK_TRAP_RET(x,y) \
if (subwin || xrandr) { \
if (trapped_getimage_xerror) { \
if (subwin) { \
static int last = 0; \
subwin_trap_count++; \
if (time(0) > last_subwin_trap + 60) { \
rfbLog("trapped GetImage xerror" \
" in SUBWIN mode. [%d]\n", \
subwin_trap_count); \
last_subwin_trap = time(0); \
last = subwin_trap_count; \
} \
if (subwin_trap_count - last > 30) { \
/* window probably iconified */ \
usleep(1000*1000); \
} \
} else { \
rfbLog("trapped GetImage xerror" \
" in XRANDR mode.\n"); \
} \
trapped_getimage_xerror = 0; \
XSetErrorHandler(old_getimage_handler); \
check_xrandr_event(y); \
X_UNLOCK; \
return(x); \
} \
}
#endif /* _X11VNC_XRANDR_H */

File diff suppressed because it is too large Load Diff

@ -0,0 +1,35 @@
#ifndef _X11VNC_XRECORD_H
#define _X11VNC_XRECORD_H
/* -- xrecord.h -- */
#include "scrollevent_t.h"
#include "winattr_t.h"
extern scroll_event_t scr_ev[];
extern int scr_ev_cnt;
extern int xrecording;
extern int xrecord_set_by_keys;
extern int xrecord_set_by_mouse;
extern Window xrecord_focus_window;
extern Window xrecord_wm_window;
extern Window xrecord_ptr_window;
extern KeySym xrecord_keysym;
extern char xrecord_name_info[];
extern winattr_t scr_attr_cache[];
extern Display *rdpy_data;
extern Display *rdpy_ctrl;
extern Display *gdpy_ctrl;
extern int xserver_grabbed;
extern void initialize_xrecord(void);
extern void shutdown_xrecord(void);
extern int xrecord_skip_keysym(rfbKeySym keysym);
extern int xrecord_skip_button(int new, int old);
extern int xrecord_scroll_keysym(rfbKeySym keysym);
extern void check_xrecord_reset(int force);
extern void xrecord_watch(int start, int setby);
#endif /* _X11VNC_XRECORD_H */

@ -0,0 +1,697 @@
/* -- xwrappers.c -- */
#include "x11vnc.h"
#include "xrecord.h"
#include "keyboard.h"
int xshm_present = 0;
int xtest_present = 0;
int xtrap_present = 0;
int xrecord_present = 0;
int xkb_present = 0;
int xinerama_present = 0;
int keycode_state[256];
int rootshift = 0;
int clipshift = 0;
int guess_bits_per_color(int bits_per_pixel);
Status XShmGetImage_wr(Display *disp, Drawable d, XImage *image, int x, int y,
unsigned long mask);
XImage *XShmCreateImage_wr(Display* disp, Visual* vis, unsigned int depth,
int format, char* data, XShmSegmentInfo* shminfo, unsigned int width,
unsigned int height);
Status XShmAttach_wr(Display *disp, XShmSegmentInfo *shminfo);
Status XShmDetach_wr(Display *disp, XShmSegmentInfo *shminfo);
Bool XShmQueryExtension_wr(Display *disp);
XImage *xreadscreen(Display *disp, Drawable d, int x, int y,
unsigned int width, unsigned int height, Bool show_cursor);
XImage *XGetSubImage_wr(Display *disp, Drawable d, int x, int y,
unsigned int width, unsigned int height, unsigned long plane_mask,
int format, XImage *dest_image, int dest_x, int dest_y);
XImage *XGetImage_wr(Display *disp, Drawable d, int x, int y,
unsigned int width, unsigned int height, unsigned long plane_mask,
int format);
XImage *XCreateImage_wr(Display *disp, Visual *visual, unsigned int depth,
int format, int offset, char *data, unsigned int width,
unsigned int height, int bitmap_pad, int bytes_per_line);
void copy_image(XImage *dest, int x, int y, unsigned int w, unsigned int h);
void init_track_keycode_state(void);
void XTRAP_FakeKeyEvent_wr(Display* dpy, KeyCode key, Bool down,
unsigned long delay);
void XTestFakeKeyEvent_wr(Display* dpy, KeyCode key, Bool down,
unsigned long delay);
void XTRAP_FakeButtonEvent_wr(Display* dpy, unsigned int button, Bool is_press,
unsigned long delay);
void XTestFakeButtonEvent_wr(Display* dpy, unsigned int button, Bool is_press,
unsigned long delay);
void XTRAP_FakeMotionEvent_wr(Display* dpy, int screen, int x, int y,
unsigned long delay);
void XTestFakeMotionEvent_wr(Display* dpy, int screen, int x, int y,
unsigned long delay);
Bool XTestCompareCurrentCursorWithWindow_wr(Display* dpy, Window w);
Bool XTestCompareCursorWithWindow_wr(Display* dpy, Window w, Cursor cursor);
Bool XTestQueryExtension_wr(Display *dpy, int *ev, int *er, int *maj,
int *min);
void XTestDiscard_wr(Display *dpy);
Bool XETrapQueryExtension_wr(Display *dpy, int *ev, int *er, int *op);
int XTestGrabControl_wr(Display *dpy, Bool impervious);
int XTRAP_GrabControl_wr(Display *dpy, Bool impervious);
void disable_grabserver(Display *in_dpy, int change);
Bool XRecordQueryVersion_wr(Display *dpy, int *maj, int *min);
static void copy_raw_fb(XImage *dest, int x, int y, unsigned int w, unsigned int h);
static void upup_downdown_warning(KeyCode key, Bool down);
/*
* used in rfbGetScreen and rfbNewFramebuffer: and estimate to the number
* of bits per color, of course for some visuals, e.g. 565, the number
* is not the same for each color. This is just a sane default.
*/
int guess_bits_per_color(int bits_per_pixel) {
int bits_per_color;
/* first guess, spread them "evenly" over R, G, and B */
bits_per_color = bits_per_pixel/3;
if (bits_per_color < 1) {
bits_per_color = 1; /* 1bpp, 2bpp... */
}
/* choose safe values for usual cases: */
if (bits_per_pixel == 8) {
bits_per_color = 2;
} else if (bits_per_pixel == 15 || bits_per_pixel == 16) {
bits_per_color = 5;
} else if (bits_per_pixel == 24 || bits_per_pixel == 32) {
bits_per_color = 8;
}
return bits_per_color;
}
/*
* Kludge to interpose image gets and limit to a subset rectangle of
* the rootwin. This is the -sid option trying to work around invisible
* saveUnders menu, etc, windows. Also -clip option.
*/
#define ADJUST_ROOTSHIFT \
if (rootshift && subwin) { \
d = rootwin; \
x += off_x; \
y += off_y; \
} \
if (clipshift) { \
x += coff_x; \
y += coff_y; \
}
/*
* Wrappers for Image related X calls
*/
Status XShmGetImage_wr(Display *disp, Drawable d, XImage *image, int x, int y,
unsigned long mask) {
ADJUST_ROOTSHIFT
/* Note: the Solaris overlay stuff is all non-shm (using_shm = 0) */
#if LIBVNCSERVER_HAVE_XSHM
return XShmGetImage(disp, d, image, x, y, mask);
#else
return (Status) 0;
#endif
}
XImage *XShmCreateImage_wr(Display* disp, Visual* vis, unsigned int depth,
int format, char* data, XShmSegmentInfo* shminfo, unsigned int width,
unsigned int height) {
#if LIBVNCSERVER_HAVE_XSHM
return XShmCreateImage(disp, vis, depth, format, data, shminfo,
width, height);
#else
return (XImage *) 0;
#endif
}
Status XShmAttach_wr(Display *disp, XShmSegmentInfo *shminfo) {
#if LIBVNCSERVER_HAVE_XSHM
return XShmAttach(disp, shminfo);
#else
return (Status) 0;
#endif
}
Status XShmDetach_wr(Display *disp, XShmSegmentInfo *shminfo) {
#if LIBVNCSERVER_HAVE_XSHM
return XShmDetach(disp, shminfo);
#else
return (Status) 0;
#endif
}
Bool XShmQueryExtension_wr(Display *disp) {
#if LIBVNCSERVER_HAVE_XSHM
return XShmQueryExtension(disp);
#else
return False;
#endif
}
/* wrapper for overlay screen reading: */
XImage *xreadscreen(Display *disp, Drawable d, int x, int y,
unsigned int width, unsigned int height, Bool show_cursor) {
#ifdef SOLARIS_OVERLAY
return XReadScreen(disp, d, x, y, width, height,
show_cursor);
#else
# ifdef IRIX_OVERLAY
{ unsigned long hints = 0, hints_ret;
if (show_cursor) hints |= XRD_READ_POINTER;
return XReadDisplay(disp, d, x, y, width, height,
hints, &hints_ret);
}
# else
/* unused vars warning: */
if (disp || d || x || y || width || height || show_cursor) {}
return NULL;
# endif
#endif
}
XImage *XGetSubImage_wr(Display *disp, Drawable d, int x, int y,
unsigned int width, unsigned int height, unsigned long plane_mask,
int format, XImage *dest_image, int dest_x, int dest_y) {
ADJUST_ROOTSHIFT
if (overlay && dest_x == 0 && dest_y == 0) {
size_t size = dest_image->height * dest_image->bytes_per_line;
XImage *xi;
xi = xreadscreen(disp, d, x, y, width, height,
(Bool) overlay_cursor);
if (! xi) return NULL;
/*
* There is extra overhead from memcpy and free...
* this is not like the real XGetSubImage(). We hope
* this significant overhead is still small compared to
* the time to retrieve the fb data.
*/
memcpy(dest_image->data, xi->data, size);
XDestroyImage(xi);
return (dest_image);
}
return XGetSubImage(disp, d, x, y, width, height, plane_mask,
format, dest_image, dest_x, dest_y);
}
XImage *XGetImage_wr(Display *disp, Drawable d, int x, int y,
unsigned int width, unsigned int height, unsigned long plane_mask,
int format) {
ADJUST_ROOTSHIFT
if (overlay) {
return xreadscreen(disp, d, x, y, width, height,
(Bool) overlay_cursor);
}
return XGetImage(disp, d, x, y, width, height, plane_mask, format);
}
XImage *XCreateImage_wr(Display *disp, Visual *visual, unsigned int depth,
int format, int offset, char *data, unsigned int width,
unsigned int height, int bitmap_pad, int bytes_per_line) {
/*
* This is a kludge to get a created XImage to exactly match what
* XReadScreen returns: we noticed the rgb masks are different
* from XCreateImage with the high color visual (red mask <->
* blue mask). Note we read from the root window(!) then free
* the data.
*/
if (raw_fb) { /* raw_fb hack */
XImage *xi;
xi = (XImage *) malloc(sizeof(XImage));
memset(xi, 0, sizeof(XImage));
xi->depth = depth;
xi->bits_per_pixel = (depth == 24) ? 32 : depth;
xi->format = format;
xi->xoffset = offset;
xi->data = data;
xi->width = width;
xi->height = height;
xi->bitmap_pad = bitmap_pad;
xi->bytes_per_line = bytes_per_line ? bytes_per_line :
xi->width * xi->bits_per_pixel / 8;
return xi;
}
if (overlay) {
XImage *xi;
xi = xreadscreen(disp, window, 0, 0, width, height, False);
if (xi == NULL) {
return xi;
}
if (xi->data != NULL) {
free(xi->data);
}
xi->data = data;
return xi;
}
return XCreateImage(disp, visual, depth, format, offset, data,
width, height, bitmap_pad, bytes_per_line);
}
static void copy_raw_fb(XImage *dest, int x, int y, unsigned int w, unsigned int h) {
char *src, *dst;
unsigned int line;
int pixelsize = bpp/8;
int bpl = wdpy_x * pixelsize;
if (clipshift) {
x += coff_x;
y += coff_y;
}
if (! raw_fb_seek) {
src = raw_fb_addr + raw_fb_offset + bpl*y + pixelsize*x;
dst = dest->data;
for (line = 0; line < h; line++) {
memcpy(dst, src, w * pixelsize);
src += bpl;
dst += dest->bytes_per_line;
}
} else{
int n, len, del, sz = w * pixelsize;
off_t off = (off_t) (raw_fb_offset + bpl*y + pixelsize*x);
lseek(raw_fb_fd, off, SEEK_SET);
dst = dest->data;
for (line = 0; line < h; line++) {
len = sz;
del = 0;
while (len > 0) {
n = read(raw_fb_fd, dst + del, len);
if (n > 0) {
del += n;
len -= n;
} else if (n == 0) {
break;
} else {
/* overkill... */
if (errno != EINTR && errno != EAGAIN) {
break;
}
}
}
if (bpl > sz) {
off = (off_t) (bpl - sz);
lseek(raw_fb_fd, off, SEEK_CUR);
}
dst += dest->bytes_per_line;
}
}
}
void copy_image(XImage *dest, int x, int y, unsigned int w, unsigned int h) {
/* default (w=0, h=0) is the fill the entire XImage */
if (w < 1) {
w = dest->width;
}
if (h < 1) {
h = dest->height;
}
if (use_snapfb && snap_fb && dest != snaprect) {
char *src, *dst;
unsigned int line;
int pixelsize = bpp/8;
src = snap->data + snap->bytes_per_line*y + pixelsize*x;
dst = dest->data;
for (line = 0; line < h; line++) {
memcpy(dst, src, w * pixelsize);
src += snap->bytes_per_line;
dst += dest->bytes_per_line;
}
} else if (raw_fb) {
copy_raw_fb(dest, x, y, w, h);
} else if (using_shm && (int) w == dest->width &&
(int) h == dest->height) {
XShmGetImage_wr(dpy, window, dest, x, y, AllPlanes);
} else {
XGetSubImage_wr(dpy, window, x, y, w, h, AllPlanes,
ZPixmap, dest, 0, 0);
}
}
#define DEBUG_SKIPPED_INPUT(dbg, str) \
if (dbg) { \
rfbLog("skipped input: %s\n", str); \
}
void init_track_keycode_state(void) {
int i;
for (i=0; i<256; i++) {
keycode_state[i] = 0;
}
get_keystate(keycode_state);
}
static void upup_downdown_warning(KeyCode key, Bool down) {
if ((down ? 1:0) == keycode_state[(int) key]) {
rfbLog("XTestFakeKeyEvent: keycode=0x%x \"%s\" is *already* "
"%s\n", key, XKeysymToString(XKeycodeToKeysym(dpy, key, 0)),
down ? "down":"up");
}
}
/*
* wrappers for XTestFakeKeyEvent, etc..
* also for XTrap equivalents XESimulateXEventRequest
*/
void XTRAP_FakeKeyEvent_wr(Display* dpy, KeyCode key, Bool down,
unsigned long delay) {
if (! xtrap_present) {
DEBUG_SKIPPED_INPUT(debug_keyboard, "keyboard: no-XTRAP");
return;
}
/* unused vars warning: */
if (dpy || key || down || delay) {}
#if LIBVNCSERVER_HAVE_LIBXTRAP
XESimulateXEventRequest(trap_ctx, down ? KeyPress : KeyRelease,
key, 0, 0, 0);
if (debug_keyboard) {
upup_downdown_warning(key, down);
}
keycode_state[(int) key] = down ? 1 : 0;
#else
DEBUG_SKIPPED_INPUT(debug_keyboard, "keyboard: no-XTRAP-build");
#endif
}
void XTestFakeKeyEvent_wr(Display* dpy, KeyCode key, Bool down,
unsigned long delay) {
static int first = 1;
if (debug_keyboard) {
rfbLog("XTestFakeKeyEvent(dpy, keycode=0x%x \"%s\", %s)\n",
key, XKeysymToString(XKeycodeToKeysym(dpy, key, 0)),
down ? "down":"up");
}
if (first) {
init_track_keycode_state();
first = 0;
}
if (down) {
last_keyboard_keycode = -key;
} else {
last_keyboard_keycode = key;
}
if (xtrap_input) {
XTRAP_FakeKeyEvent_wr(dpy, key, down, delay);
return;
}
if (! xtest_present) {
DEBUG_SKIPPED_INPUT(debug_keyboard, "keyboard: no-XTEST");
return;
}
if (debug_keyboard) {
rfbLog("calling XTestFakeKeyEvent(%d, %d) %.4f\n",
key, down, dnow() - x11vnc_start);
}
#if LIBVNCSERVER_HAVE_XTEST
XTestFakeKeyEvent(dpy, key, down, delay);
if (debug_keyboard) {
upup_downdown_warning(key, down);
}
keycode_state[(int) key] = down ? 1 : 0;
#endif
}
void XTRAP_FakeButtonEvent_wr(Display* dpy, unsigned int button, Bool is_press,
unsigned long delay) {
if (! xtrap_present) {
DEBUG_SKIPPED_INPUT(debug_keyboard, "button: no-XTRAP");
return;
}
/* unused vars warning: */
if (dpy || button || is_press || delay) {}
#if LIBVNCSERVER_HAVE_LIBXTRAP
XESimulateXEventRequest(trap_ctx,
is_press ? ButtonPress : ButtonRelease, button, 0, 0, 0);
#else
DEBUG_SKIPPED_INPUT(debug_keyboard, "button: no-XTRAP-build");
#endif
}
void XTestFakeButtonEvent_wr(Display* dpy, unsigned int button, Bool is_press,
unsigned long delay) {
if (xtrap_input) {
XTRAP_FakeButtonEvent_wr(dpy, button, is_press, delay);
return;
}
if (! xtest_present) {
DEBUG_SKIPPED_INPUT(debug_keyboard, "button: no-XTEST");
return;
}
if (debug_pointer) {
rfbLog("calling XTestFakeButtonEvent(%d, %d) %.4f\n",
button, is_press, dnow() - x11vnc_start);
}
#if LIBVNCSERVER_HAVE_XTEST
XTestFakeButtonEvent(dpy, button, is_press, delay);
#endif
}
void XTRAP_FakeMotionEvent_wr(Display* dpy, int screen, int x, int y,
unsigned long delay) {
if (! xtrap_present) {
DEBUG_SKIPPED_INPUT(debug_keyboard, "motion: no-XTRAP");
return;
}
/* unused vars warning: */
if (dpy || screen || x || y || delay) {}
#if LIBVNCSERVER_HAVE_LIBXTRAP
XESimulateXEventRequest(trap_ctx, MotionNotify, 0, x, y, 0);
#else
DEBUG_SKIPPED_INPUT(debug_keyboard, "motion: no-XTRAP-build");
#endif
}
void XTestFakeMotionEvent_wr(Display* dpy, int screen, int x, int y,
unsigned long delay) {
if (xtrap_input) {
XTRAP_FakeMotionEvent_wr(dpy, screen, x, y, delay);
return;
}
if (debug_pointer) {
rfbLog("calling XTestFakeMotionEvent(%d, %d) %.4f\n",
x, y, dnow() - x11vnc_start);
}
#if LIBVNCSERVER_HAVE_XTEST
XTestFakeMotionEvent(dpy, screen, x, y, delay);
#endif
}
Bool XTestCompareCurrentCursorWithWindow_wr(Display* dpy, Window w) {
if (! xtest_present) {
return False;
}
#if LIBVNCSERVER_HAVE_XTEST
return XTestCompareCurrentCursorWithWindow(dpy, w);
#else
return False;
#endif
}
Bool XTestCompareCursorWithWindow_wr(Display* dpy, Window w, Cursor cursor) {
if (! xtest_present) {
return False;
}
#if LIBVNCSERVER_HAVE_XTEST
return XTestCompareCursorWithWindow(dpy, w, cursor);
#else
return False;
#endif
}
Bool XTestQueryExtension_wr(Display *dpy, int *ev, int *er, int *maj,
int *min) {
#if LIBVNCSERVER_HAVE_XTEST
return XTestQueryExtension(dpy, ev, er, maj, min);
#else
return False;
#endif
}
void XTestDiscard_wr(Display *dpy) {
if (! xtest_present) {
return;
}
#if LIBVNCSERVER_HAVE_XTEST
XTestDiscard(dpy);
#endif
}
Bool XETrapQueryExtension_wr(Display *dpy, int *ev, int *er, int *op) {
#if LIBVNCSERVER_HAVE_LIBXTRAP
return XETrapQueryExtension(dpy, (INT32 *)ev, (INT32 *)er,
(INT32 *)op);
#else
/* unused vars warning: */
if (dpy || ev || er || op) {}
return False;
#endif
}
int XTestGrabControl_wr(Display *dpy, Bool impervious) {
if (! xtest_present) {
return 0;
}
#if LIBVNCSERVER_HAVE_XTEST && LIBVNCSERVER_HAVE_XTESTGRABCONTROL
XTestGrabControl(dpy, impervious);
return 1;
#else
return 0;
#endif
}
int XTRAP_GrabControl_wr(Display *dpy, Bool impervious) {
if (! xtrap_present) {
/* unused vars warning: */
if (dpy || impervious) {}
return 0;
}
#if LIBVNCSERVER_HAVE_LIBXTRAP
else {
ReqFlags requests;
if (! impervious) {
if (trap_ctx) {
XEFreeTC(trap_ctx);
}
trap_ctx = NULL;
return 1;
}
if (! trap_ctx) {
trap_ctx = XECreateTC(dpy, 0, NULL);
if (! trap_ctx) {
rfbLog("DEC-XTRAP XECreateTC failed. Watch "
"out for XGrabServer from wm's\n");
return 0;
}
XEStartTrapRequest(trap_ctx);
memset(requests, 0, sizeof(requests));
BitTrue(requests, X_GrabServer);
BitTrue(requests, X_UngrabServer);
XETrapSetRequests(trap_ctx, True, requests);
XETrapSetGrabServer(trap_ctx, True);
}
return 1;
}
#endif
return 0;
}
void disable_grabserver(Display *in_dpy, int change) {
int ok = 0;
static int didmsg = 0;
if (debug_grabs) {
fprintf(stderr, "disable_grabserver/%d %.5f\n",
xserver_grabbed, dnowx());
didmsg = 0;
}
if (! xtrap_input) {
if (XTestGrabControl_wr(in_dpy, True)) {
if (change) {
XTRAP_GrabControl_wr(in_dpy, False);
}
if (! didmsg) {
rfbLog("GrabServer control via XTEST.\n");
didmsg = 1;
}
ok = 1;
} else {
if (XTRAP_GrabControl_wr(in_dpy, True)) {
ok = 1;
if (! didmsg) {
rfbLog("Using DEC-XTRAP for protection"
" from XGrabServer.\n");
didmsg = 1;
}
}
}
} else {
if (XTRAP_GrabControl_wr(in_dpy, True)) {
if (change) {
XTestGrabControl_wr(in_dpy, False);
}
if (! didmsg) {
rfbLog("GrabServer control via DEC-XTRAP.\n");
didmsg = 1;
}
ok = 1;
} else {
if (XTestGrabControl_wr(in_dpy, True)) {
ok = 1;
if (! didmsg) {
rfbLog("DEC-XTRAP XGrabServer "
"protection not available, "
"using XTEST.\n");
didmsg = 1;
}
}
}
}
if (! ok && ! didmsg) {
rfbLog("No XTEST or DEC-XTRAP protection from XGrabServer.\n");
rfbLog("Deadlock if your window manager calls XGrabServer!!\n");
}
XFlush(in_dpy);
}
Bool XRecordQueryVersion_wr(Display *dpy, int *maj, int *min) {
#if LIBVNCSERVER_HAVE_RECORD
return XRecordQueryVersion(dpy, maj, min);
#else
return False;
#endif
}

@ -0,0 +1,68 @@
#ifndef _X11VNC_XWRAPPERS_H
#define _X11VNC_XWRAPPERS_H
/* -- xwrappers.h -- */
extern int xshm_present;
extern int xtest_present;
extern int xtrap_present;
extern int xrecord_present;
extern int xkb_present;
extern int xinerama_present;
extern int keycode_state[];
extern int rootshift;
extern int clipshift;
extern int guess_bits_per_color(int bits_per_pixel);
extern Status XShmGetImage_wr(Display *disp, Drawable d, XImage *image, int x, int y,
unsigned long mask);
extern XImage *XShmCreateImage_wr(Display* disp, Visual* vis, unsigned int depth,
int format, char* data, XShmSegmentInfo* shminfo, unsigned int width,
unsigned int height);
extern Status XShmAttach_wr(Display *disp, XShmSegmentInfo *shminfo);
extern Status XShmDetach_wr(Display *disp, XShmSegmentInfo *shminfo);
extern Bool XShmQueryExtension_wr(Display *disp);
extern XImage *xreadscreen(Display *disp, Drawable d, int x, int y,
unsigned int width, unsigned int height, Bool show_cursor);
extern XImage *XGetSubImage_wr(Display *disp, Drawable d, int x, int y,
unsigned int width, unsigned int height, unsigned long plane_mask,
int format, XImage *dest_image, int dest_x, int dest_y);
extern XImage *XGetImage_wr(Display *disp, Drawable d, int x, int y,
unsigned int width, unsigned int height, unsigned long plane_mask,
int format);
extern XImage *XCreateImage_wr(Display *disp, Visual *visual, unsigned int depth,
int format, int offset, char *data, unsigned int width,
unsigned int height, int bitmap_pad, int bytes_per_line);
extern void copy_image(XImage *dest, int x, int y, unsigned int w, unsigned int h);
extern void init_track_keycode_state(void);
extern void XTRAP_FakeKeyEvent_wr(Display* dpy, KeyCode key, Bool down,
unsigned long delay);
extern void XTestFakeKeyEvent_wr(Display* dpy, KeyCode key, Bool down,
unsigned long delay);
extern void XTRAP_FakeButtonEvent_wr(Display* dpy, unsigned int button, Bool is_press,
unsigned long delay);
extern void XTestFakeButtonEvent_wr(Display* dpy, unsigned int button, Bool is_press,
unsigned long delay);
extern void XTRAP_FakeMotionEvent_wr(Display* dpy, int screen, int x, int y,
unsigned long delay);
extern void XTestFakeMotionEvent_wr(Display* dpy, int screen, int x, int y,
unsigned long delay);
extern Bool XTestCompareCurrentCursorWithWindow_wr(Display* dpy, Window w);
extern Bool XTestCompareCursorWithWindow_wr(Display* dpy, Window w, Cursor cursor);
extern Bool XTestQueryExtension_wr(Display *dpy, int *ev, int *er, int *maj,
int *min);
extern void XTestDiscard_wr(Display *dpy);
extern Bool XETrapQueryExtension_wr(Display *dpy, int *ev, int *er, int *op);
extern int XTestGrabControl_wr(Display *dpy, Bool impervious);
extern int XTRAP_GrabControl_wr(Display *dpy, Bool impervious);
extern void disable_grabserver(Display *in_dpy, int change);
extern Bool XRecordQueryVersion_wr(Display *dpy, int *maj, int *min);
#endif /* _X11VNC_XWRAPPERS_H */
Loading…
Cancel
Save