Home | History | Annotate | Download | only in x11vnc
      1 /*
      2    Copyright (C) 2002-2010 Karl J. Runge <runge (at) karlrunge.com>
      3    All rights reserved.
      4 
      5 This file is part of x11vnc.
      6 
      7 x11vnc is free software; you can redistribute it and/or modify
      8 it under the terms of the GNU General Public License as published by
      9 the Free Software Foundation; either version 2 of the License, or (at
     10 your option) any later version.
     11 
     12 x11vnc is distributed in the hope that it will be useful,
     13 but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 GNU General Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with x11vnc; if not, write to the Free Software
     19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
     20 or see <http://www.gnu.org/licenses/>.
     21 
     22 In addition, as a special exception, Karl J. Runge
     23 gives permission to link the code of its release of x11vnc with the
     24 OpenSSL project's "OpenSSL" library (or with modified versions of it
     25 that use the same license as the "OpenSSL" library), and distribute
     26 the linked executables.  You must obey the GNU General Public License
     27 in all respects for all of the code used other than "OpenSSL".  If you
     28 modify this file, you may extend this exception to your version of the
     29 file, but you are not obligated to do so.  If you do not wish to do
     30 so, delete this exception statement from your version.
     31 */
     32 
     33 /* -- 8to24.c -- */
     34 #include "x11vnc.h"
     35 #include "cleanup.h"
     36 #include "scan.h"
     37 #include "util.h"
     38 #include "win_utils.h"
     39 #include "xwrappers.h"
     40 
     41 int multivis_count = 0;
     42 int multivis_24count = 0;
     43 
     44 void check_for_multivis(void);
     45 void bpp8to24(int, int, int, int);
     46 void mark_8bpp(int);
     47 
     48 #if SKIP_8TO24
     49 void check_for_multivis(void) {}
     50 void bpp8to24(int x, int y, int z, int t) {}
     51 void mark_8bpp(int x) {}
     52 #else
     53 /* lots... */
     54 
     55 static void set_root_cmap(void);
     56 static int check_pointer_in_depth24(void);
     57 static void parse_cmap8to24(void);
     58 static void set_poll_fb(void);
     59 static int check_depth(Window win, Window top, int doall);
     60 static int check_depth_win(Window win, Window top, XWindowAttributes *attr);
     61 static XImage *p_xi(XImage *xi, Visual *visual, int win_depth, int *w);
     62 static int poll_line(int x1, int x2, int y1, int n, sraRegionPtr mod);
     63 static void poll_line_complement(int x1, int x2, int y1, sraRegionPtr mod);
     64 static int poll_8bpp(sraRegionPtr, int);
     65 static void poll_8bpp_complement(sraRegionPtr);
     66 static void mark_rgn_rects(sraRegionPtr mod);
     67 static int get_8bpp_regions(int validate);
     68 static int get_cmap(int j, Colormap cmap);
     69 static void do_8bpp_region(int n, sraRegionPtr mark);
     70 static XImage *cmap_xi(XImage *xi, Window win, int win_depth);
     71 static void transform_rect(sraRect rect, Window win, int win_depth, int cm);
     72 
     73 /* struct for keeping info about the 8bpp windows: */
     74 typedef struct window8 {
     75 	Window win;
     76 	Window top;
     77 	int depth;
     78 	int x, y;
     79 	int w, h;
     80 	int map_state;
     81 	Colormap cmap;
     82 	Bool map_installed;
     83 	int fetched;
     84 	double last_fetched;
     85 	sraRegionPtr clip_region;
     86 } window8bpp_t;
     87 
     88 enum mark_8bpp_modes {
     89 	MARK_8BPP_ALL = 0,
     90 	MARK_8BPP_POINTER,
     91 	MARK_8BPP_TOP
     92 };
     93 
     94 
     95 #define NCOLOR 256
     96 
     97 static Colormap root_cmap = 0;
     98 static unsigned int *root_rgb = NULL;
     99 
    100 static void set_root_cmap(void) {
    101 #if NO_X11
    102 	RAWFB_RET_VOID
    103 	return;
    104 #else
    105 	static time_t last_set = 0;
    106 	time_t now = time(NULL);
    107 	XWindowAttributes attr;
    108 	static XColor *color = NULL;
    109 	int redo = 0;
    110 	int ncolor = 0;
    111 
    112 	RAWFB_RET_VOID
    113 
    114 	if (depth > 16) {
    115 		ncolor = NCOLOR;
    116 	} else if (depth > 8) {
    117 		ncolor = 1 << depth;
    118 	} else {
    119 		ncolor = NCOLOR;
    120 	}
    121 
    122 	if (!root_rgb) {
    123 		root_rgb = (unsigned int *) malloc(ncolor * sizeof(unsigned int));
    124 	}
    125 	if (!color) {
    126 		color = (XColor *) malloc(ncolor * sizeof(XColor));
    127 	}
    128 
    129 	if (now > last_set + 10) {
    130 		redo = 1;
    131 	}
    132 	if (! root_cmap || redo) {
    133 		X_LOCK;
    134 		if (! valid_window(window, &attr, 1)) {
    135 			X_UNLOCK;
    136 			return;
    137 		}
    138 		if (attr.colormap) {
    139 			int i, ncells = ncolor;
    140 
    141 			if (depth < 8) {
    142 				ncells = CellsOfScreen(ScreenOfDisplay(dpy, scr));
    143 			}
    144 			for (i=0; i < ncells; i++) {
    145 				color[i].pixel = i;
    146 				color[i].pad = 0;
    147 			}
    148 			last_set = now;
    149 			root_cmap = attr.colormap;
    150 			XQueryColors(dpy, root_cmap, color, ncells);
    151 			for (i=0; i < ncells; i++) {
    152 				unsigned int red, green, blue;
    153 				/* strip out highest 8 bits of values: */
    154 				red   = (color[i].red   & 0xff00) >> 8;
    155 				green = (color[i].green & 0xff00) >> 8;
    156 				blue  = (color[i].blue  & 0xff00) >> 8;
    157 
    158 				/*
    159 				 * the maxes should be at 255 already,
    160 				 * but just in case...
    161 				 */
    162 				red   = (main_red_max   * red  )/255;
    163 				green = (main_green_max * green)/255;
    164 				blue  = (main_blue_max  * blue )/255;
    165 
    166 				/* shift them over and or together for value */
    167 				red   = red    << main_red_shift;
    168 				green = green  << main_green_shift;
    169 				blue  = blue   << main_blue_shift;
    170 
    171 				/* store it in the array to be used later */
    172 				root_rgb[i] = red | green | blue;
    173 			}
    174 		}
    175 		X_UNLOCK;
    176 	}
    177 #endif	/* NO_X11 */
    178 }
    179 
    180 /* fixed size array.  Will primarily hold visible 8bpp windows */
    181 #define MAX_8BPP_WINDOWS 64
    182 static window8bpp_t windows_8bpp[MAX_8BPP_WINDOWS];
    183 
    184 static int db24 = 0;
    185 static int xgetimage_8to24 = 1;
    186 static double poll_8to24_delay = POLL_8TO24_DELAY;
    187 static double cache_win = 0.0;
    188 static int level2_8to24 = 0;
    189 
    190 static int check_pointer_in_depth24(void) {
    191 	int tries = 0, in_24 = 0;
    192 	XWindowAttributes attr;
    193 	Window c, w;
    194 	double now = dnow();
    195 
    196 	c = window;
    197 
    198 	RAWFB_RET(0)
    199 
    200 	if (now > last_keyboard_time + 1.0 && now > last_pointer_time + 1.0) {
    201 		return 0;
    202 	}
    203 
    204 	X_LOCK;
    205 	while (c && tries++ < 3) {
    206 		c = query_pointer(c);
    207 		if (valid_window(c, &attr, 1)) 	{
    208 			if (attr.depth == 24) {
    209 				in_24 = 1;
    210 				break;
    211 			}
    212 		}
    213 	}
    214 	X_UNLOCK;
    215 	if (in_24) {
    216 		int x1, y1, x2, y2;
    217 		X_LOCK;
    218 		xtranslate(c, window, 0, 0, &x1, &y1, &w, 1);
    219 		X_UNLOCK;
    220 		x2 = x1 + attr.width;
    221 		y2 = y1 + attr.height;
    222 		x1 = nfix(x1, dpy_x);
    223 		y1 = nfix(y1, dpy_y);
    224 		x2 = nfix(x2, dpy_x+1);
    225 		y2 = nfix(y2, dpy_y+1);
    226 		mark_rect_as_modified(x1, y1, x2, y2, 0);
    227 
    228 if (db24 > 1) fprintf(stderr, "check_pointer_in_depth24 %d %d %d %d\n", x1, y1, x2, y2);
    229 
    230 		return 1;
    231 	}
    232 	return 0;
    233 }
    234 
    235 static void parse_cmap8to24(void) {
    236 	if (cmap8to24_str) {
    237 		char *p, *str = strdup(cmap8to24_str);
    238 		p = strtok(str, ",");
    239 		/* defaults: */
    240 		db24 = 0;
    241 		xgetimage_8to24 = 1;
    242 		poll_8to24_delay = POLL_8TO24_DELAY;
    243 		level2_8to24 = 0;
    244 		cache_win = 0.0;
    245 		while (p) {
    246 			if (strstr(p, "dbg=") == p) {
    247 				db24 = atoi(p + strlen("dbg="));
    248 			} else if (strstr(p, "poll=") == p) {
    249 				poll_8to24_delay = atof(p + strlen("poll="));
    250 			} else if (strstr(p, "cachewin=") == p) {
    251 				cache_win = atof(p + strlen("cachewin="));
    252 			} else if (!strcmp(p, "nogetimage")) {
    253 				xgetimage_8to24 = 0;
    254 			} else if (!strcmp(p, "level2")) {
    255 				level2_8to24 = 1;
    256 			}
    257 			p = strtok(NULL, ",");
    258 		}
    259 		free(str);
    260 	} else {
    261 		if (getenv("DEBUG_8TO24") != NULL) {
    262 			db24 = atoi(getenv("DEBUG_8TO24"));
    263 		}
    264 		if (getenv("NOXGETIMAGE_8TO24") != NULL) {
    265 			xgetimage_8to24 = 0;
    266 		}
    267 	}
    268 }
    269 
    270 static char *poll8_fb = NULL, *poll24_fb = NULL;
    271 static int poll8_fb_w = 0, poll8_fb_h = 0;
    272 static int poll24_fb_w = 0, poll24_fb_h = 0;
    273 
    274 static void pfb(int fac, char **fb, int *w, int *h)  {
    275 	if (! *fb || *w != dpy_x || *h != dpy_y) {
    276 		if (*fb) {
    277 			free(*fb);
    278 		}
    279 		*fb = (char *) calloc(fac * dpy_x * dpy_y, 1);
    280 		*w = dpy_x;
    281 		*h = dpy_y;
    282 	}
    283 }
    284 
    285 static void set_poll_fb(void) {
    286 	/* create polling framebuffers or recreate if too small. */
    287 
    288 	if (! xgetimage_8to24) {
    289 		return;		/* this saves a bit of RAM */
    290 	}
    291 	pfb(4, &poll24_fb, &poll24_fb_w, &poll24_fb_h);
    292 	if (depth > 8 && depth <= 16) {
    293 		pfb(2, &poll8_fb,  &poll8_fb_w,  &poll8_fb_h);	/* 2X for rare 16bpp colormap case */
    294 	} else {
    295 		pfb(1, &poll8_fb,  &poll8_fb_w,  &poll8_fb_h);
    296 	}
    297 }
    298 
    299 int MV_glob = 0;
    300 int MV_count;
    301 int MV_hit;
    302 double MV_start;
    303 
    304 void check_for_multivis(void) {
    305 #if NO_X11
    306 	RAWFB_RET_VOID
    307 	return;
    308 #else
    309 	XWindowAttributes attr;
    310 	int doall = 0;
    311 	int k, i, cnt, diff;
    312 	static int first = 1;
    313 	static Window *stack_old = NULL;
    314 	static int stack_old_len = 0;
    315 	static double last_parse = 0.0;
    316 	static double last_update = 0.0;
    317 	static double last_clear = 0.0;
    318 	static double last_poll = 0.0;
    319 	static double last_fixup = 0.0;
    320 	static double last_call = 0.0;
    321 	static double last_query = 0.0;
    322 	double now = dnow();
    323 	double delay;
    324 
    325 	RAWFB_RET_VOID
    326 
    327 	if (now > last_parse + 1.0) {
    328 		last_parse = now;
    329 		parse_cmap8to24();
    330 	}
    331 if (db24 > 2) fprintf(stderr, " check_for_multivis: %.4f\n", now - last_call);
    332 	last_call = now;
    333 
    334 	if (first) {
    335 		int i;
    336 		/* initialize 8bpp window table: */
    337 		for (i=0; i < MAX_8BPP_WINDOWS; i++) 	{
    338 			windows_8bpp[i].win = None;
    339 			windows_8bpp[i].top = None;
    340 			windows_8bpp[i].map_state = IsUnmapped;
    341 			windows_8bpp[i].cmap = (Colormap) 0;
    342 			windows_8bpp[i].fetched = 0;
    343 			windows_8bpp[i].last_fetched = -1.0;
    344 			windows_8bpp[i].clip_region = NULL;
    345 		}
    346 		set_poll_fb();
    347 
    348 		first = 0;
    349 		doall = 1;	/* fetch everything first time */
    350 	}
    351 
    352 	if (wireframe_in_progress) {
    353 		return;
    354 	}
    355 
    356 	set_root_cmap();
    357 
    358 	/*
    359 	 * allocate an "old stack" list of all toplevels.  we compare
    360 	 * this to the current stack to guess stacking order changes.
    361 	 */
    362 	if (!stack_old || stack_old_len < stack_list_len) {
    363 		int n = stack_list_len;
    364 		if (n < 256) {
    365 			n = 256;
    366 		}
    367 		if (stack_old) {
    368 			free(stack_old);
    369 		}
    370 		stack_old = (Window *) calloc(n*sizeof(Window), 1);
    371 		stack_old_len = n;
    372 	}
    373 
    374 	/* fill the old stack with visible windows: */
    375 	cnt = 0;
    376 	for (k=0; k < stack_list_num; k++) {
    377 		if (stack_list[k].valid &&
    378 		    stack_list[k].map_state == IsViewable) {
    379 			stack_old[cnt++] = stack_list[k].win;
    380 		}
    381 	}
    382 
    383 	/* snapshot + update the current stacking order: */
    384 	/* TUNABLE */
    385 	if (poll_8to24_delay >= POLL_8TO24_DELAY) {
    386 		delay = 3.0 * poll_8to24_delay;
    387 	} else {
    388 		delay = 3.0 * POLL_8TO24_DELAY;	/* 0.15 */
    389 	}
    390 	if (doall || now > last_update + delay) {
    391 		snapshot_stack_list(0, 0.0);
    392 		update_stack_list();
    393 		last_update = now;
    394 	}
    395 
    396 	/* look for differences in the visible toplevels: */
    397 	diff = 0;
    398 	cnt = 0;
    399 	for (k=0; k < stack_list_num; k++) {
    400 		if (stack_list[k].valid && stack_list[k].map_state ==
    401 		    IsViewable) {
    402 			if (stack_old[cnt] != stack_list[k].win) {
    403 				diff = 1;
    404 				break;
    405 			}
    406 			cnt++;
    407 		}
    408 	}
    409 
    410 	multivis_count = 0;
    411 	multivis_24count = 0;
    412 
    413 	/*
    414 	 * every 10 seconds we try to clean out and also refresh the window
    415 	 * info in the 8bpp window table:
    416 	 */
    417 	if (now > last_clear + 10) {
    418 		last_clear = now;
    419 		X_LOCK;
    420 		for (i=0; i < MAX_8BPP_WINDOWS; i++) {
    421 			Window w = windows_8bpp[i].win;
    422 			if (! valid_window(w, &attr, 1)) {
    423 				/* catch windows that went away: */
    424 				windows_8bpp[i].win = None;
    425 				windows_8bpp[i].top = None;
    426 				windows_8bpp[i].map_state = IsUnmapped;
    427 				windows_8bpp[i].cmap = (Colormap) 0;
    428 				windows_8bpp[i].fetched = 0;
    429 				windows_8bpp[i].last_fetched = -1.0;
    430 			}
    431 		}
    432 		X_UNLOCK;
    433 	}
    434 
    435 	MV_count = 0;
    436 	MV_hit = 0;
    437 	MV_start = dnow();
    438 
    439 	set_root_cmap();
    440 
    441 	/* loop over all toplevels, both 8 and 24 depths: */
    442 
    443 	X_LOCK;	/* a giant lock around the whole activity */
    444 
    445 	for (k=0; k < stack_list_num; k++) {
    446 		Window r, parent;
    447 		Window *list0;
    448 		Status rc;
    449 		unsigned int nc0;
    450 		int i1;
    451 		XErrorHandler old_handler;
    452 		double delay;
    453 
    454 		Window win = stack_list[k].win;
    455 
    456 		/* TUNABLE */
    457 		if (poll_8to24_delay >= POLL_8TO24_DELAY) {
    458 			delay = 1.5 * poll_8to24_delay;
    459 		} else {
    460 			delay = 1.5 * POLL_8TO24_DELAY;	/* 0.075 */
    461 		}
    462 
    463 		if (now < last_query + delay) {
    464 			break;
    465 		}
    466 
    467 		if (win == None) {
    468 			continue;
    469 		}
    470 
    471 		if (stack_list[k].map_state != IsViewable) {
    472 			int i;
    473 			/*
    474 			 * if the toplevel became unmapped, mark it
    475 			 * for the children as well...
    476 			 */
    477 			for (i=0; i < MAX_8BPP_WINDOWS; i++) {
    478 				if (windows_8bpp[i].top == win) {
    479 					windows_8bpp[i].map_state =
    480 					    stack_list[k].map_state;
    481 				}
    482 			}
    483 		}
    484 
    485 		if (check_depth(win, win, doall)) {
    486 			/*
    487 			 * returns 1 if no need to recurse down e.g. It
    488 			 * is 8bpp and we assume all lower ones are too.
    489 			 */
    490 			continue;
    491 		}
    492 
    493 		/* we recurse up to two levels down from stack_list windows */
    494 
    495 		old_handler = XSetErrorHandler(trap_xerror);
    496 		trapped_xerror = 0;
    497 		rc = XQueryTree_wr(dpy, win, &r, &parent, &list0, &nc0);
    498 		XSetErrorHandler(old_handler);
    499 
    500 		if (! rc || trapped_xerror) {
    501 			trapped_xerror = 0;
    502 			continue;
    503 		}
    504 		trapped_xerror = 0;
    505 
    506 		/* loop over grandchildren of rootwin: */
    507 		for (i1=0; i1 < (int) nc0; i1++) {
    508 			Window win1 = list0[i1];
    509 			Window *list1;
    510 			unsigned int nc1;
    511 			int i2;
    512 
    513 			if (check_depth(win1, win, doall)) {
    514 				continue;
    515 			}
    516 
    517 			if (level2_8to24) {
    518 				continue;
    519 			}
    520 
    521 			old_handler = XSetErrorHandler(trap_xerror);
    522 			trapped_xerror = 0;
    523 			rc = XQueryTree_wr(dpy, win1, &r, &parent, &list1, &nc1);
    524 			XSetErrorHandler(old_handler);
    525 
    526 			if (! rc || trapped_xerror) {
    527 				trapped_xerror = 0;
    528 				continue;
    529 			}
    530 			trapped_xerror = 0;
    531 
    532 			/* loop over great-grandchildren of rootwin: */
    533 			for (i2=0; i2< (int) nc1; i2++) {
    534 				Window win2 = list1[i2];
    535 
    536 				if (check_depth(win2, win, doall)) {
    537 					continue;
    538 				}
    539 				/* more? Which wm does this? */
    540 			}
    541 			if (nc1) {
    542 				XFree_wr(list1);
    543 			}
    544 		}
    545 		if (nc0) {
    546 			XFree_wr(list0);
    547 		}
    548 	}
    549 	X_UNLOCK;
    550 
    551 	last_query = dnow();
    552 
    553 MV_glob += MV_count;
    554 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));
    555 
    556 	if (screen_fixup_8 > 0.0 && now > last_fixup + screen_fixup_8) {
    557 		last_fixup = now;
    558 		mark_8bpp(MARK_8BPP_ALL);
    559 		last_poll = now;
    560 
    561 	} else if (poll_8to24_delay > 0.0) {
    562 		int area = -1;
    563 		int validate = 0;
    564 
    565 		if (diff && multivis_count) {
    566 			validate = 1;
    567 		}
    568 		if (now > last_poll + poll_8to24_delay) {
    569 			sraRegionPtr mod;
    570 
    571 			last_poll = now;
    572 			mod = sraRgnCreate();
    573 			area = poll_8bpp(mod, validate);
    574 			if (depth == 24) {
    575 				poll_8bpp_complement(mod);
    576 			}
    577 			mark_rgn_rects(mod);
    578 			sraRgnDestroy(mod);
    579 		}
    580 		if (0 && area < dpy_x * dpy_y / 2 && diff && multivis_count) {
    581 			mark_8bpp(MARK_8BPP_POINTER);
    582 			last_poll = now;
    583 		}
    584 
    585 	} else if (diff && multivis_count) {
    586 		mark_8bpp(MARK_8BPP_ALL);
    587 		last_poll = now;
    588 
    589 	} else if (depth <= 16 && multivis_24count) {
    590 		static double last_check = 0.0;
    591 		if (now > last_check + 0.4) {
    592 			last_check = now;
    593 			if (check_pointer_in_depth24()) {
    594 				last_poll = now;
    595 			}
    596 		}
    597 	}
    598 if (0) fprintf(stderr, "done: %.4f\n", dnow() - last_query);
    599 #endif	/* NO_X11 */
    600 }
    601 
    602 #define VW_CACHE_MAX 1024
    603 static XWindowAttributes vw_cache_attr[VW_CACHE_MAX];
    604 static Window vw_cache_win[VW_CACHE_MAX];
    605 
    606 static void set_attr(XWindowAttributes *attr, int j) {
    607 	memcpy((void *) (vw_cache_attr+j), (void *) attr,
    608 	    sizeof(XWindowAttributes));
    609 }
    610 #if 0
    611 static int get_attr(XWindowAttributes *attr, int j) {
    612 	memcpy((void *) attr, (void *) (vw_cache_attr+j),
    613 	    sizeof(XWindowAttributes));
    614 	return 1;
    615 }
    616 #endif
    617 
    618 static XWindowAttributes wattr;
    619 
    620 static XWindowAttributes *vw_lookup(Window win) {
    621 	static double last_purge = 0.0;
    622 	double now;
    623 	int i, j, k;
    624 
    625 	if (win == None) {
    626 		return NULL;
    627 	}
    628 
    629 	now = dnow();
    630 	if (now > last_purge + cache_win) {
    631 		last_purge = now;
    632 		for (i=0; i<VW_CACHE_MAX; i++) {
    633 			vw_cache_win[i] = None;
    634 		}
    635 	}
    636 
    637 	j = -1;
    638 	k = -1;
    639 	for (i=0; i<VW_CACHE_MAX; i++) {
    640 		if (vw_cache_win[i] == win) {
    641 			j = i;
    642 			break;
    643 		} else if (vw_cache_win[i] == None) {
    644 			k = i;
    645 			break;
    646 		}
    647 	}
    648 
    649 	if (j >= 0) {
    650 MV_hit++;
    651 		return vw_cache_attr+j;
    652 
    653 	} else if (k >= 0) {
    654 		XWindowAttributes attr2;
    655 		int rc = valid_window(win, &attr2, 1);
    656 		if (rc) {
    657 			vw_cache_win[k] = win;
    658 			set_attr(&attr2, k);
    659 			return vw_cache_attr+k;
    660 		} else {
    661 			return NULL;
    662 		}
    663 	} else {
    664 		/* Full */
    665 		int rc = valid_window(win, &wattr, 1);
    666 		if (rc) {
    667 			return &wattr;
    668 		} else {
    669 			return NULL;
    670 		}
    671 	}
    672 }
    673 
    674 static int check_depth(Window win, Window top, int doall) {
    675 	XWindowAttributes attr, *pattr;
    676 
    677 	/* first see if it is (still) a valid window: */
    678 MV_count++;
    679 
    680 	if (cache_win > 0.0) {
    681 		pattr = vw_lookup(win);
    682 		if (pattr == NULL) {
    683 			return 1;	/* indicate done */
    684 		}
    685 	} else {
    686 		if (! valid_window(win, &attr, 1)) {
    687 			return 1;	/* indicate done */
    688 		}
    689 		pattr = &attr;
    690 	}
    691 
    692 	if (! doall && pattr->map_state != IsViewable) {
    693 		/*
    694 		 * store results anyway...  this may lead to table
    695 		 * filling up, but currently this allows us to update
    696 		 * state of onetime mapped windows.
    697 		 */
    698 		check_depth_win(win, top, pattr);
    699 		return 1;	/* indicate done */
    700 	} else if (check_depth_win(win, top, pattr)) {
    701 		return 1;	/* indicate done */
    702 	} else {
    703 		return 0;	/* indicate not done */
    704 	}
    705 }
    706 
    707 static int check_depth_win(Window win, Window top, XWindowAttributes *attr) {
    708 	int store_it = 0;
    709 	/*
    710 	 * only store windows with depth not equal to the default visual's
    711 	 * depth note some windows can have depth == 0 ... (skip them).
    712 	 */
    713 	if (attr->depth > 0) {
    714 		if (depth == 24 && attr->depth != 24) {
    715 			store_it = 1;
    716 		} else if (depth <= 16 && root_cmap && attr->colormap != root_cmap) {
    717 			store_it = 1;
    718 		}
    719 	}
    720 
    721 	if (store_it) {
    722 		int i, j = -1, none = -1, nomap = -1;
    723 		int newc = 0;
    724 		if (attr->map_state == IsViewable) {
    725 			/* count the visible ones: */
    726 			multivis_count++;
    727 			if (attr->depth == 24) {
    728 				multivis_24count++;
    729 			}
    730 if (db24 > 1) fprintf(stderr, "multivis: 0x%lx %d\n", win, attr->depth);
    731 		}
    732 
    733 		/* try to find a table slot for this window: */
    734 		for (i=0; i < MAX_8BPP_WINDOWS; i++) {
    735 			if (none < 0 && windows_8bpp[i].win == None) {
    736 				/* found first None */
    737 				none = i;
    738 			}
    739 			if (windows_8bpp[i].win == win) {
    740 				/* found myself */
    741 				j = i;
    742 				break;
    743 			}
    744 			if (nomap < 0 && windows_8bpp[i].win != None &&
    745 			    windows_8bpp[i].map_state != IsViewable) {
    746 				/* found first unmapped */
    747 				nomap = i;
    748 			}
    749 		}
    750 		if (j < 0) {
    751 			if (attr->map_state != IsViewable) {
    752 				/* no slot and not visible: not worth keeping */
    753 				return 1;
    754 			} else if (none >= 0) {
    755 				/* put it in the first None slot */
    756 				j = none;
    757 				newc = 1;
    758 			} else if (nomap >=0) {
    759 				/* put it in the first unmapped slot */
    760 				j = nomap;
    761 			}
    762 			/* otherwise we cannot store it... */
    763 		}
    764 
    765 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);
    766 
    767 		/* store if if we found a slot j: */
    768 		if (j >= 0) {
    769 			Window w;
    770 			int x, y;
    771 			int now_vis = 0;
    772 
    773 			if (attr->map_state == IsViewable &&
    774 			    windows_8bpp[j].map_state != IsViewable) {
    775 				now_vis = 1;
    776 			}
    777 if (db24 > 1) fprintf(stderr, "multivis: STORE 0x%lx j: %3d ms: %d dep=%d\n", win, j, attr->map_state, attr->depth);
    778 			windows_8bpp[j].win = win;
    779 			windows_8bpp[j].top = top;
    780 			windows_8bpp[j].depth = attr->depth;
    781 			windows_8bpp[j].map_state = attr->map_state;
    782 			windows_8bpp[j].cmap = attr->colormap;
    783 			windows_8bpp[j].map_installed = attr->map_installed;
    784 			windows_8bpp[j].w = attr->width;
    785 			windows_8bpp[j].h = attr->height;
    786 			windows_8bpp[j].fetched = 1;
    787 			windows_8bpp[j].last_fetched = dnow();
    788 
    789 			/* translate x y to be WRT the root window (not parent) */
    790 			xtranslate(win, window, 0, 0, &x, &y, &w, 1);
    791 			windows_8bpp[j].x = x;
    792 			windows_8bpp[j].y = y;
    793 
    794 			if (newc || now_vis) {
    795 if (db24) fprintf(stderr, "new/now_vis: 0x%lx %d/%d\n", win, newc, now_vis);
    796 				/* mark it immediately if a new one: */
    797 				X_UNLOCK;	/* dont forget the giant lock */
    798 				mark_rect_as_modified(x, y, x + attr->width,
    799 				    y + attr->height, 0);
    800 				X_LOCK;
    801 			}
    802 		} else {
    803 			/*
    804 			 * Error: could not find a slot.
    805 			 * perhaps keep age and expire old ones??
    806 			 */
    807 if (db24) fprintf(stderr, "multivis: CANNOT STORE 0x%lx j=%d\n", win, j);
    808 			for (i=0; i < MAX_8BPP_WINDOWS; i++) {
    809 if (db24 > 1) fprintf(stderr, "          ------------ 0x%lx i=%d\n", windows_8bpp[i].win, i);
    810 			}
    811 
    812 		}
    813 		return 1;
    814 	}
    815 	return 0;
    816 }
    817 
    818 /* polling line XImage */
    819 static XImage *p_xi(XImage *xi, Visual *visual, int win_depth, int *w) {
    820 	RAWFB_RET(NULL)
    821 
    822 #if NO_X11
    823 	if (!xi || !visual || !win_depth || !w) {}
    824 	return NULL;
    825 #else
    826 	if (xi == NULL || *w < dpy_x) {
    827 		char *d;
    828 		if (xi) {
    829 			XDestroyImage(xi);
    830 		}
    831 		if (win_depth != 24) {
    832 			if (win_depth > 8) {
    833 				d = (char *) malloc(dpy_x * 2);
    834 			} else {
    835 				d = (char *) malloc(dpy_x * 1);
    836 			}
    837 		} else {
    838 			d = (char *) malloc(dpy_x * 4);
    839 		}
    840 		*w = dpy_x;
    841 		xi = XCreateImage(dpy, visual, win_depth, ZPixmap, 0, d,
    842 		    dpy_x, 1, 8, 0);
    843 	}
    844 	return xi;
    845 #endif	/* NO_X11 */
    846 }
    847 
    848 static int poll_line(int x1, int x2, int y1, int n, sraRegionPtr mod) {
    849 #if NO_X11
    850 	RAWFB_RET(1)
    851 	if (!x1 || !x2 || !y1 || !n || !mod) {}
    852 	return 1;
    853 #else
    854 	int fac, n_off, w, xo, yo;
    855 	char *poll_fb, *dst, *src;
    856 	int w2, xl, xh, stride = 32;
    857 	int inrun = 0, rx1 = -1, rx2 = -1;
    858 
    859 	static XImage *xi8 = NULL, *xi24 = NULL, *xi_r;
    860 	static int xi8_w = 0, xi24_w = 0;
    861 
    862 	XErrorHandler old_handler = NULL;
    863 	XImage *xi;
    864 	Window c, win = windows_8bpp[n].win;
    865 
    866 	static XWindowAttributes attr;
    867 	static Window last_win = None;
    868 	static double last_time = 0.0;
    869 	double now;
    870 
    871 	sraRegionPtr rect;
    872 	int mx1, mx2, my1, my2;
    873 	int ns = NSCAN/2;
    874 
    875 	RAWFB_RET(1)
    876 
    877 	if (win == None) {
    878 		return 1;
    879 	}
    880 	if (windows_8bpp[n].map_state != IsViewable) {
    881 		return 1;
    882 	}
    883 	if (! xgetimage_8to24) {
    884 		return 1;
    885 	}
    886 
    887 	X_LOCK;
    888 	now = dnow();
    889 	if (last_win != None && win == last_win && now < last_time + 0.5) {
    890 		;	/* use previous attr */
    891 	} else {
    892 		if (! valid_window(win, &attr, 1)) {
    893 			X_UNLOCK;
    894 			last_win = None;
    895 			return 0;
    896 		}
    897 		last_time = now;
    898 		last_win = win;
    899 	}
    900 
    901 	if (attr.depth > 16 && attr.depth != 24) {
    902 		X_UNLOCK;
    903 		return 1;
    904 	} else if (attr.depth <= 16) {
    905 		xi = xi8 = p_xi(xi8, attr.visual, attr.depth, &xi8_w);
    906 
    907 		poll_fb = poll8_fb;
    908 		if (attr.depth > 8) {
    909 			fac = 2;
    910 		} else {
    911 			fac = 1;
    912 		}
    913 		n_off = poll8_fb_w * y1 + x1;
    914 	} else {
    915 		xi = xi24 = p_xi(xi24, attr.visual, 24, &xi24_w);
    916 
    917 		poll_fb = poll24_fb;
    918 		fac = 4;
    919 		n_off = poll24_fb_w * y1 + x1;
    920 	}
    921 
    922 	old_handler = XSetErrorHandler(trap_xerror);
    923 	trapped_xerror = 0;
    924 
    925 	/* xtranslate() not used to save two XSetErrorHandler calls */
    926 	XTranslateCoordinates(dpy, win, window, 0, 0, &xo, &yo, &c);
    927 
    928 	xo = x1 - xo;
    929 	yo = y1 - yo;
    930 	w = x2 - x1;
    931 
    932 	if (trapped_xerror || xo < 0 || yo < 0 || xo + w > attr.width) {
    933 if (db24 > 2) fprintf(stderr, "avoid bad match...\n");
    934 		XSetErrorHandler(old_handler);
    935 		trapped_xerror = 0;
    936 		X_UNLOCK;
    937 		return 0;
    938 	}
    939 
    940 	trapped_xerror = 0;
    941 	xi_r = XGetSubImage(dpy, win, xo, yo, w, 1, AllPlanes, ZPixmap, xi,
    942 	    0, 0);
    943 	XSetErrorHandler(old_handler);
    944 
    945 	X_UNLOCK;
    946 
    947 	if (! xi_r || trapped_xerror) {
    948 		trapped_xerror = 0;
    949 		return 0;
    950 	}
    951 	trapped_xerror = 0;
    952 
    953 	src = xi->data;
    954 	dst = poll_fb + fac * n_off;
    955 
    956 	inrun = 0;
    957 
    958 	xl = x1;
    959 	while (xl < x2) {
    960 		xh = xl + stride;
    961 		if (xh > x2) {
    962 			xh = x2;
    963 		}
    964 		w2 = xh - xl;
    965 		if (memcmp(dst, src, fac * w2)) {
    966 			if (inrun) {
    967 				rx2 = xh;
    968 			} else {
    969 				rx1 = xl;
    970 				rx2 = xh;
    971 				inrun = 1;
    972 			}
    973 		} else {
    974 			if (inrun) {
    975 				mx1 = rx1;
    976 				mx2 = rx2;
    977 				my1 = nfix(y1 - ns, dpy_y);
    978 				my2 = nfix(y1 + ns, dpy_y+1);
    979 
    980 				rect = sraRgnCreateRect(mx1, my1, mx2, my2);
    981 				sraRgnOr(mod, rect);
    982 				sraRgnDestroy(rect);
    983 				inrun = 0;
    984 			}
    985 		}
    986 
    987 		xl += stride;
    988 		dst += fac * stride;
    989 		src += fac * stride;
    990 	}
    991 
    992 	if (inrun) {
    993 		mx1 = rx1;
    994 		mx2 = rx2;
    995 		my1 = nfix(y1 - ns, dpy_y);
    996 		my2 = nfix(y1 + ns, dpy_y+1);
    997 
    998 		rect = sraRgnCreateRect(mx1, my1, mx2, my2);
    999 		sraRgnOr(mod, rect);
   1000 		sraRgnDestroy(rect);
   1001 	}
   1002 	return 1;
   1003 #endif	/* NO_X11 */
   1004 }
   1005 
   1006 static void poll_line_complement(int x1, int x2, int y1, sraRegionPtr mod) {
   1007 	int n_off, w, xl, xh, stride = 32;
   1008 	char *dst, *src;
   1009 	int inrun = 0, rx1 = -1, rx2 = -1;
   1010 	sraRegionPtr rect;
   1011 	int mx1, mx2, my1, my2;
   1012 	int ns = NSCAN/2;
   1013 
   1014 	if (depth != 24) {
   1015 		return;
   1016 	}
   1017 	if (! cmap8to24_fb) {
   1018 		return;
   1019 	}
   1020 	if (! xgetimage_8to24) {
   1021 		return;
   1022 	}
   1023 
   1024 	n_off = main_bytes_per_line * y1 + 4 * x1;
   1025 
   1026 	src = main_fb + n_off;
   1027 	dst = cmap8to24_fb + n_off;
   1028 
   1029 	inrun = 0;
   1030 
   1031 	xl = x1;
   1032 	while (xl < x2) {
   1033 		xh = xl + stride;
   1034 		if (xh > x2) {
   1035 			xh = x2;
   1036 		}
   1037 		w = xh - xl;
   1038 		if (memcmp(dst, src, 4 * w)) {
   1039 			if (inrun) {
   1040 				rx2 = xh;
   1041 			} else {
   1042 				rx1 = xl;
   1043 				rx2 = xh;
   1044 				inrun = 1;
   1045 			}
   1046 		} else {
   1047 			if (inrun) {
   1048 				mx1 = rx1;
   1049 				mx2 = rx2;
   1050 				my1 = nfix(y1 - ns, dpy_y);
   1051 				my2 = nfix(y1 + ns, dpy_y+1);
   1052 
   1053 				rect = sraRgnCreateRect(mx1, my1, mx2, my2);
   1054 				sraRgnOr(mod, rect);
   1055 				sraRgnDestroy(rect);
   1056 
   1057 				inrun = 0;
   1058 			}
   1059 		}
   1060 
   1061 		xl += stride;
   1062 		dst += 4 * stride;
   1063 		src += 4 * stride;
   1064 	}
   1065 
   1066 	if (inrun) {
   1067 		mx1 = rx1;
   1068 		mx2 = rx2;
   1069 		my1 = nfix(y1 - ns, dpy_y);
   1070 		my2 = nfix(y1 + ns, dpy_y+1);
   1071 
   1072 		rect = sraRgnCreateRect(mx1, my1, mx2, my2);
   1073 		sraRgnOr(mod, rect);
   1074 		sraRgnDestroy(rect);
   1075 
   1076 		inrun = 0;
   1077 	}
   1078 }
   1079 
   1080 #define CMAPMAX 64
   1081 static Colormap cmaps[CMAPMAX];
   1082 static int ncmaps;
   1083 
   1084 static int poll_8bpp(sraRegionPtr mod, int validate) {
   1085 	int i, y, ysh, map_count;
   1086 	static int ycnt = 0;
   1087 	sraRegionPtr line;
   1088 	sraRect rect;
   1089 	sraRectangleIterator *iter;
   1090 	int br = 0, area = 0;
   1091 	static double last_call = 0.0;
   1092 
   1093 	map_count = get_8bpp_regions(validate);
   1094 
   1095 if (db24 > 1) fprintf(stderr, "poll_8bpp mc: %d\n", map_count);
   1096 
   1097 	if (! map_count) {
   1098 		return 0;
   1099 	}
   1100 
   1101 	set_poll_fb();
   1102 
   1103 	ysh = scanlines[(ycnt++) % NSCAN];
   1104 if (db24 > 2) fprintf(stderr, "poll_8bpp: ysh: %2d  %.4f\n", ysh, dnow() - last_call);
   1105 	last_call = dnow();
   1106 
   1107 	for (i=0; i < MAX_8BPP_WINDOWS; i++) {
   1108 		sraRegionPtr reg = windows_8bpp[i].clip_region;
   1109 
   1110 		if (! reg || sraRgnEmpty(reg)) {
   1111 			continue;
   1112 		}
   1113 		y = ysh;
   1114 		while (y < dpy_y) {
   1115 			line = sraRgnCreateRect(0, y, dpy_x, y+1);
   1116 
   1117 			if (sraRgnAnd(line, reg)) {
   1118 				iter = sraRgnGetIterator(line);
   1119 				while (sraRgnIteratorNext(iter, &rect)) {
   1120 					if (! poll_line(rect.x1, rect.x2,
   1121 					    rect.y1, i, mod)) {
   1122 						br = 1;
   1123 						break;	/* exception */
   1124 					}
   1125 				}
   1126 				sraRgnReleaseIterator(iter);
   1127 			}
   1128 
   1129 			sraRgnDestroy(line);
   1130 			y += NSCAN;
   1131 			if (br) break;
   1132 		}
   1133 		if (br) break;
   1134 	}
   1135 
   1136 	iter = sraRgnGetIterator(mod);
   1137 	while (sraRgnIteratorNext(iter, &rect)) {
   1138 		area += nabs((rect.x2 - rect.x1)*(rect.y2 - rect.y1));
   1139 	}
   1140 	sraRgnReleaseIterator(iter);
   1141 
   1142 	return area;
   1143 }
   1144 
   1145 static void poll_8bpp_complement(sraRegionPtr mod) {
   1146 	int i, y, ysh;
   1147 	static int ycnt = 0;
   1148 	sraRegionPtr disp, line;
   1149 	sraRect rect;
   1150 	sraRectangleIterator *iter;
   1151 
   1152 	disp = sraRgnCreateRect(0, 0, dpy_x, dpy_y);
   1153 
   1154 	ysh = scanlines[(ycnt++) % NSCAN];
   1155 
   1156 	for (i=0; i < MAX_8BPP_WINDOWS; i++) {
   1157 		sraRegionPtr reg = windows_8bpp[i].clip_region;
   1158 
   1159 		if (! reg) {
   1160 			continue;
   1161 		}
   1162 		if (windows_8bpp[i].map_state != IsViewable) {
   1163 			continue;
   1164 		}
   1165 		sraRgnSubtract(disp, reg);
   1166 	}
   1167 
   1168 	y = ysh;
   1169 	while (y < dpy_y) {
   1170 		line = sraRgnCreateRect(0, y, dpy_x, y+1);
   1171 
   1172 		if (sraRgnAnd(line, disp)) {
   1173 			iter = sraRgnGetIterator(line);
   1174 			while (sraRgnIteratorNext(iter, &rect)) {
   1175 				poll_line_complement(rect.x1, rect.x2,
   1176 				    rect.y1, mod);
   1177 			}
   1178 			sraRgnReleaseIterator(iter);
   1179 		}
   1180 
   1181 		sraRgnDestroy(line);
   1182 
   1183 		y += NSCAN;
   1184 	}
   1185 
   1186 	sraRgnDestroy(disp);
   1187 }
   1188 
   1189 static void mark_rgn_rects(sraRegionPtr mod) {
   1190 	sraRect rect;
   1191 	sraRectangleIterator *iter;
   1192 	int area = 0;
   1193 
   1194 	if (sraRgnEmpty(mod)) {
   1195 		return;
   1196 	}
   1197 
   1198 	iter = sraRgnGetIterator(mod);
   1199 	while (sraRgnIteratorNext(iter, &rect)) {
   1200 		mark_rect_as_modified(rect.x1, rect.y1, rect.x2, rect.y2, 0);
   1201 		area += nabs((rect.x2 - rect.x1)*(rect.y2 - rect.y1));
   1202 	}
   1203 	sraRgnReleaseIterator(iter);
   1204 
   1205 if (db24 > 1) fprintf(stderr, " mark_rgn_rects area: %d\n", area);
   1206 }
   1207 
   1208 static int get_8bpp_regions(int validate) {
   1209 
   1210 	XWindowAttributes attr;
   1211 	int i, k, mapcount = 0;
   1212 
   1213 	/* initialize color map list */
   1214 	ncmaps = 0;
   1215 	for (i=0; i < CMAPMAX; i++) {
   1216 		cmaps[i] = (Colormap) 0;
   1217 	}
   1218 
   1219 	/* loop over the table of 8bpp windows: */
   1220 	for (i=0; i < MAX_8BPP_WINDOWS; i++) {
   1221 		sraRegionPtr tmp_reg, tmp_reg2;
   1222 		Window c, w = windows_8bpp[i].win;
   1223 		int x, y;
   1224 
   1225 		if (windows_8bpp[i].clip_region) {
   1226 			sraRgnDestroy(windows_8bpp[i].clip_region);
   1227 		}
   1228 		windows_8bpp[i].clip_region = NULL;
   1229 
   1230 		if (w == None) {
   1231 			continue;
   1232 		}
   1233 
   1234 if (db24 > 1) fprintf(stderr, "get_8bpp_regions: 0x%lx ms=%d dep=%d i=%d\n", w, windows_8bpp[i].map_state, windows_8bpp[i].depth, i);
   1235 		if (validate) {
   1236 			/*
   1237 			 * this could be slow: validating 8bpp windows each
   1238 			 * time...
   1239 			 */
   1240 
   1241 			X_LOCK;
   1242 			if (! valid_window(w, &attr, 1)) {
   1243 				X_UNLOCK;
   1244 				windows_8bpp[i].win = None;
   1245 				windows_8bpp[i].top = None;
   1246 				windows_8bpp[i].map_state = IsUnmapped;
   1247 				windows_8bpp[i].cmap = (Colormap) 0;
   1248 				windows_8bpp[i].fetched = 0;
   1249 				windows_8bpp[i].last_fetched = -1.0;
   1250 				continue;
   1251 			}
   1252 			X_UNLOCK;
   1253 
   1254 			windows_8bpp[i].depth = attr.depth;
   1255 			windows_8bpp[i].map_state = attr.map_state;
   1256 			windows_8bpp[i].cmap = attr.colormap;
   1257 			windows_8bpp[i].map_installed = attr.map_installed;
   1258 			windows_8bpp[i].w = attr.width;
   1259 			windows_8bpp[i].h = attr.height;
   1260 			windows_8bpp[i].fetched = 1;
   1261 			windows_8bpp[i].last_fetched = dnow();
   1262 
   1263 			if (attr.map_state != IsViewable) {
   1264 				continue;
   1265 			}
   1266 
   1267 			X_LOCK;
   1268 			xtranslate(w, window, 0, 0, &x, &y, &c, 1);
   1269 			X_UNLOCK;
   1270 			windows_8bpp[i].x = x;
   1271 			windows_8bpp[i].y = y;
   1272 
   1273 		} else {
   1274 			/* this will be faster: no call to X server: */
   1275 			if (windows_8bpp[i].map_state != IsViewable) {
   1276 				continue;
   1277 			}
   1278 			attr.depth = windows_8bpp[i].depth;
   1279 			attr.map_state = windows_8bpp[i].map_state;
   1280 			attr.colormap = windows_8bpp[i].cmap;
   1281 			attr.map_installed = windows_8bpp[i].map_installed;
   1282 			attr.width = windows_8bpp[i].w;
   1283 			attr.height = windows_8bpp[i].h;
   1284 
   1285 			x =  windows_8bpp[i].x;
   1286 			y =  windows_8bpp[i].y;
   1287 		}
   1288 
   1289 		mapcount++;
   1290 
   1291 		/* tmp region for this 8bpp rectangle: */
   1292 		tmp_reg = sraRgnCreateRect(nfix(x, dpy_x), nfix(y, dpy_y),
   1293 		    nfix(x + attr.width, dpy_x+1), nfix(y + attr.height, dpy_y+1));
   1294 
   1295 		/* loop over all toplevels, top to bottom clipping: */
   1296 		for (k = stack_list_num - 1; k >= 0; k--) {
   1297 			Window swin = stack_list[k].win;
   1298 			int sx, sy, sw, sh;
   1299 
   1300 if (db24 > 1 && stack_list[k].map_state == IsViewable) fprintf(stderr, "Stack win: 0x%lx %d iv=%d\n", swin, k, stack_list[k].map_state);
   1301 
   1302 			if (swin == windows_8bpp[i].top) {
   1303 				/* found our top level: we skip the rest. */
   1304 if (db24 > 1) fprintf(stderr, "found top: 0x%lx %d iv=%d\n", swin, k, stack_list[k].map_state);
   1305 				break;
   1306 			}
   1307 			if (stack_list[k].map_state != IsViewable) {
   1308 				/* skip unmapped ones: */
   1309 				continue;
   1310 			}
   1311 
   1312 			/* make a temp rect for this toplevel: */
   1313 			sx = stack_list[k].x;
   1314 			sy = stack_list[k].y;
   1315 			sw = stack_list[k].width;
   1316 			sh = stack_list[k].height;
   1317 
   1318 if (db24 > 1) fprintf(stderr, "subtract:  0x%lx %d -- %d %d %d %d\n", swin, k, sx, sy, sw, sh);
   1319 
   1320 			tmp_reg2 = sraRgnCreateRect(nfix(sx, dpy_x),
   1321 			    nfix(sy, dpy_y), nfix(sx + sw, dpy_x+1),
   1322 			    nfix(sy + sh, dpy_y+1));
   1323 
   1324 			/* subtract it from the 8bpp window region */
   1325 			sraRgnSubtract(tmp_reg, tmp_reg2);
   1326 
   1327 			sraRgnDestroy(tmp_reg2);
   1328 
   1329 			if (sraRgnEmpty(tmp_reg)) {
   1330 				break;
   1331 			}
   1332 		}
   1333 
   1334 		if (sraRgnEmpty(tmp_reg)) {
   1335 			/* skip this 8bpp if completely clipped away: */
   1336 			sraRgnDestroy(tmp_reg);
   1337 			continue;
   1338 		}
   1339 
   1340 		/* otherwise, store any new colormaps: */
   1341 		if (ncmaps < CMAPMAX && attr.colormap != (Colormap) 0) {
   1342 			int m, seen = 0;
   1343 			for (m=0; m < ncmaps; m++) {
   1344 				if (cmaps[m] == attr.colormap) {
   1345 					seen = 1;
   1346 					break;
   1347 				}
   1348 			}
   1349 			if (!seen && attr.depth <= 16) {
   1350 				/* store only new ones: */
   1351 				cmaps[ncmaps++] = attr.colormap;
   1352 			}
   1353 		}
   1354 
   1355 		windows_8bpp[i].clip_region = tmp_reg;
   1356 	}
   1357 
   1358 	return mapcount;
   1359 }
   1360 
   1361 static XColor *color[CMAPMAX];
   1362 static unsigned int *rgb[CMAPMAX];
   1363 static int cmap_failed[CMAPMAX];
   1364 static int color_init = 0;
   1365 int histo[65536];
   1366 
   1367 static int get_cmap(int j, Colormap cmap) {
   1368 #if NO_X11
   1369 	RAWFB_RET(0)
   1370 	if (!j || !cmap) {}
   1371 	return 0;
   1372 #else
   1373 	int i, ncells, ncolor;
   1374 	XErrorHandler old_handler = NULL;
   1375 
   1376 	RAWFB_RET(0)
   1377 
   1378 	if (depth > 16) {
   1379 		/* 24 */
   1380 		ncolor = NCOLOR;
   1381 	} else if (depth > 8) {
   1382 		ncolor = 1 << depth;
   1383 	} else {
   1384 		ncolor = NCOLOR;
   1385 	}
   1386 	if (!color_init) {
   1387 		int cm;
   1388 		for (cm = 0; cm < CMAPMAX; cm++) {
   1389 			color[cm] = (XColor *) malloc(ncolor * sizeof(XColor));
   1390 			rgb[cm] = (unsigned int *) malloc(ncolor * sizeof(unsigned int));
   1391 		}
   1392 		color_init = 1;
   1393 	}
   1394 
   1395 	if (depth <= 16) {
   1396 		/* not working properly for depth 24... */
   1397 		X_LOCK;
   1398 		ncells = CellsOfScreen(ScreenOfDisplay(dpy, scr));
   1399 		X_UNLOCK;
   1400 	} else {
   1401 		ncells = NCOLOR;
   1402 	}
   1403 
   1404 	if (depth > 16) {
   1405 		;
   1406 	} else if (ncells > ncolor) {
   1407 		ncells = ncolor;
   1408 	} else if (ncells == 8 && depth != 3) {
   1409 		/* XXX. see set_colormap() */
   1410 		ncells = 1 << depth;
   1411 	}
   1412 
   1413 	/* initialize XColor array: */
   1414 	for (i=0; i < ncells; i++) {
   1415 		color[j][i].pixel = i;
   1416 		color[j][i].pad = 0;
   1417 	}
   1418 if (db24 > 1) fprintf(stderr, "get_cmap: %d 0x%x ncolor=%d ncells=%d\n", j, (unsigned int) cmap, ncolor, ncells);
   1419 
   1420 	/* try to query the colormap, trap errors */
   1421 	X_LOCK;
   1422 	trapped_xerror = 0;
   1423 	old_handler = XSetErrorHandler(trap_xerror);
   1424 	XQueryColors(dpy, cmap, color[j], ncells);
   1425 	XSetErrorHandler(old_handler);
   1426 	X_UNLOCK;
   1427 
   1428 	if (trapped_xerror) {
   1429 		trapped_xerror = 0;
   1430 		return 0;
   1431 	}
   1432 	trapped_xerror = 0;
   1433 
   1434 	/* now map each index to depth 24 RGB */
   1435 	for (i=0; i < ncells; i++) {
   1436 		unsigned int red, green, blue;
   1437 		/* strip out highest 8 bits of values: */
   1438 		red   = (color[j][i].red   & 0xff00) >> 8;
   1439 		green = (color[j][i].green & 0xff00) >> 8;
   1440 		blue  = (color[j][i].blue  & 0xff00) >> 8;
   1441 
   1442 		/*
   1443 		 * the maxes should be at 255 already,
   1444 		 * but just in case...
   1445 		 */
   1446 		red   = (main_red_max   * red  )/255;
   1447 		green = (main_green_max * green)/255;
   1448 		blue  = (main_blue_max  * blue )/255;
   1449 
   1450 if (db24 > 2) fprintf(stderr, " cmap[%02d][%03d]: %03d %03d %03d  0x%08x \n", j, i, red, green, blue, ( red << main_red_shift | green << main_green_shift | blue << main_blue_shift));
   1451 
   1452 		/* shift them over and or together for value */
   1453 		red   = red    << main_red_shift;
   1454 		green = green  << main_green_shift;
   1455 		blue  = blue   << main_blue_shift;
   1456 
   1457 		/* store it in the array to be used later */
   1458 		rgb[j][i] = red | green | blue;
   1459 	}
   1460 	return 1;
   1461 #endif	/* NO_X11 */
   1462 }
   1463 
   1464 static void do_8bpp_region(int n, sraRegionPtr mark) {
   1465 	int k, cm = -1, failed = 0;
   1466 	sraRectangleIterator *iter;
   1467 	sraRegionPtr clip;
   1468 	sraRect rect;
   1469 
   1470 	if (! windows_8bpp[n].clip_region) {
   1471 		return;
   1472 	}
   1473 	if (windows_8bpp[n].win == None) {
   1474 		return;
   1475 	}
   1476 	if (windows_8bpp[n].map_state != IsViewable) {
   1477 		return;
   1478 	}
   1479 if (db24 > 1) fprintf(stderr, "ncmaps: %d\n", ncmaps);
   1480 
   1481 	/* see if XQueryColors failed: */
   1482 	for (k=0; k<ncmaps; k++) {
   1483 		if (windows_8bpp[n].cmap == cmaps[k]) {
   1484 			cm = k;
   1485 			if (cmap_failed[k]) {
   1486 				failed = 1;
   1487 			}
   1488 			break;
   1489 		}
   1490 	}
   1491 
   1492 	if (windows_8bpp[n].depth != 24) {	/* 24 won't have a cmap */
   1493 		if (failed || cm == -1) {
   1494 			return;
   1495 		}
   1496 	}
   1497 
   1498 	clip = sraRgnCreateRgn(mark);
   1499 	sraRgnAnd(clip, windows_8bpp[n].clip_region);
   1500 
   1501 	/* loop over the rectangles making up region */
   1502 	iter = sraRgnGetIterator(clip);
   1503 	while (sraRgnIteratorNext(iter, &rect)) {
   1504 		if (rect.x1 > rect.x2) {
   1505 			int tmp = rect.x2;
   1506 			rect.x2 = rect.x1;
   1507 			rect.x1 = tmp;
   1508 		}
   1509 		if (rect.y1 > rect.y2) {
   1510 			int tmp = rect.y2;
   1511 			rect.y2 = rect.y1;
   1512 			rect.y1 = tmp;
   1513 		}
   1514 
   1515 		transform_rect(rect, windows_8bpp[n].win,
   1516 		    windows_8bpp[n].depth, cm);
   1517 	}
   1518 	sraRgnReleaseIterator(iter);
   1519 	sraRgnDestroy(clip);
   1520 }
   1521 
   1522 static XImage *cmap_xi(XImage *xi, Window win, int win_depth) {
   1523 #if NO_X11
   1524 	if (!xi || !win || !win_depth) {}
   1525 	return NULL;
   1526 #else
   1527 	XWindowAttributes attr;
   1528 	char *d;
   1529 
   1530 	if (xi) {
   1531 		XDestroyImage(xi);
   1532 	}
   1533 	if (! dpy || ! valid_window(win, &attr, 1)) {
   1534 		return (XImage *) NULL;
   1535 	}
   1536 	if (win_depth == 24) {
   1537 		d = (char *) malloc(dpy_x * dpy_y * 4);
   1538 	} else if (win_depth <= 16) {
   1539 		if (win_depth > 8) {
   1540 			d = (char *) malloc(dpy_x * dpy_y * 2);
   1541 		} else {
   1542 			d = (char *) malloc(dpy_x * dpy_y * 1);
   1543 		}
   1544 	} else {
   1545 		return (XImage *) NULL;
   1546 	}
   1547 	return XCreateImage(dpy, attr.visual, win_depth, ZPixmap, 0, d, dpy_x, dpy_y, 8, 0);
   1548 #endif	/* NO_X11 */
   1549 }
   1550 
   1551 
   1552 static void transform_rect(sraRect rect, Window win, int win_depth, int cm) {
   1553 #if NO_X11
   1554 	RAWFB_RET_VOID
   1555 	if (!rect.x1 || !win || !win_depth || !cm) {}
   1556 	return;
   1557 #else
   1558 
   1559 	char *src, *dst, *poll;
   1560 	unsigned int *ui;
   1561 	unsigned short *us;
   1562 	unsigned char *uc;
   1563 	int ps, pixelsize = bpp/8;
   1564 	int poll_Bpl;
   1565 
   1566 	int do_getimage = xgetimage_8to24;
   1567 	int line, n_off, j, h, w;
   1568 	unsigned int hi, idx;
   1569 	XWindowAttributes attr;
   1570 	XErrorHandler old_handler = NULL;
   1571 
   1572 if (db24 > 1) fprintf(stderr, "transform %4d %4d %4d %4d cm: %d\n", rect.x1, rect.y1, rect.x2, rect.y2, cm);
   1573 
   1574 	RAWFB_RET_VOID
   1575 
   1576 	attr.width = 0;
   1577 	attr.height = 0;
   1578 
   1579 	/* now transform the pixels in this rectangle: */
   1580 	n_off = main_bytes_per_line * rect.y1 + pixelsize * rect.x1;
   1581 
   1582 	h = rect.y2 - rect.y1;
   1583 	w = rect.x2 - rect.x1;
   1584 
   1585 	if (depth != 24) {
   1586 		/* need to fetch depth 24 data. */
   1587 		do_getimage = 1;
   1588 	}
   1589 
   1590 #if 0
   1591 	if (do_getimage) {
   1592 		X_LOCK;
   1593 		vw = valid_window(win, &attr, 1);
   1594 		X_UNLOCK;
   1595 	}
   1596 
   1597 	if (do_getimage && vw) {
   1598 #else
   1599 	if (do_getimage) {
   1600 #endif
   1601 		static XImage *xi_8  = NULL;
   1602 		static XImage *xi_24 = NULL;
   1603 		XImage *xi = NULL, *xi_r;
   1604 		Window c;
   1605 		unsigned int wu, hu;
   1606 		int xo, yo;
   1607 
   1608 		wu = (unsigned int) w;
   1609 		hu = (unsigned int) h;
   1610 
   1611 		X_LOCK;
   1612 #define GETSUBIMAGE
   1613 #ifdef GETSUBIMAGE
   1614 		if (win_depth == 24) {
   1615 			if (xi_24 == NULL || xi_24->width != dpy_x ||
   1616 			    xi_24->height != dpy_y) {
   1617 				xi_24 = cmap_xi(xi_24, win, 24);
   1618 			}
   1619 			xi = xi_24;
   1620 		} else if (win_depth <= 16) {
   1621 			if (xi_8 == NULL || xi_8->width != dpy_x ||
   1622 			    xi_8->height != dpy_y) {
   1623 				if (win_depth > 8) {
   1624 					/* XXX */
   1625 					xi_8 = cmap_xi(xi_8, win, 16);
   1626 				} else {
   1627 					xi_8 = cmap_xi(xi_8, win, 8);
   1628 				}
   1629 			}
   1630 			xi = xi_8;
   1631 		}
   1632 #endif
   1633 
   1634 		if (xi == NULL) {
   1635 			rfbLog("transform_rect: xi is NULL\n");
   1636 			X_UNLOCK;
   1637 			clean_up_exit(1);
   1638 		}
   1639 
   1640 		old_handler = XSetErrorHandler(trap_xerror);
   1641 		trapped_xerror = 0;
   1642 
   1643 		XTranslateCoordinates(dpy, win, window, 0, 0, &xo, &yo, &c);
   1644 
   1645 		xo = rect.x1 - xo;
   1646 		yo = rect.y1 - yo;
   1647 
   1648 if (db24 > 1) fprintf(stderr, "xywh: %d %d %d %d vs. %d %d\n", xo, yo, w, h, attr.width, attr.height);
   1649 
   1650 		if (trapped_xerror || xo < 0 || yo < 0) {
   1651 		        /* w > attr.width || h > attr.height */
   1652 			XSetErrorHandler(old_handler);
   1653 			X_UNLOCK;
   1654 			trapped_xerror = 0;
   1655 if (db24 > 1) fprintf(stderr, "skipping due to potential bad match...\n");
   1656 			return;
   1657 		}
   1658 		trapped_xerror = 0;
   1659 
   1660 #ifndef GETSUBIMAGE
   1661 		xi = XGetImage(dpy, win, xo, yo, wu, hu, AllPlanes, ZPixmap);
   1662 		xi_r = xi;
   1663 #else
   1664 		xi_r = XGetSubImage(dpy, win, xo, yo, wu, hu, AllPlanes,
   1665 		    ZPixmap, xi, 0, 0);
   1666 #endif
   1667 		XSetErrorHandler(old_handler);
   1668 
   1669 		X_UNLOCK;
   1670 
   1671 		if (! xi_r || trapped_xerror) {
   1672 			trapped_xerror = 0;
   1673 if (db24 > 1) fprintf(stderr, "xi-fail: 0x%p trap=%d  %d %d %d %d\n", (void *)xi, trapped_xerror, xo, yo, w, h);
   1674 			return;
   1675 		} else {
   1676 if (db24 > 1) fprintf(stderr, "xi: 0x%p  %d %d %d %d -- %d %d\n", (void *)xi, xo, yo, w, h, xi->width, xi->height);
   1677 		}
   1678 		trapped_xerror = 0;
   1679 
   1680 		if (xi->depth > 16 && xi->depth != 24) {
   1681 #ifndef GETSUBIMAGE
   1682 			X_LOCK;
   1683 			XDestroyImage(xi);
   1684 			X_UNLOCK;
   1685 #endif
   1686 if (db24) fprintf(stderr, "xi: wrong depth: %d\n", xi->depth);
   1687 			return;
   1688 		}
   1689 
   1690 		set_poll_fb();
   1691 
   1692 		if (xi->depth == 24) {
   1693 			/* line by line ... */
   1694 			int ps1 = 4, fac;
   1695 			if (depth <= 8) {
   1696 				fac = 4;
   1697 			} else if (depth <= 16) {
   1698 				fac = 2;
   1699 			} else {
   1700 				fac = 1;	/* will not happen 24 on 24 */
   1701 			}
   1702 
   1703 			src = xi->data;
   1704 			dst = cmap8to24_fb + fac * n_off;
   1705 
   1706 			poll = poll24_fb + (poll24_fb_w * rect.y1 + rect.x1) * 4;
   1707 			poll_Bpl = poll24_fb_w * 4;
   1708 
   1709 			for (line = 0; line < h; line++) {
   1710 				memcpy(dst,  src, w * ps1);
   1711 				memcpy(poll, src, w * ps1);
   1712 
   1713 				src += xi->bytes_per_line;
   1714 				dst += main_bytes_per_line * fac;
   1715 				poll += poll_Bpl;
   1716 			}
   1717 		} else if (xi->depth <= 16) {
   1718 			int ps1, ps2, fac;
   1719 
   1720 			if (depth <= 8) {
   1721 				ps1 = 1;
   1722 				ps2 = 4;
   1723 				fac = 4;
   1724 			} else if (depth <= 16) {
   1725 				ps1 = 2;
   1726 				ps2 = 4;
   1727 				fac = 4;
   1728 			} else {
   1729 				/* should be 24 case */
   1730 				ps1 = 1;
   1731 				ps2 = pixelsize;
   1732 				fac = 1;
   1733 			}
   1734 
   1735 			src = xi->data;
   1736 			dst = cmap8to24_fb + (fac/ps1) * n_off;
   1737 
   1738 			poll = poll8_fb + poll8_fb_w * rect.y1 * ps1 + rect.x1 * ps1;
   1739 			poll_Bpl = poll8_fb_w * ps1;
   1740 
   1741 			/* line by line ... */
   1742 			for (line = 0; line < h; line++) {
   1743 				/* pixel by pixel... */
   1744 				for (j = 0; j < w; j++) {
   1745 					if (ps1 == 2) {
   1746 						unsigned short *ptmp;
   1747 						us    = (unsigned short *) (src + ps1 * j);
   1748 						idx   = (int) (*us);
   1749 						ptmp  = (unsigned short *) (poll + ps1 * j);
   1750 						*ptmp = *us;
   1751 					} else {
   1752 						uc  = (unsigned char *) (src + ps1 * j);
   1753 						idx = (int) (*uc);
   1754 						*(poll + ps1 * j) = *uc;
   1755 					}
   1756 					ui = (unsigned int *) (dst + ps2 * j);
   1757 					*ui = rgb[cm][idx];
   1758 
   1759 				}
   1760 				src += xi->bytes_per_line;
   1761 				dst += main_bytes_per_line * (fac/ps1);
   1762 				poll += poll_Bpl;
   1763 			}
   1764 		}
   1765 
   1766 #ifndef GETSUBIMAGE
   1767 		X_LOCK;
   1768 		XDestroyImage(xi);
   1769 		X_UNLOCK;
   1770 #endif
   1771 
   1772 	} else if (! do_getimage) {
   1773 		int fac;
   1774 
   1775 		if (depth <= 16) {
   1776 			/* cooked up depth 24 TrueColor  */
   1777 			/* but currently disabled (high bits no useful?) */
   1778 			ps = 4;
   1779 			fac = 4;
   1780 			/* XXX not correct for depth > 8, but do we ever come here in that case? */
   1781 			src = cmap8to24_fb + 4 * n_off;
   1782 		} else {
   1783 			ps = pixelsize;
   1784 			fac = 1;
   1785 			src = cmap8to24_fb + n_off;
   1786 		}
   1787 
   1788 		/* line by line ... */
   1789 		for (line = 0; line < h; line++) {
   1790 			/* pixel by pixel... */
   1791 			for (j = 0; j < w; j++) {
   1792 
   1793 				/* grab 32 bit value */
   1794 				ui = (unsigned int *) (src + ps * j);
   1795 
   1796 				/* extract top 8 bits (FIXME: masks?) */
   1797 				hi = (*ui) & 0xff000000;
   1798 
   1799 				/* map to lookup index; rewrite pixel */
   1800 				idx = hi >> 24;
   1801 				*ui = hi | rgb[cm][idx];
   1802 			}
   1803 			src += main_bytes_per_line * fac;
   1804 		}
   1805 	}
   1806 #endif	/* NO_X11 */
   1807 }
   1808 
   1809 void bpp8to24(int x1, int y1, int x2, int y2) {
   1810 	char *src, *dst;
   1811 	unsigned char *uc;
   1812 	unsigned short *us;
   1813 	unsigned int *ui;
   1814 	int idx, pixelsize = bpp/8;
   1815 	int line, k, i, j, h, w;
   1816 	int n_off;
   1817 	sraRegionPtr rect;
   1818 	int validate = 1;
   1819 	static int last_map_count = 0, call_count = 0;
   1820 	static double last_get_8bpp_validate = 0.0;
   1821 	static double last_snapshot = 0.0;
   1822 	double now;
   1823 	double dt, d0 = 0.0, t2;
   1824 
   1825 	RAWFB_RET_VOID
   1826 
   1827 	if (! cmap8to24 || ! cmap8to24_fb) {
   1828 		/* hmmm, why were we called? */
   1829 		return;
   1830 	}
   1831 
   1832 if (db24 > 1) fprintf(stderr, "bpp8to24 %d %d %d %d %.4f\n", x1, y1, x2, y2, dnow() - last_get_8bpp_validate);
   1833 
   1834 	call_count++;
   1835 
   1836 	/* clip to display just in case: */
   1837 	if (!ncache) {
   1838 		x1 = nfix(x1, dpy_x);
   1839 		y1 = nfix(y1, dpy_y);
   1840 		x2 = nfix(x2, dpy_x+1);
   1841 		y2 = nfix(y2, dpy_y+1);
   1842 	}
   1843 
   1844 	if (wireframe_in_progress) {
   1845 		/*
   1846 		 * draw_box() manages cmap8to24_fb for us so we get out as
   1847 		 * soon as we can.  No need to cp main_fb -> cmap8to24_fb.
   1848 		 */
   1849 		return;
   1850 	}
   1851 
   1852 	/* copy from main_fb to cmap8to24_fb regardless of 8bpp windows: */
   1853 
   1854 	h = y2 - y1;
   1855 	w = x2 - x1;
   1856 
   1857 	if (depth == 24) {
   1858 		/* pixelsize = 4 */
   1859 		n_off = main_bytes_per_line * y1 + pixelsize * x1;
   1860 
   1861 		src = main_fb      + n_off;
   1862 		dst = cmap8to24_fb + n_off;
   1863 
   1864 		/* otherwise, the pixel data as is */
   1865 		for (line = 0; line < h; line++) {
   1866 			memcpy(dst, src, w * pixelsize);
   1867 			src += main_bytes_per_line;
   1868 			dst += main_bytes_per_line;
   1869 		}
   1870 	} else if (depth <= 16) {
   1871 		/* need to cook up to depth 24 TrueColor  */
   1872 		int ps1 = 1, ps2 = 4;
   1873 		if (depth > 8) {
   1874 			ps1 = 2;
   1875 		}
   1876 
   1877 		/* pixelsize = 1, 2 */
   1878 		n_off = main_bytes_per_line * y1 + pixelsize * x1;
   1879 
   1880 		src = main_fb + n_off;
   1881 		dst = cmap8to24_fb + (4/ps1) * n_off;
   1882 
   1883 		set_root_cmap();
   1884 		if (root_cmap) {
   1885 #if 0
   1886 			unsigned int hi;
   1887 #endif
   1888 
   1889 			/* line by line ... */
   1890 			for (line = 0; line < h; line++) {
   1891 				/* pixel by pixel... */
   1892 				for (j = 0; j < w; j++) {
   1893 					if (ps1 == 2) {
   1894 						us = (unsigned short *) (src + ps1 * j);
   1895 						idx = (int) (*us);
   1896 					} else {
   1897 						uc = (unsigned char *)  (src + ps1 * j);
   1898 						idx = (int) (*uc);
   1899 					}
   1900 					ui = (unsigned int *)  (dst + ps2 * j);
   1901 
   1902 if (0 && line % 100 == 0 && j % 32 == 0) fprintf(stderr, "%d %d %u  x1=%d y1=%d\n", line, j, root_rgb[idx], x1, y1);
   1903 #if 0
   1904 					if (do_hibits) {
   1905 						hi = idx << 24;
   1906 						*ui = hi | rgb[0][idx];
   1907 					} else {
   1908 					}
   1909 #endif
   1910 					*ui = root_rgb[idx];
   1911 if (db24 > 2) histo[idx]++;
   1912 				}
   1913 				src += main_bytes_per_line;
   1914 				dst += main_bytes_per_line * (4/ps1);
   1915 			}
   1916 		}
   1917 
   1918 	}
   1919 
   1920 	if (last_map_count > MAX_8BPP_WINDOWS/4) {
   1921 		/* table is filling up... skip validating sometimes: */
   1922 		int skip = 3;
   1923 		if (last_map_count > MAX_8BPP_WINDOWS/2) {
   1924 			skip = 6;
   1925 		} else if (last_map_count > 3*MAX_8BPP_WINDOWS/4) {
   1926 			skip = 12;
   1927 		}
   1928 		if (call_count % skip != 0) {
   1929 			validate = 0;
   1930 		}
   1931 	}
   1932 
   1933 if (db24 > 2) {for(i=0;i<256;i++){histo[i]=0;}}
   1934 
   1935 	now = dnow();
   1936 	dt = now - last_get_8bpp_validate;
   1937 	/* TUNABLES  */
   1938 	if (dt < 0.003) {
   1939 		;	/* XXX does this still give painting errors? */
   1940 	} else {
   1941 		int snapit = 0;
   1942 		double delay1, delay2, delay3;
   1943 		if (poll_8to24_delay >= POLL_8TO24_DELAY) {
   1944 			delay1 = 1.0 * poll_8to24_delay;
   1945 			delay2 = 2.0 * poll_8to24_delay;
   1946 			delay3 = 10. * poll_8to24_delay;
   1947 		} else {
   1948 			delay1 = 1.0 * POLL_8TO24_DELAY;	/* 0.05 */
   1949 			delay2 = 2.0 * POLL_8TO24_DELAY;	/* 0.1  */
   1950 			delay3 = 10. * POLL_8TO24_DELAY;	/* 0.5  */
   1951 		}
   1952 		if (cache_win > 1.0) {
   1953 			delay2 *= 2;
   1954 			delay3 *= 2;
   1955 		}
   1956 		if (dt < delay1) {
   1957 			validate = 0;
   1958 		}
   1959 		if (last_map_count) {
   1960 			if (now > last_snapshot + delay2) {
   1961 				snapit = 1;
   1962 			}
   1963 		} else {
   1964 			if (now > last_snapshot + delay3) {
   1965 				snapit = 1;
   1966 			}
   1967 		}
   1968 
   1969 		if (snapit) {
   1970 			/* less problems if we update the stack frequently */
   1971 			snapshot_stack_list(0, 0.0);
   1972 if (0) fprintf(stderr, "SNAP time: %.4f\n", dnow() - now);
   1973 			update_stack_list();
   1974 			last_snapshot = dnow();
   1975 if (0) fprintf(stderr, "UPDA time: %.4f\n", last_snapshot - now);
   1976 		}
   1977 
   1978 if (0) t2 = dnow();
   1979 		last_map_count = get_8bpp_regions(validate);
   1980 		if (validate) {
   1981 			last_get_8bpp_validate = dnow();
   1982 		}
   1983 if (0) fprintf(stderr, "get8bpp-%d: %.4f\n", validate, dnow() - t2);
   1984 	}
   1985 if (db24) d0 = dnow();
   1986 
   1987 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);
   1988 
   1989 	/*
   1990 	 * now go back and transform and 8bpp regions to TrueColor in
   1991 	 * cmap8to24_fb.
   1992 	 */
   1993 	if (last_map_count && (ncmaps || depth <= 16)) {
   1994 		int i, j;
   1995 		int win[MAX_8BPP_WINDOWS];
   1996 		int did[MAX_8BPP_WINDOWS];
   1997 		int count = 0;
   1998 
   1999 		/*
   2000 		 * first, grab all of the associated colormaps from the
   2001 		 * X server.  Hopefully just 1 or 2...
   2002 		 */
   2003 		for (j=0; j<ncmaps; j++) {
   2004 			if (! get_cmap(j, cmaps[j])) {
   2005 				cmap_failed[j] = 1;
   2006 			} else {
   2007 				cmap_failed[j] = 0;
   2008 			}
   2009 if (db24 > 2) fprintf(stderr, "cmap %d  %.4f\n", (int) cmaps[j], dnow() - d0);
   2010 		}
   2011 		for (i=0; i < MAX_8BPP_WINDOWS; i++) {
   2012 			sraRegionPtr reg = windows_8bpp[i].clip_region;
   2013 			if (reg) {
   2014 				rect = sraRgnCreateRect(x1, y1, x2, y2);
   2015 				if (sraRgnAnd(rect, reg)) {
   2016 					win[count] = i;
   2017 					did[count++] = 0;
   2018 				}
   2019 				sraRgnDestroy(rect);
   2020 			}
   2021 		}
   2022 
   2023 		if (count) {
   2024 
   2025 			rect = sraRgnCreateRect(x1, y1, x2, y2);
   2026 			/* try to apply lower windows first */
   2027 			for (k=0; k < stack_list_num; k++) {
   2028 				Window swin = stack_list[k].win;
   2029 				for (j=0; j<count; j++) {
   2030 					i = win[j];
   2031 					if (did[j]) {
   2032 						continue;
   2033 					}
   2034 					if (windows_8bpp[i].top == swin) {
   2035 						do_8bpp_region(i, rect);
   2036 						did[j] = 1;
   2037 						break;
   2038 					}
   2039 				}
   2040 			}
   2041 			for (j=0; j<count; j++) {
   2042 				if (! did[j]) {
   2043 					i = win[j];
   2044 					do_8bpp_region(i, rect);
   2045 					did[j] = 1;
   2046 				}
   2047 			}
   2048 			sraRgnDestroy(rect);
   2049 		}
   2050 	}
   2051 if (0) fprintf(stderr, "done time: %.4f\n", dnow() - d0);
   2052 
   2053 if (db24 > 2) {for(i=0; i<256;i++) {fprintf(stderr, " cmap histo[%03d] %d\n", i, histo[i]);}}
   2054 }
   2055 
   2056 void mark_8bpp(int mode) {
   2057 	int i, cnt = 0;
   2058 	Window top = None;
   2059 
   2060 	RAWFB_RET_VOID
   2061 
   2062 	if (! cmap8to24 || !cmap8to24_fb) {
   2063 		return;
   2064 	}
   2065 
   2066 	if (mode == MARK_8BPP_TOP) {
   2067 		int k;
   2068 		for (k = stack_list_num - 1; k >= 0; k--) {
   2069 			Window swin = stack_list[k].win;
   2070 			for (i=0; i < MAX_8BPP_WINDOWS; i++) {
   2071 				if (windows_8bpp[i].win == None) {
   2072 					continue;
   2073 				}
   2074 				if (windows_8bpp[i].map_state != IsViewable) {
   2075 					continue;
   2076 				}
   2077 				if (swin == windows_8bpp[i].top) {
   2078 					top = swin;
   2079 					break;
   2080 				}
   2081 			}
   2082 			if (top != None) {
   2083 				break;
   2084 			}
   2085 		}
   2086 	}
   2087 
   2088 	/* for each mapped 8bpp window, mark it changed: */
   2089 
   2090 	for (i=0; i < MAX_8BPP_WINDOWS; i++) {
   2091 		int x1, y1, x2, y2, w, h, f = 32;
   2092 
   2093 		f = 0;	/* skip fuzz, may bring in other windows... */
   2094 
   2095 		if (windows_8bpp[i].win == None) {
   2096 			continue;
   2097 		}
   2098 		if (mode == MARK_8BPP_TOP) {
   2099 			if (windows_8bpp[i].top != top) {
   2100 				continue;
   2101 			}
   2102 		}
   2103 		if (windows_8bpp[i].map_state != IsViewable) {
   2104 			XWindowAttributes attr;
   2105 			int vw = 0;
   2106 
   2107 			X_LOCK;
   2108 			vw = valid_window(windows_8bpp[i].win, &attr, 1);
   2109 			X_UNLOCK;
   2110 			if (vw) {
   2111 				if (attr.map_state != IsViewable) {
   2112 					continue;
   2113 				}
   2114 			} else {
   2115 				continue;
   2116 			}
   2117 		}
   2118 
   2119 		x1 = windows_8bpp[i].x;
   2120 		y1 = windows_8bpp[i].y;
   2121 		w  = windows_8bpp[i].w;
   2122 		h  = windows_8bpp[i].h;
   2123 
   2124 		x2 = x1 + w;
   2125 		y2 = y1 + h;
   2126 
   2127 		if (mode == MARK_8BPP_POINTER) {
   2128 			int b = 32;	/* apply some fuzz for wm border */
   2129 			if (cursor_x < x1 - b || cursor_y < y1 - b) {
   2130 				continue;
   2131 			}
   2132 			if (cursor_x > x2 + b || cursor_y > y2 + b) {
   2133 				continue;
   2134 			}
   2135 		}
   2136 
   2137 		/* apply fuzz f around each one; constrain to screen */
   2138 		x1 = nfix(x1 - f, dpy_x);
   2139 		y1 = nfix(y1 - f, dpy_y);
   2140 		x2 = nfix(x2 + f, dpy_x+1);
   2141 		y2 = nfix(y2 + f, dpy_y+1);
   2142 
   2143 if (db24 > 1) fprintf(stderr, "mark_8bpp: 0x%lx %d %d %d %d\n", windows_8bpp[i].win, x1, y1, x2, y2);
   2144 
   2145 		mark_rect_as_modified(x1, y1, x2, y2, 0);
   2146 		cnt++;
   2147 	}
   2148 	if (cnt) {
   2149 		/* push it to viewers if possible. */
   2150 		rfbPE(-1);
   2151 	}
   2152 }
   2153 
   2154 #endif /* SKIP_8TO24 */
   2155 
   2156