diff options
Diffstat (limited to 'macosx')
-rw-r--r-- | macosx/tkMacOSXMenu.c | 70 | ||||
-rw-r--r-- | macosx/tkMacOSXNotify.c | 12 | ||||
-rw-r--r-- | macosx/tkMacOSXPrivate.h | 7 |
3 files changed, 84 insertions, 5 deletions
diff --git a/macosx/tkMacOSXMenu.c b/macosx/tkMacOSXMenu.c index 735f7d2..dceb051 100644 --- a/macosx/tkMacOSXMenu.c +++ b/macosx/tkMacOSXMenu.c @@ -108,6 +108,65 @@ static void MenuSelectEvent(TkMenu *menuPtr); static void RecursivelyClearActiveMenu(TkMenu *menuPtr); static int ModifierCharWidth(Tk_Font tkfont); +#pragma mark TkBackgroundLoop + +/* + * The function TkMacOSXEventsCheckProc (in tkMacOSXNotify.c) is the "check + * proc" for the macOS event source. Its job is to remove NSEvents from the + * default event queue of the NSApplication. It does this by calling the + * method [NSApp nextEventMatchingMask: untilDate: inMode: dequeue:]. As a + * rule, when the untilDate is set to the distant past this method returns + * immediately. An exception to that rule is when the next event is the button + * press on a menu button. In that case, the method starts running a nested + * event loop in the mode NSEventTrackingRunLoopMode which does not return + * until the menu has been dismissed. In Tk 8.6.10 and earlier, this meant + * that the Tk event loop would block in its call to the check proc as long as + * the menu was posted. For example, opening a menu during the Rube Goldberg + * demo would cause the animation to stop. This was also the case for + * menubuttons. + * + * The TKBackground object below works around this problem, and allows a Tk + * event loop to run while a menu is open. It is a subclass of NSThread which + * inserts requests to call [NSApp _runBackgroundLoop] onto the queue + * associated with the NSEventTrackingRunLoopMode. One of these threads gets + * started in the callback [NSApp menuBeginTracking] and cancelled in [NSApp + * menuEndTracking]. + */ + +@interface TKBackgroundLoop: NSThread +@end + +@implementation TKBackgroundLoop +- (void) main +{ + NSArray *modeArray = [NSArray arrayWithObjects: NSEventTrackingRunLoopMode, + nil]; + while(1) { + + /* + * Queue a request to process Tk events during event tracking. + */ + + [NSApp performSelectorOnMainThread:@selector(_runBackgroundLoop) + withObject:nil + waitUntilDone:true + modes:modeArray]; + if (self.cancelled) { + [NSThread exit]; + } + + /* + * Allow the tracked events to be processed too. + */ + + [NSThread sleepForTimeInterval:0.001]; + } +} +@end + +TKBackgroundLoop *backgroundLoop = nil; + + #pragma mark TKMenu /* @@ -395,6 +454,12 @@ static int ModifierCharWidth(Tk_Font tkfont); #ifdef TK_MAC_DEBUG_NOTIFICATIONS TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification); #endif + if (backgroundLoop) { + [backgroundLoop cancel]; + [backgroundLoop release]; + } + backgroundLoop = [[TKBackgroundLoop alloc] init]; + [backgroundLoop start]; //TkMacOSXClearMenubarActive(); //TkMacOSXPreprocessMenu(); } @@ -404,6 +469,11 @@ static int ModifierCharWidth(Tk_Font tkfont); #ifdef TK_MAC_DEBUG_NOTIFICATIONS TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification); #endif + if (backgroundLoop) { + [backgroundLoop cancel]; + [backgroundLoop release]; + backgroundLoop = nil; + } if (!inPostMenu) { TkMacOSXClearMenubarActive(); } diff --git a/macosx/tkMacOSXNotify.c b/macosx/tkMacOSXNotify.c index 83b4695..5163e21 100644 --- a/macosx/tkMacOSXNotify.c +++ b/macosx/tkMacOSXNotify.c @@ -176,6 +176,7 @@ void DebugPrintQueue(void) } } #endif + [super sendEvent:theEvent]; [NSApp tkCheckPasteboard]; @@ -185,6 +186,13 @@ void DebugPrintQueue(void) #endif } + +- (void) _runBackgroundLoop +{ + while(Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_TIMER_EVENTS|TCL_DONT_WAIT)){ + TkMacOSXDrawAllViews(NULL); + } +} @end #pragma mark - @@ -203,15 +211,13 @@ void DebugPrintQueue(void) *---------------------------------------------------------------------- */ -NSString * +static NSString * GetRunLoopMode(NSModalSession modalSession) { NSString *runLoopMode = nil; if (modalSession) { runLoopMode = NSModalPanelRunLoopMode; - } else if (TkMacOSXGetCapture()) { - runLoopMode = NSEventTrackingRunLoopMode; } if (!runLoopMode) { runLoopMode = [[NSRunLoop currentRunLoop] currentMode]; diff --git a/macosx/tkMacOSXPrivate.h b/macosx/tkMacOSXPrivate.h index 9005d82..6109024 100644 --- a/macosx/tkMacOSXPrivate.h +++ b/macosx/tkMacOSXPrivate.h @@ -304,8 +304,7 @@ MODULE_SCOPE void TkMacOSXDrawSolidBorder(Tk_Window tkwin, GC gc, int inset, int thickness); MODULE_SCOPE int TkMacOSXServices_Init(Tcl_Interp *interp); MODULE_SCOPE int TkMacOSXRegisterServiceWidgetObjCmd(ClientData clientData, - Tcl_Interp *interp, int objc, - Tcl_Obj *const objv[]); + Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE unsigned TkMacOSXAddVirtual(unsigned int keycode); MODULE_SCOPE void TkMacOSXWinNSBounds(TkWindow *winPtr, NSView *view, NSRect *bounds); @@ -341,6 +340,8 @@ VISIBILITY_HIDDEN NSArray *_defaultApplicationMenuItems, *_defaultWindowsMenuItems; NSArray *_defaultHelpMenuItems, *_defaultFileMenuItems; NSAutoreleasePool *_mainPool; + NSThread *_backgoundLoop; + #ifdef __i386__ /* The Objective C runtime used on i386 requires this. */ int _poolLock; @@ -348,6 +349,7 @@ VISIBILITY_HIDDEN Bool _isDrawing; Bool _needsToDraw; #endif + } @property int poolLock; @property int macOSVersion; @@ -378,6 +380,7 @@ VISIBILITY_HIDDEN @interface NSApplication(TKNotify) /* We need to declare this hidden method. */ - (void) _modalSession: (NSModalSession) session sendEvent: (NSEvent *) event; +- (void) _runBackgroundLoop; @end @interface TKApplication(TKEvent) - (NSEvent *)tkProcessEvent:(NSEvent *)theEvent; |