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