summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin Walzer <kw@codebykevin.com>2015-12-15 02:53:13 (GMT)
committerKevin Walzer <kw@codebykevin.com>2015-12-15 02:53:13 (GMT)
commitf4326da1c63ed8d0421a5d315255f2b2c402328e (patch)
treecdfc6c636aeca07dd6b45ac7cff0b9b530774284
parent47c6cf375321a9f00b0446e3753d6f9d8c357cd8 (diff)
downloadtk-f4326da1c63ed8d0421a5d315255f2b2c402328e.zip
tk-f4326da1c63ed8d0421a5d315255f2b2c402328e.tar.gz
tk-f4326da1c63ed8d0421a5d315255f2b2c402328e.tar.bz2
Fix for some redraw issues on Tk-Cocoa on OS X 10.11; further refinement of memory management; thanks to Marc Culler for patches
-rw-r--r--macosx/README61
-rw-r--r--macosx/tkMacOSXDraw.c10
-rw-r--r--macosx/tkMacOSXEvent.c5
-rw-r--r--macosx/tkMacOSXFont.c5
-rw-r--r--macosx/tkMacOSXInit.c67
-rw-r--r--macosx/tkMacOSXKeyEvent.c2
-rw-r--r--macosx/tkMacOSXMenu.c27
-rw-r--r--macosx/tkMacOSXNotify.c68
-rw-r--r--macosx/tkMacOSXPrivate.h3
-rw-r--r--macosx/tkMacOSXSubwindows.c11
-rw-r--r--macosx/tkMacOSXWindowEvent.c34
-rw-r--r--macosx/tkMacOSXWm.c71
-rw-r--r--macosx/tkMacOSXXStubs.c3
13 files changed, 225 insertions, 142 deletions
diff --git a/macosx/README b/macosx/README
index b992a2e..7b17fb8 100644
--- a/macosx/README
+++ b/macosx/README
@@ -386,3 +386,64 @@ make overrides to the tk/macosx GNUmakefile, e.g.
sudo make -C tk${ver}/macosx install \
TCL_FRAMEWORK_DIR=$HOME/Library/Frameworks TCLSH_DIR=$HOME/usr/bin
The Makefile variables TCL_FRAMEWORK_DIR and TCLSH_DIR were added with Tk 8.4.3.
+
+4. About the event loop in Tk for Mac OSX
+-----------------------------------------
+
+The main program in a typical OSX application looks like this (see *)
+
+ void NSApplicationMain(int argc, char *argv[]) {
+ [NSApplication sharedApplication];
+ [NSBundle loadNibNamed:@"myMain" owner:NSApp];
+ [NSApp run];
+ }
+
+The run method implements the event loop for the application. There
+are three key steps in the run method. First it calls
+[NSApp finishLaunching], which creates the bouncing application icon
+and does other mysterious things. Second it creates an
+NSAutoreleasePool. Third, it starts an event loop which drains the
+NSAutoreleasePool every time the queue is empty, and replaces the
+drained pool with a new one. This third step is essential to
+preventing memory leaks, since the internal methods of Appkit objects
+all assume that an autorelease pool is in scope and will be drained
+when the event processing cycle ends.
+
+Mac OSX Tk does not call the [NSApp run] method at all. Instead it
+uses the event loop built in to Tk. So we must take care to replicate
+the important features of the method ourselves. Here is how this
+works in outline.
+
+We add a private NSAUtoreleasePool* property to our subclass of
+NSApplication. (The subclass is called TKApplication but can be
+referenced with the global variable NSApp). The TkpInit
+function calls [NSApp _setup] which initializes this property by
+creating an NSAutoreleasePool. A bit later on, TkpInit calls
+[NSAPP _setupEventLoop] which in turn calls the
+[NSApp finishLaunching] method.
+
+Each time that Tcl processes an event in its queue, it calls a
+platform specific function which, in the case of Mac OSX, is named
+TkMacOSXEventsCheckProc. In the unix implementations of Tk, including
+the Mac OSX version, this function collects events from an "event
+source", and transfers them to the Tcl event queue. In Mac OSX the
+event source is the NSApplication event queue. Each NSEvent is
+converted to a Tcl event which is added to the Tcl event queue. The
+NSEvent is also passed to [NSApp sendevent], which sends the event on
+to the application's NSWindows, which send it to their NSViews, etc.
+Since the CheckProc function gets called for every Tk event, it is an
+appropriate place to drain the main NSAutoreleasePool and replace it
+with a new pool. This is done by calling the method
+[NSApp _resetAutoreleasePool], where _resetAutoreleasePool is a method
+which we define for the subclass TKApplication.
+
+One minor caveat is that there are several steps of the Tk
+initialization which precede the call to TkpInit. Notably, the font
+package is initialized first. Since there is no NSAUtoreleasePool in
+scope prior to calling TkpInit, the functions called in these
+preliminary stages need to create and drain their own
+NSAutoreleasePools whenever they call methods of Appkit objects
+(e.g. NSFont).
+
+* https://developer.apple.com/library/mac/documentation/Cocoa/\
+Reference/ApplicationKit/Classes/NSApplication_Class
diff --git a/macosx/tkMacOSXDraw.c b/macosx/tkMacOSXDraw.c
index b3c2499..f376591 100644
--- a/macosx/tkMacOSXDraw.c
+++ b/macosx/tkMacOSXDraw.c
@@ -138,7 +138,6 @@ BitmapRepFromDrawableRect(
CGImageRef cg_image=NULL, sub_cg_image=NULL;
NSBitmapImageRep *bitmap_rep=NULL;
NSView *view=NULL;
- NSAutoreleasePool *pool = [NSAutoreleasePool new];
if ( mac_drawable->flags & TK_IS_PIXMAP ) {
/*
This means that the MacDrawable is functioning as a Tk Pixmap, so its view
@@ -175,7 +174,6 @@ BitmapRepFromDrawableRect(
} else {
TkMacOSXDbgMsg("Invalid source drawable");
}
- [pool drain];
return bitmap_rep;
}
@@ -1636,7 +1634,6 @@ TkMacOSXSetupDrawingContext(
int dontDraw = 0, isWin = 0;
TkMacOSXDrawingContext dc = {};
CGRect clipBounds;
- NSAutoreleasePool *pool = [NSAutoreleasePool new];
dc.clipRgn = TkMacOSXGetClipRgn(d);
if (!dontDraw) {
@@ -1767,7 +1764,6 @@ end:
dc.clipRgn = NULL;
}
*dcPtr = dc;
- [pool drain];
return !dontDraw;
}
@@ -1791,7 +1787,6 @@ void
TkMacOSXRestoreDrawingContext(
TkMacOSXDrawingContext *dcPtr)
{
- NSAutoreleasePool *pool = [NSAutoreleasePool new];
if (dcPtr->context) {
CGContextSynchronize(dcPtr->context);
[[dcPtr->view window] setViewsNeedDisplay:YES];
@@ -1808,7 +1803,6 @@ TkMacOSXRestoreDrawingContext(
#ifdef TK_MAC_DEBUG
bzero(dcPtr, sizeof(TkMacOSXDrawingContext));
#endif /* TK_MAC_DEBUG */
- [pool drain];
}
/*
@@ -1834,7 +1828,6 @@ TkMacOSXGetClipRgn(
{
MacDrawable *macDraw = (MacDrawable *) drawable;
HIShapeRef clipRgn = NULL;
- NSAutoreleasePool *pool = [NSAutoreleasePool new];
if (macDraw->winPtr && macDraw->flags & TK_CLIP_INVALID) {
TkMacOSXUpdateClipRgn(macDraw->winPtr);
@@ -1860,7 +1853,6 @@ TkMacOSXGetClipRgn(
} else if (macDraw->visRgn) {
clipRgn = HIShapeCreateCopy(macDraw->visRgn);
}
- [pool drain];
return clipRgn;
}
@@ -1913,7 +1905,6 @@ TkpClipDrawableToRect(
{
MacDrawable *macDraw = (MacDrawable *) d;
NSView *view = TkMacOSXDrawableView(macDraw);
- NSAutoreleasePool *pool = [NSAutoreleasePool new];
if (macDraw->drawRgn) {
CFRelease(macDraw->drawRgn);
@@ -1947,7 +1938,6 @@ TkpClipDrawableToRect(
macDraw->flags &= ~TK_FOCUSED_VIEW;
}
}
- [pool drain];
}
/*
diff --git a/macosx/tkMacOSXEvent.c b/macosx/tkMacOSXEvent.c
index 6685b80..3c59ac3 100644
--- a/macosx/tkMacOSXEvent.c
+++ b/macosx/tkMacOSXEvent.c
@@ -126,10 +126,6 @@ enum {
MODULE_SCOPE void
TkMacOSXFlushWindows(void)
{
- /* This can be called from outside the Appkit event loop,
- * so it needs its own AutoreleasePool.
- */
- NSAutoreleasePool *pool = [NSAutoreleasePool new];
NSArray *macWindows = [NSApp orderedWindows];
for (NSWindow *w in macWindows) {
@@ -137,7 +133,6 @@ TkMacOSXFlushWindows(void)
[w flushWindow];
}
}
- [pool drain];
}
/*
diff --git a/macosx/tkMacOSXFont.c b/macosx/tkMacOSXFont.c
index f1e01d2..f329071 100644
--- a/macosx/tkMacOSXFont.c
+++ b/macosx/tkMacOSXFont.c
@@ -210,6 +210,7 @@ FindNSFont(
nsFont = [fm convertFont:nsFont toSize:size];
nsFont = [fm convertFont:nsFont toHaveTrait:traits];
}
+ [nsFont retain];
#undef defaultFont
return nsFont;
}
@@ -371,6 +372,7 @@ TkpFontPkgInit(
NSFont *nsFont;
TkFontAttributes fa;
NSMutableCharacterSet *cs;
+ /* Since we called before TkpInit, we need our own autorelease pool. */
NSAutoreleasePool *pool = [NSAutoreleasePool new];
/* force this for now */
@@ -530,7 +532,7 @@ TkpGetFontFromAttributes(
nsFont = FindNSFont(faPtr->family, traits, weight, points, 1);
}
if (!nsFont) {
- Tcl_Panic("Could not deternmine NSFont from TkFontAttributes");
+ Tcl_Panic("Could not determine NSFont from TkFontAttributes");
}
if (tkFontPtr == NULL) {
fontPtr = (MacFont *) ckalloc(sizeof(MacFont));
@@ -675,7 +677,6 @@ TkpGetFontAttrsForChar(
{
MacFont *fontPtr = (MacFont *) tkfont;
NSFont *nsFont = fontPtr->nsFont;
-
*faPtr = fontPtr->font.fa;
if (nsFont && ![[nsFont coveredCharacterSet] characterIsMember:c]) {
UTF16Char ch = c;
diff --git a/macosx/tkMacOSXInit.c b/macosx/tkMacOSXInit.c
index 8e5479e..cb97f47 100644
--- a/macosx/tkMacOSXInit.c
+++ b/macosx/tkMacOSXInit.c
@@ -59,9 +59,19 @@ static void keyboardChanged(CFNotificationCenterRef center, void *observer, CFSt
@end
@implementation TKApplication
+#ifndef __clang__
+@synthesize poolProtected = _poolProtected;
+#endif
@end
@implementation TKApplication(TKInit)
+- (void) _resetAutoreleasePool
+{
+ if(![self poolProtected]) {
+ [_mainPool drain];
+ _mainPool = [NSAutoreleasePool new];
+ }
+}
#ifdef TK_MAC_DEBUG_NOTIFICATIONS
- (void)_postedNotification:(NSNotification *)notification {
TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification);
@@ -82,14 +92,17 @@ static void keyboardChanged(CFNotificationCenterRef center, void *observer, CFSt
#endif
}
- (void)_setupEventLoop {
-
- /*Remove private API calls here.*/
+ NSAutoreleasePool *pool = [NSAutoreleasePool new];
[self finishLaunching];
[self setWindowsNeedUpdate:YES];
+ [pool drain];
}
- (void)_setup:(Tcl_Interp *)interp {
_eventInterp = interp;
+ _mainPool = nil;
+ [NSApp setPoolProtected:NO];
_defaultMainMenu = nil;
+ NSAutoreleasePool *pool = [NSAutoreleasePool new];
[self _setupMenus];
[self setDelegate:self];
#ifdef TK_MAC_DEBUG_NOTIFICATIONS
@@ -98,9 +111,11 @@ static void keyboardChanged(CFNotificationCenterRef center, void *observer, CFSt
#endif
[self _setupWindowNotifications];
[self _setupApplicationNotifications];
+ [pool drain];
}
- (NSString *)tkFrameworkImagePath:(NSString*)image {
NSString *path = nil;
+ NSAutoreleasePool *pool = [NSAutoreleasePool new];
if (tkLibPath[0] != '\0') {
path = [[NSBundle bundleWithPath:[[NSString stringWithUTF8String:
tkLibPath] stringByAppendingString:@"/../.."]]
@@ -131,6 +146,8 @@ static void keyboardChanged(CFNotificationCenterRef center, void *observer, CFSt
}
}
#endif
+ [path retain];
+ [pool drain];
return path;
}
@end
@@ -157,6 +174,7 @@ static void
SetApplicationIcon(
ClientData clientData)
{
+ NSAutoreleasePool *pool = [NSAutoreleasePool new];
NSString *path = [NSApp tkFrameworkImagePath:@"Tk.icns"];
if (path) {
NSImage *image = [[NSImage alloc] initWithContentsOfFile:path];
@@ -165,6 +183,7 @@ SetApplicationIcon(
[image release];
}
}
+ [pool drain];
}
/*
@@ -242,16 +261,19 @@ TkpInit(
}
#endif
- NSAutoreleasePool *pool = [NSAutoreleasePool new];
- [[NSUserDefaults standardUserDefaults] registerDefaults:
- [NSDictionary dictionaryWithObjectsAndKeys:
- [NSNumber numberWithBool:YES],
- @"_NSCanWrapButtonTitles",
- [NSNumber numberWithInt:-1],
- @"NSStringDrawingTypesetterBehavior",
- nil]];
- [TKApplication sharedApplication];
- [NSApp _setup:interp];
+ {
+ NSAutoreleasePool *pool = [NSAutoreleasePool new];
+ [[NSUserDefaults standardUserDefaults] registerDefaults:
+ [NSDictionary dictionaryWithObjectsAndKeys:
+ [NSNumber numberWithBool:YES],
+ @"_NSCanWrapButtonTitles",
+ [NSNumber numberWithInt:-1],
+ @"NSStringDrawingTypesetterBehavior",
+ nil]];
+ [TKApplication sharedApplication];
+ [pool drain];
+ [NSApp _setup:interp];
+ }
/* Check whether we are a bundled executable: */
bundleRef = CFBundleGetMainBundle();
@@ -308,12 +330,15 @@ TkpInit(
Tcl_DoWhenIdle(SetApplicationIcon, NULL);
}
- [NSApp _setupEventLoop];
- TkMacOSXInitAppleEvents(interp);
- TkMacOSXUseAntialiasedText(interp, -1);
- TkMacOSXInitCGDrawing(interp, TRUE, 0);
- [pool drain];
-
+ {
+ NSAutoreleasePool *pool = [NSAutoreleasePool new];
+ [NSApp _setupEventLoop];
+ TkMacOSXInitAppleEvents(interp);
+ TkMacOSXUseAntialiasedText(interp, -1);
+ TkMacOSXInitCGDrawing(interp, TRUE, 0);
+ [pool drain];
+ }
+
/*
* FIXME: Close stdin & stdout for remote debugging otherwise we will
* fight with gdb for stdin & stdout
@@ -469,9 +494,8 @@ TkpDisplayWarning(
MODULE_SCOPE void
TkMacOSXDefaultStartupScript(void)
{
- CFBundleRef bundleRef;
-
- bundleRef = CFBundleGetMainBundle();
+ NSAutoreleasePool *pool = [NSAutoreleasePool new];
+ CFBundleRef bundleRef = CFBundleGetMainBundle();
if (bundleRef != NULL) {
CFURLRef appMainURL = CFBundleCopyResourceURL(bundleRef,
@@ -495,6 +519,7 @@ TkMacOSXDefaultStartupScript(void)
CFRelease(appMainURL);
}
}
+ [pool drain];
}
/*
diff --git a/macosx/tkMacOSXKeyEvent.c b/macosx/tkMacOSXKeyEvent.c
index d21389b..da74e60 100644
--- a/macosx/tkMacOSXKeyEvent.c
+++ b/macosx/tkMacOSXKeyEvent.c
@@ -328,7 +328,7 @@ static unsigned isFunctionKey(unsigned int code);
pt.y = caret_y;
pt = [self convertPoint: pt toView: nil];
- pt = [[self window] convertBaseToScreen: pt];
+ pt = [[self window] convertPointToScreen: pt];
pt.y -= caret_height;
rect.origin = pt;
diff --git a/macosx/tkMacOSXMenu.c b/macosx/tkMacOSXMenu.c
index 3f4b3b5..8f20447 100644
--- a/macosx/tkMacOSXMenu.c
+++ b/macosx/tkMacOSXMenu.c
@@ -258,10 +258,10 @@ static int ModifierCharWidth(Tk_Font tkfont);
if (menuPtr && mePtr) {
Tcl_Interp *interp = menuPtr->interp;
- /*Add time for errors to fire if necessary. This is sub-optimal but avoids issues with Tcl/Cocoa event loop integration.*/
+ /*Add time for errors to fire if necessary. This is sub-optimal
+ *but avoids issues with Tcl/Cocoa event loop integration.
+ */
Tcl_Sleep(100);
-
- NSAutoreleasePool *pool = [NSAutoreleasePool new];
Tcl_Preserve(interp);
Tcl_Preserve(menuPtr);
@@ -274,7 +274,6 @@ static int ModifierCharWidth(Tk_Font tkfont);
}
Tcl_Release(menuPtr);
Tcl_Release(interp);
- [pool drain];
}
}
}
@@ -377,13 +376,6 @@ static int ModifierCharWidth(Tk_Font tkfont);
@implementation TKApplication(TKMenu)
-- (void) safeSetMainMenu: (NSMenu *) menu
-{
- NSAutoreleasePool* pool = [NSAutoreleasePool new];
- [self setMainMenu: menu];
- [pool drain];
-}
-
- (void) menuBeginTracking: (NSNotification *) notification
{
#ifdef TK_MAC_DEBUG_NOTIFICATIONS
@@ -420,7 +412,7 @@ static int ModifierCharWidth(Tk_Font tkfont);
if (!mePtr || !(mePtr->entryFlags & ENTRY_APPLE_MENU)) {
applicationMenuItem = [NSMenuItem itemWithSubmenu:
- [[_defaultApplicationMenu copy] autorelease]];
+ [_defaultApplicationMenu copy]];
[menu insertItem:applicationMenuItem atIndex:0];
}
[menu setSpecial:tkMainMenu];
@@ -428,7 +420,7 @@ static int ModifierCharWidth(Tk_Font tkfont);
applicationMenu = (TKMenu *)[applicationMenuItem submenu];
if (![applicationMenu isSpecial:tkApplicationMenu]) {
for (NSMenuItem *item in _defaultApplicationMenuItems) {
- [applicationMenu addItem:[[item copy] autorelease]];
+ [applicationMenu addItem:[item copy]];
}
[applicationMenu setSpecial:tkApplicationMenu];
}
@@ -438,15 +430,13 @@ static int ModifierCharWidth(Tk_Font tkfont);
for (NSMenuItem *item in itemArray) {
TkMenuEntry *mePtr = (TkMenuEntry *)[item tag];
TKMenu *submenu = (TKMenu *)[item submenu];
-
if (mePtr && submenu) {
if ((mePtr->entryFlags & ENTRY_WINDOWS_MENU) &&
![submenu isSpecial:tkWindowsMenu]) {
NSInteger index = 0;
for (NSMenuItem *i in _defaultWindowsMenuItems) {
- [submenu insertItem:[[i copy] autorelease] atIndex:
- index++];
+ [submenu insertItem:[i copy] atIndex:index++];
}
[self setWindowsMenu:submenu];
[submenu setSpecial:tkWindowsMenu];
@@ -455,8 +445,7 @@ static int ModifierCharWidth(Tk_Font tkfont);
NSInteger index = 0;
for (NSMenuItem *i in _defaultHelpMenuItems) {
- [submenu insertItem:[[i copy] autorelease] atIndex:
- index++];
+ [submenu insertItem:[i copy] atIndex:index++];
}
[submenu setSpecial:tkHelpMenu];
}
@@ -475,7 +464,7 @@ static int ModifierCharWidth(Tk_Font tkfont);
[servicesMenuItem setSubmenu:_servicesMenu];
}
[self setAppleMenu:applicationMenu];
- [self safeSetMainMenu:menu];
+ [self setMainMenu:menu];
}
@end
diff --git a/macosx/tkMacOSXNotify.c b/macosx/tkMacOSXNotify.c
index c703297..0737d74 100644
--- a/macosx/tkMacOSXNotify.c
+++ b/macosx/tkMacOSXNotify.c
@@ -49,7 +49,7 @@ static void TkMacOSXEventsCheckProc(ClientData clientData, int flags);
@end
@implementation TKApplication(TKNotify)
-/* Call super then redisplay all of our windows. */
+/* 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 {
@@ -57,9 +57,9 @@ static void TkMacOSXEventsCheckProc(ClientData clientData, int flags);
untilDate:expiration
inMode:mode
dequeue:deqFlag];
- NSAutoreleasePool *pool = [NSAutoreleasePool new];
+ /* Retain this event for later use. Must be released.*/
+ [event retain];
[NSApp makeWindowsPerform:@selector(tkDisplayIfNeeded) inOrder:NO];
- [pool drain];
return event;
}
@@ -67,10 +67,8 @@ static void TkMacOSXEventsCheckProc(ClientData clientData, int flags);
* Call super then check the pasteboard.
*/
- (void)sendEvent:(NSEvent *)theEvent {
- NSAutoreleasePool *pool = [NSAutoreleasePool new];
[super sendEvent:theEvent];
[NSApp tkCheckPasteboard];
- [pool drain];
}
@end
@@ -191,7 +189,7 @@ TkMacOSXNotifyExitHandler(
* TkMacOSXEventsSetupProc --
*
* This procedure implements the setup part of the MacOSX event
- * source. It is invoked by Tcl_DoOneEvent before calling
+ * 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.
@@ -200,7 +198,7 @@ TkMacOSXNotifyExitHandler(
* 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.
*
@@ -212,19 +210,21 @@ TkMacOSXEventsSetupProc(
ClientData clientData,
int flags)
{
- if (flags & TCL_WINDOW_EVENTS &&
- ![[NSRunLoop currentRunLoop] currentMode]) {
+ NSString *runloopMode = [[NSRunLoop currentRunLoop] currentMode];
+ /* runloopMode will be nil if we are in the Tcl event loop. */
+ if (flags & TCL_WINDOW_EVENTS && !runloopMode) {
static Tcl_Time zeroBlockTime = { 0, 0 };
- NSAutoreleasePool *pool = [NSAutoreleasePool new];
- /* Call this with dequeue=NO -- just checking if the queue is empty. */
+ /* 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 && currentEvent.type > 0) {
- Tcl_SetMaxBlockTime(&zeroBlockTime);
+ untilDate:[NSDate distantPast]
+ inMode:GetRunLoopMode(TkMacOSXGetModalSession())
+ dequeue:NO];
+ if (currentEvent) {
+ if (currentEvent.type > 0) {
+ Tcl_SetMaxBlockTime(&zeroBlockTime);
+ }
+ [currentEvent release];
}
- [pool drain];
}
}
@@ -251,13 +251,14 @@ TkMacOSXEventsCheckProc(
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]
@@ -272,25 +273,26 @@ TkMacOSXEventsCheckProc(
untilDate:[NSDate distantPast]
inMode:GetRunLoopMode(modalSession)
dequeue:YES];
- if (!currentEvent) {
- break; /* No events are available. */
- }
- NSAutoreleasePool *pool = [NSAutoreleasePool new];
- /* Generate Xevents. */
- int oldServiceMode = Tcl_SetServiceMode(TCL_SERVICE_ALL);
- NSEvent *processedEvent = [NSApp tkProcessEvent:currentEvent];
- Tcl_SetServiceMode(oldServiceMode);
- if (processedEvent) { /* Should always be non-NULL. */
+ if (currentEvent) {
+ [NSApp _resetAutoreleasePool];
+ /* 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);
+ TKLog(@" event: %@", currentEvent);
#endif
- if (modalSession) {
- [NSApp _modalSession:modalSession sendEvent:currentEvent];
- } else {
- [NSApp sendEvent:currentEvent];
+ if (modalSession) {
+ [NSApp _modalSession:modalSession sendEvent:currentEvent];
+ } else {
+ [NSApp sendEvent:currentEvent];
+ }
}
+ [currentEvent release];
+ } else {
+ break;
}
- [pool drain];
} while (1);
}
}
diff --git a/macosx/tkMacOSXPrivate.h b/macosx/tkMacOSXPrivate.h
index 4891b32..e635020 100644
--- a/macosx/tkMacOSXPrivate.h
+++ b/macosx/tkMacOSXPrivate.h
@@ -273,10 +273,13 @@ VISIBILITY_HIDDEN
NSArray *_defaultApplicationMenuItems, *_defaultWindowsMenuItems;
NSArray *_defaultHelpMenuItems;
NSWindow *_windowWithMouse;
+ NSAutoreleasePool *_mainPool;
}
+@property BOOL poolProtected;
@end
@interface TKApplication(TKInit)
- (NSString *)tkFrameworkImagePath:(NSString*)image;
+- (void)_resetAutoreleasePool;
@end
@interface TKApplication(TKEvent)
- (NSEvent *)tkProcessEvent:(NSEvent *)theEvent;
diff --git a/macosx/tkMacOSXSubwindows.c b/macosx/tkMacOSXSubwindows.c
index b985e5d..c1f16f3 100644
--- a/macosx/tkMacOSXSubwindows.c
+++ b/macosx/tkMacOSXSubwindows.c
@@ -131,11 +131,6 @@ XMapWindow(
{
MacDrawable *macWin = (MacDrawable *) window;
XEvent event;
- /*
- * This function can be called from outside the AppKit event
- * loop, so it needs its own AutoreleasePool.
- */
- NSAutoreleasePool* pool = [NSAutoreleasePool new];
/*
* Under certain situations it's possible for this function to be called
@@ -158,6 +153,7 @@ XMapWindow(
if ( [win canBecomeKeyWindow] ) {
[win makeKeyAndOrderFront:NSApp];
}
+ /* Why do we need this? (It is used by Carbon)*/
[win windowRef];
TkMacOSXApplyWindowAttributes(macWin->winPtr, win);
}
@@ -194,7 +190,6 @@ XMapWindow(
event.xvisibility.type = VisibilityNotify;
event.xvisibility.state = VisibilityUnobscured;
NotifyVisibility(macWin->winPtr, &event);
- [pool drain];
}
/*
@@ -318,7 +313,6 @@ XResizeWindow(
unsigned int height)
{
MacDrawable *macWin = (MacDrawable *) window;
- NSAutoreleasePool *pool= [NSAutoreleasePool new];
display->request++;
if (Tk_IsTopLevel(macWin->winPtr) && !Tk_IsEmbedded(macWin->winPtr)) {
NSWindow *w = macWin->winPtr->wmInfoPtr->window;
@@ -333,7 +327,6 @@ XResizeWindow(
} else {
MoveResizeWindow(macWin);
}
- [pool drain];
}
/*
@@ -366,7 +359,6 @@ XMoveResizeWindow(
display->request++;
if (Tk_IsTopLevel(macWin->winPtr) && !Tk_IsEmbedded(macWin->winPtr)) {
NSWindow *w = macWin->winPtr->wmInfoPtr->window;
-
if (w) {
NSRect r = NSMakeRect(x + macWin->winPtr->wmInfoPtr->xInParent,
tkMacOSXZeroScreenHeight - (y +
@@ -407,7 +399,6 @@ XMoveWindow(
display->request++;
if (Tk_IsTopLevel(macWin->winPtr) && !Tk_IsEmbedded(macWin->winPtr)) {
NSWindow *w = macWin->winPtr->wmInfoPtr->window;
-
if (w) {
[w setFrameTopLeftPoint:NSMakePoint(x, tkMacOSXZeroScreenHeight - y)];
}
diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c
index 0b32e7e..91cc348 100644
--- a/macosx/tkMacOSXWindowEvent.c
+++ b/macosx/tkMacOSXWindowEvent.c
@@ -808,7 +808,7 @@ ConfigureRestrictProc(
{
const NSRect *rectsBeingDrawn;
NSInteger rectsBeingDrawnCount;
-
+
[self getRectsBeingDrawn:&rectsBeingDrawn count:&rectsBeingDrawnCount];
#ifdef TK_MAC_DEBUG_DRAWING
@@ -844,7 +844,8 @@ ConfigureRestrictProc(
-(void) setFrameSize: (NSSize)newsize
{
- if ( [self inLiveResize] ) {
+ [super setFrameSize: newsize];
+ if ([self inLiveResize]) {
NSWindow *w = [self window];
TkWindow *winPtr = TkMacOSXGetTkWindow(w);
Tk_Window tkwin = (Tk_Window) winPtr;
@@ -853,17 +854,29 @@ ConfigureRestrictProc(
ClientData oldArg;
Tk_RestrictProc *oldProc;
- /* Resize the NSView */
- [super setFrameSize: newsize];
-
- /* Disable drawing until the window has been completely configured.*/
+ /* This can be called from outside the Tk event loop.
+ * Since it calls Tcl_DoOneEvent, we need to make sure we
+ * don't clobber the AutoreleasePool set up by the caller.
+ */
+ [NSApp setPoolProtected:YES];
+
+ /*
+ * Try to prevent flickers and flashes.
+ *
+ * This stops the flickers, but on OSX 10.11 flashes still occur when
+ * the width of the window is 16, 32, 48, 64, 80, 96, 112, 256, 512,
+ * 768, ...
+ */
+ [w disableFlushWindow];
+
+ /* Disable Tk drawing until the window has been completely configured.*/
TkMacOSXSetDrawingEnabled(winPtr, 0);
/* Generate and handle a ConfigureNotify event for the new size.*/
TkGenWMConfigureEvent(tkwin, Tk_X(tkwin), Tk_Y(tkwin), width, height,
TK_SIZE_CHANGED | TK_MACOSX_HANDLE_EVENT_IMMEDIATELY);
oldProc = Tk_RestrictEvents(ConfigureRestrictProc, NULL, &oldArg);
- while ( Tk_DoOneEvent(TK_X_EVENTS|TK_DONT_WAIT) ) {}
+ while (Tk_DoOneEvent(TK_X_EVENTS|TK_DONT_WAIT)) {}
Tk_RestrictEvents(oldProc, oldArg, &oldArg);
/* Now that Tk has configured all subwindows we can create the clip regions. */
@@ -875,9 +888,10 @@ ConfigureRestrictProc(
HIRect bounds = NSRectToCGRect([self bounds]);
HIShapeRef shape = HIShapeCreateWithRect(&bounds);
[self generateExposeEvents: shape];
- while ( Tk_DoOneEvent(TK_ALL_EVENTS|TK_DONT_WAIT) ) {}
- } else {
- [super setFrameSize: newsize];
+ while (Tk_DoOneEvent(TK_ALL_EVENTS|TK_DONT_WAIT)) {}
+ [w enableFlushWindow];
+ [w flushWindowIfNeeded];
+ [NSApp setPoolProtected:NO];
}
}
diff --git a/macosx/tkMacOSXWm.c b/macosx/tkMacOSXWm.c
index 4ce2206..50cac20 100644
--- a/macosx/tkMacOSXWm.c
+++ b/macosx/tkMacOSXWm.c
@@ -408,18 +408,23 @@ static void RemapWindows(TkWindow *winPtr,
if (title == nil) {
title = "unnamed window";
}
- printf("Retained <%s>. Count is: %lu\n", title, [self retainCount]);
+ if (DEBUG_ZOMBIES > 1){
+ printf("Retained <%s>. Count is: %lu\n", title, [self retainCount]);
+ }
return result;
}
- (id) autorelease
{
+ static int xcount = 0;
id result = [super autorelease];
const char *title = [[self title] UTF8String];
if (title == nil) {
title = "unnamed window";
}
- printf("Autoreleased <%s>. Count is %lu\n", title, [self retainCount]);
+ if (DEBUG_ZOMBIES > 1){
+ printf("Autoreleased <%s>. Count is %lu\n", title, [self retainCount]);
+ }
return result;
}
@@ -428,9 +433,24 @@ static void RemapWindows(TkWindow *winPtr,
if (title == nil) {
title = "unnamed window";
}
- printf("Releasing <%s>. Count is %lu\n", title, [self retainCount]);
+ if (DEBUG_ZOMBIES > 1){
+ printf("Releasing <%s>. Count is %lu\n", title, [self retainCount]);
+ }
[super release];
}
+
+- (void) dealloc {
+ const char *title = [[self title] UTF8String];
+ if (title == nil) {
+ title = "unnamed window";
+ }
+ if (DEBUG_ZOMBIES > 0){
+ printf(">>>> Freeing <%s>. Count is %lu\n", title, [self retainCount]);
+ }
+ [super dealloc];
+}
+
+
#endif
@end
@@ -544,7 +564,6 @@ FrontWindowAtPoint(
int x, int y)
{
NSPoint p = NSMakePoint(x, tkMacOSXZeroScreenHeight - y);
- NSAutoreleasePool *pool = [NSAutoreleasePool new];
NSArray *windows = [NSApp orderedWindows];
TkWindow *front = NULL;
@@ -554,7 +573,6 @@ FrontWindowAtPoint(
break;
}
}
- [pool drain];
return front;
}
@@ -860,7 +878,6 @@ TkWmDeadWindow(
NSWindow *window = wmPtr->window;
if (window && !Tk_IsEmbedded(winPtr) ) {
- NSAutoreleasePool *pool = [NSAutoreleasePool new];
NSWindow *parent = [window parentWindow];
if (parent) {
[parent removeChildWindow:window];
@@ -870,29 +887,33 @@ TkWmDeadWindow(
if (winPtr->window) {
((MacDrawable *) winPtr->window)->view = nil;
}
-#if DEBUG_ZOMBIES
+#if DEBUG_ZOMBIES > 0
{
const char *title = [[window title] UTF8String];
if (title == nil) {
title = "unnamed window";
}
- printf("Closing <%s>. Count is: %lu\n", title, [window retainCount]);
+ printf(">>>> Closing <%s>. Count is: %lu\n", title, [window retainCount]);
}
#endif
[window release];
wmPtr->window = NULL;
- /* Activate the highest window left on the screen. */
- NSArray *windows = [NSApp orderedWindows];
- if ( [windows count] > 0 ) {
- NSWindow *front = [windows objectAtIndex:0];
- if ( front && [front canBecomeKeyWindow] ) {
- [front makeKeyAndOrderFront:NSApp];
- }
- }
- [pool drain];
- }
+
+ /* Activate the highest window left on the screen. */
+ NSArray *windows = [NSApp orderedWindows];
+ if ( [windows count] > 0 ) {
+ NSWindow *front = [windows objectAtIndex:0];
+ if ( front && [front canBecomeKeyWindow] ) {
+ [front makeKeyAndOrderFront:NSApp];
+ }
+ }
+#if DEBUG_ZOMBIES > 0
+ fprintf(stderr, "================= Pool dump ===================\n");
+ [NSAutoreleasePool showPools];
+#endif
ckfree((char *)wmPtr);
winPtr->wmInfoPtr = NULL;
+ }
}
/*
@@ -5478,9 +5499,6 @@ TkMacOSXMakeRealWindowExist(
* TODO: Here we should handle out of process embedding.
*/
}
-
- NSAutoreleasePool *pool = [NSAutoreleasePool new];
-
WindowClass macClass = wmPtr->macClass;
wmPtr->attributes &= (tkAlwaysValidAttributes |
macClassAttrs[macClass].validAttrs);
@@ -5514,10 +5532,10 @@ TkMacOSXMakeRealWindowExist(
NSWindow *window = [[winClass alloc] initWithContentRect:contentRect
styleMask:styleMask backing:NSBackingStoreBuffered defer:YES];
if (!window) {
- Tcl_Panic("couldn't allocate new Mac window");
+ Tcl_Panic("couldn't allocate new Mac window");
}
TKContentView *contentView = [[TKContentView alloc]
- initWithFrame:NSZeroRect];
+ initWithFrame:NSZeroRect];
[window setContentView:contentView];
[contentView release];
[window setDelegate:NSApp];
@@ -5552,7 +5570,7 @@ TkMacOSXMakeRealWindowExist(
[window setDocumentEdited:NO];
wmPtr->window = window;
- macWin->view = contentView;
+ macWin->view = window.contentView;
TkMacOSXApplyWindowAttributes(winPtr, window);
NSRect geometry = InitialWindowBounds(winPtr, window);
@@ -5561,11 +5579,8 @@ TkMacOSXMakeRealWindowExist(
geometry.origin.y = tkMacOSXZeroScreenHeight - (geometry.origin.y +
geometry.size.height);
[window setFrame:geometry display:NO];
-
TkMacOSXRegisterOffScreenWindow((Window) macWin, window);
macWin->flags |= TK_HOST_EXISTS;
-
- [pool drain];
}
/*
@@ -5958,7 +5973,6 @@ TkpChangeFocus(
if (Tk_IsTopLevel(winPtr) && !Tk_IsEmbedded(winPtr) ){
NSWindow *win = TkMacOSXDrawableWindow(winPtr->window);
- NSAutoreleasePool *pool = [NSAutoreleasePool new];
TkWmRestackToplevel(winPtr, Above, NULL);
if (force ) {
[NSApp activateIgnoringOtherApps:YES];
@@ -5966,7 +5980,6 @@ TkpChangeFocus(
if ( win && [win canBecomeKeyWindow] ) {
[win makeKeyAndOrderFront:NSApp];
}
- [pool drain];
}
/*
diff --git a/macosx/tkMacOSXXStubs.c b/macosx/tkMacOSXXStubs.c
index 4bdd1c4..a16daa8 100644
--- a/macosx/tkMacOSXXStubs.c
+++ b/macosx/tkMacOSXXStubs.c
@@ -142,6 +142,7 @@ TkpOpenDisplay(
static NSRect maxBounds = {{0, 0}, {0, 0}};
static char vendor[25] = "";
NSArray *cgVers;
+ NSAutoreleasePool *pool = [NSAutoreleasePool new];
if (gMacDisplay != NULL) {
if (strcmp(gMacDisplay->display->display_name, display_name) == 0) {
@@ -151,8 +152,6 @@ TkpOpenDisplay(
}
}
- NSAutoreleasePool *pool = [NSAutoreleasePool new];
-
display = (Display *) ckalloc(sizeof(Display));
screen = (Screen *) ckalloc(sizeof(Screen));
bzero(display, sizeof(Display));