summaryrefslogtreecommitdiffstats
path: root/x11vnc/x11vnc.c
diff options
context:
space:
mode:
authorrunge <runge>2005-04-10 04:30:48 +0000
committerrunge <runge>2005-04-10 04:30:48 +0000
commitbaee5e2b3a00993fee00dca9d4e560f904693a6c (patch)
tree7cea15f636074f4d81fd100f6f37cc25750f3211 /x11vnc/x11vnc.c
parentac01f36ce0e2630db608537641b0335b249fea3c (diff)
downloadlibtdevnc-baee5e2b3a00993fee00dca9d4e560f904693a6c.tar.gz
libtdevnc-baee5e2b3a00993fee00dca9d4e560f904693a6c.zip
x11vnc: -rawfb, -pipeinput, -xtrap, -flag, ...
Diffstat (limited to 'x11vnc/x11vnc.c')
-rw-r--r--x11vnc/x11vnc.c1530
1 files changed, 1326 insertions, 204 deletions
diff --git a/x11vnc/x11vnc.c b/x11vnc/x11vnc.c
index d98a4c1..ef3faf4 100644
--- a/x11vnc/x11vnc.c
+++ b/x11vnc/x11vnc.c
@@ -139,6 +139,8 @@
#endif
#if OLD_TREE
+/* BEGIN OLD TREE */
+
/*
* if you have a very old tree (LibVNCServer 0.6) and get errors these may
* be need to be uncommented. LibVNCServer <= 0.5 is no longer supported.
@@ -170,6 +172,7 @@
#define LIBVNCSERVER_HAVE_PWD_H 1
#define LIBVNCSERVER_HAVE_SYS_WAIT_H 1
#define LIBVNCSERVER_HAVE_UTMPX_H 1
+#define LIBVNCSERVER_HAVE_MMAP 1
/*
#define LIBVNCSERVER_HAVE_LIBXINERAMA 1
@@ -177,15 +180,17 @@
#define LIBVNCSERVER_HAVE_LIBXDAMAGE 1
*/
-#endif /* OLD_TREE */
-/****************************************************************************/
+/* END OLD TREE */
+#endif
+/****************************************************************************/
/* 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>
@@ -291,6 +296,16 @@
#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 ;-)
+ */
+
/****************************************************************************/
@@ -308,7 +323,7 @@
#if LIBVNCSERVER_HAVE_XTEST
#include <X11/extensions/XTest.h>
#endif
-static int xtest_base_event_type = 0;
+int xtest_base_event_type = 0;
#if LIBVNCSERVER_HAVE_LIBXTRAP
#define NEED_EVENTS
@@ -317,7 +332,7 @@ static int xtest_base_event_type = 0;
#include <X11/extensions/xtraplibp.h>
XETC *trap_ctx = NULL;
#endif
-static int xtrap_base_event_type = 0;
+int xtrap_base_event_type = 0;
#if LIBVNCSERVER_HAVE_XKEYBOARD
#include <X11/XKBlib.h>
@@ -351,6 +366,10 @@ extern int h_errno;
#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.
@@ -400,8 +419,8 @@ int alt_arrow = 1;
#if LIBVNCSERVER_HAVE_LIBXFIXES
#include <X11/extensions/Xfixes.h>
-#endif
static int xfixes_base_event_type = 0;
+#endif
int xdamage_present = 0;
@@ -409,15 +428,15 @@ int use_xdamage = 1; /* just use the xdamage rects. for scanline hints */
#if LIBVNCSERVER_HAVE_LIBXDAMAGE
#include <X11/extensions/Xdamage.h>
Damage xdamage = 0;
-#endif
static int xdamage_base_event_type = 0;
+#endif
int xdamage_max_area = 20000; /* pixels */
double xdamage_memory = 1.0; /* in units of NSCAN */
int xdamage_tile_count;
/* date +'lastmod: %Y-%m-%d' */
-char lastmod[] = "0.7.2pre lastmod: 2005-04-03";
+char lastmod[] = "0.7.2pre lastmod: 2005-04-10";
int hack_val = 0;
/* X display info */
@@ -442,6 +461,7 @@ 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
/*
@@ -466,8 +486,16 @@ 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 *snap_fb = NULL; /* used under -snapfb */
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;
@@ -504,7 +532,7 @@ typedef struct _ClientData {
char *scale_str = NULL;
double scale_fac = 1.0;
int scaling = 0;
-int scaling_noblend = 0; /* no blending option (very course) */
+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 */
@@ -515,7 +543,7 @@ int scale_numer = 0, scale_denom = 0; /* n/m */
char *scale_cursor_str = NULL;
double scale_cursor_fac = 1.0;
int scaling_cursor = 0;
-int scaling_cursor_noblend = 0;
+int scaling_cursor_blend = 1;
int scaling_cursor_interpolate = 0;
int scale_cursor_numer = 0, scale_cursor_denom = 0;
@@ -602,6 +630,7 @@ double dtime(double *);
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);
@@ -624,7 +653,9 @@ void destroy_xdamage_if_needed(void);
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);
@@ -646,8 +677,11 @@ 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(void);
+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 read_vnc_connect_prop(void);
@@ -722,6 +756,7 @@ 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 */
char *clip_str = NULL; /* -clip */
@@ -776,10 +811,16 @@ 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 xtrap_input = 0; /* -xtrap for user input insertion */
int xinerama = 0; /* -xinerama */
int xrandr = 0; /* -xrandr */
int xrandr_present = 0;
@@ -857,29 +898,12 @@ int visual_depth = 0;
int overlay = 0;
int overlay_cursor = 1;
-#if LIBVNCSERVER_HAVE_XSHM
-int xshm_present = 1;
-#else
int xshm_present = 0;
-#endif
-#if LIBVNCSERVER_HAVE_XTEST
-int xtest_present = 1;
-#else
int xtest_present = 0;
-#endif
-#if LIBVNCSERVER_HAVE_LIBXTRAP
-int xtrap_present = 1;
-#else
int xtrap_present = 0;
-#endif
-#if LIBVNCSERVER_HAVE_XKEYBOARD
-int xkb_present = 1;
-#else
int xkb_present = 0;
-#endif
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 */
@@ -2253,6 +2277,24 @@ XImage *XCreateImage_wr(Display *disp, Visual *visual, unsigned int depth,
* 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);
@@ -2270,8 +2312,52 @@ XImage *XCreateImage_wr(Display *disp, Visual *visual, unsigned int depth,
width, height, bitmap_pad, bytes_per_line);
}
-void copy_image(XImage *dest, int x, int y, unsigned int w, unsigned int h) {
+void copy_raw_fb(XImage *dest, int x, int y, unsigned int w, unsigned int h) {
+ char *src, *dst;
+ int line, pixelsize = bpp/8;
+ if (! raw_fb_seek) {
+ src = (raw_fb_addr + raw_fb_offset)
+ + raw_fb_image->bytes_per_line*y + pixelsize*x;
+ dst = dest->data;
+
+ for (line = 0; line < h; line++) {
+ memcpy(dst, src, w * pixelsize);
+ src += raw_fb_image->bytes_per_line;
+ dst += dest->bytes_per_line;
+ }
+ } else{
+ int n, len, del, sz = w * pixelsize;
+ int bpl = raw_fb_image->bytes_per_line;
+ 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;
+ }
+ }
+ }
+ 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;
@@ -2291,17 +2377,44 @@ void copy_image(XImage *dest, int x, int y, unsigned int w, unsigned int h) {
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 && w == dest->width && 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); \
+ }
+
/*
* 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;
+ }
+#if LIBVNCSERVER_HAVE_LIBXTRAP
+ XESimulateXEventRequest(trap_ctx, down ? KeyPress : KeyRelease,
+ key, 0, 0, 0);
+#else
+ DEBUG_SKIPPED_INPUT(debug_keyboard, "keyboard: no-XTRAP-build");
+#endif
+}
+
void XTestFakeKeyEvent_wr(Display* dpy, KeyCode key, Bool down,
unsigned long delay) {
if (debug_keyboard) {
@@ -2309,41 +2422,81 @@ void XTestFakeKeyEvent_wr(Display* dpy, KeyCode key, Bool down,
key, XKeysymToString(XKeycodeToKeysym(dpy, key, 0)),
down ? "down":"up");
}
- if (! xtest_present) {
- return;
- }
if (down) {
last_keyboard_input = -key;
} else {
last_keyboard_input = key;
}
+
+ if (xtrap_input) {
+ return XTRAP_FakeKeyEvent_wr(dpy, key, down, delay);
+ }
+
+ if (! xtest_present) {
+ DEBUG_SKIPPED_INPUT(debug_keyboard, "keyboard: no-XTEST");
+ return;
+ }
#if LIBVNCSERVER_HAVE_XTEST
XTestFakeKeyEvent(dpy, key, down, delay);
#endif
}
-/* XTRAP: XESimulateXEventRequest(tc, KeyPress, key, 0, 0, 0); */
+
+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;
+ }
+#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) {
+ return XTRAP_FakeButtonEvent_wr(dpy, button, is_press, delay);
+ }
+
if (! xtest_present) {
+ DEBUG_SKIPPED_INPUT(debug_keyboard, "button: no-XTEST");
return;
}
#if LIBVNCSERVER_HAVE_XTEST
XTestFakeButtonEvent(dpy, button, is_press, delay);
#endif
}
-/* XTRAP: XESimulateXEventRequest(tc, ButtonPress, button, 0, 0, 0); */
-void XTestFakeMotionEvent_wr(Display* dpy, int screen, int x, int y,
+void XTRAP_FakeMotionEvent_wr(Display* dpy, int screen, int x, int y,
unsigned long delay) {
- if (! xtest_present) {
+
+ if (! xtrap_present) {
+ DEBUG_SKIPPED_INPUT(debug_keyboard, "motion: no-XTRAP");
return;
}
+#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) {
+ return XTRAP_FakeMotionEvent_wr(dpy, screen, x, y, delay);
+ }
+
#if LIBVNCSERVER_HAVE_XTEST
XTestFakeMotionEvent(dpy, screen, x, y, delay);
#endif
}
-/* XTRAP: XESimulateXEventRequest(tc, MotionNotify, 0, x, y, 0); */
Bool XTestCompareCurrentCursorWithWindow_wr(Display* dpy, Window w) {
if (! xtest_present) {
@@ -2376,17 +2529,6 @@ Bool XTestCompareCursorWithWindow_wr(Display* dpy, Window w, Cursor cursor) {
#endif
#endif
-int XTestGrabControl_wr(Display* dpy, Bool impervious) {
- if (! xtest_present) {
- return 0;
- }
-#if LIBVNCSERVER_HAVE_XTEST && LIBVNCSERVER_HAVE_XTESTGRABCONTROL
- return XTestGrabControl(dpy, impervious);
-#else
- return 0;
-#endif
-}
-
Bool XTestQueryExtension_wr(Display *dpy, int *ev, int *er, int *maj,
int *min) {
#if LIBVNCSERVER_HAVE_XTEST
@@ -2414,32 +2556,86 @@ Bool XETrapQueryExtension_wr(Display *dpy, int *ev, int *er, int *op) {
#endif
}
-void disable_grabserver(void) {
-#if LIBVNCSERVER_HAVE_XTEST && LIBVNCSERVER_HAVE_XTESTGRABCONTROL
- if (XTestGrabControl_wr(dpy, True)) {
- return;
+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) {
+ return 0;
+ }
#if LIBVNCSERVER_HAVE_LIBXTRAP
- if (xtrap_present) {
+ else {
ReqFlags requests;
- trap_ctx = XECreateTC(dpy, 0, NULL);
+ if (! impervious) {
+ if (trap_ctx) {
+ XEFreeTC(trap_ctx);
+ }
+ trap_ctx = NULL;
+ return 1;
+ }
+
if (! trap_ctx) {
- rfbLog("DEC-XTRAP XECreateTC failed. Watch out for"
- "XGrabServer from wm's\n");
- return;
+ 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);
}
- 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;
+ return 1;
}
#endif
- rfbLog("No XTEST or DEC-XTRAP protection from XGrabServer.\n");
+ return 0;
+}
+
+void disable_grabserver(void) {
+ int ok = 0;
+
+ if (! xtrap_input) {
+ if (XTestGrabControl_wr(dpy, True)) {
+ XTRAP_GrabControl_wr(dpy, False);
+ rfbLog("GrabServer control via XTEST.\n");
+ ok = 1;
+ } else {
+ if (XTRAP_GrabControl_wr(dpy, True)) {
+ ok = 1;
+ rfbLog("Using DEC-XTRAP for protection from "
+ "XGrabServer.\n");
+ }
+ }
+ } else {
+ if (XTRAP_GrabControl_wr(dpy, True)) {
+ XTestGrabControl_wr(dpy, False);
+ rfbLog("GrabServer control via DEC-XTRAP.\n");
+ ok = 1;
+ } else {
+ if (XTestGrabControl_wr(dpy, True)) {
+ ok = 1;
+ rfbLog("DEC-XTRAP XGrabServer protection not "
+ "available, using XTEST.\n");
+ }
+ }
+ }
+ if (! ok) {
+ rfbLog("No XTEST or DEC-XTRAP protection from XGrabServer.\n");
+ rfbLog("Deadlock if your window manager calls XGrabServer!!\n");
+ }
}
@@ -2454,6 +2650,8 @@ 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.
@@ -2501,6 +2699,10 @@ void clean_up_exit (int ret) {
/* remove the shm areas: */
clean_shm(0);
+ if (! dpy) {
+ exit(ret); /* raw_rb hack */
+ }
+
/* X keyboard cleanups */
delete_added_keycodes();
@@ -3090,6 +3292,8 @@ static int run_user_command(char *cmd, rfbClientPtr client, char *mode) {
static void client_gone(rfbClientPtr client) {
client_count--;
+ if (client_count < 0) client_count = 0;
+
rfbLog("client_count: %d\n", client_count);
if (no_autorepeat && client_count == 0) {
@@ -3829,7 +4033,7 @@ static int accept_client(rfbClientPtr client) {
*/
static void check_connect_file(char *file) {
FILE *in;
- char line[1024], host[1024];
+ 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);
@@ -3862,11 +4066,19 @@ static void check_connect_file(char *file) {
return;
}
- if (fgets(line, 1024, in) != NULL) {
+ if (fgets(line, VNC_CONNECT_MAX, in) != NULL) {
if (sscanf(line, "%s", host) == 1) {
if (strlen(host) > 0) {
char *str = strdup(host);
- rfbLog("read connect file: %s\n", 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;
}
}
@@ -4141,8 +4353,11 @@ enum rfbNewClientAction new_client(rfbClientPtr client) {
client->clientGoneHook = client_gone;
client_count++;
- if (no_autorepeat && client_count == 1) {
- /* first client, turn off X server autorepeat */
+ 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);
}
if (use_solid_bg && client_count == 1) {
@@ -5486,6 +5701,8 @@ void initialize_allowed_input(void) {
}
void initialize_keyboard_and_pointer(void) {
+ if (raw_fb && ! dpy) return; /* raw_fb hack */
+
if (use_modifier_tweak) {
initialize_modtweak();
}
@@ -5747,6 +5964,39 @@ void get_allowed_input(rfbClientPtr client, allowed_input_t *input) {
}
}
+/* 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();
+}
+
/*
* key event handler. See the above functions for contortions for
* running under -modtweak.
@@ -5767,6 +6017,19 @@ void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) {
X_UNLOCK;
}
+ 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 = time(0);
+ got_user_input++;
+ got_keyboard_input++;
+ }
+ return;
+ }
+ }
+
if (view_only) {
return;
}
@@ -6230,6 +6493,68 @@ static void update_x11_pointer_mask(int 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
@@ -6253,13 +6578,6 @@ void pointer(int mask, int x, int y, rfbClientPtr client) {
}
}
- if (view_only) {
- return;
- }
- get_allowed_input(client, &input);
- if (! input.motion && ! input.button) {
- return;
- }
if (scaling) {
/* map from rfb size to X11 size: */
x = ((double) x / scaled_x) * dpy_x;
@@ -6268,6 +6586,29 @@ void pointer(int mask, int x, int y, rfbClientPtr client) {
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 = mask;
+ }
+ return;
+ }
+ }
+
+ if (view_only) {
+ return;
+ }
+ get_allowed_input(client, &input);
+ if (! input.motion && ! input.button) {
+ return;
+ }
if (mask >= 0) {
/*
* mask = -1 is a special case call from scan_for_updates()
@@ -6383,6 +6724,199 @@ void pointer(int mask, int x, int y, rfbClientPtr client) {
}
}
+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;
+ char pid[16];
+
+ 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 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);
+ }
+
+ 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 like 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 Pointer like 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 yours stream:\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.
@@ -7067,6 +7601,9 @@ void check_xevents(void) {
static time_t last_sync = 0;
time_t now = time(0);
+ if (! dpy) { /* raw_fb hack */
+ return;
+ }
if (now > last_init_check+1) {
last_init_check = now;
initialize_xevents();
@@ -7102,7 +7639,7 @@ void check_xevents(void) {
if (no_autorepeat && have_clients && no_repeat_countdown) {
static time_t last_check = 0;
- if (now > last_check + 1) {
+ if (now > last_check + 1 && ! view_only) {
last_check = now;
X_UNLOCK;
if (get_autorepeat_state() != 0) {
@@ -8202,6 +8739,7 @@ char *process_remote_cmd(char *cmd, int stringonly) {
}
rfbLog("process_remote_cmd: disable viewonly mode.\n");
view_only = 0;
+ if (raw_fb) set_raw_fb_params(0);
} else if (!strcmp(p, "shared")) {
if (query) {
@@ -8551,6 +9089,8 @@ char *process_remote_cmd(char *cmd, int stringonly) {
}
rfbLog("process_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 {
@@ -8647,6 +9187,7 @@ char *process_remote_cmd(char *cmd, int stringonly) {
}
solid_str = new;
use_solid_bg = 1;
+ if (raw_fb) set_raw_fb_params(0);
if (doit && client_count) {
solid_bg(0);
@@ -8662,6 +9203,7 @@ char *process_remote_cmd(char *cmd, int stringonly) {
solid_str = strdup(solid_default);
}
use_solid_bg = 1;
+ if (raw_fb) set_raw_fb_params(0);
if (client_count && !orig) {
solid_bg(0);
}
@@ -8735,6 +9277,30 @@ char *process_remote_cmd(char *cmd, int stringonly) {
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("process_remote_cmd: enable xtrap input mode."
+ "(if applicable).\n");
+ if (! xtrap_input) {
+ xtrap_input = 1;
+ disable_grabserver();
+ }
+
+ } else if (!strcmp(p, "noxtrap")) {
+ if (query) {
+ snprintf(buf, bufn, "ans=%s:%d", p, !xtrap_input);
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: disable xtrap input mode."
+ "(if applicable).\n");
+ if (xtrap_input) {
+ xtrap_input = 0;
+ disable_grabserver();
+ }
+
} else if (!strcmp(p, "xrandr")) {
int orig = xrandr;
if (query) {
@@ -8743,6 +9309,7 @@ char *process_remote_cmd(char *cmd, int stringonly) {
if (xrandr_present) {
rfbLog("process_remote_cmd: enable xrandr mode.\n");
xrandr = 1;
+ if (raw_fb) set_raw_fb_params(0);
if (! xrandr_mode) {
xrandr_mode = strdup("default");
}
@@ -9033,7 +9600,7 @@ char *process_remote_cmd(char *cmd, int stringonly) {
if (no_repeat_countdown >= 0) {
no_repeat_countdown = 2;
}
- if (client_count) {
+ if (client_count && ! view_only) {
autorepeat(0); /* disable if any clients */
}
@@ -9767,6 +10334,29 @@ char *process_remote_cmd(char *cmd, int stringonly) {
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);
+
+ rfbLog("process_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:")
@@ -9962,13 +10552,22 @@ char *process_remote_cmd(char *cmd, int stringonly) {
/* read-only variables that can only be queried: */
if (!strcmp(p, "display")) {
- char *d = DisplayString(dpy);
- if (! d) d = "unknown";
- if (*d == ':') {
- snprintf(buf, bufn, "aro=%s:%s%s", p,
- this_host(), d);
+ if (raw_fb) {
+ snprintf(buf, bufn, "aro=%s:rawfb:%p",
+ p, raw_fb_addr);
+ } else if (! dpy) {
+ snprintf(buf, bufn, "aro=%s:%s", p,
+ "no-display");
} else {
- snprintf(buf, bufn, "aro=%s:%s", p, d);
+ 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,
@@ -10004,8 +10603,8 @@ char *process_remote_cmd(char *cmd, int stringonly) {
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_noblend")) {
- snprintf(buf, bufn, "aro=%s:%d", p, scaling_noblend);
+ } 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")) {
@@ -10025,6 +10624,8 @@ char *process_remote_cmd(char *cmd, int stringonly) {
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")) {
snprintf(buf, bufn, "aro=%s:%s", p, NONUL(rc_rcfile));
} else if (!strcmp(p, "norc")) {
@@ -10137,8 +10738,10 @@ char *process_remote_cmd(char *cmd, int stringonly) {
usleep(20*1000);
}
} else {
- set_vnc_connect_prop(buf);
- XFlush(dpy);
+ if (dpy) { /* raw_fb hack */
+ set_vnc_connect_prop(buf);
+ XFlush(dpy);
+ }
}
#endif
return NULL;
@@ -11087,7 +11690,7 @@ void setup_cursors(void) {
}
/* scale = NULL zeroes everything */
parse_scale_string(scale, &scale_cursor_fac, &scaling_cursor,
- &scaling_cursor_noblend, &j, &j, &scaling_cursor_interpolate,
+ &scaling_cursor_blend, &j, &j, &scaling_cursor_interpolate,
&scale_cursor_numer, &scale_cursor_denom);
for (i=0; i<n; i++) {
@@ -11170,9 +11773,13 @@ void setup_cursors(void) {
* looking cursors (i.e. two-color).
*/
int x, y, k = 0, bw;
+ int black = 0, white = 1;
char d, m;
- int black = BlackPixel(dpy, scr);
- int white = WhitePixel(dpy, scr);
+
+ if (dpy) { /* raw_fb hack */
+ black = BlackPixel(dpy, scr);
+ white = WhitePixel(dpy, scr);
+ }
rfb_curs->richSource
= (char *)calloc(ci->wx * ci->wy, 1);
@@ -11338,7 +11945,7 @@ void initialize_xfixes(void) {
rfbCursorPtr pixels2curs(unsigned long *pixels, int w, int h,
int xhot, int yhot, int Bpp) {
rfbCursorPtr c;
- static unsigned long black, white;
+ static unsigned long black = 0, white = 1;
static int first = 1;
char *bitmap, *rich, *alpha;
char *new_pixels = NULL;
@@ -11346,7 +11953,7 @@ rfbCursorPtr pixels2curs(unsigned long *pixels, int w, int h,
int send_alpha = 0, alpha_shift, thresh;
int i, x, y;
- if (first) {
+ if (first && dpy) { /* raw_fb hack */
X_LOCK;
black = BlackPixel(dpy, scr);
white = WhitePixel(dpy, scr);
@@ -11365,7 +11972,7 @@ rfbCursorPtr pixels2curs(unsigned long *pixels, int w, int h,
new_pixels = (char *) malloc(4 * w * h);
- scale_rect(scale_cursor_fac, scaling_cursor_noblend,
+ scale_rect(scale_cursor_fac, scaling_cursor_blend,
scaling_cursor_interpolate, 4,
(char *) pixels, 4*W, new_pixels, 4*w,
W, H, w, h,
@@ -12215,6 +12822,8 @@ void check_x11_pointer(void) {
int x, y;
unsigned int mask;
+ if (raw_fb) return; /* raw_fb hack */
+
X_LOCK;
ret = XQueryPointer(dpy, rootwin, &root_w, &child_w, &root_x, &root_y,
&win_x, &win_y, &mask);
@@ -12408,7 +13017,7 @@ void debug_colormap(XImage *fb) {
if (! fb) {
return;
}
- if (fb->bits_per_pixel != 8) {
+ if (fb->bits_per_pixel > 8) {
return;
}
@@ -12424,8 +13033,13 @@ void debug_colormap(XImage *fb) {
}
fprintf(stderr, "\nColormap histogram for current screen contents:\n");
for (i=0; i < NCOLOR; i++) {
- fprintf(stderr, " %03d: %7d", i, histo[i]);
- if ((i+1) % 4 == 0) {
+ 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");
}
}
@@ -12542,6 +13156,105 @@ void set_nofb_params(void) {
}
}
+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;
+ us0 = use_snapfb;
+ sm0 = using_shm;
+ ws0 = watch_selection;
+ wp0 = watch_primary;
+ wb0 = watch_bell;
+ na0 = no_autorepeat;
+ tn0 = take_naps;
+ mc0 = multiple_cursors_mode;
+ xr0 = xrandr;
+ sb0 = use_solid_bg;
+
+ first = 0;
+ }
+
+ if (restore) {
+ view_only = vo0;
+ use_snapfb = us0;
+ using_shm = sm0;
+ watch_selection = ws0;
+ watch_primary = wp0;
+ watch_bell = wb0;
+ no_autorepeat = na0;
+ take_naps = tn0;
+ multiple_cursors_mode = mc0;
+ xrandr = xr0;
+ use_solid_bg = sb0;
+
+ if (! dpy && raw_fb_orig_dpy) {
+ dpy = XOpenDisplay(raw_fb_orig_dpy);
+ if (dpy) {
+ rfbLog("reopened DISPLAY: %s\n",
+ raw_fb_orig_dpy);
+ } else {
+ rfbLog("WARNING: failed to reopen "
+ "DISPLAY: %s\n", raw_fb_orig_dpy);
+ }
+ }
+ return;
+ }
+
+ if (! view_only) {
+ rfbLog("rawfb: setting view_only\n");
+ view_only = 1;
+ }
+ if (use_snapfb) {
+ rfbLog("rawfb: turning off use_snapfb\n");
+ use_snapfb = 0;
+ }
+ if (using_shm) {
+ rfbLog("rawfb: turning off using_shm\n");
+ using_shm = 0;
+ }
+ if (watch_selection) {
+ rfbLog("rawfb: turning off watch_selection\n");
+ watch_selection = 0;
+ }
+ if (watch_primary) {
+ rfbLog("rawfb: turning off watch_primary\n");
+ watch_primary = 0;
+ }
+ if (watch_bell) {
+ rfbLog("rawfb: turning off watch_bell\n");
+ watch_bell = 0;
+ }
+ if (no_autorepeat) {
+ rfbLog("rawfb: turning off no_autorepeat\n");
+ no_autorepeat = 0;
+ }
+ if (take_naps) {
+ rfbLog("rawfb: turning off take_naps\n");
+ take_naps = 0;
+ }
+ multiple_cursors_mode = strdup("arrow");
+ if (xrandr) {
+ rfbLog("rawfb: turning off xrandr\n");
+ xrandr = 0;
+ }
+ if (use_solid_bg) {
+ rfbLog("rawfb: turning off use_solid_bg\n");
+ use_solid_bg = 0;
+ }
+}
+
/*
* Presumably under -nofb the clients will never request the framebuffer.
* However, we have gotten such a request... so let's just give them
@@ -12672,6 +13385,288 @@ void initialize_snap_fb(void) {
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;
+
+ 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;
+ }
+
+
+ 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 (! 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) {
+ XCloseDisplay(dpy); /* yow! */
+ }
+ dpy = 0;
+ }
+#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) {
+ rfbLog("invalid rawfb str: %s\n", raw_fb_str);
+ clean_up_exit(1);
+ }
+ /* @WxHxB */
+ if (sscanf(q, "@%dx%dx%d", &w, &h, &b) != 3) {
+ rfbLog("invalid rawfb str: %s\n", raw_fb_str);
+ clean_up_exit(1);
+ }
+
+ 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;
+
+ *q = '\0';
+ if (sscanf(str, "shm:%d", &shmid) == 1) {
+ /* shm:N */
+ raw_fb_addr = (char *) shmat(shmid, 0, SHM_RDONLY);
+ if (! raw_fb_addr) {
+ rfbLog("failed to attach to shm: %d, %s\n", shmid,
+ raw_fb_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 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) {
+ rfbLog("failed to open file: %s, %s\n", q, raw_fb_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("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) {
+ rfbLog("failed to mmap file: %s, %s\n",
+ q, raw_fb_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 {
+ rfbLog("invalid rawfb str: %s\n", raw_fb_str);
+ clean_up_exit(1);
+ }
+
+ if (! raw_fb_image) {
+ raw_fb_image = &ximage_struct;
+ }
+
+ raw_fb = (char *) malloc(w*h*b/8);
+ raw_fb_image->data = raw_fb;
+ raw_fb_image->format = ZPixmap;
+ raw_fb_image->width = w;
+ raw_fb_image->height = h;
+ raw_fb_image->bits_per_pixel = b;
+ raw_fb_image->depth = (b == 32) ? 24 : b;
+ raw_fb_image->bytes_per_line = w*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;
+
+ if (raw_fb_addr) {
+ memcpy(raw_fb, raw_fb_addr + raw_fb_offset, w*h*(b/8));
+ } else {
+ memset(raw_fb, 0xff, w*h*(b/8));
+ }
+
+ rfbLog("rawfb: raw_fb %p\n", raw_fb);
+
+ free(str);
+
+ initialize_clipshift();
+
+ 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
*/
@@ -12682,6 +13677,10 @@ XImage *initialize_xdisplay_fb(void) {
XErrorHandler old_handler;
int subwin_bs;
+ if (raw_fb_str) {
+ return initialize_raw_fb();
+ }
+
X_LOCK;
if (subwin) {
if (subwin_wait_mapped) {
@@ -12761,45 +13760,7 @@ XImage *initialize_xdisplay_fb(void) {
X_LOCK;
}
- 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_clipshift();
/* initialize depth to reasonable value, visual_id may override */
depth = DefaultDepth(dpy, scr);
@@ -12951,7 +13912,7 @@ XImage *initialize_xdisplay_fb(void) {
return fb;
}
-void parse_scale_string(char *str, double *factor, int *scaling, int *noblend,
+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;
@@ -12960,7 +13921,7 @@ void parse_scale_string(char *str, double *factor, int *scaling, int *noblend,
*factor = 1.0;
*scaling = 0;
- *noblend = 0;
+ *blend = 1;
*nomult4 = 0;
*pad = 0;
*interpolate = 0;
@@ -12974,7 +13935,10 @@ void parse_scale_string(char *str, double *factor, int *scaling, int *noblend,
if ( (p = strchr(tstr, ':')) != NULL) {
/* options */
if (strstr(p+1, "nb") != NULL) {
- *noblend = 1;
+ *blend = 0;
+ }
+ if (strstr(p+1, "fb") != NULL) {
+ *blend = 2;
}
if (strstr(p+1, "n4") != NULL) {
*nomult4 = 1;
@@ -13050,6 +14014,9 @@ int scale_round(int len, double fac) {
double eps = 0.000001;
len = (int) (len * fac + eps);
+ if (len < 1) {
+ len = 1;
+ }
return len;
}
@@ -13057,7 +14024,7 @@ 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_noblend,
+ parse_scale_string(scale_str, &scale_fac, &scaling, &scaling_blend,
&scaling_nomult4, &scaling_pad, &scaling_interpolate,
&scale_numer, &scale_denom);
@@ -13239,7 +14206,7 @@ void initialize_screen(int *argc, char **argv, XImage *fb) {
}
if (! have_masks && screen->serverFormat.bitsPerPixel == 8
- && CellsOfScreen(ScreenOfDisplay(dpy, scr))) {
+ && dpy && CellsOfScreen(ScreenOfDisplay(dpy, scr))) {
/* indexed color */
if (!quiet) {
rfbLog("X display %s is 8bpp indexed color\n",
@@ -13265,9 +14232,15 @@ void initialize_screen(int *argc, char **argv, XImage *fb) {
* color, static color, etc....
*/
if (! quiet) {
- rfbLog("X display %s is %dbpp depth=%d true "
- "color\n", DisplayString(dpy), fb->bits_per_pixel,
- fb->depth);
+ 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;
@@ -14693,7 +15666,7 @@ static int shm_create(XShmSegmentInfo *shm, XImage **ximg_ptr, int w, int h,
if (! using_shm) {
/* we only need the XImage created */
xim = XCreateImage_wr(dpy, default_visual, depth, ZPixmap,
- 0, NULL, w, h, BitmapPad(dpy), 0);
+ 0, NULL, w, h, raw_fb ? 32 : BitmapPad(dpy), 0);
X_UNLOCK;
@@ -14795,9 +15768,10 @@ void shm_delete(XShmSegmentInfo *shm) {
}
void shm_clean(XShmSegmentInfo *shm, XImage *xim) {
+
X_LOCK;
#if LIBVNCSERVER_HAVE_XSHM
- if (shm != NULL && shm->shmid != -1) {
+ if (shm != NULL && shm->shmid != -1 && dpy) {
XShmDetach_wr(dpy, shm);
}
#endif
@@ -15154,7 +16128,7 @@ weights for this scaled pixel are:
* the loop over the 4 pixels.
*/
-void scale_rect(double factor, int noblend, int interpolate, int Bpp,
+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) {
/*
@@ -15237,7 +16211,7 @@ void scale_rect(double factor, int noblend, int interpolate, int Bpp,
break;
}
}
- if (noblend || ! shrink || interpolate) {
+ if (! blend || ! shrink || interpolate) {
;
} else if (n != 0) {
if (Nx % n == 0 && Ny % n == 0) {
@@ -15262,12 +16236,12 @@ void scale_rect(double factor, int noblend, int interpolate, int Bpp,
break;
}
}
- if (noblend && factor > 1.0 && n) {
+ if (! blend && factor > 1.0 && n) {
mag_int = n;
}
}
- if (mark && factor > 1.0 && ! noblend) {
+ if (mark && factor > 1.0 && blend) {
/*
* kludge: correct for interpolating blurring leaking
* up or left 1 destination pixel.
@@ -15299,7 +16273,7 @@ void scale_rect(double factor, int noblend, int interpolate, int Bpp,
j2 = nfix(j2, ny) + 1;
/* special case integer magnification with no blending */
- if (mark && noblend && mag_int && Bpp != 3) {
+ if (mark && ! blend && mag_int && Bpp != 3) {
int jmin, jmax, imin, imax;
/* outer loop over *source* pixels */
@@ -15383,7 +16357,7 @@ void scale_rect(double factor, int noblend, int interpolate, int Bpp,
I1 = (int) FLOOR(x1);
if (I1 >= Nx) I1 = Nx - 1;
- if (noblend && use_noblend_shortcut) {
+ if (! blend && use_noblend_shortcut) {
/*
* The noblend case involves no weights,
* and 1 pixel, so just copy the value
@@ -15445,14 +16419,14 @@ void scale_rect(double factor, int noblend, int interpolate, int Bpp,
/* see comments for I, x1, x2, etc. below */
if (constant_weights) {
;
- } else if (noblend) {
+ } else if (! blend) {
if (J != J1) {
continue;
}
wy = 1.0;
/* interpolation scheme: */
- } else if (!shrink || interpolate) {
+ } else if (! shrink || interpolate) {
if (J >= Ny) {
continue;
} else if (J == J1) {
@@ -15478,13 +16452,15 @@ void scale_rect(double factor, int noblend, int interpolate, int Bpp,
if (constant_weights) {
;
- } else if (noblend) {
+ } 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;
@@ -15492,7 +16468,7 @@ void scale_rect(double factor, int noblend, int interpolate, int Bpp,
wx = 1.0;
/* interpolation scheme: */
- } else if (!shrink || interpolate) {
+ } else if (! shrink || interpolate) {
if (I >= Nx) {
continue; /* off edge */
} else if (I == I1) {
@@ -15612,11 +16588,23 @@ static void scale_and_mark_rect(int X1, int Y1, int X2, int Y2) {
if (! screen->serverFormat.trueColour) {
/*
* PseudoColor colormap... blending leads to random colors.
+ * User can override with ":fb"
*/
- scaling_noblend = 1;
+ 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_noblend, scaling_interpolate, bpp/8,
+ 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);
}
@@ -15624,6 +16612,11 @@ static void scale_and_mark_rect(int X1, int Y1, int X2, int Y2) {
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
+ * were we allow the framebuffer to be corrupted for
+ * damage_delay seconds.
+ */
int debug = 0;
if (time(0) > damage_time + damage_delay) {
if (! quiet) {
@@ -17056,6 +18049,9 @@ void run_gui(char *gui_xdisplay, int connect_to_x11vnc, int simple_gui,
fprintf(stderr, "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);
}
@@ -18473,16 +19469,18 @@ static void print_help(int mode) {
" 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). For compatibility with vncviewers the scaled\n"
-" width is adjusted to be a multiple of 4: to disable\n"
-" this use \":n4\". More esoteric options: \":in\" use\n"
-" interpolation scheme even when shrinking, \":pad\",\n"
-" pad scaled width and height to be multiples of scaling\n"
-" denominator (e.g. 3 for 2/3).\n"
+" Scaling Options: can be added after \"fraction\"\n"
+" via \":\", to supply multiple \":\" options use\n"
+" commas. If you just want a quick, rough scaling\n"
+" without blending, append \":nb\" to \"fraction\"\n"
+" (e.g. -scale 1/3:nb). No blending is the default\n"
+" for 8bpp indexed color, to force blending for this\n"
+" case use \":fb\". For compatibility with vncviewers\n"
+" the scaled width is adjusted to be a multiple of 4:\n"
+" to disable this use \":n4\". More esoteric options:\n"
+" \":in\" use interpolation scheme even when shrinking,\n"
+" \":pad\", pad scaled width and height to be multiples\n"
+" of scaling denominator (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"
@@ -18755,6 +19753,13 @@ static void print_help(int mode) {
" In general on XINERAMA displays you may need to use the\n"
" -xwarppointer option if the mouse 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"
@@ -18794,9 +19799,13 @@ static void print_help(int mode) {
"-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"
-"-rc filename Use \"filename\" instead of $HOME/.x11vncrc for rc 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"
@@ -19177,6 +20186,7 @@ static void print_help(int mode) {
" 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"
+"\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"
@@ -19191,6 +20201,52 @@ static void print_help(int mode) {
" 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) based\n"
+" reading.\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. Most of the X11 (screen,\n"
+" keyboard, mouse) options do not make sense and many\n"
+" will cause this mode to crash, so please think twice\n"
+" before setting/changing them. If you don't want x11vnc\n"
+" to close the DISPLAY in rawfb mode, then capitalize\n"
+" the prefix, SHM:, MAP: etc. Keeping the display open\n"
+" enables defautl remote control channel.\n"
+"\n"
+"-pipeinput cmd Another experimental option: it lets you supply an\n"
+" extern command in \"cmd\" that x11vnc will pipe all of\n"
+" the user input events to in a simple format. By default\n"
+" x11vnc will not process any of the user input events.\n"
+" If you prefix \"cmd\" with \"tee:\" it will both send\n"
+" them to the pipe command and process them. For a\n"
+" description of the format run \"-pipeinput tee:cat\".\n"
+" Another prefix is \"reopen\" which means to reopen pipe\n"
+" if it exits. 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"
@@ -19367,6 +20423,8 @@ static void print_help(int mode) {
" 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.\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"
@@ -19448,6 +20506,7 @@ static void print_help(int mode) {
" 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"
@@ -19515,39 +20574,39 @@ static void print_help(int mode) {
" 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 xrandr noxrandr\n"
-" xrandr_mode padgeom quiet q noquiet modtweak nomodtweak\n"
-" xkb noxkb skip_keycodes add_keysyms noadd_keysyms\n"
-" clear_mods noclear_mods clear_keys noclear_keys\n"
-" remap repeat norepeat fb nofb bell nobell sel nosel\n"
-" primary noprimary cursorshape nocursorshape cursorpos\n"
-" nocursorpos cursor show_cursor noshow_cursor nocursor\n"
-" arrow xfixes noxfixes xdamage noxdamage xd_area\n"
-" xd_mem alphacut alphafrac alpharemove noalpharemove\n"
-" alphablend noalphablend xwarp xwarppointer noxwarp\n"
-" noxwarppointer buttonmap dragging nodragging\n"
+" noflipbyteorder onetile noonetile solid_color\n"
+" solid nosolid blackout xinerama noxinerama xtrap\n"
+" noxtrap xrandr noxrandr xrandr_mode padgeom quiet q\n"
+" noquiet modtweak nomodtweak xkb noxkb skip_keycodes\n"
+" add_keysyms noadd_keysyms clear_mods noclear_mods\n"
+" clear_keys noclear_keys remap repeat norepeat fb nofb\n"
+" bell nobell sel nosel primary noprimary 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 xwarp xwarppointer\n"
+" noxwarp noxwarppointer buttonmap dragging nodragging\n"
" pointer_mode pm input_skip input client_input speeds\n"
" debug_pointer dp nodebug_pointer nodp debug_keyboard dk\n"
" nodebug_keyboard nodk deferupdate defer wait rfbwait\n"
" nap nonap sb screen_blank fs gaps grow fuzz snapfb\n"
-" nosnapfb progressive rfbport http nohttp httpport\n"
+" nosnapfb rawfb progressive rfbport http nohttp httpport\n"
" httpdir enablehttpproxy noenablehttpproxy alwaysshared\n"
" noalwaysshared nevershared noalwaysshared dontdisconnect\n"
" nodontdisconnect desktop noremote\n"
"\n"
" aro= display vncdisplay desktopname http_url auth\n"
" users rootshift clipshift scale_str scaled_x scaled_y\n"
-" scale_numer scale_denom scale_fac scaling_noblend\n"
-" scaling_nomult4 scaling_pad scaling_interpolate inetd\n"
-" safer unsafe passwdfile using_shm logfile o rc norc\n"
-" h help V version lastmod bg sigpipe threads clients\n"
-" client_count pid ext_xtest ext_xtrap ext_xkb ext_xshm\n"
-" ext_xinerama ext_overlay ext_xfixes ext_xdamage\n"
-" ext_xrandr rootwin num_buttons button_mask mouse_x\n"
-" mouse_y bpp depth indexed_color dpy_x dpy_y wdpy_x\n"
-" wdpy_y off_x off_y cdpy_x cdpy_y coff_x coff_y rfbauth\n"
-" passwd\n"
+" scale_numer scale_denom scale_fac scaling_blend\n"
+" scaling_nomult4 scaling_pad scaling_interpolate\n"
+" inetd safer unsafe passwdfile using_shm logfile o\n"
+" flag rc norc h help V version lastmod bg sigpipe\n"
+" threads clients client_count pid ext_xtest ext_xtrap\n"
+" ext_xkb ext_xshm ext_xinerama ext_overlay ext_xfixes\n"
+" ext_xdamage ext_xrandr rootwin num_buttons button_mask\n"
+" mouse_x mouse_y bpp depth indexed_color dpy_x dpy_y\n"
+" wdpy_x wdpy_y off_x off_y cdpy_x cdpy_y coff_x coff_y\n"
+" rfbauth passwd\n"
"\n"
"-sync By default -remote commands are run asynchronously, that\n"
" is, the request is posted and the program immediately\n"
@@ -19716,9 +20775,21 @@ void set_vnc_desktop_name(void) {
}
fflush(stderr);
if (inetd) {
- ; /* should not occur (port) */
+ ; /* 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);
}
@@ -20012,7 +21083,7 @@ int main(int argc, char* argv[]) {
char *remote_cmd = NULL;
char *query_cmd = NULL;
char *gui_str = NULL;
- int pw_loc = -1;
+ int pw_loc = -1, got_passwd = 0, got_rfbauth = 0;
int vpw_loc = -1;
int dt = 0, bg = 0;
int got_rfbwait = 0, got_deferupdate = 0, got_defer = 0;
@@ -20214,6 +21285,8 @@ int main(int argc, char* argv[]) {
blackout_str = strdup(argv[++i]);
} else if (!strcmp(arg, "-xinerama")) {
xinerama = 1;
+ } else if (!strcmp(arg, "-xtrap")) {
+ xtrap_input = 1;
} else if (!strcmp(arg, "-xrandr")) {
xrandr = 1;
if (i < argc-1) {
@@ -20235,6 +21308,9 @@ int main(int argc, char* argv[]) {
CHECK_ARGC
logfile_append = 1;
logfile = strdup(argv[++i]);
+ } else if (!strcmp(arg, "-flag")) {
+ CHECK_ARGC
+ flagfile = strdup(argv[++i]);
} else if (!strcmp(arg, "-rc")) {
i++; /* done above */
} else if (!strcmp(arg, "-norc")) {
@@ -20433,6 +21509,12 @@ int main(int argc, char* argv[]) {
tile_fuzz = atoi(argv[++i]);
} else if (!strcmp(arg, "-snapfb")) {
use_snapfb = 1;
+ } else if (!strcmp(arg, "-rawfb")) {
+ CHECK_ARGC
+ raw_fb_str = strdup(argv[++i]);
+ } else if (!strcmp(arg, "-pipeinput")) {
+ CHECK_ARGC
+ pipeinput_str = strdup(argv[++i]);
} else if (!strcmp(arg, "-gui")) {
launch_gui = 1;
if (i < argc-1) {
@@ -20479,6 +21561,10 @@ int main(int argc, char* argv[]) {
}
if (!strcmp(arg, "-passwd")) {
pw_loc = i;
+ got_passwd = 1;
+ }
+ if (!strcmp(arg, "-rfbauth")) {
+ got_rfbauth = 1;
}
if (!strcmp(arg, "-rfbwait")) {
got_rfbwait = 1;
@@ -20579,6 +21665,7 @@ int main(int argc, char* argv[]) {
line[len-1] = '\0';
}
argv_vnc[argc_vnc++] = strdup("-passwd");
+ got_passwd = 1;
if (!strcmp(line, "__EMPTY__")) {
argv_vnc[argc_vnc++] = strdup("");
} else if ((q = strstr(line, "__ENDPASSWD__")) !=NULL) {
@@ -20640,6 +21727,19 @@ int main(int argc, char* argv[]) {
}
}
}
+#ifdef HARDWIRE_PASSWD
+ if (! got_rfbauth && ! got_passwd) {
+ argv_vnc[argc_vnc++] = strdup("-passwd");
+ argv_vnc[argc_vnc++] = strdup(HARDWIRE_PASSWD);
+ got_passwd = 1;
+ pw_loc = 100;
+ }
+#endif
+#ifdef HARDWIRE_VIEWPASSWD
+ if (! got_rfbauth && got_passwd && ! viewonly_passwd) {
+ viewonly_passwd = strdup(HARDWIRE_VIEWPASSWD);
+ }
+#endif
if (viewonly_passwd && pw_loc < 0) {
rfbLog("-passwd must be supplied when using -viewpasswd\n");
exit(1);
@@ -20713,6 +21813,9 @@ int main(int argc, char* argv[]) {
}
}
+ if (raw_fb_str) {
+ set_raw_fb_params(0);
+ }
if (! got_deferupdate) {
char tmp[40];
/* XXX not working yet in libvncserver */
@@ -20742,6 +21845,9 @@ int main(int argc, char* argv[]) {
allow_list = strdup("127.0.0.1");
}
+ /* set OS struct UT */
+ uname(&UT);
+
if (! quiet) {
fprintf(stderr, "\n");
fprintf(stderr, "Settings:\n");
@@ -20791,6 +21897,7 @@ int main(int argc, char* argv[]) {
fprintf(stderr, " blackout: %s\n", blackout_str
? blackout_str : "null");
fprintf(stderr, " xinerama: %d\n", xinerama);
+ fprintf(stderr, " xtrap: %d\n", xtrap_input);
fprintf(stderr, " xrandr: %d\n", xrandr);
fprintf(stderr, " xrandrmode: %s\n", xrandr_mode ? xrandr_mode
: "null");
@@ -20799,6 +21906,8 @@ int main(int argc, char* argv[]) {
fprintf(stderr, " logfile: %s\n", logfile ? logfile
: "null");
fprintf(stderr, " logappend: %d\n", logfile_append);
+ fprintf(stderr, " flag: %s\n", flagfile ? flagfile
+ : "null");
fprintf(stderr, " rc_file: \"%s\"\n", rc_rcfile ? rc_rcfile
: "null");
fprintf(stderr, " norc: %d\n", rc_norc);
@@ -20855,6 +21964,10 @@ int main(int argc, char* argv[]) {
fprintf(stderr, " grow_fill: %d\n", grow_fill);
fprintf(stderr, " tile_fuzz: %d\n", tile_fuzz);
fprintf(stderr, " snapfb: %d\n", use_snapfb);
+ fprintf(stderr, " rawfb: %s\n", raw_fb_str
+ ? raw_fb_str : "null");
+ fprintf(stderr, " pipeinput: %s\n", pipeinput_str
+ ? pipeinput_str : "null");
fprintf(stderr, " gui: %d\n", launch_gui);
fprintf(stderr, " gui_mode: %s\n", gui_str
? gui_str : "null");
@@ -20909,6 +22022,12 @@ int main(int argc, char* argv[]) {
dpy = XOpenDisplay("");
}
+ if (! dpy && raw_fb_str) {
+ rfbLog("continuing without X display in -rawfb mode, "
+ "hold on tight..\n");
+ goto raw_fb_pass_go_and_collect_200_dollars;
+ }
+
if (! dpy && ! use_dpy && ! getenv("DISPLAY")) {
int i, s = 4;
rfbLog("\a\n");
@@ -20951,13 +22070,6 @@ int main(int argc, char* argv[]) {
exit(rc);
}
- if (! dt) {
- static char str[] = "-desktop";
- argv_vnc[argc_vnc++] = str;
- argv_vnc[argc_vnc++] = choose_title(use_dpy);
- rfb_desktop_name = strdup(argv_vnc[argc_vnc-1]);
- }
-
#if LIBVNCSERVER_HAVE_LIBXFIXES
if (! XFixesQueryExtension(dpy, &xfixes_base_event_type, &er)) {
if (! quiet) {
@@ -21101,12 +22213,14 @@ int main(int argc, char* argv[]) {
xtest_present = 0;
use_xwarppointer = 1;
} else {
+ xtest_present = 1;
xtest_base_event_type = ev;
}
if (! XETrapQueryExtension_wr(dpy, &ev, &er, &maj)) {
xtrap_present = 0;
} else {
+ xtrap_present = 1;
xtrap_base_event_type = ev;
}
@@ -21118,9 +22232,6 @@ int main(int argc, char* argv[]) {
*/
disable_grabserver();
- /* set OS struct UT */
- uname(&UT);
-
/* check for OS with small shm limits */
if (using_shm && ! single_copytile) {
if (limit_shm()) {
@@ -21185,6 +22296,17 @@ int main(int argc, char* argv[]) {
}
#endif
+ raw_fb_pass_go_and_collect_200_dollars:
+
+ if (! dt) {
+ static char str[] = "-desktop";
+ argv_vnc[argc_vnc++] = str;
+ argv_vnc[argc_vnc++] = choose_title(use_dpy);
+ rfb_desktop_name = strdup(argv_vnc[argc_vnc-1]);
+ }
+
+ initialize_pipeinput();
+
/*
* Create the XImage corresponding to the display framebuffer.
*/