1 /*
2 
3 Copyright 1993 by Davor Matic
4 
5 Permission to use, copy, modify, distribute, and sell this software
6 and its documentation for any purpose is hereby granted without fee,
7 provided that the above copyright notice appear in all copies and that
8 both that copyright notice and this permission notice appear in
9 supporting documentation.  Davor Matic makes no representations about
10 the suitability of this software for any purpose.  It is provided "as
11 is" 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 
42 DevPrivateKeyRec xnestWindowPrivateKeyRec;
43 
44 static int
xnestFindWindowMatch(WindowPtr pWin,void * ptr)45 xnestFindWindowMatch(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 
57 WindowPtr
xnestWindowPtr(Window window)58 xnestWindowPtr(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 
75 Bool
xnestCreateWindow(WindowPtr pWin)76 xnestCreateWindow(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 
149 Bool
xnestDestroyWindow(WindowPtr pWin)150 xnestDestroyWindow(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 
166 Bool
xnestPositionWindow(WindowPtr pWin,int x,int y)167 xnestPositionWindow(WindowPtr pWin, int x, int y)
168 {
169     xnestConfigureWindow(pWin,
170                          CWParent |
171                          CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
172 
173     return True;
174 }
175 
176 void
xnestConfigureWindow(WindowPtr pWin,unsigned int mask)177 xnestConfigureWindow(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 
259 Bool
xnestChangeWindowAttributes(WindowPtr pWin,unsigned long mask)260 xnestChangeWindowAttributes(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 
352 Bool
xnestRealizeWindow(WindowPtr pWin)353 xnestRealizeWindow(WindowPtr pWin)
354 {
355     xnestConfigureWindow(pWin, CWStackingOrder);
356     xnestShapeWindow(pWin);
357     XMapWindow(xnestDisplay, xnestWindow(pWin));
358 
359     return True;
360 }
361 
362 Bool
xnestUnrealizeWindow(WindowPtr pWin)363 xnestUnrealizeWindow(WindowPtr pWin)
364 {
365     XUnmapWindow(xnestDisplay, xnestWindow(pWin));
366 
367     return True;
368 }
369 
370 void
xnestCopyWindow(WindowPtr pWin,xPoint oldOrigin,RegionPtr oldRegion)371 xnestCopyWindow(WindowPtr pWin, xPoint oldOrigin, RegionPtr oldRegion)
372 {
373 }
374 
375 void
xnestClipNotify(WindowPtr pWin,int dx,int dy)376 xnestClipNotify(WindowPtr pWin, int dx, int dy)
377 {
378     xnestConfigureWindow(pWin, CWStackingOrder);
379     xnestShapeWindow(pWin);
380 }
381 
382 static Bool
xnestWindowExposurePredicate(Display * dpy,XEvent * event,XPointer ptr)383 xnestWindowExposurePredicate(Display * dpy, XEvent * event, XPointer ptr)
384 {
385     return (event->type == Expose && event->xexpose.window == *(Window *) ptr);
386 }
387 
388 void
xnestWindowExposures(WindowPtr pWin,RegionPtr pRgn)389 xnestWindowExposures(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 
416 void
xnestSetShape(WindowPtr pWin,int kind)417 xnestSetShape(WindowPtr pWin, int kind)
418 {
419     xnestShapeWindow(pWin);
420     miSetShape(pWin, kind);
421 }
422 
423 static Bool
xnestRegionEqual(RegionPtr pReg1,RegionPtr pReg2)424 xnestRegionEqual(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 
453 void
xnestShapeWindow(WindowPtr pWin)454 xnestShapeWindow(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