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