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