1 /*
2    Copyright (C) 2002-2010 Karl J. Runge <runge@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
check_for_multivis(void)49 void check_for_multivis(void) {}
bpp8to24(int x,int y,int z,int t)50 void bpp8to24(int x, int y, int z, int t) {}
mark_8bpp(int x)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 
set_root_cmap(void)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 
check_pointer_in_depth24(void)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 
parse_cmap8to24(void)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 
pfb(int fac,char ** fb,int * w,int * h)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 
set_poll_fb(void)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 
check_for_multivis(void)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 
set_attr(XWindowAttributes * attr,int j)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 
vw_lookup(Window win)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 
check_depth(Window win,Window top,int doall)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 
check_depth_win(Window win,Window top,XWindowAttributes * attr)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 */
p_xi(XImage * xi,Visual * visual,int win_depth,int * w)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 
poll_line(int x1,int x2,int y1,int n,sraRegionPtr mod)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 
poll_line_complement(int x1,int x2,int y1,sraRegionPtr mod)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 
poll_8bpp(sraRegionPtr mod,int validate)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 
poll_8bpp_complement(sraRegionPtr mod)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 
mark_rgn_rects(sraRegionPtr mod)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 
get_8bpp_regions(int validate)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 
get_cmap(int j,Colormap cmap)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 
do_8bpp_region(int n,sraRegionPtr mark)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 
cmap_xi(XImage * xi,Window win,int win_depth)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 
transform_rect(sraRect rect,Window win,int win_depth,int cm)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