summaryrefslogtreecommitdiffstats
path: root/x11vnc/x11vnc.c
diff options
context:
space:
mode:
authorrunge <runge>2005-03-12 22:14:44 +0000
committerrunge <runge>2005-03-12 22:14:44 +0000
commitfba6f58a1aaaa8162a9bf9905d9a0d59bd4ce2d9 (patch)
tree6eda1ecbe62e4cdb00ad3cdc19b59b32f1e002e4 /x11vnc/x11vnc.c
parent4ff783f5793cee11fe8733f7d118608a25c1b86e (diff)
downloadlibtdevnc-fba6f58a1aaaa8162a9bf9905d9a0d59bd4ce2d9.tar.gz
libtdevnc-fba6f58a1aaaa8162a9bf9905d9a0d59bd4ce2d9.zip
x11vnc: X DAMAGE support, -clip WxH+X+Y, identd.
Diffstat (limited to 'x11vnc/x11vnc.c')
-rw-r--r--x11vnc/x11vnc.c1066
1 files changed, 917 insertions, 149 deletions
diff --git a/x11vnc/x11vnc.c b/x11vnc/x11vnc.c
index f10b683..d64a318 100644
--- a/x11vnc/x11vnc.c
+++ b/x11vnc/x11vnc.c
@@ -169,7 +169,7 @@
/*
#define LIBVNCSERVER_HAVE_LIBXINERAMA 1
#define LIBVNCSERVER_HAVE_XFIXES 1
-#define LIBVNCSERVER_HAVE_XDAMAGE 1
+#define LIBVNCSERVER_HAVE_LIBXDAMAGE 1
*/
#endif /* OLD_TREE */
@@ -329,13 +329,21 @@ static int xfixes_base_event_type;
#endif
int xdamage_present = 0;
+int using_xdamage = 0;
+int use_xdamage_hints = 1; /* just use the xdamage rects. for scanline hints */
#if LIBVNCSERVER_HAVE_LIBXDAMAGE
#include <X11/extensions/Xdamage.h>
static int xdamage_base_event_type;
+Damage xdamage = 0;
#endif
+int xdamage_max_area = 20000; /* pixels */
+double xdamage_memory = 1.0; /* in units of NSCAN */
+int xdamage_tile_count;
+
+int hack_val = 0;
/* date +'lastmod: %Y-%m-%d' */
-char lastmod[] = "0.7.2pre lastmod: 2005-03-04";
+char lastmod[] = "0.7.2pre lastmod: 2005-03-12";
/* X display info */
@@ -347,6 +355,8 @@ 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 num_buttons = -1;
@@ -395,6 +405,7 @@ unsigned short main_red_shift, main_green_shift, main_blue_shift;
typedef struct _ClientData {
int uid;
char *hostname;
+ char *username;
int client_port;
int server_port;
char *server_ip;
@@ -432,6 +443,7 @@ 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, last_client = 0;
@@ -466,6 +478,15 @@ 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);
@@ -511,6 +532,9 @@ void free_tiles(void);
void initialize_watch_bell(void);
void initialize_xinerama(void);
void initialize_xfixes(void);
+void initialize_xdamage(void);
+void create_xdamage(void);
+void destroy_xdamage(void);
void initialize_xrandr(void);
XImage *initialize_xdisplay_fb(void);
@@ -596,24 +620,25 @@ void refresh_screen(void);
/*
* variables for the command line options
*/
-char *use_dpy = NULL;
-char *auth_file = NULL;
-char *visual_str = NULL;
-char *logfile = NULL;
+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 *passwdfile = NULL;
-char *blackout_str = NULL;
-int use_solid_bg = 0;
+char *passwdfile = NULL; /* -passwdfile */
+char *blackout_str = NULL; /* -blackout */
+char *clip_str = NULL; /* -clip */
+int use_solid_bg = 0; /* -solid */
char *solid_str = NULL;
char *solid_default = "cyan4";
-char *speeds_str = NULL;
+char *speeds_str = NULL; /* -speeds TBD */
int measure_speeds = 1;
int speeds_net_rate = 0;
int speeds_net_latency = 0;
int speeds_read_rate = 0;
-char *rc_rcfile = NULL;
+char *rc_rcfile = NULL; /* -rc */
int rc_norc = 0;
int opts_bg = 0;
@@ -866,6 +891,32 @@ int scan_hexdec(char *str, unsigned long *num) {
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;
str = (char *)malloc(strlen(name)+strlen(value)+2);
@@ -1704,6 +1755,7 @@ void try_to_switch_users(void) {
free(users);
}
+/* -- inet.c -- */
/*
* Simple utility to map host name to dotted IP address. Ignores aliases.
* Up to caller to free returned string.
@@ -1728,9 +1780,6 @@ char *ip2host(char *ip) {
char *str;
#if LIBVNCSERVER_HAVE_NETDB_H && LIBVNCSERVER_HAVE_NETINET_IN_H
struct hostent *hp;
-#ifndef in_addr_t
-typedef unsigned int in_addr_t;
-#endif
in_addr_t iaddr;
iaddr = inet_addr(ip);
@@ -1821,6 +1870,96 @@ 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) {
+ 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
@@ -1846,42 +1985,25 @@ int guess_bits_per_color(int bits_per_pixel) {
return bits_per_color;
}
-/* 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;
-}
-
/*
* 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.
+ * 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; \
}
-/* -- ximage.c -- */
-
/*
* Wrappers for Image related X calls
*/
@@ -2025,7 +2147,7 @@ XImage *XCreateImage_wr(Display *disp, Visual *visual, unsigned int depth,
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 */
+ /* default (w=0, h=0) is the fill the entire XImage */
if (w < 1) {
w = dest->width;
}
@@ -2222,6 +2344,11 @@ void clean_up_exit (int ret) {
}
X_LOCK;
XTestDiscard_wr(dpy);
+#if LIBVNCSERVER_HAVE_LIBXDAMAGE
+ if (xdamage) {
+ XDamageDestroy(dpy, xdamage);
+ }
+#endif
XCloseDisplay(dpy);
X_UNLOCK;
@@ -2493,9 +2620,9 @@ char *list_clients(void) {
/*
* each client:
- * <id>:<ip>:<port>:<hostname>:<input>:<loginview>,
- * 8+1+16+1+5+1+256+1+5+1+1+1
- * 123.123.123.123:60000/0x11111111-rw, = 297 bytes
+ * <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);
@@ -2514,6 +2641,12 @@ char *list_clients(void) {
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);
@@ -2525,6 +2658,26 @@ char *list_clients(void) {
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;
@@ -2779,6 +2932,9 @@ static void client_gone(rfbClientPtr client) {
if (cd->hostname) {
free(cd->hostname);
}
+ if (cd->username) {
+ free(cd->username);
+ }
}
free(client->clientData);
}
@@ -2958,8 +3114,8 @@ static int check_access(char *addr) {
* 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, int X, int Y, int timeout,
- char *mode) {
+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
@@ -2989,6 +3145,7 @@ static char t2x2_bits[] = {
/* 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";
@@ -3002,7 +3159,7 @@ static char t2x2_bits[] = {
char str_y[] = "Yes";
char str_n[] = "No";
char str_v[] = "View";
- int x, y, w = 345, h = 150, ret = 0;
+ 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;
@@ -3026,6 +3183,7 @@ static char t2x2_bits[] = {
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;
@@ -3086,7 +3244,8 @@ static char t2x2_bits[] = {
XMapWindow(dpy, awin);
XFlush(dpy);
- sprintf(strh, "x11vnc: accept connection from %s?", addr);
+ 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"));
@@ -3123,6 +3282,8 @@ static char t2x2_bits[] = {
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));
@@ -3336,6 +3497,7 @@ static int accept_client(rfbClientPtr client) {
addr = "unknown-host";
}
+
if (strstr(accept_cmd, "popup") == accept_cmd) {
/* use our builtin popup button */
@@ -3344,6 +3506,7 @@ static int accept_client(rfbClientPtr client) {
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) {
@@ -3380,7 +3543,9 @@ static int accept_client(rfbClientPtr client) {
}
rfbLog("accept_client: using builtin popup for: %s\n", addr);
- if ((ret = ugly_accept_window(addr, x, y, timeout, mode))) {
+ 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;
@@ -3388,6 +3553,7 @@ static int accept_client(rfbClientPtr client) {
rfbLog("accept_client: popup accepted: %s\n", addr);
return 1;
} else {
+ free(userhost);
rfbLog("accept_client: popup rejected: %s\n", addr);
return 0;
}
@@ -3787,6 +3953,7 @@ enum rfbNewClientAction new_client(rfbClientPtr client) {
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;
@@ -5755,11 +5922,15 @@ static void update_x11_pointer_position(int x, int y) {
X_LOCK;
if (use_xwarppointer) {
- /* off_x and off_y not needed with XWarpPointer */
- XWarpPointer(dpy, None, window, 0, 0, 0, 0, x, y);
+ /*
+ * 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, y+off_y,
- CurrentTime);
+ XTestFakeMotionEvent_wr(dpy, scr, x + off_x + coff_x,
+ y + off_y + coff_y, CurrentTime);
}
X_UNLOCK;
@@ -5786,7 +5957,7 @@ static void update_x11_pointer_position(int x, int y) {
}
/*
- * Send a pointer position event to the X server.
+ * Send a pointer button event to the X server.
*/
static void update_x11_pointer_mask(int mask) {
int i, mb;
@@ -6164,8 +6335,8 @@ XErrorHandler old_getimage_handler;
/* -- xrandr.c -- */
void initialize_xrandr(void) {
-#if LIBVNCSERVER_HAVE_LIBXRANDR
if (xrandr_present) {
+#if LIBVNCSERVER_HAVE_LIBXRANDR
Rotation rot;
xrandr_width = XDisplayWidth(dpy, scr);
@@ -6177,15 +6348,20 @@ void initialize_xrandr(void) {
} else {
XRRSelectInput(dpy, rootwin, 0);
}
- }
#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... */
+ int i, check = 10, ms = 250; /* 2.5 secs total... */
if (! subwin) {
return 0; /* hmmm... */
@@ -6200,7 +6376,7 @@ int handle_subwin_resize(char *msg) {
X_UNLOCK;
clean_up_exit(1);
}
- if (dpy_x == new_x && dpy_y == new_y) {
+ if (wdpy_x == new_x && wdpy_y == new_y) {
/* no change */
return 0;
}
@@ -6225,7 +6401,7 @@ int handle_subwin_resize(char *msg) {
}
rfbLog("subwin 0x%lx new size: x: %d -> %d, y: %d -> %d\n",
- subwin, dpy_x, new_x, dpy_y, new_y);
+ subwin, wdpy_x, new_x, wdpy_y, new_y);
rfbLog("calling handle_xrandr_change() for resizing\n");
X_UNLOCK;
@@ -6268,11 +6444,11 @@ void handle_xrandr_change(int new_x, int new_y) {
/* default, resize, and newfbsize create a new fb: */
rfbLog("check_xrandr_event: trying to create new framebuffer...\n");
- if (new_x < dpy_x || new_y < dpy_y) {
+ 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", dpy_x, dpy_y);
+ rfbLog("check_xrandr_event: fb WxH: %dx%d\n", wdpy_x, wdpy_y);
}
int check_xrandr_event(char *msg) {
@@ -6304,8 +6480,8 @@ int check_xrandr_event(char *msg) {
rfbLog(" mheight: %d mm\n", (int) rev->mheight);
rfbLog("\n");
rfbLog("check_xrandr_event: previous WxH: %dx%d\n",
- dpy_x, dpy_y);
- if (dpy_x == rev->width && dpy_y == rev->height &&
+ 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;
@@ -6624,6 +6800,7 @@ void initialize_xevents(void) {
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;
X_LOCK;
@@ -6656,6 +6833,10 @@ void initialize_xevents(void) {
initialize_xfixes();
did_xfixes = 1;
}
+ if (xdamage_present && !did_xdamage) {
+ initialize_xdamage();
+ did_xdamage = 1;
+ }
}
/*
@@ -7407,7 +7588,8 @@ char *process_remote_cmd(char *cmd, int stringonly) {
Window twin;
COLON_CHECK("id:")
if (query) {
- snprintf(buf, bufn, "ans=%s%s0x%lx", p, co, subwin);
+ snprintf(buf, bufn, "ans=%s%s0x%lx", p, co,
+ rootshift ? 0 : subwin);
goto qry;
}
p += strlen("id:");
@@ -7444,7 +7626,8 @@ char *process_remote_cmd(char *cmd, int stringonly) {
Window twin;
COLON_CHECK("sid:")
if (query) {
- snprintf(buf, bufn, "ans=%s%s0x%lx", p, co, subwin);
+ snprintf(buf, bufn, "ans=%s%s0x%lx", p, co,
+ !rootshift ? 0 : subwin);
goto qry;
}
p += strlen("sid:");
@@ -7475,6 +7658,20 @@ char *process_remote_cmd(char *cmd, int stringonly) {
do_new_fb(1);
}
}
+ } else if (strstr(p, "clip") == p) {
+ 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 (strstr(p, "waitmapped") == p) {
if (query) {
snprintf(buf, bufn, "ans=%s:%d", p,
@@ -8676,6 +8873,73 @@ char *process_remote_cmd(char *cmd, int stringonly) {
initialize_xfixes();
first_cursor();
+ } else if (!strcmp(p, "xdamage")) {
+ int orig = use_xdamage_hints;
+ if (query) {
+ snprintf(buf, bufn, "ans=%s:%d", p, use_xdamage_hints);
+ goto qry;
+ }
+ if (! xdamage_present) {
+ rfbLog("process_remote_cmd: cannot enable xdamage hints "
+ "(not supported on X display)\n");
+ goto done;
+ }
+ rfbLog("process_remote_cmd: enabling xdamage hints"
+ " (if supported).\n");
+ use_xdamage_hints = 1;
+ if (use_xdamage_hints != orig) {
+ initialize_xdamage();
+ create_xdamage();
+ }
+ } else if (!strcmp(p, "noxdamage")) {
+ int orig = use_xdamage_hints;
+ if (query) {
+ snprintf(buf, bufn, "ans=%s:%d", p, !use_xdamage_hints);
+ goto qry;
+ }
+ if (! xdamage_present) {
+ rfbLog("process_remote_cmd: disabling xdamage hints "
+ "(but not supported on X display)\n");
+ goto done;
+ }
+ rfbLog("process_remote_cmd: disabling xdamage hints.\n");
+ use_xdamage_hints = 0;
+ if (use_xdamage_hints != orig) {
+ initialize_xdamage();
+ destroy_xdamage();
+ }
+
+ } 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("process_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("process_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:")
@@ -9282,6 +9546,12 @@ char *process_remote_cmd(char *cmd, int stringonly) {
rfbLog("process_remote_cmd: disabling remote commands.\n");
accept_remote_cmds = 0; /* cannot be turned back on. */
+ } else if (strstr(p, "hack:") == p) { /* skip-cmd-list */
+ NOTAPP
+ p += strlen("hack:");
+ hack_val = atoi(p);
+ rfbLog("set hack_val to: %d\n", hack_val);
+
} else if (query) {
/* read-only variables that can only be queried: */
@@ -9314,6 +9584,8 @@ char *process_remote_cmd(char *cmd, int stringonly) {
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")) {
@@ -9406,6 +9678,22 @@ char *process_remote_cmd(char *cmd, int stringonly) {
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")) {
@@ -9447,6 +9735,329 @@ char *process_remote_cmd(char *cmd, int stringonly) {
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;
+
+ 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 (!always_accept && dt_y >= 2 && area > 1000) {
+ /*
+ * should be caught by a normal scanline poll, but we might
+ * as well keep if small.
+ */
+ return;
+ }
+
+ 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;
+ tile_row_has_xdamage_diff[iy] = 1;
+ xdamage_tile_count++;
+ }
+ }
+}
+
+void collect_xdamage(int scancnt) {
+#if LIBVNCSERVER_HAVE_LIBXDAMAGE
+ XDamageNotifyEvent *dev;
+#if 0
+ XserverRegion xregion;
+#endif
+ XEvent ev;
+ sraRegionPtr tmpregion;
+ sraRegionPtr reg;
+ static int rect_count = 0;
+ int nreg, ccount = 0, dcount = 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 16
+ int dup_x[DUPSZ], dup_y[DUPSZ], dup_w[DUPSZ], dup_h[DUPSZ];
+
+ if (! xdamage_present || ! using_xdamage) {
+ return;
+ }
+ if (! xdamage) {
+ return;
+ }
+
+ nreg = (xdamage_memory * NSCAN) + 1;
+ xdamage_ticker = (xdamage_ticker+1) % nreg;
+ reg = xdamage_regions[xdamage_ticker];
+ sraRgnMakeEmpty(reg);
+
+ X_LOCK;
+ while (XCheckTypedEvent(dpy, xdamage_base_event_type+XDamageNotify, &ev)) {
+ /* TODO max cut off time in this loop? */
+ 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) {
+ /*
+ * 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);
+ w = x2 - x; /* recompute w */
+
+ y2 = y + h;
+ y = nfix(y, dpy_y);
+ y2 = nfix(y2, dpy_y);
+ h = y2 - y;
+
+ if (w <= 0 || h <= 0) {
+ continue;
+ }
+ }
+
+
+ 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 */
+ XDamageSubtract(dpy, xdamage, None, None);
+ X_UNLOCK;
+
+ 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 (0) fprintf(stderr, "skip/tot: %04d/%04d rat=%.3f rect_count: %d desired_rects: %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
+}
+
+int xdamage_hint_skip(int y) {
+ static sraRegionPtr scanline = NULL;
+ sraRegionPtr reg, tmpl;
+ int ret, i, n, nreg;
+
+ if (!xdamage_present || !using_xdamage || !use_xdamage_hints) {
+ return 0; /* cannot skip */
+ }
+ if (! xdamage_regions) {
+ return 0; /* cannot skip */
+ }
+
+ if (! scanline) {
+ 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;
+
+ using_xdamage = 0;
+ if (xdamage_present) {
+ if (use_xdamage_hints) {
+ using_xdamage = 1;
+ }
+ }
+ if (xdamage_regions) {
+ ptr = xdamage_regions;
+ while (*ptr != NULL) {
+ sraRgnDestroy(*ptr);
+ ptr++;
+ }
+ free(xdamage_regions);
+ xdamage_regions = NULL;
+ }
+ if (using_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(void) {
+#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(void) {
+#if LIBVNCSERVER_HAVE_LIBXDAMAGE
+ if (xdamage) {
+ X_LOCK;
+ XDamageDestroy(dpy, xdamage);
+ X_UNLOCK;
+ rfbLog("destroyed xdamage object: 0x%lx\n", xdamage);
+ xdamage = 0;
+ }
+#endif
+}
+
+void check_xdamage_state(void) {
+ if (! using_xdamage || ! xdamage_present) {
+ return;
+ }
+ /*
+ * Create or destroy the Damage object as needed, we don't want
+ * one if no clients are connected.
+ */
+ if (client_count) {
+ create_xdamage();
+ } else {
+ destroy_xdamage();
+ }
+}
+
/* -- cursor.c -- */
/*
* Here begins a bit of a mess to experiment with multiple cursors
@@ -9525,7 +10136,7 @@ static cursor_info_t cur_arrow = {NULL, NULL, 18, 18, 0, 0, 0, NULL};
/*
* It turns out we can at least detect mouse is on the root window so
- * show it (under -cursorX or -X) with this familiar cursor...
+ * show it (under -cursor X) with this familiar cursor...
*/
static char* curs_root_data =
" "
@@ -10868,8 +11479,8 @@ void check_x11_pointer(void) {
}
/* offset subtracted since XQueryPointer relative to rootwin */
- x = root_x - off_x;
- y = root_y - off_y;
+ 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);
@@ -11286,8 +11897,8 @@ XImage *initialize_xdisplay_fb(void) {
if (! subwin) {
/* full screen */
window = rootwin;
- dpy_x = DisplayWidth(dpy, scr);
- dpy_y = DisplayHeight(dpy, scr);
+ 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 */
@@ -11302,8 +11913,8 @@ XImage *initialize_xdisplay_fb(void) {
X_UNLOCK;
clean_up_exit(1);
}
- dpy_x = attr.width;
- dpy_y = attr.height;
+ dpy_x = wdpy_x = attr.width;
+ dpy_y = wdpy_y = attr.height;
subwin_bs = attr.backing_store;
@@ -11315,6 +11926,46 @@ 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 depth to reasonable value, visual_id may override */
depth = DefaultDepth(dpy, scr);
@@ -11379,13 +12030,13 @@ XImage *initialize_xdisplay_fb(void) {
/* subwins can be a dicey if they are changing size... */
XTranslateCoordinates(dpy, window, rootwin, 0, 0, &subwin_x,
&subwin_y, &twin);
- if (subwin_x + dpy_x > disp_x) {
+ if (subwin_x + wdpy_x > disp_x) {
shift = 1;
- subwin_x = disp_x - dpy_x - 3;
+ subwin_x = disp_x - wdpy_x - 3;
}
- if (subwin_y + dpy_y > disp_y) {
+ if (subwin_y + wdpy_y > disp_y) {
shift = 1;
- subwin_y = disp_y - dpy_y - 3;
+ subwin_y = disp_y - wdpy_y - 3;
}
if (subwin_x < 0) {
shift = 1;
@@ -11435,17 +12086,17 @@ XImage *initialize_xdisplay_fb(void) {
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, &dpy_x, &dpy_y)) {
- rfbLog("could not get size of subwin "
- "0x%lx\n", subwin);
- X_UNLOCK;
- clean_up_exit(1);
- }
- goto again;
+ rfbLog("trapped GetImage at SUBWIN creation.\n");
+ if (try < subwin_tries) {
+ usleep(250 * 1000);
+ if (!get_window_size(window, &wdpy_x, &wdpy_y)) {
+ rfbLog("could not get size of subwin "
+ "0x%lx\n", subwin);
+ X_UNLOCK;
+ clean_up_exit(1);
}
+ goto again;
+ }
}
trapped_xerror = 0;
@@ -11727,7 +12378,7 @@ void initialize_screen(int *argc, char **argv, XImage *fb) {
screen->serverFormat.greenMax = 0;
screen->serverFormat.blueMax = 0;
- /* these main_* formats are use elsewhere by us. */
+ /* these main_* formats are used generally. */
main_red_shift = 0;
main_green_shift = 0;
main_blue_shift = 0;
@@ -12080,12 +12731,12 @@ void solid_root(char *color) {
swa.background_pixmap = None;
visual.visualid = CopyFromParent;
mask = (CWOverrideRedirect|CWBackingStore|CWSaveUnder|CWBackPixmap);
- expose = XCreateWindow(dpy, window, 0, 0, dpy_x, dpy_y, 0, depth,
+ 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, dpy_x, dpy_y, depth);
+ pixmap = XCreatePixmap(dpy, window, wdpy_x, wdpy_y, depth);
if (! image) {
/* whoops */
@@ -12100,7 +12751,7 @@ void solid_root(char *color) {
gcv.plane_mask = AllPlanes;
gc = XCreateGC(dpy, window, GCFunction|GCPlaneMask, &gcv);
- XPutImage(dpy, pixmap, gc, image, 0, 0, 0, 0, dpy_x, dpy_y);
+ 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);
@@ -12130,14 +12781,14 @@ void solid_root(char *color) {
iswa.save_under = False;
iswa.background_pixmap = ParentRelative;
- iwin = XCreateWindow(dpy, window, 0, 0, dpy_x, dpy_y, 0, depth,
- InputOutput, &visual, mask, &iswa);
+ 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, dpy_x, dpy_y, AllPlanes,
+ image = XGetImage(dpy, iwin, 0, 0, wdpy_x, wdpy_y, AllPlanes,
ZPixmap);
XSync(dpy, False);
XDestroyWindow(dpy, iwin);
@@ -12191,7 +12842,7 @@ void solid_cde(char *color) {
swa.background_pixmap = None;
visual.visualid = CopyFromParent;
mask = (CWOverrideRedirect|CWBackingStore|CWSaveUnder|CWBackPixmap);
- expose = XCreateWindow(dpy, window, 0, 0, dpy_x, dpy_y, 0, depth,
+ expose = XCreateWindow(dpy, window, 0, 0, wdpy_x, wdpy_y, 0, depth,
InputOutput, &visual, mask, &swa);
if (! color) {
@@ -12212,7 +12863,8 @@ void solid_cde(char *color) {
continue;
}
- pixmap = XCreatePixmap(dpy, twin, dpy_x, dpy_y, depth);
+ pixmap = XCreatePixmap(dpy, twin, wdpy_x, wdpy_y,
+ depth);
/* draw the image to a pixmap: */
gcv.function = GXcopy;
@@ -12220,7 +12872,7 @@ void solid_cde(char *color) {
gc = XCreateGC(dpy, twin, GCFunction|GCPlaneMask, &gcv);
XPutImage(dpy, pixmap, gc, image[n], 0, 0, 0, 0,
- dpy_x, dpy_y);
+ wdpy_x, wdpy_y);
gcv.foreground = gcv.background = BlackPixel(dpy, scr);
gc = XCreateGC(dpy, twin, GCForeground|GCBackground,
@@ -12366,7 +13018,7 @@ void solid_cde(char *color) {
iswa.background_pixmap = ParentRelative;
visual.visualid = CopyFromParent;
- iwin = XCreateWindow(dpy, twin, 0, 0, dpy_x, dpy_y,
+ iwin = XCreateWindow(dpy, twin, 0, 0, wdpy_x, wdpy_y,
0, depth, InputOutput, &visual, mask, &iswa);
rfbLog("snapshotting CDE backdrop ws%d 0x%lx -> "
@@ -12374,7 +13026,7 @@ void solid_cde(char *color) {
XMapWindow(dpy, iwin);
XSync(dpy, False);
- image[n] = XGetImage(dpy, iwin, 0, 0, dpy_x, dpy_y,
+ image[n] = XGetImage(dpy, iwin, 0, 0, wdpy_x, wdpy_y,
AllPlanes, ZPixmap);
XSync(dpy, False);
XDestroyWindow(dpy, iwin);
@@ -12673,21 +13325,7 @@ void initialize_blackouts(char *list) {
p = strtok(blist, ", \t");
while (p) {
- /* handle +/-x and +/-y */
- if (sscanf(p, "%dx%d+%d+%d", &w, &h, &x, &y) == 4) {
- ;
- } else if (sscanf(p, "%dx%d-%d+%d", &w, &h, &x, &y) == 4) {
- w = nabs(w);
- x = dpy_x - x - w;
- } else if (sscanf(p, "%dx%d+%d-%d", &w, &h, &x, &y) == 4) {
- h = nabs(h);
- y = dpy_y - y - h;
- } else if (sscanf(p, "%dx%d-%d-%d", &w, &h, &x, &y) == 4) {
- w = nabs(w);
- h = nabs(h);
- x = dpy_x - x - w;
- y = dpy_y - y - h;
- } else {
+ if (! parse_geom(p, &w, &h, &x, &y, dpy_x, dpy_y)) {
if (*p != '\0') {
rfbLog("skipping invalid geometry: %s\n", p);
}
@@ -13055,15 +13693,6 @@ 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;
-/* scan pattern jitter from x0rfbserver */
-#define NSCAN 32
-static 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
-};
-
typedef struct tile_change_region {
/* start and end lines, along y, of the changed area inside a tile. */
unsigned short first_line, last_line;
@@ -13087,6 +13716,10 @@ void initialize_tiles(void) {
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 *)
@@ -13109,6 +13742,14 @@ void free_tiles(void) {
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;
@@ -15032,7 +15673,7 @@ static int scan_display(int ystart, int rescan) {
int pixelsize = bpp/8;
int x, y, w, n;
int tile_count = 0;
- int whole_line = 1, nodiffs = 0;
+ int nodiffs = 0, diff_hint;
y = ystart;
@@ -15043,6 +15684,15 @@ static int scan_display(int ystart, int rescan) {
while (y < dpy_y) {
+ if (using_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");
@@ -15054,7 +15704,7 @@ static int scan_display(int ystart, int rescan) {
src = scanline->data;
dst = main_fb + y * main_bytes_per_line;
- if (whole_line && ! memcmp(dst, src, main_bytes_per_line)) {
+ if (! memcmp(dst, src, main_bytes_per_line)) {
/* no changes anywhere in scan line */
nodiffs = 1;
if (! rescan) {
@@ -15066,6 +15716,7 @@ static int scan_display(int ystart, int rescan) {
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,
@@ -15081,6 +15732,10 @@ static int scan_display(int ystart, int rescan) {
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: */
@@ -15094,7 +15749,7 @@ static int scan_display(int ystart, int rescan) {
w = NSCAN;
}
- if (memcmp(dst, src, w * pixelsize)) {
+ if (diff_hint || memcmp(dst, src, w * pixelsize)) {
/* found a difference, record it: */
if (! blackouts) {
tile_has_diff[n] = 1;
@@ -15129,9 +15784,15 @@ int scan_for_updates(int count_only) {
double frac3 = 0.02; /* do scan_display() again after copy_tiles() */
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
@@ -15142,15 +15803,16 @@ int scan_for_updates(int count_only) {
scan_count++;
scan_count %= NSCAN;
- if (scan_count % (NSCAN/4) == 0) {
- /* some periodic maintenance */
-
- if (subwin) {
- set_offset(); /* follow the subwindow */
- }
- if (indexed_color) { /* check for changed colormap */
- set_colormap(0);
- }
+ /* 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 (using_xdamage) {
+ collect_xdamage(scan_count);
}
}
@@ -15172,6 +15834,20 @@ int scan_for_updates(int count_only) {
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] == 1) {
+ tile_has_xdamage_diff[i] = 2;
+ tile_has_diff[i] = 1;
+ tile_count++;
+ }
+ }
+ }
+
nap_set(tile_count);
if (fs_factor && frac1 >= fs_frac) {
@@ -15349,9 +16025,11 @@ void run_gui(char *gui_xdisplay, int connect_to_x11vnc, int simple_gui,
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) {
@@ -15360,6 +16038,8 @@ void run_gui(char *gui_xdisplay, int connect_to_x11vnc, int simple_gui,
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) {
@@ -15367,11 +16047,12 @@ void run_gui(char *gui_xdisplay, int connect_to_x11vnc, int simple_gui,
dpy = XOpenDisplay(x11vnc_xdisplay);
}
if (! dpy && ! x11vnc_xdisplay) {
+ /* worstest case */
x11vnc_xdisplay = strdup(":0");
dpy = XOpenDisplay(x11vnc_xdisplay);
}
if (! dpy) {
- fprintf(stderr, "gui: could not open "
+ fprintf(stderr, "gui: could not open x11vnc "
"display: %s\n", NONUL(x11vnc_xdisplay));
exit(1);
}
@@ -15398,7 +16079,7 @@ void run_gui(char *gui_xdisplay, int connect_to_x11vnc, int simple_gui,
}
set_env("X11VNC_XDISPLAY", x11vnc_xdisplay);
if (getenv("XAUTHORITY") != NULL) {
- set_env("X11VNC_XAUTHORITY", getenv("XAUTHORITY"));
+ set_env("X11VNC_AUTH_FILE", getenv("XAUTHORITY"));
}
if (rc == 0) {
fprintf(stderr, "gui: ping succeeded.\n");
@@ -15411,7 +16092,15 @@ void run_gui(char *gui_xdisplay, int connect_to_x11vnc, int simple_gui,
XCloseDisplay(dpy);
}
if (old_xauth) {
- set_env("XAUTHORITY", 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);
}
}
@@ -15459,8 +16148,6 @@ void run_gui(char *gui_xdisplay, int connect_to_x11vnc, int simple_gui,
if (simple_gui) {
set_env("X11VNC_SIMPLE_GUI", "1");
}
- if (auth_file) {
- }
sprintf(cmd, "%s -", wish);
tmpf = tmpfile();
@@ -16509,6 +17196,10 @@ static void watch_loop(void) {
continue;
}
+ if (using_xdamage) {
+ check_xdamage_state();
+ }
+
if (watch_bell) {
/* n.b. assumes -nofb folks do not want bell... */
check_bell_event();
@@ -16618,6 +17309,12 @@ static void print_help(int mode) {
" 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"
"-flashcmap In 8bpp indexed color, let the installed colormap flash\n"
" as the pointer moves from window to window (slow).\n"
"-notruecolor For 8bpp displays, force indexed color (i.e. a colormap)\n"
@@ -17292,6 +17989,36 @@ static void print_help(int mode) {
" 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.\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"
@@ -17417,6 +18144,7 @@ static void print_help(int mode) {
" 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"
+" clip:WxH+X+Y set -clip mode to \"WxH+X+Y\"\n"
" flashcmap enable -flashcmap mode.\n"
" noflashcmap disable -flashcmap mode.\n"
" notruecolor enable -notruecolor mode.\n"
@@ -17559,6 +18287,10 @@ static void print_help(int mode) {
" 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"
@@ -17625,7 +18357,7 @@ static void print_help(int mode) {
" 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"
+" refresh reset close disconnect id sid clip waitmapped\n"
" nowaitmapped flashcmap noflashcmap truecolor notruecolor\n"
" overlay nooverlay overlay_cursor overlay_yescursor\n"
" nooverlay_nocursor nooverlay_cursor nooverlay_yescursor\n"
@@ -17641,9 +18373,10 @@ static void print_help(int mode) {
" remap repeat norepeat fb nofb bell nobell sel\n"
" nosel primary noprimary cursorshape nocursorshape\n"
" cursorpos nocursorpos cursor show_cursor noshow_cursor\n"
-" nocursor xfixes noxfixes alphacut alphafrac alpharemove\n"
-" noalpharemove alphablend noalphablend xwarp xwarppointer\n"
-" noxwarp noxwarppointer buttonmap dragging nodragging\n"
+" nocursor 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"
" 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"
@@ -17654,15 +18387,16 @@ static void print_help(int mode) {
" nodontdisconnect desktop noremote\n"
"\n"
" aro= display vncdisplay desktopname http_url auth\n"
-" users rootshift scale_str scaled_x scaled_y scale_numer\n"
-" scale_denom scale_fac scaling_noblend scaling_nomult4\n"
-" scaling_pad scaling_interpolate inetd safer unsafe\n"
-" passwdfile using_shm logfile o rc norc h help V version\n"
-" lastmod bg sigpipe threads clients client_count pid\n"
-" ext_xtest ext_xkb ext_xshm ext_xinerama ext_overlay\n"
-" ext_xfixes ext_xdamage ext_xrandr rootwin num_buttons\n"
-" button_mask mouse_x mouse_y bpp depth indexed_color\n"
-" dpy_x dpy_y rfbauth passwd\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_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\n"
"\n"
"-sync By default -remote commands are run asynchronously, that\n"
" is, the request is posted and the program immediately\n"
@@ -17761,6 +18495,7 @@ static void print_help(int mode) {
waitms,
take_naps ? "take naps":"no naps",
screen_blank,
+ xdamage_max_area, NSCAN, xdamage_memory,
use_threads ? "-threads":"-nothreads",
fs_frac,
gaps_fill,
@@ -18126,6 +18861,7 @@ int main(int argc, char* argv[]) {
int vpw_loc = -1;
int dt = 0, bg = 0;
int got_rfbwait = 0, got_deferupdate = 0, got_defer = 0;
+ int got_noxdamage = 0;
/* used to pass args we do not know about to rfbGetScreen(): */
int argc_vnc = 1; char *argv_vnc[128];
@@ -18211,6 +18947,9 @@ int main(int argc, char* argv[]) {
}
} else if (!strcmp(arg, "-waitmapped")) {
subwin_wait_mapped = 1;
+ } else if (!strcmp(arg, "-clip")) {
+ CHECK_ARGC
+ clip_str = strdup(argv[++i]);
} else if (!strcmp(arg, "-flashcmap")) {
flash_cmap = 1;
} else if (!strcmp(arg, "-notruecolor")) {
@@ -18468,6 +19207,24 @@ int main(int argc, char* argv[]) {
} else if (!strcmp(arg, "-sb")) {
CHECK_ARGC
screen_blank = atoi(argv[++i]);
+ } else if (!strcmp(arg, "-noxdamage")) {
+ using_xdamage = 0;
+ use_xdamage_hints = 0;
+ got_noxdamage = 1;
+ } else if (!strcmp(arg, "-xd_area")) {
+ int tn;
+ CHECK_ARGC
+ tn = atoi(argv[++i]);
+ if (tn >= 0) {
+ xdamage_max_area = tn;
+ }
+ } else if (!strcmp(arg, "-xd_mem")) {
+ double f;
+ CHECK_ARGC
+ f = atof(argv[++i]);
+ if (f >= 0.0) {
+ xdamage_memory = f;
+ }
} else if (!strcmp(arg, "-sigpipe")) {
CHECK_ARGC
if (known_sigpipe_mode(argv[++i])) {
@@ -18820,6 +19577,8 @@ int main(int argc, char* argv[]) {
: "null");
fprintf(stderr, " subwin: 0x%lx\n", subwin);
fprintf(stderr, " -sid mode: %d\n", rootshift);
+ fprintf(stderr, " clip: %s\n", clip_str ? clip_str
+ : "null");
fprintf(stderr, " flashcmap: %d\n", flash_cmap);
fprintf(stderr, " force_idx: %d\n", force_indexed_color);
fprintf(stderr, " visual: %s\n", visual_str ? visual_str
@@ -18909,6 +19668,9 @@ int main(int argc, char* argv[]) {
fprintf(stderr, " waitms: %d\n", waitms);
fprintf(stderr, " take_naps: %d\n", take_naps);
fprintf(stderr, " sb: %d\n", screen_blank);
+ fprintf(stderr, " xdamage: %d\n", !got_noxdamage);
+ fprintf(stderr, " xd_area: %d\n", xdamage_max_area);
+ fprintf(stderr, " xd_mem: %.3f\n", xdamage_memory);
fprintf(stderr, " sigpipe: %s\n", sigpipe
? sigpipe : "null");
fprintf(stderr, " threads: %d\n", use_threads);
@@ -19050,6 +19812,12 @@ int main(int argc, char* argv[]) {
xdamage_present = 1;
}
#endif
+ if (! quiet && xdamage_present && ! got_noxdamage) {
+ rfbLog("X DAMAGE available on display, using it for"
+ " polling hints\n");
+ rfbLog(" to disable this behavior use: "
+ "'-noxdamage'\n");
+ }
overlay_present = 0;
#ifdef SOLARIS_OVERLAY