summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--macosx/tkMacOSXMenu.c70
-rw-r--r--macosx/tkMacOSXNotify.c12
-rw-r--r--macosx/tkMacOSXPrivate.h7
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;