summaryrefslogtreecommitdiffstats
path: root/carbon/tkMacOSXSubwindows.c
diff options
context:
space:
mode:
Diffstat (limited to 'carbon/tkMacOSXSubwindows.c')
-rw-r--r--carbon/tkMacOSXSubwindows.c1476
1 files changed, 1476 insertions, 0 deletions
diff --git a/carbon/tkMacOSXSubwindows.c b/carbon/tkMacOSXSubwindows.c
new file mode 100644
index 0000000..5fe18a9
--- /dev/null
+++ b/carbon/tkMacOSXSubwindows.c
@@ -0,0 +1,1476 @@
+/*
+ * tkMacOSXSubwindows.c --
+ *
+ * Implements subwindows for the macintosh version of Tk.
+ *
+ * Copyright (c) 1995-1997 Sun Microsystems, Inc.
+ * Copyright 2001, Apple Computer, Inc.
+ * Copyright (c) 2006-2008 Daniel A. Steffen <das@users.sourceforge.net>
+ *
+ * See the file "license.terms" for information on usage and redistribution of
+ * this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ *
+ * RCS: @(#) $Id: tkMacOSXSubwindows.c,v 1.1 2009/06/26 01:42:47 das Exp $
+ */
+
+#include "tkMacOSXPrivate.h"
+#include "tkMacOSXDebug.h"
+#include "tkMacOSXWm.h"
+
+/*
+#ifdef TK_MAC_DEBUG
+#define TK_MAC_DEBUG_CLIP_REGIONS
+#endif
+*/
+
+/*
+ * Prototypes for functions used only in this file.
+ */
+
+static void MoveResizeWindow(MacDrawable *macWin);
+static void GenerateConfigureNotify(TkWindow *winPtr,
+ int includeWin);
+static void UpdateOffsets(TkWindow *winPtr, int deltaX,
+ int deltaY);
+static void NotifyVisibility(TkWindow *winPtr, XEvent *eventPtr);
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * AllocGWorld --
+ * Simplifies the allocation of new drawable ports.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static inline void
+AllocGWorld(
+ int width,
+ int height,
+ int mono,
+ CGrafPtr *grafPtrPtr)
+{
+ Rect bounds = {0, 0, height, width};
+
+#ifdef __LITTLE_ENDIAN__
+ ChkErr(NewGWorld, grafPtrPtr, mono ? 1 : 0, &bounds, NULL, NULL,
+ kNativeEndianPixMap);
+#else
+ ChkErr(NewGWorld, grafPtrPtr, mono ? 1 : 0, &bounds, NULL, NULL, 0);
+#endif
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * XDestroyWindow --
+ *
+ * Dealocates the given X Window.
+ *
+ * Results:
+ * The window id is returned.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+XDestroyWindow(
+ Display *display, /* Display. */
+ Window window) /* Window. */
+{
+ MacDrawable *macWin = (MacDrawable *) window;
+ WindowRef winRef;
+
+ /*
+ * Remove any dangling pointers that may exist if the window we are
+ * deleting is being tracked by the grab code.
+ */
+
+ TkPointerDeadWindow(macWin->winPtr);
+ macWin->toplevel->referenceCount--;
+
+ if (!Tk_IsTopLevel(macWin->winPtr)) {
+ TkMacOSXInvalidateWindow(macWin, TK_PARENT_WINDOW);
+ if (macWin->winPtr->parentPtr != NULL) {
+ TkMacOSXInvalClipRgns((Tk_Window) macWin->winPtr->parentPtr);
+ }
+ if (macWin->visRgn) {
+ CFRelease(macWin->visRgn);
+ }
+ if (macWin->aboveVisRgn) {
+ CFRelease(macWin->aboveVisRgn);
+ }
+
+ if (macWin->toplevel->referenceCount == 0) {
+ ckfree((char *) macWin->toplevel);
+ }
+ ckfree((char *) macWin);
+ return;
+ }
+
+ /*
+ * We are relying on the Activate Mac OS event to pass the focus away from
+ * a window that is getting Destroyed to the Front non-floating window. BUT
+ * we don't get activate events when a floating window is destroyed, since
+ * the front non-floating window doesn't in fact get activated... So maybe
+ * we can check here and if we are destroying a floating window, we can
+ * pass the focus back to the front non-floating window...
+ */
+
+ if (macWin->grafPtr != NULL) {
+ TkWindow *focusPtr = TkGetFocusWin(macWin->winPtr);
+
+ if (focusPtr == NULL
+ || (focusPtr->mainPtr->winPtr == macWin->winPtr)) {
+ winRef = TkMacOSXDrawableWindow(window);
+ if (TkpIsWindowFloating (winRef)) {
+ Window window = TkMacOSXGetXWindow(ActiveNonFloatingWindow());
+
+ if (window != None) {
+ TkMacOSXGenerateFocusEvent(window, 1);
+ }
+ }
+ }
+ }
+ if (macWin->visRgn) {
+ CFRelease(macWin->visRgn);
+ }
+ if (macWin->aboveVisRgn) {
+ CFRelease(macWin->aboveVisRgn);
+ }
+
+ /*
+ * Delete the Mac window and remove it from the windowTable. The window
+ * could be NULL if the window was never mapped. However, we don't do this
+ * for embedded windows, they don't go in the window list, and they do not
+ * own their portPtr's.
+ */
+
+ if (!Tk_IsEmbedded(macWin->winPtr)) {
+ WindowRef winRef = TkMacOSXDrawableWindow(window);
+
+ if (winRef) {
+ TkMacOSXWindowList *listPtr, *prevPtr;
+ WindowGroupRef group;
+
+ if (GetWindowProperty(winRef, 'Tk ', 'TsGp', sizeof(group), NULL,
+ &group) == noErr) {
+ TkDisplay *dispPtr = TkGetDisplayList();
+ ItemCount i = CountWindowGroupContents(group,
+ kWindowGroupContentsReturnWindows);
+ WindowRef macWin;
+ WindowGroupRef newGroup;
+ Window window;
+
+ while (i > 0) {
+ ChkErr(GetIndexedWindow, group, i--, 0, &macWin);
+ if (!macWin) {
+ continue;
+ }
+
+ window = TkMacOSXGetXWindow(macWin);
+ newGroup = NULL;
+ if (window != None) {
+ TkWindow *winPtr = (TkWindow *)
+ Tk_IdToWindow(dispPtr->display, window);
+
+ if (winPtr && winPtr->wmInfoPtr) {
+ newGroup = GetWindowGroupOfClass(
+ winPtr->wmInfoPtr->macClass);
+ }
+ }
+ if (!newGroup) {
+ newGroup =
+ GetWindowGroupOfClass(kDocumentWindowClass);
+ }
+ ChkErr(SetWindowGroup, macWin, newGroup);
+ }
+ ChkErr(SetWindowGroupOwner, group, NULL);
+ ChkErr(ReleaseWindowGroup, group);
+ }
+ TkMacOSXUnregisterMacWindow(winRef);
+ DisposeWindow(winRef);
+
+ for (listPtr=tkMacOSXWindowListPtr, prevPtr=NULL;
+ tkMacOSXWindowListPtr != NULL;
+ prevPtr=listPtr, listPtr=listPtr->nextPtr) {
+ if (listPtr->winPtr == macWin->winPtr) {
+ if (prevPtr == NULL) {
+ tkMacOSXWindowListPtr = listPtr->nextPtr;
+ } else {
+ prevPtr->nextPtr = listPtr->nextPtr;
+ }
+ ckfree((char *) listPtr);
+ break;
+ }
+ }
+ }
+ }
+
+ macWin->grafPtr = NULL;
+
+ /*
+ * Delay deletion of a toplevel data structure untill all children have
+ * been deleted.
+ */
+
+ if (macWin->toplevel->referenceCount == 0) {
+ ckfree((char *) macWin->toplevel);
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * XMapWindow --
+ *
+ * Map the given X Window to the screen. See X window documentation for
+ * more details.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The subwindow or toplevel may appear on the screen.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+XMapWindow(
+ Display *display, /* Display. */
+ Window window) /* Window. */
+{
+ MacDrawable *macWin = (MacDrawable *) window;
+ XEvent event;
+
+ /*
+ * Under certain situations it's possible for this function to be called
+ * before the toplevel window it's associated with has actually been
+ * mapped. In that case we need to create the real Macintosh window now as
+ * this function as well as other X functions assume that the portPtr is
+ * valid.
+ */
+
+ if (!TkMacOSXHostToplevelExists(macWin->toplevel->winPtr)) {
+ TkMacOSXMakeRealWindowExist(macWin->toplevel->winPtr);
+ }
+
+ display->request++;
+ macWin->winPtr->flags |= TK_MAPPED;
+ if (Tk_IsTopLevel(macWin->winPtr)) {
+ if (!Tk_IsEmbedded(macWin->winPtr)) {
+ /*
+ * XXX This should be ShowSheetWindow for kSheetWindowClass
+ * XXX windows that have a wmPtr->master parent set.
+ */
+
+ WindowRef wRef = TkMacOSXDrawableWindow(window);
+
+ if ((macWin->winPtr->wmInfoPtr->macClass == kSheetWindowClass)
+ && (macWin->winPtr->wmInfoPtr->master != None)) {
+ ShowSheetWindow(wRef, TkMacOSXDrawableWindow(
+ macWin->winPtr->wmInfoPtr->master));
+ } else {
+ ShowWindow(wRef);
+ }
+ }
+ TkMacOSXInvalClipRgns((Tk_Window) macWin->winPtr);
+
+ /*
+ * We only need to send the MapNotify event for toplevel windows.
+ */
+
+ event.xany.serial = display->request;
+ event.xany.send_event = False;
+ event.xany.display = display;
+
+ event.xmap.window = window;
+ event.xmap.type = MapNotify;
+ event.xmap.event = window;
+ event.xmap.override_redirect = macWin->winPtr->atts.override_redirect;
+ Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
+ } else {
+ /*
+ * Generate damage for that area of the window.
+ */
+
+ TkMacOSXInvalClipRgns((Tk_Window) macWin->winPtr->parentPtr);
+ TkMacOSXInvalidateWindow(macWin, TK_PARENT_WINDOW);
+ }
+
+ /*
+ * Generate VisibilityNotify events for window and all mapped children.
+ */
+
+ event.xany.send_event = False;
+ event.xany.display = display;
+ event.xvisibility.type = VisibilityNotify;
+ event.xvisibility.state = VisibilityUnobscured;
+ NotifyVisibility(macWin->winPtr, &event);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * NotifyVisibility --
+ *
+ * Recursively called helper proc for XMapWindow().
+
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * VisibilityNotify events are queued.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+NotifyVisibility(
+ TkWindow *winPtr,
+ XEvent *eventPtr)
+{
+ if (winPtr->atts.event_mask & VisibilityChangeMask) {
+ eventPtr->xany.serial = LastKnownRequestProcessed(winPtr->display);
+ eventPtr->xvisibility.window = winPtr->window;
+ Tk_QueueWindowEvent(eventPtr, TCL_QUEUE_TAIL);
+ }
+ for (winPtr = winPtr->childList; winPtr != NULL;
+ winPtr = winPtr->nextPtr) {
+ if (winPtr->flags & TK_MAPPED) {
+ NotifyVisibility(winPtr, eventPtr);
+ }
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * XUnmapWindow --
+ *
+ * Unmap the given X Window to the screen. See X window documentation for
+ * more details.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The subwindow or toplevel may be removed from the screen.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+XUnmapWindow(
+ Display *display, /* Display. */
+ Window window) /* Window. */
+{
+ MacDrawable *macWin = (MacDrawable *) window;
+ XEvent event;
+
+ display->request++;
+ macWin->winPtr->flags &= ~TK_MAPPED;
+ if (Tk_IsTopLevel(macWin->winPtr)) {
+ if (!Tk_IsEmbedded(macWin->winPtr) &&
+ macWin->winPtr->wmInfoPtr->hints.initial_state!=IconicState) {
+ /*
+ * XXX This should be HideSheetWindow for kSheetWindowClass
+ * XXX windows that have a wmPtr->master parent set.
+ */
+
+ WindowRef wref = TkMacOSXDrawableWindow(window);
+
+ if ((macWin->winPtr->wmInfoPtr->macClass == kSheetWindowClass)
+ && (macWin->winPtr->wmInfoPtr->master != None)) {
+ HideSheetWindow(wref);
+ } else {
+ HideWindow(wref);
+ }
+ }
+ TkMacOSXInvalClipRgns((Tk_Window) macWin->winPtr);
+
+ /*
+ * We only need to send the UnmapNotify event for toplevel windows.
+ */
+
+ event.xany.serial = display->request;
+ event.xany.send_event = False;
+ event.xany.display = display;
+
+ event.xunmap.type = UnmapNotify;
+ event.xunmap.window = window;
+ event.xunmap.event = window;
+ event.xunmap.from_configure = false;
+ Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
+ } else {
+ /*
+ * Generate damage for that area of the window.
+ */
+
+ TkMacOSXInvalidateWindow(macWin, TK_PARENT_WINDOW);
+ TkMacOSXInvalClipRgns((Tk_Window) macWin->winPtr->parentPtr);
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * XResizeWindow --
+ *
+ * Resize a given X window. See X windows documentation for further
+ * details.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+XResizeWindow(
+ Display *display, /* Display. */
+ Window window, /* Window. */
+ unsigned int width,
+ unsigned int height)
+{
+ MacDrawable *macWin = (MacDrawable *) window;
+
+ display->request++;
+ if (Tk_IsTopLevel(macWin->winPtr) && !Tk_IsEmbedded(macWin->winPtr)) {
+ WindowRef w = TkMacOSXDrawableWindow(window);
+
+ if (w) {
+ Rect bounds;
+
+ ChkErr(GetWindowBounds, w, kWindowContentRgn, &bounds);
+ bounds.right = bounds.left + width;
+ bounds.bottom = bounds.top + height;
+ ChkErr(SetWindowBounds, w, kWindowContentRgn, &bounds);
+ }
+ } else {
+ MoveResizeWindow(macWin);
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * XMoveResizeWindow --
+ *
+ * Move or resize a given X window. See X windows documentation
+ * for further details.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+XMoveResizeWindow(
+ Display *display, /* Display. */
+ Window window, /* Window. */
+ int x, int y,
+ unsigned int width,
+ unsigned int height)
+{
+ MacDrawable *macWin = (MacDrawable *) window;
+
+ display->request++;
+ if (Tk_IsTopLevel(macWin->winPtr) && !Tk_IsEmbedded(macWin->winPtr)) {
+ WindowRef w = TkMacOSXDrawableWindow(window);
+
+ if (w) {
+ Rect bounds;
+
+ bounds.left = x + macWin->winPtr->wmInfoPtr->xInParent;
+ bounds.right = bounds.left + width;
+ bounds.top = y + macWin->winPtr->wmInfoPtr->yInParent;
+ bounds.bottom = bounds.top + height;
+ ChkErr(SetWindowBounds, w, kWindowContentRgn, &bounds);
+ }
+ } else {
+ MoveResizeWindow(macWin);
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * XMoveWindow --
+ *
+ * Move a given X window. See X windows documentation for further
+ * details.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+XMoveWindow(
+ Display *display, /* Display. */
+ Window window, /* Window. */
+ int x, int y)
+{
+ MacDrawable *macWin = (MacDrawable *) window;
+
+ display->request++;
+ if (Tk_IsTopLevel(macWin->winPtr) && !Tk_IsEmbedded(macWin->winPtr)) {
+ WindowRef w = TkMacOSXDrawableWindow(window);
+
+ if (w) {
+ ChkErr(MoveWindowStructure, w, x, y);
+ }
+ } else {
+ MoveResizeWindow(macWin);
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * MoveResizeWindow --
+ *
+ * Helper proc for XResizeWindow, XMoveResizeWindow and XMoveWindow.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+MoveResizeWindow(
+ MacDrawable *macWin)
+{
+ int deltaX = 0, deltaY = 0, parentBorderwidth = 0;
+ MacDrawable *macParent = NULL;
+ CGrafPtr destPort = TkMacOSXGetDrawablePort((Drawable) macWin);
+
+ /*
+ * Find the Parent window, for an embedded window it will be its container.
+ */
+
+ if (Tk_IsEmbedded(macWin->winPtr)) {
+ TkWindow *contWinPtr = TkpGetOtherWindow(macWin->winPtr);
+
+ if (contWinPtr) {
+ macParent = contWinPtr->privatePtr;
+ } else {
+ /*
+ * Here we should handle out of process embedding. At this point,
+ * we are assuming that the changes.x,y is not maintained, if you
+ * need the info get it from Tk_GetRootCoords, and that the
+ * toplevel sits at 0,0 when it is drawn.
+ */
+ }
+ } else {
+ /*
+ * TODO: update all xOff & yOffs
+ */
+
+ macParent = macWin->winPtr->parentPtr->privatePtr;
+ parentBorderwidth = macWin->winPtr->parentPtr->changes.border_width;
+ }
+
+ if (macParent) {
+ deltaX = macParent->xOff + parentBorderwidth +
+ macWin->winPtr->changes.x - macWin->xOff;
+ deltaY = macParent->yOff + parentBorderwidth +
+ macWin->winPtr->changes.y - macWin->yOff;
+ }
+ if (destPort) {
+ TkMacOSXInvalidateWindow(macWin, TK_PARENT_WINDOW);
+ if (macParent) {
+ TkMacOSXInvalClipRgns((Tk_Window) macParent->winPtr);
+ }
+ }
+ UpdateOffsets(macWin->winPtr, deltaX, deltaY);
+ if (destPort) {
+ TkMacOSXInvalidateWindow(macWin, TK_PARENT_WINDOW);
+ }
+ GenerateConfigureNotify(macWin->winPtr, 0);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * GenerateConfigureNotify --
+ *
+ * Generates ConfigureNotify events for all the child widgets of the
+ * widget passed in the winPtr parameter. If includeWin is true, also
+ * generates ConfigureNotify event for the widget itself.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * ConfigureNotify events will be posted.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+GenerateConfigureNotify(
+ TkWindow *winPtr,
+ int includeWin)
+{
+ TkWindow *childPtr;
+
+ for (childPtr = winPtr->childList; childPtr != NULL;
+ childPtr = childPtr->nextPtr) {
+ if (!Tk_IsMapped(childPtr) || Tk_IsTopLevel(childPtr)) {
+ continue;
+ }
+ GenerateConfigureNotify(childPtr, 1);
+ }
+ if (includeWin) {
+ TkDoConfigureNotify(winPtr);
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * XRaiseWindow --
+ *
+ * Change the stacking order of a window.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Changes the stacking order of the specified window.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+XRaiseWindow(
+ Display *display, /* Display. */
+ Window window) /* Window. */
+{
+ MacDrawable *macWin = (MacDrawable *) window;
+
+ display->request++;
+ if (Tk_IsTopLevel(macWin->winPtr) && !Tk_IsEmbedded(macWin->winPtr)) {
+ TkWmRestackToplevel(macWin->winPtr, Above, NULL);
+ } else {
+ /*
+ * TODO: this should generate damage
+ */
+ }
+}
+
+#if 0
+/*
+ *----------------------------------------------------------------------
+ *
+ * XLowerWindow --
+ *
+ * Change the stacking order of a window.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Changes the stacking order of the specified window.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+XLowerWindow(
+ Display *display, /* Display. */
+ Window window) /* Window. */
+{
+ MacDrawable *macWin = (MacDrawable *) window;
+
+ display->request++;
+ if (Tk_IsTopLevel(macWin->winPtr) && !Tk_IsEmbedded(macWin->winPtr)) {
+ TkWmRestackToplevel(macWin->winPtr, Below, NULL);
+ } else {
+ /*
+ * TODO: this should generate damage
+ */
+ }
+}
+#endif
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * XConfigureWindow --
+ *
+ * Change the size, position, stacking, or border of the specified window.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Changes the attributes of the specified window. Note that we ignore the
+ * passed in values and use the values stored in the TkWindow data
+ * structure.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+XConfigureWindow(
+ Display *display, /* Display. */
+ Window w, /* Window. */
+ unsigned int value_mask,
+ XWindowChanges *values)
+{
+ MacDrawable *macWin = (MacDrawable *) w;
+ TkWindow *winPtr = macWin->winPtr;
+
+ display->request++;
+
+ /*
+ * Change the shape and/or position of the window.
+ */
+
+ if (value_mask & (CWX|CWY|CWWidth|CWHeight)) {
+ XMoveResizeWindow(display, w, winPtr->changes.x, winPtr->changes.y,
+ winPtr->changes.width, winPtr->changes.height);
+ }
+
+ /*
+ * Change the stacking order of the window. Tk actually keeps all the
+ * information we need for stacking order. All we need to do is make sure
+ * the clipping regions get updated and generate damage that will ensure
+ * things get drawn correctly.
+ */
+
+ if (value_mask & CWStackMode) {
+ Rect bounds;
+ WindowRef wRef = TkMacOSXDrawableWindow(w);
+
+ if (wRef) {
+ TkMacOSXInvalClipRgns((Tk_Window) winPtr->parentPtr);
+ TkMacOSXWinBounds(winPtr, &bounds);
+ InvalWindowRect(wRef, &bounds);
+ }
+ }
+
+ /* TkGenWMMoveRequestEvent(macWin->winPtr,
+ macWin->winPtr->changes.x, macWin->winPtr->changes.y); */
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkMacOSXUpdateClipRgn --
+ *
+ * This function updates the cliping regions for a given window and all of
+ * its children. Once updated the TK_CLIP_INVALID flag in the subwindow
+ * data structure is unset. The TK_CLIP_INVALID flag should always be
+ * unset before any drawing is attempted.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The clip regions for the window and its children are updated.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TkMacOSXUpdateClipRgn(
+ TkWindow *winPtr)
+{
+ MacDrawable *macWin;
+
+ if (winPtr == NULL) {
+ return;
+ }
+ macWin = winPtr->privatePtr;
+ if (macWin && macWin->flags & TK_CLIP_INVALID) {
+ TkWindow *win2Ptr;
+
+ if (Tk_IsMapped(winPtr)) {
+ int rgnChanged = 0;
+ CGRect bounds;
+ HIMutableShapeRef rgn;
+
+ /*
+ * Start with a region defined by the window bounds.
+ */
+
+ TkMacOSXWinCGBounds(winPtr, &bounds);
+ rgn = TkMacOSXHIShapeCreateMutableWithRect(&bounds);
+
+ /*
+ * Clip away the area of any windows that may obscure this window.
+ * For a non-toplevel window, first, clip to the parents visible
+ * clip region. Second, clip away any siblings that are higher in
+ * the stacking order. For an embedded toplevel, just clip to the
+ * container's visible clip region. Remember, we only allow one
+ * contained window in a frame, and don't support any other widgets
+ * in the frame either. This is not currently enforced, however.
+ */
+
+ if (!Tk_IsTopLevel(winPtr)) {
+ TkMacOSXUpdateClipRgn(winPtr->parentPtr);
+ if (winPtr->parentPtr) {
+ ChkErr(HIShapeIntersect,
+ winPtr->parentPtr->privatePtr->aboveVisRgn,
+ rgn, rgn);
+ }
+ win2Ptr = winPtr;
+ while ((win2Ptr = win2Ptr->nextPtr)) {
+ if (Tk_IsTopLevel(win2Ptr) || !Tk_IsMapped(win2Ptr)) {
+ continue;
+ }
+ TkMacOSXWinCGBounds(win2Ptr, &bounds);
+ ChkErr(TkMacOSHIShapeDifferenceWithRect, rgn, &bounds);
+ }
+ } else if (Tk_IsEmbedded(winPtr)) {
+ win2Ptr = TkpGetOtherWindow(winPtr);
+ if (win2Ptr) {
+ TkMacOSXUpdateClipRgn(win2Ptr);
+ ChkErr(HIShapeIntersect,
+ win2Ptr->privatePtr->aboveVisRgn, rgn, rgn);
+ } else if (tkMacOSXEmbedHandler != NULL) {
+ HIShapeRef visRgn;
+
+ TkMacOSXCheckTmpQdRgnEmpty();
+ tkMacOSXEmbedHandler->getClipProc((Tk_Window) winPtr,
+ tkMacOSXtmpQdRgn);
+ visRgn = HIShapeCreateWithQDRgn(tkMacOSXtmpQdRgn);
+ SetEmptyRgn(tkMacOSXtmpQdRgn);
+ ChkErr(HIShapeIntersect, visRgn, rgn, rgn);
+ }
+
+ /*
+ * TODO: Here we should handle out of process embedding.
+ */
+ } else if (winPtr->wmInfoPtr->attributes &
+ kWindowResizableAttribute) {
+ HIViewRef growBoxView;
+ OSErr err = HIViewFindByID(HIViewGetRoot(
+ TkMacOSXDrawableWindow(winPtr->window)),
+ kHIViewWindowGrowBoxID, &growBoxView);
+
+ if (err == noErr) {
+ ChkErr(HIViewGetFrame, growBoxView, &bounds);
+ bounds = CGRectOffset(bounds,
+ -winPtr->wmInfoPtr->xInParent,
+ -winPtr->wmInfoPtr->yInParent);
+ ChkErr(TkMacOSHIShapeDifferenceWithRect, rgn, &bounds);
+ }
+ }
+ macWin->aboveVisRgn = HIShapeCreateCopy(rgn);
+
+ /*
+ * The final clip region is the aboveVis region (or visible region)
+ * minus all the children of this window. If the window is a
+ * container, we must also subtract the region of the embedded
+ * window.
+ */
+
+ win2Ptr = winPtr->childList;
+ while (win2Ptr) {
+ if (Tk_IsTopLevel(win2Ptr) || !Tk_IsMapped(win2Ptr)) {
+ win2Ptr = win2Ptr->nextPtr;
+ continue;
+ }
+ TkMacOSXWinCGBounds(win2Ptr, &bounds);
+ ChkErr(TkMacOSHIShapeDifferenceWithRect, rgn, &bounds);
+ rgnChanged = 1;
+ win2Ptr = win2Ptr->nextPtr;
+ }
+
+ if (Tk_IsContainer(winPtr)) {
+ win2Ptr = TkpGetOtherWindow(winPtr);
+ if (win2Ptr) {
+ if (Tk_IsMapped(win2Ptr)) {
+ TkMacOSXWinCGBounds(win2Ptr, &bounds);
+ ChkErr(TkMacOSHIShapeDifferenceWithRect, rgn, &bounds);
+ rgnChanged = 1;
+ }
+ }
+
+ /*
+ * TODO: Here we should handle out of process embedding.
+ */
+ }
+
+ if (rgnChanged) {
+ HIShapeRef diffRgn = HIShapeCreateDifference(
+ macWin->aboveVisRgn, rgn);
+
+ if (!HIShapeIsEmpty(diffRgn)) {
+ macWin->visRgn = HIShapeCreateCopy(rgn);
+ }
+ CFRelease(diffRgn);
+ }
+ CFRelease(rgn);
+ } else {
+ /*
+ * An unmapped window has empty clip regions to prevent any
+ * (erroneous) drawing into it or its children from becoming
+ * visible. [Bug 940117]
+ */
+
+ if (!Tk_IsTopLevel(winPtr)) {
+ TkMacOSXUpdateClipRgn(winPtr->parentPtr);
+ } else if (Tk_IsEmbedded(winPtr)) {
+ win2Ptr = TkpGetOtherWindow(winPtr);
+ if (win2Ptr) {
+ TkMacOSXUpdateClipRgn(win2Ptr);
+ }
+ }
+ macWin->aboveVisRgn = TkMacOSXHIShapeCreateEmpty();
+ }
+ if (!macWin->visRgn) {
+ macWin->visRgn = HIShapeCreateCopy(macWin->aboveVisRgn);
+ }
+ macWin->flags &= ~TK_CLIP_INVALID;
+
+#ifdef TK_MAC_DEBUG_CLIP_REGIONS
+ TkMacOSXDebugFlashRegion((Drawable) macWin, macWin->visRgn);
+#endif /* TK_MAC_DEBUG_CLIP_REGIONS */
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkMacOSXVisableClipRgn --
+ *
+ * This function returnd the Macintosh cliping region for the given
+ * window. A NULL Rgn means the window is not visible.
+ *
+ * Results:
+ * The region.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+RgnHandle
+TkMacOSXVisableClipRgn(
+ TkWindow *winPtr)
+{
+ static RgnHandle visQdRgn = NULL;
+
+ if (visQdRgn == NULL) {
+ visQdRgn = NewRgn();
+ }
+ if (winPtr->privatePtr->flags & TK_CLIP_INVALID) {
+ TkMacOSXUpdateClipRgn(winPtr);
+ }
+ ChkErr(HIShapeGetAsQDRgn, winPtr->privatePtr->visRgn, visQdRgn);
+ return visQdRgn;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkMacOSXInvalidateWindow --
+ *
+ * This function makes the window as invalid will generate damage for the
+ * window.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Damage is created.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TkMacOSXInvalidateWindow(
+ MacDrawable *macWin, /* Make window that's causing damage. */
+ int flag) /* Should be TK_WINDOW_ONLY or
+ * TK_PARENT_WINDOW */
+{
+ WindowRef windowRef;
+ HIShapeRef rgn;
+
+ windowRef = TkMacOSXDrawableWindow((Drawable)macWin);
+ if (macWin->flags & TK_CLIP_INVALID) {
+ TkMacOSXUpdateClipRgn(macWin->winPtr);
+ }
+ rgn = (flag == TK_WINDOW_ONLY) ? macWin->visRgn : macWin->aboveVisRgn;
+ if (!HIShapeIsEmpty(rgn)) {
+ TkMacOSXCheckTmpQdRgnEmpty();
+ ChkErr(HIShapeGetAsQDRgn, rgn, tkMacOSXtmpQdRgn);
+ InvalWindowRgn(windowRef, tkMacOSXtmpQdRgn);
+ SetEmptyRgn(tkMacOSXtmpQdRgn);
+ }
+#ifdef TK_MAC_DEBUG_CLIP_REGIONS
+ TkMacOSXDebugFlashRegion((Drawable) macWin, rgn);
+#endif /* TK_MAC_DEBUG_CLIP_REGIONS */
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkMacOSXGetDrawableWindow --
+ *
+ * This function returns the WindowRef for a given X drawable.
+ *
+ * Results:
+ * A WindowRef, or NULL for off screen pixmaps.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+WindowRef
+TkMacOSXDrawableWindow(
+ Drawable drawable)
+{
+ MacDrawable *macWin = (MacDrawable *) drawable;
+ WindowRef result = NULL;
+
+ if (!macWin || macWin->flags & TK_IS_PIXMAP) {
+ result = NULL;
+ } else {
+ result = GetWindowFromPort(TkMacOSXGetDrawablePort(drawable));
+ }
+ return result;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkMacOSXGetDrawablePort --
+ *
+ * This function returns the Graphics Port for a given X drawable.
+ *
+ * Results:
+ * A CGrafPort. Either an off screen pixmap or a Window.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+CGrafPtr
+TkMacOSXGetDrawablePort(
+ Drawable drawable)
+{
+ MacDrawable *macWin = (MacDrawable *) drawable;
+ CGrafPtr resultPort = NULL;
+
+ if (!macWin) {
+ return NULL;
+ }
+
+ /*
+ * Handle toplevel windows.
+ */
+
+ if (macWin->toplevel) {
+ TkWindow *contWinPtr;
+
+ if (!(macWin->toplevel->flags & TK_EMBEDDED)) {
+ return macWin->toplevel->grafPtr;
+ }
+
+ /*
+ * If the Drawable is in an embedded window, use the Port of its
+ * container.
+ *
+ * TRICKY POINT: we can have cases when a toplevel is being destroyed
+ * where the winPtr for the toplevel has been freed, but the children
+ * are not all the way destroyed. The children will call this function
+ * as they are being destroyed, but Tk_IsEmbedded will return garbage.
+ * So we check the copy of the TK_EMBEDDED flag we put into the
+ * toplevel's macWin flags.
+ */
+
+ contWinPtr = TkpGetOtherWindow(macWin->toplevel->winPtr);
+
+ resultPort = NULL;
+ if (contWinPtr != NULL) {
+ resultPort = TkMacOSXGetDrawablePort((Drawable)
+ contWinPtr->privatePtr);
+ } else if (tkMacOSXEmbedHandler != NULL) {
+ resultPort = tkMacOSXEmbedHandler->getPortProc((Tk_Window)
+ macWin->winPtr);
+ }
+
+ if (!resultPort) {
+ /*
+ * FIXME: So far as I can tell, the only time that this happens is
+ * when we are tearing down an embedded child interpreter, and most
+ * of the time, this is harmless... However, we really need to find
+ * why the embedding loses.
+ */
+
+ TkMacOSXDbgMsg("Couldn't find container");
+ }
+
+ /*
+ * TODO: Here we should handle out of process embedding.
+ */
+
+ return resultPort;
+ }
+
+ if ((macWin->flags & TK_IS_PIXMAP) && !macWin->grafPtr) {
+ AllocGWorld(macWin->size.width, macWin->size.height,
+ macWin->flags & TK_IS_BW_PIXMAP, &macWin->grafPtr);
+ }
+ return macWin->grafPtr;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkMacOSXGetRootControl --
+ *
+ * This function returns the Root Control for a given X drawable.
+ *
+ * Results:
+ * A ControlRef .
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ControlRef
+TkMacOSXGetRootControl(
+ Drawable drawable)
+{
+ /*
+ * will probably need to fix this up for embedding
+ */
+
+ MacDrawable *macWin = (MacDrawable *) drawable;
+ TkWindow *contWinPtr;
+
+ if (macWin == NULL) {
+ return NULL;
+ }
+
+ if (!(macWin->toplevel->flags & TK_EMBEDDED)) {
+ return macWin->toplevel->rootControl;
+ }
+
+ contWinPtr = TkpGetOtherWindow(macWin->toplevel->winPtr);
+ if (contWinPtr == NULL) {
+ return NULL;
+ }
+
+ return TkMacOSXGetRootControl((Drawable) contWinPtr->privatePtr);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkMacOSXInvalClipRgns --
+ *
+ * This function invalidates the clipping regions for a given window and
+ * all of its children. This function should be called whenever changes
+ * are made to subwindows that would affect the size or position of
+ * windows.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The cliping regions for the window and its children are mark invalid.
+ * (Make sure they are valid before drawing.)
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TkMacOSXInvalClipRgns(
+ Tk_Window tkwin)
+{
+ TkWindow *winPtr = (TkWindow *) tkwin;
+ TkWindow *childPtr;
+ MacDrawable *macWin = winPtr->privatePtr;
+
+ /*
+ * If already marked we can stop because all descendants will also already
+ * be marked.
+ */
+
+ if (!macWin || macWin->flags & TK_CLIP_INVALID) {
+ return;
+ }
+
+ macWin->flags |= TK_CLIP_INVALID;
+ if (macWin->visRgn) {
+ CFRelease(macWin->visRgn);
+ macWin->visRgn = NULL;
+ }
+ if (macWin->aboveVisRgn) {
+ CFRelease(macWin->aboveVisRgn);
+ macWin->aboveVisRgn = NULL;
+ }
+
+ /*
+ * Invalidate clip regions for all children & their descendants, unless the
+ * child is a toplevel.
+ */
+
+ childPtr = winPtr->childList;
+ while (childPtr) {
+ if (!Tk_IsTopLevel(childPtr)) {
+ TkMacOSXInvalClipRgns((Tk_Window) childPtr);
+ }
+ childPtr = childPtr->nextPtr;
+ }
+
+ /*
+ * Also, if the window is a container, mark its embedded window.
+ */
+
+ if (Tk_IsContainer(winPtr)) {
+ childPtr = TkpGetOtherWindow(winPtr);
+
+ if (childPtr) {
+ TkMacOSXInvalClipRgns((Tk_Window) childPtr);
+ }
+
+ /*
+ * TODO: Here we should handle out of process embedding.
+ */
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkMacOSXWinBounds --
+ *
+ * Given a Tk window this function determines the windows bounds in
+ * relation to the Macintosh window's coordinate system. This is also the
+ * same coordinate system as the Tk toplevel window in which this window
+ * is contained.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TkMacOSXWinBounds(
+ TkWindow *winPtr,
+ Rect *bounds)
+{
+ bounds->left = winPtr->privatePtr->xOff;
+ bounds->top = winPtr->privatePtr->yOff;
+ bounds->right = bounds->left + winPtr->changes.width;
+ bounds->bottom = bounds->top + winPtr->changes.height;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkMacOSXWinCGBounds --
+ *
+ * Given a Tk window this function determines the windows bounds in
+ * relation to the Macintosh window's coordinate system. This is also the
+ * same coordinate system as the Tk toplevel window in which this window
+ * is contained.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TkMacOSXWinCGBounds(
+ TkWindow *winPtr,
+ CGRect *bounds)
+{
+ bounds->origin.x = winPtr->privatePtr->xOff;
+ bounds->origin.y = winPtr->privatePtr->yOff;
+ bounds->size.width = winPtr->changes.width;
+ bounds->size.height = winPtr->changes.height;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * UpdateOffsets --
+ *
+ * Updates the X & Y offsets of the given TkWindow from the TopLevel it is
+ * a decendant of.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The xOff & yOff fields for the Mac window datastructure is updated to
+ * the proper offset.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+UpdateOffsets(
+ TkWindow *winPtr,
+ int deltaX,
+ int deltaY)
+{
+ TkWindow *childPtr;
+
+ if (winPtr->privatePtr == NULL) {
+ /*
+ * We haven't called Tk_MakeWindowExist for this window yet. The offset
+ * information will be postponed and calulated at that time. (This will
+ * usually only happen when a mapped parent is being moved but has
+ * child windows that have yet to be mapped.)
+ */
+
+ return;
+ }
+
+ winPtr->privatePtr->xOff += deltaX;
+ winPtr->privatePtr->yOff += deltaY;
+
+ childPtr = winPtr->childList;
+ while (childPtr != NULL) {
+ if (!Tk_IsTopLevel(childPtr)) {
+ UpdateOffsets(childPtr, deltaX, deltaY);
+ }
+ childPtr = childPtr->nextPtr;
+ }
+
+ if (Tk_IsContainer(winPtr)) {
+ childPtr = TkpGetOtherWindow(winPtr);
+ if (childPtr != NULL) {
+ UpdateOffsets(childPtr,deltaX,deltaY);
+ }
+
+ /*
+ * TODO: Here we should handle out of process embedding.
+ */
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tk_GetPixmap --
+ *
+ * Creates an in memory drawing surface.
+ *
+ * Results:
+ * Returns a handle to a new pixmap.
+ *
+ * Side effects:
+ * Allocates a new Macintosh GWorld.
+ *
+ *----------------------------------------------------------------------
+ */
+
+Pixmap
+Tk_GetPixmap(
+ Display *display, /* Display for new pixmap (can be null). */
+ Drawable d, /* Drawable where pixmap will be used (ignored). */
+ int width, /* Dimensions of pixmap. */
+ int height,
+ int depth) /* Bits per pixel for pixmap. */
+{
+ MacDrawable *macPix;
+
+ if (display != NULL) {
+ display->request++;
+ }
+ macPix = (MacDrawable *) ckalloc(sizeof(MacDrawable));
+ macPix->winPtr = NULL;
+ macPix->xOff = 0;
+ macPix->yOff = 0;
+ macPix->visRgn = NULL;
+ macPix->aboveVisRgn = NULL;
+ macPix->drawRect = CGRectNull;
+ macPix->referenceCount = 0;
+ macPix->toplevel = NULL;
+ macPix->flags = TK_IS_PIXMAP | (depth == 1 ? TK_IS_BW_PIXMAP : 0);
+ macPix->grafPtr = NULL;
+ macPix->context = NULL;
+ macPix->size = CGSizeMake(width, height);
+ AllocGWorld(width, height, depth==1, &macPix->grafPtr);
+
+ return (Pixmap) macPix;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tk_FreePixmap --
+ *
+ * Release the resources associated with a pixmap.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Deletes the Macintosh GWorld created by Tk_GetPixmap.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Tk_FreePixmap(
+ Display *display, /* Display. */
+ Pixmap pixmap) /* Pixmap to destroy */
+{
+ MacDrawable *macPix = (MacDrawable *) pixmap;
+
+ display->request++;
+ if (macPix->grafPtr) {
+ DisposeGWorld(macPix->grafPtr);
+ }
+ if (macPix->context) {
+ TkMacOSXDbgMsg("Cannot free CG backed Pixmap");
+ }
+ ckfree((char *) macPix);
+}
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 4
+ * fill-column: 79
+ * coding: utf-8
+ * End:
+ */