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, pointer ptr)
46{
47  xnestWindowMatch *wm = (xnestWindowMatch *)ptr;
48  if (wm->window == xnestWindow(pWin)) {
49    wm->pWin = pWin;
50    return WT_STOPWALKING;
51  }
52  else
53    return WT_WALKCHILDREN;
54}
55
56WindowPtr
57xnestWindowPtr(Window window)
58{
59  xnestWindowMatch wm;
60  int i;
61
62  wm.pWin = NullWindow;
63  wm.window = window;
64
65  for (i = 0; i < xnestNumScreens; i++) {
66    WalkTree(screenInfo.screens[i], xnestFindWindowMatch, (pointer) &wm);
67    if (wm.pWin) break;
68  }
69
70  return wm.pWin;
71}
72
73Bool
74xnestCreateWindow(WindowPtr pWin)
75{
76  unsigned long mask;
77  XSetWindowAttributes attributes;
78  Visual *visual;
79  ColormapPtr pCmap;
80
81  if (pWin->drawable.class == InputOnly) {
82    mask = 0L;
83    visual = CopyFromParent;
84  }
85  else {
86    mask = CWEventMask | CWBackingStore;
87    attributes.event_mask = ExposureMask;
88    attributes.backing_store = NotUseful;
89
90    if (pWin->parent) {
91      if (pWin->optional && pWin->optional->visual != wVisual(pWin->parent)) {
92	visual = xnestVisualFromID(pWin->drawable.pScreen, wVisual(pWin));
93	mask |= CWColormap;
94	if (pWin->optional->colormap) {
95	  dixLookupResourceByType((pointer *)&pCmap, wColormap(pWin),
96				  RT_COLORMAP, serverClient, DixUseAccess);
97	  attributes.colormap = xnestColormap(pCmap);
98	}
99	else
100	  attributes.colormap = xnestDefaultVisualColormap(visual);
101      }
102      else
103	visual = CopyFromParent;
104    }
105    else { /* root windows have their own colormaps at creation time */
106      visual = xnestVisualFromID(pWin->drawable.pScreen, wVisual(pWin));
107      dixLookupResourceByType((pointer *)&pCmap, wColormap(pWin),
108			      RT_COLORMAP, serverClient, DixUseAccess);
109      mask |= CWColormap;
110      attributes.colormap = xnestColormap(pCmap);
111    }
112  }
113
114  xnestWindowPriv(pWin)->window = XCreateWindow(xnestDisplay,
115						xnestWindowParent(pWin),
116						pWin->origin.x -
117						wBorderWidth(pWin),
118						pWin->origin.y -
119						wBorderWidth(pWin),
120						pWin->drawable.width,
121						pWin->drawable.height,
122						pWin->borderWidth,
123						pWin->drawable.depth,
124						pWin->drawable.class,
125						visual,
126						mask, &attributes);
127  xnestWindowPriv(pWin)->parent = xnestWindowParent(pWin);
128  xnestWindowPriv(pWin)->x = pWin->origin.x - wBorderWidth(pWin);
129  xnestWindowPriv(pWin)->y = pWin->origin.y - wBorderWidth(pWin);
130  xnestWindowPriv(pWin)->width = pWin->drawable.width;
131  xnestWindowPriv(pWin)->height = pWin->drawable.height;
132  xnestWindowPriv(pWin)->border_width = pWin->borderWidth;
133  xnestWindowPriv(pWin)->sibling_above = None;
134  if (pWin->nextSib)
135    xnestWindowPriv(pWin->nextSib)->sibling_above = xnestWindow(pWin);
136  xnestWindowPriv(pWin)->bounding_shape =
137    RegionCreate(NULL, 1);
138  xnestWindowPriv(pWin)->clip_shape =
139    RegionCreate(NULL, 1);
140
141  if (!pWin->parent) /* only the root window will have the right colormap */
142    xnestSetInstalledColormapWindows(pWin->drawable.pScreen);
143
144  return True;
145}
146
147Bool
148xnestDestroyWindow(WindowPtr pWin)
149{
150  if (pWin->nextSib)
151    xnestWindowPriv(pWin->nextSib)->sibling_above =
152      xnestWindowPriv(pWin)->sibling_above;
153  RegionDestroy(xnestWindowPriv(pWin)->bounding_shape);
154  RegionDestroy(xnestWindowPriv(pWin)->clip_shape);
155  XDestroyWindow(xnestDisplay, xnestWindow(pWin));
156  xnestWindowPriv(pWin)->window = None;
157
158  if (pWin->optional && pWin->optional->colormap && pWin->parent)
159    xnestSetInstalledColormapWindows(pWin->drawable.pScreen);
160
161  return True;
162}
163
164Bool
165xnestPositionWindow(WindowPtr pWin, int x, int y)
166{
167  xnestConfigureWindow(pWin,
168		       CWParent |
169		       CWX | CWY |
170		       CWWidth | CWHeight |
171		       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 =
203	pWin->origin.x - wBorderWidth(pWin);
204  }
205
206  if (mask & CWY &&
207      xnestWindowPriv(pWin)->y != pWin->origin.y - wBorderWidth(pWin)) {
208    valuemask |= CWY;
209    values.y =
210      xnestWindowPriv(pWin)->y =
211	pWin->origin.y - wBorderWidth(pWin);
212  }
213
214  if (mask & CWWidth &&
215      xnestWindowPriv(pWin)->width != pWin->drawable.width) {
216    valuemask |= CWWidth;
217    values.width =
218      xnestWindowPriv(pWin)->width =
219	pWin->drawable.width;
220  }
221
222  if (mask & CWHeight &&
223      xnestWindowPriv(pWin)->height != pWin->drawable.height) {
224    valuemask |= CWHeight;
225    values.height =
226      xnestWindowPriv(pWin)->height =
227	pWin->drawable.height;
228  }
229
230  if (mask & CWBorderWidth &&
231      xnestWindowPriv(pWin)->border_width != pWin->borderWidth) {
232    valuemask |= CWBorderWidth;
233    values.border_width =
234      xnestWindowPriv(pWin)->border_width =
235	pWin->borderWidth;
236  }
237
238  if (valuemask)
239    XConfigureWindow(xnestDisplay, xnestWindow(pWin), valuemask, &values);
240
241  if (mask & CWStackingOrder &&
242      xnestWindowPriv(pWin)->sibling_above != xnestWindowSiblingAbove(pWin)) {
243    WindowPtr pSib;
244
245    /* find the top sibling */
246    for (pSib = pWin; pSib->prevSib != NullWindow; pSib = pSib->prevSib);
247
248    /* the top sibling */
249    valuemask = CWStackMode;
250    values.stack_mode = Above;
251    XConfigureWindow(xnestDisplay, xnestWindow(pSib), valuemask, &values);
252    xnestWindowPriv(pSib)->sibling_above = None;
253
254    /* the rest of siblings */
255    for (pSib = pSib->nextSib; pSib != NullWindow; pSib = pSib->nextSib) {
256      valuemask = CWSibling | CWStackMode;
257      values.sibling = xnestWindowSiblingAbove(pSib);
258      values.stack_mode = Below;
259      XConfigureWindow(xnestDisplay, xnestWindow(pSib), valuemask, &values);
260      xnestWindowPriv(pSib)->sibling_above = xnestWindowSiblingAbove(pSib);
261    }
262  }
263}
264
265Bool
266xnestChangeWindowAttributes(WindowPtr pWin, unsigned long mask)
267{
268  XSetWindowAttributes attributes;
269
270  if (mask & CWBackPixmap)
271    switch (pWin->backgroundState) {
272    case None:
273      attributes.background_pixmap = None;
274      break;
275
276    case ParentRelative:
277      attributes.background_pixmap = ParentRelative;
278      break;
279
280    case BackgroundPixmap:
281      attributes.background_pixmap = xnestPixmap(pWin->background.pixmap);
282      break;
283
284    case BackgroundPixel:
285      mask &= ~CWBackPixmap;
286      break;
287    }
288
289  if (mask & CWBackPixel) {
290    if (pWin->backgroundState == BackgroundPixel)
291      attributes.background_pixel = xnestPixel(pWin->background.pixel);
292    else
293      mask &= ~CWBackPixel;
294  }
295
296  if (mask & CWBorderPixmap) {
297    if (pWin->borderIsPixel)
298      mask &= ~CWBorderPixmap;
299    else
300      attributes.border_pixmap = xnestPixmap(pWin->border.pixmap);
301  }
302
303  if (mask & CWBorderPixel) {
304    if (pWin->borderIsPixel)
305      attributes.border_pixel = xnestPixel(pWin->border.pixel);
306    else
307      mask &= ~CWBorderPixel;
308  }
309
310  if (mask & CWBitGravity)
311    attributes.bit_gravity = pWin->bitGravity;
312
313  if (mask & CWWinGravity) /* dix does this for us */
314    mask &= ~CWWinGravity;
315
316  if (mask & CWBackingStore) /* this is really not useful */
317    mask &= ~CWBackingStore;
318
319  if (mask & CWBackingPlanes) /* this is really not useful */
320    mask &= ~CWBackingPlanes;
321
322  if (mask & CWBackingPixel) /* this is really not useful */
323    mask &= ~CWBackingPixel;
324
325  if (mask & CWOverrideRedirect)
326    attributes.override_redirect = pWin->overrideRedirect;
327
328  if (mask & CWSaveUnder) /* this is really not useful */
329    mask &= ~CWSaveUnder;
330
331  if (mask & CWEventMask) /* events are handled elsewhere */
332    mask &= ~CWEventMask;
333
334  if (mask & CWDontPropagate) /* events are handled elsewhere */
335    mask &= ~CWDontPropagate;
336
337  if (mask & CWColormap) {
338    ColormapPtr pCmap;
339
340    dixLookupResourceByType((pointer *)&pCmap, wColormap(pWin), RT_COLORMAP,
341			    serverClient, DixUseAccess);
342
343    attributes.colormap = xnestColormap(pCmap);
344
345    xnestSetInstalledColormapWindows(pWin->drawable.pScreen);
346  }
347
348  if (mask & CWCursor) /* this is handeled in cursor code */
349    mask &= ~CWCursor;
350
351  if (mask)
352    XChangeWindowAttributes(xnestDisplay, xnestWindow(pWin),
353			    mask, &attributes);
354
355  return True;
356}
357
358Bool
359xnestRealizeWindow(WindowPtr pWin)
360{
361  xnestConfigureWindow(pWin, CWStackingOrder);
362  xnestShapeWindow(pWin);
363  XMapWindow(xnestDisplay, xnestWindow(pWin));
364
365  return True;
366}
367
368Bool
369xnestUnrealizeWindow(WindowPtr pWin)
370{
371  XUnmapWindow(xnestDisplay, xnestWindow(pWin));
372
373  return True;
374}
375
376void
377xnestCopyWindow(WindowPtr pWin, xPoint oldOrigin, RegionPtr oldRegion)
378{
379}
380
381void
382xnestClipNotify(WindowPtr pWin, int dx, int dy)
383{
384  xnestConfigureWindow(pWin, CWStackingOrder);
385  xnestShapeWindow(pWin);
386}
387
388static Bool
389xnestWindowExposurePredicate(Display *display, XEvent *event, XPointer ptr)
390{
391  return (event->type == Expose && event->xexpose.window == *(Window *)ptr);
392}
393
394void
395xnestWindowExposures(WindowPtr pWin, RegionPtr pRgn, RegionPtr other_exposed)
396{
397  XEvent event;
398  Window window;
399  BoxRec Box;
400
401  XSync(xnestDisplay, False);
402
403  window = xnestWindow(pWin);
404
405  while (XCheckIfEvent(xnestDisplay, &event,
406		       xnestWindowExposurePredicate, (char *)&window)) {
407
408    Box.x1 = pWin->drawable.x + wBorderWidth(pWin) + event.xexpose.x;
409    Box.y1 = pWin->drawable.y + wBorderWidth(pWin) + event.xexpose.y;
410    Box.x2 = Box.x1 + event.xexpose.width;
411    Box.y2 = Box.y1 + event.xexpose.height;
412
413    event.xexpose.type = ProcessedExpose;
414
415    if (RegionContainsRect(pRgn, &Box) != rgnIN)
416      XPutBackEvent(xnestDisplay, &event);
417  }
418
419  miWindowExposures(pWin, pRgn, other_exposed);
420}
421
422void
423xnestSetShape(WindowPtr pWin, int kind)
424{
425  xnestShapeWindow(pWin);
426  miSetShape(pWin, kind);
427}
428
429static Bool
430xnestRegionEqual(RegionPtr pReg1, RegionPtr pReg2)
431{
432  BoxPtr pBox1, pBox2;
433  unsigned int n1, n2;
434
435  if (pReg1 == pReg2) return True;
436
437  if (pReg1 == NullRegion || pReg2 == NullRegion) return False;
438
439  pBox1 = RegionRects(pReg1);
440  n1 = RegionNumRects(pReg1);
441
442  pBox2 = RegionRects(pReg2);
443  n2 = RegionNumRects(pReg2);
444
445  if (n1 != n2) return False;
446
447  if (pBox1 == pBox2) return True;
448
449  if (memcmp(pBox1, pBox2, n1 * sizeof(BoxRec))) return False;
450
451  return True;
452}
453
454void
455xnestShapeWindow(WindowPtr pWin)
456{
457  Region reg;
458  BoxPtr pBox;
459  XRectangle rect;
460  int i;
461
462  if (!xnestRegionEqual(xnestWindowPriv(pWin)->bounding_shape,
463			wBoundingShape(pWin))) {
464
465    if (wBoundingShape(pWin)) {
466      RegionCopy(xnestWindowPriv(pWin)->bounding_shape, 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,
492			wClipShape(pWin))) {
493
494    if (wClipShape(pWin)) {
495      RegionCopy(xnestWindowPriv(pWin)->clip_shape, wClipShape(pWin));
496
497      reg = XCreateRegion();
498      pBox = RegionRects(xnestWindowPriv(pWin)->clip_shape);
499      for (i = 0;
500	   i < RegionNumRects(xnestWindowPriv(pWin)->clip_shape);
501	   i++) {
502        rect.x = pBox[i].x1;
503        rect.y = pBox[i].y1;
504        rect.width = pBox[i].x2 - pBox[i].x1;
505        rect.height = pBox[i].y2 - pBox[i].y1;
506        XUnionRectWithRegion(&rect, reg, reg);
507      }
508      XShapeCombineRegion(xnestDisplay, xnestWindow(pWin),
509			  ShapeClip, 0, 0, reg, ShapeSet);
510      XDestroyRegion(reg);
511    }
512    else {
513      RegionEmpty(xnestWindowPriv(pWin)->clip_shape);
514
515      XShapeCombineMask(xnestDisplay, xnestWindow(pWin),
516			ShapeClip, 0, 0, None, ShapeSet);
517    }
518  }
519}
520