Add xmag_multivis from x-S12
[unleashed-userland.git] / components / x11 / xmag_multivis / src / multivis.c
bloba5c0b164392a7ba52aca4399ab87c5fd5623ebbc
1 /*-
2 * multivis.c - Mechanism for GetImage across Multiple Visuals
4 * Original author:
5 * Milind M. Pansare
6 * Window Systems Group
7 * Sun Microsystems, Inc.
9 * Revision History:
10 * 11-15-90 Written
13 /* Copyright (c) 1990, 2011, Oracle and/or its affiliates. All rights reserved.
15 * Permission is hereby granted, free of charge, to any person obtaining a
16 * copy of this software and associated documentation files (the "Software"),
17 * to deal in the Software without restriction, including without limitation
18 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
19 * and/or sell copies of the Software, and to permit persons to whom the
20 * Software is furnished to do so, subject to the following conditions:
22 * The above copyright notice and this permission notice (including the next
23 * paragraph) shall be included in all copies or substantial portions of the
24 * Software.
26 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
29 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
31 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
32 * DEALINGS IN THE SOFTWARE.
35 #include <stdlib.h>
36 #include <X11/Xlib.h>
37 #include <X11/Xutil.h>
38 #ifdef SHAPE
39 #include <X11/extensions/shape.h>
40 #endif /* SHAPE */
41 #include "multivis.h"
43 static MVColmap *mvFindColormap(Colormap cmap);
44 static XVisualInfo *mvMatchVisual(VisualID vid);
45 static void mvGetColormap(MVWinVisInfo *pWI);
46 static void mvCalculateComposite(MVWinVisInfo *pWI);
47 static unsigned long mvCompositePixel(unsigned long i, MVColmap *pCmp);
49 static Display *mvDpy; /* Display */
50 static int mvScreen; /* Screen */
51 static XVisualInfo *mvVlist; /* List of Visuals */
52 static int mvNumVis; /* Number of visuals in list */
53 #ifdef SHAPE
54 static Bool mvShape; /* Shape extension ? */
55 #endif /* SHAPE */
57 static MVWinVisInfoList winList; /* Here we'll grow a list of windows
58 Sorted back to front */
60 static MVColmap *colMaps; /* list of colormaps we encounter */
61 static MVPel *mvImg; /* mvImg is what we compose the image
62 into */
64 static int request_width,
65 request_height; /* size of requested rectangle */
66 static int request_x, request_y; /* The top left of requested
67 rectangle in Root Space */
69 #ifdef UPDATE_HACK
70 static void *mvCallbackData;
71 static mvCallbackFunc mvCallbackFunction;
72 #endif /* UPDATE_HACK */
76 * Initialise the mvLib routines ...
79 void
80 #ifdef UPDATE_HACK
81 mvInit(
82 Display *dpy,
83 int screen,
84 XVisualInfo *vlist,
85 int num_vis,
86 void *callbackData,
87 mvCallbackFunc callbackFunction)
88 #else
89 mvInit(
90 Display *dpy,
91 int screen,
92 XVisualInfo *vlist,
93 int num_vis)
94 #endif /* UPDATE_HACK */
96 #ifdef SHAPE
97 int tmp;
98 #endif /* SHAPE */
99 /* Initialise screen info */
100 mvDpy = dpy;
101 mvScreen = screen;
102 mvVlist = vlist;
103 mvNumVis = num_vis;
104 #ifdef SHAPE
105 mvShape = XShapeQueryExtension(dpy, &tmp, &tmp);
106 #endif /* SHAPE */
108 #ifdef UPDATE_HACK
109 mvCallbackData = callbackData;
110 mvCallbackFunction = callbackFunction;
111 #endif /* UPDATE_HACK */
115 * Create an Img.. Cleared to zeros.
116 * returns 0 if failure, non-zero for success.
117 * Note that it is the reponsibility of the caller
118 * to verify that any resulting XGetImage will
119 * be within the bounds of the screen.
120 * i.e, x, y, wd, ht must be such that the rectangle
121 * is fully within the bounds of the screen.
124 mvCreatImg(int wd, int ht, int x, int y)
126 /* Create mvImg */
127 request_width = wd;
128 request_height = ht;
129 request_x = x;
130 request_y = y;
131 if ((mvImg = (MVPel *) calloc(sizeof(MVPel), request_width * request_height))
132 != NULL) {
133 return 1;
135 return 0;
139 * Reset the mvLib routines
141 void
142 mvReset(void)
144 #ifdef SHAPE
145 int i;
146 #endif /* SHAPE */
147 /* Free mvImg */
148 if (mvImg)
149 free(mvImg);
150 /* Clean winList */
151 if (winList.wins) {
152 #ifdef SHAPE
153 i = winList.used;
154 while (i--) {
155 if (winList.wins[i].region)
156 XDestroyRegion(winList.wins[i].region);
158 #endif /* SHAPE */
159 free(winList.wins);
160 winList.wins = NULL;
161 winList.used = winList.allocated = 0;
163 /* Clean colmap list */
164 while (colMaps) {
165 MVColmap *pCmap;
166 pCmap = colMaps;
167 colMaps = pCmap->next;
168 if (pCmap->Colors)
169 free(pCmap->Colors);
170 free(pCmap);
175 * Recursively walk the window tree.
176 * Find windows that intersect the requested region.
177 * Create a list of such windows in global winList.
178 * Assumes winList was cleared beforehand.
180 void
181 mvWalkTree(
182 Window win, /* This window */
183 int px, int py, /* parent's origin in root space */
184 int x, int y, /* Top left of requested rectangle in root space */
185 int wi, int hi, /* size of requested rectangle */
186 #ifdef SHAPE
187 Bool ancestorShaped, /* ancestor was a Shaped window */
188 Region ancestorRegion /* parent rel. effective Bounding region of ancestors */
189 #endif /* SHAPE */
192 XWindowAttributes xwa;
193 int width, height, x1, y1;
194 Window root, parent, *children;
195 int n;
196 unsigned int nchild;
197 MVWinVisInfo *pWinInfo;
198 #ifdef SHAPE
199 Bool isShaped = False;
200 Bool bdg, clp;
201 int xb, yb, xc, yc;
202 unsigned int wb, hb, wc, hc;
203 int count, ordering;
204 Region tmpancestorRegion, tmpreg;
205 XRectangle *rects, *rect, tmprct;
206 #endif /* SHAPE */
208 if (!XGetWindowAttributes(mvDpy, win, &xwa)
209 || xwa.map_state != IsViewable
210 || xwa.class == InputOnly) {
211 return;
214 /* compute top-left of image in root space */
215 x1 = max(x, xwa.x+px);
216 y1 = max(y, xwa.y+py);
217 width = min(x+wi, xwa.x+xwa.width+2*xwa.border_width+px)-x1;
218 height=min(y+hi, xwa.y+xwa.height+2*xwa.border_width+py)-y1;
220 if (width <=0 || height <= 0) {
221 return;
224 /* We're interested ... */
226 if (winList.used >= winList.allocated) { /* expand or create the array */
227 winList.allocated = (winList.allocated?winList.allocated*MV_WIN_TUNE2:
228 MV_WIN_TUNE1);
229 winList.wins = (MVWinVisInfo *)(winList.wins ?
230 realloc(winList.wins,winList.allocated*sizeof(MVWinVisInfo)):
231 malloc(winList.allocated*sizeof(MVWinVisInfo)));
234 pWinInfo = &(winList.wins[winList.used++]);
235 pWinInfo->window = win;
236 pWinInfo->depth = xwa.depth;
237 pWinInfo->visinfo = mvMatchVisual(XVisualIDFromVisual(xwa.visual));
238 pWinInfo->colmap = mvFindColormap(xwa.colormap);
239 pWinInfo->x = x1-xwa.border_width-xwa.x-px;
240 pWinInfo->y = y1-xwa.border_width-xwa.y-py;
241 pWinInfo->width = width;
242 pWinInfo->height = height;
243 pWinInfo->x1 = x1;
244 pWinInfo->y1 = y1;
245 #ifdef SHAPE
246 pWinInfo->region = NULL;
247 /* Is it a Shaped Window ? Help ! */
248 if ((XShapeQueryExtents(mvDpy, win, &bdg, &xb, &yb, &wb, &hb,
249 &clp, &xc, &yc, &wc, &hc)) && bdg) {
251 if ((wb == 0) || (hb == 0) || (wb > 2000) || (hb > 2000)) {
252 /* Empty shape, ignore it */
253 winList.used--;
254 return;
257 isShaped = True;
258 pWinInfo->region = XCreateRegion();
259 rect = rects =
260 XShapeGetRectangles(mvDpy, win, ShapeBounding, &count, &ordering);
262 while (count--) {
263 XUnionRectWithRegion(rect++, pWinInfo->region, pWinInfo->region);
265 if (rects != NULL) {
266 XFree((caddr_t)rects);
269 tmpreg = XCreateRegion();
270 tmprct.x = pWinInfo->x; tmprct.y = pWinInfo->y;
271 tmprct.width = pWinInfo->width; tmprct.height = pWinInfo->height;
272 XUnionRectWithRegion(&tmprct, tmpreg, tmpreg);
273 XIntersectRegion(pWinInfo->region, tmpreg, pWinInfo->region);
274 XDestroyRegion(tmpreg);
276 if (ancestorShaped) {
277 /* make a local copy */
278 tmpancestorRegion = XCreateRegion();
279 XUnionRegion(tmpancestorRegion, ancestorRegion, tmpancestorRegion);
280 /* Translate from relative parent's origin to this window's origin */
281 XOffsetRegion(tmpancestorRegion, -(xwa.x + xwa.border_width),
282 -(xwa.y + xwa.border_width));
283 if (isShaped) { /* Compute effective bdg shape */
284 XIntersectRegion(tmpancestorRegion, pWinInfo->region, pWinInfo->region);
286 else {
287 pWinInfo->region = XCreateRegion();
288 XUnionRegion(tmpancestorRegion, pWinInfo->region, pWinInfo->region);
289 tmpreg = XCreateRegion();
290 tmprct.x = pWinInfo->x; tmprct.y = pWinInfo->y;
291 tmprct.width = pWinInfo->width; tmprct.height = pWinInfo->height;
292 XUnionRectWithRegion(&tmprct, tmpreg, tmpreg);
293 XIntersectRegion(pWinInfo->region, tmpreg, pWinInfo->region);
294 XDestroyRegion(tmpreg);
296 XDestroyRegion(tmpancestorRegion);
298 #endif /* SHAPE */
300 /* Find children, back to front */
301 if (XQueryTree(mvDpy, win, &root, &parent, &children, &nchild)) {
303 #ifdef SHAPE
304 tmpreg = pWinInfo->region;
305 #endif /* SHAPE */
307 for (n=0; n<nchild; n++) {
308 #ifdef SHAPE
309 mvWalkTree(children[n], px+xwa.x+xwa.border_width,
310 py+xwa.y+xwa.border_width,
311 x1, y1, width, height, (ancestorShaped || isShaped),
312 tmpreg);
313 #else /* !SHAPE */
314 mvWalkTree(children[n], px+xwa.x+xwa.border_width,
315 py+xwa.y+xwa.border_width,
316 x1, y1, width, height);
317 #endif /* SHAPE */
319 /* free children */
320 if (nchild > 0)
321 XFree((caddr_t)children);
323 return;
327 * CHANGE
328 * Returns 0 if no problems,
329 * Returns 1 if depths differ
330 * returns 2 if colormap or visinfo differ
331 * NOTE that this chenge & the previous change are reprehensible hacks,
332 * to let xmag work with pageview, and xcolor respectively.
333 * USED TO BE...
334 * CHANGE
335 * Returns 0 if no problems,
336 * Returns 1 if visinfo or depth differ
337 * returns 2 if colormap only differ
338 * USED TO BE...
339 * Returns non-zero if the winList created by mvWalkTree
340 * might potentially have windows of different Visuals
341 * else returns 0
343 int
344 mvIsMultiVis(void)
346 int retcode = 0;
347 int i = winList.used;
349 while (i--) {
350 if(winList.wins[i].depth != winList.wins[0].depth)
351 return 1;
352 if (winList.wins[i].visinfo != winList.wins[0].visinfo)
353 retcode = 2;
354 if (winList.wins[i].colmap != winList.wins[0].colmap)
355 retcode = 2;
357 return retcode;
361 * Traverse the window list front to back. Get the entire Image
362 * from each window, but only Label a pixel in the Img once.
363 * That is, once a pixel has been Labeled, any more fetches
364 * from the same pixel position are discarded. Once all pixels
365 * positions have been fetched, we're done. This will eliminate
366 * windows that have nothing to contibute to the requested region,
367 * but will nevertheless have the problem of the painters
368 * algorithm, where more pixels were fetched from a
369 * window than were essential.
370 * Assumes that winList has been filled beforehand, and Img was cleared.
373 void
374 mvDoWindowsFrontToBack(void)
376 int i;
377 MVWinVisInfo *pWI;
378 XImage *xim;
379 int xi, yi;
380 int nPixelsUnLabeled = request_width*request_height;
382 for (i=winList.used-1; ((nPixelsUnLabeled > 0) && i >= 0); i--) {
383 pWI = &(winList.wins[i]);
384 if (!(xim = XGetImage(mvDpy, pWI->window, pWI->x, pWI->y, pWI->width,
385 pWI->height, (~0), ZPixmap))) {
386 return;
388 mvGetColormap(pWI);
389 /* For each pixel in the returned Image */
390 for (yi = 0; yi < pWI->height; yi++) {
391 #ifdef UPDATE_HACK
392 if ((yi % 128) == 0) {
393 (*mvCallbackFunction)(mvCallbackData);
395 #endif /* UPDATE_HACK */
396 for (xi = 0; xi < pWI->width; xi++) {
397 MVPel *pPel = mvFindPel(xi+pWI->x1-request_x, yi+pWI->y1-request_y);
398 /* If the pixel hasn't been labelled before */
399 if (!pPel->colmap) { /* pPel->colmap serves as a 'Label' */
400 /* label the pixel in the map with this window's cmap */
402 * If Pixel value can be discarded, this is where
403 * you get the RGB value instead.
404 * Call a routine like mvFindColorInColormap() with the pixel
405 * value, and Colormap as parameters.
406 * The 'Label', instead of pPel->colmap could be a scratch bit ?
407 * But if its a full 32 bit pixel, and there are no
408 * free bits, you need to hang in extra bits somewhere.
409 * Maybe a bitmask associated with Img ?
411 #ifdef SHAPE
412 if (!(pWI->region) ||
413 (pWI->region && (XPointInRegion(pWI->region, xi+pWI->x, yi+pWI->y))
414 #ifdef XNEWS
415 && (XPointInRegion(pWI->region, xi+pWI->x+1, yi+pWI->y))
416 && (XPointInRegion(pWI->region, xi+pWI->x, yi+pWI->y+1))
417 && (XPointInRegion(pWI->region, xi+pWI->x+1, yi+pWI->y+1))
418 #endif /* XNEWS */
421 #endif /* SHAPE */
422 pPel->colmap = pWI->colmap;
423 /* and pixel value */
424 pPel->pixel = XGetPixel(xim, xi, yi);
425 nPixelsUnLabeled--;
426 #ifdef SHAPE
428 #endif /* SHAPE */
432 /* free image */
433 XDestroyImage(xim);
438 * Get all the colors from this window's colormap.
439 * That's slightly complicated when we hit
440 * a true color or direct color visual.
441 * Assumes that a global list of colmaps is present, and
442 * that the Colors field was NULLed beforehand.
445 static void
446 mvGetColormap(MVWinVisInfo *pWI)
448 if (!pWI->colmap->Colors) { /* This is the first time we're visiting */
449 MVColmap *pCmp = pWI->colmap;
450 XVisualInfo *pVis = pWI->visinfo;
451 XColor *pCol;
452 int size = pVis->colormap_size;
454 /* Allocate enough memory */
455 pCmp->Colors = pCol = (XColor *)calloc((sizeof(XColor)), size);
456 if (pVis->class == TrueColor || pVis->class == DirectColor) {
457 unsigned long i;
458 /* We have to create a composite pixel value */
459 mvCalculateComposite(pWI);
460 for (i = 0; i < (unsigned long)(size);i++, pCol++) {
461 pCol->pixel = mvCompositePixel(i, pCmp);
464 else {
465 unsigned long i;
466 /* Fill in the pixel values by hand */
467 for (i = 0; i < (unsigned long)(size);) {
468 pCol++->pixel = i++;
471 XQueryColors(mvDpy, pCmp->cmap, pCmp->Colors, size);
476 * Given a VisualID, return a pointer to the VisualInfo structure.
477 * Assumes that a global mvVlist for this screen has already
478 * been created. Uses globals mvNumVis, and mvVlist.
479 * Returns NULL if the vid is not matched.
481 static XVisualInfo *
482 mvMatchVisual(VisualID vid)
484 XVisualInfo *pVis = mvVlist;
485 while (pVis < (mvVlist+mvNumVis)) {
486 if (vid == pVis->visualid) {
487 return pVis;
489 pVis++;
491 return NULL;
495 * Calculate a composite pixel value that indexes into all
496 * three primaries . Assumes Composite Calcs have been performed
497 * already on the colmap.
499 static unsigned long
500 mvCompositePixel(unsigned long i, MVColmap *pCmp)
502 unsigned long val = 0;
504 if (i < pCmp->rmax) val |= i << pCmp->rshft;
505 if (i < pCmp->gmax) val |= i << pCmp->gshft;
506 if (i < pCmp->bmax) val |= i << pCmp->bshft;
507 return val;
511 * Calculate the offsets used to composite a pixel value for
512 * the TrueColor & DirectColor cases
513 * Assumes its called only on a True or DirectColor visual.
515 static void
516 mvCalculateComposite(MVWinVisInfo *pWI)
518 MVColmap *pCmp = pWI->colmap;
519 XVisualInfo *pVis = pWI->visinfo;
520 /* Check if this has been done before */
521 if (!pCmp->doComposite) {
522 pCmp->doComposite = True;
523 /* These are the sizes of each primary map ... */
524 pCmp->red_mask = pVis->red_mask;
525 pCmp->green_mask = pVis->green_mask;
526 pCmp->blue_mask = pVis->blue_mask;
527 pCmp->rmax = 1 << mvOnes(pVis->red_mask);
528 pCmp->gmax = 1 << mvOnes(pVis->green_mask);
529 pCmp->bmax = 1 << mvOnes(pVis->blue_mask);
530 pCmp->rshft = mvShifts(pVis->red_mask);
531 pCmp->gshft = mvShifts(pVis->green_mask);
532 pCmp->bshft = mvShifts(pVis->blue_mask);
533 pCmp->rgbshft = (16 - pVis->bits_per_rgb);
538 * Calculate number of 1 bits in mask
539 * Classic hack not written by this author.
542 mvOnes(unsigned long mask)
544 unsigned long y;
546 y = (mask >> 1) &033333333333;
547 y = mask - y - ((y >> 1) & 033333333333);
548 return (((y + (y >> 3)) & 030707070707) % 077);
552 * Calculate the number of shifts till we hit the mask
554 int
555 mvShifts(unsigned long mask)
557 int y = 0;
559 if (mask) {
560 while(!(mask&0x1)) {
561 mask = mask >> 1;
562 y++;
565 return y;
569 * find & creat a colmap struct for this cmap
570 * Assumes that colMaps was cleared before the first time
571 * it is called.
573 static MVColmap *
574 mvFindColormap(Colormap cmap)
576 MVColmap *pCmap;
577 /* if we've seen this cmap before, return its struct colmap */
578 for (pCmap = colMaps; pCmap; pCmap = pCmap->next) {
579 if (cmap == pCmap->cmap)
580 return pCmap;
582 /* First time for this cmap, creat & link */
583 pCmap = (MVColmap *) calloc(sizeof(MVColmap), 1);
584 pCmap->next = colMaps;
585 pCmap->cmap = cmap;
586 colMaps = pCmap;
587 return pCmap;
591 * Use pixel value at x, y as an index into
592 * the colmap's list of Colors.
593 * If the pixel value were not important, this would be called
594 * in mvDoWindowsFrontToBack(), with the pixel value
595 * and colmap as parameters, to get RGB values directly.
597 XColor *
598 mvFindColorInColormap(int x, int y)
600 MVPel *pPel = mvFindPel(x, y);
601 MVColmap *pCmap = pPel->colmap;
602 static XColor scratch;
604 if (pCmap->doComposite) { /* This is either True or DirectColor */
605 /* Treat the pixel value as 3 separate indices, composite
606 the color into scratch, return a pointer to scratch */
607 unsigned long pix = pPel->pixel;
608 unsigned long index = (pix & pCmap->red_mask) >> pCmap->rshft;
609 scratch.red=pCmap->Colors[(pix & pCmap->red_mask)>>pCmap->rshft].red;
610 scratch.green=pCmap->Colors[(pix & pCmap->green_mask)>>pCmap->gshft].green;
611 scratch.blue=pCmap->Colors[(pix & pCmap->blue_mask)>>pCmap->bshft].blue;
612 scratch.pixel=pix;
613 return(&scratch);
615 else { /* This is simple */
616 return &(pCmap->Colors[pPel->pixel]);