Imported Upstream version 1.15.1
[deb_xorg-server.git] / hw / xnest / Window.c
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
45 xnestFindWindowMatch(WindowPtr pWin, pointer 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
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, (pointer) &wm);
68 if (wm.pWin)
69 break;
70 }
71
72 return wm.pWin;
73 }
74
75 Bool
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((pointer *) &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((pointer *) &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
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
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
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
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((pointer *) &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 handeled 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
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
363 xnestUnrealizeWindow(WindowPtr pWin)
364 {
365 XUnmapWindow(xnestDisplay, xnestWindow(pWin));
366
367 return True;
368 }
369
370 void
371 xnestCopyWindow(WindowPtr pWin, xPoint oldOrigin, RegionPtr oldRegion)
372 {
373 }
374
375 void
376 xnestClipNotify(WindowPtr pWin, int dx, int dy)
377 {
378 xnestConfigureWindow(pWin, CWStackingOrder);
379 xnestShapeWindow(pWin);
380 }
381
382 static Bool
383 xnestWindowExposurePredicate(Display * display, XEvent * event, XPointer ptr)
384 {
385 return (event->type == Expose && event->xexpose.window == *(Window *) ptr);
386 }
387
388 void
389 xnestWindowExposures(WindowPtr pWin, RegionPtr pRgn, RegionPtr other_exposed)
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, other_exposed);
414 }
415
416 void
417 xnestSetShape(WindowPtr pWin, int kind)
418 {
419 xnestShapeWindow(pWin);
420 miSetShape(pWin, kind);
421 }
422
423 static Bool
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
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 }