summaryrefslogtreecommitdiffstats
path: root/x11vnc/userinput.c
diff options
context:
space:
mode:
authorrunge <runge>2006-12-17 23:34:25 +0000
committerrunge <runge>2006-12-17 23:34:25 +0000
commit8aa6fb9523957c7f4a3f14fb2c90ea9f9292a41f (patch)
tree82a97c679b609325b8df6c2c9a00a85525fde0a1 /x11vnc/userinput.c
parent399a175f0bb44865cbf3d6762ad081e2a49cd4c4 (diff)
downloadlibtdevnc-8aa6fb9523957c7f4a3f14fb2c90ea9f9292a41f.tar.gz
libtdevnc-8aa6fb9523957c7f4a3f14fb2c90ea9f9292a41f.zip
x11vnc: first pass at client-side caching, -ncache option.
Diffstat (limited to 'x11vnc/userinput.c')
-rw-r--r--x11vnc/userinput.c802
1 files changed, 799 insertions, 3 deletions
diff --git a/x11vnc/userinput.c b/x11vnc/userinput.c
index 3c02fb0..60fa75d 100644
--- a/x11vnc/userinput.c
+++ b/x11vnc/userinput.c
@@ -53,10 +53,9 @@ int check_xrecord(void);
int check_wireframe(void);
int fb_update_sent(int *count);
int check_user_input(double dt, double dtr, int tile_diffs, int *cnt);
-
+void do_copyregion(sraRegionPtr region, int dx, int dy);
static void get_client_regions(int *req, int *mod, int *cpy, int *num) ;
-static void do_copyregion(sraRegionPtr region, int dx, int dy) ;
static void parse_scroll_copyrect_str(char *scr);
static void parse_wireframe_str(char *wf);
static void destroy_str_list(char **list);
@@ -81,6 +80,8 @@ static void check_user_input2(double dt);
static void check_user_input3(double dt, double dtr, int tile_diffs);
static void check_user_input4(double dt, double dtr, int tile_diffs);
+winattr_t *cache_list;
+int lookup_win_index(Window);
/*
* For -wireframe: find the direct child of rootwin that has the
@@ -1757,7 +1758,7 @@ static void get_client_regions(int *req, int *mod, int *cpy, int *num) {
* is being done. Note that copyrect under the scaling case is often
* only approximate.
*/
-static void do_copyregion(sraRegionPtr region, int dx, int dy) {
+void do_copyregion(sraRegionPtr region, int dx, int dy) {
sraRectangleIterator *iter;
sraRect rect;
int Bpp0 = bpp/8, Bpp;
@@ -3364,6 +3365,7 @@ int check_wireframe(void) {
double max_spin = wireframe_t3;
double min_draw = wireframe_t4;
int try_it = 0;
+ Window desc[6];
DB_SET
if (unixpw_in_progress) return 0;
@@ -3837,6 +3839,43 @@ if (db) fprintf(stderr, "sent_copyrect: %d - obs: %d frame: 0x%lx\n", sent_copy
/* no diff for now... */
fb_push_wait(0.1, FB_COPY);
}
+#ifndef NO_NCACHE
+ if (ncache > 0) {
+ int idx = lookup_win_index(frame);
+fprintf(stderr, "sent_copyrect: idx=%d 0x%x\n", idx, frame);
+ if (idx < 0) {
+ idx = lookup_win_index(orig_frame);
+fprintf(stderr, "sent_copyrect: idx=%d 0x%x\n", idx, orig_frame);
+ }
+ if (idx >= 0 && cache_list[idx].su_time > 0.0) {
+ sraRegionPtr r0, r1, r2;
+ sraRectangleIterator *iter;
+ sraRect rt;
+ int su_x = cache_list[idx].su_x;
+ int su_y = cache_list[idx].su_y;
+ int dx, dy;
+
+ r0 = sraRgnCreateRect(0, 0, dpy_x, dpy_y);
+ r1 = sraRgnCreateRect(orig_x, orig_y, orig_x + orig_w, orig_y + orig_h);
+ sraRgnAnd(r1, r0);
+ r2 = sraRgnCreateRect(x, y, x + w, y + h);
+ sraRgnAnd(r2, r0);
+ sraRgnSubtract(r1, r2);
+
+ dx = orig_x - su_x;
+ dy = orig_y - su_y;
+fprintf(stderr, "sent_copyrect: su_restore: %d %d\n", dx, dy);
+ do_copyregion(r1, dx, dy);
+ fb_push_wait(0.1, FB_COPY);
+fprintf(stderr, "sent_copyrect: su_restore: done.\n");
+ sraRgnDestroy(r0);
+ sraRgnDestroy(r1);
+ sraRgnDestroy(r2);
+
+ cache_list[idx].su_time = 0.0;
+ }
+ }
+#endif
if (scaling) {
static double last_time = 0.0;
double now = dnow(), delay = 0.35;
@@ -4504,4 +4543,761 @@ if (debug_scroll && rc > 1) fprintf(stderr, " CXR: check_user_input ret %d\n",
return 0;
}
+#if defined(NO_NCACHE) || NO_X11
+void check_ncache(void) {
+ return;
+}
+int lookup_win_index(Window win) {
+ return -1;
+}
+#else
+/* maybe ncache.c it if works */
+
+winattr_t* cache_list = NULL;
+int cache_list_num = 0;
+int cache_list_len = 0;
+
+void snapshot_cache_list(int free_only, double allowed_age) {
+ static double last_snap = 0.0, last_free = 0.0;
+ double now;
+ int num, rc, i, j;
+ unsigned int ui;
+ Window r, w;
+ Window *list;
+ int start = 2048;
+
+ if (! cache_list) {
+ cache_list = (winattr_t *) malloc(start*sizeof(winattr_t));
+ cache_list_num = 0;
+ cache_list_len = start;
+ }
+
+ dtime0(&now);
+ if (free_only) {
+ /* we really don't free it, just reset to zero windows */
+ cache_list_num = 0;
+ last_free = now;
+ return;
+ }
+
+ if (cache_list_num && now < last_snap + allowed_age) {
+ return;
+ }
+
+ cache_list_num = 0;
+ last_free = now;
+
+#ifdef MACOSX
+ if (! macosx_console) {
+ RAWFB_RET_VOID
+ }
+#else
+ RAWFB_RET_VOID
+#endif
+
+#if NO_X11 && !defined(MACOSX)
+ return;
+#else
+
+ X_LOCK;
+ /* no need to trap error since rootwin */
+ rc = XQueryTree_wr(dpy, rootwin, &r, &w, &list, &ui);
+ num = (int) ui;
+
+ if (! rc) {
+ cache_list_num = 0;
+ last_free = now;
+ last_snap = 0.0;
+ X_UNLOCK;
+ return;
+ }
+
+ last_snap = now;
+ if (num > cache_list_len) {
+ int n = 2*num;
+ free(cache_list);
+ cache_list = (winattr_t *) malloc(n*sizeof(winattr_t));
+ cache_list_len = n;
+ }
+ j = 0;
+ for (i=0; i<num; i++) {
+ cache_list[j].win = list[i];
+ cache_list[j].fetched = 0;
+ cache_list[j].valid = 0;
+ cache_list[j].time = now;
+ cache_list[j].selectinput = 0;
+ j++;
+ }
+ cache_list_num = num;
+ XFree_wr(list);
+ X_UNLOCK;
+#endif /* NO_X11 */
+}
+
+#define NRECENT 32
+Window recent[NRECENT];
+int recidx[NRECENT];
+int rlast, rfree;
+
+int lookup_win_index(Window win) {
+ int k, idx = -1;
+ int foundfree = 0;
+
+ if (win == rootwin || win == None) {
+ return idx;
+ }
+ for (k = 0; k < NRECENT; k++) {
+ if (recent[k] == win) {
+ int k2 = recidx[k];
+ if (cache_list[k2].win == win) {
+ idx = k2;
+fprintf(stderr, "recentA: %d 0x%x\n", idx, win);
+ break;
+ }
+ }
+ }
+ if (idx < 0) {
+ for(k=0; k<cache_list_num; k++) {
+ if (!foundfree && cache_list[k].win == None) {
+ rfree = k;
+ foundfree = 1;
+ }
+ if (cache_list[k].win == win) {
+ idx = k;
+fprintf(stderr, "recentB: %d 0x%x\n", idx, win);
+ break;
+ }
+ }
+ if (idx >= 0) {
+ recent[rlast] = win;
+ recidx[rlast++] = idx;
+ rlast = rlast % NRECENT;
+ }
+ }
+if (idx < 0) {
+fprintf(stderr, "recentC: %d 0x%x\n", idx, win);
+}
+ return idx;
+}
+
+int lookup_free_index(void) {
+ int k;
+
+ if (rfree >= 0) {
+ if (cache_list[rfree].win == None) {
+fprintf(stderr, "lookup_freeA: %d\n", rfree);
+ return rfree;
+ }
+ }
+ rfree = -1;
+ for(k=0; k<cache_list_num; k++) {
+ if (cache_list[k].win == None) {
+ rfree = k;
+ break;
+ }
+ }
+ if (rfree < 0) {
+ rfree = cache_list_num++;
+ if (rfree >= cache_list_len) {
+ /* bad news... */
+ fprintf(stderr, "Whoops: %d %d\n", rfree, cache_list_len);
+ }
+ }
+fprintf(stderr, "lookup_freeB: %d\n", rfree);
+ return rfree;
+}
+
+#define STORE(k, w, attr) \
+ cache_list[k].win = w; \
+ cache_list[k].fetched = 1; \
+ cache_list[k].valid = 1; \
+ cache_list[k].x = attr.x; \
+ cache_list[k].y = attr.y; \
+ cache_list[k].width = attr.width; \
+ cache_list[k].height = attr.height; \
+ cache_list[k].map_state = attr.map_state; \
+ cache_list[k].time = dnow();
+
+#define CLEAR(k) \
+ cache_list[k].bs_x = -1; \
+ cache_list[k].bs_y = -1; \
+ cache_list[k].bs_w = -1; \
+ cache_list[k].bs_h = -1; \
+ cache_list[k].su_x = -1; \
+ cache_list[k].su_y = -1; \
+ cache_list[k].su_w = -1; \
+ cache_list[k].su_h = -1; \
+ cache_list[k].bs_time = 0.0; \
+ cache_list[k].su_time = 0.0; \
+ cache_list[k].selectinput = 0;
+
+#define DELETE(k) \
+ cache_list[k].win = None; \
+ cache_list[k].fetched = 0; \
+ cache_list[k].valid = 0; \
+ free_rect(k);
+
+char *Etype(int type) {
+ if (type == KeyPress) return "KeyPress";
+ if (type == KeyRelease) return "KeyRelease";
+ if (type == ButtonPress) return "ButtonPress";
+ if (type == ButtonRelease) return "ButtonRelease";
+ if (type == MotionNotify) return "MotionNotify";
+ if (type == EnterNotify) return "EnterNotify";
+ if (type == LeaveNotify) return "LeaveNotify";
+ if (type == FocusIn) return "FocusIn";
+ if (type == FocusOut) return "FocusOut";
+ if (type == KeymapNotify) return "KeymapNotify";
+ if (type == Expose) return "Expose";
+ if (type == GraphicsExpose) return "GraphicsExpose";
+ if (type == NoExpose) return "NoExpose";
+ if (type == VisibilityNotify) return "VisibilityNotify";
+ if (type == CreateNotify) return "CreateNotify";
+ if (type == DestroyNotify) return "DestroyNotify";
+ if (type == UnmapNotify) return "UnmapNotify";
+ if (type == MapNotify) return "MapNotify";
+ if (type == MapRequest) return "MapRequest";
+ if (type == ReparentNotify) return "ReparentNotify";
+ if (type == ConfigureNotify) return "ConfigureNotify";
+ if (type == ConfigureRequest) return "ConfigureRequest";
+ if (type == GravityNotify) return "GravityNotify";
+ if (type == ResizeRequest) return "ResizeRequest";
+ if (type == CirculateNotify) return "CirculateNotify";
+ if (type == CirculateRequest) return "CirculateRequest";
+ if (type == PropertyNotify) return "PropertyNotify";
+ if (type == SelectionClear) return "SelectionClear";
+ if (type == SelectionRequest) return "SelectionRequest";
+ if (type == SelectionNotify) return "SelectionNotify";
+ if (type == ColormapNotify) return "ColormapNotify";
+ if (type == ClientMessage) return "ClientMessage";
+ if (type == MappingNotify) return "MappingNotify";
+ if (type == LASTEvent) return "LASTEvent";
+ return "Unknown";
+}
+sraRegionPtr rect_reg[32];
+
+int find_rect(int idx, int x, int y, int w, int h) {
+ static int first = 1;
+ sraRegionPtr r1, r2;
+ sraRectangleIterator *iter;
+ sraRect rt;
+ int n, x_hit = -1, y_hit = -1;
+
+ if (first) {
+ first = 0;
+ for (n = 1; n <= ncache; n++) {
+ rect_reg[n] = sraRgnCreateRect(0, n * dpy_y, dpy_x, (n+1) * dpy_y);
+ }
+ }
+
+ for (n = 1; n < ncache; n += 2) {
+ r1 = rect_reg[n];
+ r2 = NULL;
+ iter = sraRgnGetIterator(r1);
+ while (sraRgnIteratorNext(iter, &rt)) {
+ int rw = nabs(rt.x2 - rt.x1);
+ int rh = nabs(rt.y2 - rt.y1);
+ if (rw >= w && rh >= h) {
+ if (rt.x1 < rt.x2) {
+ x_hit = rt.x1;
+ } else {
+ x_hit = rt.x2;
+ }
+ if (rt.y1 < rt.y2) {
+ y_hit = rt.y1;
+ } else {
+ y_hit = rt.y2;
+ }
+ r2 = sraRgnCreateRect(x_hit, y_hit, x_hit + w, y_hit + h);
+ break;
+ }
+ }
+ sraRgnReleaseIterator(iter);
+ if (r2 != NULL) {
+ sraRgnSubtract(r1, r2);
+ sraRgnDestroy(r2);
+ break;
+ }
+ }
+ if (x_hit < 0) {
+ /* bad news */
+ fprintf(stderr, "*FAIL rect: %d %d %d %d -- %d %d\n", x, y, w, h, x_hit, y_hit);
+ } else {
+ fprintf(stderr, "found rect: %d %d %d %d -- %d %d\n", x, y, w, h, x_hit, y_hit);
+ }
+
+ cache_list[idx].bs_x = x_hit;
+ cache_list[idx].bs_y = y_hit;
+ cache_list[idx].bs_w = w;
+ cache_list[idx].bs_h = h;
+
+ cache_list[idx].su_x = x_hit;
+ cache_list[idx].su_y = y_hit + dpy_y;
+ cache_list[idx].su_w = w;
+ cache_list[idx].su_h = h;
+}
+
+int free_rect(int idx) {
+ int n, ok = 0;
+ sraRegionPtr r1, r2;
+ int x, y, w, h;
+
+ x = cache_list[idx].bs_x;
+ y = cache_list[idx].bs_y;
+ w = cache_list[idx].bs_w;
+ h = cache_list[idx].bs_h;
+
+ if (x < 0) {
+ CLEAR(idx);
+fprintf(stderr, "free_rect: invalid: %d\n", idx);
+ return 0;
+ }
+
+ r2 = sraRgnCreateRect(x, y, x+w, y+h);
+
+ for (n = 1; n < ncache; n += 2) {
+ if (y >= n*dpy_y && y < (n+1)*dpy_y) {
+ r1 = rect_reg[n];
+ sraRgnOr(r1, r2);
+ ok = 1;
+fprintf(stderr, "free_rect: found %d region: %d\n", idx, n);
+ break;
+ }
+ }
+ sraRgnDestroy(r2);
+
+ CLEAR(idx);
+if (! ok) fprintf(stderr, "free_rect: not-found %d\n", idx);
+ return ok;
+}
+
+int bs_save(int idx) {
+ Window win = cache_list[idx].win;
+ XWindowAttributes attr;
+ int x1, y1, w1, h1;
+ int x2, y2, w2, h2;
+ int x, y, w, h;
+ int dx, dy;
+ sraRegionPtr r;
+
+
+ x1 = cache_list[idx].x;
+ y1 = cache_list[idx].y;
+ w1 = cache_list[idx].width;
+ h1 = cache_list[idx].height;
+
+ if (! valid_window(win, &attr, 1)) {
+fprintf(stderr, "bs_save: not valid\n");
+// DELETE(idx);
+ return 0;
+ }
+
+ x2 = attr.x;
+ y2 = attr.y;
+ w2 = attr.width;
+ h2 = attr.height;
+
+ if (cache_list[idx].bs_x < 0 || w2 > cache_list[idx].bs_w || h2 > cache_list[idx].bs_h) {
+ find_rect(idx, x2, y2, w2, h2);
+ }
+ x = cache_list[idx].bs_x;
+ y = cache_list[idx].bs_y;
+ w = cache_list[idx].bs_w;
+ h = cache_list[idx].bs_h;
+
+ if (x < 0) {
+ STORE(idx, win, attr);
+ return 0;
+ }
+
+ dx = x - x2;
+ dy = y - y2;
+
+ r = sraRgnCreateRect(x2+dx, y2+dy, x2+w2+dx, y2+h2+dy);
+fprintf(stderr, "bs_save: dx=%d dy=%d\n", dx, dy);
+ do_copyregion(r, dx, dy);
+ fb_push_wait(0.01, FB_COPY);
+fprintf(stderr, "bs_save: done. %dx%d+%d+%d %dx%d+%d+%d %.2f %.2f\n", w1, h1, x1, y1, w2, h2, x2, y2, cache_list[idx].bs_time, dnow());
+ sraRgnDestroy(r);
+
+ STORE(idx, win, attr);
+ cache_list[idx].bs_time = dnow();
+
+ return 1;
+}
+
+int su_save(int idx) {
+ Window win = cache_list[idx].win;
+ XWindowAttributes attr;
+ int x1, y1, w1, h1;
+ int x2, y2, w2, h2;
+ int x, y, w, h;
+ int dx, dy;
+ sraRegionPtr r;
+
+
+ x1 = cache_list[idx].x;
+ y1 = cache_list[idx].y;
+ w1 = cache_list[idx].width;
+ h1 = cache_list[idx].height;
+
+ if (! valid_window(win, &attr, 1)) {
+fprintf(stderr, "su_save: not valid\n");
+// DELETE(idx);
+ return 0;
+ }
+
+ x2 = attr.x;
+ y2 = attr.y;
+ w2 = attr.width;
+ h2 = attr.height;
+
+ if (cache_list[idx].su_x < 0 || w2 > cache_list[idx].su_w || h2 > cache_list[idx].su_h) {
+ find_rect(idx, x2, y2, w2, h2);
+ }
+ x = cache_list[idx].su_x;
+ y = cache_list[idx].su_y;
+ w = cache_list[idx].su_w;
+ h = cache_list[idx].su_h;
+
+ if (x < 0) {
+ STORE(idx, win, attr);
+ return 0;
+ }
+
+ dx = x - x2;
+ dy = y - y2;
+
+ r = sraRgnCreateRect(x2+dx, y2+dy, x2+w2+dx, y2+h2+dy);
+fprintf(stderr, "su_save: dx=%d dy=%d\n", dx, dy);
+ do_copyregion(r, dx, dy);
+ fb_push_wait(0.01, FB_COPY);
+fprintf(stderr, "su_save: done. %dx%d+%d+%d %dx%d+%d+%d %.2f %.2f\n", w1, h1, x1, y1, w2, h2, x2, y2, cache_list[idx].su_time, dnow());
+ sraRgnDestroy(r);
+
+ STORE(idx, win, attr);
+ cache_list[idx].su_time = dnow();
+
+ return 1;
+}
+
+int bs_restore(int idx) {
+ Window win = cache_list[idx].win;
+ XWindowAttributes attr;
+ int x1, y1, w1, h1;
+ int x2, y2, w2, h2;
+ int x, y, w, h;
+ int dx, dy;
+ sraRegionPtr r;
+
+ if (cache_list[idx].bs_x < 0 || cache_list[idx].bs_time == 0.0) {
+ return 0;
+ }
+
+ x1 = cache_list[idx].x;
+ y1 = cache_list[idx].y;
+ w1 = cache_list[idx].width;
+ h1 = cache_list[idx].height;
+
+ if (! valid_window(win, &attr, 1)) {
+fprintf(stderr, "bs_restore: not valid\n");
+ DELETE(idx);
+ return 0;
+ }
+
+ x2 = attr.x;
+ y2 = attr.y;
+ w2 = attr.width;
+ h2 = attr.height;
+
+ x = cache_list[idx].bs_x;
+ y = cache_list[idx].bs_y;
+ w = cache_list[idx].bs_w;
+ h = cache_list[idx].bs_h;
+
+ if (x < 0) {
+ STORE(idx, win, attr);
+ return 0;
+ }
+
+ dx = x2 - x;
+ dy = y2 - y;
+
+ r = sraRgnCreateRect(x+dx, y+dy, x+w2+dx, y+h2+dy);
+fprintf(stderr, "bs_restore: dx=%d dy=%d\n", dx, dy);
+ do_copyregion(r, dx, dy);
+ fb_push_wait(0.01, FB_COPY);
+fprintf(stderr, "bs_rest: done. %dx%d+%d+%d %dx%d+%d+%d %.2f %.2f\n", w1, h1, x1, y1, w2, h2, x2, y2, cache_list[idx].bs_time, dnow());
+ sraRgnDestroy(r);
+
+ STORE(idx, win, attr);
+
+ return 1;
+}
+
+int su_restore(int idx) {
+ Window win = cache_list[idx].win;
+ XWindowAttributes attr;
+ int x1, y1, w1, h1;
+ int x2, y2, w2, h2;
+ int x, y, w, h;
+ int dx, dy;
+ sraRegionPtr r;
+ int invalid = 0;
+
+ if (cache_list[idx].su_x < 0 || cache_list[idx].su_time == 0.0) {
+ return 0;
+ }
+
+ x1 = cache_list[idx].x;
+ y1 = cache_list[idx].y;
+ w1 = cache_list[idx].width;
+ h1 = cache_list[idx].height;
+
+ if (! valid_window(win, &attr, 1)) {
+fprintf(stderr, "su_restore: not valid\n");
+ invalid = 1;
+ x2 = x1;
+ y2 = y1;
+ w2 = w1;
+ h2 = h1;
+ } else {
+ x2 = attr.x;
+ y2 = attr.y;
+ w2 = attr.width;
+ h2 = attr.height;
+ }
+
+ x = cache_list[idx].su_x;
+ y = cache_list[idx].su_y;
+ w = cache_list[idx].su_w;
+ h = cache_list[idx].su_h;
+
+ if (x < 0) {
+ if (invalid) {
+ DELETE(idx);
+ }
+ return 0;
+ }
+
+ dx = x2 - x;
+ dy = y2 - y;
+
+ r = sraRgnCreateRect(x+dx, y+dy, x+w2+dx, y+h2+dy);
+fprintf(stderr, "su_restore: dx=%d dy=%d\n", dx, dy);
+ do_copyregion(r, dx, dy);
+ fb_push_wait(0.01, FB_COPY);
+fprintf(stderr, "su_rest: done. %dx%d+%d+%d %dx%d+%d+%d %.2f %.2f\n", w1, h1, x1, y1, w2, h2, x2, y2, cache_list[idx].su_time, dnow());
+ sraRgnDestroy(r);
+
+ if (invalid) {
+ DELETE(idx);
+ return 0;
+ } else {
+ STORE(idx, win, attr);
+ return 1;
+ }
+}
+
+#include <rfb/default8x16.h>
+
+void check_ncache(void) {
+ static int last_map = -1;
+ static double last_root = 0.0;
+ static int first = 1;
+ int i, j, k;
+ double now, refresh = 60.0;
+ Window win, win2;
+ XWindowAttributes attr;
+ XEvent ev;
+
+ if (! ncache || ! ncache0) {
+ return;
+ }
+ if (! screen) {
+ return;
+ }
+ if (! dpy) {
+ return;
+ }
+
+ if (first) {
+ int dx = 10, dy = 24;
+ for (i=0; i < NRECENT; i++) {
+ recent[i] = None;
+ }
+ rlast = 0;
+ X_LOCK;
+ /* event leak with client_count == 0 */
+ xselectinput_rootwin |= SubstructureNotifyMask;
+ XSelectInput(dpy, rootwin, xselectinput_rootwin);
+ X_UNLOCK;
+ first = 0;
+ rfbDrawString(screen, &default8x16Font, dx, dpy_y+1*dy,
+ "This is the Pixel buffer cache region. Your VNC Viewer is not hiding it from you.",
+ white_pixel());
+ rfbDrawString(screen, &default8x16Font, dx, dpy_y+2*dy,
+ "Try resizing your VNC Viewer so you don't see it !!",
+ white_pixel());
+ rfbDrawString(screen, &default8x16Font, dx, dpy_y+3*dy,
+ "To disable run the server with: x11vnc -ncache 0 ...",
+ white_pixel());
+ rfbDrawString(screen, &default8x16Font, dx, dpy_y+4*dy,
+ "More info: http://www.karlrunge.com/x11vnc/#faq-client-caching",
+ white_pixel());
+ snapshot_cache_list(0, 100.0);
+ }
+
+ if (! client_count) {
+ return;
+ }
+ now = dnow();
+
+ if (now > last_root + refresh) {
+fprintf(stderr, "\n**** checking cache_list[%d]\n\n", cache_list_num);
+ for(k=0; k<cache_list_num; k++) {
+ win = cache_list[k].win;
+ if (win == None) {
+fprintf(stderr, " Empty[%d]: 0x%x\n", k, win);
+ } else if (cache_list[k].selectinput && cache_list[k].time > now - refresh) {
+fprintf(stderr, " Young[%d]: 0x%x\n", k, win);
+ } else if (valid_window(win, &attr, 1)) {
+ STORE(k, win, attr);
+ if (! cache_list[k].selectinput) {
+ X_LOCK;
+fprintf(stderr, " XSelectInput[%d]: 0x%x\n", k, win);
+ XSelectInput(dpy, win, StructureNotifyMask);
+ X_UNLOCK;
+ CLEAR(k);
+ cache_list[k].selectinput = 1;
+ } else {
+//fprintf(stderr, " SKIP XSelectInput[%d]: 0x%x\n", k, win);
+ }
+ } else {
+fprintf(stderr, " DELETE(%d) 0x%x\n", k, win);
+ DELETE(k);
+ }
+ }
+ last_root = dnow();
+ }
+
+ X_LOCK;
+ while (XCheckMaskEvent(dpy, SubstructureNotifyMask|StructureNotifyMask, &ev)) {
+ int type = ev.type;
+ int idx;
+ win = ev.xany.window;
+
+//fprintf(stderr, "evnt: 0x%x %d pending: %d\n", win, type, XPending(dpy));
+ if (win == rootwin) {
+ if (type == CreateNotify) {
+ int x=0,y=0,w=0,h=0;
+ win2 = ev.xcreatewindow.window;
+ idx = lookup_win_index(win2);
+ if (idx < 0) {
+ idx = lookup_free_index();
+ }
+ if (valid_window(win2, &attr, 1)) {
+ STORE(idx, win2, attr);
+ CLEAR(idx);
+// su_save(idx); // not working
+ x=attr.x;
+ y=attr.y;
+ w=attr.width;
+ h=attr.height;
+ XSelectInput(dpy, win2, StructureNotifyMask);
+ cache_list[idx].selectinput = 1;
+ }
+fprintf(stderr, "root: ** CreateNotify 0x%x %d -- %dx%d+%d+%d\n", win2, idx, w, h, x, y);
+ } else if (type == ReparentNotify) {
+ if (ev.xreparent.parent != rootwin) {
+ win2 = ev.xreparent.window;
+ if (win2 != rootwin) {
+ idx = lookup_win_index(win2);
+fprintf(stderr, "root: ReparentNotify RM: 0x%x %d\n", win2, idx);
+ if (idx >= 0) {
+ DELETE(idx);
+ }
+ XSelectInput(dpy, win2, 0);
+ }
+ }
+ } else {
+ Window ww = None;
+ /* skip rest */
+if (type == DestroyNotify) ww = ev.xdestroywindow.window;
+if (type == UnmapNotify) ww = ev.xunmap.window;
+if (type == MapNotify) ww = ev.xmap.window;
+if (type == Expose) ww = ev.xexpose.window;
+if (type == ConfigureNotify) ww = ev.xconfigure.window;
+fprintf(stderr, "root: skip %s for 0x%x\n", Etype(type), ww);
+ }
+ } else {
+ if (type == ReparentNotify) {
+ if (ev.xreparent.parent != rootwin) {
+ win2 = ev.xreparent.window;
+ if (win2 != rootwin) {
+ idx = lookup_win_index(win2);
+fprintf(stderr, "----- ReparentNotify RM: 0x%x %d\n", win2, idx);
+ if (idx >= 0) {
+ DELETE(idx);
+ }
+ XSelectInput(dpy, win2, 0);
+ }
+ }
+
+ } else if (type == DestroyNotify) {
+ win2 = ev.xdestroywindow.window;
+ idx = lookup_win_index(win2);
+fprintf(stderr, "----- DestroyNotify 0x%x %d\n", win2, idx);
+ if (idx >= 0) {
+ DELETE(idx);
+ }
+
+ } else if (type == ConfigureNotify) {
+ idx = lookup_win_index(win);
+fprintf(stderr, "----- ConfigureNotify 0x%x %d -- %dx%d+%d+%d\n", win, idx, ev.xconfigure.width, ev.xconfigure.height, ev.xconfigure.x, ev.xconfigure.y);
+ if (idx >= 0) {
+ /* XXX invalidate su and/or bs */
+ cache_list[idx].x = ev.xconfigure.x;
+ cache_list[idx].y = ev.xconfigure.y;
+ cache_list[idx].width = ev.xconfigure.width;
+ cache_list[idx].height = ev.xconfigure.height;
+ }
+
+ } else if (type == MapNotify) {
+ idx = lookup_win_index(win);
+fprintf(stderr, "----- MapNotify 0x%x %d\n", win, idx);
+ if (idx < 0) {
+ continue;
+ }
+ if (cache_list[idx].map_state == IsUnmapped) {
+ X_UNLOCK;
+ su_save(idx);
+ bs_restore(idx);
+ X_LOCK;
+ }
+
+ } else if (type == UnmapNotify) {
+ idx = lookup_win_index(win);
+fprintf(stderr, "----- UnmapNotify 0x%x %d\n", win, idx);
+ if (idx < 0) {
+ continue;
+ }
+ if (cache_list[idx].map_state == IsViewable) {
+ X_UNLOCK;
+ bs_save(idx);
+ su_restore(idx);
+ X_LOCK;
+ }
+ } else {
+ /* skip rest */
+fprintf(stderr, "----- skip %s\n", Etype(type));
+ }
+ }
+ }
+//fprintf(stderr, "pending2: %d\n", XPending(dpy));
+ X_UNLOCK;
+if (dnow() - now > 0.05) fprintf(stderr, "check_ncache OUT: %f\n", dnow() - now);
+}
+#endif
+