diff options
Diffstat (limited to 'x11vnc/x11vnc.c')
-rw-r--r-- | x11vnc/x11vnc.c | 32090 |
1 files changed, 59 insertions, 32031 deletions
diff --git a/x11vnc/x11vnc.c b/x11vnc/x11vnc.c index c25d364..70026fc 100644 --- a/x11vnc/x11vnc.c +++ b/x11vnc/x11vnc.c @@ -1,7 +1,7 @@ /* - * x11vnc.c: a VNC server for X displays. + * x11vnc: a VNC server for X displays. * - * Copyright (c) 2002-2005 Karl J. Runge <[email protected]> + * Copyright (c) 2002-2006 Karl J. Runge <[email protected]> * All rights reserved. * * This is free software; you can redistribute it and/or modify @@ -112,29614 +112,51 @@ * */ -/* - * These ' -- filename.[ch] -- ' comments represent a partial cleanup: - * they are an odd way to indicate how this huge file would be split up - * someday into multiple files. Not finished, externs and other things - * would need to be done, but it indicates a breakup, including static - * keyword for some items. - * - * The primary reason we do not break up this file is for user - * convenience: those wanting to use the latest version download a single - * file, x11vnc.c, and off they go... - */ - -/* -- x11vnc.h -- */ - -/****************************************************************************/ - -/* Standard includes and libvncserver */ - -#include <unistd.h> -#include <signal.h> -#include <sys/utsname.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 -int xtest_base_event_type = 0; - -#if LIBVNCSERVER_HAVE_LIBXTRAP -#define NEED_EVENTS -#define NEED_REPLIES -#include <X11/extensions/xtraplib.h> -#include <X11/extensions/xtraplibp.h> -XETC *trap_ctx = NULL; -#endif -int xtrap_base_event_type = 0; - -#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 - -int overlay_present = 0; - -/* - * Ditto for librandr. - * (e.g. LDFLAGS=-lXrandr before configure). -#define LIBVNCSERVER_HAVE_LIBXRANDR 1 - */ -#if LIBVNCSERVER_HAVE_LIBXRANDR -#include <X11/extensions/Xrandr.h> -#endif -int xrandr_base_event_type = 0; - - -int xfixes_present = 0; -int use_xfixes = 1; -int got_xfixes_cursor_notify = 0; -int cursor_changes = 0; -int alpha_threshold = 240; -double alpha_frac = 0.33; -int alpha_remove = 0; -int alpha_blend = 1; -int alt_arrow = 1; - -#if LIBVNCSERVER_HAVE_LIBXFIXES -#include <X11/extensions/Xfixes.h> -#endif -int xfixes_base_event_type = 0; - - -#ifndef XDAMAGE -#define XDAMAGE 1 -#endif -int use_xdamage = XDAMAGE; /* use the xdamage rects for scanline hints */ -int xdamage_present = 0; -#if LIBVNCSERVER_HAVE_LIBXDAMAGE -#include <X11/extensions/Xdamage.h> -Damage xdamage = 0; -#endif -int xdamage_base_event_type = 0; -int xdamage_max_area = 20000; /* pixels */ -double xdamage_memory = 1.0; /* in units of NSCAN */ -int xdamage_tile_count, xdamage_direct_count; -double xdamage_scheduled_mark = 0.0; -sraRegionPtr xdamage_scheduled_mark_region = NULL; - -/* date +'lastmod: %Y-%m-%d' */ -char lastmod[] = "0.7.3 lastmod: 2005-12-24"; -int hack_val = 0; - -/* X display info */ - -Display *dpy = NULL; /* the single display screen we connect to */ -int scr; -Window window, rootwin; /* polled window, root window (usu. same) */ -Visual *default_visual; /* the default visual (unless -visual) */ -int bpp, depth; -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; -XImage *fullscreen; -XImage **tile_row; /* for all possible row runs */ -XImage *fb0; -XImage *snaprect = NULL; /* for XShmGetImage (fs_factor) */ -XImage *snap = NULL; /* the full snap fb */ -XImage *raw_fb_image = NULL; /* 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 */ -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; /* our copy of the X11 fb */ -char *rfb_fb; /* 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; - -/* 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; - - 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; - -/* 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, *tile_tried, *tile_copied; -unsigned char *tile_has_xdamage_diff, *tile_row_has_xdamage_diff; - -/* 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 accepted_client = 0; -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; - -/* string for the VNC_CONNECT property */ -#define VNC_CONNECT_MAX 16384 -char vnc_connect_str[VNC_CONNECT_MAX+1]; -Atom vnc_connect_prop = None; - -struct utsname UT; - -/* scan pattern jitter from x0rfbserver */ -#define NSCAN 32 -int scanlines[NSCAN] = { - 0, 16, 8, 24, 4, 20, 12, 28, - 10, 26, 18, 2, 22, 6, 30, 14, - 1, 17, 9, 25, 7, 23, 15, 31, - 19, 3, 27, 11, 29, 13, 5, 21 -}; - - -/* function prototypes (see filename comment above) */ -int all_clients_initialized(void); -void close_all_clients(void); -void close_clients(char *); -int get_autorepeat_state(void); -int get_initial_autorepeat_state(void); -void autorepeat(int restore, int quiet); -char *bitprint(unsigned int, int); -void blackout_tiles(void); -void solid_bg(int); -void check_connect_inputs(void); -void check_gui_inputs(void); -void record_last_fb_update(void); -void check_padded_fb(void); -void clean_up_exit(int); -void clear_modifiers(int init); -void clear_keys(void); -void init_track_keycode_state(void); -void get_keystate(int *); -int copy_screen(void); -void check_black_fb(void); -void do_new_fb(int); -void install_padded_fb(char *); -void install_fake_fb(int, int, int); -void remove_fake_fb(void); - -int add_keysym(KeySym); -void delete_keycode(KeyCode, int); -void delete_added_keycodes(int); -int count_added_keycodes(void); - -double dtime(double *); -double dtime0(double *); -double dnow(void); -double dnowx(void); -double rnow(void); -double rfac(void); - -void initialize_blackouts(char *); -void initialize_blackouts_and_xinerama(void); -void initialize_clipshift(void); -void initialize_keyboard_and_pointer(void); -void initialize_allowed_input(void); -void initialize_modtweak(void); -void initialize_pointer_map(char *); -void initialize_cursors_mode(void); -void initialize_remap(char *); -void initialize_screen(int *argc, char **argv, XImage *fb); -void initialize_polling_images(void); -void initialize_signals(void); -void initialize_tiles(void); -void initialize_speeds(void); -void clean_shm(int); -void free_tiles(void); -void initialize_watch_bell(void); -void initialize_xinerama(void); -void initialize_xfixes(void); -void initialize_xdamage(void); -int valid_window(Window, XWindowAttributes *, int); -Window parent_window(Window, char**); -int xtranslate(Window, Window, int, int, int*, int*, Window*, int); -void create_xdamage_if_needed(void); -void destroy_xdamage_if_needed(void); -void mark_for_xdamage(int, int, int, int); -void mark_region_for_xdamage(sraRegionPtr); -void set_xdamage_mark(int, int, int, int); -void initialize_xrandr(void); -XImage *initialize_xdisplay_fb(void); - -void initialize_pipeinput(void); -void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client); -void pipe_keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client); - -void XTestFakeKeyEvent_wr(Display*, KeyCode, Bool, unsigned long); -void XTestFakeButtonEvent_wr(Display*, unsigned int, Bool, unsigned long); -void XTestFakeMotionEvent_wr(Display*, int, int, int, unsigned long); -int XTestGrabControl_wr(Display*, Bool); -Bool XTestCompareCurrentCursorWithWindow_wr(Display*, Window); -Bool XTestCompareCursorWithWindow_wr(Display*, Window, Cursor); -Bool XTestQueryExtension_wr(Display*, int*, int*, int*, int*); -Bool XETrapQueryExtension_wr(Display*, int*, int*, int*); -void XTestDiscard_wr(Display*); - -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; -void mark_hint(hint_t); -void mark_rect_as_modified(int x1, int y1, int x2, int y2, int force); - -enum rfbNewClientAction new_client(rfbClientPtr client); -void set_nofb_params(int); -void set_raw_fb_params(int); -void nofb_hook(rfbClientPtr client); -void pointer(int mask, int x, int y, rfbClientPtr client); -void pipe_pointer(int mask, int x, int y, rfbClientPtr client); -int check_pipeinput(void); -void cursor_position(int, int); -void do_button_mask_change(int, int); - -void parse_wireframe(void); -void parse_scroll_copyrect(void); -void parse_fixscreen(void); -void set_wirecopyrect_mode(char *); -void set_scrollcopyrect_mode(char *); -void initialize_scroll_matches(void); -void initialize_scroll_term(void); -void initialize_max_keyrepeat(void); -void initialize_scroll_keys(void); -int try_copyrect(Window, int, int, int, int, int, int, int *, sraRegionPtr, - double); -void do_copyregion(sraRegionPtr, int, int); -int direct_fb_copy(int, int, int, int, int); -int get_wm_frame_pos(int *, int *, int *, int *, int *, int *, - Window *, Window *); -Window descend_pointer(int, Window, char *, int); -int near_wm_edge(int, int, int, int, int, int); -int near_scrollbar_edge(int, int, int, int, int, int); -void read_vnc_connect_prop(void); -void set_vnc_connect_prop(char *); -void fb_push(void); -#define FB_COPY 0x1 -#define FB_MOD 0x2 -#define FB_REQ 0x4 -void fb_push_wait(double, int); -char *process_remote_cmd(char *, int); -void rfbPE(long); -void rfbCFD(long); -int scan_for_updates(int); -void set_colormap(int); -void set_offset(void); -void set_rfb_cursor(int); -void set_visual(char *vstring); -int set_cursor(int, int, int); -void setup_cursors(void); -void setup_cursors_and_push(void); -void first_cursor(void); -rfbCursorPtr pixels2curs(unsigned long *, int, int, int, int, int); -void set_no_cursor(void); -void set_cursor_was_changed(rfbScreenInfoPtr); -void set_cursor_was_moved(rfbScreenInfoPtr); -int get_which_cursor(void); -int get_xfixes_cursor(int); - -void disable_cursor_shape_updates(rfbScreenInfoPtr); -void restore_cursor_shape_updates(rfbScreenInfoPtr); -int new_fb_size_clients(rfbScreenInfoPtr); -void get_client_regions(int *, int *, int *, int *); - -void shm_clean(XShmSegmentInfo *, XImage *); -void shm_delete(XShmSegmentInfo *); - -int check_x11_pointer(void); -void check_bell_event(void); -void check_xevents(void); -char *this_host(void); -void set_vnc_desktop_name(void); - -char *short_kmb(char *); - -char **create_str_list(char *); -int match_str_list(char *, char **); - -int link_rate(int *, int *); -int get_cmp_rate(void); -int get_raw_rate(void); -int get_read_rate(void); -int get_net_rate(void); -int get_net_latency(void); -int get_latency(void); -void measure_send_rates(int); -int fb_update_sent(int *); -void snapshot_stack_list(int, double); - -int get_remote_port(int sock); -int get_local_port(int sock); -char *get_remote_host(int sock); -char *get_local_host(int sock); - -void xcut_receive(char *text, int len, rfbClientPtr client); - -void parse_scale_string(char *, double *, int *, int *, - int *, int *, int *, int *, int *); -void scale_rect(double, int, int, int, - char *, int, char *, int, - int, int, int, int, int, int, int, int, int); -int scale_round(int, double); - -void zero_fb(int, int, int, int); -void push_black_screen(int); -void push_sleep(int); -void refresh_screen(int); - -int tray_embed(Window, int); -int tray_manager_running(Display *, Window *); - -/* -- options.h -- */ -/* - * variables for the command line options - */ -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 */ - -#define LATENCY0 20 /* 20ms */ -#define NETRATE0 20 /* 20KB/sec */ -char *speeds_str = NULL; /* -speeds TBD */ -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; -enum { - LR_UNSET = 0, - LR_UNKNOWN, - LR_DIALUP, - LR_BROADBAND, - LR_LAN -}; - - -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 *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 */ -char *gui_geometry = NULL; - -int icon_mode = 0; /* hack for -gui tray */ -int icon_in_tray = 0; -char *icon_mode_file = NULL; -char *icon_mode_params = NULL; -char *icon_mode_embed_id = NULL; -char *icon_mode_font = NULL; -FILE *icon_mode_fh = NULL; -#define ICON_MODE_SOCKS 16 -int icon_mode_socks[ICON_MODE_SOCKS]; - -int tray_manager_ok = 0; -Window tray_request = None; -Window tray_window = None; -int tray_unembed = 0; - -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 */ -int xrandr_present = 0; -int xrandr_width = -1; -int xrandr_height = -1; -int xrandr_rotation = -1; -Time xrandr_timestamp = 0; -Time xrandr_cfg_time = 0; -char *xrandr_mode = NULL; -char *pad_geometry = NULL; -time_t pad_geometry_time; -int use_snapfb = 0; - -Display *rdpy_data = NULL; /* Data connection for RECORD */ -Display *rdpy_ctrl = NULL; /* Control connection for RECORD */ -int use_xrecord = 0; -int noxrecord = 0; - -Display *gdpy_data = NULL; /* Ditto for GrabServer watcher */ -Display *gdpy_ctrl = NULL; -int xserver_grabbed = 0; - -/* XXX CHECK BEFORE RELEASE */ -int grab_buster = 0; -int grab_buster_delay = 20; -int sync_tod_delay = 3; -pid_t grab_buster_pid = 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 */ -#ifndef WIREFRAME_PARMS -#define WIREFRAME_PARMS "0xff,3,0,32+8+8+8,all,0.15+0.30+5.0+0.125" -#endif -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; - -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; -winattr_t *stack_list = NULL; -int stack_list_len = 0; -int stack_list_num = 0; -#if 0 -winattr_t *stack_clip = NULL; -int stack_clip_len = 0; -int stack_clip_num = 0; -#endif - -/* T+B+L+R,tkey+presist_key,tmouse+persist_mouse */ -#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 -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; -int pointer_queued_sent = 0; - -#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; -enum scroll_types { - SCR_NONE = 0, - SCR_MOUSE, - SCR_KEY, - SCR_FAIL, - SCR_SUCCESS -}; -int last_scroll_type = SCR_NONE; - -char **scroll_good_all = NULL; -char **scroll_good_key = NULL; -char **scroll_good_mouse = NULL; -char *scroll_good_str = NULL; -char *scroll_good_str0 = -/* "##Firefox-bin," */ -/* "##Gnome-terminal," */ -/* "##XTerm", */ - "##Nomatch" -; - -char **scroll_skip_all = NULL; -char **scroll_skip_key = NULL; -char **scroll_skip_mouse = NULL; -char *scroll_skip_str = NULL; -char *scroll_skip_str0 = -/* "##Konsole," * no problems, known heuristics do not work */ - "##Soffice.bin," /* big problems, no clips, scrolls outside area */ - "##StarOffice" -; - -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 -#define POINTER_MODE_NOFB 2 -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; - -int xshm_present = 0; -int xtest_present = 0; -int xtrap_present = 0; -int xrecord_present = 0; -int xkb_present = 0; -int xinerama_present = 0; - -/* 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; - -/* 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; - -/* threaded vs. non-threaded (default) */ -#if LIBVNCSERVER_X11VNC_THREADED && ! defined(X11VNC_THREADED) -#define X11VNC_THREADED -#endif - -#if LIBVNCSERVER_HAVE_LIBPTHREAD && defined(X11VNC_THREADED) - int use_threads = 1; -#else - int use_threads = 0; -#endif - - -/* -- util.h -- */ - -#define NONUL(x) ((x) ? (x) : "") - -/* XXX usleep(3) is not thread safe on some older systems... */ -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. - */ -MUTEX(x11Mutex); -#define X_INIT INIT_MUTEX(x11Mutex) -#if 1 -#define X_LOCK LOCK(x11Mutex) -#define X_UNLOCK UNLOCK(x11Mutex) -#else -int hxl = 0; -#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 - -MUTEX(scrollMutex); -#define SCR_LOCK if (use_threads) {LOCK(scrollMutex);} -#define SCR_UNLOCK if (use_threads) {UNLOCK(scrollMutex);} -#define SCR_INIT INIT_MUTEX(scrollMutex) - -/* -- util.c -- */ - -/* - * 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; -} - -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); -} - -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 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; - } -} - -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")); - } -} - -/* -- user.c -- */ - -int switch_user(char *, int); -int switch_user_env(uid_t, char*, char *, int); -void try_to_switch_users(void); -char *guess_desktop(void); - -/* tasks for after we switch */ -void switch_user_task_dummy(void) { - ; /* dummy does nothing */ -} -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 */ -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; -} - -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; -} - -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 -} - -int try_user_and_display(uid_t, char*); - -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); - } -} - -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; -} - -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; - } -} - -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; -} - -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); -} - -/* -- inet.c -- */ -/* - * Simple utility to map host name to dotted IP address. Ignores aliases. - * Up to caller to free returned string. - */ -char *host2ip(char *host) { - struct hostent *hp; - struct sockaddr_in addr; - char *str; - - 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; -} - -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); -} - -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; -} - -/* -- ximage.c -- */ - -/* - * 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. - */ -int rootshift = 0; -int clipshift = 0; - -#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); -} - -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); \ - } - -int keycode_state[256]; - -void init_track_keycode_state(void) { - int i; - for (i=0; i<256; i++) { - keycode_state[i] = 0; - } - get_keystate(keycode_state); -} - -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 -} - -#if LIBVNCSERVER_HAVE_RECORD -XRecordRange *rr_CA = NULL; -XRecordRange *rr_CW = NULL; -XRecordRange *rr_GS = NULL; -XRecordRange *rr_scroll[10]; -XRecordContext rc_scroll; -XRecordClientSpec rcs_scroll; -XRecordRange *rr_grab[10]; -XRecordContext rc_grab; -XRecordClientSpec rcs_grab; - -void record_grab(XPointer, XRecordInterceptData *); -#endif - -int xrecording = 0; -int xrecord_set_by_keys = 0; -int xrecord_set_by_mouse = 0; -Window xrecord_focus_window = None; -Window xrecord_wm_window = None; -Window xrecord_ptr_window = None; -KeySym xrecord_keysym = NoSymbol; -#define NAMEINFO 2048 -char xrecord_name_info[NAMEINFO]; - -char *xerror_string(XErrorEvent *error); -int trap_record_xerror(Display *, XErrorEvent *); -int trapped_record_xerror; -XErrorEvent *trapped_record_xerror_event; - -void xrecord_grabserver(int start) { - XErrorHandler old_handler = NULL; - int rc; - - if (debug_grabs) { - fprintf(stderr, "xrecord_grabserver%d/%d %.5f\n", - xserver_grabbed, start, dnowx()); - } - - if (! gdpy_ctrl || ! gdpy_data) { - return; - } -#if LIBVNCSERVER_HAVE_RECORD - if (!start) { - if (! rc_grab) { - return; - } - XRecordDisableContext(gdpy_ctrl, rc_grab); - XRecordFreeContext(gdpy_ctrl, rc_grab); - XFlush(gdpy_ctrl); - rc_grab = 0; - return; - } - - xserver_grabbed = 0; - - rr_grab[0] = rr_GS; - rcs_grab = XRecordAllClients; - - rc_grab = XRecordCreateContext(gdpy_ctrl, 0, &rcs_grab, 1, rr_grab, 1); - trapped_record_xerror = 0; - old_handler = XSetErrorHandler(trap_record_xerror); - - XSync(gdpy_ctrl, True); - - if (! rc_grab || trapped_record_xerror) { - XCloseDisplay(gdpy_ctrl); - XCloseDisplay(gdpy_data); - gdpy_ctrl = NULL; - gdpy_data = NULL; - XSetErrorHandler(old_handler); - return; - } - rc = XRecordEnableContextAsync(gdpy_data, rc_grab, record_grab, NULL); - if (!rc || trapped_record_xerror) { - XCloseDisplay(gdpy_ctrl); - XCloseDisplay(gdpy_data); - gdpy_ctrl = NULL; - gdpy_data = NULL; - XSetErrorHandler(old_handler); - return; - } - XSetErrorHandler(old_handler); - XFlush(gdpy_data); -#endif - if (debug_grabs) { - fprintf(stderr, "xrecord_grabserver-done: %.5f\n", dnowx()); - } -} - -void initialize_xrecord(void) { - use_xrecord = 0; - if (! xrecord_present) { - return; - } - if (nofb) { - return; - } - if (noxrecord) { - return; - } -#if LIBVNCSERVER_HAVE_RECORD - - if (rr_CA) XFree(rr_CA); - if (rr_CW) XFree(rr_CW); - if (rr_GS) XFree(rr_GS); - - rr_CA = XRecordAllocRange(); - rr_CW = XRecordAllocRange(); - rr_GS = XRecordAllocRange(); - if (!rr_CA || !rr_CW || !rr_GS) { - return; - } - /* protocol request ranges: */ - rr_CA->core_requests.first = X_CopyArea; - rr_CA->core_requests.last = X_CopyArea; - - rr_CW->core_requests.first = X_ConfigureWindow; - rr_CW->core_requests.last = X_ConfigureWindow; - - rr_GS->core_requests.first = X_GrabServer; - rr_GS->core_requests.last = X_UngrabServer; - - X_LOCK; - /* open a 2nd control connection to DISPLAY: */ - if (rdpy_data) { - XCloseDisplay(rdpy_data); - rdpy_data = NULL; - } - if (rdpy_ctrl) { - XCloseDisplay(rdpy_ctrl); - rdpy_ctrl = NULL; - } - rdpy_ctrl = XOpenDisplay(DisplayString(dpy)); - XSync(dpy, True); - XSync(rdpy_ctrl, True); - /* open datalink connection to DISPLAY: */ - rdpy_data = XOpenDisplay(DisplayString(dpy)); - if (!rdpy_ctrl || ! rdpy_data) { - X_UNLOCK; - return; - } - disable_grabserver(rdpy_ctrl, 0); - disable_grabserver(rdpy_data, 0); - - use_xrecord = 1; - - /* - * now set up the GrabServer watcher. We get GrabServer - * deadlock in XRecordCreateContext() even with XTestGrabServer - * in place, why? Not sure, so we manually watch for grabs... - */ - if (gdpy_data) { - XCloseDisplay(gdpy_data); - gdpy_data = NULL; - } - if (gdpy_ctrl) { - XCloseDisplay(gdpy_ctrl); - gdpy_ctrl = NULL; - } - xserver_grabbed = 0; - - gdpy_ctrl = XOpenDisplay(DisplayString(dpy)); - XSync(dpy, True); - XSync(gdpy_ctrl, True); - gdpy_data = XOpenDisplay(DisplayString(dpy)); - if (gdpy_ctrl && gdpy_data) { - disable_grabserver(gdpy_ctrl, 0); - disable_grabserver(gdpy_data, 0); - xrecord_grabserver(1); - } - X_UNLOCK; -#endif -} - -void shutdown_xrecord(void) { -#if LIBVNCSERVER_HAVE_RECORD - - if (debug_grabs) { - fprintf(stderr, "shutdown_xrecord%d %.5f\n", - xserver_grabbed, dnowx()); - } - - if (rr_CA) XFree(rr_CA); - if (rr_CW) XFree(rr_CW); - if (rr_GS) XFree(rr_GS); - - rr_CA = NULL; - rr_CW = NULL; - rr_GS = NULL; - - X_LOCK; - if (rdpy_ctrl && rc_scroll) { - XRecordDisableContext(rdpy_ctrl, rc_scroll); - XRecordFreeContext(rdpy_ctrl, rc_scroll); - XSync(rdpy_ctrl, False); - rc_scroll = 0; - } - - if (gdpy_ctrl && rc_grab) { - XRecordDisableContext(gdpy_ctrl, rc_grab); - XRecordFreeContext(gdpy_ctrl, rc_grab); - XSync(gdpy_ctrl, False); - rc_grab = 0; - } - - if (rdpy_data) { - XCloseDisplay(rdpy_data); - rdpy_data = NULL; - } - if (rdpy_ctrl) { - XCloseDisplay(rdpy_ctrl); - rdpy_ctrl = NULL; - } - if (gdpy_data) { - XCloseDisplay(gdpy_data); - gdpy_data = NULL; - } - if (gdpy_ctrl) { - XCloseDisplay(gdpy_ctrl); - gdpy_ctrl = NULL; - } - xserver_grabbed = 0; - X_UNLOCK; -#endif - use_xrecord = 0; - - if (debug_grabs) { - fprintf(stderr, "shutdown_xrecord-done: %.5f\n", dnowx()); - } -} - -int xrecord_skip_keysym(rfbKeySym keysym) { - KeySym sym = (KeySym) keysym; - int ok = -1, matched = 0; - - if (scroll_key_list) { - int k, exclude = 0; - if (scroll_key_list[0]) { - exclude = 1; - } - k = 1; - while (scroll_key_list[k] != NoSymbol) { - if (scroll_key_list[k++] == sym) { - matched = 1; - break; - } - } - if (exclude) { - if (matched) { - return 1; - } else { - ok = 1; - } - } else { - if (matched) { - ok = 1; - } else { - ok = 0; - } - } - } - if (ok == 1) { - return 0; - } else if (ok == 0) { - return 1; - } - - /* apply various heuristics: */ - - if (IsModifierKey(sym)) { - /* Shift, Control, etc, usu. generate no scrolls */ - return 1; - } - if (sym == XK_space && scroll_term) { - /* space in a terminal is usu. full page... */ - Window win; - static Window prev_top = None; - int size = 256; - static char name[256]; - - X_LOCK; - win = query_pointer(rootwin); - X_UNLOCK; - if (win != None && win != rootwin) { - if (prev_top != None && win == prev_top) { - ; /* use cached result */ - } else { - prev_top = win; - X_LOCK; - win = descend_pointer(6, win, name, size); - X_UNLOCK; - } - if (match_str_list(name, scroll_term)) { - return 1; - } - } - } - - /* TBD use typing_rate() so */ - return 0; -} - -int xrecord_skip_button(int new, int old) { - /* unused vars warning: */ - if (new || old) {} - - return 0; -} - -int xrecord_vi_scroll_keysym(rfbKeySym keysym) { - KeySym sym = (KeySym) keysym; - if (sym == XK_J || sym == XK_j || sym == XK_K || sym == XK_k) { - return 1; /* vi */ - } - if (sym == XK_D || sym == XK_d || sym == XK_U || sym == XK_u) { - return 1; /* Ctrl-d/u */ - } - if (sym == XK_Z || sym == XK_z) { - return 1; /* zz, zt, zb .. */ - } - return 0; -} - -int xrecord_emacs_scroll_keysym(rfbKeySym keysym) { - KeySym sym = (KeySym) keysym; - if (sym == XK_N || sym == XK_n || sym == XK_P || sym == XK_p) { - return 1; /* emacs */ - } - /* Must be some more ... */ - return 0; -} - -int xrecord_scroll_keysym(rfbKeySym keysym) { - KeySym sym = (KeySym) keysym; - /* X11/keysymdef.h */ - - if (sym == XK_Return || sym == XK_KP_Enter || sym == XK_Linefeed) { - return 1; /* Enter */ - } - if (sym==XK_Up || sym==XK_KP_Up || sym==XK_Down || sym==XK_KP_Down) { - return 1; /* U/D arrows */ - } - if (sym == XK_Left || sym == XK_KP_Left || sym == XK_Right || - sym == XK_KP_Right) { - return 1; /* L/R arrows */ - } - if (xrecord_vi_scroll_keysym(keysym)) { - return 1; - } - if (xrecord_emacs_scroll_keysym(keysym)) { - return 1; - } - return 0; -} - -#define SCR_ATTR_CACHE 8 -winattr_t scr_attr_cache[SCR_ATTR_CACHE]; -double attr_cache_max_age = 1.5; - -int lookup_attr_cache(Window win, int *cache_index, int *next_index) { - double now, t, oldest; - int i, old_index = -1, count = 0; - Window cwin; - - *cache_index = -1; - *next_index = -1; - - if (win == None) { - return 0; - } - if (attr_cache_max_age == 0.0) { - return 0; - } - - dtime0(&now); - for (i=0; i < SCR_ATTR_CACHE; i++) { - - cwin = scr_attr_cache[i].win; - t = scr_attr_cache[i].time; - - if (now > t + attr_cache_max_age) { - /* expire it even if it is the one we want */ - scr_attr_cache[i].win = cwin = None; - scr_attr_cache[i].fetched = 0; - scr_attr_cache[i].valid = 0; - } - - if (*next_index == -1 && cwin == None) { - *next_index = i; - } - if (*next_index == -1) { - /* record oldest */ - if (old_index == -1 || t < oldest) { - oldest = t; - old_index = i; - } - } - if (cwin != None) { - count++; - } - if (cwin == win) { - if (*cache_index == -1) { - *cache_index = i; - } else { - /* remove dups */ - scr_attr_cache[i].win = None; - scr_attr_cache[i].fetched = 0; - scr_attr_cache[i].valid = 0; - } - } - } - if (*next_index == -1) { - *next_index = old_index; - } - -if (0) fprintf(stderr, "lookup_attr_cache count: %d\n", count); - if (*cache_index != -1) { - return 1; - } else { - return 0; - } -} - - -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; - -#define SCR_EV_MAX 128 -scroll_event_t scr_ev[SCR_EV_MAX]; -int scr_ev_cnt = 0; - -XID xrecord_seq = 0; -double xrecord_start = 0.0; - -#if LIBVNCSERVER_HAVE_RECORD -void record_CA(XPointer ptr, XRecordInterceptData *rec_data) { - xCopyAreaReq *req; - Window src = None, dst = None, c; - XWindowAttributes attr; - int src_x, src_y, dst_x, dst_y, rx, ry; - int good = 1, dx, dy, k=0, i; - unsigned int w, h; - int dba = 0, db = debug_scroll; - int cache_index, next_index, valid; - - if (dba || db) { - if (rec_data->category == XRecordFromClient) { - req = (xCopyAreaReq *) rec_data->data; - if (req->reqType == X_CopyArea) { - src = req->srcDrawable; - dst = req->dstDrawable; - } - } - } - -if (dba || db > 1) fprintf(stderr, "record_CA-%d id_base: 0x%lx ptr: 0x%lx " - "seq: 0x%lx rc: 0x%lx cat: %d swapped: %d 0x%lx/0x%lx\n", k++, - rec_data->id_base, (unsigned long) ptr, xrecord_seq, rc_scroll, - rec_data->category, rec_data->client_swapped, src, dst); - - if (! xrecording) { - return; - } -if (db > 1) fprintf(stderr, "record_CA-%d\n", k++); - - if (rec_data->id_base == 0) { - return; - } -if (db > 1) fprintf(stderr, "record_CA-%d\n", k++); - - if ((XID) ptr != xrecord_seq) { - return; - } -if (db > 1) fprintf(stderr, "record_CA-%d\n", k++); - - if (rec_data->category != XRecordFromClient) { - return; - } -if (db > 1) fprintf(stderr, "record_CA-%d\n", k++); - - req = (xCopyAreaReq *) rec_data->data; - - if (req->reqType != X_CopyArea) { - return; - } -if (db > 1) fprintf(stderr, "record_CA-%d\n", k++); - -/* - -xterm, gnome-terminal, others. - -Note we miss the X_ImageText8 that clears the block cursor. So there is a -short period of time with a painting error: two cursors, one above the other. - - X_ImageText8 - draw: 0x8c00017 nChars: 1, gc: 0x8c00013, x: 101, y: 585, chars=' ' - X_ClearArea - window: 0x8c00018, x: 2, y: 217, w: 10, h: 5 - X_FillPoly - draw: 0x8c00018 gc: 0x8c0000a, shape: 0, coordMode: 0, - X_FillPoly - draw: 0x8c00018 gc: 0x8c0000b, shape: 0, coordMode: 0, - X_CopyArea - src: 0x8c00017, dst: 0x8c00017, gc: 0x8c00013, srcX: 17, srcY: 15, dstX: 17, dstY: 2, w: 480, h: 572 - X_ChangeWindowAttributes - X_ClearArea - window: 0x8c00017, x: 17, y: 574, w: 480, h: 13 - X_ChangeWindowAttributes - - */ - - src = req->srcDrawable; - dst = req->dstDrawable; - src_x = req->srcX; - src_y = req->srcY; - dst_x = req->dstX; - dst_y = req->dstY; - w = req->width; - h = req->height; - - if (w*h < (unsigned int) scrollcopyrect_min_area) { - good = 0; - } else if (!src || !dst) { - good = 0; - } else if (src != dst) { - good = 0; - } else if (scr_ev_cnt >= SCR_EV_MAX) { - good = 0; - } - - dx = dst_x - src_x; - dy = dst_y - src_y; - - if (dx != 0 && dy != 0) { - good = 0; - } - - if (! good) { - return; - } -if (db > 1) fprintf(stderr, "record_CA-%d\n", k++); - - /* - * after all of the above succeeds, now contact X server. - * we try to get away with some caching here. - */ - if (lookup_attr_cache(src, &cache_index, &next_index)) { - i = cache_index; - attr.x = scr_attr_cache[i].x; - attr.y = scr_attr_cache[i].y; - attr.width = scr_attr_cache[i].width; - attr.height = scr_attr_cache[i].height; - attr.map_state = scr_attr_cache[i].map_state; - rx = scr_attr_cache[i].rx; - ry = scr_attr_cache[i].ry; - valid = scr_attr_cache[i].valid; - - } else { - valid = valid_window(src, &attr, 1); - - if (valid) { - if (!xtranslate(src, rootwin, 0, 0, &rx, &ry, &c, 1)) { - valid = 0; - } - } - if (next_index >= 0) { - i = next_index; - scr_attr_cache[i].win = src; - scr_attr_cache[i].fetched = 1; - scr_attr_cache[i].valid = valid; - scr_attr_cache[i].time = dnow(); - if (valid) { - scr_attr_cache[i].x = attr.x; - scr_attr_cache[i].y = attr.y; - scr_attr_cache[i].width = attr.width; - scr_attr_cache[i].height = attr.height; - scr_attr_cache[i].depth = attr.depth; - scr_attr_cache[i].class = attr.class; - scr_attr_cache[i].backing_store = - attr.backing_store; - scr_attr_cache[i].map_state = attr.map_state; - - scr_attr_cache[i].rx = rx; - scr_attr_cache[i].ry = ry; - } - } - } - - if (! valid) { - return; - } -if (db > 1) fprintf(stderr, "record_CA-%d\n", k++); - - if (attr.map_state != IsViewable) { - return; - } - - -if (0 || dba || db) { - double st, dt; - st = (double) rec_data->server_time/1000.0; - dt = (dnow() - servertime_diff) - st; - fprintf(stderr, "record_CA-%d *FOUND_SCROLL: src: 0x%lx dx: %d dy: %d " - "x: %d y: %d w: %d h: %d st: %.4f %.4f %.4f\n", k++, src, dx, dy, - src_x, src_y, w, h, st, dt, dnow() - x11vnc_start); -} - - i = scr_ev_cnt; - - scr_ev[i].win = src; - scr_ev[i].frame = None; - scr_ev[i].dx = dx; - scr_ev[i].dy = dy; - scr_ev[i].x = rx + dst_x; - scr_ev[i].y = ry + dst_y; - scr_ev[i].w = w; - scr_ev[i].h = h; - scr_ev[i].t = ((double) rec_data->server_time)/1000.0; - scr_ev[i].win_x = rx; - scr_ev[i].win_y = ry; - scr_ev[i].win_w = attr.width; - scr_ev[i].win_h = attr.height; - scr_ev[i].new_x = 0; - scr_ev[i].new_y = 0; - scr_ev[i].new_w = 0; - scr_ev[i].new_h = 0; - - if (dx == 0) { - if (dy > 0) { - scr_ev[i].new_x = rx + src_x; - scr_ev[i].new_y = ry + src_y; - scr_ev[i].new_w = w; - scr_ev[i].new_h = dy; - } else { - scr_ev[i].new_x = rx + src_x; - scr_ev[i].new_y = ry + dst_y + h; - scr_ev[i].new_w = w; - scr_ev[i].new_h = -dy; - } - } else if (dy == 0) { - if (dx > 0) { - scr_ev[i].new_x = rx + src_x; - scr_ev[i].new_y = rx + src_y; - scr_ev[i].new_w = dx; - scr_ev[i].new_h = h; - } else { - scr_ev[i].new_x = rx + dst_x + w; - scr_ev[i].new_y = ry + src_y; - scr_ev[i].new_w = -dx; - scr_ev[i].new_h = h; - } - } - - scr_ev_cnt++; -} - -typedef struct cw_event { - Window win; - int x, y, w, h; -} cw_event_t; - -#define MAX_CW 128 -cw_event_t cw_events[MAX_CW]; - -void record_CW(XPointer ptr, XRecordInterceptData *rec_data) { - xConfigureWindowReq *req; - Window win = None, c; - Window src = None, dst = None; - XWindowAttributes attr; - int absent = 0x100000; - int src_x, src_y, dst_x, dst_y, rx, ry; - int good = 1, dx, dy, k=0, i, j, match, list[3]; - int f_x, f_y, f_w, f_h; - int x, y, w, h; - int x0, y0, w0, h0, x1, y1, w1, h1, x2, y2, w2, h2; - static int index = 0; - unsigned int vals[4]; - unsigned tmask; - char *data; - int dba = 0, db = debug_scroll; - int cache_index, next_index, valid; - - if (db) { - if (rec_data->category == XRecordFromClient) { - req = (xConfigureWindowReq *) rec_data->data; - if (req->reqType == X_ConfigureWindow) { - src = req->window; - } - } - } - -if (dba || db > 1) fprintf(stderr, "record_CW-%d id_base: 0x%lx ptr: 0x%lx " - "seq: 0x%lx rc: 0x%lx cat: %d swapped: %d 0x%lx/0x%lx\n", k++, - rec_data->id_base, (unsigned long) ptr, xrecord_seq, rc_scroll, - rec_data->category, rec_data->client_swapped, src, dst); - - - if (! xrecording) { - return; - } -if (db > 1) fprintf(stderr, "record_CW-%d\n", k++); - - if ((XID) ptr != xrecord_seq) { - return; - } -if (db > 1) fprintf(stderr, "record_CW-%d\n", k++); - - if (rec_data->id_base == 0) { - return; - } -if (db > 1) fprintf(stderr, "record_CW-%d\n", k++); - - if (rec_data->category == XRecordStartOfData) { - index = 0; - return; - } -if (db > 1) fprintf(stderr, "record_CW-%d\n", k++); - - if (rec_data->category != XRecordFromClient) { - return; - } -if (db > 1) fprintf(stderr, "record_CW-%d\n", k++); - - if (rec_data->client_swapped) { - return; - } -if (db > 1) fprintf(stderr, "record_CW-%d\n", k++); - - req = (xConfigureWindowReq *) rec_data->data; - - if (req->reqType != X_ConfigureWindow) { - return; - } -if (db > 1) fprintf(stderr, "record_CW-%d\n", k++); - - tmask = req->mask; - - tmask &= ~CWX; - tmask &= ~CWY; - tmask &= ~CWWidth; - tmask &= ~CWHeight; - - if (tmask) { - /* require no more than these 4 flags */ - return; - } -if (db > 1) fprintf(stderr, "record_CW-%d\n", k++); - - f_x = req->mask & CWX; - f_y = req->mask & CWY; - f_w = req->mask & CWWidth; - f_h = req->mask & CWHeight; - - if (! f_x || ! f_y) { - if (f_w && f_h) { - ; /* netscape 4.x style */ - } else { - return; - } - } -if (db > 1) fprintf(stderr, "record_CW-%d\n", k++); - - if ( (f_w && !f_h) || (!f_w && f_h) ) { - return; - } -if (db > 1) fprintf(stderr, "record_CW-%d\n", k++); - - for (i=0; i<4; i++) { - vals[i] = 0; - } - - data = (char *)req; - data += sz_xConfigureWindowReq; - - for (i=0; i<req->length; i++) { - unsigned int v; - /* - * We use unsigned int for the values. There were - * some crashes on 64bit machines with unsigned longs. - * Need to check that X protocol sends 32bit values. - */ - v = *( (unsigned int *) data); -if (db > 1) fprintf(stderr, " vals[%d] 0x%x/%d\n", i, v, v); - vals[i] = v; - data += sizeof(unsigned int); - } - - if (index >= MAX_CW) { - int i, j; - - /* FIXME, circular, etc. */ - for (i=0; i<2; i++) { - j = MAX_CW - 2 + i; - cw_events[i].win = cw_events[j].win; - cw_events[i].x = cw_events[j].x; - cw_events[i].y = cw_events[j].y; - cw_events[i].w = cw_events[j].w; - cw_events[i].h = cw_events[j].h; - } - index = 2; - } - - if (! f_x && ! f_y) { - /* netscape 4.x style CWWidth,CWHeight */ - vals[2] = vals[0]; - vals[3] = vals[1]; - vals[0] = 0; - vals[1] = 0; - } - - cw_events[index].win = req->window; - - if (! f_x) { - cw_events[index].x = absent; - } else { - cw_events[index].x = (int) vals[0]; - } - if (! f_y) { - cw_events[index].y = absent; - } else { - cw_events[index].y = (int) vals[1]; - } - - if (! f_w) { - cw_events[index].w = absent; - } else { - cw_events[index].w = (int) vals[2]; - } - if (! f_h) { - cw_events[index].h = absent; - } else { - cw_events[index].h = (int) vals[3]; - } - - x = cw_events[index].x; - y = cw_events[index].y; - w = cw_events[index].w; - h = cw_events[index].h; - win = cw_events[index].win; - -if (dba || db) fprintf(stderr, " record_CW ind: %d win: 0x%lx x: %d y: %d w: %d h: %d\n", - index, win, x, y, w, h); - - index++; - - if (index < 3) { - good = 0; - } else if (w != absent && h != absent && - w*h < scrollcopyrect_min_area) { - good = 0; - } - - if (! good) { - return; - } -if (db > 1) fprintf(stderr, "record_CW-%d\n", k++); - - match = 0; - for (j=index - 1; j >= 0; j--) { - if (cw_events[j].win == win) { - list[match++] = j; - } - if (match >= 3) { - break; - } - } - - if (match != 3) { - return; - } -if (db > 1) fprintf(stderr, "record_CW-%d\n", k++); - -/* - -Mozilla: - -Up arrow: window moves down a bit (dy > 0): - - X_ConfigureWindow - length: 7, window: 0x2e000cd, mask: 0xf, v0 0, v1 -18, v2 760, v3 906, v4 327692, v5 48234701, v6 3, - CW-mask: CWX,CWY,CWWidth,CWHeight, - X_ConfigureWindow - length: 5, window: 0x2e000cd, mask: 0x3, v0 0, v1 0, v2 506636, v3 48234701, v4 48234511, - CW-mask: CWX,CWY, - X_ConfigureWindow - length: 7, window: 0x2e000cd, mask: 0xf, v0 0, v1 0, v2 760, v3 888, v4 65579, v5 0, v6 108009, - CW-mask: CWX,CWY,CWWidth,CWHeight, - -Down arrow: window moves up a bit (dy < 0): - - X_ConfigureWindow - length: 7, window: 0x2e000cd, mask: 0xf, v0 0, v1 0, v2 760, v3 906, v4 327692, v5 48234701, v6 262147, - CW-mask: CWX,CWY,CWWidth,CWHeight, - X_ConfigureWindow - length: 5, window: 0x2e000cd, mask: 0x3, v0 0, v1 -18, v2 506636, v3 48234701, v4 48234511, - CW-mask: CWX,CWY, - X_ConfigureWindow - length: 7, window: 0x2e000cd, mask: 0xf, v0 0, v1 0, v2 760, v3 888, v4 96555, v5 48265642, v6 48265262, - CW-mask: CWX,CWY,CWWidth,CWHeight, - - -Netscape 4.x - -Up arrow: -71.76142 0.01984 X_ConfigureWindow - length: 7, window: 0x9800488, mask: 0xf, v0 0, v1 -15, v2 785, v3 882, v4 327692, v5 159384712, v6 1769484, - CW-mask: CWX,CWY,CWWidth,CWHeight, -71.76153 0.00011 X_ConfigureWindow - length: 5, window: 0x9800488, mask: 0xc, v0 785, v1 867, v2 329228, v3 159384712, v4 159383555, - CW-mask: CWWidth,CWHeight, - XXX,XXX -71.76157 0.00003 X_ConfigureWindow - length: 5, window: 0x9800488, mask: 0x3, v0 0, v1 0, v2 131132, v3 159385313, v4 328759, - CW-mask: CWX,CWY, - XXX,XXX - -Down arrow: -72.93147 0.01990 X_ConfigureWindow - length: 5, window: 0x9800488, mask: 0xc, v0 785, v1 882, v2 328972, v3 159384712, v4 159383555, - CW-mask: CWWidth,CWHeight, - XXX,XXX -72.93156 0.00009 X_ConfigureWindow - length: 5, window: 0x9800488, mask: 0x3, v0 0, v1 -15, v2 458764, v3 159384712, v4 159383567, - CW-mask: CWX,CWY, -72.93160 0.00004 X_ConfigureWindow - length: 7, window: 0x9800488, mask: 0xf, v0 0, v1 0, v2 785, v3 867, v4 131132, v5 159385335, v6 328759, - CW-mask: CWX,CWY,CWWidth,CWHeight, - - -sadly, probably need to handle some more... - - */ - x0 = cw_events[list[2]].x; - y0 = cw_events[list[2]].y; - w0 = cw_events[list[2]].w; - h0 = cw_events[list[2]].h; - - x1 = cw_events[list[1]].x; - y1 = cw_events[list[1]].y; - w1 = cw_events[list[1]].w; - h1 = cw_events[list[1]].h; - - x2 = cw_events[list[0]].x; - y2 = cw_events[list[0]].y; - w2 = cw_events[list[0]].w; - h2 = cw_events[list[0]].h; - - /* see NS4 XXX's above: */ - if (w2 == absent || h2 == absent) { - /* up arrow */ - if (w2 == absent) { - w2 = w1; - } - if (h2 == absent) { - h2 = h1; - } - } - if (x1 == absent || y1 == absent) { - /* up arrow */ - if (x1 == absent) { - x1 = x2; - } - if (y1 == absent) { - y1 = y2; - } - } - if (x0 == absent || y0 == absent) { - /* down arrow */ - if (x0 == absent) { - /* hmmm... what to do */ - x0 = x2; - } - if (y0 == absent) { - y0 = y2; - } - } - -if (dba) fprintf(stderr, "%d/%d/%d/%d %d/%d/%d/%d %d/%d/%d/%d\n", x0, y0, w0, h0, x1, y1, w1, h1, x2, y2, w2, h2); - - dy = y1 - y0; - dx = x1 - x0; - - src_x = x2; - src_y = y2; - w = w2; - h = h2; - - /* check w and h before we modify them */ - if (w <= 0 || h <= 0) { - good = 0; - } else if (w == absent || h == absent) { - good = 0; - } - if (! good) { - return; - } -if (db > 1) fprintf(stderr, "record_CW-%d\n", k++); - - if (dy > 0) { - h -= dy; - } else { - h += dy; - src_y -= dy; - } - if (dx > 0) { - w -= dx; - } else { - w += dx; - src_x -= dx; - } - - dst_x = src_x + dx; - dst_y = src_y + dy; - - if (x0 == absent || x1 == absent || x2 == absent) { - good = 0; - } else if (y0 == absent || y1 == absent || y2 == absent) { - good = 0; - } else if (dx != 0 && dy != 0) { - good = 0; - } else if (w0 - w2 != nabs(dx)) { - good = 0; - } else if (h0 - h2 != nabs(dy)) { - good = 0; - } else if (scr_ev_cnt >= SCR_EV_MAX) { - good = 0; - } - - if (! good) { - return; - } -if (db > 1) fprintf(stderr, "record_CW-%d\n", k++); - - /* - * geometry OK. - * after all of the above succeeds, now contact X server. - */ - if (lookup_attr_cache(win, &cache_index, &next_index)) { - i = cache_index; - attr.x = scr_attr_cache[i].x; - attr.y = scr_attr_cache[i].y; - attr.width = scr_attr_cache[i].width; - attr.height = scr_attr_cache[i].height; - attr.map_state = scr_attr_cache[i].map_state; - rx = scr_attr_cache[i].rx; - ry = scr_attr_cache[i].ry; - valid = scr_attr_cache[i].valid; - -if (0) fprintf(stderr, "lookup_attr_cache hit: %2d %2d 0x%lx %d\n", - cache_index, next_index, win, valid); - - } else { - valid = valid_window(win, &attr, 1); - -if (0) fprintf(stderr, "lookup_attr_cache MISS: %2d %2d 0x%lx %d\n", - cache_index, next_index, win, valid); - - if (valid) { - if (!xtranslate(win, rootwin, 0, 0, &rx, &ry, &c, 1)) { - valid = 0; - } - } - if (next_index >= 0) { - i = next_index; - scr_attr_cache[i].win = win; - scr_attr_cache[i].fetched = 1; - scr_attr_cache[i].valid = valid; - scr_attr_cache[i].time = dnow(); - if (valid) { - scr_attr_cache[i].x = attr.x; - scr_attr_cache[i].y = attr.y; - scr_attr_cache[i].width = attr.width; - scr_attr_cache[i].height = attr.height; - scr_attr_cache[i].depth = attr.depth; - scr_attr_cache[i].class = attr.class; - scr_attr_cache[i].backing_store = - attr.backing_store; - scr_attr_cache[i].map_state = attr.map_state; - - scr_attr_cache[i].rx = rx; - scr_attr_cache[i].ry = ry; - } - } - } - - if (! valid) { - return; - } -if (db > 1) fprintf(stderr, "record_CW-%d\n", k++); - - if (attr.map_state != IsViewable) { - return; - } -if (db > 1) fprintf(stderr, "record_CW-%d\n", k++); - -if (0 || dba || db) { - double st, dt; - st = (double) rec_data->server_time/1000.0; - dt = (dnow() - servertime_diff) - st; - fprintf(stderr, "record_CW-%d *FOUND_SCROLL: win: 0x%lx dx: %d dy: %d " - "x: %d y: %d w: %d h: %d st: %.4f dt: %.4f %.4f\n", k++, win, - dx, dy, src_x, src_y, w, h, st, dt, dnow() - x11vnc_start); -} - - i = scr_ev_cnt; - - scr_ev[i].win = win; - scr_ev[i].frame = None; - scr_ev[i].dx = dx; - scr_ev[i].dy = dy; - scr_ev[i].x = rx + dst_x; - scr_ev[i].y = ry + dst_y; - scr_ev[i].w = w; - scr_ev[i].h = h; - scr_ev[i].t = ((double) rec_data->server_time)/1000.0; - scr_ev[i].win_x = rx; - scr_ev[i].win_y = ry; - scr_ev[i].win_w = attr.width; - scr_ev[i].win_h = attr.height; - scr_ev[i].new_x = 0; - scr_ev[i].new_y = 0; - scr_ev[i].new_w = 0; - scr_ev[i].new_h = 0; - - if (dx == 0) { - if (dy > 0) { - scr_ev[i].new_x = rx + src_x; - scr_ev[i].new_y = ry + src_y; - scr_ev[i].new_w = w; - scr_ev[i].new_h = dy; - } else { - scr_ev[i].new_x = rx + src_x; - scr_ev[i].new_y = ry + dst_y + h; - scr_ev[i].new_w = w; - scr_ev[i].new_h = -dy; - } - } else if (dy == 0) { - if (dx > 0) { - scr_ev[i].new_x = rx + src_x; - scr_ev[i].new_y = rx + src_y; - scr_ev[i].new_w = dx; - scr_ev[i].new_h = h; - } else { - scr_ev[i].new_x = rx + dst_x + w; - scr_ev[i].new_y = ry + src_y; - scr_ev[i].new_w = -dx; - scr_ev[i].new_h = h; - } - } - - /* indicate we have a new one */ - scr_ev_cnt++; - - index = 0; -} - -void record_switch(XPointer ptr, XRecordInterceptData *rec_data) { - static int first = 1; - xReq *req; - - if (first) { - int i; - for (i=0; i<SCR_ATTR_CACHE; i++) { - scr_attr_cache[i].win = None; - scr_attr_cache[i].fetched = 0; - scr_attr_cache[i].valid = 0; - scr_attr_cache[i].time = 0.0; - } - first = 0; - } - - /* should handle control msgs, start/stop/etc */ - if (rec_data->category == XRecordStartOfData) { - record_CW(ptr, rec_data); - } else if (rec_data->category == XRecordEndOfData) { - ; - } else if (rec_data->category == XRecordClientStarted) { - ; - } else if (rec_data->category == XRecordClientDied) { - ; - } else if (rec_data->category == XRecordFromServer) { - ; - } - - if (rec_data->category != XRecordFromClient) { - XRecordFreeData(rec_data); - return; - } - - req = (xReq *) rec_data->data; - - if (req->reqType == X_CopyArea) { - record_CA(ptr, rec_data); - } else if (req->reqType == X_ConfigureWindow) { - record_CW(ptr, rec_data); - } else { - ; - } - XRecordFreeData(rec_data); -} - -void record_grab(XPointer ptr, XRecordInterceptData *rec_data) { - xReq *req; - int db = 0; - - if (debug_grabs) db = 1; - - /* should handle control msgs, start/stop/etc */ - if (rec_data->category == XRecordStartOfData) { - ; - } else if (rec_data->category == XRecordEndOfData) { - ; - } else if (rec_data->category == XRecordClientStarted) { - ; - } else if (rec_data->category == XRecordClientDied) { - ; - } else if (rec_data->category == XRecordFromServer) { - ; - } - - if (rec_data->category != XRecordFromClient) { - XRecordFreeData(rec_data); - return; - } - - req = (xReq *) rec_data->data; - - if (req->reqType == X_GrabServer) { - double now = dnow() - x11vnc_start; - xserver_grabbed++; - if (db) rfbLog("X server Grabbed: %d %.5f\n", xserver_grabbed, now); - if (xserver_grabbed > 1) { - /* - * some apps do multiple grabs... very unlikely - * two apps will be doing it at same time. - */ - xserver_grabbed = 1; - } - } else if (req->reqType == X_UngrabServer) { - double now = dnow() - x11vnc_start; - xserver_grabbed--; - if (xserver_grabbed < 0) { - xserver_grabbed = 0; - } - if (db) rfbLog("X server Un-Grabbed: %d %.5f\n", xserver_grabbed, now); - } else { - ; - } - XRecordFreeData(rec_data); - - /* unused vars warning: */ - if (ptr) {} -} -#endif - -void check_xrecord_grabserver(void) { - int last_val, cnt = 0, i, max = 10; - double d; -#if LIBVNCSERVER_HAVE_RECORD - if (!gdpy_ctrl || !gdpy_data) { - return; - } - - dtime0(&d); - XFlush(gdpy_ctrl); - for (i=0; i<max; i++) { - last_val = xserver_grabbed; - XRecordProcessReplies(gdpy_data); - if (xserver_grabbed != last_val) { - cnt++; - } else if (i > 2) { - break; - } - } - if (cnt) { - XFlush(gdpy_ctrl); - } -if (debug_grabs && cnt > 0) { - d = dtime(&d); -fprintf(stderr, "check_xrecord_grabserver: cnt=%d i=%d %.4f\n", cnt, i, d); -} -#endif -} - -#if LIBVNCSERVER_HAVE_RECORD -void shutdown_record_context(XRecordContext rc, int bequiet, int reopen) { - int ret1, ret2; - int verb = (!bequiet && !quiet); - - if (0 || debug_scroll) { - rfbLog("shutdown_record_context(0x%lx, %d, %d)\n", rc, - bequiet, reopen); - verb = 1; - } - - ret1 = XRecordDisableContext(rdpy_ctrl, rc); - if (!ret1 && verb) { - rfbLog("XRecordDisableContext(0x%lx) failed.\n", rc); - } - ret2 = XRecordFreeContext(rdpy_ctrl, rc); - if (!ret2 && verb) { - rfbLog("XRecordFreeContext(0x%lx) failed.\n", rc); - } - XFlush(rdpy_ctrl); - - if (reopen == 2 && ret1 && ret2) { - reopen = 0; /* 2 means reopen only on failure */ - } - if (reopen && gdpy_ctrl) { - check_xrecord_grabserver(); - if (xserver_grabbed) { - rfbLog("shutdown_record_context: skip reopen," - " server grabbed\n"); - reopen = 0; - } - } - if (reopen) { - char *dpystr = DisplayString(dpy); - - if (debug_scroll) { - rfbLog("closing RECORD data connection.\n"); - } - XCloseDisplay(rdpy_data); - rdpy_data = NULL; - - if (debug_scroll) { - rfbLog("closing RECORD control connection.\n"); - } - XCloseDisplay(rdpy_ctrl); - rdpy_ctrl = NULL; - - rdpy_ctrl = XOpenDisplay(dpystr); - - if (! rdpy_ctrl) { - rfbLog("Failed to reopen RECORD control connection:" - "%s\n", dpystr); - rfbLog(" disabling RECORD scroll detection.\n"); - use_xrecord = 0; - return; - } - XSync(dpy, False); - - disable_grabserver(rdpy_ctrl, 0); - XSync(rdpy_ctrl, True); - - rdpy_data = XOpenDisplay(dpystr); - - if (! rdpy_data) { - rfbLog("Failed to reopen RECORD data connection:" - "%s\n", dpystr); - rfbLog(" disabling RECORD scroll detection.\n"); - XCloseDisplay(rdpy_ctrl); - rdpy_ctrl = NULL; - use_xrecord = 0; - return; - } - disable_grabserver(rdpy_data, 0); - - if (debug_scroll || (! bequiet && reopen == 2)) { - rfbLog("reopened RECORD data and control display" - " connections: %s\n", dpystr); - } - } -} -#endif - -void check_xrecord_reset(int force) { - static double last_reset = 0.0; - int reset_time = 60, require_idle = 10; - int reset_time2 = 600, require_idle2 = 40; - double now; - XErrorHandler old_handler = NULL; - - if (gdpy_ctrl) { - X_LOCK; - check_xrecord_grabserver(); - X_UNLOCK; - } else { - /* more dicey if not watching grabserver */ - reset_time = reset_time2; - require_idle = require_idle2; - } - - if (!use_xrecord) { - return; - } - if (xrecording) { - return; - } - if (button_mask) { - return; - } - if (xserver_grabbed) { - return; - } - -#if LIBVNCSERVER_HAVE_RECORD - if (! rc_scroll) { - return; - } - now = dnow(); - if (last_reset == 0.0) { - last_reset = now; - return; - } - /* - * try to wait for a break in input to reopen the displays - * this is only to avoid XGrabServer deadlock on the repopens. - */ - if (force) { - ; - } else if (now < last_reset + reset_time) { - return; - } else if (now < last_pointer_click_time + require_idle) { - return; - } else if (now < last_keyboard_time + require_idle) { - return; - } - X_LOCK; - trapped_record_xerror = 0; - old_handler = XSetErrorHandler(trap_record_xerror); - - /* unlikely, but check again since we will definitely be doing it. */ - if (gdpy_ctrl) { - check_xrecord_grabserver(); - if (xserver_grabbed) { - XSetErrorHandler(old_handler); - X_UNLOCK; - return; - } - } - - shutdown_record_context(rc_scroll, 0, 1); - rc_scroll = 0; - - XSetErrorHandler(old_handler); - X_UNLOCK; - - last_reset = now; -#endif -} - -#define RECORD_ERROR_MSG \ - if (! quiet) { \ - rfbLog("trapped RECORD XError: %s %d/%d/%d (0x%lx)\n", \ - xerror_string(trapped_record_xerror_event), \ - (int) trapped_record_xerror_event->error_code, \ - (int) trapped_record_xerror_event->request_code, \ - (int) trapped_record_xerror_event->minor_code, \ - (int) trapped_record_xerror_event->resourceid); \ - } - -void xrecord_watch(int start, int setby) { - Window focus, wm, c, clast; - static double create_time = 0.0; - double now; - static double last_error = 0.0; - int rc, db = debug_scroll; - int do_shutdown = 0; - int reopen_dpys = 1; - XErrorHandler old_handler = NULL; - static Window last_win = None, last_result = None; - -if (0) db = 1; - - if (nofb) { - xrecording = 0; - return; - } - if (use_threads) { - /* XXX not working */ - use_xrecord = 0; - xrecording = 0; - return; - } - - dtime0(&now); - if (now < last_error + 0.5) { - return; - } - - if (gdpy_ctrl) { - X_LOCK; - check_xrecord_grabserver(); - X_UNLOCK; - if (xserver_grabbed) { -if (db || debug_grabs) fprintf(stderr, "xrecord_watch: %d/%d out xserver_grabbed\n", start, setby); - return; - } - } - -#if LIBVNCSERVER_HAVE_RECORD - if (! start) { - int shut_reopen = 2, shut_time = 25; -if (db || debug_grabs) fprintf(stderr, "XRECORD OFF: %d/%d %.4f\n", xrecording, setby, now - x11vnc_start); - xrecording = 0; - if (! rc_scroll) { - xrecord_focus_window = None; - xrecord_wm_window = None; - xrecord_ptr_window = None; - xrecord_keysym = NoSymbol; - rcs_scroll = 0; - return; - } - - if (! do_shutdown && now > create_time + shut_time) { - /* XXX unstable if we keep a RECORD going forever */ - do_shutdown = 1; - } - - SCR_LOCK; - - if (do_shutdown) { -if (db > 1) fprintf(stderr, "=== shutdown-scroll 0x%lx\n", rc_scroll); - X_LOCK; - trapped_record_xerror = 0; - old_handler = XSetErrorHandler(trap_record_xerror); - - shutdown_record_context(rc_scroll, 0, shut_reopen); - rc_scroll = 0; - - /* - * n.b. there is a grabserver issue wrt - * XRecordCreateContext() even though rdpy_ctrl - * is set imprevious to grabs. Perhaps a bug - * in the X server or library... - * - * If there are further problems, a thought - * to recreate rc_scroll right after the - * reopen. - */ - - if (! use_xrecord) { - XSetErrorHandler(old_handler); - X_UNLOCK; - SCR_UNLOCK; - return; - } - - XRecordProcessReplies(rdpy_data); - - if (trapped_record_xerror) { - RECORD_ERROR_MSG; - last_error = now; - } - - XSetErrorHandler(old_handler); - X_UNLOCK; - SCR_UNLOCK; - - } else { - if (rcs_scroll) { -if (db > 1) fprintf(stderr, "=== disab-scroll 0x%lx 0x%lx\n", rc_scroll, rcs_scroll); - X_LOCK; - trapped_record_xerror = 0; - old_handler = - XSetErrorHandler(trap_record_xerror); - - rcs_scroll = XRecordCurrentClients; - XRecordUnregisterClients(rdpy_ctrl, rc_scroll, - &rcs_scroll, 1); - XRecordDisableContext(rdpy_ctrl, rc_scroll); - XFlush(rdpy_ctrl); - XRecordProcessReplies(rdpy_data); - - if (trapped_record_xerror) { - RECORD_ERROR_MSG; - - shutdown_record_context(rc_scroll, - 0, reopen_dpys); - rc_scroll = 0; - - last_error = now; - - if (! use_xrecord) { - XSetErrorHandler(old_handler); - X_UNLOCK; - SCR_UNLOCK; - return; - } - } - XSetErrorHandler(old_handler); - X_UNLOCK; - } - } - - SCR_UNLOCK; - /* - * XXX if we do a XFlush(rdpy_ctrl) here we get: - * - - X Error of failed request: XRecordBadContext - Major opcode of failed request: 145 (RECORD) - Minor opcode of failed request: 5 (XRecordEnableContext) - Context in failed request: 0x2200013 - Serial number of failed request: 29 - Current serial number in output stream: 29 - - * - * need to figure out what is going on... since it may lead - * infrequent failures. - */ - xrecord_focus_window = None; - xrecord_wm_window = None; - xrecord_ptr_window = None; - xrecord_keysym = NoSymbol; - rcs_scroll = 0; - return; - } -if (db || debug_grabs) fprintf(stderr, "XRECORD ON: %d/%d %.4f\n", xrecording, setby, now - x11vnc_start); - - if (xrecording) { - return; - } - - if (do_shutdown && rc_scroll) { - static int didmsg = 0; - /* should not happen... */ - if (0 || !didmsg) { - rfbLog("warning: do_shutdown && rc_scroll\n"); - didmsg = 1; - } - xrecord_watch(0, SCR_NONE); - } - - xrecording = 0; - xrecord_focus_window = None; - xrecord_wm_window = None; - xrecord_ptr_window = None; - xrecord_keysym = NoSymbol; - xrecord_set_by_keys = 0; - xrecord_set_by_mouse = 0; - - /* get the window with focus and mouse pointer: */ - clast = None; - focus = None; - wm = None; - - X_LOCK; - SCR_LOCK; -#if 0 - /* - * xrecord_focus_window / focus not currently used... save a - * round trip to the X server for now. - * N.B. our heuristic is inaccurate: if he is scrolling and - * drifts off of the scrollbar onto another application we - * will catch that application, not the starting ones. - * check_xrecord_{keys,mouse} mitigates this somewhat by - * delaying calls to xrecord_watch as much as possible. - */ - XGetInputFocus(dpy, &focus, &i); -#endif - - wm = query_pointer(rootwin); - if (wm) { - c = wm; - } else { - c = rootwin; - } - - /* descend a bit to avoid wm frames: */ - if (c != rootwin && c == last_win) { - /* use cached results to avoid roundtrips: */ - clast = last_result; - } else if (scroll_good_all == NULL && scroll_skip_all == NULL) { - /* more efficient if name info not needed. */ - xrecord_name_info[0] = '\0'; - clast = descend_pointer(6, c, NULL, 0); - } else { - char *nm; - int matched_good = 0, matched_skip = 0; - - clast = descend_pointer(6, c, xrecord_name_info, NAMEINFO); -if (db) fprintf(stderr, "name_info: %s\n", xrecord_name_info); - - nm = xrecord_name_info; - - if (scroll_good_all) { - matched_good += match_str_list(nm, scroll_good_all); - } - if (setby == SCR_KEY && scroll_good_key) { - matched_good += match_str_list(nm, scroll_good_key); - } - if (setby == SCR_MOUSE && scroll_good_mouse) { - matched_good += match_str_list(nm, scroll_good_mouse); - } - if (scroll_skip_all) { - matched_skip += match_str_list(nm, scroll_skip_all); - } - if (setby == SCR_KEY && scroll_skip_key) { - matched_skip += match_str_list(nm, scroll_skip_key); - } - if (setby == SCR_MOUSE && scroll_skip_mouse) { - matched_skip += match_str_list(nm, scroll_skip_mouse); - } - - if (!matched_good && matched_skip) { - clast = None; - } - } - if (c != rootwin) { - /* cache results for possible use next call */ - last_win = c; - last_result = clast; - } - - if (!clast || clast == rootwin) { -if (db) fprintf(stderr, "--- xrecord_watch: SKIP.\n"); - X_UNLOCK; - SCR_UNLOCK; - return; - } - - /* set protocol request ranges: */ - rr_scroll[0] = rr_CA; - rr_scroll[1] = rr_CW; - - /* - * start trapping... there still are some occasional failures - * not yet understood, likely some race condition WRT the - * context being setup. - */ - trapped_record_xerror = 0; - old_handler = XSetErrorHandler(trap_record_xerror); - - if (! rc_scroll) { - /* do_shutdown case or first time in */ - - if (gdpy_ctrl) { - /* - * Even though rdpy_ctrl is impervious to grabs - * at this point, we still get deadlock, why? - * It blocks in the library find_display() call. - */ - check_xrecord_grabserver(); - if (xserver_grabbed) { - XSetErrorHandler(old_handler); - X_UNLOCK; - SCR_UNLOCK; - return; - } - } - rcs_scroll = (XRecordClientSpec) clast; - rc_scroll = XRecordCreateContext(rdpy_ctrl, 0, &rcs_scroll, 1, - rr_scroll, 2); - - if (! do_shutdown) { - XSync(rdpy_ctrl, False); - } -if (db) fprintf(stderr, "NEW rc: 0x%lx\n", rc_scroll); - if (rc_scroll) { - dtime0(&create_time); - } else { - rcs_scroll = 0; - } - - } else if (! do_shutdown) { - if (rcs_scroll) { - /* - * should have been unregistered in xrecord_watch(0)... - */ - rcs_scroll = XRecordCurrentClients; - XRecordUnregisterClients(rdpy_ctrl, rc_scroll, - &rcs_scroll, 1); - -if (db > 1) fprintf(stderr, "=2= unreg-scroll 0x%lx 0x%lx\n", rc_scroll, rcs_scroll); - - } - - rcs_scroll = (XRecordClientSpec) clast; - -if (db > 1) fprintf(stderr, "=-= reg-scroll 0x%lx 0x%lx\n", rc_scroll, rcs_scroll); - - if (!XRecordRegisterClients(rdpy_ctrl, rc_scroll, 0, - &rcs_scroll, 1, rr_scroll, 2)) { - if (1 || now > last_error + 60) { - rfbLog("failed to register client 0x%lx with" - " X RECORD context rc_scroll.\n", clast); - } - last_error = now; - rcs_scroll = 0; - /* continue on for now... */ - } - } - - XFlush(rdpy_ctrl); - -if (db) fprintf(stderr, "rc_scroll: 0x%lx\n", rc_scroll); - if (trapped_record_xerror) { - RECORD_ERROR_MSG; - } - - if (! rc_scroll) { - XSetErrorHandler(old_handler); - X_UNLOCK; - SCR_UNLOCK; - use_xrecord = 0; - rfbLog("failed to create X RECORD context rc_scroll.\n"); - rfbLog(" switching to -noscrollcopyrect mode.\n"); - return; - } else if (! rcs_scroll || trapped_record_xerror) { - /* try again later */ - shutdown_record_context(rc_scroll, 0, reopen_dpys); - rc_scroll = 0; - last_error = now; - - XSetErrorHandler(old_handler); - X_UNLOCK; - SCR_UNLOCK; - return; - } - - xrecord_focus_window = focus; -#if 0 - /* xrecord_focus_window currently unused. */ - if (! xrecord_focus_window) { - xrecord_focus_window = clast; - } -#endif - xrecord_wm_window = wm; - if (! xrecord_wm_window) { - xrecord_wm_window = clast; - } - - xrecord_ptr_window = clast; - - xrecording = 1; - xrecord_seq++; - dtime0(&xrecord_start); - - rc = XRecordEnableContextAsync(rdpy_data, rc_scroll, record_switch, - (XPointer) xrecord_seq); - - if (!rc || trapped_record_xerror) { - if (1 || now > last_error + 60) { - rfbLog("failed to enable RECORD context " - "rc_scroll: 0x%lx rc: %d\n", rc_scroll, rc); - if (trapped_record_xerror) { - RECORD_ERROR_MSG; - } - } - shutdown_record_context(rc_scroll, 0, reopen_dpys); - rc_scroll = 0; - last_error = now; - xrecording = 0; - /* continue on for now... */ - } - XSetErrorHandler(old_handler); - - /* XXX this may cause more problems than it solves... */ - if (use_xrecord) { - XFlush(rdpy_data); - } - - X_UNLOCK; - SCR_UNLOCK; -#endif -} - -/* -- cleanup.c -- */ -/* - * Exiting and error handling routines - */ - -static int exit_flag = 0; -int exit_sig = 0; - -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); - } -} - -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; -XErrorEvent *trapped_xerror_event; -int trapped_xerror = 0; -int trapped_xioerror = 0; -int trapped_getimage_xerror = 0; -int trapped_record_xerror = 0; - -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; -} - -int trap_record_xerror(Display *d, XErrorEvent *error) { - trapped_record_xerror = 1; - trapped_record_xerror_event = error; - - if (d) {} /* unused vars warning: */ - - return 0; -} - -void interrupted(int); - -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); -} - -char *xerrors[] = { - "Success", - "BadRequest", - "BadValue", - "BadWindow", - "BadPixmap", - "BadAtom", - "BadCursor", - "BadFont", - "BadMatch", - "BadDrawable", - "BadAccess", - "BadAlloc", - "BadColor", - "BadGC", - "BadIDChoice", - "BadName", - "BadLength", - "BadImplementation", - "unknown" -}; -int xerrors_max = BadImplementation; - -char *xerror_string(XErrorEvent *error) { - int index = -1; - if (error) { - index = (int) error->error_code; - } - if (0 <= index && index <= xerrors_max) { - return xerrors[index]; - } else { - return xerrors[xerrors_max+1]; - } -} - -char *crash_stack_command1 = NULL; -char *crash_stack_command2 = NULL; -char *crash_debug_command = NULL; -/* XXX CHECK BEFORE RELEASE */ -int crash_debug = 0; - -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); -} - -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"); -} - -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 - */ -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); - } -} - -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 wait_until_mapped(Window win) { - int ms = 50, waittime = 30; - time_t start = time(0); - XWindowAttributes attr; - - while (1) { - if (! valid_window(win, NULL, 0)) { - if (time(0) > start + waittime) { - break; - } - usleep(ms * 1000); - continue; - } - if (! XGetWindowAttributes(dpy, win, &attr)) { - return 0; - } - if (attr.map_state == IsViewable) { - return 1; - } - usleep(ms * 1000); - } - return 0; -} - -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; - } -} - -/* 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; -} - -/* -- connections.c -- */ -/* - * routines for handling incoming, outgoing, etc connections - */ - -/* - * check that all clients are in RFB_NORMAL state - */ -int all_clients_initialized(void) { - rfbClientIteratorPtr iter; - rfbClientPtr cl; - int ok = 1; - - if (! screen) { - return ok; - } - - iter = rfbGetClientIterator(screen); - while( (cl = rfbClientIteratorNext(iter)) ) { - if (cl->state != RFB_NORMAL) { - ok = 0; - break; - } - } - rfbReleaseClientIterator(iter); - - return ok; -} - -char *list_clients(void) { - rfbClientIteratorPtr iter; - rfbClientPtr cl; - char *list, tmp[32]; - int count = 0; - - if (!screen) { - return strdup(""); - } - - iter = rfbGetClientIterator(screen); - while( (cl = rfbClientIteratorNext(iter)) ) { - count++; - } - rfbReleaseClientIterator(iter); - - /* - * each client: - * <id>:<ip>:<port>:<user>:<hostname>:<input>:<loginview>, - * 8+1+16+1+5+1+24+1+256+1+5+1+1+1 - * 123.123.123.123:60000/0x11111111-rw, - * so count+1 * 400 must cover it. - */ - list = (char *) malloc((count+1)*400); - - list[0] = '\0'; - - iter = rfbGetClientIterator(screen); - while( (cl = rfbClientIteratorNext(iter)) ) { - ClientData *cd = (ClientData *) cl->clientData; - if (*list != '\0') { - strcat(list, ","); - } - sprintf(tmp, "0x%x:", cd->uid); - strcat(list, tmp); - strcat(list, cl->host); - strcat(list, ":"); - sprintf(tmp, "%d:", cd->client_port); - strcat(list, tmp); - if (*(cd->username) == '\0') { - char *s = ident_username(cl); - if (s) free(s); - } - strcat(list, cd->username); - strcat(list, ":"); - strcat(list, cd->hostname); - strcat(list, ":"); - strcat(list, cd->input); - strcat(list, ":"); - sprintf(tmp, "%d", cd->login_viewonly); - strcat(list, tmp); - } - rfbReleaseClientIterator(iter); - return list; -} - -/* count number of clients supporting NewFBSize */ -int new_fb_size_clients(rfbScreenInfoPtr s) { - rfbClientIteratorPtr iter; - rfbClientPtr cl; - int count = 0; - - if (! s) { - return 0; - } - - iter = rfbGetClientIterator(s); - while( (cl = rfbClientIteratorNext(iter)) ) { - if (cl->useNewFBSize) { - count++; - } - } - rfbReleaseClientIterator(iter); - return count; -} - -void close_all_clients(void) { - rfbClientIteratorPtr iter; - rfbClientPtr cl; - - if (! screen) { - return; - } - - iter = rfbGetClientIterator(screen); - while( (cl = rfbClientIteratorNext(iter)) ) { - rfbCloseClient(cl); - rfbClientConnectionGone(cl); - } - rfbReleaseClientIterator(iter); -} - -rfbClientPtr *client_match(char *str) { - rfbClientIteratorPtr iter; - rfbClientPtr cl, *cl_list; - int i, n, host_warn = 0, hex_warn = 0; - - n = client_count + 10; - cl_list = (rfbClientPtr *) malloc(n * sizeof(rfbClientPtr)); - - i = 0; - iter = rfbGetClientIterator(screen); - while( (cl = rfbClientIteratorNext(iter)) ) { - if (strstr(str, "0x") == str) { - unsigned int in; - int id; - ClientData *cd = (ClientData *) cl->clientData; - if (sscanf(str, "0x%x", &in) != 1) { - if (hex_warn++) { - continue; - } - rfbLog("skipping invalid client hex id: %s\n", - str); - continue; - } - id = (unsigned int) in; - if (cd->uid == id) { - cl_list[i++] = cl; - } - } else { - char *rstr = str; - if (! dotted_ip(str)) { - rstr = host2ip(str); - if (rstr == NULL || *rstr == '\0') { - if (host_warn++) { - continue; - } - rfbLog("skipping bad lookup: \"%s\"\n", - str); - continue; - } - rfbLog("lookup: %s -> %s\n", str, rstr); - } - if (!strcmp(rstr, cl->host)) { - cl_list[i++] = cl; - } - if (rstr != str) { - free(rstr); - } - } - if (i >= n - 1) { - break; - } - } - rfbReleaseClientIterator(iter); - - cl_list[i] = NULL; - - return cl_list; -} - -void close_clients(char *str) { - rfbClientPtr *cl_list, *cp; - - if (!strcmp(str, "all") || !strcmp(str, "*")) { - close_all_clients(); - return; - } - - if (! screen) { - return; - } - - cl_list = client_match(str); - - cp = cl_list; - while (*cp) { - rfbCloseClient(*cp); - rfbClientConnectionGone(*cp); - cp++; - } - free(cl_list); -} - -void set_client_input(char *str) { - rfbClientPtr *cl_list, *cp; - char *p, *val; - - /* str is "match:value" */ - - if (! screen) { - return; - } - - p = strchr(str, ':'); - if (! p) { - return; - } - *p = '\0'; - p++; - val = short_kmb(p); - - cl_list = client_match(str); - - cp = cl_list; - while (*cp) { - ClientData *cd = (ClientData *) (*cp)->clientData; - cd->input[0] = '\0'; - strcat(cd->input, "_"); - strcat(cd->input, val); - cp++; - } - - free(val); - free(cl_list); -} - -void set_child_info(void) { - char pid[16]; - /* set up useful environment for child process */ - sprintf(pid, "%d", (int) getpid()); - set_env("X11VNC_PID", pid); - if (program_name) { - /* e.g. for remote control -R */ - set_env("X11VNC_PROG", program_name); - } - if (program_cmdline) { - set_env("X11VNC_CMDLINE", program_cmdline); - } - if (raw_fb_str) { - set_env("X11VNC_RAWFB_STR", raw_fb_str); - } else { - set_env("X11VNC_RAWFB_STR", ""); - } -} - -/* - * utility to run a user supplied command setting some RFB_ env vars. - * used by, e.g., accept_client() and client_gone() - */ -static int run_user_command(char *cmd, rfbClientPtr client, char *mode) { - char *old_display = NULL; - char *addr = client->host; - char str[100]; - int rc; - ClientData *cd = (ClientData *) client->clientData; - - if (addr == NULL || addr[0] == '\0') { - addr = "unknown-host"; - } - - /* set RFB_CLIENT_ID to semi unique id for command to use */ - if (cd && cd->uid) { - sprintf(str, "0x%x", cd->uid); - } else { - /* not accepted yet: */ - sprintf(str, "0x%x", clients_served); - } - set_env("RFB_CLIENT_ID", str); - - /* set RFB_CLIENT_IP to IP addr for command to use */ - set_env("RFB_CLIENT_IP", addr); - - /* set RFB_X11VNC_PID to our pid for command to use */ - sprintf(str, "%d", (int) getpid()); - set_env("RFB_X11VNC_PID", str); - - /* set RFB_CLIENT_PORT to peer port for command to use */ - if (cd && cd->client_port > 0) { - sprintf(str, "%d", cd->client_port); - } else { - sprintf(str, "%d", get_remote_port(client->sock)); - } - set_env("RFB_CLIENT_PORT", str); - - set_env("RFB_MODE", mode); - - /* - * now do RFB_SERVER_IP and RFB_SERVER_PORT (i.e. us!) - * This will establish a 5-tuple (including tcp) the external - * program can potentially use to work out the virtual circuit - * for this connection. - */ - if (cd && cd->server_ip) { - set_env("RFB_SERVER_IP", cd->server_ip); - } else { - char *sip = get_local_host(client->sock); - set_env("RFB_SERVER_IP", sip); - if (sip) free(sip); - } - - if (cd && cd->server_port > 0) { - sprintf(str, "%d", cd->server_port); - } else { - sprintf(str, "%d", get_local_port(client->sock)); - } - set_env("RFB_SERVER_PORT", str); - - /* - * Better set DISPLAY to the one we are polling, if they - * want something trickier, they can handle on their own - * via environment, etc. - */ - if (getenv("DISPLAY")) { - old_display = strdup(getenv("DISPLAY")); - } - - if (raw_fb && ! dpy) { /* raw_fb hack */ - set_env("DISPLAY", "rawfb"); - } else { - set_env("DISPLAY", DisplayString(dpy)); - } - - /* - * work out the number of clients (have to use client_count - * since there is deadlock in rfbGetClientIterator) - */ - sprintf(str, "%d", client_count); - set_env("RFB_CLIENT_COUNT", str); - - if (no_external_cmds) { - rfbLogEnable(1); - rfbLog("cannot run external commands in -nocmds mode:\n"); - rfbLog(" \"%s\"\n", cmd); - rfbLog(" exiting.\n"); - clean_up_exit(1); - } - rfbLog("running command:\n"); - rfbLog(" %s\n", cmd); - - /* XXX need to close port 5900, etc.. */ - rc = system(cmd); - - if (rc >= 256) { - rc = rc/256; - } - rfbLog("command returned: %d\n", rc); - - if (old_display) { - set_env("DISPLAY", old_display); - free(old_display); - } - - return rc; -} - -/* - * callback for when a client disconnects - */ -static void client_gone(rfbClientPtr client) { - - client_count--; - if (client_count < 0) client_count = 0; - - speeds_net_rate_measured = 0; - speeds_net_latency_measured = 0; - - rfbLog("client_count: %d\n", client_count); - - if (no_autorepeat && client_count == 0) { - autorepeat(1, 0); - } - if (use_solid_bg && client_count == 0) { - solid_bg(1); - } - if (gone_cmd && *gone_cmd != '\0') { - rfbLog("client_gone: using cmd for: %s\n", client->host); - run_user_command(gone_cmd, client, "gone"); - } - - if (client->clientData) { - ClientData *cd = (ClientData *) client->clientData; - if (cd) { - if (cd->server_ip) { - free(cd->server_ip); - cd->server_ip = NULL; - } - if (cd->hostname) { - free(cd->hostname); - cd->hostname = NULL; - } - if (cd->username) { - free(cd->username); - cd->username = NULL; - } - } - free(client->clientData); - client->clientData = NULL; - } - - if (inetd) { - rfbLog("viewer exited.\n"); - clean_up_exit(0); - } - if (connect_once) { - /* - * This non-exit is done for a bad passwd to be consistent - * with our RFB_CLIENT_REFUSE behavior in new_client() (i.e. - * we disconnect after 1 successful connection). - */ - if ((client->state == RFB_PROTOCOL_VERSION || - client->state == RFB_AUTHENTICATION) && accepted_client) { - rfbLog("connect_once: invalid password or early " - "disconnect.\n"); - rfbLog("connect_once: waiting for next connection.\n"); - accepted_client = 0; - return; - } - if (shared && client_count > 0) { - rfbLog("connect_once: other shared clients still " - "connected, not exiting.\n"); - return; - } - - rfbLog("viewer exited.\n"); - clean_up_exit(0); - } -} - -/* - * Simple routine to limit access via string compare. A power user will - * want to compile libvncserver with libwrap support and use /etc/hosts.allow. - */ -static int check_access(char *addr) { - int allowed = 0; - char *p, *list; - - if (deny_all) { - rfbLog("check_access: new connections are currently " - "blocked.\n"); - return 0; - } - if (addr == NULL || *addr == '\0') { - rfbLog("check_access: denying empty host IP address string.\n"); - return 0; - } - - if (allow_list == NULL) { - /* set to "" to possibly append allow_once */ - allow_list = strdup(""); - } - if (*allow_list == '\0' && allow_once == NULL) { - /* no constraints, accept it */ - return 1; - } - - if (strchr(allow_list, '/')) { - /* a file of IP addresess or prefixes */ - int len, len2 = 0; - struct stat sbuf; - FILE *in; - char line[1024], *q; - - if (stat(allow_list, &sbuf) != 0) { - rfbLogEnable(1); - rfbLog("check_access: failure stating file: %s\n", - allow_list); - rfbLogPerror("stat"); - clean_up_exit(1); - } - len = sbuf.st_size + 1; /* 1 more for '\0' at end */ - if (allow_once) { - len2 = strlen(allow_once) + 2; - len += len2; - } - list = (char *) malloc(len); - list[0] = '\0'; - - in = fopen(allow_list, "r"); - if (in == NULL) { - rfbLogEnable(1); - rfbLog("check_access: cannot open: %s\n", allow_list); - rfbLogPerror("fopen"); - clean_up_exit(1); - } - while (fgets(line, 1024, in) != NULL) { - if ( (q = strchr(line, '#')) != NULL) { - *q = '\0'; - } - if (strlen(list) + strlen(line) >= - (size_t) (len - len2)) { - /* file grew since our stat() */ - break; - } - strcat(list, line); - } - fclose(in); - if (allow_once) { - strcat(list, "\n"); - strcat(list, allow_once); - strcat(list, "\n"); - } - } else { - int len = strlen(allow_list) + 1; - if (allow_once) { - len += strlen(allow_once) + 1; - } - list = (char *) malloc(len); - list[0] = '\0'; - strcat(list, allow_list); - if (allow_once) { - strcat(list, ","); - strcat(list, allow_once); - } - } - - if (allow_once) { - free(allow_once); - allow_once = NULL; - } - - p = strtok(list, ", \t\n\r"); - while (p) { - char *chk, *q, *r = NULL; - if (*p == '\0') { - p = strtok(NULL, ", \t\n\r"); - continue; - } - if (! dotted_ip(p)) { - r = host2ip(p); - if (r == NULL || *r == '\0') { - rfbLog("check_access: bad lookup \"%s\"\n", p); - p = strtok(NULL, ", \t\n\r"); - continue; - } - rfbLog("check_access: lookup %s -> %s\n", p, r); - chk = r; - } else { - chk = p; - } - - q = strstr(addr, chk); - if (chk[strlen(chk)-1] != '.') { - if (!strcmp(addr, chk)) { - if (chk != p) { - rfbLog("check_access: client %s " - "matches host %s=%s\n", addr, - chk, p); - } else { - rfbLog("check_access: client %s " - "matches host %s\n", addr, chk); - } - allowed = 1; - } else if(!strcmp(chk, "localhost") && - !strcmp(addr, "127.0.0.1")) { - allowed = 1; - } - } else if (q == addr) { - rfbLog("check_access: client %s matches pattern %s\n", - addr, chk); - allowed = 1; - } - p = strtok(NULL, ", \t\n\r"); - if (r) { - free(r); - } - if (allowed) { - break; - } - } - free(list); - return allowed; -} - -/* - * x11vnc's first (and only) visible widget: accept/reject dialog window. - * We go through this pain to avoid dependency on libXt... - */ -static int ugly_accept_window(char *addr, char *userhost, int X, int Y, - int timeout, char *mode) { - -#define t2x2_width 16 -#define t2x2_height 16 -static unsigned char t2x2_bits[] = { - 0xff, 0xff, 0xff, 0xff, 0x33, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, - 0x33, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0x33, 0x33, 0x33, 0x33, - 0xff, 0xff, 0xff, 0xff, 0x33, 0x33, 0x33, 0x33}; - - Window awin; - GC gc; - XSizeHints hints; - XGCValues values; - static XFontStruct *font_info = NULL; - static Pixmap ico = 0; - unsigned long valuemask = 0; - static char dash_list[] = {20, 40}; - int list_length = sizeof(dash_list); - - Atom wm_protocols; - Atom wm_delete_window; - - XEvent ev; - long evmask = ExposureMask | KeyPressMask | ButtonPressMask - | StructureNotifyMask; - double waited = 0.0; - - /* strings and geometries y/n */ - KeyCode key_y, key_n, key_v; - char strh[100]; - char stri[100]; - char str1_b[] = "To accept: press \"y\" or click the \"Yes\" button"; - char str2_b[] = "To reject: press \"n\" or click the \"No\" button"; - char str3_b[] = "View only: press \"v\" or click the \"View\" button"; - char str1_m[] = "To accept: click the \"Yes\" button"; - char str2_m[] = "To reject: click the \"No\" button"; - char str3_m[] = "View only: click the \"View\" button"; - char str1_k[] = "To accept: press \"y\""; - char str2_k[] = "To reject: press \"n\""; - char str3_k[] = "View only: press \"v\""; - char *str1, *str2, *str3; - char str_y[] = "Yes"; - char str_n[] = "No"; - char str_v[] = "View"; - int x, y, w = 345, h = 175, ret = 0; - int X_sh = 20, Y_sh = 30, dY = 20; - int Ye_x = 20, Ye_y = 0, Ye_w = 45, Ye_h = 20; - int No_x = 75, No_y = 0, No_w = 45, No_h = 20; - int Vi_x = 130, Vi_y = 0, Vi_w = 45, Vi_h = 20; - - if (raw_fb && ! dpy) return 0; /* raw_fb hack */ - - if (!strcmp(mode, "mouse_only")) { - str1 = str1_m; - str2 = str2_m; - str3 = str3_m; - } else if (!strcmp(mode, "key_only")) { - str1 = str1_k; - str2 = str2_k; - str3 = str3_k; - h -= dY; - } else { - str1 = str1_b; - str2 = str2_b; - str3 = str3_b; - } - if (view_only) { - h -= dY; - } - - /* XXX handle coff_x/coff_y? */ - if (X < -dpy_x) { - x = (dpy_x - w)/2; /* large negative: center */ - if (x < 0) x = 0; - } else if (X < 0) { - x = dpy_x + X - w; /* from lower right */ - } else { - x = X; /* from upper left */ - } - - if (Y < -dpy_y) { - y = (dpy_y - h)/2; - if (y < 0) y = 0; - } else if (Y < 0) { - y = dpy_y + Y - h; - } else { - y = Y; - } - - X_LOCK; - - awin = XCreateSimpleWindow(dpy, window, x, y, w, h, 4, - BlackPixel(dpy, scr), WhitePixel(dpy, scr)); - - wm_protocols = XInternAtom(dpy, "WM_PROTOCOLS", False); - wm_delete_window = XInternAtom(dpy, "WM_DELETE_WINDOW", False); - XSetWMProtocols(dpy, awin, &wm_delete_window, 1); - - if (! ico) { - ico = XCreateBitmapFromData(dpy, awin, (char *) t2x2_bits, - t2x2_width, t2x2_height); - } - - hints.flags = PPosition | PSize | PMinSize; - hints.x = x; - hints.y = y; - hints.width = w; - hints.height = h; - hints.min_width = w; - hints.min_height = h; - - XSetStandardProperties(dpy, awin, "new x11vnc client", "x11vnc query", - ico, NULL, 0, &hints); - - XSelectInput(dpy, awin, evmask); - - if (! font_info && (font_info = XLoadQueryFont(dpy, "fixed")) == NULL) { - rfbLogEnable(1); - rfbLog("ugly_accept_window: cannot locate font fixed.\n"); - X_UNLOCK; - clean_up_exit(1); - } - - gc = XCreateGC(dpy, awin, valuemask, &values); - XSetFont(dpy, gc, font_info->fid); - XSetForeground(dpy, gc, BlackPixel(dpy, scr)); - XSetLineAttributes(dpy, gc, 1, LineSolid, CapButt, JoinMiter); - XSetDashes(dpy, gc, 0, dash_list, list_length); - - XMapWindow(dpy, awin); - XFlush(dpy); - - snprintf(strh, 100, "x11vnc: accept connection from %s?", addr); - snprintf(stri, 100, " (%s)", userhost); - key_y = XKeysymToKeycode(dpy, XStringToKeysym("y")); - key_n = XKeysymToKeycode(dpy, XStringToKeysym("n")); - key_v = XKeysymToKeycode(dpy, XStringToKeysym("v")); - - while (1) { - int out = -1, x, y, tw, k; - - if (XCheckWindowEvent(dpy, awin, evmask, &ev)) { - ; /* proceed to handling */ - } else if (XCheckTypedEvent(dpy, ClientMessage, &ev)) { - ; /* proceed to handling */ - } else { - int ms = 100; /* sleep a bit */ - usleep(ms * 1000); - waited += ((double) ms)/1000.; - if (timeout && (int) waited >= timeout) { - rfbLog("accept_client: popup timed out after " - "%d seconds.\n", timeout); - out = 0; - ev.type = 0; - } else { - continue; - } - } - - switch(ev.type) { - case Expose: - while (XCheckTypedEvent(dpy, Expose, &ev)) { - ; - } - k=0; - - /* instructions */ - XDrawString(dpy, awin, gc, X_sh, Y_sh+(k++)*dY, - strh, strlen(strh)); - XDrawString(dpy, awin, gc, X_sh, Y_sh+(k++)*dY, - stri, strlen(stri)); - XDrawString(dpy, awin, gc, X_sh, Y_sh+(k++)*dY, - str1, strlen(str1)); - XDrawString(dpy, awin, gc, X_sh, Y_sh+(k++)*dY, - str2, strlen(str2)); - if (! view_only) { - XDrawString(dpy, awin, gc, X_sh, Y_sh+(k++)*dY, - str3, strlen(str3)); - } - - if (!strcmp(mode, "key_only")) { - break; - } - - /* buttons */ - Ye_y = Y_sh+k*dY; - No_y = Y_sh+k*dY; - Vi_y = Y_sh+k*dY; - XDrawRectangle(dpy, awin, gc, Ye_x, Ye_y, Ye_w, Ye_h); - XDrawRectangle(dpy, awin, gc, No_x, No_y, No_w, No_h); - if (! view_only) { - XDrawRectangle(dpy, awin, gc, Vi_x, Vi_y, - Vi_w, Vi_h); - } - - tw = XTextWidth(font_info, str_y, strlen(str_y)); - tw = (Ye_w - tw)/2; - if (tw < 0) tw = 1; - XDrawString(dpy, awin, gc, Ye_x+tw, Ye_y+Ye_h-5, - str_y, strlen(str_y)); - - tw = XTextWidth(font_info, str_n, strlen(str_n)); - tw = (No_w - tw)/2; - if (tw < 0) tw = 1; - XDrawString(dpy, awin, gc, No_x+tw, No_y+No_h-5, - str_n, strlen(str_n)); - - if (! view_only) { - tw = XTextWidth(font_info, str_v, - strlen(str_v)); - tw = (Vi_w - tw)/2; - if (tw < 0) tw = 1; - XDrawString(dpy, awin, gc, Vi_x+tw, - Vi_y+Vi_h-5, str_v, strlen(str_v)); - } - - break; - - case ClientMessage: - if (ev.xclient.message_type == wm_protocols && - (Atom) ev.xclient.data.l[0] == wm_delete_window) { - out = 0; - } - break; - - case ButtonPress: - x = ev.xbutton.x; - y = ev.xbutton.y; - if (!strcmp(mode, "key_only")) { - ; - } else if (x > No_x && x < No_x+No_w && y > No_y - && y < No_y+No_h) { - out = 0; - } else if (x > Ye_x && x < Ye_x+Ye_w && y > Ye_y - && y < Ye_y+Ye_h) { - out = 1; - } else if (! view_only && x > Vi_x && x < Vi_x+Vi_w - && y > Vi_y && y < Vi_y+Ye_h) { - out = 2; - } - break; - - case KeyPress: - if (!strcmp(mode, "mouse_only")) { - ; - } else if (ev.xkey.keycode == key_y) { - out = 1; - } else if (ev.xkey.keycode == key_n) { - out = 0; - } else if (! view_only && ev.xkey.keycode == key_v) { - out = 2; - } - break; - default: - break; - } - if (out != -1) { - ret = out; - XSelectInput(dpy, awin, 0); - XUnmapWindow(dpy, awin); - XFreeGC(dpy, gc); - XDestroyWindow(dpy, awin); - XFlush(dpy); - break; - } - } - X_UNLOCK; - - return ret; -} - -/* - * process a "yes:0,no:*,view:3" type action list comparing to command - * return code rc. * means the default action with no other match. - */ -static int action_match(char *action, int rc) { - char *p, *q, *s = strdup(action); - int cases[4], i, result; - char *labels[4]; - - labels[1] = "yes"; - labels[2] = "no"; - labels[3] = "view"; - - rfbLog("accept_client: process action line: %s\n", - action); - - for (i=1; i <= 3; i++) { - cases[i] = -2; - } - - p = strtok(s, ","); - while (p) { - if ((q = strchr(p, ':')) != NULL) { - int in, k; - *q = '\0'; - q++; - if (strstr(p, "yes") == p) { - k = 1; - } else if (strstr(p, "no") == p) { - k = 2; - } else if (strstr(p, "view") == p) { - k = 3; - } else { - rfbLogEnable(1); - rfbLog("invalid action line: %s\n", action); - clean_up_exit(1); - } - if (*q == '*') { - cases[k] = -1; - } else if (sscanf(q, "%d", &in) == 1) { - if (in < 0) { - rfbLogEnable(1); - rfbLog("invalid action line: %s\n", - action); - clean_up_exit(1); - } - cases[k] = in; - } else { - rfbLogEnable(1); - rfbLog("invalid action line: %s\n", action); - clean_up_exit(1); - } - } else { - rfbLogEnable(1); - rfbLog("invalid action line: %s\n", action); - clean_up_exit(1); - } - p = strtok(NULL, ","); - } - free(s); - - result = -1; - for (i=1; i <= 3; i++) { - if (cases[i] == -1) { - rfbLog("accept_client: default action is case=%d %s\n", - i, labels[i]); - result = i; - break; - } - } - if (result == -1) { - rfbLog("accept_client: no default action\n"); - } - for (i=1; i <= 3; i++) { - if (cases[i] >= 0 && cases[i] == rc) { - rfbLog("accept_client: matched action is case=%d %s\n", - i, labels[i]); - result = i; - break; - } - } - if (result < 0) { - rfbLog("no action match: %s rc=%d set to no\n", action, rc); - result = 2; - } - return result; -} - -/* - * Simple routine to prompt the user on the X display whether an incoming - * client should be allowed to connect or not. If a gui is involved it - * will be running in the environment/context of the X11 DISPLAY. - * - * The command supplied via -accept is run as is (i.e. no string - * substitution) with the RFB_CLIENT_IP environment variable set to the - * incoming client's numerical IP address. - * - * If the external command exits with 0 the client is accepted, otherwise - * the client is rejected. - * - * Some builtins are provided: - * - * xmessage: use homebrew xmessage(1) for the external command. - * popup: use internal X widgets for prompting. - * - */ -static int accept_client(rfbClientPtr client) { - - char xmessage[200], *cmd = NULL; - char *addr = client->host; - char *action = NULL; - - if (accept_cmd == NULL || *accept_cmd == '\0') { - return 1; /* no command specified, so we accept */ - } - - if (addr == NULL || addr[0] == '\0') { - addr = "unknown-host"; - } - - if (strstr(accept_cmd, "popup") == accept_cmd) { - /* use our builtin popup button */ - - /* (popup|popupkey|popupmouse)[+-X+-Y][:timeout] */ - - int ret, timeout = 120; - int x = -64000, y = -64000; - char *p, *mode; - char *userhost = ident_username(client); - - /* extract timeout */ - if ((p = strchr(accept_cmd, ':')) != NULL) { - int in; - if (sscanf(p+1, "%d", &in) == 1) { - timeout = in; - } - } - /* extract geometry */ - if ((p = strpbrk(accept_cmd, "+-")) != NULL) { - int x1, y1; - if (sscanf(p, "+%d+%d", &x1, &y1) == 2) { - x = x1; - y = y1; - } else if (sscanf(p, "+%d-%d", &x1, &y1) == 2) { - x = x1; - y = -y1; - } else if (sscanf(p, "-%d+%d", &x1, &y1) == 2) { - x = -x1; - y = y1; - } else if (sscanf(p, "-%d-%d", &x1, &y1) == 2) { - x = -x1; - y = -y1; - } - } - - /* find mode: mouse, key, or both */ - if (strstr(accept_cmd, "popupmouse") == accept_cmd) { - mode = "mouse_only"; - } else if (strstr(accept_cmd, "popupkey") == accept_cmd) { - mode = "key_only"; - } else { - mode = "both"; - } - - rfbLog("accept_client: using builtin popup for: %s\n", addr); - if ((ret = ugly_accept_window(addr, userhost, x, y, timeout, - mode))) { - free(userhost); - if (ret == 2) { - rfbLog("accept_client: viewonly: %s\n", addr); - client->viewOnly = TRUE; - } - rfbLog("accept_client: popup accepted: %s\n", addr); - return 1; - } else { - free(userhost); - rfbLog("accept_client: popup rejected: %s\n", addr); - return 0; - } - - } else if (!strcmp(accept_cmd, "xmessage")) { - /* make our own command using xmessage(1) */ - - if (view_only) { - sprintf(xmessage, "xmessage -buttons yes:0,no:2 -center" - " 'x11vnc: accept connection from %s?'", addr); - } else { - sprintf(xmessage, "xmessage -buttons yes:0,no:2," - "view-only:3 -center" " 'x11vnc: accept connection" - " from %s?'", addr); - action = "yes:0,no:*,view:3"; - } - cmd = xmessage; - - } else { - /* use the user supplied command: */ - - cmd = accept_cmd; - - /* extract any action prefix: yes:N,no:M,view:K */ - if (strstr(accept_cmd, "yes:") == accept_cmd) { - char *p; - if ((p = strpbrk(accept_cmd, " \t")) != NULL) { - int i; - cmd = p; - p = accept_cmd; - for (i=0; i<200; i++) { - if (*p == ' ' || *p == '\t') { - xmessage[i] = '\0'; - break; - } - xmessage[i] = *p; - p++; - } - xmessage[200-1] = '\0'; - action = xmessage; - } - } - } - - if (cmd) { - int rc; - - rfbLog("accept_client: using cmd for: %s\n", addr); - rc = run_user_command(cmd, client, "accept"); - - if (action) { - int result; - - if (rc < 0) { - rfbLog("accept_client: cannot use negative " - "rc: %d, action %s\n", rc, action); - result = 2; - } else { - result = action_match(action, rc); - } - - if (result == 1) { - rc = 0; - } else if (result == 2) { - rc = 1; - } else if (result == 3) { - rc = 0; - rfbLog("accept_client: viewonly: %s\n", addr); - client->viewOnly = TRUE; - } else { - rc = 1; /* NOTREACHED */ - } - } - - if (rc == 0) { - rfbLog("accept_client: accepted: %s\n", addr); - return 1; - } else { - rfbLog("accept_client: rejected: %s\n", addr); - return 0; - } - } else { - rfbLog("accept_client: no command, rejecting %s\n", addr); - return 0; - } - - /* return 0; NOTREACHED */ -} - -/* - * For the -connect <file> option: periodically read the file looking for - * a connect string. If one is found set client_connect to it. - */ -static void check_connect_file(char *file) { - FILE *in; - char line[VNC_CONNECT_MAX], host[VNC_CONNECT_MAX]; - static int first_warn = 1, truncate_ok = 1; - static time_t last_time = 0; - time_t now = time(0); - - if (last_time == 0) { - last_time = now; - } - if (now - last_time < 1) { - /* check only once a second */ - return; - } - last_time = now; - - if (! truncate_ok) { - /* check if permissions changed */ - if (access(file, W_OK) == 0) { - truncate_ok = 1; - } else { - return; - } - } - - in = fopen(file, "r"); - if (in == NULL) { - if (first_warn) { - rfbLog("check_connect_file: fopen failure: %s\n", file); - rfbLogPerror("fopen"); - first_warn = 0; - } - return; - } - - if (fgets(line, VNC_CONNECT_MAX, in) != NULL) { - if (sscanf(line, "%s", host) == 1) { - if (strlen(host) > 0) { - char *str = strdup(host); - if (strlen(str) > 38) { - char trim[100]; - trim[0] = '\0'; - strncat(trim, str, 38); - rfbLog("read connect file: %s ...\n", - trim); - } else { - rfbLog("read connect file: %s\n", str); - } - client_connect = str; - } - } - } - fclose(in); - - /* truncate file */ - in = fopen(file, "w"); - if (in != NULL) { - fclose(in); - } else { - /* disable if we cannot truncate */ - rfbLog("check_connect_file: could not truncate %s, " - "disabling checking.\n", file); - truncate_ok = 0; - } -} - -/* - * Do a reverse connect for a single "host" or "host:port" - */ -static int do_reverse_connect(char *str) { - rfbClientPtr cl; - char *host, *p; - int rport = 5500, len = strlen(str); - - if (len < 1) { - return 0; - } - if (len > 1024) { - rfbLog("reverse_connect: string too long: %d bytes\n", len); - return 0; - } - if (!screen) { - rfbLog("reverse_connect: screen not setup yet.\n"); - return 0; - } - - /* copy in to host */ - host = (char *) malloc(len+1); - if (! host) { - rfbLog("reverse_connect: could not malloc string %d\n", len); - return 0; - } - strncpy(host, str, len); - host[len] = '\0'; - - /* extract port, if any */ - if ((p = strchr(host, ':')) != NULL) { - rport = atoi(p+1); - *p = '\0'; - } - - cl = rfbReverseConnection(screen, host, rport); - free(host); - - if (cl == NULL) { - rfbLog("reverse_connect: %s failed\n", str); - return 0; - } else { - rfbLog("reverse_connect: %s/%s OK\n", str, cl->host); - return 1; - } -} - -/* - * Break up comma separated list of hosts and call do_reverse_connect() - */ -static void reverse_connect(char *str) { - char *p, *tmp = strdup(str); - int sleep_between_host = 300; - int sleep_min = 1500, sleep_max = 4500, n_max = 5; - int n, tot, t, dt = 100, cnt = 0; - - p = strtok(tmp, ", \t\r\n"); - while (p) { - if ((n = do_reverse_connect(p)) != 0) { - rfbPE(-1); - } - cnt += n; - - p = strtok(NULL, ", \t\r\n"); - if (p) { - t = 0; - while (t < sleep_between_host) { - usleep(dt * 1000); - rfbPE(-1); - t += dt; - } - } - } - free(tmp); - - if (cnt == 0) { - return; - } - - /* - * XXX: we need to process some of the initial handshaking - * events, otherwise the client can get messed up (why??) - * so we send rfbProcessEvents() all over the place. - */ - - n = cnt; - if (n >= n_max) { - n = n_max; - } - t = sleep_max - sleep_min; - tot = sleep_min + ((n-1) * t) / (n_max-1); - - t = 0; - while (t < tot) { - rfbPE(-1); - usleep(dt * 1000); - t += dt; - } -} - -/* - * Routines for monitoring the VNC_CONNECT property for changes. - * The vncconnect(1) will set it on our X display. - */ -void set_vnc_connect_prop(char *str) { - XChangeProperty(dpy, rootwin, vnc_connect_prop, XA_STRING, 8, - PropModeReplace, (unsigned char *)str, strlen(str)); -} - -void read_vnc_connect_prop(void) { - Atom type; - int format, slen, dlen; - unsigned long nitems = 0, bytes_after = 0; - unsigned char* data = NULL; - int db = 1; - - vnc_connect_str[0] = '\0'; - slen = 0; - - if (! vnc_connect || vnc_connect_prop == None) { - /* not active or problem with VNC_CONNECT atom */ - return; - } - - /* read the property value into vnc_connect_str: */ - do { - if (XGetWindowProperty(dpy, DefaultRootWindow(dpy), - vnc_connect_prop, nitems/4, VNC_CONNECT_MAX/16, False, - AnyPropertyType, &type, &format, &nitems, &bytes_after, - &data) == Success) { - - dlen = nitems * (format/8); - if (slen + dlen > VNC_CONNECT_MAX) { - /* too big */ - rfbLog("warning: truncating large VNC_CONNECT" - " string > %d bytes.\n", VNC_CONNECT_MAX); - XFree(data); - break; - } - memcpy(vnc_connect_str+slen, data, dlen); - slen += dlen; - vnc_connect_str[slen] = '\0'; - XFree(data); - } - } while (bytes_after > 0); - - vnc_connect_str[VNC_CONNECT_MAX] = '\0'; - if (! db) { - ; - } else if (strstr(vnc_connect_str, "ans=stop:N/A,ans=quit:N/A,ans=")) { - ; - } else if (strstr(vnc_connect_str, "qry=stop,quit,exit")) { - ; - } else if (strstr(vnc_connect_str, "ack=") == vnc_connect_str) { - ; - } else if (quiet && strstr(vnc_connect_str, "qry=ping") == - vnc_connect_str) { - ; - } else if (strstr(vnc_connect_str, "cmd=") && - strstr(vnc_connect_str, "passwd")) { - rfbLog("read VNC_CONNECT: *\n"); - } else if (strlen(vnc_connect_str) > 38) { - char trim[100]; - trim[0] = '\0'; - strncat(trim, vnc_connect_str, 38); - rfbLog("read VNC_CONNECT: %s ...\n", trim); - - } else { - rfbLog("read VNC_CONNECT: %s\n", vnc_connect_str); - } -} - -/* - * check if client_connect has been set, if so make the reverse connections. - */ -static void send_client_connect(void) { - if (client_connect != NULL) { - char *str = client_connect; - if (strstr(str, "cmd=") == str || strstr(str, "qry=") == str) { - process_remote_cmd(client_connect, 0); - } else if (strstr(str, "ans=") == str - || strstr(str, "aro=") == str) { - ; - } else if (strstr(str, "ack=") == str) { - ; - } else { - reverse_connect(client_connect); - } - free(client_connect); - client_connect = NULL; - } -} - -/* - * monitor the various input methods - */ -void check_connect_inputs(void) { - - /* flush any already set: */ - send_client_connect(); - - /* connect file: */ - if (client_connect_file != NULL) { - check_connect_file(client_connect_file); - } - send_client_connect(); - - /* VNC_CONNECT property (vncconnect program) */ - if (vnc_connect && *vnc_connect_str != '\0') { - client_connect = strdup(vnc_connect_str); - vnc_connect_str[0] = '\0'; - } - send_client_connect(); -} - -void check_gui_inputs(void) { - int i, nmax = 0, n = 0, nfds; - int socks[ICON_MODE_SOCKS]; - fd_set fds; - struct timeval tv; - char buf[VNC_CONNECT_MAX+1]; - ssize_t nbytes; - - for (i=0; i<ICON_MODE_SOCKS; i++) { - if (icon_mode_socks[i] >= 0) { - socks[n++] = i; - if (icon_mode_socks[i] > nmax) { - nmax = icon_mode_socks[i]; - } - } - } - - if (! n) { - return; - } - - FD_ZERO(&fds); - for (i=0; i<n; i++) { - FD_SET(icon_mode_socks[socks[i]], &fds); - } - tv.tv_sec = 0; - tv.tv_usec = 0; - - nfds = select(nmax+1, &fds, NULL, NULL, &tv); - if (nfds <= 0) { - return; - } - - for (i=0; i<n; i++) { - int k, fd = icon_mode_socks[socks[i]]; - char *p; - if (! FD_ISSET(fd, &fds)) { - continue; - } - for (k=0; k<=VNC_CONNECT_MAX; k++) { - buf[k] = '\0'; - } - nbytes = read(fd, buf, VNC_CONNECT_MAX); - if (nbytes <= 0) { - close(fd); - icon_mode_socks[socks[i]] = -1; - continue; - } - - p = strtok(buf, "\r\n"); - while (p) { - if (strstr(p, "cmd=") == p || - strstr(p, "qry=") == p) { - char *str = process_remote_cmd(p, 1); - if (! str) { - str = strdup(""); - } - nbytes = write(fd, str, strlen(str)); - write(fd, "\n", 1); - free(str); - if (nbytes < 0) { - close(fd); - icon_mode_socks[socks[i]] = -1; - break; - } - } - p = strtok(NULL, "\r\n"); - } - } -} - -/* - * libvncserver callback for when a new client connects - */ -enum rfbNewClientAction new_client(rfbClientPtr client) { - ClientData *cd; - - last_event = last_input = time(0); - - if (inetd) { - /* - * Set this so we exit as soon as connection closes, - * otherwise client_gone is only called after RFB_CLIENT_ACCEPT - */ - client->clientGoneHook = client_gone; - } - - clients_served++; - - if (connect_once) { - if (screen->dontDisconnect && screen->neverShared) { - if (! shared && accepted_client) { - rfbLog("denying additional client: %s\n", - client->host); - return(RFB_CLIENT_REFUSE); - } - } - } - if (! check_access(client->host)) { - rfbLog("denying client: %s does not match %s\n", client->host, - allow_list ? allow_list : "(null)" ); - return(RFB_CLIENT_REFUSE); - } - if (! accept_client(client)) { - rfbLog("denying client: %s local user rejected connection.\n", - client->host); - rfbLog("denying client: accept_cmd=\"%s\"\n", - accept_cmd ? accept_cmd : "(null)" ); - return(RFB_CLIENT_REFUSE); - } - - client->clientData = (void *) calloc(sizeof(ClientData), 1); - cd = (ClientData *) client->clientData; - - cd->uid = clients_served; - - cd->client_port = get_remote_port(client->sock); - cd->server_port = get_local_port(client->sock); - cd->server_ip = get_local_host(client->sock); - cd->hostname = ip2host(client->host); - cd->username = strdup(""); - - cd->input[0] = '-'; - cd->login_viewonly = -1; - - client->clientGoneHook = client_gone; - - if (client_count) { - speeds_net_rate_measured = 0; - speeds_net_latency_measured = 0; - } - client_count++; - - last_keyboard_input = last_pointer_input = time(0); - - if (no_autorepeat && client_count == 1 && ! view_only) { - /* - * first client, turn off X server autorepeat - * XXX handle dynamic change of view_only and per-client. - */ - autorepeat(0, 0); - } - if (use_solid_bg && client_count == 1) { - solid_bg(0); - } - - if (pad_geometry) { - install_padded_fb(pad_geometry); - } - - cd->timer = dnow(); - cd->send_cmp_rate = 0.0; - cd->send_raw_rate = 0.0; - cd->latency = 0.0; - cd->cmp_bytes_sent = 0; - cd->raw_bytes_sent = 0; - - accepted_client = 1; - last_client = time(0); - - return(RFB_CLIENT_ACCEPT); -} - -void start_client_info_sock(char *host_port_cookie) { - char *host = NULL, *cookie = NULL, *p; - char *str = strdup(host_port_cookie); - int i, port, sock, next = -1; - static time_t start_time[ICON_MODE_SOCKS]; - time_t oldest = 0; - int db = 0; - - for (i = 0; i < ICON_MODE_SOCKS; i++) { - if (icon_mode_socks[i] < 0) { - next = i; - break; - } - if (oldest == 0 || start_time[i] < oldest) { - next = i; - oldest = start_time[i]; - } - } - - p = strtok(str, ":"); - i = 0; - while (p) { - if (i == 0) { - host = strdup(p); - } else if (i == 1) { - port = atoi(p); - } else if (i == 2) { - cookie = strdup(p); - } - i++; - p = strtok(NULL, ":"); - } - free(str); - - if (db) fprintf(stderr, "%s/%d/%s next=%d\n", host, port, cookie, next); - - if (host && port && cookie) { - if (*host == '\0') { - free(host); - host = strdup("localhost"); - } - sock = rfbConnectToTcpAddr(host, port); - if (sock < 0) { - usleep(200 * 1000); - sock = rfbConnectToTcpAddr(host, port); - } - if (sock >= 0) { - char *lst = list_clients(); - icon_mode_socks[next] = sock; - start_time[next] = time(0); - write(sock, "COOKIE:", strlen("COOKIE:")); - write(sock, cookie, strlen(cookie)); - write(sock, "\n", strlen("\n")); - write(sock, "none\n", strlen("none\n")); - write(sock, "none\n", strlen("none\n")); - write(sock, lst, strlen(lst)); - write(sock, "\n", strlen("\n")); - if (db) { - fprintf(stderr, "list: %s\n", lst); - } - free(lst); - rfbLog("client_info_sock to: %s:%d\n", host, port); - } else { - rfbLog("failed client_info_sock: %s:%d\n", host, port); - } - } else { - rfbLog("malformed client_info_sock: %s\n", host_port_cookie); - } - - if (host) free(host); - if (cookie) free(cookie); -} - -void send_client_info(char *str) { - int i; - static char *pstr = NULL; - static int len = 128; - - if (!str || strlen(str) == 0) { - return; - } - - if (!pstr) { - pstr = (char *)malloc(len); - } - if (strlen(str) + 2 > (size_t) len) { - free(pstr); - len *= 2; - pstr = (char *)malloc(len); - } - strcpy(pstr, str); - strcat(pstr, "\n"); - - if (icon_mode_fh) { - fprintf(icon_mode_fh, "%s", pstr); - fflush(icon_mode_fh); - } - - for (i=0; i<ICON_MODE_SOCKS; i++) { - int len, n, sock = icon_mode_socks[i]; - char *buf = pstr; - - if (sock < 0) { - continue; - } - - len = strlen(pstr); - while (len > 0) { - n = write(sock, buf, len); - if (n > 0) { - buf += n; - len -= n; - continue; - } - - if (n < 0 && errno == EINTR) { - continue; - } - close(sock); - icon_mode_socks[i] = -1; - break; - } - } -} - -void check_new_clients(void) { - static int last_count = 0; - rfbClientIteratorPtr iter; - rfbClientPtr cl; - int i, send_info = 0; - - if (client_count == last_count) { - return; - } - - if (! all_clients_initialized()) { - return; - } - - last_count = client_count; - - if (! screen) { - return; - } - if (! client_count) { - send_client_info("none"); - return; - } - - iter = rfbGetClientIterator(screen); - while( (cl = rfbClientIteratorNext(iter)) ) { - ClientData *cd = (ClientData *) cl->clientData; - - if (cd->login_viewonly < 0) { - /* this is a general trigger to initialize things */ - if (cl->viewOnly) { - cd->login_viewonly = 1; - if (allowed_input_view_only) { - cl->viewOnly = FALSE; - cd->input[0] = '\0'; - strncpy(cd->input, - allowed_input_view_only, CILEN); - } - } else { - cd->login_viewonly = 0; - if (allowed_input_normal) { - cd->input[0] = '\0'; - strncpy(cd->input, - allowed_input_normal, CILEN); - } - } - } - } - rfbReleaseClientIterator(iter); - - if (icon_mode_fh) { - send_info++; - } - for (i = 0; i < ICON_MODE_SOCKS; i++) { - if (send_info || icon_mode_socks[i] >= 0) { - send_info++; - break; - } - } - if (send_info) { - char *str = list_clients(); - send_client_info(str); - free(str); - } -} - -/* -- keyboard.c -- */ -/* - * Routine to retreive current state keyboard. 1 means down, 0 up. - */ -void get_keystate(int *keystate) { - int i, k; - char keys[32]; - - /* n.b. caller decides to X_LOCK or not. */ - XQueryKeymap(dpy, keys); - for (i=0; i<32; i++) { - char c = keys[i]; - - for (k=0; k < 8; k++) { - if (c & 0x1) { - keystate[8*i + k] = 1; - } else { - keystate[8*i + k] = 0; - } - c = c >> 1; - } - } -} - -/* - * Try to KeyRelease any non-Lock modifiers that are down. - */ -void clear_modifiers(int init) { - static KeyCode keycodes[256]; - static KeySym keysyms[256]; - static char *keystrs[256]; - static int kcount = 0, first = 1; - int keystate[256]; - int i, j, minkey, maxkey, syms_per_keycode; - KeySym *keymap; - KeySym keysym; - KeyCode keycode; - - /* n.b. caller decides to X_LOCK or not. */ - if (first) { - /* - * we store results in static arrays, to aid interrupted - * case, but modifiers could have changed during session... - */ - XDisplayKeycodes(dpy, &minkey, &maxkey); - - keymap = XGetKeyboardMapping(dpy, minkey, (maxkey - minkey + 1), - &syms_per_keycode); - - for (i = minkey; i <= maxkey; i++) { - for (j = 0; j < syms_per_keycode; j++) { - keysym = keymap[ (i - minkey) * syms_per_keycode + j ]; - if (keysym == NoSymbol || ! ismodkey(keysym)) { - continue; - } - keycode = XKeysymToKeycode(dpy, keysym); - if (keycode == NoSymbol) { - continue; - } - keycodes[kcount] = keycode; - keysyms[kcount] = keysym; - keystrs[kcount] = strdup(XKeysymToString(keysym)); - kcount++; - } - } - XFree((void *) keymap); - first = 0; - } - if (init) { - return; - } - - get_keystate(keystate); - for (i=0; i < kcount; i++) { - keysym = keysyms[i]; - keycode = keycodes[i]; - - if (! keystate[(int) keycode]) { - continue; - } - - if (clear_mods) { - rfbLog("clear_modifiers: up: %-10s (0x%x) " - "keycode=0x%x\n", keystrs[i], keysym, keycode); - } - XTestFakeKeyEvent_wr(dpy, keycode, False, CurrentTime); - } - XFlush(dpy); -} - -KeySym simple_mods[] = { - XK_Shift_L, XK_Shift_R, - XK_Control_L, XK_Control_R, - XK_Meta_L, XK_Meta_R, - XK_Alt_L, XK_Alt_R, - XK_Super_L, XK_Super_R, - XK_Hyper_L, XK_Hyper_R, - XK_Mode_switch, - NoSymbol -}; -#define NSIMPLE_MODS 13 - -int track_mod_state(rfbKeySym keysym, rfbBool down, rfbBool set) { - KeySym sym = (KeySym) keysym; - static rfbBool isdown[NSIMPLE_MODS]; - static int first = 1; - int i, cnt = 0; - - /* - * simple tracking method for the modifier state without - * contacting the Xserver. Ignores, of course what keys are - * pressed on the physical display. - * - * This is unrelated to our mod_tweak and xkb stuff. - * Just a simple thing for wireframe/scroll heuristics, - * sloppy keys etc. - */ - - if (first) { - for (i=0; i<NSIMPLE_MODS; i++) { - isdown[i] = FALSE; - } - first = 0; - } - - if (sym != NoSymbol) { - for (i=0; i<NSIMPLE_MODS; i++) { - if (sym == simple_mods[i]) { - if (set) { - isdown[i] = down; - return 1; - } else { - if (isdown[i]) { - return 1; - } else { - return 0; - } - } - break; - } - } - /* not a modifier */ - if (set) { - return 0; - } else { - return -1; - } - } - - /* called with NoSymbol: return number currently pressed: */ - for (i=0; i<NSIMPLE_MODS; i++) { - if (isdown[i]) { - cnt++; - } - } - return cnt; -} - -/* - * Attempt to set all keys to Up position. Can mess up typing at the - * physical keyboard so use with caution. - */ -void clear_keys(void) { - int k, keystate[256]; - - /* n.b. caller decides to X_LOCK or not. */ - get_keystate(keystate); - for (k=0; k<256; k++) { - if (keystate[k]) { - KeyCode keycode = (KeyCode) k; - rfbLog("clear_keys: keycode=%d\n", keycode); - XTestFakeKeyEvent_wr(dpy, keycode, False, CurrentTime); - } - } - XFlush(dpy); -} - -/* - * Kludge for -norepeat option: we turn off keystroke autorepeat in - * the X server when clients are connected. This may annoy people at - * the physical display. We do this because 'key down' and 'key up' - * user input events may be separated by 100s of ms due to screen fb - * processing or link latency, thereby inducing the X server to apply - * autorepeat when it should not. Since the *client* is likely doing - * keystroke autorepeating as well, it kind of makes sense to shut it - * off if no one is at the physical display... - */ -static int save_auto_repeat = -1; - -int get_autorepeat_state(void) { - XKeyboardState kstate; - X_LOCK; - XGetKeyboardControl(dpy, &kstate); - X_UNLOCK; - return kstate.global_auto_repeat; -} - -int get_initial_autorepeat_state(void) { - if (save_auto_repeat < 0) { - save_auto_repeat = get_autorepeat_state(); - } - return save_auto_repeat; -} - -void autorepeat(int restore, int bequiet) { - int global_auto_repeat; - XKeyboardControl kctrl; - - if (raw_fb && ! dpy) return; /* raw_fb hack */ - - if (restore) { - if (save_auto_repeat < 0) { - return; /* nothing to restore */ - } - global_auto_repeat = get_autorepeat_state(); - X_LOCK; - /* read state and skip restore if equal (e.g. no clients) */ - if (global_auto_repeat == save_auto_repeat) { - X_UNLOCK; - return; - } - - kctrl.auto_repeat_mode = save_auto_repeat; - XChangeKeyboardControl(dpy, KBAutoRepeatMode, &kctrl); - XFlush(dpy); - X_UNLOCK; - - if (! bequiet && ! quiet) { - rfbLog("Restored X server key autorepeat to: %d\n", - save_auto_repeat); - } - } else { - global_auto_repeat = get_autorepeat_state(); - if (save_auto_repeat < 0) { - /* - * we only remember the state at startup - * to avoid confusing ourselves later on. - */ - save_auto_repeat = global_auto_repeat; - } - - X_LOCK; - kctrl.auto_repeat_mode = AutoRepeatModeOff; - XChangeKeyboardControl(dpy, KBAutoRepeatMode, &kctrl); - XFlush(dpy); - X_UNLOCK; - - if (! bequiet && ! quiet) { - rfbLog("Disabled X server key autorepeat.\n"); - if (no_repeat_countdown >= 0) { - rfbLog(" to force back on run: 'xset r on' (%d " - "times)\n", no_repeat_countdown+1); - } - } - } -} - -/* - * We periodically delete any keysyms we have added, this is to - * lessen our effect on the X server state if we are terminated abruptly - * and cannot clear them and also to clear out any strange little used - * ones that would just fill up the keymapping. - */ -void check_add_keysyms(void) { - static time_t last_check = 0; - int clear_freq = 300, quiet = 1, count; - time_t now = time(0); - if (now > last_check + clear_freq) { - count = count_added_keycodes(); - /* - * only really delete if they have not typed recently - * and we have added 8 or more. - */ - if (now > last_keyboard_input + 5 && count >= 8) { - X_LOCK; - delete_added_keycodes(quiet); - X_UNLOCK; - } - last_check = now; - } -} - -static KeySym added_keysyms[0x100]; - -/* these are just for rfbLog messages: */ -static KeySym alltime_added_keysyms[1024]; -static int alltime_len = 1024; -static int alltime_num = 0; - -int add_keysym(KeySym keysym) { - int minkey, maxkey, syms_per_keycode; - int kc, n, ret = 0; - static int first = 1; - KeySym *keymap; - - if (first) { - for (n=0; n < 0x100; n++) { - added_keysyms[n] = NoSymbol; - } - first = 0; - } - - if (raw_fb && ! dpy) return 0; /* raw_fb hack */ - - if (keysym == NoSymbol) { - return 0; - } - /* there can be a race before MappingNotify */ - for (n=0; n < 0x100; n++) { - if (added_keysyms[n] == keysym) { - return n; - } - } - - XDisplayKeycodes(dpy, &minkey, &maxkey); - keymap = XGetKeyboardMapping(dpy, minkey, (maxkey - minkey + 1), - &syms_per_keycode); - - for (kc = minkey+1; kc <= maxkey; kc++) { - int i, j, didmsg = 0, is_empty = 1; - char *str; - KeySym new[8]; - - for (n=0; n < syms_per_keycode; n++) { - if (keymap[ (kc-minkey) * syms_per_keycode + n] - != NoSymbol) { - is_empty = 0; - break; - } - } - if (! is_empty) { - continue; - } - - for (i=0; i<8; i++) { - new[i] = NoSymbol; - } - if (add_keysyms == 2) { - new[0] = keysym; /* XXX remove me */ - } else { - for(i=0; i < syms_per_keycode; i++) { - new[i] = keysym; - if (i >= 7) break; - } - } - - XChangeKeyboardMapping(dpy, kc, syms_per_keycode, - new, 1); - - if (alltime_num >= alltime_len) { - didmsg = 1; /* something weird */ - } else { - for (j=0; j<alltime_num; j++) { - if (alltime_added_keysyms[j] == keysym) { - didmsg = 1; - break; - } - } - } - if (! didmsg) { - str = XKeysymToString(keysym); - rfbLog("added missing keysym to X display: %03d " - "0x%x \"%s\"\n", kc, keysym, str ? str : "null"); - - if (alltime_num < alltime_len) { - alltime_added_keysyms[alltime_num++] = keysym; - } - } - - XFlush(dpy); - added_keysyms[kc] = keysym; - ret = kc; - break; - } - XFree(keymap); - return ret; -} - -void delete_keycode(KeyCode kc, int bequiet) { - int minkey, maxkey, syms_per_keycode, i; - KeySym *keymap; - KeySym ksym, new[8]; - char *str; - - if (raw_fb && ! dpy) return; /* raw_fb hack */ - - XDisplayKeycodes(dpy, &minkey, &maxkey); - keymap = XGetKeyboardMapping(dpy, minkey, (maxkey - minkey + 1), - &syms_per_keycode); - - for (i=0; i<8; i++) { - new[i] = NoSymbol; - } - - XChangeKeyboardMapping(dpy, kc, syms_per_keycode, new, 1); - - if (! bequiet && ! quiet) { - ksym = XKeycodeToKeysym(dpy, kc, 0); - str = XKeysymToString(ksym); - rfbLog("deleted keycode from X display: %03d 0x%x \"%s\"\n", - kc, ksym, str ? str : "null"); - } - - XFree(keymap); - XFlush(dpy); -} - -int count_added_keycodes(void) { - int kc, count = 0; - for (kc = 0; kc < 0x100; kc++) { - if (added_keysyms[kc] != NoSymbol) { - count++; - } - } - return count; -} - -void delete_added_keycodes(int bequiet) { - int kc; - for (kc = 0; kc < 0x100; kc++) { - if (added_keysyms[kc] != NoSymbol) { - delete_keycode(kc, bequiet); - added_keysyms[kc] = NoSymbol; - } - } -} - -/* - * The following is for an experimental -remap option to allow the user - * to remap keystrokes. It is currently confusing wrt modifiers... - */ -typedef struct keyremap { - KeySym before; - KeySym after; - int isbutton; - struct keyremap *next; -} keyremap_t; - -static keyremap_t *keyremaps = NULL; - -void add_remap(char *line) { - char str1[256], str2[256]; - KeySym ksym1, ksym2; - int isbtn = 0; - unsigned int i; - static keyremap_t *current = NULL; - keyremap_t *remap; - - if (sscanf(line, "%s %s", str1, str2) != 2) { - rfbLogEnable(1); - rfbLog("remap: invalid line: %s\n", line); - clean_up_exit(1); - } - if (sscanf(str1, "0x%x", &i) == 1) { - ksym1 = (KeySym) i; - } else { - ksym1 = XStringToKeysym(str1); - } - if (sscanf(str2, "0x%x", &i) == 1) { - ksym2 = (KeySym) i; - } else { - ksym2 = XStringToKeysym(str2); - } - if (ksym2 == NoSymbol) { - if (sscanf(str2, "Button%u", &i) == 1) { - ksym2 = (KeySym) i; - isbtn = 1; - } - } - if (ksym1 == NoSymbol || ksym2 == NoSymbol) { - rfbLog("warning: skipping invalid remap line: %s", line); - return; - } - remap = (keyremap_t *) malloc((size_t) sizeof(keyremap_t)); - remap->before = ksym1; - remap->after = ksym2; - remap->isbutton = isbtn; - remap->next = NULL; - - rfbLog("remapping: (%s, 0x%x) -> (%s, 0x%x) isbtn=%d\n", str1, - ksym1, str2, ksym2, isbtn); - - if (keyremaps == NULL) { - keyremaps = remap; - } else { - current->next = remap; - } - current = remap; -} - -void add_dead_keysyms(char *str) { - char *p, *q; - int i; - char *list[] = { - "g grave dead_grave", - "a acute dead_acute", - "c asciicircum dead_circumflex", - "t asciitilde dead_tilde", - "m macron dead_macron", - "b breve dead_breve", - "D abovedot dead_abovedot", - "d diaeresis dead_diaeresis", - "o degree dead_abovering", - "A doubleacute dead_doubleacute", - "r caron dead_caron", - "e cedilla dead_cedilla", -/* "x XXX-ogonek dead_ogonek", */ -/* "x XXX-belowdot dead_belowdot", */ -/* "x XXX-hook dead_hook", */ -/* "x XXX-horn dead_horn", */ - NULL - }; - - p = str; - - while (*p != '\0') { - if (isspace(*p)) { - *p = '\0'; - } - p++; - } - - if (!strcmp(str, "DEAD")) { - for (i = 0; list[i] != NULL; i++) { - p = list[i] + 2; - add_remap(p); - } - } else if (!strcmp(str, "DEAD=missing")) { - for (i = 0; list[i] != NULL; i++) { - KeySym ksym, ksym2; - int inmap = 0; - - p = strdup(list[i] + 2); - q = strchr(p, ' '); - if (q == NULL) { - free(p); - continue; - } - *q = '\0'; - ksym = XStringToKeysym(p); - *q = ' '; - if (ksym == NoSymbol) { - free(p); - continue; - } - if (XKeysymToKeycode(dpy, ksym)) { - inmap = 1; - } -#if LIBVNCSERVER_HAVE_XKEYBOARD - if (! inmap && xkb_present) { - int kc, grp, lvl; - for (kc = 0; kc < 0x100; kc++) { - for (grp = 0; grp < 4; grp++) { - for (lvl = 0; lvl < 8; lvl++) { - ksym2 = XkbKeycodeToKeysym(dpy, - kc, grp, lvl); - if (ksym2 == NoSymbol) { - continue; - } - if (ksym2 == ksym) { - inmap = 1; - break; - } - } - } - } - } -#endif - if (! inmap) { - add_remap(p); - } - free(p); - } - } else if ((p = strchr(str, '=')) != NULL) { - while (*p != '\0') { - for (i = 0; list[i] != NULL; i++) { - q = list[i]; - if (*p == *q) { - q += 2; - add_remap(q); - break; - } - } - p++; - } - } -} - -/* - * process the -remap string (file or mapping string) - */ -void initialize_remap(char *infile) { - FILE *in; - char *p, *q, line[256]; - - if (keyremaps != NULL) { - /* free last remapping */ - keyremap_t *next_remap, *curr_remap = keyremaps; - while (curr_remap != NULL) { - next_remap = curr_remap->next; - free(curr_remap); - curr_remap = next_remap; - } - keyremaps = NULL; - } - if (infile == NULL || *infile == '\0') { - /* just unset remapping */ - return; - } - - in = fopen(infile, "r"); - if (in == NULL) { - /* assume cmd line key1-key2,key3-key4 */ - if (strstr(infile, "DEAD") == infile) { - ; - } else if (!strchr(infile, '-')) { - rfbLogEnable(1); - rfbLog("remap: cannot open: %s\n", infile); - rfbLogPerror("fopen"); - clean_up_exit(1); - } - if ((in = tmpfile()) == NULL) { - rfbLogEnable(1); - rfbLog("remap: cannot open tmpfile for %s\n", infile); - rfbLogPerror("tmpfile"); - clean_up_exit(1); - } - - /* copy in the string to file format */ - p = infile; - while (*p) { - if (*p == '-') { - fprintf(in, " "); - } else if (*p == ',' || *p == ' ' || *p == '\t') { - fprintf(in, "\n"); - } else { - fprintf(in, "%c", *p); - } - p++; - } - fprintf(in, "\n"); - fflush(in); - rewind(in); - } - - while (fgets(line, 256, in) != NULL) { - p = lblanks(line); - if (*p == '\0') { - continue; - } - if (strchr(line, '#')) { - continue; - } - - if (strstr(p, "DEAD") == p) { - add_dead_keysyms(p); - continue; - } - if ((q = strchr(line, '-')) != NULL) { - /* allow Keysym1-Keysym2 notation */ - *q = ' '; - } - add_remap(p); - } - fclose(in); -} - -/* - * preliminary support for using the Xkb (XKEYBOARD) extension for handling - * user input. inelegant, slow, and incomplete currently... but initial - * tests show it is useful for some setups. - */ -typedef struct keychar { - KeyCode code; - int group; - int level; -} keychar_t; - -/* max number of key groups and shift levels we consider */ -#define GRP 4 -#define LVL 8 -static int lvl_max, grp_max, kc_min, kc_max; -static KeySym xkbkeysyms[0x100][GRP][LVL]; -static unsigned int xkbstate[0x100][GRP][LVL]; -static unsigned int xkbignore[0x100][GRP][LVL]; -static unsigned int xkbmodifiers[0x100][GRP][LVL]; -static int multi_key[0x100], mode_switch[0x100], skipkeycode[0x100]; -static int shift_keys[0x100]; - -/* - * for trying to order the keycodes to avoid problems, note the - * *first* keycode bound to it. kc_vec will be a permutation - * of 1...256 to get them in the preferred order. - */ -static int kc_vec[0x100]; -static int kc1_shift, kc1_control, kc1_caplock, kc1_alt; -static int kc1_meta, kc1_numlock, kc1_super, kc1_hyper; -static int kc1_mode_switch, kc1_iso_level3_shift, kc1_multi_key; - -int sloppy_key_check(int key, rfbBool down, rfbKeySym keysym, int *new) { - if (!sloppy_keys) { - return 0; - } - - if (!down && !keycode_state[key] && !IsModifierKey(keysym)) { - int i, cnt = 0, downkey; - int nmods_down = track_mod_state(NoSymbol, FALSE, FALSE); - int mods_down[256]; - - if (nmods_down) { - /* tracking to skip down modifier keycodes. */ - for(i=0; i<256; i++) { - mods_down[i] = 0; - } - i = 0; - while (simple_mods[i] != NoSymbol) { - KeySym ksym = simple_mods[i]; - KeyCode k = XKeysymToKeycode(dpy, ksym); - if (k != NoSymbol && keycode_state[(int) k]) { - mods_down[(int) k] = 1; - } - - i++; - } - } - /* - * the keycode is already up... look for a single one - * (non modifier) that is down - */ - for (i=0; i<256; i++) { - if (keycode_state[i]) { - if (nmods_down && mods_down[i]) { - continue; - } - cnt++; - downkey = i; - } - } - if (cnt == 1) { - if (debug_keyboard) { - fprintf(stderr, " sloppy_keys: %d/0x%x " - "-> %d/0x%x (nmods: %d)\n", (int) key, - (int) key, downkey, downkey, nmods_down); - } - *new = downkey; - return 1; - } - } - return 0; -} - -#if !LIBVNCSERVER_HAVE_XKEYBOARD - -/* empty functions for no xkb */ -static void initialize_xkb_modtweak(void) {} -static void xkb_tweak_keyboard(rfbBool down, rfbKeySym keysym, - rfbClientPtr client) { -} -static void switch_to_xkb_if_better(void) {} - -#else - -static void switch_to_xkb_if_better(void) { - KeySym keysym, *keymap; - int miss_noxkb[256], miss_xkb[256], missing_noxkb = 0, missing_xkb = 0; - int i, j, k, n, minkey, maxkey, syms_per_keycode; - int syms_gt_4 = 0; - int kc, grp, lvl; - - /* non-alphanumeric on us keyboard */ - KeySym must_have[] = { - XK_exclam, - XK_at, - XK_numbersign, - XK_dollar, - XK_percent, -/* XK_asciicircum, */ - XK_ampersand, - XK_asterisk, - XK_parenleft, - XK_parenright, - XK_underscore, - XK_plus, - XK_minus, - XK_equal, - XK_bracketleft, - XK_bracketright, - XK_braceleft, - XK_braceright, - XK_bar, - XK_backslash, - XK_semicolon, -/* XK_apostrophe, */ - XK_colon, - XK_quotedbl, - XK_comma, - XK_period, - XK_less, - XK_greater, - XK_slash, - XK_question, -/* XK_asciitilde, */ -/* XK_grave, */ - NoSymbol - }; - - if (! use_modifier_tweak || got_noxkb) { - return; - } - if (use_xkb_modtweak) { - /* already using it */ - return; - } - - XDisplayKeycodes(dpy, &minkey, &maxkey); - - keymap = XGetKeyboardMapping(dpy, minkey, (maxkey - minkey + 1), - &syms_per_keycode); - - /* handle alphabetic char with only one keysym (no upper + lower) */ - for (i = minkey; i <= maxkey; i++) { - KeySym lower, upper; - /* 2nd one */ - keysym = keymap[(i - minkey) * syms_per_keycode + 1]; - if (keysym != NoSymbol) { - continue; - } - /* 1st one */ - keysym = keymap[(i - minkey) * syms_per_keycode + 0]; - if (keysym == NoSymbol) { - continue; - } - XConvertCase(keysym, &lower, &upper); - if (lower != upper) { - keymap[(i - minkey) * syms_per_keycode + 0] = lower; - keymap[(i - minkey) * syms_per_keycode + 1] = upper; - } - } - - k = 0; - while (must_have[k] != NoSymbol) { - int gotit = 0; - KeySym must = must_have[k]; - for (i = minkey; i <= maxkey; i++) { - for (j = 0; j < syms_per_keycode; j++) { - keysym = keymap[(i-minkey) * syms_per_keycode + j]; - if (j >= 4) { - if (k == 0 && keysym != NoSymbol) { - /* for k=0 count the high keysyms */ - syms_gt_4++; - if (debug_keyboard > 1) { - char *str = XKeysymToString(keysym); - fprintf(stderr, "- high keysym mapping" - ": at %3d j=%d " - "'%s'\n", i, j, str ? str:"null"); - } - } - continue; - } - if (keysym == must) { - if (debug_keyboard > 1) { - char *str = XKeysymToString(must); - fprintf(stderr, "- at %3d j=%d found " - "'%s'\n", i, j, str ? str:"null"); - } - /* n.b. do not break, see syms_gt_4 above. */ - gotit = 1; - } - } - } - if (! gotit) { - if (debug_keyboard > 1) { - char *str = XKeysymToString(must); - KeyCode kc = XKeysymToKeycode(dpy, must); - fprintf(stderr, "- did not find 0x%lx '%s'\t" - "Ks2Kc: %d\n", must, str ? str:"null", kc); - if (kc != None) { - int j2; - for(j2=0; j2<syms_per_keycode; j2++) { - keysym = keymap[(kc-minkey) * - syms_per_keycode + j2]; - fprintf(stderr, " %d=0x%lx", - j2, keysym); - } - fprintf(stderr, "\n"); - } - } - missing_noxkb++; - miss_noxkb[k] = 1; - } else { - miss_noxkb[k] = 0; - } - k++; - } - n = k; - - XFree(keymap); - if (missing_noxkb == 0 && syms_gt_4 >= 8) { - rfbLog("XKEYBOARD: number of keysyms per keycode %d " - "is greater\n", syms_per_keycode); - rfbLog(" than 4 and %d keysyms are mapped above 4.\n", - syms_gt_4); - rfbLog(" Automatically switching to -xkb mode.\n"); - rfbLog(" If this makes the key mapping worse you can\n"); - rfbLog(" disable it with the \"-noxkb\" option.\n"); - rfbLog(" Also, remember \"-remap DEAD\" for accenting" - " characters.\n"); - - use_xkb_modtweak = 1; - return; - - } else if (missing_noxkb == 0) { - rfbLog("XKEYBOARD: all %d \"must have\" keysyms accounted" - " for.\n", n); - rfbLog(" Not automatically switching to -xkb mode.\n"); - rfbLog(" If some keys still cannot be typed, try using" - " -xkb.\n"); - rfbLog(" Also, remember \"-remap DEAD\" for accenting" - " characters.\n"); - return; - } - - for (k=0; k<n; k++) { - miss_xkb[k] = 1; - } - - for (kc = 0; kc < 0x100; kc++) { - for (grp = 0; grp < GRP; grp++) { - for (lvl = 0; lvl < LVL; lvl++) { - /* look up the Keysym, if any */ - keysym = XkbKeycodeToKeysym(dpy, kc, grp, lvl); - if (keysym == NoSymbol) { - continue; - } - for (k=0; k<n; k++) { - if (keysym == must_have[k]) { - miss_xkb[k] = 0; - } - } - } - } - } - - for (k=0; k<n; k++) { - if (miss_xkb[k]) { - missing_xkb++; - } - } - - rfbLog("\n"); - if (missing_xkb < missing_noxkb) { - rfbLog("XKEYBOARD:\n"); - rfbLog("Switching to -xkb mode to recover these keysyms:\n"); - } else { - rfbLog("XKEYBOARD: \"must have\" keysyms better accounted" - " for\n"); - rfbLog("under -noxkb mode: not switching to -xkb mode:\n"); - } - - rfbLog(" xkb noxkb Keysym (\"X\" means present)\n"); - rfbLog(" --- ----- -----------------------------\n"); - for (k=0; k<n; k++) { - char *xx, *xn, *name; - - keysym = must_have[k]; - if (keysym == NoSymbol) { - continue; - } - if (!miss_xkb[k] && !miss_noxkb[k]) { - continue; - } - if (miss_xkb[k]) { - xx = " "; - } else { - xx = " X "; - } - if (miss_noxkb[k]) { - xn = " "; - } else { - xn = " X "; - } - name = XKeysymToString(keysym); - rfbLog(" %s %s 0x%lx %s\n", xx, xn, keysym, - name ? name : "null"); - } - rfbLog("\n"); - - if (missing_xkb < missing_noxkb) { - rfbLog(" If this makes the key mapping worse you can\n"); - rfbLog(" disable it with the \"-noxkb\" option.\n"); - rfbLog("\n"); - - use_xkb_modtweak = 1; - - } else { - rfbLog(" If some keys still cannot be typed, try using" - " -xkb.\n"); - rfbLog(" Also, remember \"-remap DEAD\" for accenting" - " characters.\n"); - } -} - -/* sets up all the keymapping info via Xkb API */ - -static void initialize_xkb_modtweak(void) { - KeySym ks; - int kc, grp, lvl, k; - unsigned int state; - -/* - * Here is a guide: - -Workarounds arrays: - -multi_key[] indicates which keycodes have Multi_key (Compose) - bound to them. -mode_switch[] indicates which keycodes have Mode_switch (AltGr) - bound to them. -shift_keys[] indicates which keycodes have Shift bound to them. -skipkeycode[] indicates which keycodes are to be skipped - for any lookups from -skip_keycodes option. - -Groups and Levels, here is an example: - - ^ -------- - | L2 | A AE | - shift | | - level L1 | a ae | - -------- - G1 G2 - - group -> - -Traditionally this it all a key could do. L1 vs. L2 selected via Shift -and G1 vs. G2 selected via Mode_switch. Up to 4 Keysyms could be bound -to a key. See initialize_modtweak() for an example of using that type -of keymap from XGetKeyboardMapping(). - -Xkb gives us up to 4 groups and 63 shift levels per key, with the -situation being potentially different for each key. This is complicated, -and I don't claim to understand it all, but in the following we just think -of ranging over the group and level indices as covering all of the cases. -This gives us an accurate view of the keymap. The main tricky part -is mapping between group+level and modifier state. - -On current linux/XFree86 setups (Xkb is enabled by default) the -information from XGetKeyboardMapping() (evidently the compat map) -is incomplete and inaccurate, so we are really forced to use the -Xkb API. - -xkbkeysyms[] For a (keycode,group,level) holds the KeySym (0 for none) -xkbstate[] For a (keycode,group,level) holds the corresponding - modifier state needed to get that KeySym -xkbignore[] For a (keycode,group,level) which modifiers can be - ignored (the 0 bits can be ignored). -xkbmodifiers[] For the KeySym bound to this (keycode,group,level) store - the modifier mask. - * - */ - - /* initialize all the arrays: */ - for (kc = 0; kc < 0x100; kc++) { - multi_key[kc] = 0; - mode_switch[kc] = 0; - skipkeycode[kc] = 0; - shift_keys[kc] = 0; - - for (grp = 0; grp < GRP; grp++) { - for (lvl = 0; lvl < LVL; lvl++) { - xkbkeysyms[kc][grp][lvl] = NoSymbol; - xkbmodifiers[kc][grp][lvl] = -1; - xkbstate[kc][grp][lvl] = -1; - } - } - } - - /* - * the array is 256*LVL*GRP, but we can make the searched region - * smaller by computing the actual ranges. - */ - lvl_max = 0; - grp_max = 0; - kc_max = 0; - kc_min = 0x100; - - /* first keycode for a modifier type (multi_key too) */ - kc1_shift = -1; - kc1_control = -1; - kc1_caplock = -1; - kc1_alt = -1; - kc1_meta = -1; - kc1_numlock = -1; - kc1_super = -1; - kc1_hyper = -1; - kc1_mode_switch = -1; - kc1_iso_level3_shift = -1; - kc1_multi_key = -1; - - /* - * loop over all possible (keycode, group, level) triples - * and record what we find for it: - */ - if (debug_keyboard > 1) { - rfbLog("initialize_xkb_modtweak: XKB keycode -> keysyms " - "mapping info:\n"); - } - for (kc = 0; kc < 0x100; kc++) { - for (grp = 0; grp < GRP; grp++) { - for (lvl = 0; lvl < LVL; lvl++) { - unsigned int ms, mods; - int state_save = -1, mods_save; - KeySym ks2; - - /* look up the Keysym, if any */ - ks = XkbKeycodeToKeysym(dpy, kc, grp, lvl); - xkbkeysyms[kc][grp][lvl] = ks; - - /* if no Keysym, on to next */ - if (ks == NoSymbol) { - continue; - } - /* - * for various workarounds, note where these special - * keys are bound to. - */ - if (ks == XK_Multi_key) { - multi_key[kc] = lvl+1; - } - if (ks == XK_Mode_switch) { - mode_switch[kc] = lvl+1; - } - if (ks == XK_Shift_L || ks == XK_Shift_R) { - shift_keys[kc] = lvl+1; - } - - if (ks == XK_Shift_L || ks == XK_Shift_R) { - if (kc1_shift == -1) { - kc1_shift = kc; - } - } - if (ks == XK_Control_L || ks == XK_Control_R) { - if (kc1_control == -1) { - kc1_control = kc; - } - } - if (ks == XK_Caps_Lock || ks == XK_Caps_Lock) { - if (kc1_caplock == -1) { - kc1_caplock = kc; - } - } - if (ks == XK_Alt_L || ks == XK_Alt_R) { - if (kc1_alt == -1) { - kc1_alt = kc; - } - } - if (ks == XK_Meta_L || ks == XK_Meta_R) { - if (kc1_meta == -1) { - kc1_meta = kc; - } - } - if (ks == XK_Num_Lock) { - if (kc1_numlock == -1) { - kc1_numlock = kc; - } - } - if (ks == XK_Super_L || ks == XK_Super_R) { - if (kc1_super == -1) { - kc1_super = kc; - } - } - if (ks == XK_Hyper_L || ks == XK_Hyper_R) { - if (kc1_hyper == -1) { - kc1_hyper = kc; - } - } - if (ks == XK_Mode_switch) { - if (kc1_mode_switch == -1) { - kc1_mode_switch = kc; - } - } - if (ks == XK_ISO_Level3_Shift) { - if (kc1_iso_level3_shift == -1) { - kc1_iso_level3_shift = kc; - } - } - if (ks == XK_Multi_key) { /* not a modifier.. */ - if (kc1_multi_key == -1) { - kc1_multi_key = kc; - } - } - - /* - * record maximum extent for group/level indices - * and keycode range: - */ - if (grp > grp_max) { - grp_max = grp; - } - if (lvl > lvl_max) { - lvl_max = lvl; - } - if (kc > kc_max) { - kc_max = kc; - } - if (kc < kc_min) { - kc_min = kc; - } - - /* - * lookup on *keysym* (i.e. not kc, grp, lvl) - * and get the modifier mask. this is 0 for - * most keysyms, only non zero for modifiers. - */ - ms = XkbKeysymToModifiers(dpy, ks); - xkbmodifiers[kc][grp][lvl] = ms; - - /* - * Amusing heuristic (may have bugs). There are - * 8 modifier bits, so 256 possible modifier - * states. We loop over all of them for this - * keycode (simulating Key "events") and ask - * XkbLookupKeySym to tell us the Keysym. Once it - * matches the Keysym we have for this (keycode, - * group, level), gotten via XkbKeycodeToKeysym() - * above, we then (hopefully...) know that state - * of modifiers needed to generate this keysym. - * - * Yes... keep your fingers crossed. - * - * Note that many of the 256 states give the - * Keysym, we just need one, and we take the - * first one found. - */ - state = 0; - while(state < 256) { - if (XkbLookupKeySym(dpy, kc, state, &mods, - &ks2)) { - - /* save these for workaround below */ - if (state_save == -1) { - state_save = state; - mods_save = mods; - } - if (ks2 == ks) { - /* - * zero the irrelevant bits - * by anding with mods. - */ - xkbstate[kc][grp][lvl] - = state & mods; - /* - * also remember the irrelevant - * bits since it is handy. - */ - xkbignore[kc][grp][lvl] = mods; - - break; - } - } - state++; - } - if (xkbstate[kc][grp][lvl] == (unsigned int) -1 - && grp == 1) { - /* - * Hack on Solaris 9 for Mode_switch - * for Group2 characters. We force the - * Mode_switch modifier bit on. - * XXX Need to figure out better what is - * happening here. Is compat on somehow?? - */ - unsigned int ms2; - ms2 = XkbKeysymToModifiers(dpy, XK_Mode_switch); - - xkbstate[kc][grp][lvl] - = (state_save & mods_save) | ms2; - - xkbignore[kc][grp][lvl] = mods_save | ms2; - } - - if (debug_keyboard > 1) { - fprintf(stderr, " %03d G%d L%d mod=%s ", - kc, grp+1, lvl+1, bitprint(ms, 8)); - fprintf(stderr, "state=%s ", - bitprint(xkbstate[kc][grp][lvl], 8)); - fprintf(stderr, "ignore=%s ", - bitprint(xkbignore[kc][grp][lvl], 8)); - fprintf(stderr, " ks=0x%08lx \"%s\"\n", - ks, XKeysymToString(ks)); - } - } - } - } - - /* - * kc_vec will be used in some places to find modifiers, etc - * we apply some permutations to it as workarounds. - */ - for (kc = 0; kc < 0x100; kc++) { - kc_vec[kc] = kc; - } - - if (kc1_mode_switch != -1 && kc1_iso_level3_shift != -1) { - if (kc1_mode_switch < kc1_iso_level3_shift) { - /* we prefer XK_ISO_Level3_Shift: */ - kc_vec[kc1_mode_switch] = kc1_iso_level3_shift; - kc_vec[kc1_iso_level3_shift] = kc1_mode_switch; - } - } - /* any more? need to watch for undoing the above. */ - - /* - * process the user supplied -skip_keycodes string. - * This is presumably a list if "ghost" keycodes, the X server - * thinks they exist, but they do not. ghosts can lead to - * ambiguities in the reverse map: Keysym -> KeyCode + Modstate, - * so if we can ignore them so much the better. Presumably the - * user can never generate them from the physical keyboard. - * There may be other reasons to deaden some keys. - */ - if (skip_keycodes != NULL) { - char *p, *str = strdup(skip_keycodes); - p = strtok(str, ", \t\n\r"); - while (p) { - k = 1; - if (sscanf(p, "%d", &k) != 1 || k < 0 || k >= 0x100) { - rfbLogEnable(1); - rfbLog("invalid skip_keycodes: %s %s\n", - skip_keycodes, p); - clean_up_exit(1); - } - skipkeycode[k] = 1; - p = strtok(NULL, ", \t\n\r"); - } - free(str); - } - if (debug_keyboard > 1) { - fprintf(stderr, "grp_max=%d lvl_max=%d\n", grp_max, lvl_max); - } -} - -/* - * Called on user keyboard input. Try to solve the reverse mapping - * problem: KeySym (from VNC client) => KeyCode(s) to press to generate - * it. The one-to-many KeySym => KeyCode mapping makes it difficult, as - * does working out what changes to the modifier keypresses are needed. - */ -static void xkb_tweak_keyboard(rfbBool down, rfbKeySym keysym, - rfbClientPtr client) { - - int kc, grp, lvl, i, kci; - int kc_f[0x100], grp_f[0x100], lvl_f[0x100], state_f[0x100], found; - int ignore_f[0x100]; - unsigned int state; - - - /* these are used for finding modifiers, etc */ - XkbStateRec kbstate; - int got_kbstate = 0; - int Kc_f, Grp_f, Lvl_f; - static int Kc_last_down = -1; - static KeySym Ks_last_down = NoSymbol; - - if (client) {} /* unused vars warning: */ - - X_LOCK; - - if (debug_keyboard) { - char *str = XKeysymToString(keysym); - - if (debug_keyboard > 1) { - rfbLog("----------start-xkb_tweak_keyboard (%s) " - "--------\n", down ? "DOWN" : "UP"); - } - - rfbLog("xkb_tweak_keyboard: %s keysym=0x%x \"%s\"\n", - down ? "down" : "up", (int) keysym, str ? str : "null"); - } - - /* - * set everything to not-yet-found. - * these "found" arrays (*_f) let us dynamically consider the - * one-to-many Keysym -> Keycode issue. we set the size at 256, - * but of course only very few will be found. - */ - for (i = 0; i < 0x100; i++) { - kc_f[i] = -1; - grp_f[i] = -1; - lvl_f[i] = -1; - state_f[i] = -1; - ignore_f[i] = -1; - } - found = 0; - - /* - * loop over all (keycode, group, level) triples looking for - * matching keysyms. Amazingly this isn't slow (but maybe if - * you type really fast...). Hash lookup into a linked list of - * (keycode,grp,lvl) triples would be the way to improve this - * in the future if needed. - */ - for (kc = kc_min; kc <= kc_max; kc++) { - for (grp = 0; grp < grp_max+1; grp++) { - for (lvl = 0; lvl < lvl_max+1; lvl++) { - if (keysym != xkbkeysyms[kc][grp][lvl]) { - continue; - } - /* got a keysym match */ - state = xkbstate[kc][grp][lvl]; - - if (debug_keyboard > 1) { - fprintf(stderr, " got match kc=%03d=0x%02x G%d" - " L%d ks=0x%x \"%s\" (basesym: \"%s\")\n", - kc, kc, grp+1, lvl+1, keysym, - XKeysymToString(keysym), XKeysymToString( - XKeycodeToKeysym(dpy, kc, 0))); - fprintf(stderr, " need state: %s\n", - bitprint(state, 8)); - fprintf(stderr, " ignorable : %s\n", - bitprint(xkbignore[kc][grp][lvl], 8)); - } - - /* save it if state is OK and not told to skip */ - if (state == (unsigned int) -1) { - continue; - } - if (skipkeycode[kc] && debug_keyboard) { - fprintf(stderr, " xxx skipping keycode: %d " - "G%d/L%d\n", kc, grp+1, lvl+1); - } - if (skipkeycode[kc]) { - continue; - } - if (found > 0 && kc == kc_f[found-1]) { - /* ignore repeats for same keycode */ - continue; - } - kc_f[found] = kc; - grp_f[found] = grp; - lvl_f[found] = lvl; - state_f[found] = state; - ignore_f[found] = xkbignore[kc][grp][lvl]; - found++; - } - } - } - -#define PKBSTATE \ - fprintf(stderr, " --- current mod state:\n"); \ - fprintf(stderr, " mods : %s\n", bitprint(kbstate.mods, 8)); \ - fprintf(stderr, " base_mods : %s\n", bitprint(kbstate.base_mods, 8)); \ - fprintf(stderr, " latch_mods: %s\n", bitprint(kbstate.latched_mods, 8)); \ - fprintf(stderr, " lock_mods : %s\n", bitprint(kbstate.locked_mods, 8)); \ - fprintf(stderr, " compat : %s\n", bitprint(kbstate.compat_state, 8)); - - /* - * Now get the current state of the keyboard from the X server. - * This seems to be the safest way to go as opposed to our - * keeping track of the modifier state on our own. Again, - * this is fortunately not too slow. - */ - - if (debug_keyboard > 1) { - /* get state early for debug output */ - XkbGetState(dpy, XkbUseCoreKbd, &kbstate); - got_kbstate = 1; - PKBSTATE - } - - if (!found && add_keysyms && keysym && ! IsModifierKey(keysym)) { - int new_kc = add_keysym(keysym); - if (new_kc != 0) { - found = 1; - kc_f[0] = new_kc; - grp_f[0] = 0; - lvl_f[0] = 0; - state_f[0] = 0; - } - } - - if (!found && debug_keyboard) { - char *str = XKeysymToString(keysym); - fprintf(stderr, " *** NO key found for: 0x%x %s " - "*keystroke ignored*\n", keysym, str ? str : "null"); - } - if (!found) { - X_UNLOCK; - return; - } - - /* - * we try to optimize here if found > 1 - * e.g. minimize lvl or grp, or other things to give - * "safest" scenario to simulate the keystrokes. - */ - - if (found > 1) { - if (down) { - int l, score[0x100]; - int best, best_score = -1; - /* need to break the tie... */ - if (! got_kbstate) { - XkbGetState(dpy, XkbUseCoreKbd, &kbstate); - got_kbstate = 1; - } - for (l=0; l < found; l++) { - int myscore = 0, b = 0x1, i; - int curr, curr_state = kbstate.mods; - int need, need_state = state_f[l]; - int ignore_state = ignore_f[l]; - - /* see how many modifiers need to be changed */ - for (i=0; i<8; i++) { - curr = b & curr_state; - need = b & need_state; - if (! (b & ignore_state)) { - ; - } else if (curr == need) { - ; - } else { - myscore++; - } - b = b << 1; - } - myscore *= 100; - - /* throw in some minimization of lvl too: */ - myscore += 2*lvl_f[l] + grp_f[l]; - - /* - * XXX since we now internally track - * keycode_state[], we could throw that into - * the score as well. I.e. if it is already - * down, it is pointless to think we can - * press it down further! E.g. - * myscore += 1000 * keycode_state[kc_f[l]]; - * Also could watch multiple modifier - * problem, e.g. Shift+key -> Alt - * keycode = 125 on my keyboard. - */ - - score[l] = myscore; - if (debug_keyboard > 1) { - fprintf(stderr, " *** score for " - "keycode %03d: %4d\n", - kc_f[l], myscore); - } - } - for (l=0; l < found; l++) { - int myscore = score[l]; - if (best_score == -1 || myscore < best_score) { - best = l; - best_score = myscore; - } - } - Kc_f = kc_f[best]; - Grp_f = grp_f[best]; - Lvl_f = lvl_f[best]; - state = state_f[best]; - - } else { - /* up */ - Kc_f = -1; - if (keysym == Ks_last_down) { - int l; - for (l=0; l < found; l++) { - if (Kc_last_down == kc_f[l]) { - Kc_f = Kc_last_down; - break; - } - } - } - if (Kc_f == -1) { - int l; - /* - * If it is already down, that is - * a great hint. Use it. - * - * note: keycode_state in internal and - * ignores someone pressing keys on the - * physical display (but is updated - * periodically to clean out stale info). - */ - for (l=0; l < found; l++) { - int key = (int) kc_f[l]; - if (keycode_state[key]) { - Kc_f = kc_f[l]; - break; - } - } - } - - if (Kc_f == -1) { - /* hope for the best... XXX check mods */ - Kc_f = kc_f[0]; - } - } - } else { - Kc_f = kc_f[0]; - Grp_f = grp_f[0]; - Lvl_f = lvl_f[0]; - state = state_f[0]; - } - - if (debug_keyboard && found > 1) { - int l; - char *str; - fprintf(stderr, " *** found more than one keycode: "); - for (l = 0; l < found; l++) { - fprintf(stderr, "%03d ", kc_f[l]); - } - for (l = 0; l < found; l++) { - str = XKeysymToString(XKeycodeToKeysym(dpy,kc_f[l],0)); - fprintf(stderr, " \"%s\"", str ? str : "null"); - } - fprintf(stderr, ", picked this one: %03d (last down: %03d)\n", - Kc_f, Kc_last_down); - } - - if (sloppy_keys) { - int new_kc; - if (sloppy_key_check(Kc_f, down, keysym, &new_kc)) { - Kc_f = new_kc; - } - } - - if (down) { - /* - * need to set up the mods for tweaking and other workarounds - */ - int needmods[8], sentmods[8], Ilist[8], keystate[256]; - int involves_multi_key, shift_is_down; - int i, j, b, curr, need; - unsigned int ms; - KeySym ks; - Bool dn; - - /* remember these to aid the subsequent up case: */ - Ks_last_down = keysym; - Kc_last_down = Kc_f; - - if (! got_kbstate) { - /* get the current modifier state if we haven't yet */ - XkbGetState(dpy, XkbUseCoreKbd, &kbstate); - got_kbstate = 1; - } - - /* - * needmods[] whether or not that modifier bit needs - * something done to it. - * < 0 means no, - * 0 means needs to go up. - * 1 means needs to go down. - * - * -1, -2, -3 are used for debugging info to indicate - * why nothing needs to be done with the modifier, see below. - * - * sentmods[] is the corresponding keycode to use - * to acheive the needmods[] requirement for the bit. - */ - - for (i=0; i<8; i++) { - needmods[i] = -1; - sentmods[i] = 0; - } - - /* - * Loop over the 8 modifier bits and check if the current - * setting is what we need it to be or whether it should - * be changed (by us sending some keycode event) - * - * If nothing needs to be done to it record why: - * -1 the modifier bit is ignored. - * -2 the modifier bit is ignored, but is correct anyway. - * -3 the modifier bit is correct. - */ - - b = 0x1; - for (i=0; i<8; i++) { - curr = b & kbstate.mods; - need = b & state; - - if (! (b & xkbignore[Kc_f][Grp_f][Lvl_f])) { - /* irrelevant modifier bit */ - needmods[i] = -1; - if (curr == need) needmods[i] = -2; - } else if (curr == need) { - /* already correct */ - needmods[i] = -3; - } else if (! curr && need) { - /* need it down */ - needmods[i] = 1; - } else if (curr && ! need) { - /* need it up */ - needmods[i] = 0; - } - - b = b << 1; - } - - /* - * Again we dynamically probe the X server for information, - * this time for the state of all the keycodes. Useful - * info, and evidently is not too slow... - */ - get_keystate(keystate); - - /* - * We try to determine if Shift is down (since that can - * screw up ISO_Level3_Shift manipulations). - */ - shift_is_down = 0; - - for (kc = kc_min; kc <= kc_max; kc++) { - if (skipkeycode[kc] && debug_keyboard) { - fprintf(stderr, " xxx skipping keycode: " - "%d\n", kc); - } - if (skipkeycode[kc]) { - continue; - } - if (shift_keys[kc] && keystate[kc]) { - shift_is_down = kc; - break; - } - } - - /* - * Now loop over the modifier bits and try to deduce the - * keycode presses/release require to match the desired - * state. - */ - for (i=0; i<8; i++) { - if (needmods[i] < 0 && debug_keyboard > 1) { - int k = -needmods[i] - 1; - char *words[] = {"ignorable", - "bitset+ignorable", "bitset"}; - fprintf(stderr, " +++ needmods: mod=%d is " - "OK (%s)\n", i, words[k]); - } - if (needmods[i] < 0) { - continue; - } - - b = 1 << i; - - if (debug_keyboard > 1) { - fprintf(stderr, " +++ needmods: mod=%d %s " - "need it to be: %d %s\n", i, bitprint(b, 8), - needmods[i], needmods[i] ? "down" : "up"); - } - - /* - * Again, an inefficient loop, this time just - * looking for modifiers... - * - * note the use of kc_vec to prefer XK_ISO_Level3_Shift - * over XK_Mode_switch. - */ - for (kci = kc_min; kci <= kc_max; kci++) { - for (grp = 0; grp < grp_max+1; grp++) { - for (lvl = 0; lvl < lvl_max+1; lvl++) { - int skip = 1, dbmsg = 0; - - kc = kc_vec[kci]; - - ms = xkbmodifiers[kc][grp][lvl]; - if (! ms || ms != (unsigned int) b) { - continue; - } - - if (skipkeycode[kc] && debug_keyboard) { - fprintf(stderr, " xxx skipping keycode:" - " %d G%d/L%d\n", kc, grp+1, lvl+1); - } - if (skipkeycode[kc]) { - continue; - } - - ks = xkbkeysyms[kc][grp][lvl]; - if (! ks) { - continue; - } - - if (ks == XK_Shift_L) { - skip = 0; - } else if (ks == XK_Shift_R) { - skip = 0; - } else if (ks == XK_Mode_switch) { - skip = 0; - } else if (ks == XK_ISO_Level3_Shift) { - skip = 0; - } - /* - * Alt, Meta, Control, Super, - * Hyper, Num, Caps are skipped. - * - * XXX need more work on Locks, - * and non-standard modifiers. - * (e.g. XF86_Next_VMode using - * Ctrl+Alt) - */ - if (debug_keyboard > 1) { - char *str = XKeysymToString(ks); - int kt = keystate[kc]; - fprintf(stderr, " === for mod=%s " - "found kc=%03d/G%d/L%d it is %d " - "%s skip=%d (%s)\n", bitprint(b,8), - kc, grp+1, lvl+1, kt, kt ? - "down" : "up ", skip, str ? - str : "null"); - } - - if (! skip && needmods[i] != - keystate[kc] && sentmods[i] == 0) { - sentmods[i] = kc; - dbmsg = 1; - } - - if (debug_keyboard > 1 && dbmsg) { - int nm = needmods[i]; - fprintf(stderr, " >>> we choose " - "kc=%03d=0x%02x to change it to: " - "%d %s\n", kc, kc, nm, nm ? - "down" : "up"); - } - - } - } - } - } - for (i=0; i<8; i++) { - /* - * reverse order is useful for tweaking - * ISO_Level3_Shift before Shift, but assumes they - * are in that order (i.e. Shift is first bit). - */ - int reverse = 1; - if (reverse) { - Ilist[i] = 7 - i; - } else { - Ilist[i] = i; - } - } - - /* - * check to see if Multi_key is bound to one of the Mods - * we have to tweak - */ - involves_multi_key = 0; - for (j=0; j<8; j++) { - i = Ilist[j]; - if (sentmods[i] == 0) continue; - dn = (Bool) needmods[i]; - if (!dn) continue; - if (multi_key[sentmods[i]]) { - involves_multi_key = i+1; - } - } - - if (involves_multi_key && shift_is_down && needmods[0] < 0) { - /* - * Workaround for Multi_key and shift. - * Assumes Shift is bit 1 (needmods[0]) - */ - if (debug_keyboard) { - fprintf(stderr, " ^^^ trying to avoid " - "inadvertent Multi_key from Shift " - "(doing %03d up now)\n", shift_is_down); - } - XTestFakeKeyEvent_wr(dpy, shift_is_down, False, - CurrentTime); - } else { - involves_multi_key = 0; - } - - for (j=0; j<8; j++) { - /* do the Mod ups */ - i = Ilist[j]; - if (sentmods[i] == 0) continue; - dn = (Bool) needmods[i]; - if (dn) continue; - XTestFakeKeyEvent_wr(dpy, sentmods[i], dn, CurrentTime); - } - for (j=0; j<8; j++) { - /* next, do the Mod downs */ - i = Ilist[j]; - if (sentmods[i] == 0) continue; - dn = (Bool) needmods[i]; - if (!dn) continue; - XTestFakeKeyEvent_wr(dpy, sentmods[i], dn, CurrentTime); - } - - if (involves_multi_key) { - /* - * Reverse workaround for Multi_key and shift. - */ - if (debug_keyboard) { - fprintf(stderr, " vvv trying to avoid " - "inadvertent Multi_key from Shift " - "(doing %03d down now)\n", shift_is_down); - } - XTestFakeKeyEvent_wr(dpy, shift_is_down, True, - CurrentTime); - } - - /* - * With the above modifier work done, send the actual keycode: - */ - XTestFakeKeyEvent_wr(dpy, Kc_f, (Bool) down, CurrentTime); - - /* - * Now undo the modifier work: - */ - for (j=7; j>=0; j--) { - /* reverse Mod downs we did */ - i = Ilist[j]; - if (sentmods[i] == 0) continue; - dn = (Bool) needmods[i]; - if (!dn) continue; - XTestFakeKeyEvent_wr(dpy, sentmods[i], !dn, - CurrentTime); - } - for (j=7; j>=0; j--) { - /* finally reverse the Mod ups we did */ - i = Ilist[j]; - if (sentmods[i] == 0) continue; - dn = (Bool) needmods[i]; - if (dn) continue; - XTestFakeKeyEvent_wr(dpy, sentmods[i], !dn, - CurrentTime); - } - - } else { /* for up case, hopefully just need to pop it up: */ - - XTestFakeKeyEvent_wr(dpy, Kc_f, (Bool) down, CurrentTime); - } - X_UNLOCK; -} -#endif - -/* - * For tweaking modifiers wrt the Alt-Graph key, etc. - */ -#define LEFTSHIFT 1 -#define RIGHTSHIFT 2 -#define ALTGR 4 -static char mod_state = 0; - -static char modifiers[0x100]; -static KeyCode keycodes[0x100]; -static KeyCode left_shift_code, right_shift_code, altgr_code, iso_level3_code; - -/* workaround for X11R5, Latin 1 only */ -#ifndef XConvertCase -#define XConvertCase(sym, lower, upper) \ -*(lower) = sym; \ -*(upper) = sym; \ -if (sym >> 8 == 0) { \ - if ((sym >= XK_A) && (sym <= XK_Z)) \ - *(lower) += (XK_a - XK_A); \ - else if ((sym >= XK_a) && (sym <= XK_z)) \ - *(upper) -= (XK_a - XK_A); \ - else if ((sym >= XK_Agrave) && (sym <= XK_Odiaeresis)) \ - *(lower) += (XK_agrave - XK_Agrave); \ - else if ((sym >= XK_agrave) && (sym <= XK_odiaeresis)) \ - *(upper) -= (XK_agrave - XK_Agrave); \ - else if ((sym >= XK_Ooblique) && (sym <= XK_Thorn)) \ - *(lower) += (XK_oslash - XK_Ooblique); \ - else if ((sym >= XK_oslash) && (sym <= XK_thorn)) \ - *(upper) -= (XK_oslash - XK_Ooblique); \ -} -#endif - -char *short_kmb(char *str) { - int i, saw_k = 0, saw_m = 0, saw_b = 0, n = 10; - char *p, tmp[10]; - - for (i=0; i<n; i++) { - tmp[i] = '\0'; - } - - p = str; - i = 0; - while (*p) { - if ((*p == 'K' || *p == 'k') && !saw_k) { - tmp[i++] = 'K'; - saw_k = 1; - } else if ((*p == 'M' || *p == 'm') && !saw_m) { - tmp[i++] = 'M'; - saw_m = 1; - } else if ((*p == 'B' || *p == 'b') && !saw_b) { - tmp[i++] = 'B'; - saw_b = 1; - } - p++; - } - return(strdup(tmp)); -} - -void initialize_allowed_input(void) { - char *str; - - if (allowed_input_normal) { - free(allowed_input_normal); - allowed_input_normal = NULL; - } - if (allowed_input_view_only) { - free(allowed_input_view_only); - allowed_input_view_only = NULL; - } - - if (! allowed_input_str) { - allowed_input_normal = strdup("KMB"); - allowed_input_view_only = strdup(""); - } else { - char *p, *str = strdup(allowed_input_str); - p = strchr(str, ','); - if (p) { - allowed_input_view_only = strdup(p+1); - *p = '\0'; - allowed_input_normal = strdup(str); - } else { - allowed_input_normal = strdup(str); - allowed_input_view_only = strdup(""); - } - free(str); - } - - /* shorten them */ - str = short_kmb(allowed_input_normal); - free(allowed_input_normal); - allowed_input_normal = str; - - str = short_kmb(allowed_input_view_only); - free(allowed_input_view_only); - allowed_input_view_only = str; - - if (screen) { - rfbClientIteratorPtr iter; - rfbClientPtr cl; - - iter = rfbGetClientIterator(screen); - while( (cl = rfbClientIteratorNext(iter)) ) { - ClientData *cd = (ClientData *) cl->clientData; - - if (cd->input[0] == '=') { - ; /* custom setting */ - } else if (cd->login_viewonly) { - if (*allowed_input_view_only != '\0') { - cl->viewOnly = FALSE; - cd->input[0] = '\0'; - strncpy(cd->input, - allowed_input_view_only, CILEN); - } else { - cl->viewOnly = TRUE; - } - } else { - if (allowed_input_normal) { - cd->input[0] = '\0'; - strncpy(cd->input, - allowed_input_normal, CILEN); - } - } - } - rfbReleaseClientIterator(iter); - } -} - -void initialize_keyboard_and_pointer(void) { - - if (raw_fb && ! dpy) return; /* raw_fb hack */ - - if (use_modifier_tweak) { - initialize_modtweak(); - } - if (remap_file != NULL) { - initialize_remap(remap_file); - } - - initialize_pointer_map(pointer_remap); - - clear_modifiers(1); - if (clear_mods == 1) { - clear_modifiers(0); - } -} - -void initialize_modtweak(void) { - KeySym keysym, *keymap; - int i, j, minkey, maxkey, syms_per_keycode; - - if (use_xkb_modtweak) { - initialize_xkb_modtweak(); - return; - } - memset(modifiers, -1, sizeof(modifiers)); - for (i=0; i<0x100; i++) { - keycodes[i] = NoSymbol; - } - - X_LOCK; - XDisplayKeycodes(dpy, &minkey, &maxkey); - - keymap = XGetKeyboardMapping(dpy, minkey, (maxkey - minkey + 1), - &syms_per_keycode); - - /* handle alphabetic char with only one keysym (no upper + lower) */ - for (i = minkey; i <= maxkey; i++) { - KeySym lower, upper; - /* 2nd one */ - keysym = keymap[(i - minkey) * syms_per_keycode + 1]; - if (keysym != NoSymbol) { - continue; - } - /* 1st one */ - keysym = keymap[(i - minkey) * syms_per_keycode + 0]; - if (keysym == NoSymbol) { - continue; - } - XConvertCase(keysym, &lower, &upper); - if (lower != upper) { - keymap[(i - minkey) * syms_per_keycode + 0] = lower; - keymap[(i - minkey) * syms_per_keycode + 1] = upper; - } - } - for (i = minkey; i <= maxkey; i++) { - if (debug_keyboard) { - if (i == minkey) { - rfbLog("initialize_modtweak: keycode -> " - "keysyms mapping info:\n"); - } - fprintf(stderr, " %03d ", i); - } - for (j = 0; j < syms_per_keycode; j++) { - if (debug_keyboard) { - char *sym; -#if 0 - sym =XKeysymToString(XKeycodeToKeysym(dpy,i,j)); -#else - keysym = keymap[(i-minkey)*syms_per_keycode+j]; - sym = XKeysymToString(keysym); -#endif - fprintf(stderr, "%-18s ", sym ? sym : "null"); - if (j == syms_per_keycode - 1) { - fprintf(stderr, "\n"); - } - } - if (j >= 4) { - /* - * Something wacky in the keymapping. - * Ignore these non Shift/AltGr chords - * for now... n.b. we try to automatically - * switch to -xkb for this case. - */ - continue; - } - keysym = keymap[ (i - minkey) * syms_per_keycode + j ]; - if ( keysym >= ' ' && keysym < 0x100 - && i == XKeysymToKeycode(dpy, keysym) ) { - keycodes[keysym] = i; - modifiers[keysym] = j; - } - } - } - - left_shift_code = XKeysymToKeycode(dpy, XK_Shift_L); - right_shift_code = XKeysymToKeycode(dpy, XK_Shift_R); - altgr_code = XKeysymToKeycode(dpy, XK_Mode_switch); - iso_level3_code = NoSymbol; -#ifdef XK_ISO_Level3_Shift - iso_level3_code = XKeysymToKeycode(dpy, XK_ISO_Level3_Shift); -#endif - - XFree ((void *) keymap); - - X_UNLOCK; -} - -/* - * does the actual tweak: - */ -static void tweak_mod(signed char mod, rfbBool down) { - rfbBool is_shift = mod_state & (LEFTSHIFT|RIGHTSHIFT); - Bool dn = (Bool) down; - KeyCode altgr = altgr_code; - - if (mod < 0) { - if (debug_keyboard) { - rfbLog("tweak_mod: Skip: down=%d index=%d\n", down, - (int) mod); - } - return; - } - if (debug_keyboard) { - rfbLog("tweak_mod: Start: down=%d index=%d mod_state=0x%x" - " is_shift=%d\n", down, (int) mod, (int) mod_state, - is_shift); - } - - if (use_iso_level3 && iso_level3_code) { - altgr = iso_level3_code; - } - - X_LOCK; - if (is_shift && mod != 1) { - if (mod_state & LEFTSHIFT) { - XTestFakeKeyEvent_wr(dpy, left_shift_code, !dn, CurrentTime); - } - if (mod_state & RIGHTSHIFT) { - XTestFakeKeyEvent_wr(dpy, right_shift_code, !dn, CurrentTime); - } - } - if ( ! is_shift && mod == 1 ) { - XTestFakeKeyEvent_wr(dpy, left_shift_code, dn, CurrentTime); - } - if ( altgr && (mod_state & ALTGR) && mod != 2 ) { - XTestFakeKeyEvent_wr(dpy, altgr, !dn, CurrentTime); - } - if ( altgr && ! (mod_state & ALTGR) && mod == 2 ) { - XTestFakeKeyEvent_wr(dpy, altgr, dn, CurrentTime); - } - X_UNLOCK; - if (debug_keyboard) { - rfbLog("tweak_mod: Finish: down=%d index=%d mod_state=0x%x" - " is_shift=%d\n", down, (int) mod, (int) mod_state, - is_shift); - } -} - -/* - * tweak the modifier under -modtweak - */ -static void modifier_tweak_keyboard(rfbBool down, rfbKeySym keysym, - rfbClientPtr client) { - KeyCode k; - int tweak = 0; - - if (use_xkb_modtweak) { - xkb_tweak_keyboard(down, keysym, client); - return; - } - if (debug_keyboard) { - rfbLog("modifier_tweak_keyboard: %s keysym=0x%x\n", - down ? "down" : "up", (int) keysym); - } - -#define ADJUSTMOD(sym, state) \ - if (keysym == sym) { \ - if (down) { \ - mod_state |= state; \ - } else { \ - mod_state &= ~state; \ - } \ - } - - ADJUSTMOD(XK_Shift_L, LEFTSHIFT) - ADJUSTMOD(XK_Shift_R, RIGHTSHIFT) - ADJUSTMOD(XK_Mode_switch, ALTGR) - - if ( down && keysym >= ' ' && keysym < 0x100 ) { - tweak = 1; - tweak_mod(modifiers[keysym], True); - k = keycodes[keysym]; - } else { - X_LOCK; - k = XKeysymToKeycode(dpy, (KeySym) keysym); - X_UNLOCK; - } - if (k == NoSymbol && add_keysyms && ! IsModifierKey(keysym)) { - int new_kc = add_keysym(keysym); - if (new_kc) { - k = new_kc; - } - } - - if (sloppy_keys) { - int new_kc; - if (sloppy_key_check((int) k, down, keysym, &new_kc)) { - k = (KeyCode) new_kc; - } - } - - if (debug_keyboard) { - rfbLog("modifier_tweak_keyboard: KeySym 0x%x \"%s\" -> " - "KeyCode 0x%x%s\n", (int) keysym, XKeysymToString(keysym), - (int) k, k ? "" : " *ignored*"); - } - if ( k != NoSymbol ) { - X_LOCK; - XTestFakeKeyEvent_wr(dpy, k, (Bool) down, CurrentTime); - X_UNLOCK; - } - - if ( tweak ) { - tweak_mod(modifiers[keysym], False); - } -} - -typedef struct allowed_input { - int keystroke; - int motion; - int button; -} allowed_input_t; - -void get_allowed_input(rfbClientPtr client, allowed_input_t *input) { - ClientData *cd; - char *str; - - input->keystroke = 0; - input->motion = 0; - input->button = 0; - - if (! client) { - return; - } - - cd = (ClientData *) client->clientData; - - if (cd->input[0] != '-') { - str = cd->input; - } else if (client->viewOnly) { - if (allowed_input_view_only) { - str = allowed_input_view_only; - } else { - str = ""; - } - } else { - if (allowed_input_normal) { - str = allowed_input_normal; - } else { - str = "KMB"; - } - } - - while (*str) { - if (*str == 'K') { - input->keystroke = 1; - } else if (*str == 'M') { - input->motion = 1; - } else if (*str == 'B') { - input->button = 1; - } - str++; - } -} - -/* for -pipeinput mode */ -void pipe_keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) { - int can_input = 0, uid; - allowed_input_t input; - char *name; - ClientData *cd = (ClientData *) client->clientData; - - if (pipeinput_fh == NULL) { - return; - } - - if (! view_only) { - get_allowed_input(client, &input); - if (input.motion || input.button) { - can_input = 1; /* XXX distinguish later */ - } - } - uid = cd->uid; - if (! can_input) { - uid = -uid; - } - - X_LOCK; - name = XKeysymToString(keysym); - X_UNLOCK; - - fprintf(pipeinput_fh, "Keysym %d %d %u %s %s\n", uid, down, - keysym, name, down ? "KeyPress" : "KeyRelease"); - - fflush(pipeinput_fh); - check_pipeinput(); -} - -typedef struct keyevent { - rfbKeySym sym; - rfbBool down; - double time; -} keyevent_t; - -#define KEY_HIST 256 -int key_history_idx = -1; -keyevent_t key_history[KEY_HIST]; - -double typing_rate(double time_window, int *repeating) { - double dt = 1.0, now = dnow(); - KeySym key = NoSymbol; - int i, idx, cnt = 0, repeat_keys = 0; - - if (key_history_idx == -1) { - if (repeating) { - *repeating = 0; - } - return 0.0; - } - if (time_window > 0.0) { - dt = time_window; - } - for (i=0; i<KEY_HIST; i++) { - idx = key_history_idx - i; - if (idx < 0) { - idx += KEY_HIST; - } - if (! key_history[idx].down) { - continue; - } - if (now > key_history[idx].time + dt) { - break; - } - cnt++; - if (key == NoSymbol) { - key = key_history[idx].sym; - repeat_keys = 1; - } else if (key == key_history[idx].sym) { - repeat_keys++; - } - } - - if (repeating) { - if (repeat_keys >= 2) { - *repeating = repeat_keys; - } else { - *repeating = 0; - } - } - - /* - * n.b. keyrate could seem very high with libvncserver buffering them - * so avoid using small dt. - */ - return ((double) cnt)/dt; -} - -int skip_cr_when_scaling(char *mode) { - int got = 0; - - if (!scaling) { - return 0; - } - - if (scaling_copyrect != scaling_copyrect0) { - /* user override via -scale: */ - if (! scaling_copyrect) { - return 1; - } else { - return 0; - } - } - if (*mode == 's') { - got = got_scrollcopyrect; - } else if (*mode == 'w') { - got = got_wirecopyrect; - } - if (scaling_copyrect || got) { - int lat, rate; - int link = link_rate(&lat, &rate); - if (link == LR_DIALUP) { - return 1; - } else if (rate < 25) { - /* the fill-in of the repair may be too slow */ - return 1; - } else { - return 0; - } - } else { - return 1; - } -} - -/* - * key event handler. See the above functions for contortions for - * running under -modtweak. - */ -static rfbClientPtr last_keyboard_client = NULL; - -void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) { - KeyCode k; - int idx, isbutton = 0; - allowed_input_t input; - time_t now = time(0); - double tnow; - static int skipped_last_down; - static rfbBool last_down; - static rfbKeySym last_keysym = NoSymbol; - static rfbKeySym max_keyrepeat_last_keysym = NoSymbol; - static double max_keyrepeat_last_time = 0.0; - - dtime0(&tnow); - got_keyboard_calls++; - - if (debug_keyboard) { - char *str; - X_LOCK; - str = XKeysymToString(keysym); - rfbLog("# keyboard(%s, 0x%x \"%s\") %.4f\n", down ? "down":"up", - (int) keysym, str ? str : "null", tnow - x11vnc_start); - X_UNLOCK; - } - - if (skip_duplicate_key_events) { - if (keysym == last_keysym && down == last_down) { - if (debug_keyboard) { - rfbLog("skipping dup key event: %d 0x%x\n", - down, keysym); - } - return; - } - } - - last_down = down; - last_keysym = keysym; - last_keyboard_time = tnow; - - last_rfb_down = down; - last_rfb_keysym = keysym; - last_rfb_keytime = tnow; - last_rfb_key_accepted = FALSE; - - if (key_history_idx == -1) { - for (idx=0; idx<KEY_HIST; idx++) { - key_history[idx].sym = NoSymbol; - key_history[idx].down = FALSE; - key_history[idx].time = 0.0; - } - } - idx = ++key_history_idx; - if (key_history_idx >= KEY_HIST) { - key_history_idx = 0; - idx = 0; - } - key_history[idx].sym = keysym; - key_history[idx].down = down; - key_history[idx].time = tnow; - - if (down && (keysym == XK_Alt_L || keysym == XK_Super_L)) { - int i, k, run = 0, ups = 0; - double delay = 1.0; - KeySym ks; - for (i=0; i<16; i++) { - k = idx - i; - if (k < 0) k += KEY_HIST; - if (!key_history[k].down) { - ups++; - continue; - } - ks = key_history[k].sym; - if (key_history[k].time < tnow - delay) { - break; - } else if (ks == keysym && ks == XK_Alt_L) { - run++; - } else if (ks == keysym && ks == XK_Super_L) { - run++; - } else { - break; - } - } - if (ups < 2) { - ; - } else if (run == 3 && keysym == XK_Alt_L) { - rfbLog("3*Alt_L, calling: refresh_screen(0)\n"); - refresh_screen(0); - } else if (run == 4 && keysym == XK_Alt_L) { - rfbLog("4*Alt_L, setting: do_copy_screen\n"); - do_copy_screen = 1; - } else if (run == 5 && keysym == XK_Alt_L) { - ; - } else if (run == 3 && keysym == XK_Super_L) { - rfbLog("3*Super_L, calling: set_xdamage_mark()\n"); - set_xdamage_mark(0, 0, dpy_x, dpy_y); - } else if (run == 4 && keysym == XK_Super_L) { - rfbLog("4*Super_L, calling: check_xrecord_reset()\n"); - check_xrecord_reset(1); - } else if (run == 5 && keysym == XK_Super_L) { - rfbLog("5*Super_L, calling: push_black_screen(0)\n"); - push_black_screen(0); - } - } - - if (!down && skipped_last_down) { - int db = debug_scroll; - if (keysym == max_keyrepeat_last_keysym) { - skipped_last_down = 0; - if (db) rfbLog("--- scroll keyrate skipping 0x%lx %s " - "%.4f %.4f\n", keysym, down ? "down":"up ", - tnow - x11vnc_start, tnow - max_keyrepeat_last_time); - return; - } - } - if (down && max_keyrepeat_time > 0.0) { - int skip = 0; - int db = debug_scroll; - - if (max_keyrepeat_last_keysym != NoSymbol && - max_keyrepeat_last_keysym != keysym) { - ; - } else { - if (tnow < max_keyrepeat_last_time+max_keyrepeat_time) { - skip = 1; - } - } - max_keyrepeat_time = 0.0; - if (skip) { - if (db) rfbLog("--- scroll keyrate skipping 0x%lx %s " - "%.4f %.4f\n", keysym, down ? "down":"up ", - tnow - x11vnc_start, tnow - max_keyrepeat_last_time); - max_keyrepeat_last_keysym = keysym; - skipped_last_down = 1; - return; - } else { - if (db) rfbLog("--- scroll keyrate KEEPING 0x%lx %s " - "%.4f %.4f\n", keysym, down ? "down":"up ", - tnow - x11vnc_start, tnow - max_keyrepeat_last_time); - } - } - max_keyrepeat_last_keysym = keysym; - max_keyrepeat_last_time = tnow; - skipped_last_down = 0; - last_rfb_key_accepted = TRUE; - - if (pipeinput_fh != NULL) { - pipe_keyboard(down, keysym, client); - if (! pipeinput_tee) { - if (! view_only || raw_fb) { /* raw_fb hack */ - last_keyboard_client = client; - last_event = last_input = now; - last_keyboard_input = now; - - last_keysym = keysym; - - last_rfb_down = down; - last_rfb_keysym = keysym; - last_rfb_keytime = tnow; - - got_user_input++; - got_keyboard_input++; - } - return; - } - } - - if (view_only) { - return; - } - get_allowed_input(client, &input); - if (! input.keystroke) { - return; - } - - track_mod_state(keysym, down, TRUE); /* ignores remaps */ - - last_keyboard_client = client; - last_event = last_input = now; - last_keyboard_input = now; - - last_keysym = keysym; - - last_rfb_down = down; - last_rfb_keysym = keysym; - last_rfb_keytime = tnow; - - got_user_input++; - got_keyboard_input++; - - if (raw_fb && ! dpy) return; /* raw_fb hack */ - - if (keyremaps) { - keyremap_t *remap = keyremaps; - while (remap != NULL) { - if (remap->before == keysym) { - keysym = remap->after; - isbutton = remap->isbutton; - if (debug_keyboard) { - X_LOCK; - rfbLog("keyboard(): remapping keysym: " - "0x%x \"%s\" -> 0x%x \"%s\"\n", - (int) remap->before, - XKeysymToString(remap->before), - (int) remap->after, - remap->isbutton ? "button" : - XKeysymToString(remap->after)); - X_UNLOCK; - } - break; - } - remap = remap->next; - } - } - - if (use_xrecord && ! xrecording && down) { - - if (!strcmp(scroll_copyrect, "never")) { - ; - } else if (!strcmp(scroll_copyrect, "mouse")) { - ; - } else if (skip_cr_when_scaling("scroll")) { - ; - } else if (! xrecord_skip_keysym(keysym)) { - snapshot_stack_list(0, 0.25); - xrecord_watch(1, SCR_KEY); - xrecord_set_by_keys = 1; - xrecord_keysym = keysym; - } else { - if (debug_scroll) { - char *str = XKeysymToString(keysym); - rfbLog("xrecord_skip_keysym: %s\n", - str ? str : "NoSymbol"); - } - } - } - - if (isbutton) { - int mask, button = (int) keysym; - if (! down) { - return; /* nothing to send */ - } - if (debug_keyboard) { - rfbLog("keyboard(): remapping keystroke to button %d" - " click\n", button); - } - dtime0(&last_key_to_button_remap_time); - - X_LOCK; - /* - * This in principle can be a little dicey... i.e. even - * remap the button click to keystroke sequences! - * Usually just will simulate the button click. - */ - mask = 1<<(button-1); - do_button_mask_change(mask, button); /* down */ - mask = 0; - do_button_mask_change(mask, button); /* up */ - XFlush(dpy); - X_UNLOCK; - return; - } - - if (use_modifier_tweak) { - modifier_tweak_keyboard(down, keysym, client); - X_LOCK; - XFlush(dpy); - X_UNLOCK; - return; - } - - X_LOCK; - - k = XKeysymToKeycode(dpy, (KeySym) keysym); - - if (k == NoSymbol && add_keysyms && ! IsModifierKey(keysym)) { - int new_kc = add_keysym(keysym); - if (new_kc) { - k = new_kc; - } - } - if (debug_keyboard) { - char *str = XKeysymToString(keysym); - rfbLog("keyboard(): KeySym 0x%x \"%s\" -> KeyCode 0x%x%s\n", - (int) keysym, str ? str : "null", (int) k, - k ? "" : " *ignored*"); - } - - if ( k != NoSymbol ) { - XTestFakeKeyEvent_wr(dpy, k, (Bool) down, CurrentTime); - XFlush(dpy); - } - - X_UNLOCK; -} - -/* -- pointer.c -- */ -/* - * pointer event (motion and button click) handling routines. - */ -typedef struct ptrremap { - KeySym keysym; - KeyCode keycode; - int end; - int button; - int down; - int up; -} prtremap_t; - -MUTEX(pointerMutex); -#define MAX_BUTTONS 5 -#define MAX_BUTTON_EVENTS 50 -static prtremap_t pointer_map[MAX_BUTTONS+1][MAX_BUTTON_EVENTS]; - -/* - * For parsing the -buttonmap sections, e.g. "4" or ":Up+Up+Up:" - */ -static void buttonparse(int from, char **s) { - char *q; - int to, i; - int modisdown[256]; - - q = *s; - - for (i=0; i<256; i++) { - modisdown[i] = 0; - } - - if (*q == ':') { - /* :sym1+sym2+...+symN: format */ - int l = 0, n = 0; - char list[1000]; - char *t, *kp = q + 1; - KeyCode kcode; - - while (*(kp+l) != ':' && *(kp+l) != '\0') { - /* loop to the matching ':' */ - l++; - if (l >= 1000) { - rfbLog("buttonparse: keysym list too long: " - "%s\n", q); - break; - } - } - *(kp+l) = '\0'; - strncpy(list, kp, l); - list[l] = '\0'; - rfbLog("remap button %d using \"%s\"\n", from, list); - - /* loop over tokens separated by '+' */ - t = strtok(list, "+"); - while (t) { - KeySym ksym; - unsigned int ui; - int i; - if (n >= MAX_BUTTON_EVENTS - 20) { - rfbLog("buttonparse: too many button map " - "events: %s\n", list); - break; - } - if (sscanf(t, "0x%x", &ui) == 1) { - ksym = (KeySym) ui; /* hex value */ - } else { - X_LOCK; - ksym = XStringToKeysym(t); /* string value */ - X_UNLOCK; - } - if (ksym == NoSymbol) { - /* see if Button<N> "keysym" was used: */ - if (sscanf(t, "Button%d", &i) == 1) { - rfbLog(" event %d: button %d\n", - from, n+1, i); - if (i == 0) i = -1; /* bah */ - pointer_map[from][n].keysym = NoSymbol; - pointer_map[from][n].keycode = NoSymbol; - pointer_map[from][n].button = i; - pointer_map[from][n].end = 0; - pointer_map[from][n].down = 0; - pointer_map[from][n].up = 0; - } else { - rfbLog("buttonparse: ignoring unknown " - "keysym: %s\n", t); - n--; - } - } else { - /* - * XXX may not work with -modtweak or -xkb - */ - X_LOCK; - kcode = XKeysymToKeycode(dpy, ksym); - - pointer_map[from][n].keysym = ksym; - pointer_map[from][n].keycode = kcode; - pointer_map[from][n].button = 0; - pointer_map[from][n].end = 0; - if (! ismodkey(ksym) ) { - /* do both down then up */ - pointer_map[from][n].down = 1; - pointer_map[from][n].up = 1; - } else { - if (modisdown[kcode]) { - pointer_map[from][n].down = 0; - pointer_map[from][n].up = 1; - modisdown[kcode] = 0; - } else { - pointer_map[from][n].down = 1; - pointer_map[from][n].up = 0; - modisdown[kcode] = 1; - } - } - rfbLog(" event %d: keysym %s (0x%x) -> " - "keycode 0x%x down=%d up=%d\n", n+1, - XKeysymToString(ksym), ksym, kcode, - pointer_map[from][n].down, - pointer_map[from][n].up); - X_UNLOCK; - } - t = strtok(NULL, "+"); - n++; - } - - /* we must release any modifiers that are still down: */ - for (i=0; i<256; i++) { - kcode = (KeyCode) i; - if (n >= MAX_BUTTON_EVENTS) { - rfbLog("buttonparse: too many button map " - "events: %s\n", list); - break; - } - if (modisdown[kcode]) { - pointer_map[from][n].keysym = NoSymbol; - pointer_map[from][n].keycode = kcode; - pointer_map[from][n].button = 0; - pointer_map[from][n].end = 0; - pointer_map[from][n].down = 0; - pointer_map[from][n].up = 1; - modisdown[kcode] = 0; - n++; - } - } - - /* advance the source pointer position */ - (*s) += l+2; - } else { - /* single digit format */ - char str[2]; - str[0] = *q; - str[1] = '\0'; - - to = atoi(str); - if (to < 1) { - rfbLog("skipping invalid remap button \"%d\" for button" - " %d from string \"%s\"\n", - to, from, str); - } else { - rfbLog("remap button %d using \"%s\"\n", from, str); - rfbLog(" button: %d -> %d\n", from, to); - pointer_map[from][0].keysym = NoSymbol; - pointer_map[from][0].keycode = NoSymbol; - pointer_map[from][0].button = to; - pointer_map[from][0].end = 0; - pointer_map[from][0].down = 0; - pointer_map[from][0].up = 0; - } - /* advance the source pointer position */ - (*s)++; - } -} - -/* - * process the -buttonmap string - */ -void initialize_pointer_map(char *pointer_remap) { - unsigned char map[MAX_BUTTONS]; - int i, k; - /* - * This routine counts the number of pointer buttons on the X - * server (to avoid problems, even crashes, if a client has more - * buttons). And also initializes any pointer button remapping - * from -buttonmap option. - */ - - X_LOCK; - num_buttons = XGetPointerMapping(dpy, map, MAX_BUTTONS); - X_UNLOCK; - - if (num_buttons < 0) { - num_buttons = 0; - } - - /* FIXME: should use info in map[] */ - for (i=1; i<= MAX_BUTTONS; i++) { - for (k=0; k < MAX_BUTTON_EVENTS; k++) { - pointer_map[i][k].end = 1; - } - pointer_map[i][0].keysym = NoSymbol; - pointer_map[i][0].keycode = NoSymbol; - pointer_map[i][0].button = i; - pointer_map[i][0].end = 0; - pointer_map[i][0].down = 0; - pointer_map[i][0].up = 0; - } - - if (pointer_remap && *pointer_remap != '\0') { - /* -buttonmap, format is like: 12-21=2 */ - char *p, *q, *remap = strdup(pointer_remap); - int n; - - if ((p = strchr(remap, '=')) != NULL) { - /* undocumented max button number */ - n = atoi(p+1); - *p = '\0'; - if (n < num_buttons || num_buttons == 0) { - num_buttons = n; - } else { - rfbLog("warning: increasing number of mouse " - "buttons from %d to %d\n", num_buttons, n); - num_buttons = n; - } - } - if ((q = strchr(remap, '-')) != NULL) { - /* - * The '-' separates the 'from' and 'to' lists, - * then it is kind of like tr(1). - */ - char str[2]; - int from; - - rfbLog("remapping pointer buttons using string:\n"); - rfbLog(" \"%s\"\n", remap); - - p = remap; - q++; - i = 0; - str[1] = '\0'; - while (*p != '-') { - str[0] = *p; - from = atoi(str); - buttonparse(from, &q); - p++; - } - } - free(remap); - } -} - -typedef struct bout { - int x1, y1, x2, y2; -} blackout_t; -int blackouts; -blackout_t blackr[]; - -/* - * 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)); -} - -/* - * Send a pointer position event to the X server. - */ -static void update_x11_pointer_position(int x, int y) { - int rc; - - if (raw_fb && ! dpy) return; /* raw_fb hack */ - - X_LOCK; - if (use_xwarppointer) { - /* - * off_x and off_y not needed with XWarpPointer since - * window is used: - */ - XWarpPointer(dpy, None, window, 0, 0, 0, 0, x + coff_x, - y + coff_y); - } else { - XTestFakeMotionEvent_wr(dpy, scr, x + off_x + coff_x, - y + off_y + coff_y, CurrentTime); - } - X_UNLOCK; - - if (cursor_x != x || cursor_y != y) { - last_pointer_motion_time = dnow(); - } - - cursor_x = x; - cursor_y = y; - - /* record the x, y position for the rfb screen as well. */ - cursor_position(x, y); - - /* change the cursor shape if necessary */ - rc = set_cursor(x, y, get_which_cursor()); - cursor_changes += rc; - - last_event = last_input = last_pointer_input = time(0); -} - -void do_button_mask_change(int mask, int button) { - int mb, k, i = button-1; - - /* - * this expands to any pointer_map button -> keystrokes - * remappings. Usually just k=0 and we send one button event. - */ - for (k=0; k < MAX_BUTTON_EVENTS; k++) { - int bmask = (mask & (1<<i)); - - if (pointer_map[i+1][k].end) { - break; - } - - if (pointer_map[i+1][k].button) { - /* send button up or down */ - - mb = pointer_map[i+1][k].button; - if ((num_buttons && mb > num_buttons) || mb < 1) { - rfbLog("ignoring mouse button out of " - "bounds: %d>%d mask: 0x%x -> 0x%x\n", - mb, num_buttons, button_mask, mask); - continue; - } - if (debug_pointer) { - rfbLog("pointer(): sending button %d" - " %s (event %d)\n", mb, bmask - ? "down" : "up", k+1); - } - XTestFakeButtonEvent_wr(dpy, mb, (mask & (1<<i)) - ? True : False, CurrentTime); - } else { - /* send keysym up or down */ - KeyCode key = pointer_map[i+1][k].keycode; - int up = pointer_map[i+1][k].up; - int down = pointer_map[i+1][k].down; - - if (! bmask) { - /* do not send keysym on button up */ - continue; - } - if (debug_pointer) { - rfbLog("pointer(): sending button %d " - "down as keycode 0x%x (event %d)\n", - i+1, key, k+1); - rfbLog(" down=%d up=%d " - "keysym: %s\n", down, up, - XKeysymToString(XKeycodeToKeysym( - dpy, key, 0))); - } - if (down) { - XTestFakeKeyEvent_wr(dpy, key, True, - CurrentTime); - } - if (up) { - XTestFakeKeyEvent_wr(dpy, key, False, - CurrentTime); - } - } - } -} - -/* - * Send a pointer button event to the X server. - */ -static void update_x11_pointer_mask(int mask) { - int snapped, xr_mouse = 1, i; - - last_event = last_input = last_pointer_input = time(0); - - if (raw_fb && ! dpy) return; /* raw_fb hack */ - - if (mask != button_mask) { - last_pointer_click_time = dnow(); - } - - if (nofb) { - xr_mouse = 0; - } else if (!strcmp(scroll_copyrect, "never")) { - xr_mouse = 0; - } else if (!strcmp(scroll_copyrect, "keys")) { - xr_mouse = 0; - } else if (skip_cr_when_scaling("scroll")) { - xr_mouse = 0; - } else if (xrecord_skip_button(mask, button_mask)) { - xr_mouse = 0; - } - - if (mask && use_xrecord && ! xrecording && xr_mouse) { - static int px, py, x, y, w, h, got_wm_frame; - static XWindowAttributes attr; - Window frame = None, mwin = None; - int skip = 0; - - if (!button_mask) { - if (get_wm_frame_pos(&px, &py, &x, &y, &w, &h, - &frame, &mwin)) { - got_wm_frame = 1; -if (debug_scroll > 1) fprintf(stderr, "wm_win: 0x%lx\n", mwin); - if (mwin != None) { - if (!valid_window(mwin, &attr, 1)) { - mwin = None; - } - } - } else { - got_wm_frame = 0; - } - } - if (got_wm_frame) { - if (wireframe && near_wm_edge(x, y, w, h, px, py)) { - /* step out of wireframe's way */ - skip = 1; - } else { - int ok = 0; - int btn4 = (1<<3); - int btn5 = (1<<4); - - if (near_scrollbar_edge(x, y, w, h, px, py)) { - ok = 1; - } - if (mask & (btn4|btn5)) { - /* scroll wheel mouse */ - ok = 1; - } - if (mwin != None) { - /* skinny internal window */ - int w = attr.width; - int h = attr.height; - if (h > 10 * w || w > 10 * h) { -if (debug_scroll > 1) fprintf(stderr, "internal scrollbar: %dx%d\n", w, h); - ok = 1; - } - } - if (! ok) { - skip = 1; - } - } - } - - if (! skip) { - xrecord_watch(1, SCR_MOUSE); - snapshot_stack_list(0, 0.50); - snapped = 1; - if (button_mask) { - xrecord_set_by_mouse = 1; - } else { - update_stack_list(); - xrecord_set_by_mouse = 2; - } - } - } - - if (mask && !button_mask) { - /* button down, snapshot the stacking list before flushing */ - if (wireframe && !wireframe_in_progress && - strcmp(wireframe_copyrect, "never")) { - if (! snapped) { - snapshot_stack_list(0, 0.0); - } - } - } - - X_LOCK; - - /* look for buttons that have be clicked or released: */ - for (i=0; i < MAX_BUTTONS; i++) { - if ( (button_mask & (1<<i)) != (mask & (1<<i)) ) { - if (debug_pointer) { - rfbLog("pointer(): mask change: mask: 0x%x -> " - "0x%x button: %d\n", button_mask, mask,i+1); - } - do_button_mask_change(mask, i+1); /* button # is i+1 */ - } - } - - X_UNLOCK; - - /* - * Remember the button state for next time and also for the - * -nodragging case: - */ - button_mask_prev = button_mask; - button_mask = mask; -} - -/* for -pipeinput */ - - -void pipe_pointer(int mask, int x, int y, rfbClientPtr client) { - int can_input = 0, uid; - allowed_input_t input; - ClientData *cd = (ClientData *) client->clientData; - char hint[MAX_BUTTONS * 20]; - - if (pipeinput_fh == NULL) { - return; - } - - if (! view_only) { - get_allowed_input(client, &input); - if (input.motion || input.button) { - can_input = 1; /* XXX distinguish later */ - } - } - uid = cd->uid; - if (! can_input) { - uid = -uid; - } - - hint[0] = '\0'; - if (mask == button_mask) { - strcat(hint, "None"); - } else { - int i, old, new, m = 1, cnt = 0; - for (i=0; i<MAX_BUTTONS; i++) { - char s[20]; - - old = button_mask & m; - new = mask & m; - m = m << 1; - - if (old == new) { - continue; - } - if (hint[0] != '\0') { - strcat(hint, ","); - } - if (new && ! old) { - sprintf(s, "ButtonPress-%d", i+1); - cnt++; - } else if (! new && old) { - sprintf(s, "ButtonRelease-%d", i+1); - cnt++; - } - strcat(hint, s); - } - if (! cnt) { - strcpy(hint, "None"); - } - } - - fprintf(pipeinput_fh, "Pointer %d %d %d %d %s\n", uid, x, y, - mask, hint); - fflush(pipeinput_fh); - check_pipeinput(); -} - -/* - * Actual callback from libvncserver when it gets a pointer event. - * This may queue pointer events rather than sending them immediately - * to the X server. (see update_x11_pointer*()) - */ -void pointer(int mask, int x, int y, rfbClientPtr client) { - allowed_input_t input; - int sent = 0, buffer_it = 0; - double now; - - if (mask >= 0) { - got_pointer_calls++; - } - - if (debug_pointer && mask >= 0) { - static int show_motion = -1; - static double last_pointer = 0.0; - double tnow, dt; - static int last_x, last_y; - if (show_motion == -1) { - if (getenv("X11VNC_DB_NOMOTION")) { - show_motion = 0; - } else { - show_motion = 1; - } - } - dtime0(&tnow); - tnow -= x11vnc_start; - dt = tnow - last_pointer; - last_pointer = tnow; - if (show_motion) { - rfbLog("# pointer(mask: 0x%x, x:%4d, y:%4d) " - "dx: %3d dy: %3d dt: %.4f t: %.4f\n", mask, x, y, - x - last_x, y - last_y, dt, tnow); - } - last_x = x; - last_y = y; - } - - if (scaling) { - /* map from rfb size to X11 size: */ - x = ((double) x / scaled_x) * dpy_x; - x = nfix(x, dpy_x); - y = ((double) y / scaled_y) * dpy_y; - y = nfix(y, dpy_y); - } - - if (pipeinput_fh != NULL && mask >= 0) { - pipe_pointer(mask, x, y, client); - if (! pipeinput_tee) { - if (! view_only || raw_fb) { /* raw_fb hack */ - got_user_input++; - got_keyboard_input++; - last_pointer_client = client; - } - if (view_only && raw_fb) { - /* raw_fb hack track button state */ - button_mask_prev = button_mask; - button_mask = mask; - } - return; - } - } - - if (view_only) { - return; - } - - now = dnow(); - - if (mask >= 0) { - /* - * mask = -1 is a special case call from scan_for_updates() - * to flush the event queue; there is no real pointer event. - */ - get_allowed_input(client, &input); - if (! input.motion && ! input.button) { - return; - } - - got_user_input++; - got_pointer_input++; - last_pointer_client = client; - - last_pointer_time = now; - - if (blackout_ptr && blackouts) { - int b, ok = 1; - /* see if it goes into the blacked out region */ - for (b=0; b < blackouts; b++) { - if (x < blackr[b].x1 || x > blackr[b].x2) { - continue; - } - if (y < blackr[b].y1 || y > blackr[b].y2) { - continue; - } - /* x1 <= x <= x2 and y1 <= y <= y2 */ - ok = 0; - break; - } - if (! ok) { - if (debug_pointer) { - rfbLog("pointer(): blackout_ptr skipping " - "x=%d y=%d in rectangle %d,%d %d,%d\n", x, y, - blackr[b].x1, blackr[b].y1, - blackr[b].x2, blackr[b].y2); - } - return; - } - } - } - - /* - * The following is hopefully an improvement wrt response during - * pointer user input (window drags) for the threaded case. - * See check_user_input() for the more complicated things we do - * in the non-threaded case. - */ - if ((use_threads && pointer_mode != 1) || pointer_flush_delay > 0.0) { -# define NEV 32 - /* storage for the event queue */ - static int mutex_init = 0; - static int nevents = 0; - static int ev[NEV][3]; - int i; - /* timer things */ - static double dt = 0.0, tmr = 0.0, maxwait = 0.4; - - if (! mutex_init) { - INIT_MUTEX(pointerMutex); - mutex_init = 1; - } - - if (pointer_flush_delay > 0.0) { - maxwait = pointer_flush_delay; - } - if (mask >= 0) { - if (fb_copy_in_progress || pointer_flush_delay > 0.0) { - buffer_it = 1; - } - } - - LOCK(pointerMutex); - - /* - * If the framebuffer is being copied in another thread - * (scan_for_updates()), we will queue up to 32 pointer - * events for later. The idea is by delaying these input - * events, the screen is less likely to change during the - * copying period, and so will give rise to less window - * "tearing". - * - * Tearing is not completely eliminated because we do - * not suspend work in the other libvncserver threads. - * Maybe that is a possibility with a mutex... - */ - if (buffer_it) { - /* - * mask = -1 is an all-clear signal from - * scan_for_updates(). - * - * dt is a timer in seconds; we only queue for so long. - */ - dt += dtime(&tmr); - - if (nevents < NEV && dt < maxwait) { - i = nevents++; - ev[i][0] = mask; - ev[i][1] = x; - ev[i][2] = y; - if (! input.button) { - ev[i][0] = -1; - } - if (! input.motion) { - ev[i][1] = -1; - ev[i][2] = -1; - } - UNLOCK(pointerMutex); - if (debug_pointer) { - rfbLog("pointer(): deferring event %d" - " %.4f\n", i, tmr - x11vnc_start); - } - return; - } - } - - /* time to send the queue */ - for (i=0; i<nevents; i++) { - int sent = 0; - if (mask < 0 && client != NULL) { - /* hack to only push the latest event */ - if (i < nevents - 1) { - if (debug_pointer) { - rfbLog("- skip deferred event:" - " %d\n", i); - } - continue; - } - } - if (debug_pointer) { - rfbLog("pointer(): sending event %d %.4f\n", - i+1, dnow() - x11vnc_start); - } - if (ev[i][1] >= 0) { - update_x11_pointer_position(ev[i][1], ev[i][2]); - sent = 1; - } - if (ev[i][0] >= 0) { - update_x11_pointer_mask(ev[i][0]); - sent = 1; - } - - if (sent) { - pointer_queued_sent++; - } - } - if (nevents && dt > maxwait) { - if (dpy) { /* raw_fb hack */ - if (mask < 0) { - if (debug_pointer) { - rfbLog("pointer(): calling XFlush " - "%.4f\n", dnow() - x11vnc_start); - } - X_LOCK; - XFlush(dpy); - X_UNLOCK; - } - } - } - nevents = 0; /* reset everything */ - dt = 0.0; - dtime0(&tmr); - - UNLOCK(pointerMutex); - } - if (mask < 0) { /* -1 just means flush the event queue */ - if (debug_pointer) { - rfbLog("pointer(): flush only. %.4f\n", - dnow() - x11vnc_start); - } - return; - } - - /* update the X display with the event: */ - if (input.motion) { - update_x11_pointer_position(x, y); - sent = 1; - } - if (input.button) { - if (mask != button_mask) { - button_change_x = cursor_x; - button_change_y = cursor_y; - } - update_x11_pointer_mask(mask); - sent = 1; - } - - if (nofb && sent) { - /* - * nofb is for, e.g. Win2VNC, where fastest pointer - * updates are desired. - */ - X_LOCK; - XFlush(dpy); - X_UNLOCK; - } else if (buffer_it) { - if (debug_pointer) { - rfbLog("pointer(): calling XFlush+" - "%.4f\n", dnow() - x11vnc_start); - } - X_LOCK; - XFlush(dpy); - X_UNLOCK; - } -} - -int check_pipeinput(void) { - if (! pipeinput_fh) { - return 1; - } - if (ferror(pipeinput_fh)) { - rfbLog("pipeinput pipe has ferror. %p\n", pipeinput_fh); - - if (pipeinput_opts && strstr(pipeinput_opts, "reopen")) { - rfbLog("restarting -pipeinput pipe...\n"); - initialize_pipeinput(); - if (pipeinput_fh) { - return 1; - } else { - return 0; - } - } else { - rfbLog("closing -pipeinput pipe...\n"); - pclose(pipeinput_fh); - pipeinput_fh = NULL; - return 0; - } - } - return 1; -} - -void initialize_pipeinput(void) { - char *p; - - if (pipeinput_fh != NULL) { - rfbLog("closing pipeinput stream: %p\n", pipeinput_fh); - pclose(pipeinput_fh); - pipeinput_fh = NULL; - } - - pipeinput_tee = 0; - if (pipeinput_opts) { - free(pipeinput_opts); - pipeinput_opts = NULL; - } - - if (! pipeinput_str) { - return; - } - - /* look for options: tee, reopen, ... */ - p = strchr(pipeinput_str, ':'); - if (p != NULL) { - char *str, *opt, *q; - int got = 0; - *p = '\0'; - str = strdup(pipeinput_str); - opt = strdup(pipeinput_str); - *p = ':'; - q = strtok(str, ","); - while (q) { - if (!strcmp(q, "key") || !strcmp(q, "keycodes")) { - got = 1; - } - if (!strcmp(q, "reopen")) { - got = 1; - } - if (!strcmp(q, "tee")) { - pipeinput_tee = 1; - got = 1; - } - q = strtok(NULL, ","); - } - if (got) { - pipeinput_opts = opt; - } else { - free(opt); - } - free(str); - p++; - } else { - p = pipeinput_str; - } - - set_child_info(); - if (no_external_cmds) { - rfbLogEnable(1); - rfbLog("cannot run external commands in -nocmds mode:\n"); - rfbLog(" \"%s\"\n", p); - rfbLog(" exiting.\n"); - clean_up_exit(1); - } - rfbLog("pipeinput: starting: \"%s\"...\n", p); - pipeinput_fh = popen(p, "w"); - - if (! pipeinput_fh) { - rfbLog("popen(\"%s\", \"w\") failed.\n", p); - rfbLogPerror("popen"); - rfbLog("Disabling -pipeinput mode.\n"); - return; - } - - fprintf(pipeinput_fh, "%s", -"# \n" -"# Format of the -pipeinput stream:\n" -"# --------------------------------\n" -"#\n" -"# Lines like these beginning with '#' are to be ignored.\n" -"#\n" -"# Pointer events (mouse motion and button clicks) come in the form:\n" -"#\n" -"#\n" -"# Pointer <client#> <x> <y> <mask> <hint>\n" -"#\n" -"#\n" -"# The <client#> is a decimal integer uniquely identifying the client\n" -"# that generated the event. If it is negative that means this event\n" -"# would have been discarded since the client was viewonly.\n" -"#\n" -"# <x> and <y> are decimal integers reflecting the position on the screen\n" -"# the event took place at.\n" -"#\n" -"# <mask> is the button mask indicating the button press state, as normal\n" -"# 0 means no buttons pressed, 1 means button 1 is down 3 (11) means buttons\n" -"# 1 and 2 are down, etc.\n" -"#\n" -"# <hint> is a string containing no spaces and may be ignored.\n" -"# It contains some interpretation about what has happened.\n" -"# It can be:\n" -"#\n" -"# None (nothing to report)\n" -"# ButtonPress-N (this event will cause button-1 to be pressed) \n" -"# ButtonRelease-N (this event will cause button-1 to be released) \n" -"#\n" -"# if two more more buttons change state in one event they are listed\n" -"# separated by commas.\n" -"#\n" -"# One might parse a Pointer line with:\n" -"#\n" -"# int client, x, y, mask; char *hint;\n" -"# sscanf(line, \"Pointer %d %d %d %s\", &client, &x, &y, &mask, &hint);\n" -"#\n" -"#\n" -"# Keysym events (keyboard presses and releases) come in the form:\n" -"#\n" -"#\n" -"# Keysym <client#> <down> <keysym#> <keysym-name> <hint>\n" -"#\n" -"#\n" -"# The <client#> is as with Pointer.\n" -"#\n" -"# <down> is a decimal either 1 or 0 indicating KeyPress or KeyRelease,\n" -"# respectively.\n" -"#\n" -"# <keysym#> is a decimal integer incidating the Keysym of the event.\n" -"#\n" -"# <keysym-name> is the corresponding Keysym name.\n" -"#\n" -"# See the file /usr/include/X11/keysymdef.h for the mappings.\n" -"# You basically remove the leading 'XK_' prefix from the macro name in\n" -"# that file to get the Keysym name.\n" -"#\n" -"# One might parse a Keysym line with:\n" -"#\n" -"# int client, down, keysym; char *name, *hint;\n" -"# sscanf(line, \"Keysym %d %d %s %s\", &client, &down, &keysym, &name, &hint);\n" -"#\n" -"# The <hint> value is currently just None, KeyPress, or KeyRelease.\n" -"#\n" -"# In the future <hint> will provide a hint for the sequence of KeyCodes\n" -"# (i.e. keyboard scancodes) that x11vnc would inject to an X display to\n" -"# simulate the Keysym.\n" -"#\n" -"# You see, some Keysyms will require more than one injected Keycode to\n" -"# generate the symbol. E.g. the Keysym \"ampersand\" going down usually\n" -"# requires a Shift key going down, then the key with the \"&\" on it going\n" -"# down, and, perhaps, the Shift key going up (that is how x11vnc does it).\n" -"#\n" -"# The Keysym => Keycode(s) stuff gets pretty messy. Hopefully the Keysym\n" -"# info will be enough for most purposes (having identical keyboards on\n" -"# both sides helps).\n" -"#\n" -"# Here comes your stream. The following token will always indicate the\n" -"# end of this informational text:\n" -"# END_OF_TOP\n" -); - fflush(pipeinput_fh); - if (raw_fb_str) { - /* the pipe program may actually create the fb */ - sleep(1); - } -} - -/* -- xkb_bell.c -- */ -/* - * Bell event handling. Requires XKEYBOARD extension. - */ -int xkb_base_event_type = 0; - -#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 - -/* -- xrandr.h -- */ - -time_t last_subwin_trap = 0; -int subwin_trap_count = 0; - -XErrorHandler old_getimage_handler; -#define XRANDR_SET_TRAP_RET(x,y) \ - if (subwin || xrandr) { \ - 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); \ - } \ - } - -/* -- xrandr.c -- */ - -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; - } -} - -void handle_xrandr_change(int, int); - -int handle_subwin_resize(char *msg) { - int new_x, new_y; - int i, check = 10, ms = 250; /* 2.5 secs 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; -} - -int known_xrandr_mode(char *); - -void handle_xrandr_change(int new_x, int new_y) { - rfbClientIteratorPtr iter; - rfbClientPtr cl; - - /* sanity check xrandr_mode */ - if (! xrandr_mode) { - xrandr_mode = strdup("default"); - } else if (! known_xrandr_mode(xrandr_mode)) { - free(xrandr_mode); - xrandr_mode = strdup("default"); - } - rfbLog("xrandr_mode: %s\n", xrandr_mode); - if (!strcmp(xrandr_mode, "exit")) { - close_all_clients(); - rfbLog(" shutting down due to XRANDR event.\n"); - clean_up_exit(0); - } - if (!strcmp(xrandr_mode, "newfbsize") && 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; - } -} - -int known_sigpipe_mode(char *s) { -/* - * skip, ignore, exit - */ - if (strcmp(s, "skip") && strcmp(s, "ignore") && - strcmp(s, "exit")) { - return 0; - } else { - return 1; - } -} - -/* -- selection.c -- */ -/* - * Selection/Cutbuffer/Clipboard handlers. - */ - -static int own_selection = 0; /* whether we currently own PRIMARY or not */ -static int set_cutbuffer = 0; /* to avoid bouncing the CutText right back */ -static int sel_waittime = 15; /* some seconds to skip before first send */ -static 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. - */ -static char *xcut_str = NULL; - -/* - * 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). - */ -#define PROP_MAX (131072L) -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. - */ -static 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. - */ -static 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 -static 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); - } -} - -/* -- xevents.c -- */ - -void initialize_vnc_connect_prop() { - vnc_connect_str[0] = '\0'; - vnc_connect_prop = XInternAtom(dpy, "VNC_CONNECT", False); -} - -void initialize_xevents(void) { - static int did_xselect_input = 0; - static int did_xcreate_simple_window = 0; - static int did_vnc_connect_prop = 0; - static int did_xfixes = 0; - static int did_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; - } -} - -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); -} - - -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); -} - -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 - -int grab_npids = 1; - -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; -} - -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; -} - -/* -- remote.c -- */ - -/* - * for the wild-n-crazy -remote/-R interface. - */ -int send_remote_cmd(char *cmd, int query, int wait) { - FILE *in = NULL; - - if (client_connect_file) { - in = fopen(client_connect_file, "w"); - if (in == NULL) { - fprintf(stderr, "send_remote_cmd: could not open " - "connect file \"%s\" for writing\n", - client_connect_file); - perror("fopen"); - return 1; - } - } else if (vnc_connect_prop == None) { - initialize_vnc_connect_prop(); - if (vnc_connect_prop == None) { - fprintf(stderr, "send_remote_cmd: could not obtain " - "VNC_CONNECT X property\n"); - return 1; - } - } - - if (in != NULL) { - fprintf(stderr, ">>> sending remote command: \"%s\"\n via" - " connect file: %s\n", cmd, client_connect_file); - fprintf(in, "%s\n", cmd); - fclose(in); - } else { - fprintf(stderr, ">>> sending remote command: \"%s\" via" - " VNC_CONNECT X property.\n", cmd); - set_vnc_connect_prop(cmd); - XFlush(dpy); - } - - if (query || wait) { - char line[VNC_CONNECT_MAX]; - int rc=1, i=0, max=70, ms_sl=50; - - if (!strcmp(cmd, "cmd=stop")) { - max = 20; - } - for (i=0; i<max; i++) { - usleep(ms_sl * 1000); - if (client_connect_file) { - char *q; - in = fopen(client_connect_file, "r"); - if (in == NULL) { - fprintf(stderr, "send_remote_cmd: could" - " not open connect file \"%s\" for" - " writing\n", client_connect_file); - perror("fopen"); - return 1; - } - fgets(line, VNC_CONNECT_MAX, in); - fclose(in); - q = line; - while (*q != '\0') { - if (*q == '\n') *q = '\0'; - q++; - } - } else { - read_vnc_connect_prop(); - strncpy(line, vnc_connect_str, VNC_CONNECT_MAX); - } - if (strcmp(cmd, line)){ - if (query) { - fprintf(stdout, "%s\n", line); - fflush(stdout); - } - rc = 0; - break; - } - } - if (rc) { - fprintf(stderr, "error: could not connect to " - "an x11vnc server at %s (rc=%d)\n", - client_connect_file ? client_connect_file - : DisplayString(dpy), rc); - } - return rc; - } - return 0; -} - -int do_remote_query(char *remote_cmd, char *query_cmd, int remote_sync, - int qdefault) { - char *rcmd = NULL, *qcmd = NULL; - int rc = 1; - - if (qdefault && !query_cmd) { - query_cmd = remote_cmd; - remote_cmd = NULL; - } - - if (remote_cmd) { - rcmd = (char *) malloc(strlen(remote_cmd) + 5); - strcpy(rcmd, "cmd="); - strcat(rcmd, remote_cmd); - } - if (query_cmd) { - qcmd = (char *) malloc(strlen(query_cmd) + 5); - strcpy(qcmd, "qry="); - strcat(qcmd, query_cmd); - } - if (qdefault) { - char *res; - if (!qcmd) { - return 1; - } - res = process_remote_cmd(qcmd, 1); - fprintf(stdout, "%s\n", res); - fflush(stdout); - return 0; - } - - if (rcmd && qcmd) { - rc = send_remote_cmd(rcmd, 0, 1); - if (rc) { - free(rcmd); - free(qcmd); - return(rc); - } - rc = send_remote_cmd(qcmd, 1, 1); - } else if (rcmd) { - rc = send_remote_cmd(rcmd, 0, remote_sync); - free(rcmd); - } else if (qcmd) { - rc = send_remote_cmd(qcmd, 1, 1); - free(qcmd); - } - return rc; -} - -char *add_item(char *instr, char *item) { - char *p, *str; - int len, saw_item = 0; - - if (! instr || *instr == '\0') { - str = strdup(item); - return str; - } - len = strlen(instr) + 1 + strlen(item) + 1; - str = (char *) malloc(len); - str[0] = '\0'; - - /* n.b. instr will be modified; caller replaces with returned string */ - p = strtok(instr, ","); - while (p) { - if (!strcmp(p, item)) { - if (saw_item) { - p = strtok(NULL, ","); - continue; - } - saw_item = 1; - } else if (*p == '\0') { - p = strtok(NULL, ","); - continue; - } - if (str[0]) { - strcat(str, ","); - } - strcat(str, p); - p = strtok(NULL, ","); - } - if (! saw_item) { - if (str[0]) { - strcat(str, ","); - } - strcat(str, item); - } - return str; -} - -char *delete_item(char *instr, char *item) { - char *p, *str; - int len; - - if (! instr || *instr == '\0') { - str = strdup(""); - return str; - } - len = strlen(instr) + 1; - str = (char *) malloc(len); - str[0] = '\0'; - - /* n.b. instr will be modified; caller replaces with returned string */ - p = strtok(instr, ","); - while (p) { - if (!strcmp(p, item) || *p == '\0') { - p = strtok(NULL, ","); - continue; - } - if (str[0]) { - strcat(str, ","); - } - strcat(str, p); - p = strtok(NULL, ","); - } - return str; -} - -void if_8bpp_do_new_fb(void) { - if (bpp == 8) { - do_new_fb(0); - } else { - rfbLog(" bpp(%d) is not 8bpp, not resetting fb\n", bpp); - } -} - -void check_black_fb(void) { - if (!screen) { - return; - } - if (new_fb_size_clients(screen) != client_count) { - rfbLog("trying to send a black fb for non-newfbsize" - " clients %d != %d\n", client_count, - new_fb_size_clients(screen)); - push_black_screen(4); - } -} - -int check_httpdir(void) { - if (http_dir) { - return 1; - } else { - char *prog = NULL, *httpdir, *q; - struct stat sbuf; - int len; - - rfbLog("check_httpdir: trying to guess httpdir...\n"); - if (program_name[0] == '/') { - prog = strdup(program_name); - } else { - char cwd[1024]; - getcwd(cwd, 1024); - len = strlen(cwd) + 1 + strlen(program_name) + 1; - prog = (char *) malloc(len); - snprintf(prog, len, "%s/%s", cwd, program_name); - if (stat(prog, &sbuf) != 0) { - char *path = strdup(getenv("PATH")); - char *p, *base; - base = strrchr(program_name, '/'); - if (base) { - base++; - } else { - base = program_name; - } - - p = strtok(path, ":"); - while(p) { - free(prog); - len = strlen(p) + 1 + strlen(base) + 1; - prog = (char *) malloc(len); - snprintf(prog, len, "%s/%s", p, base); - if (stat(prog, &sbuf) == 0) { - break; - } - p = strtok(NULL, ":"); - } - free(path); - } - } - /* - * /path/to/bin/x11vnc - * /path/to/bin/../share/x11vnc/classes - * 12345678901234567 - */ - if ((q = strrchr(prog, '/')) == NULL) { - rfbLog("check_httpdir: bad program path: %s\n", prog); - free(prog); - return 0; - } - - len = strlen(prog) + 17 + 1; - *q = '\0'; - httpdir = (char *) malloc(len); - snprintf(httpdir, len, "%s/../share/x11vnc/classes", prog); - free(prog); - - if (stat(httpdir, &sbuf) == 0) { - /* good enough for me */ - rfbLog("check_httpdir: guessed directory:\n"); - rfbLog(" %s\n", httpdir); - http_dir = httpdir; - return 1; - } else { - /* try some hardwires: */ - if (stat("/usr/local/share/x11vnc/classes", - &sbuf) == 0) { - http_dir = - strdup("/usr/local/share/x11vnc/classes"); - return 1; - } - if (stat("/usr/share/x11vnc/classes", &sbuf) == 0) { - http_dir = strdup("/usr/share/x11vnc/classes"); - return 1; - } - rfbLog("check_httpdir: bad guess:\n"); - rfbLog(" %s\n", httpdir); - return 0; - } - } -} - -void http_connections(int on) { - if (!screen) { - return; - } - if (on) { - rfbLog("http_connections: turning on http service.\n"); - screen->httpInitDone = FALSE; - screen->httpDir = http_dir; - if (check_httpdir()) { - rfbHttpInitSockets(screen); - } - } else { - rfbLog("http_connections: turning off http service.\n"); - if (screen->httpListenSock > -1) { - close(screen->httpListenSock); - } - screen->httpListenSock = -1; - screen->httpDir = NULL; - } -} - -void reset_httpport(int old, int new) { - int hp = new; - if (hp < 0) { - rfbLog("reset_httpport: invalid httpport: %d\n", hp); - } else if (hp == old) { - rfbLog("reset_httpport: unchanged httpport: %d\n", hp); - } else if (inetd) { - rfbLog("reset_httpport: cannot set httpport: %d" - " in inetd.\n", hp); - } else if (screen) { - screen->httpPort = hp; - screen->httpInitDone = FALSE; - if (screen->httpListenSock > -1) { - close(screen->httpListenSock); - } - rfbLog("reset_httpport: setting httpport %d -> %d.\n", - old == -1 ? hp : old, hp); - rfbHttpInitSockets(screen); - } -} - -void reset_rfbport(int old, int new) { - int rp = new; - if (rp < 0) { - rfbLog("reset_rfbport: invalid rfbport: %d\n", rp); - } else if (rp == old) { - rfbLog("reset_rfbport: unchanged rfbport: %d\n", rp); - } else if (inetd) { - rfbLog("reset_rfbport: cannot set rfbport: %d" - " in inetd.\n", rp); - } else if (screen) { - rfbClientIteratorPtr iter; - rfbClientPtr cl; - int maxfd; - if (rp == 0) { - screen->autoPort = TRUE; - } else { - screen->autoPort = FALSE; - } - screen->port = rp; - screen->socketState = RFB_SOCKET_INIT; - - if (screen->listenSock > -1) { - close(screen->listenSock); - } - - rfbLog("reset_rfbport: setting rfbport %d -> %d.\n", - old == -1 ? rp : old, rp); - rfbInitSockets(screen); - - maxfd = screen->maxFd; - if (screen->udpSock > 0 && screen->udpSock > maxfd) { - maxfd = screen->udpSock; - } - iter = rfbGetClientIterator(screen); - while( (cl = rfbClientIteratorNext(iter)) ) { - if (cl->sock > -1) { - FD_SET(cl->sock, &(screen->allFds)); - if (cl->sock > maxfd) { - maxfd = cl->sock; - } - } - } - rfbReleaseClientIterator(iter); - - screen->maxFd = maxfd; - - set_vnc_desktop_name(); - } -} - -/* - * Do some sanity checking of the permissions on the XAUTHORITY and the - * -connect file. This is -privremote. What should be done is check - * for an empty host access list, currently we lazily do not bring in - * libXau yet. - */ -int remote_control_access_ok(void) { - struct stat sbuf; - - if (client_connect_file) { - if (stat(client_connect_file, &sbuf) == 0) { - if (sbuf.st_mode & S_IWOTH) { - rfbLog("connect file is writable by others.\n"); - rfbLog(" %s\n", client_connect_file); - return 0; - } - if (sbuf.st_mode & S_IWGRP) { - rfbLog("connect file is writable by group.\n"); - rfbLog(" %s\n", client_connect_file); - return 0; - } - } - } - - if (dpy) { - char tmp[1000]; - char *home, *xauth; - char *dpy_str = DisplayString(dpy); - Display *dpy2; - XHostAddress *xha; - Bool enabled; - int n; - - home = get_home_dir(); - if (getenv("XAUTHORITY") != NULL) { - xauth = getenv("XAUTHORITY"); - } else if (home) { - int len = 1000 - strlen("/.Xauthority") - 1; - strncpy(tmp, home, len); - strcat(tmp, "/.Xauthority"); - xauth = tmp; - } else { - rfbLog("cannot determine default XAUTHORITY.\n"); - return 0; - } - if (home) { - free(home); - } - if (stat(xauth, &sbuf) == 0) { - if (sbuf.st_mode & S_IWOTH) { - rfbLog("XAUTHORITY is writable by others!!\n"); - rfbLog(" %s\n", xauth); - return 0; - } - if (sbuf.st_mode & S_IWGRP) { - rfbLog("XAUTHORITY is writable by group!!\n"); - rfbLog(" %s\n", xauth); - return 0; - } - if (sbuf.st_mode & S_IROTH) { - rfbLog("XAUTHORITY is readable by others.\n"); - rfbLog(" %s\n", xauth); - return 0; - } - if (sbuf.st_mode & S_IRGRP) { - rfbLog("XAUTHORITY is readable by group.\n"); - rfbLog(" %s\n", xauth); - return 0; - } - } - - xha = XListHosts(dpy, &n, &enabled); - if (! enabled) { - rfbLog("X access control is disabled, X clients can\n"); - rfbLog(" connect from any host. Run 'xhost -'\n"); - return 0; - } - if (xha) { - int i; - rfbLog("The following hosts can connect w/o X11 " - "auth:\n"); - for (i=0; i<n; i++) { - if (xha[i].family == FamilyInternet) { - char *str = raw2host(xha[i].address, - xha[i].length); - char *ip = raw2ip(xha[i].address); - rfbLog(" %s/%s\n", str, ip); - free(str); - free(ip); - } else { - rfbLog(" unknown-%d\n", i+1); - } - } - XFree(xha); - return 0; - } - - if (getenv("XAUTHORITY")) { - xauth = strdup(getenv("XAUTHORITY")); - } else { - xauth = NULL; - } - set_env("XAUTHORITY", "/impossible/xauthfile"); - - fprintf(stderr, "\nChecking if display %s requires " - "XAUTHORITY\n", dpy_str); - fprintf(stderr, " -- (ignore any Xlib: errors that" - " follow) --\n"); - dpy2 = XOpenDisplay(dpy_str); - fflush(stderr); - fprintf(stderr, " -- (done checking) --\n\n"); - - if (xauth) { - set_env("XAUTHORITY", xauth); - free(xauth); - } else { - xauth = getenv("XAUTHORITY"); - if (xauth) { - *(xauth-2) = '_'; /* yow */ - } - } - if (dpy2) { - rfbLog("XAUTHORITY is not required on display.\n"); - rfbLog(" %s\n", DisplayString(dpy)); - XCloseDisplay(dpy2); - return 0; - } - - } - return 1; -} - -/* - * Huge, ugly switch to handle all remote commands and queries - * -remote/-R and -query/-Q. - */ -char *process_remote_cmd(char *cmd, int stringonly) { -#if REMOTE_CONTROL - char *p = cmd; - char *co = ""; - char buf[VNC_CONNECT_MAX]; - int bufn = VNC_CONNECT_MAX; - int query = 0; - static char *prev_cursors_mode = NULL; - - if (!query_default && !accept_remote_cmds) { - rfbLog("remote commands disabled: %s\n", cmd); - return NULL; - } - - if (!query_default && priv_remote) { - if (! remote_control_access_ok()) { - rfbLog("** Disabling remote commands in -privremote " - "mode.\n"); - accept_remote_cmds = 0; - return NULL; - } - } - - strcpy(buf, ""); - if (strstr(cmd, "cmd=") == cmd) { - p += strlen("cmd="); - } else if (strstr(cmd, "qry=") == cmd) { - query = 1; - if (strchr(cmd, ',')) { - /* comma separated batch mode */ - char *s, *q, *res; - char tmp[512]; - strcpy(buf, ""); - s = strdup(cmd + strlen("qry=")); - q = strtok(s, ","); - while (q) { - strcpy(tmp, "qry="); - strncat(tmp, q, 500); - res = process_remote_cmd(tmp, 1); - if (res && strlen(buf)+strlen(res) - >= VNC_CONNECT_MAX - 1) { - rfbLog("overflow in process_remote_cmd:" - " %s -- %s\n", buf, res); - free(res); - break; - } - if (res) { - strcat(buf, res); - free(res); - } - q = strtok(NULL, ","); - if (q) { - strcat(buf, ","); - } - } - free(s); - goto qry; - } - p += strlen("qry="); - } else { - rfbLog("ignoring malformed command: %s\n", cmd); - goto done; - } - - /* allow var=val usage */ - if (!strchr(p, ':')) { - char *q = strchr(p, '='); - if (q) *q = ':'; - } - - /* always call like: COLON_CHECK("foobar:") */ -#define COLON_CHECK(str) \ - if (strstr(p, str) != p) { \ - co = ":"; \ - if (! query) { \ - goto done; \ - } \ - } else { \ - char *q = strchr(p, ':'); \ - if (query && q != NULL) { \ - *(q+1) = '\0'; \ - } \ - } - -#define NOTAPP \ - if (query) { \ - if (strchr(p, ':')) { \ - snprintf(buf, bufn, "ans=%sN/A", p); \ - } else { \ - snprintf(buf, bufn, "ans=%s:N/A", p); \ - } \ - goto qry; \ - } - -#define NOTAPPRO \ - if (query) { \ - if (strchr(p, ':')) { \ - snprintf(buf, bufn, "aro=%sN/A", p); \ - } else { \ - snprintf(buf, bufn, "aro=%s:N/A", p); \ - } \ - goto qry; \ - } - -/* - * Maybe add: passwdfile logfile bg rfbauth passwd... - */ - if (!strcmp(p, "stop") || !strcmp(p, "quit") || - !strcmp(p, "exit") || !strcmp(p, "shutdown")) { - NOTAPP - close_all_clients(); - rfbLog("remote_cmd: setting shut_down flag\n"); - shut_down = 1; - - } else if (!strcmp(p, "ping")) { - query = 1; - if (rfb_desktop_name) { - snprintf(buf, bufn, "ans=%s:%s", p, rfb_desktop_name); - } else { - snprintf(buf, bufn, "ans=%s:%s", p, "unknown"); - } - goto qry; - - } else if (!strcmp(p, "blacken") || !strcmp(p, "zero")) { - NOTAPP - push_black_screen(4); - } else if (!strcmp(p, "refresh")) { - NOTAPP - refresh_screen(1); - } else if (!strcmp(p, "reset")) { - NOTAPP - do_new_fb(1); - } else if (strstr(p, "zero:") == p) { /* skip-cmd-list */ - int x1, y1, x2, y2; - NOTAPP - p += strlen("zero:"); - if (sscanf(p, "%d,%d,%d,%d", &x1, &y1, &x2, &y2) == 4) { - int mark = 1; - rfbLog("zeroing rect: %s\n", p); - if (x1 < 0 || x2 < 0) { - x1 = nabs(x1); - x2 = nabs(x2); - mark = 0; /* hack for testing */ - } - - zero_fb(x1, y1, x2, y2); - if (mark) { - mark_rect_as_modified(x1, y1, x2, y2, 0); - } - push_sleep(4); - } - } else if (strstr(p, "damagefb:") == p) { /* skip-cmd-list */ - int delay; - NOTAPP - p += strlen("damagefb:"); - if (sscanf(p, "%d", &delay) == 1) { - rfbLog("damaging client fb's for %d secs " - "(by not marking rects.)\n", delay); - damage_time = time(0); - damage_delay = delay; - } - - } else if (strstr(p, "close") == p) { - NOTAPP - COLON_CHECK("close:") - p += strlen("close:"); - close_clients(p); - } else if (strstr(p, "disconnect") == p) { - NOTAPP - COLON_CHECK("disconnect:") - p += strlen("disconnect:"); - close_clients(p); - - } else if (strstr(p, "id") == p) { - int ok = 0; - Window twin; - COLON_CHECK("id:") - if (query) { - snprintf(buf, bufn, "ans=%s%s0x%lx", p, co, - rootshift ? 0 : subwin); - goto qry; - } - p += strlen("id:"); - if (*p == '\0' || !strcmp("root", p)) { - /* back to root win */ - twin = 0x0; - ok = 1; - } else if (!strcmp("pick", p)) { - twin = 0x0; - if (safe_remote_only) { - rfbLog("unsafe: '-id pick'\n"); - } else if (pick_windowid(&twin)) { - ok = 1; - } - } else if (! scan_hexdec(p, &twin)) { - rfbLog("-id: skipping incorrect hex/dec number:" - " %s\n", p); - } else { - ok = 1; - } - if (ok) { - if (twin && ! valid_window(twin, NULL, 0)) { - rfbLog("skipping invalid sub-window: 0x%lx\n", - twin); - } else { - subwin = twin; - rootshift = 0; - check_black_fb(); - do_new_fb(1); - } - } - } else if (strstr(p, "sid") == p) { - int ok = 0; - Window twin; - COLON_CHECK("sid:") - if (query) { - snprintf(buf, bufn, "ans=%s%s0x%lx", p, co, - !rootshift ? 0 : subwin); - goto qry; - } - p += strlen("sid:"); - if (*p == '\0' || !strcmp("root", p)) { - /* back to root win */ - twin = 0x0; - ok = 1; - } else if (!strcmp("pick", p)) { - twin = 0x0; - if (safe_remote_only) { - rfbLog("unsafe: '-sid pick'\n"); - } else if (pick_windowid(&twin)) { - ok = 1; - } - } else if (! scan_hexdec(p, &twin)) { - rfbLog("-sid: skipping incorrect hex/dec number: %s\n", p); - } else { - ok = 1; - } - if (ok) { - if (twin && ! valid_window(twin, NULL, 0)) { - rfbLog("skipping invalid sub-window: 0x%lx\n", - twin); - } else { - subwin = twin; - rootshift = 1; - check_black_fb(); - do_new_fb(1); - } - } - } else if (strstr(p, "waitmapped") == p) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, - subwin_wait_mapped); - goto qry; - } - subwin_wait_mapped = 1; - } else if (strstr(p, "nowaitmapped") == p) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, - !subwin_wait_mapped); - goto qry; - } - subwin_wait_mapped = 0; - - } else if (!strcmp(p, "clip") || - strstr(p, "clip:") == p) { /* skip-cmd-list */ - COLON_CHECK("clip:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%s", p, co, - NONUL(clip_str)); - goto qry; - } - p += strlen("clip:"); - if (clip_str) free(clip_str); - clip_str = strdup(p); - - /* OK, this requires a new fb... */ - do_new_fb(1); - - } else if (!strcmp(p, "flashcmap")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, flash_cmap); - goto qry; - } - rfbLog("remote_cmd: turning on flashcmap mode.\n"); - flash_cmap = 1; - } else if (!strcmp(p, "noflashcmap")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, !flash_cmap); - goto qry; - } - rfbLog("remote_cmd: turning off flashcmap mode.\n"); - flash_cmap = 0; - - } else if (strstr(p, "shiftcmap") == p) { - COLON_CHECK("shiftcmap:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%d", p, co, shift_cmap); - goto qry; - } - p += strlen("shiftcmap:"); - shift_cmap = atoi(p); - rfbLog("remote_cmd: set -shiftcmap %d\n", shift_cmap); - do_new_fb(1); - - } else if (!strcmp(p, "truecolor")) { - int orig = force_indexed_color; - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, - !force_indexed_color); - goto qry; - } - rfbLog("remote_cmd: turning off notruecolor mode.\n"); - force_indexed_color = 0; - if (orig != force_indexed_color) { - if_8bpp_do_new_fb(); - } - } else if (!strcmp(p, "notruecolor")) { - int orig = force_indexed_color; - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, - force_indexed_color); - goto qry; - } - rfbLog("remote_cmd: turning on notruecolor mode.\n"); - force_indexed_color = 1; - if (orig != force_indexed_color) { - if_8bpp_do_new_fb(); - } - - } else if (!strcmp(p, "overlay")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, overlay); - goto qry; - } - rfbLog("remote_cmd: turning on -overlay mode.\n"); - if (!overlay_present) { - rfbLog("skipping: overlay extension not present.\n"); - } else if (overlay) { - rfbLog("skipping: already in -overlay mode.\n"); - } else { - int reset_mem = 0; - /* here we go... */ - if (using_shm) { - rfbLog("setting -noshm mode.\n"); - using_shm = 0; - reset_mem = 1; - } - overlay = 1; - do_new_fb(reset_mem); - } - } else if (!strcmp(p, "nooverlay")) { - int orig = overlay; - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, !overlay); - goto qry; - } - rfbLog("remote_cmd: turning off overlay mode\n"); - overlay = 0; - if (!overlay_present) { - rfbLog("warning: overlay extension not present.\n"); - } else if (!orig) { - rfbLog("skipping: already not in -overlay mode.\n"); - } else { - /* here we go... */ - do_new_fb(0); - } - - } else if (!strcmp(p, "overlay_cursor") || - !strcmp(p, "overlay_yescursor") || - !strcmp(p, "nooverlay_nocursor")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, overlay_cursor); - goto qry; - } - rfbLog("remote_cmd: turning on overlay_cursor mode.\n"); - overlay_cursor = 1; - if (!overlay_present) { - rfbLog("warning: overlay extension not present.\n"); - } else if (!overlay) { - rfbLog("warning: not in -overlay mode.\n"); - } else { - rfbLog("You may want to run -R noshow_cursor or\n"); - rfbLog(" -R cursor:none to disable any extra " - "cursors.\n"); - } - } else if (!strcmp(p, "nooverlay_cursor") || - !strcmp(p, "nooverlay_yescursor") || - !strcmp(p, "overlay_nocursor")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, !overlay_cursor); - goto qry; - } - rfbLog("remote_cmd: turning off overlay_cursor mode\n"); - overlay_cursor = 0; - if (!overlay_present) { - rfbLog("warning: overlay extension not present.\n"); - } else if (!overlay) { - rfbLog("warning: not in -overlay mode.\n"); - } else { - rfbLog("You may want to run -R show_cursor or\n"); - rfbLog(" -R cursor:... to re-enable any cursors.\n"); - } - - } else if (strstr(p, "visual") == p) { - COLON_CHECK("visual:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%s", p, co, - NONUL(visual_str)); - goto qry; - } - p += strlen("visual:"); - if (visual_str) free(visual_str); - visual_str = strdup(p); - - /* OK, this requires a new fb... */ - do_new_fb(0); - - } else if (!strcmp(p, "scale") || - strstr(p, "scale:") == p) { /* skip-cmd-list */ - COLON_CHECK("scale:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%s", p, co, - NONUL(scale_str)); - goto qry; - } - p += strlen("scale:"); - if (scale_str) free(scale_str); - scale_str = strdup(p); - - /* OK, this requires a new fb... */ - check_black_fb(); - do_new_fb(0); - - } else if (!strcmp(p, "scale_cursor") || - strstr(p, "scale_cursor:") == p) { /* skip-cmd-list */ - COLON_CHECK("scale_cursor:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%s", p, co, - NONUL(scale_cursor_str)); - goto qry; - } - p += strlen("scale_cursor:"); - if (scale_cursor_str) free(scale_cursor_str); - if (*p == '\0') { - scale_cursor_str = NULL; - } else { - scale_cursor_str = strdup(p); - } - setup_cursors_and_push(); - - } else if (!strcmp(p, "viewonly")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, view_only); - goto qry; - } - rfbLog("remote_cmd: enable viewonly mode.\n"); - view_only = 1; - } else if (!strcmp(p, "noviewonly")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, !view_only); - goto qry; - } - rfbLog("remote_cmd: disable viewonly mode.\n"); - view_only = 0; - if (raw_fb) set_raw_fb_params(0); - - } else if (!strcmp(p, "shared")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, shared); goto qry; - } - rfbLog("remote_cmd: enable sharing.\n"); - shared = 1; - if (screen) { - screen->alwaysShared = TRUE; - screen->neverShared = FALSE; - } - } else if (!strcmp(p, "noshared")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, !shared); goto qry; - } - rfbLog("remote_cmd: disable sharing.\n"); - shared = 0; - if (screen) { - screen->alwaysShared = FALSE; - screen->neverShared = TRUE; - } - - } else if (!strcmp(p, "forever")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, 1-connect_once); - goto qry; - } - rfbLog("remote_cmd: enable -forever mode.\n"); - connect_once = 0; - } else if (!strcmp(p, "noforever") || !strcmp(p, "once")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, connect_once); - goto qry; - } - rfbLog("remote_cmd: disable -forever mode.\n"); - connect_once = 1; - - } else if (strstr(p, "timeout") == p) { - int to; - COLON_CHECK("timeout:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%d", p, co, - first_conn_timeout); - goto qry; - } - p += strlen("timeout:"); - to = atoi(p); - if (to > 0 ) { - to = -to; - } - first_conn_timeout = to; - rfbLog("remote_cmd: set -timeout to %d\n", -to); - -#if 0 - } else if (!strcmp(p, "filexfer")) { - /* does this work after rfbInitServer? */ - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, filexfer); - goto qry; - } - rfbLog("remote_cmd: enabling -filexfer.\n"); - filexfer = 1; - rfbRegisterTightVNCFileTransferExtension(); -#endif - - } else if (!strcmp(p, "deny") || !strcmp(p, "lock")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, deny_all); - goto qry; - } - rfbLog("remote_cmd: denying new connections.\n"); - deny_all = 1; - } else if (!strcmp(p, "nodeny") || !strcmp(p, "unlock")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, !deny_all); - goto qry; - } - rfbLog("remote_cmd: allowing new connections.\n"); - deny_all = 0; - - } else if (strstr(p, "connect") == p) { - NOTAPP - COLON_CHECK("connect:") - p += strlen("connect:"); - /* this is a reverse connection */ - reverse_connect(p); - - } else if (strstr(p, "allowonce") == p) { - COLON_CHECK("allowonce:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%s", p, co, - NONUL(allow_once)); - goto qry; - } - p += strlen("allowonce:"); - allow_once = strdup(p); - rfbLog("remote_cmd: set allow_once %s\n", allow_once); - - } else if (strstr(p, "allow") == p) { - char *before, *old; - COLON_CHECK("allow:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%s", p, co, - NONUL(allow_list)); - goto qry; - } - p += strlen("allow:"); - if (allow_list && strchr(allow_list, '/')) { - rfbLog("remote_cmd: cannot use allow:host\n"); - rfbLog("in '-allow %s' mode.\n", allow_list); - goto done; - } - if (allow_list) { - before = strdup(allow_list); - } else { - before = strdup(""); - } - - old = allow_list; - if (*p == '+') { - p++; - allow_list = add_item(allow_list, p); - } else if (*p == '-') { - p++; - allow_list = delete_item(allow_list, p); - } else { - allow_list = strdup(p); - } - - if (strcmp(before, allow_list)) { - rfbLog("remote_cmd: modified allow_list:\n"); - rfbLog(" from: \"%s\"\n", before); - rfbLog(" to: \"%s\"\n", allow_list); - } - if (old) free(old); - free(before); - - } else if (!strcmp(p, "localhost")) { - char *before, *old; - if (query) { - int state = 0; - char *s = allow_list; - if (s && (!strcmp(s, "127.0.0.1") || - !strcmp(s, "localhost"))) { - state = 1; - } - snprintf(buf, bufn, "ans=%s:%d", p, state); - goto qry; - } - if (allow_list) { - before = strdup(allow_list); - } else { - before = strdup(""); - } - old = allow_list; - - allow_list = strdup("127.0.0.1"); - - if (strcmp(before, allow_list)) { - rfbLog("remote_cmd: modified allow_list:\n"); - rfbLog(" from: \"%s\"\n", before); - rfbLog(" to: \"%s\"\n", allow_list); - } - if (old) free(old); - free(before); - - if (listen_str) { - free(listen_str); - } - listen_str = strdup("localhost"); - - screen->listenInterface = htonl(INADDR_LOOPBACK); - rfbLog("listening on loopback network only.\n"); - rfbLog("allow list is: '%s'\n", NONUL(allow_list)); - reset_rfbport(-1, screen->port); - if (screen->httpListenSock > -1) { - reset_httpport(-1, screen->httpPort); - } - } else if (!strcmp(p, "nolocalhost")) { - char *before, *old; - if (query) { - int state = 0; - char *s = allow_list; - if (s && (!strcmp(s, "127.0.0.1") || - !strcmp(s, "localhost"))) { - state = 1; - } - snprintf(buf, bufn, "ans=%s:%d", p, !state); - goto qry; - } - if (allow_list) { - before = strdup(allow_list); - } else { - before = strdup(""); - } - old = allow_list; - - allow_list = strdup(""); - - if (strcmp(before, allow_list)) { - rfbLog("remote_cmd: modified allow_list:\n"); - rfbLog(" from: \"%s\"\n", before); - rfbLog(" to: \"%s\"\n", allow_list); - } - if (old) free(old); - free(before); - - if (listen_str) { - free(listen_str); - } - listen_str = NULL; - - screen->listenInterface = htonl(INADDR_ANY); - rfbLog("listening on ALL network interfaces.\n"); - rfbLog("allow list is: '%s'\n", NONUL(allow_list)); - reset_rfbport(-1, screen->port); - if (screen->httpListenSock > -1) { - reset_httpport(-1, screen->httpPort); - } - - } else if (strstr(p, "listen") == p) { - char *before; - int ok, mod = 0; - - COLON_CHECK("listen:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%s", p, co, - NONUL(listen_str)); - goto qry; - } - if (listen_str) { - before = strdup(listen_str); - } else { - before = strdup(""); - } - p += strlen("listen:"); - - listen_str = strdup(p); - - if (strcmp(before, listen_str)) { - rfbLog("remote_cmd: modified listen_str:\n"); - rfbLog(" from: \"%s\"\n", before); - rfbLog(" to: \"%s\"\n", listen_str); - mod = 1; - } - - ok = 1; - if (listen_str == NULL || *listen_str == '\0' || - !strcmp(listen_str, "any")) { - screen->listenInterface = htonl(INADDR_ANY); - } else if (!strcmp(listen_str, "localhost")) { - screen->listenInterface = htonl(INADDR_LOOPBACK); - } else { - struct hostent *hp; - in_addr_t iface = inet_addr(listen_str); - if (iface == htonl(INADDR_NONE)) { - if (!host_lookup) { - ok = 0; - } else if (!(hp = gethostbyname(listen_str))) { - ok = 0; - } else { - iface = *(unsigned long *)hp->h_addr; - } - } - if (ok) { - screen->listenInterface = iface; - } - } - - if (ok && mod) { - int is_loopback = 0; - in_addr_t iface = screen->listenInterface; - - if (allow_list) { - if (!strcmp(allow_list, "127.0.0.1") || - !strcmp(allow_list, "localhost")) { - is_loopback = 1; - } - } - if (iface != htonl(INADDR_LOOPBACK)) { - if (is_loopback) { - rfbLog("re-setting -allow list to all " - "hosts for non-loopback listening.\n"); - if (allow_list) { - free(allow_list); - } - allow_list = NULL; - } - } else { - if (!is_loopback) { - if (allow_list) { - free(allow_list); - } - rfbLog("setting -allow list to 127.0.0.1\n"); - allow_list = strdup("127.0.0.1"); - } - } - } - if (ok) { - rfbLog("allow list is: '%s'\n", NONUL(allow_list)); - reset_rfbport(-1, screen->port); - if (screen->httpListenSock > -1) { - reset_httpport(-1, screen->httpPort); - } - free(before); - } else { - rfbLog("invalid listen string: %s\n", listen_str); - free(listen_str); - listen_str = before; - } - } else if (!strcmp(p, "lookup")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, host_lookup); - goto qry; - } - rfbLog("remote_cmd: enabling hostname lookup.\n"); - host_lookup = 1; - } else if (!strcmp(p, "nolookup")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, !host_lookup); - goto qry; - } - rfbLog("remote_cmd: disabling hostname lookup.\n"); - host_lookup = 0; - - } else if (strstr(p, "accept") == p) { - int doit = 1; - COLON_CHECK("accept:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%s", p, co, - NONUL(accept_cmd)); - goto qry; - } - p += strlen("accept:"); - if (safe_remote_only) { - if (icon_mode && !strcmp(p, "")) { /* skip-cmd-list */ - ; - } else if (icon_mode && !strcmp(p, "popup")) { /* skip-cmd-list */ - ; - } else { - rfbLog("unsafe: %s\n", p); - doit = 0; - } - } - - if (doit) { - if (accept_cmd) free(accept_cmd); - accept_cmd = strdup(p); - } - - } else if (strstr(p, "gone") == p) { - COLON_CHECK("gone:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%s", p, co, - NONUL(gone_cmd)); - goto qry; - } - if (safe_remote_only) { - rfbLog("unsafe: %s\n", p); - } else { - p += strlen("gone:"); - if (gone_cmd) free(gone_cmd); - gone_cmd = strdup(p); - } - - } else if (!strcmp(p, "shm")) { - int orig = using_shm; - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, using_shm); - goto qry; - } - rfbLog("remote_cmd: turning off noshm mode.\n"); - using_shm = 1; - if (raw_fb) set_raw_fb_params(0); - - if (orig != using_shm) { - do_new_fb(1); - } else { - rfbLog(" already in shm mode.\n"); - } - } else if (!strcmp(p, "noshm")) { - int orig = using_shm; - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, !using_shm); - goto qry; - } - rfbLog("remote_cmd: turning on noshm mode.\n"); - using_shm = 0; - if (orig != using_shm) { - do_new_fb(1); - } else { - rfbLog(" already in noshm mode.\n"); - } - - } else if (!strcmp(p, "flipbyteorder")) { - int orig = flip_byte_order; - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, flip_byte_order); - goto qry; - } - rfbLog("remote_cmd: turning on flipbyteorder mode.\n"); - flip_byte_order = 1; - if (orig != flip_byte_order) { - if (! using_shm) { - do_new_fb(1); - } else { - rfbLog(" using shm, not resetting fb\n"); - } - } - } else if (!strcmp(p, "noflipbyteorder")) { - int orig = flip_byte_order; - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, !flip_byte_order); - goto qry; - } - rfbLog("remote_cmd: turning off flipbyteorder mode.\n"); - flip_byte_order = 0; - if (orig != flip_byte_order) { - if (! using_shm) { - do_new_fb(1); - } else { - rfbLog(" using shm, not resetting fb\n"); - } - } - - } else if (!strcmp(p, "onetile")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, single_copytile); - goto qry; - } - rfbLog("remote_cmd: enable -onetile mode.\n"); - single_copytile = 1; - } else if (!strcmp(p, "noonetile")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, !single_copytile); - goto qry; - } - rfbLog("remote_cmd: disable -onetile mode.\n"); - if (tile_shm_count < ntiles_x) { - rfbLog(" this has no effect: tile_shm_count=%d" - " ntiles_x=%d\n", tile_shm_count, ntiles_x); - - } - single_copytile = 0; - - } else if (strstr(p, "solid_color") == p) { - /* - * n.b. this solid stuff perhaps should reflect - * safe_remote_only but at least the command names - * are fixed. - */ - char *new; - int doit = 1; - COLON_CHECK("solid_color:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%s", p, co, - NONUL(solid_str)); - goto qry; - } - p += strlen("solid_color:"); - if (*p != '\0') { - new = strdup(p); - } else { - new = strdup(solid_default); - } - rfbLog("remote_cmd: solid %s -> %s\n", NONUL(solid_str), new); - - if (solid_str) { - if (!strcmp(solid_str, new)) { - doit = 0; - } - free(solid_str); - } - solid_str = new; - use_solid_bg = 1; - if (raw_fb) set_raw_fb_params(0); - - if (doit && client_count) { - solid_bg(0); - } - } else if (!strcmp(p, "solid")) { - int orig = use_solid_bg; - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, use_solid_bg); - goto qry; - } - rfbLog("remote_cmd: enable -solid mode\n"); - if (! solid_str) { - solid_str = strdup(solid_default); - } - use_solid_bg = 1; - if (raw_fb) set_raw_fb_params(0); - if (client_count && !orig) { - solid_bg(0); - } - } else if (!strcmp(p, "nosolid")) { - int orig = use_solid_bg; - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, !use_solid_bg); - goto qry; - } - rfbLog("remote_cmd: disable -solid mode\n"); - use_solid_bg = 0; - if (client_count && orig) { - solid_bg(1); - } - - } else if (strstr(p, "blackout") == p) { - char *before, *old; - COLON_CHECK("blackout:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%s", p, co, - NONUL(blackout_str)); - goto qry; - } - p += strlen("blackout:"); - if (blackout_str) { - before = strdup(blackout_str); - } else { - before = strdup(""); - } - old = blackout_str; - if (*p == '+') { - p++; - blackout_str = add_item(blackout_str, p); - } else if (*p == '-') { - p++; - blackout_str = delete_item(blackout_str, p); - } else { - blackout_str = strdup(p); - } - if (strcmp(before, blackout_str)) { - rfbLog("remote_cmd: changing -blackout\n"); - rfbLog(" from: %s\n", before); - rfbLog(" to: %s\n", blackout_str); - if (0 && !strcmp(blackout_str, "") && - single_copytile_orig != single_copytile) { - rfbLog("resetting single_copytile to: %d\n", - single_copytile_orig); - single_copytile = single_copytile_orig; - } - initialize_blackouts_and_xinerama(); - } - if (old) free(old); - free(before); - - } else if (!strcmp(p, "xinerama")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, xinerama); - goto qry; - } - rfbLog("remote_cmd: enable xinerama mode. (if applicable).\n"); - xinerama = 1; - initialize_blackouts_and_xinerama(); - } else if (!strcmp(p, "noxinerama")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, !xinerama); - goto qry; - } - rfbLog("remote_cmd: disable xinerama mode. (if applicable).\n"); - xinerama = 0; - initialize_blackouts_and_xinerama(); - - } else if (!strcmp(p, "xtrap")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, xtrap_input); - goto qry; - } - rfbLog("remote_cmd: enable xtrap input mode." - "(if applicable).\n"); - if (! xtrap_input) { - xtrap_input = 1; - disable_grabserver(dpy, 1); - } - - } else if (!strcmp(p, "noxtrap")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, !xtrap_input); - goto qry; - } - rfbLog("remote_cmd: disable xtrap input mode." - "(if applicable).\n"); - if (xtrap_input) { - xtrap_input = 0; - disable_grabserver(dpy, 1); - } - - } else if (!strcmp(p, "xrandr")) { - int orig = xrandr; - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, xrandr); goto qry; - } - if (xrandr_present) { - rfbLog("remote_cmd: enable xrandr mode.\n"); - xrandr = 1; - if (raw_fb) set_raw_fb_params(0); - if (! xrandr_mode) { - xrandr_mode = strdup("default"); - } - if (orig != xrandr) { - initialize_xrandr(); - } - } else { - rfbLog("remote_cmd: XRANDR ext. not present.\n"); - } - } else if (!strcmp(p, "noxrandr")) { - int orig = xrandr; - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, !xrandr); goto qry; - } - xrandr = 0; - if (xrandr_present) { - rfbLog("remote_cmd: disable xrandr mode.\n"); - if (orig != xrandr) { - initialize_xrandr(); - } - } else { - rfbLog("remote_cmd: XRANDR ext. not present.\n"); - } - } else if (strstr(p, "xrandr_mode") == p) { - int orig = xrandr; - COLON_CHECK("xrandr_mode:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%s", p, co, - NONUL(xrandr_mode)); - goto qry; - } - p += strlen("xrandr_mode:"); - if (!strcmp("none", p)) { - xrandr = 0; - } else { - if (known_xrandr_mode(p)) { - if (xrandr_mode) free(xrandr_mode); - xrandr_mode = strdup(p); - } else { - rfbLog("skipping unknown xrandr mode: %s\n", p); - goto done; - } - xrandr = 1; - } - if (xrandr_present) { - if (xrandr) { - rfbLog("remote_cmd: enable xrandr mode.\n"); - } else { - rfbLog("remote_cmd: disable xrandr mode.\n"); - } - if (! xrandr_mode) { - xrandr_mode = strdup("default"); - } - if (orig != xrandr) { - initialize_xrandr(); - } - } else { - rfbLog("remote_cmd: XRANDR ext. not present.\n"); - } - - } else if (strstr(p, "padgeom") == p) { - COLON_CHECK("padgeom:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%s", p, co, - NONUL(pad_geometry)); - goto qry; - } - p += strlen("padgeom:"); - if (!strcmp("force", p) || !strcmp("do",p) || !strcmp("go",p)) { - rfbLog("remote_cmd: invoking install_padded_fb()\n"); - install_padded_fb(pad_geometry); - } else { - if (pad_geometry) free(pad_geometry); - pad_geometry = strdup(p); - rfbLog("remote_cmd: set padgeom to: %s\n", - pad_geometry); - } - - } else if (!strcmp(p, "quiet") || !strcmp(p, "q")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, quiet); goto qry; - } - rfbLog("remote_cmd: turning on quiet mode.\n"); - quiet = 1; - } else if (!strcmp(p, "noquiet")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, !quiet); goto qry; - } - rfbLog("remote_cmd: turning off quiet mode.\n"); - quiet = 0; - - } else if (!strcmp(p, "modtweak")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, use_modifier_tweak); - goto qry; - } - rfbLog("remote_cmd: enabling -modtweak mode.\n"); - if (! use_modifier_tweak) { - use_modifier_tweak = 1; - initialize_modtweak(); - } - use_modifier_tweak = 1; - - } else if (!strcmp(p, "nomodtweak")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, - !use_modifier_tweak); - goto qry; - } - rfbLog("remote_cmd: enabling -nomodtweak mode.\n"); - got_nomodtweak = 1; - use_modifier_tweak = 0; - - } else if (!strcmp(p, "xkb")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, use_xkb_modtweak); - goto qry; - } - if (! xkb_present) { - rfbLog("remote_cmd: cannot enable -xkb " - "modtweak mode (not supported on X display)\n"); - goto done; - } - rfbLog("remote_cmd: enabling -xkb modtweak mode" - " (if supported).\n"); - if (! use_modifier_tweak || ! use_xkb_modtweak) { - use_modifier_tweak = 1; - use_xkb_modtweak = 1; - initialize_modtweak(); - } - use_modifier_tweak = 1; - use_xkb_modtweak = 1; - - } else if (!strcmp(p, "noxkb")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, !use_xkb_modtweak); - goto qry; - } - if (! xkb_present) { - rfbLog("remote_cmd: cannot disable -xkb " - "modtweak mode (not supported on X display)\n"); - goto done; - } - rfbLog("remote_cmd: disabling -xkb modtweak mode.\n"); - use_xkb_modtweak = 0; - got_noxkb = 1; - initialize_modtweak(); - - } else if (strstr(p, "skip_keycodes") == p) { - COLON_CHECK("skip_keycodes:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%s", p, co, - NONUL(skip_keycodes)); - goto qry; - } - p += strlen("skip_keycodes:"); - rfbLog("remote_cmd: setting xkb -skip_keycodes" - " to:\n\t'%s'\n", p); - if (! xkb_present) { - rfbLog("remote_cmd: warning xkb not present\n"); - } else if (! use_xkb_modtweak) { - rfbLog("remote_cmd: turning on xkb.\n"); - use_xkb_modtweak = 1; - if (! use_modifier_tweak) { - rfbLog("remote_cmd: turning on modtweak.\n"); - use_modifier_tweak = 1; - } - } - if (skip_keycodes) free(skip_keycodes); - skip_keycodes = strdup(p); - initialize_modtweak(); - - } else if (!strcmp(p, "sloppy_keys")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, sloppy_keys); - goto qry; - } - sloppy_keys += 1; - rfbLog("remote_cmd: set sloppy_keys to: %d\n", sloppy_keys); - } else if (!strcmp(p, "nosloppy_keys")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, !sloppy_keys); - goto qry; - } - sloppy_keys = 0; - rfbLog("remote_cmd: set sloppy_keys to: %d\n", sloppy_keys); - - } else if (!strcmp(p, "skip_dups")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, - skip_duplicate_key_events); - goto qry; - } - rfbLog("remote_cmd: enabling -skip_dups mode\n"); - skip_duplicate_key_events = 1; - } else if (!strcmp(p, "noskip_dups")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, - !skip_duplicate_key_events); - goto qry; - } - rfbLog("remote_cmd: disabling -skip_dups mode\n"); - skip_duplicate_key_events = 0; - - } else if (!strcmp(p, "add_keysyms")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, add_keysyms); - goto qry; - } - rfbLog("remote_cmd: enabling -add_keysyms mode.\n"); - add_keysyms = 1; - - } else if (!strcmp(p, "noadd_keysyms")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, !add_keysyms); - goto qry; - } - rfbLog("remote_cmd: disabling -add_keysyms mode.\n"); - add_keysyms = 0; - - } else if (!strcmp(p, "clear_mods")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, clear_mods == 1); - goto qry; - } - rfbLog("remote_cmd: enabling -clear_mods mode.\n"); - clear_mods = 1; - clear_modifiers(0); - - } else if (!strcmp(p, "noclear_mods")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, - !(clear_mods == 1)); - goto qry; - } - rfbLog("remote_cmd: disabling -clear_mods mode.\n"); - clear_mods = 0; - - } else if (!strcmp(p, "clear_keys")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, - clear_mods == 2); - goto qry; - } - rfbLog("remote_cmd: enabling -clear_keys mode.\n"); - clear_mods = 2; - clear_keys(); - - } else if (!strcmp(p, "noclear_keys")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, - !(clear_mods == 2)); - goto qry; - } - rfbLog("remote_cmd: disabling -clear_keys mode.\n"); - clear_mods = 0; - - } else if (strstr(p, "remap") == p) { - char *before, *old; - COLON_CHECK("remap:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%s", p, co, - NONUL(remap_file)); - goto qry; - } - p += strlen("remap:"); - if ((*p == '+' || *p == '-') && remap_file && - strchr(remap_file, '/')) { - rfbLog("remote_cmd: cannot use remap:+/-\n"); - rfbLog("in '-remap %s' mode.\n", remap_file); - goto done; - } - if (remap_file) { - before = strdup(remap_file); - } else { - before = strdup(""); - } - old = remap_file; - if (*p == '+') { - p++; - remap_file = add_item(remap_file, p); - } else if (*p == '-') { - p++; - remap_file = delete_item(remap_file, p); - if (! strchr(remap_file, '-')) { - *remap_file = '\0'; - } - } else { - remap_file = strdup(p); - } - if (strcmp(before, remap_file)) { - rfbLog("remote_cmd: changed -remap\n"); - rfbLog(" from: %s\n", before); - rfbLog(" to: %s\n", remap_file); - initialize_remap(remap_file); - } - if (old) free(old); - free(before); - - } else if (!strcmp(p, "repeat")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, !no_autorepeat); - goto qry; - } - rfbLog("remote_cmd: enabling -repeat mode.\n"); - autorepeat(1, 0); /* restore initial setting */ - no_autorepeat = 0; - - } else if (!strcmp(p, "norepeat")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, no_autorepeat); - goto qry; - } - rfbLog("remote_cmd: enabling -norepeat mode.\n"); - no_autorepeat = 1; - if (no_repeat_countdown >= 0) { - no_repeat_countdown = 2; - } - if (client_count && ! view_only) { - autorepeat(0, 0); /* disable if any clients */ - } - - } else if (!strcmp(p, "fb")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, !nofb); - goto qry; - } - if (nofb) { - rfbLog("remote_cmd: disabling nofb mode.\n"); - rfbLog(" you may need to these turn back on:\n"); - rfbLog(" xfixes, xdamage, solid, flashcmap\n"); - rfbLog(" overlay, shm, noonetile, nap, cursor\n"); - rfbLog(" cursorpos, cursorshape, bell.\n"); - nofb = 0; - set_nofb_params(1); - do_new_fb(1); - } - } else if (!strcmp(p, "nofb")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, nofb); - goto qry; - } - if (!nofb) { - rfbLog("remote_cmd: enabling nofb mode.\n"); - if (main_fb) { - push_black_screen(4); - } - nofb = 1; - sound_bell = 0; - initialize_watch_bell(); - set_nofb_params(0); - do_new_fb(1); - } - - } else if (!strcmp(p, "bell")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, sound_bell); - goto qry; - } - rfbLog("remote_cmd: enabling bell (if supported).\n"); - initialize_watch_bell(); - sound_bell = 1; - - } else if (!strcmp(p, "nobell")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, !sound_bell); - goto qry; - } - rfbLog("remote_cmd: disabling bell.\n"); - initialize_watch_bell(); - sound_bell = 0; - - } else if (!strcmp(p, "sel")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, watch_selection); - goto qry; - } - rfbLog("remote_cmd: enabling watch selection+primary.\n"); - watch_selection = 1; - watch_primary = 1; - - } else if (!strcmp(p, "nosel")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, !watch_selection); - goto qry; - } - rfbLog("remote_cmd: disabling watch selection+primary.\n"); - watch_selection = 0; - watch_primary = 0; - - } else if (!strcmp(p, "primary")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, watch_primary); - goto qry; - } - rfbLog("remote_cmd: enabling watch_primary.\n"); - watch_primary = 1; - - } else if (!strcmp(p, "noprimary")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, !watch_primary); - goto qry; - } - rfbLog("remote_cmd: disabling watch_primary.\n"); - watch_primary = 0; - - } else if (strstr(p, "seldir") == p) { - COLON_CHECK("seldir:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%s", p, co, - NONUL(sel_direction)); - goto qry; - } - p += strlen("seldir:"); - rfbLog("remote_cmd: setting -seldir to %s\n", p); - if (sel_direction) free(sel_direction); - sel_direction = strdup(p); - - } else if (!strcmp(p, "set_no_cursor")) { /* skip-cmd-list */ - rfbLog("remote_cmd: calling set_no_cursor()\n"); - set_no_cursor(); - - } else if (!strcmp(p, "cursorshape")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, - cursor_shape_updates); - goto qry; - } - rfbLog("remote_cmd: turning on cursorshape mode.\n"); - - set_no_cursor(); - cursor_shape_updates = 1; - restore_cursor_shape_updates(screen); - first_cursor(); - } else if (!strcmp(p, "nocursorshape")) { - int i, max = 5; - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, - !cursor_shape_updates); - goto qry; - } - rfbLog("remote_cmd: turning off cursorshape mode.\n"); - - set_no_cursor(); - for (i=0; i<max; i++) { - /* XXX: try to force empty cursor back to client */ - rfbPE(-1); - } - cursor_shape_updates = 0; - disable_cursor_shape_updates(screen); - first_cursor(); - - } else if (!strcmp(p, "cursorpos")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, - cursor_pos_updates); - goto qry; - } - rfbLog("remote_cmd: turning on cursorpos mode.\n"); - cursor_pos_updates = 1; - } else if (!strcmp(p, "nocursorpos")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, - !cursor_pos_updates); - goto qry; - } - rfbLog("remote_cmd: turning off cursorpos mode.\n"); - cursor_pos_updates = 0; - - } else if (strstr(p, "cursor") == p) { - COLON_CHECK("cursor:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%s", p, co, - NONUL(multiple_cursors_mode)); - goto qry; - } - p += strlen("cursor:"); - if (multiple_cursors_mode) { - if (prev_cursors_mode) free(prev_cursors_mode); - prev_cursors_mode = strdup(multiple_cursors_mode); - free(multiple_cursors_mode); - } - multiple_cursors_mode = strdup(p); - - rfbLog("remote_cmd: changed -cursor mode " - "to: %s\n", multiple_cursors_mode); - - if (strcmp(multiple_cursors_mode, "none") && !show_cursor) { - show_cursor = 1; - rfbLog("remote_cmd: changed show_cursor " - "to: %d\n", show_cursor); - } - initialize_cursors_mode(); - first_cursor(); - - } else if (!strcmp(p, "show_cursor")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, show_cursor); - goto qry; - } - rfbLog("remote_cmd: enabling show_cursor.\n"); - show_cursor = 1; - if (multiple_cursors_mode && !strcmp(multiple_cursors_mode, - "none")) { - free(multiple_cursors_mode); - if (prev_cursors_mode) { - multiple_cursors_mode = - strdup(prev_cursors_mode); - } else { - multiple_cursors_mode = strdup("default"); - } - rfbLog("remote_cmd: changed -cursor mode " - "to: %s\n", multiple_cursors_mode); - } - initialize_cursors_mode(); - first_cursor(); - } else if (!strcmp(p, "noshow_cursor") || !strcmp(p, "nocursor")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, !show_cursor); - goto qry; - } - if (prev_cursors_mode) free(prev_cursors_mode); - prev_cursors_mode = strdup(multiple_cursors_mode); - - rfbLog("remote_cmd: disabling show_cursor.\n"); - show_cursor = 0; - initialize_cursors_mode(); - first_cursor(); - - } else if (strstr(p, "arrow") == p) { - COLON_CHECK("arrow:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%d", p, co, alt_arrow); - goto qry; - } - p += strlen("arrow:"); - alt_arrow = atoi(p); - rfbLog("remote_cmd: setting alt_arrow: %d.\n", alt_arrow); - setup_cursors_and_push(); - - } else if (!strcmp(p, "xfixes")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, use_xfixes); - goto qry; - } - if (! xfixes_present) { - rfbLog("remote_cmd: cannot enable xfixes " - "(not supported on X display)\n"); - goto done; - } - rfbLog("remote_cmd: enabling -xfixes" - " (if supported).\n"); - use_xfixes = 1; - initialize_xfixes(); - first_cursor(); - } else if (!strcmp(p, "noxfixes")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, !use_xfixes); - goto qry; - } - if (! xfixes_present) { - rfbLog("remote_cmd: disabling xfixes " - "(but not supported on X display)\n"); - goto done; - } - rfbLog("remote_cmd: disabling -xfixes.\n"); - use_xfixes = 0; - initialize_xfixes(); - first_cursor(); - - } else if (!strcmp(p, "xdamage")) { - int orig = use_xdamage; - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, use_xdamage); - goto qry; - } - if (! xdamage_present) { - rfbLog("remote_cmd: cannot enable xdamage hints " - "(not supported on X display)\n"); - goto done; - } - rfbLog("remote_cmd: enabling xdamage hints" - " (if supported).\n"); - use_xdamage = 1; - if (use_xdamage != orig) { - initialize_xdamage(); - create_xdamage_if_needed(); - } - } else if (!strcmp(p, "noxdamage")) { - int orig = use_xdamage; - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, !use_xdamage); - goto qry; - } - if (! xdamage_present) { - rfbLog("remote_cmd: disabling xdamage hints " - "(but not supported on X display)\n"); - goto done; - } - rfbLog("remote_cmd: disabling xdamage hints.\n"); - use_xdamage = 0; - if (use_xdamage != orig) { - initialize_xdamage(); - destroy_xdamage_if_needed(); - } - - } else if (strstr(p, "xd_area") == p) { - int a; - COLON_CHECK("xd_area:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%d", p, co, - xdamage_max_area); - goto qry; - } - p += strlen("xd_area:"); - a = atoi(p); - if (a >= 0) { - rfbLog("remote_cmd: setting xdamage_max_area " - "%d -> %d.\n", xdamage_max_area, a); - xdamage_max_area = a; - } - } else if (strstr(p, "xd_mem") == p) { - double a; - COLON_CHECK("xd_mem:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%.3f", p, co, - xdamage_memory); - goto qry; - } - p += strlen("xd_mem:"); - a = atof(p); - if (a >= 0.0) { - rfbLog("remote_cmd: setting xdamage_memory " - "%.3f -> %.3f.\n", xdamage_memory, a); - xdamage_memory = a; - } - - } else if (strstr(p, "alphacut") == p) { - int a; - COLON_CHECK("alphacut:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%d", p, co, - alpha_threshold); - goto qry; - } - p += strlen("alphacut:"); - a = atoi(p); - if (a < 0) a = 0; - if (a > 256) a = 256; /* allow 256 for testing. */ - if (alpha_threshold != a) { - rfbLog("remote_cmd: setting alphacut " - "%d -> %d.\n", alpha_threshold, a); - if (a == 256) { - rfbLog("note: alphacut=256 leads to completely" - " transparent cursors.\n"); - } - alpha_threshold = a; - setup_cursors_and_push(); - } - } else if (strstr(p, "alphafrac") == p) { - double a; - COLON_CHECK("alphafrac:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%f", p, co, - alpha_frac); - goto qry; - } - p += strlen("alphafrac:"); - a = atof(p); - if (a < 0.0) a = 0.0; - if (a > 1.0) a = 1.0; - if (alpha_frac != a) { - rfbLog("remote_cmd: setting alphafrac " - "%f -> %f.\n", alpha_frac, a); - alpha_frac = a; - setup_cursors_and_push(); - } - } else if (strstr(p, "alpharemove") == p) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, alpha_remove); - goto qry; - } - if (!alpha_remove) { - rfbLog("remote_cmd: enable alpharemove\n"); - alpha_remove = 1; - setup_cursors_and_push(); - } - } else if (strstr(p, "noalpharemove") == p) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, !alpha_remove); - goto qry; - } - if (alpha_remove) { - rfbLog("remote_cmd: disable alpharemove\n"); - alpha_remove = 0; - setup_cursors_and_push(); - } - } else if (strstr(p, "alphablend") == p) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, alpha_blend); - goto qry; - } - if (!alpha_blend) { - rfbLog("remote_cmd: enable alphablend\n"); - alpha_remove = 0; - alpha_blend = 1; - setup_cursors_and_push(); - } - } else if (strstr(p, "noalphablend") == p) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, !alpha_blend); - goto qry; - } - if (alpha_blend) { - rfbLog("remote_cmd: disable alphablend\n"); - alpha_blend = 0; - setup_cursors_and_push(); - } - - } else if (strstr(p, "xwarppointer") == p || strstr(p, "xwarp") == p) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, use_xwarppointer); - goto qry; - } - rfbLog("remote_cmd: turning on xwarppointer mode.\n"); - use_xwarppointer = 1; - } else if (strstr(p, "noxwarppointer") == p || - strstr(p, "noxwarp") == p) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, !use_xwarppointer); - goto qry; - } - rfbLog("remote_cmd: turning off xwarppointer mode.\n"); - use_xwarppointer = 0; - - } else if (strstr(p, "buttonmap") == p) { - COLON_CHECK("buttonmap:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%s", p, co, - NONUL(pointer_remap)); - goto qry; - } - p += strlen("buttonmap:"); - if (pointer_remap) free(pointer_remap); - pointer_remap = strdup(p); - - rfbLog("remote_cmd: setting -buttonmap to:\n\t'%s'\n", p); - initialize_pointer_map(p); - - } else if (!strcmp(p, "dragging")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, show_dragging); - goto qry; - } - rfbLog("remote_cmd: enabling mouse dragging mode.\n"); - show_dragging = 1; - } else if (!strcmp(p, "nodragging")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, !show_dragging); - goto qry; - } - rfbLog("remote_cmd: enabling mouse nodragging mode.\n"); - show_dragging = 0; - - } else if (strstr(p, "wireframe_mode") == p) { - COLON_CHECK("wireframe_mode:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%s", p, co, - wireframe_str ? wireframe_str : WIREFRAME_PARMS); - goto qry; - } - p += strlen("wireframe_mode:"); - if (*p) { - if (wireframe_str) { - free(wireframe_str); - } - wireframe_str = strdup(p); - parse_wireframe(); - } - rfbLog("remote_cmd: enabling -wireframe mode.\n"); - wireframe = 1; - } else if (strstr(p, "wireframe:") == p) { /* skip-cmd-list */ - COLON_CHECK("wireframe:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%d", p, co, wireframe); - goto qry; - } - p += strlen("wireframe:"); - if (*p) { - if (wireframe_str) { - free(wireframe_str); - } - wireframe_str = strdup(p); - parse_wireframe(); - } - rfbLog("remote_cmd: enabling -wireframe mode.\n"); - wireframe = 1; - } else if (strstr(p, "wf:") == p) { /* skip-cmd-list */ - COLON_CHECK("wf:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%d", p, co, wireframe); - goto qry; - } - p += strlen("wf:"); - if (*p) { - if (wireframe_str) { - free(wireframe_str); - } - wireframe_str = strdup(p); - parse_wireframe(); - } - rfbLog("remote_cmd: enabling -wireframe mode.\n"); - wireframe = 1; - } else if (!strcmp(p, "wireframe") || !strcmp(p, "wf")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, wireframe); - goto qry; - } - rfbLog("remote_cmd: enabling -wireframe mode.\n"); - wireframe = 1; - } else if (!strcmp(p, "nowireframe") || !strcmp(p, "nowf")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, !wireframe); - goto qry; - } - rfbLog("remote_cmd: enabling -nowireframe mode.\n"); - wireframe = 0; - } else if (strstr(p, "wirecopyrect") == p) { - COLON_CHECK("wirecopyrect:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%s", p, co, - NONUL(wireframe_copyrect)); - goto qry; - } - p += strlen("wirecopyrect:"); - - set_wirecopyrect_mode(p); - rfbLog("remote_cmd: changed -wirecopyrect mode " - "to: %s\n", NONUL(wireframe_copyrect)); - got_wirecopyrect = 1; - } else if (strstr(p, "wcr") == p) { - COLON_CHECK("wcr:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%s", p, co, - NONUL(wireframe_copyrect)); - goto qry; - } - p += strlen("wcr:"); - - set_wirecopyrect_mode(p); - rfbLog("remote_cmd: changed -wirecopyrect mode " - "to: %s\n", NONUL(wireframe_copyrect)); - got_wirecopyrect = 1; - } else if (!strcmp(p, "nowirecopyrect") || !strcmp(p, "nowcr")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%s", p, - NONUL(wireframe_copyrect)); - goto qry; - } - - set_wirecopyrect_mode("never"); - rfbLog("remote_cmd: changed -wirecopyrect mode " - "to: %s\n", NONUL(wireframe_copyrect)); - - } else if (strstr(p, "scr_area") == p) { - COLON_CHECK("scr_area:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%d", p, co, - scrollcopyrect_min_area); - goto qry; - } - p += strlen("scr_area:"); - - scrollcopyrect_min_area = atoi(p); - rfbLog("remote_cmd: changed -scr_area to: %d\n", - scrollcopyrect_min_area); - - } else if (strstr(p, "scr_skip") == p) { - char *s = scroll_skip_str; - COLON_CHECK("scr_skip:") - if (!s || *s == '\0') s = scroll_skip_str0; - if (query) { - snprintf(buf, bufn, "ans=%s%s%s", p, co, NONUL(s)); - goto qry; - } - p += strlen("scr_skip:"); - if (scroll_skip_str) { - free(scroll_skip_str); - } - - scroll_skip_str = strdup(p); - rfbLog("remote_cmd: changed -scr_skip to: %s\n", - scroll_skip_str); - initialize_scroll_matches(); - } else if (strstr(p, "scr_inc") == p) { - char *s = scroll_good_str; - if (!s || *s == '\0') s = scroll_good_str0; - COLON_CHECK("scr_inc:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%s", p, co, NONUL(s)); - goto qry; - } - p += strlen("scr_inc:"); - if (scroll_good_str) { - free(scroll_good_str); - } - - scroll_good_str = strdup(p); - rfbLog("remote_cmd: changed -scr_inc to: %s\n", - scroll_good_str); - initialize_scroll_matches(); - } else if (strstr(p, "scr_keys") == p) { - COLON_CHECK("scr_keys:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%s", p, co, - NONUL(scroll_key_list_str)); - goto qry; - } - p += strlen("scr_keys:"); - if (scroll_key_list_str) { - free(scroll_key_list_str); - } - - scroll_key_list_str = strdup(p); - rfbLog("remote_cmd: changed -scr_keys to: %s\n", - scroll_key_list_str); - initialize_scroll_keys(); - } else if (strstr(p, "scr_term") == p) { - char *s = scroll_term_str; - if (!s || *s == '\0') s = scroll_term_str0; - COLON_CHECK("scr_term:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%s", p, co, NONUL(s)); - goto qry; - } - p += strlen("scr_term:"); - if (scroll_term_str) { - free(scroll_term_str); - } - - scroll_term_str = strdup(p); - rfbLog("remote_cmd: changed -scr_term to: %s\n", - scroll_term_str); - initialize_scroll_term(); - - } else if (strstr(p, "scr_keyrepeat") == p) { - char *s = max_keyrepeat_str; - if (!s || *s == '\0') s = max_keyrepeat_str0; - COLON_CHECK("scr_keyrepeat:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%s", p, co, NONUL(s)); - goto qry; - } - p += strlen("scr_keyrepeat:"); - if (max_keyrepeat_str) { - free(max_keyrepeat_str); - } - - max_keyrepeat_str = strdup(p); - rfbLog("remote_cmd: changed -scr_keyrepeat to: %s\n", - max_keyrepeat_str); - initialize_max_keyrepeat(); - - } else if (strstr(p, "scr_parms") == p) { - COLON_CHECK("scr_parms:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%s", p, co, - scroll_copyrect_str ? scroll_copyrect_str - : SCROLL_COPYRECT_PARMS); - goto qry; - } - p += strlen("scr_parms:"); - if (*p) { - if (scroll_copyrect_str) { - free(scroll_copyrect_str); - } - set_scrollcopyrect_mode("always"); - scroll_copyrect_str = strdup(p); - parse_scroll_copyrect(); - } - rfbLog("remote_cmd: set -scr_parms %s.\n", - NONUL(scroll_copyrect_str)); - got_scrollcopyrect = 1; - - } else if (strstr(p, "scrollcopyrect") == p) { - COLON_CHECK("scrollcopyrect:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%s", p, co, - NONUL(scroll_copyrect)); - goto qry; - } - p += strlen("scrollcopyrect:"); - - set_scrollcopyrect_mode(p); - rfbLog("remote_cmd: changed -scrollcopyrect mode " - "to: %s\n", NONUL(scroll_copyrect)); - got_scrollcopyrect = 1; - } else if (!strcmp(p, "scr") || - strstr(p, "scr:") == p) { /* skip-cmd-list */ - COLON_CHECK("scr:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%s", p, co, - NONUL(scroll_copyrect)); - goto qry; - } - p += strlen("scr:"); - - set_scrollcopyrect_mode(p); - rfbLog("remote_cmd: changed -scrollcopyrect mode " - "to: %s\n", NONUL(scroll_copyrect)); - got_scrollcopyrect = 1; - } else if (!strcmp(p, "noscrollcopyrect") || !strcmp(p, "noscr")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%s", p, - NONUL(scroll_copyrect)); - goto qry; - } - - set_scrollcopyrect_mode("never"); - rfbLog("remote_cmd: changed -scrollcopyrect mode " - "to: %s\n", NONUL(scroll_copyrect)); - - } else if (strstr(p, "fixscreen") == p) { - COLON_CHECK("fixscreen:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%s", p, co, - NONUL(screen_fixup_str)); - goto qry; - } - p += strlen("fixscreen:"); - if (screen_fixup_str) { - free(screen_fixup_str); - } - screen_fixup_str = strdup(p); - parse_fixscreen(); - rfbLog("remote_cmd: set -fixscreen %s.\n", - NONUL(screen_fixup_str)); - - } else if (!strcmp(p, "noxrecord")) { - int orig = noxrecord; - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, noxrecord); - goto qry; - } - noxrecord = 1; - rfbLog("set noxrecord to: %d\n", noxrecord); - if (orig != noxrecord) { - shutdown_xrecord(); - } - } else if (!strcmp(p, "xrecord")) { - int orig = noxrecord; - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, !noxrecord); - goto qry; - } - noxrecord = 0; - rfbLog("set noxrecord to: %d\n", noxrecord); - if (orig != noxrecord) { - initialize_xrecord(); - } - } else if (!strcmp(p, "reset_record")) { - NOTAPP - if (use_xrecord) { - rfbLog("resetting RECORD\n"); - check_xrecord_reset(1); - } else { - rfbLog("RECORD is disabled, not resetting.\n"); - } - - } else if (strstr(p, "pointer_mode") == p) { - int pm; - COLON_CHECK("pointer_mode:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%d", p, co, pointer_mode); - goto qry; - } - p += strlen("pointer_mode:"); - pm = atoi(p); - if (pm < 0 || pm > pointer_mode_max) { - rfbLog("remote_cmd: pointer_mode out of range:" - " 1-%d: %d\n", pointer_mode_max, pm); - } else { - rfbLog("remote_cmd: setting pointer_mode %d\n", pm); - pointer_mode = pm; - } - } else if (strstr(p, "pm") == p) { - int pm; - COLON_CHECK("pm:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%d", p, co, pointer_mode); - goto qry; - } - p += strlen("pm:"); - pm = atoi(p); - if (pm < 0 || pm > pointer_mode_max) { - rfbLog("remote_cmd: pointer_mode out of range:" - " 1-%d: %d\n", pointer_mode_max, pm); - } else { - rfbLog("remote_cmd: setting pointer_mode %d\n", pm); - pointer_mode = pm; - } - - } else if (strstr(p, "input_skip") == p) { - int is; - COLON_CHECK("input_skip:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%d", p, co, ui_skip); - goto qry; - } - p += strlen("input_skip:"); - is = atoi(p); - rfbLog("remote_cmd: setting input_skip %d\n", is); - ui_skip = is; - - } else if (strstr(p, "input") == p) { - int doit = 1; - COLON_CHECK("input:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%s", p, co, - NONUL(allowed_input_str)); - goto qry; - } - p += strlen("input:"); - if (allowed_input_str && !strcmp(p, allowed_input_str)) { - doit = 0; - } - rfbLog("remote_cmd: setting input %s\n", p); - if (allowed_input_str) free(allowed_input_str); - if (*p == '\0') { - allowed_input_str = NULL; - } else { - allowed_input_str = strdup(p); - } - if (doit) { - initialize_allowed_input(); - } - } else if (strstr(p, "client_input") == p) { - NOTAPP - COLON_CHECK("client_input:") - p += strlen("client_input:"); - set_client_input(p); - - } else if (strstr(p, "speeds") == p) { - COLON_CHECK("speeds:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%s", p, co, - NONUL(speeds_str)); - goto qry; - } - p += strlen("speeds:"); - if (speeds_str) free(speeds_str); - speeds_str = strdup(p); - - rfbLog("remote_cmd: setting -speeds to:\n\t'%s'\n", p); - initialize_speeds(); - - } else if (strstr(p, "wmdt") == p) { - COLON_CHECK("wmdt:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%s", p, co, - NONUL(wmdt_str)); - goto qry; - } - p += strlen("wmdt:"); - if (wmdt_str) free(wmdt_str); - wmdt_str = strdup(p); - - rfbLog("remote_cmd: setting -wmdt to: %s\n", p); - - } else if (!strcmp(p, "debug_pointer") || !strcmp(p, "dp")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, debug_pointer); - goto qry; - } - rfbLog("remote_cmd: turning on debug_pointer.\n"); - debug_pointer = 1; - } else if (!strcmp(p, "nodebug_pointer") || !strcmp(p, "nodp")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, !debug_pointer); - goto qry; - } - rfbLog("remote_cmd: turning off debug_pointer.\n"); - debug_pointer = 0; - - } else if (!strcmp(p, "debug_keyboard") || !strcmp(p, "dk")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, debug_keyboard); - goto qry; - } - rfbLog("remote_cmd: turning on debug_keyboard.\n"); - debug_keyboard = 1; - } else if (!strcmp(p, "nodebug_keyboard") || !strcmp(p, "nodk")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, !debug_keyboard); - goto qry; - } - rfbLog("remote_cmd: turning off debug_keyboard.\n"); - debug_keyboard = 0; - - } else if (strstr(p, "deferupdate") == p) { - int d; - COLON_CHECK("deferupdate:") - if (query) { - if (!screen) { - d = defer_update; - } else { - d = screen->deferUpdateTime; - } - snprintf(buf, bufn, "ans=%s%s%d", p, co, d); - goto qry; - } - p += strlen("deferupdate:"); - d = atoi(p); - if (d < 0) d = 0; - rfbLog("remote_cmd: setting defer to %d ms.\n", d); - screen->deferUpdateTime = d; - got_defer = 1; - - } else if (strstr(p, "defer") == p) { - int d; - COLON_CHECK("defer:") - if (query) { - if (!screen) { - d = defer_update; - } else { - d = screen->deferUpdateTime; - } - snprintf(buf, bufn, "ans=%s%s%d", p, co, d); - goto qry; - } - p += strlen("defer:"); - d = atoi(p); - if (d < 0) d = 0; - rfbLog("remote_cmd: setting defer to %d ms.\n", d); - screen->deferUpdateTime = d; - got_defer = 1; - - } else if (strstr(p, "wait_ui") == p) { - double w; - COLON_CHECK("wait_ui:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%.2f", p, co, wait_ui); - goto qry; - } - p += strlen("wait_ui:"); - w = atof(p); - if (w <= 0) w = 1.0; - rfbLog("remote_cmd: setting wait_ui factor %.2f -> %.2f\n", - wait_ui, w); - wait_ui = w; - - } else if (!strcmp(p, "wait_bog")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, wait_bog); - goto qry; - } - wait_bog = 1; - rfbLog("remote_cmd: setting wait_bog to %d\n", wait_bog); - } else if (!strcmp(p, "nowait_bog")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, !wait_bog); - goto qry; - } - wait_bog = 0; - rfbLog("remote_cmd: setting wait_bog to %d\n", wait_bog); - - } else if (strstr(p, "slow_fb") == p) { - double w; - COLON_CHECK("slow_fb:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%.2f", p, co, slow_fb); - goto qry; - } - p += strlen("slow_fb:"); - w = atof(p); - if (w <= 0) w = 0.0; - rfbLog("remote_cmd: setting slow_fb factor %.2f -> %.2f\n", - slow_fb, w); - slow_fb = w; - - } else if (strstr(p, "wait") == p) { - int w; - COLON_CHECK("wait:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%d", p, co, waitms); - goto qry; - } - p += strlen("wait:"); - w = atoi(p); - if (w < 0) w = 0; - rfbLog("remote_cmd: setting wait %d -> %d ms.\n", waitms, w); - waitms = w; - - } else if (strstr(p, "readtimeout") == p) { - int w, orig = rfbMaxClientWait; - COLON_CHECK("readtimeout:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%d", p, co, - rfbMaxClientWait/1000); - goto qry; - } - p += strlen("readtimeout:"); - w = atoi(p) * 1000; - if (w <= 0) w = 0; - rfbLog("remote_cmd: setting rfbMaxClientWait %d -> " - "%d msec.\n", orig, w); - rfbMaxClientWait = w; - - } else if (!strcmp(p, "nap")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, take_naps); - goto qry; - } - rfbLog("remote_cmd: turning on nap mode.\n"); - take_naps = 1; - } else if (!strcmp(p, "nonap")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, !take_naps); - goto qry; - } - rfbLog("remote_cmd: turning off nap mode.\n"); - take_naps = 0; - - } else if (strstr(p, "sb") == p) { - int w; - COLON_CHECK("sb:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%d", p, co, screen_blank); - goto qry; - } - p += strlen("sb:"); - w = atoi(p); - if (w < 0) w = 0; - rfbLog("remote_cmd: setting screen_blank %d -> %d sec.\n", - screen_blank, w); - screen_blank = w; - } else if (strstr(p, "screen_blank") == p) { - int w; - COLON_CHECK("screen_blank:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%d", p, co, screen_blank); - goto qry; - } - p += strlen("screen_blank:"); - w = atoi(p); - if (w < 0) w = 0; - rfbLog("remote_cmd: setting screen_blank %d -> %d sec.\n", - screen_blank, w); - screen_blank = w; - - } else if (strstr(p, "fs") == p) { - COLON_CHECK("fs:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%f", p, co, fs_frac); - goto qry; - } - p += strlen("fs:"); - fs_frac = atof(p); - rfbLog("remote_cmd: setting -fs frac to %f\n", fs_frac); - - } else if (strstr(p, "gaps") == p) { - int g; - COLON_CHECK("gaps:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%d", p, co, gaps_fill); - goto qry; - } - p += strlen("gaps:"); - g = atoi(p); - if (g < 0) g = 0; - rfbLog("remote_cmd: setting gaps_fill %d -> %d.\n", - gaps_fill, g); - gaps_fill = g; - } else if (strstr(p, "grow") == p) { - int g; - COLON_CHECK("grow:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%d", p, co, grow_fill); - goto qry; - } - p += strlen("grow:"); - g = atoi(p); - if (g < 0) g = 0; - rfbLog("remote_cmd: setting grow_fill %d -> %d.\n", - grow_fill, g); - grow_fill = g; - } else if (strstr(p, "fuzz") == p) { - int f; - COLON_CHECK("fuzz:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%d", p, co, tile_fuzz); - goto qry; - } - p += strlen("fuzz:"); - f = atoi(p); - if (f < 0) f = 0; - rfbLog("remote_cmd: setting tile_fuzz %d -> %d.\n", - tile_fuzz, f); - grow_fill = f; - - } else if (!strcmp(p, "snapfb")) { - int orig = use_snapfb; - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, use_snapfb); - goto qry; - } - rfbLog("remote_cmd: turning on snapfb mode.\n"); - use_snapfb = 1; - if (orig != use_snapfb) { - do_new_fb(1); - } - } else if (!strcmp(p, "nosnapfb")) { - int orig = use_snapfb; - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, !use_snapfb); - goto qry; - } - rfbLog("remote_cmd: turning off snapfb mode.\n"); - use_snapfb = 0; - if (orig != use_snapfb) { - do_new_fb(1); - } - - } else if (strstr(p, "rawfb") == p) { - COLON_CHECK("rawfb:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%s", p, co, - NONUL(raw_fb_str)); - goto qry; - } - p += strlen("rawfb:"); - if (raw_fb_str) free(raw_fb_str); - raw_fb_str = strdup(p); - if (safe_remote_only && strstr(p, "setup:") == p) { /* skip-cmd-list */ - /* n.b. we still allow filename, shm, of rawfb */ - fprintf(stderr, "unsafe rawfb setup: %s\n", p); - exit(1); - } - - rfbLog("remote_cmd: setting -rawfb to:\n\t'%s'\n", p); - - if (*raw_fb_str == '\0') { - free(raw_fb_str); - raw_fb_str = NULL; - rfbLog("restoring per-rawfb settings...\n"); - set_raw_fb_params(1); - } - rfbLog("hang on tight, here we go...\n"); - do_new_fb(1); - - } else if (strstr(p, "progressive") == p) { - int f; - COLON_CHECK("progressive:") - if (query) { - if (!screen) { - f = 0; - } else { - f = screen->progressiveSliceHeight; - } - snprintf(buf, bufn, "ans=%s%s%d", p, co, f); - goto qry; - } - p += strlen("progressive:"); - f = atoi(p); - if (f < 0) f = 0; - rfbLog("remote_cmd: setting progressive %d -> %d.\n", - screen->progressiveSliceHeight, f); - screen->progressiveSliceHeight = f; - - } else if (strstr(p, "rfbport") == p) { - int rp, orig = screen ? screen->port : 5900; - COLON_CHECK("rfbport:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%d", p, co, orig); - goto qry; - } - p += strlen("rfbport:"); - rp = atoi(p); - reset_rfbport(orig, rp); - - } else if (!strcmp(p, "http")) { - if (query) { - int ls = screen ? screen->httpListenSock : -1; - snprintf(buf, bufn, "ans=%s:%d", p, (ls > -1)); - goto qry; - } - if (screen->httpListenSock > -1) { - rfbLog("already listening for http connections.\n"); - } else { - rfbLog("turning on listening for http connections.\n"); - if (check_httpdir()) { - http_connections(1); - } - } - } else if (!strcmp(p, "nohttp")) { - if (query) { - int ls = screen ? screen->httpListenSock : -1; - snprintf(buf, bufn, "ans=%s:%d", p, !(ls > -1)); - goto qry; - } - if (screen->httpListenSock < 0) { - rfbLog("already not listening for http connections.\n"); - } else { - rfbLog("turning off listening for http connections.\n"); - if (check_httpdir()) { - http_connections(0); - } - } - - } else if (strstr(p, "httpport") == p) { - int hp, orig = screen ? screen->httpPort : 0; - COLON_CHECK("httpport:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%d", p, co, orig); - goto qry; - } - p += strlen("httpport:"); - hp = atoi(p); - reset_httpport(orig, hp); - - } else if (strstr(p, "httpdir") == p) { - COLON_CHECK("httpdir:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%s", p, co, - NONUL(http_dir)); - goto qry; - } - p += strlen("httpdir:"); - if (http_dir && !strcmp(http_dir, p)) { - rfbLog("no change in httpdir: %s\n", http_dir); - } else { - if (http_dir) { - free(http_dir); - } - http_dir = strdup(p); - http_connections(0); - if (*p != '\0') { - http_connections(1); - } - } - - } else if (!strcmp(p, "enablehttpproxy")) { - if (query) { - int ht = screen ? screen->httpEnableProxyConnect : 0; - snprintf(buf, bufn, "ans=%s:%d", p, ht != 0); - goto qry; - } - rfbLog("turning on enablehttpproxy.\n"); - screen->httpEnableProxyConnect = 1; - } else if (!strcmp(p, "noenablehttpproxy")) { - if (query) { - int ht = screen ? screen->httpEnableProxyConnect : 0; - snprintf(buf, bufn, "ans=%s:%d", p, ht == 0); - goto qry; - } - rfbLog("turning off enablehttpproxy.\n"); - screen->httpEnableProxyConnect = 0; - - } else if (!strcmp(p, "alwaysshared")) { - if (query) { - int t = screen ? screen->alwaysShared : 0; - snprintf(buf, bufn, "ans=%s:%d", p, t != 0); - goto qry; - } - rfbLog("turning on alwaysshared.\n"); - screen->alwaysShared = 1; - } else if (!strcmp(p, "noalwaysshared")) { - if (query) { - int t = screen ? screen->alwaysShared : 0; - snprintf(buf, bufn, "ans=%s:%d", p, t == 0); - goto qry; - } - rfbLog("turning off alwaysshared.\n"); - screen->alwaysShared = 0; - - } else if (!strcmp(p, "nevershared")) { - if (query) { - int t = screen ? screen->neverShared : 1; - snprintf(buf, bufn, "ans=%s:%d", p, t != 0); - goto qry; - } - rfbLog("turning on nevershared.\n"); - screen->neverShared = 1; - } else if (!strcmp(p, "noalwaysshared")) { - if (query) { - int t = screen ? screen->neverShared : 1; - snprintf(buf, bufn, "ans=%s:%d", p, t == 0); - goto qry; - } - rfbLog("turning off nevershared.\n"); - screen->neverShared = 0; - - } else if (!strcmp(p, "dontdisconnect")) { - if (query) { - int t = screen ? screen->dontDisconnect : 1; - snprintf(buf, bufn, "ans=%s:%d", p, t != 0); - goto qry; - } - rfbLog("turning on dontdisconnect.\n"); - screen->dontDisconnect = 1; - } else if (!strcmp(p, "nodontdisconnect")) { - if (query) { - int t = screen ? screen->dontDisconnect : 1; - snprintf(buf, bufn, "ans=%s:%d", p, t == 0); - goto qry; - } - rfbLog("turning off dontdisconnect.\n"); - screen->dontDisconnect = 0; - - } else if (!strcmp(p, "desktop") || - strstr(p, "desktop:") == p) { /* skip-cmd-list */ - COLON_CHECK("desktop:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%s", p, co, - NONUL(rfb_desktop_name)); - goto qry; - } - p += strlen("desktop:"); - if (rfb_desktop_name) { - free(rfb_desktop_name); - } - rfb_desktop_name = strdup(p); - screen->desktopName = rfb_desktop_name; - rfbLog("remote_cmd: setting desktop name to %s\n", - rfb_desktop_name); - - } else if (!strcmp(p, "debug_xevents")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, debug_xevents); - goto qry; - } - debug_xevents = 1; - rfbLog("set debug_xevents to: %d\n", debug_xevents); - } else if (!strcmp(p, "nodebug_xevents")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, !debug_xevents); - goto qry; - } - debug_xevents = 0; - rfbLog("set debug_xevents to: %d\n", debug_xevents); - } else if (strstr(p, "debug_xevents") == p) { - COLON_CHECK("debug_xevents:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%d", p, co, debug_xevents); - goto qry; - } - p += strlen("debug_xevents:"); - debug_xevents = atoi(p); - rfbLog("set debug_xevents to: %d\n", debug_xevents); - - } else if (!strcmp(p, "debug_xdamage")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, debug_xdamage); - goto qry; - } - debug_xdamage = 1; - rfbLog("set debug_xdamage to: %d\n", debug_xdamage); - } else if (!strcmp(p, "nodebug_xdamage")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, !debug_xdamage); - goto qry; - } - debug_xdamage = 0; - rfbLog("set debug_xdamage to: %d\n", debug_xdamage); - } else if (strstr(p, "debug_xdamage") == p) { - COLON_CHECK("debug_xdamage:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%d", p, co, debug_xdamage); - goto qry; - } - p += strlen("debug_xdamage:"); - debug_xdamage = atoi(p); - rfbLog("set debug_xdamage to: %d\n", debug_xdamage); - - } else if (!strcmp(p, "debug_wireframe")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, debug_wireframe); - goto qry; - } - debug_wireframe = 1; - rfbLog("set debug_wireframe to: %d\n", debug_wireframe); - } else if (!strcmp(p, "nodebug_wireframe")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, !debug_wireframe); - goto qry; - } - debug_wireframe = 0; - rfbLog("set debug_wireframe to: %d\n", debug_wireframe); - } else if (strstr(p, "debug_wireframe") == p) { - COLON_CHECK("debug_wireframe:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%d", p, co, - debug_wireframe); - goto qry; - } - p += strlen("debug_wireframe:"); - debug_wireframe = atoi(p); - rfbLog("set debug_wireframe to: %d\n", debug_wireframe); - - } else if (!strcmp(p, "debug_scroll")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, debug_scroll); - goto qry; - } - debug_scroll = 1; - rfbLog("set debug_scroll to: %d\n", debug_scroll); - } else if (!strcmp(p, "nodebug_scroll")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, !debug_scroll); - goto qry; - } - debug_scroll = 0; - rfbLog("set debug_scroll to: %d\n", debug_scroll); - } else if (strstr(p, "debug_scroll") == p) { - COLON_CHECK("debug_scroll:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%d", p, co, - debug_scroll); - goto qry; - } - p += strlen("debug_scroll:"); - debug_scroll = atoi(p); - rfbLog("set debug_scroll to: %d\n", debug_scroll); - - } else if (!strcmp(p, "debug_tiles") || !strcmp(p, "dbt")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, debug_tiles); - goto qry; - } - debug_tiles = 1; - rfbLog("set debug_tiles to: %d\n", debug_tiles); - } else if (!strcmp(p, "nodebug_tiles") || !strcmp(p, "nodbt")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, !debug_tiles); - goto qry; - } - debug_tiles = 0; - rfbLog("set debug_tiles to: %d\n", debug_tiles); - } else if (strstr(p, "debug_tiles") == p) { - COLON_CHECK("debug_tiles:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%d", p, co, - debug_tiles); - goto qry; - } - p += strlen("debug_tiles:"); - debug_tiles = atoi(p); - rfbLog("set debug_tiles to: %d\n", debug_tiles); - - } else if (!strcmp(p, "debug_grabs")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, debug_grabs); - goto qry; - } - debug_grabs = 1; - rfbLog("set debug_grabs to: %d\n", debug_grabs); - } else if (!strcmp(p, "nodebug_grabs")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, !debug_grabs); - goto qry; - } - debug_grabs = 0; - rfbLog("set debug_grabs to: %d\n", debug_grabs); - - } else if (!strcmp(p, "dbg")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, crash_debug); - goto qry; - } - crash_debug = 1; - rfbLog("set crash_debug to: %d\n", crash_debug); - } else if (!strcmp(p, "nodbg")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, !crash_debug); - goto qry; - } - crash_debug = 0; - rfbLog("set crash_debug to: %d\n", crash_debug); - - } else if (strstr(p, "hack") == p) { /* skip-cmd-list */ - COLON_CHECK("hack:") - if (query) { - snprintf(buf, bufn, "ans=%s%s%d", p, co, hack_val); - goto qry; - } - p += strlen("hack:"); - hack_val = atoi(p); - rfbLog("set hack_val to: %d\n", hack_val); - - } else if (!strcmp(p, "noremote")) { - if (query) { - snprintf(buf, bufn, "ans=%s:%d", p, - !accept_remote_cmds); - goto qry; - } - rfbLog("remote_cmd: disabling remote commands.\n"); - accept_remote_cmds = 0; /* cannot be turned back on. */ - - } else if (strstr(p, "client_info_sock") == p) { /* skip-cmd-list */ - NOTAPP - p += strlen("client_info_sock:"); - if (*p != '\0') { - start_client_info_sock(p); - } - - } else if (strstr(p, "noop") == p) { - NOTAPP - rfbLog("remote_cmd: noop\n"); - - } else if (icon_mode && !query && strstr(p, "passwd") == p) { /* skip-cmd-list */ - char **passwds_new = (char **) malloc(3*sizeof(char *)); - char **passwds_old = (char **) screen->authPasswdData; - - COLON_CHECK("passwd:") - p += strlen("passwd:"); - - passwds_new[0] = strdup(p); - - if (screen->authPasswdData && - screen->passwordCheck == rfbCheckPasswordByList) { - passwds_new[1] = passwds_old[1]; - } else { - passwds_new[1] = NULL; - screen->passwordCheck = rfbCheckPasswordByList; - } - passwds_new[2] = NULL; - - screen->authPasswdData = (void*) passwds_new; - if (*p == '\0') { - screen->authPasswdData = (void*) NULL; - } - rfbLog("remote_cmd: changed full access passwd.\n"); - - } else if (icon_mode && !query && strstr(p, "viewpasswd") == p) { /* skip-cmd-list */ - char **passwds_new = (char **) malloc(3*sizeof(char *)); - char **passwds_old = (char **) screen->authPasswdData; - - COLON_CHECK("viewpasswd:") - p += strlen("viewpasswd:"); - - passwds_new[1] = strdup(p); - - if (screen->authPasswdData && - screen->passwordCheck == rfbCheckPasswordByList) { - passwds_new[0] = passwds_old[0]; - } else { - char *tmp = (char *) malloc(4 + CHALLENGESIZE); - rfbRandomBytes((unsigned char*)tmp); - passwds_new[0] = tmp; - screen->passwordCheck = rfbCheckPasswordByList; - } - passwds_new[2] = NULL; - - if (*p == '\0') { - passwds_new[1] = NULL; - } - - screen->authPasswdData = (void*) passwds_new; - rfbLog("remote_cmd: changed view only passwd.\n"); - - } else if (strstr(p, "trayembed") == p) { /* skip-cmd-list */ - unsigned long id; - NOTAPP - - COLON_CHECK("trayembed:") - p += strlen("trayembed:"); - if (scan_hexdec(p, &id)) { - tray_request = (Window) id; - tray_unembed = 0; - rfbLog("remote_cmd: will try to embed 0x%x in" - " the system tray.\n", id); - } - } else if (strstr(p, "trayunembed") == p) { /* skip-cmd-list */ - unsigned long id; - NOTAPP - - COLON_CHECK("trayunembed:") - p += strlen("trayunembed:"); - if (scan_hexdec(p, &id)) { - tray_request = (Window) id; - tray_unembed = 1; - rfbLog("remote_cmd: will try to unembed 0x%x out" - " of the system tray.\n", id); - } - - - } else if (query) { - /* read-only variables that can only be queried: */ - - if (!strcmp(p, "display")) { - if (raw_fb) { - snprintf(buf, bufn, "aro=%s:rawfb:%p", - p, raw_fb_addr); - } else if (! dpy) { - snprintf(buf, bufn, "aro=%s:", p); - } else { - char *d; - d = DisplayString(dpy); - if (! d) d = "unknown"; - if (*d == ':') { - snprintf(buf, bufn, "aro=%s:%s%s", p, - this_host(), d); - } else { - snprintf(buf, bufn, "aro=%s:%s", p, d); - } - } - } else if (!strcmp(p, "vncdisplay")) { - snprintf(buf, bufn, "aro=%s:%s", p, - NONUL(vnc_desktop_name)); - } else if (!strcmp(p, "desktopname")) { - snprintf(buf, bufn, "aro=%s:%s", p, - NONUL(rfb_desktop_name)); - } else if (!strcmp(p, "guess_desktop")) { - snprintf(buf, bufn, "aro=%s:%s", p, - NONUL(guess_desktop())); - } else if (!strcmp(p, "http_url")) { - if (!screen) { - snprintf(buf, bufn, "aro=%s:", p); - } else if (screen->httpListenSock > -1) { - snprintf(buf, bufn, "aro=%s:http://%s:%d", p, - NONUL(screen->thisHost), screen->httpPort); - } else { - snprintf(buf, bufn, "aro=%s:%s", p, - "http_not_active"); - } - } else if (!strcmp(p, "auth") || !strcmp(p, "xauth")) { - snprintf(buf, bufn, "aro=%s:%s", p, NONUL(auth_file)); - } else if (!strcmp(p, "users")) { - snprintf(buf, bufn, "aro=%s:%s", p, NONUL(users_list)); - } else if (!strcmp(p, "rootshift")) { - snprintf(buf, bufn, "aro=%s:%d", p, rootshift); - } else if (!strcmp(p, "clipshift")) { - snprintf(buf, bufn, "aro=%s:%d", p, clipshift); - } else if (!strcmp(p, "scale_str")) { - snprintf(buf, bufn, "aro=%s:%s", p, NONUL(scale_str)); - } else if (!strcmp(p, "scaled_x")) { - snprintf(buf, bufn, "aro=%s:%d", p, scaled_x); - } else if (!strcmp(p, "scaled_y")) { - snprintf(buf, bufn, "aro=%s:%d", p, scaled_y); - } else if (!strcmp(p, "scale_numer")) { - snprintf(buf, bufn, "aro=%s:%d", p, scale_numer); - } else if (!strcmp(p, "scale_denom")) { - snprintf(buf, bufn, "aro=%s:%d", p, scale_denom); - } else if (!strcmp(p, "scale_fac")) { - snprintf(buf, bufn, "aro=%s:%f", p, scale_fac); - } else if (!strcmp(p, "scaling_blend")) { - snprintf(buf, bufn, "aro=%s:%d", p, scaling_blend); - } else if (!strcmp(p, "scaling_nomult4")) { - snprintf(buf, bufn, "aro=%s:%d", p, scaling_nomult4); - } else if (!strcmp(p, "scaling_pad")) { - snprintf(buf, bufn, "aro=%s:%d", p, scaling_pad); - } else if (!strcmp(p, "scaling_interpolate")) { - snprintf(buf, bufn, "aro=%s:%d", p, - scaling_interpolate); - } else if (!strcmp(p, "inetd")) { - snprintf(buf, bufn, "aro=%s:%d", p, inetd); - } else if (!strcmp(p, "privremote")) { - snprintf(buf, bufn, "aro=%s:%d", p, priv_remote); - } else if (!strcmp(p, "unsafe")) { - snprintf(buf, bufn, "aro=%s:%d", p, !safe_remote_only); - } else if (!strcmp(p, "safer")) { - snprintf(buf, bufn, "aro=%s:%d", p, more_safe); - } else if (!strcmp(p, "nocmds")) { - snprintf(buf, bufn, "aro=%s:%d", p, no_external_cmds); - } else if (!strcmp(p, "passwdfile")) { - snprintf(buf, bufn, "aro=%s:%s", p, NONUL(passwdfile)); - } else if (!strcmp(p, "using_shm")) { - snprintf(buf, bufn, "aro=%s:%d", p, !using_shm); - } else if (!strcmp(p, "logfile") || !strcmp(p, "o")) { - snprintf(buf, bufn, "aro=%s:%s", p, NONUL(logfile)); - } else if (!strcmp(p, "flag")) { - snprintf(buf, bufn, "aro=%s:%s", p, NONUL(flagfile)); - } else if (!strcmp(p, "rc")) { - char *s = rc_rcfile; - if (rc_rcfile_default) { - s = NULL; - } - snprintf(buf, bufn, "aro=%s:%s", p, NONUL(s)); - } else if (!strcmp(p, "norc")) { - snprintf(buf, bufn, "aro=%s:%d", p, got_norc); - } else if (!strcmp(p, "h") || !strcmp(p, "help") || - !strcmp(p, "V") || !strcmp(p, "version") || - !strcmp(p, "lastmod")) { - snprintf(buf, bufn, "aro=%s:%s", p, NONUL(lastmod)); - } else if (!strcmp(p, "bg")) { - snprintf(buf, bufn, "aro=%s:%d", p, opts_bg); - } else if (!strcmp(p, "sigpipe")) { - snprintf(buf, bufn, "aro=%s:%s", p, NONUL(sigpipe)); - } else if (!strcmp(p, "threads")) { - snprintf(buf, bufn, "aro=%s:%d", p, use_threads); - } else if (!strcmp(p, "readrate")) { - snprintf(buf, bufn, "aro=%s:%d", p, get_read_rate()); - } else if (!strcmp(p, "netrate")) { - snprintf(buf, bufn, "aro=%s:%d", p, get_net_rate()); - } else if (!strcmp(p, "netlatency")) { - snprintf(buf, bufn, "aro=%s:%d", p, get_net_latency()); - } else if (!strcmp(p, "pipeinput")) { - snprintf(buf, bufn, "aro=%s:%s", p, - NONUL(pipeinput_str)); - } else if (!strcmp(p, "clients")) { - char *str = list_clients(); - snprintf(buf, bufn, "aro=%s:%s", p, str); - free(str); - } else if (!strcmp(p, "client_count")) { - snprintf(buf, bufn, "aro=%s:%d", p, client_count); - } else if (!strcmp(p, "pid")) { - snprintf(buf, bufn, "aro=%s:%d", p, (int) getpid()); - } else if (!strcmp(p, "ext_xtest")) { - snprintf(buf, bufn, "aro=%s:%d", p, xtest_present); - } else if (!strcmp(p, "ext_xtrap")) { - snprintf(buf, bufn, "aro=%s:%d", p, xtrap_present); - } else if (!strcmp(p, "ext_xrecord")) { - snprintf(buf, bufn, "aro=%s:%d", p, xrecord_present); - } else if (!strcmp(p, "ext_xkb")) { - snprintf(buf, bufn, "aro=%s:%d", p, xkb_present); - } else if (!strcmp(p, "ext_xshm")) { - snprintf(buf, bufn, "aro=%s:%d", p, xshm_present); - } else if (!strcmp(p, "ext_xinerama")) { - snprintf(buf, bufn, "aro=%s:%d", p, xinerama_present); - } else if (!strcmp(p, "ext_overlay")) { - snprintf(buf, bufn, "aro=%s:%d", p, overlay_present); - } else if (!strcmp(p, "ext_xfixes")) { - snprintf(buf, bufn, "aro=%s:%d", p, xfixes_present); - } else if (!strcmp(p, "ext_xdamage")) { - snprintf(buf, bufn, "aro=%s:%d", p, xdamage_present); - } else if (!strcmp(p, "ext_xrandr")) { - snprintf(buf, bufn, "aro=%s:%d", p, xrandr_present); - } else if (!strcmp(p, "rootwin")) { - snprintf(buf, bufn, "aro=%s:0x%x", p, - (unsigned int) rootwin); - } else if (!strcmp(p, "num_buttons")) { - snprintf(buf, bufn, "aro=%s:%d", p, num_buttons); - } else if (!strcmp(p, "button_mask")) { - snprintf(buf, bufn, "aro=%s:%d", p, button_mask); - } else if (!strcmp(p, "mouse_x")) { - snprintf(buf, bufn, "aro=%s:%d", p, cursor_x); - } else if (!strcmp(p, "mouse_y")) { - snprintf(buf, bufn, "aro=%s:%d", p, cursor_y); - } else if (!strcmp(p, "bpp")) { - snprintf(buf, bufn, "aro=%s:%d", p, bpp); - } else if (!strcmp(p, "depth")) { - snprintf(buf, bufn, "aro=%s:%d", p, depth); - } else if (!strcmp(p, "indexed_color")) { - snprintf(buf, bufn, "aro=%s:%d", p, indexed_color); - } else if (!strcmp(p, "dpy_x")) { - snprintf(buf, bufn, "aro=%s:%d", p, dpy_x); - } else if (!strcmp(p, "dpy_y")) { - snprintf(buf, bufn, "aro=%s:%d", p, dpy_y); - } else if (!strcmp(p, "wdpy_x")) { - snprintf(buf, bufn, "aro=%s:%d", p, wdpy_x); - } else if (!strcmp(p, "wdpy_y")) { - snprintf(buf, bufn, "aro=%s:%d", p, wdpy_y); - } else if (!strcmp(p, "off_x")) { - snprintf(buf, bufn, "aro=%s:%d", p, off_x); - } else if (!strcmp(p, "off_y")) { - snprintf(buf, bufn, "aro=%s:%d", p, off_y); - } else if (!strcmp(p, "cdpy_x")) { - snprintf(buf, bufn, "aro=%s:%d", p, cdpy_x); - } else if (!strcmp(p, "cdpy_y")) { - snprintf(buf, bufn, "aro=%s:%d", p, cdpy_y); - } else if (!strcmp(p, "coff_x")) { - snprintf(buf, bufn, "aro=%s:%d", p, coff_x); - } else if (!strcmp(p, "coff_y")) { - snprintf(buf, bufn, "aro=%s:%d", p, coff_y); - } else if (!strcmp(p, "rfbauth")) { - NOTAPPRO - } else if (!strcmp(p, "passwd")) { - NOTAPPRO - } else if (!strcmp(p, "viewpasswd")) { - NOTAPPRO - } else { - NOTAPP - } - goto qry; - } else { - char tmp[100]; - NOTAPP - rfbLog("remote_cmd: warning unknown\n"); - strncpy(tmp, p, 90); - rfbLog("command \"%s\"\n", tmp); - goto done; - } - - done: - - if (*buf == '\0') { - sprintf(buf, "ack=1"); - } - - qry: - - if (stringonly) { - return strdup(buf); - } else if (client_connect_file) { - FILE *out = fopen(client_connect_file, "w"); - if (out != NULL) { - fprintf(out, "%s\n", buf); - fclose(out); - usleep(20*1000); - } - } else { - if (dpy) { /* raw_fb hack */ - set_vnc_connect_prop(buf); - XFlush(dpy); - } - } -#endif - return NULL; -} - -/* -- xdamage.c -- */ - -sraRegionPtr *xdamage_regions = NULL; -int xdamage_ticker = 0; - -/* for stats */ -int XD_skip = 0, XD_tot = 0, XD_des = 0; - -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); - } -#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; - } -#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(); - } -} - -/* -- cursor.c -- */ -/* - * Here begins a bit of a mess to experiment with multiple cursors - * drawn on the remote background ... - */ -typedef struct cursor_info { - char *data; /* data and mask pointers */ - char *mask; - int wx, wy; /* size of cursor */ - int sx, sy; /* shift to its centering point */ - int reverse; /* swap black and white */ - rfbCursorPtr rfb; -} cursor_info_t; - -void curs_copy(cursor_info_t *dest, cursor_info_t *src) { - if (src->data != NULL) { - dest->data = strdup(src->data); - } else { - dest->data = NULL; - } - if (src->mask != NULL) { - dest->mask = strdup(src->mask); - } else { - dest->mask = NULL; - } - dest->wx = src->wx; - dest->wy = src->wy; - dest->sx = src->sx; - dest->sy = src->sy; - dest->reverse = src->reverse; - dest->rfb = src->rfb; -} - -/* empty cursor */ -static char* curs_empty_data = -" " -" "; - -static char* curs_empty_mask = -" " -" "; -static cursor_info_t cur_empty = {NULL, NULL, 2, 2, 0, 0, 0, NULL}; - -/* dot cursor */ -static char* curs_dot_data = -" " -" x"; - -static char* curs_dot_mask = -" " -" x"; -static cursor_info_t cur_dot = {NULL, NULL, 2, 2, 0, 0, 0, NULL}; - - -/* main cursor */ -static char* curs_arrow_data = -" " -" x " -" xx " -" xxx " -" xxxx " -" xxxxx " -" xxxxxx " -" xxxxxxx " -" xxxxxxxx " -" xxxxx " -" xx xx " -" x xx " -" xx " -" xx " -" xx " -" " -" " -" "; - -static char* curs_arrow_mask = -"xx " -"xxx " -"xxxx " -"xxxxx " -"xxxxxx " -"xxxxxxx " -"xxxxxxxx " -"xxxxxxxxx " -"xxxxxxxxxx " -"xxxxxxxxxx " -"xxxxxxx " -"xxx xxxx " -"xx xxxx " -" xxxx " -" xxxx " -" xx " -" " -" "; -static cursor_info_t cur_arrow = {NULL, NULL, 18, 18, 0, 0, 1, NULL}; - -static char* curs_arrow2_data = -" " -" x " -" xx " -" xxx " -" xxxx " -" xxxxx " -" xxxxxx " -" xxxxxxx " -" xxxxxxxx " -" xxxxx " -" xx xx " -" x xx " -" xx " -" xx " -" xx " -" " -" " -" "; - -static char* curs_arrow2_mask = -"xx " -"xxx " -"xxxx " -"xxxxx " -"xxxxxx " -"xxxxxxx " -"xxxxxxxx " -"xxxxxxxxx " -"xxxxxxxxxx " -"xxxxxxxxxx " -"xxxxxxx " -"xxx xxxx " -"xx xxxx " -" xxxx " -" xxxx " -" xx " -" " -" "; -static cursor_info_t cur_arrow2 = {NULL, NULL, 18, 18, 0, 0, 0, NULL}; - -static char* curs_arrow3_data = -" " -" xx " -" xxxx " -" xxxxx " -" xxxxxxx " -" xxxxxxxx " -" xxxxxxxxxx " -" xxxxx " -" xxxxx " -" xx x " -" xx x " -" x x " -" x x " -" x " -" x " -" "; - -static char* curs_arrow3_mask = -"xxx " -"xxxxx " -"xxxxxxx " -" xxxxxxxx " -" xxxxxxxxxx " -" xxxxxxxxxxxx " -" xxxxxxxxxxxx " -" xxxxxxxxxxx " -" xxxxxxx " -" xxxxxxx " -" xxxx xxx " -" xxx xxx " -" xxx xxx " -" xxx xxx " -" xxx" -" xx"; - -static cursor_info_t cur_arrow3 = {NULL, NULL, 16, 16, 0, 0, 1, NULL}; - -static char* curs_arrow4_data = -" " -" xx " -" xxxx " -" xxxxx " -" xxxxxxx " -" xxxxxxxx " -" xxxxxxxxxx " -" xxxxx " -" xxxxx " -" xx x " -" xx x " -" x x " -" x x " -" x " -" x " -" "; - -static char* curs_arrow4_mask = -"xxx " -"xxxxx " -"xxxxxxx " -" xxxxxxxx " -" xxxxxxxxxx " -" xxxxxxxxxxxx " -" xxxxxxxxxxxx " -" xxxxxxxxxxx " -" xxxxxxx " -" xxxxxxx " -" xxxx xxx " -" xxx xxx " -" xxx xxx " -" xxx xxx " -" xxx" -" xx"; - -static cursor_info_t cur_arrow4 = {NULL, NULL, 16, 16, 0, 0, 0, NULL}; - -static char* curs_arrow5_data = -"x " -" xx " -" xxxx " -" xxxxx " -" xxxxxxx " -" xxx " -" xx x " -" x x " -" x x " -" x " -" x " -" x " -" x " -" x " -" x"; - -static char* curs_arrow5_mask = -"xx " -"xxxx " -" xxxxx " -" xxxxxxx " -" xxxxxxxx " -" xxxxxxxx " -" xxxxx " -" xxxxxx " -" xx xxx " -" x xxx " -" xxx " -" xxx " -" xxx " -" xxx" -" xx"; - -static cursor_info_t cur_arrow5 = {NULL, NULL, 15, 15, 0, 0, 1, NULL}; - -static char* curs_arrow6_data = -"x " -" xx " -" xxxx " -" xxxxx " -" xxxxxxx " -" xxx " -" xx x " -" x x " -" x x " -" x " -" x " -" x " -" x " -" x " -" x"; - -static char* curs_arrow6_mask = -"xx " -"xxxx " -" xxxxx " -" xxxxxxx " -" xxxxxxxx " -" xxxxxxxx " -" xxxxx " -" xxxxxx " -" xx xxx " -" x xxx " -" xxx " -" xxx " -" xxx " -" xxx" -" xx"; - -static cursor_info_t cur_arrow6 = {NULL, NULL, 15, 15, 0, 0, 0, NULL}; - -int alt_arrow_max = 6; -/* - * It turns out we can at least detect mouse is on the root window so - * show it (under -cursor X) with this familiar cursor... - */ -static char* curs_root_data = -" " -" " -" xxx xxx " -" xxxx xxxx " -" xxxxx xxxxx " -" xxxxx xxxxx " -" xxxxxxxxxx " -" xxxxxxxx " -" xxxxxx " -" xxxxxx " -" xxxxxxxx " -" xxxxxxxxxx " -" xxxxx xxxxx " -" xxxxx xxxxx " -" xxxx xxxx " -" xxx xxx " -" " -" "; - -static char* curs_root_mask = -" " -" xxxx xxxx " -" xxxxx xxxxx " -" xxxxxx xxxxxx " -" xxxxxxx xxxxxxx " -" xxxxxxxxxxxxxx " -" xxxxxxxxxxxx " -" xxxxxxxxxx " -" xxxxxxxx " -" xxxxxxxx " -" xxxxxxxxxx " -" xxxxxxxxxxxx " -" xxxxxxxxxxxxxx " -" xxxxxxx xxxxxxx " -" xxxxxx xxxxxx " -" xxxxx xxxxx " -" xxxx xxxx " -" "; -static cursor_info_t cur_root = {NULL, NULL, 18, 18, 8, 8, 1, NULL}; - -static char* curs_fleur_data = -" " -" xx " -" xxxx " -" xxxxxx " -" xx " -" x xx x " -" xx xx xx " -" xxxxxxxxxxxxxx " -" xxxxxxxxxxxxxx " -" xx xx xx " -" x xx x " -" xx " -" xxxxxx " -" xxxx " -" xx " -" "; - -static char* curs_fleur_mask = -" xxxx " -" xxxxx " -" xxxxxx " -" xxxxxxxx " -" x xxxxxx x " -" xxx xxxx xxx " -"xxxxxxxxxxxxxxxx" -"xxxxxxxxxxxxxxxx" -"xxxxxxxxxxxxxxxx" -"xxxxxxxxxxxxxxxx" -" xxx xxxx xxx " -" x xxxxxx x " -" xxxxxxxx " -" xxxxxx " -" xxxx " -" xxxx "; - -static cursor_info_t cur_fleur = {NULL, NULL, 16, 16, 8, 8, 1, NULL}; - -static char* curs_plus_data = -" " -" xx " -" xx " -" xx " -" xx " -" xxxxxxxxxx " -" xxxxxxxxxx " -" xx " -" xx " -" xx " -" xx " -" "; - -static char* curs_plus_mask = -" xxxx " -" xxxx " -" xxxx " -" xxxx " -"xxxxxxxxxxxx" -"xxxxxxxxxxxx" -"xxxxxxxxxxxx" -"xxxxxxxxxxxx" -" xxxx " -" xxxx " -" xxxx " -" xxxx "; -static cursor_info_t cur_plus = {NULL, NULL, 12, 12, 5, 6, 1, NULL}; - -static char* curs_xterm_data = -" " -" xxx xxx " -" xxx " -" x " -" x " -" x " -" x " -" x " -" x " -" x " -" x " -" x " -" x " -" xxx " -" xxx xxx " -" "; - -static char* curs_xterm_mask = -" xxxx xxxx " -" xxxxxxxxx " -" xxxxxxxxx " -" xxxxx " -" xxx " -" xxx " -" xxx " -" xxx " -" xxx " -" xxx " -" xxx " -" xxx " -" xxxxx " -" xxxxxxxxx " -" xxxxxxxxx " -" xxxx xxxx "; -static cursor_info_t cur_xterm = {NULL, NULL, 16, 16, 8, 8, 1, NULL}; - -enum cursor_names { - CURS_EMPTY = 0, - CURS_DOT, - - CURS_ARROW, - CURS_ROOT, - CURS_WM, - CURS_TERM, - CURS_PLUS, - - CURS_DYN1, - CURS_DYN2, - CURS_DYN3, - CURS_DYN4, - CURS_DYN5, - CURS_DYN6, - CURS_DYN7, - CURS_DYN8, - CURS_DYN9, - CURS_DYN10, - CURS_DYN11, - CURS_DYN12, - CURS_DYN13, - CURS_DYN14, - CURS_DYN15, - CURS_DYN16 -}; - -#define CURS_DYN_MIN CURS_DYN1 -#define CURS_DYN_MAX CURS_DYN16 -#define CURS_DYN_NUM (CURS_DYN_MAX - CURS_DYN_MIN + 1) - -#define CURS_MAX 32 -static cursor_info_t *cursors[CURS_MAX]; - -void setup_cursors_and_push(void) { - setup_cursors(); - first_cursor(); -} - -void first_cursor(void) { - if (! screen) { - return; - } - if (! show_cursor) { - screen->cursor = NULL; - } else { - got_xfixes_cursor_notify++; - set_rfb_cursor(get_which_cursor()); - set_cursor_was_changed(screen); - } -} - -void setup_cursors(void) { - rfbCursorPtr rfb_curs; - char *scale = NULL; - int i, j, n = 0; - static int first = 1; - - rfbLog("setting up %d cursors...\n", CURS_MAX); - - if (first) { - for (i=0; i<CURS_MAX; i++) { - cursors[i] = NULL; - } - } - first = 0; - - if (screen) { - screen->cursor = NULL; - LOCK(screen->cursorMutex); - } - - for (i=0; i<CURS_MAX; i++) { - cursor_info_t *ci; - if (cursors[i]) { - /* clear out any existing ones: */ - ci = cursors[i]; - if (ci->rfb) { - /* this is the rfbCursor part: */ - if (ci->rfb->richSource) { - free(ci->rfb->richSource); - ci->rfb->richSource = NULL; - } - if (ci->rfb->source) { - free(ci->rfb->source); - ci->rfb->source = NULL; - } - if (ci->rfb->mask) { - free(ci->rfb->mask); - ci->rfb->mask = NULL; - } - free(ci->rfb); - ci->rfb = NULL; - } - if (ci->data) { - free(ci->data); - ci->data = NULL; - } - if (ci->mask) { - free(ci->mask); - ci->mask = NULL; - } - free(ci); - ci = NULL; - } - - /* create new struct: */ - ci = (cursor_info_t *) malloc(sizeof(cursor_info_t)); - ci->data = NULL; - ci->mask = NULL; - ci->wx = 0; - ci->wy = 0; - ci->sx = 0; - ci->sy = 0; - ci->reverse = 0; - ci->rfb = NULL; - cursors[i] = ci; - } - - /* clear any xfixes cursor cache (no freeing is done) */ - get_xfixes_cursor(1); - - /* manually fill in the data+masks: */ - cur_empty.data = curs_empty_data; - cur_empty.mask = curs_empty_mask; - - cur_dot.data = curs_dot_data; - cur_dot.mask = curs_dot_mask; - - cur_arrow.data = curs_arrow_data; - cur_arrow.mask = curs_arrow_mask; - cur_arrow2.data = curs_arrow2_data; - cur_arrow2.mask = curs_arrow2_mask; - cur_arrow3.data = curs_arrow3_data; - cur_arrow3.mask = curs_arrow3_mask; - cur_arrow4.data = curs_arrow4_data; - cur_arrow4.mask = curs_arrow4_mask; - cur_arrow5.data = curs_arrow5_data; - cur_arrow5.mask = curs_arrow5_mask; - cur_arrow6.data = curs_arrow6_data; - cur_arrow6.mask = curs_arrow6_mask; - - cur_root.data = curs_root_data; - cur_root.mask = curs_root_mask; - - cur_plus.data = curs_plus_data; - cur_plus.mask = curs_plus_mask; - - cur_fleur.data = curs_fleur_data; - cur_fleur.mask = curs_fleur_mask; - - cur_xterm.data = curs_xterm_data; - cur_xterm.mask = curs_xterm_mask; - - curs_copy(cursors[CURS_EMPTY], &cur_empty); n++; - curs_copy(cursors[CURS_DOT], &cur_dot); n++; - - if (alt_arrow < 1 || alt_arrow > alt_arrow_max) { - alt_arrow = 1; - } - if (alt_arrow == 1) { - curs_copy(cursors[CURS_ARROW], &cur_arrow); n++; - } else if (alt_arrow == 2) { - curs_copy(cursors[CURS_ARROW], &cur_arrow2); n++; - } else if (alt_arrow == 3) { - curs_copy(cursors[CURS_ARROW], &cur_arrow3); n++; - } else if (alt_arrow == 4) { - curs_copy(cursors[CURS_ARROW], &cur_arrow4); n++; - } else if (alt_arrow == 5) { - curs_copy(cursors[CURS_ARROW], &cur_arrow5); n++; - } else if (alt_arrow == 6) { - curs_copy(cursors[CURS_ARROW], &cur_arrow6); n++; - } else { - alt_arrow = 1; - curs_copy(cursors[CURS_ARROW], &cur_arrow); n++; - } - - curs_copy(cursors[CURS_ROOT], &cur_root); n++; - curs_copy(cursors[CURS_WM], &cur_fleur); n++; - curs_copy(cursors[CURS_TERM], &cur_xterm); n++; - curs_copy(cursors[CURS_PLUS], &cur_plus); n++; - - if (scale_cursor_str) { - scale = scale_cursor_str; - } else if (scaling && scale_str) { - scale = scale_str; - } - /* scale = NULL zeroes everything */ - parse_scale_string(scale, &scale_cursor_fac, &scaling_cursor, - &scaling_cursor_blend, &j, &j, &scaling_cursor_interpolate, - &scale_cursor_numer, &scale_cursor_denom); - - for (i=0; i<n; i++) { - /* create rfbCursors for the special cursors: */ - - cursor_info_t *ci = cursors[i]; - - if (scaling_cursor && scale_cursor_fac != 1.0) { - int w, h, x, y, k; - unsigned long *pixels; - - w = ci->wx; - h = ci->wy; - - pixels = (unsigned long *) malloc(w * h - * sizeof(unsigned long)); - - k = 0; - for (y=0; y<h; y++) { - for (x=0; x<w; x++) { - char d = ci->data[k]; - char m = ci->mask[k]; - unsigned long *p; - - p = pixels + k; - - /* set alpha on */ - *p = 0xff000000; - - if (d == ' ' && m == ' ') { - /* alpha off */ - *p = 0x00000000; - } else if (d != ' ') { - /* body */ - if (ci->reverse) { - *p |= 0x00000000; - } else { - *p |= 0x00ffffff; - } - } else if (m != ' ') { - /* edge */ - if (ci->reverse) { - *p |= 0x00ffffff; - } else { - *p |= 0x00000000; - } - } - k++; - } - } - - rfb_curs = pixels2curs(pixels, w, h, ci->sx, ci->sy, - bpp/8); - - free(pixels); - - } else { - - /* standard X cursor */ - rfb_curs = rfbMakeXCursor(ci->wx, ci->wy, - ci->data, ci->mask); - - if (ci->reverse) { - rfb_curs->foreRed = 0x0000; - rfb_curs->foreGreen = 0x0000; - rfb_curs->foreBlue = 0x0000; - rfb_curs->backRed = 0xffff; - rfb_curs->backGreen = 0xffff; - rfb_curs->backBlue = 0xffff; - } - rfb_curs->alphaSource = NULL; - - rfb_curs->xhot = ci->sx; - rfb_curs->yhot = ci->sy; - rfb_curs->cleanup = FALSE; - rfb_curs->cleanupSource = FALSE; - rfb_curs->cleanupMask = FALSE; - rfb_curs->cleanupRichSource = FALSE; - - if (bpp == 8 && indexed_color) { - /* - * use richsource in PseudoColor for better - * looking cursors (i.e. two-color). - */ - int x, y, k = 0, bw; - int black = 0, white = 1; - char d, m; - - if (dpy) { /* raw_fb hack */ - black = BlackPixel(dpy, scr); - white = WhitePixel(dpy, scr); - } - - rfb_curs->richSource = (unsigned char *) - calloc(ci->wx * ci->wy, 1); - - for (y = 0; y < ci->wy; y++) { - for (x = 0; x < ci->wx; x++) { - d = *(ci->data + k); - m = *(ci->mask + k); - if (d == ' ' && m == ' ') { - k++; - continue; - } else if (m != ' ' && d == ' ') { - bw = black; - } else { - bw = white; - } - if (ci->reverse) { - if (bw == black) { - bw = white; - } else { - bw = black; - } - } - *(rfb_curs->richSource+k) = - (unsigned char) bw; - k++; - } - } - } - } - ci->rfb = rfb_curs; - } - if (screen) { - UNLOCK(screen->cursorMutex); - } - rfbLog(" done.\n"); -} - -typedef struct win_str_info { - char *wm_name; - char *res_name; - char *res_class; -} win_str_info_t; - -/* - * Descends window tree at pointer until the window cursor matches the current - * cursor. So far only used to detect if mouse is on root background or not. - * (returns 0 in that case, 1 otherwise). - * - */ -void tree_descend_cursor(int *depth, Window *w, win_str_info_t *winfo) { - Window r, c; - int i, rx, ry, wx, wy; - unsigned int mask; - Window wins[10]; - int descend, maxtries = 10; - char *name, *s = multiple_cursors_mode; - static XClassHint *classhint = NULL; - int nm_info = 1; - XErrorHandler old_handler; - - X_LOCK; - - if (!strcmp(s, "default") || !strcmp(s, "X") || !strcmp(s, "arrow")) { - nm_info = 0; - } - - *(winfo->wm_name) = '\0'; - *(winfo->res_name) = '\0'; - *(winfo->res_class) = '\0'; - - - /* some times a window can go away before we get to it */ - trapped_xerror = 0; - old_handler = XSetErrorHandler(trap_xerror); - - c = window; - descend = -1; - - while (c) { - wins[++descend] = c; - if (descend >= maxtries - 1) { - break; - } - if ( XTestCompareCurrentCursorWithWindow_wr(dpy, c) ) { - break; - } - /* TBD: query_pointer() */ - XQueryPointer(dpy, c, &r, &c, &rx, &ry, &wx, &wy, &mask); - } - - if (nm_info) { - int got_wm_name = 0, got_res_name = 0, got_res_class = 0; - - if (! classhint) { - classhint = XAllocClassHint(); - } - - for (i = descend; i >=0; i--) { - c = wins[i]; - if (! c) { - continue; - } - - if (! got_wm_name && XFetchName(dpy, c, &name)) { - if (name) { - if (*name != '\0') { - strcpy(winfo->wm_name, name); - got_wm_name = 1; - } - XFree(name); - } - } - if (classhint && (! got_res_name || ! got_res_class)) { - if (XGetClassHint(dpy, c, classhint)) { - char *p; - p = classhint->res_name; - if (p) { - if (*p != '\0' && ! got_res_name) { - strcpy(winfo->res_name, p); - got_res_name = 1; - } - XFree(p); - classhint->res_name = NULL; - } - p = classhint->res_class; - if (p) { - if (*p != '\0' && ! got_res_class) { - strcpy(winfo->res_class, p); - got_res_class = 1; - } - XFree(p); - classhint->res_class = NULL; - } - } - } - } - } - - XSetErrorHandler(old_handler); - trapped_xerror = 0; - - X_UNLOCK; - - *depth = descend; - *w = wins[descend]; -} - -void initialize_xfixes(void) { -#if LIBVNCSERVER_HAVE_LIBXFIXES - if (xfixes_present) { - X_LOCK; - if (use_xfixes) { - XFixesSelectCursorInput(dpy, rootwin, - XFixesDisplayCursorNotifyMask); - } else { - XFixesSelectCursorInput(dpy, rootwin, 0); - } - X_UNLOCK; - } -#endif -} - -rfbCursorPtr pixels2curs(unsigned long *pixels, int w, int h, - int xhot, int yhot, int Bpp) { - rfbCursorPtr c; - static unsigned long black = 0, white = 1; - static int first = 1; - char *bitmap, *rich, *alpha; - char *pixels_new = NULL; - int n_opaque, n_trans, n_alpha, len, histo[256]; - int send_alpha = 0, alpha_shift, thresh; - int i, x, y; - - if (first && dpy) { /* raw_fb hack */ - X_LOCK; - black = BlackPixel(dpy, scr); - white = WhitePixel(dpy, scr); - X_UNLOCK; - first = 0; - } - - if (scaling_cursor && scale_cursor_fac != 1.0) { - int W, H; - char *pixels_use = (char *) pixels; - unsigned int *pixels32 = NULL; - - W = w; - H = h; - - w = scale_round(W, scale_cursor_fac); - h = scale_round(H, scale_cursor_fac); - - pixels_new = (char *) malloc(4*w*h); - - if (sizeof(unsigned long) == 8) { - int i, j, k = 0; - /* - * to avoid 64bpp code in scale_rect() we knock - * down to unsigned int on 64bit machines: - */ - pixels32 = (unsigned int*) malloc(4*W*H); - for (j=0; j<H; j++) { - for (i=0; i<W; i++) { - *(pixels32+k) = 0xffffffff & (*(pixels+k)); - k++; - } - } - pixels_use = (char *) pixels32; - } - - scale_rect(scale_cursor_fac, scaling_cursor_blend, - scaling_cursor_interpolate, - 4, pixels_use, 4*W, pixels_new, 4*w, - W, H, w, h, 0, 0, W, H, 0); - - if (sizeof(unsigned long) == 8) { - int i, j, k = 0; - unsigned long *pixels64; - unsigned int* source = (unsigned int*) pixels_new; - /* - * now knock it back up to unsigned long: - */ - pixels64 = (unsigned long*) malloc(8*w*h); - for (j=0; j<h; j++) { - for (i=0; i<w; i++) { - *(pixels64+k) = (unsigned long) (*(source+k)); - k++; - } - } - free(pixels_new); - pixels_new = (char *) pixels64; - if (pixels32) { - free(pixels32); - pixels32 = NULL; - } - } - - pixels = (unsigned long *) pixels_new; - - xhot = scale_round(xhot, scale_cursor_fac); - yhot = scale_round(yhot, scale_cursor_fac); - } - - len = w * h; - /* for bitmap data */ - bitmap = (char *) malloc(len+1); - bitmap[len] = '\0'; - - /* for rich cursor pixel data */ - rich = (char *)calloc(Bpp*len, 1); - alpha = (char *)calloc(1*len, 1); - - n_opaque = 0; - n_trans = 0; - n_alpha = 0; - for (i=0; i<256; i++) { - histo[i] = 0; - } - - i = 0; - for (y = 0; y < h; y++) { - for (x = 0; x < w; x++) { - unsigned long a; - - a = 0xff000000 & (*(pixels+i)); - a = a >> 24; /* alpha channel */ - if (a > 0) { - n_alpha++; - } - histo[a]++; - if (a < (unsigned int) alpha_threshold) { - n_trans++; - } else { - n_opaque++; - } - i++; - } - } - if (alpha_blend) { - send_alpha = 0; - if (Bpp == 4) { - send_alpha = 1; - } - alpha_shift = 24; - if (main_red_shift == 24 || main_green_shift == 24 || - main_blue_shift == 24) { - alpha_shift = 0; /* XXX correct? */ - } - } - if (n_opaque >= alpha_frac * n_alpha) { - thresh = alpha_threshold; - } else { - n_opaque = 0; - for (i=255; i>=0; i--) { - n_opaque += histo[i]; - thresh = i; - if (n_opaque >= alpha_frac * n_alpha) { - break; - } - } - } - - i = 0; - for (y = 0; y < h; y++) { - for (x = 0; x < w; x++) { - unsigned long r, g, b, a; - unsigned int ui; - char *p; - - a = 0xff000000 & (*(pixels+i)); - a = a >> 24; /* alpha channel */ - - - if (a < (unsigned int) thresh) { - bitmap[i] = ' '; - } else { - bitmap[i] = 'x'; - } - - r = 0x00ff0000 & (*(pixels+i)); - g = 0x0000ff00 & (*(pixels+i)); - b = 0x000000ff & (*(pixels+i)); - r = r >> 16; /* red */ - g = g >> 8; /* green */ - b = b >> 0; /* blue */ - - if (alpha_remove && a != 0) { - r = (255 * r) / a; - g = (255 * g) / a; - b = (255 * b) / a; - if (r > 255) r = 255; - if (g > 255) g = 255; - if (b > 255) b = 255; - } - - if (indexed_color) { - /* - * Choose black or white for - * PseudoColor case. - */ - int value = (r+g+b)/3; - if (value > 127) { - ui = white; - } else { - ui = black; - } - } else { - /* - * Otherwise map the RGB data onto - * the framebuffer format: - */ - r = (main_red_max * r)/255; - g = (main_green_max * g)/255; - b = (main_blue_max * b)/255; - ui = 0; - ui |= (r << main_red_shift); - ui |= (g << main_green_shift); - ui |= (b << main_blue_shift); - if (send_alpha) { - ui |= (a << alpha_shift); - } - } - - /* insert value into rich source: */ - p = rich + Bpp*i; - - if (Bpp == 1) { - *((unsigned char *)p) - = (unsigned char) ui; - } else if (Bpp == 2) { - *((unsigned short *)p) - = (unsigned short) ui; - } else if (Bpp == 3) { - *((unsigned char *)p) - = (unsigned char) ((ui & 0x0000ff) >> 0); - *((unsigned char *)(p+1)) - = (unsigned char) ((ui & 0x00ff00) >> 8); - *((unsigned char *)(p+2)) - = (unsigned char) ((ui & 0xff0000) >> 16); - } else if (Bpp == 4) { - *((unsigned int *)p) - = (unsigned int) ui; - } - - /* insert alpha value into alpha source: */ - p = alpha + i; - *((unsigned char *)p) = (unsigned char) a; - - i++; - } - } - - /* create the cursor with the bitmap: */ - c = rfbMakeXCursor(w, h, bitmap, bitmap); - free(bitmap); - - if (pixels_new) { - free(pixels_new); - } - - /* set up the cursor parameters: */ - c->xhot = xhot; - c->yhot = yhot; - c->cleanup = FALSE; - c->cleanupSource = FALSE; - c->cleanupMask = FALSE; - c->cleanupRichSource = FALSE; - c->richSource = (unsigned char *) rich; - - if (alpha_blend && !indexed_color) { - c->alphaSource = (unsigned char *) alpha; - c->alphaPreMultiplied = TRUE; - } else { - free(alpha); - c->alphaSource = NULL; - } - return c; -} - -int get_xfixes_cursor(int init) { - static unsigned long last_cursor = 0; - static int last_index = 0; - static time_t curs_times[CURS_MAX]; - static unsigned long curs_index[CURS_MAX]; - int which = CURS_ARROW; - - if (init) { - /* zero out our cache (cursors are not freed) */ - int i; - for (i=0; i<CURS_MAX; i++) { - curs_times[i] = 0; - curs_index[i] = 0; - } - last_cursor = 0; - last_index = 0; - return -1; - } - - if (xfixes_present) { -#if LIBVNCSERVER_HAVE_LIBXFIXES - int use, oldest, i; - time_t oldtime, now; - XFixesCursorImage *xfc; - - if (! got_xfixes_cursor_notify && xfixes_base_event_type) { - /* try again for XFixesCursorNotify event */ - XEvent xev; - X_LOCK; - if (XCheckTypedEvent(dpy, xfixes_base_event_type + - XFixesCursorNotify, &xev)) { - got_xfixes_cursor_notify++; - } - X_UNLOCK; - } - if (! got_xfixes_cursor_notify) { - /* evidently no cursor change, just return last one */ - if (last_index) { - return last_index; - } else { - return CURS_ARROW; - } - } - got_xfixes_cursor_notify = 0; - - /* retrieve the cursor info + pixels from server: */ - X_LOCK; - xfc = XFixesGetCursorImage(dpy); - X_UNLOCK; - if (! xfc) { - /* failure. */ - return(which); - } - - if (xfc->cursor_serial == last_cursor) { - /* same serial index: no change */ - X_LOCK; - XFree(xfc); - X_UNLOCK; - if (last_index) { - return last_index; - } else { - return CURS_ARROW; - } - } - - oldest = CURS_DYN_MIN; - if (screen && screen->cursor == cursors[oldest]->rfb) { - oldest++; - } - oldtime = curs_times[oldest]; - now = time(0); - for (i = CURS_DYN_MIN; i <= CURS_DYN_MAX; i++) { - if (screen && screen->cursor == cursors[i]->rfb) { - ; - } else if (curs_times[i] < oldtime) { - /* watch for oldest one to overwrite */ - oldest = i; - oldtime = curs_times[i]; - } - if (xfc->cursor_serial == curs_index[i]) { - /* - * got a hit with an existing cursor, - * use that one. - */ - last_cursor = curs_index[i]; - curs_times[i] = now; - last_index = i; - X_LOCK; - XFree(xfc); - X_UNLOCK; - return last_index; - } - } - - /* we need to create the cursor and overwrite oldest */ - use = oldest; - if (cursors[use]->rfb) { - /* clean up oldest if it exists */ - if (cursors[use]->rfb->richSource) { - free(cursors[use]->rfb->richSource); - cursors[use]->rfb->richSource = NULL; - } - if (cursors[use]->rfb->alphaSource) { - free(cursors[use]->rfb->alphaSource); - cursors[use]->rfb->alphaSource = NULL; - } - if (cursors[use]->rfb->source) { - free(cursors[use]->rfb->source); - cursors[use]->rfb->source = NULL; - } - if (cursors[use]->rfb->mask) { - free(cursors[use]->rfb->mask); - cursors[use]->rfb->mask = NULL; - } - free(cursors[use]->rfb); - cursors[use]->rfb = NULL; - } - - /* place cursor into our collection */ - cursors[use]->rfb = pixels2curs(xfc->pixels, xfc->width, - xfc->height, xfc->xhot, xfc->yhot, bpp/8); - - /* update time and serial index: */ - curs_times[use] = now; - curs_index[use] = xfc->cursor_serial; - last_index = use; - last_cursor = xfc->cursor_serial; - - which = last_index; - - X_LOCK; - XFree(xfc); - X_UNLOCK; -#endif - } - return(which); -} - -int known_cursors_mode(char *s) { -/* - * default: see initialize_cursors_mode() for default behavior. - * arrow: unchanging white arrow. - * Xn*: show X on root background. Optional n sets treedepth. - * some: do the heuristics for root, wm, term detection. - * most: if display have overlay or xfixes, show all cursors, - * otherwise do the same as "some" - * none: show no cursor. - */ - if (strcmp(s, "default") && strcmp(s, "arrow") && *s != 'X' && - strcmp(s, "some") && strcmp(s, "most") && strcmp(s, "none")) { - return 0; - } else { - return 1; - } -} - -void initialize_cursors_mode(void) { - char *s = multiple_cursors_mode; - if (!s || !known_cursors_mode(s)) { - rfbLog("unknown cursors mode: %s\n", s); - rfbLog("resetting cursors mode to \"default\"\n"); - if (multiple_cursors_mode) free(multiple_cursors_mode); - multiple_cursors_mode = strdup("default"); - s = multiple_cursors_mode; - } - if (!strcmp(s, "none")) { - show_cursor = 0; - } else { - /* we do NOT set show_cursor = 1, let the caller do that */ - } - - show_multiple_cursors = 0; - if (show_cursor) { - if (!strcmp(s, "default")) { - if(multiple_cursors_mode) free(multiple_cursors_mode); - multiple_cursors_mode = strdup("X"); - s = multiple_cursors_mode; - } - if (*s == 'X' || !strcmp(s, "some") || !strcmp(s, "most")) { - show_multiple_cursors = 1; - } else { - show_multiple_cursors = 0; - /* hmmm, some bug going back to arrow mode.. */ - set_rfb_cursor(CURS_ARROW); - } - if (screen) { - set_cursor_was_changed(screen); - } - } else { - if (screen) { - screen->cursor = NULL; /* dangerous? */ - set_cursor_was_changed(screen); - } - } -} - -int get_which_cursor(void) { - int which = CURS_ARROW; - - if (show_multiple_cursors) { - int depth; - static win_str_info_t winfo; - static int first = 1, depth_cutoff = -1; - Window win; - XErrorHandler old_handler; - int mode = 0; - - if (drag_in_progress || button_mask) { - /* XXX not exactly what we want for menus */ - return -1; - } - - if (!strcmp(multiple_cursors_mode, "arrow")) { - /* should not happen... */ - return CURS_ARROW; - } else if (!strcmp(multiple_cursors_mode, "default")) { - mode = 0; - } else if (!strcmp(multiple_cursors_mode, "X")) { - mode = 1; - } else if (!strcmp(multiple_cursors_mode, "some")) { - mode = 2; - } else if (!strcmp(multiple_cursors_mode, "most")) { - mode = 3; - } - - if (mode == 3 && xfixes_present && use_xfixes) { - return get_xfixes_cursor(0); - } - - if (depth_cutoff < 0) { - int din; - if (sscanf(multiple_cursors_mode, "X%d", &din) == 1) { - depth_cutoff = din; - } else { - depth_cutoff = 0; - } - } - - if (first) { - winfo.wm_name = (char *) malloc(1024); - winfo.res_name = (char *) malloc(1024); - winfo.res_class = (char *) malloc(1024); - } - first = 0; - - tree_descend_cursor(&depth, &win, &winfo); - - if (depth <= depth_cutoff && !subwin) { - which = CURS_ROOT; - - } else if (mode == 2 || mode == 3) { - int which0 = which; - - /* apply crude heuristics to choose a cursor... */ - if (win) { - int ratio = 10, x, y; - unsigned int w, h, bw, d; - Window r; - - trapped_xerror = 0; - X_LOCK; - old_handler = XSetErrorHandler(trap_xerror); - - /* "narrow" windows are WM */ - if (XGetGeometry(dpy, win, &r, &x, &y, &w, &h, - &bw, &d)) { - if (w > ratio * h || h > ratio * w) { - which = CURS_WM; - } - } - XSetErrorHandler(old_handler); - X_UNLOCK; - trapped_xerror = 0; - } - if (which == which0) { - /* the string "term" mean I-beam. */ - char *name, *class; - lowercase(winfo.res_name); - lowercase(winfo.res_class); - name = winfo.res_name; - class = winfo.res_class; - if (strstr(name, "term")) { - which = CURS_TERM; - } else if (strstr(class, "term")) { - which = CURS_TERM; - } else if (strstr(name, "text")) { - which = CURS_TERM; - } else if (strstr(class, "text")) { - which = CURS_TERM; - } else if (strstr(name, "onsole")) { - which = CURS_TERM; - } else if (strstr(class, "onsole")) { - which = CURS_TERM; - } else if (strstr(name, "cmdtool")) { - which = CURS_TERM; - } else if (strstr(class, "cmdtool")) { - which = CURS_TERM; - } else if (strstr(name, "shelltool")) { - which = CURS_TERM; - } else if (strstr(class, "shelltool")) { - which = CURS_TERM; - } - } - } - } - return which; -} - -void set_cursor_was_changed(rfbScreenInfoPtr s) { - rfbClientIteratorPtr iter; - rfbClientPtr cl; - - if (! s) { - return; - } - iter = rfbGetClientIterator(s); - while( (cl = rfbClientIteratorNext(iter)) ) { - cl->cursorWasChanged = TRUE; - } - rfbReleaseClientIterator(iter); -} - -void set_cursor_was_moved(rfbScreenInfoPtr s) { - rfbClientIteratorPtr iter; - rfbClientPtr cl; - - if (! s) { - return; - } - iter = rfbGetClientIterator(s); - while( (cl = rfbClientIteratorNext(iter)) ) { - cl->cursorWasMoved = TRUE; - } - rfbReleaseClientIterator(iter); -} - -void restore_cursor_shape_updates(rfbScreenInfoPtr s) { - rfbClientIteratorPtr iter; - rfbClientPtr cl; - int count = 0; - - if (! s || ! s->clientHead) { - return; - } - iter = rfbGetClientIterator(s); - while( (cl = rfbClientIteratorNext(iter)) ) { - int changed = 0; - ClientData *cd = (ClientData *) cl->clientData; - - if (cd->had_cursor_shape_updates) { - rfbLog("restoring enableCursorShapeUpdates for client" - " 0x%x\n", cl); - cl->enableCursorShapeUpdates = TRUE; - changed = 1; - } - if (cd->had_cursor_pos_updates) { - rfbLog("restoring enableCursorPosUpdates for client" - " 0x%x\n", cl); - cl->enableCursorPosUpdates = TRUE; - changed = 1; - } - if (changed) { - cl->cursorWasChanged = TRUE; - count++; - } - } - rfbReleaseClientIterator(iter); -} - -void disable_cursor_shape_updates(rfbScreenInfoPtr s) { - rfbClientIteratorPtr iter; - rfbClientPtr cl; - static int changed = 0; - int count = 0; - - if (! s || ! s->clientHead) { - return; - } - - iter = rfbGetClientIterator(s); - while( (cl = rfbClientIteratorNext(iter)) ) { - ClientData *cd; - cd = (ClientData *) cl->clientData; - - if (cl->enableCursorShapeUpdates) { - cd->had_cursor_shape_updates = 1; - count++; - if (debug_pointer) { - rfbLog("%s disable HCSU\n", cl->host); - } - } - if (cl->enableCursorPosUpdates) { - cd->had_cursor_pos_updates = 1; - count++; - if (debug_pointer) { - rfbLog("%s disable HCPU\n", cl->host); - } - } - - cl->enableCursorShapeUpdates = FALSE; - cl->enableCursorPosUpdates = FALSE; - cl->cursorWasChanged = FALSE; - } - rfbReleaseClientIterator(iter); - - if (count) { - changed = 1; - } -} - -int cursor_shape_updates_clients(rfbScreenInfoPtr s) { - rfbClientIteratorPtr iter; - rfbClientPtr cl; - int count = 0; - - if (! s) { - return 0; - } - iter = rfbGetClientIterator(s); - while( (cl = rfbClientIteratorNext(iter)) ) { - if (cl->enableCursorShapeUpdates) { - count++; - } - } - rfbReleaseClientIterator(iter); - return count; -} - -int cursor_pos_updates_clients(rfbScreenInfoPtr s) { - rfbClientIteratorPtr iter; - rfbClientPtr cl; - int count = 0; - - if (! s) { - return 0; - } - iter = rfbGetClientIterator(s); - while( (cl = rfbClientIteratorNext(iter)) ) { - if (cl->enableCursorPosUpdates) { - count++; - } - } - rfbReleaseClientIterator(iter); - return count; -} - -/* - * Record rfb cursor position screen->cursorX, etc (a la defaultPtrAddEvent()) - * Then set up for sending rfbCursorPosUpdates back - * to clients that understand them. This seems to be TightVNC specific. - */ -void cursor_position(int x, int y) { - rfbClientIteratorPtr iter; - rfbClientPtr cl; - int cnt = 0, nonCursorPosUpdates_clients = 0; - int x_in = x, y_in = y; - - /* x and y are current positions of X11 pointer on the X11 display */ - if (!screen) { - return; - } - - if (scaling) { - x = ((double) x / dpy_x) * scaled_x; - x = nfix(x, scaled_x); - y = ((double) y / dpy_y) * scaled_y; - y = nfix(y, scaled_y); - } - - if (x == screen->cursorX && y == screen->cursorY) { - return; - } - - LOCK(screen->cursorMutex); - screen->cursorX = x; - screen->cursorY = y; - UNLOCK(screen->cursorMutex); - - iter = rfbGetClientIterator(screen); - while( (cl = rfbClientIteratorNext(iter)) ) { - if (! cl->enableCursorPosUpdates) { - nonCursorPosUpdates_clients++; - continue; - } - if (! cursor_pos_updates) { - continue; - } - if (cl == last_pointer_client) { - /* - * special case if this client was the last one to - * send a pointer position. - */ - if (x_in == cursor_x && y_in == cursor_y) { - cl->cursorWasMoved = FALSE; - } else { - /* an X11 app evidently warped the pointer */ - if (debug_pointer) { - rfbLog("cursor_position: warp " - "detected dx=%3d dy=%3d\n", - cursor_x - x, cursor_y - y); - } - cl->cursorWasMoved = TRUE; - cnt++; - } - } else { - cl->cursorWasMoved = TRUE; - cnt++; - } - } - rfbReleaseClientIterator(iter); - - if (debug_pointer && cnt) { - rfbLog("cursor_position: sent position x=%3d y=%3d to %d" - " clients\n", x, y, cnt); - } -} - -void set_rfb_cursor(int which) { - - if (! show_cursor) { - return; - } - if (! screen) { - return; - } - - if (!cursors[which] || !cursors[which]->rfb) { - rfbLog("non-existent cursor: which=%d\n", which); - return; - } else { - rfbSetCursor(screen, cursors[which]->rfb); - } -} - -void set_no_cursor(void) { - set_rfb_cursor(CURS_EMPTY); -} - -int set_cursor(int x, int y, int which) { - static int last = -1; - int changed_cursor = 0; - - if (x || y) {} /* unused vars warning: */ - - if (which < 0) { - which = last; - } - if (last < 0 || which != last) { - set_rfb_cursor(which); - changed_cursor = 1; - } - last = which; - - return changed_cursor; -} - -/* - * routine called periodically to update cursor aspects, this catches - * warps and cursor shape changes. - */ -int check_x11_pointer(void) { - Window root_w, child_w; - rfbBool ret; - int root_x, root_y, win_x, win_y; - int x, y; - unsigned int mask; - - if (raw_fb && ! dpy) return 0; /* raw_fb hack */ - - X_LOCK; - ret = XQueryPointer(dpy, rootwin, &root_w, &child_w, &root_x, &root_y, - &win_x, &win_y, &mask); - X_UNLOCK; - - if (! ret) { - return 0; - } - if (debug_pointer) { - static int last_x = -1, last_y = -1; - if (root_x != last_x || root_y != last_y) { - rfbLog("XQueryPointer: x:%4d, y:%4d)\n", - root_x, root_y); - } - last_x = root_x; - last_y = root_y; - } - - /* offset subtracted since XQueryPointer relative to rootwin */ - x = root_x - off_x - coff_x; - y = root_y - off_y - coff_y; - - /* record the cursor position in the rfb screen */ - cursor_position(x, y); - - /* change the cursor shape if necessary */ - return set_cursor(x, y, get_which_cursor()); -} - -/* -- screen.c -- */ -/* - * X11 and rfb display/screen related routines - */ - -/* - * Some handling of 8bpp PseudoColor colormaps. Called for initializing - * the clients and dynamically if -flashcmap is specified. - */ -#define NCOLOR 256 -void set_colormap(int reset) { - static int first = 1; - static XColor color[NCOLOR], prev[NCOLOR]; - Colormap cmap; - Visual *vis; - int i, ncells, diffs = 0; - - if (reset) { - first = 1; - if (screen->colourMap.data.shorts) { - free(screen->colourMap.data.shorts); - screen->colourMap.data.shorts = NULL; - } - } - - if (first) { - screen->colourMap.count = NCOLOR; - screen->serverFormat.trueColour = FALSE; - screen->colourMap.is16 = TRUE; - screen->colourMap.data.shorts = (unsigned short *) - malloc(3*sizeof(unsigned short) * NCOLOR); - } - - for (i=0; i < NCOLOR; i++) { - prev[i].red = color[i].red; - prev[i].green = color[i].green; - prev[i].blue = color[i].blue; - } - - X_LOCK; - - cmap = DefaultColormap(dpy, scr); - ncells = CellsOfScreen(ScreenOfDisplay(dpy, scr)); - vis = default_visual; - - if (subwin) { - XWindowAttributes attr; - - if (XGetWindowAttributes(dpy, window, &attr)) { - cmap = attr.colormap; - vis = attr.visual; - ncells = vis->map_entries; - } - } - - if (ncells != NCOLOR) { - if (first && ! quiet) { - rfbLog("set_colormap: number of cells is %d " - "instead of %d.\n", ncells, NCOLOR); - } - if (! shift_cmap) { - screen->colourMap.count = ncells; - } - } - - if (flash_cmap && ! first) { - XWindowAttributes attr; - Window c; - int tries = 0; - - c = window; - while (c && tries++ < 16) { - c = query_pointer(c); - if (valid_window(c, &attr, 0)) { - if (attr.colormap && attr.map_installed) { - cmap = attr.colormap; - vis = attr.visual; - ncells = vis->map_entries; - break; - } - } else { - break; - } - } - } - if (ncells > NCOLOR && ! quiet) { - rfbLog("set_colormap: big problem: ncells=%d > %d\n", - ncells, NCOLOR); - } - - if (vis->class == TrueColor || vis->class == DirectColor) { - /* - * Kludge to make 8bpp TrueColor & DirectColor be like - * the StaticColor map. The ncells = 8 is "8 per subfield" - * mentioned in xdpyinfo. Looks OK... perhaps fortuitously. - */ - if (ncells == 8 && ! shift_cmap) { - ncells = NCOLOR; - } - } - - for (i=0; i < ncells; i++) { - color[i].pixel = i; - color[i].pad = 0; - } - - XQueryColors(dpy, cmap, color, ncells); - - X_UNLOCK; - - for(i = ncells - 1; i >= 0; i--) { - int k = i + shift_cmap; - - screen->colourMap.data.shorts[i*3+0] = color[i].red; - screen->colourMap.data.shorts[i*3+1] = color[i].green; - screen->colourMap.data.shorts[i*3+2] = color[i].blue; - - if (prev[i].red != color[i].red || - prev[i].green != color[i].green || - prev[i].blue != color[i].blue ) { - diffs++; - } - - if (shift_cmap && k >= 0 && k < NCOLOR) { - /* kludge to copy the colors to higher pixel values */ - screen->colourMap.data.shorts[k*3+0] = color[i].red; - screen->colourMap.data.shorts[k*3+1] = color[i].green; - screen->colourMap.data.shorts[k*3+2] = color[i].blue; - } - } - - if (diffs && ! first) { - if (! all_clients_initialized()) { - rfbLog("set_colormap: warning: sending cmap " - "with uninitialized clients.\n"); - } - if (shift_cmap) { - rfbSetClientColourMaps(screen, 0, NCOLOR); - } else { - rfbSetClientColourMaps(screen, 0, ncells); - } - } - - first = 0; -} - -void debug_colormap(XImage *fb) { - static int debug_cmap = -1; - int i, k, histo[NCOLOR]; - - if (debug_cmap < 0) { - if (getenv("DEBUG_CMAP") != NULL) { - debug_cmap = 1; - } else { - debug_cmap = 0; - } - } - if (! debug_cmap) { - return; - } - if (! fb) { - return; - } - if (fb->bits_per_pixel > 8) { - return; - } - - for (i=0; i < NCOLOR; i++) { - histo[i] = 0; - } - for (k = 0; k < fb->width * fb->height; k++) { - unsigned char n; - char c = *(fb->data + k); - - n = (unsigned char) c; - histo[n]++; - } - fprintf(stderr, "\nColormap histogram for current screen contents:\n"); - for (i=0; i < NCOLOR; i++) { - unsigned short r = screen->colourMap.data.shorts[i*3+0]; - unsigned short g = screen->colourMap.data.shorts[i*3+1]; - unsigned short b = screen->colourMap.data.shorts[i*3+2]; - - fprintf(stderr, " %03d: %7d %04x/%04x/%04x", i, histo[i], - r, g, b); - if ((i+1) % 2 == 0) { - fprintf(stderr, "\n"); - } - } - fprintf(stderr, "\n"); -} - -/* - * Experimental mode to force the visual of the window instead of querying - * it. Used for testing, overriding some rare cases (win2vnc), and for - * -overlay . Input string can be a decimal or 0x hex or something like - * TrueColor or TrueColor:24 to force a depth as well. - * - * visual_id and possibly visual_depth are set. - */ -void set_visual(char *str) { - int vis, vdepth, defdepth = DefaultDepth(dpy, scr); - XVisualInfo vinfo; - char *p, *vstring = strdup(str); - - visual_id = (VisualID) 0; - visual_depth = 0; - - if (!strcmp(vstring, "ignore") || !strcmp(vstring, "default") - || !strcmp(vstring, "")) { - free(vstring); - return; - } - - /* set visual depth */ - if ((p = strchr(vstring, ':')) != NULL) { - visual_depth = atoi(p+1); - *p = '\0'; - vdepth = visual_depth; - } else { - vdepth = defdepth; - } - if (! quiet) { - fprintf(stderr, "\nVisual Info:\n"); - fprintf(stderr, " set_visual(\"%s\")\n", str); - fprintf(stderr, " visual_depth: %d\n", vdepth); - } - - /* set visual id number */ - if (strcmp(vstring, "StaticGray") == 0) { - vis = StaticGray; - } else if (strcmp(vstring, "GrayScale") == 0) { - vis = GrayScale; - } else if (strcmp(vstring, "StaticColor") == 0) { - vis = StaticColor; - } else if (strcmp(vstring, "PseudoColor") == 0) { - vis = PseudoColor; - } else if (strcmp(vstring, "TrueColor") == 0) { - vis = TrueColor; - } else if (strcmp(vstring, "DirectColor") == 0) { - vis = DirectColor; - } else { - unsigned int v_in; - if (sscanf(vstring, "0x%x", &v_in) != 1) { - if (sscanf(vstring, "%u", &v_in) == 1) { - visual_id = (VisualID) v_in; - return; - } - rfbLogEnable(1); - rfbLog("invalid -visual arg: %s\n", vstring); - X_UNLOCK; - clean_up_exit(1); - } - visual_id = (VisualID) v_in; - free(vstring); - return; - } - - if (! quiet) fprintf(stderr, " visual: %d\n", vis); - if (XMatchVisualInfo(dpy, scr, visual_depth, vis, &vinfo)) { - ; - } else if (XMatchVisualInfo(dpy, scr, defdepth, vis, &vinfo)) { - ; - } else { - rfbLogEnable(1); - rfbLog("could not find visual: %s\n", vstring); - X_UNLOCK; - clean_up_exit(1); - } - free(vstring); - - /* set numerical visual id. */ - visual_id = vinfo.visualid; -} - -void set_nofb_params(int restore) { - static int first = 1; - static int save[100]; - int i = 0; - - if (first) { - first = 0; - save[i++] = use_xfixes; - save[i++] = use_xdamage; - save[i++] = use_xrecord; - save[i++] = wireframe; - save[i++] = use_solid_bg; - save[i++] = overlay; - save[i++] = overlay_cursor; - save[i++] = using_shm; - save[i++] = single_copytile; - save[i++] = take_naps; - save[i++] = measure_speeds; - save[i++] = grab_buster; - save[i++] = show_cursor; - save[i++] = cursor_shape_updates; - save[i++] = cursor_pos_updates; - } - if (restore) { - i = 0; - use_xfixes = save[i++]; - use_xdamage = save[i++]; - use_xrecord = save[i++]; - wireframe = save[i++]; - use_solid_bg = save[i++]; - overlay = save[i++]; - overlay_cursor = save[i++]; - using_shm = save[i++]; - single_copytile = save[i++]; - take_naps = save[i++]; - measure_speeds = save[i++]; - grab_buster = save[i++]; - show_cursor = save[i++]; - cursor_shape_updates = save[i++]; - cursor_pos_updates = save[i++]; - - if (cursor_shape_updates) { - restore_cursor_shape_updates(screen); - } - initialize_cursors_mode(); - - return; - } - - use_xfixes = 0; - use_xdamage = 0; - use_xrecord = 0; - wireframe = 0; - - use_solid_bg = 0; - overlay = 0; - overlay_cursor = 0; - - using_shm = 0; - single_copytile = 1; - - take_naps = 0; - measure_speeds = 0; - - /* got_grab_buster? */ - grab_buster = 0; - - show_cursor = 0; - show_multiple_cursors = 0; - cursor_shape_updates = 0; - if (! got_cursorpos) { - cursor_pos_updates = 0; - } - - if (! quiet) { - rfbLog("disabling: xfixes, xdamage, solid, overlay, shm,\n"); - rfbLog(" wireframe, scrollcopyrect,\n"); - rfbLog(" noonetile, nap, cursor, %scursorshape\n", - got_cursorpos ? "" : "cursorpos, " ); - rfbLog(" in -nofb mode.\n"); - } -} - -char *raw_fb_orig_dpy = NULL; - -void set_raw_fb_params(int restore) { - static int first = 1; - static int vo0, us0, sm0, ws0, wp0, wb0, na0, tn0; - static int xr0, sb0; - static char *mc0; - - /* - * set turn off a bunch of parameters not compatible with - * -rawfb mode: 1) ignoring the X server 2) ignoring user input. - */ - - if (first) { - /* at least save the initial settings... */ - vo0 = view_only; - ws0 = watch_selection; - wp0 = watch_primary; - wb0 = watch_bell; - na0 = no_autorepeat; - sb0 = use_solid_bg; - - us0 = use_snapfb; - sm0 = using_shm; - tn0 = take_naps; - xr0 = xrandr; - mc0 = multiple_cursors_mode; - - first = 0; - } - - if (restore) { - view_only = vo0; - watch_selection = ws0; - watch_primary = wp0; - watch_bell = wb0; - no_autorepeat = na0; - use_solid_bg = sb0; - - use_snapfb = us0; - using_shm = sm0; - take_naps = tn0; - xrandr = xr0; - multiple_cursors_mode = mc0; - - if (! dpy && raw_fb_orig_dpy) { - dpy = XOpenDisplay(raw_fb_orig_dpy); - if (dpy) { - if (! quiet) rfbLog("reopened DISPLAY: %s\n", - raw_fb_orig_dpy); - } else { - if (! quiet) rfbLog("WARNING: failed to reopen " - "DISPLAY: %s\n", raw_fb_orig_dpy); - } - } - return; - } - - if (! quiet) { - rfbLog("set_raw_fb_params: modifying settings for " - "-rawfb mode.\n"); - } - - if (got_noviewonly) { - /* - * The user input parameters are not unset under - * -noviewonly... this usage should be very rare - * (i.e. rawfb but also send user input to the X - * display, most likely using /dev/fb0 for some reason...) - */ - if (! quiet) { - rfbLog("rawfb: -noviewonly mode: still sending mouse and\n"); - rfbLog("rawfb: keyboard input to the X DISPLAY!!\n"); - } - } else { - /* Normal case: */ - if (! view_only) { - if (! quiet) rfbLog("rawfb: setting view_only\n"); - view_only = 1; - } - if (watch_selection) { - if (! quiet) rfbLog("rawfb: turning off " - "watch_selection\n"); - watch_selection = 0; - } - if (watch_primary) { - if (! quiet) rfbLog("rawfb: turning off " - "watch_primary\n"); - watch_primary = 0; - } - if (watch_bell) { - if (! quiet) rfbLog("rawfb: turning off watch_bell\n"); - watch_bell = 0; - } - if (no_autorepeat) { - if (! quiet) rfbLog("rawfb: turning off " - "no_autorepeat\n"); - no_autorepeat = 0; - } - if (use_solid_bg) { - if (! quiet) rfbLog("rawfb: turning off " - "use_solid_bg\n"); - use_solid_bg = 0; - } - multiple_cursors_mode = strdup("arrow"); - } - if (use_snapfb) { - if (! quiet) rfbLog("rawfb: turning off use_snapfb\n"); - use_snapfb = 0; - } - if (using_shm) { - if (! quiet) rfbLog("rawfb: turning off using_shm\n"); - using_shm = 0; - } - if (take_naps) { - if (! quiet) rfbLog("rawfb: turning off take_naps\n"); - take_naps = 0; - } - if (xrandr) { - if (! quiet) rfbLog("rawfb: turning off xrandr\n"); - xrandr = 0; - } -} - -/* - * Presumably under -nofb the clients will never request the framebuffer. - * However, we have gotten such a request... so let's just give them - * the current view on the display. n.b. x2vnc and perhaps win2vnc - * requests a 1x1 pixel for some workaround so sadly this evidently - * nearly always happens. - */ -void nofb_hook(rfbClientPtr cl) { - XImage *fb; - rfbLog("framebuffer requested in -nofb mode by client %s\n", cl->host); - /* ignore xrandr */ - fb = XGetImage_wr(dpy, window, 0, 0, dpy_x, dpy_y, AllPlanes, ZPixmap); - main_fb = fb->data; - rfb_fb = main_fb; - screen->frameBuffer = rfb_fb; - screen->displayHook = NULL; -} - -void do_new_fb(int reset_mem) { - XImage *fb; - char *old_main = main_fb; - char *old_rfb = rfb_fb; - - /* for threaded we really should lock libvncserver out. */ - if (use_threads) { - rfbLog("warning: changing framebuffers while threaded may\n"); - rfbLog(" not work, do not use -threads if problems arise.\n"); - } - - if (reset_mem == 1) { - /* reset_mem == 2 is a hack for changing users... */ - clean_shm(0); - free_tiles(); - } - - fb = initialize_xdisplay_fb(); - - initialize_screen(NULL, NULL, fb); - - if (reset_mem) { - initialize_tiles(); - initialize_blackouts_and_xinerama(); - initialize_polling_images(); - } - - if (old_main != old_rfb && old_main) { - free(old_main); - } - if (old_rfb) { - free(old_rfb); - } - fb0 = fb; -} - -void remove_fake_fb(void) { - if (! screen) { - return; - } - rfbLog("removing fake fb: 0x%x\n", fake_fb); - - do_new_fb(1); - - /* - * fake_fb is freed in do_new_fb(), but we set to NULL here to - * indicate it is gone. - */ - fake_fb = NULL; -} - -void install_fake_fb(int w, int h, int bpp) { - int bpc; - if (! screen) { - return; - } - if (fake_fb) { - free(fake_fb); - } - fake_fb = (char *) calloc(w*h*bpp/8, 1); - if (! fake_fb) { - rfbLog("could not create fake fb: %dx%d %d\n", w, h, bpp); - return; - } - bpc = guess_bits_per_color(bpp); - rfbLog("installing fake fb: %dx%d %d\n", w, h, bpp); - rfbLog("rfbNewFramebuffer(0x%x, 0x%x, %d, %d, %d, %d, %d)\n", - screen, fake_fb, w, h, bpc, 1, bpp/8); - - rfbNewFramebuffer(screen, fake_fb, w, h, bpc, 1, bpp/8); -} - -void check_padded_fb(void) { - if (! fake_fb) { - return; - } - if (time(0) > pad_geometry_time+1 && all_clients_initialized()) { - remove_fake_fb(); - } -} - -void install_padded_fb(char *geom) { - int w, h; - int ok = 1; - if (! geom || *geom == '\0') { - ok = 0; - } else if (sscanf(geom, "%dx%d", &w, &h) != 2) { - ok = 0; - } - w = nabs(w); - h = nabs(h); - - if (w < 5) w = 5; - if (h < 5) h = 5; - - if (!ok) { - rfbLog("skipping invalid pad geometry: '%s'\n", NONUL(geom)); - return; - } - install_fake_fb(w, h, bpp); - pad_geometry_time = time(0); -} - -void initialize_snap_fb(void) { - if (snap_fb) { - free(snap_fb); - } - snap = XGetImage_wr(dpy, window, 0, 0, dpy_x, dpy_y, AllPlanes, - ZPixmap); - snap_fb = snap->data; -} - - -XImage *initialize_raw_fb(void) { - char *str, *q; - int w, h, b, shmid = 0; - unsigned long rm = 0, gm = 0, bm = 0; - static XImage ximage_struct; /* n.b.: not (XImage *) */ - int closedpy = 1, i, m; - - if (raw_fb_addr || raw_fb_seek) { - if (raw_fb_shm) { - shmdt(raw_fb_addr); -#if LIBVNCSERVER_HAVE_MMAP - } else if (raw_fb_mmap) { - munmap(raw_fb_addr, raw_fb_mmap); - if (raw_fb_fd >= 0) { - close(raw_fb_fd); - } -#endif - } else if (raw_fb_seek) { - if (raw_fb_fd >= 0) { - close(raw_fb_fd); - } - } - raw_fb_addr = NULL; - } - if (! raw_fb_str) { - return NULL; - } - - - if ( (q = strstr(raw_fb_str, "setup:")) == raw_fb_str) { - FILE *pipe; - char line[1024], *t; - - set_child_info(); - q += strlen("setup:"); - if (no_external_cmds) { - rfbLogEnable(1); - rfbLog("cannot run external commands in -nocmds " - "mode:\n"); - rfbLog(" \"%s\"\n", q); - rfbLog(" exiting.\n"); - clean_up_exit(1); - } - rfbLog("running command to setup rawfb: %s\n", q); - pipe = popen(q, "r"); - if (! pipe) { - rfbLogEnable(1); - rfbLog("popen of setup command failed.\n"); - rfbLogPerror("popen"); - clean_up_exit(1); - } - line[0] = '\0'; - if (fgets(line, 1024, pipe) == NULL) { - rfbLogEnable(1); - rfbLog("read of setup command failed.\n"); - clean_up_exit(1); - } - pclose(pipe); - str = strdup(line); - t = str; - while (*t != '\0') { - if (*t == '\n') { - *t = '\0'; - } - t++; - } - rfbLog("setup command returned: %s\n", str); - - } else { - str = strdup(raw_fb_str); - } - - /* - * uppercase means do not close the display (e.g. for remote control) - */ - if (strstr(str, "SHM:") == str) { - closedpy = 0; - str[0] = 's'; str[1] = 'h'; str[2] = 'm'; - } else if (strstr(str, "MAP:") == str) { - closedpy = 0; - str[0] = 'm'; str[1] = 'a'; str[2] = 'p'; - } else if (strstr(str, "MMAP:") == str) { - closedpy = 0; - str[0] = 'm'; str[1] = 'm'; str[2] = 'a'; str[3] = 'p'; - } else if (strstr(str, "FILE:") == str) { - str[0] = 'f'; str[1] = 'i'; str[2] = 'l'; str[3] = 'e'; - closedpy = 0; - } - - if (closedpy && !view_only && got_noviewonly) { - rfbLog("not closing X DISPLAY under -noviewonly option.\n"); - closedpy = 0; - if (! window) { - window = rootwin; - } - } - - if (! raw_fb_orig_dpy && dpy) { - raw_fb_orig_dpy = strdup(DisplayString(dpy)); - } -#ifndef BOLDLY_CLOSE_DISPLAY -#define BOLDLY_CLOSE_DISPLAY 1 -#endif -#if BOLDLY_CLOSE_DISPLAY - if (closedpy) { - if (dpy) { - rfbLog("closing X DISPLAY: %s in rawfb mode.\n", - DisplayString(dpy)); - XCloseDisplay(dpy); /* yow! */ - } - dpy = NULL; - } -#endif - - /* - * -rawfb shm:163938442@640x480x32:ff/ff00/ff0000+3000 - * -rawfb map:/path/to/file@640x480x32:ff/ff00/ff0000 - * -rawfb file:/path/to/file@640x480x32:ff/ff00/ff0000 - */ - - raw_fb_offset = 0; - - /* +O offset */ - if ((q = strrchr(str, '+')) != NULL) { - if (sscanf(q, "+%d", &raw_fb_offset) == 1) { - *q = '\0'; - } else { - raw_fb_offset = 0; - } - } - /* :R/G/B masks */ - if ((q = strrchr(str, ':')) != NULL) { - if (sscanf(q, ":%lx/%lx/%lx", &rm, &gm, &bm) == 3) { - *q = '\0'; - } else if (sscanf(q, ":0x%lx/0x%lx/0x%lx", &rm, &gm, &bm)== 3) { - *q = '\0'; - } else if (sscanf(q, ":%lu/%lu/%lu", &rm, &gm, &bm) == 3) { - *q = '\0'; - } else { - rm = 0; - gm = 0; - bm = 0; - } - } - if ((q = strrchr(str, '@')) == NULL) { - rfbLogEnable(1); - rfbLog("invalid rawfb str: %s\n", str); - clean_up_exit(1); - } - /* @WxHxB */ - if (sscanf(q, "@%dx%dx%d", &w, &h, &b) != 3) { - rfbLogEnable(1); - rfbLog("invalid rawfb str: %s\n", str); - clean_up_exit(1); - } - *q = '\0'; - - if (strstr(str, "shm:") != str && strstr(str, "mmap:") != str && - strstr(str, "map:") != str && strstr(str, "file:") != str) { - /* hmmm, not following directions, see if map: applies */ - struct stat sbuf; - if (stat(str, &sbuf) == 0) { - char *new; - int len = strlen("map:") + strlen(str) + 1; - rfbLog("no type prefix: %s\n", raw_fb_str); - rfbLog(" but file exists, so assuming: map:%s\n", - raw_fb_str); - new = (char *) malloc(len); - strcpy(new, "map:"); - strcat(new, str); - free(str); - str = new; - } - } - - dpy_x = wdpy_x = w; - dpy_y = wdpy_y = h; - off_x = 0; - off_y = 0; - - raw_fb_shm = 0; - raw_fb_mmap = 0; - raw_fb_seek = 0; - raw_fb_fd = -1; - raw_fb_addr = NULL; - - if (sscanf(str, "shm:%d", &shmid) == 1) { - /* shm:N */ -#if LIBVNCSERVER_HAVE_XSHM - raw_fb_addr = (char *) shmat(shmid, 0, SHM_RDONLY); - if (! raw_fb_addr) { - rfbLogEnable(1); - rfbLog("failed to attach to shm: %d, %s\n", shmid, str); - rfbLogPerror("shmat"); - clean_up_exit(1); - } - raw_fb_shm = 1; - rfbLog("rawfb: shm: %d W: %d H: %d B: %d addr: %p\n", - shmid, w, h, b, raw_fb_addr); -#else - rfbLogEnable(1); - rfbLog("x11vnc was compiled without shm support.\n"); - rfbLogPerror("shmat"); - clean_up_exit(1); -#endif - } else if (strstr(str, "map:") == str || strstr(str, "mmap:") == str - || strstr(str, "file:") == str) { - /* map:/path/... or file:/path */ - int fd, do_mmap = 1, size; - struct stat sbuf; - - if (*str == 'f') { - do_mmap = 0; - } - q = strchr(str, ':'); - q++; - - fd = open(q, O_RDONLY); - if (fd < 0) { - rfbLogEnable(1); - rfbLog("failed to open file: %s, %s\n", q, str); - rfbLogPerror("open"); - clean_up_exit(1); - } - raw_fb_fd = fd; - - size = w*h*b/8 + raw_fb_offset; - if (fstat(fd, &sbuf) == 0) { - if (S_ISREG(sbuf.st_mode)) { - if (0) size = sbuf.st_size; - } else { - rfbLog("raw fb is non-regular file: %s\n", q); - } - } - - if (do_mmap) { -#if LIBVNCSERVER_HAVE_MMAP - raw_fb_addr = mmap(0, size, PROT_READ, MAP_SHARED, - fd, 0); - - if (raw_fb_addr == MAP_FAILED || raw_fb_addr == NULL) { - rfbLogEnable(1); - rfbLog("failed to mmap file: %s, %s\n", q, str); - rfbLog(" raw_fb_addr: %p\n", raw_fb_addr); - rfbLogPerror("mmap"); - clean_up_exit(1); - } - raw_fb_mmap = size; - - rfbLog("rawfb: mmap file: %s\n", q); - rfbLog(" w: %d h: %d b: %d addr: %p sz: %d\n", w, h, - b, raw_fb_addr, size); -#else - rfbLog("mmap(2) not supported on system, using" - " slower lseek(2)\n"); - raw_fb_seek = size; -#endif - } else { - raw_fb_seek = size; - - rfbLog("rawfb: seek file: %s\n", q); - rfbLog(" W: %d H: %d B: %d sz: %d\n", w, h, b, size); - } - } else { - rfbLogEnable(1); - rfbLog("invalid rawfb str: %s\n", str); - clean_up_exit(1); - } - - if (! raw_fb_image) { - raw_fb_image = &ximage_struct; - } - - initialize_clipshift(); - - raw_fb = (char *) malloc(dpy_x * dpy_y * b/8); - raw_fb_image->data = raw_fb; - raw_fb_image->format = ZPixmap; - raw_fb_image->width = dpy_x; - raw_fb_image->height = dpy_y; - raw_fb_image->bits_per_pixel = b; - raw_fb_image->bytes_per_line = dpy_x*b/8; - - if (rm == 0 && gm == 0 && bm == 0) { - /* guess masks... */ - if (b == 24 || b == 32) { - rm = 0xff0000; - gm = 0x00ff00; - bm = 0x0000ff; - } else if (b == 16) { - rm = 0xf800; - gm = 0x07e0; - bm = 0x001f; - } else if (b == 8) { - rm = 0x07; - gm = 0x38; - bm = 0xc0; - } - } - - raw_fb_image->red_mask = rm; - raw_fb_image->green_mask = gm; - raw_fb_image->blue_mask = bm; - - raw_fb_image->depth = 0; - m = 1; - for (i=0; i<32; i++) { - if (rm & m) { - raw_fb_image->depth++; - } - if (gm & m) { - raw_fb_image->depth++; - } - if (bm & m) { - raw_fb_image->depth++; - } - m = m << 1; - } - if (! raw_fb_image->depth) { - raw_fb_image->depth = (b == 32) ? 24 : b; - } - - if (clipshift) { - memset(raw_fb, 0xff, dpy_x * dpy_y * b/8); - } else if (raw_fb_addr) { - memcpy(raw_fb, raw_fb_addr + raw_fb_offset, dpy_x*dpy_y*b/8); - } else { - memset(raw_fb, 0xff, dpy_x * dpy_y * b/8); - } - - rfbLog("rawfb: raw_fb %p\n", raw_fb); - - free(str); - - return raw_fb_image; -} - -void initialize_clipshift(void) { - clipshift = 0; - cdpy_x = cdpy_y = coff_x = coff_y = 0; - if (clip_str) { - int w, h, x, y, bad = 0; - if (parse_geom(clip_str, &w, &h, &x, &y, wdpy_x, wdpy_y)) { - if (x < 0) { - x = 0; - } - if (y < 0) { - y = 0; - } - if (x + w > wdpy_x) { - w = wdpy_x - x; - } - if (y + h > wdpy_y) { - h = wdpy_y - y; - } - if (w <= 0 || h <= 0) { - bad = 1; - } - } else { - bad = 1; - } - if (bad) { - rfbLog("skipping invalid -clip WxH+X+Y: %s\n", - clip_str); - } else { - /* OK, change geom behind everyone's back... */ - cdpy_x = w; - cdpy_y = h; - coff_x = x; - coff_y = y; - - clipshift = 1; - - dpy_x = cdpy_x; - dpy_y = cdpy_y; - } - } -} - -/* - * initialize a fb for the X display - */ -XImage *initialize_xdisplay_fb(void) { - XImage *fb; - char *vis_str = visual_str; - int try = 0, subwin_tries = 3; - XErrorHandler old_handler; - int subwin_bs; - - if (raw_fb_str) { - return initialize_raw_fb(); - } - - X_LOCK; - if (subwin) { - if (subwin_wait_mapped) { - wait_until_mapped(subwin); - } - if (!valid_window((Window) subwin, NULL, 0)) { - rfbLogEnable(1); - rfbLog("invalid sub-window: 0x%lx\n", subwin); - X_UNLOCK; - clean_up_exit(1); - } - } - - if (overlay) { - /* - * ideally we'd like to not have to cook up the - * visual variables but rather let it all come out - * of XReadScreen(), however there is no way to get - * a default visual out of it, so we pretend -visual - * TrueColor:NN was supplied with NN usually 24. - */ - char str[32]; - Window twin = subwin ? subwin : rootwin; - XImage *xi; - - xi = xreadscreen(dpy, twin, 0, 0, 8, 8, False); - sprintf(str, "TrueColor:%d", xi->depth); - if (xi->depth != 24 && ! quiet) { - rfbLog("warning: overlay image has depth %d " - "instead of 24.\n", xi->depth); - } - XDestroyImage(xi); - if (visual_str != NULL && ! quiet) { - rfbLog("warning: replacing '-visual %s' by '%s' " - "for use with -overlay\n", visual_str, str); - } - vis_str = strdup(str); - } - - if (vis_str != NULL) { - set_visual(vis_str); - if (vis_str != visual_str) { - free(vis_str); - } - } - - /* set up parameters for subwin or non-subwin cases: */ - - if (! subwin) { - /* full screen */ - window = rootwin; - dpy_x = wdpy_x = DisplayWidth(dpy, scr); - dpy_y = wdpy_y = DisplayHeight(dpy, scr); - off_x = 0; - off_y = 0; - /* this may be overridden via visual_id below */ - default_visual = DefaultVisual(dpy, scr); - } else { - /* single window */ - XWindowAttributes attr; - - window = (Window) subwin; - if (! XGetWindowAttributes(dpy, window, &attr)) { - rfbLogEnable(1); - rfbLog("invalid window: 0x%lx\n", window); - X_UNLOCK; - clean_up_exit(1); - } - dpy_x = wdpy_x = attr.width; - dpy_y = wdpy_y = attr.height; - - subwin_bs = attr.backing_store; - - /* this may be overridden via visual_id below */ - default_visual = attr.visual; - - X_UNLOCK; - set_offset(); - X_LOCK; - } - - initialize_clipshift(); - - /* initialize depth to reasonable value, visual_id may override */ - depth = DefaultDepth(dpy, scr); - - if (visual_id) { - int n; - XVisualInfo vinfo_tmpl, *vinfo; - - /* - * we are in here from -visual or -overlay options - * visual_id and visual_depth were set in set_visual(). - */ - - vinfo_tmpl.visualid = visual_id; - vinfo = XGetVisualInfo(dpy, VisualIDMask, &vinfo_tmpl, &n); - if (vinfo == NULL || n == 0) { - rfbLogEnable(1); - rfbLog("could not match visual_id: 0x%x\n", - (int) visual_id); - X_UNLOCK; - clean_up_exit(1); - } - default_visual = vinfo->visual; - depth = vinfo->depth; - if (visual_depth) { - /* force it from -visual MooColor:NN */ - depth = visual_depth; - } - if (! quiet) { - fprintf(stderr, " initialize_xdisplay_fb()\n"); - fprintf(stderr, " Visual*: %p\n", - (void *) vinfo->visual); - fprintf(stderr, " visualid: 0x%x\n", - (int) vinfo->visualid); - fprintf(stderr, " screen: %d\n", vinfo->screen); - fprintf(stderr, " depth: %d\n", vinfo->depth); - fprintf(stderr, " class: %d\n", vinfo->class); - fprintf(stderr, " red_mask: 0x%08lx %s\n", - vinfo->red_mask, bitprint(vinfo->red_mask, 32)); - fprintf(stderr, " green_mask: 0x%08lx %s\n", - vinfo->green_mask, bitprint(vinfo->green_mask, 32)); - fprintf(stderr, " blue_mask: 0x%08lx %s\n", - vinfo->blue_mask, bitprint(vinfo->blue_mask, 32)); - fprintf(stderr, " cmap_size: %d\n", - vinfo->colormap_size); - fprintf(stderr, " bits b/rgb: %d\n", - vinfo->bits_per_rgb); - fprintf(stderr, "\n"); - } - XFree(vinfo); - } - - if (! quiet) { - rfbLog("Default visual ID: 0x%x\n", - (int) XVisualIDFromVisual(default_visual)); - } - - again: - if (subwin) { - int shift = 0; - int subwin_x, subwin_y; - int disp_x = DisplayWidth(dpy, scr); - int disp_y = DisplayHeight(dpy, scr); - Window twin; - /* subwins can be a dicey if they are changing size... */ - trapped_xerror = 0; - old_handler = XSetErrorHandler(trap_xerror); - XTranslateCoordinates(dpy, window, rootwin, 0, 0, &subwin_x, - &subwin_y, &twin); - - if (subwin_x + wdpy_x > disp_x) { - shift = 1; - subwin_x = disp_x - wdpy_x - 3; - } - if (subwin_y + wdpy_y > disp_y) { - shift = 1; - subwin_y = disp_y - wdpy_y - 3; - } - if (subwin_x < 0) { - shift = 1; - subwin_x = 1; - } - if (subwin_y < 0) { - shift = 1; - subwin_y = 1; - } - - if (shift) { - XMoveWindow(dpy, window, subwin_x, subwin_y); - } - XMapRaised(dpy, window); - XRaiseWindow(dpy, window); - XFlush(dpy); - } - try++; - - if (nofb) { - /* - * For -nofb we do not allocate the framebuffer, so we - * can save a few MB of memory. - */ - fb = XCreateImage_wr(dpy, default_visual, depth, ZPixmap, - 0, NULL, dpy_x, dpy_y, BitmapPad(dpy), 0); - - } else if (visual_id) { - /* - * we need to call XCreateImage to supply the visual - */ - fb = XCreateImage_wr(dpy, default_visual, depth, ZPixmap, - 0, NULL, dpy_x, dpy_y, BitmapPad(dpy), 0); - fb->data = (char *) malloc(fb->bytes_per_line * fb->height); - - } else { - fb = XGetImage_wr(dpy, window, 0, 0, dpy_x, dpy_y, AllPlanes, - ZPixmap); - if (! quiet) { - rfbLog("Read initial data from X display into" - " framebuffer.\n"); - } - } - - if (subwin) { - XSetErrorHandler(old_handler); - if (trapped_xerror) { - rfbLog("trapped GetImage at SUBWIN creation.\n"); - if (try < subwin_tries) { - usleep(250 * 1000); - if (!get_window_size(window, &wdpy_x, &wdpy_y)) { - rfbLogEnable(1); - rfbLog("could not get size of subwin " - "0x%lx\n", subwin); - X_UNLOCK; - clean_up_exit(1); - } - goto again; - } - } - trapped_xerror = 0; - - } else if (! fb && try == 1) { - /* try once more */ - usleep(250 * 1000); - goto again; - } - if (use_snapfb) { - initialize_snap_fb(); - } - X_UNLOCK; - - if (fb->bits_per_pixel == 24 && ! quiet) { - rfbLog("warning: 24 bpp may have poor performance.\n"); - } - return fb; -} - -void parse_scale_string(char *str, double *factor, int *scaling, int *blend, - int *nomult4, int *pad, int *interpolate, int *numer, int *denom) { - - int m, n; - char *p, *tstr; - double f; - - *factor = 1.0; - *scaling = 0; - *blend = 1; - *nomult4 = 0; - *pad = 0; - *interpolate = 0; - *numer = 0, *denom = 0; - - if (str == NULL || str[0] == '\0') { - return; - } - tstr = strdup(str); - - if ( (p = strchr(tstr, ':')) != NULL) { - /* options */ - if (strstr(p+1, "nb") != NULL) { - *blend = 0; - } - if (strstr(p+1, "fb") != NULL) { - *blend = 2; - } - if (strstr(p+1, "n4") != NULL) { - *nomult4 = 1; - } - if (strstr(p+1, "in") != NULL) { - *interpolate = 1; - } - if (strstr(p+1, "pad") != NULL) { - *pad = 1; - } - if (strstr(p+1, "nocr") != NULL) { - /* global */ - scaling_copyrect = 0; - } else if (strstr(p+1, "cr") != NULL) { - /* global */ - scaling_copyrect = 1; - } - *p = '\0'; - } - if (strchr(tstr, '.') != NULL) { - double test, diff, eps = 1.0e-7; - if (sscanf(tstr, "%lf", &f) != 1) { - rfbLogEnable(1); - rfbLog("invalid -scale arg: %s\n", tstr); - clean_up_exit(1); - } - *factor = (double) f; - /* look for common fractions from small ints: */ - for (n=2; n<=10; n++) { - for (m=1; m<n; m++) { - test = ((double) m)/ n; - diff = *factor - test; - if (-eps < diff && diff < eps) { - *numer = m; - *denom = n; - break; - - } - } - if (*denom) { - break; - } - } - if (*factor < 0.01) { - rfbLogEnable(1); - rfbLog("-scale factor too small: %f\n", scale_fac); - clean_up_exit(1); - } - } else { - if (sscanf(tstr, "%d/%d", &m, &n) != 2) { - if (sscanf(tstr, "%d", &m) != 1) { - rfbLogEnable(1); - rfbLog("invalid -scale arg: %s\n", tstr); - clean_up_exit(1); - } else { - /* e.g. -scale 1 or -scale 2 */ - n = 1; - } - } - if (n <= 0 || m <=0) { - rfbLogEnable(1); - rfbLog("invalid -scale arg: %s\n", tstr); - clean_up_exit(1); - } - *factor = ((double) m)/ n; - if (*factor < 0.01) { - rfbLogEnable(1); - rfbLog("-scale factor too small: %f\n", *factor); - clean_up_exit(1); - } - *numer = m; - *denom = n; - } - if (*factor == 1.0) { - if (! quiet) { - rfbLog("scaling disabled for factor %f\n", *factor); - } - } else { - *scaling = 1; - } - free(tstr); -} - -int scale_round(int len, double fac) { - double eps = 0.000001; - - len = (int) (len * fac + eps); - if (len < 1) { - len = 1; - } - return len; -} - -void setup_scaling(int *width_in, int *height_in) { - int width = *width_in; - int height = *height_in; - - parse_scale_string(scale_str, &scale_fac, &scaling, &scaling_blend, - &scaling_nomult4, &scaling_pad, &scaling_interpolate, - &scale_numer, &scale_denom); - - if (scaling) { - width = scale_round(width, scale_fac); - height = scale_round(height, scale_fac); - if (scale_denom && scaling_pad) { - /* it is not clear this padding is useful anymore */ - rfbLog("width %% denom: %d %% %d = %d\n", width, - scale_denom, width % scale_denom); - rfbLog("height %% denom: %d %% %d = %d\n", height, - scale_denom, height % scale_denom); - if (width % scale_denom != 0) { - int w = width; - w += scale_denom - (w % scale_denom); - if (!scaling_nomult4 && w % 4 != 0) { - /* need to make mult of 4 as well */ - int c = 0; - while (w % 4 != 0 && c++ <= 5) { - w += scale_denom; - } - } - width = w; - rfbLog("padded width to: %d (mult of %d%s\n", - width, scale_denom, !scaling_nomult4 ? - " and 4)" : ")"); - } - if (height % scale_denom != 0) { - height += scale_denom - (height % scale_denom); - rfbLog("padded height to: %d (mult of %d)\n", - height, scale_denom); - } - } - if (!scaling_nomult4 && width % 4 != 0 && width > 2) { - /* reset width to be multiple of 4 */ - int width0 = width; - if ((width+1) % 4 == 0) { - width = width+1; - } else if ((width-1) % 4 == 0) { - width = width-1; - } else if ((width+2) % 4 == 0) { - width = width+2; - } - rfbLog("reset scaled width %d -> %d to be a multiple of" - " 4 (to\n", width0, width); - rfbLog("make vncviewers happy). use -scale m/n:n4 to " - "disable.\n"); - } - scaled_x = width; - scaled_y = height; - - *width_in = width; - *height_in = height; - } -} - -/* - * initialize the rfb framebuffer/screen - */ -void initialize_screen(int *argc, char **argv, XImage *fb) { - int have_masks = 0; - int width = fb->width; - int height = fb->height; - int create_screen = screen ? 0 : 1; - int bits_per_color; - - main_bytes_per_line = fb->bytes_per_line; - - setup_scaling(&width, &height); - - - if (scaling) { - rfbLog("scaling screen: %dx%d -> %dx%d scale_fac=%.5f\n", - fb->width, fb->height, scaled_x, scaled_y, scale_fac); - - rfb_bytes_per_line = (main_bytes_per_line / fb->width) * width; - } else { - rfb_bytes_per_line = main_bytes_per_line; - } - - /* - * These are just hints wrt pixel format just to let - * rfbGetScreen/rfbNewFramebuffer proceed with reasonable - * defaults. We manually set them in painful detail below. - */ - bits_per_color = guess_bits_per_color(fb->bits_per_pixel); - - /* n.b. samplesPerPixel (set = 1 here) seems to be unused. */ - if (create_screen) { - screen = rfbGetScreen(argc, argv, width, height, - bits_per_color, 1, (int) fb->bits_per_pixel/8); - if (screen && http_dir) { - http_connections(1); - } - } else { - /* set set frameBuffer member below. */ - rfbLog("rfbNewFramebuffer(0x%x, 0x%x, %d, %d, %d, %d, %d)\n", - screen, NULL, width, height, - bits_per_color, 1, fb->bits_per_pixel/8); - - /* these are probably overwritten, but just to be safe: */ - screen->bitsPerPixel = fb->bits_per_pixel; - screen->depth = fb->depth; - - rfbNewFramebuffer(screen, NULL, width, height, - bits_per_color, 1, (int) fb->bits_per_pixel/8); - } - if (! screen) { - int i; - rfbLogEnable(1); - rfbLog("\n"); - rfbLog("failed to create rfb screen.\n"); - for (i=0; i< *argc; i++) { - rfbLog("\t[%d] %s\n", i, argv[i]); - } - clean_up_exit(1); - } - - if (create_screen && *argc != 1) { - int i; - rfbLogEnable(1); - rfbLog("*** unrecognized option(s) ***\n"); - for (i=1; i< *argc; i++) { - rfbLog("\t[%d] %s\n", i, argv[i]); - } - rfbLog("For a list of options run: x11vnc -opts\n"); - rfbLog("or for the full help: x11vnc -help\n"); - rfbLog("\n"); - rfbLog("Here is a list of removed or obsolete" - " options:\n"); - rfbLog("\n"); - rfbLog("removed: -hints, -nohints\n"); - rfbLog("removed: -cursorposall\n"); - rfbLog("\n"); - rfbLog("renamed: -old_copytile, use -onetile\n"); - rfbLog("renamed: -mouse, use -cursor\n"); - rfbLog("renamed: -mouseX, use -cursor X\n"); - rfbLog("renamed: -X, use -cursor X\n"); - rfbLog("renamed: -nomouse, use -nocursor\n"); - rfbLog("renamed: -old_pointer, use -pointer_mode 1\n"); - - clean_up_exit(1); - } - - /* set up format from scratch: */ - screen->paddedWidthInBytes = rfb_bytes_per_line; - screen->serverFormat.bitsPerPixel = fb->bits_per_pixel; - screen->serverFormat.depth = fb->depth; - screen->serverFormat.trueColour = TRUE; - - screen->serverFormat.redShift = 0; - screen->serverFormat.greenShift = 0; - screen->serverFormat.blueShift = 0; - screen->serverFormat.redMax = 0; - screen->serverFormat.greenMax = 0; - screen->serverFormat.blueMax = 0; - - /* these main_* formats are used generally. */ - main_red_shift = 0; - main_green_shift = 0; - main_blue_shift = 0; - main_red_max = 0; - main_green_max = 0; - main_blue_max = 0; - main_red_mask = fb->red_mask; - main_green_mask = fb->green_mask; - main_blue_mask = fb->blue_mask; - - - have_masks = ((fb->red_mask|fb->green_mask|fb->blue_mask) != 0); - if (force_indexed_color) { - have_masks = 0; - } - - if (! have_masks && screen->serverFormat.bitsPerPixel == 8 - && dpy && CellsOfScreen(ScreenOfDisplay(dpy, scr))) { - /* indexed color */ - if (!quiet) { - rfbLog("X display %s is 8bpp indexed color\n", - DisplayString(dpy)); - if (! flash_cmap && ! overlay) { - rfbLog("\n"); - rfbLog("In 8bpp PseudoColor mode if you " - "experience color\n"); - rfbLog("problems you may want to enable " - "following the\n"); - rfbLog("changing colormap by using the " - "-flashcmap option.\n"); - rfbLog("\n"); - } - } - screen->serverFormat.trueColour = FALSE; - indexed_color = 1; - set_colormap(1); - debug_colormap(fb); - } else { - /* - * general case, we call it truecolor, but could be direct - * color, static color, etc.... - */ - if (! quiet) { - if (raw_fb) { - rfbLog("Raw fb at addr %p is %dbpp depth=%d " - "true color\n", raw_fb_addr, - fb->bits_per_pixel, fb->depth); - } else { - rfbLog("X display %s is %dbpp depth=%d true " - "color\n", DisplayString(dpy), - fb->bits_per_pixel, fb->depth); - } - } - - indexed_color = 0; - - /* convert masks to bit shifts and max # colors */ - if (fb->red_mask) { - while (! (fb->red_mask - & (1 << screen->serverFormat.redShift))) { - screen->serverFormat.redShift++; - } - } - if (fb->green_mask) { - while (! (fb->green_mask - & (1 << screen->serverFormat.greenShift))) { - screen->serverFormat.greenShift++; - } - } - if (fb->blue_mask) { - while (! (fb->blue_mask - & (1 << screen->serverFormat.blueShift))) { - screen->serverFormat.blueShift++; - } - } - screen->serverFormat.redMax - = fb->red_mask >> screen->serverFormat.redShift; - screen->serverFormat.greenMax - = fb->green_mask >> screen->serverFormat.greenShift; - screen->serverFormat.blueMax - = fb->blue_mask >> screen->serverFormat.blueShift; - - main_red_max = screen->serverFormat.redMax; - main_green_max = screen->serverFormat.greenMax; - main_blue_max = screen->serverFormat.blueMax; - - main_red_shift = screen->serverFormat.redShift; - main_green_shift = screen->serverFormat.greenShift; - main_blue_shift = screen->serverFormat.blueShift; - } - -#if !SMALL_FOOTPRINT - if (!quiet) { - fprintf(stderr, "\n"); - fprintf(stderr, "FrameBuffer Info:\n"); - fprintf(stderr, " width: %d\n", fb->width); - fprintf(stderr, " height: %d\n", fb->height); - fprintf(stderr, " scaled_width: %d\n", width); - fprintf(stderr, " scaled_height: %d\n", height); - fprintf(stderr, " indexed_color: %d\n", indexed_color); - fprintf(stderr, " bits_per_pixel: %d\n", fb->bits_per_pixel); - fprintf(stderr, " depth: %d\n", fb->depth); - fprintf(stderr, " red_mask: 0x%08lx %s\n", fb->red_mask, - bitprint(fb->red_mask, 32)); - fprintf(stderr, " green_mask: 0x%08lx %s\n", fb->green_mask, - bitprint(fb->green_mask, 32)); - fprintf(stderr, " blue_mask: 0x%08lx %s\n", fb->blue_mask, - bitprint(fb->blue_mask, 32)); - fprintf(stderr, " red: max: %3d shift: %2d\n", - main_red_max, main_red_shift); - fprintf(stderr, " green: max: %3d shift: %2d\n", - main_green_max, main_green_shift); - fprintf(stderr, " blue: max: %3d shift: %2d\n", - main_blue_max, main_blue_shift); - fprintf(stderr, " mainfb_bytes_per_line: %d\n", - main_bytes_per_line); - fprintf(stderr, " rfb_fb_bytes_per_line: %d\n", - rfb_bytes_per_line); - switch(fb->format) { - case XYBitmap: - fprintf(stderr, " format: XYBitmap\n"); break; - case XYPixmap: - fprintf(stderr, " format: XYPixmap\n"); break; - case ZPixmap: - fprintf(stderr, " format: ZPixmap\n"); break; - default: - fprintf(stderr, " format: %d\n", fb->format); break; - } - switch(fb->byte_order) { - case LSBFirst: - fprintf(stderr, " byte_order: LSBFirst\n"); break; - case MSBFirst: - fprintf(stderr, " byte_order: MSBFirst\n"); break; - default: - fprintf(stderr, " byte_order: %d\n", fb->byte_order); - break; - } - fprintf(stderr, " bitmap_pad: %d\n", fb->bitmap_pad); - fprintf(stderr, " bitmap_unit: %d\n", fb->bitmap_unit); - switch(fb->bitmap_bit_order) { - case LSBFirst: - fprintf(stderr, " bitmap_bit_order: LSBFirst\n"); break; - case MSBFirst: - fprintf(stderr, " bitmap_bit_order: MSBFirst\n"); break; - default: - fprintf(stderr, " bitmap_bit_order: %d\n", - fb->bitmap_bit_order); break; - } - } - if (overlay && ! quiet) { - rfbLog("\n"); - rfbLog("Overlay mode enabled: If you experience color\n"); - rfbLog("problems when popup menus are on the screen, try\n"); - rfbLog("disabling SaveUnders in your X server, one way is\n"); - rfbLog("to start the X server with the '-su' option, e.g.:\n"); - rfbLog("Xsun -su ... see Xserver(1), xinit(1) for more info.\n"); - rfbLog("\n"); - } -#endif - /* nofb is for pointer/keyboard only handling. */ - if (nofb) { - main_fb = NULL; - rfb_fb = main_fb; - screen->displayHook = nofb_hook; - } else { - main_fb = fb->data; - if (scaling) { - rfb_fb = (char *) malloc(rfb_bytes_per_line * height); - memset(rfb_fb, 0, rfb_bytes_per_line * height); - } else { - rfb_fb = main_fb; - } - } - screen->frameBuffer = rfb_fb; - if (!quiet) { - fprintf(stderr, " main_fb: %p\n", main_fb); - fprintf(stderr, " rfb_fb: %p\n", rfb_fb); - fprintf(stderr, "\n"); - } - - bpp = screen->serverFormat.bitsPerPixel; - depth = screen->serverFormat.depth; - - /* may need, bpp, main_red_max, etc. */ - parse_wireframe(); - parse_scroll_copyrect(); - - setup_cursors_and_push(); - - if (scaling) { - mark_rect_as_modified(0, 0, dpy_x, dpy_y, 0); - } - - if (! create_screen) { - rfbClientIteratorPtr iter; - rfbClientPtr cl; - - /* - * since bits_per_color above may have been approximate, - * try to reset the individual translation tables... - * we do not seem to need this with rfbGetScreen()... - */ - if (!quiet) rfbLog("calling setTranslateFunction()...\n"); - iter = rfbGetClientIterator(screen); - while ((cl = rfbClientIteratorNext(iter)) != NULL) { - screen->setTranslateFunction(cl); - } - rfbReleaseClientIterator(iter); - if (!quiet) rfbLog(" done.\n"); - do_copy_screen = 1; - - /* done for framebuffer change case */ - return; - } - - /* - * the rest is screen server initialization, etc, only needed - * at screen creation time. - */ - - /* called from inetd, we need to treat stdio as our socket */ - if (inetd) { - int fd = dup(0); - if (fd < 0) { - rfbLogEnable(1); - rfbErr("dup(0) = %d failed.\n", fd); - rfbLogPerror("dup"); - clean_up_exit(1); - } - fclose(stdin); - fclose(stdout); - /* we keep stderr for logging */ - screen->inetdSock = fd; - screen->port = 0; - - } else if (! got_rfbport) { - screen->autoPort = TRUE; - } - - if (! got_nevershared && ! got_alwaysshared) { - if (shared) { - screen->alwaysShared = TRUE; - } else { - screen->neverShared = TRUE; - } - screen->dontDisconnect = TRUE; - } - if (! got_deferupdate) { - screen->deferUpdateTime = defer_update; - } - - /* event callbacks: */ - screen->newClientHook = new_client; - screen->kbdAddEvent = keyboard; - screen->ptrAddEvent = pointer; - screen->setXCutText = xcut_receive; - - rfbInitServer(screen); - - 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; - } -} - -/* -- solid.c -- */ - -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); -} - -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; -} - -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); -} - -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); -} - -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); -} - -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); -} - -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() { - 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; -} - -/* -- xinerama.c -- */ -/* - * routines related to xinerama and blacking out rectangles - */ - -/* blacked-out region (-blackout, -xinerama) */ -#define BO_MAX 32 -typedef struct tbout { - blackout_t bo[BO_MAX]; /* hardwired max rectangles. */ - int cover; - int count; -} tile_blackout_t; - -#define BLACKR_MAX 100 -blackout_t blackr[BLACKR_MAX]; /* hardwired max blackouts */ -tile_blackout_t *tile_blackout; -int blackouts = 0; - -/* - * Take a comma separated list of geometries: WxH+X+Y and register them as - * rectangles to black out from the screen. - */ -void initialize_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. - */ -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); - } - } - } -} - -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; - } -} - -/* -- scan.c -- */ -/* - * routines for scanning and reading the X11 display for changes, and - * for doing all the tile work (shm, etc). - */ - -/* array to hold the hints: */ -static hint_t *hint_list; - -/* nap state */ -static int nap_ok = 0, nap_diff_count = 0; - -static int scan_count = 0; /* indicates which scan pattern we are on */ -static int scan_in_progress = 0; - -typedef struct tile_change_region { - /* start and end lines, along y, of the changed area inside a tile. */ - unsigned short first_line, last_line; - short first_x, last_x; - /* info about differences along edges. */ - unsigned short left_diff, right_diff; - unsigned short top_diff, bot_diff; -} region_t; - -/* array to hold the tiles region_t-s. */ -static region_t *tile_region; - - -/* - * setup tile numbers and allocate the tile and hint arrays: - */ -void initialize_tiles(void) { - - ntiles_x = (dpy_x - 1)/tile_x + 1; - ntiles_y = (dpy_y - 1)/tile_y + 1; - ntiles = ntiles_x * ntiles_y; - - tile_has_diff = (unsigned char *) - malloc((size_t) (ntiles * sizeof(unsigned char))); - tile_has_xdamage_diff = (unsigned char *) - malloc((size_t) (ntiles * sizeof(unsigned char))); - tile_row_has_xdamage_diff = (unsigned char *) - malloc((size_t) (ntiles_y * sizeof(unsigned char))); - tile_tried = (unsigned char *) - malloc((size_t) (ntiles * sizeof(unsigned char))); - tile_copied = (unsigned char *) - malloc((size_t) (ntiles * sizeof(unsigned char))); - tile_blackout = (tile_blackout_t *) - malloc((size_t) (ntiles * sizeof(tile_blackout_t))); - tile_region = (region_t *) malloc((size_t) (ntiles * sizeof(region_t))); - - tile_row = (XImage **) - malloc((size_t) ((ntiles_x + 1) * sizeof(XImage *))); - tile_row_shm = (XShmSegmentInfo *) - malloc((size_t) ((ntiles_x + 1) * sizeof(XShmSegmentInfo))); - - /* there will never be more hints than tiles: */ - hint_list = (hint_t *) malloc((size_t) (ntiles * sizeof(hint_t))); -} - -void free_tiles(void) { - if (tile_has_diff) { - free(tile_has_diff); - tile_has_diff = NULL; - } - if (tile_has_xdamage_diff) { - free(tile_has_xdamage_diff); - tile_has_xdamage_diff = NULL; - } - if (tile_row_has_xdamage_diff) { - free(tile_row_has_xdamage_diff); - tile_row_has_xdamage_diff = NULL; - } - if (tile_tried) { - free(tile_tried); - tile_tried = NULL; - } - if (tile_copied) { - free(tile_copied); - tile_copied = NULL; - } - if (tile_blackout) { - free(tile_blackout); - tile_blackout = NULL; - } - if (tile_region) { - free(tile_region); - tile_region = NULL; - } - if (tile_row) { - free(tile_row); - tile_row = NULL; - } - if (tile_row_shm) { - free(tile_row_shm); - tile_row_shm = NULL; - } - if (hint_list) { - free(hint_list); - hint_list = NULL; - } -} - -/* - * silly function to factor dpy_y until fullscreen shm is not bigger than max. - * should always work unless dpy_y is a large prime or something... under - * failure fs_factor remains 0 and no fullscreen updates will be tried. - */ -static int fs_factor = 0; - -static void set_fs_factor(int max) { - int f, fac = 1, n = dpy_y; - - fs_factor = 0; - if ((bpp/8) * dpy_x * dpy_y <= max) { - fs_factor = 1; - return; - } - for (f=2; f <= 101; f++) { - while (n % f == 0) { - n = n / f; - fac = fac * f; - if ( (bpp/8) * dpy_x * (dpy_y/fac) <= max ) { - fs_factor = fac; - return; - } - } - } -} - -char *flip_ximage_byte_order(XImage *xim) { - char *order; - if (xim->byte_order == LSBFirst) { - order = "MSBFirst"; - xim->byte_order = MSBFirst; - xim->bitmap_bit_order = MSBFirst; - } else { - order = "LSBFirst"; - xim->byte_order = LSBFirst; - xim->bitmap_bit_order = LSBFirst; - } - return order; -} - -/* - * set up an XShm image, or if not using shm just create the XImage. - */ -static int shm_create(XShmSegmentInfo *shm, XImage **ximg_ptr, int w, int h, - char *name) { - - XImage *xim; - static int reported_flip = 0; - - shm->shmid = -1; - shm->shmaddr = (char *) -1; - *ximg_ptr = NULL; - - if (nofb) { - return 1; - } - - X_LOCK; - - if (! using_shm) { - /* we only need the XImage created */ - xim = XCreateImage_wr(dpy, default_visual, depth, ZPixmap, - 0, NULL, w, h, raw_fb ? 32 : BitmapPad(dpy), 0); - - X_UNLOCK; - - if (xim == NULL) { - rfbErr("XCreateImage(%s) failed.\n", name); - if (quiet) { - fprintf(stderr, "XCreateImage(%s) failed.\n", - name); - } - return 0; - } - xim->data = (char *) malloc(xim->bytes_per_line * xim->height); - if (xim->data == NULL) { - rfbErr("XCreateImage(%s) data malloc failed.\n", name); - if (quiet) { - fprintf(stderr, "XCreateImage(%s) data malloc" - " failed.\n", name); - } - return 0; - } - if (flip_byte_order) { - char *order = flip_ximage_byte_order(xim); - if (! reported_flip && ! quiet) { - rfbLog("Changing XImage byte order" - " to %s\n", order); - reported_flip = 1; - } - } - - *ximg_ptr = xim; - return 1; - } - - xim = XShmCreateImage_wr(dpy, default_visual, depth, ZPixmap, NULL, - shm, w, h); - - if (xim == NULL) { - rfbErr("XShmCreateImage(%s) failed.\n", name); - if (quiet) { - fprintf(stderr, "XShmCreateImage(%s) failed.\n", name); - } - X_UNLOCK; - return 0; - } - - *ximg_ptr = xim; - -#if LIBVNCSERVER_HAVE_XSHM - shm->shmid = shmget(IPC_PRIVATE, - xim->bytes_per_line * xim->height, IPC_CREAT | 0777); - - if (shm->shmid == -1) { - rfbErr("shmget(%s) failed.\n", name); - rfbLogPerror("shmget"); - - XDestroyImage(xim); - *ximg_ptr = NULL; - - X_UNLOCK; - return 0; - } - - shm->shmaddr = xim->data = (char *) shmat(shm->shmid, 0, 0); - - if (shm->shmaddr == (char *)-1) { - rfbErr("shmat(%s) failed.\n", name); - rfbLogPerror("shmat"); - - XDestroyImage(xim); - *ximg_ptr = NULL; - - shmctl(shm->shmid, IPC_RMID, 0); - shm->shmid = -1; - - X_UNLOCK; - return 0; - } - - shm->readOnly = False; - - if (! XShmAttach_wr(dpy, shm)) { - rfbErr("XShmAttach(%s) failed.\n", name); - XDestroyImage(xim); - *ximg_ptr = NULL; - - shmdt(shm->shmaddr); - shm->shmaddr = (char *) -1; - - shmctl(shm->shmid, IPC_RMID, 0); - shm->shmid = -1; - - X_UNLOCK; - return 0; - } -#endif - - X_UNLOCK; - return 1; -} - -void shm_delete(XShmSegmentInfo *shm) { -#if LIBVNCSERVER_HAVE_XSHM - if (shm != NULL && shm->shmaddr != (char *) -1) { - shmdt(shm->shmaddr); - } - if (shm != NULL && shm->shmid != -1) { - shmctl(shm->shmid, IPC_RMID, 0); - } -#endif -} - -void shm_clean(XShmSegmentInfo *shm, XImage *xim) { - - X_LOCK; -#if LIBVNCSERVER_HAVE_XSHM - if (shm != NULL && shm->shmid != -1 && dpy) { /* raw_fb hack */ - XShmDetach_wr(dpy, shm); - } -#endif - if (xim != NULL) { - XDestroyImage(xim); - xim = NULL; - } - X_UNLOCK; - - shm_delete(shm); -} - -void initialize_polling_images(void) { - int i, MB = 1024 * 1024; - - /* set all shm areas to "none" before trying to create any */ - scanline_shm.shmid = -1; - scanline_shm.shmaddr = (char *) -1; - scanline = NULL; - fullscreen_shm.shmid = -1; - fullscreen_shm.shmaddr = (char *) -1; - fullscreen = NULL; - snaprect_shm.shmid = -1; - snaprect_shm.shmaddr = (char *) -1; - snaprect = NULL; - for (i=1; i<=ntiles_x; i++) { - tile_row_shm[i].shmid = -1; - tile_row_shm[i].shmaddr = (char *) -1; - tile_row[i] = NULL; - } - - /* the scanline (e.g. 1280x1) shared memory area image: */ - - if (! shm_create(&scanline_shm, &scanline, dpy_x, 1, "scanline")) { - clean_up_exit(1); - } - - /* - * the fullscreen (e.g. 1280x1024/fs_factor) shared memory area image: - * (we cut down the size of the shm area to try avoid and shm segment - * limits, e.g. the default 1MB on Solaris) - */ - if (UT.sysname && strstr(UT.sysname, "Linux")) { - set_fs_factor(10 * MB); - } else { - set_fs_factor(1 * MB); - } - if (fs_frac >= 1.0) { - fs_frac = 1.1; - fs_factor = 0; - } - if (! fs_factor) { - rfbLog("warning: fullscreen updates are disabled.\n"); - } else { - if (! shm_create(&fullscreen_shm, &fullscreen, dpy_x, - dpy_y/fs_factor, "fullscreen")) { - clean_up_exit(1); - } - } - if (use_snapfb) { - if (! fs_factor) { - rfbLog("warning: disabling -snapfb mode.\n"); - use_snapfb = 0; - } else if (! shm_create(&snaprect_shm, &snaprect, dpy_x, - dpy_y/fs_factor, "snaprect")) { - clean_up_exit(1); - } - } - - /* - * for copy_tiles we need a lot of shared memory areas, one for - * each possible run length of changed tiles. 32 for 1024x768 - * and 40 for 1280x1024, etc. - */ - - tile_shm_count = 0; - for (i=1; i<=ntiles_x; i++) { - if (! shm_create(&tile_row_shm[i], &tile_row[i], tile_x * i, - tile_y, "tile_row")) { - if (i == 1) { - clean_up_exit(1); - } - rfbLog("shm: Error creating shared memory tile-row for" - " len=%d,\n", i); - rfbLog("shm: reverting to -onetile mode. If this" - " problem persists\n"); - rfbLog("shm: try using the -onetile or -noshm options" - " to limit\n"); - rfbLog("shm: shared memory usage, or run ipcrm(1)" - " to manually\n"); - rfbLog("shm: delete unattached shm segments.\n"); - single_copytile_count = i; - single_copytile = 1; - } - tile_shm_count++; - if (single_copytile && i >= 1) { - /* only need 1x1 tiles */ - break; - } - } - if (!quiet) { - if (using_shm) { - rfbLog("created %d tile_row shm polling images.\n", - tile_shm_count); - } else { - rfbLog("created %d tile_row polling images.\n", - tile_shm_count); - } - } -} - -/* - * A hint is a rectangular region built from 1 or more adjacent tiles - * glued together. Ultimately, this information in a single hint is sent - * to libvncserver rather than sending each tile separately. - */ -static void create_tile_hint(int x, int y, int tw, int th, hint_t *hint) { - int w = dpy_x - x; - int h = dpy_y - y; - - if (w > tw) { - w = tw; - } - if (h > th) { - h = th; - } - - hint->x = x; - hint->y = y; - hint->w = w; - hint->h = h; -} - -static void extend_tile_hint(int x, int y, int tw, int th, hint_t *hint) { - int w = dpy_x - x; - int h = dpy_y - y; - - if (w > tw) { - w = tw; - } - if (h > th) { - h = th; - } - - if (hint->x > x) { /* extend to the left */ - hint->w += hint->x - x; - hint->x = x; - } - if (hint->y > y) { /* extend upward */ - hint->h += hint->y - y; - hint->y = y; - } - - if (hint->x + hint->w < x + w) { /* extend to the right */ - hint->w = x + w - hint->x; - } - if (hint->y + hint->h < y + h) { /* extend downward */ - hint->h = y + h - hint->y; - } -} - -static void save_hint(hint_t hint, int loc) { - /* simply copy it to the global array for later use. */ - hint_list[loc].x = hint.x; - hint_list[loc].y = hint.y; - hint_list[loc].w = hint.w; - hint_list[loc].h = hint.h; -} - -/* - * Glue together horizontal "runs" of adjacent changed tiles into one big - * rectangle change "hint" to be passed to the vnc machinery. - */ -static void hint_updates(void) { - hint_t hint; - int x, y, i, n, ty, th, tx, tw; - int hint_count = 0, in_run = 0; - - for (y=0; y < ntiles_y; y++) { - for (x=0; x < ntiles_x; x++) { - n = x + y * ntiles_x; - - if (tile_has_diff[n]) { - ty = tile_region[n].first_line; - th = tile_region[n].last_line - ty + 1; - - tx = tile_region[n].first_x; - tw = tile_region[n].last_x - tx + 1; - if (tx < 0) { - tx = 0; - tw = tile_x; - } - - if (! in_run) { - create_tile_hint( x * tile_x + tx, - y * tile_y + ty, tw, th, &hint); - in_run = 1; - } else { - extend_tile_hint( x * tile_x + tx, - y * tile_y + ty, tw, th, &hint); - } - } else { - if (in_run) { - /* end of a row run of altered tiles: */ - save_hint(hint, hint_count++); - in_run = 0; - } - } - } - if (in_run) { /* save the last row run */ - save_hint(hint, hint_count++); - in_run = 0; - } - } - - for (i=0; i < hint_count; i++) { - /* pass update info to vnc: */ - mark_hint(hint_list[i]); - } -} - -/* - * kludge, simple ceil+floor for non-negative doubles: - */ -#define CEIL(x) ( (double) ((int) (x)) == (x) ? \ - (double) ((int) (x)) : (double) ((int) (x) + 1) ) -#define FLOOR(x) ( (double) ((int) (x)) ) - -/* - * Scaling: - * - * For shrinking, a destination (scaled) pixel will correspond to more - * than one source (i.e. main fb) pixel. Think of an x-y plane made with - * graph paper. Each unit square in the graph paper (i.e. collection of - * points (x,y) such that N < x < N+1 and M < y < M+1, N and M integers) - * corresponds to one pixel in the unscaled fb. There is a solid - * color filling the inside of such a square. A scaled pixel has width - * 1/scale_fac, e.g. for "-scale 3/4" the width of the scaled pixel - * is 1.333. The area of this scaled pixel is 1.333 * 1.333 (so it - * obviously overlaps more than one source pixel, each which have area 1). - * - * We take the weight an unscaled pixel (source) contributes to a - * scaled pixel (destination) as simply proportional to the overlap area - * between the two pixels. One can then think of the value of the scaled - * pixel as an integral over the portion of the graph paper it covers. - * The thing being integrated is the color value of the unscaled source. - * That color value is constant over a graph paper square (source pixel), - * and changes discontinuously from one unit square to the next. - * - -Here is an example for -scale 3/4, the solid lines are the source pixels -(graph paper unit squares), while the dotted lines denote the scaled -pixels (destination pixels): - - 0 1 4/3 2 8/3 3 4=12/3 - |---------|--.------|------.--|---------|. - | | . | . | |. - | A | . B | . | |. - | | . | . | |. - | | . | . | |. - 1 |---------|--.------|------.--|---------|. - 4/3|.........|.........|.........|.........|. - | | . | . | |. - | C | . D | . | |. - | | . | . | |. - 2 |---------|--.------|------.--|---------|. - | | . | . | |. - | | . | . | |. - 8/3|.........|.........|.........|.........|. - | | . | . | |. - 3 |---------|--.------|------.--|---------|. - -So we see the first scaled pixel (0 < x < 4/3 and 0 < y < 4/3) mostly -overlaps with unscaled source pixel "A". The integration (averaging) -weights for this scaled pixel are: - - A 1 - B 1/3 - C 1/3 - D 1/9 - - * - * The Red, Green, and Blue color values must be averaged over separately - * otherwise you can get a complete mess (except in solid regions), - * because high order bits are averaged differently from the low order bits. - * - * So the algorithm is roughly: - * - * - Given as input a rectangle in the unscaled source fb with changes, - * find the rectangle of pixels this affects in the scaled destination fb. - * - * - For each of the affected scaled (dest) pixels, determine all of the - * unscaled (source) pixels it overlaps with. - * - * - Average those unscaled source values together, weighted by the area - * overlap with the destination pixel. Average R, G, B separately. - * - * - Take this average value and convert to a valid pixel value if - * necessary (e.g. rounding, shifting), and then insert it into the - * destination framebuffer as the pixel value. - * - * - On to the next destination pixel... - * - * ======================================================================== - * - * For expanding, e.g. -scale 1.1 (which we don't think people will do - * very often... or at least so we hope, the framebuffer can become huge) - * the situation is reversed and the destination pixel is smaller than a - * "graph paper" unit square (source pixel). Some destination pixels - * will be completely within a single unscaled source pixel. - * - * What we do here is a simple 4 point interpolation scheme: - * - * Let P00 be the source pixel closest to the destination pixel but with - * x and y values less than or equal to those of the destination pixel. - * (for simplicity, think of the upper left corner of a pixel defining the - * x,y location of the pixel, the center would work just as well). So it - * is the source pixel immediately to the upper left of the destination - * pixel. Let P10 be the source pixel one to the right of P00. Let P01 - * be one down from P00. And let P11 be one down and one to the right - * of P00. They form a 2x2 square we will interpolate inside of. - * - * Let V00, V10, V01, and V11 be the color values of those 4 source - * pixels. Let dx be the displacement along x the destination pixel is - * from P00. Note: 0 <= dx < 1 by definition of P00. Similarly let - * dy be the displacement along y. The weighted average for the - * interpolation is: - * - * V_ave = V00 * (1 - dx) * (1 - dy) - * + V10 * dx * (1 - dy) - * + V01 * (1 - dx) * dy - * + V11 * dx * dy - * - * Note that the weights (1-dx)*(1-dy) + dx*(1-dy) + (1-dx)*dy + dx*dy - * automatically add up to 1. It is also nice that all the weights are - * positive (unsigned char stays unsigned char). The above formula can - * be motivated by doing two 1D interpolations along x: - * - * VA = V00 * (1 - dx) + V10 * dx - * VB = V01 * (1 - dx) + V11 * dx - * - * and then interpolating VA and VB along y: - * - * V_ave = VA * (1 - dy) + VB * dy - * - * VA - * v |<-dx->| - * -- V00 ------ V10 - * dy | | - * -- | o...|... "o" denotes the position of the desired - * ^ | . | . destination pixel relative to the P00 - * | . | . source pixel. - * V10 ----.- V11 . - * ........ - * | - * VB - * - * - * Of course R, G, B averages are done separately as in the shrinking - * case. This gives reasonable results, and the implementation for - * shrinking can simply be used with different choices for weights for - * the loop over the 4 pixels. - */ - -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) { -/* - * Notation: - * "i" an x pixel index in the destination (scaled) framebuffer - * "j" a y pixel index in the destination (scaled) framebuffer - * "I" an x pixel index in the source (un-scaled, i.e. main) framebuffer - * "J" a y pixel index in the source (un-scaled, i.e. main) framebuffer - * - * Similarly for nx, ny, Nx, Ny, etc. Lowercase: dest, Uppercase: source. - */ - int i, j, i1, i2, j1, j2; /* indices for scaled fb (dest) */ - int I, J, I1, I2, J1, J2; /* indices for main fb (source) */ - - double w, wx, wy, wtot; /* pixel weights */ - - double x1, y1, x2, y2; /* x-y coords for destination pixels edges */ - double dx, dy; /* size of destination pixel */ - double ddx, ddy; /* for interpolation expansion */ - - char *src, *dest; /* pointers to the two framebuffers */ - - - unsigned short us; - unsigned char uc; - unsigned int ui; - - int use_noblend_shortcut = 1; - int shrink; /* whether shrinking or expanding */ - static int constant_weights = -1, mag_int = -1; - static int last_Nx = -1, last_Ny = -1, cnt = 0; - static double last_factor = -1.0; - int b, k; - double pixave[4]; /* for averaging pixel values */ - - if (factor <= 1.0) { - shrink = 1; - } else { - shrink = 0; - } - - /* - * N.B. width and height (real numbers) of a scaled pixel. - * both are > 1 (e.g. 1.333 for -scale 3/4) - * they should also be equal but we don't assume it. - * - * This new way is probably the best we can do, take the inverse - * of the scaling factor to double precision. - */ - dx = 1.0/factor; - dy = 1.0/factor; - - /* - * There is some speedup if the pixel weights are constant, so - * let's special case these. - * - * If scale = 1/n and n divides Nx and Ny, the pixel weights - * are constant (e.g. 1/2 => equal on 2x2 square). - */ - if (factor != last_factor || Nx != last_Nx || Ny != last_Ny) { - constant_weights = -1; - mag_int = -1; - last_Nx = Nx; - last_Ny = Ny; - last_factor = factor; - } - - if (constant_weights < 0) { - int n = 0; - - constant_weights = 0; - mag_int = 0; - - for (i = 2; i<=128; i++) { - double test = ((double) 1)/ i; - double diff, eps = 1.0e-7; - diff = factor - test; - if (-eps < diff && diff < eps) { - n = i; - break; - } - } - if (! blend || ! shrink || interpolate) { - ; - } else if (n != 0) { - if (Nx % n == 0 && Ny % n == 0) { - static int didmsg = 0; - if (mark && ! didmsg) { - didmsg = 1; - rfbLog("scale_and_mark_rect: using " - "constant pixel weight speedup " - "for 1/%d\n", n); - } - constant_weights = 1; - } - } - - n = 0; - for (i = 2; i<=32; i++) { - double test = (double) i; - double diff, eps = 1.0e-7; - diff = factor - test; - if (-eps < diff && diff < eps) { - n = i; - break; - } - } - if (! blend && factor > 1.0 && n) { - mag_int = n; - } - } - - if (mark && factor > 1.0 && blend) { - /* - * kludge: correct for interpolating blurring leaking - * up or left 1 destination pixel. - */ - if (X1 > 0) X1--; - if (Y1 > 0) Y1--; - } - - /* - * find the extent of the change the input rectangle induces in - * the scaled framebuffer. - */ - - /* Left edges: find largest i such that i * dx <= X1 */ - i1 = FLOOR(X1/dx); - - /* Right edges: find smallest i such that (i+1) * dx >= X2+1 */ - i2 = CEIL( (X2+1)/dx ) - 1; - - /* To be safe, correct any overflows: */ - i1 = nfix(i1, nx); - i2 = nfix(i2, nx) + 1; /* add 1 to make a rectangle upper boundary */ - - /* Repeat above for y direction: */ - j1 = FLOOR(Y1/dy); - j2 = CEIL( (Y2+1)/dy ) - 1; - - j1 = nfix(j1, ny); - j2 = nfix(j2, ny) + 1; - - /* special case integer magnification with no blending */ - if (mark && ! blend && mag_int && Bpp != 3) { - int jmin, jmax, imin, imax; - - /* outer loop over *source* pixels */ - for (J=Y1; J < Y2; J++) { - jmin = J * mag_int; - jmax = jmin + mag_int; - for (I=X1; I < X2; I++) { - /* extract value */ - src = src_fb + J*src_bytes_per_line + I*Bpp; - if (Bpp == 4) { - ui = *((unsigned int *)src); - } else if (Bpp == 2) { - us = *((unsigned short *)src); - } else if (Bpp == 1) { - uc = *((unsigned char *)src); - } - imin = I * mag_int; - imax = imin + mag_int; - /* inner loop over *dest* pixels */ - for (j=jmin; j<jmax; j++) { - dest = dst_fb + j*dst_bytes_per_line + imin*Bpp; - for (i=imin; i<imax; i++) { - if (Bpp == 4) { - *((unsigned int *)dest) = ui; - } else if (Bpp == 2) { - *((unsigned short *)dest) = us; - } else if (Bpp == 1) { - *((unsigned char *)dest) = uc; - } - dest += Bpp; - } - } - } - } - goto markit; - } - - /* set these all to 1.0 to begin with */ - wx = 1.0; - wy = 1.0; - w = 1.0; - - /* - * Loop over destination pixels in scaled fb: - */ - for (j=j1; j<j2; j++) { - y1 = j * dy; /* top edge */ - if (y1 > Ny - 1) { - /* can go over with dy = 1/scale_fac */ - y1 = Ny - 1; - } - y2 = y1 + dy; /* bottom edge */ - - /* Find main fb indices covered by this dest pixel: */ - J1 = (int) FLOOR(y1); - J1 = nfix(J1, Ny); - - if (shrink && ! interpolate) { - J2 = (int) CEIL(y2) - 1; - J2 = nfix(J2, Ny); - } else { - J2 = J1 + 1; /* simple interpolation */ - ddy = y1 - J1; - } - - /* destination char* pointer: */ - dest = dst_fb + j*dst_bytes_per_line + i1*Bpp; - - for (i=i1; i<i2; i++) { - - x1 = i * dx; /* left edge */ - if (x1 > Nx - 1) { - /* can go over with dx = 1/scale_fac */ - x1 = Nx - 1; - } - x2 = x1 + dx; /* right edge */ - - cnt++; - - /* Find main fb indices covered by this dest pixel: */ - I1 = (int) FLOOR(x1); - if (I1 >= Nx) I1 = Nx - 1; - - if (! blend && use_noblend_shortcut) { - /* - * The noblend case involves no weights, - * and 1 pixel, so just copy the value - * directly. - */ - src = src_fb + J1*src_bytes_per_line + I1*Bpp; - if (Bpp == 4) { - *((unsigned int *)dest) - = *((unsigned int *)src); - } else if (Bpp == 2) { - *((unsigned short *)dest) - = *((unsigned short *)src); - } else if (Bpp == 1) { - *(dest) = *(src); - } else if (Bpp == 3) { - /* rare case */ - for (k=0; k<=2; k++) { - *(dest+k) = *(src+k); - } - } - dest += Bpp; - continue; - } - - if (shrink && ! interpolate) { - I2 = (int) CEIL(x2) - 1; - if (I2 >= Nx) I2 = Nx - 1; - } else { - I2 = I1 + 1; /* simple interpolation */ - ddx = x1 - I1; - } - - /* Zero out accumulators for next pixel average: */ - for (b=0; b<4; b++) { - pixave[b] = 0.0; /* for RGB weighted sums */ - } - - /* - * wtot is for accumulating the total weight. - * It should always sum to 1/(scale_fac * scale_fac). - */ - wtot = 0.0; - - /* - * Loop over source pixels covered by this dest pixel. - * - * These "extra" loops over "J" and "I" make - * the cache/cacheline performance unclear. - * For example, will the data brought in from - * src for j, i, and J=0 still be in the cache - * after the J > 0 data have been accessed and - * we are at j, i+1, J=0? The stride in J is - * main_bytes_per_line, and so ~4 KB. - * - * Typical case when shrinking are 2x2 loop, so - * just two lines to worry about. - */ - for (J=J1; J<=J2; J++) { - /* see comments for I, x1, x2, etc. below */ - if (constant_weights) { - ; - } else if (! blend) { - if (J != J1) { - continue; - } - wy = 1.0; - - /* interpolation scheme: */ - } else if (! shrink || interpolate) { - if (J >= Ny) { - continue; - } else if (J == J1) { - wy = 1.0 - ddy; - } else if (J != J1) { - wy = ddy; - } - - /* integration scheme: */ - } else if (J < y1) { - wy = J+1 - y1; - } else if (J+1 > y2) { - wy = y2 - J; - } else { - wy = 1.0; - } - - src = src_fb + J*src_bytes_per_line + I1*Bpp; - - for (I=I1; I<=I2; I++) { - - /* Work out the weight: */ - - if (constant_weights) { - ; - } else if (! blend) { - /* - * Ugh, PseudoColor colormap is - * bad news, to avoid random - * colors just take the first - * pixel. Or user may have - * specified :nb to fraction. - * The :fb will force blending - * for this case. - */ - if (I != I1) { - continue; - } - wx = 1.0; - - /* interpolation scheme: */ - } else if (! shrink || interpolate) { - if (I >= Nx) { - continue; /* off edge */ - } else if (I == I1) { - wx = 1.0 - ddx; - } else if (I != I1) { - wx = ddx; - } - - /* integration scheme: */ - } else if (I < x1) { - /* - * source left edge (I) to the - * left of dest left edge (x1): - * fractional weight - */ - wx = I+1 - x1; - } else if (I+1 > x2) { - /* - * source right edge (I+1) to the - * right of dest right edge (x2): - * fractional weight - */ - wx = x2 - I; - } else { - /* - * source edges (I and I+1) completely - * inside dest edges (x1 and x2): - * full weight - */ - wx = 1.0; - } - - w = wx * wy; - wtot += w; - - /* - * We average the unsigned char value - * instead of char value: otherwise - * the minimum (char 0) is right next - * to the maximum (char -1)! This way - * they are spread between 0 and 255. - */ - if (Bpp == 4) { - /* unroll the loops, can give 20% */ - pixave[0] += w * - ((unsigned char) *(src )); - pixave[1] += w * - ((unsigned char) *(src+1)); - pixave[2] += w * - ((unsigned char) *(src+2)); - pixave[3] += w * - ((unsigned char) *(src+3)); - } else if (Bpp == 2) { - /* - * 16bpp: trickier with green - * split over two bytes, so we - * use the masks: - */ - us = *((unsigned short *) src); - pixave[0] += w*(us & main_red_mask); - pixave[1] += w*(us & main_green_mask); - pixave[2] += w*(us & main_blue_mask); - } else if (Bpp == 1) { - pixave[0] += w * - ((unsigned char) *(src)); - } else { - for (b=0; b<Bpp; b++) { - pixave[b] += w * - ((unsigned char) *(src+b)); - } - } - src += Bpp; - } - } - - if (wtot <= 0.0) { - wtot = 1.0; - } - wtot = 1.0/wtot; /* normalization factor */ - - /* place weighted average pixel in the scaled fb: */ - if (Bpp == 4) { - *(dest ) = (char) (wtot * pixave[0]); - *(dest+1) = (char) (wtot * pixave[1]); - *(dest+2) = (char) (wtot * pixave[2]); - *(dest+3) = (char) (wtot * pixave[3]); - } else if (Bpp == 2) { - /* 16bpp / 565 case: */ - pixave[0] *= wtot; - pixave[1] *= wtot; - pixave[2] *= wtot; - us = (main_red_mask & (int) pixave[0]) - | (main_green_mask & (int) pixave[1]) - | (main_blue_mask & (int) pixave[2]); - *( (unsigned short *) dest ) = us; - } else if (Bpp == 1) { - *(dest) = (char) (wtot * pixave[0]); - } else { - for (b=0; b<Bpp; b++) { - *(dest+b) = (char) (wtot * pixave[b]); - } - } - dest += Bpp; - } - } - markit: - if (mark) { - mark_rect_as_modified(i1, j1, i2, j2, 1); - } -} - -static void scale_and_mark_rect(int X1, int Y1, int X2, int Y2) { - - if (!screen || !rfb_fb || !main_fb) { - return; - } - if (! screen->serverFormat.trueColour) { - /* - * PseudoColor colormap... blending leads to random colors. - * User can override with ":fb" - */ - if (scaling_blend == 1) { - /* :fb option sets it to 2 */ - if (default_visual->class == StaticGray) { - /* - * StaticGray can be blended OK, otherwise - * user can disable with :nb - */ - ; - } else { - scaling_blend = 0; - } - } - } - - scale_rect(scale_fac, scaling_blend, scaling_interpolate, bpp/8, - main_fb, main_bytes_per_line, rfb_fb, rfb_bytes_per_line, - dpy_x, dpy_y, scaled_x, scaled_y, X1, Y1, X2, Y2, 1); -} - -void mark_rect_as_modified(int x1, int y1, int x2, int y2, int force) { - - if (damage_time != 0) { - /* - * This is not XDAMAGE, rather a hack for testing - * where we allow the framebuffer to be corrupted for - * damage_delay seconds. - */ - int debug = 0; - if (time(0) > damage_time + damage_delay) { - if (! quiet) { - rfbLog("damaging turned off.\n"); - } - damage_time = 0; - damage_delay = 0; - } else { - if (debug) { - rfbLog("damaging viewer fb by not marking " - "rect: %d,%d,%d,%d\n", x1, y1, x2, y2); - } - return; - } - } - - if (rfb_fb == main_fb || force) { - rfbMarkRectAsModified(screen, x1, y1, x2, y2); - } else if (scaling) { - scale_and_mark_rect(x1, y1, x2, y2); - } -} - -/* - * Notifies libvncserver of a changed hint rectangle. - */ -void mark_hint(hint_t hint) { - int x = hint.x; - int y = hint.y; - int w = hint.w; - int h = hint.h; - - mark_rect_as_modified(x, y, x + w, y + h, 0); -} - -/* - * copy_tiles() gives a slight improvement over copy_tile() since - * adjacent runs of tiles are done all at once there is some savings - * due to contiguous memory access. Not a great speedup, but in some - * cases it can be up to 2X. Even more on a SunRay or ShadowFB where - * no graphics hardware is involved in the read. Generally, graphics - * devices are optimized for write, not read, so we are limited by the - * read bandwidth, sometimes only 5 MB/sec on otherwise fast hardware. - */ -static int *first_line = NULL, *last_line; -static unsigned short *left_diff, *right_diff; - -static int copy_tiles(int tx, int ty, int nt) { - int x, y, line; - int size_x, size_y, width1, width2; - int off, len, n, dw, dx, t; - int w1, w2, dx1, dx2; /* tmps for normal and short tiles */ - int pixelsize = bpp/8; - int first_min, last_max; - int first_x = -1, last_x = -1; - - char *src, *dst, *s_src, *s_dst, *m_src, *m_dst; - char *h_src, *h_dst; - if (! first_line) { - /* allocate arrays first time in. */ - int n = ntiles_x + 1; - first_line = (int *) malloc((size_t) (n * sizeof(int))); - last_line = (int *) malloc((size_t) (n * sizeof(int))); - left_diff = (unsigned short *) - malloc((size_t) (n * sizeof(unsigned short))); - right_diff = (unsigned short *) - malloc((size_t) (n * sizeof(unsigned short))); - } - - x = tx * tile_x; - y = ty * tile_y; - - size_x = dpy_x - x; - if ( size_x > tile_x * nt ) { - size_x = tile_x * nt; - width1 = tile_x; - width2 = tile_x; - } else { - /* short tile */ - width1 = tile_x; /* internal tile */ - width2 = size_x - (nt - 1) * tile_x; /* right hand tile */ - } - - size_y = dpy_y - y; - if ( size_y > tile_y ) { - size_y = tile_y; - } - - n = tx + ty * ntiles_x; /* number of the first tile */ - - if (blackouts && tile_blackout[n].cover == 2) { - /* - * If there are blackouts and this tile is completely covered - * no need to poll screen or do anything else.. - * n.b. we are in single copy_tile mode: nt=1 - */ - tile_has_diff[n] = 0; - return(0); - } - - X_LOCK; - XRANDR_SET_TRAP_RET(-1, "copy_tile-set"); - /* read in the whole tile run at once: */ - copy_image(tile_row[nt], x, y, size_x, size_y); - XRANDR_CHK_TRAP_RET(-1, "copy_tile-chk"); - - X_UNLOCK; - - if (blackouts && tile_blackout[n].cover == 1) { - /* - * If there are blackouts and this tile is partially covered - * we should re-black-out the portion. - * n.b. we are in single copy_tile mode: nt=1 - */ - int x1, x2, y1, y2, b; - int w, s, fill = 0; - - for (b=0; b < tile_blackout[n].count; b++) { - char *b_dst = tile_row[nt]->data; - - x1 = tile_blackout[n].bo[b].x1 - x; - y1 = tile_blackout[n].bo[b].y1 - y; - x2 = tile_blackout[n].bo[b].x2 - x; - y2 = tile_blackout[n].bo[b].y2 - y; - - w = (x2 - x1) * pixelsize; - s = x1 * pixelsize; - - for (line = 0; line < size_y; line++) { - if (y1 <= line && line < y2) { - memset(b_dst + s, fill, (size_t) w); - } - b_dst += tile_row[nt]->bytes_per_line; - } - } - } - - src = tile_row[nt]->data; - dst = main_fb + y * main_bytes_per_line + x * pixelsize; - - s_src = src; - s_dst = dst; - - for (t=1; t <= nt; t++) { - first_line[t] = -1; - } - - /* find the first line with difference: */ - w1 = width1 * pixelsize; - w2 = width2 * pixelsize; - - /* foreach line: */ - for (line = 0; line < size_y; line++) { - /* foreach horizontal tile: */ - for (t=1; t <= nt; t++) { - if (first_line[t] != -1) { - continue; - } - - off = (t-1) * w1; - if (t == nt) { - len = w2; /* possible short tile */ - } else { - len = w1; - } - - if (memcmp(s_dst + off, s_src + off, len)) { - first_line[t] = line; - } - } - s_src += tile_row[nt]->bytes_per_line; - s_dst += main_bytes_per_line; - } - - /* see if there were any differences for any tile: */ - first_min = -1; - for (t=1; t <= nt; t++) { - tile_tried[n+(t-1)] = 1; - if (first_line[t] != -1) { - if (first_min == -1 || first_line[t] < first_min) { - first_min = first_line[t]; - } - } - } - if (first_min == -1) { - /* no tile has a difference, note this and get out: */ - for (t=1; t <= nt; t++) { - tile_has_diff[n+(t-1)] = 0; - } - return(0); - } else { - /* - * at least one tile has a difference. make sure info - * is recorded (e.g. sometimes we guess tiles and they - * came in with tile_has_diff 0) - */ - for (t=1; t <= nt; t++) { - if (first_line[t] == -1) { - tile_has_diff[n+(t-1)] = 0; - } else { - tile_has_diff[n+(t-1)] = 1; - } - } - } - - m_src = src + (tile_row[nt]->bytes_per_line * size_y); - m_dst = dst + (main_bytes_per_line * size_y); - - for (t=1; t <= nt; t++) { - last_line[t] = first_line[t]; - } - - /* find the last line with difference: */ - w1 = width1 * pixelsize; - w2 = width2 * pixelsize; - - /* foreach line: */ - for (line = size_y - 1; line > first_min; line--) { - - m_src -= tile_row[nt]->bytes_per_line; - m_dst -= main_bytes_per_line; - - /* foreach tile: */ - for (t=1; t <= nt; t++) { - if (first_line[t] == -1 - || last_line[t] != first_line[t]) { - /* tile has no changes or already done */ - continue; - } - - off = (t-1) * w1; - if (t == nt) { - len = w2; /* possible short tile */ - } else { - len = w1; - } - if (memcmp(m_dst + off, m_src + off, len)) { - last_line[t] = line; - } - } - } - - /* - * determine the farthest down last changed line - * will be used below to limit our memcpy() to the framebuffer. - */ - last_max = -1; - for (t=1; t <= nt; t++) { - if (first_line[t] == -1) { - continue; - } - if (last_max == -1 || last_line[t] > last_max) { - last_max = last_line[t]; - } - } - - /* look for differences on left and right hand edges: */ - for (t=1; t <= nt; t++) { - left_diff[t] = 0; - right_diff[t] = 0; - } - - h_src = src; - h_dst = dst; - - w1 = width1 * pixelsize; - w2 = width2 * pixelsize; - - dx1 = (width1 - tile_fuzz) * pixelsize; - dx2 = (width2 - tile_fuzz) * pixelsize; - dw = tile_fuzz * pixelsize; - - /* foreach line: */ - for (line = 0; line < size_y; line++) { - /* foreach tile: */ - for (t=1; t <= nt; t++) { - if (first_line[t] == -1) { - /* tile has no changes at all */ - continue; - } - - off = (t-1) * w1; - if (t == nt) { - dx = dx2; /* possible short tile */ - if (dx <= 0) { - break; - } - } else { - dx = dx1; - } - - if (! left_diff[t] && memcmp(h_dst + off, - h_src + off, dw)) { - left_diff[t] = 1; - } - if (! right_diff[t] && memcmp(h_dst + off + dx, - h_src + off + dx, dw) ) { - right_diff[t] = 1; - } - } - h_src += tile_row[nt]->bytes_per_line; - h_dst += main_bytes_per_line; - } - - /* now finally copy the difference to the rfb framebuffer: */ - s_src = src + tile_row[nt]->bytes_per_line * first_min; - s_dst = dst + main_bytes_per_line * first_min; - - for (line = first_min; line <= last_max; line++) { - /* for I/O speed we do not do this tile by tile */ - memcpy(s_dst, s_src, size_x * pixelsize); - if (nt == 1) { - /* - * optimization for tall skinny lines, e.g. wm - * frame. try to find first_x and last_x to limit - * the size of the hint. could help for a slow - * link. Unfortunately we spent a lot of time - * reading in the many tiles. - * - * BTW, we like to think the above memcpy leaves - * the data we use below in the cache... (but - * it could be two 128 byte segments at 32bpp) - * so this inner loop is not as bad as it seems. - */ - int k, kx; - kx = pixelsize; - for (k=0; k<size_x; k++) { - if (memcmp(s_dst + k*kx, s_src + k*kx, kx)) { - if (first_x == -1 || k < first_x) { - first_x = k; - } - if (last_x == -1 || k > last_x) { - last_x = k; - } - } - } - } - s_src += tile_row[nt]->bytes_per_line; - s_dst += main_bytes_per_line; - } - - /* record all the info in the region array for this tile: */ - for (t=1; t <= nt; t++) { - int s = t - 1; - - if (first_line[t] == -1) { - /* tile unchanged */ - continue; - } - tile_region[n+s].first_line = first_line[t]; - tile_region[n+s].last_line = last_line[t]; - - tile_region[n+s].first_x = first_x; - tile_region[n+s].last_x = last_x; - - tile_region[n+s].top_diff = 0; - tile_region[n+s].bot_diff = 0; - if ( first_line[t] < tile_fuzz ) { - tile_region[n+s].top_diff = 1; - } - if ( last_line[t] > (size_y - 1) - tile_fuzz ) { - tile_region[n+s].bot_diff = 1; - } - - tile_region[n+s].left_diff = left_diff[t]; - tile_region[n+s].right_diff = right_diff[t]; - - tile_copied[n+s] = 1; - } - - return(1); -} - -/* - * The copy_tile() call in the loop below copies the changed tile into - * the rfb framebuffer. Note that copy_tile() sets the tile_region - * struct to have info about the y-range of the changed region and also - * whether the tile edges contain diffs (within distance tile_fuzz). - * - * We use this tile_region info to try to guess if the downward and right - * tiles will have diffs. These tiles will be checked later in the loop - * (since y+1 > y and x+1 > x). - * - * See copy_tiles_backward_pass() for analogous checking upward and - * left tiles. - */ -static int copy_all_tiles(void) { - int x, y, n, m; - int diffs = 0, ct; - - for (y=0; y < ntiles_y; y++) { - for (x=0; x < ntiles_x; x++) { - n = x + y * ntiles_x; - - if (tile_has_diff[n]) { - ct = copy_tiles(x, y, 1); - if (ct < 0) return ct; /* fatal */ - } - if (! tile_has_diff[n]) { - /* - * n.b. copy_tiles() may have detected - * no change and reset tile_has_diff to 0. - */ - continue; - } - diffs++; - - /* neighboring tile downward: */ - if ( (y+1) < ntiles_y && tile_region[n].bot_diff) { - m = x + (y+1) * ntiles_x; - if (! tile_has_diff[m]) { - tile_has_diff[m] = 2; - } - } - /* neighboring tile to right: */ - if ( (x+1) < ntiles_x && tile_region[n].right_diff) { - m = (x+1) + y * ntiles_x; - if (! tile_has_diff[m]) { - tile_has_diff[m] = 2; - } - } - } - } - return diffs; -} - -/* - * Routine analogous to copy_all_tiles() above, but for horizontal runs - * of adjacent changed tiles. - */ -static int copy_all_tile_runs(void) { - int x, y, n, m, i; - int diffs = 0, ct; - int in_run = 0, run = 0; - int ntave = 0, ntcnt = 0; - - for (y=0; y < ntiles_y; y++) { - for (x=0; x < ntiles_x + 1; x++) { - n = x + y * ntiles_x; - - if (x != ntiles_x && tile_has_diff[n]) { - in_run = 1; - run++; - } else { - if (! in_run) { - in_run = 0; - run = 0; - continue; - } - ct = copy_tiles(x - run, y, run); - if (ct < 0) return ct; /* fatal */ - - ntcnt++; - ntave += run; - diffs += run; - - /* neighboring tile downward: */ - for (i=1; i <= run; i++) { - if ((y+1) < ntiles_y - && tile_region[n-i].bot_diff) { - m = (x-i) + (y+1) * ntiles_x; - if (! tile_has_diff[m]) { - tile_has_diff[m] = 2; - } - } - } - - /* neighboring tile to right: */ - if (((x-1)+1) < ntiles_x - && tile_region[n-1].right_diff) { - m = ((x-1)+1) + y * ntiles_x; - if (! tile_has_diff[m]) { - tile_has_diff[m] = 2; - } - - /* note that this starts a new run */ - in_run = 1; - run = 1; - } else { - in_run = 0; - run = 0; - } - } - } - /* - * Could some activity go here, to emulate threaded - * behavior by servicing some libvncserver tasks? - */ - } - return diffs; -} - -/* - * Here starts a bunch of heuristics to guess/detect changed tiles. - * They are: - * copy_tiles_backward_pass, fill_tile_gaps/gap_try, grow_islands/island_try - */ - -/* - * Try to predict whether the upward and/or leftward tile has been modified. - * copy_all_tiles() has already done downward and rightward tiles. - */ -static int copy_tiles_backward_pass(void) { - int x, y, n, m; - int diffs = 0, ct; - - for (y = ntiles_y - 1; y >= 0; y--) { - for (x = ntiles_x - 1; x >= 0; x--) { - n = x + y * ntiles_x; /* number of this tile */ - - if (! tile_has_diff[n]) { - continue; - } - - m = x + (y-1) * ntiles_x; /* neighboring tile upward */ - - if (y >= 1 && ! tile_has_diff[m] && tile_region[n].top_diff) { - if (! tile_tried[m]) { - tile_has_diff[m] = 2; - ct = copy_tiles(x, y-1, 1); - if (ct < 0) return ct; /* fatal */ - } - } - - m = (x-1) + y * ntiles_x; /* neighboring tile to left */ - - if (x >= 1 && ! tile_has_diff[m] && tile_region[n].left_diff) { - if (! tile_tried[m]) { - tile_has_diff[m] = 2; - ct = copy_tiles(x-1, y, 1); - if (ct < 0) return ct; /* fatal */ - } - } - } - } - for (n=0; n < ntiles; n++) { - if (tile_has_diff[n]) { - diffs++; - } - } - return diffs; -} - -static int copy_tiles_additional_pass(void) { - int x, y, n; - int diffs = 0, ct; - - for (y=0; y < ntiles_y; y++) { - for (x=0; x < ntiles_x; x++) { - n = x + y * ntiles_x; /* number of this tile */ - - if (! tile_has_diff[n]) { - continue; - } - if (tile_copied[n]) { - continue; - } - - ct = copy_tiles(x, y, 1); - if (ct < 0) return ct; /* fatal */ - } - } - for (n=0; n < ntiles; n++) { - if (tile_has_diff[n]) { - diffs++; - } - } - return diffs; -} - -static int gap_try(int x, int y, int *run, int *saw, int along_x) { - int n, m, i, xt, yt, ct; - - n = x + y * ntiles_x; - - if (! tile_has_diff[n]) { - if (*saw) { - (*run)++; /* extend the gap run. */ - } - return 0; - } - if (! *saw || *run == 0 || *run > gaps_fill) { - *run = 0; /* unacceptable run. */ - *saw = 1; - return 0; - } - - for (i=1; i <= *run; i++) { /* iterate thru the run. */ - if (along_x) { - xt = x - i; - yt = y; - } else { - xt = x; - yt = y - i; - } - - m = xt + yt * ntiles_x; - if (tile_tried[m]) { /* do not repeat tiles */ - continue; - } - - ct = copy_tiles(xt, yt, 1); - if (ct < 0) return ct; /* fatal */ - } - *run = 0; - *saw = 1; - return 1; -} - -/* - * Look for small gaps of unchanged tiles that may actually contain changes. - * E.g. when paging up and down in a web broswer or terminal there can - * be a distracting delayed filling in of such gaps. gaps_fill is the - * tweak parameter that sets the width of the gaps that are checked. - * - * BTW, grow_islands() is actually pretty successful at doing this too... - */ -static int fill_tile_gaps(void) { - int x, y, run, saw; - int n, diffs = 0, ct; - - /* horizontal: */ - for (y=0; y < ntiles_y; y++) { - run = 0; - saw = 0; - for (x=0; x < ntiles_x; x++) { - ct = gap_try(x, y, &run, &saw, 1); - if (ct < 0) return ct; /* fatal */ - } - } - - /* vertical: */ - for (x=0; x < ntiles_x; x++) { - run = 0; - saw = 0; - for (y=0; y < ntiles_y; y++) { - ct = gap_try(x, y, &run, &saw, 0); - if (ct < 0) return ct; /* fatal */ - } - } - - for (n=0; n < ntiles; n++) { - if (tile_has_diff[n]) { - diffs++; - } - } - return diffs; -} - -static int island_try(int x, int y, int u, int v, int *run) { - int n, m, ct; - - n = x + y * ntiles_x; - m = u + v * ntiles_x; - - if (tile_has_diff[n]) { - (*run)++; - } else { - *run = 0; - } - - if (tile_has_diff[n] && ! tile_has_diff[m]) { - /* found a discontinuity */ - - if (tile_tried[m]) { - return 0; - } else if (*run < grow_fill) { - return 0; - } - - ct = copy_tiles(u, v, 1); - if (ct < 0) return ct; /* fatal */ - } - return 1; -} - -/* - * Scan looking for discontinuities in tile_has_diff[]. Try to extend - * the boundary of the discontinuity (i.e. make the island larger). - * Vertical scans are skipped since they do not seem to yield much... - */ -static int grow_islands(void) { - int x, y, n, run; - int diffs = 0, ct; - - /* - * n.b. the way we scan here should keep an extension going, - * and so also fill in gaps effectively... - */ - - /* left to right: */ - for (y=0; y < ntiles_y; y++) { - run = 0; - for (x=0; x <= ntiles_x - 2; x++) { - ct = island_try(x, y, x+1, y, &run); - if (ct < 0) return ct; /* fatal */ - } - } - /* right to left: */ - for (y=0; y < ntiles_y; y++) { - run = 0; - for (x = ntiles_x - 1; x >= 1; x--) { - ct = island_try(x, y, x-1, y, &run); - if (ct < 0) return ct; /* fatal */ - } - } - for (n=0; n < ntiles; n++) { - if (tile_has_diff[n]) { - diffs++; - } - } - return diffs; -} - -/* - * Fill the framebuffer with zeros for each blackout region - */ -static void blackout_regions(void) { - int i; - for (i=0; i < blackouts; i++) { - zero_fb(blackr[i].x1, blackr[i].y1, blackr[i].x2, blackr[i].y2); - } -} - -/* - * copy the whole X screen to the rfb framebuffer. For a large enough - * number of changed tiles, this is faster than tiles scheme at retrieving - * the info from the X server. Bandwidth to client and compression time - * are other issues... use -fs 1.0 to disable. - */ -int copy_screen(void) { - int pixelsize = bpp/8; - char *fbp; - int i, y, block_size; - - if (! fs_factor) { - return 0; - } - - block_size = (dpy_x * (dpy_y/fs_factor) * pixelsize); - - if (! main_fb) { - return 0; - } - fbp = main_fb; - y = 0; - - X_LOCK; - - /* screen may be too big for 1 shm area, so broken into fs_factor */ - for (i=0; i < fs_factor; i++) { - XRANDR_SET_TRAP_RET(-1, "copy_screen-set"); - copy_image(fullscreen, 0, y, 0, 0); - XRANDR_CHK_TRAP_RET(-1, "copy_screen-chk"); - - memcpy(fbp, fullscreen->data, (size_t) block_size); - - y += dpy_y / fs_factor; - fbp += block_size; - } - - X_UNLOCK; - - if (blackouts) { - blackout_regions(); - } - - mark_rect_as_modified(0, 0, dpy_x, dpy_y, 0); - return 0; -} - -int copy_snap(void) { - int pixelsize = bpp/8; - char *fbp; - int i, y, block_size; - double dt; - static int first = 1; - - if (! fs_factor) { - return 0; - } - - block_size = (dpy_x * (dpy_y/fs_factor) * pixelsize); - - if (! snap_fb || ! snap || ! snaprect) { - return 0; - } - fbp = snap_fb; - y = 0; - - dtime0(&dt); - X_LOCK; - - /* screen may be too big for 1 shm area, so broken into fs_factor */ - for (i=0; i < fs_factor; i++) { - XRANDR_SET_TRAP_RET(-1, "copy_snap-set"); - copy_image(snaprect, 0, y, 0, 0); - XRANDR_CHK_TRAP_RET(-1, "copy_snap-chk"); - - memcpy(fbp, snaprect->data, (size_t) block_size); - - y += dpy_y / fs_factor; - fbp += block_size; - } - - X_UNLOCK; - dt = dtime(&dt); - if (first) { - rfbLog("copy_snap: time for -snapfb snapshot: %.3f sec\n", dt); - first = 0; - } - - return 0; -} - - -/* - * Utilities for managing the "naps" to cut down on amount of polling. - */ -static void nap_set(int tile_cnt) { - int nap_in = nap_ok; - time_t now = time(0); - - if (scan_count == 0) { - /* roll up check for all NSCAN scans */ - nap_ok = 0; - if (naptile && nap_diff_count < 2 * NSCAN * naptile) { - /* "2" is a fudge to permit a bit of bg drawing */ - nap_ok = 1; - } - nap_diff_count = 0; - } - if (nap_ok && ! nap_in && use_xdamage) { - if (XD_skip > 0.8 * XD_tot) { - /* X DAMAGE is keeping load low, so skip nap */ - nap_ok = 0; - } - } - if (! nap_ok && client_count) { - if(now > last_fb_bytes_sent + no_fbu_blank) { - if (debug_tiles > 1) { - printf("nap_set: nap_ok=1: now: %d last: %d\n", - (int) now, (int) last_fb_bytes_sent); - } - nap_ok = 1; - } - } - - if (show_cursor) { - /* kludge for the up to 4 tiles the mouse patch could occupy */ - if ( tile_cnt > 4) { - last_event = now; - } - } else if (tile_cnt != 0) { - last_event = now; - } -} - -/* - * split up a long nap to improve the wakeup time - */ -static void nap_sleep(int ms, int split) { - int i, input = got_user_input; - - for (i=0; i<split; i++) { - usleep(ms * 1000 / split); - if (! use_threads && i != split - 1) { - rfbPE(-1); - } - if (input != got_user_input) { - break; - } - } -} - -/* - * see if we should take a nap of some sort between polls - */ -static void nap_check(int tile_cnt) { - time_t now; - - nap_diff_count += tile_cnt; - - if (! take_naps) { - return; - } - - now = time(0); - - if (screen_blank > 0) { - int dt_ev, dt_fbu, ms = 2000; - - /* if no activity, pause here for a second or so. */ - dt_ev = (int) (now - last_event); - dt_fbu = (int) (now - last_fb_bytes_sent); - if (dt_fbu > screen_blank) { - /* sleep longer for no fb requests */ - nap_sleep(2 * ms, 16); - return; - } - if (dt_ev > screen_blank) { - nap_sleep(ms, 8); - return; - } - } - if (naptile && nap_ok && tile_cnt < naptile) { - int ms = napfac * waitms; - ms = ms > napmax ? napmax : ms; - if (now - last_input <= 2) { - nap_ok = 0; - } else { - nap_sleep(ms, 1); - } - } -} - -/* - * This is called to avoid a ~20 second timeout in libvncserver. - * May no longer be needed. - */ -static void ping_clients(int tile_cnt) { - static time_t last_send = 0; - time_t now = time(0); - - if (rfbMaxClientWait < 20000) { - rfbMaxClientWait = 20000; - rfbLog("reset rfbMaxClientWait to %d msec.\n", - rfbMaxClientWait); - } - if (tile_cnt) { - last_send = now; - } else if (now - last_send > 1) { - /* Send small heartbeat to client */ - mark_rect_as_modified(0, 0, 1, 1, 1); - last_send = now; - } -} - -/* - * scan_display() wants to know if this tile can be skipped due to - * blackout regions: (no data compare is done, just a quick geometric test) - */ -static int blackout_line_skip(int n, int x, int y, int rescan, - int *tile_count) { - - if (tile_blackout[n].cover == 2) { - tile_has_diff[n] = 0; - return 1; /* skip it */ - - } else if (tile_blackout[n].cover == 1) { - int w, x1, y1, x2, y2, b, hit = 0; - if (x + NSCAN > dpy_x) { - w = dpy_x - x; - } else { - w = NSCAN; - } - - for (b=0; b < tile_blackout[n].count; b++) { - - /* n.b. these coords are in full display space: */ - x1 = tile_blackout[n].bo[b].x1; - x2 = tile_blackout[n].bo[b].x2; - y1 = tile_blackout[n].bo[b].y1; - y2 = tile_blackout[n].bo[b].y2; - - if (x2 - x1 < w) { - /* need to cover full width */ - continue; - } - if (y1 <= y && y < y2) { - hit = 1; - break; - } - } - if (hit) { - if (! rescan) { - tile_has_diff[n] = 0; - } else { - *tile_count += tile_has_diff[n]; - } - return 1; /* skip */ - } - } - return 0; /* do not skip */ -} - -static int blackout_line_cmpskip(int n, int x, int y, char *dst, char *src, - int w, int pixelsize) { - - int i, x1, y1, x2, y2, b, hit = 0; - int beg = -1, end = -1; - - if (tile_blackout[n].cover == 0) { - return 0; /* 0 means do not skip it. */ - } else if (tile_blackout[n].cover == 2) { - return 1; /* 1 means skip it. */ - } - - /* tile has partial coverage: */ - - for (i=0; i < w * pixelsize; i++) { - if (*(dst+i) != *(src+i)) { - beg = i/pixelsize; /* beginning difference */ - break; - } - } - for (i = w * pixelsize - 1; i >= 0; i--) { - if (*(dst+i) != *(src+i)) { - end = i/pixelsize; /* ending difference */ - break; - } - } - if (beg < 0 || end < 0) { - /* problem finding range... */ - return 0; - } - - /* loop over blackout rectangles: */ - for (b=0; b < tile_blackout[n].count; b++) { - - /* y in full display space: */ - y1 = tile_blackout[n].bo[b].y1; - y2 = tile_blackout[n].bo[b].y2; - - /* x relative to tile origin: */ - x1 = tile_blackout[n].bo[b].x1 - x; - x2 = tile_blackout[n].bo[b].x2 - x; - - if (y1 > y || y >= y2) { - continue; - } - if (x1 <= beg && end <= x2) { - hit = 1; - break; - } - } - if (hit) { - return 1; - } else { - return 0; - } -} - -/* - * For the subwin case follows the window if it is moved. - */ -void set_offset(void) { - Window w; - if (! subwin) { - return; - } - X_LOCK; - xtranslate(window, rootwin, 0, 0, &off_x, &off_y, &w, 0); - X_UNLOCK; -} - -/* - * Loop over 1-pixel tall horizontal scanlines looking for changes. - * Record the changes in tile_has_diff[]. Scanlines in the loop are - * equally spaced along y by NSCAN pixels, but have a slightly random - * starting offset ystart ( < NSCAN ) from scanlines[]. - */ -static int scan_display(int ystart, int rescan) { - char *src, *dst; - int pixelsize = bpp/8; - int x, y, w, n; - int tile_count = 0; - int nodiffs = 0, diff_hint; - - y = ystart; - - if (! main_fb) { - rfbLog("scan_display: no main_fb!\n"); - return 0; - } - - while (y < dpy_y) { - - if (use_xdamage) { - XD_tot++; - if (xdamage_hint_skip(y)) { - XD_skip++; - y += NSCAN; - continue; - } - } - - /* grab the horizontal scanline from the display: */ - X_LOCK; - XRANDR_SET_TRAP_RET(-1, "scan_display-set"); - copy_image(scanline, 0, y, 0, 0); - XRANDR_CHK_TRAP_RET(-1, "scan_display-chk"); - X_UNLOCK; - - /* for better memory i/o try the whole line at once */ - src = scanline->data; - dst = main_fb + y * main_bytes_per_line; - - if (! memcmp(dst, src, main_bytes_per_line)) { - /* no changes anywhere in scan line */ - nodiffs = 1; - if (! rescan) { - y += NSCAN; - continue; - } - } - - x = 0; - while (x < dpy_x) { - n = (x/tile_x) + (y/tile_y) * ntiles_x; - diff_hint = 0; - - if (blackouts) { - if (blackout_line_skip(n, x, y, rescan, - &tile_count)) { - x += NSCAN; - continue; - } - } - - if (rescan) { - if (nodiffs || tile_has_diff[n]) { - tile_count += tile_has_diff[n]; - x += NSCAN; - continue; - } - } else if (xdamage_tile_count && - tile_has_xdamage_diff[n]) { - tile_has_xdamage_diff[n] = 2; - diff_hint = 1; - } - - /* set ptrs to correspond to the x offset: */ - src = scanline->data + x * pixelsize; - dst = main_fb + y * main_bytes_per_line + x * pixelsize; - - /* compute the width of data to be compared: */ - if (x + NSCAN > dpy_x) { - w = dpy_x - x; - } else { - w = NSCAN; - } - - if (diff_hint || memcmp(dst, src, w * pixelsize)) { - /* found a difference, record it: */ - if (! blackouts) { - tile_has_diff[n] = 1; - tile_count++; - } else { - if (blackout_line_cmpskip(n, x, y, - dst, src, w, pixelsize)) { - tile_has_diff[n] = 0; - } else { - tile_has_diff[n] = 1; - tile_count++; - } - } - } - x += NSCAN; - } - y += NSCAN; - } - return tile_count; -} - - -/* - * toplevel for the scanning, rescanning, and applying the heuristics. - * returns number of changed tiles. - */ -int scan_for_updates(int count_only) { - int i, tile_count, tile_diffs; - int old_copy_tile; - double frac1 = 0.1; /* tweak parameter to try a 2nd scan_display() */ - double frac2 = 0.35; /* or 3rd */ - double frac3 = 0.02; /* do scan_display() again after copy_tiles() */ - static double last_poll = 0.0; - - if (slow_fb > 0.0) { - double now = dnow(); - if (now < last_poll + slow_fb) { - return 0; - } - last_poll = now; - } - - for (i=0; i < ntiles; i++) { - tile_has_diff[i] = 0; - tile_has_xdamage_diff[i] = 0; - tile_tried[i] = 0; - tile_copied[i] = 0; - } - for (i=0; i < ntiles_y; i++) { - /* could be useful, currently not used */ - tile_row_has_xdamage_diff[i] = 0; - } - xdamage_tile_count = 0; - - /* - * n.b. this program has only been tested so far with - * tile_x = tile_y = NSCAN = 32! - */ - - if (!count_only) { - scan_count++; - scan_count %= NSCAN; - - /* some periodic maintenance */ - if (subwin) { - set_offset(); /* follow the subwindow */ - } - if (indexed_color && scan_count % 4 == 0) { - /* check for changed colormap */ - set_colormap(0); - } - if (use_xdamage) { - /* first pass collecting DAMAGE events: */ - collect_xdamage(scan_count, 0); - } - } - -#define SCAN_FATAL(x) \ - if (x < 0) { \ - scan_in_progress = 0; \ - fb_copy_in_progress = 0; \ - return 0; \ - } - - /* scan with the initial y to the jitter value from scanlines: */ - scan_in_progress = 1; - tile_count = scan_display(scanlines[scan_count], 0); - SCAN_FATAL(tile_count); - - /* - * we do the XDAMAGE here too since after scan_display() - * there is a better chance we have received the events from - * the X server (otherwise the DAMAGE events will be processed - * in the *next* call, usually too late and wasteful since - * the unchanged tiles are read in again). - */ - if (use_xdamage) { - collect_xdamage(scan_count, 1); - } - if (count_only) { - scan_in_progress = 0; - fb_copy_in_progress = 0; - return tile_count; - } - - if (xdamage_tile_count) { - /* pick up "known" damaged tiles we missed in scan_display() */ - for (i=0; i < ntiles; i++) { - if (tile_has_diff[i]) { - continue; - } - if (tile_has_xdamage_diff[i]) { - tile_has_diff[i] = 1; - if (tile_has_xdamage_diff[i] == 1) { - tile_has_xdamage_diff[i] = 2; - tile_count++; - } - } - } - } - - nap_set(tile_count); - - if (fs_factor && frac1 >= fs_frac) { - /* make frac1 < fs_frac if fullscreen updates are enabled */ - frac1 = fs_frac/2.0; - } - - if (tile_count > frac1 * ntiles) { - /* - * many tiles have changed, so try a rescan (since it should - * be short compared to the many upcoming copy_tiles() calls) - */ - - /* this check is done to skip the extra scan_display() call */ - if (! fs_factor || tile_count <= fs_frac * ntiles) { - int cp, tile_count_old = tile_count; - - /* choose a different y shift for the 2nd scan: */ - cp = (NSCAN - scan_count) % NSCAN; - - tile_count = scan_display(scanlines[cp], 1); - SCAN_FATAL(tile_count); - - if (tile_count >= (1 + frac2) * tile_count_old) { - /* on a roll... do a 3rd scan */ - cp = (NSCAN - scan_count + 7) % NSCAN; - tile_count = scan_display(scanlines[cp], 1); - SCAN_FATAL(tile_count); - } - } - scan_in_progress = 0; - - /* - * At some number of changed tiles it is better to just - * copy the full screen at once. I.e. time = c1 + m * r1 - * where m is number of tiles, r1 is the copy_tiles() - * time, and c1 is the scan_display() time: for some m - * it crosses the full screen update time. - * - * We try to predict that crossover with the fs_frac - * fudge factor... seems to be about 1/2 the total number - * of tiles. n.b. this ignores network bandwidth, - * compression time etc... - * - * Use -fs 1.0 to disable on slow links. - */ - if (fs_factor && tile_count > fs_frac * ntiles) { - int cs; - fb_copy_in_progress = 1; - cs = copy_screen(); - fb_copy_in_progress = 0; - SCAN_FATAL(cs); - if (use_threads && pointer_mode != 1) { - pointer(-1, 0, 0, NULL); - } - nap_check(tile_count); - return tile_count; - } - } - scan_in_progress = 0; - - /* copy all tiles with differences from display to rfb framebuffer: */ - fb_copy_in_progress = 1; - - if (single_copytile || tile_shm_count < ntiles_x) { - /* - * Old way, copy I/O one tile at a time. - */ - old_copy_tile = 1; - } else { - /* - * New way, does runs of horizontal tiles at once. - * Note that below, for simplicity, the extra tile finding - * (e.g. copy_tiles_backward_pass) is done the old way. - */ - old_copy_tile = 0; - } - if (old_copy_tile) { - tile_diffs = copy_all_tiles(); - } else { - tile_diffs = copy_all_tile_runs(); - } - SCAN_FATAL(tile_diffs); - - /* - * This backward pass for upward and left tiles complements what - * was done in copy_all_tiles() for downward and right tiles. - */ - tile_diffs = copy_tiles_backward_pass(); - SCAN_FATAL(tile_diffs); - - if (tile_diffs > frac3 * ntiles) { - /* - * we spent a lot of time in those copy_tiles, run - * another scan, maybe more of the screen changed. - */ - int cp = (NSCAN - scan_count + 13) % NSCAN; - - scan_in_progress = 1; - tile_count = scan_display(scanlines[cp], 1); - SCAN_FATAL(tile_count); - scan_in_progress = 0; - - tile_diffs = copy_tiles_additional_pass(); - SCAN_FATAL(tile_diffs); - } - - /* Given enough tile diffs, try the islands: */ - if (grow_fill && tile_diffs > 4) { - tile_diffs = grow_islands(); - } - SCAN_FATAL(tile_diffs); - - /* Given enough tile diffs, try the gaps: */ - if (gaps_fill && tile_diffs > 4) { - tile_diffs = fill_tile_gaps(); - } - SCAN_FATAL(tile_diffs); - - fb_copy_in_progress = 0; - if (use_threads && pointer_mode != 1) { - /* - * tell the pointer handler it can process any queued - * pointer events: - */ - pointer(-1, 0, 0, NULL); - } - - if (blackouts) { - /* ignore any diffs in completely covered tiles */ - int x, y, n; - for (y=0; y < ntiles_y; y++) { - for (x=0; x < ntiles_x; x++) { - n = x + y * ntiles_x; - if (tile_blackout[n].cover == 2) { - tile_has_diff[n] = 0; - } - } - } - } - - hint_updates(); /* use x0rfbserver hints algorithm */ - - /* Work around threaded rfbProcessClientMessage() calls timeouts */ - if (use_threads) { - ping_clients(tile_diffs); - } - - - nap_check(tile_diffs); - return tile_diffs; -} - -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; -} - -#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 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; -} - -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; - } -} - -/* -- gui.c -- */ -#ifdef NOGUI -char gui_code[] = ""; -#else -#include "tkx11vnc.h" -#endif - -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); - } -} - -/* -- userinput.c -- */ -/* - * user input handling heuristics - */ - -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; -} - -/* - * For -wireframe: find the direct child of rootwin that has the - * pointer, assume that is the WM frame that contains the application - * (i.e. wm reparents the app toplevel) return frame position and size - * if successful. - */ -int get_wm_frame_pos(int *px, int *py, int *x, int *y, int *w, int *h, - Window *frame, Window *win) { - Window r, c; - XWindowAttributes attr; - Bool ret; - int rootx, rooty, wx, wy; - unsigned int mask; - - ret = XQueryPointer(dpy, rootwin, &r, &c, &rootx, &rooty, &wx, &wy, - &mask); - - *frame = c; - - /* current pointer position is returned too */ - *px = rootx; - *py = rooty; - - if (!ret || ! c || c == rootwin) { - /* no immediate child */ - return 0; - } - - /* child window position and size */ - if (! valid_window(c, &attr, 1)) { - return 0; - } - - *x = attr.x; - *y = attr.y; - *w = attr.width; - *h = attr.height; - - if (win != NULL) { - *win = descend_pointer(5, c, NULL, 0); - } - - return 1; -} - -static int defer_update_nofb = 6; /* defer a shorter time under -nofb */ - -int scrollcopyrect_top, scrollcopyrect_bot; -int scrollcopyrect_left, scrollcopyrect_right; -double scr_key_time, scr_key_persist; -double scr_mouse_time, scr_mouse_persist, scr_mouse_maxtime; -double scr_mouse_pointer_delay; -double scr_key_bdpush_time, scr_mouse_bdpush_time; - -void parse_scroll_copyrect_str(char *scr) { - char *p, *str; - int i; - char *part[10]; - - for (i=0; i<10; i++) { - part[i] = NULL; - } - - if (scr == NULL || *scr == '\0') { - return; - } - - str = strdup(scr); - - p = strtok(str, ","); - i = 0; - while (p) { - part[i++] = strdup(p); - p = strtok(NULL, ","); - } - free(str); - - - /* - * Top, Bottom, Left, Right tolerances for scrollbar locations. - */ - if ((str = part[0]) != NULL) { - int t, b, l, r; - if (sscanf(str, "%d+%d+%d+%d", &t, &b, &l, &r) == 4) { - scrollcopyrect_top = t; - scrollcopyrect_bot = b; - scrollcopyrect_left = l; - scrollcopyrect_right = r; - } - free(str); - } - - /* key scrolling timing heuristics. */ - if ((str = part[1]) != NULL) { - double t1, t2, t3; - if (sscanf(str, "%lf+%lf+%lf", &t1, &t2, &t3) == 3) { - scr_key_time = t1; - scr_key_persist = t2; - scr_key_bdpush_time = t3; - } - free(str); - } - - /* mouse scrolling timing heuristics. */ - if ((str = part[2]) != NULL) { - double t1, t2, t3, t4, t5; - if (sscanf(str, "%lf+%lf+%lf+%lf+%lf", &t1, &t2, &t3, &t4, - &t5) == 5) { - scr_mouse_time = t1; - scr_mouse_persist = t2; - scr_mouse_bdpush_time = t3; - scr_mouse_pointer_delay = t4; - scr_mouse_maxtime = t5; - } - free(str); - } -} - -void parse_scroll_copyrect(void) { - parse_scroll_copyrect_str(SCROLL_COPYRECT_PARMS); - if (! scroll_copyrect_str) { - scroll_copyrect_str = strdup(SCROLL_COPYRECT_PARMS); - } - parse_scroll_copyrect_str(scroll_copyrect_str); -} - -void parse_fixscreen(void) { - char *str, *p; - - screen_fixup_V = 0.0; - screen_fixup_C = 0.0; - screen_fixup_X = 0.0; - - if (! screen_fixup_str) { - return; - } - - str = strdup(screen_fixup_str); - - p = strtok(str, ","); - while (p) { - double t; - if (*p == 'V' && sscanf(p, "V=%lf", &t) == 1) { - screen_fixup_V = t; - } else if (*p == 'C' && sscanf(p, "C=%lf", &t) == 1) { - screen_fixup_C = t; - } else if (*p == 'X' && sscanf(p, "X=%lf", &t) == 1) { - screen_fixup_X = t; - } - p = strtok(NULL, ","); - } - free(str); - - if (screen_fixup_V < 0.0) screen_fixup_V = 0.0; - if (screen_fixup_C < 0.0) screen_fixup_C = 0.0; - if (screen_fixup_X < 0.0) screen_fixup_X = 0.0; -} - -/* -WIREFRAME_PARMS "0xff,2,0,30+6+6+6,Alt,0.05+0.3+2.0,8" -shade,linewidth,percent,T+B+L+R,mods,t1+t2+t3+t4 - */ -#define LW_MAX 8 -unsigned long wireframe_shade; -int wireframe_lw; -double wireframe_frac; -int wireframe_top, wireframe_bot, wireframe_left, wireframe_right; -double wireframe_t1, wireframe_t2, wireframe_t3, wireframe_t4; -char *wireframe_mods = NULL; - -/* - * Parse the gory -wireframe string for parameters. - */ -void parse_wireframe_str(char *wf) { - char *p, *str; - int i; - char *part[10]; - - for (i=0; i<10; i++) { - part[i] = NULL; - } - - if (wf == NULL || *wf == '\0') { - return; - } - - str = strdup(wf); - - /* leading ",", make it start with ignorable string "z" */ - if (*str == ',') { - char *tmp = (char *) malloc(strlen(str)+2); - strcpy(tmp, "z"); - strcat(tmp, str); - free(str); - str = tmp; - } - - p = strtok(str, ","); - i = 0; - while (p) { - part[i++] = strdup(p); - p = strtok(NULL, ","); - } - free(str); - - - /* Wireframe shade, color, RGB: */ - if ((str = part[0]) != NULL) { - unsigned long n; - int r, g, b, ok = 0; - XColor cdef; - Colormap cmap; - if (dpy && (bpp == 32 || bpp == 16)) { - cmap = DefaultColormap (dpy, scr); - if (XParseColor(dpy, cmap, str, &cdef) && - XAllocColor(dpy, cmap, &cdef)) { - r = cdef.red >> 8; - g = cdef.green >> 8; - b = cdef.blue >> 8; - if (r == 0 && g == 0) { - g = 1; /* need to be > 255 */ - } - n = 0; - n |= (r << main_red_shift); - n |= (g << main_green_shift); - n |= (b << main_blue_shift); - wireframe_shade = n; - ok = 1; - } - } - if (ok) { - ; - } else if (sscanf(str, "0x%lx", &n) == 1) { - wireframe_shade = n; - } else if (sscanf(str, "%lu", &n) == 1) { - wireframe_shade = n; - } else if (sscanf(str, "%lx", &n) == 1) { - wireframe_shade = n; - } - free(str); - } - - /* linewidth: # of pixels wide for the wireframe lines */ - if ((str = part[1]) != NULL) { - int n; - if (sscanf(str, "%d", &n) == 1) { - wireframe_lw = n; - if (wireframe_lw < 1) { - wireframe_lw = 1; - } - if (wireframe_lw > LW_MAX) { - wireframe_lw = LW_MAX; - } - } - free(str); - } - - /* percentage cutoff for opaque move/resize (like WM's) */ - if ((str = part[2]) != NULL) { - if (*str == '\0') { - ; - } else if (strchr(str, '.')) { - wireframe_frac = atof(str); - } else { - wireframe_frac = ((double) atoi(str))/100.0; - } - free(str); - } - - /* - * Top, Bottom, Left, Right tolerances to guess the wm frame is - * being grabbed (Top is traditionally bigger, i.e. titlebar): - */ - if ((str = part[3]) != NULL) { - int t, b, l, r; - if (sscanf(str, "%d+%d+%d+%d", &t, &b, &l, &r) == 4) { - wireframe_top = t; - wireframe_bot = b; - wireframe_left = l; - wireframe_right = r; - } - free(str); - } - - /* - * wireframe in interior with Modifier down. - * 0 => no mods - * 1 => all mods - * Shift,Alt,Control,Meta,Super,Hyper - */ - if (wireframe_mods) { - free(wireframe_mods); - } - wireframe_mods = NULL; - if ((str = part[4]) != NULL) { - if (*str == '0' || !strcmp(str, "none")) { - ; - } else if (*str == '1' || !strcmp(str, "all")) { - wireframe_mods = strdup("all"); - } else if (!strcmp(str, "Alt") || !strcmp(str, "Shift") - || !strcmp(str, "Control") || !strcmp(str, "Meta") - || !strcmp(str, "Super") || !strcmp(str, "Hyper")) { - wireframe_mods = strdup(str); - } - } - - /* check_wireframe() timing heuristics. */ - if ((str = part[5]) != NULL) { - double t1, t2, t3, t4; - if (sscanf(str, "%lf+%lf+%lf+%lf", &t1, &t2, &t3, &t4) == 4) { - wireframe_t1 = t1; - wireframe_t2 = t2; - wireframe_t3 = t3; - wireframe_t4 = t4; - } - free(str); - } -} - -/* - * First parse the defaults and apply any user supplied ones (may be a subset) - */ -void parse_wireframe(void) { - parse_wireframe_str(WIREFRAME_PARMS); - if (! wireframe_str) { - wireframe_str = strdup(WIREFRAME_PARMS); - } - parse_wireframe_str(wireframe_str); -} - -/* - * Set wireframe_copyrect based on desired mode. - */ -void set_wirecopyrect_mode(char *str) { - char *orig = wireframe_copyrect; - if (str == NULL || *str == '\0') { - wireframe_copyrect = strdup(wireframe_copyrect_default); - } else if (!strcmp(str, "always") || !strcmp(str, "all")) { - wireframe_copyrect = strdup("always"); - } else if (!strcmp(str, "top")) { - wireframe_copyrect = strdup("top"); - } else if (!strcmp(str, "never") || !strcmp(str, "none")) { - wireframe_copyrect = strdup("never"); - } else { - if (! wireframe_copyrect) { - wireframe_copyrect = strdup(wireframe_copyrect_default); - } else { - orig = NULL; - } - rfbLog("unknown -wirecopyrect mode: %s, using: %s\n", str, - wireframe_copyrect); - } - if (orig) { - free(orig); - } -} - -/* - * Set scroll_copyrect based on desired mode. - */ -void set_scrollcopyrect_mode(char *str) { - char *orig = scroll_copyrect; - if (str == NULL || *str == '\0') { - scroll_copyrect = strdup(scroll_copyrect_default); - } else if (!strcmp(str, "always") || !strcmp(str, "all") || - !strcmp(str, "both")) { - scroll_copyrect = strdup("always"); - } else if (!strcmp(str, "keys") || !strcmp(str, "keyboard")) { - scroll_copyrect = strdup("keys"); - } else if (!strcmp(str, "mouse") || !strcmp(str, "pointer")) { - scroll_copyrect = strdup("mouse"); - } else if (!strcmp(str, "never") || !strcmp(str, "none")) { - scroll_copyrect = strdup("never"); - } else { - if (! scroll_copyrect) { - scroll_copyrect = strdup(scroll_copyrect_default); - } else { - orig = NULL; - } - rfbLog("unknown -scrollcopyrect mode: %s, using: %s\n", str, - scroll_copyrect); - } - if (orig) { - free(orig); - } -} - -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; -} - -void initialize_scroll_keys(void) { - char *str, *p; - int i, nkeys = 0, saw_builtin = 0; - int ks_max = 2 * 0xFFFF; - - if (scroll_key_list) { - free(scroll_key_list); - scroll_key_list = NULL; - } - if (! scroll_key_list_str || *scroll_key_list_str == '\0') { - return; - } - - if (strstr(scroll_key_list_str, "builtin")) { - int k; - /* add in number of keysyms builtin gives */ - for (k=1; k<ks_max; k++) { - if (xrecord_scroll_keysym((rfbKeySym) k)) { - nkeys++; - } - } - } - - nkeys++; /* first key, i.e. no commas. */ - p = str = strdup(scroll_key_list_str); - while(*p) { - if (*p == ',') { - nkeys++; /* additional key. */ - } - p++; - } - - nkeys++; /* exclude/include 0 element */ - nkeys++; /* trailing NoSymbol */ - - scroll_key_list = (KeySym *) malloc(nkeys*sizeof(KeySym)); - for (i=0; i<nkeys; i++) { - scroll_key_list[i] = NoSymbol; - } - if (*str == '-') { - scroll_key_list[0] = 1; - p = strtok(str+1, ","); - } else { - p = strtok(str, ","); - } - i = 1; - while (p) { - if (!strcmp(p, "builtin")) { - int k; - if (saw_builtin) { - p = strtok(NULL, ","); - continue; - } - saw_builtin = 1; - for (k=1; k<ks_max; k++) { - if (xrecord_scroll_keysym((rfbKeySym) k)) { - scroll_key_list[i++] = (rfbKeySym) k; - } - } - } else { - unsigned int in; - if (sscanf(p, "%u", &in) == 1) { - scroll_key_list[i++] = (rfbKeySym) in; - } else if (sscanf(p, "0x%x", &in) == 1) { - scroll_key_list[i++] = (rfbKeySym) in; - } else if (XStringToKeysym(p) != NoSymbol) { - scroll_key_list[i++] = XStringToKeysym(p); - } else { - rfbLog("initialize_scroll_keys: skip unknown " - "keysym: %s\n", p); - } - } - p = strtok(NULL, ","); - } - free(str); -} - -void destroy_str_list(char **list) { - int i = 0; - if (! list) { - return; - } - while (list[i] != NULL) { - free(list[i++]); - } - free(list); -} - -void initialize_scroll_matches(void) { - char *str, *imp = "__IMPOSSIBLE_STR__"; - int i, n, nkey, nmouse; - - destroy_str_list(scroll_good_all); - scroll_good_all = NULL; - destroy_str_list(scroll_good_key); - scroll_good_key = NULL; - destroy_str_list(scroll_good_mouse); - scroll_good_mouse = NULL; - - destroy_str_list(scroll_skip_all); - scroll_skip_all = NULL; - destroy_str_list(scroll_skip_key); - scroll_skip_key = NULL; - destroy_str_list(scroll_skip_mouse); - scroll_skip_mouse = NULL; - - /* scroll_good: */ - if (scroll_good_str != NULL && *scroll_good_str != '\0') { - str = scroll_good_str; - } else { - str = scroll_good_str0; - } - scroll_good_all = create_str_list(str); - - nkey = 0; - nmouse = 0; - n = 0; - while (scroll_good_all[n] != NULL) { - char *s = scroll_good_all[n++]; - if (strstr(s, "KEY:") == s) nkey++; - if (strstr(s, "MOUSE:") == s) nmouse++; - } - if (nkey++) { - scroll_good_key = (char **) malloc(nkey*sizeof(char *)); - for (i=0; i<nkey; i++) scroll_good_key[i] = NULL; - } - if (nmouse++) { - scroll_good_mouse = (char **) malloc(nmouse*sizeof(char *)); - for (i=0; i<nmouse; i++) scroll_good_mouse[i] = NULL; - } - nkey = 0; - nmouse = 0; - for (i=0; i<n; i++) { - char *s = scroll_good_all[i]; - if (strstr(s, "KEY:") == s) { - scroll_good_key[nkey++] = strdup(s+strlen("KEY:")); - free(s); - scroll_good_all[i] = strdup(imp); - } else if (strstr(s, "MOUSE:") == s) { - scroll_good_mouse[nmouse++]=strdup(s+strlen("MOUSE:")); - free(s); - scroll_good_all[i] = strdup(imp); - } - } - - /* scroll_skip: */ - if (scroll_skip_str != NULL && *scroll_skip_str != '\0') { - str = scroll_skip_str; - } else { - str = scroll_skip_str0; - } - scroll_skip_all = create_str_list(str); - - nkey = 0; - nmouse = 0; - n = 0; - while (scroll_skip_all[n] != NULL) { - char *s = scroll_skip_all[n++]; - if (strstr(s, "KEY:") == s) nkey++; - if (strstr(s, "MOUSE:") == s) nmouse++; - } - if (nkey++) { - scroll_skip_key = (char **) malloc(nkey*sizeof(char *)); - for (i=0; i<nkey; i++) scroll_skip_key[i] = NULL; - } - if (nmouse++) { - scroll_skip_mouse = (char **) malloc(nmouse*sizeof(char *)); - for (i=0; i<nmouse; i++) scroll_skip_mouse[i] = NULL; - } - nkey = 0; - nmouse = 0; - for (i=0; i<n; i++) { - char *s = scroll_skip_all[i]; - if (strstr(s, "KEY:") == s) { - scroll_skip_key[nkey++] = strdup(s+strlen("KEY:")); - free(s); - scroll_skip_all[i] = strdup(imp); - } else if (strstr(s, "MOUSE:") == s) { - scroll_skip_mouse[nmouse++]=strdup(s+strlen("MOUSE:")); - free(s); - scroll_skip_all[i] = strdup(imp); - } - } -} - -void initialize_scroll_term(void) { - char *str; - int n; - - destroy_str_list(scroll_term); - scroll_term = NULL; - - if (scroll_term_str != NULL && *scroll_term_str != '\0') { - str = scroll_term_str; - } else { - str = scroll_term_str0; - } - if (!strcmp(str, "none")) { - return; - } - scroll_term = create_str_list(str); - - n = 0; - while (scroll_term[n] != NULL) { - char *s = scroll_good_all[n++]; - /* pull parameters out at some point */ - s = NULL; - } -} - -void initialize_max_keyrepeat(void) { - char *str; - int lo, hi; - - if (max_keyrepeat_str != NULL && *max_keyrepeat_str != '\0') { - str = max_keyrepeat_str; - } else { - str = max_keyrepeat_str0; - } - - if (sscanf(str, "%d-%d", &lo, &hi) != 2) { - rfbLog("skipping invalid -scr_keyrepeat string: %s\n", str); - sscanf(max_keyrepeat_str0, "%d-%d", &lo, &hi); - } - max_keyrepeat_lo = lo; - max_keyrepeat_hi = hi; - if (max_keyrepeat_lo < 1) { - max_keyrepeat_lo = 1; - } - if (max_keyrepeat_hi > 40) { - max_keyrepeat_hi = 40; - } -} - -typedef struct saveline { - int x0, y0, x1, y1; - int shift; - int vert; - int saved; - char *data; -} saveline_t; - -/* - * Draw the wireframe box onto the framebuffer. Saves the real - * framebuffer data to some storage lines. Restores previous lines. - * use restore = 1 to clean up (done with animation). - * This works with -scale. - */ -void draw_box(int x, int y, int w, int h, int restore) { - int x0, y0, x1, y1, i, pixelsize = bpp/8; - char *dst, *src; - static saveline_t *save[4]; - static int first = 1, len = 0; - int max = dpy_x > dpy_y ? dpy_x : dpy_y; - int sz, lw = wireframe_lw; - unsigned long shade = wireframe_shade; - int color = 0; - unsigned short us; - unsigned long ul; - - if (clipshift) { - x -= coff_x; - y -= coff_y; - } - /* no subwin for wireframe */ - - if (max > len) { - /* create/resize storage lines: */ - for (i=0; i<4; i++) { - len = max; - if (! first && save[i]) { - if (save[i]->data) { - free(save[i]->data); - save[i]->data = NULL; - } - free(save[i]); - } - save[i] = (saveline_t *) malloc(sizeof(saveline_t)); - save[i]->saved = 0; - sz = (LW_MAX+1)*len*pixelsize; - save[i]->data = (char *) malloc(sz); - - /* - * Four types of lines: - * 0) top horizontal - * 1) bottom horizontal - * 2) left vertical - * 3) right vertical - * - * shift means shifted by width or height. - */ - if (i == 0) { - save[i]->vert = 0; - save[i]->shift = 0; - } else if (i == 1) { - save[i]->vert = 0; - save[i]->shift = 1; - } else if (i == 2) { - save[i]->vert = 1; - save[i]->shift = 0; - } else if (i == 3) { - save[i]->vert = 1; - save[i]->shift = 1; - } - } - } - first = 0; - - /* - * restore any saved lines. see below for algorithm and - * how x0, etc. are used. we just reverse those steps. - */ - for (i=0; i<4; i++) { - int s = save[i]->shift; - int yu, y_min = -1, y_max = -1; - int y_start, y_stop, y_step; - - if (! save[i]->saved) { - continue; - } - x0 = save[i]->x0; - y0 = save[i]->y0; - x1 = save[i]->x1; - y1 = save[i]->y1; - if (save[i]->vert) { - y_start = y0+lw; - y_stop = y1-lw; - y_step = lw*pixelsize; - } else { - y_start = y0 - s*lw; - y_stop = y_start + lw; - y_step = max*pixelsize; - } - for (yu = y_start; yu < y_stop; yu++) { - if (x0 == x1) { - continue; - } - if (yu < 0 || yu >= dpy_y) { - continue; - } - if (y_min < 0 || yu < y_min) { - y_min = yu; - } - if (y_max < 0 || yu > y_max) { - y_max = yu; - } - src = save[i]->data + (yu-y_start)*y_step; - dst = main_fb + yu*main_bytes_per_line + - x0*pixelsize; - memcpy(dst, src, (x1-x0)*pixelsize); - } - if (y_min >= 0) { - mark_rect_as_modified(x0, y_min, x1, y_max+1, 0); - } - save[i]->saved = 0; - } - - if (restore) { - return; - } - -if (0) fprintf(stderr, " DrawBox: %dx%d+%d+%d\n", w, h, x, y); - - /* - * work out shade/color for the wireframe line, could be a color - * for 16bpp or 24bpp. - */ - if (shade > 255) { - if (pixelsize == 2) { - us = (unsigned short) (shade & 0xffff); - color = 1; - } else if (pixelsize == 4) { - ul = (unsigned long) shade; - color = 1; - } else { - shade = shade % 256; - } - } - - for (i=0; i<4; i++) { - int s = save[i]->shift; - int yu, y_min = -1, y_max = -1; - int yblack = -1, xblack1 = -1, xblack2 = -1; - int y_start, y_stop, y_step; - - if (save[i]->vert) { - /* - * make the narrow x's be on the screen, let - * the y's hang off (not drawn). - */ - save[i]->x0 = x0 = nfix(x + s*w - s*lw, dpy_x); - save[i]->y0 = y0 = y; - save[i]->x1 = x1 = nfix(x + s*w - s*lw + lw, dpy_x); - save[i]->y1 = y1 = y + h; - - /* - * start and stop a linewidth away from true edge, - * to avoid interfering with horizontal lines. - */ - y_start = y0+lw; - y_stop = y1-lw; - y_step = lw*pixelsize; - - /* draw a black pixel for the border if lw > 1 */ - if (s) { - xblack1 = x1-1; - } else { - xblack1 = x0; - } - } else { - /* - * make the wide x's be on the screen, let the y's - * hang off (not drawn). - */ - save[i]->x0 = x0 = nfix(x, dpy_x); - save[i]->y0 = y0 = y + s*h; - save[i]->x1 = x1 = nfix(x + w, dpy_x); - save[i]->y1 = y1 = y0 + lw; - y_start = y0 - s*lw; - y_stop = y_start + lw; - y_step = max*pixelsize; - - /* draw a black pixels for the border if lw > 1 */ - if (s) { - yblack = y_stop - 1; - } else { - yblack = y_start; - } - xblack1 = x0; - xblack2 = x1-1; - } - - /* now loop over the allowed y's for either case */ - for (yu = y_start; yu < y_stop; yu++) { - if (x0 == x1) { - continue; - } - if (yu < 0 || yu >= dpy_y) { - continue; - } - - /* record min and max y's for marking rectangle: */ - if (y_min < 0 || yu < y_min) { - y_min = yu; - } - if (y_max < 0 || yu > y_max) { - y_max = yu; - } - - /* save fb data for this line: */ - save[i]->saved = 1; - src = main_fb + yu*main_bytes_per_line + - x0*pixelsize; - dst = save[i]->data + (yu-y_start)*y_step; - memcpy(dst, src, (x1-x0)*pixelsize); - - /* apply the shade/color to make the wireframe line: */ - if (! color) { - memset(src, shade, (x1-x0)*pixelsize); - } else { - char *csrc = src; - unsigned short *usp; - unsigned long *ulp; - int k; - for (k=0; k < x1 - x0; k++) { - if (pixelsize == 4) { - ulp = (unsigned long *)csrc; - *ulp = ul; - } else if (pixelsize == 2) { - usp = (unsigned short *)csrc; - *usp = us; - } - csrc += pixelsize; - } - } - - /* apply black border for lw >= 2 */ - if (lw > 1) { - if (yu == yblack) { - memset(src, 0, (x1-x0)*pixelsize); - } - if (xblack1 >= 0) { - src = src + (xblack1 - x0)*pixelsize; - memset(src, 0, pixelsize); - } - if (xblack2 >= 0) { - src = src + (xblack2 - x0)*pixelsize; - memset(src, 0, pixelsize); - } - } - } - /* mark it for sending: */ - if (save[i]->saved) { - mark_rect_as_modified(x0, y_min, x1, y_max+1, 0); - } - } -} - -int direct_fb_copy(int x1, int y1, int x2, int y2, int mark) { - char *src, *dst; - int y, pixelsize = bpp/8; - int xmin = -1, xmax = -1, ymin = -1, ymax = -1; - int do_cmp = 2; - double tm; - int db = 0; - -if (db) dtime0(&tm); - - x1 = nfix(x1, dpy_x); - y1 = nfix(y1, dpy_y); - x2 = nfix(x2, dpy_x+1); - y2 = nfix(y2, dpy_y+1); - - if (x1 == x2) { - return 1; - } - if (y1 == y2) { - return 1; - } - - X_LOCK; - for (y = y1; y < y2; y++) { - XRANDR_SET_TRAP_RET(0, "direct_fb_copy-set"); - copy_image(scanline, x1, y, x2 - x1, 1); - XRANDR_CHK_TRAP_RET(0, "direct_fb_copy-chk"); - - src = scanline->data; - dst = main_fb + y * main_bytes_per_line + x1 * pixelsize; - - if (do_cmp == 0 || !mark) { - memcpy(dst, src, (x2 - x1)*pixelsize); - - } else if (do_cmp == 1) { - if (memcmp(dst, src, (x2 - x1)*pixelsize)) { - if (ymin == -1 || y < ymin) { - ymin = y; - } - if (ymax == -1 || y > ymax) { - ymax = y; - } - memcpy(dst, src, (x2 - x1)*pixelsize); - } - - } else if (do_cmp == 2) { - int n, shift, xlo, xhi, k, block = 32; - char *dst2, *src2; - - for (k=0; k*block < (x2 - x1); k++) { - shift = k*block; - xlo = x1 + shift; - xhi = xlo + block; - if (xhi > x2) { - xhi = x2; - } - n = xhi - xlo; - if (n < 1) { - continue; - } - src2 = src + shift*pixelsize; - dst2 = dst + shift*pixelsize; - if (memcmp(dst2, src2, n*pixelsize)) { - if (ymin == -1 || y < ymin) { - ymin = y; - } - if (ymax == -1 || y > ymax) { - ymax = y; - } - if (xmin == -1 || xlo < xmin) { - xmin = xlo; - } - if (xmax == -1 || xhi > xmax) { - xmax = xhi; - } - memcpy(dst2, src2, n*pixelsize); - } - } - } - } - X_UNLOCK; - - if (do_cmp == 0) { - xmin = x1; - ymin = y1; - xmax = x2; - ymax = y2; - } else if (do_cmp == 1) { - xmin = x1; - xmax = x2; - } - - if (xmin < 0 || ymin < 0 || xmax < 0 || xmin < 0) { - /* no diffs */ - return 1; - } - - if (xmax < x2) { - xmax++; - } - if (ymax < y2) { - ymax++; - } - - if (mark) { - mark_rect_as_modified(xmin, ymin, xmax, ymax, 0); - } - -if (db) { - fprintf(stderr, "direct_fb_copy: %dx%d+%d+%d - %d %.4f\n", - x2 - x1, y2 - y1, x1, y1, mark, dtime(&tm)); -} - - return 1; -} - -int do_bdpush(Window wm_win, int x0, int y0, int w0, int h0, int bdx, - int bdy, int bdskinny) { - - XWindowAttributes attr; - sraRectangleIterator *iter; - sraRect rect; - sraRegionPtr frame, whole, tmpregion; - int tx1, ty1, tx2, ty2; - static Window last_wm_win = None; - static int last_x, last_y, last_w, last_h; - int do_fb_push = 0; - int db = debug_scroll; - - if (wm_win == last_wm_win) { - attr.x = last_x; - attr.y = last_y; - attr.width = last_w; - attr.height = last_h; - } else { - if (!valid_window(wm_win, &attr, 1)) { - return do_fb_push; - } - last_wm_win = wm_win; - last_x = attr.x; - last_y = attr.y; - last_w = attr.width; - last_h = attr.height; - } -if (db > 1) fprintf(stderr, "BDP %d %d %d %d %d %d %d %d %d %d %d\n", - x0, y0, w0, h0, bdx, bdy, bdskinny, last_x, last_y, last_w, last_h); - - /* wm frame: */ - tx1 = attr.x; - ty1 = attr.y; - tx2 = attr.x + attr.width; - ty2 = attr.y + attr.height; - - whole = sraRgnCreateRect(0, 0, dpy_x, dpy_y); - if (clipshift) { - sraRgnOffset(whole, coff_x, coff_y); - } - if (subwin) { - sraRgnOffset(whole, off_x, off_y); - } - frame = sraRgnCreateRect(tx1, ty1, tx2, ty2); - sraRgnAnd(frame, whole); - - /* scrolling window: */ - tmpregion = sraRgnCreateRect(x0, y0, x0 + w0, y0 + h0); - sraRgnAnd(tmpregion, whole); - - sraRgnSubtract(frame, tmpregion); - sraRgnDestroy(tmpregion); - - if (!sraRgnEmpty(frame)) { - double dt = 0.0, dm; - dtime0(&dm); - iter = sraRgnGetIterator(frame); - while (sraRgnIteratorNext(iter, &rect)) { - tx1 = rect.x1; - ty1 = rect.y1; - tx2 = rect.x2; - ty2 = rect.y2; - - if (bdskinny > 0) { - int ok = 0; - if (nabs(ty2-ty1) <= bdskinny) { - ok = 1; - } - if (nabs(tx2-tx1) <= bdskinny) { - ok = 1; - } - if (! ok) { - continue; - } - } - - if (bdx >= 0) { - if (bdx < tx1 || tx2 <= bdx) { - continue; - } - } - if (bdy >= 0) { - if (bdy < ty1 || ty2 <= bdy) { - continue; - } - } - if (clipshift) { - tx1 -= coff_x; - ty1 -= coff_y; - tx2 -= coff_x; - ty2 -= coff_y; - } - if (subwin) { - tx1 -= off_x; - ty1 -= off_y; - tx2 -= off_x; - ty2 -= off_y; - } - - direct_fb_copy(tx1, ty1, tx2, ty2, 1); - - do_fb_push++; - dt += dtime(&dm); -if (db > 1) fprintf(stderr, " BDP(%d,%d-%d,%d) dt: %.4f\n", tx1, ty1, tx2, ty2, dt); - } - sraRgnReleaseIterator(iter); - } - sraRgnDestroy(whole); - sraRgnDestroy(frame); - - return do_fb_push; -} - -int set_ypad(void) { - int ev, ev_tot = scr_ev_cnt; - static Window last_win = None; - static double last_time = 0.0; - static int y_accum = 0, last_sign = 0; - double now, cut = 0.1; - int dy_sum = 0, ys = 0, sign; - int font_size = 15; - int win_y, scr_y, loc_cut = 4*font_size, y_cut = 10*font_size; - - if (!xrecord_set_by_keys || !xrecord_name_info) { - return 0; - } - if (xrecord_name_info[0] == '\0') { - return 0; - } - if (! ev_tot) { - return 0; - } - if (xrecord_keysym == NoSymbol) { - return 0; - } - if (!xrecord_scroll_keysym(xrecord_keysym)) { - return 0; - } - if (!scroll_term) { - return 0; - } - if (!match_str_list(xrecord_name_info, scroll_term)) { - return 0; - } - - for (ev=0; ev < ev_tot; ev++) { - dy_sum += nabs(scr_ev[ev].dy); - if (scr_ev[ev].dy < 0) { - ys--; - } else if (scr_ev[ev].dy > 0) { - ys++; - } else { - ys = 0; - break; - } - if (scr_ev[ev].win != scr_ev[0].win) { - ys = 0; - break; - } - if (scr_ev[ev].dx != 0) { - ys = 0; - break; - } - } - if (ys != ev_tot && ys != -ev_tot) { - return 0; - } - if (ys < 0) { - sign = -1; - } else { - sign = 1; - } - - if (sign > 0) { - /* - * this case is not as useful as scrolling near the - * bottom of a terminal. But there are problems for it too. - */ - return 0; - } - - win_y = scr_ev[0].win_y + scr_ev[0].win_h; - scr_y = scr_ev[0].y + scr_ev[0].h; - if (nabs(scr_y - win_y) > loc_cut) { - /* require it to be near the bottom. */ - return 0; - } - - now = dnow(); - - if (now < last_time + cut) { - int ok = 1; - if (last_win && scr_ev[0].win != last_win) { - ok = 0; - } - if (last_sign && sign != last_sign) { - ok = 0; - } - if (! ok) { - last_win = None; - last_sign = 0; - y_accum = 0; - last_time = 0.0; - return 0; - } - } else { - last_win = None; - last_sign = 0; - last_time = 0.0; - y_accum = 0; - } - - y_accum += sign * dy_sum; - - if (4 * nabs(y_accum) > scr_ev[0].h && y_cut) { - ; /* TBD */ - } - - last_sign = sign; - last_win = scr_ev[0].win; - last_time = now; - - return y_accum; -} - -void scale_mark(int x1, int y1, int x2, int y2) { - int s = 2; - x1 = nfix(x1 - s, dpy_x); - y1 = nfix(y1 - s, dpy_y); - x2 = nfix(x2 + s, dpy_x+1); - y2 = nfix(y2 + s, dpy_y+1); - scale_and_mark_rect(x1, y1, x2, y2); -} - -#define PUSH_TEST(n) \ -if (n) { \ - double dt = 0.0, tm; dtime0(&tm); \ - fprintf(stderr, "PUSH---\n"); \ - while (dt < 2.0) { rfbPE(50000); dt += dtime(&tm); } \ - fprintf(stderr, "---PUSH\n"); \ -} - -int push_scr_ev(double *age, int type, int bdpush, int bdx, int bdy, - int bdskinny) { - Window frame, win, win0; - int x, y, w, h, wx, wy, ww, wh, dx, dy; - int x0, y0, w0, h0; - int nx, ny, nw, nh; - int dret = 1, do_fb_push = 0, obscured; - int ev, ev_tot = scr_ev_cnt; - double tm, dt, st, waittime = 0.125; - double max_age = *age; - int db = debug_scroll, rrate = get_read_rate(); - sraRegionPtr backfill, whole, tmpregion, tmpregion2; - int link, latency, netrate; - int ypad = 0; - double last_scroll_event_save = last_scroll_event; - - /* we return the oldest one. */ - *age = 0.0; - - if (ev_tot == 0) { - return dret; - } - - link = link_rate(&latency, &netrate); - - if (link == LR_DIALUP) { - waittime *= 5; - } else if (link == LR_BROADBAND) { - waittime *= 3; - } else if (latency > 80 || netrate < 40) { - waittime *= 3; - } - - backfill = sraRgnCreate(); - whole = sraRgnCreateRect(0, 0, dpy_x, dpy_y); - if (clipshift) { - sraRgnOffset(whole, coff_x, coff_y); - } - if (subwin) { - sraRgnOffset(whole, off_x, off_y); - } - - win0 = scr_ev[0].win; - x0 = scr_ev[0].win_x; - y0 = scr_ev[0].win_y; - w0 = scr_ev[0].win_w; - h0 = scr_ev[0].win_h; - - ypad = set_ypad(); - -if (db) fprintf(stderr, "ypad: %d dy[0]: %d\n", ypad, scr_ev[0].dy); - - for (ev=0; ev < ev_tot; ev++) { - double ag; - - x = scr_ev[ev].x; - y = scr_ev[ev].y; - w = scr_ev[ev].w; - h = scr_ev[ev].h; - dx = scr_ev[ev].dx; - dy = scr_ev[ev].dy; - win = scr_ev[ev].win; - wx = scr_ev[ev].win_x; - wy = scr_ev[ev].win_y; - ww = scr_ev[ev].win_w; - wh = scr_ev[ev].win_h; - nx = scr_ev[ev].new_x; - ny = scr_ev[ev].new_y; - nw = scr_ev[ev].new_w; - nh = scr_ev[ev].new_h; - st = scr_ev[ev].t; - - ag = (dnow() - servertime_diff) - st; - if (ag > *age) { - *age = ag; - } - - if (dabs(ag) > max_age) { -if (db) fprintf(stderr, "push_scr_ev: TOO OLD: %.4f :: (%.4f - %.4f) " - "- %.4f \n", ag, dnow(), servertime_diff, st); - dret = 0; - break; - } else { -if (db) fprintf(stderr, "push_scr_ev: AGE: %.4f\n", ag); - } - if (win != win0) { -if (db) fprintf(stderr, "push_scr_ev: DIFF WIN: 0x%lx != 0x%lx\n", win, win0); - dret = 0; - break; - } - if (wx != x0 || wy != y0) { -if (db) fprintf(stderr, "push_scr_ev: WIN SHIFT: %d %d, %d %d", wx, x0, wy, y0); - dret = 0; - break; - } - if (ww != w0 || wh != h0) { -if (db) fprintf(stderr, "push_scr_ev: WIN RESIZE: %d %d, %d %d", ww, w0, wh, h0); - dret = 0; - break; - } - if (w < 1 || h < 1 || ww < 1 || wh < 1) { -if (db) fprintf(stderr, "push_scr_ev: NEGATIVE h/w: %d %d %d %d\n", w, h, ww, wh); - dret = 0; - break; - } - -if (db > 1) fprintf(stderr, "push_scr_ev: got: %d x: %4d y: %3d" - " w: %4d h: %3d dx: %d dy: %d %dx%d+%d+%d win: 0x%lx\n", - ev, x, y, w, h, dx, dy, w, h, x, y, win); - -if (db > 1) fprintf(stderr, "------------ got: %d x: %4d y: %3d" - " w: %4d h: %3d %dx%d+%d+%d\n", - ev, wx, wy, ww, wh, ww, wh, wx, wy); - -if (db > 1) fprintf(stderr, "------------ got: %d x: %4d y: %3d" - " w: %4d h: %3d %dx%d+%d+%d\n", - ev, nx, ny, nw, nh, nw, nh, nx, ny); - - frame = None; - if (xrecord_wm_window) { - frame = xrecord_wm_window; - } - if (! frame) { - X_LOCK; - frame = query_pointer(rootwin); - X_UNLOCK; - } - if (! frame) { - frame = win; - } - - dtime0(&tm); - - tmpregion = sraRgnCreateRect(0, 0, dpy_x, dpy_y); - if (clipshift) { - sraRgnOffset(tmpregion, coff_x, coff_y); - } - if (subwin) { - sraRgnOffset(tmpregion, off_x, off_y); - } - tmpregion2 = sraRgnCreateRect(wx, wy, wx+ww, wy+wh); - sraRgnAnd(tmpregion2, whole); - sraRgnSubtract(tmpregion, tmpregion2); - sraRgnDestroy(tmpregion2); - - /* do the wm frame just incase the above is bogus too. */ - if (frame && frame != win) { - int k, gotk = -1; - for (k = stack_list_num - 1; k >= 0; k--) { - if (stack_list[k].win == frame && - stack_list[k].fetched && - stack_list[k].valid && - stack_list[k].map_state == IsViewable) { - gotk = k; - break; - } - } - if (gotk != -1) { - int tx1, ty1, tx2, ty2; - tx1 = stack_list[gotk].x; - ty1 = stack_list[gotk].y; - tx2 = tx1 + stack_list[gotk].width; - ty2 = ty1 + stack_list[gotk].height; - tmpregion2 = sraRgnCreateRect(tx1,ty1,tx2,ty2); - sraRgnAnd(tmpregion2, whole); - sraRgnSubtract(tmpregion, tmpregion2); - sraRgnDestroy(tmpregion2); - } - } - - /* - * XXX Need to also clip: - * children of win - * siblings of win higher in stacking order. - * ignore for now... probably will make some apps - * act very strangely. - */ - if (ypad) { - if (ypad < 0) { - if (h > -ypad) { - h += ypad; - } else { - ypad = 0; - } - } else { - if (h > ypad) { - y += ypad; - } else { - ypad = 0; - } - } - } - - if (try_copyrect(frame, x, y, w, h, dx, dy, &obscured, - tmpregion, waittime)) { - last_scroll_type = type; - dtime0(&last_scroll_event); - - do_fb_push++; - urgent_update = 1; - sraRgnDestroy(tmpregion); - -PUSH_TEST(0); - - } else { - dret = 0; - sraRgnDestroy(tmpregion); - break; - } - dt = dtime(&tm); -if (0) fprintf(stderr, " try_copyrect dt: %.4f\n", dt); - - if (ev > 0) { - sraRgnOffset(backfill, dx, dy); - sraRgnAnd(backfill, whole); - } - - if (ypad) { - if (ypad < 0) { - ny += ypad; - nh -= ypad; - } else { - ; - } - } - - tmpregion = sraRgnCreateRect(nx, ny, nx + nw, ny + nh); - sraRgnAnd(tmpregion, whole); - sraRgnOr(backfill, tmpregion); - sraRgnDestroy(tmpregion); - } - - /* try to update the backfill region (new window contents) */ - if (dret != 0) { - double est, win_area = 0.0, area = 0.0; - sraRectangleIterator *iter; - sraRect rect; - int tx1, ty1, tx2, ty2; - - tmpregion = sraRgnCreateRect(x0, y0, x0 + w0, y0 + h0); - sraRgnAnd(tmpregion, whole); - - sraRgnAnd(backfill, tmpregion); - - iter = sraRgnGetIterator(tmpregion); - while (sraRgnIteratorNext(iter, &rect)) { - tx1 = rect.x1; - ty1 = rect.y1; - tx2 = rect.x2; - ty2 = rect.y2; - - win_area += (tx2 - tx1)*(ty2 - ty1); - } - sraRgnReleaseIterator(iter); - sraRgnDestroy(tmpregion); - - - iter = sraRgnGetIterator(backfill); - while (sraRgnIteratorNext(iter, &rect)) { - tx1 = rect.x1; - ty1 = rect.y1; - tx2 = rect.x2; - ty2 = rect.y2; - - area += (tx2 - tx1)*(ty2 - ty1); - } - sraRgnReleaseIterator(iter); - - est = (area * (bpp/8)) / (1000000.0 * rrate); -if (db) fprintf(stderr, " area %.1f win_area %.1f est: %.4f", area, win_area, est); - if (area > 0.90 * win_area) { -if (db) fprintf(stderr, " AREA_TOO_MUCH"); - dret = 0; - } else if (est > 0.6) { -if (db) fprintf(stderr, " EST_TOO_LARGE"); - dret = 0; - } else if (area <= 0.0) { - ; - } else { - dtime0(&tm); - iter = sraRgnGetIterator(backfill); - while (sraRgnIteratorNext(iter, &rect)) { - tx1 = rect.x1; - ty1 = rect.y1; - tx2 = rect.x2; - ty2 = rect.y2; - - if (clipshift) { - tx1 -= coff_x; - ty1 -= coff_y; - tx2 -= coff_x; - ty2 -= coff_y; - } - if (subwin) { - tx1 -= off_x; - ty1 -= off_y; - tx2 -= off_x; - ty2 -= off_y; - } - tx1 = nfix(tx1, dpy_x); - ty1 = nfix(ty1, dpy_y); - tx2 = nfix(tx2, dpy_x+1); - ty2 = nfix(ty2, dpy_y+1); - - dtime(&tm); -if (db) fprintf(stderr, " DFC(%d,%d-%d,%d)", tx1, ty1, tx2, ty2); - direct_fb_copy(tx1, ty1, tx2, ty2, 1); - do_fb_push++; -PUSH_TEST(0); - } - sraRgnReleaseIterator(iter); - dt = dtime(&tm); -if (db) fprintf(stderr, " dfc---- dt: %.4f", dt); - - } -if (db && dret) fprintf(stderr, " **** dret=%d", dret); -if (db && !dret) fprintf(stderr, " ---- dret=%d", dret); -if (db) fprintf(stderr, "\n"); - } - -if (db && bdpush) fprintf(stderr, "BDPUSH-TIME: 0x%lx\n", xrecord_wm_window); - - if (bdpush && xrecord_wm_window != None) { - int x, y, w, h; - x = scr_ev[0].x; - y = scr_ev[0].y; - w = scr_ev[0].w; - h = scr_ev[0].h; - do_fb_push += do_bdpush(xrecord_wm_window, x, y, w, h, - bdx, bdy, bdskinny); - } - - if (do_fb_push) { - dtime0(&tm); - fb_push(); - dt = dtime(&tm); -if (0) fprintf(stderr, " fb_push dt: %.4f", dt); - if (scaling) { - static double last_time = 0.0; - double now = dnow(), delay = 0.4, first_wait = 3.0; - double trate; - int repeating, lat, rate; - int link = link_rate(&lat, &rate); - int skip_first = 0; - - if (link == LR_DIALUP || rate < 35) { - delay *= 4; - } else if (link != LR_LAN || rate < 100) { - delay *= 2; - } - - trate = typing_rate(0.0, &repeating); - - if (xrecord_set_by_mouse || repeating >= 3) { - if (now > last_scroll_event_save + first_wait) { - skip_first = 1; - } - } - - if (skip_first) { - /* - * try not to send the first one, but a - * single keystroke scroll would be OK. - */ - } else if (now > last_time + delay) { - - scale_mark(x0, y0, x0 + w0, y0 + h0); - last_copyrect_fix = now; - } - last_time = now; - } - } - - sraRgnDestroy(backfill); - sraRgnDestroy(whole); - return dret; -} - -void get_client_regions(int *req, int *mod, int *cpy, int *num) { - - rfbClientIteratorPtr i; - rfbClientPtr cl; - - *req = 0; - *mod = 0; - *cpy = 0; - *num = 0; - - i = rfbGetClientIterator(screen); - while( (cl = rfbClientIteratorNext(i)) ) { - *req += sraRgnCountRects(cl->requestedRegion); - *mod += sraRgnCountRects(cl->modifiedRegion); - *cpy += sraRgnCountRects(cl->copyRegion); - *num += 1; - } - rfbReleaseClientIterator(i); -} - -/* - * Wrapper to apply the rfbDoCopyRegion taking into account if scaling - * is being done. Note that copyrect under the scaling case is often - * only approximate. - */ -void do_copyregion(sraRegionPtr region, int dx, int dy) { - sraRectangleIterator *iter; - sraRect rect; - int Bpp = bpp/8; - int x1, y1, x2, y2, w, stride; - int sx1, sy1, sx2, sy2, sdx, sdy; - int req, mod, cpy, ncli; - char *dst, *src; - - last_copyrect = dnow(); - - if (!scaling || rfb_fb == main_fb) { - /* normal case */ - get_client_regions(&req, &mod, &cpy, &ncli); -if (debug_scroll > 1) fprintf(stderr, "<<<-rfbDoCopyRect req: %d mod: %d cpy: %d\n", req, mod, cpy); - rfbDoCopyRegion(screen, region, dx, dy); - - get_client_regions(&req, &mod, &cpy, &ncli); -if (debug_scroll > 1) fprintf(stderr, ">>>-rfbDoCopyRect req: %d mod: %d cpy: %d\n", req, mod, cpy); - - return; - } - - /* rarer case, we need to call rfbDoCopyRect with scaled xy */ - stride = dpy_x * Bpp; - - iter = sraRgnGetReverseIterator(region, dx < 0, dy < 0); - while(sraRgnIteratorNext(iter, &rect)) { - int j; - - x1 = rect.x1; - y1 = rect.y1; - x2 = rect.x2; - y2 = rect.y2; - - w = (x2 - x1)*Bpp; - dst = main_fb + y1*stride + x1*Bpp; - src = main_fb + (y1-dy)*stride + (x1-dx)*Bpp; - - if (dy < 0) { - for (j=y1; j<y2; j++) { - memmove(dst, src, w); - dst += stride; - src += stride; - } - } else { - dst += (y2 - y1 - 1)*stride; - src += (y2 - y1 - 1)*stride; - for (j=y2-1; j>=y1; j--) { - memmove(dst, src, w); - dst -= stride; - src -= stride; - } - } - - sx1 = ((double) x1 / dpy_x) * scaled_x; - sy1 = ((double) y1 / dpy_y) * scaled_y; - sx2 = ((double) x2 / dpy_x) * scaled_x; - sy2 = ((double) y2 / dpy_y) * scaled_y; - sdx = ((double) dx / dpy_x) * scaled_x; - sdy = ((double) dy / dpy_y) * scaled_y; - - rfbDoCopyRect(screen, sx1, sy1, sx2, sy2, sdx, sdy); - } - sraRgnReleaseIterator(iter); -} - -void fb_push_wait(double max_wait, int flags) { - double tm, dt = 0.0; - int req, mod, cpy, ncli; - - dtime0(&tm); - while (dt < max_wait) { - int done = 1; - rfbCFD(0); - get_client_regions(&req, &mod, &cpy, &ncli); - if (flags & FB_COPY && cpy) { - done = 0; - } - if (flags & FB_MOD && mod) { - done = 0; - } - if (flags & FB_REQ && req) { - done = 0; - } - if (done) { - break; - } - - usleep(1000); - fb_push(); - dt += dtime(&tm); - } -} - -void fb_push(void) { - char *httpdir = screen->httpDir; - int defer = screen->deferUpdateTime; - int req0, mod0, cpy0, req1, mod1, cpy1, ncli; - int db = (debug_scroll || debug_wireframe); - - screen->httpDir = NULL; - screen->deferUpdateTime = 0; - -if (db) get_client_regions(&req0, &mod0, &cpy0, &ncli); - - rfbPE(0); - - screen->httpDir = httpdir; - screen->deferUpdateTime = defer; - -if (db) { - get_client_regions(&req1, &mod1, &cpy1, &ncli); - fprintf(stderr, "\nFB_push: req: %d/%d mod: %d/%d cpy: %d/%d %.4f\n", - req0, req1, mod0, mod1, cpy0, cpy1, dnow() - x11vnc_start); -} - -} - -/* - * utility routine for CopyRect of the window (but not CopyRegion) - */ -int crfix(int x, int dx, int Lx) { - /* adjust x so that copy source is on screen */ - if (dx > 0) { - if (x-dx < 0) { - /* off on the left */ - x = dx; - } - } else { - if (x-dx >= Lx) { - /* off on the right */ - x = Lx + dx - 1; - } - } - return x; -} - -typedef struct scroll_result { - Window win; - double time; - int result; -} scroll_result_t; - -#define SCR_RESULTS_MAX 256 -scroll_result_t scroll_results[SCR_RESULTS_MAX]; - -int scrollability(Window win, int set) { - double oldest = -1.0; - int i, index = -1, next_index = -1; - static int first = 1; - - if (first) { - for (i=0; i<SCR_RESULTS_MAX; i++) { - scroll_results[i].win = None; - scroll_results[i].time = 0.0; - scroll_results[i].result = 0; - } - first = 0; - } - - if (win == None) { - return 0; - } - if (set == SCR_NONE) { - /* lookup case */ - for (i=0; i<SCR_RESULTS_MAX; i++) { - if (win == scroll_results[i].win) { - return scroll_results[i].result; - } - if (scroll_results[i].win == None) { - break; - } - } - return 0; - } - - for (i=0; i<SCR_RESULTS_MAX; i++) { - if (oldest == -1.0 || scroll_results[i].time < oldest) { - next_index = i; - oldest = scroll_results[i].time; - } - if (win == scroll_results[i].win) { - index = i; - break; - } - if (next_index >= 0 && scroll_results[i].win == None) { - break; - } - } - - if (set == SCR_SUCCESS) { - set = 1; - } else if (set == SCR_FAIL) { - set = -1; - } else { - set = 0; - } - if (index == -1) { - scroll_results[next_index].win = win; - scroll_results[next_index].time = dnow(); - scroll_results[next_index].result = set; - } else { - if (scroll_results[index].result == 1) { - /* - * once a success, always a success, until they - * forget about us... - */ - set = 1; - } else { - scroll_results[index].result = set; - } - scroll_results[index].time = dnow(); - } - - return set; -} - -void eat_viewonly_input(int max_eat, int keep) { - int i, gp, gk; - - for (i=0; i<max_eat; i++) { - int cont = 0; - gp = got_pointer_calls; - gk = got_keyboard_calls; - rfbCFD(0); - if (got_pointer_calls > gp) { - if (debug_pointer) { - rfbLog("eat_viewonly_input: pointer: %d\n", i); - } - cont++; - } - if (got_keyboard_calls > gk) { - if (debug_keyboard) { - rfbLog("eat_viewonly_input: keyboard: %d\n", i); - } - cont++; - } - if (i >= keep - 1 && ! cont) { - break; - } - } -} - -int eat_pointer(int max_ptr_eat, int keep) { - int i, count = 0, gp = got_pointer_input; - - for (i=0; i<max_ptr_eat; i++) { - rfbCFD(0); - if (got_pointer_input > gp) { - count++; -if (0) fprintf(stderr, "GP*-%d\n", i); - gp = got_pointer_input; - } else if (i > keep) { - break; - } - } - return count; -} - -void set_bdpush(int type, double *last_bdpush, int *pushit) { - double now, delay = 0.0; - int link, latency, netrate; - - *pushit = 0; - - if (type == SCR_MOUSE) { - delay = scr_mouse_bdpush_time; - } else if (type == SCR_KEY) { - delay = scr_key_bdpush_time; - } - - link = link_rate(&latency, &netrate); - if (link == LR_DIALUP) { - delay *= 1.5; - } else if (link == LR_BROADBAND) { - delay *= 1.25; - } - - dtime0(&now); - if (delay > 0.0 && now > *last_bdpush + delay) { - *pushit = 1; - *last_bdpush = now; - } -} - -void mark_for_xdamage(int x, int y, int w, int h) { - int tx1, ty1, tx2, ty2; - sraRegionPtr tmpregion; - - if (! use_xdamage) { - return; - } - - tx1 = nfix(x, dpy_x); - ty1 = nfix(y, dpy_y); - tx2 = nfix(x + w, dpy_x+1); - ty2 = nfix(y + h, dpy_y+1); - - tmpregion = sraRgnCreateRect(tx1, ty1, tx2, ty2); - add_region_xdamage(tmpregion); - sraRgnDestroy(tmpregion); -} - -void mark_region_for_xdamage(sraRegionPtr region) { - sraRectangleIterator *iter; - sraRect rect; - iter = sraRgnGetIterator(region); - while (sraRgnIteratorNext(iter, &rect)) { - int x1 = rect.x1; - int y1 = rect.y1; - int x2 = rect.x2; - int y2 = rect.y2; - mark_for_xdamage(x1, y1, x2 - x1, y2 - y1); - } - sraRgnReleaseIterator(iter); -} - -void set_xdamage_mark(int x, int y, int w, int h) { - sraRegionPtr region; - - if (! use_xdamage) { - return; - } - mark_for_xdamage(x, y, w, h); - - if (xdamage_scheduled_mark == 0.0) { - xdamage_scheduled_mark = dnow() + 2.0; - } - - if (xdamage_scheduled_mark_region == NULL) { - xdamage_scheduled_mark_region = sraRgnCreate(); - } - region = sraRgnCreateRect(x, y, x + w, y + w); - sraRgnOr(xdamage_scheduled_mark_region, region); - sraRgnDestroy(region); -} - -int repeat_check(double last_key_scroll) { - int repeating; - double rate = typing_rate(0.0, &repeating); - double now = dnow(), delay = 0.5; - if (rate > 2.0 && repeating && now > last_key_scroll + delay) { - return 0; - } else { - return 1; - } -} - -int check_xrecord_keys(void) { - static int last_wx, last_wy, last_ww, last_wh; - double spin = 0.0, tm, tnow; - int scr_cnt = 0, input = 0, scroll_rep; - int get_out, got_one = 0, flush1 = 0, flush2 = 0; - int gk, gk0, ret = 0, db = debug_scroll; - int fail = 0; - int link, latency, netrate; - - static double last_key_scroll = 0.0; - static double persist_start = 0.0; - static double last_bdpush = 0.0; - static int persist_count = 0; - int scroll_keysym = 0; - double last_scroll, scroll_persist = scr_key_persist; - double spin_fac = 1.0, scroll_fac = 2.0, noscroll_fac = 0.75; - double max_spin, max_long_spin = 0.3; - double set_repeat_in; - static double set_repeat = 0.0; - - set_repeat_in = set_repeat; - set_repeat = 0.0; - - get_out = 1; - if (got_keyboard_input) { - get_out = 0; - } - - dtime0(&tnow); - if (tnow < last_key_scroll + scroll_persist) { - get_out = 0; - } - - if (set_repeat_in > 0.0 && tnow < last_key_scroll + set_repeat_in) { - get_out = 0; - } - - if (get_out) { - persist_start = 0.0; - persist_count = 0; - last_bdpush = 0.0; - if (xrecording) { - xrecord_watch(0, SCR_KEY); - } - return 0; - } - -#if 0 - /* not used for keyboard yet */ - scroll_rep = scrollability(xrecord_ptr_window, SCR_NONE) + 1; - if (scroll_rep == 1) { - scroll_rep = 2; /* if no info, assume the best. */ - } -#endif - - scroll_keysym = xrecord_scroll_keysym(last_rfb_keysym); - - max_spin = scr_key_time; - - if (set_repeat_in > 0.0 && tnow < last_key_scroll + 2*set_repeat_in) { - max_spin = 2 * set_repeat_in; - } else if (tnow < last_key_scroll + scroll_persist) { - max_spin = 1.25*(tnow - last_key_scroll); - } else if (tnow < last_key_to_button_remap_time + 1.5*scroll_persist) { - /* mostly a hack I use for testing -remap key -> btn4/btn5 */ - max_spin = scroll_persist; - } else if (scroll_keysym) { - if (repeat_check(last_key_scroll)) { - spin_fac = scroll_fac; - } else { - spin_fac = noscroll_fac; - } - } - if (max_spin > max_long_spin) { - max_spin = max_long_spin; - } - - /* XXX use this somehow */ -if (0) link = link_rate(&latency, &netrate); - - gk = gk0 = got_keyboard_input; - dtime0(&tm); - -if (db) fprintf(stderr, "check_xrecord_keys: BEGIN LOOP: scr_ev_cnt: " - "%d max: %.3f %.4f\n", scr_ev_cnt, max_spin, tm - x11vnc_start); - - while (1) { - - if (scr_ev_cnt) { - got_one = 1; - - scrollability(xrecord_ptr_window, SCR_SUCCESS); - scroll_rep = 2; - - dtime0(&last_scroll); - last_key_scroll = last_scroll; - scr_cnt++; - break; - } - - X_LOCK; - flush1 = 1; - XFlush(dpy); - X_UNLOCK; - - if (set_repeat_in > 0.0) { - max_keyrepeat_time = set_repeat_in; - } - - if (use_threads) { - usleep(1000); - } else { - rfbCFD(1000); - } - spin += dtime(&tm); - - X_LOCK; - if (got_keyboard_input > gk) { - gk = got_keyboard_input; - input++; - if (set_repeat_in) { - ; - } else if (xrecord_scroll_keysym(last_rfb_keysym)) { - if (repeat_check(last_key_scroll)) { - spin_fac = scroll_fac; - } else { - spin_fac = noscroll_fac; - } - } -if (0 || db) fprintf(stderr, "check_xrecord: more keys: %.3f 0x%x " - " %.4f %s %s\n", spin, last_rfb_keysym, last_rfb_keytime - x11vnc_start, - last_rfb_down ? "down":"up ", last_rfb_key_accepted ? "accept":"skip"); - flush2 = 1; - XFlush(dpy); - } -#if LIBVNCSERVER_HAVE_RECORD - SCR_LOCK; - XRecordProcessReplies(rdpy_data); - SCR_UNLOCK; -#endif - X_UNLOCK; - - if (spin >= max_spin * spin_fac) { -if (0 || db) fprintf(stderr, "check_xrecord: SPIN-OUT: %.3f/%.3f\n", spin, - max_spin * spin_fac); - fail = 1; - break; - } - } - - max_keyrepeat_time = 0.0; - - if (scr_ev_cnt) { - int dret, ev = scr_ev_cnt - 1; - int bdx, bdy, bdskinny, bdpush = 0; - double max_age = 0.25, age, tm, dt; - static double last_scr_ev = 0.0; - - last_wx = scr_ev[ev].win_x; - last_wy = scr_ev[ev].win_y; - last_ww = scr_ev[ev].win_w; - last_wh = scr_ev[ev].win_h; - - /* assume scrollbar on rhs: */ - bdx = last_wx + last_ww + 3; - bdy = last_wy + last_wh/2; - bdskinny = 32; - - if (persist_start == 0.0) { - bdpush = 0; - } else { - set_bdpush(SCR_KEY, &last_bdpush, &bdpush); - } - - dtime0(&tm); - age = max_age; - dret = push_scr_ev(&age, SCR_KEY, bdpush, bdx, bdy, bdskinny); - dt = dtime(&tm); - - ret = 1 + dret; - scr_ev_cnt = 0; - - if (ret == 2 && xrecord_scroll_keysym(last_rfb_keysym)) { - int repeating; - double time_lo = 1.0/max_keyrepeat_lo; - double time_hi = 1.0/max_keyrepeat_hi; - double rate = typing_rate(0.0, &repeating); -if (0 || db) fprintf(stderr, "Typing: dt: %.4f rate: %.1f\n", dt, rate); - if (repeating) { - /* n.b. the "quantum" is about 1/30 sec. */ - max_keyrepeat_time = 1.0*dt; - if (max_keyrepeat_time > time_lo || - max_keyrepeat_time < time_hi) { - max_keyrepeat_time = 0.0; - } else { - set_repeat = max_keyrepeat_time; -if (0 || db) fprintf(stderr, "set max_keyrepeat_time: %.2f\n", max_keyrepeat_time); - } - } - } - - last_scr_ev = dnow(); - } - - if ((got_one && ret < 2) || persist_count) { - set_xdamage_mark(last_wx, last_wy, last_ww, last_wh); - } - - if (fail) { - scrollability(xrecord_ptr_window, SCR_FAIL); - } - - if (xrecording) { - if (ret < 2) { - xrecord_watch(0, SCR_KEY); - } - } - - if (ret == 2) { - if (persist_start == 0.0) { - dtime(&persist_start); - last_bdpush = persist_start; - } - } else { - persist_start = 0.0; - last_bdpush = 0.0; - } - - /* since we've flushed it, we might as well avoid -input_skip */ - if (flush1 || flush2) { - got_keyboard_input = 0; - got_pointer_input = 0; - } - - return ret; -} - -int check_xrecord_mouse(void) { - static int last_wx, last_wy, last_ww, last_wh; - double spin = 0.0, tm, tnow; - int i, scr_cnt = 0, input = 0, scroll_rep; - int get_out, got_one = 0, flush1 = 0, flush2 = 0; - int gp, gp0, ret = 0, db = debug_scroll; - int gk, gk0; - int fail = 0; - int link, latency, netrate; - - int start_x, start_y, last_x, last_y; - static double last_mouse_scroll = 0.0; - double last_scroll; - double max_spin[3], max_long[3], persist[3]; - double flush1_time = 0.01; - static double last_flush = 0.0; - double last_bdpush = 0.0, button_up_time = 0.0; - int button_mask_save; - int already_down = 0, max_ptr_eat = 20; - static int want_back_in = 0; - int came_back_in; - - int scroll_wheel = 0; - int btn4 = (1<<3); - int btn5 = (1<<4); - - get_out = 1; - if (button_mask) { - get_out = 0; - } - if (want_back_in) { - get_out = 0; - } - dtime0(&tnow); -if (0) fprintf(stderr, "check_xrecord_mouse: IN xrecording: %d\n", xrecording); - - if (get_out) { - if (xrecording) { - xrecord_watch(0, SCR_MOUSE); - } - return 0; - } - - scroll_rep = scrollability(xrecord_ptr_window, SCR_NONE) + 1; - if (scroll_rep == 1) { - scroll_rep = 2; /* if no info, assume the best. */ - } - - if (button_mask_prev) { - already_down = 1; - } - if (want_back_in) { - came_back_in = 1; - } else { - came_back_in = 0; - } - want_back_in = 0; - - if (button_mask & (btn4|btn5)) { - scroll_wheel = 1; - } - - /* - * set up times for the various "reputations" - * - * 0 => -1, has been tried but never found a scroll. - * 1 => 0, has not been tried. - * 2 => +1, has been tried and found a scroll. - */ - - /* first spin-out time (no events) */ - max_spin[0] = 1*scr_mouse_time; - max_spin[1] = 2*scr_mouse_time; - max_spin[2] = 4*scr_mouse_time; - if (!already_down) { - for (i=0; i<3; i++) { - max_spin[i] *= 1.5; - } - } - - /* max time between events */ - persist[0] = 1*scr_mouse_persist; - persist[1] = 2*scr_mouse_persist; - persist[2] = 4*scr_mouse_persist; - - /* absolute max time in the loop */ - max_long[0] = scr_mouse_maxtime; - max_long[1] = scr_mouse_maxtime; - max_long[2] = scr_mouse_maxtime; - - pointer_flush_delay = scr_mouse_pointer_delay; - - /* slow links: */ - link = link_rate(&latency, &netrate); - if (link == LR_DIALUP) { - for (i=0; i<3; i++) { - max_spin[i] *= 2.0; - } - pointer_flush_delay *= 2; - } else if (link == LR_BROADBAND) { - pointer_flush_delay *= 2; - } - - gp = gp0 = got_pointer_input; - gk = gk0 = got_keyboard_input; - dtime0(&tm); - - /* - * this is used for border pushes (bdpush) to guess location - * of scrollbar (region rects containing this point are pushed). - */ - last_x = start_x = cursor_x; - last_y = start_y = cursor_y; - -if (db) fprintf(stderr, "check_xrecord_mouse: BEGIN LOOP: scr_ev_cnt: " - "%d max: %.3f %.4f\n", scr_ev_cnt, max_spin[scroll_rep], tm - x11vnc_start); - - while (1) { - double spin_check; - if (scr_ev_cnt) { - int dret, ev = scr_ev_cnt - 1; - int bdpush = 0, bdx, bdy, bdskinny; - double tm, dt, age = 0.35; - - got_one = 1; - scrollability(xrecord_ptr_window, SCR_SUCCESS); - scroll_rep = 2; - - scr_cnt++; - - dtime0(&last_scroll); - last_mouse_scroll = last_scroll; - - if (last_bdpush == 0.0) { - last_bdpush = last_scroll; - } - - bdx = start_x; - bdy = start_y; - if (clipshift) { - bdx += coff_x; - bdy += coff_y; - } - if (subwin) { - bdx += off_x; - bdy += off_y; - } - bdskinny = 32; - - set_bdpush(SCR_MOUSE, &last_bdpush, &bdpush); - - dtime0(&tm); - - dret = push_scr_ev(&age, SCR_MOUSE, bdpush, bdx, - bdy, bdskinny); - ret = 1 + dret; - - dt = dtime(&tm); - -if (db) fprintf(stderr, " dret: %d scr_ev_cnt: %d dt: %.4f\n", - dret, scr_ev_cnt, dt); - - last_wx = scr_ev[ev].win_x; - last_wy = scr_ev[ev].win_y; - last_ww = scr_ev[ev].win_w; - last_wh = scr_ev[ev].win_h; - scr_ev_cnt = 0; - - if (! dret) { - break; - } - if (0 && button_up_time > 0.0) { - /* we only take 1 more event with button up */ -if (db) fprintf(stderr, "check_xrecord: BUTTON_UP_SCROLL: %.3f\n", spin); - break; - } - } - - - if (! flush1) { - if (! already_down || (!scr_cnt && spin>flush1_time)) { - flush1 = 1; - X_LOCK; - XFlush(dpy); - X_UNLOCK; - dtime0(&last_flush); - } - } - - if (use_threads) { - usleep(1000); - } else { - rfbCFD(1000); - rfbCFD(0); - } - spin += dtime(&tm); - - if (got_pointer_input > gp) { - flush2 = 1; - input += eat_pointer(max_ptr_eat, 1); - gp = got_pointer_input; - } - if (got_keyboard_input > gk) { - gk = got_keyboard_input; - input++; - } - X_LOCK; -#if LIBVNCSERVER_HAVE_RECORD - SCR_LOCK; - XRecordProcessReplies(rdpy_data); - SCR_UNLOCK; -#endif - X_UNLOCK; - - if (! input) { - spin_check = 1.5 * max_spin[scroll_rep]; - } else { - spin_check = max_spin[scroll_rep]; - } - - if (button_up_time > 0.0) { - if (tm > button_up_time + max_spin[scroll_rep]) { -if (db) fprintf(stderr, "check_xrecord: SPIN-OUT-BUTTON_UP: %.3f/%.3f\n", spin, tm - button_up_time); - break; - } - } else if (!scr_cnt) { - if (spin >= spin_check) { - -if (db) fprintf(stderr, "check_xrecord: SPIN-OUT-1: %.3f/%.3f\n", spin, spin_check); - fail = 1; - break; - } - } else { - if (tm >= last_scroll + persist[scroll_rep]) { - -if (db) fprintf(stderr, "check_xrecord: SPIN-OUT-2: %.3f/%.3f\n", spin, tm - last_scroll); - break; - } - } - if (spin >= max_long[scroll_rep]) { - -if (db) fprintf(stderr, "check_xrecord: SPIN-OUT-3: %.3f/%.3f\n", spin, max_long[scroll_rep]); - break; - } - - if (! button_mask) { - int doflush = 0; - if (button_up_time > 0.0) { - ; - } else if (came_back_in) { - dtime0(&button_up_time); - doflush = 1; - } else if (scroll_wheel) { -if (db) fprintf(stderr, "check_xrecord: SCROLL-WHEEL-BUTTON-UP-KEEP-GOING: %.3f/%.3f %d/%d %d/%d\n", spin, max_long[scroll_rep], last_x, last_y, cursor_x, cursor_y); - doflush = 1; - dtime0(&button_up_time); - } else if (last_x == cursor_x && last_y == cursor_y) { -if (db) fprintf(stderr, "check_xrecord: BUTTON-UP: %.3f/%.3f %d/%d %d/%d\n", spin, max_long[scroll_rep], last_x, last_y, cursor_x, cursor_y); - break; - } else { -if (db) fprintf(stderr, "check_xrecord: BUTTON-UP-KEEP-GOING: %.3f/%.3f %d/%d %d/%d\n", spin, max_long[scroll_rep], last_x, last_y, cursor_x, cursor_y); - doflush = 1; - dtime0(&button_up_time); - } - if (doflush) { - flush1 = 1; - X_LOCK; - XFlush(dpy); - X_UNLOCK; - dtime0(&last_flush); - } - } - - last_x = cursor_x; - last_y = cursor_y; - } - - if (got_one) { - set_xdamage_mark(last_wx, last_wy, last_ww, last_wh); - } - - if (fail) { - scrollability(xrecord_ptr_window, SCR_FAIL); - } - - /* flush any remaining pointer events. */ - button_mask_save = button_mask; - pointer_queued_sent = 0; - last_x = cursor_x; - last_y = cursor_y; - pointer(-1, 0, 0, NULL); - pointer_flush_delay = 0.0; - - if (xrecording && pointer_queued_sent && button_mask_save && - (last_x != cursor_x || last_y != cursor_y) ) { -if (db) fprintf(stderr, " pointer() push yields events on: ret=%d\n", ret); - if (ret == 2) { -if (db) fprintf(stderr, " we decide to send ret=3\n"); - want_back_in = 1; - ret = 3; - flush2 = 1; - } else { - if (ret) { - ret = 1; - } else { - ret = 0; - } - xrecord_watch(0, SCR_MOUSE); - } - } else { - if (ret) { - ret = 1; - } else { - ret = 0; - } - if (xrecording) { - xrecord_watch(0, SCR_MOUSE); - } - } - - if (flush2) { - X_LOCK; - XFlush(dpy); - XFlush(rdpy_ctrl); - X_UNLOCK; - - flush2 = 1; - dtime0(&last_flush); - -if (db) fprintf(stderr, "FLUSH-2\n"); - } - - /* since we've flushed it, we might as well avoid -input_skip */ - if (flush1 || flush2) { - got_keyboard_input = 0; - got_pointer_input = 0; - } - - if (ret) { - return ret; - } else if (scr_cnt) { - return 1; - } else { - return 0; - } -} - -int check_xrecord(void) { - int watch_keys = 0, watch_mouse = 0, consider_mouse; - static int mouse_wants_back_in = 0; - - if (! use_xrecord) { - return 0; - } - if (skip_cr_when_scaling("scroll")) { - return 0; - } - -if (0) fprintf(stderr, "check_xrecord: IN xrecording: %d\n", xrecording); - - if (! xrecording) { - return 0; - } - - if (!strcmp(scroll_copyrect, "always")) { - watch_keys = 1; - watch_mouse = 1; - } else if (!strcmp(scroll_copyrect, "keys")) { - watch_keys = 1; - } else if (!strcmp(scroll_copyrect, "mouse")) { - watch_mouse = 1; - } - - if (button_mask || mouse_wants_back_in) { - consider_mouse = 1; - } else { - consider_mouse = 0; - } -if (0) fprintf(stderr, "check_xrecord: button_mask: %d mouse_wants_back_in: %d\n", button_mask, mouse_wants_back_in); - - if (watch_mouse && consider_mouse && xrecord_set_by_mouse) { - int ret = check_xrecord_mouse(); - if (ret == 3) { - mouse_wants_back_in = 1; - } else { - mouse_wants_back_in = 0; - } - return ret; - } else if (watch_keys && xrecord_set_by_keys) { - mouse_wants_back_in = 0; - return check_xrecord_keys(); - } else { - mouse_wants_back_in = 0; - return 0; - } -} - -#define DB_SET \ - int db = 0; \ - int db2 = 0; \ - if (debug_wireframe == 1) { \ - db = 1; \ - } \ - if (debug_wireframe == 2) { \ - db2 = 1; \ - } \ - if (debug_wireframe == 3) { \ - db = 1; \ - db2 = 1; \ - } - -int try_copyrect(Window frame, int x, int y, int w, int h, int dx, int dy, - int *obscured, sraRegionPtr extra_clip, double max_wait) { - - static int dt_bad = 0; - static time_t dt_bad_check = 0; - int x1, y1, x2, y2, sent_copyrect = 0; - int req, mod, cpy, ncli; - double tm, dt; - DB_SET - - get_client_regions(&req, &mod, &cpy, &ncli); - if (cpy) { - /* one is still pending... try to force it out: */ - fb_push_wait(max_wait, FB_COPY); - - get_client_regions(&req, &mod, &cpy, &ncli); - } - if (cpy) { - return 0; - } - - *obscured = 0; - /* - * XXX KDE and xfce do some weird things with the - * stacking, it does not match XQueryTree. Work around - * it for now by CopyRect-ing the *whole* on-screen - * rectangle (whether obscured or not!) - */ - if (time(0) > dt_bad_check + 5) { - char *dt = guess_desktop(); - if (!strcmp(dt, "kde")) { - dt_bad = 1; - } else if (!strcmp(dt, "xfce")) { - dt_bad = 1; - } else { - dt_bad = 0; - } - dt_bad_check = time(0); - } - - if (clipshift) { - x -= coff_x; - y -= coff_y; - } - if (subwin) { - x -= off_x; - y -= off_y; - } - - if (dt_bad && wireframe_in_progress) { - sraRegionPtr rect; - /* send the whole thing... */ - x1 = crfix(nfix(x, dpy_x), dx, dpy_x); - y1 = crfix(nfix(y, dpy_y), dy, dpy_y); - x2 = crfix(nfix(x+w, dpy_x+1), dx, dpy_x+1); - y2 = crfix(nfix(y+h, dpy_y+1), dy, dpy_y+1); - - rect = sraRgnCreateRect(x1, y1, x2, y2); - - if (blackouts) { - int i; - sraRegionPtr bo_rect; - for (i=0; i<blackouts; i++) { - bo_rect = sraRgnCreateRect(blackr[i].x1, - blackr[i].y1, blackr[i].x2, blackr[i].y2); - sraRgnSubtract(rect, bo_rect); - sraRgnDestroy(bo_rect); - } - } - do_copyregion(rect, dx, dy); - sraRgnDestroy(rect); - - sent_copyrect = 1; - *obscured = 1; /* set to avoid an aggressive push */ - - } else if (stack_list_num || dt_bad) { - int k, tx1, tx2, ty1, ty2; - sraRegionPtr moved_win, tmp_win, whole; - sraRectangleIterator *iter; - sraRect rect; - int saw_me = 0; - int orig_x, orig_y; - XWindowAttributes attr; - - orig_x = x - dx; - orig_y = y - dy; - - tx1 = nfix(orig_x, dpy_x); - ty1 = nfix(orig_y, dpy_y); - tx2 = nfix(orig_x+w, dpy_x+1); - ty2 = nfix(orig_y+h, dpy_y+1); - -if (db2) fprintf(stderr, "moved_win: %4d %3d, %4d %3d 0x%lx ---\n", - tx1, ty1, tx2, ty2, frame); - - moved_win = sraRgnCreateRect(tx1, ty1, tx2, ty2); - - dtime0(&tm); - - X_LOCK; - - /* - * loop over the stack, top to bottom until we - * find our wm frame: - */ - for (k = stack_list_num - 1; k >= 0; k--) { - Window swin; - - if (0 && dt_bad) { - break; - } - - swin = stack_list[k].win; - if (swin == frame) { -if (db2) { -saw_me = 1; fprintf(stderr, " ----------\n"); -} else { - break; -} - } -#if 0 -fprintf(stderr, "bo: %d/%lx\n", k, swin); -#endif - - /* skip some unwanted cases: */ - if (swin == None) { - continue; - } - if (swin < 10) { - ; /* blackouts */ - } else if (! stack_list[k].fetched || - stack_list[k].time > tm + 2.0) { - if (!valid_window(swin, &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; - } - stack_list[k].fetched = 1; - stack_list[k].time = tm; - } - if (!stack_list[k].valid) { - continue; - } - - attr.x = stack_list[k].x; - attr.y = stack_list[k].y; - attr.depth = stack_list[k].depth; - attr.width = stack_list[k].width; - attr.height = stack_list[k].height; - attr.map_state = stack_list[k].map_state; - - if (attr.map_state != IsViewable) { - continue; - } - - if (clipshift) { - attr.x -= coff_x; - attr.y -= coff_y; - } - if (subwin) { - attr.x -= off_x; - attr.y -= off_y; - } - - /* - * first subtract any overlap from the initial - * window rectangle - */ - - /* clip the window to the visible screen: */ - tx1 = nfix(attr.x, dpy_x); - ty1 = nfix(attr.y, dpy_y); - tx2 = nfix(attr.x + attr.width, dpy_x+1); - ty2 = nfix(attr.y + attr.height, dpy_y+1); - -if (db2) fprintf(stderr, " tmp_win-1: %4d %3d, %4d %3d 0x%lx\n", - tx1, ty1, tx2, ty2, swin); -if (db2 && saw_me) continue; - - /* see if window clips us: */ - tmp_win = sraRgnCreateRect(tx1, ty1, tx2, ty2); - if (sraRgnAnd(tmp_win, moved_win)) { - *obscured = 1; -if (db2) fprintf(stderr, " : clips it.\n"); - } - sraRgnDestroy(tmp_win); - - /* subtract it from our region: */ - tmp_win = sraRgnCreateRect(tx1, ty1, tx2, ty2); - sraRgnSubtract(moved_win, tmp_win); - sraRgnDestroy(tmp_win); - - /* - * next, subtract from the initial window rectangle - * anything that would clip it. - */ - - /* clip the window to the visible screen: */ - tx1 = nfix(attr.x - dx, dpy_x); - ty1 = nfix(attr.y - dy, dpy_y); - tx2 = nfix(attr.x - dx + attr.width, dpy_x+1); - ty2 = nfix(attr.y - dy + attr.height, dpy_y+1); - -if (db2) fprintf(stderr, " tmp_win-2: %4d %3d, %4d %3d 0x%lx\n", - tx1, ty1, tx2, ty2, swin); -if (db2 && saw_me) continue; - - /* subtract it from our region: */ - tmp_win = sraRgnCreateRect(tx1, ty1, tx2, ty2); - sraRgnSubtract(moved_win, tmp_win); - sraRgnDestroy(tmp_win); - } - X_UNLOCK; - - if (extra_clip && ! sraRgnEmpty(extra_clip)) { - whole = sraRgnCreateRect(0, 0, dpy_x, dpy_y); - - if (clipshift) { - sraRgnOffset(extra_clip, -coff_x, -coff_y); - } - if (subwin) { - sraRgnOffset(extra_clip, -off_x, -off_y); - } - - iter = sraRgnGetIterator(extra_clip); - while (sraRgnIteratorNext(iter, &rect)) { - /* clip the window to the visible screen: */ - tx1 = rect.x1; - ty1 = rect.y1; - tx2 = rect.x2; - ty2 = rect.y2; - tmp_win = sraRgnCreateRect(tx1, ty1, tx2, ty2); - sraRgnAnd(tmp_win, whole); - - /* see if window clips us: */ - if (sraRgnAnd(tmp_win, moved_win)) { - *obscured = 1; - } - sraRgnDestroy(tmp_win); - - /* subtract it from our region: */ - tmp_win = sraRgnCreateRect(tx1, ty1, tx2, ty2); - sraRgnSubtract(moved_win, tmp_win); - sraRgnDestroy(tmp_win); - - /* - * next, subtract from the initial window rectangle - * anything that would clip it. - */ - tmp_win = sraRgnCreateRect(tx1, ty1, tx2, ty2); - sraRgnOffset(tmp_win, -dx, -dy); - - /* clip the window to the visible screen: */ - sraRgnAnd(tmp_win, whole); - - /* subtract it from our region: */ - sraRgnSubtract(moved_win, tmp_win); - sraRgnDestroy(tmp_win); - } - sraRgnReleaseIterator(iter); - sraRgnDestroy(whole); - } - - dt = dtime(&tm); -if (db2) fprintf(stderr, " stack_work dt: %.4f\n", dt); - - if (*obscured && !strcmp(wireframe_copyrect, "top")) { - ; /* cannot send CopyRegion */ - } else if (! sraRgnEmpty(moved_win)) { - sraRegionPtr whole, shifted_region; - - whole = sraRgnCreateRect(0, 0, dpy_x, dpy_y); - shifted_region = sraRgnCreateRgn(moved_win); - sraRgnOffset(shifted_region, dx, dy); - sraRgnAnd(shifted_region, whole); - - sraRgnDestroy(whole); - - /* now send the CopyRegion: */ - if (! sraRgnEmpty(shifted_region)) { - dtime0(&tm); - do_copyregion(shifted_region, dx, dy); - dt = dtime(&tm); -if (0 || db2) fprintf(stderr, "do_copyregion: %d %d %d %d dx: %d dy: %d dt: %.4f\n", - tx1, ty1, tx2, ty2, dx, dy, dt); - sent_copyrect = 1; - } - sraRgnDestroy(shifted_region); - } - sraRgnDestroy(moved_win); - } - return sent_copyrect; -} - -int near_wm_edge(int x, int y, int w, int h, int px, int py) { - /* heuristics: */ - int wf_t = wireframe_top; - int wf_b = wireframe_bot; - int wf_l = wireframe_left; - int wf_r = wireframe_right; - - int near_edge = 0; - - if (wf_t || wf_b || wf_l || wf_r) { - if (nabs(y - py) < wf_t) { - near_edge = 1; - } - if (nabs(y + h - py) < wf_b) { - near_edge = 1; - } - if (nabs(x - px) < wf_l) { - near_edge = 1; - } - if (nabs(x + w - px) < wf_r) { - near_edge = 1; - } - } else { - /* all zero; always "near" edge: */ - near_edge = 1; - } - return near_edge; -} - -int near_scrollbar_edge(int x, int y, int w, int h, int px, int py) { - /* heuristics: */ - int sb_t = scrollcopyrect_top; - int sb_b = scrollcopyrect_bot; - int sb_l = scrollcopyrect_left; - int sb_r = scrollcopyrect_right; - - int near_edge = 0; - - if (sb_t || sb_b || sb_l || sb_r) { - if (nabs(y - py) < sb_t) { - near_edge = 1; - } - if (nabs(y + h - py) < sb_b) { - near_edge = 1; - } - if (nabs(x - px) < sb_l) { - near_edge = 1; - } - if (nabs(x + w - px) < sb_r) { - near_edge = 1; - } - } else { - /* all zero; always "near" edge: */ - near_edge = 1; - } - return near_edge; -} - -void check_fixscreen(void) { - double now = dnow(); - int didfull = 0, db = 0; - - if (!client_count) { - return; - } - - if (screen_fixup_X > 0.0) { - static double last = 0.0; - if (now > last + screen_fixup_X) { - if (db) rfbLog("doing screen_fixup_X\n"); - do_copy_screen = 1; - last = now; - didfull = 1; - } - - } - if (screen_fixup_V > 0.0) { - static double last = 0.0; - if (now > last + screen_fixup_V) { - if (! didfull) { - refresh_screen(0); - if (db) rfbLog("doing screen_fixup_V\n"); - } - last = now; - didfull = 1; - } - } - if (screen_fixup_C > 0.0) { - static double last = 0.0; - if (last_copyrect_fix < last_copyrect && - now > last_copyrect + screen_fixup_C) { - if (! didfull) { - refresh_screen(0); - if (db) rfbLog("doing screen_fixup_C\n"); - } - last_copyrect_fix = now; - last = now; - didfull = 1; - } - } - if (scaling && last_copyrect_fix < last_copyrect) { - static double last = 0.0; - double delay = 3.0; - if (now > last + delay) { - if (! didfull) { - scale_and_mark_rect(0, 0, dpy_x, dpy_y); - if (db) rfbLog("doing scale screen_fixup\n"); - } - last_copyrect_fix = now; - last = now; - didfull = 1; - } - } -} - -int wireframe_mod_state() { - if (! wireframe_mods) { - return 0; - } - if (!strcmp(wireframe_mods, "all")) { - if (track_mod_state(NoSymbol, FALSE, FALSE)) { - return 1; - } else { - return 0; - } - - } else if (!strcmp(wireframe_mods, "Alt")) { - if (track_mod_state(XK_Alt_L, FALSE, FALSE) == 1) { - return 1; - } else if (track_mod_state(XK_Alt_R, FALSE, FALSE) == 1) { - return 1; - } - } else if (!strcmp(wireframe_mods, "Shift")) { - if (track_mod_state(XK_Shift_L, FALSE, FALSE) == 1) { - return 1; - } else if (track_mod_state(XK_Shift_R, FALSE, FALSE) == 1) { - return 1; - } - } else if (!strcmp(wireframe_mods, "Control")) { - if (track_mod_state(XK_Control_L, FALSE, FALSE) == 1) { - return 1; - } else if (track_mod_state(XK_Control_R, FALSE, FALSE) == 1) { - return 1; - } - } else if (!strcmp(wireframe_mods, "Meta")) { - if (track_mod_state(XK_Meta_L, FALSE, FALSE) == 1) { - return 1; - } else if (track_mod_state(XK_Meta_R, FALSE, FALSE) == 1) { - return 1; - } - } else if (!strcmp(wireframe_mods, "Super")) { - if (track_mod_state(XK_Super_L, FALSE, FALSE) == 1) { - return 1; - } else if (track_mod_state(XK_Super_R, FALSE, FALSE) == 1) { - return 1; - } - } else if (!strcmp(wireframe_mods, "Hyper")) { - if (track_mod_state(XK_Hyper_L, FALSE, FALSE) == 1) { - return 1; - } else if (track_mod_state(XK_Hyper_R, FALSE, FALSE) == 1) { - return 1; - } - } - return 0; -} - -/* - * Applied just before any check_user_input() modes. Look for a - * ButtonPress; find window it happened in; find the wm frame window - * for it; watch for that window moving or resizing. If it does, do the - * wireframe animation. Do this until ButtonRelease or timeouts occur. - * Remove wireframe. - * - * Under -nowirecopyrect, return control to base scheme - * (check_user_input() ...) that will repaint the screen with the window - * in the new postion or size. Under -wirecopyrect, apply rfbDoCopyRect - * or rfbDoCopyRegion: this "pollutes" our framebuffer, but the normal - * polling will quickly repair it. Under happy circumstances, this - * reduces actual XShmGetImage work (i.e. if we correctly predicted how - * the X fb has changed. - * - * -scale doesn't always work under -wirecopyrect, but the wireframe does. - * - * testing of this mode under -threads is incomplete. - * - * returns 1 if it did an animation, 0 if no move/resize triggers - * went off. - * - * TBD: see if we can select StructureNotify ConfigureNotify events for - * the toplevel windows to get better info on moves and resizes. - */ -int check_wireframe(void) { - Window frame, orig_frame; - XWindowAttributes attr; - int dx, dy; - - int orig_px, orig_py, orig_x, orig_y, orig_w, orig_h; - int px, py, x, y, w, h; - int box_x, box_y, box_w, box_h; - int orig_cursor_x, orig_cursor_y, g; - int already_down = 0, win_gone = 0, win_unmapped = 0; - double spin = 0.0, tm, last_ptr, last_draw; - int frame_changed = 0, drew_box = 0, got_2nd_pointer = 0; - int special_t1 = 0, break_reason = 0; - static double first_dt_ave = 0.0; - static int first_dt_cnt = 0; - static time_t last_save_stacklist = 0; - - /* heuristics: */ - double first_event_spin = wireframe_t1; - double frame_changed_spin = wireframe_t2; - double max_spin = wireframe_t3; - double min_draw = wireframe_t4; - int try_it = 0; - DB_SET - - if (nofb) { - return 0; - } - if (subwin) { - return 0; /* don't even bother for -id case */ - } - if (! button_mask) { - return 0; /* no button pressed down */ - } - if (!use_threads && !got_pointer_input) { - return 0; /* need ptr input, e.g. button down, motion */ - } - -if (db) fprintf(stderr, "\n*** button down!! x: %d y: %d\n", cursor_x, cursor_y); - - /* - * Query where the pointer is and which child of the root - * window. We will assume this is the frame the window manager - * makes when it reparents the toplevel window. - */ - X_LOCK; - if (! get_wm_frame_pos(&px, &py, &x, &y, &w, &h, &frame, NULL)) { -if (db) fprintf(stderr, "NO get_wm_frame_pos: 0x%lx\n", frame); - X_UNLOCK; - return 0; - } - X_UNLOCK; -if (db) fprintf(stderr, "a: %d wf: %.3f A: %d\n", w*h, wireframe_frac, (dpy_x*dpy_y)); - - /* - * apply the percentage size criterion (allow opaque moves for - * small windows) - */ - if ((double) w*h < wireframe_frac * (dpy_x * dpy_y)) { -if (db) fprintf(stderr, "small window %.3f\n", ((double) w*h)/(dpy_x * dpy_y)); - return 0; - } -if (db) fprintf(stderr, " frame: x: %d y: %d w: %d h: %d px: %d py: %d fr: 0x%lx\n", x, y, w, h, px, py, orig_frame); - - /* - * see if the pointer is within range of the assumed wm frame - * decorations on the edge of the window. - */ - - try_it = near_wm_edge(x, y, w, h, px, py); - - /* Often Alt+ButtonDown starts a window move: */ - if (! try_it && wireframe_mod_state()) { - try_it = 1; - } - if (! try_it) { -if (db) fprintf(stderr, "INTERIOR\n"); - return 0; - } - - wireframe_in_progress = 1; - - if (button_mask_prev) { - already_down = 1; - } - - if (! wireframe_str || !strcmp(wireframe_str, WIREFRAME_PARMS)) { - int link, latency, netrate; - static int didmsg = 0; - - link = link_rate(&latency, &netrate); - if (link == LR_DIALUP || link == LR_BROADBAND) { - /* slow link, e.g. dialup, increase timeouts: */ - first_event_spin *= 2.0; - frame_changed_spin *= 2.0; - max_spin *= 2.0; - min_draw *= 1.5; - if (! didmsg) { - rfbLog("increased wireframe timeouts for " - "slow network connection.\n"); - rfbLog("netrate: %d KB/sec, latency: %d ms\n", - netrate, latency); - didmsg = 1; - } - } - } - - /* - * pointer() should have snapped the stacking list for us, if - * not, do it now (if the XFakeButtonEvent has been flushed by - * now the stacking order may be incorrect). - */ - if (strcmp(wireframe_copyrect, "never")) { - if (already_down) { - double age = 0.0; - /* - * see if we can reuse the stack list (pause - * with button down) - */ - if (stack_list_num) { - int k, got_me = 0; - for (k = stack_list_num -1; k >=0; k--) { - if (frame == stack_list[k].win) { - got_me = 1; - break; - } - } - if (got_me) { - age = 1.0; - } - snapshot_stack_list(0, age); - } - } - if (! stack_list_num) { - snapshot_stack_list(0, 0.0); - } - } - - - /* store initial parameters, we look for changes in them */ - orig_frame = frame; - orig_px = px; /* pointer position */ - orig_py = py; - orig_x = x; /* frame position */ - orig_y = y; - orig_w = w; /* frame size */ - orig_h = h; - - orig_cursor_x = cursor_x; - orig_cursor_y = cursor_y; - - /* this is the box frame we would draw */ - box_x = x; - box_y = y; - box_w = w; - box_h = h; - - dtime0(&tm); - - last_draw = spin; - - /* -threads support for check_wireframe() is rough... crash? */ - if (use_threads) { - /* purge any stored up pointer events: */ - pointer(-1, 0, 0, NULL); - } - - g = got_pointer_input; - - while (1) { - - X_LOCK; - XFlush(dpy); - X_UNLOCK; - - /* try do induce/waitfor some more user input */ - if (use_threads) { - usleep(1000); - } else if (drew_box) { - rfbPE(1000); - } else { - rfbCFD(1000); - } - - spin += dtime(&tm); - -if (0) fprintf(stderr, "wf-spin: %.3f\n", spin); - - /* check for any timeouts: */ - if (frame_changed) { - double delay; - /* max time we play this game: */ - if (spin > max_spin) { -if (db || db2) fprintf(stderr, " SPIN-OUT-MAX: %.3f\n", spin); - break_reason = 1; - break; - } - /* watch for pointer events slowing down: */ - if (special_t1) { - delay = max_spin; - } else { - delay = 2.0* frame_changed_spin; - if (spin > 3.0 * frame_changed_spin) { - delay = 1.5 * delay; - } - } - if (spin > last_ptr + delay) { -if (db || db2) fprintf(stderr, " SPIN-OUT-NOT-FAST: %.3f\n", spin); - break_reason = 2; - break; - } - } else if (got_2nd_pointer) { - /* - * pointer is moving, max time we wait for wm - * move or resize to be detected - */ - if (spin > frame_changed_spin) { -if (db || db2) fprintf(stderr, " SPIN-OUT-NOFRAME-SPIN: %.3f\n", spin); - break_reason = 3; - break; - } - } else { - /* max time we wait for any pointer input */ - if (spin > first_event_spin) { -if (db || db2) fprintf(stderr, " SPIN-OUT-NO2ND_PTR: %.3f\n", spin); - break_reason = 4; - break; - } - } - - /* see if some pointer input occurred: */ - if (got_pointer_input > g) { -if (db) fprintf(stderr, " ++pointer event!! [%02d] dt: %.3f x: %d y: %d mask: %d\n", got_2nd_pointer+1, spin, cursor_x, cursor_y, button_mask); - - g = got_pointer_input; - - X_LOCK; - XFlush(dpy); - X_UNLOCK; - - /* periodically try to let the wm get moving: */ - if (!frame_changed && got_2nd_pointer % 4 == 0) { - if (got_2nd_pointer == 0) { - usleep(50 * 1000); - } else { - usleep(25 * 1000); - } - } - got_2nd_pointer++; - last_ptr = spin; - - /* - * see where the pointer currently is. It may - * not be our starting frame (i.e. mouse now - * outside of the moving window). - */ - frame = 0x0; - X_LOCK; - - if (! get_wm_frame_pos(&px, &py, &x, &y, &w, &h, - &frame, NULL)) { - frame = 0x0; -if (db) fprintf(stderr, "NO get_wm_frame_pos: 0x%lx\n", frame); - } - - if (frame != orig_frame) { - /* see if our original frame is still there */ - if (!valid_window(orig_frame, &attr, 1)) { - X_UNLOCK; - /* our window frame went away! */ - win_gone = 1; -if (db) fprintf(stderr, "FRAME-GONE: 0x%lx\n", orig_frame); - break_reason = 5; - break; - } - if (attr.map_state == IsUnmapped) { - X_UNLOCK; - /* our window frame is now unmapped! */ - win_unmapped = 1; -if (db) fprintf(stderr, "FRAME-UNMAPPED: 0x%lx\n", orig_frame); - break_reason = 5; - break; - } - -if (db) fprintf(stderr, "OUT-OF-FRAME: old: x: %d y: %d px: %d py: %d 0x%lx\n", x, y, px, py, frame); - - /* new parameters for our frame */ - x = attr.x; /* n.b. rootwin is parent */ - y = attr.y; - w = attr.width; - h = attr.height; - } - X_UNLOCK; - -if (db) fprintf(stderr, " frame: x: %d y: %d w: %d h: %d px: %d py: %d fr: 0x%lx\n", x, y, w, h, px, py, frame); -if (db) fprintf(stderr, " MO,PT,FR: %d/%d %d/%d %d/%d\n", cursor_x - orig_cursor_x, cursor_y - orig_cursor_y, px - orig_px, py - orig_py, x - orig_x, y - orig_y); - - if (frame_changed && frame != orig_frame) { -if (db) fprintf(stderr, "CHANGED and window switch: 0x%lx\n", frame); - } - if (frame_changed && px - orig_px != x - orig_x) { -if (db) fprintf(stderr, "MOVED and diff DX\n"); - } - if (frame_changed && py - orig_py != y - orig_y) { -if (db) fprintf(stderr, "MOVED and diff DY\n"); - } - - /* check and see if our frame has been resized: */ - if (!frame_changed && (w != orig_w || h != orig_h)) { - int n; - if (!already_down) { - first_dt_ave += spin; - first_dt_cnt++; - } - n = first_dt_cnt ? first_dt_cnt : 1; - frame_changed = 2; - -if (db) fprintf(stderr, "WIN RESIZE 1st-dt: %.3f\n", first_dt_ave/n); - } - - /* check and see if our frame has been moved: */ - if (!frame_changed && (x != orig_x || y != orig_y)) { - int n; - if (!already_down) { - first_dt_ave += spin; - first_dt_cnt++; - } - n = first_dt_cnt ? first_dt_cnt : 1; - frame_changed = 1; -if (db) fprintf(stderr, "FRAME MOVE 1st-dt: %.3f\n", first_dt_ave/n); - } - - /* - * see if it is time to draw any or a new wireframe box - */ - if (frame_changed) { - int drawit = 0; - if (x != box_x || y != box_y) { - /* moved since last */ - drawit = 1; - } else if (w != box_w || h != box_h) { - /* resize since last */ - drawit = 1; - } - if (drawit) { - /* - * check time (to avoid too much - * animations on slow machines - * or links). - */ - if (spin > last_draw + min_draw || - ! drew_box) { - draw_box(x, y, w, h, 0); - drew_box = 1; - rfbPE(1000); - last_draw = spin; - } - } - box_x = x; - box_y = y; - box_w = w; - box_h = h; - } - } - - /* - * Now (not earlier) check if the button has come back up. - * we check here to get a better location and size of - * the final window. - */ - if (! button_mask) { -if (db || db2) fprintf(stderr, "NO button_mask\n"); - break_reason = 6; - break; - } - } - - if (! drew_box) { - /* nice try, but no move or resize detected. cleanup. */ - if (stack_list_num) { - stack_list_num = 0; - } - wireframe_in_progress = 0; - return 0; - } - - /* remove the wireframe */ - draw_box(0, 0, 0, 0, 1); - - dx = x - orig_x; - dy = y - orig_y; - - /* - * see if we can apply CopyRect or CopyRegion to the change: - */ - if (!strcmp(wireframe_copyrect, "never")) { - ; - } else if (win_gone || win_unmapped) { - ; - } else if (skip_cr_when_scaling("wireframe")) { - ; - } else if (w != orig_w || h != orig_h) { - ; - } else if (dx == 0 && dy == 0) { - ; - } else { - int spin_ms = (int) (spin * 1000 * 1000); - int obscured, sent_copyrect = 0; - - /* - * set a timescale comparable to the spin time, - * but not too short or too long. - */ - if (spin_ms < 30) { - spin_ms = 30; - } else if (spin_ms > 400) { - spin_ms = 400; - } - - /* try to flush the wireframe removal: */ - fb_push_wait(0.1, FB_COPY|FB_MOD); - - /* try to send a clipped copyrect of translation: */ - sent_copyrect = try_copyrect(frame, x, y, w, h, dx, dy, - &obscured, NULL, 0.15); - -if (db) fprintf(stderr, "send_copyrect: %d\n", sent_copyrect); - if (sent_copyrect) { - /* try to push the changes to viewers: */ - if (! obscured) { - fb_push_wait(0.1, FB_COPY); - } else { - /* no diff for now... */ - fb_push_wait(0.1, FB_COPY); - } - if (scaling) { - static double last_time = 0.0; - double now = dnow(), delay = 0.35; - - fb_push_wait(0.1, FB_COPY); - - if (now > last_time + delay) { - int xt = x, yt = y; - - if (clipshift) { - xt -= coff_x; - yt -= coff_y; - } - if (subwin) { - xt -= off_x; - yt -= off_y; - } - - scale_mark(xt, yt, xt+w, yt+h); - last_time = now; - last_copyrect_fix = now; - } - } - } - } - - if (stack_list_num) { - /* clean up stack_list for next time: */ - if (break_reason == 1 || break_reason == 2) { - /* - * save the stack list, perhaps the user has - * paused with button down. - */ - last_save_stacklist = time(0); - } else { - stack_list_num = 0; - } - } - - /* final push (for -nowirecopyrect) */ - rfbPE(1000); - wireframe_in_progress = 0; - urgent_update = 1; - if (use_xdamage) { - /* DAMAGE can queue ~1000 rectangles for a move */ - clear_xdamage_mark_region(NULL, 1); - xdamage_scheduled_mark = dnow() + 2.0; - } - - return 1; -} - -/* - * We need to handle user input, particularly pointer input, carefully. - * This function is only called when non-threaded. Note that - * rfbProcessEvents() only processes *one* pointer event per call, - * so if we interlace it with scan_for_updates(), we can get swamped - * with queued up pointer inputs. And if the pointer inputs are inducing - * large changes on the screen (e.g. window drags), the whole thing - * bogs down miserably and only comes back to life at some time after - * one stops moving the mouse. So, to first approximation, we are trying - * to eat as much user input here as we can using some hints from the - * duration of the previous scan_for_updates() call (in dt). - * - * note: we do this even under -nofb - * - * return of 1 means watch_loop should short-circuit and reloop, - * return of 0 means watch_loop should proceed to scan_for_updates(). - * (this is for pointer_mode == 1 mode, the others do it all internally, - * cnt is also only for that mode). - */ - -static void check_user_input2(double dt) { - - int eaten = 0, miss = 0, max_eat = 50, do_flush = 1; - int g, g_in; - double spin = 0.0, tm; - double quick_spin_fac = 0.40; - double grind_spin_time = 0.175; - - dtime0(&tm); - g = g_in = got_pointer_input; - if (!got_pointer_input) { - return; - } - /* - * Try for some "quick" pointer input processing. - * - * About as fast as we can, we try to process user input calling - * rfbProcessEvents or rfbCheckFds. We do this for a time on - * order of the last scan_for_updates() time, dt, but if we stop - * getting user input we break out. We will also break out if - * we have processed max_eat inputs. - * - * Note that rfbCheckFds() does not send any framebuffer updates, - * so is more what we want here, although it is likely they have - * all be sent already. - */ - while (1) { - if (show_multiple_cursors) { - rfbPE(1000); - } else { - rfbCFD(1000); - } - rfbCFD(0); - - spin += dtime(&tm); - - if (spin > quick_spin_fac * dt) { - /* get out if spin time comparable to last scan time */ - break; - } - if (got_pointer_input > g) { - int i, max_extra = max_eat / 2; - g = got_pointer_input; - eaten++; - for (i=0; i<max_extra; i++) { - rfbCFD(0); - if (got_pointer_input > g) { - g = got_pointer_input; - eaten++; - } else if (i > 1) { - break; - } - } - X_LOCK; - do_flush = 0; -if (0) fprintf(stderr, "check_user_input2-A: XFlush %.4f\n", tm); - XFlush(dpy); - X_UNLOCK; - if (eaten < max_eat) { - continue; - } - } else { - miss++; - } - if (miss > 1) { /* 1 means out on 2nd miss */ - break; - } - } - if (do_flush) { - X_LOCK; -if (0) fprintf(stderr, "check_user_input2-B: XFlush %.4f\n", tm); - XFlush(dpy); - X_UNLOCK; - } - - - /* - * Probably grinding with a lot of fb I/O if dt is this large. - * (need to do this more elegantly) - * - * Current idea is to spin our wheels here *not* processing any - * fb I/O, but still processing the user input. This user input - * goes to the X display and changes it, but we don't poll it - * while we "rest" here for a time on order of dt, the previous - * scan_for_updates() time. We also break out if we miss enough - * user input. - */ - if (dt > grind_spin_time) { - int i, ms, split = 30; - double shim; - - /* - * Break up our pause into 'split' steps. We get at - * most one input per step. - */ - shim = 0.75 * dt / split; - - ms = (int) (1000 * shim); - - /* cutoff how long the pause can be */ - if (split * ms > 300) { - ms = 300 / split; - } - - spin = 0.0; - dtime0(&tm); - - g = got_pointer_input; - miss = 0; - for (i=0; i<split; i++) { - usleep(ms * 1000); - if (show_multiple_cursors) { - rfbPE(1000); - } else { - rfbCFD(1000); - } - spin += dtime(&tm); - if (got_pointer_input > g) { - int i, max_extra = max_eat / 2; - for (i=0; i<max_extra; i++) { - rfbCFD(0); - if (got_pointer_input > g) { - g = got_pointer_input; - } else if (i > 1) { - break; - } - } - X_LOCK; -if (0) fprintf(stderr, "check_user_input2-C: XFlush %.4f\n", tm); - XFlush(dpy); - X_UNLOCK; - miss = 0; - } else { - miss++; - } - g = got_pointer_input; - if (miss > 2) { - break; - } - if (1000 * spin > ms * split) { - break; - } - } - } -} - -static void check_user_input3(double dt, double dtr, int tile_diffs) { - - int allowed_misses, miss_tweak, i, g, g_in; - int last_was_miss, consecutive_misses; - double spin, spin_max, tm, to, dtm; - int rfb_wait_ms = 2; - static double dt_cut = 0.075; - int gcnt, ginput; - static int first = 1; - - if (dtr || tile_diffs) {} /* unused vars warning: */ - - if (first) { - char *p = getenv("SPIN"); - if (p) { - double junk; - sscanf(p, "%lf,%lf", &dt_cut, &junk); - } - first = 0; - } - - if (!got_pointer_input) { - return; - } - - - if (dt < dt_cut) { - dt = dt_cut; /* this is to try to avoid early exit */ - } - spin_max = 0.5; - - spin = 0.0; /* amount of time spinning */ - allowed_misses = 10; /* number of ptr inputs we can miss */ - miss_tweak = 8; - last_was_miss = 0; - consecutive_misses = 1; - gcnt = 0; - ginput = 0; - - dtime0(&tm); - to = tm; /* last time we did rfbPE() */ - - g = g_in = got_pointer_input; - - while (1) { - int got_input = 0; - - gcnt++; - - if (button_mask) { - drag_in_progress = 1; - } - - rfbCFD(rfb_wait_ms * 1000); - - dtm = dtime(&tm); - spin += dtm; - - if (got_pointer_input == g) { - if (last_was_miss) { - consecutive_misses++; - } - last_was_miss = 1; - } else { - ginput++; - if (ginput % miss_tweak == 0) { - allowed_misses++; - } - consecutive_misses = 1; - last_was_miss = 0; - } - - if (spin > spin_max) { - /* get out if spin time over limit */ - break; - - } else if (got_pointer_input > g) { - /* received some input, flush to display. */ - got_input = 1; - g = got_pointer_input; - X_LOCK; - XFlush(dpy); - X_UNLOCK; - } else if (--allowed_misses <= 0) { - /* too many misses */ - break; - } else if (consecutive_misses >=3) { - /* too many misses */ - break; - } else { - /* these are misses */ - int wms = 0; - if (gcnt == 1 && button_mask) { - /* - * missed our first input, wait - * for a defer time. (e.g. on - * slow link) hopefully client - * will batch them. - */ - wms = 50; - } else if (button_mask) { - wms = 10; - } else { - } - if (wms) { - usleep(wms * 1000); - } - } - } - - if (ginput >= 2) { - /* try for a couple more quick ones */ - for (i=0; i<2; i++) { - rfbCFD(rfb_wait_ms * 1000); - } - } - - drag_in_progress = 0; -} - -int fb_update_sent(int *count) { - static int last_count = 0; - int sent = 0, rc = 0; - rfbClientIteratorPtr i; - rfbClientPtr cl; - - if (nofb) { - return 0; - } - - i = rfbGetClientIterator(screen); - while( (cl = rfbClientIteratorNext(i)) ) { - sent += cl->framebufferUpdateMessagesSent; - } - rfbReleaseClientIterator(i); - if (sent != last_count) { - rc = 1; - } - if (count != NULL) { - *count = sent; - } - last_count = sent; - return rc; -} - -static void check_user_input4(double dt, double dtr, int tile_diffs) { - - int g, g_in, i, ginput, gcnt, tmp; - int last_was_miss, consecutive_misses; - int min_frame_size = 10; /* 10 tiles */ - double spin, tm, to, tc, dtm, rpe_last; - int rfb_wait_ms = 2; - static double dt_cut = 0.050; - static int first = 1; - - int Btile = tile_x * tile_y * bpp/8; /* Bytes per tile */ - double Ttile, dt_use; - double screen_rate = 6000000.; /* 5 MB/sec */ - double vnccpu_rate = 80 * 100000.; /* 20 KB/sec @ 80X compression */ - double net_rate = 50000.; - static double Tfac_r = 1.0, Tfac_v = 1.0, Tfac_n = 1.0, Tdelay = 0.001; - static double dt_min = -1.0, dt_max = -1.0; - double dt_min_fallback = 0.050; - static int ssec = 0, total_calls = 0; - static int push_frame = 0, update_count = 0; - - if (first) { - char *p = getenv("SPIN"); - if (p) { - sscanf(p, "%lf,%lf,%lf,%lf", &dt_cut, &Tfac_r, &Tfac_v, &Tfac_n); - } - first = 0; - ssec = time(0); - - if (dtr) {} /* unused vars warning: */ - } - - total_calls++; - - if (dt_min < 0.0 || dt < dt_min) { - if (dt > 0.0) { - dt_min = dt; - } - } - if (dt_min < 0.0) { - /* sensible value for the very 1st call if dt = 0.0 */ - dt_min = dt_min_fallback; - } - if (dt_max < 0.0 || dt > dt_max) { - dt_max = dt; - } - - if (total_calls > 30 && dt_min > 0.0) { - static int first = 1; - /* - * dt_min will soon be the quickest time to do - * one scan_for_updates with no tiles copied. - * use this (instead of copy_tiles) to estimate - * screen read rate. - */ - screen_rate = (main_bytes_per_line * ntiles_y) / dt_min; - if (first) { - rfbLog("measured screen read rate: %.2f Bytes/sec\n", - screen_rate); - } - first = 0; - } - - dtime0(&tm); - - if (dt < dt_cut) { - dt_use = dt_cut; - } else { - dt_use = dt; - } - - if (push_frame) { - int cnt, iter = 0; - double tp, push_spin = 0.0; - dtime0(&tp); - while (push_spin < dt_use * 0.5) { - fb_update_sent(&cnt); - if (cnt != update_count) { - break; - } - /* damn, they didn't push our frame! */ - iter++; - rfbPE(rfb_wait_ms * 1000); - - push_spin += dtime(&tp); - } - if (iter) { - X_LOCK; - XFlush(dpy); - X_UNLOCK; - } - push_frame = 0; - update_count = 0; - } - - /* - * when we first enter we require some pointer input - */ - if (!got_pointer_input) { - return; - } - - vnccpu_rate = get_raw_rate(); - - if ((tmp = get_read_rate()) != 0) { - screen_rate = (double) tmp; - } - if ((tmp = get_net_rate()) != 0) { - net_rate = (double) tmp; - } - net_rate = (vnccpu_rate/get_cmp_rate()) * net_rate; - - if ((tmp = get_net_latency()) != 0) { - Tdelay = 0.5 * ((double) tmp)/1000.; - } - - Ttile = Btile * (Tfac_r/screen_rate + Tfac_v/vnccpu_rate + Tfac_n/net_rate); - - spin = 0.0; /* amount of time spinning */ - last_was_miss = 0; - consecutive_misses = 1; - gcnt = 0; - ginput = 0; - - rpe_last = to = tc = tm; /* last time we did rfbPE() */ - g = g_in = got_pointer_input; - - tile_diffs = 0; /* reset our knowlegde of tile_diffs to zero */ - - while (1) { - int got_input = 0; - - gcnt++; - - if (button_mask) { - /* this varible is used by our pointer handler */ - drag_in_progress = 1; - } - - /* turn libvncserver crank to process events: */ - rfbCFD(rfb_wait_ms * 1000); - - dtm = dtime(&tm); - spin += dtm; - - if ( (gcnt == 1 && got_pointer_input > g) || tm-tc > 2*dt_min) { - tile_diffs = scan_for_updates(1); - tc = tm; - } - - if (got_pointer_input == g) { - if (last_was_miss) { - consecutive_misses++; - } - last_was_miss = 1; - } else { - ginput++; - consecutive_misses = 1; - last_was_miss = 0; - } - - if (tile_diffs > min_frame_size && spin > Ttile * tile_diffs + Tdelay) { - /* we think we can push the frame */ - push_frame = 1; - fb_update_sent(&update_count); - break; - - } else if (got_pointer_input > g) { - /* received some input, flush it to display. */ - got_input = 1; - g = got_pointer_input; - X_LOCK; - XFlush(dpy); - X_UNLOCK; - - } else if (consecutive_misses >= 2) { - /* too many misses in a row */ - break; - - } else { - /* these are pointer input misses */ - int wms; - if (gcnt == 1 && button_mask) { - /* - * missed our first input, wait for - * a defer time. (e.g. on slow link) - * hopefully client will batch many - * of them for the next read. - */ - wms = 50; - - } else if (button_mask) { - wms = 10; - } else { - wms = 0; - } - if (wms) { - usleep(wms * 1000); - } - } - } - if (ginput >= 2) { - /* try for a couple more quick ones */ - for (i=0; i<2; i++) { - rfbCFD(rfb_wait_ms * 1000); - } - } - drag_in_progress = 0; -} - -static int check_user_input(double dt, double dtr, int tile_diffs, int *cnt) { - - if (raw_fb && ! dpy) return 0; /* raw_fb hack */ - - if (use_xrecord) { - int rc = check_xrecord(); - /* - * 0: nothing found, proceed to other user input schemes. - * 1: events found, want to do a screen update now. - * 2: events found, want to loop back for some more. - * 3: events found, want to loop back for some more, - * and not have rfbPE() called. - * - * For 0, we precede below, otherwise return rc-1. - */ -if (debug_scroll && rc > 1) fprintf(stderr, " CXR: check_user_input ret %d\n", rc - 1); - if (rc == 0) { - ; /* proceed below. */ - } else { - return rc - 1; - } - } - - if (wireframe) { - if (check_wireframe()) { - return 0; - } - } - - if (pointer_mode == 1) { - if ((got_user_input || ui_skip < 0) && *cnt % ui_skip != 0) { - /* every ui_skip-th drops thru to scan */ - *cnt++; - X_LOCK; - XFlush(dpy); - X_UNLOCK; - return 1; /* short circuit watch_loop */ - } else { - return 0; - } - } - if (pointer_mode >= 2 && pointer_mode <= 4) { - if (got_keyboard_input) { - /* - * for these modes, short circuit watch_loop on - * *keyboard* input. - */ - if (*cnt % ui_skip != 0) { - *cnt++; - return 1; - } - } - /* otherwise continue below with pointer input method */ - } +/* -- x11vnc.c -- */ - if (pointer_mode == 2) { - check_user_input2(dt); - } else if (pointer_mode == 3) { - check_user_input3(dt, dtr, tile_diffs); - } else if (pointer_mode == 4) { - check_user_input4(dt, dtr, tile_diffs); - } - return 0; -} +#include "x11vnc.h" +#include "xwrappers.h" +#include "xdamage.h" +#include "xrecord.h" +#include "xevents.h" +#include "xinerama.h" +#include "xrandr.h" +#include "xkb_bell.h" +#include "win_utils.h" +#include "remote.h" +#include "scan.h" +#include "gui.h" +#include "help.h" +#include "user.h" +#include "cleanup.h" +#include "keyboard.h" +#include "pointer.h" +#include "cursor.h" +#include "userinput.h" +#include "screen.h" +#include "connections.h" +#include "rates.h" -/* -- x11vnc.c -- */ /* * main routine for the x11vnc program */ -/* - * 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; -} - -void measure_display_hook(rfbClientPtr cl) { - ClientData *cd = (ClientData *) cl->clientData; - dtime0(&cd->timer); -} -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; - } +static void check_cursor_changes(void); +static void record_last_fb_update(void); +static int choose_delay(double dt); +static void watch_loop(void); +static char *choose_title(char *display); +static int limit_shm(void); +static void check_rcfile(int argc, char **argv); +static void immediate_switch_user(int argc, char* argv[]); +static void print_settings(int try_http, int bg, char *gui_str); +static void check_loop_mode(int argc, char* argv[]); - 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; -} - -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; - } -} - -void check_cursor_changes(void) { +static void check_cursor_changes(void) { static double last_push = 0.0; cursor_changes += check_x11_pointer(); @@ -29766,25 +203,7 @@ void check_cursor_changes(void) { cursor_changes = 0; } -/* - * 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 record_last_fb_update(void) { +static void record_last_fb_update(void) { static int rbs0 = -1; static time_t last_call = 0; time_t now = time(0); @@ -29823,19 +242,7 @@ void record_last_fb_update(void) { } } -void rfbCFD(long usec) { - if (! screen) { - return; - } - if (usec > USEC_MAX) { - usec = USEC_MAX; - } - if (! use_threads) { - rfbCheckFds(screen, usec); - } -} - -int choose_delay(double dt) { +static int choose_delay(double dt) { static double t0 = 0.0, t1 = 0.0, t2 = 0.0, now; static int x0, y0, x1, y1, x2, y2, first = 1; int dx0, dy0, dx1, dy1, dm, i, msec = waitms; @@ -30060,6 +467,7 @@ if (debug_scroll) fprintf(stderr, "watch_loop: LOOP-BACK: %d\n", ret); check_xdamage_state(); check_xrecord_reset(0); check_add_keysyms(); + check_new_passwds(); if (started_as_root) { check_switched_user(); } @@ -30130,13 +538,13 @@ if (debug_scroll) fprintf(stderr, "watch_loop: LOOP-BACK: %d\n", ret); last_dt = dt; } -if ((debug_tiles || debug_scroll > 1 || debug_wireframe > 1) + if ((debug_tiles || debug_scroll > 1 || debug_wireframe > 1) && (tile_diffs > 4 || debug_tiles > 1)) { double rate = (tile_x * tile_y * bpp/8 * tile_diffs) / dt; fprintf(stderr, "============================= TILES: %d dt: %.4f" " t: %.4f %.2f MB/s nap_ok: %d\n", tile_diffs, dt, tm - x11vnc_start, rate/1000000.0, nap_ok); -} + } } @@ -30155,2112 +563,6 @@ if ((debug_tiles || debug_scroll > 1 || debug_wireframe > 1) } /* - * text printed out under -help option - */ -static void print_help(int mode) { -#if !SMALL_FOOTPRINT - char help[] = -"\n" -"x11vnc: allow VNC connections to real X11 displays. %s\n" -"\n" -"Typical usage is:\n" -"\n" -" Run this command in a shell on the remote machine \"far-host\"\n" -" with X session you wish to view:\n" -"\n" -" x11vnc -display :0\n" -"\n" -" Then run this in another window on the machine you are sitting at:\n" -"\n" -" vncviewer far-host:0\n" -"\n" -"Once x11vnc establishes connections with the X11 server and starts listening\n" -"as a VNC server it will print out a string: PORT=XXXX where XXXX is typically\n" -"5900 (the default VNC server port). One would next run something like\n" -"this on the local machine: \"vncviewer hostname:N\" where \"hostname\" is\n" -"the name of the machine running x11vnc and N is XXXX - 5900, i.e. usually\n" -"\"vncviewer hostname:0\".\n" -"\n" -"By default x11vnc will not allow the screen to be shared and it will exit\n" -"as soon as the client disconnects. See -shared and -forever below to override\n" -"these protections. See the FAQ for details how to tunnel the VNC connection\n" -"through an encrypted channel such as ssh(1). In brief:\n" -"\n" -" ssh -L 5900:localhost:5900 far-host 'x11vnc -localhost -display :0'\n" -"\n" -" vncviewer -encodings 'copyrect tight zrle hextile' localhost:0\n" -"\n" -"Also, use of a VNC password (-rfbauth or -passwdfile) is strongly recommend.\n" -"\n" -"For additional info see: http://www.karlrunge.com/x11vnc/\n" -" and http://www.karlrunge.com/x11vnc/#faq\n" -"\n" -"\n" -"Rudimentary config file support: if the file $HOME/.x11vncrc exists then each\n" -"line in it is treated as a single command line option. Disable with -norc.\n" -"For each option name, the leading character \"-\" is not required. E.g. a\n" -"line that is either \"forever\" or \"-forever\" may be used and are equivalent.\n" -"Likewise \"wait 100\" or \"-wait 100\" are acceptable and equivalent lines.\n" -"The \"#\" character comments out to the end of the line in the usual way\n" -"(backslash it for a literal). Leading and trailing whitespace is trimmed off.\n" -"Lines may be continued with a \"\\\" as the last character of a line (it\n" -"becomes a space character).\n" -"\n" -"Options:\n" -"\n" -"-display disp X11 server display to connect to, usually :0. The X\n" -" server process must be running on same machine and\n" -" support MIT-SHM. Equivalent to setting the DISPLAY\n" -" environment variable to \"disp\".\n" -"-auth file Set the X authority file to be \"file\", equivalent to\n" -" setting the XAUTHORITY environment variable to \"file\"\n" -" before startup. Same as -xauth file. See Xsecurity(7),\n" -" xauth(1) man pages for more info.\n" -"\n" -"-id windowid Show the window corresponding to \"windowid\" not\n" -" the entire display. New windows like popup menus,\n" -" transient toplevels, etc, may not be seen or may be\n" -" clipped. Disabling SaveUnders or BackingStore in the\n" -" X server may help show them. x11vnc may crash if the\n" -" window is initially partially obscured, changes size,\n" -" is iconified, etc. Some steps are taken to avoid this\n" -" and the -xrandr mechanism is used to track resizes. Use\n" -" xwininfo(1) to get the window id, or use \"-id pick\"\n" -" to have x11vnc run xwininfo(1) for you and extract\n" -" the id. The -id option is useful for exporting very\n" -" simple applications (e.g. the current view on a webcam).\n" -"-sid windowid As -id, but instead of using the window directly it\n" -" shifts a root view to it: this shows SaveUnders menus,\n" -" etc, although they will be clipped if they extend beyond\n" -" the window.\n" -"-clip WxH+X+Y Only show the sub-region of the full display that\n" -" corresponds to the rectangle with size WxH and offset\n" -" +X+Y. The VNC display has size WxH (i.e. smaller than\n" -" the full display). This also works for -id/-sid mode\n" -" where the offset is relative to the upper left corner\n" -" of the selected window.\n" -"\n" -"-flashcmap In 8bpp indexed color, let the installed colormap flash\n" -" as the pointer moves from window to window (slow).\n" -"-shiftcmap n Rare problem, but some 8bpp displays use less than 256\n" -" colorcells (e.g. 16-color grayscale, perhaps the other\n" -" bits are used for double buffering) *and* also need to\n" -" shift the pixels values away from 0, .., ncells. \"n\"\n" -" indicates the shift to be applied to the pixel values.\n" -" To see the pixel values set DEBUG_CMAP=1 to print out\n" -" a colormap histogram. Example: -shiftcmap 240\n" -"-notruecolor For 8bpp displays, force indexed color (i.e. a colormap)\n" -" even if it looks like 8bpp TrueColor (rare problem).\n" -"-visual n Experimental option: probably does not do what you\n" -" think. It simply *forces* the visual used for the\n" -" framebuffer; this may be a bad thing... (e.g. messes\n" -" up colors or cause a crash). It is useful for testing\n" -" and for some workarounds. n may be a decimal number,\n" -" or 0x hex. Run xdpyinfo(1) for the values. One may\n" -" also use \"TrueColor\", etc. see <X11/X.h> for a list.\n" -" If the string ends in \":m\" then for better or for\n" -" worse the visual depth is forced to be m.\n" -"\n" -"-overlay Handle multiple depth visuals on one screen, e.g. 8+24\n" -" and 24+8 overlay visuals (the 32 bits per pixel are\n" -" packed with 8 for PseudoColor and 24 for TrueColor).\n" -"\n" -" Currently -overlay only works on Solaris via\n" -" XReadScreen(3X11) and IRIX using XReadDisplay(3).\n" -" On Solaris there is a problem with image \"bleeding\"\n" -" around transient popup menus (but not for the menu\n" -" itself): a workaround is to disable SaveUnders\n" -" by passing the \"-su\" argument to Xsun (in\n" -" /etc/dt/config/Xservers).\n" -"\n" -" Use -overlay as a workaround for situations like these:\n" -" Some legacy applications require the default visual to\n" -" be 8bpp (8+24), or they will use 8bpp PseudoColor even\n" -" when the default visual is depth 24 TrueColor (24+8).\n" -" In these cases colors in some windows will be incorrect\n" -" in x11vnc unless -overlay is used. Another use of\n" -" -overlay is to enable showing the exact mouse cursor\n" -" shape (details below).\n" -"\n" -" Under -overlay, performance will be somewhat slower\n" -" due to the extra image transformations required.\n" -" For optimal performance do not use -overlay, but rather\n" -" configure the X server so that the default visual is\n" -" depth 24 TrueColor and try to have all apps use that\n" -" visual (e.g. some apps have -use24 or -visual options).\n" -"-overlay_nocursor Sets -overlay, but does not try to draw the exact mouse\n" -" cursor shape using the overlay mechanism.\n" -"\n" -"-scale fraction Scale the framebuffer by factor \"fraction\". Values\n" -" less than 1 shrink the fb, larger ones expand it. Note:\n" -" image may not be sharp and response may be slower.\n" -" If \"fraction\" contains a decimal point \".\" it\n" -" is taken as a floating point number, alternatively\n" -" the notation \"m/n\" may be used to denote fractions\n" -" exactly, e.g. -scale 2/3\n" -"\n" -" Scaling Options: can be added after \"fraction\" via\n" -" \":\", to supply multiple \":\" options use commas.\n" -" If you just want a quick, rough scaling without\n" -" blending, append \":nb\" to \"fraction\" (e.g. -scale\n" -" 1/3:nb). No blending is the default for 8bpp indexed\n" -" color, to force blending for this case use \":fb\".\n" -"\n" -" To disable -scrollcopyrect and -wirecopyrect under\n" -" -scale use \":nocr\". If you need to to enable them use\n" -" \":cr\" or specify them explicitly on the command line.\n" -" If a slow link is detected, \":nocr\" may be applied\n" -" automatically. Default: %s\n" -"\n" -" More esoteric options: for compatibility with vncviewers\n" -" the scaled width is adjusted to be a multiple of 4:\n" -" to disable this use \":n4\". \":in\" use interpolation\n" -" scheme even when shrinking, \":pad\" pad scaled width\n" -" and height to be multiples of scaling denominator\n" -" (e.g. 3 for 2/3).\n" -"\n" -"-scale_cursor frac By default if -scale is supplied the cursor shape is\n" -" scaled by the same factor. Depending on your usage,\n" -" you may want to scale the cursor independently of the\n" -" screen or not at all. If you specify -scale_cursor\n" -" the cursor will be scaled by that factor. When using\n" -" -scale mode to keep the cursor at its \"natural\" size\n" -" use \"-scale_cursor 1\". Most of the \":\" scaling\n" -" options apply here as well.\n" -"\n" -"-viewonly All VNC clients can only watch (default %s).\n" -"-shared VNC display is shared, i.e. more than one viewer can\n" -" connect at the same time (default %s).\n" -"-once Exit after the first successfully connected viewer\n" -" disconnects, opposite of -forever. This is the Default.\n" -"-forever Keep listening for more connections rather than exiting\n" -" as soon as the first client(s) disconnect. Same as -many\n" -"-loop Create an outer loop restarting the x11vnc process\n" -" whenever it terminates. -bg and -inetd are ignored in\n" -" this mode. Useful for continuing even if the X server\n" -" terminates and restarts (you will need permission to\n" -" reconnect of course). Use, e.g., -loop100 to sleep\n" -" 100 millisecs between restarts, etc. Default is 2000ms\n" -" (i.e. 2 secs) Use, e.g. -loop300,5 to sleep 300 ms\n" -" and only loop 5 times.\n" -"-timeout n Exit unless a client connects within the first n seconds\n" -" after startup.\n" -"-inetd Launched by inetd(1): stdio instead of listening socket.\n" -" Note: if you are not redirecting stderr to a log file\n" -" (via shell 2> or -o option) you MUST also specify the -q\n" -" option, otherwise the stderr goes to the viewer which\n" -" will cause it to abort. Specifying both -inetd and -q\n" -" and no -o will automatically close the stderr.\n" -"-nofilexfer Disable the TightVNC file transfer extension. (same as\n" -" -disablefiletransfer). Note that when the -viewonly\n" -" option is supplied all file transfers are disabled.\n" -" Also clients that log in viewonly cannot transfer files.\n" -" However, if the remote control mechanism is used to\n" -" change the global or per-client viewonly state the\n" -" filetransfer permissions will NOT change.\n" -"-http Instead of using -httpdir (see below) to specify\n" -" where the Java vncviewer applet is, have x11vnc try\n" -" to *guess* where the directory is by looking relative\n" -" to the program location and in standard locations\n" -" (/usr/local/share/x11vnc/classes, etc).\n" -"-connect string For use with \"vncviewer -listen\" reverse connections.\n" -" If \"string\" has the form \"host\" or \"host:port\"\n" -" the connection is made once at startup. Use commas\n" -" for a list of host's and host:port's.\n" -"\n" -" If \"string\" contains \"/\" it is instead interpreted\n" -" as a file to periodically check for new hosts.\n" -" The first line is read and then the file is truncated.\n" -" Be careful for this usage mode if x11vnc is running as\n" -" root (e.g. via gdm(1), etc).\n" -"-vncconnect Monitor the VNC_CONNECT X property set by the standard\n" -"-novncconnect VNC program vncconnect(1). When the property is\n" -" set to \"host\" or \"host:port\" establish a reverse\n" -" connection. Using xprop(1) instead of vncconnect may\n" -" work (see the FAQ). The -remote control mechanism also\n" -" uses this VNC_CONNECT channel. Default: %s\n" -"\n" -"-allow host1[,host2..] Only allow client connections from hosts matching\n" -" the comma separated list of hostnames or IP addresses.\n" -" Can also be a numerical IP prefix, e.g. \"192.168.100.\"\n" -" to match a simple subnet, for more control build\n" -" libvncserver with libwrap support (See the FAQ). If the\n" -" list contains a \"/\" it instead is a interpreted as a\n" -" file containing addresses or prefixes that is re-read\n" -" each time a new client connects. Lines can be commented\n" -" out with the \"#\" character in the usual way.\n" -"-localhost Same as \"-allow 127.0.0.1\".\n" -"\n" -" Note: if you want to restrict which network interface\n" -" x11vnc listens on, see the -listen option below.\n" -" E.g. \"-listen localhost\" or \"-listen 192.168.3.21\".\n" -" As a special case, the option \"-localhost\" implies\n" -" \"-listen localhost\".\n" -"\n" -" For non-localhost -listen usage, if you use the remote\n" -" control mechanism (-R) to change the -listen interface\n" -" you may need to manually adjust the -allow list (and\n" -" vice versa) to avoid situations where no connections\n" -" (or too many) are allowed.\n" -"\n" -"-nolookup Do not use gethostbyname() or gethostbyaddr() to look up\n" -" host names or IP numbers. Use this if name resolution\n" -" is incorrectly set up and leads to long pauses as name\n" -" lookups time out, etc.\n" -"\n" -"-input string Fine tuning of allowed user input. If \"string\" does\n" -" not contain a comma \",\" the tuning applies only to\n" -" normal clients. Otherwise the part before \",\" is\n" -" for normal clients and the part after for view-only\n" -" clients. \"K\" is for Keystroke input, \"M\" for\n" -" Mouse-motion input, and \"B\" for Button-click input.\n" -" Their presence in the string enables that type of input.\n" -" E.g. \"-input M\" means normal users can only move\n" -" the mouse and \"-input KMB,M\" lets normal users do\n" -" anything and enables view-only users to move the mouse.\n" -" This option is ignored when a global -viewonly is in\n" -" effect (all input is discarded in that case).\n" -"\n" -"-viewpasswd string Supply a 2nd password for view-only logins. The -passwd\n" -" (full-access) password must also be supplied.\n" -"\n" -"-passwdfile filename Specify the libvncserver password via the first line\n" -" of the file \"filename\" (instead of via -passwd on\n" -" the command line where others might see it via ps(1)).\n" -"\n" -" If the filename is prefixed with \"rm:\" it will be\n" -" removed after being read. In general, the password file\n" -" should not be readable by untrusted users (BTW: neither\n" -" should the VNC -rfbauth file: it is NOT encrypted).\n" -"\n" -" Note that only the first 8 characters of a password\n" -" are used.\n" -"\n" -" If multiple non-blank lines exist in the file they are\n" -" all taken as valid passwords. Blank lines are ignored.\n" -" Password lines may be \"commented out\" (ignored) if\n" -" they begin with the charactor \"#\" or the line contains\n" -" the string \"__SKIP__\". Lines may be annotated by use\n" -" of the \"__COMM__\" string: from it to the end of the\n" -" line is ignored. An empty password may be specified\n" -" via the \"__EMPTY__\" string on a line by itself (note\n" -" your viewer might not accept empty passwords).\n" -"\n" -" If the string \"__BEGIN_VIEWONLY__\" appears on a\n" -" line by itself, the remaining passwords are used for\n" -" viewonly access. For compatibility, as a special case\n" -" if the file contains only two password lines the 2nd\n" -" one is automatically taken as the viewonly password.\n" -" Otherwise the \"__BEGIN_VIEWONLY__\" token must be used\n" -" to have viewonly passwords. (tip: make it the 3rd and\n" -" last line to have 2 full-access passwords)\n" - -"-nopw Disable the big warning message when you use x11vnc\n" -" without some sort of password.\n" -"-storepasswd pass file Store password \"pass\" as the VNC password in the\n" -" file \"file\". Once the password is stored the\n" -" program exits. Use the password via \"-rfbauth file\"\n" -"\n" -"-accept string Run a command (possibly to prompt the user at the\n" -" X11 display) to decide whether an incoming client\n" -" should be allowed to connect or not. \"string\" is\n" -" an external command run via system(3) or some special\n" -" cases described below. Be sure to quote \"string\"\n" -" if it contains spaces, shell characters, etc. If the\n" -" external command returns 0 the client is accepted,\n" -" otherwise the client is rejected. See below for an\n" -" extension to accept a client view-only.\n" -"\n" -" If x11vnc is running as root (say from inetd(1) or from\n" -" display managers xdm(1), gdm(1), etc), think about the\n" -" security implications carefully before supplying this\n" -" option (likewise for the -gone option).\n" -"\n" -" Environment: The RFB_CLIENT_IP environment variable will\n" -" be set to the incoming client IP number and the port\n" -" in RFB_CLIENT_PORT (or -1 if unavailable). Similarly,\n" -" RFB_SERVER_IP and RFB_SERVER_PORT (the x11vnc side\n" -" of the connection), are set to allow identification\n" -" of the tcp virtual circuit. The x11vnc process\n" -" id will be in RFB_X11VNC_PID, a client id number in\n" -" RFB_CLIENT_ID, and the number of other connected clients\n" -" in RFB_CLIENT_COUNT. RFB_MODE will be \"accept\"\n" -"\n" -" If \"string\" is \"popup\" then a builtin popup window\n" -" is used. The popup will time out after 120 seconds,\n" -" use \"popup:N\" to modify the timeout to N seconds\n" -" (use 0 for no timeout).\n" -"\n" -" If \"string\" is \"xmessage\" then an xmessage(1)\n" -" invocation is used for the command. xmessage must be\n" -" installed on the machine for this to work.\n" -"\n" -" Both \"popup\" and \"xmessage\" will present an option\n" -" for accepting the client \"View-Only\" (the client\n" -" can only watch). This option will not be presented if\n" -" -viewonly has been specified, in which case the entire\n" -" display is view only.\n" -"\n" -" If the user supplied command is prefixed with something\n" -" like \"yes:0,no:*,view:3 mycommand ...\" then this\n" -" associates the numerical command return code with\n" -" the actions: accept, reject, and accept-view-only,\n" -" respectively. Use \"*\" instead of a number to indicate\n" -" the default action (in case the command returns an\n" -" unexpected value). E.g. \"no:*\" is a good choice.\n" -"\n" -" Note that x11vnc blocks while the external command\n" -" or popup is running (other clients may see no updates\n" -" during this period). So a person sitting a the physical\n" -" display is needed to respond to an popup prompt. (use\n" -" a 2nd x11vnc if you lock yourself out).\n" -"\n" -" More -accept tricks: use \"popupmouse\" to only allow\n" -" mouse clicks in the builtin popup to be recognized.\n" -" Similarly use \"popupkey\" to only recognize\n" -" keystroke responses. These are to help avoid the\n" -" user accidentally accepting a client by typing or\n" -" clicking. All 3 of the popup keywords can be followed\n" -" by +N+M to supply a position for the popup window.\n" -" The default is to center the popup window.\n" -"-gone string As -accept, except to run a user supplied command when\n" -" a client goes away (disconnects). RFB_MODE will be\n" -" set to \"gone\" and the other RFB_* variables are as\n" -" in -accept. Unlike -accept, the command return code\n" -" is not interpreted by x11vnc. Example: -gone 'xlock &'\n" -"\n" -"-users list If x11vnc is started as root (say from inetd(1) or from\n" -" display managers xdm(1), gdm(1), etc), then as soon\n" -" as possible after connections to the X display are\n" -" established try to switch to one of the users in the\n" -" comma separated \"list\". If x11vnc is not running as\n" -" root this option is ignored.\n" -" \n" -" Why use this option? In general it is not needed since\n" -" x11vnc is already connected to the X display and can\n" -" perform its primary functions. The option was added\n" -" to make some of the *external* utility commands x11vnc\n" -" occasionally runs work properly. In particular under\n" -" GNOME and KDE to implement the \"-solid color\" feature\n" -" external commands (gconftool-2 and dcop) must be run\n" -" as the user owning the desktop session. Since this\n" -" option switches userid it also affects the userid used\n" -" to run the processes for the -accept and -gone options.\n" -" It also affects the ability to read files for options\n" -" such as -connect, -allow, and -remap. Note that the\n" -" -connect file is also sometimes written to.\n" -" \n" -" So be careful with this option since in many situations\n" -" its use can decrease security.\n" -" \n" -" The switch to a user will only take place if the\n" -" display can still be successfully opened as that user\n" -" (this is primarily to try to guess the actual owner\n" -" of the session). Example: \"-users fred,wilma,betty\".\n" -" Note that a malicious user \"barney\" by quickly using\n" -" \"xhost +\" when logging in may get x11vnc to switch\n" -" to user \"fred\". What happens next?\n" -" \n" -" Under display managers it may be a long time before\n" -" the switch succeeds (i.e. a user logs in). To make\n" -" it switch immediately regardless if the display\n" -" can be reopened prefix the username with the \"+\"\n" -" character. E.g. \"-users +bob\" or \"-users +nobody\".\n" -" The latter (i.e. switching immediately to user\n" -" \"nobody\") is probably the only use of this option\n" -" that increases security.\n" -" \n" -" To immediately switch to a user *before* connections\n" -" to the X display are made or any files opened use the\n" -" \"=\" character: \"-users =bob\". That user needs to\n" -" be able to open the X display of course.\n" -" \n" -" The special user \"guess=\" means to examine the utmpx\n" -" database (see who(1)) looking for a user attached to\n" -" the display number (from DISPLAY or -display option)\n" -" and try him/her. To limit the list of guesses, use:\n" -" \"-users guess=bob,betty\".\n" -" \n" -" Even more sinister is the special user \"lurk=\" that\n" -" means to try to guess the DISPLAY from the utmpx login\n" -" database as well. So it \"lurks\" waiting for anyone\n" -" to log into an X session and then connects to it.\n" -" Specify a list of users after the = to limit which\n" -" users will be tried. To enable a different searching\n" -" mode, if the first user in the list is something like\n" -" \":0\" or \":0-2\" that indicates a range of DISPLAY\n" -" numbers that will be tried (regardless of whether\n" -" they are in the utmpx database) for all users that\n" -" are logged in. Examples: \"-users lurk=\" and also\n" -" \"-users lurk=:0-1,bob,mary\"\n" -" \n" -" Be especially careful using the \"guess=\" and \"lurk=\"\n" -" modes. They are not recommended for use on machines\n" -" with untrustworthy local users.\n" -" \n" -"-noshm Do not use the MIT-SHM extension for the polling.\n" -" Remote displays can be polled this way: be careful this\n" -" can use large amounts of network bandwidth. This is\n" -" also of use if the local machine has a limited number\n" -" of shm segments and -onetile is not sufficient.\n" -"-flipbyteorder Sometimes needed if remotely polled host has different\n" -" endianness. Ignored unless -noshm is set.\n" -"-onetile Do not use the new copy_tiles() framebuffer mechanism,\n" -" just use 1 shm tile for polling. Limits shm segments\n" -" used to 3.\n" -"\n" -"-solid [color] To improve performance, when VNC clients are connected\n" -" try to change the desktop background to a solid color.\n" -" The [color] is optional: the default color is \"cyan4\".\n" -" For a different one specify the X color (rgb.txt name,\n" -" e.g. \"darkblue\" or numerical \"#RRGGBB\").\n" -"\n" -" Currently this option only works on GNOME, KDE, CDE,\n" -" and classic X (i.e. with the background image on the\n" -" root window). The \"gconftool-2\" and \"dcop\" external\n" -" commands are run for GNOME and KDE respectively.\n" -" Other desktops won't work, e.g. Xfce (send us the\n" -" corresponding commands if you find them). If x11vnc is\n" -" running as root (inetd(1) or gdm(1)), the -users option\n" -" may be needed for GNOME and KDE. If x11vnc guesses\n" -" your desktop incorrectly, you can force it by prefixing\n" -" color with \"gnome:\", \"kde:\", \"cde:\" or \"root:\".\n" -"-blackout string Black out rectangles on the screen. \"string\" is a\n" -" comma separated list of WxH+X+Y type geometries for\n" -" each rectangle. If one of the items on the list is the\n" -" string \"noptr\" the mouse pointer will not be allowed\n" -" to go into a blacked out region.\n" -"-xinerama If your screen is composed of multiple monitors\n" -" glued together via XINERAMA, and that screen is\n" -" not a rectangle this option will try to guess the\n" -" areas to black out (if your system has libXinerama).\n" -"\n" -" In general, we have noticed on XINERAMA displays you\n" -" may need to use the \"-xwarppointer\" option if the mouse\n" -" pointer misbehaves.\n" -"\n" -"-xtrap Use the DEC-XTRAP extension for keystroke and mouse\n" -" input insertion. For use on legacy systems, e.g. X11R5,\n" -" running an incomplete or missing XTEST extension.\n" -" By default DEC-XTRAP will be used if XTEST server grab\n" -" control is missing, use -xtrap to do the keystroke and\n" -" mouse insertion via DEC-XTRAP as well.\n" -"\n" -"-xrandr [mode] If the display supports the XRANDR (X Resize, Rotate\n" -" and Reflection) extension, and you expect XRANDR events\n" -" to occur to the display while x11vnc is running, this\n" -" options indicates x11vnc should try to respond to\n" -" them (as opposed to simply crashing by assuming the\n" -" old screen size). See the xrandr(1) manpage and run\n" -" 'xrandr -q' for more info. [mode] is optional and\n" -" described below.\n" -"\n" -" Since watching for XRANDR events and trapping errors\n" -" increases polling overhead, only use this option if\n" -" XRANDR changes are expected. For example on a rotatable\n" -" screen PDA or laptop, or using a XRANDR-aware Desktop\n" -" where you resize often. It is best to be viewing with a\n" -" vncviewer that supports the NewFBSize encoding, since it\n" -" knows how to react to screen size changes. Otherwise,\n" -" libvncserver tries to do so something reasonable for\n" -" viewers that cannot do this (portions of the screen\n" -" may be clipped, unused, etc).\n" -"\n" -" \"mode\" defaults to \"resize\", which means create a\n" -" new, resized, framebuffer and hope all viewers can cope\n" -" with the change. \"newfbsize\" means first disconnect\n" -" all viewers that do not support the NewFBSize VNC\n" -" encoding, and then resize the framebuffer. \"exit\"\n" -" means disconnect all viewer clients, and then terminate\n" -" x11vnc.\n" -"-padgeom WxH Whenever a new vncviewer connects, the framebuffer is\n" -" replaced with a fake, solid black one of geometry WxH.\n" -" Shortly afterwards the framebuffer is replaced with the\n" -" real one. This is intended for use with vncviewers\n" -" that do not support NewFBSize and one wants to make\n" -" sure the initial viewer geometry will be big enough\n" -" to handle all subsequent resizes (e.g. under -xrandr,\n" -" -remote id:windowid, rescaling, etc.)\n" -"\n" -"-o logfile Write stderr messages to file \"logfile\" instead of\n" -" to the terminal. Same as \"-logfile file\". To append\n" -" to the file use \"-oa file\" or \"-logappend file\".\n" -"-flag file Write the \"PORT=NNNN\" (e.g. PORT=5900) string to\n" -" \"file\" in addition to stdout. This option could be\n" -" useful by wrapper script to detect when x11vnc is ready.\n" -"\n" -"-rc filename Use \"filename\" instead of $HOME/.x11vncrc for rc file.\n" -"-norc Do not process any .x11vncrc file for options.\n" -"\n" -"-h, -help Print this help text.\n" -"-?, -opts Only list the x11vnc options.\n" -"-V, -version Print program version and last modification date.\n" -"\n" -"-dbg Instead of exiting after cleaning up, run a simple\n" -" \"debug crash shell\" when fatal errors are trapped.\n" -"\n" -"-q Be quiet by printing less informational output to\n" -" stderr. Same as -quiet.\n" -"-bg Go into the background after screen setup. Messages to\n" -" stderr are lost unless -o logfile is used. Something\n" -" like this could be useful in a script:\n" -" port=`ssh $host \"x11vnc -display :0 -bg\" | grep PORT`\n" -" port=`echo \"$port\" | sed -e 's/PORT=//'`\n" -" port=`expr $port - 5900`\n" -" vncviewer $host:$port\n" -"\n" -"-modtweak Option -modtweak automatically tries to adjust the AltGr\n" -"-nomodtweak and Shift modifiers for differing language keyboards\n" -" between client and host. Otherwise, only a single key\n" -" press/release of a Keycode is simulated (i.e. ignoring\n" -" the state of the modifiers: this usually works for\n" -" identical keyboards). Also useful in resolving cases\n" -" where a Keysym is bound to multiple keys (e.g. \"<\" + \">\"\n" -" and \",\" + \"<\" keys). Default: %s\n" -"-xkb When in modtweak mode, use the XKEYBOARD extension (if\n" -"-noxkb the X display supports it) to do the modifier tweaking.\n" -" This is powerful and should be tried if there are still\n" -" keymapping problems when using -modtweak by itself.\n" -" The default is to check whether some common keysyms,\n" -" e.g. !, @, [, are only accessible via -xkb mode and if\n" -" so then automatically enable the mode. To disable this\n" -" automatic detection use -noxkb.\n" -"-skip_keycodes string Ignore the comma separated list of decimal keycodes.\n" -" Perhaps these are keycodes not on your keyboard but\n" -" your X server thinks exist. Currently only applies\n" -" to -xkb mode. Use this option to help x11vnc in the\n" -" reverse problem it tries to solve: Keysym -> Keycode(s)\n" -" when ambiguities exist (more than one Keycode per\n" -" Keysym). Run 'xmodmap -pk' to see your keymapping.\n" -" Example: \"-skip_keycodes 94,114\"\n" -"-sloppy_keys Experimental option that tries to correct some\n" -" \"sloppy\" key behavior. E.g. if at the viewer you\n" -" press Shift+Key but then release the Shift before\n" -" Key that could give rise to extra unwanted characters\n" -" (usually only between keyboards of different languages).\n" -" Only use this option if you observe problems with\n" -" some keystrokes.\n" -"-skip_dups Some VNC viewers send impossible repeated key events,\n" -"-noskip_dups e.g. key-down, key-down, key-up, key-up all for the same\n" -" key, or 20 downs in a row for the same modifier key!\n" -" Setting -skip_dups means to skip these duplicates and\n" -" just process the first event. Note: some VNC viewers\n" -" assume they can send down's without the corresponding\n" -" up's and so you should not set this option for\n" -" these viewers (symptom: some keys do not autorepeat)\n" -" Default: %s\n" -"-add_keysyms If a Keysym is received from a VNC viewer and that\n" -"-noadd_keysyms Keysym does not exist in the X server, then add the\n" -" Keysym to the X server's keyboard mapping on an unused\n" -" key. Added Keysyms will be removed periodically and\n" -" also when x11vnc exits. Default: %s\n" -#if 0 -"-xkbcompat Ignore the XKEYBOARD extension. Use as a workaround for\n" -" some keyboard mapping problems. E.g. if you are using\n" -" an international keyboard (AltGr or ISO_Level3_Shift),\n" -" and the OS or keyboard where the VNC viewer is run\n" -" is not identical to that of the X server, and you are\n" -" having problems typing some keys. Implies -nobell.\n" -#endif -"-clear_mods At startup and exit clear the modifier keys by sending\n" -" KeyRelease for each one. The Lock modifiers are skipped.\n" -" Used to clear the state if the display was accidentally\n" -" left with any pressed down.\n" -"-clear_keys As -clear_mods, except try to release any pressed key.\n" -" Note that this option and -clear_mods can interfere\n" -" with a person typing at the physical keyboard.\n" -"-remap string Read Keysym remappings from file named \"string\".\n" -" Format is one pair of Keysyms per line (can be name\n" -" or hex value) separated by a space. If no file named\n" -" \"string\" exists, it is instead interpreted as this\n" -" form: key1-key2,key3-key4,... See <X11/keysymdef.h>\n" -" header file for a list of Keysym names, or use xev(1).\n" -" To map a key to a button click, use the fake Keysyms\n" -" \"Button1\", ..., etc. E.g: \"-remap Super_R-Button2\"\n" -" (useful for pasting on a laptop)\n" -"\n" -" Dead keys: \"dead\" (or silent, mute) keys are keys that\n" -" do not produce a character but must be followed by a 2nd\n" -" keystroke. This is often used for accenting characters,\n" -" e.g. to put \"`\" on top of \"a\" by pressing the dead\n" -" key and then \"a\". Note that this interpretation\n" -" is not part of core X11, it is up to the toolkit or\n" -" application to decide how to react to the sequence.\n" -" The X11 names for these keysyms are \"dead_grave\",\n" -" \"dead_acute\", etc. However some VNC viewers send the\n" -" keysyms \"grave\", \"acute\" instead thereby disabling\n" -" the accenting. To work around this -remap can be used.\n" -" For example \"-remap grave-dead_grave,acute-dead_acute\"\n" -" As a convenience, \"-remap DEAD\" applies these remaps:\n" -"\n" -" g grave-dead_grave\n" -" a acute-dead_acute\n" -" c asciicircum-dead_circumflex\n" -" t asciitilde-dead_tilde\n" -" m macron-dead_macron\n" -" b breve-dead_breve\n" -" D abovedot-dead_abovedot\n" -" d diaeresis-dead_diaeresis\n" -" o degree-dead_abovering\n" -" A doubleacute-dead_doubleacute\n" -" r caron-dead_caron\n" -" e cedilla-dead_cedilla\n" -"\n" -" If you just want a subset use the first letter\n" -" label, e.g. \"-remap DEAD=ga\" to get the first two.\n" -" Additional remaps may also be supplied via commas,\n" -" e.g. \"-remap DEAD=ga,Super_R-Button2\". Finally,\n" -" \"DEAD=missing\" means to apply all of the above as\n" -" long as the left hand member is not already in the\n" -" X11 keymap.\n" -"\n" -"-norepeat Option -norepeat disables X server key auto repeat when\n" -"-repeat VNC clients are connected and VNC keyboard input is\n" -" not idle for more than 5 minutes. This works around a\n" -" repeating keystrokes bug (triggered by long processing\n" -" delays between key down and key up client events: either\n" -" from large screen changes or high latency).\n" -" Default: %s\n" -"\n" -" Note: your VNC viewer side will likely do autorepeating,\n" -" so this is no loss unless someone is simultaneously at\n" -" the real X display.\n" -"\n" -" Use \"-norepeat N\" to set how many times norepeat will\n" -" be reset if something else (e.g. X session manager)\n" -" undoes it. The default is 2. Use a negative value\n" -" for unlimited resets.\n" -"\n" -"-nofb Ignore video framebuffer: only process keyboard and\n" -" pointer. Intended for use with Win2VNC and x2vnc\n" -" dual-monitor setups.\n" -"-nobell Do not watch for XBell events. (no beeps will be heard)\n" -" Note: XBell monitoring requires the XKEYBOARD extension.\n" -"-nosel Do not manage exchange of X selection/cutbuffer between\n" -" VNC viewers and the X server.\n" -"-noprimary Do not poll the PRIMARY selection for changes to send\n" -" back to clients. (PRIMARY is still set on received\n" -" changes, however).\n" -"-seldir string If direction string is \"send\", only send the selection\n" -" to viewers, and if it is \"recv\" only receive it from\n" -" viewers. To work around apps setting the selection\n" -" too frequently and messing up the other end. You can\n" -" actually supply a comma separated list of directions,\n" -" including \"debug\" to turn on debugging output.\n" -"\n" -"-cursor [mode] Sets how the pointer cursor shape (little icon at the\n" -"-nocursor mouse pointer) should be handled. The \"mode\" string\n" -" is optional and is described below. The default\n" -" is to show some sort of cursor shape(s). How this\n" -" is done depends on the VNC viewer and the X server.\n" -" Use -nocursor to disable cursor shapes completely.\n" -"\n" -" Some VNC viewers support the TightVNC CursorPosUpdates\n" -" and CursorShapeUpdates extensions (cuts down on\n" -" network traffic by not having to send the cursor image\n" -" every time the pointer is moved), in which case these\n" -" extensions are used (see -nocursorshape and -nocursorpos\n" -" below to disable). For other viewers the cursor shape\n" -" is written directly to the framebuffer every time the\n" -" pointer is moved or changed and gets sent along with\n" -" the other framebuffer updates. In this case, there\n" -" will be some lag between the vnc viewer pointer and\n" -" the remote cursor position.\n" -"\n" -" If the X display supports retrieving the cursor shape\n" -" information from the X server, then the default is\n" -" to use that mode. On Solaris this can be done with\n" -" the SUN_OVL extension using -overlay (see also the\n" -" -overlay_nocursor option). A similar overlay scheme\n" -" is used on IRIX. Xorg (e.g. Linux) and recent Solaris\n" -" Xsun servers support the XFIXES extension to retrieve\n" -" the exact cursor shape from the X server. If XFIXES\n" -" is present it is preferred over Overlay and is used by\n" -" default (see -noxfixes below). This can be disabled\n" -" with -nocursor, and also some values of the \"mode\"\n" -" option below.\n" -" \n" -" Note that under XFIXES cursors with transparency (alpha\n" -" channel) will usually not be exactly represented and one\n" -" may find Overlay preferable. See also the -alphacut\n" -" and -alphafrac options below as fudge factors to try\n" -" to improve the situation for cursors with transparency\n" -" for a given theme.\n" -"\n" -" The \"mode\" string can be used to fine-tune the\n" -" displaying of cursor shapes. It can be used the\n" -" following ways:\n" -"\n" -" \"-cursor arrow\" - just show the standard arrow\n" -" nothing more or nothing less.\n" -"\n" -" \"-cursor none\" - same as \"-nocursor\"\n" -"\n" -" \"-cursor X\" - when the cursor appears to be on the\n" -" root window, draw the familiar X shape. Some desktops\n" -" such as GNOME cover up the root window completely,\n" -" and so this will not work, try \"X1\", etc, to try to\n" -" shift the tree depth. On high latency links or slow\n" -" machines there will be a time lag between expected and\n" -" the actual cursor shape.\n" -"\n" -" \"-cursor some\" - like \"X\" but use additional\n" -" heuristics to try to guess if the window should have\n" -" a windowmanager-like resizer cursor or a text input\n" -" I-beam cursor. This is a complete hack, but may be\n" -" useful in some situations because it provides a little\n" -" more feedback about the cursor shape.\n" -"\n" -" \"-cursor most\" - try to show as many cursors as\n" -" possible. Often this will only be the same as \"some\"\n" -" unless the display has overlay visuals or XFIXES\n" -" extensions available. On Solaris and IRIX if XFIXES\n" -" is not available, -overlay mode will be attempted.\n" -"\n" -"-arrow n Choose an alternate \"arrow\" cursor from a set of\n" -" some common ones. n can be 1 to %d. Default is: %d\n" -" Ignored when in XFIXES cursor-grabbing mode.\n" -"\n" -"-noxfixes Do not use the XFIXES extension to draw the exact cursor\n" -" shape even if it is available.\n" -"-alphacut n When using the XFIXES extension for the cursor shape,\n" -" cursors with transparency will not usually be displayed\n" -" exactly (but opaque ones will). This option sets n as\n" -" a cutoff for cursors that have transparency (\"alpha\n" -" channel\" with values ranging from 0 to 255) Any cursor\n" -" pixel with alpha value less than n becomes completely\n" -" transparent. Otherwise the pixel is completely opaque.\n" -" Default %d\n" -" \n" -"-alphafrac fraction With the threshold in -alphacut some cursors will become\n" -" almost completely transparent because their alpha values\n" -" are not high enough. For those cursors adjust the\n" -" alpha threshold until fraction of the non-zero alpha\n" -" channel pixels become opaque. Default %.2f\n" -"-alpharemove By default, XFIXES cursors pixels with transparency have\n" -" the alpha factor multiplied into the RGB color values\n" -" (i.e. that corresponding to blending the cursor with a\n" -" black background). Specify this option to remove the\n" -" alpha factor. (useful for light colored semi-transparent\n" -" cursors).\n" -"-noalphablend In XFIXES mode do not send cursor alpha channel data\n" -" to libvncserver. The default is to send it. The\n" -" alphablend effect will only be visible in -nocursorshape\n" -" mode or for clients with cursorshapeupdates turned\n" -" off. (However there is a hack for 32bpp with depth 24,\n" -" it uses the extra 8 bits to store cursor transparency\n" -" for use with a hacked vncviewer that applies the\n" -" transparency locally. See the FAQ for more info).\n" -"\n" -"-nocursorshape Do not use the TightVNC CursorShapeUpdates extension\n" -" even if clients support it. See -cursor above.\n" -"-cursorpos Option -cursorpos enables sending the X cursor position\n" -"-nocursorpos back to all vnc clients that support the TightVNC\n" -" CursorPosUpdates extension. Other clients will be able\n" -" to see the pointer motions. Default: %s\n" -"-xwarppointer Move the pointer with XWarpPointer(3X) instead of\n" -" the XTEST extension. Use this as a workaround\n" -" if the pointer motion behaves incorrectly, e.g.\n" -" on touchscreens or other non-standard setups.\n" -" Also sometimes needed on XINERAMA displays.\n" -"\n" -"-buttonmap string String to remap mouse buttons. Format: IJK-LMN, this\n" -" maps buttons I -> L, etc., e.g. -buttonmap 13-31\n" -"\n" -" Button presses can also be mapped to keystrokes: replace\n" -" a button digit on the right of the dash with :<sym>:\n" -" or :<sym1>+<sym2>: etc. for multiple keys. For example,\n" -" if the viewing machine has a mouse-wheel (buttons 4 5)\n" -" but the x11vnc side does not, these will do scrolls:\n" -" -buttonmap 12345-123:Prior::Next:\n" -" -buttonmap 12345-123:Up+Up+Up::Down+Down+Down:\n" -"\n" -" See <X11/keysymdef.h> header file for a list of Keysyms,\n" -" or use the xev(1) program. Note: mapping of button\n" -" clicks to Keysyms may not work if -modtweak or -xkb is\n" -" needed for the Keysym.\n" -"\n" -" If you include a modifier like \"Shift_L\" the\n" -" modifier's up/down state is toggled, e.g. to send\n" -" \"The\" use :Shift_L+t+Shift_L+h+e: (the 1st one is\n" -" shift down and the 2nd one is shift up). (note: the\n" -" initial state of the modifier is ignored and not reset)\n" -" To include button events use \"Button1\", ... etc.\n" -"\n" -"-nodragging Do not update the display during mouse dragging events\n" -" (mouse button held down). Greatly improves response on\n" -" slow setups, but you lose all visual feedback for drags,\n" -" text selection, and some menu traversals. It overrides\n" -" any -pointer_mode setting.\n" -"\n" -"-wireframe [str] Try to detect window moves or resizes when a mouse\n" -"-nowireframe button is held down and show a wireframe instead of\n" -" the full opaque window. This is based completely on\n" -" heuristics and may not always work: it depends on your\n" -" window manager and even how you move things around.\n" -" See -pointer_mode below for discussion of the \"bogging\n" -" down\" problem this tries to avoid.\n" -" Default: %s\n" -"\n" -" Shorter aliases: -wf [str] and -nowf\n" -"\n" -" The value \"str\" is optional and, of course, is\n" -" packed with many tunable parameters for this scheme:\n" -"\n" -" Format: shade,linewidth,percent,T+B+L+R,mod,t1+t2+t3+t4\n" -" Default: %s\n" -"\n" -" If you leave nothing between commas: \",,\" the default\n" -" value is used. If you don't specify enough commas,\n" -" the trailing parameters are set to their defaults.\n" -"\n" -" \"shade\" indicate the \"color\" for the wireframe,\n" -" usually a greyscale: 0-255, however for 16 and 32bpp you\n" -" can specify an rgb.txt X color (e.g. \"dodgerblue\") or\n" -" a value > 255 is treated as RGB (e.g. red is 0xff0000).\n" -" \"linewidth\" sets the width of the wireframe in pixels.\n" -" \"percent\" indicates to not apply the wireframe scheme\n" -" to windows with area less than this percent of the\n" -" full screen.\n" -"\n" -" \"T+B+L+R\" indicates four integers for how close in\n" -" pixels the pointer has to be from the Top, Bottom, Left,\n" -" or Right edges of the window to consider wireframing.\n" -" This is a speedup to quickly exclude a window from being\n" -" wireframed: set them all to zero to not try the speedup\n" -" (scrolling and selecting text will likely be slower).\n" -"\n" -" \"mod\" specifies if a button down event in the\n" -" interior of the window with a modifier key (Alt, Shift,\n" -" etc.) down should indicate a wireframe opportunity.\n" -" It can be \"0\" or \"none\" to skip it, \"1\" or \"all\"\n" -" to apply it to any modifier, or \"Shift\", \"Alt\",\n" -" \"Control\", \"Meta\", \"Super\", or \"Hyper\" to only\n" -" apply for that type of modifier key.\n" -"\n" -" \"t1+t2+t3+t4\" specify four floating point times in\n" -" seconds: t1 is how long to wait for the pointer to move,\n" -" t2 is how long to wait for the window to start moving\n" -" or being resized (for some window managers this can be\n" -" rather long), t3 is how long to keep a wireframe moving\n" -" before repainting the window. t4 is the minimum time\n" -" between sending wireframe \"animations\". If a slow\n" -" link is detected, these values may be automatically\n" -" changed to something better for a slow link.\n" -"\n" -"-wirecopyrect mode Since the -wireframe mechanism evidently tracks moving\n" -"-nowirecopyrect windows accurately, a speedup can be obtained by\n" -" telling the VNC viewers to locally copy the translated\n" -" window region. This is the VNC CopyRect encoding:\n" -" the framebuffer update doesn't need to send the actual\n" -" new image data.\n" -"\n" -" Shorter aliases: -wcr [mode] and -nowcr\n" -"\n" -" \"mode\" can be \"never\" (same as -nowirecopyrect)\n" -" to never try the copyrect, \"top\" means only do it if\n" -" the window was not covered by any other windows, and\n" -" \"always\" means to translate the orginally unobscured\n" -" region (this may look odd as the remaining pieces come\n" -" in, but helps on a slow link). Default: \"%s\"\n" -"\n" -" Note: there can be painting errors or slow response\n" -" when using -scale so you may want to disable CopyRect\n" -" in this case \"-wirecopyrect never\" on the command\n" -" line or by remote-control. Or you can also use the\n" -" \"-scale xxx:nocr\" scale option.\n" -"\n" -"-debug_wireframe Turn on debugging info printout for the wireframe\n" -" heuristics. \"-dwf\" is an alias. Specify multiple\n" -" times for more output.\n" -"\n" -"-scrollcopyrect mode Like -wirecopyrect, but use heuristics to try to guess\n" -"-noscrollcopyrect if a window has scrolled its contents (either vertically\n" -" or horizontally). This requires the RECORD X extension\n" -" to \"snoop\" on X applications (currently for certain\n" -" XCopyArea and XConfigureWindow X protocol requests).\n" -" Examples: Hitting <Return> in a terminal window when the\n" -" cursor was at the bottom, the text scrolls up one line.\n" -" Hitting <Down> arrow in a web browser window, the web\n" -" page scrolls up a small amount. Or scrolling with a\n" -" scrollbar or mouse wheel.\n" -"\n" -" Shorter aliases: -scr [mode] and -noscr\n" -"\n" -" This scheme will not always detect scrolls, but when\n" -" it does there is a nice speedup from using the VNC\n" -" CopyRect encoding (see -wirecopyrect). The speedup\n" -" is both in reduced network traffic and reduced X\n" -" framebuffer polling/copying. On the other hand, it may\n" -" induce undesired transients (e.g. a terminal cursor\n" -" being scrolled up when it should not be) or other\n" -" painting errors (window tearing, bunching-up, etc).\n" -" These are automatically repaired in a short period\n" -" of time. If this is unacceptable disable the feature\n" -" with -noscrollcopyrect.\n" -"\n" -" Screen clearing kludges: for testing at least, there\n" -" are some \"magic key sequences\" (must be done in less\n" -" than 1 second) to aid repairing painting errors that\n" -" may be seen when using this mode:\n" -"\n" -" 3 Alt_L's in a row: resend whole screen,\n" -" 4 Alt_L's in a row: reread and resend whole screen,\n" -" 3 Super_L's in a row: mark whole screen for polling,\n" -" 4 Super_L's in a row: reset RECORD context,\n" -" 5 Super_L's in a row: try to push a black screen\n" -"\n" -" note: Alt_L is the Left \"Alt\" key (a single key)\n" -" Super_L is the Left \"Super\" key (Windows flag).\n" -" Both of these are modifier keys, and so should not\n" -" generate characters when pressed by themselves. Also,\n" -" your VNC viewer may have its own refresh hot-key\n" -" or button.\n" -"\n" -" \"mode\" can be \"never\" (same as -noscrollcopyrect)\n" -" to never try the copyrect, \"keys\" means to try it\n" -" in response to keystrokes only, \"mouse\" means to\n" -" try it in response to mouse events only, \"always\"\n" -" means to do both. Default: \"%s\"\n" -"\n" -" Note: there can be painting errors or slow response\n" -" when using -scale so you may want to disable CopyRect\n" -" in this case \"-scrollcopyrect never\" on the command\n" -" line or by remote-control. Or you can also use the\n" -" \"-scale xxx:nocr\" scale option.\n" -"\n" -"-scr_area n Set the minimum area in pixels for a rectangle\n" -" to be considered for the -scrollcopyrect detection\n" -" scheme. This is to avoid wasting the effort on small\n" -" rectangles that would be quickly updated the normal way.\n" -" E.g. suppose an app updated the position of its skinny\n" -" scrollbar first and then shifted the large panel\n" -" it controlled. We want to be sure to skip the small\n" -" scrollbar and get the large panel. Default: %d\n" -"\n" -"-scr_skip list Skip scroll detection for applications matching\n" -" the comma separated list of strings in \"list\".\n" -" Some applications implement their scrolling in\n" -" strange ways where the XCopyArea, etc, also applies\n" -" to invisible portions of the window: if we CopyRect\n" -" those areas it looks awful during the scroll and\n" -" there may be painting errors left after the scroll.\n" -" Soffice.bin is the worst known offender.\n" -"\n" -" Use \"##\" to denote the start of the application class\n" -" (e.g. \"##XTerm\") and \"++\" to denote the start\n" -" of the application instance name (e.g. \"++xterm\").\n" -" The string your list is matched against is of the form\n" -" \"^^WM_NAME##Class++Instance<same-for-any-subwindows>\"\n" -" The \"xlsclients -la\" command will provide this info.\n" -"\n" -" If a pattern is prefixed with \"KEY:\" it only applies\n" -" to Keystroke generated scrolls (e.g. Up arrow). If it\n" -" is prefixed with \"MOUSE:\" it only applies to Mouse\n" -" induced scrolls (e.g. dragging on a scrollbar).\n" -" Default: %s\n" -"\n" -"-scr_inc list Opposite of -scr_skip: this list is consulted first\n" -" and if there is a match the window will be monitored\n" -" via RECORD for scrolls irrespective of -scr_skip.\n" -" Use -scr_skip '*' to skip anything that does not match\n" -" your -scr_inc. Use -scr_inc '*' to include everything.\n" -"\n" -"-scr_keys list For keystroke scroll detection, only apply the RECORD\n" -" heuristics to the comma separated list of keysyms in\n" -" \"list\". You may find the RECORD overhead for every\n" -" one of your keystrokes disrupts typing too much, but you\n" -" don't want to turn it off completely with \"-scr mouse\"\n" -" and -scr_parms does not work or is too confusing.\n" -"\n" -" The listed keysyms can be numeric or the keysym\n" -" names in the <X11/keysymdef.h> header file or from the\n" -" xev(1) program. Example: \"-scr_keys Up,Down,Return\".\n" -" One probably wants to have application specific lists\n" -" (e.g. for terminals, etc) but that is too icky to think\n" -" about for now...\n" -"\n" -" If \"list\" begins with the \"-\" character the list\n" -" is taken as an exclude list: all keysyms except those\n" -" list will be considered. The special string \"builtin\"\n" -" expands to an internal list of keysyms that are likely\n" -" to cause scrolls. BTW, by default modifier keys,\n" -" Shift_L, Control_R, etc, are skipped since they almost\n" -" never induce scrolling by themselves.\n" -"\n" -"-scr_term list Yet another cosmetic kludge. Apply shell/terminal\n" -" heuristics to applications matching comma separated\n" -" list (same as for -scr_skip/-scr_inc). For example an\n" -" annoying transient under scroll detection is if you\n" -" hit Enter in a terminal shell with full text window,\n" -" the solid text cursor block will be scrolled up.\n" -" So for a short time there are two (or more) block\n" -" cursors on the screen. There are similar scenarios,\n" -" (e.g. an output line is duplicated).\n" -" \n" -" These transients are induced by the approximation of\n" -" scroll detection (e.g. it detects the scroll, but not\n" -" the fact that the block cursor was cleared just before\n" -" the scroll). In nearly all cases these transient errors\n" -" are repaired when the true X framebuffer is consulted\n" -" by the normal polling. But they are distracting, so\n" -" what this option provides is extra \"padding\" near the\n" -" bottom of the terminal window: a few extra lines near\n" -" the bottom will not be scrolled, but rather updated\n" -" from the actual X framebuffer. This usually reduces\n" -" the annoying artifacts. Use \"none\" to disable.\n" -" Default: \"%s\"\n" -"\n" -"-scr_keyrepeat lo-hi If a key is held down (or otherwise repeats rapidly) and\n" -" this induces a rapid sequence of scrolls (e.g. holding\n" -" down an Arrow key) the \"scrollcopyrect\" detection\n" -" and overhead may not be able to keep up. A time per\n" -" single scroll estimate is performed and if that estimate\n" -" predicts a sustainable scrollrate of keys per second\n" -" between \"lo\" and \"hi\" then repeated keys will be\n" -" DISCARDED to maintain the scrollrate. For example your\n" -" key autorepeat may be 25 keys/sec, but for a large\n" -" window or slow link only 8 scrolls per second can be\n" -" sustained, then roughly 2 out of every 3 repeated keys\n" -" will be discarded during this period. Default: \"%s\"\n" -"\n" -"-scr_parms string Set various parameters for the scrollcopyrect mode.\n" -" The format is similar to that for -wireframe and packed\n" -" with lots of parameters:\n" -"\n" -" Format: T+B+L+R,t1+t2+t3,s1+s2+s3+s4+s5\n" -" Default: %s\n" -"\n" -" If you leave nothing between commas: \",,\" the default\n" -" value is used. If you don't specify enough commas,\n" -" the trailing parameters are set to their defaults.\n" -"\n" -" \"T+B+L+R\" indicates four integers for how close in\n" -" pixels the pointer has to be from the Top, Bottom, Left,\n" -" or Right edges of the window to consider scrollcopyrect.\n" -" If -wireframe overlaps it takes precedence. This is a\n" -" speedup to quickly exclude a window from being watched\n" -" for scrollcopyrect: set them all to zero to not try\n" -" the speedup (things like selecting text will likely\n" -" be slower).\n" -"\n" -" \"t1+t2+t3\" specify three floating point times in\n" -" seconds that apply to scrollcopyrect detection with\n" -" *Keystroke* input: t1 is how long to wait after a key\n" -" is pressed for the first scroll, t2 is how long to keep\n" -" looking after a Keystroke scroll for more scrolls.\n" -" t3 is how frequently to try to update surrounding\n" -" scrollbars outside of the scrolling area (0.0 to\n" -" disable)\n" -"\n" -" \"s1+s2+s3+s4+s5\" specify five floating point times\n" -" in seconds that apply to scrollcopyrect detection with\n" -" *Mouse* input: s1 is how long to wait after a mouse\n" -" button is pressed for the first scroll, s2 is how long\n" -" to keep waiting for additional scrolls after the first\n" -" Mouse scroll was detected. s3 is how frequently to\n" -" try to update surrounding scrollbars outside of the\n" -" scrolling area (0.0 to disable). s4 is how long to\n" -" buffer pointer motion (to try to get fewer, bigger\n" -" mouse scrolls). s5 is the maximum time to spend just\n" -" updating the scroll window without updating the rest\n" -" of the screen.\n" -"\n" -"-fixscreen string Periodically \"repair\" the screen based on settings\n" -" in \"string\". Hopefully you won't need this option,\n" -" it is intended for cases when the -scrollcopyrect or\n" -" -wirecopyrect features leave too many painting errors,\n" -" but it can be used for any scenario. This option\n" -" periodically performs costly operations and so\n" -" interactive response may be reduced when it is on.\n" -" You can use 3 Alt_L's (the Left \"Alt\" key) taps in a\n" -" row described under -scrollcopyrect instead to manually\n" -" request a screen repaint when it is needed.\n" -"\n" -" \"string\" is a comma separated list of one or more of\n" -" the following: \"V=t\", \"C=t\", and \"X=t\". In these\n" -" \"t\" stands for a time in seconds (it is a floating\n" -" point even though one should usually use values > 2 to\n" -" avoid wasting resources). V sets how frequently the\n" -" entire screen should be sent to viewers (it is like the\n" -" 3 Alt_L's). C sets how long to wait after a CopyRect\n" -" to repaint the full screen. X sets how frequently\n" -" to reread the full X11 framebuffer from the X server\n" -" and push it out to connected viewers. Use of X should\n" -" be rare, please report a bug if you find you need it.\n" -" Examples: -fixscreen V=10 -fixscreen C=10\n" -"\n" -"-debug_scroll Turn on debugging info printout for the scroll\n" -" heuristics. \"-ds\" is an alias. Specify it multiple\n" -" times for more output.\n" -"\n" -"-noxrecord Disable any use of the RECORD extension. This is\n" -" currently used by the -scrollcopyrect scheme and to\n" -" monitor X server grabs.\n" -"\n" -"-grab_buster Some of the use of the RECORD extension can leave a\n" -"-nograb_buster tiny window for XGrabServer deadlock. This is only if\n" -" the whole-server grabbing application expects mouse or\n" -" keyboard input before releasing the grab. It is usually\n" -" a window manager that does this. x11vnc takes care to\n" -" avoid the the problem, but if caught x11vnc will freeze.\n" -" Without -grab_buster, the only solution is to go the\n" -" physical display and give it some input to satisfy the\n" -" grabbing app. Or manually kill and restart the window\n" -" manager if that is feasible. With -grab_buster, x11vnc\n" -" will fork a helper thread and if x11vnc appears to be\n" -" stuck in a grab after a period of time (20-30 sec) then\n" -" it will inject some user input: button clicks, Escape,\n" -" mouse motion, etc to try to break the grab. If you\n" -" experience a lot of grab deadlock, please report a bug.\n" -"\n" -"-debug_grabs Turn on debugging info printout with respect to\n" -" XGrabServer() deadlock for -scrollcopyrect mode.\n" -"\n" -"-pointer_mode n Various pointer motion update schemes. \"-pm\" is\n" -" an alias. The problem is pointer motion can cause\n" -" rapid changes on the screen: consider the rapid\n" -" changes when you drag a large window around opaquely.\n" -" Neither x11vnc's screen polling and vnc compression\n" -" routines nor the bandwidth to the vncviewers can keep\n" -" up these rapid screen changes: everything will bog down\n" -" when dragging or scrolling. So a scheme has to be used\n" -" to \"eat\" much of that pointer input before re-polling\n" -" the screen and sending out framebuffer updates. The\n" -" mode number \"n\" can be 0 to %d and selects one of\n" -" the schemes desribed below.\n" -"\n" -" Note that the -wireframe and -scrollcopyrect modes\n" -" complement -pointer_mode by detecting (and improving)\n" -" certain periods of \"rapid screen change\".\n" -"\n" -" n=0: does the same as -nodragging. (all screen polling\n" -" is suspended if a mouse button is pressed.)\n" -"\n" -" n=1: was the original scheme used to about Jan 2004:\n" -" it basically just skips -input_skip keyboard or pointer\n" -" events before repolling the screen.\n" -"\n" -" n=2 is an improved scheme: by watching the current rate\n" -" of input events it tries to detect if it should try to\n" -" \"eat\" additional pointer events before continuing.\n" -"\n" -" n=3 is basically a dynamic -nodragging mode: it detects\n" -" when the mouse motion has paused and then refreshes\n" -" the display.\n" -"\n" -" n=4 attempts to measures network rates and latency,\n" -" the video card read rate, and how many tiles have been\n" -" changed on the screen. From this, it aggressively tries\n" -" to push screen \"frames\" when it decides it has enough\n" -" resources to do so. NOT FINISHED.\n" -"\n" -" The default n is %d. Note that modes 2, 3, 4 will skip\n" -" -input_skip keyboard events (but it will not count\n" -" pointer events). Also note that these modes are not\n" -" available in -threads mode which has its own pointer\n" -" event handling mechanism.\n" -"\n" -" To try out the different pointer modes to see which\n" -" one gives the best response for your usage, it is\n" -" convenient to use the remote control function, for\n" -" example \"x11vnc -R pm:4\" or the tcl/tk gui (Tuning ->\n" -" pointer_mode -> n).\n" -"\n" -"-input_skip n For the pointer handling when non-threaded: try to\n" -" read n user input events before scanning display. n < 0\n" -" means to act as though there is always user input.\n" -" Default: %d\n" -"\n" -"-speeds rd,bw,lat x11vnc tries to estimate some speed parameters that\n" -" are used to optimize scheduling (e.g. -pointer_mode\n" -" 4, -wireframe, -scrollcopyrect) and other things.\n" -" Use the -speeds option to set these manually.\n" -" The triple \"rd,bw,lat\" corresponds to video h/w\n" -" read rate in MB/sec, network bandwidth to clients in\n" -" KB/sec, and network latency to clients in milliseconds,\n" -" respectively. If a value is left blank, e.g. \"-speeds\n" -" ,100,15\", then the internal scheme is used to estimate\n" -" the empty value(s).\n" -"\n" -" Typical PC video cards have read rates of 5-10 MB/sec.\n" -" If the framebuffer is in main memory instead of video\n" -" h/w (e.g. SunRay, shadowfb, dummy driver, Xvfb), the\n" -" read rate may be much faster. \"x11perf -getimage500\"\n" -" can be used to get a lower bound (remember to factor\n" -" in the bytes per pixel). It is up to you to estimate\n" -" the network bandwith and latency to clients. For the\n" -" latency the ping(1) command can be used.\n" -"\n" -" For convenience there are some aliases provided,\n" -" e.g. \"-speeds modem\". The aliases are: \"modem\" for\n" -" 6,4,200; \"dsl\" for 6,100,50; and \"lan\" for 6,5000,1\n" -"\n" -"-wmdt string For some features, e.g. -wireframe and -scrollcopyrect,\n" -" x11vnc has to work around issues for certain window\n" -" managers or desktops (currently kde and xfce).\n" -" By default it tries to guess which one, but it can\n" -" guess incorrectly. Use this option to indicate which\n" -" wm/dt. \"string\" can be \"gnome\", \"kde\", \"cde\",\n" -" \"xfce\", or \"root\" (classic X wm). Anything else\n" -" is interpreted as \"root\".\n" -"\n" -"-debug_pointer Print debugging output for every pointer event.\n" -"-debug_keyboard Print debugging output for every keyboard event.\n" -" Same as -dp and -dk, respectively. Use multiple\n" -" times for more output.\n" -"\n" -"-defer time Time in ms to wait for updates before sending to client\n" -" (deferUpdateTime) Default: %d\n" -"-wait time Time in ms to pause between screen polls. Used to cut\n" -" down on load. Default: %d\n" -"-wait_ui factor Factor by which to cut the -wait time if there\n" -" has been recent user input (pointer or keyboard).\n" -" Improves response, but increases the load whenever you\n" -" are moving the mouse or typing. Default: %.2f\n" -"-nowait_bog Do not detect if the screen polling is \"bogging down\"\n" -" and sleep more. Some activities with no user input can\n" -" slow things down a lot: consider a large terminal window\n" -" with a long build running in it continously streaming\n" -" text output. By default x11vnc will try to detect this\n" -" (3 screen polls in a row each longer than 0.25 sec with\n" -" no user input), and sleep up to 1.5 secs to let things\n" -" \"catch up\". Use this option to disable that detection.\n" -"-slow_fb time Floating point time in seconds delay all screen polling.\n" -" For special purpose usage where a low frame rate is\n" -" acceptable and desirable, but you want the user input\n" -" processed at the normal rate so you cannot use -wait.\n" -"-readtimeout n Set libvncserver rfbMaxClientWait to n seconds. On\n" -" slow links that take a long time to paint the first\n" -" screen libvncserver may hit the timeout and drop the\n" -" connection. Default: %d seconds.\n" -"-nap Monitor activity and if it is low take longer naps\n" -"-nonap between screen polls to really cut down load when idle.\n" -" Default: %s\n" -"-sb time Time in seconds after NO activity (e.g. screen blank)\n" -" to really throttle down the screen polls (i.e. sleep\n" -" for about 1.5 secs). Use 0 to disable. Default: %d\n" -"\n" -"-noxdamage Do not use the X DAMAGE extension to detect framebuffer\n" -" changes even if it is available. Use -xdamage if your\n" -" default is to have it off.\n" -"\n" -" x11vnc's use of the DAMAGE extension: 1) significantly\n" -" reduces the load when the screen is not changing much,\n" -" and 2) detects changed areas (small ones by default)\n" -" more quickly.\n" -"\n" -" Currently the DAMAGE extension is overly conservative\n" -" and often reports large areas (e.g. a whole terminal\n" -" or browser window) as damaged even though the actual\n" -" changed region is much smaller (sometimes just a few\n" -" pixels). So heuristics were introduced to skip large\n" -" areas and use the damage rectangles only as \"hints\"\n" -" for the traditional scanline polling. The following\n" -" tuning parameters are introduced to adjust this\n" -" behavior:\n" -"\n" -"-xd_area A Set the largest DAMAGE rectangle area \"A\" (in\n" -" pixels: width * height) to trust as truly damaged:\n" -" the rectangle will be copied from the framebuffer\n" -" (slow) no matter what. Set to zero to trust *all*\n" -" rectangles. Default: %d\n" -"-xd_mem f Set how long DAMAGE rectangles should be \"remembered\",\n" -" \"f\" is a floating point number and is in units of the\n" -" scanline repeat cycle time (%d iterations). The default\n" -" (%.1f) should give no painting problems. Increase it if\n" -" there are problems or decrease it to live on the edge\n" -" (perhaps useful on a slow machine).\n" -"\n" -"-sigpipe string Broken pipe (SIGPIPE) handling. \"string\" can be\n" -" \"ignore\" or \"exit\". For \"ignore\" libvncserver\n" -" will handle the abrupt loss of a client and continue,\n" -" for \"exit\" x11vnc will cleanup and exit at the 1st\n" -" broken connection. Default: \"ignore\". This option\n" -" is obsolete.\n" -"-threads Whether or not to use the threaded libvncserver\n" -"-nothreads algorithm [rfbRunEventLoop] if libpthread is available\n" -" Default: %s\n" -"\n" -"-fs f If the fraction of changed tiles in a poll is greater\n" -" than f, the whole screen is updated. Default: %.2f\n" -"-gaps n Heuristic to fill in gaps in rows or cols of n or\n" -" less tiles. Used to improve text paging. Default: %d\n" -"-grow n Heuristic to grow islands of changed tiles n or wider\n" -" by checking the tile near the boundary. Default: %d\n" -"-fuzz n Tolerance in pixels to mark a tiles edges as changed.\n" -" Default: %d\n" -"-debug_tiles Print debugging output for tiles, fb updates, etc.\n" -"\n" -"-snapfb Instead of polling the X display framebuffer (fb) for\n" -" changes, periodically copy all of X display fb into main\n" -" memory and examine that copy for changes. Under some\n" -" circumstances this will improve interactive response,\n" -" or at least make things look smoother, but in others\n" -" (most!) it will make the response worse. If the video\n" -" h/w fb is such that reading small tiles is very slow\n" -" this mode could help. To keep the \"framerate\" up\n" -" the screen size x bpp cannot be too large. Note that\n" -" this mode is very wasteful of memory I/O resources\n" -" (it makes full screen copies even if nothing changes).\n" -" It may be of use in video capture-like applications,\n" -" or where window tearing is a problem.\n" -"\n" -"-rawfb string Experimental option, instead of polling X, poll the\n" -" memory object specified in \"string\". For shared\n" -" memory segments it is of the form: \"shm:N@WxHxB\"\n" -" which specifies a shmid N and framebuffer Width, Height,\n" -" and Bits per pixel. To memory map mmap(2) a file use:\n" -" \"map:/path/to/a/file@WxHxB\". If there is trouble\n" -" with mmap, use \"file:/...\" for slower lseek(2)\n" -" based reading. If you do not supply a type \"map\"\n" -" is assumed if the file exists.\n" -"\n" -" If string is \"setup:cmd\", then the command \"cmd\"\n" -" is run and the first line from it is read and used\n" -" as \"string\". This allows initializing the device,\n" -" determining WxHxB, etc. These are often done as root\n" -" so take care.\n" -"\n" -" Optional suffixes are \":R/G/B\" and \"+O\" to specify\n" -" red, green, and blue masks and an offset into the\n" -" memory object. If the masks are not provided x11vnc\n" -" guesses them based on the bpp.\n" -"\n" -" Examples:\n" -" -rawfb shm:210337933@800x600x32:ff/ff00/ff0000\n" -" -rawfb map:/dev/fb0@1024x768x32\n" -" -rawfb map:/tmp/Xvfb_screen0@640x480x8+3232\n" -" -rawfb file:/tmp/my.pnm@250x200x24+37\n" -"\n" -" (see ipcs(1) and fbset(1) for the first two examples)\n" -"\n" -" All user input is discarded by default (but see the\n" -" -pipeinput option). Most of the X11 (screen, keyboard,\n" -" mouse) options do not make sense and many will cause\n" -" this mode to crash, so please think twice before\n" -" setting/changing them.\n" -"\n" -" If you don't want x11vnc to close the X DISPLAY in\n" -" rawfb mode, then capitalize the prefix, SHM:, MAP:,\n" -" FILE: Keeping the display open enables the default\n" -" remote-control channel, which could be useful. Also,\n" -" if you also specify -noviewonly, then the mouse and\n" -" keyboard input are STILL sent to the X display, this\n" -" usage should be very rare, i.e. doing something strange\n" -" with /dev/fb0.\n" -"\n" -"-pipeinput cmd Another experimental option: it lets you supply an\n" -" external command in \"cmd\" that x11vnc will pipe\n" -" all of the user input events to in a simple format.\n" -" In -pipeinput mode by default x11vnc will not process\n" -" any of the user input events. If you prefix \"cmd\"\n" -" with \"tee:\" it will both send them to the pipe\n" -" command and process them. For a description of the\n" -" format run \"-pipeinput tee:/bin/cat\". Another prefix\n" -" is \"reopen\" which means to reopen pipe if it exits.\n" -" Separate multiple prefixes with commas.\n" -"\n" -" In combination with -rawfb one might be able to\n" -" do amusing things (e.g. control non-X devices).\n" -" To facilitate this, if -rawfb is in effect then the\n" -" value is stored in X11VNC_RAWFB_STR for the pipe command\n" -" to use if it wants. Do 'env | grep X11VNC' for more.\n" -"\n" -"-gui [gui-opts] Start up a simple tcl/tk gui based on the the remote\n" -" control options -remote/-query described below.\n" -" Requires the \"wish\" program to be installed on the\n" -" machine. \"gui-opts\" is not required: the default\n" -" is to start up both the full gui and x11vnc with the\n" -" gui showing up on the X display in the environment\n" -" variable DISPLAY.\n" -"\n" -" \"gui-opts\" can be a comma separated list of items.\n" -" Currently there are these types of items: 1) a gui\n" -" mode, a 2) gui \"simplicity\", 3) the X display the\n" -" gui should display on, 4) a \"tray\" or \"icon\" mode,\n" -" and 5) a gui geometry.\n" -"\n" -" 1) The gui mode can be \"start\", \"conn\", or \"wait\"\n" -" \"start\" is the default mode above and is not required.\n" -" \"conn\" means do not automatically start up x11vnc,\n" -" but instead just try to connect to an existing x11vnc\n" -" process. \"wait\" means just start the gui and nothing\n" -" else (you will later instruct the gui to start x11vnc\n" -" or connect to an existing one.)\n" -"\n" -" 2) The gui simplicity is off by default (a power-user\n" -" gui with all options is presented) To start with\n" -" something less daunting supply the string \"simple\"\n" -" (\"ez\" is an alias for this). Once the gui is\n" -" started you can toggle between the two with \"Misc ->\n" -" simple_gui\".\n" -"\n" -" 3) Note the possible confusion regarding the potentially\n" -" two different X displays: x11vnc polls one, but you\n" -" may want the gui to appear on another. For example, if\n" -" you ssh in and x11vnc is not running yet you may want\n" -" the gui to come back to you via your ssh redirected X\n" -" display (e.g. localhost:10).\n" -"\n" -" If you do not specify a gui X display in \"gui-opts\"\n" -" then the DISPLAY environment variable and -display\n" -" option are tried (in that order). Regarding the x11vnc\n" -" X display the gui will try to communication with, it\n" -" first tries -display and then DISPLAY. For example,\n" -" \"x11vnc -display :0 -gui otherhost:0\", will remote\n" -" control an x11vnc polling :0 and display the gui on\n" -" otherhost:0 The \"tray/icon\" mode below reverses this\n" -" preference, preferring to display on the x11vnc display.\n" -"\n" -" 4) When \"tray\" or \"icon\" is specified, the gui\n" -" presents itself as a small icon with behavior typical\n" -" of a \"system tray\" or \"dock applet\". The color\n" -" of the icon indicates status (connected clients) and\n" -" there is also a balloon status. Clicking on the icon\n" -" gives a menu from which properties, etc, can be set and\n" -" the full gui is available under \"Advanced\". To be\n" -" fully functional, the gui mode should be \"start\"\n" -" (the default).\n" -"\n" -" For \"icon\" the gui just a small standalone window.\n" -" For \"tray\" it will attempt to embed itself in the\n" -" \"system tray\" if possible. If \"=setpass\" is appended then\n" -" at startup the X11 user will be prompted to set the\n" -" VNC session password. If =<hexnumber> is appended\n" -" that icon will attempt to embed itself in the window\n" -" given by hexnumber. Use =noadvanced to disable the\n" -" full gui. (To supply more than one, use \"+\" sign).\n" -" E.g. -gui tray=setpass and -gui icon=0x3600028\n" -"\n" -" Other modes: \"full\", the default and need not be\n" -" specified. \"-gui none\", do not show a gui, useful\n" -" to override a ~/.x11vncrc setting, etc.\n" -"\n" -" 5) When \"geom=+X+Y\" is specified, that geometry\n" -" is passed to the gui toplevel. This is the icon in\n" -" icon/tray mode, or the full gui otherwise. You can\n" -" also specify width and height, i.e. WxH+X+Y, but it\n" -" is not recommended. In \"tray\" mode the geometry is\n" -" ignored unless the system tray manager does not seem\n" -" to be running. One could imagine using something like\n" -" \"-gui tray,geom=+4000+4000\" with a display manager\n" -" to keep the gui invisible until someone logs in...\n" -"\n" -" More icon tricks, \"icon=minimal\" gives an icon just\n" -" with the VNC display number. You can also set the font\n" -" with \"iconfont=...\". The following could be useful:\n" -" \"-gui icon=minimal,iconfont=5x8,geom=24x10+0-0\"\n" -"\n" -" General examples of the -gui option: \"x11vnc -gui\",\n" -" \"x11vnc -gui ez\" \"x11vnc -gui localhost:10\",\n" -" \"x11vnc -gui conn,host:0\", \"x11vnc -gui tray,ez\"\n" -" \"x11vnc -gui tray=setpass\"\n" -"\n" -" If you do not intend to start x11vnc from the gui\n" -" (i.e. just remote control an existing one), then the\n" -" gui process can run on a different machine from the\n" -" x11vnc server as long as X permissions, etc. permit\n" -" communication between the two.\n" -"\n" -"-remote command Remotely control some aspects of an already running\n" -" x11vnc server. \"-R\" and \"-r\" are aliases for\n" -" \"-remote\". After the remote control command is\n" -" sent to the running server the 'x11vnc -remote ...'\n" -" command exits. You can often use the -query command\n" -" (see below) to see if the x11vnc server processed your\n" -" -remote command.\n" -"\n" -" The default communication channel is that of X\n" -" properties (specifically VNC_CONNECT), and so this\n" -" command must be run with correct settings for DISPLAY\n" -" and possibly XAUTHORITY to connect to the X server\n" -" and set the property. Alternatively, use the -display\n" -" and -auth options to set them to the correct values.\n" -" The running server cannot use the -novncconnect option\n" -" because that disables the communication channel.\n" -" See below for alternate channels.\n" -"\n" -" For example: 'x11vnc -remote stop' (which is the same as\n" -" 'x11vnc -R stop') will close down the x11vnc server.\n" -" 'x11vnc -R shared' will enable shared connections, and\n" -" 'x11vnc -R scale:3/4' will rescale the desktop.\n" -"\n" -" The following -remote/-R commands are supported:\n" -"\n" -" stop terminate the server, same as \"quit\"\n" -" \"exit\" or \"shutdown\".\n" -" ping see if the x11vnc server responds.\n" -" Return is: ans=ping:<xdisplay>\n" -" blacken try to push a black fb update to all\n" -" clients (due to timings a client\n" -" could miss it). Same as \"zero\", also\n" -" \"zero:x1,y1,x2,y2\" for a rectangle.\n" -" refresh send the entire fb to all clients.\n" -" reset recreate the fb, polling memory, etc.\n" -/* ext. cmd. */ -" id:windowid set -id window to \"windowid\". empty\n" -" or \"root\" to go back to root window\n" -" sid:windowid set -sid window to \"windowid\"\n" -" waitmapped wait until subwin is mapped.\n" -" nowaitmapped do not wait until subwin is mapped.\n" -" clip:WxH+X+Y set -clip mode to \"WxH+X+Y\"\n" -" flashcmap enable -flashcmap mode.\n" -" noflashcmap disable -flashcmap mode.\n" -" shiftcmap:n set -shiftcmap to n.\n" -" notruecolor enable -notruecolor mode.\n" -" truecolor disable -notruecolor mode.\n" -" overlay enable -overlay mode (if applicable).\n" -" nooverlay disable -overlay mode.\n" -" overlay_cursor in -overlay mode, enable cursor drawing.\n" -" overlay_nocursor disable cursor drawing. same as\n" -" nooverlay_cursor.\n" -" visual:vis set -visual to \"vis\"\n" -" scale:frac set -scale to \"frac\"\n" -" scale_cursor:f set -scale_cursor to \"f\"\n" -" viewonly enable -viewonly mode.\n" -/* access view,share,forever */ -" noviewonly disable -viewonly mode.\n" -" shared enable -shared mode.\n" -" noshared disable -shared mode.\n" -" forever enable -forever mode.\n" -" noforever disable -forever mode.\n" -" timeout:n reset -timeout to n, if there are\n" -" currently no clients, exit unless one\n" -" connects in the next n secs.\n" -/* access */ -" http enable http client connections.\n" -" nohttp disable http client connections.\n" -" deny deny any new connections, same as \"lock\"\n" -" nodeny allow new connections, same as \"unlock\"\n" -/* access, filename */ -" connect:host do reverse connection to host, \"host\"\n" -" may be a comma separated list of hosts\n" -" or host:ports. See -connect.\n" -" disconnect:host disconnect any clients from \"host\"\n" -" same as \"close:host\". Use host\n" -" \"all\" to close all current clients.\n" -" If you know the client internal hex ID,\n" -" e.g. 0x3 (returned by \"-query clients\"\n" -" and RFB_CLIENT_ID) you can use that too.\n" -/* access */ -" allowonce:host For the next connection only, allow\n" -" connection from \"host\".\n" -/* access */ -" allow:hostlist set -allow list to (comma separated)\n" -" \"hostlist\". See -allow and -localhost.\n" -" Do not use with -allow /path/to/file\n" -" Use \"+host\" to add a single host, and\n" -" use \"-host\" to delete a single host\n" -" localhost enable -localhost mode\n" -" nolocalhost disable -localhost mode\n" -" listen:str set -listen to str, empty to disable.\n" -" nolookup enable -nolookup mode.\n" -" lookup disable -nolookup mode.\n" -" input:str set -input to \"str\", empty to disable.\n" -" client_input:str set the K, M, B -input on a per-client\n" -" basis. select which client as for\n" -" disconnect, e.g. client_input:host:MB\n" -" or client_input:0x2:K\n" -/* ext. cmd. */ -" accept:cmd set -accept \"cmd\" (empty to disable).\n" -" gone:cmd set -gone \"cmd\" (empty to disable).\n" -" noshm enable -noshm mode.\n" -" shm disable -noshm mode (i.e. use shm).\n" -" flipbyteorder enable -flipbyteorder mode, you may need\n" -" to set noshm for this to do something.\n" -" noflipbyteorder disable -flipbyteorder mode.\n" -" onetile enable -onetile mode. (you may need to\n" -" set shm for this to do something)\n" -" noonetile disable -onetile mode.\n" -/* ext. cmd. */ -" solid enable -solid mode\n" -" nosolid disable -solid mode.\n" -" solid_color:color set -solid color (and apply it).\n" -" blackout:str set -blackout \"str\" (empty to disable).\n" -" See -blackout for the form of \"str\"\n" -" (basically: WxH+X+Y,...)\n" -" Use \"+WxH+X+Y\" to append a single\n" -" rectangle use \"-WxH+X+Y\" to delete one\n" -" xinerama enable -xinerama mode. (if applicable)\n" -" noxinerama disable -xinerama mode.\n" -" xtrap enable -xtrap input mode(if applicable)\n" -" noxtrap disable -xtrap input mode.\n" -" xrandr enable -xrandr mode. (if applicable)\n" -" noxrandr disable -xrandr mode.\n" -" xrandr_mode:mode set the -xrandr mode to \"mode\".\n" -" padgeom:WxH set -padgeom to WxH (empty to disable)\n" -" If WxH is \"force\" or \"do\" the padded\n" -" geometry fb is immediately applied.\n" -" quiet enable -quiet mode.\n" -" noquiet disable -quiet mode.\n" -" modtweak enable -modtweak mode.\n" -" nomodtweak enable -nomodtweak mode.\n" -" xkb enable -xkb modtweak mode.\n" -" noxkb disable -xkb modtweak mode.\n" -" skip_keycodes:str enable -xkb -skip_keycodes \"str\".\n" -" sloppy_keys enable -sloppy_keys mode.\n" -" nosloppy_keys disable -sloppy_keys mode.\n" -" skip_dups enable -skip_dups mode.\n" -" noskip_dups disable -skip_dups mode.\n" -" add_keysyms enable -add_keysyms mode.\n" -" noadd_keysyms stop adding keysyms. those added will\n" -" still be removed at exit.\n" -" clear_mods enable -clear_mods mode and clear them.\n" -" noclear_mods disable -clear_mods mode.\n" -" clear_keys enable -clear_keys mode and clear them.\n" -" noclear_keys disable -clear_keys mode.\n" -/* filename */ -" remap:str set -remap \"str\" (empty to disable).\n" -" See -remap for the form of \"str\"\n" -" (basically: key1-key2,key3-key4,...)\n" -" Use \"+key1-key2\" to append a single\n" -" keymapping, use \"-key1-key2\" to delete.\n" -" norepeat enable -norepeat mode.\n" -" repeat disable -norepeat mode.\n" -" nofb enable -nofb mode.\n" -" fb disable -nofb mode.\n" -" bell enable bell (if supported).\n" -" nobell disable bell.\n" -" nosel enable -nosel mode.\n" -" sel disable -nosel mode.\n" -" noprimary enable -noprimary mode.\n" -" primary disable -noprimary mode.\n" -" seldir:str set -seldir to \"str\"\n" -" cursor:mode enable -cursor \"mode\".\n" -" show_cursor enable showing a cursor.\n" -" noshow_cursor disable showing a cursor. (same as\n" -" \"nocursor\")\n" -" arrow:n set -arrow to alternate n.\n" -" xfixes enable xfixes cursor shape mode.\n" -" noxfixes disable xfixes cursor shape mode.\n" -" alphacut:n set -alphacut to n.\n" -" alphafrac:f set -alphafrac to f.\n" -" alpharemove enable -alpharemove mode.\n" -" noalpharemove disable -alpharemove mode.\n" -" alphablend disable -noalphablend mode.\n" -" noalphablend enable -noalphablend mode.\n" -" cursorshape disable -nocursorshape mode.\n" -" nocursorshape enable -nocursorshape mode.\n" -" cursorpos disable -nocursorpos mode.\n" -" nocursorpos enable -nocursorpos mode.\n" -" xwarp enable -xwarppointer mode.\n" -" noxwarp disable -xwarppointer mode.\n" -" buttonmap:str set -buttonmap \"str\", empty to disable\n" -" dragging disable -nodragging mode.\n" -" nodragging enable -nodragging mode.\n" -" wireframe enable -wireframe mode. same as \"wf\"\n" -" nowireframe disable -wireframe mode. same as \"nowf\"\n" -" wireframe:str enable -wireframe mode string.\n" -" wireframe_mode:str enable -wireframe mode string.\n" -" wirecopyrect:str set -wirecopyrect string. same as \"wcr:\"\n" -" scrollcopyrect:str set -scrollcopyrect string. same \"scr\"\n" -" noscrollcopyrect disable -scrollcopyrect mode. \"noscr\"\n" -" scr_area:n set -scr_area to n\n" -" scr_skip:list set -scr_skip to \"list\"\n" -" scr_inc:list set -scr_inc to \"list\"\n" -" scr_keys:list set -scr_keys to \"list\"\n" -" scr_term:list set -scr_term to \"list\"\n" -" scr_keyrepeat:str set -scr_keyrepeat to \"str\"\n" -" scr_parms:str set -scr_parms parameters.\n" -" fixscreen:str set -fixscreen to \"str\".\n" -" noxrecord disable all use of RECORD extension.\n" -" xrecord enable use of RECORD extension.\n" -" reset_record reset RECORD extension (if avail.)\n" -" pointer_mode:n set -pointer_mode to n. same as \"pm\"\n" -" input_skip:n set -input_skip to n.\n" -" speeds:str set -speeds to str.\n" -" wmdt:str set -wmdt to str.\n" -" debug_pointer enable -debug_pointer, same as \"dp\"\n" -" nodebug_pointer disable -debug_pointer, same as \"nodp\"\n" -" debug_keyboard enable -debug_keyboard, same as \"dk\"\n" -" nodebug_keyboard disable -debug_keyboard, same as \"nodk\"\n" -" defer:n set -defer to n ms,same as deferupdate:n\n" -" wait:n set -wait to n ms.\n" -" wait_ui:f set -wait_ui factor to f.\n" -" wait_bog disable -nowait_bog mode.\n" -" nowait_bog enable -nowait_bog mode.\n" -" slow_fb:f set -slow_fb to f seconds.\n" -" readtimeout:n set read timeout to n seconds.\n" -" nap enable -nap mode.\n" -" nonap disable -nap mode.\n" -" sb:n set -sb to n s, same as screen_blank:n\n" -" xdamage enable xdamage polling hints.\n" -" noxdamage disable xdamage polling hints.\n" -" xd_area:A set -xd_area max pixel area to \"A\"\n" -" xd_mem:f set -xd_mem remembrance to \"f\"\n" -" fs:frac set -fs fraction to \"frac\", e.g. 0.5\n" -" gaps:n set -gaps to n.\n" -" grow:n set -grow to n.\n" -" fuzz:n set -fuzz to n.\n" -" snapfb enable -snapfb mode.\n" -" nosnapfb disable -snapfb mode.\n" -" rawfb:str set -rawfb mode to \"str\".\n" -" progressive:n set libvncserver -progressive slice\n" -" height parameter to n.\n" -" desktop:str set -desktop name to str for new clients.\n" -" rfbport:n set -rfbport to n.\n" -/* access */ -" httpport:n set -httpport to n.\n" -" httpdir:dir set -httpdir to dir (and enable http).\n" -" enablehttpproxy enable -enablehttpproxy mode.\n" -" noenablehttpproxy disable -enablehttpproxy mode.\n" -" alwaysshared enable -alwaysshared mode.\n" -" noalwaysshared disable -alwaysshared mode.\n" -" (may interfere with other options)\n" -" nevershared enable -nevershared mode.\n" -" nonevershared disable -nevershared mode.\n" -" (may interfere with other options)\n" -" dontdisconnect enable -dontdisconnect mode.\n" -" nodontdisconnect disable -dontdisconnect mode.\n" -" (may interfere with other options)\n" -" debug_xevents enable debugging X events.\n" -" nodebug_xevents disable debugging X events.\n" -" debug_xdamage enable debugging X DAMAGE mechanism.\n" -" nodebug_xdamage disable debugging X DAMAGE mechanism.\n" -" debug_wireframe enable debugging wireframe mechanism.\n" -" nodebug_wireframe disable debugging wireframe mechanism.\n" -" debug_scroll enable debugging scrollcopy mechanism.\n" -" nodebug_scroll disable debugging scrollcopy mechanism.\n" -" debug_tiles enable -debug_tiles\n" -" nodebug_tiles disable -debug_tiles\n" -" debug_grabs enable -debug_grabs\n" -" nodebug_grabs disable -debug_grabs\n" -" dbg enable -dbg crash shell\n" -" nodbg disable -dbg crash shell\n" -"\n" -" noremote disable the -remote command processing,\n" -" it cannot be turned back on.\n" -"\n" -" The vncconnect(1) command from standard VNC\n" -" distributions may also be used if string is prefixed\n" -" with \"cmd=\" E.g. 'vncconnect cmd=stop'. Under some\n" -" circumstances xprop(1) can used if it supports -set\n" -" (see the FAQ).\n" -"\n" -" If \"-connect /path/to/file\" has been supplied to the\n" -" running x11vnc server then that file can be used as a\n" -" communication channel (this is the only way to remote\n" -" control one of many x11vnc's polling the same X display)\n" -" Simply run: 'x11vnc -connect /path/to/file -remote ...'\n" -" or you can directly write to the file via something\n" -" like: \"echo cmd=stop > /path/to/file\", etc.\n" -"\n" -"-query variable Like -remote, except just query the value of\n" -" \"variable\". \"-Q\" is an alias for \"-query\".\n" -" Multiple queries can be done by separating variables\n" -" by commas, e.g. -query var1,var2. The results come\n" -" back in the form ans=var1:value1,ans=var2:value2,...\n" -" to the standard output. If a variable is read-only,\n" -" it comes back with prefix \"aro=\" instead of \"ans=\".\n" -"\n" -" Some -remote commands are pure actions that do not make\n" -" sense as variables, e.g. \"stop\" or \"disconnect\",\n" -" in these cases the value returned is \"N/A\". To direct\n" -" a query straight to the VNC_CONNECT property or connect\n" -" file use \"qry=...\" instead of \"cmd=...\"\n" -"\n" -" Here is the current list of \"variables\" that can\n" -" be supplied to the -query command. This includes the\n" -" \"N/A\" ones that return no useful info. For variables\n" -" names that do not correspond to an x11vnc option or\n" -" remote command, we hope the name makes it obvious what\n" -" the returned value corresponds to (hint: the ext_*\n" -" variables correspond to the presence of X extensions):\n" -"\n" -" ans= stop quit exit shutdown ping blacken zero\n" -" refresh reset close disconnect id sid waitmapped\n" -" nowaitmapped clip flashcmap noflashcmap shiftcmap\n" -" truecolor notruecolor overlay nooverlay overlay_cursor\n" -" overlay_yescursor nooverlay_nocursor nooverlay_cursor\n" -" nooverlay_yescursor overlay_nocursor visual scale\n" -" scale_cursor viewonly noviewonly shared noshared\n" -" forever noforever once timeout deny lock nodeny unlock\n" -" connect allowonce allow localhost nolocalhost listen\n" -" lookup nolookup accept gone shm noshm flipbyteorder\n" -" noflipbyteorder onetile noonetile solid_color solid\n" -" nosolid blackout xinerama noxinerama xtrap noxtrap\n" -" xrandr noxrandr xrandr_mode padgeom quiet q noquiet\n" -" modtweak nomodtweak xkb noxkb skip_keycodes sloppy_keys\n" -" nosloppy_keys skip_dups noskip_dups add_keysyms\n" -" noadd_keysyms clear_mods noclear_mods clear_keys\n" -" noclear_keys remap repeat norepeat fb nofb bell\n" -" nobell sel nosel primary noprimary seldir cursorshape\n" -" nocursorshape cursorpos nocursorpos cursor show_cursor\n" -" noshow_cursor nocursor arrow xfixes noxfixes xdamage\n" -" noxdamage xd_area xd_mem alphacut alphafrac alpharemove\n" -" noalpharemove alphablend noalphablend xwarppointer\n" -" xwarp noxwarppointer noxwarp buttonmap dragging\n" -" nodragging wireframe_mode wireframe wf nowireframe\n" -" nowf wirecopyrect wcr nowirecopyrect nowcr scr_area\n" -" scr_skip scr_inc scr_keys scr_term scr_keyrepeat\n" -" scr_parms scrollcopyrect scr noscrollcopyrect noscr\n" -" fixscreen noxrecord xrecord reset_record pointer_mode\n" -" pm input_skip input client_input speeds wmdt\n" -" debug_pointer dp nodebug_pointer nodp debug_keyboard\n" -" dk nodebug_keyboard nodk deferupdate defer wait_ui\n" -" wait_bog nowait_bog slow_fb wait readtimeout nap nonap\n" -" sb screen_blank fs gaps grow fuzz snapfb nosnapfb\n" -" rawfb progressive rfbport http nohttp httpport\n" -" httpdir enablehttpproxy noenablehttpproxy alwaysshared\n" -" noalwaysshared nevershared noalwaysshared dontdisconnect\n" -" nodontdisconnect desktop debug_xevents nodebug_xevents\n" -" debug_xevents debug_xdamage nodebug_xdamage\n" -" debug_xdamage debug_wireframe nodebug_wireframe\n" -" debug_wireframe debug_scroll nodebug_scroll debug_scroll\n" -" debug_tiles dbt nodebug_tiles nodbt debug_tiles\n" -" debug_grabs nodebug_grabs dbg nodbg noremote\n" -"\n" -" aro= noop display vncdisplay desktopname guess_desktop\n" -" http_url auth xauth users rootshift clipshift\n" -" scale_str scaled_x scaled_y scale_numer scale_denom\n" -" scale_fac scaling_blend scaling_nomult4 scaling_pad\n" -" scaling_interpolate inetd privremote unsafe safer nocmds\n" -" passwdfile using_shm logfile o flag rc norc h help V\n" -" version lastmod bg sigpipe threads readrate netrate\n" -" netlatency pipeinput clients client_count pid ext_xtest\n" -" ext_xtrap ext_xrecord ext_xkb ext_xshm ext_xinerama\n" -" ext_overlay ext_xfixes ext_xdamage ext_xrandr rootwin\n" -" num_buttons button_mask mouse_x mouse_y bpp depth\n" -" indexed_color dpy_x dpy_y wdpy_x wdpy_y off_x off_y\n" -" cdpy_x cdpy_y coff_x coff_y rfbauth passwd viewpasswd\n" -"\n" -"-QD variable Just like -query variable, but returns the default\n" -" value for that parameter (no running x11vnc server\n" -" is consulted)\n" -"\n" -"-sync By default -remote commands are run asynchronously, that\n" -" is, the request is posted and the program immediately\n" -" exits. Use -sync to have the program wait for an\n" -" acknowledgement from the x11vnc server that command was\n" -" processed (somehow). On the other hand -query requests\n" -" are always processed synchronously because they have\n" -" to wait for the answer.\n" -"\n" -" Also note that if both -remote and -query requests are\n" -" supplied on the command line, the -remote is processed\n" -" first (synchronously: no need for -sync), and then\n" -" the -query request is processed in the normal way.\n" -" This allows for a reliable way to see if the -remote\n" -" command was processed by querying for any new settings.\n" -" Note however that there is timeout of a few seconds so\n" -" if the x11vnc takes longer than that to process the\n" -" requests the requestor will think that a failure has\n" -" taken place.\n" -"\n" -"-noremote Do not process any remote control commands or queries.\n" -"-yesremote Do process remote control commands or queries.\n" -" Default: %s\n" -"\n" -" A note about security wrt remote control commands.\n" -" If someone can connect to the X display and change\n" -" the property VNC_CONNECT, then they can remotely\n" -" control x11vnc. Normally access to the X display is\n" -" protected. Note that if they can modify VNC_CONNECT\n" -" on the X server, they have enough permissions to also\n" -" run their own x11vnc and thus have complete control\n" -" of the desktop. If the \"-connect /path/to/file\"\n" -" channel is being used, obviously anyone who can write\n" -" to /path/to/file can remotely control x11vnc. So be\n" -" sure to protect the X display and that file's write\n" -" permissions. See -privremote below.\n" -"\n" -" If you are paranoid and do not think -noremote is\n" -" enough, to disable the VNC_CONNECT property channel\n" -" completely use -novncconnect, or use the -safer\n" -" option that shuts many things off.\n" -"\n" -"-unsafe A few remote commands are disabled by default\n" -" (currently: id:pick, accept:<cmd>, gone:<cmd>, and\n" -" rawfb:setup:<cmd>) because they are associated with\n" -" running external programs. If you specify -unsafe, then\n" -" these remote-control commands are allowed. Note that\n" -" you can still specify these parameters on the command\n" -" line, they just cannot be invoked via remote-control.\n" -"-safer Equivalent to: -novncconnect -noremote and prohibiting\n" -" -gui and the -connect file. Shuts off communcation\n" -" channels.\n" -"-privremote Perform some sanity checks and disable remote-control\n" -" commands if it appears that the X DISPLAY and/or\n" -" connectfile can be accessed by other users. Once\n" -" remote-control is disabled it cannot be turned back on.\n" -"-nocmds No external commands (e.g. system(3), popen(3), exec(3))\n" -" will be run.\n" -"\n" -"-deny_all For use with -remote nodeny: start out denying all\n" -" incoming clients until \"-remote nodeny\" is used to\n" -" let them in.\n" -"%s\n" -"\n" -"These options are passed to libvncserver:\n" -"\n" -; - /* have both our help and rfbUsage to stdout for more(1), etc. */ - dup2(1, 2); - - /* register extention(s) to get their help output */ -#ifdef LIBVNCSERVER_WITH_TIGHTVNC_FILETRANSFER - rfbRegisterTightVNCFileTransferExtension(); -#endif - - if (mode == 1) { - char *p; - int l = 0; - fprintf(stderr, "x11vnc: allow VNC connections to real " - "X11 displays. %s\n\nx11vnc options:\n", lastmod); - p = strtok(help, "\n"); - while (p) { - int w = 23; - char tmp[100]; - if (p[0] == '-') { - strncpy(tmp, p, w); - fprintf(stderr, " %s", tmp); - l++; - if (l % 2 == 0) { - fprintf(stderr, "\n"); - } - } - p = strtok(NULL, "\n"); - } - fprintf(stderr, "\n\nlibvncserver options:\n"); - rfbUsage(); - fprintf(stderr, "\n"); - exit(1); - } - fprintf(stderr, help, lastmod, - scaling_copyrect ? ":cr":":nocr", - view_only ? "on":"off", - shared ? "on":"off", - vnc_connect ? "-vncconnect":"-novncconnect", - use_modifier_tweak ? "-modtweak":"-nomodtweak", - skip_duplicate_key_events ? "-skip_dups":"-noskip_dups", - add_keysyms ? "-add_keysyms":"-noadd_keysyms", - no_autorepeat ? "-norepeat":"-repeat", - alt_arrow_max, alt_arrow, - alpha_threshold, - alpha_frac, - cursor_pos_updates ? "-cursorpos":"-nocursorpos", - wireframe ? "-wireframe":"-nowireframe", - WIREFRAME_PARMS, - wireframe_copyrect_default, - scroll_copyrect_default, - scrollcopyrect_min_area, - scroll_skip_str0 ? scroll_skip_str0 : "(empty)", - scroll_term_str0, - max_keyrepeat_str0, - SCROLL_COPYRECT_PARMS, - pointer_mode_max, pointer_mode, - ui_skip, - defer_update, - waitms, - wait_ui, - rfbMaxClientWait/1000, - take_naps ? "take naps":"no naps", - screen_blank, - xdamage_max_area, NSCAN, xdamage_memory, - use_threads ? "-threads":"-nothreads", - fs_frac, - gaps_fill, - grow_fill, - tile_fuzz, - accept_remote_cmds ? "-yesremote":"-noremote", - "" - ); - - rfbUsage(); -#endif - exit(1); -} - -void set_vnc_desktop_name(void) { - int sz = 256; - sprintf(vnc_desktop_name, "unknown"); - if (inetd) { - sprintf(vnc_desktop_name, "inetd-no-further-clients"); - } - if (screen->port) { - char *host = this_host(); - int lport = screen->port; - char *iface = listen_str; - - if (iface != NULL && *iface != '\0' && strcmp(iface, "any")) { - host = iface; - } - if (host != NULL) { - /* note that vncviewer special cases 5900-5999 */ - if (inetd) { - ; /* should not occur (port) */ - } else if (quiet) { - if (lport >= 5900) { - snprintf(vnc_desktop_name, sz, "%s:%d", - host, lport - 5900); - fprintf(stderr, "The VNC desktop is " - "%s\n", vnc_desktop_name); - } else { - snprintf(vnc_desktop_name, sz, "%s:%d", - host, lport); - fprintf(stderr, "The VNC desktop is " - "%s\n", vnc_desktop_name); - } - } else if (lport >= 5900) { - snprintf(vnc_desktop_name, sz, "%s:%d", - host, lport - 5900); - rfbLog("\n"); - rfbLog("The VNC desktop is %s\n", - vnc_desktop_name); - if (lport >= 6000) { - rfbLog("possible aliases: %s:%d, " - "%s::%d\n", host, lport, - host, lport); - } - } else { - snprintf(vnc_desktop_name, sz, "%s:%d", - host, lport); - rfbLog("\n"); - rfbLog("The VNC desktop is %s\n", - vnc_desktop_name); - rfbLog("possible alias: %s::%d\n", - host, lport); - } - } - fflush(stderr); - if (inetd) { - ; /* should not occur (port != 0) */ - } else { - fprintf(stdout, "PORT=%d\n", screen->port); - fflush(stdout); - if (flagfile) { - FILE *flag = fopen(flagfile, "w"); - if (flag) { - fprintf(flag, "PORT=%d\n",screen->port); - fflush(flag); - fclose(flag); - } else { - rfbLog("could not open flag file: %s\n", - flagfile); - } - } - } - fflush(stdout); - } -} - -/* - * utility to get the current host name - */ -#define MAXN 256 - -char *this_host(void) { - char host[MAXN]; -#if LIBVNCSERVER_HAVE_GETHOSTNAME - if (gethostname(host, MAXN) == 0) { - return strdup(host); - } -#endif - return NULL; -} - -/* * choose a desktop name */ static char *choose_title(char *display) { @@ -32331,7 +633,7 @@ static void check_rcfile(int argc, char **argv) { for (i=1; i < argc; i++) { if (!strcmp(argv[i], "-printgui")) { - fprintf(stdout, "%s", gui_code); + fprintf(stdout, "%s", get_gui_code()); fflush(stdout); exit(0); } @@ -32546,8 +848,7 @@ static void check_rcfile(int argc, char **argv) { } else { pwlast = 1; } - while (*p != '\0') - *p++ = '\0'; + strzero(p); } if (argc2 >= argmax) { fprintf(stderr, "too many rcfile options\n"); @@ -32556,7 +857,7 @@ static void check_rcfile(int argc, char **argv) { } } -void immediate_switch_user(int argc, char* argv[]) { +static void immediate_switch_user(int argc, char* argv[]) { int i; for (i=1; i < argc; i++) { char *u; @@ -32591,79 +892,7 @@ void immediate_switch_user(int argc, char* argv[]) { } } -void xopen_display_fail_message(char *disp) { - fprintf(stderr, "\n"); - fprintf(stderr, "*** x11vnc was unable to open the X DISPLAY: \"%s\"," - " it cannot continue.\n", disp); - fprintf(stderr, "*** There may be \"Xlib:\" error messages above" - " with details about the failure.\n"); - fprintf(stderr, "\n"); - fprintf(stderr, "Some tips and guidelines:\n"); - fprintf(stderr, "\n"); - fprintf(stderr, " * An X server (the one you wish to view) must" - " be running before x11vnc is\n"); - fprintf(stderr, " started: x11vnc does not start the X server.\n"); - fprintf(stderr, "\n"); - fprintf(stderr, " * You must use -display <disp>, -OR- set and" - " export your DISPLAY\n"); - fprintf(stderr, " environment variable to refer to the display of" - " the desired X server.\n"); - fprintf(stderr, " - Usually the display is simply \":0\" (in fact" - " x11vnc uses this if you forget\n"); - fprintf(stderr, " to specify it), but in some multi-user" - " situations it could be \":1\", \":2\",\n"); - fprintf(stderr, " or even \":137\". Ask your administrator" - " or a guru if you are having\n"); - fprintf(stderr, " difficulty determining what your X DISPLAY is.\n"); - fprintf(stderr, "\n"); - fprintf(stderr, " * Next, you need to have sufficient permissions" - " (Xauthority) \n"); - fprintf(stderr, " to connect to the X DISPLAY. Here are some" - " Tips:\n"); - fprintf(stderr, "\n"); - fprintf(stderr, " - Often, you just need to run x11vnc as the user" - " logged into the X session.\n"); - fprintf(stderr, " So make sure to be that user when you type" - " x11vnc.\n"); - fprintf(stderr, " - Being root is usually not enough because the" - " incorrect MIT-MAGIC-COOKIE\n"); - fprintf(stderr, " file will be accessed. The cookie file contains" - " the secret key that\n"); - fprintf(stderr, " allows x11vnc to connect to the desired" - " X DISPLAY.\n"); - fprintf(stderr, " - You can explicity indicate which MIT-MAGIC-COOKIE" - " file should be used\n"); - fprintf(stderr, " by the -auth option, e.g.:\n"); - fprintf(stderr, " x11vnc -auth /home/someuser/.Xauthority" - " -display :0\n"); - fprintf(stderr, " you must have read permission for that file.\n"); - fprintf(stderr, "\n"); - fprintf(stderr, " - If NO ONE is logged into an X session yet, but" - " there is a greeter login\n"); - fprintf(stderr, " program like \"gdm\", \"kdm\", \"xdm\", or" - " \"dtlogin\" running, you will need\n"); - fprintf(stderr, " to find and use the raw display manager" - " MIT-MAGIC-COOKIE file.\n"); - fprintf(stderr, " Some examples for various display managers:\n"); - fprintf(stderr, "\n"); - fprintf(stderr, " gdm: -auth /var/gdm/:0.Xauth\n"); - fprintf(stderr, " kdm: -auth /var/lib/kdm/A:0-crWk72\n"); - fprintf(stderr, " xdm: -auth /var/lib/xdm/authdir/authfiles/A:0-XQvaJk\n"); - fprintf(stderr, " dtlogin: -auth /var/dt/A:0-UgaaXa\n"); - fprintf(stderr, "\n"); - fprintf(stderr, " Only root will have read permission for the" - " file, and so x11vnc must be run\n"); - fprintf(stderr, " as root. The random characters in the filenames" - " will of course change,\n"); - fprintf(stderr, " and the directory the cookie file resides in may" - " also be system dependent.\n"); - fprintf(stderr, " Sometimes the command \"ps wwaux | grep auth\"" - " can reveal the file location.\n"); - fprintf(stderr, "\n"); - fprintf(stderr, "See also: http://www.karlrunge.com/x11vnc/#faq\n"); -} - -void print_settings(int try_http, int bg, char *gui_str) { +static void print_settings(int try_http, int bg, char *gui_str) { fprintf(stderr, "\n"); fprintf(stderr, "Settings:\n"); @@ -32703,6 +932,8 @@ void print_settings(int try_http, int bg, char *gui_str) { : "null"); fprintf(stderr, " accept: %s\n", accept_cmd ? accept_cmd : "null"); + fprintf(stderr, " accept: %s\n", afteraccept_cmd ? afteraccept_cmd + : "null"); fprintf(stderr, " gone: %s\n", gone_cmd ? gone_cmd : "null"); fprintf(stderr, " users: %s\n", users_list ? users_list @@ -32834,95 +1065,8 @@ void print_settings(int try_http, int bg, char *gui_str) { rfbLog("x11vnc version: %s\n", lastmod); } -void nopassword_warning_msg(int gotloc) { - - char str1[] = -"###############################################################\n" -"#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#\n" -"#@ @#\n" -"#@ ** WARNING ** WARNING ** WARNING ** WARNING ** @#\n" -"#@ @#\n" -"#@ YOU ARE RUNNING X11VNC WITHOUT A PASSWORD!! @#\n" -"#@ @#\n" -"#@ This means anyone with network access to this computer @#\n" -"#@ will be able to easily view and control your desktop. @#\n" -"#@ @#\n" -"#@ >>> If you did not mean to do this Press CTRL-C now!! <<< @#\n" -"#@ @#\n" -"#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#\n" -; - char str2[] = -"#@ @#\n" -"#@ You can create an x11vnc password file by running: @#\n" -"#@ @#\n" -"#@ x11vnc -storepasswd password /path/to/passfile @#\n" -"#@ @#\n" -"#@ and then starting x11vnc via: @#\n" -"#@ @#\n" -"#@ x11vnc -rfbauth /path/to/passfile @#\n" -"#@ @#\n" -"#@ an existing ~/.vnc/passwd file will work too. @#\n" -"#@ @#\n" -"#@ You can also use the -passwdfile or -passwd options. @#\n" -"#@ (note -passwd is unsafe if local users are not trusted) @#\n" -"#@ @#\n" -"#@ Make sure any -rfbauth and -passwdfile password files @#\n" -"#@ cannot be read by untrusted users. @#\n" -"#@ @#\n" -"#@ Even with a password, the subsequent VNC traffic is @#\n" -"#@ sent in the clear. Consider tunnelling via ssh(1): @#\n" -"#@ @#\n" -"#@ http://www.karlrunge.com/x11vnc/#tunnelling @#\n" -"#@ @#\n" -"#@ Please Read the documention for more info about @#\n" -"#@ passwords, security, and encryption. @#\n" -"#@ @#\n" -"#@ http://www.karlrunge.com/x11vnc/#faq-passwd @#\n" -; - char str3[] = -"#@ @#\n" -"#@ You are using the -localhost option and that is a good @#\n" -"#@ thing!! Especially if you ssh(1) into this machine and @#\n" -"#@ use port redirection. Nevertheless, without a password @#\n" -"#@ other users could possibly do redirection as well to @#\n" -"#@ gain access to your desktop. @#\n" -; - char str4[] = -"#@ @#\n" -"#@ To disable this warning use the -nopw option, or put @#\n" -"#@ the setting in your ~/.x11vncrc file. @#\n" -"#@ @#\n" -"#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#\n" -"###############################################################\n" -; - char str5[] = -"###############################################################\n\n" -; - if (inetd) { - return; - } - fprintf(stderr, "%s", str1); - fflush(stderr); -#if !PASSWD_REQUIRED - usleep(2500 * 1000); -#endif - if (!quiet) { - fprintf(stderr, "%s", str2); - if (gotloc) { - fprintf(stderr, "%s", str3); - } - fprintf(stderr, "%s", str4); - } else { - fprintf(stderr, "%s", str5); - } - fflush(stderr); -#if !PASSWD_REQUIRED - usleep(500 * 1000); -#endif -} - -void check_loop_mode(int argc, char* argv[]) { +static void check_loop_mode(int argc, char* argv[]) { int i; int loop_mode = 0, loop_sleep = 2000, loop_max = 0; @@ -33209,6 +1353,9 @@ int main(int argc, char* argv[]) { } else if (!strcmp(arg, "-accept")) { CHECK_ARGC accept_cmd = strdup(argv[++i]); + } else if (!strcmp(arg, "-afteraccept")) { + CHECK_ARGC + afteraccept_cmd = strdup(argv[++i]); } else if (!strcmp(arg, "-gone")) { CHECK_ARGC gone_cmd = strdup(argv[++i]); @@ -33800,144 +1947,24 @@ int main(int argc, char* argv[]) { for (i=pw_loc; i <= pw_loc+1; i++) { if (i < argc) { char *p = argv[i]; - while (*p != '\0') { - *p++ = '\0'; - } + strzero(p); } } } else if (passwdfile) { /* read passwd(s) from file */ - char line[1024]; - char *filename; - int remove = 0; - struct stat sbuf; - int linecount = 0, i, max; - FILE *in; - - filename = passwdfile; - if (strstr(filename, "rm:") == filename) { - filename += strlen("rm:"); - remove = 1; - } - - if (stat(filename, &sbuf) == 0) { - /* upper bound to number of lines... */ - max = (int) sbuf.st_size; - } else { - max = 16; - } - - /* 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", passwdfile); - rfbLogPerror("fopen"); - if (remove) { - unlink(filename); - } - exit(1); - } - - while (fgets(line, 1024, in) != NULL) { - char *p; - int blank = 1; - int len = strlen(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_viewonly < 0) { - begin_viewonly = 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 (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", - passwdfile); - exit(1); + if (read_passwds(passwdfile)) { + argv_vnc[argc_vnc++] = strdup("-passwd"); + argv_vnc[argc_vnc++] = strdup(passwd_list[0]); + got_passwd = 1; + pw_loc = 100; /* just for pw_loc check below */ } - - 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); - while (*p != '\0') { - *p = '\0'; p++; - } - } - argv_vnc[argc_vnc++] = strdup("-passwd"); - argv_vnc[argc_vnc++] = strdup(passwd_list[0]); - got_passwd = 1; - pw_loc = 100; /* just for pw_loc check below */ - - if (begin_viewonly < 0 && linecount == 2) { - /* for compatibility with previous 2-line usage: */ - viewonly_passwd = strdup(passwd_list[1]); - begin_viewonly = 1; - } - } if (vpw_loc > 0) { int i; for (i=vpw_loc; i <= vpw_loc+1; i++) { if (i < argc) { char *p = argv[i]; - while (*p != '\0') { - *p++ = '\0'; - } + strzero(p); } } } @@ -34655,4 +2682,5 @@ int main(int argc, char* argv[]) { #undef argc #undef argv + } |