1 /***********************************************************
2
3 Copyright 1987, 1998 The Open Group
4
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in this Software without prior written authorization from The Open Group.
24
25 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
26
27 All Rights Reserved
28
29 Permission to use, copy, modify, and distribute this software and its
30 documentation for any purpose and without fee is hereby granted,
31 provided that the above copyright notice appear in all copies and that
32 both that copyright notice and this permission notice appear in
33 supporting documentation, and that the name of Digital not be
34 used in advertising or publicity pertaining to distribution of the
35 software without specific, written prior permission.
36
37 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
38 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
39 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
40 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
41 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
42 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
43 SOFTWARE.
44
45 ******************************************************************/
46 /*****************************************************************
47
48 Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts.
49
50 Permission is hereby granted, free of charge, to any person obtaining a copy
51 of this software and associated documentation files (the "Software"), to deal
52 in the Software without restriction, including without limitation the rights
53 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
54 copies of the Software.
55
56 The above copyright notice and this permission notice shall be included in
57 all copies or substantial portions of the Software.
58
59 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
60 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
61 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
62 DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
63 BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY,
64 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
65 IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
66
67 Except as contained in this notice, the name of Digital Equipment Corporation
68 shall not be used in advertising or otherwise to promote the sale, use or other
69 dealings in this Software without prior written authorization from Digital
70 Equipment Corporation.
71
72 ******************************************************************/
73
74 #ifdef HAVE_DIX_CONFIG_H
75 #include <dix-config.h>
76 #endif
77
78 #include <X11/X.h>
79 #include <X11/Xproto.h>
80 #include <X11/Xprotostr.h>
81
82 #include "misc.h"
83 #include "regionstr.h"
84 #include "scrnintstr.h"
85 #include "gcstruct.h"
86 #include "windowstr.h"
87 #include "pixmap.h"
88 #include "input.h"
89
90 #include "dixstruct.h"
91 #include "mi.h"
92 #include <X11/Xmd.h>
93
94 #include "globals.h"
95
96 #ifdef PANORAMIX
97 #include "panoramiX.h"
98 #include "panoramiXsrv.h"
99 #endif
100
101 /*
102 machine-independent graphics exposure code. any device that uses
103 the region package can call this.
104 */
105
106 #ifndef RECTLIMIT
107 #define RECTLIMIT 25 /* pick a number, any number > 8 */
108 #endif
109
110 /* miHandleExposures
111 generate a region for exposures for areas that were copied from obscured or
112 non-existent areas to non-obscured areas of the destination. Paint the
113 background for the region, if the destination is a window.
114
115 NOTE:
116 this should generally be called, even if graphicsExposures is false,
117 because this is where bits get recovered from backing store.
118
119 */
120
121 RegionPtr
miHandleExposures(DrawablePtr pSrcDrawable,DrawablePtr pDstDrawable,GCPtr pGC,int srcx,int srcy,int width,int height,int dstx,int dsty)122 miHandleExposures(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable,
123 GCPtr pGC, int srcx, int srcy, int width, int height,
124 int dstx, int dsty)
125 {
126 RegionPtr prgnSrcClip; /* drawable-relative source clip */
127 RegionRec rgnSrcRec;
128 RegionPtr prgnDstClip; /* drawable-relative dest clip */
129 RegionRec rgnDstRec;
130 BoxRec srcBox; /* unclipped source */
131 RegionRec rgnExposed; /* exposed region, calculated source-
132 relative, made dst relative to
133 intersect with visible parts of
134 dest and send events to client,
135 and then screen relative to paint
136 the window background
137 */
138 WindowPtr pSrcWin;
139 BoxRec expBox = { 0, };
140 Bool extents;
141
142 /* avoid work if we can */
143 if (!pGC->graphicsExposures &&
144 (pDstDrawable->type == DRAWABLE_PIXMAP) &&
145 ((pSrcDrawable->type == DRAWABLE_PIXMAP) ||
146 (((WindowPtr) pSrcDrawable)->backStorage == 0)))
147 return NULL;
148
149 srcBox.x1 = srcx;
150 srcBox.y1 = srcy;
151 srcBox.x2 = srcx + width;
152 srcBox.y2 = srcy + height;
153
154 if (pSrcDrawable->type != DRAWABLE_PIXMAP) {
155 BoxRec TsrcBox;
156
157 TsrcBox.x1 = srcx + pSrcDrawable->x;
158 TsrcBox.y1 = srcy + pSrcDrawable->y;
159 TsrcBox.x2 = TsrcBox.x1 + width;
160 TsrcBox.y2 = TsrcBox.y1 + height;
161 pSrcWin = (WindowPtr) pSrcDrawable;
162 if (pGC->subWindowMode == IncludeInferiors) {
163 prgnSrcClip = NotClippedByChildren(pSrcWin);
164 if ((RegionContainsRect(prgnSrcClip, &TsrcBox)) == rgnIN) {
165 RegionDestroy(prgnSrcClip);
166 return NULL;
167 }
168 }
169 else {
170 if ((RegionContainsRect(&pSrcWin->clipList, &TsrcBox)) == rgnIN)
171 return NULL;
172 prgnSrcClip = &rgnSrcRec;
173 RegionNull(prgnSrcClip);
174 RegionCopy(prgnSrcClip, &pSrcWin->clipList);
175 }
176 RegionTranslate(prgnSrcClip, -pSrcDrawable->x, -pSrcDrawable->y);
177 }
178 else {
179 BoxRec box;
180
181 if ((srcBox.x1 >= 0) && (srcBox.y1 >= 0) &&
182 (srcBox.x2 <= pSrcDrawable->width) &&
183 (srcBox.y2 <= pSrcDrawable->height))
184 return NULL;
185
186 box.x1 = 0;
187 box.y1 = 0;
188 box.x2 = pSrcDrawable->width;
189 box.y2 = pSrcDrawable->height;
190 prgnSrcClip = &rgnSrcRec;
191 RegionInit(prgnSrcClip, &box, 1);
192 pSrcWin = NULL;
193 }
194
195 if (pDstDrawable == pSrcDrawable) {
196 prgnDstClip = prgnSrcClip;
197 }
198 else if (pDstDrawable->type != DRAWABLE_PIXMAP) {
199 if (pGC->subWindowMode == IncludeInferiors) {
200 prgnDstClip = NotClippedByChildren((WindowPtr) pDstDrawable);
201 }
202 else {
203 prgnDstClip = &rgnDstRec;
204 RegionNull(prgnDstClip);
205 RegionCopy(prgnDstClip, &((WindowPtr) pDstDrawable)->clipList);
206 }
207 RegionTranslate(prgnDstClip, -pDstDrawable->x, -pDstDrawable->y);
208 }
209 else {
210 BoxRec box;
211
212 box.x1 = 0;
213 box.y1 = 0;
214 box.x2 = pDstDrawable->width;
215 box.y2 = pDstDrawable->height;
216 prgnDstClip = &rgnDstRec;
217 RegionInit(prgnDstClip, &box, 1);
218 }
219
220 /* drawable-relative source region */
221 RegionInit(&rgnExposed, &srcBox, 1);
222
223 /* now get the hidden parts of the source box */
224 RegionSubtract(&rgnExposed, &rgnExposed, prgnSrcClip);
225
226 /* move them over the destination */
227 RegionTranslate(&rgnExposed, dstx - srcx, dsty - srcy);
228
229 /* intersect with visible areas of dest */
230 RegionIntersect(&rgnExposed, &rgnExposed, prgnDstClip);
231
232 /* intersect with client clip region. */
233 if (pGC->clientClip)
234 RegionIntersect(&rgnExposed, &rgnExposed, pGC->clientClip);
235
236 /*
237 * If we have LOTS of rectangles, we decide to take the extents
238 * and force an exposure on that. This should require much less
239 * work overall, on both client and server. This is cheating, but
240 * isn't prohibited by the protocol ("spontaneous combustion" :-)
241 * for windows.
242 */
243 extents = pGC->graphicsExposures &&
244 (RegionNumRects(&rgnExposed) > RECTLIMIT) &&
245 (pDstDrawable->type != DRAWABLE_PIXMAP);
246 if (pSrcWin) {
247 RegionPtr region;
248
249 if (!(region = wClipShape(pSrcWin)))
250 region = wBoundingShape(pSrcWin);
251 /*
252 * If you try to CopyArea the extents of a shaped window, compacting the
253 * exposed region will undo all our work!
254 */
255 if (extents && pSrcWin && region &&
256 (RegionContainsRect(region, &srcBox) != rgnIN))
257 extents = FALSE;
258 }
259 if (extents) {
260 expBox = *RegionExtents(&rgnExposed);
261 RegionReset(&rgnExposed, &expBox);
262 }
263 if ((pDstDrawable->type != DRAWABLE_PIXMAP) &&
264 (((WindowPtr) pDstDrawable)->backgroundState != None)) {
265 WindowPtr pWin = (WindowPtr) pDstDrawable;
266
267 /* make the exposed area screen-relative */
268 RegionTranslate(&rgnExposed, pDstDrawable->x, pDstDrawable->y);
269
270 if (extents) {
271 /* PaintWindow doesn't clip, so we have to */
272 RegionIntersect(&rgnExposed, &rgnExposed, &pWin->clipList);
273 }
274 pDstDrawable->pScreen->PaintWindow((WindowPtr) pDstDrawable,
275 &rgnExposed, PW_BACKGROUND);
276
277 if (extents) {
278 RegionReset(&rgnExposed, &expBox);
279 }
280 else
281 RegionTranslate(&rgnExposed, -pDstDrawable->x, -pDstDrawable->y);
282 }
283 if (prgnDstClip == &rgnDstRec) {
284 RegionUninit(prgnDstClip);
285 }
286 else if (prgnDstClip != prgnSrcClip) {
287 RegionDestroy(prgnDstClip);
288 }
289
290 if (prgnSrcClip == &rgnSrcRec) {
291 RegionUninit(prgnSrcClip);
292 }
293 else {
294 RegionDestroy(prgnSrcClip);
295 }
296
297 if (pGC->graphicsExposures) {
298 /* don't look */
299 RegionPtr exposed = RegionCreate(NullBox, 0);
300
301 *exposed = rgnExposed;
302 return exposed;
303 }
304 else {
305 RegionUninit(&rgnExposed);
306 return NULL;
307 }
308 }
309
310 void
miSendExposures(WindowPtr pWin,RegionPtr pRgn,int dx,int dy)311 miSendExposures(WindowPtr pWin, RegionPtr pRgn, int dx, int dy)
312 {
313 BoxPtr pBox;
314 int numRects;
315 xEvent *pEvent, *pe;
316 int i;
317
318 pBox = RegionRects(pRgn);
319 numRects = RegionNumRects(pRgn);
320 if (!(pEvent = calloc(1, numRects * sizeof(xEvent))))
321 return;
322
323 for (i = numRects, pe = pEvent; --i >= 0; pe++, pBox++) {
324 pe->u.u.type = Expose;
325 pe->u.expose.window = pWin->drawable.id;
326 pe->u.expose.x = pBox->x1 - dx;
327 pe->u.expose.y = pBox->y1 - dy;
328 pe->u.expose.width = pBox->x2 - pBox->x1;
329 pe->u.expose.height = pBox->y2 - pBox->y1;
330 pe->u.expose.count = i;
331 }
332
333 #ifdef PANORAMIX
334 if (!noPanoramiXExtension) {
335 int scrnum = pWin->drawable.pScreen->myNum;
336 int x = 0, y = 0;
337 XID realWin = 0;
338
339 if (!pWin->parent) {
340 x = screenInfo.screens[scrnum]->x;
341 y = screenInfo.screens[scrnum]->y;
342 pWin = screenInfo.screens[0]->root;
343 realWin = pWin->drawable.id;
344 }
345 else if (scrnum) {
346 PanoramiXRes *win;
347
348 win = PanoramiXFindIDByScrnum(XRT_WINDOW,
349 pWin->drawable.id, scrnum);
350 if (!win) {
351 free(pEvent);
352 return;
353 }
354 realWin = win->info[0].id;
355 dixLookupWindow(&pWin, realWin, serverClient, DixSendAccess);
356 }
357 if (x || y || scrnum)
358 for (i = 0; i < numRects; i++) {
359 pEvent[i].u.expose.window = realWin;
360 pEvent[i].u.expose.x += x;
361 pEvent[i].u.expose.y += y;
362 }
363 }
364 #endif
365
366 DeliverEvents(pWin, pEvent, numRects, NullWindow);
367
368 free(pEvent);
369 }
370
371 void
miWindowExposures(WindowPtr pWin,RegionPtr prgn)372 miWindowExposures(WindowPtr pWin, RegionPtr prgn)
373 {
374 RegionPtr exposures = prgn;
375
376 if (prgn && !RegionNil(prgn)) {
377 RegionRec expRec;
378 int clientInterested =
379 (pWin->eventMask | wOtherEventMasks(pWin)) & ExposureMask;
380 if (clientInterested && (RegionNumRects(prgn) > RECTLIMIT)) {
381 /*
382 * If we have LOTS of rectangles, we decide to take the extents
383 * and force an exposure on that. This should require much less
384 * work overall, on both client and server. This is cheating, but
385 * isn't prohibited by the protocol ("spontaneous combustion" :-).
386 */
387 BoxRec box = *RegionExtents(prgn);
388 exposures = &expRec;
389 RegionInit(exposures, &box, 1);
390 RegionReset(prgn, &box);
391 /* miPaintWindow doesn't clip, so we have to */
392 RegionIntersect(prgn, prgn, &pWin->clipList);
393 }
394 pWin->drawable.pScreen->PaintWindow(pWin, prgn, PW_BACKGROUND);
395 if (clientInterested)
396 miSendExposures(pWin, exposures,
397 pWin->drawable.x, pWin->drawable.y);
398 if (exposures == &expRec)
399 RegionUninit(exposures);
400 RegionEmpty(prgn);
401 }
402 }
403
404 void
miPaintWindow(WindowPtr pWin,RegionPtr prgn,int what)405 miPaintWindow(WindowPtr pWin, RegionPtr prgn, int what)
406 {
407 ScreenPtr pScreen = pWin->drawable.pScreen;
408 ChangeGCVal gcval[6];
409 BITS32 gcmask;
410 GCPtr pGC;
411 int i;
412 BoxPtr pbox;
413 xRectangle *prect;
414 int numRects;
415
416 /*
417 * Distance from screen to destination drawable, use this
418 * to adjust rendering coordinates which come in in screen space
419 */
420 int draw_x_off, draw_y_off;
421
422 /*
423 * Tile offset for drawing; these need to align the tile
424 * to the appropriate window origin
425 */
426 int tile_x_off, tile_y_off;
427 PixUnion fill;
428 Bool solid = TRUE;
429 DrawablePtr drawable = &pWin->drawable;
430
431 if (what == PW_BACKGROUND) {
432 while (pWin->backgroundState == ParentRelative)
433 pWin = pWin->parent;
434
435 draw_x_off = drawable->x;
436 draw_y_off = drawable->y;
437
438 tile_x_off = pWin->drawable.x - draw_x_off;
439 tile_y_off = pWin->drawable.y - draw_y_off;
440 fill = pWin->background;
441 #ifdef COMPOSITE
442 if (pWin->inhibitBGPaint)
443 return;
444 #endif
445 switch (pWin->backgroundState) {
446 case None:
447 return;
448 case BackgroundPixmap:
449 solid = FALSE;
450 break;
451 }
452 }
453 else {
454 PixmapPtr pixmap;
455
456 fill = pWin->border;
457 solid = pWin->borderIsPixel;
458
459 /* servers without pixmaps draw their own borders */
460 if (!pScreen->GetWindowPixmap)
461 return;
462 pixmap = (*pScreen->GetWindowPixmap) ((WindowPtr) drawable);
463 drawable = &pixmap->drawable;
464
465 while (pWin->backgroundState == ParentRelative)
466 pWin = pWin->parent;
467
468 tile_x_off = pWin->drawable.x;
469 tile_y_off = pWin->drawable.y;
470
471 #ifdef COMPOSITE
472 draw_x_off = pixmap->screen_x;
473 draw_y_off = pixmap->screen_y;
474 tile_x_off -= draw_x_off;
475 tile_y_off -= draw_y_off;
476 #else
477 draw_x_off = 0;
478 draw_y_off = 0;
479 #endif
480 }
481
482 gcval[0].val = GXcopy;
483 gcmask = GCFunction;
484
485 #ifdef ROOTLESS_SAFEALPHA
486 /* Bit mask for alpha channel with a particular number of bits per
487 * pixel. Note that we only care for 32bpp data. Mac OS X uses planar
488 * alpha for 16bpp.
489 */
490 #define RootlessAlphaMask(bpp) ((bpp) == 32 ? 0xFF000000 : 0)
491 #endif
492
493 if (solid) {
494 #ifdef ROOTLESS_SAFEALPHA
495 gcval[1].val =
496 fill.pixel | RootlessAlphaMask(pWin->drawable.bitsPerPixel);
497 #else
498 gcval[1].val = fill.pixel;
499 #endif
500 gcval[2].val = FillSolid;
501 gcmask |= GCForeground | GCFillStyle;
502 }
503 else {
504 int c = 1;
505
506 #ifdef ROOTLESS_SAFEALPHA
507 gcval[c++].val =
508 ((CARD32) -1) & ~RootlessAlphaMask(pWin->drawable.bitsPerPixel);
509 gcmask |= GCPlaneMask;
510 #endif
511 gcval[c++].val = FillTiled;
512 gcval[c++].ptr = (void *) fill.pixmap;
513 gcval[c++].val = tile_x_off;
514 gcval[c++].val = tile_y_off;
515 gcmask |= GCFillStyle | GCTile | GCTileStipXOrigin | GCTileStipYOrigin;
516 }
517
518 prect = xallocarray(RegionNumRects(prgn), sizeof(xRectangle));
519 if (!prect)
520 return;
521
522 pGC = GetScratchGC(drawable->depth, drawable->pScreen);
523 if (!pGC) {
524 free(prect);
525 return;
526 }
527
528 ChangeGC(NullClient, pGC, gcmask, gcval);
529 ValidateGC(drawable, pGC);
530
531 numRects = RegionNumRects(prgn);
532 pbox = RegionRects(prgn);
533 for (i = numRects; --i >= 0; pbox++, prect++) {
534 prect->x = pbox->x1 - draw_x_off;
535 prect->y = pbox->y1 - draw_y_off;
536 prect->width = pbox->x2 - pbox->x1;
537 prect->height = pbox->y2 - pbox->y1;
538 }
539 prect -= numRects;
540 (*pGC->ops->PolyFillRect) (drawable, pGC, numRects, prect);
541 free(prect);
542
543 FreeScratchGC(pGC);
544 }
545
546 /* MICLEARDRAWABLE -- sets the entire drawable to the background color of
547 * the GC. Useful when we have a scratch drawable and need to initialize
548 * it. */
549 void
miClearDrawable(DrawablePtr pDraw,GCPtr pGC)550 miClearDrawable(DrawablePtr pDraw, GCPtr pGC)
551 {
552 ChangeGCVal fg, bg;
553 xRectangle rect;
554
555 fg.val = pGC->fgPixel;
556 bg.val = pGC->bgPixel;
557 rect.x = 0;
558 rect.y = 0;
559 rect.width = pDraw->width;
560 rect.height = pDraw->height;
561 ChangeGC(NullClient, pGC, GCForeground, &bg);
562 ValidateGC(pDraw, pGC);
563 (*pGC->ops->PolyFillRect) (pDraw, pGC, 1, &rect);
564 ChangeGC(NullClient, pGC, GCForeground, &fg);
565 ValidateGC(pDraw, pGC);
566 }
567