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