From 94b092cd2221df953632ad484a141853efd6c4e8 Mon Sep 17 00:00:00 2001
From: runge <runge>
Date: Mon, 6 Feb 2006 05:34:43 +0000
Subject:  x11vnc: -8to24 more speedups; tunables for very slow machines.

---
 x11vnc/8to24.c       | 420 +++++++++++++++++++++++++++++++++++++++------------
 x11vnc/ChangeLog     |   3 +
 x11vnc/README        |  18 ++-
 x11vnc/help.c        |  12 ++
 x11vnc/win_utils.c   |  15 +-
 x11vnc/x11vnc.1      |  14 +-
 x11vnc/x11vnc_defs.c |   2 +-
 7 files changed, 383 insertions(+), 101 deletions(-)

diff --git a/x11vnc/8to24.c b/x11vnc/8to24.c
index bfe9292..88b923c 100644
--- a/x11vnc/8to24.c
+++ b/x11vnc/8to24.c
@@ -17,7 +17,7 @@ static int check_pointer_in_depth24(void);
 static void parse_cmap8to24(void);
 static void set_poll_fb(void);
 static int check_depth(Window win, Window top, int doall);
-static int check_depth_win(Window win, Window top, XWindowAttributes attr);
+static int check_depth_win(Window win, Window top, XWindowAttributes *attr);
 static XImage *p_xi(XImage *xi, Visual *visual, int win_depth, int *w);
 static int poll_line(int x1, int x2, int y1, int n, sraRegionPtr mod);
 static void poll_line_complement(int x1, int x2, int y1, sraRegionPtr mod);
@@ -27,7 +27,7 @@ static void mark_rgn_rects(sraRegionPtr mod);
 static int get_8bpp_regions(int validate);
 static int get_cmap(int j, Colormap cmap);
 static void do_8bpp_region(int n, sraRegionPtr mark);
-static XImage *cmap_xi(XImage *xi, Visual *visual, int win_depth);
+static XImage *cmap_xi(XImage *xi, Window win, int win_depth);
 static void transform_rect(sraRect rect, Window win, int win_depth, int cm);
 
 /* struct for keeping info about the 8bpp windows: */
@@ -41,6 +41,7 @@ typedef struct window8 {
 	Colormap cmap;
 	Bool map_installed;
 	int fetched;
+	double last_fetched;
 	sraRegionPtr clip_region;
 } window8bpp_t;
 
@@ -50,21 +51,59 @@ enum mark_8bpp_modes {
 	MARK_8BPP_TOP
 };
 
+#define NCOLOR 256
+
 static Colormap root_cmap = 0;
