diff options
Diffstat (limited to 'carbon/tkMacOSXWindowEvent.c')
-rw-r--r-- | carbon/tkMacOSXWindowEvent.c | 985 |
1 files changed, 985 insertions, 0 deletions
diff --git a/carbon/tkMacOSXWindowEvent.c b/carbon/tkMacOSXWindowEvent.c new file mode 100644 index 0000000..2f46026 --- /dev/null +++ b/carbon/tkMacOSXWindowEvent.c @@ -0,0 +1,985 @@ +/* + * tkMacOSXWindowEvent.c -- + * + * This file defines the routines for both creating and handling Window + * Manager class events for Tk. + * + * Copyright 2001, Apple Computer, Inc. + * Copyright (c) 2005-2007 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. + * + * The following terms apply to all files originating from Apple + * Computer, Inc. ("Apple") and associated with the software unless + * explicitly disclaimed in individual files. + * + * Apple hereby grants permission to use, copy, modify, distribute, and + * license this software and its documentation for any purpose, provided + * that existing copyright notices are retained in all copies and that + * this notice is included verbatim in any distributions. No written + * agreement, license, or royalty fee is required for any of the + * authorized uses. Modifications to this software may be copyrighted by + * their authors and need not follow the licensing terms described here, + * provided that the new terms are clearly indicated on the first page of + * each file where they apply. + * + * IN NO EVENT SHALL APPLE, THE AUTHORS OR DISTRIBUTORS OF THE SOFTWARE + * BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR + * CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS + * DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN IF APPLE OR THE + * AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. APPLE, + * THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND + * NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND + * APPLE, THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE + * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * GOVERNMENT USE: If you are acquiring this software on behalf of the + * U.S. government, the Government shall have only "Restricted Rights" in + * the software and related documentation as defined in the Federal + * Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are + * acquiring the software on behalf of the Department of Defense, the + * software shall be classified as "Commercial Computer Software" and the + * Government shall have only "Restricted Rights" as defined in Clause + * 252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the + * authors grant the U.S. Government and others acting in its behalf + * permission to use and distribute the software in accordance with the + * terms specified in this license. + */ + +#include "tkMacOSXPrivate.h" +#include "tkMacOSXWm.h" +#include "tkMacOSXEvent.h" +#include "tkMacOSXDebug.h" + +/* +#ifdef TK_MAC_DEBUG +#define TK_MAC_DEBUG_CLIP_REGIONS +#endif +*/ + +/* + * Declaration of functions used only in this file + */ + +static int GenerateUpdateEvent(Window window); +static int GenerateUpdates(HIMutableShapeRef updateRgn, + CGRect *updateBounds, TkWindow *winPtr); +static int GenerateActivateEvents(Window window, int activeFlag); +static void ClearPort(CGrafPtr port, HIShapeRef updateRgn); + +/* + *---------------------------------------------------------------------- + * + * TkMacOSXProcessApplicationEvent -- + * + * This processes Application level events, mainly activate and + * deactivate. + * + * Results: + * 0. + * + * Side effects: + * Hide or reveal floating windows. + * + *---------------------------------------------------------------------- + */ + +MODULE_SCOPE int +TkMacOSXProcessApplicationEvent( + TkMacOSXEvent *eventPtr, + MacEventStatus *statusPtr) +{ + Tcl_CmdInfo dummy; + + /* + * This is a bit of a hack. We get "show" events both when we come back + * from being hidden, and whenever we are activated. I only want to run + * the "show" proc when we have been hidden already, not as a substitute + * for <Activate>. So I use this toggle... + */ + + static int toggleHide = 0; + + switch (eventPtr->eKind) { + case kEventAppActivated: + ShowFloatingWindows(); + break; + case kEventAppDeactivated: + TkSuspendClipboard(); + HideFloatingWindows(); + break; + case kEventAppQuit: + statusPtr->stopProcessing = 1; + break; + case kEventAppHidden: + if (toggleHide == 0) { + toggleHide = 1; + if (eventPtr->interp && Tcl_GetCommandInfo(eventPtr->interp, + "::tk::mac::OnHide", &dummy)) { + Tcl_GlobalEval(eventPtr->interp, "::tk::mac::OnHide"); + } + } + statusPtr->stopProcessing = 1; + break; + case kEventAppShown: + if (toggleHide == 1) { + toggleHide = 0; + if (eventPtr->interp && Tcl_GetCommandInfo(eventPtr->interp, + "::tk::mac::OnShow", &dummy)) { + Tcl_GlobalEval(eventPtr->interp, "::tk::mac::OnShow"); + } + } + statusPtr->stopProcessing = 1; + break; + case kEventAppAvailableWindowBoundsChanged: { + static UInt32 prevId = 0; + UInt32 id; + OSStatus err; + + err = ChkErr(GetEventParameter, eventPtr->eventRef, + kEventParamTransactionID, typeUInt32, NULL, sizeof(id), NULL, + &id); + if (err != noErr || id != prevId) { + TkDisplay *dispPtr = TkGetDisplayList(); + + prevId = id; + TkMacOSXDisplayChanged(dispPtr->display); + } + /* + * Should we call ::tk::mac::OnDisplayChanged? + */ + break; + } + default: + break; + } + return 0; +} + +/* + *---------------------------------------------------------------------- + * + * TkMacOSXProcessAppearanceEvent -- + * + * This processes Appearance events. + * + * Results: + * 0. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +MODULE_SCOPE int +TkMacOSXProcessAppearanceEvent( + TkMacOSXEvent *eventPtr, + MacEventStatus *statusPtr) +{ + switch (eventPtr->eKind) { + case kEventAppearanceScrollBarVariantChanged: + TkMacOSXInitScrollbarMetrics(); + break; + default: + break; + } + return 0; +} + +/* + *---------------------------------------------------------------------- + * + * TkMacOSXProcessWindowEvent -- + * + * This processes Window level events, mainly activate and deactivate. + * + * Results: + * 0. + * + * Side effects: + * Cause Windows to be moved forward or backward in the window stack. + * + *---------------------------------------------------------------------- + */ + +MODULE_SCOPE int +TkMacOSXProcessWindowEvent( + TkMacOSXEvent *eventPtr, + MacEventStatus *statusPtr) +{ + OSStatus err; + WindowRef whichWindow; + Window window; + int eventFound = false; + TkDisplay *dispPtr; + TkWindow *winPtr; + + switch (eventPtr->eKind) { + case kEventWindowActivated: + case kEventWindowDeactivated: + case kEventWindowUpdate: + case kEventWindowExpanding: + case kEventWindowBoundsChanged: + case kEventWindowDragStarted: + case kEventWindowDragCompleted: + case kEventWindowConstrain: + case kEventWindowGetRegion: + case kEventWindowDrawContent: + break; + default: + return 0; + break; + } + err = ChkErr(GetEventParameter, eventPtr->eventRef, + kEventParamDirectObject, typeWindowRef, NULL, sizeof(whichWindow), + NULL, &whichWindow); + if (err != noErr) { + return 0; + } + + window = TkMacOSXGetXWindow(whichWindow); + dispPtr = TkGetDisplayList(); + winPtr = (TkWindow *) Tk_IdToWindow(dispPtr->display, window); + + switch (eventPtr->eKind) { + case kEventWindowActivated: + case kEventWindowDeactivated: + if (window != None) { + int activate = (eventPtr->eKind == kEventWindowActivated); + + eventFound |= GenerateActivateEvents(window, activate); + eventFound |= TkMacOSXGenerateFocusEvent(window, activate); + if (winPtr) { + TkMacOSXEnterExitFullscreen(winPtr, activate); + } + statusPtr->stopProcessing = 1; + } + break; + case kEventWindowUpdate: + if (window != None && GenerateUpdateEvent(window)) { + eventFound = true; + statusPtr->stopProcessing = 1; + } + break; + case kEventWindowExpanding: + if (winPtr) { + winPtr->wmInfoPtr->hints.initial_state = + TkMacOSXIsWindowZoomed(winPtr) ? ZoomState : NormalState; + Tk_MapWindow((Tk_Window) winPtr); + + /* + * Need to process all Tk events generated by Tk_MapWindow() + * before returning to ensure all children are mapped, as + * otherwise the Activate event that follows Expanding would not + * be processed by any unmapped children. + */ + + while (Tcl_ServiceEvent(TCL_WINDOW_EVENTS)) {/*empty body*/}; + while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {/*empty body*/}; + } + break; + case kEventWindowBoundsChanged: + if (winPtr) { + WmInfo *wmPtr = winPtr->wmInfoPtr; + UInt32 attr; + Rect bounds; + int x = -1, y = -1, width = -1, height = -1, flags = 0; + + ChkErr(GetEventParameter, eventPtr->eventRef, + kEventParamAttributes, typeUInt32, NULL, sizeof(attr), + NULL, &attr); + ChkErr(GetEventParameter, eventPtr->eventRef, + kEventParamCurrentBounds, typeQDRectangle, NULL, + sizeof(bounds), NULL, &bounds); + if (attr & kWindowBoundsChangeOriginChanged) { + x = bounds.left - wmPtr->xInParent; + y = bounds.top - wmPtr->yInParent; + flags |= TK_LOCATION_CHANGED; + } + if (attr & kWindowBoundsChangeSizeChanged) { + width = bounds.right - bounds.left; + height = bounds.bottom - bounds.top; + flags |= TK_SIZE_CHANGED; + } + TkMacOSXInvalClipRgns((Tk_Window) winPtr); + TkMacOSXInvalidateWindow((MacDrawable*) window, TK_PARENT_WINDOW); + TkGenWMConfigureEvent((Tk_Window)winPtr, x, y, width, height, + flags); + if (attr & kWindowBoundsChangeUserResize || + attr & kWindowBoundsChangeUserDrag) { + TkMacOSXRunTclEventLoop(); + } + if (wmPtr->attributes & kWindowResizableAttribute) { + HIViewRef growBoxView; + + err = HIViewFindByID(HIViewGetRoot(whichWindow), + kHIViewWindowGrowBoxID, &growBoxView); + if (err == noErr) { + ChkErr(HIViewSetNeedsDisplay, growBoxView, true); + } + } + } + break; + case kEventWindowDragStarted: + if (!(TkMacOSXModifierState() & cmdKey)) { + TkMacOSXBringWindowForward(whichWindow); + } + TkMacOSXTrackingLoop(1); + break; + case kEventWindowDragCompleted: { + Rect maxBounds, bounds, strWidths; + int h = 0, v = 0; + + TkMacOSXTrackingLoop(0); + ChkErr(GetWindowGreatestAreaDevice, whichWindow, kWindowDragRgn, NULL, + &maxBounds); + ChkErr(GetWindowBounds, whichWindow, kWindowStructureRgn, &bounds); + ChkErr(GetWindowStructureWidths, whichWindow, &strWidths); + if (bounds.left > maxBounds.right - strWidths.left) { + h = maxBounds.right - (strWidths.left ? strWidths.left : 40) + - bounds.left; + } else if (bounds.right < maxBounds.left + strWidths.right) { + h = maxBounds.left + (strWidths.right ? strWidths.right : 40) + - bounds.right; + } + if (bounds.top > maxBounds.bottom - strWidths.top) { + v = maxBounds.bottom - (strWidths.top ? strWidths.top : 40) + - bounds.top; + } else if (bounds.bottom < maxBounds.top + strWidths.bottom) { + v = maxBounds.top + (strWidths.bottom ? strWidths.bottom : 40) + - bounds.bottom; + } else if (strWidths.top && bounds.top < maxBounds.top) { + v = maxBounds.top - bounds.top; + } + if (h || v) { + OffsetRect(&bounds, h, v); + ChkErr(SetWindowBounds, whichWindow, kWindowStructureRgn,&bounds); + } + break; + } + case kEventWindowConstrain: + if (winPtr && (winPtr->wmInfoPtr->flags & WM_FULLSCREEN) && + TkMacOSXMakeFullscreen(winPtr,whichWindow,1,NULL) == TCL_OK) { + statusPtr->stopProcessing = 1; + } + break; + case kEventWindowGetRegion: + if (winPtr && (winPtr->wmInfoPtr->flags & WM_TRANSPARENT)) { + WindowRegionCode code; + + statusPtr->stopProcessing = (CallNextEventHandler( + eventPtr->callRef, eventPtr->eventRef) == noErr); + err = ChkErr(GetEventParameter, eventPtr->eventRef, + kEventParamWindowRegionCode, typeWindowRegionCode, NULL, + sizeof(code), NULL, &code); + if (err == noErr && code == kWindowOpaqueRgn) { + RgnHandle rgn; + + err = ChkErr(GetEventParameter, eventPtr->eventRef, + kEventParamRgnHandle, typeQDRgnHandle, NULL, + sizeof(rgn), NULL, &rgn); + if (err == noErr) { + SetEmptyRgn(rgn); + statusPtr->stopProcessing = 1; + } + } + } + break; + case kEventWindowDrawContent: + if (winPtr && (winPtr->wmInfoPtr->flags & WM_TRANSPARENT)) { + CGrafPtr port; + + GetPort(&port); + ClearPort(port, NULL); + } + break; + } + + return eventFound; +} + +/* + *---------------------------------------------------------------------- + * + * GenerateUpdateEvent -- + * + * Given a Macintosh window update event this function generates all the + * Expose XEvents needed by Tk. + * + * Results: + * True if event(s) are generated - false otherwise. + * + * Side effects: + * Additional events may be place on the Tk event queue. + * + *---------------------------------------------------------------------- + */ + +static int +GenerateUpdateEvent( + Window window) +{ + WindowRef macWindow; + TkDisplay *dispPtr; + TkWindow *winPtr; + int result = 0; + CGRect updateBounds; + HIShapeRef rgn; + HIMutableShapeRef updateRgn; + int dx, dy; + + dispPtr = TkGetDisplayList(); + winPtr = (TkWindow *)Tk_IdToWindow(dispPtr->display, window); + + if (winPtr ==NULL ){ + return result; + } + macWindow = TkMacOSXDrawableWindow(window); + TK_IF_MAC_OS_X_API (5, HIWindowCopyShape, + ChkErr(HIWindowCopyShape, macWindow, kWindowUpdateRgn, + kHICoordSpaceWindow, &rgn); + dx = -winPtr->wmInfoPtr->xInParent; + dy = -winPtr->wmInfoPtr->yInParent; + ) TK_ELSE_MAC_OS_X (5, + Rect bounds; + + TkMacOSXCheckTmpQdRgnEmpty(); + ChkErr(GetWindowRegion, macWindow, kWindowUpdateRgn, tkMacOSXtmpQdRgn); + rgn = HIShapeCreateWithQDRgn(tkMacOSXtmpQdRgn); + SetEmptyRgn(tkMacOSXtmpQdRgn); + ChkErr(GetWindowBounds, macWindow, kWindowContentRgn, &bounds); + dx = -bounds.left; + dy = -bounds.top; + ) TK_ENDIF; + + updateRgn = HIShapeCreateMutableCopy(rgn); + CFRelease(rgn); + ChkErr(HIShapeOffset, updateRgn, dx, dy); + HIShapeGetBounds(updateRgn, &updateBounds); +#ifdef TK_MAC_DEBUG_CLIP_REGIONS + TkMacOSXDebugFlashRegion(window, updateRgn); +#endif /* TK_MAC_DEBUG_CLIP_REGIONS */ + BeginUpdate(macWindow); + if (winPtr->wmInfoPtr->flags & WM_TRANSPARENT) { + ClearPort(TkMacOSXGetDrawablePort(window), updateRgn); + } + result = GenerateUpdates(updateRgn, &updateBounds, winPtr); + EndUpdate(macWindow); + CFRelease(updateRgn); + if (result) { + /* + * Ensure there are no pending idle-time redraws that could prevent + * the just posted Expose events from generating new redraws. + */ + + Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT); + } + return result; + } + +/* + *---------------------------------------------------------------------- + * + * GenerateUpdates -- + * + * Given a Macintosh update region and a Tk window this function geneates + * a X Expose event for the window if it is within the update region. The + * function will then recursivly have each damaged window generate Expose + * events for its child windows. + * + * Results: + * True if event(s) are generated - false otherwise. + * + * Side effects: + * Additional events may be place on the Tk event queue. + * + *---------------------------------------------------------------------- + */ + +static int +GenerateUpdates( + HIMutableShapeRef updateRgn, + CGRect *updateBounds, + TkWindow *winPtr) +{ + TkWindow *childPtr; + XEvent event; + CGRect bounds, damageBounds; + HIShapeRef boundsRgn, damageRgn; + + TkMacOSXWinCGBounds(winPtr, &bounds); + if (!CGRectIntersectsRect(bounds, *updateBounds)) { + return 0; + } + TK_IF_MAC_OS_X_API (4, HIShapeIntersectsRect, + if (!HIShapeIntersectsRect(updateRgn, &bounds)) { + return 0; + } + ) TK_ENDIF + + /* + * Compute the bounding box of the area that the damage occured in. + */ + + boundsRgn = HIShapeCreateWithRect(&bounds); + damageRgn = HIShapeCreateIntersection(updateRgn, boundsRgn); + if (HIShapeIsEmpty(damageRgn)) { + CFRelease(damageRgn); + CFRelease(boundsRgn); + return 0; + } + HIShapeGetBounds(damageRgn, &damageBounds); + ChkErr(TkMacOSHIShapeUnion, boundsRgn, updateRgn, updateRgn); + HIShapeGetBounds(updateRgn, updateBounds); + CFRelease(damageRgn); + CFRelease(boundsRgn); + + event.xany.serial = Tk_Display(winPtr)->request; + event.xany.send_event = false; + event.xany.window = Tk_WindowId(winPtr); + event.xany.display = Tk_Display(winPtr); + event.type = Expose; + event.xexpose.x = damageBounds.origin.x - bounds.origin.x; + event.xexpose.y = damageBounds.origin.y - bounds.origin.y; + event.xexpose.width = damageBounds.size.width; + event.xexpose.height = damageBounds.size.height; + event.xexpose.count = 0; + Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); + + /* + * Generate updates for the children of this window + */ + + for (childPtr = winPtr->childList; childPtr != NULL; + childPtr = childPtr->nextPtr) { + if (!Tk_IsMapped(childPtr) || Tk_IsTopLevel(childPtr)) { + continue; + } + GenerateUpdates(updateRgn, updateBounds, childPtr); + } + + /* + * Generate updates for any contained windows + */ + + if (Tk_IsContainer(winPtr)) { + childPtr = TkpGetOtherWindow(winPtr); + if (childPtr != NULL && Tk_IsMapped(childPtr)) { + GenerateUpdates(updateRgn, updateBounds, childPtr); + } + + /* + * TODO: Here we should handle out of process embedding. + */ + } + + return 1; +} + +/* + *---------------------------------------------------------------------- + * + * GenerateActivateEvents -- + * + * Given a Macintosh window activate event this function generates all + * the X Activate events needed by Tk. + * + * Results: + * True if event(s) are generated - false otherwise. + * + * Side effects: + * Additional events may be place on the Tk event queue. + * + *---------------------------------------------------------------------- + */ + +int +GenerateActivateEvents( + Window window, /* Root X window for event. */ + int activeFlag) +{ + TkWindow *winPtr; + TkDisplay *dispPtr; + + dispPtr = TkGetDisplayList(); + winPtr = (TkWindow *) Tk_IdToWindow(dispPtr->display, window); + if (winPtr == NULL || winPtr->window == None) { + return false; + } + + TkGenerateActivateEvents(winPtr,activeFlag); + return true; +} + +/* + *---------------------------------------------------------------------- + * + * TkMacOSXGenerateFocusEvent -- + * + * Given a Macintosh window activate event this function generates all + * the X Focus events needed by Tk. + * + * Results: + * True if event(s) are generated - false otherwise. + * + * Side effects: + * Additional events may be place on the Tk event queue. + * + *---------------------------------------------------------------------- + */ + +MODULE_SCOPE int +TkMacOSXGenerateFocusEvent( + Window window, /* Root X window for event. */ + int activeFlag) +{ + XEvent event; + Tk_Window tkwin; + TkDisplay *dispPtr; + + dispPtr = TkGetDisplayList(); + tkwin = Tk_IdToWindow(dispPtr->display, window); + if (tkwin == NULL) { + return false; + } + + /* + * Don't send focus events to windows of class help or to windows with the + * kWindowNoActivatesAttribute. + */ + + if (((TkWindow *)tkwin)->wmInfoPtr->macClass == kHelpWindowClass || + ((TkWindow *)tkwin)->wmInfoPtr->attributes & + kWindowNoActivatesAttribute) { + return false; + } + + /* + * Generate FocusIn and FocusOut events. This event is only sent to the + * toplevel window. + */ + + if (activeFlag) { + event.xany.type = FocusIn; + } else { + event.xany.type = FocusOut; + } + + event.xany.serial = dispPtr->display->request; + event.xany.send_event = False; + event.xfocus.display = dispPtr->display; + event.xfocus.window = window; + event.xfocus.mode = NotifyNormal; + event.xfocus.detail = NotifyDetailNone; + + Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); + return true; +} + +/* + *---------------------------------------------------------------------- + * + * TkGenWMConfigureEvent -- + * + * Generate a ConfigureNotify event for Tk. Depending on the value of + * flag the values of width/height, x/y, or both may be changed. + * + * Results: + * None. + * + * Side effects: + * A ConfigureNotify event is sent to Tk. + * + *---------------------------------------------------------------------- + */ + +void +TkGenWMConfigureEvent( + Tk_Window tkwin, + int x, + int y, + int width, + int height, + int flags) +{ + XEvent event; + WmInfo *wmPtr; + TkWindow *winPtr = (TkWindow *) tkwin; + + if (tkwin == NULL) { + return; + } + + event.type = ConfigureNotify; + event.xconfigure.serial = Tk_Display(tkwin)->request; + event.xconfigure.send_event = False; + event.xconfigure.display = Tk_Display(tkwin); + event.xconfigure.event = Tk_WindowId(tkwin); + event.xconfigure.window = Tk_WindowId(tkwin); + event.xconfigure.border_width = winPtr->changes.border_width; + event.xconfigure.override_redirect = winPtr->atts.override_redirect; + if (winPtr->changes.stack_mode == Above) { + event.xconfigure.above = winPtr->changes.sibling; + } else { + event.xconfigure.above = None; + } + + if (!(flags & TK_LOCATION_CHANGED)) { + x = Tk_X(tkwin); + y = Tk_Y(tkwin); + } + if (!(flags & TK_SIZE_CHANGED)) { + width = Tk_Width(tkwin); + height = Tk_Height(tkwin); + } + event.xconfigure.x = x; + event.xconfigure.y = y; + event.xconfigure.width = width; + event.xconfigure.height = height; + + Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); + + /* + * Update window manager information. + */ + + if (Tk_IsTopLevel(winPtr)) { + wmPtr = winPtr->wmInfoPtr; + if (flags & TK_LOCATION_CHANGED) { + wmPtr->x = x; + wmPtr->y = y; + wmPtr->flags &= ~(WM_NEGATIVE_X | WM_NEGATIVE_Y); + } + if ((flags & TK_SIZE_CHANGED) && !(wmPtr->flags & WM_SYNC_PENDING) && + ((width != Tk_Width(tkwin)) || (height != Tk_Height(tkwin)))) { + if ((wmPtr->width == -1) && (width == winPtr->reqWidth)) { + /* + * Don't set external width, since the user didn't change it + * from what the widgets asked for. + */ + } else { + if (wmPtr->gridWin != NULL) { + wmPtr->width = wmPtr->reqGridWidth + + (width - winPtr->reqWidth)/wmPtr->widthInc; + if (wmPtr->width < 0) { + wmPtr->width = 0; + } + } else { + wmPtr->width = width; + } + } + if ((wmPtr->height == -1) && (height == winPtr->reqHeight)) { + /* + * Don't set external height, since the user didn't change it + * from what the widgets asked for. + */ + } else { + if (wmPtr->gridWin != NULL) { + wmPtr->height = wmPtr->reqGridHeight + + (height - winPtr->reqHeight)/wmPtr->heightInc; + if (wmPtr->height < 0) { + wmPtr->height = 0; + } + } else { + wmPtr->height = height; + } + } + wmPtr->configWidth = width; + wmPtr->configHeight = height; + } + } + + /* + * Now set up the changes structure. Under X we wait for the + * ConfigureNotify to set these values. On the Mac we know imediatly that + * this is what we want - so we just set them. However, we need to make + * sure the windows clipping region is marked invalid so the change is + * visible to the subwindow. + */ + + winPtr->changes.x = x; + winPtr->changes.y = y; + winPtr->changes.width = width; + winPtr->changes.height = height; + TkMacOSXInvalClipRgns(tkwin); +} + +/* + *---------------------------------------------------------------------- + * + * TkGenWMDestroyEvent -- + * + * Generate a WM Destroy event for Tk. + * + * Results: + * None. + * + * Side effects: + * A WM_PROTOCOL/WM_DELETE_WINDOW event is sent to Tk. + * + *---------------------------------------------------------------------- + */ + +void +TkGenWMDestroyEvent( + Tk_Window tkwin) +{ + XEvent event; + + event.xany.serial = Tk_Display(tkwin)->request; + event.xany.send_event = False; + event.xany.display = Tk_Display(tkwin); + + event.xclient.window = Tk_WindowId(tkwin); + event.xclient.type = ClientMessage; + event.xclient.message_type = Tk_InternAtom(tkwin, "WM_PROTOCOLS"); + event.xclient.format = 32; + event.xclient.data.l[0] = Tk_InternAtom(tkwin, "WM_DELETE_WINDOW"); + Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); +} + +/* + *---------------------------------------------------------------------- + * + * TkWmProtocolEventProc -- + * + * This procedure is called by the Tk_HandleEvent whenever a + * ClientMessage event arrives whose type is "WM_PROTOCOLS". This + * procedure handles the message from the window manager in an + * appropriate fashion. + * + * Results: + * None. + * + * Side effects: + * Depends on what sort of handler, if any, was set up for the protocol. + * + *---------------------------------------------------------------------- + */ + +void +TkWmProtocolEventProc( + TkWindow *winPtr, /* Window to which the event was sent. */ + XEvent *eventPtr) /* X event. */ +{ + WmInfo *wmPtr; + ProtocolHandler *protPtr; + Tcl_Interp *interp; + Atom protocol; + int result; + + wmPtr = winPtr->wmInfoPtr; + if (wmPtr == NULL) { + return; + } + protocol = (Atom) eventPtr->xclient.data.l[0]; + for (protPtr = wmPtr->protPtr; protPtr != NULL; + protPtr = protPtr->nextPtr) { + if (protocol == protPtr->protocol) { + Tcl_Preserve(protPtr); + interp = protPtr->interp; + Tcl_Preserve(interp); + result = Tcl_GlobalEval(interp, protPtr->command); + if (result != TCL_OK) { + Tcl_AddErrorInfo(interp, "\n (command for \""); + Tcl_AddErrorInfo(interp, + Tk_GetAtomName((Tk_Window) winPtr, protocol)); + Tcl_AddErrorInfo(interp, "\" window manager protocol)"); + Tcl_BackgroundException(interp, result); + } + Tcl_Release(interp); + Tcl_Release(protPtr); + return; + } + } + + /* + * No handler was present for this protocol. If this is a WM_DELETE_WINDOW + * message then just destroy the window. + */ + + if (protocol == Tk_InternAtom((Tk_Window) winPtr, "WM_DELETE_WINDOW")) { + Tk_DestroyWindow((Tk_Window) winPtr); + } +} + +/* + *---------------------------------------------------------------------- + * + * Tk_MacOSXIsAppInFront -- + * + * Returns 1 if this app is the foreground app. + * + * Results: + * 1 if app is in front, 0 otherwise. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +Tk_MacOSXIsAppInFront(void) +{ + OSStatus err; + ProcessSerialNumber frontPsn, ourPsn = {0, kCurrentProcess}; + Boolean isFrontProcess = true; + + err = ChkErr(GetFrontProcess, &frontPsn); + if (err == noErr) { + ChkErr(SameProcess, &frontPsn, &ourPsn, &isFrontProcess); + } + + return (isFrontProcess == true); +} + +/* + *---------------------------------------------------------------------- + * + * ClearPort -- + * + * Clear (i.e. fill with transparent color) the given port. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static void +ClearPort( + CGrafPtr port, + HIShapeRef updateRgn) +{ + CGContextRef context; + Rect bounds; + CGRect rect; + + GetPortBounds(port, &bounds); + QDBeginCGContext(port, &context); + SyncCGContextOriginWithPort(context, port); + CGContextConcatCTM(context, CGAffineTransformMake(1.0, 0.0, 0.0, -1.0, 0.0, + bounds.bottom - bounds.top)); + if (updateRgn) { + ChkErr(HIShapeReplacePathInCGContext, updateRgn, context); + CGContextEOClip(context); + } + rect = CGRectMake(0, 0, bounds.right, bounds.bottom); + CGContextClearRect(context, rect); + QDEndCGContext(port, &context); +} + +/* + * Local Variables: + * fill-column: 78 + * c-basic-offset: 4 + * End: + */ |