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