1/*
2
3Copyright 1993 by Davor Matic
4
5Permission to use, copy, modify, distribute, and sell this software
6and its documentation for any purpose is hereby granted without fee,
7provided that the above copyright notice appear in all copies and that
8both that copyright notice and this permission notice appear in
9supporting documentation.  Davor Matic makes no representations about
10the suitability of this software for any purpose.  It is provided "as
11is" without express or implied warranty.
12
13*/
14
15#ifdef HAVE_XNEST_CONFIG_H
16#include <xnest-config.h>
17#endif
18
19#include <X11/X.h>
20#include <X11/Xproto.h>
21#include "gcstruct.h"
22#include "window.h"
23#include "windowstr.h"
24#include "pixmapstr.h"
25#include "colormapst.h"
26#include "scrnintstr.h"
27#include "region.h"
28
29#include "mi.h"
30
31#include "Xnest.h"
32
33#include "Display.h"
34#include "Screen.h"
35#include "XNGC.h"
36#include "Drawable.h"
37#include "Color.h"
38#include "Visual.h"
39#include "Events.h"
40#include "Args.h"
41
42DevPrivateKeyRec xnestWindowPrivateKeyRec;
43
44static int
45xnestFindWindowMatch(WindowPtr pWin, void *ptr)
46{
47    xnestWindowMatch *wm = (xnestWindowMatch *) ptr;
48
49    if (wm->window == xnestWindow(pWin)) {
50        wm->pWin = pWin;
51        return WT_STOPWALKING;
52    }
53    else
54        return WT_WALKCHILDREN;
55}
56
57WindowPtr
58xnestWindowPtr(Window window)
59{
60    xnestWindowMatch wm;
61    int i;
62
63    wm.pWin = NullWindow;
64    wm.window = window;
65
66    for (i = 0; i < xnestNumScreens; i++) {
67        WalkTree(screenInfo.screens[i], xnestFindWindowMatch, (void *) &wm);
68        if (wm.pWin)
69            break;
70    }
71
72    return wm.pWin;
73}
74
75Bool
76xnestCreateWindow(WindowPtr pWin)
77{
78    unsigned long mask;
79    XSetWindowAttributes attributes;
80    Visual *visual;
81    ColormapPtr pCmap;
82
83    if (pWin->drawable.class == InputOnly) {
84        mask = 0L;
85        visual = CopyFromParent;
86    }
87    else {
88        mask = CWEventMask | CWBackingStore;
89        attributes.event_mask = ExposureMask;
90        attributes.backing_store = NotUseful;
91
92        if (pWin->parent) {
93            if (pWin->optional &&
94                pWin->optional->visual != wVisual(pWin->parent)) {
95                visual =
96                    xnestVisualFromID(pWin->drawable.pScreen, wVisual(pWin));
97                mask |= CWColormap;
98                if (pWin->optional->colormap) {
99                    dixLookupResourceByType((void **) &pCmap, wColormap(pWin),
100                                            RT_COLORMAP, serverClient,
101                                            DixUseAccess);
102                    attributes.colormap = xnestColormap(pCmap);
103                }
104                else
105                    attributes.colormap = xnestDefaultVisualColormap(visual);
106            }
107            else
108                visual = CopyFromParent;
109        }
110        else {                  /* root windows have their own colormaps at creation time */
111            visual = xnestVisualFromID(pWin->drawable.pScreen, wVisual(pWin));
112            dixLookupResourceByType((void **) &pCmap, wColormap(pWin),
113                                    RT_COLORMAP, serverClient, DixUseAccess);
114            mask |= CWColormap;
115            attributes.colormap = xnestColormap(pCmap);
116        }
117    }
118
119    xnestWindowPriv(pWin)->window = XCreateWindow(xnestDisplay,
120                                                  xnestWindowParent(pWin),
121                                                  pWin->origin.x -
122                                                  wBorderWidth(pWin),
123                                                  pWin->origin.y -
124                                                  wBorderWidth(pWin),
125                                                  pWin->drawable.width,
126                                                  pWin->drawable.height,
127                                                  pWin->borderWidth,
128                                                  pWin->drawable.depth,
129                                                  pWin->drawable.class,
130                                                  visual, mask, &attributes);
131    xnestWindowPriv(pWin)->parent = xnestWindowParent(pWin);
132    xnestWindowPriv(pWin)->x = pWin->origin.x - wBorderWidth(pWin);
133    xnestWindowPriv(pWin)->y = pWin->origin.y - wBorderWidth(pWin);
134    xnestWindowPriv(pWin)->width = pWin->drawable.width;
135    xnestWindowPriv(pWin)->height = pWin->drawable.height;
136    xnestWindowPriv(pWin)->border_width = pWin->borderWidth;
137    xnestWindowPriv(pWin)->sibling_above = None;
138    if (pWin->nextSib)
139        xnestWindowPriv(pWin->nextSib)->sibling_above = xnestWindow(pWin);
140    xnestWindowPriv(pWin)->bounding_shape = RegionCreate(NULL, 1);
141    xnestWindowPriv(pWin)->clip_shape = RegionCreate(NULL, 1);
142
143    if (!pWin->parent)          /* only the root window will have the right colormap */
144        xnestSetInstalledColormapWindows(pWin->drawable.pScreen);
145
146    return True;
147}
148
149Bool
150xnestDestroyWindow(WindowPtr pWin)
151{
152    if (pWin->nextSib)
153        xnestWindowPriv(pWin->nextSib)->sibling_above =
154            xnestWindowPriv(pWin)->sibling_above;
155    RegionDestroy(xnestWindowPriv(pWin)->bounding_shape);
156    RegionDestroy(xnestWindowPriv(pWin)->clip_shape);
157    XDestroyWindow(xnestDisplay, xnestWindow(pWin));
158    xnestWindowPriv(pWin)->window = None;
159
160    if (pWin->optional && pWin->optional->colormap && pWin->parent)
161        xnestSetInstalledColormapWindows(pWin->drawable.pScreen);
162
163    return True;
164}
165
166Bool
167xnestPositionWindow(WindowPtr pWin, int x, int y)
168{
169    xnestConfigureWindow(pWin,
170                         CWParent |
171                         CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
172
173    return True;
174}
175
176void
177xnestConfigureWindow(WindowPtr pWin, unsigned int mask)
178{
179    unsigned int valuemask;
180    XWindowChanges values;
181
182    if (mask & CWParent &&
183        xnestWindowPriv(pWin)->parent != xnestWindowParent(pWin)) {
184        XReparentWindow(xnestDisplay, xnestWindow(pWin),
185                        xnestWindowParent(pWin),
186                        pWin->origin.x - wBorderWidth(pWin),
187                        pWin->origin.y - wBorderWidth(pWin));
188        xnestWindowPriv(pWin)->parent = xnestWindowParent(pWin);
189        xnestWindowPriv(pWin)->x = pWin->origin.x - wBorderWidth(pWin);
190        xnestWindowPriv(pWin)->y = pWin->origin.y - wBorderWidth(pWin);
191        xnestWindowPriv(pWin)->sibling_above = None;
192        if (pWin->nextSib)
193            xnestWindowPriv(pWin->nextSib)->sibling_above = xnestWindow(pWin);
194    }
195
196    valuemask = 0;
197
198    if (mask & CWX &&
199        xnestWindowPriv(pWin)->x != pWin->origin.x - wBorderWidth(pWin)) {
200        valuemask |= CWX;
201        values.x =
202            xnestWindowPriv(pWin)->x = pWin->origin.x - wBorderWidth(pWin);
203    }
204
205    if (mask & CWY &&
206        xnestWindowPriv(pWin)->y != pWin->origin.y - wBorderWidth(pWin)) {
207        valuemask |= CWY;
208        values.y =
209            xnestWindowPriv(pWin)->y = pWin->origin.y - wBorderWidth(pWin);
210    }
211
212    if (mask & CWWidth && xnestWindowPriv(pWin)->width != pWin->drawable.width) {
213        valuemask |= CWWidth;
214        values.width = xnestWindowPriv(pWin)->width = pWin->drawable.width;
215    }
216
217    if (mask & CWHeight &&
218        xnestWindowPriv(pWin)->height != pWin->drawable.height) {
219        valuemask |= CWHeight;
220        values.height = xnestWindowPriv(pWin)->height = pWin->drawable.height;
221    }
222
223    if (mask & CWBorderWidth &&
224        xnestWindowPriv(pWin)->border_width != pWin->borderWidth) {
225        valuemask |= CWBorderWidth;
226        values.border_width =
227            xnestWindowPriv(pWin)->border_width = pWin->borderWidth;
228    }
229
230    if (valuemask)
231        XConfigureWindow(xnestDisplay, xnestWindow(pWin), valuemask, &values);
232
233    if (mask & CWStackingOrder &&
234        xnestWindowPriv(pWin)->sibling_above != xnestWindowSiblingAbove(pWin)) {
235        WindowPtr pSib;
236
237        /* find the top sibling */
238        for (pSib = pWin; pSib->prevSib != NullWindow; pSib = pSib->prevSib);
239
240        /* the top sibling */
241        valuemask = CWStackMode;
242        values.stack_mode = Above;
243        XConfigureWindow(xnestDisplay, xnestWindow(pSib), valuemask, &values);
244        xnestWindowPriv(pSib)->sibling_above = None;
245
246        /* the rest of siblings */
247        for (pSib = pSib->nextSib; pSib != NullWindow; pSib = pSib->nextSib) {
248            valuemask = CWSibling | CWStackMode;
249            values.sibling = xnestWindowSiblingAbove(pSib);
250            values.stack_mode = Below;
251            XConfigureWindow(xnestDisplay, xnestWindow(pSib), valuemask,
252                             &values);
253            xnestWindowPriv(pSib)->sibling_above =
254                xnestWindowSiblingAbove(pSib);
255        }
256    }
257}
258
259Bool
260xnestChangeWindowAttributes(WindowPtr pWin, unsigned long mask)
261{
262    XSetWindowAttributes attributes;
263
264    if (mask & CWBackPixmap)
265        switch (pWin->backgroundState) {
266        case None:
267            attributes.background_pixmap = None;
268            break;
269
270        case ParentRelative:
271            attributes.background_pixmap = ParentRelative;
272            break;
273
274        case BackgroundPixmap:
275            attributes.background_pixmap = xnestPixmap(pWin->background.pixmap);
276            break;
277
278        case BackgroundPixel:
279            mask &= ~CWBackPixmap;
280            break;
281        }
282
283    if (mask & CWBackPixel) {
284        if (pWin->backgroundState == BackgroundPixel)
285            attributes.background_pixel = xnestPixel(pWin->background.pixel);
286        else
287            mask &= ~CWBackPixel;
288    }
289
290    if (mask & CWBorderPixmap) {
291        if (pWin->borderIsPixel)
292            mask &= ~CWBorderPixmap;
293        else
294            attributes.border_pixmap = xnestPixmap(pWin->border.pixmap);
295    }
296
297    if (mask & CWBorderPixel) {
298        if (pWin->borderIsPixel)
299            attributes.border_pixel = xnestPixel(pWin->border.pixel);
300        else
301            mask &= ~CWBorderPixel;
302    }
303
304    if (mask & CWBitGravity)
305        attributes.bit_gravity = pWin->bitGravity;
306
307    if (mask & CWWinGravity)    /* dix does this for us */
308        mask &= ~CWWinGravity;
309
310    if (mask & CWBackingStore)  /* this is really not useful */
311        mask &= ~CWBackingStore;
312
313    if (mask & CWBackingPlanes) /* this is really not useful */
314        mask &= ~CWBackingPlanes;
315
316    if (mask & CWBackingPixel)  /* this is really not useful */
317        mask &= ~CWBackingPixel;
318
319    if (mask & CWOverrideRedirect)
320        attributes.override_redirect = pWin->overrideRedirect;
321
322    if (mask & CWSaveUnder)     /* this is really not useful */
323        mask &= ~CWSaveUnder;
324
325    if (mask & CWEventMask)     /* events are handled elsewhere */
326        mask &= ~CWEventMask;
327
328    if (mask & CWDontPropagate) /* events are handled elsewhere */
329        mask &= ~CWDontPropagate;
330
331    if (mask & CWColormap) {
332        ColormapPtr pCmap;
333
334        dixLookupResourceByType((void **) &pCmap, wColormap(pWin),
335                                RT_COLORMAP, serverClient, DixUseAccess);
336
337        attributes.colormap = xnestColormap(pCmap);
338
339        xnestSetInstalledColormapWindows(pWin->drawable.pScreen);
340    }
341
342    if (mask & CWCursor)        /* this is handled in cursor code */
343        mask &= ~CWCursor;
344
345    if (mask)
346        XChangeWindowAttributes(xnestDisplay, xnestWindow(pWin),
347                                mask, &attributes);
348
349    return True;
350}
351
352Bool
353xnestRealizeWindow(WindowPtr pWin)
354{
355    xnestConfigureWindow(pWin, CWStackingOrder);
356    xnestShapeWindow(pWin);
357    XMapWindow(xnestDisplay, xnestWindow(pWin));
358
359    return True;
360}
361
362Bool
363xnestUnrealizeWindow(WindowPtr pWin)
364{
365    XUnmapWindow(xnestDisplay, xnestWindow(pWin));
366
367    return True;
368}
369
370void
371xnestCopyWindow(WindowPtr pWin, xPoint oldOrigin, RegionPtr oldRegion)
372{
373}
374
375void
376xnestClipNotify(WindowPtr pWin, int dx, int dy)
377{
378    xnestConfigureWindow(pWin, CWStackingOrder);
379    xnestShapeWindow(pWin);
380}
381
382static Bool
383xnestWindowExposurePredicate(Display * dpy, XEvent * event, XPointer ptr)
384{
385    return (event->type == Expose && event->xexpose.window == *(Window *) ptr);
386}
387
388void
389xnestWindowExposures(WindowPtr pWin, RegionPtr pRgn)
390{
391    XEvent event;
392    Window window;
393    BoxRec Box;
394
395    XSync(xnestDisplay, False);
396
397    window = xnestWindow(pWin);
398
399    while (XCheckIfEvent(xnestDisplay, &event,
400                         xnestWindowExposurePredicate, (char *) &window)) {
401
402        Box.x1 = pWin->drawable.x + wBorderWidth(pWin) + event.xexpose.x;
403        Box.y1 = pWin->drawable.y + wBorderWidth(pWin) + event.xexpose.y;
404        Box.x2 = Box.x1 + event.xexpose.width;
405        Box.y2 = Box.y1 + event.xexpose.height;
406
407        event.xexpose.type = ProcessedExpose;
408
409        if (RegionContainsRect(pRgn, &Box) != rgnIN)
410            XPutBackEvent(xnestDisplay, &event);
411    }
412
413    miWindowExposures(pWin, pRgn);
414}
415
416void
417xnestSetShape(WindowPtr pWin, int kind)
418{
419    xnestShapeWindow(pWin);
420    miSetShape(pWin, kind);
421}
422
423static Bool
424xnestRegionEqual(RegionPtr pReg1, RegionPtr pReg2)
425{
426    BoxPtr pBox1, pBox2;
427    unsigned int n1, n2;
428
429    if (pReg1 == pReg2)
430        return True;
431
432    if (pReg1 == NullRegion || pReg2 == NullRegion)
433        return False;
434
435    pBox1 = RegionRects(pReg1);
436    n1 = RegionNumRects(pReg1);
437
438    pBox2 = RegionRects(pReg2);
439    n2 = RegionNumRects(pReg2);
440
441    if (n1 != n2)
442        return False;
443
444    if (pBox1 == pBox2)
445        return True;
446
447    if (memcmp(pBox1, pBox2, n1 * sizeof(BoxRec)))
448        return False;
449
450    return True;
451}
452
453void
454xnestShapeWindow(WindowPtr pWin)
455{
456    Region reg;
457    BoxPtr pBox;
458    XRectangle rect;
459    int i;
460
461    if (!xnestRegionEqual(xnestWindowPriv(pWin)->bounding_shape,
462                          wBoundingShape(pWin))) {
463
464        if (wBoundingShape(pWin)) {
465            RegionCopy(xnestWindowPriv(pWin)->bounding_shape,
466                       wBoundingShape(pWin));
467
468            reg = XCreateRegion();
469            pBox = RegionRects(xnestWindowPriv(pWin)->bounding_shape);
470            for (i = 0;
471                 i < RegionNumRects(xnestWindowPriv(pWin)->bounding_shape);
472                 i++) {
473                rect.x = pBox[i].x1;
474                rect.y = pBox[i].y1;
475                rect.width = pBox[i].x2 - pBox[i].x1;
476                rect.height = pBox[i].y2 - pBox[i].y1;
477                XUnionRectWithRegion(&rect, reg, reg);
478            }
479            XShapeCombineRegion(xnestDisplay, xnestWindow(pWin),
480                                ShapeBounding, 0, 0, reg, ShapeSet);
481            XDestroyRegion(reg);
482        }
483        else {
484            RegionEmpty(xnestWindowPriv(pWin)->bounding_shape);
485
486            XShapeCombineMask(xnestDisplay, xnestWindow(pWin),
487                              ShapeBounding, 0, 0, None, ShapeSet);
488        }
489    }
490
491    if (!xnestRegionEqual(xnestWindowPriv(pWin)->clip_shape, wClipShape(pWin))) {
492
493        if (wClipShape(pWin)) {
494            RegionCopy(xnestWindowPriv(pWin)->clip_shape, wClipShape(pWin));
495
496            reg = XCreateRegion();
497            pBox = RegionRects(xnestWindowPriv(pWin)->clip_shape);
498            for (i = 0;
499                 i < RegionNumRects(xnestWindowPriv(pWin)->clip_shape); i++) {
500                rect.x = pBox[i].x1;
501                rect.y = pBox[i].y1;
502                rect.width = pBox[i].x2 - pBox[i].x1;
503                rect.height = pBox[i].y2 - pBox[i].y1;
504                XUnionRectWithRegion(&rect, reg, reg);
505            }
506            XShapeCombineRegion(xnestDisplay, xnestWindow(pWin),
507                                ShapeClip, 0, 0, reg, ShapeSet);
508            XDestroyRegion(reg);
509        }
510        else {
511            RegionEmpty(xnestWindowPriv(pWin)->clip_shape);
512
513            XShapeCombineMask(xnestDisplay, xnestWindow(pWin),
514                              ShapeClip, 0, 0, None, ShapeSet);
515        }
516    }
517}
518