+static unsigned int root_rgb[NCOLOR];
 
 static void set_root_cmap(void) {
 	static time_t last_set = 0;
 	time_t now = time(0);
 	XWindowAttributes attr;
+	static XColor color[NCOLOR];
+	int redo = 0;
 
-	if (now > last_set + 5) {
-		root_cmap = 0;
+	if (now > last_set + 10) {
+		redo = 1;
 	}
-	if (! root_cmap) {
+	if (! root_cmap || redo) {
 		X_LOCK;
-		if (valid_window(window, &attr, 1)) {
+		if (! valid_window(window, &attr, 1)) {
+			X_UNLOCK;
+			return;
+		}
+		if (attr.colormap) {
+			int i, ncells = NCOLOR;
+			for (i=0; i < ncells; i++) {
+				color[i].pixel = i;
+				color[i].pad = 0;
+			}
 			last_set = now;
 			root_cmap = attr.colormap;
+			XQueryColors(dpy, root_cmap, color, ncells);
+			for (i=0; i < ncells; i++) {
+				unsigned int red, green, blue;
+				/* strip out highest 8 bits of values: */
+				red   = (color[i].red   & 0xff00) >> 8;
+				green = (color[i].green & 0xff00) >> 8;
+				blue  = (color[i].blue  & 0xff00) >> 8;
+
+				/*
+				 * the maxes should be at 255 already,
+				 * but just in case...
+				 */
+				red   = (main_red_max   * red  )/255;
+				green = (main_green_max * green)/255;
+				blue  = (main_blue_max  * blue )/255;
+
+				/* shift them over and or together for value */
+				red   = red    << main_red_shift;
+				green = green  << main_green_shift;
+				blue  = blue   << main_blue_shift;
+
+				/* store it in the array to be used later */
+				root_rgb[i] = red | green | blue;
+			}
 		}
 		X_UNLOCK;
 	}
@@ -77,6 +116,8 @@ static window8bpp_t windows_8bpp[MAX_8BPP_WINDOWS];
 static int db24 = 0;
 static int xgetimage_8to24 = 1;
 static double poll_8to24_delay = POLL_8TO24_DELAY;
+static double cache_win = 0.0;
+static int level2_8to24 = 0;
 
 static int check_pointer_in_depth24(void) {
 	int tries = 0, in_24 = 0;
@@ -129,13 +170,19 @@ static void parse_cmap8to24(void) {
 		db24 = 0;
 		xgetimage_8to24 = 1;
 		poll_8to24_delay = POLL_8TO24_DELAY;
+		level2_8to24 = 0;
+		cache_win = 0.0;
 		while (p) {
 			if (strstr(p, "dbg=") == p) {
 				db24 = atoi(p + strlen("dbg="));
 			} else if (strstr(p, "poll=") == p) {
 				poll_8to24_delay = atof(p + strlen("poll="));
+			} else if (strstr(p, "cachewin=") == p) {
+				cache_win = atof(p + strlen("cachewin="));
 			} else if (!strcmp(p, "nogetimage")) {
 				xgetimage_8to24 = 0;
+			} else if (!strcmp(p, "level2")) {
+				level2_8to24 = 1;
 			}
 			p = strtok(NULL, ",");
 		}
@@ -175,6 +222,11 @@ static void set_poll_fb(void) {
 	pfb(1, &poll8_fb,  &poll8_fb_w,  &poll8_fb_h);
 }
 
+int MV_glob = 0;
+int MV_count;
+int MV_hit;
+double MV_start;
+
 void check_for_multivis(void) {
 	XWindowAttributes attr;
 	int doall = 0;
@@ -190,8 +242,9 @@ void check_for_multivis(void) {
 	static double last_call = 0.0;
 	static double last_query = 0.0;
 	double now = dnow();
+	double delay;
 
-	if (now > last_parse + 0.75) {
+	if (now > last_parse + 1.0) {
 		last_parse = now;
 		parse_cmap8to24();
 	}
@@ -207,6 +260,7 @@ if (db24 > 2) fprintf(stderr, " check_for_multivis: %.4f\n", now - last_call);
 			windows_8bpp[i].map_state = IsUnmapped;
 			windows_8bpp[i].cmap = (Colormap) 0;
 			windows_8bpp[i].fetched = 0;
+			windows_8bpp[i].last_fetched = -1.0;
 			windows_8bpp[i].clip_region = NULL;
 		}
 		set_poll_fb();
@@ -215,6 +269,10 @@ if (db24 > 2) fprintf(stderr, " check_for_multivis: %.4f\n", now - last_call);
 		doall = 1;	/* fetch everything first time */
 	}
 
+	if (wireframe_in_progress) {
+		return;
+	}
+
 	set_root_cmap();
 
 	/*
@@ -243,7 +301,13 @@ if (db24 > 2) fprintf(stderr, " check_for_multivis: %.4f\n", now - last_call);
 	}
 
 	/* snapshot + update the current stacking order: */
-	if (doall || now > last_update + 0.15) {
+	/* TUNABLE */
+	if (poll_8to24_delay >= POLL_8TO24_DELAY) {
+		delay = 3.0 * poll_8to24_delay;
+	} else {
+		delay = 3.0 * POLL_8TO24_DELAY;	/* 0.15 */
+	}
+	if (doall || now > last_update + delay) {
 		snapshot_stack_list(0, 0.0);
 		update_stack_list();
 		last_update = now;
@@ -282,22 +346,41 @@ if (db24 > 2) fprintf(stderr, " check_for_multivis: %.4f\n", now - last_call);
 				windows_8bpp[i].map_state = IsUnmapped;
 				windows_8bpp[i].cmap = (Colormap) 0;
 				windows_8bpp[i].fetched = 0;
+				windows_8bpp[i].last_fetched = -1.0;
 			}
 		}
 		X_UNLOCK;
 	}
 
+	MV_count = 0;
+	MV_hit = 0;
+	MV_start = dnow();
+
+	set_root_cmap();
+
 	/* loop over all toplevels, both 8 and 24 depths: */
+
+	X_LOCK;	/* a giant lock around the whole activity */
+
 	for (k=0; k < stack_list_num; k++) {
 		Window r, parent;
 		Window *list0;
 		Status rc;
 		unsigned int nc0;
 		int i1;
+		XErrorHandler old_handler;
+		double delay;
 
 		Window win = stack_list[k].win;
 
-		if (now < last_query + 0.05) {
+		/* TUNABLE */
+		if (poll_8to24_delay >= POLL_8TO24_DELAY) {
+			delay = 1.5 * poll_8to24_delay;
+		} else {
+			delay = 1.5 * POLL_8TO24_DELAY;	/* 0.075 */
+		}
+
+		if (now < last_query + delay) {
 			break;
 		}
 
@@ -328,12 +411,17 @@ if (db24 > 2) fprintf(stderr, " check_for_multivis: %.4f\n", now - last_call);
 		}
 
 		/* we recurse up to two levels down from stack_list windows */
-		X_LOCK;
+
+		old_handler = XSetErrorHandler(trap_xerror);
+		trapped_xerror = 0;
 		rc = XQueryTree(dpy, win, &r, &parent, &list0, &nc0);
-		X_UNLOCK;
-		if (! rc) {
+		XSetErrorHandler(old_handler);
+
+		if (! rc || trapped_xerror) {
+			trapped_xerror = 0;
 			continue;
 		}
+		trapped_xerror = 0;
 
 		/* loop over grandchildren of rootwin: */
 		for (i1=0; i1 < (int) nc0; i1++) {
@@ -345,12 +433,22 @@ if (db24 > 2) fprintf(stderr, " check_for_multivis: %.4f\n", now - last_call);
 			if (check_depth(win1, win, doall)) {
 				continue;
 			}
-			X_LOCK;
+
+			if (level2_8to24) {
+				continue;
+			}
+
+			old_handler = XSetErrorHandler(trap_xerror);
+			trapped_xerror = 0;
 			rc = XQueryTree(dpy, win1, &r, &parent, &list1, &nc1);
-			X_UNLOCK;
-			if (! rc) {
+			XSetErrorHandler(old_handler);
+
+			if (! rc || trapped_xerror) {
+				trapped_xerror = 0;
 				continue;
 			}
+			trapped_xerror = 0;
+
 			/* loop over great-grandchildren of rootwin: */
 			for (i2=0; i2< (int) nc1; i2++) {
 				Window win2 = list1[i2];
@@ -361,19 +459,20 @@ if (db24 > 2) fprintf(stderr, " check_for_multivis: %.4f\n", now - last_call);
 				/* more? Which wm does this? */
 			}
 			if (nc1) {
-				X_LOCK;
 				XFree(list1);
-				X_UNLOCK;
 			}
 		}
 		if (nc0) {
-			X_LOCK;
 			XFree(list0);
-			X_UNLOCK;
 		}
 	}
+	X_UNLOCK;
+
 	last_query = dnow();
 
+MV_glob += MV_count;
+if (0) fprintf(stderr, "MV_count: %d hit: %d %.4f  %10.2f\n", MV_count, MV_hit, last_query - MV_start, MV_glob / (last_query - x11vnc_start));
+
 	if (screen_fixup_8 > 0.0 && now > last_fixup + screen_fixup_8) {
 		last_fixup = now;
 		mark_8bpp(MARK_8BPP_ALL);
@@ -416,44 +515,124 @@ if (db24 > 2) fprintf(stderr, " check_for_multivis: %.4f\n", now - last_call);
 			}
 		}
 	}
+if (0) fprintf(stderr, "done: %.4f\n", dnow() - last_query);
+}
+
+#define VW_CACHE_MAX 1024
+static XWindowAttributes vw_cache_attr[VW_CACHE_MAX];
+static Window vw_cache_win[VW_CACHE_MAX];
+
+static void set_attr(XWindowAttributes *attr, int j) {
+	memcpy((void *) (vw_cache_attr+j), (void *) attr,
+	    sizeof(XWindowAttributes));
+}
+#if 0
+static int get_attr(XWindowAttributes *attr, int j) {
+	memcpy((void *) attr, (void *) (vw_cache_attr+j),
+	    sizeof(XWindowAttributes));
+	return 1;
+}
+#endif
+
+static XWindowAttributes wattr;
+
+static XWindowAttributes *vw_lookup(Window win) {
+	static double last_purge = 0.0;
+	double now;
+	int i, j, k;
+
+	if (win == None) {
+		return NULL;
+	}
+
+	now = dnow();
+	if (now > last_purge + cache_win) {
+		last_purge = now;
+		for (i=0; i<VW_CACHE_MAX; i++) {
+			vw_cache_win[i] = None;
+		}
+	}
+
+	j = -1;
+	k = -1;
+	for (i=0; i<VW_CACHE_MAX; i++) {
+		if (vw_cache_win[i] == win) {
+			j = i;
+			break;
+		} else if (vw_cache_win[i] == None) {
+			k = i;
+			break;
+		}
+	}
+
+	if (j >= 0) {
+MV_hit++;
+		return vw_cache_attr+j;
+		
+	} else if (k >= 0) {
+		XWindowAttributes attr2;
+		int rc = valid_window(win, &attr2, 1);
+		if (rc) {
+			vw_cache_win[k] = win;
+			set_attr(&attr2, k);
+			return vw_cache_attr+k;
+		} else {
+			return NULL;
+		}
+	} else {
+		/* Full */
+		int rc = valid_window(win, &wattr, 1);
+		if (rc) {
+			return &wattr;
+		} else {
+			return NULL;
+		}
+	}
 }
 
 static int check_depth(Window win, Window top, int doall) {
-	XWindowAttributes attr;
+	XWindowAttributes attr, *pattr;
 
-	X_LOCK;
 	/* first see if it is (still) a valid window: */
-	if (! valid_window(win, &attr, 1)) {
-		X_UNLOCK;
-		return 1;	/* indicate done */
+MV_count++;
+
+	if (cache_win > 0.0) {
+		pattr = vw_lookup(win);
+		if (pattr == NULL) {
+			return 1;	/* indicate done */
+		}
+	} else {
+		if (! valid_window(win, &attr, 1)) {
+			return 1;	/* indicate done */
+		}
+		pattr = &attr;
 	}
-	X_UNLOCK;
-	if (! doall && attr.map_state != IsViewable) {
+
+	if (! doall && pattr->map_state != IsViewable) {
 		/*
 		 * store results anyway...  this may lead to table
 		 * filling up, but currently this allows us to update
 		 * state of onetime mapped windows.
 		 */
-		check_depth_win(win, top, attr);
+		check_depth_win(win, top, pattr);
 		return 1;	/* indicate done */
-	} else if (check_depth_win(win, top, attr)) {
+	} else if (check_depth_win(win, top, pattr)) {
 		return 1;	/* indicate done */
 	} else {
 		return 0;	/* indicate not done */
 	}
 }
 
-static int check_depth_win(Window win, Window top, XWindowAttributes attr) {
+static int check_depth_win(Window win, Window top, XWindowAttributes *attr) {
 	int store_it = 0;
 	/*
 	 * only store windows with depth not equal to the default visual's
 	 * depth note some windows can have depth == 0 ... (skip them).
 	 */
-	if (attr.depth > 0) {
-		set_root_cmap();
-		if (depth == 24 && attr.depth != 24) {
+	if (attr->depth > 0) {
+		if (depth == 24 && attr->depth != 24) {
 			store_it = 1;
-		} else if (depth == 8 && root_cmap && attr.colormap !=
+		} else if (depth == 8 && root_cmap && attr->colormap !=
 		    root_cmap) {
 			store_it = 1;
 		}
@@ -462,13 +641,13 @@ static int check_depth_win(Window win, Window top, XWindowAttributes attr) {
 	if (store_it) {
 		int i, j = -1, none = -1, nomap = -1;
 		int new = 0;
-		if (attr.map_state == IsViewable) {
+		if (attr->map_state == IsViewable) {
 			/* count the visible ones: */
 			multivis_count++;
-			if (attr.depth == 24) {
+			if (attr->depth == 24) {
 				multivis_24count++;
 			}
-if (db24 > 1) fprintf(stderr, "multivis: 0x%lx %d\n", win, attr.depth);
+if (db24 > 1) fprintf(stderr, "multivis: 0x%lx %d\n", win, attr->depth);
 		}
 
 		/* try to find a table slot for this window: */
@@ -489,7 +668,7 @@ if (db24 > 1) fprintf(stderr, "multivis: 0x%lx %d\n", win, attr.depth);
 			}
 		}
 		if (j < 0) {
-			if (attr.map_state != IsViewable) {
+			if (attr->map_state != IsViewable) {
 				/* no slot and not visible: not worth keeping */
 				return 1;
 			} else if (none >= 0) {
@@ -503,7 +682,7 @@ if (db24 > 1) fprintf(stderr, "multivis: 0x%lx %d\n", win, attr.depth);
 			/* otherwise we cannot store it... */
 		}
 
-if (db24 > 1) fprintf(stderr, "multivis: 0x%lx ms: %d j: %d no: %d nm: %d dep=%d\n", win, attr.map_state, j, none, nomap, attr.depth);
+if (db24 > 1) fprintf(stderr, "multivis: 0x%lx ms: %d j: %d no: %d nm: %d dep=%d\n", win, attr->map_state, j, none, nomap, attr->depth);
 
 		/* store if if we found a slot j: */
 		if (j >= 0) {
@@ -511,33 +690,34 @@ if (db24 > 1) fprintf(stderr, "multivis: 0x%lx ms: %d j: %d no: %d nm: %d dep=%d
 			int x, y;
 			int now_vis = 0;
 
-			if (attr.map_state == IsViewable &&
+			if (attr->map_state == IsViewable &&
 			    windows_8bpp[j].map_state != IsViewable) {
 				now_vis = 1;
 			} 
-if (db24 > 1) fprintf(stderr, "multivis: STORE 0x%lx j: %3d ms: %d dep=%d\n", win, j, attr.map_state, attr.depth);
+if (db24 > 1) fprintf(stderr, "multivis: STORE 0x%lx j: %3d ms: %d dep=%d\n", win, j, attr->map_state, attr->depth);
 			windows_8bpp[j].win = win;
 			windows_8bpp[j].top = top;
-			windows_8bpp[j].depth = attr.depth;
-			windows_8bpp[j].map_state = attr.map_state;
-			windows_8bpp[j].cmap = attr.colormap;
-			windows_8bpp[j].map_installed = attr.map_installed;
-			windows_8bpp[j].w = attr.width;
-			windows_8bpp[j].h = attr.height;
+			windows_8bpp[j].depth = attr->depth;
+			windows_8bpp[j].map_state = attr->map_state;
+			windows_8bpp[j].cmap = attr->colormap;
+			windows_8bpp[j].map_installed = attr->map_installed;
+			windows_8bpp[j].w = attr->width;
+			windows_8bpp[j].h = attr->height;
 			windows_8bpp[j].fetched = 1;
+			windows_8bpp[j].last_fetched = dnow();
 
 			/* translate x y to be WRT the root window (not parent) */
-			X_LOCK;
 			xtranslate(win, window, 0, 0, &x, &y, &w, 1);
-			X_UNLOCK;
 			windows_8bpp[j].x = x;
 			windows_8bpp[j].y = y;
 
 			if (new || now_vis) {
 if (db24) fprintf(stderr, "new/now_vis: 0x%lx %d/%d\n", win, new, now_vis);
 				/* mark it immediately if a new one: */
-				mark_rect_as_modified(x, y, x + attr.width,
-				    y + attr.height, 0);
+				X_UNLOCK;	/* dont forget the giant lock */
+				mark_rect_as_modified(x, y, x + attr->width,
+				    y + attr->height, 0);
+				X_LOCK;
 			}
 		} else {
 			/*
@@ -583,10 +763,14 @@ static int poll_line(int x1, int x2, int y1, int n, sraRegionPtr mod) {
 	static int xi8_w = 0, xi24_w = 0;
 
 	XErrorHandler old_handler = NULL;
-	XWindowAttributes attr;
 	XImage *xi;
 	Window c, win = windows_8bpp[n].win;
 
+	static XWindowAttributes attr;
+	static Window last_win = None; 
+	static double last_time = 0.0;
+	double now;
+
 	sraRegionPtr rect;
 	int mx1, mx2, my1, my2;
 	int ns = NSCAN/2;
@@ -602,9 +786,17 @@ static int poll_line(int x1, int x2, int y1, int n, sraRegionPtr mod) {
 	}
 
 	X_LOCK;
-	if (! valid_window(windows_8bpp[n].win, &attr, 1)) {
-		X_UNLOCK;
-		return 0;
+	now = dnow();
+	if (last_win != None && win == last_win && now < last_time + 0.5) {
+		;	/* use previous attr */
+	} else {
+		if (! valid_window(win, &attr, 1)) {
+			X_UNLOCK;
+			last_win = None;
+			return 0;
+		}
+		last_time = now;
+		last_win = win;
 	}
 
 	if (attr.depth != 8 && attr.depth != 24) {
@@ -624,19 +816,25 @@ static int poll_line(int x1, int x2, int y1, int n, sraRegionPtr mod) {
 		n_off = poll24_fb_w * y1 + x1;
 	}
 
-	xtranslate(win, window, 0, 0, &xo, &yo, &c, 1);
+	old_handler = XSetErrorHandler(trap_xerror);
+	trapped_xerror = 0;
+
+	/* xtranslate() not used to save two XSetErrorHandler calls */
+	XTranslateCoordinates(dpy, win, window, 0, 0, &xo, &yo, &c);
+
 	xo = x1 - xo;
 	yo = y1 - yo;
 	w = x2 - x1;
 
-	if (xo < 0 || yo < 0 || xo + w > attr.width) {
+	if (trapped_xerror || xo < 0 || yo < 0 || xo + w > attr.width) {
 if (db24 > 2) fprintf(stderr, "avoid bad match...\n");
+		XSetErrorHandler(old_handler);
+		trapped_xerror = 0;
 		X_UNLOCK;
 		return 0;
 	}
 
 	trapped_xerror = 0;
-	old_handler = XSetErrorHandler(trap_xerror);
 	xi_r = XGetSubImage(dpy, win, xo, yo, w, 1, AllPlanes, ZPixmap, xi,
 	    0, 0);
 	XSetErrorHandler(old_handler);
@@ -943,6 +1141,7 @@ if (db24 > 1) fprintf(stderr, "get_8bpp_regions: 0x%lx ms=%d dep=%d i=%d\n", w,
 				windows_8bpp[i].map_state = IsUnmapped;
 				windows_8bpp[i].cmap = (Colormap) 0;
 				windows_8bpp[i].fetched = 0;
+				windows_8bpp[i].last_fetched = -1.0;
 				continue;
 			}
 			X_UNLOCK;
@@ -954,6 +1153,7 @@ if (db24 > 1) fprintf(stderr, "get_8bpp_regions: 0x%lx ms=%d dep=%d i=%d\n", w,
 			windows_8bpp[i].w = attr.width;
 			windows_8bpp[i].h = attr.height;
 			windows_8bpp[i].fetched = 1;
+			windows_8bpp[i].last_fetched = dnow();
 
 			if (attr.map_state != IsViewable) {
 				continue;
@@ -1053,7 +1253,6 @@ if (db24 > 1) fprintf(stderr, "subtract:  0x%lx %d -- %d %d %d %d\n", swin, k, s
 	return mapcount;
 }
 
-#define NCOLOR 256
 static XColor color[CMAPMAX][NCOLOR];
 static unsigned int rgb[CMAPMAX][NCOLOR];
 static int cmap_failed[CMAPMAX];
@@ -1188,19 +1387,26 @@ if (db24 > 1) fprintf(stderr, "ncmaps: %d\n", ncmaps);
 	sraRgnDestroy(clip);
 }
 
-static XImage *cmap_xi(XImage *xi, Visual *visual, int win_depth) {
+static XImage *cmap_xi(XImage *xi, Window win, int win_depth) {
+	XWindowAttributes attr;
 	char *d;
+
 	if (xi) {
 		XDestroyImage(xi);
 	}
-	if (win_depth == 8) {
+	if (! valid_window(win, &attr, 1)) {
+		return (XImage *) NULL;
+	}
+	if (attr.depth != win_depth) {
+		return (XImage *) NULL;
+	} else if (win_depth == 8) {
 		d = (char *) malloc(dpy_x * dpy_y * 1);
 	} else if (win_depth == 24) {
 		d = (char *) malloc(dpy_x * dpy_y * 4);
 	} else {
 		return (XImage *) NULL;
 	}
-	return XCreateImage(dpy, visual, win_depth, ZPixmap, 0, d, dpy_x,
+	return XCreateImage(dpy, attr.visual, win_depth, ZPixmap, 0, d, dpy_x,
 	    dpy_y, 8, 0);
 }
 
@@ -1214,7 +1420,7 @@ static void transform_rect(sraRect rect, Window win, int win_depth, int cm) {
 	int poll_Bpl;
 
 	int do_getimage = xgetimage_8to24;
-	int line, n_off, j, h, w, vw;
+	int line, n_off, j, h, w;
 	unsigned int hi, idx;
 	XWindowAttributes attr;
 	XErrorHandler old_handler = NULL;
@@ -1232,6 +1438,7 @@ if (db24 > 1) fprintf(stderr, "transform %4d %4d %4d %4d cm: %d\n", rect.x1, rec
 		do_getimage = 1;
 	}
 
+#if 0
 	if (do_getimage) {
 		X_LOCK;
 		vw = valid_window(win, &attr, 1);
@@ -1239,6 +1446,9 @@ if (db24 > 1) fprintf(stderr, "transform %4d %4d %4d %4d cm: %d\n", rect.x1, rec
 	}
 
 	if (do_getimage && vw) {
+#else
+	if (do_getimage) {
+#endif
 		static XImage *xi_8  = NULL;
 		static XImage *xi_24 = NULL;
 		XImage *xi = NULL, *xi_r;
@@ -1250,37 +1460,43 @@ if (db24 > 1) fprintf(stderr, "transform %4d %4d %4d %4d cm: %d\n", rect.x1, rec
 		hu = (unsigned int) h;
 
 		X_LOCK;
-		xtranslate(win, window, 0, 0, &xo, &yo, &c, 1);
-		xo = rect.x1 - xo;
-		yo = rect.y1 - yo;
-
-if (db24 > 1) fprintf(stderr, "xywh: %d %d %d %d vs. %d %d\n", xo, yo, w, h, attr.width, attr.height);
-
-		if (xo < 0 || yo < 0 || w > attr.width || h > attr.height) {
-			X_UNLOCK;
-if (db24 > 1) fprintf(stderr, "skipping due to potential bad match...\n");
-			return;
-		}
-
 #define GETSUBIMAGE
 #ifdef GETSUBIMAGE
 		if (win_depth == 8) {
 			if (xi_8 == NULL || xi_8->width != dpy_x ||
 			    xi_8->height != dpy_y) {
-				xi_8 = cmap_xi(xi_8, attr.visual, attr.depth);
+				xi_8 = cmap_xi(xi_8, win, 8);
 			}
 			xi = xi_8;
 		} else if (win_depth == 24) {
 			if (xi_24 == NULL || xi_24->width != dpy_x ||
 			    xi_24->height != dpy_y) {
-				xi_24 = cmap_xi(xi_24, attr.visual, attr.depth);
+				xi_24 = cmap_xi(xi_24, win, 24);
 			}
 			xi = xi_24;
 		}
 #endif
 
-		trapped_xerror = 0;
 		old_handler = XSetErrorHandler(trap_xerror);
+		trapped_xerror = 0;
+
+		XTranslateCoordinates(dpy, win, window, 0, 0, &xo, &yo, &c);
+
+		xo = rect.x1 - xo;
+		yo = rect.y1 - yo;
+
+if (db24 > 1) fprintf(stderr, "xywh: %d %d %d %d vs. %d %d\n", xo, yo, w, h, attr.width, attr.height);
+
+		if (trapped_xerror || xo < 0 || yo < 0) {
+		        /* w > attr.width || h > attr.height */
+			XSetErrorHandler(old_handler);
+			X_UNLOCK;
+			trapped_xerror = 0;
+if (db24 > 1) fprintf(stderr, "skipping due to potential bad match...\n");
+			return;
+		}
+		trapped_xerror = 0;
+
 #ifndef GETSUBIMAGE
 		xi = XGetImage(dpy, win, xo, yo, wu, hu, AllPlanes, ZPixmap);
 		xi_r = xi;
@@ -1427,15 +1643,15 @@ void bpp8to24(int x1, int y1, int x2, int y2) {
 	static int last_map_count = 0, call_count = 0;
 	static double last_get_8bpp_validate = 0.0;
 	static double last_snapshot = 0.0;
-	double now, dt, d0;
+	double now;
+	double dt, d0 = 0.0, t2;
 
 	if (! cmap8to24 || ! cmap8to24_fb) {
 		/* hmmm, why were we called? */
 		return;
 	}
 
-	now = dnow();
-if (db24 > 1) fprintf(stderr, "bpp8to24 %d %d %d %d %.4f\n", x1, y1, x2, y2, now - last_get_8bpp_validate);
+if (db24 > 1) fprintf(stderr, "bpp8to24 %d %d %d %d %.4f\n", x1, y1, x2, y2, dnow() - last_get_8bpp_validate);
 
 	call_count++;
 
@@ -1453,10 +1669,6 @@ if (db24 > 1) fprintf(stderr, "bpp8to24 %d %d %d %d %.4f\n", x1, y1, x2, y2, now
 		return;
 	}
 
-	X_LOCK;
-	XFlush(dpy);	/* make sure X server is up to date WRT input, etc */
-	X_UNLOCK;
-
 	/* copy from main_fb to cmap8to24_fb regardless of 8bpp windows: */
 
 	h = y2 - y1;
@@ -1465,7 +1677,6 @@ if (db24 > 1) fprintf(stderr, "bpp8to24 %d %d %d %d %.4f\n", x1, y1, x2, y2, now
 	if (depth == 8) {
 		/* need to cook up to depth 24 TrueColor  */
 		/* pixelsize = 1 */
-		int tcm = CMAPMAX - 1;
 
 		n_off = main_bytes_per_line * y1 + pixelsize * x1;
 
@@ -1473,7 +1684,7 @@ if (db24 > 1) fprintf(stderr, "bpp8to24 %d %d %d %d %.4f\n", x1, y1, x2, y2, now
 		dst = cmap8to24_fb + 4 * n_off;
 
 		set_root_cmap();
-		if (get_cmap(tcm, root_cmap)) {
+		if (root_cmap) {
 			int ps1 = 1, ps2 = 4;
 #if 0
 			unsigned int hi;
@@ -1496,7 +1707,7 @@ if (db24 > 1) fprintf(stderr, "bpp8to24 %d %d %d %d %.4f\n", x1, y1, x2, y2, now
 					} else {
 					}
 #endif
-					*ui = rgb[tcm][idx];
+					*ui = root_rgb[idx];
 if (db24 > 2) histo[idx]++;
 				}
 				src += main_bytes_per_line;
@@ -1534,21 +1745,36 @@ if (db24 > 2) histo[idx]++;
 
 if (db24 > 2) {for(i=0;i<256;i++){histo[i]=0;}}
 
+	now = dnow();
 	dt = now - last_get_8bpp_validate;
-	d0 = dnow();
-	if (dt < 0.0025) {
+	/* TUNABLES  */
+	if (dt < 0.003) {
 		;	/* XXX does this still give painting errors? */
 	} else {
 		int snapit = 0;
-		if (dt < 0.04) {
+		double delay1, delay2, delay3;
+		if (poll_8to24_delay >= POLL_8TO24_DELAY) {
+			delay1 = 1.0 * poll_8to24_delay;
+			delay2 = 2.0 * poll_8to24_delay;
+			delay3 = 10. * poll_8to24_delay;
+		} else {
+			delay1 = 1.0 * POLL_8TO24_DELAY;	/* 0.05 */
+			delay2 = 2.0 * POLL_8TO24_DELAY;	/* 0.1  */
+			delay3 = 10. * POLL_8TO24_DELAY;	/* 0.5  */
+		}
+		if (cache_win > 1.0) {
+			delay2 *= 2;
+			delay3 *= 2;
+		}
+		if (dt < delay1) {
 			validate = 0;
 		}
 		if (last_map_count) {
-			if (now > last_snapshot + 0.05) {
+			if (now > last_snapshot + delay2) {
 				snapit = 1;
 			}
 		} else {
-			if (now > last_snapshot + 0.4) {
+			if (now > last_snapshot + delay3) {
 				snapit = 1;
 			}
 		}
@@ -1556,15 +1782,20 @@ if (db24 > 2) {for(i=0;i<256;i++){histo[i]=0;}}
 		if (snapit) {
 			/* less problems if we update the stack frequently */
 			snapshot_stack_list(0, 0.0);
+if (0) fprintf(stderr, "SNAP time: %.4f\n", dnow() - now);
 			update_stack_list();
-			last_snapshot = now;
+			last_snapshot = dnow();
+if (0) fprintf(stderr, "UPDA time: %.4f\n", last_snapshot - now);
 		}
 
+if (0) t2 = dnow();
 		last_map_count = get_8bpp_regions(validate);
 		if (validate) {
-			last_get_8bpp_validate = now;
+			last_get_8bpp_validate = dnow();
 		}
+if (0) fprintf(stderr, "get8bpp-%d: %.4f\n", validate, dnow() - t2);
 	}
+if (db24) d0 = dnow();
 
 if (db24 > 1) fprintf(stderr, "bpp8to24 w=%d h=%d m=%p c=%p r=%p ncmaps=%d\n", w, h, main_fb, cmap8to24_fb, rfb_fb, ncmaps);
 
@@ -1630,6 +1861,7 @@ if (db24 > 2) fprintf(stderr, "cmap %d  %.4f\n", (int) cmaps[j], dnow() - d0);
 			sraRgnDestroy(rect);
 		}
 	}
+if (0) fprintf(stderr, "done time: %.4f\n", dnow() - d0);
 
 if (db24 > 2) {for(i=0; i<256;i++) {fprintf(stderr, " cmap histo[%03d] %d\n", i, histo[i]);}}
 }
diff --git a/x11vnc/ChangeLog b/x11vnc/ChangeLog
index 8a5f81b..9b9f3c1 100644
--- a/x11vnc/ChangeLog
+++ b/x11vnc/ChangeLog
@@ -1,3 +1,6 @@
+2006-02-06  Karl Runge <runge@karlrunge.com>
+	* x11vnc: -8to24 more speedups; tunables for very slow machines.
+
 2006-02-04  Karl Runge <runge@karlrunge.com>
 	* x11vnc: -8to24 speedups and improvements.
 
diff --git a/x11vnc/README b/x11vnc/README
index a34b6bd..299e0fc 100644
--- a/x11vnc/README
+++ b/x11vnc/README
@@ -1,5 +1,5 @@
 
-x11vnc README file                         Date: Sat Feb  4 22:21:00 EST 2006
+x11vnc README file                         Date: Mon Feb  6 00:16:18 EST 2006
 
 The following information is taken from these URLs:
 
@@ -4898,7 +4898,7 @@ x11vnc: a VNC server for real X displays
    Here are all of x11vnc command line options:
 % x11vnc -opts      (see below for -help long descriptions)
 
-x11vnc: allow VNC connections to real X11 displays. 0.8 lastmod: 2006-02-04
+x11vnc: allow VNC connections to real X11 displays. 0.8 lastmod: 2006-02-06
 
 x11vnc options:
   -display disp            -auth file             
@@ -5009,7 +5009,7 @@ libvncserver-tight-extension options:
 
 % x11vnc -help
 
-x11vnc: allow VNC connections to real X11 displays. 0.8 lastmod: 2006-02-04
+x11vnc: allow VNC connections to real X11 displays. 0.8 lastmod: 2006-02-06
 
 Typical usage is:
 
@@ -5201,6 +5201,18 @@ Options:
                        "poll=t" where "t" is a floating point time.
                        (default: 0.05)
 
+                       Setting the option "level2" will limit the search
+                       for non-default visual windows to two levels from the
+                       root window.  Do this on slow machines where you know
+                       the window manager only imposes one extra window between
+                       the app window and the root window.
+
+                       Also for very slow machines use "cachewin=t"
+                       where t is a floating point amount of time to cache
+                       XGetWindowAttributes results.  E.g. cachewin=5.0.
+                       This may lead to the windows being unnoticed for this
+                       amount of time when deiconifying, painting errors, etc.
+
                        Debugging for this mode can be enabled by setting
                        "dbg=1", "dbg=2", or "dbg=3".
 
diff --git a/x11vnc/help.c b/x11vnc/help.c
index 3a558cd..692276a 100644
--- a/x11vnc/help.c
+++ b/x11vnc/help.c
@@ -209,6 +209,18 @@ void print_help(int mode) {
 "                       \"poll=t\" where \"t\" is a floating point time.\n"
 "                       (default: %.2f)\n"
 "\n"
+"                       Setting the option \"level2\" will limit the search\n"
+"                       for non-default visual windows to two levels from the\n"
+"                       root window.  Do this on slow machines where you know\n"
+"                       the window manager only imposes one extra window between\n"
+"                       the app window and the root window.\n"
+"\n"
+"                       Also for very slow machines use \"cachewin=t\"\n"
+"                       where t is a floating point amount of time to cache\n"
+"                       XGetWindowAttributes results.  E.g. cachewin=5.0.\n"
+"                       This may lead to the windows being unnoticed for this\n"
+"                       amount of time when deiconifying, painting errors, etc.\n"
+"\n"
 "                       Debugging for this mode can be enabled by setting \n"
 "                       \"dbg=1\", \"dbg=2\", or \"dbg=3\".\n"
 "\n"
diff --git a/x11vnc/win_utils.c b/x11vnc/win_utils.c
index 327daae..aad1362 100644
--- a/x11vnc/win_utils.c
+++ b/x11vnc/win_utils.c
@@ -25,15 +25,25 @@ Window descend_pointer(int depth, Window start, char *name_info, int len);
 Window parent_window(Window win, char **name) {
 	Window r, parent;
 	Window *list;
+	XErrorHandler old_handler;
 	unsigned int nchild;
+	int rc;
 
 	if (name != NULL) {
 		*name = NULL;
 	}
 
-	if (! XQueryTree(dpy, win, &r, &parent, &list, &nchild)) {
+	old_handler = XSetErrorHandler(trap_xerror);
+	trapped_xerror = 0;
+	rc = XQueryTree(dpy, win, &r, &parent, &list, &nchild);
+	XSetErrorHandler(old_handler);
+
+	if (! rc || trapped_xerror) {
+		trapped_xerror = 0;
 		return None;
 	}
+	trapped_xerror = 0;
+
 	if (list) {
 		XFree(list);
 	}
@@ -59,8 +69,8 @@ int valid_window(Window win, XWindowAttributes *attr_ret, int bequiet) {
 		return 0;
 	}
 
-	trapped_xerror = 0;
 	old_handler = XSetErrorHandler(trap_xerror);
+	trapped_xerror = 0;
 	if (XGetWindowAttributes(dpy, win, pattr)) {
 		ok = 1;
 	}
@@ -148,6 +158,7 @@ void snapshot_stack_list(int free_only, double allowed_age) {
 	last_free = now;
 
 	X_LOCK;
+	/* no need to trap error since rootwin */
 	rc = XQueryTree(dpy, rootwin, &r, &w, &list, &ui);
 	num = (int) ui;
 
diff --git a/x11vnc/x11vnc.1 b/x11vnc/x11vnc.1
index fb99e80..ca48b79 100644
--- a/x11vnc/x11vnc.1
+++ b/x11vnc/x11vnc.1
@@ -2,7 +2,7 @@
 .TH X11VNC "1" "February 2006" "x11vnc " "User Commands"
 .SH NAME
 x11vnc - allow VNC connections to real X11 displays
-         version: 0.8, lastmod: 2006-02-04
+         version: 0.8, lastmod: 2006-02-06
 .SH SYNOPSIS
 .B x11vnc
 [OPTION]...
@@ -241,6 +241,18 @@ non-default visual regions for changes, use the option
 "poll=t" where "t" is a floating point time.
 (default: 0.05)
 .IP
+Setting the option "level2" will limit the search
+for non-default visual windows to two levels from the
+root window.  Do this on slow machines where you know
+the window manager only imposes one extra window between
+the app window and the root window.
+.IP
+Also for very slow machines use "cachewin=t"
+where t is a floating point amount of time to cache
+XGetWindowAttributes results.  E.g. cachewin=5.0.
+This may lead to the windows being unnoticed for this
+amount of time when deiconifying, painting errors, etc.
+.IP
 Debugging for this mode can be enabled by setting
 "dbg=1", "dbg=2", or "dbg=3".
 .PP
diff --git a/x11vnc/x11vnc_defs.c b/x11vnc/x11vnc_defs.c
index d4bc860..a73b8e0 100644
--- a/x11vnc/x11vnc_defs.c
+++ b/x11vnc/x11vnc_defs.c
@@ -15,7 +15,7 @@ int xtrap_base_event_type = 0;
 int xdamage_base_event_type = 0;
 
 /*               date +'lastmod: %Y-%m-%d' */
-char lastmod[] = "0.8 lastmod: 2006-02-04";
+char lastmod[] = "0.8 lastmod: 2006-02-06";
 
 /* X display info */
 
-- 
cgit v1.2.3

