1/* 2 * tkMacOSXSubwindows.c -- 3 * 4 * Implements subwindows for the macintosh version of Tk. 5 * 6 * Copyright (c) 1995-1997 Sun Microsystems, Inc. 7 * Copyright 2001, Apple Computer, Inc. 8 * Copyright (c) 2006-2008 Daniel A. Steffen <das@users.sourceforge.net> 9 * 10 * See the file "license.terms" for information on usage and redistribution 11 * of this file, and for a DISCLAIMER OF ALL WARRANTIES. 12 * 13 * RCS: @(#) $Id: tkMacOSXSubwindows.c,v 1.2.2.22 2007/12/18 18:21:31 das Exp $ 14 */ 15 16#include "tkMacOSXPrivate.h" 17#include "tkMacOSXDebug.h" 18#include "tkMacOSXWm.h" 19 20/* 21#ifdef TK_MAC_DEBUG 22#define TK_MAC_DEBUG_CLIP_REGIONS 23#endif 24*/ 25 26/* 27 * Prototypes for functions used only in this file. 28 */ 29 30static void MoveResizeWindow(MacDrawable *macWin); 31static void GenerateConfigureNotify(TkWindow *winPtr, int includeWin); 32static void UpdateOffsets(TkWindow *winPtr, int deltaX, int deltaY); 33static void NotifyVisibility(TkWindow *winPtr, XEvent *eventPtr); 34 35 36/* 37 *---------------------------------------------------------------------- 38 * 39 * XDestroyWindow -- 40 * 41 * Dealocates the given X Window. 42 * 43 * Results: 44 * The window id is returned. 45 * 46 * Side effects: 47 * None. 48 * 49 *---------------------------------------------------------------------- 50 */ 51 52void 53XDestroyWindow( 54 Display* display, /* Display. */ 55 Window window) /* Window. */ 56{ 57 MacDrawable *macWin = (MacDrawable *) window; 58 59 /* 60 * Remove any dangling pointers that may exist if 61 * the window we are deleting is being tracked by 62 * the grab code. 63 */ 64 65 TkPointerDeadWindow(macWin->winPtr); 66 macWin->toplevel->referenceCount--; 67 68 if (Tk_IsTopLevel(macWin->winPtr)) { 69 WindowRef winRef; 70 /* 71 * We are relying on the Activate Mac OS event to pass the 72 * focus away from a window that is getting Destroyed to the 73 * Front non-floating window. BUT we don't get activate events 74 * when a floating window is destroyed - since the front non-floating 75 * window doesn't in fact get activated... So maybe we can check here 76 * and if we are destroying a floating window, we can pass the focus 77 * back to the front non-floating window... 78 */ 79 80 if (macWin->grafPtr != NULL) { 81 TkWindow *focusPtr = TkGetFocusWin(macWin->winPtr); 82 if (focusPtr == NULL || (focusPtr->mainPtr->winPtr == macWin->winPtr)) { 83 winRef = TkMacOSXDrawableWindow(window); 84 if (TkpIsWindowFloating (winRef)) { 85 Window window; 86 87 window = TkMacOSXGetXWindow(ActiveNonFloatingWindow()); 88 if (window != None) { 89 TkMacOSXGenerateFocusEvent(window, 1); 90 } 91 } 92 } 93 } 94 if (macWin->visRgn) { 95 CFRelease(macWin->visRgn); 96 } 97 if (macWin->aboveVisRgn) { 98 CFRelease(macWin->aboveVisRgn); 99 } 100 101 /* 102 * Delete the Mac window and remove it from the windowTable. 103 * The window could be NULL if the window was never mapped. 104 * However, we don't do this for embedded windows, they don't 105 * go in the window list, and they do not own their portPtr's. 106 */ 107 108 if (!(Tk_IsEmbedded(macWin->winPtr))) { 109 WindowRef winRef = TkMacOSXDrawableWindow(window); 110 111 if (winRef) { 112 TkMacOSXWindowList *listPtr, *prevPtr; 113 WindowGroupRef group; 114 115 if (GetWindowProperty(winRef, 'Tk ', 'TsGp', sizeof(group), 116 NULL, &group) == noErr) { 117 TkDisplay *dispPtr = TkGetDisplayList(); 118 ItemCount i = CountWindowGroupContents(group, 119 kWindowGroupContentsReturnWindows); 120 121 while (i > 0) { 122 WindowRef macWin; 123 124 ChkErr(GetIndexedWindow, group, i--, 0, &macWin); 125 if (macWin) { 126 WindowGroupRef newGroup = NULL; 127 Window window = TkMacOSXGetXWindow(macWin); 128 129 if (window != None) { 130 TkWindow * winPtr = (TkWindow *)Tk_IdToWindow( 131 dispPtr->display, window); 132 133 if (winPtr && winPtr->wmInfoPtr) { 134 newGroup = GetWindowGroupOfClass( 135 winPtr->wmInfoPtr->macClass); 136 } 137 } 138 if (!newGroup) { 139 newGroup = GetWindowGroupOfClass( 140 kDocumentWindowClass); 141 } 142 ChkErr(SetWindowGroup, macWin, newGroup); 143 } 144 145 } 146 ChkErr(SetWindowGroupOwner, group, NULL); 147 ChkErr(ReleaseWindowGroup, group); 148 } 149 TkMacOSXUnregisterMacWindow(winRef); 150 DisposeWindow(winRef); 151 152 for (listPtr = tkMacOSXWindowListPtr, prevPtr = NULL; 153 tkMacOSXWindowListPtr != NULL; 154 prevPtr = listPtr, listPtr = listPtr->nextPtr) { 155 if (listPtr->winPtr == macWin->winPtr) { 156 if (prevPtr == NULL) { 157 tkMacOSXWindowListPtr = listPtr->nextPtr; 158 } else { 159 prevPtr->nextPtr = listPtr->nextPtr; 160 } 161 ckfree((char *) listPtr); 162 break; 163 } 164 } 165 } 166 } 167 168 macWin->grafPtr = NULL; 169 170 /* 171 * Delay deletion of a toplevel data structure untill all 172 * children have been deleted. 173 */ 174 if (macWin->toplevel->referenceCount == 0) { 175 ckfree((char *) macWin->toplevel); 176 } 177 } else { 178 TkMacOSXInvalidateWindow(macWin, TK_PARENT_WINDOW); 179 if (macWin->winPtr->parentPtr != NULL) { 180 TkMacOSXInvalClipRgns((Tk_Window) macWin->winPtr->parentPtr); 181 } 182 if (macWin->visRgn) { 183 CFRelease(macWin->visRgn); 184 } 185 if (macWin->aboveVisRgn) { 186 CFRelease(macWin->aboveVisRgn); 187 } 188 189 if (macWin->toplevel->referenceCount == 0) { 190 ckfree((char *) macWin->toplevel); 191 } 192 ckfree((char *) macWin); 193 } 194} 195 196/* 197 *---------------------------------------------------------------------- 198 * 199 * XMapWindow -- 200 * 201 * Map the given X Window to the screen. See X window documentation 202 * for more details. 203 * 204 * Results: 205 * None. 206 * 207 * Side effects: 208 * The subwindow or toplevel may appear on the screen. 209 * 210 *---------------------------------------------------------------------- 211 */ 212 213void 214XMapWindow( 215 Display* display, /* Display. */ 216 Window window) /* Window. */ 217{ 218 MacDrawable *macWin = (MacDrawable *) window; 219 XEvent event; 220 221 /* 222 * Under certain situations it's possible for this function to be 223 * called before the toplevel window it's associated with has actually 224 * been mapped. In that case we need to create the real Macintosh 225 * window now as this function as well as other X functions assume that 226 * the portPtr is valid. 227 */ 228 if (!TkMacOSXHostToplevelExists(macWin->toplevel->winPtr)) { 229 TkMacOSXMakeRealWindowExist(macWin->toplevel->winPtr); 230 } 231 232 display->request++; 233 macWin->winPtr->flags |= TK_MAPPED; 234 if (Tk_IsTopLevel(macWin->winPtr)) { 235 if (!Tk_IsEmbedded(macWin->winPtr)) { 236 /* 237 * XXX This should be ShowSheetWindow for kSheetWindowClass 238 * XXX windows that have a wmPtr->master parent set. 239 */ 240 WindowRef wRef = TkMacOSXDrawableWindow(window); 241 242 if ((macWin->winPtr->wmInfoPtr->macClass == kSheetWindowClass) 243 && (macWin->winPtr->wmInfoPtr->master != None)) { 244 ShowSheetWindow(wRef, TkMacOSXDrawableWindow( 245 macWin->winPtr->wmInfoPtr->master)); 246 } else { 247 ShowWindow(wRef); 248 } 249 } 250 TkMacOSXInvalClipRgns((Tk_Window) macWin->winPtr); 251 252 /* 253 * We only need to send the MapNotify event 254 * for toplevel windows. 255 */ 256 257 event.xany.serial = display->request; 258 event.xany.send_event = False; 259 event.xany.display = display; 260 261 event.xmap.window = window; 262 event.xmap.type = MapNotify; 263 event.xmap.event = window; 264 event.xmap.override_redirect = macWin->winPtr->atts.override_redirect; 265 Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); 266 } else { 267 /* 268 * Generate damage for that area of the window 269 */ 270 271 TkMacOSXInvalClipRgns((Tk_Window) macWin->winPtr->parentPtr); 272 TkMacOSXInvalidateWindow(macWin, TK_PARENT_WINDOW); 273 } 274 275 /* 276 * Generate VisibilityNotify events for window and all mapped children. 277 */ 278 279 event.xany.send_event = False; 280 event.xany.display = display; 281 event.xvisibility.type = VisibilityNotify; 282 event.xvisibility.state = VisibilityUnobscured; 283 NotifyVisibility(macWin->winPtr, &event); 284} 285 286/* 287 *---------------------------------------------------------------------- 288 * 289 * NotifyVisibility -- 290 * 291 * Recursively called helper proc for XMapWindow(). 292 293 * Results: 294 * None. 295 * 296 * Side effects: 297 * VisibilityNotify events are queued. 298 * 299 *---------------------------------------------------------------------- 300 */ 301 302static void 303NotifyVisibility( 304 TkWindow *winPtr, 305 XEvent *eventPtr) 306{ 307 if (winPtr->atts.event_mask & VisibilityChangeMask) { 308 eventPtr->xany.serial = LastKnownRequestProcessed(winPtr->display); 309 eventPtr->xvisibility.window = winPtr->window; 310 Tk_QueueWindowEvent(eventPtr, TCL_QUEUE_TAIL); 311 } 312 for (winPtr = winPtr->childList; winPtr != NULL; 313 winPtr = winPtr->nextPtr) { 314 if (winPtr->flags & TK_MAPPED) { 315 NotifyVisibility(winPtr, eventPtr); 316 } 317 } 318} 319 320/* 321 *---------------------------------------------------------------------- 322 * 323 * XUnmapWindow -- 324 * 325 * Unmap the given X Window to the screen. See X window 326 * documentation for more details. 327 * 328 * Results: 329 * None. 330 * 331 * Side effects: 332 * The subwindow or toplevel may be removed from the screen. 333 * 334 *---------------------------------------------------------------------- 335 */ 336 337void 338XUnmapWindow( 339 Display* display, /* Display. */ 340 Window window) /* Window. */ 341{ 342 MacDrawable *macWin = (MacDrawable *) window; 343 XEvent event; 344 345 display->request++; 346 macWin->winPtr->flags &= ~TK_MAPPED; 347 if (Tk_IsTopLevel(macWin->winPtr)) { 348 if (!Tk_IsEmbedded(macWin->winPtr) 349 && macWin->winPtr->wmInfoPtr->hints.initial_state != IconicState) { 350 /* 351 * XXX This should be HideSheetWindow for kSheetWindowClass 352 * XXX windows that have a wmPtr->master parent set. 353 */ 354 WindowRef wref = TkMacOSXDrawableWindow(window); 355 356 if ((macWin->winPtr->wmInfoPtr->macClass == kSheetWindowClass) 357 && (macWin->winPtr->wmInfoPtr->master != None)) { 358 HideSheetWindow(wref); 359 } else { 360 HideWindow(wref); 361 } 362 } 363 TkMacOSXInvalClipRgns((Tk_Window) macWin->winPtr); 364 365 /* 366 * We only need to send the UnmapNotify event 367 * for toplevel windows. 368 */ 369 event.xany.serial = display->request; 370 event.xany.send_event = False; 371 event.xany.display = display; 372 373 event.xunmap.type = UnmapNotify; 374 event.xunmap.window = window; 375 event.xunmap.event = window; 376 event.xunmap.from_configure = false; 377 Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); 378 } else { 379 /* 380 * Generate damage for that area of the window. 381 */ 382 383 TkMacOSXInvalidateWindow(macWin, TK_PARENT_WINDOW); 384 TkMacOSXInvalClipRgns((Tk_Window) macWin->winPtr->parentPtr); 385 } 386} 387 388/* 389 *---------------------------------------------------------------------- 390 * 391 * XResizeWindow -- 392 * 393 * Resize a given X window. See X windows documentation for 394 * further details. 395 * 396 * Results: 397 * None. 398 * 399 * Side effects: 400 * None. 401 * 402 *---------------------------------------------------------------------- 403 */ 404 405void 406XResizeWindow( 407 Display* display, /* Display. */ 408 Window window, /* Window. */ 409 unsigned int width, 410 unsigned int height) 411{ 412 MacDrawable *macWin = (MacDrawable *) window; 413 414 display->request++; 415 if (Tk_IsTopLevel(macWin->winPtr) && !Tk_IsEmbedded(macWin->winPtr)) { 416 WindowRef w = TkMacOSXDrawableWindow(window); 417 418 if (w) { 419 Rect bounds; 420 421 ChkErr(GetWindowBounds, w, kWindowContentRgn, &bounds); 422 bounds.right = bounds.left + width; 423 bounds.bottom = bounds.top + height; 424 ChkErr(SetWindowBounds, w, kWindowContentRgn, &bounds); 425 } 426 } else { 427 MoveResizeWindow(macWin); 428 } 429} 430 431/* 432 *---------------------------------------------------------------------- 433 * 434 * XMoveResizeWindow -- 435 * 436 * Move or resize a given X window. See X windows documentation 437 * for further details. 438 * 439 * Results: 440 * None. 441 * 442 * Side effects: 443 * None. 444 * 445 *---------------------------------------------------------------------- 446 */ 447 448void 449XMoveResizeWindow( 450 Display* display, /* Display. */ 451 Window window, /* Window. */ 452 int x, int y, 453 unsigned int width, 454 unsigned int height) 455{ 456 MacDrawable * macWin = (MacDrawable *) window; 457 458 display->request++; 459 if (Tk_IsTopLevel(macWin->winPtr) && !Tk_IsEmbedded(macWin->winPtr)) { 460 WindowRef w = TkMacOSXDrawableWindow(window); 461 462 if (w) { 463 Rect bounds; 464 465 bounds.left = x + macWin->winPtr->wmInfoPtr->xInParent; 466 bounds.right = bounds.left + width; 467 bounds.top = y + macWin->winPtr->wmInfoPtr->yInParent; 468 bounds.bottom = bounds.top + height; 469 ChkErr(SetWindowBounds, w, kWindowContentRgn, &bounds); 470 } 471 } else { 472 MoveResizeWindow(macWin); 473 } 474} 475 476/* 477 *---------------------------------------------------------------------- 478 * 479 * XMoveWindow -- 480 * 481 * Move a given X window. See X windows documentation for further 482 * details. 483 * 484 * Results: 485 * None. 486 * 487 * Side effects: 488 * None. 489 * 490 *---------------------------------------------------------------------- 491 */ 492 493void 494XMoveWindow( 495 Display* display, /* Display. */ 496 Window window, /* Window. */ 497 int x, 498 int y) 499{ 500 MacDrawable *macWin = (MacDrawable *) window; 501 502 display->request++; 503 if (Tk_IsTopLevel(macWin->winPtr) && !Tk_IsEmbedded(macWin->winPtr)) { 504 WindowRef w = TkMacOSXDrawableWindow(window); 505 506 if (w) { 507 ChkErr(MoveWindowStructure, w, x, y); 508 } 509 } else { 510 MoveResizeWindow(macWin); 511 } 512} 513 514/* 515 *---------------------------------------------------------------------- 516 * 517 * MoveResizeWindow -- 518 * 519 * Helper proc for XResizeWindow, XMoveResizeWindow and XMoveWindow. 520 * 521 * Results: 522 * None. 523 * 524 * Side effects: 525 * None. 526 * 527 *---------------------------------------------------------------------- 528 */ 529 530static void 531MoveResizeWindow( 532 MacDrawable *macWin) 533{ 534 int deltaX = 0, deltaY = 0, parentBorderwidth = 0; 535 MacDrawable *macParent = NULL; 536 CGrafPtr destPort = TkMacOSXGetDrawablePort((Drawable) macWin); 537 538 /* 539 * Find the Parent window, for an embedded window it will be its container. 540 */ 541 if (Tk_IsEmbedded(macWin->winPtr)) { 542 TkWindow *contWinPtr = TkpGetOtherWindow(macWin->winPtr); 543 544 if (contWinPtr) { 545 macParent = contWinPtr->privatePtr; 546 } else { 547 /* 548 * Here we should handle out of process embedding. 549 * At this point, we are assuming that the changes.x,y is not 550 * maintained, if you need the info get it from Tk_GetRootCoords, 551 * and that the toplevel sits at 0,0 when it is drawn. 552 */ 553 } 554 } else { 555 /* 556 * TODO: update all xOff & yOffs 557 */ 558 559 macParent = macWin->winPtr->parentPtr->privatePtr; 560 parentBorderwidth = macWin->winPtr->parentPtr->changes.border_width; 561 } 562 if (macParent) { 563 deltaX = macParent->xOff + parentBorderwidth + 564 macWin->winPtr->changes.x - macWin->xOff; 565 deltaY = macParent->yOff + parentBorderwidth + 566 macWin->winPtr->changes.y - macWin->yOff; 567 } 568 if (destPort) { 569 TkMacOSXInvalidateWindow(macWin, TK_PARENT_WINDOW); 570 if (macParent) { 571 TkMacOSXInvalClipRgns((Tk_Window) macParent->winPtr); 572 } 573 } 574 UpdateOffsets(macWin->winPtr, deltaX, deltaY); 575 if (destPort) { 576 TkMacOSXInvalidateWindow(macWin, TK_PARENT_WINDOW); 577 } 578 GenerateConfigureNotify(macWin->winPtr, 0); 579} 580 581/* 582 *---------------------------------------------------------------------- 583 * 584 * GenerateConfigureNotify -- 585 * 586 * Generates ConfigureNotify events for all the child widgets 587 * of the widget passed in the winPtr parameter. If includeWin 588 * is true, also generates ConfigureNotify event for the 589 * widget itself. 590 * 591 * Results: 592 * None. 593 * 594 * Side effects: 595 * ConfigureNotify events will be posted. 596 * 597 *---------------------------------------------------------------------- 598 */ 599 600static void 601GenerateConfigureNotify (TkWindow *winPtr, int includeWin) 602{ 603 TkWindow *childPtr; 604 605 for (childPtr = winPtr->childList; childPtr != NULL; 606 childPtr = childPtr->nextPtr) { 607 if (!Tk_IsMapped(childPtr) || Tk_IsTopLevel(childPtr)) { 608 continue; 609 } 610 GenerateConfigureNotify(childPtr, 1); 611 } 612 if (includeWin) { 613 TkDoConfigureNotify(winPtr); 614 } 615} 616 617/* 618 *---------------------------------------------------------------------- 619 * 620 * XRaiseWindow -- 621 * 622 * Change the stacking order of a window. 623 * 624 * Results: 625 * None. 626 * 627 * Side effects: 628 * Changes the stacking order of the specified window. 629 * 630 *---------------------------------------------------------------------- 631 */ 632 633void 634XRaiseWindow( 635 Display* display, /* Display. */ 636 Window window) /* Window. */ 637{ 638 MacDrawable *macWin = (MacDrawable *) window; 639 640 display->request++; 641 if (Tk_IsTopLevel(macWin->winPtr) && !Tk_IsEmbedded(macWin->winPtr)) { 642 TkWmRestackToplevel(macWin->winPtr, Above, NULL); 643 } else { 644 /* 645 * TODO: this should generate damage 646 */ 647 } 648} 649 650#if 0 651/* 652 *---------------------------------------------------------------------- 653 * 654 * XLowerWindow -- 655 * 656 * Change the stacking order of a window. 657 * 658 * Results: 659 * None. 660 * 661 * Side effects: 662 * Changes the stacking order of the specified window. 663 * 664 *---------------------------------------------------------------------- 665 */ 666 667void 668XLowerWindow( 669 Display* display, /* Display. */ 670 Window window) /* Window. */ 671{ 672 MacDrawable *macWin = (MacDrawable *) window; 673 674 display->request++; 675 if (Tk_IsTopLevel(macWin->winPtr) && !Tk_IsEmbedded(macWin->winPtr)) { 676 TkWmRestackToplevel(macWin->winPtr, Below, NULL); 677 } else { 678 /* 679 * TODO: this should generate damage 680 */ 681 } 682} 683#endif 684 685/* 686 *---------------------------------------------------------------------- 687 * 688 * XConfigureWindow -- 689 * 690 * Change the size, position, stacking, or border of the specified 691 * window. 692 * 693 * Results: 694 * None. 695 * 696 * Side effects: 697 * Changes the attributes of the specified window. Note that we 698 * ignore the passed in values and use the values stored in the 699 * TkWindow data structure. 700 * 701 *---------------------------------------------------------------------- 702 */ 703 704void 705XConfigureWindow( 706 Display* display, /* Display. */ 707 Window w, /* Window. */ 708 unsigned int value_mask, 709 XWindowChanges* values) 710{ 711 MacDrawable *macWin = (MacDrawable *) w; 712 TkWindow *winPtr = macWin->winPtr; 713 714 display->request++; 715 716 /* 717 * Change the shape and/or position of the window. 718 */ 719 720 if (value_mask & (CWX|CWY|CWWidth|CWHeight)) { 721 XMoveResizeWindow(display, w, winPtr->changes.x, winPtr->changes.y, 722 winPtr->changes.width, winPtr->changes.height); 723 } 724 725 /* 726 * Change the stacking order of the window. Tk actuall keeps all 727 * the information we need for stacking order. All we need to do 728 * is make sure the clipping regions get updated and generate damage 729 * that will ensure things get drawn correctly. 730 */ 731 732 if (value_mask & CWStackMode) { 733 Rect bounds; 734 WindowRef wRef = TkMacOSXDrawableWindow(w); 735 736 if (wRef) { 737 TkMacOSXInvalClipRgns((Tk_Window) winPtr->parentPtr); 738 TkMacOSXWinBounds(winPtr, &bounds); 739 InvalWindowRect(wRef, &bounds); 740 } 741 } 742 743 /* TkGenWMMoveRequestEvent(macWin->winPtr, 744 macWin->winPtr->changes.x, macWin->winPtr->changes.y); */ 745} 746 747/* 748 *---------------------------------------------------------------------- 749 * 750 * TkMacOSXUpdateClipRgn -- 751 * 752 * This function updates the cliping regions for a given window 753 * and all of its children. Once updated the TK_CLIP_INVALID flag 754 * in the subwindow data structure is unset. The TK_CLIP_INVALID 755 * flag should always be unset before any drawing is attempted. 756 * 757 * Results: 758 * None. 759 * 760 * Side effects: 761 * The clip regions for the window and its children are updated. 762 * 763 *---------------------------------------------------------------------- 764 */ 765 766void 767TkMacOSXUpdateClipRgn( 768 TkWindow *winPtr) 769{ 770 MacDrawable *macWin; 771 772 if (winPtr == NULL) { 773 return; 774 } 775 macWin = winPtr->privatePtr; 776 if (macWin && macWin->flags & TK_CLIP_INVALID) { 777 TkWindow *win2Ptr; 778 779 if (Tk_IsMapped(winPtr)) { 780 int rgnChanged = 0; 781 CGRect bounds; 782 HIMutableShapeRef rgn; 783 784 /* 785 * Start with a region defined by the window bounds. 786 */ 787 788 TkMacOSXWinCGBounds(winPtr, &bounds); 789 rgn = TkMacOSXHIShapeCreateMutableWithRect(&bounds); 790 791 /* 792 * Clip away the area of any windows that may obscure this 793 * window. 794 * For a non-toplevel window, first, clip to the parents visible 795 * clip region. 796 * Second, clip away any siblings that are higher in the 797 * stacking order. 798 * For an embedded toplevel, just clip to the container's visible 799 * clip region. Remember, we only allow one contained window 800 * in a frame, and don't support any other widgets in the frame 801 * either. This is not currently enforced, however. 802 */ 803 804 if (!Tk_IsTopLevel(winPtr)) { 805 TkMacOSXUpdateClipRgn(winPtr->parentPtr); 806 if (winPtr->parentPtr) { 807 ChkErr(HIShapeIntersect, 808 winPtr->parentPtr->privatePtr->aboveVisRgn, rgn, 809 rgn); 810 } 811 win2Ptr = winPtr; 812 while ((win2Ptr = win2Ptr->nextPtr)) { 813 if (Tk_IsTopLevel(win2Ptr) || !Tk_IsMapped(win2Ptr)) { 814 continue; 815 } 816 TkMacOSXWinCGBounds(win2Ptr, &bounds); 817 ChkErr(TkMacOSHIShapeDifferenceWithRect, rgn, &bounds); 818 } 819 } else if (Tk_IsEmbedded(winPtr)) { 820 win2Ptr = TkpGetOtherWindow(winPtr); 821 if (win2Ptr) { 822 TkMacOSXUpdateClipRgn(win2Ptr); 823 ChkErr(HIShapeIntersect, 824 win2Ptr->privatePtr->aboveVisRgn, rgn, rgn); 825 } else if (tkMacOSXEmbedHandler != NULL) { 826 HIShapeRef visRgn; 827 828 TkMacOSXCheckTmpQdRgnEmpty(); 829 tkMacOSXEmbedHandler->getClipProc((Tk_Window) winPtr, 830 tkMacOSXtmpQdRgn); 831 visRgn = HIShapeCreateWithQDRgn(tkMacOSXtmpQdRgn); 832 SetEmptyRgn(tkMacOSXtmpQdRgn); 833 ChkErr(HIShapeIntersect, visRgn, rgn, rgn); 834 } 835 836 /* 837 * TODO: Here we should handle out of process embedding. 838 */ 839 } else if (winPtr->wmInfoPtr->attributes & 840 kWindowResizableAttribute) { 841 HIViewRef growBoxView; 842 OSErr err = HIViewFindByID(HIViewGetRoot( 843 TkMacOSXDrawableWindow(winPtr->window)), 844 kHIViewWindowGrowBoxID, &growBoxView); 845 846 if (err == noErr) { 847 ChkErr(HIViewGetFrame, growBoxView, &bounds); 848 bounds = CGRectOffset(bounds, 849 -winPtr->wmInfoPtr->xInParent, 850 -winPtr->wmInfoPtr->yInParent); 851 ChkErr(TkMacOSHIShapeDifferenceWithRect, rgn, &bounds); 852 } 853 } 854 macWin->aboveVisRgn = HIShapeCreateCopy(rgn); 855 856 /* 857 * The final clip region is the aboveVis region (or visible 858 * region) minus all the children of this window. 859 * If the window is a container, we must also subtract the region 860 * of the embedded window. 861 */ 862 863 win2Ptr = winPtr->childList; 864 while (win2Ptr) { 865 if (Tk_IsTopLevel(win2Ptr) || !Tk_IsMapped(win2Ptr)) { 866 win2Ptr = win2Ptr->nextPtr; 867 continue; 868 } 869 TkMacOSXWinCGBounds(win2Ptr, &bounds); 870 ChkErr(TkMacOSHIShapeDifferenceWithRect, rgn, &bounds); 871 rgnChanged = 1; 872 win2Ptr = win2Ptr->nextPtr; 873 } 874 875 if (Tk_IsContainer(winPtr)) { 876 win2Ptr = TkpGetOtherWindow(winPtr); 877 if (win2Ptr) { 878 if (Tk_IsMapped(win2Ptr)) { 879 TkMacOSXWinCGBounds(win2Ptr, &bounds); 880 ChkErr(TkMacOSHIShapeDifferenceWithRect, rgn, &bounds); 881 rgnChanged = 1; 882 } 883 } 884 885 /* 886 * TODO: Here we should handle out of process embedding. 887 */ 888 } 889 if (rgnChanged) { 890 HIShapeRef diffRgn = HIShapeCreateDifference( 891 macWin->aboveVisRgn, rgn); 892 893 if (!HIShapeIsEmpty(diffRgn)) { 894 macWin->visRgn = HIShapeCreateCopy(rgn); 895 } 896 CFRelease(diffRgn); 897 } 898 CFRelease(rgn); 899 } else { 900 /* 901 * An unmapped window has empty clip regions to prevent any 902 * (erroneous) drawing into it or its children from becoming 903 * visible. [Bug 940117] 904 */ 905 906 if (!Tk_IsTopLevel(winPtr)) { 907 TkMacOSXUpdateClipRgn(winPtr->parentPtr); 908 } else if (Tk_IsEmbedded(winPtr)) { 909 win2Ptr = TkpGetOtherWindow(winPtr); 910 if (win2Ptr) { 911 TkMacOSXUpdateClipRgn(win2Ptr); 912 } 913 } 914 macWin->aboveVisRgn = TkMacOSXHIShapeCreateEmpty(); 915 } 916 if (!macWin->visRgn) { 917 macWin->visRgn = HIShapeCreateCopy(macWin->aboveVisRgn); 918 } 919 macWin->flags &= ~TK_CLIP_INVALID; 920 921#ifdef TK_MAC_DEBUG_CLIP_REGIONS 922 TkMacOSXDebugFlashRegion((Drawable) macWin, macWin->visRgn); 923#endif /* TK_MAC_DEBUG_CLIP_REGIONS */ 924 } 925} 926 927/* 928 *---------------------------------------------------------------------- 929 * 930 * TkMacOSXVisableClipRgn -- 931 * 932 * This function returnd the Macintosh cliping region for the 933 * given window. A NULL Rgn means the window is not visible. 934 * 935 * Results: 936 * The region. 937 * 938 * Side effects: 939 * None. 940 * 941 *---------------------------------------------------------------------- 942 */ 943 944RgnHandle 945TkMacOSXVisableClipRgn( 946 TkWindow *winPtr) 947{ 948 static RgnHandle visQdRgn = NULL; 949 950 if (visQdRgn == NULL) { 951 visQdRgn = NewRgn(); 952 } 953 if (winPtr->privatePtr->flags & TK_CLIP_INVALID) { 954 TkMacOSXUpdateClipRgn(winPtr); 955 } 956 ChkErr(HIShapeGetAsQDRgn, winPtr->privatePtr->visRgn, visQdRgn); 957 return visQdRgn; 958} 959 960/* 961 *---------------------------------------------------------------------- 962 * 963 * TkMacOSXInvalidateWindow -- 964 * 965 * This function makes the window as invalid will generate damage 966 * for the window. 967 * 968 * Results: 969 * None. 970 * 971 * Side effects: 972 * Damage is created. 973 * 974 *---------------------------------------------------------------------- 975 */ 976 977void 978TkMacOSXInvalidateWindow( 979 MacDrawable *macWin, /* Make window that's causing damage. */ 980 int flag) /* Should be TK_WINDOW_ONLY or 981 * TK_PARENT_WINDOW */ 982{ 983 WindowRef windowRef; 984 HIShapeRef rgn; 985 986 windowRef = TkMacOSXDrawableWindow((Drawable)macWin); 987 if (macWin->flags & TK_CLIP_INVALID) { 988 TkMacOSXUpdateClipRgn(macWin->winPtr); 989 } 990 rgn = (flag == TK_WINDOW_ONLY) ? macWin->visRgn : macWin->aboveVisRgn; 991 if (!HIShapeIsEmpty(rgn)) { 992 TkMacOSXCheckTmpQdRgnEmpty(); 993 ChkErr(HIShapeGetAsQDRgn, rgn, tkMacOSXtmpQdRgn); 994 InvalWindowRgn(windowRef, tkMacOSXtmpQdRgn); 995 SetEmptyRgn(tkMacOSXtmpQdRgn); 996 } 997#ifdef TK_MAC_DEBUG_CLIP_REGIONS 998 TkMacOSXDebugFlashRegion((Drawable) macWin, rgn); 999#endif /* TK_MAC_DEBUG_CLIP_REGIONS */ 1000} 1001 1002/* 1003 *---------------------------------------------------------------------- 1004 * 1005 * TkMacOSXGetDrawableWindow -- 1006 * 1007 * This function returns the WindowRef for a given X drawable. 1008 * 1009 * Results: 1010 * A WindowRef, or NULL for off screen pixmaps. 1011 * 1012 * Side effects: 1013 * None. 1014 * 1015 *---------------------------------------------------------------------- 1016 */ 1017 1018WindowRef 1019TkMacOSXDrawableWindow( 1020 Drawable drawable) 1021{ 1022 MacDrawable *macWin = (MacDrawable *) drawable; 1023 WindowRef result = NULL; 1024 1025 if (!macWin || macWin->flags & TK_IS_PIXMAP) { 1026 result = NULL; 1027 } else { 1028 result = GetWindowFromPort(TkMacOSXGetDrawablePort(drawable)); 1029 } 1030 return result; 1031} 1032 1033/* 1034 *---------------------------------------------------------------------- 1035 * 1036 * TkMacOSXGetDrawablePort -- 1037 * 1038 * This function returns the Graphics Port for a given X drawable. 1039 * 1040 * Results: 1041 * A CGrafPort . Either an off screen pixmap or a Window. 1042 * 1043 * Side effects: 1044 * None. 1045 * 1046 *---------------------------------------------------------------------- 1047 */ 1048 1049CGrafPtr 1050TkMacOSXGetDrawablePort( 1051 Drawable drawable) 1052{ 1053 MacDrawable *macWin = (MacDrawable *) drawable; 1054 CGrafPtr resultPort = NULL; 1055 1056 if (macWin) { 1057 if (macWin->toplevel) { 1058 /* 1059 * If the Drawable is in an embedded window, use the Port of its 1060 * container. 1061 * 1062 * TRICKY POINT: we can have cases when a toplevel is being 1063 * destroyed where the winPtr for the toplevel has been freed, but 1064 * the children are not all the way destroyed. The children will 1065 * call this function as they are being destroyed, but 1066 * Tk_IsEmbedded will return garbage. So we check the copy of the 1067 * TK_EMBEDDED flag we put into the toplevel's macWin flags. 1068 */ 1069 1070 if (macWin->toplevel->flags & TK_EMBEDDED) { 1071 TkWindow *contWinPtr; 1072 1073 contWinPtr = TkpGetOtherWindow(macWin->toplevel->winPtr); 1074 1075 if (contWinPtr != NULL) { 1076 resultPort = TkMacOSXGetDrawablePort( 1077 (Drawable) contWinPtr->privatePtr); 1078 } else if (tkMacOSXEmbedHandler != NULL) { 1079 resultPort = tkMacOSXEmbedHandler->getPortProc( 1080 (Tk_Window) macWin->winPtr); 1081 } 1082 1083 if (!resultPort) { 1084 /* 1085 * FIXME: So far as I can tell, the only time that this 1086 * happens is when we are tearing down an embedded child 1087 * interpreter, and most of the time, this is harmless... 1088 * However, we really need to find why the embedding loses. 1089 */ 1090 TkMacOSXDbgMsg("Couldn't find container"); 1091 } 1092 1093 /* 1094 * TODO: Here we should handle out of process embedding. 1095 */ 1096 } else { 1097 resultPort = macWin->toplevel->grafPtr; 1098 } 1099 } else { 1100 if ((macWin->flags & TK_IS_PIXMAP) && !macWin->grafPtr) { 1101 Rect bounds = {0, 0, macWin->size.height, macWin->size.width}; 1102 1103 ChkErr(NewGWorld, &macWin->grafPtr, 1104 (macWin->flags & TK_IS_BW_PIXMAP) ? 1 : 0, 1105 &bounds, NULL, NULL, 0 1106#ifdef __LITTLE_ENDIAN__ 1107 | kNativeEndianPixMap 1108#endif 1109 ); 1110 } 1111 resultPort = macWin->grafPtr; 1112 } 1113 } 1114 1115 return resultPort; 1116} 1117 1118/* 1119 *---------------------------------------------------------------------- 1120 * 1121 * TkMacOSXGetRootControl -- 1122 * 1123 * This function returns the Root Control for a given X drawable. 1124 * 1125 * Results: 1126 * A ControlRef . 1127 * 1128 * Side effects: 1129 * None. 1130 * 1131 *---------------------------------------------------------------------- 1132 */ 1133 1134ControlRef 1135TkMacOSXGetRootControl( 1136 Drawable drawable) 1137{ 1138 /* 1139 * will probably need to fix this up for embedding 1140 */ 1141 MacDrawable *macWin = (MacDrawable *) drawable; 1142 ControlRef result = NULL; 1143 1144 if (macWin == NULL) { 1145 return NULL; 1146 } 1147 if (!(macWin->toplevel->flags & TK_EMBEDDED)) { 1148 return macWin->toplevel->rootControl; 1149 } else { 1150 TkWindow *contWinPtr; 1151 1152 contWinPtr = TkpGetOtherWindow(macWin->toplevel->winPtr); 1153 1154 if (contWinPtr != NULL) { 1155 result = TkMacOSXGetRootControl( 1156 (Drawable) contWinPtr->privatePtr); 1157 } else if (tkMacOSXEmbedHandler != NULL) { 1158 result = NULL; 1159 } 1160 } 1161 return result; 1162} 1163 1164/* 1165 *---------------------------------------------------------------------- 1166 * 1167 * TkMacOSXInvalClipRgns -- 1168 * 1169 * This function invalidates the clipping regions for a given 1170 * window and all of its children. This function should be 1171 * called whenever changes are made to subwindows that would 1172 * affect the size or position of windows. 1173 * 1174 * Results: 1175 * None. 1176 * 1177 * Side effects: 1178 * The cliping regions for the window and its children are 1179 * mark invalid. (Make sure they are valid before drawing.) 1180 * 1181 *---------------------------------------------------------------------- 1182 */ 1183 1184void 1185TkMacOSXInvalClipRgns( 1186 Tk_Window tkwin) 1187{ 1188 TkWindow *winPtr = (TkWindow *) tkwin; 1189 TkWindow *childPtr; 1190 MacDrawable *macWin = winPtr->privatePtr; 1191 1192 /* 1193 * If already marked we can stop because all 1194 * decendants will also already be marked. 1195 */ 1196 if (!macWin || macWin->flags & TK_CLIP_INVALID) { 1197 return; 1198 } 1199 1200 macWin->flags |= TK_CLIP_INVALID; 1201 if (macWin->visRgn) { 1202 CFRelease(macWin->visRgn); 1203 macWin->visRgn = NULL; 1204 } 1205 if (macWin->aboveVisRgn) { 1206 CFRelease(macWin->aboveVisRgn); 1207 macWin->aboveVisRgn = NULL; 1208 } 1209 1210 /* 1211 * Invalidate clip regions for all children & 1212 * their decendants - unless the child is a toplevel. 1213 */ 1214 childPtr = winPtr->childList; 1215 while (childPtr) { 1216 if (!Tk_IsTopLevel(childPtr)) { 1217 TkMacOSXInvalClipRgns((Tk_Window) childPtr); 1218 } 1219 childPtr = childPtr->nextPtr; 1220 } 1221 1222 /* 1223 * Also, if the window is a container, mark its embedded window 1224 */ 1225 1226 if (Tk_IsContainer(winPtr)) { 1227 childPtr = TkpGetOtherWindow(winPtr); 1228 1229 if (childPtr) { 1230 TkMacOSXInvalClipRgns((Tk_Window) childPtr); 1231 } 1232 1233 /* 1234 * TODO: Here we should handle out of process embedding. 1235 */ 1236 } 1237} 1238 1239/* 1240 *---------------------------------------------------------------------- 1241 * 1242 * TkMacOSXWinBounds -- 1243 * 1244 * Given a Tk window this function determines the windows 1245 * bounds in relation to the Macintosh window's coordinate 1246 * system. This is also the same coordinate system as the 1247 * Tk toplevel window in which this window is contained. 1248 * 1249 * Results: 1250 * None. 1251 * 1252 * Side effects: 1253 * None. 1254 * 1255 *---------------------------------------------------------------------- 1256 */ 1257 1258void 1259TkMacOSXWinBounds( 1260 TkWindow *winPtr, 1261 Rect *bounds) 1262{ 1263 bounds->left = winPtr->privatePtr->xOff; 1264 bounds->top = winPtr->privatePtr->yOff; 1265 bounds->right = bounds->left + winPtr->changes.width; 1266 bounds->bottom = bounds->top + winPtr->changes.height; 1267} 1268 1269/* 1270 *---------------------------------------------------------------------- 1271 * 1272 * TkMacOSXWinCGBounds -- 1273 * 1274 * Given a Tk window this function determines the windows 1275 * bounds in relation to the Macintosh window's coordinate 1276 * system. This is also the same coordinate system as the 1277 * Tk toplevel window in which this window is contained. 1278 * 1279 * Results: 1280 * None. 1281 * 1282 * Side effects: 1283 * None. 1284 * 1285 *---------------------------------------------------------------------- 1286 */ 1287 1288void 1289TkMacOSXWinCGBounds( 1290 TkWindow *winPtr, 1291 CGRect *bounds) 1292{ 1293 bounds->origin.x = winPtr->privatePtr->xOff; 1294 bounds->origin.y = winPtr->privatePtr->yOff; 1295 bounds->size.width = winPtr->changes.width; 1296 bounds->size.height = winPtr->changes.height; 1297} 1298 1299/* 1300 *---------------------------------------------------------------------- 1301 * 1302 * UpdateOffsets -- 1303 * 1304 * Updates the X & Y offsets of the given TkWindow from the 1305 * TopLevel it is a decendant of. 1306 * 1307 * Results: 1308 * None. 1309 * 1310 * Side effects: 1311 * The xOff & yOff fields for the Mac window datastructure 1312 * is updated to the proper offset. 1313 * 1314 *---------------------------------------------------------------------- 1315 */ 1316 1317static void 1318UpdateOffsets( 1319 TkWindow *winPtr, 1320 int deltaX, 1321 int deltaY) 1322{ 1323 TkWindow *childPtr; 1324 1325 if (winPtr->privatePtr == NULL) { 1326 /* 1327 * We haven't called Tk_MakeWindowExist for this window yet. The 1328 * offset information will be postponed and calulated at that 1329 * time. (This will usually only happen when a mapped parent is 1330 * being moved but has child windows that have yet to be mapped.) 1331 */ 1332 return; 1333 } 1334 1335 winPtr->privatePtr->xOff += deltaX; 1336 winPtr->privatePtr->yOff += deltaY; 1337 1338 childPtr = winPtr->childList; 1339 while (childPtr != NULL) { 1340 if (!Tk_IsTopLevel(childPtr)) { 1341 UpdateOffsets(childPtr, deltaX, deltaY); 1342 } 1343 childPtr = childPtr->nextPtr; 1344 } 1345 1346 if (Tk_IsContainer(winPtr)) { 1347 childPtr = TkpGetOtherWindow(winPtr); 1348 if (childPtr != NULL) { 1349 UpdateOffsets(childPtr,deltaX,deltaY); 1350 } 1351 1352 /* 1353 * TODO: Here we should handle out of process embedding. 1354 */ 1355 } 1356} 1357 1358/* 1359 *---------------------------------------------------------------------- 1360 * 1361 * Tk_GetPixmap -- 1362 * 1363 * Creates an in memory drawing surface. 1364 * 1365 * Results: 1366 * Returns a handle to a new pixmap. 1367 * 1368 * Side effects: 1369 * Allocates a new Macintosh GWorld. 1370 * 1371 *---------------------------------------------------------------------- 1372 */ 1373 1374Pixmap 1375Tk_GetPixmap( 1376 Display *display, /* Display for new pixmap (can be null). */ 1377 Drawable d, /* Drawable where pixmap will be used (ignored). */ 1378 int width, /* Dimensions of pixmap. */ 1379 int height, 1380 int depth) /* Bits per pixel for pixmap. */ 1381{ 1382 MacDrawable *macPix; 1383 1384 if (display != NULL) { 1385 display->request++; 1386 } 1387 macPix = (MacDrawable *) ckalloc(sizeof(MacDrawable)); 1388 macPix->winPtr = NULL; 1389 macPix->xOff = 0; 1390 macPix->yOff = 0; 1391 macPix->visRgn = NULL; 1392 macPix->aboveVisRgn = NULL; 1393 macPix->drawRect = CGRectNull; 1394 macPix->referenceCount = 0; 1395 macPix->toplevel = NULL; 1396 macPix->flags = TK_IS_PIXMAP | (depth == 1 ? TK_IS_BW_PIXMAP : 0); 1397 macPix->grafPtr = NULL; 1398 macPix->context = NULL; 1399 macPix->size = CGSizeMake(width, height); 1400 { 1401 Rect bounds = {0, 0, height, width}; 1402 1403 ChkErr(NewGWorld, &macPix->grafPtr, depth == 1 ? 1 : 0, &bounds, NULL, 1404 NULL, 0 1405#ifdef __LITTLE_ENDIAN__ 1406 | kNativeEndianPixMap 1407#endif 1408 ); 1409 } 1410 1411 return (Pixmap) macPix; 1412} 1413 1414/* 1415 *---------------------------------------------------------------------- 1416 * 1417 * Tk_FreePixmap -- 1418 * 1419 * Release the resources associated with a pixmap. 1420 * 1421 * Results: 1422 * None. 1423 * 1424 * Side effects: 1425 * Deletes the Macintosh GWorld created by Tk_GetPixmap. 1426 * 1427 *---------------------------------------------------------------------- 1428 */ 1429 1430void 1431Tk_FreePixmap( 1432 Display *display, /* Display. */ 1433 Pixmap pixmap) /* Pixmap to destroy */ 1434{ 1435 MacDrawable *macPix = (MacDrawable *) pixmap; 1436 1437 display->request++; 1438 if (macPix->grafPtr) { 1439 DisposeGWorld(macPix->grafPtr); 1440 } 1441 if (macPix->context) { 1442 TkMacOSXDbgMsg("Cannot free CG backed Pixmap"); 1443 } 1444 ckfree((char *) macPix); 1445} 1446