parent
def3012663
commit
71f2ec7918
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 *)¬ify_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 */
|
@ -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 */
|
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…
Reference in new issue