/* * tkMacOSXWindowEvent.c -- * * This file defines the routines for both creating and handling Window * Manager class events for Tk. * * Copyright 2001-2009, Apple Inc. * Copyright (c) 2005-2009 Daniel A. Steffen * * 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 "tkMacOSXWm.h" #include "tkMacOSXEvent.h" #include "tkMacOSXDebug.h" /* #ifdef TK_MAC_DEBUG #define TK_MAC_DEBUG_EVENTS #define TK_MAC_DEBUG_DRAWING #endif */ /* * Declaration of functions used only in this file */ static int GenerateUpdates(HIMutableShapeRef updateRgn, CGRect *updateBounds, TkWindow *winPtr); static int GenerateActivateEvents(TkWindow *winPtr, int activeFlag); static void DoWindowActivate(ClientData clientData); #pragma mark TKApplication(TKWindowEvent) #ifdef TK_MAC_DEBUG_NOTIFICATIONS extern NSString *NSWindowWillOrderOnScreenNotification; extern NSString *NSWindowDidOrderOnScreenNotification; extern NSString *NSWindowDidOrderOffScreenNotification; #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 #define NSWindowWillStartLiveResizeNotification @"NSWindowWillStartLiveResizeNotification" #define NSWindowDidEndLiveResizeNotification @"NSWindowDidEndLiveResizeNotification" #endif #endif extern NSString *opaqueTag; @implementation TKApplication(TKWindowEvent) - (void) windowActivation: (NSNotification *) notification { #ifdef TK_MAC_DEBUG_NOTIFICATIONS TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification); #endif BOOL activate = [[notification name] isEqualToString:NSWindowDidBecomeKeyNotification]; NSWindow *w = [notification object]; TkWindow *winPtr = TkMacOSXGetTkWindow(w); if (winPtr && Tk_IsMapped(winPtr)) { GenerateActivateEvents(winPtr, activate); } } - (void) windowBoundsChanged: (NSNotification *) notification { #ifdef TK_MAC_DEBUG_NOTIFICATIONS TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification); #endif BOOL movedOnly = [[notification name] isEqualToString:NSWindowDidMoveNotification]; if (movedOnly) { /* constraining to screen after move not needed with AppKit */ } NSWindow *w = [notification object]; TkWindow *winPtr = TkMacOSXGetTkWindow(w); if (winPtr) { WmInfo *wmPtr = winPtr->wmInfoPtr; NSRect bounds = [w frame]; int x, y, width = -1, height = -1, flags = 0; x = bounds.origin.x; y = tkMacOSXZeroScreenHeight - (bounds.origin.y + bounds.size.height); if (winPtr->changes.x != x || winPtr->changes.y != y){ flags |= TK_LOCATION_CHANGED; } else { x = y = -1; } if (!movedOnly && (winPtr->changes.width != bounds.size.width || winPtr->changes.height != bounds.size.height)) { width = bounds.size.width - wmPtr->xInParent; height = bounds.size.height - wmPtr->yInParent; flags |= TK_SIZE_CHANGED; } if (Tcl_GetServiceMode() != TCL_SERVICE_NONE) { /* * Propagate geometry changes immediately. */ flags |= TK_MACOSX_HANDLE_EVENT_IMMEDIATELY; } TkGenWMConfigureEvent((Tk_Window) winPtr, x, y, width, height, flags); } } - (void) windowExpanded: (NSNotification *) notification { #ifdef TK_MAC_DEBUG_NOTIFICATIONS TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification); #endif NSWindow *w = [notification object]; TkWindow *winPtr = TkMacOSXGetTkWindow(w); if (winPtr) { winPtr->wmInfoPtr->hints.initial_state = TkMacOSXIsWindowZoomed(winPtr) ? ZoomState : NormalState; Tk_MapWindow((Tk_Window) winPtr); if (Tcl_GetServiceMode() != TCL_SERVICE_NONE) { /* * Process all Tk events generated by Tk_MapWindow(). */ while (Tcl_ServiceEvent(0)) {} while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {} /* * NSWindowDidDeminiaturizeNotification is received after * NSWindowDidBecomeKeyNotification, so activate manually */ GenerateActivateEvents(winPtr, 1); } else { Tcl_DoWhenIdle(DoWindowActivate, winPtr); } } } - (void) windowCollapsed: (NSNotification *) notification { #ifdef TK_MAC_DEBUG_NOTIFICATIONS TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification); #endif NSWindow *w = [notification object]; TkWindow *winPtr = TkMacOSXGetTkWindow(w); if (winPtr) { Tk_UnmapWindow((Tk_Window) winPtr); } } - (BOOL) windowShouldClose: (NSWindow *) w { #ifdef TK_MAC_DEBUG_NOTIFICATIONS TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, w); #endif TkWindow *winPtr = TkMacOSXGetTkWindow(w); if (winPtr) { TkGenWMDestroyEvent((Tk_Window) winPtr); } /* * If necessary, TkGenWMDestroyEvent() handles [close]ing the window, * so can always return NO from -windowShouldClose: for a Tk window. */ return (winPtr ? NO : YES); } #ifdef TK_MAC_DEBUG_NOTIFICATIONS - (void) windowDragStart: (NSNotification *) notification { TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification); } - (void) windowLiveResize: (NSNotification *) notification { TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification); //BOOL start = [[notification name] isEqualToString:NSWindowWillStartLiveResizeNotification]; } - (void) windowMapped: (NSNotification *) notification { TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification); NSWindow *w = [notification object]; TkWindow *winPtr = TkMacOSXGetTkWindow(w); if (winPtr) { //Tk_MapWindow((Tk_Window) winPtr); } } - (void) windowBecameVisible: (NSNotification *) notification { TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification); } - (void) windowUnmapped: (NSNotification *) notification { TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification); NSWindow *w = [notification object]; TkWindow *winPtr = TkMacOSXGetTkWindow(w); if (winPtr) { //Tk_UnmapWindow((Tk_Window) winPtr); } } #endif /* TK_MAC_DEBUG_NOTIFICATIONS */ - (void) _setupWindowNotifications { NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; #define observe(n, s) \ [nc addObserver:self selector:@selector(s) name:(n) object:nil] observe(NSWindowDidBecomeKeyNotification, windowActivation:); observe(NSWindowDidResignKeyNotification, windowActivation:); observe(NSWindowDidMoveNotification, windowBoundsChanged:); observe(NSWindowDidResizeNotification, windowBoundsChanged:); observe(NSWindowDidDeminiaturizeNotification, windowExpanded:); observe(NSWindowDidMiniaturizeNotification, windowCollapsed:); #ifdef TK_MAC_DEBUG_NOTIFICATIONS observe(NSWindowWillMoveNotification, windowDragStart:); observe(NSWindowWillStartLiveResizeNotification, windowLiveResize:); observe(NSWindowDidEndLiveResizeNotification, windowLiveResize:); observe(NSWindowWillOrderOnScreenNotification, windowMapped:); observe(NSWindowDidOrderOnScreenNotification, windowBecameVisible:); observe(NSWindowDidOrderOffScreenNotification, windowUnmapped:); #endif #undef observe } @end #pragma mark TKApplication(TKApplicationEvent) @implementation TKApplication(TKApplicationEvent) - (void) applicationActivate: (NSNotification *) notification { #ifdef TK_MAC_DEBUG_NOTIFICATIONS TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification); #endif [NSApp tkCheckPasteboard]; } - (void) applicationDeactivate: (NSNotification *) notification { #ifdef TK_MAC_DEBUG_NOTIFICATIONS TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification); #endif TkSuspendClipboard(); } - (void) applicationShowHide: (NSNotification *) notification { #ifdef TK_MAC_DEBUG_NOTIFICATIONS TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification); #endif const char *cmd = ([[notification name] isEqualToString: NSApplicationDidUnhideNotification] ? "::tk::mac::OnShow" : "::tk::mac::OnHide"); if (_eventInterp && Tcl_FindCommand(_eventInterp, cmd, NULL, 0)) { int code = Tcl_EvalEx(_eventInterp, cmd, -1, TCL_EVAL_GLOBAL); if (code != TCL_OK) { Tcl_BackgroundException(_eventInterp, code); } Tcl_ResetResult(_eventInterp); } } - (void) displayChanged: (NSNotification *) notification { #ifdef TK_MAC_DEBUG_NOTIFICATIONS TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification); #endif TkDisplay *dispPtr = TkGetDisplayList(); if (dispPtr) { TkMacOSXDisplayChanged(dispPtr->display); } } @end #pragma mark - /* *---------------------------------------------------------------------- * * 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; } if (!HIShapeIntersectsRect(updateRgn, &bounds)) { return 0; } /* * 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); CFRelease(damageRgn); CFRelease(boundsRgn); event.xany.serial = LastKnownRequestProcessed(Tk_Display(winPtr)); 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); #ifdef TK_MAC_DEBUG_DRAWING TKLog(@"Expose %p {{%d, %d}, {%d, %d}}", event.xany.window, event.xexpose.x, event.xexpose.y, event.xexpose.width, event.xexpose.height); #endif /* * 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( TkWindow *winPtr, int activeFlag) { TkGenerateActivateEvents(winPtr, activeFlag); TkMacOSXGenerateFocusEvent(winPtr, activeFlag); return true; } /* *---------------------------------------------------------------------- * * DoWindowActivate -- * * Idle handler that calls GenerateActivateEvents(). * * Results: * None. * * Side effects: * Additional events may be place on the Tk event queue. * *---------------------------------------------------------------------- */ void DoWindowActivate( ClientData clientData) { GenerateActivateEvents(clientData, 1); } /* *---------------------------------------------------------------------- * * 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( TkWindow *winPtr, /* Root X window for event. */ int activeFlag) { XEvent event; /* * Don't send focus events to windows of class help or to windows with the * kWindowNoActivatesAttribute. */ if (winPtr->wmInfoPtr && (winPtr->wmInfoPtr->macClass == kHelpWindowClass || winPtr->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 = LastKnownRequestProcessed(Tk_Display(winPtr)); event.xany.send_event = False; event.xfocus.display = Tk_Display(winPtr); event.xfocus.window = winPtr->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 = LastKnownRequestProcessed(Tk_Display(tkwin)); 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; if (flags & TK_MACOSX_HANDLE_EVENT_IMMEDIATELY) { Tk_HandleEvent(&event); } else { 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 = LastKnownRequestProcessed(Tk_Display(tkwin)); 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_HandleEvent(&event); } /* *---------------------------------------------------------------------- * * 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_EvalEx(interp, protPtr->command, -1, TCL_EVAL_GLOBAL); if (result != TCL_OK) { Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf( "\n (command for \"%s\" window manager protocol)", Tk_GetAtomName((Tk_Window) winPtr, 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); } #pragma mark TKContentView #import /* * Custom content view for Tk NSWindows, containing standard NSView subviews. * The goal is to emulate X11-style drawing in response to Expose events: * during the normal AppKit drawing cycle, we supress drawing of all subviews * (using a technique adapted from WebKit's WebHTMLView) and instead send * Expose events about the subviews that would be redrawn. Tk Expose event * handling and drawing handlers then draw the subviews manually via their * -displayRectIgnoringOpacity: */ @interface TKContentView(TKWindowEvent) - (void) drawRect: (NSRect) rect; - (void) generateExposeEvents: (HIMutableShapeRef) shape; - (BOOL) isOpaque; - (BOOL) wantsDefaultClipping; - (BOOL) acceptsFirstResponder; - (void) keyDown: (NSEvent *) theEvent; @end @implementation TKContentView @end static Tk_RestrictAction ExposeRestrictProc( ClientData arg, XEvent *eventPtr) { return (eventPtr->type==Expose && eventPtr->xany.serial==PTR2UINT(arg) ? TK_PROCESS_EVENT : TK_DEFER_EVENT); } @implementation TKContentView(TKWindowEvent) - (void) drawRect: (NSRect) rect { const NSRect *rectsBeingDrawn; NSInteger rectsBeingDrawnCount; [self getRectsBeingDrawn:&rectsBeingDrawn count:&rectsBeingDrawnCount]; #ifdef TK_MAC_DEBUG_DRAWING TKLog(@"-[%@(%p) %s%@]", [self class], self, _cmd, NSStringFromRect(rect)); [[NSColor colorWithDeviceRed:0.0 green:1.0 blue:0.0 alpha:.1] setFill]; NSRectFillListUsingOperation(rectsBeingDrawn, rectsBeingDrawnCount, NSCompositeSourceOver); #endif NSWindow *w = [self window]; //remove private API calls here: not needed on systems >= 10.7 // if ([self isOpaque] && [w showsResizeIndicator]) { // NSRect bounds = [self convertRect:[w _growBoxRect] fromView:nil]; // if ([self needsToDrawRect:bounds]) { // NSEraseRect(bounds); // } // } CGFloat height = [self bounds].size.height; HIMutableShapeRef drawShape = HIShapeCreateMutable(); while (rectsBeingDrawnCount--) { CGRect r = NSRectToCGRect(*rectsBeingDrawn++); r.origin.y = height - (r.origin.y + r.size.height); HIShapeUnionWithRect(drawShape, &r); } if (CFRunLoopGetMain() == CFRunLoopGetCurrent()) { [self generateExposeEvents:drawShape]; } else { [self performSelectorOnMainThread:@selector(generateExposeEvents:) withObject:(id)drawShape waitUntilDone:NO modes:[NSArray arrayWithObjects:NSRunLoopCommonModes, NSEventTrackingRunLoopMode, NSModalPanelRunLoopMode, nil]]; } CFRelease(drawShape); } - (void) generateExposeEvents: (HIMutableShapeRef) shape { TkWindow *winPtr = TkMacOSXGetTkWindow([self window]); unsigned long serial; CGRect updateBounds; if (!winPtr) { return; } HIShapeGetBounds(shape, &updateBounds); serial = LastKnownRequestProcessed(Tk_Display(winPtr)); if (GenerateUpdates(shape, &updateBounds, winPtr) && ![[NSRunLoop currentRunLoop] currentMode] && Tcl_GetServiceMode() != TCL_SERVICE_NONE) { /* * Ensure there are no pending idle-time redraws that could prevent the * just posted Expose events from generating new redraws. */ while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {} /* * For smoother drawing, process Expose events and resulting redraws * immediately instead of at idle time. */ ClientData oldArg; Tk_RestrictProc *oldProc = Tk_RestrictEvents(ExposeRestrictProc, UINT2PTR(serial), &oldArg); while (Tcl_ServiceEvent(TCL_WINDOW_EVENTS)) {} Tk_RestrictEvents(oldProc, oldArg, &oldArg); while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {} } } - (void) tkToolbarButton: (id) sender { #ifdef TK_MAC_DEBUG_EVENTS TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd); #endif XVirtualEvent event; int x, y; TkWindow *winPtr = TkMacOSXGetTkWindow([self window]); Tk_Window tkwin = (Tk_Window) winPtr; bzero(&event, sizeof(XVirtualEvent)); event.type = VirtualEvent; event.serial = LastKnownRequestProcessed(Tk_Display(tkwin)); event.send_event = false; event.display = Tk_Display(tkwin); event.event = Tk_WindowId(tkwin); event.root = XRootWindow(Tk_Display(tkwin), 0); event.subwindow = None; event.time = TkpGetMS(); XQueryPointer(NULL, winPtr->window, NULL, NULL, &event.x_root, &event.y_root, &x, &y, &event.state); Tk_TopCoordsToWindow(tkwin, x, y, &event.x, &event.y); event.same_screen = true; event.name = Tk_GetUid("ToolbarButton"); Tk_QueueWindowEvent((XEvent *) &event, TCL_QUEUE_TAIL); } #ifdef TK_MAC_DEBUG_DRAWING - (void) setFrameSize: (NSSize) newSize { TKLog(@"-[%@(%p) %s%@]", [self class], self, _cmd, NSStringFromSize(newSize)); [super setFrameSize:newSize]; } - (void) setNeedsDisplayInRect: (NSRect) invalidRect { TKLog(@"-[%@(%p) %s%@]", [self class], self, _cmd, NSStringFromRect(invalidRect)); [super setNeedsDisplayInRect:invalidRect]; } #endif - (BOOL) isOpaque { NSWindow *w = [self window]; if (opaqueTag != NULL) { return YES; } else { return (w && (([w styleMask] & NSTexturedBackgroundWindowMask) || ![w isOpaque]) ? NO : YES); } } - (BOOL) wantsDefaultClipping { return NO; } - (BOOL) acceptsFirstResponder { return YES; } - (void) keyDown: (NSEvent *) theEvent { #ifdef TK_MAC_DEBUG_EVENTS TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, theEvent); #endif } @end /*Remove private/non-documented API calls. This is strongly discouraged by Apple and may lead to breakage in the future.*/ // #pragma mark TKContentViewPrivate // /* // * Technique adapted from WebKit/WebKit/mac/WebView/WebHTMLView.mm to supress // * normal AppKit subview drawing and make all drawing go through us. // * Overrides NSView internals. // */ // @interface TKContentView(TKContentViewPrivate) // - (id) initWithFrame: (NSRect) frame; // - (void) _setAsideSubviews; // - (void) _restoreSubviews; // @end // @interface NSView(TKContentViewPrivate) // - (void) _recursiveDisplayRectIfNeededIgnoringOpacity: (NSRect) rect // isVisibleRect: (BOOL) isVisibleRect // rectIsVisibleRectForView: (NSView *) visibleView // topView: (BOOL) topView; // - (void) _recursiveDisplayAllDirtyWithLockFocus: (BOOL) needsLockFocus // visRect: (NSRect) visRect; // - (void) _recursive: (BOOL) recurse // displayRectIgnoringOpacity: (NSRect) displayRect // inContext: (NSGraphicsContext *) context topView: (BOOL) topView; // - (void) _lightWeightRecursiveDisplayInRect: (NSRect) visRect; // - (BOOL) _drawRectIfEmpty; // - (void) _drawRect: (NSRect) inRect clip: (BOOL) clip; // - (void) _setDrawsOwnDescendants: (BOOL) drawsOwnDescendants; // @end // #endif // @implementation TKContentView(TKContentViewPrivate) // - (id) initWithFrame: (NSRect) frame // { // self = [super initWithFrame:frame]; // if (self) { // _savedSubviews = nil; // _subviewsSetAside = NO; // [self _setDrawsOwnDescendants:YES]; // } // return self; // } // - (void) _setAsideSubviews // { // #ifdef TK_MAC_DEBUG // if (_subviewsSetAside || _savedSubviews) { // Tcl_Panic("TKContentView _setAsideSubviews called incorrectly"); // } // #endif // _savedSubviews = _subviews; // _subviews = nil; // _subviewsSetAside = YES; // } // - (void) _restoreSubviews // { // #ifdef TK_MAC_DEBUG // if (!_subviewsSetAside || _subviews) { // Tcl_Panic("TKContentView _restoreSubviews called incorrectly"); // } // #endif // _subviews = _savedSubviews; // _savedSubviews = nil; // _subviewsSetAside = NO; // } // - (void) _recursiveDisplayRectIfNeededIgnoringOpacity: (NSRect) rect // isVisibleRect: (BOOL) isVisibleRect // rectIsVisibleRectForView: (NSView *) visibleView // topView: (BOOL) topView // { // [self _setAsideSubviews]; // [super _recursiveDisplayRectIfNeededIgnoringOpacity:rect // isVisibleRect:isVisibleRect rectIsVisibleRectForView:visibleView // topView:topView]; // [self _restoreSubviews]; // } // - (void) _recursiveDisplayAllDirtyWithLockFocus: (BOOL) needsLockFocus // visRect: (NSRect) visRect // { // BOOL needToSetAsideSubviews = !_subviewsSetAside; // if (needToSetAsideSubviews) { // [self _setAsideSubviews]; // } // [super _recursiveDisplayAllDirtyWithLockFocus:needsLockFocus // visRect:visRect]; // if (needToSetAsideSubviews) { // [self _restoreSubviews]; // } // } // - (void) _recursive: (BOOL) recurse // displayRectIgnoringOpacity: (NSRect) displayRect // inContext: (NSGraphicsContext *) context topView: (BOOL) topView // { // [self _setAsideSubviews]; // [super _recursive:recurse // displayRectIgnoringOpacity:displayRect inContext:context // topView:topView]; // [self _restoreSubviews]; // } // - (void) _lightWeightRecursiveDisplayInRect: (NSRect) visRect // { // BOOL needToSetAsideSubviews = !_subviewsSetAside; // if (needToSetAsideSubviews) { // [self _setAsideSubviews]; // } // [super _lightWeightRecursiveDisplayInRect:visRect]; // if (needToSetAsideSubviews) { // [self _restoreSubviews]; // } // } // - (BOOL) _drawRectIfEmpty // { // /* // * Our -drawRect manages subview drawing directly, so it needs to be called // * even if the area to be redrawn is completely obscured by subviews. // */ // return YES; // } // - (void) _drawRect: (NSRect) inRect clip: (BOOL) clip // { // #ifdef TK_MAC_DEBUG_DRAWING // TKLog(@"-[%@(%p) %s%@]", [self class], self, _cmd, // NSStringFromRect(inRect)); // #endif // BOOL subviewsWereSetAside = _subviewsSetAside; // if (subviewsWereSetAside) { // [self _restoreSubviews]; // } // [super _drawRect:inRect clip:clip]; // if (subviewsWereSetAside) { // [self _setAsideSubviews]; // } // } // @end /* * Local Variables: * mode: objc * c-basic-offset: 4 * fill-column: 79 * coding: utf-8 * End: */