From 9787a9f42d575fd80d370323e6fe37290f5609cd Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Sat, 21 Mar 2015 00:50:16 +0000 Subject: Remove garbage collections calls as GC is no longer supported on OS X; thanks to Marc Culler for patch --- macosx/tkMacOSXCursor.c | 5 +++-- macosx/tkMacOSXFont.c | 5 +++-- macosx/tkMacOSXInit.c | 2 -- macosx/tkMacOSXMenu.c | 24 +++++++++++++++--------- macosx/tkMacOSXNotify.c | 10 +++------- macosx/tkMacOSXPrivate.h | 18 ------------------ macosx/tkMacOSXWm.c | 6 +++--- macosx/tkMacOSXXStubs.c | 3 +-- 8 files changed, 28 insertions(+), 45 deletions(-) diff --git a/macosx/tkMacOSXCursor.c b/macosx/tkMacOSXCursor.c index c9815c1..08dec9e 100644 --- a/macosx/tkMacOSXCursor.c +++ b/macosx/tkMacOSXCursor.c @@ -344,7 +344,7 @@ FindCursorByName( macCursor = [[NSCursor alloc] initWithImage:image hotSpot:hotSpot]; [image release]; } - macCursorPtr->macCursor = TkMacOSXMakeUncollectable(macCursor); + macCursorPtr->macCursor = macCursor; } /* @@ -452,7 +452,8 @@ TkpFreeCursor( { TkMacOSXCursor *macCursorPtr = (TkMacOSXCursor *) cursorPtr; - TkMacOSXMakeCollectableAndRelease(macCursorPtr->macCursor); + [macCursorPtr->macCursor release]; + macCursorPtr->macCursor = NULL; if (macCursorPtr == gCurrentCursor) { gCurrentCursor = NULL; } diff --git a/macosx/tkMacOSXFont.c b/macosx/tkMacOSXFont.c index ae3be92..d30da09 100644 --- a/macosx/tkMacOSXFont.c +++ b/macosx/tkMacOSXFont.c @@ -293,7 +293,7 @@ InitFont( [NSNumber numberWithInt:fmPtr->fixed ? 0 : 1], NSLigatureAttributeName, [NSNumber numberWithDouble:kern], NSKernAttributeName, nil]; - fontPtr->nsAttributes = TkMacOSXMakeUncollectableAndRetain(nsAttributes); + fontPtr->nsAttributes = [nsAttributes retain]; #undef nCh } @@ -557,7 +557,8 @@ TkpDeleteFont( { MacFont *fontPtr = (MacFont *) tkFontPtr; - TkMacOSXMakeCollectableAndRelease(fontPtr->nsAttributes); + [fontPtr->nsAttributes release]; + fontPtr->nsAttributes = NULL; CFRelease(fontPtr->nsFont); /* Either a CTFontRef or a CFRetained NSFont */ } diff --git a/macosx/tkMacOSXInit.c b/macosx/tkMacOSXInit.c index 752ec48..6ba726d 100644 --- a/macosx/tkMacOSXInit.c +++ b/macosx/tkMacOSXInit.c @@ -30,7 +30,6 @@ static char tkLibPath[PATH_MAX + 1] = ""; static char scriptPath[PATH_MAX + 1] = ""; -int tkMacOSXGCEnabled = 0; long tkMacOSXMacOSXVersion = 0; #pragma mark TKApplication(TKInit) @@ -247,7 +246,6 @@ TkpInit( if (!pool) { pool = [NSAutoreleasePool new]; } - tkMacOSXGCEnabled = ([NSGarbageCollector defaultCollector] != nil); [[NSUserDefaults standardUserDefaults] registerDefaults: [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithBool:YES], diff --git a/macosx/tkMacOSXMenu.c b/macosx/tkMacOSXMenu.c index 3dadb45..472520f 100644 --- a/macosx/tkMacOSXMenu.c +++ b/macosx/tkMacOSXMenu.c @@ -496,8 +496,7 @@ TkpNewMenu( * platform structure for. */ { TKMenu *menu = [[TKMenu alloc] initWithTkMenu:menuPtr]; - menuPtr->platformData = (TkMenuPlatformData) - TkMacOSXMakeUncollectable(menu); + menuPtr->platformData = (TkMenuPlatformData) menu; CheckForSpecialMenu(menuPtr); return TCL_OK; } @@ -522,7 +521,10 @@ void TkpDestroyMenu( TkMenu *menuPtr) /* The common menu structure */ { - TkMacOSXMakeCollectableAndRelease(menuPtr->platformData); + NSMenu* nsmenu = (NSMenu*)(menuPtr->platformData); + + [nsmenu release]; + menuPtr->platformData = NULL; } /* @@ -555,8 +557,7 @@ TkpMenuNewEntry( } else { menuItem = [menu newTkMenuItem:mePtr]; } - mePtr->platformEntryData = (TkMenuPlatformEntryData) - TkMacOSXMakeUncollectable(menuItem); + mePtr->platformEntryData = (TkMenuPlatformEntryData) menuItem; /* * Caller TkMenuEntry() already did this same insertion into the generic @@ -720,16 +721,21 @@ void TkpDestroyMenuEntry( TkMenuEntry *mePtr) { + NSMenuItem *menuItem; + TKMenu *menu; + NSInteger index; + if (mePtr->platformEntryData && mePtr->menuPtr->platformData) { - TKMenu *menu = (TKMenu *) mePtr->menuPtr->platformData; - NSMenuItem *menuItem = (NSMenuItem *) mePtr->platformEntryData; - NSInteger index = [menu indexOfItem:menuItem]; + menu = (TKMenu *) mePtr->menuPtr->platformData; + menuItem = (NSMenuItem *) mePtr->platformEntryData; + index = [menu indexOfItem:menuItem]; if (index > -1) { [menu removeItemAtIndex:index]; } + [menuItem release]; + mePtr->platformEntryData = NULL; } - TkMacOSXMakeCollectableAndRelease(mePtr->platformEntryData); } /* diff --git a/macosx/tkMacOSXNotify.c b/macosx/tkMacOSXNotify.c index b400423..d35427a 100644 --- a/macosx/tkMacOSXNotify.c +++ b/macosx/tkMacOSXNotify.c @@ -223,8 +223,7 @@ TkMacOSXEventsSetupProc( inMode:GetRunLoopMode(TkMacOSXGetModalSession()) dequeue:YES]; if (currentEvent) { - tsdPtr->currentEvent = - TkMacOSXMakeUncollectableAndRetain(currentEvent); + tsdPtr->currentEvent = [currentEvent retain]; } } if (tsdPtr->currentEvent) { @@ -262,8 +261,8 @@ TkMacOSXEventsCheckProc( TSD_INIT(); if (tsdPtr->currentEvent) { - currentEvent = TkMacOSXMakeCollectableAndAutorelease( - tsdPtr->currentEvent); + currentEvent = tsdPtr->currentEvent; + [currentEvent autorelease]; } do { modalSession = TkMacOSXGetModalSession(); @@ -277,9 +276,6 @@ TkMacOSXEventsCheckProc( } [currentEvent retain]; pool = [NSAutoreleasePool new]; - if (tkMacOSXGCEnabled) { - objc_clear_stack(0); - } if (![NSApp tkProcessEvent:currentEvent]) { [currentEvent release]; currentEvent = nil; diff --git a/macosx/tkMacOSXPrivate.h b/macosx/tkMacOSXPrivate.h index 18af42f..b93fa18 100644 --- a/macosx/tkMacOSXPrivate.h +++ b/macosx/tkMacOSXPrivate.h @@ -142,23 +142,6 @@ } /* - * Macros for GC - */ - -#define TkMacOSXMakeUncollectable(x) ({ id o = (id)(x); \ - if (o) { if(tkMacOSXGCEnabled) CFRetain(o); } o; }) -#define TkMacOSXMakeUncollectableAndRetain(x) ({ id o = (id)(x); \ - if (o) { if(tkMacOSXGCEnabled) CFRetain(o); else [o retain]; } o; }) -#define TkMacOSXMakeCollectable(x) ({ id o = (id)(x); \ - if (o) { x = nil; if (tkMacOSXGCEnabled) CFRelease(o); } o; }) -#define TkMacOSXMakeCollectableAndRelease(x) ({ id o = (id)(x); \ - if (o) { x = nil; if (tkMacOSXGCEnabled) CFRelease(o); \ - else [o release]; } o; }) -#define TkMacOSXMakeCollectableAndAutorelease(x) ({ id o = (id)(x); \ - if (o) { x = nil; if (tkMacOSXGCEnabled) CFRelease(o); \ - else [o autorelease]; } o; }) - -/* * Structure encapsulating current drawing environment. */ @@ -176,7 +159,6 @@ typedef struct TkMacOSXDrawingContext { MODULE_SCOPE CGFloat tkMacOSXZeroScreenHeight; MODULE_SCOPE CGFloat tkMacOSXZeroScreenTop; -MODULE_SCOPE int tkMacOSXGCEnabled; MODULE_SCOPE long tkMacOSXMacOSXVersion; /* diff --git a/macosx/tkMacOSXWm.c b/macosx/tkMacOSXWm.c index 91c6858..23b107f 100644 --- a/macosx/tkMacOSXWm.c +++ b/macosx/tkMacOSXWm.c @@ -794,8 +794,9 @@ TkWmDeadWindow( if (winPtr->window) { ((MacDrawable *) winPtr->window)->view = nil; } - TkMacOSXMakeCollectableAndRelease(wmPtr->window); - /* Activate the highest window left on the screen. */ + [window release]; + wmPtr->window = NULL; + /* Activate the highest window left on the screen. */ NSArray *windows = [NSApp orderedWindows]; NSWindow *front = [windows objectAtIndex:0]; if ( front && [front canBecomeKeyWindow] ) { @@ -5426,7 +5427,6 @@ TkMacOSXMakeRealWindowExist( if (!window) { Tcl_Panic("couldn't allocate new Mac window"); } - TkMacOSXMakeUncollectable(window); TKContentView *contentView = [[TKContentView alloc] initWithFrame:NSZeroRect]; [window setContentView:contentView]; diff --git a/macosx/tkMacOSXXStubs.c b/macosx/tkMacOSXXStubs.c index c227cd6..0be5416 100644 --- a/macosx/tkMacOSXXStubs.c +++ b/macosx/tkMacOSXXStubs.c @@ -177,8 +177,7 @@ TkpOpenDisplay( display->proto_minor_version = [[cgVers objectAtIndex:2] integerValue]; } if (!vendor[0]) { - snprintf(vendor, sizeof(vendor), "Apple AppKit %s %g", - ([NSGarbageCollector defaultCollector] ? "GC" : "RR"), + snprintf(vendor, sizeof(vendor), "Apple AppKit %g", NSAppKitVersionNumber); } display->vendor = vendor; -- cgit v0.12 From f22c4207e5275f1e2c792672b41f6828372d6203 Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Sat, 21 Mar 2015 00:57:31 +0000 Subject: Cleanup and improvement of tracking of native windows in Cocoa; thanks to Marc Culler for patch --- macosx/tkMacOSXEvent.c | 38 ++++++++--------- macosx/tkMacOSXKeyEvent.c | 8 ++-- macosx/tkMacOSXMouseEvent.c | 15 +++---- macosx/tkMacOSXWm.c | 102 ++++++++++++++++++++------------------------ 4 files changed, 74 insertions(+), 89 deletions(-) diff --git a/macosx/tkMacOSXEvent.c b/macosx/tkMacOSXEvent.c index 73a67ad..6685b80 100644 --- a/macosx/tkMacOSXEvent.c +++ b/macosx/tkMacOSXEvent.c @@ -30,18 +30,19 @@ enum { NSEvent *processedEvent = theEvent; NSEventType type = [theEvent type]; NSInteger subtype; - NSUInteger flags; switch ((NSInteger)type) { case NSAppKitDefined: subtype = [theEvent subtype]; switch (subtype) { + /* Ignored at the moment. */ case NSApplicationActivatedEventType: break; case NSApplicationDeactivatedEventType: break; case NSWindowExposedEventType: + break; case NSScreenChangedEventType: break; case NSWindowMovedEventType: @@ -52,13 +53,12 @@ enum { default: break; } - break; + break; /* AppkitEvent. Return theEvent */ case NSKeyUp: case NSKeyDown: case NSFlagsChanged: - flags = [theEvent modifierFlags]; processedEvent = [self tkProcessKeyEvent:theEvent]; - break; + break; /* Key event. Return the processed event. */ case NSLeftMouseDown: case NSLeftMouseUp: case NSRightMouseDown: @@ -75,7 +75,7 @@ enum { case NSTabletPoint: case NSTabletProximity: processedEvent = [self tkProcessMouseEvent:theEvent]; - break; + break; /* Mouse event. Return the processed event. */ #if 0 case NSSystemDefined: subtype = [theEvent subtype]; @@ -99,7 +99,7 @@ enum { #endif default: - break; + break; /* return theEvent */ } return processedEvent; } @@ -112,36 +112,32 @@ enum { * * TkMacOSXFlushWindows -- * - * This routine flushes all the windows of the application. It is + * This routine flushes all the visible windows of the application. It is * called by XSync(). * * Results: * None. * * Side effects: - * Flushes all Carbon windows + * Flushes all visible Cocoa windows * *---------------------------------------------------------------------- */ - MODULE_SCOPE void TkMacOSXFlushWindows(void) { - NSInteger windowCount; - NSInteger *windowNumbers; + /* This can be called from outside the Appkit event loop, + * so it needs its own AutoreleasePool. + */ + NSAutoreleasePool *pool = [NSAutoreleasePool new]; + NSArray *macWindows = [NSApp orderedWindows]; - NSCountWindows(&windowCount); - if(windowCount) { - windowNumbers = (NSInteger *) ckalloc(windowCount * sizeof(NSInteger)); - NSWindowList(windowCount, windowNumbers); - for (NSInteger index = 0; index < windowCount; index++) { - NSWindow *w = [NSApp windowWithWindowNumber:windowNumbers[index]]; - if (TkMacOSXGetXWindow(w)) { - [w flushWindow]; - } + for (NSWindow *w in macWindows) { + if (TkMacOSXGetXWindow(w)) { + [w flushWindow]; } - ckfree((char*) windowNumbers); } + [pool drain]; } /* diff --git a/macosx/tkMacOSXKeyEvent.c b/macosx/tkMacOSXKeyEvent.c index c9ad9f1..09cdf94 100644 --- a/macosx/tkMacOSXKeyEvent.c +++ b/macosx/tkMacOSXKeyEvent.c @@ -78,16 +78,18 @@ static unsigned isFunctionKey(unsigned int code); case NSFlagsChanged: modifiers = [theEvent modifierFlags]; keyCode = [theEvent keyCode]; - w = [self windowWithWindowNumber:[theEvent windowNumber]]; + // w = [self windowWithWindowNumber:[theEvent windowNumber]]; + w = [theEvent window]; #if defined(TK_MAC_DEBUG_EVENTS) || NS_KEYLOG == 1 NSLog(@"-[%@(%p) %s] r=%d mods=%u '%@' '%@' code=%u c=%d %@ %d", [self class], self, _cmd, repeat, modifiers, characters, charactersIgnoringModifiers, keyCode,([charactersIgnoringModifiers length] == 0) ? 0 : [charactersIgnoringModifiers characterAtIndex: 0], w, type); #endif break; default: - return theEvent; + return theEvent; /* Unrecognized key event. */ } + /* Create an Xevent to add to the Tk queue. */ if (!processingCompose) { unsigned int state = 0; @@ -128,7 +130,7 @@ static unsigned isFunctionKey(unsigned int code); tkwin = (Tk_Window) winPtr->dispPtr->focusPtr; if (!tkwin) { TkMacOSXDbgMsg("tkwin == NULL"); - return theEvent; + return theEvent; /* Give up. No window for this event. */ } /* diff --git a/macosx/tkMacOSXMouseEvent.c b/macosx/tkMacOSXMouseEvent.c index 89f0642..d1b4114 100644 --- a/macosx/tkMacOSXMouseEvent.c +++ b/macosx/tkMacOSXMouseEvent.c @@ -52,19 +52,17 @@ enum { case NSCursorUpdate: #if 0 trackingArea = [theEvent trackingArea]; -#endif /* fall through */ +#endif case NSLeftMouseDown: case NSLeftMouseUp: case NSRightMouseDown: case NSRightMouseUp: case NSOtherMouseDown: case NSOtherMouseUp: - case NSLeftMouseDragged: case NSRightMouseDragged: case NSOtherMouseDragged: - case NSMouseMoved: #if 0 eventNumber = [theEvent eventNumber]; @@ -73,19 +71,17 @@ enum { buttonNumber = [theEvent buttonNumber]; } #endif - case NSTabletPoint: case NSTabletProximity: - case NSScrollWheel: - win = [self windowWithWindowNumber:[theEvent windowNumber]]; break; - default: + default: /* Unrecognized mouse event. */ return theEvent; - break; } + /* Create an Xevent to add to the Tk queue. */ + win = [theEvent window]; NSPoint global, local = [theEvent locationInWindow]; if (win) { global = [win convertBaseToScreen:local]; @@ -103,7 +99,7 @@ enum { tkwin = TkMacOSXGetCapture(); } if (!tkwin) { - return theEvent; + return theEvent; /* Give up. No window for this event. */ } /* @@ -203,7 +199,6 @@ enum { Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL); } } - return theEvent; } @end diff --git a/macosx/tkMacOSXWm.c b/macosx/tkMacOSXWm.c index 23b107f..a852ac9 100644 --- a/macosx/tkMacOSXWm.c +++ b/macosx/tkMacOSXWm.c @@ -464,28 +464,20 @@ static TkWindow* FrontWindowAtPoint( int x, int y) { - NSPoint p = NSMakePoint(x, tkMacOSXZeroScreenHeight - y); - NSWindow *win = nil; - NSInteger windowCount; - NSInteger *windowNumbers; - - NSCountWindows(&windowCount); - if (windowCount) { - windowNumbers = (NSInteger *) ckalloc(windowCount * sizeof(NSInteger)); - NSWindowList(windowCount, windowNumbers); - for (NSInteger index = 0; index < windowCount; index++) { - NSWindow *w = [NSApp windowWithWindowNumber:windowNumbers[index]]; + NSAutoreleasePool *pool = [NSAutoreleasePool new]; + NSArray *windows = [NSApp orderedWindows]; + TkWindow *front = NULL; + + for (NSWindow *w in windows) { if (w && NSMouseInRect(p, [w frame], NO)) { - win = w; + front = TkMacOSXGetTkWindow(w); break; } } - ckfree((char *) windowNumbers); - } - return (win ? TkMacOSXGetTkWindow(win) : NULL); + [pool drain]; + return front; } - /* *---------------------------------------------------------------------- @@ -681,6 +673,7 @@ TkWmMapWindow( */ XMapWindow(winPtr->display, winPtr->window); + } /* @@ -703,7 +696,7 @@ TkWmMapWindow( void TkWmUnmapWindow( TkWindow *winPtr) /* Top-level window that's about to be - * mapped. */ + * unmapped. */ { XUnmapWindow(winPtr->display, winPtr->window); } @@ -786,25 +779,30 @@ TkWmDeadWindow( */ NSWindow *window = wmPtr->window; + if (window && !Tk_IsEmbedded(winPtr) ) { - [[window parentWindow] removeChildWindow:window]; + NSWindow *parent = [window parentWindow]; + if (parent) { + [parent removeChildWindow:window]; + } [window setExcludedFromWindowsMenu:YES]; [window close]; - TkMacOSXUnregisterMacWindow(window); - if (winPtr->window) { - ((MacDrawable *) winPtr->window)->view = nil; - } - [window release]; - wmPtr->window = NULL; - /* Activate the highest window left on the screen. */ - NSArray *windows = [NSApp orderedWindows]; - NSWindow *front = [windows objectAtIndex:0]; - if ( front && [front canBecomeKeyWindow] ) { - [front makeKeyAndOrderFront:NSApp]; + TkMacOSXUnregisterMacWindow(window); + if (winPtr->window) { + ((MacDrawable *) winPtr->window)->view = nil; } - } - - ckfree((char *) wmPtr); + [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]; + } + } + } + ckfree(wmPtr); winPtr->wmInfoPtr = NULL; } @@ -5867,6 +5865,7 @@ 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]; @@ -5874,6 +5873,7 @@ TkpChangeFocus( if ( win && [win canBecomeKeyWindow] ) { [win makeKeyAndOrderFront:NSApp]; } + [pool drain]; } /* @@ -5892,7 +5892,7 @@ TkpChangeFocus( * WmStackorderToplevelWrapperMap -- * * This procedure will create a table that maps the reparent wrapper X id - * for a toplevel to the TkWindow structure that is wraps. Tk keeps track + * for a toplevel to the TkWindow structure that it wraps. Tk keeps track * of a mapping from the window X id to the TkWindow structure but that * does us no good here since we only get the X id of the wrapper window. * Only those toplevel windows that are mapped have a position in the @@ -5951,12 +5951,10 @@ TkWindow ** TkWmStackorderToplevel( TkWindow *parentPtr) /* Parent toplevel window. */ { - TkWindow *childWinPtr, **windows, **window_ptr; + TkWindow *childWinPtr, **windows, **windowPtr; Tcl_HashTable table; Tcl_HashEntry *hPtr; Tcl_HashSearch search; - NSInteger windowCount; - NSInteger *windowNumbers; /* * Map mac windows to a TkWindow of the wrapped toplevel. @@ -5983,31 +5981,26 @@ TkWmStackorderToplevel( goto done; } - NSCountWindows(&windowCount); + NSArray *macWindows = [NSApp orderedWindows]; + NSInteger windowCount = [macWindows count]; + if (!windowCount) { - ckfree((char *) windows); + ckfree(windows); windows = NULL; } else { - window_ptr = windows + table.numEntries; - *window_ptr-- = NULL; - windowNumbers = (NSInteger*)ckalloc(windowCount * sizeof(NSInteger)); - NSWindowList(windowCount, windowNumbers); - for (NSInteger index = 0; index < windowCount; index++) { - NSWindow *w = [NSApp windowWithWindowNumber:windowNumbers[index]]; - - if (w) { - hPtr = Tcl_FindHashEntry(&table, (char*) w); - if (hPtr != NULL) { - childWinPtr = Tcl_GetHashValue(hPtr); - *window_ptr-- = childWinPtr; - } + windowPtr = windows + table.numEntries; + *windowPtr-- = NULL; + for (NSWindow *w in macWindows) { + hPtr = Tcl_FindHashEntry(&table, (char*) w); + if (hPtr != NULL) { + childWinPtr = Tcl_GetHashValue(hPtr); + *windowPtr-- = childWinPtr; } } - if (window_ptr != (windows-1)) { + if (windowPtr != windows-1) { Tcl_Panic("num matched toplevel windows does not equal num " - "children"); + "children"); } - ckfree((char *) windowNumbers); } done: @@ -6569,7 +6562,6 @@ RemapWindows( MacDrawable *parentWin) { TkWindow *childPtr; - /* * Remove the OS specific window. It will get rebuilt when the window gets * Mapped. -- cgit v0.12 From 50ec1ecb24801b023618048a6704fa12670671d9 Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Sat, 21 Mar 2015 01:22:36 +0000 Subject: Cleanup and simplification of memory management in event loop; now works more smoothly; thanks to Marc Culler for patches --- macosx/tkMacOSXMenu.c | 9 +++- macosx/tkMacOSXNotify.c | 116 +++++++++++++++++++------------------------ macosx/tkMacOSXSubwindows.c | 6 +++ macosx/tkMacOSXWindowEvent.c | 33 ++++++++++-- macosx/tkMacOSXWm.c | 14 +++++- 5 files changed, 106 insertions(+), 72 deletions(-) diff --git a/macosx/tkMacOSXMenu.c b/macosx/tkMacOSXMenu.c index 472520f..5ae38f8 100644 --- a/macosx/tkMacOSXMenu.c +++ b/macosx/tkMacOSXMenu.c @@ -375,6 +375,13 @@ 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 @@ -466,7 +473,7 @@ static int ModifierCharWidth(Tk_Font tkfont); [servicesMenuItem setSubmenu:_servicesMenu]; } [self setAppleMenu:applicationMenu]; - [self setMainMenu:menu]; + [self safeSetMainMenu:menu]; } @end diff --git a/macosx/tkMacOSXNotify.c b/macosx/tkMacOSXNotify.c index d35427a..6a4e6c1 100644 --- a/macosx/tkMacOSXNotify.c +++ b/macosx/tkMacOSXNotify.c @@ -18,9 +18,9 @@ #include #import +/* This is not used for anything at the moment. */ typedef struct ThreadSpecificData { - int initialized, sendEventNestingLevel; - NSEvent *currentEvent; + int initialized; } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; @@ -34,6 +34,7 @@ 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 @@ -47,35 +48,28 @@ static void TkMacOSXEventsCheckProc(ClientData clientData, int flags); @end @implementation TKApplication(TKNotify) +/* Redisplay all of our windows, then call super. */ - (NSEvent *)nextEventMatchingMask:(NSUInteger)mask untilDate:(NSDate *)expiration inMode:(NSString *)mode dequeue:(BOOL)deqFlag { NSAutoreleasePool *pool = [NSAutoreleasePool new]; [NSApp makeWindowsPerform:@selector(tkDisplayIfNeeded) inOrder:NO]; - int oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL); - NSEvent *event = [[super nextEventMatchingMask:mask untilDate:expiration - inMode:mode dequeue:deqFlag] retain]; - Tcl_SetServiceMode(oldMode); - if (event) { - TSD_INIT(); - if (tsdPtr->sendEventNestingLevel) { - if (![NSApp tkProcessEvent:event]) { - [event release]; - event = nil; - } - } - } [pool drain]; - return [event autorelease]; + NSEvent *event = [super nextEventMatchingMask:mask + untilDate:expiration + inMode:mode + dequeue:deqFlag]; + return event; } + + /* + * Call super then check the pasteboard. + */ - (void)sendEvent:(NSEvent *)theEvent { - TSD_INIT(); - int oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL); - tsdPtr->sendEventNestingLevel++; + NSAutoreleasePool *pool = [NSAutoreleasePool new]; [super sendEvent:theEvent]; - tsdPtr->sendEventNestingLevel--; - Tcl_SetServiceMode(oldMode); [NSApp tkCheckPasteboard]; + [pool drain]; } @end @@ -152,7 +146,8 @@ Tk_MacOSXSetupTkNotifier(void) "first [load] of TkAqua has to occur in the main thread!"); } Tcl_CreateEventSource(TkMacOSXEventsSetupProc, - TkMacOSXEventsCheckProc, GetMainEventQueue()); + TkMacOSXEventsCheckProc, + GetMainEventQueue()); TkCreateExitHandler(TkMacOSXNotifyExitHandler, NULL); Tcl_SetServiceMode(TCL_SERVICE_ALL); TclMacOSXNotifierAddRunLoopMode(NSEventTrackingRunLoopMode); @@ -184,7 +179,8 @@ TkMacOSXNotifyExitHandler( { TSD_INIT(); Tcl_DeleteEventSource(TkMacOSXEventsSetupProc, - TkMacOSXEventsCheckProc, GetMainEventQueue()); + TkMacOSXEventsCheckProc, + GetMainEventQueue()); tsdPtr->initialized = 0; } @@ -193,16 +189,19 @@ TkMacOSXNotifyExitHandler( * * TkMacOSXEventsSetupProc -- * - * This procedure implements the setup part of the TkAqua Events event - * source. It is invoked by Tcl_DoOneEvent before entering the notifier - * to check for events. + * 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 TkAqua events are queued, then the maximum block time will be set - * to 0 to ensure that the notifier returns control to Tcl. + * + * If NSEvents are queued, then the maximum block time will be set + * to 0 to ensure that control returns immediately to Tcl. * *---------------------------------------------------------------------- */ @@ -213,20 +212,14 @@ TkMacOSXEventsSetupProc( int flags) { if (flags & TCL_WINDOW_EVENTS && - ![[NSRunLoop currentRunLoop] currentMode]) { + ![[NSRunLoop currentRunLoop] currentMode]) { static Tcl_Time zeroBlockTime = { 0, 0 }; - - TSD_INIT(); - if (!tsdPtr->currentEvent) { - NSEvent *currentEvent = [NSApp nextEventMatchingMask:NSAnyEventMask - untilDate:[NSDate distantPast] - inMode:GetRunLoopMode(TkMacOSXGetModalSession()) - dequeue:YES]; - if (currentEvent) { - tsdPtr->currentEvent = [currentEvent retain]; - } - } - if (tsdPtr->currentEvent) { + /* 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) { Tcl_SetMaxBlockTime(&zeroBlockTime); } } @@ -237,17 +230,18 @@ TkMacOSXEventsSetupProc( * * TkMacOSXEventsCheckProc -- * - * This procedure processes events sitting in the TkAqua event queue. + * This procedure loops through all NSEvents waiting in the + * TKApplication event queue, generating X events from them. * * Results: * None. * * Side effects: - * Moves applicable queued TkAqua events onto the Tcl event queue. + * NSevents are used to generate X events, which are added to the + * Tcl event queue. * *---------------------------------------------------------------------- */ - static void TkMacOSXEventsCheckProc( ClientData clientData, @@ -256,31 +250,23 @@ TkMacOSXEventsCheckProc( if (flags & TCL_WINDOW_EVENTS && ![[NSRunLoop currentRunLoop] currentMode]) { NSEvent *currentEvent = nil; - NSAutoreleasePool *pool = nil; NSModalSession modalSession; - TSD_INIT(); - if (tsdPtr->currentEvent) { - currentEvent = tsdPtr->currentEvent; - [currentEvent autorelease]; - } do { modalSession = TkMacOSXGetModalSession(); + currentEvent = [NSApp nextEventMatchingMask:NSAnyEventMask + untilDate:[NSDate distantPast] + inMode:GetRunLoopMode(modalSession) + dequeue:YES]; if (!currentEvent) { - currentEvent = [NSApp nextEventMatchingMask:NSAnyEventMask - untilDate:[NSDate distantPast] - inMode:GetRunLoopMode(modalSession) dequeue:YES]; + break; /* No more events. */ } - if (!currentEvent) { - break; - } - [currentEvent retain]; - pool = [NSAutoreleasePool new]; - if (![NSApp tkProcessEvent:currentEvent]) { - [currentEvent release]; - currentEvent = nil; - } - if (currentEvent) { + 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. */ #ifdef TK_MAC_DEBUG_EVENTS TKLog(@" event: %@", currentEvent); #endif @@ -289,14 +275,12 @@ TkMacOSXEventsCheckProc( } else { [NSApp sendEvent:currentEvent]; } - [currentEvent release]; - currentEvent = nil; } [pool drain]; - pool = nil; } while (1); } } + /* * Local Variables: diff --git a/macosx/tkMacOSXSubwindows.c b/macosx/tkMacOSXSubwindows.c index 95cc338..a9703c1 100644 --- a/macosx/tkMacOSXSubwindows.c +++ b/macosx/tkMacOSXSubwindows.c @@ -131,6 +131,11 @@ 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 @@ -189,6 +194,7 @@ XMapWindow( event.xvisibility.type = VisibilityNotify; event.xvisibility.state = VisibilityUnobscured; NotifyVisibility(macWin->winPtr, &event); + [pool drain]; } /* diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index 86a1960..d68a933 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -796,7 +796,6 @@ Tk_MacOSXIsAppInFront(void) @implementation TKContentView @end - /*Restrict event processing to Expose events.*/ static Tk_RestrictAction ExposeRestrictProc( @@ -846,9 +845,37 @@ ExposeRestrictProc( } +-(void) setFrameSize: (NSSize)newsize +{ + if ( [self inLiveResize] ) { + NSWindow *window = [self window]; + TkWindow *winPtr = TkMacOSXGetTkWindow([self window]); + Tk_Window tkwin = (Tk_Window) winPtr; + unsigned int width = (unsigned int)newsize.width; + unsigned int height=(unsigned int)newsize.height; + + /* Resize the Tk Window to the requested size.*/ + TkGenWMConfigureEvent(tkwin, Tk_X(tkwin), Tk_Y(tkwin), width, height, + TK_SIZE_CHANGED | TK_MACOSX_HANDLE_EVENT_IMMEDIATELY); + + /* Then resize the NSView to the actual window size*/ + newsize.width = (CGFloat)Tk_Width(tkwin); + newsize.height = (CGFloat)Tk_Height(tkwin); + [super setFrameSize: newsize]; + + /* Process all pending events to update the window. */ + while (Tcl_ServiceEvent(TCL_WINDOW_EVENTS)) {} + while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {} + + } else { + [super setFrameSize: newsize]; + } +} + /* * As insurance against bugs that might cause layout glitches during a live - * resize, we redraw the window at the end of the resize operation. + * resize, we redraw the window one more time at the end of the resize + * operation. */ - (void)viewDidEndLiveResize @@ -872,7 +899,6 @@ ExposeRestrictProc( return; } - HIShapeGetBounds(shape, &updateBounds); serial = LastKnownRequestProcessed(Tk_Display(winPtr)); if (GenerateUpdates(shape, &updateBounds, winPtr) && @@ -900,7 +926,6 @@ ExposeRestrictProc( Tk_RestrictEvents(oldProc, oldArg, &oldArg); while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {} - } } diff --git a/macosx/tkMacOSXWm.c b/macosx/tkMacOSXWm.c index a852ac9..8459bdd 100644 --- a/macosx/tkMacOSXWm.c +++ b/macosx/tkMacOSXWm.c @@ -22,6 +22,8 @@ #include "tkMacOSXDebug.h" #include +#define DEBUG_ZOMBIES 0 + /* #ifdef TK_MAC_DEBUG #define TK_MAC_DEBUG_WINDOWS @@ -338,6 +340,17 @@ static void RemapWindows(TkWindow *winPtr, { id _i1, _i2; } + +- (id) retain +{ +#if DEBUG_ZOMBIES + const char *title = [[self title] UTF8String]; + if (title != NULL) { + printf("Retaining %s with count %lu\n", title, [self retainCount]); + } +#endif + return [super retain]; +} @end @implementation TKWindow @@ -785,7 +798,6 @@ TkWmDeadWindow( if (parent) { [parent removeChildWindow:window]; } - [window setExcludedFromWindowsMenu:YES]; [window close]; TkMacOSXUnregisterMacWindow(window); if (winPtr->window) { -- cgit v0.12 From 6f271af3157483e82be0a839323490597eac5e04 Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Sat, 21 Mar 2015 01:31:02 +0000 Subject: Improvement of memory management, removal of zombie windows from Tk-Cocoa; thanks to Marc Culler for patch --- macosx/tkMacOSXKeyEvent.c | 17 +++++++++++------ macosx/tkMacOSXMenu.c | 9 +++++++++ macosx/tkMacOSXWm.c | 13 +++++++++++++ 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/macosx/tkMacOSXKeyEvent.c b/macosx/tkMacOSXKeyEvent.c index 09cdf94..7e7e8e4 100644 --- a/macosx/tkMacOSXKeyEvent.c +++ b/macosx/tkMacOSXKeyEvent.c @@ -27,7 +27,9 @@ static Tk_Window grabWinPtr = NULL; /* Current grab window, NULL if no grab. */ static Tk_Window keyboardGrabWinPtr = NULL; /* Current keyboard grab window. */ -static NSModalSession modalSession = NULL; +static NSWindow *keyboardGrabNSWindow = nil; + /* NSWindow for the current keyboard grab window. */ +static NSModalSession modalSession = nil; static BOOL processingCompose = NO; static BOOL finishedCompose = NO; @@ -476,7 +478,9 @@ XGrabKeyboard( if (modalSession) { Tcl_Panic("XGrabKeyboard: already grabbed"); } - modalSession = [NSApp beginModalSessionForWindow:[w retain]]; + keyboardGrabNSWindow = w; + [w retain]; + modalSession = [NSApp beginModalSessionForWindow:w]; } } return GrabSuccess; @@ -504,11 +508,12 @@ XUngrabKeyboard( Time time) { if (modalSession) { - NSWindow *w = keyboardGrabWinPtr ? TkMacOSXDrawableWindow( - ((TkWindow *) keyboardGrabWinPtr)->window) : nil; [NSApp endModalSession:modalSession]; - [w release]; - modalSession = NULL; + modalSession = nil; + } + if (keyboardGrabNSWindow) { + [keyboardGrabNSWindow release]; + keyboardGrabNSWindow = nil; } keyboardGrabWinPtr = NULL; } diff --git a/macosx/tkMacOSXMenu.c b/macosx/tkMacOSXMenu.c index 5ae38f8..49d1872 100644 --- a/macosx/tkMacOSXMenu.c +++ b/macosx/tkMacOSXMenu.c @@ -261,6 +261,7 @@ static int ModifierCharWidth(Tk_Font tkfont); /*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); @@ -273,6 +274,7 @@ static int ModifierCharWidth(Tk_Font tkfont); } Tcl_Release(menuPtr); Tcl_Release(interp); + [pool drain]; } } } @@ -382,6 +384,13 @@ static int ModifierCharWidth(Tk_Font tkfont); [pool drain]; } +- (void) safeSetMainMenu: (NSMenu *) menu +{ + NSAutoreleasePool* pool = [NSAutoreleasePool new]; + [self setMainMenu: menu]; + [pool drain]; +} + - (void) menuBeginTracking: (NSNotification *) notification { #ifdef TK_MAC_DEBUG_NOTIFICATIONS diff --git a/macosx/tkMacOSXWm.c b/macosx/tkMacOSXWm.c index 8459bdd..5cec236 100644 --- a/macosx/tkMacOSXWm.c +++ b/macosx/tkMacOSXWm.c @@ -24,6 +24,8 @@ #define DEBUG_ZOMBIES 0 +#define DEBUG_ZOMBIES 0 + /* #ifdef TK_MAC_DEBUG #define TK_MAC_DEBUG_WINDOWS @@ -351,6 +353,17 @@ static void RemapWindows(TkWindow *winPtr, #endif return [super retain]; } + +- (id) retain +{ +#if DEBUG_ZOMBIES + const char *title = [[self title] UTF8String]; + if (title != NULL) { + printf("Retaining %s with count %lu\n", title, [self retainCount]); + } +#endif + return [super retain]; +} @end @implementation TKWindow -- cgit v0.12 From 089db0f16e46cf86e81c5357122632031b942b09 Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Sat, 21 Mar 2015 01:39:39 +0000 Subject: Add copyright notice for Marc Culler --- macosx/tkMacOSXKeyEvent.c | 1 + macosx/tkMacOSXNotify.c | 1 + 2 files changed, 2 insertions(+) diff --git a/macosx/tkMacOSXKeyEvent.c b/macosx/tkMacOSXKeyEvent.c index 7e7e8e4..8e278f7 100644 --- a/macosx/tkMacOSXKeyEvent.c +++ b/macosx/tkMacOSXKeyEvent.c @@ -7,6 +7,7 @@ * Copyright 2001-2009, Apple Inc. * Copyright (c) 2006-2009 Daniel A. Steffen * Copyright (c) 2012 Adrian Robert. + * 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. diff --git a/macosx/tkMacOSXNotify.c b/macosx/tkMacOSXNotify.c index 6a4e6c1..cc1ba06 100644 --- a/macosx/tkMacOSXNotify.c +++ b/macosx/tkMacOSXNotify.c @@ -7,6 +7,7 @@ * Copyright (c) 1995-1997 Sun Microsystems, Inc. * Copyright 2001-2009, Apple Inc. * Copyright (c) 2005-2009 Daniel A. Steffen + * 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. -- cgit v0.12