diff options
author | William Joye <wjoye@cfa.harvard.edu> | 2017-09-22 18:57:36 (GMT) |
---|---|---|
committer | William Joye <wjoye@cfa.harvard.edu> | 2017-09-22 18:57:36 (GMT) |
commit | 04d4f0f83ae01daebf6001f40d1261464d185809 (patch) | |
tree | d1e4a8b1c22c47d70a369143d3406c524b5c1834 /tk8.6/macosx/tkMacOSXNotify.c | |
parent | 2aff4a96fa0286d875bddec0019648e2c6431cbc (diff) | |
parent | 1005c7e630baa54e58ac331f48bf876011deb6b3 (diff) | |
download | blt-04d4f0f83ae01daebf6001f40d1261464d185809.zip blt-04d4f0f83ae01daebf6001f40d1261464d185809.tar.gz blt-04d4f0f83ae01daebf6001f40d1261464d185809.tar.bz2 |
Merge commit '1005c7e630baa54e58ac331f48bf876011deb6b3' as 'tk8.6'
Diffstat (limited to 'tk8.6/macosx/tkMacOSXNotify.c')
-rw-r--r-- | tk8.6/macosx/tkMacOSXNotify.c | 317 |
1 files changed, 317 insertions, 0 deletions
diff --git a/tk8.6/macosx/tkMacOSXNotify.c b/tk8.6/macosx/tkMacOSXNotify.c new file mode 100644 index 0000000..f14e1b8 --- /dev/null +++ b/tk8.6/macosx/tkMacOSXNotify.c @@ -0,0 +1,317 @@ +/* + * tkMacOSXNotify.c -- + * + * This file contains the implementation of a tcl event source + * for the AppKit event loop. + * + * Copyright (c) 1995-1997 Sun Microsystems, Inc. + * Copyright 2001-2009, Apple Inc. + * Copyright (c) 2005-2009 Daniel A. Steffen <das@users.sourceforge.net> + * Copyright 2015 Marc Culler. + * + * 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 "tkMacOSXEvent.h" +#include <tclInt.h> +#include <pthread.h> +#import <objc/objc-auto.h> + +/* This is not used for anything at the moment. */ +typedef struct ThreadSpecificData { + int initialized; +} ThreadSpecificData; +static Tcl_ThreadDataKey dataKey; + +#define TSD_INIT() ThreadSpecificData *tsdPtr = \ + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)) + +static void TkMacOSXNotifyExitHandler(ClientData clientData); +static void TkMacOSXEventsSetupProc(ClientData clientData, int flags); +static void TkMacOSXEventsCheckProc(ClientData clientData, int flags); + +#pragma mark TKApplication(TKNotify) + +@interface NSApplication(TKNotify) +/* We need to declare this hidden method. */ +- (void) _modalSession: (NSModalSession) session sendEvent: (NSEvent *) event; +@end + +@implementation NSWindow(TKNotify) +- (id) tkDisplayIfNeeded +{ + if (![self isAutodisplay]) { + [self displayIfNeeded]; + } + return nil; +} +@end + +@implementation TKApplication(TKNotify) +/* Display all windows each time an event is removed from the queue.*/ +- (NSEvent *) nextEventMatchingMask: (NSUInteger) mask + untilDate: (NSDate *) expiration inMode: (NSString *) mode + dequeue: (BOOL) deqFlag +{ + NSEvent *event = [super nextEventMatchingMask:mask + untilDate:expiration + inMode:mode + dequeue:deqFlag]; + /* Retain this event for later use. Must be released.*/ + [event retain]; + [NSApp makeWindowsPerform:@selector(tkDisplayIfNeeded) inOrder:NO]; + return event; +} + +/* + * Call super then check the pasteboard. + */ +- (void) sendEvent: (NSEvent *) theEvent +{ + [super sendEvent:theEvent]; + [NSApp tkCheckPasteboard]; +} +@end + +#pragma mark - + +/* + *---------------------------------------------------------------------- + * + * GetRunLoopMode -- + * + * Results: + * RunLoop mode that should be passed to -nextEventMatchingMask: + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static NSString * +GetRunLoopMode(NSModalSession modalSession) +{ + NSString *runLoopMode = nil; + + if (modalSession) { + runLoopMode = NSModalPanelRunLoopMode; + } else if (TkMacOSXGetCapture()) { + runLoopMode = NSEventTrackingRunLoopMode; + } + if (!runLoopMode) { + runLoopMode = [[NSRunLoop currentRunLoop] currentMode]; + } + if (!runLoopMode) { + runLoopMode = NSDefaultRunLoopMode; + } + return runLoopMode; +} + +/* + *---------------------------------------------------------------------- + * + * Tk_MacOSXSetupTkNotifier -- + * + * This procedure is called during Tk initialization to create + * the event source for TkAqua events. + * + * Results: + * None. + * + * Side effects: + * A new event source is created. + * + *---------------------------------------------------------------------- + */ + +void +Tk_MacOSXSetupTkNotifier(void) +{ + TSD_INIT(); + + if (!tsdPtr->initialized) { + tsdPtr->initialized = 1; + + /* + * Install TkAqua event source in main event loop thread. + */ + + if (CFRunLoopGetMain() == CFRunLoopGetCurrent()) { + if (!pthread_main_np()) { + /* + * Panic if main runloop is not on the main application thread. + */ + + Tcl_Panic("Tk_MacOSXSetupTkNotifier: %s", + "first [load] of TkAqua has to occur in the main thread!"); + } + Tcl_CreateEventSource(TkMacOSXEventsSetupProc, + TkMacOSXEventsCheckProc, + GetMainEventQueue()); + TkCreateExitHandler(TkMacOSXNotifyExitHandler, NULL); + Tcl_SetServiceMode(TCL_SERVICE_ALL); + TclMacOSXNotifierAddRunLoopMode(NSEventTrackingRunLoopMode); + TclMacOSXNotifierAddRunLoopMode(NSModalPanelRunLoopMode); + } + } +} + +/* + *---------------------------------------------------------------------- + * + * TkMacOSXNotifyExitHandler -- + * + * This function is called during finalization to clean up the + * TkMacOSXNotify module. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static void +TkMacOSXNotifyExitHandler( + ClientData clientData) /* Not used. */ +{ + TSD_INIT(); + + Tcl_DeleteEventSource(TkMacOSXEventsSetupProc, + TkMacOSXEventsCheckProc, + GetMainEventQueue()); + tsdPtr->initialized = 0; +} + +/* + *---------------------------------------------------------------------- + * + * TkMacOSXEventsSetupProc -- + * + * This procedure implements the setup part of the MacOSX event + * source. It is invoked by Tcl_DoOneEvent before calling + * TkMacOSXEventsProc to process all queued NSEvents. In our + * case, all we need to do is to set the Tcl MaxBlockTime to + * 0 before starting the loop to process all queued NSEvents. + * + * Results: + * None. + * + * Side effects: + * + * If NSEvents are queued, then the maximum block time will be set + * to 0 to ensure that control returns immediately to Tcl. + * + *---------------------------------------------------------------------- + */ + +static void +TkMacOSXEventsSetupProc( + ClientData clientData, + int flags) +{ + NSString *runloopMode = [[NSRunLoop currentRunLoop] currentMode]; + /* runloopMode will be nil if we are in the Tcl event loop. */ + if (flags & TCL_WINDOW_EVENTS && !runloopMode) { + static const Tcl_Time zeroBlockTime = { 0, 0 }; + /* Call this with dequeue=NO -- just checking if the queue is empty. */ + NSEvent *currentEvent = [NSApp nextEventMatchingMask:NSAnyEventMask + untilDate:[NSDate distantPast] + inMode:GetRunLoopMode(TkMacOSXGetModalSession()) + dequeue:NO]; + if (currentEvent) { + if (currentEvent.type > 0) { + Tcl_SetMaxBlockTime(&zeroBlockTime); + } + [currentEvent release]; + } + } +} + +/* + *---------------------------------------------------------------------- + * + * TkMacOSXEventsCheckProc -- + * + * This procedure loops through all NSEvents waiting in the + * TKApplication event queue, generating X events from them. + * + * Results: + * None. + * + * Side effects: + * NSevents are used to generate X events, which are added to the + * Tcl event queue. + * + *---------------------------------------------------------------------- + */ +static void +TkMacOSXEventsCheckProc( + ClientData clientData, + int flags) +{ + NSString *runloopMode = [[NSRunLoop currentRunLoop] currentMode]; + /* runloopMode will be nil if we are in the Tcl event loop. */ + if (flags & TCL_WINDOW_EVENTS && !runloopMode) { + NSEvent *currentEvent = nil; + NSEvent *testEvent = nil; + NSModalSession modalSession; + + do { + [NSApp _resetAutoreleasePool]; + modalSession = TkMacOSXGetModalSession(); + testEvent = [NSApp nextEventMatchingMask:NSAnyEventMask + untilDate:[NSDate distantPast] + inMode:GetRunLoopMode(modalSession) + dequeue:NO]; + /* We must not steal any events during LiveResize. */ +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 + if (testEvent && [[testEvent window] inLiveResize]) { + break; + } +#else + if (testEvent && [[[testEvent window] contentView] inLiveResize]) { + break; + } +#endif + currentEvent = [NSApp nextEventMatchingMask:NSAnyEventMask + untilDate:[NSDate distantPast] + inMode:GetRunLoopMode(modalSession) + dequeue:YES]; + if (currentEvent) { + /* Generate Xevents. */ + int oldServiceMode = Tcl_SetServiceMode(TCL_SERVICE_ALL); + NSEvent *processedEvent = [NSApp tkProcessEvent:currentEvent]; + Tcl_SetServiceMode(oldServiceMode); + if (processedEvent) { /* Should always be non-NULL. */ +#ifdef TK_MAC_DEBUG_EVENTS + TKLog(@" event: %@", currentEvent); +#endif + if (modalSession) { + [NSApp _modalSession:modalSession sendEvent:currentEvent]; + } else { + [NSApp sendEvent:currentEvent]; + } + } + [currentEvent release]; + } else { + break; + } + } while (1); + } +} + + +/* + * Local Variables: + * mode: objc + * c-basic-offset: 4 + * fill-column: 79 + * coding: utf-8 + * End: + */ |