1/* 2 * Rootless window management 3 */ 4/* 5 * Copyright (c) 2001 Greg Parker. All Rights Reserved. 6 * Copyright (c) 2002-2004 Torrey T. Lyons. All Rights Reserved. 7 * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. 8 * 9 * Permission is hereby granted, free of charge, to any person obtaining a 10 * copy of this software and associated documentation files (the "Software"), 11 * to deal in the Software without restriction, including without limitation 12 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 13 * and/or sell copies of the Software, and to permit persons to whom the 14 * Software is furnished to do so, subject to the following conditions: 15 * 16 * The above copyright notice and this permission notice shall be included in 17 * all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 22 * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 23 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 24 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 * DEALINGS IN THE SOFTWARE. 26 * 27 * Except as contained in this notice, the name(s) of the above copyright 28 * holders shall not be used in advertising or otherwise to promote the sale, 29 * use or other dealings in this Software without prior written authorization. 30 */ 31 32#ifdef HAVE_DIX_CONFIG_H 33#include <dix-config.h> 34#endif 35 36#include <stddef.h> /* For NULL */ 37#include <limits.h> /* For CHAR_BIT */ 38#include <assert.h> 39#include <X11/Xatom.h> 40#ifdef __APPLE__ 41#include <Xplugin.h> 42#include "mi.h" 43#include "pixmapstr.h" 44#include "windowstr.h" 45//#include <X11/extensions/applewm.h> 46extern int darwinMainScreenX, darwinMainScreenY; 47extern Bool no_configure_window; 48#endif 49#include "fb.h" 50 51#include "rootlessCommon.h" 52#include "rootlessWindow.h" 53 54#define SCREEN_TO_GLOBAL_X \ 55 (pScreen->x + rootlessGlobalOffsetX) 56#define SCREEN_TO_GLOBAL_Y \ 57 (pScreen->y + rootlessGlobalOffsetY) 58 59#define DEFINE_ATOM_HELPER(func,atom_name) \ 60 static Atom func (void) { \ 61 static unsigned int generation = 0; \ 62 static Atom atom; \ 63 if (generation != serverGeneration) { \ 64 generation = serverGeneration; \ 65 atom = MakeAtom (atom_name, strlen (atom_name), TRUE); \ 66 } \ 67 return atom; \ 68 } 69 70DEFINE_ATOM_HELPER(xa_native_window_id, "_NATIVE_WINDOW_ID") 71 72static Bool windows_hidden; 73 74// TODO - abstract xp functions 75 76#ifdef __APPLE__ 77 78// XXX: identical to x_cvt_vptr_to_uint ? 79#define MAKE_WINDOW_ID(x) ((xp_window_id)((size_t)(x))) 80 81void 82RootlessNativeWindowStateChanged(WindowPtr pWin, unsigned int state) 83{ 84 RootlessWindowRec *winRec; 85 86 if (pWin == NULL) 87 return; 88 89 winRec = WINREC(pWin); 90 if (winRec == NULL) 91 return; 92 93 winRec->is_offscreen = ((state & XP_WINDOW_STATE_OFFSCREEN) != 0); 94 winRec->is_obscured = ((state & XP_WINDOW_STATE_OBSCURED) != 0); 95 pWin->unhittable = winRec->is_offscreen; 96} 97 98void 99RootlessNativeWindowMoved(WindowPtr pWin) 100{ 101 xp_box bounds; 102 int sx, sy, err; 103 XID vlist[2]; 104 Mask mask; 105 ClientPtr pClient; 106 RootlessWindowRec *winRec; 107 108 winRec = WINREC(pWin); 109 110 if (xp_get_window_bounds(MAKE_WINDOW_ID(winRec->wid), &bounds) != Success) 111 return; 112 113 sx = pWin->drawable.pScreen->x + darwinMainScreenX; 114 sy = pWin->drawable.pScreen->y + darwinMainScreenY; 115 116 /* Fake up a ConfigureWindow packet to resize the window to the current bounds. */ 117 vlist[0] = (INT16) bounds.x1 - sx; 118 vlist[1] = (INT16) bounds.y1 - sy; 119 mask = CWX | CWY; 120 121 /* pretend we're the owner of the window! */ 122 err = 123 dixLookupClient(&pClient, pWin->drawable.id, serverClient, 124 DixUnknownAccess); 125 if (err != Success) { 126 ErrorF("RootlessNativeWindowMoved(): Failed to lookup window: 0x%x\n", 127 (unsigned int) pWin->drawable.id); 128 return; 129 } 130 131 /* Don't want to do anything to the physical window (avoids 132 notification-response feedback loops) */ 133 134 no_configure_window = TRUE; 135 ConfigureWindow(pWin, mask, vlist, pClient); 136 no_configure_window = FALSE; 137} 138 139#endif /* __APPLE__ */ 140 141/* 142 * RootlessCreateWindow 143 * For now, don't create a physical window until either the window is 144 * realized, or we really need it (e.g. to attach VRAM surfaces to). 145 * Do reset the window size so it's not clipped by the root window. 146 */ 147Bool 148RootlessCreateWindow(WindowPtr pWin) 149{ 150 Bool result; 151 RegionRec saveRoot; 152 153 SETWINREC(pWin, NULL); 154 dixSetPrivate(&pWin->devPrivates, rootlessWindowOldPixmapPrivateKey, NULL); 155 156 SCREEN_UNWRAP(pWin->drawable.pScreen, CreateWindow); 157 158 if (!IsRoot(pWin)) { 159 /* win/border size set by DIX, not by wrapped CreateWindow, so 160 correct it here. Don't HUGE_ROOT when pWin is the root! */ 161 162 HUGE_ROOT(pWin); 163 SetWinSize(pWin); 164 SetBorderSize(pWin); 165 } 166 167 result = pWin->drawable.pScreen->CreateWindow(pWin); 168 169 if (pWin->parent) { 170 NORMAL_ROOT(pWin); 171 } 172 173 SCREEN_WRAP(pWin->drawable.pScreen, CreateWindow); 174 175 return result; 176} 177 178/* 179 * RootlessDestroyFrame 180 * Destroy the physical window associated with the given window. 181 */ 182static void 183RootlessDestroyFrame(WindowPtr pWin, RootlessWindowPtr winRec) 184{ 185 SCREENREC(pWin->drawable.pScreen)->imp->DestroyFrame(winRec->wid); 186 free(winRec); 187 SETWINREC(pWin, NULL); 188} 189 190/* 191 * RootlessDestroyWindow 192 * Destroy the physical window associated with the given window. 193 */ 194Bool 195RootlessDestroyWindow(WindowPtr pWin) 196{ 197 RootlessWindowRec *winRec = WINREC(pWin); 198 Bool result; 199 200 if (winRec != NULL) { 201 RootlessDestroyFrame(pWin, winRec); 202 } 203 204 SCREEN_UNWRAP(pWin->drawable.pScreen, DestroyWindow); 205 result = pWin->drawable.pScreen->DestroyWindow(pWin); 206 SCREEN_WRAP(pWin->drawable.pScreen, DestroyWindow); 207 208 return result; 209} 210 211static Bool 212RootlessGetShape(WindowPtr pWin, RegionPtr pShape) 213{ 214 if (wBoundingShape(pWin) == NULL) 215 return FALSE; 216 217 /* wBoundingShape is relative to *inner* origin of window. 218 Translate by borderWidth to get the outside-relative position. */ 219 220 RegionNull(pShape); 221 RegionCopy(pShape, wBoundingShape(pWin)); 222 RegionTranslate(pShape, pWin->borderWidth, pWin->borderWidth); 223 224 return TRUE; 225} 226 227/* 228 * RootlessReshapeFrame 229 * Set the frame shape. 230 */ 231static void 232RootlessReshapeFrame(WindowPtr pWin) 233{ 234 RootlessWindowRec *winRec = WINREC(pWin); 235 RegionRec newShape; 236 RegionPtr pShape; 237 238 // If the window is not yet framed, do nothing 239 if (winRec == NULL) 240 return; 241 242 if (IsRoot(pWin)) 243 return; 244 245 RootlessStopDrawing(pWin, FALSE); 246 247 pShape = RootlessGetShape(pWin, &newShape) ? &newShape : NULL; 248 249#ifdef ROOTLESSDEBUG 250 RL_DEBUG_MSG("reshaping..."); 251 if (pShape != NULL) { 252 RL_DEBUG_MSG("numrects %d, extents %d %d %d %d ", 253 RegionNumRects(&newShape), 254 newShape.extents.x1, newShape.extents.y1, 255 newShape.extents.x2, newShape.extents.y2); 256 } 257 else { 258 RL_DEBUG_MSG("no shape "); 259 } 260#endif 261 262 SCREENREC(pWin->drawable.pScreen)->imp->ReshapeFrame(winRec->wid, pShape); 263 264 if (pShape != NULL) 265 RegionUninit(&newShape); 266} 267 268/* 269 * RootlessSetShape 270 * Shape is usually set before a window is mapped and the window will 271 * not have a frame associated with it. In this case, the frame will be 272 * shaped when the window is framed. 273 */ 274void 275RootlessSetShape(WindowPtr pWin, int kind) 276{ 277 ScreenPtr pScreen = pWin->drawable.pScreen; 278 279 SCREEN_UNWRAP(pScreen, SetShape); 280 pScreen->SetShape(pWin, kind); 281 SCREEN_WRAP(pScreen, SetShape); 282 283 RootlessReshapeFrame(pWin); 284} 285 286/* Disallow ParentRelative background on top-level windows 287 because the root window doesn't really have the right background. 288 */ 289Bool 290RootlessChangeWindowAttributes(WindowPtr pWin, unsigned long vmask) 291{ 292 Bool result; 293 ScreenPtr pScreen = pWin->drawable.pScreen; 294 295 RL_DEBUG_MSG("change window attributes start "); 296 297 SCREEN_UNWRAP(pScreen, ChangeWindowAttributes); 298 result = pScreen->ChangeWindowAttributes(pWin, vmask); 299 SCREEN_WRAP(pScreen, ChangeWindowAttributes); 300 301 if (WINREC(pWin)) { 302 // disallow ParentRelative background state 303 if (pWin->backgroundState == ParentRelative) { 304 XID pixel = 0; 305 306 ChangeWindowAttributes(pWin, CWBackPixel, &pixel, serverClient); 307 } 308 } 309 310 RL_DEBUG_MSG("change window attributes end\n"); 311 return result; 312} 313 314/* 315 * RootlessPositionWindow 316 * This is a hook for when DIX moves or resizes a window. 317 * Update the frame position now although the physical window is moved 318 * in RootlessMoveWindow. (x, y) are *inside* position. After this, 319 * mi and fb are expecting the pixmap to be at the new location. 320 */ 321Bool 322RootlessPositionWindow(WindowPtr pWin, int x, int y) 323{ 324 ScreenPtr pScreen = pWin->drawable.pScreen; 325 RootlessWindowRec *winRec = WINREC(pWin); 326 Bool result; 327 328 RL_DEBUG_MSG("positionwindow start (win 0x%x @ %i, %i)\n", pWin, x, y); 329 330 if (winRec) { 331 if (winRec->is_drawing) { 332 // Reset frame's pixmap and move it to the new position. 333 int bw = wBorderWidth(pWin); 334 335 winRec->pixmap->devPrivate.ptr = winRec->pixelData; 336 SetPixmapBaseToScreen(winRec->pixmap, x - bw, y - bw); 337 } 338 } 339 340 SCREEN_UNWRAP(pScreen, PositionWindow); 341 result = pScreen->PositionWindow(pWin, x, y); 342 SCREEN_WRAP(pScreen, PositionWindow); 343 344 RL_DEBUG_MSG("positionwindow end\n"); 345 return result; 346} 347 348/* 349 * RootlessInitializeFrame 350 * Initialize some basic attributes of the frame. Note that winRec 351 * may already have valid data in it, so don't overwrite anything 352 * valuable. 353 */ 354static void 355RootlessInitializeFrame(WindowPtr pWin, RootlessWindowRec * winRec) 356{ 357 DrawablePtr d = &pWin->drawable; 358 int bw = wBorderWidth(pWin); 359 360 winRec->win = pWin; 361 362 winRec->x = d->x - bw; 363 winRec->y = d->y - bw; 364 winRec->width = d->width + 2 * bw; 365 winRec->height = d->height + 2 * bw; 366 winRec->borderWidth = bw; 367} 368 369/* 370 * RootlessEnsureFrame 371 * Make sure the given window is framed. If the window doesn't have a 372 * physical window associated with it, attempt to create one. If that 373 * is unsuccessful, return NULL. 374 */ 375static RootlessWindowRec * 376RootlessEnsureFrame(WindowPtr pWin) 377{ 378 ScreenPtr pScreen = pWin->drawable.pScreen; 379 RootlessWindowRec *winRec; 380 RegionRec shape; 381 RegionPtr pShape = NULL; 382 383 if (WINREC(pWin) != NULL) 384 return WINREC(pWin); 385 386 if (!IsTopLevel(pWin) && !IsRoot(pWin)) 387 return NULL; 388 389 if (pWin->drawable.class != InputOutput) 390 return NULL; 391 392 winRec = malloc(sizeof(RootlessWindowRec)); 393 394 if (!winRec) 395 return NULL; 396 397 RootlessInitializeFrame(pWin, winRec); 398 399 winRec->is_drawing = FALSE; 400 winRec->is_reorder_pending = FALSE; 401 winRec->pixmap = NULL; 402 winRec->wid = NULL; 403 winRec->level = 0; 404 405 SETWINREC(pWin, winRec); 406 407 // Set the frame's shape if the window is shaped 408 if (RootlessGetShape(pWin, &shape)) 409 pShape = &shape; 410 411 RL_DEBUG_MSG("creating frame "); 412 413 if (!SCREENREC(pScreen)->imp->CreateFrame(winRec, pScreen, 414 winRec->x + SCREEN_TO_GLOBAL_X, 415 winRec->y + SCREEN_TO_GLOBAL_Y, 416 pShape)) { 417 RL_DEBUG_MSG("implementation failed to create frame!\n"); 418 free(winRec); 419 SETWINREC(pWin, NULL); 420 return NULL; 421 } 422 423 if (pWin->drawable.depth == 8) 424 RootlessFlushWindowColormap(pWin); 425 426 if (pShape != NULL) 427 RegionUninit(&shape); 428 429 return winRec; 430} 431 432/* 433 * RootlessRealizeWindow 434 * The frame is usually created here and not in CreateWindow so that 435 * windows do not eat memory until they are realized. 436 */ 437Bool 438RootlessRealizeWindow(WindowPtr pWin) 439{ 440 Bool result; 441 RegionRec saveRoot; 442 ScreenPtr pScreen = pWin->drawable.pScreen; 443 444 RL_DEBUG_MSG("realizewindow start (win 0x%x) ", pWin); 445 446 if ((IsTopLevel(pWin) && pWin->drawable.class == InputOutput)) { 447 RootlessWindowRec *winRec; 448 449 winRec = RootlessEnsureFrame(pWin); 450 if (winRec == NULL) 451 return FALSE; 452 453 winRec->is_reorder_pending = TRUE; 454 455 RL_DEBUG_MSG("Top level window "); 456 457 // Disallow ParentRelative background state on top-level windows. 458 // This might have been set before the window was mapped. 459 if (pWin->backgroundState == ParentRelative) { 460 XID pixel = 0; 461 462 ChangeWindowAttributes(pWin, CWBackPixel, &pixel, serverClient); 463 } 464 } 465 466 if (!IsRoot(pWin)) 467 HUGE_ROOT(pWin); 468 SCREEN_UNWRAP(pScreen, RealizeWindow); 469 result = pScreen->RealizeWindow(pWin); 470 SCREEN_WRAP(pScreen, RealizeWindow); 471 if (!IsRoot(pWin)) 472 NORMAL_ROOT(pWin); 473 474 RL_DEBUG_MSG("realizewindow end\n"); 475 return result; 476} 477 478/* 479 * RootlessFrameForWindow 480 * Returns the frame ID for the physical window displaying the given window. 481 * If CREATE is true and the window has no frame, attempt to create one. 482 */ 483RootlessFrameID 484RootlessFrameForWindow(WindowPtr pWin, Bool create) 485{ 486 WindowPtr pTopWin; 487 RootlessWindowRec *winRec; 488 489 pTopWin = TopLevelParent(pWin); 490 if (pTopWin == NULL) 491 return NULL; 492 493 winRec = WINREC(pTopWin); 494 495 if (winRec == NULL && create && pWin->drawable.class == InputOutput) { 496 winRec = RootlessEnsureFrame(pTopWin); 497 } 498 499 if (winRec == NULL) 500 return NULL; 501 502 return winRec->wid; 503} 504 505/* 506 * RootlessUnrealizeWindow 507 * Unmap the physical window. 508 */ 509Bool 510RootlessUnrealizeWindow(WindowPtr pWin) 511{ 512 ScreenPtr pScreen = pWin->drawable.pScreen; 513 RootlessWindowRec *winRec = WINREC(pWin); 514 Bool result; 515 516 RL_DEBUG_MSG("unrealizewindow start "); 517 518 if (winRec) { 519 RootlessStopDrawing(pWin, FALSE); 520 521 SCREENREC(pScreen)->imp->UnmapFrame(winRec->wid); 522 523 winRec->is_reorder_pending = FALSE; 524 } 525 526 SCREEN_UNWRAP(pScreen, UnrealizeWindow); 527 result = pScreen->UnrealizeWindow(pWin); 528 SCREEN_WRAP(pScreen, UnrealizeWindow); 529 530 RL_DEBUG_MSG("unrealizewindow end\n"); 531 return result; 532} 533 534/* 535 * RootlessReorderWindow 536 * Reorder the frame associated with the given window so that it's 537 * physically above the window below it in the X stacking order. 538 */ 539void 540RootlessReorderWindow(WindowPtr pWin) 541{ 542 RootlessWindowRec *winRec = WINREC(pWin); 543 544 if (pWin->realized && winRec != NULL && !winRec->is_reorder_pending && 545 !windows_hidden) { 546 WindowPtr newPrevW; 547 RootlessWindowRec *newPrev; 548 RootlessFrameID newPrevID; 549 ScreenPtr pScreen = pWin->drawable.pScreen; 550 551 /* Check if the implementation wants the frame to not be reordered 552 even though the X11 window is restacked. This can be useful if 553 frames are ordered-in with animation so that the reordering is not 554 done until the animation is complete. */ 555 if (SCREENREC(pScreen)->imp->DoReorderWindow) { 556 if (!SCREENREC(pScreen)->imp->DoReorderWindow(winRec)) 557 return; 558 } 559 560 RootlessStopDrawing(pWin, FALSE); 561 562 /* Find the next window above this one that has a mapped frame. 563 * Only include cases where the windows are in the same category of 564 * hittability to ensure offscreen windows don't get restacked 565 * relative to onscreen ones (but that the offscreen ones maintain 566 * their stacking order if they are explicitly asked to Reorder). 567 */ 568 569 newPrevW = pWin->prevSib; 570 while (newPrevW && 571 (WINREC(newPrevW) == NULL || !newPrevW->realized || 572 newPrevW->unhittable != pWin->unhittable)) 573 newPrevW = newPrevW->prevSib; 574 575 newPrev = newPrevW != NULL ? WINREC(newPrevW) : NULL; 576 newPrevID = newPrev != NULL ? newPrev->wid : 0; 577 578 /* If it exists, reorder the frame above us first. */ 579 580 if (newPrev && newPrev->is_reorder_pending) { 581 newPrev->is_reorder_pending = FALSE; 582 RootlessReorderWindow(newPrevW); 583 } 584 585 SCREENREC(pScreen)->imp->RestackFrame(winRec->wid, newPrevID); 586 } 587} 588 589/* 590 * RootlessRestackWindow 591 * This is a hook for when DIX changes the window stacking order. 592 * The window has already been inserted into its new position in the 593 * DIX window stack. We need to change the order of the physical 594 * window to match. 595 */ 596void 597RootlessRestackWindow(WindowPtr pWin, WindowPtr pOldNextSib) 598{ 599 RegionRec saveRoot; 600 RootlessWindowRec *winRec = WINREC(pWin); 601 ScreenPtr pScreen = pWin->drawable.pScreen; 602 603 RL_DEBUG_MSG("restackwindow start "); 604 if (winRec) 605 RL_DEBUG_MSG("restack top level \n"); 606 607 HUGE_ROOT(pWin); 608 SCREEN_UNWRAP(pScreen, RestackWindow); 609 610 if (pScreen->RestackWindow) 611 pScreen->RestackWindow(pWin, pOldNextSib); 612 613 SCREEN_WRAP(pScreen, RestackWindow); 614 NORMAL_ROOT(pWin); 615 616 if (winRec && pWin->viewable) { 617 RootlessReorderWindow(pWin); 618 } 619 620 RL_DEBUG_MSG("restackwindow end\n"); 621} 622 623/* 624 * Specialized window copy procedures 625 */ 626 627// Globals needed during window resize and move. 628static void *gResizeDeathBits = NULL; 629static int gResizeDeathCount = 0; 630static PixmapPtr gResizeDeathPix[2] = { NULL, NULL }; 631 632static BoxRec gResizeDeathBounds[2]; 633static CopyWindowProcPtr gResizeOldCopyWindowProc = NULL; 634 635/* 636 * RootlessNoCopyWindow 637 * CopyWindow() that doesn't do anything. For MoveWindow() of 638 * top-level windows. 639 */ 640static void 641RootlessNoCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) 642{ 643 // some code expects the region to be translated 644 int dx = ptOldOrg.x - pWin->drawable.x; 645 int dy = ptOldOrg.y - pWin->drawable.y; 646 647 RL_DEBUG_MSG("ROOTLESSNOCOPYWINDOW "); 648 649 RegionTranslate(prgnSrc, -dx, -dy); 650} 651 652/* 653 * RootlessResizeCopyWindow 654 * CopyWindow used during ResizeWindow for gravity moves. Based on 655 * fbCopyWindow. The original always draws on the root pixmap, which 656 * we don't have. Instead, draw on the parent window's pixmap. 657 * Resize version: the old location's pixels are in gResizeCopyWindowSource. 658 */ 659static void 660RootlessResizeCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, 661 RegionPtr prgnSrc) 662{ 663 ScreenPtr pScreen = pWin->drawable.pScreen; 664 RegionRec rgnDst; 665 int dx, dy; 666 667 RL_DEBUG_MSG("resizecopywindowFB start (win 0x%x) ", pWin); 668 669 /* Don't unwrap pScreen->CopyWindow. 670 The bogus rewrap with RootlessCopyWindow causes a crash if 671 CopyWindow is called again during the same resize. */ 672 673 if (gResizeDeathCount == 0) 674 return; 675 676 RootlessStartDrawing(pWin); 677 678 dx = ptOldOrg.x - pWin->drawable.x; 679 dy = ptOldOrg.y - pWin->drawable.y; 680 RegionTranslate(prgnSrc, -dx, -dy); 681 RegionNull(&rgnDst); 682 RegionIntersect(&rgnDst, &pWin->borderClip, prgnSrc); 683 684 if (gResizeDeathCount == 1) { 685 /* Simple case, we only have a single source pixmap. */ 686 687 miCopyRegion(&gResizeDeathPix[0]->drawable, 688 &pScreen->GetWindowPixmap(pWin)->drawable, 0, 689 &rgnDst, dx, dy, fbCopyWindowProc, 0, 0); 690 } 691 else { 692 int i; 693 RegionRec clip, clipped; 694 695 /* More complex case, N source pixmaps (usually two). So we 696 intersect the destination with each source and copy those bits. */ 697 698 for (i = 0; i < gResizeDeathCount; i++) { 699 RegionInit(&clip, gResizeDeathBounds + 0, 1); 700 RegionNull(&clipped); 701 RegionIntersect(&rgnDst, &clip, &clipped); 702 703 miCopyRegion(&gResizeDeathPix[i]->drawable, 704 &pScreen->GetWindowPixmap(pWin)->drawable, 0, 705 &clipped, dx, dy, fbCopyWindowProc, 0, 0); 706 707 RegionUninit(&clipped); 708 RegionUninit(&clip); 709 } 710 } 711 712 /* Don't update - resize will update everything */ 713 RegionUninit(&rgnDst); 714 715 fbValidateDrawable(&pWin->drawable); 716 717 RL_DEBUG_MSG("resizecopywindowFB end\n"); 718} 719 720/* 721 * RootlessCopyWindow 722 * Update *new* location of window. Old location is redrawn with 723 * PaintWindow. Cloned from fbCopyWindow. 724 * The original always draws on the root pixmap, which we don't have. 725 * Instead, draw on the parent window's pixmap. 726 */ 727void 728RootlessCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) 729{ 730 ScreenPtr pScreen = pWin->drawable.pScreen; 731 RegionRec rgnDst; 732 int dx, dy; 733 BoxPtr extents; 734 int area; 735 736 RL_DEBUG_MSG("copywindowFB start (win 0x%x) ", pWin); 737 738 SCREEN_UNWRAP(pScreen, CopyWindow); 739 740 dx = ptOldOrg.x - pWin->drawable.x; 741 dy = ptOldOrg.y - pWin->drawable.y; 742 RegionTranslate(prgnSrc, -dx, -dy); 743 744 RegionNull(&rgnDst); 745 RegionIntersect(&rgnDst, &pWin->borderClip, prgnSrc); 746 747 extents = RegionExtents(&rgnDst); 748 area = (extents->x2 - extents->x1) * (extents->y2 - extents->y1); 749 750 /* If the area exceeds threshold, use the implementation's 751 accelerated version. */ 752 if (area > rootless_CopyWindow_threshold && 753 SCREENREC(pScreen)->imp->CopyWindow) { 754 RootlessWindowRec *winRec; 755 WindowPtr top; 756 757 top = TopLevelParent(pWin); 758 if (top == NULL) { 759 RL_DEBUG_MSG("no parent\n"); 760 goto out; 761 } 762 763 winRec = WINREC(top); 764 if (winRec == NULL) { 765 RL_DEBUG_MSG("not framed\n"); 766 goto out; 767 } 768 769 /* Move region to window local coords */ 770 RegionTranslate(&rgnDst, -winRec->x, -winRec->y); 771 772 RootlessStopDrawing(pWin, FALSE); 773 774 SCREENREC(pScreen)->imp->CopyWindow(winRec->wid, 775 RegionNumRects(&rgnDst), 776 RegionRects(&rgnDst), dx, dy); 777 } 778 else { 779 RootlessStartDrawing(pWin); 780 781 miCopyRegion((DrawablePtr) pWin, (DrawablePtr) pWin, 782 0, &rgnDst, dx, dy, fbCopyWindowProc, 0, 0); 783 784 /* prgnSrc has been translated to dst position */ 785 RootlessDamageRegion(pWin, prgnSrc); 786 } 787 788 out: 789 RegionUninit(&rgnDst); 790 fbValidateDrawable(&pWin->drawable); 791 792 SCREEN_WRAP(pScreen, CopyWindow); 793 794 RL_DEBUG_MSG("copywindowFB end\n"); 795} 796 797void 798RootlessPaintWindow(WindowPtr pWin, RegionPtr prgn, int what) 799{ 800 ScreenPtr pScreen = pWin->drawable.pScreen; 801 802 if (IsFramedWindow(pWin)) { 803 RootlessStartDrawing(pWin); 804 RootlessDamageRegion(pWin, prgn); 805 806 if (pWin->backgroundState == ParentRelative) { 807 if ((what == PW_BACKGROUND) || 808 (what == PW_BORDER && !pWin->borderIsPixel)) 809 RootlessSetPixmapOfAncestors(pWin); 810 } 811 } 812 813 SCREEN_UNWRAP(pScreen, PaintWindow); 814 pScreen->PaintWindow(pWin, prgn, what); 815 SCREEN_WRAP(pScreen, PaintWindow); 816} 817 818/* 819 * Window resize procedures 820 */ 821 822enum { 823 WIDTH_SMALLER = 1, 824 HEIGHT_SMALLER = 2, 825}; 826 827/* 828 * ResizeWeighting 829 * Choose gravity to avoid local copies. Do that by looking for 830 * a corner that doesn't move _relative to the screen_. 831 */ 832static inline unsigned int 833ResizeWeighting(int oldX1, int oldY1, int oldX2, int oldY2, int oldBW, 834 int newX1, int newY1, int newX2, int newY2, int newBW) 835{ 836#ifdef ROOTLESS_RESIZE_GRAVITY 837 if (newBW != oldBW) 838 return RL_GRAVITY_NONE; 839 840 if (newX1 == oldX1 && newY1 == oldY1) 841 return RL_GRAVITY_NORTH_WEST; 842 else if (newX1 == oldX1 && newY2 == oldY2) 843 return RL_GRAVITY_SOUTH_WEST; 844 else if (newX2 == oldX2 && newY2 == oldY2) 845 return RL_GRAVITY_SOUTH_EAST; 846 else if (newX2 == oldX2 && newY1 == oldY1) 847 return RL_GRAVITY_NORTH_EAST; 848 else 849 return RL_GRAVITY_NONE; 850#else 851 return RL_GRAVITY_NONE; 852#endif 853} 854 855/* 856 * StartFrameResize 857 * Prepare to resize a top-level window. The old window's pixels are 858 * saved and the implementation is told to change the window size. 859 * (x,y,w,h) is outer frame of window (outside border) 860 */ 861static Bool 862StartFrameResize(WindowPtr pWin, Bool gravity, 863 int oldX, int oldY, int oldW, int oldH, int oldBW, 864 int newX, int newY, int newW, int newH, int newBW) 865{ 866 ScreenPtr pScreen = pWin->drawable.pScreen; 867 RootlessWindowRec *winRec = WINREC(pWin); 868 Bool need_window_source = FALSE, resize_after = FALSE; 869 870 BoxRec rect; 871 int oldX2, newX2; 872 int oldY2, newY2; 873 unsigned int weight; 874 875 oldX2 = oldX + oldW, newX2 = newX + newW; 876 oldY2 = oldY + oldH, newY2 = newY + newH; 877 878 /* Decide which resize weighting to use */ 879 weight = ResizeWeighting(oldX, oldY, oldW, oldH, oldBW, 880 newX, newY, newW, newH, newBW); 881 882 /* Compute intersection between old and new rects */ 883 rect.x1 = max(oldX, newX); 884 rect.y1 = max(oldY, newY); 885 rect.x2 = min(oldX2, newX2); 886 rect.y2 = min(oldY2, newY2); 887 888 RL_DEBUG_MSG("RESIZE TOPLEVEL WINDOW with gravity %i ", gravity); 889 RL_DEBUG_MSG("%d %d %d %d %d %d %d %d %d %d\n", 890 oldX, oldY, oldW, oldH, oldBW, newX, newY, newW, newH, newBW); 891 892 RootlessRedisplay(pWin); 893 894 /* If gravity is true, then we need to have a way of recovering all 895 the original bits in the window for when X rearranges the contents 896 based on the various gravity settings. The obvious way is to just 897 snapshot the entire backing store before resizing it, but that 898 it slow on large windows. 899 900 So the optimization here is to use the implementation's resize 901 weighting options (if available) to allow us to reason about what 902 is left in the backing store after the resize. We can then only 903 copy what won't be there after the resize, and do a two-stage copy 904 operation. 905 906 Most of these optimizations are only applied when the top-left 907 corner of the window is fixed, since that's the common case. They 908 could probably be extended with some thought. */ 909 910 gResizeDeathCount = 0; 911 912 if (gravity && weight == RL_GRAVITY_NORTH_WEST) { 913 unsigned int code = 0; 914 915 /* Top left corner is anchored. We never need to copy the 916 entire window. */ 917 918 need_window_source = TRUE; 919 920 /* These comparisons were chosen to avoid setting bits when the sizes 921 are the same. (So the fastest case automatically gets taken when 922 dimensions are unchanging.) */ 923 924 if (newW < oldW) 925 code |= WIDTH_SMALLER; 926 if (newH < oldH) 927 code |= HEIGHT_SMALLER; 928 929 if (((code ^ (code >> 1)) & 1) == 0) { 930 /* Both dimensions are either getting larger, or both 931 are getting smaller. No need to copy anything. */ 932 933 if (code == (WIDTH_SMALLER | HEIGHT_SMALLER)) { 934 /* Since the window is getting smaller, we can do gravity 935 repair on it with its current size, then resize it 936 afterwards. */ 937 938 resize_after = TRUE; 939 } 940 941 gResizeDeathCount = 1; 942 } 943 else { 944 unsigned int copy_rowbytes, Bpp; 945 unsigned int copy_rect_width, copy_rect_height; 946 BoxRec copy_rect; 947 948 /* We can get away with a partial copy. 'rect' is the 949 intersection between old and new bounds, so copy 950 everything to the right of or below the intersection. */ 951 952 RootlessStartDrawing(pWin); 953 954 if (code == WIDTH_SMALLER) { 955 copy_rect.x1 = rect.x2; 956 copy_rect.y1 = rect.y1; 957 copy_rect.x2 = oldX2; 958 copy_rect.y2 = oldY2; 959 } 960 else if (code == HEIGHT_SMALLER) { 961 copy_rect.x1 = rect.x1; 962 copy_rect.y1 = rect.y2; 963 copy_rect.x2 = oldX2; 964 copy_rect.y2 = oldY2; 965 } 966 else 967 OsAbort(); 968 969 Bpp = winRec->win->drawable.bitsPerPixel / 8; 970 copy_rect_width = copy_rect.x2 - copy_rect.x1; 971 copy_rect_height = copy_rect.y2 - copy_rect.y1; 972 copy_rowbytes = ((copy_rect_width * Bpp) + 31) & ~31; 973 gResizeDeathBits = xallocarray(copy_rowbytes, copy_rect_height); 974 975 if (copy_rect_width * copy_rect_height > 976 rootless_CopyBytes_threshold && 977 SCREENREC(pScreen)->imp->CopyBytes) { 978 SCREENREC(pScreen)->imp->CopyBytes(copy_rect_width * Bpp, 979 copy_rect_height, 980 ((char *) winRec->pixelData) 981 + 982 ((copy_rect.y1 - 983 oldY) * 984 winRec->bytesPerRow) 985 + (copy_rect.x1 - 986 oldX) * Bpp, 987 winRec->bytesPerRow, 988 gResizeDeathBits, 989 copy_rowbytes); 990 } 991 else { 992 fbBlt((FbBits *) (winRec->pixelData 993 + 994 ((copy_rect.y1 - oldY) * winRec->bytesPerRow) 995 + (copy_rect.x1 - oldX) * Bpp), 996 winRec->bytesPerRow / sizeof(FbBits), 0, 997 (FbBits *) gResizeDeathBits, 998 copy_rowbytes / sizeof(FbBits), 0, copy_rect_width * Bpp, 999 copy_rect_height, GXcopy, FB_ALLONES, Bpp, 0, 0); 1000 } 1001 1002 gResizeDeathBounds[1] = copy_rect; 1003 gResizeDeathPix[1] 1004 = GetScratchPixmapHeader(pScreen, copy_rect_width, 1005 copy_rect_height, 1006 winRec->win->drawable.depth, 1007 winRec->win->drawable.bitsPerPixel, 1008 winRec->bytesPerRow, 1009 (void *) gResizeDeathBits); 1010 1011 SetPixmapBaseToScreen(gResizeDeathPix[1], 1012 copy_rect.x1, copy_rect.y1); 1013 1014 gResizeDeathCount = 2; 1015 } 1016 } 1017 else if (gravity) { 1018 /* The general case. Just copy everything. */ 1019 1020 RootlessStartDrawing(pWin); 1021 1022 gResizeDeathBits = xallocarray(winRec->bytesPerRow, winRec->height); 1023 1024 memcpy(gResizeDeathBits, winRec->pixelData, 1025 winRec->bytesPerRow * winRec->height); 1026 1027 gResizeDeathBounds[0] = (BoxRec) { 1028 oldX, oldY, oldX2, oldY2}; 1029 gResizeDeathPix[0] 1030 = GetScratchPixmapHeader(pScreen, winRec->width, 1031 winRec->height, 1032 winRec->win->drawable.depth, 1033 winRec->win->drawable.bitsPerPixel, 1034 winRec->bytesPerRow, 1035 (void *) gResizeDeathBits); 1036 1037 SetPixmapBaseToScreen(gResizeDeathPix[0], oldX, oldY); 1038 gResizeDeathCount = 1; 1039 } 1040 1041 RootlessStopDrawing(pWin, FALSE); 1042 1043 winRec->x = newX; 1044 winRec->y = newY; 1045 winRec->width = newW; 1046 winRec->height = newH; 1047 winRec->borderWidth = newBW; 1048 1049 /* Unless both dimensions are getting smaller, Resize the frame 1050 before doing gravity repair */ 1051 1052 if (!resize_after) { 1053 SCREENREC(pScreen)->imp->ResizeFrame(winRec->wid, pScreen, 1054 newX + SCREEN_TO_GLOBAL_X, 1055 newY + SCREEN_TO_GLOBAL_Y, 1056 newW, newH, weight); 1057 } 1058 1059 RootlessStartDrawing(pWin); 1060 1061 /* If necessary, create a source pixmap pointing at the current 1062 window bits. */ 1063 1064 if (need_window_source) { 1065 gResizeDeathBounds[0] = (BoxRec) { 1066 oldX, oldY, oldX2, oldY2}; 1067 gResizeDeathPix[0] 1068 = GetScratchPixmapHeader(pScreen, oldW, oldH, 1069 winRec->win->drawable.depth, 1070 winRec->win->drawable.bitsPerPixel, 1071 winRec->bytesPerRow, winRec->pixelData); 1072 1073 SetPixmapBaseToScreen(gResizeDeathPix[0], oldX, oldY); 1074 } 1075 1076 /* Use custom CopyWindow when moving gravity bits around 1077 ResizeWindow assumes the old window contents are in the same 1078 pixmap, but here they're in deathPix instead. */ 1079 1080 if (gravity) { 1081 gResizeOldCopyWindowProc = pScreen->CopyWindow; 1082 pScreen->CopyWindow = RootlessResizeCopyWindow; 1083 } 1084 1085 /* If we can't rely on the window server preserving the bits we 1086 need in the position we need, copy the pixels in the 1087 intersection from src to dst. ResizeWindow assumes these pixels 1088 are already present when making gravity adjustments. pWin 1089 currently has new-sized pixmap but is in old position. 1090 1091 FIXME: border width change! (?) */ 1092 1093 if (gravity && weight == RL_GRAVITY_NONE) { 1094 PixmapPtr src, dst; 1095 1096 assert(gResizeDeathCount == 1); 1097 1098 src = gResizeDeathPix[0]; 1099 dst = pScreen->GetWindowPixmap(pWin); 1100 1101 RL_DEBUG_MSG("Resize copy rect %d %d %d %d\n", 1102 rect.x1, rect.y1, rect.x2, rect.y2); 1103 1104 /* rect is the intersection of the old location and new location */ 1105 if (BOX_NOT_EMPTY(rect) && src != NULL && dst != NULL) { 1106 /* The window drawable still has the old frame position, which 1107 means that DST doesn't actually point at the origin of our 1108 physical backing store when adjusted by the drawable.x,y 1109 position. So sneakily adjust it temporarily while copying.. */ 1110 1111 ((PixmapPtr) dst)->devPrivate.ptr = winRec->pixelData; 1112 SetPixmapBaseToScreen(dst, newX, newY); 1113 1114 fbCopyWindowProc(&src->drawable, &dst->drawable, NULL, 1115 &rect, 1, 0, 0, FALSE, FALSE, 0, 0); 1116 1117 ((PixmapPtr) dst)->devPrivate.ptr = winRec->pixelData; 1118 SetPixmapBaseToScreen(dst, oldX, oldY); 1119 } 1120 } 1121 1122 return resize_after; 1123} 1124 1125static void 1126FinishFrameResize(WindowPtr pWin, Bool gravity, int oldX, int oldY, 1127 unsigned int oldW, unsigned int oldH, unsigned int oldBW, 1128 int newX, int newY, unsigned int newW, unsigned int newH, 1129 unsigned int newBW, Bool resize_now) 1130{ 1131 ScreenPtr pScreen = pWin->drawable.pScreen; 1132 RootlessWindowRec *winRec = WINREC(pWin); 1133 int i; 1134 1135 RootlessStopDrawing(pWin, FALSE); 1136 1137 if (resize_now) { 1138 unsigned int weight; 1139 1140 /* We didn't resize anything earlier, so do it now, now that 1141 we've finished gravitating the bits. */ 1142 1143 weight = ResizeWeighting(oldX, oldY, oldW, oldH, oldBW, 1144 newX, newY, newW, newH, newBW); 1145 1146 SCREENREC(pScreen)->imp->ResizeFrame(winRec->wid, pScreen, 1147 newX + SCREEN_TO_GLOBAL_X, 1148 newY + SCREEN_TO_GLOBAL_Y, 1149 newW, newH, weight); 1150 } 1151 1152 /* Redraw everything. FIXME: there must be times when we don't need 1153 to do this. Perhaps when top-left weighting and no gravity? */ 1154 1155 RootlessDamageRect(pWin, -newBW, -newBW, newW, newH); 1156 1157 for (i = 0; i < 2; i++) { 1158 if (gResizeDeathPix[i] != NULL) { 1159 FreeScratchPixmapHeader(gResizeDeathPix[i]); 1160 gResizeDeathPix[i] = NULL; 1161 } 1162 } 1163 1164 free(gResizeDeathBits); 1165 gResizeDeathBits = NULL; 1166 1167 if (gravity) { 1168 pScreen->CopyWindow = gResizeOldCopyWindowProc; 1169 } 1170} 1171 1172/* 1173 * RootlessMoveWindow 1174 * If kind==VTOther, window border is resizing (and borderWidth is 1175 * already changed!!@#$) This case works like window resize, not move. 1176 */ 1177void 1178RootlessMoveWindow(WindowPtr pWin, int x, int y, WindowPtr pSib, VTKind kind) 1179{ 1180 RootlessWindowRec *winRec = WINREC(pWin); 1181 ScreenPtr pScreen = pWin->drawable.pScreen; 1182 CopyWindowProcPtr oldCopyWindowProc = NULL; 1183 int oldX = 0, oldY = 0, newX = 0, newY = 0; 1184 unsigned int oldW = 0, oldH = 0, oldBW = 0; 1185 unsigned int newW = 0, newH = 0, newBW = 0; 1186 Bool resize_after = FALSE; 1187 RegionRec saveRoot; 1188 1189 RL_DEBUG_MSG("movewindow start \n"); 1190 1191 if (winRec) { 1192 if (kind == VTMove) { 1193 oldX = winRec->x; 1194 oldY = winRec->y; 1195 RootlessRedisplay(pWin); 1196 RootlessStartDrawing(pWin); 1197 } 1198 else { 1199 RL_DEBUG_MSG("movewindow border resizing "); 1200 1201 oldBW = winRec->borderWidth; 1202 oldX = winRec->x; 1203 oldY = winRec->y; 1204 oldW = winRec->width; 1205 oldH = winRec->height; 1206 1207 newBW = wBorderWidth(pWin); 1208 newX = x; 1209 newY = y; 1210 newW = pWin->drawable.width + 2 * newBW; 1211 newH = pWin->drawable.height + 2 * newBW; 1212 1213 resize_after = StartFrameResize(pWin, FALSE, 1214 oldX, oldY, oldW, oldH, oldBW, 1215 newX, newY, newW, newH, newBW); 1216 } 1217 } 1218 1219 HUGE_ROOT(pWin); 1220 SCREEN_UNWRAP(pScreen, MoveWindow); 1221 1222 if (winRec) { 1223 oldCopyWindowProc = pScreen->CopyWindow; 1224 pScreen->CopyWindow = RootlessNoCopyWindow; 1225 } 1226 pScreen->MoveWindow(pWin, x, y, pSib, kind); 1227 if (winRec) { 1228 pScreen->CopyWindow = oldCopyWindowProc; 1229 } 1230 1231 NORMAL_ROOT(pWin); 1232 SCREEN_WRAP(pScreen, MoveWindow); 1233 1234 if (winRec) { 1235 if (kind == VTMove) { 1236 winRec->x = x; 1237 winRec->y = y; 1238 RootlessStopDrawing(pWin, FALSE); 1239 SCREENREC(pScreen)->imp->MoveFrame(winRec->wid, pScreen, 1240 x + SCREEN_TO_GLOBAL_X, 1241 y + SCREEN_TO_GLOBAL_Y); 1242 } 1243 else { 1244 FinishFrameResize(pWin, FALSE, oldX, oldY, oldW, oldH, oldBW, 1245 newX, newY, newW, newH, newBW, resize_after); 1246 } 1247 } 1248 1249 RL_DEBUG_MSG("movewindow end\n"); 1250} 1251 1252/* 1253 * RootlessResizeWindow 1254 * Note: (x, y, w, h) as passed to this procedure don't match the frame 1255 * definition. (x,y) is corner of very outer edge, *outside* border. 1256 * w,h is width and height *inside* border, *ignoring* border width. 1257 * The rect (x, y, w, h) doesn't mean anything. (x, y, w+2*bw, h+2*bw) 1258 * is total rect and (x+bw, y+bw, w, h) is inner rect. 1259 */ 1260void 1261RootlessResizeWindow(WindowPtr pWin, int x, int y, 1262 unsigned int w, unsigned int h, WindowPtr pSib) 1263{ 1264 RootlessWindowRec *winRec = WINREC(pWin); 1265 ScreenPtr pScreen = pWin->drawable.pScreen; 1266 int oldX = 0, oldY = 0, newX = 0, newY = 0; 1267 unsigned int oldW = 0, oldH = 0, oldBW = 0, newW = 0, newH = 0, newBW = 0; 1268 Bool resize_after = FALSE; 1269 RegionRec saveRoot; 1270 1271 RL_DEBUG_MSG("resizewindow start (win 0x%x) ", pWin); 1272 1273 if (pWin->parent) { 1274 if (winRec) { 1275 oldBW = winRec->borderWidth; 1276 oldX = winRec->x; 1277 oldY = winRec->y; 1278 oldW = winRec->width; 1279 oldH = winRec->height; 1280 1281 newBW = oldBW; 1282 newX = x; 1283 newY = y; 1284 newW = w + 2 * newBW; 1285 newH = h + 2 * newBW; 1286 1287 resize_after = StartFrameResize(pWin, TRUE, 1288 oldX, oldY, oldW, oldH, oldBW, 1289 newX, newY, newW, newH, newBW); 1290 } 1291 1292 HUGE_ROOT(pWin); 1293 SCREEN_UNWRAP(pScreen, ResizeWindow); 1294 pScreen->ResizeWindow(pWin, x, y, w, h, pSib); 1295 SCREEN_WRAP(pScreen, ResizeWindow); 1296 NORMAL_ROOT(pWin); 1297 1298 if (winRec) { 1299 FinishFrameResize(pWin, TRUE, oldX, oldY, oldW, oldH, oldBW, 1300 newX, newY, newW, newH, newBW, resize_after); 1301 } 1302 } 1303 else { 1304 /* Special case for resizing the root window */ 1305 BoxRec box; 1306 1307 pWin->drawable.x = x; 1308 pWin->drawable.y = y; 1309 pWin->drawable.width = w; 1310 pWin->drawable.height = h; 1311 1312 box.x1 = x; 1313 box.y1 = y; 1314 box.x2 = x + w; 1315 box.y2 = y + h; 1316 RegionUninit(&pWin->winSize); 1317 RegionInit(&pWin->winSize, &box, 1); 1318 RegionCopy(&pWin->borderSize, &pWin->winSize); 1319 RegionCopy(&pWin->clipList, &pWin->winSize); 1320 RegionCopy(&pWin->borderClip, &pWin->winSize); 1321 1322 if (winRec) { 1323 SCREENREC(pScreen)->imp->ResizeFrame(winRec->wid, pScreen, 1324 x + SCREEN_TO_GLOBAL_X, 1325 y + SCREEN_TO_GLOBAL_Y, 1326 w, h, RL_GRAVITY_NONE); 1327 } 1328 1329 miSendExposures(pWin, &pWin->borderClip, 1330 pWin->drawable.x, pWin->drawable.y); 1331 } 1332 1333 RL_DEBUG_MSG("resizewindow end\n"); 1334} 1335 1336/* 1337 * RootlessRepositionWindow 1338 * Called by the implementation when a window needs to be repositioned to 1339 * its correct location on the screen. This routine is typically needed 1340 * due to changes in the underlying window system, such as a screen layout 1341 * change. 1342 */ 1343void 1344RootlessRepositionWindow(WindowPtr pWin) 1345{ 1346 RootlessWindowRec *winRec = WINREC(pWin); 1347 ScreenPtr pScreen = pWin->drawable.pScreen; 1348 1349 if (winRec == NULL) 1350 return; 1351 1352 RootlessStopDrawing(pWin, FALSE); 1353 SCREENREC(pScreen)->imp->MoveFrame(winRec->wid, pScreen, 1354 winRec->x + SCREEN_TO_GLOBAL_X, 1355 winRec->y + SCREEN_TO_GLOBAL_Y); 1356 1357 RootlessReorderWindow(pWin); 1358} 1359 1360/* 1361 * RootlessReparentWindow 1362 * Called after a window has been reparented. Generally windows are not 1363 * framed until they are mapped. However, a window may be framed early by the 1364 * implementation calling RootlessFrameForWindow. (e.g. this could be needed 1365 * to attach a VRAM surface to it.) If the window is subsequently reparented 1366 * by the window manager before being mapped, we need to give the frame to 1367 * the new top-level window. 1368 */ 1369void 1370RootlessReparentWindow(WindowPtr pWin, WindowPtr pPriorParent) 1371{ 1372 ScreenPtr pScreen = pWin->drawable.pScreen; 1373 RootlessWindowRec *winRec = WINREC(pWin); 1374 WindowPtr pTopWin; 1375 1376 /* Check that window is not top-level now, but used to be. */ 1377 if (IsRoot(pWin) || IsRoot(pWin->parent) 1378 || IsTopLevel(pWin) || winRec == NULL) { 1379 goto out; 1380 } 1381 1382 /* If the formerly top-level window has a frame, we want to give the 1383 frame to its new top-level parent. If we can't do that, we'll just 1384 have to jettison it... */ 1385 1386 pTopWin = TopLevelParent(pWin); 1387 assert(pTopWin != pWin); 1388 1389 pWin->unhittable = FALSE; 1390 1391 DeleteProperty(serverClient, pWin, xa_native_window_id()); 1392 1393 if (WINREC(pTopWin) != NULL) { 1394 /* We're screwed. */ 1395 RootlessDestroyFrame(pWin, winRec); 1396 } 1397 else { 1398 if (!pTopWin->realized && pWin->realized) { 1399 SCREENREC(pScreen)->imp->UnmapFrame(winRec->wid); 1400 } 1401 1402 /* Switch the frame record from one to the other. */ 1403 1404 SETWINREC(pWin, NULL); 1405 SETWINREC(pTopWin, winRec); 1406 1407 RootlessInitializeFrame(pTopWin, winRec); 1408 RootlessReshapeFrame(pTopWin); 1409 1410 SCREENREC(pScreen)->imp->ResizeFrame(winRec->wid, pScreen, 1411 winRec->x + SCREEN_TO_GLOBAL_X, 1412 winRec->y + SCREEN_TO_GLOBAL_Y, 1413 winRec->width, winRec->height, 1414 RL_GRAVITY_NONE); 1415 1416 if (SCREENREC(pScreen)->imp->SwitchWindow) { 1417 SCREENREC(pScreen)->imp->SwitchWindow(winRec, pWin); 1418 } 1419 1420 if (pTopWin->realized && !pWin->realized) 1421 winRec->is_reorder_pending = TRUE; 1422 } 1423 1424 out: 1425 if (SCREENREC(pScreen)->ReparentWindow) { 1426 SCREEN_UNWRAP(pScreen, ReparentWindow); 1427 pScreen->ReparentWindow(pWin, pPriorParent); 1428 SCREEN_WRAP(pScreen, ReparentWindow); 1429 } 1430} 1431 1432void 1433RootlessFlushWindowColormap(WindowPtr pWin) 1434{ 1435 RootlessWindowRec *winRec = WINREC(pWin); 1436 ScreenPtr pScreen = pWin->drawable.pScreen; 1437 1438 if (winRec == NULL) 1439 return; 1440 1441 RootlessStopDrawing(pWin, FALSE); 1442 1443 if (SCREENREC(pScreen)->imp->UpdateColormap) 1444 SCREENREC(pScreen)->imp->UpdateColormap(winRec->wid, pScreen); 1445} 1446 1447/* 1448 * RootlessChangeBorderWidth 1449 * FIXME: untested! 1450 * pWin inside corner stays the same; pWin->drawable.[xy] stays the same 1451 * Frame moves and resizes. 1452 */ 1453void 1454RootlessChangeBorderWidth(WindowPtr pWin, unsigned int width) 1455{ 1456 RegionRec saveRoot; 1457 Bool resize_after = FALSE; 1458 1459 RL_DEBUG_MSG("change border width "); 1460 1461 if (width != wBorderWidth(pWin)) { 1462 RootlessWindowRec *winRec = WINREC(pWin); 1463 int oldX = 0, oldY = 0, newX = 0, newY = 0; 1464 unsigned int oldW = 0, oldH = 0, oldBW = 0; 1465 unsigned int newW = 0, newH = 0, newBW = 0; 1466 1467 if (winRec) { 1468 oldBW = winRec->borderWidth; 1469 oldX = winRec->x; 1470 oldY = winRec->y; 1471 oldW = winRec->width; 1472 oldH = winRec->height; 1473 1474 newBW = width; 1475 newX = pWin->drawable.x - newBW; 1476 newY = pWin->drawable.y - newBW; 1477 newW = pWin->drawable.width + 2 * newBW; 1478 newH = pWin->drawable.height + 2 * newBW; 1479 1480 resize_after = StartFrameResize(pWin, FALSE, 1481 oldX, oldY, oldW, oldH, oldBW, 1482 newX, newY, newW, newH, newBW); 1483 } 1484 1485 HUGE_ROOT(pWin); 1486 SCREEN_UNWRAP(pWin->drawable.pScreen, ChangeBorderWidth); 1487 pWin->drawable.pScreen->ChangeBorderWidth(pWin, width); 1488 SCREEN_WRAP(pWin->drawable.pScreen, ChangeBorderWidth); 1489 NORMAL_ROOT(pWin); 1490 1491 if (winRec) { 1492 FinishFrameResize(pWin, FALSE, oldX, oldY, oldW, oldH, oldBW, 1493 newX, newY, newW, newH, newBW, resize_after); 1494 } 1495 } 1496 1497 RL_DEBUG_MSG("change border width end\n"); 1498} 1499 1500/* 1501 * RootlessOrderAllWindows 1502 * Brings all X11 windows to the top of the window stack 1503 * (i.e in front of Aqua windows) -- called when X11.app is given focus 1504 */ 1505void 1506RootlessOrderAllWindows(Bool include_unhitable) 1507{ 1508 int i; 1509 WindowPtr pWin; 1510 1511 if (windows_hidden) 1512 return; 1513 1514 RL_DEBUG_MSG("RootlessOrderAllWindows() "); 1515 for (i = 0; i < screenInfo.numScreens; i++) { 1516 if (screenInfo.screens[i] == NULL) 1517 continue; 1518 pWin = screenInfo.screens[i]->root; 1519 if (pWin == NULL) 1520 continue; 1521 1522 for (pWin = pWin->firstChild; pWin != NULL; pWin = pWin->nextSib) { 1523 if (!pWin->realized) 1524 continue; 1525 if (RootlessEnsureFrame(pWin) == NULL) 1526 continue; 1527 if (!include_unhitable && pWin->unhittable) 1528 continue; 1529 RootlessReorderWindow(pWin); 1530 } 1531 } 1532 RL_DEBUG_MSG("RootlessOrderAllWindows() done"); 1533} 1534 1535void 1536RootlessEnableRoot(ScreenPtr pScreen) 1537{ 1538 WindowPtr pRoot; 1539 1540 pRoot = pScreen->root; 1541 1542 RootlessEnsureFrame(pRoot); 1543 (*pScreen->ClearToBackground) (pRoot, 0, 0, 0, 0, TRUE); 1544 RootlessReorderWindow(pRoot); 1545} 1546 1547void 1548RootlessDisableRoot(ScreenPtr pScreen) 1549{ 1550 WindowPtr pRoot; 1551 RootlessWindowRec *winRec; 1552 1553 pRoot = pScreen->root; 1554 winRec = WINREC(pRoot); 1555 1556 if (NULL == winRec) 1557 return; 1558 1559 RootlessDestroyFrame(pRoot, winRec); 1560 DeleteProperty(serverClient, pRoot, xa_native_window_id()); 1561} 1562 1563void 1564RootlessHideAllWindows(void) 1565{ 1566 int i; 1567 ScreenPtr pScreen; 1568 WindowPtr pWin; 1569 RootlessWindowRec *winRec; 1570 1571 if (windows_hidden) 1572 return; 1573 1574 windows_hidden = TRUE; 1575 1576 for (i = 0; i < screenInfo.numScreens; i++) { 1577 pScreen = screenInfo.screens[i]; 1578 if (pScreen == NULL) 1579 continue; 1580 pWin = pScreen->root; 1581 if (pWin == NULL) 1582 continue; 1583 1584 for (pWin = pWin->firstChild; pWin != NULL; pWin = pWin->nextSib) { 1585 if (!pWin->realized) 1586 continue; 1587 1588 RootlessStopDrawing(pWin, FALSE); 1589 1590 winRec = WINREC(pWin); 1591 if (winRec != NULL) { 1592 if (SCREENREC(pScreen)->imp->HideWindow) 1593 SCREENREC(pScreen)->imp->HideWindow(winRec->wid); 1594 } 1595 } 1596 } 1597} 1598 1599void 1600RootlessShowAllWindows(void) 1601{ 1602 int i; 1603 ScreenPtr pScreen; 1604 WindowPtr pWin; 1605 RootlessWindowRec *winRec; 1606 1607 if (!windows_hidden) 1608 return; 1609 1610 windows_hidden = FALSE; 1611 1612 for (i = 0; i < screenInfo.numScreens; i++) { 1613 pScreen = screenInfo.screens[i]; 1614 if (pScreen == NULL) 1615 continue; 1616 pWin = pScreen->root; 1617 if (pWin == NULL) 1618 continue; 1619 1620 for (pWin = pWin->firstChild; pWin != NULL; pWin = pWin->nextSib) { 1621 if (!pWin->realized) 1622 continue; 1623 1624 winRec = RootlessEnsureFrame(pWin); 1625 if (winRec == NULL) 1626 continue; 1627 1628 RootlessReorderWindow(pWin); 1629 } 1630 1631 RootlessScreenExpose(pScreen); 1632 } 1633} 1634 1635/* 1636 * SetPixmapOfAncestors 1637 * Set the Pixmaps on all ParentRelative windows up the ancestor chain. 1638 */ 1639void 1640RootlessSetPixmapOfAncestors(WindowPtr pWin) 1641{ 1642 ScreenPtr pScreen = pWin->drawable.pScreen; 1643 WindowPtr topWin = TopLevelParent(pWin); 1644 RootlessWindowRec *topWinRec = WINREC(topWin); 1645 1646 while (pWin->backgroundState == ParentRelative) { 1647 if (pWin == topWin) { 1648 // disallow ParentRelative background state on top level 1649 XID pixel = 0; 1650 1651 ChangeWindowAttributes(pWin, CWBackPixel, &pixel, serverClient); 1652 RL_DEBUG_MSG("Cleared ParentRelative on 0x%x.\n", pWin); 1653 break; 1654 } 1655 1656 pWin = pWin->parent; 1657 pScreen->SetWindowPixmap(pWin, topWinRec->pixmap); 1658 } 1659} 1660