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