/*
* tkMacOSXSubwindows.c --
*
* Implements subwindows for the macintosh version of Tk.
*
* Copyright (c) 1995-1997 Sun Microsystems, Inc.
* Copyright 2001-2009, Apple Inc.
* Copyright (c) 2006-2009 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.
*/
#include "tkMacOSXPrivate.h"
#include "tkMacOSXDebug.h"
#include "tkMacOSXWm.h"
#include "tkMacOSXConstants.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);
/*
*----------------------------------------------------------------------
*
* XDestroyWindow --
*
* Deallocates the given X Window.
*
* Results:
* The window id is returned.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
XDestroyWindow(
TCL_UNUSED(Display *), /* Display. */
Window window) /* Window. */
{
MacDrawable *macWin = (MacDrawable *)window;
/*
* Remove any dangling pointers that may exist if the window we are
* deleting is being tracked by the grab code.
*/
TkPointerDeadWindow(macWin->winPtr);
TkMacOSXSelDeadWindow(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);
macWin->visRgn = NULL;
}
if (macWin->aboveVisRgn) {
CFRelease(macWin->aboveVisRgn);
macWin->aboveVisRgn = NULL;
}
if (macWin->drawRgn) {
CFRelease(macWin->drawRgn);
macWin->drawRgn = NULL;
}
if (macWin->toplevel->referenceCount == 0) {
ckfree(macWin->toplevel);
}
ckfree(macWin);
return Success;
}
if (macWin->visRgn) {
CFRelease(macWin->visRgn);
macWin->visRgn = NULL;
}
if (macWin->aboveVisRgn) {
CFRelease(macWin->aboveVisRgn);
macWin->aboveVisRgn = NULL;
}
if (macWin->drawRgn) {
CFRelease(macWin->drawRgn);
macWin->drawRgn = NULL;
}
macWin->view = nil;
/*
* Delay deletion of a toplevel data structure untill all children have
* been deleted.
*/
if (macWin->toplevel->referenceCount == 0) {
ckfree(macWin->toplevel);
}
return Success;
}
/*
*----------------------------------------------------------------------
*
* XMapWindow --
*
* This X11 stub maps the given X11 Window but does not update any of
* the Tk structures describing the window. Tk applications should
* never call this directly, but it is called by Tk_MapWindow and
* Tk_WmMapWindow.
*
* Results:
* Returns Success or BadWindow.
*
* Side effects:
* The subwindow or toplevel may appear on the screen. VisibilityNotify
* events are generated.
*
*
*----------------------------------------------------------------------
*/
int
XMapWindow(
Display *display, /* Display. */
Window window) /* Window. */
{
if (!window) {
return BadWindow;
}
MacDrawable *macWin = (MacDrawable *)window;
TkWindow *winPtr = macWin->winPtr;
NSWindow *win = TkMacOSXGetNSWindowForDrawable(window);
static Bool initialized = NO;
/*
* 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++;
if (Tk_IsTopLevel(winPtr)) {
if (!Tk_IsEmbedded(winPtr)) {
TKContentView *view = [win contentView];
/*
* We want to activate Tk when a toplevel is mapped but we must not
* supply YES here. This is because during Tk initialization the
* root window is mapped before applicationDidFinishLaunching
* returns. Forcing the app to activate too early can make the menu
* bar unresponsive.
*/
TkMacOSXApplyWindowAttributes(winPtr, win);
[win setExcludedFromWindowsMenu:NO];
[NSApp activateIgnoringOtherApps:initialized];
[view addTkDirtyRect: [view bounds]];
if (initialized) {
if ([win canBecomeKeyWindow]) {
[win makeKeyAndOrderFront:NSApp];
} else {
[win orderFrontRegardless];
}
}
} else {
TkWindow *contWinPtr = TkpGetOtherWindow(winPtr);
/*
* Rebuild the container's clipping region and display
* the window.
*/
TkMacOSXInvalClipRgns((Tk_Window)contWinPtr);
TkMacOSXInvalidateWindow(macWin, TK_PARENT_WINDOW);
}
TkMacOSXInvalClipRgns((Tk_Window)winPtr);
} else {
/*
* For non-toplevel windows, rebuild the parent's clipping region
* and redisplay the window.
*/
TkMacOSXInvalClipRgns((Tk_Window)winPtr->parentPtr);
}
/*
* Mark the toplevel as needing to be redrawn, unless the window is being
* mapped while drawing is taking place.
*/
TKContentView *view = [win contentView];
if (view != [NSView focusView]) {
[view addTkDirtyRect:[view bounds]];
}
/*
* Generate VisibilityNotify events for window and all mapped children.
*/
if (initialized) {
XEvent event;
event.xany.send_event = False;
event.xany.display = display;
event.xvisibility.type = VisibilityNotify;
event.xvisibility.state = VisibilityUnobscured;
NotifyVisibility(winPtr, &event);
} else {
initialized = YES;
}
return Success;
}
/*
*----------------------------------------------------------------------
*
* 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 --
*
* This X11 stub maps the given X11 Window but does not update any of
* The Tk structures describing the window. Tk applications should
* never call this directly, but it is called by Tk_UnmapWindow and
* Tk_WmUnmapWindow.
*
* Results:
* Always returns Success or BadWindow.
*
* Side effects:
* The subwindow or toplevel may be removed from the screen.
*
*----------------------------------------------------------------------
*/
int
XUnmapWindow(
Display *display, /* Display. */
Window window) /* Window. */
{
MacDrawable *macWin = (MacDrawable *)window;
TkWindow *winPtr = macWin->winPtr;
TkWindow *parentPtr = winPtr->parentPtr;
NSWindow *win = TkMacOSXGetNSWindowForDrawable(window);
if (!window) {
return BadWindow;
}
display->request++;
if (Tk_IsTopLevel(winPtr)) {
if (!Tk_IsEmbedded(winPtr) &&
winPtr->wmInfoPtr->hints.initial_state!=IconicState) {
[win orderOut:nil];
[win setExcludedFromWindowsMenu:YES];
}
TkMacOSXInvalClipRgns((Tk_Window)winPtr);
} else {
/*
* Rebuild the visRgn clip region for the parent so it will be allowed
* to draw in the space from which this subwindow was removed and then
* redraw the window.
*/
if (parentPtr && parentPtr->privatePtr->visRgn) {
TkMacOSXInvalidateViewRegion(
TkMacOSXGetNSViewForDrawable(parentPtr->privatePtr),
parentPtr->privatePtr->visRgn);
}
TkMacOSXInvalClipRgns((Tk_Window)parentPtr);
TkMacOSXUpdateClipRgn(parentPtr);
}
TKContentView *view = [win contentView];
if (view != [NSView focusView]) {
[view addTkDirtyRect:[view bounds]];
}
return Success;
}
/*
*----------------------------------------------------------------------
*
* XResizeWindow --
*
* Resize a given X window. See X windows documentation for further
* details.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
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)) {
TKWindow *w = (TKWindow *)macWin->winPtr->wmInfoPtr->window;
if (w) {
if ([w styleMask] & NSFullScreenWindowMask) {
[w tkLayoutChanged];
} else {
NSRect r = [w contentRectForFrameRect:[w frame]];
r.origin.y += r.size.height - height;
r.size.width = width;
r.size.height = height;
[w setFrame:[w frameRectForContentRect:r] display:NO];
}
}
} else {
MoveResizeWindow(macWin);
}
return Success;
}
/*
*----------------------------------------------------------------------
*
* XMoveResizeWindow --
*
* Move or resize a given X window. See X windows documentation for
* further details.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
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)) {
NSWindow *w = macWin->winPtr->wmInfoPtr->window;
if (w) {
/*
* We explicitly convert everything to doubles so we don't get
* surprised (again) by what happens when you do arithmetic with
* unsigned ints.
*/
CGFloat X = (CGFloat) x;
CGFloat Y = (CGFloat) y;
CGFloat Width = (CGFloat) width;
CGFloat Height = (CGFloat) height;
CGFloat XOff = (CGFloat) macWin->winPtr->wmInfoPtr->xInParent;
CGFloat YOff = (CGFloat) macWin->winPtr->wmInfoPtr->yInParent;
NSRect r = NSMakeRect(
X + XOff, TkMacOSXZeroScreenHeight() - Y - YOff - Height,
Width, Height);
[w setFrame:[w frameRectForContentRect:r] display:NO];
}
} else {
MoveResizeWindow(macWin);
}
return Success;
}
/*
*----------------------------------------------------------------------
*
* XMoveWindow --
*
* Move a given X window. See X windows documentation for further details.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
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)) {
NSWindow *w = macWin->winPtr->wmInfoPtr->window;
if (w) {
[w setFrameTopLeftPoint: NSMakePoint(
x, TkMacOSXZeroScreenHeight() - y)];
}
} else {
MoveResizeWindow(macWin);
}
return Success;
}
/*
*----------------------------------------------------------------------
*
* 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;
NSWindow *macWindow = TkMacOSXGetNSWindowForDrawable((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 (macWindow) {
TkMacOSXInvalidateWindow(macWin, TK_PARENT_WINDOW);
if (macParent) {
TkMacOSXInvalClipRgns((Tk_Window)macParent->winPtr);
}
}
UpdateOffsets(macWin->winPtr, deltaX, deltaY);
if (macWindow) {
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.
*
*----------------------------------------------------------------------
*/
int
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
*/
}
return Success;
}
/*
*----------------------------------------------------------------------
*
* XLowerWindow --
*
* Change the stacking order of a window.
*
* Results:
* None.
*
* Side effects:
* Changes the stacking order of the specified window.
*
*----------------------------------------------------------------------
*/
int
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
*/
}
return Success;
}
/*
*----------------------------------------------------------------------
*
* 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.
*
*----------------------------------------------------------------------
*/
int
XConfigureWindow(
Display *display, /* Display. */
Window w, /* Window. */
unsigned int value_mask,
TCL_UNUSED(XWindowChanges *))
{
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) {
NSView *view = TkMacOSXGetNSViewForDrawable(macWin);
if (view) {
TkMacOSXInvalClipRgns((Tk_Window)winPtr->parentPtr);
TkpRedrawWidget((Tk_Window)winPtr);
}
}
#if 0
TkGenWMMoveRequestEvent(macWin->winPtr,
macWin->winPtr->changes.x, macWin->winPtr->changes.y);
#endif
return Success;
}
/*
*----------------------------------------------------------------------
*
* TkMacOSXSetDrawingEnabled --
*
* This function sets the TK_DO_NOT_DRAW flag for a given window and
* all of its children.
*
* Results:
* None.
*
* Side effects:
* The clipping regions for the window and its children are cleared.
*
*----------------------------------------------------------------------
*/
void
TkMacOSXSetDrawingEnabled(
TkWindow *winPtr,
int flag)
{
TkWindow *childPtr;
MacDrawable *macWin = winPtr->privatePtr;
if (macWin) {
if (flag) {
macWin->flags &= ~TK_DO_NOT_DRAW;
} else {
macWin->flags |= TK_DO_NOT_DRAW;
}
}
/*
* Set the flag for all children & their descendants, excluding Toplevels.
* (??? Do we need to exclude Toplevels?)
*/
childPtr = winPtr->childList;
while (childPtr) {
if (!Tk_IsTopLevel(childPtr)) {
TkMacOSXSetDrawingEnabled(childPtr, flag);
}
childPtr = childPtr->nextPtr;
}
/*
* If the window is a container, set the flag for its embedded window.
*/
if (Tk_IsContainer(winPtr)) {
childPtr = TkpGetOtherWindow(winPtr);
if (childPtr) {
TkMacOSXSetDrawingEnabled(childPtr, flag);
}
}
}
/*
*----------------------------------------------------------------------
*
* TkMacOSXUpdateClipRgn --
*
* This function updates the clipping 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;
#ifdef TK_MAC_DEBUG_CLIP_REGIONS
TkMacOSXDbgMsg("%s", winPtr->pathName);
#endif
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 parent's 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)) {
if (winPtr->parentPtr) {
TkMacOSXUpdateClipRgn(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) {
TkRegion r = TkCreateRegion();
HIShapeRef visRgn;
tkMacOSXEmbedHandler->getClipProc((Tk_Window)winPtr, r);
visRgn = TkMacOSXGetNativeRegion(r);
ChkErr(HIShapeIntersect, visRgn, rgn, rgn);
CFRelease(visRgn);
TkDestroyRegion(r);
}
/*
* TODO: Here we should handle out of process embedding.
*/
}
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;
}
}
/*
*----------------------------------------------------------------------
*
* TkMacOSXVisableClipRgn --
*
* This function returns the Macintosh clipping region for the given
* window. The caller is responsible for disposing of the returned region
* via TkDestroyRegion().
*
* Results:
* The region.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
TkRegion
TkMacOSXVisableClipRgn(
TkWindow *winPtr)
{
if (winPtr->privatePtr->flags & TK_CLIP_INVALID) {
TkMacOSXUpdateClipRgn(winPtr);
}
return (TkRegion) HIShapeCreateMutableCopy(winPtr->privatePtr->visRgn);
}
/*
*----------------------------------------------------------------------
*
* TkMacOSXInvalidateViewRegion --
*
* This function invalidates the given region of a view.
*
* Results:
* None.
*
* Side effects:
* Damage is created.
*
*----------------------------------------------------------------------
*/
static OSStatus
InvalViewRect(
int msg,
TCL_UNUSED(HIShapeRef),
const CGRect *rect,
void *ref)
{
static CGAffineTransform t;
TKContentView *view = ref;
NSRect dirtyRect;
if (!view) {
return paramErr;
}
switch (msg) {
case kHIShapeEnumerateInit:
t = CGAffineTransformMake(1.0, 0.0, 0.0, -1.0, 0.0,
NSHeight([view bounds]));
break;
case kHIShapeEnumerateRect:
dirtyRect = NSRectFromCGRect(CGRectApplyAffineTransform(*rect, t));
[view addTkDirtyRect:dirtyRect];
break;
}
return noErr;
}
void
TkMacOSXInvalidateViewRegion(
NSView *view,
HIShapeRef rgn)
{
if (view && !HIShapeIsEmpty(rgn)) {
ChkErr(HIShapeEnumerate, rgn,
kHIShapeParseFromBottom|kHIShapeParseFromLeft,
InvalViewRect, view);
}
}
/*
*----------------------------------------------------------------------
*
* TkMacOSXInvalidateWindow --
*
* This function invalidates a window and (optionally) its children.
*
* Results:
* None.
*
* Side effects:
* Damage is created.
*
*----------------------------------------------------------------------
*/
void
TkMacOSXInvalidateWindow(
MacDrawable *macWin, /* Window to be invalidated. */
int flag) /* Should be TK_WINDOW_ONLY or
* TK_PARENT_WINDOW */
{
#ifdef TK_MAC_DEBUG_CLIP_REGIONS
TkMacOSXDbgMsg("%s", macWin->winPtr->pathName);
#endif
if (macWin->flags & TK_CLIP_INVALID) {
TkMacOSXUpdateClipRgn(macWin->winPtr);
}
TkMacOSXInvalidateViewRegion(TkMacOSXGetNSViewForDrawable(macWin),
(flag == TK_WINDOW_ONLY) ? macWin->visRgn : macWin->aboveVisRgn);
}
/*
*----------------------------------------------------------------------
*
* TkMacOSXGetNSWindowForDrawable --
*
* This function returns the NSWindow for a given X drawable.
*
* Results:
* A NSWindow, or nil for off screen pixmaps.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
void *
TkMacOSXDrawable(
Drawable drawable)
{
MacDrawable *macWin = (MacDrawable *)drawable;
NSWindow *result = nil;
if (!macWin || macWin->flags & TK_IS_PIXMAP) {
result = nil;
} else if (macWin->toplevel && macWin->toplevel->winPtr &&
macWin->toplevel->winPtr->wmInfoPtr &&
macWin->toplevel->winPtr->wmInfoPtr->window) {
result = macWin->toplevel->winPtr->wmInfoPtr->window;
} else if (macWin->winPtr && macWin->winPtr->wmInfoPtr &&
macWin->winPtr->wmInfoPtr->window) {
result = macWin->winPtr->wmInfoPtr->window;
} else if (macWin->toplevel && (macWin->toplevel->flags & TK_EMBEDDED)) {
TkWindow *contWinPtr = TkpGetOtherWindow(macWin->toplevel->winPtr);
if (contWinPtr) {
result = TkMacOSXGetNSWindowForDrawable((Drawable)contWinPtr->privatePtr);
}
}
return result;
}
/*
*----------------------------------------------------------------------
*
* TkMacOSXGetDrawablePort --
*
* This function only exists because it is listed in the stubs table.
* It is useless.
*
* Results:
* NULL.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
void *
TkMacOSXGetDrawablePort(
TCL_UNUSED(Drawable))
{
return NULL;
}
/*
*----------------------------------------------------------------------
*
* TkMacOSXGetNSViewForDrawable/TkMacOSXGetRootControl --
*
* The function name TkMacOSXGetRootControl is being preserved only
* because it exists in a stubs table. Nobody knows what it means to
* get a "RootControl". The macro TkMacOSXGetNSViewForDrawable calls
* this function and should always be used rather than directly using
* the obscure official name of this function.
*
* It returns the NSView for a given X drawable in the case that the
* drawable is a window. If the drawable is a pixmap it returns nil.
*
* Results:
* A NSView* or nil.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
void *
TkMacOSXGetRootControl(
Drawable drawable)
{
void *result = NULL;
MacDrawable *macWin = (MacDrawable *)drawable;
if (!macWin) {
result = NULL;
} else if (!macWin->toplevel) {
result = macWin->view;
} else if (!(macWin->toplevel->flags & TK_EMBEDDED)) {
result = macWin->toplevel->view;
} else {
TkWindow *contWinPtr = TkpGetOtherWindow(macWin->toplevel->winPtr);
if (contWinPtr) {
result = TkMacOSXGetRootControl((Drawable)contWinPtr->privatePtr);
}
}
return result;
}
/*
*----------------------------------------------------------------------
*
* 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 clipping regions for the window and its children are marked 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.
*/
#ifdef TK_MAC_DEBUG_CLIP_REGIONS
TkMacOSXDbgMsg("%s", winPtr->pathName);
#endif
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;
}
if (macWin->drawRgn) {
CFRelease(macWin->drawRgn);
macWin->drawRgn = 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 window's 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:
* Fills in a Rect.
*
*----------------------------------------------------------------------
*/
void
TkMacOSXWinBounds(
TkWindow *winPtr,
void *bounds)
{
Rect *b = (Rect *) bounds;
b->left = winPtr->privatePtr->xOff;
b->top = winPtr->privatePtr->yOff;
b->right = b->left + winPtr->changes.width;
b->bottom = b->top + winPtr->changes.height;
}
/*
*----------------------------------------------------------------------
*
* TkMacOSXWinCGBounds --
*
* Given a Tk window this function determines the window's bounds in
* the coordinate system of the Tk toplevel window in which this window
* is contained. This fills in a CGRect struct.
*
* Results:
* None.
*
* Side effects:
* Fill in a CGRect.
*
*----------------------------------------------------------------------
*/
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;
}
/*
*----------------------------------------------------------------------
*
* TkMacOSXWinNSBounds --
*
* Given a Tk window this function determines the window's bounds in
* the coordinate system of the TKContentView in which this Tk window
* is contained, which has the origin at the lower left corner. This
* fills in an NSRect struct and requires the TKContentView as a
* parameter
*
* Results:
* None.
*
* Side effects:
* Fills in an NSRect.
*
*----------------------------------------------------------------------
*/
void
TkMacOSXWinNSBounds(
TkWindow *winPtr,
NSView *view,
NSRect *bounds)
{
bounds->size.width = winPtr->changes.width;
bounds->size.height = winPtr->changes.height;
bounds->origin.x = winPtr->privatePtr->xOff;
bounds->origin.y = ([view bounds].size.height -
bounds->size.height -
winPtr->privatePtr->yOff);
}
/*
*----------------------------------------------------------------------
*
* UpdateOffsets --
*
* Updates the X & Y offsets of the given TkWindow from the TopLevel it is
* a descendant 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 CGBitmapContext.
*
*----------------------------------------------------------------------
*/
Pixmap
Tk_GetPixmap(
Display *display, /* Display for new pixmap (can be null). */
TCL_UNUSED(Drawable), /* 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->drawRgn = NULL;
macPix->referenceCount = 0;
macPix->toplevel = NULL;
macPix->flags = TK_IS_PIXMAP | (depth == 1 ? TK_IS_BW_PIXMAP : 0);
macPix->view = nil;
macPix->context = NULL;
macPix->size = CGSizeMake(width, height);
return (Pixmap) macPix;
}
/*
*----------------------------------------------------------------------
*
* Tk_FreePixmap --
*
* Release the resources associated with a pixmap.
*
* Results:
* None.
*
* Side effects:
* Deletes the CGBitmapContext created by Tk_GetPixmap.
*
*----------------------------------------------------------------------
*/
void
Tk_FreePixmap(
Display *display, /* Display. */
Pixmap pixmap) /* Pixmap to destroy */
{
MacDrawable *macPix = (MacDrawable *)pixmap;
display->request++;
if (macPix->context) {
char *data = CGBitmapContextGetData(macPix->context);
if (data) {
ckfree(data);
}
CFRelease(macPix->context);
}
ckfree(macPix);
}
/*
* Local Variables:
* mode: objc
* c-basic-offset: 4
* fill-column: 79
* coding: utf-8
* End:
*/