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